VirtualBox

Changeset 46969 in vbox for trunk/src/VBox/NetworkServices


Ignore:
Timestamp:
Jul 4, 2013 6:35:01 AM (12 years ago)
Author:
vboxsync
Message:

backed out r86967,r86968,r86969,r86970,r86971,r86972,r86973,r86975,r86976.
will fix build locally.

Location:
trunk/src/VBox/NetworkServices
Files:
2 deleted
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/NetworkServices/DHCP/Makefile.kmk

    r46968 r46969  
    3333# Hardened VBoxNetDHCP.
    3434#
    35 VBoxNetDHCPHardened_TEMPLATE = VBOXMAINCLIENTEXE
     35VBoxNetDHCPHardened_TEMPLATE = VBOXR3HARDENEDEXE
    3636VBoxNetDHCPHardened_SOURCES = VBoxNetDHCPHardened.cpp
    3737VBoxNetDHCPHardened_NAME = VBoxNetDHCP
     
    4141# VBoxNetDHCP
    4242#
    43 VBoxNetDHCP_TEMPLATE = VBOXMAINCLIENTEXE
    44 #VBoxNetDHCP_TEMPLATE := VBOXR3$(if-expr defined(VBOX_WITH_HARDENING),,EXE)
     43VBoxNetDHCP_TEMPLATE =
     44VBoxNetDHCP_TEMPLATE := VBOXR3$(if-expr defined(VBOX_WITH_HARDENING),,EXE)
    4545VBoxNetDHCP_SOURCES = \
    4646        VBoxNetDHCP.cpp \
    47         Config.cpp \
    4847        ../NetLib/VBoxNetIntIf.cpp \
    4948        ../NetLib/VBoxNetUDP.cpp \
    50         ../NetLib/VBoxNetARP.cpp \
    51         ../NetLib/VBoxNetBaseService.cpp
     49        ../NetLib/VBoxNetARP.cpp
    5250VBoxNetDHCP_LIBS = \
    5351        $(LIB_RUNTIME)
    5452VBoxNetDHCP_LDFLAGS.win = /SUBSYSTEM:windows
    5553
    56 ifeq ($(USERNAME),vvl)
    57 PROGRAMS += tstDhcpConfig
    58 
    59 #
    60 # VBOXMAINCLIENT here only to use DhcpOpt_T type.
    61 tstDhcpConfig_TEMPLATE = VBOXMAINCLIENTEXE
    62 #XXX: enable condtionally if user is vvl
    63 #tstDhcpConfig_INSTTYPE = none
    64 tstDhcpConfig_SOURCES = test/tstDhcpConfig.cpp
    65 endif
    66 
    6754
    6855include $(FILE_KBUILD_SUB_FOOTER)
  • trunk/src/VBox/NetworkServices/DHCP/VBoxNetDHCP.cpp

    r46962 r46969  
    2525*   Header Files                                                               *
    2626*******************************************************************************/
    27 #include <VBox/com/com.h>
    28 #include <VBox/com/listeners.h>
    29 #include <VBox/com/string.h>
    30 #include <VBox/com/Guid.h>
    31 #include <VBox/com/array.h>
    32 #include <VBox/com/ErrorInfo.h>
    33 #include <VBox/com/errorprint.h>
    34 #include <VBox/com/EventQueue.h>
    35 #include <VBox/com/VirtualBox.h>
    36 
    3727#include <iprt/alloca.h>
    3828#include <iprt/buildconfig.h>
     
    5444#include <VBox/version.h>
    5545
    56 
    5746#include "../NetLib/VBoxNetLib.h"
    5847
    5948#include <vector>
    60 #include <list>
    6149#include <string>
    62 #include <map>
    63 
    64 #include "../NetLib/VBoxNetBaseService.h"
    6550
    6651#ifdef RT_OS_WINDOWS /* WinMain */
     
    6954#endif
    7055
    71 #ifndef INET4_ADDRLEN
    72 # define INET4_ADDRLEN 17
    73 #endif
    74 
    75 #include "Config.h"
     56
    7657/*******************************************************************************
    7758*   Structures and Typedefs                                                    *
    7859*******************************************************************************/
     60
     61/**
     62 * DHCP configuration item.
     63 *
     64 * This is all public data because I'm too lazy to do it properly right now.
     65 */
     66class VBoxNetDhcpCfg
     67{
     68public:
     69    /** The etheret addresses this matches config applies to.
     70     * An empty vector means 'ANY'. */
     71    std::vector<RTMAC>          m_MacAddresses;
     72    /** The upper address in the range. */
     73    RTNETADDRIPV4               m_UpperAddr;
     74    /** The lower address in the range. */
     75    RTNETADDRIPV4               m_LowerAddr;
     76
     77    /** Option 1: The net mask. */
     78    RTNETADDRIPV4               m_SubnetMask;
     79    /* * Option 2: The time offset. */
     80    /** Option 3: Routers for the subnet. */
     81    std::vector<RTNETADDRIPV4>  m_Routers;
     82    /* * Option 4: Time server. */
     83    /* * Option 5: Name server. */
     84    /** Option 6: Domain Name Server (DNS) */
     85    std::vector<RTNETADDRIPV4>  m_DNSes;
     86    /* * Option 7: Log server. */
     87    /* * Option 8: Cookie server. */
     88    /* * Option 9: LPR server. */
     89    /* * Option 10: Impress server. */
     90    /* * Option 11: Resource location server. */
     91    /* * Option 12: Host name. */
     92    std::string                 m_HostName;
     93    /* * Option 13: Boot file size option. */
     94    /* * Option 14: Merit dump file. */
     95    /** Option 15: Domain name. */
     96    std::string                 m_DomainName;
     97    /* * Option 16: Swap server. */
     98    /* * Option 17: Root path. */
     99    /* * Option 18: Extension path. */
     100    /* * Option 19: IP forwarding enable/disable. */
     101    /* * Option 20: Non-local routing enable/disable. */
     102    /* * Option 21: Policy filter. */
     103    /* * Option 22: Maximum datagram reassembly size (MRS). */
     104    /* * Option 23: Default IP time-to-live. */
     105    /* * Option 24: Path MTU aging timeout. */
     106    /* * Option 25: Path MTU plateau table. */
     107    /* * Option 26: Interface MTU. */
     108    /* * Option 27: All subnets are local. */
     109    /* * Option 28: Broadcast address. */
     110    /* * Option 29: Perform maximum discovery. */
     111    /* * Option 30: Mask supplier. */
     112    /* * Option 31: Perform route discovery. */
     113    /* * Option 32: Router solicitation address. */
     114    /* * Option 33: Static route. */
     115    /* * Option 34: Trailer encapsulation. */
     116    /* * Option 35: ARP cache timeout. */
     117    /* * Option 36: Ethernet encapsulation. */
     118    /* * Option 37: TCP Default TTL. */
     119    /* * Option 38: TCP Keepalive Interval. */
     120    /* * Option 39: TCP Keepalive Garbage. */
     121    /* * Option 40: Network Information Service (NIS) Domain. */
     122    /* * Option 41: Network Information Servers. */
     123    /* * Option 42: Network Time Protocol Servers. */
     124    /* * Option 43: Vendor Specific Information. */
     125    /* * Option 44: NetBIOS over TCP/IP Name Server (NBNS). */
     126    /* * Option 45: NetBIOS over TCP/IP Datagram distribution Server (NBDD). */
     127    /* * Option 46: NetBIOS over TCP/IP Node Type. */
     128    /* * Option 47: NetBIOS over TCP/IP Scope. */
     129    /* * Option 48: X Window System Font Server. */
     130    /* * Option 49: X Window System Display Manager. */
     131
     132    /** Option 51: IP Address Lease Time. */
     133    uint32_t                    m_cSecLease;
     134
     135    /* * Option 64: Network Information Service+ Domain. */
     136    /* * Option 65: Network Information Service+ Servers. */
     137    /** Option 66: TFTP server name. */
     138    std::string                 m_TftpServer;
     139    /** Address for the bp_siaddr field corresponding to m_TftpServer. */
     140    RTNETADDRIPV4               m_TftpServerAddr;
     141    /** Option 67: Bootfile name. */
     142    std::string                 m_BootfileName;
     143
     144    /* * Option 68: Mobile IP Home Agent. */
     145    /* * Option 69: Simple Mail Transport Protocol (SMPT) Server. */
     146    /* * Option 70: Post Office Protocol (POP3) Server. */
     147    /* * Option 71: Network News Transport Protocol (NNTP) Server. */
     148    /* * Option 72: Default World Wide Web (WWW) Server. */
     149    /* * Option 73: Default Finger Server. */
     150    /* * Option 74: Default Internet Relay Chat (IRC) Server. */
     151    /* * Option 75: StreetTalk Server. */
     152
     153    /* * Option 119: Domain Search. */
     154
     155
     156    VBoxNetDhcpCfg()
     157    {
     158        m_UpperAddr.u = UINT32_MAX;
     159        m_LowerAddr.u = UINT32_MAX;
     160        m_SubnetMask.u = UINT32_MAX;
     161        m_cSecLease = 60*60; /* 1 hour */
     162    }
     163
     164    /** Validates the configuration.
     165     * @returns 0 on success, exit code + error message to stderr on failure. */
     166    int validate(void)
     167    {
     168        if (    m_UpperAddr.u == UINT32_MAX
     169            ||  m_LowerAddr.u == UINT32_MAX
     170            ||  m_SubnetMask.u == UINT32_MAX)
     171        {
     172            RTStrmPrintf(g_pStdErr, "VBoxNetDHCP: Config is missing:");
     173            if (m_UpperAddr.u == UINT32_MAX)
     174                RTStrmPrintf(g_pStdErr, " --upper-ip");
     175            if (m_LowerAddr.u == UINT32_MAX)
     176                RTStrmPrintf(g_pStdErr, " --lower-ip");
     177            if (m_SubnetMask.u == UINT32_MAX)
     178                RTStrmPrintf(g_pStdErr, " --netmask");
     179            return 2;
     180        }
     181
     182        if (RT_N2H_U32(m_UpperAddr.u) < RT_N2H_U32(m_LowerAddr.u))
     183        {
     184            RTStrmPrintf(g_pStdErr, "VBoxNetDHCP: The --upper-ip value is lower than the --lower-ip one!\n"
     185                                    "             %d.%d.%d.%d < %d.%d.%d.%d\n",
     186                         m_UpperAddr.au8[0], m_UpperAddr.au8[1], m_UpperAddr.au8[2], m_UpperAddr.au8[3],
     187                         m_LowerAddr.au8[0], m_LowerAddr.au8[1], m_LowerAddr.au8[2], m_LowerAddr.au8[3]);
     188            return 3;
     189        }
     190
     191        /* the code goes insane if we have too many atm. lazy bird */
     192        uint32_t cIPs = RT_N2H_U32(m_UpperAddr.u) - RT_N2H_U32(m_LowerAddr.u);
     193        if (cIPs > 1024)
     194        {
     195            RTStrmPrintf(g_pStdErr, "VBoxNetDHCP: Too many IPs between --upper-ip and --lower-ip! %d (max 1024)\n"
     196                                    "             %d.%d.%d.%d < %d.%d.%d.%d\n",
     197                         cIPs,
     198                         m_UpperAddr.au8[0], m_UpperAddr.au8[1], m_UpperAddr.au8[2], m_UpperAddr.au8[3],
     199                         m_LowerAddr.au8[0], m_LowerAddr.au8[1], m_LowerAddr.au8[2], m_LowerAddr.au8[3]);
     200            return 3;
     201        }
     202        return 0;
     203    }
     204
     205    /**
     206     * Is this config for one specific client?
     207     *
     208     * @return  true / false.
     209     */
     210    bool            isOneSpecificClient(void) const
     211    {
     212        return m_LowerAddr.u == m_UpperAddr.u
     213            && m_MacAddresses.size() > 0;
     214    }
     215
     216    /**
     217     * Checks if this config matches the specified MAC address.
     218     *
     219     * @returns true / false.
     220     *
     221     * @param   pMac    The MAC address to match.
     222     */
     223    bool            matchesMacAddress(PCRTMAC pMac) const
     224    {
     225        size_t i = m_MacAddresses.size();
     226        if (RT_LIKELY(i < 1))
     227            return true; /* no entries == ALL wildcard match */
     228
     229        while (i--)
     230        {
     231            PCRTMAC pCur = &m_MacAddresses[i];
     232            if (    pCur->au16[0] == pMac->au16[0]
     233                &&  pCur->au16[1] == pMac->au16[1]
     234                &&  pCur->au16[2] == pMac->au16[2])
     235                return true;
     236        }
     237        return false;
     238    }
     239
     240};
     241
     242/**
     243 * DHCP lease.
     244 */
     245class VBoxNetDhcpLease
     246{
     247public:
     248    typedef enum State
     249    {
     250        /** Invalid. */
     251        kState_Invalid = 0,
     252        /** The lease is free / released. */
     253        kState_Free,
     254        /** An offer has been made.
     255         * Expire time indicates when the offer expires. */
     256        kState_Offer,
     257        /** The lease is active.
     258         * Expire time indicates when the lease expires. */
     259        kState_Active
     260    } State;
     261
     262    /** The client MAC address. */
     263    RTMAC           m_MacAddress;
     264    /** The IPv4 address. */
     265    RTNETADDRIPV4   m_IPv4Address;
     266
     267    /** The current lease state. */
     268    State           m_enmState;
     269    /** The lease expiration time. */
     270    RTTIMESPEC      m_ExpireTime;
     271    /** Transaction ID. */
     272    uint32_t        m_xid;
     273    /** The configuration for this lease. */
     274    VBoxNetDhcpCfg *m_pCfg;
     275
     276public:
     277    /** Constructor taking an IPv4 address and a Config. */
     278    VBoxNetDhcpLease(RTNETADDRIPV4 IPv4Addr, VBoxNetDhcpCfg *pCfg)
     279    {
     280        m_pCfg          = pCfg;
     281        m_IPv4Address   = IPv4Addr;
     282
     283        m_MacAddress.au16[0] = m_MacAddress.au16[1] =  m_MacAddress.au16[2] = 0xff;
     284        m_enmState      = kState_Free;
     285        RTTimeSpecSetSeconds(&m_ExpireTime, 0);
     286        m_xid           = UINT32_MAX;
     287    }
     288
     289    /** Destructor.  */
     290    ~VBoxNetDhcpLease()
     291    {
     292        m_IPv4Address.u = UINT32_MAX;
     293        m_pCfg          = NULL;
     294        m_MacAddress.au16[0] = m_MacAddress.au16[1] =  m_MacAddress.au16[2] = 0xff;
     295        m_enmState      = kState_Free;
     296        m_xid           = UINT32_MAX;
     297    }
     298
     299    void            offer(uint32_t xid);
     300    void            activate(void);
     301    void            activate(uint32_t xid);
     302    void            release(void);
     303    bool            hasExpired(void) const;
     304
     305    /**
     306     * Checks if the lease is in use or not.
     307     *
     308     * @returns true if active, false if free or expired.
     309     *
     310     * @param   pNow        The current time to use. Optional.
     311     */
     312    bool            isInUse(PCRTTIMESPEC pNow = NULL) const
     313    {
     314        if  (   m_enmState == kState_Offer
     315             || m_enmState == kState_Active)
     316        {
     317            RTTIMESPEC Now;
     318            if (!pNow)
     319                pNow = RTTimeNow(&Now);
     320            return RTTimeSpecGetSeconds(&m_ExpireTime) > RTTimeSpecGetSeconds(pNow);
     321        }
     322        return false;
     323    }
     324
     325    /**
     326     * Is this lease for one specific client?
     327     *
     328     * @return  true/false.
     329     */
     330    bool            isOneSpecificClient(void) const
     331    {
     332        return m_pCfg
     333            && m_pCfg->isOneSpecificClient();
     334    }
     335
     336    /**
     337     * Is this lease currently being offered to a client.
     338     *
     339     * @returns true / false.
     340     */
     341    bool            isBeingOffered(void) const
     342    {
     343        return m_enmState == kState_Offer
     344            && isInUse();
     345    }
     346
     347    /**
     348     * Is the lease in the current config or not.
     349     *
     350     * When updating the config we might leave active leases behind which aren't
     351     * included in the new config. These will have m_pCfg set to NULL and should be
     352     * freed up when they expired.
     353     *
     354     * @returns true / false.
     355     */
     356    bool            isInCurrentConfig(void) const
     357    {
     358        return m_pCfg != NULL;
     359    }
     360};
     361
    79362/**
    80363 * DHCP server instance.
    81364 */
    82 class VBoxNetDhcp: public VBoxNetBaseService
     365class VBoxNetDhcp
    83366{
    84367public:
     
    86369    virtual ~VBoxNetDhcp();
    87370
    88     int                 init();
     371    int                 parseArgs(int argc, char **argv);
     372    int                 tryGoOnline(void);
    89373    int                 run(void);
    90     void                usage(void) { /* XXX: document options */ };
    91     int                 parseOpt(int rc, const RTGETOPTUNION& getOptVal);
    92374
    93375protected:
     376    int                 addConfig(VBoxNetDhcpCfg *pCfg);
     377    void                explodeConfig(void);
     378
    94379    bool                handleDhcpMsg(uint8_t uMsgType, PCRTNETBOOTP pDhcpMsg, size_t cb);
    95380    bool                handleDhcpReqDiscover(PCRTNETBOOTP pDhcpMsg, size_t cb);
     
    97382    bool                handleDhcpReqDecline(PCRTNETBOOTP pDhcpMsg, size_t cb);
    98383    bool                handleDhcpReqRelease(PCRTNETBOOTP pDhcpMsg, size_t cb);
    99 
     384    void                makeDhcpReply(uint8_t uMsgType, VBoxNetDhcpLease *pLease, PCRTNETBOOTP pDhcpMsg, size_t cb);
     385
     386    VBoxNetDhcpLease   *findLeaseByMacAddress(PCRTMAC pMacAddress, bool fAnyState);
     387    VBoxNetDhcpLease   *findLeaseByIpv4AndMacAddresses(RTNETADDRIPV4 IPv4Addr, PCRTMAC pMacAddress, bool fAnyState);
     388    VBoxNetDhcpLease   *newLease(PCRTNETBOOTP pDhcpMsg, size_t cb);
     389
     390    static uint8_t const *findOption(uint8_t uOption, PCRTNETBOOTP pDhcpMsg, size_t cb, size_t *pcbMaxOpt);
     391    static bool         findOptionIPv4Addr(uint8_t uOption, PCRTNETBOOTP pDhcpMsg, size_t cb, PRTNETADDRIPV4 pIPv4Addr);
     392
     393    inline void         debugPrint( int32_t iMinLevel, bool fMsg,  const char *pszFmt, ...) const;
    100394    void                debugPrintV(int32_t iMinLevel, bool fMsg,  const char *pszFmt, va_list va) const;
    101395    static const char  *debugDhcpName(uint8_t uMsgType);
    102396
    103397protected:
    104     /** @name The DHCP server specific configuration data members.
     398    /** @name The server configuration data members.
    105399     * @{ */
    106     /*
    107      * XXX: what was the plan? SQL3 or plain text file?
    108      * How it will coexists with managment from VBoxManagement, who should manage db
    109      * in that case (VBoxManage, VBoxSVC ???)
    110      */
     400    std::string         m_Name;
     401    std::string         m_Network;
     402    std::string         m_TrunkName;
     403    INTNETTRUNKTYPE     m_enmTrunkType;
     404    RTMAC               m_MacAddress;
     405    RTNETADDRIPV4       m_Ipv4Address;
    111406    std::string         m_LeaseDBName;
    112 
    113407    /** @} */
    114408
    115     /* corresponding dhcp server description in Main */
    116     ComPtr<IDHCPServer> m_DhcpServer;
    117 
    118     ComPtr<INATNetwork> m_NATNetwork;
    119    
    120     /*
    121      * We will ignore cmd line parameters IFF there will be some DHCP specific arguments
    122      * otherwise all paramters will come from Main.
    123      */
    124     bool m_fIgnoreCmdLineParameters;
    125 
    126     /*
    127      * -b -n 10.0.1.2 -m 255.255.255.0 -> to the list processing in
    128      */
    129     typedef struct
    130     {
    131         char Key;
    132         std::string strValue;
    133     } CMDLNPRM;
    134     std::list<CMDLNPRM> CmdParameterll;
    135     typedef std::list<CMDLNPRM>::iterator CmdParameterIterator;
     409    /** The current configs. */
     410    std::vector<VBoxNetDhcpCfg *> m_Cfgs;
     411
     412    /** The current leases. */
     413    std::vector<VBoxNetDhcpLease> m_Leases;
     414
     415    /** @name The network interface
     416     * @{ */
     417    PSUPDRVSESSION      m_pSession;
     418    uint32_t            m_cbSendBuf;
     419    uint32_t            m_cbRecvBuf;
     420    INTNETIFHANDLE      m_hIf;          /**< The handle to the network interface. */
     421    PINTNETBUF          m_pIfBuf;       /**< Interface buffer. */
     422    /** @} */
    136423
    137424    /** @name Debug stuff
     
    144431    /** @} */
    145432};
    146 #if 0
    147 /* XXX: clean up it. */
    148 typedef std::vector<VBoxNetDhcpLease> DhcpLeaseContainer;
    149 typedef DhcpLeaseContainer::iterator DhcpLeaseIterator;
    150 typedef DhcpLeaseContainer::reverse_iterator DhcpLeaseRIterator;
    151 typedef DhcpLeaseContainer::const_iterator DhcpLeaseCIterator;
    152 #endif
     433
    153434
    154435/*******************************************************************************
     
    158439static VBoxNetDhcp *g_pDhcp;
    159440
    160 /* DHCP server specific options */
    161 static const RTGETOPTDEF g_aOptionDefs[] =
    162 {
    163   { "--lease-db",       'D',   RTGETOPT_REQ_STRING },
    164   { "--begin-config",   'b',   RTGETOPT_REQ_NOTHING },
    165   { "--gateway",        'g',   RTGETOPT_REQ_IPV4ADDR },
    166   { "--lower-ip",       'l',   RTGETOPT_REQ_IPV4ADDR },
    167   { "--upper-ip",       'u',   RTGETOPT_REQ_IPV4ADDR },
    168 };
    169 
    170 #if 0
    171 /* XXX this will gone */
     441
    172442/**
    173443 * Offer this lease to a client.
     
    235505    return RTTimeSpecGetSeconds(&m_ExpireTime) > RTTimeSpecGetSeconds(RTTimeNow(&Now));
    236506}
    237 #endif
     507
     508
     509
    238510
    239511/**
     
    266538    memset(&m_CurHdrs, '\0', sizeof(m_CurHdrs));
    267539
    268     m_fIgnoreCmdLineParameters = true;
    269 
    270540#if 0 /* enable to hack the code without a mile long argument list. */
    271541    VBoxNetDhcpCfg *pDefCfg = new VBoxNetDhcpCfg();
     
    279549    pDefCfg->m_DNSes.push_back(Addr);
    280550    pDefCfg->m_DomainName     = "vboxnetdhcp.org";
    281 # if 0
     551#if 0
    282552    pDefCfg->m_cSecLease      = 60*60; /* 1 hour */
    283 # else
     553#else
    284554    pDefCfg->m_cSecLease      = 30; /* sec */
    285 # endif
     555#endif
    286556    pDefCfg->m_TftpServer     = "10.0.2.3"; //??
    287557    this->addConfig(pDefCfg);
     
    295565VBoxNetDhcp::~VBoxNetDhcp()
    296566{
    297 }
    298 
    299 
    300 
    301 
    302 /**
    303  * Parse the DHCP specific arguments.
    304  *
    305  * This callback caled for each paramenter so
    306  * ....
    307  * we nee post analisys of the parameters, at least
    308  *    for -b, -g, -l, -u, -m 
    309  */
    310 int VBoxNetDhcp::parseOpt(int rc, const RTGETOPTUNION& Val)
    311 {
    312     CMDLNPRM prm;
    313 
    314     /* Ok, we've entered here, thus we can't ignore cmd line parameters anymore */
    315     m_fIgnoreCmdLineParameters = false;
    316 
    317     prm.Key = rc;
    318 
    319     switch (rc)
    320     {
     567    /*
     568     * Close the interface connection.
     569     */
     570    if (m_hIf != INTNET_HANDLE_INVALID)
     571    {
     572        INTNETIFCLOSEREQ CloseReq;
     573        CloseReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
     574        CloseReq.Hdr.cbReq = sizeof(CloseReq);
     575        CloseReq.pSession = m_pSession;
     576        CloseReq.hIf = m_hIf;
     577        m_hIf = INTNET_HANDLE_INVALID;
     578        int rc = SUPR3CallVMMR0Ex(NIL_RTR0PTR, NIL_VMCPUID, VMMR0_DO_INTNET_IF_CLOSE, 0, &CloseReq.Hdr);
     579        AssertRC(rc);
     580    }
     581
     582    if (m_pSession)
     583    {
     584        SUPR3Term(false /*fForced*/);
     585        m_pSession = NIL_RTR0PTR;
     586    }
     587}
     588
     589
     590/**
     591 * Adds a config to the tail.
     592 *
     593 * @returns See VBoxNetDHCP::validate().
     594 * @param   pCfg        The config too add.
     595 *                      This object will be consumed by this call!
     596 */
     597int VBoxNetDhcp::addConfig(VBoxNetDhcpCfg *pCfg)
     598{
     599    int rc = 0;
     600    if (pCfg)
     601    {
     602        rc = pCfg->validate();
     603        if (!rc)
     604            m_Cfgs.push_back(pCfg);
     605        else
     606            delete pCfg;
     607    }
     608    return rc;
     609}
     610
     611
     612/**
     613 * Explodes the config into leases.
     614 *
     615 * @remarks     This code is brute force and not very fast nor memory efficient.
     616 *              We will have to revisit this later.
     617 *
     618 * @remarks     If an IP has been reconfigured for a fixed mac address and it's
     619 *              already leased to a client, we it won't be available until the
     620 *              client releases its lease or it expires.
     621 */
     622void VBoxNetDhcp::explodeConfig(void)
     623{
     624    RTTIMESPEC  Now;
     625    RTTimeNow(&Now);
     626
     627    /*
     628     * Remove all non-active leases from the vector and zapping the
     629     * config pointers of the once left behind.
     630     */
     631    std::vector<VBoxNetDhcpLease>::iterator Itr = m_Leases.begin();
     632    while (Itr != m_Leases.end())
     633    {
     634        if (!Itr->isInUse(&Now))
     635            Itr = m_Leases.erase(Itr);
     636        else
     637        {
     638            Itr->m_pCfg = NULL;
     639            Itr++;
     640        }
     641    }
     642
     643    /*
     644     * Loop thru the configurations in reverse order, giving the last
     645     * configs priority of the newer ones.
     646     */
     647    size_t iCfg = m_Cfgs.size();
     648    while (iCfg-- > 0)
     649    {
     650        VBoxNetDhcpCfg *pCfg = m_Cfgs[iCfg];
     651
     652        /* Expand the IP lease range. */
     653        uint32_t const uLast = RT_N2H_U32(pCfg->m_UpperAddr.u);
     654        for (uint32_t i = RT_N2H_U32(pCfg->m_LowerAddr.u); i <= uLast; i++)
     655        {
     656            RTNETADDRIPV4 IPv4Addr;
     657            IPv4Addr.u = RT_H2N_U32(i);
     658
     659            /* Check if it exists and is configured. */
     660            VBoxNetDhcpLease *pLease = NULL;
     661            for (size_t j = 0; j < m_Leases.size(); j++)
     662                if (m_Leases[j].m_IPv4Address.u == IPv4Addr.u)
     663                {
     664                    pLease = &m_Leases[j];
     665                    break;
     666                }
     667            if (pLease)
     668            {
     669                if (!pLease->m_pCfg)
     670                    pLease->m_pCfg = pCfg;
     671            }
     672            else
     673            {
     674                /* add it. */
     675                VBoxNetDhcpLease NewLease(IPv4Addr, pCfg);
     676                m_Leases.push_back(NewLease);
     677                debugPrint(10, false, "exploseConfig: new lease %d.%d.%d.%d",
     678                           IPv4Addr.au8[0], IPv4Addr.au8[1], IPv4Addr.au8[2], IPv4Addr.au8[3]);
     679            }
     680        }
     681    }
     682}
     683
     684
     685/**
     686 * Parse the arguments.
     687 *
     688 * @returns 0 on success, fully bitched exit code on failure.
     689 *
     690 * @param   argc    Argument count.
     691 * @param   argv    Argument vector.
     692 */
     693int VBoxNetDhcp::parseArgs(int argc, char **argv)
     694{
     695    static const RTGETOPTDEF s_aOptionDefs[] =
     696    {
     697        { "--name",           'N',   RTGETOPT_REQ_STRING },
     698        { "--network",        'n',   RTGETOPT_REQ_STRING },
     699        { "--trunk-name",     't',   RTGETOPT_REQ_STRING },
     700        { "--trunk-type",     'T',   RTGETOPT_REQ_STRING },
     701        { "--mac-address",    'a',   RTGETOPT_REQ_MACADDR },
     702        { "--ip-address",     'i',   RTGETOPT_REQ_IPV4ADDR },
     703        { "--lease-db",       'D',   RTGETOPT_REQ_STRING },
     704        { "--verbose",        'v',   RTGETOPT_REQ_NOTHING },
     705
     706        { "--begin-config",   'b',   RTGETOPT_REQ_NOTHING },
     707        { "--gateway",        'g',   RTGETOPT_REQ_IPV4ADDR },
     708        { "--lower-ip",       'l',   RTGETOPT_REQ_IPV4ADDR },
     709        { "--upper-ip",       'u',   RTGETOPT_REQ_IPV4ADDR },
     710        { "--netmask",        'm',   RTGETOPT_REQ_IPV4ADDR },
     711    };
     712
     713    RTGETOPTSTATE State;
     714    int rc = RTGetOptInit(&State, argc, argv, &s_aOptionDefs[0], RT_ELEMENTS(s_aOptionDefs), 0, 0 /*fFlags*/);
     715    AssertRCReturn(rc, 49);
     716
     717    VBoxNetDhcpCfg *pCurCfg = NULL;
     718    for (;;)
     719    {
     720        RTGETOPTUNION Val;
     721        rc = RTGetOpt(&State, &Val);
     722        if (!rc)
     723            break;
     724        switch (rc)
     725        {
     726            case 'N':
     727                m_Name = Val.psz;
     728                break;
     729            case 'n':
     730                m_Network = Val.psz;
     731                break;
     732            case 't':
     733                m_TrunkName = Val.psz;
     734                break;
     735            case 'T':
     736                if (!strcmp(Val.psz, "none"))
     737                    m_enmTrunkType = kIntNetTrunkType_None;
     738                else if (!strcmp(Val.psz, "whatever"))
     739                    m_enmTrunkType = kIntNetTrunkType_WhateverNone;
     740                else if (!strcmp(Val.psz, "netflt"))
     741                    m_enmTrunkType = kIntNetTrunkType_NetFlt;
     742                else if (!strcmp(Val.psz, "netadp"))
     743                    m_enmTrunkType = kIntNetTrunkType_NetAdp;
     744                else if (!strcmp(Val.psz, "srvnat"))
     745                    m_enmTrunkType = kIntNetTrunkType_SrvNat;
     746                else
     747                {
     748                    RTStrmPrintf(g_pStdErr, "Invalid trunk type '%s'\n", Val.psz);
     749                    return 1;
     750                }
     751                break;
     752            case 'a':
     753                m_MacAddress = Val.MacAddr;
     754                break;
     755            case 'i':
     756                m_Ipv4Address = Val.IPv4Addr;
     757                break;
     758            case 'd':
     759                m_LeaseDBName = Val.psz;
     760                break;
     761
     762            case 'v':
     763                m_cVerbosity++;
     764                break;
     765
    321766            /* Begin config. */
    322         case 'b':
    323             CmdParameterll.push_back(prm);
    324             break;
    325 
    326         case 'l':
    327         case 'u':
    328         case 'm':
    329         case 'g':
    330             prm.strValue = std::string(Val.psz);
    331             CmdParameterll.push_back(prm);
    332             break;
    333 
    334         case 'D':
    335             break;
    336 
    337         default:
    338             rc = RTGetOptPrintError(rc, &Val);
    339             RTPrintf("Use --help for more information.\n");
    340             return rc;
    341     }
     767            case 'b':
     768                rc = addConfig(pCurCfg);
     769                if (rc)
     770                    break;
     771                pCurCfg = NULL;
     772                /* fall thru */
     773
     774            /* config specific ones. */
     775            case 'g':
     776            case 'l':
     777            case 'u':
     778            case 'm':
     779                if (!pCurCfg)
     780                {
     781                    pCurCfg = new VBoxNetDhcpCfg();
     782                    if (!pCurCfg)
     783                    {
     784                        RTStrmPrintf(g_pStdErr, "VBoxNetDHCP: new VBoxDhcpCfg failed\n");
     785                        return 1;
     786                    }
     787                }
     788
     789                switch (rc)
     790                {
     791                    case 'g':
     792                        pCurCfg->m_Routers.push_back(Val.IPv4Addr);
     793                        break;
     794
     795                    case 'l':
     796                        pCurCfg->m_LowerAddr = Val.IPv4Addr;
     797                        break;
     798
     799                    case 'u':
     800                        pCurCfg->m_UpperAddr = Val.IPv4Addr;
     801                        break;
     802
     803                    case 'm':
     804                        pCurCfg->m_SubnetMask = Val.IPv4Addr;
     805                        break;
     806
     807                    case 0: /* ignore */ break;
     808                    default:
     809                        AssertMsgFailed(("%d", rc));
     810                        return 1;
     811                }
     812                break;
     813
     814            case 'V':
     815                RTPrintf("%sr%u\n", RTBldCfgVersion(), RTBldCfgRevision());
     816                return 1;
     817
     818            case 'h':
     819                RTPrintf("VBoxNetDHCP Version %s\n"
     820                         "(C) 2009-" VBOX_C_YEAR " " VBOX_VENDOR "\n"
     821                         "All rights reserved.\n"
     822                         "\n"
     823                         "Usage: VBoxNetDHCP <options>\n"
     824                         "\n"
     825                         "Options:\n",
     826                         RTBldCfgVersion());
     827                for (size_t i = 0; i < RT_ELEMENTS(s_aOptionDefs); i++)
     828                    RTPrintf("    -%c, %s\n", s_aOptionDefs[i].iShort, s_aOptionDefs[i].pszLong);
     829                return 1;
     830
     831            default:
     832                rc = RTGetOptPrintError(rc, &Val);
     833                RTPrintf("Use --help for more information.\n");
     834                return rc;
     835        }
     836    }
     837
     838    /*
     839     * Do the reconfig. (move this later)
     840     */
     841    if (!rc)
     842        explodeConfig();
    342843
    343844    return rc;
    344845}
    345846
    346 int VBoxNetDhcp::init()
    347 {
    348     HRESULT hrc = S_OK;
    349     /* ok, here we should initiate instance of dhcp server
    350      * and listener for Dhcp configuration events
    351      */
    352     AssertRCReturn(virtualbox.isNull(), VERR_INTERNAL_ERROR);
    353 
    354     hrc = virtualbox->FindDHCPServerByNetworkName(com::Bstr(m_Network.c_str()).raw(),
    355                                                   m_DhcpServer.asOutParam());
    356     AssertComRCReturn(hrc, VERR_INTERNAL_ERROR);
    357 
    358     hrc = virtualbox->FindNATNetworkByName(com::Bstr(m_Network.c_str()).raw(),
    359                                            m_NATNetwork.asOutParam());
    360 
    361     /* This isn't fatal in general case.
    362      * AssertComRCReturn(hrc, VERR_INTERNAL_ERROR);
    363      */
    364 
    365     ConfigurationManager *confManager = ConfigurationManager::getConfigurationManager();
    366     AssertPtrReturn(confManager, VERR_INTERNAL_ERROR);
    367 
    368     /**
    369      * if we have nat netework of the same name
    370      * this is good chance that we are assigned to this network.
    371      */
    372     BOOL fNeedDhcpServer = false;
    373     if (   !m_NATNetwork.isNull()
    374         && SUCCEEDED(m_NATNetwork->COMGETTER(NeedDhcpServer)(&fNeedDhcpServer))
    375         && fNeedDhcpServer)
    376     {
    377         /* 90% we are servicing NAT network */
    378         RTNETADDRIPV4 gateway;
    379         com::Bstr strGateway;
    380         hrc = m_NATNetwork->GetGateway(strGateway.asOutParam());
    381         AssertComRCReturn(hrc, VERR_INTERNAL_ERROR);
    382         RTNetStrToIPv4Addr(com::Utf8Str(strGateway).c_str(), &gateway);
    383 
    384         confManager->addToAddressList(RTNET_DHCP_OPT_ROUTERS, gateway);
    385     }
    386 
    387     NetworkManager *netManager = NetworkManager::getNetworkManager();
    388 
    389     netManager->setOurAddress(m_Ipv4Address);
    390     netManager->setOurNetmask(m_Ipv4Netmask);
    391     netManager->setOurMac(m_MacAddress);
    392 
    393     /* Configuration fetching */
    394     if (m_fIgnoreCmdLineParameters)
    395     {
    396         /* just fetch option array and add options to config */
    397         /* per VM-settings ???
    398          *
    399          * - we have vms with attached adapters with known mac-addresses
    400          * - mac-addresses might be changed as well as names, how keep our config cleaned ????
     847
     848/**
     849 * Tries to connect to the internal network.
     850 *
     851 * @returns 0 on success, exit code + error message to stderr on failure.
     852 */
     853int VBoxNetDhcp::tryGoOnline(void)
     854{
     855    /*
     856     * Open the session, load ring-0 and issue the request.
     857     */
     858    int rc = SUPR3Init(&m_pSession);
     859    if (RT_FAILURE(rc))
     860    {
     861        m_pSession = NIL_RTR0PTR;
     862        RTStrmPrintf(g_pStdErr, "VBoxNetDHCP: SUPR3Init -> %Rrc", rc);
     863        return 1;
     864    }
     865
     866    char szPath[RTPATH_MAX];
     867    rc = RTPathExecDir(szPath, sizeof(szPath) - sizeof("/VMMR0.r0"));
     868    if (RT_FAILURE(rc))
     869    {
     870        RTStrmPrintf(g_pStdErr, "VBoxNetDHCP: RTPathProgram -> %Rrc", rc);
     871        return 1;
     872    }
     873
     874    rc = SUPR3LoadVMM(strcat(szPath, "/VMMR0.r0"));
     875    if (RT_FAILURE(rc))
     876    {
     877        RTStrmPrintf(g_pStdErr, "VBoxNetDHCP: SUPR3LoadVMM(\"%s\") -> %Rrc", szPath, rc);
     878        return 1;
     879    }
     880
     881    /*
     882     * Create the open request.
     883     */
     884    INTNETOPENREQ OpenReq;
     885    OpenReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
     886    OpenReq.Hdr.cbReq = sizeof(OpenReq);
     887    OpenReq.pSession = m_pSession;
     888    strncpy(OpenReq.szNetwork, m_Network.c_str(), sizeof(OpenReq.szNetwork));
     889    OpenReq.szNetwork[sizeof(OpenReq.szNetwork) - 1] = '\0';
     890    strncpy(OpenReq.szTrunk, m_TrunkName.c_str(), sizeof(OpenReq.szTrunk));
     891    OpenReq.szTrunk[sizeof(OpenReq.szTrunk) - 1] = '\0';
     892    OpenReq.enmTrunkType = m_enmTrunkType;
     893    OpenReq.fFlags = 0; /** @todo check this */
     894    OpenReq.cbSend = m_cbSendBuf;
     895    OpenReq.cbRecv = m_cbRecvBuf;
     896    OpenReq.hIf = INTNET_HANDLE_INVALID;
     897
     898    /*
     899     * Issue the request.
     900     */
     901    debugPrint(2, false, "attempting to open/create network \"%s\"...", OpenReq.szNetwork);
     902    rc = SUPR3CallVMMR0Ex(NIL_RTR0PTR, NIL_VMCPUID, VMMR0_DO_INTNET_OPEN, 0, &OpenReq.Hdr);
     903    if (RT_SUCCESS(rc))
     904    {
     905        m_hIf = OpenReq.hIf;
     906        debugPrint(1, false, "successfully opened/created \"%s\" - hIf=%#x", OpenReq.szNetwork, m_hIf);
     907
     908        /*
     909         * Get the ring-3 address of the shared interface buffer.
    401910         */
    402         com::SafeArray<BSTR> sf;
    403         hrc = m_DhcpServer->GetGlobalOptions(ComSafeArrayAsOutParam(sf));
    404         AssertComRCReturn(hrc, VERR_INTERNAL_ERROR);
    405 
    406 #if 0       
    407         for (int i = 0; i < sf.size(); ++i)
    408         {
    409             RTPrintf("%d: %s\n", i, com::Utf8Str(sf[i]).c_str());
    410         }
    411      
    412 #endif   
    413         com::Bstr strUpperIp, strLowerIp;
    414        
    415         RTNETADDRIPV4 LowerAddress;
    416         RTNETADDRIPV4 UpperAddress;
    417 
    418         hrc = m_DhcpServer->GetUpperIP(strUpperIp.asOutParam());
    419         AssertComRCReturn(hrc, VERR_INTERNAL_ERROR);
    420         RTNetStrToIPv4Addr(com::Utf8Str(strUpperIp).c_str(), &UpperAddress);
    421        
    422 
    423         hrc = m_DhcpServer->GetLowerIP(strLowerIp.asOutParam());
    424         AssertComRCReturn(hrc, VERR_INTERNAL_ERROR);
    425         RTNetStrToIPv4Addr(com::Utf8Str(strLowerIp).c_str(), &LowerAddress);
    426 
    427         RTNETADDRIPV4 networkId;
    428         networkId.u = m_Ipv4Address.u & m_Ipv4Netmask.u;
    429         std::string name = std::string("default");
    430        
    431         NetworkConfigEntity *pCfg = confManager->addNetwork(unconst(g_RootConfig),
    432                                                             networkId,
    433                                                             m_Ipv4Netmask,
    434                                                             LowerAddress,
    435                                                             UpperAddress);
    436 
    437     } /* if(m_fIgnoreCmdLineParameters) */
     911        INTNETIFGETBUFFERPTRSREQ GetBufferPtrsReq;
     912        GetBufferPtrsReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
     913        GetBufferPtrsReq.Hdr.cbReq = sizeof(GetBufferPtrsReq);
     914        GetBufferPtrsReq.pSession = m_pSession;
     915        GetBufferPtrsReq.hIf = m_hIf;
     916        GetBufferPtrsReq.pRing3Buf = NULL;
     917        GetBufferPtrsReq.pRing0Buf = NIL_RTR0PTR;
     918        rc = SUPR3CallVMMR0Ex(NIL_RTR0PTR, NIL_VMCPUID, VMMR0_DO_INTNET_IF_GET_BUFFER_PTRS, 0, &GetBufferPtrsReq.Hdr);
     919        if (RT_SUCCESS(rc))
     920        {
     921            PINTNETBUF pBuf = GetBufferPtrsReq.pRing3Buf;
     922            debugPrint(1, false, "pBuf=%p cbBuf=%d cbSend=%d cbRecv=%d",
     923                       pBuf, pBuf->cbBuf, pBuf->cbSend, pBuf->cbRecv);
     924            m_pIfBuf = pBuf;
     925
     926            /*
     927             * Activate the interface.
     928             */
     929            INTNETIFSETACTIVEREQ ActiveReq;
     930            ActiveReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
     931            ActiveReq.Hdr.cbReq = sizeof(ActiveReq);
     932            ActiveReq.pSession = m_pSession;
     933            ActiveReq.hIf = m_hIf;
     934            ActiveReq.fActive = true;
     935            rc = SUPR3CallVMMR0Ex(NIL_RTR0PTR, NIL_VMCPUID, VMMR0_DO_INTNET_IF_SET_ACTIVE, 0, &ActiveReq.Hdr);
     936            if (RT_SUCCESS(rc))
     937                return 0;
     938
     939            /* bail out */
     940            RTStrmPrintf(g_pStdErr, "VBoxNetDHCP: SUPR3CallVMMR0Ex(,VMMR0_DO_INTNET_IF_SET_PROMISCUOUS_MODE,) failed, rc=%Rrc\n", rc);
     941        }
     942        else
     943            RTStrmPrintf(g_pStdErr, "VBoxNetDHCP: SUPR3CallVMMR0Ex(,VMMR0_DO_INTNET_IF_GET_BUFFER_PTRS,) failed, rc=%Rrc\n", rc);
     944    }
    438945    else
    439     {
    440         CmdParameterIterator it;
    441        
    442         RTNETADDRIPV4 networkId;
    443         networkId.u = m_Ipv4Address.u & m_Ipv4Netmask.u;
    444         RTNETADDRIPV4 netmask = m_Ipv4Netmask;
    445         RTNETADDRIPV4 LowerAddress;
    446         RTNETADDRIPV4 UpperAddress;
    447        
    448         LowerAddress = networkId;
    449         UpperAddress.u = RT_H2N_U32(RT_N2H_U32(LowerAddress.u) | RT_N2H_U32(netmask.u));
    450 
    451         int idx = 0;
    452         char name[64];
    453 
    454 
    455         for (it = CmdParameterll.begin(); it != CmdParameterll.end(); ++it)
    456         {
    457             idx++;
    458             RTStrPrintf(name, RT_ELEMENTS(name), "network-%d", idx);
    459             std::string strname(name);
    460 
    461             switch(it->Key)
    462             {
    463                 case 'b':
    464                     /* config */
    465                     NetworkConfigEntity(strname,
    466                                         g_RootConfig,
    467                                         g_AnyClient,
    468                                         5,
    469                                         networkId,
    470                                         netmask,
    471                                         LowerAddress,
    472                                         UpperAddress);
    473                 case 'l':
    474                 case 'u':
    475                 case 'm':
    476                 case 'g':
    477                     /* XXX: TBD */
    478                     break;
    479             }
    480         }
    481     }
    482     return VINF_SUCCESS;
    483 }
     946        RTStrmPrintf(g_pStdErr, "VBoxNetDHCP: SUPR3CallVMMR0Ex(,VMMR0_DO_INTNET_OPEN,) failed, rc=%Rrc\n", rc);
     947
     948    return RT_SUCCESS(rc) ? 0 : 1;
     949}
     950
    484951
    485952/**
     
    491958int VBoxNetDhcp::run(void)
    492959{
    493 
    494     /* XXX: shortcut should be hidden from network manager */
    495     NetworkManager *netManager = NetworkManager::getNetworkManager();
    496     netManager->m_pSession = m_pSession;
    497     netManager->m_hIf = m_hIf;
    498     netManager->m_pIfBuf = m_pIfBuf;
    499 
    500960    /*
    501961     * The loop.
     
    6141074bool VBoxNetDhcp::handleDhcpReqDiscover(PCRTNETBOOTP pDhcpMsg, size_t cb)
    6151075{
    616 
    617     /* let's main first */
    618     if (!m_DhcpServer.isNull())
    619     {
    620         HRESULT hrc;
    621         com::SafeArray<BSTR> sf;
    622         hrc = m_DhcpServer->GetMacOptions(com::BstrFmt("%02X%02X%02X%02X%02X%02X",
    623                                                   pDhcpMsg->bp_chaddr.Mac.au8[0],
    624                                                   pDhcpMsg->bp_chaddr.Mac.au8[1],
    625                                                   pDhcpMsg->bp_chaddr.Mac.au8[2],
    626                                                   pDhcpMsg->bp_chaddr.Mac.au8[3],
    627                                                   pDhcpMsg->bp_chaddr.Mac.au8[4],
    628                                                   pDhcpMsg->bp_chaddr.Mac.au8[5],
    629                                                   pDhcpMsg->bp_chaddr.Mac.au8[6]).raw(),
    630                                           ComSafeArrayAsOutParam(sf));
    631         if (SUCCEEDED(hrc))
    632         {
    633             /* XXX: per-host configuration */
    634         }
    635        
    636         SessionManager *sesionManager = SessionManager::getSessionManager();
    637         Session& session = sesionManager->getClientSessionByDhcpPacket(pDhcpMsg, cb);
    638         /* XXX: switch -> private */
    639         session.switchTo(DHCPDISCOVERRECEIEVED);
    640        
    641         ConfigurationManager *confManager = ConfigurationManager::getConfigurationManager();
    642         int rc = confManager->findConfiguration4Session(session);
    643         AssertRCReturn(rc, rc);
    644 
    645         rc = confManager->allocateConfiguration4Session(session);
    646         AssertRCReturn(rc, rc);
    647 
    648         NetworkManager *netManager = NetworkManager::getNetworkManager();
    649         rc = netManager->offer4Session(session);
    650         AssertRCReturn(rc, rc);
    651 
    652 
    653     } /* end of if(!m_DhcpServer.isNull()) */
    654 
    655     return VINF_SUCCESS;
     1076    /*
     1077     * The newLease() method contains logic for finding current leases
     1078     * and reusing them in case the client is forgetful.
     1079     */
     1080    VBoxNetDhcpLease *pLease = newLease(pDhcpMsg, cb);
     1081    if (!pLease)
     1082        return false;
     1083    debugPrint(1, true, "Offering %d.%d.%d.%d to %.6Rhxs xid=%#x",
     1084               pLease->m_IPv4Address.au8[0],
     1085               pLease->m_IPv4Address.au8[1],
     1086               pLease->m_IPv4Address.au8[2],
     1087               pLease->m_IPv4Address.au8[3],
     1088               &pDhcpMsg->bp_chaddr.Mac,
     1089               pDhcpMsg->bp_xid);
     1090    pLease->offer(pDhcpMsg->bp_xid);
     1091
     1092    makeDhcpReply(RTNET_DHCP_MT_OFFER, pLease, pDhcpMsg, cb);
     1093    return true;
    6561094}
    6571095
     
    6671105bool VBoxNetDhcp::handleDhcpReqRequest(PCRTNETBOOTP pDhcpMsg, size_t cb)
    6681106{
    669     SessionManager *sesionManager = SessionManager::getSessionManager();
    670     Session& session = sesionManager->getClientSessionByDhcpPacket(pDhcpMsg, cb);
    671     /* XXX: switch -> private */
    672     session.switchTo(DHCPREQUESTRECEIVED);
    673        
    674     ConfigurationManager *confManager = ConfigurationManager::getConfigurationManager();
    675     int rc = confManager->findConfiguration4Session(session);
    676     AssertRCReturn(rc, false);
    677 
    678     rc = confManager->commitConfiguration4ClientSession(session);
    679 
    680     NetworkManager *netManager = NetworkManager::getNetworkManager();
    681     if (RT_SUCCESS(rc))
    682         rc = netManager->ack(session);
     1107    /** @todo Probably need to match the server IP here to work correctly with
     1108     *        other servers. */
     1109    /** @todo This code isn't entirely correct and quite a bit of a hack, but it
     1110     *        will have to do for now as the right thing (tm) is very complex.
     1111     *        Part of the fun is verifying that the request is something we can
     1112     *        and should handle. */
     1113
     1114    /*
     1115     * Try find the lease by the requested address + client MAC address.
     1116     */
     1117    VBoxNetDhcpLease   *pLease = NULL;
     1118    RTNETADDRIPV4       IPv4Addr;
     1119    bool                fReqAddr = findOptionIPv4Addr(RTNET_DHCP_OPT_REQ_ADDR, pDhcpMsg, cb, &IPv4Addr);
     1120    if (fReqAddr)
     1121    {
     1122        fReqAddr = true;
     1123        pLease = findLeaseByIpv4AndMacAddresses(IPv4Addr, &pDhcpMsg->bp_chaddr.Mac, true /* fAnyState */);
     1124    }
     1125
     1126    /*
     1127     * Try find the lease by the client IP address + client MAC address.
     1128     */
     1129    if (    !pLease
     1130        &&  pDhcpMsg->bp_ciaddr.u)
     1131        pLease = findLeaseByIpv4AndMacAddresses(pDhcpMsg->bp_ciaddr, &pDhcpMsg->bp_chaddr.Mac, true /* fAnyState */);
     1132
     1133#if 0 /** @todo client id stuff - it doesn't make sense here imho, we need IP + MAC. What would make sense
     1134                though is to compare the client id with what we've got in the lease and use it to root out
     1135                bad requests. */
     1136    /*
     1137     * Try find the lease by using the client id.
     1138     */
     1139    if (!pLease)
     1140    {
     1141        size_t          cbClientID = 0;
     1142        uint8_t const  *pbClientID  = findOption(RTNET_DHCP_OPT_CLIENT_ID, pDhcpMsg, cb, &cbClientID);
     1143        if (    pbClientID
     1144            &&  cbClientID == sizeof(RTMAC) + 1
     1145            &&  pbClientID[0] == RTNET_ARP_ETHER
     1146            &&
     1147                )
     1148        {
     1149            pLease = findLeaseByIpv4AndMacAddresses(pDhcpMsg->bp_ciaddr, &pDhcpMsg->bp_chaddr.Mac, true /* fAnyState */);
     1150        }
     1151    }
     1152#endif
     1153
     1154    /*
     1155     * Validate the lease that's requested.
     1156     * We've already check the MAC and IP addresses.
     1157     */
     1158    bool fAckIt = false;
     1159    if (pLease)
     1160    {
     1161        if (pLease->isBeingOffered())
     1162        {
     1163            if (pLease->m_xid == pDhcpMsg->bp_xid)
     1164                debugPrint(2, true, "REQUEST for offered lease.");
     1165            else
     1166                debugPrint(2, true, "REQUEST for offered lease, xid mismatch. Expected %#x, got %#x.",
     1167                           pLease->m_xid, pDhcpMsg->bp_xid);
     1168            pLease->activate(pDhcpMsg->bp_xid);
     1169            fAckIt = true;
     1170        }
     1171        else if (!pLease->isInCurrentConfig())
     1172            debugPrint(1, true, "REQUEST for obsolete lease -> NAK");
     1173        else if (fReqAddr != (pDhcpMsg->bp_ciaddr.u != 0)) // ???
     1174        {
     1175            /** @todo this ain't safe. */
     1176            debugPrint(1, true, "REQUEST for lease not on offer, assuming renewal. lease_xid=%#x bp_xid=%#x",
     1177                       pLease->m_xid, pDhcpMsg->bp_xid);
     1178            fAckIt = true;
     1179            pLease->activate(pDhcpMsg->bp_xid);
     1180        }
     1181        else
     1182            debugPrint(1, true, "REQUEST for lease not on offer, NAK it.");
     1183    }
     1184
     1185    /*
     1186     * NAK if if no lease was found.
     1187     */
     1188    if (fAckIt)
     1189    {
     1190        debugPrint(1, false, "ACK'ing DHCP_REQUEST");
     1191        makeDhcpReply(RTNET_DHCP_MT_ACK, pLease, pDhcpMsg, cb);
     1192    }
    6831193    else
    684         rc = netManager->nak(session);
    685    
    686     AssertRCReturn(rc, false);
     1194    {
     1195        debugPrint(1, false, "NAK'ing DHCP_REQUEST");
     1196        makeDhcpReply(RTNET_DHCP_MT_NAC, NULL, pDhcpMsg, cb);
     1197    }
    6871198
    6881199    return true;
     
    7491260    debugPrint(1, true, "RELEASE is not implemented");
    7501261    return true;
     1262}
     1263
     1264
     1265/**
     1266 * Helper class for stuffing DHCP options into a reply packet.
     1267 */
     1268class VBoxNetDhcpWriteCursor
     1269{
     1270private:
     1271    uint8_t        *m_pbCur;       /**< The current cursor position. */
     1272    uint8_t        *m_pbEnd;       /**< The end the current option space. */
     1273    uint8_t        *m_pfOverload;  /**< Pointer to the flags of the overload option. */
     1274    uint8_t         m_fUsed;       /**< Overload fields that have been used. */
     1275    PRTNETDHCPOPT   m_pOpt;        /**< The current option. */
     1276    PRTNETBOOTP     m_pDhcp;       /**< The DHCP packet. */
     1277    bool            m_fOverflowed; /**< Set if we've overflowed, otherwise false. */
     1278
     1279public:
     1280    /** Instantiate an option cursor for the specified DHCP message. */
     1281    VBoxNetDhcpWriteCursor(PRTNETBOOTP pDhcp, size_t cbDhcp) :
     1282        m_pbCur(&pDhcp->bp_vend.Dhcp.dhcp_opts[0]),
     1283        m_pbEnd((uint8_t *)pDhcp + cbDhcp),
     1284        m_pfOverload(NULL),
     1285        m_fUsed(0),
     1286        m_pOpt(NULL),
     1287        m_pDhcp(pDhcp),
     1288        m_fOverflowed(false)
     1289    {
     1290        AssertPtr(pDhcp);
     1291        Assert(cbDhcp > RT_UOFFSETOF(RTNETBOOTP, bp_vend.Dhcp.dhcp_opts[10]));
     1292    }
     1293
     1294    /** Destructor.  */
     1295    ~VBoxNetDhcpWriteCursor()
     1296    {
     1297        m_pbCur = m_pbEnd = m_pfOverload = NULL;
     1298        m_pOpt = NULL;
     1299        m_pDhcp = NULL;
     1300    }
     1301
     1302    /**
     1303     * Try use the bp_file field.
     1304     * @returns true if not overloaded, false otherwise.
     1305     */
     1306    bool useBpFile(void)
     1307    {
     1308        if (    m_pfOverload
     1309            &&  (*m_pfOverload & 1))
     1310            return false;
     1311        m_fUsed |= 1 /* bp_file flag*/;
     1312        return true;
     1313    }
     1314
     1315
     1316    /**
     1317     * Try overload more BOOTP fields
     1318     */
     1319    bool overloadMore(void)
     1320    {
     1321        /* switch option area. */
     1322        uint8_t    *pbNew;
     1323        uint8_t    *pbNewEnd;
     1324        uint8_t     fField;
     1325        if (!(m_fUsed & 1))
     1326        {
     1327            fField     = 1;
     1328            pbNew      = &m_pDhcp->bp_file[0];
     1329            pbNewEnd   = &m_pDhcp->bp_file[sizeof(m_pDhcp->bp_file)];
     1330        }
     1331        else if (!(m_fUsed & 2))
     1332        {
     1333            fField     = 2;
     1334            pbNew      = &m_pDhcp->bp_sname[0];
     1335            pbNewEnd   = &m_pDhcp->bp_sname[sizeof(m_pDhcp->bp_sname)];
     1336        }
     1337        else
     1338            return false;
     1339
     1340        if (!m_pfOverload)
     1341        {
     1342            /* Add an overload option. */
     1343            *m_pbCur++ = RTNET_DHCP_OPT_OPTION_OVERLOAD;
     1344            *m_pbCur++ = fField;
     1345            m_pfOverload = m_pbCur;
     1346            *m_pbCur++ = 1;     /* bp_file flag */
     1347        }
     1348        else
     1349            *m_pfOverload |= fField;
     1350
     1351        /* pad current option field */
     1352        while (m_pbCur != m_pbEnd)
     1353            *m_pbCur++ = RTNET_DHCP_OPT_PAD; /** @todo not sure if this stuff is at all correct... */
     1354
     1355        /* switch */
     1356        m_pbCur = pbNew;
     1357        m_pbEnd = pbNewEnd;
     1358        return true;
     1359    }
     1360
     1361    /**
     1362     * Begin an option.
     1363     *
     1364     * @returns true on success, false if we're out of space.
     1365     *
     1366     * @param   uOption     The option number.
     1367     * @param   cb          The amount of data.
     1368     */
     1369    bool begin(uint8_t uOption, size_t cb)
     1370    {
     1371        /* Check that the data of the previous option has all been written. */
     1372        Assert(   !m_pOpt
     1373               || (m_pbCur - m_pOpt->dhcp_len == (uint8_t *)(m_pOpt + 1)));
     1374        AssertMsg(cb <= 255, ("%#x\n", cb));
     1375
     1376        /* Check if we need to overload more stuff. */
     1377        if ((uintptr_t)(m_pbEnd - m_pbCur) < cb + 2 + (m_pfOverload ? 1 : 3))
     1378        {
     1379            m_pOpt = NULL;
     1380            if (!overloadMore())
     1381            {
     1382                m_fOverflowed = true;
     1383                AssertMsgFailedReturn(("%u %#x\n", uOption, cb), false);
     1384            }
     1385            if ((uintptr_t)(m_pbEnd - m_pbCur) < cb + 2 + 1)
     1386            {
     1387                m_fOverflowed = true;
     1388                AssertMsgFailedReturn(("%u %#x\n", uOption, cb), false);
     1389            }
     1390        }
     1391
     1392        /* Emit the option header. */
     1393        m_pOpt = (PRTNETDHCPOPT)m_pbCur;
     1394        m_pOpt->dhcp_opt = uOption;
     1395        m_pOpt->dhcp_len = (uint8_t)cb;
     1396        m_pbCur += 2;
     1397        return true;
     1398    }
     1399
     1400    /**
     1401     * Puts option data.
     1402     *
     1403     * @param   pvData      The data.
     1404     * @param   cb          The amount to put.
     1405     */
     1406    void put(void const *pvData, size_t cb)
     1407    {
     1408        Assert(m_pOpt || m_fOverflowed);
     1409        if (RT_LIKELY(m_pOpt))
     1410        {
     1411            Assert((uintptr_t)m_pbCur - (uintptr_t)(m_pOpt + 1) + cb  <= (size_t)m_pOpt->dhcp_len);
     1412            memcpy(m_pbCur, pvData, cb);
     1413            m_pbCur += cb;
     1414        }
     1415    }
     1416
     1417    /**
     1418     * Puts an IPv4 Address.
     1419     *
     1420     * @param   IPv4Addr    The address.
     1421     */
     1422    void putIPv4Addr(RTNETADDRIPV4 IPv4Addr)
     1423    {
     1424        put(&IPv4Addr, 4);
     1425    }
     1426
     1427    /**
     1428     * Adds an IPv4 address option.
     1429     *
     1430     * @returns true/false just like begin().
     1431     *
     1432     * @param   uOption     The option number.
     1433     * @param   IPv4Addr    The address.
     1434     */
     1435    bool optIPv4Addr(uint8_t uOption, RTNETADDRIPV4 IPv4Addr)
     1436    {
     1437        if (!begin(uOption, 4))
     1438            return false;
     1439        putIPv4Addr(IPv4Addr);
     1440        return true;
     1441    }
     1442
     1443    /**
     1444     * Adds an option taking 1 or more IPv4 address.
     1445     *
     1446     * If the vector contains no addresses, the option will not be added.
     1447     *
     1448     * @returns true/false just like begin().
     1449     *
     1450     * @param   uOption     The option number.
     1451     * @param   rIPv4Addrs  Reference to the address vector.
     1452     */
     1453    bool optIPv4Addrs(uint8_t uOption, std::vector<RTNETADDRIPV4> const &rIPv4Addrs)
     1454    {
     1455        size_t const c = rIPv4Addrs.size();
     1456        if (!c)
     1457            return true;
     1458
     1459        if (!begin(uOption, 4*c))
     1460            return false;
     1461        for (size_t i = 0; i < c; i++)
     1462            putIPv4Addr(rIPv4Addrs[i]);
     1463        return true;
     1464    }
     1465
     1466    /**
     1467     * Puts an 8-bit integer.
     1468     *
     1469     * @param   u8          The integer.
     1470     */
     1471    void putU8(uint8_t u8)
     1472    {
     1473        put(&u8, 1);
     1474    }
     1475
     1476    /**
     1477     * Adds an 8-bit integer option.
     1478     *
     1479     * @returns true/false just like begin().
     1480     *
     1481     * @param   uOption     The option number.
     1482     * @param   u8          The integer
     1483     */
     1484    bool optU8(uint8_t uOption, uint8_t u8)
     1485    {
     1486        if (!begin(uOption, 1))
     1487            return false;
     1488        putU8(u8);
     1489        return true;
     1490    }
     1491
     1492    /**
     1493     * Puts an 32-bit integer (network endian).
     1494     *
     1495     * @param   u32Network  The integer.
     1496     */
     1497    void putU32(uint32_t u32)
     1498    {
     1499        put(&u32, 4);
     1500    }
     1501
     1502    /**
     1503     * Adds an 32-bit integer (network endian) option.
     1504     *
     1505     * @returns true/false just like begin().
     1506     *
     1507     * @param   uOption     The option number.
     1508     * @param   u32Network  The integer.
     1509     */
     1510    bool optU32(uint8_t uOption, uint32_t u32)
     1511    {
     1512        if (!begin(uOption, 4))
     1513            return false;
     1514        putU32(u32);
     1515        return true;
     1516    }
     1517
     1518    /**
     1519     * Puts a std::string.
     1520     *
     1521     * @param   rStr        Reference to the string.
     1522     */
     1523    void putStr(std::string const &rStr)
     1524    {
     1525        put(rStr.c_str(), rStr.size());
     1526    }
     1527
     1528    /**
     1529     * Adds an std::string option if the string isn't empty.
     1530     *
     1531     * @returns true/false just like begin().
     1532     *
     1533     * @param   uOption     The option number.
     1534     * @param   rStr        Reference to the string.
     1535     */
     1536    bool optStr(uint8_t uOption, std::string const &rStr)
     1537    {
     1538        const size_t cch = rStr.size();
     1539        if (!cch)
     1540            return true;
     1541
     1542        if (!begin(uOption, cch))
     1543            return false;
     1544        put(rStr.c_str(), cch);
     1545        return true;
     1546    }
     1547
     1548    /**
     1549     * Whether we've overflowed.
     1550     *
     1551     * @returns true on overflow, false otherwise.
     1552     */
     1553    bool hasOverflowed(void) const
     1554    {
     1555        return m_fOverflowed;
     1556    }
     1557
     1558    /**
     1559     * Adds the terminating END option.
     1560     *
     1561     * The END will always be added as we're reserving room for it, however, we
     1562     * might have dropped previous options due to overflows and that is what the
     1563     * return status indicates.
     1564     *
     1565     * @returns true on success, false on a (previous) overflow.
     1566     */
     1567    bool optEnd(void)
     1568    {
     1569        Assert((uintptr_t)(m_pbEnd - m_pbCur) < 4096);
     1570        *m_pbCur++ = RTNET_DHCP_OPT_END;
     1571        return !hasOverflowed();
     1572    }
     1573};
     1574
     1575
     1576/**
     1577 * Constructs and sends a reply to a client.
     1578 *
     1579 * @returns
     1580 * @param   uMsgType        The DHCP message type.
     1581 * @param   pLease          The lease. This can be NULL for some replies.
     1582 * @param   pDhcpMsg        The client message. We will dig out the MAC address,
     1583 *                          transaction ID, and requested options from this.
     1584 * @param   cb              The size of the client message.
     1585 */
     1586void VBoxNetDhcp::makeDhcpReply(uint8_t uMsgType, VBoxNetDhcpLease *pLease, PCRTNETBOOTP pDhcpMsg, size_t cb)
     1587{
     1588    size_t      cbReply = RTNET_DHCP_NORMAL_SIZE; /** @todo respect the RTNET_DHCP_OPT_MAX_DHCP_MSG_SIZE option */
     1589    PRTNETBOOTP pReply = (PRTNETBOOTP)alloca(cbReply);
     1590
     1591    /*
     1592     * The fixed bits stuff.
     1593     */
     1594    pReply->bp_op     = RTNETBOOTP_OP_REPLY;
     1595    pReply->bp_htype  = RTNET_ARP_ETHER;
     1596    pReply->bp_hlen   = sizeof(RTMAC);
     1597    pReply->bp_hops   = 0;
     1598    pReply->bp_xid    = pDhcpMsg->bp_xid;
     1599    pReply->bp_secs   = 0;
     1600    pReply->bp_flags  = 0; // (pDhcpMsg->bp_flags & RTNET_DHCP_FLAGS_NO_BROADCAST); ??
     1601    pReply->bp_ciaddr.u = 0;
     1602    pReply->bp_yiaddr.u = pLease ? pLease->m_IPv4Address.u : 0xffffffff;
     1603    pReply->bp_siaddr.u = pLease && pLease->m_pCfg ? pLease->m_pCfg->m_TftpServerAddr.u : 0; /* (next server == TFTP)*/
     1604    pReply->bp_giaddr.u = 0;
     1605    memset(&pReply->bp_chaddr, '\0', sizeof(pReply->bp_chaddr));
     1606    pReply->bp_chaddr.Mac = pDhcpMsg->bp_chaddr.Mac;
     1607    memset(&pReply->bp_sname[0], '\0', sizeof(pReply->bp_sname));
     1608    memset(&pReply->bp_file[0],  '\0', sizeof(pReply->bp_file));
     1609    pReply->bp_vend.Dhcp.dhcp_cookie = RT_H2N_U32_C(RTNET_DHCP_COOKIE);
     1610    memset(&pReply->bp_vend.Dhcp.dhcp_opts[0], '\0', RTNET_DHCP_OPT_SIZE);
     1611
     1612    /*
     1613     * The options - use a cursor class for dealing with the ugly stuff.
     1614     */
     1615    VBoxNetDhcpWriteCursor Cursor(pReply, cbReply);
     1616
     1617    /* The basics */
     1618    Cursor.optU8(RTNET_DHCP_OPT_MSG_TYPE, uMsgType);
     1619    Cursor.optIPv4Addr(RTNET_DHCP_OPT_SERVER_ID, m_Ipv4Address);
     1620
     1621    if (uMsgType != RTNET_DHCP_MT_NAC)
     1622    {
     1623        AssertReturnVoid(pLease && pLease->m_pCfg);
     1624        const VBoxNetDhcpCfg *pCfg = pLease->m_pCfg; /* no need to retain it. */
     1625
     1626        /* The IP config. */
     1627        Cursor.optU32(RTNET_DHCP_OPT_LEASE_TIME, RT_H2N_U32(pCfg->m_cSecLease));
     1628        Cursor.optIPv4Addr(RTNET_DHCP_OPT_SUBNET_MASK, pCfg->m_SubnetMask);
     1629        Cursor.optIPv4Addrs(RTNET_DHCP_OPT_ROUTERS, pCfg->m_Routers);
     1630        Cursor.optIPv4Addrs(RTNET_DHCP_OPT_ROUTERS, pCfg->m_DNSes);
     1631        Cursor.optStr(RTNET_DHCP_OPT_HOST_NAME, pCfg->m_HostName);
     1632        Cursor.optStr(RTNET_DHCP_OPT_DOMAIN_NAME, pCfg->m_DomainName);
     1633
     1634        /* The PXE config. */
     1635        if (pCfg->m_BootfileName.size())
     1636        {
     1637            if (Cursor.useBpFile())
     1638                RTStrPrintf((char *)&pReply->bp_file[0], sizeof(pReply->bp_file), "%s", pCfg->m_BootfileName.c_str());
     1639            else
     1640                Cursor.optStr(RTNET_DHCP_OPT_BOOTFILE_NAME, pCfg->m_BootfileName);
     1641        }
     1642    }
     1643
     1644    /* Terminate the options. */
     1645    if (!Cursor.optEnd())
     1646        debugPrint(0, true, "option overflow\n");
     1647
     1648    /*
     1649     * Send it.
     1650     */
     1651    int rc;
     1652#if 0
     1653    if (!(pDhcpMsg->bp_flags & RTNET_DHCP_FLAGS_NO_BROADCAST)) /** @todo need to see someone set this flag to check that it's correct. */
     1654    {
     1655        RTNETADDRIPV4 IPv4AddrBrdCast;
     1656        IPv4AddrBrdCast.u = UINT32_C(0xffffffff); /* broadcast IP */
     1657        rc = VBoxNetUDPUnicast(m_pSession, m_hIf, m_pIfBuf,
     1658                               m_Ipv4Address, &m_MacAddress, RTNETIPV4_PORT_BOOTPS,                 /* sender */
     1659                               IPv4AddrBrdCast, &pDhcpMsg->bp_chaddr.Mac, RTNETIPV4_PORT_BOOTPC,    /* receiver */
     1660                               pReply, cbReply);
     1661    }
     1662    else
     1663#endif
     1664        rc = VBoxNetUDPBroadcast(m_pSession, m_hIf, m_pIfBuf,
     1665                                 m_Ipv4Address, &m_MacAddress, RTNETIPV4_PORT_BOOTPS,               /* sender */
     1666                                 RTNETIPV4_PORT_BOOTPC,                                             /* receiver port */
     1667                                 pReply, cbReply);
     1668    if (RT_FAILURE(rc))
     1669        debugPrint(0, true, "error %Rrc when sending the reply", rc);
     1670}
     1671
     1672
     1673/**
     1674 * Look up a lease by MAC address.
     1675 *
     1676 * @returns Pointer to the lease if found, NULL if not found.
     1677 * @param   pMacAddress             The mac address.
     1678 * @param   fAnyState       Any state.
     1679 */
     1680VBoxNetDhcpLease *VBoxNetDhcp::findLeaseByMacAddress(PCRTMAC pMacAddress, bool fAnyState)
     1681{
     1682    size_t iLease = m_Leases.size();
     1683    while (iLease-- > 0)
     1684    {
     1685        VBoxNetDhcpLease *pLease = &m_Leases[iLease];
     1686        if (    pLease
     1687            &&  pLease->m_MacAddress.au16[0] == pMacAddress->au16[0]
     1688            &&  pLease->m_MacAddress.au16[1] == pMacAddress->au16[1]
     1689            &&  pLease->m_MacAddress.au16[2] == pMacAddress->au16[2]
     1690            &&  (   fAnyState
     1691                 || (pLease->m_enmState != VBoxNetDhcpLease::kState_Free)) )
     1692            return pLease;
     1693    }
     1694
     1695    return NULL;
     1696}
     1697
     1698
     1699/**
     1700 * Look up a lease by IPv4 and MAC addresses.
     1701 *
     1702 * @returns Pointer to the lease if found, NULL if not found.
     1703 * @param   IPv4Addr        The IPv4 address.
     1704 * @param   pMacAddress     The mac address.
     1705 * @param   fAnyState       Any state.
     1706 */
     1707VBoxNetDhcpLease *VBoxNetDhcp::findLeaseByIpv4AndMacAddresses(RTNETADDRIPV4 IPv4Addr, PCRTMAC pMacAddress, bool fAnyState)
     1708{
     1709    size_t iLease = m_Leases.size();
     1710    while (iLease-- > 0)
     1711    {
     1712        VBoxNetDhcpLease *pLease = &m_Leases[iLease];
     1713        if (    pLease
     1714            &&  pLease->m_IPv4Address.u      == IPv4Addr.u
     1715            &&  pLease->m_MacAddress.au16[0] == pMacAddress->au16[0]
     1716            &&  pLease->m_MacAddress.au16[1] == pMacAddress->au16[1]
     1717            &&  pLease->m_MacAddress.au16[2] == pMacAddress->au16[2]
     1718            &&  (   fAnyState
     1719                 || (pLease->m_enmState != VBoxNetDhcpLease::kState_Free)) )
     1720            return pLease;
     1721    }
     1722
     1723    return NULL;
     1724}
     1725
     1726
     1727/**
     1728 * Creates a new lease for the client specified in the DHCP message.
     1729 *
     1730 * The caller has already made sure it doesn't already have a lease.
     1731 *
     1732 * @returns Pointer to the lease if found, NULL+log if not found.
     1733 * @param   IPv4Addr        The IPv4 address.
     1734 * @param   pMacAddress     The MAC address.
     1735 */
     1736VBoxNetDhcpLease *VBoxNetDhcp::newLease(PCRTNETBOOTP pDhcpMsg, size_t cb)
     1737{
     1738    RTMAC const MacAddr = pDhcpMsg->bp_chaddr.Mac;
     1739    RTTIMESPEC  Now;
     1740    RTTimeNow(&Now);
     1741
     1742    /*
     1743     * Search the possible leases.
     1744     *
     1745     * We'll try do all the searches in one pass, that is to say, perfect
     1746     * match, old lease, and next free/expired lease.
     1747     */
     1748    VBoxNetDhcpLease *pBest = NULL;
     1749    VBoxNetDhcpLease *pOld  = NULL;
     1750    VBoxNetDhcpLease *pFree = NULL;
     1751
     1752    size_t cLeases = m_Leases.size();
     1753    for (size_t i = 0; i < cLeases; i++)
     1754    {
     1755        VBoxNetDhcpLease *pCur = &m_Leases[i];
     1756
     1757        /* Skip it if no configuration, that means its not in the current config. */
     1758        if (!pCur->m_pCfg)
     1759            continue;
     1760
     1761        /* best */
     1762        if (    pCur->isOneSpecificClient()
     1763            &&  pCur->m_pCfg->matchesMacAddress(&MacAddr))
     1764        {
     1765            if (    !pBest
     1766                ||  pBest->m_pCfg->m_MacAddresses.size() < pCur->m_pCfg->m_MacAddresses.size())
     1767                pBest = pCur;
     1768        }
     1769
     1770        /* old lease */
     1771        if (    pCur->m_MacAddress.au16[0] == MacAddr.au16[0]
     1772            &&  pCur->m_MacAddress.au16[1] == MacAddr.au16[1]
     1773            &&  pCur->m_MacAddress.au16[2] == MacAddr.au16[2])
     1774        {
     1775            if (    !pOld
     1776                ||  RTTimeSpecGetSeconds(&pCur->m_ExpireTime) > RTTimeSpecGetSeconds(&pFree->m_ExpireTime))
     1777                pOld = pCur;
     1778        }
     1779
     1780        /* expired lease */
     1781        if (!pCur->isInUse(&Now))
     1782        {
     1783            if (    !pFree
     1784                ||  RTTimeSpecGetSeconds(&pCur->m_ExpireTime) < RTTimeSpecGetSeconds(&pFree->m_ExpireTime))
     1785                pFree = pCur;
     1786        }
     1787    }
     1788
     1789    VBoxNetDhcpLease *pNew = pBest;
     1790    if (!pNew)
     1791        pNew = pOld;
     1792    if (!pNew)
     1793        pNew = pFree;
     1794    if (!pNew)
     1795    {
     1796        debugPrint(0, true, "No more leases.");
     1797        return NULL;
     1798    }
     1799
     1800    /*
     1801     * Init the lease.
     1802     */
     1803    pNew->m_MacAddress = MacAddr;
     1804    pNew->m_xid        = pDhcpMsg->bp_xid;
     1805    /** @todo extract the client id. */
     1806
     1807    return pNew;
     1808}
     1809
     1810
     1811/**
     1812 * Finds an option.
     1813 *
     1814 * @returns On success, a pointer to the first byte in the option data (no none
     1815 *          then it'll be the byte following the 0 size field) and *pcbOpt set
     1816 *          to the option length.
     1817 *          On failure, NULL is returned and *pcbOpt unchanged.
     1818 *
     1819 * @param   uOption         The option to search for.
     1820 * @param   pDhcpMsg        The DHCP message.
     1821 * @param   cb              The size of the message.
     1822 * @param   pcbOpt          Where to store the option size size. Optional. Note
     1823 *                          that this is adjusted if the option length is larger
     1824 *                          than the message buffer.
     1825 */
     1826/* static */ const uint8_t *
     1827VBoxNetDhcp::findOption(uint8_t uOption, PCRTNETBOOTP pDhcpMsg, size_t cb, size_t *pcbOpt)
     1828{
     1829    Assert(uOption != RTNET_DHCP_OPT_PAD);
     1830
     1831    /*
     1832     * Validate the DHCP bits and figure the max size of the options in the vendor field.
     1833     */
     1834    if (cb <= RT_UOFFSETOF(RTNETBOOTP, bp_vend.Dhcp.dhcp_opts))
     1835        return NULL;
     1836    if (pDhcpMsg->bp_vend.Dhcp.dhcp_cookie != RT_H2N_U32_C(RTNET_DHCP_COOKIE))
     1837        return NULL;
     1838    size_t cbLeft = cb - RT_UOFFSETOF(RTNETBOOTP, bp_vend.Dhcp.dhcp_opts);
     1839    if (cbLeft > RTNET_DHCP_OPT_SIZE)
     1840        cbLeft = RTNET_DHCP_OPT_SIZE;
     1841
     1842    /*
     1843     * Search the vendor field.
     1844     */
     1845    bool            fExtended = false;
     1846    uint8_t const  *pb = &pDhcpMsg->bp_vend.Dhcp.dhcp_opts[0];
     1847    while (pb && cbLeft > 0)
     1848    {
     1849        uint8_t uCur  = *pb;
     1850        if (uCur == RTNET_DHCP_OPT_PAD)
     1851        {
     1852            cbLeft--;
     1853            pb++;
     1854        }
     1855        else if (cbLeft <= 1)
     1856            break;
     1857        else
     1858        {
     1859            size_t  cbCur = pb[1];
     1860            if (cbCur > cbLeft - 2)
     1861                cbCur = cbLeft - 2;
     1862            if (uCur == uOption)
     1863            {
     1864                if (pcbOpt)
     1865                    *pcbOpt = cbCur;
     1866                return pb+2;
     1867            }
     1868            pb     += cbCur + 2;
     1869            cbLeft -= cbCur - 2;
     1870        }
     1871    }
     1872
     1873    /** @todo search extended dhcp option field(s) when present */
     1874
     1875    return NULL;
     1876}
     1877
     1878
     1879/**
     1880 * Locates an option with an IPv4 address in the DHCP message.
     1881 *
     1882 * @returns true and *pIpv4Addr if found, false if not.
     1883 *
     1884 * @param   uOption         The option to find.
     1885 * @param   pDhcpMsg        The DHCP message.
     1886 * @param   cb              The size of the message.
     1887 * @param   pIPv4Addr       Where to put the address.
     1888 */
     1889/* static */ bool
     1890VBoxNetDhcp::findOptionIPv4Addr(uint8_t uOption, PCRTNETBOOTP pDhcpMsg, size_t cb, PRTNETADDRIPV4 pIPv4Addr)
     1891{
     1892    size_t          cbOpt;
     1893    uint8_t const  *pbOpt = findOption(uOption, pDhcpMsg, cb, &cbOpt);
     1894    if (pbOpt)
     1895    {
     1896        if (cbOpt >= sizeof(RTNETADDRIPV4))
     1897        {
     1898            *pIPv4Addr = *(PCRTNETADDRIPV4)pbOpt;
     1899            return true;
     1900        }
     1901    }
     1902    return false;
     1903}
     1904
     1905
     1906/**
     1907 * Print debug message depending on the m_cVerbosity level.
     1908 *
     1909 * @param   iMinLevel       The minimum m_cVerbosity level for this message.
     1910 * @param   fMsg            Whether to dump parts for the current DHCP message.
     1911 * @param   pszFmt          The message format string.
     1912 * @param   ...             Optional arguments.
     1913 */
     1914inline void VBoxNetDhcp::debugPrint(int32_t iMinLevel, bool fMsg, const char *pszFmt, ...) const
     1915{
     1916    if (iMinLevel <= m_cVerbosity)
     1917    {
     1918        va_list va;
     1919        va_start(va, pszFmt);
     1920        debugPrintV(iMinLevel, fMsg, pszFmt, va);
     1921        va_end(va);
     1922    }
    7511923}
    7521924
     
    7731945            &&  m_pCurMsg)
    7741946        {
    775             /* XXX: export this to debugPrinfDhcpMsg or variant and other method export
    776              *  to base class
    777              */
    7781947            const char *pszMsg = m_uCurMsgType != UINT8_MAX ? debugDhcpName(m_uCurMsgType) : "";
    7791948            RTStrmPrintf(g_pStdErr, "VBoxNetDHCP: debug: %8s chaddr=%.6Rhxs ciaddr=%d.%d.%d.%d yiaddr=%d.%d.%d.%d siaddr=%d.%d.%d.%d xid=%#x\n",
     
    8342003     * Instantiate the DHCP server and hand it the options.
    8352004     */
    836     HRESULT hrc = com::Initialize();
    837     Assert(!FAILED(hrc));
    838 
    8392005    VBoxNetDhcp *pDhcp = new VBoxNetDhcp();
    8402006    if (!pDhcp)
     
    8462012    if (rc)
    8472013        return rc;
    848 
    849     pDhcp->init();
    8502014
    8512015    /*
  • trunk/src/VBox/NetworkServices/NetLib/VBoxNetBaseService.cpp

    r46962 r46969  
    11/* $Id$ */
    22/** @file
    3  * VBoxNetBaseService - Base Service class for connecting to IntNet.
    4  */
     3 * VBoxNetDHCP - DHCP Service for connecting to IntNet.
     4 */
     5/** @todo r=bird: Cut&Past rules... Please fix DHCP refs! */
    56
    67/*
     
    2122#define LOG_GROUP LOG_GROUP_NET_SERVICE
    2223
    23 #include <VBox/com/com.h>
    24 #include <VBox/com/listeners.h>
    25 #include <VBox/com/string.h>
    26 #include <VBox/com/Guid.h>
    27 #include <VBox/com/array.h>
    28 #include <VBox/com/ErrorInfo.h>
    29 #include <VBox/com/errorprint.h>
    30 #include <VBox/com/EventQueue.h>
    31 #include <VBox/com/VirtualBox.h>
    32 
    3324#include <iprt/alloca.h>
    3425#include <iprt/buildconfig.h>
     
    3930#include <iprt/param.h>
    4031#include <iprt/path.h>
    41 #include <iprt/process.h>
    4232#include <iprt/stream.h>
    4333#include <iprt/string.h>
    4434#include <iprt/time.h>
    4535#include <iprt/mem.h>
    46 #include <iprt/message.h>
    4736
    4837#include <VBox/sup.h>
     
    5544#include <string>
    5645
    57 #include <VBox/err.h>
    5846#include <VBox/log.h>
    5947
     
    7058*   Structures and Typedefs                                                    *
    7159*******************************************************************************/
    72 
    73 /*******************************************************************************
    74 *   Global Variables                                                           *
    75 *******************************************************************************/
    76 /* Commonly used options for network configuration */
    7760static RTGETOPTDEF g_aGetOptDef[] =
    7861{
     
    8669    { "--verbose",        'v',   RTGETOPT_REQ_NOTHING },
    8770};
    88 
    89 
    9071VBoxNetBaseService::VBoxNetBaseService()
    9172{
    92     int rc = RTCritSectInit(&m_csThis);
    93     AssertRC(rc);
    94     /* numbers from DrvIntNet */
    95     m_cbSendBuf             = 128 * _1K;
    96     m_cbRecvBuf             = 256 * _1K;
    97     m_hIf                   = INTNET_HANDLE_INVALID;
    98     m_pIfBuf                = NULL;
    99 
    100     m_cVerbosity            = 0;
    101     m_Name                  = "VBoxNetNAT";
    102     m_Network               = "intnet";
    103    
    104     for(unsigned int i = 0; i < RT_ELEMENTS(g_aGetOptDef); ++i)
    105         m_vecOptionDefs.push_back(&g_aGetOptDef[i]);
    106 
    107     HRESULT hrc = virtualbox.createLocalObject(CLSID_VirtualBox);
    108     if (FAILED(hrc))
    109         RTMsgError("Failed to create the VirtualBox object!");
    110 }
    111 
    112 
     73  int rc = RTCritSectInit(&m_csThis);
     74  AssertRC(rc);
     75}
    11376VBoxNetBaseService::~VBoxNetBaseService()
    11477{
     
    13699}
    137100
    138 
    139101int VBoxNetBaseService::init()
    140102{
     103    /* numbers from DrvIntNet */
     104    m_cbSendBuf             = 128 * _1K;
     105    m_cbRecvBuf             = 256 * _1K;
     106    m_hIf                   = INTNET_HANDLE_INVALID;
     107    m_pIfBuf                = NULL;
     108
     109    m_cVerbosity            = 0;
     110    m_Name                  = "VBoxNetNAT";
     111    m_Network               = "intnet";
     112    for(unsigned int i = 0; i < RT_ELEMENTS(g_aGetOptDef); ++i)
     113        m_vecOptionDefs.push_back(&g_aGetOptDef[i]);
    141114    return VINF_SUCCESS;
    142115}
    143 
    144 
    145116/**
    146117 * Parse the arguments.
     
    217188
    218189            case 'h':
    219                 RTPrintf("%s Version %s\n"
     190                RTPrintf("VBoxNetDHCP Version %s\n"
    220191                         "(C) 2009-" VBOX_C_YEAR " " VBOX_VENDOR "\n"
    221192                         "All rights reserved.\n"
    222193                         "\n"
    223                          "Usage: %s <options>\n"
     194                         "Usage: VBoxNetDHCP <options>\n"
    224195                         "\n"
    225196                         "Options:\n",
    226                          RTProcShortName(),
    227                          RTProcShortName(),
    228                          RTProcShortName(),
    229197                         RTBldCfgVersion());
    230198                for (unsigned int i = 0; i < m_vecOptionDefs.size(); i++)
     
    247215    return rc;
    248216}
    249 
    250217
    251218int VBoxNetBaseService::tryGoOnline(void)
     
    350317}
    351318
    352 
    353319void VBoxNetBaseService::shutdown(void)
    354320{
    355321}
    356 
    357322
    358323int VBoxNetBaseService::waitForIntNetEvent(int cMillis)
     
    412377}
    413378
    414 
    415379/**
    416380 * Print debug message depending on the m_cVerbosity level.
    417381 *
    418382 * @param   iMinLevel       The minimum m_cVerbosity level for this message.
    419  * @param   fMsg            Whether to dump parts for the current service message.
     383 * @param   fMsg            Whether to dump parts for the current DHCP message.
     384 * @param   pszFmt          The message format string.
     385 * @param   ...             Optional arguments.
     386 */
     387inline void VBoxNetBaseService::debugPrint(int32_t iMinLevel, bool fMsg, const char *pszFmt, ...) const
     388{
     389    if (iMinLevel <= m_cVerbosity)
     390    {
     391        va_list va;
     392        va_start(va, pszFmt);
     393        debugPrintV(iMinLevel, fMsg, pszFmt, va);
     394        va_end(va);
     395    }
     396}
     397
     398
     399/**
     400 * Print debug message depending on the m_cVerbosity level.
     401 *
     402 * @param   iMinLevel       The minimum m_cVerbosity level for this message.
     403 * @param   fMsg            Whether to dump parts for the current DHCP message.
    420404 * @param   pszFmt          The message format string.
    421405 * @param   va              Optional arguments.
     
    427411        va_list vaCopy;                 /* This dude is *very* special, thus the copy. */
    428412        va_copy(vaCopy, va);
    429         RTStrmPrintf(g_pStdErr, "%s: %s: %N\n",
    430                      RTProcShortName(),
    431                      iMinLevel >= 2 ? "debug" : "info",
    432                      pszFmt,
    433                      &vaCopy);
     413        RTStrmPrintf(g_pStdErr, "VBoxNetDHCP: %s: %N\n", iMinLevel >= 2 ? "debug" : "info", pszFmt, &vaCopy);
    434414        va_end(vaCopy);
    435415    }
    436416
    437417}
    438 
    439418
    440419PRTGETOPTDEF VBoxNetBaseService::getOptionsPtr()
  • trunk/src/VBox/NetworkServices/NetLib/VBoxNetBaseService.h

    r46962 r46969  
    1818#ifndef ___VBoxNetBaseService_h___
    1919#define ___VBoxNetBaseService_h___
    20 
    2120#include <iprt/critsect.h>
    2221class VBoxNetBaseService
     
    3332    int                 sendBufferOnWire(PCINTNETSEG pSg, int cSg, size_t cbBuffer);
    3433    void                flushWire();
    35 
    3634    virtual void        usage(void) = 0;
    37     virtual int         run(void) = 0;
     35    virtual void        run(void) = 0;
     36    virtual int         init(void);
    3837    virtual int         parseOpt(int rc, const RTGETOPTUNION& getOptVal) = 0;
    3938
    40     virtual int         init(void);
    41 
    42     /* VirtualBox instance */
    43     ComPtr<IVirtualBox> virtualbox;
    44 
    45 protected:
    46     /**
    47      * Print debug message depending on the m_cVerbosity level.
    48      *
    49      * @param   iMinLevel       The minimum m_cVerbosity level for this message.
    50      * @param   fMsg            Whether to dump parts for the current DHCP message.
    51      * @param   pszFmt          The message format string.
    52      * @param   ...             Optional arguments.
    53      */
    54     void debugPrint(int32_t iMinLevel, bool fMsg, const char *pszFmt, ...) const
    55     {
    56         if (iMinLevel <= m_cVerbosity)
    57         {
    58             va_list va;
    59             va_start(va, pszFmt);
    60             debugPrintV(iMinLevel, fMsg, pszFmt, va);
    61             va_end(va);
    62         }
    63     }
    64 
    65     virtual void debugPrintV(int32_t iMinLevel, bool fMsg, const char *pszFmt, va_list va) const;
    66 
     39    inline void         debugPrint( int32_t iMinLevel, bool fMsg,  const char *pszFmt, ...) const;
     40    void                debugPrintV(int32_t iMinLevel, bool fMsg,  const char *pszFmt, va_list va) const;
     41public:
    6742    /** @name The server configuration data members.
    6843     * @{ */
     
    7449    RTNETADDRIPV4       m_Ipv4Address;
    7550    RTNETADDRIPV4       m_Ipv4Netmask;
     51    /* cs for syncing */
     52    RTCRITSECT          m_csThis;
    7653    /** @} */
    7754    /** @name The network interface
     
    8966private:
    9067    PRTGETOPTDEF getOptionsPtr();
    91 
    92     /* cs for syncing */
    93     RTCRITSECT          m_csThis;
    94 
    9568    /** @} */
    9669};
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette