Title: ip_fd / ip_fd_table[]

If a process opens up an ip device file (e.g., /dev/ip), an "ip file descriptor" is acquired to handle all read, write, and ioctl operations. Also, during the initialization of the higher-layer protocols (e.g., udp), an ip file descriptor is acquired to handle the read, write, and ioctl operations from the higher-layer port (e.g., udp_port). The relationships between various ports and file descriptors are shown in this figure:

ip file descriptors are ip_fd struct's. ip_fd_table[] is an array of all the ip file descriptors.

typedef struct ip_fd

int if_flags;
struct nwio_ipopt if_ipopt;
ip_port_t *if_port;
struct ip_fd *if_proto_next;
int if_srfd;
acc_t *if_rdbuf_head;
acc_t *if_rdbuf_tail;
get_userdata_t if_get_userdata;
put_userdata_t if_put_userdata;
put_pkt_t if_put_pkt;
time_t if_exp_time;
size_t if_rd_count;
} ip_fd_t;

typedef struct nwio_ipopt
u32_t nwio_flags;
ipaddr_t nwio_rem;
ip_hdropt_t nwio_hdropt;
u8_t nwio_tos;
u8_t nwio_ttl;
u8_t nwio_df;
ipproto_t nwio_proto;
} nwio_ipopt_t;

typedef struct ip_hdropt
u8_t iho_opt_siz;
} ip_hdropt_t;
int if_flags:

#define IFF_EMPTY 0x0
#define IFF_INUSE 0x1
#define IFF_OPTSET 0x2
#define IFF_BUSY 0xC
#define IFF_READ_IP 0x4
#define IFF_GIPCONF_IP 0x8

During the initialization of ip_fd_table[], each ip_fd is set to IFF_EMPTY. After the ip file descriptor has been allocated, IFF_INUSE is set to indicate that the ip file descriptor is no longer available. And after the ip file descriptor has been configured, IFF_OPTSET is set. The ip file descriptor cannot be used until it has been configured. Later, when a higher layer (e.g., udp) wants to read from the ip file descriptor, the IFF_READ_IP flag is set.

struct nwio_ipopt if_ipopt: (fields shown below)

ip_port_t *if_port:

if_port points to the ip file descriptor's associated ip port. For example, if udp_port_table[0] is being initialized, ip_open() returns an ip file descriptor. if_port of this ip file descriptor will point to ip_port_table[0].

struct ip_fd *if_proto_next:

Points to the next ip file descriptor in the ip_proto[] or ip_proto_any linked lists.

int if_srfd:

if_srfd is the port number/file descriptor of the layer immediately above the ip layer. For example, if udp opens up this file descriptor, if_srfd will be the port number of the port that opened up this ip file descriptor. If, on the other hand, this file descriptor is opened up directly by the user (i.e., the user opens up /dev/ip instead of /dev/tcp or /dev/up), if_srfd will be the corresponding slot in sr_fd_table[]. Since if_srfd could be either a port or a file descriptor (fd), if_srfd is probably not the best name for this field.

acc_t *if_rdbuf_head:
acc_t *if_rdbuf_tail:

if_rdbuf_head is the head of a linked list of buffers (acc_t struct's) that are waiting to be read by a higher layer (e.g., udp). The acc_t struct's are linked together by the acc_ext_link field.

get_userdata_t if_get_userdata:
put_userdata_t if_put_userdata:
put_pkt_t if_put_pkt:

The three fields above are all pointers to functions that move packets and configuration data from one layer to the next. For example, if the udp code opens up an ip file descriptor, if_get_userdata, if_put_userdata, and if_put_pkt are set to udp_get_data(), udp_put_data(), and udp_ip_arrived().

These three functions are used to move packets and configuration data to and from the layer above (e.g., udp).

time_t if_exp_time:

Only a certain amount of time can pass from the time a packet is placed in the ip file descriptor's read queue until the packet is read. if_exp_time is this expiration time for the packet. If the packet is not read, the packet and all the later packets in the queue are deleted.

size_t if_rd_count:

The number of bytes to be read. if_rd_count is set in ip_read(). If the udp code opened up the ip file descriptor, this if_rd_count is always UDP_MAX_DATAGRAM.

u32_t nwio_flags:

nwio_flags will be a combination of the flags below. Most of the flags within a set are exclusionary. For example, both NWIO_REMSPEC and NWIO_REMANY can't both be set.

Note that "EN" stands for "ENable" and "DI" stands for "DIsable".

#define NWIO_EXCL 0x00000001l
#define NWIO_SHARED 0x00000002l
#define NWIO_COPY 0x00000003l

From ip(4):

"The options covered by NWIO_ACC_MASK control the number of channels that can use one IP protocol. If NWIO_EXCL is specified then only that channel can use a certain IP protocol. If NWIO_SHARED then multiple channels that all have to specify NWIO_SHARED can use the same IP protocol, but incoming packets will be delivered to a most one channel. NWIO_COPY does not impose any restrictions. Every channel gets a copy of an incoming packet."

Note that, for whatever reason, NWIO_EXCL behaves exactly as NWIO_COPY. Every channel receives a copy of an incoming packet.

The access flags are important during the read of an ip packet.

#define NWIO_EN_LOC 0x00000010l
#define NWIO_DI_LOC 0x00100000l
#define NWIO_EN_BROAD 0x00000020l
#define NWIO_DI_BROAD 0x00200000l

NWIO_EN_LOC specifies that this file descriptor can receive packets destined for this machine and NWIO_EN_BROAD specifies that this file descriptor can receive broadcast packets.

#define NWIO_REMSPEC 0x00000100l
#define NWIO_REMANY 0x01000000l

If the NWIO_REMANY flag is set, this file descriptor can send packets to any destination. If, on the other hand, the NWIO_REMSPEC flag is set, this file descriptor can only communicate with a single host. This host is specified by nwio_rem (see below).

#define NWIO_PROTOSPEC 0x00000200l
#define NWIO_PROTOANY 0x02000000l

If NWIO_PROTOANY is set, the ip file descriptor will accept packets of any protocol type. However, if NWIO_PROTOSPEC is set, only packets with a protocol type of nwio_proto (see below) are accepted.

#define NWIO_HDR_O_SPEC 0x00000400l
#define NWIO_HDR_O_ANY 0x04000000l

If the NWIO_HDR_O_SPEC flag in nwio_flags is set, nwio_hdropt (see below) must be set. If this is the case, the extra header information for all outgoing packets will be taken from nwio_hdropt, nwio_tos, nwio_ttl, and nwio_df (see below).

#define NWIO_RWDATONLY 0x00001000l
#define NWIO_RWDATALL 0x10000000l

NWIO_RWDATALL is a little tricky. If the NWIO_RWDATALL flag is set, the header was omitted when passing the packet down to ip code and the NWIO_EN_LOC, NWIO_DI_BROAD, NWIO_REMSPEC, NWIO_PROTOSPEC and NWIO_HDR_O_SPEC flags must all be set (and NWIO_REMANY and NWIO_PROTOANY cannot be set). In other words, this file descriptor can only send the data to one destination using one protocol.

During the configuration of an ip file descriptor being opened by the udp code, ip_ioctl() calls udp_get_data() (indirectly) to get configuration information. udp_get_data() returns the following configuration information:


ipaddr_t nwio_rem:

If the NWIO_REMSPEC flag in nwio_flags is set (see above), nwio_rem is the ip address of the destination host.

ip_hdropt_t nwio_hdropt:

The ip header length is flexible to allow for extra options. For example, in addition to the normal fields (e.g., destination ip address), an ip header may specify the route it wishes to take or request that the route be recorded.

that it wishes to record a route or to ip_chk_hdropt().

u8_t nwio_tos:

"tos" stands for "Type Of Service". nwio_tos is initialized to 0 but can be changed by ip_ioctl().

u8_t nwio_ttl:

"ttl" stands for "Time To Live", which is the number of hops that a packet can take before being dropped by a router. nwio_ttl is initialized to 255 but can be changed by ip_ioctl().

u8_t nwio_df:

nwio_df specifies whether fragmentation is allowed or not. nwio_df is initialized to FALSE but, again, can be changed by ip_ioctl().

ipproto_t nwio_proto:

nwio_proto can take one of the values below. Obviously, if the udp code opens up an ip file descriptor, nwio_proto will be IPPROTO_UDP. The same is true for icmp and tcp.

#define IPPROTO_ICMP 1
#define IPPROTO_TCP 6
#define IPPROTO_UDP 17

This field is used in conjunction with the NWIO_PROTOSPEC flag in nwio_flags. If this flag is set, nwio_proto must be set.

ip_hdropt: If the NWIO_HDR_O_SPEC flag is set (see above), any outgoing packets will have ip options as specified by iho_data[]. The length of the options will then be iho_opt_siz.

u8_t iho_opt_siz: The length of the options.

u8_t iho_data[IP_MAX_HDR_SIZE-IP_MIN_HDR_SIZE]: The actual options.