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 + -
显示快捷键?