Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2272 lines
83 KiB

  1. #include "precomp.h"
  2. #ifdef H_ONLY
  3. //================================================================================
  4. // Copyright (C) 1997 Microsoft Corporation
  5. // Author: RameshV
  6. // Description: these are the exported dhcp client api function definitions
  7. //================================================================================
  8. #ifndef APIAPPL_H_INCLUDED
  9. #define APIAPPL_H_INCLUDED
  10. #ifndef DHCPAPI_PARAMS_DEFINED
  11. #define DHCPAPI_PARAMS_DEFINED
  12. typedef struct _DHCPAPI_PARAMS { // use this structure to request params
  13. ULONG Flags; // for future use
  14. ULONG OptionId; // what option is this?
  15. BOOL IsVendor; // is this vendor specific?
  16. LPBYTE Data; // the actual data
  17. DWORD nBytesData; // how many bytes of data are there in Data?
  18. } DHCPAPI_PARAMS, *PDHCPAPI_PARAMS, *LPDHCPAPI_PARAMS;
  19. #endif DHCPAPI_PARAMS_DEFINED
  20. DWORD // win32 status
  21. DhcpAcquireParameters( // acquire/renew a lease
  22. IN LPWSTR AdapterName // adapter to acquire lease on
  23. );
  24. DWORD // win32 status
  25. DhcpAcquireParametersByBroadcast( // acquire/renew a lease
  26. IN LPWSTR AdapterName // adapter to acquire lease on
  27. );
  28. DWORD // win32 status
  29. DhcpFallbackRefreshParams( // refresh fallback params
  30. IN LPWSTR AdapterName // adapter to be refreshed
  31. );
  32. DWORD // win32 status
  33. DhcpReleaseParameters( // release an existing lease
  34. IN LPWSTR AdapterName // adpater to release lease for
  35. );
  36. DWORD // win32 status
  37. DhcpEnableDynamicConfic( // convert from static to dhcp
  38. IN LPWSTR AdapterName // convert for this adapter
  39. );
  40. DWORD // win32 status
  41. DhcpDisableDynamicConfig( // convert from dhcp to static
  42. IN LPWSTR AdapterName // convert this adapter
  43. );
  44. DWORD // win32 status
  45. DhcpReRegisterDynDns( // reregister static address with dns
  46. IN LPWSTR AdapterName
  47. );
  48. DWORD // win32 status
  49. APIENTRY
  50. DhcpRequestParams( // request parameters of client
  51. IN LPWSTR AdapterName, // adapter name to request for
  52. IN LPBYTE ClassId, // byte stream of class id to use
  53. IN DWORD ClassIdLen, // # of bytes of class id to use
  54. IN PDHCPAPI_PARAMS SendParams, // parameters to send to server
  55. IN DWORD nSendParams, // size of above array
  56. IN DWORD Flags, // must be zero, reserved
  57. IN OUT PDHCPAPI_PARAMS RecdParams, // fill this array with received params
  58. IN OUT LPDWORD pnRecdParamsBytes // i/p: size of above in BYTES, o/p required bytes or filled up # of elements
  59. ); // returns ERROR_MORE_DATA if o/p buffer is of insufficient size, and fills in reqd size in # of bytes
  60. DWORD // win32 status
  61. DhcpRegisterParameterChangeNotification( // notify if a parameter has changed
  62. IN LPWSTR AdapterName, // adapter of interest
  63. IN LPBYTE ClassId, // byte stream of class id to use
  64. IN DWORD ClassIdLen, // # of bytes of class id
  65. IN PDHCPAPI_PARAMS Params, // params of interest
  66. IN DWORD nParams, // # of elts in above array
  67. IN DWORD Flags, // must be zero, reserved
  68. IN OUT PHANDLE hEvent // handle to event that will be SetEvent'ed in case of param change
  69. );
  70. DhcpDeRegisterParameterChangeNotification( // undo the registration
  71. IN HANDLE Event // handle to event returned by DhcpRegisterParameterChangeNotification, NULL ==> everything
  72. );
  73. DWORD // win32 status
  74. DhcpPersistentRequestParams( // parameters to request persistently
  75. IN LPWSTR AdapterName, // adapter name to request for
  76. IN LPBYTE ClassId, // byte stream of class id to use
  77. IN DWORD ClassIdLen, // # of bytes of class id
  78. IN PDHCPAPI_PARAMS SendParams, // persistent parameters
  79. IN DWORD nSendParams, // size of above array
  80. IN DWORD Flags, // must be zero, reserved
  81. IN LPWSTR AppName, // the name of the app that is to be used for this instance
  82. IN OUT LPDWORD UniqueId // OPTIONAL, return value is id that can be used in DhcpDelPersistentRequestParams
  83. );
  84. DWORD // win32 status
  85. DhcpDelPersistentRequestParams( // undo the effect of a persistent request -- currently undo from registry
  86. IN LPWSTR AdapterName, // the name of the adpater to delete for
  87. IN LPWSTR AppName, // the name used by the app
  88. IN DWORD UniqueId // something for this instance
  89. );
  90. #endif APIAPPL_H_INCLUDED
  91. #else H_ONLY
  92. #include <apiargs.h>
  93. #include <apistub.h>
  94. #include <apiimpl.h>
  95. #include <apiappl.h>
  96. #include <dhcploc.h>
  97. #include <dhcppro.h>
  98. #include <dhcpcsdk.h>
  99. DWORD INLINE // win32 status
  100. DhcpApiFillBuffer( // fill the buffer with some params
  101. IN OUT LPBYTE Buffer, // the buffer to fill
  102. IN DWORD MaxBufferSize, // the max size of buffer allwoed
  103. IN LPWSTR AdapterName, // fill in adapter name
  104. IN BYTE OpCode // what opcode to use?
  105. ) {
  106. DWORD Size;
  107. if( NULL == AdapterName ) Size = 0;
  108. else Size = (wcslen(AdapterName)+1)*sizeof(WCHAR);
  109. return DhcpApiArgAdd( // fill in the buffer with the reqd options
  110. Buffer,
  111. MaxBufferSize,
  112. OpCode,
  113. Size,
  114. (LPBYTE)AdapterName
  115. );
  116. }
  117. DWORD INLINE // win32 status
  118. DhcpAdapterOnlyApi( // execute apis that take only adapter name params
  119. IN LPWSTR AdapterName, // the adapter name
  120. IN BYTE OpCode
  121. )
  122. {
  123. LPBYTE Buffer;
  124. LPBYTE Buffer2;
  125. DWORD BufSize;
  126. DWORD Size;
  127. DWORD Error;
  128. BufSize = 0;
  129. Error = DhcpApiFillBuffer((LPBYTE)&BufSize, sizeof(BufSize), AdapterName, OpCode);
  130. DhcpAssert( ERROR_SUCCESS != Error );
  131. if( ERROR_MORE_DATA != Error ) return Error;
  132. DhcpAssert(BufSize);
  133. BufSize = ntohl(BufSize) + 2*sizeof(DWORD);
  134. Buffer = DhcpAllocateMemory(BufSize);
  135. if( NULL == Buffer ) return ERROR_NOT_ENOUGH_MEMORY;
  136. *(DWORD UNALIGNED *)Buffer = htonl(0);
  137. Buffer2 = Buffer + sizeof(DWORD);
  138. *(DWORD UNALIGNED *)Buffer2 = 0;
  139. BufSize -= sizeof(DWORD);
  140. Error = DhcpApiFillBuffer(Buffer2, BufSize, AdapterName, OpCode);
  141. Size = 0;
  142. if( ERROR_SUCCESS == Error ) Error = ExecuteApiRequest(Buffer, NULL, &Size);
  143. DhcpFreeMemory(Buffer);
  144. return Error;
  145. }
  146. DWORD // win32 status
  147. DhcpAcquireParameters( // acquire/renew a lease
  148. IN LPWSTR AdapterName // adapter to acquire lease on
  149. ) {
  150. return DhcpAdapterOnlyApi(AdapterName, AcquireParametersOpCode);
  151. }
  152. DWORD // win32 status
  153. DhcpAcquireParametersByBroadcast( // acquire/renew a lease
  154. IN LPWSTR AdapterName // adapter to acquire lease on
  155. ) {
  156. return DhcpAdapterOnlyApi(AdapterName, AcquireParametersByBroadcastOpCode);
  157. }
  158. DWORD // win32 status
  159. DhcpFallbackRefreshParams( // refresh fallback params
  160. IN LPWSTR AdapterName // adapter to be refreshed
  161. )
  162. {
  163. return DhcpAdapterOnlyApi(AdapterName, FallbackParamsOpCode);
  164. }
  165. DWORD // win32 status
  166. DhcpReleaseParameters( // release an existing lease
  167. IN LPWSTR AdapterName // adpater to release lease for
  168. ) {
  169. return DhcpAdapterOnlyApi(AdapterName, ReleaseParametersOpCode);
  170. }
  171. DWORD // win32 status
  172. DhcpEnableDynamicConfig( // convert from static to dhcp
  173. IN LPWSTR AdapterName // convert for this adapter
  174. ) {
  175. return DhcpAdapterOnlyApi(AdapterName, EnableDhcpOpCode);
  176. }
  177. DWORD // win32 status
  178. DhcpDisableDynamicConfig( // convert from dhcp to static
  179. IN LPWSTR AdapterName // convert this adapter
  180. ) {
  181. return DhcpAdapterOnlyApi(AdapterName, DisableDhcpOpCode);
  182. }
  183. DWORD // win32 status
  184. DhcpStaticRefreshParamsInternal( // refresh some static parameters that have changed
  185. IN LPWSTR AdapterName,
  186. IN BOOL fDoDns
  187. )
  188. {
  189. LPBYTE Buffer, Buffer2;
  190. DWORD BufSize, Size, Error, Code;
  191. BufSize = 0;
  192. Error = DhcpApiFillBuffer(
  193. (LPBYTE)&BufSize, sizeof(BufSize), AdapterName, StaticRefreshParamsOpCode
  194. );
  195. if( ERROR_MORE_DATA != Error ) return Error;
  196. DhcpAssert( BufSize );
  197. BufSize = ntohl(BufSize) + 2 * sizeof(DWORD);
  198. BufSize += 3*sizeof(DWORD);
  199. Buffer = DhcpAllocateMemory( BufSize );
  200. if( NULL == Buffer ) return ERROR_NOT_ENOUGH_MEMORY;
  201. *(DWORD*)Buffer = 0;
  202. Buffer2 = Buffer + sizeof(DWORD);
  203. *(DWORD*)Buffer2 = 0;
  204. BufSize -= sizeof(DWORD);
  205. Error = DhcpApiFillBuffer(
  206. Buffer2, BufSize, AdapterName, StaticRefreshParamsOpCode
  207. );
  208. DhcpAssert( ERROR_SUCCESS == Error );
  209. Code = (fDoDns ? 0x00 : 0x01);
  210. Error = DhcpApiArgAdd(
  211. Buffer2, BufSize, (BYTE)FlagsParam, sizeof(DWORD), (LPBYTE)&Code
  212. );
  213. DhcpAssert( ERROR_SUCCESS == Error );
  214. Size = 0;
  215. Error = ExecuteApiRequest(Buffer, NULL, &Size);
  216. DhcpFreeMemory( Buffer );
  217. return Error;
  218. }
  219. DWORD
  220. DhcpStaticRefreshParams(
  221. IN LPWSTR AdapterName
  222. )
  223. {
  224. return DhcpStaticRefreshParamsInternal(AdapterName, TRUE );
  225. }
  226. #if 0
  227. // pl dont use this api, use DhcpRequestParams instead.
  228. DWORD // win32 status
  229. DhcpRequestOptions( // request for specific options
  230. IN LPWSTR AdapterName, // which adapter's info is needed
  231. IN LPBYTE RequestedOpt, // list of requested options
  232. IN DWORD nRequestedOpts,// size of above BYTE array
  233. OUT LPBYTE *OptData, // the data for each available option
  234. IN OUT LPDWORD OptDataSize, // # of bytes of above byte array
  235. OUT LPBYTE *AvailOpts, // the list of available options
  236. IN OUT LPDWORD nAvailOpts // # of available options
  237. ) {
  238. PDHCP_API_ARGS DhcpApiArgs;
  239. CHAR TmpBuf[OPTION_END+1];
  240. LPBYTE OutBuf;
  241. LPBYTE InBuf;
  242. LPBYTE Buffer;
  243. LPBYTE Endp;
  244. LPBYTE RetOptList;
  245. LPBYTE RetDataList;
  246. DWORD Size;
  247. DWORD OutBufSize;
  248. DWORD InBufSize;
  249. DWORD i;
  250. DWORD nArgsReturned;
  251. DWORD Error;
  252. BOOL Tmp;
  253. // check parameter consistency
  254. if( NULL == AdapterName || NULL == RequestedOpt || 0 == nRequestedOpts )
  255. return ERROR_INVALID_PARAMETER;
  256. if( NULL == AvailOpts || 0 == nAvailOpts || NULL == OptData || 0 == OptDataSize )
  257. return ERROR_INVALID_PARAMETER;
  258. if( nRequestedOpts >= OPTION_END ) return ERROR_NO_SYSTEM_RESOURCES;
  259. // initialize out params
  260. (*nAvailOpts) = (*OptDataSize) = 0;
  261. (*AvailOpts) = (*OptData) = NULL;
  262. // calculate input buffer size for ONE option to be sent and allocate it
  263. InBufSize = 0;
  264. InBufSize += sizeof(DWORD)*2; // INBUF_SIZE, OUTBUF_SIZE
  265. InBufSize += sizeof(BYTE)+sizeof(DWORD)+(1+wcslen(AdapterName))*sizeof(WCHAR);
  266. InBufSize += sizeof(BYTE)+sizeof(DWORD)+nRequestedOpts+sizeof(BYTE);
  267. InBuf = DhcpAllocateMemory(InBufSize);
  268. if( NULL == InBuf ) return ERROR_NOT_ENOUGH_MEMORY;
  269. // intialize ptrs
  270. OutBufSize = 0; OutBuf = NULL;
  271. DhcpApiArgs = NULL;
  272. RetOptList = RetDataList = NULL;
  273. // now fill the input buffer
  274. ((DWORD UNALIGNED*)InBuf)[0] = htonl(OutBufSize);
  275. ((DWORD UNALIGNED*)InBuf)[1] = 0;
  276. Buffer = InBuf + sizeof(DWORD); InBufSize -= sizeof(DWORD);
  277. Error = DhcpApiFillBuffer(Buffer, InBufSize, AdapterName, RequestParamsOpCode);
  278. DhcpAssert(ERROR_SUCCESS == Error);
  279. TmpBuf[0] = (BYTE)OPTION_PARAMETER_REQUEST_LIST;
  280. memcpy(&TmpBuf[1], RequestedOpt, nRequestedOpts);
  281. Error = DhcpApiArgAdd(Buffer, InBufSize, NormalOptionParam, nRequestedOpts+1, TmpBuf);
  282. DhcpAssert(ERROR_SUCCESS == Error);
  283. Error = ExecuteApiRequest(InBuf, NULL, &OutBufSize);
  284. if( ERROR_SUCCESS == Error ) {
  285. DhcpAssert(0 == OutBufSize);
  286. goto Cleanup;
  287. }
  288. if( ERROR_MORE_DATA != Error ) goto Cleanup; // ERROR_MORE_DATA ==> need to allocate buffer
  289. DhcpPrint((DEBUG_OPTIONS, "RequestOptions: retrying with buffer size [%ld]\n", OutBufSize));
  290. DhcpAssert(OutBufSize);
  291. OutBuf = DhcpAllocateMemory(OutBufSize);
  292. if( NULL == OutBuf) {
  293. Error = ERROR_NOT_ENOUGH_MEMORY;
  294. goto Cleanup;
  295. }
  296. ((DWORD UNALIGNED*)InBuf)[0] = htonl(OutBufSize);
  297. Error = ExecuteApiRequest(InBuf, OutBuf, &OutBufSize);
  298. DhcpAssert(ERROR_MORE_DATA != Error); // can happen, just hope it does not...
  299. if( ERROR_SUCCESS != Error ) goto Cleanup; // unexpected error
  300. nArgsReturned = 0;
  301. DhcpApiArgs = NULL;
  302. Error = DhcpApiArgDecode(OutBuf, OutBufSize, DhcpApiArgs, &nArgsReturned );
  303. if( ERROR_MORE_DATA != Error ) goto Cleanup;
  304. DhcpAssert(nArgsReturned);
  305. if( 0 == nArgsReturned ) goto Cleanup; // no options sent? funny.. still, quit its
  306. DhcpApiArgs = DhcpAllocateMemory(sizeof(DHCP_API_ARGS)*nArgsReturned);
  307. if( NULL == DhcpApiArgs ) {
  308. Error = ERROR_NOT_ENOUGH_MEMORY;
  309. goto Cleanup;
  310. }
  311. nArgsReturned = 0;
  312. Error = DhcpApiArgDecode(OutBuf, OutBufSize, DhcpApiArgs, &nArgsReturned);
  313. if( ERROR_SUCCESS != Error ) {
  314. DhcpAssert(FALSE);
  315. goto Cleanup;
  316. }
  317. DhcpAssert(nArgsReturned);
  318. RetOptList = DhcpAllocateMemory(nArgsReturned);
  319. if( NULL == RetOptList ) {
  320. Error = ERROR_NOT_ENOUGH_MEMORY;
  321. goto Cleanup;
  322. }
  323. Size = 0;
  324. for( i = 0; i < nArgsReturned; i ++ ) {
  325. DhcpAssert(DhcpApiArgs[i].ArgId == NormalOptionParam);
  326. if( DhcpApiArgs[i].ArgId != NormalOptionParam ) continue;
  327. DhcpAssert(DhcpApiArgs[i].ArgSize <= OPTION_END +1 );
  328. if( DhcpApiArgs[i].ArgSize <= 1 ) continue;
  329. Size += DhcpApiArgs[i].ArgSize;
  330. }
  331. RetDataList = DhcpAllocateMemory(Size);
  332. if( NULL == RetDataList ) {
  333. Error = ERROR_NOT_ENOUGH_MEMORY;
  334. goto Cleanup;
  335. }
  336. Size = 0;
  337. for(i = 0; i < nArgsReturned; i ++ ) {
  338. if( DhcpApiArgs[i].ArgId != NormalOptionParam ) continue;
  339. if( DhcpApiArgs[i].ArgSize <= 1 ) continue;
  340. RetOptList[i] = DhcpApiArgs[i].ArgVal[0];
  341. RetDataList[Size++] = (BYTE)(DhcpApiArgs[i].ArgSize - 1);
  342. memcpy(&RetDataList[Size], DhcpApiArgs[i].ArgVal, DhcpApiArgs[i].ArgSize - 1);
  343. Size += DhcpApiArgs[i].ArgSize - 1;
  344. }
  345. (*AvailOpts) = RetOptList;
  346. (*nAvailOpts) = nArgsReturned;
  347. (*OptData) = RetDataList;
  348. (*OptDataSize) = Size;
  349. DhcpFreeMemory(InBuf);
  350. DhcpFreeMemory(OutBuf);
  351. DhcpFreeMemory(DhcpApiArgs);
  352. return ERROR_SUCCESS;
  353. Cleanup:
  354. if( InBuf ) DhcpFreeMemory(InBuf);
  355. if( OutBuf ) DhcpFreeMemory(OutBuf);
  356. if( DhcpApiArgs ) DhcpFreeMemory(DhcpApiArgs);
  357. if( RetDataList ) DhcpFreeMemory(RetDataList);
  358. if( RetOptList) DhcpFreeMemory(RetOptList);
  359. return Error;
  360. }
  361. #endif
  362. // pl dont use this api, use DhcpRequestParams instead.
  363. DWORD // win32 status
  364. DhcpRequestOptions( // request for specific options
  365. IN LPWSTR AdapterName, // which adapter's info is needed
  366. IN LPBYTE RequestedOpt, // list of requested options
  367. IN DWORD nRequestedOpts,// size of above BYTE array
  368. OUT LPBYTE *OptData, // the data for each available option
  369. IN OUT LPDWORD OptDataSize, // # of bytes of above byte array
  370. OUT LPBYTE *AvailOpts, // the list of available options
  371. IN OUT LPDWORD nAvailOpts // # of available options
  372. ) {
  373. DHCPAPI_PARAMS SendParams;
  374. PDHCPAPI_PARAMS RecdParams;
  375. LPBYTE RetDataList;
  376. LPBYTE RetOptList;
  377. DWORD nRecdParams;
  378. DWORD Error;
  379. DWORD i;
  380. DWORD OutBufSize;
  381. // check parameter consistency
  382. if( NULL == AdapterName || NULL == RequestedOpt || 0 == nRequestedOpts )
  383. return ERROR_INVALID_PARAMETER;
  384. if( NULL == AvailOpts || 0 == nAvailOpts || NULL == OptData || 0 == OptDataSize )
  385. return ERROR_INVALID_PARAMETER;
  386. if( nRequestedOpts >= OPTION_END ) return ERROR_NO_SYSTEM_RESOURCES;
  387. // initialize out params
  388. (*nAvailOpts) = (*OptDataSize) = 0;
  389. (*AvailOpts) = (*OptData) = NULL;
  390. // try to process this request
  391. SendParams.OptionId = (BYTE)OPTION_PARAMETER_REQUEST_LIST;
  392. SendParams.IsVendor = FALSE;
  393. SendParams.Data = RequestedOpt;
  394. SendParams.nBytesData = nRequestedOpts;
  395. nRecdParams = 0;
  396. Error = DhcpRequestParameters(
  397. AdapterName,
  398. NULL,
  399. 0,
  400. &SendParams,
  401. 1,
  402. 0,
  403. NULL,
  404. &nRecdParams
  405. );
  406. if( ERROR_MORE_DATA != Error ) return Error;
  407. while ( TRUE ) {
  408. DhcpAssert(nRecdParams);
  409. DhcpPrint((DEBUG_OPTIONS, "RequestOptions: require: 0x%lx bytes\n", nRecdParams));
  410. RecdParams = DhcpAllocateMemory(nRecdParams);
  411. if( NULL == RecdParams ) return ERROR_NOT_ENOUGH_MEMORY;
  412. Error = DhcpRequestParameters(
  413. AdapterName,
  414. NULL,
  415. 0,
  416. &SendParams,
  417. 1,
  418. 0,
  419. RecdParams,
  420. &nRecdParams
  421. );
  422. // DhcpAssert(ERROR_MORE_DATA != Error);
  423. if( ERROR_SUCCESS != Error ) {
  424. DhcpPrint((DEBUG_ERRORS, "RequestOptions:RequestParams:0x%lx\n", Error));
  425. DhcpFreeMemory(RecdParams);
  426. if( ERROR_MORE_DATA == Error ) continue;
  427. return Error;
  428. }
  429. break;
  430. }
  431. if( 0 == nRecdParams ) return ERROR_SUCCESS;
  432. DhcpPrint((DEBUG_OPTIONS, "Received 0x%lx options\n", nRecdParams));
  433. RetOptList = NULL;
  434. RetDataList = NULL;
  435. OutBufSize = 0;
  436. for( i = 0; i < nRecdParams; i ++ ) {
  437. DhcpPrint((DEBUG_TRACE, "Received option 0x%lx, 0x%lx bytes\n",
  438. RecdParams[i].OptionId, RecdParams[i].nBytesData));
  439. OutBufSize += RecdParams[i].nBytesData + sizeof(BYTE);
  440. }
  441. RetOptList = DhcpAllocateMemory(nRecdParams);
  442. RetDataList = DhcpAllocateMemory(OutBufSize);
  443. if( NULL == RetOptList || NULL == RetDataList ) {
  444. if( RetOptList ) DhcpFreeMemory(RetOptList);
  445. if( RetDataList ) DhcpFreeMemory(RetDataList);
  446. if( RecdParams ) DhcpFreeMemory(RecdParams);
  447. return ERROR_NOT_ENOUGH_MEMORY;
  448. }
  449. OutBufSize = 0;
  450. for( i = 0; i < nRecdParams ; i ++ ) {
  451. RetOptList[i] = (BYTE)RecdParams[i].OptionId;
  452. RetDataList[OutBufSize++] = (BYTE)RecdParams[i].nBytesData;
  453. memcpy(&RetDataList[OutBufSize], RecdParams[i].Data, RecdParams[i].nBytesData);
  454. OutBufSize += RecdParams[i].nBytesData;
  455. }
  456. (*AvailOpts) = RetOptList;
  457. (*nAvailOpts) = nRecdParams;
  458. (*OptData) = RetDataList;
  459. (*OptDataSize) = OutBufSize;
  460. if( RecdParams ) DhcpFreeMemory(RecdParams);
  461. return ERROR_SUCCESS;
  462. }
  463. DWORD // win32 status
  464. DhcpRequestParamsInternalEx( // request parameters of client
  465. IN BYTE OpCodeParam, // opcode to use
  466. IN LPWSTR AdapterName, // adapter name to request for
  467. IN LPBYTE ClassId, // byte stream of class id to use
  468. IN DWORD ClassIdLen, // # of bytes of class id to use
  469. IN PDHCPAPI_PARAMS SendParams, // parameters to send to server
  470. IN DWORD nSendParams, // size of above array
  471. IN DWORD Flags, // must be zero, reserved
  472. IN OUT PDHCPAPI_PARAMS RecdParams, // fill this array with received params
  473. IN OUT DWORD *pnRecdParams, // input: size of above array output: filled size
  474. IN LPBYTE Bufp, // buffer for data ptrs
  475. IN OUT LPDWORD pSize // i/p: size of above array, o/p filled size
  476. )
  477. {
  478. PDHCP_API_ARGS DhcpApiArgs = NULL;
  479. LPBYTE OutBuf;
  480. LPBYTE InBuf = NULL;
  481. LPBYTE Buffer;
  482. LPBYTE Endp;
  483. DWORD OutBufSize;
  484. DWORD InBufSize;
  485. DWORD i,j;
  486. DWORD nArgsReturned;
  487. DWORD Error;
  488. DWORD nRecdParams = (*pnRecdParams);
  489. DWORD nParamsRequested;
  490. DWORD nVParamsRequested;
  491. ULONG Tmp, VTmp;
  492. CHAR TmpBuf[256], VTmpBuf[256];
  493. DWORD dwBufLen = 0;
  494. BYTE * Buf = NULL;
  495. BYTE OpCode;
  496. // check parameter consistency
  497. if( ClassIdLen && NULL == ClassId) return ERROR_INVALID_PARAMETER;
  498. if( 0 == ClassIdLen && NULL != ClassId ) return ERROR_INVALID_PARAMETER;
  499. if( nSendParams && NULL == SendParams) return ERROR_INVALID_PARAMETER;
  500. if( 0 == nSendParams && NULL != SendParams) return ERROR_INVALID_PARAMETER;
  501. if( NULL == RecdParams || 0 == nRecdParams ) return ERROR_INVALID_PARAMETER;
  502. if( NULL == AdapterName ) return ERROR_INVALID_PARAMETER;
  503. Tmp = VTmp = 0;
  504. for( i = 0; i < nRecdParams ; i ++ ) {
  505. if( FALSE == RecdParams[i].IsVendor ) {
  506. TmpBuf[ ++Tmp] = (BYTE)RecdParams[i].OptionId;
  507. } else {
  508. VTmpBuf[ ++VTmp] = (BYTE)RecdParams[i].OptionId;
  509. }
  510. if (Tmp >= sizeof(TmpBuf) - 1 || VTmp >= sizeof(VTmpBuf) - 1) {
  511. break;
  512. }
  513. }
  514. if (i < nRecdParams) return ERROR_INVALID_PARAMETER;
  515. if( 0 == (VTmp + Tmp) ) return ERROR_INVALID_PARAMETER;
  516. // allocate buffers
  517. OutBufSize = (*pSize);
  518. (*pSize) = 0;
  519. if( 0 == OutBufSize ) OutBuf = NULL;
  520. else {
  521. OutBuf = Bufp;
  522. }
  523. // calculate input buffer size required
  524. InBufSize = 0;
  525. InBufSize += (DWORD)(sizeof(DWORD)*2); // INBUF_SIZE, OUTBUF_SIZE
  526. InBufSize += (DWORD)(sizeof(BYTE)+sizeof(DWORD)+(1+wcslen(AdapterName))*sizeof(WCHAR));
  527. if( ClassIdLen )
  528. InBufSize += sizeof(BYTE)+sizeof(DWORD)+ClassIdLen;
  529. for( i = 0; i < nSendParams; i ++ ) {
  530. InBufSize += sizeof(BYTE)+sizeof(DWORD)+sizeof(BYTE)+SendParams[i].nBytesData;
  531. }
  532. //
  533. // Now for options request list (vendor and otherwise)
  534. //
  535. if( Tmp ) {
  536. InBufSize += sizeof(BYTE)+sizeof(DWORD)+sizeof(BYTE)+Tmp;
  537. }
  538. if( VTmp ) {
  539. InBufSize += sizeof(BYTE)+sizeof(DWORD)+sizeof(BYTE)+VTmp;
  540. }
  541. InBuf = DhcpAllocateMemory(InBufSize);
  542. if( NULL == InBuf ) {
  543. return ERROR_NOT_ENOUGH_MEMORY;
  544. }
  545. // fill up output buffer size right at start of input buffer
  546. ((DWORD UNALIGNED*)InBuf)[0] = htonl(OutBufSize);
  547. ((DWORD UNALIGNED*)InBuf)[1] = 0;
  548. Buffer = InBuf + sizeof(DWORD);
  549. InBufSize -= sizeof(DWORD);
  550. // fill in input buffer
  551. Error = DhcpApiFillBuffer(Buffer, InBufSize, AdapterName, OpCodeParam);
  552. DhcpAssert(ERROR_SUCCESS == Error);
  553. if( ClassIdLen ) {
  554. Error = DhcpApiArgAdd(Buffer, InBufSize, ClassIdParam, ClassIdLen, ClassId);
  555. DhcpAssert(ERROR_SUCCESS == Error);
  556. }
  557. for( i = 0; i < nSendParams; i ++ ) {
  558. //
  559. // Increase the Buf if needed
  560. //
  561. if (dwBufLen < SendParams[i].nBytesData + 1) {
  562. dwBufLen = SendParams[i].nBytesData + 1;
  563. if (Buf) {
  564. DhcpFreeMemory(Buf);
  565. Buf = NULL;
  566. }
  567. }
  568. //
  569. // Allocate Buf if it hasn't done yet
  570. //
  571. if (NULL == Buf) {
  572. Buf = DhcpAllocateMemory(dwBufLen);
  573. }
  574. if (Buf == NULL) {
  575. Error = ERROR_NOT_ENOUGH_MEMORY;
  576. goto Cleanup;
  577. }
  578. Buf[0] = (BYTE)SendParams[i].OptionId;
  579. memcpy(&Buf[1], SendParams[i].Data, SendParams[i].nBytesData);
  580. OpCode = SendParams[i].IsVendor? VendorOptionParam: NormalOptionParam;
  581. Error = DhcpApiArgAdd(Buffer, InBufSize, OpCode, SendParams[i].nBytesData+1, Buf);
  582. DhcpAssert(ERROR_SUCCESS == Error);
  583. }
  584. //
  585. // Now fillup the request lists (vendor & otherwise)
  586. //
  587. if( Tmp ) {
  588. TmpBuf[0] = (BYTE)OPTION_PARAMETER_REQUEST_LIST;
  589. Error = DhcpApiArgAdd(Buffer, InBufSize, NormalOptionParam, Tmp+1, TmpBuf);
  590. DhcpAssert(ERROR_SUCCESS == Error);
  591. }
  592. if( VTmp ) {
  593. VTmpBuf[0] = (BYTE)OPTION_PAD;
  594. Error = DhcpApiArgAdd(Buffer, InBufSize, VendorOptionParam, VTmp+1, VTmpBuf);
  595. }
  596. // now, execute and obtain the output filled in OutBuf
  597. Error = ExecuteApiRequest(InBuf, OutBuf, &OutBufSize);
  598. (*pSize) = OutBufSize;
  599. if( ERROR_MORE_DATA == Error ) {
  600. // recalculate the real OutBufSize required
  601. DhcpAssert(OutBufSize != 0);
  602. goto Cleanup;
  603. }
  604. if( ERROR_SUCCESS != Error ) goto Cleanup;
  605. if( 0 == OutBufSize ) goto Cleanup;
  606. // parse output and fill in the structures..
  607. nArgsReturned = 0;
  608. DhcpApiArgs = NULL;
  609. Error = DhcpApiArgDecode(OutBuf, OutBufSize, DhcpApiArgs, &nArgsReturned);
  610. DhcpAssert( 0 == nArgsReturned || ERROR_MORE_DATA == Error);
  611. if( ERROR_MORE_DATA != Error ) goto Cleanup;
  612. DhcpAssert(0 != nArgsReturned);
  613. DhcpApiArgs = DhcpAllocateMemory( sizeof(DHCP_API_ARGS) * nArgsReturned);
  614. if( NULL == DhcpApiArgs ) {
  615. Error = ERROR_NOT_ENOUGH_MEMORY;
  616. goto Cleanup;
  617. }
  618. Error = DhcpApiArgDecode(OutBuf, OutBufSize, DhcpApiArgs, &nArgsReturned);
  619. DhcpAssert(ERROR_SUCCESS == Error);
  620. DhcpAssert(nArgsReturned);
  621. for(i = j = 0; i < nArgsReturned && j < nRecdParams; i ++ ) {
  622. DhcpAssert( VendorOptionParam == DhcpApiArgs[i].ArgId || NormalOptionParam == DhcpApiArgs[i].ArgId);
  623. DhcpAssert( DhcpApiArgs[i].ArgSize > 1); // one byte for option id, and atleast one byte actual option
  624. if( VendorOptionParam != DhcpApiArgs[i].ArgId && NormalOptionParam != DhcpApiArgs[i].ArgId )
  625. continue;
  626. RecdParams[j].OptionId = DhcpApiArgs[i].ArgVal[0];
  627. RecdParams[j].IsVendor = ( VendorOptionParam == DhcpApiArgs[i].ArgId );
  628. RecdParams[j].nBytesData = DhcpApiArgs[i].ArgSize-1;
  629. RecdParams[j].Data = &DhcpApiArgs[i].ArgVal[1];
  630. j ++;
  631. }
  632. (*pnRecdParams) = j;
  633. Error = ERROR_SUCCESS;
  634. Cleanup:
  635. if( NULL != InBuf ) DhcpFreeMemory(InBuf);
  636. if( NULL != DhcpApiArgs ) DhcpFreeMemory(DhcpApiArgs);
  637. if (NULL != Buf) DhcpFreeMemory(Buf);
  638. return Error;
  639. }
  640. DWORD // win32 status
  641. DhcpRequestParamsInternal( // request parameters of client
  642. IN BYTE OpCodeParam, // opcode to use
  643. IN LPWSTR AdapterName, // adapter name to request for
  644. IN LPBYTE ClassId, // byte stream of class id to use
  645. IN DWORD ClassIdLen, // # of bytes of class id to use
  646. IN PDHCPAPI_PARAMS SendParams, // parameters to send to server
  647. IN DWORD nSendParams, // size of above array
  648. IN DWORD Flags, // must be zero, reserved
  649. IN OUT PDHCPAPI_PARAMS RecdParams, // fill this array with received params
  650. IN OUT LPDWORD pnRecdParams // i/p: size of above in BYTES, o/p required or filled up size
  651. ) {
  652. PDHCP_API_ARGS DhcpApiArgs = NULL;
  653. LPBYTE OutBuf;
  654. LPBYTE InBuf = NULL;
  655. LPBYTE Buffer;
  656. LPBYTE Endp;
  657. DWORD OutBufSize;
  658. DWORD InBufSize;
  659. DWORD i,j;
  660. DWORD nArgsReturned;
  661. DWORD Error;
  662. DWORD nParamsRequested;
  663. DWORD nVParamsRequested;
  664. ULONG Tmp, VTmp;
  665. ULONG OriginalOutBufSize;
  666. // check parameter consistency
  667. if( ClassIdLen && NULL == ClassId) return ERROR_INVALID_PARAMETER;
  668. if( 0 == ClassIdLen && NULL != ClassId ) return ERROR_INVALID_PARAMETER;
  669. if( nSendParams && NULL == SendParams) return ERROR_INVALID_PARAMETER;
  670. if( 0 == nSendParams && NULL != SendParams) return ERROR_INVALID_PARAMETER;
  671. if( NULL == pnRecdParams ) return ERROR_INVALID_PARAMETER;
  672. if( *pnRecdParams && NULL == RecdParams ) return ERROR_INVALID_PARAMETER;
  673. if( NULL == AdapterName ) return ERROR_INVALID_PARAMETER;
  674. Tmp = VTmp = 0;
  675. for( i = 0; i < nSendParams ; i ++ ) {
  676. if( SendParams[i].nBytesData > OPTION_END ) return ERROR_INVALID_PARAMETER;
  677. if( SendParams[i].nBytesData && NULL == SendParams[i].Data )
  678. return ERROR_INVALID_PARAMETER;
  679. if( OPTION_PARAMETER_REQUEST_LIST == SendParams[i].OptionId ) {
  680. if( SendParams[i].IsVendor ) continue;
  681. nParamsRequested = SendParams[i].nBytesData;
  682. Tmp ++;
  683. }
  684. if( OPTION_PAD == SendParams[i].OptionId ) {
  685. if( !SendParams[i].IsVendor ) continue;
  686. nVParamsRequested = SendParams[i].nBytesData;
  687. VTmp ++;
  688. }
  689. }
  690. if( 0 == (VTmp + Tmp) || 1 < VTmp || 1 < Tmp ) return ERROR_INVALID_PARAMETER;
  691. if( 0 == Tmp) nParamsRequested = 0;
  692. if( VTmp ) nParamsRequested += nVParamsRequested;
  693. // allocate buffers
  694. OriginalOutBufSize = OutBufSize = (*pnRecdParams);
  695. (*pnRecdParams) = 0;
  696. if( 0 == OutBufSize ) OutBuf = NULL;
  697. else {
  698. OutBuf = DhcpAllocateMemory(OutBufSize);
  699. if( NULL == OutBuf ) return ERROR_NOT_ENOUGH_MEMORY;
  700. }
  701. // calculate input buffer size required
  702. InBufSize = 0;
  703. InBufSize += (DWORD)(sizeof(DWORD)*2); // INBUF_SIZE, OUTBUF_SIZE
  704. InBufSize += (DWORD)(sizeof(BYTE)+sizeof(DWORD)+(1+wcslen(AdapterName))*sizeof(WCHAR));
  705. if( ClassIdLen )
  706. InBufSize += sizeof(BYTE)+sizeof(DWORD)+ClassIdLen;
  707. for( i = 0; i < nSendParams; i ++ ) {
  708. InBufSize += sizeof(BYTE)+sizeof(DWORD)+sizeof(BYTE)+SendParams[i].nBytesData;
  709. }
  710. InBuf = DhcpAllocateMemory(InBufSize);
  711. if( NULL == InBuf ) {
  712. DhcpFreeMemory(OutBuf);
  713. return ERROR_NOT_ENOUGH_MEMORY;
  714. }
  715. // fill up output buffer size right at start of input buffer
  716. ((DWORD UNALIGNED*)InBuf)[0] = htonl(OutBufSize);
  717. ((DWORD UNALIGNED*)InBuf)[1] = 0;
  718. Buffer = InBuf + sizeof(DWORD);
  719. InBufSize -= sizeof(DWORD);
  720. // fill in input buffer
  721. Error = DhcpApiFillBuffer(Buffer, InBufSize, AdapterName, OpCodeParam);
  722. DhcpAssert(ERROR_SUCCESS == Error);
  723. if( ClassIdLen ) {
  724. Error = DhcpApiArgAdd(Buffer, InBufSize, ClassIdParam, ClassIdLen, ClassId);
  725. DhcpAssert(ERROR_SUCCESS == Error);
  726. }
  727. for( i = 0; i < nSendParams; i ++ ) {
  728. BYTE Buf[OPTION_END+1];
  729. BYTE OpCode;
  730. Buf[0] = (BYTE)SendParams[i].OptionId;
  731. memcpy(&Buf[1], SendParams[i].Data, SendParams[i].nBytesData);
  732. OpCode = SendParams[i].IsVendor? VendorOptionParam: NormalOptionParam;
  733. Error = DhcpApiArgAdd(Buffer, InBufSize, OpCode, SendParams[i].nBytesData+1, Buf);
  734. DhcpAssert(ERROR_SUCCESS == Error);
  735. }
  736. // now, execute and obtain the output filled in OutBuf
  737. Error = ExecuteApiRequest(InBuf, OutBuf, &OutBufSize);
  738. if( ERROR_MORE_DATA == Error ) {
  739. // recalculate the real OutBufSize required
  740. DhcpAssert(OutBufSize != 0);
  741. OutBufSize += nParamsRequested*(sizeof(DHCPAPI_PARAMS) - (2*sizeof(BYTE)+sizeof(DWORD)));
  742. (*pnRecdParams) = OutBufSize;
  743. goto Cleanup;
  744. }
  745. if( ERROR_SUCCESS != Error ) goto Cleanup;
  746. if( 0 == OutBufSize ) goto Cleanup;
  747. // parse output and fill in the structures..
  748. nArgsReturned = 0;
  749. DhcpApiArgs = NULL;
  750. Error = DhcpApiArgDecode(OutBuf, OutBufSize, DhcpApiArgs, &nArgsReturned);
  751. DhcpAssert( 0 == nArgsReturned || ERROR_MORE_DATA == Error);
  752. if( ERROR_MORE_DATA != Error ) goto Cleanup;
  753. DhcpAssert(0 != nArgsReturned);
  754. DhcpApiArgs = DhcpAllocateMemory( sizeof(DHCP_API_ARGS) * nArgsReturned);
  755. if( NULL == DhcpApiArgs ) {
  756. Error = ERROR_NOT_ENOUGH_MEMORY;
  757. goto Cleanup;
  758. }
  759. Error = DhcpApiArgDecode(OutBuf, OutBufSize, DhcpApiArgs, &nArgsReturned);
  760. DhcpAssert(ERROR_SUCCESS == Error);
  761. DhcpAssert(nArgsReturned);
  762. if( OriginalOutBufSize < OutBufSize + nParamsRequested*(sizeof(DHCPAPI_PARAMS) - (2*sizeof(BYTE)+sizeof(DWORD)) ) ) {
  763. //
  764. // Input size is not sufficient
  765. //
  766. (*pnRecdParams ) = OutBufSize + nParamsRequested*(
  767. sizeof(DHCPAPI_PARAMS) - (2*sizeof(BYTE)+sizeof(DWORD) )
  768. );
  769. Error = ERROR_MORE_DATA;
  770. // DbgPrint("Bug 330419 repro'ed");
  771. goto Cleanup;
  772. }
  773. Endp = OutBufSize + (LPBYTE)RecdParams + nParamsRequested*(sizeof(DHCPAPI_PARAMS) - (2*sizeof(BYTE)+sizeof(DWORD)));
  774. for(i = j = 0; i < nArgsReturned; i ++ ) {
  775. DhcpAssert( VendorOptionParam == DhcpApiArgs[i].ArgId || NormalOptionParam == DhcpApiArgs[i].ArgId);
  776. DhcpAssert( DhcpApiArgs[i].ArgSize > 1); // one byte for option id, and atleast one byte actual option
  777. if( VendorOptionParam != DhcpApiArgs[i].ArgId && NormalOptionParam != DhcpApiArgs[i].ArgId )
  778. continue;
  779. RecdParams[j].OptionId = DhcpApiArgs[i].ArgVal[0];
  780. RecdParams[j].IsVendor = ( VendorOptionParam == DhcpApiArgs[i].ArgId );
  781. RecdParams[j].nBytesData = DhcpApiArgs[i].ArgSize-1;
  782. Endp -= RecdParams[j].nBytesData;
  783. memcpy(Endp, &DhcpApiArgs[i].ArgVal[1], RecdParams[j].nBytesData);
  784. RecdParams[j].Data = Endp;
  785. j ++;
  786. }
  787. DhcpAssert(((LPBYTE)&RecdParams[j]) <= Endp);
  788. *pnRecdParams = j;
  789. Error = ERROR_SUCCESS;
  790. Cleanup:
  791. DhcpFreeMemory(InBuf);
  792. if(OutBuf) DhcpFreeMemory(OutBuf);
  793. if(DhcpApiArgs) DhcpFreeMemory(DhcpApiArgs);
  794. return Error;
  795. }
  796. DWORD // win32 status
  797. APIENTRY
  798. DhcpRequestParameters( // request parameters of client
  799. IN LPWSTR AdapterName, // adapter name to request for
  800. IN LPBYTE ClassId, // byte stream of class id to use
  801. IN DWORD ClassIdLen, // # of bytes of class id to use
  802. IN PDHCPAPI_PARAMS SendParams, // parameters to send to server
  803. IN DWORD nSendParams, // size of above array
  804. IN DWORD Flags, // must be zero, reserved
  805. IN OUT PDHCPAPI_PARAMS RecdParams, // fill this array with received params
  806. IN OUT LPDWORD pnRecdParams // i/p: size of above in BYTES, o/p required or filled up size
  807. ) {
  808. return DhcpRequestParamsInternal(
  809. RequestParamsOpCode,
  810. AdapterName,
  811. ClassId,
  812. ClassIdLen,
  813. SendParams,
  814. nSendParams,
  815. Flags,
  816. RecdParams,
  817. pnRecdParams
  818. );
  819. }
  820. DWORD // win32 status
  821. DhcpRegisterParameterChangeNotificationInternal( // notify if a parameter has changed -- common between NT and VxD
  822. IN LPWSTR AdapterName, // adapter of interest
  823. IN LPBYTE ClassId, // byte stream of class id to use
  824. IN DWORD ClassIdLen, // # of bytes of class id
  825. IN PDHCPAPI_PARAMS Params, // params of interest
  826. IN DWORD nParams, // # of elts in above array
  827. IN DWORD Flags, // must be zero, reserved
  828. IN DWORD Descriptor, // thsi describes the event uniquely for this process
  829. IN HANDLE hEvent // handle to event that will be SetEvent'ed in case of param change
  830. ) {
  831. LPBYTE InBuf;
  832. LPBYTE OptList;
  833. LPBYTE VendorOptList;
  834. LPBYTE Buffer;
  835. DWORD Error;
  836. DWORD InBufSize;
  837. DWORD nVendorOpts;
  838. DWORD nOpts;
  839. DWORD ProcId;
  840. DWORD OutBufSize;
  841. DWORD i;
  842. VendorOptList = OptList = NULL;
  843. nVendorOpts = nOpts = 0;
  844. InBufSize = 2*sizeof(DWORD); // expected outbuf size + inbuf size
  845. InBufSize += sizeof(BYTE) + 2*sizeof(DWORD); // Proc Id
  846. InBufSize += sizeof(BYTE) + 2*sizeof(DWORD); // Event Handle
  847. InBufSize += sizeof(BYTE) + 2*sizeof(DWORD); // Descriptor
  848. InBufSize += (DWORD)(sizeof(Descriptor)+sizeof(hEvent)+sizeof(DWORD));
  849. InBufSize += (DWORD)(sizeof(BYTE)+sizeof(DWORD)+(1+wcslen(AdapterName))*sizeof(WCHAR));
  850. if( ClassIdLen )
  851. InBufSize += sizeof(BYTE)+sizeof(DWORD)+ClassIdLen;
  852. for( i = 0; i < nParams; i ++ ) {
  853. if( OPTION_PARAMETER_REQUEST_LIST == Params[i].OptionId ) {
  854. if( Params[i].IsVendor ) continue;
  855. if( nOpts ) return ERROR_INVALID_PARAMETER;
  856. nOpts = Params[i].nBytesData;
  857. if( 0 == nOpts ) return ERROR_INVALID_PARAMETER;
  858. OptList = Params[i].Data;
  859. continue;
  860. }
  861. if( OPTION_PAD == Params[i].OptionId ) {
  862. if( ! Params[i].IsVendor ) continue;
  863. if( nVendorOpts ) return ERROR_INVALID_PARAMETER;
  864. nVendorOpts = Params[i].nBytesData;
  865. if( 0 == nVendorOpts ) return ERROR_INVALID_PARAMETER;
  866. VendorOptList = Params[i].Data;
  867. continue;
  868. }
  869. }
  870. if( 0 == nOpts + nVendorOpts ) return ERROR_INVALID_PARAMETER;
  871. if( nOpts ) InBufSize += sizeof(BYTE) + sizeof(DWORD) + nOpts;
  872. if( nVendorOpts ) InBufSize += sizeof(BYTE) + sizeof(DWORD) + nVendorOpts;
  873. InBuf = DhcpAllocateMemory(InBufSize);
  874. if( NULL == InBuf ) {
  875. return ERROR_NOT_ENOUGH_MEMORY;
  876. }
  877. Buffer = InBuf + sizeof(DWORD);
  878. ((DWORD UNALIGNED*)InBuf)[0] = 0; // dont expect anything in return other than status
  879. ((DWORD UNALIGNED*)Buffer)[0] = 0; // increase the input buffer size each time we add something
  880. InBufSize -= sizeof(DWORD); // ignore the first DWORD
  881. Error = DhcpApiFillBuffer(Buffer, InBufSize, AdapterName, RegisterParamsOpCode);
  882. DhcpAssert(ERROR_SUCCESS == Error );
  883. if( ClassIdLen ) {
  884. Error = DhcpApiArgAdd(Buffer, InBufSize, ClassIdParam, ClassIdLen, ClassId);
  885. DhcpAssert(ERROR_SUCCESS == Error);
  886. }
  887. if( nOpts ) {
  888. Error = DhcpApiArgAdd(Buffer, InBufSize, NormalOptionParam, nOpts, OptList);
  889. DhcpAssert(ERROR_SUCCESS == Error);
  890. }
  891. if( nVendorOpts ) {
  892. Error = DhcpApiArgAdd(Buffer, InBufSize, VendorOptionParam, nVendorOpts, VendorOptList);
  893. DhcpAssert(ERROR_SUCCESS == Error);
  894. }
  895. ProcId = GetCurrentProcessId();
  896. Error = DhcpApiArgAdd(Buffer, InBufSize, ProcIdParam, sizeof(ProcId), (LPBYTE) &ProcId);
  897. DhcpAssert(ERROR_SUCCESS == Error);
  898. Error = DhcpApiArgAdd(Buffer, InBufSize, DescriptorParam, sizeof(Descriptor), (LPBYTE) &Descriptor);
  899. DhcpAssert(ERROR_SUCCESS == Error);
  900. Error = DhcpApiArgAdd(Buffer, InBufSize, EventHandleParam, sizeof(hEvent), (LPBYTE) &hEvent);
  901. DhcpAssert(ERROR_SUCCESS == Error);
  902. OutBufSize = 0;
  903. Error = ExecuteApiRequest(InBuf, NULL, &OutBufSize);
  904. DhcpFreeMemory(InBuf);
  905. DhcpAssert(ERROR_MORE_DATA != Error );
  906. return Error;
  907. }
  908. DWORD // Ring 0 handle -- used only on win9x platform
  909. VxDGetDescriptor( // convert Event to Ring0 handle for use in vdhcp.vxd
  910. IN HANDLE Event,
  911. IN OUT LPDWORD pDescriptor
  912. ) {
  913. HANDLE Kernel32;
  914. DWORD (*HandleToRing0Handle)(HANDLE);
  915. DWORD RetVal;
  916. Kernel32 = LoadLibraryA("kernel32.dll");
  917. if( NULL == Kernel32 ) return GetLastError();
  918. HandleToRing0Handle = (DWORD (*)(HANDLE))GetProcAddress(Kernel32, "OpenVxDHandle");
  919. if( NULL == HandleToRing0Handle ) {
  920. CloseHandle(Kernel32);
  921. return GetLastError();
  922. }
  923. (*pDescriptor) = HandleToRing0Handle(Event);
  924. CloseHandle(Kernel32);
  925. if( 0 == (*pDescriptor) ) return ERROR_INVALID_PARAMETER;
  926. return ERROR_SUCCESS;
  927. }
  928. DWORD // win32 status
  929. DhcpCreateApiEventAndDescriptor( // create both the api event handle and the unique descriptor for it
  930. IN OUT LPHANDLE hEvent, // fill this with a valid event handle if succeeded
  931. IN OUT LPDWORD pDescriptor // this descriptor is unique for this process.
  932. ) {
  933. static DWORD Descriptor = 1;// use this for the descriptor
  934. OSVERSIONINFO OsVersion; // need to know if NT or Win95+
  935. BOOL BoolError;
  936. CHAR NameBuf[sizeof("DhcpPid-1-2-3-4-5-6-7-8UniqueId-1-2-3-4-5-6-7-8")];
  937. DWORD Error;
  938. // *** changing NameBuf's format requires change in apiimpl.c NotifyClients...*
  939. OsVersion.dwOSVersionInfoSize = sizeof(OsVersion);
  940. BoolError = GetVersionEx(&OsVersion);
  941. if( FALSE == BoolError ) return GetLastError();
  942. if( VER_PLATFORM_WIN32_WINDOWS == OsVersion.dwPlatformId ) {
  943. (*hEvent) = CreateEvent(
  944. NULL, // no security
  945. FALSE, // auto reset
  946. FALSE, // intially signaled? NO
  947. NULL // no name
  948. );
  949. } else {
  950. (*pDescriptor) = InterlockedIncrement(pDescriptor);
  951. sprintf(NameBuf, "DhcpPid%16xUniqueId%16x", GetCurrentProcessId(), *pDescriptor);
  952. (*hEvent) = CreateEventA( // now create the required event
  953. NULL, // no security
  954. FALSE, // automatic reset
  955. FALSE, // intially signalled? NO!
  956. NameBuf // the name to use to create
  957. );
  958. }
  959. if( NULL == (*hEvent) ) return GetLastError();
  960. if( VER_PLATFORM_WIN32_WINDOWS != OsVersion.dwPlatformId )
  961. return ERROR_SUCCESS; // done for NT.
  962. // for Memphis, need to get OpenVxdHandle procedure to get Descriptor value
  963. Error = VxDGetDescriptor(*hEvent, pDescriptor);
  964. if( ERROR_SUCCESS != Error ) {
  965. CloseHandle(*hEvent);
  966. }
  967. return Error;
  968. }
  969. DWORD // win32 status
  970. DhcpRegisterParameterChangeNotification( // notify if a parameter has changed
  971. IN LPWSTR AdapterName, // adapter of interest
  972. IN LPBYTE ClassId, // byte stream of class id to use
  973. IN DWORD ClassIdLen, // # of bytes of class id
  974. IN PDHCPAPI_PARAMS Params, // params of interest
  975. IN DWORD nParams, // # of elts in above array
  976. IN DWORD Flags, // must be zero, reserved
  977. IN OUT PHANDLE hEvent // handle to event that will be SetEvent'ed in case of param change
  978. ) {
  979. DWORD Descriptor; // on NT this is an id unique across this process, on VxD ring0 handle
  980. DWORD Error; //
  981. DWORD i;
  982. if( 0 == ClassIdLen && NULL != ClassId ) return ERROR_INVALID_PARAMETER;
  983. if( 0 != ClassIdLen && NULL == ClassId ) return ERROR_INVALID_PARAMETER;
  984. if( 0 == nParams && NULL != Params ) return ERROR_INVALID_PARAMETER;
  985. if( 0 != nParams && NULL == Params ) return ERROR_INVALID_PARAMETER;
  986. if( Flags ) return ERROR_INVALID_PARAMETER;
  987. if( NULL == hEvent ) return ERROR_INVALID_PARAMETER;
  988. for( i = 0; i < nParams ; i ++ ) {
  989. if( Params[i].nBytesData > OPTION_END ) return ERROR_INVALID_PARAMETER;
  990. if( Params[i].nBytesData && NULL == Params[i].Data )
  991. return ERROR_INVALID_PARAMETER;
  992. }
  993. Error = DhcpCreateApiEventAndDescriptor(hEvent, &Descriptor);
  994. if( ERROR_SUCCESS != Error ) return Error;
  995. Error = DhcpRegisterParameterChangeNotificationInternal(
  996. AdapterName,
  997. ClassId,
  998. ClassIdLen,
  999. Params,
  1000. nParams,
  1001. Flags,
  1002. Descriptor,
  1003. (*hEvent)
  1004. );
  1005. if( ERROR_SUCCESS != Error ) {
  1006. CloseHandle(*hEvent);
  1007. *hEvent = NULL;
  1008. return Error;
  1009. }
  1010. return ERROR_SUCCESS;
  1011. }
  1012. DhcpDeRegisterParameterChangeNotification( // undo the registration
  1013. IN HANDLE Event // handle to event returned by DhcpRegisterParameterChangeNotification, NULL ==> everything
  1014. ) {
  1015. DWORD Error;
  1016. DWORD Descriptor;
  1017. DWORD ProcId;
  1018. DWORD InBufSize;
  1019. DWORD OutBufSize;
  1020. LPBYTE InBuf;
  1021. LPBYTE Buffer;
  1022. InBufSize = 2*sizeof(DWORD); // input/output sizes
  1023. InBufSize += sizeof(BYTE) + sizeof(DWORD); // opcode
  1024. InBufSize += sizeof(BYTE) + sizeof(DWORD)*2; // proc id
  1025. InBufSize += sizeof(BYTE) + sizeof(DWORD)*2; // handle
  1026. InBuf = DhcpAllocateMemory(InBufSize);
  1027. if( NULL == InBuf ) return ERROR_NOT_ENOUGH_MEMORY;
  1028. Buffer = InBuf + sizeof(DWORD);
  1029. ((DWORD UNALIGNED*)InBuf)[0] = 0; // nothing expected in return
  1030. ((DWORD UNALIGNED*)Buffer)[0] = 0; // initialize size to zero -- will be increased each time something is added
  1031. Error = DhcpApiFillBuffer(Buffer, InBufSize, NULL, DeRegisterParamsOpCode);
  1032. DhcpAssert(ERROR_SUCCESS == Error);
  1033. ProcId = GetCurrentProcessId();
  1034. Error = DhcpApiArgAdd(Buffer, InBufSize, ProcIdParam, sizeof(ProcId), (LPBYTE)&ProcId);
  1035. DhcpAssert(ERROR_SUCCESS == Error);
  1036. Error = DhcpApiArgAdd(Buffer, InBufSize, EventHandleParam, sizeof(Event), (LPBYTE) &Event);
  1037. DhcpAssert(ERROR_SUCCESS == Error);
  1038. OutBufSize = 0;
  1039. Error = ExecuteApiRequest(InBuf, NULL, &OutBufSize);
  1040. DhcpFreeMemory(InBuf);
  1041. DhcpAssert(ERROR_MORE_DATA != Error);
  1042. if( ERROR_SUCCESS == Error ) {
  1043. CloseHandle(Event);
  1044. }
  1045. return Error;
  1046. }
  1047. DWORD // win32 status
  1048. DhcpRegistryFillParamsList( // read the registry value and add this list of values to it
  1049. IN LPWSTR AppName, // prefix for key
  1050. IN DWORD nSendParams // # of values to add
  1051. ) {
  1052. HKEY DhcpOptionKey;
  1053. LPWSTR OldValueName;
  1054. LPWSTR NewValueName;
  1055. LPWSTR ValueName;
  1056. LPWSTR Tmp, Tmp2;
  1057. BOOL fOldValueExists = FALSE;
  1058. DWORD ValueNameSize;
  1059. DWORD OldValueNameSize;
  1060. DWORD NewValueNameSize;
  1061. DWORD Error;
  1062. DWORD i;
  1063. Error = RegOpenKeyEx( // open the dhcp option key first
  1064. HKEY_LOCAL_MACHINE,
  1065. DHCP_CLIENT_OPTION_KEY,
  1066. 0 /* Reserved */,
  1067. DHCP_CLIENT_KEY_ACCESS,
  1068. &DhcpOptionKey
  1069. );
  1070. if( ERROR_SUCCESS != Error ) return Error;
  1071. OldValueName = NULL;
  1072. Error = GetRegistryString(
  1073. DhcpOptionKey,
  1074. DHCP_OPTION_LIST_VALUE,
  1075. &OldValueName,
  1076. &OldValueNameSize
  1077. );
  1078. if( ERROR_SUCCESS != Error ) {
  1079. OldValueName = DEFAULT_DHCP_KEYS_LIST_VALUE;
  1080. OldValueNameSize = sizeof(DEFAULT_DHCP_KEYS_LIST_VALUE);
  1081. } else {
  1082. fOldValueExists = TRUE;
  1083. }
  1084. NewValueNameSize = OldValueNameSize;
  1085. ValueNameSize = 0;
  1086. ValueNameSize += wcslen(AppName)*sizeof(WCHAR);
  1087. ValueNameSize += sizeof(L"\\12345");
  1088. ValueName = DhcpAllocateMemory(ValueNameSize);
  1089. if( NULL == ValueName ) {
  1090. RegCloseKey(DhcpOptionKey);
  1091. if( fOldValueExists ) DhcpFreeMemory(OldValueName);
  1092. return ERROR_NOT_ENOUGH_MEMORY;
  1093. }
  1094. NewValueNameSize = nSendParams*ValueNameSize + OldValueNameSize;
  1095. NewValueName = DhcpAllocateMemory(NewValueNameSize);
  1096. if( NULL == NewValueName ) {
  1097. RegCloseKey(DhcpOptionKey);
  1098. if( fOldValueExists ) DhcpFreeMemory(OldValueName);
  1099. DhcpFreeMemory(ValueName);
  1100. return ERROR_NOT_ENOUGH_MEMORY;
  1101. }
  1102. wcscpy(ValueName, AppName);
  1103. wcscat(ValueName, L"\\");
  1104. Tmp = NewValueName;
  1105. for( i = 0; i < nSendParams ; i ++ ) { // for each value, add its to the list
  1106. wcscpy(Tmp, ValueName);
  1107. Tmp += wcslen(Tmp);
  1108. swprintf(Tmp, L"%5x", i);
  1109. Tmp += wcslen(Tmp);
  1110. Tmp ++; // move the ptr off the last L'\0'
  1111. }
  1112. DhcpFreeMemory(ValueName);
  1113. Tmp2 = OldValueName;
  1114. while(wcslen(Tmp2)) {
  1115. wcscpy(Tmp, Tmp2);
  1116. Tmp += wcslen(Tmp2);
  1117. Tmp2 += wcslen(Tmp2);
  1118. Tmp ++;
  1119. Tmp2 ++;
  1120. }
  1121. *Tmp++ = L'\0';
  1122. if(fOldValueExists ) DhcpFreeMemory(OldValueName);
  1123. Error = RegSetValueEx( // write this string back
  1124. DhcpOptionKey,
  1125. DHCP_OPTION_LIST_VALUE,
  1126. 0 /* Reserved */,
  1127. REG_MULTI_SZ,
  1128. (LPBYTE) NewValueName,
  1129. (ULONG)(((LPBYTE)Tmp) - ((LPBYTE)NewValueName))
  1130. );
  1131. DhcpFreeMemory(NewValueName);
  1132. RegCloseKey(DhcpOptionKey);
  1133. if( ERROR_SUCCESS != Error ) {
  1134. DhcpPrint((DEBUG_ERRORS, "RegSetValueEx(OPTION_LIST):0x%lx\n", Error));
  1135. }
  1136. return Error;
  1137. }
  1138. DWORD // win32 status
  1139. DhcpRegistryFillParams( // make a subkey and fill in the details
  1140. IN LPWSTR AdapterName, // NULL ==> global change
  1141. IN LPBYTE ClassId, // this is the class of the option
  1142. IN DWORD ClassIdLen, // # of bytes of above
  1143. IN DWORD i, // key index is 3hex-digit convertion onf this
  1144. IN HKEY Key, // use this key for creating subkeys
  1145. IN PDHCPAPI_PARAMS SendParam, // ptr to structure to use for this one key write operation
  1146. IN LPWSTR AppName // name of app
  1147. ) {
  1148. HKEY SubKey;
  1149. WCHAR KeyName[7]; // key is just 5 bytes
  1150. LPWSTR SendLocation;
  1151. LPWSTR ValueName;
  1152. LPBYTE SendData;
  1153. DWORD SendDataSize;
  1154. DWORD Size;
  1155. DWORD Disposition;
  1156. DWORD Error;
  1157. DWORD OptionId;
  1158. DWORD IsVendor;
  1159. DWORD DummyKeyType;
  1160. swprintf(KeyName, L"%5x", i);
  1161. OptionId = SendParam->OptionId;
  1162. IsVendor = SendParam->IsVendor;
  1163. SendData = SendParam->Data;
  1164. SendDataSize = SendParam->nBytesData;
  1165. Size = wcslen(AppName)*sizeof(WCHAR)+sizeof(KeyName) + sizeof(L"\\");
  1166. if( AdapterName ) {
  1167. Size += (DWORD)(sizeof(DHCP_SERVICES_KEY) + sizeof(DHCP_ADAPTER_PARAMETERS_KEY) + wcslen(AdapterName)*sizeof(WCHAR));
  1168. } else {
  1169. Size += sizeof(DHCP_TCPIP_PARAMETERS_KEY);
  1170. }
  1171. SendLocation = DhcpAllocateMemory(Size);
  1172. if( NULL == SendLocation ) return ERROR_NOT_ENOUGH_MEMORY;
  1173. if( AdapterName ) {
  1174. wcscpy(SendLocation, DHCP_SERVICES_KEY DHCP_ADAPTER_PARAMETERS_KEY);
  1175. wcscat(SendLocation, L"\\?\\");
  1176. } else {
  1177. wcscpy(SendLocation, DHCP_TCPIP_PARAMETERS_KEY);
  1178. }
  1179. wcscat(SendLocation, AppName);
  1180. wcscat(SendLocation, KeyName);
  1181. Error = RegCreateKeyEx( // create the option key
  1182. Key,
  1183. KeyName,
  1184. 0 /* Reserved */,
  1185. DHCP_CLASS,
  1186. REG_OPTION_NON_VOLATILE,
  1187. KEY_ALL_ACCESS,
  1188. NULL,
  1189. &SubKey,
  1190. &Disposition
  1191. );
  1192. if( ERROR_SUCCESS != Error ) {
  1193. DhcpFreeMemory(SendLocation);
  1194. return Error;
  1195. }
  1196. DhcpAssert(REG_CREATED_NEW_KEY == Disposition);
  1197. Error = RegSetValueEx( // now create each of the values -- OPTION ID
  1198. SubKey,
  1199. DHCP_OPTION_OPTIONID_VALUE,
  1200. 0 /* Reserved */,
  1201. DHCP_OPTION_OPTIONID_TYPE,
  1202. (LPBYTE)&OptionId,
  1203. sizeof(OptionId)
  1204. );
  1205. DhcpAssert(ERROR_SUCCESS == Error);
  1206. Error = RegSetValueEx( // IS VENDOR
  1207. SubKey,
  1208. DHCP_OPTION_ISVENDOR_VALUE,
  1209. 0 /* Reserved */,
  1210. DHCP_OPTION_ISVENDOR_TYPE,
  1211. (LPBYTE) (&IsVendor),
  1212. sizeof(IsVendor)
  1213. );
  1214. DhcpAssert(ERROR_SUCCESS == Error);
  1215. if( ClassIdLen ) {
  1216. Error = RegSetValueEx( // CLASS ID
  1217. SubKey,
  1218. DHCP_OPTION_CLASSID_VALUE,
  1219. 0 /* Reserved */,
  1220. REG_BINARY,
  1221. ClassId,
  1222. ClassIdLen
  1223. );
  1224. DhcpAssert(ERROR_SUCCESS == Error);
  1225. }
  1226. Error = RegSetValueEx(
  1227. SubKey,
  1228. DHCP_OPTION_SEND_LOCATION_VALUE,
  1229. 0 /* Reserved */,
  1230. REG_SZ,
  1231. (LPBYTE)SendLocation,
  1232. (wcslen(SendLocation)+1)*sizeof(WCHAR)
  1233. );
  1234. DhcpAssert(ERROR_SUCCESS == Error);
  1235. DummyKeyType = REG_DWORD; // KeyType
  1236. Error = RegSetValueEx(
  1237. SubKey,
  1238. DHCP_OPTION_SAVE_TYPE_VALUE,
  1239. 0 /* Reserved */,
  1240. DHCP_OPTION_SAVE_TYPE_TYPE,
  1241. (LPBYTE)&DummyKeyType,
  1242. sizeof(DummyKeyType));
  1243. DhcpAssert(ERROR_SUCCESS == Error);
  1244. RegCloseKey(SubKey);
  1245. if( AdapterName ) {
  1246. wcscpy(SendLocation, DHCP_SERVICES_KEY DHCP_ADAPTER_PARAMETERS_KEY);
  1247. wcscat(SendLocation, L"\\");
  1248. wcscat(SendLocation, AdapterName);
  1249. } else {
  1250. wcscpy(SendLocation, DHCP_TCPIP_PARAMETERS_KEY);
  1251. }
  1252. ValueName = wcslen(SendLocation) + 1 + SendLocation;
  1253. wcscpy(ValueName, AppName);
  1254. wcscat(ValueName, KeyName);
  1255. Error = RegOpenKeyEx(
  1256. HKEY_LOCAL_MACHINE,
  1257. SendLocation,
  1258. 0 /* Reserved */,
  1259. KEY_ALL_ACCESS,
  1260. &SubKey
  1261. );
  1262. if( ERROR_SUCCESS != Error ) {
  1263. DhcpFreeMemory(SendLocation);
  1264. return Error;
  1265. }
  1266. Error = RegSetValueEx(
  1267. SubKey,
  1268. ValueName,
  1269. 0 /* Reserved */,
  1270. REG_BINARY,
  1271. SendData,
  1272. SendDataSize
  1273. );
  1274. DhcpAssert(ERROR_SUCCESS == Error);
  1275. RegCloseKey(SubKey);
  1276. DhcpFreeMemory(SendLocation);
  1277. return ERROR_SUCCESS;
  1278. }
  1279. DWORD // win32 status
  1280. DhcpRegistryCreateUniqueKey( // create a unique key with prefix AppName
  1281. IN LPWSTR AppName, // some App descriptor
  1282. IN OUT HKEY* Key // return the opened key here
  1283. ) {
  1284. DWORD FullKeyNameSize, Disposition;
  1285. DWORD Error;
  1286. LPWSTR FullKeyName;
  1287. FullKeyNameSize = sizeof(DHCP_CLIENT_OPTION_KEY);
  1288. FullKeyNameSize += wcslen(AppName)*sizeof(WCHAR) + sizeof(WCHAR);
  1289. FullKeyName = DhcpAllocateMemory(FullKeyNameSize);
  1290. if( NULL == FullKeyName ) return ERROR_NOT_ENOUGH_MEMORY;
  1291. wcscpy(FullKeyName, DHCP_CLIENT_OPTION_KEY);
  1292. wcscat(FullKeyName, L"\\");
  1293. wcscat(FullKeyName, AppName);
  1294. Error = RegCreateKeyEx(
  1295. HKEY_LOCAL_MACHINE,
  1296. FullKeyName,
  1297. 0 /* Reserved */,
  1298. DHCP_CLASS,
  1299. REG_OPTION_NON_VOLATILE,
  1300. KEY_ALL_ACCESS,
  1301. NULL,
  1302. Key,
  1303. &Disposition
  1304. );
  1305. DhcpFreeMemory(FullKeyName);
  1306. if( ERROR_SUCCESS != Error ) return Error;
  1307. if( REG_OPENED_EXISTING_KEY == Disposition ) {
  1308. RegCloseKey(*Key);
  1309. return ERROR_ALREADY_EXISTS;
  1310. }
  1311. return ERROR_SUCCESS;
  1312. }
  1313. DWORD // win32 status
  1314. DhcpRegistryPersistentRequestParams( // edit registry to consider this additional persistent request
  1315. IN LPWSTR AdapterName, // which adapter is this request for?
  1316. IN LPBYTE ClassId, // class
  1317. IN DWORD ClassIdLen, // # of bytes in class id
  1318. IN PDHCPAPI_PARAMS SendParams, // the actual parameters to fill up
  1319. IN DWORD nSendParams, // the size of the above array
  1320. IN PDHCPAPI_PARAMS RecdParams, // would like to receive these
  1321. IN DWORD nRecdParams, // count..
  1322. IN LPWSTR AppName // some thing unique about the app that wants to do registrations
  1323. ) {
  1324. HKEY Key;
  1325. DWORD i;
  1326. DWORD Error;
  1327. DWORD LastError;
  1328. DHCPAPI_PARAMS NonVendorParams;
  1329. ULONG nVendorOpt, nNonVendorOpt;
  1330. CHAR Buf[256];
  1331. if( NULL == AppName ) return ERROR_INVALID_PARAMETER;
  1332. if( 0 == nSendParams && NULL != SendParams ) return ERROR_INVALID_PARAMETER;
  1333. if( 0 != nSendParams && NULL == SendParams ) return ERROR_INVALID_PARAMETER;
  1334. if( 0 != nRecdParams && NULL == RecdParams ) return ERROR_INVALID_PARAMETER;
  1335. if( 0 == nRecdParams && NULL != RecdParams ) return ERROR_INVALID_PARAMETER;
  1336. if( ClassIdLen && NULL == ClassId || 0 == ClassIdLen && NULL != ClassId)
  1337. return ERROR_INVALID_PARAMETER;
  1338. for( i = 0; i < nSendParams; i ++ ) {
  1339. if( SendParams[i].nBytesData == 0 ) return ERROR_INVALID_PARAMETER;
  1340. }
  1341. nVendorOpt = nNonVendorOpt = 0;
  1342. // --ft: 07/25/00 fixes the way the non-vendor options
  1343. // are collected from RecdParams.
  1344. for (i = 0; i < nRecdParams; i++)
  1345. {
  1346. if (RecdParams[i].IsVendor)
  1347. {
  1348. nVendorOpt = 1;
  1349. }
  1350. else
  1351. {
  1352. Buf[nNonVendorOpt++] = (BYTE)RecdParams[i].OptionId;
  1353. }
  1354. }
  1355. // if nVendorOpt is 1 this means we have at least one vendor option in
  1356. // the requested parameters list. Make sure then OPTION_VENDOR_SPEC_INFO
  1357. // is mentioned in the array to be sent as OPTION_PARAMETER_REQUEST_LIST
  1358. if( nVendorOpt ) {
  1359. for( i = 0; i < nNonVendorOpt ; i ++ )
  1360. if( Buf[i] == OPTION_VENDOR_SPEC_INFO )
  1361. break;
  1362. if( i == nNonVendorOpt ) Buf[nNonVendorOpt ++] = (BYTE)OPTION_VENDOR_SPEC_INFO;
  1363. }
  1364. NonVendorParams.Flags = 0;
  1365. NonVendorParams.OptionId = OPTION_PARAMETER_REQUEST_LIST;
  1366. NonVendorParams.IsVendor = FALSE;
  1367. NonVendorParams.Data = Buf;
  1368. NonVendorParams.nBytesData = nNonVendorOpt;
  1369. Error = DhcpRegistryCreateUniqueKey( // first try creating the key
  1370. AppName,
  1371. &Key
  1372. );
  1373. if( ERROR_SUCCESS != Error ) return Error;
  1374. Error = DhcpRegistryFillParamsList(
  1375. AppName,
  1376. nSendParams + (nNonVendorOpt?1:0)
  1377. );
  1378. if( ERROR_SUCCESS != Error ) {
  1379. DhcpAssert(FALSE);
  1380. DhcpPrint((DEBUG_ERRORS, "DhcpRegistryFillParamsList:0x%lx\n", Error));
  1381. RegCloseKey(Key);
  1382. return Error;
  1383. }
  1384. LastError = ERROR_SUCCESS;
  1385. for( i = 0; i < nSendParams; i ++ ) { // now enter the particular option in the registry
  1386. Error = DhcpRegistryFillParams(
  1387. AdapterName,
  1388. ClassId,
  1389. ClassIdLen,
  1390. i,
  1391. Key,
  1392. &SendParams[i],
  1393. AppName
  1394. );
  1395. if( ERROR_SUCCESS != Error ) {
  1396. DhcpAssert(FALSE);
  1397. DhcpPrint((DEBUG_ERRORS, "DhcpRegistryFillParams:0x%lx\n", Error));
  1398. LastError = Error;
  1399. }
  1400. }
  1401. if( nNonVendorOpt ) {
  1402. Error = DhcpRegistryFillParams(
  1403. AdapterName,
  1404. ClassId,
  1405. ClassIdLen,
  1406. i ++,
  1407. Key,
  1408. &NonVendorParams,
  1409. AppName
  1410. );
  1411. if( ERROR_SUCCESS != Error ) {
  1412. DhcpAssert(FALSE);
  1413. DhcpPrint((DEBUG_ERRORS, "DhcpRegistryFillParams:0x%lx\n", Error));
  1414. LastError = Error;
  1415. }
  1416. }
  1417. RegCloseKey(Key);
  1418. return LastError;
  1419. }
  1420. // Please note that AppName must be unique for each request (and if it is not, things are
  1421. // likely to behave weirdly.. This is the same name that should be used for the deletion..
  1422. DWORD // win32 status
  1423. DhcpPersistentRequestParams( // parameters to request persistently
  1424. IN LPWSTR AdapterName, // adapter name to request for
  1425. IN LPBYTE ClassId, // byte stream of class id to use
  1426. IN DWORD ClassIdLen, // # of bytes of class id
  1427. IN PDHCPAPI_PARAMS SendParams, // persistent parameters
  1428. IN DWORD nSendParams, // size of above array
  1429. IN DWORD Flags, // must be zero, reserved
  1430. IN LPWSTR AppName // name of app doing the persistent request
  1431. ) {
  1432. DWORD Error;
  1433. DWORD nRecdParams;
  1434. nRecdParams = 0;
  1435. Error = DhcpRequestParamsInternal(
  1436. PersistentRequestParamsOpCode,
  1437. AdapterName,
  1438. ClassId,
  1439. ClassIdLen,
  1440. SendParams,
  1441. nSendParams,
  1442. Flags,
  1443. NULL,
  1444. &nRecdParams
  1445. );
  1446. DhcpAssert(ERROR_MORE_DATA != Error );
  1447. if( ERROR_INVALID_PARAMETER == Error ) Error = ERROR_SUCCESS; // see below comment
  1448. if( ERROR_SUCCESS != Error ) { // if AdapterName is NULL or if ClassId is not the one currently in use
  1449. return Error; // only then do we get ERROR_INVALID_PARAMETER -- so filter those out
  1450. }
  1451. return DhcpRegistryPersistentRequestParams( // now munge the registry
  1452. AdapterName,
  1453. ClassId,
  1454. ClassIdLen,
  1455. SendParams,
  1456. nSendParams,
  1457. NULL,
  1458. 0,
  1459. AppName
  1460. );
  1461. }
  1462. DWORD // win32 status
  1463. DhcpDelPersistentRequestParams( // undo the effect of a persistent request -- currently undo from registry
  1464. IN LPWSTR AdapterName, // the name of the adpater to delete for
  1465. IN LPWSTR AppName // the name used by the app
  1466. ) {
  1467. HKEY Key;
  1468. DWORD Error;
  1469. DWORD LocationSize;
  1470. DWORD FullKeyNameSize, Disposition;
  1471. LPWSTR FullKeyName;
  1472. LPWSTR LocationValue;
  1473. LPWSTR Tmp, Tmp2;
  1474. FullKeyNameSize = sizeof(DHCP_CLIENT_OPTION_KEY);
  1475. FullKeyNameSize += wcslen(AppName)*sizeof(WCHAR) + sizeof(WCHAR);
  1476. FullKeyName = DhcpAllocateMemory(FullKeyNameSize);
  1477. if( NULL == FullKeyName ) return ERROR_NOT_ENOUGH_MEMORY;
  1478. wcscpy(FullKeyName, DHCP_CLIENT_OPTION_KEY);
  1479. wcscat(FullKeyName, L"\\");
  1480. wcscat(FullKeyName, AppName);
  1481. Error = DhcpRegRecurseDelete(HKEY_LOCAL_MACHINE, FullKeyName);
  1482. DhcpAssert(ERROR_SUCCESS == Error);
  1483. DhcpFreeMemory(FullKeyName);
  1484. Error = RegOpenKeyEx(
  1485. HKEY_LOCAL_MACHINE,
  1486. DHCP_CLIENT_OPTION_KEY,
  1487. 0 /* Reserved */,
  1488. DHCP_CLIENT_KEY_ACCESS,
  1489. &Key
  1490. );
  1491. if( ERROR_SUCCESS != Error ) {
  1492. DhcpAssert(FALSE);
  1493. return Error;
  1494. } else {
  1495. DhcpRegRecurseDelete(Key, AppName);
  1496. }
  1497. LocationValue = NULL;
  1498. Error = GetRegistryString( // read the value
  1499. Key,
  1500. DHCP_OPTION_LIST_VALUE,
  1501. &LocationValue,
  1502. &LocationSize
  1503. );
  1504. if( LocationValue == NULL ) Error = ERROR_FILE_NOT_FOUND;
  1505. if( ERROR_SUCCESS != Error ) {
  1506. RegCloseKey(Key);
  1507. return Error;
  1508. }
  1509. Tmp = Tmp2 = LocationValue;
  1510. while(wcslen(Tmp) ) {
  1511. if( 0 != wcsncmp(AppName, Tmp, wcslen(AppName))) {
  1512. wcscpy(Tmp2, Tmp);
  1513. Tmp2 += wcslen(Tmp) +1;
  1514. Tmp += wcslen(Tmp) +1;
  1515. continue;
  1516. }
  1517. if( Tmp[wcslen(AppName)] != L'\\' ) {
  1518. wcscpy(Tmp2, Tmp);
  1519. Tmp2 += wcslen(Tmp) +1;
  1520. Tmp += wcslen(Tmp) +1;
  1521. continue;
  1522. }
  1523. //
  1524. // found required entry.. just skip over it..
  1525. //
  1526. Tmp += wcslen(Tmp) +1;
  1527. }
  1528. *Tmp2 ++ = L'\0';
  1529. Error = RegSetValueEx(
  1530. Key,
  1531. DHCP_OPTION_LIST_VALUE,
  1532. 0 /* Reserved */,
  1533. REG_MULTI_SZ,
  1534. (LPBYTE)LocationValue,
  1535. (ULONG)(((LPBYTE)Tmp2 - (LPBYTE)LocationValue))
  1536. );
  1537. RegCloseKey(Key);
  1538. DhcpFreeMemory(LocationValue);
  1539. return Error;
  1540. }
  1541. BOOL _inline
  1542. CharInMem(
  1543. IN BYTE Byte,
  1544. IN LPBYTE Mem,
  1545. IN ULONG MemSz
  1546. )
  1547. {
  1548. while(MemSz) {
  1549. if( Byte == *Mem ) return TRUE;
  1550. Mem ++; MemSz --;
  1551. }
  1552. return FALSE;
  1553. }
  1554. DWORD
  1555. APIENTRY
  1556. DhcpRegisterOptions(
  1557. IN LPWSTR AdapterName,
  1558. IN LPBYTE OptionList,
  1559. IN DWORD OptionListSz,
  1560. IN HANDLE *pdwHandle
  1561. ) {
  1562. DHCPAPI_PARAMS DhcpParams;
  1563. DWORD Error;
  1564. DHCP_OPTION DummyOption;
  1565. LPBYTE Value;
  1566. DWORD ValueSize, ValueType;
  1567. BYTE Buf[256];
  1568. ULONG nElementsInBuf;
  1569. DhcpParams.OptionId = OPTION_PARAMETER_REQUEST_LIST;
  1570. DhcpParams.IsVendor = FALSE;
  1571. DhcpParams.Data = OptionList;
  1572. DhcpParams.nBytesData = OptionListSz;
  1573. Error = DhcpRegisterParameterChangeNotification(
  1574. AdapterName,
  1575. NULL,
  1576. 0,
  1577. &DhcpParams,
  1578. 1,
  1579. 0,
  1580. pdwHandle
  1581. );
  1582. if( ERROR_SUCCESS != Error ) return Error;
  1583. memset(&DummyOption, 0, sizeof(DummyOption));
  1584. Value = NULL; ValueSize = 0;
  1585. Error = DhcpRegReadFromAnyLocation(
  1586. DHCP_REGISTER_OPTIONS_LOC,
  1587. AdapterName,
  1588. &Value,
  1589. &ValueType,
  1590. &ValueSize
  1591. );
  1592. if( ERROR_SUCCESS == Error && REG_BINARY == ValueType && 0 != ValueSize ) {
  1593. //
  1594. // Got some pre-existing values... add the remaining to it..
  1595. //
  1596. memcpy(Buf, Value, ValueSize);
  1597. while(OptionListSz) {
  1598. if( !CharInMem(*OptionList, Value, ValueSize) )
  1599. Buf[ValueSize++] = *OptionList;
  1600. OptionList ++; OptionListSz --;
  1601. }
  1602. OptionList = Buf;
  1603. OptionListSz = ValueSize;
  1604. }
  1605. if( NULL != Value ) DhcpFreeMemory(Value);
  1606. DummyOption.Data = OptionList;
  1607. DummyOption.DataLen = OptionListSz;
  1608. Error = DhcpRegSaveOptionAtLocationEx(
  1609. &DummyOption,
  1610. AdapterName,
  1611. DHCP_REGISTER_OPTIONS_LOC,
  1612. REG_BINARY
  1613. );
  1614. return Error;
  1615. }
  1616. DWORD
  1617. APIENTRY
  1618. DhcpDeRegisterOptions (
  1619. IN HANDLE OpenHandle
  1620. ) {
  1621. DWORD Error;
  1622. Error = DhcpDeRegisterParameterChangeNotification(OpenHandle);
  1623. if( ERROR_SUCCESS != Error ) return Error;
  1624. //
  1625. // can't undo registry as we don't have enough information to do that.
  1626. //
  1627. return Error;
  1628. }
  1629. //================================================================================
  1630. // C L I E N T A P I E N T R Y P O I N T S
  1631. //================================================================================
  1632. DWORD
  1633. APIENTRY
  1634. DhcpCApiInitialize(
  1635. OUT LPDWORD Version
  1636. )
  1637. /*++
  1638. Routine Description:
  1639. This routine intializes all the DHCP Client side APIs
  1640. Arguemnts:
  1641. Version - a pointer to a DWORD that gets filled with DHCP APIs version #.
  1642. Return Value:
  1643. Returns STatus.
  1644. --*/
  1645. {
  1646. if( NULL != Version ) *Version = 2;
  1647. return ERROR_SUCCESS;
  1648. }
  1649. VOID
  1650. APIENTRY
  1651. DhcpCApiCleanup(
  1652. VOID
  1653. )
  1654. /*++
  1655. Routine Description:
  1656. This routine cleansup afterall the DHCP Client side APIs have been called.
  1657. --*/
  1658. {
  1659. return ;
  1660. }
  1661. DWORD // win32 status
  1662. APIENTRY
  1663. DhcpRequestParams( // request parameters of client
  1664. IN DWORD Flags, // must be DHCPCAPI_REQUEST_SYNCHRONOUS
  1665. IN LPVOID Reserved, // this parameter is reserved
  1666. IN LPWSTR AdapterName, // adapter name to request for
  1667. IN LPDHCPCAPI_CLASSID ClassId, // reserved must be NULL
  1668. IN DHCPCAPI_PARAMS_ARRAY SendParams, // parameters to send.
  1669. IN OUT DHCPCAPI_PARAMS_ARRAY RecdParams, // parameters that are to be requested..
  1670. IN LPBYTE Buffer, // a buffer to hold data for RecdParams
  1671. IN OUT LPDWORD pSize, // i/p: size of above in BYTES, o/p required bytes..
  1672. IN LPWSTR RequestIdStr // name of the application, unique per request
  1673. ) // returns ERROR_MORE_DATA if o/p buffer is of insufficient size, and fills in reqd size in # of bytes
  1674. /*++
  1675. Routine Description:
  1676. This routine can be used to do Request options from the DHCP Server and based on
  1677. whether then whether the request is permanent or not, this request would be stored
  1678. in the registry for persistence across boots. The requests can have a particular class
  1679. for which they'd be defined... (the class is sent on wire for the server to decide
  1680. which options to send). The request could be ASYNCHRONOUS in the sense that the call
  1681. returns even before the server returns the data.. But this is not yet implemented.
  1682. Arugments:
  1683. Flags - currently DHCPCAPI_REQUEST_SYNCHRONOUS must be defined.
  1684. if a persisten request is desired, DHCPCAPI_REQUEST_PERSISTENT can
  1685. also be passed (bit-wise OR'ed)
  1686. Reserved - MUST be NULL. Reserved for future USE.
  1687. AdapterName - The Name of the adapter for which this request is designed. This
  1688. cannot be NULL currently though it is a nice thing to implement for
  1689. future.
  1690. ClassId - The binary ClassId information to use to send on wire.
  1691. SendParams - The Parameters to actual send on wire.
  1692. RecdParams - The parameters to be received back from the DHCP server
  1693. Buffer - A buffer to hold some information. This cannot be NULL and some
  1694. pointers within the RecdParams structure use this buffer, so it cannot
  1695. be deallocated so long as the RecdParams array is in USE.
  1696. pSize - This is (on input) the size in bytes of the Buffer variable. When
  1697. the function returns ERROR_MORE_DATA, this variable would be the size
  1698. in bytes required. If the function returns SUCCESSFULLY, this would
  1699. be the number of bytes space used up in reality.
  1700. RequestIdStr - a string identifying the request being made. This has to be unique
  1701. to each request (and a Guid is suggested). This string is needed to
  1702. undo the effects of a RequestParam via UndoRequestParams..
  1703. Return Value:
  1704. This function returns ERROR_MORE_DATA if the buffer space provided by "Buffer" variable
  1705. is not sufficient. (In this case, the pSize variable is filled in with the actual
  1706. size required). On success it returns ERROR_SUCCESS. Otherwise, it returns Win32
  1707. status.
  1708. --*/
  1709. {
  1710. ULONG Error;
  1711. ULONG i;
  1712. //
  1713. // Parameter validation
  1714. //
  1715. if( Flags != DHCPCAPI_REQUEST_SYNCHRONOUS &&
  1716. Flags != DHCPCAPI_REQUEST_PERSISTENT &&
  1717. Flags != (DHCPCAPI_REQUEST_SYNCHRONOUS | DHCPCAPI_REQUEST_PERSISTENT)) {
  1718. return ERROR_INVALID_PARAMETER;
  1719. }
  1720. if( NULL != Reserved || NULL == AdapterName ||
  1721. 0 == RecdParams.nParams || NULL == pSize ) {
  1722. return ERROR_INVALID_PARAMETER;
  1723. }
  1724. if( NULL == Buffer && *pSize ) {
  1725. return ERROR_INVALID_PARAMETER;
  1726. }
  1727. if( NULL != ClassId ) {
  1728. if( 0 != ClassId->Flags ) return ERROR_INVALID_PARAMETER;
  1729. if( NULL == ClassId->Data || 0 == ClassId->nBytesData ) {
  1730. return ERROR_INVALID_PARAMETER;
  1731. }
  1732. }
  1733. if( NULL == RecdParams.Params || (0 != SendParams.nParams && NULL == SendParams.Params) ) {
  1734. return ERROR_INVALID_PARAMETER;
  1735. }
  1736. for( i = 0; i < RecdParams.nParams ; i ++ ) {
  1737. if( 0 != RecdParams.Params[i].nBytesData ||
  1738. NULL != RecdParams.Params[i].Data ) {
  1739. return ERROR_INVALID_PARAMETER;
  1740. }
  1741. }
  1742. //
  1743. // Now call the DhcpRequestParameters API and do datatype conversions for that..
  1744. //
  1745. Error = ERROR_SUCCESS;
  1746. if( Flags & DHCPCAPI_REQUEST_SYNCHRONOUS ) {
  1747. Error = DhcpRequestParamsInternalEx(
  1748. RequestParamsOpCode,
  1749. AdapterName,
  1750. ClassId? ClassId->Data : NULL,
  1751. ClassId? ClassId->nBytesData : 0,
  1752. SendParams.Params,
  1753. SendParams.nParams,
  1754. 0,
  1755. RecdParams.Params,
  1756. &RecdParams.nParams,
  1757. Buffer,
  1758. pSize
  1759. );
  1760. }
  1761. if( ERROR_SUCCESS != Error ) return Error;
  1762. if( Flags & DHCPCAPI_REQUEST_PERSISTENT ) {
  1763. Error = DhcpRegistryPersistentRequestParams(
  1764. AdapterName,
  1765. ClassId? ClassId->Data : NULL,
  1766. ClassId? ClassId->nBytesData : 0,
  1767. SendParams.Params,
  1768. SendParams.nParams,
  1769. RecdParams.Params,
  1770. RecdParams.nParams,
  1771. RequestIdStr
  1772. );
  1773. }
  1774. return Error;
  1775. }
  1776. DWORD // win32 status
  1777. APIENTRY
  1778. DhcpUndoRequestParams( // undo the effect of a persistent request -- currently undo from registry
  1779. IN DWORD Flags, // must be zero, reserved
  1780. IN LPVOID Reserved, // this parameter is reserved
  1781. IN LPWSTR AdapterName, // the original adapter this was registerdd for,..
  1782. IN LPWSTR RequestIdStr // the requestId str passed to RequestParams..
  1783. )
  1784. /*++
  1785. Routine Description:
  1786. This function is used to undo the effects of a persistent request done
  1787. via DhcpRequestParams with DHCPCAPI_REQUEST_PERSISTENT option.
  1788. Arguments:
  1789. Flags - MUST be zero. Reserved for future use.
  1790. Reserved - MUST be NULL
  1791. AdapterName - The original adapter name this request was made for
  1792. RequestIdStr - The original request Id string passed to RequestParams
  1793. Return Value:
  1794. returns Win32 status
  1795. --*/
  1796. {
  1797. if( 0 != Flags || NULL != Reserved || NULL == RequestIdStr )
  1798. return ERROR_INVALID_PARAMETER;
  1799. return DhcpDelPersistentRequestParams(
  1800. AdapterName,
  1801. RequestIdStr
  1802. );
  1803. }
  1804. DWORD // win32 status
  1805. APIENTRY
  1806. DhcpRegisterParamChange( // notify if a parameter has changed
  1807. IN DWORD Flags, // must be DHCPCAPI_REGISTER_HANDLE_EVENT
  1808. IN LPVOID Reserved, // this parameter is reserved
  1809. IN LPWSTR AdapterName, // adapter of interest
  1810. IN LPDHCPCAPI_CLASSID ClassId, // reserved must be NULL
  1811. IN DHCPCAPI_PARAMS_ARRAY Params, // parameters of interest
  1812. IN OUT LPVOID Handle // handle to event that will be SetEvent'ed in case of param change
  1813. )
  1814. /*++
  1815. Routine Description;
  1816. This function registers with DHCP for any notifications on changes to the
  1817. specified options.. (notifications are via an EVENT handle)
  1818. Arguments:
  1819. Flags - this decides how the notification works -- via EVENTS or otherwise.
  1820. Currently, only event based mechanism is provided. So, this must be
  1821. DHCPCAPI_REGISTER_HANDLE_EVENT. In this case, Handle must also
  1822. be the address of a handle variable. (This is not the event handle
  1823. itself, the event handle is returned in this address).
  1824. Reserved - MUST be NULL.
  1825. AdapterName - MUST NOT BE NULL. This is the name of the adapter for which the
  1826. notification is being registered..
  1827. ClassId - This specifies the classId if any for which the registration is.
  1828. Params - This is the set of parameter to listen on and notify of when any
  1829. change happens..
  1830. Handle - See "Flags" for what this variable is.
  1831. Return values:
  1832. returns Win32 status codes
  1833. --*/
  1834. {
  1835. DWORD Error;
  1836. CHAR Buf[256]; // cannot request more options than this!
  1837. CHAR VBuf[256];
  1838. DHCPAPI_PARAMS Param[2], *pReqParams;
  1839. ULONG i;
  1840. DWORD nOpt, nVOpt;
  1841. if( Flags != DHCPCAPI_REGISTER_HANDLE_EVENT ) {
  1842. return ERROR_INVALID_PARAMETER;
  1843. }
  1844. if( NULL != Reserved || NULL == AdapterName || 0 == Params.nParams || NULL == Handle ) {
  1845. return ERROR_INVALID_PARAMETER;
  1846. }
  1847. nOpt = nVOpt = 0;
  1848. for( i = 0; i < Params.nParams ; i ++ ) {
  1849. if( Params.Params[i].IsVendor ) {
  1850. VBuf[nVOpt++] = (BYTE)Params.Params[i].OptionId;
  1851. } else {
  1852. Buf[nOpt++] = (BYTE)Params.Params[i].OptionId;
  1853. }
  1854. }
  1855. Param[0].OptionId = OPTION_PARAMETER_REQUEST_LIST;
  1856. Param[0].IsVendor = FALSE;
  1857. Param[0].Data = Buf;
  1858. Param[0].nBytesData = nOpt;
  1859. Param[1].OptionId = OPTION_PAD;
  1860. Param[1].IsVendor = TRUE;
  1861. Param[1].Data = VBuf;
  1862. Param[1].nBytesData = nVOpt;
  1863. if( 0 == nOpt ) pReqParams = &Param[1]; else pReqParams = &Param[0];
  1864. return DhcpRegisterParameterChangeNotification(
  1865. AdapterName,
  1866. ClassId? ClassId->Data : NULL,
  1867. ClassId? ClassId->nBytesData : 0,
  1868. pReqParams,
  1869. (nOpt != 0) + (nVOpt != 0),
  1870. 0,
  1871. Handle
  1872. );
  1873. }
  1874. DWORD
  1875. APIENTRY
  1876. DhcpDeRegisterParamChange( // undo the registration
  1877. IN DWORD Flags, // MUST BE ZERO --> No flags yet.
  1878. IN LPVOID Reserved, // MUST BE NULL --> Reserved
  1879. IN LPVOID Event // handle to event returned by DhcpRegisterParamChange.
  1880. )
  1881. /*++
  1882. Routine description:
  1883. This routine undoes whateve was done by previous routine, and closes the
  1884. handle also. The handle cannot be used after this.
  1885. Arguments:
  1886. Flags - MUST BE DHCPCAPI_REGISTER_HANDLE_EVENT currently.
  1887. Reserved - MuST BE NULL
  1888. Event - this is the event handle returned in the "Handle" parameter to
  1889. DhcpRegisterParamChange function.
  1890. Return Value:
  1891. Win32 status
  1892. --*/
  1893. {
  1894. return DhcpDeRegisterParameterChangeNotification(Event);
  1895. }
  1896. DWORD
  1897. APIENTRY
  1898. DhcpRemoveDNSRegistrations(
  1899. VOID
  1900. )
  1901. {
  1902. return DhcpAdapterOnlyApi(NULL, RemoveDNSRegistrationsOpCode);
  1903. }
  1904. //================================================================================
  1905. // end of file
  1906. //================================================================================
  1907. #endif H_ONLY