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

📄 netdhcp.c

📁 一个tcp/ip协议栈,带有PPP、IP、TCP、UDP等协议
💻 C
字号:
/*****************************************************************************
* netdhcp.c - 
*
* portions Copyright (c) 2001 by Cognizant Pty Ltd.
* portions Copyright (c) 2002 by Access Devices Ltd.
*
* The authors hereby grant permission to use, copy, modify, distribute,
* and license this software and its documentation for any purpose, provided
* that existing copyright notices are retained in all copies and that this
* notice and the following disclaimer are included verbatim in any 
* distributions. No written agreement, license, or royalty fee is required
* for any of the authorized uses.
*
* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
* REVISION HISTORY (please don't use tabs!)
*
*(yyyy-mm-dd)
* 2001-06-01 Robert Dickenson <odin@pnc.com.au>, Cognizant Pty Ltd.
*            Original file.
* 2002-01-03 Craig Graham <c_graham@hinge.mistral.co.uk>, Access Devices Ltd
*            Implemented DHCP (sort of, not fully, but works ok).
******************************************************************************
*/
#include "netconf.h"
#include "net.h"
#include "netbuf.h"
#include "netos.h"
#include <stdio.h>
#include <string.h>
#include "netdebug.h"
#include "netudp.h"
#include "netaddrs.h"
#include "netether.h"
#include "netip.h"
#include "netdhcp.h"

// this is in netether.c
extern etherSetup mySetup;
extern u_int32_t localHost;
extern int inDHCP;

#define DHCP_DEBUG(X) printf X

/**
 * Broadcast a DHCPDISCOVER message.
 * We cheat a little here, by fiddling our IP address instead of setting up the rest of
 * the stack to support broadcast stuff...
 */
static int DHCP_SendDiscover(DHCP_INFO* i)
{
	unsigned char buf[sizeof(DHCP_HEADER) + 100];
	unsigned char* option;
	struct sockaddr_in addr;
	DHCP_HEADER *h = (DHCP_HEADER*)buf;

	DHCP_DEBUG(("DHCP_SendDiscover()\n"));
	localHost = 0;
	option = (unsigned char*)(h + 1);
	h->op = DHCP_BOOTREQUEST;
	h->htype = DHCP_ETHERNET;
	h->hlen = 6;
	h->hops = 0;

	h->xid = htonl(i->xid);
	h->secs = 0;
	h->flags = htons(0x8000);
	h->ciaddr = 0;
	h->yiaddr = 0;
	h->siaddr = 0;
	h->giaddr = 0;
	memset(h->chaddr, 0, 16);
	memcpy(h->chaddr, mySetup.hardwareAddr, 6);
	memset(h->sname, 0, 64);
	memset(h->file, 0, 128);
	h->magic = DHCP_MAGIC;
	// set message type DHCPDISCOVER
	*option++ = DHCP_OPTION_MESSAGE_TYPE;
	*option++ = 1;
	*option++ = DHCPDISCOVER;
	// set client identifier (==MAC address)
	*option++ = DHCP_OPTION_CLIENT_IDENTIFIER;
	*option++ = 7;
	*option++ = DHCP_ETHERNET;
	memcpy(option, mySetup.hardwareAddr, 6);
	option += 6;
	// end option
	*option++ = DHCP_OPTION_END;
	// pad out to minimum DHCP packet length
	while (((long)(option-buf)) < 300)
		*option++ = DHCP_OPTION_PAD;
	addr.sin_family = AF_INET;
	addr.sin_port = htons(BOOTPC);	// we have to send from bootp client port (68)
	memset(&addr.sin_addr, 0, 4);
	udpBind(i->s, &addr);
	addr.sin_family = AF_INET;
	addr.sin_port = htons(BOOTPS);	// we have to send to bootp server port (67)
	memset(&addr.sin_addr, 0xff, 4); // broadcast address
	udpSendTo(i->s, buf, (long)(option-buf), &addr);
	i->state = DHCPS_DISCOVER;
    return 0;
}

/**
 * Send a DHCPREQUEST message.
 * We cheat a little here, by fiddling our IP address instead of setting up the rest of
 * the stack to support broadcast stuff...
 */
