Logo Search packages:      
Sourcecode: libnl version File versions  Download package

int nl_recvmsgs ( struct nl_handle *  handle,
struct nl_cb *  cb 
)

Receive a set of messages from a netlink socket.

  • handle netlink handle
  • cb set of callbacks to control the behaviour.
Repeatedly calls nl_recv() and parses the messages as netlink messages. Stops reading if one of the callbacks returns NL_EXIT 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 683 of file nl.c.

References nlmsgerr::error, NL_CB_ACK, NL_CB_FINISH, NL_CB_INVALID, NL_CB_MSG_IN, NL_CB_OVERRUN, NL_CB_SEND_ACK, NL_CB_SEQ_CHECK, NL_CB_SKIPPED, NL_CB_VALID, NL_EXIT, nl_recv(), NL_SKIP, nlmsg_data(), nlmsghdr::nlmsg_flags, nlmsg_free(), nlmsghdr::nlmsg_len, nlmsg_msg_size(), nlmsg_next(), NLMSG_NOOP, nlmsg_ok(), nlmsghdr::nlmsg_seq, and nlmsghdr::nlmsg_type.

Referenced by nl_cache_pickup(), nl_recvmsgs_def(), and nl_wait_for_ack().

{
      int n, err = 0;
      unsigned char *buf = NULL;
      struct nlmsghdr *hdr;
      struct sockaddr_nl nla = {0};
      struct nl_msg *msg = NULL;

continue_reading:
      if (cb->cb_recv_ow)
            n = cb->cb_recv_ow(handle, &nla, &buf);
      else
            n = nl_recv(handle, &nla, &buf);

      if (n <= 0)
            return n;

      hdr = (struct nlmsghdr *) buf;
      while (nlmsg_ok(hdr, n)) {

            nlmsg_free(msg);
            msg = nlmsg_convert(hdr);
            if (!msg) {
                  err = nl_errno(ENOMEM);
                  goto out;
            }

            nlmsg_set_proto(msg, handle->h_proto);
            nlmsg_set_src(msg, &nla);

            /* Raw callback is the first, it gives the most control
             * to the user and he can do his very own parsing. */
            if (cb->cb_set[NL_CB_MSG_IN]) {
                  err = nl_cb_call(cb, NL_CB_MSG_IN, msg);
                  if (err == NL_SKIP)
                        goto skip;
                  else if (err == NL_EXIT || err < 0)
                        goto out;
            }

            /* Sequence number checking. The check may be done by
             * the user, otherwise a very simple check is applied
             * enforcing strict ordering */
            if (cb->cb_set[NL_CB_SEQ_CHECK]) {
                  err = nl_cb_call(cb, NL_CB_SEQ_CHECK, msg);
                  if (err == NL_SKIP)
                        goto skip;
                  else if (err == NL_EXIT || err < 0)
                        goto out;
            } else if (hdr->nlmsg_seq != handle->h_seq_expect) {
                  if (cb->cb_set[NL_CB_INVALID]) {
                        err = nl_cb_call(cb, NL_CB_INVALID, msg);
                        if (err == NL_SKIP)
                              goto skip;
                        else if (err == NL_EXIT || err < 0)
                              goto out;
                  } else
                        goto out;
            }

            if (hdr->nlmsg_type == NLMSG_DONE ||
                hdr->nlmsg_type == NLMSG_ERROR ||
                hdr->nlmsg_type == NLMSG_NOOP ||
                hdr->nlmsg_type == NLMSG_OVERRUN) {
                  /* We can't check for !NLM_F_MULTI since some netlink
                   * users in the kernel are broken. */
                  handle->h_seq_expect++;
            }
      
            /* Other side wishes to see an ack for this message */
            if (hdr->nlmsg_flags & NLM_F_ACK) {
                  if (cb->cb_set[NL_CB_SEND_ACK]) {
                        err = nl_cb_call(cb, NL_CB_SEND_ACK, msg);
                        if (err == NL_SKIP)
                              goto skip;
                        else if (err == NL_EXIT || err < 0)
                              goto out;
                  } else {
                        /* FIXME: implement */
                  }
            }

            /* messages terminates a multpart message, this is
             * usually the end of a message and therefore we slip
             * out of the loop by default. the user may overrule
             * this action by skipping this packet. */
            if (hdr->nlmsg_type == NLMSG_DONE) {
                  if (cb->cb_set[NL_CB_FINISH]) {
                        err = nl_cb_call(cb, NL_CB_FINISH, msg);
                        if (err == NL_SKIP)
                              goto skip;
                        else if (err == NL_EXIT || err < 0)
                              goto out;
                  }
                  goto out;
            }

            /* Message to be ignored, the default action is to
             * skip this message if no callback is specified. The
             * user may overrule this action by returning
             * NL_PROCEED. */
            else if (hdr->nlmsg_type == NLMSG_NOOP) {
                  if (cb->cb_set[NL_CB_SKIPPED]) {
                        err = nl_cb_call(cb, NL_CB_SKIPPED, msg);
                        if (err == NL_SKIP)
                              goto skip;
                        else if (err == NL_EXIT || err < 0)
                              goto out;
                  } else
                        goto skip;
            }

            /* Data got lost, report back to user. The default action is to
             * quit parsing. The user may overrule this action by retuning
             * NL_SKIP or NL_PROCEED (dangerous) */
            else if (hdr->nlmsg_type == NLMSG_OVERRUN) {
                  if (cb->cb_set[NL_CB_OVERRUN]) {
                        err = nl_cb_call(cb, NL_CB_OVERRUN, msg);
                        if (err == NL_SKIP)
                              goto skip;
                        else if (err == NL_EXIT || err < 0)
                              goto out;
                  } else
                        goto out;
            }

            /* Message carries a nlmsgerr */
            else if (hdr->nlmsg_type == NLMSG_ERROR) {
                  struct nlmsgerr *e = nlmsg_data(hdr);

                  if (hdr->nlmsg_len < nlmsg_msg_size(sizeof(*e))) {
                        /* Truncated error message, the default action
                         * is to stop parsing. The user may overrule
                         * this action by returning NL_SKIP or
                         * NL_PROCEED (dangerous) */
                        if (cb->cb_set[NL_CB_INVALID]) {
                              err = nl_cb_call(cb, NL_CB_INVALID,
                                           msg);
                              if (err == NL_SKIP)
                                    goto skip;
                              else if (err == NL_EXIT || err < 0)
                                    goto out;
                        } else
                              goto out;
                  } else if (e->error) {
                        /* Error message reported back from kernel. */
                        if (cb->cb_err) {
                              err = cb->cb_err(&nla, e,
                                             cb->cb_err_arg);
                              if (err == NL_SKIP)
                                    goto skip;
                              else if (err == NL_EXIT || err < 0) {
                                    nl_error(-e->error,
                                           "Netlink Error");
                                    err = e->error;
                                    goto out;
                              }
                        } else {
                              nl_error(-e->error, "Netlink Error");
                              err = e->error;
                              goto out;
                        }
                  } else if (cb->cb_set[NL_CB_ACK]) {
                        /* ACK */
                        err = nl_cb_call(cb, NL_CB_ACK, msg);
                        if (err == NL_SKIP)
                              goto skip;
                        else if (err == NL_EXIT || err < 0)
                              goto out;
                  }
            } else {
                  /* Valid message (not checking for MULTIPART bit to
                   * get along with broken kernels. NL_SKIP has no
                   * effect on this.  */
                  if (cb->cb_set[NL_CB_VALID]) {
                        err = nl_cb_call(cb, NL_CB_VALID, msg);
                        if (err == NL_SKIP)
                              goto skip;
                        else if (err == NL_EXIT || err < 0)
                              goto out;
                  }
            }
skip:
            hdr = nlmsg_next(hdr, &n);
      }
      
      nlmsg_free(msg);
      free(buf);
      buf = NULL;
      msg = NULL;

      /* Multipart message not yet complete, continue reading */
      goto continue_reading;

out:
      nlmsg_free(msg);
      free(buf);

      return err;
}


Generated by  Doxygen 1.6.0   Back to index