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.

1217 lines
31 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. ntos\tdi\isn\fwd\driver.c
  5. Abstract:
  6. IPX Forwarder driver dispatch routines
  7. Author:
  8. Vadim Eydelman
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. const UCHAR BROADCAST_NODE[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
  13. const LONGLONG WaitTimeout = -50000000i64;
  14. volatile BOOLEAN IpxFwdInitialized = FALSE;
  15. BOOLEAN MeasuringPerformance = FALSE;
  16. KSPIN_LOCK PerfCounterLock;
  17. FWD_PERFORMANCE PerfBlock;
  18. LONG ClientCount = 0;
  19. KEVENT ClientsGoneEvent;
  20. PFILE_OBJECT RouterFile, FilterFile;
  21. NTSTATUS
  22. IpxFwdDispatch(
  23. IN PDEVICE_OBJECT DeviceObject,
  24. IN PIRP Irp
  25. );
  26. VOID
  27. IpxFwdUnload(
  28. IN PDRIVER_OBJECT DriverObject
  29. );
  30. NTSTATUS
  31. DoStart (
  32. IN ULONG RouteHashTableSize,
  33. IN BOOLEAN thisMachineOnly
  34. );
  35. NTSTATUS
  36. DoStop (
  37. void
  38. );
  39. NTSTATUS
  40. DoSetInterface (
  41. IN ULONG InterfaceIndex,
  42. IN BOOLEAN NetbiosAccept,
  43. IN UCHAR NetbiosDeliver
  44. );
  45. NTSTATUS
  46. DoGetInterface (
  47. IN ULONG InterfaceIndex,
  48. OUT PFWD_IF_STATS stats,
  49. OUT BOOLEAN *NetbiosAccept,
  50. OUT UCHAR *NetbiosDeliver
  51. );
  52. NTSTATUS
  53. DoSetNbNames (
  54. IN ULONG InterfaceIndex,
  55. IN ULONG Count,
  56. IN PFWD_NB_NAME Names
  57. );
  58. NTSTATUS
  59. DoGetNbNames (
  60. IN ULONG InterfaceIndex,
  61. IN OUT ULONG *BufferSize,
  62. OUT ULONG *Count,
  63. OUT PFWD_NB_NAME Names
  64. );
  65. NTSTATUS
  66. DoBindInterface (
  67. IN ULONG InterfaceIndex,
  68. IN PFWD_ADAPTER_BINDING_INFO info
  69. );
  70. NTSTATUS
  71. DoUnbindInterface (
  72. IN ULONG InterfaceIndex
  73. );
  74. NTSTATUS
  75. DoDisableInterface (
  76. IN ULONG InterfaceIndex
  77. );
  78. NTSTATUS
  79. DoEnableInterface (
  80. IN ULONG InterfaceIndex
  81. );
  82. NTSTATUS
  83. DoSetRoutes (
  84. IN PFWD_ROUTE_SET_PARAMS routeArray,
  85. IN ULONG nRoutes,
  86. OUT PULONG nProcessed
  87. );
  88. VOID
  89. IpxFwdCancel (
  90. IN PDEVICE_OBJECT DeviceObject,
  91. IN PIRP irp
  92. );
  93. NTSTATUS
  94. DoGetPerfCounters (
  95. OUT PFWD_PERFORMANCE_PARAMS perfParams,
  96. OUT ULONG* plSize
  97. );
  98. // [pmay] Keep the forwarder sync'd with the stack's nic id
  99. // numbering scheme.
  100. NTSTATUS DecrementNicids (USHORT usThreshold);
  101. NTSTATUS IncrementNicids (USHORT usThreshold);
  102. NTSTATUS DoGetIfTable (FWD_INTERFACE_TABLE_ROW * pRows,
  103. ULONG dwRowBufferSize);
  104. /*++
  105. D r i v e r E n t r y
  106. Routine Description:
  107. Installable driver initialization entry point.
  108. This entry point is called directly by the I/O system.
  109. Arguments:
  110. DriverObject - pointer to the driver object
  111. RegistryPath - pointer to a unicode string representing the path
  112. to driver-specific key in the registry
  113. Return Value:
  114. STATUS_SUCCESS if successful,
  115. STATUS_UNSUCCESSFUL otherwise
  116. --*/
  117. NTSTATUS
  118. DriverEntry (
  119. IN PDRIVER_OBJECT DriverObject,
  120. IN PUNICODE_STRING RegistryPath
  121. ) {
  122. PDEVICE_OBJECT deviceObject = NULL;
  123. NTSTATUS status;
  124. WCHAR deviceNameBuffer[] = IPXFWD_NAME;
  125. UNICODE_STRING deviceNameUnicodeString;
  126. IpxFwdDbgPrint(DBG_IOCTLS, DBG_INFORMATION,
  127. ("IpxFwd: Entering DriverEntry\n"));
  128. //
  129. // Create an non-EXCLUSIVE device object
  130. //
  131. RtlInitUnicodeString (&deviceNameUnicodeString,
  132. deviceNameBuffer);
  133. status = IoCreateDevice (DriverObject,
  134. 0,
  135. &deviceNameUnicodeString,
  136. FILE_DEVICE_IPXFWD,
  137. 0,
  138. FALSE, // Non-Exclusive
  139. &deviceObject
  140. );
  141. if (NT_SUCCESS(status)) {
  142. //
  143. // Create dispatch points for device control, create, close.
  144. //
  145. GetForwarderParameters (RegistryPath);
  146. DriverObject->MajorFunction[IRP_MJ_CREATE]
  147. = DriverObject->MajorFunction[IRP_MJ_CLEANUP]
  148. = DriverObject->MajorFunction[IRP_MJ_CLOSE]
  149. = DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL]
  150. = IpxFwdDispatch;
  151. DriverObject->DriverUnload = IpxFwdUnload;
  152. status = BindToIpxDriver (KernelMode);
  153. if (NT_SUCCESS (status)) {
  154. #if DBG
  155. KeQueryPerformanceCounter (&CounterFrequency);
  156. #endif
  157. FilterFile = RouterFile = NULL;
  158. ClientCount = 0;
  159. return STATUS_SUCCESS;
  160. }
  161. IoDeleteDevice (DriverObject->DeviceObject);
  162. }
  163. else
  164. IpxFwdDbgPrint (DBG_IOCTLS, DBG_ERROR,
  165. ("IpxFwd: IoCreateDevice failed\n"));
  166. return status;
  167. }
  168. /*++
  169. Routine Description:
  170. Process the IRPs sent to this device.
  171. Arguments:
  172. DeviceObject - pointer to a device object
  173. Irp - pointer to an I/O Request Packet
  174. Return Value:
  175. --*/
  176. NTSTATUS
  177. IpxFwdDispatch(
  178. IN PDEVICE_OBJECT DeviceObject,
  179. IN PIRP Irp
  180. ) {
  181. PIO_STACK_LOCATION IrpStack;
  182. PVOID inBuffer, outBuffer;
  183. ULONG inpBufLength;
  184. ULONG outBufLength;
  185. NTSTATUS status;
  186. KIRQL cancelIRQL;
  187. LONG lNumProcessed;
  188. ULONG ulBytesCopied;
  189. ulBytesCopied = 0;
  190. lNumProcessed = 0;
  191. Irp->IoStatus.Information = 0;
  192. status = STATUS_SUCCESS;
  193. //
  194. // Get a pointer to the current location in the Irp. This is where
  195. // the function codes and parameters are located.
  196. //
  197. IrpStack = IoGetCurrentIrpStackLocation(Irp);
  198. switch (IrpStack->MajorFunction) {
  199. case IRP_MJ_CREATE:
  200. IpxFwdDbgPrint(DBG_IOCTLS, DBG_WARNING, ("IpxFwd: IRP_MJ_CREATE\n"));
  201. break;
  202. case IRP_MJ_CLOSE:
  203. IpxFwdDbgPrint(DBG_IOCTLS, DBG_WARNING, ("IpxFwd: IRP_MJ_CLOSE\n"));
  204. if (EnterForwarder ()) {
  205. if (IrpStack->FileObject==RouterFile) {
  206. LeaveForwarder ();
  207. IpxFwdInitialized = FALSE;
  208. while (InterlockedDecrement (&ClientCount)>=0) {
  209. KeWaitForSingleObject (&ClientsGoneEvent,
  210. Executive,
  211. KernelMode,
  212. FALSE,
  213. (PLARGE_INTEGER)&WaitTimeout);
  214. InterlockedIncrement (&ClientCount);
  215. IpxFwdDbgPrint(DBG_IOCTLS, DBG_ERROR,
  216. ("IpxFwd: Waiting for all clients (%ld) to exit.\n",
  217. ClientCount));
  218. }
  219. status = DoStop ();
  220. ClientCount = 0;
  221. RouterFile = NULL;
  222. }
  223. else if (IrpStack->FileObject==FilterFile) {
  224. UnbindFilterDriver ();
  225. FilterFile = NULL;
  226. LeaveForwarder ();
  227. }
  228. else
  229. LeaveForwarder ();
  230. }
  231. break;
  232. case IRP_MJ_CLEANUP:
  233. IpxFwdDbgPrint(DBG_IOCTLS, DBG_WARNING, ("IpxFwd: IRP_MJ_CLEANUP\n"));
  234. if (EnterForwarder ()) {
  235. if (IrpStack->FileObject==RouterFile) {
  236. IoAcquireCancelSpinLock (&cancelIRQL);
  237. while (!IsListEmpty (&ConnectionIrpQueue)) {
  238. PIRP irp = CONTAINING_RECORD (ConnectionIrpQueue.Blink,
  239. IRP, Tail.Overlay.ListEntry);
  240. irp->Cancel = TRUE;
  241. irp->CancelIrql = cancelIRQL;
  242. irp->CancelRoutine = NULL;
  243. IpxFwdCancel(DeviceObject, irp);
  244. IoAcquireCancelSpinLock (&cancelIRQL);
  245. }
  246. IoReleaseCancelSpinLock(cancelIRQL);
  247. }
  248. LeaveForwarder ();
  249. }
  250. break;
  251. case IRP_MJ_DEVICE_CONTROL:
  252. //
  253. // Get the pointer to the input/output buffer and it's length
  254. //
  255. status = STATUS_INVALID_PARAMETER;
  256. inpBufLength = IrpStack->Parameters.DeviceIoControl.InputBufferLength;
  257. outBufLength = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
  258. switch (IrpStack->Parameters.DeviceIoControl.IoControlCode&3) {
  259. case METHOD_BUFFERED:
  260. inBuffer = outBuffer = Irp->AssociatedIrp.SystemBuffer;
  261. break;
  262. case METHOD_IN_DIRECT:
  263. case METHOD_OUT_DIRECT:
  264. inBuffer = Irp->AssociatedIrp.SystemBuffer;
  265. if (outBufLength>0) {
  266. outBuffer = MmGetSystemAddressForMdlSafe (Irp->MdlAddress, NormalPagePriority);
  267. if (outBuffer == NULL)
  268. {
  269. IpxFwdDbgPrint(DBG_IOCTLS, DBG_ERROR,
  270. ("IpxFwd: System too low on memory to allocate mdl buffer.\n"));
  271. goto DispatchExit;
  272. }
  273. }
  274. else {
  275. outBuffer = NULL;
  276. IpxFwdDbgPrint(DBG_IOCTLS, DBG_ERROR,
  277. ("IpxFwd: IOCTL...METHOD_DIRECT with 0 output buffer ???\n"));
  278. }
  279. break;
  280. default:
  281. IpxFwdDbgPrint(DBG_IOCTLS, DBG_ERROR,
  282. ("IpxFwd: IOCTL...METHOD_NEITHER ???\n"));
  283. goto DispatchExit;
  284. }
  285. if (EnterForwarder ()) {
  286. if (IrpStack->FileObject==RouterFile) {
  287. switch (IrpStack->Parameters.DeviceIoControl.IoControlCode) {
  288. case IOCTL_FWD_SET_ROUTES:
  289. IpxFwdDbgPrint(DBG_IOCTLS, DBG_INFORMATION, ("IpxFwd: IOCTL_FWD_SET_ROUTES\n"));
  290. if (inpBufLength>=sizeof (FWD_ROUTE_SET_PARAMS))
  291. status = DoSetRoutes (
  292. (PFWD_ROUTE_SET_PARAMS)inBuffer,
  293. inpBufLength/sizeof(FWD_ROUTE_SET_PARAMS),
  294. &lNumProcessed);
  295. break;
  296. case IOCTL_FWD_SET_NB_NAMES:
  297. IpxFwdDbgPrint(DBG_IOCTLS, DBG_INFORMATION, ("IpxFwd: IOCTL_FWD_SET_NB_NAMES\n"));
  298. if (inpBufLength==sizeof (ULONG))
  299. status = DoSetNbNames (
  300. *((PULONG)inBuffer),
  301. outBufLength/sizeof (FWD_NB_NAME),
  302. (PFWD_NB_NAME)outBuffer);
  303. break;
  304. case IOCTL_FWD_RESET_NB_NAMES:
  305. IpxFwdDbgPrint(DBG_IOCTLS, DBG_INFORMATION, ("IpxFwd: IOCTL_FWD_RESET_NB_NAMES\n"));
  306. if (inpBufLength==sizeof (ULONG))
  307. status = DoSetNbNames (*((PULONG)inBuffer), 0, NULL);
  308. break;
  309. case IOCTL_FWD_GET_NB_NAMES:
  310. IpxFwdDbgPrint(DBG_IOCTLS, DBG_INFORMATION, ("IpxFwd: IOCTL_FWD_GET_NB_NAMES\n"));
  311. if ((inpBufLength==sizeof (ULONG))
  312. && (outBufLength>=sizeof(ULONG))) {
  313. Irp->IoStatus.Information = outBufLength
  314. -FIELD_OFFSET (FWD_NB_NAMES_PARAMS, Names);
  315. status = DoGetNbNames (
  316. *((PULONG)inBuffer),
  317. &ulBytesCopied,
  318. &((PFWD_NB_NAMES_PARAMS)outBuffer)->TotalCount,
  319. ((PFWD_NB_NAMES_PARAMS)outBuffer)->Names);
  320. Irp->IoStatus.Information = ulBytesCopied;
  321. if (NT_SUCCESS (status)) {
  322. Irp->IoStatus.Information += FIELD_OFFSET (
  323. FWD_NB_NAMES_PARAMS, Names);
  324. }
  325. }
  326. break;
  327. case IOCTL_FWD_CREATE_INTERFACE:
  328. IpxFwdDbgPrint(DBG_IOCTLS, DBG_INFORMATION, ("IpxFwd: IOCTL_FWD_CREATE_INTERFACE\n"));
  329. if (inpBufLength==sizeof(FWD_IF_CREATE_PARAMS))
  330. status = AddInterface (
  331. ((PFWD_IF_CREATE_PARAMS)inBuffer)->Index,
  332. ((PFWD_IF_CREATE_PARAMS)inBuffer)->InterfaceType,
  333. ((PFWD_IF_CREATE_PARAMS)inBuffer)->NetbiosAccept,
  334. ((PFWD_IF_CREATE_PARAMS)inBuffer)->NetbiosDeliver);
  335. break;
  336. case IOCTL_FWD_DELETE_INTERFACE:
  337. IpxFwdDbgPrint(DBG_IOCTLS, DBG_INFORMATION, ("IpxFwd: IOCTL_FWD_DELETE_INTERFACE\n"));
  338. if (inpBufLength==sizeof(ULONG))
  339. status = DeleteInterface (
  340. *((PULONG)inBuffer));
  341. break;
  342. case IOCTL_FWD_SET_INTERFACE:
  343. IpxFwdDbgPrint(DBG_IOCTLS, DBG_INFORMATION, ("IpxFwd: IOCTL_FWD_SET_INTERFACE\n"));
  344. if (inpBufLength==sizeof(FWD_IF_SET_PARAMS))
  345. status = DoSetInterface (
  346. ((PFWD_IF_SET_PARAMS)inBuffer)->Index,
  347. ((PFWD_IF_SET_PARAMS)inBuffer)->NetbiosAccept,
  348. ((PFWD_IF_SET_PARAMS)inBuffer)->NetbiosDeliver);
  349. break;
  350. case IOCTL_FWD_GET_INTERFACE:
  351. IpxFwdDbgPrint(DBG_IOCTLS, DBG_INFORMATION, ("IpxFwd: IOCTL_FWD_GET_INTERFACE\n"));
  352. if ((inpBufLength==sizeof(ULONG))
  353. && (outBufLength==sizeof(FWD_IF_GET_PARAMS))) {
  354. status = DoGetInterface (
  355. *((PULONG)inBuffer),
  356. &((PFWD_IF_GET_PARAMS)outBuffer)->Stats,
  357. &((PFWD_IF_GET_PARAMS)outBuffer)->NetbiosAccept,
  358. &((PFWD_IF_GET_PARAMS)outBuffer)->NetbiosDeliver);
  359. if (NT_SUCCESS (status))
  360. Irp->IoStatus.Information = sizeof(FWD_IF_GET_PARAMS);
  361. }
  362. break;
  363. case IOCTL_FWD_BIND_INTERFACE:
  364. IpxFwdDbgPrint(DBG_IOCTLS, DBG_INFORMATION, ("IpxFwd: IOCTL_FWD_BIND_INTERFACE\n"));
  365. if (inpBufLength==sizeof(FWD_IF_BIND_PARAMS))
  366. status = DoBindInterface (
  367. ((PFWD_IF_BIND_PARAMS)inBuffer)->Index,
  368. &((PFWD_IF_BIND_PARAMS)inBuffer)->Info);
  369. break;
  370. case IOCTL_FWD_UNBIND_INTERFACE:
  371. IpxFwdDbgPrint(DBG_IOCTLS, DBG_INFORMATION, ("IpxFwd: IOCTL_FWD_UNBIND_INTERFACE\n"));
  372. if (inpBufLength==sizeof(ULONG))
  373. status = DoUnbindInterface (*((PULONG)inBuffer));
  374. break;
  375. case IOCTL_FWD_RENUMBER_NICS:
  376. IpxFwdDbgPrint(DBG_IOCTLS, DBG_INFORMATION, ("IpxFwd: IOCTL_FWD_RENUMBER_NICS\n"));
  377. if (inpBufLength == sizeof(FWD_RENUMBER_NICS_DATA)) {
  378. if (((FWD_RENUMBER_NICS_DATA*)inBuffer)->ulOpCode == FWD_NIC_OPCODE_DECREMENT)
  379. status = DecrementNicids (((FWD_RENUMBER_NICS_DATA*)inBuffer)->usThreshold);
  380. else
  381. status = IncrementNicids (((FWD_RENUMBER_NICS_DATA*)inBuffer)->usThreshold);
  382. }
  383. break;
  384. case IOCTL_FWD_GET_DIAL_REQUEST:
  385. IpxFwdDbgPrint(DBG_IOCTLS, DBG_INFORMATION, ("IpxFwd: IOCTL_FWD_GET_DIAL_REQUEST\n"));
  386. if (outBufLength>=sizeof (ULONG)) {
  387. IoAcquireCancelSpinLock (&cancelIRQL);
  388. if (!IsListEmpty (&ConnectionRequestQueue)) {
  389. PINTERFACE_CB ifCB = CONTAINING_RECORD (
  390. ConnectionRequestQueue.Flink,
  391. INTERFACE_CB,
  392. ICB_ConnectionLink);
  393. RemoveEntryList (&ifCB->ICB_ConnectionLink);
  394. InitializeListEntry (&ifCB->ICB_ConnectionLink);
  395. IoReleaseCancelSpinLock (cancelIRQL);
  396. KeAcquireSpinLock (&ifCB->ICB_Lock, &cancelIRQL);
  397. FillConnectionRequest (
  398. ifCB->ICB_Index,
  399. ifCB->ICB_ConnectionPacket,
  400. ifCB->ICB_ConnectionData,
  401. (PFWD_DIAL_REQUEST)outBuffer,
  402. outBufLength,
  403. &ulBytesCopied);
  404. Irp->IoStatus.Information = ulBytesCopied;
  405. status = STATUS_SUCCESS;
  406. KeReleaseSpinLock (&ifCB->ICB_Lock, cancelIRQL);
  407. }
  408. else {
  409. InsertTailList (&ConnectionIrpQueue,
  410. &Irp->Tail.Overlay.ListEntry);
  411. IoSetCancelRoutine (Irp, IpxFwdCancel);
  412. IoMarkIrpPending (Irp);
  413. Irp->IoStatus.Status = status = STATUS_PENDING;
  414. IoReleaseCancelSpinLock (cancelIRQL);
  415. }
  416. }
  417. break;
  418. case IOCTL_FWD_DIAL_REQUEST_FAILED:
  419. IpxFwdDbgPrint(DBG_IOCTLS, DBG_INFORMATION, ("IpxFwd: IOCTL_FWD_DIAL_REQUEST_FAILED\n"));
  420. if (inpBufLength==sizeof (ULONG))
  421. status = FailConnectionRequest (
  422. *((PULONG)inBuffer));
  423. break;
  424. case IOCTL_FWD_DISABLE_INTERFACE:
  425. IpxFwdDbgPrint(DBG_IOCTLS, DBG_INFORMATION, ("IpxFwd: IOCTL_FWD_DISABLE_INTERFACE\n"));
  426. if (inpBufLength==sizeof (ULONG))
  427. status = DoDisableInterface (
  428. *((PULONG)inBuffer));
  429. break;
  430. case IOCTL_FWD_ENABLE_INTERFACE:
  431. IpxFwdDbgPrint(DBG_IOCTLS, DBG_INFORMATION, ("IpxFwd: IOCTL_FWD_ENABLE_INTERFACE\n"));
  432. if (inpBufLength==sizeof (ULONG))
  433. status = DoEnableInterface (
  434. *((PULONG)inBuffer));
  435. break;
  436. case IOCTL_FWD_UPDATE_CONFIG:
  437. IpxFwdDbgPrint(DBG_IOCTLS, DBG_INFORMATION, ("IpxFwd: IOCTL_FWD_UPDATE_CONFIG\n"));
  438. if (inpBufLength==sizeof (FWD_UPDATE_CONFIG_PARAMS)) {
  439. ThisMachineOnly = ((FWD_UPDATE_CONFIG_PARAMS*)inBuffer)->bThisMachineOnly;
  440. status = STATUS_SUCCESS;
  441. }
  442. break;
  443. default:
  444. IpxFwdDbgPrint (DBG_IOCTLS, DBG_WARNING, ("IpxFwd: unknown IRP_MJ_DEVICE_CONTROL\n"));
  445. break;
  446. }
  447. }
  448. else if (IrpStack->Parameters.DeviceIoControl.IoControlCode
  449. ==IOCTL_FWD_INTERNAL_BIND_FILTER)
  450. {
  451. IpxFwdDbgPrint(DBG_IOCTLS, DBG_INFORMATION, ("IpxFwd: IOCTL_FWD_INTERNAL_BIND_FILTER\n"));
  452. //
  453. // pmay: 218246
  454. // We only allow the kernel-mode ipx filter driver
  455. // to bind to us.
  456. //
  457. if (
  458. (ExGetPreviousMode() == KernelMode) &&
  459. (inpBufLength == sizeof(IPX_FLT_BIND_INPUT) ) &&
  460. (outBufLength >= sizeof(ULONG) )
  461. )
  462. {
  463. if (outBufLength >= sizeof (IPX_FLT_BIND_OUTPUT)) {
  464. BindFilterDriver (
  465. (PIPX_FLT_BIND_INPUT)inBuffer,
  466. (PIPX_FLT_BIND_OUTPUT)outBuffer);
  467. Irp->IoStatus.Information = sizeof (IPX_FLT_BIND_OUTPUT);
  468. FilterFile = IrpStack->FileObject;
  469. status = STATUS_SUCCESS;
  470. }
  471. else {
  472. IPX_FLT_BIND_OUTPUT bindOutput;
  473. BindFilterDriver (
  474. (PIPX_FLT_BIND_INPUT)inBuffer,
  475. &bindOutput);
  476. memcpy (outBuffer, &bindOutput, outBufLength);
  477. Irp->IoStatus.Information = outBufLength;
  478. status = STATUS_BUFFER_OVERFLOW;
  479. }
  480. }
  481. }
  482. else if (IrpStack->Parameters.DeviceIoControl.IoControlCode
  483. ==IOCTL_FWD_GET_PERF_COUNTERS) {
  484. IpxFwdDbgPrint(DBG_IOCTLS, DBG_INFORMATION, ("IpxFwd: IOCTL_FWD_GET_PERF_COUNTERS\n"));
  485. if (outBufLength==sizeof (FWD_PERFORMANCE_PARAMS))
  486. {
  487. status = DoGetPerfCounters (
  488. ((PFWD_PERFORMANCE_PARAMS)outBuffer),
  489. &ulBytesCopied);
  490. Irp->IoStatus.Information = ulBytesCopied;
  491. }
  492. }
  493. else if (IrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_FWD_GET_IF_TABLE) {
  494. IpxFwdDbgPrint(DBG_IOCTLS, DBG_INFORMATION, ("IpxFwd: IOCTL_FWD_GET_IF_TABLE\n"));
  495. status = DoGetIfTable (outBuffer, outBufLength);
  496. Irp->IoStatus.Information = outBufLength;
  497. }
  498. else {
  499. status = STATUS_ACCESS_DENIED;
  500. IpxFwdDbgPrint(DBG_IOCTLS, DBG_WARNING,
  501. ("IpxFwd: IOCTL: %08lx on non-router file object!\n",
  502. IrpStack->Parameters.DeviceIoControl.IoControlCode));
  503. }
  504. LeaveForwarder ();
  505. } else {
  506. if (IrpStack->Parameters.DeviceIoControl.IoControlCode==IOCTL_FWD_START) {
  507. IpxFwdDbgPrint (DBG_IOCTLS, DBG_WARNING,
  508. ("IpxFwd: IOCTL_FWD_START\n"));
  509. if (inpBufLength==sizeof (FWD_START_PARAMS)) {
  510. KeInitializeEvent (&ClientsGoneEvent,
  511. SynchronizationEvent,
  512. FALSE);
  513. status = DoStart (
  514. ((PFWD_START_PARAMS)inBuffer)->RouteHashTableSize,
  515. ((PFWD_START_PARAMS)inBuffer)->ThisMachineOnly);
  516. if (NT_SUCCESS (status)) {
  517. RouterFile = IrpStack->FileObject;
  518. IpxFwdInitialized = TRUE;
  519. }
  520. }
  521. }
  522. else {
  523. IpxFwdDbgPrint (DBG_IOCTLS, DBG_ERROR,
  524. ("IpxFwd: IOCTL: %08lx but fwd not started.\n",
  525. IrpStack->Parameters.DeviceIoControl.IoControlCode));
  526. }
  527. }
  528. break;
  529. default:
  530. IpxFwdDbgPrint (DBG_IOCTLS, DBG_ERROR,
  531. ("IpxFwd: unknown MajorFunction.\n"));
  532. break;
  533. }
  534. DispatchExit:
  535. if (status!=STATUS_PENDING) {
  536. IpxFwdDbgPrint(DBG_IOCTLS,
  537. NT_ERROR(status) ? DBG_WARNING : DBG_INFORMATION,
  538. ("IpxFwd: completing IOCTL %08lx with status %08lx.\n",
  539. IrpStack->Parameters.DeviceIoControl.IoControlCode,
  540. status));
  541. Irp->IoStatus.Status = status;
  542. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  543. }
  544. return status;
  545. }
  546. /*++
  547. Routine Description:
  548. Cleans up on driver unload
  549. Arguments:
  550. DriverObject - pointer to a driver object
  551. Return Value:
  552. --*/
  553. VOID
  554. IpxFwdUnload(
  555. IN PDRIVER_OBJECT DriverObject
  556. ) {
  557. IpxFwdDbgPrint(DBG_IOCTLS, DBG_WARNING, ("IpxFwd: unloading\n"));
  558. if (EnterForwarder ()) {
  559. LeaveForwarder ();
  560. IpxFwdInitialized = FALSE;
  561. while (InterlockedDecrement (&ClientCount)>=0) {
  562. KeWaitForSingleObject (&ClientsGoneEvent,
  563. Executive,
  564. KernelMode,
  565. FALSE,
  566. (PLARGE_INTEGER)&WaitTimeout);
  567. InterlockedIncrement (&ClientCount);
  568. IpxFwdDbgPrint(DBG_IOCTLS, DBG_ERROR,
  569. ("IpxFwd: Waiting for all clients (%ld) to exit.\n",
  570. ClientCount));
  571. }
  572. DoStop ();
  573. }
  574. UnbindFromIpxDriver (KernelMode);
  575. IoDeleteDevice (DriverObject->DeviceObject);
  576. }
  577. /*++
  578. D o S t a r t
  579. Routine Description:
  580. Initializes all driver components and binds to IPX
  581. stack driver at strat up
  582. Arguments:
  583. RouteHashTableSize - size of route hash table
  584. thisMachineOnly - whether to forward dialin client packets
  585. to other dests on the net
  586. Return Value:
  587. STATUS_SUCCESS - initialization succeded
  588. STATUS_UNSUCCESSFULL - failure
  589. --*/
  590. NTSTATUS
  591. DoStart (
  592. IN ULONG RouteHashTableSize,
  593. IN BOOLEAN thisMachineOnly
  594. ) {
  595. NTSTATUS status;
  596. InitializeConnectionQueues ();
  597. RouteHashSize = RouteHashTableSize;
  598. status = CreateTables ();
  599. if (NT_SUCCESS (status)) {
  600. InitializePacketAllocator ();
  601. InitializeNetbiosQueue ();
  602. InitializeRecvQueue ();
  603. InitializeSendQueue ();
  604. MeasuringPerformance = FALSE;
  605. KeInitializeSpinLock (&PerfCounterLock);
  606. ThisMachineOnly = thisMachineOnly;
  607. return STATUS_SUCCESS;
  608. }
  609. return status;
  610. }
  611. /*++
  612. D o S t o p
  613. Routine Description:
  614. Cleans up allocated resources and unbinds from IPX stack
  615. driver when forwarder is stopped
  616. Arguments:
  617. None
  618. Return Value:
  619. STATUS_SUCCESS - cleanup succeded
  620. --*/
  621. NTSTATUS
  622. DoStop (
  623. void
  624. ) {
  625. if (FilterFile!=NULL) {
  626. UnbindFilterDriver ();
  627. FilterFile = NULL;
  628. }
  629. DeleteSendQueue ();
  630. DeleteRecvQueue ();
  631. DeleteNetbiosQueue ();
  632. DeleteTables (); // Unbinds all bound interfaces
  633. if (WanPacketListId!=-1) {
  634. DeregisterPacketConsumer (WanPacketListId);
  635. WanPacketListId = -1;
  636. }
  637. DeletePacketAllocator ();
  638. return STATUS_SUCCESS;
  639. }
  640. /*++
  641. D o S e t R o u t e s
  642. Routine Description:
  643. Updates route table with supplied routes
  644. Arguments:
  645. routeArray - array of routes to add/de;ete/update
  646. nRoutes - number of routes in the array
  647. nProcessed - number of routes that were processed successfully
  648. Return Value:
  649. STATUS_SUCCESS - all routes were processed ok
  650. error status - reason of failure for the first unprocessed route
  651. --*/
  652. NTSTATUS
  653. DoSetRoutes (
  654. IN PFWD_ROUTE_SET_PARAMS routeArray,
  655. IN ULONG nRoutes,
  656. OUT PULONG nProcessed
  657. ) {
  658. NTSTATUS status=STATUS_SUCCESS;
  659. UINT i;
  660. for (i=0; i<nRoutes; i++, routeArray++) {
  661. switch (routeArray->Action) {
  662. case FWD_ADD_ROUTE:
  663. status = AddRoute (routeArray->Network,
  664. routeArray->NextHopAddress,
  665. routeArray->TickCount,
  666. routeArray->HopCount,
  667. routeArray->InterfaceIndex);
  668. break;
  669. case FWD_DELETE_ROUTE:
  670. status = DeleteRoute (routeArray->Network);
  671. break;
  672. case FWD_UPDATE_ROUTE:
  673. status = UpdateRoute (routeArray->Network,
  674. routeArray->NextHopAddress,
  675. routeArray->TickCount,
  676. routeArray->HopCount,
  677. routeArray->InterfaceIndex);
  678. break;
  679. default:
  680. status = STATUS_INVALID_PARAMETER;
  681. break;
  682. }
  683. if (!NT_SUCCESS (status))
  684. break;
  685. }
  686. *nProcessed = i;
  687. return status;
  688. }
  689. /*++
  690. D o S e t N b N a m e s
  691. Routine Description:
  692. Sets static Netbios Names on the interface
  693. Arguments:
  694. InterfaceIndex - index oc interface on which to set names
  695. Count - number of names to set
  696. Names - array of netbios names
  697. Return Value:
  698. STATUS_SUCCESS - names were set OK
  699. STATUS_UNSUCCESSFULL - interface does not exist
  700. STATUS_INSUFFICIENT_RESOURCES - not enough resources to complete
  701. the operation
  702. --*/
  703. NTSTATUS
  704. DoSetNbNames (
  705. IN ULONG InterfaceIndex,
  706. IN ULONG Count,
  707. IN PFWD_NB_NAME Names
  708. ) {
  709. PINTERFACE_CB ifCB;
  710. KIRQL oldIRQL;
  711. PNB_ROUTE nbRoutes;
  712. NTSTATUS status=STATUS_SUCCESS;
  713. ifCB = GetInterfaceReference (InterfaceIndex);
  714. if (ifCB!=NULL) {
  715. if (ifCB->ICB_NBRoutes!=NULL) {
  716. DeleteNBRoutes (ifCB->ICB_NBRoutes, ifCB->ICB_NBRouteCount);
  717. ifCB->ICB_NBRoutes = NULL;
  718. ifCB->ICB_NBRouteCount = 0;
  719. }
  720. if (Count>0) {
  721. status = AddNBRoutes (ifCB, Names, Count, &nbRoutes);
  722. if (NT_SUCCESS (status)) {
  723. ifCB->ICB_NBRoutes = nbRoutes;
  724. ifCB->ICB_NBRouteCount = Count;
  725. }
  726. }
  727. ReleaseInterfaceReference (ifCB);
  728. }
  729. else
  730. status = STATUS_UNSUCCESSFUL;
  731. return status;
  732. }
  733. /*++
  734. D o G e t N b N a m e s
  735. Routine Description:
  736. Gets all static Netbios Names on the interface
  737. Arguments:
  738. InterfaceIndex - index of interface from which to get names
  739. ArraySize - on input: size of the buffer to put names into
  740. on output: size of data put into the array
  741. Names - buffer to put names into names, if buffer
  742. is to small to hold all names, this orutine stuffs
  743. total number of names into the first ULONG in the
  744. array (this is the only way to return in to the
  745. caller through the IOCTL interface)
  746. Return Value:
  747. STATUS_SUCCESS - names were copied into the array
  748. STATUS_UNSUCCESSFULL - interface does not exist
  749. STATUS_BUFFER_OVERFLOW - buffer is too small to copy all the
  750. names, number of names are in the first ULONG of
  751. the buffer
  752. --*/
  753. NTSTATUS
  754. DoGetNbNames (
  755. IN ULONG InterfaceIndex,
  756. IN OUT ULONG *ArraySize,
  757. OUT ULONG *TotalCount,
  758. OUT PFWD_NB_NAME Names
  759. ) {
  760. PINTERFACE_CB ifCB;
  761. KIRQL oldIRQL;
  762. NTSTATUS status=STATUS_SUCCESS;
  763. ifCB = GetInterfaceReference (InterfaceIndex);
  764. if (ifCB!=NULL) {
  765. if (ifCB->ICB_NBRoutes!=NULL) {
  766. ULONG i;
  767. PFWD_NB_NAME nameLM = Names+(*ArraySize/sizeof(FWD_NB_NAME));
  768. for (i=0; (i<ifCB->ICB_NBRouteCount)&&(Names<nameLM); i++, Names++)
  769. NB_NAME_CPY (Names, &ifCB->ICB_NBRoutes[i].NBR_Name);
  770. *ArraySize = sizeof (FWD_NB_NAME)*i;
  771. *TotalCount = ifCB->ICB_NBRouteCount;
  772. }
  773. else {
  774. *ArraySize = 0;
  775. *TotalCount = 0;
  776. }
  777. ReleaseInterfaceReference (ifCB);
  778. }
  779. else
  780. status = STATUS_UNSUCCESSFUL;
  781. return status;
  782. }
  783. /*++
  784. D o S e t I n t e r f a c e
  785. Routine Description:
  786. Sets interface configurable parameters
  787. Arguments:
  788. InterfaceIndex - index of interface to set
  789. NetbiosAccept - whether to accept nb packets on the interface
  790. NetbiosDeliver - whether to deliver nb packets on the interface
  791. Return Value:
  792. STATUS_SUCCESS - interface was set OK
  793. STATUS_UNSUCCESSFULL - interface does not exist
  794. --*/
  795. NTSTATUS
  796. DoSetInterface (
  797. IN ULONG InterfaceIndex,
  798. IN BOOLEAN NetbiosAccept,
  799. IN UCHAR NetbiosDeliver
  800. ) {
  801. PINTERFACE_CB ifCB;
  802. KIRQL oldIRQL;
  803. ifCB = GetInterfaceReference (InterfaceIndex);
  804. if (ifCB!=NULL) {
  805. KeAcquireSpinLock (&ifCB->ICB_Lock, &oldIRQL);
  806. ifCB->ICB_NetbiosAccept = NetbiosAccept;
  807. ifCB->ICB_NetbiosDeliver = NetbiosDeliver;
  808. KeReleaseSpinLock (&ifCB->ICB_Lock, oldIRQL);
  809. ReleaseInterfaceReference (ifCB);
  810. return STATUS_SUCCESS;
  811. }
  812. else
  813. return STATUS_UNSUCCESSFUL;
  814. }
  815. /*++
  816. D o G e t I n t e r f a c e
  817. Routine Description:
  818. Gets interface configurable parameters and statistics
  819. Arguments:
  820. InterfaceIndex - index of interface to query
  821. stats - interface statistics
  822. NetbiosAccept - whether nb packets accepter on the interface
  823. NetbiosDeliver - whether nb packets delivered on the interface
  824. Return Value:
  825. STATUS_SUCCESS - interface data was queried OK
  826. STATUS_UNSUCCESSFULL - interface does not exist
  827. --*/
  828. NTSTATUS
  829. DoGetInterface (
  830. IN ULONG InterfaceIndex,
  831. OUT PFWD_IF_STATS stats,
  832. OUT BOOLEAN *NetbiosAccept,
  833. OUT UCHAR *NetbiosDeliver
  834. ) {
  835. PINTERFACE_CB ifCB;
  836. KIRQL oldIRQL;
  837. ifCB = GetInterfaceReference (InterfaceIndex);
  838. if (ifCB!=NULL) {
  839. *NetbiosAccept = ifCB->ICB_NetbiosAccept;
  840. *NetbiosDeliver = ifCB->ICB_NetbiosDeliver;
  841. IF_STATS_CPY (stats, &ifCB->ICB_Stats);
  842. if (!IS_IF_ENABLED(ifCB))
  843. stats->OperationalState = FWD_OPER_STATE_DOWN;
  844. ReleaseInterfaceReference (ifCB);
  845. return STATUS_SUCCESS;
  846. }
  847. else
  848. return STATUS_UNSUCCESSFUL;
  849. }
  850. /*++
  851. D o B i n d I n t e r f a c e
  852. Routine Description:
  853. Binds interface to the specified adapter and sets binding
  854. parameters
  855. Arguments:
  856. InterfaceIndex - index of interface to bind
  857. info - binding info
  858. Return Value:
  859. STATUS_SUCCESS - interface was bound OK
  860. STATUS_UNSUCCESSFULL - interface does not exist or could not be
  861. bound
  862. --*/
  863. NTSTATUS
  864. DoBindInterface (
  865. IN ULONG InterfaceIndex,
  866. IN PFWD_ADAPTER_BINDING_INFO info
  867. ) {
  868. PINTERFACE_CB ifCB;
  869. NTSTATUS status;
  870. ifCB = GetInterfaceReference (InterfaceIndex);
  871. if (ifCB!=NULL) {
  872. if (ifCB->ICB_InterfaceType==FWD_IF_PERMANENT)
  873. status = BindInterface (ifCB,
  874. (USHORT)info->AdapterIndex,
  875. info->MaxPacketSize,
  876. info->Network,
  877. info->LocalNode,
  878. info->RemoteNode);
  879. else
  880. status = STATUS_SUCCESS;
  881. ReleaseInterfaceReference (ifCB);
  882. return status;
  883. }
  884. else
  885. return STATUS_UNSUCCESSFUL;
  886. }
  887. /*++
  888. D o U n b i n d I n t e r f a c e
  889. Routine Description:
  890. Unbinds interface from the adapter and invalidates binding
  891. parameters
  892. Arguments:
  893. InterfaceIndex - index of interface to unbind
  894. Return Value:
  895. STATUS_SUCCESS - interface was unbound OK
  896. STATUS_UNSUCCESSFULL - interface does not exist
  897. --*/
  898. NTSTATUS
  899. DoUnbindInterface (
  900. IN ULONG InterfaceIndex
  901. ) {
  902. PINTERFACE_CB ifCB;
  903. ifCB = GetInterfaceReference (InterfaceIndex);
  904. if (ifCB!=NULL) {
  905. if (ifCB->ICB_InterfaceType==FWD_IF_PERMANENT)
  906. UnbindInterface (ifCB);
  907. ReleaseInterfaceReference (ifCB);
  908. return STATUS_SUCCESS;
  909. }
  910. else
  911. return STATUS_UNSUCCESSFUL;
  912. }
  913. /*++
  914. D o D i s a b l e I n t e r f a c e
  915. Routine Description:
  916. Disables all packet traffic through the interface
  917. Arguments:
  918. InterfaceIndex - index of interface to disable
  919. Return Value:
  920. STATUS_SUCCESS - interface was disabled OK
  921. STATUS_UNSUCCESSFULL - interface does not exist
  922. --*/
  923. NTSTATUS
  924. DoDisableInterface (
  925. IN ULONG InterfaceIndex
  926. ) {
  927. PINTERFACE_CB ifCB;
  928. ifCB = GetInterfaceReference (InterfaceIndex);
  929. if (ifCB!=NULL) {
  930. KIRQL oldIRQL;
  931. KeAcquireSpinLock (&ifCB->ICB_Lock, &oldIRQL);
  932. if (IS_IF_ENABLED (ifCB)) {
  933. SET_IF_DISABLED (ifCB);
  934. KeReleaseSpinLock (&ifCB->ICB_Lock, oldIRQL);
  935. if (InterfaceIndex!=FWD_INTERNAL_INTERFACE_INDEX) {
  936. ProcessInternalQueue (ifCB);
  937. ProcessExternalQueue (ifCB);
  938. }
  939. }
  940. else
  941. KeReleaseSpinLock (&ifCB->ICB_Lock, oldIRQL);
  942. ReleaseInterfaceReference (ifCB);
  943. return STATUS_SUCCESS;
  944. }
  945. else
  946. return STATUS_UNSUCCESSFUL;
  947. }
  948. /*++
  949. D o E n a b l e I n t e r f a c e
  950. Routine Description:
  951. Enables all packet traffic through the interface
  952. Arguments:
  953. InterfaceIndex - index of interface to enable
  954. Return Value:
  955. STATUS_SUCCESS - interface was disabled OK
  956. STATUS_UNSUCCESSFULL - interface does not exist
  957. --*/
  958. NTSTATUS
  959. DoEnableInterface (
  960. IN ULONG InterfaceIndex
  961. ) {
  962. PINTERFACE_CB ifCB;
  963. ifCB = GetInterfaceReference (InterfaceIndex);
  964. if (ifCB!=NULL) {
  965. SET_IF_ENABLED (ifCB);
  966. ReleaseInterfaceReference (ifCB);
  967. return STATUS_SUCCESS;
  968. }
  969. else
  970. return STATUS_UNSUCCESSFUL;
  971. }
  972. /*++
  973. I p x F w d C a n c e l
  974. Routine Description:
  975. Cancels specified IRP
  976. Arguments:
  977. DeviceObject - forwarder device object
  978. irp - irp to cancel
  979. Return Value:
  980. None
  981. --*/
  982. VOID
  983. IpxFwdCancel (
  984. IN PDEVICE_OBJECT DeviceObject,
  985. IN PIRP irp
  986. ) {
  987. RemoveEntryList (&irp->Tail.Overlay.ListEntry);
  988. IoReleaseCancelSpinLock (irp->CancelIrql);
  989. irp->IoStatus.Information = 0;
  990. irp->IoStatus.Status = STATUS_CANCELLED;
  991. IpxFwdDbgPrint(DBG_IOCTLS, DBG_WARNING, ("IpxFwd: completing cancelled irp.\n"));
  992. IoCompleteRequest(irp, IO_NO_INCREMENT);
  993. }
  994. /*++
  995. D o G e t P e r f C o u n t e r s
  996. Routine Description:
  997. Gets performance counters
  998. Arguments:
  999. perfParams - buffer ot pu counters into
  1000. Return Value:
  1001. STATUS_SUCCESS - counter were copied ok
  1002. STATUS_UNSUCCESSFULL - performance measurement were not enabled
  1003. --*/
  1004. NTSTATUS
  1005. DoGetPerfCounters (
  1006. OUT PFWD_PERFORMANCE_PARAMS perfParams,
  1007. OUT ULONG* pulSize
  1008. ) {
  1009. LONGLONG lTotalPacketProcessingTime;
  1010. LONGLONG lMaxPacketProcessingTime;
  1011. LONG lPacketCounter;
  1012. LONGLONG lTotalNbPacketProcessingTime;
  1013. LONGLONG lMaxNbPacketProcessingTime;
  1014. LONG lNbPacketCounter;
  1015. KIRQL oldIRQL;
  1016. if (!MeasuringPerformance)
  1017. return STATUS_UNSUCCESSFUL;
  1018. KeAcquireSpinLock (&PerfCounterLock, &oldIRQL);
  1019. *perfParams = PerfBlock;
  1020. memset (&PerfBlock, 0, sizeof (PerfBlock));
  1021. KeReleaseSpinLock (&PerfCounterLock, oldIRQL);
  1022. *pulSize = sizeof(PerfBlock);
  1023. return STATUS_SUCCESS;
  1024. }
  1025. BOOLEAN
  1026. DoLeaveForwarder (
  1027. VOID
  1028. ) {
  1029. return LeaveForwarder () != 0;
  1030. }