libnl 1.1
Data Structures | Modules

Core Netlink API

Data Structures

struct  sockaddr_nl
 Netlink socket address. More...

Modules

 Callbacks/Customization
 

Callbacks and overwriting capabilities are provided to take influence in various control flows inside the library.


 Messages
 

Netlink Message Construction/Parsing Interface.


 Socket
 

Handle representing a netlink socket.


Connection Management

int nl_connect (struct nl_handle *handle, int protocol)
 Create and connect netlink socket.
void nl_close (struct nl_handle *handle)
 Close/Disconnect netlink socket.

Send

int nl_sendto (struct nl_handle *handle, void *buf, size_t size)
 Send raw data over netlink socket.
int nl_sendmsg (struct nl_handle *handle, struct nl_msg *msg, struct msghdr *hdr)
 Send netlink message with control over sendmsg() message header.
int nl_send (struct nl_handle *handle, struct nl_msg *msg)
 Send netlink message.
int nl_send_auto_complete (struct nl_handle *handle, struct nl_msg *msg)
 Send netlink message and check & extend header values as needed.
int nl_send_simple (struct nl_handle *handle, int type, int flags, void *buf, size_t size)
 Send simple netlink message using nl_send_auto_complete()

Receive

int nl_recv (struct nl_handle *handle, struct sockaddr_nl *nla, unsigned char **buf, struct ucred **creds)
 Receive data from netlink socket.
int nl_recvmsgs (struct nl_handle *handle, struct nl_cb *cb)
 Receive a set of messages from a netlink socket.
int nl_recvmsgs_default (struct nl_handle *handle)
 Receive a set of message from a netlink socket using handlers in nl_handle.
int nl_wait_for_ack (struct nl_handle *handle)
 Wait for ACK.
#define NL_CB_CALL(cb, type, msg)

Detailed Description

Receiving Semantics
          nl_recvmsgs_default(socket)
                 |
                 | cb = nl_socket_get_cb(socket)
                 v
          nl_recvmsgs(socket, cb)
                 |           [Application provides nl_recvmsgs() replacement]
                 |- - - - - - - - - - - - - - - v
                 |                     cb->cb_recvmsgs_ow()
                 |
                 |               [Application provides nl_recv() replacement]
 +-------------->|- - - - - - - - - - - - - - - v
 |           nl_recv()                   cb->cb_recv_ow()
 |  +----------->|<- - - - - - - - - - - - - - -+
 |  |            v
 |  |      Parse Message
 |  |            |- - - - - - - - - - - - - - - v
 |  |            |                         NL_CB_MSG_IN()
 |  |            |<- - - - - - - - - - - - - - -+
 |  |            |
 |  |            |- - - - - - - - - - - - - - - v
 |  |      Sequence Check                NL_CB_SEQ_CHECK()
 |  |            |<- - - - - - - - - - - - - - -+
 |  |            |
 |  |            |- - - - - - - - - - - - - - - v  [ NLM_F_ACK is set ]
 |  |            |                      NL_CB_SEND_ACK()
 |  |            |<- - - - - - - - - - - - - - -+
 |  |            |
 |  |      +-----+------+--------------+----------------+--------------+
 |  |      v            v              v                v              v
 |  | Valid Message    ACK        NOOP Message  End of Multipart  Error Message
 |  |      |            |              |                |              |
 |  |      v            v              v                v              v
 |  |NL_CB_VALID()  NL_CB_ACK()  NL_CB_SKIPPED()  NL_CB_FINISH()  cb->cb_err()
 |  |      |            |              |                |              |
 |  |      +------------+--------------+----------------+              v
 |  |                                  |                           (FAILURE)
 |  |                                  |  [Callback returned NL_SKIP]
 |  |  [More messages to be parsed]    |<-----------
 |  +----------------------------------|
 |                                     |
 |         [Multipart message]         |
 +-------------------------------------|  [Callback returned NL_STOP]
                                       |<-----------
                                       v
                                   (SUCCESS)

                          At any time:
                                Message Format Error
                                         |- - - - - - - - - - - - v
                                         v                  NL_CB_INVALID()
                                     (FAILURE)

                                Message Overrun (Kernel Lost Data)
                                         |- - - - - - - - - - - - v
                                         v                  NL_CB_OVERRUN()
                                     (FAILURE)

                                Callback returned negative error code
                                     (FAILURE)
