Hello,

I can save IRP requests, and complete/cancel them later successfully.
But I want to queue events, set by TDI_SET_EVENT_HANDLER as well.

Could anybody clarify how this can be done?

Thanks!

Best regards,
Serge.

TDI driver event queueing by Steve

Steve
Tue Feb 08 20:25:23 CST 2005

Firstly, you will need to filter the events. With
filtering in place, when an event is triggered on an
address object your event filter function will get
called, and then you can call the original event
function, either immediately, or later if you are
queueing.

To setup filtering events you must first filter the
handler for TDI_SET_EVENT_HANDLER (as you filter any
other IRP). A client that wants to register an event
will send a TDI_SET_EVENT_HANDLER irp for a particular
address object. This irp will contain an event type,
handler and context. Here you patch in your handler (and
context) and store away the original handler and
context. You will need the original values so that when
your event handler is called, you can then call the
original handler. A typical way to store the
originalvalues is to store them in your own event context.

Here is an example handler for TDI_SET_EVENT_HANDLER ...

typedef struct
{
PFILE_OBJECT fileobj; // address object
PVOID oldEventHandler;
PVOID oldEventContext;

} EventContext;


// ------------------------------------------------------
----------------------
void SetEventHandler(PIRP irp, PIO_STACK_LOCATION irps)
{
PTDI_REQUEST_KERNEL_SET_EVENT event =
(PTDI_REQUEST_KERNEL_SET_EVENT)&irps->Parameters;
EventContext *filteredCtx;

filteredCtx = ExAllocatePool(NonPagedPool, sizeof
(TDI_EVENT_CONTEXT));

// store original (client supplied) data
//
filteredCtx->fileobj = irps->FileObject; // address
object
filteredCtx->oldEventHandler = event->EventHandler;
filteredCtx->oldEventContext = event->EventContext;

// patch in our data
//
event->EventHandler = filteredEventHandler; // this
must point to a function
// that
has the same definition
// as the
event function you are
//
filtering
event->EventContext = filteredCtx;

// now send IRP on down to lower driver ...
}

If you need more help email me.
Steve.

>-----Original Message-----
>Hello,
>
>I can save IRP requests, and complete/cancel them later
successfully.
>But I want to queue events, set by TDI_SET_EVENT_HANDLER
as well.
>
>Could anybody clarify how this can be done?
>
>Thanks!
>
>Best regards,
>Serge.
>
>
>.
>

Re: TDI driver event queueing by serge

serge
Wed Feb 09 10:13:27 CST 2005

Hello, Steve!

Thanks for the reply.
There are several moments that are not crear for me.
Almost all event callback functions have pointers as input parameters.
Do they point to static memory? Can I simply store pointers, or I must
allocate memory and copy original one?

Can you clarify the following:

//
// the callback function set via TDI_SET_EVENT_HANDLER
//
NTSTATUS tdi_event_receive_datagram(
//
// ** I do not know memory size pointed by TdiEventContext
IN PVOID TdiEventContext,
IN LONG SourceAddressLength,
IN PVOID SourceAddress,
IN LONG OptionsLength,
IN PVOID Options,
IN ULONG ReceiveDatagramFlags,
IN ULONG BytesIndicated,
IN ULONG BytesAvailable,
//
// ** does it point to static variable?
OUT ULONG *BytesTaken,
//
// ** memory size pointed by Tsdu is unknown?
IN PVOID Tsdu,
//
// ** do I need to store the pointer or the value?
OUT PIRP *IoRequestPacket)
{

// adding to queue all the input parameters;


//
// what value should I return exactly?
//
return STATUS_PENDING;
}


void MyThread()
{
// here I will call old original event handler
// with parameters previously stored in queue.
// and then release allocated memory.
}

Best regards,
Serge.



You wrote on Tue, 8 Feb 2005 18:25:23 -0800:

S> Firstly, you will need to filter the events. With
S> filtering in place, when an event is triggered on an
S> address object your event filter function will get
S> called, and then you can call the original event
S> function, either immediately, or later if you are
S> queueing.

S> To setup filtering events you must first filter the
S> handler for TDI_SET_EVENT_HANDLER (as you filter any
S> other IRP). A client that wants to register an event
S> will send a TDI_SET_EVENT_HANDLER irp for a particular
S> address object. This irp will contain an event type,
S> handler and context. Here you patch in your handler (and
S> context) and store away the original handler and
S> context. You will need the original values so that when
S> your event handler is called, you can then call the
S> original handler. A typical way to store the
S> originalvalues is to store them in your own event context.

S> Here is an example handler for TDI_SET_EVENT_HANDLER ...

S> typedef struct
S> {
S> PFILE_OBJECT fileobj; // address object
S> PVOID oldEventHandler;
S> PVOID oldEventContext;

S> } EventContext;

