📄 dhcpboot.c
字号:
/* dhcpboot.c: * This code implements a subset of the DHCP client protocol. * Based on RFC2131 spec, the "automatic allocation" mode, in which DHCP * assigns a permanent IP address to a client, is the only mode supported. * * The idea is that the monitor boots up, and if IPADD is set to DHCP, then * DHCP is used to populate shell variables with a server-supplied IP * address, NetMask and Gateway IP address. Then, when the application * is launched (probably via TFS), it can retrieve the content of those * shell variables for use by the application. * * Sequence of events for this limited implementation of DHCP... * Client issues a DHCP_DISCOVER, server responds with a DHCP_OFFER, * client issues a DHCP_REQUEST and server responds with a DHCP_ACK. * DISCOVER: request by the client to broadcast the fact that it is looking * for a DHCP server. * OFFER: reply from the server when it receives a DISCOVER request from * a client. The offer may contain all the information that the DHCP * client needs to bootup, but this is dependent on the configuration of * the server. * REQUEST: request by the client for the server (now known because an OFFER * was received) to send it the information it needs. * ACK: reply from the server with the information requested. * * NOTE: this file contains a generic DHCP client supporting "automatic * allocation mode" (infinite lease time). There are several different * application-specific enhancements that can be added and hopefully * they have been isolated through the use of the dhcp_00.c file. * I've attempted to isolate as much of the non-generic code to * the file dhcp_XX.c (where dhcp_00.c is the default code). If non-default * code is necessary, then limit the changes to a new dhcp_XX.c file. This * will allow the code in this file to stay generic; hence, the user of this * code will be able to accept monitor upgrades without the need to touch * this file. The makefile must link in some additional dhcp_XX.c file * (default is dhcp_00.c). Bottom line... there should be no need to modify * this file for application-specific stuff; if there is, please let me know. * * NOTE1: the shell variable IPADD can also be set to DHCPV or DHCPv to * enable different levels of verbosity during DHCP transactions... 'V' * is full DHCP verbosity and 'v' only prints the DhcpSetEnv() calls. * * NOTE2: this file supports DHCP and BOOTP. Most of the function names * refer to DHCP even though their functionality is shared by both DHCP * and BOOTP. This is because I wrote this originally for DHCP, then added * the hooks for BOOTP... Bottom line: don't let the names confuse you! * * General notice: * This code is part of a boot-monitor package developed as a generic base * platform for embedded system designs. As such, it is likely to be * distributed to various projects beyond the control of the original * author. Please notify the author of any enhancements made or bugs found * so that all may benefit from the changes. In addition, notification back * to the author will allow the new user to pick up changes that may have * been made by other users after this version of the code was distributed. * * Note1: the majority of this code was edited with 4-space tabs. * Note2: as more and more contributions are accepted, the term "author" * is becoming a mis-representation of credit. * * Original author: Ed Sutter * Email: esutter@lucent.com * Phone: 908-582-2351 */#include "config.h"#include "endian.h"#include "cpuio.h"#include "ether.h"#include "tfs.h"#include "tfsprivate.h"#include "genlib.h"#include "stddefs.h"#include "cli.h"int DHCPStartup(short), BOOTPStartup(short);int DhcpSetEnv(char *,char *);int SendDHCPDiscover(int,short);void dhcpDumpVsa(void), printDhcpOptions(uchar *);unsigned short DHCPState;#if INCLUDE_DHCPBOOTstatic int DHCPCommandIssued;static ulong DHCPTransactionId;/* Variables used for DHCP Class ID specification: */static char *DHCPClassId;static int DHCPClassIdSize;/* Variables used for DHCP Client ID specification: */static char DHCPClientId[32];static int DHCPClientIdSize, DHCPClientIdType;/* Variables used for setting up a DHCP Parameter Request List: */static uchar DHCPRequestList[32];static int DHCPRqstListSize;/* Variable to keep track of elapsed seconds since DHCP started: */static short DHCPElapsedSecs;char *DhcpHelp[] = { "Issue a DHCP discover", "-[bvV] [vsa]", "Options...", " -b use bootp", " -v|V verbosity", 0,};intDhcp(int argc,char *argv[]){ int opt, bootp; bootp = 0; DHCPCommandIssued = 1; while ((opt=getopt(argc,argv,"bvV")) != -1) { switch(opt) { case 'b': bootp = 1; break; case 'v': EtherVerbose = SHOW_DHCP; break; case 'V': EtherVerbose = DHCP_VERBOSE; break; default: return(CMD_PARAM_ERROR); } } if (argc == optind+1) { if (!strcmp(argv[optind],"vsa")) { dhcpDumpVsa(); return(CMD_SUCCESS); } else return(CMD_PARAM_ERROR); } else if (argc != optind) return(CMD_PARAM_ERROR); /* Initialize the retransmission delay calculator: */ RetransmitDelay(DELAY_INIT_DHCP); if (bootp) { DHCPState = BOOTPSTATE_INITIALIZE; BOOTPStartup(0); } else { DHCPState = DHCPSTATE_INITIALIZE; DHCPStartup(0); } return(CMD_SUCCESS);}/* dhcpDumpVsa(): * Simply dump the content of the VSA shell variable in DHCP format. * The variable content is stored in ascii and must be converted to binary * prior to calling printDhcpOptions(). */voiddhcpDumpVsa(void){ int i; char tmp[3], *vsa_b, *vsa_a, len; vsa_a = getenv("DHCPVSA"); if (!vsa_a) return; len = strlen(vsa_a); vsa_b = malloc(len); if (!vsa_b) return; len >>= 1; tmp[2] = 0; for(i=0;i<len;i++) { tmp[0] = *vsa_a++; tmp[1] = *vsa_a++; vsa_b[i] = (char)strtol(tmp,0,16); } /* First 4 bytes of DHCPVSA is the cookie, so skip over that. */ printDhcpOptions(vsa_b+4); free(vsa_b);}voiddhcpDisable(){ DHCPState = DHCPSTATE_NOTUSED;}/* DHCPStartup(): * This function is called at the point in which the ethernet interface is * started if, and only if, the IPADD shell variable is set to DHCP. * In older version of DHCP, the default was to use "LUCENT.PPA.1.1" as * the default vcid. Now it is only used if specified in the shell variable * DHCPCLASSID. The same strategy applies to DHCPCLIENTID.*/intDHCPStartup(short seconds){ char *id, *colon, *rlist;#if !INCLUDE_TFTP printf("WARNING: DHCP can't load bootfile, TFTP not built into monitor.\n");#endif /* The format of DHCPCLASSID is simply a string of characters. */ id = getenv("DHCPCLASSID"); if (id) DHCPClassId = id; else DHCPClassId = ""; DHCPClassIdSize = strlen(DHCPClassId); /* The format of DHCPCLIENTID is "TYPE:ClientID" where 'TYPE is a * decimal number ranging from 1-255 used as the "type" portion of * the option, and ClientID is a string of ascii-coded hex pairs * that are converted to binary and used as the client identifier. */ id = getenv("DHCPCLIENTID"); if (id) { colon = strchr(id,':'); if ((colon) && (!(strlen(colon+1) & 1))) { DHCPClientIdType = atoi(id); colon++; for(DHCPClientIdSize=0;*colon;DHCPClientIdSize++) { uchar tmp; tmp = colon[2]; colon[2] = 0; DHCPClientId[DHCPClientIdSize] = (uchar)strtol(colon,0,16); colon[2] = tmp; colon+=2; } } } else DHCPClientIdSize = 0; /* The format of DHCPRQSTLIST is #:#:#:#:# where each '#' is a decimal * number representing a parameter to be requested via the Parameter * Request List option... */ rlist = getenv("DHCPRQSTLIST"); if (rlist) { DHCPRqstListSize = 0; colon = rlist; while(*colon) { if (*colon++ == ':') DHCPRqstListSize++; } if (DHCPRqstListSize > sizeof(DHCPRequestList)) { printf("DHCPRQSTLIST too big.\n"); DHCPRqstListSize = 0; } else { char *rqst; DHCPRqstListSize = 0; rqst = rlist; while(1) { DHCPRequestList[DHCPRqstListSize++] = strtol(rqst,&colon,0); if (*colon != ':') break; rqst = colon+1; } DHCPRequestList[DHCPRqstListSize] = 0; } } else DHCPRqstListSize = 0; return(SendDHCPDiscover(0,seconds));}intBOOTPStartup(short seconds){ return(SendDHCPDiscover(1,seconds));}uchar *dhcpLoadShellVarOpts(uchar *options){ if (DHCPClassIdSize) { *options++ = DHCPOPT_CLASSID; *options++ = DHCPClassIdSize; memcpy(options,DHCPClassId,DHCPClassIdSize); options += DHCPClassIdSize; } if (DHCPClientIdSize) { *options++ = DHCPOPT_CLIENTID; *options++ = DHCPClientIdSize+1; *options++ = DHCPClientIdType; memcpy(options,DHCPClientId,DHCPClientIdSize); options += DHCPClientIdSize; } if (DHCPRqstListSize) { *options++ = DHCPOPT_PARMRQSTLIST; *options++ = DHCPRqstListSize; memcpy(options,DHCPRequestList,DHCPRqstListSize); options += DHCPRqstListSize; } return(options);}/* SendDHCPDiscover() * The DHCPDISCOVER is issued as an ethernet broadcast. IF the bootp * flag is non-zero then just do a bootp request (a subset of the * DHCPDISCOVER stuff). */intSendDHCPDiscover(int bootp,short seconds){ struct dhcphdr *dhcpdata; struct bootphdr *bootpdata; struct ether_header *te; struct ip *ti; struct Udphdr *tu; ushort uh_ulen; int optlen; char *dhcpflags; ulong cookie; uchar *dhcpOptions, *dhcpOptionsBase; /* Retrieve an ethernet buffer from the driver and populate the * ethernet level of packet: */ 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); /* Move to the IP portion of the packet and populate it appropriately: */ 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); /* Now udp... */ tu = (struct Udphdr *) (ti + 1); tu->uh_sport = ecs(DhcpClientPort); tu->uh_dport = ecs(DhcpServerPort); /* First the stuff that is the same for BOOTP or DHCP... */ bootpdata = (struct bootphdr *)(tu+1); dhcpdata = (struct dhcphdr *)(tu+1); dhcpdata->op = DHCPBOOTP_REQUEST; dhcpdata->htype = 1; dhcpdata->hlen = 6; dhcpdata->hops = 0; dhcpdata->seconds = ecs(seconds); memset(dhcpdata->bootfile,0,sizeof(dhcpdata->bootfile)); memset(dhcpdata->server_hostname,0,sizeof(dhcpdata->server_hostname)); /* For the first DHCPDISCOVER issued, establish a transaction id based * on a crc32 of the mac address. For each DHCPDISCOVER after that, * just increment. */ if (!DHCPTransactionId) DHCPTransactionId = crc32(BinEnetAddr,6); else DHCPTransactionId++; memcpy((char *)&dhcpdata->transaction_id,(char *)&DHCPTransactionId,4); memset((char *)&dhcpdata->client_ip,0,4); memset((char *)&dhcpdata->your_ip,0,4); memset((char *)&dhcpdata->server_ip,0,4); memset((char *)&dhcpdata->router_ip,0,4); memcpy(dhcpdata->client_macaddr,BinEnetAddr,6); dhcpflags = getenv("DHCPFLAGS"); if (dhcpflags) /* 0x8000 is the only bit used currently. */ dhcpdata->flags = (ushort)strtoul(dhcpflags,0,0); else dhcpdata->flags = 0; self_ecs(dhcpdata->flags); /* Finally, the DHCP or BOOTP specific stuff... * Based on RFC1534 (Interoperation Between DHCP and BOOTP), any message * received by a DHCP server that contains a 'DHCP_MESSAGETYPE' option * is assumed to have been sent by a DHCP client. A message without the * DHCP_MESSAGETYPE option is assumed to have been sent by a BOOTP * client. */ uh_ulen = optlen = 0; if (bootp) { memset(bootpdata->vsa,0,sizeof(bootpdata->vsa)); uh_ulen = sizeof(struct Udphdr) + sizeof(struct bootphdr); tu->uh_ulen = ecs(uh_ulen); } else { if (!buildDhcpHdr(dhcpdata)) { /* The cookie should only be loaded at the start of the * vendor specific area if vendor-specific options are present. */ cookie = ecl(STANDARD_MAGIC_COOKIE); memcpy((char *)&dhcpdata->magic_cookie,(char *)&cookie,4); dhcpOptionsBase = (uchar *)(dhcpdata+1); dhcpOptions = dhcpOptionsBase; *dhcpOptions++ = DHCPOPT_MESSAGETYPE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -