TDI question

Hi,
I’m writing a TDI filter and having trouble sending the data back to the upper driver (AFD).
When calling the original AFD eventReceive I get STATUS_DATA_NOT_ACCEPTED. I did a search on all threads here and understood that I have to push the data in a pipe and wait for a TDI_RECEIVE from the upper driver in order to unblock me and signal me that I now can send more eventReceive.
My question is when and how can I start calling the original event handler ? I’m fullfilling the TDI request (with part of the data kept in the pipe) and the calling IoCompleteRequest and returning the irp->IoStatus.Status. Now, since I blocked the below driver (tcpip) by returning STATUS_DATA_NOT_ACCEPTED to its eventReceive calls it wont call me anymore (untill i free it with TDI_RECEIVE) so I have no one to wake me up and the flow is stopped.
I thinking about several solutions

  1. implement a timer which will file occasionally and see if there is something in the pipe and send it thru an eventReceive to the upper driver and then unlocking the lower driver by sending TDI_RECEIVE
  2. sending the remainder of the pipe content with a eventReceive ot the upper driver just after the call IoCompleteRequest (is it allowed ?)
    I 'll be happy to hear you suggestions as I’m sure few peoples had the same issues.
    Thanks
    Lior

No timers at all.

Your filter should have a notion of “current data portion”. When some new
incoming (from down) portion becomes current, AND if IndicationsBlocked flag
was not set - then you fire ClientEventReceive to AFD.
AFD’s outcomes:

  • failure. Tear the whole connection.
  • STATUS_MORE_PROCESSING_REQUIRED with an IRP. Just complete this IRP with
    the current data portion as usual TDI_RECEIVE. This can cause the current data
    portion to be consumed 100%, OK, this is well, you just continue without the
    current data portion.
  • STATUS_DATA_NOT_ACCEPTED. Internally, this is SO_RCVBUF overflow - AFD is
    the implementation of this buffer. In this case, you must set the
    IndicationsBlocked and do nothing more.

When TDI_RECEIVE arrives the usual way, not as OUT parameter from
ClientEventReceive:

  • you take the current data portion and complete the IRP off it. Also, you
    reset the IndicationsBlocked flag.

The last question is - what to do if the current data portion was fully
consumed by TDI_RECEIVE, we have no “current data portion” in the driver, but
we have the actual next data portion (in some queue or so)?

This means - take the next data portion and make it current, and, yes, fire
ClientEventReceive if not blocked. This must be done every time your current
data portion is 100% consumed and you have more data.

Some sample.

  • data portion 1 arrives
  • becomes current
  • ClientEventReceive is fired
  • AFD returns STATUS_MORE_PROCESSING_REQUIRED with an IRP
  • you move the data from the portion to the IRP, complete the IRP, and note
    that the whole data portion is consumed!
  • OK, you take data portion 2 from the queue (if any), it becomes current,
    and another ClientEventReceive is fired. Then the things go on.

Normally, AFD sends you large TDI_RECEIVE IRPs (much larger then your
indicated size, this is to allow TCP to implement the PSH semantics and PSH
timer), so, they have good chance of consuming all of your accumulated data.

I see no chances of stack-eating recursion here (TDI was designed by smart
guys who did ClientEventReceive properly). See the stack usage:
YourCode
YourCode calls ClientEventReceive
YourCode after return from ClientEventReceive with an IRP
YourCode fills and completes the IRP
YourCode moves to the next data portion
YourCode calls the second ClientEventReceive

So, no recursion. If AFD would send TDI_RECEIVE in a usual way from
ClientEventReceive - then this would be a problem. But ClientEventReceive is
smarter.


Maxim Shatskih, Windows DDK MVP
StorageCraft Corporation
xxxxx@storagecraft.com
http://www.storagecraft.com

wrote in message news:xxxxx@ntdev…
> Hi,
> I’m writing a TDI filter and having trouble sending the data back to the
upper driver (AFD).
> When calling the original AFD eventReceive I get STATUS_DATA_NOT_ACCEPTED. I
did a search on all threads here and understood that I have to push the data in
a pipe and wait for a TDI_RECEIVE from the upper driver in order to unblock me
and signal me that I now can send more eventReceive.
> My question is when and how can I start calling the original event handler ?
I’m fullfilling the TDI request (with part of the data kept in the pipe) and
the calling IoCompleteRequest and returning the irp->IoStatus.Status. Now,
since I blocked the below driver (tcpip) by returning STATUS_DATA_NOT_ACCEPTED
to its eventReceive calls it wont call me anymore (untill i free it with
TDI_RECEIVE) so I have no one to wake me up and the flow is stopped.
> I thinking about several solutions
> 1. implement a timer which will file occasionally and see if there is
something in the pipe and send it thru an eventReceive to the upper driver and
then unlocking the lower driver by sending TDI_RECEIVE
> 2. sending the remainder of the pipe content with a eventReceive ot the upper
driver just after the call IoCompleteRequest (is it allowed ?)
> I 'll be happy to hear you suggestions as I’m sure few peoples had the same
issues.
> Thanks
> Lior
>

Thanks you Maxim for the detailed answer which helped me a lot. I’m still not sure about how to unlock the transport driver (since I already sent it a DATA_NOT_ACCEPTED). Do I do it in the TDI_RECEIVE dispatch function (since it is there that I know that the upper client driver is unlocking) received from the upper driver ?
Doesn’t it pose race condition issues ?
suppose I send (in the TDI_RECEIVE) a TDI_RECEIVE to the lower driver, it might start to send receive events immediately, even before the IoCompleteRequest and so if my event receive handler forward the event to the upper driver, a later data might arrive before the earlier data (stuck in the TDI_RECEIVE IoComplete)
What do you think?
Thanks