Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of Bonjour by
ip.cpp
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_chksum.h" 00047 #include "lwip/netif.h" 00048 #include "lwip/icmp.h" 00049 #include "lwip/igmp.h" 00050 #include "lwip/raw.h" 00051 #include "lwip/udp.h" 00052 #include "lwip/tcp_impl.h" 00053 #include "lwip/snmp.h" 00054 #include "lwip/dhcp.h " 00055 #include "lwip/autoip.h" 00056 #include "lwip/stats.h" 00057 #include "arch/perf.h" 00058 00059 #include <string.h> 00060 00061 /** 00062 * The interface that provided the packet for the current callback 00063 * invocation. 00064 */ 00065 struct netif *current_netif; 00066 00067 /** 00068 * Header of the input packet currently being processed. 00069 */ 00070 const struct ip_hdr *current_header; 00071 00072 /** 00073 * Finds the appropriate network interface for a given IP address. It 00074 * searches the list of network interfaces linearly. A match is found 00075 * if the masked IP address of the network interface equals the masked 00076 * IP address given to the function. 00077 * 00078 * @param dest the destination IP address for which to find the route 00079 * @return the netif on which to send to reach dest 00080 */ 00081 struct netif * 00082 ip_route(ip_addr_t *dest) 00083 { 00084 struct netif *netif; 00085 00086 /* iterate through netifs */ 00087 for(netif = netif_list; netif != NULL; netif = netif->next) { 00088 /* network mask matches? */ 00089 if (netif_is_up(netif)) { 00090 if (ip_addr_netcmp(dest, &(netif->ip_addr), &(netif->netmask))) { 00091 /* return netif on which to forward IP packet */ 00092 return netif; 00093 } 00094 } 00095 } 00096 if ((netif_default == NULL) || (!netif_is_up(netif_default))) { 00097 LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip_route: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", 00098 ip4_addr1_16(dest), ip4_addr2_16(dest), ip4_addr3_16(dest), ip4_addr4_16(dest))); 00099 IP_STATS_INC(ip.rterr); 00100 snmp_inc_ipoutnoroutes(); 00101 return NULL; 00102 } 00103 /* no matching netif found, use default netif */ 00104 return netif_default; 00105 } 00106 00107 #if IP_FORWARD 00108 /** 00109 * Forwards an IP packet. It finds an appropriate route for the 00110 * packet, decrements the TTL value of the packet, adjusts the 00111 * checksum and outputs the packet on the appropriate interface. 00112 * 00113 * @param p the packet to forward (p->payload points to IP header) 00114 * @param iphdr the IP header of the input packet 00115 * @param inp the netif on which this packet was received 00116 * @return the netif on which the packet was sent (NULL if it wasn't sent) 00117 */ 00118 static struct netif * 00119 ip_forward(struct pbuf *p, struct ip_hdr *iphdr, struct netif *inp) 00120 { 00121 struct netif *netif; 00122 ip_addr_t dest; 00123 00124 PERF_START; 00125 dest = iphdr->dest; 00126 00127 /* RFC3927 2.7: do not forward link-local addresses */ 00128 if (ip_addr_islinklocal(&dest)) { 00129 LWIP_DEBUGF(IP_DEBUG, ("ip_forward: not forwarding LLA %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", 00130 ip4_addr1_16(&dest), ip4_addr2_16(&dest), ip4_addr3_16(&dest), ip4_addr4_16(&dest))); 00131 snmp_inc_ipoutnoroutes(); 00132 return (struct netif *)NULL; 00133 } 00134 00135 /* Find network interface where to forward this IP packet to. */ 00136 netif = ip_route(&dest); 00137 if (netif == NULL) { 00138 LWIP_DEBUGF(IP_DEBUG, ("ip_forward: no forwarding route for %"U16_F".%"U16_F".%"U16_F".%"U16_F" found\n", 00139 ip4_addr1_16(&dest), ip4_addr2_16(&dest), ip4_addr3_16(&dest), ip4_addr4_16(&dest))); 00140 snmp_inc_ipoutnoroutes(); 00141 return (struct netif *)NULL; 00142 } 00143 /* Do not forward packets onto the same network interface on which 00144 * they arrived. */ 00145 if (netif == inp) { 00146 LWIP_DEBUGF(IP_DEBUG, ("ip_forward: not bouncing packets back on incoming interface.\n")); 00147 snmp_inc_ipoutnoroutes(); 00148 return (struct netif *)NULL; 00149 } 00150 00151 /* decrement TTL */ 00152 IPH_TTL_SET(iphdr, IPH_TTL(iphdr) - 1); 00153 /* send ICMP if TTL == 0 */ 00154 if (IPH_TTL(iphdr) == 0) { 00155 snmp_inc_ipinhdrerrors(); 00156 #if LWIP_ICMP 00157 /* Don't send ICMP messages in response to ICMP messages */ 00158 if (IPH_PROTO(iphdr) != IP_PROTO_ICMP) { 00159 icmp_time_exceeded(p, ICMP_TE_TTL); 00160 } 00161 #endif /* LWIP_ICMP */ 00162 return (struct netif *)NULL; 00163 } 00164 00165 /* Incrementally update the IP checksum. */ 00166 if (IPH_CHKSUM(iphdr) >= htons(0xffff - 0x100)) { 00167 IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + htons(0x100) + 1); 00168 } else { 00169 IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + htons(0x100)); 00170 } 00171 00172 LWIP_DEBUGF(IP_DEBUG, ("ip_forward: forwarding packet to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", 00173 ip4_addr1_16(&dest), ip4_addr2_16(&dest), ip4_addr3_16(&dest), ip4_addr4_16(&dest))); 00174 00175 IP_STATS_INC(ip.fw); 00176 IP_STATS_INC(ip.xmit); 00177 snmp_inc_ipforwdatagrams(); 00178 00179 PERF_STOP("ip_forward"); 00180 /* transmit pbuf on chosen interface */ 00181 netif->output(netif, p, &dest); 00182 return netif; 00183 } 00184 #endif /* IP_FORWARD */ 00185 00186 /** 00187 * This function is called by the network interface device driver when 00188 * an IP packet is received. The function does the basic checks of the 00189 * IP header such as packet size being at least larger than the header 00190 * size etc. If the packet was not destined for us, the packet is 00191 * forwarded (using ip_forward). The IP checksum is always checked. 00192 * 00193 * Finally, the packet is sent to the upper layer protocol input function. 00194 * 00195 * @param p the received IP packet (p->payload points to IP header) 00196 * @param inp the netif on which this packet was received 00197 * @return ERR_OK if the packet was processed (could return ERR_* if it wasn't 00198 * processed, but currently always returns ERR_OK) 00199 */ 00200 err_t 00201 ip_input(struct pbuf *p, struct netif *inp) 00202 { 00203 struct ip_hdr *iphdr; 00204 struct netif *netif; 00205 u16_t iphdr_hlen; 00206 u16_t iphdr_len; 00207 #if LWIP_DHCP 00208 int check_ip_src=1; 00209 #endif /* LWIP_DHCP */ 00210 00211 IP_STATS_INC(ip.recv); 00212 snmp_inc_ipinreceives(); 00213 00214 /* identify the IP header */ 00215 iphdr = (struct ip_hdr *)p->payload; 00216 if (IPH_V(iphdr) != 4) { 00217 LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_WARNING, ("IP packet dropped due to bad version number %"U16_F"\n", IPH_V(iphdr))); 00218 ip_debug_print(p); 00219 pbuf_free(p); 00220 IP_STATS_INC(ip.err); 00221 IP_STATS_INC(ip.drop); 00222 snmp_inc_ipinhdrerrors(); 00223 return ERR_OK; 00224 } 00225 00226 /* obtain IP header length in number of 32-bit words */ 00227 iphdr_hlen = IPH_HL(iphdr); 00228 /* calculate IP header length in bytes */ 00229 iphdr_hlen *= 4; 00230 /* obtain ip length in bytes */ 00231 iphdr_len = ntohs(IPH_LEN(iphdr)); 00232 00233 /* header length exceeds first pbuf length, or ip length exceeds total pbuf length? */ 00234 if ((iphdr_hlen > p->len) || (iphdr_len > p->tot_len)) { 00235 if (iphdr_hlen > p->len) { 00236 LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, 00237 ("IP header (len %"U16_F") does not fit in first pbuf (len %"U16_F"), IP packet dropped.\n", 00238 iphdr_hlen, p->len)); 00239 } 00240 if (iphdr_len > p->tot_len) { 00241 LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, 00242 ("IP (len %"U16_F") is longer than pbuf (len %"U16_F"), IP packet dropped.\n", 00243 iphdr_len, p->tot_len)); 00244 } 00245 /* free (drop) packet pbufs */ 00246 pbuf_free(p); 00247 IP_STATS_INC(ip.lenerr); 00248 IP_STATS_INC(ip.drop); 00249 snmp_inc_ipindiscards(); 00250 return ERR_OK; 00251 } 00252 00253 /* verify checksum */ 00254 #if CHECKSUM_CHECK_IP 00255 if (inet_chksum(iphdr, iphdr_hlen) != 0) { 00256 00257 LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, 00258 ("Checksum (0x%"X16_F") failed, IP packet dropped.\n", inet_chksum(iphdr, iphdr_hlen))); 00259 ip_debug_print(p); 00260 pbuf_free(p); 00261 IP_STATS_INC(ip.chkerr); 00262 IP_STATS_INC(ip.drop); 00263 snmp_inc_ipinhdrerrors(); 00264 return ERR_OK; 00265 } 00266 #endif 00267 00268 /* Trim pbuf. This should have been done at the netif layer, 00269 * but we'll do it anyway just to be sure that its done. */ 00270 pbuf_realloc(p, iphdr_len); 00271 00272 /* match packet against an interface, i.e. is this packet for us? */ 00273 #if LWIP_IGMP 00274 if (ip_addr_ismulticast(&(iphdr->dest))) { 00275 if ((inp->flags & NETIF_FLAG_IGMP) && (igmp_lookfor_group(inp, &(iphdr->dest)))) { 00276 netif = inp; 00277 } else { 00278 netif = NULL; 00279 } 00280 } else 00281 #endif /* LWIP_IGMP */ 00282 { 00283 /* start trying with inp. if that's not acceptable, start walking the 00284 list of configured netifs. 00285 'first' is used as a boolean to mark whether we started walking the list */ 00286 int first = 1; 00287 netif = inp; 00288 do { 00289 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", 00290 ip4_addr_get_u32(&iphdr->dest), ip4_addr_get_u32(&netif->ip_addr), 00291 ip4_addr_get_u32(&iphdr->dest) & ip4_addr_get_u32(&netif->netmask), 00292 ip4_addr_get_u32(&netif->ip_addr) & ip4_addr_get_u32(&netif->netmask), 00293 ip4_addr_get_u32(&iphdr->dest) & ~ip4_addr_get_u32(&netif->netmask))); 00294 00295 /* interface is up and configured? */ 00296 if ((netif_is_up(netif)) && (!ip_addr_isany(&(netif->ip_addr)))) { 00297 /* unicast to this interface address? */ 00298 if (ip_addr_cmp(&(iphdr->dest), &(netif->ip_addr)) 00299 /* or broadcast on this interface network address? */ 00300 || ip_addr_isbroadcast(&(iphdr->dest), netif) 00301 #if 0 00302 /* or is this to our multicast interface? DIRKX */ 00303 || ip_addr_ismulticast(&(iphdr->dest)) 00304 #endif 00305 ) { 00306 LWIP_DEBUGF(IP_DEBUG, ("ip_input: packet accepted on interface %c%c\n", 00307 netif->name[0], netif->name[1])); 00308 /* break out of for loop */ 00309 break; 00310 } 00311 #if LWIP_AUTOIP 00312 /* connections to link-local addresses must persist after changing 00313 the netif's address (RFC3927 ch. 1.9) */ 00314 if ((netif->autoip != NULL) && 00315 ip_addr_cmp(&(iphdr->dest), &(netif->autoip->llipaddr))) { 00316 LWIP_DEBUGF(IP_DEBUG, ("ip_input: LLA packet accepted on interface %c%c\n", 00317 netif->name[0], netif->name[1])); 00318 /* break out of for loop */ 00319 break; 00320 } 00321 #endif /* LWIP_AUTOIP */ 00322 } 00323 if (first) { 00324 first = 0; 00325 netif = netif_list; 00326 } else { 00327 netif = netif->next; 00328 } 00329 if (netif == inp) { 00330 netif = netif->next; 00331 } 00332 } while(netif != NULL); 00333 } 00334 00335 #if LWIP_DHCP 00336 /* Pass DHCP messages regardless of destination address. DHCP traffic is addressed 00337 * using link layer addressing (such as Ethernet MAC) so we must not filter on IP. 00338 * According to RFC 1542 section 3.1.1, referred by RFC 2131). 00339 */ 00340 if (netif == NULL) { 00341 /* remote port is DHCP server? */ 00342 if (IPH_PROTO(iphdr) == IP_PROTO_UDP) { 00343 LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip_input: UDP packet to DHCP client port %"U16_F"\n", 00344 ntohs(((struct udp_hdr *)((u8_t *)iphdr + iphdr_hlen))->dest))); 00345 if (ntohs(((struct udp_hdr *)((u8_t *)iphdr + iphdr_hlen))->dest) == DHCP_CLIENT_PORT) { 00346 LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip_input: DHCP packet accepted.\n")); 00347 netif = inp; 00348 check_ip_src = 0; 00349 } 00350 } 00351 } 00352 #endif /* LWIP_DHCP */ 00353 00354 /* broadcast or multicast packet source address? Compliant with RFC 1122: 3.2.1.3 */ 00355 #if LWIP_DHCP 00356 /* DHCP servers need 0.0.0.0 to be allowed as source address (RFC 1.1.2.2: 3.2.1.3/a) */ 00357 if (check_ip_src && !ip_addr_isany(&iphdr->src)) 00358 #endif /* LWIP_DHCP */ 00359 { if ((ip_addr_isbroadcast(&(iphdr->src), inp)) || 00360 (ip_addr_ismulticast(&(iphdr->src)))) { 00361 /* packet source is not valid */ 00362 LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("ip_input: packet source is not valid.\n")); 00363 /* free (drop) packet pbufs */ 00364 pbuf_free(p); 00365 IP_STATS_INC(ip.drop); 00366 snmp_inc_ipinaddrerrors(); 00367 snmp_inc_ipindiscards(); 00368 return ERR_OK; 00369 } 00370 } 00371 00372 /* packet not for us? */ 00373 if (netif == NULL) { 00374 /* packet not for us, route or discard */ 00375 LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip_input: packet not for us.\n")); 00376 #if IP_FORWARD 00377 /* non-broadcast packet? */ 00378 if (!ip_addr_isbroadcast(&(iphdr->dest), inp)) { 00379 /* try to forward IP packet on (other) interfaces */ 00380 ip_forward(p, iphdr, inp); 00381 } else 00382 #endif /* IP_FORWARD */ 00383 { 00384 snmp_inc_ipinaddrerrors(); 00385 snmp_inc_ipindiscards(); 00386 } 00387 pbuf_free(p); 00388 return ERR_OK; 00389 } 00390 /* packet consists of multiple fragments? */ 00391 if ((IPH_OFFSET(iphdr) & htons(IP_OFFMASK | IP_MF)) != 0) { 00392 #if IP_REASSEMBLY /* packet fragment reassembly code present? */ 00393 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", 00394 ntohs(IPH_ID(iphdr)), p->tot_len, ntohs(IPH_LEN(iphdr)), !!(IPH_OFFSET(iphdr) & htons(IP_MF)), (ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK)*8)); 00395 /* reassemble the packet*/ 00396 p = ip_reass(p); 00397 /* packet not fully reassembled yet? */ 00398 if (p == NULL) { 00399 return ERR_OK; 00400 } 00401 iphdr = (struct ip_hdr *)p->payload; 00402 #else /* IP_REASSEMBLY == 0, no packet fragment reassembly code present */ 00403 pbuf_free(p); 00404 LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("IP packet dropped since it was fragmented (0x%"X16_F") (while IP_REASSEMBLY == 0).\n", 00405 ntohs(IPH_OFFSET(iphdr)))); 00406 IP_STATS_INC(ip.opterr); 00407 IP_STATS_INC(ip.drop); 00408 /* unsupported protocol feature */ 00409 snmp_inc_ipinunknownprotos(); 00410 return ERR_OK; 00411 #endif /* IP_REASSEMBLY */ 00412 } 00413 00414 #if IP_OPTIONS_ALLOWED == 0 /* no support for IP options in the IP header? */ 00415 00416 #if LWIP_IGMP 00417 /* there is an extra "router alert" option in IGMP messages which we allow for but do not police */ 00418 if((iphdr_hlen > IP_HLEN) && (IPH_PROTO(iphdr) != IP_PROTO_IGMP)) { 00419 #else 00420 if (iphdr_hlen > IP_HLEN) { 00421 #endif /* LWIP_IGMP */ 00422 LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("IP packet dropped since there were IP options (while IP_OPTIONS_ALLOWED == 0).\n")); 00423 pbuf_free(p); 00424 IP_STATS_INC(ip.opterr); 00425 IP_STATS_INC(ip.drop); 00426 /* unsupported protocol feature */ 00427 snmp_inc_ipinunknownprotos(); 00428 return ERR_OK; 00429 } 00430 #endif /* IP_OPTIONS_ALLOWED == 0 */ 00431 00432 /* send to upper layers */ 00433 LWIP_DEBUGF(IP_DEBUG, ("ip_input: \n")); 00434 ip_debug_print(p); 00435 LWIP_DEBUGF(IP_DEBUG, ("ip_input: p->len %"U16_F" p->tot_len %"U16_F"\n", p->len, p->tot_len)); 00436 00437 current_netif = inp; 00438 current_header = iphdr; 00439 00440 #if LWIP_RAW 00441 /* raw input did not eat the packet? */ 00442 if (raw_input(p, inp) == 0) 00443 #endif /* LWIP_RAW */ 00444 { 00445 00446 switch (IPH_PROTO(iphdr)) { 00447 #if LWIP_UDP 00448 case IP_PROTO_UDP: 00449 #if LWIP_UDPLITE 00450 case IP_PROTO_UDPLITE: 00451 #endif /* LWIP_UDPLITE */ 00452 snmp_inc_ipindelivers(); 00453 udp_input(p, inp); 00454 break; 00455 #endif /* LWIP_UDP */ 00456 #if LWIP_TCP 00457 case IP_PROTO_TCP: 00458 snmp_inc_ipindelivers(); 00459 tcp_input(p, inp); 00460 break; 00461 #endif /* LWIP_TCP */ 00462 #if LWIP_ICMP 00463 case IP_PROTO_ICMP: 00464 snmp_inc_ipindelivers(); 00465 icmp_input(p, inp); 00466 break; 00467 #endif /* LWIP_ICMP */ 00468 #if LWIP_IGMP 00469 case IP_PROTO_IGMP: 00470 igmp_input(p,inp,&(iphdr->dest)); 00471 break; 00472 #endif /* LWIP_IGMP */ 00473 default: 00474 #if LWIP_ICMP 00475 /* send ICMP destination protocol unreachable unless is was a broadcast */ 00476 if (!ip_addr_isbroadcast(&(iphdr->dest), inp) && 00477 !ip_addr_ismulticast(&(iphdr->dest))) { 00478 p->payload = iphdr; 00479 icmp_dest_unreach(p, ICMP_DUR_PROTO); 00480 } 00481 #endif /* LWIP_ICMP */ 00482 pbuf_free(p); 00483 00484 LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("Unsupported transport protocol %"U16_F"\n", IPH_PROTO(iphdr))); 00485 00486 IP_STATS_INC(ip.proterr); 00487 IP_STATS_INC(ip.drop); 00488 snmp_inc_ipinunknownprotos(); 00489 } 00490 } 00491 00492 current_netif = NULL; 00493 current_header = NULL; 00494 00495 return ERR_OK; 00496 } 00497 00498 /** 00499 * Sends an IP packet on a network interface. This function constructs 00500 * the IP header and calculates the IP header checksum. If the source 00501 * IP address is NULL, the IP address of the outgoing network 00502 * interface is filled in as source address. 00503 * If the destination IP address is IP_HDRINCL, p is assumed to already 00504 * include an IP header and p->payload points to it instead of the data. 00505 * 00506 * @param p the packet to send (p->payload points to the data, e.g. next 00507 protocol header; if dest == IP_HDRINCL, p already includes an IP 00508 header and p->payload points to that IP header) 00509 * @param src the source IP address to send from (if src == IP_ADDR_ANY, the 00510 * IP address of the netif used to send is used as source address) 00511 * @param dest the destination IP address to send the packet to 00512 * @param ttl the TTL value to be set in the IP header 00513 * @param tos the TOS value to be set in the IP header 00514 * @param proto the PROTOCOL to be set in the IP header 00515 * @param netif the netif on which to send this packet 00516 * @return ERR_OK if the packet was sent OK 00517 * ERR_BUF if p doesn't have enough space for IP/LINK headers 00518 * returns errors returned by netif->output 00519 * 00520 * @note ip_id: RFC791 "some host may be able to simply use 00521 * unique identifiers independent of destination" 00522 */ 00523 err_t 00524 ip_output_if(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, 00525 u8_t ttl, u8_t tos, 00526 u8_t proto, struct netif *netif) 00527 { 00528 #if IP_OPTIONS_SEND 00529 return ip_output_if_opt(p, src, dest, ttl, tos, proto, netif, NULL, 0); 00530 } 00531 00532 /** 00533 * Same as ip_output_if() but with the possibility to include IP options: 00534 * 00535 * @ param ip_options pointer to the IP options, copied into the IP header 00536 * @ param optlen length of ip_options 00537 */ 00538 err_t ip_output_if_opt(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, 00539 u8_t ttl, u8_t tos, u8_t proto, struct netif *netif, void *ip_options, 00540 u16_t optlen) 00541 { 00542 #endif /* IP_OPTIONS_SEND */ 00543 struct ip_hdr *iphdr; 00544 static u16_t ip_id = 0; 00545 00546 /* pbufs passed to IP must have a ref-count of 1 as their payload pointer 00547 gets altered as the packet is passed down the stack */ 00548 LWIP_ASSERT("p->ref == 1", p->ref == 1); 00549 00550 snmp_inc_ipoutrequests(); 00551 00552 /* Should the IP header be generated or is it already included in p? */ 00553 if (dest != IP_HDRINCL) { 00554 u16_t ip_hlen = IP_HLEN; 00555 #if IP_OPTIONS_SEND 00556 u16_t optlen_aligned = 0; 00557 if (optlen != 0) { 00558 /* round up to a multiple of 4 */ 00559 optlen_aligned = ((optlen + 3) & ~3); 00560 ip_hlen += optlen_aligned; 00561 /* First write in the IP options */ 00562 if (pbuf_header(p, optlen_aligned)) { 00563 LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip_output_if_opt: not enough room for IP options in pbuf\n")); 00564 IP_STATS_INC(ip.err); 00565 snmp_inc_ipoutdiscards(); 00566 return ERR_BUF; 00567 } 00568 MEMCPY(p->payload, ip_options, optlen); 00569 if (optlen < optlen_aligned) { 00570 /* zero the remaining bytes */ 00571 memset(((char*)p->payload) + optlen, 0, optlen_aligned - optlen); 00572 } 00573 } 00574 #endif /* IP_OPTIONS_SEND */ 00575 /* generate IP header */ 00576 if (pbuf_header(p, IP_HLEN)) { 00577 LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip_output: not enough room for IP header in pbuf\n")); 00578 00579 IP_STATS_INC(ip.err); 00580 snmp_inc_ipoutdiscards(); 00581 return ERR_BUF; 00582 } 00583 00584 iphdr = (struct ip_hdr *)p->payload; 00585 LWIP_ASSERT("check that first pbuf can hold struct ip_hdr", 00586 (p->len >= sizeof(struct ip_hdr))); 00587 00588 IPH_TTL_SET(iphdr, ttl); 00589 IPH_PROTO_SET(iphdr, proto); 00590 00591 /* dest cannot be NULL here */ 00592 ip_addr_copy(iphdr->dest, *dest); 00593 00594 IPH_VHLTOS_SET(iphdr, 4, ip_hlen / 4, tos); 00595 IPH_LEN_SET(iphdr, htons(p->tot_len)); 00596 IPH_OFFSET_SET(iphdr, 0); 00597 IPH_ID_SET(iphdr, htons(ip_id)); 00598 ++ip_id; 00599 00600 if (ip_addr_isany(src)) { 00601 ip_addr_copy(iphdr->src, netif->ip_addr); 00602 } else { 00603 /* src cannot be NULL here */ 00604 ip_addr_copy(iphdr->src, *src); 00605 } 00606 00607 IPH_CHKSUM_SET(iphdr, 0); 00608 #if CHECKSUM_GEN_IP 00609 IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, ip_hlen)); 00610 #endif 00611 } else { 00612 /* IP header already included in p */ 00613 iphdr = (struct ip_hdr *)p->payload; 00614 dest = &(iphdr->dest); 00615 } 00616 00617 IP_STATS_INC(ip.xmit); 00618 00619 LWIP_DEBUGF(IP_DEBUG, ("ip_output_if: %c%c%"U16_F"\n", netif->name[0], netif->name[1], netif->num)); 00620 ip_debug_print(p); 00621 00622 #if ENABLE_LOOPBACK 00623 if (ip_addr_cmp(dest, &netif->ip_addr)) { 00624 /* Packet to self, enqueue it for loopback */ 00625 LWIP_DEBUGF(IP_DEBUG, ("netif_loop_output()")); 00626 return netif_loop_output(netif, p, dest); 00627 } 00628 #endif /* ENABLE_LOOPBACK */ 00629 #if IP_FRAG 00630 /* don't fragment if interface has mtu set to 0 [loopif] */ 00631 if (netif->mtu && (p->tot_len > netif->mtu)) { 00632 return ip_frag(p,netif,dest); 00633 } 00634 #endif 00635 00636 LWIP_DEBUGF(IP_DEBUG, ("netif->output()")); 00637 return netif->output(netif, p, dest); 00638 } 00639 00640 /** 00641 * Simple interface to ip_output_if. It finds the outgoing network 00642 * interface and calls upon ip_output_if to do the actual work. 00643 * 00644 * @param p the packet to send (p->payload points to the data, e.g. next 00645 protocol header; if dest == IP_HDRINCL, p already includes an IP 00646 header and p->payload points to that IP header) 00647 * @param src the source IP address to send from (if src == IP_ADDR_ANY, the 00648 * IP address of the netif used to send is used as source address) 00649 * @param dest the destination IP address to send the packet to 00650 * @param ttl the TTL value to be set in the IP header 00651 * @param tos the TOS value to be set in the IP header 00652 * @param proto the PROTOCOL to be set in the IP header 00653 * 00654 * @return ERR_RTE if no route is found 00655 * see ip_output_if() for more return values 00656 */ 00657 err_t 00658 ip_output(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, 00659 u8_t ttl, u8_t tos, u8_t proto) 00660 { 00661 struct netif *netif; 00662 00663 /* pbufs passed to IP must have a ref-count of 1 as their payload pointer 00664 gets altered as the packet is passed down the stack */ 00665 LWIP_ASSERT("p->ref == 1", p->ref == 1); 00666 00667 if ((netif = ip_route(dest)) == NULL) { 00668 LWIP_DEBUGF(IP_DEBUG, ("ip_output: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", 00669 ip4_addr1_16(dest), ip4_addr2_16(dest), ip4_addr3_16(dest), ip4_addr4_16(dest))); 00670 IP_STATS_INC(ip.rterr); 00671 return ERR_RTE; 00672 } 00673 00674 return ip_output_if(p, src, dest, ttl, tos, proto, netif); 00675 } 00676 00677 #if LWIP_NETIF_HWADDRHINT 00678 /** Like ip_output, but takes and addr_hint pointer that is passed on to netif->addr_hint 00679 * before calling ip_output_if. 00680 * 00681 * @param p the packet to send (p->payload points to the data, e.g. next 00682 protocol header; if dest == IP_HDRINCL, p already includes an IP 00683 header and p->payload points to that IP header) 00684 * @param src the source IP address to send from (if src == IP_ADDR_ANY, the 00685 * IP address of the netif used to send is used as source address) 00686 * @param dest the destination IP address to send the packet to 00687 * @param ttl the TTL value to be set in the IP header 00688 * @param tos the TOS value to be set in the IP header 00689 * @param proto the PROTOCOL to be set in the IP header 00690 * @param addr_hint address hint pointer set to netif->addr_hint before 00691 * calling ip_output_if() 00692 * 00693 * @return ERR_RTE if no route is found 00694 * see ip_output_if() for more return values 00695 */ 00696 err_t 00697 ip_output_hinted(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, 00698 u8_t ttl, u8_t tos, u8_t proto, u8_t *addr_hint) 00699 { 00700 struct netif *netif; 00701 err_t err; 00702 00703 /* pbufs passed to IP must have a ref-count of 1 as their payload pointer 00704 gets altered as the packet is passed down the stack */ 00705 LWIP_ASSERT("p->ref == 1", p->ref == 1); 00706 00707 if ((netif = ip_route(dest)) == NULL) { 00708 LWIP_DEBUGF(IP_DEBUG, ("ip_output: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", 00709 ip4_addr1_16(dest), ip4_addr2_16(dest), ip4_addr3_16(dest), ip4_addr4_16(dest))); 00710 IP_STATS_INC(ip.rterr); 00711 return ERR_RTE; 00712 } 00713 00714 netif->addr_hint = addr_hint; 00715 err = ip_output_if(p, src, dest, ttl, tos, proto, netif); 00716 netif->addr_hint = NULL; 00717 00718 return err; 00719 } 00720 #endif /* LWIP_NETIF_HWADDRHINT*/ 00721 00722 #if IP_DEBUG 00723 /* Print an IP header by using LWIP_DEBUGF 00724 * @param p an IP packet, p->payload pointing to the IP header 00725 */ 00726 void 00727 ip_debug_print(struct pbuf *p) 00728 { 00729 struct ip_hdr *iphdr = (struct ip_hdr *) p->payload; 00730 u8_t *payload; 00731 00732 payload = (u8_t *)iphdr + IP_HLEN; 00733 00734 LWIP_DEBUGF(IP_DEBUG, ("IP header:\n")); 00735 LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); 00736 LWIP_DEBUGF(IP_DEBUG, ("|%2"S16_F" |%2"S16_F" | 0x%02"X16_F" | %5"U16_F" | (v, hl, tos, len)\n", 00737 IPH_V(iphdr), 00738 IPH_HL(iphdr), 00739 IPH_TOS(iphdr), 00740 ntohs(IPH_LEN(iphdr)))); 00741 LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); 00742 LWIP_DEBUGF(IP_DEBUG, ("| %5"U16_F" |%"U16_F"%"U16_F"%"U16_F"| %4"U16_F" | (id, flags, offset)\n", 00743 ntohs(IPH_ID(iphdr)), 00744 ntohs(IPH_OFFSET(iphdr)) >> 15 & 1, 00745 ntohs(IPH_OFFSET(iphdr)) >> 14 & 1, 00746 ntohs(IPH_OFFSET(iphdr)) >> 13 & 1, 00747 ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK)); 00748 LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); 00749 LWIP_DEBUGF(IP_DEBUG, ("| %3"U16_F" | %3"U16_F" | 0x%04"X16_F" | (ttl, proto, chksum)\n", 00750 IPH_TTL(iphdr), 00751 IPH_PROTO(iphdr), 00752 ntohs(IPH_CHKSUM(iphdr)))); 00753 LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); 00754 LWIP_DEBUGF(IP_DEBUG, ("| %3"U16_F" | %3"U16_F" | %3"U16_F" | %3"U16_F" | (src)\n", 00755 ip4_addr1_16(&iphdr->src), 00756 ip4_addr2_16(&iphdr->src), 00757 ip4_addr3_16(&iphdr->src), 00758 ip4_addr4_16(&iphdr->src))); 00759 LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); 00760 LWIP_DEBUGF(IP_DEBUG, ("| %3"U16_F" | %3"U16_F" | %3"U16_F" | %3"U16_F" | (dest)\n", 00761 ip4_addr1_16(&iphdr->dest), 00762 ip4_addr2_16(&iphdr->dest), 00763 ip4_addr3_16(&iphdr->dest), 00764 ip4_addr4_16(&iphdr->dest))); 00765 LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); 00766 } 00767 #endif /* IP_DEBUG */
Generated on Tue Jul 12 2022 18:11:29 by
