
An Introduction to Network Programming Using the NetBIOS Interface

Alok Sinha and Raymond Patch



Most networks today are based on the Open System Interconnect (OSI) model 
developed by the International Standards Organization (ISO) in 1978. The model 
separates network software and hardware into layers (see Figure 1). It is 
based on two principles. The first is peer-to-peer communication. Each layer 
within a network-based program assumes that it is communicating with its peer 
on a remote machine, in a standard or negotiated protocol known to either 
party. Each layer is unaware of any other layer on a remote machine. 


Figure 1  OSI/ISO Reference Model

The second principle is that each layer provides a service to the layer above 
it. Every layer exposes itself to the layer above it through an interface and 
hides all implementation details. Peer-to-peer communication is achieved 
through data encapsulation. Each layer (service provider) puts a frame around 
the data to be transmitted and passes it to the layer above it (service 
requester). The frame contains header information that is understood only by 
the peer service provider on a remote machine (see Figure 2). Thus, upon 
receiving a frame, the peer provider reads in the header information. It then 
proceeds to interpret the header information for its own service controls. 
Finally, it strips out the header from the frame and passes the rest of the 
packet to the layer above it. 


Figure 2  Data Encapsulation Between Layers

Each layer can provide either a connectionless or connection-oriented service 
to the upper layer. Connection-oriented service establishes and maintains a 
virtual circuit between the sender and the recipient, similar to a telephone 
connection between two people who have one end-to-end connection and disregard 
the intermediate telephone network. They have a virtual connection--messages 
are passed back and forth in an ordered and error-free manner. 

Connectionless-oriented service uses the datagram method for internal 
communication, where each packet is given a complete source and destination 
address and then "dropped" into the network. This is similar to mailing a 
letter. You drop it into the mailbox and the Postal Service makes a "best 
attempt" to get it to the recipient. Each letter, or packet in this case, is 
routed to the recipient independently. In fact, two letters mailed at the same 
time, and destined for the same recipient, may follow completely separate 
routes. In connectionless-oriented service, each datagram packet is routed 
through the network independent of the next or previous packet. 



Reference Model Layers

The first layer of the reference model, the physical layer, is responsible for 
transmitting data over a physical communication medium such as microwave, 
twisted pair, or coax cable. The topology of a network, such as Ethernet or 
Token-Ring, is also part of the physical layer. The service provided by the 
physical layer is error-prone. The second layer, the data link layer, makes 
the data transmission over the physical layer appear error-free by 
implementing error-control techniques such as packet sequencing and 
acknowledgment. 

Next, the network layer determines the complete network route between any two 
communicating stations, which could be on the same LAN or across the globe in 
an internet environment. The transport layer provides an end-to-end or source-
to-destination data transmission channel to the session layer. It can split a 
data packet into multiple packets to suit the network layer limitations and 
also multiplex several data streams over the same physical channel. The 
session layer manages sessions between two communicating processes at the 
presentation layer by first binding to the remote process using some transport 
layer service, and then presenting connection-oriented service to the upper 
layer. 

The next layer, the presentation layer, is concerned with data representation 
and transformation when data is traveling between different platforms, such as 
between a Digital VAX and an IBM System/360. The top layer, the application 
layer, is where applications such as FTP or Telnet reside, using the services 
provided by underlying layers. 



NetBIOS

NetBIOS was first introduced in 1984 along with IBM's PC Network adapter card, 
designed by Sytek Inc. Around that time, Microsoft designed Microsoft Networks 
("MS-Net") LAN software for IBM, which was also based on the NetBIOS interface 
and protocols. Since then, all IBM LAN software (from the PCLP Program 
through LAN Server) and Microsoft LAN software (MS-Net through LAN Manager) 
have provided NetBIOS interfaces. Newer operating systems such as Windows and 
OS/2 have provided APIs and the appropriate drivers for submitting NCBs. This 
early presence of a session layer interface backed by IBM caused developers to 
create network-aware applications that write to the NetBIOS interface. This 
pressured other dominant LAN software vendors to provide NetBIOS drivers for 
workstations (including those for MS-DOS, Windows, and OS/2). Hence, any 
application written to the NetBIOS interface can be easily run on a Novell 
Network, IBM PC LAN network, IBM LAN Server network, Microsoft Networks, 
Microsoft LAN Manager network, and all MS-Net- or LAN Manager-based OEM-
adapted or modified products, such as DEC Pathworks or Ungermann-Bass Net/One. 
NetBIOS is the standard session-layer interface for a large body of network-
aware applications. 

Many LANs today follow the ANSI/IEEE 802-1985 Standard, which was adopted by 
ISO as ISO 8802:1989. Figure 3 shows how the 802 standard compares to the OSI 
reference model. 802 is a set of standards, each of which describes part of 
the LAN. The first standard, 802.1, introduces all the 802 standards. The 
Logical Link Control (LLC) layer, defined in the 802.2 standard, outlines a 
low-level protocol for maintaining a logical link between two physical 
stations on the network. The underlying network topology is defined by the 
Media Access Control layer and can be one of the following: Carrier Sense 
Multiple Access with Collision Detection (CSMA/CD), Token-Bus, or Token-Ring. 
These are known as the 802.3, 802.4, and 802.5 standards. Ethernet, a popular 
topology, is compatible with 802.3. ISO has published its counterparts to the 
IEEE 802.x standards: ISO 8802-2, 8802-3, 8802-4, and 8802-5. 


