2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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.
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
20 * @APPLE_LICENSE_HEADER_END@
23 * Copyright (c) 1998 Apple Computer, Inc.
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>
39 #include <net/if_dl.h>
40 #include <net/if_types.h>
41 #include <net/etherdefs.h>
42 #include <net/tokendefs.h>
45 #include <netat/appletalk.h>
46 #include <netat/sysglue.h>
47 #include <netat/at_pcb.h>
48 #include <netat/at_var.h>
49 #include <netat/ddp.h>
50 #include <netat/nbp.h>
51 #include <netat/routing_tables.h>
52 #include <netat/debug.h>
54 extern int at_ioctl(struct atpcb
*, u_long
, caddr_t
, int fromKernel
);
55 extern int routerStart(at_kern_err_t
*);
56 extern void elap_offline(at_ifaddr_t
*);
57 extern at_ifaddr_t
*find_ifID(char *);
58 extern at_nvestr_t
*getRTRLocalZone(zone_usage_t
*);
59 extern int setLocalZones(at_nvestr_t
*, int);
62 extern at_ifaddr_t at_interfaces
[];
63 extern at_ifaddr_t
*ifID_home
;
64 extern TAILQ_HEAD(name_registry
, _nve_
) name_registry
;
67 struct etalk_addr etalk_multicast_addr
= {
68 {0x09, 0x00, 0x07, 0xff, 0xff, 0xff}};
69 struct etalk_addr ttalk_multicast_addr
= {
70 {0xC0, 0x00, 0x40, 0x00, 0x00, 0x00}};
72 /* called only in router mode */
73 static int set_zones(ifz
)
76 /* 1. adds zone to table
77 2. looks up each route entry from zone list
78 3. sets zone bit in each route entry
80 returns 0 if successful
81 errno if error occurred
89 zno
= zt_add_zone(ifz
->zone_name
.str
, ifz
->zone_name
.len
);
91 if (zno
== ZT_MAXEDOUT
) {
92 dPrintf(D_M_ELAP
, D_L_ERROR
, ("set_zones: error: table full\n"));
96 ifID_home
->ifZoneName
= ifz
->zone_name
;
97 ifID_home
->ifDefZone
= zno
;
100 for (i
=0; i
<IF_TOTAL_MAX
; i
++) {
101 if (ifz
->zone_iflist
.at_if
[i
][0]) {
102 if ((ifID
= find_ifID(ifz
->zone_iflist
.at_if
[i
]))) {
103 rte
= rt_blookup(ifID
->ifThisCableEnd
);
105 dPrintf(D_M_ELAP
, D_L_ERROR
,
106 ("set_zones: error: can't find route\n"));
108 zt_set_zmap(zno
, rte
->ZoneBitMap
);
110 /* if first zone for this I/F,
112 if (!ifID
->ifDefZone
)
113 ifID
->ifDefZone
= zno
;
123 * Generic internet control operations (ioctl's).
124 * ifp is 0 if not an interface-specific ioctl.
127 int at_control(so
, cmd
, data
, ifp
)
133 struct ifreq
*ifr
= (struct ifreq
*)data
;
134 int pat_id
= 0, error
= 0;
135 struct proc
*p
= current_proc();
136 at_ifaddr_t
*ifID
= 0;
138 struct sockaddr_dl
*sdl
;
140 if (cmd
== 0x2000ff99) {
141 /* *** this is a temporary hack to get at_send_to_dev() to
142 work with BSD-style sockets instead of the special purpose
143 system calls, ATsocket() and ATioctl().
145 if ((error
= at_ioctl((struct atpcb
*)so
->so_pcb
, cmd
, data
, 0))) {
146 if (((struct atpcb
*)so
->so_pcb
)->proto
!= ATPROTO_LAP
) {
147 ((struct atpcb
*)so
->so_pcb
)->proto
= ATPROTO_LAP
;
148 error
= at_ioctl((struct atpcb
*)so
->so_pcb
, cmd
, data
, 0);
153 /* *** processing should be
158 * Find address for this interface, if it exists.
161 for (pat_id
= 0; pat_id
< xpatcnt
; pat_id
++)
162 if (at_interfaces
[pat_id
].aa_ifp
== ifp
) {
163 ifID
= &at_interfaces
[pat_id
];
171 at_state_t
*global_state
= (at_state_t
*)data
;
173 *global_state
= at_state
;
180 at_if_cfg_t
*cfgp
= (at_if_cfg_t
*)data
;
183 if ((at_state
.flags
& AT_ST_STARTED
) &&
185 if (strlen(cfgp
->ifr_name
)) {
186 TAILQ_FOREACH(ifID
, &at_ifQueueHd
, aa_link
) {
187 if (!strncmp(ifID
->ifName
, cfgp
->ifr_name
,
188 strlen(ifID
->ifName
)))
193 strncpy(cfgp
->ifr_name
, ifID
->ifName
,
194 sizeof(ifID
->ifName
));
196 if (ifID
&& ifID
->ifState
!= LAP_OFFLINE
) {
197 cfgp
->flags
= ifID
->ifFlags
;
198 /* put the IF state into the low order
200 cfgp
->flags
|= (ifID
->ifState
& LAP_STATE_MASK
);
201 cfgp
->node
= ifID
->ifThisNode
;
202 cfgp
->router
= ifID
->ifARouter
;
203 cfgp
->netStart
= ifID
->ifThisCableStart
;
204 cfgp
->netEnd
= ifID
->ifThisCableEnd
;
205 cfgp
->zonename
= ifID
->ifZoneName
;
216 at_def_zone_t
*defzonep
= (at_def_zone_t
*)data
;
218 /* check for root access */
219 if (error
= suser(p
->p_ucred
, &p
->p_acflag
))
223 if ((at_state
.flags
& AT_ST_STARTED
) && ifID_home
) {
224 if (strlen(defzonep
->ifr_name
)) {
225 TAILQ_FOREACH(ifID
, &at_ifQueueHd
, aa_link
) {
226 if (!strncmp(ifID
->ifName
, defzonep
->ifr_name
,
227 strlen(ifID
->ifName
)))
232 strncpy(defzonep
->ifr_name
, ifID
->ifName
,
233 sizeof(ifID
->ifName
));
236 /* In routing mode the default zone is only set for the
237 default interface. */
238 if (ROUTING_MODE
&& (ifID
!= ifID_home
))
241 if (ifID
&& ifID
->ifState
!= LAP_OFFLINE
) {
242 if (zonename_equal(&ifID
->ifZoneName
,
243 &defzonep
->zonename
))
246 /* check the zone name */
247 if (MULTIPORT_MODE
) {
249 char ifs_in_zone
[IF_TOTAL_MAX
];
251 if (!(zno
= zt_find_zname(&defzonep
->zonename
)))
254 getIfUsage(zno
-1, ifs_in_zone
);
255 if (!ifs_in_zone
[ifID
->ifPort
])
257 ifID
->ifDefZone
= zno
+1;
262 for (i
= 0, zone
= getSPLocalZone(i
);
264 i
++, zone
= getSPLocalZone(i
)) {
265 if (zonename_equal(zone
,
266 &defzonep
->zonename
))
272 ifID
->ifZoneName
= defzonep
->zonename
;
273 (void)regDefaultZone(ifID
);
285 at_nvestr_t
*zone
= (at_nvestr_t
*)data
;
287 if (!(at_state
.flags
& AT_ST_STARTED
) || !ifID_home
)
293 return(setLocalZones(zone
, zone
->len
));
298 if (!(at_state
.flags
& AT_ST_STARTED
) || !ifID_home
)
304 return(set_zones((zone_usage_t
*)data
));
309 if (!(at_state
.flags
& AT_ST_STARTED
) || !ifID_home
)
315 if (getRTRLocalZone((zone_usage_t
*)data
))
323 at_nbp_reg_t
*nbpP
= (at_nbp_reg_t
*)data
;
327 if (!(at_state
.flags
& AT_ST_STARTED
) || !ifID_home
)
330 /* multihoming mode */
331 if (MULTIHOME_MODE
) {
332 return(nbp_mh_reg(nbpP
));
335 /* single port mode or router mode */
336 if (nbp_fillin_nve(&nbpP
->name
, &nve
) != 0) {
341 /* In routing mode when the zone is specified, we need to
342 find an interface on which the specified zone is seeded, so
343 that the zone multicast will be plausible. */
344 if (ROUTING_MODE
&& !(DEFAULT_ZONE(&nve
.zone
))) {
345 /* find first segment (interface) which is seeded for
347 int finished
= FALSE
;
349 char ifs_in_zone
[IF_TOTAL_MAX
];
350 if (!(zno
= zt_find_zname(&nve
.zone
))) {
353 getIfUsage(zno
-1, ifs_in_zone
);
355 TAILQ_FOREACH(ifID
, &at_ifQueueHd
, aa_link
) {
356 if (!ifs_in_zone
[ifID
->ifPort
])
357 /* zone doesn't match */
367 nve
.address
.net
= ifID
->ifThisNode
.s_net
;
368 nve
.address
.node
= ifID
->ifThisNode
.s_node
;
369 nve
.address
.socket
= nbpP
->addr
.socket
;
370 nve
.ddptype
= nbpP
->ddptype
;
372 if (nbp_find_nve(&nve
))
373 return(EADDRNOTAVAIL
);
375 /* Normal case; no tuple found for this name, so insert
376 * this tuple in the registry and return ok response.
378 ATDISABLE(nve_lock
, NVE_LOCK
);
379 if ((error
= nbp_new_nve_entry(&nve
, ifID
)) == 0) {
380 nbpP
->addr
.net
= ifID
->ifThisNode
.s_net
;
381 nbpP
->addr
.node
= ifID
->ifThisNode
.s_node
;
382 nbpP
->unique_nbp_id
= nve
.unique_nbp_id
;
384 ATENABLE(nve_lock
, NVE_LOCK
);
392 at_nbp_reg_t
*nbpP
= (at_nbp_reg_t
*)data
;
393 nve_entry_t
*nve_entry
, nve
;
395 if (!(at_state
.flags
& AT_ST_STARTED
))
399 if (nbpP
->unique_nbp_id
) {
400 ATDISABLE(nve_lock
, NVE_LOCK
);
401 TAILQ_FOREACH(nve_entry
, &name_registry
, nve_link
) {
402 if (nve_entry
->unique_nbp_id
== nbpP
->unique_nbp_id
) {
404 nbp_delete_entry(nve_entry
);
405 ATENABLE(nve_lock
, NVE_LOCK
);
409 ATENABLE(nve_lock
, NVE_LOCK
);
410 return(EADDRNOTAVAIL
);
413 /* delete by entity */
414 if (nbp_fillin_nve(&nbpP
->name
, &nve
) != 0) {
419 if (MULTIHOME_MODE
&& DEFAULT_ZONE(&nbpP
->name
.zone
)) {
420 /* if mhome & *, remove nve from all default zones */
421 int found
= FALSE
; /* if any found & deleted */
423 TAILQ_FOREACH(ifID
, &at_ifQueueHd
, aa_link
) {
424 nve
.zone
= ifID
->ifZoneName
;
425 nve
.zone_hash
= nbp_strhash(&nve
.zone
);
426 if ((nve_entry
= nbp_find_nve(&nve
)) == NULL
)
429 ATDISABLE(nve_lock
, NVE_LOCK
);
430 nbp_delete_entry(nve_entry
);
431 ATENABLE(nve_lock
, NVE_LOCK
);
437 return(EADDRNOTAVAIL
);
440 if ((nve_entry
= nbp_find_nve(&nve
)) == NULL
)
441 /* Can't find the tuple we're looking for, send error*/
442 return(EADDRNOTAVAIL
);
444 /* Normal case; tuple found for this name, so delete
445 * the entry from the registry and return ok response.
447 ATDISABLE(nve_lock
, NVE_LOCK
);
448 nbp_delete_entry(nve_entry
);
449 ATENABLE(nve_lock
, NVE_LOCK
);
457 at_router_params_t
*rt
= (at_router_params_t
*)data
;
459 /* check for root access */
460 if (error
= suser(p
->p_ucred
, &p
->p_acflag
))
463 /* when in routing/multihome mode the AIOCSETROUTER IOCTL
465 if (at_state
.flags
& AT_ST_STARTED
)
468 /* Setup the routing & zip table size for the router */
469 if (rt
->rtmp_table_sz
>= RT_MIN
&& rt
->rtmp_table_sz
<= RT_MAX
)
470 RT_maxentry
= rt
->rtmp_table_sz
;
472 RT_maxentry
= RT_DEFAULT
;
474 if (rt
->zone_table_sz
>= ZT_MIN
&& rt
->zone_table_sz
<= ZT_MAX
)
475 ZT_maxentry
= rt
->zone_table_sz
;
477 ZT_maxentry
= ZT_DEFAULT
;
479 if (rt_table_init() == ENOBUFS
)
483 RouterMix
= (int)rt
->router_mix
;
485 RouterMix
= RT_MIX_DEFAULT
;
487 add_ddp_handler(RTMP_SOCKET
, rtmp_router_input
);
490 at_state
.flags
|= AT_ST_MULTIHOME
;
492 at_state
.flags
|= AT_ST_ROUTER
;
495 case AIOCSTARTROUTER
:
497 at_kern_err_t
*keP
= (at_kern_err_t
*)data
;
499 /* check for root access */
500 if (suser(p
->p_ucred
, &p
->p_acflag
))
503 if (!(at_state
.flags
& AT_ST_STARTED
))
506 bzero(keP
, sizeof(at_kern_err_t
));
507 error
= routerStart(keP
);
513 at_router_params_t
*rt
= (at_router_params_t
*)data
;
515 if (!(at_state
.flags
& AT_ST_STARTED
))
518 rt
->multihome
= (MULTIHOME_MODE
)? 1: 0;
519 rt
->rtmp_table_sz
= RT_maxentry
;
520 rt
->zone_table_sz
= ZT_maxentry
;
521 rt
->router_mix
= RouterMix
;
527 int *count_only
= (int *)data
,
530 /* check for root access */
531 if (error
= suser(p
->p_ucred
, &p
->p_acflag
))
534 ret
= ddp_shutdown(*count_only
);
539 return((ret
== 0)? 0 : EBUSY
);
544 /* check for root access */
545 if (error
= suser(p
->p_ucred
, &p
->p_acflag
))
552 at_state
.flags
|= AT_ST_STARTED
;
556 /* *** find an empty entry *** */
557 ifID
= &at_interfaces
[xpatcnt
];
558 bzero((caddr_t
)ifID
, sizeof(at_ifaddr_t
));
559 strncpy(ifID
->ifName
, ifr
->ifr_name
, sizeof(ifID
->ifName
));
563 TAILQ_FOREACH(ifa
, &ifp
->if_addrhead
, ifa_link
)
564 if ((sdl
= (struct sockaddr_dl
*)ifa
->ifa_addr
) &&
565 (sdl
->sdl_family
== AF_LINK
)) {
566 bcopy(LLADDR(sdl
), ifID
->xaddr
, sizeof(ifID
->xaddr
));
567 #ifdef APPLETALK_DEBUG
568 kprintf("SIOCSIFADDR: local enet address is %x.%x.%x.%x.%x.%x\n",
569 ifID
->xaddr
[0], ifID
->xaddr
[1],
570 ifID
->xaddr
[2], ifID
->xaddr
[3],
571 ifID
->xaddr
[4], ifID
->xaddr
[5]);
576 /* attach the AppleTalk address to the ifnet structure */
578 ifa
->ifa_addr
= (struct sockaddr
*)&ifID
->ifNodeAddress
;
579 ifID
->ifNodeAddress
.sat_len
= sizeof(struct sockaddr_at
);
580 ifID
->ifNodeAddress
.sat_family
= AF_APPLETALK
;
581 /* the address itself will be filled in when ifThisNode
584 TAILQ_INSERT_TAIL(&ifp
->if_addrhead
, ifa
, ifa_link
);
587 switch (ifp
->if_type
) {
589 ether_attach_at(ifp
, &ifID
->at_dl_tag
,
592 ifID
->cable_multicast_addr
= etalk_multicast_addr
;
597 ifID
->cable_multicast_addr
= etalk_multicast_addr
;
598 ddp_bit_reverse(&ifID
->cable_multicast_addr
);
601 case IFT_ISO88025
: /* token ring */
602 ifID
->cable_multicast_addr
= ttalk_multicast_addr
;
603 ddp_bit_reverse(&ifID
->cable_multicast_addr
);
613 /* complete the initialization started in SIOCSIFADDR */
616 at_if_cfg_t
*cfgp
= (at_if_cfg_t
*)data
;
618 if (!(at_state
.flags
& AT_ST_STARTED
))
621 if (!(ifID
= find_ifID(cfgp
->ifr_name
)))
624 return(lap_online(ifID
, cfgp
));
629 /* *** this can't be added until AT can handle dynamic addition and
630 deletion of interfaces *** */
632 /* check for root access */
633 if (error
= suser(p
->p_ucred
, &p
->p_acflag
))
644 struct atpcb
*at_pcb
, *clonedat_pcb
;
645 int cloned_fd
= *(int *)data
;
647 s
= splnet(); /* XXX */
648 at_pcb
= sotoatpcb(so
);
650 /* let's make sure it's either -1 or a valid file descriptor */
651 if (cloned_fd
!= -1) {
652 struct socket
*cloned_so
;
653 struct file
*cloned_fp
;
654 error
= getsock(p
->p_fd
, cloned_fd
, &cloned_fp
);
659 cloned_so
= (struct socket
*)cloned_fp
->f_data
;
660 clonedat_pcb
= sotoatpcb(cloned_so
);
665 if (clonedat_pcb
== NULL
) {
666 at_pcb
->ddp_flags
|= DDPFLG_STRIPHDR
;
668 at_pcb
->ddp_flags
= clonedat_pcb
->ddp_flags
;
675 if (ifp
== 0 || ifp
->if_ioctl
== 0)
677 return dlil_ioctl(0, ifp
, cmd
, (caddr_t
) data
);