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.

1112 lines
30 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. receive.c
  5. Abstract:
  6. This module contains code which processes all read NCB's including
  7. both session and datagram based transfers.
  8. Author:
  9. Colin Watson (ColinW) 13-Mar-1991
  10. Environment:
  11. Kernel mode
  12. Revision History:
  13. --*/
  14. #include "nb.h"
  15. PDNCB
  16. FindReceive (
  17. IN PCB pcb
  18. );
  19. VOID
  20. ReturnDatagram(
  21. IN PAB pab,
  22. IN PVOID SourceAddress,
  23. IN PDNCB pdncb,
  24. IN BOOL MultipleReceive
  25. );
  26. NTSTATUS
  27. NbCompletionBroadcast(
  28. IN PDEVICE_OBJECT DeviceObject,
  29. IN PIRP Irp,
  30. IN PVOID Context
  31. );
  32. NTSTATUS
  33. NbReceive(
  34. IN PDNCB pdncb,
  35. IN PIRP Irp,
  36. IN PIO_STACK_LOCATION IrpSp,
  37. IN ULONG Buffer2Length,
  38. IN BOOLEAN Locked,
  39. IN KIRQL LockedIrql
  40. )
  41. /*++
  42. Routine Description:
  43. This routine is called to read a buffer of data.
  44. Arguments:
  45. pdncb - Pointer to the NCB.
  46. Irp - Pointer to the request packet representing the I/O request.
  47. IrpSp - Pointer to current IRP stack frame.
  48. Buffer2Length - Length of user provided buffer for data.
  49. Locked - TRUE if the spinlock is already held.
  50. LockedIrql - OldIrql if Locked == TRUE.
  51. Return Value:
  52. The function value is the status of the operation.
  53. --*/
  54. {
  55. PFCB pfcb = IrpSp->FileObject->FsContext2;
  56. PCB pcb;
  57. PPCB ppcb;
  58. NTSTATUS Status;
  59. KIRQL OldIrql; // Used when SpinLock held.
  60. if ( Locked != TRUE ) {
  61. LOCK( pfcb, OldIrql );
  62. } else {
  63. OldIrql = LockedIrql;
  64. }
  65. ppcb = FindCb( pfcb, pdncb, FALSE);
  66. pdncb->irp = Irp;
  67. pdncb->pfcb = pfcb;
  68. if ( ppcb == NULL ) {
  69. // FindCb has put the error in the NCB
  70. UNLOCK( pfcb, OldIrql );
  71. IF_NBDBG (NB_DEBUG_RECEIVE) {
  72. NbPrint(( "NB receive on invalid connection\n" ));
  73. }
  74. if ( pdncb->ncb_retcode == NRC_SCLOSED ) {
  75. // Tell dll to hangup the connection.
  76. return STATUS_HANGUP_REQUIRED;
  77. } else {
  78. return STATUS_SUCCESS;
  79. }
  80. }
  81. pcb = *ppcb;
  82. pdncb->tick_count = pcb->ReceiveTimeout;
  83. if ( (pcb->DeviceObject == NULL) || (pcb->ConnectionObject == NULL)) {
  84. UNLOCK( pfcb, OldIrql );
  85. NCB_COMPLETE( pdncb, NRC_SCLOSED );
  86. return STATUS_SUCCESS;
  87. }
  88. if ( pcb->ReceiveIndicated == 0 ) {
  89. IF_NBDBG (NB_DEBUG_RECEIVE) {
  90. NbPrint(( "NB receive, queue receive pcb: %lx, pdncb: %lx\n", pcb, pdncb ));
  91. }
  92. // Note: QueueRequest UNLOCKS the fcb.
  93. QueueRequest(&pcb->ReceiveList, pdncb, Irp, pfcb, OldIrql, FALSE);
  94. } else {
  95. PDEVICE_OBJECT DeviceObject;
  96. IF_NBDBG (NB_DEBUG_RECEIVE) {
  97. NbPrint(( "NB receive, submit receive pcb: %lx, pdncb: %lx\n", pcb, pdncb ));
  98. }
  99. IoMarkIrpPending( Irp );
  100. pcb->ReceiveIndicated = 0;
  101. TdiBuildReceive (Irp,
  102. pcb->DeviceObject,
  103. pcb->ConnectionObject,
  104. NbCompletionPDNCB,
  105. pdncb,
  106. Irp->MdlAddress,
  107. 0,
  108. Buffer2Length);
  109. // Save the DeviceObject before pcb gets released by UNLOCK
  110. DeviceObject = pcb->DeviceObject;
  111. UNLOCK( pfcb, OldIrql );
  112. IoCallDriver (DeviceObject, Irp);
  113. //
  114. // Transport will complete the request. Return pending so that
  115. // netbios does not complete as well.
  116. //
  117. }
  118. Status = STATUS_PENDING;
  119. IF_NBDBG (NB_DEBUG_RECEIVE) {
  120. NbPrint(( "\n NB receive: %X, %X\n", Status, Irp->IoStatus.Status ));
  121. }
  122. return Status;
  123. UNREFERENCED_PARAMETER( Buffer2Length );
  124. }
  125. NTSTATUS
  126. NbReceiveAny(
  127. IN PDNCB pdncb,
  128. IN PIRP Irp,
  129. IN PIO_STACK_LOCATION IrpSp,
  130. IN ULONG Buffer2Length
  131. )
  132. /*++
  133. Routine Description:
  134. This routine is called to read a buffer of data from any session on
  135. a particular address, provided there is not a read on that address
  136. already.
  137. Arguments:
  138. pdncb - Pointer to the NCB.
  139. Irp - Pointer to the request packet representing the I/O request.
  140. IrpSp - Pointer to current IRP stack frame.
  141. Buffer2Length - Length of user provided buffer for data.
  142. Return Value:
  143. The function value is the status of the operation.
  144. --*/
  145. {
  146. PFCB pfcb = IrpSp->FileObject->FsContext2;
  147. PPCB ppcb;
  148. PPAB ppab;
  149. KIRQL OldIrql; // Used when SpinLock held.
  150. LOCK( pfcb, OldIrql );
  151. ppab = FindAbUsingNum( pfcb, pdncb, pdncb->ncb_num );
  152. if ( ppab == NULL ) {
  153. UNLOCK( pfcb, OldIrql );
  154. IF_NBDBG (NB_DEBUG_RECEIVE) {
  155. NbPrint(( "NB receive any on invalid connection\n" ));
  156. }
  157. return STATUS_SUCCESS;
  158. }
  159. pdncb->irp = Irp;
  160. pdncb->pfcb = pfcb;
  161. //
  162. // If there is already a receive any on the address block then add
  163. // this request to the tail of the queue. If the list is empty then
  164. // look for a connection on this address flagged as having a receive
  165. // indicated. Either queue the request if there are no indications or
  166. // satisfy the indicated receive any with this request.
  167. //
  168. if ( !IsListEmpty( &(*ppab)->ReceiveAnyList )) {
  169. IF_NBDBG (NB_DEBUG_RECEIVE) {
  170. NbPrint(( "NB receive any with receive any list non empty\n" ));
  171. ppcb = FindReceiveIndicated( pfcb, pdncb, ppab );
  172. if ( ppcb != NULL ) {
  173. NbPrint(( " ppcb: %lx has a receive indicated( %lx )!\n",
  174. ppcb,
  175. (*ppcb)->ReceiveIndicated));
  176. ASSERT( FALSE );
  177. }
  178. }
  179. // Note: QueueRequest UNLOCKS the fcb.
  180. QueueRequest(&(*ppab)->ReceiveAnyList, pdncb, Irp, pfcb, OldIrql, FALSE);
  181. return STATUS_PENDING;
  182. }
  183. //
  184. // Find either a connection with a receive indicated or one that has been
  185. // disconnected but not reported yet.
  186. //
  187. ppcb = FindReceiveIndicated( pfcb, pdncb, ppab );
  188. if ( ppcb == NULL ) {
  189. // No connections with receive indications set.
  190. // Note: QueueRequest UNLOCKS the fcb.
  191. QueueRequest(&(*ppab)->ReceiveAnyList, pdncb, Irp, pfcb, OldIrql, FALSE);
  192. return STATUS_PENDING;
  193. } else {
  194. // FindReceiveIndicated has set the LSN appropriately in the NCB
  195. // Note : NbReceive will unlock the spinlock & resource
  196. return NbReceive( pdncb, Irp, IrpSp, Buffer2Length, TRUE, OldIrql );
  197. }
  198. }
  199. NTSTATUS
  200. NbTdiReceiveHandler (
  201. IN PVOID ReceiveEventContext,
  202. IN PVOID ConnectionContext,
  203. IN USHORT ReceiveFlags,
  204. IN ULONG BytesIndicated,
  205. IN ULONG BytesAvailable,
  206. OUT PULONG BytesTaken,
  207. IN PVOID Tsdu,
  208. OUT PIRP *IoRequestPacket
  209. )
  210. /*++
  211. Routine Description:
  212. This routine is the receive event indication handler.
  213. It is called when an NCB arrives from the network, it will look for a
  214. connection for this address with an appropriate read outstanding.
  215. The connection that has the read associated with it is indicated by the
  216. context parameter.
  217. If it finds an appropriate read it processes the NCB.
  218. Arguments:
  219. IN PVOID ReceiveEventContext - Context provided for this event - pab
  220. IN PVOID ConnectionContext - Connection Context - pcb
  221. IN USHORT ReceiveFlags - Flags describing the message
  222. IN ULONG BytesIndicated - Number of bytes available at indication time
  223. IN ULONG BytesAvailable - Number of bytes available to receive
  224. OUT PULONG BytesTaken - Number of bytes consumed by redirector.
  225. IN PVOID Tsdu - Data from remote machine.
  226. OUT PIRP *IoRequestPacket - I/O request packet filled in if received data
  227. Return Value:
  228. NTSTATUS - Status of receive operation
  229. --*/
  230. {
  231. KIRQL OldIrql; // Used when SpinLock held.
  232. PCB pcb = *(PPCB)ConnectionContext;
  233. PAB pab = *(pcb->ppab);
  234. PFCB pfcb = pab->pLana->pFcb;
  235. PDNCB pdncb;
  236. *IoRequestPacket = NULL;
  237. LOCK_SPINLOCK( pfcb, OldIrql );
  238. if (( pcb == NULL ) ||
  239. ( pcb->Status != SESSION_ESTABLISHED )) {
  240. //
  241. // The receive indication came in after we had an
  242. // allocation error on the Irp to be used for orderly disconnect.
  243. // If the Irp allocation fails then we should ignore receives
  244. // since we are in the process of putting down a ZwClose on this
  245. // connection.
  246. //
  247. UNLOCK_SPINLOCK( pfcb, OldIrql );
  248. return STATUS_DATA_NOT_ACCEPTED;
  249. }
  250. pdncb = FindReceive( pcb );
  251. if ( pdncb == NULL ) {
  252. pcb->ReceiveIndicated = 1;
  253. UNLOCK_SPINLOCK( pfcb, OldIrql );
  254. return STATUS_DATA_NOT_ACCEPTED;
  255. }
  256. pcb->ReceiveIndicated = 0;
  257. UNLOCK_SPINLOCK( pfcb, OldIrql );
  258. //
  259. // If this is the simple case where all the data required has been
  260. // indicated and it all fits in the buffer then copy the packet
  261. // contents directly into the users buffer rather than returning the
  262. // Irp. This should always be faster than returning an Irp to the
  263. // transport.
  264. //
  265. if (( BytesAvailable <= pdncb->ncb_length ) &&
  266. ( BytesAvailable == BytesIndicated ) &&
  267. ( ReceiveFlags & TDI_RECEIVE_ENTIRE_MESSAGE )) {
  268. PIRP Irp = pdncb->irp;
  269. if ( BytesAvailable != 0 ) {
  270. PUCHAR UsersBuffer = MmGetSystemAddressForMdlSafe(
  271. Irp->MdlAddress, NormalPagePriority);
  272. if (UsersBuffer == NULL) {
  273. pcb->ReceiveIndicated = 1;
  274. return STATUS_DATA_NOT_ACCEPTED;
  275. }
  276. TdiCopyLookaheadData(
  277. UsersBuffer,
  278. Tsdu,
  279. BytesAvailable,
  280. ReceiveFlags);
  281. }
  282. *BytesTaken = BytesAvailable;
  283. pdncb->ncb_length = (WORD)BytesAvailable;
  284. NCB_COMPLETE( pdncb, NRC_GOODRET );
  285. Irp->IoStatus.Information = FIELD_OFFSET( DNCB, ncb_cmd_cplt );
  286. NbCompleteRequest(Irp,STATUS_SUCCESS);
  287. return STATUS_SUCCESS;
  288. } else {
  289. TdiBuildReceive (pdncb->irp,
  290. pcb->DeviceObject,
  291. pcb->ConnectionObject,
  292. NbCompletionPDNCB,
  293. pdncb,
  294. pdncb->irp->MdlAddress,
  295. 0,
  296. pdncb->ncb_length);
  297. IoSetNextIrpStackLocation( pdncb->irp );
  298. *IoRequestPacket = pdncb->irp;
  299. return STATUS_MORE_PROCESSING_REQUIRED;
  300. }
  301. UNREFERENCED_PARAMETER( ReceiveEventContext );
  302. UNREFERENCED_PARAMETER( Tsdu );
  303. }
  304. PIRP
  305. BuildReceiveIrp (
  306. IN PCB pcb
  307. )
  308. /*++
  309. Routine Description:
  310. This routine is the receive event indication handler.
  311. It is called when an NCB arrives from the network and also when
  312. a receive completes with STATUS_BUFFER_OVERFLOW.
  313. If no Irp is available then this routine sets ReceiveIndicated so
  314. that the next appropriate receive will be passed to the transport.
  315. Arguments:
  316. IN PCB pcb - Supplies the connection which should put a receive Irp
  317. down if it has one available.
  318. Return Value:
  319. PDNCB to be satisfied by this receive request
  320. --*/
  321. {
  322. PDNCB pdncb = FindReceive( pcb );
  323. if ( pdncb == NULL ) {
  324. pcb->ReceiveIndicated = 1;
  325. return NULL;
  326. }
  327. TdiBuildReceive (pdncb->irp,
  328. pcb->DeviceObject,
  329. pcb->ConnectionObject,
  330. NbCompletionPDNCB,
  331. pdncb,
  332. pdncb->irp->MdlAddress,
  333. 0,
  334. pdncb->ncb_length);
  335. pcb->ReceiveIndicated = 0;
  336. return pdncb->irp;
  337. }
  338. PDNCB
  339. FindReceive (
  340. IN PCB pcb
  341. )
  342. /*++
  343. Routine Description:
  344. It is called when an NCB arrives from the network and also when
  345. a receive completes with STATUS_BUFFER_OVERFLOW.
  346. Arguments:
  347. IN PCB pcb - Supplies the connection which should put a receive Irp
  348. down if it has one available.
  349. Return Value:
  350. PDNCB to be satisfied by this receive request
  351. --*/
  352. {
  353. PAB pab;
  354. PFCB pfcb;
  355. PDNCB pdncb;
  356. pab = *(pcb->ppab);
  357. pfcb = pab->pLana->pFcb;
  358. IF_NBDBG (NB_DEBUG_RECEIVE) {
  359. NbPrint(( "NB receive handler pcb: %lx\n", pcb ));
  360. }
  361. ASSERT( pcb->Signature == CB_SIGNATURE );
  362. //
  363. // If there is a receive in the list then hand over the data.
  364. //
  365. if ( (pdncb = DequeueRequest( &pcb->ReceiveList)) != NULL ) {
  366. IF_NBDBG (NB_DEBUG_RECEIVE) {
  367. NbPrint(( "\n NB receive handler pcb: %lx, ncb: %lx\n", pcb, pdncb ));
  368. }
  369. return pdncb;
  370. }
  371. //
  372. // No receives on this connection. Is there a receive any for this
  373. // address?
  374. //
  375. ASSERT( pab != NULL );
  376. if ( (pdncb = DequeueRequest( &pab->ReceiveAnyList)) != NULL ) {
  377. IF_NBDBG (NB_DEBUG_RECEIVE) {
  378. NbPrint(( "\n NB receiveANY handler pcb: %lx, ncb: %lx\n", pcb, pdncb ));
  379. }
  380. pdncb->ncb_num = pab->NameNumber;
  381. pdncb->ncb_lsn = pcb->SessionNumber;
  382. return pdncb;
  383. }
  384. //
  385. // No receives on this connection. Is there a receive any for any
  386. // address on this adapter?
  387. //
  388. pab = pcb->Adapter->AddressBlocks[MAXIMUM_ADDRESS];
  389. ASSERT( pab != NULL );
  390. if ( (pdncb = DequeueRequest( &pab->ReceiveAnyList)) != NULL ) {
  391. IF_NBDBG (NB_DEBUG_RECEIVE) {
  392. NbPrint(( "\n NB receiveANYANY handler pcb: %lx, ncb: %lx\n", pcb, pdncb ));
  393. }
  394. pdncb->ncb_num = pab->NameNumber;
  395. pdncb->ncb_lsn = pcb->SessionNumber;
  396. return pdncb;
  397. }
  398. //
  399. // Transport will complete the processing of the request, we don't
  400. // want the data yet.
  401. //
  402. IF_NBDBG (NB_DEBUG_RECEIVE) {
  403. NbPrint(( "\n NB receive handler ignored receive, pcb: %lx\n", pcb ));
  404. }
  405. return NULL;
  406. }
  407. NTSTATUS
  408. NbReceiveDatagram(
  409. IN PDNCB pdncb,
  410. IN PIRP Irp,
  411. IN PIO_STACK_LOCATION IrpSp,
  412. IN ULONG Buffer2Length
  413. )
  414. /*++
  415. Routine Description:
  416. This routine is called to read a buffer of data.
  417. Arguments:
  418. pdncb - Pointer to the NCB.
  419. Irp - Pointer to the request packet representing the I/O request.
  420. IrpSp - Pointer to current IRP stack frame.
  421. Buffer2Length - Length of user provided buffer for data.
  422. Return Value:
  423. The function value is the status of the operation.
  424. --*/
  425. {
  426. PFCB pfcb = IrpSp->FileObject->FsContext2;
  427. NTSTATUS Status;
  428. PPAB ppab;
  429. KIRQL OldIrql; // Used when SpinLock held.
  430. LOCK( pfcb, OldIrql );
  431. pdncb->irp = Irp;
  432. pdncb->pfcb = pfcb;
  433. ppab = FindAbUsingNum( pfcb, pdncb, pdncb->ncb_num );
  434. if ( ppab == NULL ) {
  435. UNLOCK( pfcb, OldIrql );
  436. return STATUS_SUCCESS;
  437. }
  438. // Build the ReceiveInformation datastructure in the DNCB.
  439. if ( (pdncb->ncb_command & ~ASYNCH) == NCBDGRECVBC ) {
  440. //
  441. // Receive broadcast commands can be requested on any valid
  442. // name number but once accepted, they are treated seperately
  443. // from the name. To implement this, the driver queues the
  444. // receives on address 255.
  445. //
  446. ppab = FindAbUsingNum( pfcb, pdncb, MAXIMUM_ADDRESS );
  447. if ((ppab == NULL) || (pdncb->ncb_num == MAXIMUM_ADDRESS) ) {
  448. NCB_COMPLETE( pdncb, NRC_ILLNN );
  449. UNLOCK( pfcb, OldIrql );
  450. return STATUS_SUCCESS;
  451. }
  452. IF_NBDBG (NB_DEBUG_RECEIVE) {
  453. NbPrint(( "\n NB Bdatagram receive, queue ppab: %lx, pab: %lx, pdncb: %lx\n",
  454. ppab, (*ppab), pdncb ));
  455. }
  456. if ( (*ppab)->ReceiveDatagramRegistered == FALSE) {
  457. (*ppab)->ReceiveDatagramRegistered = TRUE;
  458. UNLOCK_SPINLOCK( pfcb, OldIrql);
  459. Status = NbSetEventHandler( (*ppab)->DeviceObject,
  460. (*ppab)->AddressObject,
  461. TDI_EVENT_RECEIVE_DATAGRAM,
  462. (PVOID)NbTdiDatagramHandler,
  463. (*ppab));
  464. if (Status != STATUS_SUCCESS)
  465. {
  466. return(Status);
  467. }
  468. LOCK_SPINLOCK( pfcb, OldIrql);
  469. }
  470. //
  471. // When one receive broadcast is received, we must satisfy all the receive
  472. // broadcasts. To do this, the largest receive is placed at the head of the queue.
  473. // When a datagram is received, this receive is given to the transport to fill in
  474. // with data. In the completion routine this driver propogates the same data to
  475. // the other receive datagram requests.
  476. //
  477. IoMarkIrpPending( Irp );
  478. if ( !IsListEmpty( &(*ppab)->ReceiveBroadcastDatagramList) ) {
  479. PDNCB pdncbHead = CONTAINING_RECORD( &(*ppab)->ReceiveBroadcastDatagramList.Flink , DNCB, ncb_next);
  480. if ( pdncb->ncb_length >= pdncbHead->ncb_length ) {
  481. IF_NBDBG (NB_DEBUG_RECEIVE) {
  482. NbPrint(( "\n NB Bdatagram receive, Head of queue ppab: %lx, pab: %lx, pdncb: %lx\n",
  483. ppab, (*ppab), pdncb ));
  484. }
  485. // Note: QueueRequest UNLOCKS the fcb.
  486. QueueRequest(&(*ppab)->ReceiveBroadcastDatagramList, pdncb, Irp, pfcb, OldIrql, TRUE);
  487. } else {
  488. IF_NBDBG (NB_DEBUG_RECEIVE) {
  489. NbPrint(( "\n NB Bdatagram receive, Tail of queue ppab: %lx, pab: %lx, pdncb: %lx\n",
  490. ppab, (*ppab), pdncb ));
  491. }
  492. QueueRequest(&(*ppab)->ReceiveBroadcastDatagramList, pdncb, Irp, pfcb, OldIrql, FALSE);
  493. }
  494. } else {
  495. IF_NBDBG (NB_DEBUG_RECEIVE) {
  496. NbPrint(( "\n NB Bdatagram receive, Tail2 of queue ppab: %lx, pab: %lx, pdncb: %lx\n",
  497. ppab, (*ppab), pdncb ));
  498. }
  499. QueueRequest(&(*ppab)->ReceiveBroadcastDatagramList, pdncb, Irp, pfcb, OldIrql, FALSE);
  500. }
  501. } else {
  502. IF_NBDBG (NB_DEBUG_RECEIVE) {
  503. NbPrint(( "\n NB datagram receive, queue ppab: %lx, pab: %lx, pdncb: %lx\n",
  504. ppab, (*ppab), pdncb ));
  505. }
  506. QueueRequest(&(*ppab)->ReceiveDatagramList, pdncb, Irp, pfcb, OldIrql, FALSE);
  507. }
  508. Status = STATUS_PENDING;
  509. IF_NBDBG (NB_DEBUG_RECEIVE) {
  510. NbPrint(( "\n NB datagram receive: %X, %X\n", Status, Irp->IoStatus.Status ));
  511. }
  512. return Status;
  513. UNREFERENCED_PARAMETER( Buffer2Length );
  514. }
  515. NTSTATUS
  516. NbTdiDatagramHandler(
  517. IN PVOID TdiEventContext, // the event context - pab
  518. IN int SourceAddressLength, // length of the originator of the datagram
  519. IN PVOID SourceAddress, // string describing the originator of the datagram
  520. IN int OptionsLength, // options for the receive
  521. IN PVOID Options, //
  522. IN ULONG ReceiveDatagramFlags, //
  523. IN ULONG BytesIndicated, // number of bytes this indication
  524. IN ULONG BytesAvailable, // number of bytes in complete Tsdu
  525. OUT ULONG *BytesTaken, // number of bytes used
  526. IN PVOID Tsdu, // pointer describing this TSDU, typically a lump of bytes
  527. OUT PIRP *IoRequestPacket // TdiReceive IRP if MORE_PROCESSING_REQUIRED.
  528. )
  529. /*++
  530. Routine Description:
  531. This routine is the receive datagram event indication handler.
  532. It is called when an NCB arrives from the network, it will look for a
  533. the address with an appropriate read datagram outstanding.
  534. The address that has the read associated with it is indicated by the
  535. context parameter.
  536. If it finds an appropriate read it processes the NCB.
  537. Arguments:
  538. IN PVOID TdiEventContext - Context provided for this event - pab
  539. IN int SourceAddressLength, // length of the originator of the datagram
  540. IN PVOID SourceAddress, // string describing the originator of the datagram
  541. IN int OptionsLength, // options for the receive
  542. IN PVOID Options, //
  543. IN ULONG BytesIndicated, // number of bytes this indication
  544. IN ULONG BytesAvailable, // number of bytes in complete Tsdu
  545. OUT ULONG *BytesTaken, // number of bytes used
  546. IN PVOID Tsdu, // pointer describing this TSDU, typically a lump of bytes
  547. OUT PIRP *IoRequestPacket // TdiReceive IRP if MORE_PROCESSING_REQUIRED.
  548. Return Value:
  549. NTSTATUS - Status of receive operation
  550. --*/
  551. {
  552. PAB pab = (PAB)TdiEventContext;
  553. PAB pab255;
  554. PDNCB pdncb;
  555. PFCB pfcb;
  556. KIRQL OldIrql; // Used when SpinLock held.
  557. pfcb = pab->pLana->pFcb;
  558. LOCK_SPINLOCK( pfcb, OldIrql );
  559. IF_NBDBG (NB_DEBUG_RECEIVE) {
  560. NbPrint(( "NB receive datagram handler pfcb: %lx, pab: %lx\n", pfcb, pab ));
  561. }
  562. *IoRequestPacket = NULL;
  563. ASSERT( pab->Signature == AB_SIGNATURE );
  564. // If its address 255 then we are receiving a broadcast datagram.
  565. if ( pab->NameNumber == MAXIMUM_ADDRESS ) {
  566. if ( (pdncb = DequeueRequest( &pab->ReceiveBroadcastDatagramList)) != NULL ) {
  567. ReturnDatagram(
  568. pab,
  569. SourceAddress,
  570. pdncb,
  571. !IsListEmpty( &pab->ReceiveBroadcastDatagramList));
  572. *IoRequestPacket = pdncb->irp;
  573. IoSetNextIrpStackLocation( pdncb->irp );
  574. UNLOCK_SPINLOCK( pfcb, OldIrql );
  575. return STATUS_MORE_PROCESSING_REQUIRED;
  576. }
  577. //
  578. // Transport will complete the processing of the request, we don't
  579. // want the datagram.
  580. //
  581. IF_NBDBG (NB_DEBUG_RECEIVE) {
  582. NbPrint(( "\n NB receive BD handler ignored receive, pab: %lx\n", pab ));
  583. }
  584. UNLOCK_SPINLOCK( pfcb, OldIrql );
  585. return STATUS_DATA_NOT_ACCEPTED;
  586. }
  587. //
  588. // Check the address block looking for a Receive Datagram.
  589. //
  590. if ( (pdncb = DequeueRequest( &pab->ReceiveDatagramList)) != NULL ) {
  591. ReturnDatagram(
  592. pab,
  593. SourceAddress,
  594. pdncb,
  595. FALSE);
  596. *IoRequestPacket = pdncb->irp;
  597. IoSetNextIrpStackLocation( pdncb->irp );
  598. UNLOCK_SPINLOCK( pfcb, OldIrql );
  599. return STATUS_MORE_PROCESSING_REQUIRED;
  600. }
  601. //
  602. // Check to see if there is a receive any datagram.
  603. //
  604. // look at the list on address 255.
  605. pab255 = pab->pLana->AddressBlocks[MAXIMUM_ADDRESS];
  606. if ( (pdncb = DequeueRequest( &pab255->ReceiveDatagramList)) != NULL ) {
  607. ReturnDatagram(
  608. pab255,
  609. SourceAddress,
  610. pdncb,
  611. FALSE);
  612. pdncb->ncb_num = pab->NameNumber;
  613. *IoRequestPacket = pdncb->irp;
  614. IoSetNextIrpStackLocation( pdncb->irp );
  615. UNLOCK_SPINLOCK( pfcb, OldIrql );
  616. return STATUS_MORE_PROCESSING_REQUIRED;
  617. }
  618. //
  619. // Transport will complete the processing of the request, we don't
  620. // want the datagram.
  621. //
  622. IF_NBDBG (NB_DEBUG_RECEIVE) {
  623. NbPrint(( "\n NB receive datagram handler ignored receive, pab: %lx\n", pab ));
  624. }
  625. UNLOCK_SPINLOCK( pfcb, OldIrql );
  626. return STATUS_DATA_NOT_ACCEPTED;
  627. UNREFERENCED_PARAMETER( SourceAddressLength );
  628. UNREFERENCED_PARAMETER( BytesIndicated );
  629. UNREFERENCED_PARAMETER( BytesAvailable );
  630. UNREFERENCED_PARAMETER( BytesTaken );
  631. UNREFERENCED_PARAMETER( Tsdu );
  632. UNREFERENCED_PARAMETER( OptionsLength );
  633. UNREFERENCED_PARAMETER( Options );
  634. UNREFERENCED_PARAMETER( ReceiveDatagramFlags );
  635. }
  636. VOID
  637. ReturnDatagram(
  638. IN PAB pab,
  639. IN PVOID SourceAddress,
  640. IN PDNCB pdncb,
  641. IN BOOL MultipleReceive
  642. )
  643. /*++
  644. Routine Description:
  645. This routine is used to provide the Irp for a receive datagram to
  646. the transport.
  647. Arguments:
  648. IN PAB pab - Supplies the address block associated with the NCB.
  649. IN PVOID SourceAddress - Supplies the sender of the datagram.
  650. IN PDNCB pdncb - Supplies the NCB to be satisfied.
  651. IN BOOL MultipleReceive - True if the special Receive Broadcast datagram completion
  652. handler is to be used.
  653. Return Value:
  654. none.
  655. --*/
  656. {
  657. PIRP Irp = pdncb->irp;
  658. PIO_COMPLETION_ROUTINE CompletionRoutine;
  659. IF_NBDBG (NB_DEBUG_RECEIVE) {
  660. NbPrint(( "\n NB BDatagramreceive handler pab: %lx, ncb: %lx\n",
  661. pab, pdncb ));
  662. }
  663. // Copy the name into the NCB for return to the application.
  664. RtlMoveMemory(
  665. pdncb->ncb_callname,
  666. ((PTA_NETBIOS_ADDRESS)SourceAddress)->Address[0].Address[0].NetbiosName,
  667. NCBNAMSZ
  668. );
  669. // Tell TDI we do not want to specify any filters.
  670. pdncb->Information.RemoteAddress = 0;
  671. pdncb->Information.RemoteAddressLength = 0;
  672. pdncb->Information.UserData = NULL;
  673. pdncb->Information.UserDataLength = 0;
  674. pdncb->Information.Options = NULL;
  675. pdncb->Information.OptionsLength = 0;
  676. // Tell TDI we do not want any more information on the remote name.
  677. pdncb->ReturnInformation.RemoteAddress = 0;
  678. pdncb->ReturnInformation.RemoteAddressLength = 0;
  679. pdncb->ReturnInformation.UserData = NULL;
  680. pdncb->ReturnInformation.UserDataLength = 0;
  681. pdncb->ReturnInformation.Options = NULL;
  682. pdncb->ReturnInformation.OptionsLength = 0;
  683. CompletionRoutine = ( MultipleReceive == FALSE ) ? NbCompletionPDNCB: NbCompletionBroadcast;
  684. ASSERT(Irp->MdlAddress != NULL);
  685. TdiBuildReceiveDatagram (Irp,
  686. pab->DeviceObject,
  687. pab->AddressObject,
  688. CompletionRoutine,
  689. pdncb,
  690. Irp->MdlAddress,
  691. pdncb->ncb_length,
  692. &pdncb->Information,
  693. &pdncb->ReturnInformation,
  694. 0);
  695. return;
  696. }
  697. NTSTATUS
  698. NbCompletionBroadcast(
  699. IN PDEVICE_OBJECT DeviceObject,
  700. IN PIRP Irp,
  701. IN PVOID Context
  702. )
  703. /*++
  704. Routine Description:
  705. This routine takes the completed datagram receive and copies the data in the buffer
  706. to all the other receive broadcast datagram requests.
  707. Arguments:
  708. DeviceObject - unused.
  709. Irp - Supplies Irp that the transport has finished processing.
  710. Context - Supplies the NCB associated with the Irp.
  711. Return Value:
  712. The final status from the operation (success or an exception).
  713. --*/
  714. {
  715. PDNCB pdncb = (PDNCB) Context;
  716. KIRQL OldIrql; // Used when SpinLock held.
  717. PUCHAR pData;
  718. UCHAR NcbStatus;
  719. PAB pab;
  720. PDNCB pdncbNext;
  721. IF_NBDBG (NB_DEBUG_COMPLETE) {
  722. NbPrint( ("NbCompletionBroadcast pdncb: %lx, Status: %X, Length %lx\n",
  723. Context,
  724. Irp->IoStatus.Status,
  725. Irp->IoStatus.Information ));
  726. }
  727. // Tell application how many bytes were transferred
  728. pdncb->ncb_length = (unsigned short)Irp->IoStatus.Information;
  729. if ( NT_SUCCESS(Irp->IoStatus.Status) ) {
  730. NcbStatus = NRC_GOODRET;
  731. } else {
  732. NcbStatus = NbMakeNbError( Irp->IoStatus.Status );
  733. }
  734. //
  735. // Tell IopCompleteRequest how much to copy back when the request
  736. // completes.
  737. //
  738. Irp->IoStatus.Information = FIELD_OFFSET( DNCB, ncb_cmd_cplt );
  739. pData = MmGetSystemAddressForMdlSafe (Irp->MdlAddress, NormalPagePriority);
  740. if (pData != NULL) {
  741. LOCK_SPINLOCK( pdncb->pfcb, OldIrql );
  742. pab = *(FindAbUsingNum( pdncb->pfcb, pdncb, MAXIMUM_ADDRESS ));
  743. //
  744. // For each request on the queue, copy the data, update the NCb and complete the IRP.
  745. //
  746. while ( (pdncbNext = DequeueRequest( &pab->ReceiveBroadcastDatagramList)) != NULL ) {
  747. PUCHAR pNextData;
  748. WORD Length;
  749. IF_NBDBG (NB_DEBUG_COMPLETE) {
  750. NbPrint( ("NbCompletionBroadcast pdncb: %lx, Length %lx\n",
  751. pdncbNext,
  752. Irp->IoStatus.Information ));
  753. }
  754. ASSERT(pdncbNext->irp->MdlAddress != NULL);
  755. if (pdncbNext->irp->MdlAddress != NULL ) {
  756. pNextData = MmGetSystemAddressForMdlSafe(
  757. pdncbNext->irp->MdlAddress, NormalPagePriority
  758. );
  759. }
  760. if ((pdncbNext->irp->MdlAddress == NULL) ||
  761. (pNextData == NULL)) {
  762. Length = 0;
  763. }
  764. else {
  765. Length = min( pdncb->ncb_length, pdncbNext->ncb_length);
  766. pdncbNext->ncb_length = Length;
  767. RtlMoveMemory( pNextData, pData, Length );
  768. }
  769. if (( Length != pdncb->ncb_length ) &&
  770. ( NcbStatus == NRC_GOODRET )) {
  771. if (Length == 0) {
  772. NCB_COMPLETE( pdncbNext, NRC_NORES );
  773. }
  774. else {
  775. NCB_COMPLETE( pdncbNext, NRC_INCOMP );
  776. }
  777. } else {
  778. NCB_COMPLETE( pdncbNext, NcbStatus );
  779. }
  780. pdncbNext->irp->IoStatus.Information = FIELD_OFFSET( DNCB, ncb_cmd_cplt );
  781. NbCompleteRequest(pdncbNext->irp, STATUS_SUCCESS );
  782. }
  783. UNLOCK_SPINLOCK( pdncb->pfcb, OldIrql );
  784. }
  785. NCB_COMPLETE( pdncb, NcbStatus );
  786. //
  787. // Must return a non-error status otherwise the IO system will not copy
  788. // back the NCB into the users buffer.
  789. //
  790. Irp->IoStatus.Status = STATUS_SUCCESS;
  791. return STATUS_SUCCESS;
  792. UNREFERENCED_PARAMETER( DeviceObject );
  793. }