|
|
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.