Porting a Real-Time Network Filter Driver to the NAL

This topic describes the steps required to port an existing filter so that it can use the RTX64 NAL.

For information on creating a new application to use with the NAL, see Creating a Real-Time Application that Uses the NAL.

The RT-TCP/IP Stack filter driver must be used if the device supports a single receive or transmit queue. Additionally, the device must be shared between a Layer 2 protocol and the RT-TCP/IP Stack. In this case, there is no option of replacing the filter driver with the NAL application. The filter driver can be used unchanged.

If there is a designated network interface (or some receive and transmit queues) for Layer 2 protocol, the protocol can be implemented as a NAL client application. If a network interface is designated to a Layer 2 protocol and is not needed to run the RT-TCP/IP Stack, this interface must be configured without TCP/IP support.

If a network interface is used to run Layer 2 protocol as well as the RT-TCP/IP Stack, the Stack will run on the default receive queue and the transmit queue with the same number. All other queues can be used for Layer 2 protocols. Only the RtNalIGB driver allows for reassigning of the default receive queue. All other drivers use the default receive queue 0. Using multiple device queues affects the performance on each queue, because they share the same physical wire.

NOTE: The NAL includes no exclusive filter drivers. Once you have ported an existing filter driver, that driver will function similar to other applications connected to the NAL.

Sections in this topic:

Initialization

The RTX64 Control Panel allows you to associate Real-Time network device drivers and filter drivers through the creation of interfaces that are available from the RT-TCP/IP Stack. The filter starts after the Stack configures its network device and passes a device pointer to RtndConfigureFilter. You can retrieve the device name by calling RtnGetDeviceName.

The NAL application must know the interface name to attach to a device’s receive and transmit queues. First, the application must call RtNalInit. This associates the application with the NAL so the NAL will not exit until the application exits. Then, if the application does not know about the available queues provided by the NAL, it can call RtNalGetNumberOfQueues and iterate through all NAL queues using RtNalGetQueueInfoByIndex.

In order to use the device queue your application must acquire ownership of the queue by calling RtNalAcquireQueue and then configure its use through RtNalConfigureQueue. You must pass the interface name to RtNalAcquireQueue, which returns the queue handle. You will use this queue handle in all following NAL API calls.

After the successful return from RtNalAcquireQueue, you now have an exclusive use of the device queue.

An application needs to acquire two separate queues to send and receive data: a receive queue and a transmit queue. An application might use only one queue to only receive data or only transmit data. In order to start sending or receiving data, you must call RtNalConfigureQueue with the queue handle. The other arguments of RtNalConfigureQueue are the application context pointer and a pointer to the capabilities structure RTNAL_QUEUE_CAPABILITIES. It is in this structure where you would set up callbacks for operations like transmitting and receiving packets. The two callbacks, fpRtnGetPacket and fpRtnDecodePacket, must be written to use RtNalReceive. The fpRtnDecodePacket callback must be written to use RtNalTransmit. These are explained in later sections. The callbacks to decode a packet for receive and transmit queue might be different. The application must write the receive packet callback fpRtnReceiveCallback if it uses RtNalReceiveWithCallback or RtNalEnableReceivePolling.

The application context pointer is typically a pointer to your application structure associated with this device queue. The structure can have a device name, physical address, packet buffers, and all other necessary information. This context pointer is passed to the application callbacks.

Receiving Packets

The filter application receives data in the RtndReceiveFilter or RtndReceiveFilterEx callback called from the device receive thread run by the RT-TCP/IP stack.

The NAL does not run a receive thread. The NAL application must run its own receive thread or use a polling timer. Normally, this thread should start before the call to RtNalConfigureQueue.

If the NAL application runs the receive thread, this thread should wait on the receive notification event handle, returned in the structure RTNAL_QUEUE_EVENTS required by RtNalAcquireQueue. The receive thread should call RtNalGetReceivePacketCount, then call RtNalReceive or RtNalReceiveWithCallback the exact number of times as is returned in the second argument of RtNalGetReceivePacketCount. Alternatively, the application can elect not use RtNalGetReceivePacketCount and instead call RtNalReceive until it fails with error code ERROR_NO_DATA.

If a device receives a valid Ethernet packet, RtNalReceive calls the fpRtnGetPacket and fpRtnDecodePacket callbacks. As part of porting your application to the NAL, you must write these callbacks and pass their pointers in a capabilities structure to RtNalConfigureQueue if you use RtNalReceive.

