Annotation of XNU/bsd/netat/at.c, revision 1.1.1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.