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.

1094 lines
23 KiB

  1. /*++
  2. Copyright (c) 1992-1996 Microsoft Corporation
  3. Module Name:
  4. ioctl.c
  5. Abstract:
  6. This file contains the code to implement the IOCTL interface to the atmarp server.
  7. Author:
  8. Jameel Hyder (jameelh@microsoft.com) July 1996
  9. Environment:
  10. Kernel mode
  11. Revision History:
  12. --*/
  13. #include <precomp.h>
  14. #define _FILENUM_ FILENUM_IOCTL
  15. NTSTATUS
  16. ArpSDispatch(
  17. IN PDEVICE_OBJECT pDeviceObject,
  18. IN PIRP pIrp
  19. )
  20. /*++
  21. Routine Description:
  22. Handler for the ioctl interface - not implemented yet.
  23. Arguments:
  24. pDeviceObject ARP Server device object
  25. pIrp IRP
  26. Return Value:
  27. STATUS_NOT_IMPLEMENTED currently
  28. --*/
  29. {
  30. PIO_STACK_LOCATION pIrpSp;
  31. NTSTATUS Status;
  32. static ULONG OpenCount = 0;
  33. ARPS_PAGED_CODE( );
  34. pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
  35. pIrp->IoStatus.Information = 0;
  36. switch (pIrpSp->MajorFunction)
  37. {
  38. case IRP_MJ_CREATE:
  39. DBGPRINT(DBG_LEVEL_INFO,
  40. ("ArpSDispatch: Open Handle\n"));
  41. InterlockedIncrement(&OpenCount);
  42. Status = STATUS_SUCCESS;
  43. break;
  44. case IRP_MJ_CLOSE:
  45. DBGPRINT(DBG_LEVEL_INFO,
  46. ("ArpSDispatch: Close Handle\n"));
  47. Status = STATUS_SUCCESS;
  48. break;
  49. case IRP_MJ_DEVICE_CONTROL:
  50. Status = ArpSHandleIoctlRequest(pIrp, pIrpSp);
  51. break;
  52. case IRP_MJ_FILE_SYSTEM_CONTROL:
  53. Status = STATUS_NOT_IMPLEMENTED;
  54. break;
  55. case IRP_MJ_CLEANUP:
  56. DBGPRINT(DBG_LEVEL_INFO,
  57. ("ArpSDispatch: Cleanup Handle\n"));
  58. Status = STATUS_SUCCESS;
  59. InterlockedDecrement(&OpenCount);
  60. break;
  61. case IRP_MJ_SHUTDOWN:
  62. DBGPRINT(DBG_LEVEL_INFO,
  63. ("ArpSDispatch: Shutdown\n"));
  64. ArpSShutDown();
  65. Status = STATUS_SUCCESS;
  66. break;
  67. default:
  68. Status = STATUS_NOT_IMPLEMENTED;
  69. break;
  70. }
  71. ASSERT (KeGetCurrentIrql() < DISPATCH_LEVEL);
  72. if (Status != STATUS_PENDING)
  73. {
  74. pIrp->IoStatus.Status = Status;
  75. IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT);
  76. }
  77. else
  78. {
  79. IoMarkIrpPending(pIrp);
  80. }
  81. return Status;
  82. }
  83. NTSTATUS
  84. ArpSHandleIoctlRequest(
  85. IN PIRP pIrp,
  86. IN PIO_STACK_LOCATION pIrpSp
  87. )
  88. /*++
  89. Routine Description:
  90. Arguments:
  91. Return Value:
  92. --*/
  93. {
  94. NTSTATUS Status = STATUS_SUCCESS;
  95. PUCHAR pBuf;
  96. UINT BufLen;
  97. PINTF pIntF = NULL;
  98. pIrp->IoStatus.Information = 0;
  99. pBuf = pIrp->AssociatedIrp.SystemBuffer;
  100. BufLen = pIrpSp->Parameters.DeviceIoControl.InputBufferLength;
  101. switch (pIrpSp->Parameters.DeviceIoControl.IoControlCode)
  102. {
  103. case ARPS_IOCTL_FLUSH_ARPCACHE:
  104. case ARPS_IOCTL_QUERY_ARPCACHE:
  105. case ARPS_IOCTL_ADD_ARPENTRY:
  106. case ARPS_IOCTL_QUERY_IP_FROM_ATM:
  107. case ARPS_IOCTL_QUERY_ATM_FROM_IP:
  108. case ARPS_IOCTL_QUERY_ARP_STATISTICS:
  109. case ARPS_IOCTL_QUERY_MARSCACHE:
  110. case ARPS_IOCTL_QUERY_MARS_STATISTICS:
  111. case ARPS_IOCTL_RESET_STATISTICS:
  112. {
  113. INTERFACE_NAME RawName;
  114. UINT Offset;
  115. if (pIrpSp->Parameters.DeviceIoControl.IoControlCode == ARPS_IOCTL_QUERY_ARPCACHE)
  116. {
  117. Offset = FIELD_OFFSET(IOCTL_QUERY_CACHE, Name);
  118. }
  119. else if (pIrpSp->Parameters.DeviceIoControl.IoControlCode == ARPS_IOCTL_QUERY_MARSCACHE)
  120. {
  121. Offset = FIELD_OFFSET(IOCTL_QUERY_MARS_CACHE, Name);
  122. }
  123. else
  124. {
  125. Offset = 0;
  126. }
  127. if (BufLen < sizeof(INTERFACE_NAME) + Offset)
  128. {
  129. return STATUS_INVALID_PARAMETER;
  130. }
  131. RawName = *(PINTERFACE_NAME)((PUCHAR)pBuf + Offset);
  132. RawName.Buffer = (PWSTR)(pBuf + Offset + (ULONG_PTR)RawName.Buffer); // fixup ptr
  133. //
  134. // Probe away...
  135. //
  136. if ( (PUCHAR)RawName.Buffer < (pBuf+sizeof(INTERFACE_NAME))
  137. || (PUCHAR)RawName.Buffer >= (pBuf+BufLen)
  138. || ((PUCHAR)RawName.Buffer + RawName.Length) > (pBuf+BufLen))
  139. {
  140. return STATUS_INVALID_PARAMETER;
  141. }
  142. pIntF = ArpSReferenceIntFByName(&RawName);
  143. if (pIntF == NULL)
  144. {
  145. return STATUS_NOT_FOUND;
  146. }
  147. }
  148. break;
  149. }
  150. switch (pIrpSp->Parameters.DeviceIoControl.IoControlCode)
  151. {
  152. case ARPS_IOCTL_QUERY_INTERFACES:
  153. DBGPRINT(DBG_LEVEL_NOTICE,
  154. ("ArpSHandleIoctlRequest: QUERY_INTERFACES\n"));
  155. pIrp->IoStatus.Information = BufLen;
  156. Status = ArpSEnumerateInterfaces(pBuf, &pIrp->IoStatus.Information);
  157. break;
  158. case ARPS_IOCTL_FLUSH_ARPCACHE:
  159. ASSERT (pIntF);
  160. DBGPRINT(DBG_LEVEL_NOTICE,
  161. ("ArpSHandleIoctlRequest: FLUSH_ARPCACHE on %Z\n",
  162. &pIntF->FriendlyName));
  163. Status = ArpSFlushArpCache(pIntF);
  164. pIrp->IoStatus.Information = 0;
  165. break;
  166. case ARPS_IOCTL_QUERY_ARPCACHE:
  167. ASSERT (pIntF);
  168. DBGPRINT(DBG_LEVEL_NOTICE,
  169. ("ArpSHandleIoctlRequest: QUERY_ARPCACHE on %Z\n",
  170. &pIntF->FriendlyName));
  171. pIrp->IoStatus.Information = pIrpSp->Parameters.DeviceIoControl.OutputBufferLength;
  172. Status = ArpSQueryArpCache(pIntF, pBuf, &pIrp->IoStatus.Information);
  173. break;
  174. #if 0
  175. //
  176. // These need more work - commented out as they aren't critical.
  177. //
  178. case ARPS_IOCTL_ADD_ARPENTRY:
  179. ASSERT (pIntF);
  180. DBGPRINT(DBG_LEVEL_NOTICE,
  181. ("ArpSHandleIoctlRequest: QUERY_ADD_ARPENTRY on %Z\n",
  182. &pIntF->FriendlyName));
  183. Status = ArpSQueryOrAddArpEntry(pIntF, (PIOCTL_QA_ENTRY)pBuf, ADD_ARP_ENTRY);
  184. break;
  185. case ARPS_IOCTL_QUERY_IP_FROM_ATM:
  186. ASSERT (pIntF);
  187. DBGPRINT(DBG_LEVEL_NOTICE,
  188. ("ArpSHandleIoctlRequest: QUERY_IP_ADDR on %Z\n",
  189. &pIntF->FriendlyName));
  190. Status = ArpSQueryOrAddArpEntry(pIntF, (PIOCTL_QA_ENTRY)pBuf, QUERY_IP_FROM_ATM);
  191. if (Status == STATUS_SUCCESS)
  192. {
  193. pIrp->IoStatus.Information = sizeof(IOCTL_QA_ENTRY);
  194. }
  195. break;
  196. case ARPS_IOCTL_QUERY_ATM_FROM_IP:
  197. ASSERT (pIntF);
  198. DBGPRINT(DBG_LEVEL_NOTICE,
  199. ("ArpSHandleIoctlRequest: QUERY_ATM_ADDR on %Z\n",
  200. pIntF->FriendlyName));
  201. Status = ArpSQueryOrAddArpEntry( pIntF, (PIOCTL_QA_ENTRY)pBuf, QUERY_ATM_FROM_IP );
  202. if (Status == STATUS_SUCCESS)
  203. {
  204. pIrp->IoStatus.Information = sizeof(IOCTL_QA_ENTRY);
  205. }
  206. break;
  207. #endif // 0
  208. case ARPS_IOCTL_QUERY_ARP_STATISTICS:
  209. ASSERT (pIntF);
  210. DBGPRINT(DBG_LEVEL_NOTICE,
  211. ("ArpSHandleIoctlRequest: QUERY_ARP_STATS on %Z\n",
  212. pIntF->FriendlyName));
  213. if (BufLen<sizeof(ARP_SERVER_STATISTICS))
  214. {
  215. Status = STATUS_BUFFER_TOO_SMALL;
  216. break;
  217. }
  218. Status = ArpSQueryArpStats( pIntF, (PARP_SERVER_STATISTICS)pBuf);
  219. if (Status == STATUS_SUCCESS)
  220. {
  221. pIrp->IoStatus.Information = sizeof(ARP_SERVER_STATISTICS);
  222. }
  223. break;
  224. case ARPS_IOCTL_QUERY_MARSCACHE:
  225. ASSERT (pIntF);
  226. DBGPRINT(DBG_LEVEL_NOTICE,
  227. ("ArpSHandleIoctlRequest: QUERY_MARSCACHE on %Z\n",
  228. &pIntF->FriendlyName));
  229. pIrp->IoStatus.Information = pIrpSp->Parameters.DeviceIoControl.OutputBufferLength;
  230. Status = ArpSQueryMarsCache(pIntF, pBuf, &pIrp->IoStatus.Information);
  231. break;
  232. case ARPS_IOCTL_QUERY_MARS_STATISTICS:
  233. ASSERT (pIntF);
  234. DBGPRINT(DBG_LEVEL_NOTICE,
  235. ("ArpSHandleIoctlRequest: QUERY_MARS_STATS on %Z\n",
  236. pIntF->FriendlyName));
  237. if (BufLen<sizeof(MARS_SERVER_STATISTICS))
  238. {
  239. Status = STATUS_BUFFER_TOO_SMALL;
  240. break;
  241. }
  242. Status = ArpSQueryMarsStats( pIntF, (PMARS_SERVER_STATISTICS)pBuf);
  243. if (Status == STATUS_SUCCESS)
  244. {
  245. pIrp->IoStatus.Information = sizeof(MARS_SERVER_STATISTICS);
  246. }
  247. break;
  248. case ARPS_IOCTL_RESET_STATISTICS:
  249. ASSERT (pIntF);
  250. DBGPRINT(DBG_LEVEL_NOTICE,
  251. ("ArpSHandleIoctlRequest: RESET_STATISTICS on %Z\n",
  252. pIntF->FriendlyName));
  253. ArpSResetStats(pIntF);
  254. pIrp->IoStatus.Information = 0;
  255. break;
  256. default:
  257. Status = STATUS_NOT_SUPPORTED;
  258. DBGPRINT(DBG_LEVEL_NOTICE,
  259. ("ArpSHandleIoctlRequest: Unknown request %lx\n",
  260. pIrpSp->Parameters.DeviceIoControl.IoControlCode));
  261. break;
  262. }
  263. if (pIntF != NULL)
  264. {
  265. ArpSDereferenceIntF(pIntF);
  266. }
  267. return Status;
  268. }
  269. NTSTATUS
  270. ArpSEnumerateInterfaces(
  271. IN PUCHAR pBuffer,
  272. IN OUT PULONG_PTR pSize
  273. )
  274. /*++
  275. Routine Description:
  276. Arguments:
  277. Return Value:
  278. --*/
  279. {
  280. PINTERFACES pInterfaces = (PINTERFACES)pBuffer;
  281. PINTERFACE_NAME pInterface;
  282. NTSTATUS Status = STATUS_SUCCESS;
  283. PINTF pIntF;
  284. KIRQL OldIrql;
  285. UINT Size, Total, Remaining;
  286. PUCHAR pBuf;
  287. UINT InputSize = (UINT) *pSize;
  288. ULONG IfIndex;
  289. if (InputSize < sizeof(INTERFACES))
  290. {
  291. return STATUS_BUFFER_TOO_SMALL;
  292. }
  293. pInterfaces->NumberOfInterfaces = 0;
  294. pBuf = (PUCHAR)pInterfaces + InputSize;
  295. ACQUIRE_SPIN_LOCK(&ArpSIfListLock, &OldIrql);
  296. pInterface = &pInterfaces->Interfaces[0];
  297. for (pIntF = ArpSIfList, Total = 0, Remaining = InputSize, IfIndex = 1;
  298. pIntF != NULL;
  299. pIntF = pIntF->Next, pInterface++, IfIndex++)
  300. {
  301. if (IfIndex > ArpSIfListSize)
  302. {
  303. DbgPrint("ATMARPS: EnumInt: IF list at %p not consistent with list size %d\n",
  304. ArpSIfList, ArpSIfListSize);
  305. DbgBreakPoint();
  306. break;
  307. }
  308. Size = sizeof(INTERFACE_NAME) + pIntF->FriendlyName.Length;
  309. if (Size > Remaining)
  310. {
  311. Status = STATUS_BUFFER_OVERFLOW;
  312. break;
  313. }
  314. pInterfaces->NumberOfInterfaces ++;
  315. pInterface->MaximumLength = pInterface->Length = pIntF->FriendlyName.Length;
  316. pInterface->Buffer = (PWSTR)(pBuf - pIntF->FriendlyName.Length);
  317. COPY_MEM(pInterface->Buffer, pIntF->FriendlyName.Buffer, pIntF->FriendlyName.Length);
  318. pBuf -= pIntF->FriendlyName.Length;
  319. Total += Size;
  320. Remaining -= Size;
  321. //
  322. // Convert the ptr now to an offset
  323. //
  324. pInterface->Buffer = (PWSTR)((ULONG_PTR)pInterface->Buffer - (ULONG_PTR)pInterface);
  325. }
  326. RELEASE_SPIN_LOCK(&ArpSIfListLock, OldIrql);
  327. //
  328. // Note: leave *pSize as is, because we write at the end of the
  329. // passed-in buffer.
  330. //
  331. return Status;
  332. }
  333. NTSTATUS
  334. ArpSFlushArpCache(
  335. IN PINTF pIntF
  336. )
  337. /*++
  338. Routine Description:
  339. Arguments:
  340. Return Value:
  341. --*/
  342. {
  343. NTSTATUS Status = STATUS_SUCCESS;
  344. PARP_ENTRY ArpEntry, NextArpEntry;
  345. KIRQL OldIrql;
  346. UINT i;
  347. //
  348. // Acquire the ArpCache mutex now.
  349. //
  350. WAIT_FOR_OBJECT(Status, &pIntF->ArpCacheMutex, NULL);
  351. ASSERT (Status == STATUS_SUCCESS);
  352. for (i = 0; i < ARP_TABLE_SIZE; i++)
  353. {
  354. for (ArpEntry = pIntF->ArpCache[i];
  355. ArpEntry != NULL;
  356. ArpEntry = NextArpEntry)
  357. {
  358. NextArpEntry = ArpEntry->Next;
  359. if (ArpEntry->Vc != NULL)
  360. {
  361. ACQUIRE_SPIN_LOCK(&pIntF->Lock, &OldIrql);
  362. ArpEntry->Vc->ArpEntry = NULL;
  363. RELEASE_SPIN_LOCK(&pIntF->Lock, OldIrql);
  364. }
  365. if (ArpEntry->Next != NULL)
  366. {
  367. ((PENTRY_HDR)(ArpEntry->Next))->Prev = ArpEntry->Prev;
  368. }
  369. *(ArpEntry->Prev) = ArpEntry->Next;
  370. ArpSFreeBlock(ArpEntry);
  371. pIntF->NumCacheEntries --;
  372. }
  373. }
  374. RELEASE_MUTEX(&pIntF->ArpCacheMutex);
  375. return Status;
  376. }
  377. NTSTATUS
  378. ArpSQueryOrAddArpEntry(
  379. IN PINTF pIntF,
  380. IN OUT PIOCTL_QA_ENTRY pQaBuf,
  381. IN OPERATION Operation
  382. )
  383. /*++
  384. Routine Description:
  385. Arguments:
  386. Return Value:
  387. --*/
  388. {
  389. NTSTATUS Status = STATUS_SUCCESS;
  390. PARP_ENTRY ArpEntry;
  391. //
  392. // Acquire the ArpCache mutex now.
  393. //
  394. WAIT_FOR_OBJECT(Status, &pIntF->ArpCacheMutex, NULL);
  395. ASSERT (Status == STATUS_SUCCESS);
  396. switch (Operation)
  397. {
  398. case QUERY_IP_FROM_ATM:
  399. if ( !ArpSValidAtmAddress(&pQaBuf->ArpEntry.AtmAddress, 0) // TODO
  400. || !ArpSValidAtmAddress(&pQaBuf->ArpEntry.SubAddress, 0)) // TODO
  401. {
  402. DBGPRINT(DBG_LEVEL_ERROR,
  403. ("QueryIpAddress: Invalid address or subaddress\n"));
  404. Status = STATUS_INVALID_PARAMETER;
  405. break;
  406. }
  407. DBGPRINT(DBG_LEVEL_NOTICE,
  408. ("QueryIpAddress for "));
  409. ArpSDumpAtmAddr(&pQaBuf->ArpEntry.AtmAddress, "");
  410. if (pQaBuf->ArpEntry.SubAddress.NumberOfDigits != 0)
  411. ArpSDumpAtmAddr(&pQaBuf->ArpEntry.SubAddress, "\tSub");
  412. ArpEntry = ArpSLookupEntryByAtmAddr(pIntF,
  413. &pQaBuf->ArpEntry.AtmAddress,
  414. (pQaBuf->ArpEntry.SubAddress.NumberOfDigits != 0) ?
  415. &pQaBuf->ArpEntry.SubAddress : NULL);
  416. Status = STATUS_NOT_FOUND;
  417. if (ArpEntry != NULL)
  418. {
  419. pQaBuf->ArpEntry.IpAddr = ArpEntry->IpAddr;
  420. Status = STATUS_SUCCESS;
  421. }
  422. break;
  423. case QUERY_ATM_FROM_IP:
  424. DBGPRINT(DBG_LEVEL_NOTICE,
  425. ("QueryAtmAddress for "));
  426. ArpSDumpIpAddr(pQaBuf->ArpEntry.IpAddr, "");
  427. ArpEntry = ArpSLookupEntryByIpAddr(pIntF, pQaBuf->ArpEntry.IpAddr);
  428. Status = STATUS_NOT_FOUND;
  429. if (ArpEntry != NULL)
  430. {
  431. COPY_ATM_ADDR(&pQaBuf->ArpEntry.AtmAddress, &ArpEntry->HwAddr.Address);
  432. Status = STATUS_SUCCESS;
  433. }
  434. break;
  435. #if 0
  436. case ADD_ARP_ENTRY:
  437. if ( !ArpSValidAtmAddress(&pQaBuf->ArpEntry.AtmAddress, 0) // TODO
  438. || !ArpSValidAtmAddress(&pQaBuf->ArpEntry.SubAddress, 0)) // TODO
  439. {
  440. DBGPRINT(DBG_LEVEL_ERROR,
  441. ("AddArpEntry: Invalid address or subaddress\n"));
  442. Status = STATUS_INVALID_PARAMETER;
  443. break;
  444. }
  445. DBGPRINT(DBG_LEVEL_NOTICE, ("AddArpEntry: IpAddr "));
  446. ArpSDumpIpAddr(pQaBuf->ArpEntry.IpAddr, "");
  447. ArpSDumpAtmAddr(&pQaBuf->ArpEntry.AtmAddress, "");
  448. if (pQaBuf->ArpEntry.SubAddress.NumberOfDigits != 0)
  449. ArpSDumpAtmAddr(&pQaBuf->ArpEntry.SubAddress, "\tSub");
  450. ArpEntry = ArpSAddArpEntry(pIntF,
  451. pQaBuf->ArpEntry.IpAddr,
  452. &pQaBuf->ArpEntry.AtmAddress,
  453. (pQaBuf->ArpEntry.SubAddress.NumberOfDigits != 0) ?
  454. &pQaBuf->ArpEntry.SubAddress : NULL,
  455. NULL);
  456. #endif // 0
  457. break;
  458. default:
  459. Status = STATUS_NOT_SUPPORTED;
  460. break;
  461. }
  462. RELEASE_MUTEX(&pIntF->ArpCacheMutex);
  463. return Status;
  464. }
  465. NTSTATUS
  466. ArpSQueryArpCache(
  467. IN PINTF pIntF,
  468. IN PUCHAR pBuf,
  469. IN OUT PULONG_PTR pSize
  470. )
  471. {
  472. NTSTATUS Status = STATUS_SUCCESS;
  473. PIOCTL_QUERY_CACHE pQCache = (PIOCTL_QUERY_CACHE)pBuf;
  474. PARP_ENTRY ArpEntry;
  475. PARPENTRY Entry;
  476. UINT i, Total, Remaining;
  477. UINT InputSize = (UINT) *pSize;
  478. UINT StartIndex;
  479. #define HEADERSIZE (UINT)FIELD_OFFSET(IOCTL_QUERY_CACHE, Entries.Entries)
  480. if (InputSize < HEADERSIZE)
  481. {
  482. //
  483. // We don't even have enough space to store the
  484. // IOCTL_QUERY_CACHE.Entries structure!
  485. //
  486. return STATUS_BUFFER_TOO_SMALL;
  487. }
  488. //
  489. // Acquire the ArpCache mutex now.
  490. //
  491. WAIT_FOR_OBJECT(Status, &pIntF->ArpCacheMutex, NULL);
  492. ASSERT (Status == STATUS_SUCCESS);
  493. StartIndex = pQCache->StartEntryIndex;
  494. pQCache->Entries.TotalNumberOfEntries = pIntF->NumCacheEntries;
  495. pQCache->Entries.NumberOfEntriesInBuffer = 0;
  496. Entry = &pQCache->Entries.Entries[0];
  497. for (i = 0, Total = 0, Remaining = InputSize - HEADERSIZE;
  498. i < ARP_TABLE_SIZE;
  499. i++)
  500. {
  501. for (ArpEntry = pIntF->ArpCache[i];
  502. ArpEntry != NULL;
  503. ArpEntry = ArpEntry->Next)
  504. {
  505. //
  506. // Skip entries until we reach entry # StartIndex
  507. //
  508. if (StartIndex != 0)
  509. {
  510. StartIndex--;
  511. continue;
  512. }
  513. if (sizeof(*Entry) > Remaining)
  514. {
  515. break;
  516. }
  517. Remaining -= sizeof(ARPENTRY);
  518. Entry->IpAddr = ArpEntry->IpAddr;
  519. Entry->AtmAddress = ArpEntry->HwAddr.Address;
  520. Entry->SubAddress.NumberOfDigits = 0;
  521. if (ArpEntry->HwAddr.SubAddress != NULL)
  522. Entry->SubAddress = *ArpEntry->HwAddr.SubAddress;
  523. pQCache->Entries.NumberOfEntriesInBuffer ++;
  524. Entry ++;
  525. }
  526. if (Status == STATUS_BUFFER_OVERFLOW)
  527. break;
  528. }
  529. RELEASE_MUTEX(&pIntF->ArpCacheMutex);
  530. return Status;
  531. }
  532. NTSTATUS
  533. ArpSQueryMarsCache(
  534. IN PINTF pIntF,
  535. IN PUCHAR pBuf,
  536. IN OUT PULONG_PTR pSize
  537. )
  538. /*++
  539. Routine Description:
  540. Dump the mars cache into pBuf. The structure is QUERY_MARS_CACHE.MarsCache.
  541. The atm addresses are all placed together at the end of the supplied buffer,
  542. so the full size, *pSize, is used.
  543. Arguments:
  544. pIntF - The interface on which the MARS_REQUEST arrived
  545. Vc - The VC on which the packet arrived
  546. Header - Points to the request packet
  547. Packet - Packet where the incoming information is copied
  548. Return Value:
  549. None
  550. --*/
  551. {
  552. NTSTATUS Status = STATUS_SUCCESS;
  553. PMARS_ENTRY pMarsEntry;
  554. PMARSENTRY pEntry;
  555. UINT i, Total, Remaining;
  556. KIRQL OldIrql;
  557. ATM_ADDRESS *pAtmAddr;
  558. UINT InputSize;
  559. UINT StartIndex;
  560. PIOCTL_QUERY_MARS_CACHE pQCache = (PIOCTL_QUERY_MARS_CACHE)pBuf;
  561. #define MCHEADERSIZE \
  562. ((UINT)FIELD_OFFSET(IOCTL_QUERY_MARS_CACHE, MarsCache.Entries))
  563. //
  564. // Since we put stuff at the end of the buffer, let's force the
  565. // size to be a multiple of ULONG_PTR size.
  566. //
  567. InputSize = (UINT)(*pSize) & ~ ((UINT) (sizeof(ULONG_PTR)-1));
  568. DBGPRINT(DBG_LEVEL_NOTICE,
  569. ("QueryMarsCache: pBuf=0x%lx Size=%lu. pBuf+Size=0x%lx\n",
  570. pBuf,
  571. InputSize,
  572. pBuf+InputSize
  573. ));
  574. if (InputSize < MCHEADERSIZE)
  575. {
  576. DBGPRINT(DBG_LEVEL_NOTICE,
  577. ("QueryMarsCache: Size %lu too small. Want %lu\n",
  578. InputSize,
  579. MCHEADERSIZE
  580. ));
  581. //
  582. // We don't even have enough space to store the
  583. // IOCTL_QUERY_CACHE.Entries structure!
  584. //
  585. return STATUS_BUFFER_TOO_SMALL;
  586. }
  587. StartIndex = pQCache->StartEntryIndex;
  588. // Acquire the lock on the interface now
  589. ACQUIRE_SPIN_LOCK(&pIntF->Lock, &OldIrql);
  590. pQCache->MarsCache.TotalNumberOfEntries = 0;
  591. pQCache->MarsCache.Sig = SIG_MARSENTRY;
  592. pQCache->MarsCache.NumberOfEntriesInBuffer = 0;
  593. pEntry = &pQCache->MarsCache.Entries[0];
  594. //
  595. // We'll go through the entire cache, but only pick up as many
  596. // as we have space for. pAtmAddr contains the next location to
  597. // put an atm address -- it starts out at the end of the buffer and
  598. // works it's way backwards. Meanwhile, the mars entries are growing
  599. // forward, starting with pQCache->MarseCache.Entries[1].
  600. // Needless to say, we must keep track of how much space is left.
  601. //
  602. pAtmAddr = ((PATM_ADDRESS) (pBuf + InputSize));
  603. for (i = 0, Total = 0, Remaining = InputSize-MCHEADERSIZE;
  604. i < MARS_TABLE_SIZE && Status == STATUS_SUCCESS;
  605. i++)
  606. {
  607. for (pMarsEntry = pIntF->MarsCache[i];
  608. pMarsEntry != NULL && Status == STATUS_SUCCESS;
  609. pMarsEntry = pMarsEntry->Next)
  610. {
  611. PGROUP_MEMBER pGroup;
  612. UINT NumMembersPickedUp=0;
  613. //
  614. // Skip entries until we reach entry # StartIndex
  615. //
  616. if (StartIndex != 0)
  617. {
  618. StartIndex--;
  619. continue;
  620. }
  621. if (sizeof(*pEntry) > Remaining)
  622. {
  623. DBGPRINT(
  624. DBG_LEVEL_NOTICE,
  625. ("QueryMarsCache: \tOut of space. Remaining=%lu\n", Remaining));
  626. break;
  627. }
  628. DBGPRINT(
  629. DBG_LEVEL_NOTICE,
  630. ("QueryMarsCache: \tPicking up Group 0x%x. IP=0x%08lx NumAddr=%lu pE=0x%x Remaining=%lu\n",
  631. pMarsEntry,
  632. pMarsEntry->IPAddress,
  633. pMarsEntry->NumMembers,
  634. pEntry,
  635. Remaining));
  636. Remaining -= sizeof(*pEntry);
  637. pQCache->MarsCache.NumberOfEntriesInBuffer ++;
  638. GETULONG2ULONG(&(pEntry->IpAddr), &(pMarsEntry->IPAddress));
  639. pEntry->Flags = 0;
  640. pEntry->NumAtmAddresses = pMarsEntry->NumMembers;
  641. pEntry->OffsetAtmAddresses = 0;
  642. if (MarsIsAddressMcsServed(pIntF, pMarsEntry->IPAddress))
  643. {
  644. pEntry->Flags |= MARSENTRY_MCS_SERVED;
  645. }
  646. //
  647. // Pick up the HW addresses of all the members of this group.
  648. // (TODO: We don't pick up the subaddress).
  649. //
  650. for (
  651. pGroup = pMarsEntry->pMembers, NumMembersPickedUp=0;
  652. pGroup != NULL;
  653. pGroup = pGroup->Next, NumMembersPickedUp++)
  654. {
  655. ARPS_ASSERT(pGroup != NULL_PGROUP_MEMBER);
  656. //
  657. // Check that we have enough space.
  658. //
  659. if (Remaining < sizeof(*pAtmAddr))
  660. {
  661. //
  662. // If there is not enough space to store all atm addresses
  663. // of a particular group, we return none, this is indicated
  664. // by setting pEntry->OffsetAtmAdresses to 0.
  665. //
  666. DBGPRINT(
  667. DBG_LEVEL_NOTICE,
  668. ("QueryMarsCache: \t\tOut of space adding addreses. Remaining=%lu\n", Remaining));
  669. Status = STATUS_BUFFER_OVERFLOW;
  670. break;
  671. }
  672. ARPS_ASSERT( (PUCHAR)(pAtmAddr-1) >= (PUCHAR)(pEntry+1));
  673. //
  674. // Copy over the atm address
  675. //
  676. DBGPRINT(
  677. DBG_LEVEL_NOTICE,
  678. ("QueryMarsCache: \t\tPicking up Addr. pDestAddr=%x. Remaining=%lu\n",
  679. pAtmAddr-1,
  680. Remaining));
  681. *--pAtmAddr = pGroup->pClusterMember->HwAddr.Address;
  682. Remaining -= sizeof(*pAtmAddr);
  683. }
  684. if (Status == STATUS_SUCCESS && NumMembersPickedUp)
  685. {
  686. //
  687. // There are non-zero members of this entry and they were
  688. // all copied successfully. Let's set the offset to these
  689. // addresses.
  690. //
  691. pEntry->OffsetAtmAddresses =
  692. (UINT) ((PUCHAR)pAtmAddr - (PUCHAR) pEntry);
  693. //
  694. // We expect NumMembersPickedUp to be equal to
  695. // pMarsEntry->NumMembers.
  696. //
  697. ARPS_ASSERT(pMarsEntry->NumMembers == NumMembersPickedUp);
  698. if (pMarsEntry->NumMembers != NumMembersPickedUp)
  699. {
  700. pEntry->NumAtmAddresses = NumMembersPickedUp;
  701. }
  702. DBGPRINT(
  703. DBG_LEVEL_NOTICE,
  704. ("QueryMarsCache: \t Picked up all addresses. OffsetAtmAddresses = %lu\n",
  705. pEntry->OffsetAtmAddresses));
  706. pEntry++;
  707. }
  708. }
  709. }
  710. pQCache->MarsCache.TotalNumberOfEntries =
  711. pQCache->MarsCache.NumberOfEntriesInBuffer; // TODO
  712. RELEASE_SPIN_LOCK(&pIntF->Lock, OldIrql);
  713. return Status;
  714. }
  715. UINT
  716. ArpSElapsedSeconds(
  717. IN PLARGE_INTEGER pStatisticsStartTimeStamp
  718. )
  719. /*++
  720. Routine Description:
  721. Return the elapsed time, in seconds, relative to *pStatisticsStartTimeStamp
  722. Arguments:
  723. pStatisticsStartTimeStamp ptr to the start time.
  724. Return Value:
  725. None
  726. --*/
  727. {
  728. UINT Ret;
  729. LARGE_INTEGER Current;
  730. NdisGetCurrentSystemTime(&Current);
  731. //
  732. // Current is in units of 100-nanoseconds so we must convert the difference
  733. // to seconds. Note we use implicit large-arithmetic operators here.
  734. //
  735. Ret = (UINT) ((Current.QuadPart - pStatisticsStartTimeStamp->QuadPart)/10000000);
  736. return Ret;
  737. }
  738. extern
  739. NTSTATUS
  740. ArpSQueryArpStats(
  741. IN PINTF pIntF,
  742. OUT PARP_SERVER_STATISTICS pArpStats
  743. )
  744. /*++
  745. Routine Description:
  746. Fill in the current arp statistics. Also set the ElapsedSeconds field
  747. to the time in seconds since statistics computation started.
  748. Arguments:
  749. pIntF - The interface applicable to the request
  750. pArpStats - Arp statistics to fill out
  751. Return Value:
  752. STATUS_SUCCESS
  753. --*/
  754. {
  755. KIRQL OldIrql;
  756. ACQUIRE_SPIN_LOCK(&pIntF->Lock, &OldIrql);
  757. *pArpStats = pIntF->ArpStats; // big structure copy.
  758. pArpStats->ElapsedSeconds = ArpSElapsedSeconds(
  759. &(pIntF->StatisticsStartTimeStamp)
  760. );
  761. RELEASE_SPIN_LOCK(&pIntF->Lock, OldIrql);
  762. return STATUS_SUCCESS;
  763. }
  764. extern
  765. NTSTATUS
  766. ArpSQueryMarsStats(
  767. IN PINTF pIntF,
  768. OUT PMARS_SERVER_STATISTICS pMarsStats
  769. )
  770. /*++
  771. Routine Description:
  772. Fill in the current mars statistics. Also set the ElapsedSeconds field
  773. to the time in seconds since statistics computation started.
  774. Arguments:
  775. pIntF - The interface applicable to the request
  776. pMarsStats - Mars statistics to fill out.
  777. Return Value:
  778. STATUS_SUCCESS
  779. --*/
  780. {
  781. KIRQL OldIrql;
  782. ACQUIRE_SPIN_LOCK(&pIntF->Lock, &OldIrql);
  783. *pMarsStats = pIntF->MarsStats; // big structure copy.
  784. pMarsStats->ElapsedSeconds = ArpSElapsedSeconds(
  785. &(pIntF->StatisticsStartTimeStamp)
  786. );
  787. RELEASE_SPIN_LOCK(&pIntF->Lock, OldIrql);
  788. return STATUS_SUCCESS;
  789. }
  790. extern
  791. VOID
  792. ArpSResetStats(
  793. IN PINTF pIntF
  794. )
  795. /*++
  796. Routine Description:
  797. Reset all arp and mars statistics. Update the statistics start timestamp.
  798. Arguments:
  799. pIntF - The interface on which the MARS_REQUEST arrived
  800. Return Value:
  801. None
  802. --*/
  803. {
  804. KIRQL OldIrql;
  805. ACQUIRE_SPIN_LOCK(&pIntF->Lock, &OldIrql);
  806. ZERO_MEM(&(pIntF->ArpStats), sizeof(pIntF->ArpStats));
  807. ZERO_MEM(&(pIntF->MarsStats), sizeof(pIntF->MarsStats));
  808. NdisGetCurrentSystemTime(&(pIntF->StatisticsStartTimeStamp));
  809. //
  810. // Now recompute the "current" and "max" values...
  811. //
  812. //
  813. // Arp cache entries
  814. //
  815. pIntF->ArpStats.CurrentArpEntries
  816. = pIntF->ArpStats.MaxArpEntries
  817. = pIntF->NumCacheEntries;
  818. //
  819. // Cluster member count
  820. //
  821. {
  822. pIntF->MarsStats.CurrentClusterMembers
  823. = pIntF->MarsStats.MaxClusterMembers
  824. = pIntF->NumClusterMembers;
  825. }
  826. //
  827. // MCast group count and max group-size - we have to go through the entire
  828. // mars cache to get this information.
  829. //
  830. {
  831. UINT u;
  832. UINT MaxGroupSize;
  833. UINT NumGroups;
  834. for (u = 0, MaxGroupSize = 0, NumGroups = 0;
  835. u < MARS_TABLE_SIZE;
  836. u++)
  837. {
  838. PMARS_ENTRY pMarsEntry;
  839. for (pMarsEntry = pIntF->MarsCache[u];
  840. pMarsEntry != NULL;
  841. pMarsEntry = pMarsEntry->Next)
  842. {
  843. if (MaxGroupSize < pMarsEntry->NumMembers)
  844. {
  845. MaxGroupSize = pMarsEntry->NumMembers;
  846. }
  847. NumGroups++;
  848. }
  849. }
  850. pIntF->MarsStats.CurrentGroups
  851. = pIntF->MarsStats.MaxGroups
  852. = NumGroups;
  853. pIntF->MarsStats.MaxAddressesPerGroup = MaxGroupSize;
  854. }
  855. RELEASE_SPIN_LOCK(&pIntF->Lock, OldIrql);
  856. }