代码拉取完成,页面将自动刷新
同步操作将从 src-openEuler/lwip 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
From bd5283f4d24be4b982652b38a680264b4a3efdf4 Mon Sep 17 00:00:00 2001
From: wanfeng <wanfeng@kylinos.cn>
Date: Mon, 8 Apr 2024 10:31:20 +0800
Subject: [PATCH] support mldv2
---
src/api/api_msg.c | 60 +++--
src/api/sockets.c | 262 +++++++++++++++++---
src/core/ipv6/icmp6.c | 3 +
src/core/ipv6/mld6.c | 360 +++++++++++++++++++++++++++-
src/core/mcast.c | 438 +++++++++++++++++++++++++++++++++-
src/core/udp.c | 12 +-
src/include/lwip/api.h | 1 +
src/include/lwip/mcast.h | 35 +++
src/include/lwip/mld6.h | 30 +++
src/include/lwip/netbuf.h | 3 +
src/include/lwip/opt.h | 8 +
src/include/lwip/prot/icmp6.h | 2 +
src/include/lwip/prot/mld6.h | 79 ++++++
src/include/lwip/sockets.h | 45 +++-
src/include/lwipopts.h | 5 +
15 files changed, 1249 insertions(+), 94 deletions(-)
diff --git a/src/api/api_msg.c b/src/api/api_msg.c
index 7cae567..f0a3e0b 100644
--- a/src/api/api_msg.c
+++ b/src/api/api_msg.c
@@ -202,7 +202,23 @@ recv_raw(void *arg, struct raw_pcb *pcb, struct pbuf *p,
if (IP_IS_V4(addr)) {
struct ip_hdr *iphdr = (struct ip_hdr *)p->payload;
ip_addr_copy_from_ip4(buf->toaddr, iphdr->dest);
- } else {}
+ } else
+#if LWIP_IPV6
+ {
+ struct ip6_hdr *ip6hdr = (struct ip6_hdr *)p->payload;
+ ip_addr_copy_from_ip6_packed(buf->toaddr, ip6hdr->dest);
+ }
+#endif /* LWIP_IPV6 */
+ }
+#if LWIP_IPV6
+ if (conn->flags & NETCONN_FLAG_HOPLIM) { /* IPV6_HOPLIMIT */
+ if (IP_IS_V6(addr)) {
+ struct ip6_hdr *ip6hdr = (struct ip6_hdr *)p->payload;
+ buf->flags |= NETBUF_FLAG_HOPLIM; /* IPV6_RECVHOPLIMIT (Hop limit) */
+ buf->hoplim = IP6H_HOPLIM(ip6hdr);
+ }
+ }
+#endif /* LWIP_IPV6 */
#endif /* LWIP_NETBUF_RECVINFO */
len = q->tot_len;
@@ -290,6 +306,15 @@ recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p,
ip_addr_set(&buf->toaddr, ip_current_dest_addr());
buf->toport_chksum = udphdr->dest;
}
+#if LWIP_IPV6
+ if (conn->flags & NETCONN_FLAG_HOPLIM) { /* IPV6_HOPLIMIT */
+ if (IP_IS_V6(addr)) {
+ struct ip6_hdr *ip6hdr = (struct ip6_hdr *)ip6_current_header();
+ buf->flags |= NETBUF_FLAG_HOPLIM; /* IPV6_RECVHOPLIMIT (Hop limit) */
+ buf->hoplim = IP6H_HOPLIM(ip6hdr);
+ }
+ }
+#endif /* LWIP_IPV6 */
#endif /* LWIP_NETBUF_RECVINFO */
}
@@ -2084,25 +2109,11 @@ lwip_netconn_do_join_leave_group(void *m)
#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
- if (NETCONNTYPE_ISIPV6(msg->conn->type)) {
- if (msg->msg.jl.join_or_leave == NETCONN_JOIN) {
- msg->err = mld6_joingroup(ip_2_ip6(API_EXPR_REF(msg->msg.jl.netif_addr)),
- ip_2_ip6(API_EXPR_REF(msg->msg.jl.multiaddr)));
- } else {
- 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 {
-#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
-#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 */
@@ -2146,30 +2157,15 @@ lwip_netconn_do_join_leave_group_netif(void *m)
#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
- if (NETCONNTYPE_ISIPV6(msg->conn->type)) {
- if (msg->msg.jl.join_or_leave == NETCONN_JOIN) {
- msg->err = mld6_joingroup_netif(netif,
- ip_2_ip6(API_EXPR_REF(msg->msg.jl.multiaddr)));
- } else {
- msg->err = mld6_leavegroup_netif(netif,
- ip_2_ip6(API_EXPR_REF(msg->msg.jl.multiaddr)));
- }
- } else
-#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
- {
-#if LWIP_IGMP
- if (msg->msg.jl.join_or_leave == NETCONN_JOIN) {
+ 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 */
- }
- } else if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_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);
diff --git a/src/api/sockets.c b/src/api/sockets.c
index 0caebdd..6b2f5ee 100644
--- a/src/api/sockets.c
+++ b/src/api/sockets.c
@@ -3936,34 +3936,43 @@ lwip_setsockopt_impl(int s, int level, int optname, const void *optval, socklen_
#if LWIP_IPV6_MLD
case IPV6_JOIN_GROUP:
case IPV6_LEAVE_GROUP: {
- /* If this is a TCP or a RAW socket, ignore these options. */
- err_t mld6_err;
- struct netif *netif;
- ip6_addr_t multi_addr;
- const struct ipv6_mreq *imr = (const struct ipv6_mreq *)optval;
- LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, struct ipv6_mreq, NETCONN_UDP);
- inet6_addr_to_ip6addr(&multi_addr, &imr->ipv6mr_multiaddr);
- LWIP_ASSERT("Invalid netif index", imr->ipv6mr_interface <= 0xFFu);
- netif = netif_get_by_index((u8_t)imr->ipv6mr_interface);
- if (netif == NULL) {
- err = EADDRNOTAVAIL;
- break;
+ LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, struct ipv6_mreq);
+#if LWIP_UDP
+ if (NETCONNTYPE_GROUPV6(netconn_type(sock->conn)) == NETCONN_UDP_IPV6) {
+ err = mcast_sock_ipv6_add_drop_membership(s, &sock->conn->pcb.udp->ipmc, optname, (const struct ipv6_mreq *)optval);
+ } else
+#endif /* LWIP_UDP */
+#if LWIP_RAW
+ if (NETCONNTYPE_GROUPV6(netconn_type(sock->conn)) == NETCONN_RAW_IPV6) {
+ err = mcast_sock_ipv6_add_drop_membership(s, &sock->conn->pcb.raw->ipmc, optname, (const struct ipv6_mreq *)optval);
+ } else
+#endif /* LWIP_RAW */
+ {
+ done_socket(sock);
+ return ENOPROTOOPT;
}
-
- if (optname == IPV6_JOIN_GROUP) {
- if (!lwip_socket_register_mld6_membership(s, imr->ipv6mr_interface, &multi_addr)) {
- /* cannot track membership (out of memory) */
- err = ENOMEM;
- mld6_err = ERR_OK;
- } else {
- mld6_err = mld6_joingroup_netif(netif, &multi_addr);
- }
- } else {
- mld6_err = mld6_leavegroup_netif(netif, &multi_addr);
- lwip_socket_unregister_mld6_membership(s, imr->ipv6mr_interface, &multi_addr);
+ }
+ break;
+ case MCAST_JOIN_GROUP:
+ case MCAST_LEAVE_GROUP: {
+ LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, struct group_req);
+ if (((const struct group_req *)optval)->gr_group.ss_family != AF_INET6) {
+ done_socket(sock);
+ return EINVAL;
}
- if (mld6_err != ERR_OK) {
- err = EADDRNOTAVAIL;
+#if LWIP_UDP
+ if (NETCONNTYPE_GROUPV6(netconn_type(sock->conn)) == NETCONN_UDP_IPV6) {
+ err = mcast_sock_join_leave_group(s, &sock->conn->pcb.udp->ipmc, optname, (const struct group_req *)optval);
+ } else
+#endif /* LWIP_UDP */
+#if LWIP_RAW
+ if (NETCONNTYPE_GROUPV6(netconn_type(sock->conn)) == NETCONN_RAW_IPV6) {
+ err = mcast_sock_join_leave_group(s, &sock->conn->pcb.raw->ipmc, optname, (const struct group_req *)optval);
+ } else
+#endif /* LWIP_RAW */
+ {
+ done_socket(sock);
+ return ENOPROTOOPT;
}
}
break;
@@ -4486,17 +4495,13 @@ lwip_socket_register_mld6_membership(int s, unsigned int if_idx, const ip6_addr_
if (!sock) {
return 0;
}
-
SYS_ARCH_DECL_PROTECT(lev);
SYS_ARCH_PROTECT(lev);
+#if GAZELLE_ENABLE
+ i = s;
+#else
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;
- }
-
+#endif
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;
@@ -4504,7 +4509,9 @@ lwip_socket_register_mld6_membership(int s, unsigned int if_idx, const ip6_addr_
done_socket(sock);
return 1;
}
+#if !GAZELLE_ENABLE
}
+#endif
SYS_ARCH_UNPROTECT(lev);
done_socket(sock);
return 0;
@@ -4524,19 +4531,26 @@ lwip_socket_unregister_mld6_membership(int s, unsigned int if_idx, const ip6_add
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_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)) {
+ 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);
+#if !GAZELLE_ENABLE
break;
+#endif
}
+#if !GAZELLE_ENABLE
}
+#endif
SYS_ARCH_UNPROTECT(lev);
done_socket(sock);
}
@@ -4556,7 +4570,11 @@ lwip_socket_drop_registered_mld6_memberships(int s)
}
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_ipv6_multicast_memberships[i].sock == sock) {
ip_addr_t multi_addr;
u8_t if_idx;
@@ -4570,7 +4588,9 @@ lwip_socket_drop_registered_mld6_memberships(int s)
netconn_join_leave_group_netif(sock->conn, &multi_addr, if_idx, NETCONN_LEAVE);
}
+#if !GAZELLE_ENABLE
}
+#endif
SYS_ARCH_UNPROTECT(lev);
done_socket(sock);
}
@@ -4597,6 +4617,25 @@ mcast_pcb_remove(struct ip_mc *ipmc)
}
}
#endif /* LWIP_IPV4 && LWIP_IGMP */
+
+#if LWIP_IPV6 && LWIP_IPV6_MLD
+ {
+ struct ip6_mc *mc, *next;
+ struct netif *netif;
+
+ mc = ipmc->mc6;
+ while (mc) {
+ next = mc->next;
+ mcast_ip6_mc_src_remove(mc->src);
+ netif = netif_get_by_index(mc->if_idx);
+ if (netif) {
+ mld6_leavegroup_netif(netif, &mc->multi_addr);
+ }
+ mem_free(mc);
+ mc = next;
+ }
+ }
+#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
}
/** Common code to see if the current input multicast packet matches the pcb
@@ -4637,8 +4676,38 @@ mcast_input_local_match(struct ip_mc *ipmc, struct netif *inp)
}
}
}
- } else {}
+ } else
#endif /* LWIP_IPV4 && LWIP_IGMP */
+ {
+#if LWIP_IPV6 && LWIP_IPV6_MLD
+ struct mld6_src *src;
+ struct ip6_mc *mc;
+ ip6_addr_t *multi_addr = ip6_current_dest_addr();
+ ip6_addr_t *src_addr = ip6_current_src_addr();
+
+ IP6_MC_FOREACH(ipmc, mc) {
+ if (((mc->if_idx == NETIF_NO_INDEX) || (mc->if_idx == netif_get_index(inp))) &&
+ ip6_addr_cmp_zoneless(&mc->multi_addr, multi_addr)) {
+ if (mc->fmode == MCAST_EXCLUDE) {
+ IP6_MC_SRC_FOREACH(mc, src) {
+ if (ip6_addr_cmp_zoneless(&src->src_addr, src_addr)) {
+ return 0;
+ }
+ }
+ return 1; /* MCAST_EXCLUDE src_addr must not in src list */
+
+ } else { /* MCAST_INCLUDE */
+ IP6_MC_SRC_FOREACH(mc, src) {
+ if (ip6_addr_cmp_zoneless(&src->src_addr, src_addr)) {
+ return 1;
+ }
+ }
+ return 0; /* MCAST_INCLUDE src_addr must in src list */
+ }
+ }
+ }
+#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
+ }
return 0;
}
@@ -4722,6 +4791,125 @@ mcast_sock_add_drop_membership(int s, struct ip_mc *ipmc, int optname, const str
out:
return (u8_t)err_to_errno(err);
}
+
+/**
+ * setsockopt() MCAST_JOIN_GROUP / MCAST_LEAVE_GROUP command
+ */
+int
+mcast_sock_join_leave_group(int s, struct ip_mc *ipmc, int optname, const struct group_req *gr)
+{
+ struct netif *netif;
+ ip_addr_t multi_addr;
+ err_t err;
+ u8_t if_idx;
+
+ if (gr->gr_group.ss_family == AF_INET) {
+ inet_addr_to_ip4addr(ip_2_ip4(&multi_addr), &(((struct sockaddr_in *)&(gr->gr_group))->sin_addr));
+ IP_SET_TYPE_VAL(multi_addr, IPADDR_TYPE_V4);
+ if (!ip4_addr_ismulticast(ip_2_ip4(&multi_addr))) {
+ return EADDRNOTAVAIL;
+ }
+
+ } else if (gr->gr_group.ss_family == AF_INET6) {
+ inet6_addr_to_ip6addr(ip_2_ip6(&multi_addr), &(((struct sockaddr_in6 *)&(gr->gr_group))->sin6_addr));
+ IP_SET_TYPE_VAL(multi_addr, IPADDR_TYPE_V6);
+ if (!ip6_addr_ismulticast(ip_2_ip6(&multi_addr))) {
+ return EADDRNOTAVAIL;
+ }
+
+ } else {
+ return EADDRNOTAVAIL;
+ }
+
+ if (gr->gr_interface) {
+ netif = netif_get_by_index((u8_t)gr->gr_interface);
+ } else {
+ netif = netif_default; /* To default network interface */
+ }
+ if (netif == NULL) {
+ return ENXIO;
+ }
+
+ if_idx = netif_get_index(netif);
+ if (optname == MCAST_JOIN_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, NULL);
+ } else {
+ err = mcast_leave_netif(ipmc, netif, &multi_addr, NULL);
+#if LWIP_IPV4 && LWIP_IGMP
+ if (IP_IS_V4(&multi_addr)) {
+ lwip_socket_unregister_membership(s, if_idx, ip_2_ip4(&multi_addr));
+ } else
+#endif
+ {
+#if LWIP_IPV6 && LWIP_IPV6_MLD
+ lwip_socket_unregister_mld6_membership(s, if_idx, ip_2_ip6(&multi_addr));
+#endif
+ }
+ }
+out:
+ return err_to_errno(err);
+}
+
+/**
+ * setsockopt() IPV6_JOIN_GROUP / IPV6_LEAVE_GROUP command
+ */
+int
+mcast_sock_ipv6_add_drop_membership(int s, struct ip_mc *ipmc, int optname, const struct ipv6_mreq *imr)
+{
+ struct netif *netif;
+ ip_addr_t multi_addr;
+ err_t err;
+
+ inet6_addr_to_ip6addr(ip_2_ip6(&multi_addr), &imr->ipv6mr_multiaddr);
+ IP_SET_TYPE_VAL(multi_addr, IPADDR_TYPE_V6);
+
+ if (!ip6_addr_ismulticast(ip_2_ip6(&multi_addr))) {
+ return EADDRNOTAVAIL;
+ }
+
+ if (imr->ipv6mr_interface) {
+ netif = netif_get_by_index((u8_t)imr->ipv6mr_interface);
+ } else {
+ netif = netif_default; /* To default network interface */
+ }
+ if (netif == NULL) {
+ return ENXIO;
+ }
+
+ u8_t if_idx = netif_get_index(netif);
+ if (optname == IPV6_JOIN_GROUP) {
+ if (!lwip_socket_register_mld6_membership(s, if_idx, ip_2_ip6(&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);
+ lwip_socket_unregister_mld6_membership(s, if_idx, ip_2_ip6(&multi_addr));
+ }
+out:
+ return err_to_errno(err);
+}
#endif /* (LWIP_IPV4 && LWIP_IGMP) || (LWIP_IPV6 && LWIP_IPV6_MLD)*/
#if GAZELLE_ENABLE
diff --git a/src/core/ipv6/icmp6.c b/src/core/ipv6/icmp6.c
index ed0bd7b..143cb20 100644
--- a/src/core/ipv6/icmp6.c
+++ b/src/core/ipv6/icmp6.c
@@ -129,6 +129,9 @@ icmp6_input(struct pbuf *p, struct netif *inp)
case ICMP6_TYPE_MLQ:
case ICMP6_TYPE_MLR:
case ICMP6_TYPE_MLD:
+#if LWIP_IPV6_MLD_V2
+ case ICMP6_TYPE_MLR2:
+#endif
mld6_input(p, inp);
return;
#endif
diff --git a/src/core/ipv6/mld6.c b/src/core/ipv6/mld6.c
index ac4fb01..29c45bc 100644
--- a/src/core/ipv6/mld6.c
+++ b/src/core/ipv6/mld6.c
@@ -66,6 +66,7 @@
#include "lwip/netif.h"
#include "lwip/memp.h"
#include "lwip/stats.h"
+#include "lwip/sockets.h"
#include <string.h>
@@ -80,12 +81,22 @@
#define MLD6_GROUP_DELAYING_MEMBER 1
#define MLD6_GROUP_IDLE_MEMBER 2
+#define MLD6_MINLEN 12
+#define MLD6_V2_MINLEN 16
+
/* Forward declarations. */
static struct mld_group *mld6_new_group(struct netif *ifp, const ip6_addr_t *addr);
static err_t mld6_remove_group(struct netif *netif, struct mld_group *group);
static void mld6_delayed_report(struct mld_group *group, u16_t maxresp);
static void mld6_send(struct netif *netif, struct mld_group *group, u8_t type);
+static void mld6_timeout(struct netif *netif, struct mld_group *group);
+
+#if LWIP_IPV6_MLD_V2
+static void mld6_v2_timeout(struct netif *netif, struct mld_group *group);
+static void mld6_v2_delayed_report(struct mld_group *group, u16_t maxresp_in);
+static void mld6_v2_send(struct netif *netif, struct mld_group *group, u8_t type);
+#endif
/**
* Stop MLD processing on interface
@@ -128,6 +139,9 @@ mld6_report_groups(struct netif *netif)
while (group != NULL) {
mld6_delayed_report(group, MLD6_JOIN_DELAYING_MEMBER_TMR_MS);
+#if LWIP_IPV6_MLD_V2
+ mld6_v2_delayed_report(group, MLD6_JOIN_DELAYING_MEMBER_TMR_MS);
+#endif
group = group->next;
}
}
@@ -177,6 +191,12 @@ mld6_new_group(struct netif *ifp, const ip6_addr_t *addr)
group->last_reporter_flag = 0;
group->use = 0;
group->next = netif_mld6_data(ifp);
+#if LWIP_IPV6_MLD_V2
+ group->v2_fmode = MLD6_FMODE_INIT;
+ group->v2_last_reporter_flag = 0;
+ group->v2_group_state = MLD6_GROUP_IDLE_MEMBER;
+ group->v2_timer = 0;
+#endif
netif_set_client_data(ifp, LWIP_NETIF_CLIENT_DATA_INDEX_MLD6, group);
}
@@ -244,6 +264,58 @@ mld6_input(struct pbuf *p, struct netif *inp)
switch (mld_hdr->type) {
case ICMP6_TYPE_MLQ: /* Multicast listener query. */
+#if LWIP_IPV6_MLD_V2
+ if (p->len >= MLD6_V2_MINLEN) {
+ struct mld_v2_query *mld_v2_hdr = (struct mld_v2_query *)p->payload;
+
+ /* Is it a general query? */
+ if (ip6_addr_isallnodes_linklocal(ip6_current_dest_addr()) &&
+ ip6_addr_isany(&(mld_v2_hdr->multicast_address))) {
+ MLD6_STATS_INC(mld6.rx_general);
+ /* Report all groups, except all nodes group, and if-local groups. */
+ group = netif_mld6_data(inp);
+ while (group != NULL) {
+ if ((!(ip6_addr_ismulticast_iflocal(&(group->group_address)))) &&
+ (!(ip6_addr_isallnodes_linklocal(&(group->group_address))))) {
+ mld6_v2_delayed_report(group, lwip_ntohs(mld_hdr->max_resp_delay));
+ }
+ group = group->next;
+ }
+ } else { /* query to a specific group ? */
+ if (!ip6_addr_isany(&(mld_v2_hdr->multicast_address))) {
+ u16_t src_num = PP_NTOHS(mld_v2_hdr->src_num);
+ ip6_addr_p_t *src_buf;
+ u16_t src_buf_size = src_num << 4;
+ ip6_addr_t group_addr;
+
+ MLD6_STATS_INC(mld6.rx_group);
+ ip6_addr_copy(group_addr, mld_v2_hdr->multicast_address);
+ group = mld6_lookfor_group(inp, &group_addr);
+
+ if (0 == src_num) {
+ if (group != NULL) {
+ /* Schedule a report. */
+ mld6_v2_delayed_report(group, lwip_ntohs(mld_v2_hdr->max_resp_delay));
+ }
+ } else {
+ src_buf = (ip6_addr_p_t *)mem_malloc(src_buf_size);
+ if (src_buf == NULL) {
+ pbuf_free(p);
+ MLD6_STATS_INC(mld6.memerr);
+ LWIP_DEBUGF(MLD6_DEBUG, ("mld6_input: not enough memory for mld6_input\n"));
+ return;
+ }
+ pbuf_copy_partial(p, src_buf, src_buf_size, MLD_V2_QUERY_HLEN);
+ if (mcast_ip6_filter_interest(inp, (const ip6_addr_t *)&group_addr, src_buf, src_num)) {
+ /* We interest! */
+ mld6_v2_delayed_report(group, lwip_ntohs(mld_v2_hdr->max_resp_delay));
+ }
+ }
+ }
+ }
+
+ }
+#endif
/* Is it a general query? */
if (ip6_addr_isallnodes_linklocal(ip6_current_dest_addr()) &&
ip6_addr_isany(&(mld_hdr->multicast_address))) {
@@ -381,6 +453,10 @@ mld6_joingroup_netif(struct netif *netif, const ip6_addr_t *groupaddr)
MLD6_STATS_INC(mld6.tx_report);
mld6_send(netif, group, ICMP6_TYPE_MLR);
mld6_delayed_report(group, MLD6_JOIN_DELAYING_MEMBER_TMR_MS);
+#if LWIP_IPV6_MLD_V2
+ mld6_v2_send(netif, group, ICMP6_TYPE_MLR2);
+ mld6_v2_delayed_report(group, MLD6_JOIN_DELAYING_MEMBER_TMR_MS);
+#endif
}
/* Increment group use */
@@ -464,6 +540,13 @@ mld6_leavegroup_netif(struct netif *netif, const ip6_addr_t *groupaddr)
MLD6_STATS_INC(mld6.tx_leave);
mld6_send(netif, group, ICMP6_TYPE_MLD);
}
+#if LWIP_IPV6_MLD_V2
+ /* If we are the last reporter for this group */
+ if (group->v2_last_reporter_flag) {
+ MLD6_STATS_INC(mld6.tx_leave);
+ mld6_v2_send(netif, group, ICMP6_TYPE_MLD);
+ }
+#endif
/* Disable the group at the MAC level */
if (netif->mld_mac_filter != NULL) {
@@ -485,6 +568,51 @@ mld6_leavegroup_netif(struct netif *netif, const ip6_addr_t *groupaddr)
return ERR_VAL;
}
+/**
+ * Called if a timeout for one group is reached.
+ * Sends a report for this group.
+ *
+ * @param group an mld_group for which a timeout is reached
+ */
+static void
+mld6_timeout(struct netif *netif, struct mld_group *group)
+{
+ /* If the state is MLD6_GROUP_DELAYING_MEMBER then we send a report for this group */
+ if (group->group_state == MLD6_GROUP_DELAYING_MEMBER) {
+ LWIP_DEBUGF(MLD6_DEBUG, ("mld6_timeout: report membership for group with address "));
+ ip6_addr_debug_print_val(MLD6_DEBUG, group->group_address);
+ LWIP_DEBUGF(MLD6_DEBUG, (" on if %p\n", (void *)netif));
+
+ group->group_state = MLD6_GROUP_IDLE_MEMBER;
+
+ MLD6_STATS_INC(mld6.tx_report);
+ mld6_send(netif, group, ICMP6_TYPE_MLR);
+ }
+}
+
+#if LWIP_IPV6_MLD_V2
+/**
+ * Called if a timeout for one group is reached.
+ * Sends a report for this group.
+ *
+ * @param group an mld_group for which a timeout is reached
+ */
+static void
+mld6_v2_timeout(struct netif *netif, struct mld_group *group)
+{
+ /* If the state is MLD6_GROUP_DELAYING_MEMBER then we send a report for this group */
+ if (group->v2_group_state == MLD6_GROUP_DELAYING_MEMBER) {
+ LWIP_DEBUGF(MLD6_DEBUG, ("mld6_v2_timeout: report membership for group with address "));
+ ip6_addr_debug_print_val(MLD6_DEBUG, group->group_address);
+ LWIP_DEBUGF(MLD6_DEBUG, (" on if %p\n", (void *)netif));
+
+ group->v2_group_state = MLD6_GROUP_IDLE_MEMBER;
+
+ MLD6_STATS_INC(mld6.tx_report);
+ mld6_v2_send(netif, group, ICMP6_TYPE_MLR2);
+ }
+}
+#endif /* LWIP_IPV6_MLD_V2 */
/**
* Periodic timer for mld processing. Must be called every
@@ -504,14 +632,17 @@ mld6_tmr(void)
if (group->timer > 0) {
group->timer--;
if (group->timer == 0) {
- /* If the state is MLD6_GROUP_DELAYING_MEMBER then we send a report for this group */
- if (group->group_state == MLD6_GROUP_DELAYING_MEMBER) {
- MLD6_STATS_INC(mld6.tx_report);
- mld6_send(netif, group, ICMP6_TYPE_MLR);
- group->group_state = MLD6_GROUP_IDLE_MEMBER;
- }
+ mld6_timeout(netif, group);
+ }
+ }
+#if LWIP_IPV6_MLD_V2
+ if (group->v2_timer > 0) {
+ group->v2_timer--;
+ if (group->v2_timer == 0) {
+ mld6_v2_timeout(netif, group);
}
}
+#endif
group = group->next;
}
}
@@ -550,6 +681,46 @@ mld6_delayed_report(struct mld_group *group, u16_t maxresp_in)
}
}
+#if LWIP_IPV6_MLD_V2
+/**
+ * Schedule a delayed membership report for a group
+ *
+ * @param group the mld_group for which "delaying" membership report
+ * should be sent
+ * @param maxresp_in the max resp delay provided in the query
+ */
+static void
+mld6_v2_delayed_report(struct mld_group *group, u16_t maxresp_in)
+{
+ /* Convert maxresp from milliseconds to tmr ticks */
+ u16_t maxresp = maxresp_in / MLD6_TMR_INTERVAL;
+ if (maxresp >= 32768) {
+ maxresp = ((maxresp & 0x0fff) | 0x1000) << (((maxresp >> 12) & 7) + 3);;
+ }
+ if (maxresp == 0) {
+ maxresp = 1;
+ }
+
+#ifdef LWIP_RAND
+ /* Randomize maxresp. (if LWIP_RAND is supported) */
+ maxresp = (u16_t)(LWIP_RAND() % maxresp);
+ if (maxresp == 0) {
+ maxresp = 1;
+ }
+#endif /* LWIP_RAND */
+
+ /* Apply timer value if no report has been scheduled already. */
+ if ((group->v2_group_state == MLD6_GROUP_IDLE_MEMBER) ||
+ ((group->v2_group_state == MLD6_GROUP_DELAYING_MEMBER) &&
+ ((group->v2_timer == 0) || (maxresp < group->v2_timer)))) {
+ group->v2_timer = maxresp;
+ group->v2_group_state = MLD6_GROUP_DELAYING_MEMBER;
+ }
+}
+
+#endif
+
+
/**
* Send a MLD message (report or done).
*
@@ -623,4 +794,181 @@ mld6_send(struct netif *netif, struct mld_group *group, u8_t type)
pbuf_free(p);
}
+#if LWIP_IPV6_MLD_V2
+/**
+ * Build a mld v2 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
+mld_v2_build_record(struct mld_v2_record *rec, struct mld_group *group, u8_t fmode, ip6_addr_p_t *src_array, u32_t src_cnt)
+{
+ ip6_addr_p_t *src_copy;
+
+ if (fmode == MCAST_EXCLUDE) {
+ if (group->v2_fmode != MCAST_EXCLUDE) {
+ group->v2_fmode = MCAST_EXCLUDE;
+ rec->type = MLD2_CHANGE_TO_EXCLUDE;
+ } else {
+ rec->type = MLD2_MODE_IS_EXCLUDE;
+ }
+
+ } else {
+ if (group->v2_fmode != MCAST_INCLUDE) {
+ group->v2_fmode = MCAST_INCLUDE;
+ rec->type = MLD2_CHANGE_TO_INCLUDE;
+ } else {
+ rec->type = MLD2_MODE_IS_INCLUDE;
+ }
+ }
+
+ rec->aux_len = 0;
+ rec->src_num = PP_HTONS(src_cnt);
+ ip6_addr_copy_to_packed(rec->multicast_address, group->group_address);
+
+ if (src_cnt) {
+ src_copy = (ip6_addr_p_t *)(rec + 1);
+ MEMCPY(src_copy, src_array, (src_cnt << 4));
+ }
+}
+
+/**
+ * Send a MLD message (report).
+ *
+ * An IPv6 hop-by-hop options header with a router alert option
+ * is prepended.
+ *
+ * @param group the group to report or quit
+ * @param type ICMP6_TYPE_MLR (report) or ICMP6_TYPE_MLD (done)
+ */
+static void
+mld6_v2_send(struct netif *netif, struct mld_group *group, u8_t type)
+{
+ struct mld_v2_report *mld_hdr;
+ struct mld_v2_record *rec;
+ struct pbuf *p;
+ const ip6_addr_t *src_addr;
+
+ /* Select our source address. */
+ if (!ip6_addr_isvalid(netif_ip6_addr_state(netif, 0))) {
+ /* This is a special case, when we are performing duplicate address detection.
+ * We must join the multicast group, but we don't have a valid address yet. */
+ src_addr = IP6_ADDR_ANY6;
+ } else {
+ /* Use link-local address as source address. */
+ src_addr = netif_ip6_addr(netif, 0);
+ }
+
+ if (ICMP6_TYPE_MLD == type) {
+ p = pbuf_alloc(PBUF_IP, MLD_V2_REPORT_HLEN + MLD_V2_RECORD_LEN(0) + MLD6_HBH_HLEN, PBUF_RAM);
+ if (p == NULL) {
+ LWIP_DEBUGF(MLD6_DEBUG, ("mld6_v2_send: not enough memory for mld6_v2_send\n"));
+ IGMP_STATS_INC(mld6.memerr);
+ return;
+ }
+
+ /* Move to make room for Hop-by-hop options header. */
+ if (pbuf_remove_header(p, MLD6_HBH_HLEN)) {
+ pbuf_free(p);
+ MLD6_STATS_INC(mld6.lenerr);
+ return;
+ }
+
+ mld_hdr = (struct mld_v2_report *)p->payload;
+ mld_hdr->type = ICMP6_TYPE_MLR2;
+ mld_hdr->reserved1 = 0;
+ mld_hdr->chksum = 0;
+ mld_hdr->reserved2 = 0;
+ mld_hdr->mrec_num = PP_HTONS(1);
+
+ rec = (struct mld_v2_record *)(mld_hdr + 1);
+ if (group->v2_fmode == MCAST_EXCLUDE) {
+ rec->type = MLD2_CHANGE_TO_INCLUDE;
+ } else {
+ rec->type = MLD2_MODE_IS_INCLUDE;
+ }
+ rec->aux_len = 0;
+ rec->src_num = 0; /* IS_IN (NULL) mean drop group */
+ ip6_addr_copy_to_packed(rec->multicast_address, group->group_address);
+ } else {/* Report a group */
+ ip6_addr_p_t src_array[LWIP_MCAST_SRC_TBL_SIZE];
+ u16_t src_cnt;
+ u8_t fmode;
+
+ src_cnt = mcast_ip6_filter_info(netif, &group->group_address, src_array, LWIP_MCAST_SRC_TBL_SIZE, &fmode);
+ LWIP_ASSERT("mld6_v2_send: multicast filter error!", !(!src_cnt && (fmode == MCAST_INCLUDE)));
+
+ p = pbuf_alloc(PBUF_IP, MLD_V2_REPORT_HLEN + MLD_V2_RECORD_LEN(src_cnt) + MLD6_HBH_HLEN, PBUF_RAM);
+ if (p == NULL) {
+ LWIP_DEBUGF(MLD6_DEBUG, ("mld6_v2_send: not enough memory for mld6_v2_send\n"));
+ IGMP_STATS_INC(mld6.memerr);
+ return;
+ }
+
+ mld_hdr = (struct mld_v2_report *)p->payload;
+ mld_hdr->type = ICMP6_TYPE_MLR2;
+ mld_hdr->reserved1 = 0;
+ mld_hdr->chksum = 0;
+ mld_hdr->reserved2 = 0;
+ mld_hdr->mrec_num = PP_HTONS(1);
+
+ rec = (struct mld_v2_record *)(mld_hdr + 1);
+ mld_v2_build_record(rec, group, fmode, src_array, src_cnt);
+ group->v2_last_reporter_flag = 1;/* Remember we were the last to report */
+ }
+
+ #if CHECKSUM_GEN_ICMP6
+ IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_ICMP6) {
+ mld_hdr->chksum = ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->len,
+ src_addr, &(group->group_address));
+ }
+#endif /* CHECKSUM_GEN_ICMP6 */
+
+ /* Add hop-by-hop headers options: router alert with MLD value. */
+ ip6_options_add_hbh_ra(p, IP6_NEXTH_ICMP6, IP6_ROUTER_ALERT_VALUE_MLD);
+
+ /* Send the packet out. */
+ MLD6_STATS_INC(mld6.xmit);
+ ip6_output_if(p, (ip6_addr_isany(src_addr)) ? NULL : src_addr, &(group->group_address),
+ MLD6_HL, 0, IP6_NEXTH_HOPBYHOP, netif);
+ pbuf_free(p);
+}
+
+/**
+ * mld v2 report trigger.
+ */
+void
+mld6_v2_trigger(struct netif *netif, const ip6_addr_t *groupaddr)
+{
+ struct mld_group *group;
+#if LWIP_IPV6_SCOPES
+ ip6_addr_t ip6addr;
+
+ /* If the address has a particular scope but no zone set, use the netif to
+ * set one now. Within the mld6 module, all addresses are properly zoned. */
+ if (ip6_addr_lacks_zone(groupaddr, IP6_MULTICAST)) {
+ ip6_addr_set(&ip6addr, groupaddr);
+ ip6_addr_assign_zone(&ip6addr, IP6_MULTICAST, netif);
+ groupaddr = &ip6addr;
+ }
+ IP6_ADDR_ZONECHECK_NETIF(groupaddr, netif);
+#endif /* LWIP_IPV6_SCOPES */
+
+ /* find group */
+ group = mld6_lookfor_group(netif, groupaddr);
+ if (group) {
+ mld6_v2_send(netif, group, ICMP6_TYPE_MLR2);
+
+ mld6_v2_delayed_report(group, MLD6_JOIN_DELAYING_MEMBER_TMR_MS);
+
+ /* Need to work out where this timer comes from */
+ group->v2_group_state = MLD6_GROUP_DELAYING_MEMBER;
+ }
+}
+#endif
+
#endif /* LWIP_IPV6 */
diff --git a/src/core/mcast.c b/src/core/mcast.c
index 5e3463b..fa46f10 100644
--- a/src/core/mcast.c
+++ b/src/core/mcast.c
@@ -250,6 +250,204 @@ mcast_ip4_filter_interest(struct netif *netif, const ip4_addr_t *multi_addr, con
#endif /* LWIP_IGMP_V3 */
#endif /* LWIP_IPV4 && LWIP_IGMP */
+#if LWIP_IPV6 && LWIP_IPV6_MLD
+/**
+ * ipv6 multicast filter find
+ */
+struct ip6_mc *
+mcast_ip6_mc_find(struct ip_mc *ipmc, struct netif *netif, const ip6_addr_t *multi_addr, struct ip6_mc **mc_prev)
+{
+ struct ip6_mc *prev = NULL;
+ struct ip6_mc *mc;
+
+ IP6_MC_FOREACH(ipmc, mc) {
+ if (((mc->if_idx == NETIF_NO_INDEX) || (mc->if_idx == netif_get_index(netif))) &&
+ ip6_addr_cmp_zoneless(&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! */
+}
+
+/**
+ * ipv6 multicast filter find source
+ */
+static struct mld6_src *
+mcast_ip6_mc_src_find(struct ip6_mc *mc, const ip6_addr_t *src_addr, struct mld6_src **src_prev)
+{
+ struct mld6_src *prev = NULL;
+ struct mld6_src *src;
+
+ IP6_MC_SRC_FOREACH(mc, src) {
+ if (ip6_addr_cmp_zoneless(&src->src_addr, src_addr)) { /* check source address */
+ if (src_prev) {
+ *src_prev = prev;
+ }
+ return src; /* found! */
+ }
+ prev = src;
+ }
+
+ return NULL; /* not found! */
+}
+
+/**
+ * ipv6 multicast filter remove all source
+ */
+void
+mcast_ip6_mc_src_remove(struct mld6_src *src)
+{
+ struct mld6_src *next;
+
+ while (src) {
+ next = src->next;
+ mem_free(src);
+ src = next;
+ }
+}
+
+#if LWIP_IPV6_MLD_V2
+/**
+ * ipv6 multicast filter group source infomation (use ip6_addr_p_t for MLDv2 speedup)
+ */
+u16_t
+mcast_ip6_filter_info(struct netif *netif, const ip6_addr_t *multi_addr, ip6_addr_p_t addr_array[], u16_t arr_cnt, u8_t *fmode)
+{
+ static ip6_addr_p_t in_tbl[LWIP_MCAST_SRC_TBL_SIZE];
+ static ip6_addr_p_t ex_tbl[LWIP_MCAST_SRC_TBL_SIZE];
+
+ struct ip6_mc *mc;
+ struct mld6_src *src;
+ ip6_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_IP6_MC_GET(pcb, pcbs, type, tbl, c) \
+ for ((pcb) = (pcbs); (pcb) != NULL; (pcb) = (pcb)->next) { \
+ mc = mcast_ip6_mc_find(&(pcb)->ipmc, netif, multi_addr, NULL); \
+ if ((mc == NULL) || (mc->fmode != (type))) { \
+ continue; \
+ } \
+ match = 1; \
+ IP6_MC_SRC_FOREACH(mc, src) { \
+ if ((c) < max_cnt) { \
+ ip6_addr_copy_to_packed((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_IP6_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_IP6_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_IP6_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_IP6_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++) {
+ ip6_addr_copy_from_packed(addr, ex_tbl[i]);
+ for (j = 0; j < in_cnt; j++) {
+ if (ip6_addr_cmp_zoneless(&addr, &in_tbl[j])) { /* check exclude conflict with include table */
+ ip6_addr_copy_to_packed(ex_tbl[i], *IP6_ADDR_ANY6); /* remove from exclude table */
+ break;
+ }
+ }
+ }
+
+ for (i = 0, cnt = 0; i < ex_cnt; i++) {
+ if (!ip6_addr_isany(&ex_tbl[i])) {
+ ip6_addr_copy_to_packed(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++) {
+ ip6_addr_copy_to_packed(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);
+}
+
+/**
+ * ipv6 multicast filter source address interest (use ip6_addr_p_t for MLDv2 speedup)
+ */
+u8_t
+mcast_ip6_filter_interest(struct netif *netif, const ip6_addr_t *multi_addr, const ip6_addr_p_t src_addr[], u16_t arr_cnt)
+{
+ static ip6_addr_p_t ip_tbl[LWIP_MCAST_SRC_TBL_SIZE];
+ u16_t i, j, cnt;
+ u8_t fmode;
+
+ cnt = mcast_ip6_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 (ip6_addr_cmp_zoneless(&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 (ip6_addr_cmp_zoneless(&src_addr[j], &ip_tbl[i])) {
+ return 1;
+ }
+ }
+ }
+ return 0;
+ }
+}
+#endif /* LWIP_IPV6_MLD_V2 */
+#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
+
#if (LWIP_IPV4 && LWIP_IGMP) || (LWIP_IPV6 && LWIP_IPV6_MLD)
/** Join a multicast group (Can with a source specified)
*
@@ -303,8 +501,9 @@ mcast_join_netif(struct ip_mc *ipmc, struct netif *netif, const ip_addr_t *multi
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;
}
- return ERR_OK;
+ return EADDRINUSE;
}
mc = (struct ip4_mc *)mem_malloc(sizeof(struct ip4_mc)); /* Make a new mc */
@@ -334,8 +533,68 @@ mcast_join_netif(struct ip_mc *ipmc, struct netif *netif, const ip_addr_t *multi
mc->next = ipmc->mc4;
ipmc->mc4 = mc;
igmp_joingroup_netif(netif, ip_2_ip4(multi_addr));
- } else {}
+ } else
#endif /* LWIP_IPV4 && LWIP_IGMP */
+ {
+#if LWIP_IPV6 && LWIP_IPV6_MLD
+ struct ip6_mc *mc;
+ struct mld6_src *src;
+
+ mc = mcast_ip6_mc_find(ipmc, netif, ip_2_ip6(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_ip6_mc_src_find(mc, ip_2_ip6(src_addr), NULL);
+ if (src) {
+ return ERR_ALREADY; /* already in source list */
+ }
+
+ src = (struct mld6_src *)mem_malloc(sizeof(struct mld6_src));
+ if (src == NULL) {
+ return ERR_MEM; /* no memory */
+ }
+ ip6_addr_set(&src->src_addr, ip_2_ip6(src_addr));
+ src->next = mc->src;
+ mc->src = src;
+ mc->fmode = MCAST_INCLUDE; /* change to include mode */
+ IP6_MC_TRIGGER_CALL(netif, ip_2_ip6(multi_addr)); /* trigger a report */
+ return ERR_OK;
+ }
+ return EADDRINUSE;
+ }
+
+ mc = (struct ip6_mc *)mem_malloc(sizeof(struct ip6_mc)); /* Make a new mc */
+ if (mc == NULL) {
+ mld6_leavegroup_netif(netif, ip_2_ip6(multi_addr));
+ return ERR_MEM; /* no memory */
+ }
+ mc->if_idx = netif_get_index(netif);
+ ip6_addr_set(&mc->multi_addr, ip_2_ip6(multi_addr));
+
+ if (src_addr) {
+ mc->fmode = MCAST_INCLUDE;
+ src = (struct mld6_src *)mem_malloc(sizeof(struct mld6_src));
+ if (src == NULL) {
+ mld6_leavegroup_netif(netif, ip_2_ip6(multi_addr));
+ mem_free(mc);
+ return ERR_MEM; /* no memory */
+ }
+ ip6_addr_set(&src->src_addr, ip_2_ip6(src_addr));
+ src->next = NULL;
+ mc->src = src;
+
+ } else {
+ mc->fmode = MCAST_EXCLUDE; /* no source specified */
+ mc->src = NULL;
+ }
+
+ mc->next = ipmc->mc6;
+ ipmc->mc6 = mc;
+ mld6_joingroup_netif(netif, ip_2_ip6(multi_addr));
+#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
+ }
return ERR_OK;
}
@@ -364,8 +623,23 @@ mcast_join_group(struct ip_mc *ipmc, const ip_addr_t *if_addr, const ip_addr_t *
}
}
}
- } else {}
+ } else
#endif /* LWIP_IPV4 && LWIP_IGMP */
+ {
+#if LWIP_IPV6 && LWIP_IPV6_MLD
+ struct netif *netif;
+
+ NETIF_FOREACH(netif) {
+ if (ip6_addr_isany(ip_2_ip6(if_addr)) ||
+ netif_get_ip6_addr_match(netif, ip_2_ip6(if_addr)) >= 0) {
+ err = mcast_join_netif(ipmc, netif, multi_addr, src_addr);
+ if (err != ERR_OK) {
+ return (err);
+ }
+ }
+ }
+#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
+ }
return err;
}
@@ -423,8 +697,53 @@ mcast_leave_netif(struct ip_mc *ipmc, struct netif *netif, const ip_addr_t *mult
ipmc->mc4 = mc->next;
}
mem_free(mc);
- } else {}
+ } else
#endif /* LWIP_IPV4 && LWIP_IGMP */
+ {
+#if LWIP_IPV6 && LWIP_IPV6_MLD
+ struct ip6_mc *mc_prev;
+ struct ip6_mc *mc;
+ struct mld6_src *src_prev;
+ struct mld6_src *src;
+
+ mc = mcast_ip6_mc_find(ipmc, netif, ip_2_ip6(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_ip6_mc_src_find(mc, ip_2_ip6(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) {
+ IP6_MC_TRIGGER_CALL(netif, ip_2_ip6(multi_addr)); /* trigger a report */
+ return ERR_OK;
+ }
+ } else { /* we want drop this group */
+ mcast_ip6_mc_src_remove(mc->src);
+ }
+
+ mld6_leavegroup_netif(netif, ip_2_ip6(multi_addr));
+ if (mc_prev) {
+ mc_prev->next = mc->next;
+ } else {
+ ipmc->mc6 = mc->next;
+ }
+ mem_free(mc);
+#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
+ }
return ERR_OK;
}
@@ -453,8 +772,23 @@ mcast_leave_group(struct ip_mc *ipmc, const ip_addr_t *if_addr, const ip_addr_t
}
}
}
- } else {}
+ } else
#endif /* LWIP_IPV4 && LWIP_IGMP */
+ {
+#if LWIP_IPV6 && LWIP_IPV6_MLD
+ struct netif *netif;
+
+ NETIF_FOREACH(netif) {
+ if (ip6_addr_isany(ip_2_ip6(if_addr)) ||
+ netif_get_ip6_addr_match(netif, ip_2_ip6(if_addr)) >= 0) {
+ res = mcast_leave_netif(ipmc, netif, multi_addr, src_addr);
+ if (err != ERR_OK) {
+ err = res;
+ }
+ }
+ }
+#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
+ }
return err;
}
@@ -492,11 +826,36 @@ mcast_block_netif(struct ip_mc *ipmc, struct netif *netif, const ip_addr_t *mult
src->next = mc->src;
mc->src = src;
IP4_MC_TRIGGER_CALL(netif, ip_2_ip4(multi_addr)); /* trigger a report */
- return ERR_OK;
}
- } else {}
+ } else
#endif /* LWIP_IPV4 && LWIP_IGMP */
- return EADDRINUSE;
+ {
+#if LWIP_IPV6 && LWIP_IPV6_MLD
+ struct ip6_mc *mc;
+ struct mld6_src *src;
+
+ mc = mcast_ip6_mc_find(ipmc, netif, ip_2_ip6(multi_addr), NULL);
+ if (mc == NULL) {
+ return ERR_VAL;
+ }
+ if (mc->fmode != MCAST_EXCLUDE) { /* we must in exclude mode */
+ return ERR_VAL;
+ }
+
+ src = mcast_ip6_mc_src_find(mc, ip_2_ip6(blk_addr), NULL);
+ if (src == NULL) {
+ src = (struct mld6_src *)mem_malloc(sizeof(struct mld6_src));
+ if (src == NULL) {
+ return ERR_MEM;
+ }
+ ip6_addr_set(&src->src_addr, ip_2_ip6(blk_addr));
+ src->next = mc->src;
+ mc->src = src;
+ IP6_MC_TRIGGER_CALL(netif, ip_2_ip6(multi_addr)); /* trigger a report */
+ }
+#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
+ }
+ return ERR_OK;
}
/** Add a block source address to a multicast group
@@ -524,8 +883,23 @@ mcast_block_group(struct ip_mc *ipmc, const ip_addr_t *if_addr, const ip_addr_t
}
}
}
- } else {}
+ } else
#endif /* LWIP_IPV4 && LWIP_IGMP */
+ {
+#if LWIP_IPV6 && LWIP_IPV6_MLD
+ struct netif *netif;
+
+ NETIF_FOREACH(netif) {
+ if (ip6_addr_isany(ip_2_ip6(if_addr)) ||
+ netif_get_ip6_addr_match(netif, ip_2_ip6(if_addr)) >= 0) {
+ err = mcast_block_netif(ipmc, netif, multi_addr, blk_addr);
+ if (err != ERR_OK) {
+ return (err);
+ }
+ }
+ }
+#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
+ }
return err;
}
@@ -565,8 +939,35 @@ mcast_unblock_netif(struct ip_mc *ipmc, struct netif *netif, const ip_addr_t *mu
}
mem_free(src);
IP4_MC_TRIGGER_CALL(netif, ip_2_ip4(multi_addr)); /* trigger a report */
- } else {}
+ } else
#endif /* LWIP_IPV4 && LWIP_IGMP */
+ {
+#if LWIP_IPV6 && LWIP_IPV6_MLD
+ struct ip6_mc *mc;
+ struct mld6_src *src_prev;
+ struct mld6_src *src;
+
+ mc = mcast_ip6_mc_find(ipmc, netif, ip_2_ip6(multi_addr), NULL);
+ if (mc == NULL) {
+ return ERR_VAL;
+ }
+ if (mc->fmode != MCAST_EXCLUDE) { /* we must in exclude mode */
+ return ERR_VAL;
+ }
+
+ src = mcast_ip6_mc_src_find(mc, ip_2_ip6(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);
+ IP6_MC_TRIGGER_CALL(netif, ip_2_ip6(multi_addr)); /* trigger a report */
+#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
+ }
return ERR_OK;
}
@@ -595,8 +996,23 @@ mcast_unblock_group(struct ip_mc *ipmc, const ip_addr_t *if_addr, const ip_addr_
}
}
}
- } else {}
+ } else
#endif /* LWIP_IPV4 && LWIP_IGMP */
+ {
+#if LWIP_IPV6 && LWIP_IPV6_MLD
+ struct netif *netif;
+
+ NETIF_FOREACH(netif) {
+ if (ip6_addr_isany(ip_2_ip6(if_addr)) ||
+ netif_get_ip6_addr_match(netif, ip_2_ip6(if_addr)) >= 0) {
+ res = mcast_unblock_netif(ipmc, netif, multi_addr, unblk_addr);
+ if (err != ERR_OK) {
+ err = res;
+ }
+ }
+ }
+#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
+ }
return err;
}
diff --git a/src/core/udp.c b/src/core/udp.c
index e1f9e1b..4a47e99 100644
--- a/src/core/udp.c
+++ b/src/core/udp.c
@@ -195,6 +195,12 @@ udp_input_local_match(struct udp_pcb *pcb, struct netif *inp, u8_t broadcast)
return 0;
}
+#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) */
+
/* Dual-stack: PCBs listening to any IP type also listen to any IP address */
if (IP_IS_ANY_TYPE_VAL(pcb->local_ip)) {
#if LWIP_IPV4 && IP_SOF_BROADCAST_RECV
@@ -205,12 +211,6 @@ udp_input_local_match(struct udp_pcb *pcb, struct netif *inp, u8_t broadcast)
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
diff --git a/src/include/lwip/api.h b/src/include/lwip/api.h
index d5783dd..319ee09 100644
--- a/src/include/lwip/api.h
+++ b/src/include/lwip/api.h
@@ -103,6 +103,7 @@ extern "C" {
#define NETCONNTYPE_ISIPV6(t) (((t)&NETCONN_TYPE_IPV6) != 0)
#define NETCONNTYPE_ISUDPLITE(t) (((t)&0xF3) == NETCONN_UDPLITE)
#define NETCONNTYPE_ISUDPNOCHKSUM(t) (((t)&0xF3) == NETCONN_UDPNOCHKSUM)
+#define NETCONNTYPE_GROUPV6(t) ((t)&0xFF)
#else /* LWIP_IPV6 */
#define NETCONNTYPE_ISIPV6(t) (0)
#define NETCONNTYPE_ISUDPLITE(t) ((t) == NETCONN_UDPLITE)
diff --git a/src/include/lwip/mcast.h b/src/include/lwip/mcast.h
index c7b195d..16a27ae 100644
--- a/src/include/lwip/mcast.h
+++ b/src/include/lwip/mcast.h
@@ -74,6 +74,28 @@ struct ip4_mc {
#endif /* LWIP_IPV4 && LWIP_IGMP */
+#if LWIP_IPV6 && LWIP_IPV6_MLD
+/** the IPv6 multicast filter */
+struct ip6_mc {
+ struct ip6_mc *next;
+ /** the interface index */
+ u8_t if_idx;
+ /** the group address */
+ ip6_addr_t multi_addr;
+ /** the source address list filter mode 0: EXCLUDE 1: INCLUDE */
+ u8_t fmode;
+ /** the source address list */
+ struct mld6_src *src;
+};
+
+/** The list of ip6_mc. */
+#define IP6_MC_FOREACH(ipmc, mc) \
+ for ((mc) = (ipmc)->mc6; (mc) != NULL; (mc) = (mc)->next)
+#define IP6_MC_SRC_FOREACH(mc, src) \
+ for ((src) = (mc)->src; (src) != NULL; (src) = (src)->next)
+#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
+
+
#if (LWIP_IPV4 && LWIP_IGMP) || (LWIP_IPV6 && LWIP_IPV6_MLD)
/* multicast filter control block */
struct ip_mc {
@@ -85,6 +107,10 @@ struct ip_mc {
#if LWIP_IPV4 && LWIP_IGMP
struct ip4_mc *mc4;
#endif /* LWIP_IPV4 && LWIP_IGMP */
+
+#if LWIP_IPV6 && LWIP_IPV6_MLD
+ struct ip6_mc *mc6;
+#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
};
#if LWIP_IPV4 && LWIP_IGMP && LWIP_IGMP_V3
@@ -93,6 +119,13 @@ u16_t mcast_ip4_filter_info(struct netif *netif, const ip4_addr_t *multi_addr,
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 */
+#if LWIP_IPV6 && LWIP_IPV6_MLD && LWIP_IPV6_MLD_V2
+/* MLDv2 use the following function to get specified group of total multicast filter source address array */
+u16_t mcast_ip6_filter_info(struct netif *netif, const ip6_addr_t *multi_addr, ip6_addr_p_t addr_array[], u16_t arr_cnt, u8_t *fmode);
+u8_t mcast_ip6_filter_interest(struct netif *netif, const ip6_addr_t *multi_addr, const ip6_addr_p_t src_addr[], u16_t arr_cnt);
+#endif /* LWIP_IPV6 && LWIP_IPV6_MLD && LWIP_IPV6_MLD_V2 */
+
+
/* 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);
@@ -109,6 +142,8 @@ err_t mcast_unblock_group(struct ip_mc *ipmc, const ip_addr_t *if_addr, const
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);
+struct ip6_mc *mcast_ip6_mc_find(struct ip_mc *ipmc, struct netif *netif, const ip6_addr_t *multi_addr, struct ip6_mc **mc_prev);
+void mcast_ip6_mc_src_remove(struct mld6_src *src);
#endif /* (LWIP_IPV4 && LWIP_IGMP) || (LWIP_IPV6 && LWIP_IPV6_MLD) */
diff --git a/src/include/lwip/mld6.h b/src/include/lwip/mld6.h
index 2764fdd..7819551 100644
--- a/src/include/lwip/mld6.h
+++ b/src/include/lwip/mld6.h
@@ -54,6 +54,13 @@
extern "C" {
#endif
+/* Multicast filter support */
+struct mld6_src {
+ struct mld6_src *next;
+ /** the source address */
+ ip6_addr_t src_addr;
+};
+
/** MLD group */
struct mld_group {
/** next link */
@@ -68,6 +75,16 @@ struct mld_group {
u16_t timer;
/** counter of simultaneous uses */
u8_t use;
+ #if LWIP_IPV6_MLD_V2
+ /** Last report fmode */
+ u8_t v2_fmode;
+ /** signifies we were the last person to report */
+ u8_t v2_last_reporter_flag;
+ /** current state of the group */
+ u8_t v2_group_state;
+ /** timer for reporting, negative is OFF */
+ u16_t v2_timer;
+#endif /* LWIP_IPV6_MLD_V2 */
};
#define MLD6_TMR_INTERVAL 100 /* Milliseconds */
@@ -90,6 +107,19 @@ err_t mld6_leavegroup_netif(struct netif *netif, const ip6_addr_t *groupaddr);
*/
#define netif_mld6_data(netif) ((struct mld_group *)netif_get_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_MLD6))
+/**
+ * ipv6 multicast filter trigger function
+ */
+#if LWIP_IPV6_MLD_V2
+
+#define MLD6_FMODE_INIT 2 /* Not MCAST_INCLUDE or MCAST_EXCLUDE */
+void mld6_v2_trigger(struct netif *netif, const ip6_addr_t *groupaddr);
+#define IP6_MC_TRIGGER_CALL(netif, multi_addr) mld6_v2_trigger(netif, multi_addr)
+#else
+#define IP6_MC_TRIGGER_CALL(netif, multi_addr)
+#endif /* !LWIP_IPV6_MLD_V2 */
+
+
#ifdef __cplusplus
}
#endif
diff --git a/src/include/lwip/netbuf.h b/src/include/lwip/netbuf.h
index e32c9bd..e7f0713 100644
--- a/src/include/lwip/netbuf.h
+++ b/src/include/lwip/netbuf.h
@@ -68,6 +68,9 @@ struct netbuf {
u16_t toport_chksum;
#if LWIP_NETBUF_RECVINFO
ip_addr_t toaddr;
+#if LWIP_IPV6
+ u8_t hoplim;
+#endif /* LWIP_IPV6 */
#endif /* LWIP_NETBUF_RECVINFO */
#endif /* LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY */
};
diff --git a/src/include/lwip/opt.h b/src/include/lwip/opt.h
index 06303f4..9a1a32d 100644
--- a/src/include/lwip/opt.h
+++ b/src/include/lwip/opt.h
@@ -3584,6 +3584,14 @@
#if !defined DHCP6_DEBUG || defined __DOXYGEN__
#define DHCP6_DEBUG LWIP_DBG_OFF
#endif
+
+/**
+ * MLD6_DEBUG: Enable debugging in mld6.c.
+ */
+#if !defined MLD6_DEBUG || defined __DOXYGEN__
+#define MLD6_DEBUG LWIP_DBG_OFF
+#endif
+
/**
* @}
*/
diff --git a/src/include/lwip/prot/icmp6.h b/src/include/lwip/prot/icmp6.h
index 36989f6..17186b6 100644
--- a/src/include/lwip/prot/icmp6.h
+++ b/src/include/lwip/prot/icmp6.h
@@ -70,6 +70,8 @@ enum icmp6_type {
ICMP6_TYPE_MLR = 131,
/** Multicast listener done */
ICMP6_TYPE_MLD = 132,
+ /** Multicast listener report v2*/
+ ICMP6_TYPE_MLR2 = 143,
/** Router solicitation */
ICMP6_TYPE_RS = 133,
/** Router advertisement */
diff --git a/src/include/lwip/prot/mld6.h b/src/include/lwip/prot/mld6.h
index 71f1dcb..40f1ca6 100644
--- a/src/include/lwip/prot/mld6.h
+++ b/src/include/lwip/prot/mld6.h
@@ -64,6 +64,85 @@ PACK_STRUCT_END
# include "arch/epstruct.h"
#endif
+#if LWIP_IPV6_MLD_V2 /* RFC 3810 */
+/**
+ * MLDv2 query packet format.
+ */
+#ifdef PACK_STRUCT_USE_INCLUDES
+# include "arch/bpstruct.h"
+#endif
+ PACK_STRUCT_BEGIN
+ struct mld_v2_query {
+ PACK_STRUCT_FLD_8(u8_t type);
+ PACK_STRUCT_FLD_8(u8_t code);
+ PACK_STRUCT_FIELD(u16_t chksum);
+ PACK_STRUCT_FIELD(u16_t max_resp_delay);
+ PACK_STRUCT_FIELD(u16_t reserved);
+ PACK_STRUCT_FLD_S(ip6_addr_t multicast_address);
+ PACK_STRUCT_FLD_8(u8_t resv_s_qrv);
+ PACK_STRUCT_FLD_8(u8_t qqic);
+ PACK_STRUCT_FIELD(u16_t src_num);
+ } PACK_STRUCT_STRUCT;
+ PACK_STRUCT_END
+#ifdef PACK_STRUCT_USE_INCLUDES
+# include "arch/epstruct.h"
+#endif
+
+#define MLD_V2_QUERY_HLEN sizeof(struct mld_v2_query)
+
+/**
+ * MLDv2 report packet header format.
+ */
+#ifdef PACK_STRUCT_USE_INCLUDES
+# include "arch/bpstruct.h"
+#endif
+ PACK_STRUCT_BEGIN
+ struct mld_v2_report {
+ PACK_STRUCT_FLD_8(u8_t type);
+ PACK_STRUCT_FLD_8(u8_t reserved1);
+ PACK_STRUCT_FIELD(u16_t chksum);
+ PACK_STRUCT_FIELD(u16_t reserved2);
+ PACK_STRUCT_FIELD(u16_t mrec_num);
+ } PACK_STRUCT_STRUCT;
+ PACK_STRUCT_END
+#ifdef PACK_STRUCT_USE_INCLUDES
+# include "arch/epstruct.h"
+#endif
+
+#define MLD_V2_REPORT_HLEN sizeof(struct mld_v2_report)
+
+/*
+ * Definitions for MLDv2
+ */
+#define MLD2_MODE_IS_INCLUDE 1
+#define MLD2_MODE_IS_EXCLUDE 2
+#define MLD2_CHANGE_TO_INCLUDE 3
+#define MLD2_CHANGE_TO_EXCLUDE 4
+#define MLD2_ALLOW_NEW_SOURCES 5
+#define MLD2_BLOCK_OLD_SOURCES 6
+
+/**
+ * MLDv2 report packet group record format.
+ */
+#ifdef PACK_STRUCT_USE_INCLUDES
+# include "arch/bpstruct.h"
+#endif
+ PACK_STRUCT_BEGIN
+ struct mld_v2_record {
+ PACK_STRUCT_FLD_8(u8_t type);
+ PACK_STRUCT_FLD_8(u8_t aux_len);
+ PACK_STRUCT_FIELD(u16_t src_num);
+ PACK_STRUCT_FLD_S(ip6_addr_p_t multicast_address);
+ } PACK_STRUCT_STRUCT;
+ PACK_STRUCT_END
+#ifdef PACK_STRUCT_USE_INCLUDES
+# include "arch/epstruct.h"
+#endif
+
+#define MLD_V2_RECORD_LEN(src_cnt) (sizeof(struct mld_v2_record) + (src_cnt << 4))
+#endif /* LWIP_IPV6_MLD_V2 */
+
+
#ifdef __cplusplus
}
#endif
diff --git a/src/include/lwip/sockets.h b/src/include/lwip/sockets.h
index 00aca53..f2a1b59 100644
--- a/src/include/lwip/sockets.h
+++ b/src/include/lwip/sockets.h
@@ -114,8 +114,11 @@ struct sockaddr {
char sa_data[14];
};
+#ifndef LWIP_IPV6_MLD_V2
struct sockaddr_storage {
+#if !GAZELLE_ENABLE
u8_t s2_len;
+#endif
sa_family_t ss_family;
char s2_data1[2];
u32_t s2_data2[3];
@@ -123,6 +126,27 @@ struct sockaddr_storage {
u32_t s2_data3[3];
#endif /* LWIP_IPV6 */
};
+#else
+#ifndef _SS_SIZE
+#define _SS_SIZE 128
+#endif //_SS_SIZE
+#ifndef __SOCKADDR_COMMON_SIZE
+#define __SOCKADDR_COMMON_SIZE (sizeof (unsigned short int))
+#endif //__SOCKADDR_COMMON_SIZE
+#ifndef __ss_aligntype
+#define __ss_aligntype unsigned long int
+#endif //__ss_aligntype
+#ifndef _SS_PADSIZE
+#define _SS_PADSIZE \
+ (_SS_SIZE - __SOCKADDR_COMMON_SIZE - sizeof (__ss_aligntype))
+#endif //_SS_PADSIZE
+struct sockaddr_storage
+ {
+ sa_family_t ss_family; /* Address family, etc. */
+ char __ss_padding[_SS_PADSIZE];
+ __ss_aligntype __ss_align; /* Force desired alignment. */
+ };
+#endif //LWIP_IPV6_MLD_V2
/* If your port already typedef's socklen_t, define SOCKLEN_T_DEFINED
to prevent this code from redefining it. */
@@ -335,6 +359,11 @@ struct linger {
*/
#define IPV6_CHECKSUM 7 /* RFC3542: calculate and insert the ICMPv6 checksum for raw sockets. */
#define IPV6_V6ONLY 27 /* RFC3493: boolean control to restrict AF_INET6 sockets to IPv6 communications only. */
+#define IPV6_RECVPKTINFO 49 /* Recv IPV6_PKTINFO message */
+#define IPV6_PKTINFO 50
+#define IPV6_RECVHOPLIMIT 51 /* Recv IPV6_HOPLIMIT message */
+#define IPV6_HOPLIMIT 52
+#define IPV6_MINHOPCNT 99
#endif /* LWIP_IPV6 */
#if LWIP_UDP && LWIP_UDPLITE
@@ -369,13 +398,24 @@ struct in_pktinfo {
};
#endif /* LWIP_IPV4 */
+#if LWIP_IPV6
+struct in6_pktinfo {
+ struct in6_addr ipi6_addr;
+ int ipi6_ifindex;
+};
+#endif /* LWIP_IPV6 */
+
#if LWIP_IPV6_MLD
+#define IPV6_UNICAST_HOPS 16 /* IPv6 ttl */
+#define IPV6_MULTICAST_IF 17 /* Set mcast ifindex, (The argument is a pointer to an interface index) */
+#define IPV6_MULTICAST_HOPS 18 /* IPv6 mcast ttl */
+#define IPV6_MULTICAST_LOOP 19 /* Mcast loop */
/*
* Options and types related to IPv6 multicast membership
*/
-#define IPV6_JOIN_GROUP 12
+#define IPV6_JOIN_GROUP 20
#define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
-#define IPV6_LEAVE_GROUP 13
+#define IPV6_LEAVE_GROUP 21
#define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP
typedef struct ipv6_mreq {
@@ -807,6 +847,7 @@ int mcast_sock_block_unblock_source_group(struct ip_mc *ipmc, int optname, c
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);
+int mcast_sock_ipv6_add_drop_membership(int s, struct ip_mc *ipmc, int optname, const struct ipv6_mreq *imr);
#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);
diff --git a/src/include/lwipopts.h b/src/include/lwipopts.h
index ab36688..396bcdf 100644
--- a/src/include/lwipopts.h
+++ b/src/include/lwipopts.h
@@ -292,4 +292,9 @@
*/
#define LWIP_IGMP_V3 1
+ /**
+ * LWIP_IPV6_MLD_V2==1: Enable multicast listener discovery protocol v2.
+ */
+#define LWIP_IPV6_MLD_V2 1
+
#endif /* __LWIPOPTS_H__ */
--
2.25.1
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。