Browse files

bring in latest KAME (as of 19991130, KAME/NetBSD141) into kame branch

just for reference purposes.
This commit includes 1.4 -> 1.4.1 sync for kame branch.

The branch does not compile at all (due to the lack of ALTQ and some other
source code).  Please do not try to modify the branch, this is just for
referenre purposes.

synchronization to latest KAME will take place on HEAD branch soon.
  • Loading branch information...
1 parent 2c845c5 commit cc83b69ed3d2845dd239bd7e4a4c4548cfbf69b5 itojun committed Nov 30, 1999
Showing with 904 additions and 449 deletions.
  1. +904 −449 sys/netinet/if_arp.c
View
1,353 sys/netinet/if_arp.c
@@ -1,7 +1,46 @@
-/*
- * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
+/* $NetBSD: if_arp.c,v 1.56.2.2.4.1 1999/11/30 13:35:21 itojun Exp $ */
+
+/*-
+ * Copyright (c) 1998 The NetBSD Foundation, Inc.
* All rights reserved.
*
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Public Access Networks Corporation ("Panix"). It was developed under
+ * contract to Panix by Eric Haszlakiewicz and Thor Lancelot Simon.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Copyright (c) 1982, 1986, 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -30,578 +69,994 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)if_ether.c 7.13 (Berkeley) 10/31/90
+ * @(#)if_ether.c 8.2 (Berkeley) 9/26/94
*/
/*
* Ethernet address resolution protocol.
* TODO:
- * run at splnet (add ARP protocol intr.)
- * link entries onto hash chains, keep free list
* add "inuse/lock" bit (or ref. count) along with valid bit
*/
-#include "param.h"
-#include "systm.h"
-#include "malloc.h"
-#include "mbuf.h"
-#include "socket.h"
-#include "time.h"
-#include "kernel.h"
-#include "errno.h"
-#include "ioctl.h"
-#include "syslog.h"
-
-#include "../net/if.h"
-#include "in.h"
-#include "in_systm.h"
-#include "in_var.h"
-#include "ip.h"
-#include "if_ether.h"
-
-#ifdef GATEWAY
-#define ARPTAB_BSIZ 16 /* bucket size */
-#define ARPTAB_NB 37 /* number of buckets */
-#else
-#define ARPTAB_BSIZ 9 /* bucket size */
-#define ARPTAB_NB 19 /* number of buckets */
-#endif
-#define ARPTAB_SIZE (ARPTAB_BSIZ * ARPTAB_NB)
-struct arptab arptab[ARPTAB_SIZE];
-int arptab_size = ARPTAB_SIZE; /* for arp command */
+#include "opt_ddb.h"
+#include "opt_inet.h"
+
+#ifdef INET
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/kernel.h>
+#include <sys/errno.h>
+#include <sys/ioctl.h>
+#include <sys/syslog.h>
+#include <sys/proc.h>
+
+#include <net/ethertypes.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_token.h>
+#include <net/if_types.h>
+#include <net/route.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/ip.h>
+#include <netinet/if_inarp.h>
+
+#include "loop.h"
+#include "token.h"
+
+#define SIN(s) ((struct sockaddr_in *)s)
+#define SDL(s) ((struct sockaddr_dl *)s)
+#define SRP(s) ((struct sockaddr_inarp *)s)
/*
* ARP trailer negotiation. Trailer protocol is not IP specific,
* but ARP request/response use IP addresses.
*/
#define ETHERTYPE_IPTRAILERS ETHERTYPE_TRAIL
-#define ARPTAB_HASH(a) \
- ((u_long)(a) % ARPTAB_NB)
-
-#define ARPTAB_LOOK(at,addr) { \
- register n; \
- at = &arptab[ARPTAB_HASH(addr) * ARPTAB_BSIZ]; \
- for (n = 0 ; n < ARPTAB_BSIZ ; n++,at++) \
- if (at->at_iaddr.s_addr == addr) \
- break; \
- if (n >= ARPTAB_BSIZ) \
- at = 0; \
+/* timer values */
+int arpt_prune = (5*60*1); /* walk list every 5 minutes */
+int arpt_keep = (20*60); /* once resolved, good for 20 more minutes */
+int arpt_down = 20; /* once declared down, don't send for 20 secs */
+#define rt_expire rt_rmx.rmx_expire
+
+static void arprequest __P((struct ifnet *,
+ struct in_addr *, struct in_addr *, u_int8_t *));
+static void arptfree __P((struct llinfo_arp *));
+static void arptimer __P((void *));
+static struct llinfo_arp *arplookup __P((struct in_addr *, int, int));
+static void in_arpinput __P((struct mbuf *));
+
+#if NLOOP > 0
+extern struct ifnet loif[NLOOP];
+#endif
+LIST_HEAD(, llinfo_arp) llinfo_arp;
+struct ifqueue arpintrq = {0, 0, 0, 50};
+int arp_inuse, arp_allocated, arp_intimer;
+int arp_maxtries = 5;
+int useloopback = 1; /* use loopback interface for local traffic */
+int arpinit_done = 0;
+
+/* revarp state */
+static struct in_addr myip, srv_ip;
+static int myip_initialized = 0;
+static int revarp_in_progress = 0;
+static struct ifnet *myip_ifp = NULL;
+
+#ifdef DDB
+static void db_print_sa __P((struct sockaddr *));
+static void db_print_ifa __P((struct ifaddr *));
+static void db_print_llinfo __P((caddr_t));
+static int db_show_radix_node __P((struct radix_node *, void *));
+#endif
+
+/*
+ * this should be elsewhere.
+ */
+
+static char *
+lla_snprintf __P((u_int8_t *, int));
+
+static char *
+lla_snprintf(adrp, len)
+ u_int8_t *adrp;
+ int len;
+{
+ static char buf[16*3];
+ static const char hexdigits[] = {
+ '0','1','2','3','4','5','6','7',
+ '8','9','a','b','c','d','e','f'
+ };
+
+ int i;
+ char *p;
+
+ p = buf;
+
+ *p++ = hexdigits[(*adrp)>>4];
+ *p++ = hexdigits[(*adrp++)&0xf];
+
+ for (i=1; i<len && i<16; i++) {
+ *p++ = ':';
+ *p++ = hexdigits[(*adrp)>>4];
+ *p++ = hexdigits[(*adrp++)&0xf];
+ }
+
+ *p = 0;
+ return buf;
}
-/* timer values */
-#define ARPT_AGE (60*1) /* aging timer, 1 min. */
-#define ARPT_KILLC 20 /* kill completed entry in 20 mins. */
-#define ARPT_KILLI 3 /* kill incomplete entry in 3 minutes */
+/*
+ * Timeout routine. Age arp_tab entries periodically.
+ */
+/* ARGSUSED */
+static void
+arptimer(arg)
+ void *arg;
+{
+ int s;
+ register struct llinfo_arp *la, *nla;
+
+ s = splsoftnet();
+ timeout(arptimer, NULL, arpt_prune * hz);
+ for (la = llinfo_arp.lh_first; la != 0; la = nla) {
+ register struct rtentry *rt = la->la_rt;
-extern struct ifnet loif;
+ nla = la->la_list.le_next;
+ if (rt->rt_expire && rt->rt_expire <= time.tv_sec)
+ arptfree(la); /* timer has expired; clear */
+ }
+ splx(s);
+}
/*
- * Timeout routine. Age arp_tab entries once a minute.
+ * Parallel to llc_rtrequest.
*/
-arptimer()
+void
+arp_rtrequest(req, rt, sa)
+ int req;
+ register struct rtentry *rt;
+ struct sockaddr *sa;
{
- register struct arptab *at;
- register i;
-
- timeout(arptimer, (caddr_t)0, ARPT_AGE * hz);
- at = &arptab[0];
- for (i = 0; i < ARPTAB_SIZE; i++, at++) {
- if (at->at_flags == 0 || (at->at_flags & ATF_PERM))
- continue;
- if (++at->at_timer < ((at->at_flags&ATF_COM) ?
- ARPT_KILLC : ARPT_KILLI))
- continue;
- /* timer has expired, clear entry */
- arptfree(at);
+ register struct sockaddr *gate = rt->rt_gateway;
+ register struct llinfo_arp *la = (struct llinfo_arp *)rt->rt_llinfo;
+ static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK};
+ size_t allocsize;
+
+ if (!arpinit_done) {
+ arpinit_done = 1;
+ /*
+ * We generate expiration times from time.tv_sec
+ * so avoid accidently creating permanent routes.
+ */
+ if (time.tv_sec == 0) {
+ time.tv_sec++;
+ }
+ timeout(arptimer, (caddr_t)0, hz);
+ }
+ if (rt->rt_flags & RTF_GATEWAY)
+ return;
+ switch (req) {
+
+ case RTM_ADD:
+ /*
+ * XXX: If this is a manually added route to interface
+ * such as older version of routed or gated might provide,
+ * restore cloning bit.
+ */
+ if ((rt->rt_flags & RTF_HOST) == 0 &&
+ SIN(rt_mask(rt))->sin_addr.s_addr != 0xffffffff)
+ rt->rt_flags |= RTF_CLONING;
+ if (rt->rt_flags & RTF_CLONING) {
+ /*
+ * Case 1: This route should come from a route to iface.
+ */
+ rt_setgate(rt, rt_key(rt),
+ (struct sockaddr *)&null_sdl);
+ gate = rt->rt_gateway;
+ SDL(gate)->sdl_type = rt->rt_ifp->if_type;
+ SDL(gate)->sdl_index = rt->rt_ifp->if_index;
+ /*
+ * Give this route an expiration time, even though
+ * it's a "permanent" route, so that routes cloned
+ * from it do not need their expiration time set.
+ */
+ rt->rt_expire = time.tv_sec;
+ break;
+ }
+ /* Announce a new entry if requested. */
+ if (rt->rt_flags & RTF_ANNOUNCE)
+ arprequest(rt->rt_ifp,
+ &SIN(rt_key(rt))->sin_addr,
+ &SIN(rt_key(rt))->sin_addr,
+ (u_char *)LLADDR(SDL(gate)));
+ /*FALLTHROUGH*/
+ case RTM_RESOLVE:
+ if (gate->sa_family != AF_LINK ||
+ gate->sa_len < sizeof(null_sdl)) {
+ log(LOG_DEBUG, "arp_rtrequest: bad gateway value\n");
+ break;
+ }
+ SDL(gate)->sdl_type = rt->rt_ifp->if_type;
+ SDL(gate)->sdl_index = rt->rt_ifp->if_index;
+ if (la != 0)
+ break; /* This happens on a route change */
+ /*
+ * Case 2: This route may come from cloning, or a manual route
+ * add with a LL address.
+ */
+ switch (SDL(gate)->sdl_type) {
+#if NTOKEN > 0
+ case IFT_ISO88025:
+ allocsize = sizeof(*la) + sizeof(struct token_rif);
+ break;
+#endif /* NTOKEN > 0 */
+ default:
+ allocsize = sizeof(*la);
+ }
+ R_Malloc(la, struct llinfo_arp *, allocsize);
+ rt->rt_llinfo = (caddr_t)la;
+ if (la == 0) {
+ log(LOG_DEBUG, "arp_rtrequest: malloc failed\n");
+ break;
+ }
+ arp_inuse++, arp_allocated++;
+ Bzero(la, allocsize);
+ la->la_rt = rt;
+ rt->rt_flags |= RTF_LLINFO;
+ LIST_INSERT_HEAD(&llinfo_arp, la, la_list);
+ if (in_hosteq(SIN(rt_key(rt))->sin_addr,
+ (IA_SIN(rt->rt_ifa))->sin_addr)) {
+ /*
+ * This test used to be
+ * if (loif.if_flags & IFF_UP)
+ * It allowed local traffic to be forced through
+ * the hardware by configuring the loopback down.
+ * However, it causes problems during network
+ * configuration for boards that can't receive
+ * packets they send. It is now necessary to clear
+ * "useloopback" and remove the route to force
+ * traffic out to the hardware.
+ */
+ rt->rt_expire = 0;
+ Bcopy(LLADDR(rt->rt_ifp->if_sadl),
+ LLADDR(SDL(gate)),
+ SDL(gate)->sdl_alen =
+ rt->rt_ifp->if_data.ifi_addrlen);
+#if NLOOP > 0
+ if (useloopback)
+ rt->rt_ifp = &loif[0];
+#endif
+ }
+ break;
+
+ case RTM_DELETE:
+ if (la == 0)
+ break;
+ arp_inuse--;
+ LIST_REMOVE(la, la_list);
+ rt->rt_llinfo = 0;
+ rt->rt_flags &= ~RTF_LLINFO;
+ if (la->la_hold)
+ m_freem(la->la_hold);
+ Free((caddr_t)la);
}
}
/*
- * Broadcast an ARP packet, asking who has addr on interface ac.
+ * Broadcast an ARP request. Caller specifies:
+ * - arp header source ip address
+ * - arp header target ip address
+ * - arp header source ethernet address
*/
-arpwhohas(ac, addr)
- register struct arpcom *ac;
- struct in_addr *addr;
+static void
+arprequest(ifp, sip, tip, enaddr)
+ register struct ifnet *ifp;
+ register struct in_addr *sip, *tip;
+ register u_int8_t *enaddr;
{
register struct mbuf *m;
- register struct ether_header *eh;
- register struct ether_arp *ea;
+ struct arphdr *ah;
struct sockaddr sa;
if ((m = m_gethdr(M_DONTWAIT, MT_DATA)) == NULL)
return;
- m->m_len = sizeof(*ea);
- m->m_pkthdr.len = sizeof(*ea);
- MH_ALIGN(m, sizeof(*ea));
- ea = mtod(m, struct ether_arp *);
- eh = (struct ether_header *)sa.sa_data;
- bzero((caddr_t)ea, sizeof (*ea));
- bcopy((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost,
- sizeof(eh->ether_dhost));
- eh->ether_type = ETHERTYPE_ARP; /* if_output will swap */
- ea->arp_hrd = htons(ARPHRD_ETHER);
- ea->arp_pro = htons(ETHERTYPE_IP);
- ea->arp_hln = sizeof(ea->arp_sha); /* hardware address length */
- ea->arp_pln = sizeof(ea->arp_spa); /* protocol address length */
- ea->arp_op = htons(ARPOP_REQUEST);
- bcopy((caddr_t)ac->ac_enaddr, (caddr_t)ea->arp_sha,
- sizeof(ea->arp_sha));
- bcopy((caddr_t)&ac->ac_ipaddr, (caddr_t)ea->arp_spa,
- sizeof(ea->arp_spa));
- bcopy((caddr_t)addr, (caddr_t)ea->arp_tpa, sizeof(ea->arp_tpa));
- sa.sa_family = AF_UNSPEC;
- sa.sa_len = sizeof(sa);
- (*ac->ac_if.if_output)(&ac->ac_if, m, &sa, (struct rtentry *)0);
+ m->m_len = sizeof(*ah) + 2*sizeof(struct in_addr) +
+ 2*ifp->if_data.ifi_addrlen;
+ m->m_pkthdr.len = m->m_len;
+ MH_ALIGN(m, m->m_len);
+ ah = mtod(m, struct arphdr *);
+ bzero((caddr_t)ah, m->m_len);
+ ah->ar_pro = htons(ETHERTYPE_IP);
+ ah->ar_hln = ifp->if_data.ifi_addrlen; /* hardware address length */
+ ah->ar_pln = sizeof(struct in_addr); /* protocol address length */
+ ah->ar_op = htons(ARPOP_REQUEST);
+ bcopy((caddr_t)enaddr, (caddr_t)ar_sha(ah), ah->ar_hln);
+ bcopy((caddr_t)sip, (caddr_t)ar_spa(ah), ah->ar_pln);
+ bcopy((caddr_t)tip, (caddr_t)ar_tpa(ah), ah->ar_pln);
+ sa.sa_family = AF_ARP;
+ sa.sa_len = 2;
+ m->m_flags |= M_BCAST;
+ (*ifp->if_output)(ifp, m, &sa, (struct rtentry *)0);
}
-int useloopback = 1; /* use loopback interface for local traffic */
-
/*
- * Resolve an IP address into an ethernet address. If success,
+ * Resolve an IP address into an ethernet address. If success,
* desten is filled in. If there is no entry in arptab,
* set one up and broadcast a request for the IP address.
* Hold onto this mbuf and resend it once the address
* is finally resolved. A return value of 1 indicates
* that desten has been filled in and the packet should be sent
* normally; a 0 return indicates that the packet has been
* taken over here, either now or for later transmission.
- *
- * We do some (conservative) locking here at splimp, since
- * arptab is also altered from input interrupt service (ecintr/ilintr
- * calls arpinput when ETHERTYPE_ARP packets come in).
*/
-arpresolve(ac, m, destip, desten, usetrailers)
- register struct arpcom *ac;
+int
+arpresolve(ifp, rt, m, dst, desten)
+ register struct ifnet *ifp;
+ register struct rtentry *rt;
struct mbuf *m;
- register struct in_addr *destip;
+ register struct sockaddr *dst;
register u_char *desten;
- int *usetrailers;
{
- register struct arptab *at;
- struct sockaddr_in sin;
- register struct in_ifaddr *ia;
- u_long lna;
- int s;
+ register struct llinfo_arp *la;
+ struct sockaddr_dl *sdl;
- *usetrailers = 0;
- if (m->m_flags & M_BCAST) { /* broadcast */
- bcopy((caddr_t)etherbroadcastaddr, (caddr_t)desten,
- sizeof(etherbroadcastaddr));
- return (1);
+ if (rt)
+ la = (struct llinfo_arp *)rt->rt_llinfo;
+ else {
+ if ((la = arplookup(&SIN(dst)->sin_addr, 1, 0)) != NULL)
+ rt = la->la_rt;
}
- lna = in_lnaof(*destip);
- /* if for us, use software loopback driver if up */
- for (ia = in_ifaddr; ia; ia = ia->ia_next)
- if ((ia->ia_ifp == &ac->ac_if) &&
- (destip->s_addr == ia->ia_addr.sin_addr.s_addr)) {
- /*
- * This test used to be
- * if (loif.if_flags & IFF_UP)
- * It allowed local traffic to be forced
- * through the hardware by configuring the loopback down.
- * However, it causes problems during network configuration
- * for boards that can't receive packets they send.
- * It is now necessary to clear "useloopback"
- * to force traffic out to the hardware.
- */
- if (useloopback) {
- sin.sin_family = AF_INET;
- sin.sin_addr = *destip;
- (void) looutput(&loif, m, (struct sockaddr *)&sin, 0);
- /*
- * The packet has already been sent and freed.
- */
- return (0);
- } else {
- bcopy((caddr_t)ac->ac_enaddr, (caddr_t)desten,
- sizeof(ac->ac_enaddr));
- return (1);
- }
- }
- s = splimp();
- ARPTAB_LOOK(at, destip->s_addr);
- if (at == 0) { /* not found */
- if (ac->ac_if.if_flags & IFF_NOARP) {
- bcopy((caddr_t)ac->ac_enaddr, (caddr_t)desten, 3);
- desten[3] = (lna >> 16) & 0x7f;
- desten[4] = (lna >> 8) & 0xff;
- desten[5] = lna & 0xff;
- splx(s);
- return (1);
- } else {
- at = arptnew(destip);
- if (at == 0)
- panic("arpresolve: no free entry");
- at->at_hold = m;
- arpwhohas(ac, destip);
- splx(s);
- return (0);
- }
+ if (la == 0 || rt == 0) {
+ log(LOG_DEBUG, "arpresolve: can't allocate llinfo\n");
+ m_freem(m);
+ return (0);
}
- at->at_timer = 0; /* restart the timer */
- if (at->at_flags & ATF_COM) { /* entry IS complete */
- bcopy((caddr_t)at->at_enaddr, (caddr_t)desten,
- sizeof(at->at_enaddr));
- if (at->at_flags & ATF_USETRAILERS)
- *usetrailers = 1;
- splx(s);
- return (1);
+ sdl = SDL(rt->rt_gateway);
+ /*
+ * Check the address family and length is valid, the address
+ * is resolved; otherwise, try to resolve.
+ */
+ if ((rt->rt_expire == 0 || rt->rt_expire > time.tv_sec) &&
+ sdl->sdl_family == AF_LINK && sdl->sdl_alen != 0) {
+ bcopy(LLADDR(sdl), desten,
+ min(sdl->sdl_alen, ifp->if_data.ifi_addrlen));
+ return 1;
}
/*
* There is an arptab entry, but no ethernet address
* response yet. Replace the held mbuf with this
* latest one.
*/
- if (at->at_hold)
- m_freem(at->at_hold);
- at->at_hold = m;
- arpwhohas(ac, destip); /* ask again */
- splx(s);
+ if (la->la_hold)
+ m_freem(la->la_hold);
+ la->la_hold = m;
+ /*
+ * Re-send the ARP request when appropriate.
+ */
+#ifdef DIAGNOSTIC
+ if (rt->rt_expire == 0) {
+ /* This should never happen. (Should it? -gwr) */
+ printf("arpresolve: unresolved and rt_expire == 0\n");
+ /* Set expiration time to now (expired). */
+ rt->rt_expire = time.tv_sec;
+ }
+#endif
+ if (rt->rt_expire) {
+ rt->rt_flags &= ~RTF_REJECT;
+ if (la->la_asked == 0 || rt->rt_expire != time.tv_sec) {
+ rt->rt_expire = time.tv_sec;
+ if (la->la_asked++ < arp_maxtries)
+ arprequest(ifp,
+ &SIN(rt->rt_ifa->ifa_addr)->sin_addr,
+ &SIN(dst)->sin_addr,
+ LLADDR(ifp->if_sadl));
+ else {
+ rt->rt_flags |= RTF_REJECT;
+ rt->rt_expire += arpt_down;
+ la->la_asked = 0;
+ }
+ }
+ }
return (0);
}
/*
- * Called from 10 Mb/s Ethernet interrupt handlers
- * when ether packet type ETHERTYPE_ARP
- * is received. Common length and type checks are done here,
+ * Common length and type checks are done here,
* then the protocol-specific routine is called.
*/
-arpinput(ac, m)
- struct arpcom *ac;
- struct mbuf *m;
+void
+arpintr()
{
+ register struct mbuf *m;
register struct arphdr *ar;
+ int s;
- if (ac->ac_if.if_flags & IFF_NOARP)
- goto out;
- if (m->m_len < sizeof(struct arphdr))
- goto out;
- ar = mtod(m, struct arphdr *);
- if (ntohs(ar->ar_hrd) != ARPHRD_ETHER)
- goto out;
- if (m->m_len < sizeof(struct arphdr) + 2 * ar->ar_hln + 2 * ar->ar_pln)
- goto out;
-
- switch (ntohs(ar->ar_pro)) {
+ while (arpintrq.ifq_head) {
+ s = splimp();
+ IF_DEQUEUE(&arpintrq, m);
+ splx(s);
+ if (m == 0 || (m->m_flags & M_PKTHDR) == 0)
+ panic("arpintr");
- case ETHERTYPE_IP:
- case ETHERTYPE_IPTRAILERS:
- in_arpinput(ac, m);
- return;
+ if (m->m_len >= sizeof(struct arphdr) &&
+ (ar = mtod(m, struct arphdr *)) &&
+ /* XXX ntohs(ar->ar_hrd) == ARPHRD_ETHER && */
+ m->m_len >=
+ sizeof(struct arphdr) + 2 * (ar->ar_hln + ar->ar_pln))
+ switch (ntohs(ar->ar_pro)) {
- default:
- break;
+ case ETHERTYPE_IP:
+ case ETHERTYPE_IPTRAILERS:
+ in_arpinput(m);
+ continue;
+ }
+ m_freem(m);
}
-out:
- m_freem(m);
}
/*
* ARP for Internet protocols on 10 Mb/s Ethernet.
* Algorithm is that given in RFC 826.
* In addition, a sanity check is performed on the sender
* protocol address, to catch impersonators.
- * We also handle negotiations for use of trailer protocol:
- * ARP replies for protocol type ETHERTYPE_TRAIL are sent
- * along with IP replies if we want trailers sent to us,
- * and also send them in response to IP replies.
- * This allows either end to announce the desire to receive
+ * We no longer handle negotiations for use of trailer protocol:
+ * Formerly, ARP replied for protocol type ETHERTYPE_TRAIL sent
+ * along with IP replies if we wanted trailers sent to us,
+ * and also sent them in response to IP replies.
+ * This allowed either end to announce the desire to receive
* trailer packets.
- * We reply to requests for ETHERTYPE_TRAIL protocol as well,
- * but don't normally send requests.
+ * We no longer reply to requests for ETHERTYPE_TRAIL protocol either,
+ * but formerly didn't normally send requests.
*/
-in_arpinput(ac, m)
- register struct arpcom *ac;
+static void
+in_arpinput(m)
struct mbuf *m;
{
- register struct ether_arp *ea;
- struct ether_header *eh;
- register struct arptab *at; /* same as "merge" flag */
- register struct in_ifaddr *ia;
- struct in_ifaddr *maybe_ia = 0;
- struct mbuf *mcopy = 0;
- struct sockaddr_in sin;
+ struct arphdr *ah;
+ register struct ifnet *ifp = m->m_pkthdr.rcvif;
+ register struct llinfo_arp *la = 0;
+ register struct rtentry *rt;
+ struct in_ifaddr *ia;
+ struct sockaddr_dl *sdl;
struct sockaddr sa;
struct in_addr isaddr, itaddr, myaddr;
- int proto, op, s, completed = 0;
-
- ea = mtod(m, struct ether_arp *);
- proto = ntohs(ea->arp_pro);
- op = ntohs(ea->arp_op);
- bcopy((caddr_t)ea->arp_spa, (caddr_t)&isaddr, sizeof (isaddr));
- bcopy((caddr_t)ea->arp_tpa, (caddr_t)&itaddr, sizeof (itaddr));
- for (ia = in_ifaddr; ia; ia = ia->ia_next)
- if (ia->ia_ifp == &ac->ac_if) {
- maybe_ia = ia;
- if ((itaddr.s_addr == ia->ia_addr.sin_addr.s_addr) ||
- (isaddr.s_addr == ia->ia_addr.sin_addr.s_addr))
- break;
- }
- if (maybe_ia == 0)
+ int op;
+
+ ah = mtod(m, struct arphdr *);
+ op = ntohs(ah->ar_op);
+ bcopy((caddr_t)ar_spa(ah), (caddr_t)&isaddr, sizeof (isaddr));
+ bcopy((caddr_t)ar_tpa(ah), (caddr_t)&itaddr, sizeof (itaddr));
+
+ /*
+ * If the target IP address is zero, ignore the packet.
+ * This prevents the code below from tring to answer
+ * when we are using IP address zero (booting).
+ */
+ if (in_nullhost(itaddr))
+ goto out;
+
+ /*
+ * If the source IP address is zero, this is most likely a
+ * confused host trying to use IP address zero. (Windoze?)
+ * XXX: Should we bother trying to reply to these?
+ */
+ if (in_nullhost(isaddr))
goto out;
- myaddr = ia ? ia->ia_addr.sin_addr : maybe_ia->ia_addr.sin_addr;
- if (!bcmp((caddr_t)ea->arp_sha, (caddr_t)ac->ac_enaddr,
- sizeof (ea->arp_sha)))
+
+ /*
+ * Search for a matching interface address
+ * or any address on the interface to use
+ * as a dummy address in the rest of this function
+ */
+ INADDR_TO_IA(itaddr, ia);
+ while ((ia != NULL) && ia->ia_ifp != m->m_pkthdr.rcvif)
+ NEXT_IA_WITH_SAME_ADDR(ia);
+
+ if (ia == NULL) {
+ INADDR_TO_IA(isaddr, ia);
+ while ((ia != NULL) && ia->ia_ifp != m->m_pkthdr.rcvif)
+ NEXT_IA_WITH_SAME_ADDR(ia);
+
+ if (ia == NULL) {
+ IFP_TO_IA(ifp, ia);
+ if (ia == NULL)
+ goto out;
+ }
+ }
+
+ myaddr = ia->ia_addr.sin_addr;
+
+ if (!bcmp((caddr_t)ar_sha(ah), LLADDR(ifp->if_sadl),
+ ifp->if_data.ifi_addrlen))
goto out; /* it's from me, ignore it. */
- if (!bcmp((caddr_t)ea->arp_sha, (caddr_t)etherbroadcastaddr,
- sizeof (ea->arp_sha))) {
+
+ if (!bcmp((caddr_t)ar_sha(ah), (caddr_t)ifp->if_broadcastaddr,
+ ifp->if_data.ifi_addrlen)) {
log(LOG_ERR,
- "arp: ether address is broadcast for IP address %x!\n",
- ntohl(isaddr.s_addr));
+ "%s: arp: link address is broadcast for IP address %s!\n",
+ ifp->if_xname, in_fmtaddr(isaddr));
goto out;
}
- if (isaddr.s_addr == myaddr.s_addr) {
+
+ if (in_hosteq(isaddr, myaddr)) {
log(LOG_ERR,
- "duplicate IP address %x!! sent from ethernet address: %s\n",
- ntohl(isaddr.s_addr), ether_sprintf(ea->arp_sha));
+ "duplicate IP address %s sent from link address %s\n",
+ in_fmtaddr(isaddr), lla_snprintf(ar_sha(ah), ah->ar_hln));
itaddr = myaddr;
- if (op == ARPOP_REQUEST)
- goto reply;
- goto out;
+ goto reply;
}
- s = splimp();
- ARPTAB_LOOK(at, isaddr.s_addr);
- if (at) {
- bcopy((caddr_t)ea->arp_sha, (caddr_t)at->at_enaddr,
- sizeof(ea->arp_sha));
- if ((at->at_flags & ATF_COM) == 0)
- completed = 1;
- at->at_flags |= ATF_COM;
- if (at->at_hold) {
- sin.sin_family = AF_INET;
- sin.sin_addr = isaddr;
- (*ac->ac_if.if_output)(&ac->ac_if, at->at_hold,
- (struct sockaddr *)&sin, (struct rtentry *)0);
- at->at_hold = 0;
+ la = arplookup(&isaddr, in_hosteq(itaddr, myaddr), 0);
+ if (la && (rt = la->la_rt) && (sdl = SDL(rt->rt_gateway))) {
+ if (sdl->sdl_alen &&
+ bcmp((caddr_t)ar_sha(ah), LLADDR(sdl), sdl->sdl_alen)) {
+ if (rt->rt_flags & RTF_STATIC) {
+ log(LOG_INFO,
+ "%s tried to overwrite permanent arp info"
+ " for %s\n",
+ lla_snprintf(ar_sha(ah), ah->ar_hln),
+ in_fmtaddr(isaddr));
+ goto out;
+ } else if (rt->rt_ifp != ifp) {
+ log(LOG_INFO,
+ "%s on %s tried to overwrite "
+ "arp info for %s on %s\n",
+ lla_snprintf(ar_sha(ah), ah->ar_hln),
+ ifp->if_xname, in_fmtaddr(isaddr),
+ rt->rt_ifp->if_xname);
+ goto out;
+ } else {
+ log(LOG_INFO,
+ "arp info overwritten for %s by %s\n",
+ in_fmtaddr(isaddr),
+ lla_snprintf(ar_sha(ah), ah->ar_hln));
+ }
}
- }
- if (at == 0 && itaddr.s_addr == myaddr.s_addr) {
- /* ensure we have a table entry */
- if (at = arptnew(&isaddr)) {
- bcopy((caddr_t)ea->arp_sha, (caddr_t)at->at_enaddr,
- sizeof(ea->arp_sha));
- completed = 1;
- at->at_flags |= ATF_COM;
+ /*
+ * sanity check for the address length.
+ * XXX this does not work for protocols with variable address
+ * length. -is
+ */
+ if (sdl->sdl_alen &&
+ sdl->sdl_alen != ah->ar_hln) {
+ log(LOG_WARNING,
+ "arp from %s: new addr len %d, was %d",
+ in_fmtaddr(isaddr), ah->ar_hln, sdl->sdl_alen);
}
- }
- splx(s);
-reply:
- switch (proto) {
-
- case ETHERTYPE_IPTRAILERS:
- /* partner says trailers are OK */
- if (at)
- at->at_flags |= ATF_USETRAILERS;
+ if (ifp->if_data.ifi_addrlen != ah->ar_hln) {
+ log(LOG_WARNING,
+ "arp from %s: addr len: new %d, i/f %d (ignored)",
+ in_fmtaddr(isaddr), ah->ar_hln,
+ ifp->if_data.ifi_addrlen);
+ goto reply;
+ }
+#if NTOKEN > 0
/*
- * Reply to request iff we want trailers.
+ * XXX uses m_pktdat and assumes the complete answer including
+ * XXX token-ring headers is in the same buf
*/
- if (op != ARPOP_REQUEST || ac->ac_if.if_flags & IFF_NOTRAILERS)
- goto out;
- break;
+ if (ifp->if_type == IFT_ISO88025 &&
+ m->m_pktdat[8] & TOKEN_RI_PRESENT) {
+ struct token_rif *rif;
+ size_t riflen;
- case ETHERTYPE_IP:
- /*
- * Reply if this is an IP request,
- * or if we want to send a trailer response.
- * Send the latter only to the IP response
- * that completes the current ARP entry.
- */
- if (op != ARPOP_REQUEST &&
- (completed == 0 || ac->ac_if.if_flags & IFF_NOTRAILERS))
- goto out;
+ rif = TOKEN_RIF((struct token_header *) m->m_pktdat);
+ riflen = (ntohs(rif->tr_rcf) & TOKEN_RCF_LEN_MASK) >> 8;
+
+ if (riflen > 2 && riflen < sizeof(struct token_rif) &&
+ (riflen & 1) == 0) {
+ rif->tr_rcf ^= htons(TOKEN_RCF_DIRECTION);
+ rif->tr_rcf &= htons(~TOKEN_RCF_BROADCAST_MASK);
+ bcopy(rif, TOKEN_RIF(la), riflen);
+ }
+ }
+#endif /* NTOKEN > 0 */
+ bcopy((caddr_t)ar_sha(ah), LLADDR(sdl),
+ sdl->sdl_alen = ah->ar_hln);
+ if (rt->rt_expire)
+ rt->rt_expire = time.tv_sec + arpt_keep;
+ rt->rt_flags &= ~RTF_REJECT;
+ la->la_asked = 0;
+ if (la->la_hold) {
+ (*ifp->if_output)(ifp, la->la_hold,
+ rt_key(rt), rt);
+ la->la_hold = 0;
+ }
}
- if (itaddr.s_addr == myaddr.s_addr) {
+reply:
+ if (op != ARPOP_REQUEST) {
+ out:
+ m_freem(m);
+ return;
+ }
+ if (in_hosteq(itaddr, myaddr)) {
/* I am the target */
- bcopy((caddr_t)ea->arp_sha, (caddr_t)ea->arp_tha,
- sizeof(ea->arp_sha));
- bcopy((caddr_t)ac->ac_enaddr, (caddr_t)ea->arp_sha,
- sizeof(ea->arp_sha));
+ bcopy((caddr_t)ar_sha(ah), (caddr_t)ar_tha(ah), ah->ar_hln);
+ bcopy(LLADDR(ifp->if_sadl), (caddr_t)ar_sha(ah), ah->ar_hln);
} else {
- ARPTAB_LOOK(at, itaddr.s_addr);
- if (at == NULL || (at->at_flags & ATF_PUBL) == 0)
+ la = arplookup(&itaddr, 0, SIN_PROXY);
+ if (la == 0)
goto out;
- bcopy((caddr_t)ea->arp_sha, (caddr_t)ea->arp_tha,
- sizeof(ea->arp_sha));
- bcopy((caddr_t)at->at_enaddr, (caddr_t)ea->arp_sha,
- sizeof(ea->arp_sha));
+ rt = la->la_rt;
+ bcopy((caddr_t)ar_sha(ah), (caddr_t)ar_tha(ah), ah->ar_hln);
+ sdl = SDL(rt->rt_gateway);
+ bcopy(LLADDR(sdl), (caddr_t)ar_sha(ah), ah->ar_hln);
}
- bcopy((caddr_t)ea->arp_spa, (caddr_t)ea->arp_tpa,
- sizeof(ea->arp_spa));
- bcopy((caddr_t)&itaddr, (caddr_t)ea->arp_spa,
- sizeof(ea->arp_spa));
- ea->arp_op = htons(ARPOP_REPLY);
- /*
- * If incoming packet was an IP reply,
- * we are sending a reply for type IPTRAILERS.
- * If we are sending a reply for type IP
- * and we want to receive trailers,
- * send a trailer reply as well.
- */
- if (op == ARPOP_REPLY)
- ea->arp_pro = htons(ETHERTYPE_IPTRAILERS);
- else if (proto == ETHERTYPE_IP &&
- (ac->ac_if.if_flags & IFF_NOTRAILERS) == 0)
- mcopy = m_copy(m, 0, (int)M_COPYALL);
- eh = (struct ether_header *)sa.sa_data;
- bcopy((caddr_t)ea->arp_tha, (caddr_t)eh->ether_dhost,
- sizeof(eh->ether_dhost));
- eh->ether_type = ETHERTYPE_ARP;
- sa.sa_family = AF_UNSPEC;
- sa.sa_len = sizeof(sa);
- (*ac->ac_if.if_output)(&ac->ac_if, m, &sa, (struct rtentry *)0);
- if (mcopy) {
- ea = mtod(mcopy, struct ether_arp *);
- ea->arp_pro = htons(ETHERTYPE_IPTRAILERS);
- (*ac->ac_if.if_output)(&ac->ac_if,
- mcopy, &sa, (struct rtentry *)0);
- }
- return;
-out:
- m_freem(m);
+ bcopy((caddr_t)ar_spa(ah), (caddr_t)ar_tpa(ah), ah->ar_pln);
+ bcopy((caddr_t)&itaddr, (caddr_t)ar_spa(ah), ah->ar_pln);
+ ah->ar_op = htons(ARPOP_REPLY);
+ ah->ar_pro = htons(ETHERTYPE_IP); /* let's be sure! */
+ m->m_flags &= ~(M_BCAST|M_MCAST); /* never reply by broadcast */
+ m->m_len = sizeof(*ah) + (2 * ah->ar_pln) + (2 * ah->ar_hln);
+ m->m_pkthdr.len = m->m_len;
+ sa.sa_family = AF_ARP;
+ sa.sa_len = 2;
+ (*ifp->if_output)(ifp, m, &sa, (struct rtentry *)0);
return;
}
/*
- * Free an arptab entry.
+ * Free an arp entry.
*/
-arptfree(at)
- register struct arptab *at;
+static void
+arptfree(la)
+ register struct llinfo_arp *la;
{
- int s = splimp();
+ register struct rtentry *rt = la->la_rt;
+ register struct sockaddr_dl *sdl;
- if (at->at_hold)
- m_freem(at->at_hold);
- at->at_hold = 0;
- at->at_timer = at->at_flags = 0;
- at->at_iaddr.s_addr = 0;
- splx(s);
+ if (rt == 0)
+ panic("arptfree");
+ if (rt->rt_refcnt > 0 && (sdl = SDL(rt->rt_gateway)) &&
+ sdl->sdl_family == AF_LINK) {
+ sdl->sdl_alen = 0;
+ la->la_asked = 0;
+ rt->rt_flags &= ~RTF_REJECT;
+ return;
+ }
+ rtrequest(RTM_DELETE, rt_key(rt), (struct sockaddr *)0, rt_mask(rt),
+ 0, (struct rtentry **)0);
}
/*
- * Enter a new address in arptab, pushing out the oldest entry
- * from the bucket if there is no room.
- * This always succeeds since no bucket can be completely filled
- * with permanent entries (except from arpioctl when testing whether
- * another permanent entry will fit).
- * MUST BE CALLED AT SPLIMP.
+ * Lookup or enter a new address in arptab.
*/
-struct arptab *
-arptnew(addr)
+static struct llinfo_arp *
+arplookup(addr, create, proxy)
struct in_addr *addr;
+ int create, proxy;
{
- register n;
- int oldest = -1;
- register struct arptab *at, *ato = NULL;
- static int first = 1;
+ register struct rtentry *rt;
+ static struct sockaddr_inarp sin;
+ const char *why = 0;
- if (first) {
- first = 0;
- timeout(arptimer, (caddr_t)0, hz);
- }
- at = &arptab[ARPTAB_HASH(addr->s_addr) * ARPTAB_BSIZ];
- for (n = 0; n < ARPTAB_BSIZ; n++,at++) {
- if (at->at_flags == 0)
- goto out; /* found an empty entry */
- if (at->at_flags & ATF_PERM)
- continue;
- if ((int) at->at_timer > oldest) {
- oldest = at->at_timer;
- ato = at;
- }
- }
- if (ato == NULL)
- return (NULL);
- at = ato;
- arptfree(at);
-out:
- at->at_iaddr = *addr;
- at->at_flags = ATF_INUSE;
- return (at);
+ sin.sin_len = sizeof(sin);
+ sin.sin_family = AF_INET;
+ sin.sin_addr = *addr;
+ sin.sin_other = proxy ? SIN_PROXY : 0;
+ rt = rtalloc1(sintosa(&sin), create);
+ if (rt == 0)
+ return (0);
+ rt->rt_refcnt--;
+
+ if (rt->rt_flags & RTF_GATEWAY)
+ why = "host is not on local network";
+ else if ((rt->rt_flags & RTF_LLINFO) == 0)
+ why = "could not allocate llinfo";
+ else if (rt->rt_gateway->sa_family != AF_LINK)
+ why = "gateway route is not ours";
+ else
+ return ((struct llinfo_arp *)rt->rt_llinfo);
+
+ if (create)
+ log(LOG_DEBUG, "arplookup: unable to enter address"
+ " for %s (%s)\n",
+ in_fmtaddr(*addr), why);
+ return (0);
}
+int
arpioctl(cmd, data)
- int cmd;
+ u_long cmd;
caddr_t data;
{
- register struct arpreq *ar = (struct arpreq *)data;
- register struct arptab *at;
- register struct sockaddr_in *sin;
- int s;
- sin = (struct sockaddr_in *)&ar->arp_ha;
-#if defined(COMPAT_43) && BYTE_ORDER != BIG_ENDIAN
- if (sin->sin_family == 0 && sin->sin_len < 16)
- sin->sin_family = sin->sin_len;
-#endif
- sin->sin_len = sizeof(ar->arp_ha);
- sin = (struct sockaddr_in *)&ar->arp_pa;
-#if defined(COMPAT_43) && BYTE_ORDER != BIG_ENDIAN
- if (sin->sin_family == 0 && sin->sin_len < 16)
- sin->sin_family = sin->sin_len;
+ return (EOPNOTSUPP);
+}
+
+void
+arp_ifinit(ifp, ifa)
+ struct ifnet *ifp;
+ struct ifaddr *ifa;
+{
+ struct in_addr *ip;
+
+ /*
+ * Warn the user if another station has this IP address,
+ * but only if the interface IP address is not zero.
+ */
+ ip = &IA_SIN(ifa)->sin_addr;
+ if (!in_nullhost(*ip))
+ arprequest(ifp, ip, ip, LLADDR(ifp->if_sadl));
+
+ ifa->ifa_rtrequest = arp_rtrequest;
+ ifa->ifa_flags |= RTF_CLONING;
+}
+
+/*
+ * Called from 10 Mb/s Ethernet interrupt handlers
+ * when ether packet type ETHERTYPE_REVARP
+ * is received. Common length and type checks are done here,
+ * then the protocol-specific routine is called.
+ */
+void
+revarpinput(m)
+ struct mbuf *m;
+{
+ struct arphdr *ar;
+
+ if (m->m_len < sizeof(struct arphdr))
+ goto out;
+ ar = mtod(m, struct arphdr *);
+#if 0 /* XXX I don't think we need this... and it will prevent other LL */
+ if (ntohs(ar->ar_hrd) != ARPHRD_ETHER)
+ goto out;
#endif
- sin->sin_len = sizeof(ar->arp_pa);
- if (ar->arp_pa.sa_family != AF_INET ||
- ar->arp_ha.sa_family != AF_UNSPEC)
- return (EAFNOSUPPORT);
- s = splimp();
- ARPTAB_LOOK(at, sin->sin_addr.s_addr);
- if (at == NULL) { /* not found */
- if (cmd != SIOCSARP) {
- splx(s);
- return (ENXIO);
- }
- if (ifa_ifwithnet(&ar->arp_pa) == NULL) {
- splx(s);
- return (ENETUNREACH);
- }
- }
- switch (cmd) {
-
- case SIOCSARP: /* set entry */
- if (at == NULL) {
- at = arptnew(&sin->sin_addr);
- if (at == NULL) {
- splx(s);
- return (EADDRNOTAVAIL);
- }
- if (ar->arp_flags & ATF_PERM) {
- /* never make all entries in a bucket permanent */
- register struct arptab *tat;
-
- /* try to re-allocate */
- tat = arptnew(&sin->sin_addr);
- if (tat == NULL) {
- arptfree(at);
- splx(s);
- return (EADDRNOTAVAIL);
- }
- arptfree(tat);
- }
- }
- bcopy((caddr_t)ar->arp_ha.sa_data, (caddr_t)at->at_enaddr,
- sizeof(at->at_enaddr));
- at->at_flags = ATF_COM | ATF_INUSE |
- (ar->arp_flags & (ATF_PERM|ATF_PUBL|ATF_USETRAILERS));
- at->at_timer = 0;
- break;
+ if (m->m_len < sizeof(struct arphdr) + 2 * (ar->ar_hln + ar->ar_pln))
+ goto out;
+ switch (ntohs(ar->ar_pro)) {
+
+ case ETHERTYPE_IP:
+ case ETHERTYPE_IPTRAILERS:
+ in_revarpinput(m);
+ return;
- case SIOCDARP: /* delete entry */
- arptfree(at);
+ default:
break;
+ }
+out:
+ m_freem(m);
+}
- case SIOCGARP: /* get entry */
- case OSIOCGARP:
- bcopy((caddr_t)at->at_enaddr, (caddr_t)ar->arp_ha.sa_data,
- sizeof(at->at_enaddr));
-#ifdef COMPAT_43
- if (cmd == OSIOCGARP)
- *(u_short *)&ar->arp_ha = ar->arp_ha.sa_family;
-#endif
- ar->arp_flags = at->at_flags;
+/*
+ * RARP for Internet protocols on 10 Mb/s Ethernet.
+ * Algorithm is that given in RFC 903.
+ * We are only using for bootstrap purposes to get an ip address for one of
+ * our interfaces. Thus we support no user-interface.
+ *
+ * Since the contents of the RARP reply are specific to the interface that
+ * sent the request, this code must ensure that they are properly associated.
+ *
+ * Note: also supports ARP via RARP packets, per the RFC.
+ */
+void
+in_revarpinput(m)
+ struct mbuf *m;
+{
+ struct ifnet *ifp;
+ struct arphdr *ah;
+ int op;
+
+ ah = mtod(m, struct arphdr *);
+ op = ntohs(ah->ar_op);
+ switch (op) {
+ case ARPOP_REQUEST:
+ case ARPOP_REPLY: /* per RFC */
+ in_arpinput(m);
+ return;
+ case ARPOP_REVREPLY:
break;
+ case ARPOP_REVREQUEST: /* handled by rarpd(8) */
+ default:
+ goto out;
}
- splx(s);
+ if (!revarp_in_progress)
+ goto out;
+ ifp = m->m_pkthdr.rcvif;
+ if (ifp != myip_ifp) /* !same interface */
+ goto out;
+ if (myip_initialized)
+ goto wake;
+ if (bcmp(ar_tha(ah), LLADDR(ifp->if_sadl), ifp->if_sadl->sdl_alen))
+ goto out;
+ bcopy((caddr_t)ar_spa(ah), (caddr_t)&srv_ip, sizeof(srv_ip));
+ bcopy((caddr_t)ar_tpa(ah), (caddr_t)&myip, sizeof(myip));
+ myip_initialized = 1;
+wake: /* Do wakeup every time in case it was missed. */
+ wakeup((caddr_t)&myip);
+
+out:
+ m_freem(m);
+}
+
+/*
+ * Send a RARP request for the ip address of the specified interface.
+ * The request should be RFC 903-compliant.
+ */
+void
+revarprequest(ifp)
+ struct ifnet *ifp;
+{
+ struct sockaddr sa;
+ struct mbuf *m;
+ struct arphdr *ah;
+
+ if ((m = m_gethdr(M_DONTWAIT, MT_DATA)) == NULL)
+ return;
+ m->m_len = sizeof(*ah) + 2*sizeof(struct in_addr) +
+ 2*ifp->if_data.ifi_addrlen;
+ m->m_pkthdr.len = m->m_len;
+ MH_ALIGN(m, m->m_len);
+ ah = mtod(m, struct arphdr *);
+ bzero((caddr_t)ah, m->m_len);
+ ah->ar_pro = htons(ETHERTYPE_IP);
+ ah->ar_hln = ifp->if_data.ifi_addrlen; /* hardware address length */
+ ah->ar_pln = sizeof(struct in_addr); /* protocol address length */
+ ah->ar_op = htons(ARPOP_REVREQUEST);
+
+ bcopy(LLADDR(ifp->if_sadl), (caddr_t)ar_sha(ah), ah->ar_hln);
+ bcopy(LLADDR(ifp->if_sadl), (caddr_t)ar_tha(ah), ah->ar_hln);
+
+ sa.sa_family = AF_ARP;
+ sa.sa_len = 2;
+ m->m_flags |= M_BCAST;
+ (*ifp->if_output)(ifp, m, &sa, (struct rtentry *)0);
+
+}
+
+/*
+ * RARP for the ip address of the specified interface, but also
+ * save the ip address of the server that sent the answer.
+ * Timeout if no response is received.
+ */
+int
+revarpwhoarewe(ifp, serv_in, clnt_in)
+ struct ifnet *ifp;
+ struct in_addr *serv_in;
+ struct in_addr *clnt_in;
+{
+ int result, count = 20;
+
+ myip_initialized = 0;
+ myip_ifp = ifp;
+
+ revarp_in_progress = 1;
+ while (count--) {
+ revarprequest(ifp);
+ result = tsleep((caddr_t)&myip, PSOCK, "revarp", hz/2);
+ if (result != EWOULDBLOCK)
+ break;
+ }
+ revarp_in_progress = 0;
+
+ if (!myip_initialized)
+ return ENETUNREACH;
+
+ bcopy((caddr_t)&srv_ip, serv_in, sizeof(*serv_in));
+ bcopy((caddr_t)&myip, clnt_in, sizeof(*clnt_in));
+ return 0;
+}
+
+
+
+#ifdef DDB
+
+#include <machine/db_machdep.h>
+#include <ddb/db_interface.h>
+#include <ddb/db_output.h>
+static void
+db_print_sa(sa)
+ struct sockaddr *sa;
+{
+ int len;
+ u_char *p;
+
+ if (sa == 0) {
+ db_printf("[NULL]");
+ return;
+ }
+
+ p = (u_char*)sa;
+ len = sa->sa_len;
+ db_printf("[");
+ while (len > 0) {
+ db_printf("%d", *p);
+ p++; len--;
+ if (len) db_printf(",");
+ }
+ db_printf("]\n");
+}
+static void
+db_print_ifa(ifa)
+ struct ifaddr *ifa;
+{
+ if (ifa == 0)
+ return;
+ db_printf(" ifa_addr=");
+ db_print_sa(ifa->ifa_addr);
+ db_printf(" ifa_dsta=");
+ db_print_sa(ifa->ifa_dstaddr);
+ db_printf(" ifa_mask=");
+ db_print_sa(ifa->ifa_netmask);
+ db_printf(" flags=0x%x,refcnt=%d,metric=%d\n",
+ ifa->ifa_flags,
+ ifa->ifa_refcnt,
+ ifa->ifa_metric);
+}
+static void
+db_print_llinfo(li)
+ caddr_t li;
+{
+ struct llinfo_arp *la;
+
+ if (li == 0)
+ return;
+ la = (struct llinfo_arp *)li;
+ db_printf(" la_rt=%p la_hold=%p, la_asked=0x%lx\n",
+ la->la_rt, la->la_hold, la->la_asked);
+}
+/*
+ * Function to pass to rn_walktree().
+ * Return non-zero error to abort walk.
+ */
+static int
+db_show_radix_node(rn, w)
+ struct radix_node *rn;
+ void *w;
+{
+ struct rtentry *rt = (struct rtentry *)rn;
+
+ db_printf("rtentry=%p", rt);
+
+ db_printf(" flags=0x%x refcnt=%d use=%ld expire=%ld\n",
+ rt->rt_flags, rt->rt_refcnt,
+ rt->rt_use, rt->rt_expire);
+
+ db_printf(" key="); db_print_sa(rt_key(rt));
+ db_printf(" mask="); db_print_sa(rt_mask(rt));
+ db_printf(" gw="); db_print_sa(rt->rt_gateway);
+
+ db_printf(" ifp=%p ", rt->rt_ifp);
+ if (rt->rt_ifp)
+ db_printf("(%s)", rt->rt_ifp->if_xname);
+ else
+ db_printf("(NULL)");
+
+ db_printf(" ifa=%p\n", rt->rt_ifa);
+ db_print_ifa(rt->rt_ifa);
+
+ db_printf(" genmask="); db_print_sa(rt->rt_genmask);
+
+ db_printf(" gwroute=%p llinfo=%p\n",
+ rt->rt_gwroute, rt->rt_llinfo);
+ db_print_llinfo(rt->rt_llinfo);
+
return (0);
}
+/*
+ * Function to print all the route trees.
+ * Use this from ddb: "call db_show_arptab"
+ */
+int
+db_show_arptab()
+{
+ struct radix_node_head *rnh;
+ rnh = rt_tables[AF_INET];
+ db_printf("Route tree for AF_INET\n");
+ if (rnh == NULL) {
+ db_printf(" (not initialized)\n");
+ return (0);
+ }
+ rn_walktree(rnh, db_show_radix_node, NULL);
+ return (0);
+}
+#endif
+#endif /* INET */

0 comments on commit cc83b69

Please sign in to comment.