Index: trunk/src/VBox/NetworkServices/DHCP/Config.cpp
===================================================================
--- trunk/src/VBox/NetworkServices/DHCP/Config.cpp	(revision 47500)
+++ trunk/src/VBox/NetworkServices/DHCP/Config.cpp	(revision 47501)
@@ -36,31 +36,19 @@
 
 const NullConfigEntity *g_NullConfig = new NullConfigEntity();
-const RootConfigEntity *g_RootConfig = new RootConfigEntity(std::string("ROOT"));
+RootConfigEntity *g_RootConfig = new RootConfigEntity(std::string("ROOT"), 1200 /* 20 min. */);
 const ClientMatchCriteria *g_AnyClient = new AnyClientMatchCriteria();
 
-static SessionManager *g_SessionManager = SessionManager::getSessionManager();
 static ConfigurationManager *g_ConfigurationManager = ConfigurationManager::getConfigurationManager();
 
 static NetworkManager *g_NetworkManager = NetworkManager::getNetworkManager();
 
+
+
 /* Client */
 
-Client::Client(const RTMAC& mac, uint32_t xid)
+Client::Client(const RTMAC& mac)
 {
     m_mac = mac;
-    //    m_sessions.insert(Map2ClientSessionType(xid, Session(this, xid)));
-}
-
-/* Session */
-
-bool Session::operator < (const Session& s) const
-{
-    return (m_u32Xid < s.m_u32Xid);
-}
-
-int Session::switchTo(CLIENTSESSIONSTATE enmState)
-{
-    m_state = enmState;
-    return VINF_SUCCESS;
+    m_lease = NULL;
 }
 
@@ -74,28 +62,29 @@
 static const RTNETADDRIPV4 g_AnyIpv4 = {0};
 static const RTNETADDRIPV4 g_AllIpv4 = {0xffffffff};
