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