1139827Simp/*-
2194619Srwatson * Copyright (c) 2004-2009 Robert N. M. Watson
3133422Srwatson * All rights reserved.
4133422Srwatson *
5133422Srwatson * Redistribution and use in source and binary forms, with or without
6133422Srwatson * modification, are permitted provided that the following conditions
7133422Srwatson * are met:
8133422Srwatson * 1. Redistributions of source code must retain the above copyright
9133422Srwatson *    notice, this list of conditions and the following disclaimer.
10133422Srwatson * 2. Redistributions in binary form must reproduce the above copyright
11133422Srwatson *    notice, this list of conditions and the following disclaimer in the
12133422Srwatson *    documentation and/or other materials provided with the distribution.
13133422Srwatson *
14133422Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15133422Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16133422Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17133422Srwatson * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18133422Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19133422Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20133422Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21133422Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22133422Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23133422Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24133422Srwatson * SUCH DAMAGE.
25165891Srwatson *
26133422Srwatson * Copyright (c) 1990,1991,1994 Regents of The University of Michigan.
2715885Sjulian * All Rights Reserved.
2858795Sjulian *
29133422Srwatson * Permission to use, copy, modify, and distribute this software and
30133422Srwatson * its documentation for any purpose and without fee is hereby granted,
31133422Srwatson * provided that the above copyright notice appears in all copies and
32133422Srwatson * that both that copyright notice and this permission notice appear
33133422Srwatson * in supporting documentation, and that the name of The University
34133422Srwatson * of Michigan not be used in advertising or publicity pertaining to
35133422Srwatson * distribution of the software without specific, written prior
36133422Srwatson * permission. This software is supplied as is without expressed or
37133422Srwatson * implied warranties of any kind.
38133422Srwatson *
39133422Srwatson * This product includes software developed by the University of
40133422Srwatson * California, Berkeley and its contributors.
41133422Srwatson *
42133422Srwatson *	Research Systems Unix Group
43133422Srwatson *	The University of Michigan
44133422Srwatson *	c/o Wesley Craig
45133422Srwatson *	535 W. William Street
46133422Srwatson *	Ann Arbor, Michigan
47133422Srwatson *	+1-313-764-2278
48133422Srwatson *	netatalk@umich.edu
49133422Srwatson *
5058795Sjulian * $FreeBSD$
5115885Sjulian */
5215885Sjulian
5332929Seivind#include "opt_atalk.h"
5432929Seivind
5515885Sjulian#include <sys/param.h>
5615885Sjulian#include <sys/systm.h>
5715885Sjulian#include <sys/mbuf.h>
5815885Sjulian#include <sys/kernel.h>
5929188Sbde#include <sys/socket.h>
6029188Sbde#include <sys/syslog.h>
6129188Sbde
6215885Sjulian#include <net/if.h>
63152315Sru#include <net/if_dl.h>
6429188Sbde
6515885Sjulian#include <netinet/in.h>
6615885Sjulian#undef s_net
6715885Sjulian#include <netinet/if_ether.h>
6815885Sjulian
6915885Sjulian#include <netatalk/at.h>
7015885Sjulian#include <netatalk/at_var.h>
7115885Sjulian#include <netatalk/aarp.h>
7215885Sjulian#include <netatalk/phase2.h>
7315885Sjulian#include <netatalk/at_extern.h>
7415885Sjulian
75163606Srwatson#include <security/mac/mac_framework.h>
76163606Srwatson
77165971Srwatsonstatic void	aarptfree(struct aarptab *aat);
78165971Srwatsonstatic void	at_aarpinput(struct ifnet *ifp, struct mbuf *m);
7915885Sjulian
80165971Srwatson#define	AARPTAB_BSIZ	9
81165971Srwatson#define	AARPTAB_NB	19
82165971Srwatson#define	AARPTAB_SIZE	(AARPTAB_BSIZ * AARPTAB_NB)
8333181Seivindstatic struct aarptab	aarptab[AARPTAB_SIZE];
8415885Sjulian
85165971Srwatsonstruct mtx	aarptab_mtx;
86128042SrwatsonMTX_SYSINIT(aarptab_mtx, &aarptab_mtx, "aarptab_mtx", MTX_DEF);
87128042Srwatson
88165971Srwatson#define	AARPTAB_HASH(a)	((((a).s_net << 8) + (a).s_node) % AARPTAB_NB)
8915885Sjulian
90165971Srwatson#define	AARPTAB_LOOK(aat, addr)	do {					\
91165971Srwatson	int n;								\
92165971Srwatson									\
93165971Srwatson	AARPTAB_LOCK_ASSERT();						\
94165971Srwatson	aat = &aarptab[ AARPTAB_HASH(addr) * AARPTAB_BSIZ ];		\
95165971Srwatson	for (n = 0; n < AARPTAB_BSIZ; n++, aat++) {			\
96165971Srwatson		if (aat->aat_ataddr.s_net == (addr).s_net &&		\
97165971Srwatson		    aat->aat_ataddr.s_node == (addr).s_node)		\
98165971Srwatson			break;						\
99165971Srwatson	}								\
100165971Srwatson	if (n >= AARPTAB_BSIZ)						\
101165971Srwatson		aat = NULL;						\
102165971Srwatson} while (0)
10315885Sjulian
104165971Srwatson#define	AARPT_AGE	(60 * 1)
105165971Srwatson#define	AARPT_KILLC	20
106165971Srwatson#define	AARPT_KILLI	3
10715885Sjulian
108165971Srwatsonstatic const u_char	atmulticastaddr[6] = {
109165971Srwatson	0x09, 0x00, 0x07, 0xff, 0xff, 0xff,
11015885Sjulian};
11115885Sjulian
112165971Srwatsonu_char	at_org_code[3] = {
113165971Srwatson	0x08, 0x00, 0x07,
11415885Sjulian};
115165971Srwatsonconst u_char	aarp_org_code[3] = {
116165971Srwatson	0x00, 0x00, 0x00,
11715885Sjulian};
11815885Sjulian
119165971Srwatsonstatic struct callout_handle	aarptimer_ch =
12029681Sgibbs    CALLOUT_HANDLE_INITIALIZER(&aarptimer_ch);
12129681Sgibbs
12215885Sjulianstatic void
12315885Sjulianaarptimer(void *ignored)
12415885Sjulian{
125165971Srwatson	struct aarptab *aat;
126165971Srwatson	int i;
12715885Sjulian
128165971Srwatson	aarptimer_ch = timeout(aarptimer, NULL, AARPT_AGE * hz);
129165971Srwatson	aat = aarptab;
130165971Srwatson	AARPTAB_LOCK();
131165971Srwatson	for (i = 0; i < AARPTAB_SIZE; i++, aat++) {
132165971Srwatson		if (aat->aat_flags == 0 || (aat->aat_flags & ATF_PERM))
133165971Srwatson			continue;
134165971Srwatson		if (++aat->aat_timer < ((aat->aat_flags & ATF_COM) ?
135165971Srwatson		    AARPT_KILLC : AARPT_KILLI))
136165971Srwatson			continue;
137165971Srwatson		aarptfree(aat);
138165971Srwatson	}
139165971Srwatson	AARPTAB_UNLOCK();
14015885Sjulian}
14115885Sjulian
14217921Sjulian/*
143165971Srwatson * Search through the network addresses to find one that includes the given
144165971Srwatson * network.  Remember to take netranges into consideration.
145194819Srwatson *
146194819Srwatson * The _locked variant relies on the caller holding the at_ifaddr lock; the
147194819Srwatson * unlocked variant returns a reference that the caller must dispose of.
14817921Sjulian */
14930822Sjulianstruct at_ifaddr *
150249925Sglebiusat_ifawithnet_locked(const struct sockaddr_at  *sat)
15115885Sjulian{
152165971Srwatson	struct at_ifaddr *aa;
153165971Srwatson	struct sockaddr_at *sat2;
15415885Sjulian
155194619Srwatson	AT_IFADDR_LOCK_ASSERT();
156194619Srwatson
157194913Srwatson	TAILQ_FOREACH(aa, &at_ifaddrhead, aa_link) {
15830822Sjulian		sat2 = &(aa->aa_addr);
159165971Srwatson		if (sat2->sat_addr.s_net == sat->sat_addr.s_net)
16030822Sjulian			break;
161165971Srwatson		if ((aa->aa_flags & AFA_PHASE2) &&
162165971Srwatson		    (ntohs(aa->aa_firstnet) <= ntohs(sat->sat_addr.s_net)) &&
163165971Srwatson		    (ntohs(aa->aa_lastnet) >= ntohs(sat->sat_addr.s_net)))
164165971Srwatson			break;
16515885Sjulian	}
166127288Srwatson	return (aa);
16715885Sjulian}
16815885Sjulian
169194819Srwatsonstruct at_ifaddr *
170249925Sglebiusat_ifawithnet(const struct sockaddr_at *sat)
171194819Srwatson{
172194819Srwatson	struct at_ifaddr *aa;
173194819Srwatson
174194819Srwatson	AT_IFADDR_RLOCK();
175194819Srwatson	aa = at_ifawithnet_locked(sat);
176194819Srwatson	if (aa != NULL)
177194819Srwatson		ifa_ref(&aa->aa_ifa);
178194819Srwatson	AT_IFADDR_RUNLOCK();
179194819Srwatson	return (aa);
180194819Srwatson}
181194819Srwatson
18215885Sjulianstatic void
183249925Sglebiusaarpwhohas(struct ifnet *ifp, const struct sockaddr_at *sat)
18415885Sjulian{
185165971Srwatson	struct mbuf *m;
186165971Srwatson	struct ether_header *eh;
187165971Srwatson	struct ether_aarp *ea;
188165971Srwatson	struct at_ifaddr *aa;
189165971Srwatson	struct llc *llc;
190165971Srwatson	struct sockaddr	sa;
19115885Sjulian
192165971Srwatson	AARPTAB_UNLOCK_ASSERT();
193243882Sglebius	m = m_gethdr(M_NOWAIT, MT_DATA);
194165971Srwatson	if (m == NULL)
195165971Srwatson		return;
196101937Srwatson#ifdef MAC
197173095Srwatson	mac_netatalk_aarp_send(ifp, m);
198101937Srwatson#endif
199165971Srwatson	m->m_len = sizeof(*ea);
200165971Srwatson	m->m_pkthdr.len = sizeof(*ea);
201165971Srwatson	MH_ALIGN(m, sizeof(*ea));
20215885Sjulian
203165971Srwatson	ea = mtod(m, struct ether_aarp *);
204165971Srwatson	bzero((caddr_t)ea, sizeof(*ea));
20515885Sjulian
206165971Srwatson	ea->aarp_hrd = htons(AARPHRD_ETHER);
207165971Srwatson	ea->aarp_pro = htons(ETHERTYPE_AT);
208165971Srwatson	ea->aarp_hln = sizeof(ea->aarp_sha);
209165971Srwatson	ea->aarp_pln = sizeof(ea->aarp_spu);
210165971Srwatson	ea->aarp_op = htons(AARPOP_REQUEST);
211165971Srwatson	bcopy(IF_LLADDR(ifp), (caddr_t)ea->aarp_sha, sizeof(ea->aarp_sha));
21215885Sjulian
213165971Srwatson	/*
214165971Srwatson	 * We need to check whether the output ethernet type should be phase
215165971Srwatson	 * 1 or 2.  We have the interface that we'll be sending the aarp out.
216165971Srwatson	 * We need to find an AppleTalk network on that interface with the
217165971Srwatson	 * same address as we're looking for.  If the net is phase 2,
218165971Srwatson	 * generate an 802.2 and SNAP header.
219165971Srwatson	 */
220194819Srwatson	aa = at_ifawithnet(sat);
221194819Srwatson	if (aa == NULL) {
222165971Srwatson		m_freem(m);
223165971Srwatson		return;
224165971Srwatson	}
22515885Sjulian
226165971Srwatson	eh = (struct ether_header *)sa.sa_data;
22715885Sjulian
228165971Srwatson	if (aa->aa_flags & AFA_PHASE2) {
229165971Srwatson		bcopy(atmulticastaddr, eh->ether_dhost,
230165971Srwatson		    sizeof(eh->ether_dhost));
231165971Srwatson		eh->ether_type = htons(sizeof(struct llc) +
232165971Srwatson		    sizeof(struct ether_aarp));
233243882Sglebius		M_PREPEND(m, sizeof(struct llc), M_NOWAIT);
234194619Srwatson		if (m == NULL) {
235194819Srwatson			ifa_free(&aa->aa_ifa);
236165971Srwatson			return;
237194619Srwatson		}
238165971Srwatson		llc = mtod(m, struct llc *);
239165971Srwatson		llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP;
240165971Srwatson		llc->llc_control = LLC_UI;
241165971Srwatson		bcopy(aarp_org_code, llc->llc_org_code,
242165971Srwatson		    sizeof(aarp_org_code));
243165971Srwatson		llc->llc_ether_type = htons(ETHERTYPE_AARP);
244165971Srwatson		bcopy(&AA_SAT(aa)->sat_addr.s_net, ea->aarp_spnet,
245165971Srwatson		    sizeof(ea->aarp_spnet));
246165971Srwatson		bcopy(&sat->sat_addr.s_net, ea->aarp_tpnet,
247165971Srwatson		    sizeof(ea->aarp_tpnet));
248165971Srwatson		ea->aarp_spnode = AA_SAT(aa)->sat_addr.s_node;
249165971Srwatson		ea->aarp_tpnode = sat->sat_addr.s_node;
250165971Srwatson	} else {
251165971Srwatson		bcopy(ifp->if_broadcastaddr, (caddr_t)eh->ether_dhost,
252165971Srwatson		    sizeof(eh->ether_dhost));
253165971Srwatson		eh->ether_type = htons(ETHERTYPE_AARP);
254165971Srwatson		ea->aarp_spa = AA_SAT(aa)->sat_addr.s_node;
255165971Srwatson		ea->aarp_tpa = sat->sat_addr.s_node;
256119561Srwatson	}
25715885Sjulian
25815885Sjulian#ifdef NETATALKDEBUG
259165971Srwatson	printf("aarp: sending request for %u.%u\n",
260165971Srwatson	    ntohs(AA_SAT(aa)->sat_addr.s_net), AA_SAT(aa)->sat_addr.s_node);
26132929Seivind#endif /* NETATALKDEBUG */
262194819Srwatson	ifa_free(&aa->aa_ifa);
26315885Sjulian
264165971Srwatson	sa.sa_len = sizeof(struct sockaddr);
265165971Srwatson	sa.sa_family = AF_UNSPEC;
266165971Srwatson	ifp->if_output(ifp, m, &sa, NULL);
26715885Sjulian}
26815885Sjulian
26915885Sjulianint
270249925Sglebiusaarpresolve(struct ifnet *ifp, struct mbuf *m,
271249925Sglebius    const struct sockaddr_at *destsat, u_char *desten)
27215885Sjulian{
273165971Srwatson	struct at_ifaddr *aa;
274165971Srwatson	struct aarptab *aat;
27515885Sjulian
276194619Srwatson	AT_IFADDR_RLOCK();
277165971Srwatson	if (at_broadcast(destsat)) {
278165971Srwatson		m->m_flags |= M_BCAST;
279194819Srwatson		if ((aa = at_ifawithnet_locked(destsat)) == NULL)  {
280194619Srwatson			AT_IFADDR_RUNLOCK();
281165971Srwatson			m_freem(m);
282165971Srwatson			return (0);
283165971Srwatson		}
284165971Srwatson		if (aa->aa_flags & AFA_PHASE2)
285165971Srwatson			bcopy(atmulticastaddr, (caddr_t)desten,
286165971Srwatson			    sizeof(atmulticastaddr));
287165971Srwatson		else
288165971Srwatson			bcopy(ifp->if_broadcastaddr, (caddr_t)desten,
289165971Srwatson			    sizeof(ifp->if_addrlen));
290194619Srwatson		AT_IFADDR_RUNLOCK();
291165971Srwatson		return (1);
29215885Sjulian	}
293194619Srwatson	AT_IFADDR_RUNLOCK();
294165971Srwatson
295165971Srwatson	AARPTAB_LOCK();
296165971Srwatson	AARPTAB_LOOK(aat, destsat->sat_addr);
297165971Srwatson	if (aat == NULL) {
298165971Srwatson		/* No entry. */
299165971Srwatson		aat = aarptnew(&destsat->sat_addr);
300165971Srwatson
301165971Srwatson		/* We should fail more gracefully. */
302165971Srwatson		if (aat == NULL)
303165971Srwatson			panic("aarpresolve: no free entry");
304165971Srwatson		goto done;
30515885Sjulian	}
30615885Sjulian
307165971Srwatson	/* Found an entry. */
308165971Srwatson	aat->aat_timer = 0;
309165971Srwatson	if (aat->aat_flags & ATF_COM) {
310165971Srwatson		/* Entry is COMplete. */
311165971Srwatson		bcopy((caddr_t)aat->aat_enaddr, (caddr_t)desten,
312165971Srwatson		    sizeof(aat->aat_enaddr));
313165971Srwatson		AARPTAB_UNLOCK();
314165971Srwatson		return (1);
31515885Sjulian	}
316165971Srwatson
317165971Srwatson	/* Entry has not completed. */
318165971Srwatson	if (aat->aat_hold)
319165971Srwatson		m_freem(aat->aat_hold);
320165971Srwatsondone:
321165971Srwatson	aat->aat_hold = m;
322128042Srwatson	AARPTAB_UNLOCK();
323165971Srwatson	aarpwhohas(ifp, destsat);
324165971Srwatson	return (0);
32515885Sjulian}
32615885Sjulian
32715885Sjulianvoid
328165971Srwatsonaarpintr(struct mbuf *m)
32915885Sjulian{
330165971Srwatson	struct arphdr *ar;
331165971Srwatson	struct ifnet *ifp;
33215885Sjulian
333165971Srwatson	ifp = m->m_pkthdr.rcvif;
334165971Srwatson	if (ifp->if_flags & IFF_NOARP)
335165971Srwatson		goto out;
33615885Sjulian
337165971Srwatson	if (m->m_len < sizeof(struct arphdr))
338165971Srwatson		goto out;
33915885Sjulian
340165971Srwatson	ar = mtod(m, struct arphdr *);
341165971Srwatson	if (ntohs(ar->ar_hrd) != AARPHRD_ETHER)
342165971Srwatson		goto out;
343165971Srwatson
344165971Srwatson	if (m->m_len < sizeof(struct arphdr) + 2 * ar->ar_hln +
345165971Srwatson	    2 * ar->ar_pln)
346165971Srwatson		goto out;
347165971Srwatson
348165971Srwatson	switch(ntohs(ar->ar_pro)) {
349165971Srwatson	case ETHERTYPE_AT:
350165971Srwatson		at_aarpinput(ifp, m);
351165971Srwatson		return;
352165971Srwatson	default:
353165971Srwatson		break;
354165971Srwatson	}
35515885Sjulian
35615885Sjulianout:
357165971Srwatson	m_freem(m);
35815885Sjulian}
35915885Sjulian
36015885Sjulianstatic void
361128636Sluigiat_aarpinput(struct ifnet *ifp, struct mbuf *m)
36215885Sjulian{
363165971Srwatson	struct ether_aarp *ea;
364165971Srwatson	struct at_ifaddr *aa;
365165971Srwatson	struct aarptab *aat;
366165971Srwatson	struct ether_header *eh;
367165971Srwatson	struct llc *llc;
368165971Srwatson	struct sockaddr_at sat;
369165971Srwatson	struct sockaddr sa;
370165971Srwatson	struct at_addr spa, tpa, ma;
371165971Srwatson	int op;
372165971Srwatson	u_short net;
37315885Sjulian
374165971Srwatson	ea = mtod(m, struct ether_aarp *);
37515885Sjulian
376165971Srwatson	/* Check to see if from my hardware address. */
377165971Srwatson	if (!bcmp((caddr_t)ea->aarp_sha, IF_LLADDR(ifp), ETHER_ADDR_LEN)) {
378165971Srwatson		m_freem(m);
379165971Srwatson		return;
380165971Srwatson	}
38115885Sjulian
382173783Srwatson	/* Don't accept requests from broadcast address. */
383173783Srwatson	if (!bcmp(ea->aarp_sha, ifp->if_broadcastaddr, ifp->if_addrlen)) {
384173783Srwatson		log(LOG_ERR, "aarp: source link address is broadcast\n");
385173783Srwatson		m_freem(m);
386173783Srwatson		return;
387173783Srwatson	}
388173783Srwatson
389165971Srwatson	op = ntohs(ea->aarp_op);
390165971Srwatson	bcopy(ea->aarp_tpnet, &net, sizeof(net));
39115885Sjulian
392165971Srwatson	if (net != 0) {
393165971Srwatson		/* Should be ATADDR_ANYNET? */
394165971Srwatson		sat.sat_len = sizeof(struct sockaddr_at);
395165971Srwatson		sat.sat_family = AF_APPLETALK;
396165971Srwatson		sat.sat_addr.s_net = net;
397194819Srwatson		aa = at_ifawithnet(&sat);
398194819Srwatson		if (aa == NULL) {
399165971Srwatson			m_freem(m);
400165971Srwatson			return;
401165971Srwatson		}
402165971Srwatson		bcopy(ea->aarp_spnet, &spa.s_net, sizeof(spa.s_net));
403165971Srwatson		bcopy(ea->aarp_tpnet, &tpa.s_net, sizeof(tpa.s_net));
404165971Srwatson	} else {
405165971Srwatson		/*
406165971Srwatson		 * Since we don't know the net, we just look for the first
407165971Srwatson		 * phase 1 address on the interface.
408165971Srwatson		 */
409229621Sjhb		IF_ADDR_RLOCK(ifp);
410165971Srwatson		for (aa = (struct at_ifaddr *)TAILQ_FIRST(&ifp->if_addrhead);
411165971Srwatson		    aa;
412165971Srwatson		    aa = (struct at_ifaddr *)aa->aa_ifa.ifa_link.tqe_next) {
413165971Srwatson			if (AA_SAT(aa)->sat_family == AF_APPLETALK &&
414165971Srwatson			    (aa->aa_flags & AFA_PHASE2) == 0) {
415165971Srwatson				break;
416165971Srwatson			}
417165971Srwatson		}
418165971Srwatson		if (aa == NULL) {
419229621Sjhb			IF_ADDR_RUNLOCK(ifp);
420165971Srwatson			m_freem(m);
421165971Srwatson			return;
422165971Srwatson		}
423194619Srwatson		ifa_ref(&aa->aa_ifa);
424229621Sjhb		IF_ADDR_RUNLOCK(ifp);
425165971Srwatson		tpa.s_net = spa.s_net = AA_SAT(aa)->sat_addr.s_net;
42615885Sjulian	}
427165971Srwatson
428165971Srwatson	spa.s_node = ea->aarp_spnode;
429165971Srwatson	tpa.s_node = ea->aarp_tpnode;
430165971Srwatson	ma.s_net = AA_SAT(aa)->sat_addr.s_net;
431165971Srwatson	ma.s_node = AA_SAT(aa)->sat_addr.s_node;
432165971Srwatson
43315885Sjulian	/*
434165971Srwatson	 * This looks like it's from us.
43515885Sjulian	 */
436165971Srwatson	if (spa.s_net == ma.s_net && spa.s_node == ma.s_node) {
437165971Srwatson		if (aa->aa_flags & AFA_PROBING) {
438165971Srwatson			/*
439165971Srwatson			 * We're probing, someone either responded to our
440165971Srwatson			 * probe, or probed for the same address we'd like to
441165971Srwatson			 * use. Change the address we're probing for.
442165971Srwatson	    		 */
443165971Srwatson			callout_stop(&aa->aa_callout);
444165971Srwatson			wakeup(aa);
445194619Srwatson			ifa_free(&aa->aa_ifa);
446165971Srwatson			m_freem(m);
447165971Srwatson			return;
448165971Srwatson		} else if (op != AARPOP_PROBE) {
449165971Srwatson			/*
450165971Srwatson			 * This is not a probe, and we're not probing.  This
451165971Srwatson			 * means that someone's saying they have the same
452165971Srwatson			 * source address as the one we're using.  Get upset.
453165971Srwatson			 */
454194619Srwatson			ifa_free(&aa->aa_ifa);
455165971Srwatson			log(LOG_ERR,
456165971Srwatson			    "aarp: duplicate AT address!! %x:%x:%x:%x:%x:%x\n",
457165971Srwatson			    ea->aarp_sha[0], ea->aarp_sha[1],
458165971Srwatson			    ea->aarp_sha[2], ea->aarp_sha[3],
459165971Srwatson			    ea->aarp_sha[4], ea->aarp_sha[5]);
460165971Srwatson			m_freem(m);
461165971Srwatson			return;
462165971Srwatson		}
46315885Sjulian	}
46415885Sjulian
465165971Srwatson	AARPTAB_LOCK();
466165971Srwatson	AARPTAB_LOOK(aat, spa);
467165971Srwatson	if (aat != NULL) {
468165971Srwatson		if (op == AARPOP_PROBE) {
469165971Srwatson			/*
470232254Skevlo			 * Someone's probing for spa, deallocate the one we've
471165971Srwatson			 * got, so that if the prober keeps the address,
472165971Srwatson			 * we'll be able to arp for him.
473165971Srwatson			 */
474165971Srwatson			aarptfree(aat);
475165971Srwatson			AARPTAB_UNLOCK();
476194619Srwatson			ifa_free(&aa->aa_ifa);
477165971Srwatson			m_freem(m);
478165971Srwatson			return;
479165971Srwatson		}
48015885Sjulian
481127288Srwatson		bcopy((caddr_t)ea->aarp_sha, (caddr_t)aat->aat_enaddr,
482127288Srwatson		    sizeof(ea->aarp_sha));
483127288Srwatson		aat->aat_flags |= ATF_COM;
484165971Srwatson		if (aat->aat_hold) {
485165971Srwatson			struct mbuf *mhold = aat->aat_hold;
486165971Srwatson			aat->aat_hold = NULL;
487165971Srwatson			AARPTAB_UNLOCK();
488165971Srwatson			sat.sat_len = sizeof(struct sockaddr_at);
489165971Srwatson			sat.sat_family = AF_APPLETALK;
490165971Srwatson			sat.sat_addr = spa;
491165971Srwatson			(*ifp->if_output)(ifp, mhold,
492165971Srwatson			    (struct sockaddr *)&sat, NULL); /* XXX */
493165971Srwatson		} else
494165971Srwatson			AARPTAB_UNLOCK();
495165971Srwatson	} else if ((tpa.s_net == ma.s_net) && (tpa.s_node == ma.s_node)
496165971Srwatson	    && (op != AARPOP_PROBE) && ((aat = aarptnew(&spa)) != NULL)) {
497165971Srwatson		bcopy((caddr_t)ea->aarp_sha, (caddr_t)aat->aat_enaddr,
498165971Srwatson		    sizeof(ea->aarp_sha));
499165971Srwatson		aat->aat_flags |= ATF_COM;
500128042Srwatson	        AARPTAB_UNLOCK();
501165971Srwatson	} else
502165971Srwatson		AARPTAB_UNLOCK();
50315885Sjulian
504165971Srwatson	/*
505165971Srwatson	 * Don't respond to responses, and never respond if we're still
506165971Srwatson	 * probing.
507165971Srwatson	 */
508165971Srwatson	if (tpa.s_net != ma.s_net || tpa.s_node != ma.s_node ||
509127288Srwatson	    op == AARPOP_RESPONSE || (aa->aa_flags & AFA_PROBING)) {
510194619Srwatson		ifa_free(&aa->aa_ifa);
511165971Srwatson		m_freem(m);
512165971Srwatson		return;
513165971Srwatson	}
51415885Sjulian
515165971Srwatson	bcopy((caddr_t)ea->aarp_sha, (caddr_t)ea->aarp_tha,
516127288Srwatson	    sizeof(ea->aarp_sha));
517165971Srwatson	bcopy(IF_LLADDR(ifp), (caddr_t)ea->aarp_sha, sizeof(ea->aarp_sha));
51815885Sjulian
519165971Srwatson	/* XXX */
520165971Srwatson	eh = (struct ether_header *)sa.sa_data;
521165971Srwatson	bcopy((caddr_t)ea->aarp_tha, (caddr_t)eh->ether_dhost,
522127288Srwatson	    sizeof(eh->ether_dhost));
52315885Sjulian
524165971Srwatson	if (aa->aa_flags & AFA_PHASE2) {
525165971Srwatson		eh->ether_type = htons(sizeof(struct llc) +
526165971Srwatson		    sizeof(struct ether_aarp));
527243882Sglebius		M_PREPEND(m, sizeof(struct llc), M_NOWAIT);
528194619Srwatson		if (m == NULL) {
529194619Srwatson			ifa_free(&aa->aa_ifa);
530165971Srwatson			return;
531194619Srwatson		}
532165971Srwatson		llc = mtod(m, struct llc *);
533165971Srwatson		llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP;
534165971Srwatson		llc->llc_control = LLC_UI;
535165971Srwatson		bcopy(aarp_org_code, llc->llc_org_code,
536165971Srwatson		    sizeof(aarp_org_code));
537165971Srwatson		llc->llc_ether_type = htons(ETHERTYPE_AARP);
53815885Sjulian
539165971Srwatson		bcopy(ea->aarp_spnet, ea->aarp_tpnet,
540165971Srwatson		    sizeof(ea->aarp_tpnet));
541165971Srwatson		bcopy(&ma.s_net, ea->aarp_spnet, sizeof(ea->aarp_spnet));
542165971Srwatson	} else
543165971Srwatson		eh->ether_type = htons(ETHERTYPE_AARP);
544194619Srwatson	ifa_free(&aa->aa_ifa);
54515885Sjulian
546165971Srwatson	ea->aarp_tpnode = ea->aarp_spnode;
547165971Srwatson	ea->aarp_spnode = ma.s_node;
548165971Srwatson	ea->aarp_op = htons(AARPOP_RESPONSE);
54915885Sjulian
550165971Srwatson	sa.sa_len = sizeof(struct sockaddr);
551165971Srwatson	sa.sa_family = AF_UNSPEC;
552165971Srwatson	(*ifp->if_output)(ifp, m, &sa, NULL); /* XXX */
553165971Srwatson	return;
55415885Sjulian}
55515885Sjulian
55615885Sjulianstatic void
557127288Srwatsonaarptfree(struct aarptab *aat)
55815885Sjulian{
55915885Sjulian
560165971Srwatson	AARPTAB_LOCK_ASSERT();
561165971Srwatson	if (aat->aat_hold)
562165971Srwatson		m_freem(aat->aat_hold);
563165971Srwatson	aat->aat_hold = NULL;
564165971Srwatson	aat->aat_timer = aat->aat_flags = 0;
565165971Srwatson	aat->aat_ataddr.s_net = 0;
566165971Srwatson	aat->aat_ataddr.s_node = 0;
56715885Sjulian}
56815885Sjulian
569128042Srwatsonstruct aarptab *
570249925Sglebiusaarptnew(const struct at_addr *addr)
57115885Sjulian{
572165971Srwatson	int n;
573165971Srwatson	int oldest = -1;
574165971Srwatson	struct aarptab *aat, *aato = NULL;
575165971Srwatson	static int first = 1;
57615885Sjulian
577165971Srwatson	AARPTAB_LOCK_ASSERT();
578165971Srwatson	if (first) {
579165971Srwatson		first = 0;
580165971Srwatson		aarptimer_ch = timeout(aarptimer, (caddr_t)0, hz);
58115885Sjulian	}
582165971Srwatson	aat = &aarptab[AARPTAB_HASH(*addr) * AARPTAB_BSIZ];
583165971Srwatson	for (n = 0; n < AARPTAB_BSIZ; n++, aat++) {
584165971Srwatson		if (aat->aat_flags == 0)
585165971Srwatson			goto out;
586165971Srwatson		if (aat->aat_flags & ATF_PERM)
587165971Srwatson			continue;
588165971Srwatson		if ((int) aat->aat_timer > oldest) {
589165971Srwatson			oldest = aat->aat_timer;
590165971Srwatson			aato = aat;
591165971Srwatson		}
592165971Srwatson	}
593165971Srwatson	if (aato == NULL)
594165971Srwatson		return (NULL);
595165971Srwatson	aat = aato;
596165971Srwatson	aarptfree(aat);
59715885Sjulianout:
598165971Srwatson	aat->aat_ataddr = *addr;
599165971Srwatson	aat->aat_flags = ATF_INUSE;
600165971Srwatson	return (aat);
60115885Sjulian}
60215885Sjulian
60315885Sjulian
60415885Sjulianvoid
605127288Srwatsonaarpprobe(void *arg)
60615885Sjulian{
607165971Srwatson	struct ifnet *ifp = arg;
608165971Srwatson	struct mbuf *m;
609165971Srwatson	struct ether_header *eh;
610165971Srwatson	struct ether_aarp *ea;
611165971Srwatson	struct at_ifaddr *aa;
612165971Srwatson	struct llc *llc;
613165971Srwatson	struct sockaddr sa;
61415885Sjulian
615165971Srwatson	/*
616165971Srwatson	 * We need to check whether the output ethernet type should be phase
617165971Srwatson	 * 1 or 2.  We have the interface that we'll be sending the aarp out.
618165971Srwatson	 * We need to find an AppleTalk network on that interface with the
619165971Srwatson	 * same address as we're looking for.  If the net is phase 2,
620165971Srwatson	 * generate an 802.2 and SNAP header.
621165971Srwatson	 */
622165971Srwatson	AARPTAB_LOCK();
623165971Srwatson	for (aa = (struct at_ifaddr *)TAILQ_FIRST(&ifp->if_addrhead); aa;
62420407Swollman	    aa = (struct at_ifaddr *)aa->aa_ifa.ifa_link.tqe_next) {
625165971Srwatson		if (AA_SAT(aa)->sat_family == AF_APPLETALK &&
626165971Srwatson		    (aa->aa_flags & AFA_PROBING))
627165971Srwatson			break;
62815885Sjulian	}
629165971Srwatson	if (aa == NULL) {
630165971Srwatson		/* Serious error XXX. */
631165971Srwatson		AARPTAB_UNLOCK();
632165971Srwatson		printf("aarpprobe why did this happen?!\n");
633165971Srwatson		return;
634165971Srwatson	}
63515885Sjulian
636165971Srwatson	if (aa->aa_probcnt <= 0) {
637165971Srwatson		aa->aa_flags &= ~AFA_PROBING;
638165971Srwatson		wakeup(aa);
639165971Srwatson		AARPTAB_UNLOCK();
640165971Srwatson		return;
641165971Srwatson	} else
642165971Srwatson		callout_reset(&aa->aa_callout, hz / 5, aarpprobe, ifp);
643194619Srwatson	ifa_ref(&aa->aa_ifa);
644142226Srwatson	AARPTAB_UNLOCK();
64515885Sjulian
646243882Sglebius	m = m_gethdr(M_NOWAIT, MT_DATA);
647194619Srwatson	if (m == NULL) {
648194619Srwatson		ifa_free(&aa->aa_ifa);
649165971Srwatson		return;
650194619Srwatson	}
651101937Srwatson#ifdef MAC
652173095Srwatson	mac_netatalk_aarp_send(ifp, m);
653101937Srwatson#endif
654165971Srwatson	m->m_len = sizeof(*ea);
655165971Srwatson	m->m_pkthdr.len = sizeof(*ea);
656165971Srwatson	MH_ALIGN(m, sizeof(*ea));
65715885Sjulian
658165971Srwatson	ea = mtod(m, struct ether_aarp *);
659165971Srwatson	bzero((caddr_t)ea, sizeof(*ea));
66015885Sjulian
661165971Srwatson	ea->aarp_hrd = htons(AARPHRD_ETHER);
662165971Srwatson	ea->aarp_pro = htons(ETHERTYPE_AT);
663165971Srwatson	ea->aarp_hln = sizeof(ea->aarp_sha);
664165971Srwatson	ea->aarp_pln = sizeof(ea->aarp_spu);
665165971Srwatson	ea->aarp_op = htons(AARPOP_PROBE);
666165971Srwatson	bcopy(IF_LLADDR(ifp), (caddr_t)ea->aarp_sha,
667127288Srwatson	    sizeof(ea->aarp_sha));
66815885Sjulian
669165971Srwatson	eh = (struct ether_header *)sa.sa_data;
67015885Sjulian
671165971Srwatson	if (aa->aa_flags & AFA_PHASE2) {
672165971Srwatson		bcopy(atmulticastaddr, eh->ether_dhost,
673165971Srwatson		    sizeof(eh->ether_dhost));
674165971Srwatson		eh->ether_type = htons(sizeof(struct llc) +
675165971Srwatson		    sizeof(struct ether_aarp));
676243882Sglebius		M_PREPEND(m, sizeof(struct llc), M_WAITOK);
677165971Srwatson		llc = mtod(m, struct llc *);
678165971Srwatson		llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP;
679165971Srwatson		llc->llc_control = LLC_UI;
680165971Srwatson		bcopy(aarp_org_code, llc->llc_org_code,
681165971Srwatson		    sizeof(aarp_org_code));
682165971Srwatson		llc->llc_ether_type = htons(ETHERTYPE_AARP);
683165971Srwatson
684165971Srwatson		bcopy(&AA_SAT(aa)->sat_addr.s_net, ea->aarp_spnet,
685165971Srwatson		    sizeof(ea->aarp_spnet));
686165971Srwatson		bcopy(&AA_SAT(aa)->sat_addr.s_net, ea->aarp_tpnet,
687165971Srwatson		    sizeof(ea->aarp_tpnet));
688165971Srwatson		ea->aarp_spnode = ea->aarp_tpnode =
689165971Srwatson		    AA_SAT(aa)->sat_addr.s_node;
690165971Srwatson	} else {
691165971Srwatson		bcopy(ifp->if_broadcastaddr, (caddr_t)eh->ether_dhost,
692165971Srwatson		    sizeof(eh->ether_dhost));
693165971Srwatson		eh->ether_type = htons(ETHERTYPE_AARP);
694165971Srwatson		ea->aarp_spa = ea->aarp_tpa = AA_SAT(aa)->sat_addr.s_node;
695119561Srwatson	}
69615885Sjulian
69715885Sjulian#ifdef NETATALKDEBUG
698165971Srwatson	printf("aarp: sending probe for %u.%u\n",
699165971Srwatson	    ntohs(AA_SAT(aa)->sat_addr.s_net), AA_SAT(aa)->sat_addr.s_node);
70032929Seivind#endif /* NETATALKDEBUG */
701194619Srwatson	ifa_free(&aa->aa_ifa);
70215885Sjulian
703165971Srwatson	sa.sa_len = sizeof(struct sockaddr);
704165971Srwatson	sa.sa_family = AF_UNSPEC;
705165971Srwatson	(*ifp->if_output)(ifp, m, &sa, NULL); /* XXX */
706165971Srwatson	aa->aa_probcnt--;
70715885Sjulian}
70815885Sjulian
70915885Sjulianvoid
71015885Sjulianaarp_clean(void)
71115885Sjulian{
712165971Srwatson	struct aarptab *aat;
713165971Srwatson	int i;
71415885Sjulian
715165971Srwatson	untimeout(aarptimer, 0, aarptimer_ch);
716165971Srwatson	AARPTAB_LOCK();
717165971Srwatson	for (i = 0, aat = aarptab; i < AARPTAB_SIZE; i++, aat++) {
718165971Srwatson		if (aat->aat_hold) {
719165971Srwatson			m_freem(aat->aat_hold);
720165971Srwatson			aat->aat_hold = NULL;
721165971Srwatson		}
72215885Sjulian	}
723165971Srwatson	AARPTAB_UNLOCK();
72415885Sjulian}
725