]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - sys/netatalk/aarp.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / sys / netatalk / aarp.c
1 /*-
2  * Copyright (c) 2004-2009 Robert N. M. Watson
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * Copyright (c) 1990,1991,1994 Regents of The University of Michigan.
27  * All Rights Reserved.
28  *
29  * Permission to use, copy, modify, and distribute this software and
30  * its documentation for any purpose and without fee is hereby granted,
31  * provided that the above copyright notice appears in all copies and
32  * that both that copyright notice and this permission notice appear
33  * in supporting documentation, and that the name of The University
34  * of Michigan not be used in advertising or publicity pertaining to
35  * distribution of the software without specific, written prior
36  * permission. This software is supplied as is without expressed or
37  * implied warranties of any kind.
38  *
39  * This product includes software developed by the University of
40  * California, Berkeley and its contributors.
41  *
42  *      Research Systems Unix Group
43  *      The University of Michigan
44  *      c/o Wesley Craig
45  *      535 W. William Street
46  *      Ann Arbor, Michigan
47  *      +1-313-764-2278
48  *      netatalk@umich.edu
49  *
50  * $FreeBSD$
51  */
52
53 #include "opt_atalk.h"
54
55 #include <sys/param.h>
56 #include <sys/systm.h>
57 #include <sys/mbuf.h>
58 #include <sys/kernel.h>
59 #include <sys/socket.h>
60 #include <sys/syslog.h>
61
62 #include <net/if.h>
63 #include <net/if_dl.h>
64
65 #include <netinet/in.h>
66 #undef s_net
67 #include <netinet/if_ether.h>
68
69 #include <netatalk/at.h>
70 #include <netatalk/at_var.h>
71 #include <netatalk/aarp.h>
72 #include <netatalk/phase2.h>
73 #include <netatalk/at_extern.h>
74
75 #include <security/mac/mac_framework.h>
76
77 static void     aarptfree(struct aarptab *aat);
78 static void     at_aarpinput(struct ifnet *ifp, struct mbuf *m);
79
80 #define AARPTAB_BSIZ    9
81 #define AARPTAB_NB      19
82 #define AARPTAB_SIZE    (AARPTAB_BSIZ * AARPTAB_NB)
83 static struct aarptab   aarptab[AARPTAB_SIZE];
84
85 struct mtx      aarptab_mtx;
86 MTX_SYSINIT(aarptab_mtx, &aarptab_mtx, "aarptab_mtx", MTX_DEF);
87
88 #define AARPTAB_HASH(a) ((((a).s_net << 8) + (a).s_node) % AARPTAB_NB)
89
90 #define AARPTAB_LOOK(aat, addr) do {                                    \
91         int n;                                                          \
92                                                                         \
93         AARPTAB_LOCK_ASSERT();                                          \
94         aat = &aarptab[ AARPTAB_HASH(addr) * AARPTAB_BSIZ ];            \
95         for (n = 0; n < AARPTAB_BSIZ; n++, aat++) {                     \
96                 if (aat->aat_ataddr.s_net == (addr).s_net &&            \
97                     aat->aat_ataddr.s_node == (addr).s_node)            \
98                         break;                                          \
99         }                                                               \
100         if (n >= AARPTAB_BSIZ)                                          \
101                 aat = NULL;                                             \
102 } while (0)
103
104 #define AARPT_AGE       (60 * 1)
105 #define AARPT_KILLC     20
106 #define AARPT_KILLI     3
107
108 static const u_char     atmulticastaddr[6] = {
109         0x09, 0x00, 0x07, 0xff, 0xff, 0xff,
110 };
111
112 u_char  at_org_code[3] = {
113         0x08, 0x00, 0x07,
114 };
115 const u_char    aarp_org_code[3] = {
116         0x00, 0x00, 0x00,
117 };
118
119 static struct callout_handle    aarptimer_ch =
120     CALLOUT_HANDLE_INITIALIZER(&aarptimer_ch);
121
122 static void
123 aarptimer(void *ignored)
124 {
125         struct aarptab *aat;
126         int i;
127
128         aarptimer_ch = timeout(aarptimer, NULL, AARPT_AGE * hz);
129         aat = aarptab;
130         AARPTAB_LOCK();
131         for (i = 0; i < AARPTAB_SIZE; i++, aat++) {
132                 if (aat->aat_flags == 0 || (aat->aat_flags & ATF_PERM))
133                         continue;
134                 if (++aat->aat_timer < ((aat->aat_flags & ATF_COM) ?
135                     AARPT_KILLC : AARPT_KILLI))
136                         continue;
137                 aarptfree(aat);
138         }
139         AARPTAB_UNLOCK();
140 }
141
142 /* 
143  * Search through the network addresses to find one that includes the given
144  * network.  Remember to take netranges into consideration.
145  *
146  * The _locked variant relies on the caller holding the at_ifaddr lock; the
147  * unlocked variant returns a reference that the caller must dispose of.
148  */
149 struct at_ifaddr *
150 at_ifawithnet_locked(const struct sockaddr_at  *sat)
151 {
152         struct at_ifaddr *aa;
153         struct sockaddr_at *sat2;
154
155         AT_IFADDR_LOCK_ASSERT();
156
157         TAILQ_FOREACH(aa, &at_ifaddrhead, aa_link) {
158                 sat2 = &(aa->aa_addr);
159                 if (sat2->sat_addr.s_net == sat->sat_addr.s_net)
160                         break;
161                 if ((aa->aa_flags & AFA_PHASE2) &&
162                     (ntohs(aa->aa_firstnet) <= ntohs(sat->sat_addr.s_net)) &&
163                     (ntohs(aa->aa_lastnet) >= ntohs(sat->sat_addr.s_net)))
164                         break;
165         }
166         return (aa);
167 }
168
169 struct at_ifaddr *
170 at_ifawithnet(const struct sockaddr_at *sat)
171 {
172         struct at_ifaddr *aa;
173
174         AT_IFADDR_RLOCK();
175         aa = at_ifawithnet_locked(sat);
176         if (aa != NULL)
177                 ifa_ref(&aa->aa_ifa);
178         AT_IFADDR_RUNLOCK();
179         return (aa);
180 }
181
182 static void
183 aarpwhohas(struct ifnet *ifp, const struct sockaddr_at *sat)
184 {
185         struct mbuf *m;
186         struct ether_header *eh;
187         struct ether_aarp *ea;
188         struct at_ifaddr *aa;
189         struct llc *llc;
190         struct sockaddr sa;
191
192         AARPTAB_UNLOCK_ASSERT();
193         m = m_gethdr(M_NOWAIT, MT_DATA);
194         if (m == NULL)
195                 return;
196 #ifdef MAC
197         mac_netatalk_aarp_send(ifp, m);
198 #endif
199         m->m_len = sizeof(*ea);
200         m->m_pkthdr.len = sizeof(*ea);
201         MH_ALIGN(m, sizeof(*ea));
202
203         ea = mtod(m, struct ether_aarp *);
204         bzero((caddr_t)ea, sizeof(*ea));
205
206         ea->aarp_hrd = htons(AARPHRD_ETHER);
207         ea->aarp_pro = htons(ETHERTYPE_AT);
208         ea->aarp_hln = sizeof(ea->aarp_sha);
209         ea->aarp_pln = sizeof(ea->aarp_spu);
210         ea->aarp_op = htons(AARPOP_REQUEST);
211         bcopy(IF_LLADDR(ifp), (caddr_t)ea->aarp_sha, sizeof(ea->aarp_sha));
212
213         /*
214          * We need to check whether the output ethernet type should be phase
215          * 1 or 2.  We have the interface that we'll be sending the aarp out.
216          * We need to find an AppleTalk network on that interface with the
217          * same address as we're looking for.  If the net is phase 2,
218          * generate an 802.2 and SNAP header.
219          */
220         aa = at_ifawithnet(sat);
221         if (aa == NULL) {
222                 m_freem(m);
223                 return;
224         }
225
226         eh = (struct ether_header *)sa.sa_data;
227
228         if (aa->aa_flags & AFA_PHASE2) {
229                 bcopy(atmulticastaddr, eh->ether_dhost,
230                     sizeof(eh->ether_dhost));
231                 eh->ether_type = htons(sizeof(struct llc) +
232                     sizeof(struct ether_aarp));
233                 M_PREPEND(m, sizeof(struct llc), M_NOWAIT);
234                 if (m == NULL) {
235                         ifa_free(&aa->aa_ifa);
236                         return;
237                 }
238                 llc = mtod(m, struct llc *);
239                 llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP;
240                 llc->llc_control = LLC_UI;
241                 bcopy(aarp_org_code, llc->llc_org_code,
242                     sizeof(aarp_org_code));
243                 llc->llc_ether_type = htons(ETHERTYPE_AARP);
244                 bcopy(&AA_SAT(aa)->sat_addr.s_net, ea->aarp_spnet,
245                     sizeof(ea->aarp_spnet));
246                 bcopy(&sat->sat_addr.s_net, ea->aarp_tpnet,
247                     sizeof(ea->aarp_tpnet));
248                 ea->aarp_spnode = AA_SAT(aa)->sat_addr.s_node;
249                 ea->aarp_tpnode = sat->sat_addr.s_node;
250         } else {
251                 bcopy(ifp->if_broadcastaddr, (caddr_t)eh->ether_dhost,
252                     sizeof(eh->ether_dhost));
253                 eh->ether_type = htons(ETHERTYPE_AARP);
254                 ea->aarp_spa = AA_SAT(aa)->sat_addr.s_node;
255                 ea->aarp_tpa = sat->sat_addr.s_node;
256         }
257
258 #ifdef NETATALKDEBUG
259         printf("aarp: sending request for %u.%u\n",
260             ntohs(AA_SAT(aa)->sat_addr.s_net), AA_SAT(aa)->sat_addr.s_node);
261 #endif /* NETATALKDEBUG */
262         ifa_free(&aa->aa_ifa);
263
264         sa.sa_len = sizeof(struct sockaddr);
265         sa.sa_family = AF_UNSPEC;
266         ifp->if_output(ifp, m, &sa, NULL);
267 }
268
269 int
270 aarpresolve(struct ifnet *ifp, struct mbuf *m,
271     const struct sockaddr_at *destsat, u_char *desten)
272 {
273         struct at_ifaddr *aa;
274         struct aarptab *aat;
275
276         AT_IFADDR_RLOCK();
277         if (at_broadcast(destsat)) {
278                 m->m_flags |= M_BCAST;
279                 if ((aa = at_ifawithnet_locked(destsat)) == NULL)  {
280                         AT_IFADDR_RUNLOCK();
281                         m_freem(m);
282                         return (0);
283                 }
284                 if (aa->aa_flags & AFA_PHASE2)
285                         bcopy(atmulticastaddr, (caddr_t)desten,
286                             sizeof(atmulticastaddr));
287                 else
288                         bcopy(ifp->if_broadcastaddr, (caddr_t)desten,
289                             sizeof(ifp->if_addrlen));
290                 AT_IFADDR_RUNLOCK();
291                 return (1);
292         }
293         AT_IFADDR_RUNLOCK();
294
295         AARPTAB_LOCK();
296         AARPTAB_LOOK(aat, destsat->sat_addr);
297         if (aat == NULL) {
298                 /* No entry. */
299                 aat = aarptnew(&destsat->sat_addr);
300
301                 /* We should fail more gracefully. */
302                 if (aat == NULL)
303                         panic("aarpresolve: no free entry");
304                 goto done;
305         }
306
307         /* Found an entry. */
308         aat->aat_timer = 0;
309         if (aat->aat_flags & ATF_COM) {
310                 /* Entry is COMplete. */
311                 bcopy((caddr_t)aat->aat_enaddr, (caddr_t)desten,
312                     sizeof(aat->aat_enaddr));
313                 AARPTAB_UNLOCK();
314                 return (1);
315         }
316
317         /* Entry has not completed. */
318         if (aat->aat_hold)
319                 m_freem(aat->aat_hold);
320 done:
321         aat->aat_hold = m;
322         AARPTAB_UNLOCK();
323         aarpwhohas(ifp, destsat);
324         return (0);
325 }
326
327 void
328 aarpintr(struct mbuf *m)
329 {
330         struct arphdr *ar;
331         struct ifnet *ifp;
332
333         ifp = m->m_pkthdr.rcvif;
334         if (ifp->if_flags & IFF_NOARP)
335                 goto out;
336
337         if (m->m_len < sizeof(struct arphdr))
338                 goto out;
339
340         ar = mtod(m, struct arphdr *);
341         if (ntohs(ar->ar_hrd) != AARPHRD_ETHER)
342                 goto out;
343         
344         if (m->m_len < sizeof(struct arphdr) + 2 * ar->ar_hln +
345             2 * ar->ar_pln)
346                 goto out;
347         
348         switch(ntohs(ar->ar_pro)) {
349         case ETHERTYPE_AT:
350                 at_aarpinput(ifp, m);
351                 return;
352         default:
353                 break;
354         }
355
356 out:
357         m_freem(m);
358 }
359
360 static void
361 at_aarpinput(struct ifnet *ifp, struct mbuf *m)
362 {
363         struct ether_aarp *ea;
364         struct at_ifaddr *aa;
365         struct aarptab *aat;
366         struct ether_header *eh;
367         struct llc *llc;
368         struct sockaddr_at sat;
369         struct sockaddr sa;
370         struct at_addr spa, tpa, ma;
371         int op;
372         u_short net;
373
374         ea = mtod(m, struct ether_aarp *);
375
376         /* Check to see if from my hardware address. */
377         if (!bcmp((caddr_t)ea->aarp_sha, IF_LLADDR(ifp), ETHER_ADDR_LEN)) {
378                 m_freem(m);
379                 return;
380         }
381
382         /* Don't accept requests from broadcast address. */
383         if (!bcmp(ea->aarp_sha, ifp->if_broadcastaddr, ifp->if_addrlen)) {
384                 log(LOG_ERR, "aarp: source link address is broadcast\n");
385                 m_freem(m);
386                 return;
387         }
388
389         op = ntohs(ea->aarp_op);
390         bcopy(ea->aarp_tpnet, &net, sizeof(net));
391
392         if (net != 0) {
393                 /* Should be ATADDR_ANYNET? */
394                 sat.sat_len = sizeof(struct sockaddr_at);
395                 sat.sat_family = AF_APPLETALK;
396                 sat.sat_addr.s_net = net;
397                 aa = at_ifawithnet(&sat);
398                 if (aa == NULL) {
399                         m_freem(m);
400                         return;
401                 }
402                 bcopy(ea->aarp_spnet, &spa.s_net, sizeof(spa.s_net));
403                 bcopy(ea->aarp_tpnet, &tpa.s_net, sizeof(tpa.s_net));
404         } else {
405                 /*
406                  * Since we don't know the net, we just look for the first
407                  * phase 1 address on the interface.
408                  */
409                 IF_ADDR_RLOCK(ifp);
410                 for (aa = (struct at_ifaddr *)TAILQ_FIRST(&ifp->if_addrhead);
411                     aa;
412                     aa = (struct at_ifaddr *)aa->aa_ifa.ifa_link.tqe_next) {
413                         if (AA_SAT(aa)->sat_family == AF_APPLETALK &&
414                             (aa->aa_flags & AFA_PHASE2) == 0) {
415                                 break;
416                         }
417                 }
418                 if (aa == NULL) {
419                         IF_ADDR_RUNLOCK(ifp);
420                         m_freem(m);
421                         return;
422                 }
423                 ifa_ref(&aa->aa_ifa);
424                 IF_ADDR_RUNLOCK(ifp);
425                 tpa.s_net = spa.s_net = AA_SAT(aa)->sat_addr.s_net;
426         }
427
428         spa.s_node = ea->aarp_spnode;
429         tpa.s_node = ea->aarp_tpnode;
430         ma.s_net = AA_SAT(aa)->sat_addr.s_net;
431         ma.s_node = AA_SAT(aa)->sat_addr.s_node;
432
433         /*
434          * This looks like it's from us.
435          */
436         if (spa.s_net == ma.s_net && spa.s_node == ma.s_node) {
437                 if (aa->aa_flags & AFA_PROBING) {
438                         /*
439                          * We're probing, someone either responded to our
440                          * probe, or probed for the same address we'd like to
441                          * use. Change the address we're probing for.
442                          */
443                         callout_stop(&aa->aa_callout);
444                         wakeup(aa);
445                         ifa_free(&aa->aa_ifa);
446                         m_freem(m);
447                         return;
448                 } else if (op != AARPOP_PROBE) {
449                         /*
450                          * This is not a probe, and we're not probing.  This
451                          * means that someone's saying they have the same
452                          * source address as the one we're using.  Get upset.
453                          */
454                         ifa_free(&aa->aa_ifa);
455                         log(LOG_ERR,
456                             "aarp: duplicate AT address!! %x:%x:%x:%x:%x:%x\n",
457                             ea->aarp_sha[0], ea->aarp_sha[1],
458                             ea->aarp_sha[2], ea->aarp_sha[3],
459                             ea->aarp_sha[4], ea->aarp_sha[5]);
460                         m_freem(m);
461                         return;
462                 }
463         }
464
465         AARPTAB_LOCK();
466         AARPTAB_LOOK(aat, spa);
467         if (aat != NULL) {
468                 if (op == AARPOP_PROBE) {
469                         /*
470                          * Someone's probing for spa, deallocate the one we've
471                          * got, so that if the prober keeps the address,
472                          * we'll be able to arp for him.
473                          */
474                         aarptfree(aat);
475                         AARPTAB_UNLOCK();
476                         ifa_free(&aa->aa_ifa);
477                         m_freem(m);
478                         return;
479                 }
480
481                 bcopy((caddr_t)ea->aarp_sha, (caddr_t)aat->aat_enaddr,
482                     sizeof(ea->aarp_sha));
483                 aat->aat_flags |= ATF_COM;
484                 if (aat->aat_hold) {
485                         struct mbuf *mhold = aat->aat_hold;
486                         aat->aat_hold = NULL;
487                         AARPTAB_UNLOCK();
488                         sat.sat_len = sizeof(struct sockaddr_at);
489                         sat.sat_family = AF_APPLETALK;
490                         sat.sat_addr = spa;
491                         (*ifp->if_output)(ifp, mhold,
492                             (struct sockaddr *)&sat, NULL); /* XXX */
493                 } else
494                         AARPTAB_UNLOCK();
495         } else if ((tpa.s_net == ma.s_net) && (tpa.s_node == ma.s_node)
496             && (op != AARPOP_PROBE) && ((aat = aarptnew(&spa)) != NULL)) {
497                 bcopy((caddr_t)ea->aarp_sha, (caddr_t)aat->aat_enaddr,
498                     sizeof(ea->aarp_sha));
499                 aat->aat_flags |= ATF_COM;
500                 AARPTAB_UNLOCK();
501         } else
502                 AARPTAB_UNLOCK();
503
504         /*
505          * Don't respond to responses, and never respond if we're still
506          * probing.
507          */
508         if (tpa.s_net != ma.s_net || tpa.s_node != ma.s_node ||
509             op == AARPOP_RESPONSE || (aa->aa_flags & AFA_PROBING)) {
510                 ifa_free(&aa->aa_ifa);
511                 m_freem(m);
512                 return;
513         }
514
515         bcopy((caddr_t)ea->aarp_sha, (caddr_t)ea->aarp_tha,
516             sizeof(ea->aarp_sha));
517         bcopy(IF_LLADDR(ifp), (caddr_t)ea->aarp_sha, sizeof(ea->aarp_sha));
518
519         /* XXX */
520         eh = (struct ether_header *)sa.sa_data;
521         bcopy((caddr_t)ea->aarp_tha, (caddr_t)eh->ether_dhost,
522             sizeof(eh->ether_dhost));
523
524         if (aa->aa_flags & AFA_PHASE2) {
525                 eh->ether_type = htons(sizeof(struct llc) +
526                     sizeof(struct ether_aarp));
527                 M_PREPEND(m, sizeof(struct llc), M_NOWAIT);
528                 if (m == NULL) {
529                         ifa_free(&aa->aa_ifa);
530                         return;
531                 }
532                 llc = mtod(m, struct llc *);
533                 llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP;
534                 llc->llc_control = LLC_UI;
535                 bcopy(aarp_org_code, llc->llc_org_code,
536                     sizeof(aarp_org_code));
537                 llc->llc_ether_type = htons(ETHERTYPE_AARP);
538
539                 bcopy(ea->aarp_spnet, ea->aarp_tpnet,
540                     sizeof(ea->aarp_tpnet));
541                 bcopy(&ma.s_net, ea->aarp_spnet, sizeof(ea->aarp_spnet));
542         } else
543                 eh->ether_type = htons(ETHERTYPE_AARP);
544         ifa_free(&aa->aa_ifa);
545
546         ea->aarp_tpnode = ea->aarp_spnode;
547         ea->aarp_spnode = ma.s_node;
548         ea->aarp_op = htons(AARPOP_RESPONSE);
549
550         sa.sa_len = sizeof(struct sockaddr);
551         sa.sa_family = AF_UNSPEC;
552         (*ifp->if_output)(ifp, m, &sa, NULL); /* XXX */
553         return;
554 }
555
556 static void
557 aarptfree(struct aarptab *aat)
558 {
559
560         AARPTAB_LOCK_ASSERT();
561         if (aat->aat_hold)
562                 m_freem(aat->aat_hold);
563         aat->aat_hold = NULL;
564         aat->aat_timer = aat->aat_flags = 0;
565         aat->aat_ataddr.s_net = 0;
566         aat->aat_ataddr.s_node = 0;
567 }
568
569 struct aarptab *
570 aarptnew(const struct at_addr *addr)
571 {
572         int n;
573         int oldest = -1;
574         struct aarptab *aat, *aato = NULL;
575         static int first = 1;
576
577         AARPTAB_LOCK_ASSERT();
578         if (first) {
579                 first = 0;
580                 aarptimer_ch = timeout(aarptimer, (caddr_t)0, hz);
581         }
582         aat = &aarptab[AARPTAB_HASH(*addr) * AARPTAB_BSIZ];
583         for (n = 0; n < AARPTAB_BSIZ; n++, aat++) {
584                 if (aat->aat_flags == 0)
585                         goto out;
586                 if (aat->aat_flags & ATF_PERM)
587                         continue;
588                 if ((int) aat->aat_timer > oldest) {
589                         oldest = aat->aat_timer;
590                         aato = aat;
591                 }
592         }
593         if (aato == NULL)
594                 return (NULL);
595         aat = aato;
596         aarptfree(aat);
597 out:
598         aat->aat_ataddr = *addr;
599         aat->aat_flags = ATF_INUSE;
600         return (aat);
601 }
602
603
604 void
605 aarpprobe(void *arg)
606 {
607         struct ifnet *ifp = arg;
608         struct mbuf *m;
609         struct ether_header *eh;
610         struct ether_aarp *ea;
611         struct at_ifaddr *aa;
612         struct llc *llc;
613         struct sockaddr sa;
614
615         /*
616          * We need to check whether the output ethernet type should be phase
617          * 1 or 2.  We have the interface that we'll be sending the aarp out.
618          * We need to find an AppleTalk network on that interface with the
619          * same address as we're looking for.  If the net is phase 2,
620          * generate an 802.2 and SNAP header.
621          */
622         AARPTAB_LOCK();
623         for (aa = (struct at_ifaddr *)TAILQ_FIRST(&ifp->if_addrhead); aa;
624             aa = (struct at_ifaddr *)aa->aa_ifa.ifa_link.tqe_next) {
625                 if (AA_SAT(aa)->sat_family == AF_APPLETALK &&
626                     (aa->aa_flags & AFA_PROBING))
627                         break;
628         }
629         if (aa == NULL) {
630                 /* Serious error XXX. */
631                 AARPTAB_UNLOCK();
632                 printf("aarpprobe why did this happen?!\n");
633                 return;
634         }
635
636         if (aa->aa_probcnt <= 0) {
637                 aa->aa_flags &= ~AFA_PROBING;
638                 wakeup(aa);
639                 AARPTAB_UNLOCK();
640                 return;
641         } else
642                 callout_reset(&aa->aa_callout, hz / 5, aarpprobe, ifp);
643         ifa_ref(&aa->aa_ifa);
644         AARPTAB_UNLOCK();
645
646         m = m_gethdr(M_NOWAIT, MT_DATA);
647         if (m == NULL) {
648                 ifa_free(&aa->aa_ifa);
649                 return;
650         }
651 #ifdef MAC
652         mac_netatalk_aarp_send(ifp, m);
653 #endif
654         m->m_len = sizeof(*ea);
655         m->m_pkthdr.len = sizeof(*ea);
656         MH_ALIGN(m, sizeof(*ea));
657
658         ea = mtod(m, struct ether_aarp *);
659         bzero((caddr_t)ea, sizeof(*ea));
660
661         ea->aarp_hrd = htons(AARPHRD_ETHER);
662         ea->aarp_pro = htons(ETHERTYPE_AT);
663         ea->aarp_hln = sizeof(ea->aarp_sha);
664         ea->aarp_pln = sizeof(ea->aarp_spu);
665         ea->aarp_op = htons(AARPOP_PROBE);
666         bcopy(IF_LLADDR(ifp), (caddr_t)ea->aarp_sha,
667             sizeof(ea->aarp_sha));
668
669         eh = (struct ether_header *)sa.sa_data;
670
671         if (aa->aa_flags & AFA_PHASE2) {
672                 bcopy(atmulticastaddr, eh->ether_dhost,
673                     sizeof(eh->ether_dhost));
674                 eh->ether_type = htons(sizeof(struct llc) +
675                     sizeof(struct ether_aarp));
676                 M_PREPEND(m, sizeof(struct llc), M_WAITOK);
677                 llc = mtod(m, struct llc *);
678                 llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP;
679                 llc->llc_control = LLC_UI;
680                 bcopy(aarp_org_code, llc->llc_org_code,
681                     sizeof(aarp_org_code));
682                 llc->llc_ether_type = htons(ETHERTYPE_AARP);
683
684                 bcopy(&AA_SAT(aa)->sat_addr.s_net, ea->aarp_spnet,
685                     sizeof(ea->aarp_spnet));
686                 bcopy(&AA_SAT(aa)->sat_addr.s_net, ea->aarp_tpnet,
687                     sizeof(ea->aarp_tpnet));
688                 ea->aarp_spnode = ea->aarp_tpnode =
689                     AA_SAT(aa)->sat_addr.s_node;
690         } else {
691                 bcopy(ifp->if_broadcastaddr, (caddr_t)eh->ether_dhost,
692                     sizeof(eh->ether_dhost));
693                 eh->ether_type = htons(ETHERTYPE_AARP);
694                 ea->aarp_spa = ea->aarp_tpa = AA_SAT(aa)->sat_addr.s_node;
695         }
696
697 #ifdef NETATALKDEBUG
698         printf("aarp: sending probe for %u.%u\n",
699             ntohs(AA_SAT(aa)->sat_addr.s_net), AA_SAT(aa)->sat_addr.s_node);
700 #endif /* NETATALKDEBUG */
701         ifa_free(&aa->aa_ifa);
702
703         sa.sa_len = sizeof(struct sockaddr);
704         sa.sa_family = AF_UNSPEC;
705         (*ifp->if_output)(ifp, m, &sa, NULL); /* XXX */
706         aa->aa_probcnt--;
707 }
708
709 void
710 aarp_clean(void)
711 {
712         struct aarptab *aat;
713         int i;
714
715         untimeout(aarptimer, 0, aarptimer_ch);
716         AARPTAB_LOCK();
717         for (i = 0, aat = aarptab; i < AARPTAB_SIZE; i++, aat++) {
718                 if (aat->aat_hold) {
719                         m_freem(aat->aat_hold);
720                         aat->aat_hold = NULL;
721                 }
722         }
723         AARPTAB_UNLOCK();
724 }