Sending Semantics
     nl_send_auto_complete()
             |
             | Automatically fill in PID and/or sequence number
             |
             |                   [Application provides nl_send() replacement]
             |- - - - - - - - - - - - - - - - - - - - v
             v                                 cb->cb_send_ow()
         nl_send()
             | Add destination address and credentials
             v
        nl_sendmsg()
             | Set source address
             |
             |- - - - - - - - - - - - - - - - - - - - v
             |                                 NL_CB_MSG_OUT()
             |<- - - - - - - - - - - - - - - - - - - -+
             v
         sendmsg()
1) Connecting the socket
 // Bind and connect the socket to a protocol, NETLINK_ROUTE in this example.
 nl_connect(handle, NETLINK_ROUTE);
2) Sending data
 // The most rudimentary method is to use nl_sendto() simply pushing
 // a piece of data to the other netlink peer. This method is not
 // recommended.
 const char buf[] = { 0x01, 0x02, 0x03, 0x04 };
 nl_sendto(handle, buf, sizeof(buf));

 // A more comfortable interface is nl_send() taking a pointer to
 // a netlink message.
 struct nl_msg *msg = my_msg_builder();
 nl_send(handle, nlmsg_hdr(msg));

 // nl_sendmsg() provides additional control over the sendmsg() message
 // header in order to allow more specific addressing of multiple peers etc.
 struct msghdr hdr = { ... };
 nl_sendmsg(handle, nlmsg_hdr(msg), &hdr);

 // You're probably too lazy to fill out the netlink pid, sequence number
 // and message flags all the time. nl_send_auto_complete() automatically
 // extends your message header as needed with an appropriate sequence
 // number, the netlink pid stored in the netlink handle and the message
 // flags NLM_F_REQUEST and NLM_F_ACK
 nl_send_auto_complete(handle, nlmsg_hdr(msg));

 // Simple protocols don't require the complex message construction interface
 // and may favour nl_send_simple() to easly send a bunch of payload
 // encapsulated in a netlink message header.
 nl_send_simple(handle, MY_MSG_TYPE, 0, buf, sizeof(buf));
3) Receiving data
 // nl_recv() receives a single message allocating a buffer for the message
 // content and gives back the pointer to you.
 struct sockaddr_nl peer;
 unsigned char *msg;
 nl_recv(handle, &peer, &msg);

 // nl_recvmsgs() receives a bunch of messages until the callback system
 // orders it to state, usually after receving a compolete multi part
 // message series.
 nl_recvmsgs(handle, my_callback_configuration);

 // nl_recvmsgs_default() acts just like nl_recvmsg() but uses the callback
 // configuration stored in the handle.
 nl_recvmsgs_default(handle);

 // In case you want to wait for the ACK to be recieved that you requested
 // with your latest message, you can call nl_wait_for_ack()
 nl_wait_for_ack(handle);
4) Closing
 // Close the socket first to release kernel memory
 nl_close(handle);

Define Documentation

#define NL_CB_CALL (   cb,
  type,
  msg 
)
Value:
do { \
        err = nl_cb_call(cb, type, msg); \
        switch (err) { \
        case NL_OK: \
                err = 0; \
                break; \
        case NL_SKIP: \
                goto skip; \
        case NL_STOP: \
                goto stop; \
        default: \
                goto out; \
        } \
} while (0)

Definition at line 551 of file nl.c.


Function Documentation

int nl_connect ( struct nl_handle *  handle,
int  protocol 
)
Parameters:
handleNetlink handle.
protocolNetlink protocol to use.

Creates a netlink socket using the specified protocol, binds the socket and issues a connection attempt.

Returns:
0 on success or a negative error code.

Definition at line 191 of file nl.c.

References nl_set_buffer_size().

Referenced by nfnl_connect(), and nl_cache_mngr_alloc().

