dhcpboot.c
来自「完整的Bell实验室的嵌入式文件系统TFS」· C语言 代码 · 共 1,232 行 · 第 1/3 页
C
1,232 行
*dhcpOptions++ = 1; *dhcpOptions++ = DHCPDISCOVER; dhcpOptions = dhcpLoadShellVarOpts(dhcpOptions); *dhcpOptions++ = 0xff; /* Calculate ip and udp lengths after all DHCP options are loaded * so that the size is easily computed based on the value of the * dhcpOptions pointer. Apparently, the minimum size of the * options space is 64 bytes, we determined this simply because * the DHCP server we are using complains if the size is smaller. * Also, NULL out the space that is added to get a minimum option * size of 64 bytes, */ optlen = dhcpOptions - dhcpOptionsBase; if (optlen < 64) { memset(dhcpOptions,0,64-optlen); optlen = 64; } uh_ulen = sizeof(struct Udphdr)+sizeof(struct dhcphdr)+optlen; tu->uh_ulen = ecs(uh_ulen); } } ti->ip_len = ecs(sizeof(struct ip) + uh_ulen); ipChksum(ti); /* Compute checksum of ip hdr */ udpChksum(ti); /* Compute UDP checksum */ if (bootp) { DHCPState = BOOTPSTATE_REQUEST; sendBuffer(BOOTPSIZE); } else { DHCPState = DHCPSTATE_SELECT; sendBuffer(DHCPSIZE+optlen); } if (EtherVerbose & SHOW_DHCP) printf(" %s startup (%d elapsed secs)\n", bootp ? "BOOTP" : "DHCP",seconds); return(0);}/* SendDHCPRequest() * The DHCP request is broadcast back with the "server identifier" option * set to indicate which server has been selected (in case more than one * has offered). */intSendDHCPRequest(dhdr)struct dhcphdr *dhdr;{ uchar *op; struct dhcphdr *dhcpdata; struct ether_header *te; struct ip *ti; struct Udphdr *tu; int optlen; uchar *dhcpOptions, *dhcpOptionsBase; ushort uh_ulen; ulong cookie; if (EtherVerbose & SHOW_DHCP) printf(" DHCP request\n"); te = (struct ether_header *) getXmitBuffer(); memcpy((char *)&te->ether_shost,BinEnetAddr,6); memcpy((char *)&te->ether_dhost,BroadcastAddr,6); te->ether_type = ecs(ETHERTYPE_IP); ti = (struct ip *) (te + 1); ti->ip_vhl = IP_HDR_VER_LEN; ti->ip_tos = 0; ti->ip_id = 0; ti->ip_off = ecs(0x4000); /* No fragmentation allowed */ ti->ip_ttl = UDP_TTL; ti->ip_p = IP_UDP; memset((char *)&ti->ip_src.s_addr,0,4); memset((char *)&ti->ip_dst.s_addr,0xff,4); tu = (struct Udphdr *) (ti + 1); tu->uh_sport = ecs(DhcpClientPort); tu->uh_dport = ecs(DhcpServerPort); dhcpdata = (struct dhcphdr *)(tu+1); dhcpdata->op = DHCPBOOTP_REQUEST; dhcpdata->htype = 1; dhcpdata->hlen = 6; dhcpdata->hops = 0; DHCPElapsedSecs += 1; /* Not accurate */ dhcpdata->seconds = ecs(DHCPElapsedSecs); /* Use the same xid for the request as was used for the discover... * (rfc2131 section 4.4.1) */ memcpy((char *)&dhcpdata->transaction_id,(char *)&dhdr->transaction_id,4); dhcpdata->flags = dhdr->flags; memset((char *)&dhcpdata->client_ip,0,4); memcpy((char *)&dhcpdata->your_ip,(char *)&dhdr->your_ip,4); memset((char *)&dhcpdata->server_ip,0,4); memset((char *)&dhcpdata->router_ip,0,4); cookie = ecl(STANDARD_MAGIC_COOKIE); memcpy((char *)&dhcpdata->magic_cookie,(char *)&cookie,4); memcpy(dhcpdata->client_macaddr,BinEnetAddr,6); dhcpOptionsBase = (uchar *)(dhcpdata+1); dhcpOptions = dhcpOptionsBase; *dhcpOptions++ = DHCPOPT_MESSAGETYPE; *dhcpOptions++ = 1; *dhcpOptions++ = DHCPREQUEST; *dhcpOptions++ = DHCPOPT_SERVERID; /* Server id ID */ *dhcpOptions++ = 4; op = DhcpGetOption(DHCPOPT_SERVERID,dhdr+1); if (op) memcpy(dhcpOptions,op+2,4); else memset(dhcpOptions,0,4); dhcpOptions+=4; *dhcpOptions++ = DHCPOPT_REQUESTEDIP; /* Requested IP */ *dhcpOptions++ = 4; memcpy(dhcpOptions,(char *)&dhdr->your_ip,4); dhcpOptions += 4; dhcpOptions = dhcpLoadShellVarOpts(dhcpOptions); *dhcpOptions++ = 0xff; /* See note in SendDHCPDiscover() regarding the computation of the * ip and udp lengths. */ optlen = dhcpOptions - dhcpOptionsBase; if (optlen < 64) optlen = 64; uh_ulen = sizeof(struct Udphdr) + sizeof(struct dhcphdr) + optlen; tu->uh_ulen = ecs(uh_ulen); ti->ip_len = ecs(sizeof(struct ip) + uh_ulen); ipChksum(ti); /* Compute checksum of ip hdr */ udpChksum(ti); /* Compute UDP checksum */ DHCPState = DHCPSTATE_REQUEST; sendBuffer(DHCPSIZE+optlen); return(0);}/* randomDhcpStartupDelay(): * Randomize the startup for DHCP/BOOTP (see RFC2131 Sec 4.4.1)... * Return a value between 1 and 10 based on the last 4 bits of the * board's MAC address. */intrandomDhcpStartupDelay(){ int randomsec; randomsec = (BinEnetAddr[5] & 0xf); if (randomsec > 10) randomsec -= 7; else if (randomsec == 0) randomsec = 10; return(randomsec);}/* dhcpStateCheck(): * Called by pollethernet() to monitor the progress of DHCPState. * The retry rate is "almost" what is specified in the RFC... * Refer to the RetransmitDelay() function for details. * * Regarding timing... * The DHCP startup may be running without an accurate measure of elapsed * time. The value of LoopsPerSecond is used as an approximation of * the number of times this function must be called for one second to * pass (dependent on network traffic, etc...). RetransmitDelay() is * called to retrieve the number of seconds that must elapse prior to * retransmitting the last DHCP message. The static variables in this * function are used to keep track of that timeout. */voiddhcpStateCheck(void){ static int dhcpretry, delayloops, delaysecs; /* If the DHCP command has been issued, it is assumed that the script * is handling retries... */ if (DHCPCommandIssued) return; /* Return, restart or fall through; depending on DHCPState... */ switch(DHCPState) { case DHCPSTATE_NOTUSED: case BOOTPSTATE_COMPLETE: case DHCPSTATE_BOUND: delayloops = 0; return; case DHCPSTATE_RESTART: delayloops = 0; DHCPStartup(0); return; case BOOTPSTATE_RESTART: delayloops = 0; BOOTPStartup(0); return; case DHCPSTATE_INITIALIZE: /* Randomized delay prior to startup */ case BOOTPSTATE_INITIALIZE: /* of the BOOTP/DHCP transaction. */ if (!delayloops) { dhcpretry = 0; delaysecs = randomDhcpStartupDelay(); delayloops = delaysecs * LoopsPerSecond; if (EtherVerbose & SHOW_DHCP) printf("\nDHCP/BOOTP %d sec startup delay...\n",delaysecs); } else if ((++dhcpretry > delayloops) || (gotachar())) { DHCPElapsedSecs = 0; if (DHCPState & BOOTP_MODE) BOOTPStartup(0); else DHCPStartup(0); dhcpretry = 0; delayloops = 0; } return; default: break; } /* If the DHCP or BOOTP transaction hasn't completed by the time * the static variable dhcpretry reaches the current retransmit-delay * point, then restart the transaction. * Note that we only do the multiplication if delayloops is zero. This * just avoids the wasted processing time. */ if (!delayloops) { delaysecs = RetransmitDelay(DELAY_RETURN); delayloops = delaysecs*LoopsPerSecond; dhcpretry = 0; } if (++dhcpretry > delayloops) { DHCPElapsedSecs += delaysecs; if (DHCPState & BOOTP_MODE) BOOTPStartup(DHCPElapsedSecs); else DHCPStartup(DHCPElapsedSecs); if (EtherVerbose & SHOW_DHCP) printf(" DHCP/BOOTP retry (%d secs)\n",delaysecs); dhcpretry = 0; delayloops = 0; RetransmitDelay(DELAY_INCREMENT); }}/* xidCheck(): * Common function used for DHCP and BOOTP to verify incoming transaction * id... */intxidCheck(char *id,int bootp){ if (memcmp(id,(char *)&DHCPTransactionId,4)) { if (EtherVerbose & SHOW_DHCP) { printf("%s ignored: unexpected transaction id.\n", bootp ? "BOOTP":"DHCP"); } return(-1); } return(0);}intloadBootFile(int bootp){#if INCLUDE_TFTP char bfile[TFSNAMESIZE+TFSINFOSIZE+32]; char *flags, *info, *icomma, *fcomma, *argv[2]; char *bootfile, *tftpsrvr; ulong addr; /* If both bootfile and server-ip are specified, then boot it. * The name of the file must contain information that tells the monitor * what type of file it is, so the first 'comma' extension is used as * the flag field (if it is a valid flag set) and the second 'comma' * extension is used as the info field. */ bootfile = getenv("BOOTFILE"); tftpsrvr = getenv("BOOTSRVR"); if (bootfile && tftpsrvr) { int tftpworked; addr = getAppRamStart(); info = ""; flags = "e"; strncpy(bfile,bootfile,sizeof(bfile)); fcomma = strchr(bfile,','); if (fcomma) { icomma = strchr(fcomma+1,','); if (icomma) { *icomma = 0; info = icomma+1; } *fcomma = 0; if (tfsctrl(TFS_FATOB,(long)(fcomma+1),0) != 0) flags = fcomma+1; } /* Since we are about to transition to TFTP, match TFTP's * verbosity to the verbosity currently set for DHCP... */ if (EtherVerbose & SHOW_DHCP) EtherVerbose |= SHOW_TFTP; /* If the TFTP transfer succeeds, attempt to run the boot file; * if the TFTP transfer fails, then re-initialize the tftp state * and set the DHCP state such that dhcpStateCheck() will * cause the handshake to start over again... */ tftpworked = tftpGet(addr,tftpsrvr,"octet",bfile,bfile,flags,info); if (tftpworked) { EtherVerbose = 0; argv[0] = bfile; argv[1] = 0; tfsrun(argv,0); } else { tftpInit(); RetransmitDelay(DELAY_INIT_DHCP); EtherVerbose &= ~SHOW_TFTP; if (bootp) DHCPState = BOOTPSTATE_RESTART; else DHCPState = DHCPSTATE_RESTART; } } else EtherVerbose &= ~(SHOW_DHCP|DHCP_VERBOSE);#endif return(0);}/* processBOOTP(): * A subset of processDHCP(). * We get here from processDHCP, because it detects that the current * value of DHCPState is BOOTPSTATE_REQUEST. */intprocessBOOTP(ehdr,size)struct ether_header *ehdr;ushort size;{ struct ip *ihdr; struct Udphdr *uhdr; struct bootphdr *bhdr; ulong ip, temp_ip, cookie; uchar buf[16], *op; printMem((uchar *)ehdr,size); ihdr = (struct ip *)(ehdr + 1); uhdr = (struct Udphdr *)((char *)ihdr + IP_HLEN(ihdr)); bhdr = (struct bootphdr *)(uhdr+1); /* Verify incoming transaction id matches the previous outgoing value: */ if (xidCheck((char *)&bhdr->transaction_id,1) < 0) return(-1); /* If bootfile is nonzero, store it into BOOTFILE shell var: */ if (bhdr->bootfile[0]) DhcpSetEnv("BOOTFILE",bhdr->bootfile); /* Assign IP "server_ip" to the BOOTSRVR shell var (if non-zero): */ memcpy((char *)&temp_ip,(char *)&bhdr->server_ip,4); if (temp_ip) DhcpSetEnv("BOOTSRVR",IpToString(temp_ip,buf)); /* Assign IP "router_ip" to the RLYAGNT shell var (if non-zero): */ memcpy((char *)&temp_ip,(char *)&bhdr->router_ip,4); if (temp_ip) DhcpSetEnv("RLYAGNT",IpToString(temp_ip,buf)); /* Assign IP address loaded in "your_ip" to the IPADD shell var: */ memcpy(BinIpAddr,(char *)&bhdr->your_ip,4); memcpy((char *)&temp_ip,(char *)&bhdr->your_ip,4); DhcpSetEnv("IPADD",IpToString(temp_ip,buf)); /* If STANDARD_MAGIC_COOKIE exists, then process options... */ memcpy((char *)&cookie,(char *)bhdr->vsa,4); if (cookie == ecl(STANDARD_MAGIC_COOKIE)) { /* Assign subnet mask option to NETMASK shell var (if found): */ op = DhcpGetOption(DHCPOPT_SUBNETMASK,&bhdr->vsa[4]); if (op) { memcpy((char *)&ip,op+2,4); DhcpSetEnv("NETMASK",IpToString(ip,buf)); } /* Assign first router option to GIPADD shell var (if found): */ /* (the router option can have multiple entries, and they are */ /* supposed to be in order of preference, so use the first one) */ op = DhcpGetOption(DHCPOPT_ROUTER,&bhdr->vsa[4]); if (op) { memcpy((char *)&ip,op+2,4); DhcpSetEnv("GIPADD",IpToString(ip,buf)); } } DhcpBootpDone(1,(struct dhcphdr *)bhdr, size - ((int)((int)&bhdr->vsa - (int)ehdr))); DHCPState = BOOTPSTATE_COMPLETE; /* Call loadBootFile() which will then kick off a tftp client * transfer if both BOOTFILE and BOOTSRVR shell variables are * loaded; otherwise, we are done. */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?