A version of LWIP, provided for backwards compatibility.

Dependents:   AA_DemoBoard DemoBoard HelloServerDemo DemoBoard_RangeIndicator ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ip.c Source File

ip.c

Go to the documentation of this file.
00001 /**
00002  * @file
00003  * This is the IPv4 layer implementation for incoming and outgoing IP traffic.
00004  * 
00005  * @see ip_frag.c
00006  *
00007  */
00008 
00009 /*
00010  * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
00011  * All rights reserved.
00012  *
00013  * Redistribution and use in source and binary forms, with or without modification,
00014  * are permitted provided that the following conditions are met:
00015  *
00016  * 1. Redistributions of source code must retain the above copyright notice,
00017  *    this list of conditions and the following disclaimer.
00018  * 2. Redistributions in binary form must reproduce the above copyright notice,
00019  *    this list of conditions and the following disclaimer in the documentation
00020  *    and/or other materials provided with the distribution.
00021  * 3. The name of the author may not be used to endorse or promote products
00022  *    derived from this software without specific prior written permission.
00023  *
00024  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
00025  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
00026  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
00027  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00028  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
00029  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00030  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00031  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
00032  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
00033  * OF SUCH DAMAGE.
00034  *
00035  * This file is part of the lwIP TCP/IP stack.
00036  *
00037  * Author: Adam Dunkels <adam@sics.se>
00038  *
00039  */
00040 
00041 #include "lwip/opt.h"
00042 #include "lwip/ip.h"
00043 #include "lwip/def.h"
00044 #include "lwip/mem.h"
00045 #include "lwip/ip_frag.h"
00046 #include "lwip/inet.h"
00047 #include "lwip/inet_chksum.h"
00048 #include "lwip/netif.h"
00049 #include "lwip/icmp.h"
00050 #include "lwip/igmp.h"
00051 #include "lwip/raw.h"
00052 #include "lwip/udp.h"
00053 #include "lwip/tcp.h"
00054 #include "lwip/snmp.h"
00055 #include "lwip/dhcp.h"
00056 #include "lwip/stats.h"
00057 #include "arch/perf.h"
00058 
00059 /**
00060  * Finds the appropriate network interface for a given IP address. It
00061  * searches the list of network interfaces linearly. A match is found
00062  * if the masked IP address of the network interface equals the masked
00063  * IP address given to the function.
00064  *
00065  * @param dest the destination IP address for which to find the route
00066  * @return the netif on which to send to reach dest
00067  */
00068 struct netif *
00069 ip_route(struct ip_addr *dest)
00070 {
00071   struct netif *netif;
00072 
00073   /* iterate through netifs */
00074   for(netif = netif_list; netif != NULL; netif = netif->next) {
00075     /* network mask matches? */
00076     if (netif_is_up(netif)) {
00077       if (ip_addr_netcmp(dest, &(netif->ip_addr), &(netif->netmask))) {
00078         /* return netif on which to forward IP packet */
00079         return netif;
00080       }
00081     }
00082   }
00083   if ((netif_default == NULL) || (!netif_is_up(netif_default))) {
00084     LWIP_DEBUGF(IP_DEBUG | 2, ("ip_route: No route to 0x%"X32_F"\n", dest->addr));
00085     IP_STATS_INC(ip.rterr);
00086     snmp_inc_ipoutnoroutes();
00087     return (struct netif *)(NULL); // static_cast<struct netif *>(x)
00088   }
00089   /* no matching netif found, use default netif */
00090   return netif_default;
00091 }
00092 
00093 #if IP_FORWARD
00094 /**
00095  * Forwards an IP packet. It finds an appropriate route for the
00096  * packet, decrements the TTL value of the packet, adjusts the
00097  * checksum and outputs the packet on the appropriate interface.
00098  *
00099  * @param p the packet to forward (p->payload points to IP header)
00100  * @param iphdr the IP header of the input packet
00101  * @param inp the netif on which this packet was received
00102  * @return the netif on which the packet was sent (NULL if it wasn't sent)
00103  */
00104 static struct netif *
00105 ip_forward(struct pbuf *p, struct ip_hdr *iphdr, struct netif *inp)
00106 {
00107   struct netif *netif;
00108 
00109   PERF_START;
00110   /* Find network interface where to forward this IP packet to. */
00111   netif = ip_route((struct ip_addr *)&(iphdr->dest));
00112   if (netif == NULL) {
00113     LWIP_DEBUGF(IP_DEBUG, ("ip_forward: no forwarding route for 0x%"X32_F" found\n",
00114                       iphdr->dest.addr));
00115     snmp_inc_ipoutnoroutes();
00116     return (struct netif *)NULL;
00117   }
00118   /* Do not forward packets onto the same network interface on which
00119    * they arrived. */
00120   if (netif == inp) {
00121     LWIP_DEBUGF(IP_DEBUG, ("ip_forward: not bouncing packets back on incoming interface.\n"));
00122     snmp_inc_ipoutnoroutes();
00123     return (struct netif *)NULL;
00124   }
00125 
00126   /* decrement TTL */
00127   IPH_TTL_SET(iphdr, IPH_TTL(iphdr) - 1);
00128   /* send ICMP if TTL == 0 */
00129   if (IPH_TTL(iphdr) == 0) {
00130     snmp_inc_ipinhdrerrors();
00131 #if LWIP_ICMP
00132     /* Don't send ICMP messages in response to ICMP messages */
00133     if (IPH_PROTO(iphdr) != IP_PROTO_ICMP) {
00134       icmp_time_exceeded(p, ICMP_TE_TTL);
00135     }
00136 #endif /* LWIP_ICMP */
00137     return (struct netif *)NULL;
00138   }
00139 
00140   /* Incrementally update the IP checksum. */
00141   if (IPH_CHKSUM(iphdr) >= htons(0xffff - 0x100)) {
00142     IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + htons(0x100) + 1);
00143   } else {
00144     IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + htons(0x100));
00145   }
00146 
00147   LWIP_DEBUGF(IP_DEBUG, ("ip_forward: forwarding packet to 0x%"X32_F"\n",
00148                     iphdr->dest.addr));
00149 
00150   IP_STATS_INC(ip.fw);
00151   IP_STATS_INC(ip.xmit);
00152   snmp_inc_ipforwdatagrams();
00153 
00154   PERF_STOP("ip_forward");
00155   /* transmit pbuf on chosen interface */
00156   netif->output(netif, p, (struct ip_addr *)&(iphdr->dest));
00157   return netif;
00158 }
00159 #endif /* IP_FORWARD */
00160 
00161 /**
00162  * This function is called by the network interface device driver when
00163  * an IP packet is received. The function does the basic checks of the
00164  * IP header such as packet size being at least larger than the header
00165  * size etc. If the packet was not destined for us, the packet is
00166  * forwarded (using ip_forward). The IP checksum is always checked.
00167  *
00168  * Finally, the packet is sent to the upper layer protocol input function.
00169  * 
00170  * @param p the received IP packet (p->payload points to IP header)
00171  * @param inp the netif on which this packet was received
00172  * @return ERR_OK if the packet was processed (could return ERR_* if it wasn't
00173  *         processed, but currently always returns ERR_OK)
00174  */
00175 err_t
00176 ip_input(struct pbuf *p, struct netif *inp)
00177 {
00178   struct ip_hdr *iphdr;
00179   struct netif *netif;
00180   u16_t iphdr_hlen;
00181   u16_t iphdr_len;
00182 #if LWIP_DHCP
00183   int check_ip_src=1;
00184 #endif /* LWIP_DHCP */
00185 
00186   IP_STATS_INC(ip.recv);
00187   snmp_inc_ipinreceives();
00188 
00189   /* identify the IP header */
00190   iphdr = (struct ip_hdr *)(p->payload); // static_cast<struct ip_hdr *>(x)
00191   if (IPH_V(iphdr) != 4) {
00192     LWIP_DEBUGF(IP_DEBUG | 1, ("IP packet dropped due to bad version number %"U16_F"\n", IPH_V(iphdr)));
00193     ip_debug_print(p);
00194     pbuf_free(p);
00195     IP_STATS_INC(ip.err);
00196     IP_STATS_INC(ip.drop);
00197     snmp_inc_ipinhdrerrors();
00198     return ERR_OK;
00199   }
00200 
00201   /* obtain IP header length in number of 32-bit words */
00202   iphdr_hlen = IPH_HL(iphdr);
00203   /* calculate IP header length in bytes */
00204   iphdr_hlen *= 4;
00205   /* obtain ip length in bytes */
00206   iphdr_len = ntohs(IPH_LEN(iphdr));
00207 
00208   /* header length exceeds first pbuf length, or ip length exceeds total pbuf length? */
00209   if ((iphdr_hlen > p->len) || (iphdr_len > p->tot_len)) {
00210     if (iphdr_hlen > p->len)
00211     LWIP_DEBUGF(IP_DEBUG | 2, ("IP header (len %"U16_F") does not fit in first pbuf (len %"U16_F"), IP packet dropped.\n",
00212                                iphdr_hlen, p->len));
00213     if (iphdr_len > p->tot_len)
00214     LWIP_DEBUGF(IP_DEBUG | 2, ("IP (len %"U16_F") is longer than pbuf (len %"U16_F"), "
00215                                "IP packet dropped.\n",
00216                                iphdr_len, p->tot_len));
00217     /* free (drop) packet pbufs */
00218     pbuf_free(p);
00219     IP_STATS_INC(ip.lenerr);
00220     IP_STATS_INC(ip.drop);
00221     snmp_inc_ipindiscards();
00222     return ERR_OK;
00223   }
00224 
00225   /* verify checksum */
00226 #if CHECKSUM_CHECK_IP
00227   if (inet_chksum(iphdr, iphdr_hlen) != 0) {
00228 
00229     LWIP_DEBUGF(IP_DEBUG | 2, ("Checksum (0x%"X16_F") failed, IP packet dropped.\n", inet_chksum(iphdr, iphdr_hlen)));
00230     ip_debug_print(p);
00231     pbuf_free(p);
00232     IP_STATS_INC(ip.chkerr);
00233     IP_STATS_INC(ip.drop);
00234     snmp_inc_ipinhdrerrors();
00235     return ERR_OK;
00236   }
00237 #endif
00238 
00239   /* Trim pbuf. This should have been done at the netif layer,
00240    * but we'll do it anyway just to be sure that its done. */
00241   pbuf_realloc(p, iphdr_len);
00242 
00243   /* match packet against an interface, i.e. is this packet for us? */
00244 #if LWIP_IGMP
00245   if (ip_addr_ismulticast(&(iphdr->dest))) {
00246     if ((inp->flags & NETIF_FLAG_IGMP) && (igmp_lookfor_group(inp, &(iphdr->dest)))) {
00247       netif = inp;
00248     } else {
00249       netif = NULL;
00250     }
00251   } else
00252 #endif /* LWIP_IGMP */
00253   {
00254     /* start trying with inp. if that's not acceptable, start walking the
00255        list of configured netifs.
00256        'first' is used as a boolean to mark whether we started walking the list */
00257     int first = 1;
00258     netif = inp;
00259     do {
00260       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",
00261           iphdr->dest.addr, netif->ip_addr.addr,
00262           iphdr->dest.addr & netif->netmask.addr,
00263           netif->ip_addr.addr & netif->netmask.addr,
00264           iphdr->dest.addr & ~(netif->netmask.addr)));
00265 
00266       /* interface is up and configured? */
00267       if ((netif_is_up(netif)) && (!ip_addr_isany(&(netif->ip_addr)))) {
00268         /* unicast to this interface address? */
00269         if (ip_addr_cmp(&(iphdr->dest), &(netif->ip_addr)) ||
00270             /* or broadcast on this interface network address? */
00271             ip_addr_isbroadcast(&(iphdr->dest), netif)) {
00272           LWIP_DEBUGF(IP_DEBUG, ("ip_input: packet accepted on interface %c%c\n",
00273               netif->name[0], netif->name[1]));
00274           /* break out of for loop */
00275           break;
00276         }
00277       }
00278       if (first) {
00279         first = 0;
00280         netif = netif_list;
00281       } else {
00282         netif = netif->next;
00283       }
00284       if (netif == inp) {
00285         netif = netif->next;
00286       }
00287     } while(netif != NULL);
00288   }
00289 
00290 #if LWIP_DHCP
00291   /* Pass DHCP messages regardless of destination address. DHCP traffic is addressed
00292    * using link layer addressing (such as Ethernet MAC) so we must not filter on IP.
00293    * According to RFC 1542 section 3.1.1, referred by RFC 2131).
00294    */
00295   if (netif == NULL) {
00296     /* remote port is DHCP server? */
00297     if (IPH_PROTO(iphdr) == IP_PROTO_UDP) {
00298       LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE | 1, ("ip_input: UDP packet to DHCP client port %"U16_F"\n",
00299         ntohs(((struct udp_hdr *)((u8_t *)iphdr + iphdr_hlen))->dest)));
00300       if (ntohs(((struct udp_hdr *)((u8_t *)iphdr + iphdr_hlen))->dest) == DHCP_CLIENT_PORT) {
00301         LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE | 1, ("ip_input: DHCP packet accepted.\n"));
00302         netif = inp;
00303         check_ip_src = 0;
00304       }
00305     }
00306   }
00307 #endif /* LWIP_DHCP */
00308 
00309   /* broadcast or multicast packet source address? Compliant with RFC 1122: 3.2.1.3 */
00310 #if LWIP_DHCP
00311   if (check_ip_src)
00312 #endif /* LWIP_DHCP */
00313   {  if ((ip_addr_isbroadcast(&(iphdr->src), inp)) ||
00314          (ip_addr_ismulticast(&(iphdr->src)))) {
00315       /* packet source is not valid */
00316       LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE | 1, ("ip_input: packet source is not valid.\n"));
00317       /* free (drop) packet pbufs */
00318       pbuf_free(p);
00319       IP_STATS_INC(ip.drop);
00320       snmp_inc_ipinaddrerrors();
00321       snmp_inc_ipindiscards();
00322       return ERR_OK;
00323     }
00324   }
00325 
00326   /* packet not for us? */
00327   if (netif == NULL) {
00328     /* packet not for us, route or discard */
00329     LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE | 1, ("ip_input: packet not for us.\n"));
00330 #if IP_FORWARD
00331     /* non-broadcast packet? */
00332     if (!ip_addr_isbroadcast(&(iphdr->dest), inp)) {
00333       /* try to forward IP packet on (other) interfaces */
00334       ip_forward(p, iphdr, inp);
00335     } else
00336 #endif /* IP_FORWARD */
00337     {
00338       snmp_inc_ipinaddrerrors();
00339       snmp_inc_ipindiscards();
00340     }
00341     pbuf_free(p);
00342     return ERR_OK;
00343   }
00344   /* packet consists of multiple fragments? */
00345   if ((IPH_OFFSET(iphdr) & htons(IP_OFFMASK | IP_MF)) != 0) {
00346 #if IP_REASSEMBLY /* packet fragment reassembly code present? */
00347     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",
00348       ntohs(IPH_ID(iphdr)), p->tot_len, ntohs(IPH_LEN(iphdr)), !!(IPH_OFFSET(iphdr) & htons(IP_MF)), (ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK)*8));
00349     /* reassemble the packet*/
00350     p = ip_reass(p);
00351     /* packet not fully reassembled yet? */
00352     if (p == NULL) {
00353       return ERR_OK;
00354     }
00355     iphdr = (struct ip_hdr *)(p->payload); // static_cast<struct ip_hdr *>(x)
00356 #else /* IP_REASSEMBLY == 0, no packet fragment reassembly code present */
00357     pbuf_free(p);
00358     LWIP_DEBUGF(IP_DEBUG | 2, ("IP packet dropped since it was fragmented (0x%"X16_F") (while IP_REASSEMBLY == 0).\n",
00359       ntohs(IPH_OFFSET(iphdr))));
00360     IP_STATS_INC(ip.opterr);
00361     IP_STATS_INC(ip.drop);
00362     /* unsupported protocol feature */
00363     snmp_inc_ipinunknownprotos();
00364     return ERR_OK;
00365 #endif /* IP_REASSEMBLY */
00366   }
00367 
00368 #if IP_OPTIONS_ALLOWED == 0 /* no support for IP options in the IP header? */
00369 
00370 #if LWIP_IGMP
00371   /* there is an extra "router alert" option in IGMP messages which we allow for but do not police */
00372   if((iphdr_hlen > IP_HLEN &&  (IPH_PROTO(iphdr) != IP_PROTO_IGMP)) {
00373 #else
00374   if (iphdr_hlen > IP_HLEN) {
00375 #endif /* LWIP_IGMP */
00376     LWIP_DEBUGF(IP_DEBUG | 2, ("IP packet dropped since there were IP options (while IP_OPTIONS_ALLOWED == 0).\n"));
00377     pbuf_free(p);
00378     IP_STATS_INC(ip.opterr);
00379     IP_STATS_INC(ip.drop);
00380     /* unsupported protocol feature */
00381     snmp_inc_ipinunknownprotos();
00382     return ERR_OK;
00383   }
00384 #endif /* IP_OPTIONS_ALLOWED == 0 */
00385 
00386   /* send to upper layers */
00387   LWIP_DEBUGF(IP_DEBUG, ("ip_input: \n"));
00388   ip_debug_print(p);
00389   LWIP_DEBUGF(IP_DEBUG, ("ip_input: p->len %"U16_F" p->tot_len %"U16_F"\n", p->len, p->tot_len));
00390 
00391 #if LWIP_RAW
00392   /* raw input did not eat the packet? */
00393   if (raw_input(p, inp) == 0)
00394 #endif /* LWIP_RAW */
00395   {
00396 
00397     switch (IPH_PROTO(iphdr)) {
00398 #if LWIP_UDP
00399     case IP_PROTO_UDP:
00400 #if LWIP_UDPLITE
00401     case IP_PROTO_UDPLITE:
00402 #endif /* LWIP_UDPLITE */
00403       snmp_inc_ipindelivers();
00404       udp_input(p, inp);
00405       break;
00406 #endif /* LWIP_UDP */
00407 #if LWIP_TCP
00408     case IP_PROTO_TCP:
00409       snmp_inc_ipindelivers();
00410       tcp_input(p, inp);
00411       break;
00412 #endif /* LWIP_TCP */
00413 #if LWIP_ICMP
00414     case IP_PROTO_ICMP:
00415       snmp_inc_ipindelivers();
00416       icmp_input(p, inp);
00417       break;
00418 #endif /* LWIP_ICMP */
00419 #if LWIP_IGMP
00420     case IP_PROTO_IGMP:
00421       igmp_input(p,inp,&(iphdr->dest));
00422       break;
00423 #endif /* LWIP_IGMP */
00424     default:
00425 #if LWIP_ICMP
00426       /* send ICMP destination protocol unreachable unless is was a broadcast */
00427       if (!ip_addr_isbroadcast(&(iphdr->dest), inp) &&
00428           !ip_addr_ismulticast(&(iphdr->dest))) {
00429         p->payload = iphdr;
00430         icmp_dest_unreach(p, ICMP_DUR_PROTO);
00431       }
00432 #endif /* LWIP_ICMP */
00433       pbuf_free(p);
00434 
00435       LWIP_DEBUGF(IP_DEBUG | 2, ("Unsupported transport protocol %"U16_F"\n", IPH_PROTO(iphdr)));
00436 
00437       IP_STATS_INC(ip.proterr);
00438       IP_STATS_INC(ip.drop);
00439       snmp_inc_ipinunknownprotos();
00440     }
00441   }
00442 
00443   return ERR_OK;
00444 }
00445 
00446 /**
00447  * Sends an IP packet on a network interface. This function constructs
00448  * the IP header and calculates the IP header checksum. If the source
00449  * IP address is NULL, the IP address of the outgoing network
00450  * interface is filled in as source address.
00451  * If the destination IP address is IP_HDRINCL, p is assumed to already
00452  * include an IP header and p->payload points to it instead of the data.
00453  *
00454  * @param p the packet to send (p->payload points to the data, e.g. next
00455             protocol header; if dest == IP_HDRINCL, p already includes an IP
00456             header and p->payload points to that IP header)
00457  * @param src the source IP address to send from (if src == IP_ADDR_ANY, the
00458  *         IP  address of the netif used to send is used as source address)
00459  * @param dest the destination IP address to send the packet to
00460  * @param ttl the TTL value to be set in the IP header
00461  * @param tos the TOS value to be set in the IP header
00462  * @param proto the PROTOCOL to be set in the IP header
00463  * @param netif the netif on which to send this packet
00464  * @return ERR_OK if the packet was sent OK
00465  *         ERR_BUF if p doesn't have enough space for IP/LINK headers
00466  *         returns errors returned by netif->output
00467  *
00468  * @note ip_id: RFC791 "some host may be able to simply use
00469  *  unique identifiers independent of destination"
00470  */
00471 err_t
00472 ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
00473              u8_t ttl, u8_t tos,
00474              u8_t proto, struct netif *netif)
00475 {
00476   struct ip_hdr *iphdr;
00477   static u16_t ip_id = 0;
00478 
00479   snmp_inc_ipoutrequests();
00480 
00481   /* Should the IP header be generated or is it already included in p? */
00482   if (dest != IP_HDRINCL) {
00483     /* generate IP header */
00484     if (pbuf_header(p, IP_HLEN)) {
00485       LWIP_DEBUGF(IP_DEBUG | 2, ("ip_output: not enough room for IP header in pbuf\n"));
00486 
00487       IP_STATS_INC(ip.err);
00488       snmp_inc_ipoutdiscards();
00489       return ERR_BUF;
00490     }
00491 
00492     iphdr = (struct ip_hdr *)(p->payload); // static_cast<struct ip_hdr *>(x)
00493     LWIP_ASSERT("check that first pbuf can hold struct ip_hdr",
00494                (p->len >= sizeof(struct ip_hdr)));
00495 
00496     IPH_TTL_SET(iphdr, ttl);
00497     IPH_PROTO_SET(iphdr, proto);
00498 
00499     ip_addr_set(&(iphdr->dest), dest);
00500 
00501     IPH_VHLTOS_SET(iphdr, 4, IP_HLEN / 4, tos);
00502     IPH_LEN_SET(iphdr, htons(p->tot_len));
00503     IPH_OFFSET_SET(iphdr, 0);
00504     IPH_ID_SET(iphdr, htons(ip_id));
00505     ++ip_id;
00506 
00507     if (ip_addr_isany(src)) {
00508       ip_addr_set(&(iphdr->src), &(netif->ip_addr));
00509     } else {
00510       ip_addr_set(&(iphdr->src), src);
00511     }
00512 
00513     IPH_CHKSUM_SET(iphdr, 0);
00514 #if CHECKSUM_GEN_IP
00515     IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));
00516 #endif
00517   } else {
00518     /* IP header already included in p */
00519     iphdr = (struct ip_hdr *)(p->payload);  // static_cast<struct ip_hdr *>(x)
00520     struct ip_addr dest_addr;
00521     dest_addr.addr = iphdr->dest.addr;
00522     dest = &dest_addr;
00523   }
00524 
00525 #if IP_FRAG
00526   /* don't fragment if interface has mtu set to 0 [loopif] */
00527   if (netif->mtu && (p->tot_len > netif->mtu))
00528     return ip_frag(p,netif,dest);
00529 #endif
00530 
00531   IP_STATS_INC(ip.xmit);
00532 
00533   LWIP_DEBUGF(IP_DEBUG, ("ip_output_if: %c%c%"U16_F"\n", netif->name[0], netif->name[1], netif->num));
00534   ip_debug_print(p);
00535 
00536 #if (LWIP_NETIF_LOOPBACK || LWIP_HAVE_LOOPIF)
00537   if (ip_addr_cmp(dest, &netif->ip_addr)) {
00538     /* Packet to self, enqueue it for loopback */
00539     LWIP_DEBUGF(IP_DEBUG, ("netif_loop_output()"));
00540 
00541     return netif_loop_output(netif, p, dest);
00542   } else
00543 #endif /* (LWIP_NETIF_LOOPBACK || LWIP_HAVE_LOOPIF) */
00544   {
00545     LWIP_DEBUGF(IP_DEBUG, ("netif->output()"));
00546 
00547     return netif->output(netif, p, dest);
00548   }
00549 }
00550 
00551 /**
00552  * Simple interface to ip_output_if. It finds the outgoing network
00553  * interface and calls upon ip_output_if to do the actual work.
00554  *
00555  * @param p the packet to send (p->payload points to the data, e.g. next
00556             protocol header; if dest == IP_HDRINCL, p already includes an IP
00557             header and p->payload points to that IP header)
00558  * @param src the source IP address to send from (if src == IP_ADDR_ANY, the
00559  *         IP  address of the netif used to send is used as source address)
00560  * @param dest the destination IP address to send the packet to
00561  * @param ttl the TTL value to be set in the IP header
00562  * @param tos the TOS value to be set in the IP header
00563  * @param proto the PROTOCOL to be set in the IP header
00564  *
00565  * @return ERR_RTE if no route is found
00566  *         see ip_output_if() for more return values
00567  */
00568 err_t
00569 ip_output(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
00570           u8_t ttl, u8_t tos, u8_t proto)
00571 {
00572   struct netif *netif;
00573 
00574   if ((netif = ip_route(dest)) == NULL) {
00575     LWIP_DEBUGF(IP_DEBUG, ("ip_output: No route to 0x%"X32_F"\n", dest->addr));
00576     IP_STATS_INC(ip.rterr);
00577     return ERR_RTE;
00578   }
00579 
00580   return ip_output_if(p, src, dest, ttl, tos, proto, netif);
00581 }
00582 
00583 #if LWIP_NETIF_HWADDRHINT
00584 /** Like ip_output, but takes and addr_hint pointer that is passed on to netif->addr_hint
00585  *  before calling ip_output_if.
00586  *
00587  * @param p the packet to send (p->payload points to the data, e.g. next
00588             protocol header; if dest == IP_HDRINCL, p already includes an IP
00589             header and p->payload points to that IP header)
00590  * @param src the source IP address to send from (if src == IP_ADDR_ANY, the
00591  *         IP  address of the netif used to send is used as source address)
00592  * @param dest the destination IP address to send the packet to
00593  * @param ttl the TTL value to be set in the IP header
00594  * @param tos the TOS value to be set in the IP header
00595  * @param proto the PROTOCOL to be set in the IP header
00596  * @param addr_hint address hint pointer set to netif->addr_hint before
00597  *        calling ip_output_if()
00598  *
00599  * @return ERR_RTE if no route is found
00600  *         see ip_output_if() for more return values
00601  */
00602 err_t
00603 ip_output_hinted(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
00604           u8_t ttl, u8_t tos, u8_t proto, u8_t *addr_hint)
00605 {
00606   struct netif *netif;
00607   err_t err;
00608 
00609   if ((netif = ip_route(dest)) == NULL) {
00610     LWIP_DEBUGF(IP_DEBUG, ("ip_output: No route to 0x%"X32_F"\n", dest->addr));
00611     IP_STATS_INC(ip.rterr);
00612     return ERR_RTE;
00613   }
00614 
00615   netif->addr_hint = addr_hint;
00616   err = ip_output_if(p, src, dest, ttl, tos, proto, netif);
00617   netif->addr_hint = NULL;
00618 
00619   return err;
00620 }
00621 #endif /* LWIP_NETIF_HWADDRHINT*/
00622 
00623 #if IP_DEBUG
00624 /* Print an IP header by using LWIP_DEBUGF
00625  * @param p an IP packet, p->payload pointing to the IP header
00626  */
00627 void
00628 ip_debug_print(struct pbuf *p)
00629 {
00630   struct ip_hdr *iphdr = (struct ip_hdr *)p->payload; // static_cast<struct ip_hdr *>(x)
00631   u8_t *payload;
00632 
00633   payload = (u8_t *)iphdr + IP_HLEN;
00634 
00635   LWIP_DEBUGF(IP_DEBUG, ("IP header:\n"));
00636   LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
00637   LWIP_DEBUGF(IP_DEBUG, ("|%2"S16_F" |%2"S16_F" |  0x%02"X16_F" |     %5"U16_F"     | (v, hl, tos, len)\n",
00638                     IPH_V(iphdr),
00639                     IPH_HL(iphdr),
00640                     IPH_TOS(iphdr),
00641                     ntohs(IPH_LEN(iphdr))));
00642   LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
00643   LWIP_DEBUGF(IP_DEBUG, ("|    %5"U16_F"      |%"U16_F"%"U16_F"%"U16_F"|    %4"U16_F"   | (id, flags, offset)\n",
00644                     ntohs(IPH_ID(iphdr)),
00645                     ntohs(IPH_OFFSET(iphdr)) >> 15 & 1,
00646                     ntohs(IPH_OFFSET(iphdr)) >> 14 & 1,
00647                     ntohs(IPH_OFFSET(iphdr)) >> 13 & 1,
00648                     ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK));
00649   LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
00650   LWIP_DEBUGF(IP_DEBUG, ("|  %3"U16_F"  |  %3"U16_F"  |    0x%04"X16_F"     | (ttl, proto, chksum)\n",
00651                     IPH_TTL(iphdr),
00652                     IPH_PROTO(iphdr),
00653                     ntohs(IPH_CHKSUM(iphdr))));
00654   LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
00655   LWIP_DEBUGF(IP_DEBUG, ("|  %3"U16_F"  |  %3"U16_F"  |  %3"U16_F"  |  %3"U16_F"  | (src)\n",
00656                     ip4_addr1(&iphdr->src),
00657                     ip4_addr2(&iphdr->src),
00658                     ip4_addr3(&iphdr->src),
00659                     ip4_addr4(&iphdr->src)));
00660   LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
00661   LWIP_DEBUGF(IP_DEBUG, ("|  %3"U16_F"  |  %3"U16_F"  |  %3"U16_F"  |  %3"U16_F"  | (dest)\n",
00662                     ip4_addr1(&iphdr->dest),
00663                     ip4_addr2(&iphdr->dest),
00664                     ip4_addr3(&iphdr->dest),
00665                     ip4_addr4(&iphdr->dest)));
00666   LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
00667 }
00668 #endif /* IP_DEBUG */