S> // ------------------------------------------------------
S> ----------------------
S> void SetEventHandler(PIRP irp, PIO_STACK_LOCATION irps)
S> {
S> PTDI_REQUEST_KERNEL_SET_EVENT event =
S> (PTDI_REQUEST_KERNEL_SET_EVENT)&irps->Parameters;
S> EventContext *filteredCtx;

S> filteredCtx = ExAllocatePool(NonPagedPool, sizeof
S> (TDI_EVENT_CONTEXT));

S> // store original (client supplied) data
S> //
S> filteredCtx->fileobj = irps->FileObject; // address
S> object
S> filteredCtx->oldEventHandler = event->EventHandler;
S> filteredCtx->oldEventContext = event->EventContext;

S> // patch in our data
S> //
S> event->EventHandler = filteredEventHandler; // this
S> must point to a function
S> // that
S> has the same definition
S> // as the
S> event function you are
S> //
S> filtering
S> event->EventContext = filteredCtx;

S> // now send IRP on down to lower driver ...
S> }

S> If you need more help email me.
S> Steve.

>> -----Original Message-----
>> Hello,
>>
>> I can save IRP requests, and complete/cancel them later
S> successfully.
>> But I want to queue events, set by TDI_SET_EVENT_HANDLER
S> as well.
>>
>> Could anybody clarify how this can be done?
>>
>> Thanks!
>>
>> Best regards,
>> Serge.
>>
>> .
>>

With best regards, serge. E-mail: pserge77@ukr.net



Re: TDI driver event queueing by Steve

Steve
Wed Feb 09 18:27:47 CST 2005

TdiEventContext is the context that you supplied in the
filter function for TDI_SET_EVENT_HANDLER. If you look at
the example I gave you TdiEventContext is ...
EventContext *filteredCtx;

You use this value to get back the original context and
handler. If you call the original handler within your
filtered handler your code will look something like
this ...

EventContext *ctx = (EventContext*)TdiEventContext;

// call old handler with old context
//
return ((PTDI_IND_RECEIVE_DATAGRAM)(ctx->oldEventHandler))
(ctx->oldEventContext,
SourceAddressLength,
SourceAddress,
OptionsLength,
Options,
ReceiveDatagramFlags,
BytesIndicated,
BytesAvailable,
BytesTaken,
Tsdu,
IoRequestPacket);

I recommend that you firstly get the code working without
queueing (i.e. call the original handler immediately in
your filtered handler) ... this way you can ensure your
filters are working correctly. Move on to queueing
after ... this is something I have not tried so you will
have to work that out. The help on
ClientEventReceiveDatagram should answer most of your
other questions.

There is a great example tdi firewall called tdi_fw that
you should try to download
http://sourceforge.net/projects/tdifw.

ps. you might have noticed there is a small bug in the
example ...
filteredCtx = ExAllocatePool(NonPagedPool, sizeof
(TDI_EVENT_CONTEXT));

This should be ...
filteredCtx = ExAllocatePool(NonPagedPool, sizeof
(EventContext));

Steve



