Exemple #1
0
void dhcp_send_request(uint32_t xid, uint32_t requested_ip, uint32_t server_ip, int offer_answer)
{
    DhcpHead dhcp_request;
    uint8_t *op;

    memset(&dhcp_request, 0, sizeof(DhcpHead));

    dhcp_request.op = BOOTREQUEST;
    dhcp_request.htype = 1; /* ethernet */
    dhcp_request.hlen = 6;
    dhcp_request.hops = 0;
    dhcp_request.xid = xid;
    if (offer_answer)
        dhcp_request.ciaddr = requested_ip;
    dhcp_request.siaddr = server_ip;

    memcpy(dhcp_request.chaddr, simple_net_get_mac(), 6);

    dhcp_request.options[0] = 99;
    dhcp_request.options[1] = 130;
    dhcp_request.options[2] = 83;
    dhcp_request.options[3] = 99;
    op = dhcp_create_option_simple(dhcp_request.options+4, OPTION_DHCP_MESSAGE_TYPE, 1, DHCPREQUEST);
    op = dhcp_create_option_simple(op, OPTION_DHCP_REQUESTED_IP, 4, ntohl(requested_ip));
    op = dhcp_create_option_simple(op, OPTION_DHCP_SERVER_IDENTIFIER, 4, ntohl(dhcp_request.siaddr));
    op[0] = OPTION_END;
    dhcp_send(&dhcp_request, requested_ip, 0xffffffff, _bmac);
}
Exemple #2
0
void dhcp_discover(void)
{
    DhcpHead dhcp;
    uint8_t *op;

    memset(&dhcp, 0, sizeof(DhcpHead));

    dhcp.op = BOOTREQUEST;
    dhcp.htype = 1; /* ethernet */
    dhcp.hlen = 6;
    dhcp.hops = 0;
    dhcp.xid = rand();

    memcpy(dhcp.chaddr, simple_net_get_mac(), 6);

    /* DHCP Magic Cookie */
    dhcp.options[0] = 99;
    dhcp.options[1] = 130;
    dhcp.options[2] = 83;
    dhcp.options[3] = 99;
    op = dhcp_create_option_simple(dhcp.options+4, OPTION_DHCP_MESSAGE_TYPE, 1, DHCPDISCOVER);
    op[0] = OPTION_END;

    dhcp_send(&dhcp, 0, 0xffffffff, _bmac);
}
Exemple #3
0
// ------------------------------------------------
// Function:        dhcp_discover()
// ------------------------------------------------
// Input:           -
// Output:          TRUE if succesful
// ------------------------------------------------
// Description:     Find out a DHCP server address
// ------------------------------------------------
BOOL dhcp_discover(void)
{
    BYTE opt;
    PPBUF pbuf;

    retry = 0;
    while(retry < MAX_RETRIES) {
        if(!dhcp_send(DHCPDISCOVER, TRUE)) return FALSE;
        os_set_timeout(TIMEOUT_DHCP_DISCOVER);
        if(udp_listen(SOCKET_DHCP, UDP_DHCP_CLI)) {
            pbuf = udp_read(SOCKET_DHCP);
            opt = parse_dhcp(pbuf);
            release_buffer(pbuf);
            if(opt == DHCPOFFER) break;
        }
        retry++;
    }

    if(retry >= MAX_RETRIES) return FALSE;
    return TRUE;
}	
Exemple #4
0
// Update the DHCP lease if necessary.
//
// Returns:     True    Success
//              False   Otherwise
//
bool EtherCard::dhcpLease () {
    // If leaseStart is invalid, just quit
    if (leaseStart == 0)
        return false;

    // Find out when we are
    uint32_t now = millis();
    uint32_t renew = leaseStart + leaseTime / 2;
    uint32_t rebind = leaseStart + (leaseTime / 8 ) * 7;
    uint32_t restart = leaseStart + leaseTime;
    uint32_t newStart;
    byte rc = false;

    // The unsigned arithmetic makes rollover calculations tricky.
    // Re-assign leaseStart to (leaseStart + leaseTime) as soon as
    // the new tick is large enough. OTOH, rollover is ~50 days with
    // a msec tick - do we care ???
    if (now < leaseStart) {
        newStart = leaseTime - ((UINT32_MAX - leaseStart) % leaseTime);
        if (now < newStart) {
            if (now > leaseTime / 2)
                renew = newStart - leaseTime / 2;
            if (now > (leaseTime / 8))
                rebind = newStart - leaseTime / 8;
            restart = newStart;
        }
        else
            leaseStart = newStart;
    }

    // Update dhcpState according to the timers
    switch (dhcpState) {
    case DHCP_STATE_BAD:
    case DHCP_STATE_INIT:
    case DHCP_STATE_SELECT:
    case DHCP_STATE_REQUEST:
        break;
    case DHCP_STATE_BOUND:
        // At > 50% of the lease time,
        // move to DHCP_STATE_RENEW
        if (now > renew)
            dhcpState = DHCP_STATE_RENEW;
        break;
    case DHCP_STATE_RENEW:
        // At > 87.5% of the lease time,
        // move to DHCP_STATE_REBIND
        if (now > rebind)
            dhcpState = DHCP_STATE_REBIND;
        dhcp_send(DHCP_MSG_REQUEST, false);
        rc = true;
        break;
    case DHCP_STATE_REBIND:
        // At a 100% of the lease time,
        // move to DHCP_STATE_INIT
        if (now > restart)
            dhcpState = DHCP_STATE_INIT;
        else
            // This is a broadcast message.
            dhcp_send(DHCP_MSG_REQUEST, true);
        rc = true;
        break;
    default:
        // Never happen
        break;
    }

    // Call the main DHCP state machine
    // to handle the actual work.
    return rc ? dhcp_fsm() : true;
}
Exemple #5
0
// This handles both the initialisation of DHCP, and subsequent
// renegotiations.  Lacking a dedicated timer, EtherCard::dhcpLease()
// must be called on a regular basis to keep things on track.
//
// Returns:     True    Success
//              False   Otherwise
//
static bool dhcp_fsm () {
    // Enable reception of broadcast packets as some DHCP servers
    // use this to send responses. Use only in DHCP_STATE_INIT ???
    EtherCard::enableBroadcast();

    // We typically wait up to 20 seconds for an answer
    uint32_t end = millis() + DHCP_WAIT;
    while (dhcpState != DHCP_STATE_BOUND && millis() < end) {
        byte rc = DHCP_STATE_BAD;
        word len = 0;

        // We have no hardware link, so no further point
        if (!EtherCard::isLinkUp())
            continue;

        // Get a packet, and check it's ok. packetReceive returns the
        // sum of the source address (6), the destination address (6),
        // the type/length (2), and the data/padding (46-1500) fields.
        // The trailing CRC field (4) is dropped by the software.
        // packetLoop(), unfortunately, is strange and undocumented.
        if (dhcpState != DHCP_STATE_INIT) {
            len = EtherCard::packetReceive();
            // Reject inadequate packets
            if (len == 0 || EtherCard::packetLoop(len) > 0)
                continue;
#if 0
            // These are a waste of space
            // Reject ARP packets
            if (gPB[ETHTYPE_IP_H_V] == ETHTYPE_ARP_H_V &&
                        gPB[ETHTYPE_IP_L_V] == ETHTYPE_ARP_L_V)
                continue;
            // Reject ICMP packets (why are they here ???)
            if (gPB[IP_PROTO_P] == IP_PROTO_ICMP_V)
                continue;
#endif
            // Reject everything but UDP packets
            if (gPB[IP_PROTO_P] != IP_PROTO_UDP_V)
                continue;
        }

        // Switch between DHCP states.  This is a pretty
        // minimal DHCP state machine, but it should be
        // reliable, if slow.
        switch (dhcpState) {
        case DHCP_STATE_INIT:
            EtherCard::copyIp(EtherCard::myip, allZeros);
            EtherCard::copyIp(EtherCard::dhcpip, allZeros);
            currentXid = millis();
            currentXid = (currentXid << 16) + millis();
            dhcp_send(DHCP_MSG_DISCOVER, true);
            dhcpState = DHCP_STATE_SELECT;
            leaseStart = 0; // Set an invalid start time
            break;
        case DHCP_STATE_SELECT:
            if (check_for_dhcp_answer(len) == DHCP_STATE_SELECT) {
                parse_dhcpoffer(len);
                dhcp_send(DHCP_MSG_REQUEST, false);
                dhcpState = DHCP_STATE_REQUEST;
            }
            else
                dhcpState = DHCP_STATE_INIT;
            break;
        case DHCP_STATE_REQUEST:
            if (check_for_dhcp_answer(len) == DHCP_STATE_REQUEST) {
                dhcpState = DHCP_STATE_BOUND;
                leaseStart = millis();
            }
            else
                dhcpState = DHCP_STATE_INIT;
            break;
        case DHCP_STATE_BOUND:
            // Lease timed at 50%   :  move to DHCP_STATE_RENEW
            // We're only bounced out of this state by a timer.
            // Otherwise just hang on to the lease.
            break;
        case DHCP_STATE_RENEW:
            // Lease timed at 87.5% :  move to DHCP_STATE_REBIND
            // Otherwise just hang on to the lease if possible.
            rc = check_for_dhcp_answer(len);
            if (rc == DHCP_STATE_BOUND) {
                dhcpState = DHCP_STATE_BOUND;
                leaseStart = millis();
            }
            else if (rc == DHCP_STATE_INIT)
                dhcpState = DHCP_STATE_INIT;
            break;
        case DHCP_STATE_REBIND:
            // Lease timed at 100%  :  move to DHCP_STATE_INIT
            // Otherwise just hang on to the lease if possible.
            rc = check_for_dhcp_answer(len);
            if (rc == DHCP_STATE_BOUND) {
                dhcpState = DHCP_STATE_BOUND;
                leaseStart = millis();
            }
            else if (rc == DHCP_STATE_INIT)
                dhcpState = DHCP_STATE_INIT;
            break;
        // Never happen
        default:
            dhcpState = DHCP_STATE_INIT;
            break;
        }
    }

    EtherCard::disableBroadcast();

    // Did we get here with an IP or a timeout?
    if (EtherCard::myip[0] != 0) {
        if (EtherCard::gwip[0] != 0)
            EtherCard::setGwIp(EtherCard::gwip);
        return true;
    }

    return false;
}