diff --git a/CHANGELOG b/CHANGELOG index b05055e0..4c946eae 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -6,6 +6,12 @@ HISTORY ++ New features: + 2011-07-21: Simon Goldschmidt (patch by hanhui) + * ip4.c, etharp.c, pbuf.h: bug #33634 ip_forward() have a faulty behaviour: + Added pbuf flags to mark incoming packets as link-layer broadcast/multicast. + Also added code to allow ip_forward() to forward non-broadcast packets to + the input netif (set IP_FORWARD_ALLOW_TX_ON_RX_NETIF==1). + 2011-07-21: Simon Goldschmidt * sockets.c, opt.h: (bug #30185): added LWIP_FIONREAD_LINUXMODE that makes ioctl/FIONREAD return the size of the next pending datagram. diff --git a/src/core/ipv4/ip4.c b/src/core/ipv4/ip4.c index 3ec50b66..0f7960e3 100644 --- a/src/core/ipv4/ip4.c +++ b/src/core/ipv4/ip4.c @@ -113,8 +113,15 @@ ip_route(ip_addr_t *dest) { struct netif *netif; +#ifdef LWIP_HOOK_IP4_ROUTE + netif = LWIP_HOOK_IP4_ROUTE(dest); + if (netif != NULL) { + return netif; + } +#endif + /* iterate through netifs */ - for(netif = netif_list; netif != NULL; netif = netif->next) { + for (netif = netif_list; netif != NULL; netif = netif->next) { /* network mask matches? */ if (netif_is_up(netif)) { if (ip_addr_netcmp(dest, &(netif->ip_addr), &(netif->netmask))) { @@ -135,6 +142,41 @@ ip_route(ip_addr_t *dest) } #if IP_FORWARD +/** + * Determine whether an IP address is in a reserved set of addresses + * that may not be forwarded, or whether datagrams to that destination + * may be forwarded. + * @param p the packet to forward + * @param dest the destination IP address + * @return 1: can forward 0: discard + */ +static int +ip_canforward(struct pbuf *p) +{ + u32_t addr = ip4_addr_get_u32(ip_current_dest_addr()); + + if (p->flags & PBUF_FLAG_LLBCAST) { + /* don't route link-layer broadcasts */ + return 0; + } + if ((p->flags & PBUF_FLAG_LLMCAST) && !IP_MULTICAST(addr)) { + /* don't route link-layer multicasts unless the destination address is an IP + multicast address */ + return 0; + } + if (IP_EXPERIMENTAL(addr)) { + return 0; + } + if (IP_CLASSA(addr)) { + u32_t net = addr & IP_CLASSA_NET; + if ((net == 0) || (net == (IP_LOOPBACKNET << IP_CLASSA_NSHIFT))) { + /* don't route loopback packets */ + return 0; + } + } + return 1; +} + /** * Forwards an IP packet. It finds an appropriate route for the * packet, decrements the TTL value of the packet, adjusts the @@ -151,6 +193,10 @@ ip_forward(struct pbuf *p, struct ip_hdr *iphdr, struct netif *inp) PERF_START; + if (!ip_canforward(p)) { + goto return_noroute; + } + /* RFC3927 2.7: do not forward link-local addresses */ if (ip_addr_islinklocal(ip_current_dest_addr())) { LWIP_DEBUGF(IP_DEBUG, ("ip_forward: not forwarding LLA %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", @@ -167,12 +213,14 @@ ip_forward(struct pbuf *p, struct ip_hdr *iphdr, struct netif *inp) ip4_addr3_16(ip_current_dest_addr()), ip4_addr4_16(ip_current_dest_addr()))); goto return_noroute; } +#if !IP_FORWARD_ALLOW_TX_ON_RX_NETIF /* 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")); goto return_noroute; } +#endif /* IP_FORWARD_ALLOW_TX_ON_RX_NETIF */ /* decrement TTL */ IPH_TTL_SET(iphdr, IPH_TTL(iphdr) - 1); @@ -252,6 +300,13 @@ ip_input(struct pbuf *p, struct netif *inp) return ERR_OK; } +#ifdef LWIP_HOOK_IP4_INPUT + if (LWIP_HOOK_IP4_INPUT(p, inp)) { + /* the packet has been eaten */ + return ERR_OK; + } +#endif + /* obtain IP header length in number of 32-bit words */ iphdr_hlen = IPH_HL(iphdr); /* calculate IP header length in bytes */ diff --git a/src/include/lwip/opt.h b/src/include/lwip/opt.h index 911b6251..f4647b64 100644 --- a/src/include/lwip/opt.h +++ b/src/include/lwip/opt.h @@ -593,6 +593,17 @@ #define IP_SOF_BROADCAST_RECV 0 #endif +/** + * IP_FORWARD_ALLOW_TX_ON_RX_NETIF==1: allow ip_forward() to send packets back + * out on the netif where it was received. This should only be used for + * wireless networks. + * ATTENTION: When this is 1, make sure your netif driver correctly marks incoming + * link-layer-broadcast/multicast packets as such using the corresponding pbuf flags! + */ +#ifndef IP_FORWARD_ALLOW_TX_ON_RX_NETIF +#define IP_FORWARD_ALLOW_TX_ON_RX_NETIF 0 +#endif + /* ---------------------------------- ---------- ICMP options ---------- @@ -2056,6 +2067,34 @@ #define LWIP_IPV6_DHCP6 0 #endif +/* + --------------------------------------- + ---------- Hook options --------------- + --------------------------------------- +*/ + +/* Hooks are undefined by default, define them to a function if you need them. */ + +/** + * LWIP_HOOK_IP4_INPUT(pbuf, input_netif): + * - called from ip_input() (IPv4) + * - pbuf: received struct pbuf passed to ip_input() + * - input_netif: struct netif on which the packet has been received + * Return values: + * - 0: Hook has not consumed the packet, packet is processed as normal + * - != 0: Hook has consumed the packet. + * If the hook consumed the packet, 'pbuf' is in the responsibility of the hook + * (i.e. free it when done). + */ + +/** + * LWIP_HOOK_IP4_ROUTE(dest): + * - called from ip_route() (IPv4) + * - dest: destination IPv4 address + * Returns the destination netif or NULL if no destination netif is found. In + * that case, ip_route() continues as normal. + */ + /* --------------------------------------- ---------- Debugging options ---------- diff --git a/src/include/lwip/pbuf.h b/src/include/lwip/pbuf.h index 53fdc69b..50407e90 100644 --- a/src/include/lwip/pbuf.h +++ b/src/include/lwip/pbuf.h @@ -76,6 +76,10 @@ typedef enum { #define PBUF_FLAG_IS_CUSTOM 0x02U /** indicates this pbuf is UDP multicast to be looped back */ #define PBUF_FLAG_MCASTLOOP 0x04U +/** indicates this pbuf was received as link-level broadcast */ +#define PBUF_FLAG_LLBCAST 0x08U +/** indicates this pbuf was received as link-level multicast */ +#define PBUF_FLAG_LLMCAST 0x10U struct pbuf { /** next pbuf in singly linked pbuf chain */ diff --git a/src/netif/etharp.c b/src/netif/etharp.c index 004d2274..f2b87e27 100644 --- a/src/netif/etharp.c +++ b/src/netif/etharp.c @@ -66,6 +66,11 @@ const struct eth_addr ethbroadcast = {{0xff,0xff,0xff,0xff,0xff,0xff}}; const struct eth_addr ethzero = {{0,0,0,0,0,0}}; +/** The 24-bit IANA multicast OUI is 01-00-5e: */ +#define LL_MULTICAST_ADDR_0 0x01 +#define LL_MULTICAST_ADDR_1 0x00 +#define LL_MULTICAST_ADDR_2 0x5e + #if LWIP_ARP /* don't build if not configured for use in lwipopts.h */ /** the time an ARP entry stays valid after its last update, @@ -932,9 +937,9 @@ etharp_output(struct netif *netif, struct pbuf *q, ip_addr_t *ipaddr) /* multicast destination IP address? */ } else if (ip_addr_ismulticast(ipaddr)) { /* Hash IP multicast address to MAC address.*/ - mcastaddr.addr[0] = 0x01; - mcastaddr.addr[1] = 0x00; - mcastaddr.addr[2] = 0x5e; + mcastaddr.addr[0] = LL_MULTICAST_ADDR_0; + mcastaddr.addr[1] = LL_MULTICAST_ADDR_1; + mcastaddr.addr[2] = LL_MULTICAST_ADDR_2; mcastaddr.addr[3] = ip4_addr2(ipaddr) & 0x7f; mcastaddr.addr[4] = ip4_addr3(ipaddr); mcastaddr.addr[5] = ip4_addr4(ipaddr); @@ -1308,6 +1313,20 @@ ethernet_input(struct pbuf *p, struct netif *netif) netif = LWIP_ARP_FILTER_NETIF_FN(p, netif, htons(type)); #endif /* LWIP_ARP_FILTER_NETIF*/ + if (ethhdr->dest.addr[0] & 1) { + /* this might be a multicast or broadcast packet */ + if (ethhdr->dest.addr[0] == LL_MULTICAST_ADDR_0) { + if ((ethhdr->dest.addr[1] == LL_MULTICAST_ADDR_1) && + (ethhdr->dest.addr[2] == LL_MULTICAST_ADDR_2)) { + /* mark the pbuf as link-layer multicast */ + p->flags |= PBUF_FLAG_LLMCAST; + } + } else if (eth_addr_cmp(ðhdr->dest, ðbroadcast)) { + /* mark the pbuf as link-layer broadcast */ + p->flags |= PBUF_FLAG_LLBCAST; + } + } + switch (type) { #if LWIP_ARP /* IP packet? */