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