1 /* $NetBSD: at_control.c,v 1.31 2009/03/18 17:06:51 cegger Exp $ */
4 * Copyright (c) 1990,1994 Regents of The University of Michigan.
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.
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
20 * Research Systems Unix Group
21 * The University of Michigan
23 * 535 W. William Street
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: at_control.c,v 1.31 2009/03/18 17:06:51 cegger Exp $");
32 #include <sys/param.h>
33 #include <sys/systm.h>
35 #include <sys/errno.h>
36 #include <sys/ioctl.h>
38 #include <sys/kernel.h>
39 #include <sys/socket.h>
40 #include <sys/socketvar.h>
41 #include <sys/kauth.h>
43 #include <net/route.h>
44 #include <net/if_ether.h>
45 #include <netinet/in.h>
48 #include <netatalk/at.h>
49 #include <netatalk/at_var.h>
50 #include <netatalk/aarp.h>
51 #include <netatalk/phase2.h>
52 #include <netatalk/at_extern.h>
54 static int aa_dorangeroute(struct ifaddr
* ifa
,
55 u_int first
, u_int last
, int cmd
);
56 static int aa_addsingleroute(struct ifaddr
* ifa
,
57 struct at_addr
* addr
, struct at_addr
* mask
);
58 static int aa_delsingleroute(struct ifaddr
* ifa
,
59 struct at_addr
* addr
, struct at_addr
* mask
);
60 static int aa_dosingleroute(struct ifaddr
* ifa
, struct at_addr
* addr
,
61 struct at_addr
* mask
, int cmd
, int flags
);
62 static int at_scrub(struct ifnet
* ifp
, struct at_ifaddr
* aa
);
63 static int at_ifinit(struct ifnet
*, struct at_ifaddr
*,
64 const struct sockaddr_at
*);
66 static void aa_clean(void);
69 #define sateqaddr(a,b) ((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 )
75 at_control(u_long cmd
, void * data
, struct ifnet
*ifp
, struct lwp
*l
)
77 struct ifreq
*ifr
= (struct ifreq
*) data
;
78 const struct sockaddr_at
*csat
;
80 const struct netrange
*cnr
;
81 struct at_aliasreq
*ifra
= (struct at_aliasreq
*) data
;
82 struct at_ifaddr
*aa0
;
83 struct at_ifaddr
*aa
= 0;
86 * If we have an ifp, then find the matching at_ifaddr if it exists
89 for (aa
= at_ifaddr
.tqh_first
; aa
; aa
= aa
->aa_list
.tqe_next
)
90 if (aa
->aa_ifp
== ifp
)
94 * In this first switch table we are basically getting ready for
95 * the second one, by getting the atalk-specific things set up
96 * so that they start to look more similar to other protocols etc.
103 * If we have an appletalk sockaddr, scan forward of where
104 * we are now on the at_ifaddr list to find one with a matching
105 * address on this interface.
106 * This may leave aa pointing to the first address on the
109 if (ifra
->ifra_addr
.sat_family
== AF_APPLETALK
) {
110 for (; aa
; aa
= aa
->aa_list
.tqe_next
)
111 if (aa
->aa_ifp
== ifp
&&
112 sateqaddr(&aa
->aa_addr
, &ifra
->ifra_addr
))
116 * If we a retrying to delete an addres but didn't find such,
117 * then return with an error
119 if (cmd
== SIOCDIFADDR
&& aa
== 0)
120 return (EADDRNOTAVAIL
);
125 * If we are not superuser, then we don't get to do these
128 if (l
&& kauth_authorize_network(l
->l_cred
,
129 KAUTH_NETWORK_INTERFACE
,
130 KAUTH_REQ_NETWORK_INTERFACE_SETPRIV
, ifp
, (void *)cmd
,
134 csat
= satocsat(ifreq_getaddr(cmd
, ifr
));
135 cnr
= (const struct netrange
*)csat
->sat_zero
;
136 if (cnr
->nr_phase
== 1) {
138 * Look for a phase 1 address on this interface.
139 * This may leave aa pointing to the first address on
140 * the NEXT interface!
142 for (; aa
; aa
= aa
->aa_list
.tqe_next
) {
143 if (aa
->aa_ifp
== ifp
&&
144 (aa
->aa_flags
& AFA_PHASE2
) == 0)
147 } else { /* default to phase 2 */
149 * Look for a phase 2 address on this interface.
150 * This may leave aa pointing to the first address on
151 * the NEXT interface!
153 for (; aa
; aa
= aa
->aa_list
.tqe_next
) {
154 if (aa
->aa_ifp
== ifp
&&
155 (aa
->aa_flags
& AFA_PHASE2
))
164 * If we failed to find an existing at_ifaddr entry, then we
165 * allocate a fresh one.
166 * XXX change this to use malloc
168 if (aa
== (struct at_ifaddr
*) 0) {
169 aa
= (struct at_ifaddr
*)
170 malloc(sizeof(struct at_ifaddr
), M_IFADDR
,
176 callout_init(&aa
->aa_probe_ch
, 0);
178 if ((aa0
= at_ifaddr
.tqh_first
) != NULL
) {
180 * Don't let the loopback be first, since the
181 * first address is the machine's default
182 * address for binding.
183 * If it is, stick ourself in front, otherwise
184 * go to the back of the list.
186 if (aa0
->aa_ifp
->if_flags
& IFF_LOOPBACK
) {
187 TAILQ_INSERT_HEAD(&at_ifaddr
, aa
,
190 TAILQ_INSERT_TAIL(&at_ifaddr
, aa
,
194 TAILQ_INSERT_TAIL(&at_ifaddr
, aa
, aa_list
);
199 * Find the end of the interface's addresses
200 * and link our new one on the end
202 ifa_insert(ifp
, &aa
->aa_ifa
);
205 * As the at_ifaddr contains the actual sockaddrs,
206 * and the ifaddr itself, link them al together
209 aa
->aa_ifa
.ifa_addr
=
210 (struct sockaddr
*) &aa
->aa_addr
;
211 aa
->aa_ifa
.ifa_dstaddr
=
212 (struct sockaddr
*) &aa
->aa_addr
;
213 aa
->aa_ifa
.ifa_netmask
=
214 (struct sockaddr
*) &aa
->aa_netmask
;
217 * Set/clear the phase 2 bit.
219 if (cnr
->nr_phase
== 1)
220 aa
->aa_flags
&= ~AFA_PHASE2
;
222 aa
->aa_flags
|= AFA_PHASE2
;
225 * and link it all together
230 * If we DID find one then we clobber any routes
238 csat
= satocsat(ifreq_getaddr(cmd
, ifr
));
239 cnr
= (const struct netrange
*)csat
->sat_zero
;
240 if (cnr
->nr_phase
== 1) {
242 * If the request is specifying phase 1, then
243 * only look at a phase one address
245 for (; aa
; aa
= aa
->aa_list
.tqe_next
) {
246 if (aa
->aa_ifp
== ifp
&&
247 (aa
->aa_flags
& AFA_PHASE2
) == 0)
250 } else if (cnr
->nr_phase
== 2) {
252 * If the request is specifying phase 2, then
253 * only look at a phase two address
255 for (; aa
; aa
= aa
->aa_list
.tqe_next
) {
256 if (aa
->aa_ifp
== ifp
&&
257 (aa
->aa_flags
& AFA_PHASE2
))
262 * default to everything
264 for (; aa
; aa
= aa
->aa_list
.tqe_next
) {
265 if (aa
->aa_ifp
== ifp
)
270 if (aa
== (struct at_ifaddr
*) 0)
271 return (EADDRNOTAVAIL
);
276 * By the time this switch is run we should be able to assume that
277 * the "aa" pointer is valid when needed.
283 struct sockaddr_at sat
;
287 * copy the contents of the sockaddr blindly.
289 sockaddr_copy(&u
.sa
, sizeof(u
),
290 (const struct sockaddr
*)&aa
->aa_addr
);
292 * and do some cleanups
294 nr
= (struct netrange
*)&u
.sat
.sat_zero
;
295 nr
->nr_phase
= (aa
->aa_flags
& AFA_PHASE2
) ? 2 : 1;
296 nr
->nr_firstnet
= aa
->aa_firstnet
;
297 nr
->nr_lastnet
= aa
->aa_lastnet
;
298 ifreq_setaddr(cmd
, ifr
, &u
.sa
);
303 return at_ifinit(ifp
, aa
,
304 (const struct sockaddr_at
*)ifreq_getaddr(cmd
, ifr
));
307 if (sateqaddr(&ifra
->ifra_addr
, &aa
->aa_addr
))
309 return at_ifinit(ifp
, aa
,
310 (const struct sockaddr_at
*)ifreq_getaddr(cmd
, ifr
));
313 at_purgeaddr(&aa
->aa_ifa
);
323 at_purgeaddr(struct ifaddr
*ifa
)
325 struct ifnet
*ifp
= ifa
->ifa_ifp
;
326 struct at_ifaddr
*aa
= (void *) ifa
;
329 * scrub all routes.. didn't we just DO this? XXX yes, del it
330 * XXX above XXX not necessarily true anymore
335 * remove the ifaddr from the interface
337 ifa_remove(ifp
, &aa
->aa_ifa
);
338 TAILQ_REMOVE(&at_ifaddr
, aa
, aa_list
);
339 IFAFREE(&aa
->aa_ifa
);
343 at_purgeif(struct ifnet
*ifp
)
345 if_purgeaddrs(ifp
, AF_APPLETALK
, at_purgeaddr
);
349 * Given an interface and an at_ifaddr (supposedly on that interface) remove
350 * any routes that depend on this. Why ifp is needed I'm not sure, as
351 * aa->at_ifaddr.ifa_ifp should be the same.
354 at_scrub(struct ifnet
*ifp
, struct at_ifaddr
*aa
)
358 if (aa
->aa_flags
& AFA_ROUTE
) {
359 if (ifp
->if_flags
& IFF_LOOPBACK
)
360 error
= aa_delsingleroute(&aa
->aa_ifa
,
361 &aa
->aa_addr
.sat_addr
, &aa
->aa_netmask
.sat_addr
);
362 else if (ifp
->if_flags
& IFF_POINTOPOINT
)
363 error
= rtinit(&aa
->aa_ifa
, RTM_DELETE
, RTF_HOST
);
364 else if (ifp
->if_flags
& IFF_BROADCAST
)
365 error
= aa_dorangeroute(&aa
->aa_ifa
,
366 ntohs(aa
->aa_firstnet
), ntohs(aa
->aa_lastnet
),
369 aa
->aa_ifa
.ifa_flags
&= ~IFA_ROUTE
;
370 aa
->aa_flags
&= ~AFA_ROUTE
;
376 * given an at_ifaddr,a sockaddr_at and an ifp,
377 * bang them all together at high speed and see what happens
380 at_ifinit(struct ifnet
*ifp
, struct at_ifaddr
*aa
, const struct sockaddr_at
*sat
)
382 struct netrange nr
, onr
;
383 struct sockaddr_at oldaddr
;
384 int s
= splnet(), error
= 0, i
, j
;
385 int netinc
, nodeinc
, nnets
;
389 * save the old addresses in the at_ifaddr just in case we need them.
391 oldaddr
= aa
->aa_addr
;
392 onr
.nr_firstnet
= aa
->aa_firstnet
;
393 onr
.nr_lastnet
= aa
->aa_lastnet
;
396 * take the address supplied as an argument, and add it to the
397 * at_ifnet (also given). Remember ing to update
398 * those parts of the at_ifaddr that need special processing
400 memset(AA_SAT(aa
), 0, sizeof(struct sockaddr_at
));
401 memcpy(&nr
, sat
->sat_zero
, sizeof(struct netrange
));
402 memcpy(AA_SAT(aa
)->sat_zero
, sat
->sat_zero
, sizeof(struct netrange
));
403 nnets
= ntohs(nr
.nr_lastnet
) - ntohs(nr
.nr_firstnet
) + 1;
404 aa
->aa_firstnet
= nr
.nr_firstnet
;
405 aa
->aa_lastnet
= nr
.nr_lastnet
;
408 printf("at_ifinit: %s: %u.%u range %u-%u phase %d\n",
410 ntohs(sat
->sat_addr
.s_net
), sat
->sat_addr
.s_node
,
411 ntohs(aa
->aa_firstnet
), ntohs(aa
->aa_lastnet
),
412 (aa
->aa_flags
& AFA_PHASE2
) ? 2 : 1);
416 * We could eliminate the need for a second phase 1 probe (post
417 * autoconf) if we check whether we're resetting the node. Note
418 * that phase 1 probes use only nodes, not net.node pairs. Under
419 * phase 2, both the net and node must be the same.
421 AA_SAT(aa
)->sat_len
= sat
->sat_len
;
422 AA_SAT(aa
)->sat_family
= AF_APPLETALK
;
423 if (ifp
->if_flags
& IFF_LOOPBACK
) {
424 AA_SAT(aa
)->sat_addr
.s_net
= sat
->sat_addr
.s_net
;
425 AA_SAT(aa
)->sat_addr
.s_node
= sat
->sat_addr
.s_node
;
427 } else if (fp
->if_flags
& IFF_POINTOPOINT
) {
430 * we'd have to copy the dstaddr field over from the sat
431 * but it's not clear that it would contain the right info..
436 * We are a normal (probably ethernet) interface.
437 * apply the new address to the interface structures etc.
438 * We will probe this address on the net first, before
439 * applying it to ensure that it is free.. If it is not, then
440 * we will try a number of other randomly generated addresses
441 * in this net and then increment the net. etc.etc. until
442 * we find an unused address.
444 aa
->aa_flags
|= AFA_PROBING
; /* if not loopback we Must
446 if (aa
->aa_flags
& AFA_PHASE2
) {
447 if (sat
->sat_addr
.s_net
== ATADDR_ANYNET
) {
449 * If we are phase 2, and the net was not
450 * specified * then we select a random net
451 * within the supplied netrange.
452 * XXX use /dev/random?
455 net
= ntohs(nr
.nr_firstnet
) +
456 time_second
% (nnets
- 1);
458 net
= ntohs(nr
.nr_firstnet
);
462 * if a net was supplied, then check that it
463 * is within the netrange. If it is not then
464 * replace the old values and return an error
466 if (ntohs(sat
->sat_addr
.s_net
) <
467 ntohs(nr
.nr_firstnet
) ||
468 ntohs(sat
->sat_addr
.s_net
) >
469 ntohs(nr
.nr_lastnet
)) {
470 aa
->aa_addr
= oldaddr
;
471 aa
->aa_firstnet
= onr
.nr_firstnet
;
472 aa
->aa_lastnet
= onr
.nr_lastnet
;
477 * otherwise just use the new net number..
479 net
= ntohs(sat
->sat_addr
.s_net
);
483 * we must be phase one, so just use whatever we were
484 * given. I guess it really isn't going to be used...
487 net
= ntohs(sat
->sat_addr
.s_net
);
491 * set the node part of the address into the ifaddr. If it's
492 * not specified, be random about it... XXX use /dev/random?
494 if (sat
->sat_addr
.s_node
== ATADDR_ANYNODE
) {
495 AA_SAT(aa
)->sat_addr
.s_node
= time_second
;
497 AA_SAT(aa
)->sat_addr
.s_node
= sat
->sat_addr
.s_node
;
501 * step through the nets in the range starting at the
502 * (possibly random) start point.
504 for (i
= nnets
, netinc
= 1; i
> 0; net
= ntohs(nr
.nr_firstnet
) +
505 ((net
- ntohs(nr
.nr_firstnet
) + netinc
) % nnets
), i
--) {
506 AA_SAT(aa
)->sat_addr
.s_net
= htons(net
);
509 * using a rather strange stepping method,
510 * stagger through the possible node addresses
511 * Once again, starting at the (possibly random)
512 * initial node address.
514 for (j
= 0, nodeinc
= time_second
| 1; j
< 256;
515 j
++, AA_SAT(aa
)->sat_addr
.s_node
+= nodeinc
) {
516 if (AA_SAT(aa
)->sat_addr
.s_node
> 253 ||
517 AA_SAT(aa
)->sat_addr
.s_node
< 1) {
523 * start off the probes as an asynchronous
524 * activity. though why wait 200mSec?
526 callout_reset(&aa
->aa_probe_ch
, hz
/ 5,
528 if (tsleep(aa
, PPAUSE
| PCATCH
, "at_ifinit",
531 * theoretically we shouldn't time out
532 * here so if we returned with an error.
534 printf("at_ifinit: timeout?!\n");
535 aa
->aa_addr
= oldaddr
;
536 aa
->aa_firstnet
= onr
.nr_firstnet
;
537 aa
->aa_lastnet
= onr
.nr_lastnet
;
542 * The async activity should have woken us
543 * up. We need to see if it was successful in
544 * finding a free spot, or if we need to
545 * iterate to the next address to try.
547 if ((aa
->aa_flags
& AFA_PROBING
) == 0)
552 * of course we need to break out through two loops...
554 if ((aa
->aa_flags
& AFA_PROBING
) == 0)
557 /* reset node for next network */
558 AA_SAT(aa
)->sat_addr
.s_node
= time_second
;
562 * if we are still trying to probe, then we have finished all
563 * the possible addresses, so we need to give up
565 if (aa
->aa_flags
& AFA_PROBING
) {
566 aa
->aa_addr
= oldaddr
;
567 aa
->aa_firstnet
= onr
.nr_firstnet
;
568 aa
->aa_lastnet
= onr
.nr_lastnet
;
575 * Now that we have selected an address, we need to tell the
576 * interface about it, just in case it needs to adjust something.
578 if ((error
= (*ifp
->if_ioctl
)(ifp
, SIOCINITIFADDR
, aa
)) != 0) {
580 * of course this could mean that it objects violently
581 * so if it does, we back out again..
583 aa
->aa_addr
= oldaddr
;
584 aa
->aa_firstnet
= onr
.nr_firstnet
;
585 aa
->aa_lastnet
= onr
.nr_lastnet
;
590 * set up the netmask part of the at_ifaddr and point the appropriate
591 * pointer in the ifaddr to it. probably pointless, but what the
594 memset(&aa
->aa_netmask
, 0, sizeof(aa
->aa_netmask
));
595 aa
->aa_netmask
.sat_len
= sizeof(struct sockaddr_at
);
596 aa
->aa_netmask
.sat_family
= AF_APPLETALK
;
597 aa
->aa_netmask
.sat_addr
.s_net
= 0xffff;
598 aa
->aa_netmask
.sat_addr
.s_node
= 0;
600 aa
->aa_ifa
.ifa_netmask
= (struct sockaddr
*) &(aa
->aa_netmask
);/* XXX */
604 * Initialize broadcast (or remote p2p) address
606 memset(&aa
->aa_broadaddr
, 0, sizeof(aa
->aa_broadaddr
));
607 aa
->aa_broadaddr
.sat_len
= sizeof(struct sockaddr_at
);
608 aa
->aa_broadaddr
.sat_family
= AF_APPLETALK
;
610 aa
->aa_ifa
.ifa_metric
= ifp
->if_metric
;
611 if (ifp
->if_flags
& IFF_BROADCAST
) {
612 aa
->aa_broadaddr
.sat_addr
.s_net
= htons(0);
613 aa
->aa_broadaddr
.sat_addr
.s_node
= 0xff;
614 aa
->aa_ifa
.ifa_broadaddr
=
615 (struct sockaddr
*) &aa
->aa_broadaddr
;
616 /* add the range of routes needed */
617 error
= aa_dorangeroute(&aa
->aa_ifa
,
618 ntohs(aa
->aa_firstnet
), ntohs(aa
->aa_lastnet
), RTM_ADD
);
619 } else if (ifp
->if_flags
& IFF_POINTOPOINT
) {
620 struct at_addr rtaddr
, rtmask
;
622 memset(&rtaddr
, 0, sizeof(rtaddr
));
623 memset(&rtmask
, 0, sizeof(rtmask
));
624 /* fill in the far end if we know it here XXX */
625 aa
->aa_ifa
.ifa_dstaddr
= (struct sockaddr
*) & aa
->aa_dstaddr
;
626 error
= aa_addsingleroute(&aa
->aa_ifa
, &rtaddr
, &rtmask
);
627 } else if (ifp
->if_flags
& IFF_LOOPBACK
) {
628 struct at_addr rtaddr
, rtmask
;
630 memset(&rtaddr
, 0, sizeof(rtaddr
));
631 memset(&rtmask
, 0, sizeof(rtmask
));
632 rtaddr
.s_net
= AA_SAT(aa
)->sat_addr
.s_net
;
633 rtaddr
.s_node
= AA_SAT(aa
)->sat_addr
.s_node
;
634 rtmask
.s_net
= 0xffff;
636 error
= aa_addsingleroute(&aa
->aa_ifa
, &rtaddr
, &rtmask
);
639 * of course if we can't add these routes we back out, but it's getting
644 aa
->aa_addr
= oldaddr
;
645 aa
->aa_firstnet
= onr
.nr_firstnet
;
646 aa
->aa_lastnet
= onr
.nr_lastnet
;
651 * note that the address has a route associated with it....
653 aa
->aa_ifa
.ifa_flags
|= IFA_ROUTE
;
654 aa
->aa_flags
|= AFA_ROUTE
;
660 * check whether a given address is a broadcast address for us..
663 at_broadcast(const struct sockaddr_at
*sat
)
665 struct at_ifaddr
*aa
;
668 * If the node is not right, it can't be a broadcast
670 if (sat
->sat_addr
.s_node
!= ATADDR_BCAST
)
674 * If the node was right then if the net is right, it's a broadcast
676 if (sat
->sat_addr
.s_net
== ATADDR_ANYNET
)
680 * failing that, if the net is one we have, it's a broadcast as well.
682 for (aa
= at_ifaddr
.tqh_first
; aa
; aa
= aa
->aa_list
.tqe_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
)))
695 * Add a route for a range of networks from bot to top - 1.
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 it's 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 teh can be merged
704 * by using the next higher netmask..
708 aa_dorangeroute(struct ifaddr
*ifa
, u_int bot
, u_int top
, int cmd
)
716 * slight sanity check
724 * just start out with the lowest boundary
725 * and keep extending the mask till it's too big.
730 while (((bot
& ~mask1
) >= bot
)
731 && ((bot
| mask1
) <= top
)) {
736 mask
.s_net
= htons(~mask1
);
737 addr
.s_net
= htons(bot
);
738 if (cmd
== RTM_ADD
) {
739 error
= aa_addsingleroute(ifa
, &addr
, &mask
);
745 error
= aa_delsingleroute(ifa
, &addr
, &mask
);
747 bot
= (bot
| mask1
) + 1;
753 aa_addsingleroute(struct ifaddr
*ifa
, struct at_addr
*addr
, struct at_addr
*mask
)
758 printf("aa_addsingleroute: %x.%x mask %x.%x ...",
759 ntohs(addr
->s_net
), addr
->s_node
,
760 ntohs(mask
->s_net
), mask
->s_node
);
763 error
= aa_dosingleroute(ifa
, addr
, mask
, RTM_ADD
, RTF_UP
);
766 printf("aa_addsingleroute: error %d\n", error
);
772 aa_delsingleroute(struct ifaddr
*ifa
, struct at_addr
*addr
, struct at_addr
*mask
)
777 printf("aa_delsingleroute: %x.%x mask %x.%x ...",
778 ntohs(addr
->s_net
), addr
->s_node
,
779 ntohs(mask
->s_net
), mask
->s_node
);
782 error
= aa_dosingleroute(ifa
, addr
, mask
, RTM_DELETE
, 0);
785 printf("aa_delsingleroute: error %d\n", error
);
791 aa_dosingleroute(struct ifaddr
*ifa
, struct at_addr
*at_addr
, struct at_addr
*at_mask
, int cmd
, int flags
)
793 struct sockaddr_at addr
, mask
, *gate
;
795 memset(&addr
, 0, sizeof(addr
));
796 memset(&mask
, 0, sizeof(mask
));
797 addr
.sat_family
= AF_APPLETALK
;
798 addr
.sat_len
= sizeof(struct sockaddr_at
);
799 addr
.sat_addr
.s_net
= at_addr
->s_net
;
800 addr
.sat_addr
.s_node
= at_addr
->s_node
;
801 mask
.sat_family
= AF_APPLETALK
;
802 mask
.sat_len
= sizeof(struct sockaddr_at
);
803 mask
.sat_addr
.s_net
= at_mask
->s_net
;
804 mask
.sat_addr
.s_node
= at_mask
->s_node
;
806 if (at_mask
->s_node
) {
807 gate
= satosat(ifa
->ifa_dstaddr
);
810 gate
= satosat(ifa
->ifa_addr
);
814 printf("on %s %x.%x\n", (flags
& RTF_HOST
) ? "host" : "net",
815 ntohs(gate
->sat_addr
.s_net
), gate
->sat_addr
.s_node
);
817 return (rtrequest(cmd
, (struct sockaddr
*) &addr
,
818 (struct sockaddr
*) gate
, (struct sockaddr
*) &mask
, flags
, NULL
));
825 struct at_ifaddr
*aa
;
829 while ((aa
= TAILQ_FIRST(&at_ifaddr
)) != NULL
) {
830 TAILQ_REMOVE(&at_ifaddr
, aa
, aa_list
);
833 IFADDR_FOREACH(ifa
, ifp
) {
834 if (ifa
== &aa
->aa_ifa
)
838 panic("aa not present");
839 ifa_remove(ifp
, ifa
);