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