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