VirtualBox

Ignore:
Timestamp:
Mar 12, 2009 6:13:04 PM (16 years ago)
Author:
vboxsync
Message:

VBoxNetDhcp: more code.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/NetworkServices/DHCP/VBoxNetDHCP.cpp

    r17691 r17770  
    2929*   Header Files                                                               *
    3030*******************************************************************************/
     31#include <iprt/net.h>
    3132#include <iprt/initterm.h>
    32 #include <iprt/net.h>
     33#include <iprt/alloca.h>
    3334#include <iprt/err.h>
    3435#include <iprt/time.h>
     
    4748#include <vector>
    4849#include <string>
    49 
    50 /** @Todo move these:  */
    51 
    52 /** The requested address. */
    53 #define RTNET_DHCP_OPT_REQUESTED_ADDRESS    50
    54 
    55 /** The normal size of RTNETBOOTP::bp_vend::Dhcp::dhcp_opts.  */
    56 #define RTNET_DHCP_OPT_SIZE         (312 - 4)
    5750
    5851
     
    9285    /* * Option 11: Resource location server. */
    9386    /* * Option 12: Host name. */
    94     //std::string<char>           m_HostName;
     87    std::string                 m_HostName;
    9588    /* * Option 13: Boot file size option. */
    9689    /* * Option 14: Merit dump file. */
    9790    /** Option 15: Domain name. */
    98     std::string                m_DomainName;
     91    std::string                 m_DomainName;
    9992    /* * Option 16: Swap server. */
    10093    /* * Option 17: Root path. */
     
    139132    /** Option 66: TFTP server name. */
    140133    std::string                 m_TftpServer;
     134    /** Address for the bp_siaddr field corresponding to m_TftpServer. */
     135    RTNETADDRIPV4               m_TftpServerAddr;
    141136    /** Option 67: Bootfile name. */
    142137    std::string                 m_BootfileName;
     
    261256    std::string         m_Network;
    262257    RTMAC               m_MacAddress;
    263     RTNETADDRIPV4       m_IpAddress;
     258    RTNETADDRIPV4       m_Ipv4Address;
    264259    /** @} */
    265260
     
    347342    m_MacAddress.au8[4]     = 0x41;
    348343    m_MacAddress.au8[5]     = 0x42;
    349     m_IpAddress.u           = RT_H2N_U32_C(RT_BSWAP_U32_C(RT_MAKE_U32_FROM_U8( 10,  0,  2,  5)));
     344    m_Ipv4Address.u         = RT_H2N_U32_C(RT_BSWAP_U32_C(RT_MAKE_U32_FROM_U8( 10,  0,  2,  5)));
    350345
    351346    m_pSession              = NIL_RTR0PTR;
     
    478473                break;
    479474            case 'i':
    480                 m_IpAddress = Val.IPv4Addr;
     475                m_Ipv4Address = Val.IPv4Addr;
    481476                break;
    482477
     
    537532            case 'V':
    538533                RTPrintf("%sr%d\n", VBOX_VERSION_STRING, VBOX_SVN_REV);
    539                 rc = 0;
    540                 break;
     534                return 0;
    541535
    542536            case 'h':
     
    548542                         "  TODO\n",
    549543                         VBOX_VERSION_STRING);
    550                 rc = 1;
    551                 break;
     544                return 1;
    552545
    553546            default:
     
    817810     * make a new one and return NAC.
    818811     */
    819     RTNETADDRIPV4       IPv4Addr;
    820     if (findOptionIPv4Addr(RTNET_DHCP_OPT_REQUESTED_ADDRESS, pDhcpMsg, cb, &IPv4Addr))
     812    RTNETADDRIPV4 IPv4Addr;
     813    if (findOptionIPv4Addr(RTNET_DHCP_OPT_REQ_ADDR, pDhcpMsg, cb, &IPv4Addr))
    821814    {
    822815        VBoxNetDhcpLease *pLease = findLeaseByIpv4AndMacAddresses(IPv4Addr, &pDhcpMsg->bp_chaddr.Mac);
     
    935928
    936929/**
     930 * Helper class for stuffing DHCP options into a reply packet.
     931 */
     932class VBoxNetDhcpWriteCursor
     933{
     934private:
     935    uint8_t        *m_pbCur;       /**< The current cursor position. */
     936    uint8_t        *m_pbEnd;       /**< The end the current option space. */
     937    uint8_t        *m_pfOverload;  /**< Pointer to the flags of the overload option. */
     938    PRTNETDHCPOPT   m_pOpt;        /**< The current option. */
     939    PRTNETBOOTP     m_pDhcp;       /**< The DHCP packet. */
     940    bool            m_fOverflowed; /**< Set if we've overflowed, otherwise false. */
     941
     942public:
     943    /** Instantiate an option cursor for the specified DHCP message. */
     944    VBoxNetDhcpWriteCursor(PRTNETBOOTP pDhcp, size_t cbDhcp) :
     945        m_pbCur(&pDhcp->bp_vend.Dhcp.dhcp_opts[0]),
     946        m_pbEnd((uint8_t *)pDhcp + cbDhcp),
     947        m_pfOverload(NULL),
     948        m_pOpt(NULL),
     949        m_pDhcp(pDhcp),
     950        m_fOverflowed(false)
     951    {
     952        AssertPtr(pDhcp);
     953        Assert(cbDhcp > RT_UOFFSETOF(RTNETBOOTP, bp_vend.Dhcp.dhcp_opts[10]));
     954    }
     955
     956    /** Destructor.  */
     957    ~VBoxNetDhcpWriteCursor()
     958    {
     959        m_pbCur = m_pbEnd = m_pfOverload = NULL;
     960        m_pOpt = NULL;
     961        m_pDhcp = NULL;
     962    }
     963
     964    /**
     965     * Try overload more BOOTP fields
     966     */
     967    bool overloadMore(void)
     968    {
     969        /* switch option area. */
     970        uint8_t    *pbNew;
     971        uint8_t    *pbNewEnd;
     972        if (!m_pfOverload)
     973        {
     974            /* Add an overload option. */
     975            *m_pbCur++ = RTNET_DHCP_OPT_OPTION_OVERLOAD;
     976            *m_pbCur++ = 1;
     977            m_pfOverload = m_pbCur;
     978            *m_pbCur++ = 1;     /* bp_file flag */
     979
     980            pbNew      = &m_pDhcp->bp_file[0];
     981            pbNewEnd   = &m_pDhcp->bp_file[sizeof(m_pDhcp->bp_file)];
     982        }
     983        else if (!(*m_pfOverload & 2))
     984        {
     985            *m_pfOverload |= 2; /* bp_sname flag */
     986
     987            pbNew      = &m_pDhcp->bp_sname[0];
     988            pbNewEnd   = &m_pDhcp->bp_sname[sizeof(m_pDhcp->bp_sname)];
     989        }
     990        else
     991            return false;
     992
     993        /* pad current option field */
     994        while (m_pbCur != m_pbEnd)
     995            *m_pbCur++ = RTNET_DHCP_OPT_PAD; /** @todo not sure if this stuff is at all correct... */
     996
     997        m_pbCur = pbNew;
     998        m_pbEnd = pbNewEnd;
     999        return true;
     1000    }
     1001
     1002    /**
     1003     * Begin an option.
     1004     *
     1005     * @returns true on succes, false if we're out of space.
     1006     *
     1007     * @param   uOption     The option number.
     1008     * @param   cb          The amount of data.
     1009     */
     1010    bool begin(uint8_t uOption, size_t cb)
     1011    {
     1012        /* Check that the data of the previous option has all been written. */
     1013        Assert(   !m_pOpt
     1014               || (m_pbCur - m_pOpt->dhcp_len == (uint8_t *)(m_pOpt + 1)));
     1015        AssertMsg(cb <= 255, ("%#x\n", cb));
     1016
     1017        /* Check if we need to overload more stuff. */
     1018        if ((uintptr_t)(m_pbEnd - m_pbCur) < cb + 2 + 3)
     1019        {
     1020            m_pOpt = NULL;
     1021            if (!overloadMore())
     1022            {
     1023                m_fOverflowed = true;
     1024                AssertMsgFailedReturn(("%u %#x\n", uOption, cb), false);
     1025            }
     1026            if ((uintptr_t)(m_pbEnd - m_pbCur) < cb + 2 + 3)
     1027            {
     1028                m_fOverflowed = true;
     1029                AssertMsgFailedReturn(("%u %#x\n", uOption, cb), false);
     1030            }
     1031        }
     1032
     1033        /* Emit the option header. */
     1034        m_pOpt = (PRTNETDHCPOPT)m_pbCur;
     1035        m_pOpt->dhcp_opt = uOption;
     1036        m_pOpt->dhcp_len = cb;
     1037        m_pbCur += 2;
     1038        return true;
     1039    }
     1040
     1041    /**
     1042     * Puts option data.
     1043     *
     1044     * @param   pvData      The data.
     1045     * @param   cb          The amount to put.
     1046     */
     1047    void put(void const *pvData, size_t cb)
     1048    {
     1049        Assert(m_pOpt || m_fOverflowed);
     1050        if (RT_LIKELY(m_pOpt))
     1051        {
     1052            Assert((uintptr_t)m_pbCur - (uintptr_t)(m_pOpt + 1) + cb  <= (size_t)m_pOpt->dhcp_len);
     1053            memcpy(m_pbCur, pvData, cb);
     1054            m_pbCur += cb;
     1055        }
     1056    }
     1057
     1058    /**
     1059     * Puts an IPv4 Address.
     1060     *
     1061     * @param   IPv4Addr    The address.
     1062     */
     1063    void putIPv4Addr(RTNETADDRIPV4 IPv4Addr)
     1064    {
     1065        put(&IPv4Addr, 4);
     1066    }
     1067
     1068    /**
     1069     * Adds an IPv4 address option.
     1070     *
     1071     * @returns true/false just like begin().
     1072     *
     1073     * @param   uOption     The option number.
     1074     * @param   IPv4Addr    The address.
     1075     */
     1076    bool optIPv4Addr(uint8_t uOption, RTNETADDRIPV4 IPv4Addr)
     1077    {
     1078        if (!begin(uOption, 4))
     1079            return false;
     1080        putIPv4Addr(IPv4Addr);
     1081        return true;
     1082    }
     1083
     1084    /**
     1085     * Adds an option taking 1 or more IPv4 address.
     1086     *
     1087     * If the vector contains no addresses, the option will not be added.
     1088     *
     1089     * @returns true/false just like begin().
     1090     *
     1091     * @param   uOption     The option number.
     1092     * @param   rIPv4Addrs  Reference to the address vector.
     1093     */
     1094    bool optIPv4Addrs(uint8_t uOption, std::vector<RTNETADDRIPV4> const &rIPv4Addrs)
     1095    {
     1096        size_t const c = rIPv4Addrs.size();
     1097        if (!c)
     1098            return true;
     1099
     1100        if (!begin(uOption, 4*c))
     1101            return false;
     1102        for (size_t i = 0; i < c; i++)
     1103            putIPv4Addr(rIPv4Addrs[i]);
     1104        return true;
     1105    }
     1106
     1107    /**
     1108     * Puts an 8-bit integer.
     1109     *
     1110     * @param   u8          The integer.
     1111     */
     1112    void putU8(uint8_t u8)
     1113    {
     1114        put(&u8, 1);
     1115    }
     1116
     1117    /**
     1118     * Adds an 8-bit integer option.
     1119     *
     1120     * @returns true/false just like begin().
     1121     *
     1122     * @param   uOption     The option number.
     1123     * @param   u8          The integer
     1124     */
     1125    bool optU8(uint8_t uOption, uint8_t u8)
     1126    {
     1127        if (!begin(uOption, 1))
     1128            return false;
     1129        putU8(u8);
     1130        return true;
     1131    }
     1132
     1133    /**
     1134     * Puts an 32-bit integer (network endian).
     1135     *
     1136     * @param   u32Network  The integer.
     1137     */
     1138    void putU32(uint32_t u32)
     1139    {
     1140        put(&u32, 4);
     1141    }
     1142
     1143    /**
     1144     * Adds an 32-bit integer (network endian) option.
     1145     *
     1146     * @returns true/false just like begin().
     1147     *
     1148     * @param   uOption     The option number.
     1149     * @param   u32Network  The integer.
     1150     */
     1151    bool optU32(uint8_t uOption, uint32_t u32)
     1152    {
     1153        if (!begin(uOption, 4))
     1154            return false;
     1155        putU32(u32);
     1156        return true;
     1157    }
     1158
     1159    /**
     1160     * Puts a std::string.
     1161     *
     1162     * @param   rStr        Reference to the string.
     1163     */
     1164    void putStr(std::string const &rStr)
     1165    {
     1166        put(rStr.c_str(), rStr.size());
     1167    }
     1168
     1169    /**
     1170     * Adds an std::string option if the string isn't empty.
     1171     *
     1172     * @returns true/false just like begin().
     1173     *
     1174     * @param   uOption     The option number.
     1175     * @param   rStr        Reference to the string.
     1176     */
     1177    bool optStr(uint8_t uOption, std::string const &rStr)
     1178    {
     1179        const size_t cch = rStr.size();
     1180        if (!cch)
     1181            return true;
     1182
     1183        if (!begin(uOption, cch))
     1184            return false;
     1185        put(rStr.c_str(), cch);
     1186        return true;
     1187    }
     1188
     1189    /**
     1190     * Whether we've overflowed.
     1191     *
     1192     * @returns true on overflow, false otherwise.
     1193     */
     1194    bool hasOverflowed(void) const
     1195    {
     1196        return m_fOverflowed;
     1197    }
     1198
     1199    /**
     1200     * Adds the terminating END option.
     1201     *
     1202     * The END will always be added as we're reserving room for it, however, we
     1203     * might've dropped previous options due to overflows and that is what the
     1204     * return status indicates.
     1205     *
     1206     * @returns true on success, false on a (previous) overflow.
     1207     */
     1208    bool optEnd(void)
     1209    {
     1210        return hasOverflowed();
     1211    }
     1212};
     1213
     1214
     1215/**
    9371216 * Constructs and sends a reply to a client.
    9381217 *
     
    9461225void VBoxNetDhcp::makeDhcpReply(uint8_t uMsgType, VBoxNetDhcpLease *pLease, PCRTNETBOOTP pDhcpMsg, size_t cb)
    9471226{
    948     /** @todo this is required. :-) */
     1227    size_t      cbReply = RTNET_DHCP_NORMAL_SIZE; /** @todo respect the RTNET_DHCP_OPT_MAX_DHCP_MSG_SIZE option */
     1228    PRTNETBOOTP pReply = (PRTNETBOOTP)alloca(cbReply);
     1229
     1230    /*
     1231     * The fixed bits stuff.
     1232     */
     1233    pReply->bp_op     = RTNETBOOTP_OP_REPLY;
     1234    pReply->bp_htype  = RTNET_ARP_ETHER;
     1235    pReply->bp_hlen   = sizeof(RTMAC);
     1236    pReply->bp_hops   = 0;
     1237    pReply->bp_xid    = pDhcpMsg->bp_xid;
     1238    pReply->bp_secs   = 0;
     1239    pReply->bp_flags  = 0; // (pDhcpMsg->bp_flags & RTNET_DHCP_FLAGS_NO_BROADCAST); ??
     1240    pReply->bp_ciaddr.u = 0;
     1241    pReply->bp_yiaddr.u = pLease ? pLease->m_IPv4Address.u : 0xffffffff;
     1242    pReply->bp_siaddr.u = pLease && pLease->m_pCfg ? pLease->m_pCfg->m_TftpServerAddr.u : 0;
     1243    pReply->bp_giaddr.u = 0;
     1244    memset(&pReply->bp_chaddr, '\0', sizeof(pReply->bp_chaddr));
     1245    pReply->bp_chaddr.Mac = pDhcpMsg->bp_chaddr.Mac;
     1246    memset(&pReply->bp_sname[0], '\0', sizeof(pReply->bp_sname));
     1247    memset(&pReply->bp_file[0],  '\0', sizeof(pReply->bp_file));
     1248    pReply->bp_vend.Dhcp.dhcp_cookie = RT_H2N_U32_C(RTNET_DHCP_COOKIE);
     1249    memset(&pReply->bp_vend.Dhcp.dhcp_opts[0], '\0', RTNET_DHCP_OPT_SIZE);
     1250
     1251    /*
     1252     * The options - use a cursor class for dealing with the ugly stuff.
     1253     */
     1254    VBoxNetDhcpWriteCursor Cursor(pReply, cbReply);
     1255
     1256    /* The basics */
     1257    Cursor.optU8(RTNET_DHCP_OPT_MSG_TYPE, uMsgType);
     1258    Cursor.optIPv4Addr(RTNET_DHCP_OPT_SERVER_ID, m_Ipv4Address);
     1259
     1260    if (uMsgType != RTNET_DHCP_MT_NAC)
     1261    {
     1262        AssertReturnVoid(pLease && pLease->m_pCfg);
     1263        const VBoxNetDhcpCfg *pCfg = pLease->m_pCfg; /* no need to retain it. */
     1264
     1265        /* The IP config. */
     1266        Cursor.optU32(RTNET_DHCP_OPT_LEASE_TIME, RT_H2N_U32(pCfg->m_cSecLease));
     1267        Cursor.optIPv4Addr(RTNET_DHCP_OPT_SUBNET_MASK, pCfg->m_SubnetMask);
     1268        Cursor.optIPv4Addrs(RTNET_DHCP_OPT_ROUTERS, pCfg->m_Routers);
     1269        Cursor.optIPv4Addrs(RTNET_DHCP_OPT_ROUTERS, pCfg->m_DNSes);
     1270        Cursor.optStr(RTNET_DHCP_OPT_HOST_NAME, pCfg->m_HostName);
     1271        Cursor.optStr(RTNET_DHCP_OPT_DOMAIN_NAME, pCfg->m_DomainName);
     1272
     1273        /* The PXE config. */
     1274    }
     1275
     1276    /* Terminate the options. */
     1277    if (!Cursor.optEnd())
     1278        debugPrint(0, true, "option overflow\n");
     1279
     1280    /*
     1281     * Send it.
     1282     */
     1283
    9491284}
    9501285
     
    9831318 *
    9841319 * @returns Pointer to the lease if found, NULL if not found.
    985  * @param   IPv4Addr                The IPv4 address.
    986  * @param   pMacAddress             The mac address.
     1320 * @param   IPv4Addr        The IPv4 address.
     1321 * @param   pMacAddress     The mac address.
    9871322 */
    9881323VBoxNetDhcpLease *VBoxNetDhcp::findLeaseByIpv4AndMacAddresses(RTNETADDRIPV4 IPv4Addr, PCRTMAC pMacAddress)
     
    10101345 *
    10111346 * @returns Pointer to the lease if found, NULL+log if not found.
    1012  * @param   IPv4Addr                The IPv4 address.
    1013  * @param   pMacAddress             The MAC address.
     1347 * @param   IPv4Addr        The IPv4 address.
     1348 * @param   pMacAddress     The MAC address.
    10141349 */
    10151350VBoxNetDhcpLease *VBoxNetDhcp::newLease(PCRTNETBOOTP pDhcpMsg, size_t cb)
    10161351{
    1017 
     1352    debugPrint(0, true, "newLease is not implemented");
    10181353    return NULL;
     1354}
     1355
     1356
     1357/**
     1358 * Updates the configuration of the lease in question.
     1359 *
     1360 * @todo it's possible that we'll simplify this stuff by expanding all the
     1361 *       possible leases when loading the config instead in newLease()...
     1362 *
     1363 * @param   pLease          The lease.
     1364 */
     1365void VBoxNetDhcp::updateLeaseConfig(VBoxNetDhcpLease *pLease)
     1366{
    10191367}
    10201368
     
    10451393    if (cb <= RT_UOFFSETOF(RTNETBOOTP, bp_vend.Dhcp.dhcp_opts))
    10461394        return NULL;
    1047     if (pDhcpMsg->bp_vend.Dhcp.dhcp_cookie != RTNET_DHCP_COOKIE)
     1395    if (pDhcpMsg->bp_vend.Dhcp.dhcp_cookie != RT_H2N_U32_C(RTNET_DHCP_COOKIE))
    10481396        return NULL;
    10491397    size_t cbLeft = cb - RT_UOFFSETOF(RTNETBOOTP, bp_vend.Dhcp.dhcp_opts);
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