NDIS Driver Developer's Tool Kit for OS/2 and DOS - Programmer's Guide

Preface
How to Use This Manual
 * Audience
 * Content
 * Result

Audience
The principal audience for this manual is developers of NDIS Media Access Control (MAC) drivers for both DOS and OS/2. It is assumed that the reader is an experienced system programmer, familiar with the operating system, x86 programming, and system internals. Experience with networking and/or device drivers is highly recommended. Familiarity with NDIS, while helpful, is not assumed.

Content
This manual contains guidelines for writing an NDIS MAC driver. It is organized into four chapters. Chapter 1, Overview, contains general background information on device drivers, NDIS, and MAC drivers. Chapter 2, OS/2 Device Drivers, contains OS/2 specific information. Chapter 3, DOS Device Drivers, contains DOS specific information, from the point of view of the differences between DOS and OS/2 drivers. Finally Chapter 4, Writing a Media Access Control Driver, gives guidelines and examples useful for writing your MAC driver.

Result
The intended result of this manual is to aid your driver development.

Notational Conventions
The following notational conventions are used in this manual

For example, 0x28 is hexadecimal for the decimal number 40.
 * Hexadecimal (base 16) numbers are given in the form 0xdd, 0xdddd, etc.
 * File names are given in all capital letters. Hence CONFIG.SYS stands for the file named CONFIG.SYS.
 * Code examples are given in Courier type face.

NDIS
NDIS details an internal architecture for network drivers. Drivers are divided into two categories: Media Access Control (MAC) drivers and Protocol drivers. MAC drivers directly control network adapter cards, while protocol drivers interface with the operating system and/or applications. The NDIS details the responsibilities of both types of drivers as well as the interface between them. For more information on NDIS, see the publications: 3Com/Microsoft LAN Manager Network Driver Interface Specification 2.0.1 and NDIS Implementation Information for IBM LAN Systems, NDIS Extensions.

Finding Further Information
Further information can be found in the following document:

If you already have the LAN Technical Reference, you need to order the following document:

Note: Once the Supplement is available, it will ship with orders of the LAN Technical Reference.

Chapter 1. Overview
OS/2 and DOS use specialized software, known as device drivers, to manage input and output. Examples are screen display, keyboard or mouse input, printer output, floppy or hard drive file input/output, and network adapter input/output. Each device driver is responsible for the interface between the device (that is, its controller) and the operating system.

Types of Device Drivers
Each device driver falls into one of two distinct categories, character drivers or block drivers, depending upon its device. Block drivers manage random access devices, such as disc drives, that support logical units and a directory structure. Character drivers manage all other devices, including network adapter cards. We will be concerned with character drivers.

Device drivers are further authorized into base drivers and installable drivers. Base drivers handle the basic system input/output and are usually considered part of the operating system. We will not be concerned with base drivers. Installable drivers handle all other input/output functions.

Installable Device Drivers
Installable device drivers are loaded at system initiation time. The driver initialization thread reads the CONFIG.SYS file and loads and initializes the drivers specified in the "DEVICE=" statements on a first-read-first-loaded basis.

Drivers are loaded into low memory and must consist of a data segment followed by a code segment. Additional data or code segments, if present, will be loaded into high memory.

Parts of a Device Driver
Device drivers consist of from two to five components as follows:
 * Device Driver Header (required). The first item in the driver's initial data segment is the device driver header. The header specifies device attributes and driver entry points.
 * Strategy Routine (required). System communication with device drivers is accomplished by calling the driver's strategy routine. System requests include initialization and, for most device drivers, input/output requests.
 * (Hardware) Interrupt Routine (recommended). OS/2 device drivers usually service hardware requests by means of hardware interrupts.
 * Software Interrupt Handler (optional). DOS device drivers usually service hardware requests by means of software interrupts. OS/2 drivers may contain a software interrupt handle for backwards compatibility with DOS.
 * Timer Handler (optional). OS/2 device drivers may specify a timer entry point which will be called by the system every 31.25 milliseconds.

Real Versus Protected Mode
OS/2 can emulate DOS, running DOS applications in the "DOS Compatibility Box". While in this mode, the processor emulates the behavior of the 8088 and 8086 chips by running in real mode. Otherwise the processor runs in protected mode.

While in real mode, the processor interprets the CS, DS, ES, and SS registers as segment registers, in protected mode they are selector registers. That is to say, in real mode 20-bit physical addresses are split into an high-order, 16-bit segment and a low-order, 4-bit offset. While in protected mode, address are virtual and consist of a 16-bit selector (whose three low order bits are ignored) and a 16-bit offset. The selector references a position in the appropriate (local or global) descriptor table (LDT or GDT).

Privilege Levels
While OS/2 is in protected mode, processes (and their threads) have a privilege level or ring number. The privilege level of a process determines its access to descriptor tables. Applications run at Ring 3, and can only access their own local descriptor table. The operating system runs at Ring 0, or kernel mode and can access both local and global descriptor tables.

Device drivers, however, initialize at Ring 3 (as do most applications) and run at Ring 0, to have greater access to the kernel and to hardware.

Introduction to NDIS
Network device drivers were traditionally large, monolithic drivers, containing code for protocols (the language of the network) as well as network hardware. Traditional drivers were difficult to write, had less flexibility, were harder to upgrade, and didn't support multiple protocols. A fully functional monolithic network driver would have to have the ability to interface with every protocol available.

A modular approach to protocol handling (in which only those protocols required are loaded) is a much more efficient use of system memory. The Network Device Interface Specification (NDIS) was developed to eliminate the need for multiple protocols within a single driver. Under NDIS, protocol handling is completely separated from hardware manipulation. NDIS replaces the traditional network driver with two distinct types of installable character drivers: protocol drivers and Media Access Control (MAC) drivers.

NDIS protocol drivers do not manipulate network hardware - they handle the various network data formats. MAC drivers handle the hardware. Working together, these two driver types replace the large monolithic network driver. As a result, protocol and hardware handling drivers are modular and streamlined. Protocol and MAC drivers, as a group, are called NDIS device drivers

The NDIS describes the functionality that both protocol and MAC drivers must provide for each other. The specification also describes a standard network driver interface for the two types (MAC and protocol) of NDIS device drivers

The interface includes a Protocol Manager to help organize configuration data and to bind the various modules together.

NDIS device drivers may choose to run under both OS/2 and DOS. NDIS drivers provide access to many kinds of complex protocols under multiple hardware configurations.

NDIS and the OSI Reference Model
The International Standards Organization, in an effort to standardize networks created the Open Systems Interconnection (OSI) reference model. In the OSI model, network software is thought of as a system of layers with each layer representing a particular task. The OSI model defines seven layers of networking tasks as follows



