aarp.c revision 1.2 1 1.2 christos /* $NetBSD: aarp.c,v 1.2 1997/04/03 18:38:21 christos Exp $ */
2 1.1 christos
3 1.1 christos /*
4 1.1 christos * Copyright (c) 1990,1991 Regents of The University of Michigan.
5 1.1 christos * All Rights Reserved.
6 1.1 christos *
7 1.1 christos * Permission to use, copy, modify, and distribute this software and
8 1.1 christos * its documentation for any purpose and without fee is hereby granted,
9 1.1 christos * provided that the above copyright notice appears in all copies and
10 1.1 christos * that both that copyright notice and this permission notice appear
11 1.1 christos * in supporting documentation, and that the name of The University
12 1.1 christos * of Michigan not be used in advertising or publicity pertaining to
13 1.1 christos * distribution of the software without specific, written prior
14 1.1 christos * permission. This software is supplied as is without expressed or
15 1.1 christos * implied warranties of any kind.
16 1.1 christos *
17 1.1 christos * This product includes software developed by the University of
18 1.1 christos * California, Berkeley and its contributors.
19 1.1 christos *
20 1.1 christos * Research Systems Unix Group
21 1.1 christos * The University of Michigan
22 1.1 christos * c/o Wesley Craig
23 1.1 christos * 535 W. William Street
24 1.1 christos * Ann Arbor, Michigan
25 1.1 christos * +1-313-764-2278
26 1.1 christos * netatalk (at) umich.edu
27 1.1 christos */
28 1.1 christos
29 1.1 christos #include <sys/types.h>
30 1.1 christos #include <sys/cdefs.h>
31 1.1 christos #include <sys/socket.h>
32 1.1 christos #include <sys/syslog.h>
33 1.1 christos #include <sys/param.h>
34 1.1 christos #include <sys/systm.h>
35 1.1 christos #include <sys/proc.h>
36 1.1 christos #include <sys/mbuf.h>
37 1.1 christos #include <sys/time.h>
38 1.1 christos #include <sys/kernel.h>
39 1.1 christos #include <net/if.h>
40 1.1 christos #include <net/route.h>
41 1.1 christos #include <net/if_ether.h>
42 1.1 christos #include <net/if_dl.h>
43 1.1 christos #include <netinet/in.h>
44 1.1 christos #undef s_net
45 1.1 christos
46 1.1 christos #include <netatalk/at.h>
47 1.1 christos #include <netatalk/at_var.h>
48 1.1 christos #include <netatalk/aarp.h>
49 1.1 christos #include <netatalk/ddp_var.h>
50 1.1 christos #include <netatalk/phase2.h>
51 1.1 christos #include <netatalk/at_extern.h>
52 1.1 christos
53 1.1 christos static struct aarptab *aarptnew __P((struct at_addr *));
54 1.1 christos static void aarptfree __P((struct aarptab *));
55 1.1 christos static void at_aarpinput __P((struct ifnet *, struct mbuf *));
56 1.1 christos static void aarptimer __P((void *));
57 1.1 christos static void aarpwhohas __P((struct ifnet *, struct sockaddr_at *));
58 1.1 christos
59 1.1 christos #define AARPTAB_BSIZ 9
60 1.1 christos #define AARPTAB_NB 19
61 1.1 christos #define AARPTAB_SIZE (AARPTAB_BSIZ * AARPTAB_NB)
62 1.1 christos struct aarptab aarptab[AARPTAB_SIZE];
63 1.1 christos int aarptab_size = AARPTAB_SIZE;
64 1.1 christos
65 1.1 christos #define AARPTAB_HASH(a) \
66 1.1 christos ((((a).s_net << 8 ) + (a).s_node ) % AARPTAB_NB )
67 1.1 christos
68 1.1 christos #define AARPTAB_LOOK(aat,addr) { \
69 1.1 christos int n; \
70 1.1 christos aat = &aarptab[ AARPTAB_HASH(addr) * AARPTAB_BSIZ ]; \
71 1.1 christos for ( n = 0; n < AARPTAB_BSIZ; n++, aat++ ) \
72 1.1 christos if ( aat->aat_ataddr.s_net == (addr).s_net && \
73 1.1 christos aat->aat_ataddr.s_node == (addr).s_node ) \
74 1.1 christos break; \
75 1.1 christos if ( n >= AARPTAB_BSIZ ) \
76 1.1 christos aat = 0; \
77 1.1 christos }
78 1.1 christos
79 1.1 christos #define AARPT_AGE (60 * 1)
80 1.1 christos #define AARPT_KILLC 20
81 1.1 christos #define AARPT_KILLI 3
82 1.1 christos
83 1.1 christos #if !defined( __FreeBSD__ )
84 1.1 christos extern u_char etherbroadcastaddr[6];
85 1.1 christos #endif /* __FreeBSD__ */
86 1.1 christos
87 1.1 christos u_char atmulticastaddr[6] = {
88 1.1 christos 0x09, 0x00, 0x07, 0xff, 0xff, 0xff
89 1.1 christos };
90 1.1 christos
91 1.1 christos u_char at_org_code[3] = {
92 1.1 christos 0x08, 0x00, 0x07
93 1.1 christos };
94 1.1 christos u_char aarp_org_code[3] = {
95 1.1 christos 0x00, 0x00, 0x00
96 1.1 christos };
97 1.1 christos
98 1.1 christos
99 1.1 christos static void
100 1.1 christos aarptimer(ignored)
101 1.1 christos void *ignored;
102 1.1 christos {
103 1.1 christos struct aarptab *aat;
104 1.1 christos int i, s;
105 1.1 christos
106 1.1 christos timeout(aarptimer, NULL, AARPT_AGE * hz);
107 1.1 christos aat = aarptab;
108 1.1 christos for (i = 0; i < AARPTAB_SIZE; i++, aat++) {
109 1.1 christos int killtime = (aat->aat_flags & ATF_COM) ? AARPT_KILLC :
110 1.1 christos AARPT_KILLI;
111 1.1 christos if (aat->aat_flags == 0 || (aat->aat_flags & ATF_PERM))
112 1.1 christos continue;
113 1.1 christos if (++aat->aat_timer < killtime)
114 1.1 christos continue;
115 1.1 christos s = splimp();
116 1.1 christos aarptfree(aat);
117 1.1 christos splx(s);
118 1.1 christos }
119 1.1 christos }
120 1.1 christos
121 1.1 christos /*
122 1.1 christos * search through the network addresses to find one that includes the given
123 1.1 christos * network.. remember to take netranges into consideration.
124 1.1 christos */
125 1.2 christos struct ifaddr *
126 1.2 christos at_ifawithnet(sat, ifp)
127 1.1 christos struct sockaddr_at *sat;
128 1.2 christos struct ifnet *ifp;
129 1.2 christos {
130 1.1 christos struct ifaddr *ifa;
131 1.1 christos struct sockaddr_at *sat2;
132 1.1 christos struct netrange *nr;
133 1.1 christos
134 1.2 christos for (ifa = ifp->if_addrlist.tqh_first; ifa;
135 1.2 christos ifa = ifa->ifa_list.tqe_next) {
136 1.1 christos if (ifa->ifa_addr->sa_family != AF_APPLETALK)
137 1.1 christos continue;
138 1.1 christos
139 1.1 christos sat2 = satosat(ifa->ifa_addr);
140 1.1 christos if (sat2->sat_addr.s_net == sat->sat_addr.s_net)
141 1.1 christos break;
142 1.1 christos
143 1.1 christos nr = (struct netrange *) (sat2->sat_zero);
144 1.1 christos if ((nr->nr_phase == 2)
145 1.1 christos && (nr->nr_firstnet <= sat->sat_addr.s_net)
146 1.1 christos && (nr->nr_lastnet >= sat->sat_addr.s_net))
147 1.1 christos break;
148 1.1 christos }
149 1.1 christos return ifa;
150 1.1 christos }
151 1.1 christos
152 1.1 christos static void
153 1.1 christos aarpwhohas(ifp, sat)
154 1.1 christos struct ifnet *ifp;
155 1.1 christos struct sockaddr_at *sat;
156 1.1 christos {
157 1.1 christos struct mbuf *m;
158 1.1 christos struct ether_header *eh;
159 1.1 christos struct ether_aarp *ea;
160 1.1 christos struct at_ifaddr *aa;
161 1.1 christos struct llc *llc;
162 1.1 christos struct sockaddr sa;
163 1.1 christos
164 1.1 christos if ((m = m_gethdr(M_DONTWAIT, MT_DATA)) == NULL)
165 1.1 christos return;
166 1.1 christos
167 1.1 christos m->m_len = sizeof(*ea);
168 1.1 christos m->m_pkthdr.len = sizeof(*ea);
169 1.1 christos MH_ALIGN(m, sizeof(*ea));
170 1.1 christos
171 1.1 christos ea = mtod(m, struct ether_aarp *);
172 1.1 christos bzero(ea, sizeof(*ea));
173 1.1 christos
174 1.1 christos ea->aarp_hrd = htons(AARPHRD_ETHER);
175 1.1 christos ea->aarp_pro = htons(ETHERTYPE_AT);
176 1.1 christos ea->aarp_hln = sizeof(ea->aarp_sha);
177 1.1 christos ea->aarp_pln = sizeof(ea->aarp_spu);
178 1.1 christos ea->aarp_op = htons(AARPOP_REQUEST);
179 1.1 christos bcopy(LLADDR(ifp->if_sadl), ea->aarp_sha, sizeof(ea->aarp_sha));
180 1.1 christos
181 1.1 christos /*
182 1.1 christos * We need to check whether the output ethernet type should
183 1.1 christos * be phase 1 or 2. We have the interface that we'll be sending
184 1.1 christos * the aarp out. We need to find an AppleTalk network on that
185 1.1 christos * interface with the same address as we're looking for. If the
186 1.1 christos * net is phase 2, generate an 802.2 and SNAP header.
187 1.1 christos */
188 1.2 christos if ((aa = (struct at_ifaddr *) at_ifawithnet(sat, ifp)) == NULL) {
189 1.1 christos m_freem(m);
190 1.1 christos return;
191 1.1 christos }
192 1.1 christos eh = (struct ether_header *) sa.sa_data;
193 1.1 christos
194 1.1 christos if (aa->aa_flags & AFA_PHASE2) {
195 1.1 christos bcopy(atmulticastaddr, eh->ether_dhost,
196 1.1 christos sizeof(eh->ether_dhost));
197 1.1 christos eh->ether_type = htons(sizeof(struct llc) +
198 1.1 christos sizeof(struct ether_aarp));
199 1.1 christos M_PREPEND(m, sizeof(struct llc), M_WAIT);
200 1.1 christos llc = mtod(m, struct llc *);
201 1.1 christos llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP;
202 1.1 christos llc->llc_control = LLC_UI;
203 1.1 christos bcopy(aarp_org_code, llc->llc_org_code, sizeof(aarp_org_code));
204 1.1 christos llc->llc_ether_type = htons(ETHERTYPE_AARP);
205 1.1 christos
206 1.1 christos bcopy(&AA_SAT(aa)->sat_addr.s_net, ea->aarp_spnet,
207 1.1 christos sizeof(ea->aarp_spnet));
208 1.1 christos bcopy(&sat->sat_addr.s_net, ea->aarp_tpnet,
209 1.1 christos sizeof(ea->aarp_tpnet));
210 1.1 christos ea->aarp_spnode = AA_SAT(aa)->sat_addr.s_node;
211 1.1 christos ea->aarp_tpnode = sat->sat_addr.s_node;
212 1.1 christos } else {
213 1.1 christos bcopy(etherbroadcastaddr, eh->ether_dhost,
214 1.1 christos sizeof(eh->ether_dhost));
215 1.1 christos eh->ether_type = htons(ETHERTYPE_AARP);
216 1.1 christos
217 1.1 christos ea->aarp_spa = AA_SAT(aa)->sat_addr.s_node;
218 1.1 christos ea->aarp_tpa = sat->sat_addr.s_node;
219 1.1 christos }
220 1.1 christos
221 1.1 christos #ifdef NETATALKDEBUG
222 1.1 christos printf("aarp: sending request via %u.%u seaking %u.%u\n",
223 1.1 christos ntohs(AA_SAT(aa)->sat_addr.s_net), AA_SAT(aa)->sat_addr.s_node,
224 1.1 christos ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node);
225 1.1 christos #endif /* NETATALKDEBUG */
226 1.1 christos
227 1.1 christos sa.sa_len = sizeof(struct sockaddr);
228 1.1 christos sa.sa_family = AF_UNSPEC;
229 1.1 christos (*ifp->if_output) (ifp, m, &sa, NULL); /* XXX NULL should be routing */
230 1.1 christos /* information */
231 1.1 christos }
232 1.1 christos
233 1.1 christos int
234 1.1 christos aarpresolve(ifp, m, destsat, desten)
235 1.1 christos struct ifnet *ifp;
236 1.1 christos struct mbuf *m;
237 1.1 christos struct sockaddr_at *destsat;
238 1.1 christos u_char *desten;
239 1.1 christos {
240 1.1 christos struct at_ifaddr *aa;
241 1.1 christos struct aarptab *aat;
242 1.1 christos int s;
243 1.1 christos
244 1.1 christos if (at_broadcast(destsat)) {
245 1.2 christos aa = (struct at_ifaddr *) at_ifawithnet(destsat, ifp);
246 1.2 christos if (aa == NULL) {
247 1.1 christos m_freem(m);
248 1.1 christos return (0);
249 1.1 christos }
250 1.1 christos if (aa->aa_flags & AFA_PHASE2)
251 1.1 christos bcopy(atmulticastaddr, desten,
252 1.1 christos sizeof(atmulticastaddr));
253 1.1 christos else
254 1.1 christos bcopy(etherbroadcastaddr, desten,
255 1.1 christos sizeof(etherbroadcastaddr));
256 1.1 christos return 1;
257 1.1 christos }
258 1.1 christos s = splimp();
259 1.1 christos AARPTAB_LOOK(aat, destsat->sat_addr);
260 1.1 christos if (aat == 0) { /* No entry */
261 1.1 christos aat = aarptnew(&destsat->sat_addr);
262 1.1 christos if (aat == 0)
263 1.1 christos panic("aarpresolve: no free entry");
264 1.1 christos
265 1.1 christos aat->aat_hold = m;
266 1.1 christos aarpwhohas(ifp, destsat);
267 1.1 christos splx(s);
268 1.1 christos return 0;
269 1.1 christos }
270 1.1 christos
271 1.1 christos /* found an entry */
272 1.1 christos aat->aat_timer = 0;
273 1.1 christos if (aat->aat_flags & ATF_COM) { /* entry is COMplete */
274 1.1 christos bcopy(aat->aat_enaddr, desten, sizeof(aat->aat_enaddr));
275 1.1 christos splx(s);
276 1.1 christos return 1;
277 1.1 christos }
278 1.1 christos
279 1.1 christos /* entry has not completed */
280 1.1 christos if (aat->aat_hold)
281 1.1 christos m_freem(aat->aat_hold);
282 1.1 christos aat->aat_hold = m;
283 1.1 christos aarpwhohas(ifp, destsat);
284 1.1 christos splx(s);
285 1.1 christos
286 1.1 christos return 0;
287 1.1 christos }
288 1.1 christos
289 1.1 christos void
290 1.1 christos aarpinput(ifp, m)
291 1.1 christos struct ifnet *ifp;
292 1.1 christos struct mbuf *m;
293 1.1 christos {
294 1.1 christos struct arphdr *ar;
295 1.1 christos
296 1.1 christos if (ifp->if_flags & IFF_NOARP)
297 1.1 christos goto out;
298 1.1 christos
299 1.1 christos if (m->m_len < sizeof(struct arphdr))
300 1.1 christos goto out;
301 1.1 christos
302 1.1 christos ar = mtod(m, struct arphdr *);
303 1.1 christos if (ntohs(ar->ar_hrd) != AARPHRD_ETHER)
304 1.1 christos goto out;
305 1.1 christos
306 1.1 christos if (m->m_len < sizeof(struct arphdr) + 2 * ar->ar_hln + 2 * ar->ar_pln)
307 1.1 christos goto out;
308 1.1 christos
309 1.1 christos switch (ntohs(ar->ar_pro)) {
310 1.1 christos case ETHERTYPE_AT:
311 1.1 christos at_aarpinput(ifp, m);
312 1.1 christos return;
313 1.1 christos
314 1.1 christos default:
315 1.1 christos break;
316 1.1 christos }
317 1.1 christos
318 1.1 christos out:
319 1.1 christos m_freem(m);
320 1.1 christos }
321 1.1 christos
322 1.1 christos static void
323 1.1 christos at_aarpinput(ifp, m)
324 1.1 christos struct ifnet *ifp;
325 1.1 christos struct mbuf *m;
326 1.1 christos {
327 1.1 christos struct ether_aarp *ea;
328 1.1 christos struct at_ifaddr *aa;
329 1.1 christos struct aarptab *aat;
330 1.1 christos struct ether_header *eh;
331 1.1 christos struct llc *llc;
332 1.1 christos struct sockaddr_at sat;
333 1.1 christos struct sockaddr sa;
334 1.1 christos struct at_addr spa, tpa, ma;
335 1.1 christos int op;
336 1.1 christos u_int16_t net;
337 1.1 christos
338 1.1 christos ea = mtod(m, struct ether_aarp *);
339 1.1 christos
340 1.1 christos /* Check to see if from my hardware address */
341 1.1 christos if (!bcmp(ea->aarp_sha, LLADDR(ifp->if_sadl), sizeof(ea->aarp_sha))) {
342 1.1 christos m_freem(m);
343 1.1 christos return;
344 1.1 christos }
345 1.1 christos op = ntohs(ea->aarp_op);
346 1.1 christos bcopy(ea->aarp_tpnet, &net, sizeof(net));
347 1.1 christos
348 1.1 christos if (net != 0) { /* should be ATADDR_ANYNET? */
349 1.1 christos sat.sat_len = sizeof(struct sockaddr_at);
350 1.1 christos sat.sat_family = AF_APPLETALK;
351 1.1 christos sat.sat_addr.s_net = net;
352 1.2 christos aa = (struct at_ifaddr *) at_ifawithnet(&sat, ifp);
353 1.2 christos if (aa == NULL) {
354 1.1 christos m_freem(m);
355 1.1 christos return;
356 1.1 christos }
357 1.1 christos bcopy(ea->aarp_spnet, &spa.s_net, sizeof(spa.s_net));
358 1.1 christos bcopy(ea->aarp_tpnet, &tpa.s_net, sizeof(tpa.s_net));
359 1.1 christos } else {
360 1.1 christos /*
361 1.1 christos * Since we don't know the net, we just look for the first
362 1.1 christos * phase 1 address on the interface.
363 1.1 christos */
364 1.1 christos for (aa = (struct at_ifaddr *) ifp->if_addrlist.tqh_first; aa;
365 1.1 christos aa = (struct at_ifaddr *) aa->aa_ifa.ifa_list.tqe_next) {
366 1.1 christos if (AA_SAT(aa)->sat_family == AF_APPLETALK &&
367 1.1 christos (aa->aa_flags & AFA_PHASE2) == 0)
368 1.1 christos break;
369 1.1 christos }
370 1.1 christos if (aa == NULL) {
371 1.1 christos m_freem(m);
372 1.1 christos return;
373 1.1 christos }
374 1.1 christos tpa.s_net = spa.s_net = AA_SAT(aa)->sat_addr.s_net;
375 1.1 christos }
376 1.1 christos
377 1.1 christos spa.s_node = ea->aarp_spnode;
378 1.1 christos tpa.s_node = ea->aarp_tpnode;
379 1.1 christos ma.s_net = AA_SAT(aa)->sat_addr.s_net;
380 1.1 christos ma.s_node = AA_SAT(aa)->sat_addr.s_node;
381 1.1 christos
382 1.1 christos /*
383 1.1 christos * This looks like it's from us.
384 1.1 christos */
385 1.1 christos if (spa.s_net == ma.s_net && spa.s_node == ma.s_node) {
386 1.1 christos if (aa->aa_flags & AFA_PROBING) {
387 1.1 christos /*
388 1.1 christos * We're probing, someone either responded to our
389 1.1 christos * probe, or probed for the same address we'd like
390 1.1 christos * to use. Change the address we're probing for.
391 1.1 christos */
392 1.1 christos untimeout(aarpprobe, ifp);
393 1.1 christos wakeup(aa);
394 1.1 christos m_freem(m);
395 1.1 christos return;
396 1.1 christos } else if (op != AARPOP_PROBE) {
397 1.1 christos /*
398 1.1 christos * This is not a probe, and we're not probing.
399 1.1 christos * This means that someone's saying they have the same
400 1.1 christos * source address as the one we're using. Get upset...
401 1.1 christos */
402 1.1 christos log(LOG_ERR, "aarp: duplicate AT address!! %s\n",
403 1.1 christos ether_sprintf(ea->aarp_sha));
404 1.1 christos m_freem(m);
405 1.1 christos return;
406 1.1 christos }
407 1.1 christos }
408 1.1 christos AARPTAB_LOOK(aat, spa);
409 1.1 christos if (aat) {
410 1.1 christos if (op == AARPOP_PROBE) {
411 1.1 christos /*
412 1.1 christos * Someone's probing for spa, dealocate the one we've
413 1.1 christos * got, so that if the prober keeps the address, we'll
414 1.1 christos * be able to arp for him.
415 1.1 christos */
416 1.1 christos aarptfree(aat);
417 1.1 christos m_freem(m);
418 1.1 christos return;
419 1.1 christos }
420 1.1 christos bcopy(ea->aarp_sha, aat->aat_enaddr, sizeof(ea->aarp_sha));
421 1.1 christos aat->aat_flags |= ATF_COM;
422 1.1 christos if (aat->aat_hold) {
423 1.1 christos sat.sat_len = sizeof(struct sockaddr_at);
424 1.1 christos sat.sat_family = AF_APPLETALK;
425 1.1 christos sat.sat_addr = spa;
426 1.1 christos (*ifp->if_output)(ifp, aat->aat_hold,
427 1.1 christos (struct sockaddr *) & sat, NULL); /* XXX */
428 1.1 christos aat->aat_hold = 0;
429 1.1 christos }
430 1.1 christos }
431 1.1 christos if (aat == 0 && tpa.s_net == ma.s_net && tpa.s_node == ma.s_node
432 1.1 christos && op != AARPOP_PROBE) {
433 1.1 christos if ((aat = aarptnew(&spa)) != NULL) {
434 1.1 christos bcopy(ea->aarp_sha, aat->aat_enaddr,
435 1.1 christos sizeof(ea->aarp_sha));
436 1.1 christos aat->aat_flags |= ATF_COM;
437 1.1 christos }
438 1.1 christos }
439 1.1 christos /*
440 1.1 christos * Don't respond to responses, and never respond if we're
441 1.1 christos * still probing.
442 1.1 christos */
443 1.1 christos if (tpa.s_net != ma.s_net || tpa.s_node != ma.s_node ||
444 1.1 christos op == AARPOP_RESPONSE || (aa->aa_flags & AFA_PROBING)) {
445 1.1 christos m_freem(m);
446 1.1 christos return;
447 1.1 christos }
448 1.1 christos bcopy(ea->aarp_sha, ea->aarp_tha, sizeof(ea->aarp_sha));
449 1.1 christos bcopy(LLADDR(ifp->if_sadl), ea->aarp_sha, sizeof(ea->aarp_sha));
450 1.1 christos
451 1.1 christos /* XXX */
452 1.1 christos eh = (struct ether_header *) sa.sa_data;
453 1.1 christos bcopy(ea->aarp_tha, eh->ether_dhost, sizeof(eh->ether_dhost));
454 1.1 christos
455 1.1 christos if (aa->aa_flags & AFA_PHASE2) {
456 1.1 christos eh->ether_type = htons(sizeof(struct llc) +
457 1.1 christos sizeof(struct ether_aarp));
458 1.1 christos M_PREPEND(m, sizeof(struct llc), M_DONTWAIT);
459 1.1 christos if (m == NULL)
460 1.1 christos return;
461 1.1 christos
462 1.1 christos llc = mtod(m, struct llc *);
463 1.1 christos llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP;
464 1.1 christos llc->llc_control = LLC_UI;
465 1.1 christos bcopy(aarp_org_code, llc->llc_org_code, sizeof(aarp_org_code));
466 1.1 christos llc->llc_ether_type = htons(ETHERTYPE_AARP);
467 1.1 christos
468 1.1 christos bcopy(ea->aarp_spnet, ea->aarp_tpnet, sizeof(ea->aarp_tpnet));
469 1.1 christos bcopy(&ma.s_net, ea->aarp_spnet, sizeof(ea->aarp_spnet));
470 1.1 christos } else {
471 1.1 christos eh->ether_type = htons(ETHERTYPE_AARP);
472 1.1 christos }
473 1.1 christos
474 1.1 christos ea->aarp_tpnode = ea->aarp_spnode;
475 1.1 christos ea->aarp_spnode = ma.s_node;
476 1.1 christos ea->aarp_op = htons(AARPOP_RESPONSE);
477 1.1 christos
478 1.1 christos sa.sa_len = sizeof(struct sockaddr);
479 1.1 christos sa.sa_family = AF_UNSPEC;
480 1.1 christos (*ifp->if_output) (ifp, m, &sa, NULL); /* XXX */
481 1.1 christos return;
482 1.1 christos }
483 1.1 christos
484 1.1 christos static void
485 1.1 christos aarptfree(aat)
486 1.1 christos struct aarptab *aat;
487 1.1 christos {
488 1.1 christos
489 1.1 christos if (aat->aat_hold)
490 1.1 christos m_freem(aat->aat_hold);
491 1.1 christos aat->aat_hold = 0;
492 1.1 christos aat->aat_timer = aat->aat_flags = 0;
493 1.1 christos aat->aat_ataddr.s_net = 0;
494 1.1 christos aat->aat_ataddr.s_node = 0;
495 1.1 christos }
496 1.1 christos
497 1.1 christos static struct aarptab *
498 1.1 christos aarptnew(addr)
499 1.1 christos struct at_addr *addr;
500 1.1 christos {
501 1.1 christos int n;
502 1.1 christos int oldest = -1;
503 1.1 christos struct aarptab *aat, *aato = NULL;
504 1.1 christos static int first = 1;
505 1.1 christos
506 1.1 christos if (first) {
507 1.1 christos first = 0;
508 1.1 christos timeout(aarptimer, NULL, hz);
509 1.1 christos }
510 1.1 christos aat = &aarptab[AARPTAB_HASH(*addr) * AARPTAB_BSIZ];
511 1.1 christos for (n = 0; n < AARPTAB_BSIZ; n++, aat++) {
512 1.1 christos if (aat->aat_flags == 0)
513 1.1 christos goto out;
514 1.1 christos if (aat->aat_flags & ATF_PERM)
515 1.1 christos continue;
516 1.1 christos if ((int) aat->aat_timer > oldest) {
517 1.1 christos oldest = aat->aat_timer;
518 1.1 christos aato = aat;
519 1.1 christos }
520 1.1 christos }
521 1.1 christos if (aato == NULL)
522 1.1 christos return (NULL);
523 1.1 christos aat = aato;
524 1.1 christos aarptfree(aat);
525 1.1 christos out:
526 1.1 christos aat->aat_ataddr = *addr;
527 1.1 christos aat->aat_flags = ATF_INUSE;
528 1.1 christos return (aat);
529 1.1 christos }
530 1.1 christos
531 1.1 christos
532 1.1 christos void
533 1.1 christos aarpprobe(arp)
534 1.1 christos void *arp;
535 1.1 christos {
536 1.1 christos struct mbuf *m;
537 1.1 christos struct ether_header *eh;
538 1.1 christos struct ether_aarp *ea;
539 1.1 christos struct at_ifaddr *aa;
540 1.1 christos struct llc *llc;
541 1.1 christos struct sockaddr sa;
542 1.1 christos struct ifnet *ifp = arp;
543 1.1 christos
544 1.1 christos /*
545 1.1 christos * We need to check whether the output ethernet type should
546 1.1 christos * be phase 1 or 2. We have the interface that we'll be sending
547 1.1 christos * the aarp out. We need to find an AppleTalk network on that
548 1.1 christos * interface with the same address as we're looking for. If the
549 1.1 christos * net is phase 2, generate an 802.2 and SNAP header.
550 1.1 christos */
551 1.1 christos for (aa = (struct at_ifaddr *) ifp->if_addrlist.tqh_first; aa;
552 1.1 christos aa = (struct at_ifaddr *) aa->aa_ifa.ifa_list.tqe_next) {
553 1.1 christos if (AA_SAT(aa)->sat_family == AF_APPLETALK &&
554 1.1 christos (aa->aa_flags & AFA_PROBING))
555 1.1 christos break;
556 1.1 christos }
557 1.1 christos if (aa == NULL) { /* serious error XXX */
558 1.1 christos printf("aarpprobe why did this happen?!\n");
559 1.1 christos return;
560 1.1 christos }
561 1.1 christos if (aa->aa_probcnt <= 0) {
562 1.1 christos aa->aa_flags &= ~AFA_PROBING;
563 1.1 christos wakeup(aa);
564 1.1 christos return;
565 1.1 christos } else {
566 1.1 christos timeout(aarpprobe, arp, hz / 5);
567 1.1 christos }
568 1.1 christos
569 1.1 christos if ((m = m_gethdr(M_DONTWAIT, MT_DATA)) == NULL) {
570 1.1 christos return;
571 1.1 christos }
572 1.1 christos m->m_len = sizeof(*ea);
573 1.1 christos m->m_pkthdr.len = sizeof(*ea);
574 1.1 christos MH_ALIGN(m, sizeof(*ea));
575 1.1 christos
576 1.1 christos ea = mtod(m, struct ether_aarp *);
577 1.1 christos bzero(ea, sizeof(*ea));
578 1.1 christos
579 1.1 christos ea->aarp_hrd = htons(AARPHRD_ETHER);
580 1.1 christos ea->aarp_pro = htons(ETHERTYPE_AT);
581 1.1 christos ea->aarp_hln = sizeof(ea->aarp_sha);
582 1.1 christos ea->aarp_pln = sizeof(ea->aarp_spu);
583 1.1 christos ea->aarp_op = htons(AARPOP_PROBE);
584 1.1 christos bcopy(LLADDR(ifp->if_sadl), ea->aarp_sha, sizeof(ea->aarp_sha));
585 1.1 christos
586 1.1 christos eh = (struct ether_header *) sa.sa_data;
587 1.1 christos
588 1.1 christos if (aa->aa_flags & AFA_PHASE2) {
589 1.1 christos bcopy(atmulticastaddr, eh->ether_dhost,
590 1.1 christos sizeof(eh->ether_dhost));
591 1.1 christos eh->ether_type = htons(sizeof(struct llc) +
592 1.1 christos sizeof(struct ether_aarp));
593 1.1 christos M_PREPEND(m, sizeof(struct llc), M_WAIT);
594 1.1 christos llc = mtod(m, struct llc *);
595 1.1 christos llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP;
596 1.1 christos llc->llc_control = LLC_UI;
597 1.1 christos bcopy(aarp_org_code, llc->llc_org_code, sizeof(aarp_org_code));
598 1.1 christos llc->llc_ether_type = htons(ETHERTYPE_AARP);
599 1.1 christos
600 1.1 christos bcopy(&AA_SAT(aa)->sat_addr.s_net, ea->aarp_spnet,
601 1.1 christos sizeof(ea->aarp_spnet));
602 1.1 christos bcopy(&AA_SAT(aa)->sat_addr.s_net, ea->aarp_tpnet,
603 1.1 christos sizeof(ea->aarp_tpnet));
604 1.1 christos ea->aarp_spnode = ea->aarp_tpnode =
605 1.1 christos AA_SAT(aa)->sat_addr.s_node;
606 1.1 christos } else {
607 1.1 christos bcopy(etherbroadcastaddr, eh->ether_dhost,
608 1.1 christos sizeof(eh->ether_dhost));
609 1.1 christos eh->ether_type = htons(ETHERTYPE_AARP);
610 1.1 christos ea->aarp_spa = ea->aarp_tpa = AA_SAT(aa)->sat_addr.s_node;
611 1.1 christos }
612 1.1 christos
613 1.1 christos #ifdef NETATALKDEBUG
614 1.1 christos printf("aarp: sending probe for %u.%u\n",
615 1.1 christos ntohs(AA_SAT(aa)->sat_addr.s_net),
616 1.1 christos AA_SAT(aa)->sat_addr.s_node);
617 1.1 christos #endif /* NETATALKDEBUG */
618 1.1 christos
619 1.1 christos sa.sa_len = sizeof(struct sockaddr);
620 1.1 christos sa.sa_family = AF_UNSPEC;
621 1.1 christos (*ifp->if_output) (ifp, m, &sa, NULL); /* XXX */
622 1.1 christos aa->aa_probcnt--;
623 1.1 christos }
624 1.1 christos
625 1.1 christos void
626 1.1 christos aarp_clean()
627 1.1 christos {
628 1.1 christos struct aarptab *aat;
629 1.1 christos int i;
630 1.1 christos
631 1.1 christos untimeout(aarptimer, 0);
632 1.1 christos for (i = 0, aat = aarptab; i < AARPTAB_SIZE; i++, aat++)
633 1.1 christos if (aat->aat_hold)
634 1.1 christos m_freem(aat->aat_hold);
635 1.1 christos }
636