NetServices Stack source
Dependents: HelloWorld ServoInterfaceBoardExample1 4180_Lab4
Diff: lwip/core/ipv4/ip.c
- Revision:
- 5:dd63a1e02b1b
- Parent:
- 0:632c9925f013
--- a/lwip/core/ipv4/ip.c Fri Jul 09 14:46:47 2010 +0000 +++ b/lwip/core/ipv4/ip.c Tue Jul 27 15:59:42 2010 +0000 @@ -58,6 +58,41 @@ #include <string.h> +/** Set this to 0 in the rare case of wanting to call an extra function to + * generate the IP checksum (in contrast to calculating it on-the-fly). */ +#ifndef LWIP_INLINE_IP_CHKSUM +#define LWIP_INLINE_IP_CHKSUM 1 +#endif +#if LWIP_INLINE_IP_CHKSUM && CHECKSUM_GEN_IP +#define CHECKSUM_GEN_IP_INLINE 1 +#else +#define CHECKSUM_GEN_IP_INLINE 0 +#endif + +#if LWIP_DHCP || defined(LWIP_IP_ACCEPT_UDP_PORT) +#define IP_ACCEPT_LINK_LAYER_ADDRESSING 1 + +/** Some defines for DHCP to let link-layer-addressed packets through while the + * netif is down. + * To use this in your own application/protocol, define LWIP_IP_ACCEPT_UDP_PORT + * to return 1 if the port is accepted and 0 if the port is not accepted. + */ +#if LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT) +/* accept DHCP client port and custom port */ +#define IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(port) (((port) == PP_NTOHS(DHCP_CLIENT_PORT)) \ + || (LWIP_IP_ACCEPT_UDP_PORT(port))) +#elif defined(LWIP_IP_ACCEPT_UDP_PORT) /* LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT) */ +/* accept custom port only */ +#define IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(port) (LWIP_IP_ACCEPT_UDP_PORT(dst_port)) +#else /* LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT) */ +/* accept DHCP client port only */ +#define IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(port) ((port) == PP_NTOHS(DHCP_CLIENT_PORT)) +#endif /* LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT) */ + +#else /* LWIP_DHCP */ +#define IP_ACCEPT_LINK_LAYER_ADDRESSING 0 +#endif /* LWIP_DHCP */ + /** * The interface that provided the packet for the current callback * invocation. @@ -68,6 +103,13 @@ * Header of the input packet currently being processed. */ const struct ip_hdr *current_header; +/** Source IP address of current_header */ +ip_addr_t current_iphdr_src; +/** Destination IP address of current_header */ +ip_addr_t current_iphdr_dest; + +/** The IP header ID of the next outgoing IP packet */ +static u16_t ip_id; /** * Finds the appropriate network interface for a given IP address. It @@ -113,39 +155,35 @@ * @param p the packet to forward (p->payload points to IP header) * @param iphdr the IP header of the input packet * @param inp the netif on which this packet was received - * @return the netif on which the packet was sent (NULL if it wasn't sent) */ -static struct netif * +static void ip_forward(struct pbuf *p, struct ip_hdr *iphdr, struct netif *inp) { struct netif *netif; - ip_addr_t dest; PERF_START; - dest = iphdr->dest; /* RFC3927 2.7: do not forward link-local addresses */ - if (ip_addr_islinklocal(&dest)) { + if (ip_addr_islinklocal(¤t_iphdr_dest)) { LWIP_DEBUGF(IP_DEBUG, ("ip_forward: not forwarding LLA %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", - ip4_addr1_16(&dest), ip4_addr2_16(&dest), ip4_addr3_16(&dest), ip4_addr4_16(&dest))); - snmp_inc_ipoutnoroutes(); - return (struct netif *)NULL; + ip4_addr1_16(¤t_iphdr_dest), ip4_addr2_16(¤t_iphdr_dest), + ip4_addr3_16(¤t_iphdr_dest), ip4_addr4_16(¤t_iphdr_dest))); + goto return_noroute; } /* Find network interface where to forward this IP packet to. */ - netif = ip_route(&dest); + netif = ip_route(¤t_iphdr_dest); if (netif == NULL) { LWIP_DEBUGF(IP_DEBUG, ("ip_forward: no forwarding route for %"U16_F".%"U16_F".%"U16_F".%"U16_F" found\n", - ip4_addr1_16(&dest), ip4_addr2_16(&dest), ip4_addr3_16(&dest), ip4_addr4_16(&dest))); - snmp_inc_ipoutnoroutes(); - return (struct netif *)NULL; + ip4_addr1_16(¤t_iphdr_dest), ip4_addr2_16(¤t_iphdr_dest), + ip4_addr3_16(¤t_iphdr_dest), ip4_addr4_16(¤t_iphdr_dest))); + goto return_noroute; } /* Do not forward packets onto the same network interface on which * they arrived. */ if (netif == inp) { LWIP_DEBUGF(IP_DEBUG, ("ip_forward: not bouncing packets back on incoming interface.\n")); - snmp_inc_ipoutnoroutes(); - return (struct netif *)NULL; + goto return_noroute; } /* decrement TTL */ @@ -159,18 +197,19 @@ icmp_time_exceeded(p, ICMP_TE_TTL); } #endif /* LWIP_ICMP */ - return (struct netif *)NULL; + return; } /* Incrementally update the IP checksum. */ - if (IPH_CHKSUM(iphdr) >= htons(0xffff - 0x100)) { - IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + htons(0x100) + 1); + if (IPH_CHKSUM(iphdr) >= PP_HTONS(0xffff - 0x100)) { + IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + PP_HTONS(0x100) + 1); } else { - IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + htons(0x100)); + IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + PP_HTONS(0x100)); } LWIP_DEBUGF(IP_DEBUG, ("ip_forward: forwarding packet to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", - ip4_addr1_16(&dest), ip4_addr2_16(&dest), ip4_addr3_16(&dest), ip4_addr4_16(&dest))); + ip4_addr1_16(¤t_iphdr_dest), ip4_addr2_16(¤t_iphdr_dest), + ip4_addr3_16(¤t_iphdr_dest), ip4_addr4_16(¤t_iphdr_dest))); IP_STATS_INC(ip.fw); IP_STATS_INC(ip.xmit); @@ -178,8 +217,10 @@ PERF_STOP("ip_forward"); /* transmit pbuf on chosen interface */ - netif->output(netif, p, &dest); - return netif; + netif->output(netif, p, ¤t_iphdr_dest); + return; +return_noroute: + snmp_inc_ipoutnoroutes(); } #endif /* IP_FORWARD */ @@ -204,9 +245,9 @@ struct netif *netif; u16_t iphdr_hlen; u16_t iphdr_len; -#if LWIP_DHCP +#if IP_ACCEPT_LINK_LAYER_ADDRESSING int check_ip_src=1; -#endif /* LWIP_DHCP */ +#endif /* IP_ACCEPT_LINK_LAYER_ADDRESSING */ IP_STATS_INC(ip.recv); snmp_inc_ipinreceives(); @@ -269,10 +310,14 @@ * but we'll do it anyway just to be sure that its done. */ pbuf_realloc(p, iphdr_len); + /* copy IP addresses to aligned ip_addr_t */ + ip_addr_copy(current_iphdr_dest, iphdr->dest); + ip_addr_copy(current_iphdr_src, iphdr->src); + /* match packet against an interface, i.e. is this packet for us? */ #if LWIP_IGMP - if (ip_addr_ismulticast(&(iphdr->dest))) { - if ((inp->flags & NETIF_FLAG_IGMP) && (igmp_lookfor_group(inp, &(iphdr->dest)))) { + if (ip_addr_ismulticast(¤t_iphdr_dest)) { + if ((inp->flags & NETIF_FLAG_IGMP) && (igmp_lookfor_group(inp, ¤t_iphdr_dest))) { netif = inp; } else { netif = NULL; @@ -295,9 +340,9 @@ /* interface is up and configured? */ if ((netif_is_up(netif)) && (!ip_addr_isany(&(netif->ip_addr)))) { /* unicast to this interface address? */ - if (ip_addr_cmp(&(iphdr->dest), &(netif->ip_addr)) || + if (ip_addr_cmp(¤t_iphdr_dest, &(netif->ip_addr)) || /* or broadcast on this interface network address? */ - ip_addr_isbroadcast(&(iphdr->dest), netif)) { + ip_addr_isbroadcast(¤t_iphdr_dest, netif)) { LWIP_DEBUGF(IP_DEBUG, ("ip_input: packet accepted on interface %c%c\n", netif->name[0], netif->name[1])); /* break out of for loop */ @@ -307,7 +352,7 @@ /* connections to link-local addresses must persist after changing the netif's address (RFC3927 ch. 1.9) */ if ((netif->autoip != NULL) && - ip_addr_cmp(&(iphdr->dest), &(netif->autoip->llipaddr))) { + ip_addr_cmp(¤t_iphdr_dest, &(netif->autoip->llipaddr))) { LWIP_DEBUGF(IP_DEBUG, ("ip_input: LLA packet accepted on interface %c%c\n", netif->name[0], netif->name[1])); /* break out of for loop */ @@ -327,32 +372,38 @@ } while(netif != NULL); } -#if LWIP_DHCP +#if IP_ACCEPT_LINK_LAYER_ADDRESSING /* Pass DHCP messages regardless of destination address. DHCP traffic is addressed * using link layer addressing (such as Ethernet MAC) so we must not filter on IP. * According to RFC 1542 section 3.1.1, referred by RFC 2131). + * + * If you want to accept private broadcast communication while a netif is down, + * define LWIP_IP_ACCEPT_UDP_PORT(dst_port), e.g.: + * + * #define LWIP_IP_ACCEPT_UDP_PORT(dst_port) ((dst_port) == PP_NTOHS(12345)) */ if (netif == NULL) { /* remote port is DHCP server? */ if (IPH_PROTO(iphdr) == IP_PROTO_UDP) { + struct udp_hdr *udphdr = (struct udp_hdr *)((u8_t *)iphdr + iphdr_hlen); LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip_input: UDP packet to DHCP client port %"U16_F"\n", - ntohs(((struct udp_hdr *)((u8_t *)iphdr + iphdr_hlen))->dest))); - if (ntohs(((struct udp_hdr *)((u8_t *)iphdr + iphdr_hlen))->dest) == DHCP_CLIENT_PORT) { + ntohs(udphdr->dest))); + if (IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(udphdr->dest)) { LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip_input: DHCP packet accepted.\n")); netif = inp; check_ip_src = 0; } } } -#endif /* LWIP_DHCP */ +#endif /* IP_ACCEPT_LINK_LAYER_ADDRESSING */ /* broadcast or multicast packet source address? Compliant with RFC 1122: 3.2.1.3 */ -#if LWIP_DHCP +#if IP_ACCEPT_LINK_LAYER_ADDRESSING /* DHCP servers need 0.0.0.0 to be allowed as source address (RFC 1.1.2.2: 3.2.1.3/a) */ - if (check_ip_src && !ip_addr_isany(&iphdr->src)) -#endif /* LWIP_DHCP */ - { if ((ip_addr_isbroadcast(&(iphdr->src), inp)) || - (ip_addr_ismulticast(&(iphdr->src)))) { + if (check_ip_src && !ip_addr_isany(¤t_iphdr_src)) +#endif /* IP_ACCEPT_LINK_LAYER_ADDRESSING */ + { if ((ip_addr_isbroadcast(¤t_iphdr_src, inp)) || + (ip_addr_ismulticast(¤t_iphdr_src))) { /* packet source is not valid */ LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("ip_input: packet source is not valid.\n")); /* free (drop) packet pbufs */ @@ -370,7 +421,7 @@ LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip_input: packet not for us.\n")); #if IP_FORWARD /* non-broadcast packet? */ - if (!ip_addr_isbroadcast(&(iphdr->dest), inp)) { + if (!ip_addr_isbroadcast(¤t_iphdr_dest, inp)) { /* try to forward IP packet on (other) interfaces */ ip_forward(p, iphdr, inp); } else @@ -383,10 +434,10 @@ return ERR_OK; } /* packet consists of multiple fragments? */ - if ((IPH_OFFSET(iphdr) & htons(IP_OFFMASK | IP_MF)) != 0) { + if ((IPH_OFFSET(iphdr) & PP_HTONS(IP_OFFMASK | IP_MF)) != 0) { #if IP_REASSEMBLY /* packet fragment reassembly code present? */ 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", - ntohs(IPH_ID(iphdr)), p->tot_len, ntohs(IPH_LEN(iphdr)), !!(IPH_OFFSET(iphdr) & htons(IP_MF)), (ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK)*8)); + ntohs(IPH_ID(iphdr)), p->tot_len, ntohs(IPH_LEN(iphdr)), !!(IPH_OFFSET(iphdr) & PP_HTONS(IP_MF)), (ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK)*8)); /* reassemble the packet*/ p = ip_reass(p); /* packet not fully reassembled yet? */ @@ -462,14 +513,14 @@ #endif /* LWIP_ICMP */ #if LWIP_IGMP case IP_PROTO_IGMP: - igmp_input(p,inp,&(iphdr->dest)); + igmp_input(p, inp, ¤t_iphdr_dest); break; #endif /* LWIP_IGMP */ default: #if LWIP_ICMP /* send ICMP destination protocol unreachable unless is was a broadcast */ - if (!ip_addr_isbroadcast(&(iphdr->dest), inp) && - !ip_addr_ismulticast(&(iphdr->dest))) { + if (!ip_addr_isbroadcast(¤t_iphdr_dest, inp) && + !ip_addr_ismulticast(¤t_iphdr_dest)) { p->payload = iphdr; icmp_dest_unreach(p, ICMP_DUR_PROTO); } @@ -486,6 +537,8 @@ current_netif = NULL; current_header = NULL; + ip_addr_set_any(¤t_iphdr_src); + ip_addr_set_any(¤t_iphdr_dest); return ERR_OK; } @@ -536,7 +589,10 @@ { #endif /* IP_OPTIONS_SEND */ struct ip_hdr *iphdr; - static u16_t ip_id = 0; + ip_addr_t dest_addr; +#if CHECKSUM_GEN_IP_INLINE + u32_t chk_sum = 0; +#endif /* CHECKSUM_GEN_IP_INLINE */ /* pbufs passed to IP must have a ref-count of 1 as their payload pointer gets altered as the packet is passed down the stack */ @@ -550,6 +606,9 @@ #if IP_OPTIONS_SEND u16_t optlen_aligned = 0; if (optlen != 0) { +#if CHECKSUM_GEN_IP_INLINE + int i; +#endif /* CHECKSUM_GEN_IP_INLINE */ /* round up to a multiple of 4 */ optlen_aligned = ((optlen + 3) & ~3); ip_hlen += optlen_aligned; @@ -565,6 +624,11 @@ /* zero the remaining bytes */ memset(((char*)p->payload) + optlen, 0, optlen_aligned - optlen); } +#if CHECKSUM_GEN_IP_INLINE + for (i = 0; i < optlen_aligned; i += sizeof(u16_t)) { + chk_sum += ((u16_t*)p->payload)[i]; + } +#endif /* CHECKSUM_GEN_IP_INLINE */ } #endif /* IP_OPTIONS_SEND */ /* generate IP header */ @@ -582,14 +646,30 @@ IPH_TTL_SET(iphdr, ttl); IPH_PROTO_SET(iphdr, proto); +#if CHECKSUM_GEN_IP_INLINE + chk_sum += LWIP_MAKE_U16(proto, ttl); +#endif /* CHECKSUM_GEN_IP_INLINE */ /* dest cannot be NULL here */ ip_addr_copy(iphdr->dest, *dest); +#if CHECKSUM_GEN_IP_INLINE + chk_sum += ip4_addr_get_u32(&iphdr->dest) & 0xFFFF; + chk_sum += ip4_addr_get_u32(&iphdr->dest) >> 16; +#endif /* CHECKSUM_GEN_IP_INLINE */ IPH_VHLTOS_SET(iphdr, 4, ip_hlen / 4, tos); +#if CHECKSUM_GEN_IP_INLINE + chk_sum += iphdr->_v_hl_tos; +#endif /* CHECKSUM_GEN_IP_INLINE */ IPH_LEN_SET(iphdr, htons(p->tot_len)); +#if CHECKSUM_GEN_IP_INLINE + chk_sum += iphdr->_len; +#endif /* CHECKSUM_GEN_IP_INLINE */ IPH_OFFSET_SET(iphdr, 0); IPH_ID_SET(iphdr, htons(ip_id)); +#if CHECKSUM_GEN_IP_INLINE + chk_sum += iphdr->_id; +#endif /* CHECKSUM_GEN_IP_INLINE */ ++ip_id; if (ip_addr_isany(src)) { @@ -599,14 +679,24 @@ ip_addr_copy(iphdr->src, *src); } +#if CHECKSUM_GEN_IP_INLINE + chk_sum += ip4_addr_get_u32(&iphdr->src) & 0xFFFF; + chk_sum += ip4_addr_get_u32(&iphdr->src) >> 16; + chk_sum = (chk_sum >> 16) + (chk_sum & 0xFFFF); + chk_sum = (chk_sum >> 16) + chk_sum; + chk_sum = ~chk_sum; + iphdr->_chksum = chk_sum; /* network order */ +#else /* CHECKSUM_GEN_IP_INLINE */ IPH_CHKSUM_SET(iphdr, 0); #if CHECKSUM_GEN_IP IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, ip_hlen)); #endif +#endif /* CHECKSUM_GEN_IP_INLINE */ } else { /* IP header already included in p */ iphdr = (struct ip_hdr *)p->payload; - dest = &(iphdr->dest); + ip_addr_copy(dest_addr, iphdr->dest); + dest = &dest_addr; } IP_STATS_INC(ip.xmit); @@ -620,13 +710,18 @@ LWIP_DEBUGF(IP_DEBUG, ("netif_loop_output()")); return netif_loop_output(netif, p, dest); } +#if LWIP_IGMP + if ((p->flags & PBUF_FLAG_MCASTLOOP) != 0) { + netif_loop_output(netif, p, dest); + } +#endif /* LWIP_IGMP */ #endif /* ENABLE_LOOPBACK */ #if IP_FRAG /* don't fragment if interface has mtu set to 0 [loopif] */ if (netif->mtu && (p->tot_len > netif->mtu)) { - return ip_frag(p,netif,dest); + return ip_frag(p, netif, dest); } -#endif +#endif /* IP_FRAG */ LWIP_DEBUGF(IP_DEBUG, ("netif->output()")); return netif->output(netif, p, dest); @@ -721,7 +816,7 @@ void ip_debug_print(struct pbuf *p) { - struct ip_hdr *iphdr = (struct ip_hdr *) p->payload; + struct ip_hdr *iphdr = (struct ip_hdr *)p->payload; u8_t *payload; payload = (u8_t *)iphdr + IP_HLEN;