Annotation of Net2/arch/i386/netboot/arp.c, revision 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.