A NAL application can define a packet structure in its own format. The fpRtnGetPacket function, called with the queue context pointer and the requested packet length as arguments, would return the pointer to this structure. The fpRtnDecodePacket function is called with the application packet pointer, and provides an application context pointer, a pointer to the packet data area, and the packet data length.

Unlike RtndReceiveFilter, the length requested in fpRtnGetPacket includes the length of the Ethernet header. This length should be greater than or equal to the maximum packet size + 4.

Upon the successful return of RtNalReceive, the application packet structure (returned by fpRtnGetPacket) has a received packet, the data area (to which fpRtnDecodePacket provided a pointer to) has packet data.

In the NalDataStream sample provided with the NAL, these are called AppRtnGetPacket and AppRtnDecodePacket.

NOTE: The fpRtnGetPacket and fpRtnDecodePacket functions are called directly from the driver receive routine when it is holding a driver’s DMA ring lock.

Receive Packet Callback

NOTE: RtndReceiveWithCallback is not supported by RtNalE1000 driver.

The application receive packet callback can be passed to the driver in fpRtnReceiveCallback in a capabilities structure passed to RtNalConfigureQueue.

The fpRtnReceiveCallback function is called directly from RtndReceive or RtndReceiveWithCallback in a driver.

If the application calls RtNalReceiveWithCallback, it must process the packet in the receive packet callback, but it does not need the fpRtnGetPacket and fpRtnDecodePacket callbacks. The NalMultiplePacketTx sample uses RtNalReceiveWithCallback API and the receive packet callback.

If the application calls RtNalReceive, it can also process a packet in the receive packet callback, which will return TRUE. Callbacks fpRtnGetPacket and fpRtnDecodePacket would not be called. Or, it can use a callback to decide whether to accept or reject a packet. In this case, the packet callback returns TRUE to reject the packet. The packet callback returns FALSE to pass the packet to be processed after RtNalReceive returns.

NOTE: The fpRtnReceiveCallback function (same as fpRtnGetPacket and fpRtnDecodePacket) is called directly from the driver receive routine when it is holding a driver’s DMA ring lock.

If the application uses a polling timer, it must acquire the receive queue without the receive notifications. It requires a receive packet callback fpRtnReceiveCallback. It does not need the fpRtnGetPacket and fpRtnDecodePacket callbacks.

Sending Data

To send data using RtNalTransmit, you must implement the fpRtnDecodePacket callback, which decodes the application packet structure passed to RtNalTransmit to let the driver know the data area pointer and frame length (including the size of the Ethernet header). RtNalTransmit calls RtndTransmit in a NIC driver that copies data to the DMA buffer.

RtNalTransmitEx transmits multiple Ethernet frames in a single call. The frames must be pre-allocated by RtNalAllocateFrame, which returns a pointer to the RTNAL_FRAME structure, which contains the virtual and the physical addresses of the Ethernet frame buffer. An array of pointers to RTNAL_FRAME structures is passed to RtNalTransmitEx. An application can also provide callbacks to be called with each or some of the frames from a transmit complete thread. A pointer to a transmit complete callback is a field of RTNAL_FRAME structure.

To use transmit complete callbacks the transmit notifications must be enabled for this queue. When the queue is acquired with the transmit notifications, the NAL runs an additional transmit complete thread per queue in the application context. This thread runs on the ideal processor and with the priority, configured for the interface. Even though the transmit complete event handle is returned in the structure RTNAL_QUEUE_EVENTS from RtNalAcquireQueue, the application should not use it directly.

The NalMultiplePacketEx sample uses the RtNalTransmitEx API and the transmit complete callback.

NOTE: RtndTransmitEx (used by RtNalTransmitEx) is not supported by the RtNalE1000 driver.

Link Status Change

The link change notification event handle is returned in the structure RTNAL_QUEUE_EVENTS from RtNalAcquireQueue. When an application detects this event, it should call RtNalIoctl with ENIOLINKSTATUS to determine whether the link is up or down. This IOCTL can be made at any time. There is no link notification during RtNalAcquireQueue or RtNalConfigureQueue, since the device driver does not re-negotiate the link.

The provided NalDataStream sample shows this in the GetLinkStatus function.

Additional Notes

See Also: