Watt-32 tcp/ip  2.2 dev-rel.10
transmit.c
Go to the documentation of this file.
1 
5 /* BSD sockets functionality for Watt-32 TCP/IP
6  *
7  * Copyright (c) 1997-2002 Gisle Vanem <gvanem@yahoo.no>
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  * notice, this list of conditions and the following disclaimer in the
16  * documentation and/or other materials provided with the distribution.
17  * 3. All advertising materials mentioning features or use of this software
18  * must display the following acknowledgement:
19  * This product includes software developed by Gisle Vanem
20  * Bergen, Norway.
21  *
22  * THIS SOFTWARE IS PROVIDED BY ME (Gisle Vanem) AND CONTRIBUTORS ``AS IS''
23  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED. IN NO EVENT SHALL I OR CONTRIBUTORS BE LIABLE FOR ANY
26  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
27  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
29  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  *
33  * Version
34  *
35  * 0.5 : Dec 18, 1997 : G. Vanem - created
36  */
37 
38 #include "socket.h"
39 #include "pcicmp6.h"
40 
41 #if defined(USE_BSD_API)
42 
43 static int raw_transmit (Socket *socket, const void *buf, unsigned len);
44 static int udp_transmit (Socket *socket, const void *buf, unsigned len);
45 static int tcp_transmit (Socket *socket, const void *buf, unsigned len, int flags);
46 static int setup_udp_raw (Socket *socket, const struct sockaddr *to, int tolen);
47 
48 static int transmit (const char *func, int s, const void *buf, unsigned len,
49  int flags, const struct sockaddr *to, int tolen,
50  BOOL have_remote_addr);
51 
52 int W32_CALL sendto (int s, const void *buf, int len, int flags,
53  const struct sockaddr *to, int tolen)
54 {
55  return transmit ("sendto", s, buf, len, flags, to, tolen, TRUE);
56 }
57 
58 int W32_CALL send (int s, const void *buf, int len, int flags)
59 {
60  return transmit ("send", s, buf, len, flags, NULL, 0, FALSE);
61 }
62 
63 int W32_CALL write_s (int s, const char *buf, int nbyte)
64 {
65  return transmit ("write_s", s, buf, nbyte, 0, NULL, 0, FALSE);
66 }
67 
68 int W32_CALL writev_s (int s, const struct iovec *vector, size_t count)
69 {
70  int i, len, bytes = 0;
71 
72  SOCK_DEBUGF (("\nwritev_s:%d, iovecs=%lu", s, (DWORD)count));
73 
74  for (i = 0; i < (int)count; i++)
75  {
76 #if (DOSX)
77  if (!valid_addr(vector[i].iov_base, vector[i].iov_len))
78  {
79  SOCK_DEBUGF ((", EFAULT (iovec[%d] = %p, len %d)",
80  i, vector[i].iov_base, vector[i].iov_len));
81  SOCK_ERRNO (EFAULT);
82  return (-1);
83  }
84 #endif
85 
86  len = transmit (NULL, s, vector[i].iov_base, vector[i].iov_len,
87  0, NULL, 0, FALSE);
88  if (len < 0)
89  {
90  bytes = -1;
91  break;
92  }
93  bytes += len;
94  }
95 
96  SOCK_DEBUGF ((", total %d", bytes)); /* writing 0 byte is not an error */
97  return (bytes);
98 }
99 
100 /*
101  * sendmsg():
102  */
103 int W32_CALL sendmsg (int s, const struct msghdr *msg, int flags)
104 {
105  const struct iovec *iov;
106  int count = msg->msg_iovlen;
107  int i, bytes, len;
108 
109  SOCK_DEBUGF (("\nsendmsg:%d, iovecs=%d", s, count));
110 
111  iov = msg->msg_iov;
112  if (!iov)
113  {
114  SOCK_DEBUGF ((", EFAULT"));
115  SOCK_ERRNO (EFAULT);
116  return (-1);
117  }
118 
119  for (i = bytes = 0; i < count; i++)
120  {
121 #if (DOSX)
122  if (!valid_addr(iov[i].iov_base, iov[i].iov_len))
123  {
124  SOCK_DEBUGF ((", EFAULT (iovec[%d] = %p/%d)",
125  (int)i, iov[i].iov_base, iov[i].iov_len));
126  SOCK_ERRNO (EFAULT);
127  return (-1);
128  }
129 #endif
130 
131  len = transmit (NULL, s, iov[i].iov_base, iov[i].iov_len,
132  flags, (struct sockaddr*)msg->msg_name,
133  msg->msg_namelen, TRUE);
134  if (len < 0)
135  {
136  bytes = -1;
137  break;
138  }
139  bytes += len;
140  }
141  SOCK_DEBUGF ((", total %d", bytes));
142  return (bytes);
143 }
144 
145 /*
146  * Close socket if MSG_EOR specified in flags.
147  */
148 static __inline void msg_eor_close (Socket *socket)
149 {
150  switch (socket->so_type)
151  {
152  case SOCK_STREAM:
153  socket->so_state |= SS_CANTSENDMORE;
154  sock_close ((sock_type*)socket->tcp_sock);
155  break;
156  case SOCK_DGRAM:
157  socket->so_state |= SS_CANTSENDMORE;
158  sock_close ((sock_type*)socket->udp_sock);
159  break;
160  case SOCK_RAW:
161  socket->so_state |= SS_CANTSENDMORE;
162  break;
163  }
164 }
165 
166 /*
167  * transmit() flags:
168  * MSG_DONTROUTE (not supported)
169  * MSG_EOR Close sending side after data sent
170  * MSG_TRUNC (not supported)
171  * MSG_CTRUNC (not supported)
172  * MSG_OOB (not supported)
173  * MSG_WAITALL Wait till room in tx-buffer (not supported)
174  * MSG_NOSIGNAL ?? (not supported)
175  */
176 static int transmit (const char *func, int s, const void *buf, unsigned len,
177  int flags, const struct sockaddr *to, int tolen,
178  BOOL have_remote_addr) /* for sendto() and sendmsg() */
179 {
180  Socket *socket = _socklist_find (s);
181  int rc;
182 
183  if (func)
184  {
185  SOCK_DEBUGF (("\n%s:%d, len=%d", func, s, len));
186  if (flags)
187  SOCK_DEBUGF ((", flags 0x%X", flags));
188  }
189 
190  if (!socket)
191  {
192  if (_sock_dos_fd(s))
193  {
194  SOCK_DEBUGF ((", ENOTSOCK"));
195  SOCK_ERRNO (ENOTSOCK);
196  return (-1);
197  }
198  SOCK_DEBUGF ((", EBADF"));
199  SOCK_ERRNO (EBADF);
200  return (-1);
201  }
202 
203  if (flags & MSG_NOSIGNAL) /* Don't do 'raise(SIGPIPE)' */
204  socket->msg_nosig = TRUE;
205 
206  if (socket->so_type == SOCK_STREAM || /* TCP-socket or */
207  (socket->so_state & SS_ISCONNECTED)) /* "connected" udp/raw */
208  {
209  /* Note: SOCK_RAW doesn't really need a local address/port, but
210  * makes the code more similar for all socket-types.
211  * Disadvantage is that SOCK_RAW ties up a local port and a bit
212  * more memory.
213  */
214 
215  if (!socket->local_addr)
216  {
217  SOCK_DEBUGF ((", no local_addr"));
218  SOCK_ERRNO (ENOTCONN);
219  return (-1);
220  }
221 
222  if (!socket->remote_addr)
223  {
224  SOCK_DEBUGF ((", no remote_addr"));
225  SOCK_ERRNO (ENOTCONN);
226  return (-1);
227  }
228 
229  if (socket->so_state & SS_CONN_REFUSED)
230  {
231  if (socket->so_error == ECONNRESET) /* set in tcp_sockreset() */
232  {
233  SOCK_DEBUGF ((", ECONNRESET"));
234  SOCK_ERRNO (ECONNRESET);
235  }
236  else
237  {
238  SOCK_DEBUGF ((", ECONNREFUSED"));
239  SOCK_ERRNO (ECONNREFUSED);
240  }
241  return (-1);
242  }
243  }
244 
245  /* connectionless protocol setup.
246  * SOCK_PACKET sockets go pretty much unchecked.
247  */
248  if (socket->so_type == SOCK_DGRAM ||
249  socket->so_type == SOCK_RAW)
250  {
251  size_t sa_len = (socket->so_family == AF_INET6) ?
252  sizeof(struct sockaddr_in6) :
253  (socket->so_family == AF_PACKET) ?
254  sizeof(struct sockaddr_ll) :
255  sizeof(struct sockaddr_in);
256 
257  if (!have_remote_addr)
258  {
259  to = (const struct sockaddr*) socket->remote_addr;
260  tolen = sa_len;
261  }
262  if (!to || tolen < (int)sa_len)
263  {
264  SOCK_DEBUGF ((", illegal to-addr (tolen = %d, sa_len %d)",
265  tolen, (int)sa_len));
266  SOCK_ERRNO (EINVAL);
267  return (-1);
268  }
269  if (socket->so_type != SOCK_PACKET &&
270  setup_udp_raw(socket,to,tolen) < 0)
271  return (-1);
272  }
273 
274  if (len > 0)
275  VERIFY_RW (buf, len);
276 
277  if (socket->so_type != SOCK_DGRAM && (!buf || len == 0))
278  {
279  SOCK_DEBUGF ((", EINVAL"));
280  SOCK_ERRNO (EINVAL);
281  return (-1);
282  }
283 
284  if (_sock_sig_setup() < 0)
285  {
286  SOCK_ERRNO (EINTR);
287  return (-1);
288  }
289 
290  switch (socket->so_type)
291  {
292  case SOCK_DGRAM:
293  rc = udp_transmit (socket, buf, len);
294  break;
295 
296  case SOCK_STREAM:
297  rc = tcp_transmit (socket, buf, len, flags);
298  break;
299 
300  case SOCK_RAW:
301  rc = raw_transmit (socket, buf, len);
302  break;
303 
304  case SOCK_PACKET:
305  rc = sock_packet_transmit (socket, buf, len, to, tolen);
306  break;
307 
308  default:
309  SOCK_DEBUGF ((", EPROTONOSUPPORT"));
310  SOCK_ERRNO (EPROTONOSUPPORT);
311  rc = -1;
312  break;
313  }
314 
315  if (rc >= 0 && (flags & MSG_EOR))
316  msg_eor_close (socket);
317 
318  _sock_sig_restore();
319  return (rc);
320 }
321 
322 
323 /*
324  * Setup remote_addr for SOCK_RAW/SOCK_DGRAM (connectionless) protocols.
325  * Must "reconnect" socket if 'remote_addr' or 'to' address are different.
326  * I.e we're sending to another host/port than last time.
327  */
328 static int setup_udp_raw (Socket *socket, const struct sockaddr *to, int tolen)
329 {
330  const struct sockaddr_in *peer = (const struct sockaddr_in*) to;
331  DWORD keepalive = socket->keepalive;
332  WORD lport = 0;
333  BOOL is_ip6 = (socket->so_family == AF_INET6);
334  BYTE *rdata = NULL;
335  int rc;
336 
337  if (socket->so_state & SS_ISCONNECTED)
338  {
339  if (!socket->remote_addr)
340  SOCK_FATAL (("setup_udp_raw(): no remote_addr\n"));
341 
342  /* No need to reconnect if same peer address/port.
343  */
344  if (!is_ip6)
345  {
346  const struct sockaddr_in *ra = (const struct sockaddr_in*)socket->remote_addr;
347 
348  if (peer->sin_addr.s_addr == ra->sin_addr.s_addr &&
349  peer->sin_port == ra->sin_port)
350  return (1);
351  }
352 #if defined(USE_IPV6)
353  else
354  {
355  const struct sockaddr_in6 *ra = (const struct sockaddr_in6*)socket->remote_addr;
356  const struct sockaddr_in6 *peer6 = (const struct sockaddr_in6*)to;
357 
358  if (!memcmp(&peer6->sin6_addr, &ra->sin6_addr, sizeof(peer6->sin6_addr)) &&
359  peer6->sin6_port == ra->sin6_port)
360  return (1);
361  }
362 #endif
363 
364  SOCK_DEBUGF ((", reconnecting"));
365 
366  free (socket->remote_addr);
367  socket->remote_addr = NULL;
368 
369  /* Clear any effect of previous ICMP errors etc.
370  */
371  socket->so_state &= ~(SS_CONN_REFUSED | SS_CANTSENDMORE | SS_CANTRCVMORE);
372  socket->so_error = 0;
373 
374  if (socket->so_type == SOCK_DGRAM)
375  {
376  lport = socket->udp_sock->myport;
377  rdata = socket->udp_sock->rx_data; /* preserve current data */
378  }
379  }
380 
381  /* For SOCK_DGRAM, udp_close() will be called when (re)opening socket.
382  */
383  SOCK_ENTER_SCOPE();
384  rc = connect (socket->fd, to, tolen);
385  SOCK_LEAVE_SCOPE();
386 
387  if (rc < 0)
388  return (-1);
389 
390 #if 0
391  if ((socket->so_state & SS_PRIV) && socket->so_type == SOCK_DGRAM)
392  {
393  SOCK_DEBUGF ((", SS_PRIV"));
394 
395  /* Clear any effect of previous ICMP errors etc.
396  */
397  socket->so_state &= ~(SS_CONN_REFUSED | SS_CANTSENDMORE | SS_CANTRCVMORE);
398  socket->so_error = 0;
399 
400  lport = socket->udp_sock->myport;
401  grab_localport (lport);
402  }
403 #endif
404 
405  if (rdata) /* Must be SOCK_DGRAM */
406  {
407  _udp_Socket *udp = socket->udp_sock;
408 
409  /* free new rx-buffer set in connect() / _UDP_open().
410  */
411  DISABLE();
413  udp->rx_data = rdata; /* reuse previous data buffer */
414  ENABLE();
415 
416  grab_localport (lport); /* Restore free'd localport */
417  }
418 
419  /* restore keepalive timer changed in connect()
420  */
421  socket->keepalive = keepalive;
422  return (1);
423 }
424 
425 /*
426  * Check for enough room in Tx-buffer for a non-blocking socket
427  * to transmit without waiting. Only called for SOCK_DGRAM/SOCK_STREAM
428  * sockets.
429  *
430  * If '*len > room', modify '*len' on output to 'room' (the size of
431  * bytes left in Tx-buf).
432  */
433 static __inline BOOL check_non_block_tx (Socket *socket, unsigned *len)
434 {
435  sock_type *sk;
436  unsigned room;
437 
438  if (socket->so_type == SOCK_DGRAM)
439  sk = (sock_type*) socket->udp_sock;
440  else sk = (sock_type*) socket->tcp_sock;
441 
442  room = sock_tbleft (sk);
443  if (*len <= room)
444  return (TRUE); /* okay, enough room, '*len' unmodified */
445 
446 #if 0
447  WATT_YIELD(); /* a small delay to clear up things */
448  tcp_tick (sk);
449 
450  room = sock_tbleft (sk);
451  if (*len <= room)
452  return (TRUE);
453 #endif
454 
455  /* Still no room, but cannot split up datagrams (only in IP-fragments)
456  */
457  if (socket->so_type == SOCK_DGRAM)
458  return (FALSE);
459 
460  /* Stream: Tx room below (or equal) low-water mark is failure.
461  */
462  if (*len > 0 && room <= socket->send_lowat)
463  return (FALSE);
464 
465  /* Streams may be split up, modify '*len'
466  */
467  *len = room;
468  return (TRUE);
469 }
470 
471 /*
472  * TCP transmitter.
473  */
474 static int tcp_transmit (Socket *socket, const void *buf, unsigned len,
475  int flags)
476 {
477  sock_type *sk = (sock_type*)socket->tcp_sock;
478  int rc;
479 
480  /* Don't timeout BSD sockets on inactivity (not sending)
481  */
482  sk->tcp.datatimer = 0;
483 
484  tcp_tick (sk);
485  tcp_Retransmitter (TRUE);
486 
489  if (sk->tcp.state < tcp_StateESTAB || sk->tcp.state >= tcp_StateLASTACK)
490  {
491  socket->so_state |= SS_CANTSENDMORE;
492  SOCK_DEBUGF ((", EPIPE"));
493  SOCK_ERRNO (EPIPE); /* !! was ENOTCONN */
494  return (-1);
495  }
496 
497  if (socket->so_state & SS_NBIO)
498  {
499  unsigned in_len = len;
500 
501  if (!check_non_block_tx(socket,&len))
502  {
503  SOCK_DEBUGF ((", EWOULDBLOCK"));
504  SOCK_ERRNO (EWOULDBLOCK);
505  return (-1);
506  }
507  if (in_len != len)
508  SOCK_DEBUGF ((" [%u]", len)); /* trace "len=x [y]" */
509  }
510 
511 #if defined(USE_IPV6)
512  if (socket->so_family == AF_INET6)
513  {
514  struct sockaddr_in6 *ra = (struct sockaddr_in6*) socket->remote_addr;
515 
516  SOCK_DEBUGF ((", %s (%d) / TCP",
517  _inet6_ntoa(&ra->sin6_addr),
518  ntohs(socket->remote_addr->sin_port)));
519  ARGSUSED (ra);
520  }
521  else
522 #endif
523  SOCK_DEBUGF ((", %s (%d) / TCP",
524  inet_ntoa(socket->remote_addr->sin_addr),
525  ntohs(socket->remote_addr->sin_port)));
526 
527 #if 0
528  if (len > sizof(sk->tcp.max_tx_data) - 1)
529  {
530  unsigned total = len;
531  BYTE *buffer = (BYTE*)buf;
532 
533  while (1)
534  {
535  if (sock_tbused(sk) == 0) /* Tx buffer empty */
536  {
537  unsigned bytes = min (sk->tcp.max_tx_data, total);
538 
539  if (bytes > 0)
540  {
541  buffer += sock_enqueue (sk, buffer, bytes);
542  total -= bytes;
543  }
544  else
545  break;
546  }
547  if (!tcp_tick(sk))
548  break;
549  }
550  rc = buffer - (BYTE*)buf;
551  }
552  else
553 #endif
554  rc = sock_write (sk, (const BYTE*)buf, len);
555 
556  socket->keepalive = 0UL;
557 
558  if (rc <= 0) /* error in tcp_write() */
559  {
560  if (sk->tcp.locflags & LF_GOT_ICMP) /* got ICMP host/port unreachable */
561  {
562  SOCK_DEBUGF ((", ECONNREFUSED")); /* !! a better code? */
563  SOCK_ERRNO (ECONNREFUSED);
564  }
565  else if (sk->tcp.state != tcp_StateESTAB)
566  {
567  SOCK_DEBUGF ((", EPIPE"));
568  SOCK_ERRNO (EPIPE); /* !! was ENOTCONN */
569  }
570  else
571  {
572  SOCK_DEBUGF ((", ENETDOWN"));
573  SOCK_ERRNO (ENETDOWN);
574  }
575  return (-1);
576  }
577  ARGSUSED (flags);
578  return (rc);
579 }
580 
581 
582 /*
583  * UDP transmitter
584  */
585 static int udp_transmit (Socket *socket, const void *buf, unsigned len)
586 {
587  sock_type *sk = (sock_type*) socket->udp_sock;
588  BOOL is_ip6 = (socket->so_family == AF_INET6);
589  BOOL is_bcast, is_mcast;
590  unsigned tx_room;
591  int rc;
592  const void *dest;
593 
594  if (!tcp_tick(sk))
595  {
596  socket->so_state |= SS_CANTSENDMORE;
597  SOCK_DEBUGF ((", EPIPE (can't send)"));
598  SOCK_ERRNO (EPIPE); /* !! was ENOTCONN */
599  return (-1);
600  }
601 
602  tcp_Retransmitter (TRUE);
603 
604  if ((socket->so_state & SS_NBIO) &&
605  !check_non_block_tx(socket,&len))
606  {
607  SOCK_DEBUGF ((", EWOULDBLOCK"));
608  SOCK_ERRNO (EWOULDBLOCK);
609  return (-1);
610  }
611 
612 #if defined(USE_IPV6)
613  if (is_ip6)
614  {
615  const struct sockaddr_in6 *ra = (const struct sockaddr_in6*)socket->remote_addr;
616 
617  dest = &ra->sin6_addr.s6_addr[0];
618  is_bcast = IN6_IS_ADDR_MC_GLOBAL (dest);
619  is_mcast = IN6_IS_ADDR_MULTICAST (dest);
620 
621  SOCK_DEBUGF ((", %s (%d) / UDP %s", _inet6_ntoa(dest),
622  ntohs(socket->remote_addr->sin_port),
623  is_mcast ? "(mcast)" : ""));
624  }
625  else
626 #endif
627  {
628  dest = &socket->remote_addr->sin_addr.s_addr;
629  is_bcast = (*(DWORD*)dest == INADDR_BROADCAST ||
630  *(DWORD*)dest == INADDR_ANY);
631  is_mcast = IN_MULTICAST (ntohl(*(DWORD*)dest));
632 
633  SOCK_DEBUGF ((", %s (%d) / UDP %s",
634  inet_ntoa(*(struct in_addr*)dest),
635  ntohs(socket->remote_addr->sin_port),
636  is_mcast ? "(mcast)" : ""));
637  }
638 
639  if (len == 0) /* 0-byte probe packet */
640  return raw_transmit (socket, NULL, 0);
641 
642  tx_room = sock_tbleft (sk); /* always MTU-28 */
643 
644  /* Special tests for broadcast messages
645  */
646  if (is_bcast)
647  {
648  if (len > tx_room) /* no room, fragmented broadcasts not allowed */
649  {
650  SOCK_DEBUGF ((", EMSGSIZE"));
651  SOCK_ERRNO (EMSGSIZE);
652  goto drop;
653  }
654  if (_pktserial) /* Link-layer doesn't allow broadcast */
655  {
656  SOCK_DEBUGF ((", EADDRNOTAVAIL"));
657  SOCK_ERRNO (EADDRNOTAVAIL);
658  goto drop;
659  }
660  }
661 
662  /* set new TTL if setsockopt() used before sending to Class-D socket
663  */
664  if (is_mcast)
665  udp_SetTTL (socket->udp_sock, socket->ip_ttl);
666 
667 #if defined(USE_FRAGMENTS)
668  if (len > USHRT_MAX - sizeof(udp_Header))
669  {
670  SOCK_DEBUGF ((", EMSGSIZE"));
671  SOCK_ERRNO (EMSGSIZE);
672  if (!is_ip6)
673  STAT (ip4stats.ips_toolong++);
674  return (-1);
675  }
676 
677  if (!is_ip6 && len > tx_room)
678  return _IP4_SEND_FRAGMENTS (sk, UDP_PROTO, *(DWORD*)dest, buf, len);
679 #endif
680 
681  sk->udp.hisaddr = ntohl (socket->remote_addr->sin_addr.s_addr);
682  sk->udp.hisport = ntohs (socket->remote_addr->sin_port);
683 
684  rc = sock_write (sk, (BYTE*)buf, len);
685 
686  /* Patch hisaddr/hisport so that udp_demux() will handle further
687  * traffic as broadcast.
688  */
689  if (socket->so_state & SS_PRIV)
690  {
691  sk->udp.hisaddr = INADDR_BROADCAST;
692  sk->udp.hisport = IPPORT_ANY;
693  }
694 
695  if (rc <= 0) /* error in udp_write() */
696  {
697  if (sk->udp.locflags & LF_GOT_ICMP)
698  {
699  SOCK_DEBUGF ((", ECONNREFUSED"));
700  SOCK_ERRNO (ECONNREFUSED);
701  }
702  else
703  {
704  SOCK_DEBUGF ((", ENETDOWN"));
705  SOCK_ERRNO (ENETDOWN);
706  }
707  return (-1);
708  }
709  return (rc);
710 
711 drop:
712  if (is_ip6)
713  STAT (ip6stats.ip6s_odropped++);
714  else STAT (ip4stats.ips_odropped++);
715  return (-1);
716 }
717 
724 static int ip4_transmit (Socket *socket, const void *tx, unsigned len)
725 {
726  eth_address eth;
727  u_long dest;
728  unsigned tx_len, tx_room;
729  sock_type *sk = (sock_type*) socket->raw_sock;
730  struct ip *ip = (struct ip*) tx;
731  const BYTE *buf = (const BYTE*) tx;
732  UINT h_len, o_len;
733 
734  if (ip) /* NULL if called from udp_transmit() */
735  {
736  if ((socket->so_state & SS_NBIO) &&
737  sock_tbleft(sk) < (len + socket->send_lowat))
738  {
739  SOCK_DEBUGF ((", EWOULDBLOCK"));
740  SOCK_ERRNO (EWOULDBLOCK);
741  return (-1);
742  }
743  }
744 
745  SOCK_DEBUGF ((", %s / Raw", inet_ntoa(socket->remote_addr->sin_addr)));
746 
747  if (ip && (socket->inp_flags & INP_HDRINCL))
748  {
749  dest = ip->ip_dst.s_addr;
750  tx_len = len;
751  tx_room = _mtu;
752  }
753  else
754  {
755  dest = socket->remote_addr->sin_addr.s_addr;
756  tx_len = len + sizeof (*ip);
757  tx_room = _mtu + sizeof (*ip);
758  }
759 
760  if (socket->ip_opt &&
761  socket->ip_opt->ip_dst.s_addr) /* using source routing */
762  dest = socket->ip_opt->ip_dst.s_addr;
763 
764  if (!dest)
765  {
766  SOCK_DEBUGF ((", no dest"));
767  SOCK_ERRNO (EHOSTUNREACH);
768  STAT (ip4stats.ips_noroute++);
769  return (-1);
770  }
771 
772  if (!_arp_resolve(ntohl(dest),&eth))
773  {
774  SOCK_DEBUGF ((", no route"));
775  SOCK_ERRNO (EHOSTUNREACH);
776  return (-1);
777  }
778 
779  if (socket->inp_flags & INP_HDRINCL) /* IP-header included */
780  {
781  DWORD offset = ntohs (ip->ip_off);
782  WORD flags = (WORD) (offset & ~IP_OFFMASK);
783 
784  offset = (offset & IP_OFFMASK) << 3; /* 0 <= ip_ofs <= 65536-8 */
785 
786  if ((flags & IP_DF) && /* DF requested */
787  tx_len > tx_room) /* tx-size above MTU */
788  {
789  SOCK_DEBUGF ((", EMSGSIZE"));
790  SOCK_ERRNO (EMSGSIZE);
791  STAT (ip4stats.ips_toolong++);
792  return (-1);
793  }
794  }
795  else if (tx_len + socket->ip_opt_len > tx_room) /* tx-size above MTU */
796 #if defined(USE_FRAGMENTS)
797  {
798  if (socket->ip_opt_len > 0)
799  ((void)0);
800  return _IP4_SEND_FRAGMENTS (sk, socket->so_proto, dest, buf, len);
801  }
802 #else
803  {
804  SOCK_DEBUGF ((", EMSGSIZE"));
805  SOCK_ERRNO (EMSGSIZE);
806  STAT (ip4stats.ips_toolong++);
807  return (-1);
808  }
809 #endif
810 
811 
812  /* "Normal" small (tx_len < MTU) IPv4 packets are sent below
813  */
814  ip = (struct ip*) _eth_formatpacket (&eth, IP4_TYPE);
815 
816  if (socket->inp_flags & INP_HDRINCL) /* caller provided IP-header */
817  {
818  memcpy (ip, buf, len); /* SOCK_RAW can never have 0 length */
819  if (ip->ip_src.s_addr == 0)
820  {
821  ip->ip_src.s_addr = gethostid();
822  ip->ip_sum = 0;
823  ip->ip_sum = ~CHECKSUM ((void*)ip, ip->ip_hl << 2);
824  }
825  if (ip->ip_sum == 0) /* add header checksum if needed */
826  ip->ip_sum = ~CHECKSUM ((void*)ip, ip->ip_hl << 2);
827  }
828  else
829  {
830  if (socket->ip_opt && socket->ip_opt_len > 0)
831  {
832  BYTE *data;
833 
834  o_len = min (socket->ip_opt_len, sizeof(socket->ip_opt->IP_opts));
835  h_len = sizeof(*ip) + o_len;
836  data = (BYTE*)ip + h_len;
837  memcpy (ip+1, &socket->ip_opt->IP_opts[0], o_len);
838  if (buf && len > 0)
839  memcpy (data, buf, len);
840  tx_len += o_len;
841  }
842  else
843  {
844  if (buf && len > 0)
845  memcpy (ip+1, buf, len);
846  h_len = sizeof (*ip);
847  }
848 
849  ip->ip_v = IPVERSION;
850  ip->ip_hl = h_len >> 2;
851  ip->ip_tos = socket->ip_tos;
852  ip->ip_len = htons (tx_len);
853  ip->ip_id = _get_ip4_id();
854  ip->ip_off = 0;
855  ip->ip_ttl = socket->ip_ttl;
856  ip->ip_p = socket->so_proto;
857 
858  ip->ip_src.s_addr = gethostid();
859  ip->ip_dst.s_addr = dest;
860 
861  ip->ip_sum = 0;
862  ip->ip_sum = ~CHECKSUM (ip, h_len);
863  }
864 
865  if (!_eth_send (tx_len, NULL, __FILE__, __LINE__))
866  {
867  SOCK_DEBUGF ((", ENETDOWN"));
868  SOCK_ERRNO (ENETDOWN);
869  return (-1);
870  }
871  return (len);
872 }
873 
874 #if defined(USE_IPV6)
875 
881 static int ip6_transmit (Socket *socket, const void *tx, unsigned len)
882 {
883  eth_address eth;
884  ip6_address dest;
885  unsigned tx_len, tx_room;
886 
887  sock_type *sk = (sock_type*) socket->raw_sock;
888  struct in6_Header *ip6 = (struct in6_Header*) tx;
889  struct sockaddr_in6 *ra = (struct sockaddr_in6*) socket->remote_addr;
890  const BYTE *buf = (const BYTE*) tx;
891 
892  if ((socket->so_state & SS_NBIO) &&
893  sock_tbleft(sk) < (len + socket->send_lowat))
894  {
895  SOCK_DEBUGF ((", EWOULDBLOCK"));
896  SOCK_ERRNO (EWOULDBLOCK);
897  return (-1);
898  }
899 
900  SOCK_DEBUGF ((", %s / Raw", _inet6_ntoa(&ra->sin6_addr)));
901 
902  if (ip6 && (socket->inp_flags & INP_HDRINCL))
903  {
904  memcpy (dest, &ip6->destination[0], sizeof(dest));
905  tx_len = len;
906  tx_room = _mtu;
907  }
908  else
909  {
910  memcpy (dest, &ra->sin6_addr, sizeof(dest));
911  tx_len = len + sizeof (*ip6);
912  tx_room = _mtu + sizeof (*ip6);
913  }
914 
915  if (IN6_IS_ADDR_UNSPECIFIED(&dest) || !icmp6_neigh_solic(&dest,&eth))
916  {
917  SOCK_DEBUGF ((", no route"));
918  SOCK_ERRNO (EHOSTUNREACH);
919  STAT (ip6stats.ip6s_noroute++);
920  return (-1);
921  }
922 
923  if (!(socket->inp_flags & INP_HDRINCL) &&
924  tx_len + socket->ip_opt_len > tx_room)
925  {
926  SOCK_DEBUGF ((", EMSGSIZE"));
927  SOCK_ERRNO (EMSGSIZE);
928  STAT (ip6stats.ip6s_odropped++);
929  return (-1);
930  }
931 
932  ip6 = (struct in6_Header*) _eth_formatpacket (&eth, IP6_TYPE);
933 
934  if (socket->inp_flags & INP_HDRINCL)
935  {
936  if (buf && len > 0)
937  memcpy (ip6, buf, len);
938  if (IN6_IS_ADDR_UNSPECIFIED(&ip6->source))
939  memcpy (&ip6->source[0], _gethostid6(), sizeof(ip6->source));
940  }
941  else
942  {
943 #if 0 /* option header not yet supported */
944  if (socket->ip_opt && socket->ip_opt_len > 0)
945  {
946  BYTE *data;
947  int h_len;
948 
949  o_len = min (socket->ip_opt_len, sizeof(socket->ip_opt->ip_opts));
950  h_len = sizeof(*ip) + o_len;
951  data = (BYTE*)ip + h_len;
952  memcpy (ip+1, &socket->ip_opt->ip_opts, o_len);
953  if (buf && len > 0)
954  memcpy (data, buf, len);
955  tx_len += o_len;
956  if (socket->ip_opt->ip_dst.s_addr) /* using source routing */
957  dest = socket->ip_opt->ip_dst.s_addr;
958  }
959  else
960 #endif
961  {
962  if (buf && len > 0)
963  memcpy (ip6+1, buf, len);
964  }
965  ip6->pri = 0;
966  ip6->ver = 6;
967  ip6->len = htons (len);
968  ip6->next_hdr = socket->so_proto;
969  ip6->hop_limit = _default_ttl;
970 
971  memset (&ip6->flow_lbl[0], 0, sizeof(ip6->flow_lbl));
972  memcpy (&ip6->source[0], _gethostid6(), sizeof(ip6->source));
973  memcpy (&ip6->destination[0], dest, sizeof(ip6->destination));
974  }
975 
976  if (!_eth_send (tx_len, NULL, __FILE__, __LINE__))
977  {
978  SOCK_DEBUGF ((", ENETDOWN"));
979  SOCK_ERRNO (ENETDOWN);
980  return (-1);
981  }
982  return (len);
983 }
984 #endif /* USE_IPV6 */
985 
986 
987 static int raw_transmit (Socket *socket, const void *buf, unsigned len)
988 {
989 #if 0
990  SOCK_ENTER_SCOPE();
991  tcp_tick (NULL); /* process other TCBs too */
992  tcp_Retransmitter (TRUE);
993  SOCK_LEAVE_SCOPE();
994 #endif
995 
996 #if defined(USE_IPV6)
997  if (socket->so_family == AF_INET6)
998  return ip6_transmit (socket, buf, len);
999 #endif
1000 
1001  if (socket->so_family == AF_INET)
1002  return ip4_transmit (socket, buf, len);
1003 
1004  SOCK_DEBUGF ((", EAFNOSUPPORT "));
1005  SOCK_ERRNO (EAFNOSUPPORT );
1006  return (-1);
1007 }
1008 #endif /* USE_BSD_API */
int _default_ttl
Definition: ip4_out.c:54
int icmp6_neigh_solic(const void *addr, eth_address *eth)
Definition: pcicmp6.c:172
Definition: socket.h:137
Definition: socket.h:242
int W32_CALL sock_close(sock_type *s)
Close a UDP/TCP socket.
Definition: pctcp.c:3139
int W32_CALL _eth_send(WORD len, const void *sock, const char *file, unsigned line)
_eth_send() does the actual transmission once we are complete with filling the buffer.
Definition: pcsed.c:306
UINT max_tx_data
Last index for tx_data[].
Definition: wattcp.h:681
Definition: if.h:84
void _sock_free_rcv_buf(sock_type *s)
Free receive buffer associated with udp/tcp sockets.
Definition: socket.c:267
int W32_CALL sock_write(sock_type *s, const BYTE *data, int len)
Writes data and returns length written.
Definition: pctcp.c:2960
WORD _get_ip4_id(void)
Increment IPv4-identifier before returning it.
Definition: ip4_out.c:65
int W32_CALL udp_SetTTL(_udp_Socket *s, BYTE ttl)
Set the TTL on an outgoing UDP datagram.
Definition: pctcp.c:289
Socket * _socklist_find(int s)
Returns a pointer to the Socket structure associated with socket 's'.
Definition: socket.c:1534
BOOL _sock_dos_fd(int s)
_sock_dos_fd - Return TRUE if `s' is a valid DOS/Win32 handle.
Definition: socket.c:222
void *W32_CALL _eth_formatpacket(const void *mac_dest, WORD eth_type)
_eth_format_packet() places the next packet to be transmitted into the above link-layer output packet...
Definition: pcsed.c:135
const void * _gethostid6(void)
Core-style: Returns local IPv6-address.
Definition: bsdname.c:91
Definition: ip.h:67
XHOSTID_RETV W32_CALL gethostid(void)
BSD style: returns local IPv4-address.
Definition: bsdname.c:68
Definition: in.h:146
static int ip4_transmit(Socket *socket, const void *tx, unsigned len)
Raw IPv4 transmitter.
Definition: transmit.c:724
BOOL _pktserial
using serial driver, SLIP/PPP
Definition: pcpkt.c:54
Definition: wtypes.h:179
void tcp_Retransmitter(BOOL force)
Called periodically to perform retransmissions.
Definition: pctcp.c:1209
static int tcp_transmit(Socket *socket, const void *buf, unsigned len, int flags)
Definition: transmit.c:474
const char * _inet6_ntoa(const void *ip)
Convert an IPv6-address 'ip' into a string.
Definition: netaddr.c:401
DWORD datatimer
inactive timer (no Tx data)
Definition: wattcp.h:672
WORD W32_CALL tcp_tick(sock_type *s)
Must be called periodically by user application (or BSD socket API).
Definition: pctcp.c:1389
BOOL W32_CALL _arp_resolve(DWORD ip, eth_address *eth)
The blocking lookup function visible to higher functions.
Definition: pcarp.c:1279
static int ip6_transmit(Socket *socket, const void *tx, unsigned len)
Raw IPv6 transmitter.
Definition: transmit.c:881
int W32_CALL sock_enqueue(sock_type *s, const BYTE *data, int len)
For UDP, this function is same as sock_write().
Definition: pctcp.c:3044
UINT state
tcp connection state
Definition: wattcp.h:622