-RootConfigEntity::RootConfigEntity(std::string name):
+RootConfigEntity::RootConfigEntity(std::string name, uint32_t expPeriod):
   NetworkConfigEntity(name, g_NullConfig, g_AnyClient, g_AnyIpv4, g_AllIpv4)
 {
     m_MatchLevel = 2;
-}
-
-/* Session Manager */
-SessionManager *SessionManager::getSessionManager()
-{
-    if (!g_SessionManager)
-        g_SessionManager = new SessionManager();
-    return g_SessionManager;
-}
-
-/*
- *  XXX: it sounds like a hack, we use packet descriptor to get the session,
- * instead use corresponding functions in NetworkManager to fetch client identification
- * (note: it isn't only mac driven) and XID for the session.
- */
-
-/**
- * XXX: what about leases ... Lease is a committed Session....
- */
-Session& SessionManager::getClientSessionByDhcpPacket(const RTNETBOOTP *pDhcpMsg, size_t cbDhcpMsg)
+    m_u32ExpirationPeriod = expPeriod;
+}
+
+
+/* Configuration Manager */
+ConfigurationManager *ConfigurationManager::getConfigurationManager()
+{
+    if (!g_ConfigurationManager)
+        g_ConfigurationManager = new ConfigurationManager();
+
+    return g_ConfigurationManager;
+}
+
+
+int ConfigurationManager::extractRequestList(PCRTNETBOOTP pDhcpMsg, size_t cbDhcpMsg, RawOption& rawOpt)
+{
+    return ConfigurationManager::findOption(RTNET_DHCP_OPT_PARAM_REQ_LIST, pDhcpMsg, cbDhcpMsg, rawOpt);
+}
+
+
+Client *ConfigurationManager::getClientByDhcpPacket(const RTNETBOOTP *pDhcpMsg, size_t cbDhcpMsg)
 {
 
@@ -103,8 +92,9 @@
     bool fDhcpValid = false;
     uint8_t uMsgType = 0;
-
+    
     fDhcpValid = RTNetIPv4IsDHCPValid(NULL, pDhcpMsg, cbDhcpMsg, &uMsgType);
-    Assert(fDhcpValid);
-
+    AssertReturn(fDhcpValid, NULL);
+
+    LogFlowFunc(("dhcp:mac:%RTmac\n", &pDhcpMsg->bp_chaddr.Mac));
     /* 1st. client IDs */
     for ( it = m_clients.begin();
@@ -112,115 +102,21 @@
          ++it)
     {
-        /* OK. */
-        if ((*it) == pDhcpMsg->bp_chaddr.Mac)
-            break;
-    }
-
-    const uint32_t xid = pDhcpMsg->bp_xid;
+        if (*(*it) == pDhcpMsg->bp_chaddr.Mac)
+        {
+            LogFlowFunc(("client:mac:%RTmac\n",  &(*it)->m_mac));
+            /* check timestamp that request wasn't expired. */
+            return (*it);
+        }
+    }
+
     if (it == m_clients.end())
     {
         /* We hasn't got any session for this client */
-        m_clients.push_back(Client(pDhcpMsg->bp_chaddr.Mac,
-                                   pDhcpMsg->bp_xid));
-        Client& client = m_clients.back();
-        client.m_sessions.insert(Map2ClientSessionType(xid, Session(&client, xid)));
-        Assert(client.m_sessions[xid].m_pClient);
-        return client.m_sessions[xid];
-    }
-
-    Session& session = it->m_sessions[xid];
-    session.m_pClient = &(*it);
-    session.m_u32Xid = xid;
-
-    RawOption opt;
-    int rc;
-
-    switch(uMsgType)
-    {
-        case RTNET_DHCP_MT_DISCOVER:
-            session.switchTo(DHCPDISCOVERRECEIEVED);
-            /* MAY */
-            rc = ConfigurationManager::findOption(RTNET_DHCP_OPT_REQ_ADDR, pDhcpMsg, cbDhcpMsg, opt);
-            if (RT_SUCCESS(rc))
-            {
-                /* hint for address allocation here */
-                session.addressHint = *(PRTNETADDRIPV4)opt.au8RawOpt;
-            }
-            /* MAY: todo */
-            rc = ConfigurationManager::findOption(RTNET_DHCP_OPT_LEASE_TIME, pDhcpMsg, cbDhcpMsg, opt);
-
-            /* MAY: not now  */
-            rc = ConfigurationManager::findOption(RTNET_DHCP_OPT_CLIENT_ID, pDhcpMsg, cbDhcpMsg, opt);
-            /* XXX: MAY
-            ConfigurationManager::findOption(RTNET_DHCP_OPT_VENDOR_CLASS_IDENTIFIER, pDhcpMsg, opt);
-            */
-            /* MAY: well */
-            rc = ConfigurationManager::findOption(RTNET_DHCP_OPT_PARAM_REQ_LIST, pDhcpMsg, cbDhcpMsg, opt);
-            if (RT_SUCCESS(rc))
-                memcpy(&session.reqParamList, &opt, sizeof(RawOption));
-
-            /* MAY: todo */
-            rc = ConfigurationManager::findOption(RTNET_DHCP_OPT_MAX_DHCP_MSG_SIZE, pDhcpMsg, cbDhcpMsg, opt);
-
-            break;
-
-        case RTNET_DHCP_MT_REQUEST:
-            session.switchTo(DHCPREQUESTRECEIVED);
-            /* MUST in (SELECTING. INIT-REBOOT) MUST NOT BOUND. RENEW MAY  */
-            rc = ConfigurationManager::findOption(RTNET_DHCP_OPT_REQ_ADDR, pDhcpMsg, cbDhcpMsg, opt);
-            if (RT_SUCCESS(rc))
-            {
-                /* hint for address allocation here */
-                session.addressHint = *(PRTNETADDRIPV4)opt.au8RawOpt;
-            }
-
-            /* MAY */
-            ConfigurationManager::findOption(RTNET_DHCP_OPT_LEASE_TIME, pDhcpMsg, cbDhcpMsg, opt);
-            /* MAY */
-            ConfigurationManager::findOption(RTNET_DHCP_OPT_CLIENT_ID, pDhcpMsg, cbDhcpMsg, opt);
-            /* XXX: MAY
-            ConfigurationManager::findOption(RTNET_DHCP_OPT_VENDOR_CLASS_IDENTIFIER, pDhcpMsg, opt);
-            */
-            /* MAY */
-            rc = ConfigurationManager::findOption(RTNET_DHCP_OPT_PARAM_REQ_LIST, pDhcpMsg, cbDhcpMsg, opt);
-            if (RT_SUCCESS(rc))
-                memcpy(&session.reqParamList, &opt, sizeof(RawOption));
-
-            /* MAY */
-            ConfigurationManager::findOption(RTNET_DHCP_OPT_MAX_DHCP_MSG_SIZE, pDhcpMsg, cbDhcpMsg, opt);
-
-            break;
-
-        case RTNET_DHCP_MT_DECLINE:
-        case RTNET_DHCP_MT_OFFER:
-        case RTNET_DHCP_MT_ACK:
-        case RTNET_DHCP_MT_NAC:
-        case RTNET_DHCP_MT_RELEASE:
-        case RTNET_DHCP_MT_INFORM:
-            AssertMsgFailed(("unimplemented"));
-    }
-
-    Assert(session.m_pClient);
-    return session;
-}
-
-void SessionManager::releaseClientSession(Session& session)
-{
-}
-
-void SessionManager::releaseClient(Client& client)
-{
-}
-
-
-/* Configuration Manager */
-ConfigurationManager *ConfigurationManager::getConfigurationManager()
-{
-    if (!g_ConfigurationManager)
-        g_ConfigurationManager = new ConfigurationManager();
-
-    return g_ConfigurationManager;
-}
-
+        m_clients.push_back(new Client(pDhcpMsg->bp_chaddr.Mac));
+        return m_clients.back();
+    }
+
+    return NULL;
+}
 
 /**
@@ -272,5 +168,5 @@
         else
         {
-            size_t  cbCur = pb[1];
+            size_t cbCur = pb[1];
             if (cbCur > cbLeft - 2)
                 cbCur = cbLeft - 2;
@@ -294,134 +190,122 @@
 
 /**
- * We've find the config for session ...
- * XXX: using Session's private members
- */
-int ConfigurationManager::findConfiguration4Session(Session& session)
-{
-    /* XXX: state switching broken?
-     * XXX: DHCPDECLINE and DHCPINFO should we support them.
-     */
-    AssertReturn(   session.m_state == DHCPDISCOVERRECEIEVED
-                 || session.m_state == DHCPREQUESTRECEIVED, VERR_INTERNAL_ERROR);
-
-    if (session.m_pCfg)
-        return VINF_SUCCESS;
-
-    Assert(session.m_pClient);
-    if (g_RootConfig->match(*session.m_pClient, &session.m_pCfg) > 0)
-        return VINF_SUCCESS;
-    else
-        return VERR_INTERNAL_ERROR; /* XXX: is it really *internal* error? Perhaps some misconfiguration */
-
-}
-
-/**
- * What we are archieveing here is non commited lease ()
- */
-int ConfigurationManager::allocateConfiguration4Session(Session& session)
+ * We bind lease for client till it continue with it on DHCPREQUEST.
+ */
+Lease *ConfigurationManager::allocateLease4Client(Client *client, PCRTNETBOOTP pDhcpMsg, size_t cbDhcpMsg)
 {
     /**
      * Well, session hasn't get the config.
      */
-    AssertPtrReturn(session.m_pCfg, VERR_INTERNAL_ERROR);
-
-    bool fWithAddressHint = (session.addressHint.u != 0);
-
-    if (fWithAddressHint)
-    {
-        if (m_allocations[session].u == session.addressHint.u)
+    AssertPtrReturn(client, NULL);
+    
+    /**
+     * This mean that client has already bound or commited lease.
+     * If we've it happens it means that we received DHCPDISCOVER twice. 
+     */
+    if (client->m_lease)
+    {
+        if (client->m_lease->isExpired())
+            expireLease4Client(client);
+        else
         {
-            /* Good, our hint matches allocation  */
-            return VINF_SUCCESS;
+            AssertReturn(client->m_lease->m_address.u != 0,NULL);
+            return client->m_lease;
         }
-        /**
-         * This definetly depends on client state ...
-         * AssertMsgFailed(("Debug Me"));
-         * Workaround #1
-         * clear and ignore.
-         */
-        fWithAddressHint = false;
-        session.addressHint.u = 0;
-    }
-
-    /*
-     * We've received DHCPDISCOVER
-     */
-    AssertReturn(session.m_state == DHCPDISCOVERRECEIEVED, VERR_INTERNAL_ERROR);
-
-    /**
-     * XXX: this is wrong allocation check...
-     * session initilized by client shouldn't be equal to lease in STL terms.
-     */
-    MapSession2Ip4AddressIterator it = m_allocations.find(session);
-
-    if (it == m_allocations.end())
-    {
-        /* XXX: not optimal allocation */
-        const NetworkConfigEntity *pNetCfg = dynamic_cast<const NetworkConfigEntity *>(session.m_pCfg);
-
-        /**
-         * Check config class.
-         */
-        AssertPtrReturn(pNetCfg, VERR_INTERNAL_ERROR);
-
-        uint32_t u32Address = RT_N2H_U32(pNetCfg->lowerIp().u);
-        while (u32Address < RT_N2H_U32(pNetCfg->upperIp().u))
+    }
+
+    RTNETADDRIPV4 hintAddress;
+    RawOption opt;
+    Lease *please = NULL;
+
+    NetworkConfigEntity *pNetCfg;
+
+    AssertReturn(g_RootConfig->match(*client, (BaseConfigEntity **)&pNetCfg) > 0, NULL);
+
+    /* 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, NULL))
+    {
+        please = new Lease();
+        please->pCfg = pNetCfg;
+        please->m_client = client;
+        client->m_lease = please;
+        client->m_lease->m_address = hintAddress;
+        m_allocations[please] = hintAddress;
+        return please;
+    }
+
+    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, NULL))
         {
-
-            /* u32Address in host format */
-            MapSession2Ip4AddressIterator addressIterator;
-            bool fFound = false;
-
-            for (addressIterator = m_allocations.begin();
-                 addressIterator != m_allocations.end();
-                 ++addressIterator)
-            {
-                if (RT_N2H_U32(addressIterator->second.u) == u32Address)
-                {
-                    /*
-                     * This address is taken
-                     * XXX: check if session isn't expired... if expired we can
-                     * reuse it for this request
-                     */
-                    /* XXX: fTakeAddress = true; owning session is expired */
-                    fFound = true;
-                    break;
-                }
-            } /* end of for over allocations */
-
-            if (!fFound)
-            {
-                RTNETADDRIPV4 address = { RT_H2N_U32_C(u32Address)};
-                m_allocations.insert(MapSession2Ip4AddressPair(session, address));
-                session.switchTo(DHCPOFFERPREPARED);
-                return VINF_SUCCESS;
-            }
-
-            u32Address ++;
-        } /* end of while over candidates */
-
-    }
-
-    /* XXX: really??? */
-    session.switchTo(DHCPOFFERPREPARED);
+            please = new Lease();
+            please->pCfg = pNetCfg;
+            please->m_client = client;
+            client->m_lease = please;
+            client->m_lease->m_address = address;
+            m_allocations[please] = client->m_lease->m_address;
+            return please;
+        }
+    }
+   
+    return NULL;
+}
+
+
+int ConfigurationManager::commitLease4Client(Client *client)
+{
+    client->m_lease->u64TimestampBindingStarted = 0;
+    client->m_lease->u32LeaseExpirationPeriod = client->m_lease->pCfg->expirationPeriod();
+    client->m_lease->u64TimestampLeasingStarted = RTTimeMilliTS();
+    client->m_lease->fBinding = false;
     return VINF_SUCCESS;
 }
 
-
-int ConfigurationManager::commitConfiguration4ClientSession(Session& session)
-{
-    /**/
-    session.switchTo(DHCPACKNAKPREPARED);
-
-    /* XXX: clean up the rest of the session, now this session LEASE!!! */
+int ConfigurationManager::expireLease4Client(Client *client)
+{
+    MapLease2Ip4AddressIterator it = m_allocations.find(client->m_lease);
+    AssertReturn(it != m_allocations.end(), VERR_NOT_FOUND);
+
+    m_allocations.erase(it);
+
+    delete client->m_lease;
+    client->m_lease = NULL;
+    
     return VINF_SUCCESS;
 }
 
-RTNETADDRIPV4 ConfigurationManager::getSessionAddress(const Session& session)
-{
-    return m_allocations[session];
-}
-
+bool ConfigurationManager::isAddressTaken(const RTNETADDRIPV4& addr, Lease** ppLease)
+{
+    MapLease2Ip4AddressIterator it;
+    
+    for (it = m_allocations.begin();
+         it != m_allocations.end();
+         ++it)
+    {
+        if (it->second.u == addr.u)
+        {
+            if (ppLease)
+                *ppLease = it->first;
+            
+            return true;
+        }
+    }
+    return false;
+}
 
 NetworkConfigEntity *ConfigurationManager::addNetwork(NetworkConfigEntity *pCfg,
@@ -484,11 +368,14 @@
  * Network manager creates DHCPOFFER datagramm
  */
-int NetworkManager::offer4Session(Session& session)
-{
-    AssertReturn(session.m_state == DHCPOFFERPREPARED, VERR_INTERNAL_ERROR);
-
-    prepareReplyPacket4Session(session);
-
-    RTNETADDRIPV4 address = ConfigurationManager::getConfigurationManager()->getSessionAddress(session);
+int NetworkManager::offer4Client(Client *client, uint32_t u32Xid, 
+                                 uint8_t *pu8ReqList, int cReqList)
+{
+    AssertPtrReturn(client, VERR_INTERNAL_ERROR);
+    AssertPtrReturn(client->m_lease, VERR_INTERNAL_ERROR);
+
+    prepareReplyPacket4Client(client, u32Xid);
+
+    
+    RTNETADDRIPV4 address = client->m_lease->m_address;
     BootPReplyMsg.BootPHeader.bp_yiaddr =  address;
 
@@ -505,5 +392,4 @@
 
     /* XXX: can't store options per session */
-    Client *client = unconst(session.m_pClient);
     AssertPtr(client);
 
@@ -514,11 +400,11 @@
 
     opt.u8OptId = RTNET_DHCP_OPT_LEASE_TIME;
-    *(uint32_t *)opt.au8RawOpt = RT_H2N_U32(ConfigurationManager::getConfigurationManager()->getLeaseTime());
+    *(uint32_t *)opt.au8RawOpt = RT_H2N_U32(client->m_lease->pCfg->expirationPeriod());
     opt.cbRawOpt = sizeof(RTNETADDRIPV4);
     client->rawOptions.push_back(opt);
 
-    processParameterReqList(session);
-
-    return doReply(session);
+    processParameterReqList(client, pu8ReqList, cReqList);
+
+    return doReply(client);
 }
 
@@ -527,12 +413,15 @@
  * Network manager creates DHCPACK
  */
-int NetworkManager::ack(Session& session)
-{
+int NetworkManager::ack(Client *client, uint32_t u32Xid,
+                        uint8_t *pu8ReqList, int cReqList)
+{
+    AssertPtrReturn(client, VERR_INTERNAL_ERROR);
+    AssertPtrReturn(client->m_lease, VERR_INTERNAL_ERROR);
+
     RTNETADDRIPV4 address;
 
-    AssertReturn(session.m_state == DHCPACKNAKPREPARED, VERR_INTERNAL_ERROR);
-    prepareReplyPacket4Session(session);
-
-    address = ConfigurationManager::getConfigurationManager()->getSessionAddress(session);
+    prepareReplyPacket4Client(client, u32Xid);
+
+    address = client->m_lease->m_address;
     BootPReplyMsg.BootPHeader.bp_ciaddr =  address;
 
@@ -542,6 +431,6 @@
      * XXX: Using addressHint is not correct way to initialize [cy]iaddress...
      */
-    BootPReplyMsg.BootPHeader.bp_ciaddr = session.addressHint;
-    BootPReplyMsg.BootPHeader.bp_yiaddr = session.addressHint;
+    BootPReplyMsg.BootPHeader.bp_ciaddr = client->m_lease->m_address;
+    BootPReplyMsg.BootPHeader.bp_yiaddr = client->m_lease->m_address;
 
     Assert(BootPReplyMsg.BootPHeader.bp_yiaddr.u);
@@ -555,8 +444,4 @@
     RT_ZERO(opt);
 
-    /* XXX: can't store options per session */
-    Client *client = unconst(session.m_pClient);
-    AssertPtr(client);
-
     opt.u8OptId = RTNET_DHCP_OPT_MSG_TYPE;
     opt.au8RawOpt[0] = RTNET_DHCP_MT_ACK;
@@ -569,13 +454,11 @@
      */
     opt.u8OptId = RTNET_DHCP_OPT_LEASE_TIME;
-    *(uint32_t *)opt.au8RawOpt = 
-      RT_H2N_U32(ConfigurationManager::getConfigurationManager()->getLeaseTime());
+    *(uint32_t *)opt.au8RawOpt = RT_H2N_U32(client->m_lease->u32LeaseExpirationPeriod);
     opt.cbRawOpt = sizeof(RTNETADDRIPV4);
     client->rawOptions.push_back(opt);
 
-    processParameterReqList(session);
-
-    return doReply(session);
-
+    processParameterReqList(client, pu8ReqList, cReqList);
+
+    return doReply(client);
 }
 
@@ -584,9 +467,10 @@
  * Network manager creates DHCPNAK
  */
-int NetworkManager::nak(Session& session)
-{
-    AssertReturn(session.m_state == DHCPACKNAKPREPARED, VERR_INTERNAL_ERROR);
-
-    prepareReplyPacket4Session(session);
+int NetworkManager::nak(Client* client, uint32_t u32Xid)
+{
+    AssertPtrReturn(client, VERR_INTERNAL_ERROR);
+    AssertPtrReturn(client->m_lease, VERR_INTERNAL_ERROR);
+
+    prepareReplyPacket4Client(client, u32Xid);
 
     /* this field filed in prepareReplyPacket4Session, and
@@ -601,8 +485,4 @@
     RawOption opt;
     RT_ZERO(opt);
-
-    /* XXX: can't store options per session */
-    Client *client = unconst(session.m_pClient);
-    AssertPtr(client);
 
     opt.u8OptId = RTNET_DHCP_OPT_MSG_TYPE;
@@ -611,5 +491,5 @@
     client->rawOptions.push_back(opt);
 
-    return doReply(session);
+    return doReply(client);
 }
 
@@ -618,6 +498,9 @@
  *
  */
-int NetworkManager::prepareReplyPacket4Session(const Session& session)
-{
+int NetworkManager::prepareReplyPacket4Client(Client *client, uint32_t u32Xid)
+{
+    AssertPtrReturn(client, VERR_INTERNAL_ERROR);
+    AssertPtrReturn(client->m_lease, VERR_INTERNAL_ERROR);
+
     memset(&BootPReplyMsg, 0, sizeof(BootPReplyMsg));
 
@@ -626,5 +509,5 @@
     BootPReplyMsg.BootPHeader.bp_hlen   = sizeof(RTMAC);
     BootPReplyMsg.BootPHeader.bp_hops   = 0;
-    BootPReplyMsg.BootPHeader.bp_xid    = session.m_u32Xid;
+    BootPReplyMsg.BootPHeader.bp_xid    = u32Xid;
     BootPReplyMsg.BootPHeader.bp_secs   = 0;
     /* XXX: bp_flags should be processed specially */
@@ -633,10 +516,7 @@
     BootPReplyMsg.BootPHeader.bp_giaddr.u = 0;
 
-    Assert(session.m_pClient);
-    BootPReplyMsg.BootPHeader.bp_chaddr.Mac = session.m_pClient->m_mac;
-
-    BootPReplyMsg.BootPHeader.bp_yiaddr =
-      ConfigurationManager::getConfigurationManager()->getSessionAddress(session);
-
+    BootPReplyMsg.BootPHeader.bp_chaddr.Mac = client->m_mac;
+
+    BootPReplyMsg.BootPHeader.bp_yiaddr = client->m_lease->m_address;
     BootPReplyMsg.BootPHeader.bp_siaddr.u = 0;
 
@@ -652,7 +532,10 @@
 
 
-int NetworkManager::doReply(const Session& session)
+int NetworkManager::doReply(Client *client)
 {
     int rc;
+
+    AssertPtrReturn(client, VERR_INTERNAL_ERROR);
+    AssertPtrReturn(client->m_lease, VERR_INTERNAL_ERROR);
 
     /*
@@ -661,41 +544,27 @@
     VBoxNetDhcpWriteCursor Cursor(&BootPReplyMsg.BootPHeader, RTNET_DHCP_NORMAL_SIZE);
 
-    /* XXX: unconst */
-    Client *cl = unconst(session.m_pClient);
-    AssertPtrReturn(cl, VERR_INTERNAL_ERROR);
-
     /* The basics */
 
     Cursor.optIPv4Addr(RTNET_DHCP_OPT_SERVER_ID, m_OurAddress);
 
-    while(!cl->rawOptions.empty())
-    {
-        RawOption opt = cl->rawOptions.back();
+    while(!client->rawOptions.empty())
+    {
+        RawOption opt = client->rawOptions.back();
         if (!Cursor.begin(opt.u8OptId, opt.cbRawOpt))
             break;
         Cursor.put(opt.au8RawOpt, opt.cbRawOpt);
 
-        cl->rawOptions.pop_back();
-    }
-
-
-    if (!cl->rawOptions.empty())
+        client->rawOptions.pop_back();
+    }
+
+
+    if (!client->rawOptions.empty())
     {
         Log(("Wasn't able to put all options\n"));
         /* force clean up */
-        cl->rawOptions.clear();
+        client->rawOptions.clear();
     }
 
     Cursor.optEnd();
-
-    switch (session.m_state)
-    {
-        case DHCPOFFERPREPARED:
-            break;
-        case DHCPACKNAKPREPARED:
-            break;
-        default:
-            AssertMsgFailedReturn(("Unsupported state(%d)\n", session.m_state), VERR_INTERNAL_ERROR);
-    }
 
     /*
@@ -732,5 +601,5 @@
 
 
-int NetworkManager::processParameterReqList(Session& session)
+int NetworkManager::processParameterReqList(Client* client, uint8_t *pu8ReqList, int cReqList)
 {
     /* request parameter list */
@@ -738,14 +607,11 @@
     int idxParam = 0;
 
-    uint8_t *pReqList = session.reqParamList.au8RawOpt;
-
-    const NetworkConfigEntity *pNetCfg = dynamic_cast<const NetworkConfigEntity *>(session.m_pCfg);
-
-    /* XXX: can't store options per session */
-    Client *client = unconst(session.m_pClient);
-    AssertPtr(client);
-
-
-    for (idxParam = 0; idxParam < session.reqParamList.cbRawOpt; ++idxParam)
+    AssertPtrReturn(client, VERR_INTERNAL_ERROR);
+
+    uint8_t *pReqList = pu8ReqList;
+
+    const NetworkConfigEntity *pNetCfg = client->m_lease->pCfg;
+
+    for (idxParam = 0; idxParam < cReqList; ++idxParam)
     {
 
@@ -762,5 +628,7 @@
             case RTNET_DHCP_OPT_ROUTERS:
                 {
-                    const Ipv4AddressContainer lst = g_ConfigurationManager->getAddressList(RTNET_DHCP_OPT_ROUTERS);
+                    const Ipv4AddressContainer lst = 
+                      g_ConfigurationManager->getAddressList(
+                        RTNET_DHCP_OPT_ROUTERS);
                     PRTNETADDRIPV4 pAddresses = (PRTNETADDRIPV4)&opt.au8RawOpt[0];
 
Index: trunk/src/VBox/NetworkServices/DHCP/Config.h
===================================================================
--- trunk/src/VBox/NetworkServices/DHCP/Config.h	(revision 47500)
+++ trunk/src/VBox/NetworkServices/DHCP/Config.h	(revision 47501)
@@ -7,4 +7,5 @@
 # define _CONFIG_H_
 
+#include <iprt/asm-math.h>
 #include <iprt/cpp/utils.h>
 
@@ -25,54 +26,4 @@
     return (b < a);
 }
-
-
-typedef enum CLIENTSESSIONSTATE
-{
-  /**
-   * defult state, session isn't operable, not initialized an so on.
-   */
-  DHCPNONSENSE,
-  /** We've received dhcp discover =>
-   * we're starting new client and/or session.
-   * Using XID (we record session)
-   * and response with DHCPOFFER
-   */
-  DHCPDISCOVERRECEIEVED,
-  /**
-   * We're ready to send DHCPOFFER
-   */
-  DHCPOFFERPREPARED,
-  /**
-   * This more, session state, we responsed, to
-   * client with DHCPOFFER using session's XID
-   */
-  DHCPOFFERSENT,
-  /**
-   * this is session's state, client's done DHCPREQUEST with (XID)
-   */
-  DHCPREQUESTRECEIVED,
-  /**
-   * We're ready to send DHCPACK or DHCPNAK
-   */
-  DHCPACKNAKPREPARED,
-  /**
-   * We've been able to furfill client's request for (XID) session, erased others Client
-   * 's sessions ... and send DHCPACK (should be Lease bind at this point?)
-   */
-  DHCPACKSENT,
-  /**
-   * We couldn't furfill client's request -> destroy session.
-   */
-  DHCPNACKSENT,
-  /**
-   * real client, don't want our DHCPOFFER, we're delating our client representation,
-   * and sessions objects.
-   */
-  DHCPDECLINERECEIVED,
-  /**
-   * nice to have, but not mandatory.
-   */
-  DHCPINFORMRECEIVED
-} CLIENTSESSIONSTATE;
 
 
@@ -87,84 +38,15 @@
 
 class Client;
+class Lease;
 class BaseConfigEntity;
 
-/**
- * This class joins client and the lease ...
- * at the begining client might request several address assignments...
- *
- * So session here is descriptor joining client to each of it's requests.
- * When client finalizes its selection ... only single assignment is chosen,
- * others are released.
- */
-class Session
-{
-public:
-    Session(const Client *client = NULL,
-            uint32_t xid = 0,
-            CLIENTSESSIONSTATE enmState = DHCPNONSENSE):
-      m_pClient(client),
-      m_state(enmState),
-      m_u32Xid(xid),
-      m_pCfg(NULL)
-    {
-        /* XXX: state ? Which is acceptable on initialization ?! */
-        addressHint.u = 0;
-        RT_ZERO(reqParamList);
-    }
-
-    bool operator < (const Session& s) const;
-
-    int switchTo(CLIENTSESSIONSTATE);
-    /* XXX private: */
-
-    /**/
-    const Client* m_pClient;
-    /* We don't store the state in the client, because client might initiate several
-     * sessions.
-     */
-    CLIENTSESSIONSTATE m_state;
-    /**
-     * uniq identificator of session
-     */
-    uint32_t m_u32Xid;
-
-    /* dhcp-opts: request address */
-    RTNETADDRIPV4 addressHint;
-
-    /* dhcp-opts: request parameter list */
-    RawOption reqParamList;
-    /* Config for this session */
-    const BaseConfigEntity *m_pCfg;
-
-    /**
-     * times used for evaluating wherther Session/Lease could be expired.
-     */
-
-    RTTIMESPEC creation;
-    RTTIMESPEC expiration;
-};
-
-typedef std::map<uint32_t, Session>   Map2ClientSession;
-typedef Map2ClientSession::value_type Map2ClientSessionType;
-typedef Map2ClientSession::iterator   Map2ClientSessionIterator;
-
-class Lease
-{
-public:
-    Lease(const Session& session):m_pClient(session.m_pClient){}
-    virtual ~Lease(){}
-private:
-    const Client *m_pClient;
-
-    bool operator == (const Session& session) const
-    {
-        /* XXX: pointer comparison, perhaps not we really need */
-        return (session.m_pClient == m_pClient);
-    }
-};
-
-typedef std::map<Lease, RTNETADDRIPV4> MapLease2Ip4Address;
+
+class NetworkConfigEntity;
+class HostConfigEntity;
+class ClientMatchCriteria;
+
+typedef std::map<Lease *, RTNETADDRIPV4> MapLease2Ip4Address;
+typedef MapLease2Ip4Address::iterator MapLease2Ip4AddressIterator;
 typedef MapLease2Ip4Address::value_type MapLease2Ip4AddressPair;
-typedef MapLease2Ip4Address::iterator MapLease2Ip4AddressIterator;
 
 /*
@@ -182,5 +64,5 @@
 
     /* XXX: Option 60 and 61 */
-    Client(const RTMAC& mac, uint32_t xid = 0);
+    Client(const RTMAC& mac);
 
     bool operator== (const RTMAC& mac) const
@@ -196,189 +78,15 @@
 
     RTMAC m_mac;
-    Map2ClientSession m_sessions;
-    /* XXX: it's logically per session object, but some client broke XIDness */
-    /* XXX: we're using it as stack */
+    Lease *m_lease;
+
+    /* XXX: should be in lease */
     std::vector<RawOption> rawOptions;
 };
 
 
-typedef std::vector<Client> VecClient;
+typedef std::vector<Client*> VecClient;
 typedef VecClient::iterator VecClientIterator;
 typedef VecClient::const_iterator VecClientConstIterator;
 
-
-class SessionManager
-{
-    public:
-
-    static SessionManager* getSessionManager();
-
-    /**
-     * This method we call on every DHCP packet we've received.
-     * 1. it finds/creates Client/and Session Object.
-     */
-    Session& getClientSessionByDhcpPacket(const RTNETBOOTP* pDhcpMsg, size_t cbPacket);
-
-    /* XXX: DHCPDECLINE */
-    void releaseClientSession(Session& session);
-    /* XXX: DHCPRELEASE */
-    void releaseClient(Client& client);
-
-    private:
-
-    VecClient m_clients;
-
-    SessionManager(){}
-    virtual ~SessionManager(){}
-};
-
-
-typedef std::map<Session, RTNETADDRIPV4> MapSession2Ip4Address;
-typedef MapSession2Ip4Address::iterator MapSession2Ip4AddressIterator;
-typedef MapSession2Ip4Address::value_type MapSession2Ip4AddressPair;
-
-class NetworkConfigEntity;
-class HostConfigEntity;
-class ClientMatchCriteria;
-
-class ConfigurationManager
-{
-    public:
-    static ConfigurationManager* getConfigurationManager();
-
-    /**
-     * We call this on DHCPDISCOVER
-     */
-    int findConfiguration4Session(Session& session);
-
-    /**
-     * XXX: it's could be done on DHCPOFFER or on DHCPACK (rfc2131 gives freedom here
-     * 3.1.2, what is strict that allocation should do address check before real
-     * allocation)...
-     */
-    int allocateConfiguration4Session(Session& session);
-
-    /*
-     * We call this before DHCPACK sent and after DHCPREQUEST received ...
-     * when requested configuration is acceptable.
-     */
-    int commitConfiguration4ClientSession(Session& sesion);
-
-    static int findOption(uint8_t uOption, PCRTNETBOOTP pDhcpMsg, size_t cbDhcpMsg, RawOption& opt);
-
-    NetworkConfigEntity *addNetwork(NetworkConfigEntity *pCfg,
-                                    const RTNETADDRIPV4& networkId,
-                                    const RTNETADDRIPV4& netmask,
-                                    RTNETADDRIPV4& UpperAddress,
-                                    RTNETADDRIPV4& LowerAddress);
-
-    HostConfigEntity *addHost(NetworkConfigEntity*, const RTNETADDRIPV4&, ClientMatchCriteria*);
-
-    RTNETADDRIPV4  getSessionAddress(const Session& session);
-
-    /* XXX: from config */
-    uint32_t getLeaseTime() {return 600;}
-
-    int addToAddressList(uint8_t u8OptId, RTNETADDRIPV4& address)
-    {
-        switch(u8OptId)
-        {
-            case RTNET_DHCP_OPT_DNS:
-                m_nameservers.push_back(address);
-                break;
-            case RTNET_DHCP_OPT_ROUTERS:
-                m_routers.push_back(address);
-                break;
-            default:
-                Log(("dhcp-opt: list (%d) unsupported\n", u8OptId));
-        }
-        return VINF_SUCCESS;
-    }
-
-    int flushAddressList(uint8_t u8OptId)
-    {
-       switch(u8OptId)
-       {
-           case RTNET_DHCP_OPT_DNS:
-                m_nameservers.clear();
-                break;
-           case RTNET_DHCP_OPT_ROUTERS:
-               m_routers.clear();
-               break;
-           default:
-               Log(("dhcp-opt: list (%d) unsupported\n", u8OptId));
-       }
-       return VINF_SUCCESS;
-    }
-
-    const Ipv4AddressContainer& getAddressList(uint8_t u8OptId)
-    {
-       switch(u8OptId)
-       {
-           case RTNET_DHCP_OPT_DNS:
-               return m_nameservers;
-
-           case RTNET_DHCP_OPT_ROUTERS:
-               return m_routers;
-
-       }
-       /* XXX: Grrr !!! */
-       return m_empty;
-    }
-
-    private:
-    ConfigurationManager(){}
-    virtual ~ConfigurationManager(){}
-    MapSession2Ip4Address m_allocations;
-    /*
-     *
-     */
-    Ipv4AddressContainer m_nameservers;
-    Ipv4AddressContainer m_routers;
-    Ipv4AddressContainer m_empty;
-
-};
-
-
-class NetworkManager
-{
-    public:
-    static NetworkManager *getNetworkManager();
-
-    int offer4Session(Session& ses);
-    int ack(Session& ses);
-    int nak(Session& ses);
-
-    const RTNETADDRIPV4& getOurAddress(){ return m_OurAddress;}
-    const RTNETADDRIPV4& getOurNetmask(){ return m_OurNetmask;}
-    const RTMAC& getOurMac() {return m_OurMac;}
-
-    void setOurAddress(const RTNETADDRIPV4& aAddress){ m_OurAddress = aAddress;}
-    void setOurNetmask(const RTNETADDRIPV4& aNetmask){ m_OurNetmask = aNetmask;}
-    void setOurMac(const RTMAC& aMac) {m_OurMac = aMac;}
-
-    /* XXX: artifacts should be hidden or removed from here. */
-    PSUPDRVSESSION m_pSession;
-    INTNETIFHANDLE m_hIf;
-    PINTNETBUF m_pIfBuf;
-
-    private:
-    int prepareReplyPacket4Session(const Session& session);
-    int doReply(const Session& session);
-    int processParameterReqList(Session& session);
-
-    union {
-        RTNETBOOTP BootPHeader;
-        uint8_t au8Storage[1024];
-    } BootPReplyMsg;
-    int cbBooPReplyMsg;
-
-    RTNETADDRIPV4 m_OurAddress;
-    RTNETADDRIPV4 m_OurNetmask;
-    RTMAC m_OurMac;
-
-    NetworkManager(){}
-    virtual ~NetworkManager(){}
-};
 
 /**
@@ -476,5 +184,5 @@
 public:
     BaseConfigEntity(const ClientMatchCriteria *criteria = NULL,
-                     int matchingLevel = 0)
+      int matchingLevel = 0)
       : m_criteria(criteria),
       m_MatchLevel(matchingLevel){};
@@ -488,5 +196,5 @@
 
     /* Should return how strong matching */
-    virtual int match(const Client& client, const BaseConfigEntity **cfg) const
+    virtual int match(Client& client, BaseConfigEntity **cfg)
     {
         int iMatch = (m_criteria && m_criteria->check(client)? m_MatchLevel: 0);
@@ -503,8 +211,8 @@
             *cfg = this;
             /* XXX: hack */
-            BaseConfigEntity const *matching = this;
+            BaseConfigEntity *matching = this;
             int matchingLevel = m_MatchLevel;
 
-            for (std::vector<const BaseConfigEntity *>::const_iterator it = m_children.begin();
+            for (std::vector<BaseConfigEntity *>::iterator it = m_children.begin();
                  it != m_children.end();
                  ++it)
@@ -521,9 +229,9 @@
         return iMatch;
     }
-
+    virtual uint32_t expirationPeriod() const = 0;
     protected:
     const ClientMatchCriteria *m_criteria;
     int m_MatchLevel;
-    std::vector<const BaseConfigEntity *> m_children;
+    std::vector<BaseConfigEntity *> m_children;
 };
 
@@ -538,4 +246,5 @@
         return 0;
     }
+    virtual uint32_t expirationPeriod() const {return 0;}
 };
 
@@ -560,4 +269,14 @@
     std::string m_name;
     const BaseConfigEntity *m_parentCfg;
+    virtual uint32_t expirationPeriod() const
+    {
+        if (!m_u32ExpirationPeriod)
+            return m_parentCfg->expirationPeriod();
+        else
+            return m_u32ExpirationPeriod;
+    }
+
+    /* XXX: private:*/
+    uint32_t m_u32ExpirationPeriod;
 };
 
@@ -646,5 +365,5 @@
 {
     public:
-    RootConfigEntity(std::string name);
+    RootConfigEntity(std::string name, uint32_t expirationPeriod);
     virtual ~RootConfigEntity(){};
 };
@@ -675,7 +394,207 @@
 #endif
 
+class ConfigurationManager
+{
+    public:
+    static ConfigurationManager* getConfigurationManager();
+    static int extractRequestList(PCRTNETBOOTP pDhcpMsg, size_t cbDhcpMsg, RawOption& rawOpt);
+
+    /**
+     * 
+     */
+    Client* getClientByDhcpPacket(const RTNETBOOTP *pDhcpMsg, size_t cbDhcpMsg);
+
+    /**
+     * XXX: it's could be done on DHCPOFFER or on DHCPACK (rfc2131 gives freedom here
+     * 3.1.2, what is strict that allocation should do address check before real
+     * allocation)...
+     */
+    Lease* allocateLease4Client(Client *client, PCRTNETBOOTP pDhcpMsg, size_t cbDhcpMsg);
+
+    /**
+     * We call this before DHCPACK sent and after DHCPREQUEST received ...
+     * when requested configuration is acceptable.
+     */
+    int commitLease4Client(Client *client);
+    
+    /**
+     * Expires client lease.
+     */
+    int expireLease4Client(Client *client);
+
+    static int findOption(uint8_t uOption, PCRTNETBOOTP pDhcpMsg, size_t cbDhcpMsg, RawOption& opt);
+
+    NetworkConfigEntity *addNetwork(NetworkConfigEntity *pCfg,
+                                    const RTNETADDRIPV4& networkId,
+                                    const RTNETADDRIPV4& netmask,
+                                    RTNETADDRIPV4& UpperAddress,
+                                    RTNETADDRIPV4& LowerAddress);
+
+    HostConfigEntity *addHost(NetworkConfigEntity*, const RTNETADDRIPV4&, ClientMatchCriteria*);
+
+    int addToAddressList(uint8_t u8OptId, RTNETADDRIPV4& address)
+    {
+        switch(u8OptId)
+        {
+            case RTNET_DHCP_OPT_DNS:
+                m_nameservers.push_back(address);
+                break;
+            case RTNET_DHCP_OPT_ROUTERS:
+                m_routers.push_back(address);
+                break;
+            default:
+                Log(("dhcp-opt: list (%d) unsupported\n", u8OptId));
+        }
+        return VINF_SUCCESS;
+    }
+
+    int flushAddressList(uint8_t u8OptId)
+    {
+       switch(u8OptId)
+       {
+           case RTNET_DHCP_OPT_DNS:
+                m_nameservers.clear();
+                break;
+           case RTNET_DHCP_OPT_ROUTERS:
+               m_routers.clear();
+               break;
+           default:
+               Log(("dhcp-opt: list (%d) unsupported\n", u8OptId));
+       }
+       return VINF_SUCCESS;
+    }
+
+    const Ipv4AddressContainer& getAddressList(uint8_t u8OptId)
+    {
+       switch(u8OptId)
+       {
+           case RTNET_DHCP_OPT_DNS:
+               return m_nameservers;
+
+           case RTNET_DHCP_OPT_ROUTERS:
+               return m_routers;
+
+       }
+       /* XXX: Grrr !!! */
+       return m_empty;
+    }
+
+    private:
+    ConfigurationManager(){}
+    virtual ~ConfigurationManager(){}
+
+    bool isAddressTaken(const RTNETADDRIPV4& addr, Lease** ppLease = NULL);
+    MapLease2Ip4Address m_allocations;
+    /**
+     * Here we can store expired Leases to do not re-allocate them latter.
+     */
+    /* XXX: MapLease2Ip4Address m_freed; */
+    /*
+     *
+     */
+    Ipv4AddressContainer m_nameservers;
+    Ipv4AddressContainer m_routers;
+    Ipv4AddressContainer m_empty;
+    VecClient m_clients;
+
+};
+
+
+class NetworkManager
+{
+    public:
+    static NetworkManager *getNetworkManager();
+
+    int offer4Client(Client* lease, uint32_t u32Xid, uint8_t *pu8ReqList, int cReqList);
+    int ack(Client *lease, uint32_t u32Xid, uint8_t *pu8ReqList, int cReqList);
+    int nak(Client *lease, uint32_t u32Xid);
+
+    const RTNETADDRIPV4& getOurAddress(){ return m_OurAddress;}
+    const RTNETADDRIPV4& getOurNetmask(){ return m_OurNetmask;}
+    const RTMAC& getOurMac() {return m_OurMac;}
+
+    void setOurAddress(const RTNETADDRIPV4& aAddress){ m_OurAddress = aAddress;}
+    void setOurNetmask(const RTNETADDRIPV4& aNetmask){ m_OurNetmask = aNetmask;}
+    void setOurMac(const RTMAC& aMac) {m_OurMac = aMac;}
+
+    /* XXX: artifacts should be hidden or removed from here. */
+    PSUPDRVSESSION m_pSession;
+    INTNETIFHANDLE m_hIf;
+    PINTNETBUF m_pIfBuf;
+
+    private:
+    int prepareReplyPacket4Client(Client *client, uint32_t u32Xid);
+    int doReply(Client *client);
+    int processParameterReqList(Client *client, uint8_t *pu8ReqList, int cReqList);
+
+    union {
+        RTNETBOOTP BootPHeader;
+        uint8_t au8Storage[1024];
+    } BootPReplyMsg;
+    int cbBooPReplyMsg;
+
+    RTNETADDRIPV4 m_OurAddress;
+    RTNETADDRIPV4 m_OurNetmask;
+    RTMAC m_OurMac;
+
+    NetworkManager(){}
+    virtual ~NetworkManager(){}
+};
+
+
+
+class Lease
+{
+public:
+    Lease()
+    {
+        m_address.u = 0;
+        m_client = NULL;
+        fBinding = false;
+        u64TimestampBindingStarted = 0;
+        u64TimestampLeasingStarted = 0;
+        u32LeaseExpirationPeriod = 0;
+        u32BindExpirationPeriod = 0;
+        pCfg = NULL;
+    }
+    virtual ~Lease(){}
+    
+    bool isExpired()
+    {
+        if (!fBinding)
+            return (ASMDivU64ByU32RetU32(RTTimeMilliTS() - u64TimestampLeasingStarted, 1000) 
+                    > u32LeaseExpirationPeriod);
+        else
+            return (ASMDivU64ByU32RetU32(RTTimeMilliTS() - u64TimestampBindingStarted, 1000) 
+                    > u32BindExpirationPeriod);
+
+    }
+
+    /* XXX private: */
+    RTNETADDRIPV4 m_address;
+    
+    /** lease isn't commited */
+    bool fBinding;
+    
+    /** Timestamp when lease commited. */
+    uint64_t u64TimestampLeasingStarted;
+    /** Period when lease is expired in secs. */
+    uint32_t u32LeaseExpirationPeriod;
+
+    /** timestamp when lease was bound */
+    uint64_t u64TimestampBindingStarted;
+    /* Period when binding is expired in secs. */
+    uint32_t u32BindExpirationPeriod;
+
+    NetworkConfigEntity *pCfg;
+    Client *m_client;
+};
+
+
+
+
 
 extern const ClientMatchCriteria *g_AnyClient;
-extern const RootConfigEntity *g_RootConfig;
+extern RootConfigEntity *g_RootConfig;
 extern const NullConfigEntity *g_NullConfig;
 
Index: trunk/src/VBox/NetworkServices/DHCP/VBoxNetDHCP.cpp
===================================================================
--- trunk/src/VBox/NetworkServices/DHCP/VBoxNetDHCP.cpp	(revision 47500)
+++ trunk/src/VBox/NetworkServices/DHCP/VBoxNetDHCP.cpp	(revision 47501)
@@ -618,4 +618,5 @@
     if (!m_DhcpServer.isNull())
     {
+#if 0
         HRESULT hrc;
         com::SafeArray<BSTR> sf;
@@ -632,22 +633,24 @@
             /* XXX: per-host configuration */
         }
-
-        SessionManager *sesionManager = SessionManager::getSessionManager();
-        Session& session = sesionManager->getClientSessionByDhcpPacket(pDhcpMsg, cb);
-        /* XXX: switch -> private */
-        session.switchTo(DHCPDISCOVERRECEIEVED);
-
+#endif
+        RawOption opt;
+        memset(&opt, 0, sizeof(RawOption));
+        /* 1. Find client */
         ConfigurationManager *confManager = ConfigurationManager::getConfigurationManager();
-        int rc = confManager->findConfiguration4Session(session);
-        AssertRCReturn(rc, false);
-
-        rc = confManager->allocateConfiguration4Session(session);
-        AssertRCReturn(rc, false);
-
-        NetworkManager *netManager = NetworkManager::getNetworkManager();
-        rc = netManager->offer4Session(session);
-        AssertRCReturn(rc, false);
-
-
+        Client *client = confManager->getClientByDhcpPacket(pDhcpMsg, cb);
+
+        /* 2. Find/Bind lease for client */
+        Lease *lease = confManager->allocateLease4Client(client, pDhcpMsg, cb);
+        AssertPtrReturn(lease, VINF_SUCCESS);
+
+        int rc = ConfigurationManager::extractRequestList(pDhcpMsg, cb, opt);
+        
+        /* 3. Send of offer */
+        NetworkManager *networkManager = NetworkManager::getNetworkManager();
+        
+        lease->fBinding = true;
+        lease->u64TimestampBindingStarted = RTTimeMilliTS();
+        lease->u32BindExpirationPeriod = 300; /* 3 min. */
+        networkManager->offer4Client(client, pDhcpMsg->bp_xid, opt.au8RawOpt, opt.cbRawOpt);
     } /* end of if(!m_DhcpServer.isNull()) */
 
@@ -666,23 +669,37 @@
 bool VBoxNetDhcp::handleDhcpReqRequest(PCRTNETBOOTP pDhcpMsg, size_t cb)
 {
-    SessionManager *sesionManager = SessionManager::getSessionManager();
-    Session& session = sesionManager->getClientSessionByDhcpPacket(pDhcpMsg, cb);
-    /* XXX: switch -> private */
-    session.switchTo(DHCPREQUESTRECEIVED);
-
     ConfigurationManager *confManager = ConfigurationManager::getConfigurationManager();
-    int rc = confManager->findConfiguration4Session(session);
-    AssertRCReturn(rc, false);
-
-    rc = confManager->commitConfiguration4ClientSession(session);
-
-    NetworkManager *netManager = NetworkManager::getNetworkManager();
-    if (RT_SUCCESS(rc))
-        rc = netManager->ack(session);
+    NetworkManager *networkManager = NetworkManager::getNetworkManager();
+
+    /* 1. find client */
+    Client *client = confManager->getClientByDhcpPacket(pDhcpMsg, cb);
+
+    /* 2. find bound lease */
+    if (client->m_lease)
+    {
+
+        if (client->m_lease->isExpired())
+        {
+            /* send client to INIT state */
+            networkManager->nak(client, pDhcpMsg->bp_xid);
+            confManager->expireLease4Client(client);
+            return true;
+        }
+        /* XXX: Validate request */
+        RawOption opt;
+        memset((void *)&opt, 0, sizeof(RawOption));
+
+        int rc = confManager->commitLease4Client(client);
+        AssertRCReturn(rc, false);
+
+        rc = ConfigurationManager::extractRequestList(pDhcpMsg, cb, opt);
+        AssertRCReturn(rc, false);
+
+        networkManager->ack(client, pDhcpMsg->bp_xid, opt.au8RawOpt, opt.cbRawOpt);
+    }
     else
-        rc = netManager->nak(session);
-
-    AssertRCReturn(rc, false);
-
+    {
+        networkManager->nak(client, pDhcpMsg->bp_xid);
+    }
     return true;
 }
