|
|
1.1 root 1: /* netboot
2: *
3: * arp.c,v
4: * Revision 1.2 1993/07/09 15:24:10 brezak
5: * Cleanup warnings and add netbsd kernel name suffix.
6: *
7: * Revision 1.1 1993/07/08 16:03:47 brezak
8: * Diskless boot prom code from Jim McKim ([email protected])
9: *
10: * Revision 1.2 1993/06/30 20:14:10 mckim
11: * Added BOOTP support.
12: *
13: * Revision 1.1.1.1 1993/05/28 11:41:06 mckim
14: * Initial version.
15: *
16: *
17: * source in this file came from
18: * the Mach ethernet boot written by Leendert van Doorn.
19: *
20: * Ethernet (Reverse) Address Resolution Protocol (see RFC 903, and 826).
21: * No doubt this code is overkill, but I had it lying around.
22: *
23: * Copyright (c) 1992 by Leendert van Doorn
24: */
25:
26: #include "proto.h"
27: #include "assert.h"
28: #include "param.h"
29: #include "packet.h"
30: #include "ether.h"
31: #include "inet.h"
32: #include "arp.h"
33: #include "bootp.h"
34: #include "tftp.h"
35:
36: static u_char bcastaddr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
37: static arptab_t arptab[ARPTAB_SIZE];
38:
39: extern u_char vendor_area[64];
40: ipaddr_t ip_myaddr = IP_ANYADDR;
41: ipaddr_t ip_gateway = IP_ANYADDR;
42:
43: #ifdef USE_RARP
44: /*
45: * Broadcast a RARP request (i.e. who knows who I am)
46: */
47: static void
48: RarpWhoAmI(void) {
49: arphdr_t *ap;
50: packet_t *pkt;
51: pkt = PktAlloc(sizeof(ethhdr_t));
52: pkt->pkt_len = sizeof(arphdr_t);
53: ap = (arphdr_t *) pkt->pkt_offset;
54: ap->arp_hrd = htons(ARPHRD_ETHER);
55: ap->arp_pro = htons(ETHTYPE_IP);
56: ap->arp_hln = ETH_ADDRSIZE;
57: ap->arp_pln = sizeof(ipaddr_t);
58: ap->arp_op = htons(REVARP_REQUEST);
59: bcopy((char *)eth_myaddr, (char *)ap->arp_sha, ETH_ADDRSIZE);
60: bcopy((char *)eth_myaddr, (char *)ap->arp_tha, ETH_ADDRSIZE);
61: EtherSend(pkt, ETHTYPE_RARP, bcastaddr);
62: PktRelease(pkt);
63: }
64: #endif
65:
66:
67: #ifdef USE_BOOTP
68: static int saved_bootp_xid; /* from last bootp req */
69: extern int time_zero;
70: /*
71: * Broadcast a BOOTP request (i.e. who knows who I am)
72: */
73: static void
74: BootpWhoAmI(void) {
75: struct bootp *bp;
76: packet_t *pkt;
77: udphdr_t *up;
78: pkt = PktAlloc(sizeof(ethhdr_t)+sizeof(iphdr_t));
79: pkt->pkt_len = sizeof(ethhdr_t) + sizeof(iphdr_t) +
80: sizeof(udphdr_t) +sizeof(struct bootp);
81: up = (udphdr_t *) pkt->pkt_offset;
82: bp = (struct bootp *) ((char *)up + sizeof(udphdr_t));
83: up->uh_dport = htons(IPPORT_BOOTPS);
84: up->uh_len = htons(sizeof(udphdr_t) + sizeof(struct bootp));
85: bp->bp_op = BOOTREQUEST;
86: bp->bp_htype = 1;
87: bp->bp_hlen = ETH_ADDRSIZE;
88: bp->bp_xid = saved_bootp_xid = rand();
89: bp->bp_secs = htons(timer() - time_zero);
90: bcopy((char *)eth_myaddr, (char *)bp->bp_chaddr, ETH_ADDRSIZE);
91: IpSend(pkt, IP_BCASTADDR, IP_ANYADDR);
92: PktInit();
93: }
94: #endif
95:
96: extern ipaddr_t tftp_gateway;
97: extern ipaddr_t tftp_server;
98:
99: #ifdef USE_RARP
100: /*
101: * Called when packet containing RARP is received
102: */
103: static inline ipaddr_t
104: RarpInput(packet_t *pkt, ipaddr_t *server) {
105: ipaddr_t ipaddr;
106: ethhdr_t *ep;
107: ep = (ethhdr_t *)pkt->pkt_offset;
108:
109: /* is rarp? */
110: if (pkt->pkt_len >= sizeof(arphdr_t) &&
111: ntohs(ep->eth_proto) == ETHTYPE_RARP) {
112: ipaddr_t ipa;
113: arphdr_t *ap;
114: ap = (arphdr_t *) (pkt->pkt_offset + sizeof(ethhdr_t));
115: if (ntohs(ap->arp_op) != REVARP_REPLY ||
116: ntohs(ap->arp_pro) != ETHTYPE_IP)
117: return 0;
118: if (bcmp(ap->arp_tha, eth_myaddr, ETH_ADDRSIZE))
119: return 0;
120:
121: bcopy((char *)ap->arp_tpa, (char *)&ipaddr, sizeof(ipaddr_t));
122: printf("From RARP server ");
123: bcopy((char *)ap->arp_spa, (char *)&ipa, sizeof(ipaddr_t));
124: IpPrintAddr(ipa);
125: printf(": using IP address ");
126: IpPrintAddr(ipaddr);
127:
128: if (server) {
129: bcopy((char *)ap->arp_spa, (char *)server, sizeof(ipaddr_t));
130: printf(",\n tftp server ");
131: IpPrintAddr(*server);
132: }
133:
134: printf("\n");
135: return ipaddr;
136: }
137: return 0;
138: }
139: #endif
140:
141: #ifdef USE_BOOTP
142: static inline ipaddr_t
143: BootpInput(packet_t *pkt, ipaddr_t *server, ipaddr_t *gateway, char *filename) {
144: ipaddr_t ipaddr;
145: ethhdr_t *ep;
146: ep = (ethhdr_t *)pkt->pkt_offset;
147:
148:
149: if (pkt->pkt_len < sizeof(iphdr_t)+sizeof(udphdr_t)+sizeof(struct bootp))
150: return 0;
151: if (ntohs(ep->eth_proto) == ETHTYPE_IP) {
152: iphdr_t *ip;
153: udphdr_t *up;
154: struct bootp *bp;
155: ip = (iphdr_t *) ((char *)ep + sizeof(ethhdr_t));
156: up = (udphdr_t *) ((char *)ip + sizeof(iphdr_t));
157: bp = (struct bootp *) ((char *)up + sizeof(udphdr_t));
158:
159: #if 0
160: DUMP_STRUCT("eboot", ep, 100);
161: printf("pktlen %d of %d\n\n", pkt->pkt_len, sizeof(iphdr_t)+sizeof(udphdr_t)+sizeof(struct bootp));
162: #endif
163:
164: if (ip->ip_p != IP_PROTO_UDP) {
165: return 0;
166: }
167:
168: if (up->uh_dport != htons(IPPORT_BOOTPC)) {
169: return 0;
170: }
171:
172: if (bp->bp_xid != saved_bootp_xid) {
173: return 0;
174: }
175:
176: /* passed all checks - is the packet we expected */
177: ipaddr = bp->bp_yiaddr;
178: printf("From BOOTP server ");
179: IpPrintAddr(ip->ip_src);
180: printf(": using IP address ");
181: IpPrintAddr(bp->bp_yiaddr);
182:
183: if (server) {
184: *server = bp->bp_siaddr;
185: printf(",\n tftp server ");
186: IpPrintAddr(bp->bp_siaddr);
187: }
188:
189: if (bp->bp_giaddr) {
190: *gateway = bp->bp_giaddr;
191: printf(",\n gateway ");
192: IpPrintAddr(bp->bp_giaddr);
193: }
194:
195: if (*bp->bp_file) {
196: bcopy((char *)bp->bp_file, filename, MAX_FILE_NAME_LEN-1);
197: printf(",\n file '%s'", bp->bp_file);
198: }
199:
200: bcopy((char *)bp->bp_vend, (char *)vendor_area, sizeof(vendor_area));
201:
202: printf("\n");
203:
204: PktInit();
205: return ipaddr;
206: }
207: return 0;
208: }
209: #endif
210:
211: /*
212: * Using the BOOTP and/or RARP request/reply exchange we try to obtain our
213: * internet address (see RFC 903).
214: */
215: ipaddr_t
216: GetIpAddress(ipaddr_t *serv_addr, ipaddr_t *myaddr, ipaddr_t *gateway, char *filename) {
217: u_long time, current, timeout;
218: int retry;
219: packet_t *pkt;
220: int spin = 0;
221:
222: #if TRACE > 0
223: printe("GetIpAddress: Requesting IP address for ");
224: EtherPrintAddr(eth_myaddr);
225: printe("\n");
226: #endif
227:
228: timeout = 4; /* four seconds */
229: for (retry = 0; retry < NRETRIES; retry++) {
230: #ifdef USE_RARP
231: RarpWhoAmI();
232: #endif
233: #ifdef USE_BOOTP
234: BootpWhoAmI();
235: #endif
236: printf("%c\b", "-\\|/"[spin++ % 4]);
237:
238: time = timer() + timeout;
239: do {
240: pkt = EtherReceive();
241: if (pkt) {
242: *myaddr = 0;
243: #ifdef USE_RARP
244: *myaddr = RarpInput(pkt, serv_addr);
245: #endif
246: #ifdef USE_BOOTP
247: if (!*myaddr)
248: *myaddr = BootpInput(pkt, serv_addr, gateway, filename);
249: #endif
250: PktRelease(pkt);
251: if (*myaddr) {
252: return 1;
253: }
254: }
255: HandleKbdAttn();
256: current = timer();
257: } while (current < time);
258: EtherReset();
259: timeout <<= 1;
260: }
261: printf("No response for "
262: #ifdef USE_BOOTP
263: "BOOTP "
264: #endif
265: #ifdef USE_RARP
266: "RARP "
267: #endif
268: "request\n");
269: return IP_ANYADDR;
270: }
271:
272: /*
273: * Broadcast an ARP packet (i.e. ask who has address "addr")
274: */
275: static void
276: ArpWhoHas(ipaddr_t addr) {
277: arphdr_t *ap;
278: packet_t *pkt;
279:
280: pkt = PktAlloc(sizeof(ethhdr_t));
281: pkt->pkt_len = sizeof(arphdr_t);
282: ap = (arphdr_t *) pkt->pkt_offset;
283: ap->arp_hrd = htons(ARPHRD_ETHER);
284: ap->arp_pro = htons(ETHTYPE_IP);
285: ap->arp_hln = ETH_ADDRSIZE;
286: ap->arp_pln = sizeof(ipaddr_t);
287: ap->arp_op = htons(ARPOP_REQUEST);
288: bcopy((char *)eth_myaddr, (char *)ap->arp_sha, ETH_ADDRSIZE);
289: bcopy((char *)&ip_myaddr, (char *)ap->arp_spa, sizeof(ipaddr_t));
290: bcopy((char *)&addr, (char *)ap->arp_tpa, sizeof(ipaddr_t));
291: #if TRACE > 0
292: printe("ArpWhoHas:\n");
293: DUMP_STRUCT("arphdr_t", ap, sizeof(arphdr_t));
294: #endif
295: EtherSend(pkt, ETHTYPE_ARP, bcastaddr);
296: PktRelease(pkt);
297: }
298:
299: /*
300: * Free an arptab entry
301: */
302: static void
303: ArpTfree(arptab_t *at) {
304: if (at->at_hold)
305: PktRelease(at->at_hold);
306: at->at_hold = (packet_t *)0;
307: at->at_timer = at->at_flags = 0;
308: at->at_ipaddr = 0;
309: }
310:
311: /*
312: * Enter a new address in arptab, pushing out the oldest entry
313: * from the bucket if there is no room.
314: */
315: static arptab_t *
316: ArpTnew(ipaddr_t addr) {
317: u_short n;
318: u_long oldest;
319: arptab_t *at, *ato;
320:
321: oldest = ~0;
322: ato = at = &arptab[ARPTAB_HASH(addr) * ARPTAB_BSIZ];
323: for (n = 0 ; n < ARPTAB_BSIZ ; n++,at++) {
324: if (at->at_flags == 0)
325: goto out; /* found an empty entry */
326: if (at->at_timer < oldest) {
327: oldest = at->at_timer;
328: ato = at;
329: }
330: }
331: at = ato;
332: ArpTfree(at);
333: out:
334: at->at_ipaddr = addr;
335: at->at_flags = ATF_INUSE;
336: return at;
337: }
338:
339: /*
340: * Resolve an IP address into a hardware address. If success,
341: * destha is filled in and 1 is returned. If there is no entry
342: * in arptab, set one up and broadcast a request
343: * for the IP address; return 0. Hold onto this packet and
344: * resend it once the address is finally resolved.
345: */
346: int
347: ArpResolve(packet_t *pkt, ipaddr_t destip, u_char *destha) {
348: arptab_t *at;
349: u_long lna = ntohl(destip) & 0xFF;
350:
351: if (lna == 0xFF || lna == 0x0) { /* broadcast address */
352: bcopy((char *)bcastaddr, (char *)destha, ETH_ADDRSIZE);
353: return 1;
354: }
355:
356: ARPTAB_LOOK(at, destip);
357: if (at == 0) {
358: at = ArpTnew(destip);
359: at->at_hold = pkt;
360: ArpWhoHas(destip);
361: return 0;
362: }
363:
364: at->at_timer = timer(); /* restart the timer */
365: if (at->at_flags & ATF_COM) { /* entry is complete */
366: bcopy((char *)at->at_eaddr, (char *)destha, ETH_ADDRSIZE);
367: return 1;
368: }
369:
370: /*
371: * There is an arptab entry, but no hardware address
372: * response yet. Replace the held packet with this
373: * latest one.
374: */
375: if (at->at_hold)
376: PktRelease(at->at_hold);
377: at->at_hold = pkt;
378: ArpWhoHas(destip);
379: return 0;
380: }
381:
382:
383: /*
384: * Called when packet containing ARP is received.
385: * Algorithm is that given in RFC 826.
386: */
387: void
388: ArpInput(packet_t *pkt) {
389: arphdr_t *ap;
390: arptab_t *at;
391: packet_t *phold;
392: ipaddr_t isaddr, itaddr;
393:
394: #if 0
395: T(ArpInput);
396: #endif
397: if (pkt->pkt_len < sizeof(arphdr_t)) {
398: #if 0
399: printf("ArpInput: bad packet size %d\n", pkt->pkt_len);
400: #endif
401: return;
402: }
403:
404: ap = (arphdr_t *) (pkt->pkt_offset + sizeof(ethhdr_t));
405: #if 0
406: DUMP_STRUCT("arphdr_t", ap, sizeof(arphdr_t));
407: #endif
408: if (ntohs(ap->arp_pro) != ETHTYPE_IP) {
409: #if 0
410: printf("ArpInput: incorrect proto addr %x\n", ap->arp_pro);
411: #endif
412: return;
413: }
414:
415: bcopy((char *)ap->arp_spa, (char *)&isaddr, sizeof(ipaddr_t));
416: bcopy((char *)ap->arp_tpa, (char *)&itaddr, sizeof(ipaddr_t));
417: if (!bcmp(ap->arp_sha, eth_myaddr, ETH_ADDRSIZE)) {
418: #if 0
419: printf("ArpInput: incorrect sender h/w addr ");
420: EtherPrintAddr(ap->arp_sha);
421: printf("/n");
422: #endif
423: return;
424: }
425:
426: at = (arptab_t *)0;
427: ARPTAB_LOOK(at, isaddr);
428: if (at) {
429: bcopy((char *)ap->arp_sha, (char *)at->at_eaddr, ETH_ADDRSIZE);
430: at->at_flags |= ATF_COM;
431: if (at->at_hold) {
432: phold = at->at_hold;
433: at->at_hold = (packet_t *)0;
434: #if 0
435: printf("ArpInput: found addr, releasing packet\n");
436: #endif
437: EtherSend(phold, ETHTYPE_IP, at->at_eaddr);
438: PktRelease(phold);
439: }
440: }
441:
442: /*
443: * Only answer ARP request which are for me
444: */
445: if (itaddr != ip_myaddr) {
446: #if 0
447: printf("ArpInput: it addr ");
448: IpPrintAddr(itaddr);
449: printf(" somebody else\n");
450: #endif
451: return;
452: }
453:
454: if (at == 0) { /* ensure we have a table entry */
455: at = ArpTnew(isaddr);
456: bcopy((char *)ap->arp_sha, (char *)at->at_eaddr, ETH_ADDRSIZE);
457: at->at_flags |= ATF_COM;
458: }
459: if (ntohs(ap->arp_op) != ARPOP_REQUEST) {
460: printf("ArpInput: incorrect operation: 0x%x\n", ntohs(ap->arp_op));
461: return;
462: }
463: bcopy((char *)ap->arp_sha, (char *)ap->arp_tha, ETH_ADDRSIZE);
464: bcopy((char *)ap->arp_spa, (char *)ap->arp_tpa, sizeof(ipaddr_t));
465: bcopy((char *)eth_myaddr, (char *)ap->arp_sha, ETH_ADDRSIZE);
466: bcopy((char *)&itaddr, (char *)ap->arp_spa, sizeof(ipaddr_t));
467: ap->arp_op = htons(ARPOP_REPLY);
468: #if 0
469: printf("ArpInput: valid request rec'd, replying\n");
470: #endif
471: EtherSend(pkt, ETHTYPE_ARP, ap->arp_tha);
472: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.