Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/stand/libsa/arp.c
34677 views
1
/* $NetBSD: arp.c,v 1.18 1997/07/07 15:52:49 drochner Exp $ */
2
3
/*
4
* Copyright (c) 1992 Regents of the University of California.
5
* All rights reserved.
6
*
7
* This software was developed by the Computer Systems Engineering group
8
* at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
9
* contributed to Berkeley.
10
*
11
* Redistribution and use in source and binary forms, with or without
12
* modification, are permitted provided that the following conditions
13
* are met:
14
* 1. Redistributions of source code must retain the above copyright
15
* notice, this list of conditions and the following disclaimer.
16
* 2. Redistributions in binary form must reproduce the above copyright
17
* notice, this list of conditions and the following disclaimer in the
18
* documentation and/or other materials provided with the distribution.
19
* 3. Neither the name of the University nor the names of its contributors
20
* may be used to endorse or promote products derived from this software
21
* without specific prior written permission.
22
*
23
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33
* SUCH DAMAGE.
34
*/
35
36
#include <sys/types.h>
37
#include <sys/socket.h>
38
#include <net/if.h>
39
#include <netinet/in.h>
40
#include <netinet/if_ether.h>
41
42
#include <netinet/in_systm.h>
43
44
#include <string.h>
45
46
#include "stand.h"
47
#include "net.h"
48
49
/* Cache stuff */
50
#define ARP_NUM 8 /* need at most 3 arp entries */
51
52
struct arp_list {
53
struct in_addr addr;
54
u_char ea[6];
55
} arp_list[ARP_NUM] = {
56
/* XXX - net order `INADDR_BROADCAST' must be a constant */
57
{ {0xffffffff}, BA }
58
};
59
int arp_num = 1;
60
61
/* Local forwards */
62
static ssize_t arpsend(struct iodesc *, void *, size_t);
63
static ssize_t arprecv(struct iodesc *, void **, void **, time_t, void *);
64
65
/* Broadcast an ARP packet, asking who has addr on interface d */
66
u_char *
67
arpwhohas(struct iodesc *d, struct in_addr addr)
68
{
69
int i;
70
struct ether_arp *ah;
71
struct arp_list *al;
72
void *pkt;
73
struct {
74
struct ether_header eh;
75
struct {
76
struct ether_arp arp;
77
u_char pad[18]; /* 60 - sizeof(...) */
78
} data;
79
} wbuf;
80
81
/* Try for cached answer first */
82
for (i = 0, al = arp_list; i < arp_num; ++i, ++al)
83
if (addr.s_addr == al->addr.s_addr)
84
return (al->ea);
85
86
/* Don't overflow cache */
87
if (arp_num > ARP_NUM - 1) {
88
arp_num = 1; /* recycle */
89
printf("arpwhohas: overflowed arp_list!\n");
90
}
91
92
#ifdef ARP_DEBUG
93
if (debug)
94
printf("arpwhohas: send request for %s\n", inet_ntoa(addr));
95
#endif
96
97
bzero((char*)&wbuf.data, sizeof(wbuf.data));
98
ah = &wbuf.data.arp;
99
ah->arp_hrd = htons(ARPHRD_ETHER);
100
ah->arp_pro = htons(ETHERTYPE_IP);
101
ah->arp_hln = sizeof(ah->arp_sha); /* hardware address length */
102
ah->arp_pln = sizeof(ah->arp_spa); /* protocol address length */
103
ah->arp_op = htons(ARPOP_REQUEST);
104
MACPY(d->myea, ah->arp_sha);
105
bcopy(&d->myip, ah->arp_spa, sizeof(ah->arp_spa));
106
/* Leave zeros in arp_tha */
107
bcopy(&addr, ah->arp_tpa, sizeof(ah->arp_tpa));
108
109
/* Store ip address in cache (incomplete entry). */
110
al->addr = addr;
111
112
pkt = NULL;
113
ah = NULL;
114
i = sendrecv(d,
115
arpsend, &wbuf.data, sizeof(wbuf.data),
116
arprecv, &pkt, (void **)&ah, NULL);
117
if (i == -1) {
118
panic("arp: no response for %s",
119
inet_ntoa(addr));
120
}
121
122
/* Store ethernet address in cache */
123
#ifdef ARP_DEBUG
124
if (debug) {
125
struct ether_header *eh;
126
127
eh = (struct ether_header *)((uintptr_t)pkt + ETHER_ALIGN);
128
printf("arp: response from %s\n",
129
ether_sprintf(eh->ether_shost));
130
printf("arp: cacheing %s --> %s\n",
131
inet_ntoa(addr), ether_sprintf(ah->arp_sha));
132
}
133
#endif
134
MACPY(ah->arp_sha, al->ea);
135
++arp_num;
136
137
free(pkt);
138
return (al->ea);
139
}
140
141
static ssize_t
142
arpsend(struct iodesc *d, void *pkt, size_t len)
143
{
144
145
#ifdef ARP_DEBUG
146
if (debug)
147
printf("arpsend: called\n");
148
#endif
149
150
return (sendether(d, pkt, len, bcea, ETHERTYPE_ARP));
151
}
152
153
/*
154
* Returns 0 if this is the packet we're waiting for
155
* else -1 (and errno == 0)
156
*/
157
static ssize_t
158
arprecv(struct iodesc *d, void **pkt, void **payload, time_t tleft, void *extra)
159
{
160
ssize_t n;
161
struct ether_arp *ah;
162
uint16_t etype; /* host order */
163
void *ptr;
164
165
#ifdef ARP_DEBUG
166
if (debug)
167
printf("arprecv: ");
168
#endif
169
170
ptr = NULL;
171
n = readether(d, &ptr, (void **)&ah, tleft, &etype);
172
errno = 0; /* XXX */
173
if (n == -1 || n < sizeof(struct ether_arp)) {
174
#ifdef ARP_DEBUG
175
if (debug)
176
printf("bad len=%zd\n", n);
177
#endif
178
free(ptr);
179
return (-1);
180
}
181
182
if (etype != ETHERTYPE_ARP) {
183
#ifdef ARP_DEBUG
184
if (debug)
185
printf("not arp type=%d\n", etype);
186
#endif
187
free(ptr);
188
return (-1);
189
}
190
191
/* Ethernet address now checked in readether() */
192
if (ah->arp_hrd != htons(ARPHRD_ETHER) ||
193
ah->arp_pro != htons(ETHERTYPE_IP) ||
194
ah->arp_hln != sizeof(ah->arp_sha) ||
195
ah->arp_pln != sizeof(ah->arp_spa) )
196
{
197
#ifdef ARP_DEBUG
198
if (debug)
199
printf("bad hrd/pro/hln/pln\n");
200
#endif
201
free(ptr);
202
return (-1);
203
}
204
205
if (ah->arp_op == htons(ARPOP_REQUEST)) {
206
#ifdef ARP_DEBUG
207
if (debug)
208
printf("is request\n");
209
#endif
210
arp_reply(d, ah);
211
free(ptr);
212
return (-1);
213
}
214
215
if (ah->arp_op != htons(ARPOP_REPLY)) {
216
#ifdef ARP_DEBUG
217
if (debug)
218
printf("not ARP reply\n");
219
#endif
220
free(ptr);
221
return (-1);
222
}
223
224
/* Is the reply from the source we want? */
225
if (bcmp(&arp_list[arp_num].addr,
226
ah->arp_spa, sizeof(ah->arp_spa)))
227
{
228
#ifdef ARP_DEBUG
229
if (debug)
230
printf("unwanted address\n");
231
#endif
232
free(ptr);
233
return (-1);
234
}
235
/* We don't care who the reply was sent to. */
236
237
/* We have our answer. */
238
#ifdef ARP_DEBUG
239
if (debug)
240
printf("got it\n");
241
#endif
242
*pkt = ptr;
243
*payload = ah;
244
return (n);
245
}
246
247
/*
248
* Convert an ARP request into a reply and send it.
249
* Notes: Re-uses buffer. Pad to length = 46.
250
*/
251
void
252
arp_reply(struct iodesc *d, void *pkt)
253
{
254
struct ether_arp *arp = pkt;
255
256
if (arp->arp_hrd != htons(ARPHRD_ETHER) ||
257
arp->arp_pro != htons(ETHERTYPE_IP) ||
258
arp->arp_hln != sizeof(arp->arp_sha) ||
259
arp->arp_pln != sizeof(arp->arp_spa) )
260
{
261
#ifdef ARP_DEBUG
262
if (debug)
263
printf("arp_reply: bad hrd/pro/hln/pln\n");
264
#endif
265
return;
266
}
267
268
if (arp->arp_op != htons(ARPOP_REQUEST)) {
269
#ifdef ARP_DEBUG
270
if (debug)
271
printf("arp_reply: not request!\n");
272
#endif
273
return;
274
}
275
276
/* If we are not the target, ignore the request. */
277
if (bcmp(arp->arp_tpa, &d->myip, sizeof(arp->arp_tpa)))
278
return;
279
280
#ifdef ARP_DEBUG
281
if (debug) {
282
printf("arp_reply: to %s\n", ether_sprintf(arp->arp_sha));
283
}
284
#endif
285
286
arp->arp_op = htons(ARPOP_REPLY);
287
/* source becomes target */
288
bcopy(arp->arp_sha, arp->arp_tha, sizeof(arp->arp_tha));
289
bcopy(arp->arp_spa, arp->arp_tpa, sizeof(arp->arp_tpa));
290
/* here becomes source */
291
bcopy(d->myea, arp->arp_sha, sizeof(arp->arp_sha));
292
bcopy(&d->myip, arp->arp_spa, sizeof(arp->arp_spa));
293
294
/*
295
* No need to get fancy here. If the send fails, the
296
* requestor will just ask again.
297
*/
298
(void) sendether(d, pkt, sizeof(*arp) + 18,
299
arp->arp_tha, ETHERTYPE_ARP);
300
}
301
302