![]() |
![]() |
![]() |
![]() |
Functions in io-net that your driver can call
typedef struct _io_net_self { u_int nfuncs; void *(*alloc) (...); npkt_t *(*alloc_down_npkt) (...); npkt_t *(*alloc_up_npkt) (...); int (*free) (...); paddr_t (*mphys) (...); int (*reg) (...); int (*dereg) (...); int (*tx_up) (...); int (*tx_down) (...); int (*tx_done) (...); int (*reg_tx_done) (...); int (*reg_byte_pat) (...); int (*dereg_byte_pat) (...); int (*devctl) (...); int (*tx_up_start) (...); int (*memcpy_from_npkt) (...); int (*raw_devctl) (...); } io_net_self_t;
The io_net_self_t pointer points to a structure that contains io-net's functions that are accessible to your driver. You should cache this pointer (passed to you in your init() function) so that you have access to those functions later.
The nfuncs member indicates how many functions are provided in the table; it's filled automatically by io-net. The functions are described below.
The prototype is:
void *(*alloc) (size_t size, int flags)
This function allocates a buffer of the given size that's safe to pass to any other module.
There are currently no flags defined.
This function returns a pointer to the allocated buffer, or NULL if an error occurred.
The prototype is:
npkt_t *(*alloc_down_npkt) ( int registrant_hdl, size_t size, void **data)
This function allocates an npkt_t structure and initializes its internal members to values required for downward travel. The required tx_done array elements (slots) are allocated immediately implicitly following the npkt_t structure, in order to successfully reach any endpoint registrant this driver is currently connected to.
The arguments are:
This function returns a pointer to the allocated buffer, or NULL if an error occurred.
The prototype is:
npkt_t *(*alloc_up_npkt) (size_t size, void **data)
This function allocates an npkt_t and initializes its internal members to values required for upward travel, as follows:
On successful completion, data points to a buffer of size bytes in length.
This function returns a pointer to the allocated buffer, or NULL if an error occurred.
The prototype is:
int (*free) (void *ptr)
This function frees a buffer, pointed to by ptr, that was allocated by any of the above methods (alloc(), alloc_down_npkt(), and alloc_up_npkt()).
This function returns:
The prototype is:
paddr_t (*mphys) (void *ptr)
This function does a quick lookup of the physical address of the buffer, pointed to by ptr, that was allocated by any of the above methods (alloc(), alloc_down_npkt(), and alloc_up_npkt()).
This function returns the physical address of the buffer on success, or -1 if an error occurred (errno is set).
This call binds your driver to io-net. The prototype is:
int (*reg) (void *dll_hdl, io_net_registrant_t *registrant, int *reg_hdlp, uint16_t *cell, uint16_t *endpoint)
The arguments are:
This function returns:
The prototype is:
int (*dereg) (int registrant_hdl)
Deregister from io-net. Note that if a shared object has registered multiple times, its main shared object shutdown function (defined in the io_net_dll_entry_t structure) isn't called until after all registrants have deregistered.
The registrant_hdl argument is the registrant handle that was filled in when your driver registered by calling io-net's reg() function.
This function returns EOK on success, or an error code.
The prototype is:
int (*tx_up) (int registrant_hdl, npkt_t *npkt, int off, int framlen_sub, uint16_t cell, uint16_t endpoint, uint16_t iface)
This function sends a packet to the layer above you. The arguments are:
The iface is for internal use and lets a single registrant present multiple interfaces of the same type to upper modules. It should start at 0 and increase sequentially. In the case of a driver talking to hardware (a simple up producer with no modules below it), it's actually more flexible to register multiple times if multiple interfaces are present (once for each interface). In this case, the iface parameter is always 0.
On success, tx_up() returns the number of modules above the calling module that took the packet (which could be 0). If an error occurred, tx_up() returns -1, and errno is set.
The prototype is:
int (*tx_down) (int registrant_hdl, npkt_t *npkt)
This function sends a packet, pointed to by npkt, down to the layer below you. The registrant_hdl argument is the registrant handle that was filled in when your driver registered by calling io-net's reg() function. The destination that you're trying to reach is stored in the cell, endpoint, and iface members of npkt.
This function returns:
The prototype is:
int (*tx_done) (int registrant_hdl, npkt_t *npkt)
For downward-headed packets, this function is called once by the module that consumes the packet. This causes the chain of tx_done() functions stored in npkt to be called in LIFO order (see the reg_tx_done() function, below).
The registrant_hdl argument is the registrant handle that was filled in when your driver registered by calling io-net's reg() function.
For upward-headed packets, this function is called by each module (including the originator) when finished with the packet. The single tx_done() stored in the packet is called when the ref_cnt member goes to zero.
This function returns:
The prototype is:
int (*reg_tx_done) (int registrant_hdl, npkt_t *npkt, void *done_hdl)
This function is used to store a tx_done() callback in a packet. It's called once by the originator for upward-headed packets, and called by every module that adds to the npkt buffer chain for downward-headed packets. You must call this function rather than stuffing the value directly because io-net keeps track of how many tx_done() functions a module has outstanding (used for unmounting the module).
The arguments are:
This function returns:
The prototype is:
int (*reg_byte_pat) (int registrant_hdl, unsigned off, unsigned len, unsigned char *pat, unsigned flags)
Before a module will receive any upward-headed packets, it must register with io-net to indicate what subtype it wants. This is in place to allow packet filtering, so that the module isn't getting packets that it won't be dealing with. The module already specified its bottom type when it registered (e.g. en to specify Ethernet subtypes 0x0800 and 0x0806 (for ARP), or the IP protocol type PROT_QNET for qnet).
The arguments are:
![]() |
Your module must register for some kind of byte pattern, or it won't get any up-headed packets. |
This function returns:
The prototype is:
int (*dereg_byte_pat) (int registrant_hdl, unsigned off, unsigned len, unsigned char *pat, unsigned flags)
This function deregisters a byte pattern from io-net.
The arguments are:
This function returns:
The prototype is:
int (*devctl) (int registrant_hdl, int dcmd, void *data, size_t size, int *ret)
Send a devctl() command to io-net.
The arguments are:
This function returns EOK on success, or an error code.
The prototype is:
npkt_t *(*tx_up_start) (int registrant_hdl, nptk_t *npkt, int off, int framelen_sub, uint16_t cell, uint16_t endpoint, uint16_t iface, void *done_hdl)
A utility function for use by originators of up-headed packets.
This function efficiently combines io-net's reg_tx_done(), tx_up() and tx_done() functions (three common operations for originators of up-packets) as follows:
reg_tx_done (reg_hdl, npkt, done_hdl); tx_up (reg_hdl, npkt, off, framelen_sub, cell, endpoint, iface); tx_done (reg_hdl, nptk);
The arguments are:
The iface argument is for internal use and lets a single registrant present multiple interfaces of the same type to upper modules. It should start at 0 and increase sequentially. In the case of a driver talking to hardware (a simple up producer with no modules below it), it's actually more flexible to register multiple times if multiple interfaces are present (once for each interface). In this case, the iface parameter is always 0.
This function returns a linked list of npkt structures for which a tx_done() callback couldn't be registered (i.e. for which reg_tx_done() failed. If this is non-NULL, errno is set.
The prototype is:
int (*memcpy_from_npkt) (const iov_t *dst, int dparts, int doff, const npkt_t *snpkt, int soff, int smax_len)
This utility function is generally useful for copying data from packets. It's similar to memcpyv(). The arguments are:
The return value is the number of bytes copied.
This function is used when writing a _REG_FILTER_ABOVE module that sits above, say, all Ethernet registrants, and is passed all open() calls so it can then handle all read()s, write()s, etc., to that device. The only I/O message that io-net is concerned about is the message corresponding to the devctl() function call, so if the filter gets a devctl() that it can't handle, it calls this function. The prototype is:
int (*raw_devctl) (resmgr_context_t *ctp, io_devctl_t *m, io_net_iofunc_attr_t *attr)
This function returns EOK on success, or an error code on failure.
QNX
![]() |
![]() |
![]() |
![]() |