Figure 3  OSI Versus IEEE/ANSI 802 Standards
Unfortunately, the 802 standard does not yet define layers above the data link 
layer. But there is a de facto standard, originally defined by IBM, that 
defines a protocol, and provides services, at the session layer, called 
NetBIOS. NetBIOS provides the session-layer services to upper layers and uses 
the services of the data link layer. NetBIOS is made up of a set of commands, 
each of which corresponds to a frame transmitted on the network. Each NetBIOS 
frame is encapsulated within an LLC frame, and the LLC frame is, in turn, 
encapsulated within the Media Access Control frame (see Figure 4). The general 
format of a NetBIOS frame header is shown in Figure 5 and the set of NetBIOS 
commands (frame types) is shown in Figure 6. 


Figure 4  Encapsulated NetBIOS Frame


Figure 5  NetBIOS Frame Header Format


length          Length of NetBIOS frame, includes header and user data
EFFFH           Delimiter
command         NetBIOS protocol command such as NAME_QUERY
                Command values 00H to 13H implies UI frame
                Command values 14H to 1FH implies I frame
data1, data2    Optional data depending on the command
xmit/resp       One or two numbers used to associate
                received responses with transmitted requests
dest            1-byte destination session number in I-frames
                16-byte destination name in UI-frames
src             1-byte source session number in I-frames
                16-byte source name in UI-frames


Figure 6  NetBIOS Frame Types

Frame Name              Command Type


ADD_GROUP_NAME_QUERY    00H     UI
ADD_NAME_QUERY          01H     UI
NAME_IN_CONFLICT        02H     UI
STATUS_QUERY            03H     UI
TERMINATE_TRACE (remote)07H     UI
DATAGRAM                08H     UI 
DATAGRAM_BROADCAST      09H     UI
NAME_QUERY              0AH     UI 
ADD_NAME_RESPONSE       0DH     UI
NAME_RECOGNIZED         0EH     UI
STATUS_RESPONSE         0FH     UI
TERMINATE_TRACE         13H     UI
DATA_ACK                14H     I
DATA_FIRST_MIDDLE       15H     I
DATA_ONLY_LAST          16H     I
SESSION_CONFIRM         17H     I
SESSION_END             18H     I
SESSION_INITIALIZE      19H     I
NO_RECEIVE              1AH     I
RECEIVE_OUTSTANDING     1BH     I
RECEIVE_CONTINUE        1CH     I
SESSION_ALIVE           1FH     I

NetBIOS frames are either information frames (I-frames) or unnumbered 
information frames (UI-frames). I-frames transmit and receive sequentially 
numbered frames of data and are guaranteed to be delivered. One use for I-
frames is file transfers. When a file is sent from one station to another, 
each block of data read and transmitted must be received and written in the 
same order or portions of the file will be scrambled at the remote station. 
The sequence number added to each frame by the LLC layer ensures this. The LLC 
layer also takes care of frame retransmissions. An I-frame is only useful when 
a connection between two stations has been established. It is usually 
impractical to use I-frames when more than one station must receive the same 
data. This is because the transmitting station would need to establish a 
separate connection and send the same frame repeatedly to each station. 

UI-frames are neither numbered nor guaranteed to be delivered. UI-frames are 
used when a connection between two stations is unnecessary or nonexistent. 
Using a UI-frame in the above example, only one frame has to be sent to all 
stations. Only interested stations will receive and process it. A UI-frame 
does not use a sequence number and the transmitting station gets no 
acknowledgment that the frame was received by any station. A set of NetBIOS 
services is made available to the upper layer, specifically, applications. 
There are four categories of these services: name management, connection-
oriented data transfer, connectionless-oriented data transfer, and general 
purpose services. 



Name Management

Each network adapter card in a station (computer) has a unique physical 
address assigned to it by its manufacturer that allows it to be uniquely 
identified on the network. A station can have more than one adapter to define 
more unique physical addresses. NetBIOS allows each computer to have up to 254 
logical names per adapter card. The logical name (also referred to here as the 
NetBIOS name) of a station is a name that your application creates that refers 
to a physical address. This name also provides a layer of abstraction from the 
hardware. Therefore, a program can send some data from one station to another 
using logical names regardless of what physical address (or which adapter 
card) those names are associated with. Furthermore, the same program can run 
on any computer on the network since a NetBIOS name is not physically bound to 
an adapter address. In contrast, a program that sends data from, say, physical 
address 02608C3C6786H to physical address 02608C469372H, can only run on the 
two networked machines that contain the network adapter cards with those 
addresses. 

NetBIOS names can be individual or group. An individual name must be unique 
across the network. On the other hand, multiple stations can be associated 
with a group name. Group names allow easy transmission of information to all 
members of a group without having to know or enumerate all current members. 
Much of the name management is done on the station itself. The NetBIOS driver 
maintains a data structure called a name table that contains information about 
each name. When an application issues a request to add a name to this table, 
NetBIOS queries the network to see if the name exists: if it doesn't, NetBIOS 
adds it to the table and returns a number called a name number that identifies 
the name in future requests. The name number is a value between 1 and 254; 0 
and 255 are reserved. A NetBIOS name has a maximum length of 16 characters. 



Connection-oriented Data Transfer

In many cases, applications need to make reliable data transactions over the 
network. NetBIOS provides a connection-oriented mechanism, called a virtual 
circuit or session, by which two unique, nongroup names on the network can 
perform data transfers. A session is created using a combination of I- and UI-
frames. Once a session has been established, data may be transferred and 
received using I-frames. The I-frames that contain user data are 
DATA_FIRST_MIDDLE and DATA_ONLY_LAST. An application can send between 0 and 
64KB of data by submitting a request to NetBIOS. NetBIOS breaks the data into 
smaller chunks if needed and sends it as a sequence of one or more I-frames. 

