|
|
1.1 root 1: /*
2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * The contents of this file constitute Original Code as defined in and
7: * are subject to the Apple Public Source License Version 1.1 (the
8: * "License"). You may not use this file except in compliance with the
9: * License. Please obtain a copy of the License at
10: * http://www.apple.com/publicsource and read it before using this file.
11: *
12: * This Original Code and all software distributed under the License are
13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17: * License for the specific language governing rights and limitations
18: * under the License.
19: *
20: * @APPLE_LICENSE_HEADER_END@
21: */
22: /*
23: * Copyright (c) 1998 Apple Computer, Inc.
24: */
25:
26: /* at.c
27: */
28:
29: #include <sys/param.h>
30: #include <sys/systm.h>
31: #include <sys/ioctl.h>
32: #include <sys/errno.h>
33: #include <sys/malloc.h>
34: #include <sys/socket.h>
35: #include <sys/socketvar.h>
36:
37: #include <net/if.h>
38: #include <net/if_dl.h>
39: #include <net/if_types.h>
40: #include <net/etherdefs.h>
41: #include <net/tokendefs.h>
42: #include <net/dlil.h>
43:
44: #include <netat/appletalk.h>
45: #include <netat/sysglue.h>
46: #include <netat/at_pcb.h>
47: #include <netat/at_var.h>
48: #include <netat/ddp.h>
49: #include <netat/nbp.h>
50: #include <netat/routing_tables.h>
51: #include <netat/at_config.h>
52:
53: extern int at_ioctl(struct atpcb *, u_long, caddr_t);
54: extern int routerStart(at_kern_err_t *);
55: extern void elap_offline(at_ifaddr_t *);
56: extern at_ifaddr_t *find_ifID(char *);
57:
58: extern int xpatcnt;
59: extern at_ifaddr_t at_interfaces[];
60: extern at_ifaddr_t *ifID_home;
61: extern TAILQ_HEAD(name_registry, _nve_) name_registry;
62: extern int nve_lock;
63:
64: struct etalk_addr etalk_multicast_addr = {
65: {0x09, 0x00, 0x07, 0xff, 0xff, 0xff}};
66: struct etalk_addr ttalk_multicast_addr = {
67: {0xC0, 0x00, 0x40, 0x00, 0x00, 0x00}};
68:
69: /*
70: * Generic internet control operations (ioctl's).
71: * ifp is 0 if not an interface-specific ioctl.
72: */
73:
74: int at_control(so, cmd, data, ifp)
75: struct socket *so;
76: u_long cmd;
77: caddr_t data;
78: struct ifnet *ifp;
79: {
80: struct ifreq *ifr = (struct ifreq *)data;
81: int pat_id = 0, error = 0;
82: struct proc *p = current_proc();
83: at_ifaddr_t *ifID = 0;
84: struct ifaddr *ifa;
85: struct sockaddr_dl *sdl;
86:
87: if (cmd == 0x2000ff99) {
88: /* *** this is a temporary hack to get at_send_to_dev() to
89: work with BSD-style sockets instead of the special purpose
90: system calls, ATsocket() and ATioctl().
91: *** */
92: if ((error = at_ioctl((struct atpcb *)so->so_pcb, cmd, data))) {
93: if (((struct atpcb *)so->so_pcb)->proto != ATPROTO_LAP) {
94: ((struct atpcb *)so->so_pcb)->proto = ATPROTO_LAP;
95: error = at_ioctl((struct atpcb *)so->so_pcb, cmd, data);
96: }
97: }
98: return(error);
99:
100: /* *** processing should be
101: return(EINVAL);
102: *** */
103: }
104: /*
105: * Find address for this interface, if it exists.
106: */
107: if (ifp)
108: for (pat_id = 0; pat_id < xpatcnt; pat_id++)
109: if (at_interfaces[pat_id].aa_ifp == ifp) {
110: ifID = &at_interfaces[pat_id];
111: break;
112: }
113:
114: switch (cmd) {
115:
116: case AIOCGETSTATE:
117: {
118: at_state_t *global_state = (at_state_t *)data;
119:
120: *global_state = at_state;
121: return(0);
122: break;
123: }
124:
125: case AIOCGETIFCFG:
126: {
127: at_if_cfg_t *cfgp = (at_if_cfg_t *)data;
128:
129: ifID = 0;
130: if ((at_state.flags & AT_ST_STARTED) &&
131: ifID_home) {
132: if (strlen(cfgp->ifr_name)) {
133: TAILQ_FOREACH(ifID, &at_ifQueueHd, aa_link) {
134: if (!strncmp(ifID->ifName, cfgp->ifr_name,
135: strlen(ifID->ifName)))
136: break;
137: }
138: } else {
139: ifID = ifID_home;
140: strncpy(cfgp->ifr_name, ifID->ifName,
141: sizeof(ifID->ifName));
142: }
143: if (ifID && ifID->ifState != LAP_OFFLINE) {
144: cfgp->flags = ifID->ifFlags;
145: /* put the IF state into the low order
146: bits of flags */
147: cfgp->flags |= (ifID->ifState & LAP_STATE_MASK);
148: cfgp->node = ifID->ifThisNode;
149: cfgp->router = ifID->ifARouter;
150: cfgp->netStart = ifID->ifThisCableStart;
151: cfgp->netEnd = ifID->ifThisCableEnd;
152: cfgp->zonename = ifID->ifZoneName;
153: return(0);
154: } else
155: return(EINVAL);
156: } else
157: return(ENOTREADY);
158: break;
159: }
160:
161: case AIOCSETDEFZONE:
162: {
163: at_def_zone_t *defzonep = (at_def_zone_t *)data;
164:
165: /* check for root access */
166: if (error = suser(p->p_ucred, &p->p_acflag))
167: return(EACCES);
168:
169: ifID = 0;
170: if ((at_state.flags & AT_ST_STARTED) && ifID_home) {
171: if (strlen(defzonep->ifr_name)) {
172: TAILQ_FOREACH(ifID, &at_ifQueueHd, aa_link) {
173: if (!strncmp(ifID->ifName, defzonep->ifr_name,
174: strlen(ifID->ifName)))
175: break;
176: }
177: } else {
178: ifID = ifID_home;
179: strncpy(defzonep->ifr_name, ifID->ifName,
180: sizeof(ifID->ifName));
181: }
182:
183: /* In routing mode the default zone is only set for the
184: default interface. */
185: if (ROUTING_MODE && (ifID != ifID_home))
186: return(EINVAL);
187:
188: if (ifID && ifID->ifState != LAP_OFFLINE) {
189: if (zonename_equal(&ifID->ifZoneName,
190: &defzonep->zonename))
191: return(0);
192: else {
193: /* check the zone name */
194: if (MULTIPORT_MODE) {
195: short zno;
196: char ifs_in_zone[IF_TOTAL_MAX];
197:
198: if (!(zno = zt_find_zname(&defzonep->zonename)))
199: return(EINVAL);
200:
201: getIfUsage(zno-1, ifs_in_zone);
202: if (!ifs_in_zone[ifID->ifPort])
203: return(EINVAL);
204: ifID->ifDefZone = zno+1;
205: } else {
206: int i;
207: at_nvestr_t *zone;
208:
209: for (i = 0, zone = getSPLocalZone(i);
210: zone;
211: i++, zone = getSPLocalZone(i)) {
212: if (zonename_equal(zone,
213: &defzonep->zonename))
214: break;
215: }
216: if (!zone)
217: return(EINVAL);
218: }
219: ifID->ifZoneName = defzonep->zonename;
220: (void)regDefaultZone(ifID);
221: return(0);
222: }
223: } else
224: return(EINVAL);
225: } else
226: return(ENOTREADY);
227: break;
228: }
229:
230: case AIOCNBPREG:
231: {
232: at_nbp_reg_t *nbpP = (at_nbp_reg_t *)data;
233: nve_entry_t nve;
234: int error;
235:
236: if (!(at_state.flags & AT_ST_STARTED) || !ifID_home)
237: return(ENOTREADY);
238:
239: /* multihoming mode */
240: if (MULTIHOME_MODE) {
241: return(nbp_mh_reg(nbpP));
242: }
243:
244: /* single port mode or router mode */
245: if (nbp_fillin_nve(&nbpP->name, &nve) != 0) {
246: /* bad tuple... */
247: return(EINVAL);
248: }
249:
250: /* In routing mode when the zone is specified, we need to
251: find an interface on which the specified zone is seeded, so
252: that the zone multicast will be plausible. */
253: if (ROUTING_MODE && !(DEFAULT_ZONE(&nve.zone))) {
254: /* find first segment (interface) which is seeded for
255: this zone */
256: int finished = FALSE;
257: int zno;
258: char ifs_in_zone[IF_TOTAL_MAX];
259: if (!(zno = zt_find_zname(&nve.zone))) {
260: return(EINVAL);
261: }
262: getIfUsage(zno-1, ifs_in_zone);
263:
264: TAILQ_FOREACH(ifID, &at_ifQueueHd, aa_link) {
265: if (!ifs_in_zone[ifID->ifPort])
266: /* zone doesn't match */
267: continue;
268: else
269: finished = TRUE;
270: }
271: if (!finished)
272: return(EINVAL);
273: } else
274: ifID = ifID_home;
275:
276: nve.address.net = ifID->ifThisNode.s_net;
277: nve.address.node = ifID->ifThisNode.s_node;
278: nve.address.socket = nbpP->addr.socket;
279: nve.ddptype = nbpP->ddptype;
280:
281: if (nbp_find_nve(&nve))
282: return(EADDRNOTAVAIL);
283:
284: /* Normal case; no tuple found for this name, so insert
285: * this tuple in the registry and return ok response.
286: */
287: ATDISABLE(nve_lock, NVE_LOCK);
288: if ((error = nbp_new_nve_entry(&nve, ifID)) == 0) {
289: nbpP->addr.net = ifID->ifThisNode.s_net;
290: nbpP->addr.node = ifID->ifThisNode.s_node;
291: nbpP->unique_nbp_id = nve.unique_nbp_id;
292: }
293: ATENABLE(nve_lock, NVE_LOCK);
294:
295: return(error);
296: break;
297: }
298:
299: case AIOCNBPREMOVE:
300: {
301: at_nbp_reg_t *nbpP = (at_nbp_reg_t *)data;
302: nve_entry_t *nve_entry, nve;
303:
304: if (!(at_state.flags & AT_ST_STARTED))
305: return(ENOTREADY);
306:
307: /* delete by id */
308: if (nbpP->unique_nbp_id) {
309: ATDISABLE(nve_lock, NVE_LOCK);
310: TAILQ_FOREACH(nve_entry, &name_registry, nve_link) {
311: if (nve_entry->unique_nbp_id == nbpP->unique_nbp_id) {
312: /* Found a match! */
313: nbp_delete_entry(nve_entry);
314: ATENABLE(nve_lock, NVE_LOCK);
315: return(0);
316: }
317: }
318: ATENABLE(nve_lock, NVE_LOCK);
319: return(EADDRNOTAVAIL);
320: }
321:
322: /* delete by entity */
323: if (nbp_fillin_nve(&nbpP->name, &nve) != 0) {
324: /* bad tuple... */
325: return(EINVAL);
326: }
327:
328: if (MULTIHOME_MODE && DEFAULT_ZONE(&nbpP->name.zone)) {
329: /* if mhome & *, remove nve from all default zones */
330: int found = FALSE; /* if any found & deleted */
331:
332: TAILQ_FOREACH(ifID, &at_ifQueueHd, aa_link) {
333: nve.zone = ifID->ifZoneName;
334: nve.zone_hash = nbp_strhash(&nve.zone);
335: if ((nve_entry = nbp_find_nve(&nve)) == NULL)
336: continue;
337:
338: ATDISABLE(nve_lock, NVE_LOCK);
339: nbp_delete_entry(nve_entry);
340: ATENABLE(nve_lock, NVE_LOCK);
341: found = TRUE;
342: }
343: if (found)
344: return(0);
345: else
346: return(EADDRNOTAVAIL);
347: }
348:
349: if ((nve_entry = nbp_find_nve(&nve)) == NULL)
350: /* Can't find the tuple we're looking for, send error*/
351: return(EADDRNOTAVAIL);
352:
353: /* Normal case; tuple found for this name, so delete
354: * the entry from the registry and return ok response.
355: */
356: ATDISABLE(nve_lock, NVE_LOCK);
357: nbp_delete_entry(nve_entry);
358: ATENABLE(nve_lock, NVE_LOCK);
359: return(0);
360:
361: break;
362: }
363:
364: case AIOCSETROUTER:
365: {
366: at_router_params_t *rt = (at_router_params_t *)data;
367:
368: /* check for root access */
369: if (error = suser(p->p_ucred, &p->p_acflag))
370: return(EACCES);
371:
372: /* when in routing/multihome mode the AIOCSETROUTER IOCTL
373: is done first */
374: if (at_state.flags & AT_ST_STARTED)
375: return(EALREADY);
376:
377: /* Setup the routing & zip table size for the router */
378: if (rt->rtmp_table_sz >= RT_MIN && rt->rtmp_table_sz <= RT_MAX)
379: RT_maxentry = rt->rtmp_table_sz;
380: else
381: RT_maxentry = RT_DEFAULT;
382:
383: if (rt->zone_table_sz >= ZT_MIN && rt->zone_table_sz <= ZT_MAX)
384: ZT_maxentry = rt->zone_table_sz;
385: else
386: ZT_maxentry = ZT_DEFAULT;
387:
388: if (rt_table_init() == ENOBUFS)
389: return(ENOBUFS);
390:
391: if (rt->router_mix)
392: RouterMix = (int)rt->router_mix;
393: else
394: RouterMix = RT_MIX_DEFAULT;
395:
396: add_ddp_handler(RTMP_SOCKET, rtmp_router_input);
397:
398: if (rt->multihome)
399: at_state.flags |= AT_ST_MULTIHOME;
400: else
401: at_state.flags |= AT_ST_ROUTER;
402: break;
403: }
404: case AIOCSTARTROUTER:
405: {
406: at_kern_err_t *keP = (at_kern_err_t *)data;
407:
408: /* check for root access */
409: if (suser(p->p_ucred, &p->p_acflag))
410: return(EACCES);
411:
412: if (!(at_state.flags & AT_ST_STARTED))
413: return(ENOTREADY);
414:
415: bzero(keP, sizeof(at_kern_err_t));
416: error = routerStart(keP);
417:
418: break;
419: }
420: case AIOCGETROUTER:
421: {
422: at_router_params_t *rt = (at_router_params_t *)data;
423:
424: if (!(at_state.flags & AT_ST_STARTED))
425: return(ENOTREADY);
426:
427: rt->multihome = (MULTIHOME_MODE)? 1: 0;
428: rt->rtmp_table_sz = RT_maxentry;
429: rt->zone_table_sz = ZT_maxentry;
430: rt->router_mix = RouterMix;
431:
432: break;
433: }
434: case AIOCSTOPATALK:
435: /* check for root access */
436: if (error = suser(p->p_ucred, &p->p_acflag))
437: return(EACCES);
438:
439: ddp_shutdown();
440: break;
441:
442: case SIOCSIFADDR:
443: /* check for root access */
444: if (error = suser(p->p_ucred, &p->p_acflag))
445: error = EACCES;
446: else if (ifID)
447: error = EEXIST;
448: else {
449: int s;
450: if (xpatcnt == 0) {
451: at_state.flags |= AT_ST_STARTED;
452: ddp_brt_init();
453: }
454:
455: /* *** find an empty entry *** */
456: ifID = &at_interfaces[xpatcnt];
457: bzero((caddr_t)ifID, sizeof(at_ifaddr_t));
458: strncpy(ifID->ifName, ifr->ifr_name, sizeof(ifID->ifName));
459:
460: ifID->aa_ifp = ifp;
461: ifa = &ifID->aa_ifa;
462: TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link)
463: if ((sdl = (struct sockaddr_dl *)ifa->ifa_addr) &&
464: (sdl->sdl_family == AF_LINK)) {
465: bcopy(LLADDR(sdl), ifID->xaddr, sizeof(ifID->xaddr));
466: #ifdef APPLETALK_DEBUG
467: kprintf("SIOCSIFADDR: local enet address is %x.%x.%x.%x.%x.%x\n",
468: ifID->xaddr[0], ifID->xaddr[1],
469: ifID->xaddr[2], ifID->xaddr[3],
470: ifID->xaddr[4], ifID->xaddr[5]);
471: #endif
472: break;
473: }
474:
475: /* attach the AppleTalk address to the ifnet structure */
476: ifa = &ifID->aa_ifa;
477: ifa->ifa_addr = (struct sockaddr *)&ifID->ifNodeAddress;
478: ifID->ifNodeAddress.sat_len = sizeof(struct sockaddr_at);
479: ifID->ifNodeAddress.sat_family = AF_APPLETALK;
480: /* the address itself will be filled in when ifThisNode
481: is set */
482: s = splnet();
483: TAILQ_INSERT_TAIL(&ifp->if_addrhead, ifa, ifa_link);
484: splx(s);
485:
486: switch (ifp->if_type) {
487: case IFT_ETHER:
488: /* Check if a tag was already registered for AppleTalk */
489: error = dlil_find_dltag(ifp->if_family, ifp->if_unit,
490: PF_APPLETALK, &ifID->at_dl_tag);
491:
492: ifID->aarp_dl_tag = ifID->at_dl_tag; /*both tags are the same right now */
493:
494: #ifdef APPLETALK_DEBUG
495: kprintf("atcontrol: ifp=%s%u find_dltag returns=%d dl_tag=%d\n",
496: ifp->if_name, ifp->if_unit, error, ifID->at_dl_tag);
497: #endif
498: if (error == EPROTONOSUPPORT) {
499: ether_attach_at(ifp, &ifID->at_dl_tag,
500: &ifID->aarp_dl_tag);
501: error = 0;
502: }
503: ifID->cable_multicast_addr = etalk_multicast_addr;
504:
505: xpatcnt++;
506: break;
507: case IFT_FDDI:
508: ifID->cable_multicast_addr = etalk_multicast_addr;
509: ddp_bit_reverse(&ifID->cable_multicast_addr);
510: xpatcnt++;
511: break;
512: case IFT_ISO88025: /* token ring */
513: ifID->cable_multicast_addr = ttalk_multicast_addr;
514: ddp_bit_reverse(&ifID->cable_multicast_addr);
515:
516: xpatcnt++;
517: break;
518: default:
519: error = EINVAL;
520: }
521:
522: /* *** if (!error) make entry in if_types[] *** */
523: }
524: break;
525:
526: /* complete the initialization started in SIOCSIFADDR */
527: case AIOCSIFADDR:
528: {
529: at_if_cfg_t *cfgp = (at_if_cfg_t *)data;
530:
531: if (!(at_state.flags & AT_ST_STARTED))
532: return(ENOTREADY);
533:
534: if (!(ifID = find_ifID(cfgp->ifr_name)))
535: return(EINVAL);
536:
537: return(lap_online(ifID, cfgp));
538: break;
539: }
540:
541: #ifdef NOT_YET
542: /* *** this can't be added until AT can handle dynamic addition and
543: deletion of interfaces *** */
544: case SIOCDIFADDR:
545: /* check for root access */
546: if (error = suser(p->p_ucred, &p->p_acflag))
547: error = EACCES;
548: else if (!ifID)
549: error = EINVAL;
550: else
551: elap_offline(ifID);
552: break;
553: #endif
554: default:
555: if (ifp == 0 || ifp->if_ioctl == 0)
556: return (EOPNOTSUPP);
557: return dlil_ioctl(0, ifp, cmd, (caddr_t) data);
558: }
559:
560: return(error);
561: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.