1 |
/* |
/* |
2 |
* Copyright (c) 2001-2003 Swedish Institute of Computer Science. |
* Copyright (c) 2001-2003 Swedish Institute of Computer Science. |
3 |
* All rights reserved. |
* All rights reserved. |
4 |
* |
* |
5 |
* Redistribution and use in source and binary forms, with or without modification, |
* Redistribution and use in source and binary forms, with or without modification, |
6 |
* are permitted provided that the following conditions are met: |
* are permitted provided that the following conditions are met: |
7 |
* |
* |
8 |
* 1. Redistributions of source code must retain the above copyright notice, |
* 1. Redistributions of source code must retain the above copyright notice, |
11 |
* this list of conditions and the following disclaimer in the documentation |
* this list of conditions and the following disclaimer in the documentation |
12 |
* and/or other materials provided with the distribution. |
* and/or other materials provided with the distribution. |
13 |
* 3. The name of the author may not be used to endorse or promote products |
* 3. The name of the author may not be used to endorse or promote products |
14 |
* derived from this software without specific prior written permission. |
* derived from this software without specific prior written permission. |
15 |
* |
* |
16 |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED |
17 |
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
18 |
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT |
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT |
19 |
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
20 |
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT |
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT |
21 |
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
22 |
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
23 |
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING |
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING |
24 |
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY |
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY |
25 |
* OF SUCH DAMAGE. |
* OF SUCH DAMAGE. |
26 |
* |
* |
27 |
* This file is part of the lwIP TCP/IP stack. |
* This file is part of the lwIP TCP/IP stack. |
28 |
* |
* |
29 |
* Author: Adam Dunkels <adam@sics.se> |
* Author: Adam Dunkels <adam@sics.se> |
30 |
* |
* |
31 |
*/ |
*/ |
36 |
* |
* |
37 |
* This is the code for the IP layer. |
* This is the code for the IP layer. |
38 |
* |
* |
39 |
*/ |
*/ |
40 |
/*-----------------------------------------------------------------------------------*/ |
/*-----------------------------------------------------------------------------------*/ |
41 |
|
|
42 |
#include "lwip/opt.h" |
#include "lwip/opt.h" |
104 |
return 0; |
return 0; |
105 |
} |
} |
106 |
#endif /* IP_OPTIONS == 0 */ |
#endif /* IP_OPTIONS == 0 */ |
107 |
|
|
108 |
switch (IPH_PROTO(iphdr)) { |
switch (IPH_PROTO(iphdr)) { |
109 |
#if LWIP_UDP > 0 |
#if LWIP_UDP > 0 |
110 |
case IP_PROTO_UDP: |
case IP_PROTO_UDP: |
111 |
return udp_lookup(iphdr, inp); |
return udp_lookup(iphdr, inp); |
112 |
#endif /* LWIP_UDP */ |
#endif /* LWIP_UDP */ |
113 |
#if LWIP_TCP > 0 |
#if LWIP_TCP > 0 |
114 |
case IP_PROTO_TCP: |
case IP_PROTO_TCP: |
115 |
return 1; |
return 1; |
116 |
#endif /* LWIP_TCP */ |
#endif /* LWIP_TCP */ |
135 |
{ |
{ |
136 |
struct netif *netif; |
struct netif *netif; |
137 |
|
|
138 |
/* iterate through netifs */ |
/* iterate through netifs */ |
139 |
for(netif = netif_list; netif != NULL; netif = netif->next) { |
for(netif = netif_list; netif != NULL; netif = netif->next) { |
140 |
/* network mask matches? */ |
/* network mask matches? */ |
141 |
if (ip_addr_maskcmp(dest, &(netif->ip_addr), &(netif->netmask))) { |
if (ip_addr_maskcmp(dest, &(netif->ip_addr), &(netif->netmask))) { |
159 |
ip_forward(struct pbuf *p, struct ip_hdr *iphdr, struct netif *inp) |
ip_forward(struct pbuf *p, struct ip_hdr *iphdr, struct netif *inp) |
160 |
{ |
{ |
161 |
struct netif *netif; |
struct netif *netif; |
162 |
|
|
163 |
PERF_START; |
PERF_START; |
164 |
/* Find network interface where to forward this IP packet to. */ |
/* Find network interface where to forward this IP packet to. */ |
165 |
netif = ip_route((struct ip_addr *)&(iphdr->dest)); |
netif = ip_route((struct ip_addr *)&(iphdr->dest)); |
176 |
snmp_inc_ipnoroutes(); |
snmp_inc_ipnoroutes(); |
177 |
return; |
return; |
178 |
} |
} |
179 |
|
|
180 |
/* decrement TTL */ |
/* decrement TTL */ |
181 |
IPH_TTL_SET(iphdr, IPH_TTL(iphdr) - 1); |
IPH_TTL_SET(iphdr, IPH_TTL(iphdr) - 1); |
182 |
/* send ICMP if TTL == 0 */ |
/* send ICMP if TTL == 0 */ |
186 |
icmp_time_exceeded(p, ICMP_TE_TTL); |
icmp_time_exceeded(p, ICMP_TE_TTL); |
187 |
snmp_inc_icmpouttimeexcds(); |
snmp_inc_icmpouttimeexcds(); |
188 |
} |
} |
189 |
return; |
return; |
190 |
} |
} |
191 |
|
|
192 |
/* Incrementally update the IP checksum. */ |
/* Incrementally update the IP checksum. */ |
193 |
if (IPH_CHKSUM(iphdr) >= htons(0xffff - 0x100)) { |
if (IPH_CHKSUM(iphdr) >= htons(0xffff - 0x100)) { |
194 |
IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + htons(0x100) + 1); |
IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + htons(0x100) + 1); |
227 |
static struct ip_hdr *iphdr; |
static struct ip_hdr *iphdr; |
228 |
static struct netif *netif; |
static struct netif *netif; |
229 |
static u16_t iphdrlen; |
static u16_t iphdrlen; |
230 |
|
|
231 |
#ifdef IP_STATS |
#ifdef IP_STATS |
232 |
++lwip_stats.ip.recv; |
++lwip_stats.ip.recv; |
233 |
#endif /* IP_STATS */ |
#endif /* IP_STATS */ |
236 |
/* identify the IP header */ |
/* identify the IP header */ |
237 |
iphdr = p->payload; |
iphdr = p->payload; |
238 |
if (IPH_V(iphdr) != 4) { |
if (IPH_V(iphdr) != 4) { |
239 |
LWIP_DEBUGF(IP_DEBUG | 1, ("IP packet dropped due to bad version number %d\n", IPH_V(iphdr))); |
LWIP_DEBUGF(IP_DEBUG | 1, ("IP packet dropped due to bad version number %u\n", IPH_V(iphdr))); |
240 |
#if IP_DEBUG |
#if IP_DEBUG |
241 |
ip_debug_print(p); |
ip_debug_print(p); |
242 |
#endif /* IP_DEBUG */ |
#endif /* IP_DEBUG */ |
253 |
/* calculate IP header length in bytes */ |
/* calculate IP header length in bytes */ |
254 |
iphdrlen *= 4; |
iphdrlen *= 4; |
255 |
|
|
256 |
/* header length exceeds first pbuf length? */ |
/* header length exceeds first pbuf length? */ |
257 |
if (iphdrlen > p->len) { |
if (iphdrlen > p->len) { |
258 |
LWIP_DEBUGF(IP_DEBUG | 2, ("IP header (len %u) does not fit in first pbuf (len %u), IP packet droppped.\n", |
LWIP_DEBUGF(IP_DEBUG | 2, ("IP header (len %u) does not fit in first pbuf (len %u), IP packet droppped.\n", |
259 |
iphdrlen, p->len)); |
iphdrlen, p->len)); |
282 |
snmp_inc_ipindiscards(); |
snmp_inc_ipindiscards(); |
283 |
return ERR_OK; |
return ERR_OK; |
284 |
} |
} |
285 |
|
|
286 |
/* Trim pbuf. This should have been done at the netif layer, |
/* Trim pbuf. This should have been done at the netif layer, |
287 |
but we'll do it anyway just to be sure that its done. */ |
but we'll do it anyway just to be sure that its done. */ |
288 |
pbuf_realloc(p, ntohs(IPH_LEN(iphdr))); |
pbuf_realloc(p, ntohs(IPH_LEN(iphdr))); |
329 |
} |
} |
330 |
} |
} |
331 |
#endif /* LWIP_DHCP */ |
#endif /* LWIP_DHCP */ |
332 |
/* packet not for us? */ |
/* packet not for us? */ |
333 |
if (netif == NULL) { |
if (netif == NULL) { |
334 |
/* packet not for us, route or discard */ |
/* packet not for us, route or discard */ |
335 |
LWIP_DEBUGF(IP_DEBUG | DBG_TRACE | 1, ("ip_input: packet not for us.\n")); |
LWIP_DEBUGF(IP_DEBUG | DBG_TRACE | 1, ("ip_input: packet not for us.\n")); |
350 |
|
|
351 |
#if IP_REASSEMBLY |
#if IP_REASSEMBLY |
352 |
if ((IPH_OFFSET(iphdr) & htons(IP_OFFMASK | IP_MF)) != 0) { |
if ((IPH_OFFSET(iphdr) & htons(IP_OFFMASK | IP_MF)) != 0) { |
353 |
LWIP_DEBUGF(IP_DEBUG, ("IP packet is a fragment (id=0x%04x tot_len=%u len=%u MF=%u offset=%u), calling ip_reass()\n", ntohs(IPH_ID(iphdr)), p->tot_len, ntohs(IPH_LEN(iphdr)), !!(IPH_OFFSET(iphdr) & htons(IP_MF)), (ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK)*8)); |
LWIP_DEBUGF(IP_DEBUG, ("IP packet is a fragment (id=0x%04x tot_len=%u len=%u MF=%u offset=%u), |
354 |
|
calling ip_reass()\n", ntohs(IPH_ID(iphdr)), p->tot_len, ntohs(IPH_LEN(iphdr)), !!(IPH_OFFSET(iphdr) & htons(IP_MF)), (ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK)*8)); |
355 |
p = ip_reass(p); |
p = ip_reass(p); |
356 |
if (p == NULL) { |
if (p == NULL) { |
357 |
return ERR_OK; |
return ERR_OK; |
371 |
return ERR_OK; |
return ERR_OK; |
372 |
} |
} |
373 |
#endif /* IP_REASSEMBLY */ |
#endif /* IP_REASSEMBLY */ |
374 |
|
|
375 |
#if IP_OPTIONS == 0 |
#if IP_OPTIONS == 0 |
376 |
if (iphdrlen > IP_HLEN) { |
if (iphdrlen > IP_HLEN) { |
377 |
LWIP_DEBUGF(IP_DEBUG | 2, ("IP packet dropped since there were IP options (while IP_OPTIONS == 0).\n")); |
LWIP_DEBUGF(IP_DEBUG | 2, ("IP packet dropped since there were IP options (while IP_OPTIONS == 0).\n")); |
378 |
pbuf_free(p); |
pbuf_free(p); |
379 |
#ifdef IP_STATS |
#ifdef IP_STATS |
380 |
++lwip_stats.ip.opterr; |
++lwip_stats.ip.opterr; |
381 |
++lwip_stats.ip.drop; |
++lwip_stats.ip.drop; |
382 |
#endif /* IP_STATS */ |
#endif /* IP_STATS */ |
383 |
snmp_inc_ipunknownprotos(); |
snmp_inc_ipunknownprotos(); |
384 |
return ERR_OK; |
return ERR_OK; |
385 |
} |
} |
386 |
#endif /* IP_OPTIONS == 0 */ |
#endif /* IP_OPTIONS == 0 */ |
387 |
|
|
388 |
/* send to upper layers */ |
/* send to upper layers */ |
390 |
LWIP_DEBUGF(IP_DEBUG, ("ip_input: \n")); |
LWIP_DEBUGF(IP_DEBUG, ("ip_input: \n")); |
391 |
ip_debug_print(p); |
ip_debug_print(p); |
392 |
LWIP_DEBUGF(IP_DEBUG, ("ip_input: p->len %d p->tot_len %d\n", p->len, p->tot_len)); |
LWIP_DEBUGF(IP_DEBUG, ("ip_input: p->len %d p->tot_len %d\n", p->len, p->tot_len)); |
393 |
#endif /* IP_DEBUG */ |
#endif /* IP_DEBUG */ |
394 |
|
|
395 |
switch (IPH_PROTO(iphdr)) { |
switch (IPH_PROTO(iphdr)) { |
396 |
#if LWIP_UDP > 0 |
#if LWIP_UDP > 0 |
397 |
case IP_PROTO_UDP: |
case IP_PROTO_UDP: |
398 |
snmp_inc_ipindelivers(); |
snmp_inc_ipindelivers(); |
399 |
udp_input(p, inp); |
udp_input(p, inp); |
400 |
break; |
break; |
401 |
#endif /* LWIP_UDP */ |
#endif /* LWIP_UDP */ |
402 |
#if LWIP_TCP > 0 |
#if LWIP_TCP > 0 |
403 |
case IP_PROTO_TCP: |
case IP_PROTO_TCP: |
404 |
snmp_inc_ipindelivers(); |
snmp_inc_ipindelivers(); |
405 |
tcp_input(p, inp); |
tcp_input(p, inp); |
448 |
static u16_t ip_id = 0; |
static u16_t ip_id = 0; |
449 |
|
|
450 |
snmp_inc_ipoutrequests(); |
snmp_inc_ipoutrequests(); |
451 |
|
|
452 |
if (dest != IP_HDRINCL) { |
if (dest != IP_HDRINCL) { |
453 |
if (pbuf_header(p, IP_HLEN)) { |
if (pbuf_header(p, IP_HLEN)) { |
454 |
LWIP_DEBUGF(IP_DEBUG | 2, ("ip_output: not enough room for IP header in pbuf\n")); |
LWIP_DEBUGF(IP_DEBUG | 2, ("ip_output: not enough room for IP header in pbuf\n")); |
455 |
|
|
456 |
#ifdef IP_STATS |
#ifdef IP_STATS |
457 |
++lwip_stats.ip.err; |
++lwip_stats.ip.err; |
458 |
#endif /* IP_STATS */ |
#endif /* IP_STATS */ |
459 |
snmp_inc_ipoutdiscards(); |
snmp_inc_ipoutdiscards(); |
460 |
return ERR_BUF; |
return ERR_BUF; |
461 |
} |
} |
462 |
|
|
463 |
iphdr = p->payload; |
iphdr = p->payload; |
464 |
|
|
465 |
IPH_TTL_SET(iphdr, ttl); |
IPH_TTL_SET(iphdr, ttl); |
466 |
IPH_PROTO_SET(iphdr, proto); |
IPH_PROTO_SET(iphdr, proto); |
467 |
|
|
468 |
ip_addr_set(&(iphdr->dest), dest); |
ip_addr_set(&(iphdr->dest), dest); |
469 |
|
|
470 |
IPH_VHLTOS_SET(iphdr, 4, IP_HLEN / 4, 0); |
IPH_VHLTOS_SET(iphdr, 4, IP_HLEN / 4, 0); |
486 |
dest = &(iphdr->dest); |
dest = &(iphdr->dest); |
487 |
} |
} |
488 |
|
|
489 |
#if IP_FRAG |
#if IP_FRAG |
490 |
/* don't fragment if interface has mtu set to 0 [loopif] */ |
/* don't fragment if interface has mtu set to 0 [loopif] */ |
491 |
if (netif->mtu && (p->tot_len > netif->mtu)) |
if (netif->mtu && (p->tot_len > netif->mtu)) |
492 |
return ip_frag(p,netif,dest); |
return ip_frag(p,netif,dest); |
493 |
#endif |
#endif |
494 |
|
|
495 |
#ifdef IP_STATS |
#ifdef IP_STATS |
496 |
lwip_stats.ip.xmit++; |
lwip_stats.ip.xmit++; |
497 |
#endif /* IP_STATS */ |
#endif /* IP_STATS */ |
502 |
|
|
503 |
LWIP_DEBUGF(IP_DEBUG, ("netif->output()")); |
LWIP_DEBUGF(IP_DEBUG, ("netif->output()")); |
504 |
|
|
505 |
return netif->output(netif, p, dest); |
return netif->output(netif, p, dest); |
506 |
} |
} |
507 |
/*-----------------------------------------------------------------------------------*/ |
/*-----------------------------------------------------------------------------------*/ |
508 |
/* ip_output: |
/* ip_output: |
516 |
u8_t ttl, u8_t proto) |
u8_t ttl, u8_t proto) |
517 |
{ |
{ |
518 |
struct netif *netif; |
struct netif *netif; |
519 |
|
|
520 |
if ((netif = ip_route(dest)) == NULL) { |
if ((netif = ip_route(dest)) == NULL) { |
521 |
LWIP_DEBUGF(IP_DEBUG | 2, ("ip_output: No route to 0x%lx\n", dest->addr)); |
LWIP_DEBUGF(IP_DEBUG | 2, ("ip_output: No route to 0x%lx\n", dest->addr)); |
522 |
|
|
538 |
u8_t *payload; |
u8_t *payload; |
539 |
|
|
540 |
payload = (u8_t *)iphdr + IP_HLEN; |
payload = (u8_t *)iphdr + IP_HLEN; |
541 |
|
|
542 |
LWIP_DEBUGF(IP_DEBUG, ("IP header:\n")); |
LWIP_DEBUGF(IP_DEBUG, ("IP header:\n")); |
543 |
LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); |
LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); |
544 |
LWIP_DEBUGF(IP_DEBUG, ("|%2d |%2d | 0x%02x | %5u | (v, hl, tos, len)\n", |
LWIP_DEBUGF(IP_DEBUG, ("|%2d |%2d | 0x%02x | %5u | (v, hl, tos, len)\n", |