The size of each data chunk is dependent on the underlying network topology. 
For example, an Ethernet network (802.3) can only send between 0 and 1500 
bytes of data in a single frame. In this case, if you have greater than 1500 
bytes of data, NetBIOS has to break the data into smaller-sized frames. A 
DATA_ONLY_LAST frame is used if there is only one frame needed (all the data 
fits into a single frame) or it is used to transmit the last frame in a 
sequence of frames. The DATA_FIRST_MIDDLE frame is used only when the amount 
of data sent will not fit into a single I-frame. In this case, it takes more 
than one I-frame to send all of the data. These are all DATA_FIRST_MIDDLE 
frames except the last frame, which is a DATA_ONLY_LAST. A DATA_ACK frame is 
sent by the receiving station to inform the sender that the data has been 
received successfully. 



Connectionless-oriented Data Transfer

Because connection-oriented data transfer is not always necessary, NetBIOS 
provides a connectionless-oriented communication mechanism, called a datagram, 
that allows an application to send unacknowledged data to one, some, or all 
names on the network with no guarantee of delivery. Suppose there are 100 
different stations with the same (group) name, MANAGERS, in the NetBIOS name 
table and one station, Barney, wants to send a message to all of them. Barney 
could create 100 different sessions and send the data 100 different times or 
Barney could send one datagram containing the message. 

There are three types of datagrams that can be generated: a datagram to a 
logical name, a datagram to a group name, or a broadcast datagram. The first 
two both use the DATAGRAM command; the only difference is the destination ID. 
The third type of datagram uses a special NetBIOS frame called a 
DATAGRAM_BROADCAST. The DATAGRAM_BROADCAST frame works just like a DATAGRAM 
frame but has no destination ID associated with it since it goes to every 
station on the entire network. 



General Purpose Services

NetBIOS provides some general purpose services to application programs. Using 
the network adapter status query, you can check the limits and status of the 
underlying card. NetBIOS can also find a logical name on the network. This is 
an important feature. If a certain name you're looking for is present on the 
network, it will respond with useful routing and physical address information. 
NetBIOS uses the physical address and route information returned for 
subsequent communications. You can also cancel a command previously issued to 
the NetBIOS interface. NetBIOS also provides a reset facility to applications. 
The network adapter reset is a destructive (software) action and is usually 
not used by general applications. 



Network Control Block

NetBIOS includes session and transport layer peer-to-peer protocols. The 
session layer is a means for dialog between logical names and does not depend 
on the frame formats used at the transport layer. For example, Barney can send 
data to Fred regardless of the frame format being used to exchange the 
information at the transport layer. The transport layer protocol defines frame 
formats that will actually carry the data to the remote station. The frames 
listed in Figure 6 are the frames defined by IBM for NetBIOS. The frames used 
in a NetBIOS implementation need not be those defined by IBM; different frames 
are used in XNS, TCP/IP, and other implementations of NetBIOS. If two stations 
are running NetBIOS implementations that differ at the transport layer (such 
as IBM NetBIOS protocol and Xerox XNS protocol) the two machines will not be 
able to communicate. 

NetBIOS defines a programming interface that applications can use to request 
services (see Figure 7). NetBIOS drivers can be implemented as an application, 
a TSR, a device driver, a UNIX daemon, or a combination of multiple 
components. A 64-byte data structure called a Network Control Block (NCB) is 
the means by which you send commands to the NetBIOS driver (see Figure 8). 

Figure 7  The NetBIOS Interface Is Supported on a Variety of Transport Layers



Figure 8  The NCB Structure


 typedef struct NCB{              
                BYTE     ncb_command;                    
                BYTE     ncb_retcode;                    
                BYTE     ncb_lsn;                             
                BYTE     ncb_num;                  
                DWORD    ncb_buffer;                             
                WORD     ncb_length;                   
                BYTE     ncb_callName[16];         
                BYTE     ncb_name[16];                

                BYTE     ncb_rto;                  
                BYTE     ncb_sto;                  
                DWORD    ncb_post;
                BYTE     ncb_lana_num;    
                BYTE     ncb_cmd_cplt;       
                BYTE     ncb_reserved[14];           
         } NCB;

The method by which the NCB is sent to the driver depends on the operating 
system and LAN software. Microsoft LAN Manager uses INT 5CH or INT 2AH in the 
MS-DOS operating system and the NetBiosSubmit function in the OS/2 operating 
system. In either case, the 4-byte address of the NCB is used. In MS-DOS1, the 
ES and BX registers contain the segment and offset addresses of the NCB block. 
Before submitting an NCB to the NetBIOS driver, the NCB structure must be 
initialized. 

Each NCB sent to NetBIOS represents an action to be performed; the action is 
specified in the ncb_command field. A NetBIOS command comes in two flavors, 
synchronous and asynchronous. A synchronous command blocks execution of the 
submitting process until the command is completed. Asynchronous commands are 
queued internally by the NetBIOS and are nonblocking. Once the command 
completes, the ncb_cmd_cplt field of the NCB structure is set to the final 
return code. When a command is submitted to the NetBIOS driver, it returns the 
success or failure status of the command in the ncb_retcode. A value of 00H in 
this field indicates success. With asynchronous commands, the NetBIOS driver 
immediately returns to the application with the ncb_retcode field set to FFH 
to indicate that the command has been queued; when the command completes, the 
ncb_retcode field, as well as ncb_cmd_cplt, is set to the final return code. 

