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.

662 lines
17 KiB

  1. /*++
  2. Copyright (c) 1989, 1990, 1991 Microsoft Corporation
  3. Module Name:
  4. action.c
  5. Abstract:
  6. This module contains support for the TdiAction handler.
  7. Author:
  8. David Beaver (dbeaver) 2-July-1991
  9. Environment:
  10. Kernel mode
  11. Revision History:
  12. --*/
  13. #include "precomp.h"
  14. #pragma hdrstop
  15. typedef struct _QUERY_INDICATION {
  16. UCHAR Command;
  17. USHORT Data2;
  18. UCHAR DestinationName[16];
  19. UCHAR SourceName[16];
  20. } QUERY_INDICATION, *PQUERY_INDICATION;
  21. typedef struct _ACTION_QUERY_INDICATION {
  22. TDI_ACTION_HEADER Header;
  23. QUERY_INDICATION QueryIndication;
  24. } ACTION_QUERY_INDICATION, *PACTION_QUERY_INDICATION;
  25. typedef struct _DATAGRAM_INDICATION {
  26. UCHAR DestinationName[16];
  27. UCHAR SourceName[16];
  28. USHORT DatagramBufferLength;
  29. UCHAR DatagramBuffer[1];
  30. } DATAGRAM_INDICATION, *PDATAGRAM_INDICATION;
  31. typedef struct _ACTION_DATAGRAM_INDICATION {
  32. TDI_ACTION_HEADER Header;
  33. DATAGRAM_INDICATION DatagramIndication;
  34. } ACTION_DATAGRAM_INDICATION, *PACTION_DATAGRAM_INDICATION;
  35. #define QUERY_INDICATION_CODE 1
  36. #define DATAGRAM_INDICATION_CODE 2
  37. VOID
  38. NbfCancelAction(
  39. IN PDEVICE_OBJECT DeviceObject,
  40. IN PIRP Irp
  41. );
  42. NTSTATUS
  43. NbfTdiAction(
  44. IN PDEVICE_CONTEXT DeviceContext,
  45. IN PIRP Irp
  46. )
  47. /*++
  48. Routine Description:
  49. This routine performs the TdiAction request for the transport
  50. provider.
  51. Arguments:
  52. DeviceContext - The device context for the operation
  53. Irp - the Irp for the requested operation.
  54. Return Value:
  55. NTSTATUS - status of operation.
  56. --*/
  57. {
  58. NTSTATUS status;
  59. PIO_STACK_LOCATION irpSp;
  60. PTDI_ACTION_HEADER ActionHeader;
  61. LARGE_INTEGER timeout = {0,0};
  62. PTP_REQUEST tpRequest;
  63. KIRQL oldirql, cancelirql;
  64. ULONG BytesRequired;
  65. //
  66. // what type of status do we want?
  67. //
  68. irpSp = IoGetCurrentIrpStackLocation (Irp);
  69. if ((!Irp->MdlAddress) ||
  70. (MmGetMdlByteCount(Irp->MdlAddress) < sizeof(TDI_ACTION_HEADER))) {
  71. return STATUS_INVALID_PARAMETER;
  72. }
  73. ActionHeader = (PTDI_ACTION_HEADER)MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
  74. if (!ActionHeader) {
  75. return STATUS_INSUFFICIENT_RESOURCES;
  76. }
  77. //
  78. // Make sure we have required number of bytes for this type of request
  79. //
  80. switch (ActionHeader->ActionCode) {
  81. case QUERY_INDICATION_CODE:
  82. BytesRequired = sizeof(ACTION_QUERY_INDICATION);
  83. break;
  84. case DATAGRAM_INDICATION_CODE:
  85. BytesRequired = sizeof(ACTION_DATAGRAM_INDICATION);
  86. break;
  87. default:
  88. return STATUS_NOT_IMPLEMENTED;
  89. }
  90. if (MmGetMdlByteCount(Irp->MdlAddress) < BytesRequired) {
  91. return STATUS_INVALID_PARAMETER;
  92. }
  93. //
  94. // Here the request is one of QUERY_INDICATION or DATAGRAM_INDICATION
  95. //
  96. //
  97. // These two requests are sent by RAS to "MABF"
  98. //
  99. if (!RtlEqualMemory ((PVOID)(&ActionHeader->TransportId), "MABF", 4)) {
  100. return STATUS_NOT_SUPPORTED;
  101. }
  102. //
  103. // They should be sent on the control channel
  104. //
  105. if (irpSp->FileObject->FsContext2 != UlongToPtr(NBF_FILE_TYPE_CONTROL)) {
  106. return STATUS_NOT_SUPPORTED;
  107. }
  108. //
  109. // Create a request to describe this.
  110. //
  111. status = NbfCreateRequest (
  112. Irp, // IRP for this request.
  113. DeviceContext, // context.
  114. REQUEST_FLAGS_DC, // partial flags.
  115. Irp->MdlAddress,
  116. MmGetMdlByteCount(Irp->MdlAddress),
  117. timeout,
  118. &tpRequest);
  119. if (NT_SUCCESS (status)) {
  120. NbfReferenceDeviceContext ("Action", DeviceContext, DCREF_REQUEST);
  121. tpRequest->Owner = DeviceContextType;
  122. tpRequest->FrameContext = (USHORT)irpSp->FileObject->FsContext;
  123. IoAcquireCancelSpinLock(&cancelirql);
  124. ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock,&oldirql);
  125. //
  126. // Disallow these requests on a stopping device.
  127. //
  128. if (DeviceContext->State != DEVICECONTEXT_STATE_OPEN) {
  129. RELEASE_SPIN_LOCK (&DeviceContext->SpinLock,oldirql);
  130. IoReleaseCancelSpinLock(cancelirql);
  131. NbfCompleteRequest (tpRequest, STATUS_DEVICE_NOT_READY, 0);
  132. } else {
  133. if (ActionHeader->ActionCode == QUERY_INDICATION_CODE) {
  134. InsertTailList (
  135. &DeviceContext->QueryIndicationQueue,
  136. &tpRequest->Linkage);
  137. } else {
  138. InsertTailList (
  139. &DeviceContext->DatagramIndicationQueue,
  140. &tpRequest->Linkage);
  141. }
  142. DeviceContext->IndicationQueuesInUse = TRUE;
  143. //
  144. // If this IRP has been cancelled, then call the
  145. // cancel routine.
  146. //
  147. if (Irp->Cancel) {
  148. RELEASE_SPIN_LOCK (&DeviceContext->SpinLock,oldirql);
  149. Irp->CancelIrql = cancelirql;
  150. NbfCancelAction((PDEVICE_OBJECT)DeviceContext, Irp);
  151. return STATUS_PENDING;
  152. }
  153. IoSetCancelRoutine(Irp, NbfCancelAction);
  154. RELEASE_SPIN_LOCK (&DeviceContext->SpinLock,oldirql);
  155. IoReleaseCancelSpinLock(cancelirql);
  156. }
  157. status = STATUS_PENDING;
  158. }
  159. return status;
  160. }
  161. VOID
  162. NbfCancelAction(
  163. IN PDEVICE_OBJECT DeviceObject,
  164. IN PIRP Irp
  165. )
  166. /*++
  167. Routine Description:
  168. This routine is called by the I/O system to cancel an Action.
  169. What is done to cancel it is specific to each action.
  170. NOTE: This routine is called with the CancelSpinLock held and
  171. is responsible for releasing it.
  172. Arguments:
  173. DeviceObject - Pointer to the device object for this driver.
  174. Irp - Pointer to the request packet representing the I/O request.
  175. Return Value:
  176. none.
  177. --*/
  178. {
  179. KIRQL oldirql;
  180. PIO_STACK_LOCATION IrpSp;
  181. PTP_REQUEST Request;
  182. PLIST_ENTRY p;
  183. BOOLEAN Found;
  184. PTDI_ACTION_HEADER ActionHeader;
  185. PLIST_ENTRY QueueHead, QueueEnd;
  186. PDEVICE_CONTEXT DeviceContext = (PDEVICE_CONTEXT)DeviceObject;
  187. //
  188. // Get a pointer to the current stack location in the IRP. This is where
  189. // the function codes and parameters are stored.
  190. //
  191. IrpSp = IoGetCurrentIrpStackLocation (Irp);
  192. ASSERT ((IrpSp->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL) &&
  193. (IrpSp->MinorFunction == TDI_ACTION));
  194. ActionHeader = (PTDI_ACTION_HEADER)MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
  195. if (!ActionHeader) {
  196. return;
  197. }
  198. switch (ActionHeader->ActionCode) {
  199. case QUERY_INDICATION_CODE:
  200. case DATAGRAM_INDICATION_CODE:
  201. //
  202. // Scan through the appropriate queue, looking for this IRP.
  203. // If we find it, we just remove it from the queue; there
  204. // is nothing else involved in cancelling.
  205. //
  206. ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
  207. if (ActionHeader->ActionCode == QUERY_INDICATION_CODE) {
  208. QueueHead = DeviceContext->QueryIndicationQueue.Flink;
  209. QueueEnd = &DeviceContext->QueryIndicationQueue;
  210. } else {
  211. QueueHead = DeviceContext->DatagramIndicationQueue.Flink;
  212. QueueEnd = &DeviceContext->DatagramIndicationQueue;
  213. }
  214. Found = FALSE;
  215. for (p = QueueHead; p != QueueEnd; p = p->Flink) {
  216. Request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
  217. if (Request->IoRequestPacket == Irp) {
  218. //
  219. // Found it, remove it from the list here.
  220. //
  221. RemoveEntryList (p);
  222. Found = TRUE;
  223. break;
  224. }
  225. }
  226. RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
  227. IoReleaseCancelSpinLock (Irp->CancelIrql);
  228. if (Found) {
  229. NbfCompleteRequest (Request, STATUS_CANCELLED, 0);
  230. } else {
  231. #if DBG
  232. DbgPrint("NBF: Tried to cancel action %lx on %lx, not found\n",
  233. Irp, DeviceContext);
  234. #endif
  235. }
  236. break;
  237. default:
  238. IoReleaseCancelSpinLock (Irp->CancelIrql);
  239. break;
  240. }
  241. }
  242. VOID
  243. NbfStopControlChannel(
  244. IN PDEVICE_CONTEXT DeviceContext,
  245. IN USHORT ChannelIdentifier
  246. )
  247. /*++
  248. Routine Description:
  249. This routine is called when an MJ_CLEANUP IRP is received
  250. on a control channel. It walks the device context's list of
  251. pending action requests and cancels those associated with
  252. this channel (as identified by ChannelIdentifier.
  253. Arguments:
  254. DeviceContext - Pointer to our device context.
  255. ChannelIdentifier - The identifier for this open of the control
  256. channel, which is stored in Request->FrameContext for requests
  257. made on this channel.
  258. Return Value:
  259. None
  260. --*/
  261. {
  262. KIRQL oldirql, cancelirql;
  263. PTP_REQUEST Request;
  264. PLIST_ENTRY p;
  265. UINT i;
  266. BOOLEAN FoundRequest;
  267. PLIST_ENTRY QueueHead, QueueEnd;
  268. //
  269. // Scan both queues, looking for requests. Since the list
  270. // may change, we scan until we find one, then remove it
  271. // and complete it. We then start scanning at the beginning
  272. // again. We continue until we find none on the queue that
  273. // belong to this control channel.
  274. //
  275. // The outer loop only runs twice; the first time it
  276. // processes QueryIndicationQueue, the second time
  277. // DatagramIndicationQueue.
  278. //
  279. for (i = 0; i < 2; i++) {
  280. do {
  281. //
  282. // Loop until we do not find a request on this
  283. // pass through the queue.
  284. //
  285. FoundRequest = FALSE;
  286. IoAcquireCancelSpinLock(&cancelirql);
  287. ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
  288. if (i == 0) {
  289. QueueHead = DeviceContext->QueryIndicationQueue.Flink;
  290. QueueEnd = &DeviceContext->QueryIndicationQueue;
  291. } else {
  292. QueueHead = DeviceContext->DatagramIndicationQueue.Flink;
  293. QueueEnd = &DeviceContext->DatagramIndicationQueue;
  294. }
  295. //
  296. // Scan the appropriate queue for a request on this
  297. // channel.
  298. //
  299. for (p = QueueHead; p != QueueEnd; p = p->Flink) {
  300. Request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
  301. if (Request->FrameContext == ChannelIdentifier) {
  302. //
  303. // Found it, remove it from the list here.
  304. //
  305. IoSetCancelRoutine(Request->IoRequestPacket, NULL);
  306. RemoveEntryList (p);
  307. FoundRequest = TRUE;
  308. break;
  309. }
  310. }
  311. RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
  312. IoReleaseCancelSpinLock(cancelirql);
  313. //
  314. // If we found a request, then complete it and loop
  315. // back to the top of the while loop to rescan the
  316. // list. If not, then we will exit the while loop
  317. // now.
  318. //
  319. if (FoundRequest) {
  320. NbfCompleteRequest (Request, STATUS_CANCELLED, 0);
  321. }
  322. } while (FoundRequest);
  323. }
  324. }
  325. VOID
  326. NbfActionQueryIndication(
  327. IN PDEVICE_CONTEXT DeviceContext,
  328. IN PNBF_HDR_CONNECTIONLESS UiFrame
  329. )
  330. /*++
  331. Routine Description:
  332. This routine is called after a UI frame of type NAME_QUERY,
  333. ADD_NAME_QUERY, or ADD_GROUP_NAME_QUERY has been processed.
  334. It checks if there is a QUERY.INDICATION IRP waiting to
  335. be completed, and if so completes it.
  336. Arguments:
  337. DeviceContext - Pointer to our device context.
  338. UiFrame - Pointer to the incoming frame. The first byte of
  339. information is the first byte of the NetBIOS connectionless
  340. header.
  341. Return Value:
  342. None
  343. --*/
  344. {
  345. KIRQL oldirql, cancelirql;
  346. PTP_REQUEST Request;
  347. PLIST_ENTRY p;
  348. PMDL Mdl;
  349. PACTION_QUERY_INDICATION ActionHeader;
  350. PQUERY_INDICATION QueryIndication;
  351. IoAcquireCancelSpinLock (&cancelirql);
  352. ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
  353. if (!IsListEmpty (&DeviceContext->QueryIndicationQueue)) {
  354. p = RemoveHeadList (&DeviceContext->QueryIndicationQueue);
  355. RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
  356. Request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
  357. IoSetCancelRoutine(Request->IoRequestPacket,NULL);
  358. IoReleaseCancelSpinLock(cancelirql);
  359. Mdl = Request->Buffer2;
  360. ActionHeader = (PACTION_QUERY_INDICATION)
  361. (MmGetSystemAddressForMdl(Mdl));
  362. QueryIndication = &ActionHeader->QueryIndication;
  363. //
  364. // Copy over data from frame (note that dest and source
  365. // address are copied with one call).
  366. //
  367. QueryIndication->Command = UiFrame->Command;
  368. RtlCopyMemory ((PUCHAR)(&QueryIndication->Data2), (PUCHAR)(&UiFrame->Data2Low), 2);
  369. RtlCopyMemory ((PUCHAR)(QueryIndication->DestinationName),
  370. (PUCHAR)(UiFrame->DestinationName),
  371. 2 * NETBIOS_NAME_LENGTH);
  372. NbfCompleteRequest (Request, STATUS_SUCCESS, sizeof(ACTION_QUERY_INDICATION));
  373. } else {
  374. RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
  375. IoReleaseCancelSpinLock(cancelirql);
  376. }
  377. }
  378. VOID
  379. NbfActionDatagramIndication(
  380. IN PDEVICE_CONTEXT DeviceContext,
  381. IN PNBF_HDR_CONNECTIONLESS UiFrame,
  382. IN ULONG Length
  383. )
  384. /*++
  385. Routine Description:
  386. This routine is called after a datagram frame has been
  387. received. It checks if there is a DATAGRAM.INDICATION IRP
  388. waiting to be completed, and if so completes it.
  389. Arguments:
  390. DeviceContext - Pointer to our device context.
  391. UiFrame - Pointer to the incoming frame. The first byte of
  392. information is the first byte of the NetBIOS connectionless
  393. header.
  394. Length - The length of the frame starting at UiFrame.
  395. Return Value:
  396. None
  397. --*/
  398. {
  399. KIRQL oldirql, cancelirql;
  400. PTP_REQUEST Request;
  401. PLIST_ENTRY p;
  402. PACTION_DATAGRAM_INDICATION ActionHeader;
  403. PDATAGRAM_INDICATION DatagramIndication;
  404. ULONG CopyLength;
  405. PMDL Mdl;
  406. NTSTATUS Status;
  407. IoAcquireCancelSpinLock (&cancelirql);
  408. ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
  409. if (!IsListEmpty (&DeviceContext->DatagramIndicationQueue)) {
  410. p = RemoveHeadList (&DeviceContext->DatagramIndicationQueue);
  411. RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
  412. Request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
  413. IoSetCancelRoutine(Request->IoRequestPacket, NULL);
  414. IoReleaseCancelSpinLock(cancelirql);
  415. Mdl = Request->Buffer2;
  416. ActionHeader = (PACTION_DATAGRAM_INDICATION)
  417. (MmGetSystemAddressForMdl(Mdl));
  418. DatagramIndication = &ActionHeader->DatagramIndication;
  419. //
  420. // Copy over data from frame (note that dest and source
  421. // address are copied with one call).
  422. //
  423. RtlCopyMemory ((PUCHAR)(DatagramIndication->DestinationName),
  424. (PUCHAR)(UiFrame->DestinationName),
  425. 2 * NETBIOS_NAME_LENGTH);
  426. if ((Length-sizeof(NBF_HDR_CONNECTIONLESS)) <=
  427. (ULONG)DatagramIndication->DatagramBufferLength) {
  428. CopyLength = Length - sizeof(NBF_HDR_CONNECTIONLESS);
  429. Status = STATUS_SUCCESS;
  430. } else {
  431. CopyLength = DatagramIndication->DatagramBufferLength;
  432. Status = STATUS_BUFFER_OVERFLOW;
  433. }
  434. RtlCopyMemory(
  435. (PUCHAR)DatagramIndication->DatagramBuffer,
  436. ((PUCHAR)UiFrame) + sizeof(NBF_HDR_CONNECTIONLESS),
  437. CopyLength);
  438. DatagramIndication->DatagramBufferLength = (USHORT)CopyLength;
  439. NbfCompleteRequest (Request, Status, CopyLength +
  440. FIELD_OFFSET (ACTION_DATAGRAM_INDICATION, DatagramIndication.DatagramBuffer[0]));
  441. } else {
  442. RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
  443. IoReleaseCancelSpinLock(cancelirql);
  444. }
  445. }