⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dhcp_prot.c

📁 ecos实时嵌入式操作系统
💻 C
📖 第 1 页 / 共 4 页
字号:
        if (errno != EEXIST) {            perror("SIOCADDRT 3");            return false;        }    }    close(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}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;    else {        timeout_random++;        pstate->secs = ptv->tv_sec * 2 - 2 + (timeout_random & 3);        pstate->countdown = 2; // later fast retries        ptv->tv_sec = 0;    }    return pstate->secs < 100; // If longer, too many tries...}// ------------------------------------------------------------------------// Lease expiry and alarms to notify itstatic cyg_alarm_t alarm_function;static void alarm_function(cyg_handle_t alarm, cyg_addrword_t data){    struct dhcp_lease *lease = (struct dhcp_lease *)data;    lease->which |= lease->next;    if ( lease->needs_attention )        cyg_semaphore_post( lease->needs_attention );    // Step the lease on into its next state of being alarmed ;-)    if ( lease->next & DHCP_LEASE_EX ) {        cyg_alarm_disable( alarm );    }    else if ( lease->next & DHCP_LEASE_T2 ) {        lease->next = DHCP_LEASE_EX;        cyg_alarm_initialize( lease->alarm, lease->expiry, 0 );        cyg_alarm_enable( lease->alarm );    }    else if ( lease->next & DHCP_LEASE_T1 ) {        lease->next = DHCP_LEASE_T2;        cyg_alarm_initialize( lease->alarm, lease->t2, 0 );        cyg_alarm_enable( lease->alarm );    }}static inline void no_lease( struct dhcp_lease *lease ){    if ( lease->alarm ) {        // Already set: delete this.        cyg_alarm_disable( lease->alarm );        cyg_alarm_delete( lease->alarm );        lease->alarm = 0;    }}static inline void new_lease( struct bootp *bootp, struct dhcp_lease *lease ){    cyg_tick_count_t now = cyg_current_time();    cyg_tick_count_t then;    cyg_uint32 tag = 0;    cyg_uint32 expiry_then;    cyg_resolution_t resolution =         cyg_clock_get_resolution(cyg_real_time_clock());    cyg_handle_t h;    unsigned int length;        // Silence any jabbering from past lease on this interface    no_lease( lease );    lease->which = lease->next = 0;    cyg_clock_to_counter(cyg_real_time_clock(), &h);    cyg_alarm_create( h, alarm_function, (cyg_addrword_t)lease,                      &lease->alarm, &lease->alarm_obj );    // extract the lease time and scale it &c to now.    length = sizeof(tag);    if(!get_bootp_option( bootp, TAG_DHCP_LEASE_TIME, &tag ,&length))        tag = 0xffffffff;    if ( 0xffffffff == tag ) {        lease->expiry = 0xffffffffffffffff;        lease->t2     = 0xffffffffffffffff;        lease->t1     = 0xffffffffffffffff;        return; // it's an infinite lease, hurrah!    }    then = (cyg_uint64)(ntohl(tag));    expiry_then = then;    then *= 1000000000; // into nS - we know there is room in a tick_count_t    then = (then / resolution.dividend) * resolution.divisor; // into system ticks    lease->expiry = now + then;    length = sizeof(tag);    if (get_bootp_option( bootp, TAG_DHCP_REBIND_TIME, &tag, &length ))        then = (cyg_uint64)(ntohl(tag));    else        then = expiry_then - expiry_then/4;    then *= 1000000000; // into nS - we know there is room in a tick_count_t    then = (then / resolution.dividend) * resolution.divisor; // into system ticks    lease->t2 = now + then;    length = sizeof(tag);    if (get_bootp_option( bootp, TAG_DHCP_RENEWAL_TIME, &tag, &length ))        then = (cyg_uint64)(ntohl(tag));    else        then = expiry_then/2;    then *= 1000000000; // into nS - we know there is room in a tick_count_t    then = (then / resolution.dividend) * resolution.divisor; // into system ticks    lease->t1 = now + then;#if 0 // for testing this mechanism    lease->expiry = now + 5000; // 1000 here makes for failure in the DHCP test    lease->t2     = now + 3500;    lease->t1     = now + 2500;#endif#ifdef CYGDBG_NET_DHCP_CHATTER    diag_printf("new_lease:\n");    diag_printf("  expiry = %d\n",lease->expiry);    diag_printf("      t1 = %d\n",lease->t1);    diag_printf("      t2 = %d\n",lease->t2);#endif    lease->next = DHCP_LEASE_T1;    cyg_alarm_initialize( lease->alarm, lease->t1, 0 );    cyg_alarm_enable( lease->alarm );}// ------------------------------------------------------------------------// Set all the tags we want to use when sending a packet.// This has expanded to a large, explicit set to interwork better// with a variety of DHCP servers.static void set_default_dhcp_tags( struct bootp *xmit ){    // Explicitly request full set of params that are default for LINUX    // dhcp servers, but not default for others.  This is rather arbitrary,    // but it preserves behaviour for people using those servers.    // Perhaps configury of this set will be needed in future?    //    // Here's the set:    static cyg_uint8 req_list[]  = {#ifdef CYGOPT_NET_DHCP_PARM_REQ_LIST_REPLACE        CYGOPT_NET_DHCP_PARM_REQ_LIST_REPLACE ,#else        TAG_DHCP_SERVER_ID    ,     //     DHCP server id: 10.16.19.66        TAG_DHCP_LEASE_TIME   ,     //     DHCP time 51: 60        TAG_DHCP_RENEWAL_TIME ,     //     DHCP time 58: 30        TAG_DHCP_REBIND_TIME  ,     //     DHCP time 59: 52        TAG_SUBNET_MASK       ,     //     subnet mask: 255.255.255.0        TAG_GATEWAY           ,     //     gateway: 10.16.19.66        TAG_DOMAIN_SERVER     ,     //     domain server: 10.16.19.66        TAG_DOMAIN_NAME       ,     //     domain name: hmt10.cambridge.redhat.com        TAG_IP_BROADCAST      ,     //     IP broadcast: 10.16.19.255#endif#ifdef CYGOPT_NET_DHCP_PARM_REQ_LIST_ADDITIONAL        CYGOPT_NET_DHCP_PARM_REQ_LIST_ADDITIONAL ,#endif    };    if ( req_list[0] ) // So that one may easily turn it all off by configury        set_variable_tag( xmit, TAG_DHCP_PARM_REQ_LIST,                          &req_list[0], sizeof( req_list ) );    // Explicitly specify our max message size.    set_fixed_tag( xmit, TAG_DHCP_MAX_MSGSZ, BP_MINPKTSZ, 2 );}// ------------------------------------------------------------------------// the DHCP state machine - this does all the workintdo_dhcp(const char *intf, struct bootp *res,        cyg_uint8 *pstate, struct dhcp_lease *lease){    struct ifreq ifr;    struct sockaddr_in cli_addr, broadcast_addr, server_addr, rx_addr;    int s, addrlen;    int one = 1;    unsigned char mincookie[] = {99,130,83,99,255} ;    struct timeval tv;    struct timeout_state timeout_scratch;    cyg_uint8 oldstate = *pstate;    cyg_uint8 msgtype = 0, seen_bootp_reply = 0;    unsigned int length;        cyg_uint32 xid;#define CHECK_XID() (  /* and other details */                                  \    received->bp_xid   != xid            || /* not the same transaction */      \    received->bp_htype != xmit->bp_htype || /* not the same ESA type    */      \    received->bp_hlen  != xmit->bp_hlen  || /* not the same length      */      \    bcmp( &received->bp_chaddr, &xmit->bp_chaddr, xmit->bp_hlen )               \    )    // IMPORTANT: xmit is the same as res throughout this; *received is a    // scratch buffer for reception; its contents are always copied to res    // when we are happy with them.  So we always transmit from the    // existing state.    struct bootp rx_local;    struct bootp *received = &rx_local;    struct bootp *xmit = res;    struct bootp xmit2;    int xlen;    // First, get a socket on the interface in question.  But Zeroth, if    // needs be, bring it to the half-up broadcast only state if needs be.        if ( DHCPSTATE_INIT      == oldstate         || DHCPSTATE_FAILED == oldstate         || 0                == oldstate ) {        // either explicit init state or the beginning of time or retry        if ( ! bring_half_up( intf, &ifr ) )            return false;        *pstate = DHCPSTATE_INIT;    }    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;    }    memset((char *) &cli_addr, 0, sizeof(cli_addr));    cli_addr.sin_family = AF_INET;    cli_addr.sin_len = sizeof(cli_addr);    cli_addr.sin_addr.s_addr = htonl(INADDR_ANY);    cli_addr.sin_port = htons(IPPORT_BOOTPC);        memset((char *) &broadcast_addr, 0, sizeof(broadcast_addr));    broadcast_addr.sin_family = AF_INET;    broadcast_addr.sin_len = sizeof(broadcast_addr);    broadcast_addr.sin_addr.s_addr = htonl(INADDR_BROADCAST);    broadcast_addr.sin_port = htons(IPPORT_BOOTPS);    memset((char *) &server_addr, 0, sizeof(server_addr));    server_addr.sin_family = AF_INET;    server_addr.sin_len = sizeof(server_addr);    server_addr.sin_addr.s_addr = htonl(INADDR_BROADCAST); // overwrite later    server_addr.sin_port = htons(IPPORT_BOOTPS);    if(bind(s, (struct sockaddr *) &cli_addr, sizeof(cli_addr)) < 0) {        perror("bind error");        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;    }        // Now, we can launch into the DHCP state machine.  I think this will    // be the neatest way to do it; it returns from within the switch arms    // when all is well, or utterly failed.    reset_timeout( &tv, &timeout_scratch );    // Choose a new XID: first get the ESA as a basis:    strcpy(&ifr.ifr_name[0], intf);    if (ioctl(s, SIOCGIFHWADDR, &ifr) < 0) {        perror("SIOCGIFHWADDR 2");        return false;    }    // Choose from scratch depending on ifr_hwaddr...[]    xid = ifr.ifr_hwaddr.sa_data[5];    xid |= (ifr.ifr_hwaddr.sa_data[4]) << 8;    xid |= (ifr.ifr_hwaddr.sa_data[3]) << 16;    xid |= (ifr.ifr_hwaddr.sa_data[2]) << 24;    xid ^= (cyg_arc4random() & 0xffff0000);    // Avoid adjacent ESAs colliding by increment#define NEW_XID(_xid) CYG_MACRO_START (_xid)+= 0x10000; CYG_MACRO_END    while ( 1 ) {        // If we are active rather than in the process of shutting down,        // check for any lease expiry every time round, so that alarms        // *can* change the course of events even when already renewing,        // for example.        if ( DHCPSTATE_DO_RELEASE   != *pstate             && DHCPSTATE_NOTBOUND  != *pstate             && DHCPSTATE_FAILED    != *pstate ) {            cyg_uint8 lease_state;            cyg_scheduler_lock();            lease_state = lease->which;            lease->which = 0; // flag that we have noticed it            cyg_scheduler_unlock();            if ( lease_state & DHCP_LEASE_EX ) {                // then the lease has expired completely!                *pstate = DHCPSTATE_NOTBOUND;            }            else if ( lease_state & DHCP_LEASE_T2 ) {                // Time to renew                reset_timeout( &tv, &timeout_scratch ); // next conversation                *pstate = DHCPSTATE_REBINDING;            }            else if ( lease_state & DHCP_LEASE_T1 ) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -