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