Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2545 lines
74 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. net\routing\ipx\adptif\adptif.c
  5. Abstract:
  6. Router/sap agent interface to ipx stack
  7. Author:
  8. Vadim Eydelman
  9. Revision History:
  10. --*/
  11. #include "ipxdefs.h"
  12. #ifdef UNICODE
  13. #define _UNICODE
  14. #endif
  15. // [pmay] Make adptif pnp aware
  16. #include "pnp.h"
  17. // [pmay] The global trace id.
  18. DWORD g_dwTraceId = 0;
  19. DWORD g_dwBufferId = 0;
  20. WCHAR ISN_IPX_NAME[] = L"\\Device\\NwlnkIpx"; // Ipx stack driver name
  21. ULONG InternalNetworkNumber=0; // Internal network parameters
  22. UCHAR INTERNAL_NODE_ADDRESS[6]={0,0,0,0,0,1};
  23. IO_STATUS_BLOCK IoctlStatus; // IO status buffer for config change notifications
  24. HANDLE IpxDriverHandle; // Driver handle for config change notifications
  25. LONG AdapterChangeApcPending = 0;
  26. /*
  27. DWORD (APIENTRY * RouterQueueWorkItemProc) (WORKERFUNCTION, PVOID, BOOL)=NULL;
  28. // Thread management API routine when running
  29. // under router
  30. #define InRouter() (RouterQueueWorkItemProc!=NULL)
  31. */
  32. LIST_ENTRY PortListHead; // List of configuraiton ports
  33. PCONFIG_PORT IpxWanPort; // Special port for IPX WAN
  34. CRITICAL_SECTION ConfigInfoLock; // Protects access to port and message queues
  35. ULONG NumAdapters; // Total number of available adapters (used
  36. // to estimate the size of the buffer passed to
  37. // the driver in config change notification calls)
  38. DWORD
  39. OpenAdapterConfigPort (
  40. void
  41. );
  42. NTSTATUS
  43. CloseAdapterConfigPort (
  44. PVOID pvConfigBuffer
  45. );
  46. VOID APIENTRY
  47. PostAdapterConfigRequest (
  48. PVOID context
  49. );
  50. NTSTATUS
  51. ProcessAdapterConfigInfo (
  52. PVOID pvConfigBuffer
  53. );
  54. DWORD
  55. InitializeMessageQueueForClient (
  56. PCONFIG_PORT config
  57. );
  58. VOID
  59. AdapterChangeAPC (
  60. PVOID context,
  61. PIO_STATUS_BLOCK IoStatus,
  62. ULONG Reserved
  63. );
  64. VOID
  65. IpxSendCompletion (
  66. IN PVOID Context,
  67. IN PIO_STATUS_BLOCK IoStatus,
  68. IN ULONG Reserved
  69. );
  70. VOID
  71. IpxRecvCompletion (
  72. IN PVOID Context,
  73. IN PIO_STATUS_BLOCK IoStatus,
  74. IN ULONG Reserved
  75. );
  76. VOID
  77. FwCleanup (
  78. void
  79. );
  80. // [pmay] Synchronize the forwarder with nic id renumberings
  81. // in the stack.
  82. DWORD FwRenumberNics (DWORD dwOpCode, USHORT usThreshold);
  83. #if DBG && defined(WATCHER_DIALOG)
  84. #include "watcher.c"
  85. #endif
  86. /*++
  87. *******************************************************************
  88. D l l M a i n
  89. Routine Description:
  90. Dll initialization and cleanup
  91. Arguments:
  92. hinstDLL, handle of DLL module
  93. fdwReason, reason for calling function
  94. lpvReserved reserved
  95. Return Value:
  96. TRUE intialized OK
  97. FALSE failed
  98. Remarks:
  99. Return value is only valid when called with DLL_PROCESS_ATTACH reason
  100. This DLL makes use of CRT.DLL, so this entry point should
  101. be called from CRT.DLL entry point
  102. *******************************************************************
  103. --*/
  104. BOOL WINAPI DllMain(
  105. HINSTANCE hinstDLL,
  106. DWORD fdwReason,
  107. LPVOID lpvReserved
  108. ) {
  109. BOOL res = FALSE;
  110. TCHAR ProcessFileName[MAX_PATH];
  111. DWORD cnt;
  112. switch (fdwReason) {
  113. case DLL_PROCESS_ATTACH: // We are being attached to a new process
  114. // Initialize the system that maps virtual nic ids to physical ones
  115. NicMapInitialize ();
  116. InitializeCriticalSection (&ConfigInfoLock);
  117. InitializeListHead (&PortListHead);
  118. IpxWanPort = NULL;
  119. // Register with the trace utility
  120. g_dwTraceId = TraceRegisterExA("IpxAdptif", 0);
  121. #if DBG && defined(WATCHER_DIALOG)
  122. InitializeWatcher (hinstDLL);
  123. #endif
  124. res = TRUE;
  125. break;
  126. case DLL_PROCESS_DETACH: // The process is exiting
  127. #if DBG && defined(WATCHER_DIALOG)
  128. CleanupWatcher ();
  129. #endif
  130. DeleteCriticalSection (&ConfigInfoLock);
  131. FwCleanup ();
  132. TraceDeregisterExA(g_dwTraceId , 4);
  133. // Cleanup the system that maps virtual nic ids to physical ones
  134. NicMapCleanup ();
  135. default: // Not interested in all other cases
  136. res = TRUE;
  137. break;
  138. }
  139. return res;
  140. }
  141. // Debug functions
  142. char * DbgStatusToString(DWORD dwStatus) {
  143. switch (dwStatus) {
  144. case NIC_CREATED:
  145. return "Created";
  146. case NIC_DELETED:
  147. return "Deleted";
  148. case NIC_CONNECTED:
  149. return "Connected";
  150. case NIC_DISCONNECTED:
  151. return "Disconnected";
  152. case NIC_LINE_DOWN:
  153. return "Line down";
  154. case NIC_LINE_UP:
  155. return "Line up";
  156. case NIC_CONFIGURED:
  157. return "Configured";
  158. }
  159. return "Unknown";
  160. }
  161. // Debugging functions
  162. char * DbgTypeToString(DWORD dwType) {
  163. switch (dwType) {
  164. case NdisMedium802_3:
  165. return "802.3";
  166. case NdisMedium802_5:
  167. return "802.5";
  168. case NdisMediumFddi:
  169. return "Fddi";
  170. case NdisMediumWan:
  171. return "Wan";
  172. case NdisMediumLocalTalk:
  173. return "LocalTalk";
  174. case NdisMediumDix:
  175. return "Dix";
  176. case NdisMediumArcnetRaw:
  177. return "Raw Arcnet";
  178. case NdisMediumArcnet878_2:
  179. return "878.2";
  180. case NdisMediumAtm:
  181. return "Atm";
  182. case NdisMediumWirelessWan:
  183. return "Wireless Wan";
  184. case NdisMediumIrda:
  185. return "Irda";
  186. case NdisMediumBpc:
  187. return "Bpc";
  188. case NdisMediumCoWan:
  189. return "Co Wan";
  190. case NdisMediumMax:
  191. return "Maxium value allowed";
  192. }
  193. return "Unknown";
  194. }
  195. // Returns the op-code (for nic id renumbering) associated with this
  196. // message
  197. DWORD GetNicOpCode(PIPX_NIC_INFO pNic) {
  198. DWORD dwOp = (DWORD)(pNic->Status & 0xf0);
  199. pNic->Status &= 0x0f;
  200. return dwOp;
  201. }
  202. // Inserts the op-code (for nic id renumbering) associated with this
  203. // message
  204. DWORD PutNicOpCode(PIPX_NIC_INFO pNic, DWORD dwOp) {
  205. pNic->Status |= dwOp;
  206. return dwOp;
  207. }
  208. // Outputs a list of nics to the tracing service
  209. DWORD DbgDisplayNics(PIPX_NIC_INFO NicPtr, DWORD dwNicCount) {
  210. DWORD i;
  211. for (i = 0; i < dwNicCount; i++) {
  212. PUCHAR ln = NicPtr[i].Details.Node;
  213. USHORT NicId = NicPtr[i].Details.NicId;
  214. BOOLEAN Status = NicPtr[i].Status;
  215. GetNicOpCode(&NicPtr[i]);
  216. TracePrintf(g_dwTraceId, "[R=%d V=%x: %s]: Net=%x IfNum=%d Local=%x%x%x%x%x%x Type= %s",
  217. NicId,
  218. NicMapGetVirtualNicId(NicId),
  219. DbgStatusToString(NicPtr[i].Status),
  220. NicPtr[i].Details.NetworkNumber,
  221. NicPtr[i].InterfaceIndex,
  222. ln[0], ln[1], ln[2], ln[3], ln[4], ln[5],
  223. DbgTypeToString(NicPtr[i].NdisMediumType)
  224. );
  225. NicPtr[i].Status = Status;
  226. }
  227. TracePrintf(g_dwTraceId, "\n");
  228. return NO_ERROR;
  229. }
  230. int DVNID (int x) {
  231. USHORT tmp;
  232. tmp = (USHORT)NicMapGetVirtualNicId((USHORT)x);
  233. return (tmp < 50) ? tmp : -1;
  234. }
  235. int DRNID (int x) {
  236. USHORT tmp;
  237. tmp = NicMapGetPhysicalNicId((USHORT)x);
  238. return (tmp < 50) ? tmp : -1;
  239. }
  240. // Outputs the virtual to physical adapter map
  241. DWORD DbgDisplayMap() {
  242. USHORT i;
  243. /* for (i = 0; i < 6; i++) {
  244. PUCHAR m = GlobalNicIdMap.nidMacAddrs[i];
  245. if (m) {
  246. TracePrintf(g_dwTraceId,
  247. "Real %d \tis Virtual %x \t(%x->%x) \twith Mac %x%x%x%x%x%x",
  248. i, NicMapGetVirtualNicId(i), i, NicMapGetPhysicalNicId(i),
  249. m[0], m[1], m[2], m[3], m[4], m[5]);
  250. }
  251. else {
  252. TracePrintf(g_dwTraceId,
  253. "Real %d \tis Virtual %x \t(%x->%x)",
  254. i, NicMapGetVirtualNicId(i), i, NicMapGetPhysicalNicId(i));
  255. }
  256. }
  257. */
  258. TracePrintf(g_dwTraceId, "R: %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d",
  259. 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
  260. TracePrintf(g_dwTraceId, "V: %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d",
  261. DVNID(1), DVNID(2), DVNID(3), DVNID(4), DVNID(5),
  262. DVNID(6), DVNID(7), DVNID(8), DVNID(9), DVNID(10));
  263. TracePrintf(g_dwTraceId, "V: %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d",
  264. 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
  265. TracePrintf(g_dwTraceId, "R: %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d\n",
  266. DRNID(1), DRNID(2), DRNID(3), DRNID(4), DRNID(5),
  267. DRNID(6), DRNID(7), DRNID(8), DRNID(9), DRNID(10));
  268. return NO_ERROR;
  269. }
  270. /*++
  271. C r e a t e S o c k e t P o r t
  272. Routine Description:
  273. Creates port to communicate over IPX socket
  274. Arguments:
  275. Socket - IPX socket number to use (network byte order)
  276. Return Value:
  277. Handle to communication port that provides async interface
  278. to IPX stack. Returns INVALID_HANDLE_VALUE if port can not be opened
  279. --*/
  280. HANDLE WINAPI
  281. CreateSocketPort(
  282. IN USHORT Socket
  283. ) {
  284. NTSTATUS status;
  285. HANDLE AddressHandle;
  286. IO_STATUS_BLOCK IoStatusBlock;
  287. UNICODE_STRING FileString;
  288. OBJECT_ATTRIBUTES ObjectAttributes;
  289. CHAR spec[IPX_ENDPOINT_SPEC_BUFFER_SIZE];
  290. #define ea ((PFILE_FULL_EA_INFORMATION)&spec)
  291. #define TrAddress ((PTRANSPORT_ADDRESS)&ea->EaName[ROUTER_INTERFACE_LENGTH+1])
  292. #define TaAddress ((PTA_ADDRESS)&TrAddress->Address[0])
  293. #define IpxAddress ((PTDI_ADDRESS_IPX)&TaAddress->Address[0])
  294. RtlInitUnicodeString (&FileString, ISN_IPX_NAME);
  295. InitializeObjectAttributes(
  296. &ObjectAttributes,
  297. &FileString,
  298. OBJ_CASE_INSENSITIVE,
  299. NULL,
  300. NULL);
  301. ea->NextEntryOffset = 0;
  302. ea->Flags = 0;
  303. ea->EaNameLength = ROUTER_INTERFACE_LENGTH;
  304. RtlCopyMemory (ea->EaName, ROUTER_INTERFACE, ROUTER_INTERFACE_LENGTH + 1);
  305. ea->EaValueLength = sizeof(TRANSPORT_ADDRESS) - 1
  306. + sizeof(TDI_ADDRESS_IPX);
  307. TrAddress->TAAddressCount = 1;
  308. TaAddress->AddressType = TDI_ADDRESS_TYPE_IPX;
  309. TaAddress->AddressLength = sizeof(TDI_ADDRESS_IPX);
  310. IpxAddress->Socket = Socket;
  311. status = NtCreateFile(
  312. &AddressHandle,
  313. GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
  314. &ObjectAttributes,
  315. &IoStatusBlock, // returned status information
  316. 0, // block size (unused).
  317. 0, // file attributes.
  318. FILE_SHARE_READ | FILE_SHARE_WRITE,
  319. FILE_CREATE, // create disposition.
  320. 0, // create options.
  321. ea,
  322. sizeof (spec)
  323. );
  324. if (NT_SUCCESS (status)) {
  325. SetLastError (NO_ERROR);
  326. return AddressHandle;
  327. }
  328. else {
  329. #if DBG
  330. DbgPrint ("NtCreateFile (router if) failed with status %08x\n",
  331. status);
  332. #endif
  333. RtlNtStatusToDosError (status); // Sets last error in Teb
  334. }
  335. return INVALID_HANDLE_VALUE;
  336. #undef TrAddress
  337. #undef TaAddress
  338. #undef IpxAddress
  339. }
  340. /*++
  341. D e l e t e S o c k e t P o r t
  342. Routine Description:
  343. Cancel all the outstandng requests and dispose of all the resources
  344. allocated for communication port
  345. Arguments:
  346. Handle - Handle to communication port to be disposed of
  347. Return Value:
  348. NO_ERROR - success
  349. Windows error code - operation failed
  350. --*/
  351. DWORD WINAPI
  352. DeleteSocketPort (
  353. HANDLE Handle
  354. ) {
  355. return RtlNtStatusToDosError (NtClose (Handle));
  356. }
  357. /*++
  358. I p x S e n d C o m p l e t i o n
  359. Routine Description:
  360. Io APC. Calls client provided completion routine
  361. Arguments:
  362. Context - Pointer to client completion routine
  363. IoStatus - status of completed io operation (clients overlapped
  364. structure is used as the buffer)
  365. Reserved - ???
  366. Return Value:
  367. None
  368. --*/
  369. VOID
  370. IpxSendCompletion (
  371. IN PVOID Context,
  372. IN PIO_STATUS_BLOCK IoStatus,
  373. IN ULONG Reserved
  374. ) {
  375. if (NT_SUCCESS (IoStatus->Status))
  376. (*(LPOVERLAPPED_COMPLETION_ROUTINE)Context) (NO_ERROR,
  377. // Adjust byte trasferred parameter to
  378. // include header supplied in the
  379. // packet
  380. ((DWORD)IoStatus->Information+=sizeof (IPX_HEADER)),
  381. (LPOVERLAPPED)IoStatus);
  382. else
  383. (*(LPOVERLAPPED_COMPLETION_ROUTINE)Context) (
  384. RtlNtStatusToDosError (IoStatus->Status),
  385. // Adjust byte trasferred parameter to
  386. // include header supplied in the
  387. // packet if something was sent
  388. (IoStatus->Information > 0)
  389. ? ((DWORD)IoStatus->Information += sizeof (IPX_HEADER))
  390. : ((DWORD)IoStatus->Information = 0),
  391. (LPOVERLAPPED)IoStatus);
  392. }
  393. /*++
  394. I p x R e c v C o m p l e t i on
  395. Routine Description:
  396. Io APC. Calls client provided completion routine
  397. Arguments:
  398. Context - Pointer to client completion routine
  399. IoStatus - status of completed io operation (clients overlapped
  400. structure is used as the buffer)
  401. Reserved - ???
  402. Return Value:
  403. None
  404. --*/
  405. VOID
  406. IpxRecvCompletion (
  407. IN PVOID Context,
  408. IN PIO_STATUS_BLOCK IoStatus,
  409. IN ULONG Reserved
  410. ) {
  411. if (NT_SUCCESS (IoStatus->Status))
  412. (*(LPOVERLAPPED_COMPLETION_ROUTINE)Context) (NO_ERROR,
  413. // Substract size of options header
  414. // reported by the driver in the beggining
  415. // of the buffer
  416. ((DWORD)IoStatus->Information
  417. -= FIELD_OFFSET (IPX_DATAGRAM_OPTIONS2,Data)),
  418. (LPOVERLAPPED)IoStatus);
  419. else
  420. (*(LPOVERLAPPED_COMPLETION_ROUTINE)Context) (
  421. RtlNtStatusToDosError (IoStatus->Status),
  422. // Substract size of options header
  423. // reported by the driver in the beggining
  424. // of the buffer if dirver was able
  425. // to actually receive something (not
  426. // just options in the buffer
  427. ((DWORD)IoStatus->Information >
  428. FIELD_OFFSET (IPX_DATAGRAM_OPTIONS2,Data))
  429. ? ((DWORD)IoStatus->Information
  430. -= FIELD_OFFSET (IPX_DATAGRAM_OPTIONS2,Data))
  431. : ((DWORD)IoStatus->Information = 0),
  432. (LPOVERLAPPED)IoStatus);
  433. }
  434. /*++
  435. I p x G e t O v e r l a p p e d R e s u l t
  436. Routine Description:
  437. GetOverlappedResult wrapper: gives adptif.dll a chance to adjust
  438. returned parameters (currently number of bytes transferred).
  439. Arguments:
  440. Same as in GetOverlappedResult (see SDK doc)
  441. Return Value:
  442. Same as in GetOverlappedResult (see SDK doc)
  443. --*/
  444. BOOL
  445. IpxGetOverlappedResult (
  446. HANDLE Handle,
  447. LPOVERLAPPED lpOverlapped,
  448. LPDWORD lpNumberOfBytesTransferred,
  449. BOOL bWait
  450. ) {
  451. BOOL res = GetOverlappedResult (Handle, lpOverlapped, lpNumberOfBytesTransferred, bWait);
  452. if (res) {
  453. if (NT_SUCCESS (lpOverlapped->Internal)) {
  454. if (lpOverlapped->Offset==MIPX_SEND_DATAGRAM)
  455. *lpNumberOfBytesTransferred += sizeof (IPX_HEADER);
  456. else if (lpOverlapped->Offset==MIPX_RCV_DATAGRAM)
  457. *lpNumberOfBytesTransferred -= FIELD_OFFSET (IPX_DATAGRAM_OPTIONS2,Data);
  458. // else - neither, for packets generated with
  459. // PostQueuedCompletionStatus
  460. }
  461. else {
  462. if (lpOverlapped->Offset==MIPX_SEND_DATAGRAM) {
  463. if (*lpNumberOfBytesTransferred>0)
  464. *lpNumberOfBytesTransferred += sizeof (IPX_HEADER);
  465. }
  466. else if (lpOverlapped->Offset==MIPX_RCV_DATAGRAM) {
  467. if (*lpNumberOfBytesTransferred>FIELD_OFFSET (IPX_DATAGRAM_OPTIONS2,Data))
  468. *lpNumberOfBytesTransferred -= FIELD_OFFSET (IPX_DATAGRAM_OPTIONS2,Data);
  469. else
  470. *lpNumberOfBytesTransferred = 0;
  471. }
  472. // else - neither, for packets generated with
  473. // PostQueuedCompletionStatus
  474. }
  475. }
  476. return res;
  477. }
  478. /*++
  479. I p x G e t Q u e u e d C o m p l e t i o n S t a t u s
  480. Routine Description:
  481. GetQueuedCompletionStatus wrapper: gives adptif.dll a chance to adjust
  482. returned parameters (currently number of bytes transferred)
  483. Arguments:
  484. Same as in GetQueuedCompletionStatus (see SDK doc)
  485. Return Value:
  486. Same as in GetQueuedCompletionStatus (see SDK doc)
  487. --*/
  488. BOOL
  489. IpxGetQueuedCompletionStatus(
  490. HANDLE CompletionPort,
  491. LPDWORD lpNumberOfBytesTransferred,
  492. PULONG_PTR lpCompletionKey,
  493. LPOVERLAPPED *lpOverlapped,
  494. DWORD dwMilliseconds
  495. ) {
  496. BOOL res = GetQueuedCompletionStatus (CompletionPort,
  497. lpNumberOfBytesTransferred,
  498. lpCompletionKey,
  499. lpOverlapped,
  500. dwMilliseconds);
  501. if (res) {
  502. if (NT_SUCCESS ((*lpOverlapped)->Internal)) {
  503. if ((*lpOverlapped)->Offset==MIPX_SEND_DATAGRAM) {
  504. *lpNumberOfBytesTransferred += sizeof (IPX_HEADER);
  505. (*lpOverlapped)->InternalHigh = *lpNumberOfBytesTransferred;
  506. }
  507. else if ((*lpOverlapped)->Offset==MIPX_RCV_DATAGRAM) {
  508. *lpNumberOfBytesTransferred -= FIELD_OFFSET (IPX_DATAGRAM_OPTIONS2,Data);
  509. (*lpOverlapped)->InternalHigh = *lpNumberOfBytesTransferred;
  510. }
  511. // else - neither, for packets generated with
  512. // PostQueuedCompletionStatus
  513. }
  514. else {
  515. if ((*lpOverlapped)->Offset==MIPX_SEND_DATAGRAM) {
  516. if (*lpNumberOfBytesTransferred>0) {
  517. *lpNumberOfBytesTransferred += sizeof (IPX_HEADER);
  518. (*lpOverlapped)->InternalHigh = *lpNumberOfBytesTransferred;
  519. }
  520. }
  521. else if ((*lpOverlapped)->Offset==MIPX_RCV_DATAGRAM) {
  522. if (*lpNumberOfBytesTransferred>FIELD_OFFSET (IPX_DATAGRAM_OPTIONS2,Data)) {
  523. *lpNumberOfBytesTransferred -= FIELD_OFFSET (IPX_DATAGRAM_OPTIONS2,Data);
  524. (*lpOverlapped)->InternalHigh = *lpNumberOfBytesTransferred;
  525. }
  526. else {
  527. *lpNumberOfBytesTransferred = 0;
  528. (*lpOverlapped)->InternalHigh = *lpNumberOfBytesTransferred;
  529. }
  530. }
  531. // else - neither, for packets generated with
  532. // PostQueuedCompletionStatus
  533. }
  534. }
  535. return res;
  536. }
  537. /*++
  538. I p x A d j u s t I o C o m p l e t i o n P a r a m s
  539. Routine Description:
  540. Adjust io completion parameters for io performed
  541. by IpxSendPacket or IpxReceivePacket and completed
  542. through the mechanisms other than routines provided
  543. above
  544. Arguments:
  545. lpOverlapped - overlapped structure passed to
  546. Ipx(Send/Recv)Packet routines
  547. lpNumberOfBytesTransferred - adjusted number of bytes
  548. transferred in io
  549. error - win32 error code
  550. Return Value:
  551. None
  552. --*/
  553. VOID
  554. IpxAdjustIoCompletionParams (
  555. IN OUT LPOVERLAPPED lpOverlapped,
  556. OUT LPDWORD lpNumberOfBytesTransferred,
  557. OUT LPDWORD error
  558. ) {
  559. if (NT_SUCCESS (lpOverlapped->Internal)) {
  560. if (lpOverlapped->Offset==MIPX_SEND_DATAGRAM) {
  561. lpOverlapped->InternalHigh += sizeof (IPX_HEADER);
  562. *lpNumberOfBytesTransferred = (DWORD)lpOverlapped->InternalHigh;
  563. }
  564. else if (lpOverlapped->Offset==MIPX_RCV_DATAGRAM) {
  565. lpOverlapped->InternalHigh -= FIELD_OFFSET (IPX_DATAGRAM_OPTIONS2,Data);
  566. *lpNumberOfBytesTransferred = (DWORD)lpOverlapped->InternalHigh;
  567. }
  568. // else - neither, for packets generated with
  569. // PostQueuedCompletionStatus
  570. *error = NO_ERROR;
  571. }
  572. else {
  573. if (lpOverlapped->Offset==MIPX_SEND_DATAGRAM) {
  574. if (lpOverlapped->InternalHigh>0) {
  575. lpOverlapped->InternalHigh += sizeof (IPX_HEADER);
  576. *lpNumberOfBytesTransferred = (DWORD)lpOverlapped->InternalHigh;
  577. }
  578. }
  579. else if (lpOverlapped->Offset==MIPX_RCV_DATAGRAM) {
  580. if (lpOverlapped->InternalHigh>FIELD_OFFSET (IPX_DATAGRAM_OPTIONS2,Data)) {
  581. lpOverlapped->InternalHigh -= FIELD_OFFSET (IPX_DATAGRAM_OPTIONS2,Data);
  582. *lpNumberOfBytesTransferred = (DWORD)lpOverlapped->InternalHigh;
  583. }
  584. else {
  585. lpOverlapped->InternalHigh = 0;
  586. *lpNumberOfBytesTransferred = 0;
  587. }
  588. }
  589. // else - neither, for packets generated with
  590. // PostQueuedCompletionStatus
  591. *error = RtlNtStatusToDosError ((DWORD)lpOverlapped->Internal);
  592. }
  593. }
  594. /*++
  595. I p x P o s t Q u e u e d C o m p l e t i o n S t a t u s
  596. Routine Description:
  597. PostQueuedCompletionStatus wrapper: gives adptif.dll a chance to
  598. setup lpOverlapped so it can be correctly processed by
  599. the IpxGetQueueCompletionStatus and IpxGetOverlappedResult
  600. Arguments:
  601. Same as in PostQueuedCompletionStatus (see SDK doc)
  602. Return Value:
  603. Same as in PostQueuedCompletionStatus (see SDK doc)
  604. --*/
  605. BOOL
  606. IpxPostQueuedCompletionStatus(
  607. HANDLE CompletionPort,
  608. DWORD dwNumberOfBytesTransferred,
  609. DWORD dwCompletionKey,
  610. LPOVERLAPPED lpOverlapped
  611. ) {
  612. lpOverlapped->Offset = 0;
  613. return PostQueuedCompletionStatus (CompletionPort,
  614. dwNumberOfBytesTransferred,
  615. dwCompletionKey,
  616. lpOverlapped);
  617. }
  618. /*++
  619. I p x S e n d P a c k e t
  620. Routine Description:
  621. Enqueue request to receive IPX packet and return immediately. Event will
  622. be signalled or comletion routine will be called when done
  623. Arguments:
  624. Handle - Handle to adapter & socket to use
  625. AdapterIdx - adapter on which to send
  626. IpxPacket - ipx packet complete with header
  627. IpxPacketLength - length of the packet
  628. pReserved - buffer to supply info to IPX stack
  629. lpOverlapped - structure to be used for async IO:
  630. Internal - reserved
  631. InternalHigh - reserved
  632. Offset - not used
  633. OffsetHigh - not used
  634. hEvent - event to be signalled when IO completes or NULL
  635. if CompletionRoutine is to be called
  636. CompletionRoutine - to be called when IO operation is completes
  637. Return Value:
  638. NO_ERROR - if lpOverlapped->hEvent!=NULL, then recv has successfully completed
  639. (do not need to wait on event), otherwise, recv operation has
  640. started and completion routine will be called when done
  641. ERROR_IO_PENDING - only returned if lpOverlapped->hEvent!=NULL and recv could not
  642. be completed immediately, event will be signalled when
  643. operation is done: call GetOverlapedResult to retrieve result of
  644. the operation
  645. other (windows error code) - operation could not be started (completion routine
  646. won't be called)
  647. --*/
  648. DWORD WINAPI
  649. IpxSendPacket (
  650. IN HANDLE Handle,
  651. IN ULONG AdapterIdx,
  652. IN PUCHAR IpxPacket,
  653. IN ULONG IpxPacketLength,
  654. IN PADDRESS_RESERVED lpReserved,
  655. LPOVERLAPPED lpOverlapped,
  656. LPOVERLAPPED_COMPLETION_ROUTINE CompletionRoutine
  657. ) {
  658. #define hdr ((PIPX_HEADER)IpxPacket)
  659. #define opt ((PIPX_DATAGRAM_OPTIONS2)lpReserved)
  660. NTSTATUS status;
  661. // Send the data to the correct physical index
  662. AdapterIdx = (ULONG)NicMapGetPhysicalNicId((USHORT)AdapterIdx);
  663. // Put IPX header parameters into datagram options:
  664. // Packet type
  665. opt->DgrmOptions.PacketType = hdr->pkttype;
  666. // Source
  667. opt->DgrmOptions.LocalTarget.NicId = (USHORT)AdapterIdx;
  668. IPX_NODENUM_CPY (&opt->DgrmOptions.LocalTarget.MacAddress, hdr->dst.node);
  669. // Destination
  670. IPX_NODENUM_CPY (&opt->RemoteAddress.NodeAddress, hdr->dst.node);
  671. IPX_NETNUM_CPY (&opt->RemoteAddress.NetworkAddress, hdr->dst.net);
  672. opt->RemoteAddress.Socket = hdr->dst.socket;
  673. lpOverlapped->Offset = MIPX_SEND_DATAGRAM;
  674. status = NtDeviceIoControlFile(
  675. Handle,
  676. lpOverlapped->hEvent,
  677. ((lpOverlapped->hEvent!=NULL) || (CompletionRoutine==NULL))
  678. ? NULL
  679. : IpxSendCompletion,
  680. CompletionRoutine ? (LPVOID)CompletionRoutine : (LPVOID)lpOverlapped,
  681. (PIO_STATUS_BLOCK)lpOverlapped,
  682. MIPX_SEND_DATAGRAM,
  683. lpReserved,
  684. sizeof (IPX_DATAGRAM_OPTIONS2),
  685. &hdr[1],
  686. IpxPacketLength-sizeof (IPX_HEADER)
  687. );
  688. if (NT_SUCCESS (status)) {
  689. SetLastError (NO_ERROR);
  690. return NO_ERROR;
  691. }
  692. #if DBG
  693. DbgPrint ("Ioctl MIPX_SEND_DATAGRAM failed with status %08x\n", status);
  694. #endif
  695. return RtlNtStatusToDosError (status);
  696. #undef hdr
  697. #undef opt
  698. }
  699. /*++
  700. I p x R e c v P a c k e t
  701. Routine Description:
  702. Enqueue request to receive IPX packet and return immediately. Event will
  703. be signalled or comletion routine will be called when done
  704. Arguments:
  705. Handle - Handle to adapter & socket to use
  706. AdapterIdx - adapter on which to packet was received (set upon completion)
  707. IpxPacket - buffer for ipx packet (complete with header)
  708. IpxPacketLength - length of the buffer
  709. pReserved - buffer to get info from IPX stack
  710. lpOverlapped - structure to be used for async IO:
  711. Internal - Reserved
  712. InternalHigh - Reserved
  713. Offset - not used
  714. OffsetHigh - not used
  715. hEvent - event to be signalled when IO completes or NULL
  716. if CompletionRoutine is to be called
  717. CompletionRoutine - to be called when IO operation is completes
  718. Return Value:
  719. NO_ERROR - if lpOverlapped->hEvent!=NULL, then send has successfully completed
  720. (do not need to wait on event), otherwise, send operation has
  721. started and completion routine will be called when done
  722. ERROR_IO_PENDING - only returned if lpOverlapped->hEvent!=NULL and send could not
  723. be completed immediately, event will be signalled when
  724. operation is done: call GetOverlapedResult to retrieve result of
  725. the operation
  726. other (windows error code) - operation could not be started (completion routine
  727. won't be called)
  728. --*/
  729. DWORD WINAPI
  730. IpxRecvPacket(
  731. IN HANDLE Handle,
  732. OUT PUCHAR IpxPacket,
  733. IN ULONG IpxPacketLength,
  734. IN PADDRESS_RESERVED lpReserved,
  735. LPOVERLAPPED lpOverlapped,
  736. LPOVERLAPPED_COMPLETION_ROUTINE CompletionRoutine
  737. ) {
  738. NTSTATUS status;
  739. // A temporary hack (due to the available ipx interface):
  740. ASSERTMSG ("Packet buffer does not follow reserved area ",
  741. IpxPacket==(PUCHAR)(&lpReserved[1]));
  742. lpOverlapped->Offset = MIPX_RCV_DATAGRAM;
  743. status = NtDeviceIoControlFile(
  744. Handle,
  745. lpOverlapped->hEvent,
  746. ((lpOverlapped->hEvent!=NULL) || (CompletionRoutine==NULL))
  747. ? NULL
  748. : IpxRecvCompletion,
  749. CompletionRoutine ? (LPVOID)CompletionRoutine : (LPVOID)lpOverlapped,
  750. (PIO_STATUS_BLOCK)lpOverlapped,
  751. MIPX_RCV_DATAGRAM,
  752. NULL,
  753. 0,
  754. lpReserved,
  755. FIELD_OFFSET (IPX_DATAGRAM_OPTIONS2,Data)
  756. + IpxPacketLength
  757. );
  758. if (NT_SUCCESS (status)) {
  759. SetLastError (NO_ERROR);
  760. return NO_ERROR;
  761. }
  762. #if DBG
  763. DbgPrint ("Ioctl MIPX_RCV_DATAGRAM failed with status %08x\n", status);
  764. #endif
  765. return RtlNtStatusToDosError (status);
  766. }
  767. /*++
  768. I p x C r e a t e A d a p t e r C o n f i g u r a t i o n P o r t
  769. Routine Description:
  770. Register client that wants to be updated of any changes in
  771. adapter state
  772. Arguments:
  773. NotificationEvent - event to be signaled when adapter state changes
  774. AdptGlobalParameters - parameters that common to all adapters
  775. Return Value:
  776. Handle to configuration port thru which changes in adapter state
  777. are reported. Returns INVALID_HANDLE_VALUE if port could not be created
  778. --*/
  779. HANDLE WINAPI
  780. IpxCreateAdapterConfigurationPort(IN HANDLE NotificationEvent,
  781. OUT PADAPTERS_GLOBAL_PARAMETERS AdptGlobalParameters)
  782. {
  783. PCONFIG_PORT port;
  784. INT i;
  785. DWORD error=NO_ERROR;
  786. TracePrintf(
  787. g_dwTraceId,
  788. "IpxCreateAdapterConfigurationPort: entered.");
  789. // Allocate port data structure
  790. port = (PCONFIG_PORT)
  791. RtlAllocateHeap (RtlProcessHeap (), 0, sizeof (CONFIG_PORT));
  792. if (port == NULL)
  793. {
  794. TracePrintf(
  795. g_dwTraceId,
  796. "IpxCreateAdapterConfigurationPort: unable to allocate port.");
  797. SetLastError (ERROR_NOT_ENOUGH_MEMORY);
  798. return INVALID_HANDLE_VALUE;
  799. }
  800. // Initialize port data structure
  801. port->event = NotificationEvent;
  802. InitializeListHead (&port->msgqueue);
  803. // Make sure we own the list
  804. EnterCriticalSection (&ConfigInfoLock);
  805. // Open channel to IPX stack if not already opened
  806. //
  807. if (IpxDriverHandle == NULL)
  808. {
  809. TracePrintf(
  810. g_dwTraceId,
  811. "IpxCreateAdapterConfigurationPort: calling OpenAdapterConfigPort.");
  812. error = OpenAdapterConfigPort();
  813. }
  814. else
  815. {
  816. error = NO_ERROR;
  817. }
  818. if (error==NO_ERROR)
  819. {
  820. // Add messages about existing adapters to the beginning of the queue
  821. // (to be seen only by the new client)
  822. error = InitializeMessageQueueForClient(port);
  823. if (error==NO_ERROR)
  824. {
  825. InsertTailList (&PortListHead, &port->link);
  826. AdptGlobalParameters->AdaptersCount = NumAdapters;
  827. }
  828. else
  829. {
  830. TracePrintf(
  831. g_dwTraceId,
  832. "IpxCreateAdapterConfigurationPort: InitMessQForClient fail.");
  833. }
  834. }
  835. else
  836. {
  837. TracePrintf(
  838. g_dwTraceId,
  839. "IpxCreateAdapterConfigurationPort: OpenAdapterConfigPort failed.");
  840. }
  841. // Release our lock on the configuration information
  842. LeaveCriticalSection (&ConfigInfoLock);
  843. if (error==NO_ERROR)
  844. return (HANDLE)port;
  845. else
  846. SetLastError (error);
  847. RtlFreeHeap (RtlProcessHeap (), 0, port);
  848. return INVALID_HANDLE_VALUE;
  849. }
  850. /*++
  851. I p x W a n C r e a t e A d a p t e r C o n f i g u r a t i o n P o r t
  852. Routine Description:
  853. Same as above, but creates port that only reports ADAPTER_UP
  854. events on WAN adapters that require IPXWAN negotiation.
  855. IpxGetQueuedAdapterConfigurationStatus on this port should be
  856. followed by IpxWanSetAdapterConfiguration obtained during the
  857. negotiation process, and ADAPTER_UP event will then be reported
  858. to other clients (including forwarder dirver)
  859. */
  860. HANDLE WINAPI
  861. IpxWanCreateAdapterConfigurationPort(
  862. IN HANDLE NotificationEvent,
  863. OUT PADAPTERS_GLOBAL_PARAMETERS AdptGlobalParameters
  864. ) {
  865. INT i;
  866. DWORD error=NO_ERROR;
  867. PCONFIG_PORT port;
  868. // Allocate port data structure
  869. port = (PCONFIG_PORT)RtlAllocateHeap (RtlProcessHeap (), 0,
  870. sizeof (CONFIG_PORT));
  871. if (port!=NULL) {
  872. // Initialize port data structure
  873. port->event = NotificationEvent;
  874. InitializeListHead (&port->msgqueue);
  875. EnterCriticalSection (&ConfigInfoLock);
  876. if (IpxWanPort==NULL) {
  877. // Open channel to IPX stack if not already opened
  878. if (IpxDriverHandle==NULL) {
  879. error = OpenAdapterConfigPort ();
  880. }
  881. else
  882. error = NO_ERROR;
  883. if (error==NO_ERROR) {
  884. IpxWanPort = port;
  885. AdptGlobalParameters->AdaptersCount = NumAdapters;
  886. }
  887. }
  888. else
  889. error = ERROR_ALREADY_EXISTS;
  890. LeaveCriticalSection (&ConfigInfoLock);
  891. if (error==NO_ERROR)
  892. return (HANDLE)port;
  893. else
  894. SetLastError (error);
  895. RtlFreeHeap (RtlProcessHeap (), 0, port);
  896. }
  897. else
  898. SetLastError (ERROR_NOT_ENOUGH_MEMORY);
  899. return INVALID_HANDLE_VALUE;
  900. }
  901. /*++
  902. I p x D e l e t e A d a p t e r C o n f i g u r a t i o n P o r t
  903. Routine Description:
  904. Unregister client
  905. Arguments:
  906. Handle - configuration port handle
  907. Return Value:
  908. NO_ERROR
  909. ERROR_INVALID_PARAMETER
  910. ERROR_GEN_FAILURE
  911. --*/
  912. DWORD WINAPI
  913. IpxDeleteAdapterConfigurationPort (
  914. IN HANDLE Handle
  915. ) {
  916. PCONFIG_PORT port = (PCONFIG_PORT)Handle;
  917. // Make sure we owe the list
  918. EnterCriticalSection (&ConfigInfoLock);
  919. if (port==IpxWanPort)
  920. {
  921. IpxWanPort = NULL;
  922. }
  923. else
  924. {
  925. RemoveEntryList (&port->link);
  926. }
  927. #if DBG && defined(WATCHER_DIALOG)
  928. // Adapter port is maintained by the watcher dialog
  929. #else
  930. if (IsListEmpty (&PortListHead) && (IpxWanPort==NULL))
  931. {
  932. CloseAdapterConfigPort (NULL);
  933. }
  934. #endif
  935. LeaveCriticalSection (&ConfigInfoLock);
  936. // Delete messages that client have not dequeued
  937. while (!IsListEmpty (&port->msgqueue))
  938. {
  939. PLIST_ENTRY cur = RemoveHeadList (&port->msgqueue);
  940. RtlFreeHeap (RtlProcessHeap (), 0,
  941. CONTAINING_RECORD (cur, ADAPTER_MSG, link));
  942. }
  943. // Free the port itself
  944. RtlFreeHeap (RtlProcessHeap (), 0, port);
  945. return NO_ERROR;
  946. }
  947. /*++
  948. G e t Q u e u e d A d a p t e r C o n f i g u r a t i o n S t a t u s
  949. Routine Description:
  950. Get info from the list of adapter info chages queued to the
  951. configuration info port
  952. Arguments:
  953. Handle - configuration port handle
  954. AdapterIndex - number of adapter being reported
  955. AdapterConfigurationStatus - new adapter status
  956. AdapterParameters - adapter parameters
  957. Return Value:
  958. NO_ERROR - new information is reported
  959. ERROR_NO_MORE_ITEMS - there is nothing to report
  960. Windows error code - operation failed
  961. --*/
  962. DWORD WINAPI
  963. IpxGetQueuedAdapterConfigurationStatus(IN HANDLE Handle,
  964. OUT PULONG AdapterIndex,
  965. OUT PULONG AdapterConfigurationStatus,
  966. PADAPTER_INFO AdapterInfo)
  967. {
  968. PCONFIG_PORT port = (PCONFIG_PORT)Handle;
  969. DWORD error;
  970. PWCHAR pszName;
  971. // Make sure nothing changes while we are reading the info
  972. EnterCriticalSection (&ConfigInfoLock);
  973. // If there is something to report
  974. if (!IsListEmpty (&port->msgqueue)) {
  975. PADAPTER_MSG msg = CONTAINING_RECORD (port->msgqueue.Flink, ADAPTER_MSG, link);
  976. RemoveEntryList (&msg->link);
  977. LeaveCriticalSection (&ConfigInfoLock);
  978. // By now, the correct virtual nic id has been set
  979. *AdapterIndex = (ULONG)msg->info.Details.NicId;
  980. // Map driver reported nic states to adapter states
  981. switch (msg->info.Status) {
  982. case NIC_CREATED:
  983. case NIC_CONFIGURED:
  984. *AdapterConfigurationStatus = ADAPTER_CREATED;
  985. break;
  986. case NIC_DELETED:
  987. *AdapterConfigurationStatus = ADAPTER_DELETED;
  988. break;
  989. case NIC_LINE_UP:
  990. *AdapterConfigurationStatus = ADAPTER_UP;
  991. break;
  992. case NIC_LINE_DOWN:
  993. *AdapterConfigurationStatus = ADAPTER_DOWN;
  994. break;
  995. default:
  996. ASSERTMSG ("Unknown nic status ", FALSE);
  997. }
  998. // Copy adapter parameters to client's buffer
  999. AdapterInfo->InterfaceIndex = msg->info.InterfaceIndex;
  1000. IPX_NETNUM_CPY (&AdapterInfo->Network,
  1001. &msg->info.Details.NetworkNumber);
  1002. IPX_NODENUM_CPY (&AdapterInfo->LocalNode,
  1003. &msg->info.Details.Node);
  1004. IPX_NODENUM_CPY (&AdapterInfo->RemoteNode,
  1005. &msg->info.RemoteNodeAddress);
  1006. AdapterInfo->LinkSpeed = msg->info.LinkSpeed;
  1007. AdapterInfo->PacketType = msg->info.PacketType;
  1008. AdapterInfo->MaxPacketSize = msg->info.MaxPacketSize;
  1009. AdapterInfo->NdisMedium = msg->info.NdisMediumType;
  1010. AdapterInfo->ConnectionId = msg->info.ConnectionId;
  1011. // Copy in the adapter name
  1012. pszName = wcsstr(msg->info.Details.AdapterName, L"{");
  1013. if (!pszName)
  1014. pszName = (PWCHAR)msg->info.Details.AdapterName;
  1015. wcsncpy(AdapterInfo->pszAdpName, pszName, MAX_ADAPTER_NAME_LEN);
  1016. EnterCriticalSection (&ConfigInfoLock);
  1017. if (IsListEmpty (&port->msgqueue)) {
  1018. // Last message -> reset event (in case
  1019. // client uses manual reset event)
  1020. BOOL res = ResetEvent (port->event);
  1021. ASSERTMSG ("Can't reset port event ", res);
  1022. }
  1023. // Decrement reference count on processed message and dispose of it
  1024. // when ref count gets to 0
  1025. RtlFreeHeap(RtlProcessHeap (), 0, msg);
  1026. error = NO_ERROR; // There is a message in the buffer
  1027. }
  1028. else if (NT_SUCCESS (IoctlStatus.Status)) {
  1029. error = ERROR_NO_MORE_ITEMS; // No more messages, request is pending
  1030. }
  1031. else { // Last request completed with error, report it to client,
  1032. // Client will have to reopen the port to force posting of new request
  1033. error = RtlNtStatusToDosError (IoctlStatus.Status);
  1034. #if DBG
  1035. DbgPrint ("Reporting result of failed Ioctl to client: status:%0lx -> error:%ld\n",
  1036. IoctlStatus.Status, error);
  1037. #endif
  1038. }
  1039. LeaveCriticalSection (&ConfigInfoLock);
  1040. SetLastError (error);
  1041. return error;
  1042. }
  1043. //
  1044. // Function: IpxGetAdapterConfig
  1045. //
  1046. // Queries the stack for the internal network number along with the current total
  1047. // number of adapters. Function blocks until the query completes.
  1048. //
  1049. DWORD IpxGetAdapterConfig(OUT LPDWORD lpdwInternalNetNum,
  1050. OUT LPDWORD lpdwAdapterCount)
  1051. {
  1052. DWORD dwErr = NO_ERROR, dwNet, dwCount;
  1053. // Synchronize
  1054. EnterCriticalSection (&ConfigInfoLock);
  1055. // Open channel to IPX stack if not already opened
  1056. if (IpxDriverHandle==NULL)
  1057. dwErr = OpenAdapterConfigPort();
  1058. // Set the values that were read
  1059. dwNet = InternalNetworkNumber;
  1060. dwCount = NumAdapters;
  1061. // Release our lock on the configuration information
  1062. LeaveCriticalSection (&ConfigInfoLock);
  1063. if (dwErr != NO_ERROR)
  1064. return dwErr;
  1065. *lpdwInternalNetNum = dwNet;
  1066. *lpdwAdapterCount = dwCount;
  1067. return NO_ERROR;
  1068. }
  1069. //
  1070. // Function: IpxGetAdapterConfig
  1071. //
  1072. // Queries the stack for the list of all adapters currently bound to a network.
  1073. // This function blocks until the query completes.
  1074. //
  1075. DWORD IpxGetAdapterList(OUT PIPX_ADAPTER_BINDING_INFO pAdapters,
  1076. IN DWORD dwMaxAdapters,
  1077. OUT LPDWORD lpdwAdaptersRead)
  1078. {
  1079. NTSTATUS status;
  1080. PNWLINK_ACTION action;
  1081. PIPX_NICS request;
  1082. IO_STATUS_BLOCK IoStatus;
  1083. PIPX_NIC_INFO info=NULL;
  1084. DWORD dwActionBufSize, dwRead;
  1085. *lpdwAdaptersRead = 0;
  1086. // Calculate the size of the buffer that we'll use
  1087. // to retrieve adapter information from the IPX Stack
  1088. dwActionBufSize = FIELD_OFFSET (NWLINK_ACTION, Data) +
  1089. FIELD_OFFSET (IPX_NICS, Data) +
  1090. sizeof (IPX_NIC_INFO) *
  1091. (dwMaxAdapters>0 ? dwMaxAdapters : 1);
  1092. // Prepare the data to send to the IPX Stack to retrieve the
  1093. // information about each adapter
  1094. action = (PNWLINK_ACTION) RtlAllocateHeap(RtlProcessHeap (), 0, dwActionBufSize);
  1095. if (action!=NULL) {
  1096. // Initialize the action buffer with the appropriate identifiers
  1097. action->Header.TransportId = ISN_ACTION_TRANSPORT_ID;
  1098. action->OptionType = NWLINK_OPTION_CONTROL;
  1099. action->Option = MIPX_GETNEWNICINFO;
  1100. // The BufferLength includes the length of everything after it,
  1101. // which is sizeof(ULONG) for Option plus whatever Data is present.
  1102. action->BufferLength = sizeof (action->Option) +
  1103. FIELD_OFFSET(IPX_NICS,Data) +
  1104. sizeof (IPX_NIC_INFO) *
  1105. (dwMaxAdapters>0 ? dwMaxAdapters : 1);
  1106. // Setting this flag makes the stack return information about
  1107. // all known adapters
  1108. request = (PIPX_NICS)action->Data;
  1109. request->NoOfNics = 0;
  1110. request->TotalNoOfNics = 0;
  1111. request->fAllNicsDesired = TRUE;
  1112. // Send the Ioctl
  1113. status = NtDeviceIoControlFile(IpxDriverHandle,NULL,NULL,NULL,&IoStatus,
  1114. IOCTL_TDI_ACTION,NULL,0,action,dwActionBufSize);
  1115. // Wait for it to complete
  1116. if (status==STATUS_PENDING) {
  1117. status = NtWaitForSingleObject (IpxDriverHandle, FALSE, NULL);
  1118. if (NT_SUCCESS (status))
  1119. status = IoStatus.Status;
  1120. }
  1121. // Make sure it was a successful completion
  1122. if (NT_SUCCESS (status)) {
  1123. PADAPTER_MSG msg;
  1124. PIPX_NIC_INFO NicPtr = (PIPX_NIC_INFO)request->Data;
  1125. UINT i, j=0;
  1126. dwRead = request->TotalNoOfNics;
  1127. // Loop through the adapters
  1128. for (i=0; (i<dwRead) && (status==STATUS_SUCCESS); i++, NicPtr++) {
  1129. if (NicPtr->Details.NetworkNumber != 0) {
  1130. pAdapters[j].AdapterIndex = (ULONG)NicMapGetVirtualNicId((USHORT)NicPtr->Details.NetworkNumber);
  1131. PUTULONG2LONG(pAdapters[j].Network, NicPtr->Details.NetworkNumber);
  1132. memcpy(pAdapters[j].LocalNode, NicPtr->Details.Node, 6);
  1133. memcpy(pAdapters[j].RemoteNode, NicPtr->RemoteNodeAddress, 6);
  1134. pAdapters[j].MaxPacketSize = NicPtr->MaxPacketSize;
  1135. pAdapters[j].LinkSpeed = NicPtr->LinkSpeed;
  1136. j++;
  1137. }
  1138. }
  1139. *lpdwAdaptersRead = j;
  1140. }
  1141. // We're done with the action buffer we sent to the stack
  1142. // now. It's safe to clean it up.
  1143. RtlFreeHeap (RtlProcessHeap (), 0, action);
  1144. }
  1145. return NO_ERROR;
  1146. }
  1147. // Requests the list of adapters from the stack
  1148. DWORD IpxSeedNicMap() {
  1149. NTSTATUS status;
  1150. PNWLINK_ACTION action;
  1151. PIPX_NICS request;
  1152. IO_STATUS_BLOCK IoStatus;
  1153. PIPX_NIC_INFO info=NULL;
  1154. DWORD dwActionBufSize, dwRead;
  1155. TracePrintf(g_dwTraceId, "IpxSeedMap: entered.");
  1156. // Calculate the size of the buffer that we'll use
  1157. // to retrieve adapter information from the IPX Stack
  1158. dwActionBufSize = FIELD_OFFSET (NWLINK_ACTION, Data) +
  1159. FIELD_OFFSET (IPX_NICS, Data) +
  1160. sizeof (IPX_NIC_INFO);
  1161. // Prepare the data to send to the IPX Stack to retrieve the
  1162. // information about each adapter
  1163. action = (PNWLINK_ACTION) RtlAllocateHeap(RtlProcessHeap (), 0, dwActionBufSize);
  1164. if (action!=NULL) {
  1165. // Initialize the action buffer with the appropriate identifiers
  1166. action->Header.TransportId = ISN_ACTION_TRANSPORT_ID;
  1167. action->OptionType = NWLINK_OPTION_CONTROL;
  1168. action->Option = MIPX_GETNEWNICINFO;
  1169. // The BufferLength includes the length of everything after it,
  1170. // which is sizeof(ULONG) for Option plus whatever Data is present.
  1171. action->BufferLength = sizeof (action->Option) +
  1172. FIELD_OFFSET(IPX_NICS,Data) +
  1173. sizeof (IPX_NIC_INFO);
  1174. // Setting this flag makes the stack return information about
  1175. // all known adapters
  1176. request = (PIPX_NICS)action->Data;
  1177. request->NoOfNics = 0;
  1178. request->TotalNoOfNics = 0;
  1179. request->fAllNicsDesired = TRUE;
  1180. // Send the Ioctl
  1181. status = NtDeviceIoControlFile(IpxDriverHandle,NULL,NULL,NULL,&IoStatus,
  1182. IOCTL_TDI_ACTION,NULL,0,action,dwActionBufSize);
  1183. // Wait for it to complete
  1184. if (status==STATUS_PENDING) {
  1185. status = NtWaitForSingleObject (IpxDriverHandle, FALSE, NULL);
  1186. if (NT_SUCCESS (status))
  1187. status = IoStatus.Status;
  1188. }
  1189. // Make sure it was a successful completion
  1190. if (NT_SUCCESS (status)) {
  1191. PADAPTER_MSG msg;
  1192. PIPX_NIC_INFO NicPtr = (PIPX_NIC_INFO)request->Data;
  1193. UINT i, j=0;
  1194. NumAdapters = request->TotalNoOfNics;
  1195. dwRead = request->NoOfNics;
  1196. // Display the nics and their status as reported in this completion of the
  1197. // MIPX_GETNEWNICINFO ioctl.
  1198. TracePrintf(g_dwTraceId, "==========================");
  1199. TracePrintf(g_dwTraceId, "MIPX_GETNEWNICS Completed. (%d of %d adapters reported)", request->NoOfNics, request->TotalNoOfNics);
  1200. TracePrintf(g_dwTraceId, "Internal Net Number: %x", InternalNetworkNumber);
  1201. DbgDisplayNics(NicPtr, dwRead);
  1202. // Loop through the adapters
  1203. for (i=0; (i<dwRead) && (status==STATUS_SUCCESS); i++, NicPtr++) {
  1204. GetNicOpCode(NicPtr); // get rid of op code since this is clean (shouldn't be one)
  1205. NicMapAdd (NicPtr); // add the nic to the map
  1206. }
  1207. // Post an irp for each adapter in case the stack decides to
  1208. // send information one adapter at a time. Sending 5 extra
  1209. // irps gives pad so that stack will always have an irp to complete
  1210. for (i = 0; i < 5; i++) {
  1211. status = RtlQueueWorkItem (PostAdapterConfigRequest, NULL,
  1212. WT_EXECUTEINIOTHREAD);
  1213. ASSERTMSG ("Could not queue router work item ", status==STATUS_SUCCESS);
  1214. }
  1215. }
  1216. // We're done with the action buffer we sent to the stack
  1217. // now. It's safe to clean it up.
  1218. RtlFreeHeap (RtlProcessHeap (), 0, action);
  1219. }
  1220. return NO_ERROR;
  1221. }
  1222. // Simulates a message in the given port that the internal adapter
  1223. // was reported as configured.
  1224. DWORD IpxPostIntNetNumMessage(PCONFIG_PORT pPort, DWORD dwNewNetNum) {
  1225. PADAPTER_MSG msg;
  1226. TracePrintf(g_dwTraceId, "IpxPostIntNetNumMessage: entered.");
  1227. // Send a regular adapter update message but make the
  1228. // adapter index equal to zero.
  1229. msg = (PADAPTER_MSG)RtlAllocateHeap (RtlProcessHeap (), 0, sizeof(ADAPTER_MSG));
  1230. if (msg == NULL)
  1231. return ERROR_NOT_ENOUGH_MEMORY;
  1232. // Initialize the message
  1233. ZeroMemory(msg, sizeof(ADAPTER_MSG));
  1234. msg->info.Details.NetworkNumber = dwNewNetNum;
  1235. msg->info.Status = NIC_CONFIGURED;
  1236. IPX_NODENUM_CPY (msg->info.Details.Node, INTERNAL_NODE_ADDRESS);
  1237. // Signal event if this is the first message we process
  1238. // and client queue is empty
  1239. if (IsListEmpty (&pPort->msgqueue)) {
  1240. BOOL res = SetEvent (pPort->event);
  1241. ASSERTMSG ("Can't set client event ", res);
  1242. }
  1243. // Insert the message into the port's message queue.
  1244. InsertTailList (&pPort->msgqueue, &msg->link);
  1245. return NO_ERROR;
  1246. }
  1247. //
  1248. // Function IpxDoesRouteExist
  1249. //
  1250. // Queries the stack to see if it has a route to the given network
  1251. //
  1252. // Arguments:
  1253. // puNetwork The network-ordered network number to query for
  1254. // pbRouteFound Set to true if network is found, false otherwise
  1255. //
  1256. // Returns:
  1257. // NO_ERROR on success
  1258. // Otherwise, an error that can be displayed with FormatMessage
  1259. //
  1260. DWORD IpxDoesRouteExist (IN PUCHAR puNetwork, OUT PBOOL pbRouteFound) {
  1261. NTSTATUS status;
  1262. PNWLINK_ACTION action;
  1263. PISN_ACTION_GET_LOCAL_TARGET pTarget;
  1264. IO_STATUS_BLOCK IoStatusBlock;
  1265. PUCHAR puIoctlBuffer;
  1266. DWORD dwBufferSize;
  1267. // Verify parameters
  1268. if (!puNetwork || !pbRouteFound)
  1269. return ERROR_INVALID_PARAMETER;
  1270. // Initialize
  1271. *pbRouteFound = FALSE;
  1272. dwBufferSize = sizeof(NWLINK_ACTION) + sizeof(ISN_ACTION_GET_LOCAL_TARGET);
  1273. puIoctlBuffer = (PUCHAR) RtlAllocateHeap(RtlProcessHeap(), 0, dwBufferSize);
  1274. if (!puIoctlBuffer)
  1275. return ERROR_NOT_ENOUGH_MEMORY;
  1276. ZeroMemory(puIoctlBuffer, dwBufferSize);
  1277. // Initialize the buffer for the ioctl
  1278. action = (PNWLINK_ACTION)puIoctlBuffer;
  1279. action->Header.TransportId = ISN_ACTION_TRANSPORT_ID;
  1280. action->OptionType = NWLINK_OPTION_CONTROL;
  1281. action->Option = MIPX_LOCALTARGET;
  1282. action->BufferLength = sizeof (action->Option) + sizeof(ISN_ACTION_GET_LOCAL_TARGET);
  1283. pTarget = (PISN_ACTION_GET_LOCAL_TARGET) action->Data;
  1284. pTarget->IpxAddress.NetworkAddress = *((ULONG*)puNetwork);
  1285. // Use critical section to serialize usage of driver handle
  1286. EnterCriticalSection (&ConfigInfoLock);
  1287. // Ask the stack if the route exists
  1288. status = NtDeviceIoControlFile(IpxDriverHandle,
  1289. NULL,
  1290. NULL,
  1291. NULL,
  1292. &IoStatusBlock,
  1293. IOCTL_TDI_ACTION,
  1294. NULL,
  1295. 0,
  1296. action,
  1297. dwBufferSize);
  1298. // Wait for an answer
  1299. if (status == STATUS_PENDING)
  1300. status = NtWaitForSingleObject (IpxDriverHandle, FALSE, NULL);
  1301. LeaveCriticalSection (&ConfigInfoLock);
  1302. // Find out if the route was found
  1303. if (NT_SUCCESS(IoStatusBlock.Status))
  1304. *pbRouteFound = TRUE;
  1305. else
  1306. *pbRouteFound = FALSE;
  1307. // Cleanup
  1308. RtlFreeHeap (RtlProcessHeap (), 0, puIoctlBuffer);
  1309. return RtlNtStatusToDosError (status);
  1310. }
  1311. /*++
  1312. G e t A d a p t e r N a m e W
  1313. Routine Description:
  1314. Returns UNICODE name of the adapter associated with given index
  1315. Arguments:
  1316. AdapterIndex - index of adapter
  1317. AdapterNameSize - size of adapter name (in bytes), including terminal wchar NULL
  1318. AdapterNameBuffer - buffer to receive adapter name
  1319. Return Value:
  1320. NO_ERROR - adapter name is in the buffer
  1321. ERROR_INVALID_PARAMETER - adapter with given index does not exist
  1322. ERROR_INSUFFICIENT_BUFFER - buffer in to small. Updates AdapterNameSize to
  1323. the correct value.
  1324. Other windows error code - operation failed
  1325. --*/
  1326. DWORD WINAPI
  1327. GetAdapterNameFromPhysNicW(
  1328. IN ULONG AdapterIndex,
  1329. IN OUT PULONG AdapterNameSize,
  1330. OUT LPWSTR AdapterNameBuffer
  1331. ) {
  1332. NTSTATUS status;
  1333. DWORD error;
  1334. ULONG ln;
  1335. PNWLINK_ACTION action;
  1336. IO_STATUS_BLOCK IoStatusBlock;
  1337. PISN_ACTION_GET_DETAILS details;
  1338. CHAR IoctlBuffer[
  1339. sizeof (NWLINK_ACTION)
  1340. +sizeof (ISN_ACTION_GET_DETAILS)];
  1341. action = (PNWLINK_ACTION)IoctlBuffer;
  1342. action->Header.TransportId = ISN_ACTION_TRANSPORT_ID;
  1343. action->OptionType = NWLINK_OPTION_CONTROL;
  1344. action->BufferLength = sizeof (action->Option)
  1345. +sizeof (ISN_ACTION_GET_DETAILS);
  1346. action->Option = MIPX_CONFIG;
  1347. details = (PISN_ACTION_GET_DETAILS)action->Data;
  1348. details->NicId = (USHORT)AdapterIndex;
  1349. // Use critical section to serialize usage of driver handle
  1350. EnterCriticalSection (&ConfigInfoLock);
  1351. status = NtDeviceIoControlFile(
  1352. IpxDriverHandle,
  1353. NULL,
  1354. NULL,
  1355. NULL,
  1356. &IoStatusBlock,
  1357. IOCTL_TDI_ACTION,
  1358. NULL,
  1359. 0,
  1360. action,
  1361. sizeof(NWLINK_ACTION)
  1362. +sizeof (ISN_ACTION_GET_DETAILS));
  1363. if (status==STATUS_PENDING){
  1364. status = NtWaitForSingleObject (IpxDriverHandle, FALSE, NULL);
  1365. if (NT_SUCCESS (status))
  1366. status = IoStatusBlock.Status;
  1367. }
  1368. LeaveCriticalSection (&ConfigInfoLock);
  1369. if (NT_SUCCESS (status)) {
  1370. // Compute required buffer size
  1371. ln = (lstrlenW (details->AdapterName)+1)*sizeof(WCHAR);
  1372. if (ln<=(*AdapterNameSize)) {
  1373. // Size of provided buffer is ok, copy the result
  1374. *AdapterNameSize = ln;
  1375. lstrcpyW (AdapterNameBuffer,details->AdapterName);
  1376. error = NO_ERROR;
  1377. }
  1378. else {
  1379. // Caller buffer is to small
  1380. *AdapterNameSize = ln;
  1381. error = ERROR_INSUFFICIENT_BUFFER;
  1382. }
  1383. }
  1384. else {
  1385. error = RtlNtStatusToDosError (status);
  1386. #if DBG
  1387. DbgPrint ("TDI Ioctl MIPX_CONFIG failed with status %08x\n",
  1388. status);
  1389. #endif
  1390. }
  1391. return error;
  1392. }
  1393. DWORD WINAPI
  1394. GetAdapterNameW(IN ULONG AdapterIndex,
  1395. IN OUT PULONG AdapterNameSize,
  1396. OUT LPWSTR AdapterNameBuffer)
  1397. {
  1398. return GetAdapterNameFromPhysNicW((ULONG)NicMapGetPhysicalNicId((USHORT)AdapterIndex),
  1399. AdapterNameSize,
  1400. AdapterNameBuffer);
  1401. }
  1402. DWORD WINAPI
  1403. GetAdapterNameFromMacAddrW(IN PUCHAR puMacAddr,
  1404. IN OUT PULONG AdapterNameSize,
  1405. OUT LPWSTR AdapterNameBuffer)
  1406. {
  1407. // return GetAdapterNameFromPhysNicW((ULONG)GetPhysFromMac(puMacAddr),
  1408. // AdapterNameSize,
  1409. // AdapterNameBuffer);
  1410. return NO_ERROR;
  1411. }
  1412. /*++
  1413. I p x W a n S e t A d a p t e r C o n f i g u r a t i o n
  1414. Routine Description:
  1415. Sets adapter configuration to be reported to both user and
  1416. kernel mode clients (through the ADAPTER_UP/LINE_UP events)
  1417. Arguments:
  1418. AdapterIndex - number of adapter being set
  1419. IpxWanInfo - IPXWAN negotiated parameters
  1420. Return Value:
  1421. NO_ERROR - adapter info set successfully
  1422. Windows error code - operation failed
  1423. --*/
  1424. DWORD
  1425. IpxWanSetAdapterConfiguration (
  1426. IN ULONG AdapterIndex,
  1427. IN PIPXWAN_INFO IpxWanInfo
  1428. ) {
  1429. NTSTATUS status;
  1430. PNWLINK_ACTION action;
  1431. IO_STATUS_BLOCK IoStatusBlock;
  1432. PIPXWAN_CONFIG_DONE config;
  1433. CHAR IoctlBuffer[
  1434. sizeof (NWLINK_ACTION)
  1435. +sizeof (IPXWAN_CONFIG_DONE)];
  1436. action = (PNWLINK_ACTION)IoctlBuffer;
  1437. action->Header.TransportId = ISN_ACTION_TRANSPORT_ID;
  1438. action->OptionType = NWLINK_OPTION_CONTROL;
  1439. action->BufferLength = sizeof (action->Option)
  1440. +sizeof (IPXWAN_CONFIG_DONE);
  1441. action->Option = MIPX_IPXWAN_CONFIG_DONE;
  1442. config = (PIPXWAN_CONFIG_DONE)action->Data;
  1443. config->NicId = NicMapGetPhysicalNicId((USHORT)AdapterIndex);
  1444. IPX_NETNUM_CPY (&config->Network, &IpxWanInfo->Network);
  1445. IPX_NODENUM_CPY (&config->LocalNode, &IpxWanInfo->LocalNode);
  1446. IPX_NODENUM_CPY (&config->RemoteNode, &IpxWanInfo->RemoteNode);
  1447. // Use critical section to serialize usage of driver handle
  1448. EnterCriticalSection (&ConfigInfoLock);
  1449. status = NtDeviceIoControlFile(
  1450. IpxDriverHandle,
  1451. NULL,
  1452. NULL,
  1453. NULL,
  1454. &IoStatusBlock,
  1455. IOCTL_TDI_ACTION,
  1456. NULL,
  1457. 0,
  1458. action,
  1459. sizeof(NWLINK_ACTION)
  1460. +sizeof (IPXWAN_CONFIG_DONE));
  1461. if (status==STATUS_PENDING){
  1462. status = NtWaitForSingleObject (IpxDriverHandle, FALSE, NULL);
  1463. if (NT_SUCCESS (status))
  1464. status = IoStatusBlock.Status;
  1465. }
  1466. LeaveCriticalSection (&ConfigInfoLock);
  1467. #if DBG
  1468. if (!NT_SUCCESS (status)) {
  1469. DbgPrint ("TDI Ioctl MIPX_IPXWAN_CONFIG_DONE failed with status %08x\n",
  1470. status);
  1471. }
  1472. #endif
  1473. return RtlNtStatusToDosError (status);
  1474. }
  1475. /*++
  1476. I p x W a n Q u e r y I n a c t i v i t y T i m e r
  1477. Routine Description:
  1478. Returns value of inactivity timer associated with WAN line
  1479. Arguments:
  1480. ConnectionId - connection id that identifies WAN line (used only
  1481. if *AdapterIndex==INVALID_NICID
  1482. AdapterIndex - adapter index that identifies WAN line (preferred
  1483. over connection id), if *AdapterIndex==INVALID_NICID
  1484. the value of connection id is used to identify the
  1485. WAN line and value of AdapterIndex is returned.
  1486. InactivityCounter - value of inactivity counter.
  1487. Return Value:
  1488. NO_ERROR - inactivity timer reading is returned
  1489. Windows error code - operation failed
  1490. --*/
  1491. DWORD
  1492. IpxWanQueryInactivityTimer (
  1493. IN ULONG ConnectionId,
  1494. IN OUT PULONG AdapterIndex,
  1495. OUT PULONG InactivityCounter
  1496. ) {
  1497. NTSTATUS status;
  1498. PNWLINK_ACTION action;
  1499. IO_STATUS_BLOCK IoStatusBlock;
  1500. PIPX_QUERY_WAN_INACTIVITY query;
  1501. CHAR IoctlBuffer[
  1502. sizeof (NWLINK_ACTION)
  1503. +sizeof (IPX_QUERY_WAN_INACTIVITY)];
  1504. action = (PNWLINK_ACTION)IoctlBuffer;
  1505. action->Header.TransportId = ISN_ACTION_TRANSPORT_ID;
  1506. action->OptionType = NWLINK_OPTION_CONTROL;
  1507. action->BufferLength = sizeof (action->Option)
  1508. +sizeof (IPX_QUERY_WAN_INACTIVITY);
  1509. action->Option = MIPX_QUERY_WAN_INACTIVITY;
  1510. query = (PIPX_QUERY_WAN_INACTIVITY)action->Data;
  1511. query->ConnectionId = ConnectionId;
  1512. query->NicId = NicMapGetPhysicalNicId((USHORT)(*AdapterIndex));
  1513. // Use critical section to serialize usage of driver handle
  1514. EnterCriticalSection (&ConfigInfoLock);
  1515. status = NtDeviceIoControlFile(
  1516. IpxDriverHandle,
  1517. NULL,
  1518. NULL,
  1519. NULL,
  1520. &IoStatusBlock,
  1521. IOCTL_TDI_ACTION,
  1522. NULL,
  1523. 0,
  1524. action,
  1525. sizeof(NWLINK_ACTION)
  1526. +sizeof (IPX_QUERY_WAN_INACTIVITY));
  1527. if (status==STATUS_PENDING){
  1528. status = NtWaitForSingleObject (IpxDriverHandle, FALSE, NULL);
  1529. if (NT_SUCCESS (status))
  1530. status = IoStatusBlock.Status;
  1531. }
  1532. LeaveCriticalSection (&ConfigInfoLock);
  1533. if (NT_SUCCESS (status)) {
  1534. *AdapterIndex = query->NicId;
  1535. *InactivityCounter = query->WanInactivityCounter;
  1536. }
  1537. #if DBG
  1538. else {
  1539. DbgPrint ("TDI Ioctl MIPX_QUERY_WAN_INACTIVITY failed with status %08x\n",
  1540. status);
  1541. }
  1542. #endif
  1543. return RtlNtStatusToDosError (status);
  1544. }
  1545. /*++
  1546. O p e n A d a p t e r C o n f i g P o r t
  1547. Routine Description:
  1548. Creates path to adapter configuration mechanism provided by the IPX stack
  1549. and obtains "static" adapter information (number of adapters, internal net parameters)
  1550. Arguments:
  1551. None
  1552. Return Value:
  1553. NO_ERROR - port was open OK
  1554. Windows error code - operation failed
  1555. --*/
  1556. DWORD
  1557. OpenAdapterConfigPort (void) {
  1558. UNICODE_STRING FileString;
  1559. OBJECT_ATTRIBUTES ObjectAttributes;
  1560. IO_STATUS_BLOCK IoStatus;
  1561. NTSTATUS status;
  1562. DWORD i;
  1563. // Initialize the parameters needed to open the driver
  1564. RtlInitUnicodeString (&FileString, ISN_IPX_NAME);
  1565. InitializeObjectAttributes(
  1566. &ObjectAttributes,
  1567. &FileString,
  1568. OBJ_CASE_INSENSITIVE,
  1569. NULL,
  1570. NULL);
  1571. // Get a handle to the ipx driver
  1572. status = NtOpenFile(&IpxDriverHandle,
  1573. SYNCHRONIZE | FILE_READ_DATA | FILE_WRITE_DATA,
  1574. &ObjectAttributes,
  1575. &IoStatus,
  1576. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1577. 0);
  1578. // If the driver handle wasn't opened, we're in an error state
  1579. if (NT_SUCCESS (status)) {
  1580. PISN_ACTION_GET_DETAILS details;
  1581. PNWLINK_ACTION action;
  1582. CHAR IoctlBuffer[sizeof (NWLINK_ACTION)
  1583. +sizeof (ISN_ACTION_GET_DETAILS)];
  1584. // Prepare to send an ioctl to the stack to get the internal
  1585. // net information along with the global adapter information
  1586. action = (PNWLINK_ACTION)IoctlBuffer;
  1587. action->Header.TransportId = ISN_ACTION_TRANSPORT_ID;
  1588. action->OptionType = NWLINK_OPTION_CONTROL;
  1589. action->BufferLength = sizeof(action->Option) + sizeof(ISN_ACTION_GET_DETAILS);
  1590. action->Option = MIPX_CONFIG;
  1591. details = (PISN_ACTION_GET_DETAILS)action->Data;
  1592. // Nic id 0 will return internal net information and
  1593. // total number of adapters
  1594. details->NicId = 0;
  1595. // Send the ioctl
  1596. status = NtDeviceIoControlFile(
  1597. IpxDriverHandle,
  1598. NULL,
  1599. NULL,
  1600. NULL,
  1601. &IoStatus,
  1602. IOCTL_TDI_ACTION,
  1603. NULL,
  1604. 0,
  1605. action,
  1606. sizeof(NWLINK_ACTION) + sizeof(ISN_ACTION_GET_DETAILS));
  1607. // Wait for the ioctl to complete
  1608. if (status==STATUS_PENDING) {
  1609. status = NtWaitForSingleObject (IpxDriverHandle, FALSE, NULL);
  1610. if (NT_SUCCESS (status))
  1611. status = IoStatus.Status;
  1612. }
  1613. // If the stack reports all the requested information without error,
  1614. // update global variables with the information retrieved.
  1615. if (NT_SUCCESS (status)) {
  1616. NumAdapters = details->NicId;
  1617. InternalNetworkNumber = details->NetworkNumber;
  1618. // Seed the nic map by forcing the stack to at least report
  1619. // one nic. (you'll always be guarenteed that one nic will
  1620. // be available -- the IpxLoopbackAdadpter
  1621. IpxSeedNicMap();
  1622. return NO_ERROR;
  1623. }
  1624. #if DBG
  1625. // If this branch is reached, display the ioctl error code
  1626. else
  1627. DbgPrint ("TDI Ioctl MIPX_CONFIG failed with status %08x\n",status);
  1628. #endif
  1629. }
  1630. #if DBG
  1631. // If this branch is reached, display the couldn't open driver error
  1632. else
  1633. DbgPrint ("NtOpenFile failed with status %08x\n",status);
  1634. #endif
  1635. return RtlNtStatusToDosError (status);
  1636. }
  1637. /*++
  1638. I n i t i a l i z e M e s s a g e Q u e u e F o r C l i e n t
  1639. Routine Description:
  1640. Inserts messages that were already reported to existing clients
  1641. in the beginning of the queue and points new client port (control block)
  1642. to them. Thus new client can see adapters that were already reported to
  1643. others before, while others are not disturbed
  1644. Arguments:
  1645. config - new client port (control block)
  1646. Return Value:
  1647. NO_ERROR - messages were inserted OK
  1648. Windows error code - operation failed
  1649. --*/
  1650. DWORD
  1651. InitializeMessageQueueForClient (PCONFIG_PORT port) {
  1652. NTSTATUS status = STATUS_SUCCESS;
  1653. DWORD dwAdapterCount;
  1654. PADAPTER_MSG msg;
  1655. PIPX_NIC_INFO NicPtr;
  1656. DWORD i, dwErr;
  1657. USHORT usNicId;
  1658. // Output some debug information
  1659. TracePrintf(g_dwTraceId, "InitializeMessageQueueForClient: entered.");
  1660. // Find out how many adapters we know about in our table.
  1661. dwAdapterCount = NicMapGetMaxNicId();
  1662. // Loop through the adapters
  1663. for (i = 0; i <= dwAdapterCount; i++)
  1664. {
  1665. NicPtr = NicMapGetNicInfo ((USHORT)i);
  1666. if (!NicPtr)
  1667. continue;
  1668. #if DBG && defined(WATCHER_DIALOG)
  1669. if (IsAdapterDisabled (NicPtr->NicId))
  1670. continue;
  1671. #endif
  1672. if (NicPtr->IpxwanConfigRequired == 1)
  1673. continue;
  1674. // Place the appropriate messages in the message queue of
  1675. // the port of the client passed in.
  1676. //
  1677. switch (NicPtr->Status)
  1678. {
  1679. case NIC_CONFIGURED:
  1680. case NIC_LINE_UP:
  1681. // Insert the message in the client queue
  1682. //
  1683. usNicId = NicMapGetVirtualNicId(NicPtr->Details.NicId);
  1684. if (usNicId == NIC_MAP_INVALID_NICID)
  1685. {
  1686. break;
  1687. }
  1688. NicPtr->Details.NicId = usNicId;
  1689. msg = (PADAPTER_MSG)
  1690. RtlAllocateHeap(RtlProcessHeap (), 0, sizeof(ADAPTER_MSG));
  1691. if (msg!=NULL)
  1692. {
  1693. RtlCopyMemory (&msg->info, NicPtr, sizeof (IPX_NIC_INFO));
  1694. InsertTailList (&port->msgqueue, &msg->link);
  1695. status = STATUS_SUCCESS;
  1696. }
  1697. else
  1698. {
  1699. #if DBG
  1700. DbgPrint ("Could not allocate memory for config"
  1701. " message (gle:%08x).\n",
  1702. GetLastError ());
  1703. #endif
  1704. status = STATUS_NO_MEMORY;
  1705. }
  1706. break;
  1707. case NIC_DELETED:
  1708. case NIC_CREATED:
  1709. case NIC_LINE_DOWN:
  1710. break;
  1711. default:
  1712. ASSERTMSG ("Unknown nic state reported ", FALSE);
  1713. }
  1714. }
  1715. DbgDisplayMap();
  1716. // Advertise the internal adapter
  1717. dwErr = IpxPostIntNetNumMessage(port, InternalNetworkNumber);
  1718. if (dwErr != NO_ERROR)
  1719. {
  1720. TracePrintf(
  1721. g_dwTraceId,
  1722. "Unable to report internal network number: %x Err: %x",
  1723. InternalNetworkNumber,
  1724. dwErr);
  1725. }
  1726. // Go ahead and signal the client to do its processing
  1727. // if everything has been successful to this point and
  1728. // if the client's message queue isn't empty.
  1729. if (NT_SUCCESS (status))
  1730. {
  1731. if (!IsListEmpty (&port->msgqueue))
  1732. {
  1733. BOOL res = SetEvent (port->event);
  1734. ASSERTMSG ("Can't set client's event ", res);
  1735. }
  1736. }
  1737. return RtlNtStatusToDosError (status);
  1738. }
  1739. /*++
  1740. C l o s e A d a p t e r C o n f i g P o r t
  1741. Routine Description:
  1742. Closes path to the IPX stack adapter notification mechanism
  1743. Arguments:
  1744. None
  1745. Return Value:
  1746. STATUS_SUCCESS - port was closed OK
  1747. NT error status - operation failed
  1748. --*/
  1749. NTSTATUS
  1750. CloseAdapterConfigPort (PVOID pvConfigBuffer) {
  1751. NTSTATUS status;
  1752. TracePrintf(g_dwTraceId, "CloseAdapterConfigPort: Entered");
  1753. // Only close it if it is open
  1754. if (IpxDriverHandle!=NULL) {
  1755. HANDLE localHandle = IpxDriverHandle;
  1756. IpxDriverHandle = NULL;
  1757. status = NtClose (localHandle);
  1758. ASSERTMSG ("NtClose failed ", NT_SUCCESS (status));
  1759. }
  1760. // Get rid of the buffer
  1761. if (pvConfigBuffer != NULL)
  1762. RtlFreeHeap (RtlProcessHeap(), 0, pvConfigBuffer);
  1763. while (AdapterChangeApcPending>0)
  1764. Sleep (100);
  1765. return NO_ERROR;
  1766. }
  1767. /*++
  1768. I n s e r t M e s s a g e
  1769. Routine Description:
  1770. Inserts message into client port queue
  1771. Arguments:
  1772. port - client port to isert message into
  1773. NicInfo - adapter info to be inserted as the message
  1774. Return Value:
  1775. STATUS_SUCCESS - message was inserted ok
  1776. NT error status - operation failed
  1777. --*/
  1778. NTSTATUS
  1779. InsertMessage (PCONFIG_PORT port,
  1780. PIPX_NIC_INFO NicInfo)
  1781. {
  1782. PADAPTER_MSG msg;
  1783. // Allocate a new message
  1784. msg = (PADAPTER_MSG)RtlAllocateHeap (RtlProcessHeap (),
  1785. 0,
  1786. sizeof (ADAPTER_MSG));
  1787. if (msg!=NULL) {
  1788. // Copy in the Nic information
  1789. RtlCopyMemory (&msg->info, NicInfo, sizeof (IPX_NIC_INFO));
  1790. // Signal event if this is the first message we process
  1791. // and client queue is empty
  1792. if (IsListEmpty (&port->msgqueue)) {
  1793. BOOL res = SetEvent (port->event);
  1794. ASSERTMSG ("Can't set client event ", res);
  1795. }
  1796. // Insert the message into the port's message queue.
  1797. InsertTailList (&port->msgqueue, &msg->link);
  1798. return STATUS_SUCCESS;
  1799. }
  1800. else {
  1801. #if DBG
  1802. DbgPrint ("Could not allocate memory for config" " message (gle:%08x).\n",GetLastError ());
  1803. #endif
  1804. return STATUS_NO_MEMORY;
  1805. }
  1806. }
  1807. /*++
  1808. P r o c e s s A d a p t e r C o n f i g I n f o
  1809. Routine Description:
  1810. Process adapter change information returned by the IPX stack and
  1811. converts it to messages
  1812. Arguments:
  1813. None
  1814. Return Value:
  1815. None
  1816. --*/
  1817. NTSTATUS
  1818. ProcessAdapterConfigInfo (
  1819. IN PVOID pvConfigBuffer)
  1820. {
  1821. INT i, nMessages, nClients=0;
  1822. PNWLINK_ACTION action = (PNWLINK_ACTION)pvConfigBuffer;
  1823. PIPX_NICS request = (PIPX_NICS)action->Data;
  1824. PIPX_NIC_INFO NicPtr = (PIPX_NIC_INFO)request->Data;
  1825. NTSTATUS status = STATUS_SUCCESS;
  1826. // Update number of adapters
  1827. NumAdapters = request->TotalNoOfNics;
  1828. nMessages = request->NoOfNics;
  1829. // Display the nics and their status as reported in this completion of the
  1830. // MIPX_GETNEWNICINFO ioctl.
  1831. DbgDisplayNics(NicPtr, nMessages);
  1832. // Loop through all of the adapters
  1833. for (i=0; (i<nMessages) && (status==STATUS_SUCCESS); i++, NicPtr++)
  1834. {
  1835. PLIST_ENTRY cur;
  1836. DWORD dwOpCode;
  1837. // The stack will notify us that we need to renumber our
  1838. // nic id's based on the addition/deletion adapters. Find
  1839. // out if this message is telling us that we need to renumber
  1840. dwOpCode = GetNicOpCode(NicPtr);
  1841. // Map the physical nic id to a virtual one -- rearraging
  1842. // the mapping tables if needed. Also, instruct the
  1843. // forwarder to renumber its nic id's as well
  1844. if (dwOpCode == NIC_OPCODE_INCREMENT_NICIDS)
  1845. {
  1846. FwRenumberNics (dwOpCode, NicPtr->Details.NicId);
  1847. NicMapRenumber (dwOpCode, NicPtr->Details.NicId);
  1848. NicMapAdd(NicPtr);
  1849. TracePrintf(
  1850. g_dwTraceId,
  1851. "Added %d -- Increment map",
  1852. NicPtr->Details.NicId);
  1853. NicPtr->Details.NicId =
  1854. NicMapGetVirtualNicId(NicPtr->Details.NicId);
  1855. }
  1856. else if (dwOpCode == NIC_OPCODE_DECREMENT_NICIDS)
  1857. {
  1858. USHORT usNicId =
  1859. NicMapGetVirtualNicId(NicPtr->Details.NicId);
  1860. FwRenumberNics (dwOpCode, NicPtr->Details.NicId);
  1861. NicMapDel (NicPtr);
  1862. NicMapRenumber (dwOpCode, NicPtr->Details.NicId);
  1863. TracePrintf(
  1864. g_dwTraceId,
  1865. "Deleted %d -- Decrement map",
  1866. NicPtr->Details.NicId);
  1867. NicPtr->Details.NicId = usNicId;
  1868. }
  1869. else
  1870. {
  1871. if (NicPtr->Status != NIC_DELETED)
  1872. {
  1873. TracePrintf(
  1874. g_dwTraceId,
  1875. "Configured: %d -- Map reconfigure",
  1876. NicPtr->Details.NicId);
  1877. NicMapReconfigure(NicPtr);
  1878. }
  1879. else
  1880. {
  1881. TracePrintf(
  1882. g_dwTraceId,
  1883. "Deleted: %d -- No map renumber",
  1884. NicPtr->Details.NicId);
  1885. NicMapDel(NicPtr);
  1886. }
  1887. NicPtr->Details.NicId =
  1888. NicMapGetVirtualNicId(NicPtr->Details.NicId);
  1889. }
  1890. // If the information about the current NIC is stating
  1891. // that a NIC has been created with a network address of
  1892. // zero, and it's not a wan link (unumbered wan links can
  1893. // have net number = 0), then nothing needs to be done
  1894. // about this adapter since we wont be able to send information
  1895. // out over it anyway.
  1896. if ((NicPtr->Status==NIC_CREATED) &&
  1897. (NicPtr->Details.NetworkNumber==0) &&
  1898. (NicPtr->NdisMediumType!=NdisMediumWan))
  1899. {
  1900. continue;
  1901. }
  1902. #if DBG && defined(WATCHER_DIALOG)
  1903. // Make sure that the adapter is enabled
  1904. if (IsAdapterDisabled (NicPtr->NicId))
  1905. {
  1906. continue;
  1907. }
  1908. #endif
  1909. // Update the ipxwan configuration if neccesary
  1910. //
  1911. if (NicPtr->IpxwanConfigRequired==1)
  1912. {
  1913. if (IpxWanPort!=NULL)
  1914. {
  1915. status = InsertMessage (IpxWanPort, NicPtr);
  1916. }
  1917. }
  1918. else
  1919. {
  1920. // If this is a notification that the nic was deleted,
  1921. // tell the computers calling in that the nic was deleted.
  1922. if ((IpxWanPort!=NULL) && (NicPtr->Status==NIC_DELETED))
  1923. {
  1924. status = InsertMessage (IpxWanPort, NicPtr);
  1925. }
  1926. // Signal each client (as in rtrmgr, sap, rip) to
  1927. // check the status of the current Nic.
  1928. for (cur = PortListHead.Flink;
  1929. (cur != &PortListHead) && (status == STATUS_SUCCESS);
  1930. cur = cur->Flink)
  1931. {
  1932. status =
  1933. InsertMessage (
  1934. CONTAINING_RECORD (cur, CONFIG_PORT, link),
  1935. NicPtr);
  1936. }
  1937. }
  1938. }
  1939. DbgDisplayMap();
  1940. return status;
  1941. }
  1942. /*++
  1943. A d a p t e r C h a n g e A P C
  1944. Routine Description:
  1945. APC invoked when adapter change notification IRP is completed by the Ipx Stack
  1946. It is only used when running in router context (alertable thread provided by
  1947. rtutils is used)
  1948. Arguments:
  1949. Context - Not used
  1950. IoStatus - status of completed io operation
  1951. Reserved - ???
  1952. Return Value:
  1953. None
  1954. --*/
  1955. VOID
  1956. AdapterChangeAPC (
  1957. PVOID context,
  1958. PIO_STATUS_BLOCK IoStatus,
  1959. ULONG Reserved)
  1960. {
  1961. DWORD dwErr, dwNetNum = 0;
  1962. BOOL bNewInternal = FALSE;
  1963. PVOID pvConfigBuffer = ((PUCHAR)context) + sizeof(DWORD);
  1964. ASSERT (IoStatus==&IoctlStatus);
  1965. // Display the id of the buffer reporting this information
  1966. //
  1967. TracePrintf(
  1968. g_dwTraceId,
  1969. "AdapterChangeAPC called for buffer %d",
  1970. *((DWORD*)context));
  1971. // [pmay] Check to see if the internal network number has
  1972. // changed.
  1973. if (PnpGetCurrentInternalNetNum(&dwNetNum) == NO_ERROR)
  1974. {
  1975. if ((bNewInternal = (InternalNetworkNumber != dwNetNum)) == TRUE)
  1976. {
  1977. // Notify all clients to adptif (rtrmgr, sap, rip) that the
  1978. // internalnetwork number has changed.
  1979. if (PnpHandleInternalNetNumChange(dwNetNum) == NO_ERROR)
  1980. {
  1981. InternalNetworkNumber = dwNetNum;
  1982. }
  1983. }
  1984. }
  1985. // Output some debug information
  1986. {
  1987. PNWLINK_ACTION action = (PNWLINK_ACTION)pvConfigBuffer;
  1988. PIPX_NICS request = (PIPX_NICS)action->Data;
  1989. TracePrintf(
  1990. g_dwTraceId,
  1991. "==========================");
  1992. TracePrintf(
  1993. g_dwTraceId,
  1994. "MIPX_GETNEWNICS Completed. (%d of %d adapters reported)",
  1995. request->NoOfNics,
  1996. request->TotalNoOfNics);
  1997. TracePrintf(
  1998. g_dwTraceId,
  1999. "Internal Net Number: %x (%s)",
  2000. dwNetNum,
  2001. (bNewInternal) ? "new" : "same");
  2002. }
  2003. // Ignore request when port is closed
  2004. //
  2005. if (IpxDriverHandle!=NULL)
  2006. {
  2007. EnterCriticalSection (&ConfigInfoLock);
  2008. // If the Irp completed successfully, process the received
  2009. // information.
  2010. if (NT_SUCCESS (IoctlStatus.Status))
  2011. {
  2012. IoctlStatus.Status = ProcessAdapterConfigInfo (pvConfigBuffer);
  2013. }
  2014. // Re-send the IRP immediately so that the next time
  2015. // an adapter change occurs, we'll be notified.
  2016. if (NT_SUCCESS (IoctlStatus.Status))
  2017. {
  2018. PostAdapterConfigRequest (NULL);
  2019. }
  2020. else
  2021. {
  2022. PLIST_ENTRY cur;
  2023. // Signal clients dialing in, so that they can get
  2024. // error information.
  2025. //
  2026. if ((IpxWanPort!=NULL) && IsListEmpty (&IpxWanPort->msgqueue))
  2027. {
  2028. BOOL res = SetEvent (IpxWanPort->event);
  2029. ASSERTMSG ("Can't set client event ", res);
  2030. }
  2031. // Loop through all of the clients to this dll (i.e. rip,
  2032. // sap, router manager)
  2033. for (cur=PortListHead.Flink; cur!=&PortListHead; cur = cur->Flink)
  2034. {
  2035. PCONFIG_PORT port = CONTAINING_RECORD (cur, CONFIG_PORT, link);
  2036. // If the mes queue for client is empty at this point, then
  2037. // it means ProcessAdapterConfigInfo() didn't detect any work
  2038. // items for the client in question. We set the message
  2039. // here so that the client knows that something happened.
  2040. if (IsListEmpty (&port->msgqueue))
  2041. {
  2042. BOOL res = SetEvent (port->event);
  2043. ASSERTMSG ("Can't set client event ", res);
  2044. }
  2045. }
  2046. }
  2047. LeaveCriticalSection (&ConfigInfoLock);
  2048. #if DBG && defined(WATCHER_DIALOG)
  2049. InformWatcher (); // Let watcher update its info as well
  2050. #endif
  2051. }
  2052. else
  2053. {
  2054. TracePrintf(g_dwTraceId, "Warning - IpxDriverHandle is NULL, not processing");
  2055. }
  2056. // [pmay]
  2057. // We're done with the new nic info buffer now.
  2058. //
  2059. if (context)
  2060. {
  2061. RtlFreeHeap (RtlProcessHeap(), 0, context);
  2062. }
  2063. InterlockedDecrement (&AdapterChangeApcPending);
  2064. }
  2065. /*++
  2066. P o s t A d a p t e r C o n f i g R e q u e s t
  2067. Routine Description:
  2068. Posts IRP to the driver to get adapter change notifications
  2069. Arguments:
  2070. Context - event to be used to signal completion of the IRP, NULL if APC
  2071. is to be used for this purpose
  2072. Return Value:
  2073. None
  2074. --*/
  2075. VOID
  2076. APIENTRY
  2077. PostAdapterConfigRequest (
  2078. IN PVOID context)
  2079. {
  2080. HANDLE WaitHandle = (HANDLE)context;
  2081. PNWLINK_ACTION action;
  2082. PIPX_NICS request;
  2083. PVOID pvConfigBuffer = NULL;
  2084. DWORD dwBufSize = 0, dwActionSize = 0, dwNicBufSize = 0;
  2085. TracePrintf(g_dwTraceId, "PostAdapterConfigRequest: Entered\n");
  2086. EnterCriticalSection (&ConfigInfoLock);
  2087. // Allocate request buffer, making sure that we have space for at
  2088. // least one adapter.
  2089. //
  2090. dwNicBufSize =
  2091. FIELD_OFFSET (IPX_NICS, Data) +
  2092. (sizeof (IPX_NIC_INFO) * (NumAdapters>0 ? NumAdapters : 1));
  2093. dwActionSize =
  2094. FIELD_OFFSET (NWLINK_ACTION, Data) + dwNicBufSize;
  2095. dwBufSize =
  2096. sizeof(DWORD) + dwActionSize;
  2097. pvConfigBuffer =
  2098. RtlAllocateHeap (RtlProcessHeap (), 0, dwBufSize);
  2099. if (pvConfigBuffer == NULL)
  2100. {
  2101. #if DBG
  2102. DbgPrint (
  2103. "Could not alloc mem for global req buffer (gle:%08x).\n",
  2104. GetLastError ());
  2105. #endif
  2106. IoctlStatus.Status=STATUS_NO_MEMORY;
  2107. LeaveCriticalSection (&ConfigInfoLock);
  2108. return;
  2109. }
  2110. // Set up global buffer parameters
  2111. //
  2112. *((DWORD*)pvConfigBuffer) = g_dwBufferId++;
  2113. // Set up the actions parameters
  2114. //
  2115. action = (PNWLINK_ACTION)((PUCHAR)pvConfigBuffer + sizeof(DWORD));
  2116. action->Header.TransportId = ISN_ACTION_TRANSPORT_ID;
  2117. action->OptionType = NWLINK_OPTION_CONTROL;
  2118. action->BufferLength = sizeof (action->Option) + dwNicBufSize;
  2119. action->Option = MIPX_GETNEWNICINFO;
  2120. request = (PIPX_NICS)action->Data;
  2121. request->NoOfNics = 0;
  2122. request->TotalNoOfNics = 0;
  2123. request->fAllNicsDesired = FALSE;
  2124. IoctlStatus.Status =
  2125. NtDeviceIoControlFile(
  2126. IpxDriverHandle,
  2127. WaitHandle,
  2128. (WaitHandle==NULL) ? AdapterChangeAPC : NULL,
  2129. (WaitHandle==NULL) ? pvConfigBuffer : NULL,
  2130. &IoctlStatus,
  2131. IOCTL_TDI_ACTION,
  2132. NULL,
  2133. 0,
  2134. action,
  2135. dwActionSize);
  2136. if (NT_SUCCESS (IoctlStatus.Status))
  2137. {
  2138. if (WaitHandle==NULL)
  2139. {
  2140. InterlockedIncrement (&AdapterChangeApcPending);
  2141. }
  2142. }
  2143. else
  2144. {
  2145. #if DBG
  2146. DbgPrint (
  2147. "Ioctl MIPX_GETNEWNICINFO failed with status %08x\n",
  2148. IoctlStatus.Status);
  2149. #endif
  2150. }
  2151. LeaveCriticalSection (&ConfigInfoLock);
  2152. }