The lower portion of an NDIS protocol driver functions in the upper portion of the data link layer, above the network device driver interface. The upper portion of an NDIS protocol driver may reside anywhere from the data link to the application layer of the OSI model.

The device driver interface described in the NDIS specification functions within the data link layer of the OSI reference model.

NDIS MAC drivers are implemented at the bottom portion of the data link layer. MAC drivers may work with any physical media: PC Network, Token-Ring, ArcNet, etc. IBM protocol drivers support 802.3 or DIX (EtherNet) and 802.5 (Token-Ring) networks.

The Protocol Manager
The network device driver interface is implemented through a Protocol Manager used to coordinate connections (bindings) between modules. When an NDIS protocol or MAC driver loads and initializes, it passes to the Protocol Manager a pointer to an internal characteristics table that includes the module's name and entry points. Protocol drivers also pass a list of MAC drivers with which they wish to bind. The Protocol Manager reads the protocol driver's bindings list and helps the protocol driver to exchange information with each MAC driver in the list. The information exchanged consists of pointers to each other's characteristics tables. The exchanged entry point information allows protocol and MAC drivers to exchange characteristics tables and communicate directly with one another.

VECTOR
While a protocol driver may bind to multiple MAC drivers, each MAC driver must bind to one, and only one, protocol driver. To allow a MAC driver to bind to multiple protocol drivers or to allow a protocol driver to be dynamically loaded and unloaded, the Protocol Manager provides an additional module known as VECTOR. The VECTOR module shields a MAC driver from these details, allowing the MAC driver to be written as if there were always a single protocol driver bound to it.

Media Access Control Drivers
MAC drivers provide low-level access to network adapters. MAC drivers are loaded at system initialization time and are static - that is, they may not be removed from memory. The primary function of a MAC driver is to transmit and receive packets. Secondarily, the MAC driver also provides some basic adapter management functions.

Parts of a MAC Device Driver
Like other device drivers. an NDIS MAC driver contains the following components:
 * Header
 * Strategy Routine
 * Initialization Routine
 * Interrupt Routine

Additionally, an NDIS MAC driver must contain entry points for the following seven, NDIS-specific, entry points:
 * System Request Routine
 * General Request Routine
 * TransmitChain Routine
 * TransferData Routine
 * ReceiveRelease Routine
 * IndicationOff Routine
 * IndicationOn Routine

Finally, an NDIS MAC driver must contain the following data structures:
 * Common Characteristics Table
 * Service-Specific Characteristics Table
 * Service-Specific Status Table
 * Upper Dispatch Table

How a MAC Device Driver Works
The sole purpose of the Strategy Routine in an NDIS MAC driver is to handle load-time initialization of the driver. Later the Protocol Manager directs NDIS drivers to exchange common characteristics table addresses with the drivers they bind to. Chained off of the common characteristics table are the other tables as well as entry points to their NDIS-specific routines.

A MAC driver's Interrupt Routine handles notifications from the hardware to the MAC. These notifications will cover such matters as changes in adapter status, reception of frames, and the completion of previous transmissions.

The System Request Routine handles such matters as binding (during which characteristics tables are exchanged) and unbinding. The General Request Routine handles protocol requests of the MAC. These requests include opening and closing the adapter, setting the station address, updating statistics, and many others. Both system and general requests utilize a request packet and return a completion code in a manner similar to that of an OS/2 driver's Strategy Routine.

The TransmitChain, TransferData, and ReceiveRelease routines are used during the transmission and reception of frames in order to pass data buffers between a protocol and a MAC driver.

The IndicationOff and IndicationOn routines are used to control (turn on and off) status and reception indications. Indications are notifications from a MAC driver to a protocol driver of a change in adapter status or of a reception of a frame. A protocol driver reacts to an indication in a manner similar to a MAC driver reacting to an interrupt.

Chapter 2. OS/2 Device Drivers
As mentioned in the first chapter, OS/2 device drivers contain a device driver header and a strategy routine. As these components are common to all device drivers, they will be discussed here. For more detailed information on OS/2 device drivers, see the following publications from the OS/2 2.0 Technical Library: Control Program Programming Reference (S10G-6263-0), and Physical Device Driver Reference (S10G-6266-0). In this section, we provide a summary of that information.

The Device Driver Header
The first item in the driver's initial data segment is the device driver header. This twenty-six byte data structure is organized as follows:

In order to support multiple devices within a single driver, the device driver header is a linked list. This list is terminated by a pointer of - 1 (0xFFFFFFFF), so if your driver supports only a single device, you should fill this field with -1.

The Device Attribute Field contains descriptive information used by the system. Its structure is as follows:

The other bits are reserved, and should be set to zero.

Following the Device Attribute Field offsets into the main code segment to the entry points of the Strategy Routine and the Inter Device Communication Routine.

Character devices then have an eight byte, ASCII, blank-filled name of the device driver. This name must match the "DriverName=" keyword given in the PROTOCOL.INI file. As a device name takes precedence over a file name in a DosOpen function call, device names should contain some unusual character. A terminating "$" is traditional.

The final eight bytes of the header are reserved and should be zero filled.

The Strategy Routine
The Strategy Routine handles the system's requests of the device driver. For an OS/2 device driver, these requests include installation, normal I/O, character device-specific I/O, block device-specific I/O, and generic I/O control.

The Strategy Routine follows the far call/return mode and can be called in either real or protect mode. At entry, a pointer to a Request Packet is contained in the ES:BX register pair. This pointer is bi-modal and references the same address whether the processor is in real or in protect mode.

The Strategy Routine reads the Request Packet and takes the appropriate action. Upon completion of the request, a status field is set in the Request Packet to indicate the completion status of the request.

The Request Packet
The Request Packet consists of a thirteen byte header followed by a command specific data area. The structure of the request packet header is as follows:

The first byte gives the total length of the packet, including the header and command-specific data area. The next byte is ignored for character devices. The third byte gives the command code, indicating which function (for example, 0 = driver initialization) has been requested of the driver.

The next two bytes contain the status field. This field should be set by the driver to indicate the request completion status. Errors are indicated by setting the high order bit of this field. In this case, an error code should be returned in the low order eight bits.

The next four bytes are reserved, and the final four bytes of the header can be used to maintain a linked list of queued request packets. Either DevHlp services or the driver's own queue management may be used.

The remainder of the request packet contains command-specific data. The type and amount of command-specific data varies with each command.

Overview
Every device driver's Strategy Routine must accept the INIT initialization request (request code = 0). The driver's code which processes this request is known as the driver's Initialization Routine. The INIT request is generated by the system during driver loading and initialization. At this time, the driver initialization thread reads the CONFIG.SYS file and interprets the "DEVICE=" command lines.

For each driver referenced, the system loads the first two segments into low memory (and any remaining segments into high memory), resolves intersegment memory references, and interprets the device driver header. Then if the device driver is a DOS-compatible driver (function level = 000) that may only run in the compatibility box, the system switches the processor to real mode, otherwise it remains in protect mode. Finally the driver initialization thread formats an INIT request packet and makes a far call to the driver's Strategy Routine to allow the driver to initialize itself.

The INIT Request Packet
The INIT request packet is twenty-three (0x17) bytes long. It consists of the standard thirteen byte header, followed by ten bytes of INIT-specific data in the following format: On entry, Data_1 is unused. Pointer_1 contains a bi-modal pointer to the device helper (DevHlp) routine. Pointer_2 contains a far pointer to the device driver parameter string as defined in the "DEVICE=" command in the CONFIG.SYS file. This string consists of the driver file name, followed by blank-separated arguments and is null-terminated. Data_2 is set, for block drivers only, to the drive number of the next logical unit the file manager expects to install. Data_2 is unused for character drivers.

On exit, Data_1 will be set, by block drivers only, to the number of logical units supported by the device. Character drivers should set Data_1 to zero. Pointer_1 should be set to the lengths of the code and data segments after initialization time, with the high-order word giving the code segment length and the low-order word the data segment. This allows the system to free memory used only by the initialization routine. Pointer_2 will be set, by block drivers only, to a far pointer top the BIOS parameter block array. Data_2 is not used on exit.

Finally, on exit the driver should set the status field in the Request Packet header. Successful initialization is indicated by a status value of 0x0100 (only bit 8 set, indicating request done). General Failure is signaled by a status value of 0x810C (bit 15 set, indicating error, bit 8 set, indicating request done, and error code 0x0C, indicating General Failure).

OS/2 Functions Available at Initialization
There are over 200 Application Program Interface (API) function calls available under OS/2. These functions perform I/O, control processes, manage interprocess communication, and perform many other tasks. A subset of these API functions are available to a device driver at initialization time.

An OS/2 device driver's initialization routine is called at Ring 3 in protect mode, and a DOS compatibility box driver's initialization routine is called in real mode. Hence neither process management nor memory management API calls are permitted. However, at a device driver's initialization time, the system base drivers have loaded. Hence the following API calls are available at initialization time:


 * FileI/O:
 * Randomly reposition file pointer
 * Close a file
 * Perform generic I/O control functions
 * Open a file
 * Read from a file
 * Write to a file


 * Directory Management:
 * Delete a file
 * Terminate a pattern matching search
 * Look for a file, using pattern matching
 * Look for next file matching pattern


 * File System Information
 * Get system configuration information
 * Get current working directory
 * Get current working disk
 * Get file status
 * Get file attribute bits


 * System Message Handling
 * Retrieve message from system message file
 * Write message to system message file


 * Base-Line I/O:Produce system audio alert

DevHlp Service
As device drivers run at Ring 0, kernel mode, API calls are only available during initialization time. Hence an interface to the OS/2 operating services is provided to device drivers through the DevHlp Interface. A pointer to the entry point for DevHlp calls is passed to the driver with the INIT request packet.

There are a total of fifty-seven DevHlp services. The following subsets of these are available at driver initialization time:
 * System Clock Management: SchedClockAddr
 * Character Que Management: QueueInit
 * Memory Management: AllocGDTSelector, AllocPhys, FreePhys, Lock, PhysToGDTSelector, PhysToVirt, Unlock, UnPhysToVirt, VirtToPhys
 * Interrupt Management: EOI, SetIRQ, SetROMVector, UnSetIRQ
 * Timer Services: ResetTimer, SetTimer, TickCount
 * System Services: GetDOSVar
 * Advanced BIOS Services: ABIOSCall, ABIOSCommonEntry, FreeLIDEntry, GetLIDEntry

Chapter 3. DOS Device Drivers
There are several areas of difference between DOS and OS/2, mostly in the area of memory access and management. For real mode DOS, the driver's view of memory is straight-forward. A valid address is always valid whether operating in interrupt, system, or user context. Under OS/2 the validity of an address is entirely dependent upon its context. Extra care and planning is required to ensure that the driver's memory management strategy is correctly defined.

The Device Driver Header
The interfaces and entry points defined by NDIS are the same both for DOS and for OS/2. There are however, differences in the basic device driver structure in the two systems. These discrepancies are illustrated by the format of the driver's device header. The DOS driver's header contains two entry points referred to as Strategy and Interrupt and is eight bytes shorter than the OS/2 header. The eighteen byte DOS device header is organized as follows:

See the section on the OS/2 device header for a detailed description of the Device Attribute Field.

The Strategy Routine
Under DOS when the system processes a request packet, it initially calls the driver's strategy entry point with the register pair ES:BX containing the address of the packet. The only function the DOS strategy routine performs is saving this address in local memory. Immediately after return from the driver strategy routine, DOS calls the driver at the Software Interrupt entry point. The Software Interrupt routine retrieves the pointer stored by the strategy handler and then proceeds to execute the requested task.

The Request Packet
The DOS Request Packet, like the OS/2 Request Packet, consists of a thirteen byte header followed by a command-specific data area. The structure of the request packet header is as follows: See the section on the OS/2 Request Packet for a detailed description of these fields.

Overview
Under DOS, the Strategy Routine will save the address of the INIT request packet and return. The initialization Routine will be accessed through the Software Interrupt Entry point.

The INIT Request Packet
The DOS INIT request packet is, like the OS/2 packet, twenty-three (Ox 17) bytes long. It consists of the standard thirteen byte header, followed by ten bytes of INIT-specific data in the following format:

The only difference between the DOS and OS/2 packet is in the usage of Pointer_1. On entry for a DOS device driver, Pointer_1 is unused. On exit for a DOS driver, Pointer_1 should be set to point to the first available byte of memory above the driver.

INT 21 Function Calls at Initialization Time
During system initialization, there are typically several functions which require interface with the underlying operating system. For example, the driver may wish to display a text message identifying itself, or it may wish to query the revision of the system to be sure that some piece of required functionality is present. Particularly, in the case of an NDIS driver, interaction with another driver that has already been loaded is required.

The two operating environments, DOS and OS/2, provide the means to accomplish these tasks. Under DOS, operating system functions are executed by loading parameter values into registers and executing a software interrupt. The system dispatcher fields such requests via vector X'21'. The DOS Technical Reference provides a comprehensive description of the functions available via this method.

The OS/2 driver accesses the system via far calls to API functions linked into the executable file in precisely the same manner as an application program would. This is possible because the OS/2 initialization process executes in Ring 3 just as if it were an ordinary application program.

For both DOS and for OS/2, this functionality is accessible only during system startup. Once the initialization process has returned, neither the INT 21 or the application APIs are available.

