📄 dhcpboot.c
字号:
*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).
*/
int
SendDHCPRequest(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;
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,(char *)(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.
* The presence of the DHCPSTARTUPDELAY shell variable overrides
* this random value.
*/
int
randomDhcpStartupDelay()
{
char *env;
int randomsec;
env = getenv("DHCPSTARTUPDELAY");
if (env) {
randomsec = (int)strtol(env,0,0);
}
else {
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 LoopsPerMillisecond 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.
*/
void
dhcpStateCheck(void)
{
int 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:
return;
case DHCPSTATE_RESTART:
DHCPStartup(0);
return;
case BOOTPSTATE_RESTART:
BOOTPStartup(0);
return;
case DHCPSTATE_INITIALIZE:
case BOOTPSTATE_INITIALIZE:
delaysecs = randomDhcpStartupDelay();
startElapsedTimer(&dhcpTmr,delaysecs * 1000);
if (EtherVerbose & SHOW_DHCP)
printf("\nDHCP/BOOTP %d sec startup delay...\n",delaysecs);
if (DHCPState & BOOTP_MODE)
DHCPState = BOOTPSTATE_INITDELAY;
else
DHCPState = DHCPSTATE_INITDELAY;
return;
case DHCPSTATE_INITDELAY:
case BOOTPSTATE_INITDELAY:
if (msecElapsed(&dhcpTmr) || (gotachar())) {
DHCPElapsedSecs = 0;
startElapsedTimer(&dhcpTmr,
RetransmitDelay(DELAY_INIT_DHCP)*1000);
if (DHCPState & BOOTP_MODE)
BOOTPStartup(0);
else
DHCPStartup(0);
}
return;
default:
break;
}
if (msecElapsed(&dhcpTmr)) {
int lastdelay;
lastdelay = RetransmitDelay(DELAY_RETURN);
delaysecs = RetransmitDelay(DELAY_INCREMENT);
if (delaysecs != RETRANSMISSION_TIMEOUT) {
DHCPElapsedSecs += delaysecs;
startElapsedTimer(&dhcpTmr,delaysecs*1000);
if (DHCPState & BOOTP_MODE)
BOOTPStartup(DHCPElapsedSecs);
else
DHCPStartup(DHCPElapsedSecs);
if (EtherVerbose & SHOW_DHCP)
printf(" DHCP/BOOTP retry (%d secs)\n",lastdelay);
}
else {
if (EtherVerbose & SHOW_DHCP)
printf(" DHCP/BOOTP giving up\n");
}
}
}
/* xidCheck():
* Common function used for DHCP and BOOTP to verify incoming transaction
* id...
*/
int
xidCheck(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);
}
int
loadBootFile(int bootp)
{
#if INCLUDE_TFTP
char bfile[TFSNAMESIZE+TFSINFOSIZE+32];
char *flags, *info, *icomma, *fcomma, *argv[2];
char *bootfile, *tftpsrvr;
int err;
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_STATE;
/* 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) {
//stone debug tftp
docommand("call 0xa0300000",0);
/*
EtherVerbose = 0;
argv[0] = bfile;
argv[1] = 0;
err = tfsrun(argv,0);
if (err != TFS_OKAY)
printf("DHCP-invoked tfsrun(%s) failed: %s\n",
bfile,tfserrmsg(err));
*/
}
else {
tftpInit();
RetransmitDelay(DELAY_INIT_TFTP);
EtherVerbose &= ~SHOW_TFTP_STATE;
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.
*/
int
processBOOTP(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;
if (EtherVerbose & SHOW_HEX)
printMem((uchar *)ehdr,size,EtherVerbose & SHOW_ASCII);
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)));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -