Sending a packet to all machines is called a BROADCAST.
These packets have a specific structure which is shown in figure 1.

                        Figure 1 - The IPX header
   ------------------------------------------------------------------------
   | Name          | Size (bytes) | Description                           |
   ----------------|--------------|---------------------------------------|
   |Check          | 2 bytes      | Bigendian check sum                   |
   |Length         | 2 bytes      | Bigendian length of packet            |
   |tc             | 1 byte       | Transport control (age of packet)     |
   |pType          | 1 byte       | Packet type  (always use 0)           |
   |dest           | 12 bytes     | Address of destination node           |
   |src            | 12 bytes     | Address of source node                |
   ----------------|--------------|---------------------------------------|

  By the way, bigendian means that the first byte holds the most significant
value, which is the opposite of the normal way of doing things on the PC.

  For reasons better known to Novell, the checksum is always set to $ffff.
The length field contains the total length of the packet, including the IPX
header.  Transport control keeps a count of the number of routers a packet
has been through.  The format of the address is shown in Figure 2.

                       Figure 2 - The net address field
   ------------------------------------------------------------------------
   | Name          | Size (bytes) | Description                           |
   ----------------|--------------|---------------------------------------|
   |network        | 4 bytes      | Network address                       |
   |node           | 6 bytes      | Node address                          |
   |socket         | 2 byte       | Socket number                         |
   ----------------|--------------|---------------------------------------|

  Sockets are a device that lets a node decide if it will act on a packet.
It allows multiple programs on the one PC to use IPX packets completely
transparent to the others.  It also means that a broadcasted packet will only
be received by a machine if it has a socket open for that which the packet is
addressed.  So packets can be ignored by nodes that are not capable of
accepting them.  Special care must be taken to ensure that no two programs try
to send different types of packets to the same socket!

  The next order of bussiness is to tell the PC that we want to open a socket.
This is accomplished by creating an Event Control Block (ECB).  Figure 3 shows
the format of the ECB.

                      Figure 3 - Format of the ECB
   ------------------------------------------------------------------------
   | Name          | Size (bytes) | Description                           |
   ----------------|--------------|---------------------------------------|
   |Link           | 4 bytes      | Pointer to next ECB?                  |
   |ESR            | 4 bytes      | Pointer to Event Service Routine      |
   |InUse          | 1 byte       | Flag telling the ECB status           |
   |complete       | 1 byte       | Flag telling the ECB completion code  |
   |socket         | 2 bytes      | Bigendian socket number for ECB       |
   |IPXwork        | 4 bytes      | Work space for IPX                    |
   |Dwork          | 12 bytes     | Work space for driver                 |
   |immedAddr      | 12 bytes     | Address to send to.                   |
   |fragCount      | 2 bytes      | Number of fragments                   |
   |FragData       | 4 bytes      | Pointer to data fragment              |
   |FragSize       | 2 bytes      | Size of data fragment                 |
   ----------------|--------------|---------------------------------------|

  All the fields in the ECB should be set to zero before initializing the ECB.
This makes the code to initialize the ECB much nicer!  No ESR is used in my
routines which means the the program must constantly ckeck the ECB to see if
a packet has arrived.  I don't see this as any great drawback however.

  To send a broadcast, set the node address to all $ff.  This is done
automatically by my routines.

  FragData must be initialized to point to the IPX header and the data we want
to send MUST follow directly after this header.  An example of this can be
seen in Appendix B in the definition of the record type "Packet".  The ECB
need not be included in the packet record, but for simplicity I chose to do
so.

  The procedures InitSendPacket and InitReceivePacket give examples of the
initialization of both the ECB and IPX header.

  Once all of the fields are initialized, it is necessary to tell the IPX
driver about our ECB.  This is done by first opening a socket to use.
Interrupt $7A is assigned to the Novell API, and is the old way of accessing
the routines.  It is however a much easier to use than the recommended method
(in my opinion anyway).  The sub-functions that we use are given in Table 1.

                                Table 1
-----------------------------------------------------------------------------
|Function|Name        |Regs                                                 |
-----------------------------------------------------------------------------
|  $0000 |Open Socket |AL=Longevity  DX=Socket number  (bigendian)          |
|        |            |Returns:AL=Error code  DX=Socket Number  (bigendian) |
-----------------------------------------------------------------------------
|  $0001 |Close Socket|DX=Socket number  (bigendian)                        |
-----------------------------------------------------------------------------
|  $0003 |Send Packet |ES=Seg of ECB  SI=Offset of ECB                      |
-----------------------------------------------------------------------------
|  $0004 |Listen for  |ES=Seg of ECB  SI=Offset of ECB                      |
|        |packet      |Returns:AL=Error code                                |
-----------------------------------------------------------------------------
|  $0009 |Get Local   |ES=Seg of address array   SI=Offset of address array |
|        |Address     |                                                     |
-----------------------------------------------------------------------------
|  $000A |Im Idle     |None                                                 |
-----------------------------------------------------------------------------

  NOTE:  The function number is stored in BX.

  After attempting to open a socket it is advisable to test if IPX is
present.  This is done by calling int $2F with AX=$7F00.  If on return AL
does not  contain $FF, then IPX is not installed.  This is also a good point
to get your local address as your program should only have to do this once.
See the procedure InitIPX in appendix A for an example of this.

  Once we have an open socket and some set up ECBs and IPX headers, we can
tell the IPX driver about them.   First we will look at a recieving ECB and
IPX header, followed by a sending.

  For a recieve record, the IPX header does not need to be initialized at all.
However, I think it is a good idea to zero all the fields just be on the safe
side.  The ECB however, does need to have several fields set.  The inUse flag
should be set to $1D  (don't ask me why, actually it works without this, but
several of the recources I consulted did this).  The socket number must be
initialized, and remember, this is bigendian so be careful!  Finally the
fragCount, fragData and fragSize fields must be set.  All the other fields
should be set to zero!

  Once all these fields are set, call "Listen For Packet" to tell the IPX
driver about the ECB.  This will return immediatly, but if any packets arrive
for that socket they will be placed into the record.  To see if a packet has
arrived, it is necessary to check the InUse flag in the ECB.  If this is $00,
then a packet has arrived and needs to be processed before another can be
accepted.  If a packet arrives when there is an unprocessed packet, then it
will be lost.  This means that a packet should be processed as soon as
possible.  The record can be released by simply calling "Listen For Packet"
again.

  OK, we now have a recieve record waiting for a packet to arrive.  Now we
need a send record!  A send record needs all of the same fields as a receive
record, but on top of that it also needs the IPX header to be filled in.
The checksum is set to $ffff and the packet type is set to $00 (this is a
packet exchange packet).  Next the destination address is set.  For a
broadcast you should set the net address to your local net address, the node
sould be the broadcast node ($ff,$ff,$ff,$ff,$ff,$ff) and the socket should be
set up.  Your program should set up the source address with the info from the
localAddr record, and the source socket can be anything, but again, for
simplicity I usually set it to the same value as the destination socket.

  We then put some data into the data portion of the record and call "Send
Packet".  The packet will then be sent to the destination node on the network.
If the node field is set to the broadcast address, the packet will be sent to
all nodes on the network, including the source node.

  As a point of interest, you should call "Im idle" whenever your program
isn't doing anything an particular to allow the IPX driver to run more
quickly.