From 078e2f60d613eda13cc69bb6bdb1f5c322d4a6ef Mon Sep 17 00:00:00 2001 From: goldsimon Date: Tue, 12 May 2009 18:00:47 +0000 Subject: [PATCH] bug #26487: Added ip_output_if_opt that can add IP options to the IP header (used by igmp_ip_output_if) --- CHANGELOG | 6 +++- src/core/ipv4/igmp.c | 64 ++++---------------------------------- src/core/ipv4/ip.c | 40 ++++++++++++++++++++++-- src/include/ipv4/lwip/ip.h | 8 +++++ 4 files changed, 57 insertions(+), 61 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 4239dcad..92ed75e1 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -47,7 +47,7 @@ HISTORY 2009-04-15 Simon Goldschmidt * dhcp.c: patch #6763: Global DHCP XID can be redefined to something more unique -² + 2009-03-31 Kieran Mansley * tcp.c, tcp_out.c, tcp_in.c, sys.h, tcp.h, opts.h: add support for TCP timestamp options, off by default. Rework tcp_enqueue() to @@ -109,6 +109,10 @@ HISTORY ++ Bugfixes: + 2009-05-12 Simon Goldschmidt + * ip.h, ip.c, igmp.c: bug #26487: Added ip_output_if_opt that can add IP options + to the IP header (used by igmp_ip_output_if) + 2009-05-06 Simon Goldschmidt * inet_chksum.c: On little endian architectures, use LWIP_PLATFORM_HTONS (if defined) for SWAP_BYTES_IN_WORD to speed up checksumming. diff --git a/src/core/ipv4/igmp.c b/src/core/ipv4/igmp.c index 33ce5fc3..062500aa 100644 --- a/src/core/ipv4/igmp.c +++ b/src/core/ipv4/igmp.c @@ -667,7 +667,8 @@ igmp_stop_timer(struct igmp_group *group) void igmp_delaying_member( struct igmp_group *group, u8_t maxresp) { - if ((group->group_state == IGMP_GROUP_IDLE_MEMBER) || ((group->group_state == IGMP_GROUP_DELAYING_MEMBER) && (maxresp > group->timer))) { + if ((group->group_state == IGMP_GROUP_IDLE_MEMBER) || + ((group->group_state == IGMP_GROUP_DELAYING_MEMBER) && (maxresp > group->timer))) { igmp_start_timer(group, (maxresp)/2); group->group_state = IGMP_GROUP_DELAYING_MEMBER; } @@ -696,64 +697,11 @@ err_t igmp_ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, u8_t ttl, u8_t proto, struct netif *netif) { - static u16_t ip_id = 0; - struct ip_hdr * iphdr = NULL; - u16_t * ra = NULL; - - /* First write in the "router alert" */ - if (pbuf_header(p, ROUTER_ALERTLEN)) { - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_ip_output_if: not enough room for IP header in pbuf\n")); - return ERR_BUF; - } - /* This is the "router alert" option */ - ra = p->payload; + u16_t ra[2]; ra[0] = htons (ROUTER_ALERT); ra[1] = 0x0000; /* Router shall examine packet */ - - /* now the normal ip header */ - if (pbuf_header(p, IP_HLEN)) { - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_ip_output_if: not enough room for IP header in pbuf\n")); - return ERR_BUF; - } - - iphdr = p->payload; - - /* Should the IP header be generated or is it already included in p? */ - if (dest != IP_HDRINCL) { - /** @todo should be shared with ip.c - ip_output_if */ - IPH_TTL_SET(iphdr, ttl); - IPH_PROTO_SET(iphdr, proto); - - ip_addr_set(&(iphdr->dest), dest); - - IPH_VHLTOS_SET(iphdr, 4, ((IP_HLEN + ROUTER_ALERTLEN) / 4), 0/*tos*/); - IPH_LEN_SET(iphdr, htons(p->tot_len)); - IPH_OFFSET_SET(iphdr, 0); - IPH_ID_SET(iphdr, htons(ip_id)); - ++ip_id; - - if (ip_addr_isany(src)) { - ip_addr_set(&(iphdr->src), &(netif->ip_addr)); - } else { - ip_addr_set(&(iphdr->src), src); - } - - IPH_CHKSUM_SET(iphdr, 0); -#if CHECKSUM_GEN_IP - IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, (IP_HLEN + ROUTER_ALERTLEN))); -#endif - } else { - dest = &(iphdr->dest); - } - -#if IP_DEBUG - ip_debug_print(p); -#endif - - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_ip_output_if: sending to if %p\n", netif)); - - return netif->output(netif, p, dest); + return ip_output_if_opt(p, src, dest, ttl, 0, proto, netif, ra, ROUTER_ALERTLEN); } /** @@ -797,10 +745,10 @@ igmp_send(struct igmp_group *group, u8_t type) igmp->igmp_checksum = 0; igmp->igmp_checksum = inet_chksum( igmp, IGMP_MINLEN); - igmp_ip_output_if( p, &src, dest, IGMP_TTL, IP_PROTO_IGMP, group->interface); + igmp_ip_output_if(p, &src, dest, IGMP_TTL, IP_PROTO_IGMP, group->interface); } - pbuf_free (p); + pbuf_free(p); } else { LWIP_DEBUGF(IGMP_DEBUG, ("igmp_send: not enough memory for igmp_send\n")); } diff --git a/src/core/ipv4/ip.c b/src/core/ipv4/ip.c index 6ca24f5a..f2545040 100644 --- a/src/core/ipv4/ip.c +++ b/src/core/ipv4/ip.c @@ -518,6 +518,21 @@ ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, u8_t ttl, u8_t tos, u8_t proto, struct netif *netif) { +#if IP_OPTIONS_SEND + return ip_output_if_opt(p, src, dest, ttl, tos, proto, netif, NULL, 0); +} + +/** + * Same as ip_output_if() but with the possibility to include IP options: + * + * @ param ip_options pointer to the IP options, copied into the IP header + * @ param optlen length of ip_options + */ +err_t ip_output_if_opt(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, + u8_t ttl, u8_t tos, u8_t proto, struct netif *netif, void *ip_options, + u16_t optlen) +{ +#endif /* IP_OPTIONS_SEND */ struct ip_hdr *iphdr; static u16_t ip_id = 0; @@ -525,6 +540,27 @@ ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, /* Should the IP header be generated or is it already included in p? */ if (dest != IP_HDRINCL) { + u16_t ip_hlen = IP_HLEN; +#if IP_OPTIONS_SEND + u16_t optlen_aligned = 0; + if (optlen != 0) { + /* round up to a multiple of 4 */ + optlen_aligned = ((optlen + 3) & ~3); + ip_hlen += optlen_aligned; + /* First write in the IP options */ + if (pbuf_header(p, optlen_aligned)) { + LWIP_DEBUGF(IP_DEBUG | 2, ("ip_output_if_opt: not enough room for IP options in pbuf\n")); + IP_STATS_INC(ip.err); + snmp_inc_ipoutdiscards(); + return ERR_BUF; + } + MEMCPY(p->payload, ip_options, optlen); + if (optlen < optlen_aligned) { + /* zero the remaining bytes */ + memset(((char*)p->payload) + optlen, 0, optlen_aligned - optlen); + } + } +#endif /* IP_OPTIONS_SEND */ /* generate IP header */ if (pbuf_header(p, IP_HLEN)) { LWIP_DEBUGF(IP_DEBUG | 2, ("ip_output: not enough room for IP header in pbuf\n")); @@ -543,7 +579,7 @@ ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, ip_addr_set(&(iphdr->dest), dest); - IPH_VHLTOS_SET(iphdr, 4, IP_HLEN / 4, tos); + IPH_VHLTOS_SET(iphdr, 4, ip_hlen / 4, tos); IPH_LEN_SET(iphdr, htons(p->tot_len)); IPH_OFFSET_SET(iphdr, 0); IPH_ID_SET(iphdr, htons(ip_id)); @@ -557,7 +593,7 @@ ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, IPH_CHKSUM_SET(iphdr, 0); #if CHECKSUM_GEN_IP - IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN)); + IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, ip_hlen)); #endif } else { /* IP header already included in p */ diff --git a/src/include/ipv4/lwip/ip.h b/src/include/ipv4/lwip/ip.h index 88364cf5..9b6f5bef 100644 --- a/src/include/ipv4/lwip/ip.h +++ b/src/include/ipv4/lwip/ip.h @@ -43,6 +43,9 @@ extern "C" { #endif +/** Currently, the function ip_output_if_opt() is only used with IGMP */ +#define IP_OPTIONS_SEND LWIP_IGMP + #define ip_init() /* Compatibility define, not init needed. */ struct netif *ip_route(struct ip_addr *dest); err_t ip_input(struct pbuf *p, struct netif *inp); @@ -55,6 +58,11 @@ err_t ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, err_t ip_output_hinted(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, u8_t ttl, u8_t tos, u8_t proto, u8_t *addr_hint); #endif /* LWIP_NETIF_HWADDRHINT */ +#if IP_OPTIONS_SEND +err_t ip_output_if_opt(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, + u8_t ttl, u8_t tos, u8_t proto, struct netif *netif, void *ip_options, + u16_t optlen); +#endif /* IP_OPTIONS_SEND */ struct netif *ip_current_netif(); const struct ip_hdr *ip_current_header();