iproute2/tipc/msg.c
<<
>>
Prefs
   1/*
   2 * msg.c        Messaging (netlink) helper functions.
   3 *
   4 *              This program is free software; you can redistribute it and/or
   5 *              modify it under the terms of the GNU General Public License
   6 *              as published by the Free Software Foundation; either version
   7 *              2 of the License, or (at your option) any later version.
   8 *
   9 * Authors:     Richard Alpe <richard.alpe@ericsson.com>
  10 */
  11
  12#include <stdio.h>
  13#include <time.h>
  14#include <errno.h>
  15
  16#include <linux/tipc_netlink.h>
  17#include <linux/tipc.h>
  18#include <linux/genetlink.h>
  19#include <libmnl/libmnl.h>
  20
  21#include "msg.h"
  22
  23int parse_attrs(const struct nlattr *attr, void *data)
  24{
  25        const struct nlattr **tb = data;
  26        int type = mnl_attr_get_type(attr);
  27
  28        tb[type] = attr;
  29
  30        return MNL_CB_OK;
  31}
  32
  33static int family_id_cb(const struct nlmsghdr *nlh, void *data)
  34{
  35        struct nlattr *tb[CTRL_ATTR_MAX + 1] = {};
  36        struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
  37        int *id = data;
  38
  39        mnl_attr_parse(nlh, sizeof(*genl), parse_attrs, tb);
  40        if (!tb[CTRL_ATTR_FAMILY_ID])
  41                return MNL_CB_ERROR;
  42
  43        *id = mnl_attr_get_u16(tb[CTRL_ATTR_FAMILY_ID]);
  44
  45        return MNL_CB_OK;
  46}
  47
  48static struct mnl_socket *msg_send(struct nlmsghdr *nlh)
  49{
  50        int ret;
  51        struct mnl_socket *nl;
  52
  53        nl = mnl_socket_open(NETLINK_GENERIC);
  54        if (nl == NULL) {
  55                perror("mnl_socket_open");
  56                return NULL;
  57        }
  58
  59        ret = mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID);
  60        if (ret < 0) {
  61                perror("mnl_socket_bind");
  62                return NULL;
  63        }
  64
  65        ret = mnl_socket_sendto(nl, nlh, nlh->nlmsg_len);
  66        if (ret < 0) {
  67                perror("mnl_socket_send");
  68                return NULL;
  69        }
  70
  71        return nl;
  72}
  73
  74static int msg_recv(struct mnl_socket *nl, mnl_cb_t callback, void *data, int seq)
  75{
  76        int ret;
  77        unsigned int portid;
  78        char buf[MNL_SOCKET_BUFFER_SIZE];
  79
  80        portid = mnl_socket_get_portid(nl);
  81
  82        ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
  83        while (ret > 0) {
  84                ret = mnl_cb_run(buf, ret, seq, portid, callback, data);
  85                if (ret <= 0)
  86                        break;
  87                ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
  88        }
  89        if (ret == -1)
  90                perror("error");
  91
  92        mnl_socket_close(nl);
  93
  94        return ret;
  95}
  96
  97static int msg_query(struct nlmsghdr *nlh, mnl_cb_t callback, void *data)
  98{
  99        unsigned int seq;
 100        struct mnl_socket *nl;
 101
 102        seq = time(NULL);
 103        nlh->nlmsg_seq = seq;
 104
 105        nl = msg_send(nlh);
 106        if (!nl)
 107                return -ENOTSUP;
 108
 109        return msg_recv(nl, callback, data, seq);
 110}
 111
 112static int get_family(void)
 113{
 114        int err;
 115        int nl_family;
 116        struct nlmsghdr *nlh;
 117        struct genlmsghdr *genl;
 118        char buf[MNL_SOCKET_BUFFER_SIZE];
 119
 120        nlh = mnl_nlmsg_put_header(buf);
 121        nlh->nlmsg_type = GENL_ID_CTRL;
 122        nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
 123
 124        genl = mnl_nlmsg_put_extra_header(nlh, sizeof(struct genlmsghdr));
 125        genl->cmd = CTRL_CMD_GETFAMILY;
 126        genl->version = 1;
 127
 128        mnl_attr_put_u16(nlh, CTRL_ATTR_FAMILY_ID, GENL_ID_CTRL);
 129        mnl_attr_put_strz(nlh, CTRL_ATTR_FAMILY_NAME, TIPC_GENL_V2_NAME);
 130
 131        if ((err = msg_query(nlh, family_id_cb, &nl_family)))
 132                return err;
 133
 134        return nl_family;
 135}
 136
 137int msg_doit(struct nlmsghdr *nlh, mnl_cb_t callback, void *data)
 138{
 139        nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
 140        return msg_query(nlh, callback, data);
 141}
 142
 143int msg_dumpit(struct nlmsghdr *nlh, mnl_cb_t callback, void *data)
 144{
 145        nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
 146        return msg_query(nlh, callback, data);
 147}
 148
 149struct nlmsghdr *msg_init(char *buf, int cmd)
 150{
 151        int family;
 152        struct nlmsghdr *nlh;
 153        struct genlmsghdr *genl;
 154
 155        family = get_family();
 156        if (family <= 0) {
 157                fprintf(stderr,
 158                        "Unable to get TIPC nl family id (module loaded?)\n");
 159                return NULL;
 160        }
 161
 162        nlh = mnl_nlmsg_put_header(buf);
 163        nlh->nlmsg_type = family;
 164
 165        genl = mnl_nlmsg_put_extra_header(nlh, sizeof(struct genlmsghdr));
 166        genl->cmd = cmd;
 167        genl->version = 1;
 168
 169        return nlh;
 170}
 171