iproute2/lib/mnl_utils.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * mnl_utils.c  Helpers for working with libmnl.
   4 */
   5
   6#include <errno.h>
   7#include <string.h>
   8#include <time.h>
   9#include <libmnl/libmnl.h>
  10
  11#include "libnetlink.h"
  12#include "mnl_utils.h"
  13#include "utils.h"
  14
  15struct mnl_socket *mnlu_socket_open(int bus)
  16{
  17        struct mnl_socket *nl;
  18        int one = 1;
  19
  20        nl = mnl_socket_open(bus);
  21        if (nl == NULL)
  22                return NULL;
  23
  24        mnl_socket_setsockopt(nl, NETLINK_CAP_ACK, &one, sizeof(one));
  25        mnl_socket_setsockopt(nl, NETLINK_EXT_ACK, &one, sizeof(one));
  26
  27        if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0)
  28                goto err_bind;
  29
  30        return nl;
  31
  32err_bind:
  33        mnl_socket_close(nl);
  34        return NULL;
  35}
  36
  37struct nlmsghdr *mnlu_msg_prepare(void *buf, uint32_t nlmsg_type, uint16_t flags,
  38                                  void *extra_header, size_t extra_header_size)
  39{
  40        struct nlmsghdr *nlh;
  41        void *eh;
  42
  43        nlh = mnl_nlmsg_put_header(buf);
  44        nlh->nlmsg_type = nlmsg_type;
  45        nlh->nlmsg_flags = flags;
  46        nlh->nlmsg_seq = time(NULL);
  47
  48        eh = mnl_nlmsg_put_extra_header(nlh, extra_header_size);
  49        memcpy(eh, extra_header, extra_header_size);
  50
  51        return nlh;
  52}
  53
  54static int mnlu_cb_noop(const struct nlmsghdr *nlh, void *data)
  55{
  56        return MNL_CB_OK;
  57}
  58
  59static int mnlu_cb_error(const struct nlmsghdr *nlh, void *data)
  60{
  61        const struct nlmsgerr *err = mnl_nlmsg_get_payload(nlh);
  62
  63        /* Netlink subsystems returns the errno value with different signess */
  64        if (err->error < 0)
  65                errno = -err->error;
  66        else
  67                errno = err->error;
  68
  69        if (nl_dump_ext_ack(nlh, NULL))
  70                return MNL_CB_ERROR;
  71
  72        return err->error == 0 ? MNL_CB_STOP : MNL_CB_ERROR;
  73}
  74
  75static int mnlu_cb_stop(const struct nlmsghdr *nlh, void *data)
  76{
  77        int len = *(int *)NLMSG_DATA(nlh);
  78
  79        if (len < 0) {
  80                errno = -len;
  81                nl_dump_ext_ack_done(nlh, len);
  82                return MNL_CB_ERROR;
  83        }
  84        return MNL_CB_STOP;
  85}
  86
  87static mnl_cb_t mnlu_cb_array[NLMSG_MIN_TYPE] = {
  88        [NLMSG_NOOP]    = mnlu_cb_noop,
  89        [NLMSG_ERROR]   = mnlu_cb_error,
  90        [NLMSG_DONE]    = mnlu_cb_stop,
  91        [NLMSG_OVERRUN] = mnlu_cb_noop,
  92};
  93
  94int mnlu_socket_recv_run(struct mnl_socket *nl, unsigned int seq, void *buf, size_t buf_size,
  95                         mnl_cb_t cb, void *data)
  96{
  97        unsigned int portid = mnl_socket_get_portid(nl);
  98        int err;
  99
 100        do {
 101                err = mnl_socket_recvfrom(nl, buf, buf_size);
 102                if (err <= 0)
 103                        break;
 104                err = mnl_cb_run2(buf, err, seq, portid,
 105                                  cb, data, mnlu_cb_array,
 106                                  ARRAY_SIZE(mnlu_cb_array));
 107        } while (err > 0);
 108
 109        return err;
 110}
 111