{
        int err;
        socklen_t addrlen;

        handle->h_fd = socket(AF_NETLINK, SOCK_RAW, protocol);
        if (handle->h_fd < 0) {
                err = nl_error(1, "socket(AF_NETLINK, ...) failed");
                goto errout;
        }

        if (!(handle->h_flags & NL_SOCK_BUFSIZE_SET)) {
                err = nl_set_buffer_size(handle, 0, 0);
                if (err < 0)
                        goto errout;
        }

        err = bind(handle->h_fd, (struct sockaddr*) &handle->h_local,
                   sizeof(handle->h_local));
        if (err < 0) {
                err = nl_error(1, "bind() failed");
                goto errout;
        }

        addrlen = sizeof(handle->h_local);
        err = getsockname(handle->h_fd, (struct sockaddr *) &handle->h_local,
                          &addrlen);
        if (err < 0) {
                err = nl_error(1, "getsockname failed");
                goto errout;
        }

        if (addrlen != sizeof(handle->h_local)) {
                err = nl_error(EADDRNOTAVAIL, "Invalid address length");
                goto errout;
        }

        if (handle->h_local.nl_family != AF_NETLINK) {
                err = nl_error(EPFNOSUPPORT, "Address format not supported");
                goto errout;
        }

        handle->h_proto = protocol;

        return 0;
errout:
        close(handle->h_fd);
        handle->h_fd = -1;

        return err;
}
void nl_close ( struct nl_handle *  handle)
Parameters:
handleNetlink handle

Definition at line 247 of file nl.c.

Referenced by nl_cache_mngr_free().

{
        if (handle->h_fd >= 0) {
                close(handle->h_fd);
                handle->h_fd = -1;
        }

        handle->h_proto = 0;
}
int nl_sendto ( struct nl_handle *  handle,
void *  buf,
size_t  size 
)
Parameters:
handleNetlink handle.
bufData buffer.
sizeSize of data buffer.
Returns:
Number of characters written on success or a negative error code.

Definition at line 271 of file nl.c.

{
        int ret;

        ret = sendto(handle->h_fd, buf, size, 0, (struct sockaddr *)
                     &handle->h_peer, sizeof(handle->h_peer));
        if (ret < 0)
                return nl_errno(errno);

        return ret;
}
int nl_sendmsg ( struct nl_handle *  handle,
struct nl_msg *  msg,
struct msghdr *  hdr 
)
Parameters:
handleNetlink handle.
msgNetlink message to be sent.
hdrSendmsg() message header.
Returns:
Number of characters sent on sucess or a negative error code.

Definition at line 290 of file nl.c.

References NL_CB_MSG_OUT, NL_OK, nlmsg_hdr(), and nlmsghdr::nlmsg_len.

Referenced by nl_send().

{
        struct nl_cb *cb;
        int ret;

        struct iovec iov = {
                .iov_base = (void *) nlmsg_hdr(msg),
                .iov_len = nlmsg_hdr(msg)->nlmsg_len,
        };

        hdr->msg_iov = &iov;
        hdr->msg_iovlen = 1;

        nlmsg_set_src(msg, &handle->h_local);

        cb = handle->h_cb;
        if (cb->cb_set[NL_CB_MSG_OUT])
                if (nl_cb_call(cb, NL_CB_MSG_OUT, msg) != NL_OK)
                        return 0;

        ret = sendmsg(handle->h_fd, hdr, 0);
        if (ret < 0)
                return nl_errno(errno);

        return ret;
}
int nl_send ( struct nl_handle *  handle,
struct nl_msg *  msg 
)
Parameters:
handleNetlink handle
msgNetlink message to be sent.
See also:
nl_sendmsg()
Returns:
Number of characters sent on success or a negative error code.

Definition at line 325 of file nl.c.

References sockaddr_nl::nl_family, and nl_sendmsg().

Referenced by nl_send_auto_complete().

{
        struct sockaddr_nl *dst;
        struct ucred *creds;
        
        struct msghdr hdr = {
                .msg_name = (void *) &handle->h_peer,
                .msg_namelen = sizeof(struct sockaddr_nl),
        };

        /* Overwrite destination if specified in the message itself, defaults
         * to the peer address of the handle.
         */
        dst = nlmsg_get_dst(msg);
        if (dst->nl_family == AF_NETLINK)
                hdr.msg_name = dst;

        /* Add credentials if present. */
        creds = nlmsg_get_creds(msg);
        if (creds != NULL) {
                char buf[CMSG_SPACE(sizeof(struct ucred))];
                struct cmsghdr *cmsg;

                hdr.msg_control = buf;
                hdr.msg_controllen = sizeof(buf);

                cmsg = CMSG_FIRSTHDR(&hdr);
                cmsg->cmsg_level = SOL_SOCKET;
                cmsg->cmsg_type = SCM_CREDENTIALS;
                cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred));
                memcpy(CMSG_DATA(cmsg), creds, sizeof(struct ucred));
        }

        return nl_sendmsg(handle, msg, &hdr);
}
int nl_send_auto_complete ( struct nl_handle *  handle,
struct nl_msg *  msg 
)
Parameters:
handleNetlink handle.
msgNetlink message to be sent.

Checks the netlink message nlh for completness and extends it as required before sending it out. Checked fields include pid, sequence nr, and flags.

See also:
nl_send()
Returns:
Number of characters sent or a negative error code.

Definition at line 373 of file nl.c.

References nl_send(), NLM_F_ACK, NLM_F_REQUEST, nlmsghdr::nlmsg_flags, nlmsg_hdr(), nlmsghdr::nlmsg_pid, and nlmsghdr::nlmsg_seq.

Referenced by flnl_lookup(), nl_send_simple(), rtnl_addr_add(), rtnl_addr_delete(), rtnl_class_add(), rtnl_cls_add(), rtnl_cls_change(), rtnl_cls_delete(), rtnl_link_change(), rtnl_neigh_add(), rtnl_neigh_change(), rtnl_neigh_delete(), rtnl_neightbl_change(), rtnl_qdisc_add(), rtnl_qdisc_change(), rtnl_qdisc_delete(), rtnl_rule_add(), and rtnl_rule_delete().

{
        struct nlmsghdr *nlh;
        struct nl_cb *cb = handle->h_cb;

        nlh = nlmsg_hdr(msg);
        if (nlh->nlmsg_pid == 0)
                nlh->nlmsg_pid = handle->h_local.nl_pid;

        if (nlh->nlmsg_seq == 0)
                nlh->nlmsg_seq = handle->h_seq_next++;

        if (msg->nm_protocol == -1)
                msg->nm_protocol = handle->h_proto;
        
        nlh->nlmsg_flags |= (NLM_F_REQUEST | NLM_F_ACK);

        if (cb->cb_send_ow)
                return cb->cb_send_ow(handle, msg);
        else
                return nl_send(handle, msg);
}
int nl_send_simple ( struct nl_handle *  handle,
int  type,
int  flags,
void *  buf,
size_t  size 
)
Parameters:
handleNetlink handle.
typeNetlink message type.
flagsNetlink message flags.
bufData buffer.
sizeSize of data buffer.

Builds a netlink message with the specified type and flags and appends the specified data as payload to the message.

See also:
nl_send_auto_complete()
Returns:
Number of characters sent on success or a negative error code.

Definition at line 410 of file nl.c.

References nl_send_auto_complete(), nlmsg_alloc_simple(), nlmsg_append(), and nlmsg_free().

Referenced by genl_send_simple(), nfnl_send_simple(), and nl_rtgen_request().

{
        int err;
        struct nl_msg *msg;

        msg = nlmsg_alloc_simple(type, flags);
        if (!msg)
                return nl_errno(ENOMEM);

        if (buf && size) {
                err = nlmsg_append(msg, buf, size, NLMSG_ALIGNTO);
                if (err < 0)
                        goto errout;
        }
        

        err = nl_send_auto_complete(handle, msg);
errout:
        nlmsg_free(msg);

        return err;
}
int nl_recv ( struct nl_handle *  handle,
struct sockaddr_nl nla,
unsigned char **  buf,
struct ucred **  creds 
)
Parameters:
handleNetlink handle.
nlaDestination pointer for peer's netlink address.
bufDestination pointer for message content.
credsDestination pointer for credentials.

Receives a netlink message, allocates a buffer in *buf and stores the message content. The peer's netlink address is stored in *nla. The caller is responsible for freeing the buffer allocated in *buf if a positive value is returned. Interruped system calls are handled by repeating the read. The input buffer size is determined by peeking before the actual read is done.

A non-blocking sockets causes the function to return immediately with a return value of 0 if no data is available.

Returns:
Number of octets read, 0 on EOF or a negative error code.

Definition at line 460 of file nl.c.

