📄 dhcp_prot.c
字号:
/*==========================================================================//// 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.//// 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// Date: 2000-07-01// Purpose: DHCP support// Description: ////####DESCRIPTIONEND####////========================================================================*/#include <pkgconf/system.h>#include <pkgconf/net.h>#ifdef CYGPKG_NET_DHCP#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// ------------------------------------------------------------------------// 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) { 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; int one = 1; struct sockaddr_in *addrp; struct ecos_rtentry route; // 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"); 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; if (ioctl(s, SIOCADDRT, &route)) { /* add route */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -