On 18/11/13(Mon) 12:54, Alexey E. Suslikov wrote:
> Martin Pieuchot <mpieuchot <at> nolizard.org> writes:
>
> > <at> <at> -1803,8 +1651,12 <at> <at> in6_delmulti(struct in6_multi
> *in6m)
>
> <snip>
>
> > + s = splsoftnet();
> > + TAILQ_REMOVE(&ifp->if_maddrlist, &in6m->in6m_ifma, ifma_list);
> > + splx(s);
> > +
> > free(in6m, M_IPMADDR);
> > }
> > splx(s);
>
> this splx seems wrong.
Good catch! Here's and updated version, that comes with more spl love.
Index: net/if.c
===================================================================
RCS file: /home/ncvs/src/sys/net/if.c,v
retrieving revision 1.277
diff -u -p -r1.277 if.c
--- net/if.c 19 Nov 2013 09:00:43 -0000 1.277
+++ net/if.c 19 Nov 2013 10:07:24 -0000
@@ -437,8 +437,9 @@ if_attach(struct ifnet *ifp)
void
if_attach_common(struct ifnet *ifp)
{
-
TAILQ_INIT(&ifp->if_addrlist);
+ TAILQ_INIT(&ifp->if_maddrlist);
+
ifp->if_addrhooks = malloc(sizeof(*ifp->if_addrhooks),
M_TEMP, M_WAITOK);
TAILQ_INIT(ifp->if_addrhooks);
Index: net/if.h
===================================================================
RCS file: /home/ncvs/src/sys/net/if.h,v
retrieving revision 1.152
diff -u -p -r1.152 if.h
--- net/if.h 9 Nov 2013 06:38:42 -0000 1.152
+++ net/if.h 19 Nov 2013 10:07:24 -0000
@@ -262,6 +262,7 @@ struct ifnet { /* and the
entries */
TAILQ_ENTRY(ifnet) if_list; /* all struct ifnets are chained */
TAILQ_ENTRY(ifnet) if_txlist; /* list of ifnets ready to tx */
TAILQ_HEAD(, ifaddr) if_addrlist; /* linked list of addresses per if */
+ TAILQ_HEAD(, ifmaddr) if_maddrlist; /* list of multicast records */
TAILQ_HEAD(, ifg_list) if_groups; /* linked list of groups per if */
struct hook_desc_head *if_addrhooks; /* address change callbacks */
struct hook_desc_head *if_linkstatehooks; /* link change callbacks */
@@ -506,6 +507,16 @@ struct ifaddr_item {
struct ifaddr *ifai_ifa;
struct ifaddr_item *ifai_next;
u_int ifai_rdomain;
+};
+
+/*
+ * Interface multicast address.
+ */
+struct ifmaddr {
+ struct sockaddr *ifma_addr; /* Protocol address */
+ struct ifnet *ifma_ifp; /* Back pointer to ifnet */
+ unsigned int ifma_refcnt; /* Count of references */
+ TAILQ_ENTRY(ifmaddr) ifma_list; /* Per-interface list */
};
/*
Index: netinet/igmp.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet/igmp.c,v
retrieving revision 1.35
diff -u -p -r1.35 igmp.c
--- netinet/igmp.c 18 Oct 2013 09:04:02 -0000 1.35
+++ netinet/igmp.c 19 Nov 2013 10:07:24 -0000
@@ -193,6 +193,7 @@ igmp_input(struct mbuf *m, ...)
struct igmp *igmp;
int igmplen;
int minlen;
+ struct ifmaddr *ifma;
struct in_multi *inm;
struct router_info *rti;
struct in_ifaddr *ia;
@@ -266,7 +267,10 @@ igmp_input(struct mbuf *m, ...)
* except those that are already running and those
* that belong to a "local" group (224.0.0.X).
*/
- IN_FOREACH_MULTI(ia, ifp, inm) {
+ TAILQ_FOREACH(ifma, &ifp->if_maddrlist, ifma_list) {
+ if (ifma->ifma_addr->sa_family != AF_INET)
+ continue;
+ inm = ifmatoinm(ifma);
if (inm->inm_timer == 0 &&
!IN_LOCAL_GROUP(inm->inm_addr.s_addr)) {
inm->inm_state = IGMP_DELAYING_MEMBER;
@@ -294,7 +298,10 @@ igmp_input(struct mbuf *m, ...)
* timers already running, check if they need to be
* reset.
*/
- IN_FOREACH_MULTI(ia, ifp, inm) {
+ TAILQ_FOREACH(ifma, &ifp->if_maddrlist, ifma_list) {
+ if (ifma->ifma_addr->sa_family != AF_INET)
+ continue;
+ inm = ifmatoinm(ifma);
if (!IN_LOCAL_GROUP(inm->inm_addr.s_addr) &&
(ip->ip_dst.s_addr == INADDR_ALLHOSTS_GROUP
||
ip->ip_dst.s_addr ==
inm->inm_addr.s_addr)) {
@@ -479,6 +486,8 @@ void
igmp_leavegroup(struct in_multi *inm)
{
+ int s = splsoftnet();
+
switch (inm->inm_state) {
case IGMP_DELAYING_MEMBER:
case IGMP_IDLE_MEMBER:
@@ -494,6 +503,7 @@ igmp_leavegroup(struct in_multi *inm)
case IGMP_SLEEPING_MEMBER:
break;
}
+ splx(s);
}
void
@@ -521,11 +531,14 @@ void
igmp_checktimer(struct ifnet *ifp)
{
struct in_multi *inm;
- struct in_ifaddr *ia;
+ struct ifmaddr *ifma;
splsoftassert(IPL_SOFTNET);
- IN_FOREACH_MULTI(ia, ifp, inm) {
+ TAILQ_FOREACH(ifma, &ifp->if_maddrlist, ifma_list) {
+ if (ifma->ifma_addr->sa_family != AF_INET)
+ continue;
+ inm = ifmatoinm(ifma);
if (inm->inm_timer == 0) {
/* do nothing */
} else if (--inm->inm_timer == 0) {
Index: netinet/in.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet/in.c,v
retrieving revision 1.88
diff -u -p -r1.88 in.c
--- netinet/in.c 23 Oct 2013 13:39:35 -0000 1.88
+++ netinet/in.c 19 Nov 2013 10:07:24 -0000
@@ -258,7 +258,6 @@ in_control(struct socket *so, u_long cmd
ia->ia_broadaddr.sin_family = AF_INET;
}
ia->ia_ifp = ifp;
- LIST_INIT(&ia->ia_multiaddrs);
newifaddr = 1;
} else
@@ -922,8 +921,7 @@ in_addmulti(struct in_addr *ap, struct i
{
struct in_multi *inm;
struct ifreq ifr;
- struct in_ifaddr *ia;
- int s = splsoftnet();
+ int s;
/*
* See if address already in list.
@@ -933,50 +931,47 @@ in_addmulti(struct in_addr *ap, struct i
/*
* Found it; just increment the reference count.
*/
- ++inm->inm_refcount;
+ ++inm->inm_refcnt;
} else {
+ if (ifp->if_ioctl == NULL)
+ return (NULL);
+
/*
* New address; allocate a new multicast record
* and link it into the interface's multicast list.
*/
- inm = (struct in_multi *)malloc(sizeof(*inm),
- M_IPMADDR, M_NOWAIT);
- if (inm == NULL) {
- splx(s);
+ inm = malloc(sizeof(*inm), M_IPMADDR, M_NOWAIT);
+ if (inm == NULL)
return (NULL);
- }
- inm->inm_addr = *ap;
- inm->inm_refcount = 1;
- IFP_TO_IA(ifp, ia);
- if (ia == NULL) {
- free(inm, M_IPMADDR);
- splx(s);
- return (NULL);
- }
- inm->inm_ia = ia;
- ia->ia_ifa.ifa_refcnt++;
- LIST_INSERT_HEAD(&ia->ia_multiaddrs, inm, inm_list);
+
+ inm->inm_sin.sin_len = sizeof(struct sockaddr_in);
+ inm->inm_sin.sin_family = AF_INET;
+ inm->inm_sin.sin_addr = *ap;
+ inm->inm_refcnt = 1;
+ inm->inm_ifp = ifp;
+ inm->inm_ifma.ifma_addr = sintosa(&inm->inm_sin);
+
/*
* Ask the network driver to update its multicast reception
* filter appropriately for the new address.
*/
- satosin(&ifr.ifr_addr)->sin_len = sizeof(struct sockaddr_in);
- satosin(&ifr.ifr_addr)->sin_family = AF_INET;
- satosin(&ifr.ifr_addr)->sin_addr = *ap;
- if ((ifp->if_ioctl == NULL) ||
- (*ifp->if_ioctl)(ifp, SIOCADDMULTI,(caddr_t)&ifr) != 0) {
- LIST_REMOVE(inm, inm_list);
- ifafree(&inm->inm_ia->ia_ifa);
+ memcpy(&ifr.ifr_addr, &inm->inm_sin, sizeof(inm->inm_sin));
+ if ((*ifp->if_ioctl)(ifp, SIOCADDMULTI,(caddr_t)&ifr) != 0) {
free(inm, M_IPMADDR);
- splx(s);
return (NULL);
}
+
+ s = splsoftnet();
+ TAILQ_INSERT_HEAD(&ifp->if_maddrlist, &inm->inm_ifma,
+ ifma_list);
+ splx(s);
+
/*
* Let IGMP know that we have joined a new IP multicast group.
*/
igmp_joingroup(inm);
}
- splx(s);
+
return (inm);
}
@@ -988,33 +983,31 @@ in_delmulti(struct in_multi *inm)
{
struct ifreq ifr;
struct ifnet *ifp;
- int s = splsoftnet();
+ int s;
- if (--inm->inm_refcount == 0) {
+ if (--inm->inm_refcnt == 0) {
/*
* No remaining claims to this record; let IGMP know that
* we are leaving the multicast group.
*/
igmp_leavegroup(inm);
+ ifp = inm->inm_ifp;
+
/*
- * Unlink from list.
+ * Notify the network driver to update its multicast
+ * reception filter.
*/
- LIST_REMOVE(inm, inm_list);
- ifp = inm->inm_ifp;
- ifafree(&inm->inm_ia->ia_ifa);
+ satosin(&ifr.ifr_addr)->sin_len = sizeof(struct sockaddr_in);
+ satosin(&ifr.ifr_addr)->sin_family = AF_INET;
+ satosin(&ifr.ifr_addr)->sin_addr = inm->inm_addr;
+ (*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)&ifr);
+
+ s = splsoftnet();
+ TAILQ_REMOVE(&ifp->if_maddrlist, &inm->inm_ifma, ifma_list);
+ splx(s);
- if (ifp) {
- /*
- * Notify the network driver to update its multicast
- * reception filter.
- */
- satosin(&ifr.ifr_addr)->sin_family = AF_INET;
- satosin(&ifr.ifr_addr)->sin_addr = inm->inm_addr;
- (*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)&ifr);
- }
free(inm, M_IPMADDR);
}
- splx(s);
}
#endif
@@ -1023,11 +1016,20 @@ void
in_ifdetach(struct ifnet *ifp)
{
struct ifaddr *ifa, *next;
+ struct ifmaddr *ifma, *mnext;
/* nuke any of IPv4 addresses we have */
TAILQ_FOREACH_SAFE(ifa, &ifp->if_addrlist, ifa_list, next) {
if (ifa->ifa_addr->sa_family != AF_INET)
continue;
in_purgeaddr(ifa);
+ }
+
+ TAILQ_FOREACH_SAFE(ifma, &ifp->if_maddrlist, ifma_list, mnext) {
+ if (ifma->ifma_addr->sa_family != AF_INET)
+ continue;
+
+ ifma->ifma_refcnt = 1;
+ in_delmulti(ifmatoinm(ifma));
}
}
Index: netinet/in_var.h
===================================================================
RCS file: /home/ncvs/src/sys/netinet/in_var.h,v
retrieving revision 1.26
diff -u -p -r1.26 in_var.h
--- netinet/in_var.h 23 Oct 2013 15:12:42 -0000 1.26
+++ netinet/in_var.h 19 Nov 2013 10:07:24 -0000
@@ -55,7 +55,6 @@ struct in_ifaddr {
struct sockaddr_in ia_dstaddr; /* reserve space for broadcast addr */
#define ia_broadaddr ia_dstaddr
struct sockaddr_in ia_sockmask; /* reserve space for general netmask */
- LIST_HEAD(, in_multi) ia_multiaddrs; /* list of multicast addresses */
struct in_multi *ia_allhosts; /* multicast address record for
the allhosts multicast group */
};
@@ -128,32 +127,29 @@ struct router_info {
/*
* Internet multicast address structure. There is one of these for each IP
* multicast group to which this host belongs on a given network interface.
- * They are kept in a linked list, rooted in the interface's in_ifaddr
- * structure.
*/
struct in_multi {
- struct in_addr inm_addr; /* IP multicast address */
- struct in_ifaddr *inm_ia; /* back pointer to in_ifaddr */
-#define inm_ifp inm_ia->ia_ifp
- u_int inm_refcount; /* no. membership claims by sockets */
- u_int inm_timer; /* IGMP membership report timer */
- LIST_ENTRY(in_multi) inm_list; /* list of multicast addresses */
- u_int inm_state; /* state of membership */
- struct router_info *inm_rti; /* router version info */
+ struct ifmaddr inm_ifma; /* Protocol-independent info */
+#define inm_refcnt inm_ifma.ifma_refcnt
+#define inm_ifp inm_ifma.ifma_ifp
+
+ struct sockaddr_in inm_sin; /* IPv4 multicast address */
+#define inm_addr inm_sin.sin_addr
+
+ u_int inm_state; /* state of membership */
+ u_int inm_timer; /* IGMP membership report timer */
+
+ struct router_info *inm_rti; /* router version info */
};
+
#ifdef _KERNEL
-/*
- * Macro for iterating over all the in_multi records linked to a given
- * interface.
- */
-#define IN_FOREACH_MULTI(ia, ifp, inm) \
- /* struct in_ifaddr *ia; */ \
- /* struct ifnet *ifp; */ \
- /* struct in_multi *inm; */ \
- IFP_TO_IA((ifp), ia); \
- if (ia != NULL) \
- LIST_FOREACH((inm), &ia->ia_multiaddrs, inm_list) \
+
+static __inline struct in_multi *
+ifmatoinm(struct ifmaddr *ifma)
+{
+ return ((struct in_multi *)(ifma));
+}
/*
* Macro for looking up the in_multi record for a given IP multicast
@@ -165,12 +161,15 @@ struct in_multi {
/* struct ifnet *ifp; */ \
/* struct in_multi *inm; */ \
do { \
- struct in_ifaddr *ia; \
+ struct ifmaddr *ifma; \
\
(inm) = NULL; \
- IN_FOREACH_MULTI(ia, ifp, inm) \
- if ((inm)->inm_addr.s_addr == (addr).s_addr) \
+ TAILQ_FOREACH(ifma, &(ifp)->if_maddrlist, ifma_list) \
+ if (ifma->ifma_addr->sa_family == AF_INET && \
+ ifmatoinm(ifma)->inm_addr.s_addr == (addr).s_addr) {\
+ (inm) = ifmatoinm(ifma); \
break; \
+ } \
} while (/* CONSTCOND */ 0)
int in_ifinit(struct ifnet *,
Index: netinet6/in6.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet6/in6.c,v
retrieving revision 1.124
diff -u -p -r1.124 in6.c
--- netinet6/in6.c 13 Nov 2013 08:27:24 -0000 1.124
+++ netinet6/in6.c 19 Nov 2013 10:07:24 -0000
@@ -130,18 +130,6 @@ const struct sockaddr_in6 sa6_any = {
};
/*
- * This structure is used to keep track of in6_multi chains which belong to
- * deleted interface addresses.
- */
-static LIST_HEAD(, multi6_kludge) in6_mk; /* XXX BSS initialization */
-
-struct multi6_kludge {
- LIST_ENTRY(multi6_kludge) mk_entry;
- struct ifnet *mk_ifp;
- struct in6_multihead mk_head;
-};
-
-/*
* Subroutine for in6_ifaddloop() and in6_ifremloop().
* This routine does actual work.
*/
@@ -1246,10 +1234,6 @@ in6_unlink_ifa(struct in6_ifaddr *ia, st
TAILQ_REMOVE(&in6_ifaddr, ia, ia_list);
- if (!LIST_EMPTY(&ia->ia6_multiaddrs)) {
- in6_savemkludge(ia);
- }
-
/* Release the reference to the base prefix. */
if (ia->ia6_ndpr == NULL) {
char addr[INET6_ADDRSTRLEN];
@@ -1569,141 +1553,19 @@ in6_ifinit(struct ifnet *ifp, struct in6
in6_ifaddloop(&(ia->ia_ifa));
}
- if (ifp->if_flags & IFF_MULTICAST)
- in6_restoremkludge(ia, ifp);
-
return (error);
}
/*
- * Multicast address kludge:
- * If there were any multicast addresses attached to this interface address,
- * either move them to another address on this interface, or save them until
- * such time as this interface is reconfigured for IPv6.
- */
-void
-in6_savemkludge(struct in6_ifaddr *oia)
-{
- struct in6_ifaddr *ia;
- struct in6_multi *in6m, *next;
-
- IFP_TO_IA6(oia->ia_ifp, ia);
- if (ia) { /* there is another address */
- for (in6m = LIST_FIRST(&oia->ia6_multiaddrs);
- in6m != NULL; in6m = next) {
- next = LIST_NEXT(in6m, in6m_entry);
- ifafree(&in6m->in6m_ia->ia_ifa);
- ia->ia_ifa.ifa_refcnt++;
- in6m->in6m_ia = ia;
- LIST_INSERT_HEAD(&ia->ia6_multiaddrs, in6m, in6m_entry);
- }
- } else { /* last address on this if deleted, save */
- struct multi6_kludge *mk;
-
- LIST_FOREACH(mk, &in6_mk, mk_entry) {
- if (mk->mk_ifp == oia->ia_ifp)
- break;
- }
- if (mk == NULL) /* this should not happen! */
- panic("in6_savemkludge: no kludge space");
-
- for (in6m = LIST_FIRST(&oia->ia6_multiaddrs);
- in6m != NULL; in6m = next) {
- next = LIST_NEXT(in6m, in6m_entry);
- ifafree(&in6m->in6m_ia->ia_ifa); /* release reference */
- in6m->in6m_ia = NULL;
- LIST_INSERT_HEAD(&mk->mk_head, in6m, in6m_entry);
- }
- }
-}
-
-/*
- * Continuation of multicast address hack:
- * If there was a multicast group list previously saved for this interface,
- * then we re-attach it to the first address configured on the i/f.
- */
-void
-in6_restoremkludge(struct in6_ifaddr *ia, struct ifnet *ifp)
-{
- struct multi6_kludge *mk;
-
- LIST_FOREACH(mk, &in6_mk, mk_entry) {
- if (mk->mk_ifp == ifp) {
- struct in6_multi *in6m, *next;
-
- for (in6m = LIST_FIRST(&mk->mk_head); in6m != NULL;
- in6m = next) {
- next = LIST_NEXT(in6m, in6m_entry);
- in6m->in6m_ia = ia;
- ia->ia_ifa.ifa_refcnt++;
- LIST_INSERT_HEAD(&ia->ia6_multiaddrs,
- in6m, in6m_entry);
- }
- LIST_INIT(&mk->mk_head);
- break;
- }
- }
-}
-
-/*
- * Allocate space for the kludge at interface initialization time.
- * Formerly, we dynamically allocated the space in in6_savemkludge() with
- * malloc(M_WAITOK). However, it was wrong since the function could be called
- * under an interrupt context (software timer on address lifetime expiration).
- * Also, we cannot just give up allocating the strucutre, since the group
- * membership structure is very complex and we need to keep it anyway.
- * Of course, this function MUST NOT be called under an interrupt context.
- * Specifically, it is expected to be called only from in6_ifattach(), though
- * it is a global function.
- */
-void
-in6_createmkludge(struct ifnet *ifp)
-{
- struct multi6_kludge *mk;
-
- LIST_FOREACH(mk, &in6_mk, mk_entry) {
- /* If we've already had one, do not allocate. */
- if (mk->mk_ifp == ifp)
- return;
- }
-
- mk = malloc(sizeof(*mk), M_IPMADDR, M_WAITOK | M_ZERO);
-
- LIST_INIT(&mk->mk_head);
- mk->mk_ifp = ifp;
- LIST_INSERT_HEAD(&in6_mk, mk, mk_entry);
-}
-
-void
-in6_purgemkludge(struct ifnet *ifp)
-{
- struct multi6_kludge *mk;
- struct in6_multi *in6m;
-
- LIST_FOREACH(mk, &in6_mk, mk_entry) {
- if (mk->mk_ifp != ifp)
- continue;
-
- /* leave from all multicast groups joined */
- while ((in6m = LIST_FIRST(&mk->mk_head)) != NULL)
- in6_delmulti(in6m);
- LIST_REMOVE(mk, mk_entry);
- free(mk, M_IPMADDR);
- break;
- }
-}
-
-/*
* Add an address to the list of IP6 multicast addresses for a
* given interface.
*/
struct in6_multi *
in6_addmulti(struct in6_addr *maddr6, struct ifnet *ifp, int *errorp)
{
- struct in6_ifaddr *ia;
struct in6_ifreq ifr;
struct in6_multi *in6m;
- int s = splsoftnet();
+ int s;
*errorp = 0;
/*
@@ -1714,60 +1576,53 @@ in6_addmulti(struct in6_addr *maddr6, st
/*
* Found it; just increment the refrence count.
*/
- in6m->in6m_refcount++;
+ in6m->in6m_refcnt++;
} else {
+ if (ifp->if_ioctl == NULL) {
+ *errorp = ENXIO; /* XXX: appropriate? */
+ return (NULL);
+ }
+
/*
* New address; allocate a new multicast record
* and link it into the interface's multicast list.
*/
- in6m = (struct in6_multi *)
- malloc(sizeof(*in6m), M_IPMADDR, M_NOWAIT);
+ in6m = malloc(sizeof(*in6m), M_IPMADDR, M_NOWAIT);
if (in6m == NULL) {
- splx(s);
*errorp = ENOBUFS;
return (NULL);
}
- in6m->in6m_addr = *maddr6;
+
+ in6m->in6m_sin.sin6_len = sizeof(struct sockaddr_in6);
+ in6m->in6m_sin.sin6_family = AF_INET6;
+ in6m->in6m_sin.sin6_addr = *maddr6;
+ in6m->in6m_refcnt = 1;
in6m->in6m_ifp = ifp;
- in6m->in6m_refcount = 1;
- IFP_TO_IA6(ifp, ia);
- if (ia == NULL) {
- free(in6m, M_IPMADDR);
- splx(s);
- *errorp = EADDRNOTAVAIL; /* appropriate? */
- return (NULL);
- }
- in6m->in6m_ia = ia;
- ia->ia_ifa.ifa_refcnt++; /* gain a reference */
- LIST_INSERT_HEAD(&ia->ia6_multiaddrs, in6m, in6m_entry);
+ in6m->in6m_ifma.ifma_addr = sin6tosa(&in6m->in6m_sin);
/*
* Ask the network driver to update its multicast reception
* filter appropriately for the new address.
*/
- bzero(&ifr.ifr_addr, sizeof(struct sockaddr_in6));
- ifr.ifr_addr.sin6_len = sizeof(struct sockaddr_in6);
- ifr.ifr_addr.sin6_family = AF_INET6;
- ifr.ifr_addr.sin6_addr = *maddr6;
- if (ifp->if_ioctl == NULL)
- *errorp = ENXIO; /* XXX: appropriate? */
- else
- *errorp = (*ifp->if_ioctl)(ifp, SIOCADDMULTI,
- (caddr_t)&ifr);
+ memcpy(&ifr.ifr_addr, &in6m->in6m_sin, sizeof(in6m->in6m_sin));
+ *errorp = (*ifp->if_ioctl)(ifp, SIOCADDMULTI, (caddr_t)&ifr);
if (*errorp) {
- LIST_REMOVE(in6m, in6m_entry);
free(in6m, M_IPMADDR);
- ifafree(&ia->ia_ifa);
- splx(s);
return (NULL);
}
+
+ s = splsoftnet();
+ TAILQ_INSERT_HEAD(&ifp->if_maddrlist, &in6m->in6m_ifma,
+ ifma_list);
+ splx(s);
+
/*
* Let MLD6 know that we have joined a new IP6 multicast
* group.
*/
mld6_start_listening(in6m);
}
- splx(s);
+
return (in6m);
}
@@ -1778,22 +1633,16 @@ void
in6_delmulti(struct in6_multi *in6m)
{
struct in6_ifreq ifr;
- int s = splsoftnet();
+ struct ifnet *ifp;
+ int s;
- if (--in6m->in6m_refcount == 0) {
+ if (--in6m->in6m_refcnt == 0) {
/*
* No remaining claims to this record; let MLD6 know
* that we are leaving the multicast group.
*/
mld6_stop_listening(in6m);
-
- /*
- * Unlink from list.
- */
- LIST_REMOVE(in6m, in6m_entry);
- if (in6m->in6m_ia) {
- ifafree(&in6m->in6m_ia->ia_ifa); /* release reference */
- }
+ ifp = in6m->in6m_ifp;
/*
* Notify the network driver to update its multicast
@@ -1803,11 +1652,14 @@ in6_delmulti(struct in6_multi *in6m)
ifr.ifr_addr.sin6_len = sizeof(struct sockaddr_in6);
ifr.ifr_addr.sin6_family = AF_INET6;
ifr.ifr_addr.sin6_addr = in6m->in6m_addr;
- (*in6m->in6m_ifp->if_ioctl)(in6m->in6m_ifp,
- SIOCDELMULTI, (caddr_t)&ifr);
+ (*ifp->if_ioctl)(in6m->in6m_ifp, SIOCDELMULTI, (caddr_t)&ifr);
+
+ s = splsoftnet();
+ TAILQ_REMOVE(&ifp->if_maddrlist, &in6m->in6m_ifma, ifma_list);
+ splx(s);
+
free(in6m, M_IPMADDR);
}
- splx(s);
}
struct in6_multi_mship *
Index: netinet6/in6_ifattach.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet6/in6_ifattach.c,v
retrieving revision 1.63
diff -u -p -r1.63 in6_ifattach.c
--- netinet6/in6_ifattach.c 19 Nov 2013 09:00:43 -0000 1.63
+++ netinet6/in6_ifattach.c 19 Nov 2013 10:07:24 -0000
@@ -594,9 +594,6 @@ in6_ifattach(struct ifnet *ifp, struct i
return;
}
- /* create a multicast kludge storage (if we have not had one) */
- in6_createmkludge(ifp);
-
/*
* quirks based on interface type
*/
@@ -652,6 +649,7 @@ void
in6_ifdetach(struct ifnet *ifp)
{
struct ifaddr *ifa, *next;
+ struct ifmaddr *ifma, *mnext;
struct rtentry *rt;
struct sockaddr_in6 sin6;
@@ -670,8 +668,14 @@ in6_ifdetach(struct ifnet *ifp)
in6_purgeaddr(ifa);
}
- /* cleanup multicast address kludge table, if there is any */
- in6_purgemkludge(ifp);
+
+ TAILQ_FOREACH_SAFE(ifma, &ifp->if_maddrlist, ifma_list, mnext) {
+ if (ifma->ifma_addr->sa_family != AF_INET6)
+ continue;
+
+ ifma->ifma_refcnt = 1;
+ in6_delmulti(ifmatoin6m(ifma));
+ }
/*
* remove neighbor management table. we call it twice just to make
Index: netinet6/in6_var.h
===================================================================
RCS file: /home/ncvs/src/sys/netinet6/in6_var.h,v
retrieving revision 1.44
diff -u -p -r1.44 in6_var.h
--- netinet6/in6_var.h 24 Oct 2013 11:31:43 -0000 1.44
+++ netinet6/in6_var.h 19 Nov 2013 10:07:24 -0000
@@ -106,8 +106,6 @@ struct in6_ifaddr {
struct sockaddr_in6 ia_dstaddr; /* space for destination addr */
struct sockaddr_in6 ia_prefixmask; /* prefix mask */
TAILQ_ENTRY(in6_ifaddr) ia_list; /* list of IP6 addresses */
- LIST_HEAD(in6_multihead, in6_multi) ia6_multiaddrs;
- /* list of multicast addresses */
int ia6_flags;
struct in6_addrlifetime ia6_lifetime;
@@ -458,24 +456,6 @@ do {
\
} while (0)
/*
- * Macro for finding the internet address structure (in6_ifaddr) corresponding
- * to a given interface (ifnet structure).
- */
-#define IFP_TO_IA6(ifp, ia) \
-/* struct ifnet *ifp; */ \
-/* struct in6_ifaddr *ia; */ \
-do { \
- struct ifaddr *ifa; \
- TAILQ_FOREACH(ifa, &(ifp)->if_addrlist, ifa_list) { \
- if (!ifa->ifa_addr) \
- continue; \
- if (ifa->ifa_addr->sa_family == AF_INET6) \
- break; \
- } \
- (ia) = (struct in6_ifaddr *)ifa; \
-} while (0)
-
-/*
* Multi-cast membership entry. One for each group/ifp that a PCB
* belongs to.
*/
@@ -484,27 +464,23 @@ struct in6_multi_mship {
LIST_ENTRY(in6_multi_mship) i6mm_chain; /* multicast options chain */
};
-struct in6_multi {
- LIST_ENTRY(in6_multi) in6m_entry; /* list glue */
- struct in6_addr in6m_addr; /* IP6 multicast address */
- struct ifnet *in6m_ifp; /* back pointer to ifnet */
- struct in6_ifaddr *in6m_ia; /* back pointer to in6_ifaddr */
- u_int in6m_refcount; /* # membership claims by sockets */
- u_int in6m_state; /* state of the membership */
- u_int in6m_timer; /* MLD6 listener report timer */
-};
-
-/*
- * Macro for iterating over all the in6_multi records linked to a given
- * interface.
- */
-#define IN6_FOREACH_MULTI(ia, ifp, in6m) \
- /* struct in6_ifaddr *ia; */ \
- /* struct ifnet *ifp; */ \
- /* struct in6_multi *in6m; */ \
- IFP_TO_IA6((ifp), ia); \
- if (ia != NULL) \
- LIST_FOREACH((in6m), &ia->ia6_multiaddrs, in6m_entry) \
+struct in6_multi {
+ struct ifmaddr in6m_ifma; /* Protocol-independent info */
+#define in6m_refcnt in6m_ifma.ifma_refcnt
+#define in6m_ifp in6m_ifma.ifma_ifp
+
+ struct sockaddr_in6 in6m_sin; /* IPv6 multicast address */
+#define in6m_addr in6m_sin.sin6_addr
+
+ u_int in6m_state; /* state of membership */
+ u_int in6m_timer; /* MLD6 membership report timer */
+};
+
+static __inline struct in6_multi *
+ifmatoin6m(struct ifmaddr *ifma)
+{
+ return ((struct in6_multi *)(ifma));
+}
/*
* Macros for looking up the in6_multi record for a given IP6 multicast
@@ -516,12 +492,16 @@ struct in6_multi {
/* struct ifnet *ifp; */ \
/* struct in6_multi *in6m; */ \
do { \
- struct in6_ifaddr *ia; \
+ struct ifmaddr *ifma; \
\
(in6m) = NULL; \
- IN6_FOREACH_MULTI(ia, ifp, in6m) \
- if (IN6_ARE_ADDR_EQUAL(&(in6m)->in6m_addr, &(addr))) \
+ TAILQ_FOREACH(ifma, &(ifp)->if_maddrlist, ifma_list) \
+ if (ifma->ifma_addr->sa_family == AF_INET6 && \
+ IN6_ARE_ADDR_EQUAL(&ifmatoin6m(ifma)->in6m_addr, \
+ &(addr))) { \
+ (in6m) = ifmatoin6m(ifma); \
break; \
+ } \
} while (/* CONSTCOND */ 0)
struct in6_multi *in6_addmulti(struct in6_addr *, struct ifnet *, int *);
@@ -534,13 +514,9 @@ int in6_update_ifa(struct ifnet *, struc
struct in6_ifaddr *);
void in6_purgeaddr(struct ifaddr *);
int in6if_do_dad(struct ifnet *);
-void in6_savemkludge(struct in6_ifaddr *);
void in6_setmaxmtu(void);
void *in6_domifattach(struct ifnet *);
void in6_domifdetach(struct ifnet *, void *);
-void in6_restoremkludge(struct in6_ifaddr *, struct ifnet *);
-void in6_createmkludge(struct ifnet *);
-void in6_purgemkludge(struct ifnet *);
struct in6_ifaddr *in6ifa_ifpforlinklocal(struct ifnet *, int);
struct in6_ifaddr *in6ifa_ifpwithaddr(struct ifnet *, struct in6_addr *);
int in6_ifpprefix(const struct ifnet *, const struct in6_addr *);
Index: netinet6/mld6.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet6/mld6.c,v
retrieving revision 1.33
diff -u -p -r1.33 mld6.c
--- netinet6/mld6.c 14 Nov 2013 23:30:23 -0000 1.33
+++ netinet6/mld6.c 19 Nov 2013 10:07:24 -0000
@@ -146,6 +146,8 @@ mld6_start_listening(struct in6_multi *i
void
mld6_stop_listening(struct in6_multi *in6m)
{
+ int s = splsoftnet();
+
mld_all_nodes_linklocal.s6_addr16[1] =
htons(in6m->in6m_ifp->if_index); /* XXX */
mld_all_routers_linklocal.s6_addr16[1] =
@@ -156,6 +158,7 @@ mld6_stop_listening(struct in6_multi *in
__IPV6_ADDR_MC_SCOPE(&in6m->in6m_addr) >
__IPV6_ADDR_SCOPE_INTFACELOCAL)
mld6_sendpkt(in6m, MLD_LISTENER_DONE,
&mld_all_routers_linklocal);
+ splx(s);
}
void
@@ -165,7 +168,7 @@ mld6_input(struct mbuf *m, int off)
struct mld_hdr *mldh;
struct ifnet *ifp = m->m_pkthdr.rcvif;
struct in6_multi *in6m;
- struct in6_ifaddr *ia;
+ struct ifmaddr *ifma;
int timer; /* timer value in the MLD query header */
IP6_EXTHDR_GET(mldh, struct mld_hdr *, m, off, sizeof(*mldh));
@@ -227,9 +230,6 @@ mld6_input(struct mbuf *m, int off)
* - Use the value specified in the query message as
* the maximum timeout.
*/
- IFP_TO_IA6(ifp, ia);
- if (ia == NULL)
- break;
/*
* XXX: System timer resolution is too low to handle Max
@@ -243,7 +243,10 @@ mld6_input(struct mbuf *m, int off)
mld_all_nodes_linklocal.s6_addr16[1] =
htons(ifp->if_index); /* XXX */
- LIST_FOREACH(in6m, &ia->ia6_multiaddrs, in6m_entry) {
+ TAILQ_FOREACH(ifma, &ifp->if_maddrlist, ifma_list) {
+ if (ifma->ifma_addr->sa_family != AF_INET6)
+ continue;
+ in6m = ifmatoin6m(ifma);
if (IN6_ARE_ADDR_EQUAL(&in6m->in6m_addr,
&mld_all_nodes_linklocal) ||
__IPV6_ADDR_MC_SCOPE(&in6m->in6m_addr) <
@@ -343,11 +346,14 @@ void
mld6_checktimer(struct ifnet *ifp)
{
struct in6_multi *in6m;
- struct in6_ifaddr *ia;
+ struct ifmaddr *ifma;
splsoftassert(IPL_SOFTNET);
- IN6_FOREACH_MULTI(ia, ifp, in6m) {
+ TAILQ_FOREACH(ifma, &ifp->if_maddrlist, ifma_list) {
+ if (ifma->ifma_addr->sa_family != AF_INET6)
+ continue;
+ in6m = ifmatoin6m(ifma);
if (in6m->in6m_timer == 0) {
/* do nothing */
} else if (--in6m->in6m_timer == 0) {