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