Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys First-draft if_detach() implementation, originally from ...



details:   https://anonhg.NetBSD.org/src/rev/4fb9c0b6e7c9
branches:  trunk
changeset: 481549:4fb9c0b6e7c9
user:      thorpej <thorpej%NetBSD.org@localhost>
date:      Tue Feb 01 22:52:04 2000 +0000

description:
First-draft if_detach() implementation, originally from Bill Studnemund,
although this version has been changed somewhat:
- reference counting on ifaddrs isn't as complete as Bill's original
  work was.  This is hard to get right, and we should attack one
  protocol at a time.
- This doesn't do reference counting or dynamic allocation of ifnets yet.
- This version introduces a new PRU -- PRU_PURGEADDR, which is used to
  purge an ifaddr from a protocol.  The old method Bill used didn't work
  on all protocols, and it only worked on some because it was Very Lucky.

This mostly works ... i.e. works for my USB Ethernet, except for a dangling
ifaddr reference left by the IPv6 code; have not yet tracked this down.

diffstat:

 sys/net/if.c                |  419 +++++++++++++++++++++++++++++++++++++------
 sys/net/if.h                |  101 +++++++++-
 sys/net/if_ethersubr.c      |   10 +-
 sys/net/route.c             |   19 +-
 sys/net/rtsock.c            |   33 +-
 sys/netatalk/at_control.c   |   38 ++-
 sys/netatalk/at_extern.h    |    4 +-
 sys/netatalk/ddp_usrreq.c   |    6 +-
 sys/netccitt/hd_subr.c      |    3 +-
 sys/netccitt/pk_input.c     |    6 +-
 sys/netccitt/pk_usrreq.c    |    3 +-
 sys/netinet/in.c            |   29 ++-
 sys/netinet/in_var.h        |    5 +-
 sys/netinet/raw_ip.c        |    7 +-
 sys/netinet/tcp_usrreq.c    |    7 +-
 sys/netinet/udp_usrreq.c    |    7 +-
 sys/netinet6/in6.c          |  138 ++++++++-----
 sys/netinet6/in6_ifattach.c |    8 +-
 sys/netinet6/in6_var.h      |    3 +-
 sys/netinet6/nd6.c          |    6 +-
 sys/netinet6/nd6_nbr.c      |   10 +-
 sys/netinet6/nd6_rtr.c      |    7 +-
 sys/netinet6/raw_ip6.c      |    7 +-
 sys/netinet6/udp6_usrreq.c  |    7 +-
 sys/netiso/cltp_usrreq.c    |    7 +-
 sys/netiso/iso.c            |   23 +-
 sys/netiso/iso_var.h        |    3 +-
 sys/netns/idp_usrreq.c      |    7 +-
 sys/netns/ns.c              |   35 ++-
 sys/netns/spp_usrreq.c      |    7 +-
 sys/sys/protosw.h           |    7 +-
 31 files changed, 754 insertions(+), 218 deletions(-)

diffs (truncated from 1835 to 300 lines):

