📄 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#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//#define CYGDBG_NET_DHCP_CHATTER#ifdef CYGDBG_NET_DHCP_CHATTER#define perror diag_printf#endif#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 bufferstatic intdhcp_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 intdhcp_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 bufferstatic intset_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 intset_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 intunset_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 arestatic intbring_half_up(const char *intf, struct ifreq *ifrp, int *s_p , cyg_uint8 state ){ int s; int one = 1; struct sockaddr_in *addrp; s = socket(AF_INET, SOCK_DGRAM, 0); *s_p = s; 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); /* ioctl calls only on init, MAC addr get is for building packet*/ if(state == DHCPSTATE_INIT){ if (ioctl(s, SIOCSIFADDR, ifrp)) { /* set ifnet address */ if (errno != EEXIST) { perror("SIOCSIFADDR");#ifdef CYGDBG_NET_DHCP_CHATTER diag_printf (" errno = %d\n", errno);#endif 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; } if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one))) { perror("setsockopt SO_REUSEADDR"); return false; } if (setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one))) { perror("setsockopt SO_REUSEPORT"); return false; } *s_p = s; return true;}// ------------------------------------------------------------------------// DHCP retransmission timeouts and number of tries//// To work better with simulated failures (or real ones!) so that the rest// of the system is tested, rather than DHCP renewal failures pulling// everything down, we try a little more zealously than the RFC suggests.static unsigned char timeout_random = 0;struct timeout_state{ unsigned int secs; int countdown;};static inline void reset_timeout( struct timeval *ptv, struct timeout_state *pstate ){ timeout_random++; pstate->countdown = 4; // initial fast retries pstate->secs = 3 + (timeout_random & 3); ptv->tv_sec = 0; ptv->tv_usec = 65536 * (2 + (timeout_random & 3)); // 0.1 - 0.3S, about// ptv->tv_usec = 65536 * (7 + (timeout_random & 3)); // 0.1 - 0.3S, about}static inline int next_timeout( struct timeval *ptv, struct timeout_state *pstate ){ if ( 0 < pstate->countdown-- ) return true; if ( 0 == ptv->tv_sec ) ptv->tv_sec = pstate->secs;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -