[My Home Page] [Library] [Net]

IPX/SPX protocol

for communicating over Novell networks

In this short overview of IPX/SPX protocol I'll give an description of these packets and some examples of usage. As a basis of this work the Rahner James' story from Doctor Dobbs Journal (May, 1992) "IPX - the Great Communicator" was used. The sources of this text can be downloaded from DDJ's FTP server.

On ISO (International Standards Organization) OSI (Open System Interconnection) model, the IPX stays on Network level, and SPX on Transport level, as it relates to Novell's NetWare.

Table 1 - ISO/OSI model
Level Layers Protocol
7 Application NCP/DOS-shell, Applications
6 Presentation
5 Session NetBIOS
4 Transport SPX
3 Network IPX
2
Data-Link (2a+2b)
2b-Logical Link Control (LLC)
2a-Medium Access Control (MAC)
CSMA/CD
1
Physical (1a+1b)
1b-Physical (PHY)
1a-Physical Medium Dependant (PMD)
802.3/802.5

Internetwork Packet Exchange (IPX) is a protocol that allows for high-speed, peer-to-peer communication on Novell's NetWare. IPX is the lowest level of communication that can be performed on a network without resorting to direct access of the hardware. Novell refers to the functions that enable this type of connection as "IPX/SPX Communication Services". SPX - Sequenced Packet Exchange. These packets can be sent from one machine to another or sent to all machines (nodes). Sending a packet to all machines is called a BROADCAST. A broadcast will be confined to just the local network, however there are ways around this which I will not go into here. Both IPX and SPX are developed by Novell, Inc. For simplicity, I refer to both IPX and SPX as XPX.

Normal Novell Operating system accesses are through the MS-DOS INT 21h window. XPX however, uses a slightly different machanism. Before any function calls can be made, the application must call the MS-DOS multiplex (2Fh) and get the vector to the XPX entry point. Code sample in assembler shows how to do that.

Sample 1
mov  ax, 7A00h         ; function 7Ah, AL=0
int  2Fh               ; MS-DOS Multiplex Interrupt
                       ; Returns with AL==0FFh if xPX 
                       ;  exists and ES:DI==xPX vector
inc  al                ; Set ZERO if AL==-1
jnz  outta_here        ; Quit if xPX isn't around
mov  IPX_Vector, di    ; Save the xPX entry vector
mov  IPX_Vector+2, es 
  

Although one could call each function via multiplex, it is much more efficient to make call using the saved vector. XPX uses register BX to hold an XPX command number. An XPX call is not kind to unused registers and, in general, sensitive registers should be saved (especially BP). By using a far call (rather than MS-DOS int 21h), most XPX functions can be called from background process without the programmer worrying about trashing the system. All XPX functions return the status of their result in AL.

All network interfaces (Ethernet, Arcnet, and so on) require a unique 6-byte node ID to differentiate between them. The node ID only differentiates a network interface within a single network. Therefore, two network can have interfaces with identical node IDs. Because a single computer can have multiple network interfaces or a network interface can be placed on another computer, a node ID does not necessarily specify a single, distinct computer system.

Every Novell network has a 4-byte ID number that uniquely differentiates it from any other Novell networks to which it is connected. If no other networks are connected, any number is unique.

Every node connected to a network can open several different channels of communication, called "sockets". Sockets allow application to differentiate types of communication performed by a node. One socket can be used to broadcast one message to all nodes while another socket can be used to send and/or receive messages from specific nodes or group of nodes. By default, XPX can support up to 20 sockets on a single node. Through configuration, the number of sockets that may be used can be increated to 150. A 2-byte number is used as a socket ID.

Numerically, the network, node, and socket IDs are in Motorola (Big Endian) format which is opposite to the format used by Intel (Small Endian) products. The format is actually no consequence because the magnitude, order, and content are not relevant to the application or XPX. There are special cases of each type of ID, but all are palindromes, so byte order is still not important. The 4-byte network ID can be viewed as a 32-bit long integer with no significance associated with its magnitude. The 6-byte node ID can be viewed as a non-ASCII string, such as a filename, with no naming convension. The 2-byte socket ID can be a short integer that also has no significance associated with its magnitude.

