Annotation of sys/netatalk/at_control.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: at_control.c,v 1.10 2007/04/10 17:47:55 miod Exp $ */
! 2:
! 3: /*
! 4: * Copyright (c) 1990,1991 Regents of The University of Michigan.
! 5: * All Rights Reserved.
! 6: */
! 7:
! 8: /*
! 9: * The following is the contents of the COPYRIGHT file from the
! 10: * netatalk-1.4a2 distribution, from which this file is derived.
! 11: */
! 12: /*
! 13: * Copyright (c) 1990,1996 Regents of The University of Michigan.
! 14: *
! 15: * All Rights Reserved.
! 16: *
! 17: * Permission to use, copy, modify, and distribute this software and
! 18: * its documentation for any purpose and without fee is hereby granted,
! 19: * provided that the above copyright notice appears in all copies and
! 20: * that both that copyright notice and this permission notice appear
! 21: * in supporting documentation, and that the name of The University
! 22: * of Michigan not be used in advertising or publicity pertaining to
! 23: * distribution of the software without specific, written prior
! 24: * permission. This software is supplied as is without expressed or
! 25: * implied warranties of any kind.
! 26: *
! 27: * This product includes software developed by the University of
! 28: * California, Berkeley and its contributors.
! 29: *
! 30: * Solaris code is encumbered by the following:
! 31: *
! 32: * Copyright (C) 1996 by Sun Microsystems Computer Co.
! 33: *
! 34: * Permission to use, copy, modify, and distribute this software and
! 35: * its documentation for any purpose and without fee is hereby
! 36: * granted, provided that the above copyright notice appear in all
! 37: * copies and that both that copyright notice and this permission
! 38: * notice appear in supporting documentation. This software is
! 39: * provided "as is" without express or implied warranty.
! 40: *
! 41: * Research Systems Unix Group
! 42: * The University of Michigan
! 43: * c/o Wesley Craig
! 44: * 535 W. William Street
! 45: * Ann Arbor, Michigan
! 46: * +1-313-764-2278
! 47: * netatalk@umich.edu
! 48: */
! 49: /*
! 50: * None of the Solaris code mentioned is included in OpenBSD.
! 51: * This code also relies heavily on previous effort in FreeBSD and NetBSD.
! 52: */
! 53:
! 54: #include <sys/param.h>
! 55: #include <sys/systm.h>
! 56: #include <sys/kernel.h>
! 57: #include <sys/malloc.h>
! 58: #include <sys/mbuf.h>
! 59: #include <sys/protosw.h>
! 60: #include <sys/socket.h>
! 61: #include <sys/ioctl.h>
! 62: #include <sys/errno.h>
! 63: #include <sys/syslog.h>
! 64: #include <sys/proc.h>
! 65: #include <sys/timeout.h>
! 66:
! 67: #include <net/if.h>
! 68: #include <net/route.h>
! 69: #include <netinet/in.h>
! 70: #undef s_net
! 71: #include <netinet/if_ether.h>
! 72: #include <net/if_llc.h>
! 73:
! 74: #include <netatalk/at.h>
! 75: #include <netatalk/at_var.h>
! 76: #include <netatalk/aarp.h>
! 77: #include <netatalk/phase2.h>
! 78: #include <netatalk/at_extern.h>
! 79:
! 80: #include <dev/rndvar.h>
! 81:
! 82: int at_control( u_long, caddr_t, struct ifnet *, struct proc * );
! 83: static int at_scrub( struct ifnet *, struct at_ifaddr * );
! 84: static int at_ifinit( struct ifnet *, struct at_ifaddr *,
! 85: struct sockaddr_at * );
! 86: int at_broadcast( struct sockaddr_at * );
! 87:
! 88: static int aa_dorangeroute(struct ifaddr *, u_int, u_int, int);
! 89: static int aa_addsingleroute(struct ifaddr *, struct at_addr *,
! 90: struct at_addr *);
! 91: static int aa_delsingleroute(struct ifaddr *, struct at_addr *,
! 92: struct at_addr *);
! 93: static int aa_dosingleroute(struct ifaddr *, struct at_addr *,
! 94: struct at_addr *, int, int );
! 95:
! 96: # define sateqaddr(a,b) ((a)->sat_len == (b)->sat_len && \
! 97: (a)->sat_family == (b)->sat_family && \
! 98: (a)->sat_addr.s_net == (b)->sat_addr.s_net && \
! 99: (a)->sat_addr.s_node == (b)->sat_addr.s_node )
! 100:
! 101: extern struct timeout aarpprobe_timeout;
! 102:
! 103: int
! 104: at_control( cmd, data, ifp, p )
! 105: u_long cmd;
! 106: caddr_t data;
! 107: struct ifnet *ifp;
! 108: struct proc *p;
! 109: {
! 110: struct ifreq *ifr = (struct ifreq *)data;
! 111: struct sockaddr_at *sat;
! 112: struct netrange *nr;
! 113: struct at_aliasreq *ifra = (struct at_aliasreq *)data;
! 114: struct at_ifaddr *aa0;
! 115: struct at_ifaddr *aa = 0;
! 116: struct ifaddr *ifa, *ifa0;
! 117:
! 118: if ( ifp ) {
! 119: for ( aa = at_ifaddr; aa; aa = aa->aa_next ) {
! 120: if ( aa->aa_ifp == ifp ) break;
! 121: }
! 122: }
! 123:
! 124: switch ( cmd ) {
! 125: case SIOCAIFADDR:
! 126: case SIOCDIFADDR:
! 127: if ( ifra->ifra_addr.sat_family == AF_APPLETALK ) {
! 128: for ( ; aa; aa = aa->aa_next ) {
! 129: if ( aa->aa_ifp == ifp &&
! 130: sateqaddr( &aa->aa_addr, &ifra->ifra_addr )) {
! 131: break;
! 132: }
! 133: }
! 134: }
! 135: if ( cmd == SIOCDIFADDR && aa == 0 ) {
! 136: return( EADDRNOTAVAIL );
! 137: }
! 138: /*FALLTHROUGH*/
! 139:
! 140: case SIOCSIFADDR:
! 141: /*
! 142: * What a great idea this is: Let's reverse the meaning of
! 143: * the return...
! 144: */
! 145: if ( suser( p, 0 )) {
! 146: return( EPERM );
! 147: }
! 148:
! 149: sat = satosat( &ifr->ifr_addr );
! 150: nr = (struct netrange *)sat->sat_zero;
! 151: if ( nr->nr_phase == 1 ) {
! 152: for ( ; aa; aa = aa->aa_next ) {
! 153: if ( aa->aa_ifp == ifp &&
! 154: ( aa->aa_flags & AFA_PHASE2 ) == 0 ) {
! 155: break;
! 156: }
! 157: }
! 158: } else { /* default to phase 2 */
! 159: for ( ; aa; aa = aa->aa_next ) {
! 160: if ( aa->aa_ifp == ifp && ( aa->aa_flags & AFA_PHASE2 )) {
! 161: break;
! 162: }
! 163: }
! 164: }
! 165:
! 166: if ( ifp == 0 )
! 167: panic( "at_control" );
! 168:
! 169: if ( aa == (struct at_ifaddr *) 0 ) {
! 170: aa0 = malloc(sizeof(struct at_ifaddr), M_IFADDR, M_WAITOK);
! 171: bzero(aa0, sizeof(struct at_ifaddr));
! 172:
! 173: if (( aa = at_ifaddr ) != NULL ) {
! 174: /*
! 175: * Don't let the loopback be first, since the first
! 176: * address is the machine's default address for
! 177: * binding.
! 178: */
! 179: if ( at_ifaddr->aa_ifp->if_flags & IFF_LOOPBACK ) {
! 180: aa = aa0;
! 181: aa->aa_next = at_ifaddr;
! 182: at_ifaddr = aa;
! 183: } else {
! 184: for ( ; aa->aa_next; aa = aa->aa_next )
! 185: ;
! 186: aa->aa_next = aa0;
! 187: }
! 188: } else {
! 189: at_ifaddr = aa0;
! 190: }
! 191:
! 192: aa = aa0;
! 193:
! 194: if (( ifa = ifp->if_addrlist.tqh_first ) != NULL ) {
! 195: for ( ; ifa->ifa_list.tqe_next; ifa = ifa->ifa_list.tqe_next )
! 196: ;
! 197: ifa->ifa_list.tqe_next = (struct ifaddr *)aa;
! 198: } else {
! 199: ifp->if_addrlist.tqh_first = (struct ifaddr *)aa;
! 200: }
! 201:
! 202: /* FreeBSD found this. Whew */
! 203: aa->aa_ifa.ifa_refcnt++;
! 204:
! 205: aa->aa_ifa.ifa_addr = (struct sockaddr *)&aa->aa_addr;
! 206: aa->aa_ifa.ifa_dstaddr = (struct sockaddr *)&aa->aa_addr;
! 207: aa->aa_ifa.ifa_netmask = (struct sockaddr *)&aa->aa_netmask;
! 208:
! 209: /*
! 210: * Set/clear the phase 2 bit.
! 211: */
! 212: if ( nr->nr_phase == 1 ) {
! 213: aa->aa_flags &= ~AFA_PHASE2;
! 214: } else {
! 215: aa->aa_flags |= AFA_PHASE2;
! 216: }
! 217: aa->aa_ifp = ifp;
! 218: } else {
! 219: at_scrub( ifp, aa );
! 220: }
! 221: break;
! 222:
! 223: case SIOCGIFADDR :
! 224: sat = satosat( &ifr->ifr_addr );
! 225: nr = (struct netrange *)sat->sat_zero;
! 226: if ( nr->nr_phase == 1 ) {
! 227: for ( ; aa; aa = aa->aa_next ) {
! 228: if ( aa->aa_ifp == ifp &&
! 229: ( aa->aa_flags & AFA_PHASE2 ) == 0 ) {
! 230: break;
! 231: }
! 232: }
! 233: } else { /* default to phase 2 */
! 234: for ( ; aa; aa = aa->aa_next ) {
! 235: if ( aa->aa_ifp == ifp && ( aa->aa_flags & AFA_PHASE2 )) {
! 236: break;
! 237: }
! 238: }
! 239: }
! 240:
! 241: if ( aa == (struct at_ifaddr *) 0 )
! 242: return( EADDRNOTAVAIL );
! 243: break;
! 244: }
! 245:
! 246: switch ( cmd ) {
! 247: case SIOCGIFADDR:
! 248: *(struct sockaddr_at *)&ifr->ifr_addr = aa->aa_addr;
! 249:
! 250: /* from FreeBSD : some cleanups about netranges */
! 251: ((struct netrange *)&sat->sat_zero)->nr_phase
! 252: = (aa->aa_flags & AFA_PHASE2) ? 2 : 1;
! 253: ((struct netrange *)&sat->sat_zero)->nr_firstnet = aa->aa_firstnet;
! 254: ((struct netrange *)&sat->sat_zero)->nr_lastnet = aa->aa_lastnet;
! 255: break;
! 256:
! 257: case SIOCSIFADDR:
! 258: return( at_ifinit( ifp, aa, (struct sockaddr_at *)&ifr->ifr_addr ));
! 259:
! 260: case SIOCAIFADDR:
! 261: if ( sateqaddr( &ifra->ifra_addr, &aa->aa_addr )) {
! 262: return( 0 );
! 263: }
! 264: return( at_ifinit( ifp, aa, (struct sockaddr_at *)&ifr->ifr_addr ));
! 265:
! 266: case SIOCDIFADDR:
! 267: at_scrub( ifp, aa );
! 268: ifa0 = (struct ifaddr *)aa;
! 269: if (( ifa = ifp->if_addrlist.tqh_first ) == ifa0 ) {
! 270: ifp->if_addrlist.tqh_first = ifa->ifa_list.tqe_next;
! 271: } else {
! 272: while ( ifa->ifa_list.tqe_next &&
! 273: ( ifa->ifa_list.tqe_next != ifa0 )) {
! 274: ifa = ifa->ifa_list.tqe_next;
! 275: }
! 276: if ( ifa->ifa_list.tqe_next ) {
! 277: ifa->ifa_list.tqe_next = ifa0->ifa_list.tqe_next;
! 278: } else {
! 279: panic( "at_control" );
! 280: }
! 281: }
! 282:
! 283: /* FreeBSD */
! 284: IFAFREE(ifa0);
! 285:
! 286: aa0 = aa;
! 287: if ( aa0 == ( aa = at_ifaddr )) {
! 288: at_ifaddr = aa->aa_next;
! 289: } else {
! 290: while ( aa->aa_next && ( aa->aa_next != aa0 )) {
! 291: aa = aa->aa_next;
! 292: }
! 293: if ( aa->aa_next ) {
! 294: aa->aa_next = aa0->aa_next;
! 295: } else {
! 296: panic( "at_control" );
! 297: }
! 298: }
! 299:
! 300: /* FreeBSD */
! 301: IFAFREE(ifa0);
! 302: break;
! 303:
! 304: default:
! 305: if ( ifp == 0 || ifp->if_ioctl == 0 )
! 306: return( EOPNOTSUPP );
! 307: return( (*ifp->if_ioctl)( ifp, cmd, data ));
! 308: }
! 309: return( 0 );
! 310: }
! 311:
! 312: /* replaced this routine with the one from FreeBSD */
! 313: static int
! 314: at_scrub( ifp, aa )
! 315: struct ifnet *ifp;
! 316: struct at_ifaddr *aa;
! 317: {
! 318: int error;
! 319:
! 320: if ( aa->aa_flags & AFA_ROUTE ) {
! 321: if (ifp->if_flags & IFF_LOOPBACK) {
! 322: if ((error = aa_delsingleroute(&aa->aa_ifa,
! 323: &aa->aa_addr.sat_addr,
! 324: &aa->aa_netmask.sat_addr))) {
! 325: return( error );
! 326: }
! 327: } else if (ifp->if_flags & IFF_POINTOPOINT) {
! 328: if ((error = rtinit( &aa->aa_ifa, RTM_DELETE, RTF_HOST)) != 0)
! 329: return( error );
! 330: } else if (ifp->if_flags & IFF_BROADCAST) {
! 331: error = aa_dorangeroute(&aa->aa_ifa,
! 332: ntohs(aa->aa_firstnet),
! 333: ntohs(aa->aa_lastnet),
! 334: RTM_DELETE );
! 335: }
! 336: aa->aa_ifa.ifa_flags &= ~IFA_ROUTE;
! 337: aa->aa_flags &= ~AFA_ROUTE;
! 338: }
! 339: return( 0 );
! 340: }
! 341:
! 342: static int
! 343: at_ifinit( ifp, aa, sat )
! 344: struct ifnet *ifp;
! 345: struct at_ifaddr *aa;
! 346: struct sockaddr_at *sat;
! 347: {
! 348: struct netrange nr, onr;
! 349: struct sockaddr_at oldaddr;
! 350: int s = splnet(), error = 0, i, j, netinc, nodeinc, nnets;
! 351: u_int16_t net;
! 352:
! 353: oldaddr = aa->aa_addr;
! 354: bzero( AA_SAT( aa ), sizeof( struct sockaddr_at ));
! 355: bcopy( sat->sat_zero, &nr, sizeof( struct netrange ));
! 356: bcopy( sat->sat_zero, AA_SAT( aa )->sat_zero, sizeof( struct netrange ));
! 357: nnets = ntohs( nr.nr_lastnet ) - ntohs( nr.nr_firstnet ) + 1;
! 358:
! 359: onr.nr_firstnet = aa->aa_firstnet;
! 360: onr.nr_lastnet = aa->aa_lastnet;
! 361: aa->aa_firstnet = nr.nr_firstnet;
! 362: aa->aa_lastnet = nr.nr_lastnet;
! 363:
! 364: /*
! 365: * We could eliminate the need for a second phase 1 probe (post
! 366: * autoconf) if we check whether we're resetting the node. Note
! 367: * that phase 1 probes use only nodes, not net.node pairs. Under
! 368: * phase 2, both the net and node must be the same.
! 369: */
! 370: if ( ifp->if_flags & IFF_LOOPBACK ) {
! 371: AA_SAT( aa )->sat_len = sat->sat_len;
! 372: AA_SAT( aa )->sat_family = AF_APPLETALK;
! 373: AA_SAT( aa )->sat_addr.s_net = sat->sat_addr.s_net;
! 374: AA_SAT( aa )->sat_addr.s_node = sat->sat_addr.s_node;
! 375: } else {
! 376: aa->aa_flags |= AFA_PROBING;
! 377: AA_SAT( aa )->sat_len = sizeof(struct sockaddr_at);
! 378: AA_SAT( aa )->sat_family = AF_APPLETALK;
! 379: if ( aa->aa_flags & AFA_PHASE2 ) {
! 380: if ( sat->sat_addr.s_net == ATADDR_ANYNET ) {
! 381: if ( nnets != 1 ) {
! 382: net = ntohs( nr.nr_firstnet ) +
! 383: arc4random() % ( nnets - 1 );
! 384: } else {
! 385: net = ntohs( nr.nr_firstnet );
! 386: }
! 387: } else {
! 388: if ( ntohs( sat->sat_addr.s_net ) < ntohs( nr.nr_firstnet ) ||
! 389: ntohs( sat->sat_addr.s_net ) > ntohs( nr.nr_lastnet )) {
! 390: aa->aa_addr = oldaddr;
! 391: aa->aa_firstnet = onr.nr_firstnet;
! 392: aa->aa_lastnet = onr.nr_lastnet;
! 393: splx(s);
! 394: return( EINVAL );
! 395: }
! 396: net = ntohs( sat->sat_addr.s_net );
! 397: }
! 398: } else {
! 399: net = ntohs( sat->sat_addr.s_net );
! 400: }
! 401:
! 402: if ( sat->sat_addr.s_node == ATADDR_ANYNODE ) {
! 403: AA_SAT( aa )->sat_addr.s_node = arc4random();
! 404: } else {
! 405: AA_SAT( aa )->sat_addr.s_node = sat->sat_addr.s_node;
! 406: }
! 407:
! 408: for ( i = nnets, netinc = 1; i > 0; net = ntohs( nr.nr_firstnet ) +
! 409: (( net - ntohs( nr.nr_firstnet ) + netinc ) % nnets ), i-- ) {
! 410: AA_SAT( aa )->sat_addr.s_net = htons( net );
! 411:
! 412: for ( j = 0, nodeinc = arc4random() | 1; j < 256;
! 413: j++, AA_SAT( aa )->sat_addr.s_node += nodeinc ) {
! 414: if ( AA_SAT( aa )->sat_addr.s_node > 253 ||
! 415: AA_SAT( aa )->sat_addr.s_node < 1 ) {
! 416: continue;
! 417: }
! 418: aa->aa_probcnt = 10;
! 419: timeout_set(&aarpprobe_timeout, aarpprobe, ifp);
! 420: /* XXX don't use hz so badly */
! 421: timeout_add(&aarpprobe_timeout, hz / 5);
! 422: if ( tsleep( aa, PPAUSE|PCATCH, "at_ifinit", 0 )) {
! 423: printf( "at_ifinit why did this happen?!\n" );
! 424: aa->aa_addr = oldaddr;
! 425: aa->aa_firstnet = onr.nr_firstnet;
! 426: aa->aa_lastnet = onr.nr_lastnet;
! 427: splx( s );
! 428: return( EINTR );
! 429: }
! 430: if (( aa->aa_flags & AFA_PROBING ) == 0 ) {
! 431: break;
! 432: }
! 433: }
! 434: if (( aa->aa_flags & AFA_PROBING ) == 0 ) {
! 435: break;
! 436: }
! 437: /* reset node for next network */
! 438: AA_SAT( aa )->sat_addr.s_node = arc4random();
! 439: }
! 440:
! 441: if ( aa->aa_flags & AFA_PROBING ) {
! 442: aa->aa_addr = oldaddr;
! 443: aa->aa_firstnet = onr.nr_firstnet;
! 444: aa->aa_lastnet = onr.nr_lastnet;
! 445: splx( s );
! 446: return( EADDRINUSE );
! 447: }
! 448: }
! 449:
! 450: if ( ifp->if_ioctl &&
! 451: ( error = (*ifp->if_ioctl)( ifp, SIOCSIFADDR, (caddr_t) aa ))) {
! 452: aa->aa_addr = oldaddr;
! 453: aa->aa_firstnet = onr.nr_firstnet;
! 454: aa->aa_lastnet = onr.nr_lastnet;
! 455: splx( s );
! 456: return( error );
! 457: }
! 458:
! 459: bzero(&aa->aa_netmask, sizeof(aa->aa_netmask));
! 460: aa->aa_netmask.sat_len = sizeof(struct sockaddr_at);
! 461: aa->aa_netmask.sat_family = AF_APPLETALK;
! 462: aa->aa_netmask.sat_addr.s_net = 0xffff;
! 463: aa->aa_netmask.sat_addr.s_node = 0;
! 464: /* XXX From FreeBSD. Why does it do this? */
! 465: aa->aa_ifa.ifa_netmask =(struct sockaddr *) &(aa->aa_netmask);
! 466:
! 467: /* This block came from FreeBSD too */
! 468: /*
! 469: * Initialize broadcast (or remote p2p) address
! 470: */
! 471: bzero(&aa->aa_broadaddr, sizeof(aa->aa_broadaddr));
! 472: aa->aa_broadaddr.sat_len = sizeof(struct sockaddr_at);
! 473: aa->aa_broadaddr.sat_family = AF_APPLETALK;
! 474:
! 475: aa->aa_ifa.ifa_metric = ifp->if_metric;
! 476: if (ifp->if_flags & IFF_BROADCAST) {
! 477: aa->aa_broadaddr.sat_addr.s_net = htons(0);
! 478: aa->aa_broadaddr.sat_addr.s_node = 0xff;
! 479: aa->aa_ifa.ifa_broadaddr = (struct sockaddr *) &aa->aa_broadaddr;
! 480: /* add the range of routes needed */
! 481: error = aa_dorangeroute(&aa->aa_ifa,
! 482: ntohs(aa->aa_firstnet), ntohs(aa->aa_lastnet), RTM_ADD );
! 483: }
! 484: else if (ifp->if_flags & IFF_POINTOPOINT) {
! 485: struct at_addr rtaddr, rtmask;
! 486:
! 487: bzero(&rtaddr, sizeof(rtaddr));
! 488: bzero(&rtmask, sizeof(rtmask));
! 489: /* fill in the far end if we know it here XXX */
! 490: aa->aa_ifa.ifa_dstaddr = (struct sockaddr *) &aa->aa_broadaddr;
! 491: error = aa_addsingleroute(&aa->aa_ifa, &rtaddr, &rtmask);
! 492: }
! 493: else if ( ifp->if_flags & IFF_LOOPBACK ) {
! 494: struct at_addr rtaddr, rtmask;
! 495:
! 496: bzero(&rtaddr, sizeof(rtaddr));
! 497: bzero(&rtmask, sizeof(rtmask));
! 498: rtaddr.s_net = AA_SAT( aa )->sat_addr.s_net;
! 499: rtaddr.s_node = AA_SAT( aa )->sat_addr.s_node;
! 500: rtmask.s_net = 0xffff;
! 501: rtmask.s_node = 0x0; /* XXX should not be so.. should be HOST route */
! 502: error = aa_addsingleroute(&aa->aa_ifa, &rtaddr, &rtmask);
! 503: }
! 504:
! 505: if ( error ) {
! 506: at_scrub( ifp, aa );
! 507: aa->aa_addr = oldaddr;
! 508: aa->aa_firstnet = onr.nr_firstnet;
! 509: aa->aa_lastnet = onr.nr_lastnet;
! 510: splx( s );
! 511: return( error );
! 512: }
! 513:
! 514: aa->aa_ifa.ifa_flags |= IFA_ROUTE;
! 515: aa->aa_flags |= AFA_ROUTE;
! 516: splx( s );
! 517: return( 0 );
! 518: }
! 519:
! 520: int
! 521: at_broadcast( sat )
! 522: struct sockaddr_at *sat;
! 523: {
! 524: struct at_ifaddr *aa;
! 525:
! 526: if ( sat->sat_addr.s_node != ATADDR_BCAST ) {
! 527: return( 0 );
! 528: }
! 529: if ( sat->sat_addr.s_net == ATADDR_ANYNET ) {
! 530: return( 1 );
! 531: } else {
! 532: for ( aa = at_ifaddr; aa; aa = aa->aa_next ) {
! 533: if (( aa->aa_ifp->if_flags & IFF_BROADCAST ) &&
! 534: ( ntohs( sat->sat_addr.s_net ) >= ntohs( aa->aa_firstnet ) &&
! 535: ntohs( sat->sat_addr.s_net ) <= ntohs( aa->aa_lastnet ))) {
! 536: return( 1 );
! 537: }
! 538: }
! 539: }
! 540: return( 0 );
! 541: }
! 542:
! 543: /* Yet another bunch of routines from FreeBSD. Those guys are good */
! 544: /*
! 545: * aa_dorangeroute()
! 546: *
! 547: * Add a route for a range of networks from bot to top - 1.
! 548: * Algorithm:
! 549: *
! 550: * Split the range into two subranges such that the middle
! 551: * of the two ranges is the point where the highest bit of difference
! 552: * between the two addresses, makes its transition
! 553: * Each of the upper and lower ranges might not exist, or might be
! 554: * representable by 1 or more netmasks. In addition, if both
! 555: * ranges can be represented by the same netmask, then they can be merged
! 556: * by using the next higher netmask..
! 557: */
! 558:
! 559: static int
! 560: aa_dorangeroute(struct ifaddr *ifa, u_int bot, u_int top, int cmd)
! 561: {
! 562: u_int mask1;
! 563: struct at_addr addr;
! 564: struct at_addr mask;
! 565: int error;
! 566:
! 567: /*
! 568: * slight sanity check
! 569: */
! 570: if (bot > top) return (EINVAL);
! 571:
! 572: addr.s_node = 0;
! 573: mask.s_node = 0;
! 574: /*
! 575: * just start out with the lowest boundary
! 576: * and keep extending the mask till it's too big.
! 577: */
! 578:
! 579: while (bot <= top) {
! 580: mask1 = 1;
! 581: while ((( bot & ~mask1) >= bot)
! 582: && (( bot | mask1) <= top)) {
! 583: mask1 <<= 1;
! 584: mask1 |= 1;
! 585: }
! 586: mask1 >>= 1;
! 587: mask.s_net = htons(~mask1);
! 588: addr.s_net = htons(bot);
! 589: if(cmd == RTM_ADD) {
! 590: error = aa_addsingleroute(ifa,&addr,&mask);
! 591: if (error) {
! 592: /* XXX clean up? */
! 593: return (error);
! 594: }
! 595: } else {
! 596: error = aa_delsingleroute(ifa,&addr,&mask);
! 597: }
! 598: bot = (bot | mask1) + 1;
! 599: }
! 600: return 0;
! 601: }
! 602:
! 603: static int
! 604: aa_addsingleroute(struct ifaddr *ifa,
! 605: struct at_addr *addr, struct at_addr *mask)
! 606: {
! 607: int error;
! 608:
! 609: #if 0
! 610: printf("aa_addsingleroute: %x.%x mask %x.%x ...\n",
! 611: ntohs(addr->s_net), addr->s_node,
! 612: ntohs(mask->s_net), mask->s_node);
! 613: #endif
! 614:
! 615: error = aa_dosingleroute(ifa, addr, mask, RTM_ADD, RTF_UP);
! 616: if (error)
! 617: printf("aa_addsingleroute: error %d\n", error);
! 618: return(error);
! 619: }
! 620:
! 621: static int
! 622: aa_delsingleroute(struct ifaddr *ifa,
! 623: struct at_addr *addr, struct at_addr *mask)
! 624: {
! 625: int error;
! 626:
! 627: error = aa_dosingleroute(ifa, addr, mask, RTM_DELETE, 0);
! 628: if (error)
! 629: printf("aa_delsingleroute: error %d\n", error);
! 630: return(error);
! 631: }
! 632:
! 633: static int
! 634: aa_dosingleroute(struct ifaddr *ifa,
! 635: struct at_addr *at_addr, struct at_addr *at_mask, int cmd, int flags)
! 636: {
! 637: struct sockaddr_at addr, mask;
! 638:
! 639: bzero(&addr, sizeof(addr));
! 640: bzero(&mask, sizeof(mask));
! 641: addr.sat_family = AF_APPLETALK;
! 642: addr.sat_len = sizeof(struct sockaddr_at);
! 643: addr.sat_addr.s_net = at_addr->s_net;
! 644: addr.sat_addr.s_node = at_addr->s_node;
! 645: mask.sat_family = AF_APPLETALK;
! 646: mask.sat_len = sizeof(struct sockaddr_at);
! 647: mask.sat_addr.s_net = at_mask->s_net;
! 648: mask.sat_addr.s_node = at_mask->s_node;
! 649: if (at_mask->s_node)
! 650: flags |= RTF_HOST;
! 651: return(rtrequest(cmd, (struct sockaddr *) &addr,
! 652: (flags & RTF_HOST)?(ifa->ifa_dstaddr):(ifa->ifa_addr),
! 653: (struct sockaddr *) &mask, flags, NULL, 0));
! 654: }
CVSweb