diff --git a/src/api/sockets.c b/src/api/sockets.c index f67162ab..27d8bc76 100644 --- a/src/api/sockets.c +++ b/src/api/sockets.c @@ -2020,7 +2020,7 @@ lwip_getsockopt_impl(int s, int level, int optname, void *optval, socklen_t *opt LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TOS) = %d\n", s, *(int *)optval)); break; -#if LWIP_MULTICAST_TX_OPTIONS +#if LWIP_IPV4 && LWIP_MULTICAST_TX_OPTIONS case IP_MULTICAST_TTL: LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, u8_t); if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP) { @@ -2049,7 +2049,7 @@ lwip_getsockopt_impl(int s, int level, int optname, void *optval, socklen_t *opt LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_LOOP) = %d\n", s, *(int *)optval)); break; -#endif /* LWIP_MULTICAST_TX_OPTIONS */ +#endif /* LWIP_IPV4 && LWIP_MULTICAST_TX_OPTIONS */ default: LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n", s, optname)); @@ -2389,7 +2389,7 @@ lwip_setsockopt_impl(int s, int level, int optname, const void *optval, socklen_ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TOS, ..)-> %d\n", s, sock->conn->pcb.ip->tos)); break; -#if LWIP_MULTICAST_TX_OPTIONS +#if LWIP_IPV4 && LWIP_MULTICAST_TX_OPTIONS case IP_MULTICAST_TTL: LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, u8_t, NETCONN_UDP); udp_set_multicast_ttl(sock->conn->pcb.udp, (u8_t)(*(const u8_t*)optval)); @@ -2410,7 +2410,7 @@ lwip_setsockopt_impl(int s, int level, int optname, const void *optval, socklen_ udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) & ~UDP_FLAGS_MULTICAST_LOOP); } break; -#endif /* LWIP_MULTICAST_TX_OPTIONS */ +#endif /* LWIP_IPV4 && LWIP_MULTICAST_TX_OPTIONS */ #if LWIP_IGMP case IP_ADD_MEMBERSHIP: case IP_DROP_MEMBERSHIP: diff --git a/src/core/init.c b/src/core/init.c index ee415a97..1f89997e 100644 --- a/src/core/init.c +++ b/src/core/init.c @@ -96,7 +96,7 @@ PACK_STRUCT_END #error "If you want to use DHCP, you have to define LWIP_UDP=1 in your lwipopts.h" #endif #if (!LWIP_UDP && LWIP_MULTICAST_TX_OPTIONS) - #error "If you want to use IGMP/LWIP_MULTICAST_TX_OPTIONS, you have to define LWIP_UDP=1 in your lwipopts.h" + #error "If you want to use LWIP_MULTICAST_TX_OPTIONS, you have to define LWIP_UDP=1 in your lwipopts.h" #endif #if (!LWIP_UDP && LWIP_DNS) #error "If you want to use DNS, you have to define LWIP_UDP=1 in your lwipopts.h" @@ -123,9 +123,6 @@ PACK_STRUCT_END #if (LWIP_IGMP && !LWIP_IPV4) #error "IGMP needs LWIP_IPV4 enabled in your lwipopts.h" #endif -#if (LWIP_MULTICAST_TX_OPTIONS && !LWIP_IPV4) - #error "LWIP_MULTICAST_TX_OPTIONS needs LWIP_IPV4 enabled in your lwipopts.h" -#endif #if ((LWIP_NETCONN || LWIP_SOCKET) && (MEMP_NUM_TCPIP_MSG_API<=0)) #error "If you want to use Sequential API, you have to define MEMP_NUM_TCPIP_MSG_API>=1 in your lwipopts.h" #endif diff --git a/src/core/ipv6/ip6.c b/src/core/ipv6/ip6.c index 55567073..59d112d9 100644 --- a/src/core/ipv6/ip6.c +++ b/src/core/ipv6/ip6.c @@ -1028,6 +1028,11 @@ ip6_output_if_src(struct pbuf *p, const ip6_addr_t *src, const ip6_addr_t *dest, } } } +#if LWIP_MULTICAST_TX_OPTIONS + if ((p->flags & PBUF_FLAG_MCASTLOOP) != 0) { + netif_loop_output(netif, p); + } +#endif /* LWIP_MULTICAST_TX_OPTIONS */ #endif /* ENABLE_LOOPBACK */ #if LWIP_IPV6_FRAG /* don't fragment if interface has mtu set to 0 [loopif] */ diff --git a/src/core/udp.c b/src/core/udp.c index 5bdb3cd1..25a04ade 100644 --- a/src/core/udp.c +++ b/src/core/udp.c @@ -514,7 +514,7 @@ udp_sendto_chksum(struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *dst_ip, { #endif /* LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP */ struct netif *netif; - const ip_addr_t *dst_ip_route = dst_ip; + const ip_addr_t *src_ip_route; if ((pcb == NULL) || (dst_ip == NULL) || !IP_ADDR_PCB_VERSION_MATCH(pcb, dst_ip)) { return ERR_VAL; @@ -522,8 +522,31 @@ udp_sendto_chksum(struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *dst_ip, LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_send\n")); -#if LWIP_IPV4 && LWIP_MULTICAST_TX_OPTIONS - if (ip_addr_ismulticast(dst_ip_route)) { + if (IP_IS_ANY_TYPE_VAL(pcb->local_ip)) { + /* Don't call ip_route() with IP_ANY_TYPE */ + src_ip_route = IP46_ADDR_ANY(IP_GET_TYPE(dst_ip)); + } else { + src_ip_route = &pcb->local_ip; + } + +#if LWIP_MULTICAST_TX_OPTIONS + netif = NULL; + if (ip_addr_ismulticast(dst_ip)) { + /* For IPv6, the interface to use for packets with a multicast destination + * is specified using an interface index. The same approach may be used for + * IPv4 as well, in which case it overrides the IPv4 multicast override + * address below. Here we have to look up the netif by going through the + * list, but by doing so we skip a route lookup. If the interface index has + * gone stale, we fall through and do the regular route lookup after all. */ + if (pcb->mcast_ifindex != NETIF_NO_INDEX) { + for (netif = netif_list; netif != NULL; netif = netif->next) { + if (pcb->mcast_ifindex == netif_num_to_index(netif)) { + break; /* found! */ + } + } + } +#if LWIP_IPV4 + else #if LWIP_IPV6 if (IP_IS_V4(dst_ip)) #endif /* LWIP_IPV6 */ @@ -531,21 +554,21 @@ udp_sendto_chksum(struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *dst_ip, /* IPv4 does not use source-based routing by default, so we use an administratively selected interface for multicast by default. However, this can be overridden by setting an interface address - in pcb->multicast_ip that is used for routing. */ - if (!ip_addr_isany_val(pcb->multicast_ip) && - !ip4_addr_cmp(ip_2_ip4(&pcb->multicast_ip), IP4_ADDR_BROADCAST)) { - dst_ip_route = &pcb->multicast_ip; + in pcb->mcast_ip4 that is used for routing. If this routing lookup + fails, we try regular routing as though no override was set. */ + if (!ip4_addr_isany_val(pcb->mcast_ip4) && + !ip4_addr_cmp(&pcb->mcast_ip4, IP4_ADDR_BROADCAST)) { + netif = ip4_route_src(ip_2_ip4(src_ip_route), &pcb->mcast_ip4); } } +#endif /* LWIP_IPV4 */ } -#endif /* LWIP_IPV4 && LWIP_MULTICAST_TX_OPTIONS */ - /* find the outgoing network interface for this packet */ - if(IP_IS_ANY_TYPE_VAL(pcb->local_ip)) { - /* Don't call ip_route() with IP_ANY_TYPE */ - netif = ip_route(IP46_ADDR_ANY(IP_GET_TYPE(dst_ip_route)), dst_ip_route); - } else { - netif = ip_route(&pcb->local_ip, dst_ip_route); + if (netif == NULL) +#endif /* LWIP_MULTICAST_TX_OPTIONS */ + { + /* find the outgoing network interface for this packet */ + netif = ip_route(src_ip_route, dst_ip); } /* no outgoing network interface could be found? */ @@ -604,10 +627,11 @@ udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *dst_i return ERR_VAL; } - /* PCB local address is IP_ANY_ADDR? */ + /* PCB local address is IP_ANY_ADDR or multicast? */ #if LWIP_IPV6 if (IP_IS_V6(dst_ip)) { - if (ip6_addr_isany(ip_2_ip6(&pcb->local_ip))) { + if (ip6_addr_isany(ip_2_ip6(&pcb->local_ip)) || + ip6_addr_ismulticast(ip_2_ip6(&pcb->local_ip))) { src_ip = ip6_select_source_address(netif, ip_2_ip6(dst_ip)); if (src_ip == NULL) { /* No suitable source address was found. */ @@ -737,11 +761,11 @@ udp_sendto_if_src_chksum(struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *d udphdr->chksum = 0x0000; /* Multicast Loop? */ -#if (LWIP_IPV4 && LWIP_MULTICAST_TX_OPTIONS) || (LWIP_IPV6 && LWIP_IPV6_MLD) +#if LWIP_MULTICAST_TX_OPTIONS if (((pcb->flags & UDP_FLAGS_MULTICAST_LOOP) != 0) && ip_addr_ismulticast(dst_ip)) { q->flags |= PBUF_FLAG_MCASTLOOP; } -#endif /* (LWIP_IPV4 && LWIP_MULTICAST_TX_OPTIONS) || (LWIP_IPV6 && LWIP_IPV6_MLD) */ +#endif /* LWIP_MULTICAST_TX_OPTIONS */ LWIP_DEBUGF(UDP_DEBUG, ("udp_send: sending datagram of length %"U16_F"\n", q->tot_len)); @@ -917,7 +941,7 @@ udp_bind(struct udp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port) * This is legacy support: scope-aware callers should always provide properly * zoned source addresses. Do the zone selection before the address-in-use * check below; as such we have to make a temporary copy of the address. */ - if (IP_IS_V6(ipaddr) && ip6_addr_lacks_zone(ip_2_ip6(ipaddr), IP6_UNICAST)) { + if (IP_IS_V6(ipaddr) && ip6_addr_lacks_zone(ip_2_ip6(ipaddr), IP6_UNKNOWN)) { ip_addr_copy(zoned_ipaddr, *ipaddr); ip6_addr_select_zone(ip_2_ip6(&zoned_ipaddr), ip_2_ip6(&zoned_ipaddr)); ipaddr = &zoned_ipaddr; diff --git a/src/include/lwip/netif.h b/src/include/lwip/netif.h index 7241b42a..0b47ec06 100644 --- a/src/include/lwip/netif.h +++ b/src/include/lwip/netif.h @@ -504,6 +504,7 @@ char * netif_index_to_name(u8_t idx, char *name); /* Interface indexes always start at 1 per RFC 3493, section 4, num starts at 0 */ #define netif_num_to_index(netif) ((netif)->num + 1) #define netif_index_to_num(index) ((index) - 1) +#define NETIF_NO_INDEX (0) #ifdef __cplusplus } diff --git a/src/include/lwip/opt.h b/src/include/lwip/opt.h index eb911e92..1c4f2919 100644 --- a/src/include/lwip/opt.h +++ b/src/include/lwip/opt.h @@ -972,7 +972,29 @@ /* ---------------------------------- - ----- Multicast/IGMP options ----- + -------- Multicast options ------- + ---------------------------------- +*/ +/** + * @defgroup lwip_opts_multicast Multicast + * @ingroup lwip_opts_infrastructure + * @{ + */ +/** + * LWIP_MULTICAST_TX_OPTIONS==1: Enable multicast TX support like the socket options + * IP_MULTICAST_TTL/IP_MULTICAST_IF/IP_MULTICAST_LOOP, as well as (currently only) + * core support for the corresponding IPv6 options. + */ +#if !defined LWIP_MULTICAST_TX_OPTIONS || defined __DOXYGEN__ +#define LWIP_MULTICAST_TX_OPTIONS ((LWIP_IGMP || LWIP_IPV6_MLD) && LWIP_UDP) +#endif +/** + * @} + */ + +/* + ---------------------------------- + ---------- IGMP options ---------- ---------------------------------- */ /** @@ -990,14 +1012,6 @@ #undef LWIP_IGMP #define LWIP_IGMP 0 #endif - -/** - * LWIP_MULTICAST_TX_OPTIONS==1: Enable multicast TX support like the socket options - * IP_MULTICAST_TTL/IP_MULTICAST_IF/IP_MULTICAST_LOOP - */ -#if !defined LWIP_MULTICAST_TX_OPTIONS || defined __DOXYGEN__ -#define LWIP_MULTICAST_TX_OPTIONS (LWIP_IGMP && LWIP_UDP) -#endif /** * @} */ diff --git a/src/include/lwip/udp.h b/src/include/lwip/udp.h index b9299073..30cfb332 100644 --- a/src/include/lwip/udp.h +++ b/src/include/lwip/udp.h @@ -91,8 +91,12 @@ struct udp_pcb { u16_t local_port, remote_port; #if LWIP_MULTICAST_TX_OPTIONS - /** outgoing network interface for multicast packets */ - ip_addr_t multicast_ip; +#if LWIP_IPV4 + /** outgoing network interface for multicast packets, by IPv4 address (if not 'any') */ + ip4_addr_t mcast_ip4; +#endif /* LWIP_IPV4 */ + /** outgoing network interface for multicast packets, by interface index (if nonzero) */ + u8_t mcast_ifindex; /** TTL for outgoing multicast packets */ u8_t mcast_ttl; #endif /* LWIP_MULTICAST_TX_OPTIONS */ @@ -159,9 +163,13 @@ void udp_init (void); #define udp_new_ip6() udp_new_ip_type(IPADDR_TYPE_V6) #if LWIP_MULTICAST_TX_OPTIONS -#define udp_set_multicast_netif_addr(pcb, ip4addr) ip_addr_copy_from_ip4((pcb)->multicast_ip, *(ip4addr)) -#define udp_get_multicast_netif_addr(pcb) ip_2_ip4(&(pcb)->multicast_ip) -#define udp_set_multicast_ttl(pcb, value) do { (pcb)->mcast_ttl = value; } while(0) +#if LWIP_IPV4 +#define udp_set_multicast_netif_addr(pcb, ip4addr) ip4_addr_copy((pcb)->mcast_ip4, *(ip4addr)) +#define udp_get_multicast_netif_addr(pcb) (&(pcb)->mcast_ip4) +#endif /* LWIP_IPV4 */ +#define udp_set_multicast_netif_index(pcb, idx) ((pcb)->mcast_ifindex = (idx)) +#define udp_get_multicast_netif_index(pcb) ((pcb)->mcast_ifindex) +#define udp_set_multicast_ttl(pcb, value) ((pcb)->mcast_ttl = (value)) #define udp_get_multicast_ttl(pcb) ((pcb)->mcast_ttl) #endif /* LWIP_MULTICAST_TX_OPTIONS */