1*5707ddccSriastradh /* $NetBSD: at_control.c,v 1.44 2023/03/30 15:58:10 riastradh Exp $ */
25bf5cd24Schristos
35bf5cd24Schristos /*
45bf5cd24Schristos * Copyright (c) 1990,1994 Regents of The University of Michigan.
55bf5cd24Schristos * All Rights Reserved.
65bf5cd24Schristos *
75bf5cd24Schristos * Permission to use, copy, modify, and distribute this software and
85bf5cd24Schristos * its documentation for any purpose and without fee is hereby granted,
95bf5cd24Schristos * provided that the above copyright notice appears in all copies and
105bf5cd24Schristos * that both that copyright notice and this permission notice appear
115bf5cd24Schristos * in supporting documentation, and that the name of The University
125bf5cd24Schristos * of Michigan not be used in advertising or publicity pertaining to
135bf5cd24Schristos * distribution of the software without specific, written prior
145bf5cd24Schristos * permission. This software is supplied as is without expressed or
155bf5cd24Schristos * implied warranties of any kind.
165bf5cd24Schristos *
175bf5cd24Schristos * This product includes software developed by the University of
185bf5cd24Schristos * California, Berkeley and its contributors.
195bf5cd24Schristos *
205bf5cd24Schristos * Research Systems Unix Group
215bf5cd24Schristos * The University of Michigan
225bf5cd24Schristos * c/o Wesley Craig
235bf5cd24Schristos * 535 W. William Street
245bf5cd24Schristos * Ann Arbor, Michigan
255bf5cd24Schristos * +1-313-764-2278
265bf5cd24Schristos * netatalk@umich.edu
275bf5cd24Schristos */
285bf5cd24Schristos
29b60687cbSlukem #include <sys/cdefs.h>
30*5707ddccSriastradh __KERNEL_RCSID(0, "$NetBSD: at_control.c,v 1.44 2023/03/30 15:58:10 riastradh Exp $");
31ec4b7077Srjs
32ec4b7077Srjs #include "opt_atalk.h"
33b60687cbSlukem
345bf5cd24Schristos #include <sys/param.h>
355bf5cd24Schristos #include <sys/systm.h>
365bf5cd24Schristos #include <sys/proc.h>
375bf5cd24Schristos #include <sys/errno.h>
385bf5cd24Schristos #include <sys/ioctl.h>
395bf5cd24Schristos #include <sys/mbuf.h>
405bf5cd24Schristos #include <sys/kernel.h>
415bf5cd24Schristos #include <sys/socket.h>
425bf5cd24Schristos #include <sys/socketvar.h>
43874fef37Selad #include <sys/kauth.h>
445bf5cd24Schristos #include <net/if.h>
455bf5cd24Schristos #include <net/route.h>
465bf5cd24Schristos #include <net/if_ether.h>
475bf5cd24Schristos #include <netinet/in.h>
485bf5cd24Schristos #undef s_net
495bf5cd24Schristos
505bf5cd24Schristos #include <netatalk/at.h>
515bf5cd24Schristos #include <netatalk/at_var.h>
525bf5cd24Schristos #include <netatalk/aarp.h>
535bf5cd24Schristos #include <netatalk/phase2.h>
545bf5cd24Schristos #include <netatalk/at_extern.h>
555bf5cd24Schristos
562fc10275Sdyoung static int aa_dorangeroute(struct ifaddr * ifa,
572fc10275Sdyoung u_int first, u_int last, int cmd);
582fc10275Sdyoung static int aa_addsingleroute(struct ifaddr * ifa,
592fc10275Sdyoung struct at_addr * addr, struct at_addr * mask);
602fc10275Sdyoung static int aa_delsingleroute(struct ifaddr * ifa,
612fc10275Sdyoung struct at_addr * addr, struct at_addr * mask);
622fc10275Sdyoung static int aa_dosingleroute(struct ifaddr * ifa, struct at_addr * addr,
632fc10275Sdyoung struct at_addr * mask, int cmd, int flags);
642fc10275Sdyoung static int at_scrub(struct ifnet * ifp, struct at_ifaddr * aa);
652fc10275Sdyoung static int at_ifinit(struct ifnet *, struct at_ifaddr *,
662fc10275Sdyoung const struct sockaddr_at *);
675bf5cd24Schristos #if 0
682fc10275Sdyoung static void aa_clean(void);
695bf5cd24Schristos #endif
705bf5cd24Schristos
715bf5cd24Schristos #define sateqaddr(a,b) ((a)->sat_len == (b)->sat_len && \
725bf5cd24Schristos (a)->sat_family == (b)->sat_family && \
735bf5cd24Schristos (a)->sat_addr.s_net == (b)->sat_addr.s_net && \
745bf5cd24Schristos (a)->sat_addr.s_node == (b)->sat_addr.s_node )
755bf5cd24Schristos
765bf5cd24Schristos int
at_control(u_long cmd,void * data,struct ifnet * ifp)77ae1253a1Srtr at_control(u_long cmd, void *data, struct ifnet *ifp)
785bf5cd24Schristos {
795bf5cd24Schristos struct ifreq *ifr = (struct ifreq *) data;
802fc10275Sdyoung const struct sockaddr_at *csat;
815bf5cd24Schristos struct netrange *nr;
822fc10275Sdyoung const struct netrange *cnr;
835bf5cd24Schristos struct at_aliasreq *ifra = (struct at_aliasreq *) data;
845bf5cd24Schristos struct at_ifaddr *aa0;
855bf5cd24Schristos struct at_ifaddr *aa = 0;
865bf5cd24Schristos
875bf5cd24Schristos /*
885bf5cd24Schristos * If we have an ifp, then find the matching at_ifaddr if it exists
895bf5cd24Schristos */
905bf5cd24Schristos if (ifp)
9197e4f819Sriastradh TAILQ_FOREACH(aa, &at_ifaddr, aa_list)
925bf5cd24Schristos if (aa->aa_ifp == ifp)
935bf5cd24Schristos break;
945bf5cd24Schristos
955bf5cd24Schristos /*
965bf5cd24Schristos * In this first switch table we are basically getting ready for
975bf5cd24Schristos * the second one, by getting the atalk-specific things set up
985bf5cd24Schristos * so that they start to look more similar to other protocols etc.
995bf5cd24Schristos */
1005bf5cd24Schristos
1015bf5cd24Schristos switch (cmd) {
1025bf5cd24Schristos case SIOCAIFADDR:
1035bf5cd24Schristos case SIOCDIFADDR:
1045bf5cd24Schristos /*
1055bf5cd24Schristos * If we have an appletalk sockaddr, scan forward of where
1065bf5cd24Schristos * we are now on the at_ifaddr list to find one with a matching
1075bf5cd24Schristos * address on this interface.
1085bf5cd24Schristos * This may leave aa pointing to the first address on the
1095bf5cd24Schristos * NEXT interface!
1105bf5cd24Schristos */
1115bf5cd24Schristos if (ifra->ifra_addr.sat_family == AF_APPLETALK) {
11297e4f819Sriastradh for (; aa; aa = TAILQ_NEXT(aa, aa_list))
1135bf5cd24Schristos if (aa->aa_ifp == ifp &&
1145bf5cd24Schristos sateqaddr(&aa->aa_addr, &ifra->ifra_addr))
1155bf5cd24Schristos break;
1165bf5cd24Schristos }
1175bf5cd24Schristos /*
118932411bdSandvar * If we a retrying to delete an address but didn't find such,
1195bf5cd24Schristos * then return with an error
1205bf5cd24Schristos */
1215bf5cd24Schristos if (cmd == SIOCDIFADDR && aa == 0)
1225bf5cd24Schristos return (EADDRNOTAVAIL);
1235bf5cd24Schristos /* FALLTHROUGH */
1245bf5cd24Schristos
1255bf5cd24Schristos case SIOCSIFADDR:
1265bf5cd24Schristos /*
1275bf5cd24Schristos * If we are not superuser, then we don't get to do these
1285bf5cd24Schristos * ops.
1295bf5cd24Schristos */
130c0633eb0Schristos if (kauth_authorize_network(kauth_cred_get(),
1316fac6c46Selad KAUTH_NETWORK_INTERFACE,
1326fac6c46Selad KAUTH_REQ_NETWORK_INTERFACE_SETPRIV, ifp, (void *)cmd,
1336fac6c46Selad NULL) != 0)
1345bf5cd24Schristos return (EPERM);
1355bf5cd24Schristos
1362fc10275Sdyoung csat = satocsat(ifreq_getaddr(cmd, ifr));
1372fc10275Sdyoung cnr = (const struct netrange *)csat->sat_zero;
1382fc10275Sdyoung if (cnr->nr_phase == 1) {
1395bf5cd24Schristos /*
1405bf5cd24Schristos * Look for a phase 1 address on this interface.
1415bf5cd24Schristos * This may leave aa pointing to the first address on
1425bf5cd24Schristos * the NEXT interface!
1435bf5cd24Schristos */
14497e4f819Sriastradh for (; aa; aa = TAILQ_NEXT(aa, aa_list)) {
1455bf5cd24Schristos if (aa->aa_ifp == ifp &&
1465bf5cd24Schristos (aa->aa_flags & AFA_PHASE2) == 0)
1475bf5cd24Schristos break;
1485bf5cd24Schristos }
1495bf5cd24Schristos } else { /* default to phase 2 */
1505bf5cd24Schristos /*
1515bf5cd24Schristos * Look for a phase 2 address on this interface.
1525bf5cd24Schristos * This may leave aa pointing to the first address on
1535bf5cd24Schristos * the NEXT interface!
1545bf5cd24Schristos */
15597e4f819Sriastradh for (; aa; aa = TAILQ_NEXT(aa, aa_list)) {
1565bf5cd24Schristos if (aa->aa_ifp == ifp &&
1575bf5cd24Schristos (aa->aa_flags & AFA_PHASE2))
1585bf5cd24Schristos break;
1595bf5cd24Schristos }
1605bf5cd24Schristos }
1615bf5cd24Schristos
1625bf5cd24Schristos if (ifp == 0)
1635bf5cd24Schristos panic("at_control");
1645bf5cd24Schristos
1655bf5cd24Schristos /*
1665bf5cd24Schristos * If we failed to find an existing at_ifaddr entry, then we
1675bf5cd24Schristos * allocate a fresh one.
1685bf5cd24Schristos * XXX change this to use malloc
1695bf5cd24Schristos */
1705bf5cd24Schristos if (aa == (struct at_ifaddr *) 0) {
1715bf5cd24Schristos aa = (struct at_ifaddr *)
1725bf5cd24Schristos malloc(sizeof(struct at_ifaddr), M_IFADDR,
173be4b6d7eSmatt M_WAITOK|M_ZERO);
1745bf5cd24Schristos
1755bf5cd24Schristos if (aa == NULL)
1765bf5cd24Schristos return (ENOBUFS);
1775bf5cd24Schristos
17888ab7da9Sad callout_init(&aa->aa_probe_ch, 0);
1795bf5cd24Schristos
18097e4f819Sriastradh if ((aa0 = TAILQ_FIRST(&at_ifaddr)) != NULL) {
1815bf5cd24Schristos /*
1825bf5cd24Schristos * Don't let the loopback be first, since the
1835bf5cd24Schristos * first address is the machine's default
1845bf5cd24Schristos * address for binding.
1855bf5cd24Schristos * If it is, stick ourself in front, otherwise
1865bf5cd24Schristos * go to the back of the list.
1875bf5cd24Schristos */
1885bf5cd24Schristos if (aa0->aa_ifp->if_flags & IFF_LOOPBACK) {
1895bf5cd24Schristos TAILQ_INSERT_HEAD(&at_ifaddr, aa,
1905bf5cd24Schristos aa_list);
1915bf5cd24Schristos } else {
1925bf5cd24Schristos TAILQ_INSERT_TAIL(&at_ifaddr, aa,
1935bf5cd24Schristos aa_list);
1945bf5cd24Schristos }
1955bf5cd24Schristos } else {
1965bf5cd24Schristos TAILQ_INSERT_TAIL(&at_ifaddr, aa, aa_list);
1975bf5cd24Schristos }
198c419de4aSrmind ifaref(&aa->aa_ifa);
1993ad55fb6Sozaki-r ifa_psref_init(&aa->aa_ifa);
2005bf5cd24Schristos
2015bf5cd24Schristos /*
2025bf5cd24Schristos * Find the end of the interface's addresses
2035bf5cd24Schristos * and link our new one on the end
2045bf5cd24Schristos */
205b579a81eSdyoung ifa_insert(ifp, &aa->aa_ifa);
2065bf5cd24Schristos
2075bf5cd24Schristos /*
2085bf5cd24Schristos * As the at_ifaddr contains the actual sockaddrs,
2095bf5cd24Schristos * and the ifaddr itself, link them al together
2105bf5cd24Schristos * correctly.
2115bf5cd24Schristos */
2125bf5cd24Schristos aa->aa_ifa.ifa_addr =
2135bf5cd24Schristos (struct sockaddr *) &aa->aa_addr;
2145bf5cd24Schristos aa->aa_ifa.ifa_dstaddr =
2155bf5cd24Schristos (struct sockaddr *) &aa->aa_addr;
2165bf5cd24Schristos aa->aa_ifa.ifa_netmask =
2175bf5cd24Schristos (struct sockaddr *) &aa->aa_netmask;
2185bf5cd24Schristos
2195bf5cd24Schristos /*
2205bf5cd24Schristos * Set/clear the phase 2 bit.
2215bf5cd24Schristos */
2222fc10275Sdyoung if (cnr->nr_phase == 1)
2235bf5cd24Schristos aa->aa_flags &= ~AFA_PHASE2;
2245bf5cd24Schristos else
2255bf5cd24Schristos aa->aa_flags |= AFA_PHASE2;
2265bf5cd24Schristos
2275bf5cd24Schristos /*
2285bf5cd24Schristos * and link it all together
2295bf5cd24Schristos */
2305bf5cd24Schristos aa->aa_ifp = ifp;
2315bf5cd24Schristos } else {
2325bf5cd24Schristos /*
2335bf5cd24Schristos * If we DID find one then we clobber any routes
2345bf5cd24Schristos * dependent on it..
2355bf5cd24Schristos */
2365bf5cd24Schristos at_scrub(ifp, aa);
2375bf5cd24Schristos }
2385bf5cd24Schristos break;
2395bf5cd24Schristos
2405bf5cd24Schristos case SIOCGIFADDR:
2412fc10275Sdyoung csat = satocsat(ifreq_getaddr(cmd, ifr));
2422fc10275Sdyoung cnr = (const struct netrange *)csat->sat_zero;
2432fc10275Sdyoung if (cnr->nr_phase == 1) {
2445bf5cd24Schristos /*
2455bf5cd24Schristos * If the request is specifying phase 1, then
2465bf5cd24Schristos * only look at a phase one address
2475bf5cd24Schristos */
24897e4f819Sriastradh for (; aa; aa = TAILQ_NEXT(aa, aa_list)) {
2495bf5cd24Schristos if (aa->aa_ifp == ifp &&
2505bf5cd24Schristos (aa->aa_flags & AFA_PHASE2) == 0)
2515bf5cd24Schristos break;
2525bf5cd24Schristos }
2532fc10275Sdyoung } else if (cnr->nr_phase == 2) {
2545bf5cd24Schristos /*
255a40ad8abSis * If the request is specifying phase 2, then
256a40ad8abSis * only look at a phase two address
2575bf5cd24Schristos */
25897e4f819Sriastradh for (; aa; aa = TAILQ_NEXT(aa, aa_list)) {
2595bf5cd24Schristos if (aa->aa_ifp == ifp &&
2605bf5cd24Schristos (aa->aa_flags & AFA_PHASE2))
2615bf5cd24Schristos break;
2625bf5cd24Schristos }
263a40ad8abSis } else {
264a40ad8abSis /*
265a40ad8abSis * default to everything
266a40ad8abSis */
26797e4f819Sriastradh for (; aa; aa = TAILQ_NEXT(aa, aa_list)) {
268a40ad8abSis if (aa->aa_ifp == ifp)
269a40ad8abSis break;
270a40ad8abSis }
2715bf5cd24Schristos }
2725bf5cd24Schristos
2735bf5cd24Schristos if (aa == (struct at_ifaddr *) 0)
2745bf5cd24Schristos return (EADDRNOTAVAIL);
2755bf5cd24Schristos break;
2765bf5cd24Schristos }
2775bf5cd24Schristos
2785bf5cd24Schristos /*
2795bf5cd24Schristos * By the time this switch is run we should be able to assume that
2805bf5cd24Schristos * the "aa" pointer is valid when needed.
2815bf5cd24Schristos */
2825bf5cd24Schristos switch (cmd) {
2832fc10275Sdyoung case SIOCGIFADDR: {
2842fc10275Sdyoung union {
2852fc10275Sdyoung struct sockaddr sa;
2862fc10275Sdyoung struct sockaddr_at sat;
2872fc10275Sdyoung } u;
2885bf5cd24Schristos
2895bf5cd24Schristos /*
2905bf5cd24Schristos * copy the contents of the sockaddr blindly.
2915bf5cd24Schristos */
2922fc10275Sdyoung sockaddr_copy(&u.sa, sizeof(u),
2932fc10275Sdyoung (const struct sockaddr *)&aa->aa_addr);
2945bf5cd24Schristos /*
2955bf5cd24Schristos * and do some cleanups
2965bf5cd24Schristos */
2972fc10275Sdyoung nr = (struct netrange *)&u.sat.sat_zero;
2982fc10275Sdyoung nr->nr_phase = (aa->aa_flags & AFA_PHASE2) ? 2 : 1;
2992fc10275Sdyoung nr->nr_firstnet = aa->aa_firstnet;
3002fc10275Sdyoung nr->nr_lastnet = aa->aa_lastnet;
3012fc10275Sdyoung ifreq_setaddr(cmd, ifr, &u.sa);
3025bf5cd24Schristos break;
3032fc10275Sdyoung }
3045bf5cd24Schristos
3055bf5cd24Schristos case SIOCSIFADDR:
3062fc10275Sdyoung return at_ifinit(ifp, aa,
3072fc10275Sdyoung (const struct sockaddr_at *)ifreq_getaddr(cmd, ifr));
3085bf5cd24Schristos
3095bf5cd24Schristos case SIOCAIFADDR:
3105bf5cd24Schristos if (sateqaddr(&ifra->ifra_addr, &aa->aa_addr))
3115bf5cd24Schristos return 0;
3122fc10275Sdyoung return at_ifinit(ifp, aa,
3132fc10275Sdyoung (const struct sockaddr_at *)ifreq_getaddr(cmd, ifr));
3145bf5cd24Schristos
3155bf5cd24Schristos case SIOCDIFADDR:
316b8f324faSdyoung at_purgeaddr(&aa->aa_ifa);
3175bf5cd24Schristos break;
3185bf5cd24Schristos
3195bf5cd24Schristos default:
320de87fe67Sdyoung return ENOTTY;
3215bf5cd24Schristos }
3225bf5cd24Schristos return (0);
3235bf5cd24Schristos }
3245bf5cd24Schristos
325d844a3acSthorpej void
at_purgeaddr(struct ifaddr * ifa)326b8f324faSdyoung at_purgeaddr(struct ifaddr *ifa)
327d844a3acSthorpej {
328b8f324faSdyoung struct ifnet *ifp = ifa->ifa_ifp;
329d844a3acSthorpej struct at_ifaddr *aa = (void *) ifa;
330d844a3acSthorpej
331d844a3acSthorpej /*
332d844a3acSthorpej * scrub all routes.. didn't we just DO this? XXX yes, del it
333d844a3acSthorpej * XXX above XXX not necessarily true anymore
334d844a3acSthorpej */
335d844a3acSthorpej at_scrub(ifp, aa);
336d844a3acSthorpej
337d844a3acSthorpej /*
338d844a3acSthorpej * remove the ifaddr from the interface
339d844a3acSthorpej */
340b579a81eSdyoung ifa_remove(ifp, &aa->aa_ifa);
341d844a3acSthorpej TAILQ_REMOVE(&at_ifaddr, aa, aa_list);
342c419de4aSrmind ifafree(&aa->aa_ifa);
343d844a3acSthorpej }
344d844a3acSthorpej
345c1185c10Sthorpej void
at_purgeif(struct ifnet * ifp)346b8f324faSdyoung at_purgeif(struct ifnet *ifp)
347c1185c10Sthorpej {
348b8f324faSdyoung if_purgeaddrs(ifp, AF_APPLETALK, at_purgeaddr);
349c1185c10Sthorpej }
350c1185c10Sthorpej
3515bf5cd24Schristos /*
3525bf5cd24Schristos * Given an interface and an at_ifaddr (supposedly on that interface) remove
3535bf5cd24Schristos * any routes that depend on this. Why ifp is needed I'm not sure, as
3545bf5cd24Schristos * aa->at_ifaddr.ifa_ifp should be the same.
3555bf5cd24Schristos */
3565bf5cd24Schristos static int
at_scrub(struct ifnet * ifp,struct at_ifaddr * aa)357454af1c0Sdsl at_scrub(struct ifnet *ifp, struct at_ifaddr *aa)
3585bf5cd24Schristos {
3595bf5cd24Schristos int error = 0;
3605bf5cd24Schristos
3615bf5cd24Schristos if (aa->aa_flags & AFA_ROUTE) {
3625bf5cd24Schristos if (ifp->if_flags & IFF_LOOPBACK)
3635bf5cd24Schristos error = aa_delsingleroute(&aa->aa_ifa,
3645bf5cd24Schristos &aa->aa_addr.sat_addr, &aa->aa_netmask.sat_addr);
3655bf5cd24Schristos else if (ifp->if_flags & IFF_POINTOPOINT)
3665bf5cd24Schristos error = rtinit(&aa->aa_ifa, RTM_DELETE, RTF_HOST);
3675bf5cd24Schristos else if (ifp->if_flags & IFF_BROADCAST)
3685bf5cd24Schristos error = aa_dorangeroute(&aa->aa_ifa,
3695bf5cd24Schristos ntohs(aa->aa_firstnet), ntohs(aa->aa_lastnet),
3705bf5cd24Schristos RTM_DELETE);
3715bf5cd24Schristos
3725bf5cd24Schristos aa->aa_ifa.ifa_flags &= ~IFA_ROUTE;
3735bf5cd24Schristos aa->aa_flags &= ~AFA_ROUTE;
3745bf5cd24Schristos }
3755bf5cd24Schristos return error;
3765bf5cd24Schristos }
3775bf5cd24Schristos
3785bf5cd24Schristos /*
3795bf5cd24Schristos * given an at_ifaddr,a sockaddr_at and an ifp,
3805bf5cd24Schristos * bang them all together at high speed and see what happens
3815bf5cd24Schristos */
3825bf5cd24Schristos static int
at_ifinit(struct ifnet * ifp,struct at_ifaddr * aa,const struct sockaddr_at * sat)383454af1c0Sdsl at_ifinit(struct ifnet *ifp, struct at_ifaddr *aa, const struct sockaddr_at *sat)
3845bf5cd24Schristos {
3855bf5cd24Schristos struct netrange nr, onr;
3865bf5cd24Schristos struct sockaddr_at oldaddr;
387bf2dcec4Sthorpej int s = splnet(), error = 0, i, j;
3885bf5cd24Schristos int netinc, nodeinc, nnets;
3895bf5cd24Schristos u_short net;
3905bf5cd24Schristos
3915bf5cd24Schristos /*
3925bf5cd24Schristos * save the old addresses in the at_ifaddr just in case we need them.
3935bf5cd24Schristos */
3945bf5cd24Schristos oldaddr = aa->aa_addr;
3955bf5cd24Schristos onr.nr_firstnet = aa->aa_firstnet;
3965bf5cd24Schristos onr.nr_lastnet = aa->aa_lastnet;
3975bf5cd24Schristos
3985bf5cd24Schristos /*
3995bf5cd24Schristos * take the address supplied as an argument, and add it to the
4005bf5cd24Schristos * at_ifnet (also given). Remember ing to update
4015bf5cd24Schristos * those parts of the at_ifaddr that need special processing
4025bf5cd24Schristos */
403c363a9cbScegger memset(AA_SAT(aa), 0, sizeof(struct sockaddr_at));
404e2cb8590Scegger memcpy(&nr, sat->sat_zero, sizeof(struct netrange));
405e2cb8590Scegger memcpy(AA_SAT(aa)->sat_zero, sat->sat_zero, sizeof(struct netrange));
4065bf5cd24Schristos nnets = ntohs(nr.nr_lastnet) - ntohs(nr.nr_firstnet) + 1;
4075bf5cd24Schristos aa->aa_firstnet = nr.nr_firstnet;
4085bf5cd24Schristos aa->aa_lastnet = nr.nr_lastnet;
4095bf5cd24Schristos
4105bf5cd24Schristos #ifdef NETATALKDEBUG
4115bf5cd24Schristos printf("at_ifinit: %s: %u.%u range %u-%u phase %d\n",
4125bf5cd24Schristos ifp->if_xname,
4135bf5cd24Schristos ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node,
4145bf5cd24Schristos ntohs(aa->aa_firstnet), ntohs(aa->aa_lastnet),
4155bf5cd24Schristos (aa->aa_flags & AFA_PHASE2) ? 2 : 1);
4165bf5cd24Schristos #endif
4175bf5cd24Schristos
4185bf5cd24Schristos /*
4195bf5cd24Schristos * We could eliminate the need for a second phase 1 probe (post
4205bf5cd24Schristos * autoconf) if we check whether we're resetting the node. Note
4215bf5cd24Schristos * that phase 1 probes use only nodes, not net.node pairs. Under
4225bf5cd24Schristos * phase 2, both the net and node must be the same.
4235bf5cd24Schristos */
424*5707ddccSriastradh AA_SAT(aa)->sat_len = sizeof(struct sockaddr_at);
4255bf5cd24Schristos AA_SAT(aa)->sat_family = AF_APPLETALK;
4265bf5cd24Schristos if (ifp->if_flags & IFF_LOOPBACK) {
4275bf5cd24Schristos AA_SAT(aa)->sat_addr.s_net = sat->sat_addr.s_net;
4285bf5cd24Schristos AA_SAT(aa)->sat_addr.s_node = sat->sat_addr.s_node;
4295bf5cd24Schristos #if 0
4305bf5cd24Schristos } else if (fp->if_flags & IFF_POINTOPOINT) {
4315bf5cd24Schristos /* unimplemented */
4325bf5cd24Schristos /*
4335bf5cd24Schristos * we'd have to copy the dstaddr field over from the sat
4345bf5cd24Schristos * but it's not clear that it would contain the right info..
4355bf5cd24Schristos */
4365bf5cd24Schristos #endif
4375bf5cd24Schristos } else {
4385bf5cd24Schristos /*
4395bf5cd24Schristos * We are a normal (probably ethernet) interface.
4405bf5cd24Schristos * apply the new address to the interface structures etc.
4415bf5cd24Schristos * We will probe this address on the net first, before
4425bf5cd24Schristos * applying it to ensure that it is free.. If it is not, then
4435bf5cd24Schristos * we will try a number of other randomly generated addresses
4445bf5cd24Schristos * in this net and then increment the net. etc.etc. until
4455bf5cd24Schristos * we find an unused address.
4465bf5cd24Schristos */
4475bf5cd24Schristos aa->aa_flags |= AFA_PROBING; /* if not loopback we Must
4485bf5cd24Schristos * probe? */
4495bf5cd24Schristos if (aa->aa_flags & AFA_PHASE2) {
4505bf5cd24Schristos if (sat->sat_addr.s_net == ATADDR_ANYNET) {
4515bf5cd24Schristos /*
4525bf5cd24Schristos * If we are phase 2, and the net was not
4535bf5cd24Schristos * specified * then we select a random net
4545bf5cd24Schristos * within the supplied netrange.
4555bf5cd24Schristos * XXX use /dev/random?
4565bf5cd24Schristos */
4575bf5cd24Schristos if (nnets != 1) {
4585bf5cd24Schristos net = ntohs(nr.nr_firstnet) +
459de4337abSkardel time_second % (nnets - 1);
4605bf5cd24Schristos } else {
4615bf5cd24Schristos net = ntohs(nr.nr_firstnet);
4625bf5cd24Schristos }
4635bf5cd24Schristos } else {
4645bf5cd24Schristos /*
4655bf5cd24Schristos * if a net was supplied, then check that it
4665bf5cd24Schristos * is within the netrange. If it is not then
4675bf5cd24Schristos * replace the old values and return an error
4685bf5cd24Schristos */
4695bf5cd24Schristos if (ntohs(sat->sat_addr.s_net) <
4705bf5cd24Schristos ntohs(nr.nr_firstnet) ||
4715bf5cd24Schristos ntohs(sat->sat_addr.s_net) >
4725bf5cd24Schristos ntohs(nr.nr_lastnet)) {
4735bf5cd24Schristos aa->aa_addr = oldaddr;
4745bf5cd24Schristos aa->aa_firstnet = onr.nr_firstnet;
4755bf5cd24Schristos aa->aa_lastnet = onr.nr_lastnet;
4765bf5cd24Schristos splx(s);
4775bf5cd24Schristos return (EINVAL);
4785bf5cd24Schristos }
4795bf5cd24Schristos /*
4805bf5cd24Schristos * otherwise just use the new net number..
4815bf5cd24Schristos */
4825bf5cd24Schristos net = ntohs(sat->sat_addr.s_net);
4835bf5cd24Schristos }
4845bf5cd24Schristos } else {
4855bf5cd24Schristos /*
4865bf5cd24Schristos * we must be phase one, so just use whatever we were
4875bf5cd24Schristos * given. I guess it really isn't going to be used...
4885bf5cd24Schristos * RIGHT?
4895bf5cd24Schristos */
4905bf5cd24Schristos net = ntohs(sat->sat_addr.s_net);
4915bf5cd24Schristos }
4925bf5cd24Schristos
4935bf5cd24Schristos /*
4945bf5cd24Schristos * set the node part of the address into the ifaddr. If it's
4955bf5cd24Schristos * not specified, be random about it... XXX use /dev/random?
4965bf5cd24Schristos */
4975bf5cd24Schristos if (sat->sat_addr.s_node == ATADDR_ANYNODE) {
498de4337abSkardel AA_SAT(aa)->sat_addr.s_node = time_second;
4995bf5cd24Schristos } else {
5005bf5cd24Schristos AA_SAT(aa)->sat_addr.s_node = sat->sat_addr.s_node;
5015bf5cd24Schristos }
5025bf5cd24Schristos
5035bf5cd24Schristos /*
5045bf5cd24Schristos * step through the nets in the range starting at the
5055bf5cd24Schristos * (possibly random) start point.
5065bf5cd24Schristos */
5075bf5cd24Schristos for (i = nnets, netinc = 1; i > 0; net = ntohs(nr.nr_firstnet) +
5085bf5cd24Schristos ((net - ntohs(nr.nr_firstnet) + netinc) % nnets), i--) {
5095bf5cd24Schristos AA_SAT(aa)->sat_addr.s_net = htons(net);
5105bf5cd24Schristos
5115bf5cd24Schristos /*
5125bf5cd24Schristos * using a rather strange stepping method,
5135bf5cd24Schristos * stagger through the possible node addresses
5145bf5cd24Schristos * Once again, starting at the (possibly random)
5155bf5cd24Schristos * initial node address.
5165bf5cd24Schristos */
517de4337abSkardel for (j = 0, nodeinc = time_second | 1; j < 256;
5185bf5cd24Schristos j++, AA_SAT(aa)->sat_addr.s_node += nodeinc) {
5195bf5cd24Schristos if (AA_SAT(aa)->sat_addr.s_node > 253 ||
5205bf5cd24Schristos AA_SAT(aa)->sat_addr.s_node < 1) {
5215bf5cd24Schristos continue;
5225bf5cd24Schristos }
5235bf5cd24Schristos aa->aa_probcnt = 10;
5245bf5cd24Schristos
5255bf5cd24Schristos /*
5265bf5cd24Schristos * start off the probes as an asynchronous
5275bf5cd24Schristos * activity. though why wait 200mSec?
5285bf5cd24Schristos */
529fc96443dSthorpej callout_reset(&aa->aa_probe_ch, hz / 5,
530fc96443dSthorpej aarpprobe, ifp);
5313ddd7168Sad if (tsleep(aa, PPAUSE | PCATCH, "at_ifinit",
5323ddd7168Sad 0)) {
5335bf5cd24Schristos /*
5345bf5cd24Schristos * theoretically we shouldn't time out
5355bf5cd24Schristos * here so if we returned with an error.
5365bf5cd24Schristos */
5375bf5cd24Schristos printf("at_ifinit: timeout?!\n");
5385bf5cd24Schristos aa->aa_addr = oldaddr;
5395bf5cd24Schristos aa->aa_firstnet = onr.nr_firstnet;
5405bf5cd24Schristos aa->aa_lastnet = onr.nr_lastnet;
5415bf5cd24Schristos splx(s);
5425bf5cd24Schristos return (EINTR);
5435bf5cd24Schristos }
5445bf5cd24Schristos /*
5455bf5cd24Schristos * The async activity should have woken us
5465bf5cd24Schristos * up. We need to see if it was successful in
5475bf5cd24Schristos * finding a free spot, or if we need to
5485bf5cd24Schristos * iterate to the next address to try.
5495bf5cd24Schristos */
5505bf5cd24Schristos if ((aa->aa_flags & AFA_PROBING) == 0)
5515bf5cd24Schristos break;
5525bf5cd24Schristos }
5535bf5cd24Schristos
5545bf5cd24Schristos /*
5555bf5cd24Schristos * of course we need to break out through two loops...
5565bf5cd24Schristos */
5575bf5cd24Schristos if ((aa->aa_flags & AFA_PROBING) == 0)
5585bf5cd24Schristos break;
5595bf5cd24Schristos
5605bf5cd24Schristos /* reset node for next network */
561de4337abSkardel AA_SAT(aa)->sat_addr.s_node = time_second;
5625bf5cd24Schristos }
5635bf5cd24Schristos
5645bf5cd24Schristos /*
5655bf5cd24Schristos * if we are still trying to probe, then we have finished all
5665bf5cd24Schristos * the possible addresses, so we need to give up
5675bf5cd24Schristos */
5685bf5cd24Schristos if (aa->aa_flags & AFA_PROBING) {
5695bf5cd24Schristos aa->aa_addr = oldaddr;
5705bf5cd24Schristos aa->aa_firstnet = onr.nr_firstnet;
5715bf5cd24Schristos aa->aa_lastnet = onr.nr_lastnet;
5725bf5cd24Schristos splx(s);
5735bf5cd24Schristos return (EADDRINUSE);
5745bf5cd24Schristos }
5755bf5cd24Schristos }
5765bf5cd24Schristos
5775bf5cd24Schristos /*
5785bf5cd24Schristos * Now that we have selected an address, we need to tell the
5795bf5cd24Schristos * interface about it, just in case it needs to adjust something.
5805bf5cd24Schristos */
581cf4cd8e0Sdyoung if ((error = if_addr_init(ifp, &aa->aa_ifa, true)) != 0) {
5825bf5cd24Schristos /*
5835bf5cd24Schristos * of course this could mean that it objects violently
5845bf5cd24Schristos * so if it does, we back out again..
5855bf5cd24Schristos */
5865bf5cd24Schristos aa->aa_addr = oldaddr;
5875bf5cd24Schristos aa->aa_firstnet = onr.nr_firstnet;
5885bf5cd24Schristos aa->aa_lastnet = onr.nr_lastnet;
5895bf5cd24Schristos splx(s);
5905bf5cd24Schristos return (error);
5915bf5cd24Schristos }
5925bf5cd24Schristos /*
5935bf5cd24Schristos * set up the netmask part of the at_ifaddr and point the appropriate
5945bf5cd24Schristos * pointer in the ifaddr to it. probably pointless, but what the
5955bf5cd24Schristos * heck.. XXX
5965bf5cd24Schristos */
597c363a9cbScegger memset(&aa->aa_netmask, 0, sizeof(aa->aa_netmask));
5985bf5cd24Schristos aa->aa_netmask.sat_len = sizeof(struct sockaddr_at);
5995bf5cd24Schristos aa->aa_netmask.sat_family = AF_APPLETALK;
6005bf5cd24Schristos aa->aa_netmask.sat_addr.s_net = 0xffff;
6015bf5cd24Schristos aa->aa_netmask.sat_addr.s_node = 0;
6025bf5cd24Schristos #if 0
6035bf5cd24Schristos aa->aa_ifa.ifa_netmask = (struct sockaddr *) &(aa->aa_netmask);/* XXX */
6045bf5cd24Schristos #endif
6055bf5cd24Schristos
6065bf5cd24Schristos /*
6075bf5cd24Schristos * Initialize broadcast (or remote p2p) address
6085bf5cd24Schristos */
609c363a9cbScegger memset(&aa->aa_broadaddr, 0, sizeof(aa->aa_broadaddr));
6105bf5cd24Schristos aa->aa_broadaddr.sat_len = sizeof(struct sockaddr_at);
6115bf5cd24Schristos aa->aa_broadaddr.sat_family = AF_APPLETALK;
6125bf5cd24Schristos
6135bf5cd24Schristos aa->aa_ifa.ifa_metric = ifp->if_metric;
6145bf5cd24Schristos if (ifp->if_flags & IFF_BROADCAST) {
6153f0090f6Sis aa->aa_broadaddr.sat_addr.s_net = htons(ATADDR_ANYNET);
6163f0090f6Sis aa->aa_broadaddr.sat_addr.s_node = ATADDR_BCAST;
6175bf5cd24Schristos aa->aa_ifa.ifa_broadaddr =
6185bf5cd24Schristos (struct sockaddr *) &aa->aa_broadaddr;
6195bf5cd24Schristos /* add the range of routes needed */
6205bf5cd24Schristos error = aa_dorangeroute(&aa->aa_ifa,
6215bf5cd24Schristos ntohs(aa->aa_firstnet), ntohs(aa->aa_lastnet), RTM_ADD);
6225bf5cd24Schristos } else if (ifp->if_flags & IFF_POINTOPOINT) {
6235bf5cd24Schristos struct at_addr rtaddr, rtmask;
6245bf5cd24Schristos
625c363a9cbScegger memset(&rtaddr, 0, sizeof(rtaddr));
626c363a9cbScegger memset(&rtmask, 0, sizeof(rtmask));
6275bf5cd24Schristos /* fill in the far end if we know it here XXX */
6285bf5cd24Schristos aa->aa_ifa.ifa_dstaddr = (struct sockaddr *) & aa->aa_dstaddr;
6295bf5cd24Schristos error = aa_addsingleroute(&aa->aa_ifa, &rtaddr, &rtmask);
6305bf5cd24Schristos } else if (ifp->if_flags & IFF_LOOPBACK) {
6315bf5cd24Schristos struct at_addr rtaddr, rtmask;
6325bf5cd24Schristos
633c363a9cbScegger memset(&rtaddr, 0, sizeof(rtaddr));
634c363a9cbScegger memset(&rtmask, 0, sizeof(rtmask));
6355bf5cd24Schristos rtaddr.s_net = AA_SAT(aa)->sat_addr.s_net;
6365bf5cd24Schristos rtaddr.s_node = AA_SAT(aa)->sat_addr.s_node;
6375bf5cd24Schristos rtmask.s_net = 0xffff;
6385bf5cd24Schristos rtmask.s_node = 0x0;
6395bf5cd24Schristos error = aa_addsingleroute(&aa->aa_ifa, &rtaddr, &rtmask);
6405bf5cd24Schristos }
6415bf5cd24Schristos /*
6425bf5cd24Schristos * of course if we can't add these routes we back out, but it's getting
6435bf5cd24Schristos * risky by now XXX
6445bf5cd24Schristos */
6455bf5cd24Schristos if (error) {
6465bf5cd24Schristos at_scrub(ifp, aa);
6475bf5cd24Schristos aa->aa_addr = oldaddr;
6485bf5cd24Schristos aa->aa_firstnet = onr.nr_firstnet;
6495bf5cd24Schristos aa->aa_lastnet = onr.nr_lastnet;
6505bf5cd24Schristos splx(s);
6515bf5cd24Schristos return (error);
6525bf5cd24Schristos }
6535bf5cd24Schristos /*
6545bf5cd24Schristos * note that the address has a route associated with it....
6555bf5cd24Schristos */
6565bf5cd24Schristos aa->aa_ifa.ifa_flags |= IFA_ROUTE;
6575bf5cd24Schristos aa->aa_flags |= AFA_ROUTE;
6585bf5cd24Schristos splx(s);
6595bf5cd24Schristos return (0);
6605bf5cd24Schristos }
6615bf5cd24Schristos
6625bf5cd24Schristos /*
6635bf5cd24Schristos * check whether a given address is a broadcast address for us..
6645bf5cd24Schristos */
6655bf5cd24Schristos int
at_broadcast(const struct sockaddr_at * sat)6665493f188Sdyoung at_broadcast(const struct sockaddr_at *sat)
6675bf5cd24Schristos {
6685bf5cd24Schristos struct at_ifaddr *aa;
6695bf5cd24Schristos
6705bf5cd24Schristos /*
6715bf5cd24Schristos * If the node is not right, it can't be a broadcast
6725bf5cd24Schristos */
6735bf5cd24Schristos if (sat->sat_addr.s_node != ATADDR_BCAST)
6745bf5cd24Schristos return 0;
6755bf5cd24Schristos
6765bf5cd24Schristos /*
6775bf5cd24Schristos * If the node was right then if the net is right, it's a broadcast
6785bf5cd24Schristos */
6795bf5cd24Schristos if (sat->sat_addr.s_net == ATADDR_ANYNET)
6805bf5cd24Schristos return 1;
6815bf5cd24Schristos
6825bf5cd24Schristos /*
6835bf5cd24Schristos * failing that, if the net is one we have, it's a broadcast as well.
6845bf5cd24Schristos */
68597e4f819Sriastradh TAILQ_FOREACH(aa, &at_ifaddr, aa_list) {
6865bf5cd24Schristos if ((aa->aa_ifp->if_flags & IFF_BROADCAST)
6875bf5cd24Schristos && (ntohs(sat->sat_addr.s_net) >= ntohs(aa->aa_firstnet)
6885bf5cd24Schristos && ntohs(sat->sat_addr.s_net) <= ntohs(aa->aa_lastnet)))
6895bf5cd24Schristos return 1;
6905bf5cd24Schristos }
6915bf5cd24Schristos return 0;
6925bf5cd24Schristos }
6935bf5cd24Schristos
6945bf5cd24Schristos
6955bf5cd24Schristos /*
6965bf5cd24Schristos * aa_dorangeroute()
6975bf5cd24Schristos *
6985bf5cd24Schristos * Add a route for a range of networks from bot to top - 1.
6995bf5cd24Schristos * Algorithm:
7005bf5cd24Schristos *
7015bf5cd24Schristos * Split the range into two subranges such that the middle
7025bf5cd24Schristos * of the two ranges is the point where the highest bit of difference
7037d1220acSsnj * between the two addresses, makes its transition
7045bf5cd24Schristos * Each of the upper and lower ranges might not exist, or might be
7055bf5cd24Schristos * representable by 1 or more netmasks. In addition, if both
7065bf5cd24Schristos * ranges can be represented by the same netmask, then teh can be merged
7075bf5cd24Schristos * by using the next higher netmask..
7085bf5cd24Schristos */
7095bf5cd24Schristos
7105bf5cd24Schristos static int
aa_dorangeroute(struct ifaddr * ifa,u_int bot,u_int top,int cmd)711454af1c0Sdsl aa_dorangeroute(struct ifaddr *ifa, u_int bot, u_int top, int cmd)
7125bf5cd24Schristos {
7135bf5cd24Schristos u_int mask1;
7145bf5cd24Schristos struct at_addr addr;
7155bf5cd24Schristos struct at_addr mask;
7165bf5cd24Schristos int error;
7175bf5cd24Schristos
7185bf5cd24Schristos /*
7195bf5cd24Schristos * slight sanity check
7205bf5cd24Schristos */
7215bf5cd24Schristos if (bot > top)
7225bf5cd24Schristos return (EINVAL);
7235bf5cd24Schristos
7245bf5cd24Schristos addr.s_node = 0;
7255bf5cd24Schristos mask.s_node = 0;
7265bf5cd24Schristos /*
7275bf5cd24Schristos * just start out with the lowest boundary
7285bf5cd24Schristos * and keep extending the mask till it's too big.
7295bf5cd24Schristos */
7305bf5cd24Schristos
7315bf5cd24Schristos while (bot <= top) {
7325bf5cd24Schristos mask1 = 1;
7335bf5cd24Schristos while (((bot & ~mask1) >= bot)
7345bf5cd24Schristos && ((bot | mask1) <= top)) {
7355bf5cd24Schristos mask1 <<= 1;
7365bf5cd24Schristos mask1 |= 1;
7375bf5cd24Schristos }
7385bf5cd24Schristos mask1 >>= 1;
7395bf5cd24Schristos mask.s_net = htons(~mask1);
7405bf5cd24Schristos addr.s_net = htons(bot);
7415bf5cd24Schristos if (cmd == RTM_ADD) {
7425bf5cd24Schristos error = aa_addsingleroute(ifa, &addr, &mask);
7435bf5cd24Schristos if (error) {
7445bf5cd24Schristos /* XXX clean up? */
7455bf5cd24Schristos return (error);
7465bf5cd24Schristos }
7475bf5cd24Schristos } else {
7485bf5cd24Schristos error = aa_delsingleroute(ifa, &addr, &mask);
7495bf5cd24Schristos }
7505bf5cd24Schristos bot = (bot | mask1) + 1;
7515bf5cd24Schristos }
7525bf5cd24Schristos return 0;
7535bf5cd24Schristos }
7545bf5cd24Schristos
7555bf5cd24Schristos static int
aa_addsingleroute(struct ifaddr * ifa,struct at_addr * addr,struct at_addr * mask)756454af1c0Sdsl aa_addsingleroute(struct ifaddr *ifa, struct at_addr *addr, struct at_addr *mask)
7575bf5cd24Schristos {
7585bf5cd24Schristos int error;
7595bf5cd24Schristos
7605bf5cd24Schristos #ifdef NETATALKDEBUG
7615bf5cd24Schristos printf("aa_addsingleroute: %x.%x mask %x.%x ...",
7625bf5cd24Schristos ntohs(addr->s_net), addr->s_node,
7635bf5cd24Schristos ntohs(mask->s_net), mask->s_node);
7645bf5cd24Schristos #endif
7655bf5cd24Schristos
7665bf5cd24Schristos error = aa_dosingleroute(ifa, addr, mask, RTM_ADD, RTF_UP);
7675bf5cd24Schristos #ifdef NETATALKDEBUG
7685bf5cd24Schristos if (error)
7695bf5cd24Schristos printf("aa_addsingleroute: error %d\n", error);
7705bf5cd24Schristos #endif
7715bf5cd24Schristos return (error);
7725bf5cd24Schristos }
7735bf5cd24Schristos
7745bf5cd24Schristos static int
aa_delsingleroute(struct ifaddr * ifa,struct at_addr * addr,struct at_addr * mask)775454af1c0Sdsl aa_delsingleroute(struct ifaddr *ifa, struct at_addr *addr, struct at_addr *mask)
7765bf5cd24Schristos {
7775bf5cd24Schristos int error;
7785bf5cd24Schristos
7795bf5cd24Schristos #ifdef NETATALKDEBUG
7805bf5cd24Schristos printf("aa_delsingleroute: %x.%x mask %x.%x ...",
7815bf5cd24Schristos ntohs(addr->s_net), addr->s_node,
7825bf5cd24Schristos ntohs(mask->s_net), mask->s_node);
7835bf5cd24Schristos #endif
7845bf5cd24Schristos
7855bf5cd24Schristos error = aa_dosingleroute(ifa, addr, mask, RTM_DELETE, 0);
7865bf5cd24Schristos #ifdef NETATALKDEBUG
7875bf5cd24Schristos if (error)
7885bf5cd24Schristos printf("aa_delsingleroute: error %d\n", error);
7895bf5cd24Schristos #endif
7905bf5cd24Schristos return (error);
7915bf5cd24Schristos }
7925bf5cd24Schristos
7935bf5cd24Schristos static int
aa_dosingleroute(struct ifaddr * ifa,struct at_addr * at_addr,struct at_addr * at_mask,int cmd,int flags)794454af1c0Sdsl aa_dosingleroute(struct ifaddr *ifa, struct at_addr *at_addr, struct at_addr *at_mask, int cmd, int flags)
7955bf5cd24Schristos {
7965bf5cd24Schristos struct sockaddr_at addr, mask, *gate;
7975bf5cd24Schristos
798c363a9cbScegger memset(&addr, 0, sizeof(addr));
799c363a9cbScegger memset(&mask, 0, sizeof(mask));
8005bf5cd24Schristos addr.sat_family = AF_APPLETALK;
8015bf5cd24Schristos addr.sat_len = sizeof(struct sockaddr_at);
8025bf5cd24Schristos addr.sat_addr.s_net = at_addr->s_net;
8035bf5cd24Schristos addr.sat_addr.s_node = at_addr->s_node;
8045bf5cd24Schristos mask.sat_family = AF_APPLETALK;
8055bf5cd24Schristos mask.sat_len = sizeof(struct sockaddr_at);
8065bf5cd24Schristos mask.sat_addr.s_net = at_mask->s_net;
8075bf5cd24Schristos mask.sat_addr.s_node = at_mask->s_node;
8085bf5cd24Schristos
8095bf5cd24Schristos if (at_mask->s_node) {
8105bf5cd24Schristos gate = satosat(ifa->ifa_dstaddr);
8115bf5cd24Schristos flags |= RTF_HOST;
8125bf5cd24Schristos } else {
8135bf5cd24Schristos gate = satosat(ifa->ifa_addr);
8145bf5cd24Schristos }
8155bf5cd24Schristos
8165bf5cd24Schristos #ifdef NETATALKDEBUG
8175bf5cd24Schristos printf("on %s %x.%x\n", (flags & RTF_HOST) ? "host" : "net",
8185bf5cd24Schristos ntohs(gate->sat_addr.s_net), gate->sat_addr.s_node);
8195bf5cd24Schristos #endif
8205bf5cd24Schristos return (rtrequest(cmd, (struct sockaddr *) &addr,
8215bf5cd24Schristos (struct sockaddr *) gate, (struct sockaddr *) &mask, flags, NULL));
8225bf5cd24Schristos }
8235bf5cd24Schristos
8245bf5cd24Schristos #if 0
8255bf5cd24Schristos static void
826df7f595eScegger aa_clean(void)
8275bf5cd24Schristos {
8285bf5cd24Schristos struct at_ifaddr *aa;
8295bf5cd24Schristos struct ifaddr *ifa;
8305bf5cd24Schristos struct ifnet *ifp;
8315bf5cd24Schristos
832399c4bedSdyoung while ((aa = TAILQ_FIRST(&at_ifaddr)) != NULL) {
833399c4bedSdyoung TAILQ_REMOVE(&at_ifaddr, aa, aa_list);
8345bf5cd24Schristos ifp = aa->aa_ifp;
8355bf5cd24Schristos at_scrub(ifp, aa);
8363d4d635bSozaki-r IFADDR_READER_FOREACH(ifa, ifp) {
837399c4bedSdyoung if (ifa == &aa->aa_ifa)
838399c4bedSdyoung break;
8395bf5cd24Schristos }
840399c4bedSdyoung if (ifa == NULL)
841399c4bedSdyoung panic("aa not present");
842b579a81eSdyoung ifa_remove(ifp, ifa);
8435bf5cd24Schristos }
8445bf5cd24Schristos }
8455bf5cd24Schristos #endif
846