Changeset 17770 in vbox for trunk/src/VBox/NetworkServices/DHCP/VBoxNetDHCP.cpp
- Timestamp:
- Mar 12, 2009 6:13:04 PM (16 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/NetworkServices/DHCP/VBoxNetDHCP.cpp
r17691 r17770 29 29 * Header Files * 30 30 *******************************************************************************/ 31 #include <iprt/net.h> 31 32 #include <iprt/initterm.h> 32 #include <iprt/ net.h>33 #include <iprt/alloca.h> 33 34 #include <iprt/err.h> 34 35 #include <iprt/time.h> … … 47 48 #include <vector> 48 49 #include <string> 49 50 /** @Todo move these: */51 52 /** The requested address. */53 #define RTNET_DHCP_OPT_REQUESTED_ADDRESS 5054 55 /** The normal size of RTNETBOOTP::bp_vend::Dhcp::dhcp_opts. */56 #define RTNET_DHCP_OPT_SIZE (312 - 4)57 50 58 51 … … 92 85 /* * Option 11: Resource location server. */ 93 86 /* * Option 12: Host name. */ 94 //std::string<char>m_HostName;87 std::string m_HostName; 95 88 /* * Option 13: Boot file size option. */ 96 89 /* * Option 14: Merit dump file. */ 97 90 /** Option 15: Domain name. */ 98 std::string m_DomainName;91 std::string m_DomainName; 99 92 /* * Option 16: Swap server. */ 100 93 /* * Option 17: Root path. */ … … 139 132 /** Option 66: TFTP server name. */ 140 133 std::string m_TftpServer; 134 /** Address for the bp_siaddr field corresponding to m_TftpServer. */ 135 RTNETADDRIPV4 m_TftpServerAddr; 141 136 /** Option 67: Bootfile name. */ 142 137 std::string m_BootfileName; … … 261 256 std::string m_Network; 262 257 RTMAC m_MacAddress; 263 RTNETADDRIPV4 m_Ip Address;258 RTNETADDRIPV4 m_Ipv4Address; 264 259 /** @} */ 265 260 … … 347 342 m_MacAddress.au8[4] = 0x41; 348 343 m_MacAddress.au8[5] = 0x42; 349 m_Ip Address.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))); 350 345 351 346 m_pSession = NIL_RTR0PTR; … … 478 473 break; 479 474 case 'i': 480 m_Ip Address = Val.IPv4Addr;475 m_Ipv4Address = Val.IPv4Addr; 481 476 break; 482 477 … … 537 532 case 'V': 538 533 RTPrintf("%sr%d\n", VBOX_VERSION_STRING, VBOX_SVN_REV); 539 rc = 0; 540 break; 534 return 0; 541 535 542 536 case 'h': … … 548 542 " TODO\n", 549 543 VBOX_VERSION_STRING); 550 rc = 1; 551 break; 544 return 1; 552 545 553 546 default: … … 817 810 * make a new one and return NAC. 818 811 */ 819 RTNETADDRIPV4 820 if (findOptionIPv4Addr(RTNET_DHCP_OPT_REQ UESTED_ADDRESS, pDhcpMsg, cb, &IPv4Addr))812 RTNETADDRIPV4 IPv4Addr; 813 if (findOptionIPv4Addr(RTNET_DHCP_OPT_REQ_ADDR, pDhcpMsg, cb, &IPv4Addr)) 821 814 { 822 815 VBoxNetDhcpLease *pLease = findLeaseByIpv4AndMacAddresses(IPv4Addr, &pDhcpMsg->bp_chaddr.Mac); … … 935 928 936 929 /** 930 * Helper class for stuffing DHCP options into a reply packet. 931 */ 932 class VBoxNetDhcpWriteCursor 933 { 934 private: 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 942 public: 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 /** 937 1216 * Constructs and sends a reply to a client. 938 1217 * … … 946 1225 void VBoxNetDhcp::makeDhcpReply(uint8_t uMsgType, VBoxNetDhcpLease *pLease, PCRTNETBOOTP pDhcpMsg, size_t cb) 947 1226 { 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 949 1284 } 950 1285 … … 983 1318 * 984 1319 * @returns Pointer to the lease if found, NULL if not found. 985 * @param IPv4Addr 986 * @param pMacAddress 1320 * @param IPv4Addr The IPv4 address. 1321 * @param pMacAddress The mac address. 987 1322 */ 988 1323 VBoxNetDhcpLease *VBoxNetDhcp::findLeaseByIpv4AndMacAddresses(RTNETADDRIPV4 IPv4Addr, PCRTMAC pMacAddress) … … 1010 1345 * 1011 1346 * @returns Pointer to the lease if found, NULL+log if not found. 1012 * @param IPv4Addr 1013 * @param pMacAddress 1347 * @param IPv4Addr The IPv4 address. 1348 * @param pMacAddress The MAC address. 1014 1349 */ 1015 1350 VBoxNetDhcpLease *VBoxNetDhcp::newLease(PCRTNETBOOTP pDhcpMsg, size_t cb) 1016 1351 { 1017 1352 debugPrint(0, true, "newLease is not implemented"); 1018 1353 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 */ 1365 void VBoxNetDhcp::updateLeaseConfig(VBoxNetDhcpLease *pLease) 1366 { 1019 1367 } 1020 1368 … … 1045 1393 if (cb <= RT_UOFFSETOF(RTNETBOOTP, bp_vend.Dhcp.dhcp_opts)) 1046 1394 return NULL; 1047 if (pDhcpMsg->bp_vend.Dhcp.dhcp_cookie != RT NET_DHCP_COOKIE)1395 if (pDhcpMsg->bp_vend.Dhcp.dhcp_cookie != RT_H2N_U32_C(RTNET_DHCP_COOKIE)) 1048 1396 return NULL; 1049 1397 size_t cbLeft = cb - RT_UOFFSETOF(RTNETBOOTP, bp_vend.Dhcp.dhcp_opts);
Note:
See TracChangeset
for help on using the changeset viewer.