>-----Original Message-----
>Hello, Steve!
>
>Thanks for the reply.
>There are several moments that are not crear for me.
>Almost all event callback functions have pointers as
input parameters.
>Do they point to static memory? Can I simply store
pointers, or I must
>allocate memory and copy original one?
>
>Can you clarify the following:
>
>//
>// the callback function set via TDI_SET_EVENT_HANDLER
>//
>NTSTATUS tdi_event_receive_datagram(
> //
> // ** I do not know memory size pointed by
TdiEventContext
> IN PVOID TdiEventContext,
> IN LONG SourceAddressLength,
> IN PVOID SourceAddress,
> IN LONG OptionsLength,
> IN PVOID Options,
> IN ULONG ReceiveDatagramFlags,
> IN ULONG BytesIndicated,
> IN ULONG BytesAvailable,
> //
> // ** does it point to static variable?
> OUT ULONG *BytesTaken,
> //
> // ** memory size pointed by Tsdu is unknown?
> IN PVOID Tsdu,
> //
> // ** do I need to store the pointer or the value?
> OUT PIRP *IoRequestPacket)
>{
>
> // adding to queue all the input parameters;
>
>
> //
> // what value should I return exactly?
> //
> return STATUS_PENDING;
>}
>
>
>void MyThread()
>{
> // here I will call old original event handler
> // with parameters previously stored in queue.
> // and then release allocated memory.
>}
>
>Best regards,
>Serge.
>
>
>
>You wrote on Tue, 8 Feb 2005 18:25:23 -0800:
>
> S> Firstly, you will need to filter the events. With
> S> filtering in place, when an event is triggered on an
> S> address object your event filter function will get
> S> called, and then you can call the original event
> S> function, either immediately, or later if you are
> S> queueing.
>
> S> To setup filtering events you must first filter the
> S> handler for TDI_SET_EVENT_HANDLER (as you filter any
> S> other IRP). A client that wants to register an event
> S> will send a TDI_SET_EVENT_HANDLER irp for a
particular
> S> address object. This irp will contain an event type,
> S> handler and context. Here you patch in your handler
(and
> S> context) and store away the original handler and
> S> context. You will need the original values so that
when
> S> your event handler is called, you can then call the
> S> original handler. A typical way to store the
> S> originalvalues is to store them in your own event
context.
>
> S> Here is an example handler for
TDI_SET_EVENT_HANDLER ...
>
> S> typedef struct
> S> {
> S> PFILE_OBJECT fileobj; // address object
> S> PVOID oldEventHandler;
> S> PVOID oldEventContext;
>
> S> } EventContext;
>
> S> // -------------------------------------------------
-----
> S> ----------------------
> S> void SetEventHandler(PIRP irp, PIO_STACK_LOCATION
irps)
> S> {
> S> PTDI_REQUEST_KERNEL_SET_EVENT event =
> S> (PTDI_REQUEST_KERNEL_SET_EVENT)&irps->Parameters;
> S> EventContext *filteredCtx;
>
> S> filteredCtx = ExAllocatePool(NonPagedPool, sizeof
> S> (TDI_EVENT_CONTEXT));
>
> S> // store original (client supplied) data
> S> //
> S> filteredCtx->fileobj = irps->FileObject; //
address
> S> object
> S> filteredCtx->oldEventHandler = event->EventHandler;
> S> filteredCtx->oldEventContext = event->EventContext;
>
> S> // patch in our data
> S> //
> S> event->EventHandler = filteredEventHandler; //
this
> S> must point to a function
> S> //
that
> S> has the same definition
> S> // as
the
> S> event function you are
> S> //
> S> filtering
> S> event->EventContext = filteredCtx;
>
> S> // now send IRP on down to lower driver ...
> S> }
>
> S> If you need more help email me.
> S> Steve.
>
> >> -----Original Message-----
> >> Hello,
> >>
> >> I can save IRP requests, and complete/cancel them
later
> S> successfully.
> >> But I want to queue events, set by
TDI_SET_EVENT_HANDLER
> S> as well.
> >>
> >> Could anybody clarify how this can be done?
> >>
> >> Thanks!
> >>
> >> Best regards,
> >> Serge.
> >>
> >> .
> >>
>
>With best regards, serge. E-mail: pserge77@ukr.net
>
>
>.
>

Re: TDI driver event queueing by serge

serge
Wed Feb 09 19:15:11 CST 2005

Hello, Steve!

I already created transparent TDI driver that filters all the events and
requests, so now I am moving towards queueing. Yes, I have seen tdi_fw
sources, thay are great as a start point.

I can not understand one thing:
When kernel-mode client sends event to my TDI driver, does it want to get
reply immediately?
I can save input variables, and then call original event handler in my
worker thread, but what about output variables?

In our example parameters BytesTaken and IoRequestPacket are output one.
Can I save these pointers and use them in my thread later?
Are these variables located in static memory?
I afraid I will receive BSOD when I try to write there something there from
my thread...

Best regards,
Serge.



You wrote on Wed, 9 Feb 2005 16:27:47 -0800:

S> TdiEventContext is the context that you supplied in the
S> filter function for TDI_SET_EVENT_HANDLER. If you look at
S> the example I gave you TdiEventContext is ...
S> EventContext *filteredCtx;

S> You use this value to get back the original context and
S> handler. If you call the original handler within your
S> filtered handler your code will look something like
S> this ...

S> EventContext *ctx = (EventContext*)TdiEventContext;

S> // call old handler with old context
S> //
S> return ((PTDI_IND_RECEIVE_DATAGRAM)(ctx->oldEventHandler))
S> (ctx->oldEventContext,
S> SourceAddressLength,
S> SourceAddress,
S> OptionsLength,
S> Options,
S> ReceiveDatagramFlags,
S> BytesIndicated,
S> BytesAvailable,
S> BytesTaken,
S> Tsdu,
S> IoRequestPacket);

S> I recommend that you firstly get the code working without
S> queueing (i.e. call the original handler immediately in
S> your filtered handler) ... this way you can ensure your
S> filters are working correctly. Move on to queueing
S> after ... this is something I have not tried so you will
S> have to work that out. The help on
S> ClientEventReceiveDatagram should answer most of your
S> other questions.

S> There is a great example tdi firewall called tdi_fw that
S> you should try to download
S> http://sourceforge.net/projects/tdifw.

S> ps. you might have noticed there is a small bug in the
S> example ...
S> filteredCtx = ExAllocatePool(NonPagedPool, sizeof
S> (TDI_EVENT_CONTEXT));

S> This should be ...
S> filteredCtx = ExAllocatePool(NonPagedPool, sizeof
S> (EventContext));

S> Steve