static int DHCP_SendRequest(DHCP_INFO* i)
{
	unsigned char buf[sizeof(DHCP_HEADER) + 100];
	unsigned char* option;
	DHCP_HEADER* h = (DHCP_HEADER*)buf;
	struct sockaddr_in addr;
//	u_int32_t tmp;

	DHCP_DEBUG(("DHCP_SendRequest()\n"));
	localHost = 0;

	option = (unsigned char*)(h + 1);
	h->op = DHCP_BOOTREQUEST;
	h->htype = DHCP_ETHERNET;
	h->hlen = 6;
	h->hops = 0;
	h->xid = htonl(i->xid);
	h->secs = 0;
	h->flags = htons(0x8000);
	h->ciaddr = 0;
	h->yiaddr = 0;
	h->siaddr = 0;
	h->giaddr = 0;
	memset(h->chaddr, 0, 16);
	memcpy(h->chaddr, mySetup.hardwareAddr, 6);
	memset(h->sname, 0, 64);
	memset(h->file, 0, 128);
	h->magic = DHCP_MAGIC;
	// set message type DHCPREQUEST
	*option++ = DHCP_OPTION_MESSAGE_TYPE;
	*option++ = 1;
	*option++ = DHCPREQUEST;
	// set client identifier ( == MAC address)
	*option++ = DHCP_OPTION_CLIENT_IDENTIFIER;
	*option++ = 7;
	*option++ = DHCP_ETHERNET;
	memcpy(option, mySetup.hardwareAddr, 6);
	option += 6;
	// set ip address we're requesting
	*option++ = DHCP_OPTION_REQUESTED_IP_ADDRESS;
	*option++ = 4;
	*option++ = (i->my_ip>>24) & 0xff;
	*option++ = (i->my_ip>>16) & 0xff;
	*option++ = (i->my_ip>>8) & 0xff;
	*option++ = (i->my_ip) & 0xff;
	// DHCP server's ip address
	*option++ = DHCP_OPTION_SERVER_IDENTIFIER;
	*option++ = 4;
	*option++ = (i->dhcp_server>>24) & 0xff;
	*option++ = (i->dhcp_server>>16) & 0xff;
	*option++ = (i->dhcp_server>>8)& 0xff;
	*option++ = (i->dhcp_server) & 0xff;
	// Let's make sure we get the DNS and gateway passed back.
	// Microsoft's DNS servers don't do this by default (unlike the Linux DHCP server),
	// so we must explicitly ask for them.
	*option++ = DHCP_OPTION_PARAMETER_LIST_REQUEST;
	*option++ = 3;
	*option++ = DHCP_OPTION_ROUTER;
	*option++ = DHCP_OPTION_DNS_SERVER;
	*option++ = DHCP_OPTION_SUBNET_MASK;
	// end option
	*option++ = DHCP_OPTION_END;
	// pad out to minimum DHCP packet length
	while (((long)(option-buf)) < 300)
		*option++ = DHCP_OPTION_PAD;
	addr.sin_family = AF_INET;
	addr.sin_port = htons(BOOTPC);	// we have to send from bootp client port (68)
	memset(&addr.sin_addr, 0, 4);
	udpBind(i->s, &addr);
	addr.sin_family = AF_INET;
	addr.sin_port = htons(BOOTPS);	// we have to send to bootp server port (67)
	memset(&addr.sin_addr, 0xff, 4); // broadcast address
	udpSendTo(i->s, buf, (long)(option-buf), &addr);
	i->state = DHCPS_REQUEST;
    return 0;
}

static void DHCP_GRTimeout(void* p)
{
	DHCP_INFO* i = (DHCP_INFO*)p;
	udpUnblockRead(i->s);
	i->err = -2;
}

static int DHCP_GetResponse(DHCP_INFO* i)
{
	long l;
	unsigned char option;
	unsigned char optionLength;
	u_int32_t tmp;

	DHCP_DEBUG(("DHCP_GetResponse()\n"));

	localHost = 0xffffffff;
__retry:
	i->err = 0;
	if (timerTempSeconds(DHCP_TIMEOUT,DHCP_GRTimeout,i)) {
		i->state = DHCPS_ABORT;
		return -1;
	}

	l  =  udpRead(i->s, &i->h, sizeof(DHCP_HEADER));
	if (i->err)	{
		DHCP_DEBUG(("DHCP_GetResponse():timeout\n"));
		i->state = DHCPS_TIMEOUT;
		return i->err;
	}

	timerCancel(DHCP_GRTimeout,i);
	if (l < 0)
		return l;
	DHCP_DEBUG(("got response, length = %ld\n",l));
	if (l < sizeof(DHCP_HEADER)) {
		i->state = DHCPS_ABORT;
		DHCP_DEBUG(("DHCP_GetResponse():short packet\n"));
		return -4;
	}
	NTOHL(i->h.xid);
	NTOHS(i->h.secs);
	NTOHS(i->h.flags);
	NTOHL(i->h.ciaddr);
	NTOHL(i->h.yiaddr);
	NTOHL(i->h.siaddr);
	NTOHL(i->h.giaddr);
	NTOHL(i->h.magic);
	if (i->h.xid != i->xid)	{
		DHCP_DEBUG(("wrong xid\n"));
		goto __retry;
	}
	if (i->h.magic != DHCP_MAGIC) {
		DHCP_DEBUG(("magic failled\n"));
		return -3;
	}
	DHCP_DEBUG(("seems ok :) - let's process options\n"));
	i->lastMessageType = DHCPERROR;
	do {
		l = udpRead(i->s, &option, 1);
		DHCP_DEBUG(("%ld : ",option));
		switch (option) {
		case DHCP_OPTION_END:
			DHCP_DEBUG(("end\n"));
			udpClose(i->s);
			i->s = udpOpen();
			break;
		case DHCP_OPTION_PAD:
			DHCP_DEBUG(("pad\n"));
			break;
		case DHCP_OPTION_SUBNET_MASK:
			udpRead(i->s, &optionLength, 1);
			udpRead(i->s, &i->subnet_mask, 4);
			NTOHL(i->subnet_mask);
			DHCP_DEBUG(("subnet = %s\n", ip_ntoa(i->subnet_mask)));
			break;
		case DHCP_OPTION_ROUTER:
			udpRead(i->s, &optionLength, 1);
			udpRead(i->s, &i->router, 4);
			NTOHL(i->router);
			optionLength >>= 2;
			while (--optionLength)
				udpRead(i->s, &tmp, 4);
			DHCP_DEBUG(("router = %s\n", ip_ntoa(i->router)));
			break;
		case DHCP_OPTION_DNS_SERVER:
			udpRead(i->s, &optionLength, 1);
			optionLength >>= 2;
			tmp = 0;
			DHCP_DEBUG(("dns server:\n"));
			while ((tmp < 2) && (optionLength)) {
				udpRead(i->s, &i->dns_server[tmp], 4);
				NTOHL(i->dns_server[tmp]);
				DHCP_DEBUG(("   %s\n", ip_ntoa(i->dns_server[tmp])));
				optionLength--;
                tmp++;
			}
			while (optionLength--)
				udpRead(i->s, &tmp, 4);
			break;

		case DHCP_OPTION_MESSAGE_TYPE:
			udpRead(i->s, &optionLength, 1);
			udpRead(i->s, &optionLength, 1);
			i->lastMessageType = (DHCP_MESSAGE_TYPE)optionLength;
			DHCP_DEBUG(("message type = %d\n", i->lastMessageType));
			break;

		case DHCP_OPTION_LEASE_TIME:
			udpRead(i->s, &optionLength, 1);
			udpRead(i->s, &i->lease_time, 4);
			NTOHL(i->lease_time);
			DHCP_DEBUG(("lease time = %ld\n", i->lease_time));
			break;

		case DHCP_OPTION_SERVER_IDENTIFIER:
			udpRead(i->s, &optionLength, 1);
			udpRead(i->s, &i->dhcp_server, 4);
			NTOHL(i->dhcp_server);
			DHCP_DEBUG(("DHCP server = %s\n", ip_ntoa(i->dhcp_server)));
			break;

		case DHCP_OPTION_RENEWAL_TIME:
			udpRead(i->s, &optionLength, 1);
			udpRead(i->s, &i->renewal_time, 4);
			NTOHL(i->renewal_time);
			DHCP_DEBUG(("renewal time = %ld\n", i->renewal_time));
			break;

		case DHCP_OPTION_REBINDING_TIME:
			udpRead(i->s, &optionLength, 1);
			udpRead(i->s, &i->rebinding_time, 4);
			NTOHL(i->rebinding_time);
			DHCP_DEBUG(("rebinding time = %ld\n", i->rebinding_time));
			break;

		default:
			udpRead(i->s, &optionLength, 1);
			DHCP_DEBUG(("unknown option %ld, length %ld\n", option, optionLength));
			while (optionLength--)
				udpRead(i->s, &tmp, 1);
			break;
		}
	} while(option != DHCP_OPTION_END);
	return 0;
}

