From c822d404bae65db647d7c0ddec4647f8b0cce1e1 Mon Sep 17 00:00:00 2001 From: wanfeng Date: Tue, 16 Apr 2024 15:23:46 +0800 Subject: [PATCH] add MCAST_JOIN_SOURCE_GROUP to setsockopt for mldv2 --- src/api/sockets.c | 94 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) diff --git a/src/api/sockets.c b/src/api/sockets.c index 6b2f5ee..50fa335 100644 --- a/src/api/sockets.c +++ b/src/api/sockets.c @@ -3976,6 +3976,29 @@ lwip_setsockopt_impl(int s, int level, int optname, const void *optval, socklen_ } } break; + case MCAST_JOIN_SOURCE_GROUP: + case MCAST_LEAVE_SOURCE_GROUP: + LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, struct group_source_req); + if ((((const struct group_source_req *)optval)->gsr_group.ss_family != AF_INET6) || + (((const struct group_source_req *)optval)->gsr_source.ss_family != AF_INET6)) { + done_socket(sock); + return EINVAL; + } +#if LWIP_UDP + if (NETCONNTYPE_GROUPV6(netconn_type(sock->conn)) == NETCONN_UDP_IPV6) { + err = mcast_sock_join_leave_source_group(s, &sock->conn->pcb.udp->ipmc, optname, (const struct group_source_req *)optval); + } else +#endif /* LWIP_UDP */ +#if LWIP_RAW + if (NETCONNTYPE_GROUPV6(netconn_type(sock->conn)) == NETCONN_RAW_IPV6) { + err = mcast_sock_join_leave_source_group(s, &sock->conn->pcb.raw->ipmc, optname, (const struct group_source_req *)optval); + } else +#endif /* LWIP_RAW */ + { + done_socket(sock); + return ENOPROTOOPT; + } + break; #endif /* LWIP_IPV6_MLD */ default: LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IPV6, UNIMPL: optname=0x%x, ..)\n", @@ -4869,6 +4892,77 @@ out: return err_to_errno(err); } +/** + * setsockopt() MCAST_JOIN_SOURCE_GROUP / MCAST_LEAVE_SOURCE_GROUP command + */ +int +mcast_sock_join_leave_source_group(int s, struct ip_mc *ipmc, int optname, const struct group_source_req *gsr) +{ + struct netif *netif; + ip_addr_t multi_addr; + ip_addr_t src_addr; + err_t err; + u8_t if_idx; + + if (gsr->gsr_group.ss_family == AF_INET) { + inet_addr_to_ip4addr(ip_2_ip4(&multi_addr), &(((struct sockaddr_in *)&(gsr->gsr_group))->sin_addr)); + inet_addr_to_ip4addr(ip_2_ip4(&src_addr), &(((struct sockaddr_in *)&(gsr->gsr_source))->sin_addr)); + IP_SET_TYPE_VAL(multi_addr, IPADDR_TYPE_V4); + IP_SET_TYPE_VAL(src_addr, IPADDR_TYPE_V4); + if (!ip4_addr_ismulticast(ip_2_ip4(&multi_addr)) || ip4_addr_isany(ip_2_ip4(&src_addr))) { + return EADDRNOTAVAIL; + } + + } else if (gsr->gsr_group.ss_family == AF_INET6) { + inet6_addr_to_ip6addr(ip_2_ip6(&multi_addr), &(((struct sockaddr_in6 *)&(gsr->gsr_group))->sin6_addr)); + inet6_addr_to_ip6addr(ip_2_ip6(&src_addr), &(((struct sockaddr_in6 *)&(gsr->gsr_source))->sin6_addr)); + IP_SET_TYPE_VAL(multi_addr, IPADDR_TYPE_V6); + IP_SET_TYPE_VAL(src_addr, IPADDR_TYPE_V6); + if (!ip6_addr_ismulticast(ip_2_ip6(&multi_addr)) || ip6_addr_isany(ip_2_ip6(&src_addr))) { + return EADDRNOTAVAIL; + } + + } else { + return EADDRNOTAVAIL; + } + + if (gsr->gsr_interface) { + netif = netif_get_by_index((u8_t)gsr->gsr_interface); + } else { + netif = netif_default; /* To default network interface */ + } + if (netif == NULL) { + return ENXIO; + } + + if_idx = netif_get_index(netif); + if (optname == MCAST_JOIN_SOURCE_GROUP) { +#if LWIP_IPV4 && LWIP_IGMP + if (IP_IS_V4(&multi_addr)) { + if (!lwip_socket_register_membership(s, if_idx, ip_2_ip4(&multi_addr))) { + /* cannot track membership (out of memory) */ + err = ENOMEM; + goto out; + } + } else +#endif + { +#if LWIP_IPV6 && LWIP_IPV6_MLD + if (!lwip_socket_register_mld6_membership(s, if_idx, ip_2_ip6(&multi_addr))) { + /* cannot track membership (out of memory) */ + err = ENOMEM; + goto out; + } +#endif + } + err = mcast_join_netif(ipmc, netif, &multi_addr, &src_addr); + } else { + err = mcast_leave_netif(ipmc, netif, &multi_addr, &src_addr); + } +out: + return err_to_errno(err); +} + /** * setsockopt() IPV6_JOIN_GROUP / IPV6_LEAVE_GROUP command */ -- 2.25.1