>> -----Original Message-----
>> Hello, Steve!
>>
>> Thanks for the reply.
>> There are several moments that are not crear for me.
>> Almost all event callback functions have pointers as
S> input parameters.
>> Do they point to static memory? Can I simply store
S> pointers, or I must
>> allocate memory and copy original one?
>>
>> Can you clarify the following:
>>
>> //
>> // the callback function set via TDI_SET_EVENT_HANDLER
>> //
>> NTSTATUS tdi_event_receive_datagram(
>> //
>> // ** I do not know memory size pointed by
S> TdiEventContext
>> IN PVOID TdiEventContext,
>> IN LONG SourceAddressLength,
>> IN PVOID SourceAddress,
>> IN LONG OptionsLength,
>> IN PVOID Options,
>> IN ULONG ReceiveDatagramFlags,
>> IN ULONG BytesIndicated,
>> IN ULONG BytesAvailable,
>> //
>> // ** does it point to static variable?
>> OUT ULONG *BytesTaken,
>> //
>> // ** memory size pointed by Tsdu is unknown?
>> IN PVOID Tsdu,
>> //
>> // ** do I need to store the pointer or the value?
>> OUT PIRP *IoRequestPacket)
>> {
>>
>> // adding to queue all the input parameters;
>>
>> //
>> // what value should I return exactly?
>> //
>> return STATUS_PENDING;
>> }
>>
>> void MyThread()
>> {
>> // here I will call old original event handler
>> // with parameters previously stored in queue.
>> // and then release allocated memory.
>> }
>>
>> Best regards,
>> Serge.
>>
>> You wrote on Tue, 8 Feb 2005 18:25:23 -0800:
>>
S>>> Firstly, you will need to filter the events. With
S>>> filtering in place, when an event is triggered on an
S>>> address object your event filter function will get
S>>> called, and then you can call the original event
S>>> function, either immediately, or later if you are
S>>> queueing.
>>
S>>> To setup filtering events you must first filter the
S>>> handler for TDI_SET_EVENT_HANDLER (as you filter any
S>>> other IRP). A client that wants to register an event
S>>> will send a TDI_SET_EVENT_HANDLER irp for a
S> particular
S>>> address object. This irp will contain an event type,
S>>> handler and context. Here you patch in your handler
S> (and
S>>> context) and store away the original handler and
S>>> context. You will need the original values so that
S> when
S>>> your event handler is called, you can then call the
S>>> original handler. A typical way to store the
S>>> originalvalues is to store them in your own event
S> context.
>>
S>>> Here is an example handler for
S> TDI_SET_EVENT_HANDLER ...
>>
S>>> typedef struct
S>>> {
S>>> PFILE_OBJECT fileobj; // address object
S>>> PVOID oldEventHandler;
S>>> PVOID oldEventContext;
>>
S>>> } EventContext;
>>
S>>> // -------------------------------------------------
S> -----
S>>> ----------------------
S>>> void SetEventHandler(PIRP irp, PIO_STACK_LOCATION
S> irps)
S>>> {
S>>> PTDI_REQUEST_KERNEL_SET_EVENT event =
S>>> (PTDI_REQUEST_KERNEL_SET_EVENT)&irps->Parameters;
S>>> EventContext *filteredCtx;
>>
S>>> filteredCtx = ExAllocatePool(NonPagedPool, sizeof
S>>> (TDI_EVENT_CONTEXT));
>>
S>>> // store original (client supplied) data
S>>> //
S>>> filteredCtx->fileobj = irps->FileObject; //
S> address
S>>> object
S>>> filteredCtx->oldEventHandler = event->EventHandler;
S>>> filteredCtx->oldEventContext = event->EventContext;
>>
S>>> // patch in our data
S>>> //
S>>> event->EventHandler = filteredEventHandler; //
S> this
S>>> must point to a function
S>>> //
S> that
S>>> has the same definition
S>>> // as
S> the
S>>> event function you are
S>>> //
S>>> filtering
S>>> event->EventContext = filteredCtx;
>>
S>>> // now send IRP on down to lower driver ...
S>>> }
>>
S>>> If you need more help email me.
S>>> Steve.
>>
>>>> -----Original Message-----
>>>> Hello,
>>>>
>>>> I can save IRP requests, and complete/cancel them
S> later
S>>> successfully.
>>>> But I want to queue events, set by
S> TDI_SET_EVENT_HANDLER
S>>> as well.
>>>>
>>>> Could anybody clarify how this can be done?
>>>>
>>>> Thanks!
>>>>
>>>> Best regards,
>>>> Serge.



Re: TDI driver event queueing by Steve

Steve
Wed Feb 09 19:49:32 CST 2005

Firstly, your event is called by tcpip (when the event
occurrs) not by the kernel-mode client. You call the
kernel-mode client when you call the original handler
(which is the clients handler).

As for the BytesTaken and IoRequestPacket I am not sure
how you can deal with them. They are pointers to
variables that belong to tcpip. The client in its event
handler would read the data received and inform tcpip how
much it read in BytesTaken. Also, the client might
allocate an irp for IoRequestPacket, this irp would be
set up to receive any more available data. What you are
attempting to do is very difficult. If your filter does
nothing with BytesTaken and IoRequestPacket tcpip will
assume that the client is not interested in the received
data! You will have to process this event as if you were
the client, i.e. read all data and set BytesTaken, and
create irp for IoRequestPacket. This gets even trickier
because then you will be responsible for this irp - you
will need to register a completion routine for it, etc.

