xref: /netbsd/sys/netatalk/at_control.c (revision 5707ddcc)
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