diff --git a/CHANGELOG b/CHANGELOG index eff3a274..58519a75 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -13,6 +13,9 @@ HISTORY ++ New features: + 2010-04-28: Patch by Bill Auerbach + * ip.c: Inline generating IP checksum to save a function call + 2010-04-14: Simon Goldschmidt * tcpip.h/.c, timers.c: Added an overridable define to get informed when the tcpip_thread processes messages or timeouts to implement a watchdog. diff --git a/src/core/ipv4/ip.c b/src/core/ipv4/ip.c index 0b6d94db..fcca17c6 100644 --- a/src/core/ipv4/ip.c +++ b/src/core/ipv4/ip.c @@ -58,6 +58,17 @@ #include +/** 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 + /** * The interface that provided the packet for the current callback * invocation. @@ -537,6 +548,9 @@ err_t ip_output_if_opt(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, #endif /* IP_OPTIONS_SEND */ struct ip_hdr *iphdr; static u16_t ip_id = 0; +#if CHECKSUM_GEN_IP_INLINE + u32_t chk_sum; +#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 */ @@ -582,14 +596,30 @@ err_t ip_output_if_opt(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, IPH_TTL_SET(iphdr, ttl); IPH_PROTO_SET(iphdr, proto); +#if CHECKSUM_GEN_IP_INLINE + chk_sum = (proto << 8) | ttl; +#endif /* CHECKSUM_GEN_IP_INLINE */ /* dest cannot be NULL here */ ip_addr_copy(iphdr->dest, *dest); +#if CHECKSUM_GEN_IP_INLINE + chk_sum += iphdr->dest.addr & 0xFFFF; + chk_sum += iphdr->dest.addr >> 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,10 +629,19 @@ err_t ip_output_if_opt(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, ip_addr_copy(iphdr->src, *src); } +#if CHECKSUM_GEN_IP_INLINE + chk_sum += iphdr->src.addr & 0xFFFF; + chk_sum += iphdr->src.addr >> 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;