Annotation of Net2/arch/i386/netboot/arp.c, revision 1.1.1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.