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