From inoue@tcs.dnsalias.org  Tue Jul 31 01:22:37 2001
Return-Path: <inoue@tcs.dnsalias.org>
Received: from router.tcs.dnsalias.org (ip167-211.fli-ykh.psinet.ne.jp [210.129.167.211])
	by hub.freebsd.org (Postfix) with ESMTP id A70C037B403
	for <FreeBSD-gnats-submit@freebsd.org>; Tue, 31 Jul 2001 01:22:34 -0700 (PDT)
	(envelope-from inoue@tcs.dnsalias.org)
Received: (from inoue@localhost)
	by router.tcs.dnsalias.org (8.11.4/3.7Wpl2/01032921) id f6V8QjX45246;
	Tue, 31 Jul 2001 17:26:45 +0900 (JST)
Message-Id: <200107310826.f6V8QjX45246@router.tcs.dnsalias.org>
Date: Tue, 31 Jul 2001 17:26:45 +0900 (JST)
From: inoue@nd.net.fujitsu.co.jp
Reply-To: inoue@nd.net.fujitsu.co.jp
To: FreeBSD-gnats-submit@freebsd.org
Cc: inoue@nd.net.fujitsu.co.jp
Subject: freebsd can crash after removing a network card
X-Send-Pr-Version: 3.113
X-GNATS-Notify:

>Number:         29345
>Category:       kern
>Synopsis:       freebsd can crash after removing a network card
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    ume
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Tue Jul 31 01:30:01 PDT 2001
>Closed-Date:    Sat Aug 4 10:31:32 PDT 2001
>Last-Modified:  Sat Aug 04 10:33:19 PDT 2001
>Originator:     Inoue Yuichi
>Release:        FreeBSD 5.0-CURRENT-20010729-JPSNAP
>Organization:
FUJITSU
>Environment:
	FreeBSD dhcp022158141.nd.net.fujitsu.co.jp
	5.0-CURRENT-20010729-JPSNAP FreeBSD 5.0-CURRENT-20010729-JPSNAP #1:
	Tue Jul 31 12:56:22 JST 2001
	inoue@dhcp022158141.nd.net.fujitsu.co.jp:
	/usr/src/sys/i386/compile/GENERIC i386

	FreeBSD 4.3-RELEASE
>Description:
	When running aplication joined multicast address,
	removing network card, and kill aplication.
	imo_membership[].inm_ifp refer interface pointer
	after removing interface.
	When kill aplication, release socket,and imo_membership.
	imo_membership use already not exist interface pointer.
	Then, kernel panic.
>How-To-Repeat:
	shell> route6d
	removing a netword card
	shell> kill `cat /var/run/route6d`
	kernel panic
>Fix:
--- netinet.patch ---
diff -uNr netinet/in.c /usr/src/sys/netinet/in.c
--- netinet/in.c	Tue Jul 31 14:04:40 2001
+++ /usr/src/sys/netinet/in.c	Tue Jul 31 12:54:46 2001
@@ -48,6 +48,7 @@
 
 #include <netinet/in.h>
 #include <netinet/in_var.h>
+#include <netinet/in_pcb.h>
 
 #include <netinet/igmp_var.h>
 
@@ -68,6 +69,9 @@
 
 struct in_multihead in_multihead; /* XXX BSS initialization */
 
+extern struct inpcbinfo ripcbinfo;
+extern struct inpcbinfo udbinfo;
+
 /*
  * Return 1 if an internet address is for a ``local'' host
  * (one to which we have a connection).  If subnetsarelocal
@@ -402,6 +406,14 @@
 		 * a routing process they will come back.
 		 */
 		in_ifadown(&ia->ia_ifa, 1);
