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