Source code of Windows XP (NT5)
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.

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