darwin-xnu/bsd/netat/at.c
<<
>>
Prefs
   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#include <sys/file.h>
  37#include <sys/kauth.h>
  38
  39#include <net/if.h>
  40#include <net/if_dl.h>
  41#include <net/if_types.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/debug.h>
  52
  53#include <sys/kern_event.h>
  54
  55extern int at_ioctl(struct atpcb *, u_long, caddr_t, int fromKernel);
  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
 128int
 129at_control(so, cmd, data, ifp)
 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
 142    if ((cmd & 0xffff) == 0xff99) {
 143                u_long  fixed_command;
 144                char ioctl_buffer[32];
 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                   *** */
 149                fixed_command = _IOW(0, 0xff99, user_addr_t); 
 150                if ((error = at_ioctl((struct atpcb *)so->so_pcb, fixed_command, data, 0))) {
 151                  if (((struct atpcb *)so->so_pcb)->proto != ATPROTO_LAP) {
 152                    ((struct atpcb *)so->so_pcb)->proto = ATPROTO_LAP;
 153                    error = at_ioctl((struct atpcb *)so->so_pcb, fixed_command, data , 0);
 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 */
 224                if (error = suser(kauth_cred_get(), 0))
 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;
 254                                          at_ifnames_t ifs_in_zone;
 255
 256                                          if (!(zno = zt_find_zname(&defzonep->zonename)))
 257                                            return(EINVAL);
 258
 259                                          getIfUsage(zno-1, &ifs_in_zone);
 260                                          if (!ifs_in_zone.at_if[ifID->ifPort]) 
 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);
 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
 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;
 334                int error2;
 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;
 358                        at_ifnames_t ifs_in_zone;
 359                        if (!(zno = zt_find_zname(&nve.zone))) {
 360                                return(EINVAL);
 361                        }
 362                        getIfUsage(zno-1, &ifs_in_zone);
 363
 364                        TAILQ_FOREACH(ifID, &at_ifQueueHd, aa_link) {
 365                                if (!ifs_in_zone.at_if[ifID->ifPort]) 
 366                                                /* zone doesn't match */
 367                                        continue;
 368                                else {
 369                                        finished = TRUE;
 370                                        break;
 371                                }
 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);
 390                if ((error2 = nbp_new_nve_entry(&nve, ifID)) == 0) {
 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
 397                return(error2);
 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 */
 471                if (error = suser(kauth_cred_get(), 0))
 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 */
 511                if (suser(kauth_cred_get(), 0))
 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:
 537        {
 538                int *count_only = (int *)data,
 539                    ret;
 540
 541                /* check for root access */
 542                if (error = suser(kauth_cred_get(), 0))
 543                        return(EACCES);
 544
 545                ret = ddp_shutdown(*count_only);
 546                
 547                if (*count_only != 0) 
 548                {
 549                        *count_only = ret;
 550                        return(0);
 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
 564                break;
 565        }
 566
 567        case SIOCSIFADDR:
 568                /* check for root access */
 569                if (error = suser(kauth_cred_get(), 0))
 570                        error = EACCES;
 571                else if (ifID)
 572                        error = EEXIST;
 573                else {
 574                        int s;
 575                        if (xpatcnt == 0) {
 576                                at_state.flags |= AT_ST_STARTING;
 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;
 587                        ifnet_lock_exclusive(ifp);
 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 */
 608                        if_attach_ifa(ifp, ifa);
 609                        ifnet_lock_done(ifp);
 610
 611                        switch (ifp->if_type) {
 612                        case IFT_ETHER:
 613                        case IFT_L2VLAN:
 614                        case IFT_IEEE8023ADLAG: /* bonded ethernet */
 615                                ether_attach_at(ifp);
 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:
 640        {
 641                at_if_cfg_t *cfgp = (at_if_cfg_t *)data;
 642
 643                if (!(at_state.flags & AT_ST_STARTING))
 644                        return(ENOTREADY);
 645 
 646                if (!(ifID = find_ifID(cfgp->ifr_name)))
 647                        return(EINVAL);
 648                
 649                return(lap_online(ifID, cfgp));
 650                break;
 651        }
 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 */
 658                if (error = suser(kauth_cred_get(), 0))
 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;
 678                        error = file_socket(cloned_fd, &cloned_so);
 679            if (error){
 680                splx(s);        /* XXX */
 681                break;
 682            }
 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 */
 694                file_drop(cloned_fd);
 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}
 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}
 739
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.