In order to send a packet over a IPX network one needs to set up a basic control structure, called Event Control Block (ECB) which is vital for the driver. The ECB is passed to XPX to describe its associated channels and buffers. The ECB consists of several data fields and its structure is shown on Table 2. The first 34 bytes of the ECB contain control and addressing information. A list of "associated fragments" immediately follows this 34-byte header.

Table 2 - ECB fields
Name Size (bytes) Description
Link4 Pointer to next ECB
ESR4 Pointer to Event Service Routine
InUse1 Flag telling the ECB status
Complete1 Flag telling the ECB completion code
Socket2 Big endian socket number for ECB
IPXWork4 Work space for IPX
DrvWork12 Work space for driver
ImmedAddr12 Address to send to
FragCount2 Number of data fragments

FragData4 Pointer to data fragment (first fragment)
FragSize2 Size of data fragment (first fragment)

Optional... Last two fields repeated FragCount-1 times

When initalizing ECB record, set all fields to zero first, then set necessary fields.

Link field is used internally by IPX driver and needs no attention from a programmer's side.

ESR field is a pointer to an Event Service Routine, which is called whenever a packet arrives or is sent. The ESR is a function provided by the application and called by XPX when the ECB has been processed. The ESR is called in the following contitions:

An ESR must return with RETF instruction and interrupts disabled and maintain the stack's integrity. It can call any XPX function except Close Socket; reschedule itself through an AES call; and enable interrupts during operation, as long as blocking is done against another event calling the same function.

An application could conceivably have a separate ESR for every ECB; however, that approach would be excessive. The ESR should be fairly general purpose and should be approached with the same mind-set as an Interrupt Service Routine (ISR).

An application can use ESR for speeding up the processing by allowing packets to come and go in the background; or it can leave it empty - then the application should constantly check the InUse flag to see if any packet has been arrived or sent.

InUse flag can have several values but only 0 indicates that application can use received data or send data to the socket. In table 3 are listed values that InUse flag can take

Table 3 - InUse flag values
Value Name Description
00hDone Indicates that the ECB has been processed and completion code is valid
F8hWaiting ECB has been put in a waiting queue bacause IPX was busy
FAhProcessing ECB is being processed by IPX
FBhHolding Send/receive has occurred, but ECB is in holding queue waiting to be processed
FDhScheduled Event has been scheduled and is waiting for time-out
FEhListening IPX is listening for incoming packets at a socket
FFhSending ECB is being sent or in the process of being sent

Completion code flag contains the result of the latest action and is filled by XPX after the ECB has been processed. It is valid only when the InUse flag is 00h. This field can take following values

Table 4 - Completion Code flag values
Value Name Description
00hSuccess The packet has been sent successfully
FChCanceled Send request for this ECB has been cancelled, just like Twin Peaks
FDhChallenged Packet was malformed (eg. IPX packet header < 30 bytes, SPX header < 42 bytes, or packet size > 576 bytes)
FEhUndelivered Packet couldn't be sent, no listener available
FFhFailure Network was physically unable to deliver the packet
Additional for reception
FDhOverflow The size of the fragment received is either 0 or too large (> 576 bytes)
FFhClosed The reception socket was not open
Additional for cancellation of an ECB
F9hCancel_Fail The ECB could not be cancelled

Socket field contains an big endian 2-byte number. In few words, the socket is a number that lets a node decide if it will act on a packet. It allows multiple programs on the computer to use IPX packets completely transparent to others. Packets can be received only if they are addressed to specific socket and that socket has been opened. So packets can be ignored by nodes that are not capable of accepting them.

