iproute2/lib/libgenl.c
<<
>>
Prefs
   1/* SPDX-License-Identifier: GPL-2.0 */
   2/*
   3 * libgenl.c    GENL library
   4 */
   5
   6#include <errno.h>
   7#include <stdio.h>
   8#include <stdlib.h>
   9#include <unistd.h>
  10
  11#include <linux/genetlink.h>
  12#include "libgenl.h"
  13
  14static int genl_parse_getfamily(struct nlmsghdr *nlh)
  15{
  16        struct rtattr *tb[CTRL_ATTR_MAX + 1];
  17        struct genlmsghdr *ghdr = NLMSG_DATA(nlh);
  18        int len = nlh->nlmsg_len;
  19        struct rtattr *attrs;
  20
  21        if (nlh->nlmsg_type != GENL_ID_CTRL) {
  22                fprintf(stderr, "Not a controller message, nlmsg_len=%d "
  23                        "nlmsg_type=0x%x\n", nlh->nlmsg_len, nlh->nlmsg_type);
  24                return -1;
  25        }
  26
  27        len -= NLMSG_LENGTH(GENL_HDRLEN);
  28
  29        if (len < 0) {
  30                fprintf(stderr, "wrong controller message len %d\n", len);
  31                return -1;
  32        }
  33
  34        if (ghdr->cmd != CTRL_CMD_NEWFAMILY) {
  35                fprintf(stderr, "Unknown controller command %d\n", ghdr->cmd);
  36                return -1;
  37        }
  38
  39        attrs = (struct rtattr *) ((char *) ghdr + GENL_HDRLEN);
  40        parse_rtattr(tb, CTRL_ATTR_MAX, attrs, len);
  41
  42        if (tb[CTRL_ATTR_FAMILY_ID] == NULL) {
  43                fprintf(stderr, "Missing family id TLV\n");
  44                return -1;
  45        }
  46
  47        return rta_getattr_u16(tb[CTRL_ATTR_FAMILY_ID]);
  48}
  49
  50int genl_resolve_family(struct rtnl_handle *grth, const char *family)
  51{
  52        GENL_REQUEST(req, 1024, GENL_ID_CTRL, 0, 0, CTRL_CMD_GETFAMILY,
  53                     NLM_F_REQUEST);
  54        struct nlmsghdr *answer;
  55        int fnum;
  56
  57        addattr_l(&req.n, sizeof(req), CTRL_ATTR_FAMILY_NAME,
  58                  family, strlen(family) + 1);
  59
  60        if (rtnl_talk(grth, &req.n, &answer) < 0) {
  61                fprintf(stderr, "Error talking to the kernel\n");
  62                return -2;
  63        }
  64
  65        fnum = genl_parse_getfamily(answer);
  66        free(answer);
  67
  68        return fnum;
  69}
  70
  71static int genl_parse_grps(struct rtattr *attr, const char *name, unsigned int *id)
  72{
  73        const struct rtattr *pos;
  74
  75        rtattr_for_each_nested(pos, attr) {
  76                struct rtattr *tb[CTRL_ATTR_MCAST_GRP_MAX + 1];
  77
  78                parse_rtattr_nested(tb, CTRL_ATTR_MCAST_GRP_MAX, pos);
  79
  80                if (tb[CTRL_ATTR_MCAST_GRP_NAME] && tb[CTRL_ATTR_MCAST_GRP_ID]) {
  81                        if (strcmp(name, rta_getattr_str(tb[CTRL_ATTR_MCAST_GRP_NAME])) == 0) {
  82                                *id = rta_getattr_u32(tb[CTRL_ATTR_MCAST_GRP_ID]);
  83                                return 0;
  84                        }
  85                }
  86        }
  87
  88        errno = ENOENT;
  89        return -1;
  90}
  91
  92int genl_add_mcast_grp(struct rtnl_handle *grth, __u16 fnum, const char *group)
  93{
  94        GENL_REQUEST(req, 1024, GENL_ID_CTRL, 0, 0, CTRL_CMD_GETFAMILY,
  95                     NLM_F_REQUEST);
  96        struct rtattr *tb[CTRL_ATTR_MAX + 1];
  97        struct nlmsghdr *answer = NULL;
  98        struct genlmsghdr *ghdr;
  99        struct rtattr *attrs;
 100        int len, ret = -1;
 101        unsigned int id;
 102
 103        addattr16(&req.n, sizeof(req), CTRL_ATTR_FAMILY_ID, fnum);
 104
 105        if (rtnl_talk(grth, &req.n, &answer) < 0) {
 106                fprintf(stderr, "Error talking to the kernel\n");
 107                return -2;
 108        }
 109
 110        ghdr = NLMSG_DATA(answer);
 111        len = answer->nlmsg_len;
 112
 113        if (answer->nlmsg_type != GENL_ID_CTRL) {
 114                errno = EINVAL;
 115                goto err_free;
 116        }
 117
 118        len -= NLMSG_LENGTH(GENL_HDRLEN);
 119        if (len < 0) {
 120                errno = EINVAL;
 121                goto err_free;
 122        }
 123
 124        attrs = (struct rtattr *) ((char *) ghdr + GENL_HDRLEN);
 125        parse_rtattr(tb, CTRL_ATTR_MAX, attrs, len);
 126
 127        if (tb[CTRL_ATTR_MCAST_GROUPS] == NULL) {
 128                errno = ENOENT;
 129                fprintf(stderr, "Missing mcast groups TLV\n");
 130                goto err_free;
 131        }
 132
 133        if (genl_parse_grps(tb[CTRL_ATTR_MCAST_GROUPS], group, &id) < 0)
 134                goto err_free;
 135
 136        ret = rtnl_add_nl_group(grth, id);
 137
 138err_free:
 139        free(answer);
 140        return ret;
 141}
 142
 143int genl_init_handle(struct rtnl_handle *grth, const char *family,
 144                     int *genl_family)
 145{
 146        if (*genl_family >= 0)
 147                return 0;
 148
 149        if (rtnl_open_byproto(grth, 0, NETLINK_GENERIC) < 0) {
 150                fprintf(stderr, "Cannot open generic netlink socket\n");
 151                return -1;
 152        }
 153
 154        *genl_family = genl_resolve_family(grth, family);
 155        if (*genl_family < 0)
 156                return -1;
 157
 158        return 0;
 159}
 160