The ncb_lsn field is set by the NetBIOS driver when establishing a session 
with remote application process; it's called the Local Session Number (LSN). 
In subsequent communications, the local process need only specify the ncb_lsn 
field in the NCB structure to communicate to the remote process, instead of 
specifying the entire logical name of the remote process in the callname 
field. On a workstation with a single adapter, each process can have up to 254 
sessions at a time and can communicate with any one of them by simply 
specifying the relevant ncb_lsn. The values 0 and 255 are never assigned and 
have special significance. 

Each process on a workstation can add up to 254 logical names to the name 
table. A process can initiate multiple sessions for the same logical name. 
Upon successful addition of a name in the NetBIOS driver's private name table, 
the NetBIOS driver returns what appears to be an index, name_number, into the 
name table in the ncb_num field. This field can subsequently be used for 
connectionless (datagram) communication with a remote process. Name numbers 0 
and 255 are never assigned and have special meanings. The adapter's physical 
address is always at index 1 of the name table (that is, name_number=1). 

The next field of an NCB, ncb_buffer, is set to the address of the data buffer 
to be transmitted or the address of a buffer where received data should be 
placed. The ncb_length field is set to the buffer size specified in the 
ncb_buffer field. This is done by the application when specifying a buffer for 
an NCB command and set by NetBIOS when a block of data is received. The 
ncb_callname field is a 16-byte field that is set to the logical name of the 
remote process by an application when setting up a connection or sending a 
datagram packet to a remote process. All bytes are significant and are used. 
The ncb_callname field is filled in by NetBIOS when a remote driver connects 
to a local process that's expecting to receive a connection call. Thus, the 
local process can find out the name of the remote caller. 

The next field in the NCB, ncb_name, is set to the logical name of the local 
process by an application when setting up a connection or when sending a 
datagram packet to a remote process. All 16 bytes are significant and are 
used. This field cannot contain a binary 0 or an asterisk in the first byte. 
Furthermore, IBM specified that the first three bytes cannot contain the 
letters IBM and the 16th byte cannot contain 00H through 1FH. In LAN Manager, 
the last character (16th byte) has special significance (see Figure 9). 

Figure 9  Encoding of 16th Byte of ncb_name

Last byte       Meaning

00H             Redirector name
03H             User name
05H             Forwarded name
20H             Server name

An application fills the ncb_rto (Receive Time Out) field with the length of 
time to wait, in half-second periods, for the arrival of a packet from one or 
more remote processes. If no incoming packets are received within this time 
period, the NetBIOS driver returns an error in the ncb_retcode field. 
Specifying a value of 00H in ncb_rto makes the command block, until a packet 
arrives for the local process. The ncb_sto field (Send Time Out) is similar to 
the ncb_rto field, except that it defines the time to wait (also in half-
second periods) before a NetBIOS connection-oriented command, such as Send, 
times out and returns an error. Specifying 00H in ncb_sto means that the 
application does not want to specify a time threshold for Send operations; it 
will block until either a packet is successfully sent out or the NetBIOS or 
lower-level transport mechanism such as the LLC layer stops retrying. 

The ncb_post field may be set by an application when submitting an 
asynchronous command. In MS-DOS, the field is set by the application to the 
address of a post-processing routine to be called by the NetBIOS driver when 
the command completes. In OS/2, this field is set with the address of an OS/2 
system semaphore, which is cleared (reset) by NetBIOS upon completion of the 
asynchronous command. Since there may be more than one network adapter card in 
a workstation, the NCB contains a field that identifies which network adapter 
the application wishes to use. This field, ncb_lana_num, is the LAN Adapter 
(or LANA) number. LANA numbers start from zero. 

In some network software environments, such as LAN Manager, it is possible to 
have multiple transport drivers (such as TCP/IP, NetBEUI, or XNS) loaded at 
the same time, each of which present a NetBIOS interface. Furthermore, there 
might be one or more LAN adapter cards present in the workstation. The 
ncb_lana_num field identifies both the transport driver and the adapter card 
to be used. The final NCB field, ncb_cmd_cplt, is used by the NetBIOS driver 
to indicate completion of an asynchronous command. This field is initially set 
to FFH by the NetBIOS driver when an asynchronous command is submitted by an 
application. It is set to a final value at command completion. Thus, after 
submitting an asynchronous command, an application can monitor (poll) this 
field until a non-FFH value is placed in it. 



Submitting an NCB to the NetBIOS driver

The first step in NetBIOS programming is figuring out how an NCB is submitted 
to the NetBIOS driver. The function NetBiosRequest in COMMON.C (see Figure 10) 
shows how to make NetBIOS function calls for MS-DOS, the Microsoft Windows 
operating system, and OS/2. In MS-DOS, you set ES:BX to the address of an NCB 
structure and either issue an INT 5C or use the C function Int86x. In 
Windows2, you have to use the Windows NetBiosCall function from an assembly-
language routine (see Figure 11). NetBiosCall virtualizes the INT 5CH for the 
calling application. 


Figure 11  Making a NetBIOS Call from Windows


      TITLE netbios.asm


extrn NETBIOSCALL : far


       ASSUME CS:_TEXT

_TEXT SEGMENT WORD PUBLIC 'CODE'

;****************************************************************************
;    FUNCTION: unsigned int far pascal NetBios( char far *NCB)
;
;    PURPOSE:  Submits an NCB thru a Windows NetBIOSCall
;
;    COMMENTS:
;               Returns immediate return code (NCB.RetCode)
;
;*****************************************************************************/


        PUBLIC NETBIOS

NETBIOS PROC FAR
         push    bp                     ; save  bp
         mov     bp, sp                 ; move sp into bp to allow stack access
         push    es                     ; save es
         push    bx                     ; save bx

         mov     es, WORD PTR [bp+8]    ; put HIWORD() into es
         mov     bx, WORD PTR [bp+6]    ; put LOWORD() into bx

         call    NetBiosCall            ; call Windows NetBios API


         xor     ah, ah
         mov     al, BYTE PTR es:[bx+1] ; return the NCB return code

         pop     bx                     ; restore bx
         pop     es                     ; restore es
         mov     sp, bp                 ; restore sp
         pop     bp                     ; restore bp
         ret     4                      ; return to caller, and fix up stack

NETBIOS ENDP

_TEXT    ENDS

END

OS/2 programmers must open the NetBIOS driver prior to submitting NCB commands 
to it. The function NetBiosInit in COMMON.C (see Figure 10) shows you how to 
call NetBiosOpen to open the driver. Once a handle to the driver has been 
obtained, you can call NetBiosSubmit. Finally, your application must call 
NetBiosClose to clean up any internal resources set up by the NetBIOS driver. 
In all cases, the result of an NCB command is returned in the ncb_retcode 
field of the submitted NCB. If an error is encountered in making the call 
itself (as opposed to errors caused by execution of the NCB command), AX may 
contain a return value (or 0 for success). When asynchronous NCB commands are 
used, the immediate value of ncb_retcode is set to FFH. Once the command 
completes, the final error codes (or 0 for success) are placed in the 
ncb_retcode and ncb_cmd_cplt fields. 



Asynchronous Calls

Asynchronous calls often make applications more efficient and user-friendly. 
Programs that block on networkI/O do not tend to leave a good impression on 
users. Fortunately, almost all NetBIOS commands can be executed 
asynchronously. You have three ways to handle asynchronous calls. In all 
cases, the NCB command must be ORed with the ASYNCH flag, which is defined as 
80H, and the submitted NCB must not be destroyed or freed until the command 
completes. Not freeing the NCB until the command completes is critical when 
programming in Windows. You can specify the timeout periods in the ncb_rto and 
ncb_sto fields of the NCB. After the NCB command completes or a timeout 
occurs, the NetBIOS driver sets the ncb_retcode and ncb_cmd_cplt fields of the 
NCB. 

You can also utilize the ncb_post to signal completion or timeout of a 
submitted asynchronous NCB call. Programmers coding for MS-DOS can put the far 
address of a post-processing routine in this field. The routine is called by 
the NetBIOS driver with ES:BX pointing to the just-completed NCB. You cannot 
make any INT 21H calls from within a post-processing routine. Pseudo-code for 
such a routine is shown in Figure 12. In OS/2, ncb_post can be set to the 
address of a system semaphore to be cleared upon completion of an asynchronous 
NCB command submitted using NetBiosSubmit. You must, of course, set the 
semaphore prior to submitting the NCB command. 

Asynchronous calls are complicated in Windows because of data and code 
swapping. This will be covered in a future article. 


Figure 12  Post-processing Routine


/*
 * Boolean signal between main and PostRoutine
 */

#include <ncb.h>
#include <common.h>
#include <string.h>

/*
 * In this example, a global variable is used as a signal between main and
 * post processing routine
 */
int  PostRoutineDriven = FALSE;

int main ()
{
/*
 * Adding a group name asynchronously
 */
    NCB    tstNCB;
    unsigned short *usPtr;

    tstNCB.ncb_command = NCBADDGRNAME | ASYNCH; // Async Add Name
    CopyToBuffer(tstNCB.ncb_name,"LanGroup");   // Set up a name.

                                                // See TTY.C for this function
    tstNCB.ncb_lana_num = 0;             // operate on 1st net

/*
 *  Set the Post_Routine_Address (ncb.post)
 */
    tstNCB.ncb_post =  (DWORD) (void far *) PostRoutine;

/*
 *  Submit the Command
 */
    printf("submitting NCBADDGRNAME   ");
    NetBiosRequest((NCB far *)&tstNCB);

/*
 *  Now, wait for the completion of the command
 */
  while ( !PostRoutineDriven)
  {
     /*
      * We are still waiting. At this time, we can perform

      * some task, update user interface etc.
      */

        .
        .
        .

} /* while  waiting for completion of command */

} /* end of main */

/*
 *  Post Routine
 *  Entry: ES:BX pointed to completed NCB.
 *  Exit: must return with RETF
 *
 *  Comments:
 *     One must use one's own stack if large stack usage is expected.
 *     The stack must be restored back before returning.
 *
 */
void  _loadds cdecl interrupt far  PostRoutine( es,  ds,
                                                di,  si,

                                                bp,  sp,
                                                bx,  dx,
                                                cx,  ax,
                                                ip,  cs,
                                                flags )
  unsigned es, ds, di, si, bp, sp, bx, dx, cx, ax, ip, cs, flags;
{

/*  ES:BX points to completed ncb
 *  NO DOS CALLS ALLOWED HERE SINCE DOS IS NON-REENTRANT
 */
/*
 *  In our example, we simply turn on a flag

 */
    PostRoutineDriven = TRUE;
}



Using Name Services

The NetBIOS Name service can be used to register unique (individual) or global 
names on the network. The NetBIOS name service commands are NCB.ADD.NAME, 
NCB.ADD.GROUP.NAME, NCB.DELETE.NAME, and NCB.FIND.NAME. These commands can be 
executed synchronously or asynchronously. Figure 13 shows generic routines 
that add, delete, and find a name. NAMETEST.C uses these generic routines (see 
Figure 14). 