Socket number can not always be arbitrarily used. Novell & Xerox have reserved the range of socket IDs from 1 to 0BB8h, inclusive. An application may use of socket IDs from 8000h to FFFFh as they see fit. If the application requests socket ID 0, Netware will dynamically allocate a socket ID in the range of 4000h to 7FFFh. Some of the documented socket IDs used by Novell are: 451h - used by Netware file servers for service requests (Netware Core Protocol - NCP); 452h - Service Advertising Protocol (SAP); 453h - Routing Information Packet (RIP); 455h - Used by NetBIOS; 456h - Diagnostic Packet; 457h - Server Serial Number (labeled "Copy Protection" by Lanalyzer); 4000h - 7FFFh - used for dynamic allocation; 4444h, 5555h, 8000h - FFFFh - assigned by Novell.

IPXWork & DrvWork are used internally by driver and must be initialized to 0.

Immediate Address contains the address of the node the packet should be sent to or nodes in case of broadcasting. If ECB is being sent (a talker) using IPX (rather than SPX), this field should be filled in by an application. If ECB is a receiver (a listener) or uses SPX, this field is set by driver.

FragCount is filled by appliaction to tell XPX (I use XPX to refer both the IPX and SPX) how many fragment descriptions are to follow. All ECBs must have at least one fragment descriptor to point to an XPX header. The cumulative size of fragments associated with an ECB can not exceed 576 bytes. If more than 1 fragment is used, the next two fields are repeated.

FragData is a pointer to the fragment data. Application must have at least one fragment that contains a complete IPX or SPX header. Any additional data buffers can be contiguous extension of the XPX header or segmented into unconnected memory locations. Noncontiguous memory fragments require more than one fragment descriptor as stated above.

FragSize defines the number of bytes in the fragment. If the size of the first fragment is not at least the size of neither IPX nor SPX header, XPX returns an error. Fragments that follow must contain at least 1 byte.

Optional Frag desctiptions are optional and do not need to be used or declared if the first fragment descriptor describes the packet entirely.

The next structure to be defined is an IPX (or SPX) header. The application needs to fill the IPX structure only if the packet is being transmitted. If the packet is being used as a listener, XPX fills in all the fields. IPX header is 30 bytes in size and is structured in the following manner:

Table 5 - IPX Packet header
Name Size (bytes) Description
CheckSum2 Big endian checksum. Set to FFFFh (-1) by XPX
Length2 Big endian length of the entire XPX packet, including all other fragments
TC1 Transport Control (age of packet). Set to 0 by XPX
PktType1 Packet Type. Set by application to 4 for an IPX Packet or 5 for an SPX Packet, if the packet is being sent (talker). Detailed description follows
DestNetID4 Destination network ID. Set by application if packet is being sent (talker). If set to 0, the current network is used regardless of its true ID
DestNodeID6 Destination Node ID. Set by application if packet is being sent (talker). If set to all 0FFh's, the IPX packet will be sent to all IPX listeners on the network with an equal socket ID, including active listeners on transmitting node
DestSocketID2 Destination Socket ID. Set by application if packet is being sent (talker). Socket ID must be opened before socket ID can be used.
SrcNetID4 Source Network ID. Set by XPX to the network ID of the packet's source
SrcNodeID6 Source Node ID. Set by XPX to the node ID of packet's source
SrcSocketID2 Source Socket ID. Set by XPX to the socket ID of packet's source
Total:30  

PktType filled values...

If using SPX instead of IPX, the header is as shown on Table 6. SPX header is actually a superset of IPX packet header. None of the SPX-specific fields need to be filled in by the application for either transmissions on reception. These fields must be available for SPX packets.

Table 6 - SPX Packet header
Name Size (bytes) Description
IPX Header30 IPX Header as defined in Table 5
CC1 Connection Control. Used by SPX to control flow of data
DST1 Data-stream Type. Information byte that can be used by application for any purpose. Created by SPX for use by application
SrcConnID2 Source Connection ID. Connection number of source node for this SPX packet. Created by SPX for use by application
DestConnID2 Destination Connection ID. Connection number of destination node for this SPX packet. Created by SPX for use by application
SeqNr2 Sequence Number. Used by SPX to keep sequence of received and transmitted packets straight
AckNr2 Acknowledge Number. Used by SPX to acknowledge receipt of a packet
AllocNr2 Allocation Number. Used by SPX to keep track of packets sent but not acknowledged
Total:42  

