]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/ipv4/ip.c
Add FreeRTOS-Plus directory.
[freertos] / FreeRTOS / Demo / Common / ethernet / lwIP_130 / src / core / ipv4 / ip.c
1 /**\r
2  * @file\r
3  * This is the IPv4 layer implementation for incoming and outgoing IP traffic.\r
4  *\r
5  * @see ip_frag.c\r
6  *\r
7  */\r
8 \r
9 /*\r
10  * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
11  * All rights reserved.\r
12  *\r
13  * Redistribution and use in source and binary forms, with or without modification,\r
14  * are permitted provided that the following conditions are met:\r
15  *\r
16  * 1. Redistributions of source code must retain the above copyright notice,\r
17  *    this list of conditions and the following disclaimer.\r
18  * 2. Redistributions in binary form must reproduce the above copyright notice,\r
19  *    this list of conditions and the following disclaimer in the documentation\r
20  *    and/or other materials provided with the distribution.\r
21  * 3. The name of the author may not be used to endorse or promote products\r
22  *    derived from this software without specific prior written permission.\r
23  *\r
24  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
25  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
26  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
27  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
28  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
29  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
30  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
31  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
32  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
33  * OF SUCH DAMAGE.\r
34  *\r
35  * This file is part of the lwIP TCP/IP stack.\r
36  *\r
37  * Author: Adam Dunkels <adam@sics.se>\r
38  *\r
39  */\r
40 \r
41 #include "lwip/opt.h"\r
42 #include "lwip/ip.h"\r
43 #include "lwip/def.h"\r
44 #include "lwip/mem.h"\r
45 #include "lwip/ip_frag.h"\r
46 #include "lwip/inet.h"\r
47 #include "lwip/inet_chksum.h"\r
48 #include "lwip/netif.h"\r
49 #include "lwip/icmp.h"\r
50 #include "lwip/igmp.h"\r
51 #include "lwip/raw.h"\r
52 #include "lwip/udp.h"\r
53 #include "lwip/tcp.h"\r
54 #include "lwip/snmp.h"\r
55 #include "lwip/dhcp.h"\r
56 #include "lwip/stats.h"\r
57 #include "arch/perf.h"\r
58 \r
59 /**\r
60  * Finds the appropriate network interface for a given IP address. It\r
61  * searches the list of network interfaces linearly. A match is found\r
62  * if the masked IP address of the network interface equals the masked\r
63  * IP address given to the function.\r
64  *\r
65  * @param dest the destination IP address for which to find the route\r
66  * @return the netif on which to send to reach dest\r
67  */\r
68 struct netif *\r
69 ip_route(struct ip_addr *dest)\r
70 {\r
71   struct netif *netif;\r
72 \r
73   /* iterate through netifs */\r
74   for(netif = netif_list; netif != NULL; netif = netif->next) {\r
75     /* network mask matches? */\r
76     if (netif_is_up(netif)) {\r
77       if (ip_addr_netcmp(dest, &(netif->ip_addr), &(netif->netmask))) {\r
78         /* return netif on which to forward IP packet */\r
79         return netif;\r
80       }\r
81     }\r
82   }\r
83   if ((netif_default == NULL) || (!netif_is_up(netif_default))) {\r
84     LWIP_DEBUGF(IP_DEBUG | 2, ("ip_route: No route to 0x%"X32_F"\n", dest->addr));\r
85     IP_STATS_INC(ip.rterr);\r
86     snmp_inc_ipoutnoroutes();\r
87     return NULL;\r
88   }\r
89   /* no matching netif found, use default netif */\r
90   return netif_default;\r
91 }\r
92 \r
93 #if IP_FORWARD\r
94 /**\r
95  * Forwards an IP packet. It finds an appropriate route for the\r
96  * packet, decrements the TTL value of the packet, adjusts the\r
97  * checksum and outputs the packet on the appropriate interface.\r
98  *\r
99  * @param p the packet to forward (p->payload points to IP header)\r
100  * @param iphdr the IP header of the input packet\r
101  * @param inp the netif on which this packet was received\r
102  * @return the netif on which the packet was sent (NULL if it wasn't sent)\r
103  */\r
104 static struct netif *\r
105 ip_forward(struct pbuf *p, struct ip_hdr *iphdr, struct netif *inp)\r
106 {\r
107   struct netif *netif;\r
108 \r
109   PERF_START;\r
110   /* Find network interface where to forward this IP packet to. */\r
111   netif = ip_route((struct ip_addr *)&(iphdr->dest));\r
112   if (netif == NULL) {\r
113     LWIP_DEBUGF(IP_DEBUG, ("ip_forward: no forwarding route for 0x%"X32_F" found\n",\r
114                       iphdr->dest.addr));\r
115     snmp_inc_ipoutnoroutes();\r
116     return (struct netif *)NULL;\r
117   }\r
118   /* Do not forward packets onto the same network interface on which\r
119    * they arrived. */\r
120   if (netif == inp) {\r
121     LWIP_DEBUGF(IP_DEBUG, ("ip_forward: not bouncing packets back on incoming interface.\n"));\r
122     snmp_inc_ipoutnoroutes();\r
123     return (struct netif *)NULL;\r
124   }\r
125 \r
126   /* decrement TTL */\r
127   IPH_TTL_SET(iphdr, IPH_TTL(iphdr) - 1);\r
128   /* send ICMP if TTL == 0 */\r
129   if (IPH_TTL(iphdr) == 0) {\r
130     snmp_inc_ipinhdrerrors();\r
131 #if LWIP_ICMP\r
132     /* Don't send ICMP messages in response to ICMP messages */\r
133     if (IPH_PROTO(iphdr) != IP_PROTO_ICMP) {\r
134       icmp_time_exceeded(p, ICMP_TE_TTL);\r
135     }\r
136 #endif /* LWIP_ICMP */\r
137     return (struct netif *)NULL;\r
138   }\r
139 \r
140   /* Incrementally update the IP checksum. */\r
141   if (IPH_CHKSUM(iphdr) >= htons(0xffff - 0x100)) {\r
142     IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + htons(0x100) + 1);\r
143   } else {\r
144     IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + htons(0x100));\r
145   }\r
146 \r
147   LWIP_DEBUGF(IP_DEBUG, ("ip_forward: forwarding packet to 0x%"X32_F"\n",\r
148                     iphdr->dest.addr));\r
149 \r
150   IP_STATS_INC(ip.fw);\r
151   IP_STATS_INC(ip.xmit);\r
152   snmp_inc_ipforwdatagrams();\r
153 \r
154   PERF_STOP("ip_forward");\r
155   /* transmit pbuf on chosen interface */\r
156   netif->output(netif, p, (struct ip_addr *)&(iphdr->dest));\r
157   return netif;\r
158 }\r
159 #endif /* IP_FORWARD */\r
160 \r
161 /**\r
162  * This function is called by the network interface device driver when\r
163  * an IP packet is received. The function does the basic checks of the\r
164  * IP header such as packet size being at least larger than the header\r
165  * size etc. If the packet was not destined for us, the packet is\r
166  * forwarded (using ip_forward). The IP checksum is always checked.\r
167  *\r
168  * Finally, the packet is sent to the upper layer protocol input function.\r
169  *\r
170  * @param p the received IP packet (p->payload points to IP header)\r
171  * @param inp the netif on which this packet was received\r
172  * @return ERR_OK if the packet was processed (could return ERR_* if it wasn't\r
173  *         processed, but currently always returns ERR_OK)\r
174  */\r
175 err_t\r
176 ip_input(struct pbuf *p, struct netif *inp)\r
177 {\r
178   struct ip_hdr *iphdr;\r
179   struct netif *netif;\r
180   u16_t iphdr_hlen;\r
181   u16_t iphdr_len;\r
182 #if LWIP_DHCP\r
183   int check_ip_src=1;\r
184 #endif /* LWIP_DHCP */\r
185 \r
186   IP_STATS_INC(ip.recv);\r
187   snmp_inc_ipinreceives();\r
188 \r
189   /* identify the IP header */\r
190   iphdr = p->payload;\r
191   if (IPH_V(iphdr) != 4) {\r
192     LWIP_DEBUGF(IP_DEBUG | 1, ("IP packet dropped due to bad version number %"U16_F"\n", IPH_V(iphdr)));\r
193     ip_debug_print(p);\r
194     pbuf_free(p);\r
195     IP_STATS_INC(ip.err);\r
196     IP_STATS_INC(ip.drop);\r
197     snmp_inc_ipinhdrerrors();\r
198     return ERR_OK;\r
199   }\r
200 \r
201   /* obtain IP header length in number of 32-bit words */\r
202   iphdr_hlen = IPH_HL(iphdr);\r
203   /* calculate IP header length in bytes */\r
204   iphdr_hlen *= 4;\r
205   /* obtain ip length in bytes */\r
206   iphdr_len = ntohs(IPH_LEN(iphdr));\r
207 \r
208   /* header length exceeds first pbuf length, or ip length exceeds total pbuf length? */\r
209   if ((iphdr_hlen > p->len) || (iphdr_len > p->tot_len)) {\r
210     if (iphdr_hlen > p->len)\r
211     LWIP_DEBUGF(IP_DEBUG | 2, ("IP header (len %"U16_F") does not fit in first pbuf (len %"U16_F"), IP packet dropped.\n",\r
212                                iphdr_hlen, p->len));\r
213     if (iphdr_len > p->tot_len)\r
214     LWIP_DEBUGF(IP_DEBUG | 2, ("IP (len %"U16_F") is longer than pbuf (len %"U16_F"), "\r
215                                "IP packet dropped.\n",\r
216                                iphdr_len, p->tot_len));\r
217     /* free (drop) packet pbufs */\r
218     pbuf_free(p);\r
219     IP_STATS_INC(ip.lenerr);\r
220     IP_STATS_INC(ip.drop);\r
221     snmp_inc_ipindiscards();\r
222     return ERR_OK;\r
223   }\r
224 \r
225   /* verify checksum */\r
226 #if CHECKSUM_CHECK_IP\r
227   if (inet_chksum(iphdr, iphdr_hlen) != 0) {\r
228 \r
229     LWIP_DEBUGF(IP_DEBUG | 2, ("Checksum (0x%"X16_F") failed, IP packet dropped.\n", inet_chksum(iphdr, iphdr_hlen)));\r
230     ip_debug_print(p);\r
231     pbuf_free(p);\r
232     IP_STATS_INC(ip.chkerr);\r
233     IP_STATS_INC(ip.drop);\r
234     snmp_inc_ipinhdrerrors();\r
235     return ERR_OK;\r
236   }\r
237 #endif\r
238 \r
239   /* Trim pbuf. This should have been done at the netif layer,\r
240    * but we'll do it anyway just to be sure that its done. */\r
241   pbuf_realloc(p, iphdr_len);\r
242 \r
243   /* match packet against an interface, i.e. is this packet for us? */\r
244 #if LWIP_IGMP\r
245   if (ip_addr_ismulticast(&(iphdr->dest))) {\r
246     if ((inp->flags & NETIF_FLAG_IGMP) && (igmp_lookfor_group(inp, &(iphdr->dest)))) {\r
247       netif = inp;\r
248     } else {\r
249       netif = NULL;\r
250     }\r
251   } else\r
252 #endif /* LWIP_IGMP */\r
253   {\r
254     /* start trying with inp. if that's not acceptable, start walking the\r
255        list of configured netifs.\r
256        'first' is used as a boolean to mark whether we started walking the list */\r
257     int first = 1;\r
258     netif = inp;\r
259     do {\r
260       LWIP_DEBUGF(IP_DEBUG, ("ip_input: iphdr->dest 0x%"X32_F" netif->ip_addr 0x%"X32_F" (0x%"X32_F", 0x%"X32_F", 0x%"X32_F")\n",\r
261           iphdr->dest.addr, netif->ip_addr.addr,\r
262           iphdr->dest.addr & netif->netmask.addr,\r
263           netif->ip_addr.addr & netif->netmask.addr,\r
264           iphdr->dest.addr & ~(netif->netmask.addr)));\r
265 \r
266       /* interface is up and configured? */\r
267       if ((netif_is_up(netif)) && (!ip_addr_isany(&(netif->ip_addr)))) {\r
268         /* unicast to this interface address? */\r
269         if (ip_addr_cmp(&(iphdr->dest), &(netif->ip_addr)) ||\r
270             /* or broadcast on this interface network address? */\r
271             ip_addr_isbroadcast(&(iphdr->dest), netif)) {\r
272           LWIP_DEBUGF(IP_DEBUG, ("ip_input: packet accepted on interface %c%c\n",\r
273               netif->name[0], netif->name[1]));\r
274           /* break out of for loop */\r
275           break;\r
276         }\r
277       }\r
278       if (first) {\r
279         first = 0;\r
280         netif = netif_list;\r
281       } else {\r
282         netif = netif->next;\r
283       }\r
284       if (netif == inp) {\r
285         netif = netif->next;\r
286       }\r
287     } while(netif != NULL);\r
288   }\r
289 \r
290 #if LWIP_DHCP\r
291   /* Pass DHCP messages regardless of destination address. DHCP traffic is addressed\r
292    * using link layer addressing (such as Ethernet MAC) so we must not filter on IP.\r
293    * According to RFC 1542 section 3.1.1, referred by RFC 2131).\r
294    */\r
295   if (netif == NULL) {\r
296     /* remote port is DHCP server? */\r
297     if (IPH_PROTO(iphdr) == IP_PROTO_UDP) {\r
298       LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE | 1, ("ip_input: UDP packet to DHCP client port %"U16_F"\n",\r
299         ntohs(((struct udp_hdr *)((u8_t *)iphdr + iphdr_hlen))->dest)));\r
300       if (ntohs(((struct udp_hdr *)((u8_t *)iphdr + iphdr_hlen))->dest) == DHCP_CLIENT_PORT) {\r
301         LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE | 1, ("ip_input: DHCP packet accepted.\n"));\r
302         netif = inp;\r
303         check_ip_src = 0;\r
304       }\r
305     }\r
306   }\r
307 #endif /* LWIP_DHCP */\r
308 \r
309   /* broadcast or multicast packet source address? Compliant with RFC 1122: 3.2.1.3 */\r
310 #if LWIP_DHCP\r
311   if (check_ip_src)\r
312 #endif /* LWIP_DHCP */\r
313   {  if ((ip_addr_isbroadcast(&(iphdr->src), inp)) ||\r
314          (ip_addr_ismulticast(&(iphdr->src)))) {\r
315       /* packet source is not valid */\r
316       LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE | 1, ("ip_input: packet source is not valid.\n"));\r
317       /* free (drop) packet pbufs */\r
318       pbuf_free(p);\r
319       IP_STATS_INC(ip.drop);\r
320       snmp_inc_ipinaddrerrors();\r
321       snmp_inc_ipindiscards();\r
322       return ERR_OK;\r
323     }\r
324   }\r
325 \r
326   /* packet not for us? */\r
327   if (netif == NULL) {\r
328     /* packet not for us, route or discard */\r
329     LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE | 1, ("ip_input: packet not for us.\n"));\r
330 #if IP_FORWARD\r
331     /* non-broadcast packet? */\r
332     if (!ip_addr_isbroadcast(&(iphdr->dest), inp)) {\r
333       /* try to forward IP packet on (other) interfaces */\r
334       ip_forward(p, iphdr, inp);\r
335     } else\r
336 #endif /* IP_FORWARD */\r
337     {\r
338       snmp_inc_ipinaddrerrors();\r
339       snmp_inc_ipindiscards();\r
340     }\r
341     pbuf_free(p);\r
342     return ERR_OK;\r
343   }\r
344   /* packet consists of multiple fragments? */\r
345   if ((IPH_OFFSET(iphdr) & htons(IP_OFFMASK | IP_MF)) != 0) {\r
346 #if IP_REASSEMBLY /* packet fragment reassembly code present? */\r
347     LWIP_DEBUGF(IP_DEBUG, ("IP packet is a fragment (id=0x%04"X16_F" tot_len=%"U16_F" len=%"U16_F" MF=%"U16_F" offset=%"U16_F"), calling ip_reass()\n",\r
348       ntohs(IPH_ID(iphdr)), p->tot_len, ntohs(IPH_LEN(iphdr)), !!(IPH_OFFSET(iphdr) & htons(IP_MF)), (ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK)*8));\r
349     /* reassemble the packet*/\r
350     p = ip_reass(p);\r
351     /* packet not fully reassembled yet? */\r
352     if (p == NULL) {\r
353       return ERR_OK;\r
354     }\r
355     iphdr = p->payload;\r
356 #else /* IP_REASSEMBLY == 0, no packet fragment reassembly code present */\r
357     pbuf_free(p);\r
358     LWIP_DEBUGF(IP_DEBUG | 2, ("IP packet dropped since it was fragmented (0x%"X16_F") (while IP_REASSEMBLY == 0).\n",\r
359       ntohs(IPH_OFFSET(iphdr))));\r
360     IP_STATS_INC(ip.opterr);\r
361     IP_STATS_INC(ip.drop);\r
362     /* unsupported protocol feature */\r
363     snmp_inc_ipinunknownprotos();\r
364     return ERR_OK;\r
365 #endif /* IP_REASSEMBLY */\r
366   }\r
367 \r
368 #if IP_OPTIONS_ALLOWED == 0 /* no support for IP options in the IP header? */\r
369 \r
370 #if LWIP_IGMP\r
371   /* there is an extra "router alert" option in IGMP messages which we allow for but do not police */\r
372   if((iphdr_hlen > IP_HLEN &&  (IPH_PROTO(iphdr) != IP_PROTO_IGMP)) {\r
373 #else\r
374   if (iphdr_hlen > IP_HLEN) {\r
375 #endif /* LWIP_IGMP */\r
376     LWIP_DEBUGF(IP_DEBUG | 2, ("IP packet dropped since there were IP options (while IP_OPTIONS_ALLOWED == 0).\n"));\r
377     pbuf_free(p);\r
378     IP_STATS_INC(ip.opterr);\r
379     IP_STATS_INC(ip.drop);\r
380     /* unsupported protocol feature */\r
381     snmp_inc_ipinunknownprotos();\r
382     return ERR_OK;\r
383   }\r
384 #endif /* IP_OPTIONS_ALLOWED == 0 */\r
385 \r
386   /* send to upper layers */\r
387   LWIP_DEBUGF(IP_DEBUG, ("ip_input: \n"));\r
388   ip_debug_print(p);\r
389   LWIP_DEBUGF(IP_DEBUG, ("ip_input: p->len %"U16_F" p->tot_len %"U16_F"\n", p->len, p->tot_len));\r
390 \r
391 #if LWIP_RAW\r
392   /* raw input did not eat the packet? */\r
393   if (raw_input(p, inp) == 0)\r
394 #endif /* LWIP_RAW */\r
395   {\r
396 \r
397     switch (IPH_PROTO(iphdr)) {\r
398 #if LWIP_UDP\r
399     case IP_PROTO_UDP:\r
400 #if LWIP_UDPLITE\r
401     case IP_PROTO_UDPLITE:\r
402 #endif /* LWIP_UDPLITE */\r
403       snmp_inc_ipindelivers();\r
404       udp_input(p, inp);\r
405       break;\r
406 #endif /* LWIP_UDP */\r
407 #if LWIP_TCP\r
408     case IP_PROTO_TCP:\r
409       snmp_inc_ipindelivers();\r
410       tcp_input(p, inp);\r
411       break;\r
412 #endif /* LWIP_TCP */\r
413 #if LWIP_ICMP\r
414     case IP_PROTO_ICMP:\r
415       snmp_inc_ipindelivers();\r
416       icmp_input(p, inp);\r
417       break;\r
418 #endif /* LWIP_ICMP */\r
419 #if LWIP_IGMP\r
420     case IP_PROTO_IGMP:\r
421       igmp_input(p,inp,&(iphdr->dest));\r
422       break;\r
423 #endif /* LWIP_IGMP */\r
424     default:\r
425 #if LWIP_ICMP\r
426       /* send ICMP destination protocol unreachable unless is was a broadcast */\r
427       if (!ip_addr_isbroadcast(&(iphdr->dest), inp) &&\r
428           !ip_addr_ismulticast(&(iphdr->dest))) {\r
429         p->payload = iphdr;\r
430         icmp_dest_unreach(p, ICMP_DUR_PROTO);\r
431       }\r
432 #endif /* LWIP_ICMP */\r
433       pbuf_free(p);\r
434 \r
435       LWIP_DEBUGF(IP_DEBUG | 2, ("Unsupported transport protocol %"U16_F"\n", IPH_PROTO(iphdr)));\r
436 \r
437       IP_STATS_INC(ip.proterr);\r
438       IP_STATS_INC(ip.drop);\r
439       snmp_inc_ipinunknownprotos();\r
440     }\r
441   }\r
442 \r
443   return ERR_OK;\r
444 }\r
445 \r
446 /**\r
447  * Sends an IP packet on a network interface. This function constructs\r
448  * the IP header and calculates the IP header checksum. If the source\r
449  * IP address is NULL, the IP address of the outgoing network\r
450  * interface is filled in as source address.\r
451  * If the destination IP address is IP_HDRINCL, p is assumed to already\r
452  * include an IP header and p->payload points to it instead of the data.\r
453  *\r
454  * @param p the packet to send (p->payload points to the data, e.g. next\r
455             protocol header; if dest == IP_HDRINCL, p already includes an IP\r
456             header and p->payload points to that IP header)\r
457  * @param src the source IP address to send from (if src == IP_ADDR_ANY, the\r
458  *         IP  address of the netif used to send is used as source address)\r
459  * @param dest the destination IP address to send the packet to\r
460  * @param ttl the TTL value to be set in the IP header\r
461  * @param tos the TOS value to be set in the IP header\r
462  * @param proto the PROTOCOL to be set in the IP header\r
463  * @param netif the netif on which to send this packet\r
464  * @return ERR_OK if the packet was sent OK\r
465  *         ERR_BUF if p doesn't have enough space for IP/LINK headers\r
466  *         returns errors returned by netif->output\r
467  *\r
468  * @note ip_id: RFC791 "some host may be able to simply use\r
469  *  unique identifiers independent of destination"\r
470  */\r
471 err_t\r
472 ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,\r
473              u8_t ttl, u8_t tos,\r
474              u8_t proto, struct netif *netif)\r
475 {\r
476   struct ip_hdr *iphdr;\r
477   static u16_t ip_id = 0;\r
478 \r
479   snmp_inc_ipoutrequests();\r
480 \r
481   /* Should the IP header be generated or is it already included in p? */\r
482   if (dest != IP_HDRINCL) {\r
483     /* generate IP header */\r
484     if (pbuf_header(p, IP_HLEN)) {\r
485       LWIP_DEBUGF(IP_DEBUG | 2, ("ip_output: not enough room for IP header in pbuf\n"));\r
486 \r
487       IP_STATS_INC(ip.err);\r
488       snmp_inc_ipoutdiscards();\r
489       return ERR_BUF;\r
490     }\r
491 \r
492     iphdr = p->payload;\r
493     LWIP_ASSERT("check that first pbuf can hold struct ip_hdr",\r
494                (p->len >= sizeof(struct ip_hdr)));\r
495 \r
496     IPH_TTL_SET(iphdr, ttl);\r
497     IPH_PROTO_SET(iphdr, proto);\r
498 \r
499     ip_addr_set(&(iphdr->dest), dest);\r
500 \r
501     IPH_VHLTOS_SET(iphdr, 4, IP_HLEN / 4, tos);\r
502     IPH_LEN_SET(iphdr, htons(p->tot_len));\r
503     IPH_OFFSET_SET(iphdr, 0);\r
504     IPH_ID_SET(iphdr, htons(ip_id));\r
505     ++ip_id;\r
506 \r
507     if (ip_addr_isany(src)) {\r
508       ip_addr_set(&(iphdr->src), &(netif->ip_addr));\r
509     } else {\r
510       ip_addr_set(&(iphdr->src), src);\r
511     }\r
512 \r
513     IPH_CHKSUM_SET(iphdr, 0);\r
514 #if CHECKSUM_GEN_IP\r
515     IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));\r
516 #endif\r
517   } else {\r
518     /* IP header already included in p */\r
519     iphdr = p->payload;\r
520     dest = &(iphdr->dest);\r
521   }\r
522 \r
523 #if IP_FRAG\r
524   /* don't fragment if interface has mtu set to 0 [loopif] */\r
525   if (netif->mtu && (p->tot_len > netif->mtu))\r
526     return ip_frag(p,netif,dest);\r
527 #endif\r
528 \r
529   IP_STATS_INC(ip.xmit);\r
530 \r
531   LWIP_DEBUGF(IP_DEBUG, ("ip_output_if: %c%c%"U16_F"\n", netif->name[0], netif->name[1], netif->num));\r
532   ip_debug_print(p);\r
533 \r
534   LWIP_DEBUGF(IP_DEBUG, ("netif->output()"));\r
535 \r
536   return netif->output(netif, p, dest);\r
537 }\r
538 \r
539 /**\r
540  * Simple interface to ip_output_if. It finds the outgoing network\r
541  * interface and calls upon ip_output_if to do the actual work.\r
542  *\r
543  * @param p the packet to send (p->payload points to the data, e.g. next\r
544             protocol header; if dest == IP_HDRINCL, p already includes an IP\r
545             header and p->payload points to that IP header)\r
546  * @param src the source IP address to send from (if src == IP_ADDR_ANY, the\r
547  *         IP  address of the netif used to send is used as source address)\r
548  * @param dest the destination IP address to send the packet to\r
549  * @param ttl the TTL value to be set in the IP header\r
550  * @param tos the TOS value to be set in the IP header\r
551  * @param proto the PROTOCOL to be set in the IP header\r
552  *\r
553  * @return ERR_RTE if no route is found\r
554  *         see ip_output_if() for more return values\r
555  */\r
556 err_t\r
557 ip_output(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,\r
558           u8_t ttl, u8_t tos, u8_t proto)\r
559 {\r
560   struct netif *netif;\r
561 \r
562   if ((netif = ip_route(dest)) == NULL) {\r
563     return ERR_RTE;\r
564   }\r
565 \r
566   return ip_output_if(p, src, dest, ttl, tos, proto, netif);\r
567 }\r
568 \r
569 #if IP_DEBUG\r
570 /* Print an IP header by using LWIP_DEBUGF\r
571  * @param p an IP packet, p->payload pointing to the IP header\r
572  */\r
573 void\r
574 ip_debug_print(struct pbuf *p)\r
575 {\r
576   struct ip_hdr *iphdr = p->payload;\r
577   u8_t *payload;\r
578 \r
579   payload = (u8_t *)iphdr + IP_HLEN;\r
580 \r
581   LWIP_DEBUGF(IP_DEBUG, ("IP header:\n"));\r
582   LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));\r
583   LWIP_DEBUGF(IP_DEBUG, ("|%2"S16_F" |%2"S16_F" |  0x%02"X16_F" |     %5"U16_F"     | (v, hl, tos, len)\n",\r
584                     IPH_V(iphdr),\r
585                     IPH_HL(iphdr),\r
586                     IPH_TOS(iphdr),\r
587                     ntohs(IPH_LEN(iphdr))));\r
588   LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));\r
589   LWIP_DEBUGF(IP_DEBUG, ("|    %5"U16_F"      |%"U16_F"%"U16_F"%"U16_F"|    %4"U16_F"   | (id, flags, offset)\n",\r
590                     ntohs(IPH_ID(iphdr)),\r
591                     ntohs(IPH_OFFSET(iphdr)) >> 15 & 1,\r
592                     ntohs(IPH_OFFSET(iphdr)) >> 14 & 1,\r
593                     ntohs(IPH_OFFSET(iphdr)) >> 13 & 1,\r
594                     ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK));\r
595   LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));\r
596   LWIP_DEBUGF(IP_DEBUG, ("|  %3"U16_F"  |  %3"U16_F"  |    0x%04"X16_F"     | (ttl, proto, chksum)\n",\r
597                     IPH_TTL(iphdr),\r
598                     IPH_PROTO(iphdr),\r
599                     ntohs(IPH_CHKSUM(iphdr))));\r
600   LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));\r
601   LWIP_DEBUGF(IP_DEBUG, ("|  %3"U16_F"  |  %3"U16_F"  |  %3"U16_F"  |  %3"U16_F"  | (src)\n",\r
602                     ip4_addr1(&iphdr->src),\r
603                     ip4_addr2(&iphdr->src),\r
604                     ip4_addr3(&iphdr->src),\r
605                     ip4_addr4(&iphdr->src)));\r
606   LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));\r
607   LWIP_DEBUGF(IP_DEBUG, ("|  %3"U16_F"  |  %3"U16_F"  |  %3"U16_F"  |  %3"U16_F"  | (dest)\n",\r
608                     ip4_addr1(&iphdr->dest),\r
609                     ip4_addr2(&iphdr->dest),\r
610                     ip4_addr3(&iphdr->dest),\r
611                     ip4_addr4(&iphdr->dest)));\r
612   LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));\r
613 }\r
614 #endif /* IP_DEBUG */\r