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.

2599 lines
82 KiB

  1. /*++
  2. Copyright (c) 1994 Microsoft Corporation
  3. Module Name:
  4. mdhccapi.c
  5. Abstract:
  6. This file contains the client side APIs for the Madcap.
  7. Author:
  8. Munil Shah (munils) 02-Sept-97
  9. Environment:
  10. User Mode - Win32
  11. Revision History:
  12. --*/
  13. #include "precomp.h"
  14. #include "dhcpglobal.h"
  15. #include <dhcploc.h>
  16. #include <dhcppro.h>
  17. #define MADCAP_DATA_ALLOCATE
  18. #include "mdhcpcli.h"
  19. #include <rpc.h>
  20. //
  21. // constants
  22. //
  23. #define Madcap_ADAPTER_NAME L"Madcap Adapter"
  24. #define MadcapMiscPrint( Msg ) DhcpPrint(( DEBUG_MISC, ( Msg ) ))
  25. static
  26. LONG Initialized = 0;
  27. WSADATA MadcapGlobalWsaData;
  28. DWORD
  29. MadcapInitGlobalData(
  30. VOID
  31. )
  32. /*++
  33. Routine Description:
  34. This routine initializes data required for Multicast APIs to work
  35. correctly. This has to be called exactly once (and this is ensured
  36. by calling it in DLL init in dhcp.c )
  37. Return Value:
  38. This function returns a Win32 status.
  39. --*/
  40. {
  41. DWORD Error;
  42. LOCK_MSCOPE_LIST();
  43. do {
  44. if( Initialized > 0 ) {
  45. Initialized ++;
  46. Error = NO_ERROR;
  47. break;
  48. }
  49. gMadcapScopeList = NULL;
  50. gMScopeQueryInProgress = FALSE;
  51. gMScopeQueryEvent =
  52. CreateEvent(
  53. NULL, // no security.
  54. TRUE, // manual reset.
  55. FALSE, // initial state is not-signaled.
  56. NULL ); // no name.
  57. if( gMScopeQueryEvent == NULL ) {
  58. Error = GetLastError();
  59. break;
  60. }
  61. Error = WSAStartup( 0x0101, &MadcapGlobalWsaData );
  62. if( ERROR_SUCCESS != Error ) {
  63. CloseHandle(gMScopeQueryEvent);
  64. gMScopeQueryEvent = NULL;
  65. break;
  66. }
  67. Initialized ++;
  68. Error = NO_ERROR;
  69. } while ( 0 );
  70. UNLOCK_MSCOPE_LIST();
  71. return Error;
  72. }
  73. VOID
  74. MadcapCleanupGlobalData(
  75. VOID
  76. )
  77. /*++
  78. Routine Description:
  79. This routine cleans up any resources allocated in MadcapInitGlobalData.
  80. This can be called even if the InitData routine fails..
  81. Return Value:
  82. Nothing
  83. --*/
  84. {
  85. LOCK_MSCOPE_LIST();
  86. do {
  87. DhcpAssert(Initialized >= 0);
  88. if( Initialized <= 0 ) break;
  89. Initialized --;
  90. if( 0 != Initialized ) break;
  91. gMadcapScopeList = NULL;
  92. gMScopeQueryInProgress = FALSE;
  93. if( NULL != gMScopeQueryEvent ) {
  94. CloseHandle(gMScopeQueryEvent);
  95. gMScopeQueryEvent = NULL;
  96. }
  97. WSACleanup();
  98. } while ( 0 );
  99. UNLOCK_MSCOPE_LIST();
  100. }
  101. BOOL
  102. ShouldRequeryMScopeList()
  103. /*++
  104. Routine Description:
  105. This routine checks if the multicast scope list can be
  106. queried or not.
  107. * If there is already a query in progress, then this routine
  108. waits for that to complete and then returns FALSE.
  109. * If there is no query in progress, it returns TRUE.
  110. Arguments:
  111. Return Value:
  112. The status of the operation.
  113. --*/
  114. {
  115. LOCK_MSCOPE_LIST();
  116. if ( gMScopeQueryInProgress ) {
  117. DWORD result;
  118. DhcpPrint((DEBUG_API, "MScopeQuery is in progress - waiting\n"));
  119. // make sure the event is not in signalled state from before.
  120. ResetEvent( gMScopeQueryEvent );
  121. UNLOCK_MSCOPE_LIST();
  122. switch( result = WaitForSingleObject( gMScopeQueryEvent, INFINITE ) ) {
  123. case WAIT_OBJECT_0:
  124. // it's signled now, no need to requery the list, just take the result from previous query.
  125. DhcpPrint((DEBUG_API, "MScopeQuery event signalled\n"));
  126. return FALSE;
  127. case WAIT_ABANDONED:
  128. DhcpPrint((DEBUG_ERRORS, "WaitForSingleObject - thread died before the wait completed\n"));
  129. return TRUE;
  130. case WAIT_FAILED:
  131. DhcpPrint((DEBUG_ERRORS, "WaitForSingleObject failed - %lx\n",GetLastError()));
  132. DhcpAssert(FALSE);
  133. //
  134. // BUG 519461
  135. //
  136. // Add the "return TRUE" to make typo.pl happy
  137. //
  138. return TRUE;
  139. default:
  140. DhcpPrint((DEBUG_ERRORS, "WaitForSingleObject returned unknown value - %lx\n", result));
  141. DhcpAssert(FALSE);
  142. return TRUE;
  143. }
  144. } else {
  145. gMScopeQueryInProgress = TRUE;
  146. UNLOCK_MSCOPE_LIST();
  147. return TRUE;
  148. }
  149. }
  150. DWORD
  151. InitializeMadcapSocket(
  152. SOCKET *Socket,
  153. DHCP_IP_ADDRESS IpAddress
  154. )
  155. /*++
  156. Routine Description:
  157. This function initializes and binds a socket to the specified IP address.
  158. Arguments:
  159. Socket - Returns a pointer to the initialized socket.
  160. IpAddress - The IP address to bind the socket to.
  161. Return Value:
  162. The status of the operation.
  163. --*/
  164. {
  165. DWORD error;
  166. DWORD closeError;
  167. DWORD value;
  168. struct sockaddr_in socketName;
  169. DWORD i;
  170. SOCKET sock;
  171. //
  172. // Sockets initialization
  173. //
  174. sock = socket( PF_INET, SOCK_DGRAM, IPPROTO_UDP );
  175. if ( sock == INVALID_SOCKET ) {
  176. error = WSAGetLastError();
  177. DhcpPrint(( DEBUG_ERRORS, "socket failed, error = %ld\n", error ));
  178. return( error );
  179. }
  180. //
  181. // Make the socket share-able
  182. //
  183. value = 1;
  184. error = setsockopt( sock, SOL_SOCKET, SO_REUSEADDR, (char FAR *)&value, sizeof(value) );
  185. if ( error != 0 ) {
  186. error = WSAGetLastError();
  187. DhcpPrint((DEBUG_ERRORS, "setsockopt failed, err = %ld\n", error ));
  188. closeError = closesocket( sock );
  189. if ( closeError != 0 ) {
  190. DhcpPrint((DEBUG_ERRORS, "closesocket failed, err = %d\n", closeError ));
  191. }
  192. return( error );
  193. }
  194. socketName.sin_family = PF_INET;
  195. socketName.sin_port = 0; // let the winsock pick a port for us.
  196. socketName.sin_addr.s_addr = IpAddress;
  197. for ( i = 0; i < 8 ; i++ ) {
  198. socketName.sin_zero[i] = 0;
  199. }
  200. //
  201. // Bind this socket to the DHCP server port
  202. //
  203. error = bind(
  204. sock,
  205. (struct sockaddr FAR *)&socketName,
  206. sizeof( socketName )
  207. );
  208. if ( error != 0 ) {
  209. error = WSAGetLastError();
  210. DhcpPrint((DEBUG_ERRORS, "bind failed, err = %ld\n", error ));
  211. closeError = closesocket( sock );
  212. if ( closeError != 0 ) {
  213. DhcpPrint((DEBUG_ERRORS, "closesocket failed, err = %d\n", closeError ));
  214. }
  215. return( error );
  216. }
  217. // set the multicast IF to be the one on which we are doing Madcap
  218. if (INADDR_ANY != IpAddress) {
  219. value = IpAddress;
  220. DhcpPrint((DEBUG_ERRORS, "setsockopt: IP_MULTICAST_IF, if = %lx\n", IpAddress ));
  221. error = setsockopt( sock, IPPROTO_IP, IP_MULTICAST_IF,
  222. (char FAR *)&value, sizeof(value) );
  223. if ( error != 0 ) {
  224. error = WSAGetLastError();
  225. DhcpPrint((DEBUG_ERRORS, "setsockopt failed, err = %ld\n", error ));
  226. closeError = closesocket( sock );
  227. if ( closeError != 0 ) {
  228. DhcpPrint((DEBUG_ERRORS, "closesocket failed, err = %d\n", closeError ));
  229. }
  230. return( error );
  231. }
  232. }
  233. *Socket = sock;
  234. return( NO_ERROR );
  235. }
  236. DWORD
  237. ReInitializeMadcapSocket(
  238. SOCKET *Socket,
  239. DHCP_IP_ADDRESS IpAddress
  240. )
  241. /*++
  242. Routine Description:
  243. This function closes and reinitializes the socket to specified IP address.
  244. Arguments:
  245. Socket - Returns a pointer to the initialized socket.
  246. IpAddress - The IP address to bind the socket to.
  247. Return Value:
  248. The status of the operation.
  249. --*/
  250. {
  251. DWORD Error;
  252. if (*Socket != INVALID_SOCKET) {
  253. Error = closesocket( *Socket );
  254. if ( Error != 0 ) {
  255. DhcpPrint((DEBUG_ERRORS, "closesocket failed, err = %d\n", Error ));
  256. return Error;
  257. }
  258. }
  259. return InitializeMadcapSocket( Socket, IpAddress );
  260. }
  261. DWORD
  262. OpenMadcapSocket(
  263. PDHCP_CONTEXT DhcpContext
  264. )
  265. {
  266. DWORD Error;
  267. PLOCAL_CONTEXT_INFO localInfo;
  268. struct sockaddr_in socketName;
  269. int sockAddrLen;
  270. localInfo = DhcpContext->LocalInformation;
  271. if ( INVALID_SOCKET == localInfo->Socket ) {
  272. Error = InitializeMadcapSocket(&localInfo->Socket, DhcpContext->IpAddress);
  273. if( Error != ERROR_SUCCESS ) {
  274. localInfo->Socket = INVALID_SOCKET;
  275. DhcpPrint(( DEBUG_ERRORS, " Socket Open failed, %ld\n", Error ));
  276. return Error;
  277. }
  278. }
  279. // find out which port we are bound to.
  280. sockAddrLen = sizeof(struct sockaddr_in);
  281. Error = getsockname(
  282. localInfo->Socket ,
  283. (struct sockaddr FAR *)&socketName,
  284. &sockAddrLen
  285. );
  286. if ( Error != 0 ) {
  287. DWORD closeError;
  288. Error = WSAGetLastError();
  289. DhcpPrint((DEBUG_ERRORS, "bind failed, err = %ld\n", Error ));
  290. closeError = closesocket( localInfo->Socket );
  291. if ( closeError != 0 ) {
  292. DhcpPrint((DEBUG_ERRORS, "closesocket failed, err = %d\n", closeError ));
  293. }
  294. return( Error );
  295. }
  296. return(Error);
  297. }
  298. DWORD
  299. CreateMadcapContext(
  300. IN OUT PDHCP_CONTEXT *ppContext,
  301. IN LPMCAST_CLIENT_UID pRequestID,
  302. IN DHCP_IP_ADDRESS IpAddress
  303. )
  304. /*++
  305. Routine Description:
  306. This routine creates a dummy context for doing Madcap operation
  307. on it.
  308. Arguments:
  309. ppContext - pointer to where context pointer is to be stored.
  310. pRequestID - The client id to be used in the context.
  311. IpAddress - The ipaddress the context is initialized with.
  312. Return Value:
  313. The status of the operation.
  314. --*/
  315. {
  316. DWORD Error;
  317. PDHCP_CONTEXT DhcpContext = NULL;
  318. ULONG DhcpContextSize;
  319. PLOCAL_CONTEXT_INFO LocalInfo = NULL;
  320. LPVOID Ptr;
  321. LPDHCP_LEASE_INFO LocalLeaseInfo = NULL;
  322. time_t LeaseObtained;
  323. DWORD T1, T2, Lease;
  324. DWORD AdapterNameLen;
  325. //
  326. // prepare dhcp context structure.
  327. //
  328. DhcpContextSize =
  329. ROUND_UP_COUNT(sizeof(DHCP_CONTEXT), ALIGN_WORST) +
  330. ROUND_UP_COUNT(pRequestID->ClientUIDLength, ALIGN_WORST) +
  331. ROUND_UP_COUNT(sizeof(LOCAL_CONTEXT_INFO), ALIGN_WORST) +
  332. ROUND_UP_COUNT(DHCP_RECV_MESSAGE_SIZE, ALIGN_WORST);
  333. Ptr = DhcpAllocateMemory( DhcpContextSize );
  334. if ( Ptr == NULL ) {
  335. return( ERROR_NOT_ENOUGH_MEMORY );
  336. }
  337. RtlZeroMemory( Ptr, DhcpContextSize );
  338. //
  339. // make sure the pointers are aligned.
  340. //
  341. DhcpContext = Ptr;
  342. Ptr = ROUND_UP_POINTER( (LPBYTE)Ptr + sizeof(DHCP_CONTEXT), ALIGN_WORST);
  343. DhcpContext->ClientIdentifier.pbID = Ptr;
  344. Ptr = ROUND_UP_POINTER( (LPBYTE)Ptr + pRequestID->ClientUIDLength, ALIGN_WORST);
  345. DhcpContext->LocalInformation = Ptr;
  346. LocalInfo = Ptr;
  347. Ptr = ROUND_UP_POINTER( (LPBYTE)Ptr + sizeof(LOCAL_CONTEXT_INFO), ALIGN_WORST);
  348. DhcpContext->MadcapMessageBuffer = Ptr;
  349. //
  350. // initialize fields.
  351. //
  352. DhcpContext->ClientIdentifier.fSpecified = TRUE;
  353. DhcpContext->ClientIdentifier.bType = HARDWARE_TYPE_NONE;
  354. DhcpContext->ClientIdentifier.cbID = pRequestID->ClientUIDLength;
  355. RtlCopyMemory(
  356. DhcpContext->ClientIdentifier.pbID,
  357. pRequestID->ClientUID,
  358. pRequestID->ClientUIDLength
  359. );
  360. DhcpContext->IpAddress = IpAddress;
  361. DhcpContext->SubnetMask = DhcpDefaultSubnetMask(0);
  362. DhcpContext->DhcpServerAddress = MADCAP_SERVER_IP_ADDRESS;
  363. DhcpContext->DesiredIpAddress = 0;
  364. SET_MDHCP_STATE(DhcpContext);
  365. InitializeListHead(&DhcpContext->RenewalListEntry);
  366. InitializeListHead(&DhcpContext->SendOptionsList);
  367. InitializeListHead(&DhcpContext->RecdOptionsList);
  368. InitializeListHead(&DhcpContext->FbOptionsList);
  369. InitializeListHead(&DhcpContext->NicListEntry);
  370. DhcpContext->DontPingGatewayFlag = TRUE;
  371. //
  372. // copy local info.
  373. //
  374. //
  375. // unused portion of the local info.
  376. //
  377. LocalInfo->IpInterfaceContext = 0xFFFFFFFF;
  378. LocalInfo->IpInterfaceInstance = 0xFFFFFFFF;
  379. LocalInfo->AdapterName = NULL;
  380. LocalInfo->NetBTDeviceName= NULL;
  381. LocalInfo->RegistryKey= NULL;
  382. LocalInfo->Socket = INVALID_SOCKET;
  383. LocalInfo->DefaultGatewaysSet = FALSE;
  384. //
  385. // used portion of the local info.
  386. //
  387. LocalInfo->Socket = INVALID_SOCKET;
  388. //
  389. // open socket now. receive any.
  390. //
  391. Error = InitializeMadcapSocket(&LocalInfo->Socket,DhcpContext->IpAddress);
  392. if( Error != ERROR_SUCCESS ) {
  393. DhcpFreeMemory( DhcpContext );
  394. return Error;
  395. } else {
  396. *ppContext = DhcpContext;
  397. return Error;
  398. }
  399. }
  400. DWORD
  401. SendMadcapMessage(
  402. PDHCP_CONTEXT DhcpContext,
  403. DWORD MessageLength,
  404. PDWORD TransactionId
  405. )
  406. /*++
  407. Routine Description:
  408. This function sends a UDP message to the DHCP server specified
  409. in the DhcpContext.
  410. Arguments:
  411. DhcpContext - A pointer to a DHCP context block.
  412. MessageLength - The length of the message to send.
  413. TransactionID - The transaction ID for this message. If 0, the
  414. function generates a random ID, and returns it.
  415. Return Value:
  416. The status of the operation.
  417. --*/
  418. {
  419. DWORD error;
  420. int i;
  421. struct sockaddr_in socketName;
  422. time_t TimeNow;
  423. BOOL LockedInterface = FALSE;
  424. if ( *TransactionId == 0 ) {
  425. *TransactionId = (rand() << 16) + rand();
  426. }
  427. DhcpContext->MadcapMessageBuffer->TransactionID = *TransactionId;
  428. //
  429. // Initialize the outgoing address.
  430. //
  431. socketName.sin_family = PF_INET;
  432. socketName.sin_port = htons( MADCAP_SERVER_PORT);
  433. socketName.sin_addr.s_addr = DhcpContext->DhcpServerAddress;
  434. if ( CLASSD_NET_ADDR( DhcpContext->DhcpServerAddress ) ) {
  435. int TTL = 16;
  436. //
  437. // Set TTL
  438. // MBUG: we need to read this from the registry.
  439. //
  440. if (setsockopt(
  441. ((PLOCAL_CONTEXT_INFO)DhcpContext->LocalInformation)->Socket,
  442. IPPROTO_IP,
  443. IP_MULTICAST_TTL,
  444. (char *)&TTL,
  445. sizeof((int)TTL)) == SOCKET_ERROR){
  446. error = WSAGetLastError();
  447. DhcpPrint((DEBUG_ERRORS,"could not set MCast TTL %ld\n",error ));
  448. return error;
  449. }
  450. }
  451. for ( i = 0; i < 8 ; i++ ) {
  452. socketName.sin_zero[i] = 0;
  453. }
  454. error = sendto(
  455. ((PLOCAL_CONTEXT_INFO)
  456. DhcpContext->LocalInformation)->Socket,
  457. (PCHAR)DhcpContext->MadcapMessageBuffer,
  458. MessageLength,
  459. 0,
  460. (struct sockaddr *)&socketName,
  461. sizeof( struct sockaddr )
  462. );
  463. if ( error == SOCKET_ERROR ) {
  464. error = WSAGetLastError();
  465. DhcpPrint(( DEBUG_ERRORS, "Send failed, error = %ld\n", error ));
  466. } else {
  467. IF_DEBUG( PROTOCOL ) {
  468. DhcpPrint(( DEBUG_PROTOCOL, "Sent message to %s: \n", inet_ntoa( socketName.sin_addr )));
  469. }
  470. MadcapDumpMessage(
  471. DEBUG_PROTOCOL_DUMP,
  472. DhcpContext->MadcapMessageBuffer,
  473. DHCP_MESSAGE_SIZE
  474. );
  475. error = NO_ERROR;
  476. }
  477. return( error );
  478. }
  479. WIDE_OPTION UNALIGNED * // ptr to add additional options
  480. FormatMadcapCommonMessage( // format the packet for an INFORM
  481. IN PDHCP_CONTEXT DhcpContext, // format for this context
  482. IN BYTE MessageType
  483. ) {
  484. DWORD size;
  485. DWORD Error;
  486. WIDE_OPTION UNALIGNED *option;
  487. LPBYTE OptionEnd;
  488. PMADCAP_MESSAGE dhcpMessage;
  489. dhcpMessage = DhcpContext->MadcapMessageBuffer;
  490. RtlZeroMemory( dhcpMessage, DHCP_SEND_MESSAGE_SIZE );
  491. dhcpMessage->Version = MADCAP_VERSION;
  492. dhcpMessage->MessageType = MessageType;
  493. dhcpMessage->AddressFamily = htons(MADCAP_ADDR_FAMILY_V4);
  494. option = &dhcpMessage->Option;
  495. OptionEnd = (LPBYTE)dhcpMessage + DHCP_SEND_MESSAGE_SIZE;
  496. option = AppendWideOption( // ==> use this client id as option
  497. option,
  498. MADCAP_OPTION_LEASE_ID,
  499. DhcpContext->ClientIdentifier.pbID,
  500. (WORD)DhcpContext->ClientIdentifier.cbID,
  501. OptionEnd
  502. );
  503. return( option );
  504. }
  505. DWORD // status
  506. SendMadcapInform( // send an inform packet after filling required options
  507. IN PDHCP_CONTEXT DhcpContext, // sned out for this context
  508. IN OUT DWORD *pdwXid // use this Xid (if zero fill something and return it)
  509. ) {
  510. DWORD size;
  511. WIDE_OPTION UNALIGNED * option;
  512. LPBYTE OptionEnd;
  513. WORD OptVal[] = { // for now we just need this one option.
  514. htons(MADCAP_OPTION_MCAST_SCOPE_LIST) // multicast scope list.
  515. };
  516. option = FormatMadcapCommonMessage(DhcpContext, MADCAP_INFORM_MESSAGE);
  517. OptionEnd = (LPBYTE)(DhcpContext->MadcapMessageBuffer) + DHCP_SEND_MESSAGE_SIZE;
  518. option = AppendWideOption(
  519. option,
  520. MADCAP_OPTION_REQUEST_LIST,
  521. OptVal,
  522. sizeof (OptVal),
  523. OptionEnd
  524. );
  525. option = AppendWideOption( option, MADCAP_OPTION_END, NULL, 0, OptionEnd );
  526. size = (DWORD)((PBYTE)option - (PBYTE)DhcpContext->MadcapMessageBuffer);
  527. return SendMadcapMessage( // finally send the message and return
  528. DhcpContext,
  529. size,
  530. pdwXid
  531. );
  532. }
  533. DWORD // status
  534. SendMadcapDiscover( // send an inform packet after filling required options
  535. IN PDHCP_CONTEXT DhcpContext, // sned out for this context
  536. IN PIPNG_ADDRESS pScopeID,
  537. IN PMCAST_LEASE_REQUEST pAddrRequest,
  538. IN OUT DWORD *pdwXid // use this Xid (if zero fill something and return it)
  539. ) {
  540. DWORD size;
  541. WIDE_OPTION UNALIGNED * option;
  542. LPBYTE OptionEnd;
  543. option = FormatMadcapCommonMessage(DhcpContext, MADCAP_DISCOVER_MESSAGE);
  544. OptionEnd = (LPBYTE)(DhcpContext->MadcapMessageBuffer) + DHCP_SEND_MESSAGE_SIZE;
  545. DhcpAssert(pScopeID);
  546. option = AppendWideOption(
  547. option,
  548. MADCAP_OPTION_MCAST_SCOPE,
  549. (LPBYTE)&pScopeID->IpAddrV4,
  550. sizeof (pScopeID->IpAddrV4),
  551. OptionEnd
  552. );
  553. if (pAddrRequest->LeaseDuration) {
  554. DWORD Lease = htonl(pAddrRequest->LeaseDuration);
  555. option = AppendWideOption(
  556. option,
  557. MADCAP_OPTION_LEASE_TIME,
  558. (LPBYTE)&Lease,
  559. sizeof (Lease),
  560. OptionEnd
  561. );
  562. }
  563. if( pAddrRequest->MinLeaseDuration ) {
  564. DWORD MinLease = htonl(pAddrRequest->MinLeaseDuration);
  565. option = AppendWideOption(
  566. option,
  567. MADCAP_OPTION_MIN_LEASE_TIME,
  568. (LPBYTE)&MinLease,
  569. sizeof(MinLease),
  570. OptionEnd
  571. );
  572. }
  573. if( pAddrRequest->MaxLeaseStartTime ) {
  574. DWORD TimeNow = htonl((DWORD)time(NULL));
  575. DWORD StartTime = htonl(pAddrRequest->MaxLeaseStartTime);
  576. option = AppendWideOption(
  577. option,
  578. MADCAP_OPTION_MAX_START_TIME,
  579. (LPBYTE)&StartTime,
  580. sizeof (StartTime),
  581. OptionEnd
  582. );
  583. if( !(pAddrRequest->LeaseStartTime) ) {
  584. //
  585. // if lease start time specified, then current time
  586. // option will be added at a later point
  587. //
  588. option = AppendWideOption(
  589. option,
  590. MADCAP_OPTION_TIME,
  591. (LPBYTE)&TimeNow,
  592. sizeof (TimeNow),
  593. OptionEnd
  594. );
  595. }
  596. }
  597. if (pAddrRequest->LeaseStartTime) {
  598. DWORD TimeNow = htonl((DWORD)time(NULL));
  599. DWORD StartTime = htonl(pAddrRequest->LeaseStartTime);
  600. option = AppendWideOption(
  601. option,
  602. MADCAP_OPTION_START_TIME,
  603. (LPBYTE)&StartTime,
  604. sizeof (StartTime),
  605. OptionEnd
  606. );
  607. option = AppendWideOption(
  608. option,
  609. MADCAP_OPTION_TIME,
  610. (LPBYTE)&TimeNow,
  611. sizeof (TimeNow),
  612. OptionEnd
  613. );
  614. }
  615. option = AppendWideOption( option, MADCAP_OPTION_END, NULL, 0, OptionEnd );
  616. size = (DWORD)((PBYTE)option - (PBYTE)DhcpContext->MadcapMessageBuffer);
  617. return SendMadcapMessage( // finally send the message and return
  618. DhcpContext,
  619. size,
  620. pdwXid
  621. );
  622. }
  623. DWORD // status
  624. SendMadcapRequest( //
  625. IN PDHCP_CONTEXT DhcpContext, // sned out for this context
  626. IN PIPNG_ADDRESS pScopeID,
  627. IN PMCAST_LEASE_REQUEST pAddrRequest,
  628. IN DWORD SelectedServer, // is there a prefernce for a server?
  629. IN OUT DWORD *pdwXid // use this Xid (if zero fill something and return it)
  630. ) {
  631. DWORD size;
  632. WIDE_OPTION UNALIGNED * option;
  633. LPBYTE OptionEnd;
  634. BYTE ServerId[6];
  635. WORD AddrFamily = htons(MADCAP_ADDR_FAMILY_V4);
  636. option = FormatMadcapCommonMessage(DhcpContext, MADCAP_REQUEST_MESSAGE);
  637. OptionEnd = (LPBYTE)(DhcpContext->MadcapMessageBuffer) + DHCP_SEND_MESSAGE_SIZE;
  638. option = AppendMadcapAddressList(
  639. option,
  640. (DWORD UNALIGNED *)pAddrRequest->pAddrBuf,
  641. pAddrRequest->AddrCount,
  642. OptionEnd
  643. );
  644. option = AppendWideOption(
  645. option,
  646. MADCAP_OPTION_MCAST_SCOPE,
  647. (LPBYTE)&pScopeID->IpAddrV4,
  648. sizeof (pScopeID->IpAddrV4),
  649. OptionEnd
  650. );
  651. if (pAddrRequest->LeaseDuration) {
  652. DWORD TimeNow = (DWORD)time(NULL);
  653. DWORD Lease = htonl(pAddrRequest->LeaseDuration);
  654. option = AppendWideOption(
  655. option,
  656. MADCAP_OPTION_LEASE_TIME,
  657. (LPBYTE)&Lease,
  658. sizeof (Lease),
  659. OptionEnd
  660. );
  661. }
  662. if( pAddrRequest->MinLeaseDuration ) {
  663. DWORD MinLease = htonl(pAddrRequest->MinLeaseDuration);
  664. option = AppendWideOption(
  665. option,
  666. MADCAP_OPTION_MIN_LEASE_TIME,
  667. (LPBYTE)&MinLease,
  668. sizeof(MinLease),
  669. OptionEnd
  670. );
  671. }
  672. if( pAddrRequest->MaxLeaseStartTime ) {
  673. DWORD TimeNow = htonl((DWORD)time(NULL));
  674. DWORD StartTime = htonl(pAddrRequest->MaxLeaseStartTime);
  675. option = AppendWideOption(
  676. option,
  677. MADCAP_OPTION_MAX_START_TIME,
  678. (LPBYTE)&StartTime,
  679. sizeof (StartTime),
  680. OptionEnd
  681. );
  682. if( !(pAddrRequest->LeaseStartTime) ) {
  683. //
  684. // if lease start time specified, then current time
  685. // option will be added at a later point
  686. //
  687. option = AppendWideOption(
  688. option,
  689. MADCAP_OPTION_TIME,
  690. (LPBYTE)&TimeNow,
  691. sizeof (TimeNow),
  692. OptionEnd
  693. );
  694. }
  695. }
  696. if (pAddrRequest->LeaseStartTime) {
  697. DWORD TimeNow = htonl((DWORD)time(NULL));
  698. DWORD StartTime = htonl(pAddrRequest->LeaseStartTime);
  699. option = AppendWideOption(
  700. option,
  701. MADCAP_OPTION_START_TIME,
  702. (LPBYTE)&StartTime,
  703. sizeof (StartTime),
  704. OptionEnd
  705. );
  706. option = AppendWideOption(
  707. option,
  708. MADCAP_OPTION_TIME,
  709. (LPBYTE)&TimeNow,
  710. sizeof (TimeNow),
  711. OptionEnd
  712. );
  713. }
  714. memcpy(ServerId, &AddrFamily, 2);
  715. memcpy(ServerId + 2, &SelectedServer, 4);
  716. option = AppendWideOption(
  717. option, // append this option to talk to that server alone
  718. MADCAP_OPTION_SERVER_ID,
  719. ServerId,
  720. sizeof( ServerId ),
  721. OptionEnd
  722. );
  723. option = AppendWideOption( option, MADCAP_OPTION_END, NULL, 0, OptionEnd );
  724. size = (DWORD)((PBYTE)option - (PBYTE)DhcpContext->MadcapMessageBuffer);
  725. return SendMadcapMessage( // finally send the message and return
  726. DhcpContext,
  727. size,
  728. pdwXid
  729. );
  730. }
  731. DWORD // status
  732. SendMadcapRenew( // send an inform packet after filling required options
  733. IN PDHCP_CONTEXT DhcpContext, // sned out for this context
  734. IN PMCAST_LEASE_REQUEST pAddrRequest,
  735. IN OUT DWORD *pdwXid // use this Xid (if zero fill something and return it)
  736. ) {
  737. DWORD size;
  738. WIDE_OPTION UNALIGNED * option;
  739. LPBYTE OptionEnd;
  740. option = FormatMadcapCommonMessage(DhcpContext, MADCAP_RENEW_MESSAGE);
  741. OptionEnd = (LPBYTE)(DhcpContext->MadcapMessageBuffer) + DHCP_SEND_MESSAGE_SIZE;
  742. if (pAddrRequest->LeaseDuration) {
  743. DWORD Lease = htonl(pAddrRequest->LeaseDuration);
  744. option = AppendWideOption(
  745. option,
  746. MADCAP_OPTION_LEASE_TIME,
  747. (LPBYTE)&Lease,
  748. sizeof (Lease),
  749. OptionEnd
  750. );
  751. }
  752. if( pAddrRequest->MinLeaseDuration ) {
  753. DWORD MinLease = htonl(pAddrRequest->MinLeaseDuration);
  754. option = AppendWideOption(
  755. option,
  756. MADCAP_OPTION_MIN_LEASE_TIME,
  757. (LPBYTE)&MinLease,
  758. sizeof(MinLease),
  759. OptionEnd
  760. );
  761. }
  762. if( pAddrRequest->MaxLeaseStartTime ) {
  763. DWORD TimeNow = htonl((DWORD)time(NULL));
  764. DWORD StartTime = htonl(pAddrRequest->MaxLeaseStartTime);
  765. option = AppendWideOption(
  766. option,
  767. MADCAP_OPTION_MAX_START_TIME,
  768. (LPBYTE)&StartTime,
  769. sizeof (StartTime),
  770. OptionEnd
  771. );
  772. if( !(pAddrRequest->LeaseStartTime) ) {
  773. //
  774. // if lease start time specified, then current time
  775. // option will be added at a later point
  776. //
  777. option = AppendWideOption(
  778. option,
  779. MADCAP_OPTION_TIME,
  780. (LPBYTE)&TimeNow,
  781. sizeof (TimeNow),
  782. OptionEnd
  783. );
  784. }
  785. }
  786. if (pAddrRequest->LeaseStartTime) {
  787. DWORD TimeNow = htonl((DWORD)time(NULL));
  788. DWORD StartTime = htonl(pAddrRequest->LeaseStartTime);
  789. option = AppendWideOption(
  790. option,
  791. MADCAP_OPTION_START_TIME,
  792. (LPBYTE)&StartTime,
  793. sizeof (StartTime),
  794. OptionEnd
  795. );
  796. option = AppendWideOption(
  797. option,
  798. MADCAP_OPTION_TIME,
  799. (LPBYTE)&TimeNow,
  800. sizeof (TimeNow),
  801. OptionEnd
  802. );
  803. }
  804. option = AppendWideOption( option, MADCAP_OPTION_END, NULL, 0, OptionEnd );
  805. size = (DWORD)((PBYTE)option - (PBYTE)DhcpContext->MadcapMessageBuffer);
  806. return SendMadcapMessage( // finally send the message and return
  807. DhcpContext,
  808. size,
  809. pdwXid
  810. );
  811. }
  812. DWORD // status
  813. SendMadcapRelease( // send an inform packet after filling required options
  814. IN PDHCP_CONTEXT DhcpContext, // sned out for this context
  815. IN OUT DWORD *pdwXid // use this Xid (if zero fill something and return it)
  816. ) {
  817. DWORD size;
  818. WIDE_OPTION UNALIGNED * option;
  819. LPBYTE OptionEnd;
  820. option = FormatMadcapCommonMessage(DhcpContext, MADCAP_RELEASE_MESSAGE);
  821. OptionEnd = (LPBYTE)(DhcpContext->MadcapMessageBuffer) + DHCP_SEND_MESSAGE_SIZE;
  822. option = AppendWideOption( option, MADCAP_OPTION_END, NULL, 0, OptionEnd );
  823. size = (DWORD)((PBYTE)option - (PBYTE)DhcpContext->MadcapMessageBuffer);
  824. return SendMadcapMessage( // finally send the message and return
  825. DhcpContext,
  826. size,
  827. pdwXid
  828. );
  829. }
  830. #define RATIO 1
  831. DWORD
  832. GetSpecifiedMadcapMessage(
  833. PDHCP_CONTEXT DhcpContext,
  834. PDWORD BufferLength,
  835. DWORD TransactionId,
  836. DWORD TimeToWait
  837. )
  838. /*++
  839. Routine Description:
  840. This function waits TimeToWait seconds to receives the specified
  841. DHCP response.
  842. Arguments:
  843. DhcpContext - A pointer to a DHCP context block.
  844. BufferLength - Returns the size of the input buffer.
  845. TransactionID - A filter. Wait for a message with this TID.
  846. TimeToWait - Time, in milli seconds, to wait for the message.
  847. Return Value:
  848. The status of the operation. If the specified message has been
  849. been returned, the status is ERROR_TIMEOUT.
  850. --*/
  851. {
  852. struct sockaddr socketName;
  853. int socketNameSize = sizeof( socketName );
  854. struct timeval timeout;
  855. time_t startTime, now;
  856. DWORD error;
  857. time_t actualTimeToWait;
  858. SOCKET clientSocket;
  859. fd_set readSocketSet;
  860. PMADCAP_MESSAGE MadcapMessage;
  861. startTime = time( NULL );
  862. actualTimeToWait = TimeToWait;
  863. //
  864. // Setup the file descriptor set for select.
  865. //
  866. clientSocket = ((PLOCAL_CONTEXT_INFO)DhcpContext->LocalInformation)->Socket;
  867. MadcapMessage = DhcpContext->MadcapMessageBuffer;
  868. FD_ZERO( &readSocketSet );
  869. FD_SET( clientSocket, &readSocketSet );
  870. while ( 1 ) {
  871. timeout.tv_sec = (long)(actualTimeToWait / RATIO);
  872. timeout.tv_usec = (long)(actualTimeToWait % RATIO);
  873. DhcpPrint((DEBUG_TRACE, "Select: waiting for: %ld seconds\n", actualTimeToWait));
  874. error = select( 0, &readSocketSet, NULL, NULL, &timeout );
  875. if ( error == 0 ) {
  876. //
  877. // Timeout before read data is available.
  878. //
  879. DhcpPrint(( DEBUG_ERRORS, "Recv timed out\n", 0 ));
  880. error = ERROR_TIMEOUT;
  881. break;
  882. }
  883. error = recvfrom(
  884. clientSocket,
  885. (PCHAR)MadcapMessage,
  886. *BufferLength,
  887. 0,
  888. &socketName,
  889. &socketNameSize
  890. );
  891. if ( error == SOCKET_ERROR ) {
  892. error = WSAGetLastError();
  893. DhcpPrint(( DEBUG_ERRORS, "Recv failed, error = %ld\n", error ));
  894. if( WSAECONNRESET != error ) break;
  895. //
  896. // ignore connreset -- this could be caused by someone sending random ICMP port unreachable.
  897. //
  898. } else if (error <= MADCAP_MESSAGE_FIXED_PART_SIZE) {
  899. DhcpPrint(( DEBUG_PROTOCOL, "Received a too short madcap message, length = %lx\n",
  900. error ));
  901. } else if (MadcapMessage->TransactionID == TransactionId ) {
  902. DhcpPrint(( DEBUG_PROTOCOL,
  903. "Received Message, XID = %lx\n",
  904. TransactionId));
  905. // just sanity check the remaining fields
  906. if ( MADCAP_VERSION == MadcapMessage->Version &&
  907. MADCAP_ADDR_FAMILY_V4 == ntohs(MadcapMessage->AddressFamily)) {
  908. MadcapDumpMessage(
  909. DEBUG_PROTOCOL_DUMP,
  910. MadcapMessage,
  911. DHCP_RECV_MESSAGE_SIZE
  912. );
  913. *BufferLength = error;
  914. error = NO_ERROR;
  915. break;
  916. }
  917. } else {
  918. DhcpPrint(( DEBUG_PROTOCOL,
  919. "Received a buffer with unknown XID = %lx\n",
  920. MadcapMessage->TransactionID ));
  921. }
  922. //
  923. // We received a message, but not the one we're interested in.
  924. // Reset the timeout to reflect elapsed time, and wait for
  925. // another message.
  926. //
  927. now = time( NULL );
  928. actualTimeToWait = TimeToWait - RATIO * (now - startTime);
  929. if ( (LONG)actualTimeToWait < 0 ) {
  930. error = ERROR_TIMEOUT;
  931. break;
  932. }
  933. }
  934. return( error );
  935. }
  936. //--------------------------------------------------------------------------------
  937. // This function decides if multicast offer is to be accepted or not.
  938. //--------------------------------------------------------------------------------
  939. BOOL
  940. AcceptMadcapMsg(
  941. IN DWORD MessageType, // message type to which this response came
  942. IN PDHCP_CONTEXT DhcpContext, // The context of the adapter..
  943. IN PMADCAP_OPTIONS MadcapOptions, // rcvd options.
  944. IN DHCP_IP_ADDRESS SelectedServer, // the server which we care about.
  945. OUT DWORD *Error // additional fatal error.
  946. ) {
  947. PMADCAP_MESSAGE MadcapMessage;
  948. *Error = ERROR_SUCCESS;
  949. MadcapMessage = DhcpContext->MadcapMessageBuffer;
  950. if ( !MadcapOptions->ServerIdentifier ){
  951. DhcpPrint((DEBUG_ERRORS, "Received no server identifier, dropping response\n"));
  952. return FALSE;
  953. }
  954. if ( !MadcapOptions->ClientGuid ){
  955. DhcpPrint((DEBUG_ERRORS, "Received no client identifier, dropping response\n"));
  956. return FALSE;
  957. }
  958. if (DhcpContext->ClientIdentifier.cbID != MadcapOptions->ClientGuidLength ||
  959. 0 != memcmp(DhcpContext->ClientIdentifier.pbID,
  960. MadcapOptions->ClientGuid,
  961. MadcapOptions->ClientGuidLength) ) {
  962. return FALSE;
  963. }
  964. if (MadcapOptions->MCastLeaseStartTime && !MadcapOptions->Time) {
  965. DhcpPrint((DEBUG_ERRORS, "Received start time but no current time\n"));
  966. return FALSE;
  967. }
  968. switch( MessageType ) {
  969. case MADCAP_INFORM_MESSAGE:
  970. if (MADCAP_ACK_MESSAGE != MadcapMessage->MessageType) {
  971. return FALSE;
  972. }
  973. break;
  974. case MADCAP_DISCOVER_MESSAGE:
  975. if (MADCAP_OFFER_MESSAGE != MadcapMessage->MessageType) {
  976. return FALSE;
  977. }
  978. if (!MadcapOptions->AddrRangeList) {
  979. return FALSE;
  980. }
  981. if (!MadcapOptions->LeaseTime) {
  982. return FALSE;
  983. }
  984. if (!MadcapOptions->McastScope) {
  985. return FALSE;
  986. }
  987. break;
  988. case MADCAP_RENEW_MESSAGE:
  989. case MADCAP_REQUEST_MESSAGE:
  990. if (MADCAP_NACK_MESSAGE == MadcapMessage->MessageType &&
  991. SelectedServer == *MadcapOptions->ServerIdentifier) {
  992. DhcpPrint((DEBUG_ERRORS, "Received NACK\n"));
  993. *Error = ERROR_ACCESS_DENIED;
  994. return FALSE;
  995. }
  996. if (MADCAP_ACK_MESSAGE != MadcapMessage->MessageType) {
  997. return FALSE;
  998. }
  999. if (SelectedServer && SelectedServer != *MadcapOptions->ServerIdentifier) {
  1000. return FALSE;
  1001. }
  1002. if (!MadcapOptions->LeaseTime) {
  1003. return FALSE;
  1004. }
  1005. if (!MadcapOptions->AddrRangeList) {
  1006. return FALSE;
  1007. }
  1008. if (!MadcapOptions->McastScope) {
  1009. return FALSE;
  1010. }
  1011. break;
  1012. case MADCAP_RELEASE_MESSAGE:
  1013. if (MADCAP_ACK_MESSAGE != MadcapMessage->MessageType) {
  1014. return FALSE;
  1015. }
  1016. break;
  1017. default:
  1018. DhcpAssert( FALSE );
  1019. DhcpPrint(( DEBUG_PROTOCOL, "Received Unknown Message.\n"));
  1020. return FALSE;
  1021. }
  1022. // Is this really necessary?
  1023. if (MadcapOptions->Error) {
  1024. return FALSE;
  1025. }
  1026. return TRUE; // accept this message.
  1027. }
  1028. VOID
  1029. MadcapExtractOptions( // Extract some important options alone or ALL
  1030. IN PDHCP_CONTEXT DhcpContext, // input context
  1031. IN LPBYTE OptStart, // start of the options stuff
  1032. IN DWORD MessageSize, // # of bytes of options
  1033. OUT PMADCAP_OPTIONS MadcapOptions, // this is where the options would be stored
  1034. IN OUT PLIST_ENTRY RecdOptions, // if !LiteOnly this gets filled with all incoming options
  1035. IN DWORD ServerId // if !LiteOnly this specifies the server which gave this
  1036. ) {
  1037. WIDE_OPTION UNALIGNED* NextOpt;
  1038. BYTE UNALIGNED* EndOpt;
  1039. WORD Size;
  1040. DWORD OptionType;
  1041. DWORD Error;
  1042. WORD AddrFamily;
  1043. EndOpt = OptStart + MessageSize; // all options should be < EndOpt;
  1044. RtlZeroMemory((LPBYTE)MadcapOptions, sizeof(*MadcapOptions));
  1045. if( 0 == MessageSize ) goto DropPkt; // nothing to do in this case
  1046. NextOpt = (WIDE_OPTION UNALIGNED*)OptStart;
  1047. while( NextOpt->OptionValue <= EndOpt &&
  1048. MADCAP_OPTION_END != (OptionType = ntohs(NextOpt->OptionType)) ) {
  1049. Size = ntohs(NextOpt->OptionLength);
  1050. if ((NextOpt->OptionValue + Size) > EndOpt) {
  1051. goto DropPkt;
  1052. }
  1053. switch( OptionType ) {
  1054. case MADCAP_OPTION_LEASE_TIME:
  1055. if( Size != sizeof(DWORD) ) goto DropPkt;
  1056. MadcapOptions->LeaseTime = (DWORD UNALIGNED *)NextOpt->OptionValue;
  1057. break;
  1058. case MADCAP_OPTION_SERVER_ID:
  1059. if (Size != 6) goto DropPkt;
  1060. AddrFamily = ntohs(*(WORD UNALIGNED *)NextOpt->OptionValue);
  1061. if ( MADCAP_ADDR_FAMILY_V4 != AddrFamily ) goto DropPkt;
  1062. MadcapOptions->ServerIdentifier = (DHCP_IP_ADDRESS UNALIGNED *)(NextOpt->OptionValue+2);
  1063. break;
  1064. case MADCAP_OPTION_LEASE_ID:
  1065. if( 0 == Size ) goto DropPkt;
  1066. MadcapOptions->ClientGuidLength = Size;
  1067. MadcapOptions->ClientGuid = NextOpt->OptionValue;
  1068. break;
  1069. case MADCAP_OPTION_MCAST_SCOPE:
  1070. if( Size != sizeof(DWORD) ) goto DropPkt;
  1071. MadcapOptions->McastScope = (DWORD UNALIGNED *)NextOpt->OptionValue;
  1072. break;
  1073. case MADCAP_OPTION_START_TIME:
  1074. if ( Size != sizeof(DATE_TIME) ) goto DropPkt;
  1075. MadcapOptions->MCastLeaseStartTime = (DWORD UNALIGNED *)NextOpt->OptionValue;
  1076. break;
  1077. case MADCAP_OPTION_ADDR_LIST:
  1078. if( Size % 6 ) goto DropPkt;
  1079. MadcapOptions->AddrRangeList = NextOpt->OptionValue;
  1080. MadcapOptions->AddrRangeListSize = Size;
  1081. break;
  1082. case MADCAP_OPTION_TIME:
  1083. if( Size != sizeof(DWORD) ) goto DropPkt;
  1084. MadcapOptions->Time = (DWORD UNALIGNED *)NextOpt->OptionValue;
  1085. break;
  1086. case MADCAP_OPTION_FEATURE_LIST:
  1087. break;
  1088. case MADCAP_OPTION_RETRY_TIME:
  1089. if( Size != sizeof(DWORD) ) goto DropPkt;
  1090. MadcapOptions->RetryTime = (DWORD UNALIGNED *)NextOpt->OptionValue;
  1091. break;
  1092. case MADCAP_OPTION_ERROR:
  1093. if( Size != sizeof(DWORD) ) goto DropPkt;
  1094. MadcapOptions->Error = (DWORD UNALIGNED *)NextOpt->OptionValue;
  1095. break;
  1096. default:
  1097. // unknowm message, nothing to do.. especially dont log this
  1098. break;
  1099. }
  1100. if (RecdOptions) {
  1101. DhcpAssert(ServerId);
  1102. Error = MadcapAddIncomingOption( // Now add this option to the list
  1103. RecdOptions,
  1104. OptionType,
  1105. ServerId,
  1106. NextOpt->OptionValue,
  1107. Size,
  1108. (DWORD)INFINIT_TIME
  1109. );
  1110. if (ERROR_SUCCESS != Error) {
  1111. goto DropPkt;
  1112. }
  1113. }
  1114. NextOpt = (WIDE_OPTION UNALIGNED*)(NextOpt->OptionValue + Size);
  1115. } // while NextOpt < EndOpt
  1116. return;
  1117. DropPkt:
  1118. RtlZeroMemory(MadcapOptions, sizeof(MadcapOptions));
  1119. if(RecdOptions) DhcpFreeAllOptions(RecdOptions);// ok undo the options that we just added
  1120. }
  1121. DWORD
  1122. MadcapDoInform(
  1123. IN PDHCP_CONTEXT DhcpContext
  1124. )
  1125. /*++
  1126. Routine Description:
  1127. This routine does the inform part by sending inform messages and
  1128. collecting responses etc. on given context.
  1129. In case of no-response, no error is returned as a timeout is not
  1130. considered an error.
  1131. Arguments:
  1132. DhcpContext -- context to dhcp struct
  1133. fBroadcast -- should the inform be broadcast or unicast?
  1134. Return Values:
  1135. Win32 errors
  1136. --*/
  1137. {
  1138. time_t StartTime;
  1139. time_t TimeNow;
  1140. time_t TimeToWait;
  1141. DWORD Error;
  1142. DWORD Xid;
  1143. DWORD MessageSize;
  1144. DWORD RoundNum;
  1145. DWORD MessageCount;
  1146. DWORD LeaseExpirationTime;
  1147. MADCAP_OPTIONS MadcapOptions;
  1148. BOOL GotAck;
  1149. #define MIN_ACKS_FOR_INFORM MADCAP_QUERY_SCOPE_LIST_RETRIES
  1150. DWORD MadcapServers[MIN_ACKS_FOR_INFORM];
  1151. DhcpPrint((DEBUG_PROTOCOL, "MadcapDoInform entered\n"));
  1152. Xid = 0; // Will be generated by first SendDhcpPacket
  1153. MessageCount = 0; // total # of messages we have got
  1154. TimeToWait = MADCAP_QUERY_SCOPE_LIST_TIME * 1000;
  1155. TimeToWait += ((rand() * ((DWORD) 1000))/RAND_MAX);
  1156. TimeToWait /= 1000;
  1157. for( RoundNum = 0; RoundNum <= MADCAP_QUERY_SCOPE_LIST_RETRIES; RoundNum ++ ) {
  1158. if( RoundNum != MADCAP_QUERY_SCOPE_LIST_RETRIES ) {
  1159. Error = SendMadcapInform(DhcpContext, &Xid);
  1160. if( ERROR_SUCCESS != Error ) {
  1161. DhcpPrint((DEBUG_ERRORS, "SendMadcapInform: %ld\n", Error));
  1162. goto Cleanup;
  1163. } else {
  1164. DhcpPrint((DEBUG_PROTOCOL, "Sent DhcpInform\n"));
  1165. }
  1166. }
  1167. StartTime = time(NULL);
  1168. while ( TRUE ) { // wiat for the specified wait time
  1169. MessageSize = DHCP_RECV_MESSAGE_SIZE;
  1170. DhcpPrint((DEBUG_TRACE, "Waiting for ACK[Xid=%x]: %ld seconds\n",Xid, TimeToWait));
  1171. Error = GetSpecifiedMadcapMessage( // try to receive an ACK
  1172. DhcpContext,
  1173. &MessageSize,
  1174. Xid,
  1175. (DWORD)TimeToWait
  1176. );
  1177. if ( Error == ERROR_TIMEOUT ) break;
  1178. if( Error != ERROR_SUCCESS ) {
  1179. DhcpPrint((DEBUG_ERRORS, "GetSpecifiedMadcapMessage: %ld\n", Error));
  1180. goto Cleanup;
  1181. }
  1182. MadcapExtractOptions( // Need to see if this is an ACK
  1183. DhcpContext,
  1184. (LPBYTE)&DhcpContext->MadcapMessageBuffer->Option,
  1185. MessageSize - MADCAP_MESSAGE_FIXED_PART_SIZE,
  1186. &MadcapOptions, // check for only expected options
  1187. NULL, // unused
  1188. 0 // unused
  1189. );
  1190. GotAck = AcceptMadcapMsg( // check up and see if we find this offer kosher
  1191. MADCAP_INFORM_MESSAGE,
  1192. DhcpContext,
  1193. &MadcapOptions,
  1194. 0,
  1195. &Error
  1196. );
  1197. if (GotAck) {
  1198. ULONG i;
  1199. for( i = 0; i < MessageCount ; i ++ ) {
  1200. if( MadcapServers[i] == *MadcapOptions.ServerIdentifier ) {
  1201. break;
  1202. }
  1203. }
  1204. if( i == MessageCount && MessageCount < MIN_ACKS_FOR_INFORM ) {
  1205. MessageCount ++;
  1206. MadcapServers[i] = *MadcapOptions.ServerIdentifier;
  1207. }
  1208. DhcpPrint((DEBUG_TRACE, "Received %ld ACKS so far\n", MessageCount));
  1209. MadcapExtractOptions( // do FULL options..
  1210. DhcpContext,
  1211. (LPBYTE)&DhcpContext->MadcapMessageBuffer->Option,
  1212. MessageSize - MADCAP_MESSAGE_FIXED_PART_SIZE,
  1213. &MadcapOptions,
  1214. &(DhcpContext->RecdOptionsList),
  1215. *MadcapOptions.ServerIdentifier
  1216. );
  1217. }
  1218. TimeNow = time(NULL); // Reset the time values to reflect new time
  1219. if( TimeToWait < (TimeNow - StartTime) ) {
  1220. break; // no more time left to wait..
  1221. }
  1222. TimeToWait -= (TimeNow - StartTime); // recalculate time now
  1223. StartTime = TimeNow; // reset start time also
  1224. } // end of while ( TimeToWait > 0)
  1225. if( MessageCount >= MIN_ACKS_FOR_INFORM ) goto Cleanup;
  1226. if( RoundNum != 0 && MessageCount != 0 ) goto Cleanup;
  1227. TimeToWait = MADCAP_QUERY_SCOPE_LIST_TIME ;
  1228. } // for (RoundNum = 0; RoundNum < nInformsToSend ; RoundNum ++ )
  1229. Cleanup:
  1230. CloseDhcpSocket(DhcpContext);
  1231. if( MessageCount ) Error = ERROR_SUCCESS;
  1232. DhcpPrint((DEBUG_PROTOCOL, "MadcapDoInform: got %d ACKS (returning %ld)\n", MessageCount,Error));
  1233. return Error;
  1234. }
  1235. DWORD
  1236. CopyMScopeList(
  1237. IN OUT PMCAST_SCOPE_ENTRY pScopeList,
  1238. IN OUT PDWORD pScopeLen,
  1239. OUT PDWORD pScopeCount
  1240. )
  1241. /*++
  1242. Routine Description:
  1243. This routine obtains the multicast scope list from the Madcap
  1244. server. It sends DHCPINFORM to Madcap multicast address and
  1245. collects all the responses.
  1246. Arguments:
  1247. Return Value:
  1248. The status of the operation.
  1249. --*/
  1250. {
  1251. PMCAST_SCOPE_ENTRY pScopeSource;
  1252. DWORD i;
  1253. LOCK_MSCOPE_LIST();
  1254. if ( *pScopeLen >= gMadcapScopeList->ScopeLen ) {
  1255. RtlCopyMemory( pScopeList, gMadcapScopeList->pScopeBuf, gMadcapScopeList->ScopeLen );
  1256. *pScopeLen = gMadcapScopeList->ScopeLen;
  1257. *pScopeCount = gMadcapScopeList->ScopeCount;
  1258. // remember the start pointer because we need to remap all the buffers into client space.
  1259. pScopeSource = gMadcapScopeList->pScopeBuf;
  1260. UNLOCK_MSCOPE_LIST();
  1261. // now remap UNICODE_STRING scope desc to client address space.
  1262. for (i=0;i<*pScopeCount;i++) {
  1263. pScopeList[i].ScopeDesc.Buffer = (USHORT *) ((PBYTE)pScopeList +
  1264. ((PBYTE)pScopeList[i].ScopeDesc.Buffer - (PBYTE)pScopeSource));
  1265. }
  1266. return ERROR_SUCCESS;
  1267. } else {
  1268. UNLOCK_MSCOPE_LIST();
  1269. return ERROR_INSUFFICIENT_BUFFER;
  1270. }
  1271. }
  1272. DWORD
  1273. StoreMScopeList(
  1274. IN PDHCP_CONTEXT pContext,
  1275. IN BOOL NewList
  1276. )
  1277. /*++
  1278. Routine Description:
  1279. This routine stores the scope list it retrieved from the inform requests
  1280. into the global scope list..
  1281. the scope option is of the following form.
  1282. ---------------------------------
  1283. | code (2 byte) | length (2byte)|
  1284. ---------------------------------
  1285. | count ( 4 bytes ) |
  1286. ---------------------------------
  1287. | Scope list
  1288. ---------------------------------
  1289. where scope list is of the following form
  1290. --------------------------------------------------------------------------
  1291. | scope ID(4 byte) | Last Addr(4/16) |TTL(1) | Count (1) | Description...|
  1292. --------------------------------------------------------------------------
  1293. where scope description is of the following form
  1294. Language Tag
  1295. --------------------------------------------------------------
  1296. | Flags(1) | Tag Length(1) | Tag...| Name Length(1) | Name...|
  1297. --------------------------------------------------------------
  1298. Arguments:
  1299. pContext - pointer to the context to be used during inform
  1300. NewList - TRUE if a new list is to be created o/w prepend the
  1301. current list.
  1302. Return Value:
  1303. The status of the operation.
  1304. --*/
  1305. {
  1306. PBYTE pOptBuf;
  1307. PBYTE pOptBufEnd;
  1308. PLIST_ENTRY pOptionList;
  1309. PDHCP_OPTION pScopeOption, pFirstOption, pPrevOption;
  1310. DWORD TotalNewScopeDescLen;
  1311. DWORD TotalNewScopeCount;
  1312. DWORD TotalNewScopeListMem;
  1313. PMCAST_SCOPE_LIST pScopeList;
  1314. PMCAST_SCOPE_ENTRY pNextScope;
  1315. LPWSTR pNextUnicodeBuf;
  1316. DWORD TotalCurrScopeListMem;
  1317. DWORD TotalCurrScopeCount;
  1318. DWORD Error;
  1319. DWORD IpAddrLen;
  1320. BOOL WellFormed;
  1321. // MBUG - make sure we collect options from all the servers when
  1322. // we do dhcpinform.
  1323. // initialize variables.
  1324. TotalNewScopeCount = TotalCurrScopeCount = 0;
  1325. TotalNewScopeDescLen = 0;
  1326. pScopeList = NULL;
  1327. Error = ERROR_SUCCESS;
  1328. LOCK_MSCOPE_LIST();
  1329. if (FALSE == NewList) {
  1330. TotalCurrScopeListMem = gMadcapScopeList->ScopeLen;
  1331. TotalCurrScopeCount = gMadcapScopeList->ScopeCount;
  1332. DhcpPrint(( DEBUG_API, "StoreMScopeList: appending to CurrScopeLen %ld, ScopeCount %ld\n",
  1333. gMadcapScopeList->ScopeLen, gMadcapScopeList->ScopeCount ));
  1334. }
  1335. // First calculate the space required for the scope list.
  1336. // pFirstOption is used to track that we traverse the list only once
  1337. pOptionList = &pContext->RecdOptionsList;
  1338. pFirstOption = NULL;
  1339. WellFormed = TRUE;
  1340. while ( ( pScopeOption = DhcpFindOption(
  1341. pOptionList,
  1342. MADCAP_OPTION_MCAST_SCOPE_LIST,
  1343. FALSE,
  1344. NULL,
  1345. 0,
  1346. 0 //dont care about serverid
  1347. )) &&
  1348. ( pScopeOption != pFirstOption ) ) {
  1349. DWORD ScopeCount;
  1350. DWORD i;
  1351. // point to the next entry in the list.
  1352. pOptionList = &pScopeOption->OptionList;
  1353. // set the pFirstOption if it is not set already.
  1354. if ( !pFirstOption ) {
  1355. pFirstOption = pScopeOption;
  1356. IpAddrLen = (pScopeOption->OptionVer.Proto == PROTO_MADCAP_V6 ? 16 : 4);
  1357. }
  1358. // if the last option was not well formatted from the list
  1359. // then remove it from the list.
  1360. if (!WellFormed) {
  1361. DhcpDelOption(pPrevOption);
  1362. //we may need to reset first option pointer.
  1363. if (pPrevOption == pFirstOption) {
  1364. pFirstOption = pScopeOption;
  1365. }
  1366. } else {
  1367. WellFormed = FALSE; // set it back to false for this iteration.
  1368. }
  1369. // save the prev option pointer
  1370. pPrevOption = pScopeOption;
  1371. pOptBuf = pScopeOption->Data;
  1372. pOptBufEnd = pScopeOption->Data + pScopeOption->DataLen;
  1373. ScopeCount = 0;
  1374. // Read the scope count
  1375. if ( pOptBuf < pOptBufEnd ) {
  1376. ScopeCount = *pOptBuf;
  1377. pOptBuf ++;
  1378. }
  1379. else continue;
  1380. for ( i=0;i<ScopeCount;i++ ) {
  1381. DWORD ScopeDescLen;
  1382. DWORD ScopeDescWLen;
  1383. PBYTE pScopeDesc;
  1384. DWORD NameCount, TagLen;
  1385. // skip the scopeid, last addr and ttl
  1386. pOptBuf += (2*IpAddrLen + 1);
  1387. // read name count
  1388. if (pOptBuf < pOptBufEnd) {
  1389. NameCount = *pOptBuf;
  1390. pOptBuf++;
  1391. } else break;
  1392. if (0 == NameCount) {
  1393. break;
  1394. }
  1395. do {
  1396. // Skip flags
  1397. pOptBuf++;
  1398. // read language tag len
  1399. if (pOptBuf < pOptBufEnd) {
  1400. TagLen = *pOptBuf;
  1401. pOptBuf++;
  1402. }else break;
  1403. // skip the tag
  1404. pOptBuf += TagLen;
  1405. // Read the name length
  1406. if (pOptBuf < pOptBufEnd) {
  1407. ScopeDescLen = *pOptBuf;
  1408. ScopeDescWLen = ConvertUTF8ToUnicode(pOptBuf+1, *pOptBuf, NULL, 0);
  1409. pOptBuf ++;
  1410. } else break;
  1411. // pick the scope name
  1412. pScopeDesc = pOptBuf;
  1413. pOptBuf += ScopeDescLen;
  1414. }while(--NameCount);
  1415. // if formatted correctly namecount should drop to 0
  1416. if (0 != NameCount) {
  1417. break;
  1418. }
  1419. // update total desc len count.
  1420. if ( pOptBuf <= pOptBufEnd ) {
  1421. if (pScopeDesc[ScopeDescLen-1]) { // if not NULL terminated.
  1422. ScopeDescWLen++;
  1423. }
  1424. TotalNewScopeDescLen += ScopeDescWLen * sizeof(WCHAR);
  1425. TotalNewScopeCount++;
  1426. // Set the wellformed to true so that this option stays
  1427. WellFormed = TRUE;
  1428. }
  1429. else break;
  1430. }
  1431. }
  1432. if ( !TotalNewScopeCount ) {
  1433. DhcpPrint((DEBUG_ERRORS, "StoreMScopeList - no scopes found in the options, bad format..\n"));
  1434. Error = ERROR_BAD_FORMAT;
  1435. goto Cleanup;
  1436. }
  1437. DhcpPrint(( DEBUG_API, "TotalNewScopeCount %d, TotalNewScopeDescLen %d\n",TotalNewScopeCount,TotalNewScopeDescLen));
  1438. // now allocate the memory.
  1439. TotalNewScopeListMem = ROUND_UP_COUNT( sizeof(MCAST_SCOPE_LIST) + // scope list struct
  1440. sizeof(MCAST_SCOPE_ENTRY) * (TotalNewScopeCount -1),
  1441. ALIGN_WORST) + // scope buffers.
  1442. TotalNewScopeDescLen; // scope descriptors,
  1443. if (FALSE == NewList) {
  1444. TotalNewScopeListMem += TotalCurrScopeListMem;
  1445. TotalNewScopeCount += TotalCurrScopeCount;
  1446. }
  1447. pScopeList = DhcpAllocateMemory( TotalNewScopeListMem );
  1448. if ( !pScopeList ) {
  1449. UNLOCK_MSCOPE_LIST();
  1450. return ERROR_NOT_ENOUGH_MEMORY;
  1451. }
  1452. RtlZeroMemory( pScopeList, TotalNewScopeListMem );
  1453. pScopeList->ScopeCount = 0; // we will fill this up as we go.
  1454. pScopeList->ScopeLen = TotalNewScopeListMem - sizeof(MCAST_SCOPE_LIST) + sizeof(MCAST_SCOPE_ENTRY);
  1455. // set the first scope pointer.
  1456. pNextScope = pScopeList->pScopeBuf;
  1457. // unicode strings starts after all the fixed sized scope structures.
  1458. pNextUnicodeBuf = (LPWSTR)((PBYTE)pScopeList +
  1459. ROUND_UP_COUNT( sizeof(MCAST_SCOPE_LIST) + // scope list struct
  1460. sizeof(MCAST_SCOPE_ENTRY) * (TotalNewScopeCount -1),
  1461. ALIGN_WORST)); // scope buffers.
  1462. DhcpPrint(( DEBUG_API, "ScopeList %lx TotalNewScopeListMem %d, ScopeDescBuff %lx\n",
  1463. pScopeList, TotalNewScopeListMem,pNextUnicodeBuf));
  1464. // now repeat the loop and fill up the scopelist.
  1465. pOptionList = &pContext->RecdOptionsList;
  1466. pFirstOption = NULL;
  1467. while ( ( pScopeOption = DhcpFindOption(
  1468. pOptionList,
  1469. MADCAP_OPTION_MCAST_SCOPE_LIST,
  1470. FALSE,
  1471. NULL,
  1472. 0,
  1473. 0 //dont care about serverid
  1474. )) &&
  1475. ( pScopeOption != pFirstOption ) ) {
  1476. DWORD ScopeCount;
  1477. DWORD i;
  1478. DHCP_IP_ADDRESS ServerIpAddr;
  1479. // point to the next entry in the list.
  1480. pOptionList = &pScopeOption->OptionList;
  1481. // set the pFirstOption if it is not set already.
  1482. if ( !pFirstOption ) {
  1483. pFirstOption = pScopeOption;
  1484. }
  1485. pOptBuf = pScopeOption->Data;
  1486. DhcpPrint(( DEBUG_API, "MScopeOption - Data %lx\n", pOptBuf ));
  1487. pOptBufEnd = pScopeOption->Data + pScopeOption->DataLen;
  1488. // store ipaddr
  1489. ServerIpAddr = pScopeOption->ServerId;
  1490. DhcpPrint(( DEBUG_API, "MScopeOption - ServerIpAddr %lx\n", ServerIpAddr ));
  1491. // read the scope count.
  1492. ScopeCount = *pOptBuf; pOptBuf++;
  1493. DhcpPrint(( DEBUG_API, "MScopeOption - ScopeCount %ld\n", ScopeCount ));
  1494. for ( i=0;i<ScopeCount;i++ ) {
  1495. BYTE ScopeDescLen;
  1496. PBYTE pScopeDesc;
  1497. IPNG_ADDRESS ScopeID, LastAddr;
  1498. DWORD NameCount, TagLen;
  1499. DWORD TTL;
  1500. // read the scopeid, last addr.
  1501. RtlZeroMemory (&ScopeID, sizeof (ScopeID));
  1502. RtlCopyMemory (&ScopeID, pOptBuf, IpAddrLen);
  1503. pOptBuf += IpAddrLen;
  1504. RtlZeroMemory (&LastAddr, sizeof (ScopeID));
  1505. RtlCopyMemory (&LastAddr, pOptBuf, IpAddrLen);
  1506. pOptBuf += IpAddrLen;
  1507. DhcpPrint(( DEBUG_API, "MScopeOption - ScopeID %lx\n", ntohl(ScopeID.IpAddrV4) ));
  1508. DhcpPrint(( DEBUG_API, "MScopeOption - LastAddr %lx\n", ntohl(LastAddr.IpAddrV4) ));
  1509. TTL = *pOptBuf++;
  1510. NameCount = *pOptBuf++;
  1511. while (NameCount--) {
  1512. // MBUG ignore the flags for now
  1513. pOptBuf++;
  1514. TagLen = *pOptBuf++;
  1515. // MBUG ignore lang tag also
  1516. pOptBuf += TagLen;
  1517. ScopeDescLen = *pOptBuf++;
  1518. pScopeDesc = pOptBuf;
  1519. DhcpPrint(( DEBUG_API, "MScopeOption - ScopeDesc %lx ScopeDescLen %ld\n", pScopeDesc, ScopeDescLen ));
  1520. pOptBuf += ScopeDescLen;
  1521. }
  1522. if ( ScopeDescLen ) {
  1523. BYTE ScopeDescWLen;
  1524. WORD MaximumLength;
  1525. /* CHAR DescAnsi[256];
  1526. WORD MaximumLength;
  1527. RtlCopyMemory(DescAnsi, pScopeDesc, ScopeDescLen );
  1528. // null terminate it if necessary.
  1529. if ( pScopeDesc[ScopeDescLen - 1] ) {
  1530. DescAnsi[ScopeDescLen] = '\0';
  1531. MaximumLength = (ScopeDescLen + 1) * sizeof(WCHAR);
  1532. } else {
  1533. MaximumLength = (ScopeDescLen) * sizeof(WCHAR);
  1534. }
  1535. pNextUnicodeBuf = DhcpOemToUnicode( DescAnsi, pNextUnicodeBuf ); */
  1536. ScopeDescWLen = (BYTE)ConvertUTF8ToUnicode(pScopeDesc, ScopeDescLen, pNextUnicodeBuf, TotalNewScopeDescLen);
  1537. if ( pNextUnicodeBuf[ScopeDescWLen - 1] ) {
  1538. pNextUnicodeBuf[ScopeDescWLen] = L'\0';
  1539. MaximumLength = (ScopeDescWLen + 1) * sizeof(WCHAR);
  1540. } else {
  1541. MaximumLength = (ScopeDescWLen) * sizeof(WCHAR);
  1542. }
  1543. TotalNewScopeDescLen -= MaximumLength;
  1544. DhcpPrint(( DEBUG_API, "MScopeOption - UnicodeScopeDesc %lx %ws\n",pNextUnicodeBuf, pNextUnicodeBuf));
  1545. RtlInitUnicodeString(&pNextScope->ScopeDesc, pNextUnicodeBuf );
  1546. pNextScope->ScopeDesc.MaximumLength = MaximumLength;
  1547. pNextUnicodeBuf = (LPWSTR)((PBYTE)pNextUnicodeBuf + MaximumLength);
  1548. DhcpAssert((PBYTE)pNextUnicodeBuf <= ((PBYTE)pScopeList + TotalNewScopeListMem));
  1549. } else {
  1550. // set the unicode descriptor string to NULL;
  1551. pNextScope->ScopeDesc.Length = pNextScope->ScopeDesc.MaximumLength = 0;
  1552. pNextScope->ScopeDesc.Buffer = NULL;
  1553. }
  1554. // everything looks good, now fill up the NextScope
  1555. pNextScope->ScopeCtx.ScopeID = ScopeID;
  1556. pNextScope->ScopeCtx.ServerID.IpAddrV4 = ServerIpAddr;
  1557. pNextScope->ScopeCtx.Interface.IpAddrV4 = pContext->IpAddress;
  1558. pNextScope->LastAddr = LastAddr;
  1559. pNextScope->TTL = TTL;
  1560. pNextScope++;
  1561. pScopeList->ScopeCount++;
  1562. }
  1563. }
  1564. DhcpAssert( pScopeList->ScopeCount == (TotalNewScopeCount - TotalCurrScopeCount) );
  1565. // now append the previous scope list if exist.
  1566. if (FALSE == NewList) {
  1567. DWORD CurrScopeCount;
  1568. PMCAST_SCOPE_ENTRY CurrScopeNextPtr;
  1569. CurrScopeCount = gMadcapScopeList->ScopeCount;
  1570. CurrScopeNextPtr = gMadcapScopeList->pScopeBuf;
  1571. while(CurrScopeCount--) {
  1572. *pNextScope = *CurrScopeNextPtr;
  1573. // now copy the unicode strings also.
  1574. RtlCopyMemory( pNextUnicodeBuf, CurrScopeNextPtr->ScopeDesc.Buffer, CurrScopeNextPtr->ScopeDesc.MaximumLength);
  1575. pNextScope->ScopeDesc.Buffer = pNextUnicodeBuf ;
  1576. pNextUnicodeBuf = (LPWSTR)((PBYTE)pNextUnicodeBuf + CurrScopeNextPtr->ScopeDesc.MaximumLength);
  1577. pNextScope++; CurrScopeNextPtr++;
  1578. }
  1579. pScopeList->ScopeCount += gMadcapScopeList->ScopeCount;
  1580. DhcpAssert( pScopeList->ScopeCount == TotalNewScopeCount);
  1581. }
  1582. // Finally copy this buffer to our global pointer.
  1583. // first free the existing list.
  1584. if (gMadcapScopeList) DhcpFreeMemory( gMadcapScopeList );
  1585. gMadcapScopeList = pScopeList;
  1586. Cleanup:
  1587. UNLOCK_MSCOPE_LIST();
  1588. return Error;
  1589. }
  1590. DWORD
  1591. ObtainMScopeList(
  1592. )
  1593. /*++
  1594. Routine Description:
  1595. This routine obtains the multicast scope list from the Madcap
  1596. server. It sends DHCPINFORM to Madcap multicast address and
  1597. collects all the responses.
  1598. Arguments:
  1599. Return Value:
  1600. The status of the operation.
  1601. --*/
  1602. {
  1603. MCAST_CLIENT_UID RequestID;
  1604. BYTE IDBuf[MCAST_CLIENT_ID_LEN];
  1605. PDHCP_CONTEXT pContext;
  1606. DWORD Error;
  1607. PMIB_IPADDRTABLE pIpAddrTable;
  1608. PLOCAL_CONTEXT_INFO localInfo;
  1609. DWORD i;
  1610. BOOL NewList;
  1611. pContext = NULL;
  1612. Error = ERROR_SUCCESS;
  1613. pIpAddrTable = NULL;
  1614. if ( !ShouldRequeryMScopeList() ) {
  1615. return ERROR_SUCCESS;
  1616. } else {
  1617. RequestID.ClientUID = IDBuf;
  1618. RequestID.ClientUIDLength = MCAST_CLIENT_ID_LEN;
  1619. Error = GenMadcapClientUID( RequestID.ClientUID, &RequestID.ClientUIDLength );
  1620. if ( ERROR_SUCCESS != Error)
  1621. goto Exit;
  1622. Error = CreateMadcapContext(&pContext, &RequestID, INADDR_ANY );
  1623. if ( ERROR_SUCCESS != Error )
  1624. goto Exit;
  1625. APICTXT_ENABLED(pContext); // mark the context as being created by the API
  1626. localInfo = pContext->LocalInformation;
  1627. // now get primary ipaddresses on each adapter.
  1628. Error = GetIpPrimaryAddresses(&pIpAddrTable);
  1629. if ( ERROR_SUCCESS != Error ) {
  1630. goto Exit;
  1631. }
  1632. DhcpPrint((DEBUG_API, "ObtainMScopeList: ipaddress table has %d addrs\n",
  1633. pIpAddrTable->dwNumEntries));
  1634. NewList = TRUE;
  1635. Error = ERROR_TIMEOUT;
  1636. for (i = 0; i < pIpAddrTable->dwNumEntries; i++) {
  1637. DWORD LocalError;
  1638. PMIB_IPADDRROW pAddrRow;
  1639. pAddrRow = &pIpAddrTable->table[i];
  1640. // if primary bit set this is a primary address.
  1641. if (0 == (pAddrRow->wType & MIB_IPADDR_PRIMARY) ||
  1642. 0 == pAddrRow->dwAddr ||
  1643. htonl(INADDR_LOOPBACK) == pAddrRow->dwAddr) {
  1644. continue;
  1645. }
  1646. DhcpPrint((DEBUG_API, "ObtainMScopeList: DoInform on %s interface\n",
  1647. DhcpIpAddressToDottedString(ntohl(pAddrRow->dwAddr)) ));
  1648. LocalError = ReInitializeMadcapSocket(&localInfo->Socket, pAddrRow->dwAddr);
  1649. if (ERROR_SUCCESS != LocalError) {
  1650. continue;
  1651. }
  1652. pContext->IpAddress = pAddrRow->dwAddr;
  1653. // now do the inform and get scope list.
  1654. LocalError = MadcapDoInform(pContext);
  1655. if ( ERROR_SUCCESS == LocalError ) {
  1656. // now copy the scope list.
  1657. LocalError = StoreMScopeList(pContext, NewList);
  1658. if (ERROR_SUCCESS == LocalError ) {
  1659. NewList = FALSE;
  1660. Error = ERROR_SUCCESS;
  1661. }
  1662. }
  1663. LOCK_OPTIONS_LIST();
  1664. DhcpDestroyOptionsList(&pContext->SendOptionsList, &DhcpGlobalClassesList);
  1665. DhcpDestroyOptionsList(&pContext->RecdOptionsList, &DhcpGlobalClassesList);
  1666. UNLOCK_OPTIONS_LIST();
  1667. }
  1668. Exit:
  1669. // signal the thread could be waiting on this.
  1670. LOCK_MSCOPE_LIST();
  1671. gMScopeQueryInProgress = FALSE;
  1672. UNLOCK_MSCOPE_LIST();
  1673. SetEvent( gMScopeQueryEvent );
  1674. if ( pContext ) {
  1675. DhcpDestroyContext( pContext );
  1676. }
  1677. if (pIpAddrTable) {
  1678. DhcpFreeMemory( pIpAddrTable );
  1679. }
  1680. return Error;
  1681. }
  1682. }
  1683. DWORD
  1684. GenMadcapClientUID(
  1685. OUT PBYTE pRequestID,
  1686. IN OUT PDWORD pRequestIDLen
  1687. )
  1688. /*++
  1689. Routine Description:
  1690. This routine generates a client UID.
  1691. Arguments:
  1692. pRequestID - pointer where client UID is to be stored.
  1693. pRequestIDLen - pointer where the length of request id is stored.
  1694. Return Value:
  1695. --*/
  1696. {
  1697. PULONG UID;
  1698. RPC_STATUS Status;
  1699. GUID RequestGuid;
  1700. DhcpAssert( pRequestID && pRequestIDLen );
  1701. if (*pRequestIDLen < MCAST_CLIENT_ID_LEN) {
  1702. DhcpPrint((DEBUG_ERRORS,"GenMadcapId - IDLen too small, %ld\n", *pRequestIDLen ));
  1703. return ERROR_INVALID_PARAMETER;
  1704. }
  1705. Status = UuidCreate( &RequestGuid );
  1706. if (Status != RPC_S_OK) {
  1707. Status = ERROR_LUIDS_EXHAUSTED;
  1708. }
  1709. *pRequestID++ = 0; // first octet is type and for guid the type is 0
  1710. *((GUID UNALIGNED *)pRequestID) = RequestGuid;
  1711. return Status;
  1712. }
  1713. DWORD
  1714. ObtainMadcapAddress(
  1715. IN PDHCP_CONTEXT DhcpContext,
  1716. IN PIPNG_ADDRESS pScopeID,
  1717. IN PMCAST_LEASE_REQUEST pAddrRequest,
  1718. IN OUT PMCAST_LEASE_RESPONSE pAddrResponse
  1719. )
  1720. /*++
  1721. Routine Description:
  1722. This routine attempts to obtains a new lease from a DHCP server.
  1723. Arguments:
  1724. DhcpContext - Points to a DHCP context block for the NIC to initialize.
  1725. MadcapOptions - Returns DHCP options returned by the DHCP server.
  1726. Return Value:
  1727. --*/
  1728. {
  1729. MADCAP_OPTIONS MadcapOptions;
  1730. DATE_TIME HostOrderLeaseTime;
  1731. DWORD Error;
  1732. time_t StartTime;
  1733. time_t InitialStartTime;
  1734. time_t TimeNow;
  1735. time_t TimeToWait;
  1736. DWORD Xid;
  1737. DWORD RoundNum;
  1738. DWORD MessageSize;
  1739. DWORD SelectedServer;
  1740. DWORD SelectedAddress;
  1741. DWORD LeaseExpiryTime;
  1742. BOOL GotOffer;
  1743. PMCAST_LEASE_REQUEST pRenewRequest;
  1744. Xid = 0; // generate xid on first send. keep it same throughout
  1745. SelectedServer = (DWORD)-1;
  1746. SelectedAddress = (DWORD)-1;
  1747. GotOffer = FALSE;
  1748. InitialStartTime = time(NULL);
  1749. Error = ERROR_SEM_TIMEOUT;
  1750. // Make private copy of the request so that we don't modify original request.
  1751. pRenewRequest = DhcpAllocateMemory(
  1752. sizeof(*pAddrRequest) +
  1753. sizeof(DWORD)*(pAddrRequest->AddrCount));
  1754. if (NULL == pRenewRequest) {
  1755. return ERROR_NOT_ENOUGH_MEMORY;
  1756. }
  1757. memcpy(pRenewRequest,pAddrRequest,sizeof(*pAddrRequest) );
  1758. pRenewRequest->pAddrBuf = (PBYTE)pRenewRequest + sizeof(*pRenewRequest);
  1759. if (pAddrRequest->pAddrBuf) {
  1760. memcpy(pRenewRequest->pAddrBuf, pAddrRequest->pAddrBuf, sizeof(DWORD)*(pAddrRequest->AddrCount));
  1761. }
  1762. for (RoundNum = 0; RoundNum < MADCAP_MAX_RETRIES; RoundNum++ ) {
  1763. Error = SendMadcapDiscover( // send a discover packet
  1764. DhcpContext,
  1765. pScopeID,
  1766. pAddrRequest,
  1767. &Xid
  1768. );
  1769. if ( Error != ERROR_SUCCESS ) { // can't really fail here
  1770. DhcpPrint((DEBUG_ERRORS, "Send Dhcp Discover failed, %ld.\n", Error));
  1771. return Error ;
  1772. }
  1773. DhcpPrint((DEBUG_PROTOCOL, "Sent DhcpDiscover Message.\n"));
  1774. TimeToWait = DhcpCalculateWaitTime(RoundNum, NULL);
  1775. StartTime = time(NULL);
  1776. while ( TimeToWait > 0 ) { // wait for specified time
  1777. MessageSize = DHCP_RECV_MESSAGE_SIZE;
  1778. DhcpPrint((DEBUG_TRACE, "Waiting for Offer: %ld seconds\n", TimeToWait));
  1779. Error = GetSpecifiedMadcapMessage( // try to receive an offer
  1780. DhcpContext,
  1781. &MessageSize,
  1782. Xid,
  1783. (DWORD)TimeToWait
  1784. );
  1785. if ( Error == ERROR_TIMEOUT ) { // get out and try another discover
  1786. DhcpPrint(( DEBUG_PROTOCOL, "Dhcp offer receive Timeout.\n" ));
  1787. break;
  1788. }
  1789. if ( ERROR_SUCCESS != Error ) { // unexpected error
  1790. DhcpPrint(( DEBUG_PROTOCOL, "Dhcp Offer receive failed, %ld.\n", Error ));
  1791. return Error ;
  1792. }
  1793. MadcapExtractOptions( // now extract basic information
  1794. DhcpContext,
  1795. (LPBYTE)&DhcpContext->MadcapMessageBuffer->Option,
  1796. MessageSize - MADCAP_MESSAGE_FIXED_PART_SIZE,
  1797. &MadcapOptions,
  1798. NULL,
  1799. 0
  1800. );
  1801. GotOffer = AcceptMadcapMsg( // check up and see if we find this offer kosher
  1802. MADCAP_DISCOVER_MESSAGE,
  1803. DhcpContext,
  1804. &MadcapOptions,
  1805. 0,
  1806. &Error
  1807. );
  1808. DhcpAssert(ERROR_SUCCESS == Error);
  1809. Error = ExpandMadcapAddressList(
  1810. MadcapOptions.AddrRangeList,
  1811. MadcapOptions.AddrRangeListSize,
  1812. (DWORD UNALIGNED *)pRenewRequest->pAddrBuf,
  1813. &pRenewRequest->AddrCount
  1814. );
  1815. if (ERROR_SUCCESS != Error) {
  1816. GotOffer = FALSE;
  1817. }
  1818. if (GotOffer) {
  1819. break;
  1820. }
  1821. TimeNow = time( NULL ); // calc the remaining wait time for this round
  1822. TimeToWait -= ((TimeNow - StartTime));
  1823. StartTime = TimeNow;
  1824. } // while (TimeToWait > 0 )
  1825. if(GotOffer) { // if we got an offer, everything should be fine
  1826. DhcpAssert(ERROR_SUCCESS == Error);
  1827. break;
  1828. }
  1829. } // for n tries... send discover.
  1830. if(!GotOffer ) { // did not get any valid offers
  1831. DhcpPrint((DEBUG_ERRORS, "ObtainMadcapAddress timed out\n"));
  1832. Error = ERROR_TIMEOUT ;
  1833. goto Cleanup;
  1834. }
  1835. DhcpPrint((DEBUG_PROTOCOL, "Successfully received a DhcpOffer (%s) ",
  1836. inet_ntoa(*(struct in_addr *)pRenewRequest->pAddrBuf) ));
  1837. DhcpPrint((DEBUG_PROTOCOL, "from %s.\n",
  1838. inet_ntoa(*(struct in_addr*)MadcapOptions.ServerIdentifier) ));
  1839. SelectedServer = *MadcapOptions.ServerIdentifier;
  1840. Error = RenewMadcapAddress(
  1841. DhcpContext,
  1842. pScopeID,
  1843. pRenewRequest,
  1844. pAddrResponse,
  1845. SelectedServer
  1846. );
  1847. Cleanup:
  1848. if (pRenewRequest) {
  1849. DhcpFreeMemory(pRenewRequest);
  1850. }
  1851. return Error;
  1852. }
  1853. DWORD
  1854. RenewMadcapAddress(
  1855. IN PDHCP_CONTEXT DhcpContext,
  1856. IN PIPNG_ADDRESS pScopeID,
  1857. IN PMCAST_LEASE_REQUEST pAddrRequest,
  1858. IN OUT PMCAST_LEASE_RESPONSE pAddrResponse,
  1859. IN DHCP_IP_ADDRESS SelectedServer
  1860. )
  1861. /*++
  1862. Routine Description:
  1863. This routine is called for two different purposes.
  1864. 1. To request an address for which we got offer.
  1865. 2. To renew an address.
  1866. Arguments:
  1867. DhcpContext - Points to a DHCP context block for the NIC to initialize.
  1868. pScopeID - ScopeId from which the address is to be renewed. for renewals
  1869. this is passed as null.
  1870. pAddrRequest - The lease info structure describing the request.
  1871. pAddrResponse - The lease info structure which receives the response data.
  1872. SelectedServer - If we are sending REQUEST message then this describes the server
  1873. from which we accepted the offer originally.
  1874. Return Value:
  1875. The status of the operation.
  1876. --*/
  1877. {
  1878. MADCAP_OPTIONS MadcapOptions;
  1879. DWORD Error;
  1880. DWORD Xid;
  1881. DWORD RoundNum;
  1882. size_t TimeToWait;
  1883. DWORD MessageSize;
  1884. DWORD LeaseTime;
  1885. DWORD LeaseExpiryTime;
  1886. time_t InitialStartTime;
  1887. time_t StartTime;
  1888. time_t TimeNow;
  1889. BOOL GotAck;
  1890. DATE_TIME HostOrderLeaseTime;
  1891. BOOL Renew;
  1892. Xid = 0; // new Xid will be generated first time
  1893. InitialStartTime = time(NULL);
  1894. GotAck = FALSE;
  1895. Error = ERROR_TIMEOUT;
  1896. Renew = (0 == SelectedServer);
  1897. for ( RoundNum = 0; RoundNum < MADCAP_MAX_RETRIES; RoundNum ++ ) {
  1898. if (Renew) {
  1899. Error = SendMadcapRenew(
  1900. DhcpContext,
  1901. pAddrRequest,
  1902. &Xid
  1903. );
  1904. } else {
  1905. Error = SendMadcapRequest( // send a request
  1906. DhcpContext,
  1907. pScopeID,
  1908. pAddrRequest,
  1909. SelectedServer, //
  1910. &Xid
  1911. );
  1912. }
  1913. if ( Error != ERROR_SUCCESS ) { // dont expect send to fail
  1914. DhcpPrint(( DEBUG_ERRORS,"Send request failed, %ld.\n", Error));
  1915. return Error ;
  1916. }
  1917. TimeToWait = DhcpCalculateWaitTime(RoundNum, NULL);
  1918. StartTime = time(NULL);
  1919. while ( TimeToWait > 0 ) { // try to recv message for this full period
  1920. MessageSize = DHCP_RECV_MESSAGE_SIZE;
  1921. Error = GetSpecifiedMadcapMessage( // expect to recv an ACK
  1922. DhcpContext,
  1923. &MessageSize,
  1924. Xid,
  1925. TimeToWait
  1926. );
  1927. if ( Error == ERROR_TIMEOUT ) { // No response, so resend DHCP REQUEST.
  1928. DhcpPrint(( DEBUG_PROTOCOL, "Dhcp ACK receive Timeout.\n" ));
  1929. break;
  1930. }
  1931. if ( ERROR_SUCCESS != Error ) { // unexpected error
  1932. DhcpPrint(( DEBUG_PROTOCOL, "Dhcp ACK receive failed, %ld.\n", Error ));
  1933. return Error ;
  1934. }
  1935. MadcapExtractOptions( // now extract basic information
  1936. DhcpContext,
  1937. (LPBYTE)&DhcpContext->MadcapMessageBuffer->Option,
  1938. MessageSize - MADCAP_MESSAGE_FIXED_PART_SIZE,
  1939. &MadcapOptions,
  1940. NULL,
  1941. 0
  1942. );
  1943. GotAck = AcceptMadcapMsg( // check up and see if we find this offer kosher
  1944. Renew ? MADCAP_RENEW_MESSAGE : MADCAP_REQUEST_MESSAGE,
  1945. DhcpContext,
  1946. &MadcapOptions,
  1947. SelectedServer,
  1948. &Error
  1949. );
  1950. if (ERROR_SUCCESS != Error) {
  1951. return Error;
  1952. }
  1953. // check that the ack came from the same server as the selected server.
  1954. if ( SelectedServer && SelectedServer != *MadcapOptions.ServerIdentifier ) {
  1955. GotAck = FALSE;
  1956. }
  1957. Error = ExpandMadcapAddressList(
  1958. MadcapOptions.AddrRangeList,
  1959. MadcapOptions.AddrRangeListSize,
  1960. (DWORD UNALIGNED *)pAddrResponse->pAddrBuf,
  1961. &pAddrResponse->AddrCount
  1962. );
  1963. if (ERROR_SUCCESS != Error) {
  1964. GotAck = FALSE;
  1965. }
  1966. if ( GotAck ) {
  1967. break;
  1968. }
  1969. TimeNow = time( NULL );
  1970. TimeToWait -= (TimeNow - StartTime);
  1971. StartTime = TimeNow;
  1972. } // while time to wait
  1973. if(TRUE == GotAck) { // if we got an ack, everything must be good
  1974. DhcpAssert(ERROR_SUCCESS == Error); // cannot have any errors
  1975. break;
  1976. }
  1977. DhcpContext->SecondsSinceBoot = (DWORD)(time(NULL) - InitialStartTime);
  1978. } // for RoundNum < MAX_RETRIES
  1979. if(!GotAck) {
  1980. DhcpPrint((DEBUG_ERRORS, "RenewMadcapAddress timed out\n"));
  1981. return ERROR_TIMEOUT;
  1982. }
  1983. if (0 == SelectedServer ) SelectedServer = *MadcapOptions.ServerIdentifier;
  1984. if( MadcapOptions.LeaseTime ) LeaseTime = ntohl(*MadcapOptions.LeaseTime);
  1985. else LeaseTime = 0;
  1986. pAddrResponse->ServerAddress.IpAddrV4 = SelectedServer;
  1987. time( &TimeNow );
  1988. pAddrResponse->LeaseStartTime = (LONG)TimeNow;
  1989. pAddrResponse->LeaseEndTime = (LONG)(TimeNow+LeaseTime);
  1990. DhcpPrint((DEBUG_PROTOCOL, "Accepted ACK (%s) ",
  1991. inet_ntoa(*(struct in_addr *)pAddrResponse->pAddrBuf) ));
  1992. DhcpPrint((DEBUG_PROTOCOL, "from %s.\n",
  1993. inet_ntoa(*(struct in_addr *)&SelectedServer)));
  1994. DhcpPrint((DEBUG_PROTOCOL, "Lease is %ld secs.\n", LeaseTime));
  1995. return ERROR_SUCCESS;
  1996. }
  1997. DWORD
  1998. ReleaseMadcapAddress(
  1999. PDHCP_CONTEXT DhcpContext
  2000. )
  2001. /*++
  2002. Routine Description:
  2003. This routine to releases a lease for an IP address. Since the
  2004. packet we send is not responded to, we assume that the release
  2005. works.
  2006. Arguments:
  2007. DhcpContext - Points to a DHCP context block for the NIC to initialize.
  2008. Return Value:
  2009. None.
  2010. --*/
  2011. {
  2012. DWORD Xid;
  2013. MADCAP_OPTIONS MadcapOptions;
  2014. DWORD Error;
  2015. time_t StartTime;
  2016. time_t InitialStartTime;
  2017. time_t TimeNow;
  2018. time_t TimeToWait;
  2019. DWORD RoundNum;
  2020. DWORD MessageSize;
  2021. BOOL GotAck;
  2022. Xid = 0; // new Xid will be generated first time
  2023. GotAck = FALSE;
  2024. InitialStartTime = time(NULL);
  2025. Error = ERROR_TIMEOUT;
  2026. for (RoundNum = 0; RoundNum < MADCAP_MAX_RETRIES; RoundNum++ ) {
  2027. Error = SendMadcapRelease( // send a discover packet
  2028. DhcpContext,
  2029. &Xid
  2030. );
  2031. if ( Error != ERROR_SUCCESS ) { // can't really fail here
  2032. DhcpPrint((DEBUG_ERRORS, "Send Dhcp Release failed, %ld.\n", Error));
  2033. return Error ;
  2034. }
  2035. DhcpPrint((DEBUG_PROTOCOL, "Sent DhcpRelease Message.\n"));
  2036. TimeToWait = DhcpCalculateWaitTime(RoundNum, NULL);
  2037. StartTime = time(NULL);
  2038. while ( TimeToWait > 0 ) { // wait for specified time
  2039. MessageSize = DHCP_RECV_MESSAGE_SIZE;
  2040. DhcpPrint((DEBUG_TRACE, "Waiting for Ack: %ld seconds\n", TimeToWait));
  2041. Error = GetSpecifiedMadcapMessage( // try to receive an offer
  2042. DhcpContext,
  2043. &MessageSize,
  2044. Xid,
  2045. (DWORD)TimeToWait
  2046. );
  2047. if ( Error == ERROR_TIMEOUT ) { // get out and try another discover
  2048. DhcpPrint(( DEBUG_PROTOCOL, "Dhcp Ack receive Timeout.\n" ));
  2049. break;
  2050. }
  2051. if ( ERROR_SUCCESS != Error ) { // unexpected error
  2052. DhcpPrint(( DEBUG_PROTOCOL, "Dhcp Ack receive failed, %ld.\n", Error ));
  2053. return Error ;
  2054. }
  2055. MadcapExtractOptions( // now extract basic information
  2056. DhcpContext,
  2057. (LPBYTE)&DhcpContext->MadcapMessageBuffer->Option,
  2058. MessageSize - MADCAP_MESSAGE_FIXED_PART_SIZE,
  2059. &MadcapOptions,
  2060. NULL,
  2061. 0
  2062. );
  2063. GotAck = AcceptMadcapMsg( // check up and see if we find this offer kosher
  2064. MADCAP_RELEASE_MESSAGE,
  2065. DhcpContext,
  2066. &MadcapOptions,
  2067. DhcpContext->DhcpServerAddress,
  2068. &Error
  2069. );
  2070. DhcpAssert(ERROR_SUCCESS == Error);
  2071. if (GotAck) {
  2072. break;
  2073. }
  2074. TimeNow = time( NULL ); // calc the remaining wait time for this round
  2075. TimeToWait -= ((TimeNow - StartTime));
  2076. StartTime = TimeNow;
  2077. } // while (TimeToWait > 0 )
  2078. if(GotAck) { // if we got an offer, everything should be fine
  2079. DhcpAssert(ERROR_SUCCESS == Error);
  2080. break;
  2081. }
  2082. } // for n tries... send discover.
  2083. if(!GotAck ) { // did not get any valid offers
  2084. DhcpPrint((DEBUG_ERRORS, "MadcapReleaseAddress timed out\n"));
  2085. Error = ERROR_TIMEOUT ;
  2086. } else {
  2087. DhcpPrint((DEBUG_PROTOCOL, "Successfully released the address\n" ));
  2088. Error = ERROR_SUCCESS;
  2089. }
  2090. return Error;
  2091. }