The size of an SPX packet header is 12 bytes larger than the header for IPX packets. Because the headers must be part of every XPX packet, the maximum size of data can be sent with an IPX packet is 546 bytes, and the maximum for SPX is 534 bytes.


As Rahner James wrote in his article, he tried to use ESRs with his IPX function set. Experimentations yielded 100% delivery rate for over 100'000 packet transmission. To find out reasonable limit, 4 16MHz 386SX computers were used to continuously send and receive 512-byte packets. There were no loss of packets until they reached about 70 packets/second/node (280 packets/second, overall).

Before going into details, lets look at core IPX function set and how they should be treated. First thing to do is to find out the presence of an IPX driver and get it's entry vector. The code example was shown on
Sample 2
mov  bx, 9        ; BX = IPX Get Internetwork Address
mov  ax, ds       ; ES:SI -> structure to fill with the network
mov  es, ax       ; and node IDs
mov  si, offset reply_buffer

call dword ptr IPX_Vector
  

This function will always return good status (0) in AX. The buffer to by ES:SI will be filled with 0-3 (Network ID of the application's computer) or 4-9 (Node ID of the application's side).

The application would need to open a socket ID in order to communicate with the other peers. The following code would open a socket ID:

Sample 3
mov  bx, 0          ; BX = IPX Open Socket command
mov  dx, socket     ; DX = socket ID to open

mov  al, life_time  ; AL = socket longevity flag

call dword ptr IPX_Vector
  

This function returns the socket number that was opened in DX and a completion status in AL. Valid returns from this function are 00h (Socket opened), 0FFh (Socket previously opened, no problem), and 0FEh (Socket table is full, bummer).

The socket longevity flag informs XPX of how long the application intends to keep the socket open. A 0 indicates that the socket will be closed explicitly by the application or XPX should close it when the application exits back to MS-DOS. A 0FFh tells XPX to close the socket only when explicitly told to do so by the application. A 0FFh life allows the application to TSR and still maintain an open socket ID.

When the application has opened a socket ID, it must setup listeners and/or talkers. To create a listener, the application must first create an ECB and fill in the fields that deal with listening. Next, the application needs an IPX header structure and a buffer in which the received data will be placed. The fragment descriptor(s) of the ECB should point to the IPX header and the destination data buffer. If the IPX header and data buffer are one contiguous memory block, only one fragment descriptor is required. When the ECB, IPX header and data buffer are setup, a far pointer to the ECB is sent to XPX. The ECB sits with XPX until a packet comes in from the network that matches the ECB's socket ID. When the received packet is transferred to the listeners structures, the In Use Flag is set to 0 and the Completion Code field is set appropriately. If an ESR was provided by the ECB, the ESR is called by XPX. The ECB is then free to be used by the application.

To send an ECB off to the listening post, the following code fragment could be used:

Sample 4
mov  bx, 4                    ; BX = IPX Listen For Packet
les  si, offset ECB_Packet    ; ES:SI -> ECB for the packet

call dword ptr IPX_Vector
  

The function returns immediately with the status in AL. A return of 0 indicates that the ECB has been placed in a listening queue, waiting for the next incoming packet. A return of 0FFh indicates that the socket ID set within the ECB has not been opened.

The application should either poll the In Use Flag field for completion code or wait for the ESR to be called by XPX.

The application can send any number of listening packets to XPX. If a packet is received by XPX and no listener is ready to receive it, the packet and its data are lost. If a packet is lost, IPX does not inform either the destination or the source node of this condition. IPX does not guarantee delivery, SPX does.

The requirements for sending a packet is similar to setting up a listening packet. The ECB, IPX header and data buffer are set up with pertinent information. XPX can then be called with the following code fragment:

Sample 5
mov  bx, 3                    ; BX = IPX Send Packet command
les  si, offset ECB_Packet    ; ES:SI -> ECB for the packet

