?? dhcp_prot.c
字號:
/*==========================================================================
//
// dhcp_prot.c
//
// DHCP protocol implementation for DHCP client
//
//==========================================================================
//####ECOSPDCOPYRIGHTBEGIN####
//
// Copyright (C) 2000, 2001, 2002 Red Hat, Inc.
// All Rights Reserved.
//
// Permission is granted to use, copy, modify and redistribute this
// file.
//
//####ECOSPDCOPYRIGHTEND####
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): hmt
// Contributors: gthomas
// Date: 2000-07-01
// Purpose: DHCP support
// Description:
//
//####DESCRIPTIONEND####
//
//========================================================================*/
/* Define these locally because we are porting this code from a later package,
* therefore these are not defined in pkgconf/net.h */
#define CYGPKG_NET_DHCP
#define CYGOPT_NET_DHCP_DHCP_THREAD
/*Added to fix bug 2757, DHCPDISCOVER AND DHCPREQUEST have the broadcast bit set*/
#define ORIG_DHCP_CODE
#ifdef CYGPKG_NET_DHCP
#include <pkgconf/system.h>
#include <pkgconf/net.h>
#if 0
#define perror( txt ) // nothing
#endif
#include <network.h>
#include <dhcp.h>
#include <errno.h>
#include <cyg/infra/cyg_ass.h>
#ifdef INET6
#include <net/if_var.h>
#include <netinet6/in6_var.h>
#endif
#ifdef AP5X
#include "oem.h"
#define DHCP_TIMEOUT_IN_SEC 20
#else
#include "buildModes.h"
#endif
// ------------------------------------------------------------------------
// Returns a pointer to the end of dhcp message (or NULL if invalid)
// meaning the address of the byte *after* the TAG_END token in the vendor
// data.
static unsigned char *
scan_dhcp_size( struct bootp *ppkt )
{
unsigned char *op;
op = &ppkt->bp_vend[0];
// First check for the cookie!
if ( op[0] != 99 ||
op[1] != 130 ||
op[2] != 83 ||
op[3] != 99 )
{
CYG_FAIL( "Bad DHCP cookie" );
return NULL;
}
op += 4;
while (*op != TAG_END)
{
#if 1
if(*op == 0x0f) /* temp code to bypass the len problem, later remove this
if stat completely */
{
//op += *(op + 1) + 2;
*op = TAG_END;
}
else
#endif
{
op += *(op + 1) + 2;
}
#if 1
if ( op > &ppkt->bp_vend[BP_VEND_LEN - 1] )
{
CYG_FAIL( "Oversize DHCP packet in dhcp_size");
return NULL;
}
#endif
}
// Check op has not gone wild
CYG_ASSERT( op > (unsigned char *)(&ppkt[0]), "op pointer underflow!" );
// Compare op with non-existent "next" struct bootp in the array.
CYG_ASSERT( op < (unsigned char *)(&ppkt[1]), "op pointer overflow!" );
return op + 1; // Address of first invalid byte
}
// ------------------------------------------------------------------------
// Get the actual packet size of an initialized buffer
static int
dhcp_size( struct bootp *ppkt )
{
unsigned char *op;
op = scan_dhcp_size( ppkt );
if ( !op )
return 0;
return (op - (unsigned char *)ppkt);
}
// ------------------------------------------------------------------------
// Get the actual packet size of an initialized buffer
// This will also pad the packet with 0 if length is less
// than BP_STD_TX_MINPKTSZ.
static int
dhcp_size_for_send( struct bootp *ppkt )
{
unsigned char *op;
op = scan_dhcp_size( ppkt );
if ( !op )
return 0; // Better not scribble!
// Zero extra bytes until the packet is large enough.
for ( ; op < (((unsigned char *)ppkt) + BP_STD_TX_MINPKTSZ); op++ )
*op = 0;
return (op - (unsigned char *)ppkt);
}
// ------------------------------------------------------------------------
// Insert/set an option value in an initialized buffer
static int
set_fixed_tag( struct bootp *ppkt,
unsigned char tag,
cyg_uint32 value,
int len)
{
unsigned char *op;
// Initially this will only scan the options field.
op = &ppkt->bp_vend[4];
while (*op != TAG_END)
{
if ( op > &ppkt->bp_vend[BP_VEND_LEN - 1] )
{
CYG_FAIL( "Oversize DHCP packet in set_fixed_tag" );
return false;
}
if (*op == tag) // Found it...
break;
op += *(op + 1) + 2;
}
if (*op == tag)
{ // Found it...
if ( *(op + 1) != len )
{
CYG_FAIL( "Wrong size in set_fixed_tag" );
return false; // wrong size
}
}
else
{ // overwrite the end tag and install a new one
if ( op + len + 2 > &ppkt->bp_vend[BP_VEND_LEN - 1] )
{
CYG_FAIL( "Oversize DHCP packet in set_fixed_tag append" );
return false;
}
*op = tag;
*(op + 1) = len;
*(op + len + 2) = TAG_END;
}
// and insert the value. Net order is BE.
op += len + 2 - 1; // point to end of value
while ( len-- > 0 )
{
*op-- = (unsigned char)(value & 255);
value >>= 8;
}
return true;
}
// Note that this does not permit changing the size of an extant tag.
static int
set_variable_tag( struct bootp *ppkt,
unsigned char tag,
cyg_uint8 *pvalue,
int len)
{
unsigned char *op;
// Initially this will only scan the options field.
op = &ppkt->bp_vend[4];
while (*op != TAG_END)
{
if ( op > &ppkt->bp_vend[BP_VEND_LEN - 1] )
{
CYG_FAIL( "Oversize DHCP packet in set_variable_tag" );
return false;
}
if (*op == tag) // Found it...
break;
op += *(op + 1) + 2;
}
if (*op == tag)
{ // Found it...
if ( *(op + 1) != len )
{
CYG_FAIL( "Wrong size in set_variable_tag" );
return false; // wrong size
}
}
else
{ // overwrite the end tag and install a new one
if ( op + len + 2 > &ppkt->bp_vend[BP_VEND_LEN - 1] )
{
CYG_FAIL( "Oversize DHCP packet in set_variable_tag append" );
return false;
}
*op = tag;
*(op + 1) = len;
*(op + len + 2) = TAG_END;
}
// and insert the value. No order is implied.
op += 2; // point to start of value
while ( len-- > 0 )
{
*op++ = *pvalue++;
}
return true;
}
static int
unset_tag( struct bootp *ppkt,
unsigned char tag )
{
unsigned char *op, *nextp = 0, *killp = 0;
// Initially this will only scan the options field.
op = &ppkt->bp_vend[4];
while (*op != TAG_END)
{
if ( op > &ppkt->bp_vend[BP_VEND_LEN - 1] )
{
CYG_FAIL( "Oversize DHCP packet in unset_tag" );
return false;
}
if (*op == tag)
{ // Found it...
killp = op; // item to kill
nextp = op + *(op + 1) + 2; // next item address
}
op += *(op + 1) + 2; // scan to the end
}
if ( !killp )
return false;
// Obliterate the found op by copying down: *op is the end.
while ( nextp <= op ) // <= to copy the TAG_END too.
*killp++ = *nextp++;
return true;
}
// ------------------------------------------------------------------------
// Bring up an interface enough to broadcast, before we know who we are
static int
bring_half_up(const char *intf, struct ifreq *ifrp )
{
int s;
int one = 1;
struct sockaddr_in *addrp;
struct ecos_rtentry route;
// Ensure clean slate
route_reinit(); // Force any existing routes to be forgotten
s = socket(AF_INET, SOCK_DGRAM, 0);
if (s < 0)
{
perror("socket");
return false;
}
if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &one, sizeof(one)))
{
perror("setsockopt");
return false;
}
addrp = (struct sockaddr_in *) &ifrp->ifr_addr;
memset(addrp, 0, sizeof(*addrp));
addrp->sin_family = AF_INET;
addrp->sin_len = sizeof(*addrp);
addrp->sin_port = 0;
addrp->sin_addr.s_addr = INADDR_ANY;
strcpy(ifrp->ifr_name, intf);
if (ioctl(s, SIOCSIFADDR, ifrp))
{ /* set ifnet address */
perror("SIOCSIFADDR");
return false;
}
if (ioctl(s, SIOCSIFNETMASK, ifrp))
{ /* set net addr mask */
perror("SIOCSIFNETMASK");
return false;
}
/* the broadcast address is 255.255.255.255 */
memset(&addrp->sin_addr, 255, sizeof(addrp->sin_addr));
if (ioctl(s, SIOCSIFBRDADDR, ifrp))
{ /* set broadcast addr */
perror("SIOCSIFBRDADDR");
return false;
}
ifrp->ifr_flags = IFF_UP | IFF_BROADCAST | IFF_RUNNING;
if (ioctl(s, SIOCSIFFLAGS, ifrp))
{ /* set ifnet flags */
perror("SIOCSIFFLAGS up");
return false;
}
if (ioctl(s, SIOCGIFHWADDR, ifrp) < 0)
{ /* get MAC address */
perror("SIOCGIFHWADDR 1");
return false;
}
// Set up routing
addrp->sin_family = AF_INET;
addrp->sin_port = 0;
addrp->sin_len = sizeof(*addrp); // Size of address
/* the broadcast address is 255.255.255.255 */
memset(&addrp->sin_addr, 255, sizeof(addrp->sin_addr));
memset(&route, 0, sizeof(route));
memcpy(&route.rt_gateway, addrp, sizeof(*addrp));
addrp->sin_addr.s_addr = INADDR_ANY;
memcpy(&route.rt_dst, addrp, sizeof(*addrp));
memcpy(&route.rt_genmask, addrp, sizeof(*addrp));
route.rt_dev = ifrp->ifr_name;
route.rt_flags = RTF_UP | RTF_GATEWAY;
route.rt_metric = 0;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -