From a56795c1490d4c8d29dfdf69e48c094bff57f966 Mon Sep 17 00:00:00 2001 From: goldsimon Date: Sat, 15 May 2010 14:52:39 +0000 Subject: [PATCH] Added new option SO_REUSE_RXTOALL to pass received UDP broadcast/multicast packets to more than one pcb --- CHANGELOG | 4 +++- src/core/udp.c | 42 ++++++++++++++++++++++++++++++++++++++++++ src/include/lwip/opt.h | 11 ++++++++++- 3 files changed, 55 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index fe3458e4..d6e2a2c1 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -14,7 +14,9 @@ HISTORY ++ New features: 2010-05-13: Simon Goldschmidt - * tcp.c, udp.c: task #6995: Implement SO_REUSEADDR (correctly) + * tcp.c, udp.c: task #6995: Implement SO_REUSEADDR (correctly), added + new option SO_REUSE_RXTOALL to pass received UDP broadcast/multicast + packets to more than one pcb. 2010-05-02: Simon Goldschmidt * netbuf.h/.c, sockets.c, api_msg.c: use checksum-on-copy for sending diff --git a/src/core/udp.c b/src/core/udp.c index 954e1c19..7b5d0492 100644 --- a/src/core/udp.c +++ b/src/core/udp.c @@ -276,6 +276,48 @@ udp_input(struct pbuf *p, struct netif *inp) } if (pcb != NULL) { snmp_inc_udpindatagrams(); +#if SO_REUSE_RXTOALL + if ((broadcast || ip_addr_ismulticast(&iphdr->dest)) && + ((pcb->so_options & SOF_REUSEADDR) != 0)) { + /* pass broadcast- or multicast packets to all multicast pcbs + if SOF_REUSEADDR is set on the first match */ + struct udp_pcb *mpcb; + /* for that, move payload to IP header again */ + pbuf_header(p, (s16_t)((IPH_HL(iphdr) * 4) + UDP_HLEN)); + for (mpcb = udp_pcbs; mpcb != NULL; mpcb = mpcb->next) { + if (mpcb != pcb) { + /* compare PCB local addr+port to UDP destination addr+port */ + if ((mpcb->local_port == dest) && + ((!broadcast && ip_addr_isany(&mpcb->local_ip)) || + ip_addr_cmp(&(mpcb->local_ip), &(iphdr->dest)) || +#if LWIP_IGMP + ip_addr_ismulticast(&(iphdr->dest)) || +#endif /* LWIP_IGMP */ +#if IP_SOF_BROADCAST_RECV + (broadcast && (mpcb->so_options & SOF_BROADCAST)))) { +#else /* IP_SOF_BROADCAST_RECV */ + (broadcast))) { +#endif /* IP_SOF_BROADCAST_RECV */ + /* pass a copy of the packet to all local matches */ + if (mpcb->recv != NULL) { + struct pbuf *q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM); + if (q != NULL) { + err_t err = pbuf_copy(q, p); + if (err == ERR_OK) { + /* move payload to UDP data */ + struct ip_hdr *q_iphdr = (struct ip_hdr *)q->payload; + pbuf_header(q, -(s16_t)((IPH_HL(iphdr) * 4) + UDP_HLEN)); + mpcb->recv(mpcb->recv_arg, mpcb, q, &q_iphdr->src, src); + } + } + } + } + } + } + /* and move payload to UDP data again */ + pbuf_header(p, -(s16_t)((IPH_HL(iphdr) * 4) + UDP_HLEN)); + } +#endif /* SO_REUSE_RXTOALL */ /* callback */ if (pcb->recv != NULL) { /* now the recv function is responsible for freeing p */ diff --git a/src/include/lwip/opt.h b/src/include/lwip/opt.h index 81d98970..1aa2c400 100644 --- a/src/include/lwip/opt.h +++ b/src/include/lwip/opt.h @@ -1388,12 +1388,21 @@ #endif /** - * SO_REUSE==1: Enable SO_REUSEADDR and SO_REUSEPORT options. DO NOT USE! + * SO_REUSE==1: Enable SO_REUSEADDR option. */ #ifndef SO_REUSE #define SO_REUSE 0 #endif +/** + * SO_REUSE_RXTOALL==1: Pass a copy of incoming broadcast/multicast packets + * to all local matches if SO_REUSEADDR is turned on. + * WARNING: Adds a memcpy for every packet if passing to more than one pcb! + */ +#ifndef SO_REUSE_RXTOALL +#define SO_REUSE_RXTOALL 0 +#endif + /* ---------------------------------------- ---------- Statistics options ----------