arp.c revision 84221
138451Smsmith/*	$NetBSD: arp.c,v 1.18 1997/07/07 15:52:49 drochner Exp $	*/
238451Smsmith
338451Smsmith/*
438451Smsmith * Copyright (c) 1992 Regents of the University of California.
538451Smsmith * All rights reserved.
638451Smsmith *
738451Smsmith * This software was developed by the Computer Systems Engineering group
838451Smsmith * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
938451Smsmith * contributed to Berkeley.
1038451Smsmith *
1138451Smsmith * Redistribution and use in source and binary forms, with or without
1238451Smsmith * modification, are permitted provided that the following conditions
1338451Smsmith * are met:
1438451Smsmith * 1. Redistributions of source code must retain the above copyright
1538451Smsmith *    notice, this list of conditions and the following disclaimer.
1638451Smsmith * 2. Redistributions in binary form must reproduce the above copyright
1738451Smsmith *    notice, this list of conditions and the following disclaimer in the
1838451Smsmith *    documentation and/or other materials provided with the distribution.
1938451Smsmith * 3. All advertising materials mentioning features or use of this software
2038451Smsmith *    must display the following acknowledgement:
2138451Smsmith *	This product includes software developed by the University of
2238451Smsmith *	California, Lawrence Berkeley Laboratory and its contributors.
2338451Smsmith * 4. Neither the name of the University nor the names of its contributors
2438451Smsmith *    may be used to endorse or promote products derived from this software
2538451Smsmith *    without specific prior written permission.
2638451Smsmith *
2738451Smsmith * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2838451Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2938451Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3038451Smsmith * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
3138451Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3238451Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3338451Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3438451Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3538451Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3638451Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3738451Smsmith * SUCH DAMAGE.
3838451Smsmith *
3938451Smsmith * @(#) Header: arp.c,v 1.5 93/07/15 05:52:26 leres Exp  (LBL)
4038451Smsmith */
4138451Smsmith
4284221Sdillon#include <sys/cdefs.h>
4384221Sdillon__FBSDID("$FreeBSD: head/lib/libstand/arp.c 84221 2001-09-30 22:28:01Z dillon $");
4484221Sdillon
4538451Smsmith#include <sys/types.h>
4638451Smsmith#include <sys/socket.h>
4738451Smsmith#include <net/if.h>
4838451Smsmith#include <netinet/in.h>
4938451Smsmith#include <netinet/if_ether.h>
5038451Smsmith
5138451Smsmith#include <netinet/in_systm.h>
5238451Smsmith
5338451Smsmith#include <string.h>
5438451Smsmith
5538451Smsmith#include "stand.h"
5638451Smsmith#include "net.h"
5738451Smsmith
5838451Smsmith/* Cache stuff */
5938451Smsmith#define ARP_NUM 8			/* need at most 3 arp entries */
6038451Smsmith
6138451Smsmithstruct arp_list {
6238451Smsmith	struct in_addr	addr;
6338451Smsmith	u_char		ea[6];
6438451Smsmith} arp_list[ARP_NUM] = {
6538451Smsmith	/* XXX - net order `INADDR_BROADCAST' must be a constant */
6638451Smsmith	{ {0xffffffff}, BA }
6738451Smsmith};
6838451Smsmithint arp_num = 1;
6938451Smsmith
7038451Smsmith/* Local forwards */
7138451Smsmithstatic	ssize_t arpsend(struct iodesc *, void *, size_t);
7238451Smsmithstatic	ssize_t arprecv(struct iodesc *, void *, size_t, time_t);
7338451Smsmith
7438451Smsmith/* Broadcast an ARP packet, asking who has addr on interface d */
7538451Smsmithu_char *
7638451Smsmitharpwhohas(d, addr)
7738451Smsmith	register struct iodesc *d;
7838451Smsmith	struct in_addr addr;
7938451Smsmith{
8038451Smsmith	register int i;
8138451Smsmith	register struct ether_arp *ah;
8238451Smsmith	register struct arp_list *al;
8338451Smsmith	struct {
8438451Smsmith		struct ether_header eh;
8538451Smsmith		struct {
8638451Smsmith			struct ether_arp arp;
8738451Smsmith			u_char pad[18]; 	/* 60 - sizeof(...) */
8838451Smsmith		} data;
8938451Smsmith	} wbuf;
9038451Smsmith	struct {
9138451Smsmith		struct ether_header eh;
9238451Smsmith		struct {
9338451Smsmith			struct ether_arp arp;
9438451Smsmith			u_char pad[24]; 	/* extra space */
9538451Smsmith		} data;
9638451Smsmith	} rbuf;
9738451Smsmith
9838451Smsmith	/* Try for cached answer first */
9938451Smsmith	for (i = 0, al = arp_list; i < arp_num; ++i, ++al)
10038451Smsmith		if (addr.s_addr == al->addr.s_addr)
10138451Smsmith			return (al->ea);
10238451Smsmith
10338451Smsmith	/* Don't overflow cache */
10438451Smsmith	if (arp_num > ARP_NUM - 1) {
10538451Smsmith		arp_num = 1;	/* recycle */
10638451Smsmith		printf("arpwhohas: overflowed arp_list!\n");
10738451Smsmith	}
10838451Smsmith
10938451Smsmith#ifdef ARP_DEBUG
11038451Smsmith 	if (debug)
11138451Smsmith 	    printf("arpwhohas: send request for %s\n", inet_ntoa(addr));
11238451Smsmith#endif
11338451Smsmith
11438451Smsmith	bzero((char*)&wbuf.data, sizeof(wbuf.data));
11538451Smsmith	ah = &wbuf.data.arp;
11638451Smsmith	ah->arp_hrd = htons(ARPHRD_ETHER);
11738451Smsmith	ah->arp_pro = htons(ETHERTYPE_IP);
11838451Smsmith	ah->arp_hln = sizeof(ah->arp_sha); /* hardware address length */
11938451Smsmith	ah->arp_pln = sizeof(ah->arp_spa); /* protocol address length */
12038451Smsmith	ah->arp_op = htons(ARPOP_REQUEST);
12138451Smsmith	MACPY(d->myea, ah->arp_sha);
12238451Smsmith	bcopy(&d->myip, ah->arp_spa, sizeof(ah->arp_spa));
12338451Smsmith	/* Leave zeros in arp_tha */
12438451Smsmith	bcopy(&addr, ah->arp_tpa, sizeof(ah->arp_tpa));
12538451Smsmith
12638451Smsmith	/* Store ip address in cache (incomplete entry). */
12738451Smsmith	al->addr = addr;
12838451Smsmith
12938451Smsmith	i = sendrecv(d,
13038451Smsmith	    arpsend, &wbuf.data, sizeof(wbuf.data),
13138451Smsmith	    arprecv, &rbuf.data, sizeof(rbuf.data));
13238451Smsmith	if (i == -1) {
13338451Smsmith		panic("arp: no response for %s\n",
13438451Smsmith			  inet_ntoa(addr));
13538451Smsmith	}
13638451Smsmith
13738451Smsmith	/* Store ethernet address in cache */
13838451Smsmith	ah = &rbuf.data.arp;
13938451Smsmith#ifdef ARP_DEBUG
14038451Smsmith 	if (debug) {
14138451Smsmith		printf("arp: response from %s\n",
14238451Smsmith		    ether_sprintf(rbuf.eh.ether_shost));
14338451Smsmith		printf("arp: cacheing %s --> %s\n",
14438451Smsmith		    inet_ntoa(addr), ether_sprintf(ah->arp_sha));
14538451Smsmith	}
14638451Smsmith#endif
14738451Smsmith	MACPY(ah->arp_sha, al->ea);
14838451Smsmith	++arp_num;
14938451Smsmith
15038451Smsmith	return (al->ea);
15138451Smsmith}
15238451Smsmith
15338451Smsmithstatic ssize_t
15438451Smsmitharpsend(d, pkt, len)
15538451Smsmith	register struct iodesc *d;
15638451Smsmith	register void *pkt;
15738451Smsmith	register size_t len;
15838451Smsmith{
15938451Smsmith
16038451Smsmith#ifdef ARP_DEBUG
16138451Smsmith 	if (debug)
16238451Smsmith		printf("arpsend: called\n");
16338451Smsmith#endif
16438451Smsmith
16538451Smsmith	return (sendether(d, pkt, len, bcea, ETHERTYPE_ARP));
16638451Smsmith}
16738451Smsmith
16838451Smsmith/*
16938451Smsmith * Returns 0 if this is the packet we're waiting for
17038451Smsmith * else -1 (and errno == 0)
17138451Smsmith */
17238451Smsmithstatic ssize_t
17338451Smsmitharprecv(d, pkt, len, tleft)
17438451Smsmith	register struct iodesc *d;
17538451Smsmith	register void *pkt;
17638451Smsmith	register size_t len;
17738451Smsmith	time_t tleft;
17838451Smsmith{
17938451Smsmith	register ssize_t n;
18038451Smsmith	register struct ether_arp *ah;
18138451Smsmith	u_int16_t etype;	/* host order */
18238451Smsmith
18338451Smsmith#ifdef ARP_DEBUG
18438451Smsmith 	if (debug)
18538451Smsmith		printf("arprecv: ");
18638451Smsmith#endif
18738451Smsmith
18838451Smsmith	n = readether(d, pkt, len, tleft, &etype);
18938451Smsmith	errno = 0;	/* XXX */
19038451Smsmith	if (n == -1 || n < sizeof(struct ether_arp)) {
19138451Smsmith#ifdef ARP_DEBUG
19238451Smsmith		if (debug)
19338451Smsmith			printf("bad len=%d\n", n);
19438451Smsmith#endif
19538451Smsmith		return (-1);
19638451Smsmith	}
19738451Smsmith
19838451Smsmith	if (etype != ETHERTYPE_ARP) {
19938451Smsmith#ifdef ARP_DEBUG
20038451Smsmith		if (debug)
20138451Smsmith			printf("not arp type=%d\n", etype);
20238451Smsmith#endif
20338451Smsmith		return (-1);
20438451Smsmith	}
20538451Smsmith
20638451Smsmith	/* Ethernet address now checked in readether() */
20738451Smsmith
20838451Smsmith	ah = (struct ether_arp *)pkt;
20938451Smsmith	if (ah->arp_hrd != htons(ARPHRD_ETHER) ||
21038451Smsmith	    ah->arp_pro != htons(ETHERTYPE_IP) ||
21138451Smsmith	    ah->arp_hln != sizeof(ah->arp_sha) ||
21238451Smsmith	    ah->arp_pln != sizeof(ah->arp_spa) )
21338451Smsmith	{
21438451Smsmith#ifdef ARP_DEBUG
21538451Smsmith		if (debug)
21638451Smsmith			printf("bad hrd/pro/hln/pln\n");
21738451Smsmith#endif
21838451Smsmith		return (-1);
21938451Smsmith	}
22038451Smsmith
22138451Smsmith	if (ah->arp_op == htons(ARPOP_REQUEST)) {
22238451Smsmith#ifdef ARP_DEBUG
22338451Smsmith		if (debug)
22438451Smsmith			printf("is request\n");
22538451Smsmith#endif
22638451Smsmith		arp_reply(d, ah);
22738451Smsmith		return (-1);
22838451Smsmith	}
22938451Smsmith
23038451Smsmith	if (ah->arp_op != htons(ARPOP_REPLY)) {
23138451Smsmith#ifdef ARP_DEBUG
23238451Smsmith		if (debug)
23338451Smsmith			printf("not ARP reply\n");
23438451Smsmith#endif
23538451Smsmith		return (-1);
23638451Smsmith	}
23738451Smsmith
23838451Smsmith	/* Is the reply from the source we want? */
23938451Smsmith	if (bcmp(&arp_list[arp_num].addr,
24038451Smsmith			 ah->arp_spa, sizeof(ah->arp_spa)))
24138451Smsmith	{
24238451Smsmith#ifdef ARP_DEBUG
24338451Smsmith		if (debug)
24438451Smsmith			printf("unwanted address\n");
24538451Smsmith#endif
24638451Smsmith		return (-1);
24738451Smsmith	}
24838451Smsmith	/* We don't care who the reply was sent to. */
24938451Smsmith
25038451Smsmith	/* We have our answer. */
25138451Smsmith#ifdef ARP_DEBUG
25238451Smsmith 	if (debug)
25338451Smsmith		printf("got it\n");
25438451Smsmith#endif
25538451Smsmith	return (n);
25638451Smsmith}
25738451Smsmith
25838451Smsmith/*
25938451Smsmith * Convert an ARP request into a reply and send it.
26038451Smsmith * Notes:  Re-uses buffer.  Pad to length = 46.
26138451Smsmith */
26238451Smsmithvoid
26338451Smsmitharp_reply(d, pkt)
26438451Smsmith	register struct iodesc *d;
26538451Smsmith	register void *pkt;		/* the request */
26638451Smsmith{
26738451Smsmith	struct ether_arp *arp = pkt;
26838451Smsmith
26938451Smsmith	if (arp->arp_hrd != htons(ARPHRD_ETHER) ||
27038451Smsmith	    arp->arp_pro != htons(ETHERTYPE_IP) ||
27138451Smsmith	    arp->arp_hln != sizeof(arp->arp_sha) ||
27238451Smsmith	    arp->arp_pln != sizeof(arp->arp_spa) )
27338451Smsmith	{
27438451Smsmith#ifdef ARP_DEBUG
27538451Smsmith		if (debug)
27638451Smsmith			printf("arp_reply: bad hrd/pro/hln/pln\n");
27738451Smsmith#endif
27838451Smsmith		return;
27938451Smsmith	}
28038451Smsmith
28138451Smsmith	if (arp->arp_op != htons(ARPOP_REQUEST)) {
28238451Smsmith#ifdef ARP_DEBUG
28338451Smsmith		if (debug)
28438451Smsmith			printf("arp_reply: not request!\n");
28538451Smsmith#endif
28638451Smsmith		return;
28738451Smsmith	}
28838451Smsmith
28938451Smsmith	/* If we are not the target, ignore the request. */
29038451Smsmith	if (bcmp(arp->arp_tpa, &d->myip, sizeof(arp->arp_tpa)))
29138451Smsmith		return;
29238451Smsmith
29338451Smsmith#ifdef ARP_DEBUG
29438451Smsmith	if (debug) {
29538451Smsmith		printf("arp_reply: to %s\n", ether_sprintf(arp->arp_sha));
29638451Smsmith	}
29738451Smsmith#endif
29838451Smsmith
29938451Smsmith	arp->arp_op = htons(ARPOP_REPLY);
30038451Smsmith	/* source becomes target */
30138451Smsmith	bcopy(arp->arp_sha, arp->arp_tha, sizeof(arp->arp_tha));
30238451Smsmith	bcopy(arp->arp_spa, arp->arp_tpa, sizeof(arp->arp_tpa));
30338451Smsmith	/* here becomes source */
30438451Smsmith	bcopy(d->myea,  arp->arp_sha, sizeof(arp->arp_sha));
30538451Smsmith	bcopy(&d->myip, arp->arp_spa, sizeof(arp->arp_spa));
30638451Smsmith
30738451Smsmith	/*
30838451Smsmith	 * No need to get fancy here.  If the send fails, the
30938451Smsmith	 * requestor will just ask again.
31038451Smsmith	 */
31138451Smsmith	(void) sendether(d, pkt, sizeof(*arp) + 18,
31238451Smsmith	                 arp->arp_tha, ETHERTYPE_ARP);
31338451Smsmith}
314