]> git.saurik.com Git - apple/xnu.git/blame - bsd/netinet/if_ether.c
xnu-201.42.3.tar.gz
[apple/xnu.git] / bsd / netinet / if_ether.c
CommitLineData
1c79356b
A
1/*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22/*
23 * Copyright (c) 1982, 1986, 1988, 1993
24 * The Regents of the University of California. All rights reserved.
25 *
26 * Redistribution and use in source and binary forms, with or without
27 * modification, are permitted provided that the following conditions
28 * are met:
29 * 1. Redistributions of source code must retain the above copyright
30 * notice, this list of conditions and the following disclaimer.
31 * 2. Redistributions in binary form must reproduce the above copyright
32 * notice, this list of conditions and the following disclaimer in the
33 * documentation and/or other materials provided with the distribution.
34 * 3. All advertising materials mentioning features or use of this software
35 * must display the following acknowledgement:
36 * This product includes software developed by the University of
37 * California, Berkeley and its contributors.
38 * 4. Neither the name of the University nor the names of its contributors
39 * may be used to endorse or promote products derived from this software
40 * without specific prior written permission.
41 *
42 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
43 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
44 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
45 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
46 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
47 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
48 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
49 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
50 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
51 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
52 * SUCH DAMAGE.
53 *
54 * @(#)if_ether.c 8.1 (Berkeley) 6/10/93
55 */
56
57/*
58 * Ethernet address resolution protocol.
59 * TODO:
60 * add "inuse/lock" bit (or ref. count) along with valid bit
61 */
62
63#if NOTFB31
64#include "opt_inet.h"
65#include "opt_bdg.h"
66#endif
67
68#include <sys/param.h>
69#include <sys/kernel.h>
70
71#include <sys/sysctl.h>
72
73#include <sys/systm.h>
74#include <sys/mbuf.h>
75#include <sys/malloc.h>
76#include <sys/socket.h>
77#include <sys/syslog.h>
78
79#include <net/if.h>
80#include <net/if_dl.h>
81#include <net/route.h>
82#include <net/netisr.h>
83
84#include <netinet/in.h>
85#include <netinet/in_var.h>
86#include <netinet/if_ether.h>
87
88#define SIN(s) ((struct sockaddr_in *)s)
89#define SDL(s) ((struct sockaddr_dl *)s)
90
91SYSCTL_DECL(_net_link_ether);
92SYSCTL_NODE(_net_link_ether, PF_INET, inet, CTLFLAG_RW, 0, "");
93
94/* timer values */
95static int arpt_prune = (5*60*1); /* walk list every 5 minutes */
96static int arpt_keep = (20*60); /* once resolved, good for 20 more minutes */
97static int arpt_down = 20; /* once declared down, don't send for 20 sec */
98
0b4e3aa0
A
99/* Apple Hardware SUM16 checksuming */
100int apple_hwcksum_tx = 1;
101int apple_hwcksum_rx = 1;
102
1c79356b
A
103SYSCTL_INT(_net_link_ether_inet, OID_AUTO, prune_intvl, CTLFLAG_RW,
104 &arpt_prune, 0, "");
105SYSCTL_INT(_net_link_ether_inet, OID_AUTO, max_age, CTLFLAG_RW,
106 &arpt_keep, 0, "");
107SYSCTL_INT(_net_link_ether_inet, OID_AUTO, host_down_time, CTLFLAG_RW,
108 &arpt_down, 0, "");
0b4e3aa0
A
109SYSCTL_INT(_net_link_ether_inet, OID_AUTO, apple_hwcksum_tx, CTLFLAG_RW,
110 &apple_hwcksum_tx, 0, "");
111SYSCTL_INT(_net_link_ether_inet, OID_AUTO, apple_hwcksum_rx, CTLFLAG_RW,
112 &apple_hwcksum_rx, 0, "");
1c79356b
A
113
114#define rt_expire rt_rmx.rmx_expire
115
116struct llinfo_arp {
117 LIST_ENTRY(llinfo_arp) la_le;
118 struct rtentry *la_rt;
119 struct mbuf *la_hold; /* last packet until resolved/timeout */
120 long la_asked; /* last time we QUERIED for this addr */
121#define la_timer la_rt->rt_rmx.rmx_expire /* deletion time in seconds */
122};
123
124static LIST_HEAD(, llinfo_arp) llinfo_arp;
125
126struct ifqueue arpintrq = {0, 0, 0, 50};
127static int arp_inuse, arp_allocated;
128
129static int arp_maxtries = 5;
130static int useloopback = 1; /* use loopback interface for local traffic */
131static int arp_proxyall = 0;
132static int arp_init_called = 0;
133
134SYSCTL_INT(_net_link_ether_inet, OID_AUTO, maxtries, CTLFLAG_RW,
135 &arp_maxtries, 0, "");
136SYSCTL_INT(_net_link_ether_inet, OID_AUTO, useloopback, CTLFLAG_RW,
137 &useloopback, 0, "");
138SYSCTL_INT(_net_link_ether_inet, OID_AUTO, proxyall, CTLFLAG_RW,
139 &arp_proxyall, 0, "");
140
141void arp_rtrequest __P((int, struct rtentry *, struct sockaddr *));
142static void arprequest __P((struct arpcom *,
143 struct in_addr *, struct in_addr *, u_char *));
144void arpintr __P((void));
145static void arptfree __P((struct llinfo_arp *));
146static void arptimer __P((void *));
147static u_char etherbroadcastaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
148static struct llinfo_arp
149 *arplookup __P((u_long, int, int));
150#if INET
151static void in_arpinput __P((struct mbuf *));
152#endif
153
154/*
155 * Timeout routine. Age arp_tab entries periodically.
156 */
157/* ARGSUSED */
158static void
159arptimer(ignored_arg)
160 void *ignored_arg;
161{
162 int s ;
163 register struct llinfo_arp *la;
164 struct llinfo_arp *ola;
165 boolean_t funnel_state;
166
167
168 funnel_state = thread_funnel_set(network_flock, TRUE);
169 s = splnet();
170 la = llinfo_arp.lh_first;
171
172 timeout(arptimer, (caddr_t)0, arpt_prune * hz);
173 while ((ola = la) != 0) {
174 register struct rtentry *rt = la->la_rt;
175 la = la->la_le.le_next;
176 if (rt->rt_expire && rt->rt_expire <= time_second)
177 arptfree(ola); /* timer has expired, clear */
178 }
179 splx(s);
180 (void) thread_funnel_set(network_flock, FALSE);
181
182}
183
184/*
185 * Parallel to llc_rtrequest.
186 */
187void
188arp_rtrequest(req, rt, sa)
189 int req;
190 register struct rtentry *rt;
191 struct sockaddr *sa;
192{
193 register struct sockaddr *gate = rt->rt_gateway;
194 register struct llinfo_arp *la = (struct llinfo_arp *)rt->rt_llinfo;
195 static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK};
196 static int arpinit_done;
197
198 if (!arpinit_done) {
199 arpinit_done = 1;
200 LIST_INIT(&llinfo_arp);
201 timeout(arptimer, (caddr_t)0, hz);
202 }
203 if (rt->rt_flags & RTF_GATEWAY)
204 return;
205 switch (req) {
206
207 case RTM_ADD:
208 /*
209 * XXX: If this is a manually added route to interface
210 * such as older version of routed or gated might provide,
211 * restore cloning bit.
212 */
213 if ((rt->rt_flags & RTF_HOST) == 0 &&
214 SIN(rt_mask(rt))->sin_addr.s_addr != 0xffffffff)
215 rt->rt_flags |= RTF_CLONING;
216 if (rt->rt_flags & RTF_CLONING) {
217 /*
218 * Case 1: This route should come from a route to iface.
219 */
220 rt_setgate(rt, rt_key(rt),
221 (struct sockaddr *)&null_sdl);
222 gate = rt->rt_gateway;
223 SDL(gate)->sdl_type = rt->rt_ifp->if_type;
224 SDL(gate)->sdl_index = rt->rt_ifp->if_index;
225 rt->rt_expire = time_second;
226 break;
227 }
228 /* Announce a new entry if requested. */
229 if (rt->rt_flags & RTF_ANNOUNCE)
230 arprequest((struct arpcom *)rt->rt_ifp,
231 &SIN(rt_key(rt))->sin_addr,
232 &SIN(rt_key(rt))->sin_addr,
233 (u_char *)LLADDR(SDL(gate)));
234 /*FALLTHROUGH*/
235 case RTM_RESOLVE:
236 if (gate->sa_family != AF_LINK ||
237 gate->sa_len < sizeof(null_sdl)) {
238 log(LOG_DEBUG, "arp_rtrequest: bad gateway value\n");
239 break;
240 }
241 SDL(gate)->sdl_type = rt->rt_ifp->if_type;
242 SDL(gate)->sdl_index = rt->rt_ifp->if_index;
243 if (la != 0)
244 break; /* This happens on a route change */
245 /*
246 * Case 2: This route may come from cloning, or a manual route
247 * add with a LL address.
248 */
249 R_Malloc(la, struct llinfo_arp *, sizeof(*la));
250 rt->rt_llinfo = (caddr_t)la;
251 if (la == 0) {
252 log(LOG_DEBUG, "arp_rtrequest: malloc failed\n");
253 break;
254 }
255 arp_inuse++, arp_allocated++;
256 Bzero(la, sizeof(*la));
257 la->la_rt = rt;
258 rt->rt_flags |= RTF_LLINFO;
259 LIST_INSERT_HEAD(&llinfo_arp, la, la_le);
260
261#if INET
262 /*
263 * This keeps the multicast addresses from showing up
264 * in `arp -a' listings as unresolved. It's not actually
265 * functional. Then the same for broadcast.
266 */
267 if (IN_MULTICAST(ntohl(SIN(rt_key(rt))->sin_addr.s_addr))) {
268 ETHER_MAP_IP_MULTICAST(&SIN(rt_key(rt))->sin_addr,
269 LLADDR(SDL(gate)));
270 SDL(gate)->sdl_alen = 6;
271 rt->rt_expire = 0;
272 }
273 if (in_broadcast(SIN(rt_key(rt))->sin_addr, rt->rt_ifp)) {
274 memcpy(LLADDR(SDL(gate)), etherbroadcastaddr, 6);
275 SDL(gate)->sdl_alen = 6;
276 rt->rt_expire = 0;
277 }
278#endif
279
280 if (SIN(rt_key(rt))->sin_addr.s_addr ==
281 (IA_SIN(rt->rt_ifa))->sin_addr.s_addr) {
282 /*
283 * This test used to be
284 * if (loif.if_flags & IFF_UP)
285 * It allowed local traffic to be forced
286 * through the hardware by configuring the loopback down.
287 * However, it causes problems during network configuration
288 * for boards that can't receive packets they send.
289 * It is now necessary to clear "useloopback" and remove
290 * the route to force traffic out to the hardware.
291 */
292 rt->rt_expire = 0;
293 Bcopy(((struct arpcom *)rt->rt_ifp)->ac_enaddr,
294 LLADDR(SDL(gate)), SDL(gate)->sdl_alen = 6);
295 if (useloopback)
296 rt->rt_ifp = loif;
297
298 }
299 break;
300
301 case RTM_DELETE:
302 if (la == 0)
303 break;
304 arp_inuse--;
305 LIST_REMOVE(la, la_le);
306 rt->rt_llinfo = 0;
307 rt->rt_flags &= ~RTF_LLINFO;
308 if (la->la_hold)
309 m_freem(la->la_hold);
310 Free((caddr_t)la);
311 }
312}
313
314
315
316
317/*
318 * Broadcast an ARP packet, asking who has addr on interface ac.
319 */
320void
321arpwhohas(ac, addr)
322 register struct arpcom *ac;
323 register struct in_addr *addr;
324{ struct ifnet *ifp = (struct ifnet *)ac;
325 struct ifaddr *ifa = TAILQ_FIRST(&ifp->if_addrhead);
326
327 while (ifa)
328 { if (ifa->ifa_addr->sa_family == AF_INET)
329 { arprequest(ac, &SIN(ifa->ifa_addr)->sin_addr, addr, ac->ac_enaddr);
330 return;
331 }
332 ifa = TAILQ_NEXT(ifa, ifa_link);
333 }
334 return; /* XXX */
335}
336
337
338
339/*
340 * Broadcast an ARP request. Caller specifies:
341 * - arp header source ip address
342 * - arp header target ip address
343 * - arp header source ethernet address
344 */
345static void
346arprequest(ac, sip, tip, enaddr)
347 register struct arpcom *ac;
348 register struct in_addr *sip, *tip;
349 register u_char *enaddr;
350{
351 register struct mbuf *m;
352 register struct ether_header *eh;
353 register struct ether_arp *ea;
354 struct sockaddr sa;
355
356 if ((m = m_gethdr(M_DONTWAIT, MT_DATA)) == NULL)
357 return;
358 m->m_len = sizeof(*ea);
359 m->m_pkthdr.len = sizeof(*ea);
360 m->m_pkthdr.rcvif = (struct ifnet *)0;
361 MH_ALIGN(m, sizeof(*ea));
362 ea = mtod(m, struct ether_arp *);
363 eh = (struct ether_header *)sa.sa_data;
364 bzero((caddr_t)ea, sizeof (*ea));
365 (void)memcpy(eh->ether_dhost, etherbroadcastaddr, sizeof(eh->ether_dhost));
366 eh->ether_type = htons(ETHERTYPE_ARP); /* if_output will not swap */
367 ea->arp_hrd = htons(ARPHRD_ETHER);
368 ea->arp_pro = htons(ETHERTYPE_IP);
369 ea->arp_hln = sizeof(ea->arp_sha); /* hardware address length */
370 ea->arp_pln = sizeof(ea->arp_spa); /* protocol address length */
371 ea->arp_op = htons(ARPOP_REQUEST);
372 (void)memcpy(ea->arp_sha, enaddr, sizeof(ea->arp_sha));
373 (void)memcpy(ea->arp_spa, sip, sizeof(ea->arp_spa));
374 (void)memcpy(ea->arp_tpa, tip, sizeof(ea->arp_tpa));
375 sa.sa_family = AF_UNSPEC;
376 sa.sa_len = sizeof(sa);
377 dlil_output((u_long) ac, m, 0, &sa, 0);
378}
379
380/*
381 * Resolve an IP address into an ethernet address. If success,
382 * desten is filled in. If there is no entry in arptab,
383 * set one up and broadcast a request for the IP address.
384 * Hold onto this mbuf and resend it once the address
385 * is finally resolved. A return value of 1 indicates
386 * that desten has been filled in and the packet should be sent
387 * normally; a 0 return indicates that the packet has been
388 * taken over here, either now or for later transmission.
389 */
390int
391arpresolve(ac, rt, m, dst, desten, rt0)
392 register struct arpcom *ac;
393 register struct rtentry *rt;
394 struct mbuf *m;
395 register struct sockaddr *dst;
396 register u_char *desten;
397 struct rtentry *rt0;
398{
399 register struct llinfo_arp *la = 0;
400 struct sockaddr_dl *sdl;
401
402 if (m->m_flags & M_BCAST) { /* broadcast */
403 (void)memcpy(desten, etherbroadcastaddr, sizeof(etherbroadcastaddr));
404 return (1);
405 }
406 if (m->m_flags & M_MCAST) { /* multicast */
407 ETHER_MAP_IP_MULTICAST(&SIN(dst)->sin_addr, desten);
408 return(1);
409 }
410 if (rt)
411 la = (struct llinfo_arp *)rt->rt_llinfo;
412 if (la == 0) {
413 la = arplookup(SIN(dst)->sin_addr.s_addr, 1, 0);
414 if (la)
415 rt = la->la_rt;
416 }
417 if (la == 0 || rt == 0) {
418 log(LOG_DEBUG, "arpresolve: can't allocate llinfo for %s%s%s\n",
419 inet_ntoa(SIN(dst)->sin_addr), la ? "la" : "",
420 rt ? "rt" : "");
421 m_freem(m);
422 return (0);
423 }
424 sdl = SDL(rt->rt_gateway);
425 /*
426 * Check the address family and length is valid, the address
427 * is resolved; otherwise, try to resolve.
428 */
429 if ((rt->rt_expire == 0 || rt->rt_expire > time_second) &&
430 sdl->sdl_family == AF_LINK && sdl->sdl_alen != 0) {
431 bcopy(LLADDR(sdl), desten, sdl->sdl_alen);
432 return 1;
433 }
434 /*
435 * There is an arptab entry, but no ethernet address
436 * response yet. Replace the held mbuf with this
437 * latest one.
438 */
439 if (la->la_hold)
440 m_freem(la->la_hold);
441 la->la_hold = m;
442 if (rt->rt_expire) {
443 rt->rt_flags &= ~RTF_REJECT;
444 if (la->la_asked == 0 || rt->rt_expire != time_second) {
445 rt->rt_expire = time_second;
446 if (la->la_asked++ < arp_maxtries)
447 arprequest(ac,
448 &SIN(rt->rt_ifa->ifa_addr)->sin_addr,
449 &SIN(dst)->sin_addr, ac->ac_enaddr);
450 else {
451 rt->rt_flags |= RTF_REJECT;
452 rt->rt_expire += arpt_down;
453 la->la_asked = 0;
454 }
455
456 }
457 }
458 return (0);
459}
460
461/*
462 * Common length and type checks are done here,
463 * then the protocol-specific routine is called.
464 */
465void
466arpintr()
467{
468 register struct mbuf *m;
469 register struct arphdr *ar;
470 int s;
471
472 while (arpintrq.ifq_head) {
473 s = splimp();
474 IF_DEQUEUE(&arpintrq, m);
475 splx(s);
476 if (m == 0 || (m->m_flags & M_PKTHDR) == 0)
477 panic("arpintr");
478 if (m->m_len >= sizeof(struct arphdr) &&
479 (ar = mtod(m, struct arphdr *)) &&
480 ntohs(ar->ar_hrd) == ARPHRD_ETHER &&
481 m->m_len >=
482 sizeof(struct arphdr) + 2 * ar->ar_hln + 2 * ar->ar_pln)
483
484 switch (ntohs(ar->ar_pro)) {
485
486#if INET
487 case ETHERTYPE_IP:
488 in_arpinput(m);
489 continue;
490#endif
491 }
492 m_freem(m);
493 }
494}
495
496NETISR_SET(NETISR_ARP, arpintr);
497
498
499#if INET
500/*
501 * ARP for Internet protocols on 10 Mb/s Ethernet.
502 * Algorithm is that given in RFC 826.
503 * In addition, a sanity check is performed on the sender
504 * protocol address, to catch impersonators.
505 * We no longer handle negotiations for use of trailer protocol:
506 * Formerly, ARP replied for protocol type ETHERTYPE_TRAIL sent
507 * along with IP replies if we wanted trailers sent to us,
508 * and also sent them in response to IP replies.
509 * This allowed either end to announce the desire to receive
510 * trailer packets.
511 * We no longer reply to requests for ETHERTYPE_TRAIL protocol either,
512 * but formerly didn't normally send requests.
513 */
514static void
515in_arpinput(m)
516 struct mbuf *m;
517{
518 register struct ether_arp *ea;
519 register struct arpcom *ac = (struct arpcom *)m->m_pkthdr.rcvif;
520 struct ether_header *eh;
521 register struct llinfo_arp *la = 0;
522 register struct rtentry *rt;
523 struct in_ifaddr *ia, *maybe_ia = 0;
524 struct sockaddr_dl *sdl;
525 struct sockaddr sa;
526 struct in_addr isaddr, itaddr, myaddr;
527 int op;
528 unsigned char buf[18];
529
530 ea = mtod(m, struct ether_arp *);
531 op = ntohs(ea->arp_op);
532 (void)memcpy(&isaddr, ea->arp_spa, sizeof (isaddr));
533 (void)memcpy(&itaddr, ea->arp_tpa, sizeof (itaddr));
0b4e3aa0
A
534
535 /* Don't respond to requests for 0.0.0.0 */
536 if (itaddr.s_addr == 0 && op == ARPOP_REQUEST) {
537 m_freem(m);
538 return;
539 }
540
1c79356b
A
541 for (ia = in_ifaddrhead.tqh_first; ia; ia = ia->ia_link.tqe_next)
542#if BRIDGE
543 /*
544 * For a bridge, we want to check the address irrespective
545 * of the receive interface. (This will change slightly
546 * when we have clusters of interfaces).
547 */
548 {
549#else
550 if (ia->ia_ifp == &ac->ac_if) {
551#endif
552 maybe_ia = ia;
553 if ((itaddr.s_addr == ia->ia_addr.sin_addr.s_addr) ||
554 (isaddr.s_addr == ia->ia_addr.sin_addr.s_addr))
555 break;
556 }
557 if (maybe_ia == 0) {
558 m_freem(m);
559 return;
560 }
561 myaddr = ia ? ia->ia_addr.sin_addr : maybe_ia->ia_addr.sin_addr;
0b4e3aa0 562
1c79356b
A
563 if (!bcmp((caddr_t)ea->arp_sha, (caddr_t)etherbroadcastaddr,
564 sizeof (ea->arp_sha))) {
565 log(LOG_ERR,
566 "arp: ether address is broadcast for IP address %s!\n",
567 inet_ntoa(isaddr));
568 m_freem(m);
569 return;
570 }
571 if (isaddr.s_addr == myaddr.s_addr) {
572 log(LOG_ERR,
573 "duplicate IP address %s sent from ethernet address %s\n",
574 inet_ntoa(isaddr), ether_sprintf(buf, ea->arp_sha));
575 itaddr = myaddr;
576 goto reply;
577 }
578 la = arplookup(isaddr.s_addr, itaddr.s_addr == myaddr.s_addr, 0);
579 if (la && (rt = la->la_rt) && (sdl = SDL(rt->rt_gateway))) {
580#ifndef BRIDGE /* the following is not an error when doing bridging */
581 if (rt->rt_ifp != &ac->ac_if) {
582 log(LOG_ERR, "arp: %s is on %s%d but got reply from %6D on %s%d\n",
583 inet_ntoa(isaddr),
584 rt->rt_ifp->if_name, rt->rt_ifp->if_unit,
585 ea->arp_sha, ":",
586 ac->ac_if.if_name, ac->ac_if.if_unit);
587 goto reply;
588 }
589#endif
590 if (sdl->sdl_alen &&
591 bcmp((caddr_t)ea->arp_sha, LLADDR(sdl), sdl->sdl_alen))
592 if (rt->rt_expire)
593 log(LOG_INFO, "arp: %s moved from %6D to %6D on %s%d\n",
594 inet_ntoa(isaddr), (u_char *)LLADDR(sdl), ":",
595 ea->arp_sha, ":",
596 ac->ac_if.if_name, ac->ac_if.if_unit);
597 else {
598 log(LOG_ERR,
599 "arp: %6D attempts to modify permanent entry for %s on %s%d",
600 ea->arp_sha, ":", inet_ntoa(isaddr),
601 ac->ac_if.if_name, ac->ac_if.if_unit);
602 goto reply;
603 }
604 (void)memcpy(LLADDR(sdl), ea->arp_sha, sizeof(ea->arp_sha));
605 sdl->sdl_alen = sizeof(ea->arp_sha);
606 if (rt->rt_expire)
607 rt->rt_expire = time_second + arpt_keep;
608 rt->rt_flags &= ~RTF_REJECT;
609 la->la_asked = 0;
610 if (la->la_hold) {
611 dlil_output((u_long) ac, la->la_hold, rt,
612 rt_key(rt), 0);
613 la->la_hold = 0;
614 }
615 }
616reply:
617 if (op != ARPOP_REQUEST) {
618 m_freem(m);
619 return;
620 }
621 if (itaddr.s_addr == myaddr.s_addr) {
622 /* I am the target */
623 (void)memcpy(ea->arp_tha, ea->arp_sha, sizeof(ea->arp_sha));
624 (void)memcpy(ea->arp_sha, ac->ac_enaddr, sizeof(ea->arp_sha));
625 } else {
626 la = arplookup(itaddr.s_addr, 0, SIN_PROXY);
627 if (la == NULL) {
628 struct sockaddr_in sin;
629
630 if (!arp_proxyall) {
631 m_freem(m);
632 return;
633 }
634
635 bzero(&sin, sizeof sin);
636 sin.sin_family = AF_INET;
637 sin.sin_len = sizeof sin;
638 sin.sin_addr = itaddr;
639
640 rt = rtalloc1((struct sockaddr *)&sin, 0, 0UL);
641 if (!rt) {
642 m_freem(m);
643 return;
644 }
645 /*
646 * Don't send proxies for nodes on the same interface
647 * as this one came out of, or we'll get into a fight
648 * over who claims what Ether address.
649 */
650 if (rt->rt_ifp == &ac->ac_if) {
651 rtfree(rt);
652 m_freem(m);
653 return;
654 }
655 (void)memcpy(ea->arp_tha, ea->arp_sha, sizeof(ea->arp_sha));
656 (void)memcpy(ea->arp_sha, ac->ac_enaddr, sizeof(ea->arp_sha));
657 rtfree(rt);
658#if DEBUG_PROXY
659 printf("arp: proxying for %s\n",
660 inet_ntoa(itaddr));
661#endif
662 } else {
663 rt = la->la_rt;
664 (void)memcpy(ea->arp_tha, ea->arp_sha, sizeof(ea->arp_sha));
665 sdl = SDL(rt->rt_gateway);
666 (void)memcpy(ea->arp_sha, LLADDR(sdl), sizeof(ea->arp_sha));
667 }
668 }
669
670 (void)memcpy(ea->arp_tpa, ea->arp_spa, sizeof(ea->arp_spa));
671 (void)memcpy(ea->arp_spa, &itaddr, sizeof(ea->arp_spa));
672 ea->arp_op = htons(ARPOP_REPLY);
673 ea->arp_pro = htons(ETHERTYPE_IP); /* let's be sure! */
674 eh = (struct ether_header *)sa.sa_data;
0b4e3aa0
A
675 if (IN_LINKLOCAL(ntohl(*((u_int32_t*)ea->arp_spa))))
676 (void)memcpy(eh->ether_dhost, etherbroadcastaddr, sizeof(eh->ether_dhost));
677 else
678 (void)memcpy(eh->ether_dhost, ea->arp_tha, sizeof(eh->ether_dhost));
1c79356b
A
679 eh->ether_type = htons(ETHERTYPE_ARP);
680 sa.sa_family = AF_UNSPEC;
681 sa.sa_len = sizeof(sa);
682 dlil_output((u_long) ac, m, 0, &sa, 0);
683 return;
684}
685#endif
686
687/*
688 * Free an arp entry.
689 */
690static void
691arptfree(la)
692 register struct llinfo_arp *la;
693{
694 register struct rtentry *rt = la->la_rt;
695 register struct sockaddr_dl *sdl;
696 if (rt == 0)
697 panic("arptfree");
698 if (rt->rt_refcnt > 0 && (sdl = SDL(rt->rt_gateway)) &&
699 sdl->sdl_family == AF_LINK) {
700 sdl->sdl_alen = 0;
701 la->la_asked = 0;
702 rt->rt_flags &= ~RTF_REJECT;
703 return;
704 }
705 rtrequest(RTM_DELETE, rt_key(rt), (struct sockaddr *)0, rt_mask(rt),
706 0, (struct rtentry **)0);
707}
708/*
709 * Lookup or enter a new address in arptab.
710 */
711static struct llinfo_arp *
712arplookup(addr, create, proxy)
713 u_long addr;
714 int create, proxy;
715{
716 register struct rtentry *rt;
717 static struct sockaddr_inarp sin = {sizeof(sin), AF_INET };
718 const char *why = 0;
719
720 sin.sin_addr.s_addr = addr;
721 sin.sin_other = proxy ? SIN_PROXY : 0;
722 rt = rtalloc1((struct sockaddr *)&sin, create, 0UL);
723 if (rt == 0)
724 return (0);
725 rt->rt_refcnt--;
726
727 if (rt->rt_flags & RTF_GATEWAY)
728 why = "host is not on local network";
729 else if ((rt->rt_flags & RTF_LLINFO) == 0)
730 why = "could not allocate llinfo";
731 else if (rt->rt_gateway->sa_family != AF_LINK)
732 why = "gateway route is not ours";
733
734 if (why && create) {
735 log(LOG_DEBUG, "arplookup %s failed: %s\n",
736 inet_ntoa(sin.sin_addr), why);
737 return 0;
738 } else if (why) {
739 return 0;
740 }
741 return ((struct llinfo_arp *)rt->rt_llinfo);
742}
743
744void
745arp_ifinit(ac, ifa)
746 struct arpcom *ac;
747 struct ifaddr *ifa;
748{
749 if (ntohl(IA_SIN(ifa)->sin_addr.s_addr) != INADDR_ANY)
750 arprequest(ac, &IA_SIN(ifa)->sin_addr,
751 &IA_SIN(ifa)->sin_addr, ac->ac_enaddr);
752 ifa->ifa_rtrequest = arp_rtrequest;
753 ifa->ifa_flags |= RTF_CLONING;
754}