/**
 * The client is requesting an offer.
 *
 * @returns true.
 *
 * @param   pDhcpMsg    The message.
 * @param   cb          The message size.
 */
bool NetworkManager::handleDhcpReqRequest(PCRTNETBOOTP pDhcpMsg, size_t cb)
{
    ConfigurationManager *confManager = ConfigurationManager::getConfigurationManager();

    /* 1. find client */
    Client client = confManager->getClientByDhcpPacket(pDhcpMsg, cb);

    /* 2. find bound lease */
    Lease l = client.lease();
    if (l != Lease::NullLease)
    {

        if (l.isExpired())
        {
            /* send client to INIT state */
            Client c(client);
            nak(client, pDhcpMsg->bp_xid);
            confManager->expireLease4Client(c);
            return true;
        }
        else {
            /* XXX: Validate request */
            RawOption opt;
            RT_ZERO(opt);

            Client c(client);
            int rc = confManager->commitLease4Client(c);
            AssertRCReturn(rc, false);

            rc = ConfigurationManager::extractRequestList(pDhcpMsg, cb, opt);
            AssertRCReturn(rc, false);

            ack(client, pDhcpMsg->bp_xid, opt.au8RawOpt, opt.cbRawOpt);
        }
    }
    else
    {
        nak(client, pDhcpMsg->bp_xid);
    }
    return true;
}
/**
 * We bind lease for client till it continue with it on DHCPREQUEST.
 */
Lease ConfigurationManager::allocateLease4Client(const Client& client, PCRTNETBOOTP pDhcpMsg, size_t cbDhcpMsg)
{
    {
        /**
         * This mean that client has already bound or commited lease.
         * If we've it happens it means that we received DHCPDISCOVER twice.
         */
        const Lease l = client.lease();
        if (l != Lease::NullLease)
        {
            /* Here we should take lease from the m_allocation which was feed with leases
             *  on start
             */
            if (l.isExpired())
            {
                expireLease4Client(const_cast<Client&>(client));
                if (!l.isExpired())
                    return l;
            }
            else
            {
                AssertReturn(l.getAddress().u != 0, Lease::NullLease);
                return l;
            }
        }
    }

    RTNETADDRIPV4 hintAddress;
    RawOption opt;
    NetworkConfigEntity *pNetCfg;

    Client cl(client);
    AssertReturn(g_RootConfig->match(cl, (BaseConfigEntity **)&pNetCfg) > 0, Lease::NullLease);

    /* DHCPDISCOVER MAY contain request address */
    hintAddress.u = 0;
    int rc = findOption(RTNET_DHCP_OPT_REQ_ADDR, pDhcpMsg, cbDhcpMsg, opt);
    if (RT_SUCCESS(rc))
    {
        hintAddress.u = *(uint32_t *)opt.au8RawOpt;
        if (   RT_H2N_U32(hintAddress.u) < RT_H2N_U32(pNetCfg->lowerIp().u)
            || RT_H2N_U32(hintAddress.u) > RT_H2N_U32(pNetCfg->upperIp().u))
            hintAddress.u = 0; /* clear hint */
    }

    if (   hintAddress.u
        && !isAddressTaken(hintAddress))
    {
        Lease l(cl);
        l.setConfig(pNetCfg);
        l.setAddress(hintAddress);
        m->m_allocations.insert(MapLease2Ip4AddressPair(l, hintAddress));
        return l;
    }

    uint32_t u32 = 0;
    for(u32 = RT_H2N_U32(pNetCfg->lowerIp().u);
        u32 <= RT_H2N_U32(pNetCfg->upperIp().u);
        ++u32)
    {
        RTNETADDRIPV4 address;
        address.u = RT_H2N_U32(u32);
        if (!isAddressTaken(address))
        {
            Lease l(cl);
            l.setConfig(pNetCfg);
            l.setAddress(address);
            m->m_allocations.insert(MapLease2Ip4AddressPair(l, address));
            return l;
        }
    }

    return Lease::NullLease;
}