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.

1671 lines
42 KiB

  1. // Copyright (c) 1997, Microsoft Corporation, all rights reserved
  2. //
  3. // util.c
  4. // RAS L2TP WAN mini-port/call-manager driver
  5. // General utility routines
  6. //
  7. // 01/07/97 Steve Cobb
  8. #include "l2tpp.h"
  9. // Debug counts of oddities that should not be happening.
  10. //
  11. ULONG g_ulAllocTwFailures = 0;
  12. //-----------------------------------------------------------------------------
  13. // Local prototypes (alphabetically)
  14. //-----------------------------------------------------------------------------
  15. ULONG
  16. atoul(
  17. IN CHAR* pszNumber );
  18. VOID
  19. ReversePsz(
  20. IN OUT CHAR* psz );
  21. VOID
  22. TunnelWork(
  23. IN NDIS_WORK_ITEM* pWork,
  24. IN VOID* pContext );
  25. VOID
  26. ultoa(
  27. IN ULONG ul,
  28. OUT CHAR* pszBuf );
  29. //-----------------------------------------------------------------------------
  30. // General utility routines (alphabetically)
  31. //-----------------------------------------------------------------------------
  32. #if 0
  33. ULONGLONG g_llLastTime2 = 0;
  34. ULONGLONG g_llLastTime1 = 0;
  35. ULONGLONG g_llLastTime = 0;
  36. NDIS_SPIN_LOCK g_lockX;
  37. VOID
  38. XNdisGetCurrentSystemTime(
  39. IN LARGE_INTEGER* plrgTime )
  40. {
  41. static BOOLEAN f = 0;
  42. if (!f)
  43. {
  44. NdisAllocateSpinLock( &g_lockX );
  45. f = 1;
  46. }
  47. NdisGetCurrentSystemTime( plrgTime );
  48. NdisAcquireSpinLock( &g_lockX );
  49. {
  50. LONGLONG ll;
  51. g_llLastTime2 = g_llLastTime1;
  52. g_llLastTime1 = g_llLastTime;
  53. g_llLastTime = plrgTime->QuadPart;
  54. ll = g_llLastTime - g_llLastTime1;
  55. TRACE( TL_I, TM_Spec, ( "Time delta=%d", *((LONG* )&ll) ) );
  56. ASSERT( g_llLastTime >= g_llLastTime1 );
  57. }
  58. NdisReleaseSpinLock( &g_lockX );
  59. }
  60. #endif
  61. VOID
  62. AddHostRoute(
  63. IN TUNNELWORK* pWork,
  64. IN TUNNELCB* pTunnel,
  65. IN VCCB* pVc,
  66. IN ULONG_PTR* punpArgs )
  67. // A PTUNNELWORK routine to change an existing host route.
  68. //
  69. // This routine is called only at PASSIVE IRQL.
  70. //
  71. {
  72. ADAPTERCB* pAdapter;
  73. TRACE( TL_N, TM_Misc, ( "AddHostRoute" ) );
  74. // Unpack context information then free the work item.
  75. //
  76. pAdapter = pTunnel->pAdapter;
  77. FREE_TUNNELWORK( pAdapter, pWork );
  78. // Add the host route, noting success for clean-up later, or closing the
  79. // tunnel on failure.
  80. //
  81. pTunnel->pRoute =
  82. TdixAddHostRoute( &pAdapter->tdix, pTunnel->address.ulIpAddress,
  83. pTunnel->address.sUdpPort);
  84. if (pTunnel->pRoute != NULL)
  85. {
  86. NDIS_STATUS status;
  87. // Setup the connection to do connected udp
  88. // if required
  89. //
  90. status = TdixSetupConnection(
  91. &pAdapter->tdix, pTunnel->address.ulIpAddress,
  92. pTunnel->address.sUdpPort,
  93. pTunnel->pRoute,
  94. &pTunnel->udpContext);
  95. if(status != STATUS_SUCCESS)
  96. {
  97. TdixDestroyConnection(&pTunnel->udpContext);
  98. TdixDeleteHostRoute(&pAdapter->tdix,
  99. pTunnel->address.ulIpAddress);
  100. pTunnel->pRoute = NULL;
  101. ScheduleTunnelWork(
  102. pTunnel, NULL, FsmCloseTunnel,
  103. (ULONG_PTR )TRESULT_GeneralWithError,
  104. (ULONG_PTR )GERR_NoResources,
  105. 0, 0, FALSE, FALSE );
  106. }
  107. SetFlags( &pTunnel->ulFlags, TCBF_HostRouteAdded );
  108. if (pTunnel->udpContext.hCtrlAddr != NULL) {
  109. SetFlags (&pTunnel->ulFlags, TCBF_SendConnected);
  110. }
  111. }
  112. else
  113. {
  114. ScheduleTunnelWork(
  115. pTunnel, NULL, FsmCloseTunnel,
  116. (ULONG_PTR )TRESULT_GeneralWithError,
  117. (ULONG_PTR )GERR_NoResources,
  118. 0, 0, FALSE, FALSE );
  119. }
  120. }
  121. BOOLEAN
  122. AdjustSendWindowAtAckReceived(
  123. IN ULONG ulMaxSendWindow,
  124. IN OUT ULONG* pulAcksSinceSendTimeout,
  125. IN OUT ULONG* pulSendWindow )
  126. // Adjust send window/factors for the acknowledge just received.
  127. //
  128. // Returns true if the send window was changed, false if not.
  129. //
  130. {
  131. // Update the "ack streak" counter and, if a full windows worth has been
  132. // received since timing out, bump up the send window.
  133. //
  134. ++(*pulAcksSinceSendTimeout);
  135. if (*pulAcksSinceSendTimeout >= *pulSendWindow
  136. && *pulSendWindow < ulMaxSendWindow)
  137. {
  138. TRACE( TL_N, TM_Send,
  139. ( "SW open to %d, %d acks",
  140. (*pulSendWindow), *pulAcksSinceSendTimeout ) );
  141. *pulAcksSinceSendTimeout = 0;
  142. ++(*pulSendWindow);
  143. return TRUE;
  144. }
  145. return FALSE;
  146. }
  147. VOID
  148. AdjustTimeoutsAtAckReceived(
  149. IN LONGLONG llSendTime,
  150. IN ULONG ulMaxSendTimeoutMs,
  151. OUT ULONG* pulSendTimeoutMs,
  152. IN OUT ULONG* pulRoundTripMs,
  153. IN OUT LONG* plDeviationMs )
  154. // Adjust send timeout/factors for the acknowledge just received.
  155. //
  156. {
  157. LARGE_INTEGER lrgTime;
  158. LONGLONG llSampleMs;
  159. ULONG ulSampleMs;
  160. LONG lDiff;
  161. LONG lDif8;
  162. LONG lAbsDif8;
  163. LONG lDev8;
  164. ULONG ulAto;
  165. // First, calculate the "sample", i.e. the time that was actually required
  166. // for the round trip.
  167. //
  168. NdisGetCurrentSystemTime( &lrgTime );
  169. if (llSendTime > lrgTime.QuadPart)
  170. {
  171. // This shouldn't happen but once it appeared that it did, so this
  172. // defensive conditional is included. Maybe NdisGetCurrentSystemTime
  173. // has a bug?
  174. //
  175. TRACE( TL_A, TM_Misc, ( "Future send time?" ) );
  176. llSendTime = lrgTime.QuadPart;
  177. }
  178. llSampleMs = (lrgTime.QuadPart - llSendTime) / 10000;
  179. ASSERT( ((LARGE_INTEGER* )(&llSampleMs))->HighPart == 0 );
  180. ulSampleMs = (ULONG )(((LARGE_INTEGER* )(&llSampleMs))->LowPart);
  181. // The typical 'alpha' of 1/8, 'beta' of 1/4, and 'chi' of 4 are used, per
  182. // the suggestion in the draft/RFC. To eliminate multiplication and
  183. // division, the factors are scaled by 8, calculated, and scaled back.
  184. //
  185. // Find the intermediate DIFF value, representing the difference between
  186. // the estimated and actual round trip times, and the scaled and absolute
  187. // scaled values of same.
  188. //
  189. lDiff = (LONG )ulSampleMs - (LONG )(*pulRoundTripMs);
  190. lDif8 = lDiff << 3;
  191. lAbsDif8 = (lDif8 < 0) ? -lDif8 : lDif8;
  192. // Calculate the scaled new DEV value, representing the approximate
  193. // standard deviation.
  194. //
  195. lDev8 = *plDeviationMs << 3;
  196. lDev8 = lDev8 + ((lAbsDif8 - lDev8) << 1);
  197. *plDeviationMs = lDev8 >> 3;
  198. // Find the scaled new RTT value, representing the estimated round trip
  199. // time. The draft/RFC shows the calculation "old RTT + diff", but that's
  200. // just the "sample" we found earlier, i.e. the actual round trip time of
  201. // this packet.
  202. //
  203. *pulRoundTripMs = ulSampleMs;
  204. // Calculate the ATO value, representing the new send timeout. Because of
  205. // clock granularity the timeout might come out 0, which is converted to
  206. // the more reasonable 1.
  207. //
  208. ulAto = (ULONG )(((LONG )*pulRoundTripMs) + (*plDeviationMs << 2));
  209. if (ulAto == 0)
  210. {
  211. ulAto = 1;
  212. }
  213. *pulSendTimeoutMs = min( ulAto, ulMaxSendTimeoutMs );
  214. }
  215. VOID
  216. AdjustTimeoutsAndSendWindowAtTimeout(
  217. IN ULONG ulMaxSendTimeoutMs,
  218. IN LONG lDeviationMs,
  219. OUT ULONG* pulSendTimeoutMs,
  220. IN OUT ULONG* pulRoundTripMs,
  221. IN OUT ULONG* pulSendWindow,
  222. OUT ULONG* pulAcksSinceSendTimeout )
  223. // Adjust send timeout/factors and send window for the timeout that just
  224. // occurred.
  225. //
  226. // Returns true if the send window was changed, false if not.
  227. //
  228. {
  229. ULONG ulNew;
  230. // Using the suggested 'delta' of 2, the round trip estimate is doubled.
  231. //
  232. *pulRoundTripMs <<= 1;
  233. // Using the typical 'chi' of 4, the send timeout is increased. Because
  234. // of clock granularity the timeout might come out 0, which is converted
  235. // to the more reasonable 1.
  236. //
  237. ulNew = (ULONG )(((LONG )*pulRoundTripMs) + (lDeviationMs << 2));
  238. *pulSendTimeoutMs = min( ulNew, ulMaxSendTimeoutMs );
  239. if (*pulSendTimeoutMs == 0)
  240. {
  241. *pulSendTimeoutMs = 1;
  242. }
  243. // The send window is halved.
  244. //
  245. ulNew = *pulSendWindow >> 1;
  246. *pulSendWindow = max( ulNew, 1 );
  247. // Consecutive acknowledge counter is reset.
  248. //
  249. *pulAcksSinceSendTimeout = 0;
  250. }
  251. #if 0
  252. VOID
  253. BuildWanAddress(
  254. IN CHAR* pArg1,
  255. IN ULONG ulLength1,
  256. IN CHAR* pArg2,
  257. IN ULONG ulLength2,
  258. IN CHAR* pArg3,
  259. IN ULONG ulLength3,
  260. OUT WAN_ADDRESS* pWanAddress )
  261. // Builds a '\0' separated token list in WAN address 'pWanAddress',
  262. // consisting of the 3 arguments. If the arguments are too long the last
  263. // ones are truncated.
  264. //
  265. {
  266. CHAR* pch;
  267. ULONG ulLengthLeft;
  268. ULONG ulCopyLength;
  269. // Reserve room for 3 end-of-argument null characters, plus a final null.
  270. //
  271. NdisZeroMemory( &pWanAddress->Address[ MAX_WAN_ADDRESSLENGTH - 4 ], 4 );
  272. pch = pWanAddress->Address;
  273. ulLengthLeft = MAX_WAN_ADDRESSLENGTH - 4;
  274. ulCopyLength = min( ulLength1, ulLengthLeft );
  275. if (ulCopyLength)
  276. {
  277. NdisMoveMemory( pch, pArg1, ulCopyLength );
  278. ulLengthLeft -= ulCopyLength;
  279. pch += ulCopyLength;
  280. }
  281. *pch++ = '\0';
  282. ulCopyLength = min( ulLength2, ulLengthLeft );
  283. if (ulCopyLength)
  284. {
  285. NdisMoveMemory( pch, pArg2, ulCopyLength );
  286. ulLengthLeft -= ulCopyLength;
  287. pch += ulCopyLength;
  288. }
  289. *pch++ = '\0';
  290. ulCopyLength = min( ulLength3, ulLengthLeft );
  291. if (ulCopyLength)
  292. {
  293. NdisMoveMemory( pch, pArg3, ulCopyLength );
  294. pch += ulCopyLength;
  295. }
  296. *pch++ = '\0';
  297. *pch++ = '\0';
  298. pWanAddress->AddressLength = (ULONG )(pch - pWanAddress->Address);
  299. }
  300. #endif
  301. VOID
  302. CalculateResponse(
  303. IN UCHAR* puchChallenge,
  304. IN ULONG ulChallengeLength,
  305. IN CHAR* pszPassword,
  306. IN UCHAR uchId,
  307. OUT UCHAR* puchResponse )
  308. // Loads caller's 16-byte challenge response buffer, 'puchResponse', with
  309. // the CHAP-style MD5ed response based on packet ID 'uchId', the
  310. // 'ulChallengeLength' byte challenge 'puchChallenge', and the null
  311. // terminated password 'pszPassword'.
  312. //
  313. {
  314. ULONG ul;
  315. MD5_CTX md5ctx;
  316. MD5Init( &md5ctx );
  317. MD5Update( &md5ctx, &uchId, 1 );
  318. MD5Update( &md5ctx, pszPassword, strlen( pszPassword ) );
  319. MD5Update( &md5ctx, puchChallenge, ulChallengeLength );
  320. MD5Final( &md5ctx );
  321. NdisMoveMemory( puchResponse, md5ctx.digest, 16 );
  322. }
  323. VOID
  324. ChangeHostRoute(
  325. IN TUNNELWORK* pWork,
  326. IN TUNNELCB* pTunnel,
  327. IN VCCB* pVc,
  328. IN ULONG_PTR* punpArgs )
  329. // A PTUNNELWORK routine to change an existing host route. Arg0 is the IP
  330. // address of the existing host route to be deleted. Arg1 is the IP
  331. // address of the host route to add.
  332. //
  333. // This routine is called only at PASSIVE IRQL.
  334. //
  335. {
  336. ADAPTERCB* pAdapter;
  337. ULONG ulOldIpAddress;
  338. ULONG ulNewIpAddress;
  339. TRACE( TL_N, TM_Misc, ( "ChangeHostRoute" ) );
  340. // Unpack context information then free the work item.
  341. //
  342. pAdapter = pTunnel->pAdapter;
  343. ulOldIpAddress = (ULONG )(punpArgs[ 0 ]);
  344. ulNewIpAddress = (ULONG )(punpArgs[ 1 ]);
  345. FREE_TUNNELWORK( pAdapter, pWork );
  346. // Add the new host route, then delete the old one.
  347. //
  348. if (TdixAddHostRoute( &pAdapter->tdix, ulNewIpAddress,
  349. pTunnel->address.sUdpPort))
  350. {
  351. ClearFlags( &pTunnel->ulFlags, TCBF_HostRouteAdded );
  352. TdixDestroyConnection(&pTunnel->udpContext);
  353. TdixDeleteHostRoute( &pAdapter->tdix, ulOldIpAddress);
  354. }
  355. else
  356. {
  357. ScheduleTunnelWork(
  358. pTunnel, NULL, CloseTunnel,
  359. 0, 0, 0, 0, FALSE, FALSE );
  360. }
  361. }
  362. VOID
  363. ClearFlags(
  364. IN OUT ULONG* pulFlags,
  365. IN ULONG ulMask )
  366. // Set 'ulMask' bits in '*pulFlags' flags as an interlocked operation.
  367. //
  368. {
  369. ULONG ulFlags;
  370. ULONG ulNewFlags;
  371. do
  372. {
  373. ulFlags = ReadFlags( pulFlags );
  374. ulNewFlags = ulFlags & ~(ulMask);
  375. }
  376. while (InterlockedCompareExchange(
  377. pulFlags, ulNewFlags, ulFlags ) != (LONG )ulFlags);
  378. }
  379. VOID
  380. CloseTdix(
  381. IN TUNNELWORK* pWork,
  382. IN TUNNELCB* pTunnel,
  383. IN VCCB* pVc,
  384. IN ULONG_PTR* punpArgs )
  385. // A PTUNNELWORK routine to close the TDIX context associated with a
  386. // tunnel.
  387. //
  388. // This routine is called only at PASSIVE IRQL.
  389. //
  390. {
  391. ADAPTERCB* pAdapter;
  392. TRACE( TL_N, TM_Misc, ( "CloseTdix" ) );
  393. // Unpack context information then free the work item.
  394. //
  395. pAdapter = pTunnel->pAdapter;
  396. FREE_TUNNELWORK( pAdapter, pWork );
  397. // Delete the old host route, and note same in tunnel flags.
  398. //
  399. TdixClose( &pAdapter->tdix );
  400. ClearFlags( &pTunnel->ulFlags, TCBF_TdixReferenced );
  401. }
  402. VOID
  403. DeleteHostRoute(
  404. IN TUNNELWORK* pWork,
  405. IN TUNNELCB* pTunnel,
  406. IN VCCB* pVc,
  407. IN ULONG_PTR* pulArgs )
  408. // A PTUNNELWORK routine to change an existing host route.
  409. //
  410. // This routine is called only at PASSIVE IRQL.
  411. //
  412. {
  413. ADAPTERCB* pAdapter;
  414. TRACE( TL_N, TM_Misc, ( "DeleteHostRoute" ) );
  415. // Unpack context information then free the work item.
  416. //
  417. pAdapter = pTunnel->pAdapter;
  418. FREE_TUNNELWORK( pAdapter, pWork );
  419. // Destroy the connected udp context
  420. //
  421. TdixDestroyConnection(&pTunnel->udpContext);
  422. // Delete the old host route, and note same in tunnel flags.
  423. //
  424. TdixDeleteHostRoute( &pAdapter->tdix,
  425. pTunnel->address.ulIpAddress);
  426. ClearFlags( &pTunnel->ulFlags, TCBF_HostRouteAdded );
  427. }
  428. VOID
  429. DottedFromIpAddress(
  430. IN ULONG ulIpAddress,
  431. OUT CHAR* pszIpAddress,
  432. IN BOOLEAN fUnicode )
  433. // Converts network byte-ordered IP addresss 'ulIpAddress' to a string in
  434. // the a.b.c.d form and returns same in caller's 'pszIpAddress' buffer.
  435. // The buffer should be at least 16 characters long. If 'fUnicode' is set
  436. // the returned 'pszIpAddress' is in Unicode and must be at least 16 wide
  437. // characters long.
  438. //
  439. {
  440. CHAR szBuf[ 3 + 1 ];
  441. ULONG ulA = (ulIpAddress & 0x000000FF);
  442. ULONG ulB = (ulIpAddress & 0x0000FF00) >> 8;
  443. ULONG ulC = (ulIpAddress & 0x00FF0000) >> 16;
  444. ULONG ulD = (ulIpAddress & 0xFF000000) >> 24;
  445. ultoa( ulA, szBuf );
  446. strcpy( pszIpAddress, szBuf );
  447. strcat( pszIpAddress, "." );
  448. ultoa( ulB, szBuf );
  449. strcat( pszIpAddress, szBuf );
  450. strcat( pszIpAddress, "." );
  451. ultoa( ulC, szBuf );
  452. strcat( pszIpAddress, szBuf );
  453. strcat( pszIpAddress, "." );
  454. ultoa( ulD, szBuf );
  455. strcat( pszIpAddress, szBuf );
  456. if (fUnicode)
  457. {
  458. WCHAR* psz;
  459. psz = StrDupAsciiToUnicode( pszIpAddress, strlen( pszIpAddress ) );
  460. if (psz)
  461. {
  462. NdisMoveMemory(
  463. pszIpAddress, psz, (StrLenW( psz ) + 1) * sizeof(WCHAR) );
  464. FREE_NONPAGED( psz );
  465. }
  466. else
  467. {
  468. *((WCHAR*)pszIpAddress) = L'\0';
  469. }
  470. }
  471. }
  472. #if 0
  473. NDIS_STATUS
  474. ExecuteWork(
  475. IN ADAPTERCB* pAdapter,
  476. IN NDIS_PROC pProc,
  477. IN PVOID pContext,
  478. IN ULONG ulArg1,
  479. IN ULONG ulArg2,
  480. IN ULONG ulArg3,
  481. IN ULONG ulArg4 )
  482. // This provides a way to call a routine designed to be called by the
  483. // ScheduleWork utility when caller is already at passive IRQL. The
  484. // 'pProc' routine is executed inline instead of scheduled. The context
  485. // 'pContext' is passed to 'pProc' The extra context arguments 'ulArg1'
  486. // and 'ulArg2' are stashed in extra space allocated on the end of the
  487. // NDIS_WORK_ITEM. 'PAdapter' is the adapter control block from which the
  488. // work item is allocated.
  489. //
  490. // Returns NDIS_STATUS_SUCCESS or an error code.
  491. //
  492. {
  493. NDIS_STATUS status;
  494. NDIS_WORK_ITEM* pWork;
  495. // TDI setup must be done at PASSIVE IRQL so schedule a routine to do it.
  496. //
  497. pWork = ALLOC_NDIS_WORK_ITEM( pAdapter );
  498. if (!pWork)
  499. {
  500. ASSERT( !"Alloc work" );
  501. return NDIS_STATUS_RESOURCES;
  502. }
  503. ((ULONG*)(pWork + 1))[ 0 ] = ulArg1;
  504. ((ULONG*)(pWork + 1))[ 1 ] = ulArg2;
  505. ((ULONG*)(pWork + 1))[ 2 ] = ulArg3;
  506. ((ULONG*)(pWork + 1))[ 3 ] = ulArg4;
  507. pProc( pWork, pContext );
  508. }
  509. #endif
  510. #if 0
  511. VOID
  512. ExplodeWanAddress(
  513. IN WAN_ADDRESS* pWanAddress,
  514. OUT CHAR** ppArg1,
  515. OUT ULONG* pulLength1,
  516. OUT CHAR** ppArg2,
  517. OUT ULONG* pulLength2,
  518. OUT CHAR** ppArg3,
  519. OUT ULONG* pulLength3 )
  520. // Returns the '\0'-separated tokens in WAN address 'pWanAddress', and
  521. // their lengths.
  522. //
  523. {
  524. CHAR* pch;
  525. // Make sure 3 null characters will be found before going off the end of
  526. // the buffer.
  527. //
  528. pch = &pWanAddress->Address[ MAX_WAN_ADDRESSLENGTH - 3 ];
  529. NdisZeroMemory( pch, 3 );
  530. *ppArg1 = pWanAddress->Address;
  531. *pulLength1 = (ULONG )strlen( *ppArg1 );
  532. *ppArg2 = *ppArg1 + *pulLength1 + 1;
  533. *pulLength2 = (ULONG )strlen( *ppArg2 );
  534. *ppArg3 = *ppArg2 + *pulLength2 + 1;
  535. *pulLength3 = (ULONG )strlen( *ppArg3 );
  536. }
  537. #endif
  538. USHORT
  539. GetNextTerminationCallId(
  540. IN ADAPTERCB* pAdapter )
  541. // Returns the next unused termination Call-ID. Termination Call-IDs are
  542. // IDs out of the VC lookup table range that are used to gracefully
  543. // terminate failed incoming calls.
  544. //
  545. {
  546. do
  547. {
  548. ++pAdapter->usNextTerminationCallId;
  549. }
  550. while (pAdapter->usNextTerminationCallId < pAdapter->usMaxVcs + 1);
  551. return pAdapter->usNextTerminationCallId;
  552. }
  553. USHORT
  554. GetNextTunnelId(
  555. IN ADAPTERCB* pAdapter )
  556. // Returns the next tunnel ID to be assigned.
  557. //
  558. // IMPORTANT: Caller must hold 'pAdapter->lockTunnels'.
  559. {
  560. while (++pAdapter->usNextTunnelId == 0)
  561. ;
  562. return pAdapter->usNextTunnelId;
  563. }
  564. CHAR*
  565. GetFullHostNameFromRegistry(
  566. VOID )
  567. // Returns a heap block containing an ASCII string of the form
  568. // "hostname.domain", or if no domain of the form "hostname". Returns
  569. // NULL if none. Caller must eventually call FREE_NONPAGED on the
  570. // returned string.
  571. //
  572. {
  573. NTSTATUS status;
  574. OBJECT_ATTRIBUTES objattr;
  575. UNICODE_STRING uni;
  576. HANDLE hParams;
  577. CHAR* pszResult;
  578. WCHAR* pszFullHostName;
  579. KEY_VALUE_PARTIAL_INFORMATION* pHostNameValue;
  580. KEY_VALUE_PARTIAL_INFORMATION* pDomainValue;
  581. ULONG ulSize;
  582. TRACE( TL_I, TM_Cm, ( "GetFullHostNameFromRegistry" ) );
  583. hParams = NULL;
  584. pszFullHostName = NULL;
  585. pHostNameValue = NULL;
  586. pDomainValue = NULL;
  587. pszResult = NULL;
  588. #define GFHNFR_BufSize 512
  589. do
  590. {
  591. // Get a handle to the TCPIP Parameters registry key.
  592. //
  593. RtlInitUnicodeString(
  594. &uni,
  595. L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Tcpip\\Parameters" );
  596. InitializeObjectAttributes(
  597. &objattr, &uni, OBJ_CASE_INSENSITIVE, NULL, NULL );
  598. status = ZwOpenKey(
  599. &hParams, KEY_QUERY_VALUE, &objattr );
  600. if (status != STATUS_SUCCESS)
  601. {
  602. TRACE( TL_A, TM_Cm, ( "ZwOpenKey(ipp)=$%08x?", status ) );
  603. break;
  604. }
  605. // Query the "Hostname" registry value.
  606. //
  607. pHostNameValue = ALLOC_NONPAGED( GFHNFR_BufSize, MTAG_UTIL );
  608. if (!pHostNameValue)
  609. {
  610. break;
  611. }
  612. RtlInitUnicodeString( &uni, L"Hostname" );
  613. status = ZwQueryValueKey(
  614. hParams, &uni, KeyValuePartialInformation,
  615. pHostNameValue, GFHNFR_BufSize, &ulSize );
  616. if (status != STATUS_SUCCESS || pHostNameValue->Type != REG_SZ)
  617. {
  618. TRACE( TL_A, TM_Cm, ( "ZwQValueKey=$%08x?", status ) );
  619. break;
  620. }
  621. // Query the "Domain" registry value.
  622. //
  623. pDomainValue = ALLOC_NONPAGED( GFHNFR_BufSize, MTAG_UTIL );
  624. if (pDomainValue)
  625. {
  626. RtlInitUnicodeString( &uni, L"Domain" );
  627. status = ZwQueryValueKey(
  628. hParams, &uni, KeyValuePartialInformation,
  629. pDomainValue, GFHNFR_BufSize, &ulSize );
  630. }
  631. else
  632. {
  633. status = !STATUS_SUCCESS;
  634. }
  635. // Build a Unicode version of the combined "hostname.domain" or
  636. // "hostname".
  637. //
  638. pszFullHostName = ALLOC_NONPAGED( GFHNFR_BufSize * 2, MTAG_UTIL );
  639. if (!pszFullHostName)
  640. {
  641. break;
  642. }
  643. StrCpyW( pszFullHostName, (WCHAR* )pHostNameValue->Data );
  644. if (status == STATUS_SUCCESS
  645. && pDomainValue->Type == REG_SZ
  646. && pDomainValue->DataLength > sizeof(WCHAR)
  647. && ((WCHAR* )pDomainValue->Data)[ 0 ] != L'\0')
  648. {
  649. WCHAR* pch;
  650. pch = &pszFullHostName[ StrLenW( pszFullHostName ) ];
  651. *pch = L'.';
  652. ++pch;
  653. StrCpyW( pch, (WCHAR* )pDomainValue->Data );
  654. }
  655. // Convert the Unicode version to ASCII.
  656. //
  657. pszResult = StrDupUnicodeToAscii(
  658. pszFullHostName, StrLenW( pszFullHostName ) * sizeof(WCHAR) );
  659. }
  660. while (FALSE);
  661. if (hParams)
  662. {
  663. ZwClose( hParams );
  664. }
  665. if (pHostNameValue)
  666. {
  667. FREE_NONPAGED( pHostNameValue );
  668. }
  669. if (pDomainValue)
  670. {
  671. FREE_NONPAGED( pDomainValue );
  672. }
  673. if (pszFullHostName)
  674. {
  675. FREE_NONPAGED( pszFullHostName );
  676. }
  677. return pszResult;
  678. }
  679. ULONG
  680. IpAddressFromDotted(
  681. IN CHAR* pchIpAddress )
  682. // Convert caller's a.b.c.d IP address string to the network byte-order
  683. // numeric equivalent.
  684. //
  685. // Returns the numeric IP address or 0 if formatted incorrectly.
  686. //
  687. {
  688. INT i;
  689. LONG lResult;
  690. CHAR* pch;
  691. lResult = 0;
  692. pch = pchIpAddress;
  693. for (i = 1; i <= 4; ++i)
  694. {
  695. LONG lField;
  696. lField = atoul( pch );
  697. if (lField > 255)
  698. return 0;
  699. lResult = (lResult << 8) + lField;
  700. while (*pch >= '0' && *pch <= '9')
  701. ++pch;
  702. if (i < 4 && *pch != '.')
  703. return 0;
  704. ++pch;
  705. }
  706. return htonl( lResult );
  707. }
  708. VOID
  709. IndicateLinkStatus(
  710. IN VCCB* pVc,
  711. IN LINKSTATUSINFO* pInfo )
  712. // Indicate new WAN_CO_LINKPARAMS settings for 'pVc' to NDISWAN. Caller
  713. // should not be holding locks.
  714. //
  715. {
  716. ASSERT( pInfo->params.SendWindow > 0 );
  717. TRACE( TL_I, TM_Mp, ( "NdisMCoIndStatus(LINK) bps=%d sw=%d",
  718. pInfo->params.TransmitSpeed, pInfo->params.SendWindow ) );
  719. NdisMCoIndicateStatus(
  720. pInfo->MiniportAdapterHandle,
  721. pInfo->NdisVcHandle,
  722. NDIS_STATUS_WAN_CO_LINKPARAMS,
  723. &pInfo->params,
  724. sizeof(pInfo->params) );
  725. TRACE( TL_N, TM_Mp, ( "NdisMCoIndStatus done" ) );
  726. }
  727. #if DBG
  728. CHAR*
  729. MsgTypePszFromUs(
  730. IN USHORT usMsgType )
  731. // Debug utility to convert message type attribute code 'usMsgType' to a
  732. // corresponding display string.
  733. //
  734. {
  735. static CHAR szBuf[ 5 + 1 ];
  736. static CHAR* aszMsgType[ 16 ] =
  737. {
  738. "SCCRQ",
  739. "SCCRP",
  740. "SCCCN",
  741. "StopCCN",
  742. "StopCCRP???",
  743. "Hello",
  744. "OCRQ",
  745. "OCRP",
  746. "OCCN",
  747. "ICRQ",
  748. "ICRP",
  749. "ICCN",
  750. "CCR???",
  751. "CDN",
  752. "WEN",
  753. "SLI"
  754. };
  755. if (usMsgType >= 1 && usMsgType <= 16)
  756. {
  757. return aszMsgType[ usMsgType - 1 ];
  758. }
  759. else
  760. {
  761. ultoa( (ULONG )usMsgType, szBuf );
  762. return szBuf;
  763. }
  764. }
  765. #endif
  766. #ifndef READFLAGSDIRECT
  767. ULONG
  768. ReadFlags(
  769. IN ULONG* pulFlags )
  770. // Read the value of '*pulFlags' as an interlocked operation.
  771. //
  772. {
  773. return InterlockedExchangeAdd( pulFlags, 0 );
  774. }
  775. #endif
  776. VOID
  777. ScheduleTunnelWork(
  778. IN TUNNELCB* pTunnel,
  779. IN VCCB* pVc,
  780. IN PTUNNELWORK pHandler,
  781. IN ULONG_PTR unpArg0,
  782. IN ULONG_PTR unpArg1,
  783. IN ULONG_PTR unpArg2,
  784. IN ULONG_PTR unpArg3,
  785. IN BOOLEAN fTcbPreReferenced,
  786. IN BOOLEAN fHighPriority )
  787. // Schedules caller's 'pHandler' to be executed in an APC serially with
  788. // other work scheduled via this routine. 'PTunnel' is the tunnel to
  789. // which the work is related. 'UnpArgX' are the context arguments passed
  790. // to caller's 'pHandler'. 'FPreRefenced' indicates caller has already
  791. // made the tunnel reference associated with a scheduled work item. This
  792. // is a convenience if he already holds 'ADAPTERCB.lockTunnels'.
  793. // 'FHighPriority' causes the item to be queued at the head rather than
  794. // the tail of the list.
  795. //
  796. {
  797. ADAPTERCB* pAdapter;
  798. TUNNELWORK* pWork;
  799. pAdapter = pTunnel->pAdapter;
  800. if (!fTcbPreReferenced)
  801. {
  802. // Each queued work item holds a tunnel reference.
  803. //
  804. ReferenceTunnel( pTunnel, FALSE );
  805. }
  806. pWork = ALLOC_TUNNELWORK( pAdapter );
  807. if (!pWork)
  808. {
  809. // Can't get memory to schedule an APC so there's no
  810. // way we'll ever get things cleaned up.
  811. //
  812. ASSERT( !"Alloc TWork?" );
  813. ++g_ulAllocTwFailures;
  814. if (!fTcbPreReferenced)
  815. {
  816. DereferenceTunnel( pTunnel );
  817. }
  818. return;
  819. }
  820. if (pVc)
  821. {
  822. // Each queued work item that refers to a VC holds a VC reference.
  823. //
  824. ReferenceVc( pVc );
  825. }
  826. pWork->pHandler = pHandler;
  827. pWork->pVc = pVc;
  828. pWork->aunpArgs[ 0 ] = unpArg0;
  829. pWork->aunpArgs[ 1 ] = unpArg1;
  830. pWork->aunpArgs[ 2 ] = unpArg2;
  831. pWork->aunpArgs[ 3 ] = unpArg3;
  832. NdisAcquireSpinLock( &pTunnel->lockWork );
  833. {
  834. if (fHighPriority)
  835. {
  836. InsertHeadList( &pTunnel->listWork, &pWork->linkWork );
  837. TRACE( TL_N, TM_TWrk, ( "Q-TunnelWork($%08x,HIGH)", pHandler ) );
  838. }
  839. else
  840. {
  841. InsertTailList( &pTunnel->listWork, &pWork->linkWork );
  842. TRACE( TL_N, TM_TWrk, ( "Q-TunnelWork($%08x)", pHandler ) );
  843. }
  844. // Kickstart the tunnel worker if it's not running already.
  845. //
  846. if (!(ReadFlags( &pTunnel->ulFlags ) & TCBF_InWork ))
  847. {
  848. SetFlags( &pTunnel->ulFlags, TCBF_InWork );
  849. TRACE( TL_N, TM_TWrk, ( "Schedule TunnelWork" ) );
  850. ScheduleWork( pAdapter, TunnelWork, pTunnel );
  851. }
  852. }
  853. NdisReleaseSpinLock( &pTunnel->lockWork );
  854. }
  855. NDIS_STATUS
  856. ScheduleWork(
  857. IN ADAPTERCB* pAdapter,
  858. IN NDIS_PROC pProc,
  859. IN PVOID pContext )
  860. // Schedules a PASSIVE IRQL callback to routine 'pProc' which will be
  861. // passed 'pContext'. 'PAdapter' is the adapter control block from which
  862. // the work item is allocated. This routine takes an adapter reference
  863. // that should be removed by the called 'pProc'.
  864. //
  865. // Returns NDIS_STATUS_SUCCESS or an error code.
  866. //
  867. {
  868. NDIS_STATUS status;
  869. NDIS_WORK_ITEM* pWork;
  870. pWork = ALLOC_NDIS_WORK_ITEM( pAdapter );
  871. if (!pWork)
  872. {
  873. ASSERT( !"Alloc work?" );
  874. return NDIS_STATUS_RESOURCES;
  875. }
  876. NdisInitializeWorkItem( pWork, pProc, pContext );
  877. ReferenceAdapter( pAdapter );
  878. status = NdisScheduleWorkItem( pWork );
  879. if (status != NDIS_STATUS_SUCCESS)
  880. {
  881. ASSERT( !"SchedWork?" );
  882. FREE_NDIS_WORK_ITEM( pAdapter, pWork );
  883. DereferenceAdapter( pAdapter );
  884. }
  885. return status;
  886. }
  887. VOID
  888. SetFlags(
  889. IN OUT ULONG* pulFlags,
  890. IN ULONG ulMask )
  891. // Set 'ulMask' bits in '*pulFlags' flags as an interlocked operation.
  892. //
  893. {
  894. ULONG ulFlags;
  895. ULONG ulNewFlags;
  896. do
  897. {
  898. ulFlags = InterlockedExchangeAdd( pulFlags, 0 );
  899. ulNewFlags = ulFlags | ulMask;
  900. }
  901. while (InterlockedCompareExchange(
  902. pulFlags, ulNewFlags, ulFlags ) != (LONG )ulFlags);
  903. }
  904. VOID
  905. StrCpyW(
  906. IN WCHAR* psz1,
  907. IN WCHAR* psz2 )
  908. // Copies 'psz2' to 'psz1'.
  909. //
  910. {
  911. while (*psz2)
  912. {
  913. *psz1++ = *psz2++;
  914. }
  915. *psz1 = L'\0';
  916. }
  917. CHAR*
  918. StrDup(
  919. IN CHAR* psz )
  920. // Return a duplicate of 'psz'. Caller must eventually call FREE_NONPAGED
  921. // on the returned string.
  922. //
  923. {
  924. return StrDupSized( psz, strlen( psz ), 0 );
  925. }
  926. WCHAR*
  927. StrDupNdisString(
  928. IN NDIS_STRING* pNdisString )
  929. // Returns null-terminated Unicode copy of the NDIS_STRING 'pNdisString'
  930. // Caller must eventually call FREE_NONPAGED on the returned string.
  931. //
  932. {
  933. WCHAR* pszDup;
  934. pszDup = ALLOC_NONPAGED( pNdisString->Length + sizeof(WCHAR), MTAG_UTIL );
  935. if (pszDup)
  936. {
  937. NdisZeroMemory( pszDup, pNdisString->Length + sizeof(WCHAR) );
  938. if (pNdisString->Length)
  939. {
  940. NdisMoveMemory( pszDup, pNdisString->Buffer, pNdisString->Length );
  941. }
  942. }
  943. return pszDup;
  944. }
  945. CHAR*
  946. StrDupNdisStringToA(
  947. IN NDIS_STRING* pNdisString )
  948. // Returns null-terminated ASCII copy of the NDIS_STRING 'pNdisString'
  949. // Caller must eventually call FREE_NONPAGED on the returned string.
  950. //
  951. {
  952. return StrDupUnicodeToAscii( pNdisString->Buffer, pNdisString->Length );
  953. }
  954. #if 0
  955. CHAR*
  956. StrDupNdisVarDataDescStringA(
  957. IN NDIS_VAR_DATA_DESC* pDesc )
  958. // Returns null-terminated copy of the NDIS_VAR_DATA_DESC ANSI/ASCII
  959. // string 'pDesc'. Caller must eventually call FREE_NON-PAGED on the
  960. // returned string.
  961. //
  962. {
  963. CHAR* pszDup;
  964. pszDup = ALLOC_NONPAGED( pDesc->Length + 1, MTAG_UTIL );
  965. if (pszDup)
  966. {
  967. NdisZeroMemory( pszDup, pDesc->Length + 1 );
  968. if (pDesc->Length)
  969. {
  970. NdisMoveMemory(
  971. pszDup, ((CHAR* )pDesc) + pDesc->Offset, pDesc->Length );
  972. }
  973. }
  974. return pszDup;
  975. }
  976. #endif
  977. CHAR*
  978. StrDupNdisVarDataDescStringToA(
  979. IN NDIS_VAR_DATA_DESC UNALIGNED* pDesc )
  980. // Returns null-terminated ASCII copy of the NDIS_VAR_DATA_DESC string
  981. // 'pDesc'. Caller must eventually call FREE_NON-PAGED on the returned
  982. // string.
  983. //
  984. {
  985. return StrDupUnicodeToAscii(
  986. (WCHAR* )(((CHAR* )pDesc) + pDesc->Offset), pDesc->Length );
  987. }
  988. CHAR*
  989. StrDupSized(
  990. IN CHAR* psz,
  991. IN ULONG ulLength,
  992. IN ULONG ulExtra )
  993. // Return a duplicate of the first 'ulLength' bytes of 'psz' followed by a
  994. // null character and 'ulExtra' extra bytes, or NULL on error. Caller
  995. // must eventually call FREE_NONPAGED on the returned string.
  996. //
  997. {
  998. CHAR* pszDup;
  999. pszDup = ALLOC_NONPAGED( ulLength + 1 + ulExtra, MTAG_UTIL );
  1000. if (pszDup)
  1001. {
  1002. if (ulLength)
  1003. {
  1004. NdisMoveMemory( pszDup, psz, ulLength );
  1005. }
  1006. pszDup[ ulLength ] = '\0';
  1007. }
  1008. return pszDup;
  1009. }
  1010. CHAR*
  1011. StrDupUnicodeToAscii(
  1012. IN WCHAR* pwsz,
  1013. IN ULONG ulPwszBytes )
  1014. // Returns an ASCII duplicate of Unicode string 'pwsz', where 'pwsz' is
  1015. // 'ulPwszBytes' in length and not necessarily null terminated. A null
  1016. // terminator is added to the ASCII result. The "conversion" consists of
  1017. // picking out every other byte, hopefully all the non-zero ones. This is
  1018. // not foolproof, but then Unicode doesn't convert to ASCII in any
  1019. // foolproof way. It is caller's responsibility to FREE_NONPAGED the
  1020. // returned string, if non-NULL.
  1021. //
  1022. {
  1023. CHAR* pszDup;
  1024. pszDup = ALLOC_NONPAGED( ulPwszBytes + 1, MTAG_UTIL );
  1025. if (pszDup)
  1026. {
  1027. *((WCHAR* )pszDup) = L'\0';
  1028. if (ulPwszBytes)
  1029. {
  1030. NdisMoveMemory( pszDup, pwsz, ulPwszBytes );
  1031. }
  1032. if (ulPwszBytes > 1 && pszDup[ 1 ] == '\0')
  1033. {
  1034. ULONG i;
  1035. for (i = 0; i * 2 < ulPwszBytes; ++i)
  1036. {
  1037. pszDup[ i ] = pszDup[ i * 2 ];
  1038. }
  1039. pszDup[ i ] = '\0';
  1040. }
  1041. }
  1042. return pszDup;
  1043. }
  1044. WCHAR*
  1045. StrDupAsciiToUnicode(
  1046. IN CHAR* psz,
  1047. IN ULONG ulPszBytes )
  1048. // Returns a Unicode duplicate of ASCII string 'psz', where 'psz' is
  1049. // 'ulPszBytes' in length and not necessarily null terminated. A null
  1050. // terminator is added to the Unicode result. The "conversion" consists
  1051. // of adding zero characters every other byte. This is not foolproof, but
  1052. // is OK for numericals like IP address strings, avoiding the change to
  1053. // PASSIVE IRQL required to use the real RTL conversions. It is caller's
  1054. // responsibility to FREE_NONPAGED the returned string, if non-NULL.
  1055. //
  1056. {
  1057. WCHAR* pszDup;
  1058. pszDup = (WCHAR* )ALLOC_NONPAGED(
  1059. (ulPszBytes + 1) * sizeof(WCHAR), MTAG_UTIL );
  1060. if (pszDup)
  1061. {
  1062. CHAR* pszDupA;
  1063. ULONG i;
  1064. pszDupA = (CHAR* )pszDup;
  1065. for (i = 0; i < ulPszBytes; ++i)
  1066. {
  1067. pszDup[ i ] = (WCHAR )(psz[ i ]);
  1068. }
  1069. pszDup[ i ] = L'\0';
  1070. }
  1071. return pszDup;
  1072. }
  1073. ULONG
  1074. StrLenW(
  1075. IN WCHAR* psz )
  1076. // Return the length in characters of null terminated wide string 'psz'.
  1077. //
  1078. {
  1079. ULONG ulLen;
  1080. ulLen = 0;
  1081. if (psz)
  1082. {
  1083. while (*psz++ != L'\0')
  1084. {
  1085. ++ulLen;
  1086. }
  1087. }
  1088. return ulLen;
  1089. }
  1090. TUNNELCB*
  1091. TunnelCbFromIpAddressAndAssignedTunnelId(
  1092. IN ADAPTERCB* pAdapter,
  1093. IN ULONG ulIpAddress,
  1094. IN USHORT usAssignedTunnelId )
  1095. // Return the tunnel control block associated with 'ulIpAddress' in
  1096. // 'pAdapter's list of TUNNELCBs or NULL if not found. If
  1097. // 'usAssignedTunnelId' is non-zero, that must match as well, otherwise it
  1098. // is ignored. Tunnels in the process of closing are not returned.
  1099. //
  1100. // IMPORTANT: Caller must hold 'pAdapter->lockTunnels'.
  1101. //
  1102. {
  1103. TUNNELCB* pTunnel;
  1104. LIST_ENTRY* pLink;
  1105. pTunnel = NULL;
  1106. for (pLink = pAdapter->listTunnels.Flink;
  1107. pLink != &pAdapter->listTunnels;
  1108. pLink = pLink->Flink)
  1109. {
  1110. TUNNELCB* pThis;
  1111. pThis = CONTAINING_RECORD( pLink, TUNNELCB, linkTunnels );
  1112. if (pThis->address.ulIpAddress == ulIpAddress
  1113. && (!usAssignedTunnelId
  1114. || usAssignedTunnelId == pThis->usAssignedTunnelId))
  1115. {
  1116. BOOLEAN fClosing;
  1117. fClosing = !!(ReadFlags( &pThis->ulFlags ) & TCBF_Closing);
  1118. if (fClosing)
  1119. {
  1120. TRACE( TL_A, TM_Misc, ( "Closing pT=$%p skipped", pThis ) );
  1121. }
  1122. else
  1123. {
  1124. pTunnel = pThis;
  1125. break;
  1126. }
  1127. }
  1128. }
  1129. return pTunnel;
  1130. }
  1131. VOID
  1132. TransferLinkStatusInfo(
  1133. IN VCCB* pVc,
  1134. OUT LINKSTATUSINFO* pInfo )
  1135. // Transfer information from 'pVc' to callers 'pInfo' block in preparation
  1136. // for a call to IndicateLinkStatus after 'lockV' has been released.
  1137. //
  1138. // IMPORTANT: Caller must hold 'pVc->lockV'.
  1139. //
  1140. {
  1141. ADAPTERCB* pAdapter;
  1142. pAdapter = pVc->pAdapter;
  1143. pInfo->MiniportAdapterHandle = pAdapter->MiniportAdapterHandle;
  1144. pInfo->NdisVcHandle = pVc->NdisVcHandle;
  1145. //
  1146. // Convert to bytes per second
  1147. //
  1148. pInfo->params.TransmitSpeed = pVc->ulConnectBps/8;
  1149. pInfo->params.ReceiveSpeed = pInfo->params.TransmitSpeed/8;
  1150. pInfo->params.SendWindow =
  1151. min( pVc->ulSendWindow, pAdapter->info.MaxSendWindow );
  1152. }
  1153. VOID
  1154. TunnelWork(
  1155. IN NDIS_WORK_ITEM* pWork,
  1156. IN VOID* pContext )
  1157. // An NDIS_PROC routine to execute work from a tunnel work queue. The
  1158. // context passed is the TUNNELCB, which has been referenced for this
  1159. // operation.
  1160. //
  1161. // This routine is called only at PASSIVE IRQL.
  1162. //
  1163. {
  1164. ADAPTERCB* pAdapter;
  1165. TUNNELCB* pTunnel;
  1166. LIST_ENTRY* pLink;
  1167. LONG lDerefTunnels;
  1168. // Unpack context information then free the work item.
  1169. //
  1170. pTunnel = (TUNNELCB* )pContext;
  1171. pAdapter = pTunnel->pAdapter;
  1172. FREE_NDIS_WORK_ITEM( pAdapter, pWork );
  1173. // Execute all work queued on the tunnel serially.
  1174. //
  1175. lDerefTunnels = 0;
  1176. NdisAcquireSpinLock( &pTunnel->lockWork );
  1177. {
  1178. ASSERT( ReadFlags( &pTunnel->ulFlags ) & TCBF_InWork );
  1179. while (!IsListEmpty( &pTunnel->listWork ))
  1180. {
  1181. TUNNELWORK* pWork;
  1182. pLink = RemoveHeadList( &pTunnel->listWork );
  1183. InitializeListHead( pLink );
  1184. pWork = CONTAINING_RECORD( pLink, TUNNELWORK, linkWork );
  1185. TRACE( TL_N, TM_TWrk,
  1186. ( "\nL2TP: TUNNELWORK=$%08x", pWork->pHandler ) );
  1187. NdisReleaseSpinLock( &pTunnel->lockWork );
  1188. {
  1189. VCCB* pVc;
  1190. pVc = pWork->pVc;
  1191. pWork->pHandler( pWork, pTunnel, pVc, pWork->aunpArgs );
  1192. if (pVc)
  1193. {
  1194. DereferenceVc( pVc );
  1195. }
  1196. ++lDerefTunnels;
  1197. }
  1198. NdisAcquireSpinLock( &pTunnel->lockWork );
  1199. }
  1200. ClearFlags( &pTunnel->ulFlags, TCBF_InWork );
  1201. }
  1202. NdisReleaseSpinLock( &pTunnel->lockWork );
  1203. while (lDerefTunnels--)
  1204. {
  1205. DereferenceTunnel( pTunnel );
  1206. }
  1207. // Remove the reference for scheduled work.
  1208. //
  1209. DereferenceAdapter( pAdapter );
  1210. }
  1211. VOID
  1212. UpdateGlobalCallStats(
  1213. IN VCCB* pVc )
  1214. // Add the call statistics in 'pVc' to the global call statistics.
  1215. //
  1216. // IMPORTANT: Caller must hold 'pVc->lockV'.
  1217. //
  1218. {
  1219. extern CALLSTATS g_stats;
  1220. extern NDIS_SPIN_LOCK g_lockStats;
  1221. CALLSTATS* pStats;
  1222. pStats = &pVc->stats;
  1223. if (pStats->ulSeconds == 0)
  1224. {
  1225. return;
  1226. }
  1227. NdisAcquireSpinLock( &g_lockStats );
  1228. {
  1229. ++g_stats.llCallUp;
  1230. g_stats.ulSeconds += pStats->ulSeconds;
  1231. g_stats.ulDataBytesRecd += pStats->ulDataBytesRecd;
  1232. g_stats.ulDataBytesSent += pStats->ulDataBytesSent;
  1233. g_stats.ulRecdDataPackets += pStats->ulRecdDataPackets;
  1234. g_stats.ulDataPacketsDequeued += pStats->ulDataPacketsDequeued;
  1235. g_stats.ulRecdZlbs += pStats->ulRecdZlbs;
  1236. g_stats.ulRecdResets += pStats->ulRecdResets;
  1237. g_stats.ulRecdResetsIgnored += pStats->ulRecdResetsIgnored;
  1238. g_stats.ulSentDataPacketsSeq += pStats->ulSentDataPacketsSeq;
  1239. g_stats.ulSentDataPacketsUnSeq += pStats->ulSentDataPacketsUnSeq;
  1240. g_stats.ulSentPacketsAcked += pStats->ulSentPacketsAcked;
  1241. g_stats.ulSentPacketsTimedOut += pStats->ulSentPacketsTimedOut;
  1242. g_stats.ulSentZAcks += pStats->ulSentZAcks;
  1243. g_stats.ulSentResets += pStats->ulSentResets;
  1244. g_stats.ulSendWindowChanges += pStats->ulSendWindowChanges;
  1245. g_stats.ulSendWindowTotal += pStats->ulSendWindowTotal;
  1246. g_stats.ulMaxSendWindow += pStats->ulMaxSendWindow;
  1247. g_stats.ulMinSendWindow += pStats->ulMinSendWindow;
  1248. g_stats.ulRoundTrips += pStats->ulRoundTrips;
  1249. g_stats.ulRoundTripMsTotal += pStats->ulRoundTripMsTotal;
  1250. g_stats.ulMaxRoundTripMs += pStats->ulMaxRoundTripMs;
  1251. g_stats.ulMinRoundTripMs += pStats->ulMinRoundTripMs;
  1252. }
  1253. NdisReleaseSpinLock( &g_lockStats );
  1254. TRACE( TL_I, TM_Stat,
  1255. ( ".--- CALL STATISTICS -------------------------" ) );
  1256. TRACE( TL_I, TM_Stat,
  1257. ( "| Duration: %d minutes, %d seconds",
  1258. pStats->ulSeconds / 60,
  1259. pStats->ulSeconds % 60 ) );
  1260. TRACE( TL_I, TM_Stat,
  1261. ( "| Data out: %d bytes, %d/sec, %d/pkt",
  1262. pStats->ulDataBytesSent,
  1263. AVGTRACE(
  1264. pStats->ulDataBytesSent,
  1265. pStats->ulSeconds ),
  1266. AVGTRACE(
  1267. pStats->ulDataBytesSent,
  1268. pStats->ulRecdDataPackets ) ) );
  1269. TRACE( TL_I, TM_Stat,
  1270. ( "| Data in: %d bytes, %d/sec, %d/pkt",
  1271. pStats->ulDataBytesRecd,
  1272. AVGTRACE( pStats->ulDataBytesRecd, pStats->ulSeconds ),
  1273. AVGTRACE(
  1274. pStats->ulDataBytesRecd,
  1275. pStats->ulSentDataPacketsSeq
  1276. + pStats->ulSentDataPacketsUnSeq ) ) );
  1277. TRACE( TL_I, TM_Stat,
  1278. ( "| Acks in: %d/%d (%d%%) %d flushed",
  1279. pStats->ulSentPacketsAcked,
  1280. pStats->ulSentDataPacketsSeq,
  1281. PCTTRACE(
  1282. pStats->ulSentPacketsAcked,
  1283. pStats->ulSentPacketsAcked
  1284. + pStats->ulSentPacketsTimedOut ),
  1285. pStats->ulSentDataPacketsSeq
  1286. + pStats->ulSentDataPacketsUnSeq
  1287. - pStats->ulSentPacketsAcked
  1288. - pStats->ulSentPacketsTimedOut ) );
  1289. TRACE( TL_I, TM_Stat,
  1290. ( "| Misordered: %d (%d%%)",
  1291. pStats->ulDataPacketsDequeued,
  1292. PCTTRACE(
  1293. pStats->ulDataPacketsDequeued,
  1294. pStats->ulRecdDataPackets ) ) );
  1295. TRACE( TL_I, TM_Stat,
  1296. ( "| Out: Resets=%d ZAcks=%d UnSeqs=%d",
  1297. pStats->ulSentResets,
  1298. pStats->ulSentZAcks,
  1299. pStats->ulSentDataPacketsUnSeq ) );
  1300. TRACE( TL_I, TM_Stat,
  1301. ( "| In: Resets=%d (%d%% old) Zlbs=%d",
  1302. pStats->ulRecdResets,
  1303. PCTTRACE(
  1304. pStats->ulRecdResetsIgnored,
  1305. pStats->ulRecdResets ),
  1306. pStats->ulRecdZlbs ) );
  1307. TRACE( TL_I, TM_Stat,
  1308. ( "| Send window: Min=%d Avg=%d Max=%d Changes=%d",
  1309. pStats->ulMinSendWindow,
  1310. AVGTRACE(
  1311. pStats->ulSendWindowTotal,
  1312. pStats->ulSentDataPacketsSeq ),
  1313. pStats->ulMaxSendWindow,
  1314. pStats->ulSendWindowChanges ) );
  1315. TRACE( TL_I, TM_Stat,
  1316. ( "| Trip in ms: Min=%d Avg=%d Max=%d",
  1317. pStats->ulMinRoundTripMs,
  1318. AVGTRACE(
  1319. pStats->ulRoundTripMsTotal,
  1320. pStats->ulRoundTrips ),
  1321. pStats->ulMaxRoundTripMs ) );
  1322. TRACE( TL_I, TM_Stat,
  1323. ( "'---------------------------------------------" ) );
  1324. }
  1325. //-----------------------------------------------------------------------------
  1326. // Local utility routines (alphabetically)
  1327. //-----------------------------------------------------------------------------
  1328. ULONG
  1329. atoul(
  1330. IN CHAR* pszNumber )
  1331. // Convert string of digits 'pszNumber' to it's ULONG value.
  1332. //
  1333. {
  1334. ULONG ulResult;
  1335. ulResult = 0;
  1336. while (*pszNumber && *pszNumber >= '0' && *pszNumber <= '9')
  1337. {
  1338. ulResult *= 10;
  1339. ulResult += *pszNumber - '0';
  1340. ++pszNumber;
  1341. }
  1342. return ulResult;
  1343. }
  1344. VOID
  1345. ReversePsz(
  1346. IN OUT CHAR* psz )
  1347. // Reverse the order of the characters in 'psz' in place.
  1348. //
  1349. {
  1350. CHAR* pchLeft;
  1351. CHAR* pchRight;
  1352. pchLeft = psz;
  1353. pchRight = psz + strlen( psz ) - 1;
  1354. while (pchLeft < pchRight)
  1355. {
  1356. CHAR ch;
  1357. ch = *pchLeft;
  1358. *pchLeft = *pchRight;
  1359. *pchRight = ch;
  1360. ++pchLeft;
  1361. --pchRight;
  1362. }
  1363. }
  1364. VOID
  1365. ultoa(
  1366. IN ULONG ul,
  1367. OUT CHAR* pszBuf )
  1368. // Convert 'ul' to null-terminated string form in caller's 'pszBuf'. It's
  1369. // caller job to make sure 'pszBuf' is long enough to hold the returned
  1370. // string.
  1371. //
  1372. {
  1373. CHAR* pch;
  1374. pch = pszBuf;
  1375. do
  1376. {
  1377. *pch++ = (CHAR )((ul % 10) + '0');
  1378. ul /= 10;
  1379. }
  1380. while (ul);
  1381. *pch = '\0';
  1382. ReversePsz( pszBuf );
  1383. }