Title: eth_fd_t / nwio_ethopt

If an ip port uses the ethernet data-link layer or an ethernet device file (e.g., /dev/eth) is opened directly, an ethernet file descriptor must be acquired. The relationships between various file descriptors and ports is shown in the following diagram:

typedef struct eth_fd

       int ef_flags;
       nwio_ethopt_t ef_ethopt;
       eth_port_t *ef_port;
       struct eth_fd *ef_type_next;
       int ef_srfd;
       acc_t *ef_rdbuf_head;
       acc_t *ef_rdbuf_tail;
       get_userdata_t ef_get_userdata;
       put_userdata_t ef_put_userdata;
       put_pkt_t ef_put_pkt;
       time_t ef_exp_time;
       size_t ef_write_count;
} eth_fd_t;
int ef_flags:

ef_flags can be the following:

#define EFF_FLAGS 0xf
#define EFF_EMPTY 0x0
#define EFF_INUSE 0x1
#define EFF_BUSY 0x6
#define EFF_READ_IP 0x2
#define EFF_WRITE_IP 0x4
#define EFF_OPTSET 0x8

ef_flags is initialized to EFF_EMPTY, but once the ethernet file descriptor is opened, ef_flags is set to EFF_INUSE. If the ethernet file descriptor has been configured and the nweo_flags (see below) are valid, the EFF_OPTSET (OPTions SET) flag is set. Only then can the ethernet file descriptor be used.

The EFF_BUSY flag is never set. The meaning of the other flags is self-explanatory.

nwio_ethopt_t ef_ethopt:

typedef struct nwio_ethopt

u32_t nweo_flags;
ether_addr_t nweo_multi, nweo_rem;
ether_type_t nweo_type;
} nwio_ethopt_t;


If the ethernet file descriptor was opened by the ip code, the following flags and type will be set:

nweo_type= HTONS(ETH_IP_PROTO);

#define NWEO_NOFLAGS 0x0000L

#define NWEO_ACC_MASK 0x0003L
#define NWEO_EXCL 0x00000001L
#define NWEO_SHARED 0x00000002L
#define NWEO_COPY 0x00000003L

From ip(4):

"If NWEO_SHARED is selected, then multiple channels (which all must select NWEO_SHARED) can use the same Ethernet type and they can all send packets. However, incoming packets will be delivered to at most one of them."

Note that, for whatever reason, NWEO_EXCL behaves exactly as NWEO_COPY. Every ethernet file descriptor so configured receives a copy of an incoming packet.

The access flags are important when an ethernet packet is being read.

#define NWEO_LOC_MASK 0x0010L

#define NWEO_BROAD_MASK 0x0020L
#define NWEO_EN_BROAD 0x00000020L
#define NWEO_DI_BROAD 0x00200000L

NWEO_EN_BROAD enables the receipt of broadcast packets.

#define NWEO_MULTI_MASK 0x0040L
#define NWEO_EN_MULTI 0x00000040L
#define NWEO_DI_MULTI 0x00400000L

NWEO_EN_MULTI enables the receipt of multicast packets. The nweo_multi field does not appear to be used in any meaningful way.

#define NWEO_PROMISC_MASK 0x0080L
#define NWEO_EN_PROMISC 0x00000080L
#define NWEO_DI_PROMISC 0x00800000L

If an ethernet file descriptor is in promiscuous mode, the file descriptor not only accepts any packet regardless of destination ethernet address but can also send out packets with any source ethernet address (not just the ethernet card's address).

If this is not the case, use the ethernet port's ethernet address.

#define NWEO_REM_MASK 0x0100L
#define NWEO_REMSPEC 0x00000100L
#define NWEO_REMANY 0x01000000L

From ip(4):

"NWEO_REMSPEC restricts sending and receiving of packets to the single remote computer specified in the nweo_rem field."

If the NWEO_REMANY flag is set, an ethernet packet may have any destination.

#define NWEO_TYPE_MASK 0x0200L
#define NWEO_TYPESPEC 0x00000200L
#define NWEO_TYPEANY 0x02000000L

From ip(4):

"NWEO_TYPESPEC restricts sending and receiving of packets to the type specified in nweo_type."

If the NWEO_TYPESPEC flag is set, the nweo_type field (see below) may be one of the following:

#define ETH_RARP_PROTO 0x8035
#define ETH_ARP_PROTO 0x806
#define ETH_IP_PROTO 0x800

#define NWEO_RW_MASK 0x1000L
#define NWEO_RWDATONLY 0x00001000L
#define NWEO_RWDATALL 0x10000000L

From ip(4):

"If the Ethernet header is completely specified by the nweo_flags (i.e.,
NWEO_REMSPEC and NWEO_TYPESPEC are specified), then NWEO_RWDATONLY can be
used to send and receive only the data part of an Ethernet packet."

The default for the ethernet file descriptors opened by the ip and arp layers is NWEO_RWDATALL.

ether_addr_t nweo_multi:

This field is not used in any meaningful way.


Used with the NWEO_REMSPEC flag (see above).

ether_type_t nweo_type:

Used with the NWEO_TYPESPEC flag (see above). The nweo_type field may be one of the following:

#define ETH_RARP_PROTO 0x8035
#define ETH_ARP_PROTO 0x806
#define ETH_IP_PROTO 0x800

eth_port_t *ef_port:

All ethernet file descriptors have an associated ethernet port (see figure above). ef_port is this associated ethernet port.

struct eth_fd *ef_type_next:

Two linked lists (actually, one linked list and one array of linked lists) of ethernet file descriptors in an ethernet port are etp_type_any and etp_type[]. ef_type_next links the ethernet file descriptors in these two linked lists.

int ef_srfd:

If the ip layer opens up this ethernet file descriptor, then ef_srfd will be the ip port that corresponds to this ethernet file descriptor. If the ethernet file descriptor is opened up directly (and eth_open() is called indirectly), then ef_srfd will be the corresponding slot in sr_fd_table[].

acc_t *ef_rdbuf_head; acc_t *ef_rdbuf_tail:

Incoming packets are placed in the ef_rdbuf_head/ef_rdbuf_tail linked list if the ethernet file descriptor is not being read (i.e., the EFF_READ_IP flag is not set).

get_userdata_t ef_get_userdata; put_userdata_t ef_put_userdata:

If the ip layer opens up this ethernet file descriptor, then ef_get_userdata will be get_eth_data() and ef_put_userdata will be put_eth_data(). If the ethernet file descriptor is opened up directly (and eth_open() is called indirectly), then ef_get_userdata will be set to sr_get_userdata (which copies data from a user process to a buffer in the network process) and ef_put_userdata will be set to sr_put_userdata (which copies data from a buffer in the network process to a user process).

put_pkt_t ef_put_pkt:

ef_put_pkt is set to ip_eth_arrived() by eth_open(). ip_eth_arrived() moves a packet from the ethernet layer to the ip layer.

time_t ef_exp_time:

ef_exp_time is the expiration timer for the read queue. If the ethernet file descriptor's read queue is empty and packet2user() was not able to pass a packet that arrived from the ethernet task to the higher layer (e.g., the ip code), packet2user() places the packet in the read queue and sets the timer. Note that there is only a single timer for the read queue so if the timer has expired for the first packet, all of the packets will be discarded.

size_t ef_write_count:

ef_write_count is the size (in bytes) of the next packet to be sent out the ethernet file descriptor. If an ip port is associated with the ethernet file descriptor, this packet is in the ip port's de_frame field.