diff -r d94437932e73 -r 4fb9c0b6e7c9 sys/net/if.c
--- a/sys/net/if.c      Tue Feb 01 22:39:51 2000 +0000
+++ b/sys/net/if.c      Tue Feb 01 22:52:04 2000 +0000
@@ -1,4 +1,40 @@
-/*     $NetBSD: if.c,v 1.52 1999/09/29 22:42:02 thorpej Exp $  */
+/*     $NetBSD: if.c,v 1.53 2000/02/01 22:52:04 thorpej Exp $  */
+
+/*-
+ * Copyright (c) 1999, 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by William Studnemund and Jason R. Thorpe.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the NetBSD
+ *     Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -85,6 +121,7 @@
 #include <net/if_dl.h>
 #include <net/if_types.h>
 #include <net/radix.h>
+#include <net/route.h>
 #ifdef NETATALK
 #include <netatalk/at_extern.h>
 #include <netatalk/at.h>
@@ -106,6 +143,8 @@
 extern void nd6_setmtu __P((struct ifnet *));
 #endif 
 
+int    if_rt_walktree __P((struct radix_node *, void *));
+
 /*
  * Network interface utility routines.
  *
@@ -119,6 +158,81 @@
        if_slowtimo(NULL);
 }
 
+/*
+ * Null routines used while an interface is going away.  These routines
+ * just return an error.
+ */
+int    if_nulloutput __P((struct ifnet *, struct mbuf *,
+           struct sockaddr *, struct rtentry *));
+void   if_nullinput __P((struct ifnet *, struct mbuf *));
+void   if_nullstart __P((struct ifnet *));
+int    if_nullioctl __P((struct ifnet *, u_long, caddr_t));
+int    if_nullreset __P((struct ifnet *));
+void   if_nullwatchdog __P((struct ifnet *));
+void   if_nulldrain __P((struct ifnet *));
+
+int
+if_nulloutput(ifp, m, so, rt)
+       struct ifnet *ifp;
+       struct mbuf *m;
+       struct sockaddr *so;
+       struct rtentry *rt;
+{
+
+       return (ENXIO);
+}
+
+void
+if_nullinput(ifp, m)
+       struct ifnet *ifp;
+       struct mbuf *m;
+{
+
+       /* Nothing. */
+}
+
+void
+if_nullstart(ifp)
+       struct ifnet *ifp;
+{
+
+       /* Nothing. */
+}
+
+int
+if_nullioctl(ifp, cmd, data)
+       struct ifnet *ifp;
+       u_long cmd;
+       caddr_t data;
+{
+
+       return (ENXIO);
+}
+
+int
+if_nullreset(ifp)
+       struct ifnet *ifp;
+{
+
+       return (ENXIO);
+}
+
+void
+if_nullwatchdog(ifp)
+       struct ifnet *ifp;
+{
+
+       /* Nothing. */
+}
+
+void
+if_nulldrain(ifp)
+       struct ifnet *ifp;
+{
+
+       /* Nothing. */
+}
+
 int if_index = 0;
 struct ifaddr **ifnet_addrs = NULL;
 struct ifnet **ifindex2ifnet = NULL;
@@ -149,11 +263,12 @@
         *      struct ifadd **ifnet_addrs
         *      struct ifnet **ifindex2ifnet
         */
-       if (ifnet_addrs == 0 || ifindex2ifnet == 0 || if_index >= if_indexlim) {
+       if (ifnet_addrs == 0 || ifindex2ifnet == 0 ||
+           ifp->if_index >= if_indexlim) {
                size_t n;
                caddr_t q;
                
-               while (if_index >= if_indexlim)
+               while (ifp->if_index >= if_indexlim)
                        if_indexlim <<= 1;
 
                /* grow ifnet_addrs */
@@ -177,7 +292,7 @@
                ifindex2ifnet = (struct ifnet **)q;
        }
 
-       ifindex2ifnet[if_index] = ifp;
+       ifindex2ifnet[ifp->if_index] = ifp;
 
        /*
         * create a Link Level name for this device
@@ -199,10 +314,12 @@
        sdl->sdl_nlen = namelen;
        sdl->sdl_index = ifp->if_index;
        sdl->sdl_type = ifp->if_type;
-       ifnet_addrs[if_index] = ifa;
+       ifnet_addrs[ifp->if_index] = ifa;
+       IFAREF(ifa);
        ifa->ifa_ifp = ifp;
        ifa->ifa_rtrequest = link_rtrequest;
        TAILQ_INSERT_HEAD(&ifp->if_addrlist, ifa, ifa_list);
+       IFAREF(ifa);
        ifa->ifa_addr = (struct sockaddr *)sdl;
        ifp->if_sadl = sdl;
        sdl = (struct sockaddr_dl *)(socksize + (caddr_t)sdl);
@@ -214,6 +331,144 @@
            ifp->if_snd.ifq_maxlen = ifqmaxlen;
        ifp->if_broadcastaddr = 0; /* reliably crash if used uninitialized */
 }