Interrupt Handlers
Hardware interrupts and the associated interrupt handlers are managed in a slightly different manner between DOS and OS/2. Please note that interrupt handler as used in this context is distinct from the Software Interrupt routine described in the preceding discussions. In the current context, the interrupt handler is the body of code that executes in response to a hardware event and not as part of system request processing.

In an OS/2 environment, the handler is called indirectly by the system's interrupt manager. At the point at which the handler begins execution, all of the system's registers have been saved and a special interrupt stack is in use. In addition, the system provides helper routines to aid in managing Process Interrupt Control (PIC) related tasks such as delivering the SetIRQ command.

Under DOS, the handler is executed directly when a hardware interrupt occurs. Preserving the processor context, switching stacks, and dismissing the interrupt through direct interaction with the PIC are tasks which the driver must perform on its own behalf.

Chapter 4. Writing a Media Access Control Driver
The Media Access Control driver bridges the gap between the physical components of the network and the logical elements contained in the protocol stack. Every network transaction is processed by the MAC driver. Great care must be taken during implementation to ensure that a highly performant and flexible interface is provided. See the NDIS Driver Developer's Tool Kit for OS/2 and DOS Programmer's Performance Guide for guidance on performance Issues.

Typical drivers contain an entry point for requests from the operating system and usually an interrupt handler as well. NDIS MAC drivers contain additional entry points to process the functions that are defined at the boundary with the protocol driver. The calling sequence for the NDIS functions differs from that used by the operating system. Normal system functions such as read, write, open, and close are passed to the driver via a parameter block. NDIS functions are executed across the boundary between the MAC and the protocol using direct calls to entry points defined by the specification. The calling sequence used is far Pascal. The calling routine pushes its parameters on the stack from left to right, and the called routine releases the stack space occupied by the parameters on exit. Return status is passed via register AX. Called routines are responsible for saving and restoring standard register variables DS, DI, SI, and BP.

The following sections of this chapter will provide detailed descriptions and code samples illustrating the process that must be implemented by a MAC driver. These samples are written in assembly language, although C could be used. These samples are examples intended to illustrate possible code structures. Where differences exist between DOS and OS/2 the code fragments contain conditionals to control the assembly time generation of a driver for one system or the other.

The Strategy and Initialization Routines
Standard operating system type functions are signaled to an OS/2 driver via a far call to the Strategy Routine entry point defined in the driver header. The argument to this call is a pointer to a parameter block containing a code that indicates the function to be executed as well as supplementary information to be used in processing the request. The only function that a MAC driver must implement is initialization. Other functions may be implemented at the developer's discretion. For example, read and write might be used to provide access to the MAC's internal structures during debug. But in all cases, whether a function is implemented or not, every request must return a completed status in order to prevent exhaustion of system resources.

The initialization function is signaled to the driver during the processing of the CONFIG.SYS file at system startup time. During initialization, the driver establishes its operating environment, locates its adapter, and allocates the resources necessary for operation.

The PROTOCOL.INI file contains the definition of the communications subsystem that will be built. The PROTOCOL.INI file contains an entry for each driver that is configured in the NDIS environment. As part of its initialization path, the Protocol Manager reads this file and parses its contents into a tree structure. Each node directly below the root of the tree describes a [module] section from this definitions file.

Opening the Protocol Manager
As each NDIS driver initializes, it interacts with the Protocol Manager to obtain its individual parameters and to register itself. Access to the Protocol Manager is via the file system APIs. This is possible because during startup, the driver initialization code executes in Ring 3, just as if it were a normal application. The first step required is to open the Protocol Manager. The format of the function should be similar to that given below. if     OS2 push   ds                 ;    Far pointer to name (input) push   offset ProtocolManagerName push   ds                 ;    Far pointer to handle (output) push   offset ProtocolManagerHandle push   ds                 ;    Far pointer (output) push   offset ActionTaken push   0                  ;    Dword file size (output) push   0 push   1                  ;    Flag (input) push   0C2h               ;    Mode (input) push   0                  ;    Dword reserved push   0 call   DOSOPEN or     ax, ax             ;    Return status? jnz    NoManager          ;    Display error and abort else                              ;    DOS interface mov    dx, offset ProtocolManagerName mov    ax, 3d00h          ;    DOS open function int    21h jc     NoManager endif
 * -- Get handle for Protocol Manager
 * -- Get handle for Protocol Manager

Protocol Manager Requests
After the Protocol Manager open has succeeded and the file handle is obtained, requests are executed using IOCTL functions, passing a pointer to a parameter block which defines the function to be performed. Under OS/2 the generic IOCTL, function code 16, is used to provide access to all of the functionality provided by the Protocol Manager. The Category code used is 0x81 signifying LAN Manager, with a function code of 0x58, indicating Protocol Manager type command. The parameter buffer contains a far pointer to a common request block structure. The structure given below describes the Protocol Manager request block. PMBlock        struc           ; Function code PMCode         dw      ? ; Status returned by PMStatus       dw      ? ; ProtMan PMPtrl         dd      ? ; First parameter PMPtr2         dd      ? ; Second parameter PMWord         dw      ? ; Third parameter PMBlock        ends

Getting Configuration Information
Typically, the next step is to gain access to the ConfigMemoryImage parsed from PROTOCOL.INI by the Protocol Manager. The code fragment provided below illustrates the correct procedure for filling in the request block and invoking the Protocol Manager. mov    PMReqBlk.PMCode, GetProtManInfo if     OS2 push   0               ;       Far null pointer push   0 push   ds              ;       Far pointer to ReqBlk push   offset PMReqBlk push   ProtManCode     ;       0x58 push   LanManCat       ;       0x81 mov    ax,[ProtoclManagerHandle] push   ax              ;       Handle returned by open call   DOSDEVIOCTL     ;       System API or     ax, ax          ;       Return okay? jnz    NoConfigInfo    ;       Display error and abort else                           ;       DOS mov    bx, [ProtocolManagerHandle] mov    dx, offset PMReqBlk mov    cx, 14          ;       size of block mov    ax, 4402h       ;       IOCTL function int    21h jc     NoConfigInfo endif
 * --    Fill in request block.  Only parameter required
 * is function code.
 * is function code.

mov    ax, PMReqBlk.PMWord cmp    ax, ProtManLevel jne    InvalidProtMan      ;Display error and abort lds    si,PMReqBlk.PMPtrl  ;Get pointer to config tree The driver must now traverse the list of ModuleConfig structures, seeking the one that contains its operational parameters. Note that although the nodes are based an the square-bracketed [ModuleName] sections contained in the PROTOCOL.INI file, ModuleName is not the correct key to be used for the search. The value of this field is user definable and may be installation specific. The search should be based on the "DriverName=" keyword. This entry is required within every ModuleName section and must accurately reflect the name used within the driver's device header. Other fields are optional in general, but may be required by specific drivers. Below is an example PROTOCOL.INI entry for the driver for the fictional BITHOSE card. This driver requires two additional parameters, namely the I/O base address of the card and the IRQ to be used. [bithose_NIF] DriverName     = bithose$ Base           = 0x300 IntLevel       = 3 When the Protocol Manager builds the ConfigMemoryImage, lower case characters are converted to upper case and white space and comment lines are ignored. During initialization, the bithose driver searches for a ModuleName section with the correct DriverName value. ModuleConfig           struc ModuleNext     dd      0               ;       Next in chain or                                        ;       Null ModulePrev     dd      0               ;       Previous in chain ModuleName     db      16 dup (0)      ;       Square bracket name KeyWordList    dd      0               ;       First keyword ModuleConfig           ends KeyWord        struc KeyWordNext    dd      0               ;       Next in chain or                                        ;       NULL KeyWordPrev    dd      0               ;       Previous in chain KeyWordName    db      16 dup (0)      ;       Keyword text NumParams      dw      0               ;       Count of parameters ParamType      dw      0               ;       Type of parameter ;      =0 then long ;      =1 then ASCIIZ string ParamValue     dd      0               ;       Variable depending ;      on type Keyword                ends CheckEndModules: mov       ax, ds                  ;       Check for end of     or         ax, si                  ;       the line jz        NoDriverName            ;       Display error and ;      abort push      ds                      ;       Save our place push      si     lds        si, [si].KeyWordList CheckEndKeywords: mov   ax, ds     or     ax, si                      ;       Null pointer? jz    EndKeywords                 ;       Yes - try next module mov       bx, si                  ;       Save structure pointer mov       si, [si].KeyWordName mov       di, offset DriverKeyword mov       cx, 10                  ;       Length of "DRIVERNAME" cld rep       cmpsb jcxz      FoundDriverKeyword NextKeyword: lds       si, [bx].NextKeyword jmp       CheckEndKeyWords FoundDriverKeyword: cmp       [bx].NumParams, 1 jne       NextKeyword             ;       Invalid entry lea       si, [bx].Param cmp       [si].ParamType, ASCIIZ jne       NextKeyword mov       cx, OurNameLen cmp       cx, [si].ParamLen jne       NextKeyWord lea       si, [si].ParamValue mov       di, offset OurName rep       cmpsb jcxz      FoundOurName jmp       NextKeyword EndKeywords: pop       si     pop        ds                      ;       Restore ;      ModuleConfig ptr lds       si, [si].NextModule jmp       CheckEndModules FoundOurName: pop       si     pop        ds                      ;       We have our section ;      now
 * --    Success.  First pointer contains address of
 * ConfigMemoryInfo structure. Word parameter
 * contains revision of Protocol Manager. Check
 * for acceptable values.
 * for acceptable values.
 * -- The following structure definitions are used
 * by the parsing routine below.
 * -- The next section repeats NumParams times
 * -- The next section repeats NumParams times
 * -- Find our ModuleName section.
 * ds:si--> Head of ModuleConfig linked list.
 * ds:si--> Head of ModuleConfig linked list.

Building the Characteristics Tables
After locating the correct ModuleName section, the driver should copy the Name specified by the user into its common characteristics table. The driver should scan the keywords linked to this module for any specific required parameters. In this example, the bithose driver would continue the scan for the two additional required parameters. If they are not present, the driver may choose to display an error message and abort its initialization. For each parameter encountered, the driver should check to ensure that the parameter is of the correct type and that the value given is within range.

After parsing its ModuleConfig section, the driver should have enough information to query its adapter and complete the initialization of its characteristics tables. NDIS defines a set of tables that are maintained by conformant drivers. These tables contain information describing the capabilities of the driver and adapter, as well as several entry points within the driver that are callable by external entities across the NDIS boundary. Most of the fields in the table may be initialized when the driver is coded, with the default values in selected fields overridden by information gained from PROTOCOL.INI parsing.

Several fields within these tables contain far pointers to be used by the protocol driver after binding. The values contained must be Ring 0 GDT selectors. They can not be established at initialization time because the driver is operating in Ring 3. The value for these pointer fields are properly established using the SEG assembler pseudo-op as illustrated in the example below, describing the NDIS System Request dispatch entry point as it might appear within the MAC's Common Characteristics Table. dw        offset System dw        SEG System

Completing Initialization
After the Characteristics Tables have been completely built, the MAC driver can proceed to the final stages of initialization. Depending on the MAC, this may, under OS/2 require reserving GDT selectors and locking extra segments for use during operation. When the implementation-specific initialization functions have completed, the driver is ready to complete its start-up path by registering with the Protocol Manager. This function is executed as a generic IOCTL as described in the preceding section on obtaining the ConfigMemoryInfo. The format of the call is described below. mov             PMReqBlk.PMCode, RegisterModule mov             word ptr PMReqBlk.PMPtrl, offset CCTable mov             word ptr PMReqBlk.PMPtrl + 2, SEG CCTable mov             word ptr PMReqBlk.PMPtr2, 0 mov             word ptr PMReqBlk.PMPtr2 + 2, 0 if    OS2 push    0                       ;       Far null pointer push    0 push    ds                      ;       Far pointer to ReqBlk push    offset PMReqBlk push    ProtManCode             ;       0x58 push    LanManCat               ;       0x81 mov     ax, [ProtoclManagerHandle] push    ax                      ;       Handle returned by open call    DOSDEVIOCTL             ;       System API or      ax, ax                  ;       Return okay? jnz     RegisterFail            ;       Display error and abort else                                   ;       DOS mov     bx, [ProtocolManagerHandle] mov     dx, offset PMReqblk mov     cx, 14 mov     ax, 4402h               ;       DOS IOCTL int     21h jc      RegisterFail endif Initialization is now completed and no further interaction with the Protocol Manager is required. The file handle used for the interface may now be closed and the driver may exit back to the OS/2 configuration processor.
 * -- Fill in request block. Required parameters are
 * function code and far pointer to the Common
 * Characteristics Table. Pointer 2 (bindings
 * list) must be null for MAC's.
 * list) must be null for MAC's.

The System Request Routine
At some point after the system has completed boot up, an application program may request that the network interface be started. This is signaled to the Protocol Manager via a BindAndStart function. A typical source of this request is the NETBIND.EXE program. During the RegisterModule phase, the Protocol Manager built a binding tree describing the protocol driver to MAC linkages to be established in order to create the communications subsystem. Upon receipt of the BindAndStart command the Protocol Manager traverses this tree, requesting that the higher level entities (protocol drivers) bind to the lower (MAC drivers).

For the MAC driver, the end result of this activity will, if the system is correctly configured, generate one and only one bind request from an upper level routine. This request may be issued by a single protocol driver module or it may be issued by a sub-function of the Protocol Manager called VECTOR acting on behalf of multiple protocol driver modules that have specified a binding to the MAC driver. In either case, the interface to the MAC driver is identical. When the MAC is invoked, the stack contains the parameters passed by the protocol driver in the following format stack  -->     dword   far return -->    word    MAC's data_seg -->    word    opcode for Bind (2) -->    word    pad (0) -->    dword   pointer where to return CCTable address -->    dword   callers CCTable address

The Bind System Request
Bind is the only System Request that MAC drivers implement. The MAC should be prepared to bind with no more than one upper lead module. Succeeding Bind requests should return an invalid status. The code fragment provided below demonstrates the Bind procedure. System proc far push    bp                      ;       Save frame pointer mov     bp, sp                  ;       And establish ;      addressability push    ds                      ;       Save push    di       push     si       mov      ds, [bp].SysDs          ;       Our data_seg mov     ax, INVALID_FUNCTION cmp     [bp].SysFunc, BIND jne     SysExit                 ;       Nothing else mov     ax, [BindStatus] or      ax, ax                  ;       We update this when a                                        ;       bind has occurred. ;      If 1=0 then ;      already bound. jnz     SysExit call GetAdapter                  ;       Do adapter specific stuff or       ax, ax                  ;       Make sure all went well jnz      SysExit                 ;       Some kind of hardware ;      problem - fail the bind mov  [BindStatus], INVALID_FUNCTION or     SpecStatusTable.SpecStatus, MACBound mov      ax, ds      mov       es, ax      mov       di, offset ProtocolTable lds      si, [bp].SysProtTable mov      ax, [si].CCTableDS      ;       Save Protocol's DS      mov       es: [ProtcolDS], ax      lds       si, [si].CCTableLowerDispatch mov      cx, SizeLowerDispatch cld rep      movsb xor      ax, ax                  ;       Status cleared SysExit: pop      si      pop       di      pop       ds      pop       bp      ret       SizeSysParms            ;       Clean up stack and exit System endp If the MAC driver has chosen not to implement Open and Close then, on exit from the System Request function after a successful Bind, the adapter and the MAC should be fully conditioned and ready to support network traffic.
 * -- Take control of the adapter now. It shouldn't be
 * done during bootup in case the adapter is being
 * used for remote boot.
 * used for remote boot.
 * -- Mark ourselves as bound and copy in some of the
 * Protocol's information for fast access.
 * Protocol's information for fast access.

The Indication Routines
An indication, as generated by the MAC to the protocol driver, is a higher level notification of an adapter-generated event. Indications may occur when a frame is received, when an adapter error condition occurs, or, if supported by the underlying hardware. as the result of an InterruptRequest Gall Request issued at some earlier point in time by the protocol driver MAC drivers implement two entry points, IndicationOn and IndicationOff, that provide the protocol driver with a logical mechanism for enabling and disabling these events.

The MAC driver maintains its indication level as a counter. IndicationOff increments the counter and IndicationOn decrements it. At any point if the value of the counter is non-zero, indications may not be signaled to the protocol drive. This correctly handles unwinding from the case where IndicationOff requests have been nested.

On entry to the indication routines, the stack holds the calling context as follows: Stack   -->     dword   far return -->    word    MAC's data_seg

IndicationOff
The code fragment below provides an example IndicationOff routine. As part of its process path, the routine calls an adapter specific routine to disable its interrupt generation. Depending on the hardware, it may be possible to execute a partial disable, allowing the driver to continue processing non-indication generating functions such as TransmitChain. IndicationOff                  proc far push     bp                      ;       Standard preamble mov      bp, sp      push      ds      push      di      push      si      mov       ax, [bp].IndDS cli                              ;       Per NDIS we return disabled mov      al, [IndicationLevel] inc      [IndicationLevel] or       al, al                  ;       Enabled before? jnz      IOffExit                ;       Yes - HW already disabled call      AdapterDisable          ;       Specific to adapter IOffExit xor      ax, ax                  ;       Return okay pop      si      pop       di      pop       ds      pop       bp      ret       IndParmSize IndicationOff                  endp

IndicationOn
The IndicationOn procedure is the complement of the IndicationOff function. The MACs indication level is decremented and, if the count reaches zero, adapter interrupts are re-enabled. IndicationOn                                   proc far push      bp                      ;       Standard preamble mov       bp, sp                  ;       Get stack addressability push      ds     push       di     push       si     mov        ds, [bp].IndDS          ;       Our data_seg cli                               ;       Per NDIS we return disabled dec       [IndicationLevel] jnz       IOnExit                 ;       Still off call AdapterEnable                ;       HW specific to restart ;      Must run disabled because ;      indications not allowed within ;      the context of this call IOnExit xor       ax, ax                  ;       Status = okay pop       si     pop        di     pop        ds     pop        bp     ret        IndParmSize IndicationOn                           endp In addition to these two routines, the indication level is implicitly manipulated by the MAC driver whenever an indication is about to be signaled to the protocol drive. This will be described more fully in the following sections describing the specific indications.

The TransmitChain Routine
The MAC's TransmitChain entry point is called by the protocol driver when there is a frame ready to be dispatched to the network. MAC's may implement TransmitChain synchronously or asynchronously. If the transmission is completed successfully within the context of this call, a successful return status is provided to the calling protocol. If the adapter is currently unable to accept another frame for transmission, the MAC may queue the request and return immediately to the protocol with a status indicating that the request was pended. At some later point when adapter resources become available, probably within the context of the interrupt handler, the frame can be dequeued and transmitted.

If transmission is deferred, the MAC has two additional responsibilities. First, the TransmitChainBuffer Descriptor and any immediate data it describes are valid only during the execution of the original TransmitChain call. Therefore, these volatile portions of the frame description must be copied into the MAC's memory space before returning. Second, when the deferred frame is finally transmitted, it must be confirmed to the protocol driver via the TransmitConfirm function described below.

On entry to TransmitChain, the stack contains the arguments provided by the protocol driver to be used in processing this request. stack   -->     dword   far return -->    word    MAC's data_seg -->    dword   pointer to buffer descriptor -->    word    request handle -->    word    Protocol ID TransmitChain                           proc far push      bp                      ;       Standard preamble mov       bp, sp     push       ds     push       es     push       di     push       si     call       CheckResources          ;       Adapter specific or        ax, ax                  ;       ax=0 then all systems go     jz         TxOkay call      CopyChain               ;       Copy descriptor, immediate ;      data, handle, and protocol ID                                        ;       ss:bp -->TxChain info mov       ax, REQUEST_QUEUED jmp       TxChainExit             ;       Return - xmit deferred ;    Call DoTransmit                    ;       Adapter specific ;      ss:bp-->Txchain info ;      Returns status of xmit. TxChainExit: pop       si     pop        di     pop        es     pop        ds     pop        bp     ret        TxChainParmSize TransmitChain                          endp
 * -- First check if we can start a transmit now.
 * -- First check if we can start a transmit now.
 * -- Else we have to queue request.
 * -- Else we have to queue request.
 * --  We can send now.

