Subject: Re: kern/29580
To: None <kern-bug-people@netbsd.org, gnats-admin@netbsd.org,>
From: Greg Troxel <gdt@ir.bbn.com>
List: netbsd-bugs
Date: 05/12/2005 17:18:01
The following reply was made to PR kern/29580; it has been noted by GNATS.
From: Greg Troxel <gdt@ir.bbn.com>
To: gnats-bugs@netbsd.org
Cc:
Subject: Re: kern/29580
Date: Thu, 12 May 2005 13:16:38 -0400
The following patch causes PRU_PURGEIF to be invoked even if no
addresses are configured. This may not include all protocols that
might store pointers, but does include the common INET/INET6 ones.
Index: sys/protosw.h
===================================================================
RCS file: /SINEW-CVS/netbsd/src/sys/sys/protosw.h,v
retrieving revision 1.1.1.3
diff -u -r1.1.1.3 protosw.h
--- sys/protosw.h 22 Apr 2004 01:34:17 -0000 1.1.1.3
+++ sys/protosw.h 12 May 2005 17:09:02 -0000
@@ -114,6 +114,9 @@
#define PR_LASTHDR 0x40 /* enforce ipsec policy; last header */
#define PR_ABRTACPTDIS 0x80 /* abort on accept(2) to disconnected
socket */
+#define PR_PURGEIF 0x100 /* might store struct ifnet pointer;
+ PRU_PURGEIF must be called on ifnet
+ deletion */
/*
* The arguments to usrreq are:
Index: net/if.c
===================================================================
RCS file: /SINEW-CVS/netbsd/src/sys/net/if.c,v
retrieving revision 1.4
diff -u -r1.4 if.c
--- net/if.c 4 Feb 2005 14:57:25 -0000 1.4
+++ net/if.c 12 May 2005 17:09:02 -0000
@@ -647,10 +647,39 @@
(void) (*rnh->rnh_walktree)(rnh, if_rt_walktree, ifp);
}
+ /*
+ * Perhaps this should remove multicast memberships, but inet
+ * domain does not have a dom_ifdetach function.
+ */
DOMAIN_FOREACH(dp) {
if (dp->dom_ifdetach && ifp->if_afdata[dp->dom_family])
(*dp->dom_ifdetach)(ifp,
ifp->if_afdata[dp->dom_family]);
+
+ /*
+ * One would expect multicast memberships (INET and
+ * INET6) on UDP sockets to be purged by the PURGEIF
+ * calls above, but if all addresses were removed from
+ * the interface prior to destruction, the calls will
+ * not be made (e.g. ppp, for which pppd(8) generally
+ * removees addresses before destroying the
+ * interface). Because there is no invariant that
+ * multicast memberships only exist for interfaces
+ * with IPv4 addresses, we must call PURGEIF
+ * regardless of addresses. Protocols which might
+ * store ifnet pointers are marked with PR_PURGEIF.
+ */
+ for (pr = dp->dom_protosw;
+ pr < dp->dom_protoswNPROTOSW; pr++) {
+ so.so_proto = pr;
+ if (pr->pr_usrreq != NULL &&
+ pr->pr_flags & PR_PURGEIF) {
+ (void) (*pr->pr_usrreq)(&so,
+ PRU_PURGEIF, NULL, NULL,
+ (struct mbuf *) ifp, curproc);
+ purged = 1;
+ }
+ }
}
/* Announce that the interface is gone. */
Index: netinet/in_proto.c
===================================================================
RCS file: /SINEW-CVS/netbsd/src/sys/netinet/in_proto.c,v
retrieving revision 1.1.1.3
diff -u -r1.1.1.3 in_proto.c
--- netinet/in_proto.c 31 Jan 2005 23:49:36 -0000 1.1.1.3
+++ netinet/in_proto.c 12 May 2005 17:09:02 -0000
@@ -156,17 +156,17 @@
0,
ip_init, 0, ip_slowtimo, ip_drain, NULL
},
-{ SOCK_DGRAM, &inetdomain, IPPROTO_UDP, PR_ATOMIC|PR_ADDR,
+{ SOCK_DGRAM, &inetdomain, IPPROTO_UDP, PR_ATOMIC|PR_ADDR|PR_PURGEIF,
udp_input, 0, udp_ctlinput, ip_ctloutput,
udp_usrreq,
udp_init, 0, 0, 0, NULL
},
-{ SOCK_STREAM, &inetdomain, IPPROTO_TCP, PR_CONNREQUIRED|PR_WANTRCVD|PR_LISTEN|PR_ABRTACPTDIS,
+{ SOCK_STREAM, &inetdomain, IPPROTO_TCP, PR_CONNREQUIRED|PR_WANTRCVD|PR_LISTEN|PR_ABRTACPTDIS|PR_PURGEIF,
tcp_input, 0, tcp_ctlinput, tcp_ctloutput,
tcp_usrreq,
tcp_init, 0, tcp_slowtimo, tcp_drain, NULL
},
-{ SOCK_RAW, &inetdomain, IPPROTO_RAW, PR_ATOMIC|PR_ADDR,
+{ SOCK_RAW, &inetdomain, IPPROTO_RAW, PR_ATOMIC|PR_ADDR|PR_PURGEIF,
rip_input, rip_output, rip_ctlinput, rip_ctloutput,
rip_usrreq,
0, 0, 0, 0,
Index: netinet6/in6_proto.c
===================================================================
RCS file: /SINEW-CVS/netbsd/src/sys/netinet6/in6_proto.c,v
retrieving revision 1.1.1.3
diff -u -r1.1.1.3 in6_proto.c
--- netinet6/in6_proto.c 23 Jan 2005 18:41:57 -0000 1.1.1.3
+++ netinet6/in6_proto.c 12 May 2005 17:09:02 -0000
@@ -136,13 +136,13 @@
ip6_init, 0, frag6_slowtimo, frag6_drain,
NULL,
},
-{ SOCK_DGRAM, &inet6domain, IPPROTO_UDP, PR_ATOMIC|PR_ADDR,
+{ SOCK_DGRAM, &inet6domain, IPPROTO_UDP, PR_ATOMIC|PR_ADDR|PR_PURGEIF,
udp6_input, 0, udp6_ctlinput, ip6_ctloutput,
udp6_usrreq, udp6_init,
0, 0, 0,
NULL,
},
-{ SOCK_STREAM, &inet6domain, IPPROTO_TCP, PR_CONNREQUIRED|PR_WANTRCVD|PR_LISTEN|PR_ABRTACPTDIS,
+{ SOCK_STREAM, &inet6domain, IPPROTO_TCP, PR_CONNREQUIRED|PR_WANTRCVD|PR_LISTEN|PR_ABRTACPTDIS|PR_PURGEIF,
tcp6_input, 0, tcp6_ctlinput, tcp_ctloutput,
tcp_usrreq,
#ifdef INET /* don't call initialization and timeout routines twice */
@@ -152,7 +152,7 @@
#endif
NULL,
},
-{ SOCK_RAW, &inet6domain, IPPROTO_RAW, PR_ATOMIC|PR_ADDR,
+{ SOCK_RAW, &inet6domain, IPPROTO_RAW, PR_ATOMIC|PR_ADDR|PR_PURGEIF,
rip6_input, rip6_output, rip6_ctlinput, rip6_ctloutput,
rip6_usrreq,
0, 0, 0, 0,