Initial import from FreeBSD RELENG_4:
[dragonfly.git] / sys / netproto / atalk / at_control.c
1 /*
2  * Copyright (c) 1990,1991 Regents of The University of Michigan.
3  * All Rights Reserved.
4  */
5
6 #include <sys/param.h>
7 #include <sys/systm.h>
8 #include <sys/proc.h>
9 #include <sys/sockio.h>
10 #include <sys/malloc.h>
11 #include <sys/kernel.h>
12 #include <sys/socket.h>
13 #include <net/if.h>
14 #include <net/route.h>
15 #include <netinet/in.h>
16 #undef s_net
17 #include <netinet/if_ether.h>
18
19 #include <netatalk/at.h>
20 #include <netatalk/at_var.h>
21 #include <netatalk/at_extern.h>
22
23 struct at_ifaddr        *at_ifaddr;
24
25 static int aa_dorangeroute(struct ifaddr *ifa,
26                         u_int first, u_int last, int cmd);
27 static int aa_addsingleroute(struct ifaddr *ifa,
28                         struct at_addr *addr, struct at_addr *mask);
29 static int aa_delsingleroute(struct ifaddr *ifa,
30                         struct at_addr *addr, struct at_addr *mask);
31 static int aa_dosingleroute(struct ifaddr *ifa, struct at_addr *addr,
32                         struct at_addr *mask, int cmd, int flags);
33 static int at_scrub( struct ifnet *ifp, struct at_ifaddr *aa );
34 static int at_ifinit( struct ifnet *ifp, struct at_ifaddr *aa,
35                                         struct sockaddr_at *sat );
36 static int aa_claim_addr(struct ifaddr *ifa, struct sockaddr *gw);
37
38 # define sateqaddr(a,b) ((a)->sat_len == (b)->sat_len && \
39                     (a)->sat_family == (b)->sat_family && \
40                     (a)->sat_addr.s_net == (b)->sat_addr.s_net && \
41                     (a)->sat_addr.s_node == (b)->sat_addr.s_node )
42
43 int
44 at_control(struct socket *so, u_long cmd, caddr_t data,
45                 struct ifnet *ifp, struct proc *p )
46 {
47     struct ifreq        *ifr = (struct ifreq *)data;
48     struct sockaddr_at  *sat;
49     struct netrange     *nr;
50     struct at_aliasreq  *ifra = (struct at_aliasreq *)data;
51     struct at_ifaddr    *aa0;
52     struct at_ifaddr    *aa = 0;
53     struct ifaddr       *ifa, *ifa0;
54
55     /*
56      * If we have an ifp, then find the matching at_ifaddr if it exists
57      */
58     if ( ifp ) {
59         for ( aa = at_ifaddr; aa; aa = aa->aa_next ) {
60             if ( aa->aa_ifp == ifp ) break;
61         }
62     }
63
64     /*
65      * In this first switch table we are basically getting ready for
66      * the second one, by getting the atalk-specific things set up
67      * so that they start to look more similar to other protocols etc.
68      */
69
70     switch ( cmd ) {
71     case SIOCAIFADDR:
72     case SIOCDIFADDR:
73         /*
74          * If we have an appletalk sockaddr, scan forward of where
75          * we are now on the at_ifaddr list to find one with a matching 
76          * address on this interface.
77          * This may leave aa pointing to the first address on the
78          * NEXT interface!
79          */
80         if ( ifra->ifra_addr.sat_family == AF_APPLETALK ) {
81             for ( ; aa; aa = aa->aa_next ) {
82                 if ( aa->aa_ifp == ifp &&
83                         sateqaddr( &aa->aa_addr, &ifra->ifra_addr )) {
84                     break;
85                 }
86             }
87         }
88         /*
89          * If we a retrying to delete an addres but didn't find such,
90          * then rewurn with an error
91          */
92         if ( cmd == SIOCDIFADDR && aa == 0 ) {
93             return( EADDRNOTAVAIL );
94         }
95         /*FALLTHROUGH*/
96
97     case SIOCSIFADDR:
98         /* 
99          * If we are not superuser, then we don't get to do these ops.
100          */
101         if ( suser(p) ) {
102             return( EPERM );
103         }
104
105         sat = satosat( &ifr->ifr_addr );
106         nr = (struct netrange *)sat->sat_zero;
107         if ( nr->nr_phase == 1 ) {
108             /*
109              * Look for a phase 1 address on this interface.
110              * This may leave aa pointing to the first address on the
111              * NEXT interface!
112              */
113             for ( ; aa; aa = aa->aa_next ) {
114                 if ( aa->aa_ifp == ifp &&
115                         ( aa->aa_flags & AFA_PHASE2 ) == 0 ) {
116                     break;
117                 }
118             }
119         } else {                /* default to phase 2 */
120             /*
121              * Look for a phase 2 address on this interface.
122              * This may leave aa pointing to the first address on the
123              * NEXT interface!
124              */
125             for ( ; aa; aa = aa->aa_next ) {
126                 if ( aa->aa_ifp == ifp && ( aa->aa_flags & AFA_PHASE2 )) {
127                     break;
128                 }
129             }
130         }
131
132         if ( ifp == 0 )
133             panic( "at_control" );
134
135         /*
136          * If we failed to find an existing at_ifaddr entry, then we 
137          * allocate a fresh one. 
138          */
139         if ( aa == (struct at_ifaddr *) 0 ) {
140             aa0 = malloc(sizeof(struct at_ifaddr), M_IFADDR, M_WAITOK);
141             bzero(aa0, sizeof(struct at_ifaddr));
142             if (( aa = at_ifaddr ) != NULL ) {
143                 /*
144                  * Don't let the loopback be first, since the first
145                  * address is the machine's default address for
146                  * binding.
147                  * If it is, stick ourself in front, otherwise
148                  * go to the back of the list.
149                  */
150                 if ( at_ifaddr->aa_ifp->if_flags & IFF_LOOPBACK ) {
151                     aa = aa0;
152                     aa->aa_next = at_ifaddr;
153                     at_ifaddr = aa;
154                 } else {
155                     for ( ; aa->aa_next; aa = aa->aa_next )
156                         ;
157                     aa->aa_next = aa0;
158                 }
159             } else {
160                 at_ifaddr = aa0;
161             }
162             /* 
163              * Don't Add a reference for the aa itself!
164              * I fell into this trap. IFAFREE tests for <=0
165              * not <= 1 like RTFREE
166              */
167             /* aa->aa_ifa.ifa_refcnt++; DON'T DO THIS!! */
168             aa = aa0;
169
170             /*
171              * Find the end of the interface's addresses
172              * and link our new one on the end 
173              */
174             ifa = (struct ifaddr *)aa;
175             TAILQ_INSERT_TAIL(&ifp->if_addrhead, ifa, ifa_link);
176
177             /*
178              * Add a reference for the linking into the ifp_if_addrlist.
179              */
180             ifa->ifa_refcnt++;
181
182             /*
183              * As the at_ifaddr contains the actual sockaddrs,
184              * and the ifaddr itself, link them al together correctly.
185              */
186             ifa->ifa_addr = (struct sockaddr *)&aa->aa_addr;
187             ifa->ifa_dstaddr = (struct sockaddr *)&aa->aa_addr;
188             ifa->ifa_netmask = (struct sockaddr *)&aa->aa_netmask;
189
190             /*
191              * Set/clear the phase 2 bit.
192              */
193             if ( nr->nr_phase == 1 ) {
194                 aa->aa_flags &= ~AFA_PHASE2;
195             } else {
196                 aa->aa_flags |= AFA_PHASE2;
197             }
198
199             /*
200              * and link it all together
201              */
202             aa->aa_ifp = ifp;
203         } else {
204             /*
205              * If we DID find one then we clobber any routes dependent on it..
206              */
207             at_scrub( ifp, aa );
208         }
209         break;
210
211     case SIOCGIFADDR :
212         sat = satosat( &ifr->ifr_addr );
213         nr = (struct netrange *)sat->sat_zero;
214         if ( nr->nr_phase == 1 ) {
215             /*
216              * If the request is specifying phase 1, then
217              * only look at a phase one address
218              */
219             for ( ; aa; aa = aa->aa_next ) {
220                 if ( aa->aa_ifp == ifp &&
221                         ( aa->aa_flags & AFA_PHASE2 ) == 0 ) {
222                     break;
223                 }
224             }
225         } else {
226             /*
227              * default to phase 2
228              */
229             for ( ; aa; aa = aa->aa_next ) {
230                 if ( aa->aa_ifp == ifp && ( aa->aa_flags & AFA_PHASE2 )) {
231                     break;
232                 }
233             }
234         }
235
236         if ( aa == (struct at_ifaddr *) 0 )
237             return( EADDRNOTAVAIL );
238         break;
239     }
240
241     /*
242      * By the time this switch is run we should be able to assume that
243      * the "aa" pointer is valid when needed.
244      */
245     switch ( cmd ) {
246     case SIOCGIFADDR:
247
248         /*
249          * copy the contents of the sockaddr blindly.
250          */
251         sat = (struct sockaddr_at *)&ifr->ifr_addr;
252         *sat = aa->aa_addr;
253
254         /* 
255          * and do some cleanups
256          */
257         ((struct netrange *)&sat->sat_zero)->nr_phase
258                 = (aa->aa_flags & AFA_PHASE2) ? 2 : 1;
259         ((struct netrange *)&sat->sat_zero)->nr_firstnet = aa->aa_firstnet;
260         ((struct netrange *)&sat->sat_zero)->nr_lastnet = aa->aa_lastnet;
261         break;
262
263     case SIOCSIFADDR:
264         return( at_ifinit( ifp, aa, (struct sockaddr_at *)&ifr->ifr_addr ));
265
266     case SIOCAIFADDR:
267         if ( sateqaddr( &ifra->ifra_addr, &aa->aa_addr )) {
268             return( 0 );
269         }
270         return( at_ifinit( ifp, aa, (struct sockaddr_at *)&ifr->ifr_addr ));
271
272     case SIOCDIFADDR:
273         /*
274          * scrub all routes.. didn't we just DO this? XXX yes, del it
275          */
276         at_scrub( ifp, aa );
277
278         /*
279          * remove the ifaddr from the interface
280          */
281         ifa0 = (struct ifaddr *)aa;
282         TAILQ_REMOVE(&ifp->if_addrhead, ifa0, ifa_link);
283
284         /*
285          * refs goes from 1->0 if no external refs. note.. 
286          * This will not free it ... looks for -1.
287          */
288         IFAFREE(ifa0);
289
290         /*
291          * Now remove the at_ifaddr from the parallel structure
292          * as well, or we'd be in deep trouble
293          */
294         aa0 = aa;
295         if ( aa0 == ( aa = at_ifaddr )) {
296             at_ifaddr = aa->aa_next;
297         } else {
298             while ( aa->aa_next && ( aa->aa_next != aa0 )) {
299                 aa = aa->aa_next;
300             }
301
302             /*
303              * if we found it, remove it, otherwise we screwed up.
304              */
305             if ( aa->aa_next ) {
306                 aa->aa_next = aa0->aa_next;
307             } else {
308                 panic( "at_control" );
309             }
310         }
311
312         /*
313          * Now dump the memory we were using.
314          * Decrement the reference count.
315          * This should probably be the last reference
316          * as the count will go from 0 to -1.
317          * (unless there is still a route referencing this)
318          */
319         IFAFREE(ifa0);
320         break;
321
322     default:
323         if ( ifp == 0 || ifp->if_ioctl == 0 )
324             return( EOPNOTSUPP );
325         return( (*ifp->if_ioctl)( ifp, cmd, data ));
326     }
327     return( 0 );
328 }
329
330 /* 
331  * Given an interface and an at_ifaddr (supposedly on that interface)
332  * remove  any routes that depend on this.
333  * Why ifp is needed I'm not sure,
334  * as aa->at_ifaddr.ifa_ifp should be the same.
335  */
336 static int
337 at_scrub( ifp, aa )
338     struct ifnet        *ifp;
339     struct at_ifaddr    *aa;
340 {
341     int                 error;
342
343     if ( aa->aa_flags & AFA_ROUTE ) {
344         if (ifp->if_flags & IFF_LOOPBACK) {
345                 if ((error = aa_delsingleroute(&aa->aa_ifa,
346                                         &aa->aa_addr.sat_addr,
347                                         &aa->aa_netmask.sat_addr)) != 0) {
348                         return( error );
349                 }
350         } else if (ifp->if_flags & IFF_POINTOPOINT) {
351                 if ((error = rtinit( &aa->aa_ifa, RTM_DELETE, RTF_HOST)) != 0)
352                         return( error );
353         } else if (ifp->if_flags & IFF_BROADCAST) {
354                 error = aa_dorangeroute(&aa->aa_ifa,
355                                 ntohs(aa->aa_firstnet),
356                                 ntohs(aa->aa_lastnet),
357                                 RTM_DELETE );
358         }
359         aa->aa_ifa.ifa_flags &= ~IFA_ROUTE;
360         aa->aa_flags &= ~AFA_ROUTE;
361     }
362     return( 0 );
363 }
364
365 /*
366  * given an at_ifaddr,a sockaddr_at and an ifp,
367  * bang them all together at high speed and see what happens
368  */
369 static int 
370 at_ifinit( ifp, aa, sat )
371     struct ifnet        *ifp;
372     struct at_ifaddr    *aa;
373     struct sockaddr_at  *sat;
374 {
375     struct netrange     nr, onr;
376     struct sockaddr_at  oldaddr;
377     int                 s = splimp(), error = 0, i, j;
378     int                 netinc, nodeinc, nnets;
379     u_short             net;
380
381     /* 
382      * save the old addresses in the at_ifaddr just in case we need them.
383      */
384     oldaddr = aa->aa_addr;
385     onr.nr_firstnet = aa->aa_firstnet;
386     onr.nr_lastnet = aa->aa_lastnet;
387
388     /*
389      * take the address supplied as an argument, and add it to the 
390      * at_ifnet (also given). Remember ing to update
391      * those parts of the at_ifaddr that need special processing
392      */
393     bzero( AA_SAT( aa ), sizeof( struct sockaddr_at ));
394     bcopy( sat->sat_zero, &nr, sizeof( struct netrange ));
395     bcopy( sat->sat_zero, AA_SAT( aa )->sat_zero, sizeof( struct netrange ));
396     nnets = ntohs( nr.nr_lastnet ) - ntohs( nr.nr_firstnet ) + 1;
397     aa->aa_firstnet = nr.nr_firstnet;
398     aa->aa_lastnet = nr.nr_lastnet;
399
400 /* XXX ALC */
401 #if 0
402     printf("at_ifinit: %s: %u.%u range %u-%u phase %d\n",
403         ifp->if_name,
404         ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node,
405         ntohs(aa->aa_firstnet), ntohs(aa->aa_lastnet),
406         (aa->aa_flags & AFA_PHASE2) ? 2 : 1);
407 #endif
408
409     /*
410      * We could eliminate the need for a second phase 1 probe (post
411      * autoconf) if we check whether we're resetting the node. Note
412      * that phase 1 probes use only nodes, not net.node pairs.  Under
413      * phase 2, both the net and node must be the same.
414      */
415     if ( ifp->if_flags & IFF_LOOPBACK ) {
416         AA_SAT( aa )->sat_len = sat->sat_len;
417         AA_SAT( aa )->sat_family = AF_APPLETALK;
418         AA_SAT( aa )->sat_addr.s_net = sat->sat_addr.s_net;
419         AA_SAT( aa )->sat_addr.s_node = sat->sat_addr.s_node;
420 #if 0
421     } else if ( fp->if_flags & IFF_POINTOPOINT) {
422         /* unimplemented */
423         /*
424          * we'd have to copy the dstaddr field over from the sat 
425          * but it's not clear that it would contain the right info..
426          */
427 #endif
428     } else {
429         /*
430          * We are a normal (probably ethernet) interface.
431          * apply the new address to the interface structures etc.
432          * We will probe this address on the net first, before
433          * applying it to ensure that it is free.. If it is not, then
434          * we will try a number of other randomly generated addresses
435          * in this net and then increment the net.  etc.etc. until
436          * we find an unused address.
437          */
438         aa->aa_flags |= AFA_PROBING; /* if not loopback we Must probe? */
439         AA_SAT( aa )->sat_len = sizeof(struct sockaddr_at);
440         AA_SAT( aa )->sat_family = AF_APPLETALK;
441         if ( aa->aa_flags & AFA_PHASE2 ) {
442             if ( sat->sat_addr.s_net == ATADDR_ANYNET ) {
443                 /*
444                  * If we are phase 2, and the net was not specified
445                  * then we select a random net within the supplied netrange.
446                  * XXX use /dev/random?
447                  */
448                 if ( nnets != 1 ) {
449                     net = ntohs( nr.nr_firstnet ) + time_second % ( nnets - 1 );
450                 } else {
451                     net = ntohs( nr.nr_firstnet );
452                 }
453             } else {
454                 /*
455                  * if a net was supplied, then check that it is within
456                  * the netrange. If it is not then replace the old values
457                  * and return an error
458                  */
459                 if ( ntohs( sat->sat_addr.s_net ) < ntohs( nr.nr_firstnet ) ||
460                         ntohs( sat->sat_addr.s_net ) > ntohs( nr.nr_lastnet )) {
461                     aa->aa_addr = oldaddr;
462                     aa->aa_firstnet = onr.nr_firstnet;
463                     aa->aa_lastnet = onr.nr_lastnet;
464                     splx(s);
465                     return( EINVAL );
466                 }
467                 /*
468                  * otherwise just use the new net number..
469                  */
470                 net = ntohs( sat->sat_addr.s_net );
471             }
472         } else {
473             /*
474              * we must be phase one, so just use whatever we were given.
475              * I guess it really isn't going to be used... RIGHT?
476              */
477             net = ntohs( sat->sat_addr.s_net );
478         }
479
480         /* 
481          * set the node part of the address into the ifaddr.
482          * If it's not specified, be random about it...
483          * XXX use /dev/random?
484          */
485         if ( sat->sat_addr.s_node == ATADDR_ANYNODE ) {
486             AA_SAT( aa )->sat_addr.s_node = time_second;
487         } else {
488             AA_SAT( aa )->sat_addr.s_node = sat->sat_addr.s_node;
489         }
490
491         /* 
492          * Copy the phase.
493          */
494         AA_SAT( aa )->sat_range.r_netrange.nr_phase
495                 = ((aa->aa_flags & AFA_PHASE2) ? 2:1);
496
497         /* 
498          * step through the nets in the range
499          * starting at the (possibly random) start point.
500          */
501         for ( i = nnets, netinc = 1; i > 0; net = ntohs( nr.nr_firstnet ) +
502                 (( net - ntohs( nr.nr_firstnet ) + netinc ) % nnets ), i-- ) {
503             AA_SAT( aa )->sat_addr.s_net = htons( net );
504
505             /*
506              * using a rather strange stepping method,
507              * stagger through the possible node addresses
508              * Once again, starting at the (possibly random)
509              * initial node address.
510              */
511             for ( j = 0, nodeinc = time_second | 1; j < 256;
512                     j++, AA_SAT( aa )->sat_addr.s_node += nodeinc ) {
513                 if ( AA_SAT( aa )->sat_addr.s_node > 253 ||
514                         AA_SAT( aa )->sat_addr.s_node < 1 ) {
515                     continue;
516                 }
517                 aa->aa_probcnt = 10;
518
519                 /*
520                  * start off the probes as an asynchronous activity.
521                  * though why wait 200mSec?
522                  */
523                 aa->aa_ch = timeout( aarpprobe, (caddr_t)ifp, hz / 5 );
524                 if ( tsleep( aa, PPAUSE|PCATCH, "at_ifinit", 0 )) {
525                     /*
526                      * theoretically we shouldn't time out here
527                      * so if we returned with an error..
528                      */
529                     printf( "at_ifinit: why did this happen?!\n" );
530                     aa->aa_addr = oldaddr;
531                     aa->aa_firstnet = onr.nr_firstnet;
532                     aa->aa_lastnet = onr.nr_lastnet;
533                     splx( s ); 
534                     return( EINTR );
535                 }
536
537                 /* 
538                  * The async activity should have woken us up.
539                  * We need to see if it was successful in finding
540                  * a free spot, or if we need to iterate to the next 
541                  * address to try.
542                  */
543                 if (( aa->aa_flags & AFA_PROBING ) == 0 ) {
544                     break;
545                 }
546             }
547
548             /*
549              * of course we need to break out through two loops...
550              */
551             if (( aa->aa_flags & AFA_PROBING ) == 0 ) {
552                 break;
553             }
554             /* reset node for next network */
555             AA_SAT( aa )->sat_addr.s_node = time_second;
556         }
557
558         /*
559          * if we are still trying to probe, then we have finished all
560          * the possible addresses, so we need to give up
561          */
562
563         if ( aa->aa_flags & AFA_PROBING ) {
564             aa->aa_addr = oldaddr;
565             aa->aa_firstnet = onr.nr_firstnet;
566             aa->aa_lastnet = onr.nr_lastnet;
567             splx( s );
568             return( EADDRINUSE );
569         }
570     }
571
572     /* 
573      * Now that we have selected an address, we need to tell the interface
574      * about it, just in case it needs to adjust something.
575      */
576     if ( ifp->if_ioctl &&
577             ( error = (*ifp->if_ioctl)( ifp, SIOCSIFADDR, (caddr_t)aa ))) {
578         /*
579          * of course this could mean that it objects violently
580          * so if it does, we back out again..
581          */
582         aa->aa_addr = oldaddr;
583         aa->aa_firstnet = onr.nr_firstnet;
584         aa->aa_lastnet = onr.nr_lastnet;
585         splx( s );
586         return( error );
587     }
588
589     /* 
590      * set up the netmask part of the at_ifaddr
591      * and point the appropriate pointer in the ifaddr to it.
592      * probably pointless, but what the heck.. XXX
593      */
594     bzero(&aa->aa_netmask, sizeof(aa->aa_netmask));
595     aa->aa_netmask.sat_len = sizeof(struct sockaddr_at);
596     aa->aa_netmask.sat_family = AF_APPLETALK;
597     aa->aa_netmask.sat_addr.s_net = 0xffff;
598     aa->aa_netmask.sat_addr.s_node = 0;
599     aa->aa_ifa.ifa_netmask =(struct sockaddr *) &(aa->aa_netmask); /* XXX */
600
601     /*
602      * Initialize broadcast (or remote p2p) address
603      */
604     bzero(&aa->aa_broadaddr, sizeof(aa->aa_broadaddr));
605     aa->aa_broadaddr.sat_len = sizeof(struct sockaddr_at);
606     aa->aa_broadaddr.sat_family = AF_APPLETALK;
607
608     aa->aa_ifa.ifa_metric = ifp->if_metric;
609     if (ifp->if_flags & IFF_BROADCAST) {
610         aa->aa_broadaddr.sat_addr.s_net = htons(0);
611         aa->aa_broadaddr.sat_addr.s_node = 0xff;
612         aa->aa_ifa.ifa_broadaddr = (struct sockaddr *) &aa->aa_broadaddr;
613         /* add the range of routes needed */
614         error = aa_dorangeroute(&aa->aa_ifa,
615                 ntohs(aa->aa_firstnet), ntohs(aa->aa_lastnet), RTM_ADD );
616     }
617     else if (ifp->if_flags & IFF_POINTOPOINT) {
618         struct at_addr  rtaddr, rtmask;
619
620         bzero(&rtaddr, sizeof(rtaddr));
621         bzero(&rtmask, sizeof(rtmask));
622         /* fill in the far end if we know it here XXX */
623         aa->aa_ifa.ifa_dstaddr = (struct sockaddr *) &aa->aa_dstaddr;
624         error = aa_addsingleroute(&aa->aa_ifa, &rtaddr, &rtmask);
625     }
626     else if ( ifp->if_flags & IFF_LOOPBACK ) {
627         struct at_addr  rtaddr, rtmask;
628
629         bzero(&rtaddr, sizeof(rtaddr));
630         bzero(&rtmask, sizeof(rtmask));
631         rtaddr.s_net = AA_SAT( aa )->sat_addr.s_net;
632         rtaddr.s_node = AA_SAT( aa )->sat_addr.s_node;
633         rtmask.s_net = 0xffff;
634         rtmask.s_node = 0x0; /* XXX should not be so.. should be HOST route */
635         error = aa_addsingleroute(&aa->aa_ifa, &rtaddr, &rtmask);
636     }
637
638
639     /*
640      * set the address of our "check if this addr is ours" routine.
641      */
642     aa->aa_ifa.ifa_claim_addr = aa_claim_addr;
643
644     /*
645      * of course if we can't add these routes we back out, but it's getting
646      * risky by now XXX
647      */
648     if ( error ) {
649         at_scrub( ifp, aa );
650         aa->aa_addr = oldaddr;
651         aa->aa_firstnet = onr.nr_firstnet;
652         aa->aa_lastnet = onr.nr_lastnet;
653         splx( s );
654         return( error );
655     }
656
657     /*
658      * note that the address has a route associated with it....
659      */
660     aa->aa_ifa.ifa_flags |= IFA_ROUTE;
661     aa->aa_flags |= AFA_ROUTE;
662     splx( s );
663     return( 0 );
664 }
665
666 /*
667  * check whether a given address is a broadcast address for us..
668  */
669 int
670 at_broadcast( sat )
671     struct sockaddr_at  *sat;
672 {
673     struct at_ifaddr    *aa;
674
675     /*
676      * If the node is not right, it can't be a broadcast 
677      */
678     if ( sat->sat_addr.s_node != ATADDR_BCAST ) {
679         return( 0 );
680     }
681
682     /*
683      * If the node was right then if the net is right, it's a broadcast
684      */
685     if ( sat->sat_addr.s_net == ATADDR_ANYNET ) {
686         return( 1 );
687     }
688
689     /*
690      * failing that, if the net is one we have, it's a broadcast as well.
691      */
692     for ( aa = at_ifaddr; aa; aa = aa->aa_next ) {
693         if (( aa->aa_ifp->if_flags & IFF_BROADCAST )
694          && ( ntohs( sat->sat_addr.s_net ) >= ntohs( aa->aa_firstnet )
695          && ntohs( sat->sat_addr.s_net ) <= ntohs( aa->aa_lastnet ))) {
696                         return( 1 );
697         }
698     }
699     return( 0 );
700 }
701
702 /*
703  * aa_dorangeroute()
704  *
705  * Add a route for a range of networks from bot to top - 1.
706  * Algorithm:
707  *
708  * Split the range into two subranges such that the middle
709  * of the two ranges is the point where the highest bit of difference
710  * between the two addresses makes its transition.
711  * Each of the upper and lower ranges might not exist, or might be 
712  * representable by 1 or more netmasks. In addition, if both
713  * ranges can be represented by the same netmask, then they can be merged
714  * by using the next higher netmask..
715  */
716
717 static int
718 aa_dorangeroute(struct ifaddr *ifa, u_int bot, u_int top, int cmd)
719 {
720         u_int mask1;
721         struct at_addr addr;
722         struct at_addr mask;
723         int error;
724
725         /*
726          * slight sanity check
727          */
728         if (bot > top) return (EINVAL);
729
730         addr.s_node = 0;
731         mask.s_node = 0;
732         /*
733          * just start out with the lowest boundary
734          * and keep extending the mask till it's too big.
735          */
736         
737          while (bot <= top) {
738                 mask1 = 1;
739                 while ((( bot & ~mask1) >= bot)
740                    && (( bot | mask1) <= top)) {
741                         mask1 <<= 1;
742                         mask1 |= 1;
743                 }
744                 mask1 >>= 1;
745                 mask.s_net = htons(~mask1);
746                 addr.s_net = htons(bot);
747                 if(cmd == RTM_ADD) {
748                 error =  aa_addsingleroute(ifa,&addr,&mask);
749                         if (error) {
750                                 /* XXX clean up? */
751                                 return (error);
752                         }
753                 } else {
754                         error =  aa_delsingleroute(ifa,&addr,&mask);
755                 }
756                 bot = (bot | mask1) + 1;
757         }
758         return 0;
759 }
760
761 static int
762 aa_addsingleroute(struct ifaddr *ifa,
763         struct at_addr *addr, struct at_addr *mask)
764 {
765   int   error;
766
767 #if 0
768   printf("aa_addsingleroute: %x.%x mask %x.%x ...\n",
769     ntohs(addr->s_net), addr->s_node,
770     ntohs(mask->s_net), mask->s_node);
771 #endif
772
773   error = aa_dosingleroute(ifa, addr, mask, RTM_ADD, RTF_UP);
774   if (error)
775     printf("aa_addsingleroute: error %d\n", error);
776   return(error);
777 }
778
779 static int
780 aa_delsingleroute(struct ifaddr *ifa,
781         struct at_addr *addr, struct at_addr *mask)
782 {
783   int   error;
784
785   error = aa_dosingleroute(ifa, addr, mask, RTM_DELETE, 0);
786   if (error)
787         printf("aa_delsingleroute: error %d\n", error);
788   return(error);
789 }
790
791 static int
792 aa_dosingleroute(struct ifaddr *ifa,
793         struct at_addr *at_addr, struct at_addr *at_mask, int cmd, int flags)
794 {
795   struct sockaddr_at    addr, mask;
796
797   bzero(&addr, sizeof(addr));
798   bzero(&mask, sizeof(mask));
799   addr.sat_family = AF_APPLETALK;
800   addr.sat_len = sizeof(struct sockaddr_at);
801   addr.sat_addr.s_net = at_addr->s_net;
802   addr.sat_addr.s_node = at_addr->s_node;
803   mask.sat_family = AF_APPLETALK;
804   mask.sat_len = sizeof(struct sockaddr_at);
805   mask.sat_addr.s_net = at_mask->s_net;
806   mask.sat_addr.s_node = at_mask->s_node;
807   if (at_mask->s_node)
808     flags |= RTF_HOST;
809   return(rtrequest(cmd, (struct sockaddr *) &addr,
810         (flags & RTF_HOST)?(ifa->ifa_dstaddr):(ifa->ifa_addr),
811         (struct sockaddr *) &mask, flags, NULL));
812 }
813
814 #if 0
815
816 static void
817 aa_clean(void)
818 {
819     struct at_ifaddr    *aa;
820     struct ifaddr       *ifa;
821     struct ifnet        *ifp;
822
823     while ( aa = at_ifaddr ) {
824         ifp = aa->aa_ifp;
825         at_scrub( ifp, aa );
826         at_ifaddr = aa->aa_next;
827         if (( ifa = ifp->if_addrlist ) == (struct ifaddr *)aa ) {
828             ifp->if_addrlist = ifa->ifa_next;
829         } else {
830             while ( ifa->ifa_next &&
831                     ( ifa->ifa_next != (struct ifaddr *)aa )) {
832                 ifa = ifa->ifa_next;
833             }
834             if ( ifa->ifa_next ) {
835                 ifa->ifa_next = ((struct ifaddr *)aa)->ifa_next;
836             } else {
837                 panic( "at_entry" );
838             }
839         }
840     }
841 }
842
843 #endif
844
845 static int
846 aa_claim_addr(struct ifaddr *ifa, struct sockaddr *gw0)
847 {
848         struct sockaddr_at *addr = (struct sockaddr_at *)ifa->ifa_addr;
849         struct sockaddr_at *gw = (struct sockaddr_at *)gw0;
850
851         switch (gw->sat_range.r_netrange.nr_phase) {
852         case 1:
853                 if(addr->sat_range.r_netrange.nr_phase == 1)
854                         return 1;
855         case 0:
856         case 2:
857                 /*
858                  * if it's our net (including 0),
859                  * or netranges are valid, and we are in the range,
860                  * then it's ours.
861                  */
862                 if ((addr->sat_addr.s_net == gw->sat_addr.s_net)
863                 || ((addr->sat_range.r_netrange.nr_lastnet)
864                   && (ntohs(gw->sat_addr.s_net)
865                         >= ntohs(addr->sat_range.r_netrange.nr_firstnet ))
866                   && (ntohs(gw->sat_addr.s_net)
867                         <= ntohs(addr->sat_range.r_netrange.nr_lastnet )))) {
868                         return 1;
869                 } 
870                 break;
871         default:
872                 printf("atalk: bad phase\n");
873         }
874         return 0;
875 }