diff options
Diffstat (limited to 'sys/netinet6')
| -rw-r--r-- | sys/netinet6/in6_ifattach.c | 7 | ||||
| -rw-r--r-- | sys/netinet6/in6_pcb.c | 39 | ||||
| -rw-r--r-- | sys/netinet6/in6_pcb.h | 1 |
3 files changed, 47 insertions, 0 deletions
diff --git a/sys/netinet6/in6_ifattach.c b/sys/netinet6/in6_ifattach.c index 516826d76b38..3e41bd7ca8f6 100644 --- a/sys/netinet6/in6_ifattach.c +++ b/sys/netinet6/in6_ifattach.c @@ -47,10 +47,12 @@ #include <netinet/in.h> #include <netinet/in_var.h> #include <netinet/if_ether.h> +#include <netinet/in_pcb.h> #include <netinet/ip6.h> #include <netinet6/ip6_var.h> #include <netinet6/in6_var.h> +#include <netinet6/in6_pcb.h> #include <netinet6/in6_ifattach.h> #include <netinet6/ip6_var.h> #include <netinet6/nd6.h> @@ -72,6 +74,9 @@ int ip6_auto_linklocal = 1; /* enable by default */ struct callout in6_tmpaddrtimer_ch; +extern struct inpcbinfo udbinfo; +extern struct inpcbinfo ripcbinfo; + static int get_rand_ifid __P((struct ifnet *, struct in6_addr *)); static int generate_tmp_ifid __P((u_int8_t *, const u_int8_t *, u_int8_t *)); static int get_hw_ifid __P((struct ifnet *, struct in6_addr *)); @@ -942,6 +947,8 @@ in6_ifdetach(ifp) } /* leave from all multicast groups joined */ + in6_pcbpurgeif0(LIST_FIRST(udbinfo.listhead), ifp); + in6_pcbpurgeif0(LIST_FIRST(ripcbinfo.listhead), ifp); for (in6m = LIST_FIRST(&in6_multihead); in6m; in6m = in6m_next) { in6m_next = LIST_NEXT(in6m, in6m_entry); if (in6m->in6m_ifp != ifp) diff --git a/sys/netinet6/in6_pcb.c b/sys/netinet6/in6_pcb.c index 9175a65431fa..de4f1a82f599 100644 --- a/sys/netinet6/in6_pcb.c +++ b/sys/netinet6/in6_pcb.c @@ -932,6 +932,45 @@ in6_pcblookup_local(pcbinfo, laddr, lport_arg, wild_okay) } } +void +in6_pcbpurgeif0(head, ifp) + struct in6pcb *head; + struct ifnet *ifp; +{ + struct in6pcb *in6p; + struct ip6_moptions *im6o; + struct in6_multi_mship *imm, *nimm; + + for (in6p = head; in6p != NULL; in6p = LIST_NEXT(in6p, inp_list)) { + im6o = in6p->in6p_moptions; + if ((in6p->inp_vflag & INP_IPV6) && + im6o) { + /* + * Unselect the outgoing interface if it is being + * detached. + */ + if (im6o->im6o_multicast_ifp == ifp) + im6o->im6o_multicast_ifp = NULL; + + /* + * Drop multicast group membership if we joined + * through the interface being detached. + * XXX controversial - is it really legal for kernel + * to force this? + */ + for (imm = im6o->im6o_memberships.lh_first; + imm != NULL; imm = nimm) { + nimm = imm->i6mm_chain.le_next; + if (imm->i6mm_maddr->in6m_ifp == ifp) { + LIST_REMOVE(imm, i6mm_chain); + in6_delmulti(imm->i6mm_maddr); + free(imm, M_IPMADDR); + } + } + } + } +} + /* * Check for alternatives when higher level complains * about service problems. For now, invalidate cached diff --git a/sys/netinet6/in6_pcb.h b/sys/netinet6/in6_pcb.h index 15cd033ff0a2..df8e2c883e3a 100644 --- a/sys/netinet6/in6_pcb.h +++ b/sys/netinet6/in6_pcb.h @@ -74,6 +74,7 @@ #define sin6tosa(sin6) ((struct sockaddr *)(sin6)) #define ifatoia6(ifa) ((struct in6_ifaddr *)(ifa)) +void in6_pcbpurgeif0 __P((struct in6pcb *, struct ifnet *)); void in6_losing __P((struct inpcb *)); int in6_pcballoc __P((struct socket *, struct inpcbinfo *, struct proc *)); int in6_pcbbind __P((struct inpcb *, struct sockaddr *, struct proc *)); |
