Microsoft KB Archive/156081

{|
 * width="100%"|

INFO: Differences Between Data Link Control APIs on WinNT & DOS

 * }

Q156081

-

The information in this article applies to:


 * Microsoft Win32 Application Programming Interface (API), used with:
 * the operating system: Microsoft Windows NT 3.51
 * the operating system: Microsoft Windows 2000

-

SUMMARY
This article describes the major differences between the Win32 Data Link Control (DLC) API and the DOS DLC interface. It assumes familiarity with the DLC protocol and the relevant specification documents. Where appropriate, differences from the IBM OS/2 DLC interface are also described.

MORE INFORMATION
The Win32 DLC API has been designed to be as compatible with the IBM OS/2 DLC API for OS/2 1.xx as possible. The limits to compatibility are those imposed by the operating system functions (such as Event vs. Semaphores), and the differing memory models (flat vs. segmented).

The API is described herein as differences from the Command Control Block (CCB) interface in the IBM LAN Technical Reference, Fourth Edition (Dec, 1990). Areas addressed in the IBM documentation are generally not repeated here.

Differences between the Win32 and OS/2 DLC API
The following is a list of the differences between IBM OS/2 DLC and the Win32 DLC API.


 * All 16-bit segment offsets in CCBs and parameter tables have been replaced by 32-bit flat pointers.
 * The buffer pool is managed by the DLC driver. Applications can no longer define the segment size of the buffer pool or add new buffers to the pool. The application must, however, always check the size field in the buffer header.
 * The application ID and application key code fields in the CCB structure have been rendered obsolete by the ability to provide an optional security descriptor when an adapter is opened.
 * The IBM Token-Ring hardware-specific parameter fields that cannot be supported by other common token-ring adapters have been removed. These fields are not available on Ethernet adapters and applications should in general, avoid using them.
 * Win32 Events are used instead of OS/2 system semaphores to signal the completion of asycnhronous requests.
 * All global resources like functional address, group address on Ethernet, link, sap and direct stations, which were shared by all active applications are now available to each application separately.
 * Ethernet type codes are supported when sending DIRECT frames.
 * Applications may define a 48-bit multicast address on Ethernet adapters. This address overwrites the 32-bit broadcast address set by DIR.SET.GROUP.ADDRESS
 * Applications can send several frames with the TRANSMIT.FRAMES command from a DLC station.

Differences between the Win32 and DOS/2 DLC API

 * The post routines of DOS DLC have been replaced by a READ request.
 * The receive buffers are compatible with OS/2 1.xx DLC API and are different from the DOS DLC receive headers.
 * The parameter tables use OS/2 specific parameter fields.
 * No DOS-specific functions have been implemented.

Win32 DLC API
In general, most of the functions and their parameter blocks are identical to those of the IBM DLC API for OS/2 1.xx, with the pointers being changed from 16-bit offsets to 32-bit flat addresses.

Because of the compatibility with the IBM DLC specification, all Ethernet network and broadcast addresses in the functions and data structures that are common to Ethernet and token-ring networks, use the token-ring Net headers and have swapped bit order in the addresses. The functions and data structures that are only possible on the Ethernet use the normal Ethernet Net headers and bit order. For example, DIX Ethernet frames use the Ethernet order in the receive and transmit buffer Net headers. DIR.SET.MULTICAST.ADDRESS also uses the Ethernet order.

The data types, constants and error codes mentioned in the following sections are documented in the DLCAPI.H file, which ships with Microsoft Visual C++ version 4.0, or the Win32 SDK.

API Call
The Win32 DLC services are provided by a single entry point of

ASCLAN_STATUS Acslan(PLLC_CCB pCCB, PLLC_CCB * ppBadCCB);

where:

   pCCB    - Command Control Block, defines the function type and its input parameters. pBadCCB - Returns the address of the invalid CCB, if server CCBs were queued together and one of them failed. The parameter may be             NULL if the application only specifies one command.

Return code: ASCLAN status code. The DLC error or success status is                always returned in the CCB status field. The Command Control Block (CCB) defines parameters common for all DLC requests. The request-specific parameters are either in an external parameter table or in four bytes reserved for them in the Win32 CCB. For example:

// // LLC_CCB - the Command Control Block structure from DLCAPI.H //

typedef struct _LLC_CCB { UCHAR uchAdapterNumber;        // Adapter UCHAR uchDlcCommand;           // DLC command UCHAR uchDlcStatus;            // DLC command completion code UCHAR uchReserved1;            // reserved for DLC DLL struct _LLC_CCB* pNext;        // CCB chain ULONG ulCompletionFlag;        // used in command completion CCB_PARMS u;                   // parameters HANDLE hCompletionEvent;       // event for command completion UCHAR uchReserved2;            // reserved for DLC DLL UCHAR uchReadFlag;             // set when special READ CCB chained USHORT usReserved3;            // reserved for DLC DLL } LLC_CCB, *PLLC_CCB; where:

   uchAdapterNumber - Network adapter number, 0, 1, 2.. 255   uchCommand       - Function code, mostly compatible with IBM spec. uchDlcStatus    - DLC return status pNext           - Used to chain CCBs. Several Canceled commands or                      completed TRANSMIT CCBs may be chained with this field. It can also provide a READ command to                      complete the current command. ulCompletionFlag - Optional flag set by READ when the command is                      completed. The DLC API driver does not use the parameter if it was set to 0 before the call. u               - Function-dependent parameter table. hCompletionEvent - Event handle which can be used to wait for command completion. This must be created with the Win32 API CreateEvent. uchReadFlag     - This should be set if a READ CCB is chained in this command. Most DLC commands may only be executed synchronously, with the status and the optional output parameters being returned immediately. The network I/O commands may be executed sychronously or asynchronously.

Command Completion
The NT DLC command can be completed in two ways:

Waiting on the event handle defined in the CCB.

"-or-" Setting a completion flag in the CCB and reading the command completion with the READ command.

The method of polling on the status code in the CCB is unreliable in Windows NT and should not be used. The status field may be updated before the other returned parameters have been set, and should not be polled for completion.

Ethernet Type Support
The DLC API specification for the direct interface only allows data encapsulated in 802.5 or 802.3 frames. This makes it impossible to receive other Ethernet types. The new direct station ids 0004H and 0005H can receive all Ethernet types.

Users may also specify a specific Ethernet frame type in the new parameter field of the DIR.OPEN.STATION command. The direct station then only receives frames which have that specific Ethernet frame type. The received frame type is returned in the DLC header field of the non-contiguous frame header.

Received DIX Ethernet frames always include the frame padding, if the frame length is less than 64 bytes.

The Ethernet NET header is used whenever an application is sending or receiving Ethernet type frames.

Buffer Management
The buffer allocation and management methods in the Win32 DLC API are quite different from the DOS or OS/2 1.xx methods. The buffer headers, however, are as defined in the specifications.

The DLC buffers of Win32 are allocated from a single virtual memory block and the DLC driver defines the buffer segment sizes. For each received frame it allocates a minimal combination of 256, 512, 1024, 2048 and 4096 buffer segments (at most one of each size). The algorithm minimizes the non-paged memory needed for different buffer segment headers (DLC headers, internal segment header and MDL). It also allocates the minimal number of buffers for the received frames. Applications may request the fixed size buffers or an optimal number of buffers for a frame size.

The DLC buffers pools are dynamically expanded from the application-specified minimum size threshold if the size of free buffers is less than this value during a READ, DLC.FLOW.CONTROL or BUFFER.GET command. The buffer pool cannot, however, be increased beyond its maximum size.

An application may use its own transmit buffers or send data directly from the buffer pool. Because the DLC driver locks all the transmit buffers that are not in the buffer pool, applications should avoid using too many small transmit buffers.

Use the following methods to obtain better performance:


 * Allocate transmit buffers from the buffer pool. Data may be copied to these buffers from the user buffers.
 * The negotiated maximum frame size should fit into a single DLC buffer (e.g., 2048 or 4096 bytes minus the frame and buffer headers).
 * Receive several frames with the READ command.
 * Use the CCBs defined in the LLC_READ_COMMAND structure.

DLC API Functions
The following section itemizes the functions in the Win32 DLC set that are different from the CCB2 interface of the IBM LAN Technical Reference. Other functions are identical to the specification, except that pointers are 32-bit flat pointers.

1. BUFFER.CREATE
This function creates a new DLC buffer pool and returns its handle. All SAP stations and the direct station on the same adapter number use the same buffer pool. The same buffer pool may also be shared by different adapters owned by the same application. For example:

  typedef struct _LLC_BUFFER_CREATE_PARMS { OUT HANDLE hBufferPoolHandle; IN PVOID       pBuffer; IN ULONG       cbBufferSize; IN ULONG       cbMinimumSizeThreshold; } LLC_BUFFER_CREATE_PARMS, *PLLC_UFFER_CREATE_PARMS;

LLC_BUFFER_CREATE_PARMS Structure
   hBufferPoolHandle - Handle of the created buffer pool. This handle can be used by the same process to share a single buffer pool by several adapter contexts. This handle may be given in the extended parameter table of another DIR.OPEN.ADAPTER command.

pBuffer          - The application must provide this buffer to                        the DLC buffer manager. The buffer may be static or allocated from the heap. The buffer manager allocates all DLC buffers from this virtual buffer. This buffer area must not be used for anything else.

cbBufferSize     - The total size of the buffer. This must be the maximum size of the buffer pool. 0x2000 (hex) is                       the minimum buffer size, because the buffer manager only uses the full 4K pages.

cbMinimumSizeThreshold - The buffer manager tries to keep at least this much free space in the buffer pool. The buffer pool is extended by READ, BUFFER.GET and DLC.FLOW.CONTROL commands. This parameter should be big enough to hold all data received between two sequential READ commands. The buffer manager also releases (unlocks) the extra buffer space after a                            constant time. All buffer segments in a DLC buffer pool are allocated from a single virtual memory block. Its size is also the maximum size of the buffer pool. This command returns an error if it cannot lock the given minimum buffer size. At least one adapter must be open before buffer pool can be created. The RECEIVE command fails if a buffer pool has not been defined for the adapter.

Windows/Windows NT DLC applications should very carefully select the total and minimum buffer pool sizes, because the memory manager of Windows/Windows NT has a dynamic quota available pages for each process. A DLC application may not work at all if it tries to allocate too large a buffer pool in low memory conditions. The transmit commands using buffers outside of the buffer pool may fail for the same reason.

DLC applications should minimize the time that the buffers returned by the data receive or by the BUFFER.GET request are held, because those buffers are still locked in the memory. DLC applications should also be able to recover if the DLC device driver runs out of the buffers, because it may not be able to add new memory to the buffer pool (if the entire system is running out of memory).

In any case, there always is at least the minimal free buffer space if the BUFFER.CREATE request has been completed successfully.

2. BUFFER.FREE
This request returns one or more buffers to the adapter's pool. It cannot be used to add new virtual memory blocks to the existing pool. The buffers must have been obtained with BUFFER.GET

3. BUFFER.GET
This command returns the requested buffers. The command can be used both to get several buffers of the same size or to get an optimal set of buffers for the given frame size.

In the first case below, cBufferToGet includes the number the returned buffers and cbBufferSize is the size of the returned buffer segment. The size is rounded up to next available buffer size (256, 512, 1024, 2048 or 4096).

In the second case the number of returned buffers must be 0 and cbBufferSize includes the size of the actual frame that is copied to buffers. The buffer manager returns enough buffers to contain the whole frame including its buffer headers. cbBuffersLeft returns the size of free locked memory in 256 bytes blocks or 65536 if the actual size is above 1MB. For example:

  typedef struct _LLC_BUFFER_GET_PARMS { IN USHORT          usReserved; IN USHORT          cBuffersLeft; IN USHORT          cBufferToGet; IN USHORT          cbBufferSize; OUT PLLC_BUFFER    pFirstBuffer; } LLC_BUFFER_GET_PARMS, *PLLC_BUFFER_GET_PARMS;

4. DLC.FLOW.CONTROL
A Windows NT application should issue this command immediately when a link station enters a local busy state. The driver clears the busy state when there are enough free buffers to receive more frames in the buffer pool.

5. DIR.CLOSE.ADAPTER
This command closes the adapter logically, release all its resource and cancels any outstanding commands. Open SAP or link stations are reset prior to completion of this command. The canceled commands return error code 0x62. If the application has previously set bits of the functional address, the adapter support software resets the bits.

6. DIR.INITIALIZE
This command resets the network adapter. Only the BRING_UPS field in the parameter block is returned. All other fields are reserved. For security reasons, the command resets the adapter physically only if the adapter was not functioning normally when the command was issued.

See the "IBM LAN Technical Reference" for further information.

7. DIR.INTERRUPT
This command does not do anything in Windows NT.

8. DIR.OPEN.ADAPTER
This command must be completed successfully before any network communication can start. It does not usually open the physical adapter, but results in a logical open. This is because multiple applications and drivers may be accessing the same DLC driver.

Applications may have to provide the security descriptor parameter in the parameter table.

All fields specific to the IBM Token Ring hardware or the DOS NETBIOS interface have been removed from the parameter tables. The DOS security and direct interface buffer pool parameters are also obsolete.

The bring-up diagnostic result is returned (it is not defined in CCB1). Otherwise, the CCB1 parameter tables and parameters are used.

DIR_OPEN_ADAPTER_PARMS Structure
  typedef struct _LLC_DIR_OPEN_ADAPTER_PARMS { PDIR_ADAPTER_PARMS pAdapterParms; PLLC_EXTENDED_ADAPTER_PARMS pExtendedParms; PLLC_PARMS         pDlcParms; PVOID              Reserved1; } LLC_DIR_OPEN_ADAPTER_PARMS, *PLLC_DIR_OPEN_ADAPTER_PARMS;

pExtendedParms -    Pointer to new open parameters. pAdapterParameters - Pointer to adapter parameter table. pDlcParameters    - Pointer to DLC parameter table, see IBM documentation for further information.

EXTENDED_ADAPTER_PARMS Structure
  typedef struct _LLC_EXTENDED_ADAPTER_PARMS { HANDLE             hBufferPoolHandle; PVOID              pSecurityDescriptor;

} LLC_EXTENDED_ADAPTER_PARMS, *PLLC_EXTENDED_ADAPTER_PARMS;

hBufferPoolHandle  - Buffer pool handle returned by a                             BUFFER.CREATE command. pSecurityDescriptor - Windows/Windows NT security descriptor used by                            all open commands on the adapter. See "IBM Local Area Network Technical Reference" for further information.

9. DIR.OPEN.DIRECT
The fields that define the buffer pool in the IBM specification are not used. Windows NT provides an extension to receive frames of specific Ethernet types using the direct station when the usEthernetType field has a valid Ethernet type (>1500).

The protocol type mask, match and offset can be used to receive frames for a particular subprotocol type or socket. The optional parameters are ignored if the ulProtocolTypeMask is zero. The offset defines the distance of the protocol type from the beginning of the protocol header (offset 14 in the frame header). The mask is used to bitwise AND the data and the result must be equal to the match.

That is, the packet is received whenever:

   (*(PULONG)((PUCHAR)pFrame + 14 + offset) & mask) == match)

