libnl 1.1

lib/nl.c

00001 /*
00002  * lib/nl.c             Core Netlink Interface
00003  *
00004  *      This library is free software; you can redistribute it and/or
00005  *      modify it under the terms of the GNU Lesser General Public
00006  *      License as published by the Free Software Foundation version 2.1
00007  *      of the License.
00008  *
00009  * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
00010  */
00011 
00012 /**
00013  * @defgroup nl Core Netlink API
00014  * @brief
00015  *
00016  * @par Receiving Semantics
00017  * @code
00018  *          nl_recvmsgs_default(socket)
00019  *                 |
00020  *                 | cb = nl_socket_get_cb(socket)
00021  *                 v
00022  *          nl_recvmsgs(socket, cb)
00023  *                 |           [Application provides nl_recvmsgs() replacement]
00024  *                 |- - - - - - - - - - - - - - - v
00025  *                 |                     cb->cb_recvmsgs_ow()
00026  *                 |
00027  *                 |               [Application provides nl_recv() replacement]
00028  * +-------------->|- - - - - - - - - - - - - - - v
00029  * |           nl_recv()                   cb->cb_recv_ow()
00030  * |  +----------->|<- - - - - - - - - - - - - - -+
00031  * |  |            v
00032  * |  |      Parse Message
00033  * |  |            |- - - - - - - - - - - - - - - v
00034  * |  |            |                         NL_CB_MSG_IN()
00035  * |  |            |<- - - - - - - - - - - - - - -+
00036  * |  |            |
00037  * |  |            |- - - - - - - - - - - - - - - v
00038  * |  |      Sequence Check                NL_CB_SEQ_CHECK()
00039  * |  |            |<- - - - - - - - - - - - - - -+
00040  * |  |            |
00041  * |  |            |- - - - - - - - - - - - - - - v  [ NLM_F_ACK is set ]
00042  * |  |            |                      NL_CB_SEND_ACK()
00043  * |  |            |<- - - - - - - - - - - - - - -+
00044  * |  |            |
00045  * |  |      +-----+------+--------------+----------------+--------------+
00046  * |  |      v            v              v                v              v
00047  * |  | Valid Message    ACK        NOOP Message  End of Multipart  Error Message
00048  * |  |      |            |              |                |              |
00049  * |  |      v            v              v                v              v
00050  * |  |NL_CB_VALID()  NL_CB_ACK()  NL_CB_SKIPPED()  NL_CB_FINISH()  cb->cb_err()
00051  * |  |      |            |              |                |              |
00052  * |  |      +------------+--------------+----------------+              v
00053  * |  |                                  |                           (FAILURE)
00054  * |  |                                  |  [Callback returned NL_SKIP]
00055  * |  |  [More messages to be parsed]    |<-----------
00056  * |  +----------------------------------|
00057  * |                                     |
00058  * |         [Multipart message]         |
00059  * +-------------------------------------|  [Callback returned NL_STOP]
00060  *                                       |<-----------
00061  *                                       v
00062  *                                   (SUCCESS)
00063  *
00064  *                          At any time:
00065  *                                Message Format Error
00066  *                                         |- - - - - - - - - - - - v
00067  *                                         v                  NL_CB_INVALID()
00068  *                                     (FAILURE)
00069  *
00070  *                                Message Overrun (Kernel Lost Data)
00071  *                                         |- - - - - - - - - - - - v
00072  *                                         v                  NL_CB_OVERRUN()
00073  *                                     (FAILURE)
00074  *
00075  *                                Callback returned negative error code
00076  *                                     (FAILURE)
00077  * @endcode
00078  *
00079  * @par Sending Semantics
00080  * @code
00081  *     nl_send_auto_complete()
00082  *             |
00083  *             | Automatically fill in PID and/or sequence number
00084  *             |
00085  *             |                   [Application provides nl_send() replacement]
00086  *             |- - - - - - - - - - - - - - - - - - - - v
00087  *             v                                 cb->cb_send_ow()
00088  *         nl_send()
00089  *             | Add destination address and credentials
00090  *             v
00091  *        nl_sendmsg()
00092  *             | Set source address
00093  *             |
00094  *             |- - - - - - - - - - - - - - - - - - - - v
00095  *             |                                 NL_CB_MSG_OUT()
00096  *             |<- - - - - - - - - - - - - - - - - - - -+
00097  *             v
00098  *         sendmsg()
00099  * @endcode
00100  *
00101  * @par 1) Connecting the socket
00102  * @code
00103  * // Bind and connect the socket to a protocol, NETLINK_ROUTE in this example.
00104  * nl_connect(handle, NETLINK_ROUTE);
00105  * @endcode
00106  *
00107  * @par 2) Sending data
00108  * @code
00109  * // The most rudimentary method is to use nl_sendto() simply pushing
00110  * // a piece of data to the other netlink peer. This method is not
00111  * // recommended.
00112  * const char buf[] = { 0x01, 0x02, 0x03, 0x04 };
00113  * nl_sendto(handle, buf, sizeof(buf));
00114  *
00115  * // A more comfortable interface is nl_send() taking a pointer to
00116  * // a netlink message.
00117  * struct nl_msg *msg = my_msg_builder();
00118  * nl_send(handle, nlmsg_hdr(msg));
00119  *
00120  * // nl_sendmsg() provides additional control over the sendmsg() message
00121  * // header in order to allow more specific addressing of multiple peers etc.
00122  * struct msghdr hdr = { ... };
00123  * nl_sendmsg(handle, nlmsg_hdr(msg), &hdr);
00124  *
00125  * // You're probably too lazy to fill out the netlink pid, sequence number
00126  * // and message flags all the time. nl_send_auto_complete() automatically
00127  * // extends your message header as needed with an appropriate sequence
00128  * // number, the netlink pid stored in the netlink handle and the message
00129  * // flags NLM_F_REQUEST and NLM_F_ACK
00130  * nl_send_auto_complete(handle, nlmsg_hdr(msg));
00131  *
00132  * // Simple protocols don't require the complex message construction interface
00133  * // and may favour nl_send_simple() to easly send a bunch of payload
00134  * // encapsulated in a netlink message header.
00135  * nl_send_simple(handle, MY_MSG_TYPE, 0, buf, sizeof(buf));
00136  * @endcode
00137  *
00138  * @par 3) Receiving data
00139  * @code
00140  * // nl_recv() receives a single message allocating a buffer for the message
00141  * // content and gives back the pointer to you.
00142  * struct sockaddr_nl peer;
00143  * unsigned char *msg;
00144  * nl_recv(handle, &peer, &msg);
00145  *
00146  * // nl_recvmsgs() receives a bunch of messages until the callback system
00147  * // orders it to state, usually after receving a compolete multi part
00148  * // message series.
00149  * nl_recvmsgs(handle, my_callback_configuration);
00150  *
00151  * // nl_recvmsgs_default() acts just like nl_recvmsg() but uses the callback
00152  * // configuration stored in the handle.
00153  * nl_recvmsgs_default(handle);
00154  *
00155  * // In case you want to wait for the ACK to be recieved that you requested
00156  * // with your latest message, you can call nl_wait_for_ack()
00157  * nl_wait_for_ack(handle);
00158  * @endcode
00159  *
00160  * @par 4) Closing
00161  * @code
00162  * // Close the socket first to release kernel memory
00163  * nl_close(handle);
00164  * @endcode
00165  * 
00166  * @{
00167  */
00168 
00169 #include <netlink-local.h>
00170 #include <netlink/netlink.h>
00171 #include <netlink/utils.h>
00172 #include <netlink/handlers.h>
00173 #include <netlink/msg.h>
00174 #include <netlink/attr.h>
00175 
00176 /**
00177  * @name Connection Management
00178  * @{
00179  */
00180 
00181 /**
00182  * Create and connect netlink socket.
00183  * @arg handle          Netlink handle.
00184  * @arg protocol        Netlink protocol to use.
00185  *
00186  * Creates a netlink socket using the specified protocol, binds the socket
00187  * and issues a connection attempt.
00188  *
00189  * @return 0 on success or a negative error code.
00190  */
00191 int nl_connect(struct nl_handle *handle, int protocol)
00192 {
00193         int err;
00194         socklen_t addrlen;
00195 
00196         handle->h_fd = socket(AF_NETLINK, SOCK_RAW, protocol);
00197         if (handle->h_fd < 0) {
00198                 err = nl_error(1, "socket(AF_NETLINK, ...) failed");
00199                 goto errout;
00200         }
00201 
00202         if (!(handle->h_flags & NL_SOCK_BUFSIZE_SET)) {
00203                 err = nl_set_buffer_size(handle, 0, 0);
00204                 if (err < 0)
00205                         goto errout;
00206         }
00207 
00208         err = bind(handle->h_fd, (struct sockaddr*) &handle->h_local,
00209                    sizeof(handle->h_local));
00210         if (err < 0) {
00211                 err = nl_error(1, "bind() failed");
00212                 goto errout;
00213         }
00214 
00215         addrlen = sizeof(handle->h_local);
00216         err = getsockname(handle->h_fd, (struct sockaddr *) &handle->h_local,
00217                           &addrlen);
00218         if (err < 0) {
00219                 err = nl_error(1, "getsockname failed");
00220                 goto errout;
00221         }
00222 
00223         if (addrlen != sizeof(handle->h_local)) {
00224                 err = nl_error(EADDRNOTAVAIL, "Invalid address length");
00225                 goto errout;
00226         }
00227 
00228         if (handle->h_local.nl_family != AF_NETLINK) {
00229                 err = nl_error(EPFNOSUPPORT, "Address format not supported");
00230                 goto errout;
00231         }
00232 
00233         handle->h_proto = protocol;
00234 
00235         return 0;
00236 errout:
00237         close(handle->h_fd);
00238         handle->h_fd = -1;
00239 
00240         return err;
00241 }
00242 
00243 /**
00244  * Close/Disconnect netlink socket.
00245  * @arg handle          Netlink handle
00246  */
00247 void nl_close(struct nl_handle *handle)
00248 {
00249         if (handle->h_fd >= 0) {
00250                 close(handle->h_fd);
00251                 handle->h_fd = -1;
00252         }
00253 
00254         handle->h_proto = 0;
00255 }
00256 
00257 /** @} */
00258 
00259 /**
00260  * @name Send
00261  * @{
00262  */
00263 
00264 /**
00265  * Send raw data over netlink socket.
00266  * @arg handle          Netlink handle.
00267  * @arg buf             Data buffer.
00268  * @arg size            Size of data buffer.
00269  * @return Number of characters written on success or a negative error code.
00270  */
00271 int nl_sendto(struct nl_handle *handle, void *buf, size_t size)
00272 {
00273         int ret;
00274 
00275         ret = sendto(handle->h_fd, buf, size, 0, (struct sockaddr *)
00276                      &handle->h_peer, sizeof(handle->h_peer));
00277         if (ret < 0)
00278                 return nl_errno(errno);
00279 
00280         return ret;
00281 }
00282 
00283 /**
00284  * Send netlink message with control over sendmsg() message header.
00285  * @arg handle          Netlink handle.
00286  * @arg msg             Netlink message to be sent.
00287  * @arg hdr             Sendmsg() message header.
00288  * @return Number of characters sent on sucess or a negative error code.
00289  */
00290 int nl_sendmsg(struct nl_handle *handle, struct nl_msg *msg, struct msghdr *hdr)
00291 {
00292         struct nl_cb *cb;
00293         int ret;
00294 
00295         struct iovec iov = {
00296                 .iov_base = (void *) nlmsg_hdr(msg),
00297                 .iov_len = nlmsg_hdr(msg)->nlmsg_len,
00298         };
00299 
00300         hdr->msg_iov = &iov;
00301         hdr->msg_iovlen = 1;
00302 
00303         nlmsg_set_src(msg, &handle->h_local);
00304 
00305         cb = handle->h_cb;
00306         if (cb->cb_set[NL_CB_MSG_OUT])
00307                 if (nl_cb_call(cb, NL_CB_MSG_OUT, msg) != NL_OK)
00308                         return 0;
00309 
00310         ret = sendmsg(handle->h_fd, hdr, 0);
00311         if (ret < 0)
00312                 return nl_errno(errno);
00313 
00314         return ret;
00315 }
00316 
00317 
00318 /**
00319  * Send netlink message.
00320  * @arg handle          Netlink handle
00321  * @arg msg             Netlink message to be sent.
00322  * @see nl_sendmsg()
00323  * @return Number of characters sent on success or a negative error code.
00324  */
00325 int nl_send(struct nl_handle *handle, struct nl_msg *msg)
00326 {
00327         struct sockaddr_nl *dst;
00328         struct ucred *creds;
00329         
00330         struct msghdr hdr = {
00331                 .msg_name = (void *) &handle->h_peer,
00332                 .msg_namelen = sizeof(struct sockaddr_nl),
00333         };
00334 
00335         /* Overwrite destination if specified in the message itself, defaults
00336          * to the peer address of the handle.
00337          */
00338         dst = nlmsg_get_dst(msg);
00339         if (dst->nl_family == AF_NETLINK)
00340                 hdr.msg_name = dst;
00341 
00342         /* Add credentials if present. */
00343         creds = nlmsg_get_creds(msg);
00344         if (creds != NULL) {
00345                 char buf[CMSG_SPACE(sizeof(struct ucred))];
00346                 struct cmsghdr *cmsg;
00347 
00348                 hdr.msg_control = buf;
00349                 hdr.msg_controllen = sizeof(buf);
00350 
00351                 cmsg = CMSG_FIRSTHDR(&hdr);
00352                 cmsg->cmsg_level = SOL_SOCKET;
00353                 cmsg->cmsg_type = SCM_CREDENTIALS;
00354                 cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred));
00355                 memcpy(CMSG_DATA(cmsg), creds, sizeof(struct ucred));
00356         }
00357 
00358         return nl_sendmsg(handle, msg, &hdr);
00359 }
00360 
00361 /**
00362  * Send netlink message and check & extend header values as needed.
00363  * @arg handle          Netlink handle.
00364  * @arg msg             Netlink message to be sent.
00365  *
00366  * Checks the netlink message \c nlh for completness and extends it
00367  * as required before sending it out. Checked fields include pid,
00368  * sequence nr, and flags.
00369  *
00370  * @see nl_send()
00371  * @return Number of characters sent or a negative error code.
00372  */
00373 int nl_send_auto_complete(struct nl_handle *handle, struct nl_msg *msg)
00374 {
00375         struct nlmsghdr *nlh;
00376         struct nl_cb *cb = handle->h_cb;
00377 
00378         nlh = nlmsg_hdr(msg);
00379         if (nlh->nlmsg_pid == 0)
00380                 nlh->nlmsg_pid = handle->h_local.nl_pid;
00381 
00382         if (nlh->nlmsg_seq == 0)
00383                 nlh->nlmsg_seq = handle->h_seq_next++;
00384 
00385         if (msg->nm_protocol == -1)
00386                 msg->nm_protocol = handle->h_proto;
00387         
00388         nlh->nlmsg_flags |= (NLM_F_REQUEST | NLM_F_ACK);
00389 
00390         if (cb->cb_send_ow)
00391                 return cb->cb_send_ow(handle, msg);
00392         else
00393                 return nl_send(handle, msg);
00394 }
00395 
00396 /**
00397  * Send simple netlink message using nl_send_auto_complete()
00398  * @arg handle          Netlink handle.
00399  * @arg type            Netlink message type.
00400  * @arg flags           Netlink message flags.
00401  * @arg buf             Data buffer.
00402  * @arg size            Size of data buffer.
00403  *
00404  * Builds a netlink message with the specified type and flags and
00405  * appends the specified data as payload to the message.
00406  *
00407  * @see nl_send_auto_complete()
00408  * @return Number of characters sent on success or a negative error code.
00409  */
00410 int nl_send_simple(struct nl_handle *handle, int type, int flags, void *buf,
00411                    size_t size)
00412 {
00413         int err;
00414         struct nl_msg *msg;
00415 
00416         msg = nlmsg_alloc_simple(type, flags);
00417         if (!msg)
00418                 return nl_errno(ENOMEM);
00419 
00420         if (buf && size) {
00421                 err = nlmsg_append(msg, buf, size, NLMSG_ALIGNTO);
00422                 if (err < 0)
00423                         goto errout;
00424         }
00425         
00426 
00427         err = nl_send_auto_complete(handle, msg);
00428 errout:
00429         nlmsg_free(msg);
00430 
00431         return err;
00432 }
00433 
00434 /** @} */
00435 
00436 /**
00437  * @name Receive
00438  * @{
00439  */
00440 
00441 /**
00442  * Receive data from netlink socket
00443  * @arg handle          Netlink handle.
00444  * @arg nla             Destination pointer for peer's netlink address.
00445  * @arg buf             Destination pointer for message content.
00446  * @arg creds           Destination pointer for credentials.
00447  *
00448  * Receives a netlink message, allocates a buffer in \c *buf and
00449  * stores the message content. The peer's netlink address is stored
00450  * in \c *nla. The caller is responsible for freeing the buffer allocated
00451  * in \c *buf if a positive value is returned.  Interruped system calls
00452  * are handled by repeating the read. The input buffer size is determined
00453  * by peeking before the actual read is done.
00454  *
00455  * A non-blocking sockets causes the function to return immediately with
00456  * a return value of 0 if no data is available.
00457  *
00458  * @return Number of octets read, 0 on EOF or a negative error code.
00459  */
00460 int nl_recv(struct nl_handle *handle, struct sockaddr_nl *nla,
00461             unsigned char **buf, struct ucred **creds)
00462 {
00463         int n;
00464         int flags = 0;
00465         static int page_size = 0;
00466         struct iovec iov;
00467         struct msghdr msg = {
00468                 .msg_name = (void *) nla,
00469                 .msg_namelen = sizeof(struct sockaddr_nl),
00470                 .msg_iov = &iov,
00471                 .msg_iovlen = 1,
00472                 .msg_control = NULL,
00473                 .msg_controllen = 0,
00474                 .msg_flags = 0,
00475         };
00476         struct cmsghdr *cmsg;
00477 
00478         if (handle->h_flags & NL_MSG_PEEK)
00479                 flags |= MSG_PEEK;
00480 
00481         if (page_size == 0)
00482                 page_size = getpagesize();
00483 
00484         iov.iov_len = page_size;
00485         iov.iov_base = *buf = calloc(1, iov.iov_len);
00486 
00487         if (handle->h_flags & NL_SOCK_PASSCRED) {
00488                 msg.msg_controllen = CMSG_SPACE(sizeof(struct ucred));
00489                 msg.msg_control = calloc(1, msg.msg_controllen);
00490         }
00491 retry:
00492 
00493         n = recvmsg(handle->h_fd, &msg, flags);
00494         if (!n)
00495                 goto abort;
00496         else if (n < 0) {
00497                 if (errno == EINTR) {
00498                         NL_DBG(3, "recvmsg() returned EINTR, retrying\n");
00499                         goto retry;
00500                 } else if (errno == EAGAIN) {
00501                         NL_DBG(3, "recvmsg() returned EAGAIN, aborting\n");
00502                         goto abort;
00503                 } else {
00504                         free(msg.msg_control);
00505                         free(*buf);
00506                         return nl_error(errno, "recvmsg failed");
00507                 }
00508         }
00509 
00510         if (iov.iov_len < n ||
00511             msg.msg_flags & MSG_TRUNC) {
00512                 /* Provided buffer is not long enough, enlarge it
00513                  * and try again. */
00514                 iov.iov_len *= 2;
00515                 iov.iov_base = *buf = realloc(*buf, iov.iov_len);
00516                 goto retry;
00517         } else if (msg.msg_flags & MSG_CTRUNC) {
00518                 msg.msg_controllen *= 2;
00519                 msg.msg_control = realloc(msg.msg_control, msg.msg_controllen);
00520                 goto retry;
00521         } else if (flags != 0) {
00522                 /* Buffer is big enough, do the actual reading */
00523                 flags = 0;
00524                 goto retry;
00525         }
00526 
00527         if (msg.msg_namelen != sizeof(struct sockaddr_nl)) {
00528                 free(msg.msg_control);
00529                 free(*buf);
00530                 return nl_error(EADDRNOTAVAIL, "socket address size mismatch");
00531         }
00532 
00533         for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
00534                 if (cmsg->cmsg_level == SOL_SOCKET &&
00535                     cmsg->cmsg_type == SCM_CREDENTIALS) {
00536                         *creds = calloc(1, sizeof(struct ucred));
00537                         memcpy(*creds, CMSG_DATA(cmsg), sizeof(struct ucred));
00538                         break;
00539                 }
00540         }
00541 
00542         free(msg.msg_control);
00543         return n;
00544 
00545 abort:
00546         free(msg.msg_control);
00547         free(*buf);
00548         return 0;
00549 }
00550 
00551 #define NL_CB_CALL(cb, type, msg) \
00552 do { \
00553         err = nl_cb_call(cb, type, msg); \
00554         switch (err) { \
00555         case NL_OK: \
00556                 err = 0; \
00557                 break; \
00558         case NL_SKIP: \
00559                 goto skip; \
00560         case NL_STOP: \
00561                 goto stop; \
00562         default: \
00563                 goto out; \
00564         } \
00565 } while (0)
00566 
00567 static int recvmsgs(struct nl_handle *handle, struct nl_cb *cb)
00568 {
00569         int n, err = 0, multipart = 0;
00570         unsigned char *buf = NULL;
00571         struct nlmsghdr *hdr;
00572         struct sockaddr_nl nla = {0};
00573         struct nl_msg *msg = NULL;
00574         struct ucred *creds = NULL;
00575 
00576 continue_reading:
00577         NL_DBG(3, "Attempting to read from %p\n", handle);
00578         if (cb->cb_recv_ow)
00579                 n = cb->cb_recv_ow(handle, &nla, &buf, &creds);
00580         else
00581                 n = nl_recv(handle, &nla, &buf, &creds);
00582 
00583         if (n <= 0)
00584                 return n;
00585 
00586         NL_DBG(3, "recvmsgs(%p): Read %d bytes\n", handle, n);
00587 
00588         hdr = (struct nlmsghdr *) buf;
00589         while (nlmsg_ok(hdr, n)) {
00590                 NL_DBG(3, "recgmsgs(%p): Processing valid message...\n",
00591                        handle);
00592 
00593                 nlmsg_free(msg);
00594                 msg = nlmsg_convert(hdr);
00595                 if (!msg) {
00596                         err = nl_errno(ENOMEM);
00597                         goto out;
00598                 }
00599 
00600                 nlmsg_set_proto(msg, handle->h_proto);
00601                 nlmsg_set_src(msg, &nla);
00602                 if (creds)
00603                         nlmsg_set_creds(msg, creds);
00604 
00605                 /* Raw callback is the first, it gives the most control
00606                  * to the user and he can do his very own parsing. */
00607                 if (cb->cb_set[NL_CB_MSG_IN])
00608                         NL_CB_CALL(cb, NL_CB_MSG_IN, msg);
00609 
00610                 /* Sequence number checking. The check may be done by
00611                  * the user, otherwise a very simple check is applied
00612                  * enforcing strict ordering */
00613                 if (cb->cb_set[NL_CB_SEQ_CHECK])
00614                         NL_CB_CALL(cb, NL_CB_SEQ_CHECK, msg);
00615                 else if (hdr->nlmsg_seq != handle->h_seq_expect) {
00616                         if (cb->cb_set[NL_CB_INVALID])
00617                                 NL_CB_CALL(cb, NL_CB_INVALID, msg);
00618                         else {
00619                                 err = nl_error(EINVAL,
00620                                         "Sequence number mismatch");
00621                                 goto out;
00622                         }
00623                 }
00624 
00625                 if (hdr->nlmsg_type == NLMSG_DONE ||
00626                     hdr->nlmsg_type == NLMSG_ERROR ||
00627                     hdr->nlmsg_type == NLMSG_NOOP ||
00628                     hdr->nlmsg_type == NLMSG_OVERRUN) {
00629                         /* We can't check for !NLM_F_MULTI since some netlink
00630                          * users in the kernel are broken. */
00631                         handle->h_seq_expect++;
00632                         NL_DBG(3, "recvmsgs(%p): Increased expected " \
00633                                "sequence number to %d\n",
00634                                handle, handle->h_seq_expect);
00635                 }
00636 
00637                 if (hdr->nlmsg_flags & NLM_F_MULTI)
00638                         multipart = 1;
00639         
00640                 /* Other side wishes to see an ack for this message */
00641                 if (hdr->nlmsg_flags & NLM_F_ACK) {
00642                         if (cb->cb_set[NL_CB_SEND_ACK])
00643                                 NL_CB_CALL(cb, NL_CB_SEND_ACK, msg);
00644                         else {
00645                                 /* FIXME: implement */
00646                         }
00647                 }
00648 
00649                 /* messages terminates a multpart message, this is
00650                  * usually the end of a message and therefore we slip
00651                  * out of the loop by default. the user may overrule
00652                  * this action by skipping this packet. */
00653                 if (hdr->nlmsg_type == NLMSG_DONE) {
00654                         multipart = 0;
00655                         if (cb->cb_set[NL_CB_FINISH])
00656                                 NL_CB_CALL(cb, NL_CB_FINISH, msg);
00657                 }
00658 
00659                 /* Message to be ignored, the default action is to
00660                  * skip this message if no callback is specified. The
00661                  * user may overrule this action by returning
00662                  * NL_PROCEED. */
00663                 else if (hdr->nlmsg_type == NLMSG_NOOP) {
00664                         if (cb->cb_set[NL_CB_SKIPPED])
00665                                 NL_CB_CALL(cb, NL_CB_SKIPPED, msg);
00666                         else
00667                                 goto skip;
00668                 }
00669 
00670                 /* Data got lost, report back to user. The default action is to
00671                  * quit parsing. The user may overrule this action by retuning
00672                  * NL_SKIP or NL_PROCEED (dangerous) */
00673                 else if (hdr->nlmsg_type == NLMSG_OVERRUN) {
00674                         if (cb->cb_set[NL_CB_OVERRUN])
00675                                 NL_CB_CALL(cb, NL_CB_OVERRUN, msg);
00676                         else {
00677                                 err = nl_error(EOVERFLOW, "Overrun");
00678                                 goto out;
00679                         }
00680                 }
00681 
00682                 /* Message carries a nlmsgerr */
00683                 else if (hdr->nlmsg_type == NLMSG_ERROR) {
00684                         struct nlmsgerr *e = nlmsg_data(hdr);
00685 
00686                         if (hdr->nlmsg_len < nlmsg_msg_size(sizeof(*e))) {
00687                                 /* Truncated error message, the default action
00688                                  * is to stop parsing. The user may overrule
00689                                  * this action by returning NL_SKIP or
00690                                  * NL_PROCEED (dangerous) */
00691                                 if (cb->cb_set[NL_CB_INVALID])
00692                                         NL_CB_CALL(cb, NL_CB_INVALID, msg);
00693                                 else {
00694                                         err = nl_error(EINVAL,
00695                                                 "Truncated error message");
00696                                         goto out;
00697                                 }
00698                         } else if (e->error) {
00699                                 /* Error message reported back from kernel. */
00700                                 if (cb->cb_err) {
00701                                         err = cb->cb_err(&nla, e,
00702                                                            cb->cb_err_arg);
00703                                         if (err < 0)
00704                                                 goto out;
00705                                         else if (err == NL_SKIP)
00706                                                 goto skip;
00707                                         else if (err == NL_STOP) {
00708                                                 err = nl_error(-e->error,
00709                                                          "Netlink Error");
00710                                                 goto out;
00711                                         }
00712                                 } else {
00713                                         err = nl_error(-e->error,
00714                                                   "Netlink Error");
00715                                         goto out;
00716                                 }
00717                         } else if (cb->cb_set[NL_CB_ACK])
00718                                 NL_CB_CALL(cb, NL_CB_ACK, msg);
00719                 } else {
00720                         /* Valid message (not checking for MULTIPART bit to
00721                          * get along with broken kernels. NL_SKIP has no
00722                          * effect on this.  */
00723                         if (cb->cb_set[NL_CB_VALID])
00724                                 NL_CB_CALL(cb, NL_CB_VALID, msg);
00725                 }
00726 skip:
00727                 err = 0;
00728                 hdr = nlmsg_next(hdr, &n);
00729         }
00730         
00731         nlmsg_free(msg);
00732         free(buf);
00733         free(creds);
00734         buf = NULL;
00735         msg = NULL;
00736         creds = NULL;
00737 
00738         if (multipart) {
00739                 /* Multipart message not yet complete, continue reading */
00740                 goto continue_reading;
00741         }
00742 stop:
00743         err = 0;
00744 out:
00745         nlmsg_free(msg);
00746         free(buf);
00747         free(creds);
00748 
00749         return err;
00750 }
00751 
00752 /**
00753  * Receive a set of messages from a netlink socket.
00754  * @arg handle          netlink handle
00755  * @arg cb              set of callbacks to control behaviour.
00756  *
00757  * Repeatedly calls nl_recv() or the respective replacement if provided
00758  * by the application (see nl_cb_overwrite_recv()) and parses the
00759  * received data as netlink messages. Stops reading if one of the
00760  * callbacks returns NL_STOP or nl_recv returns either 0 or a negative error code.
00761  *
00762  * A non-blocking sockets causes the function to return immediately if
00763  * no data is available.
00764  *
00765  * @return 0 on success or a negative error code from nl_recv().
00766  */
00767 int nl_recvmsgs(struct nl_handle *handle, struct nl_cb *cb)
00768 {
00769         if (cb->cb_recvmsgs_ow)
00770                 return cb->cb_recvmsgs_ow(handle, cb);
00771         else
00772                 return recvmsgs(handle, cb);
00773 }
00774 
00775 /**
00776  * Receive a set of message from a netlink socket using handlers in nl_handle.
00777  * @arg handle          netlink handle
00778  *
00779  * Calls nl_recvmsgs() with the handlers configured in the netlink handle.
00780  */
00781 int nl_recvmsgs_default(struct nl_handle *handle)
00782 {
00783         return nl_recvmsgs(handle, handle->h_cb);
00784 
00785 }
00786 
00787 static int ack_wait_handler(struct nl_msg *msg, void *arg)
00788 {
00789         return NL_STOP;
00790 }
00791 
00792 /**
00793  * Wait for ACK.
00794  * @arg handle          netlink handle
00795  * @pre The netlink socket must be in blocking state.
00796  *
00797  * Waits until an ACK is received for the latest not yet acknowledged
00798  * netlink message.
00799  */
00800 int nl_wait_for_ack(struct nl_handle *handle)
00801 {
00802         int err;
00803         struct nl_cb *cb;
00804 
00805         cb = nl_cb_clone(handle->h_cb);
00806         if (cb == NULL)
00807                 return nl_get_errno();
00808 
00809         nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_wait_handler, NULL);
00810         err = nl_recvmsgs(handle, cb);
00811         nl_cb_put(cb);
00812 
00813         return err;
00814 }
00815 
00816 /** @} */
00817 
00818 /** @} */