VirtualBox

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


Ignore:
Timestamp:
Jul 4, 2013 5:44:31 AM (11 years ago)
Author:
vboxsync
Message:

NetworkServices:
DHCP becomes Main client, internals changed to let more flexible managment and describing more complex networks (current state, so it should not brake a lot things, but something could stop working).

more stuff moved to BaseNetworkService class.

Location:
trunk/src/VBox/NetworkServices
Files:
1 added
4 edited

Legend:

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

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

    r44529 r46962  
    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
    2737#include <iprt/alloca.h>
    2838#include <iprt/buildconfig.h>
     
    4454#include <VBox/version.h>
    4555
     56
    4657#include "../NetLib/VBoxNetLib.h"
    4758
    4859#include <vector>
     60#include <list>
    4961#include <string>
     62#include <map>
     63
     64#include "../NetLib/VBoxNetBaseService.h"
    5065
    5166#ifdef RT_OS_WINDOWS /* WinMain */
     
    5469#endif
    5570
    56 
     71#ifndef INET4_ADDRLEN
     72# define INET4_ADDRLEN 17
     73#endif
     74
     75#include "Config.h"
    5776/*******************************************************************************
    5877*   Structures and Typedefs                                                    *
    5978*******************************************************************************/
    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  */
    66 class VBoxNetDhcpCfg
    67 {
    68 public:
    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  */
    245 class VBoxNetDhcpLease
    246 {
    247 public:
    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 
    276 public:
    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 
    36279/**
    36380 * DHCP server instance.
    36481 */
    365 class VBoxNetDhcp
     82class VBoxNetDhcp: public VBoxNetBaseService
    36683{
    36784public:
     
    36986    virtual ~VBoxNetDhcp();
    37087
    371     int                 parseArgs(int argc, char **argv);
    372     int                 tryGoOnline(void);
     88    int                 init();
    37389    int                 run(void);
     90    void                usage(void) { /* XXX: document options */ };
     91    int                 parseOpt(int rc, const RTGETOPTUNION& getOptVal);
    37492
    37593protected:
    376     int                 addConfig(VBoxNetDhcpCfg *pCfg);
    377     void                explodeConfig(void);
    378 
    37994    bool                handleDhcpMsg(uint8_t uMsgType, PCRTNETBOOTP pDhcpMsg, size_t cb);
    38095    bool                handleDhcpReqDiscover(PCRTNETBOOTP pDhcpMsg, size_t cb);
     
    38297    bool                handleDhcpReqDecline(PCRTNETBOOTP pDhcpMsg, size_t cb);
    38398    bool                handleDhcpReqRelease(PCRTNETBOOTP pDhcpMsg, size_t cb);
    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;
     99
    394100    void                debugPrintV(int32_t iMinLevel, bool fMsg,  const char *pszFmt, va_list va) const;
    395101    static const char  *debugDhcpName(uint8_t uMsgType);
    396102
    397103protected:
    398     /** @name The server configuration data members.
     104    /** @name The DHCP server specific configuration data members.
    399105     * @{ */
    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;
     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     */
    406111    std::string         m_LeaseDBName;
     112
    407113    /** @} */
    408114
    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     /** @} */
     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;
    423136
    424137    /** @name Debug stuff
     
    431144    /** @} */
    432145};
    433 
     146#if 0
     147/* XXX: clean up it. */
     148typedef std::vector<VBoxNetDhcpLease> DhcpLeaseContainer;
     149typedef DhcpLeaseContainer::iterator DhcpLeaseIterator;
     150typedef DhcpLeaseContainer::reverse_iterator DhcpLeaseRIterator;
     151typedef DhcpLeaseContainer::const_iterator DhcpLeaseCIterator;
     152#endif
    434153
    435154/*******************************************************************************
     
    439158static VBoxNetDhcp *g_pDhcp;
    440159
    441 
     160/* DHCP server specific options */
     161static 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 */
    442172/**
    443173 * Offer this lease to a client.
     
    505235    return RTTimeSpecGetSeconds(&m_ExpireTime) > RTTimeSpecGetSeconds(RTTimeNow(&Now));
    506236}
    507 
    508 
    509 
     237#endif
    510238
    511239/**
     
    538266    memset(&m_CurHdrs, '\0', sizeof(m_CurHdrs));
    539267
     268    m_fIgnoreCmdLineParameters = true;
     269
    540270#if 0 /* enable to hack the code without a mile long argument list. */
    541271    VBoxNetDhcpCfg *pDefCfg = new VBoxNetDhcpCfg();
     
    549279    pDefCfg->m_DNSes.push_back(Addr);
    550280    pDefCfg->m_DomainName     = "vboxnetdhcp.org";
    551 #if 0
     281# if 0
    552282    pDefCfg->m_cSecLease      = 60*60; /* 1 hour */
    553 #else
     283# else
    554284    pDefCfg->m_cSecLease      = 30; /* sec */
    555 #endif
     285# endif
    556286    pDefCfg->m_TftpServer     = "10.0.2.3"; //??
    557287    this->addConfig(pDefCfg);
     
    565295VBoxNetDhcp::~VBoxNetDhcp()
    566296{
    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);
     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 */
     310int 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    {
     321            /* 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;
    580341    }
    581342
    582     if (m_pSession)
    583     {
    584         SUPR3Term(false /*fForced*/);
    585         m_pSession = NIL_RTR0PTR;
     343    return rc;
     344}
     345
     346int 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);
    586385    }
    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  */
    597 int 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  */
    622 void 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
     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 ????
     401         */
     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)
    637408        {
    638             Itr->m_pCfg = NULL;
    639             Itr++;
     409            RTPrintf("%d: %s\n", i, com::Utf8Str(sf[i]).c_str());
    640410        }
    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++)
     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) */
     438    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)
    655456        {
    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];
     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 */
    665478                    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]);
    679479            }
    680480        }
    681481    }
    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  */
    693 int 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 
    766             /* Begin config. */
    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();
    843 
    844     return rc;
    845 }
    846 
    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  */
    853 int 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.
    910          */
    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     }
    945     else
    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 
     482    return VINF_SUCCESS;
     483}
    951484
    952485/**
     
    958491int VBoxNetDhcp::run(void)
    959492{
     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
    960500    /*
    961501     * The loop.
     
    1074614bool VBoxNetDhcp::handleDhcpReqDiscover(PCRTNETBOOTP pDhcpMsg, size_t cb)
    1075615{
    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;
     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;
    1094656}
    1095657
     
    1105667bool VBoxNetDhcp::handleDhcpReqRequest(PCRTNETBOOTP pDhcpMsg, size_t cb)
    1106668{
    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     }
     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);
    1193683    else
    1194     {
    1195         debugPrint(1, false, "NAK'ing DHCP_REQUEST");
    1196         makeDhcpReply(RTNET_DHCP_MT_NAC, NULL, pDhcpMsg, cb);
    1197     }
     684        rc = netManager->nak(session);
     685   
     686    AssertRCReturn(rc, false);
    1198687
    1199688    return true;
     
    1264753
    1265754/**
    1266  * Helper class for stuffing DHCP options into a reply packet.
    1267  */
    1268 class VBoxNetDhcpWriteCursor
    1269 {
    1270 private:
    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 
    1279 public:
    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  */
    1586 void 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  */
    1680 VBoxNetDhcpLease *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  */
    1707 VBoxNetDhcpLease *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  */
    1736 VBoxNetDhcpLease *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 *
    1827 VBoxNetDhcp::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
    1890 VBoxNetDhcp::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  */
    1914 inline 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     }
    1923 }
    1924 
    1925 
    1926 /**
    1927755 * Print debug message depending on the m_cVerbosity level.
    1928756 *
     
    1945773            &&  m_pCurMsg)
    1946774        {
     775            /* XXX: export this to debugPrinfDhcpMsg or variant and other method export
     776             *  to base class
     777             */
    1947778            const char *pszMsg = m_uCurMsgType != UINT8_MAX ? debugDhcpName(m_uCurMsgType) : "";
    1948779            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",
     
    2003834     * Instantiate the DHCP server and hand it the options.
    2004835     */
     836    HRESULT hrc = com::Initialize();
     837    Assert(!FAILED(hrc));
     838
    2005839    VBoxNetDhcp *pDhcp = new VBoxNetDhcp();
    2006840    if (!pDhcp)
     
    2012846    if (rc)
    2013847        return rc;
     848
     849    pDhcp->init();
    2014850
    2015851    /*
  • trunk/src/VBox/NetworkServices/NetLib/VBoxNetBaseService.cpp

    r45114 r46962  
    11/* $Id$ */
    22/** @file
    3  * VBoxNetDHCP - DHCP Service for connecting to IntNet.
     3 * VBoxNetBaseService - Base Service class for connecting to IntNet.
    44 */
    5 /** @todo r=bird: Cut&Past rules... Please fix DHCP refs! */
    65
    76/*
     
    2221#define LOG_GROUP LOG_GROUP_NET_SERVICE
    2322
     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
    2433#include <iprt/alloca.h>
    2534#include <iprt/buildconfig.h>
     
    3039#include <iprt/param.h>
    3140#include <iprt/path.h>
     41#include <iprt/process.h>
    3242#include <iprt/stream.h>
    3343#include <iprt/string.h>
    3444#include <iprt/time.h>
    3545#include <iprt/mem.h>
     46#include <iprt/message.h>
    3647
    3748#include <VBox/sup.h>
     
    4455#include <string>
    4556
     57#include <VBox/err.h>
    4658#include <VBox/log.h>
    4759
     
    5870*   Structures and Typedefs                                                    *
    5971*******************************************************************************/
     72
     73/*******************************************************************************
     74*   Global Variables                                                           *
     75*******************************************************************************/
     76/* Commonly used options for network configuration */
    6077static RTGETOPTDEF g_aGetOptDef[] =
    6178{
     
    6986    { "--verbose",        'v',   RTGETOPT_REQ_NOTHING },
    7087};
     88
     89
    7190VBoxNetBaseService::VBoxNetBaseService()
    7291{
    73   int rc = RTCritSectInit(&m_csThis);
    74   AssertRC(rc);
    75 }
     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
    76113VBoxNetBaseService::~VBoxNetBaseService()
    77114{
     
    99136}
    100137
     138
    101139int VBoxNetBaseService::init()
    102140{
    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]);
    114141    return VINF_SUCCESS;
    115142}
     143
     144
    116145/**
    117146 * Parse the arguments.
     
    188217
    189218            case 'h':
    190                 RTPrintf("VBoxNetDHCP Version %s\n"
     219                RTPrintf("%s Version %s\n"
    191220                         "(C) 2009-" VBOX_C_YEAR " " VBOX_VENDOR "\n"
    192221                         "All rights reserved.\n"
    193222                         "\n"
    194                          "Usage: VBoxNetDHCP <options>\n"
     223                         "Usage: %s <options>\n"
    195224                         "\n"
    196225                         "Options:\n",
     226                         RTProcShortName(),
     227                         RTProcShortName(),
     228                         RTProcShortName(),
    197229                         RTBldCfgVersion());
    198230                for (unsigned int i = 0; i < m_vecOptionDefs.size(); i++)
     
    215247    return rc;
    216248}
     249
    217250
    218251int VBoxNetBaseService::tryGoOnline(void)
     
    317350}
    318351
     352
    319353void VBoxNetBaseService::shutdown(void)
    320354{
    321355}
     356
    322357
    323358int VBoxNetBaseService::waitForIntNetEvent(int cMillis)
     
    377412}
    378413
     414
    379415/**
    380416 * Print debug message depending on the m_cVerbosity level.
    381417 *
    382418 * @param   iMinLevel       The minimum m_cVerbosity level for this 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  */
    387 inline 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.
     419 * @param   fMsg            Whether to dump parts for the current service message.
    404420 * @param   pszFmt          The message format string.
    405421 * @param   va              Optional arguments.
     
    411427        va_list vaCopy;                 /* This dude is *very* special, thus the copy. */
    412428        va_copy(vaCopy, va);
    413         RTStrmPrintf(g_pStdErr, "VBoxNetDHCP: %s: %N\n", iMinLevel >= 2 ? "debug" : "info", pszFmt, &vaCopy);
     429        RTStrmPrintf(g_pStdErr, "%s: %s: %N\n",
     430                     RTProcShortName(),
     431                     iMinLevel >= 2 ? "debug" : "info",
     432                     pszFmt,
     433                     &vaCopy);
    414434        va_end(vaCopy);
    415435    }
    416436
    417437}
     438
    418439
    419440PRTGETOPTDEF VBoxNetBaseService::getOptionsPtr()
  • trunk/src/VBox/NetworkServices/NetLib/VBoxNetBaseService.h

    r45114 r46962  
    1818#ifndef ___VBoxNetBaseService_h___
    1919#define ___VBoxNetBaseService_h___
     20
    2021#include <iprt/critsect.h>
    2122class VBoxNetBaseService
     
    3233    int                 sendBufferOnWire(PCINTNETSEG pSg, int cSg, size_t cbBuffer);
    3334    void                flushWire();
     35
    3436    virtual void        usage(void) = 0;
    35     virtual void        run(void) = 0;
    36     virtual int         init(void);
     37    virtual int         run(void) = 0;
    3738    virtual int         parseOpt(int rc, const RTGETOPTUNION& getOptVal) = 0;
    3839
    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;
    41 public:
     40    virtual int         init(void);
     41
     42    /* VirtualBox instance */
     43    ComPtr<IVirtualBox> virtualbox;
     44
     45protected:
     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
    4267    /** @name The server configuration data members.
    4368     * @{ */
     
    4974    RTNETADDRIPV4       m_Ipv4Address;
    5075    RTNETADDRIPV4       m_Ipv4Netmask;
    51     /* cs for syncing */
    52     RTCRITSECT          m_csThis;
    5376    /** @} */
    5477    /** @name The network interface
     
    6689private:
    6790    PRTGETOPTDEF getOptionsPtr();
     91
     92    /* cs for syncing */
     93    RTCRITSECT          m_csThis;
     94
    6895    /** @} */
    6996};
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