static int DHCP_Begin(DHCP_INFO* i)
{
	DHCP_DEBUG(("DHCP_Begin()\n"));
	i->s = udpOpen();
	if (i->s < 0) {
		DHCP_DEBUG(("udpOpen() failled\n"));
		i->state = DHCPS_ABORT;
		return -1;
	}
	i->xid = OSTimeGet();
	inDHCP = 1;
	i->state = DHCPS_BEGIN;
	return 0;
}

static int DHCP_End(DHCP_INFO* i)
{
	DHCP_DEBUG(("DHCP_End()\n"));
	if (i->s >= 0) {
		inDHCP = 0;
		udpClose(i->s);
		return 0;
	}
	return -1;
}

int DHCP(void)
{
	DHCP_INFO i;
	int retry = DHCP_MAX_RETRYS;

	DHCP_DEBUG(("DHCP()\n"));
	if (DHCP_Begin(&i))
		return -1;
	do {
		switch (i.state) {
		case DHCPS_BEGIN:
			DHCP_SendDiscover(&i);
			break;
		case DHCPS_OK:
			break;
		case DHCPS_DISCOVER:
			if (DHCP_GetResponse(&i))
				break;
			switch(i.lastMessageType) {
			case DHCPOFFER:
				DHCP_DEBUG(("had an offer: %s\n",ip_ntoa(i.h.yiaddr)));
				i.my_ip = i.h.yiaddr;
				DHCP_SendRequest(&i);
				break;
			default:
				DHCP_DEBUG(("error1\n"));
				break;
			}
			break;
		case DHCPS_TIMEOUT:
			if (--retry) i.state = DHCPS_BEGIN;
			else         i.state = DHCPS_ABORT;
			break;
		case DHCPS_REQUEST:
			if (DHCP_GetResponse(&i))
				break;
			switch(i.lastMessageType) {
			case DHCPACK:
				DHCP_DEBUG(("got ACK :)\n"));
				i.state = DHCPS_OK;
				break;
			case DHCPNAK:
				if (--retry)
					i.state = DHCPS_BEGIN;
				else
					i.state = DHCPS_ABORT;
				break;
			default:
				DHCP_DEBUG(("error2\n"));
				break;
			}
			break;
		}
	} while ((i.state != DHCPS_ABORT) && (i.state != DHCPS_OK));
	DHCP_End(&i);
	if (i.state == DHCPS_OK) {
		// this is a really bad way of reconfiguring the ethernet - what we really need is
		// a way to reconfig it...
		DHCP_DEBUG(("DHCP(): success\n"));
		localHost = mySetup.localAddr = i.my_ip;
		mySetup.gatewayAddr = i.router;
		mySetup.subnetMask = i.subnet_mask;
		DHCP_DEBUG((" our IP =  %s\n", ip_ntoa(i.my_ip)));
		DHCP_DEBUG((" default gateway = %s\n", ip_ntoa(i.router)));
		DHCP_DEBUG((" subnet = %s\n", ip_ntoa(i.subnet_mask)));
	} else {
		DHCP_DEBUG(("DHCP(): failled\n"));
	}
	return (i.state == DHCPS_OK) ? 0 : -1;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -