]> git.saurik.com Git - apple/xnu.git/blame - bsd/netat/at.c
xnu-792.tar.gz
[apple/xnu.git] / bsd / netat / at.c
CommitLineData
1c79356b
A
1/*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
e5568f75
A
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.
1c79356b 11 *
e5568f75
A
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
1c79356b
A
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
e5568f75
A
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.
1c79356b
A
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#include <sys/file.h>
91447636 37#include <sys/kauth.h>
1c79356b
A
38
39#include <net/if.h>
40#include <net/if_dl.h>
41#include <net/if_types.h>
1c79356b
A
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/debug.h>
52
9bccf70c
A
53#include <sys/kern_event.h>
54
0b4e3aa0 55extern int at_ioctl(struct atpcb *, u_long, caddr_t, int fromKernel);
1c79356b
A
56extern int routerStart(at_kern_err_t *);
57extern void elap_offline(at_ifaddr_t *);
58extern at_ifaddr_t *find_ifID(char *);
59extern at_nvestr_t *getRTRLocalZone(zone_usage_t *);
60extern int setLocalZones(at_nvestr_t *, int);
61
62extern int xpatcnt;
63extern at_ifaddr_t at_interfaces[];
64extern at_ifaddr_t *ifID_home;
65extern TAILQ_HEAD(name_registry, _nve_) name_registry;
66extern int nve_lock;
67
68struct etalk_addr etalk_multicast_addr = {
69 {0x09, 0x00, 0x07, 0xff, 0xff, 0xff}};
70struct etalk_addr ttalk_multicast_addr = {
71 {0xC0, 0x00, 0x40, 0x00, 0x00, 0x00}};
72
73/* called only in router mode */
74static int set_zones(ifz)
75 zone_usage_t *ifz;
76
77/* 1. adds zone to table
78 2. looks up each route entry from zone list
79 3. sets zone bit in each route entry
80
81 returns 0 if successful
82 errno if error occurred
83*/
84{
85 int i;
86 at_ifaddr_t *ifID;
87 short zno;
88 RT_entry *rte;
89
90 zno = zt_add_zone(ifz->zone_name.str, ifz->zone_name.len);
91
92 if (zno == ZT_MAXEDOUT) {
93 dPrintf(D_M_ELAP, D_L_ERROR, ("set_zones: error: table full\n"));
94 return(ENOSPC);
95 }
96 if (ifz->zone_home) {
97 ifID_home->ifZoneName = ifz->zone_name;
98 ifID_home->ifDefZone = zno;
99 }
100
101 for (i=0; i<IF_TOTAL_MAX; i++) {
102 if (ifz->zone_iflist.at_if[i][0]) {
103 if ((ifID = find_ifID(ifz->zone_iflist.at_if[i]))) {
104 rte = rt_blookup(ifID->ifThisCableEnd);
105 if (!rte) {
106 dPrintf(D_M_ELAP, D_L_ERROR,
107 ("set_zones: error: can't find route\n"));
108 } else {
109 zt_set_zmap(zno, rte->ZoneBitMap);
110
111 /* if first zone for this I/F,
112 make default */
113 if (!ifID->ifDefZone)
114 ifID->ifDefZone = zno;
115 }
116 }
117 }
118 }
119
120 return(0);
121} /* set_zones */
122
123/*
124 * Generic internet control operations (ioctl's).
125 * ifp is 0 if not an interface-specific ioctl.
126 */
127
91447636
A
128int
129at_control(so, cmd, data, ifp)
1c79356b
A
130 struct socket *so;
131 u_long cmd;
132 caddr_t data;
133 struct ifnet *ifp;
134{
135 struct ifreq *ifr = (struct ifreq *)data;
136 int pat_id = 0, error = 0;
137 struct proc *p = current_proc();
138 at_ifaddr_t *ifID = 0;
139 struct ifaddr *ifa;
140 struct sockaddr_dl *sdl;
141
91447636
A
142 if ((cmd & 0xffff) == 0xff99) {
143 u_long fixed_command;
144 char ioctl_buffer[32];
1c79356b
A
145 /* *** this is a temporary hack to get at_send_to_dev() to
146 work with BSD-style sockets instead of the special purpose
147 system calls, ATsocket() and ATioctl().
148 *** */
91447636
A
149 fixed_command = _IOW(0, 0xff99, user_addr_t);
150 if ((error = at_ioctl((struct atpcb *)so->so_pcb, fixed_command, data, 0))) {
1c79356b
A
151 if (((struct atpcb *)so->so_pcb)->proto != ATPROTO_LAP) {
152 ((struct atpcb *)so->so_pcb)->proto = ATPROTO_LAP;
91447636 153 error = at_ioctl((struct atpcb *)so->so_pcb, fixed_command, data , 0);
1c79356b
A
154 }
155 }
156 return(error);
157
158 /* *** processing should be
159 return(EINVAL);
160 *** */
161 }
162 /*
163 * Find address for this interface, if it exists.
164 */
165 if (ifp)
166 for (pat_id = 0; pat_id < xpatcnt; pat_id++)
167 if (at_interfaces[pat_id].aa_ifp == ifp) {
168 ifID = &at_interfaces[pat_id];
169 break;
170 }
171
172 switch (cmd) {
173
174 case AIOCGETSTATE:
175 {
176 at_state_t *global_state = (at_state_t *)data;
177
178 *global_state = at_state;
179 return(0);
180 break;
181 }
182
183 case AIOCGETIFCFG:
184 {
185 at_if_cfg_t *cfgp = (at_if_cfg_t *)data;
186
187 ifID = 0;
188 if ((at_state.flags & AT_ST_STARTED) &&
189 ifID_home) {
190 if (strlen(cfgp->ifr_name)) {
191 TAILQ_FOREACH(ifID, &at_ifQueueHd, aa_link) {
192 if (!strncmp(ifID->ifName, cfgp->ifr_name,
193 strlen(ifID->ifName)))
194 break;
195 }
196 } else {
197 ifID = ifID_home;
198 strncpy(cfgp->ifr_name, ifID->ifName,
199 sizeof(ifID->ifName));
200 }
201 if (ifID && ifID->ifState != LAP_OFFLINE) {
202 cfgp->flags = ifID->ifFlags;
203 /* put the IF state into the low order
204 bits of flags */
205 cfgp->flags |= (ifID->ifState & LAP_STATE_MASK);
206 cfgp->node = ifID->ifThisNode;
207 cfgp->router = ifID->ifARouter;
208 cfgp->netStart = ifID->ifThisCableStart;
209 cfgp->netEnd = ifID->ifThisCableEnd;
210 cfgp->zonename = ifID->ifZoneName;
211 return(0);
212 } else
213 return(EINVAL);
214 } else
215 return(ENOTREADY);
216 break;
217 }
218
219 case AIOCSETDEFZONE:
220 {
221 at_def_zone_t *defzonep = (at_def_zone_t *)data;
222
223 /* check for root access */
91447636 224 if (error = suser(kauth_cred_get(), 0))
1c79356b
A
225 return(EACCES);
226
227 ifID = 0;
228 if ((at_state.flags & AT_ST_STARTED) && ifID_home) {
229 if (strlen(defzonep->ifr_name)) {
230 TAILQ_FOREACH(ifID, &at_ifQueueHd, aa_link) {
231 if (!strncmp(ifID->ifName, defzonep->ifr_name,
232 strlen(ifID->ifName)))
233 break;
234 }
235 } else {
236 ifID = ifID_home;
237 strncpy(defzonep->ifr_name, ifID->ifName,
238 sizeof(ifID->ifName));
239 }
240
241 /* In routing mode the default zone is only set for the
242 default interface. */
243 if (ROUTING_MODE && (ifID != ifID_home))
244 return(EINVAL);
245
246 if (ifID && ifID->ifState != LAP_OFFLINE) {
247 if (zonename_equal(&ifID->ifZoneName,
248 &defzonep->zonename))
249 return(0);
250 else {
251 /* check the zone name */
252 if (MULTIPORT_MODE) {
253 short zno;
9bccf70c 254 at_ifnames_t ifs_in_zone;
1c79356b
A
255
256 if (!(zno = zt_find_zname(&defzonep->zonename)))
257 return(EINVAL);
258
9bccf70c
A
259 getIfUsage(zno-1, &ifs_in_zone);
260 if (!ifs_in_zone.at_if[ifID->ifPort])
1c79356b
A
261 return(EINVAL);
262 ifID->ifDefZone = zno+1;
263 } else {
264 int i;
265 at_nvestr_t *zone;
266
267 for (i = 0, zone = getSPLocalZone(i);
268 zone;
269 i++, zone = getSPLocalZone(i)) {
270 if (zonename_equal(zone,
271 &defzonep->zonename))
272 break;
273 }
274 if (!zone)
275 return(EINVAL);
276 }
277 ifID->ifZoneName = defzonep->zonename;
278 (void)regDefaultZone(ifID);
9bccf70c
A
279
280 /* AppleTalk zone was changed. Send event with zone info. */
281 atalk_post_msg(ifID->aa_ifp, KEV_ATALK_ZONEUPDATED, 0, &(ifID->ifZoneName));
282
1c79356b
A
283 return(0);
284 }
285 } else
286 return(EINVAL);
287 } else
288 return(ENOTREADY);
289 break;
290 }
291
292 case AIOCREGLOCALZN:
293 {
294 at_nvestr_t *zone = (at_nvestr_t *)data;
295
296 if (!(at_state.flags & AT_ST_STARTED) || !ifID_home)
297 return(ENOTREADY);
298
299 if (MULTIPORT_MODE)
300 return(EINVAL);
301
302 return(setLocalZones(zone, zone->len));
303
304 break;
305 }
306 case AIOCSETZNUSAGE:
307 if (!(at_state.flags & AT_ST_STARTED) || !ifID_home)
308 return(ENOTREADY);
309
310 if (!ROUTING_MODE)
311 return(EINVAL);
312
313 return(set_zones((zone_usage_t *)data));
314
315 break;
316
317 case AIOCGETZNUSAGE:
318 if (!(at_state.flags & AT_ST_STARTED) || !ifID_home)
319 return(ENOTREADY);
320
321 if (!MULTIPORT_MODE)
322 return(EINVAL);
323
324 if (getRTRLocalZone((zone_usage_t *)data))
325 return(0);
326 else
327 return(ENOENT);
328 break;
329
330 case AIOCNBPREG:
331 {
332 at_nbp_reg_t *nbpP = (at_nbp_reg_t *)data;
333 nve_entry_t nve;
91447636 334 int error2;
1c79356b
A
335
336 if (!(at_state.flags & AT_ST_STARTED) || !ifID_home)
337 return(ENOTREADY);
338
339 /* multihoming mode */
340 if (MULTIHOME_MODE) {
341 return(nbp_mh_reg(nbpP));
342 }
343
344 /* single port mode or router mode */
345 if (nbp_fillin_nve(&nbpP->name, &nve) != 0) {
346 /* bad tuple... */
347 return(EINVAL);
348 }
349
350 /* In routing mode when the zone is specified, we need to
351 find an interface on which the specified zone is seeded, so
352 that the zone multicast will be plausible. */
353 if (ROUTING_MODE && !(DEFAULT_ZONE(&nve.zone))) {
354 /* find first segment (interface) which is seeded for
355 this zone */
356 int finished = FALSE;
357 int zno;
9bccf70c 358 at_ifnames_t ifs_in_zone;
1c79356b
A
359 if (!(zno = zt_find_zname(&nve.zone))) {
360 return(EINVAL);
361 }
9bccf70c 362 getIfUsage(zno-1, &ifs_in_zone);
1c79356b
A
363
364 TAILQ_FOREACH(ifID, &at_ifQueueHd, aa_link) {
9bccf70c 365 if (!ifs_in_zone.at_if[ifID->ifPort])
1c79356b
A
366 /* zone doesn't match */
367 continue;
9bccf70c 368 else {
1c79356b 369 finished = TRUE;
9bccf70c
A
370 break;
371 }
1c79356b
A
372 }
373 if (!finished)
374 return(EINVAL);
375 } else
376 ifID = ifID_home;
377
378 nve.address.net = ifID->ifThisNode.s_net;
379 nve.address.node = ifID->ifThisNode.s_node;
380 nve.address.socket = nbpP->addr.socket;
381 nve.ddptype = nbpP->ddptype;
382
383 if (nbp_find_nve(&nve))
384 return(EADDRNOTAVAIL);
385
386 /* Normal case; no tuple found for this name, so insert
387 * this tuple in the registry and return ok response.
388 */
389 ATDISABLE(nve_lock, NVE_LOCK);
91447636 390 if ((error2 = nbp_new_nve_entry(&nve, ifID)) == 0) {
1c79356b
A
391 nbpP->addr.net = ifID->ifThisNode.s_net;
392 nbpP->addr.node = ifID->ifThisNode.s_node;
393 nbpP->unique_nbp_id = nve.unique_nbp_id;
394 }
395 ATENABLE(nve_lock, NVE_LOCK);
396
91447636 397 return(error2);
1c79356b
A
398 break;
399 }
400
401 case AIOCNBPREMOVE:
402 {
403 at_nbp_reg_t *nbpP = (at_nbp_reg_t *)data;
404 nve_entry_t *nve_entry, nve;
405
406 if (!(at_state.flags & AT_ST_STARTED))
407 return(ENOTREADY);
408
409 /* delete by id */
410 if (nbpP->unique_nbp_id) {
411 ATDISABLE(nve_lock, NVE_LOCK);
412 TAILQ_FOREACH(nve_entry, &name_registry, nve_link) {
413 if (nve_entry->unique_nbp_id == nbpP->unique_nbp_id) {
414 /* Found a match! */
415 nbp_delete_entry(nve_entry);
416 ATENABLE(nve_lock, NVE_LOCK);
417 return(0);
418 }
419 }
420 ATENABLE(nve_lock, NVE_LOCK);
421 return(EADDRNOTAVAIL);
422 }
423
424 /* delete by entity */
425 if (nbp_fillin_nve(&nbpP->name, &nve) != 0) {
426 /* bad tuple... */
427 return(EINVAL);
428 }
429
430 if (MULTIHOME_MODE && DEFAULT_ZONE(&nbpP->name.zone)) {
431 /* if mhome & *, remove nve from all default zones */
432 int found = FALSE; /* if any found & deleted */
433
434 TAILQ_FOREACH(ifID, &at_ifQueueHd, aa_link) {
435 nve.zone = ifID->ifZoneName;
436 nve.zone_hash = nbp_strhash(&nve.zone);
437 if ((nve_entry = nbp_find_nve(&nve)) == NULL)
438 continue;
439
440 ATDISABLE(nve_lock, NVE_LOCK);
441 nbp_delete_entry(nve_entry);
442 ATENABLE(nve_lock, NVE_LOCK);
443 found = TRUE;
444 }
445 if (found)
446 return(0);
447 else
448 return(EADDRNOTAVAIL);
449 }
450
451 if ((nve_entry = nbp_find_nve(&nve)) == NULL)
452 /* Can't find the tuple we're looking for, send error*/
453 return(EADDRNOTAVAIL);
454
455 /* Normal case; tuple found for this name, so delete
456 * the entry from the registry and return ok response.
457 */
458 ATDISABLE(nve_lock, NVE_LOCK);
459 nbp_delete_entry(nve_entry);
460 ATENABLE(nve_lock, NVE_LOCK);
461 return(0);
462
463 break;
464 }
465
466 case AIOCSETROUTER:
467 {
468 at_router_params_t *rt = (at_router_params_t *)data;
469
470 /* check for root access */
91447636 471 if (error = suser(kauth_cred_get(), 0))
1c79356b
A
472 return(EACCES);
473
474 /* when in routing/multihome mode the AIOCSETROUTER IOCTL
475 is done first */
476 if (at_state.flags & AT_ST_STARTED)
477 return(EALREADY);
478
479 /* Setup the routing & zip table size for the router */
480 if (rt->rtmp_table_sz >= RT_MIN && rt->rtmp_table_sz <= RT_MAX)
481 RT_maxentry = rt->rtmp_table_sz;
482 else
483 RT_maxentry = RT_DEFAULT;
484
485 if (rt->zone_table_sz >= ZT_MIN && rt->zone_table_sz <= ZT_MAX)
486 ZT_maxentry = rt->zone_table_sz;
487 else
488 ZT_maxentry = ZT_DEFAULT;
489
490 if (rt_table_init() == ENOBUFS)
491 return(ENOBUFS);
492
493 if (rt->router_mix)
494 RouterMix = (int)rt->router_mix;
495 else
496 RouterMix = RT_MIX_DEFAULT;
497
498 add_ddp_handler(RTMP_SOCKET, rtmp_router_input);
499
500 if (rt->multihome)
501 at_state.flags |= AT_ST_MULTIHOME;
502 else
503 at_state.flags |= AT_ST_ROUTER;
504 break;
505 }
506 case AIOCSTARTROUTER:
507 {
508 at_kern_err_t *keP = (at_kern_err_t *)data;
509
510 /* check for root access */
91447636 511 if (suser(kauth_cred_get(), 0))
1c79356b
A
512 return(EACCES);
513
514 if (!(at_state.flags & AT_ST_STARTED))
515 return(ENOTREADY);
516
517 bzero(keP, sizeof(at_kern_err_t));
518 error = routerStart(keP);
519
520 break;
521 }
522 case AIOCGETROUTER:
523 {
524 at_router_params_t *rt = (at_router_params_t *)data;
525
526 if (!(at_state.flags & AT_ST_STARTED))
527 return(ENOTREADY);
528
529 rt->multihome = (MULTIHOME_MODE)? 1: 0;
530 rt->rtmp_table_sz = RT_maxentry;
531 rt->zone_table_sz = ZT_maxentry;
532 rt->router_mix = RouterMix;
533
534 break;
535 }
536 case AIOCSTOPATALK:
9bccf70c
A
537 {
538 int *count_only = (int *)data,
1c79356b
A
539 ret;
540
541 /* check for root access */
91447636 542 if (error = suser(kauth_cred_get(), 0))
1c79356b
A
543 return(EACCES);
544
545 ret = ddp_shutdown(*count_only);
9bccf70c
A
546
547 if (*count_only != 0)
548 {
1c79356b
A
549 *count_only = ret;
550 return(0);
9bccf70c
A
551 }
552 else
553 {
554 if (ret == 0)
555 {
556 /* AppleTalk was successfully shut down. Send event. */
557 atalk_post_msg(0, KEV_ATALK_DISABLED, 0, 0);
558 return 0;
559 }
560 else
561 return EBUSY;
562 }
563
1c79356b 564 break;
9bccf70c 565 }
1c79356b
A
566
567 case SIOCSIFADDR:
568 /* check for root access */
91447636 569 if (error = suser(kauth_cred_get(), 0))
1c79356b
A
570 error = EACCES;
571 else if (ifID)
572 error = EEXIST;
573 else {
574 int s;
575 if (xpatcnt == 0) {
9bccf70c 576 at_state.flags |= AT_ST_STARTING;
1c79356b
A
577 ddp_brt_init();
578 }
579
580 /* *** find an empty entry *** */
581 ifID = &at_interfaces[xpatcnt];
582 bzero((caddr_t)ifID, sizeof(at_ifaddr_t));
583 strncpy(ifID->ifName, ifr->ifr_name, sizeof(ifID->ifName));
584
585 ifID->aa_ifp = ifp;
586 ifa = &ifID->aa_ifa;
91447636 587 ifnet_lock_exclusive(ifp);
1c79356b
A
588 TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link)
589 if ((sdl = (struct sockaddr_dl *)ifa->ifa_addr) &&
590 (sdl->sdl_family == AF_LINK)) {
591 bcopy(LLADDR(sdl), ifID->xaddr, sizeof(ifID->xaddr));
592#ifdef APPLETALK_DEBUG
593 kprintf("SIOCSIFADDR: local enet address is %x.%x.%x.%x.%x.%x\n",
594 ifID->xaddr[0], ifID->xaddr[1],
595 ifID->xaddr[2], ifID->xaddr[3],
596 ifID->xaddr[4], ifID->xaddr[5]);
597#endif
598 break;
599 }
600
601 /* attach the AppleTalk address to the ifnet structure */
602 ifa = &ifID->aa_ifa;
603 ifa->ifa_addr = (struct sockaddr *)&ifID->ifNodeAddress;
604 ifID->ifNodeAddress.sat_len = sizeof(struct sockaddr_at);
605 ifID->ifNodeAddress.sat_family = AF_APPLETALK;
606 /* the address itself will be filled in when ifThisNode
607 is set */
91447636
A
608 if_attach_ifa(ifp, ifa);
609 ifnet_lock_done(ifp);
1c79356b
A
610
611 switch (ifp->if_type) {
612 case IFT_ETHER:
91447636
A
613 case IFT_L2VLAN:
614 case IFT_IEEE8023ADLAG: /* bonded ethernet */
615 ether_attach_at(ifp);
1c79356b
A
616 error = 0;
617 ifID->cable_multicast_addr = etalk_multicast_addr;
618
619 xpatcnt++;
620 break;
621 case IFT_FDDI:
622 ifID->cable_multicast_addr = etalk_multicast_addr;
623 ddp_bit_reverse(&ifID->cable_multicast_addr);
624 xpatcnt++;
625 break;
626 case IFT_ISO88025: /* token ring */
627 ifID->cable_multicast_addr = ttalk_multicast_addr;
628 ddp_bit_reverse(&ifID->cable_multicast_addr);
629
630 xpatcnt++;
631 break;
632 default:
633 error = EINVAL;
634 }
635 }
636 break;
637
638 /* complete the initialization started in SIOCSIFADDR */
639 case AIOCSIFADDR:
9bccf70c 640 {
1c79356b
A
641 at_if_cfg_t *cfgp = (at_if_cfg_t *)data;
642
9bccf70c 643 if (!(at_state.flags & AT_ST_STARTING))
1c79356b
A
644 return(ENOTREADY);
645
646 if (!(ifID = find_ifID(cfgp->ifr_name)))
647 return(EINVAL);
9bccf70c 648
1c79356b
A
649 return(lap_online(ifID, cfgp));
650 break;
9bccf70c 651 }
1c79356b
A
652
653#ifdef NOT_YET
654 /* *** this can't be added until AT can handle dynamic addition and
655 deletion of interfaces *** */
656 case SIOCDIFADDR:
657 /* check for root access */
91447636 658 if (error = suser(kauth_cred_get(), 0))
1c79356b
A
659 error = EACCES;
660 else if (!ifID)
661 error = EINVAL;
662 else
663 elap_offline(ifID);
664 break;
665#endif
666
667 case SIOCSETOT: {
668 int s;
669 struct atpcb *at_pcb, *clonedat_pcb;
670 int cloned_fd = *(int *)data;
671
672 s = splnet(); /* XXX */
673 at_pcb = sotoatpcb(so);
674
675 /* let's make sure it's either -1 or a valid file descriptor */
676 if (cloned_fd != -1) {
677 struct socket *cloned_so;
91447636 678 error = file_socket(cloned_fd, &cloned_so);
1c79356b
A
679 if (error){
680 splx(s); /* XXX */
681 break;
682 }
1c79356b
A
683 clonedat_pcb = sotoatpcb(cloned_so);
684 } else {
685 clonedat_pcb = NULL;
686 }
687
688 if (clonedat_pcb == NULL) {
689 at_pcb->ddp_flags |= DDPFLG_STRIPHDR;
690 } else {
691 at_pcb->ddp_flags = clonedat_pcb->ddp_flags;
692 }
693 splx(s); /* XXX */
91447636 694 file_drop(cloned_fd);
1c79356b
A
695 break;
696 }
697
698 default:
699 if (ifp == 0 || ifp->if_ioctl == 0)
700 return (EOPNOTSUPP);
701 return dlil_ioctl(0, ifp, cmd, (caddr_t) data);
702 }
703
704 return(error);
705}
9bccf70c
A
706
707/* From dlil_post_msg() */
708void atalk_post_msg(struct ifnet *ifp, u_long event_code, struct at_addr *address, at_nvestr_t *zone)
709{
710 struct kev_atalk_data at_event_data;
711 struct kev_msg ev_msg;
712
713 ev_msg.vendor_code = KEV_VENDOR_APPLE;
714 ev_msg.kev_class = KEV_NETWORK_CLASS;
715 ev_msg.kev_subclass = KEV_ATALK_SUBCLASS;
716 ev_msg.event_code = event_code;
717
718 bzero(&at_event_data, sizeof(struct kev_atalk_data));
719
720 if (ifp != 0) {
721 strncpy(&at_event_data.link_data.if_name[0], ifp->if_name, IFNAMSIZ);
722 at_event_data.link_data.if_family = ifp->if_family;
723 at_event_data.link_data.if_unit = (unsigned long) ifp->if_unit;
724 }
725
726 if (address != 0) {
727 at_event_data.node_data.address = *address;
728 }
729 else if (zone != 0) {
730 at_event_data.node_data.zone = *zone;
731 }
732
733 ev_msg.dv[0].data_length = sizeof(struct kev_atalk_data);
734 ev_msg.dv[0].data_ptr = &at_event_data;
735 ev_msg.dv[1].data_length = 0;
736
737 kev_post_msg(&ev_msg);
738}