]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/netat/at.c
xnu-1699.22.73.tar.gz
[apple/xnu.git] / bsd / netat / at.c
index 526f002f2efc834e196a3a733baf4fe46d1effec..ae612079885f6354aed532268acbd289331be653 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2000-2010 Apple Inc. All rights reserved.
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  * 
@@ -47,8 +47,8 @@
 #include <net/if_types.h>
 #include <net/dlil.h>
 
-#include <netat/appletalk.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/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 at_ioctl(struct atpcb *, u_long, caddr_t, int fromKernel);
 extern int routerStart(at_kern_err_t *);
 extern void elap_offline(at_ifaddr_t *);
 extern at_ifaddr_t *find_ifID(char *);
-extern at_nvestr_t *getRTRLocalZone(zone_usage_t *);
-extern int setLocalZones(at_nvestr_t *, int);
 
 extern int xpatcnt;
 extern at_ifaddr_t at_interfaces[];
@@ -92,7 +92,10 @@ static int set_zones(zone_usage_t *ifz)
        short zno;
        RT_entry *rte;
 
-       zno = zt_add_zone(ifz->zone_name.str, ifz->zone_name.len);
+       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"));
@@ -125,6 +128,21 @@ static int set_zones(zone_usage_t *ifz)
        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.
@@ -139,7 +157,6 @@ at_control(so, cmd, data, ifp)
 {
        struct ifreq *ifr = (struct ifreq *)data;
        int pat_id = 0, error = 0;
-       struct proc *p = current_proc();       
        at_ifaddr_t *ifID = 0;
        struct ifaddr *ifa;
        struct sockaddr_dl *sdl;
@@ -225,7 +242,7 @@ at_control(so, cmd, data, ifp)
                at_def_zone_t *defzonep = (at_def_zone_t *)data;
 
                /* check for root access */
-               if (error = suser(kauth_cred_get(), 0))
+               if ((error = suser(kauth_cred_get(), 0)))
                        return(EACCES);
 
                ifID = 0;
@@ -463,7 +480,7 @@ at_control(so, cmd, data, ifp)
                at_router_params_t *rt = (at_router_params_t *)data;
 
                /* check for root access */
-               if (error = suser(kauth_cred_get(), 0))
+               if ((error = suser(kauth_cred_get(), 0)))
                        return(EACCES);
 
                /* when in routing/multihome mode the AIOCSETROUTER IOCTL 
@@ -534,7 +551,7 @@ at_control(so, cmd, data, ifp)
                    ret;
 
                /* check for root access */
-               if (error = suser(kauth_cred_get(), 0))
+               if ((error = suser(kauth_cred_get(), 0)))
                        return(EACCES);
 
                ret = ddp_shutdown(*count_only);
@@ -561,12 +578,11 @@ at_control(so, cmd, data, ifp)
 
        case SIOCSIFADDR:
                /* check for root access */
-               if (error = suser(kauth_cred_get(), 0))
+               if ((error = suser(kauth_cred_get(), 0)))
                        error = EACCES;
                else if (ifID)
                        error = EEXIST;
                else {
-                       int s;
                        if (xpatcnt == 0) {
                                at_state.flags |= AT_ST_STARTING;
                                ddp_brt_init();
@@ -579,54 +595,49 @@ at_control(so, cmd, data, ifp)
 
                        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);
-                       TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) 
-                               if ((sdl = (struct sockaddr_dl *)ifa->ifa_addr) &&
-                                     (sdl->sdl_family == AF_LINK)) {
-                                   bcopy(LLADDR(sdl), ifID->xaddr, sizeof(ifID->xaddr));
+                       /*
+                        * 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]);
+                       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
-                                   break;
-                                 }
 
                        /* 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);
-
-                       switch (ifp->if_type) {
-                       case IFT_ETHER:
-                        case IFT_L2VLAN:
-                        case IFT_IEEE8023ADLAG: /* bonded ethernet */
-                               ether_attach_at(ifp);
-                               error = 0;
-                               ifID->cable_multicast_addr = etalk_multicast_addr;
-
-                               xpatcnt++;
-                               break;
-                       case IFT_FDDI:
-                               ifID->cable_multicast_addr = etalk_multicast_addr;
-                               ddp_bit_reverse(&ifID->cable_multicast_addr);
-                               xpatcnt++;
-                               break;
-                       case IFT_ISO88025: /* token ring */     
-                               ifID->cable_multicast_addr = ttalk_multicast_addr;
-                               ddp_bit_reverse(&ifID->cable_multicast_addr);
-
-                               xpatcnt++;
-                               break;
-                       default:
-                               error = EINVAL;
-                       }
                }
          break;
 
@@ -685,10 +696,32 @@ at_control(so, cmd, data, ifp)
         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 dlil_ioctl(0, ifp, cmd, (caddr_t) data);
+               return ifnet_ioctl(ifp, 0, cmd, data);
        }
 
        return(error);
@@ -700,6 +733,7 @@ void atalk_post_msg(struct ifnet *ifp, u_long event_code, struct at_addr *addres
        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;
@@ -726,3 +760,22 @@ void atalk_post_msg(struct ifnet *ifp, u_long event_code, struct at_addr *addres
        
        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);
+               }
+       }
+}