{
        int n;
        int flags = 0;
        static int page_size = 0;
        struct iovec iov;
        struct msghdr msg = {
                .msg_name = (void *) nla,
                .msg_namelen = sizeof(struct sockaddr_nl),
                .msg_iov = &iov,
                .msg_iovlen = 1,
                .msg_control = NULL,
                .msg_controllen = 0,
                .msg_flags = 0,
        };
        struct cmsghdr *cmsg;

        if (handle->h_flags & NL_MSG_PEEK)
                flags |= MSG_PEEK;

        if (page_size == 0)
                page_size = getpagesize();

        iov.iov_len = page_size;
        iov.iov_base = *buf = calloc(1, iov.iov_len);

        if (handle->h_flags & NL_SOCK_PASSCRED) {
                msg.msg_controllen = CMSG_SPACE(sizeof(struct ucred));
                msg.msg_control = calloc(1, msg.msg_controllen);
        }
retry:

        n = recvmsg(handle->h_fd, &msg, flags);
        if (!n)
                goto abort;
        else if (n < 0) {
                if (errno == EINTR) {
                        NL_DBG(3, "recvmsg() returned EINTR, retrying\n");
                        goto retry;
                } else if (errno == EAGAIN) {
                        NL_DBG(3, "recvmsg() returned EAGAIN, aborting\n");
                        goto abort;
                } else {
                        free(msg.msg_control);
                        free(*buf);
                        return nl_error(errno, "recvmsg failed");
                }
        }

        if (iov.iov_len < n ||
            msg.msg_flags & MSG_TRUNC) {
                /* Provided buffer is not long enough, enlarge it
                 * and try again. */
                iov.iov_len *= 2;
                iov.iov_base = *buf = realloc(*buf, iov.iov_len);
                goto retry;
        } else if (msg.msg_flags & MSG_CTRUNC) {
                msg.msg_controllen *= 2;
                msg.msg_control = realloc(msg.msg_control, msg.msg_controllen);
                goto retry;
        } else if (flags != 0) {
                /* Buffer is big enough, do the actual reading */
                flags = 0;
                goto retry;
        }

        if (msg.msg_namelen != sizeof(struct sockaddr_nl)) {
                free(msg.msg_control);
                free(*buf);
                return nl_error(EADDRNOTAVAIL, "socket address size mismatch");
        }

        for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
                if (cmsg->cmsg_level == SOL_SOCKET &&
                    cmsg->cmsg_type == SCM_CREDENTIALS) {
                        *creds = calloc(1, sizeof(struct ucred));
                        memcpy(*creds, CMSG_DATA(cmsg), sizeof(struct ucred));
                        break;
                }
        }

        free(msg.msg_control);
        return n;

abort:
        free(msg.msg_control);
        free(*buf);
        return 0;
}
int nl_recvmsgs ( struct nl_handle *  handle,
struct nl_cb *  cb 
)
Parameters:
handlenetlink handle
cbset of callbacks to control behaviour.

Repeatedly calls nl_recv() or the respective replacement if provided by the application (see nl_cb_overwrite_recv()) and parses the received data as netlink messages. Stops reading if one of the callbacks returns NL_STOP or nl_recv returns either 0 or a negative error code.

A non-blocking sockets causes the function to return immediately if no data is available.

Returns:
0 on success or a negative error code from nl_recv().

Definition at line 767 of file nl.c.

Referenced by nl_recvmsgs_default(), and nl_wait_for_ack().

{
        if (cb->cb_recvmsgs_ow)
                return cb->cb_recvmsgs_ow(handle, cb);
        else
                return recvmsgs(handle, cb);
}
int nl_recvmsgs_default ( struct nl_handle *  handle)
Parameters:
handlenetlink handle

Calls nl_recvmsgs() with the handlers configured in the netlink handle.

Definition at line 781 of file nl.c.

References nl_recvmsgs().

Referenced by nl_cache_mngr_data_ready().

{
        return nl_recvmsgs(handle, handle->h_cb);

}
int nl_wait_for_ack ( struct nl_handle *  handle)
Parameters:
handlenetlink handle
Precondition:
The netlink socket must be in blocking state.

Waits until an ACK is received for the latest not yet acknowledged netlink message.

Definition at line 800 of file nl.c.

References NL_CB_ACK, nl_cb_clone(), NL_CB_CUSTOM, nl_cb_set(), and nl_recvmsgs().

Referenced by rtnl_addr_add(), rtnl_addr_delete(), rtnl_class_add(), rtnl_cls_add(), rtnl_cls_change(), rtnl_cls_delete(), rtnl_link_change(), rtnl_neigh_add(), rtnl_neigh_change(), rtnl_neigh_delete(), rtnl_neightbl_change(), rtnl_qdisc_add(), rtnl_qdisc_change(), rtnl_qdisc_delete(), rtnl_rule_add(), and rtnl_rule_delete().

{
        int err;
        struct nl_cb *cb;

        cb = nl_cb_clone(handle->h_cb);
        if (cb == NULL)
                return nl_get_errno();

        nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_wait_handler, NULL);
        err = nl_recvmsgs(handle, cb);
        nl_cb_put(cb);

        return err;
}