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