When you dequeue and call the original client handler you
will have to look and behave like tcpip, i.e. process any
irp the client gives you in IoRequestPacket (i.e. copy
data from the irp your filter created).

Filtering in the tdi is very complicated, as you are
finding. You are the middle man, to the client you must
look and act like tcpip, to tcpip you must look and act
like the client. Have you considered using an NDIS IM
driver and queueing packets instead?

Steve.

>-----Original Message-----
>Hello, Steve!
>
>I already created transparent TDI driver that filters
all the events and
>requests, so now I am moving towards queueing. Yes, I
have seen tdi_fw
>sources, thay are great as a start point.
>
>I can not understand one thing:
>When kernel-mode client sends event to my TDI driver,
does it want to get
>reply immediately?
>I can save input variables, and then call original event
handler in my
>worker thread, but what about output variables?
>
>In our example parameters BytesTaken and IoRequestPacket
are output one.
>Can I save these pointers and use them in my thread
later?
>Are these variables located in static memory?
>I afraid I will receive BSOD when I try to write there
something there from
>my thread...
>
>Best regards,
>Serge.
>
>
>
>You wrote on Wed, 9 Feb 2005 16:27:47 -0800:
>
> S> TdiEventContext is the context that you supplied in
the
> S> filter function for TDI_SET_EVENT_HANDLER. If you
look at
> S> the example I gave you TdiEventContext is ...
> S> EventContext *filteredCtx;
>
> S> You use this value to get back the original context
and
> S> handler. If you call the original handler within
your
> S> filtered handler your code will look something like
> S> this ...
>
> S> EventContext *ctx = (EventContext*)TdiEventContext;
>
> S> // call old handler with old context
> S> //
> S> return ((PTDI_IND_RECEIVE_DATAGRAM)(ctx-
>oldEventHandler))
> S> (ctx->oldEventContext,
> S> SourceAddressLength,
> S> SourceAddress,
> S> OptionsLength,
> S> Options,
> S> ReceiveDatagramFlags,
> S> BytesIndicated,
> S> BytesAvailable,
> S> BytesTaken,
> S> Tsdu,
> S> IoRequestPacket);
>
> S> I recommend that you firstly get the code working
without
> S> queueing (i.e. call the original handler immediately
in
> S> your filtered handler) ... this way you can ensure
your
> S> filters are working correctly. Move on to queueing
> S> after ... this is something I have not tried so you
will
> S> have to work that out. The help on
> S> ClientEventReceiveDatagram should answer most of your
> S> other questions.
>
> S> There is a great example tdi firewall called tdi_fw
that
> S> you should try to download
> S> http://sourceforge.net/projects/tdifw.
>
> S> ps. you might have noticed there is a small bug in
the
> S> example ...
> S> filteredCtx = ExAllocatePool(NonPagedPool, sizeof
> S> (TDI_EVENT_CONTEXT));
>
> S> This should be ...
> S> filteredCtx = ExAllocatePool(NonPagedPool, sizeof
> S> (EventContext));
>
> S> Steve
>
> >> -----Original Message-----
> >> Hello, Steve!
> >>
> >> Thanks for the reply.
> >> There are several moments that are not crear for me.
> >> Almost all event callback functions have pointers as
> S> input parameters.
> >> Do they point to static memory? Can I simply store
> S> pointers, or I must
> >> allocate memory and copy original one?
> >>
> >> Can you clarify the following:
> >>
> >> //
> >> // the callback function set via
TDI_SET_EVENT_HANDLER
> >> //
> >> NTSTATUS tdi_event_receive_datagram(
> >> //
> >> // ** I do not know memory size pointed by
> S> TdiEventContext
> >> IN PVOID TdiEventContext,
> >> IN LONG SourceAddressLength,
> >> IN PVOID SourceAddress,
> >> IN LONG OptionsLength,
> >> IN PVOID Options,
> >> IN ULONG ReceiveDatagramFlags,
> >> IN ULONG BytesIndicated,
> >> IN ULONG BytesAvailable,
> >> //
> >> // ** does it point to static variable?
> >> OUT ULONG *BytesTaken,
> >> //
> >> // ** memory size pointed by Tsdu is unknown?
> >> IN PVOID Tsdu,
> >> //
> >> // ** do I need to store the pointer or the value?
> >> OUT PIRP *IoRequestPacket)
> >> {
> >>
> >> // adding to queue all the input parameters;
> >>
> >> //
> >> // what value should I return exactly?
> >> //
> >> return STATUS_PENDING;
> >> }
> >>
> >> void MyThread()
> >> {
> >> // here I will call old original event handler
> >> // with parameters previously stored in queue.
> >> // and then release allocated memory.
> >> }
> >>
> >> Best regards,
> >> Serge.
> >>
> >> You wrote on Tue, 8 Feb 2005 18:25:23 -0800:
> >>
> S>>> Firstly, you will need to filter the events. With
> S>>> filtering in place, when an event is triggered on
an
> S>>> address object your event filter function will get
> S>>> called, and then you can call the original event
> S>>> function, either immediately, or later if you are
> S>>> queueing.
> >>
> S>>> To setup filtering events you must first filter the
> S>>> handler for TDI_SET_EVENT_HANDLER (as you filter
any
> S>>> other IRP). A client that wants to register an
event
> S>>> will send a TDI_SET_EVENT_HANDLER irp for a
> S> particular
> S>>> address object. This irp will contain an event
type,
> S>>> handler and context. Here you patch in your
handler
> S> (and
> S>>> context) and store away the original handler and
> S>>> context. You will need the original values so that
> S> when
> S>>> your event handler is called, you can then call the
> S>>> original handler. A typical way to store the
> S>>> originalvalues is to store them in your own event
> S> context.
> >>
> S>>> Here is an example handler for
> S> TDI_SET_EVENT_HANDLER ...
> >>
> S>>> typedef struct
> S>>> {
> S>>> PFILE_OBJECT fileobj; // address object
> S>>> PVOID oldEventHandler;
> S>>> PVOID oldEventContext;
> >>
> S>>> } EventContext;
> >>
> S>>> // -----------------------------------------------
--
> S> -----
> S>>> ----------------------
> S>>> void SetEventHandler(PIRP irp, PIO_STACK_LOCATION
> S> irps)
> S>>> {
> S>>> PTDI_REQUEST_KERNEL_SET_EVENT event =
> S>>> (PTDI_REQUEST_KERNEL_SET_EVENT)&irps->Parameters;
> S>>> EventContext *filteredCtx;
> >>
> S>>> filteredCtx = ExAllocatePool(NonPagedPool, sizeof
> S>>> (TDI_EVENT_CONTEXT));
> >>
> S>>> // store original (client supplied) data
> S>>> //
> S>>> filteredCtx->fileobj = irps->FileObject; //
> S> address
> S>>> object
> S>>> filteredCtx->oldEventHandler = event-
>EventHandler;
> S>>> filteredCtx->oldEventContext = event-
>EventContext;
> >>
> S>>> // patch in our data
> S>>> //
> S>>> event->EventHandler = filteredEventHandler; //
> S> this
> S>>> must point to a function
> S>>> //
> S> that
> S>>> has the same definition
> S>>> //
as
> S> the
> S>>> event function you are
> S>>> //
> S>>> filtering
> S>>> event->EventContext = filteredCtx;
> >>
> S>>> // now send IRP on down to lower driver ...
> S>>> }
> >>
> S>>> If you need more help email me.
> S>>> Steve.
> >>
> >>>> -----Original Message-----
> >>>> Hello,
> >>>>
> >>>> I can save IRP requests, and complete/cancel them
> S> later
> S>>> successfully.
> >>>> But I want to queue events, set by
> S> TDI_SET_EVENT_HANDLER
> S>>> as well.
> >>>>
> >>>> Could anybody clarify how this can be done?
> >>>>
> >>>> Thanks!
> >>>>
> >>>> Best regards,
> >>>> Serge.
>
>
>.
>

