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

📄 dhcp_prot.c

📁 嵌入式操作系统ECOS的网络开发包
💻 C
📖 第 1 页 / 共 4 页
字号:
                                  &length);
            }

            // check it was a DHCP reply
            length = sizeof(msgtype);
            if ( get_bootp_option( received, TAG_DHCP_MESS_TYPE, &msgtype,
                                   &length) ) {
                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,
                                  &length);
            }

            // check it was a DHCP reply
            length = sizeof(msgtype);
            if ( get_bootp_option( received, TAG_DHCP_MESS_TYPE, &msgtype,
                                   &length) ) {
                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
    cyg_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 + -