arp.c revision 38451
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
4238451Smsmith#include <sys/types.h>
4338451Smsmith#include <sys/socket.h>
4438451Smsmith#include <net/if.h>
4538451Smsmith#include <netinet/in.h>
4638451Smsmith#include <netinet/if_ether.h>
4738451Smsmith
4838451Smsmith#include <netinet/in_systm.h>
4938451Smsmith
5038451Smsmith#include <string.h>
5138451Smsmith
5238451Smsmith#include "stand.h"
5338451Smsmith#include "net.h"
5438451Smsmith
5538451Smsmith/* Cache stuff */
5638451Smsmith#define ARP_NUM 8			/* need at most 3 arp entries */
5738451Smsmith
5838451Smsmithstruct arp_list {
5938451Smsmith	struct in_addr	addr;
6038451Smsmith	u_char		ea[6];
6138451Smsmith} arp_list[ARP_NUM] = {
6238451Smsmith	/* XXX - net order `INADDR_BROADCAST' must be a constant */
6338451Smsmith	{ {0xffffffff}, BA }
6438451Smsmith};
6538451Smsmithint arp_num = 1;
6638451Smsmith
6738451Smsmith/* Local forwards */
6838451Smsmithstatic	ssize_t arpsend(struct iodesc *, void *, size_t);
6938451Smsmithstatic	ssize_t arprecv(struct iodesc *, void *, size_t, time_t);
7038451Smsmith
7138451Smsmith/* Broadcast an ARP packet, asking who has addr on interface d */
7238451Smsmithu_char *
7338451Smsmitharpwhohas(d, addr)
7438451Smsmith	register struct iodesc *d;
7538451Smsmith	struct in_addr addr;
7638451Smsmith{
7738451Smsmith	register int i;
7838451Smsmith	register struct ether_arp *ah;
7938451Smsmith	register struct arp_list *al;
8038451Smsmith	struct {
8138451Smsmith		struct ether_header eh;
8238451Smsmith		struct {
8338451Smsmith			struct ether_arp arp;
8438451Smsmith			u_char pad[18]; 	/* 60 - sizeof(...) */
8538451Smsmith		} data;
8638451Smsmith	} wbuf;
8738451Smsmith	struct {
8838451Smsmith		struct ether_header eh;
8938451Smsmith		struct {
9038451Smsmith			struct ether_arp arp;
9138451Smsmith			u_char pad[24]; 	/* extra space */
9238451Smsmith		} data;
9338451Smsmith	} rbuf;
9438451Smsmith
9538451Smsmith	/* Try for cached answer first */
9638451Smsmith	for (i = 0, al = arp_list; i < arp_num; ++i, ++al)
9738451Smsmith		if (addr.s_addr == al->addr.s_addr)
9838451Smsmith			return (al->ea);
9938451Smsmith
10038451Smsmith	/* Don't overflow cache */
10138451Smsmith	if (arp_num > ARP_NUM - 1) {
10238451Smsmith		arp_num = 1;	/* recycle */
10338451Smsmith		printf("arpwhohas: overflowed arp_list!\n");
10438451Smsmith	}
10538451Smsmith
10638451Smsmith#ifdef ARP_DEBUG
10738451Smsmith 	if (debug)
10838451Smsmith 	    printf("arpwhohas: send request for %s\n", inet_ntoa(addr));
10938451Smsmith#endif
11038451Smsmith
11138451Smsmith	bzero((char*)&wbuf.data, sizeof(wbuf.data));
11238451Smsmith	ah = &wbuf.data.arp;
11338451Smsmith	ah->arp_hrd = htons(ARPHRD_ETHER);
11438451Smsmith	ah->arp_pro = htons(ETHERTYPE_IP);
11538451Smsmith	ah->arp_hln = sizeof(ah->arp_sha); /* hardware address length */
11638451Smsmith	ah->arp_pln = sizeof(ah->arp_spa); /* protocol address length */
11738451Smsmith	ah->arp_op = htons(ARPOP_REQUEST);
11838451Smsmith	MACPY(d->myea, ah->arp_sha);
11938451Smsmith	bcopy(&d->myip, ah->arp_spa, sizeof(ah->arp_spa));
12038451Smsmith	/* Leave zeros in arp_tha */
12138451Smsmith	bcopy(&addr, ah->arp_tpa, sizeof(ah->arp_tpa));
12238451Smsmith
12338451Smsmith	/* Store ip address in cache (incomplete entry). */
12438451Smsmith	al->addr = addr;
12538451Smsmith
12638451Smsmith	i = sendrecv(d,
12738451Smsmith	    arpsend, &wbuf.data, sizeof(wbuf.data),
12838451Smsmith	    arprecv, &rbuf.data, sizeof(rbuf.data));
12938451Smsmith	if (i == -1) {
13038451Smsmith		panic("arp: no response for %s\n",
13138451Smsmith			  inet_ntoa(addr));
13238451Smsmith	}
13338451Smsmith
13438451Smsmith	/* Store ethernet address in cache */
13538451Smsmith	ah = &rbuf.data.arp;
13638451Smsmith#ifdef ARP_DEBUG
13738451Smsmith 	if (debug) {
13838451Smsmith		printf("arp: response from %s\n",
13938451Smsmith		    ether_sprintf(rbuf.eh.ether_shost));
14038451Smsmith		printf("arp: cacheing %s --> %s\n",
14138451Smsmith		    inet_ntoa(addr), ether_sprintf(ah->arp_sha));
14238451Smsmith	}
14338451Smsmith#endif
14438451Smsmith	MACPY(ah->arp_sha, al->ea);
14538451Smsmith	++arp_num;
14638451Smsmith
14738451Smsmith	return (al->ea);
14838451Smsmith}
14938451Smsmith
15038451Smsmithstatic ssize_t
15138451Smsmitharpsend(d, pkt, len)
15238451Smsmith	register struct iodesc *d;
15338451Smsmith	register void *pkt;
15438451Smsmith	register size_t len;
15538451Smsmith{
15638451Smsmith
15738451Smsmith#ifdef ARP_DEBUG
15838451Smsmith 	if (debug)
15938451Smsmith		printf("arpsend: called\n");
16038451Smsmith#endif
16138451Smsmith
16238451Smsmith	return (sendether(d, pkt, len, bcea, ETHERTYPE_ARP));
16338451Smsmith}
16438451Smsmith
16538451Smsmith/*
16638451Smsmith * Returns 0 if this is the packet we're waiting for
16738451Smsmith * else -1 (and errno == 0)
16838451Smsmith */
16938451Smsmithstatic ssize_t
17038451Smsmitharprecv(d, pkt, len, tleft)
17138451Smsmith	register struct iodesc *d;
17238451Smsmith	register void *pkt;
17338451Smsmith	register size_t len;
17438451Smsmith	time_t tleft;
17538451Smsmith{
17638451Smsmith	register ssize_t n;
17738451Smsmith	register struct ether_arp *ah;
17838451Smsmith	u_int16_t etype;	/* host order */
17938451Smsmith
18038451Smsmith#ifdef ARP_DEBUG
18138451Smsmith 	if (debug)
18238451Smsmith		printf("arprecv: ");
18338451Smsmith#endif
18438451Smsmith
18538451Smsmith	n = readether(d, pkt, len, tleft, &etype);
18638451Smsmith	errno = 0;	/* XXX */
18738451Smsmith	if (n == -1 || n < sizeof(struct ether_arp)) {
18838451Smsmith#ifdef ARP_DEBUG
18938451Smsmith		if (debug)
19038451Smsmith			printf("bad len=%d\n", n);
19138451Smsmith#endif
19238451Smsmith		return (-1);
19338451Smsmith	}
19438451Smsmith
19538451Smsmith	if (etype != ETHERTYPE_ARP) {
19638451Smsmith#ifdef ARP_DEBUG
19738451Smsmith		if (debug)
19838451Smsmith			printf("not arp type=%d\n", etype);
19938451Smsmith#endif
20038451Smsmith		return (-1);
20138451Smsmith	}
20238451Smsmith
20338451Smsmith	/* Ethernet address now checked in readether() */
20438451Smsmith
20538451Smsmith	ah = (struct ether_arp *)pkt;
20638451Smsmith	if (ah->arp_hrd != htons(ARPHRD_ETHER) ||
20738451Smsmith	    ah->arp_pro != htons(ETHERTYPE_IP) ||
20838451Smsmith	    ah->arp_hln != sizeof(ah->arp_sha) ||
20938451Smsmith	    ah->arp_pln != sizeof(ah->arp_spa) )
21038451Smsmith	{
21138451Smsmith#ifdef ARP_DEBUG
21238451Smsmith		if (debug)
21338451Smsmith			printf("bad hrd/pro/hln/pln\n");
21438451Smsmith#endif
21538451Smsmith		return (-1);
21638451Smsmith	}
21738451Smsmith
21838451Smsmith	if (ah->arp_op == htons(ARPOP_REQUEST)) {
21938451Smsmith#ifdef ARP_DEBUG
22038451Smsmith		if (debug)
22138451Smsmith			printf("is request\n");
22238451Smsmith#endif
22338451Smsmith		arp_reply(d, ah);
22438451Smsmith		return (-1);
22538451Smsmith	}
22638451Smsmith
22738451Smsmith	if (ah->arp_op != htons(ARPOP_REPLY)) {
22838451Smsmith#ifdef ARP_DEBUG
22938451Smsmith		if (debug)
23038451Smsmith			printf("not ARP reply\n");
23138451Smsmith#endif
23238451Smsmith		return (-1);
23338451Smsmith	}
23438451Smsmith
23538451Smsmith	/* Is the reply from the source we want? */
23638451Smsmith	if (bcmp(&arp_list[arp_num].addr,
23738451Smsmith			 ah->arp_spa, sizeof(ah->arp_spa)))
23838451Smsmith	{
23938451Smsmith#ifdef ARP_DEBUG
24038451Smsmith		if (debug)
24138451Smsmith			printf("unwanted address\n");
24238451Smsmith#endif
24338451Smsmith		return (-1);
24438451Smsmith	}
24538451Smsmith	/* We don't care who the reply was sent to. */
24638451Smsmith
24738451Smsmith	/* We have our answer. */
24838451Smsmith#ifdef ARP_DEBUG
24938451Smsmith 	if (debug)
25038451Smsmith		printf("got it\n");
25138451Smsmith#endif
25238451Smsmith	return (n);
25338451Smsmith}
25438451Smsmith
25538451Smsmith/*
25638451Smsmith * Convert an ARP request into a reply and send it.
25738451Smsmith * Notes:  Re-uses buffer.  Pad to length = 46.
25838451Smsmith */
25938451Smsmithvoid
26038451Smsmitharp_reply(d, pkt)
26138451Smsmith	register struct iodesc *d;
26238451Smsmith	register void *pkt;		/* the request */
26338451Smsmith{
26438451Smsmith	struct ether_arp *arp = pkt;
26538451Smsmith
26638451Smsmith	if (arp->arp_hrd != htons(ARPHRD_ETHER) ||
26738451Smsmith	    arp->arp_pro != htons(ETHERTYPE_IP) ||
26838451Smsmith	    arp->arp_hln != sizeof(arp->arp_sha) ||
26938451Smsmith	    arp->arp_pln != sizeof(arp->arp_spa) )
27038451Smsmith	{
27138451Smsmith#ifdef ARP_DEBUG
27238451Smsmith		if (debug)
27338451Smsmith			printf("arp_reply: bad hrd/pro/hln/pln\n");
27438451Smsmith#endif
27538451Smsmith		return;
27638451Smsmith	}
27738451Smsmith
27838451Smsmith	if (arp->arp_op != htons(ARPOP_REQUEST)) {
27938451Smsmith#ifdef ARP_DEBUG
28038451Smsmith		if (debug)
28138451Smsmith			printf("arp_reply: not request!\n");
28238451Smsmith#endif
28338451Smsmith		return;
28438451Smsmith	}
28538451Smsmith
28638451Smsmith	/* If we are not the target, ignore the request. */
28738451Smsmith	if (bcmp(arp->arp_tpa, &d->myip, sizeof(arp->arp_tpa)))
28838451Smsmith		return;
28938451Smsmith
29038451Smsmith#ifdef ARP_DEBUG
29138451Smsmith	if (debug) {
29238451Smsmith		printf("arp_reply: to %s\n", ether_sprintf(arp->arp_sha));
29338451Smsmith	}
29438451Smsmith#endif
29538451Smsmith
29638451Smsmith	arp->arp_op = htons(ARPOP_REPLY);
29738451Smsmith	/* source becomes target */
29838451Smsmith	bcopy(arp->arp_sha, arp->arp_tha, sizeof(arp->arp_tha));
29938451Smsmith	bcopy(arp->arp_spa, arp->arp_tpa, sizeof(arp->arp_tpa));
30038451Smsmith	/* here becomes source */
30138451Smsmith	bcopy(d->myea,  arp->arp_sha, sizeof(arp->arp_sha));
30238451Smsmith	bcopy(&d->myip, arp->arp_spa, sizeof(arp->arp_spa));
30338451Smsmith
30438451Smsmith	/*
30538451Smsmith	 * No need to get fancy here.  If the send fails, the
30638451Smsmith	 * requestor will just ask again.
30738451Smsmith	 */
30838451Smsmith	(void) sendether(d, pkt, sizeof(*arp) + 18,
30938451Smsmith	                 arp->arp_tha, ETHERTYPE_ARP);
31038451Smsmith}
311