Re: TDI driver event queueing by serge

serge
Thu Feb 10 09:58:29 CST 2005

Hello, Steve!

S> Have you considered using an NDIS IM
S> driver and queueing packets instead?

This is already done :)
Probably you rememer my NDIS IM related questions here some weeks ago.

I want to allow/deny incoming and outgoing connections on user level.
I can do so on NDIS IM level, but there is one problem:

Process name is unknown when SYN packet arrives. I can not provide user with
application name that attempts to connect to remote host, or accepts
incoming connection.

I can see two solutions:
(1) wait until system replies with SYN+ACK. This will be done in process
context, so we can get it's name.
(2) filter connections on TDI level.

As for (1) - I am not sure about security. Probably it's not not safe to
allow application to receive stand-alone SYN packet. Also, it's not clear
how to drop connection in this case (application sent SYN+ACK will be
waiting for ACK packet(s) from remote host....)

Also, I feel that TDI queueing is not very simple task, and it even may not
work on all Windows builds...

Best regards,
Serge.


You wrote on Wed, 9 Feb 2005 17:49:32 -0800:

S> Firstly, your event is called by tcpip (when the event
S> occurrs) not by the kernel-mode client. You call the
S> kernel-mode client when you call the original handler
S> (which is the clients handler).

S> As for the BytesTaken and IoRequestPacket I am not sure
S> how you can deal with them. They are pointers to
S> variables that belong to tcpip. The client in its event
S> handler would read the data received and inform tcpip how
S> much it read in BytesTaken. Also, the client might
S> allocate an irp for IoRequestPacket, this irp would be
S> set up to receive any more available data. What you are
S> attempting to do is very difficult. If your filter does
S> nothing with BytesTaken and IoRequestPacket tcpip will
S> assume that the client is not interested in the received
S> data! You will have to process this event as if you were
S> the client, i.e. read all data and set BytesTaken, and
S> create irp for IoRequestPacket. This gets even trickier
S> because then you will be responsible for this irp - you
S> will need to register a completion routine for it, etc.

