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 */