Watt-32 tcp/ip  2.2 dev-rel.10
ip4_out.c
Go to the documentation of this file.
1 
5 /* Copyright (c) 1997-2002 Gisle Vanem <gvanem@yahoo.no>
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  * notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  * notice, this list of conditions and the following disclaimer in the
14  * documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  * must display the following acknowledgement:
17  * This product includes software developed by Gisle Vanem
18  * Bergen, Norway.
19  *
20  * THIS SOFTWARE IS PROVIDED BY ME (Gisle Vanem) AND CONTRIBUTORS ``AS IS''
21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED. IN NO EVENT SHALL I OR CONTRIBUTORS BE LIABLE FOR ANY
24  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
27  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  *
31  * Version
32  *
33  * 1.0 : Apr 18, 1999 : G. Vanem - created
34  * 1.1 : Jan 29, 2000 : G. Vanem - added functions for
35  * handling list of IP-fragments.
36  */
37 
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <sys/socket.h>
42 
43 #include "wattcp.h"
44 #include "misc.h"
45 #include "chksum.h"
46 #include "pcdbug.h"
47 #include "pcsed.h"
48 #include "pctcp.h"
49 #include "pcstat.h"
50 #include "pcicmp.h"
51 #include "socket.h"
52 
53 BYTE _default_tos = 0; /* Type-Of-Service */
54 int _default_ttl = 254; /* TTL on outgoing packets */
55 int _ip4_id_increment = 1; /* Some stacks uses 5 */
56 BOOL _ip4_dont_frag = FALSE; /* Don't set DF bit on every packet */
57 
58 static WORD ip4_id = 0;
59 
65 WORD _get_ip4_id (void)
66 {
67  ip4_id += _ip4_id_increment;
68  return intel16 (ip4_id);
69 }
70 
74 WORD _get_this_ip4_id (void)
75 {
76  return intel16 (ip4_id);
77 }
78 
86 int _ip4_output (in_Header *ip, /* ip-structure to fill in */
87  DWORD src_ip, /* from address (network order!) */
88  DWORD dst_ip, /* dest address (network order!) */
89  BYTE protocol, /* IP-protocol number */
90  BYTE ttl, /* Time To Live */
91  BYTE tos, /* Type Of Service, 0 unspecified */
92  WORD ip_id, /* IP identification, normally 0 */
93  int data_len, /* length of data after ip header */
94  const void *sock, /* which socket is this */
95  const char *file, /* Debug: from what file */
96  unsigned line) /* and line was _ip4_output called */
97 {
98  int len = sizeof(*ip) + data_len;
99 
100  /*
101  * Note: the 'ip->frag_ofs' field isn't normally set here (it's
102  * cleared in eth_formatpacket() causing IP_DF bit to off).
103  * If sending fragments it's set in _ip4_send_fragments() below.
104  */
105 
106  if (src_ip == 0)
107  src_ip = intel (my_ip_addr);
108 
109  if (_ip4_dont_frag)
110  ip->frag_ofs |= intel16 (IP_DF);
111 
112  ip->ver = 4;
113  ip->hdrlen = sizeof(*ip) / 4;
114  ip->length = intel16 (len);
115  ip->tos = tos & IP_TOSMASK;
116  ip->ttl = ttl ? ttl : _default_ttl;
117  ip->identification = ip_id ? ip_id : _get_ip4_id();
118  ip->proto = protocol;
119  ip->source = src_ip;
120  ip->destination = dst_ip;
121  ip->checksum = 0;
122  ip->checksum = ~CHECKSUM (ip, sizeof(*ip));
123 
124  return _eth_send (len, sock, file, line);
125 }
126 
127 #if defined(USE_FRAGMENTS)
128 /*
129  * Note: host is on network order.
130  * No IP options supported here.
131  */
132 static __inline in_Header *make_ip_pkt (DWORD host, BOOL first, char **data)
133 {
134  eth_address dest;
135  in_Header *ip;
136 
137  if (first && !_arp_resolve(intel(host),&dest))
138  {
139  if (debug_on)
140  outsnl (_LANG("make_ip_pkt(): ARP failed"));
141  SOCK_DEBUGF ((", EHOSTUNREACH"));
142  SOCK_ERRNO (EHOSTUNREACH);
143  return (NULL);
144  }
145 
146  ip = (in_Header*) _eth_formatpacket (&dest, IP4_TYPE);
147  *data = (char*) (ip+1);
148  return (ip);
149 }
150 
151 /*
152  * \todo Handle IP/TCP options.
153  */
154 static in_Header *make_tcp_pkt (const _tcp_Socket *s,
155  BOOL first, char **data)
156 {
157  in_Header *ip = (in_Header*) _eth_formatpacket (&s->his_ethaddr, IP4_TYPE);
158 
159  if (first)
160  {
161  tcp_Header *tcp = (tcp_Header*) (ip+1);
162  tcp_PseudoHeader ph;
163  WORD tcp_len = sizeof(*tcp);
164 
165  tcp->srcPort = intel16 (s->myport);
166  tcp->dstPort = intel16 (s->hisport);
167  tcp->seqnum = intel (s->send_next + s->send_una);
168  tcp->acknum = intel (s->recv_next);
169  tcp->window = intel16 (s->max_rx_data - s->rx_datalen);
170  tcp->flags = (BYTE) s->flags;
171  tcp->unused = 0;
172  tcp->checksum = 0;
173  tcp->urgent = 0;
174  tcp->offset = tcp_len / 4;
175 
176  memset (&ph, 0, sizeof(ph));
177  ph.src = intel (s->myaddr);
178  ph.dst = intel (s->hisaddr);
179  ph.protocol = TCP_PROTO;
180  ph.length = intel16 (tcp_len);
181  ph.checksum = CHECKSUM (tcp, tcp_len);
182  tcp->checksum = ~CHECKSUM (&ph, sizeof(ph));
183  *data = (char*)tcp + sizeof(*tcp);
184  }
185  else
186  *data = (char*)(ip+1);
187 
188  return (ip);
189 }
190 
191 /*
192  * Note: We assume 's->his_ethaddr' is filled by udp_open() or udp_demux().
193  * I.e. socket is active and not a broadcast socket.
194  */
195 static __inline in_Header *make_udp_pkt (const _udp_Socket *s, BOOL first,
196  unsigned len, char **data)
197 {
198  in_Header *ip = (in_Header*) _eth_formatpacket (&s->his_ethaddr, IP4_TYPE);
199 
200  if (first)
201  {
202  udp_Header *udp = (udp_Header*) (ip+1);
203  tcp_PseudoHeader ph;
204 
205  udp->srcPort = intel16 (s->myport);
206  udp->dstPort = intel16 (s->hisport);
207  udp->checksum = 0;
208  udp->length = intel16 ((WORD)(sizeof(*udp) + len));
209  memset (&ph, 0, sizeof(ph));
210  ph.src = intel (s->myaddr);
211  ph.dst = intel (s->hisaddr);
212 
213  if (s->sockmode & SOCK_MODE_UDPCHK)
214  {
215  ph.protocol = UDP_PROTO;
216  ph.length = udp->length;
217  ph.checksum = CHECKSUM (udp, sizeof(*udp)) + CHECKSUM (*data, len);
218  udp->checksum = ~CHECKSUM (&ph, sizeof(ph));
219  }
220  *data = (char*)udp + sizeof(*udp);
221  }
222  else
223  *data = (char*)(ip+1);
224 
225  return (ip);
226 }
227 
228 
229 /*
230  * Sends a chain of IPv4 fragments for proto. `buf' is higher-level
231  * protocol (ICMP/UDP/TCP).
232  * Note: `dest' is on network order. This function is only called
233  * when we're sure fragment are needed; num_frags >= 1.
234  */
235 int _ip4_send_fragments (sock_type *s, BYTE proto, DWORD dest,
236  const void *buf, unsigned len,
237  const char *file, unsigned line)
238 {
239  int i, num_frags, rc = 0;
240  int frag_size, frag_ofs;
241  WORD ip_id;
242  WORD ip_max = _mtu - sizeof(in_Header);
243 
244  num_frags = len / ip_max;
245 
246  WATT_ASSERT (num_frags >= 1);
247 
248  if (len % ip_max)
249  num_frags++;
250 
251  /* Increment IP-identifier. Use same value for all fragments
252  */
253  ip_id = _get_ip4_id();
254 
257  for (frag_ofs = i = 0; i < num_frags; i++)
258  {
259  in_Header *ip = NULL;
260  char *data = (char*) buf;
261 
262  switch (proto)
263  {
264 #if 0
265  case IP4_TYPE: /* raw IP type (from ip4_transmit) */
266  proto = ((in_Header*)buf)->proto;
267  /* fall through */
268 #endif
269  case ICMP_PROTO:
270  ip = make_ip_pkt (dest, frag_ofs == 0, &data);
271  if (!ip)
272  return (-1);
273  break;
274 
275  case UDP_PROTO:
276  ip = make_udp_pkt (&s->udp, frag_ofs == 0, len, &data);
277  break;
278 
279  case TCP_PROTO:
280  if (s->tcp.state != tcp_StateESTAB)
281  return (0);
282  ip = make_tcp_pkt (&s->tcp, frag_ofs == 0, &data);
283  break;
284 
285  default:
286  TCP_CONSOLE_MSG (0, ("%s (%d): Illegal protocol %04X\n",
287  __FILE__, __LINE__, proto));
288  return (0);
289  }
290 
291  if (i == num_frags-1) /* last fragment */
292  {
293  frag_size = len;
294  ip->frag_ofs = intel16 (frag_ofs/8);
295  /* memset (data+frag_size-8, 0, len); */ /* padding */
296  }
297  else
298  {
299  frag_size = ip_max;
300  ip->frag_ofs = intel16 (frag_ofs/8 | IP_MF);
301  }
302 
303  memcpy (data, (const char*)buf + frag_ofs, frag_size);
304 
305  if (_ip4_output (ip, 0, dest, proto, 0, 0, ip_id, frag_size,
306  s, file, line) <= 0)
307  {
308  SOCK_DEBUGF ((", ENETDOWN"));
309  SOCK_ERRNO (ENETDOWN);
310  rc = -1;
311  break;
312  }
313  STAT (ip4stats.ips_ofragments++);
314 
315  frag_ofs += frag_size;
316  len -= frag_size;
317  rc += frag_size;
318  }
319 
320  tcp_tick (NULL); /* !! for viewing loopback trace */
321  return (rc);
322 }
323 #endif /* USE_FRAGMENTS */
324 
WORD flags
TCP flags used in next Tx.
Definition: wattcp.h:634
int _default_ttl
Definition: ip4_out.c:54
int _ip4_output(in_Header *ip, DWORD src_ip, DWORD dst_ip, BYTE protocol, BYTE ttl, BYTE tos, WORD ip_id, int data_len, const void *sock, const char *file, unsigned line)
The IP4 packet transmitter.
Definition: ip4_out.c:86
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
int _ip4_send_fragments(sock_type *s, BYTE proto, DWORD dest, const void *buf, unsigned len, const char *file, unsigned line)
Definition: ip4_out.c:235
long send_una
unacked send data, must be signed
Definition: wattcp.h:625
Core definitions.
WORD _get_ip4_id(void)
Increment IPv4-identifier before returning it.
Definition: ip4_out.c:65
BOOL _ip4_dont_frag
Definition: ip4_out.c:56
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
Definition: ip.h:67
int _ip4_id_increment
Definition: ip4_out.c:55
DWORD my_ip_addr
our IP address
Definition: pctcp.c:70
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
WORD _get_this_ip4_id(void)
Return IPv4-identifier but don't increment it.
Definition: ip4_out.c:74
DWORD recv_next
SEQ number we expect to receive.
Definition: wattcp.h:623
DWORD send_next
SEQ we send but not ACK-ed by peer.
Definition: wattcp.h:624
BYTE _default_tos
Definition: ip4_out.c:53
UINT state
tcp connection state
Definition: wattcp.h:622