call dword ptr IPX_Vector
  

The function returns immediately, but has no status in AL. As with listening, the application should poll the In Use Flag/Completion Code fields for any result of the transmission.

Using IPX, if the transmitted packet does not reach its target, the source node is not informed. SPX on the other hand has methods to acknowledge packet arrival.

The Immediate Address field of the ECB needs to be filled for talking packets. If the target node is on the same network as the source node, the Immediate Address is merely the destination's node ID. If multiple networks are connected, the application needs to query XPX as to what the Immediate Address is for a full node and network ID. That query is made with the following code fragment:

Sample 6
mov  bx, 2          ; BX = IPX Get Local Target command
mov  ax, ds         ; ES = data segment of the request and
mov  es, ax         ;      reply buffer

mov  si, offset request_buffer
mov  di, offset reply_buffer

call dword ptr IPX_Vector
  

On entry ES:SI should point to the following structure 0-3 (Network ID of the destination node), 4-9 (Node ID of the destination node), or 10-11 (Socket ID of the destination node.

This function returns the status of the operation in AL. A status of 0 indicates that the network and node were found. A status of 0FAh indicates that xPX could not find a network path to the node. If the local target was found, CX will contain an estimate of the number of system ticks (1/18th of a second) that a packet would take to arrive at the destination node's socket. If the node was found, the six byte buffer pointed to by ES:DI will be filled with the Immediate Address of the target node. If the node is on another network, the local address is the node ID of the bridge to the other network.

When the application has completed its transmissions and receptions, it should disconnect from its target node(s), cancel any active events and close any open socket IDs. Informing peers and closing socket IDs are not as important as canceling any outstanding events. If an ECB is still in xPX's queue and the associated ESR vector is not NULL, xPX will still call that ESR without regard to whether the program is still operating. A call to an ESR of a program that has terminated will probably hang the computer system. If the peer is not informed of closure, packets will be ignored, but no catastrophic failure will occur. If the socket ID's longevity flag was 0 (eg. a mere mortal), the socket will be closed automatically when the program terminates.

The following code fragment will cancel an IPX event:

Sample 7
mov  bx, 6          ; BX = IPX Cancel Event command
les  si, ECB        ; ES:SI -> ECB to cancel

call dword ptr IPX_Vector
  

Status is returned in AL. If AL is 0, the ECB was canceled successfully and an 0FCh is placed in the Completion Code field of the ECB. If AL is 0FFh, the ECB was not scheduled for use. If AL is 0F9h, the ECB cannot be canceled - possibly because it is at the moment of transfer. In most instances, the return status from a Cancel Event command is immaterial

A canceled ECB does not call its associated ESR.

The following code fragment can be used to disconnect from a target address:

Sample 8
mov  bx, 0Bh        ; BX = IPX Disconnect From Target cmd
mov  ax, ds         ; ES:SI -> full address of target
mov  es, ax
mov  si, offset address

call dword ptr IPX_Vector
  

On entry ES:SI should point to the following structure:

RegionDescription
0 - 3Network ID of the target
4 - 9Node ID of the target
10-11Socket ID of the target

No status is returned from this function.

Finally, in order to explicitly close a socket ID, the following code fragment can be used:

Sample 9
mov  bx, 1          ; BX = IPX Close Socket command
mov  dx, socket_ID  ; DX = socket ID to close

call dword ptr IPX_Vector
  

There is no status returned by this function. If the socket was never open, IPX does not care. If the socket was open, all events that were associated with the socket by previous calls will be canceled. The closure of a socket ID and its associated events does not trigger a call to any ESRs.

Conclusion

IPX is a high performance protocol available on Novell NetWare networks. IPX adds a level of complexity and uncertanty to peer-to-peer communications, but can be fashioned into a useful resource. SPX is slightly slower, but guarantees data delivery.


Sources of information

More information

Literature


[My Home Page] [Library] [Net] Last Updated:

Copyright © 1997 Priidu Paomets
Design & Test Center