typedef struct _LLC_DIR_OPEN_DIRECT_PARMS { IN USHORT          usReserved[4]; IN USHORT          usOpenOptions; IN USHORT          usEthernetType; IN ULONG           ulProtocolTypeMask OPTIONAL; IN ULONG           ulProtocolTypeMatch OPTIONAL; IN USHORT          usProtocolTypeOffset OPTIONAL; } LLC_DIR_OPEN_DIRECT_PARMS, *PLLC_DIR_OPEN_DIRECT_PARMS;

10. DIR.READ.LOG
All parameter fields of this function may not be supported by some network adapters because the implementation of error counters is optional in NDIS 3.0. These fields are supported by Microsoft-provided NDIS 3.0 drivers, including IBM Token Ring.

11. DIR.SET.FUNCTIONAL.ADDRESS
On Ethernet, each bit set in the token-ring functional addresses causes a mapping to an Ethernet-multicast address. Please see the "IBM LAN Technical Reference" for more information.

12. DIR.SET.MULTICAST.ADDRESS
This command sets a 48-bit multicast address for the currently open DLC adapter context. A zero value removes the previous multicast address. This command is only supported on Ethernet networks and is an alternative to the DIR.SET.GROUP.ADDRESS function that can only set the lowest 32 bits of a multicast address. This operation may fail if the Ethernet adapter does not have a multicast address available.

