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> 
  43 #include <netat/appletalk.h> 
  44 #include <netat/sysglue.h> 
  45 #include <netat/at_pcb.h> 
  46 #include <netat/at_var.h> 
  47 #include <netat/ddp.h> 
  48 #include <netat/nbp.h> 
  49 #include <netat/routing_tables.h> 
  50 #include <netat/debug.h> 
  52 #include <sys/kern_event.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                                           at_ifnames_t ifs_in_zone
; 
 251                                           if (!(zno 
= zt_find_zname(&defzonep
->zonename
))) 
 254                                           getIfUsage(zno
-1, &ifs_in_zone
); 
 255                                           if (!ifs_in_zone
.at_if
[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
); 
 275                                         /* AppleTalk zone was changed. Send event with zone info. */ 
 276                                         atalk_post_msg(ifID
->aa_ifp
, KEV_ATALK_ZONEUPDATED
, 0, &(ifID
->ifZoneName
)); 
 289                 at_nvestr_t 
*zone 
= (at_nvestr_t 
*)data
; 
 291                 if (!(at_state
.flags 
& AT_ST_STARTED
) || !ifID_home
) 
 297                 return(setLocalZones(zone
, zone
->len
)); 
 302                 if (!(at_state
.flags 
& AT_ST_STARTED
) || !ifID_home
) 
 308                 return(set_zones((zone_usage_t 
*)data
)); 
 313                 if (!(at_state
.flags 
& AT_ST_STARTED
) || !ifID_home
) 
 319                 if (getRTRLocalZone((zone_usage_t 
*)data
)) 
 327                 at_nbp_reg_t 
*nbpP 
= (at_nbp_reg_t 
*)data
; 
 331                 if (!(at_state
.flags 
& AT_ST_STARTED
) || !ifID_home
) 
 334                 /* multihoming mode */ 
 335                 if (MULTIHOME_MODE
) { 
 336                         return(nbp_mh_reg(nbpP
)); 
 339                 /* single port mode or router mode */ 
 340                 if (nbp_fillin_nve(&nbpP
->name
, &nve
) != 0) { 
 345                 /* In routing mode when the zone is specified, we need to  
 346                    find an interface on which the specified zone is seeded, so 
 347                    that the zone multicast will be plausible. */ 
 348                 if (ROUTING_MODE 
&& !(DEFAULT_ZONE(&nve
.zone
))) { 
 349                         /* find first segment (interface) which is seeded for  
 351                         int finished 
= FALSE
; 
 353                         at_ifnames_t ifs_in_zone
; 
 354                         if (!(zno 
= zt_find_zname(&nve
.zone
))) { 
 357                         getIfUsage(zno
-1, &ifs_in_zone
); 
 359                         TAILQ_FOREACH(ifID
, &at_ifQueueHd
, aa_link
) { 
 360                                 if (!ifs_in_zone
.at_if
[ifID
->ifPort
])  
 361                                                 /* zone doesn't match */ 
 373                 nve
.address
.net 
= ifID
->ifThisNode
.s_net
; 
 374                 nve
.address
.node 
= ifID
->ifThisNode
.s_node
; 
 375                 nve
.address
.socket 
= nbpP
->addr
.socket
; 
 376                 nve
.ddptype 
= nbpP
->ddptype
; 
 378                 if (nbp_find_nve(&nve
)) 
 379                         return(EADDRNOTAVAIL
); 
 381                 /* Normal case; no tuple found for this name, so insert 
 382                  * this tuple in the registry and return ok response. 
 384                 ATDISABLE(nve_lock
, NVE_LOCK
); 
 385                 if ((error 
= nbp_new_nve_entry(&nve
, ifID
)) == 0) { 
 386                         nbpP
->addr
.net 
= ifID
->ifThisNode
.s_net
; 
 387                         nbpP
->addr
.node 
= ifID
->ifThisNode
.s_node
; 
 388                         nbpP
->unique_nbp_id 
= nve
.unique_nbp_id
; 
 390                 ATENABLE(nve_lock
, NVE_LOCK
); 
 398                 at_nbp_reg_t 
*nbpP 
= (at_nbp_reg_t 
*)data
; 
 399                 nve_entry_t    
*nve_entry
, nve
; 
 401                 if (!(at_state
.flags 
& AT_ST_STARTED
)) 
 405                 if (nbpP
->unique_nbp_id
) { 
 406                         ATDISABLE(nve_lock
, NVE_LOCK
); 
 407                         TAILQ_FOREACH(nve_entry
, &name_registry
, nve_link
) { 
 408                                 if (nve_entry
->unique_nbp_id 
== nbpP
->unique_nbp_id
) { 
 410                                         nbp_delete_entry(nve_entry
); 
 411                                         ATENABLE(nve_lock
, NVE_LOCK
); 
 415                         ATENABLE(nve_lock
, NVE_LOCK
); 
 416                         return(EADDRNOTAVAIL
); 
 419                 /* delete by entity */ 
 420                 if (nbp_fillin_nve(&nbpP
->name
, &nve
) != 0) { 
 425                 if (MULTIHOME_MODE 
&& DEFAULT_ZONE(&nbpP
->name
.zone
)) { 
 426                         /* if mhome & *, remove nve from all default zones */ 
 427                         int found 
= FALSE
;      /* if any found & deleted */ 
 429                         TAILQ_FOREACH(ifID
, &at_ifQueueHd
, aa_link
) { 
 430                                 nve
.zone 
= ifID
->ifZoneName
; 
 431                                 nve
.zone_hash 
= nbp_strhash(&nve
.zone
); 
 432                                 if ((nve_entry 
= nbp_find_nve(&nve
)) == NULL
)  
 435                                 ATDISABLE(nve_lock
, NVE_LOCK
); 
 436                                 nbp_delete_entry(nve_entry
); 
 437                                 ATENABLE(nve_lock
, NVE_LOCK
); 
 443                                 return(EADDRNOTAVAIL
); 
 446                 if ((nve_entry 
= nbp_find_nve(&nve
)) == NULL
) 
 447                         /* Can't find the tuple we're looking for, send error*/ 
 448                         return(EADDRNOTAVAIL
); 
 450                 /* Normal case; tuple found for this name, so delete 
 451                  * the entry from the registry and return ok response. 
 453                 ATDISABLE(nve_lock
, NVE_LOCK
); 
 454                 nbp_delete_entry(nve_entry
); 
 455                 ATENABLE(nve_lock
, NVE_LOCK
); 
 463                 at_router_params_t 
*rt 
= (at_router_params_t 
*)data
; 
 465                 /* check for root access */ 
 466                 if (error 
= suser(p
->p_ucred
, &p
->p_acflag
)) 
 469                 /* when in routing/multihome mode the AIOCSETROUTER IOCTL  
 471                 if (at_state
.flags 
& AT_ST_STARTED
) 
 474                 /* Setup the routing & zip table size for the router */ 
 475                 if (rt
->rtmp_table_sz 
>= RT_MIN 
&& rt
->rtmp_table_sz 
<= RT_MAX
) 
 476                         RT_maxentry 
= rt
->rtmp_table_sz
; 
 478                         RT_maxentry 
= RT_DEFAULT
; 
 480                 if (rt
->zone_table_sz 
>= ZT_MIN 
&& rt
->zone_table_sz 
<= ZT_MAX
) 
 481                         ZT_maxentry 
= rt
->zone_table_sz
; 
 483                         ZT_maxentry 
= ZT_DEFAULT
; 
 485                 if (rt_table_init() == ENOBUFS
) 
 489                         RouterMix 
= (int)rt
->router_mix
; 
 491                         RouterMix 
= RT_MIX_DEFAULT
; 
 493                 add_ddp_handler(RTMP_SOCKET
, rtmp_router_input
); 
 496                         at_state
.flags 
|= AT_ST_MULTIHOME
; 
 498                         at_state
.flags 
|= AT_ST_ROUTER
; 
 501         case AIOCSTARTROUTER
: 
 503                 at_kern_err_t 
*keP 
= (at_kern_err_t 
*)data
; 
 505                 /* check for root access */ 
 506                 if (suser(p
->p_ucred
, &p
->p_acflag
)) 
 509                 if (!(at_state
.flags 
& AT_ST_STARTED
)) 
 512                 bzero(keP
, sizeof(at_kern_err_t
)); 
 513                 error 
= routerStart(keP
); 
 519                 at_router_params_t 
*rt 
= (at_router_params_t 
*)data
; 
 521                 if (!(at_state
.flags 
& AT_ST_STARTED
)) 
 524                 rt
->multihome 
= (MULTIHOME_MODE
)? 1: 0; 
 525                 rt
->rtmp_table_sz 
= RT_maxentry
; 
 526                 rt
->zone_table_sz 
= ZT_maxentry
; 
 527                 rt
->router_mix 
= RouterMix
; 
 533                 int *count_only 
= (int *)data
, 
 536                 /* check for root access */ 
 537                 if (error 
= suser(p
->p_ucred
, &p
->p_acflag
)) 
 540                 ret 
= ddp_shutdown(*count_only
); 
 542                 if (*count_only 
!= 0)  
 551                                 /* AppleTalk was successfully shut down. Send event. */ 
 552                                 atalk_post_msg(0, KEV_ATALK_DISABLED
, 0, 0); 
 563                 /* check for root access */ 
 564                 if (error 
= suser(p
->p_ucred
, &p
->p_acflag
)) 
 571                                 at_state
.flags 
|= AT_ST_STARTING
; 
 575                         /* *** find an empty entry *** */ 
 576                         ifID 
= &at_interfaces
[xpatcnt
]; 
 577                         bzero((caddr_t
)ifID
, sizeof(at_ifaddr_t
)); 
 578                         strncpy(ifID
->ifName
, ifr
->ifr_name
, sizeof(ifID
->ifName
)); 
 582                         TAILQ_FOREACH(ifa
, &ifp
->if_addrhead
, ifa_link
)  
 583                                 if ((sdl 
= (struct sockaddr_dl 
*)ifa
->ifa_addr
) && 
 584                                       (sdl
->sdl_family 
== AF_LINK
)) { 
 585                                     bcopy(LLADDR(sdl
), ifID
->xaddr
, sizeof(ifID
->xaddr
)); 
 586 #ifdef APPLETALK_DEBUG 
 587                                     kprintf("SIOCSIFADDR: local enet address is %x.%x.%x.%x.%x.%x\n",  
 588                                             ifID
->xaddr
[0], ifID
->xaddr
[1],  
 589                                             ifID
->xaddr
[2], ifID
->xaddr
[3],  
 590                                             ifID
->xaddr
[4], ifID
->xaddr
[5]); 
 595                         /* attach the AppleTalk address to the ifnet structure */ 
 597                         ifa
->ifa_addr 
= (struct sockaddr 
*)&ifID
->ifNodeAddress
; 
 598                         ifID
->ifNodeAddress
.sat_len 
= sizeof(struct sockaddr_at
); 
 599                         ifID
->ifNodeAddress
.sat_family 
=  AF_APPLETALK
; 
 600                         /* the address itself will be filled in when ifThisNode 
 603                         TAILQ_INSERT_TAIL(&ifp
->if_addrhead
, ifa
, ifa_link
); 
 606                         switch (ifp
->if_type
) { 
 608                                 ether_attach_at(ifp
, &ifID
->at_dl_tag
,  
 611                                 ifID
->cable_multicast_addr 
= etalk_multicast_addr
; 
 616                                 ifID
->cable_multicast_addr 
= etalk_multicast_addr
; 
 617                                 ddp_bit_reverse(&ifID
->cable_multicast_addr
); 
 620                         case IFT_ISO88025
: /* token ring */      
 621                                 ifID
->cable_multicast_addr 
= ttalk_multicast_addr
; 
 622                                 ddp_bit_reverse(&ifID
->cable_multicast_addr
); 
 632         /* complete the initialization started in SIOCSIFADDR */ 
 635                 at_if_cfg_t 
*cfgp 
= (at_if_cfg_t 
*)data
; 
 637                 if (!(at_state
.flags 
& AT_ST_STARTING
)) 
 640                 if (!(ifID 
= find_ifID(cfgp
->ifr_name
))) 
 643                 return(lap_online(ifID
, cfgp
)); 
 648         /* *** this can't be added until AT can handle dynamic addition and 
 649                deletion of interfaces *** */ 
 651                 /* check for root access */ 
 652                 if (error 
= suser(p
->p_ucred
, &p
->p_acflag
)) 
 663         struct atpcb    
*at_pcb
, *clonedat_pcb
; 
 664         int                             cloned_fd 
= *(int *)data
; 
 666         s 
= splnet();           /* XXX */ 
 667         at_pcb 
= sotoatpcb(so
); 
 669         /* let's make sure it's either -1 or a valid file descriptor */ 
 670         if (cloned_fd 
!= -1) { 
 671             struct socket       
*cloned_so
; 
 672             struct file     
*cloned_fp
; 
 673             error 
= getsock(p
->p_fd
, cloned_fd
, &cloned_fp
); 
 678             cloned_so 
= (struct socket 
*)cloned_fp
->f_data
; 
 679             clonedat_pcb 
= sotoatpcb(cloned_so
); 
 684         if (clonedat_pcb 
== NULL
) { 
 685             at_pcb
->ddp_flags 
|= DDPFLG_STRIPHDR
; 
 687             at_pcb
->ddp_flags 
= clonedat_pcb
->ddp_flags
; 
 694                 if (ifp 
== 0 || ifp
->if_ioctl 
== 0) 
 696                 return dlil_ioctl(0, ifp
, cmd
, (caddr_t
) data
); 
 702 /* From dlil_post_msg() */ 
 703 void atalk_post_msg(struct ifnet 
*ifp
, u_long event_code
, struct at_addr 
*address
, at_nvestr_t 
*zone
)  
 705         struct kev_atalk_data   at_event_data
; 
 706         struct kev_msg                  ev_msg
; 
 708         ev_msg
.vendor_code    
= KEV_VENDOR_APPLE
; 
 709         ev_msg
.kev_class      
= KEV_NETWORK_CLASS
; 
 710         ev_msg
.kev_subclass   
= KEV_ATALK_SUBCLASS
; 
 711         ev_msg
.event_code         
= event_code
; 
 713         bzero(&at_event_data
, sizeof(struct kev_atalk_data
)); 
 716                 strncpy(&at_event_data
.link_data
.if_name
[0], ifp
->if_name
, IFNAMSIZ
); 
 717                 at_event_data
.link_data
.if_family 
= ifp
->if_family
; 
 718                 at_event_data
.link_data
.if_unit   
= (unsigned long) ifp
->if_unit
; 
 722                 at_event_data
.node_data
.address 
= *address
; 
 724         else if (zone 
!= 0) { 
 725                 at_event_data
.node_data
.zone 
= *zone
; 
 728         ev_msg
.dv
[0].data_length 
= sizeof(struct kev_atalk_data
); 
 729         ev_msg
.dv
[0].data_ptr    
= &at_event_data
;       
 730         ev_msg
.dv
[1].data_length 
= 0; 
 732         kev_post_msg(&ev_msg
);