+		/*
+		 * XXX horrible hack to detect that we are being called
+		 * from if_detach()
+		 */
+		if (!ifnet_addrs[ifp->if_index - 1]) {
+			in_pcbpurgeif0(LIST_FIRST(ripcbinfo.listhead), ifp);
+			in_pcbpurgeif0(LIST_FIRST(udbinfo.listhead), ifp);
+		}
 
 		/*
 		 * Protect from ipintr() traversing address list
diff -uNr netinet/in_pcb.c /usr/src/sys/netinet/in_pcb.c
--- netinet/in_pcb.c	Tue Jul 31 14:04:40 2001
+++ /usr/src/sys/netinet/in_pcb.c	Tue Jul 31 12:53:05 2001
@@ -689,6 +689,44 @@
 	splx(s);
 }
 
+void
+in_pcbpurgeif0(head, ifp)
+	struct inpcb *head;
+	struct ifnet *ifp;
+{
+	struct inpcb *inp;
+	struct ip_moptions *imo;
+	int i, gap;
+
+	for (inp = head; inp != NULL; inp = LIST_NEXT(inp, inp_list)) {
+		imo = inp->inp_moptions;
+		if ((inp->inp_vflag & INP_IPV4) &&
+		    imo != NULL) {
+			/*
+			 * Unselect the outgoing interface if it is being
+			 * detached.
+			 */
+			if (imo->imo_multicast_ifp == ifp)
+				imo->imo_multicast_ifp = NULL;
+
+			/*
+			 * Drop multicast group membership if we joined
+			 * through the interface being detached.
+			 */
+			for (i = 0, gap = 0; i < imo->imo_num_memberships;
+			    i++) {
+				if (imo->imo_membership[i]->inm_ifp == ifp) {
+					in_delmulti(imo->imo_membership[i]);
+					gap++;
+				} else if (gap != 0)
+					imo->imo_membership[i - gap] =
+					    imo->imo_membership[i];
+			}
+			imo->imo_num_memberships -= gap;
+		}
+	}
+}
+
 /*
  * Check for alternatives when higher level complains
  * about service problems.  For now, invalidate cached
diff -uNr netinet/in_pcb.h /usr/src/sys/netinet/in_pcb.h
--- netinet/in_pcb.h	Tue Jul 31 14:04:40 2001
+++ /usr/src/sys/netinet/in_pcb.h	Tue Jul 31 12:53:05 2001
@@ -275,6 +275,7 @@
 extern int	ipport_hifirstauto;
 extern int	ipport_hilastauto;
 
+void	in_pcbpurgeif0 __P((struct inpcb *, struct ifnet *));
 void	in_losing __P((struct inpcb *));
 void	in_rtchange __P((struct inpcb *, int));
 int	in_pcballoc __P((struct socket *, struct inpcbinfo *, struct proc *));
--- netinet.patch ---

--- netinet6.patch ---
diff -uNr netinet6/in6_ifattach.c /usr/src/sys/netinet6/in6_ifattach.c
--- netinet6/in6_ifattach.c	Tue Jul 31 14:04:47 2001
+++ /usr/src/sys/netinet6/in6_ifattach.c	Tue Jul 31 12:55:52 2001
@@ -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 @@
 
 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 @@
 	}
 
 	/* 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 -uNr netinet6/in6_pcb.c /usr/src/sys/netinet6/in6_pcb.c
--- netinet6/in6_pcb.c	Tue Jul 31 14:04:47 2001
+++ /usr/src/sys/netinet6/in6_pcb.c	Tue Jul 31 12:53:10 2001
@@ -932,6 +932,45 @@
 	}
 }
 
+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 -uNr netinet6/in6_pcb.h /usr/src/sys/netinet6/in6_pcb.h
--- netinet6/in6_pcb.h	Tue Jul 31 14:04:47 2001
+++ /usr/src/sys/netinet6/in6_pcb.h	Tue Jul 31 12:53:10 2001
@@ -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 *));
--- netinet6.patch ---
>Release-Note:
>Audit-Trail:
State-Changed-From-To: open->closed 
State-Changed-By: ume 
State-Changed-When: Sat Aug 4 10:31:32 PDT 2001 
State-Changed-Why:  
Thanks!  I just committed it. 


Responsible-Changed-From-To: freebsd-bugs->ume 
Responsible-Changed-By: ume 
Responsible-Changed-When: Sat Aug 4 10:31:32 PDT 2001 
Responsible-Changed-Why:  
Because it is KAME related and I committed it. 

http://www.FreeBSD.org/cgi/query-pr.cgi?pr=29345 
>Unformatted:
