/*
- * 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.
#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[];
{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
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.
{
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 & 0xffff) == 0xff99) {
u_long fixed_command;
- char ioctl_buffer[32];
/* *** 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().
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;
/* 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 ((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(error2);
break;
/* 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);
}
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)
/* 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;
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
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);
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();
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;
#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;
error = file_socket(cloned_fd, &cloned_so);
- if (error){
- splx(s); /* XXX */
+ if (error)
break;
- }
clonedat_pcb = sotoatpcb(cloned_so);
} else {
clonedat_pcb = NULL;
} 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);
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;
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);
+ }
+ }
+}