S> When you dequeue and call the original client handler you
S> will have to look and behave like tcpip, i.e. process any
S> irp the client gives you in IoRequestPacket (i.e. copy
S> data from the irp your filter created).

S> Filtering in the tdi is very complicated, as you are
S> finding. You are the middle man, to the client you must
S> look and act like tcpip, to tcpip you must look and act
S> like the client. Have you considered using an NDIS IM
S> driver and queueing packets instead?

S> Steve.

>> -----Original Message-----
>> Hello, Steve!
>>
>> I already created transparent TDI driver that filters
S> all the events and
>> requests, so now I am moving towards queueing. Yes, I
S> have seen tdi_fw
>> sources, thay are great as a start point.
>>
>> I can not understand one thing:
>> When kernel-mode client sends event to my TDI driver,
S> does it want to get
>> reply immediately?
>> I can save input variables, and then call original event
S> handler in my
>> worker thread, but what about output variables?
>>
>> In our example parameters BytesTaken and IoRequestPacket
S> are output one.
>> Can I save these pointers and use them in my thread
S> later?
>> Are these variables located in static memory?
>> I afraid I will receive BSOD when I try to write there
S> something there from
>> my thread...
>>
>> Best regards,
>> Serge.
>>
>> You wrote on Wed, 9 Feb 2005 16:27:47 -0800:
>>
S>>> TdiEventContext is the context that you supplied in
S> the
S>>> filter function for TDI_SET_EVENT_HANDLER. If you
S> look at
S>>> the example I gave you TdiEventContext is ...
S>>> EventContext *filteredCtx;
>>
S>>> You use this value to get back the original context
S> and
S>>> handler. If you call the original handler within
S> your
S>>> filtered handler your code will look something like
S>>> this ...
>>
S>>> EventContext *ctx = (EventContext*)TdiEventContext;
>>
S>>> // call old handler with old context
S>>> //
S>>> return ((PTDI_IND_RECEIVE_DATAGRAM)(ctx-
>> oldEventHandler))
S>>> (ctx->oldEventContext,
S>>> SourceAddressLength,
S>>> SourceAddress,
S>>> OptionsLength,
S>>> Options,
S>>> ReceiveDatagramFlags,
S>>> BytesIndicated,
S>>> BytesAvailable,
S>>> BytesTaken,
S>>> Tsdu,
S>>> IoRequestPacket);
>>
S>>> I recommend that you firstly get the code working
S> without
S>>> queueing (i.e. call the original handler immediately
S> in
S>>> your filtered handler) ... this way you can ensure
S> your
S>>> filters are working correctly. Move on to queueing
S>>> after ... this is something I have not tried so you
S> will
S>>> have to work that out. The help on
S>>> ClientEventReceiveDatagram should answer most of your
S>>> other questions.
>>
S>>> There is a great example tdi firewall called tdi_fw
S> that
S>>> you should try to download
S>>> http://sourceforge.net/projects/tdifw.
>>
S>>> ps. you might have noticed there is a small bug in
S> the
S>>> example ...
S>>> filteredCtx = ExAllocatePool(NonPagedPool, sizeof
S>>> (TDI_EVENT_CONTEXT));
>>
S>>> This should be ...
S>>> filteredCtx = ExAllocatePool(NonPagedPool, sizeof
S>>> (EventContext));
>>
S>>> Steve
>>
>>>> -----Original Message-----
>>>> Hello, Steve!
>>>>
>>>> Thanks for the reply.
>>>> There are several moments that are not crear for me.
>>>> Almost all event callback functions have pointers as
S>>> input parameters.
>>>> Do they point to static memory? Can I simply store
S>>> pointers, or I must
>>>> allocate memory and copy original one?
>>>>
>>>> Can you clarify the following:
>>>>
>>>> //
>>>> // the callback function set via
S> TDI_SET_EVENT_HANDLER
>>>> //
>>>> NTSTATUS tdi_event_receive_datagram(
>>>> //
>>>> // ** I do not know memory size pointed by
S>>> TdiEventContext
>>>> IN PVOID TdiEventContext,
>>>> IN LONG SourceAddressLength,
>>>> IN PVOID SourceAddress,
>>>> IN LONG OptionsLength,
>>>> IN PVOID Options,
>>>> IN ULONG ReceiveDatagramFlags,
>>>> IN ULONG BytesIndicated,
>>>> IN ULONG BytesAvailable,
>>>> //
>>>> // ** does it point to static variable?
>>>> OUT ULONG *BytesTaken,
>>>> //
>>>> // ** memory size pointed by Tsdu is unknown?
>>>> IN PVOID Tsdu,
>>>> //
>>>> // ** do I need to store the pointer or the value?
>>>> OUT PIRP *IoRequestPacket)
>>>> {
>>>>
>>>> // adding to queue all the input parameters;
>>>>
>>>> //
>>>> // what value should I return exactly?
>>>> //
>>>> return STATUS_PENDING;
>>>> }
>>>>
>>>> void MyThread()
>>>> {
>>>> // here I will call old original event handler
>>>> // with parameters previously stored in queue.
>>>> // and then release allocated memory.
>>>> }
>>>>
>>>> Best regards,
>>>> Serge.
>>>>
>>>> You wrote on Tue, 8 Feb 2005 18:25:23 -0800:
>>>>
S>>>>> Firstly, you will need to filter the events. With
S>>>>> filtering in place, when an event is triggered on
S> an
S>>>>> address object your event filter function will get
S>>>>> called, and then you can call the original event
S>>>>> function, either immediately, or later if you are
S>>>>> queueing.
>>>>
S>>>>> To setup filtering events you must first filter the
S>>>>> handler for TDI_SET_EVENT_HANDLER (as you filter
S> any
S>>>>> other IRP). A client that wants to register an
S> event
S>>>>> will send a TDI_SET_EVENT_HANDLER irp for a
S>>> particular
S>>>>> address object. This irp will contain an event
S> type,
S>>>>> handler and context. Here you patch in your
S> handler
S>>> (and
S>>>>> context) and store away the original handler and
S>>>>> context. You will need the original values so that
S>>> when
S>>>>> your event handler is called, you can then call the
S>>>>> original handler. A typical way to store the
S>>>>> originalvalues is to store them in your own event
S>>> context.
>>>>
S>>>>> Here is an example handler for
S>>> TDI_SET_EVENT_HANDLER ...
>>>>
S>>>>> typedef struct
S>>>>> {
S>>>>> PFILE_OBJECT fileobj; // address object
S>>>>> PVOID oldEventHandler;
S>>>>> PVOID oldEventContext;
>>>>
S>>>>> } EventContext;
>>>>
S>>>>> // -----------------------------------------------
S> --
S>>> -----
S>>>>> ----------------------
S>>>>> void SetEventHandler(PIRP irp, PIO_STACK_LOCATION
S>>> irps)
S>>>>> {
S>>>>> PTDI_REQUEST_KERNEL_SET_EVENT event =
S>>>>> (PTDI_REQUEST_KERNEL_SET_EVENT)&irps->Parameters;
S>>>>> EventContext *filteredCtx;
>>>>
S>>>>> filteredCtx = ExAllocatePool(NonPagedPool, sizeof
S>>>>> (TDI_EVENT_CONTEXT));
>>>>
S>>>>> // store original (client supplied) data
S>>>>> //
S>>>>> filteredCtx->fileobj = irps->FileObject; //
S>>> address
S>>>>> object
S>>>>> filteredCtx->oldEventHandler = event-
>> EventHandler;
S>>>>> filteredCtx->oldEventContext = event-
>> EventContext;
>>>>
S>>>>> // patch in our data
S>>>>> //
S>>>>> event->EventHandler = filteredEventHandler; //
S>>> this
S>>>>> must point to a function
S>>>>> //
S>>> that
S>>>>> has the same definition
S>>>>> //
S> as
S>>> the
S>>>>> event function you are
S>>>>> //
S>>>>> filtering
S>>>>> event->EventContext = filteredCtx;
>>>>
S>>>>> // now send IRP on down to lower driver ...
S>>>>> }
>>>>
S>>>>> If you need more help email me.
S>>>>> Steve.
>>>>
>>>>>> -----Original Message-----
>>>>>> Hello,
>>>>>>
>>>>>> I can save IRP requests, and complete/cancel them
S>>> later
S>>>>> successfully.
>>>>>> But I want to queue events, set by
S>>> TDI_SET_EVENT_HANDLER
S>>>>> as well.
>>>>>>
>>>>>> Could anybody clarify how this can be done?
>>>>>>
>>>>>> Thanks!
>>>>>>
>>>>>> Best regards,
>>>>>> Serge.



Re: TDI driver event queueing by Maxim

Maxim
Thu Feb 10 11:20:45 CST 2005

> Process name is unknown when SYN packet arrives. I can not provide user with
> application name that attempts to connect to remote host, or accepts
> incoming connection.

Use a tiny, not heavy, TDI filter, which will filter CREATEs and CLOSEs only
and keep a map of process -> port.

Do the rest in NDIS IM.

Once more - look at UNIXen, they have great firewalls and no filtering at the
level similar to TDI :)

> allow application to receive stand-alone SYN packet. Also, it's not clear
> how to drop connection in this case (application sent SYN+ACK will be

By sending RST, surely :)

> Also, I feel that TDI queueing is not very simple task, and it even may not
> work on all Windows builds...

Yes. Contrary to NDIS IM.

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