dhcp_prot.c
来自「eCos操作系统源码」· C语言 代码 · 共 1,431 行 · 第 1/4 页
C
1,431 行
/*==========================================================================//// dhcp_prot.c//// DHCP protocol implementation for DHCP client////==========================================================================//####ECOSGPLCOPYRIGHTBEGIN####// -------------------------------------------// This file is part of eCos, the Embedded Configurable Operating System.// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.// Copyright (C) 2003 Andrew Lunn//// eCos is free software; you can redistribute it and/or modify it under// the terms of the GNU General Public License as published by the Free// Software Foundation; either version 2 or (at your option) any later version.//// eCos is distributed in the hope that it will be useful, but WITHOUT ANY// WARRANTY; without even the implied warranty of MERCHANTABILITY or// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License// for more details.//// You should have received a copy of the GNU General Public License along// with eCos; if not, write to the Free Software Foundation, Inc.,// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.//// As a special exception, if other files instantiate templates or use macros// or inline functions from this file, or you compile this file and link it// with other works to produce a work based on this file, this file does not// by itself cause the resulting work to be covered by the GNU General Public// License. However the source code for this file must still be made available// in accordance with section (3) of the GNU General Public License.//// This exception does not invalidate any other reasons why a work based on// this file might be covered by the GNU General Public License.//// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.// at http://sources.redhat.com/ecos/ecos-license/// -------------------------------------------//####ECOSGPLCOPYRIGHTEND####//==========================================================================//#####DESCRIPTIONBEGIN####//// Author(s): hmt// Contributors: gthomas, andrew.lunn@ascom.ch// Date: 2000-07-01// Purpose: DHCP support// Description: ////####DESCRIPTIONEND####////========================================================================*/#include <pkgconf/system.h>#include <pkgconf/net.h>#ifdef CYGPKG_NET_DHCP#ifdef CYGPKG_NET_SNTP#include <pkgconf/net_sntp.h>#endif /* CYGPKG_NET_SNTP */#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>#endifextern int cyg_arc4random(void);#ifdef CYGOPT_NET_DHCP_OPTION_HOST_NAMEstatic char dhcp_hostname[CYGNUM_NET_DHCP_OPTION_HOST_NAME_LEN+1];// Set the hostname used by the DHCP TAG_HOST_NAME option. We// copy the callers name into a private buffer, since we don't// know the context in which the callers hostname was allocated.void dhcp_set_hostname(char *hostname){ CYG_ASSERT( (strlen(hostname)<=CYGNUM_NET_DHCP_OPTION_HOST_NAME_LEN), "dhcp hostname too long" ); strncpy(dhcp_hostname, hostname, CYGNUM_NET_DHCP_OPTION_HOST_NAME_LEN);}#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; // This will only scan the options field. while (*op != TAG_END) { if ( *op == TAG_PAD ) { op++; } else { op += *(op+1)+2; } if ( op > &ppkt->bp_vend[BP_VEND_LEN-1] ) { CYG_FAIL( "Oversize DHCP packet in dhcp_size" ); return NULL; } } // 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 = -1; int one = 1; struct sockaddr_in *addrp; struct ecos_rtentry route; int retcode = false; // Ensure clean slate cyg_route_reinit(); // Force any existing routes to be forgotten s = socket(AF_INET, SOCK_DGRAM, 0); if (s < 0) { perror("socket"); goto out; } if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &one, sizeof(one))) { perror("setsockopt"); goto out; } 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"); goto out; } if (ioctl(s, SIOCSIFNETMASK, ifrp)) { /* set net addr mask */ perror("SIOCSIFNETMASK"); goto out; } /* 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"); goto out; } ifrp->ifr_flags = IFF_UP | IFF_BROADCAST | IFF_RUNNING; if (ioctl(s, SIOCSIFFLAGS, ifrp)) { /* set ifnet flags */ perror("SIOCSIFFLAGS up"); goto out; } if (ioctl(s, SIOCGIFHWADDR, ifrp) < 0) { /* get MAC address */ perror("SIOCGIFHWADDR 1"); goto out; } // 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));
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?