Show link.asc syntax highlighted
liblink: The EmStar Link Interface Library
==========================================
/*********************************************************************
Link Library Interface
The Link API consists of a group of libraries, data structures, and
support functions that define the basic IPC interface between all
components in the EmStar framework.
The Link Interface is written on top of the other libraries, like the
packet device library, the status device library and the command
device library. Many of its functions are simply wrappers around
other library calls.
By using the Link Interface, all EmStar components can be linked
together using string names. By default, when a module registers an
interface, the link library will automatically create the following
hierarchical structure:
/dev/link/<name>/data
/dev/link/<name>/status
/dev/link/<name>/command
where <name> is, for example, udp0, mote0, smac0, etc. All network
stack components will support a common command-line options format,
--uses and --provides to specify which name is used/provided. This is
the standard command line option to define the linkage of all the
components in EmStar from the configuration file. By supporting
names, users are free to establish any naming convention without
modifying a single line of code.
The main design philosophy has been to do as much as possible in the
library without the user (the EmStar module programmer) having to
worry about many mundane details. The library performs type and error
checking, it answers status queries of the interfaces, and many other
things.
The framework basically consists of two parts: the link provider and
the link user part. Most of the library calls, data structures, and
callbacks definitions follow the naming convention lp_* for link
provider functions, and lu_* for link user functions.
The link provider (lp) part consist of all the functions that support
the creation of interfaces that are provided or exported to other
EmStar modules. For example, there could be functions to register
interfaces at run time, to send/receive packets to/from interface
users, etc.
The link user (lu) part consist of all the functions that support
usage of interfaces that are provided or exported by other EmStar
modules. For example, there could be functions to open the interface,
to send and receive data from it, to access internal data structures,
etc.
*********************************************************************/
/********************************************************************/
/* interfaces to functions in liblink - the link library interface */
/********************************************************************/
/* common declarations for both link USERS and PROVIDERS functions */
/* maximum string device name for link devices */
#define MAX_DEV_NAME 127
/* common options for both the users and providers of link services */
typedef struct link_opts {
char *dev_name; /* the name of the device is used to
* differentiate multiple links of the
* the same type that might be on the
* machine. */
pd_queue_opts_t q_opts; /* Queue length and loopback options */
pkt_type_t pkt_type; /* packet type assoc with this link,
* if any. used to filter for uses,
* for documentation in provides */
void *data; /* Data pointer used by apps */
} link_opts_t;
/********************************************************************/
/******************** Link Provider Interface ***********************/
/********************************************************************/
/* typedef link provider context */
typedef struct _lp_context lp_context_t;
#define LP_BLOCKED PD_BLOCKED
/**************** Typdefs for link provider callbacks ***************/
/*********************************************************************
send: callback used by the link provider to receive packets from link
users.
This function is not called directly by link users, but called by the
link interface framework when it is service its write queue, and has
a packet to send from a client send queue to the layer below. packet
and packetlen are the data and length to be sent. If 'loop_needed'
is set to 1, then it means at least one client wants to receive
outgoing packets; call lp_loop_receive after doing any transformation
on the packet that might be required before loopback delivery.
The return value of the send callback should be:
* 0, if the packet was handled without error, and the link library
is ready to send other packet (i.e. it's okay to call send() again)
* An -errno value (e.g. -EMSGSIZE) if the packet was processed and an
error was encountered. Note that this error value will probably not
reach the link user (unless it is in non-queue synchronous mode)
since its write() will have already completed. Therefore, it is best
to return as many errors as possible in the (nonblocking) enqueue()
callback instead.
* LP_BLOCKED, if this packet is still being processed. If the
callback returns this value, it must later call lp_unblock() to let
the framework know that it is OK to send packets again. The data
pointed to by "packet" will continue to be valid until lp_unblock()
is called. Note that it is legal to call lp_unblock() from within
the send() callback and then return LP_BLOCKED.
*********************************************************************/
typedef int (*lp_send_cb_t)(lp_context_t *lp, const link_pkt_t *link_pkt,
int data_len, int loop_needed);
/*********************************************************************
enqueue: callback used by the link provider to do verification of
packets from link users.
This function is called when a link user tries to send a packet.
This is a good place for the link provider to check the packet for
validity of a packet; at send() time, the link user can no longer
receive errors, since its write() has already completed. Should
return 0 if the packet is allowed to be enqueued, or a negative errno
(e.g. -EINVAL) if the packet should be rejected.
*********************************************************************/
typedef int (*lp_enqueue_cb_t)(lp_context_t *lp, const void *packet,
int packetlen);
/*********************************************************************
ioctl: callback used by the link provider to receive ioctl calls from
link users.
If a link user does an ioctl() on an opened link, the link provider
can register a callback to handle the ioctl.
*********************************************************************/
typedef int (* lp_ioctl_cb_t)(lp_context_t *lp, int cmd, void *arg);
/*********************************************************************
status: callback used by the link provider to add/modify status
information passed to the link user by the link interface.
If a link provider wants to modify the information the link interface
provides the link user when it queries the status device, the link
provider can register a callback to handle the status query. The
status field in lp_context is the status state.
*********************************************************************/
typedef int (*lp_status_cb_t)(lp_context_t *status);
/***************** Link Providers data structures *******************/
/* options available for link providers */
typedef struct lp_opts {
link_opts_t opts; /* common options */
lp_send_cb_t send; /* send callback */
lp_enqueue_cb_t enqueue; /* enqueue callback */
lp_ioctl_cb_t ioctl; /* ioctl callback */
lp_status_cb_t status_provider; /* status callback */
} lp_opts_t;
/***************** Functions used by Link Providers *****************/
/*********************************************************************
register: called by link providers to register a new interface.
The link providers call this function when they want to create a new
interface. All the options of the inteface, including the name, queue
lenght and various callbacks are passed with the opts argument.
Optionally, link providers can also passed a reference to get a link
context of the interface they provide.
In case of success, the function returns zero, and the following
device structure is created:
/dev/link/<name>/data the packet data device
/dev/link/<name>/status the status device
/dev/link/<name>/command the command device
In case of error, the function returns -1, and errno is set to the
appropriate error.
*********************************************************************/
gint lp_register(lp_opts_t *opts, lp_context_t **ref);
/*********************************************************************
receive: send a packet up to all clients waiting for data
*********************************************************************/
void lp_receive(lp_context_t *lp, const link_pkt_t *data, int data_len);
/*********************************************************************
loop_receive: send a packet up to clients waiting for loopback data
*********************************************************************/
void lp_loop_receive(lp_context_t *lp, const link_pkt_t *data, int data_len);
/*********************************************************************
unblock: unblock the link provider interface from receiving packets.
This function tells the link library that it can start sending
packets down again. retval is the retval of the packet that had been
blocked for sending.
*********************************************************************/
void lp_unblock(lp_context_t *lp, int retval);
/*********************************************************************
dev_destroy: link provide destructor
*********************************************************************/
void lp_destroy(lp_context_t *context);
/*********************************************************************
Accessor functions used to get info out of a link provider context
*********************************************************************/
lp_opts_t *lp_opts(lp_context_t *lp);
void *lp_data(lp_context_t *lp);
/* push updated status info to the link provider instance */
void lp_push_status(lp_context_t *lp, link_status_t *new_status);
/* get the name of the link */
char *lp_name(lp_context_t *lp, char *suffix);
/********************************************************************/
/*********************** Link User Interface ************************/
/********************************************************************/
/* typedef link user context */
typedef struct _lu_context lu_context_t;
/**************** Typdefs for link provider callbacks ***************/
/*********************************************************************
pkt_recieve: callback used by the link user to receive packets from
the link provider.
This is the basic callback to recieve packets from the link provider
the user is connected to. data_len is the size of the data (the
header-size is NOT include).
*********************************************************************/
typedef int (*lu_pkt_receive_cb_t)(link_pkt_t *pkt, ssize_t data_len,
lu_context_t *lu);
/*********************************************************************
writable: callback used by the link user to be informed when the
link provider is ready to accept packets.
status_notify: callback used by the link user to receive notification
when the link provider status device connected to changes its
information (e.g. MTU or radio state).
*********************************************************************/
typedef int (*lu_notify_cb_t)(lu_context_t *lu);
/******************** Link Users data structures ********************/
/* options available for the link users */
typedef struct lu_opts {
link_opts_t opts; /* common options */
lu_pkt_receive_cb_t receive; /* Callback when packets arrive */
lu_notify_cb_t writable; /* ...when the dev is writable */
lu_notify_cb_t status_notify; /* ...when the status changes */
} lu_opts_t;
/***************** Functions used by Link Providers *****************/
/*********************************************************************
open: opens a link interface provided by a link provider.
This function opens the underlying link interface provided by a link
provider. It is called by link users when they want to start using
the link. Several options are passed using the opts argument,
including the device name, queue options, the packet type the user
wants to receive, and several callbacks (see lp_opts for details).
If the open is successful, lu_open returns 0, and writes the link
user context to "ref" (a pointer provided by the user). If it fails,
lu_open returns -1 and sets errno appropriately.
If a "receive" callback is set in the lu_opts structure, it will be
called when packets arrive.
*********************************************************************/
gint lu_open(lu_opts_t *opts, lu_context_t **ref);
void lu_destroy(lu_context_t *lu);
/*********************************************************************
send: send a packet out on the link.
This function is used by link users when they want to send packets to
the link they have opened. The first argument "lu" is the lu_context
obtained when opened the link; the second argument "pkt" is a pointer
to a link_pkt header; and the third argument is "data_len" bytes of
data. (data_len does NOT include the length of the link_pkt_t header
itself.)
If the send is successful, lu_open returns 0, and writes the link
user context to "ref" (a pointer provided by the user). If it fails,
lu_open returns -1 and sets errno appropriately.
Please note that a successful send does not guarantees end-to-end
reception by the link provider, but only that the packet passed some
checks and was appropriatelly enqueued.
*********************************************************************/
gint lu_send(lu_context_t *lu, link_pkt_t *pkt, ssize_t data_len);
/*********************************************************************
writable_set_enable: (de)activate the "writable" callback
notification.
This function activate/deactivates the "writable" callback
notification if a callback was provided at opening time. To
deactivate the callback passed the argument "enable" with 0 value, or
<> from zero to activate it.
When active, the callback will be called every time there is space
available in the queue (i.e. lu_send will succeed without EAGAIN).
It is adviced to disable the writable callback if the link user has
nothing to send, or it will get a continuous stream of "writeable"
notifications.
*********************************************************************/
void lu_writable_cb_set_enable(lu_context_t *lu, int enable);
/*********************************************************************
status: get status of the link being used.
This function gets the status of the link. The status can also be
retrieved via ioctl; this will likely to change!).
If successful, retval is 0 and status is written to the 2nd argument.
In case of error, -1 is returned and errno is set.
*********************************************************************/
gint lu_status(lu_context_t *lu, link_status_t *status_return);
/*********************************************************************
ioctl: peform an ioctl on an open link.
This function performs an ioctl on an open link. See the
LINK_IOCTL_TYPE ioctls in link_structs.h for valid ioctls.
*********************************************************************/
gint lu_ioctl(lu_context_t *lu, int cmd, ...);
/*********************************************************************
get_mtu and get_if_id:
These functions get the the MTU and interface ID, respectively.
If successful, retval is 0 and status is written to the 2nd argument.
In case of error, -1 is returned and errno is set.
*********************************************************************/
gint lu_get_mtu(lu_context_t *lu, uint16_t *mtu);
gint lu_get_if_id(lu_context_t *lu, if_id_t *if_id);
/*********************************************************************
Accessor functions used to get info out of a link user context
*********************************************************************/
lu_opts_t *lu_opts(lu_context_t *lu);
void *lu_data(lu_context_t *lu);
char *lu_name(lu_context_t *lu, char *suffix);
/*
* link_status_t related functions
*/
int link_status_to_buf(buf_t *buf, link_status_t *stat);
int link_hdr_to_buf(buf_t *buf, link_pkt_t *hdr);
/********************************************************************/
/****************** Command Line Helper Functions *******************/
/********************************************************************/
/*
* Simple command line helper functions
*/
/* parses out the --uses flag, or uses default if not found */
char *link_parse_uses(int *argc, char **argv, char *default_name);
char *link_parse_provides(int *argc, char **argv, char *default_name);
/*********************************************************************
By using the link interface, all the components determine their
linkage by using --uses and --provides keyword from the command line.
As a convenience, a group of utility function is provided in order to
facilitate the parsing of this arguments from the command line.
*********************************************************************/
/******************** CL Helper Data Structures *********************/
/* helper struct to parse command line arguments for used and provided
* link interfaces */
typedef struct link_ifs {
link_opts_t *provides; /* link interfaces provided */
int num_provided; /* number of interfaces provided */
link_opts_t *uses; /* link interfaces used */
int num_used; /* number of interfaces used */
} link_ifs_t;
/*********************** CL Helper Functions ************************/
/*********************************************************************
config: extract the --uses and --provides arguments from the command
line arguments and fill the link_ifs data structure with the data.
This function extracts the names of the links it uses and provides,
and then fills the appropriate link_opts structures in link_ifs (with
the device names set).
*********************************************************************/
void link_config(link_ifs_t *ifs, int *argc, char **argv);
/*********************************************************************
usage: simple utility to provide usage and explanation strings that
link users could use in their own usage() functions.
*********************************************************************/
void link_usage(char **usage, char **expl);
/*********************************************************************
add_one: utility to add a new opts with the appropriate device name
set to "string" to the opts structure.
*********************************************************************/
int link_addone(link_opts_t **opts, char *string);
/********************************************************************/
/********************** Miscellanous Utilities **********************/
/********************************************************************/
/*********************************************************************
name: generate the name of a link (e.g. /dev/link/udp0/xxx)
*********************************************************************/
char *link_name(link_opts_t *l_opts, char *suffix);
/*********** Various utilities for dealing with a link_pkt **********/
char *print_if_id(if_id_t id);
void link_set_rcv_time(link_pkt_t *link_pkt, struct timeval *rcv_time);
#endif /* __LINK_H__ */
See more files for this project here