diff -Nur lwip-2.2.0init/src/api/api_msg.c lwip-2.2.0/src/api/api_msg.c --- lwip-2.2.0init/src/api/api_msg.c 2024-04-02 19:14:40.959584000 +0800 +++ lwip-2.2.0/src/api/api_msg.c 2024-04-02 19:15:03.866584000 +0800 @@ -192,9 +192,19 @@ buf->p = q; buf->ptr = q; - ip_addr_copy(buf->addr, *ip_current_src_addr()); + ip_addr_copy(buf->addr, *addr); buf->port = pcb->protocol; +#if LWIP_NETBUF_RECVINFO + if (conn->flags & NETCONN_FLAG_PKTINFO) { + buf->flags = NETBUF_FLAG_DESTADDR; + /* If we use mroute this packet maybe a mroute fake packet so we must get ipv4/ipv6 header */ + if (IP_IS_V4(addr)) { + struct ip_hdr *iphdr = (struct ip_hdr *)p->payload; + ip_addr_copy_from_ip4(buf->toaddr, iphdr->dest); + } else {} +#endif /* LWIP_NETBUF_RECVINFO */ + len = q->tot_len; if (sys_mbox_trypost(&conn->recvmbox, buf) != ERR_OK) { netbuf_delete(buf); @@ -2071,6 +2081,7 @@ msg->err = ERR_CONN; if (msg->conn->pcb.tcp != NULL) { +#if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) { #if LWIP_UDP #if LWIP_IPV6 && LWIP_IPV6_MLD @@ -2082,25 +2093,33 @@ msg->err = mld6_leavegroup(ip_2_ip6(API_EXPR_REF(msg->msg.jl.netif_addr)), ip_2_ip6(API_EXPR_REF(msg->msg.jl.multiaddr))); } - } else + } else { #endif /* LWIP_IPV6 && LWIP_IPV6_MLD */ - { -#if LWIP_IGMP - if (msg->msg.jl.join_or_leave == NETCONN_JOIN) { - msg->err = igmp_joingroup(ip_2_ip4(API_EXPR_REF(msg->msg.jl.netif_addr)), - ip_2_ip4(API_EXPR_REF(msg->msg.jl.multiaddr))); - } else { - msg->err = igmp_leavegroup(ip_2_ip4(API_EXPR_REF(msg->msg.jl.netif_addr)), - ip_2_ip4(API_EXPR_REF(msg->msg.jl.multiaddr))); - } -#endif /* LWIP_IGMP */ +#if LWIP_IGMP + if (msg->msg.jl.join_or_leave == NETCONN_JOIN) { + msg->err = mcast_join_group(&msg->conn->pcb.udp->ipmc, API_EXPR_REF(msg->msg.jl.netif_addr), API_EXPR_REF(msg->msg.jl.multiaddr), NULL); + } else { + msg->err = mcast_leave_group(&msg->conn->pcb.udp->ipmc, API_EXPR_REF(msg->msg.jl.netif_addr), API_EXPR_REF(msg->msg.jl.multiaddr), NULL); + } +#endif /*LWIP_IGMP*/ } +#else + msg->err = ERR_VAL; #endif /* LWIP_UDP */ -#if (LWIP_TCP || LWIP_RAW) + } else if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_RAW) { +#if LWIP_RAW + if (msg->msg.jl.join_or_leave == NETCONN_JOIN) { + msg->err = mcast_join_group(&msg->conn->pcb.raw->ipmc, API_EXPR_REF(msg->msg.jl.netif_addr), API_EXPR_REF(msg->msg.jl.multiaddr), NULL); + } else { + msg->err = mcast_leave_group(&msg->conn->pcb.raw->ipmc, API_EXPR_REF(msg->msg.jl.netif_addr), API_EXPR_REF(msg->msg.jl.multiaddr), NULL); + } +#else + msg->err = ERR_VAL; +#endif /* LWIP_RAW */ } else { msg->err = ERR_VAL; -#endif /* (LWIP_TCP || LWIP_RAW) */ } +#endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */ } TCPIP_APIMSG_ACK(msg); } @@ -2124,6 +2143,7 @@ msg->err = ERR_CONN; if (msg->conn->pcb.tcp != NULL) { +#if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) { #if LWIP_UDP #if LWIP_IPV6 && LWIP_IPV6_MLD @@ -2137,23 +2157,32 @@ } } else #endif /* LWIP_IPV6 && LWIP_IPV6_MLD */ - { -#if LWIP_IGMP - if (msg->msg.jl.join_or_leave == NETCONN_JOIN) { - msg->err = igmp_joingroup_netif(netif, - ip_2_ip4(API_EXPR_REF(msg->msg.jl.multiaddr))); - } else { - msg->err = igmp_leavegroup_netif(netif, - ip_2_ip4(API_EXPR_REF(msg->msg.jl.multiaddr))); - } -#endif /* LWIP_IGMP */ + { +#if LWIP_IGMP + if (msg->msg.jl.join_or_leave == NETCONN_JOIN) { + msg->err = mcast_join_netif(&msg->conn->pcb.udp->ipmc, netif, API_EXPR_REF(msg->msg.jl.multiaddr), NULL); + } else { + msg->err = mcast_leave_netif(&msg->conn->pcb.udp->ipmc, netif, API_EXPR_REF(msg->msg.jl.multiaddr), NULL); } +#endif /*LWIP_IGMP*/ +#else + msg->err = ERR_VAL; #endif /* LWIP_UDP */ -#if (LWIP_TCP || LWIP_RAW) + } + } else if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_RAW) { +#if LWIP_RAW + if (msg->msg.jl.join_or_leave == NETCONN_JOIN) { + msg->err = mcast_join_netif(&msg->conn->pcb.raw->ipmc, netif, API_EXPR_REF(msg->msg.jl.multiaddr), NULL); + } else { + msg->err = mcast_leave_netif(&msg->conn->pcb.raw->ipmc, netif, API_EXPR_REF(msg->msg.jl.multiaddr), NULL); + } +#else + msg->err = ERR_VAL; +#endif /* LWIP_RAW */ } else { msg->err = ERR_VAL; -#endif /* (LWIP_TCP || LWIP_RAW) */ } +#endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */ } done: diff -Nur lwip-2.2.0init/src/api/sockets.c lwip-2.2.0/src/api/sockets.c --- lwip-2.2.0init/src/api/sockets.c 2024-04-02 19:14:40.959584000 +0800 +++ lwip-2.2.0/src/api/sockets.c 2024-04-02 19:15:03.867584000 +0800 @@ -293,16 +293,16 @@ struct lwip_socket_multicast_pair { /** the socket */ struct lwip_sock *sock; - /** the interface address */ - ip4_addr_t if_addr; + /** the interface index */ + u8_t if_idx; /** the group address */ ip4_addr_t multi_addr; }; static struct lwip_socket_multicast_pair socket_ipv4_multicast_memberships[LWIP_SOCKET_MAX_MEMBERSHIPS]; -static int lwip_socket_register_membership(int s, const ip4_addr_t *if_addr, const ip4_addr_t *multi_addr); -static void lwip_socket_unregister_membership(int s, const ip4_addr_t *if_addr, const ip4_addr_t *multi_addr); +static int lwip_socket_register_membership(int s, unsigned int if_idx, const ip4_addr_t *multi_addr); +static void lwip_socket_unregister_membership(int s, unsigned int if_idx, const ip4_addr_t *multi_addr); static void lwip_socket_drop_registered_memberships(int s); #endif /* LWIP_IGMP */ @@ -3841,32 +3841,24 @@ #endif /* LWIP_IPV4 && LWIP_MULTICAST_TX_OPTIONS && LWIP_UDP */ #if LWIP_IGMP case IP_ADD_MEMBERSHIP: - case IP_DROP_MEMBERSHIP: { + case IP_DROP_MEMBERSHIP: /* If this is a TCP or a RAW socket, ignore these options. */ - err_t igmp_err; - const struct ip_mreq *imr = (const struct ip_mreq *)optval; - ip4_addr_t if_addr; - ip4_addr_t multi_addr; - LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, struct ip_mreq, NETCONN_UDP); - inet_addr_to_ip4addr(&if_addr, &imr->imr_interface); - inet_addr_to_ip4addr(&multi_addr, &imr->imr_multiaddr); - if (optname == IP_ADD_MEMBERSHIP) { - if (!lwip_socket_register_membership(s, &if_addr, &multi_addr)) { - /* cannot track membership (out of memory) */ - err = ENOMEM; - igmp_err = ERR_OK; - } else { - igmp_err = igmp_joingroup(&if_addr, &multi_addr); - } - } else { - igmp_err = igmp_leavegroup(&if_addr, &multi_addr); - lwip_socket_unregister_membership(s, &if_addr, &multi_addr); - } - if (igmp_err != ERR_OK) { - err = EADDRNOTAVAIL; - } - } - break; + LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, struct ip_mreq); +#if LWIP_UDP + if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_UDP) { + err = mcast_sock_add_drop_membership(s, &sock->conn->pcb.udp->ipmc, optname, (const struct ip_mreq *)optval); + } else +#endif /* LWIP_UDP */ +#if LWIP_RAW + if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_RAW) { + err = mcast_sock_add_drop_membership(s, &sock->conn->pcb.raw->ipmc, optname, (const struct ip_mreq *)optval); + } else +#endif /* LWIP_RAW */ + { + done_socket(sock); + return ENOPROTOOPT; + } + break; #endif /* LWIP_IGMP */ default: LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n", @@ -4343,7 +4335,7 @@ #if LWIP_IGMP #if GAZELLE_ENABLE -int lwip_socket_get_multi_memberships(int s, ip4_addr_t *if_addr, ip4_addr_t *multi_addr) +int lwip_socket_get_multi_memberships(int s, unsigned int if_idx, ip4_addr_t *multi_addr) { struct lwip_sock *sock = get_socket(s); @@ -4352,7 +4344,7 @@ } if (socket_ipv4_multicast_memberships[s].sock == sock) { - ip4_addr_copy(*if_addr, socket_ipv4_multicast_memberships[s].if_addr); + if_idx = socket_ipv4_multicast_memberships[s].if_idx; ip4_addr_copy(*multi_addr, socket_ipv4_multicast_memberships[s].multi_addr); done_socket(sock); return 1; @@ -4370,7 +4362,7 @@ * @return 1 on success, 0 on failure */ static int -lwip_socket_register_membership(int s, const ip4_addr_t *if_addr, const ip4_addr_t *multi_addr) +lwip_socket_register_membership(int s, unsigned int if_idx, const ip4_addr_t *multi_addr) { struct lwip_sock *sock = get_socket(s); int i; @@ -4378,6 +4370,8 @@ if (!sock) { return 0; } + SYS_ARCH_DECL_PROTECT(lev); + SYS_ARCH_PROTECT(lev); #if GAZELLE_ENABLE i = s; #else @@ -4385,7 +4379,7 @@ #endif if (socket_ipv4_multicast_memberships[i].sock == NULL) { socket_ipv4_multicast_memberships[i].sock = sock; - ip4_addr_copy(socket_ipv4_multicast_memberships[i].if_addr, *if_addr); + socket_ipv4_multicast_memberships[i].if_idx = if_idx; ip4_addr_copy(socket_ipv4_multicast_memberships[i].multi_addr, *multi_addr); done_socket(sock); return 1; @@ -4393,6 +4387,7 @@ #if !GAZELLE_ENABLE } #endif + SYS_ARCH_UNPROTECT(lev); done_socket(sock); return 0; } @@ -4403,7 +4398,7 @@ * ATTENTION: this function is called from tcpip_thread (or under CORE_LOCK). */ static void -lwip_socket_unregister_membership(int s, const ip4_addr_t *if_addr, const ip4_addr_t *multi_addr) +lwip_socket_unregister_membership(int s, unsigned int if_idx, const ip4_addr_t *multi_addr) { struct lwip_sock *sock = get_socket(s); int i; @@ -4411,17 +4406,18 @@ if (!sock) { return; } - + SYS_ARCH_DECL_PROTECT(lev); + SYS_ARCH_PROTECT(lev); #if GAZELLE_ENABLE i = s; #else for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) { #endif if ((socket_ipv4_multicast_memberships[i].sock == sock) && - ip4_addr_eq(&socket_ipv4_multicast_memberships[i].if_addr, if_addr) && - ip4_addr_eq(&socket_ipv4_multicast_memberships[i].multi_addr, multi_addr)) { + (socket_ipv4_multicast_memberships[i].if_idx == if_idx) && + ip4_addr_cmp(&socket_ipv4_multicast_memberships[i].multi_addr, multi_addr)) { socket_ipv4_multicast_memberships[i].sock = NULL; - ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].if_addr); + socket_ipv4_multicast_memberships[i].if_idx = NETIF_NO_INDEX; ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].multi_addr); #if !GAZELLE_ENABLE break; @@ -4430,6 +4426,7 @@ #if !GAZELLE_ENABLE } #endif + SYS_ARCH_UNPROTECT(lev); done_socket(sock); } @@ -4446,24 +4443,29 @@ if (!sock) { return; } + SYS_ARCH_DECL_PROTECT(lev); + SYS_ARCH_PROTECT(lev); #if GAZELLE_ENABLE i = s; #else for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) { #endif if (socket_ipv4_multicast_memberships[i].sock == sock) { - ip_addr_t multi_addr, if_addr; + ip_addr_t multi_addr; + u8_t if_idx; ip_addr_copy_from_ip4(multi_addr, socket_ipv4_multicast_memberships[i].multi_addr); - ip_addr_copy_from_ip4(if_addr, socket_ipv4_multicast_memberships[i].if_addr); + if_idx = socket_ipv4_multicast_memberships[i].if_idx; + + socket_ipv4_multicast_memberships[i].if_idx = NETIF_NO_INDEX; socket_ipv4_multicast_memberships[i].sock = NULL; - ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].if_addr); ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].multi_addr); - netconn_join_leave_group(sock->conn, &multi_addr, &if_addr, NETCONN_LEAVE); + netconn_join_leave_group_netif(sock->conn, &multi_addr, if_idx, NETCONN_LEAVE); } #if !GAZELLE_ENABLE } #endif + SYS_ARCH_UNPROTECT(lev); done_socket(sock); } #endif /* LWIP_IGMP */ @@ -4484,8 +4486,17 @@ if (!sock) { return 0; } - + + SYS_ARCH_DECL_PROTECT(lev); + SYS_ARCH_PROTECT(lev); for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) { + if ((socket_ipv6_multicast_memberships[i].sock == sock) && + (socket_ipv6_multicast_memberships[i].if_idx == if_idx) && + ip6_addr_cmp(&socket_ipv6_multicast_memberships[i].multi_addr, multi_addr)) { + done_socket(sock); + return 1; + } + if (socket_ipv6_multicast_memberships[i].sock == NULL) { socket_ipv6_multicast_memberships[i].sock = sock; socket_ipv6_multicast_memberships[i].if_idx = (u8_t)if_idx; @@ -4494,6 +4505,7 @@ return 1; } } + SYS_ARCH_UNPROTECT(lev); done_socket(sock); return 0; } @@ -4513,16 +4525,19 @@ return; } + SYS_ARCH_DECL_PROTECT(lev); + SYS_ARCH_PROTECT(lev); for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) { if ((socket_ipv6_multicast_memberships[i].sock == sock) && (socket_ipv6_multicast_memberships[i].if_idx == if_idx) && - ip6_addr_eq(&socket_ipv6_multicast_memberships[i].multi_addr, multi_addr)) { + ip6_addr_cmp(&socket_ipv6_multicast_memberships[i].multi_addr, multi_addr)) { socket_ipv6_multicast_memberships[i].sock = NULL; socket_ipv6_multicast_memberships[i].if_idx = NETIF_NO_INDEX; ip6_addr_set_zero(&socket_ipv6_multicast_memberships[i].multi_addr); break; } } + SYS_ARCH_UNPROTECT(lev); done_socket(sock); } @@ -4539,7 +4554,8 @@ if (!sock) { return; } - + SYS_ARCH_DECL_PROTECT(lev); + SYS_ARCH_PROTECT(lev); for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) { if (socket_ipv6_multicast_memberships[i].sock == sock) { ip_addr_t multi_addr; @@ -4555,10 +4571,159 @@ netconn_join_leave_group_netif(sock->conn, &multi_addr, if_idx, NETCONN_LEAVE); } } + SYS_ARCH_UNPROTECT(lev); done_socket(sock); } #endif /* LWIP_IPV6_MLD */ +/** Remove multicast filter when pcb remove + * + * @param ipmc multicast filter control block + */ +void +mcast_pcb_remove(struct ip_mc *ipmc) +{ +#if LWIP_IPV4 && LWIP_IGMP + { + struct ip4_mc *mc, *next; + + mc = ipmc->mc4; + while (mc) { + next = mc->next; + mcast_ip4_mc_src_remove(mc->src); + igmp_leavegroup(&mc->if_addr, &mc->multi_addr); + mem_free(mc); + mc = next; + } + } +#endif /* LWIP_IPV4 && LWIP_IGMP */ +} + +/** Common code to see if the current input multicast packet matches the pcb + * (current input packet is accessed via ip(4/6)_current_* macros) + * + * @param ipmc multicast filter control block + * @param inp network interface on which the datagram was received (only used for IPv4) + * @return 1 on match, 0 otherwise + */ +u8_t +mcast_input_local_match(struct ip_mc *ipmc, struct netif *inp) +{ +#if LWIP_IPV4 && LWIP_IGMP + if (!ip_current_is_v6()) { + struct igmp_src *src; + struct ip4_mc *mc; + ip4_addr_t *multi_addr = ip4_current_dest_addr(); + ip4_addr_t *src_addr = ip4_current_src_addr(); + + IP4_MC_FOREACH(ipmc, mc) { + if (ip4_addr_cmp(&mc->if_addr, netif_ip4_addr(inp)) && + ip4_addr_cmp(&mc->multi_addr, multi_addr)) { + if (mc->fmode == MCAST_EXCLUDE) { + IP4_MC_SRC_FOREACH(mc, src) { + if (ip4_addr_cmp(&src->src_addr, src_addr)) { + return 0; + } + } + return 1; /* MCAST_EXCLUDE src_addr must not in src list */ + + } else { /* MCAST_INCLUDE */ + IP4_MC_SRC_FOREACH(mc, src) { + if (ip4_addr_cmp(&src->src_addr, src_addr)) { + return 1; + } + } + return 0; /* MCAST_INCLUDE src_addr must in src list */ + } + } + } + } else {} +#endif /* LWIP_IPV4 && LWIP_IGMP */ + return 0; +} + +#if (LWIP_IPV4 && LWIP_IGMP) || (LWIP_IPV6 && LWIP_IPV6_MLD) +/** + * setsockopt() IP_ADD_MEMBERSHIP / IP_DROP_MEMBERSHIP command + */ +int +mcast_sock_add_drop_membership(int s, struct ip_mc *ipmc, int optname, const struct ip_mreq *imr) +{ + struct netif *netif; + ip_addr_t if_addr; + ip_addr_t multi_addr; + err_t err; + u8_t if_idx; + + inet_addr_to_ip4addr(ip_2_ip4(&if_addr), &imr->imr_interface); + inet_addr_to_ip4addr(ip_2_ip4(&multi_addr), &imr->imr_multiaddr); + IP_SET_TYPE_VAL(if_addr, IPADDR_TYPE_V4); + IP_SET_TYPE_VAL(multi_addr, IPADDR_TYPE_V4); + + if (!ip4_addr_ismulticast(ip_2_ip4(&multi_addr))) { + return EADDRNOTAVAIL; + } + + if (ip4_addr_isany(ip_2_ip4(&if_addr))) { /* To all network interface */ + if (optname == IP_ADD_MEMBERSHIP) { + NETIF_FOREACH(netif) { + if_idx = netif_get_index(netif); + if (!lwip_socket_register_membership(s, if_idx, ip_2_ip4(&multi_addr))) { + /* cannot track membership (out of memory) */ + err = ENOMEM; + goto out; + } + } + + err = mcast_join_group(ipmc, &if_addr, &multi_addr, NULL); + } else { + err = mcast_leave_group(ipmc, &if_addr, &multi_addr, NULL); + NETIF_FOREACH(netif) { + if_idx = netif_get_index(netif); + lwip_socket_unregister_membership(s, if_idx, ip_2_ip4(&multi_addr)); + } + } + + } else { /* To specified network interface */ + if (!(ip_2_ip4(&if_addr)->addr & PP_HTONL(IP_CLASSA_NET))) { /* IS a BSD style index ? */ + u8_t idx = (u8_t)PP_NTOHL(ip_2_ip4(&if_addr)->addr); + netif = netif_get_by_index(idx); + if (netif == NULL) { + return ENXIO; + } + *ip_2_ip4(&if_addr) = *netif_ip4_addr(netif); + + } else { + NETIF_FOREACH(netif) { + if (ip4_addr_cmp(ip_2_ip4(&if_addr), netif_ip4_addr(netif))) { + break; + } + } + if (netif == NULL) { + return ENXIO; + } + } + + if (optname == IP_ADD_MEMBERSHIP) { + if_idx = netif_get_index(netif); + if (!lwip_socket_register_membership(s, if_idx, ip_2_ip4(&multi_addr))) { + /* cannot track membership (out of memory) */ + err = ENOMEM; + goto out; + } + err = mcast_join_netif(ipmc, netif, &multi_addr, NULL); + } else { + err = mcast_leave_netif(ipmc, netif, &multi_addr, NULL); + if_idx = netif_get_index(netif); + lwip_socket_unregister_membership(s, if_idx, ip_2_ip4(&multi_addr)); + } + } + +out: + return (u8_t)err_to_errno(err); +} +#endif /* (LWIP_IPV4 && LWIP_IGMP) || (LWIP_IPV6 && LWIP_IPV6_MLD)*/ + #if GAZELLE_ENABLE void lwip_sock_init(void) { diff -Nur lwip-2.2.0init/src/core/dir.mk lwip-2.2.0/src/core/dir.mk --- lwip-2.2.0init/src/core/dir.mk 2024-04-02 19:14:40.969584000 +0800 +++ lwip-2.2.0/src/core/dir.mk 2024-04-02 19:15:03.867584000 +0800 @@ -3,6 +3,6 @@ ipv4/icmp.c ipv4/ip4_addr.c ipv4/ip4_frag.c ipv4/etharp.c \ ipv4/ip4.c ipv4/igmp.c ipv6/icmp6.c ipv6/ip6_addr.c ipv6/ip6_frag.c \ ipv6/ethip6.c ipv6/ip6.c ipv6/dhcp6.c ipv6/inet6.c \ - ipv6/mld6.c ipv6/nd6.c + ipv6/mld6.c ipv6/nd6.c mcast.c $(eval $(call register_dir, core, $(SRC))) diff -Nur lwip-2.2.0init/src/core/ipv4/igmp.c lwip-2.2.0/src/core/ipv4/igmp.c --- lwip-2.2.0init/src/core/ipv4/igmp.c 2024-04-02 19:14:40.968584000 +0800 +++ lwip-2.2.0/src/core/ipv4/igmp.c 2024-04-02 19:15:03.867584000 +0800 @@ -93,6 +93,7 @@ #include "lwip/netif.h" #include "lwip/stats.h" #include "lwip/prot/igmp.h" +#include "lwip/sockets.h" #include @@ -104,9 +105,21 @@ static err_t igmp_ip_output_if(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest, struct netif *netif); static void igmp_send(struct netif *netif, struct igmp_group *group, u8_t type); +#if LWIP_IGMP_V3 +static void igmp_v3_timeout(struct netif *netif, struct igmp_group *group); +static void igmp_v3_start_timer(struct igmp_group *group, u8_t max_time); +static void igmp_v3_delaying_member(struct igmp_group *group, u8_t maxresp); +static void igmp_v3_send(struct netif *netif, struct igmp_group *group, u8_t type); +static void igmp_v3_send_allgroups(struct netif *netif); +#endif /* LWIP_IGMP_V3 */ + static ip4_addr_t allsystems; static ip4_addr_t allrouters; +#if LWIP_IGMP_V3 +static ip4_addr_t v3_routers; +#endif /* LWIP_IGMP_V3 */ + /** * Initialize the IGMP module */ @@ -117,6 +130,10 @@ IP4_ADDR(&allsystems, 224, 0, 0, 1); IP4_ADDR(&allrouters, 224, 0, 0, 2); + +#if LWIP_IGMP_V3 + IP4_ADDR(&v3_routers, 224, 0, 0, 22); +#endif /* LWIP_IGMP_V3 */ } /** @@ -136,6 +153,9 @@ if (group != NULL) { group->group_state = IGMP_GROUP_IDLE_MEMBER; group->use++; +#if LWIP_IGMP_V3 + group->v3_group_state = IGMP_GROUP_IDLE_MEMBER; +#endif /* LWIP_IGMP_V3 */ /* Allow the igmp messages at the MAC level */ if (netif->igmp_mac_filter != NULL) { @@ -204,6 +224,15 @@ igmp_delaying_member(group, IGMP_JOIN_DELAYING_MEMBER_TMR); group = group->next; } + +#if LWIP_IGMP_V3 + group = netif_igmp_data(netif); + + if (group) { + /* We use first group to determine report all groups */ + igmp_v3_delaying_member(group, IGMP_JOIN_DELAYING_MEMBER_TMR); + } +#endif /* LWIP_IGMP_V3 */ } /** @@ -261,6 +290,12 @@ group->group_state = IGMP_GROUP_NON_MEMBER; group->last_reporter_flag = 0; group->use = 0; +#if LWIP_IGMP_V3 + group->v3_fmode = IGMP_FMODE_INIT; /* Non mode with init-stat */ + group->v3_timer = 0; /* Not running */ + group->v3_group_state = IGMP_GROUP_NON_MEMBER; + group->v3_last_reporter_flag = 0; +#endif /* LWIP_IGMP_V3 */ /* Ensure allsystems group is always first in list */ if (list_head == NULL) { @@ -365,6 +400,71 @@ /* NOW ACT ON THE INCOMING MESSAGE TYPE... */ switch (igmp->igmp_msgtype) { case IGMP_MEMB_QUERY: +#if LWIP_IGMP_V3 + if (p->len >= IGMP_V3_MINLEN) { /* this is a igmp v3 query packet */ + struct igmp_v3_query *igmp_v3 = (struct igmp_v3_query *)p->payload; + + if ((ip4_addr_cmp(dest, &allsystems)) && ip4_addr_isany(&igmp_v3->igmp_v3_group_address)) { + /* THIS IS THE GENERAL QUERY */ + groupref = netif_igmp_data(inp); + + if (groupref) { + /* We use first group to determine report all groups */ + igmp_v3_delaying_member(groupref, igmp_v3->igmp_v3_maxresp); + } + + } else { + /* IGMP_MEMB_QUERY to a specific group ? */ + if (!ip4_addr_isany(&igmp_v3->igmp_v3_group_address)) { + u16_t src_cnt = PP_NTOHS(igmp_v3->igmp_v3_srccnt); + u16_t src_buf_size = src_cnt << 2; + u8_t need_free; + ip4_addr_p_t *src_buf; + + if (p->tot_len < (IGMP_V3_QUERY_HLEN + src_buf_size)) { + /* packet len error */ + pbuf_free(p); + IGMP_STATS_INC(igmp.lenerr); + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: length error\n")); + return; + } + + if (src_cnt) { /* Seach interest */ + if (p->len < (IGMP_V3_QUERY_HLEN + src_buf_size)) { /* Unfortunately! the source address memory is not contiguous */ + src_buf = (ip4_addr_p_t *)mem_malloc(src_buf_size); + if (src_buf == NULL) { + pbuf_free(p); + IGMP_STATS_INC(igmp.memerr); + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: not enough memory for igmp_input\n")); + return; + } + need_free = 1; + pbuf_copy_partial(p, src_buf, src_buf_size, IGMP_V3_QUERY_HLEN); + + } else { + need_free = 0; + src_buf = (ip4_addr_p_t *)((u8_t *)p->payload + IGMP_V3_QUERY_HLEN); + } + + LWIP_ASSERT("igmp_v3_query packet source address array not aligned!", !((mem_ptr_t)src_buf & 0x3)); + ip4_addr_t igmp_v3_group_address; + memcpy(&igmp_v3_group_address, &igmp_v3->igmp_v3_group_address, sizeof(igmp_v3_group_address)); + if (mcast_ip4_filter_interest(inp, (const ip4_addr_t *)&igmp_v3_group_address, src_buf, src_cnt)) { + /* We interest! */ + igmp_v3_delaying_member(group, igmp_v3->igmp_v3_maxresp); + } + + if (need_free) { + mem_free(src_buf); + } + + } else { /* Report! */ + igmp_v3_delaying_member(group, igmp_v3->igmp_v3_maxresp); + } + } + } + } +#endif /* LWIP_IGMP_V3 */ /* IGMP_MEMB_QUERY to the "all systems" address ? */ if ((ip4_addr_eq(dest, &allsystems)) && ip4_addr_isany(&igmp->igmp_group_address)) { /* THIS IS THE GENERAL QUERY */ @@ -523,6 +623,16 @@ /* Need to work out where this timer comes from */ group->group_state = IGMP_GROUP_DELAYING_MEMBER; + + +#if LWIP_IGMP_V3 + igmp_v3_send(netif, group, IGMP_V3_MEMB_REPORT); + + igmp_v3_start_timer(group, IGMP_JOIN_DELAYING_MEMBER_TMR); + + /* Need to work out where this timer comes from */ + group->v3_group_state = IGMP_GROUP_DELAYING_MEMBER; +#endif /* LWIP_IGMP_V3 */ } /* Increment group use */ group->use++; @@ -612,6 +722,13 @@ igmp_send(netif, group, IGMP_LEAVE_GROUP); } +#if LWIP_IGMP_V3 + /* If we are the last reporter for this group */ + if (group->v3_last_reporter_flag) { + igmp_v3_send(netif, group, IGMP_LEAVE_GROUP); + } +#endif /* LWIP_IGMP_V3 */ + /* Disable the group at the MAC level */ if (netif->igmp_mac_filter != NULL) { LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup_netif: igmp_mac_filter(DEL ")); @@ -654,6 +771,19 @@ } group = group->next; } + +#if LWIP_IGMP_V3 + group = netif_igmp_data(netif); + while (group != NULL) { + if (group->v3_timer > 0) { + group->v3_timer--; + if (group->v3_timer == 0) { + igmp_v3_timeout(netif, group); + } + } + group = group->next; + } +#endif /* LWIP_IGMP_V3 */ } } @@ -681,6 +811,36 @@ } } +#if LWIP_IGMP_V3 +/** + * Called if a timeout for one group is reached. + * Sends a report for this group. + * + * @param group an igmp_group for which a timeout is reached + */ +static void +igmp_v3_timeout(struct netif *netif, struct igmp_group *group) +{ + /* If the state is IGMP_GROUP_DELAYING_MEMBER then we send a report for this group + (if it is the allsystems group to all groups) */ + if (group->v3_group_state == IGMP_GROUP_DELAYING_MEMBER) { + group->group_state = IGMP_GROUP_IDLE_MEMBER; + if (ip4_addr_cmp(&(group->group_address), &allsystems)) { + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_v3_timeout: report all membership\n")); + IGMP_STATS_INC(igmp.tx_report); + igmp_v3_send_allgroups(netif); + + } else { + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_v3_timeout: report membership for group with address ")); + ip4_addr_debug_print(IGMP_DEBUG, &(group->group_address)); + LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", (void *)netif)); + IGMP_STATS_INC(igmp.tx_report); + igmp_v3_send(netif, group, IGMP_V3_MEMB_REPORT); + } + } +} +#endif /* LWIP_IGMP_V3 */ + /** * Start a timer for an igmp group * @@ -703,6 +863,51 @@ } } +#if LWIP_IGMP_V3 +/** + * Start a timer for an igmp group + * + * @param group the igmp_group for which to start a timer + * @param max_time the time in multiples of IGMP_TMR_INTERVAL (decrease with + * every call to igmp_tmr()) + */ +static void +igmp_v3_start_timer(struct igmp_group *group, u8_t max_time) +{ + /* + * If Max Resp Code < 128, Max Resp Time = Max Resp Code + * + * If Max Resp Code >= 128, Max Resp Code represents a floating-point + * value as follows: + * + * 0 1 2 3 4 5 6 7 + * +-+-+-+-+-+-+-+-+ + * |1| exp | mant | + * +-+-+-+-+-+-+-+-+ + * + * Max Resp Time = (mant | 0x10) << (exp + 3) + */ + u16_t delay; + + if (max_time < 128) { + delay = max_time; + } else { + delay = ((max_time & 0xf) | 0x10) << (((max_time >> 4) & 7) + 3); + } + +#ifdef LWIP_RAND + group->v3_timer = (u16_t)(delay > 2 ? (LWIP_RAND() % delay) : 1); +#else /* LWIP_RAND */ + /* ATTENTION: use this only if absolutely necessary! */ + group->v3_timer = delay / 2; +#endif /* LWIP_RAND */ + + if (group->v3_timer == 0) { + group->v3_timer = 1; + } +} +#endif /* LWIP_IGMP_V3 */ + /** * Delaying membership report for a group if necessary * @@ -721,6 +926,33 @@ } +#if LWIP_IGMP_V3 +/** + * Delaying membership report for a group if necessary + * + * @param group the igmp_group for which "delaying" membership report + * @param maxresp query delay + */ +static void +igmp_v3_delaying_member(struct igmp_group *group, u8_t maxresp) +{ + u16_t delay; + + if (maxresp < 128) { + delay = maxresp; + } else { + delay = ((maxresp & 0xf) | 0x10) << (((maxresp >> 4) & 7) + 3); + } + + if ((group->v3_group_state == IGMP_GROUP_IDLE_MEMBER) || + ((group->v3_group_state == IGMP_GROUP_DELAYING_MEMBER) && + ((group->v3_timer == 0) || (delay < group->timer)))) { + igmp_v3_start_timer(group, maxresp); + group->v3_group_state = IGMP_GROUP_DELAYING_MEMBER; + } +} +#endif /* LWIP_IGMP_V3 */ + /** * Sends an IP packet on a network interface. This function constructs the IP header * and calculates the IP header checksum. If the source IP address is NULL, @@ -798,4 +1030,220 @@ } } +#if LWIP_IGMP_V3 +/** + * Build a igmp v3 record to a specific group. + * + * @param rec record to build + * @param group the group to which to send the packet + * @param fmode filter mode + * @param src_array source addr array + * @param src_cnt source addr cnt + */ +static void +igmp_v3_build_record(struct igmp_v3_record *rec, struct igmp_group *group, u8_t fmode, ip4_addr_p_t *src_array, u32_t src_cnt) +{ + ip4_addr_p_t *src_copy; + + if (fmode == MCAST_EXCLUDE) { + if (group->v3_fmode != MCAST_EXCLUDE) { + group->v3_fmode = MCAST_EXCLUDE; + rec->igmp_v3_rc_type = IGMP_V3_REC_TO_EX; + } else { + rec->igmp_v3_rc_type = IGMP_V3_REC_IS_EX; + } + + } else { + if (group->v3_fmode != MCAST_INCLUDE) { + group->v3_fmode = MCAST_INCLUDE; + rec->igmp_v3_rc_type = IGMP_V3_REC_TO_IN; + } else { + rec->igmp_v3_rc_type = IGMP_V3_REC_IS_IN; + } + } + + rec->igmp_v3_rc_auxlen = 0; + rec->igmp_v3_rc_srccnt = PP_HTONS(src_cnt); + ip4_addr_set(&rec->igmp_v3_rc_group_address, &group->group_address); + + if (src_cnt) { + src_copy = (ip4_addr_p_t *)(rec + 1); + MEMCPY(src_copy, src_array, (src_cnt << 2)); + } +} + +/** + * Send an igmp v3 packet to a specific group. + * + * @param group the group to which to send the packet + * @param type the type of igmp packet to send + */ +static void +igmp_v3_send(struct netif *netif, struct igmp_group *group, u8_t type) +{ + struct igmp_v3_report *rep; + struct igmp_v3_record *rec; + ip4_addr_t src; + struct pbuf *p; + + ip4_addr_copy(src, *netif_ip4_addr(netif)); + + if (type == IGMP_LEAVE_GROUP) { /* Leave from a group */ + p = pbuf_alloc(PBUF_TRANSPORT, IGMP_V3_REPORT_HLEN + IGMP_V3_RECORD_LEN(0), PBUF_RAM); + if (p == NULL) { + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_v3_send: not enough memory for igmp_v3_send\n")); + IGMP_STATS_INC(igmp.memerr); + return; + } + + rep = (struct igmp_v3_report *)p->payload; + rep->igmp_v3_msgtype = IGMP_V3_MEMB_REPORT; + rep->igmp_v3_reserve1 = 0; + rep->igmp_v3_checksum = 0; + rep->igmp_v3_reserve2 = 0; + rep->igmp_v3_reccnt = PP_HTONS(1); + + rec = (struct igmp_v3_record *)(rep + 1); + if (group->v3_fmode == MCAST_EXCLUDE) { + rec->igmp_v3_rc_type = IGMP_V3_REC_TO_IN; + } else { + rec->igmp_v3_rc_type = IGMP_V3_REC_IS_IN; + } + rec->igmp_v3_rc_auxlen = 0; + rec->igmp_v3_rc_srccnt = 0; /* IS_IN (NULL) mean drop group */ + ip4_addr_set(&rec->igmp_v3_rc_group_address, &group->group_address); + rep->igmp_v3_checksum = inet_chksum(rep, IGMP_V3_REPORT_HLEN + IGMP_V3_RECORD_LEN(0)); + + } else { /* Report a group */ + ip4_addr_p_t src_array[LWIP_MCAST_SRC_TBL_SIZE]; + u16_t src_cnt; + u8_t fmode; + + src_cnt = mcast_ip4_filter_info(netif, &group->group_address, src_array, LWIP_MCAST_SRC_TBL_SIZE, &fmode); + LWIP_ASSERT("igmp_v3_send: multicast filter error!", !(!src_cnt && (fmode == MCAST_INCLUDE))); + + p = pbuf_alloc(PBUF_TRANSPORT, IGMP_V3_REPORT_HLEN + IGMP_V3_RECORD_LEN(src_cnt), PBUF_RAM); + if (p == NULL) { + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_v3_send: not enough memory for igmp_v3_send\n")); + IGMP_STATS_INC(igmp.memerr); + return; + } + + rep = (struct igmp_v3_report *)p->payload; + rep->igmp_v3_msgtype = IGMP_V3_MEMB_REPORT; + rep->igmp_v3_reserve1 = 0; + rep->igmp_v3_checksum = 0; + rep->igmp_v3_reserve2 = 0; + rep->igmp_v3_reccnt = PP_HTONS(1); + + rec = (struct igmp_v3_record *)(rep + 1); + igmp_v3_build_record(rec, group, fmode, src_array, src_cnt); + rep->igmp_v3_checksum = inet_chksum(rep, IGMP_V3_REPORT_HLEN + IGMP_V3_RECORD_LEN(src_cnt)); + group->v3_last_reporter_flag = 1; /* Remember we were the last to report */ + } + + igmp_ip_output_if(p, &src, &v3_routers, netif); + pbuf_free(p); +} + +/** + * Send igmp v3 packet to report all groups. + */ +static void +igmp_v3_send_allgroups(struct netif *netif) +{ + struct igmp_group *group; + struct igmp_v3_report *rep; + struct igmp_v3_record *rec; + struct pbuf *p, *p_rec; + ip4_addr_t src; + ip4_addr_p_t src_array[LWIP_MCAST_SRC_TBL_SIZE]; + u16_t src_cnt; + u16_t max_pkt_len = (u16_t)(netif->mtu ? netif->mtu : 0xffff); + u8_t fmode; + + ip4_addr_copy(src, *netif_ip4_addr(netif)); + + group = netif_igmp_data(netif); + if (group) { + group = group->next; /* do not report allsystem group */ + } + + if (!group) { + return; /* no group */ + } + + src_cnt = mcast_ip4_filter_info(netif, &group->group_address, src_array, LWIP_MCAST_SRC_TBL_SIZE, &fmode); + LWIP_ASSERT("igmp_v3_send: multicast filter error!", !(!src_cnt && (fmode == MCAST_INCLUDE))); + + while (group) { + p = pbuf_alloc(PBUF_TRANSPORT, IGMP_V3_REPORT_HLEN + IGMP_V3_RECORD_LEN(src_cnt), PBUF_RAM); + if (p == NULL) { + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_v3_send_allgroups: not enough memory for igmp_v3_send_allgroups\n")); + IGMP_STATS_INC(igmp.memerr); + return; + } + + rep = (struct igmp_v3_report *)p->payload; + rep->igmp_v3_msgtype = IGMP_V3_MEMB_REPORT; + rep->igmp_v3_reserve1 = 0; + rep->igmp_v3_checksum = 0; + rep->igmp_v3_reserve2 = 0; + rep->igmp_v3_reccnt = PP_HTONS(1); + + rec = (struct igmp_v3_record *)(rep + 1); + igmp_v3_build_record(rec, group, fmode, src_array, src_cnt); + group->v3_last_reporter_flag = 1; /* Remember we were the last to report */ + +cat_rec: + group = group->next; /* the next group */ + if (group) { + src_cnt = mcast_ip4_filter_info(netif, &group->group_address, src_array, LWIP_MCAST_SRC_TBL_SIZE, &fmode); + LWIP_ASSERT("igmp_v3_send: multicast filter error!", !(!src_cnt && (fmode == MCAST_INCLUDE))); + + if (p->tot_len + IGMP_V3_RECORD_LEN(src_cnt) < max_pkt_len) { /* can add a record? */ + p_rec = pbuf_alloc(PBUF_RAW, IGMP_V3_RECORD_LEN(src_cnt), PBUF_RAM); + if (p_rec) { + rep->igmp_v3_reccnt = PP_HTONS(PP_NTOHS(rep->igmp_v3_reccnt) + 1); /* add a record */ + + rec = (struct igmp_v3_record *)p_rec->payload; + igmp_v3_build_record(rec, group, fmode, src_array, src_cnt); + group->v3_last_reporter_flag = 1; /* Remember we were the last to report */ + pbuf_cat(p, p_rec); /* cat to tail */ + goto cat_rec; + + } else { + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_v3_send_allgroups: not enough memory for igmp_v3_send_allgroups\n")); + IGMP_STATS_INC(igmp.memerr); + } + } + } + + rep->igmp_v3_checksum = inet_chksum_pbuf(p); + igmp_ip_output_if(p, &src, &v3_routers, netif); + pbuf_free(p); + } +} + +/** + * igmp v3 report trigger. + */ +void +igmp_v3_trigger(struct netif *netif, const ip4_addr_t *groupaddr) +{ + struct igmp_group *group; + + /* find group */ + group = igmp_lookfor_group(netif, groupaddr); + if (group) { + igmp_v3_send(netif, group, IGMP_V3_MEMB_REPORT); + + igmp_v3_start_timer(group, IGMP_JOIN_DELAYING_MEMBER_TMR); + + /* Need to work out where this timer comes from */ + group->v3_group_state = IGMP_GROUP_DELAYING_MEMBER; + } +} + +#endif /* LWIP_IGMP_V3 */ #endif /* LWIP_IPV4 && LWIP_IGMP */ diff -Nur lwip-2.2.0init/src/core/mcast.c lwip-2.2.0/src/core/mcast.c --- lwip-2.2.0init/src/core/mcast.c 1970-01-01 08:00:00.000000000 +0800 +++ lwip-2.2.0/src/core/mcast.c 2024-04-02 19:15:03.867584000 +0800 @@ -0,0 +1,605 @@ +/** + * @file + * Multicast filter module\n + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Kylinos Technologies + * + */ + +#include "lwip/opt.h" + +#if LWIP_UDP || LWIP_RAW /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/err.h" +#include "lwip/udp.h" +#include "lwip/raw.h" +#include "lwip/def.h" +#include "lwip/mem.h" +#include "lwip/netif.h" +#include "lwip/errno.h" +#include "lwip/ip_addr.h" +#include "lwip/sockets.h" +#include "lwip/mcast.h" + +#include /* We need offsetof() */ + +#if LWIP_IPV4 && LWIP_IGMP +/** + * ipv4 multicast filter find + */ +struct ip4_mc * +mcast_ip4_mc_find(struct ip_mc *ipmc, struct netif *netif, const ip4_addr_t *multi_addr, struct ip4_mc **mc_prev) +{ + struct ip4_mc *prev = NULL; + struct ip4_mc *mc; + + IP4_MC_FOREACH(ipmc, mc) { + if (ip4_addr_cmp(&mc->if_addr, netif_ip4_addr(netif)) && + ip4_addr_cmp(&mc->multi_addr, multi_addr)) { /* check interface and multicast address */ + if (mc_prev) { + *mc_prev = prev; + } + return mc; /* found! */ + } + prev = mc; + } + + return NULL; /* not found! */ +} + +/** + * ipv4 multicast filter find source + */ +static struct igmp_src * +mcast_ip4_mc_src_find(struct ip4_mc *mc, const ip4_addr_t *src_addr, struct igmp_src **src_prev) +{ + struct igmp_src *prev = NULL; + struct igmp_src *src; + + IP4_MC_SRC_FOREACH(mc, src) { + if (ip4_addr_cmp(&src->src_addr, src_addr)) { /* check source address */ + if (src_prev) { + *src_prev = prev; + } + return src; /* found! */ + } + prev = src; + } + + return NULL; /* not found! */ +} + +/** + * ipv4 multicast filter remove all source + */ +void +mcast_ip4_mc_src_remove(struct igmp_src *src) +{ + struct igmp_src *next; + + while (src) { + next = src->next; + mem_free(src); + src = next; + } +} + +#if LWIP_IGMP_V3 +/** + * ipv4 multicast filter group source infomation (use ip4_addr_p_t for IGMPv3 speedup) + */ +u16_t +mcast_ip4_filter_info(struct netif *netif, const ip4_addr_t *multi_addr, ip4_addr_p_t addr_array[], u16_t arr_cnt, u8_t *fmode) +{ + static ip4_addr_p_t in_tbl[LWIP_MCAST_SRC_TBL_SIZE]; + static ip4_addr_p_t ex_tbl[LWIP_MCAST_SRC_TBL_SIZE]; + + struct ip4_mc *mc; + struct igmp_src *src; + ip4_addr_t addr; /* for compare speed */ + u16_t i, j; + u16_t cnt, in_cnt = 0, ex_cnt = 0; + u16_t max_cnt = (u16_t)((arr_cnt > LWIP_MCAST_SRC_TBL_SIZE) ? LWIP_MCAST_SRC_TBL_SIZE : arr_cnt); + u8_t match = 0; + +#define LWIP_IP4_MC_GET(pcb, pcbs, type, tbl, c) \ + for ((pcb) = (pcbs); (pcb) != NULL; (pcb) = (pcb)->next) { \ + mc = mcast_ip4_mc_find(&(pcb)->ipmc, netif, multi_addr, NULL); \ + if ((mc == NULL) || (mc->fmode != (type))) { \ + continue; \ + } \ + match = 1; /* group matched */ \ + IP4_MC_SRC_FOREACH(mc, src) { \ + if ((c) < max_cnt) { \ + ip4_addr_set(&(tbl)[(c)], &src->src_addr); /* save a source */ \ + (c)++; \ + } else { \ + *fmode = MCAST_EXCLUDE; /* table overflow, we need all this group packet */ \ + return (0); \ + } \ + } \ + } + +#if LWIP_UDP + { + struct udp_pcb *pcb; + LWIP_IP4_MC_GET(pcb, udp_pcbs, MCAST_INCLUDE, in_tbl, in_cnt); /* copy all udp include source address to in_tbl[] */ + } +#endif /* LWIP_UDP */ + +#if LWIP_RAW + { + struct raw_pcb *pcb; + LWIP_IP4_MC_GET(pcb, raw_pcbs, MCAST_INCLUDE, in_tbl, in_cnt); /* copy all raw include source address to in_tbl[] */ + } +#endif /* LWIP_UDP */ + +#if LWIP_UDP + { + struct udp_pcb *pcb; + LWIP_IP4_MC_GET(pcb, udp_pcbs, MCAST_EXCLUDE, ex_tbl, ex_cnt); /* copy all udp exclude source address to ex_tbl[] */ + } +#endif /* LWIP_UDP */ + +#if LWIP_RAW + { + struct raw_pcb *pcb; + LWIP_IP4_MC_GET(pcb, raw_pcbs, MCAST_EXCLUDE, ex_tbl, ex_cnt); /* copy all raw exclude source address to ex_tbl[] */ + } +#endif /* LWIP_UDP */ + + if (ex_cnt) { /* at least have one exclude source address */ + *fmode = MCAST_EXCLUDE; + for (i = 0; i < ex_cnt; i++) { + ip4_addr_set(&addr, &ex_tbl[i]); + for (j = 0; j < in_cnt; j++) { + if (ip4_addr_cmp(&addr, &in_tbl[j])) { /* check exclude conflict with include table */ + ip4_addr_set_any(&ex_tbl[i]); /* remove from exclude table */ + break; + } + } + } + + for (i = 0, cnt = 0; i < ex_cnt; i++) { + if (!ip4_addr_isany(&ex_tbl[i])) { + ip4_addr_set(&addr_array[cnt], &ex_tbl[i]); + cnt++; + } + } + + } else if (in_cnt) { /* at least have one include source address */ + *fmode = MCAST_INCLUDE; + for (i = 0; i < in_cnt; i++) { + ip4_addr_set(&addr_array[i], &in_tbl[i]); + } + cnt = i; + + } else { + if (match) { /* at least have one pcb matched */ + *fmode = MCAST_EXCLUDE; + } else { /* no match! */ + *fmode = MCAST_INCLUDE; + } + cnt = 0; + } + + return (cnt); +} + +/** + * ipv4 multicast filter source address interest (use ip4_addr_p_t for IGMPv3 speedup) + */ +u8_t +mcast_ip4_filter_interest(struct netif *netif, const ip4_addr_t *multi_addr, const ip4_addr_p_t src_addr[], u16_t arr_cnt) +{ + static ip4_addr_p_t ip_tbl[LWIP_MCAST_SRC_TBL_SIZE]; + u16_t i, j, cnt; + u8_t fmode; + + cnt = mcast_ip4_filter_info(netif, multi_addr, ip_tbl, LWIP_MCAST_SRC_TBL_SIZE, &fmode); + if (fmode == MCAST_EXCLUDE) { + for (i = 0; i < cnt; i++) { + for (j = 0; j < arr_cnt; j++) { + if (ip4_addr_cmp(&src_addr[j], &ip_tbl[i])) { + return 0; + } + } + } + return 1; + + } else { + for (i = 0; i < cnt; i++) { + for (j = 0; j < arr_cnt; j++) { + if (ip4_addr_cmp(&src_addr[j], &ip_tbl[i])) { + return 1; + } + } + } + return 0; + } +} +#endif /* LWIP_IGMP_V3 */ +#endif /* LWIP_IPV4 && LWIP_IGMP */ + +#if (LWIP_IPV4 && LWIP_IGMP) || (LWIP_IPV6 && LWIP_IPV6_MLD) +/** Join a multicast group (Can with a source specified) + * + * @param ipmc multicast filter control block + * @param netif the network interface which should join a new group. + * @param multi_addr the ipv6 address of the group to join + * @param src_addr multicast source address (can be NULL) + * @return lwIP error definitions + */ +err_t +mcast_join_netif(struct ip_mc *ipmc, struct netif *netif, const ip_addr_t *multi_addr, const ip_addr_t *src_addr) +{ +#if LWIP_UDP + if (ipmc->proto == IPPROTO_UDP) { + err_t err; + struct udp_pcb *pcb; + /* prepare UDP pcb to udp_pcbs list */ + pcb = (struct udp_pcb *)((u8_t *)ipmc - offsetof(struct udp_pcb, ipmc)); + if (pcb->local_port == 0) { + err = udp_bind(pcb, &pcb->local_ip, pcb->local_port); + if (err != ERR_OK) { + LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("mcast_join_netif: forced port bind failed\n")); + return err; + } + } + } +#endif /* LWIP_UDP */ + +#if LWIP_IPV4 && LWIP_IGMP + if (IP_IS_V4(multi_addr)) { + struct ip4_mc *mc; + struct igmp_src *src; + + mc = mcast_ip4_mc_find(ipmc, netif, ip_2_ip4(multi_addr), NULL); + if (mc) { + if (src_addr) { + if ((mc->fmode == MCAST_EXCLUDE) && (mc->src)) { + return ERR_VAL; /* filter mode not include mode */ + } + src = mcast_ip4_mc_src_find(mc, ip_2_ip4(src_addr), NULL); + if (src) { + return ERR_ALREADY; /* already in source list */ + } + + src = (struct igmp_src *)mem_malloc(sizeof(struct igmp_src)); + if (src == NULL) { + return ERR_MEM; /* no memory */ + } + ip4_addr_set(&src->src_addr, ip_2_ip4(src_addr)); + src->next = mc->src; + mc->src = src; + mc->fmode = MCAST_INCLUDE; /* change to include mode */ + IP4_MC_TRIGGER_CALL(netif, ip_2_ip4(multi_addr)); /* trigger a report */ + } + return ERR_OK; + } + + mc = (struct ip4_mc *)mem_malloc(sizeof(struct ip4_mc)); /* Make a new mc */ + if (mc == NULL) { + igmp_leavegroup_netif(netif, ip_2_ip4(multi_addr)); + return ERR_MEM; /* no memory */ + } + ip4_addr_set(&mc->if_addr, netif_ip4_addr(netif)); + ip4_addr_set(&mc->multi_addr, ip_2_ip4(multi_addr)); + + if (src_addr) { /* have a source specified */ + mc->fmode = MCAST_INCLUDE; + src = (struct igmp_src *)mem_malloc(sizeof(struct igmp_src)); + if (src == NULL) { + mem_free(mc); + return ERR_MEM; /* no memory */ + } + ip4_addr_set(&src->src_addr, ip_2_ip4(src_addr)); + src->next = NULL; + mc->src = src; + + } else { + mc->fmode = MCAST_EXCLUDE; /* no source specified */ + mc->src = NULL; + } + + mc->next = ipmc->mc4; + ipmc->mc4 = mc; + igmp_joingroup_netif(netif, ip_2_ip4(multi_addr)); + } else {} +#endif /* LWIP_IPV4 && LWIP_IGMP */ + return ERR_OK; +} + +/** Join a multicast group (Can with a source specified) + * + * @param ipmc multicast filter control block + * @param if_addr the network interface address. + * @param multi_addr the ipv6 address of the group to join + * @param src_addr multicast source address (can be NULL) + * @return lwIP error definitions + */ +err_t +mcast_join_group(struct ip_mc *ipmc, const ip_addr_t *if_addr, const ip_addr_t *multi_addr, const ip_addr_t *src_addr) +{ + err_t err = ERR_VAL; /* no matching interface */ + +#if LWIP_IPV4 && LWIP_IGMP + if (IP_IS_V4(multi_addr)) { + struct netif *netif; + + NETIF_FOREACH(netif) { + if ((netif->flags & NETIF_FLAG_IGMP) && ((ip4_addr_isany(ip_2_ip4(if_addr)) || ip4_addr_cmp(netif_ip4_addr(netif), ip_2_ip4(if_addr))))) { + err = mcast_join_netif(ipmc, netif, multi_addr, src_addr); + if (err != ERR_OK) { + return (err); + } + } + } + } else {} +#endif /* LWIP_IPV4 && LWIP_IGMP */ + return err; +} + +/** Leave or drop a source from group on a network interface. + * + * @param ipmc multicast filter control block + * @param netif the network interface which should leave group. + * @param multi_addr the address of the group to leave + * @param src_addr multicast source address + * @return lwIP error definitions + */ +err_t +mcast_leave_netif(struct ip_mc *ipmc, struct netif *netif, const ip_addr_t *multi_addr, const ip_addr_t *src_addr) +{ +#if LWIP_IPV4 && LWIP_IGMP + if (IP_IS_V4(multi_addr)) { + struct ip4_mc *mc_prev; + struct ip4_mc *mc; + struct igmp_src *src_prev; + struct igmp_src *src; + + mc = mcast_ip4_mc_find(ipmc, netif, ip_2_ip4(multi_addr), &mc_prev); + if (mc == NULL) { + return ERR_VAL; + } + + if (src_addr) { + if ((mc->fmode == MCAST_EXCLUDE) && (mc->src)) { + return ERR_VAL; /* drop source membership must in include mode */ + } + + src = mcast_ip4_mc_src_find(mc, ip_2_ip4(src_addr), &src_prev); + if (src) { + if (src_prev) { + src_prev->next = src->next; + } else { + mc->src = src->next; + } + mem_free(src); + } else { + return ERR_VAL; + } + if (mc->src) { + IP4_MC_TRIGGER_CALL(netif, ip_2_ip4(multi_addr)); /* trigger a report */ + return ERR_OK; + } + } else { /* we want drop this group */ + mcast_ip4_mc_src_remove(mc->src); + } + + igmp_leavegroup_netif(netif, ip_2_ip4(multi_addr)); + if (mc_prev) { + mc_prev->next = mc->next; + } else { + ipmc->mc4 = mc->next; + } + mem_free(mc); + } else {} +#endif /* LWIP_IPV4 && LWIP_IGMP */ + return ERR_OK; +} + +/** Leave or drop a source from group on a network interface. + * + * @param ipmc multicast filter control block + * @param if_addr the network interface address. + * @param multi_addr the address of the group to leave + * @param src_addr multicast source address + * @return lwIP error definitions + */ +err_t +mcast_leave_group(struct ip_mc *ipmc, const ip_addr_t *if_addr, const ip_addr_t *multi_addr, const ip_addr_t *src_addr) +{ + err_t res, err = ERR_VAL; /* no matching interface */ + +#if LWIP_IPV4 && LWIP_IGMP + if (IP_IS_V4(multi_addr)) { + struct netif *netif; + + NETIF_FOREACH(netif) { + if ((netif->flags & NETIF_FLAG_IGMP) && ((ip4_addr_isany(ip_2_ip4(if_addr)) || ip4_addr_cmp(netif_ip4_addr(netif), ip_2_ip4(if_addr))))) { + res = mcast_leave_netif(ipmc, netif, multi_addr, src_addr); + if (err != ERR_OK) { + err = res; + } + } + } + } else {} +#endif /* LWIP_IPV4 && LWIP_IGMP */ + return err; +} + +/** Add a block source address to a multicast group + * + * @param ipmc multicast filter control block + * @param netif the network interface which group we already join. + * @param multi_addr the address of the group to add source + * @param blk_addr block multicast source address + * @return lwIP error definitions + */ +err_t +mcast_block_netif(struct ip_mc *ipmc, struct netif *netif, const ip_addr_t *multi_addr, const ip_addr_t *blk_addr) +{ +#if LWIP_IPV4 && LWIP_IGMP + if (IP_IS_V4(multi_addr)) { + struct ip4_mc *mc; + struct igmp_src *src; + + mc = mcast_ip4_mc_find(ipmc, netif, ip_2_ip4(multi_addr), NULL); + if (mc == NULL) { + return ERR_VAL; + } + if (mc->fmode != MCAST_EXCLUDE) { /* we must in exclude mode */ + return ERR_VAL; + } + + src = mcast_ip4_mc_src_find(mc, ip_2_ip4(blk_addr), NULL); + if (src == NULL) { + src = (struct igmp_src *)mem_malloc(sizeof(struct igmp_src)); + if (src == NULL) { + return ERR_MEM; + } + ip4_addr_set(&src->src_addr, ip_2_ip4(blk_addr)); + src->next = mc->src; + mc->src = src; + IP4_MC_TRIGGER_CALL(netif, ip_2_ip4(multi_addr)); /* trigger a report */ + return ERR_OK; + } + } else {} +#endif /* LWIP_IPV4 && LWIP_IGMP */ + return EADDRINUSE; +} + +/** Add a block source address to a multicast group + * + * @param ipmc multicast filter control block + * @param if_addr the network interface address. + * @param multi_addr the address of the group to add source + * @param blk_addr block multicast source address + * @return lwIP error definitions + */ +err_t +mcast_block_group(struct ip_mc *ipmc, const ip_addr_t *if_addr, const ip_addr_t *multi_addr, const ip_addr_t *blk_addr) +{ + err_t err = ERR_VAL; /* no matching interface */ + +#if LWIP_IPV4 && LWIP_IGMP + if (IP_IS_V4(multi_addr)) { + struct netif *netif; + + NETIF_FOREACH(netif) { + if ((netif->flags & NETIF_FLAG_IGMP) && ((ip4_addr_isany(ip_2_ip4(if_addr)) || ip4_addr_cmp(netif_ip4_addr(netif), ip_2_ip4(if_addr))))) { + err = mcast_block_netif(ipmc, netif, multi_addr, blk_addr); + if (err != ERR_OK) { + return (err); + } + } + } + } else {} +#endif /* LWIP_IPV4 && LWIP_IGMP */ + return err; +} + +/** Remove a block source address from a multicast group + * + * @param ipmc multicast filter control block + * @param netif the network interface which group we already join. + * @param multi_addr the address of the group to add source + * @param unblk_addr unblock multicast source address + * @return lwIP error definitions + */ +err_t +mcast_unblock_netif(struct ip_mc *ipmc, struct netif *netif, const ip_addr_t *multi_addr, const ip_addr_t *unblk_addr) +{ +#if LWIP_IPV4 && LWIP_IGMP + if (IP_IS_V4(multi_addr)) { + struct ip4_mc *mc; + struct igmp_src *src_prev; + struct igmp_src *src; + + mc = mcast_ip4_mc_find(ipmc, netif, ip_2_ip4(multi_addr), NULL); + if (mc == NULL) { + return ERR_VAL; + } + if (mc->fmode != MCAST_EXCLUDE) { /* we must in exclude mode */ + return ERR_VAL; + } + + src = mcast_ip4_mc_src_find(mc, ip_2_ip4(unblk_addr), &src_prev); + if (src == NULL) { + return ERR_VAL; + } + if (src_prev) { + src_prev->next = src->next; + } else { + mc->src = src->next; + } + mem_free(src); + IP4_MC_TRIGGER_CALL(netif, ip_2_ip4(multi_addr)); /* trigger a report */ + } else {} +#endif /* LWIP_IPV4 && LWIP_IGMP */ + return ERR_OK; +} + +/** Remove a block source address from a multicast group + * + * @param ipmc multicast filter control block + * @param if_addr the network interface address. + * @param multi_addr the address of the group to add source + * @param unblk_addr unblock multicast source address + * @return lwIP error definitions + */ +err_t +mcast_unblock_group(struct ip_mc *ipmc, const ip_addr_t *if_addr, const ip_addr_t *multi_addr, const ip_addr_t *unblk_addr) +{ + err_t res, err = ERR_VAL; /* no matching interface */ + +#if LWIP_IPV4 && LWIP_IGMP + if (IP_IS_V4(multi_addr)) { + struct netif *netif; + + NETIF_FOREACH(netif) { + if ((netif->flags & NETIF_FLAG_IGMP) && ((ip4_addr_isany(ip_2_ip4(if_addr)) || ip4_addr_cmp(netif_ip4_addr(netif), ip_2_ip4(if_addr))))) { + res = mcast_unblock_netif(ipmc, netif, multi_addr, unblk_addr); + if (err != ERR_OK) { + err = res; + } + } + } + } else {} +#endif /* LWIP_IPV4 && LWIP_IGMP */ + return err; +} + +#endif /* (LWIP_IPV4 && LWIP_IGMP) || (LWIP_IPV6 && LWIP_IPV6_MLD) */ + +#endif /* LWIP_UDP || LWIP_RAW */ diff -Nur lwip-2.2.0init/src/core/raw.c lwip-2.2.0/src/core/raw.c --- lwip-2.2.0init/src/core/raw.c 2024-04-02 19:14:40.969584000 +0800 +++ lwip-2.2.0/src/core/raw.c 2024-04-02 19:15:03.867584000 +0800 @@ -63,10 +63,10 @@ #include /** The list of RAW PCBs */ -static struct raw_pcb *raw_pcbs; +struct raw_pcb *raw_pcbs; static u8_t -raw_input_local_match(struct raw_pcb *pcb, u8_t broadcast) +raw_input_local_match(struct raw_pcb *pcb, u8_t broadcast, struct netif *inp) { LWIP_UNUSED_ARG(broadcast); /* in IPv6 only case */ @@ -88,6 +88,12 @@ } #endif /* LWIP_IPV4 && LWIP_IPV6 */ +#if (LWIP_IPV4 && LWIP_IGMP) || (LWIP_IPV6 && LWIP_IPV6_MLD) + if (ip_addr_ismulticast(ip_current_dest_addr())) { + return mcast_input_local_match(&pcb->ipmc, inp); + } +#endif /* (LWIP_IPV4 && LWIP_IGMP) || (LWIP_IPV6 && LWIP_IPV6_MLD) */ + /* Only need to check PCB if incoming IP version matches PCB IP version */ if (IP_ADDR_PCB_VERSION_MATCH_EXACT(pcb, ip_current_dest_addr())) { #if LWIP_IPV4 @@ -164,9 +170,20 @@ /* loop through all raw pcbs until the packet is eaten by one */ /* this allows multiple pcbs to match against the packet by design */ while (pcb != NULL) { - if ((pcb->protocol == proto) && raw_input_local_match(pcb, broadcast) && + if ((pcb->protocol == proto) && raw_input_local_match(pcb, broadcast, inp) && (((pcb->flags & RAW_FLAGS_CONNECTED) == 0) || ip_addr_eq(&pcb->remote_ip, ip_current_src_addr()))) { + if (pcb->min_ttl) { + if (ip_current_is_v6()) { + if (pcb->min_ttl > IP6H_HOPLIM(ip6_current_header())) { + continue; + } + } else { + if (pcb->min_ttl > IPH_TTL(ip4_current_header())) { + continue; + } + } + } /* receive callback function available? */ if (pcb->recv != NULL) { u8_t eaten; @@ -371,7 +388,26 @@ /* For multicast-destined packets, use the user-provided interface index to * determine the outgoing interface, if an interface index is set and a * matching netif can be found. Otherwise, fall back to regular routing. */ - netif = netif_get_by_index(pcb->mcast_ifindex); + if (pcb->mcast_ifindex != NETIF_NO_INDEX) { + netif = netif_get_by_index(pcb->mcast_ifindex); + } +#if LWIP_IPV4 + else +#if LWIP_IPV6 + if (IP_IS_V4(ipaddr)) +#endif /* LWIP_IPV6 */ + { + /* 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->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(&pcb->local_ip), &pcb->mcast_ip4); + } + } +#endif /* LWIP_IPV4 */ } if (netif == NULL) @@ -450,6 +486,16 @@ if (p->len < header_size) { return ERR_VAL; } +#if CHECKSUM_GEN_IP + if (IP_IS_V4(dst_ip)) { + struct ip_hdr *iphdr = (struct ip_hdr *)p->payload; + if (IPH_CHKSUM(iphdr) == 0) { + IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_IP) { + IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IPH_HL(iphdr) << 2)); + } + } + } +#endif /* CHECKSUM_GEN_IP */ /* @todo multicast loop support, if at all desired for this scenario.. */ NETIF_SET_HINTS(netif, &pcb->netif_hints); err = ip_output_if_hdrincl(p, src_ip, dst_ip, netif); @@ -563,6 +609,11 @@ { struct raw_pcb *pcb2; LWIP_ASSERT_CORE_LOCKED(); + +#if (LWIP_IPV4 && LWIP_IGMP) || (LWIP_IPV6 && LWIP_IPV6_MLD) + mcast_pcb_remove(&pcb->ipmc); +#endif /* (LWIP_IPV4 && LWIP_IGMP) || (LWIP_IPV6 && LWIP_IPV6_MLD) */ + /* pcb to be removed is first in list? */ if (raw_pcbs == pcb) { /* make list start at 2nd pcb */ @@ -611,6 +662,9 @@ raw_set_multicast_ttl(pcb, RAW_TTL); #endif /* LWIP_MULTICAST_TX_OPTIONS */ pcb_tci_init(pcb); +#if (LWIP_IPV4 && LWIP_IGMP) || (LWIP_IPV6 && LWIP_IPV6_MLD) + pcb->ipmc.proto = IPPROTO_RAW; +#endif /* (LWIP_IPV4 && LWIP_IGMP) || (LWIP_IPV6 && LWIP_IPV6_MLD) */ pcb->next = raw_pcbs; raw_pcbs = pcb; } diff -Nur lwip-2.2.0init/src/core/udp.c lwip-2.2.0/src/core/udp.c --- lwip-2.2.0init/src/core/udp.c 2024-04-02 19:14:40.969584000 +0800 +++ lwip-2.2.0/src/core/udp.c 2024-04-02 19:15:03.868584000 +0800 @@ -205,6 +205,12 @@ return 1; } +#if (LWIP_IPV4 && LWIP_IGMP) || (LWIP_IPV6 && LWIP_IPV6_MLD) + if (ip_addr_ismulticast(ip_current_dest_addr())) { + return mcast_input_local_match(&pcb->ipmc, inp); + } +#endif /* (LWIP_IPV4 && LWIP_IGMP) || (LWIP_IPV6 && LWIP_IPV6_MLD) */ + /* Only need to check PCB if incoming IP version matches PCB IP version */ if (IP_ADDR_PCB_VERSION_MATCH_EXACT(pcb, ip_current_dest_addr())) { #if LWIP_IPV4 @@ -347,6 +353,21 @@ if ((pcb->remote_port == src) && (ip_addr_isany_val(pcb->remote_ip) || ip_addr_eq(&pcb->remote_ip, ip_current_src_addr()))) { + if (pcb->min_ttl) { + if (ip_current_is_v6()) { + if (pcb->min_ttl > IP6H_HOPLIM(ip6_current_header())) { + UDP_STATS_INC(udp.drop); + pbuf_free(p); + goto end; + } + } else { + if (pcb->min_ttl > IPH_TTL(ip4_current_header())) { + UDP_STATS_INC(udp.drop); + pbuf_free(p); + goto end; + } + } + } /* the first fully matching PCB */ if (prev != NULL) { /* move the pcb to the front of udp_pcbs so that is @@ -1321,6 +1342,10 @@ LWIP_ERROR("udp_remove: invalid pcb", pcb != NULL, return); +#if (LWIP_IPV4 && LWIP_IGMP) || (LWIP_IPV6 && LWIP_IPV6_MLD) + mcast_pcb_remove(&pcb->ipmc); +#endif /* (LWIP_IPV4 && LWIP_IGMP) || (LWIP_IPV6 && LWIP_IPV6_MLD) */ + mib2_udp_unbind(pcb); /* pcb to be removed is first in list? */ if (udp_pcbs == pcb) { @@ -1375,6 +1400,9 @@ udp_set_multicast_ttl(pcb, UDP_TTL); #endif /* LWIP_MULTICAST_TX_OPTIONS */ pcb_tci_init(pcb); +#if (LWIP_IPV4 && LWIP_IGMP) || (LWIP_IPV6 && LWIP_IPV6_MLD) + pcb->ipmc.proto = IPPROTO_UDP; +#endif /* (LWIP_IPV4 && LWIP_IGMP) || (LWIP_IPV6 && LWIP_IPV6_MLD) */ } return pcb; } diff -Nur lwip-2.2.0init/src/include/lwip/api.h lwip-2.2.0/src/include/lwip/api.h --- lwip-2.2.0init/src/include/lwip/api.h 2024-04-02 19:14:40.965584000 +0800 +++ lwip-2.2.0/src/include/lwip/api.h 2024-04-02 19:15:03.868584000 +0800 @@ -89,6 +89,8 @@ #if LWIP_NETBUF_RECVINFO /** Received packet info will be recorded for this netconn */ #define NETCONN_FLAG_PKTINFO 0x40 +/** Received hoplim will be recorded for this netconn */ +#define NETCONN_FLAG_HOPLIM 0x100 #endif /* LWIP_NETBUF_RECVINFO */ /** A FIN has been received but not passed to the application yet */ #define NETCONN_FIN_RX_PENDING 0x80 @@ -309,7 +311,7 @@ s16_t linger; #endif /* LWIP_SO_LINGER */ /** flags holding more netconn-internal state, see NETCONN_FLAG_* defines */ - u8_t flags; + u16_t flags; #if LWIP_TCP /** TCP: when data passed to netconn_write doesn't fit into the send buffer, this temporarily stores the message. diff -Nur lwip-2.2.0init/src/include/lwip/igmp.h lwip-2.2.0/src/include/lwip/igmp.h --- lwip-2.2.0init/src/include/lwip/igmp.h 2024-04-02 19:14:40.964584000 +0800 +++ lwip-2.2.0/src/include/lwip/igmp.h 2024-04-02 19:15:03.868584000 +0800 @@ -51,6 +51,13 @@ extern "C" { #endif +/* Multicast filter support */ +struct igmp_src { + struct igmp_src *next; + /** the source address */ + ip4_addr_t src_addr; +}; + /* IGMP timer */ #define IGMP_TMR_INTERVAL 100 /* Milliseconds */ #define IGMP_V1_DELAYING_MEMBER_TMR (1000/IGMP_TMR_INTERVAL) @@ -60,6 +67,10 @@ #define IGMP_DEL_MAC_FILTER NETIF_DEL_MAC_FILTER #define IGMP_ADD_MAC_FILTER NETIF_ADD_MAC_FILTER +#if LWIP_IGMP_V3 +#define IGMP_FMODE_INIT 2 /* Not MCAST_INCLUDE or MCAST_EXCLUDE */ +#endif /* LWIP_IGMP_V3 */ + /** * igmp group structure - there is * a list of groups for each interface @@ -84,6 +95,16 @@ u16_t timer; /** counter of simultaneous uses */ u8_t use; +#if LWIP_IGMP_V3 + /** Last report fmode */ + u8_t v3_fmode; + /** signifies we were the last person to report */ + u8_t v3_last_reporter_flag; + /** current state of the group */ + u8_t v3_group_state; + /** timer for reporting, negative is OFF */ + u16_t v3_timer; +#endif /* LWIP_IGMP_V3 */ }; /* Prototypes */ @@ -106,6 +127,20 @@ */ #define netif_igmp_data(netif) ((struct igmp_group *)netif_get_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_IGMP)) +/** + * ipv4 multicast filter trigger function + */ +#if LWIP_IGMP_V3 + void igmp_v3_trigger(struct netif *netif, const ip4_addr_t *groupaddr); + + /* IGMPv3 must install a trigger function to report multicast filter changes */ + +#define IP4_MC_TRIGGER_CALL(netif, multi_addr) igmp_v3_trigger(netif, multi_addr) +#else +#define IP4_MC_TRIGGER_CALL(netif, multi_addr) +#endif /* !LWIP_IGMP_V3 */ + + #ifdef __cplusplus } #endif diff -Nur lwip-2.2.0init/src/include/lwip/ip.h lwip-2.2.0/src/include/lwip/ip.h --- lwip-2.2.0init/src/include/lwip/ip.h 2024-04-02 19:14:40.965584000 +0800 +++ lwip-2.2.0/src/include/lwip/ip.h 2024-04-02 19:15:03.868584000 +0800 @@ -85,7 +85,9 @@ /* Type Of Service */ \ u8_t tos; \ /* Time To Live */ \ - u8_t ttl \ + u8_t ttl; \ + /* min TTL */ \ + u8_t min_ttl \ /* link layer address resolution hint */ \ IP_PCB_NETIFHINT diff -Nur lwip-2.2.0init/src/include/lwip/mcast.h lwip-2.2.0/src/include/lwip/mcast.h --- lwip-2.2.0init/src/include/lwip/mcast.h 1970-01-01 08:00:00.000000000 +0800 +++ lwip-2.2.0/src/include/lwip/mcast.h 2024-04-02 19:15:03.868584000 +0800 @@ -0,0 +1,117 @@ +/** + * @file + * Multicast filter module\n + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Kylinos Technologies + * + */ +#ifndef LWIP_HDR_MCAST_H +#define LWIP_HDR_MCAST_H + +#include "lwip/opt.h" + +#if LWIP_UDP || LWIP_RAW /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/def.h" +#include "lwip/ip.h" +#include "lwip/ip_addr.h" +#include "lwip/ip6_addr.h" +#include "lwip/netif.h" +#include "lwip/igmp.h" +#include "lwip/mld6.h" +#include "lwip/prot/ip4.h" +#include "lwip/prot/ip6.h" + + +#if LWIP_IPV4 && LWIP_IGMP +/** the IPv4 multicast filter */ +struct ip4_mc { + struct ip4_mc *next; + /** the interface address */ + ip4_addr_t if_addr; + /** the group address */ + ip4_addr_t multi_addr; + /** the source address list filter mode 0: EXCLUDE 1: INCLUDE */ + u8_t fmode; + /** the source address list */ + struct igmp_src *src; +}; + +/** The list of ip4_mc. */ +#define IP4_MC_FOREACH(ipmc, mc) \ + for ((mc) = (ipmc)->mc4; (mc) != NULL; (mc) = (mc)->next) +#define IP4_MC_SRC_FOREACH(mc, src) \ + for ((src) = (mc)->src; (src) != NULL; (src) = (src)->next) +#endif /* LWIP_IPV4 && LWIP_IGMP */ + + +#if (LWIP_IPV4 && LWIP_IGMP) || (LWIP_IPV6 && LWIP_IPV6_MLD) +/* multicast filter control block */ +struct ip_mc { +#if !LWIP_SOCKET +#define IPPROTO_UDP 17 +#define IPPROTO_RAW 255 +#endif /* !LWIP_SOCKET */ + u8_t proto; /* IPPROTO_UDP or IPPROTO_RAW */ +#if LWIP_IPV4 && LWIP_IGMP + struct ip4_mc *mc4; +#endif /* LWIP_IPV4 && LWIP_IGMP */ +}; + +#if LWIP_IPV4 && LWIP_IGMP && LWIP_IGMP_V3 +/* IGMPv3 use the following function to get specified group of total multicast filter source address array */ +u16_t mcast_ip4_filter_info(struct netif *netif, const ip4_addr_t *multi_addr, ip4_addr_p_t addr_array[], u16_t arr_cnt, u8_t *fmode); +u8_t mcast_ip4_filter_interest(struct netif *netif, const ip4_addr_t *multi_addr, const ip4_addr_p_t src_addr[], u16_t arr_cnt); +#endif /* LWIP_IPV4 && LWIP_IGMP && LWIP_IGMP_V3 */ + +/* UDP or RAW use the following functions */ +void mcast_pcb_remove(struct ip_mc *ipmc); +u8_t mcast_input_local_match(struct ip_mc *ipmc, struct netif *inp); + +/* The following functions is for Non-Socket API user */ +err_t mcast_join_netif(struct ip_mc *ipmc, struct netif *netif, const ip_addr_t *multi_addr, const ip_addr_t *src_addr); +err_t mcast_join_group(struct ip_mc *ipmc, const ip_addr_t *if_addr, const ip_addr_t *multi_addr, const ip_addr_t *src_addr); +err_t mcast_leave_netif(struct ip_mc *ipmc, struct netif *netif, const ip_addr_t *multi_addr, const ip_addr_t *src_addr); +err_t mcast_leave_group(struct ip_mc *ipmc, const ip_addr_t *if_addr, const ip_addr_t *multi_addr, const ip_addr_t *src_addr); +err_t mcast_block_netif(struct ip_mc *ipmc, struct netif *netif, const ip_addr_t *multi_addr, const ip_addr_t *blk_addr); +err_t mcast_block_group(struct ip_mc *ipmc, const ip_addr_t *if_addr, const ip_addr_t *multi_addr, const ip_addr_t *blk_addr); +err_t mcast_unblock_netif(struct ip_mc *ipmc, struct netif *netif, const ip_addr_t *multi_addr, const ip_addr_t *unblk_addr); +err_t mcast_unblock_group(struct ip_mc *ipmc, const ip_addr_t *if_addr, const ip_addr_t *multi_addr, const ip_addr_t *unblk_addr); + +struct ip4_mc *mcast_ip4_mc_find(struct ip_mc *ipmc, struct netif *netif, const ip4_addr_t *multi_addr, struct ip4_mc **mc_prev); +void mcast_ip4_mc_src_remove(struct igmp_src *src); + +#endif /* (LWIP_IPV4 && LWIP_IGMP) || (LWIP_IPV6 && LWIP_IPV6_MLD) */ + +#endif /* LWIP_UDP || LWIP_RAW */ + +#endif /* LWIP_HDR_MCAST_H */ diff -Nur lwip-2.2.0init/src/include/lwip/netbuf.h lwip-2.2.0/src/include/lwip/netbuf.h --- lwip-2.2.0init/src/include/lwip/netbuf.h 2024-04-02 19:14:40.964584000 +0800 +++ lwip-2.2.0/src/include/lwip/netbuf.h 2024-04-02 19:15:03.868584000 +0800 @@ -55,6 +55,8 @@ #define NETBUF_FLAG_DESTADDR 0x01 /** This netbuf includes a checksum */ #define NETBUF_FLAG_CHKSUM 0x02 +/** This netbuf has hoplim set */ +#define NETBUF_FLAG_HOPLIM 0x80 /** "Network buffer" - contains data and addressing info */ struct netbuf { diff -Nur lwip-2.2.0init/src/include/lwip/opt.h lwip-2.2.0/src/include/lwip/opt.h --- lwip-2.2.0init/src/include/lwip/opt.h 2024-04-02 19:14:40.965584000 +0800 +++ lwip-2.2.0/src/include/lwip/opt.h 2024-04-02 19:15:03.868584000 +0800 @@ -1126,9 +1126,12 @@ #if !defined LWIP_IGMP || defined __DOXYGEN__ #define LWIP_IGMP 1 #endif + #if !LWIP_IPV4 #undef LWIP_IGMP #define LWIP_IGMP 0 +#undef LWIP_IGMP_V3 +#define LWIP_IGMP_V3 0 #endif /** * @} diff -Nur lwip-2.2.0init/src/include/lwip/prot/igmp.h lwip-2.2.0/src/include/lwip/prot/igmp.h --- lwip-2.2.0init/src/include/lwip/prot/igmp.h 2024-04-02 19:14:40.963584000 +0800 +++ lwip-2.2.0/src/include/lwip/prot/igmp.h 2024-04-02 19:15:03.868584000 +0800 @@ -49,6 +49,7 @@ */ #define IGMP_TTL 1 #define IGMP_MINLEN 8 +#define IGMP_V3_MINLEN 12 #define ROUTER_ALERT 0x9404U #define ROUTER_ALERTLEN 4 @@ -59,6 +60,7 @@ #define IGMP_V1_MEMB_REPORT 0x12 /* Ver. 1 membership report */ #define IGMP_V2_MEMB_REPORT 0x16 /* Ver. 2 membership report */ #define IGMP_LEAVE_GROUP 0x17 /* Leave-group message */ +#define IGMP_V3_MEMB_REPORT 0x22 /* Ver. 3 membership report */ /* Group membership states */ #define IGMP_GROUP_NON_MEMBER 0 @@ -83,6 +85,79 @@ # include "arch/epstruct.h" #endif +#if LWIP_IGMP_V3 /* RFC 3367 */ +/** + * IGMPv3 query packet format. + */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct igmp_v3_query { + PACK_STRUCT_FLD_8(u8_t igmp_v3_msgtype); + PACK_STRUCT_FLD_8(u8_t igmp_v3_maxresp); + PACK_STRUCT_FIELD(u16_t igmp_v3_checksum); + PACK_STRUCT_FLD_S(ip4_addr_p_t igmp_v3_group_address); + PACK_STRUCT_FLD_8(u8_t igmp_v3_sqrv); + PACK_STRUCT_FLD_8(u8_t igmp_v3_qqic); + PACK_STRUCT_FIELD(u16_t igmp_v3_srccnt); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#define IGMP_V3_QUERY_HLEN sizeof(struct igmp_v3_query) + +/** + * IGMPv3 report packet header format. + */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct igmp_v3_report { + PACK_STRUCT_FLD_8(u8_t igmp_v3_msgtype); + PACK_STRUCT_FLD_8(u8_t igmp_v3_reserve1); + PACK_STRUCT_FIELD(u16_t igmp_v3_checksum); + PACK_STRUCT_FIELD(u16_t igmp_v3_reserve2); + PACK_STRUCT_FIELD(u16_t igmp_v3_reccnt); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#define IGMP_V3_REPORT_HLEN sizeof(struct igmp_v3_report) + +#define IGMP_V3_REC_IS_IN 0x01 /* Type MODE_IS_INCLUDE */ +#define IGMP_V3_REC_IS_EX 0x02 /* Type MODE_IS_EXCLUDE */ +#define IGMP_V3_REC_TO_IN 0x03 /* Type CHANGE_TO_INCLUDE_MODE */ +#define IGMP_V3_REC_TO_EX 0x04 /* Type CHANGE_TO_EXCLUDE_MODE */ +#define IGMP_V3_REC_ALLOW 0x05 /* Type ALLOW_NEW_SOURCES */ +#define IGMP_V3_REC_BLOCK 0x06 /* Type BLOCK_OLD_SOURCES */ + +/** + * IGMPv3 report packet group record format. + */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct igmp_v3_record { + PACK_STRUCT_FLD_8(u8_t igmp_v3_rc_type); + PACK_STRUCT_FLD_8(u8_t igmp_v3_rc_auxlen); + PACK_STRUCT_FIELD(u16_t igmp_v3_rc_srccnt); + PACK_STRUCT_FLD_S(ip4_addr_p_t igmp_v3_rc_group_address); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#define IGMP_V3_RECORD_LEN(src_cnt) (sizeof(struct igmp_v3_record) + (src_cnt << 2)) +#endif /* LWIP_IGMP_V3 */ + #ifdef __cplusplus } #endif diff -Nur lwip-2.2.0init/src/include/lwip/raw.h lwip-2.2.0/src/include/lwip/raw.h --- lwip-2.2.0init/src/include/lwip/raw.h 2024-04-02 19:14:40.965584000 +0800 +++ lwip-2.2.0/src/include/lwip/raw.h 2024-04-02 19:15:03.869584000 +0800 @@ -47,6 +47,7 @@ #include "lwip/ip.h" #include "lwip/ip_addr.h" #include "lwip/ip6_addr.h" +#include "lwip/mcast.h" #ifdef __cplusplus extern "C" { @@ -82,12 +83,20 @@ u8_t flags; #if LWIP_MULTICAST_TX_OPTIONS +#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 */ +#if (LWIP_IPV4 && LWIP_IGMP) || (LWIP_IPV6 && LWIP_IPV6_MLD) + struct ip_mc ipmc; +#endif /* (LWIP_IPV4 && LWIP_IGMP) || (LWIP_IPV6 && LWIP_IPV6_MLD) */ + /** receive callback function */ raw_recv_fn recv; /* user-supplied argument for the recv callback */ @@ -98,6 +107,7 @@ u8_t chksum_reqd; #endif }; +extern struct raw_pcb *raw_pcbs; /* The following functions is the application layer interface to the RAW code. */ @@ -128,6 +138,10 @@ #define raw_new_ip6(proto) raw_new_ip_type(IPADDR_TYPE_V6, proto) #if LWIP_MULTICAST_TX_OPTIONS +#if LWIP_IPV4 +#define raw_set_multicast_netif_addr(pcb, ip4addr) ip4_addr_copy((pcb)->mcast_ip4, *(ip4addr)) +#define raw_get_multicast_netif_addr(pcb) (&(pcb)->mcast_ip4) +#endif /* LWIP_IPV4 */ #define raw_set_multicast_netif_index(pcb, idx) ((pcb)->mcast_ifindex = (idx)) #define raw_get_multicast_netif_index(pcb) ((pcb)->mcast_ifindex) #define raw_set_multicast_ttl(pcb, value) ((pcb)->mcast_ttl = (value)) diff -Nur lwip-2.2.0init/src/include/lwip/sockets.h lwip-2.2.0/src/include/lwip/sockets.h --- lwip-2.2.0init/src/include/lwip/sockets.h 2024-04-02 19:14:40.964584000 +0800 +++ lwip-2.2.0/src/include/lwip/sockets.h 2024-04-02 19:15:03.869584000 +0800 @@ -53,7 +53,7 @@ #include "lwip/inet.h" #include "lwip/errno.h" #include "lwip/api.h" - +#include "lwip/mcast.h" #include #ifdef __cplusplus @@ -304,6 +304,10 @@ #define IP_TOS 1 #define IP_TTL 2 #define IP_PKTINFO 8 +#define IP_MINTTL 99 +#define IP_HDRINCL 100 +#define IP_OPTIONS 101 + #if LWIP_TCP /* @@ -357,24 +361,6 @@ #endif /* GAZELLE_UDP_ENABLE */ #endif /* LWIP_MULTICAST_TX_OPTIONS */ -#if LWIP_IGMP -#if GAZELLE_UDP_ENABLE -#define IP_ADD_MEMBERSHIP 35 -#define IP_DROP_MEMBERSHIP 36 -int lwip_socket_get_multi_memberships(int s, ip4_addr_t *if_addr, ip4_addr_t *multi_addr); -#else -/* - * Options and types related to multicast membership - */ -#define IP_ADD_MEMBERSHIP 3 -#define IP_DROP_MEMBERSHIP 4 -#endif /* GAZELLE_UDP_ENABLE */ - -typedef struct ip_mreq { - struct in_addr imr_multiaddr; /* IP multicast address of group */ - struct in_addr imr_interface; /* local IP address of interface */ -} ip_mreq; -#endif /* LWIP_IGMP */ #if LWIP_IPV4 struct in_pktinfo { @@ -717,6 +703,112 @@ int lwip_fcntl(int s, int cmd, int val); #endif /* GAZELLE_ENABLE */ +#if (LWIP_IPV4 && LWIP_IGMP) || (LWIP_IPV6 && LWIP_IPV6_MLD) +/* Protocol Independent Multicast API [RFC3678] */ +#define MCAST_JOIN_GROUP 42 /* join an any-source group */ +#define MCAST_BLOCK_SOURCE 43 /* block a source */ +#define MCAST_UNBLOCK_SOURCE 44 /* unblock a source */ +#define MCAST_LEAVE_GROUP 45 /* leave all sources for group */ +#define MCAST_JOIN_SOURCE_GROUP 46 /* join a source-specific group */ +#define MCAST_LEAVE_SOURCE_GROUP 47 /* leave a single source */ +#define MCAST_MSFILTER 48 + +#define LWIP_MCAST_SRC_TBL_SIZE 32 + + +#if (LWIP_IPV4 && LWIP_IGMP) +#if GAZELLE_UDP_ENABLE +#define IP_ADD_MEMBERSHIP 35 +#define IP_DROP_MEMBERSHIP 36 +int lwip_socket_get_multi_memberships(int s, unsigned int if_idx, ip4_addr_t *multi_addr); +#else +/* + * Options and types related to multicast membership + */ +#define IP_ADD_MEMBERSHIP 3 +#define IP_DROP_MEMBERSHIP 4 +#endif /* GAZELLE_UDP_ENABLE */ + +typedef struct ip_mreq { + struct in_addr imr_multiaddr; /* IP multicast address of group */ + struct in_addr imr_interface; /* local IP address of interface */ +} ip_mreq; + +/* IPv4 Source Filter Multicast API [RFC3678] */ +#define IP_UNBLOCK_SOURCE 37 /* unblock a source */ +#define IP_BLOCK_SOURCE 38 /* block a source */ +#define IP_ADD_SOURCE_MEMBERSHIP 39 /* join a source-specific group */ +#define IP_DROP_SOURCE_MEMBERSHIP 40 /* drop a single source */ +#define IP_MSFILTER 41 /* set/get msfilter */ +/* + * Argument structure for IPv4 Multicast Source Filter APIs. [RFC3678] + */ +struct ip_mreq_source { + struct in_addr imr_multiaddr; /* IP multicast address of group */ + struct in_addr imr_sourceaddr; /* IP address of source */ + struct in_addr imr_interface; /* local IP address of interface */ +}; + +#define IP_MSFILTER_SIZE(numsrc) \ + (sizeof(struct ip_msfilter) - sizeof(struct in_addr) \ + + (numsrc) * sizeof(struct in_addr)) + +struct ip_msfilter { + struct in_addr imsf_multiaddr; + struct in_addr imsf_interface; + u32_t imsf_fmode; +#define MCAST_EXCLUDE 0 +#define MCAST_INCLUDE 1 + u32_t imsf_numsrc; + struct in_addr imsf_slist[1]; +}; +#endif /*(LWIP_IPV4 && LWIP_IGMP)*/ + +/* ++ * Argument structures for Protocol-Independent Multicast Source ++ * Filter APIs. [RFC3678] ++ */ +struct group_req { + u32_t gr_interface; /* interface index */ + struct sockaddr_storage gr_group; /* group address */ +}; + +struct group_source_req { + u32_t gsr_interface; /* interface index */ + struct sockaddr_storage gsr_group; /* group address */ + struct sockaddr_storage gsr_source; /* source address */ +}; + +#define GROUP_FILTER_SIZE(numsrc) \ + (sizeof(struct group_filter) - sizeof(struct sockaddr_storage) \ + + (numsrc) * sizeof(struct sockaddr_storage)) + +struct group_filter { + u32_t gf_interface; /* interface index */ + struct sockaddr_storage gf_group; /* multicast address */ + u32_t gf_fmode; /* filter mode */ + u32_t gf_numsrc; /* number of sources */ + struct sockaddr_storage gf_slist[1]; /* interface index */ +}; + +err_t mcast_set_msfilter_netif(struct ip_mc *ipmc, struct netif *netif, const ip_addr_t *multi_addr, const struct ip_msfilter *imsf); +err_t mcast_set_groupfilter_netif(struct ip_mc *ipmc, struct netif *netif, const ip_addr_t *multi_addr, const struct group_filter *gf); +err_t mcast_get_msfilter_netif(struct ip_mc *ipmc, struct netif *netif, const ip_addr_t *multi_addr, struct ip_msfilter *imsf, socklen_t *bufsz); +err_t mcast_get_groupfilter_netif(struct ip_mc *ipmc, struct netif *netif, const ip_addr_t *multi_addr, struct group_filter *gf, socklen_t *bufsz); + +int mcast_sock_add_drop_membership(int s, struct ip_mc *ipmc, int optname, const struct ip_mreq *imr); +int mcast_sock_add_drop_source_membership(int s, struct ip_mc *ipmc, int optname, const struct ip_mreq_source *imr); +int mcast_sock_block_unblock_source(struct ip_mc *ipmc, int optname, const struct ip_mreq_source *imr); +int mcast_sock_set_msfilter(struct ip_mc *ipmc, int optname, const struct ip_msfilter *imsf); +int mcast_sock_get_msfilter(struct ip_mc *ipmc, int optname, struct ip_msfilter *imsf, socklen_t *size); +int mcast_sock_join_leave_group(int s, struct ip_mc *ipmc, int optname, const struct group_req *gr); +int mcast_sock_join_leave_source_group(int s, struct ip_mc *ipmc, int optname, const struct group_source_req *gsr); +int mcast_sock_block_unblock_source_group(struct ip_mc *ipmc, int optname, const struct group_source_req *gsr); +int mcast_sock_set_groupfilter(struct ip_mc *ipmc, int optname, const struct group_filter *gf); +int mcast_sock_get_groupfilter(struct ip_mc *ipmc, int optname, struct group_filter *gf, socklen_t *size); + +#endif /*(LWIP_IPV4 && LWIP_IGMP) || (LWIP_IPV6 && LWIP_IPV6_MLD)*/ + const char *lwip_inet_ntop(int af, const void *src, char *dst, socklen_t size); int lwip_inet_pton(int af, const char *src, void *dst); diff -Nur lwip-2.2.0init/src/include/lwip/udp.h lwip-2.2.0/src/include/lwip/udp.h --- lwip-2.2.0init/src/include/lwip/udp.h 2024-04-02 19:14:40.964584000 +0800 +++ lwip-2.2.0/src/include/lwip/udp.h 2024-04-02 19:15:03.869584000 +0800 @@ -48,6 +48,7 @@ #include "lwip/ip.h" #include "lwip/ip6_addr.h" #include "lwip/prot/udp.h" +#include "lwip/mcast.h" #ifdef __cplusplus extern "C" { @@ -101,6 +102,10 @@ u8_t mcast_ttl; #endif /* LWIP_MULTICAST_TX_OPTIONS */ +#if (LWIP_IPV4 && LWIP_IGMP) || (LWIP_IPV6 && LWIP_IPV6_MLD) + struct ip_mc ipmc; +#endif /* (LWIP_IPV4 && LWIP_IGMP) || (LWIP_IPV6 && LWIP_IPV6_MLD) */ + #if LWIP_UDPLITE /** used for UDP_LITE only */ u16_t chksum_len_rx, chksum_len_tx; diff -Nur lwip-2.2.0init/src/include/lwipopts.h lwip-2.2.0/src/include/lwipopts.h --- lwip-2.2.0init/src/include/lwipopts.h 2024-04-02 19:14:40.968584000 +0800 +++ lwip-2.2.0/src/include/lwipopts.h 2024-04-02 19:16:42.759584000 +0800 @@ -282,4 +282,14 @@ #define LWIP_VLAN_PCP 1 #define VLAN_LEN 4 +/* + ------------------------------------ + ---------- multicast options ---------- + ------------------------------------ +*/ +/** + * LWIP_IGMP_V3==1: Turn on IGMPv3 module. + */ +#define LWIP_IGMP_V3 1 + #endif /* __LWIPOPTS_H__ */