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.

2237 lines
53 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. wanarp\conn.c
  5. Abstract:
  6. The file contains the code needed for connection management
  7. Revision History:
  8. AmritanR
  9. --*/
  10. #define __FILE_SIG__ CONN_SIG
  11. #include "inc.h"
  12. VOID
  13. WanNdisStatus(
  14. NDIS_HANDLE nhHandle,
  15. NDIS_STATUS nsNdisStatus,
  16. PVOID pvStatusInfo,
  17. UINT uiStatusInfoSize
  18. )
  19. /*++
  20. Routine Description:
  21. Status handler for NDIS. we simply pass the buffer on to our private
  22. handlers
  23. Locks:
  24. None needed
  25. Arguments:
  26. nhHandle
  27. nsNdisStatus
  28. pvStatusInfo
  29. uiSatusInfoSize
  30. Return Value:
  31. None
  32. --*/
  33. {
  34. UNREFERENCED_PARAMETER(uiStatusInfoSize);
  35. UNREFERENCED_PARAMETER(nhHandle);
  36. switch(nsNdisStatus)
  37. {
  38. case NDIS_STATUS_WAN_LINE_UP:
  39. {
  40. PNDIS_WAN_LINE_UP pLineUp;
  41. pLineUp = (PNDIS_WAN_LINE_UP)pvStatusInfo;
  42. WanpLinkUpIndication(pLineUp);
  43. break;
  44. }
  45. case NDIS_STATUS_WAN_LINE_DOWN:
  46. {
  47. PNDIS_WAN_LINE_DOWN pLineDown;
  48. pLineDown = (PNDIS_WAN_LINE_DOWN)pvStatusInfo;
  49. WanpLinkDownIndication(pLineDown);
  50. break;
  51. }
  52. case NDIS_STATUS_WAN_FRAGMENT:
  53. default:
  54. {
  55. //
  56. // Ignore all other indications
  57. //
  58. break;
  59. }
  60. }
  61. }
  62. VOID
  63. WanNdisStatusComplete(
  64. NDIS_HANDLE nhHandle
  65. )
  66. /*++
  67. Routine Description:
  68. Called after the driver is done indicating a set of status
  69. indications
  70. We dont do anything
  71. Locks:
  72. None
  73. Arguments:
  74. nhHandle
  75. Return Value:
  76. None
  77. --*/
  78. {
  79. UNREFERENCED_PARAMETER(nhHandle);
  80. return;
  81. }
  82. NDIS_STATUS
  83. WanpLinkUpIndication(
  84. PNDIS_WAN_LINE_UP pInfoBuffer
  85. )
  86. /*++
  87. Routine Description:
  88. The routine that handles a new connection. We also get this when a
  89. link in a multi-linked bundle comes up or goes down.
  90. If this is a new connection, we allocate a CONN_ENTRY for this.
  91. Then, if this is a dial in connection, we lock and ref the server
  92. adapter and interface. If this is a router connection, we see if
  93. we already have a mapped adapter. If we do, we lock the adapter
  94. otherwise, we find a free adapter to map for the linkup.
  95. If this is a dial out connection, we create an interface and find a
  96. free adapter to map for the connection.
  97. We set up the needed cross mappings between the conn entry, adapter
  98. and interface and initialize the conn entry
  99. If this is a router connection, we drain all packets, and complete
  100. an IRP to tell router manager about it.
  101. For non dial in connections we indicate a Status change to IP, while
  102. for dial in, we add a link to IP for the client.
  103. Locks:
  104. MUST be called at PASSIVE because we call IPAddInterface.
  105. We acquire the g_rlConnTableLock, g_rwlAdapterLock, g_rwlIfLock
  106. in addition to locking down the adapter and the interface
  107. Arguments:
  108. Return Value:
  109. NDIS_STATUS_SUCCESS
  110. NDIS_STATUS_ADAPTER_NOT_READY
  111. STATUS_INVALID_PARAMETER
  112. NDIS_STATUS_RESOURCES
  113. STATUS_OBJECT_NAME_NOT_FOUND
  114. STATUS_INVALID_DEVICE_STATE
  115. --*/
  116. {
  117. PADAPTER pAdapter;
  118. PCONN_ENTRY pConnEntry;
  119. ULONG ulConnIndex;
  120. KIRQL kiIrql;
  121. LLIPMTUChange mtuChangeInfo;
  122. LLIPSpeedChange speedChangeInfo;
  123. IP_STATUS isStatus;
  124. ULONG ulIndex;
  125. UNICODE_STRING usTempName;
  126. WCHAR rgwcGuid[GUID_STR_LEN + 1];
  127. PUMODE_INTERFACE pInterface;
  128. PIP_WAN_LINKUP_INFO pLinkInfo;
  129. PPENDING_NOTIFICATION pMsg;
  130. //
  131. // This must be at PASSIVE (because we may need to drive a
  132. // IPAddInterface from here)
  133. //
  134. TraceEnter(CONN, "LinkUpIndication");
  135. pLinkInfo = (PIP_WAN_LINKUP_INFO)pInfoBuffer->ProtocolBuffer;
  136. Trace(CONN, INFO,
  137. ("HandleLinkUpIndication: %d.%d.%d.%d/%d.%d.%d.%d - %d.%d.%d.%d\n",
  138. PRINT_IPADDR(pLinkInfo->dwLocalAddr),
  139. PRINT_IPADDR(pLinkInfo->dwLocalMask),
  140. PRINT_IPADDR(pLinkInfo->dwRemoteAddr)));
  141. if(!EnterDriverCode())
  142. {
  143. return NDIS_STATUS_ADAPTER_NOT_READY;
  144. }
  145. ulConnIndex = GetConnIndexFromAddr(pInfoBuffer->LocalAddress);
  146. if(ulConnIndex isnot 0)
  147. {
  148. PVOID pvLinkContext;
  149. //
  150. // This is not the first lineup for this entry
  151. // We should find the entry (if it is on this interface)
  152. // and update speed and mtu info
  153. //
  154. RtAcquireSpinLock(&g_rlConnTableLock,
  155. &kiIrql);
  156. pConnEntry = GetConnEntryGivenIndex(ulConnIndex);
  157. if((pConnEntry is NULL) or
  158. (pConnEntry->byState isnot CS_CONNECTED))
  159. {
  160. RtAssert(FALSE);
  161. RtReleaseSpinLock(&g_rlConnTableLock,
  162. kiIrql);
  163. ExitDriverCode();
  164. return NDIS_STATUS_SUCCESS;
  165. }
  166. RtAssert(pConnEntry->pAdapter);
  167. //
  168. // Lock the conn entry or the adapter
  169. //
  170. RtAcquireSpinLockAtDpcLevel(pConnEntry->prlLock);
  171. RtReleaseSpinLockFromDpcLevel(&g_rlConnTableLock);
  172. if(pInfoBuffer->MaximumTotalSize isnot pConnEntry->ulMtu)
  173. {
  174. pConnEntry->ulMtu = pInfoBuffer->MaximumTotalSize;
  175. mtuChangeInfo.lmc_mtu = pConnEntry->ulMtu;
  176. }
  177. else
  178. {
  179. mtuChangeInfo.lmc_mtu = 0;
  180. }
  181. if((pInfoBuffer->LinkSpeed * 100L) isnot pConnEntry->ulSpeed)
  182. {
  183. pConnEntry->ulSpeed = pInfoBuffer->LinkSpeed * 100L;
  184. speedChangeInfo.lsc_speed = pConnEntry->ulSpeed;
  185. }
  186. else
  187. {
  188. speedChangeInfo.lsc_speed = 0;
  189. }
  190. RtReleaseSpinLock(pConnEntry->prlLock,
  191. kiIrql);
  192. if(mtuChangeInfo.lmc_mtu isnot 0)
  193. {
  194. g_pfnIpStatus(pConnEntry->pAdapter->pvIpContext,
  195. LLIP_STATUS_MTU_CHANGE,
  196. &mtuChangeInfo,
  197. sizeof(LLIPMTUChange),
  198. pConnEntry->pvIpLinkContext);
  199. }
  200. if(speedChangeInfo.lsc_speed isnot 0)
  201. {
  202. g_pfnIpStatus(pConnEntry->pAdapter->pvIpContext,
  203. LLIP_STATUS_SPEED_CHANGE,
  204. &speedChangeInfo,
  205. sizeof(LLIPSpeedChange),
  206. pConnEntry->pvIpLinkContext);
  207. }
  208. DereferenceConnEntry(pConnEntry);
  209. TraceLeave(CONN, "LinkUpIndication");
  210. ExitDriverCode();
  211. return NDIS_STATUS_SUCCESS;
  212. }
  213. PASSIVE_ENTRY();
  214. if((pLinkInfo->duUsage isnot DU_CALLIN) and
  215. (pLinkInfo->duUsage isnot DU_CALLOUT) and
  216. (pLinkInfo->duUsage isnot DU_ROUTER))
  217. {
  218. RtAssert(FALSE);
  219. Trace(CONN,ERROR,
  220. ("LinkUpIndication: Invalid usage %d\n", pLinkInfo->duUsage));
  221. TraceLeave(CONN, "LinkUpIndication");
  222. ExitDriverCode();
  223. return STATUS_INVALID_PARAMETER;
  224. }
  225. RtlZeroMemory(pInfoBuffer->LocalAddress,
  226. ARP_802_ADDR_LENGTH);
  227. //
  228. // Get a connection entry for this connection
  229. // This function finds a free slot in the connection table and puts
  230. // the conn entry into the slot. It sets the ulSlot field in the
  231. // conn entry to be the index of the slot
  232. //
  233. RtAcquireSpinLock(&g_rlConnTableLock,
  234. &kiIrql);
  235. pConnEntry = WanpCreateConnEntry(pLinkInfo->duUsage);
  236. if(pConnEntry is NULL)
  237. {
  238. RtReleaseSpinLock(&g_rlConnTableLock,
  239. kiIrql);
  240. Trace(CONN,ERROR,
  241. ("LinkUpIndication: Couldnt allocate conn entry\n"));
  242. TraceLeave(CONN, "LinkUpIndication");
  243. ExitDriverCode();
  244. return NDIS_STATUS_RESOURCES;
  245. }
  246. RtReleaseSpinLock(&g_rlConnTableLock,
  247. kiIrql);
  248. //
  249. // Create a GUID from a name
  250. //
  251. usTempName.MaximumLength = (GUID_STR_LEN + 1) * sizeof(WCHAR);
  252. usTempName.Length = GUID_STR_LEN * sizeof(WCHAR);
  253. usTempName.Buffer = rgwcGuid;
  254. ConvertGuidToString((GUID *)(pInfoBuffer->DeviceName.Buffer),
  255. rgwcGuid);
  256. rgwcGuid[GUID_STR_LEN] = UNICODE_NULL;
  257. pAdapter = NULL;
  258. //
  259. // Do this usage specific thing. At the end of this switch statement
  260. // we have a locked and referenced Adapter and Interface for the
  261. // connection
  262. //
  263. switch(pLinkInfo->duUsage)
  264. {
  265. case DU_CALLIN:
  266. {
  267. //
  268. // Just get the server adapter and interface
  269. //
  270. Trace(CONN, INFO,
  271. ("LinkUpIndication: Linkup Usage is CALLIN\n"));
  272. //
  273. // Just use 0 as adapter index, since it is not really needed
  274. // for the CALLIN case
  275. //
  276. pAdapter = WanpFindAdapterToMap(DU_CALLIN,
  277. &kiIrql,
  278. 0,
  279. NULL);
  280. if(pAdapter is NULL)
  281. {
  282. WanpDeleteConnEntry(pConnEntry);
  283. ExitDriverCode();
  284. return NDIS_STATUS_RESOURCES;
  285. }
  286. RtAssert(pAdapter is g_pServerAdapter);
  287. //
  288. // clients lock the connection entry
  289. //
  290. RtInitializeSpinLock(&(pConnEntry->rlLock));
  291. pConnEntry->prlLock = &(pConnEntry->rlLock);
  292. RtAssert(pAdapter->pInterface is g_pServerInterface);
  293. RtAssert(pAdapter->byState is AS_MAPPED);
  294. //
  295. // Lock the server interface. We have to have a server interface.
  296. //
  297. pInterface = g_pServerInterface;
  298. //
  299. // Lock and reference the interface
  300. //
  301. RtAcquireSpinLockAtDpcLevel(&(pInterface->rlLock));
  302. ReferenceInterface(pInterface);
  303. break;
  304. }
  305. case DU_CALLOUT:
  306. {
  307. Trace(CONN, INFO,
  308. ("LinkUpIndication: Linkup Usage is CALLOUT\n"));
  309. //
  310. // Allocate a notification for informing the router manager
  311. // of this connection
  312. //
  313. pMsg = AllocateNotification();
  314. if(pMsg is NULL)
  315. {
  316. Trace(CONN, ERROR,
  317. ("LinkUpIndication: Couldnt allocate msg\n"));
  318. TraceLeave(CONN, "LinkUpIndication");
  319. WanpDeleteConnEntry(pConnEntry);
  320. ExitDriverCode();
  321. return NDIS_STATUS_RESOURCES;
  322. }
  323. //
  324. // For dial out, we dynamically create an interface
  325. //
  326. pInterface = RtAllocate(NonPagedPool,
  327. sizeof(UMODE_INTERFACE),
  328. WAN_INTERFACE_TAG);
  329. if(pInterface is NULL)
  330. {
  331. Trace(CONN, ERROR,
  332. ("LinkUpIndication: Couldnt allocate I/f\n"));
  333. TraceLeave(CONN, "LinkUpIndication");
  334. WanpDeleteConnEntry(pConnEntry);
  335. FreeNotification(pMsg);
  336. ExitDriverCode();
  337. return NDIS_STATUS_RESOURCES;
  338. }
  339. RtlZeroMemory(pInterface,
  340. sizeof(UMODE_INTERFACE));
  341. //
  342. // Get a new index from IP for this
  343. // This sets the value to INVALID_IF_INDEX if it fails
  344. //
  345. isStatus = WanpGetNewIndex(&(pInterface->dwRsvdAdapterIndex));
  346. if(isStatus isnot STATUS_SUCCESS)
  347. {
  348. RtFree(pInterface);
  349. Trace(CONN, ERROR,
  350. ("LinkUpIndication: Couldnt get index for I/f\n"));
  351. TraceLeave(CONN, "LinkUpIndication");
  352. WanpDeleteConnEntry(pConnEntry);
  353. FreeNotification(pMsg);
  354. ExitDriverCode();
  355. return NDIS_STATUS_RESOURCES;
  356. }
  357. Trace(CONN, INFO,
  358. ("LinkUpIndication: DialOut name is %S\n",
  359. rgwcGuid));
  360. //
  361. // Find an adapter
  362. //
  363. pAdapter = WanpFindAdapterToMap(DU_CALLOUT,
  364. &kiIrql,
  365. pInterface->dwRsvdAdapterIndex,
  366. &usTempName);
  367. if(pAdapter is NULL)
  368. {
  369. WanpFreeIndex(pInterface->dwRsvdAdapterIndex);
  370. RtFree(pInterface);
  371. WanpDeleteConnEntry(pConnEntry);
  372. FreeNotification(pMsg);
  373. ExitDriverCode();
  374. return NDIS_STATUS_RESOURCES;
  375. }
  376. //
  377. // Initialize the interface block
  378. //
  379. RtInitializeSpinLock(&(pInterface->rlLock));
  380. //
  381. // Structure copy
  382. //
  383. pInterface->Guid = *((GUID *)(pInfoBuffer->DeviceName.Buffer));
  384. pInterface->dwAdminState = IF_ADMIN_STATUS_UP;
  385. pInterface->dwOperState = IF_OPER_STATUS_CONNECTING;
  386. pInterface->dwLastChange = GetTimeTicks();
  387. pInterface->dwIfIndex = INVALID_IF_INDEX;
  388. pInterface->duUsage = DU_CALLOUT;
  389. InitInterfaceRefCount(pInterface);
  390. //
  391. // Reference and lock the interface because the code after
  392. // the switch statement expects pInterface to be locked and
  393. // ref'ed
  394. //
  395. ReferenceInterface(pInterface);
  396. RtAcquireSpinLockAtDpcLevel(&(pInterface->rlLock));
  397. EnterWriterAtDpcLevel(&g_rwlIfLock);
  398. InsertHeadList(&g_leIfList,
  399. &(pInterface->leIfLink));
  400. //
  401. // No need to insert this in the quick lookup table since
  402. // this interface is never accessed by the index
  403. //
  404. InterlockedIncrement(&g_ulNumDialOutInterfaces);
  405. ExitWriterFromDpcLevel(&g_rwlIfLock);
  406. //
  407. // Initialize the message
  408. //
  409. pMsg->wnMsg.ddeEvent = DDE_CALLOUT_LINKUP;
  410. pMsg->wnMsg.dwUserIfIndex = INVALID_IF_INDEX;
  411. pMsg->wnMsg.dwAdapterIndex = pInterface->dwRsvdAdapterIndex;
  412. pMsg->wnMsg.dwLocalMask = pLinkInfo->dwLocalMask;
  413. pMsg->wnMsg.dwLocalAddr = pLinkInfo->dwLocalAddr;
  414. pMsg->wnMsg.dwRemoteAddr = pLinkInfo->dwRemoteAddr;
  415. pMsg->wnMsg.fDefaultRoute = pLinkInfo->fDefaultRoute;
  416. RtAssert(pInfoBuffer->DeviceName.Length <= WANARP_MAX_DEVICE_NAME_LEN);
  417. RtAssert((pInfoBuffer->DeviceName.Length % sizeof(WCHAR)) is 0)
  418. RtlCopyMemory(pMsg->wnMsg.rgwcName,
  419. usTempName.Buffer,
  420. usTempName.Length);
  421. pMsg->wnMsg.rgwcName[usTempName.Length/sizeof(WCHAR)] = UNICODE_NULL;
  422. break;
  423. }
  424. case DU_ROUTER:
  425. {
  426. pMsg = AllocateNotification();
  427. if(pMsg is NULL)
  428. {
  429. Trace(CONN, ERROR,
  430. ("LinkUpIndication: Couldnt allocate msg\n"));
  431. TraceLeave(CONN, "LinkUpIndication");
  432. WanpDeleteConnEntry(pConnEntry);
  433. ExitDriverCode();
  434. return NDIS_STATUS_RESOURCES;
  435. }
  436. //
  437. // Get the interface
  438. //
  439. EnterReader(&g_rwlIfLock,
  440. &kiIrql);
  441. pInterface = WanpFindInterfaceGivenIndex(
  442. pLinkInfo->dwUserIfIndex
  443. );
  444. if(pInterface is NULL)
  445. {
  446. ExitReader(&g_rwlIfLock,
  447. kiIrql);
  448. Trace(CONN, ERROR,
  449. ("LinkUpIndication: No interface %d\n",
  450. pLinkInfo->dwUserIfIndex));
  451. WanpDeleteConnEntry(pConnEntry);
  452. FreeNotification(pMsg);
  453. TraceLeave(CONN, "LinkUpIndication");
  454. ExitDriverCode();
  455. return STATUS_OBJECT_NAME_NOT_FOUND;
  456. }
  457. ExitReaderFromDpcLevel(&g_rwlIfLock);
  458. if((pInterface->dwOperState isnot IF_OPER_STATUS_CONNECTING) and
  459. (pInterface->dwOperState isnot IF_OPER_STATUS_DISCONNECTED))
  460. {
  461. Trace(CONN, ERROR,
  462. ("LinkUpIndication: Interface %p is in state %d\n",
  463. pInterface,
  464. pInterface->dwOperState));
  465. RtReleaseSpinLock(&(pInterface->rlLock),
  466. kiIrql);
  467. WanpDeleteConnEntry(pConnEntry);
  468. FreeNotification(pMsg);
  469. TraceLeave(CONN, "LinkUpIndication");
  470. ExitDriverCode();
  471. return STATUS_INVALID_DEVICE_STATE;
  472. }
  473. pInterface->Guid = *((GUID *)(pInfoBuffer->DeviceName.Buffer));
  474. Trace(CONN, TRACE,
  475. ("LinkUpIndication: For interface %p\n",
  476. pInterface));
  477. //
  478. // See if the interface is mapped to an adapter. This happens
  479. // if this connection is being brought up due to a DODCallout
  480. //
  481. pAdapter = pInterface->pAdapter;
  482. if(pAdapter isnot NULL)
  483. {
  484. //
  485. // We have an adapter and we need to lock it. However
  486. // we cant lock it till we unlock the interface
  487. // So we let go of the interface lock, but dont deref
  488. //
  489. RtReleaseSpinLockFromDpcLevel(&(pInterface->rlLock));
  490. //
  491. // Acquire the adapter lock
  492. //
  493. RtAcquireSpinLockAtDpcLevel(&(pAdapter->rlLock));
  494. //
  495. // This adapter better be mapped to the above interface
  496. // because the only way to unmap an adapter is to delete it
  497. // or to get a LinkDown or a ConnFailure. All these cases are
  498. // mutually exclusive with LinkUp
  499. //
  500. RtAssert(pAdapter->pInterface is pInterface);
  501. RtAssert(pAdapter->byState is AS_MAPPED);
  502. ReferenceAdapter(pAdapter);
  503. //
  504. // Go back and lock the interface
  505. //
  506. RtAcquireSpinLockAtDpcLevel(&(pInterface->rlLock));
  507. RtAssert(pInterface->dwOperState is IF_OPER_STATUS_CONNECTING);
  508. }
  509. else
  510. {
  511. //
  512. // So we dont have an adapter...
  513. // This function MUST be called at PASSIVE
  514. //
  515. RtReleaseSpinLock(&(pInterface->rlLock),
  516. kiIrql);
  517. pAdapter = WanpFindAdapterToMap(DU_ROUTER,
  518. &kiIrql,
  519. pInterface->dwRsvdAdapterIndex,
  520. &usTempName);
  521. if(pAdapter is NULL)
  522. {
  523. DereferenceInterface(pInterface);
  524. WanpDeleteConnEntry(pConnEntry);
  525. FreeNotification(pMsg);
  526. ExitDriverCode();
  527. return NDIS_STATUS_RESOURCES;
  528. }
  529. //
  530. // Got the adapter, lock the interface. We are at
  531. // DPC since the adapter is locked
  532. //
  533. RtAcquireSpinLockAtDpcLevel(&(pInterface->rlLock));
  534. }
  535. //
  536. // Interface and adapter refcounted and locked
  537. //
  538. pMsg->wnMsg.ddeEvent = DDE_INTERFACE_CONNECTED;
  539. pMsg->wnMsg.dwUserIfIndex = pInterface->dwIfIndex;
  540. pMsg->wnMsg.dwAdapterIndex = pInterface->dwRsvdAdapterIndex;
  541. pMsg->wnMsg.dwLocalMask = pLinkInfo->dwLocalMask;
  542. pMsg->wnMsg.dwLocalAddr = pLinkInfo->dwLocalAddr;
  543. pMsg->wnMsg.dwRemoteAddr = pLinkInfo->dwRemoteAddr;
  544. pMsg->wnMsg.fDefaultRoute = pLinkInfo->fDefaultRoute;
  545. break;
  546. }
  547. default:
  548. {
  549. RtAssert(FALSE);
  550. WanpDeleteConnEntry(pConnEntry);
  551. ExitDriverCode();
  552. return STATUS_INVALID_PARAMETER;
  553. }
  554. }
  555. //
  556. // At this point we have a locked and refcounted adapter
  557. // The adapter has been moved to the MAPPED adapter list
  558. // We also have a locked and recfounted interface
  559. // pConnEntry points to a CONN_ENTRY which is in the table but
  560. // is neither locked nor refcounted
  561. //
  562. Trace(CONN, INFO,
  563. ("LinkUpIndication: Found adapter %x to map to i/f %x %d\n",
  564. pAdapter, pInterface, pInterface->dwIfIndex));
  565. #if DBG
  566. Trace(CONN, INFO,
  567. ("LinkUpIndication: Adapter Name is %s\n",
  568. pAdapter->asDeviceNameA.Buffer));
  569. #endif
  570. if(pLinkInfo->duUsage isnot DU_CALLIN)
  571. {
  572. //
  573. // Set the cross mappings between the interface and the adapter
  574. //
  575. pAdapter->pInterface = pInterface;
  576. pInterface->pAdapter = pAdapter;
  577. pAdapter->byState = AS_MAPPED;
  578. pInterface->dwOperState = IF_OPER_STATUS_CONNECTED;
  579. pInterface->dwLastChange= GetTimeTicks();
  580. //
  581. // Put a refcount on both the adapter and the interface
  582. // because the mapping stored pointers to them
  583. //
  584. ReferenceAdapter(pAdapter);
  585. ReferenceInterface(pInterface);
  586. //
  587. // Set the lock in the conn entry
  588. //
  589. pConnEntry->prlLock = &(pAdapter->rlLock);
  590. //
  591. // Non Client adapters store a pointer to the connection entry
  592. // However we dont ref the conn entry for that
  593. //
  594. pAdapter->pConnEntry = pConnEntry;
  595. }
  596. else
  597. {
  598. //
  599. // For callin, the mappings are already set up
  600. //
  601. RtAssert(pAdapter->pInterface is pInterface);
  602. RtAssert(pInterface->pAdapter is pAdapter);
  603. RtAssert(pInterface->dwOperState is IF_OPER_STATUS_CONNECTED);
  604. }
  605. RtlZeroMemory(pInfoBuffer->DeviceName.Buffer,
  606. pInfoBuffer->DeviceName.MaximumLength);
  607. //
  608. // Copy the adapter(device) name into the buffer.
  609. //
  610. RtAssert(pAdapter->usDeviceNameW.Length <= pInfoBuffer->DeviceName.MaximumLength);
  611. pInfoBuffer->DeviceName.Length = pAdapter->usDeviceNameW.Length;
  612. RtlCopyMemory(pInfoBuffer->DeviceName.Buffer,
  613. pAdapter->usDeviceNameW.Buffer,
  614. pAdapter->usDeviceNameW.Length);
  615. //
  616. // Copy out the connection index for this connection into NDISWAN's
  617. // LocalAddress - this will then be put in the DestAddr field by
  618. // NDISWAN in all the receive indications, and in the linkdown
  619. //
  620. InsertConnIndexInAddr(pInfoBuffer->LocalAddress,
  621. pConnEntry->ulSlotIndex);
  622. //
  623. // Set up the connection entry
  624. //
  625. pConnEntry->dwLocalMask = pLinkInfo->dwLocalMask;
  626. pConnEntry->dwLocalAddr = pLinkInfo->dwLocalAddr;
  627. pConnEntry->dwRemoteAddr = pLinkInfo->dwRemoteAddr;
  628. pConnEntry->ulMtu = pInfoBuffer->MaximumTotalSize;
  629. pConnEntry->ulSpeed = pInfoBuffer->LinkSpeed * 100L;
  630. pConnEntry->bFilterNetBios = (pLinkInfo->fFilterNetBios == 1);
  631. pConnEntry->byState = CS_CONNECTED;
  632. RtAssert(pConnEntry->duUsage is pLinkInfo->duUsage);
  633. pConnEntry->pvIpLinkContext = NULL;
  634. //
  635. // Map the entry to the adapter
  636. // Because of the stored pointer, refcount the adapter
  637. //
  638. pConnEntry->pAdapter = pAdapter;
  639. ReferenceAdapter(pAdapter);
  640. //
  641. // Initialize the prebuilt ethernet header
  642. // First zero out the source address in the ethernet header
  643. //
  644. RtlZeroMemory(pConnEntry->ehHeader.rgbySourceAddr,
  645. ARP_802_ADDR_LENGTH);
  646. //
  647. // Put our context in the right place in the ethernet source
  648. // address
  649. //
  650. InsertConnIndexInAddr(pConnEntry->ehHeader.rgbySourceAddr,
  651. pConnEntry->ulSlotIndex);
  652. //
  653. // Refcount the connentry because it lies in the connection table,
  654. // NDISWAN has a "pointer" to it and because pAdapter->pConnEntry
  655. // may have a pointer to it.
  656. // NOTE: since we keep only one ref for all these conditions, all the
  657. // pointer must be cleared in the same function with the connection
  658. // locked
  659. //
  660. ReferenceConnEntry(pConnEntry);
  661. pConnEntry->ehHeader.wType = RtlUshortByteSwap(ARP_ETYPE_IP);
  662. //
  663. // A send is from WANARP -> NDISWAN so put the NDISWAN context in
  664. // the DEST address of our prebuilt ethernet header
  665. //
  666. RtlCopyMemory(pConnEntry->ehHeader.rgbyDestAddr,
  667. pInfoBuffer->RemoteAddress,
  668. ARP_802_ADDR_LENGTH);
  669. //
  670. // For a router connection, tell router manager about it
  671. //
  672. if(pLinkInfo->duUsage is DU_ROUTER)
  673. {
  674. //
  675. // If there are packets queued to the interface, drain them now
  676. //
  677. WanpTransmitQueuedPackets(pAdapter,
  678. pInterface,
  679. pConnEntry,
  680. kiIrql);
  681. //
  682. // Let Router Manager know of a new connection
  683. //
  684. WanpCompleteIrp(pMsg);
  685. }
  686. else
  687. {
  688. //
  689. // Done with the interfaces. We can unlock them now
  690. // Router interfaces are unlocked in WanpSendPackets which
  691. // is called from WanpTransmitQueuedPackets
  692. //
  693. RtReleaseSpinLockFromDpcLevel(&(pInterface->rlLock));
  694. RtReleaseSpinLock(&(pAdapter->rlLock),
  695. kiIrql);
  696. if(pLinkInfo->duUsage is DU_CALLOUT)
  697. {
  698. //
  699. // Complete the IRP to the router manager (or queue if no IRPs
  700. // are pending)
  701. //
  702. WanpCompleteIrp(pMsg);
  703. }
  704. }
  705. //
  706. // Need to make this call without holding locks.
  707. // We can let go of the locks since we wont get any NDIS layer
  708. // calls for this connection till this function completes and
  709. // the IP and IOCTL interface functions can be handled with no
  710. // consistency problems
  711. //
  712. if(pLinkInfo->duUsage isnot DU_CALLIN)
  713. {
  714. //
  715. // Notify upper layer of mtu change
  716. //
  717. mtuChangeInfo.lmc_mtu = pConnEntry->ulMtu;
  718. speedChangeInfo.lsc_speed = pConnEntry->ulSpeed;
  719. g_pfnIpStatus(pAdapter->pvIpContext,
  720. LLIP_STATUS_MTU_CHANGE,
  721. &mtuChangeInfo,
  722. sizeof(LLIPMTUChange),
  723. NULL);
  724. g_pfnIpStatus(pConnEntry->pAdapter->pvIpContext,
  725. LLIP_STATUS_SPEED_CHANGE,
  726. &speedChangeInfo,
  727. sizeof(LLIPSpeedChange),
  728. pConnEntry->pvIpLinkContext);
  729. }
  730. else
  731. {
  732. isStatus = g_pfnIpAddLink(pAdapter->pvIpContext,
  733. pConnEntry->dwRemoteAddr,
  734. pConnEntry,
  735. &(pConnEntry->pvIpLinkContext),
  736. pConnEntry->ulMtu);
  737. if(isStatus isnot IP_SUCCESS)
  738. {
  739. Trace(CONN, ERROR,
  740. ("LinkUpIndication: IpAddLink returned %x\n",
  741. isStatus));
  742. RtlZeroMemory(pInfoBuffer->DeviceName.Buffer,
  743. pInfoBuffer->DeviceName.MaximumLength);
  744. pInfoBuffer->DeviceName.Length = 0;
  745. RtlZeroMemory(pInfoBuffer->LocalAddress,
  746. ARP_802_ADDR_LENGTH);
  747. //
  748. // Just deref the connection entry
  749. // This will clear up everything
  750. //
  751. DereferenceConnEntry(pConnEntry);
  752. }
  753. else
  754. {
  755. //
  756. // Reference it once for the fact that we now have this entry
  757. // with IP
  758. //
  759. ReferenceConnEntry(pConnEntry);
  760. }
  761. }
  762. //
  763. // Done with the interface and adapter. Dereference them now because
  764. // the Find..() functions put a reference on them
  765. //
  766. DereferenceAdapter(pAdapter);
  767. DereferenceInterface(pInterface);
  768. ExitDriverCode();
  769. return NDIS_STATUS_SUCCESS;
  770. }
  771. NDIS_STATUS
  772. WanpLinkDownIndication(
  773. PNDIS_WAN_LINE_DOWN pInfoBuffer
  774. )
  775. /*++
  776. Routine Description:
  777. Locks:
  778. Arguments:
  779. Return Value:
  780. --*/
  781. {
  782. PADAPTER pAdapter;
  783. PUMODE_INTERFACE pInterface;
  784. KIRQL kiIrql;
  785. PCONN_ENTRY pConnEntry;
  786. ULONG ulIndex;
  787. PPENDING_NOTIFICATION pMsg;
  788. TraceEnter(CONN, "LinkDownIndication");
  789. ulIndex = GetConnIndexFromAddr(pInfoBuffer->LocalAddress);
  790. //
  791. // Lock out the connection entry
  792. //
  793. RtAcquireSpinLock(&g_rlConnTableLock,
  794. &kiIrql);
  795. pConnEntry = GetConnEntryGivenIndex(ulIndex);
  796. if(pConnEntry is NULL)
  797. {
  798. Trace(CONN, ERROR,
  799. ("LinkDownIndication: No entry in slot %d\n",
  800. ulIndex));
  801. RtReleaseSpinLock(&g_rlConnTableLock,
  802. kiIrql);
  803. return NDIS_STATUS_SUCCESS;
  804. }
  805. //
  806. // Lock the connection entry or adapter
  807. //
  808. RtAcquireSpinLockAtDpcLevel(pConnEntry->prlLock);
  809. //
  810. // Done with the connection table
  811. //
  812. RtReleaseSpinLockFromDpcLevel(&g_rlConnTableLock);
  813. //
  814. // Mark this connection/adapter as disconnecting
  815. // We can reference these field of the CONN_ENTRY since they cant
  816. // change during its lifetime
  817. //
  818. pAdapter = pConnEntry->pAdapter;
  819. RtAssert(pAdapter);
  820. RtAssert(pAdapter->byState is AS_MAPPED);
  821. pInterface = pAdapter->pInterface;
  822. pMsg = NULL;
  823. if(pInterface->duUsage is DU_CALLIN)
  824. {
  825. IP_STATUS isStatus;
  826. //
  827. // Client connection. This means we have the connection entry
  828. // locked, but the adapter is unlocked
  829. //
  830. pConnEntry->byState = CS_DISCONNECTING;
  831. RtReleaseSpinLock(pConnEntry->prlLock,
  832. kiIrql);
  833. isStatus = g_pfnIpDeleteLink(g_pServerAdapter->pvIpContext,
  834. pConnEntry->pvIpLinkContext);
  835. if(isStatus isnot IP_SUCCESS)
  836. {
  837. Trace(CONN, ERROR,
  838. ("LinkDownIndication: IpDeleteLink returned %x\n",
  839. isStatus));
  840. //
  841. // This is really bad
  842. //
  843. RtAssert(FALSE);
  844. }
  845. }
  846. else
  847. {
  848. //
  849. // Here we have the adapter locked
  850. // The connection entry is protected by the same lock
  851. //
  852. pConnEntry->byState = CS_DISCONNECTING;
  853. //
  854. // Free the interface mapping
  855. //
  856. pAdapter->pInterface = NULL;
  857. pAdapter->byState = AS_UNMAPPING;
  858. //
  859. // Lock the interface list and the interface
  860. // The interface has to be present since it is ref counted
  861. //
  862. EnterWriterAtDpcLevel(&g_rwlIfLock);
  863. RtAcquireSpinLockAtDpcLevel(&(pInterface->rlLock));
  864. //
  865. // Clear out the adapter field.
  866. //
  867. pInterface->pAdapter = NULL;
  868. pInterface->dwOperState = IF_OPER_STATUS_DISCONNECTED;
  869. pInterface->dwLastChange= GetTimeTicks();
  870. pMsg = AllocateNotification();
  871. if(pMsg is NULL)
  872. {
  873. Trace(CONN, ERROR,
  874. ("LinkDownIndication: Couldnt allocate msg\n"));
  875. //
  876. // Really no failure path here
  877. //
  878. RtAssert(FALSE);
  879. }
  880. if(pInterface->duUsage is DU_CALLOUT)
  881. {
  882. if(pMsg)
  883. {
  884. //
  885. // Setup the message
  886. //
  887. pMsg->wnMsg.ddeEvent = DDE_CALLOUT_LINKDOWN;
  888. pMsg->wnMsg.dwAdapterIndex = pInterface->dwRsvdAdapterIndex;
  889. pMsg->wnMsg.dwUserIfIndex = INVALID_IF_INDEX;
  890. pMsg->wnMsg.dwAdapterIndex = pAdapter->dwAdapterIndex;
  891. pMsg->wnMsg.dwLocalAddr = pConnEntry->dwLocalAddr;
  892. pMsg->wnMsg.dwLocalMask = pConnEntry->dwLocalMask;
  893. pMsg->wnMsg.dwRemoteAddr = pConnEntry->dwRemoteAddr;
  894. }
  895. //
  896. // Remove from list and dereference the interface
  897. //
  898. RemoveEntryList(&(pInterface->leIfLink));
  899. InterlockedDecrement(&g_ulNumDialOutInterfaces);
  900. //
  901. // Done with the interface list
  902. //
  903. ExitWriterFromDpcLevel(&g_rwlIfLock);
  904. //
  905. // One ref kept for being on list
  906. // The final deletion will free the index
  907. //
  908. DereferenceInterface(pInterface);
  909. }
  910. else
  911. {
  912. //
  913. // Dont need the interface list lock
  914. //
  915. ExitWriterFromDpcLevel(&g_rwlIfLock);
  916. Trace(CONN, TRACE,
  917. ("LinkDownIndication: For interface %p\n",
  918. pInterface));
  919. //
  920. // For ROUTER interfaces notify user mode of the connection
  921. // going down
  922. //
  923. if(pMsg)
  924. {
  925. //
  926. // Setup the message
  927. //
  928. pMsg->wnMsg.ddeEvent = DDE_INTERFACE_DISCONNECTED;
  929. pMsg->wnMsg.dwAdapterIndex = pInterface->dwRsvdAdapterIndex;
  930. pMsg->wnMsg.dwUserIfIndex = pInterface->dwIfIndex;
  931. pMsg->wnMsg.dwAdapterIndex = pAdapter->dwAdapterIndex;
  932. pMsg->wnMsg.dwLocalAddr = pConnEntry->dwLocalAddr;
  933. pMsg->wnMsg.dwLocalMask = pConnEntry->dwLocalMask;
  934. pMsg->wnMsg.dwRemoteAddr = pConnEntry->dwRemoteAddr;
  935. }
  936. }
  937. //
  938. // Done with the interface and adapter
  939. //
  940. RtReleaseSpinLockFromDpcLevel(&(pInterface->rlLock));
  941. RtReleaseSpinLock(&(pAdapter->rlLock),
  942. kiIrql);
  943. //
  944. // Deref the adapter because it was mapped to the interface
  945. //
  946. DereferenceAdapter(pAdapter);
  947. //
  948. // Deref the interface because it was mapped to the adapter
  949. //
  950. DereferenceInterface(pInterface);
  951. }
  952. //
  953. // Dereference the connection entry twice. Once because NDISWAN is
  954. // removing the connection, and again because GetConnEntry put a
  955. // reference on it
  956. //
  957. DereferenceConnEntry(pConnEntry);
  958. DereferenceConnEntry(pConnEntry);
  959. if(pMsg)
  960. {
  961. //
  962. // Will be non null only for callout where allocation succeeded
  963. //
  964. WanpCompleteIrp(pMsg);
  965. }
  966. return NDIS_STATUS_SUCCESS;
  967. }
  968. UINT
  969. WanDemandDialRequest(
  970. ROUTE_CONTEXT Context,
  971. IPAddr dwDest,
  972. IPAddr dwSource,
  973. BYTE byProtocol,
  974. PBYTE pbyBuffer,
  975. UINT uiLength,
  976. IPAddr dwHdrSrc
  977. )
  978. /*++
  979. Routine Description:
  980. This function services the request by IP to dial out an interface.
  981. IP passes us the context stored within the route. This context is
  982. nothing but the index of the interface to dial.
  983. We first find the interface. If found, we see if the interface is
  984. already mapped. This can happen in some window of time. In such a case
  985. we simply return the adapter mapped to the interface. Otherwise, we
  986. find a free adapter. We map this adapter to the interface and
  987. complete an IRP to the router manager to ask it to connect the interface.
  988. We set the state on the interface and the adapter to reflect the fact
  989. that they are mapped and awaiting connection.
  990. If we dont find a free adapter, we nevertheless ask the router manager
  991. to dial out the interface, but we fail the demand dial request to IP.
  992. We return the adapter (IP) index of the adapter that was mapped.
  993. Locks:
  994. Acquires the g_rwlIfLock as READER to lock out the interface
  995. The release the g_rwlIfLock and acquires the g_rwlAdapterlock to
  996. lock out a free adapter. (NOTE: DOES NOT FOLLOW adapter->interface
  997. hierarchy)
  998. Arguments:
  999. Context
  1000. dwDest
  1001. dwSource
  1002. byProtocol
  1003. pbyBuffer
  1004. uiLength
  1005. Return Value:
  1006. The adapter of the index mapped
  1007. INVALID_IF_INDEX on failure
  1008. --*/
  1009. {
  1010. PADAPTER pAdapter;
  1011. PPENDING_NOTIFICATION pMsg;
  1012. PUMODE_INTERFACE pInterface;
  1013. KIRQL kiIrql;
  1014. DWORD dwAdapterIndex;
  1015. PLIST_ENTRY pleNode;
  1016. TraceEnter(CONN, "DemandDialRequest");
  1017. EnterWriter(&g_rwlAdapterLock,
  1018. &kiIrql);
  1019. EnterReaderAtDpcLevel(&g_rwlIfLock);
  1020. pInterface = WanpFindInterfaceGivenIndex(Context);
  1021. if(pInterface is NULL)
  1022. {
  1023. ExitReaderFromDpcLevel(&g_rwlIfLock);
  1024. ExitWriter(&g_rwlAdapterLock,
  1025. kiIrql);
  1026. Trace(CONN, ERROR,
  1027. ("DemandDialRequest: Couldnt find interface %d\n",
  1028. Context));
  1029. TraceLeave(CONN, "DemandDialRequest");
  1030. return INVALID_IF_INDEX;
  1031. }
  1032. ExitReaderFromDpcLevel(&g_rwlIfLock);
  1033. Trace(CONN, TRACE,
  1034. ("DemandDialRequest: For interface %p\n",
  1035. pInterface));
  1036. //
  1037. // If the interface is already connected, this is just race condition
  1038. //
  1039. if(pInterface->dwOperState >= IF_OPER_STATUS_CONNECTING)
  1040. {
  1041. Trace(CONN, WARN,
  1042. ("DemandDialRequest: I/f state %d, returning old adapter %p\n",
  1043. pInterface->dwOperState,
  1044. pInterface->pAdapter));
  1045. if(pInterface->pAdapter)
  1046. {
  1047. //
  1048. // We can get the adapter index without the holding the adapter
  1049. // lock , because it is a read-only field once the adapter has
  1050. // been added to IP, and can not change while the adapter is
  1051. // is mapped to the interface
  1052. //
  1053. RtAssert(pInterface->pAdapter->dwAdapterIndex is pInterface->dwRsvdAdapterIndex);
  1054. dwAdapterIndex = pInterface->dwRsvdAdapterIndex;
  1055. }
  1056. else
  1057. {
  1058. dwAdapterIndex = INVALID_IF_INDEX;
  1059. }
  1060. RtReleaseSpinLockFromDpcLevel(&(pInterface->rlLock));
  1061. ExitWriter(&g_rwlAdapterLock,
  1062. kiIrql);
  1063. DereferenceInterface(pInterface);
  1064. TraceLeave(CONN, "DemandDialRequest");
  1065. return dwAdapterIndex;
  1066. }
  1067. //
  1068. // We will need to connect this. If we cant get the memory
  1069. // needed for the connection message, bail out
  1070. //
  1071. pMsg = AllocateNotification();
  1072. if(pMsg is NULL)
  1073. {
  1074. Trace(CONN, ERROR,
  1075. ("DemandDialRequest: Couldnt allocate notification\n"));
  1076. RtReleaseSpinLockFromDpcLevel(&(pInterface->rlLock));
  1077. ExitWriter(&g_rwlAdapterLock,
  1078. kiIrql);
  1079. DereferenceInterface(pInterface);
  1080. TraceLeave(CONN, "DemandDialRequest");
  1081. return INVALID_IF_INDEX;
  1082. }
  1083. pInterface->dwOperState = IF_OPER_STATUS_CONNECTING;
  1084. pInterface->dwLastChange= GetTimeTicks();
  1085. //
  1086. // So we dont have an adapter mapped to the interface. Try and find one
  1087. // We dont call FindAdapterToMap because that needs to be at passive
  1088. //
  1089. if(IsListEmpty(&g_leAddedAdapterList))
  1090. {
  1091. Trace(CONN, INFO,
  1092. ("DemandDialRequest: Couldnt find an adapter already added to IP\n"));
  1093. ExitWriterFromDpcLevel(&g_rwlAdapterLock);
  1094. pAdapter = NULL;
  1095. dwAdapterIndex = INVALID_IF_INDEX;
  1096. }
  1097. else
  1098. {
  1099. pleNode = RemoveHeadList(&g_leAddedAdapterList);
  1100. pAdapter = CONTAINING_RECORD(pleNode,
  1101. ADAPTER,
  1102. leAdapterLink);
  1103. RtAcquireSpinLockAtDpcLevel(&(pAdapter->rlLock));
  1104. InsertHeadList(&g_leMappedAdapterList,
  1105. &(pAdapter->leAdapterLink));
  1106. ExitWriterFromDpcLevel(&g_rwlAdapterLock);
  1107. RtAssert(pAdapter->byState is AS_ADDED);
  1108. //
  1109. // So we have a locked adapter
  1110. //
  1111. dwAdapterIndex = pAdapter->dwAdapterIndex;
  1112. //
  1113. // Map the adapter to the interface and refcount the adapter
  1114. // to account for the fact that there is a stored pointer to it
  1115. //
  1116. pInterface->pAdapter = pAdapter;
  1117. ReferenceAdapter(pAdapter);
  1118. //
  1119. // Setup the cross mapping
  1120. //
  1121. pAdapter->pInterface = pInterface;
  1122. pAdapter->byState = AS_MAPPED;
  1123. ReferenceInterface(pInterface);
  1124. Trace(CONN, INFO,
  1125. ("DemandDialRequest: Found adapter %d free for %d\n",
  1126. pAdapter->dwAdapterIndex,
  1127. pInterface->dwIfIndex));
  1128. #if DBG
  1129. Trace(CONN, INFO,
  1130. ("DemandDialRequest: Adapter Index is %d. Name is %s\n",
  1131. pAdapter->dwAdapterIndex,
  1132. pAdapter->asDeviceNameA.Buffer));
  1133. #endif
  1134. }
  1135. //
  1136. // Initialize the info to be sent to the router manager
  1137. //
  1138. pMsg->wnMsg.ddeEvent = DDE_CONNECT_INTERFACE;
  1139. pMsg->wnMsg.dwUserIfIndex = pInterface->dwIfIndex;
  1140. pMsg->wnMsg.dwAdapterIndex = dwAdapterIndex;
  1141. pMsg->wnMsg.dwPacketSrcAddr = dwHdrSrc;
  1142. pMsg->wnMsg.dwPacketDestAddr = dwDest;
  1143. pMsg->wnMsg.ulPacketLength = uiLength;
  1144. pMsg->wnMsg.byPacketProtocol = byProtocol;
  1145. if(uiLength)
  1146. {
  1147. RtlCopyMemory(pMsg->wnMsg.rgbyPacket,
  1148. pbyBuffer,
  1149. MIN(MAX_PACKET_COPY_SIZE,uiLength));
  1150. }
  1151. //
  1152. // Complete any pending IRP or queue the notification
  1153. //
  1154. ExInitializeWorkItem(&pMsg->wqi,
  1155. WanpCompleteIrp,
  1156. pMsg);
  1157. ExQueueWorkItem(&pMsg->wqi,
  1158. DelayedWorkQueue);
  1159. // WanpCompleteIrp(pMsg);
  1160. //
  1161. // Ok so we are done with the adapter and the interface
  1162. //
  1163. RtReleaseSpinLockFromDpcLevel(&(pInterface->rlLock));
  1164. DereferenceInterface(pInterface);
  1165. if(pAdapter)
  1166. {
  1167. RtReleaseSpinLock(&(pAdapter->rlLock),
  1168. kiIrql);
  1169. }
  1170. else
  1171. {
  1172. KeLowerIrql(kiIrql);
  1173. }
  1174. //
  1175. // No need to deref the adapter, since we didnt call FindAdapter
  1176. //
  1177. Trace(CONN, INFO,
  1178. ("DemandDialRequest: Returning adapter %d\n",
  1179. dwAdapterIndex));
  1180. return dwAdapterIndex;
  1181. }
  1182. PCONN_ENTRY
  1183. WanpCreateConnEntry(
  1184. DIAL_USAGE duUsage
  1185. )
  1186. /*++
  1187. Routine Description:
  1188. Allocate a connection entry and find a free slot for it in the
  1189. connection table. Sets the slot into the conn entry
  1190. The connection entry returned is not refcounted.
  1191. Locks:
  1192. Must be called with the g_rlConnTableLock held.
  1193. Arguments:
  1194. duUsage Type of the connection.
  1195. Return Value:
  1196. Pointer to allocate conn entry (if successfull)
  1197. --*/
  1198. {
  1199. PCONN_ENTRY pConnEntry;
  1200. KIRQL kiIrql;
  1201. PULONG_PTR puipTable;
  1202. ULONG ulSize;
  1203. ULONG i, ulIndex;
  1204. TraceEnter(CONN, "CreateConnEntry");
  1205. pConnEntry = AllocateConnection();
  1206. if(pConnEntry is NULL)
  1207. {
  1208. return NULL;
  1209. }
  1210. RtlZeroMemory(pConnEntry,
  1211. sizeof(CONN_ENTRY));
  1212. //
  1213. // The refcount of a connection entry is set to 0 and not 1
  1214. //
  1215. InitConnEntryRefCount(pConnEntry);
  1216. pConnEntry->byState = CS_CONNECTING;
  1217. pConnEntry->duUsage = duUsage;
  1218. //
  1219. // Find a free slot. g_ulNextIndex is a hint
  1220. //
  1221. for(i = 0, ulIndex = g_ulNextConnIndex;
  1222. i < g_ulConnTableSize;
  1223. i++)
  1224. {
  1225. //
  1226. // Slot 0 is initialized to (ULONG_PTR)-1 so it cant match
  1227. //
  1228. if(g_puipConnTable[ulIndex] is (ULONG_PTR)0)
  1229. {
  1230. //
  1231. // Free Slot
  1232. //
  1233. g_puipConnTable[ulIndex] = (ULONG_PTR)pConnEntry;
  1234. g_rgulConns[duUsage]++;
  1235. pConnEntry->ulSlotIndex = ulIndex;
  1236. //
  1237. // We just assume that the next one will be free
  1238. // If not, the timer can fix it. If we get a connection before
  1239. // the timer gets a chance to fix it then we will take a
  1240. // perf hit
  1241. //
  1242. g_ulNextConnIndex++;
  1243. g_ulNextConnIndex = g_ulNextConnIndex % g_ulConnTableSize;
  1244. return pConnEntry;
  1245. }
  1246. ulIndex++;
  1247. //
  1248. // Wrap around
  1249. //
  1250. ulIndex = ulIndex % g_ulConnTableSize;
  1251. }
  1252. //
  1253. // Couldnt find a slot. Grow the table. We are still holding the
  1254. // lock. The way we do this is by growing the table in blocks of
  1255. // 64 entries. We then copy out what we have and update the next index
  1256. // etc
  1257. //
  1258. ulSize = (g_ulConnTableSize + WAN_CONN_TABLE_INCREMENT) * sizeof(ULONG_PTR);
  1259. puipTable = RtAllocate(NonPagedPool,
  1260. ulSize,
  1261. WAN_CONN_TAG);
  1262. if(puipTable is NULL)
  1263. {
  1264. Trace(CONN, ERROR,
  1265. ("AllocateConnEntry: couldnt realloc table of size %d\n",
  1266. ulSize));
  1267. FreeConnection(pConnEntry);
  1268. return NULL;
  1269. }
  1270. //
  1271. // Zero out the new memory
  1272. //
  1273. RtlZeroMemory(puipTable,
  1274. ulSize);
  1275. //
  1276. // Copy out the old table
  1277. //
  1278. RtlCopyMemory(puipTable,
  1279. g_puipConnTable,
  1280. g_ulConnTableSize * sizeof(ULONG_PTR));
  1281. //
  1282. // Free the old table
  1283. //
  1284. RtFree(g_puipConnTable);
  1285. //
  1286. // Set up pointers, indices etc
  1287. //
  1288. g_puipConnTable = puipTable;
  1289. //
  1290. // Since the table was totally full, the next index will be
  1291. // at the start of the new memory. Set the entry to that
  1292. //
  1293. g_puipConnTable[g_ulConnTableSize] = (ULONG_PTR)pConnEntry;
  1294. g_rgulConns[duUsage]++;
  1295. pConnEntry->ulSlotIndex = g_ulConnTableSize;
  1296. //
  1297. // Set the next index to one after the slot we just used
  1298. //
  1299. g_ulNextConnIndex = g_ulConnTableSize + 1;
  1300. //
  1301. // Increast the size to what is currently is
  1302. //
  1303. g_ulConnTableSize += WAN_CONN_TABLE_INCREMENT;
  1304. return pConnEntry;
  1305. }
  1306. VOID
  1307. WanIpCloseLink(
  1308. PVOID pvAdapterContext,
  1309. PVOID pvLinkContext
  1310. )
  1311. /*++
  1312. Routine Description:
  1313. This function is called by IP when its ref counts on the link fall
  1314. to 0.
  1315. Locks:
  1316. None needed
  1317. Arguments:
  1318. pvAdapterContext The context we passed for the P2MP interface
  1319. pvLinkContext The context we passed for a link in IpAddLink()
  1320. Return Value:
  1321. None
  1322. --*/
  1323. {
  1324. PCONN_ENTRY pConnEntry;
  1325. TraceEnter(CONN, "IpCloseLink");
  1326. RtAssert(pvAdapterContext is g_pServerAdapter);
  1327. pConnEntry = (PCONN_ENTRY)pvLinkContext;
  1328. DereferenceConnEntry(pConnEntry);
  1329. }
  1330. VOID
  1331. WanpDeleteConnEntry(
  1332. PCONN_ENTRY pConnEntry
  1333. )
  1334. /*++
  1335. Routine Description:
  1336. This function is called when the refcount on a connection falls to zero
  1337. The connection entry is different from the other structures in wanarp
  1338. in that even when the refcount falls to zero, the pAdapter has a
  1339. pointer to the connection. However when we get here we know that
  1340. no new sends could be forthcoming on this connection because we
  1341. set the connection state to be disconnecting. We have already
  1342. gotten a LinkDown indication on this and all our pending SendComplete's
  1343. have been called
  1344. We also sets the next free index for the connection table
  1345. No shrinking is done here because we do that off a timer
  1346. Locks:
  1347. Acquires the g_rlConnTableLock. The connection entry itself should
  1348. not be locked
  1349. Arguments:
  1350. pConnEntry The connection entry to free
  1351. Return Value:
  1352. None
  1353. --*/
  1354. {
  1355. ULONG ulIndex;
  1356. KIRQL kiIrql;
  1357. PULONG_PTR puipTable;
  1358. SIZE_T stSize;
  1359. PADAPTER pAdapter;
  1360. //
  1361. // Get the slot number
  1362. //
  1363. ulIndex = pConnEntry->ulSlotIndex;
  1364. RtAcquireSpinLock(&g_rlConnTableLock,
  1365. &kiIrql);
  1366. g_puipConnTable[ulIndex] = (ULONG_PTR)0;
  1367. #if DBG
  1368. RtAssert((pConnEntry->duUsage is DU_CALLIN) or
  1369. (pConnEntry->duUsage is DU_CALLOUT) or
  1370. (pConnEntry->duUsage is DU_ROUTER));
  1371. #endif
  1372. g_rgulConns[pConnEntry->duUsage]--;
  1373. if(g_puipConnTable[g_ulNextConnIndex] isnot (ULONG_PTR)0)
  1374. {
  1375. g_ulNextConnIndex = ulIndex;
  1376. }
  1377. RtReleaseSpinLockFromDpcLevel(&g_rlConnTableLock);
  1378. //
  1379. // Get the adapter this connection is mapped to
  1380. //
  1381. pAdapter = pConnEntry->pAdapter;
  1382. #if DBG
  1383. pConnEntry->ulSlotIndex = 0;
  1384. pConnEntry->pAdapter = NULL;
  1385. #endif
  1386. //
  1387. // Done with the connection entry
  1388. //
  1389. FreeConnection(pConnEntry);
  1390. if(pAdapter is NULL)
  1391. {
  1392. KeLowerIrql(kiIrql);
  1393. //
  1394. // Wasnt mapped. Can happen when this function is called to
  1395. // merely free resources from an error case
  1396. //
  1397. return;
  1398. }
  1399. //
  1400. // Lock the adapter list
  1401. //
  1402. EnterWriterAtDpcLevel(&g_rwlAdapterLock);
  1403. if(pAdapter is g_pServerAdapter)
  1404. {
  1405. ExitWriter(&g_rwlAdapterLock,
  1406. kiIrql);
  1407. //
  1408. // Client connection, simply deref the adapter
  1409. //
  1410. DereferenceAdapter(pAdapter);
  1411. return;
  1412. }
  1413. ExitWriterFromDpcLevel(&g_rwlAdapterLock);
  1414. //
  1415. // Lock the adapter
  1416. //
  1417. RtAcquireSpinLockAtDpcLevel(&(pAdapter->rlLock));
  1418. //
  1419. // Remove the entry from the adapter
  1420. //
  1421. pAdapter->pConnEntry = NULL;
  1422. //
  1423. // Done with the adapter
  1424. //
  1425. RtReleaseSpinLock(&(pAdapter->rlLock),
  1426. kiIrql);
  1427. //
  1428. // Called with no locks held
  1429. //
  1430. WanpUnmapAdapter(pAdapter);
  1431. //
  1432. // Dereference the adapter because the conn entry had a pointer
  1433. // to it, which is now gone
  1434. //
  1435. DereferenceAdapter(pAdapter);
  1436. return;
  1437. }
  1438. VOID
  1439. WanpNotifyRouterManager(
  1440. PPENDING_NOTIFICATION pMsg,
  1441. PUMODE_INTERFACE pInterface,
  1442. PADAPTER pAdapter,
  1443. PCONN_ENTRY pConnEntry,
  1444. BOOLEAN bConnected
  1445. )
  1446. /*++
  1447. Routine Description:
  1448. Notifies the router manager when an interface is connected or
  1449. disconnected
  1450. Locks:
  1451. The interface must be locked
  1452. Arguments:
  1453. pMsg
  1454. pInterface The interface being connected or disconnected
  1455. pAdapter
  1456. bConnected Set to TRUE if the interface is being connected
  1457. Return Value:
  1458. --*/
  1459. {
  1460. KIRQL kiIrql;
  1461. TraceEnter(CONN, "WanpNotifyRouterManager");
  1462. if(bConnected)
  1463. {
  1464. pMsg->wnMsg.ddeEvent = DDE_INTERFACE_CONNECTED;
  1465. }
  1466. else
  1467. {
  1468. pMsg->wnMsg.ddeEvent = DDE_INTERFACE_DISCONNECTED;
  1469. }
  1470. pMsg->wnMsg.dwUserIfIndex = pInterface->dwIfIndex;
  1471. pMsg->wnMsg.dwAdapterIndex = pAdapter->dwAdapterIndex;
  1472. pMsg->wnMsg.dwLocalAddr = pConnEntry->dwLocalAddr;
  1473. pMsg->wnMsg.dwLocalMask = pConnEntry->dwLocalMask;
  1474. pMsg->wnMsg.dwRemoteAddr = pConnEntry->dwRemoteAddr;
  1475. //
  1476. // Complete any pending IRP or queue the notification
  1477. //
  1478. WanpCompleteIrp(pMsg);
  1479. }
  1480. PCONN_ENTRY
  1481. WanpGetConnEntryGivenAddress(
  1482. DWORD dwAddress
  1483. )
  1484. {
  1485. ULONG i;
  1486. KIRQL kiIrql;
  1487. PCONN_ENTRY pConnEntry;
  1488. BOOLEAN bFindFirst;
  1489. pConnEntry = NULL;
  1490. RtAcquireSpinLock(&g_rlConnTableLock,
  1491. &kiIrql);
  1492. if((dwAddress is 0xFFFFFFFF) and
  1493. (g_rgulConns[DU_CALLIN] is 1))
  1494. {
  1495. bFindFirst = TRUE;
  1496. }
  1497. else
  1498. {
  1499. bFindFirst = FALSE;
  1500. }
  1501. //
  1502. // Slot 0 is never used
  1503. //
  1504. for(i = 1; i < g_ulConnTableSize; i++)
  1505. {
  1506. //
  1507. // If there is a non-null connection and
  1508. // If either the dest matches, or we want to send a bcast to the
  1509. // first client (that is fully connected)
  1510. //
  1511. if(((PCONN_ENTRY)(g_puipConnTable[i]) isnot NULL) and
  1512. ((((PCONN_ENTRY)(g_puipConnTable[i]))->dwRemoteAddr is dwAddress) or
  1513. (bFindFirst and
  1514. (((PCONN_ENTRY)(g_puipConnTable[i]))->duUsage is DU_CALLIN) and
  1515. (((PCONN_ENTRY)(g_puipConnTable[i]))->byState is CS_CONNECTED))))
  1516. {
  1517. pConnEntry = (PCONN_ENTRY)(g_puipConnTable[i]);
  1518. break;
  1519. }
  1520. }
  1521. RtReleaseSpinLock(&g_rlConnTableLock,
  1522. kiIrql);
  1523. return pConnEntry;
  1524. }
  1525. ULONG
  1526. WanpRemoveAllConnections(
  1527. VOID
  1528. )
  1529. {
  1530. KIRQL kiIrql;
  1531. ULONG ulCount, i;
  1532. RtAcquireSpinLock(&g_rlConnTableLock,
  1533. &kiIrql);
  1534. //
  1535. // Slot 0 is never used
  1536. //
  1537. for(ulCount = 0, i = 1; i < g_ulConnTableSize; i++)
  1538. {
  1539. PCONN_ENTRY pConnEntry;
  1540. pConnEntry = (PCONN_ENTRY)(g_puipConnTable[i]);
  1541. if(pConnEntry is NULL)
  1542. {
  1543. continue;
  1544. }
  1545. g_rgulConns[pConnEntry->duUsage]--;
  1546. FreeConnection(pConnEntry);
  1547. ulCount++;
  1548. g_puipConnTable[i] = 0;
  1549. }
  1550. #if DBG
  1551. RtAssert((g_rgulConns[DU_CALLIN] + g_rgulConns[DU_CALLOUT] + g_rgulConns[DU_ROUTER]) is 0);
  1552. #endif
  1553. RtReleaseSpinLock(&g_rlConnTableLock,
  1554. kiIrql);
  1555. return ulCount;
  1556. }
  1557. BOOLEAN
  1558. WanpIsConnectionTableEmpty(
  1559. VOID
  1560. )
  1561. {
  1562. ULONG i;
  1563. KIRQL kiIrql;
  1564. RtAcquireSpinLock(&g_rlConnTableLock,
  1565. &kiIrql);
  1566. for(i = 1; i < g_ulConnTableSize; i++)
  1567. {
  1568. PCONN_ENTRY pConnEntry;
  1569. pConnEntry = (PCONN_ENTRY)(g_puipConnTable[i]);
  1570. if(pConnEntry isnot NULL)
  1571. {
  1572. RtAssert((g_rgulConns[DU_CALLIN] + g_rgulConns[DU_CALLOUT] + g_rgulConns[DU_ROUTER]) isnot 0);
  1573. RtReleaseSpinLock(&g_rlConnTableLock,
  1574. kiIrql);
  1575. return FALSE;
  1576. }
  1577. }
  1578. RtAssert((g_rgulConns[DU_CALLIN] + g_rgulConns[DU_CALLOUT] + g_rgulConns[DU_ROUTER]) is 0);
  1579. RtReleaseSpinLock(&g_rlConnTableLock,
  1580. kiIrql);
  1581. return TRUE;
  1582. }