cnet v4.0.4  

home topology files command‑line options the core API FAQ download and install

cnet's Physical Layer

The Physical Layer attempts to deliver data frames between nodes. Frames are delivered along any combination of wide-area-networking (WAN), local-area-networking (LAN), or wireless-local-area-networking (WLAN) links.

Each physical link is numbered within each node from 1 to its total number of links. As a special case, link 0 represents a loopback link, and is provided to simply copy a frame immediately from a node's output to input. In general, the Physical Layer will randomly corrupt and drop data frames on all WAN, LAN, or WLAN links, but not on the loopback link or Ethernet segments.

When your protocols wish to transmit a data frame along a link, they write that frame to the Physical Layer. On calling the CNET_write_physical function, you indicate the length of the frame to be written and on return CNET_write_physical indicates how many bytes were accepted. A typical sequence for a network of just 2 nodes, connected by a single WAN link is:

char myframe[ MAX_MESSAGE_SIZE + MY_OVERHEAD ]; size_t length; ... // prepare frame contents for transmission length = ... ; result = CNET_write_physical(1, myframe, &length);

When cnet informs the destination node that a frame has arrived, the handler for EV_PHYSICALREADY should read that frame. On return from a successful call to CNET_read_physical, your protocol is informed on which link the frame arrived and how long it was.

Of course, in a simple network with just one WAN connection or one Ethernet segment, all frames will be transmitted and will arrive on link number 1. WAN links impose no particular format on the frames written to it; unless corrupted or lost, whatever is written to a WAN link will arrive unmodified, and without interpretation, at the other end of the link.

As an aid to debugging protocols, the function CNET_write_physical() will 'trap' the situation when a large number of frames have been written to the Physical Layer, and when the receiving node has not read any of them off. This trap is currently set at the large value of 1000, which surely indicates an error in a protocol. An errant protocol may have some unbounded loop, or a very short timeout-and-retransmission sequence, resulting in many calls to CNET_write_physical() at the sender, before any EV_PHYSICALREADY events are handled at the receiver. If the frame limit is exceeded, CNET_write_physical() will return -1 and set cnet_errno to ER_TOOBUSY.

char myframe[ MAX_MESSAGE_SIZE + MY_OVERHEAD ]; size_t length; int link; length = sizeof(myframe); result = CNET_read_physical(&link, myframe, &length); ... // process frame contents

To provide some sense of realism, frames (or packets) written to Ethernet links are expected to carry the address of their destination Network Interface Card (NIC) at the very beginning of the frame. cnet provides the data type CnetNICaddr to represent the addresses of its NICs, as an array of LEN_NICADDR (=6) unsigned characters.

cnet interprets the leading LEN_NICADDR bytes of each frame on an Ethernet segment to be an address. The special address, whose string representation is ff:ff:ff:ff:ff:ff, is interpreted as the Ethernet broadcast address. Any frame carrying the broadcast address as its destination address will be delivered to all NICs on the Ethernet segment, except the sender. cnet does not support multicast or group addressing.

Consider the following example function, used to write data to an Ethernet segment:

typedef struct { CnetNICaddr dest; CnetNICaddr src; char type[2]; char data[ETH_MAXDATA]; } ETHERPACKET; #define LEN_ETHERHEADER (sizeof(ETHERPACKET) - ETH_MAXDATA) static void write_to_ethernet(CnetNICaddr dest, int link, char *buf, size_t len) { ETHERPACKET packet; short int twobytes; memcpy(packet.dest, dest, sizeof(CnetNICaddr)); memcpy(packet.src, linkinfo[link].nicaddr, sizeof(CnetNICaddr)); twobytes = len; // type carries the data's true length memcpy(packet.type, &twobytes, 2); memcpy(packet.data, buf, len); len += LEN_ETHERHEADER; if(len < ETH_MINPACKET) // pad short packets to minimum length len = ETH_MINPACKET; CHECK(CNET_write_physical(link, (char *)&packet, &len)); ...... }

This function assumes that the data's length is not too long for Ethernet (<= ETH_MAXDATA (=1500) bytes). The required destination's NIC address is first copied to the destination address field, and then the address of the local NIC used copied to the source address field. Notice that because the CnetNICaddr type is actually an array of characters, we do not use the & operator in the calls to memcpy.

The data's true length is copied into the packet's two-byte type field, the provided data copied to the packet's data. After ensuring that the packet to be written is at least ETH_MINPACKET (=64) bytes long, the packet is written to the link.

Again, cnet does not enforce (nor understand) the use of our ETHERPACKET data type, but does assume that the first LEN_NICADDR bytes of each packet provides the destination NIC address.

Two additional Physical Layer functions are provided to assist in the debugging of multi-layered protocols. CNET_write_physical_reliable is identical to CNET_write_physical except that frames sent using it will not be subject to frame corruption or loss. It can be considered as a "perfect" Data Link Layer if you just want to implement higher-layered protocols. The function CNET_write_direct also bypasses all Physical Layer errors and instructs a message to be sent directly to the node whose address is specified as a parameter. It thus provides perfect a Data Link Layer and Network Layer.


cnet v4.0.4 - [email protected]