📄 dhcp.c
字号:
/**************************************************************************
*
* CopyrIght (c) 1993 - 2001 Accelerated Technology, Inc.
*
* PROPRIETARY RIGHTS of Accelerated Technology are involved in the subject
* matter of this material. All manufacturing, reproduction, use and sales
* rights pertaining to this subject matter are governed by the license
* agreement. The recipient of this software implicity accepts the terms
* of the license.
*
****************************************************************************/
/****************************************************************************
* FILENAME VERSION
*
* DHCP.C 4.4
*
* DESCRIPTION
*
* This file will contain all the DHCP routines.
*
*
* DATA STRUCTURES
*
* None.
*
* FUNCTIONS
*
* NU_Dhcp Creates a DHCP request packet and
* sends to the DHCP server to obtain an
* IP address for the specified named
* device.
* NU_Dhcp_Release Releases the address obtained by the
* DHCP process.
* DHCP_Build_Message Initializes DHCP Packet.
* DHCP_Event_Handler Process DHCP timer events.
* DHCP_Initialize Initialize the DHCP Module.
* DHCP_Init_IP_Layer Initialize the IP header that
* encapsulates the DHCP message.
* DHCP_Init_UDP_Layer Initialize the UDP header that
* encapsulates the DHCP message.
* DHCP_Init_DHCP_Layer Initialize the DHCP message.
* DHCP_Message_Type Return the DHCP message type.
* DHCP_Pkt_Copy Copy a DHCP message into a Nucleus
* NET buffer chain.
* DHCP_Process_ACK Process a DHCP ACK message.
* DHCP_Process_Offer Process a DHCP offer message.
* DHCP_Queue_Event Push an event onto the DHCP event Queue.
* DHCP_Send Send a DHCP Message.
* DHCP_Send_Request Send a DHCP Request message.
* DHCP_Vendor_Options User defined vendor option function.
* DHCP_Validate User defined validation function.
* DHCP_Init_Timers
* DHCP_Update_Timers
*
* DEPENDENCIES
*
* DHCP.H Holds the defines necessary for
* DHCP to function properly.
*
*
*****************************************************************************/
#include "plus/nucleus.h"
#include "net/target.h"
#include "net/inc/nerrs.h"
#include "net/inc/externs.h"
#include "net/inc/ip.h"
#include "net/inc/tcp.h"
#include "net/inc/dhcp.h"
#include "net/inc/netevent.h"
#include "net/inc/udp.h"
/* Only compile this code if DHCP is to be used. */
#if (INCLUDE_DHCP == NU_TRUE)
/* Define prototypes for function references. */
static STATUS DHCP_Build_Message( NET_BUFFER **, DHCP_STRUCT *,
DV_DEVICE_ENTRY *, UINT8);
static STATUS DHCP_Pkt_Copy(UINT8 *, NET_BUFFER *, INT);
static STATUS DHCP_Send_Request( DHCP_STRUCT *, INT, DV_DEVICE_ENTRY *);
static VOID DHCP_Init_UDP_Layer(NET_BUFFER *buf_ptr, UINT32 src, UINT32 dst);
static VOID DHCP_Init_IP_Layer(NET_BUFFER *buf_ptr, UINT32 ip_src, UINT32
ip_dest);
static STATUS DHCP_Init_DHCP_Layer( NET_BUFFER *, DHCP_STRUCT *,
DV_DEVICE_ENTRY *, UINT8);
static STATUS DHCP_Send(DV_DEVICE_ENTRY *, DHCP_STRUCT *, UINT8);
static STATUS DHCP_Vendor_Options(DV_DEVICE_ENTRY *, UINT8, UINT16, UINT8 *,
DHCP_STRUCT *);
static STATUS DHCP_Process_ACK(INT, DHCP_STRUCT *, DV_DEVICE_ENTRY *, UINT32);
static STATUS DHCP_Process_Offer(INT, DHCP_STRUCT *, DV_DEVICE_ENTRY *, UINT32);
static UINT8 DHCP_Message_Type(UINT8 *opt);
static VOID DHCP_Event_Handler(UNSIGNED argc, VOID *argv);
static VOID DHCP_Init_Timers(DV_DEVICE_ENTRY *device);
NU_TASK *DHCP_Event_Handler_Tcb;
NU_QUEUE *DHCP_Event_Queue;
/* These two globals will be initialized with the well known port numbers for a
DHCP client and a DHCP server. */
INT16 DHCP_Server_Port;
INT16 DHCP_Client_Port;
/* Take advantage of the TCP backoff values for DHCP. */
extern INT TCP_Backoff[];
extern NU_TASK NU_EventsDispatcher_ptr;
extern NU_TASK timer_task_ptr;
/******************************************************************************
* FUNCTION
*
* NU_Dhcp
*
* DESCRIPTION
*
* This function creates a DHCP request packet and sends it
* to the DHCP server to obtain an IP address for the specified
* named device.
*
* INPUTS
*
* ds_ptr Pointer to DHCP Structure that
* contains data that can be obtained
* at the application layer.
* dv_name Pointer to Device name.
*
* OUTPUTS
*
* NU_SUCCESS
* NU_DHCP_INIT_FAILED
* NU_INVALID_PROTOCOL
* NU_NO_MEMORY
* NU_NO_SOCKET_SPACE
* NU_DHCP_REQUEST_FAILED
*
*
******************************************************************************/
STATUS NU_Dhcp(DHCP_STRUCT *ds_ptr, CHAR *dv_name)
{
INT i;
INT ret;
INT found = 0;
STATUS socketd = -1;
INT32 delay, rand;
STATUS retval;
struct addr_struct clientaddr;
DV_DEVICE_ENTRY *device;
STATUS status;
NU_SUPERV_USER_VARIABLES
if (ds_ptr == NU_NULL || dv_name == NU_NULL)
return (NU_INVALID_PARM);
/* Get a pointer to the interface. */
device = DEV_Get_Dev_By_Name(dv_name);
if( device == (DV_DEVICE_ENTRY *)0 )
return NU_DHCP_INIT_FAILED;
/* Switch to supervisor mode. */
NU_SUPERVISOR_MODE();
/* Copy device MAC address */
memcpy(ds_ptr->dhcp_mac_addr, device->dev_mac_addr, DADDLEN);
/* If options were provided and this is the first time an attempt has been
made to obtain a lease for this device then memory needs to be allocated
to store the options in. */
if ( (ds_ptr->dhcp_opts != NU_NULL) &&
(device->dev_addr.dev_dhcp_options == NU_NULL))
{
status = NU_Allocate_Memory(&System_Memory,
(VOID **)&device->dev_addr.dev_dhcp_options,
(UNSIGNED)ds_ptr->dhcp_opts_len,
(UNSIGNED)NU_NO_SUSPEND);
if (status != NU_SUCCESS)
{
retval = status;
goto DHCP_Exit;
}
/* Copy the user specified options. */
memcpy(device->dev_addr.dev_dhcp_options, ds_ptr->dhcp_opts,
ds_ptr->dhcp_opts_len);
/* Preserve the length of the options. */
device->dev_addr.dev_dhcp_opts_length = ds_ptr->dhcp_opts_len;
}
/* Create a socket and bind to it, so that we can receive packets. */
socketd = NU_Socket(NU_FAMILY_IP, NU_TYPE_DGRAM, NU_NONE);
if( socketd < NU_SUCCESS )
{
NERRS_Log_Error( NERR_FATAL, __FILE__, __LINE__);
NU_USER_MODE();
return socketd;
}
/* build local address and port to bind to. */
clientaddr.family = NU_FAMILY_IP;
clientaddr.port = DHCP_Client_Port;
*(UINT32 *)clientaddr.id.is_ip_addrs = 0;
clientaddr.name = "DHCP";
/* Bind the socket. */
ret = NU_Bind(socketd, &clientaddr, 0);
if( ret != socketd )
{
NERRS_Log_Error( NERR_FATAL, __FILE__, __LINE__);
retval = NU_DHCP_INIT_FAILED;
goto DHCP_Exit;
}
/* Grab the semaphore because we are about to by pass the sockets API
to create a UDP port. */
NU_Obtain_Semaphore(&TCP_Resource, NU_SUSPEND);
/* Create the UDP port. Normally this would get created during the
send of the DHCP discover. However, DHCP does not use the socket API
for sending. */
if (UDP_Make_Port(clientaddr.port, socketd) < 0)
{
NERRS_Log_Error( NERR_FATAL, __FILE__, __LINE__);
retval = NU_DHCP_INIT_FAILED;
goto DHCP_Exit;
}
NU_Release_Semaphore(&TCP_Resource);
UTL_Zero(ds_ptr->dhcp_siaddr, sizeof(ds_ptr->dhcp_siaddr));
UTL_Zero(ds_ptr->dhcp_giaddr, sizeof(ds_ptr->dhcp_giaddr));
UTL_Zero(ds_ptr->dhcp_sname, sizeof(ds_ptr->dhcp_sname));
UTL_Zero(ds_ptr->dhcp_file, sizeof(ds_ptr->dhcp_file));
/* Initialize the transaciton ID. */
ds_ptr->dhcp_xid = UTL_Rand();
/* Set the DHCP state. */
device->dev_addr.dev_dhcp_state = DHCP_INIT_STATE;
/* The (i + 2) check is because the third element of the
TCP backoff array is used first and we don't want to
extend past the end of the backoff array. See it's use below. */
for( i = 0; (i < RETRIES_COUNT) && ( (i + 2) < TCP_MAX_BACKOFFS); i++ )
{
/* Send the packet. */
status = DHCP_Send(device, ds_ptr, DHCPDISCOVER);
if( status != NU_SUCCESS )
{
NERRS_Log_Error( NERR_FATAL, __FILE__, __LINE__);
retval = status;
goto DHCP_Exit;
}
/* Compute a delay between retransmissions of DHCP messages. RFC 2131
specifies that a randomized exponential backoff algorithm must be
used. The first retransmission should be at 4 seconds, then 8, then
16, etc., up to a max of 64. This value should be randomized by plus
or minus a second. */
/* Get a random number. */
rand = UTL_Rand();
/* Compute a number that is between 0 and SCK_Ticks_Per_Second. */
delay = rand % SCK_Ticks_Per_Second;
/* At this point we have a delay that is equal to some value between
0 and 1 second. Now an arbitrary bit has been chosen from the random
number. If this bit is set then change the sign of the delay. About
half the time we should end up with a negative number. */
if (rand & 0x80)
delay = (-delay);
/* Here we make use of the TCP backoff array. This array looks like
{1, 2, 4, 8, 16, .... 64, 64,..}. The first value taken from this
array will be 4 (i+2). 4 will be multiplied by SCK_Ticks_Per_Second and
the original delay will be added to it. The original delay
will be a number of ticks that is in the range of -1 to +1 seconds.
The final delay computed will be between 3 and 5 seconds (4 +|- 1). */
delay = (TCP_Backoff[i+2] * SCK_Ticks_Per_Second) + delay;
/* Look at each packet on buffer_list to see if it is mine */
found = DHCP_Process_Offer(socketd, ds_ptr, device, (UINT32)delay);
/* An Offer was received. Get out of the loop. */
if( found )
break;
found = 0;
}
/* The returned value from DHCP_Process_Packet is tested here */
/* to see if the IP address was accepted by the caller. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -