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