-
Notifications
You must be signed in to change notification settings - Fork 1
/
arp.c
466 lines (414 loc) · 14.7 KB
/
arp.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
/* File MSNARP.C
* ARP and RARP packet processor
*
* Copyright (C) 1991, University of Waterloo.
* Copyright (C) 1982, 1999, Trustees of Columbia University in the
* City of New York. The MS-DOS Kermit software may not be, in whole
* or in part, licensed or sold for profit as a software product itself,
* nor may it be included in or distributed with commercial products
* or otherwise distributed by commercial concerns to their clients
* or customers without written permission of the Office of Kermit
* Development and Distribution, Columbia University. This copyright
* notice must not be removed, altered, or obscured.
*
* Original version created by Erick Engelke of the University of
* Waterloo, Waterloo, Ontario, Canada.
* Adapted, modified, redesigned for MS-DOS Kermit by Joe R. Doupnik,
* Utah State University, jrd@cc.usu.edu, jrd@usu.Bitnet.
*
* Last edit
* 12 Jan 1995 v3.14
*
* Address Resolution Protocol RFC826.TXT
* Reverse Address Resolution Protocol RFC903.TXT
* Externals:
* ap_handler(pb) - returns 1 on handled correctly, 0 on problems
* arp_resolve - rets 1 on success, 0 on fail
* - does not return hardware address if passed NULL for buffer
*
*/
#include "tcp.h"
#include "netlibc.h"
#define MAX_ARP_DATA 10 /* cache entries */
#define MAX_ARP_ALIVE 300 /* cache lifetime, five minutes */
#define MAX_ARP_GRACE 100 /* additional grace upon expiration */
#define PLEN 4 /* bytes in an IP address longword */
#define NEW_EXPIRY /* refresh cache on the fly */
/* ARP and RARP header. Note that address lengths and hardware type ident
vary depending on frame type at the hardware level. The frame handler
(Packet Driver or ODI driver) will set these values. jrd */
typedef struct {
word hwType; /* hardware type ident */
word protType; /* protocol ident */
byte hlen; /* length of MAC hardware address */
byte plen; /* plen, length of protocol address */
word opcode;
byte sender_mac[6]; /* But smaller MAC_lens are usable */
longword sender_IP; /* by not referencing these entries*/
byte target_mac[6]; /* directly: use sender_mac+offset */
longword target_IP;
} arp_header;
typedef struct
{
longword ip; /* host IP number */
eth_address mac; /* mac address to use */
byte flags; /* cache entry status */
byte bits; /* reserved */
longword expiry; /* Bios tics when entry expires */
} arp_tables;
typedef struct
{
longword gate_ip;
} gate_tables;
/* ARP style op codes */
#define ARP_REQUEST 0x0100 /* ARP request */
#define ARP_REPLY 0x0200 /* ARP reply */
#define RARP_REQUEST 0x0300 /* RARP request */
#define RARP_REPLY 0x0400 /* RARP reply */
#define ARP_FLAG_NEED 0 /* cache state, no mac address yet */
#define ARP_FLAG_FOUND 1 /* have mac address */
#define ARP_FLAG_FIXED 2 /* cannot be removed */
#define ARP_FLAG_IMPOSTER 4 /* imposter response discovered */
extern longword ipbcast; /* IP broadcast address */
extern byte kdebug;
/* MAC_len and arp_hardware can be set by the packet frame routines */
word MAC_len = 6; /* bytes in MAC level hardware addr */
word arp_hardware = 0x0001; /* ARP, hardware ident, little end */
/*
* arp resolution cache - we zero fill it to save an initialization routine
*/
static arp_tables arp_data[MAX_ARP_DATA] = {0};
gate_tables arp_gate_data[MAX_GATE_DATA] = {0};
word arp_last_gateway = 0;
static word arp_index = 0; /* rotates round-robin */
static void arp_display(arp_header *, longword, longword);
/*
* arp_add_gateway
*/
void
arp_add_gateway(byte *data, longword ip)
{
if ((data == NULL) && (ip == 0L)) return; /* nothing to do */
if ((data != NULL) && (ip == 0L)) /* if text form given */
ip = aton(data); /* convert to 32 bit long */
if (arp_last_gateway >= MAX_GATE_DATA) return;
arp_gate_data[arp_last_gateway].gate_ip = ip;
arp_last_gateway++; /* used up another one */
}
longword
arp_rpt_gateway(int i) /* report IP of gateway i */
{
if (i >= 0 && i < MAX_GATE_DATA)
return (arp_gate_data[i].gate_ip);
else return (0L);
}
static void
arp_request(longword ip)
{
register arp_header *op;
longword temp;
if (ip == 0L || ip == 0xffffffffL)
return; /* can't ARP for these */
op = (arp_header *)eth_formatpacket(ð_brdcast[0], TYPE_ARP);
op->hwType = htons(arp_hardware); /* hardware frame */
op->protType = TYPE_IP; /* IP protocol */
op->hlen = (byte)(MAC_len & 0xff); /* MAC address len */
op->plen = PLEN; /* IP address len */
op->opcode = ARP_REQUEST;
/* our MAC address */
bcopy(ð_addr[6-MAC_len], op->sender_mac, MAC_len);
temp = htonl(my_ip_addr);
bcopy(&temp, &op->sender_mac[MAC_len], PLEN); /* our IP */
temp = htonl(ip);
bcopy(&temp, &op->sender_mac[MAC_len * 2 + PLEN], PLEN); /* host IP */
eth_send(sizeof(arp_header)); /* send the packet */
if (kdebug & DEBUG_STATUS)
arp_display(op, my_ip_addr, ip);
}
/* Search ARP table, given an IP address ip. Create an entry if
create is != 0.
Return pointer to entry if IP is in the table (perhaps from a
create request), else NULL for no entry found.
*/
static arp_tables *
arp_search(longword ip, int create)
{
register int i;
register arp_tables *arp_ptr;
for (i = 0; i < MAX_ARP_DATA; i++)
if (ip == arp_data[i].ip)
return(&arp_data[i]); /* found an entry */
if (create == 0) /* do not create new one */
return (NULL);
/* pick an old or empty one */
for (i = 0; i < MAX_ARP_DATA; i++)
{
arp_ptr = &arp_data[i];
if ((arp_ptr->ip == 0L) ||
chk_timeout(arp_ptr->expiry + MAX_ARP_GRACE))
arp_ptr->flags = ARP_FLAG_NEED; /* clear status flag */
return(arp_ptr);
}
/* pick one at pseudo-random */
arp_index = (arp_index + 1) % MAX_ARP_DATA;
arp_ptr->flags = ARP_FLAG_NEED; /* new MAC address needed */
return (&arp_data[arp_index]);
}
void
arp_register(longword new_IP, longword old_IP)
{ /* insert new IP to use instead of old IP */
register arp_tables *arp_ptr;
if (arp_ptr = arp_search(old_IP, 0)) /* if in ARP cache */
{ /* insert MAC address of new IP */
arp_resolve(new_IP, arp_ptr->mac);
arp_ptr->expiry = set_timeout(MAX_ARP_ALIVE);
return;
}
arp_ptr = arp_search(new_IP, 1); /* create a new one */
arp_ptr->flags = ARP_FLAG_NEED;
arp_ptr->ip = old_IP;
arp_resolve(new_IP, arp_ptr->mac);
arp_ptr->expiry = set_timeout(MAX_ARP_ALIVE);
}
/*
* arp_handler - handle incoming ARP packets
* Information will be put into the ARP cache only if an entry for that IP
* already exists (from an arp_resolve call).
*/
int
arp_handler(arp_header *in)
{
register arp_header *op;
longword his_ip, target_ip, temp;
register arp_tables *arp_ptr;
if (in == NULL) return (0); /* failure */
if (in->protType != TYPE_IP) /* IP protocol */
return(0); /* 0 means no, fail */
/* continuously accept data - but only for people we talk to */
bcopy(&in->sender_mac[MAC_len], &his_ip, PLEN);
his_ip = ntohl(his_ip);
bcopy(&in->sender_mac[MAC_len * 2 + PLEN], &target_ip, PLEN);
target_ip = ntohl(target_ip);
if ((in->opcode == ARP_REPLY) && /* a resolution reply */
(arp_ptr = arp_search(his_ip, 0)) != NULL)
{ /* do not create entry */
if (kdebug & DEBUG_STATUS)
arp_display(in, his_ip, target_ip);
arp_ptr->expiry = set_timeout(MAX_ARP_ALIVE);
memset(arp_ptr->mac, 0, 6); /* zero their MAC address */
/* then copy their MAC address to the trailing end */
bcopy(in->sender_mac, &arp_ptr->mac[6 - MAC_len], MAC_len);
arp_ptr->flags = ARP_FLAG_FOUND;
if (his_ip == my_ip_addr) /* their IP == my IP, uh oh */
{
arp_ptr->flags = ARP_FLAG_IMPOSTER;
outs("\r\n Another station is using our IP address");
outs(" from MAC address ");
outhexes(&in->sender_mac, in->hlen);
outs("\r\n");
}
} /* end of REPLY section */
/* Does someone want our hardware address? */
if ((in->opcode == ARP_REQUEST) && (target_ip == my_ip_addr))
{
if (kdebug & DEBUG_STATUS)
{
arp_display(in, his_ip, target_ip);
outs(" ARP Request is for our IP; replying.\r\n");
}
op = (arp_header *)eth_formatpacket(in->sender_mac, TYPE_ARP);
op->hwType = htons(arp_hardware);
op->protType = TYPE_IP; /* IP protocol */
op->hlen = (byte) (MAC_len & 0xff); /* MAC address len */
op->plen = PLEN; /* IP address len */
op->opcode = ARP_REPLY;
/* host's MAC and IP address */
bcopy(in->sender_mac, /* to target_mac */
&op->sender_mac[MAC_len + PLEN], MAC_len + PLEN);
/* our MAC and IP address */
bcopy(ð_addr[6-MAC_len], op->sender_mac, MAC_len);
temp = htonl(my_ip_addr); /* our IP in net order */
bcopy(&temp, &op->sender_mac[MAC_len], PLEN);
return (eth_send(sizeof(arp_header))); /* send the packet */
}
return (1); /* for success */
}
/* Display contents of an ARP packet, given initial IP address info */
void
arp_display(arp_header *in, longword sender_ip, longword target_ip)
{
byte temp[17];
outs("\r\n ARP");
if (in->opcode == ARP_REQUEST)
outs(" request");
if (in->opcode == ARP_REPLY)
outs(" reply");
if (sender_ip == my_ip_addr)
outs(" sent. Sender_IP=");
else
outs(" received. Sender_IP=");
ntoa(temp, sender_ip);
outs(temp);
outs(", Target_IP=");
ntoa(temp, target_ip);
outs(temp);
outs("\r\n Sender_MAC=");
outhexes(in->sender_mac, in->hlen);
}
/*
* arp_resolve - resolve IP address to hardware address
* return non-zero if successful, else zero
*/
int
arp_resolve(longword ina, eth_address *ethap)
{
register arp_tables *arp_ptr;
register word i;
byte nametemp[17];
int j;
longword timeout, resend;
static int arp_gateway = 0; /* distinguish gateway from host */
/* If we are running SLIP or ODI's SLIP_PPP which do not use
MAC level addresses */
if (pktdevclass == PD_SLIP ||
(pktdevclass == PD_ETHER && MAC_len == 0 ))
if (ina == my_ip_addr)
return (0); /* fail if ARP for self */
else
return(1);
if (ina == 0L || ina == 0xffffffffL || ina == ipbcast)
return (0); /* cannot resolve IP of 0's or 0xff's*/
/* check cache first */
if (((arp_ptr = arp_search(ina, 0)) != NULL) &&
(arp_ptr->flags & (ARP_FLAG_FOUND + ARP_FLAG_FIXED)))
{
if (ethap != NULL)
bcopy(arp_ptr->mac, ethap, 6); /* keep 6 byte MACs */
#ifdef NEW_EXPIRY
if (chk_timeout(arp_ptr->expiry + MAX_ARP_GRACE) == TIMED_OUT)
arp_ptr->flags = ARP_FLAG_NEED; /* too old, expire */
else
#endif /* NEW_EXPIRY */
return(1); /* success */
}
/* we must look elsewhere - but is it on our subnet? */
if (((ina ^ my_ip_addr) & sin_mask) /* not on this network */
&& (arp_gateway == 0)) /* host, not gateway */
{
for (i = 0; i < arp_last_gateway; i++)
{ /* watch out RECURSIVE CALL! */
arp_gateway = 1; /* remember doing gateway */
j = arp_resolve(arp_gate_data[i].gate_ip, ethap);
arp_gateway = 0; /* done doing gateway */
if (j != 0)
return (j); /* success */
}
return (0); /* fail */
}
/* make a new entry if necessary */
if (arp_ptr == NULL)
{
arp_ptr = arp_search(ina, 1); /* 1 means create an entry */
arp_ptr->flags = ARP_FLAG_NEED; /* say need mac address */
}
tcp_tick(NULL); /* read packets thus far */
/* is on our subnet, we must resolve */
timeout = set_timeout(2); /* two seconds is long for ARP */
if (ina == my_ip_addr)
timeout = set_ttimeout(6); /* briefly look for imposter*/
while (chk_timeout(timeout) != TIMED_OUT)
{ /* do the request */
resend = set_ttimeout(4); /* 4 / 18.2 sec */
arp_request(arp_ptr->ip = ina);
while (chk_timeout(resend) != TIMED_OUT)
{
tcp_tick(NULL); /* read packets */
if (arp_ptr->flags == ARP_FLAG_NEED)
continue;
if (arp_ptr->flags & ARP_FLAG_IMPOSTER)
return (1); /* IP imposter */
if (arp_ptr->flags & (ARP_FLAG_FOUND + ARP_FLAG_FIXED))
{
if (ethap != NULL) /* get MAC address */
bcopy(arp_ptr->mac, ethap, 6);
return (1); /* success */
}
} /* end of resend while */
} /* end of timeout while */
if (ina != my_ip_addr) /* if not my own IP address */
{
outs("\r\n Unable to ARP resolve ");
if (arp_gateway == 1) outs("gateway ");
ntoa(nametemp, ina);
outs(nametemp); /* show IP involved */
}
return(0); /* fail */
}
int
rarp_handler(arp_header *in)
{
register word i;
longword his_ip;
register arp_tables *arp_ptr;
if (in == NULL) return (0); /* failure */
if ((in->protType != TYPE_IP)) /* Internet protocol*/
return (0); /* 0 means no, fail */
bcopy(&in->sender_mac[MAC_len], &his_ip, PLEN);
his_ip = ntohl(his_ip);
if ((arp_ptr = arp_search(his_ip, 0)) != NULL)
{
arp_ptr->expiry = set_timeout(MAX_ARP_ALIVE);
memset(arp_ptr->mac, 0, 6); /* zero their MAC address */
/* then copy their MAC address to the trailing end */
bcopy(in->sender_mac, &arp_ptr->mac[6 - MAC_len], MAC_len);
arp_ptr->flags = ARP_FLAG_FOUND;
}
/* look for RARP Reply */
if ((my_ip_addr == 0) && (in->opcode == RARP_REPLY))
{ /* match our Ethernet address too */
for (i = 0; i < MAC_len; i++)
if (in->sender_mac[MAC_len + PLEN + i] !=
eth_addr[6 - MAC_len + i])
return (1); /* not for us */
bcopy(&in->sender_mac[MAC_len * 2 + PLEN], &my_ip_addr, PLEN);
my_ip_addr = ntohl(my_ip_addr); /* our IP addr */
}
return (1); /* for success */
}
/* send a RARP packet to request an IP address for our MAC address */
static void
arp_rev_request(void)
{
register arp_header *op;
op = (arp_header *)eth_formatpacket(ð_brdcast[0], TYPE_RARP);
op->hwType = htons(arp_hardware);
op->protType = TYPE_IP; /* IP protocol */
op->hlen = (byte)(MAC_len & 0xff); /* MAC address len */
op->plen = PLEN; /* IP address len */
op->opcode = RARP_REQUEST;
/* our MAC address into sender_mac and target_mac */
bcopy(ð_addr[6 - MAC_len], &op->sender_mac[0], MAC_len);
bcopy(ð_addr[6 - MAC_len], &op->sender_mac[MAC_len + PLEN], MAC_len);
eth_send(sizeof(arp_header)); /* send the packet */
}
/* Send a series of RARP requests until our IP address is non-zero or
we timeout.
*/
int
do_rarp(void)
{
longword timeout, resend;
my_ip_addr = 0L; /* init our IP */
timeout = set_timeout(10); /* 10 seconds total */
while (chk_timeout(timeout) != TIMED_OUT)
{
arp_rev_request(); /* ask for our IP */
resend = set_timeout(2); /* two second retry */
while (chk_timeout(resend) != TIMED_OUT)
{
tcp_tick(NULL); /* read packets */
if (my_ip_addr != 0L) return (1); /* got a reply */
}
}
return (0); /* got no reply */
}