⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dhcpboot.c

📁 umon bootloader source code, support mips cpu.
💻 C
📖 第 1 页 / 共 3 页
字号:
/* 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"
#include "timer.h"

int	DHCPStartup(short), BOOTPStartup(short);
int DhcpSetEnv(char *,char *);
int SendDHCPDiscover(int,short);
void dhcpDumpVsa(void), printDhcpOptions(uchar *);

unsigned short	DHCPState;

#if INCLUDE_DHCPBOOT

static struct elapsed_tmr dhcpTmr;
static 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",
	"-[brvV] [vsa]",
#if INCLUDE_VERBOSEHELP
	"Options...",
	" -b      use bootp",
	" -r      retry",
	" -v|V    verbosity",
#endif
		0,
};

int
Dhcp(int argc,char *argv[])
{
	int	opt, bootp;

	bootp = 0;
	DHCPCommandIssued = 1;
	while ((opt=getopt(argc,argv,"brvV")) != -1) {
		switch(opt) {
		case 'b':
			bootp = 1;
			break;
		case 'r':
			DHCPCommandIssued = 0;
			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);

	startElapsedTimer(&dhcpTmr,RetransmitDelay(DELAY_INIT_DHCP)*1000);

	if (bootp) {
		DHCPState = BOOTPSTATE_INITIALIZE;
		if (DHCPCommandIssued)
			BOOTPStartup(0);
	}
	else {
		DHCPState = DHCPSTATE_INITIALIZE;
		if (DHCPCommandIssued)
			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().
 */
void
dhcpDumpVsa(void)
{
	int		i;
	char	tmp[3],  *vsa_b, *vsa_a, len;

	vsa_a = getenv("DHCPVSA");
	if ((!vsa_a) || (!strcmp(vsa_a,"TRUE")))
		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);
}

void
dhcpDisable()
{
	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.
*/
int
DHCPStartup(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));
}

int
BOOTPStartup(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).
 */
int
SendDHCPDiscover(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 + -