From d4ecb23015e851577b0fd780a9184d4b0a92e05b Mon Sep 17 00:00:00 2001 From: fbernon Date: Wed, 29 Apr 2009 12:42:43 +0000 Subject: [PATCH] raw.c, udp.c, init.c, opt.h, ip.h, sockets.h: bug #26309: Implement the SO(F)_BROADCAST filter for all API layers. Avoid the unindented reception of broadcast packets even when this option wasn't set. Port maintainers which want to enable this filter have to set IP_SOF_BROADCAST=1 in opt.h. If you want this option also filter broadcast on recv operations, you also have to set IP_SOF_BROADCAST_RECV=1 in opt.h. --- CHANGELOG | 8 +++++++ src/core/init.c | 3 +++ src/core/raw.c | 49 +++++++++++++++++++++++++------------- src/core/udp.c | 26 ++++++++++++++++---- src/include/ipv4/lwip/ip.h | 2 +- src/include/lwip/opt.h | 17 +++++++++++++ src/include/lwip/sockets.h | 2 +- 7 files changed, 84 insertions(+), 23 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 76063219..566bf1c1 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -95,6 +95,14 @@ HISTORY ++ Bugfixes: + 2009-04-29 Frédéric Bernon + * raw.c, udp.c, init.c, opt.h, ip.h, sockets.h: bug #26309: Implement the + SO(F)_BROADCAST filter for all API layers. Avoid the unindented reception + of broadcast packets even when this option wasn't set. Port maintainers + which want to enable this filter have to set IP_SOF_BROADCAST=1 in opt.h. + If you want this option also filter broadcast on recv operations, you also + have to set IP_SOF_BROADCAST_RECV=1 in opt.h. + 2009-04-28 Simon Goldschmidt, Jakob Stoklund Olesen * dhcp.c: patch #6721: Some small fixes to DHCP and DHCP/AUTOIP cooperation diff --git a/src/core/init.c b/src/core/init.c index 37fe7f12..80e8c6e6 100644 --- a/src/core/init.c +++ b/src/core/init.c @@ -61,6 +61,9 @@ #ifndef BYTE_ORDER #error "BYTE_ORDER is not defined, you have to define it in your cc.h" #endif +#if (!IP_SOF_BROADCAST && IP_SOF_BROADCAST_RECV) + #error "If you want to use broadcast filter per pcb on recv operations, you have to define IP_SOF_BROADCAST=1 in your lwipopts.h" +#endif #if (!LWIP_ARP && ARP_QUEUEING) #error "If you want to use ARP Queueing, you have to define LWIP_ARP=1 in your lwipopts.h" #endif diff --git a/src/core/raw.c b/src/core/raw.c index 5131c702..589950e7 100644 --- a/src/core/raw.c +++ b/src/core/raw.c @@ -93,24 +93,29 @@ raw_input(struct pbuf *p, struct netif *inp) /* this allows multiple pcbs to match against the packet by design */ while ((eaten == 0) && (pcb != NULL)) { if (pcb->protocol == proto) { - /* receive callback function available? */ - if (pcb->recv != NULL) { - /* the receive callback function did not eat the packet? */ - if (pcb->recv(pcb->recv_arg, pcb, p, &(iphdr->src)) != 0) - { - /* receive function ate the packet */ - p = NULL; - eaten = 1; - if (prev != NULL) { - /* move the pcb to the front of raw_pcbs so that is - found faster next time */ - prev->next = pcb->next; - pcb->next = raw_pcbs; - raw_pcbs = pcb; +#if IP_SOF_BROADCAST_RECV + /* broadcast filter? */ + if ((pcb->so_options & SOF_BROADCAST) || !ip_addr_isbroadcast(&(iphdr->dest), inp)) +#endif /* IP_SOF_BROADCAST_RECV */ + { + /* receive callback function available? */ + if (pcb->recv != NULL) { + /* the receive callback function did not eat the packet? */ + if (pcb->recv(pcb->recv_arg, pcb, p, &(iphdr->src)) != 0) { + /* receive function ate the packet */ + p = NULL; + eaten = 1; + if (prev != NULL) { + /* move the pcb to the front of raw_pcbs so that is + found faster next time */ + prev->next = pcb->next; + pcb->next = raw_pcbs; + raw_pcbs = pcb; + } } } + /* no receive callback function was set for this raw PCB */ } - /* no receive callback function was set for this raw PCB */ /* drop the packet */ } prev = pcb; @@ -228,7 +233,7 @@ raw_sendto(struct raw_pcb *pcb, struct pbuf *p, struct ip_addr *ipaddr) return ERR_MEM; } } - + if ((netif = ip_route(ipaddr)) == NULL) { LWIP_DEBUGF(RAW_DEBUG | 1, ("raw_sendto: No route to 0x%"X32_F"\n", ipaddr->addr)); /* free any temporary header pbuf allocated by pbuf_header() */ @@ -238,6 +243,18 @@ raw_sendto(struct raw_pcb *pcb, struct pbuf *p, struct ip_addr *ipaddr) return ERR_RTE; } +#if IP_SOF_BROADCAST + /* broadcast filter? */ + if ( ((pcb->so_options & SOF_BROADCAST) == 0) && ip_addr_isbroadcast(ipaddr, netif) ) { + LWIP_DEBUGF(RAW_DEBUG | 1, ("raw_sendto: SOF_BROADCAST not enabled on pcb %p\n", (void *)pcb)); + /* free any temporary header pbuf allocated by pbuf_header() */ + if (q != p) { + pbuf_free(q); + } + return ERR_VAL; + } +#endif /* IP_SOF_BROADCAST */ + if (ip_addr_isany(&pcb->local_ip)) { /* use outgoing network interface IP address as source address */ src_ip = &(netif->ip_addr); diff --git a/src/core/udp.c b/src/core/udp.c index 25364625..d8d644d4 100644 --- a/src/core/udp.c +++ b/src/core/udp.c @@ -90,6 +90,7 @@ udp_input(struct pbuf *p, struct netif *inp) struct ip_hdr *iphdr; u16_t src, dest; u8_t local_match; + u8_t broadcast; PERF_START; @@ -112,6 +113,9 @@ udp_input(struct pbuf *p, struct netif *inp) udphdr = (struct udp_hdr *)p->payload; + /* is broadcast packet ? */ + broadcast = ip_addr_isbroadcast(&(iphdr->dest), inp); + LWIP_DEBUGF(UDP_DEBUG, ("udp_input: received datagram of length %"U16_F"\n", p->tot_len)); /* convert src and dest ports to host byte order */ @@ -169,16 +173,20 @@ udp_input(struct pbuf *p, struct netif *inp) /* compare PCB local addr+port to UDP destination addr+port */ if ((pcb->local_port == dest) && - (ip_addr_isany(&pcb->local_ip) || - ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest)) || + ((!broadcast && ip_addr_isany(&pcb->local_ip)) || + ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest)) || #if LWIP_IGMP ip_addr_ismulticast(&(iphdr->dest)) || #endif /* LWIP_IGMP */ - ip_addr_isbroadcast(&(iphdr->dest), inp))) { +#if IP_SOF_BROADCAST_RECV + (broadcast && (pcb->so_options & SOF_BROADCAST)))) { +#else /* IP_SOF_BROADCAST_RECV */ + (broadcast))) { +#endif /* IP_SOF_BROADCAST_RECV */ local_match = 1; if ((uncon_pcb == NULL) && ((pcb->flags & UDP_FLAGS_CONNECTED) == 0)) { - /* the first unconnected matching PCB */ + /* the first unconnected matching PCB */ uncon_pcb = pcb; } } @@ -286,7 +294,7 @@ udp_input(struct pbuf *p, struct netif *inp) #if LWIP_ICMP /* No match was found, send ICMP destination port unreachable unless destination address was broadcast/multicast. */ - if (!ip_addr_isbroadcast(&iphdr->dest, inp) && + if (!broadcast && !ip_addr_ismulticast(&iphdr->dest)) { /* move payload pointer back to ip header */ pbuf_header(p, (IPH_HL(iphdr) * 4) + UDP_HLEN); @@ -400,6 +408,14 @@ udp_sendto_if(struct udp_pcb *pcb, struct pbuf *p, err_t err; struct pbuf *q; /* q will be sent down the stack */ +#if IP_SOF_BROADCAST + /* broadcast filter? */ + if ( ((pcb->so_options & SOF_BROADCAST) == 0) && ip_addr_isbroadcast(dst_ip, netif) ) { + LWIP_DEBUGF(UDP_DEBUG | 1, ("udp_sendto_if: SOF_BROADCAST not enabled on pcb %p\n", (void *)pcb)); + return ERR_VAL; + } +#endif /* IP_SOF_BROADCAST */ + /* if the PCB is not yet bound to a port, bind it here */ if (pcb->local_port == 0) { LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | 2, ("udp_send: not yet bound to a port, binding now\n")); diff --git a/src/include/ipv4/lwip/ip.h b/src/include/ipv4/lwip/ip.h index 36fd5c9d..f342af95 100644 --- a/src/include/ipv4/lwip/ip.h +++ b/src/include/ipv4/lwip/ip.h @@ -107,7 +107,7 @@ struct ip_pcb { #define SOF_REUSEADDR (u16_t)0x0004U /* allow local address reuse */ #define SOF_KEEPALIVE (u16_t)0x0008U /* keep connections alive */ #define SOF_DONTROUTE (u16_t)0x0010U /* just use interface addresses */ -#define SOF_BROADCAST (u16_t)0x0020U /* permit sending of broadcast msgs */ +#define SOF_BROADCAST (u16_t)0x0020U /* permit to send and to receive broadcast messages (see IP_SOF_BROADCAST option) */ #define SOF_USELOOPBACK (u16_t)0x0040U /* bypass hardware when possible */ #define SOF_LINGER (u16_t)0x0080U /* linger on close if data present */ #define SOF_OOBINLINE (u16_t)0x0100U /* leave received OOB data in line */ diff --git a/src/include/lwip/opt.h b/src/include/lwip/opt.h index dfa09157..623c28f4 100644 --- a/src/include/lwip/opt.h +++ b/src/include/lwip/opt.h @@ -450,6 +450,23 @@ #define IP_DEFAULT_TTL 255 #endif +/** + * IP_SOF_BROADCAST=1: Use the SOF_BROADCAST field to enable broadcast + * filter per pcb on udp and raw send operations. To enable broadcast filter + * on recv operations, you also have to set IP_SOF_BROADCAST_RECV=1. + */ +#ifndef IP_SOF_BROADCAST +#define IP_SOF_BROADCAST 0 +#endif + +/** + * IP_SOF_BROADCAST_RECV (requires IP_SOF_BROADCAST=1) enable the broadcast + * filter on recv operations. + */ +#ifndef IP_SOF_BROADCAST_RECV +#define IP_SOF_BROADCAST_RECV 0 +#endif + /* ---------------------------------- ---------- ICMP options ---------- diff --git a/src/include/lwip/sockets.h b/src/include/lwip/sockets.h index 994c2421..63d1a9a9 100644 --- a/src/include/lwip/sockets.h +++ b/src/include/lwip/sockets.h @@ -77,7 +77,7 @@ struct sockaddr { #define SO_REUSEADDR 0x0004 /* Unimplemented: allow local address reuse */ #define SO_KEEPALIVE 0x0008 /* keep connections alive */ #define SO_DONTROUTE 0x0010 /* Unimplemented: just use interface addresses */ -#define SO_BROADCAST 0x0020 /* Unimplemented: permit sending of broadcast msgs */ +#define SO_BROADCAST 0x0020 /* permit to send and to receive broadcast messages (see IP_SOF_BROADCAST option) */ #define SO_USELOOPBACK 0x0040 /* Unimplemented: bypass hardware when possible */ #define SO_LINGER 0x0080 /* linger on close if data present */ #define SO_OOBINLINE 0x0100 /* Unimplemented: leave received OOB data in line */