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

📄 dhcp_prot.c

📁 Mavell 无线模块原厂IC AP32源代码。DHCP客户端与服务端源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
    // Choose a new XID: first get the ESA as a basis:    // 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 ^= (arc4random() & 0xffff0000);    // Avoid adjacent ESAs colliding by increment#define NEW_XID(_xid) CYG_MACRO_START (_xid)+= 0x10000; CYG_MACRO_END    while ( 1 )    {#ifdef CYGDBG_NET_DHCP_CHATTER     diag_printf("do_dhcp:  state %d\n",*pstate);#endif        // 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 )            {                // Time to renew                reset_timeout( &tv, &timeout_scratch ); // next conversation                *pstate = DHCPSTATE_RENEWING;            }        }        switch ( *pstate )        {        case DHCPSTATE_INIT:            // Send the DHCPDISCOVER packet            // Fill in the BOOTP request - DHCPDISCOVER packet            bzero(xmit, sizeof(*xmit));            xmit->bp_op = BOOTREQUEST;            xmit->bp_htype = HTYPE_ETHERNET;            xmit->bp_hlen = IFHWADDRLEN;            xmit->bp_xid = xid;            xmit->bp_secs = 0;            xmit->bp_flags = htons(0x8000); // BROADCAST FLAG            bcopy(ifr.ifr_hwaddr.sa_data, &xmit->bp_chaddr, xmit->bp_hlen);            bcopy(mincookie, xmit->bp_vend, sizeof(mincookie));            // remove the next line to test ability to handle bootp packets.            set_fixed_tag( xmit, TAG_DHCP_MESS_TYPE, DHCPDISCOVER, 1 );            // Set all the tags we want to use when sending a packet            set_default_dhcp_tags( xmit );#ifdef CYGDBG_NET_DHCP_CHATTER            diag_printf( "---------DHCPSTATE_INIT sending:\n" );            show_bootp( intf, xmit );#endif#ifdef ORIG_DHCP_CODE            if (sendto(s, xmit, dhcp_size_for_send(xmit), 0,                       (struct sockaddr *)&broadcast_addr, sizeof(broadcast_addr)) < 0)#else            if(dhcp_send_broadcast_to_driver(dhcp_size_for_send(xmit),(cyg_uint8 *) xmit,ifr.ifr_hwaddr.sa_data) < 0 )#endif            {                *pstate = DHCPSTATE_FAILED;#ifdef CYGDBG_NET_DHCP_CHATTER                diag_printf("do_dhcp: send packet ERROR N %d\n", errno);#endif                break;            }            seen_bootp_reply = 0;            *pstate = DHCPSTATE_SELECTING;            break;        case DHCPSTATE_SELECTING:            // This is a separate state so that we can listen again            // *without* retransmitting.            // listen for the DHCPOFFER reply            setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));            addrlen = sizeof(rx_addr);            if (recvfrom(s, received, sizeof(struct bootp), 0,                         (struct sockaddr *)&rx_addr, &addrlen) < 0)            {                // No packet arrived (this time)                if ( seen_bootp_reply )                { // then already have a bootp reply                    // Save the good packet in *xmit                    bcopy( received, xmit, dhcp_size(received) );                    *pstate = DHCPSTATE_BOOTP_FALLBACK;                    NEW_XID( xid ); // Happy to advance, so new XID                    reset_timeout( &tv, &timeout_scratch );                    break;                }                // go to the next larger timeout and re-send:                if ( ! next_timeout( &tv, &timeout_scratch ) )                {                    *pstate = DHCPSTATE_FAILED;#ifdef CYGDBG_NET_DHCP_CHATTER                    diag_printf("do_dhcp:  no receive \n");#endif                    break;                }                *pstate = DHCPSTATE_INIT; // to retransmit                break;            }            // Check for well-formed packet with correct termination (not truncated)            length = dhcp_size( received );#ifdef CYGDBG_NET_DHCP_CHATTER            diag_printf( "---------DHCPSTATE_SELECTING received:\n" );            if ( length <= 0 )                diag_printf( "WARNING! malformed or truncated packet\n" );            diag_printf( "...rx_addr is family %d, addr %08x, port %d\n",                         rx_addr.sin_family,                         rx_addr.sin_addr.s_addr,                         rx_addr.sin_port );            show_bootp( intf, received );#endif            if ( length <= 0 )                break;            if ( CHECK_XID() )          // XID and ESA matches?                break;                  // listen again...            if ( 0 == received->bp_siaddr.s_addr )            {                // then fill in from the options...                length = sizeof(received->bp_siaddr.s_addr);                get_bootp_option( received, TAG_DHCP_SERVER_ID,                                  &received->bp_siaddr.s_addr);            }            // see if it was a DHCP reply or a bootp reply; it could be            // either.            length = sizeof(msgtype);            if ( get_bootp_option( received, TAG_DHCP_MESS_TYPE, &msgtype) )            {                if ( DHCPOFFER == msgtype )                { // all is well                    // Save the good packet in *xmit                    bcopy( received, xmit, dhcp_size(received) );                    // we like the packet, so reset the timeout for next time                    reset_timeout( &tv, &timeout_scratch );                    *pstate = DHCPSTATE_REQUESTING;                    NEW_XID( xid ); // Happy to advance, so new XID                }            }            else // No TAG_DHCP_MESS_TYPE entry so it's a bootp reply                seen_bootp_reply = 1; // (keep the bootp packet in received)            // If none of the above state changes occurred, we got a packet            // that "should not happen", OR we have a bootp reply in our            // hand; so listen again with the same timeout, without            // retrying the send, in the hope of getting a DHCP reply.            break;        case DHCPSTATE_REQUESTING:            // Just send what you got with a DHCPREQUEST in the message type.            // then wait for an ACK in DHCPSTATE_REQUEST_RECV.            // Fill in the BOOTP request - DHCPREQUEST packet            xmit->bp_xid = xid;            xmit->bp_op = BOOTREQUEST;            xmit->bp_flags = htons(0x8000); // BROADCAST FLAG            set_fixed_tag( xmit, TAG_DHCP_MESS_TYPE, DHCPREQUEST, 1 );            // Set all the tags we want to use when sending a packet            set_default_dhcp_tags( xmit );            // And this will be a new one:            set_fixed_tag( xmit, TAG_DHCP_REQ_IP, ntohl(xmit->bp_yiaddr.s_addr), 4 );#ifdef CYGDBG_NET_DHCP_CHATTER            diag_printf( "---------DHCPSTATE_REQUESTING sending:\n" );            show_bootp( intf, xmit );#endif            // Send back a [modified] copy.  Note that some fields are explicitly            // cleared, as per the RFC.  We need the copy because these fields are            // still useful to us (and currently stored in the 'result' structure)            xlen = dhcp_size_for_send( xmit );            bcopy( xmit, &xmit2, xlen );            xmit2.bp_yiaddr.s_addr = xmit2.bp_siaddr.s_addr = xmit2.bp_giaddr.s_addr = 0;            xmit2.bp_hops = 0;#ifdef ORIG_DHCP_CODE            if (sendto(s, &xmit2, xlen, 0,                       (struct sockaddr *)&broadcast_addr, sizeof(broadcast_addr)) < 0)#else            if(dhcp_send_broadcast_to_driver(xlen,(cyg_uint8 *) &xmit2,ifr.ifr_hwaddr.sa_data) < 0 )#endif            {                *pstate = DHCPSTATE_FAILED;                break;            }            *pstate = DHCPSTATE_REQUEST_RECV;            break;        case DHCPSTATE_REQUEST_RECV:            // wait for an ACK or a NACK - retry by going back to            // DHCPSTATE_REQUESTING; NACK means go back to INIT.            setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));            addrlen = sizeof(rx_addr);            if (recvfrom(s, received, sizeof(struct bootp), 0,                         (struct sockaddr *)&rx_addr, &addrlen) < 0)            {                // No packet arrived                // go to the next larger timeout and re-send:                if ( ! next_timeout( &tv, &timeout_scratch ) )                {                    *pstate = DHCPSTATE_FAILED;                    break;                }                *pstate = DHCPSTATE_REQUESTING;                break;            }            // Check for well-formed packet with correct termination (not truncated)            length = dhcp_size( received );#ifdef CYGDBG_NET_DHCP_CHATTER            diag_printf( "---------DHCPSTATE_REQUEST_RECV received:\n" );            if ( length <= 0 )                diag_printf( "WARNING! malformed or truncated packet\n" );            diag_printf( "...rx_addr is family %d, addr %08x, port %d\n",                         rx_addr.sin_family,                         rx_addr.sin_addr.s_addr,                         rx_addr.sin_port );            show_bootp( intf, received );#endif            if ( length <= 0 )                break;            if ( CHECK_XID() )          // not the same transaction;                break;                  // listen again...            if ( 0 == received->bp_siaddr.s_addr )            {                // then fill in from the options...                length = sizeof(received->bp_siaddr.s_addr );                get_bootp_option( received, TAG_DHCP_SERVER_ID,                                  &received->bp_siaddr.s_addr);            }            // check it was a DHCP reply            length = sizeof(msgtype);            if ( get_bootp_option( received, TAG_DHCP_MESS_TYPE, &msgtype) )            {                if ( DHCPACK == msgtype // Same offer & server?                        && received->bp_yiaddr.s_addr == xmit->bp_yiaddr.s_addr                        && received->bp_siaddr.s_addr == xmit->bp_siaddr.s_addr)                {                    // we like the packet, so reset the timeout for next time                    reset_timeout( &tv, &timeout_scratch );                    // Record the new lease and set up timers &c                    new_lease( received, lease );                    *pstate = DHCPSTATE_BOUND;                    break;                }                if ( DHCPNAK == msgtype // Same server?                        && received->bp_siaddr.s_addr == xmit->bp_siaddr.s_addr)                {                    // we're bounced!                    *pstate = DHCPSTATE_INIT;  // So back the start of the rigmarole.                    NEW_XID( xid ); // Unhappy to advance, so new XID                    reset_timeout( &tv, &timeout_scratch );                    break;                }                // otherwise it's something else, maybe another offer, or a bogus                // NAK from someone we are not asking!                // Just listen again, which implicitly discards it.            }            break;        case DHCPSTATE_BOUND:            // We are happy now, we have our address.            // All done with socket            close(s);            // Re-initialize the interface with the new state            if ( DHCPSTATE_BOUND != oldstate )            {                // Then need to go down and up                do_dhcp_down_net( intf, res, &oldstate, lease ); // oldstate used                if ( 0 != oldstate )                {                    // Then not called from init_all_network_interfaces()                    // so we must initialize the interface ourselves                    if (!init_net(intf, res))                    {                        do_dhcp_down_net( intf, res, pstate, lease );                        *pstate = DHCPSTATE_FAILED;                        return false;                    }                }            }            // Otherwise, nothing whatsoever to do...            return true;        case DHCPSTATE_RENEWING:            // Just send what you got with a DHCPREQUEST in the message            // type UNICAST straight to the server.  Then wait for an ACK.            // Fill in the BOOTP request - DHCPREQUEST packet            xmit->bp_xid = xid;            xmit->bp_op = BOOTREQUEST;            xmit->bp_flags = htons(0); // No BROADCAST FLAG            // Use the *client* address here:            xmit->bp_ciaddr.s_addr = xmit->bp_yiaddr.s_addr;            set_fixed_tag( xmit, TAG_DHCP_MESS_TYPE, DHCPREQUEST, 1 );            // These must not be set in this context            unset_tag( xmit, TAG_DHCP_REQ_IP );            unset_tag( xmit, TAG_DHCP_SERVER_ID );            // Set all the tags we want to use when sending a packet            set_default_dhcp_tags( xmit );            // Set unicast address to *server*            server_addr.sin_addr.s_addr = res->bp_siaddr.s_addr;#ifdef CYGDBG_NET_DHCP_CHATTER            diag_printf( "---------DHCPSTATE_RENEWING sending:\n" );            diag_printf( "UNICAST to family %d, addr %08x, port %d\n",                         server_addr.sin_family,                         server_addr.sin_addr.s_addr,                         server_addr.sin_port );            show_bootp( intf, xmit );#endif            // Send back a [modified] copy.  Note that some fields are explicitly            // cleared, as per the RFC.  We need the copy because these fields are            // still useful to us (and currently stored in the 'result' structure)            xlen = dhcp_size_for_send(xmit);            bcopy( xmit, &xmit2, xlen );            xmit2.bp_yiaddr.s_addr = xmit2.bp_siaddr.s_addr = xmit2.bp_giaddr.s_addr = 0;            xmit2.bp_hops = 0;            if (sendto(s, &xmit2, xlen, 0,                       // UNICAST address of the server:                       (struct sockaddr *)&server_addr,                       sizeof(server_addr)) < 0)            {                *pstate = DHCPSTATE_FAILED;                break;            }            *pstate = DHCPSTATE_RENEW_RECV;            break;        case DHCPSTATE_RENEW_RECV:            // wait for an ACK or a NACK - retry by going back to            // DHCPSTATE_RENEWING; NACK means go to NOTBOUND.            // No answer means just wait for T2, to broadcast.            setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));            addrlen = sizeof(rx_addr);            if (recvfrom(s, received, sizeof(struct bootp), 0,                         (struct sockaddr *)&rx_addr, &addrlen) < 0)            {                // No packet arrived                // go to the next larger timeout and re-send:                if ( ! next_timeout( &tv, &timeout_scratch ) )                {                    // If we timed out completely, just give up until T2                    // expires - retain the lease meanwhile.  The normal                    // lease mechanism will invoke REBINDING as and when                    // necessary.                    *pstate = DHCPSTATE_BOUND;                    break;                }

⌨️ 快捷键说明

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