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