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