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