+
+/*
+ * Deactivate an interface.  This points all of the procedure
+ * handles at error stubs.  May be called from interrupt context.
+ */
+void
+if_deactivate(ifp)
+       struct ifnet *ifp;
+{
+       int s;
+
+       s = splimp();
+
+       ifp->if_output   = if_nulloutput;
+       ifp->if_input    = if_nullinput;
+       ifp->if_start    = if_nullstart;
+       ifp->if_ioctl    = if_nullioctl;
+       ifp->if_reset    = if_nullreset;
+       ifp->if_watchdog = if_nullwatchdog;
+       ifp->if_drain    = if_nulldrain;
+
+       /* No more packets may be enqueued. */
+       ifp->if_snd.ifq_maxlen = 0;
+
+       splx(s);
+}
+
+/*
+ * Detach an interface from the list of "active" interfaces,
+ * freeing any resources as we go along.
+ *
+ * NOTE: This routine must be called with a valid thread context,
+ * as it may block.
+ */
+void
+if_detach(ifp)
+       struct ifnet *ifp;
+{
+       struct ifaddr *ifa;
+#ifdef IFAREF_DEBUG
+       struct ifaddr *last_ifa = NULL;
+#endif
+       struct protosw *pr;
+       struct socket so;
+       struct radix_node_head *rnh;
+       int s, i;
+
+       /* XXX Rethink this part. */
+       so.so_type = SOCK_DGRAM;
+       so.so_options = 0;
+       so.so_linger = 0;
+       so.so_state = SS_NOFDREF | SS_CANTSENDMORE | SS_CANTRCVMORE;
+       so.so_pcb = 0;
+       so.so_head = 0;
+       TAILQ_INIT(&so.so_q0);
+       TAILQ_INIT(&so.so_q);
+
+       so.so_q0len = so.so_qlen = so.so_qlimit = 0;
+       so.so_timeo = so.so_oobmark = 0;
+
+       s = splimp();
+
+       /*
+        * Do an if_down() to give protocols a chance to do something.
+        */
+       if_down(ifp);
+
+       /*
+        * Rip all the addresses off the interface.  This should make
+        * all of the routes go away.
+        */
+       while ((ifa = TAILQ_FIRST(&ifp->if_addrlist)) != NULL) {
+#ifdef IFAREF_DEBUG
+               printf("if_detach: ifaddr %p, family %d, refcnt %d\n",
+                   ifa, ifa->ifa_addr->sa_family, ifa->ifa_refcnt);
+               if (last_ifa != NULL && ifa == last_ifa)
+                       panic("loop detected");
+               last_ifa = ifa;
+#endif
+               if (ifa->ifa_addr->sa_family == AF_LINK) {
+                       rtinit(ifa, RTM_DELETE, 0);
+                       TAILQ_REMOVE(&ifp->if_addrlist, ifa, ifa_list);
+                       IFAFREE(ifa);
+               } else {
+                       pr = pffindtype(ifa->ifa_addr->sa_family, SOCK_DGRAM);
+                       so.so_proto = pr;
+                       if (pr->pr_usrreq) {
+                               (void) (*pr->pr_usrreq)(&so, PRU_PURGEADDR,
+                                   NULL,
+                                   (struct mbuf *) ifa,
+                                   (struct mbuf *) ifp, curproc);
+                       } else {
+                               rtinit(ifa, RTM_DELETE, 0);
+                               TAILQ_REMOVE(&ifp->if_addrlist, ifa, ifa_list);
+                               IFAFREE(ifa);
+                       }
+               }
+       }
+
+       /* Walk the routing table looking for straglers. */
+       for (i = 1; i <= AF_MAX; i++) {
+               if ((rnh = rt_tables[i]) != NULL &&
+                   (*rnh->rnh_walktree)(rnh, if_rt_walktree, ifp) != 0)
+                       break;
+       }
+
+       IFAFREE(ifnet_addrs[ifp->if_index]);
+       ifnet_addrs[ifp->if_index] = NULL;
+
+       TAILQ_REMOVE(&ifnet, ifp, if_list);
+
+       splx(s);
+}
+



Home | Main Index | Thread Index | Old Index