The bit order of the multicast address is the normal Ethernet bit order.

13. DIR.SET.GROUP.ADDRESS
Only one application may set a group address for a token ring adapter. This operation may also fail if the Ethernet adapter does not have available multicast addresses.

14. READ
As in the IBM specification, except that all the fields in the parameter table are naturally aligned. The not contiguous buffer is also aligned. The data and the optional header begin at offset 64.

15.READ.CANCEL
As in the CCB2 specification, except that the pParameter field in the CCB of the command is used to specify the CCB pointer of the canceled command.

16. RECEIVE
The receive option 5 (BREAK) is not supported.

17. RECEIVE.CANCEL
Uses the pParameter field of the CCB to point to the CCB pointer of the canceled command.

Unsupported DOS Commands
The following DOS DLC commands are not supported by Windows NT:


 * DIR.SET.USER.APPENDAGE
 * RECEIVE.MODIFY
 * DIR.RESTORE.OPEN.PARMS
 * DIR.MODIFY.OPEN.PARMS

WOW/DOS DLC
DLC services are made available to DOS applications running in the DOS/WOW environment on Windows NT. The API is directly compatible with existing IBM emulators using the DOS DLC API in DOS.

Windows applications that communicate with DOS terminate-and-stay-resident (TSR) applications to access DLC services should also work unmodified on WOW.