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

📄 dhcp_prot.c

📁 Mavell 无线模块原厂IC AP32源代码。DHCP客户端与服务端源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
            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?
                        && received->bp_yiaddr.s_addr == xmit->bp_yiaddr.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 )
                { // we're bounced!
                    *pstate = DHCPSTATE_NOTBOUND;  // So quit out.
                    break;
                }
                // otherwise it's something else, maybe another offer.
                // Just listen again, which implicitly discards it.
            }
            break;

        case DHCPSTATE_REBINDING:
            // Just send what you got with a DHCPREQUEST in the message type.
            // Then wait for an ACK.  This one is BROADCAST.

            // 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 );

#ifdef CYGDBG_NET_DHCP_CHATTER

            diag_printf( "---------DHCPSTATE_REBINDING 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;
            if (sendto(s, &xmit2, xlen, 0,
                       (struct sockaddr *)&broadcast_addr, sizeof(broadcast_addr)) < 0)
            {
                *pstate = DHCPSTATE_FAILED;
                break;
            }

            *pstate = DHCPSTATE_REBIND_RECV;
            break;

        case DHCPSTATE_REBIND_RECV:
            // wait for an ACK or a NACK - retry by going back to
            // DHCPSTATE_REBINDING; NACK means go to NOTBOUND.
            // No answer means just wait for expiry; we tried!

            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 EX
                    // expires - retain the lease meanwhile.  The normal
                    // lease mechanism will invoke NOTBOUND state as and
                    // when necessary.
                    *pstate = DHCPSTATE_BOUND;
                    break;
                }
                *pstate = DHCPSTATE_REBINDING;
                break;
            }
            // Check for well-formed packet with correct termination (not truncated)
            length = dhcp_size( received );
#ifdef CYGDBG_NET_DHCP_CHATTER

            diag_printf( "---------DHCPSTATE_REBIND_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...
                //int 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?
                        && received->bp_yiaddr.s_addr == xmit->bp_yiaddr.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;
                }
                else if ( DHCPNAK == msgtype )
                { // we're bounced!
                    *pstate = DHCPSTATE_NOTBOUND;  // So back the start of the rigmarole.
                    break;
                }
                // otherwise it's something else, maybe another offer.
                // Just listen again, which implicitly discards it.
            }
            break;

        case DHCPSTATE_BOOTP_FALLBACK:
            // All done with socket
            close(s);
            // And no lease should have become active, but JIC
            no_lease( lease );
            // Re-initialize the interface with the new state
            if ( DHCPSTATE_BOOTP_FALLBACK != 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_NOTBOUND:
            // All done with socket
            close(s);
            // No lease active
            no_lease( lease );
            // Leave interface up so app can tidy.
            return false;

        case DHCPSTATE_FAILED:
            // All done with socket
            close(s);
            // No lease active
            no_lease( lease );
            // Unconditionally down the interface.
            do_dhcp_down_net( intf, res, &oldstate, lease );
            return false;

        case DHCPSTATE_DO_RELEASE:
            // We have been forced here by external means, to release the
            // lease for graceful shutdown.

            // Just send what you got with a DHCPRELEASE in the message
            // type UNICAST straight to the server.  No ACK.  Then go to
            // NOTBOUND state.
            NEW_XID( xid );
            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, DHCPRELEASE, 1 );

            // Set unicast address to *server*
            server_addr.sin_addr.s_addr = res->bp_siaddr.s_addr;

#ifdef CYGDBG_NET_DHCP_CHATTER

            diag_printf( "---------DHCPSTATE_DO_RELEASE 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_NOTBOUND;
            break;

        default:
            no_lease( lease );
            close(s);
            return false;
        }
    }
    /* NOTREACHED */
    return false;
}

// ------------------------------------------------------------------------
// Bring an interface down, failed to initialize it or lease is expired
// Also part of normal startup, bring down for proper reinitialization

int
do_dhcp_down_net(const char *intf, struct bootp *res,
                 cyg_uint8 *pstate, struct dhcp_lease *lease)
{
    struct sockaddr_in *addrp;
    struct ifreq ifr;
    int s;

    // Ensure clean slate
    route_reinit();  // Force any existing routes to be forgotten

    s = socket(AF_INET, SOCK_DGRAM, 0);
    if (s < 0)
    {
        perror("socket");
        return false;
    }

    addrp = (struct sockaddr_in *) &ifr.ifr_addr;

    // Remove any existing address
    if ( DHCPSTATE_FAILED == *pstate
            || DHCPSTATE_INIT == *pstate
            || 0 == *pstate )
    {
        // it was configured for broadcast only, "half-up"
        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;
    }
    else
    {
        // get the specific address that was used
        strcpy(ifr.ifr_name, intf);
        if (ioctl(s, SIOCGIFADDR, &ifr))
        {
            perror("SIOCGIFADDR 1");
            return false;
        }
    }

    strcpy(ifr.ifr_name, intf);
    if (ioctl(s, SIOCDIFADDR, &ifr))
    { /* delete IF addr */
        perror("SIOCDIFADDR1");
    }

#ifdef INET6
    {
        int s6;

        s6 = socket(AF_INET6, SOCK_DGRAM, 0);
        if (s6 < 0)
        {
            perror("socket AF_INET6");
            return false;
        }
        // Now delete the ipv6 addr
        strcpy(ifr.ifr_name, intf);
        if (ioctl(s6, SIOCGLIFADDR, &ifr))
        {
            perror("SIOCGIFADDR_IN6 1");
            return false;
        }

        strcpy(ifr.ifr_name, intf);
        if (ioctl(s6, SIOCDLIFADDR, &ifr))
        { /* delete IF addr */
            perror("SIOCDIFADDR_IN61");
        }
        close(s6);
    }
#endif /* IP6 */

    // Shut down interface so it can be reinitialized
    ifr.ifr_flags &= ~(IFF_UP | IFF_RUNNING);
    if (ioctl(s, SIOCSIFFLAGS, &ifr))
    { /* set ifnet flags */
        perror("SIOCSIFFLAGS down");
        return false;
    }

    // All done with socket
    close(s);

    if ( 0 != *pstate ) // preserve initial state
        *pstate = DHCPSTATE_INIT;

    return true;
}

// ------------------------------------------------------------------------
// Release (relinquish) a leased address - if we have one - and bring down
// the interface.
int
do_dhcp_release(const char *intf, struct bootp *res,
                cyg_uint8 *pstate, struct dhcp_lease *lease)
{
    if ( 0 != *pstate
            && DHCPSTATE_INIT != *pstate
            && DHCPSTATE_NOTBOUND != *pstate
            && DHCPSTATE_FAILED != *pstate
            && DHCPSTATE_BOOTP_FALLBACK != *pstate )
    {
        *pstate = DHCPSTATE_DO_RELEASE;
        do_dhcp( intf, res, pstate, lease ); // to send the release packet
        cyg_thread_delay( 100 );             // to let it leave the building
    }
    return true;
}

// ------------------------------------------------------------------------

#endif // CYGPKG_NET_DHCP

// EOF dhcp_prot.c

⌨️ 快捷键说明

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