]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/netat/at.c
xnu-2422.1.72.tar.gz
[apple/xnu.git] / bsd / netat / at.c
diff --git a/bsd/netat/at.c b/bsd/netat/at.c
deleted file mode 100644 (file)
index ae61207..0000000
+++ /dev/null
@@ -1,781 +0,0 @@
-/*
- * Copyright (c) 2000-2010 Apple Inc. All rights reserved.
- *
- * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
- * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. The rights granted to you under the License
- * may not be used to create, or enable the creation or redistribution of,
- * unlawful or unlicensed copies of an Apple operating system, or to
- * circumvent, violate, or enable the circumvention or violation of, any
- * terms of an Apple operating system software license agreement.
- * 
- * Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this file.
- * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- * 
- * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
- */
-/*
- *     Copyright (c) 1998 Apple Computer, Inc. 
- */
-
-/*     at.c
- */
-
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/ioctl.h>
-#include <sys/errno.h>
-#include <sys/malloc.h>
-#include <sys/socket.h>
-#include <sys/socketvar.h>
-#include <sys/file.h>
-#include <sys/kauth.h>
-
-#include <net/if.h>
-#include <net/if_dl.h>
-#include <net/if_types.h>
-#include <net/dlil.h>
-
-#include <netat/sysglue.h>
-#include <netat/appletalk.h>
-#include <netat/at_pcb.h>
-#include <netat/at_var.h>
-#include <netat/ddp.h>
-#include <netat/nbp.h>
-#include <netat/routing_tables.h>
-#include <netat/debug.h>
-
-#include <sys/kern_event.h>
-#include <net/kpi_protocol.h>
-
-int lap_online( at_ifaddr_t *, at_if_cfg_t *cfgp);
-
-extern int routerStart(at_kern_err_t *);
-extern void elap_offline(at_ifaddr_t *);
-extern at_ifaddr_t *find_ifID(char *);
-
-extern int xpatcnt;
-extern at_ifaddr_t at_interfaces[];
-extern at_ifaddr_t *ifID_home;
-extern TAILQ_HEAD(name_registry, _nve_) name_registry;
-extern int nve_lock;
-
-struct  etalk_addr      etalk_multicast_addr = {
-  {0x09, 0x00, 0x07, 0xff, 0xff, 0xff}};
-struct  etalk_addr      ttalk_multicast_addr = {
-  {0xC0, 0x00, 0x40, 0x00, 0x00, 0x00}};
-
-/* called only in router mode */
-static int set_zones(zone_usage_t *ifz)
-
-/* 1. adds zone to table
-   2. looks up each route entry from zone list
-   3. sets zone bit in each route entry
-
-   returns  0 if successful
-           errno if error occurred
-*/
-{
-       int i;
-       at_ifaddr_t *ifID;
-       short zno;
-       RT_entry *rte;
-
-       if (ifz->zone_name.len <= 0 || ifz->zone_name.len > NBP_NVE_STR_SIZE)
-               return(ENOSPC);
-
-       zno = zt_add_zone((char *)ifz->zone_name.str, ifz->zone_name.len);
-
-       if (zno == ZT_MAXEDOUT) {
-               dPrintf(D_M_ELAP, D_L_ERROR, ("set_zones: error: table full\n"));
-               return(ENOSPC);
-       }
-       if (ifz->zone_home) {
-               ifID_home->ifZoneName = ifz->zone_name;
-               ifID_home->ifDefZone = zno;
-       }
-
-       for (i=0; i<IF_TOTAL_MAX; i++)  {
-               if (ifz->zone_iflist.at_if[i][0]) {  
-                       if ((ifID = find_ifID(ifz->zone_iflist.at_if[i]))) {
-                               rte = rt_blookup(ifID->ifThisCableEnd);
-                               if (!rte) {
-                                       dPrintf(D_M_ELAP, D_L_ERROR,
-                                               ("set_zones: error: can't find route\n"));
-                               } else {
-                                       zt_set_zmap(zno, rte->ZoneBitMap); 
-
-                                       /* if first zone for this I/F, 
-                                          make default */
-                                       if (!ifID->ifDefZone)
-                                               ifID->ifDefZone = zno;
-                               }
-                       }
-               }
-       }
-
-       return(0);
-} /* set_zones */
-
-static int
-at_domifattach(struct ifnet *ifp, at_ifaddr_t *ifID)
-{
-       int error;
-       
-       if ((error = proto_plumb(PF_APPLETALK, ifp))) {
-               if (error != EEXIST)
-                       log(LOG_ERR, "%s: proto_plumb returned %d if=%s%d\n",
-                           __func__, error, ifp->if_name, ifp->if_unit);
-       } else if (ifID)
-               ifID->at_was_attached = 1;
-
-       return (error);
-}
-
-/*
-  * Generic internet control operations (ioctl's).
-  * ifp is 0 if not an interface-specific ioctl.
-  */
-
-int
-at_control(so, cmd, data, ifp)
-     struct socket *so;
-     u_long cmd;
-     caddr_t data;
-     struct ifnet *ifp;
-{
-       struct ifreq *ifr = (struct ifreq *)data;
-       int pat_id = 0, error = 0;
-       at_ifaddr_t *ifID = 0;
-       struct ifaddr *ifa;
-       struct sockaddr_dl *sdl;
-
-    if ((cmd & 0xffff) == 0xff99) {
-               u_long  fixed_command;
-               /* *** this is a temporary hack to get at_send_to_dev() to
-                  work with BSD-style sockets instead of the special purpose 
-                  system calls, ATsocket() and ATioctl().
-                  *** */
-               fixed_command = _IOW(0, 0xff99, user_addr_t); 
-               if ((error = at_ioctl((struct atpcb *)so->so_pcb, fixed_command, data, 0))) {
-                 if (((struct atpcb *)so->so_pcb)->proto != ATPROTO_LAP) {
-                   ((struct atpcb *)so->so_pcb)->proto = ATPROTO_LAP;
-                   error = at_ioctl((struct atpcb *)so->so_pcb, fixed_command, data , 0);
-                 }
-               }
-               return(error);
-
-               /* *** processing should be
-                  return(EINVAL);
-                  *** */
-       }
-        /*
-        * Find address for this interface, if it exists.
-        */
-       if (ifp)
-               for (pat_id = 0; pat_id < xpatcnt; pat_id++)
-                 if (at_interfaces[pat_id].aa_ifp == ifp) {
-                       ifID = &at_interfaces[pat_id];
-                       break;
-                 }
-       
-       switch (cmd) {
-
-       case AIOCGETSTATE:
-         {
-               at_state_t *global_state = (at_state_t *)data;
-
-               *global_state = at_state;
-               return(0);
-               break;
-         }
-
-       case AIOCGETIFCFG:
-         {
-               at_if_cfg_t *cfgp = (at_if_cfg_t *)data;
-
-               ifID = 0;
-               if ((at_state.flags & AT_ST_STARTED) &&
-                   ifID_home) {
-                       if (strlen(cfgp->ifr_name)) {
-                               TAILQ_FOREACH(ifID, &at_ifQueueHd, aa_link) {
-                                       if (!strncmp(ifID->ifName, cfgp->ifr_name, 
-                                                    strlen(ifID->ifName)))
-                                               break;
-                               }
-                       } else {
-                               ifID = ifID_home;
-                               strlcpy(cfgp->ifr_name, ifID->ifName, 
-                                       sizeof(cfgp->ifr_name));
-                       }
-                       if  (ifID && ifID->ifState != LAP_OFFLINE) {
-                               cfgp->flags = ifID->ifFlags;
-                               /* put the IF state into the low order 
-                                  bits of flags */
-                               cfgp->flags |= (ifID->ifState & LAP_STATE_MASK);
-                               cfgp->node = ifID->ifThisNode;
-                               cfgp->router = ifID->ifARouter;
-                               cfgp->netStart = ifID->ifThisCableStart;
-                               cfgp->netEnd = ifID->ifThisCableEnd;
-                               cfgp->zonename = ifID->ifZoneName;
-                               return(0);
-                       } else
-                               return(EINVAL);
-               } else
-                       return(ENOTREADY);
-               break;
-         }
-
-       case AIOCSETDEFZONE:
-         {
-               at_def_zone_t *defzonep = (at_def_zone_t *)data;
-
-               /* check for root access */
-               if ((error = suser(kauth_cred_get(), 0)))
-                       return(EACCES);
-
-               ifID = 0;
-               if ((at_state.flags & AT_ST_STARTED) && ifID_home) {
-                       if (strlen(defzonep->ifr_name)) {
-                           TAILQ_FOREACH(ifID, &at_ifQueueHd, aa_link) {
-                               if (!strncmp(ifID->ifName, defzonep->ifr_name, 
-                                            strlen(ifID->ifName)))
-                                   break;
-                           }
-                       } else {
-                               ifID = ifID_home;
-                               strlcpy(defzonep->ifr_name, ifID->ifName, 
-                                       sizeof(defzonep->ifr_name));
-                       }
-
-                       /* In routing mode the default zone is only set for the 
-                          default interface. */
-                       if (ROUTING_MODE && (ifID != ifID_home))
-                               return(EINVAL);
-
-                       if  (ifID && ifID->ifState != LAP_OFFLINE) {
-                               if (zonename_equal(&ifID->ifZoneName, 
-                                                  &defzonep->zonename)) 
-                                       return(0);
-                               else {
-                                       /* check the zone name */
-                                       if (MULTIPORT_MODE) {
-                                         short zno;
-                                         at_ifnames_t ifs_in_zone;
-
-                                         if (!(zno = zt_find_zname(&defzonep->zonename)))
-                                           return(EINVAL);
-
-                                         getIfUsage(zno-1, &ifs_in_zone);
-                                         if (!ifs_in_zone.at_if[ifID->ifPort]) 
-                                           return(EINVAL);
-                                         ifID->ifDefZone = zno+1;
-                                       } else {
-                                         int i;
-                                         at_nvestr_t *zone;
-
-                                         for (i = 0, zone = getSPLocalZone(i); 
-                                              zone; 
-                                              i++, zone = getSPLocalZone(i)) {
-                                           if (zonename_equal(zone, 
-                                                              &defzonep->zonename))
-                                             break;
-                                         }
-                                         if (!zone)
-                                           return(EINVAL);
-                                       }
-                                       ifID->ifZoneName = defzonep->zonename;
-                                       (void)regDefaultZone(ifID);
-
-                                       /* AppleTalk zone was changed. Send event with zone info. */
-                                       atalk_post_msg(ifID->aa_ifp, KEV_ATALK_ZONEUPDATED, 0, &(ifID->ifZoneName));
-
-                                       return(0);
-                               }
-                       } else
-                               return(EINVAL);
-               } else
-                       return(ENOTREADY);
-               break;
-         }
-
-       case AIOCREGLOCALZN:
-         {
-               at_nvestr_t *zone = (at_nvestr_t *)data;
-
-               if (!(at_state.flags & AT_ST_STARTED) || !ifID_home)
-                       return(ENOTREADY);
-
-               if (MULTIPORT_MODE)
-                       return(EINVAL);
-
-               return(setLocalZones(zone, zone->len));
-
-               break;
-         }
-       case AIOCSETZNUSAGE:
-               if (!(at_state.flags & AT_ST_STARTED) || !ifID_home)
-                       return(ENOTREADY);
-
-               if (!ROUTING_MODE)
-                       return(EINVAL);
-
-               return(set_zones((zone_usage_t *)data));
-
-               break;
-
-       case AIOCGETZNUSAGE:
-               if (!(at_state.flags & AT_ST_STARTED) || !ifID_home)
-                       return(ENOTREADY);
-
-               if (!MULTIPORT_MODE)
-                       return(EINVAL);
-
-               if (getRTRLocalZone((zone_usage_t *)data))
-                       return(0);
-               else
-                       return(ENOENT);
-               break;
-
-       case AIOCNBPREG:
-         {
-               at_nbp_reg_t *nbpP = (at_nbp_reg_t *)data;
-               nve_entry_t nve;
-               int error2;
-
-               if (!(at_state.flags & AT_ST_STARTED) || !ifID_home)
-                       return(ENOTREADY);
-
-               /* multihoming mode */
-               if (MULTIHOME_MODE) {
-                       return(nbp_mh_reg(nbpP));
-               }
-
-               /* single port mode or router mode */
-               if (nbp_fillin_nve(&nbpP->name, &nve) != 0) {
-                       /* bad tuple... */
-                       return(EINVAL);
-               }
-
-               /* In routing mode when the zone is specified, we need to 
-                  find an interface on which the specified zone is seeded, so
-                  that the zone multicast will be plausible. */
-               if (ROUTING_MODE && !(DEFAULT_ZONE(&nve.zone))) {
-                       /* find first segment (interface) which is seeded for 
-                          this zone */
-                       int finished = FALSE;
-                       int zno;
-                       at_ifnames_t ifs_in_zone;
-                       if (!(zno = zt_find_zname(&nve.zone))) {
-                               return(EINVAL);
-                       }
-                       getIfUsage(zno-1, &ifs_in_zone);
-
-                       TAILQ_FOREACH(ifID, &at_ifQueueHd, aa_link) {
-                               if (!ifs_in_zone.at_if[ifID->ifPort]) 
-                                               /* zone doesn't match */
-                                       continue;
-                               else {
-                                       finished = TRUE;
-                                       break;
-                               }
-                       }
-                       if (!finished)
-                               return(EINVAL);
-               } else 
-                       ifID = ifID_home;
-
-               nve.address.net = ifID->ifThisNode.s_net;
-               nve.address.node = ifID->ifThisNode.s_node;
-               nve.address.socket = nbpP->addr.socket;
-               nve.ddptype = nbpP->ddptype;
-
-               if (nbp_find_nve(&nve))
-                       return(EADDRNOTAVAIL);
-
-               /* Normal case; no tuple found for this name, so insert
-                * this tuple in the registry and return ok response.
-                */
-               if ((error2 = nbp_new_nve_entry(&nve, ifID)) == 0) {
-                       nbpP->addr.net = ifID->ifThisNode.s_net;
-                       nbpP->addr.node = ifID->ifThisNode.s_node;
-                       nbpP->unique_nbp_id = nve.unique_nbp_id;
-               }
-
-               return(error2);
-               break;
-         }
-
-       case AIOCNBPREMOVE:
-         {
-               at_nbp_reg_t *nbpP = (at_nbp_reg_t *)data;
-               nve_entry_t    *nve_entry, nve;
-
-               if (!(at_state.flags & AT_ST_STARTED))
-                       return(ENOTREADY);
-
-               /* delete by id */
-               if (nbpP->unique_nbp_id) {
-                       TAILQ_FOREACH(nve_entry, &name_registry, nve_link) {
-                               if (nve_entry->unique_nbp_id == nbpP->unique_nbp_id) {
-                                       /* Found a match! */
-                                       nbp_delete_entry(nve_entry);
-                                       return(0);
-                               }
-                       }
-                       return(EADDRNOTAVAIL);
-               }
-
-               /* delete by entity */
-               if (nbp_fillin_nve(&nbpP->name, &nve) != 0) {
-                       /* bad tuple... */
-                       return(EINVAL);
-               }
-
-               if (MULTIHOME_MODE && DEFAULT_ZONE(&nbpP->name.zone)) {
-                       /* if mhome & *, remove nve from all default zones */
-                       int found = FALSE;      /* if any found & deleted */
-
-                       TAILQ_FOREACH(ifID, &at_ifQueueHd, aa_link) {
-                               nve.zone = ifID->ifZoneName;
-                               nve.zone_hash = nbp_strhash(&nve.zone);
-                               if ((nve_entry = nbp_find_nve(&nve)) == NULL) 
-                                       continue;
-
-                               nbp_delete_entry(nve_entry);
-                               found = TRUE;
-                       }
-                       if (found) 
-                               return(0);
-                       else
-                               return(EADDRNOTAVAIL);
-               }
-
-               if ((nve_entry = nbp_find_nve(&nve)) == NULL)
-                       /* Can't find the tuple we're looking for, send error*/
-                       return(EADDRNOTAVAIL);
-
-               /* Normal case; tuple found for this name, so delete
-                * the entry from the registry and return ok response.
-                */
-               nbp_delete_entry(nve_entry);
-               return(0);
-
-               break;
-         }
-
-       case AIOCSETROUTER:
-         {
-               at_router_params_t *rt = (at_router_params_t *)data;
-
-               /* check for root access */
-               if ((error = suser(kauth_cred_get(), 0)))
-                       return(EACCES);
-
-               /* when in routing/multihome mode the AIOCSETROUTER IOCTL 
-                  is done first */
-               if (at_state.flags & AT_ST_STARTED)
-                       return(EALREADY);
-
-               /* Setup the routing & zip table size for the router */
-               if (rt->rtmp_table_sz >= RT_MIN && rt->rtmp_table_sz <= RT_MAX)
-                       RT_maxentry = rt->rtmp_table_sz;
-               else
-                       RT_maxentry = RT_DEFAULT;
-
-               if (rt->zone_table_sz >= ZT_MIN && rt->zone_table_sz <= ZT_MAX)
-                       ZT_maxentry = rt->zone_table_sz;
-               else
-                       ZT_maxentry = ZT_DEFAULT;
-
-               if (rt_table_init() == ENOBUFS)
-                       return(ENOBUFS);
-
-               if (rt->router_mix)
-                       RouterMix = (int)rt->router_mix;
-               else
-                       RouterMix = RT_MIX_DEFAULT;
-
-               add_ddp_handler(RTMP_SOCKET, rtmp_router_input);
-
-               if (rt->multihome)
-                       at_state.flags |= AT_ST_MULTIHOME;
-               else
-                       at_state.flags |= AT_ST_ROUTER;
-               break;
-         }
-       case AIOCSTARTROUTER:
-         {
-               at_kern_err_t *keP = (at_kern_err_t *)data;
-
-               /* check for root access */
-               if (suser(kauth_cred_get(), 0))
-                       return(EACCES);
-
-               if (!(at_state.flags & AT_ST_STARTED))
-                       return(ENOTREADY);
-
-               bzero(keP, sizeof(at_kern_err_t));
-               error = routerStart(keP);
-
-               break;
-         }
-       case AIOCGETROUTER:
-         {
-               at_router_params_t *rt = (at_router_params_t *)data;
-
-               if (!(at_state.flags & AT_ST_STARTED))
-                       return(ENOTREADY);
-
-               rt->multihome = (MULTIHOME_MODE)? 1: 0;
-               rt->rtmp_table_sz = RT_maxentry;
-               rt->zone_table_sz = ZT_maxentry;
-               rt->router_mix = RouterMix;
-
-               break;
-         }
-       case AIOCSTOPATALK:
-       {
-               int *count_only = (int *)data,
-                   ret;
-
-               /* check for root access */
-               if ((error = suser(kauth_cred_get(), 0)))
-                       return(EACCES);
-
-               ret = ddp_shutdown(*count_only);
-               
-               if (*count_only != 0) 
-               {
-                       *count_only = ret;
-                       return(0);
-               }
-               else
-               {
-                       if (ret == 0)
-                       {
-                               /* AppleTalk was successfully shut down. Send event. */
-                               atalk_post_msg(0, KEV_ATALK_DISABLED, 0, 0);
-                               return 0;
-                       }
-                       else
-                               return EBUSY;
-               }
-
-               break;
-       }
-
-       case SIOCSIFADDR:
-               /* check for root access */
-               if ((error = suser(kauth_cred_get(), 0)))
-                       error = EACCES;
-               else if (ifID)
-                       error = EEXIST;
-               else {
-                       if (xpatcnt == 0) {
-                               at_state.flags |= AT_ST_STARTING;
-                               ddp_brt_init();
-                       }
-
-                       /* *** find an empty entry *** */
-                       ifID = &at_interfaces[xpatcnt];
-                       bzero((caddr_t)ifID, sizeof(at_ifaddr_t));
-                       strlcpy(ifID->ifName, ifr->ifr_name, sizeof(ifID->ifName));
-
-                       ifID->aa_ifp = ifp;
-                       ifa = &ifID->aa_ifa;
-                       error = at_domifattach(ifp, ifID);
-                       if (error == EEXIST) {
-                               ifID->at_was_attached = 1;
-                               error = 0;
-                       }
-                       if (error != 0) {
-                               break;
-                       }
-                       /* XXX ethernet-specific */
-                       ifID->cable_multicast_addr = etalk_multicast_addr;
-                       xpatcnt++;
-                       ifnet_lock_exclusive(ifp);
-                       /*
-                        * Holding ifnet lock here prevents the link address
-                        * from changing contents, so no need to hold the ifa
-                        * lock.  The link address is always present; it's
-                        * never freed.
-                        */
-                       sdl = (struct sockaddr_dl *)ifp->if_lladdr->ifa_addr;
-                       bcopy(LLADDR(sdl), ifID->xaddr, sizeof(ifID->xaddr));
-#ifdef APPLETALK_DEBUG
-                       kprintf("SIOCSIFADDR: local enet address is "
-                           "%x.%x.%x.%x.%x.%x\n",
-                           ifID->xaddr[0], ifID->xaddr[1],
-                           ifID->xaddr[2], ifID->xaddr[3],
-                           ifID->xaddr[4], ifID->xaddr[5]);
-#endif
-
-                       /* attach the AppleTalk address to the ifnet structure */
-                       ifa = &ifID->aa_ifa;
-                       ifa_lock_init(ifa);
-                       VERIFY(!(ifa->ifa_debug & IFD_ALLOC));
-                       ifa->ifa_addr = (struct sockaddr *)&ifID->ifNodeAddress;
-                       ifID->ifNodeAddress.sat_len = sizeof(struct sockaddr_at);
-                       ifID->ifNodeAddress.sat_family =  AF_APPLETALK;
-                       /* the address itself will be filled in when ifThisNode
-                          is set */
-                       IFA_LOCK(ifa);
-                       if_attach_ifa(ifp, ifa);
-                       /* add a reference for at_interfaces[] */
-                       IFA_ADDREF_LOCKED(ifa);
-                       IFA_UNLOCK(ifa);
-                       ifnet_lock_done(ifp);
-               }
-         break;
-
-       /* complete the initialization started in SIOCSIFADDR */
-       case AIOCSIFADDR:
-       {
-               at_if_cfg_t *cfgp = (at_if_cfg_t *)data;
-
-               if (!(at_state.flags & AT_ST_STARTING))
-                       return(ENOTREADY);
-               if (!(ifID = find_ifID(cfgp->ifr_name)))
-                       return(EINVAL);
-               
-               return(lap_online(ifID, cfgp));
-               break;
-       }
-
-#ifdef NOT_YET
-       /* *** this can't be added until AT can handle dynamic addition and
-              deletion of interfaces *** */
-       case SIOCDIFADDR:
-               /* check for root access */
-               if (error = suser(kauth_cred_get(), 0))
-                       error = EACCES;
-               else if (!ifID) 
-                       error = EINVAL;
-               else
-                       elap_offline(ifID);
-               break;
-#endif
-
-    case SIOCSETOT: {
-        struct atpcb   *at_pcb, *clonedat_pcb;
-        int                            cloned_fd = *(int *)data;
-
-        at_pcb = sotoatpcb(so);
-        
-        /* let's make sure it's either -1 or a valid file descriptor */
-        if (cloned_fd != -1) {
-            struct socket      *cloned_so;
-                       error = file_socket(cloned_fd, &cloned_so);
-            if (error)
-                break;
-            clonedat_pcb = sotoatpcb(cloned_so);
-        } else {
-            clonedat_pcb = NULL;
-        }
-
-        if (clonedat_pcb == NULL) {
-            at_pcb->ddp_flags |= DDPFLG_STRIPHDR;
-        } else {
-            at_pcb->ddp_flags = clonedat_pcb->ddp_flags;
-        }
-               file_drop(cloned_fd);
-        break;
-    }
-        
-       case SIOCPROTOATTACH:
-               /* check for root access */
-               if (suser(kauth_cred_get(), 0) != 0) {
-                       error = EACCES;
-                       break;
-               }
-               error = at_domifattach(ifp, ifID);
-               break;
-
-       case SIOCPROTODETACH:
-               /* check for root access */
-               if (suser(kauth_cred_get(), 0) != 0) {
-                       error = EACCES;
-                       break;
-               }
-               if (ifID != NULL) {
-                       error = EBUSY;
-                       break;
-               }
-               error = proto_unplumb(PF_APPLETALK, ifp);
-               break;
-
-       default:
-               if (ifp == 0 || ifp->if_ioctl == 0)
-                       return (EOPNOTSUPP);
-               return ifnet_ioctl(ifp, 0, cmd, data);
-       }
-
-       return(error);
-}
-
-/* From dlil_post_msg() */
-void atalk_post_msg(struct ifnet *ifp, u_long event_code, struct at_addr *address, at_nvestr_t *zone) 
-{
-       struct kev_atalk_data   at_event_data;
-       struct kev_msg                  ev_msg;
-
-       bzero(&ev_msg, sizeof(struct kev_msg));
-       ev_msg.vendor_code    = KEV_VENDOR_APPLE;
-       ev_msg.kev_class      = KEV_NETWORK_CLASS;
-       ev_msg.kev_subclass   = KEV_ATALK_SUBCLASS;
-       ev_msg.event_code         = event_code;
-       
-       bzero(&at_event_data, sizeof(struct kev_atalk_data));
-    
-       if (ifp != 0) {
-               strlcpy(&at_event_data.link_data.if_name[0], ifp->if_name, IFNAMSIZ);
-               at_event_data.link_data.if_family = ifp->if_family;
-               at_event_data.link_data.if_unit   = (unsigned long) ifp->if_unit;
-       }
-       
-       if (address != 0) {
-               at_event_data.node_data.address = *address;
-       }
-       else if (zone != 0) {
-               at_event_data.node_data.zone = *zone;
-       }
-    
-       ev_msg.dv[0].data_length = sizeof(struct kev_atalk_data);
-       ev_msg.dv[0].data_ptr    = &at_event_data;      
-       ev_msg.dv[1].data_length = 0;
-       
-       kev_post_msg(&ev_msg);
-}
-
-
-/*
- * This is untested; the code is here only for completeness.
- */
-void
-at_purgeaddrs(struct ifnet *ifp)
-{
-       at_ifaddr_t *ifID = NULL;
-       int pat_id;
-
-        /* Find address for this interface, if it exists */
-       for (pat_id = 0; pat_id < xpatcnt; pat_id++) {
-               if (at_interfaces[pat_id].aa_ifp == ifp) {
-                       ifID = &at_interfaces[pat_id];
-                       elap_offline(ifID);
-               }
-       }
-}