|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.