X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/1c79356b52d46aa6b508fb032f5ae709b1f2897b..6d2010ae8f7a6078e10b361c6962983bab233e0f:/bsd/netat/at.c diff --git a/bsd/netat/at.c b/bsd/netat/at.c index f1a750bbf..ae6120798 100644 --- a/bsd/netat/at.c +++ b/bsd/netat/at.c @@ -1,23 +1,29 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2010 Apple Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. + * 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. * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * 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 OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. + * 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_LICENSE_HEADER_END@ + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ /* * Copyright (c) 1998 Apple Computer, Inc. @@ -34,16 +40,15 @@ #include #include #include +#include #include #include #include -#include -#include #include -#include #include +#include #include #include #include @@ -51,12 +56,14 @@ #include #include -extern int at_ioctl(struct atpcb *, u_long, caddr_t); +#include +#include + +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 at_nvestr_t *getRTRLocalZone(zone_usage_t *); -extern int setLocalZones(at_nvestr_t *, int); extern int xpatcnt; extern at_ifaddr_t at_interfaces[]; @@ -70,8 +77,7 @@ struct etalk_addr ttalk_multicast_addr = { {0xC0, 0x00, 0x40, 0x00, 0x00, 0x00}}; /* called only in router mode */ -static int set_zones(ifz) - zone_usage_t *ifz; +static int set_zones(zone_usage_t *ifz) /* 1. adds zone to table 2. looks up each route entry from zone list @@ -86,7 +92,10 @@ static int set_zones(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")); @@ -119,12 +128,28 @@ static int set_zones(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. */ -int at_control(so, cmd, data, ifp) +int +at_control(so, cmd, data, ifp) struct socket *so; u_long cmd; caddr_t data; @@ -132,20 +157,21 @@ int 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; - if (cmd == 0x2000ff99) { + 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(). *** */ - if ((error = at_ioctl((struct atpcb *)so->so_pcb, cmd, data))) { + 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, cmd, data); + error = at_ioctl((struct atpcb *)so->so_pcb, fixed_command, data , 0); } } return(error); @@ -190,8 +216,8 @@ int at_control(so, cmd, data, ifp) } } else { ifID = ifID_home; - strncpy(cfgp->ifr_name, ifID->ifName, - sizeof(ifID->ifName)); + strlcpy(cfgp->ifr_name, ifID->ifName, + sizeof(cfgp->ifr_name)); } if (ifID && ifID->ifState != LAP_OFFLINE) { cfgp->flags = ifID->ifFlags; @@ -216,7 +242,7 @@ int at_control(so, cmd, data, ifp) at_def_zone_t *defzonep = (at_def_zone_t *)data; /* check for root access */ - if (error = suser(p->p_ucred, &p->p_acflag)) + if ((error = suser(kauth_cred_get(), 0))) return(EACCES); ifID = 0; @@ -229,8 +255,8 @@ int at_control(so, cmd, data, ifp) } } else { ifID = ifID_home; - strncpy(defzonep->ifr_name, ifID->ifName, - sizeof(ifID->ifName)); + strlcpy(defzonep->ifr_name, ifID->ifName, + sizeof(defzonep->ifr_name)); } /* In routing mode the default zone is only set for the @@ -246,13 +272,13 @@ int at_control(so, cmd, data, ifp) /* check the zone name */ if (MULTIPORT_MODE) { short zno; - char ifs_in_zone[IF_TOTAL_MAX]; + 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[ifID->ifPort]) + getIfUsage(zno-1, &ifs_in_zone); + if (!ifs_in_zone.at_if[ifID->ifPort]) return(EINVAL); ifID->ifDefZone = zno+1; } else { @@ -271,6 +297,10 @@ int at_control(so, cmd, data, ifp) } 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 @@ -322,7 +352,7 @@ int at_control(so, cmd, data, ifp) { at_nbp_reg_t *nbpP = (at_nbp_reg_t *)data; nve_entry_t nve; - int error; + int error2; if (!(at_state.flags & AT_ST_STARTED) || !ifID_home) return(ENOTREADY); @@ -346,18 +376,20 @@ int at_control(so, cmd, data, ifp) this zone */ int finished = FALSE; int zno; - char ifs_in_zone[IF_TOTAL_MAX]; + at_ifnames_t ifs_in_zone; if (!(zno = zt_find_zname(&nve.zone))) { return(EINVAL); } - getIfUsage(zno-1, ifs_in_zone); + getIfUsage(zno-1, &ifs_in_zone); TAILQ_FOREACH(ifID, &at_ifQueueHd, aa_link) { - if (!ifs_in_zone[ifID->ifPort]) + if (!ifs_in_zone.at_if[ifID->ifPort]) /* zone doesn't match */ continue; - else + else { finished = TRUE; + break; + } } if (!finished) return(EINVAL); @@ -375,15 +407,13 @@ int at_control(so, cmd, data, ifp) /* Normal case; no tuple found for this name, so insert * this tuple in the registry and return ok response. */ - ATDISABLE(nve_lock, NVE_LOCK); - if ((error = nbp_new_nve_entry(&nve, ifID)) == 0) { + 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; } - ATENABLE(nve_lock, NVE_LOCK); - return(error); + return(error2); break; } @@ -397,16 +427,13 @@ int at_control(so, cmd, data, ifp) /* delete by id */ if (nbpP->unique_nbp_id) { - ATDISABLE(nve_lock, NVE_LOCK); 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); - ATENABLE(nve_lock, NVE_LOCK); return(0); } } - ATENABLE(nve_lock, NVE_LOCK); return(EADDRNOTAVAIL); } @@ -426,9 +453,7 @@ int at_control(so, cmd, data, ifp) if ((nve_entry = nbp_find_nve(&nve)) == NULL) continue; - ATDISABLE(nve_lock, NVE_LOCK); nbp_delete_entry(nve_entry); - ATENABLE(nve_lock, NVE_LOCK); found = TRUE; } if (found) @@ -444,9 +469,7 @@ int at_control(so, cmd, data, ifp) /* Normal case; tuple found for this name, so delete * the entry from the registry and return ok response. */ - ATDISABLE(nve_lock, NVE_LOCK); nbp_delete_entry(nve_entry); - ATENABLE(nve_lock, NVE_LOCK); return(0); break; @@ -457,7 +480,7 @@ int at_control(so, cmd, data, ifp) at_router_params_t *rt = (at_router_params_t *)data; /* check for root access */ - if (error = suser(p->p_ucred, &p->p_acflag)) + if ((error = suser(kauth_cred_get(), 0))) return(EACCES); /* when in routing/multihome mode the AIOCSETROUTER IOCTL @@ -497,7 +520,7 @@ int at_control(so, cmd, data, ifp) at_kern_err_t *keP = (at_kern_err_t *)data; /* check for root access */ - if (suser(p->p_ucred, &p->p_acflag)) + if (suser(kauth_cred_get(), 0)) return(EACCES); if (!(at_state.flags & AT_ST_STARTED)) @@ -523,114 +546,122 @@ int at_control(so, cmd, data, ifp) break; } case AIOCSTOPATALK: - { - int *count_only = (int *)data, + { + int *count_only = (int *)data, ret; /* check for root access */ - if (error = suser(p->p_ucred, &p->p_acflag)) + if ((error = suser(kauth_cred_get(), 0))) return(EACCES); ret = ddp_shutdown(*count_only); - if (*count_only) { + + if (*count_only != 0) + { *count_only = ret; return(0); - } else - return((ret == 0)? 0 : EBUSY); + } + 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(p->p_ucred, &p->p_acflag)) + 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_STARTED; + 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)); - strncpy(ifID->ifName, ifr->ifr_name, sizeof(ifID->ifName)); + strlcpy(ifID->ifName, ifr->ifr_name, sizeof(ifID->ifName)); ifID->aa_ifp = ifp; ifa = &ifID->aa_ifa; - 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)); + 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]); + 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 */ - s = splnet(); - TAILQ_INSERT_TAIL(&ifp->if_addrhead, ifa, ifa_link); - splx(s); - - switch (ifp->if_type) { - case IFT_ETHER: - ether_attach_at(ifp, &ifID->at_dl_tag, - &ifID->aarp_dl_tag); - 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; - } + 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_STARTED)) + 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(p->p_ucred, &p->p_acflag)) + if (error = suser(kauth_cred_get(), 0)) error = EACCES; else if (!ifID) error = EINVAL; @@ -640,23 +671,17 @@ int at_control(so, cmd, data, ifp) #endif case SIOCSETOT: { - int s; struct atpcb *at_pcb, *clonedat_pcb; int cloned_fd = *(int *)data; - s = splnet(); /* XXX */ 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; - struct file *cloned_fp; - error = getsock(p->p_fd, cloned_fd, &cloned_fp); - if (error){ - splx(s); /* XXX */ + error = file_socket(cloned_fd, &cloned_so); + if (error) break; - } - cloned_so = (struct socket *)cloned_fp->f_data; clonedat_pcb = sotoatpcb(cloned_so); } else { clonedat_pcb = NULL; @@ -667,15 +692,90 @@ int at_control(so, cmd, data, ifp) } else { at_pcb->ddp_flags = clonedat_pcb->ddp_flags; } - splx(s); /* XXX */ + 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 dlil_ioctl(0, ifp, cmd, (caddr_t) data); + 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); + } + } +}