xref: /netbsd-src/sys/netatalk/aarp.c (revision 481d3881954fd794ca5f2d880b68c53a5db8620e)
1*481d3881Srin /*	$NetBSD: aarp.c,v 1.47 2024/07/05 04:31:53 rin Exp $	*/
25bf5cd24Schristos 
35bf5cd24Schristos /*
45bf5cd24Schristos  * Copyright (c) 1990,1991 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*481d3881Srin __KERNEL_RCSID(0, "$NetBSD: aarp.c,v 1.47 2024/07/05 04:31:53 rin Exp $");
31d505b189Smartin 
32d505b189Smartin #include "opt_mbuftrace.h"
336f874b81Srjs #include "opt_atalk.h"
34b60687cbSlukem 
3525656462Slukem #include <sys/param.h>
365bf5cd24Schristos #include <sys/socket.h>
375bf5cd24Schristos #include <sys/syslog.h>
385bf5cd24Schristos #include <sys/systm.h>
39fc96443dSthorpej #include <sys/callout.h>
405bf5cd24Schristos #include <sys/proc.h>
415bf5cd24Schristos #include <sys/mbuf.h>
425bf5cd24Schristos #include <sys/time.h>
435bf5cd24Schristos #include <sys/kernel.h>
4415e29e98Sad #include <sys/socketvar.h>
455bf5cd24Schristos #include <net/if.h>
465bf5cd24Schristos #include <net/route.h>
475bf5cd24Schristos #include <net/if_ether.h>
485bf5cd24Schristos #include <net/if_dl.h>
495bf5cd24Schristos #include <netinet/in.h>
505bf5cd24Schristos #undef s_net
515bf5cd24Schristos 
525bf5cd24Schristos #include <netatalk/at.h>
535bf5cd24Schristos #include <netatalk/at_var.h>
545bf5cd24Schristos #include <netatalk/aarp.h>
555bf5cd24Schristos #include <netatalk/ddp_var.h>
565bf5cd24Schristos #include <netatalk/phase2.h>
575bf5cd24Schristos #include <netatalk/at_extern.h>
585bf5cd24Schristos 
595493f188Sdyoung static struct aarptab *aarptnew(const struct at_addr *);
605493f188Sdyoung static void aarptfree(struct aarptab *);
615493f188Sdyoung static void at_aarpinput(struct ifnet *, struct mbuf *);
625493f188Sdyoung static void aarptimer(void *);
635493f188Sdyoung static void aarpwhohas(struct ifnet *, const struct sockaddr_at *);
645bf5cd24Schristos 
655bf5cd24Schristos #define AARPTAB_BSIZ	9
665bf5cd24Schristos #define AARPTAB_NB	19
675bf5cd24Schristos #define AARPTAB_SIZE	(AARPTAB_BSIZ * AARPTAB_NB)
685bf5cd24Schristos struct aarptab  aarptab[AARPTAB_SIZE];
695bf5cd24Schristos 
705bf5cd24Schristos #define AARPTAB_HASH(a) \
715bf5cd24Schristos     ((((a).s_net << 8 ) + (a).s_node ) % AARPTAB_NB )
725bf5cd24Schristos 
735bf5cd24Schristos #define AARPTAB_LOOK(aat, addr) { 				\
745bf5cd24Schristos 	int n;							\
75e4107f29Sdholland 								\
76268ecba0Sdholland 	(aat) = &aarptab[AARPTAB_HASH(addr) * AARPTAB_BSIZ];	\
77268ecba0Sdholland 	for (n = 0; n < AARPTAB_BSIZ; n++, (aat)++) {		\
78268ecba0Sdholland 		if ((aat)->aat_ataddr.s_net == (addr).s_net &&	\
79268ecba0Sdholland 	            (aat)->aat_ataddr.s_node == (addr).s_node)	\
805bf5cd24Schristos 			break;					\
811161b087Sdholland 	}							\
821161b087Sdholland 	if (n >= AARPTAB_BSIZ) {				\
83268ecba0Sdholland 		(aat) = 0;					\
841161b087Sdholland 	}							\
855bf5cd24Schristos }
865bf5cd24Schristos 
875bf5cd24Schristos #define AARPT_AGE	(60 * 1)
885bf5cd24Schristos #define AARPT_KILLC	20
895bf5cd24Schristos #define AARPT_KILLI	3
905bf5cd24Schristos 
910f46b890Smatt const u_char atmulticastaddr[6] = {
925bf5cd24Schristos 	0x09, 0x00, 0x07, 0xff, 0xff, 0xff
935bf5cd24Schristos };
945bf5cd24Schristos 
950f46b890Smatt const u_char at_org_code[3] = {
965bf5cd24Schristos 	0x08, 0x00, 0x07
975bf5cd24Schristos };
980f46b890Smatt const u_char aarp_org_code[3] = {
995bf5cd24Schristos 	0x00, 0x00, 0x00
1005bf5cd24Schristos };
1015bf5cd24Schristos 
102fc96443dSthorpej struct callout aarptimer_callout;
1030f46b890Smatt #ifdef MBUFTRACE
10455ddfc9aSdogcow struct mowner aarp_mowner = MOWNER_INIT("atalk", "arp");
1050f46b890Smatt #endif
1065bf5cd24Schristos 
10706374318Sperry /*ARGSUSED*/
1085bf5cd24Schristos static void
aarptimer(void * ignored)109168cd830Schristos aarptimer(void *ignored)
1105bf5cd24Schristos {
1115bf5cd24Schristos 	struct aarptab *aat;
1125bf5cd24Schristos 	int             i, s;
1135bf5cd24Schristos 
11415e29e98Sad 	mutex_enter(softnet_lock);
115fc96443dSthorpej 	callout_reset(&aarptimer_callout, AARPT_AGE * hz, aarptimer, NULL);
1165bf5cd24Schristos 	aat = aarptab;
1175bf5cd24Schristos 	for (i = 0; i < AARPTAB_SIZE; i++, aat++) {
1185bf5cd24Schristos 		int killtime = (aat->aat_flags & ATF_COM) ? AARPT_KILLC :
1195bf5cd24Schristos 		    AARPT_KILLI;
1205bf5cd24Schristos 		if (aat->aat_flags == 0 || (aat->aat_flags & ATF_PERM))
1215bf5cd24Schristos 			continue;
1225bf5cd24Schristos 		if (++aat->aat_timer < killtime)
1235bf5cd24Schristos 			continue;
124bf2dcec4Sthorpej 		s = splnet();
1255bf5cd24Schristos 		aarptfree(aat);
1265bf5cd24Schristos 		splx(s);
1275bf5cd24Schristos 	}
12815e29e98Sad 	mutex_exit(softnet_lock);
1295bf5cd24Schristos }
1305bf5cd24Schristos 
1315bf5cd24Schristos /*
1325bf5cd24Schristos  * search through the network addresses to find one that includes the given
1335bf5cd24Schristos  * network.. remember to take netranges into consideration.
1345bf5cd24Schristos  */
1355bf5cd24Schristos struct ifaddr *
at_ifawithnet(const struct sockaddr_at * sat,struct ifnet * ifp)136454af1c0Sdsl at_ifawithnet(const struct sockaddr_at *sat, struct ifnet *ifp)
1375bf5cd24Schristos {
1383b17cac3Schristos 	struct ifaddr *ifa;
1395bf5cd24Schristos 	struct sockaddr_at *sat2;
1405bf5cd24Schristos 	struct netrange *nr;
1415bf5cd24Schristos 
1429e4c2bdaSozaki-r 	IFADDR_READER_FOREACH(ifa, ifp) {
1435bf5cd24Schristos 		if (ifa->ifa_addr->sa_family != AF_APPLETALK)
1445bf5cd24Schristos 			continue;
1455bf5cd24Schristos 
1465bf5cd24Schristos 		sat2 = satosat(ifa->ifa_addr);
1475bf5cd24Schristos 		if (sat2->sat_addr.s_net == sat->sat_addr.s_net)
1485bf5cd24Schristos 			break;
1495bf5cd24Schristos 
1505bf5cd24Schristos 		nr = (struct netrange *) (sat2->sat_zero);
1515bf5cd24Schristos 		if ((nr->nr_phase == 2)
15234772d5eSchristos 		    && (ntohs(nr->nr_firstnet) <= ntohs(sat->sat_addr.s_net))
15334772d5eSchristos 		    && (ntohs(nr->nr_lastnet) >= ntohs(sat->sat_addr.s_net)))
1545bf5cd24Schristos 			break;
1555bf5cd24Schristos 	}
156a403cbd4Sozaki-r 
1575bf5cd24Schristos 	return ifa;
1585bf5cd24Schristos }
1595bf5cd24Schristos 
1605bf5cd24Schristos static void
aarpwhohas(struct ifnet * ifp,const struct sockaddr_at * sat)161454af1c0Sdsl aarpwhohas(struct ifnet *ifp, const struct sockaddr_at *sat)
1625bf5cd24Schristos {
1635bf5cd24Schristos 	struct mbuf    *m;
1645bf5cd24Schristos 	struct ether_header *eh;
1655bf5cd24Schristos 	struct ether_aarp *ea;
1665bf5cd24Schristos 	struct at_ifaddr *aa;
1675bf5cd24Schristos 	struct llc     *llc;
1685bf5cd24Schristos 	struct sockaddr sa;
1695bf5cd24Schristos 
1705bf5cd24Schristos 	if ((m = m_gethdr(M_DONTWAIT, MT_DATA)) == NULL)
1715bf5cd24Schristos 		return;
1725bf5cd24Schristos 
1730f46b890Smatt 	MCLAIM(m, &aarp_mowner);
1745bf5cd24Schristos 	m->m_len = sizeof(*ea);
1755bf5cd24Schristos 	m->m_pkthdr.len = sizeof(*ea);
1765b040abeSmaxv 	m_align(m, sizeof(*ea));
1775bf5cd24Schristos 
1785bf5cd24Schristos 	ea = mtod(m, struct ether_aarp *);
179c363a9cbScegger 	memset(ea, 0, sizeof(*ea));
1805bf5cd24Schristos 
1815bf5cd24Schristos 	ea->aarp_hrd = htons(AARPHRD_ETHER);
182cd7e3136Skim 	ea->aarp_pro = htons(ETHERTYPE_ATALK);
1835bf5cd24Schristos 	ea->aarp_hln = sizeof(ea->aarp_sha);
1845bf5cd24Schristos 	ea->aarp_pln = sizeof(ea->aarp_spu);
1855bf5cd24Schristos 	ea->aarp_op = htons(AARPOP_REQUEST);
186e2cb8590Scegger 	memcpy(ea->aarp_sha, CLLADDR(ifp->if_sadl), sizeof(ea->aarp_sha));
1875bf5cd24Schristos 
1885bf5cd24Schristos 	/*
1895bf5cd24Schristos          * We need to check whether the output ethernet type should
1905bf5cd24Schristos          * be phase 1 or 2. We have the interface that we'll be sending
1915bf5cd24Schristos          * the aarp out. We need to find an AppleTalk network on that
1925bf5cd24Schristos          * interface with the same address as we're looking for. If the
1935bf5cd24Schristos          * net is phase 2, generate an 802.2 and SNAP header.
1945bf5cd24Schristos          */
1953b17cac3Schristos 	if ((aa = (struct at_ifaddr *) at_ifawithnet(sat, ifp)) == NULL) {
1965bf5cd24Schristos 		m_freem(m);
1975bf5cd24Schristos 		return;
1985bf5cd24Schristos 	}
1995bf5cd24Schristos 	eh = (struct ether_header *) sa.sa_data;
2005bf5cd24Schristos 
2015bf5cd24Schristos 	if (aa->aa_flags & AFA_PHASE2) {
202e2cb8590Scegger 		memcpy(eh->ether_dhost, atmulticastaddr,
2035bf5cd24Schristos 		    sizeof(eh->ether_dhost));
20472a3b3a0Smatt 		eh->ether_type = 0;	/* if_output will treat as 802 */
20501c8c2e9Sitojun 		M_PREPEND(m, sizeof(struct llc), M_DONTWAIT);
20601c8c2e9Sitojun 		if (!m)
20701c8c2e9Sitojun 			return;
20801c8c2e9Sitojun 
2095bf5cd24Schristos 		llc = mtod(m, struct llc *);
2105bf5cd24Schristos 		llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP;
2115bf5cd24Schristos 		llc->llc_control = LLC_UI;
212e2cb8590Scegger 		memcpy(llc->llc_org_code, aarp_org_code, sizeof(aarp_org_code));
2135bf5cd24Schristos 		llc->llc_ether_type = htons(ETHERTYPE_AARP);
2145bf5cd24Schristos 
215e2cb8590Scegger 		memcpy(ea->aarp_spnet, &AA_SAT(aa)->sat_addr.s_net,
2165bf5cd24Schristos 		      sizeof(ea->aarp_spnet));
217e2cb8590Scegger 		memcpy(ea->aarp_tpnet, &sat->sat_addr.s_net,
2185bf5cd24Schristos 		      sizeof(ea->aarp_tpnet));
2195bf5cd24Schristos 		ea->aarp_spnode = AA_SAT(aa)->sat_addr.s_node;
2205bf5cd24Schristos 		ea->aarp_tpnode = sat->sat_addr.s_node;
2215bf5cd24Schristos 	} else {
222e2cb8590Scegger 		memcpy(eh->ether_dhost, etherbroadcastaddr,
2235bf5cd24Schristos 		    sizeof(eh->ether_dhost));
2245bf5cd24Schristos 		eh->ether_type = htons(ETHERTYPE_AARP);
2255bf5cd24Schristos 
2265bf5cd24Schristos 		ea->aarp_spa = AA_SAT(aa)->sat_addr.s_node;
2275bf5cd24Schristos 		ea->aarp_tpa = sat->sat_addr.s_node;
2285bf5cd24Schristos 	}
2295bf5cd24Schristos 
2302e878a9dShauke 	/* If we are talking to ourselves, use the loopback interface. */
2312e878a9dShauke 	if (AA_SAT(aa)->sat_addr.s_net == sat->sat_addr.s_net &&
2322e878a9dShauke 	    AA_SAT(aa)->sat_addr.s_node == sat->sat_addr.s_node)
2332e878a9dShauke 		ifp = lo0ifp;
2342e878a9dShauke 
2355bf5cd24Schristos #ifdef NETATALKDEBUG
2362e878a9dShauke 	printf("aarp: sending request via %u.%u through %s seeking %u.%u\n",
2372e878a9dShauke 	    ntohs(AA_SAT(aa)->sat_addr.s_net),
2382e878a9dShauke 	    AA_SAT(aa)->sat_addr.s_node,
2392e878a9dShauke 	    ifp->if_xname,
2402e878a9dShauke 	    ntohs(sat->sat_addr.s_net),
2412e878a9dShauke 	    sat->sat_addr.s_node);
2425bf5cd24Schristos #endif /* NETATALKDEBUG */
2435bf5cd24Schristos 
2445bf5cd24Schristos 	sa.sa_len = sizeof(struct sockaddr);
2455bf5cd24Schristos 	sa.sa_family = AF_UNSPEC;
24695fc1456Sknakahara 	if_output_lock(ifp, ifp, m, &sa, NULL);	/* XXX NULL should be routing */
2475bf5cd24Schristos 						/* information */
2485bf5cd24Schristos }
2495bf5cd24Schristos 
2505bf5cd24Schristos int
aarpresolve(struct ifnet * ifp,struct mbuf * m,const struct sockaddr_at * destsat,u_char * desten)2515493f188Sdyoung aarpresolve(struct ifnet *ifp, struct mbuf *m,
2525493f188Sdyoung     const struct sockaddr_at *destsat, u_char *desten)
2535bf5cd24Schristos {
2545bf5cd24Schristos 	struct at_ifaddr *aa;
2555bf5cd24Schristos 	struct aarptab *aat;
2565bf5cd24Schristos 	int             s;
2575bf5cd24Schristos 
2585bf5cd24Schristos 	if (at_broadcast(destsat)) {
259a403cbd4Sozaki-r 		struct ifaddr *ifa;
260a403cbd4Sozaki-r 
261a403cbd4Sozaki-r 		s = pserialize_read_enter();
262a403cbd4Sozaki-r 		ifa = at_ifawithnet(destsat, ifp);
263a403cbd4Sozaki-r 		if (ifa == NULL) {
264a403cbd4Sozaki-r 			pserialize_read_exit(s);
2655bf5cd24Schristos 			m_freem(m);
2665bf5cd24Schristos 			return (0);
2675bf5cd24Schristos 		}
268a403cbd4Sozaki-r 		aa = (struct at_ifaddr *)ifa;
269a403cbd4Sozaki-r 
2705bf5cd24Schristos 		if (aa->aa_flags & AFA_PHASE2)
271e2cb8590Scegger 			memcpy(desten, atmulticastaddr,
2725bf5cd24Schristos 			    sizeof(atmulticastaddr));
2735bf5cd24Schristos 		else
274e2cb8590Scegger 			memcpy(desten, etherbroadcastaddr,
2755bf5cd24Schristos 			    sizeof(etherbroadcastaddr));
276a403cbd4Sozaki-r 		pserialize_read_exit(s);
2775bf5cd24Schristos 		return 1;
2785bf5cd24Schristos 	}
279bf2dcec4Sthorpej 	s = splnet();
2805bf5cd24Schristos 	AARPTAB_LOOK(aat, destsat->sat_addr);
2815bf5cd24Schristos 	if (aat == 0) {		/* No entry */
2825bf5cd24Schristos 		aat = aarptnew(&destsat->sat_addr);
2835bf5cd24Schristos 		if (aat == 0)
2845bf5cd24Schristos 			panic("aarpresolve: no free entry");
2855bf5cd24Schristos 
2865bf5cd24Schristos 		aat->aat_hold = m;
2875bf5cd24Schristos 		aarpwhohas(ifp, destsat);
2885bf5cd24Schristos 		splx(s);
2895bf5cd24Schristos 		return 0;
2905bf5cd24Schristos 	}
2915bf5cd24Schristos 
2925bf5cd24Schristos 	/* found an entry */
2935bf5cd24Schristos 	aat->aat_timer = 0;
2945bf5cd24Schristos 	if (aat->aat_flags & ATF_COM) {	/* entry is COMplete */
295e2cb8590Scegger 		memcpy(desten, aat->aat_enaddr, sizeof(aat->aat_enaddr));
2965bf5cd24Schristos 		splx(s);
2975bf5cd24Schristos 		return 1;
2985bf5cd24Schristos 	}
2995bf5cd24Schristos 
3005bf5cd24Schristos 	/* entry has not completed */
3015bf5cd24Schristos 	m_freem(aat->aat_hold);
3025bf5cd24Schristos 	aat->aat_hold = m;
3035bf5cd24Schristos 	aarpwhohas(ifp, destsat);
3045bf5cd24Schristos 	splx(s);
3055bf5cd24Schristos 
3065bf5cd24Schristos 	return 0;
3075bf5cd24Schristos }
3085bf5cd24Schristos 
3095bf5cd24Schristos void
aarpinput(struct ifnet * ifp,struct mbuf * m)310454af1c0Sdsl aarpinput(struct ifnet *ifp, struct mbuf *m)
3115bf5cd24Schristos {
3125bf5cd24Schristos 	struct arphdr  *ar;
3135bf5cd24Schristos 
3145bf5cd24Schristos 	if (ifp->if_flags & IFF_NOARP)
3155bf5cd24Schristos 		goto out;
3165bf5cd24Schristos 
3175bf5cd24Schristos 	if (m->m_len < sizeof(struct arphdr))
3185bf5cd24Schristos 		goto out;
3195bf5cd24Schristos 
3205bf5cd24Schristos 	ar = mtod(m, struct arphdr *);
3215bf5cd24Schristos 	if (ntohs(ar->ar_hrd) != AARPHRD_ETHER)
3225bf5cd24Schristos 		goto out;
3235bf5cd24Schristos 
3245bf5cd24Schristos 	if (m->m_len < sizeof(struct arphdr) + 2 * ar->ar_hln + 2 * ar->ar_pln)
3255bf5cd24Schristos 		goto out;
3265bf5cd24Schristos 
3275bf5cd24Schristos 	switch (ntohs(ar->ar_pro)) {
328cd7e3136Skim 	case ETHERTYPE_ATALK:
3295bf5cd24Schristos 		at_aarpinput(ifp, m);
3305bf5cd24Schristos 		return;
3315bf5cd24Schristos 
3325bf5cd24Schristos 	default:
3335bf5cd24Schristos 		break;
3345bf5cd24Schristos 	}
3355bf5cd24Schristos 
3365bf5cd24Schristos out:
3375bf5cd24Schristos 	m_freem(m);
3385bf5cd24Schristos }
3395bf5cd24Schristos 
3405bf5cd24Schristos static void
at_aarpinput(struct ifnet * ifp,struct mbuf * m)341454af1c0Sdsl at_aarpinput(struct ifnet *ifp, struct mbuf *m)
3425bf5cd24Schristos {
3435bf5cd24Schristos 	struct ether_aarp *ea;
3445bf5cd24Schristos 	struct at_ifaddr *aa;
3455bf5cd24Schristos 	struct aarptab *aat;
3465bf5cd24Schristos 	struct ether_header *eh;
3475bf5cd24Schristos 	struct llc     *llc;
3485bf5cd24Schristos 	struct sockaddr_at sat;
3495bf5cd24Schristos 	struct sockaddr sa;
3505bf5cd24Schristos 	struct at_addr  spa, tpa, ma;
3515bf5cd24Schristos 	int             op;
3525bf5cd24Schristos 	u_int16_t       net;
353a403cbd4Sozaki-r 	int		s;
354a403cbd4Sozaki-r 	struct psref	psref;
355a403cbd4Sozaki-r 	struct ifaddr *ifa;
3565bf5cd24Schristos 
357012aa161Smaxv 	/* We should also check ar_hln and ar_pln. */
358012aa161Smaxv 	if ((m = m_pullup(m, sizeof(struct ether_aarp))) == NULL) {
359012aa161Smaxv 		return;
360012aa161Smaxv 	}
361012aa161Smaxv 
3625bf5cd24Schristos 	ea = mtod(m, struct ether_aarp *);
3635bf5cd24Schristos 
3645bf5cd24Schristos 	/* Check to see if from my hardware address */
36535fb6474Scegger 	if (!memcmp(ea->aarp_sha, CLLADDR(ifp->if_sadl), sizeof(ea->aarp_sha))) {
3665bf5cd24Schristos 		m_freem(m);
3675bf5cd24Schristos 		return;
3685bf5cd24Schristos 	}
3695bf5cd24Schristos 	op = ntohs(ea->aarp_op);
370e2cb8590Scegger 	memcpy(&net, ea->aarp_tpnet, sizeof(net));
3715bf5cd24Schristos 
3725bf5cd24Schristos 	if (net != 0) {		/* should be ATADDR_ANYNET? */
3735bf5cd24Schristos 		sat.sat_len = sizeof(struct sockaddr_at);
3745bf5cd24Schristos 		sat.sat_family = AF_APPLETALK;
3755bf5cd24Schristos 		sat.sat_addr.s_net = net;
376a403cbd4Sozaki-r 
377a403cbd4Sozaki-r 		s = pserialize_read_enter();
378a403cbd4Sozaki-r 		ifa = at_ifawithnet(&sat, ifp);
379a403cbd4Sozaki-r 		if (ifa == NULL) {
380a403cbd4Sozaki-r 			pserialize_read_exit(s);
3815bf5cd24Schristos 			m_freem(m);
3825bf5cd24Schristos 			return;
3835bf5cd24Schristos 		}
384a403cbd4Sozaki-r 		ifa_acquire(ifa, &psref);
385a403cbd4Sozaki-r 		pserialize_read_exit(s);
386a403cbd4Sozaki-r 		aa = (struct at_ifaddr *)ifa;
387a403cbd4Sozaki-r 
388e2cb8590Scegger 		memcpy(&spa.s_net, ea->aarp_spnet, sizeof(spa.s_net));
389e2cb8590Scegger 		memcpy(&tpa.s_net, ea->aarp_tpnet, sizeof(tpa.s_net));
3905bf5cd24Schristos 	} else {
3915bf5cd24Schristos 		/*
3925bf5cd24Schristos 		 * Since we don't know the net, we just look for the first
3935bf5cd24Schristos 		 * phase 1 address on the interface.
3945bf5cd24Schristos 		 */
395a403cbd4Sozaki-r 		s = pserialize_read_enter();
396a403cbd4Sozaki-r 		IFADDR_READER_FOREACH(ifa, ifp) {
397a403cbd4Sozaki-r 			aa = (struct at_ifaddr *)ifa;
3985bf5cd24Schristos 			if (AA_SAT(aa)->sat_family == AF_APPLETALK &&
399a403cbd4Sozaki-r 			    (aa->aa_flags & AFA_PHASE2) == 0) {
400a403cbd4Sozaki-r 				ifa_acquire(ifa, &psref);
4015bf5cd24Schristos 				break;
4025bf5cd24Schristos 			}
403a403cbd4Sozaki-r 		}
404a403cbd4Sozaki-r 		pserialize_read_exit(s);
405a403cbd4Sozaki-r 
406a403cbd4Sozaki-r 		if (ifa == NULL) {
4075bf5cd24Schristos 			m_freem(m);
4085bf5cd24Schristos 			return;
4095bf5cd24Schristos 		}
4105bf5cd24Schristos 		tpa.s_net = spa.s_net = AA_SAT(aa)->sat_addr.s_net;
4115bf5cd24Schristos 	}
4125bf5cd24Schristos 
4135bf5cd24Schristos 	spa.s_node = ea->aarp_spnode;
4145bf5cd24Schristos 	tpa.s_node = ea->aarp_tpnode;
4155bf5cd24Schristos 	ma.s_net = AA_SAT(aa)->sat_addr.s_net;
4165bf5cd24Schristos 	ma.s_node = AA_SAT(aa)->sat_addr.s_node;
4175bf5cd24Schristos 
4185bf5cd24Schristos 	/*
4195bf5cd24Schristos          * This looks like it's from us.
4205bf5cd24Schristos          */
4215bf5cd24Schristos 	if (spa.s_net == ma.s_net && spa.s_node == ma.s_node) {
4225bf5cd24Schristos 		if (aa->aa_flags & AFA_PROBING) {
4235bf5cd24Schristos 			/*
4245bf5cd24Schristos 		         * We're probing, someone either responded to our
4255bf5cd24Schristos 			 * probe, or probed for the same address we'd like
4265bf5cd24Schristos 			 * to use. Change the address we're probing for.
4275bf5cd24Schristos 		         */
428fc96443dSthorpej 			callout_stop(&aa->aa_probe_ch);
4295bf5cd24Schristos 			wakeup(aa);
4305bf5cd24Schristos 			m_freem(m);
431a403cbd4Sozaki-r 			goto out;
4325bf5cd24Schristos 		} else if (op != AARPOP_PROBE) {
4335bf5cd24Schristos 			/*
4345bf5cd24Schristos 		         * This is not a probe, and we're not probing.
4355bf5cd24Schristos 			 * This means that someone's saying they have the same
4365bf5cd24Schristos 			 * source address as the one we're using. Get upset...
4375bf5cd24Schristos 		         */
4385bf5cd24Schristos 			log(LOG_ERR, "aarp: duplicate AT address!! %s\n",
4395bf5cd24Schristos 			    ether_sprintf(ea->aarp_sha));
4405bf5cd24Schristos 			m_freem(m);
441a403cbd4Sozaki-r 			goto out;
4425bf5cd24Schristos 		}
4435bf5cd24Schristos 	}
4445bf5cd24Schristos 	AARPTAB_LOOK(aat, spa);
4455bf5cd24Schristos 	if (aat) {
4465bf5cd24Schristos 		if (op == AARPOP_PROBE) {
4475bf5cd24Schristos 			/*
44886932ac5Swiz 		         * Someone's probing for spa, deallocate the one we've
4495bf5cd24Schristos 			 * got, so that if the prober keeps the address, we'll
4505bf5cd24Schristos 			 * be able to arp for him.
4515bf5cd24Schristos 		         */
4525bf5cd24Schristos 			aarptfree(aat);
4535bf5cd24Schristos 			m_freem(m);
454a403cbd4Sozaki-r 			goto out;
4555bf5cd24Schristos 		}
456e2cb8590Scegger 		memcpy(aat->aat_enaddr, ea->aarp_sha, sizeof(ea->aarp_sha));
4575bf5cd24Schristos 		aat->aat_flags |= ATF_COM;
4585bf5cd24Schristos 		if (aat->aat_hold) {
4595bf5cd24Schristos 			sat.sat_len = sizeof(struct sockaddr_at);
4605bf5cd24Schristos 			sat.sat_family = AF_APPLETALK;
4615bf5cd24Schristos 			sat.sat_addr = spa;
46295fc1456Sknakahara 			if_output_lock(ifp, ifp, aat->aat_hold,
4635bf5cd24Schristos 			    (struct sockaddr *) & sat, NULL);	/* XXX */
4645bf5cd24Schristos 			aat->aat_hold = 0;
4655bf5cd24Schristos 		}
4665bf5cd24Schristos 	}
4675bf5cd24Schristos 	if (aat == 0 && tpa.s_net == ma.s_net && tpa.s_node == ma.s_node
4685bf5cd24Schristos 	    && op != AARPOP_PROBE) {
4695bf5cd24Schristos 		if ((aat = aarptnew(&spa)) != NULL) {
470e2cb8590Scegger 			memcpy(aat->aat_enaddr, ea->aarp_sha,
4715bf5cd24Schristos 			    sizeof(ea->aarp_sha));
4725bf5cd24Schristos 			aat->aat_flags |= ATF_COM;
4735bf5cd24Schristos 		}
4745bf5cd24Schristos 	}
4755bf5cd24Schristos 	/*
4765bf5cd24Schristos          * Don't respond to responses, and never respond if we're
4775bf5cd24Schristos          * still probing.
4785bf5cd24Schristos          */
4795bf5cd24Schristos 	if (tpa.s_net != ma.s_net || tpa.s_node != ma.s_node ||
4805bf5cd24Schristos 	    op == AARPOP_RESPONSE || (aa->aa_flags & AFA_PROBING)) {
4815bf5cd24Schristos 		m_freem(m);
482a403cbd4Sozaki-r 		goto out;
4835bf5cd24Schristos 	}
484c3427738Stsutsui 
485c3427738Stsutsui 	/*
486c3427738Stsutsui 	 * Prepare and send AARP-response.
487c3427738Stsutsui 	 */
488c3427738Stsutsui 	m->m_len = sizeof(*ea);
489c3427738Stsutsui 	m->m_pkthdr.len = sizeof(*ea);
490e2cb8590Scegger 	memcpy(ea->aarp_tha, ea->aarp_sha, sizeof(ea->aarp_sha));
491e2cb8590Scegger 	memcpy(ea->aarp_sha, CLLADDR(ifp->if_sadl), sizeof(ea->aarp_sha));
4925bf5cd24Schristos 
4935bf5cd24Schristos 	/* XXX */
4945bf5cd24Schristos 	eh = (struct ether_header *) sa.sa_data;
495e2cb8590Scegger 	memcpy(eh->ether_dhost, ea->aarp_tha, sizeof(eh->ether_dhost));
4965bf5cd24Schristos 
4975bf5cd24Schristos 	if (aa->aa_flags & AFA_PHASE2) {
4985bf5cd24Schristos 		M_PREPEND(m, sizeof(struct llc), M_DONTWAIT);
4995bf5cd24Schristos 		if (m == NULL)
500a403cbd4Sozaki-r 			goto out;
5015bf5cd24Schristos 
5025bf5cd24Schristos 		llc = mtod(m, struct llc *);
5035bf5cd24Schristos 		llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP;
5045bf5cd24Schristos 		llc->llc_control = LLC_UI;
505e2cb8590Scegger 		memcpy(llc->llc_org_code, aarp_org_code, sizeof(aarp_org_code));
5065bf5cd24Schristos 		llc->llc_ether_type = htons(ETHERTYPE_AARP);
5075bf5cd24Schristos 
508e2cb8590Scegger 		memcpy(ea->aarp_tpnet, ea->aarp_spnet, sizeof(ea->aarp_tpnet));
509e2cb8590Scegger 		memcpy(ea->aarp_spnet, &ma.s_net, sizeof(ea->aarp_spnet));
51072a3b3a0Smatt 		eh->ether_type = 0;	/* if_output will treat as 802 */
5115bf5cd24Schristos 	} else {
5125bf5cd24Schristos 		eh->ether_type = htons(ETHERTYPE_AARP);
5135bf5cd24Schristos 	}
5145bf5cd24Schristos 
5155bf5cd24Schristos 	ea->aarp_tpnode = ea->aarp_spnode;
5165bf5cd24Schristos 	ea->aarp_spnode = ma.s_node;
5175bf5cd24Schristos 	ea->aarp_op = htons(AARPOP_RESPONSE);
5185bf5cd24Schristos 
5195bf5cd24Schristos 	sa.sa_len = sizeof(struct sockaddr);
5205bf5cd24Schristos 	sa.sa_family = AF_UNSPEC;
5215bf5cd24Schristos 	(*ifp->if_output) (ifp, m, &sa, NULL);	/* XXX */
522a403cbd4Sozaki-r out:
523a403cbd4Sozaki-r 	ifa_release(ifa, &psref);
5245bf5cd24Schristos 	return;
5255bf5cd24Schristos }
5265bf5cd24Schristos 
5275bf5cd24Schristos static void
aarptfree(struct aarptab * aat)528454af1c0Sdsl aarptfree(struct aarptab *aat)
5295bf5cd24Schristos {
5305bf5cd24Schristos 
5315bf5cd24Schristos 	m_freem(aat->aat_hold);
5325bf5cd24Schristos 	aat->aat_hold = 0;
5335bf5cd24Schristos 	aat->aat_timer = aat->aat_flags = 0;
5345bf5cd24Schristos 	aat->aat_ataddr.s_net = 0;
5355bf5cd24Schristos 	aat->aat_ataddr.s_node = 0;
5365bf5cd24Schristos }
5375bf5cd24Schristos 
5385bf5cd24Schristos static struct aarptab *
aarptnew(const struct at_addr * addr)5395493f188Sdyoung aarptnew(const struct at_addr *addr)
5405bf5cd24Schristos {
5415bf5cd24Schristos 	int             n;
5425bf5cd24Schristos 	int             oldest = -1;
5435bf5cd24Schristos 	struct aarptab *aat, *aato = NULL;
5445bf5cd24Schristos 	static int      first = 1;
5455bf5cd24Schristos 
5465bf5cd24Schristos 	if (first) {
5475bf5cd24Schristos 		first = 0;
54888ab7da9Sad 		callout_init(&aarptimer_callout, 0);
549fc96443dSthorpej 		callout_reset(&aarptimer_callout, hz, aarptimer, NULL);
5505bf5cd24Schristos 	}
5515bf5cd24Schristos 	aat = &aarptab[AARPTAB_HASH(*addr) * AARPTAB_BSIZ];
5525bf5cd24Schristos 	for (n = 0; n < AARPTAB_BSIZ; n++, aat++) {
5535bf5cd24Schristos 		if (aat->aat_flags == 0)
5545bf5cd24Schristos 			goto out;
5555bf5cd24Schristos 		if (aat->aat_flags & ATF_PERM)
5565bf5cd24Schristos 			continue;
5575bf5cd24Schristos 		if ((int) aat->aat_timer > oldest) {
5585bf5cd24Schristos 			oldest = aat->aat_timer;
5595bf5cd24Schristos 			aato = aat;
5605bf5cd24Schristos 		}
5615bf5cd24Schristos 	}
5625bf5cd24Schristos 	if (aato == NULL)
5635bf5cd24Schristos 		return (NULL);
5645bf5cd24Schristos 	aat = aato;
5655bf5cd24Schristos 	aarptfree(aat);
5665bf5cd24Schristos out:
5675bf5cd24Schristos 	aat->aat_ataddr = *addr;
5685bf5cd24Schristos 	aat->aat_flags = ATF_INUSE;
5695bf5cd24Schristos 	return (aat);
5705bf5cd24Schristos }
5715bf5cd24Schristos 
5725bf5cd24Schristos 
5735bf5cd24Schristos void
aarpprobe(void * arp)574454af1c0Sdsl aarpprobe(void *arp)
5755bf5cd24Schristos {
5765bf5cd24Schristos 	struct mbuf    *m;
5775bf5cd24Schristos 	struct ether_header *eh;
5785bf5cd24Schristos 	struct ether_aarp *ea;
57972f0a6dfSdyoung 	struct ifaddr *ia;
5805bf5cd24Schristos 	struct at_ifaddr *aa;
5815bf5cd24Schristos 	struct llc     *llc;
5825bf5cd24Schristos 	struct sockaddr sa;
5835bf5cd24Schristos 	struct ifnet   *ifp = arp;
5845bf5cd24Schristos 
58515e29e98Sad 	mutex_enter(softnet_lock);
58615e29e98Sad 
5875bf5cd24Schristos 	/*
5885bf5cd24Schristos          * We need to check whether the output ethernet type should
5895bf5cd24Schristos          * be phase 1 or 2. We have the interface that we'll be sending
5905bf5cd24Schristos          * the aarp out. We need to find an AppleTalk network on that
5915bf5cd24Schristos          * interface with the same address as we're looking for. If the
5925bf5cd24Schristos          * net is phase 2, generate an 802.2 and SNAP header.
5935bf5cd24Schristos          */
5949e4c2bdaSozaki-r 	IFADDR_READER_FOREACH(ia, ifp) {
59572f0a6dfSdyoung 		aa = (struct at_ifaddr *)ia;
5965bf5cd24Schristos 		if (AA_SAT(aa)->sat_family == AF_APPLETALK &&
5975bf5cd24Schristos 		    (aa->aa_flags & AFA_PROBING))
5985bf5cd24Schristos 			break;
5995bf5cd24Schristos 	}
60072f0a6dfSdyoung 	if (ia == NULL) {	/* serious error XXX */
6015bf5cd24Schristos 		printf("aarpprobe why did this happen?!\n");
60215e29e98Sad 		mutex_exit(softnet_lock);
6035bf5cd24Schristos 		return;
6045bf5cd24Schristos 	}
6055bf5cd24Schristos 	if (aa->aa_probcnt <= 0) {
6065bf5cd24Schristos 		aa->aa_flags &= ~AFA_PROBING;
6075bf5cd24Schristos 		wakeup(aa);
60815e29e98Sad 		mutex_exit(softnet_lock);
6095bf5cd24Schristos 		return;
6105bf5cd24Schristos 	} else {
611fc96443dSthorpej 		callout_reset(&aa->aa_probe_ch, hz / 5, aarpprobe, arp);
6125bf5cd24Schristos 	}
6135bf5cd24Schristos 
61415e29e98Sad 	if ((m = m_gethdr(M_DONTWAIT, MT_DATA)) == NULL) {
61515e29e98Sad 		mutex_exit(softnet_lock);
6165bf5cd24Schristos 		return;
61715e29e98Sad 	}
6180f46b890Smatt 
6190f46b890Smatt 	MCLAIM(m, &aarp_mowner);
6205bf5cd24Schristos 	m->m_len = sizeof(*ea);
6215bf5cd24Schristos 	m->m_pkthdr.len = sizeof(*ea);
6225b040abeSmaxv 	m_align(m, sizeof(*ea));
6235bf5cd24Schristos 
6245bf5cd24Schristos 	ea = mtod(m, struct ether_aarp *);
625c363a9cbScegger 	memset(ea, 0, sizeof(*ea));
6265bf5cd24Schristos 
6275bf5cd24Schristos 	ea->aarp_hrd = htons(AARPHRD_ETHER);
628cd7e3136Skim 	ea->aarp_pro = htons(ETHERTYPE_ATALK);
6295bf5cd24Schristos 	ea->aarp_hln = sizeof(ea->aarp_sha);
6305bf5cd24Schristos 	ea->aarp_pln = sizeof(ea->aarp_spu);
6315bf5cd24Schristos 	ea->aarp_op = htons(AARPOP_PROBE);
632e2cb8590Scegger 	memcpy(ea->aarp_sha, CLLADDR(ifp->if_sadl), sizeof(ea->aarp_sha));
6335bf5cd24Schristos 
6345bf5cd24Schristos 	eh = (struct ether_header *) sa.sa_data;
6355bf5cd24Schristos 
6365bf5cd24Schristos 	if (aa->aa_flags & AFA_PHASE2) {
637e2cb8590Scegger 		memcpy(eh->ether_dhost, atmulticastaddr,
6385bf5cd24Schristos 		    sizeof(eh->ether_dhost));
63972a3b3a0Smatt 		eh->ether_type = 0;	/* if_output will treat as 802 */
64001c8c2e9Sitojun 		M_PREPEND(m, sizeof(struct llc), M_DONTWAIT);
64115e29e98Sad 		if (!m) {
64215e29e98Sad 			mutex_exit(softnet_lock);
64301c8c2e9Sitojun 			return;
64415e29e98Sad 		}
64501c8c2e9Sitojun 
6465bf5cd24Schristos 		llc = mtod(m, struct llc *);
6475bf5cd24Schristos 		llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP;
6485bf5cd24Schristos 		llc->llc_control = LLC_UI;
649e2cb8590Scegger 		memcpy(llc->llc_org_code, aarp_org_code, sizeof(aarp_org_code));
6505bf5cd24Schristos 		llc->llc_ether_type = htons(ETHERTYPE_AARP);
6515bf5cd24Schristos 
652e2cb8590Scegger 		memcpy(ea->aarp_spnet, &AA_SAT(aa)->sat_addr.s_net,
6535bf5cd24Schristos 		      sizeof(ea->aarp_spnet));
654e2cb8590Scegger 		memcpy(ea->aarp_tpnet, &AA_SAT(aa)->sat_addr.s_net,
6555bf5cd24Schristos 		      sizeof(ea->aarp_tpnet));
6565bf5cd24Schristos 		ea->aarp_spnode = ea->aarp_tpnode =
6575bf5cd24Schristos 		    AA_SAT(aa)->sat_addr.s_node;
6585bf5cd24Schristos 	} else {
659e2cb8590Scegger 		memcpy(eh->ether_dhost, etherbroadcastaddr,
6605bf5cd24Schristos 		    sizeof(eh->ether_dhost));
6615bf5cd24Schristos 		eh->ether_type = htons(ETHERTYPE_AARP);
6625bf5cd24Schristos 		ea->aarp_spa = ea->aarp_tpa = AA_SAT(aa)->sat_addr.s_node;
6635bf5cd24Schristos 	}
6645bf5cd24Schristos 
6655bf5cd24Schristos #ifdef NETATALKDEBUG
6665bf5cd24Schristos 	printf("aarp: sending probe for %u.%u\n",
6675bf5cd24Schristos 	       ntohs(AA_SAT(aa)->sat_addr.s_net),
6685bf5cd24Schristos 	       AA_SAT(aa)->sat_addr.s_node);
6695bf5cd24Schristos #endif	/* NETATALKDEBUG */
6705bf5cd24Schristos 
6715bf5cd24Schristos 	sa.sa_len = sizeof(struct sockaddr);
6725bf5cd24Schristos 	sa.sa_family = AF_UNSPEC;
6735bf5cd24Schristos 	(*ifp->if_output) (ifp, m, &sa, NULL);	/* XXX */
6745bf5cd24Schristos 	aa->aa_probcnt--;
67515e29e98Sad 	mutex_exit(softnet_lock);
6765bf5cd24Schristos }
677