Figure 14  Using Name Management Services



/**************************************************************************
 *  NAMETEST.C                                                             *
 *     This file is used to demonstrate the usage of                       *
 *     Name Management Services                                            *
 *  Usage:                                                                 *
 *      Nametest < name to be add and deleted> <LAN adapter number>        *
 *      e.g                                                                *

 *          Nametest  0                                                    *
 *                                                                         *
 ***************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <common.h>
#include <namesrv.h>

void CopyToBuffer ( char *pchDest , char * pchSrc);

int main ( int argc, char **argv)
{

    char chNameBuffer [ NCBNAMSZ ];

    unsigned char   ucLana;
    unsigned char   ucNameNum;
    unsigned char   ucRc;
    int i;

    if (argc < 2 )
    {
        printf ("Usage: NameTest <name to be added/del> [<lana>]\n");
        exit (1);

    }
    CopyToBuffer( chNameBuffer, argv[1]);

    printf("Name: [");
    for ( i=0; i < NCBNAMSZ; i++)
        printf ("%c", chNameBuffer[i]);
    printf ("]\n");

    /* What is the LAN Adapter number */
    if (argc >= 3)
        ucLana = (unsigned  char ) atoi ( argv [2] );

    else
        ucLana = 0;
    printf ( "LANA: [%d] \n",    ucLana);

    /* Initialize in case of OS/2 */
    NetInit( ucLana);

    /* Add a Name */
    ucRc =     AddName ( chNameBuffer,
                         ADD_UNIQUE_NAME,
                         ucLana,
                         &ucNameNum );

    Printf("AddName:: RC: [%x] NameNumber: [%x]\n", ucRc, ucNameNum);

    if (ucRc )
        return NetCleanUp (1);

    /* Find the Name  */

    ucRc =     FindName ( chNameBuffer,

                          ucLana );

    Printf("FindName:: RC: [%x] \n", ucRc);

    /* Delete the Name */
    ucRc =     DelName ( chNameBuffer,
                         ucLana,
                         ucNameNum );


    Printf("DelName:: RC: [%x] \n", ucRc);

    return NetCleanUp ( 0 );
}

Every process that engages in NetBIOS-based communication must first add its 
name (group or unique, with a maximum length of 16 bytes) to the adapter name 
table using the NetBIOS command NCB.ADD.NAME. Then NetBIOS returns a name 
number. The AddName function in Figure 13 shows how a group or unique name is 
added. A well-behaved application must delete all the names it has added prior 
to termination. It can use the NCB.DELETE.NAME command, which does not 
distinguish between unique names and group names. The DelName Function deletes 
a name from an adapter name table. 

Sophisticated applications use the NetBIOS command NCB.FIND.NAME to locate the 
network address of a registered process or user. This feature can detect the 
presence of, say, a file server, a print server, or a user. NCB.FIND.NAME 
takes the name-to-be-located (and its LANA number) and broadcasts it on the 
net. Nodes on the net that have this name in their name table, respond with 
their complete network addresses and routing information. Of course if the 
name-to-be-located is a unique name, there will be only one respondent. If a 
group name has been broadcast, all nodes registered as a part of the group 
will respond. Thus, the data returned by NCB.FIND.NAME (see Figure 15) has a 
fixed part (struct FINDBUF in NCB.H) and a variable part. 


Figure 15  Data Returned by NCB.FIND.NAME

Field Type      Significance

Fixed portion   

WORD    Number of nodes responding; >1 only for group names
BYTE    Reserved
BYTE    Status (00H implies unique name, 01H implies group name)
BYTE    LAN header length


Variable portion        

BYTE[33]        LAN header(s) containing the complete source and destination 
                address, which can be used by the recipient to send subsequent 
                messages to the sender(s). This 33 byte header is repeated for 
                each respondent. 

It's important to note that each name management command operates on one 
adapter at a time and each adapter has a name table. Therefore NetBIOS 
applications that communicate to all adapters must check for the presence of 
multiple adapters and repeat the process of adding/finding/deleting names for 
every adapter. This way, each process is capable of communicating with any 
process on any LAN. It follows then that there can be identical unique-named 
entities on nonconnected LANs. If a node has two adapters, it can be part of 
two separate LANs. This allows for the presence of a process named Foo on both 
at the same time. 



Using Datagram Service

NetBIOS datagram commands are NCB.SEND.DATAGRAM, NCB.SEND.BROADCAST.DATAGRAM, 
NCB.RECEIVE.DATAGRAM, and NCB.RECEIVE.BROADCAST.DATAGRAM. These commands can 
be executed synchronously or asynchronously. The source file DATASRV.C (see 
Figure 16) shows how to use the datagram commands NCB.SEND.DATAGRAM and 
NCB.RECEIVE.DATAGRAM. The sample program TTY.C (see Figure 17), shows how to 
implement datagram service for a simple and not-too-user-friendly TTY program. 
More on TTY.C below. 

Before it sends or receives datagrams, a process must add at least one name to 
the name table and get a name number. Of course, a process can add multiple 
names and receive/send data for each (name, name number) pair. It is usually 
recommended that you submit asynchronous receive commands. In MS-DOS and 
Windows, synchronous receive commands block not only the process, but the 
whole system as well until a data packet is received. A broadcast datagram 
goes to all nodes on the net. Up to 512 bytes can be sent in one broadcast. 
When submitting an NCB.SEND.BROADCAST.DATAGRAM command, the sender needs to 
specify the LAN adapter, the name number, a pointer to the data buffer, and 
data buffer size. A process can receive its own broadcast message provided it 
has a pending (asynchronous) NCB.RECEIVE.BROADCAST.DATAGRAM. 

Any node on the net can listen to broadcasts by submitting an NCB with the 
command field set to NCB.RECEIVE.BROADCAST.DATAGRAM. Of course, the receiver 
process must specify its own name number, a pointer to a buffer, and the size 
of the buffer. When a broadcast is received, NetBIOS returns the data in the 
buffer provided by the receiver. If the buffer is smaller than the data 
received, extra data is lost and an error code is returned in the ncb_retcode 
field. The receiver is not guaranteed to receive all broadcast messages on the 
net. 

Unlike broadcast datagram commands, NCB.SEND.DATAGRAM and NCB.RECEIVE.DATAGRAM 
commands are geared towards peer-to-peer nonguaranteed data transfer. As shown 
in the SendDatagram function in Figure 16, you must specify a name (unique or 
global) to send a datagram to. Successful completion of NCB.SEND.DATAGRAM does 
not mean that the receiver has received the data packet; it merely signifies 
that the packet was successfully sent out on the network. One can send up to 
512 bytes using NCB.SEND.DATAGRAM. 

A process can receive a datagram directed towards a specific name by 
submitting an NCB.RECEIVE.DATAGRAM command. It submits an NCB.RECEIVE.DATAGRAM 
NCB filled with the name number, a buffer to receive data in, the size of the 
buffer, and the LAN adapter number. The command completes when a datagram 
directed towards a name (unique or global) associated with the name number is 
received by the NetBIOS driver. It is also possible for a receiver to specify 
a name number of FFH, which means that the receiver can receive any datagram 
directed towards any name on the net. The ReceiveDatagram function in Figure 
16 shows how to submit a synchronous NCB.RECEIVE.DATAGRAM command. 



TTY.C

The teletype program TTY.C sends lines of characters between two machines (see 
Figure 17). The program also demonstrates some good programming practices for 
writing a NetBIOS application. First, note that in TTY.C the CopyToBuffer 
function is used instead of strcpy. This is because NetBIOS names must be 16 
bytes long and the convention is to pad the name with blank spaces (20H). All 
16 bytes are significant. For example, a valid NetBIOS name for the colloquial 
name "foo" would be "foo             "

Second, prior to setting up an NCB, the NCB structure must be completely 
cleared out as shown in the ClearNcb function in Figure 10. Then, each field 
can be explicitly set with the appropriate values. This leads to clean, self-
documenting, and bug-free functions. Finally, every name added in the name 
table must be deleted prior to exiting from the program. The SendReceive 
function in Figure 17 loops until the Ctrl-Z key combination is detected. By 
default, the function starts receiving datagrams or becomes a listener. By 
pressing Esc, a user can change the mode of the program from Listening to 
Receiving and vice-versa. To make the program more user-friendly, the 
synchronous receives should be replaced with asynchronous receives (see Figure 
12). 



Using Session Services

The NCB commands used to create and destroy a session are NCB.CALL, 
NCB.LISTEN, and NCB.HANGUP (for a demonstration of submitting session-based 
service commands, see SESSION.C and TTY2.C, Figures 18 and 19). The first two 
commands create the session and NCB.HANGUP terminates it. To create a session, 
a program issues an NCB.CALL to a remote NetBIOS name. The name must already 
exist on the network and the remote program must have an NCB.LISTEN command 
pending for that name. If no NCB.LISTEN command is pending, the NCB.CALL 
command will fail. Your program can expect a call from a unique name by 
explicitly posting an NCB.LISTEN for that name or it can listen for any name 
by using an asterisk (*) as the remote name. When both the NCB.LISTEN and the 
NCB.CALL complete successfully, each returns a unique number to the calling 
application: the lsn in the ncb_lsn field of the NCB. The application must use 
the LSN when making subsequent NetBIOS requests for the session identified by 
the LSN. The valid range of values for an LSN is 1 to 254 inclusive. Once the 
session has been created, data may be sent and received, in full duplex, 
between both applications using a variety of NetBIOS send and receive 
commands. 

As described earlier, timeout values for both sending and receiving can be set 
using the ncb_sto and ncb_rto fields when a session is created. The two basic 
commands for sending and receiving data on a session are NCB.SEND and 
NCB.RECEIVE; all other send and receive operations are variations of them. 
Before sending or receiving data, an application must fill in the ncb_buffer 
with a 4-byte pointer to the data to be sent or received. The ncb_length field 
must be set to the number of bytes of buffer space to be used. 



Send Session Commands

There are four  NetBIOS commands for sending data on a session: NCB.SEND, 
NCB.CHAIN.SEND, NCB.SEND.NO.ACK, and NCB.CHAIN.SEND.NO.ACK. The simplest is 
NCB.SEND, which allows up to 64KB minus 1 byte of data to be sent in a single 
NCB. The NCB.CHAIN.SEND is similar, except that two 64KB minus 1 byte buffers 
may be sent in a single NCB. Since the NCB only provides one buffer and length 
field, the first 6 bytes of the ncb_callname field are used to hold a second 
length value and buffer pointer. The first 2 bytes of the ncb_callname field 
hold the length of the second buffer and bytes 2 through 5 hold the 4-byte 
pointer to the second data buffer. 

After submitting a send command, NetBIOS transmits one or more data packets on 
the network. When all of the data has been sent, the recipient generates an 
acknowledgment. Acknowledgments are not always necessary, so NetBIOS provides 
two alternate send commands, NCB.CHAIN.SEND.NO.ACK and NCB.SEND.NO.ACK. These 
commands are more efficient (since the extra ack frame can be omitted) but 
less reliable than the acknowledged commands. 