The Interrupt Routine
In large part, the design of the interrupt routine is dictated by the functionality of the adapter. There are, however, certain common sense guidelines to which all drivers should adhere.

The Interrupt Routine should be divided into two major sections. The front end is responsible for time-critical functions that execute during initial processing with the adapter disabled. The back end, while still in interrupt context, handles the less critical tasks after the adapter has been reconditioned to process network traffic. It is recommended that nesting within the Interrupt Routine be kept to a minimum. One invocation of the Interrupt Routine can completely clear the adapter's interrupt queue, efficiently using system resources. If multiple invocations of the Interrupt Routine are allowed to occur, then the potential exists to exhaust finite system resources such as stack space.

A simple, workable methodology, that eliminates Interrupt Routine nesting, gates access to the two portions of the Interrupt Routine based on memory resident flags. On entry the front end Interrupt Routine dismisses the interrupt at the PIC and, while interrupts are disabled, the following code sequence guarantees exclusive access to the Interrupt Routine code. A similar mechanism can be used when the front end handler has completed his critical execution path and is ready to continue the back end processing if necessary. mov        ax, 1 xchg       al, [Level1Flag] or         al, al    jnz         IntlExit                        ;       Already running - bail out -      -       -     cli                                        ;       Tests must execute disabled xor       al, al     xchg   [Level1Flag],       al              ;       Get/Clear level 1 xchg  [Level2Flag],       al              ;       Get/Set level 2 or        al, al     jz     ExecLevel2                          ;       Not running - go execute IntlExit: if  DOS                                        ;       Restore registers and swap ;       back to original stack popa pop       es     pop        ds     mov        ss, cs: [savedss] mov       sp, cs: [savedsp] iret else                                           ;       OS/2 ret endif
 * -- Get and set the exclusion flag.
 * -- Get and set the exclusion flag.
 * -- Execute front end code
 * -- Front end completed. Clear semaphore and see
 * if tail is running.
 * if tail is running.

ExecLevel2: if  DOS                                        ;       Swap off of interrupt stack popa pop       es     pop        ds     mov        ss, cs: [savedss] mov       sp, cs: [savedsp] end -    -     -     cli                                        ;       Clear until we exit mov       [Level2Flag], 0 if  DOS iret else                                           ;       OS/2 ret With this technique, at most one iteration of the front end handler and one iteration of the back end handler we be active at any one time
 * -- Execute back end code.
 * -- Execute back end code.

Time-Critical Tasks
On entry to the Interrupt Routine, there are several house-keeping functions that are required for all drivers. When the Interrupt Routine begins execution, interrupts are disabled. Several critical tasks must be performed before re-enabling. The adapter's interrupt should be masked, either at the PIC or at the adapter itself, whichever is more convenient, and an End-of-Interrupt command must be delivered to the PIC to re-enable normal hardware interrupt processing. If running under DOS, the driver must swap to a private interrupt stack. Finally, with the Interrupt Routine secure from recursion, the processor interrupt flag should be set to allow normal system operation.

Changing Mode
Before continuing further along its processing path, the driver must ensure that it is executing in protected mode. This is a requirement if any upcalls to the protocol are to be executed during interrupt handling. The procedure for ascertaining whether or not the Interrupt Routine is running in protected mode and, if necessary, executing the mode switch is given below. if   OS2 smsw     ax                      ;       Get machine status word mov  [ModeSwitch],  ax      shr       ax, 1                   ;       Shift out Protected Mode bit jc       InProtMode              ;       Okay mov      dl, RealtoProt          ;       0x2F call     dword ptr [DevHelp] mov      [ModeSwitch], 1 InProtMode: endif Similarly, during the Interrupt Routine's exit procedure, the processor must be resumed to real mode if a switch has been executed at the driver's request. if   OS2 xor      al, al      xchg      [ModeSwitch], al      or        al, al                  ;       =0 then no switch jz       NoSwitch mov      dl, ProttoReal          ;       0x30 call     dword ptr [DevHelp] NoSwitch: endif
 * -- Ready to exit. See if we did mode switch.
 * -- Ready to exit. See if we did mode switch.

Receiving Frames
There are two basic mechanisms provided for passing received frames up to the protocol. The choice is based primarily on the type of interface supported by the adapter. For adapters that support shared memory such that the MAC drive has complete visibility to the entire received frame, the ReceiveChain primitive provides the more efficient mechanism for conveying frames to the protocol driver. If, on the other hand, the adapter interfaces via programmed I/O, ReceiveLookahead offers a facility whereby the driver can input a relatively small leading portion of the received frame and advertise it to the protocol driver. Drivers that generally use ReceiveChain may occasionally revert to ReceiveLookahead in situations where adapter memory resources are running low. Both methods are described in more detail below.

ReceiveLookahead and ReceiveChain are both defined as indications, and may be suppressed based on the value of the indication level variable. The level of indication may be manipulated explicitly by the protocol driver via the IndicationOn and IndicationOff MAC entries. Additionally, the MAC explicitly disables indications before calling the protocol driver at an indication entry point. This ensures that the protocol driver will not be interrupted during indication processing by the arrival of another indication. Beside the other arguments passed to the protocol driver during an indication call, the MAC passes the address of a byte location called the IndicateFlag. Before the upcall, the MAC initializes this location with the value 0xFF. During indication processing the protocol driver may clear this location. On return, the MAC examines the value contained in the flag. If it has been cleared, then indications remain disabled. Otherwise, the MAC decrements the value of indication level potentially re-enabling indications.

ReceiveLookahead
The code fragment given below illustrates the sequence required to signal a ReceiveLookahead indication to the protocol driver. If the Protocol accepts the frame, it will call the MAC driver's TransferData entry within the context of the ReceiveLookahead call in order to receive a copy of the frame data. mov      byte ptr [IndicateFlag], -1 inc  byte ptr [IndicationLevel1] push     [MacId]                 ;       Assigned by ProtMan push     [FrameSize]             ;       Total size of frame push     [LookAheadLen]          ;       Range of LookAhead ;      This could be entire frame push     ds                      ;       Far ptr to LookAhead buffer push     offset LookAheadBuff push     ds                      ;       Far ptr to action flag push     offset IndicateFlag push     [ProtocolDS]            ;       Obtained during bind push     dword ptr [ReceiveLookahead] ;      Address copied during bind mov      dl [IndicateFlag] ;      On return either 0 or -1 add      [IndicationLevel, dl      inc       [NeedIndComplete] ;      Remember we need a complete
 * -- Execute a ReceiveLookahead upcall. The assumption is
 * that if we have reached this point indications are
 * currently enabled.
 * currently enabled.
 * -- If the Protocol wants the frame it will call our
 * TransferData entry from within the context of this call
 * TransferData entry from within the context of this call

