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