Receive Session Commands

There are two NetBIOS receive commands for sessions: NCB.RECEIVE and 
NCB.RECEIVE.ANY. Either may be used to receive data sent by any of the four 
send commands mentioned above. Before submitting an NCB receive command, the 
ncb_buffer field must be filled with the address of a data buffer, where the 
incoming data will be stored, and the ncb_length field must be filled with the 
length of that data buffer. Since the recipient may not know how much data is 
being sent, it is possible that the receive buffer is not large enough to hold 
all of the incoming data. If this occurs, NetBIOS copies as much data as it 
can and returns error code 6H in the receive NCB's ncb_retcode field, 
informing the application that more data is available. (The ncb_length field 
is always filled in by NetBIOS with the number of bytes copied into the data 
buffer.) The application can then submit one or more NCB receive commands to 
obtain the rest of the data. Multiple NCB receive commands are always 
necessary if more than 64KB minus 1 byte of data are sent by one of the 
chained send commands. The NCB.RECEIVE command can only be used to receive 
data on a particular session and therefore must contain an LSN before it is 
submitted. 

The NCB.RECEIVE.ANY command is similar to NCB.RECEIVE except that it allows an 
application to receive data destined for any name instead of a specific 
session. Because of this, the name number is used instead of the LSN. For 
example, if an application has sessions established between one local name and 
many remote names, it can choose to receive data from a specific name rather 
than from a specific session. Upon returning from the NCB.RECEIVE.ANY command, 
NetBIOS fills in the ncb_lsn field with the LSN of the session for which the 
data was received. If the name number is set to FFH, the NCB.RECEIVE.ANY 
command can receive data from any remote name that the local machine has a 
session with, for any name on the local machine. This feature is known as a 
receive any-any. If the name number is FFH, the actual name number of the 
local name for which the data is intended is returned in the ncb_num field. 



Hanging Up Sessions

Terminating a session is supposed to be the simplest NetBIOS procedure, but it 
can still be quite complex. To terminate a session, simply submit an 
NCB.HANGUP command with the LSN of that session. When an NCB.HANGUP command is 
issued, all pending NCB receive commands are terminated; they return the error 
"session closed" in the ncb_retcode field. An NCB.HANGUP command completes 
immediately if there are no NCB send commands pending. NetBIOS will wait up to 
a specified number of seconds (the number of seconds depends on the 
implementation of NetBIOS) for all pending NCB send commands to complete in 
one of the following ways: 

        The send command completes successfully
        The send command has aborted
        The send command timed out
        The send command failed due to a remote hangup

If none of these conditions occur within the system timeout period, for any 
send pending, the NCB.HANGUP command returns a timeout error code of 05H in 
the ncb_retcode field. 



Miscellaneous Commands

There are also a few miscellaneous NetBIOS commands (ADAPTER_STATUS, RESET, 
CANCEL, and UNLINK) that haven't been covered. The NCB.RESET command resets 
the adapter, the name table, and the session table. Because of its destructive 
nature, it should be used with caution. The NCB.ADAPTER.STATUS command returns 
information about a local or remote network adapter, such as the registration 
status of a group name or a unique name, the physical address of the adapter 
card, the number of frames rejected or received, the successful transmit and 
receive frame counts, the current maximum pending NCBs, the maximum datagram 
packet size, and the maximum number of sessions. The values returned in the 
buffer depend on the adapter type and LAN software used. 

The format of the name table remains constant across all adapters and LAN 
software. This allows applications to browse Name Tables on the adapter. The 
NCB.CANCEL command cancels a previous NetBIOS command. This is a graceful way 
to cancel pending (asynchronous) commands; this command cannot be submitted to 
be executed asynchronously. You must specify in the ncb_buffer field a pointer 
to the original NCB structure that you want to cancel. Commands that cannot be 
canceled include NCB.ADD.GROUP.NAME, NCB.ADD.NAME, NCB.CANCEL, 
NCB.DELETE.NAME, NCB.RESET, NCB.SEND.DATAGRAM, NCB.SEND.BROADCAST.DATAGRAM, 
NCB.SESSION.STATUS, and NCB.UNLINK. 

The NCB.UNLINK command is provided for backward compatibility with the 
original IBM PC network and is used to disconnect a remotely booted 
workstation from a RPL (Remote Program Load) server.  



Conclusion

We have covered the core commands in NetBIOS version 3.0. Interested readers 
can obtain a copy of the latest NetBIOS specifications from IBM (IBM Local 
Area Network Reference, IBM Part Number SC30-3383-03). TCP/IP (transport) 
drivers shipped with Microsoft LAN Manager provide a NetBIOS interface that 
conforms to this specification, which addresses internetwork routing and name 
resolution on an internetwork. The result is that NetBIOS programs can operate 
in an internet environment. Thus, NetBIOS is quite pervasive across multiple 
operating systems, LAN software, and multiple transports (as long as they 
offer a NetBIOS interface beside their native interface, like the TCP/IP 
transport driver shipped with Microsoft LAN Manager). 

In this article, we discussed layered network architecture, the NetBIOS 
interfaces, and NetBIOS programming in MS-DOS. In our next article, we will 
address NetBIOS programming in Windows. 





1       For ease of reading, "MS-DOS" refers to the Microsoft MS-DOS operating 
system. "MS-DOS" is a trademark that refers only to this Microsoft product. 

2       For ease of reading, "Windows" refers to the Microsoft Windows 
operating system. "Windows" refers only to this Microsoft product. 


