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