diff --git a/CHANGELOG b/CHANGELOG index 6416ee52..b9f0f98d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -13,6 +13,10 @@ HISTORY ++ New features: + 2010-07-12: Simon Goldschmidt (patch by Stephane Lesage) + * ip.c, udp.c/.h, pbuf.h, sockets.c: task #10495: Added support for + IP_MULTICAST_LOOP at socket- and raw-API level. + 2010-06-16: Simon Goldschmidt * ip.c: Added an optional define (LWIP_IP_ACCEPT_UDP_PORT) that can allow link-layer-addressed UDP traffic to be received while a netif is down (just diff --git a/src/api/sockets.c b/src/api/sockets.c index e4b78f96..9919b611 100644 --- a/src/api/sockets.c +++ b/src/api/sockets.c @@ -1524,6 +1524,14 @@ lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen) err = EINVAL; } break; + case IP_MULTICAST_LOOP: + if (*optlen < sizeof(u8_t)) { + err = EINVAL; + } + if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) { + err = EAFNOSUPPORT; + } + break; #endif /* LWIP_IGMP */ default: @@ -1738,6 +1746,15 @@ lwip_getsockopt_internal(void *arg) LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_IF) = 0x%"X32_F"\n", s, *(u32_t *)optval)); break; + case IP_MULTICAST_LOOP: + if ((sock->conn->pcb.udp->flags & UDP_FLAGS_MULTICAST_LOOP) != 0) { + *(u8_t*)optval = 1; + } else { + *(u8_t*)optval = 0; + } + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_LOOP) = %d\n", + s, *(int *)optval)); + break; #endif /* LWIP_IGMP */ default: LWIP_ASSERT("unhandled optname", 0); @@ -1906,6 +1923,14 @@ lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t opt err = EAFNOSUPPORT; } break; + case IP_MULTICAST_LOOP: + if (optlen < sizeof(u8_t)) { + err = EINVAL; + } + if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) { + err = EAFNOSUPPORT; + } + break; case IP_ADD_MEMBERSHIP: case IP_DROP_MEMBERSHIP: if (optlen < sizeof(struct ip_mreq)) { @@ -2098,6 +2123,13 @@ lwip_setsockopt_internal(void *arg) case IP_MULTICAST_IF: inet_addr_to_ipaddr(&sock->conn->pcb.udp->multicast_ip, (struct in_addr*)optval); break; + case IP_MULTICAST_LOOP: + if (*(u8_t*)optval) { + udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) | UDP_FLAGS_MULTICAST_LOOP); + } else { + udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) & ~UDP_FLAGS_MULTICAST_LOOP); + } + break; case IP_ADD_MEMBERSHIP: case IP_DROP_MEMBERSHIP: { diff --git a/src/core/ipv4/ip.c b/src/core/ipv4/ip.c index 59bcd24b..862c609d 100644 --- a/src/core/ipv4/ip.c +++ b/src/core/ipv4/ip.c @@ -710,13 +710,18 @@ err_t ip_output_if_opt(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, LWIP_DEBUGF(IP_DEBUG, ("netif_loop_output()")); return netif_loop_output(netif, p, dest); } +#if LWIP_IGMP + if ((p->flags & PBUF_FLAG_MCASTLOOP) != 0) { + netif_loop_output(netif, p, dest); + } +#endif /* LWIP_IGMP */ #endif /* ENABLE_LOOPBACK */ #if IP_FRAG /* don't fragment if interface has mtu set to 0 [loopif] */ if (netif->mtu && (p->tot_len > netif->mtu)) { return ip_frag(p, netif, dest); } -#endif +#endif /* IP_FRAG */ LWIP_DEBUGF(IP_DEBUG, ("netif->output()")); return netif->output(netif, p, dest); diff --git a/src/core/udp.c b/src/core/udp.c index 0b335cda..e4dd44fb 100644 --- a/src/core/udp.c +++ b/src/core/udp.c @@ -540,6 +540,14 @@ udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip, /* in UDP, 0 checksum means 'no checksum' */ udphdr->chksum = 0x0000; + /* Multicast Loop? */ +#if LWIP_IGMP + if (ip_addr_ismulticast(dst_ip) && ((pcb->flags & UDP_FLAGS_MULTICAST_LOOP) != 0)) { + q->flags |= PBUF_FLAG_MCASTLOOP; + } +#endif /* LWIP_IGMP */ + + /* PCB local address is IP_ANY_ADDR? */ if (ip_addr_isany(&pcb->local_ip)) { /* use outgoing network interface IP address as source address */ @@ -927,6 +935,10 @@ udp_new(void) /* initialize PCB to all zeroes */ memset(pcb, 0, sizeof(struct udp_pcb)); pcb->ttl = UDP_TTL; +#if LWIP_IGMP + /* multicast loopback shall be turned on by default */ + pcb->flags = PBUF_FLAG_MCASTLOOP; +#endif /* LWIP_IGMP */ } return pcb; } diff --git a/src/include/lwip/pbuf.h b/src/include/lwip/pbuf.h index 239edd77..3b1d608b 100644 --- a/src/include/lwip/pbuf.h +++ b/src/include/lwip/pbuf.h @@ -67,6 +67,8 @@ typedef enum { /** indicates this is a custom pbuf: pbuf_free and pbuf_header handle such a a pbuf differently */ #define PBUF_FLAG_IS_CUSTOM 0x02U +/** indicates this pbuf is UDP multicast to be looped back */ +#define PBUF_FLAG_MCASTLOOP 0x04U struct pbuf { /** next pbuf in singly linked pbuf chain */ diff --git a/src/include/lwip/udp.h b/src/include/lwip/udp.h index ac1bb769..c98c1b3e 100644 --- a/src/include/lwip/udp.h +++ b/src/include/lwip/udp.h @@ -63,9 +63,10 @@ PACK_STRUCT_END # include "arch/epstruct.h" #endif -#define UDP_FLAGS_NOCHKSUM 0x01U -#define UDP_FLAGS_UDPLITE 0x02U -#define UDP_FLAGS_CONNECTED 0x04U +#define UDP_FLAGS_NOCHKSUM 0x01U +#define UDP_FLAGS_UDPLITE 0x02U +#define UDP_FLAGS_CONNECTED 0x04U +#define UDP_FLAGS_MULTICAST_LOOP 0x08U struct udp_pcb;