ReceiveChain
The process path for ReceiveChain is conceptually similar to that used by ReceiveLookahead. ReceiveChain is more appropriately used when the entire frame is available in memory visible to the MAC driver. The indication level is managed similarly for both calls. With ReceiveChain the protocol driver may elect to copy the frame immediately into its space or it may defer the copy and queue the frame for copy and process during back end interrupt processing. If the protocol driver chooses to defer, the MAC driver must maintain the data buffers until they are explicitly released. mov        byte ptr [IndicateFlag], -1 inc        byte ptr [IndicationLevel] inc        word ptr [RequestHandle]        ;       Generate a new handle push push       [MacId]                         ;       Assigned by ProtMan push       [FrameSize]                     ;       Total size of frame push       [RequestHandle]                 ;       Identify this request push       ds                              ;       Far ptr to BufDescr push       offset RxBufDescr               ;       These are volatile so we                                                ;       we only need one push       ds                              ;       Far ptr to action flag push       offset IndicateFlag push       [ProtocolDS]                    ;       Obtained during bind call       dword ptr [ReceiveChain]        ;       Address copied ;      during bind mov    dl, [IndicateFlag]                  ;       On return either 0 or -1 add        [IndicationLevel], dl    inc         [NeedIndComplete]               ;       Remember that we need a                                                ;       complete cmp        ax, REQUEST_QUEUED              ;       If no -- jne        ReleaseBuf                      ;       then we can release call       QueuedRecv                      ;       Put buffers on a waiting ;      queue. The unique handle ;      generated before the ;      call will be used for ID                                                ;       during release Note that a MAC that normally uses ReceiveChain may switch temporarily to ReceiveLookahead if the protocol driver has deferred processing on several frames and the MAC is running low on resources. ReceiveLookahead forces the protocol driver to process or reject the frame synchronously within the context of the call.
 * -- ReceiveChain upcall processing. On entry the
 * frame buffers have already been linked to the
 * BufDescr.
 * BufDescr.

Other Tasks
In addition to receive processing, there are several other tasks that the interrupt Interrupt Routine may be called upon to manage. Adapter errors should be monitored and if necessary AdapterCheck status indications may be generated to the protocol driver in response to serious failures. If a transmit completion occurs, the MAC must generate a confirmation to the protocol driver, using the request handle passed with the original TransmitChain. If another frame is queued, a new transmit request can be passed to the adapter.

Only those functions that are time critical should be processed during front end interrupt handling. Whenever possible, work should be deferred until post processing when the adapter is re-enabled. Before exiting its back end interrupt processing, the MAC driver should generate an IndicationComplete upcall to allow the protocol driver to complete any of the processing it has deferred during indication time.

The TransferData Routine
TransferData is used only in conjunction with ReceiveLookahead. It describes a service entry point within the MAC driver that the protocol driver may invoke in order to transfer a received frame into its space. This call is valid only within the context of a ReceiveLookahead upcall from the MAC.

The MAC driver processes the data from the network card into the buffers linked to the TransferData buffer descriptor. The actual method of interface, DMA, programmed I/O, etc., is specific to the adapter. The process completes until either the entire frame has been transferred or until the protocol driver's buffers have been completely filled. In either case, the actual number of bytes copied is returned to the protocol driver in the location pointed to by the BytesCopied argument.

Depending on the hardware, the MAC may be able to support multiple calls to TransferData within the context of a single ReceiveLookahead upcall. If at all possible, the MAC should support this feature to allow for the case where multiple protocols are bound, via Vector, to a single MAC.

The ReceiveRelease Routine
ReceiveRelease is a MAC entry point called by the protocol driver when a ReceiveChain indication has been deferred. The protocol driver must remember the handle passed with the original ReceiveChain upcall and pass it back to the MAC. The handle is used to uniquely identify the buffers that are to be released.

The General Request Routines
The General Requests provide the protocol driver with the ability to perform adapter administration operations. All of the requests are handled via a single entry point. Specific operations are demultiplexed by the MAC via a function code parameter.

The MAC may choose to either handle the requests synchronously or to queue the request for later processing. If the request is deferred, the MAC must remember the handle and protocol ID passed with the call to be used later when the request is confirmed.

Notices
January, 1996

Issued by:

IBM Corporation

Personal Software Products

11400 Burnet Road

Austin, Texas 78758

Second Edition (January 1996)

First Edition (May 1993)

The following paragraph does not apply to the United Kingdom or any country where such provisions are inconsistent with local law: INTERNATIONAL BUSINESS MACHINES CORPORATION PROVIDES THIS PUBLICATION "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Some states do not allow disclaimer of express or implied warranties in certain transactions, therefore, this statement may not apply to you.

This publication could include technical inaccuracies or typographical errors. Changes are periodically made to the information herein; these changes will be incorporated in new editions of the publication. IBM may make improvements and/or changes in the product(s) and/or program(s) described in this publication at any time.

It is possible that this publication may contain reference to, or information about, IBM products (machines and programs), programming, or services that are not announced in your country. Such references or information must not be construed to mean that IBM intends to announce such IBM products, programming, or services in your country.

Copyright Notices
© '''Copyright International Business Machines Corporation 1993. All rights reserved.'''

Note to U.S. Government Users - Documentation related to restricted rights - Use, duplication or disclosure is subject to restrictions set forth in GSA ADP Schedule Contract with IBM Corp.

Disclaimers
References in this products to IBM products, programs or services do not imply that IBM intends to make these available in all countries in which IBM operates. Any reference to an IBM product, program or service is not intended to state or imply that only IBM's product, program, or service may be used. Any functionally equivalent product, program, or service that does not infringe any of the intellectual property rights of IBM may be used instead of the IBM product, program, or service. The evaluation and verification of operation in conjunction with other products except those expressly designated by IBM, are the responsibility of the user.

IBM may have patents or pending patent applications covering subject matter this document. The furnishing of this document does not give you any license to these patents. You can send license inquiries in writing to the IBM Director of Commercial relations IBM Corporation Purchase NY 10577 - USA.

Trademarks
The following terms are trademarks of the International Business Machine Company:
 * IBM  OS/2

The following terms are trademarks of the indicated companies:
 * Microsoft - Microsoft Corporation
 * LAN Manager - Microsoft Corporation
 * 3Com - 3Com Corporation