iproute2/lib/libnetlink.c
<<
>>
Prefs
   1/* SPDX-License-Identifier: GPL-2.0-or-later */
   2/*
   3 * libnetlink.c RTnetlink service routines.
   4 *
   5 * Authors:     Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
   6 */
   7
   8#include <stdio.h>
   9#include <stdlib.h>
  10#include <stdbool.h>
  11#include <unistd.h>
  12#include <fcntl.h>
  13#include <net/if_arp.h>
  14#include <sys/socket.h>
  15#include <netinet/in.h>
  16#include <string.h>
  17#include <errno.h>
  18#include <time.h>
  19#include <sys/uio.h>
  20#include <linux/fib_rules.h>
  21#include <linux/if_addrlabel.h>
  22#include <linux/if_bridge.h>
  23#include <linux/nexthop.h>
  24
  25#include "libnetlink.h"
  26#include "utils.h"
  27
  28#ifndef __aligned
  29#define __aligned(x)            __attribute__((aligned(x)))
  30#endif
  31
  32#ifndef SOL_NETLINK
  33#define SOL_NETLINK 270
  34#endif
  35
  36#ifndef MIN
  37#define MIN(a, b) ((a) < (b) ? (a) : (b))
  38#endif
  39
  40int rcvbuf = 1024 * 1024;
  41
  42#ifdef HAVE_LIBMNL
  43#include <libmnl/libmnl.h>
  44
  45static const enum mnl_attr_data_type extack_policy[NLMSGERR_ATTR_MAX + 1] = {
  46        [NLMSGERR_ATTR_MSG]     = MNL_TYPE_NUL_STRING,
  47        [NLMSGERR_ATTR_OFFS]    = MNL_TYPE_U32,
  48};
  49
  50static int err_attr_cb(const struct nlattr *attr, void *data)
  51{
  52        const struct nlattr **tb = data;
  53        uint16_t type;
  54
  55        if (mnl_attr_type_valid(attr, NLMSGERR_ATTR_MAX) < 0) {
  56                fprintf(stderr, "Invalid extack attribute\n");
  57                return MNL_CB_ERROR;
  58        }
  59
  60        type = mnl_attr_get_type(attr);
  61        if (mnl_attr_validate(attr, extack_policy[type]) < 0) {
  62                fprintf(stderr, "extack attribute %d failed validation\n",
  63                        type);
  64                return MNL_CB_ERROR;
  65        }
  66
  67        tb[type] = attr;
  68        return MNL_CB_OK;
  69}
  70
  71static void print_ext_ack_msg(bool is_err, const char *msg)
  72{
  73        fprintf(stderr, "%s: %s", is_err ? "Error" : "Warning", msg);
  74        if (msg[strlen(msg) - 1] != '.')
  75                fprintf(stderr, ".");
  76        fprintf(stderr, "\n");
  77}
  78
  79/* dump netlink extended ack error message */
  80int nl_dump_ext_ack(const struct nlmsghdr *nlh, nl_ext_ack_fn_t errfn)
  81{
  82        struct nlattr *tb[NLMSGERR_ATTR_MAX + 1] = {};
  83        const struct nlmsgerr *err = mnl_nlmsg_get_payload(nlh);
  84        const struct nlmsghdr *err_nlh = NULL;
  85        unsigned int hlen = sizeof(*err);
  86        const char *msg = NULL;
  87        uint32_t off = 0;
  88
  89        /* no TLVs, nothing to do here */
  90        if (!(nlh->nlmsg_flags & NLM_F_ACK_TLVS))
  91                return 0;
  92
  93        /* if NLM_F_CAPPED is set then the inner err msg was capped */
  94        if (!(nlh->nlmsg_flags & NLM_F_CAPPED))
  95                hlen += mnl_nlmsg_get_payload_len(&err->msg);
  96
  97        if (mnl_attr_parse(nlh, hlen, err_attr_cb, tb) != MNL_CB_OK)
  98                return 0;
  99
 100        if (tb[NLMSGERR_ATTR_MSG])
 101                msg = mnl_attr_get_str(tb[NLMSGERR_ATTR_MSG]);
 102
 103        if (tb[NLMSGERR_ATTR_OFFS]) {
 104                off = mnl_attr_get_u32(tb[NLMSGERR_ATTR_OFFS]);
 105
 106                if (off > nlh->nlmsg_len) {
 107                        fprintf(stderr,
 108                                "Invalid offset for NLMSGERR_ATTR_OFFS\n");
 109                        off = 0;
 110                } else if (!(nlh->nlmsg_flags & NLM_F_CAPPED))
 111                        err_nlh = &err->msg;
 112        }
 113
 114        if (tb[NLMSGERR_ATTR_MISS_TYPE])
 115                fprintf(stderr, "Missing required attribute type %u\n",
 116                        mnl_attr_get_u32(tb[NLMSGERR_ATTR_MISS_TYPE]));
 117
 118        if (errfn)
 119                return errfn(msg, off, err_nlh);
 120
 121        if (msg && *msg != '\0') {
 122                bool is_err = !!err->error;
 123
 124                print_ext_ack_msg(is_err, msg);
 125                return is_err ? 1 : 0;
 126        }
 127
 128        return 0;
 129}
 130
 131int nl_dump_ext_ack_done(const struct nlmsghdr *nlh, unsigned int offset, int error)
 132{
 133        struct nlattr *tb[NLMSGERR_ATTR_MAX + 1] = {};
 134        const char *msg = NULL;
 135
 136        if (mnl_attr_parse(nlh, offset, err_attr_cb, tb) != MNL_CB_OK)
 137                return 0;
 138
 139        if (tb[NLMSGERR_ATTR_MSG])
 140                msg = mnl_attr_get_str(tb[NLMSGERR_ATTR_MSG]);
 141
 142        if (msg && *msg != '\0') {
 143                bool is_err = !!error;
 144
 145                print_ext_ack_msg(is_err, msg);
 146                return is_err ? 1 : 0;
 147        }
 148
 149        return 0;
 150}
 151#else
 152#warning "libmnl required for error support"
 153
 154/* No extended error ack without libmnl */
 155int nl_dump_ext_ack(const struct nlmsghdr *nlh, nl_ext_ack_fn_t errfn)
 156{
 157        return 0;
 158}
 159
 160int nl_dump_ext_ack_done(const struct nlmsghdr *nlh, unsigned int offset, int error)
 161{
 162        return 0;
 163}
 164#endif
 165
 166/* Older kernels may not support strict dump and filtering */
 167void rtnl_set_strict_dump(struct rtnl_handle *rth)
 168{
 169        int one = 1;
 170
 171        if (setsockopt(rth->fd, SOL_NETLINK, NETLINK_GET_STRICT_CHK,
 172                       &one, sizeof(one)) < 0)
 173                return;
 174
 175        rth->flags |= RTNL_HANDLE_F_STRICT_CHK;
 176}
 177
 178int rtnl_add_nl_group(struct rtnl_handle *rth, unsigned int group)
 179{
 180        return setsockopt(rth->fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP,
 181                          &group, sizeof(group));
 182}
 183
 184void rtnl_close(struct rtnl_handle *rth)
 185{
 186        if (rth->fd >= 0) {
 187                close(rth->fd);
 188                rth->fd = -1;
 189        }
 190}
 191
 192int rtnl_open_byproto(struct rtnl_handle *rth, unsigned int subscriptions,
 193                      int protocol)
 194{
 195        socklen_t addr_len;
 196        int sndbuf = 32768;
 197        int one = 1;
 198
 199        memset(rth, 0, sizeof(*rth));
 200
 201        rth->proto = protocol;
 202        rth->fd = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, protocol);
 203        if (rth->fd < 0) {
 204                perror("Cannot open netlink socket");
 205                return -1;
 206        }
 207
 208        if (setsockopt(rth->fd, SOL_SOCKET, SO_SNDBUF,
 209                       &sndbuf, sizeof(sndbuf)) < 0) {
 210                perror("SO_SNDBUF");
 211                goto err;
 212        }
 213
 214        if (setsockopt(rth->fd, SOL_SOCKET, SO_RCVBUF,
 215                       &rcvbuf, sizeof(rcvbuf)) < 0) {
 216                perror("SO_RCVBUF");
 217                goto err;
 218        }
 219
 220        /* Older kernels may no support extended ACK reporting */
 221        setsockopt(rth->fd, SOL_NETLINK, NETLINK_EXT_ACK,
 222                   &one, sizeof(one));
 223
 224        memset(&rth->local, 0, sizeof(rth->local));
 225        rth->local.nl_family = AF_NETLINK;
 226        rth->local.nl_groups = subscriptions;
 227
 228        if (bind(rth->fd, (struct sockaddr *)&rth->local,
 229                 sizeof(rth->local)) < 0) {
 230                perror("Cannot bind netlink socket");
 231                goto err;
 232        }
 233        addr_len = sizeof(rth->local);
 234        if (getsockname(rth->fd, (struct sockaddr *)&rth->local,
 235                        &addr_len) < 0) {
 236                perror("Cannot getsockname");
 237                goto err;
 238        }
 239        if (addr_len != sizeof(rth->local)) {
 240                fprintf(stderr, "Wrong address length %d\n", addr_len);
 241                goto err;
 242        }
 243        if (rth->local.nl_family != AF_NETLINK) {
 244                fprintf(stderr, "Wrong address family %d\n",
 245                        rth->local.nl_family);
 246                goto err;
 247        }
 248        rth->seq = time(NULL);
 249        return 0;
 250err:
 251        rtnl_close(rth);
 252        return -1;
 253}
 254
 255int rtnl_open(struct rtnl_handle *rth, unsigned int subscriptions)
 256{
 257        return rtnl_open_byproto(rth, subscriptions, NETLINK_ROUTE);
 258}
 259
 260int rtnl_nexthopdump_req(struct rtnl_handle *rth, int family,
 261                         req_filter_fn_t filter_fn)
 262{
 263        struct {
 264                struct nlmsghdr nlh;
 265                struct nhmsg nhm;
 266                char buf[128];
 267        } req = {
 268                .nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct nhmsg)),
 269                .nlh.nlmsg_type = RTM_GETNEXTHOP,
 270                .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
 271                .nlh.nlmsg_seq = rth->dump = ++rth->seq,
 272                .nhm.nh_family = family,
 273        };
 274
 275        if (filter_fn) {
 276                int err;
 277
 278                err = filter_fn(&req.nlh, sizeof(req));
 279                if (err)
 280                        return err;
 281        }
 282
 283        return send(rth->fd, &req, sizeof(req), 0);
 284}
 285
 286int rtnl_nexthop_bucket_dump_req(struct rtnl_handle *rth, int family,
 287                                 req_filter_fn_t filter_fn)
 288{
 289        struct {
 290                struct nlmsghdr nlh;
 291                struct nhmsg nhm;
 292                char buf[128];
 293        } req = {
 294                .nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct nhmsg)),
 295                .nlh.nlmsg_type = RTM_GETNEXTHOPBUCKET,
 296                .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
 297                .nlh.nlmsg_seq = rth->dump = ++rth->seq,
 298                .nhm.nh_family = family,
 299        };
 300
 301        if (filter_fn) {
 302                int err;
 303
 304                err = filter_fn(&req.nlh, sizeof(req));
 305                if (err)
 306                        return err;
 307        }
 308
 309        return send(rth->fd, &req, sizeof(req), 0);
 310}
 311
 312int rtnl_addrdump_req(struct rtnl_handle *rth, int family,
 313                      req_filter_fn_t filter_fn)
 314{
 315        struct {
 316                struct nlmsghdr nlh;
 317                struct ifaddrmsg ifm;
 318                char buf[128];
 319        } req = {
 320                .nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)),
 321                .nlh.nlmsg_type = RTM_GETADDR,
 322                .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
 323                .nlh.nlmsg_seq = rth->dump = ++rth->seq,
 324                .ifm.ifa_family = family,
 325        };
 326
 327        if (filter_fn) {
 328                int err;
 329
 330                err = filter_fn(&req.nlh, sizeof(req));
 331                if (err)
 332                        return err;
 333        }
 334
 335        return send(rth->fd, &req, sizeof(req), 0);
 336}
 337
 338int rtnl_addrlbldump_req(struct rtnl_handle *rth, int family)
 339{
 340        struct {
 341                struct nlmsghdr nlh;
 342                struct ifaddrlblmsg ifal;
 343        } req = {
 344                .nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrlblmsg)),
 345                .nlh.nlmsg_type = RTM_GETADDRLABEL,
 346                .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
 347                .nlh.nlmsg_seq = rth->dump = ++rth->seq,
 348                .ifal.ifal_family = family,
 349        };
 350
 351        return send(rth->fd, &req, sizeof(req), 0);
 352}
 353
 354int rtnl_routedump_req(struct rtnl_handle *rth, int family,
 355                       req_filter_fn_t filter_fn)
 356{
 357        struct {
 358                struct nlmsghdr nlh;
 359                struct rtmsg rtm;
 360                char buf[128];
 361        } req = {
 362                .nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)),
 363                .nlh.nlmsg_type = RTM_GETROUTE,
 364                .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
 365                .nlh.nlmsg_seq = rth->dump = ++rth->seq,
 366                .rtm.rtm_family = family,
 367        };
 368
 369        if (filter_fn) {
 370                int err;
 371
 372                err = filter_fn(&req.nlh, sizeof(req));
 373                if (err)
 374                        return err;
 375        }
 376
 377        return send(rth->fd, &req, sizeof(req), 0);
 378}
 379
 380int rtnl_ruledump_req(struct rtnl_handle *rth, int family)
 381{
 382        struct {
 383                struct nlmsghdr nlh;
 384                struct fib_rule_hdr frh;
 385        } req = {
 386                .nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct fib_rule_hdr)),
 387                .nlh.nlmsg_type = RTM_GETRULE,
 388                .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
 389                .nlh.nlmsg_seq = rth->dump = ++rth->seq,
 390                .frh.family = family
 391        };
 392
 393        return send(rth->fd, &req, sizeof(req), 0);
 394}
 395
 396int rtnl_neighdump_req(struct rtnl_handle *rth, int family,
 397                       req_filter_fn_t filter_fn)
 398{
 399        struct {
 400                struct nlmsghdr nlh;
 401                struct ndmsg ndm;
 402                char buf[256];
 403        } req = {
 404                .nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)),
 405                .nlh.nlmsg_type = RTM_GETNEIGH,
 406                .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
 407                .nlh.nlmsg_seq = rth->dump = ++rth->seq,
 408                .ndm.ndm_family = family,
 409        };
 410
 411        if (filter_fn) {
 412                int err;
 413
 414                err = filter_fn(&req.nlh, sizeof(req));
 415                if (err)
 416                        return err;
 417        }
 418
 419        return send(rth->fd, &req, sizeof(req), 0);
 420}
 421
 422int rtnl_neightbldump_req(struct rtnl_handle *rth, int family)
 423{
 424        struct {
 425                struct nlmsghdr nlh;
 426                struct ndtmsg ndtmsg;
 427        } req = {
 428                .nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndtmsg)),
 429                .nlh.nlmsg_type = RTM_GETNEIGHTBL,
 430                .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
 431                .nlh.nlmsg_seq = rth->dump = ++rth->seq,
 432                .ndtmsg.ndtm_family = family,
 433        };
 434
 435        return send(rth->fd, &req, sizeof(req), 0);
 436}
 437
 438int rtnl_mdbdump_req(struct rtnl_handle *rth, int family)
 439{
 440        struct {
 441                struct nlmsghdr nlh;
 442                struct br_port_msg bpm;
 443        } req = {
 444                .nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct br_port_msg)),
 445                .nlh.nlmsg_type = RTM_GETMDB,
 446                .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
 447                .nlh.nlmsg_seq = rth->dump = ++rth->seq,
 448                .bpm.family = family,
 449        };
 450
 451        return send(rth->fd, &req, sizeof(req), 0);
 452}
 453
 454int rtnl_brvlandump_req(struct rtnl_handle *rth, int family, __u32 dump_flags)
 455{
 456        struct {
 457                struct nlmsghdr nlh;
 458                struct br_vlan_msg bvm;
 459                char buf[256];
 460        } req = {
 461                .nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct br_vlan_msg)),
 462                .nlh.nlmsg_type = RTM_GETVLAN,
 463                .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
 464                .nlh.nlmsg_seq = rth->dump = ++rth->seq,
 465                .bvm.family = family,
 466        };
 467
 468        addattr32(&req.nlh, sizeof(req), BRIDGE_VLANDB_DUMP_FLAGS, dump_flags);
 469
 470        return send(rth->fd, &req, sizeof(req), 0);
 471}
 472
 473int rtnl_netconfdump_req(struct rtnl_handle *rth, int family)
 474{
 475        struct {
 476                struct nlmsghdr nlh;
 477                struct netconfmsg ncm;
 478                char buf[0] __aligned(NLMSG_ALIGNTO);
 479        } req = {
 480                .nlh.nlmsg_len = NLMSG_LENGTH(NLMSG_ALIGN(sizeof(struct netconfmsg))),
 481                .nlh.nlmsg_type = RTM_GETNETCONF,
 482                .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
 483                .nlh.nlmsg_seq = rth->dump = ++rth->seq,
 484                .ncm.ncm_family = family,
 485        };
 486
 487        return send(rth->fd, &req, sizeof(req), 0);
 488}
 489
 490int rtnl_nsiddump_req_filter_fn(struct rtnl_handle *rth, int family,
 491                                req_filter_fn_t filter_fn)
 492{
 493        struct {
 494                struct nlmsghdr nlh;
 495                struct rtgenmsg rtm;
 496                char buf[1024];
 497        } req = {
 498                .nlh.nlmsg_len = NLMSG_LENGTH(NLMSG_ALIGN(sizeof(struct rtgenmsg))),
 499                .nlh.nlmsg_type = RTM_GETNSID,
 500                .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
 501                .nlh.nlmsg_seq = rth->dump = ++rth->seq,
 502                .rtm.rtgen_family = family,
 503        };
 504        int err;
 505
 506        if (!filter_fn)
 507                return -EINVAL;
 508
 509        err = filter_fn(&req.nlh, sizeof(req));
 510        if (err)
 511                return err;
 512
 513        return send(rth->fd, &req, req.nlh.nlmsg_len, 0);
 514}
 515
 516static int __rtnl_linkdump_req(struct rtnl_handle *rth, int family)
 517{
 518        struct {
 519                struct nlmsghdr nlh;
 520                struct ifinfomsg ifm;
 521        } req = {
 522                .nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
 523                .nlh.nlmsg_type = RTM_GETLINK,
 524                .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
 525                .nlh.nlmsg_seq = rth->dump = ++rth->seq,
 526                .ifm.ifi_family = family,
 527        };
 528
 529        return send(rth->fd, &req, sizeof(req), 0);
 530}
 531
 532int rtnl_linkdump_req(struct rtnl_handle *rth, int family)
 533{
 534        if (family == AF_UNSPEC)
 535                return rtnl_linkdump_req_filter(rth, family, RTEXT_FILTER_VF);
 536
 537        return __rtnl_linkdump_req(rth, family);
 538}
 539
 540int rtnl_linkdump_req_filter(struct rtnl_handle *rth, int family,
 541                            __u32 filt_mask)
 542{
 543        if (family == AF_UNSPEC || family == AF_BRIDGE) {
 544                struct {
 545                        struct nlmsghdr nlh;
 546                        struct ifinfomsg ifm;
 547                        /* attribute has to be NLMSG aligned */
 548                        struct rtattr ext_req __aligned(NLMSG_ALIGNTO);
 549                        __u32 ext_filter_mask;
 550                } req = {
 551                        .nlh.nlmsg_len = sizeof(req),
 552                        .nlh.nlmsg_type = RTM_GETLINK,
 553                        .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
 554                        .nlh.nlmsg_seq = rth->dump = ++rth->seq,
 555                        .ifm.ifi_family = family,
 556                        .ext_req.rta_type = IFLA_EXT_MASK,
 557                        .ext_req.rta_len = RTA_LENGTH(sizeof(__u32)),
 558                        .ext_filter_mask = filt_mask,
 559                };
 560
 561                return send(rth->fd, &req, sizeof(req), 0);
 562        }
 563
 564        return __rtnl_linkdump_req(rth, family);
 565}
 566
 567int rtnl_linkdump_req_filter_fn(struct rtnl_handle *rth, int family,
 568                                req_filter_fn_t filter_fn)
 569{
 570        if (family == AF_UNSPEC || family == AF_PACKET) {
 571                struct {
 572                        struct nlmsghdr nlh;
 573                        struct ifinfomsg ifm;
 574                        char buf[1024];
 575                } req = {
 576                        .nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
 577                        .nlh.nlmsg_type = RTM_GETLINK,
 578                        .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
 579                        .nlh.nlmsg_seq = rth->dump = ++rth->seq,
 580                        .ifm.ifi_family = family,
 581                };
 582                int err;
 583
 584                if (!filter_fn)
 585                        return -EINVAL;
 586
 587                err = filter_fn(&req.nlh, sizeof(req));
 588                if (err)
 589                        return err;
 590
 591                return send(rth->fd, &req, req.nlh.nlmsg_len, 0);
 592        }
 593
 594        return __rtnl_linkdump_req(rth, family);
 595}
 596
 597int rtnl_fdb_linkdump_req_filter_fn(struct rtnl_handle *rth,
 598                                    req_filter_fn_t filter_fn)
 599{
 600        struct {
 601                struct nlmsghdr nlh;
 602                struct ifinfomsg ifm;
 603                char buf[128];
 604        } req = {
 605                .nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
 606                .nlh.nlmsg_type = RTM_GETNEIGH,
 607                .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
 608                .nlh.nlmsg_seq = rth->dump = ++rth->seq,
 609                .ifm.ifi_family = PF_BRIDGE,
 610        };
 611        int err;
 612
 613        err = filter_fn(&req.nlh, sizeof(req));
 614        if (err)
 615                return err;
 616
 617        return send(rth->fd, &req, sizeof(req), 0);
 618}
 619
 620int rtnl_statsdump_req_filter(struct rtnl_handle *rth, int fam,
 621                              __u32 filt_mask,
 622                              int (*filter_fn)(struct ipstats_req *req,
 623                                               void *data),
 624                              void *filter_data)
 625{
 626        struct ipstats_req req;
 627
 628        memset(&req, 0, sizeof(req));
 629        req.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct if_stats_msg));
 630        req.nlh.nlmsg_type = RTM_GETSTATS;
 631        req.nlh.nlmsg_flags = NLM_F_DUMP|NLM_F_REQUEST;
 632        req.nlh.nlmsg_pid = 0;
 633        req.nlh.nlmsg_seq = rth->dump = ++rth->seq;
 634        req.ifsm.family = fam;
 635        req.ifsm.filter_mask = filt_mask;
 636
 637        if (filter_fn) {
 638                int err;
 639
 640                err = filter_fn(&req, filter_data);
 641                if (err)
 642                        return err;
 643        }
 644
 645        return send(rth->fd, &req, sizeof(req), 0);
 646}
 647
 648int rtnl_send(struct rtnl_handle *rth, const void *buf, int len)
 649{
 650        return send(rth->fd, buf, len, 0);
 651}
 652
 653int rtnl_send_check(struct rtnl_handle *rth, const void *buf, int len)
 654{
 655        struct nlmsghdr *h;
 656        int status;
 657        char resp[1024];
 658
 659        status = send(rth->fd, buf, len, 0);
 660        if (status < 0)
 661                return status;
 662
 663        /* Check for immediate errors */
 664        status = recv(rth->fd, resp, sizeof(resp), MSG_DONTWAIT|MSG_PEEK);
 665        if (status < 0) {
 666                if (errno == EAGAIN)
 667                        return 0;
 668                return -1;
 669        }
 670
 671        for (h = (struct nlmsghdr *)resp; NLMSG_OK(h, status);
 672             h = NLMSG_NEXT(h, status)) {
 673                if (h->nlmsg_type == NLMSG_ERROR) {
 674                        struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(h);
 675
 676                        if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
 677                                fprintf(stderr, "ERROR truncated\n");
 678                        else
 679                                errno = -err->error;
 680                        return -1;
 681                }
 682        }
 683
 684        return 0;
 685}
 686
 687int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len)
 688{
 689        struct nlmsghdr nlh = {
 690                .nlmsg_len = NLMSG_LENGTH(len),
 691                .nlmsg_type = type,
 692                .nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
 693                .nlmsg_seq = rth->dump = ++rth->seq,
 694        };
 695        struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK };
 696        struct iovec iov[2] = {
 697                { .iov_base = &nlh, .iov_len = sizeof(nlh) },
 698                { .iov_base = req, .iov_len = len }
 699        };
 700        struct msghdr msg = {
 701                .msg_name = &nladdr,
 702                .msg_namelen = sizeof(nladdr),
 703                .msg_iov = iov,
 704                .msg_iovlen = 2,
 705        };
 706
 707        return sendmsg(rth->fd, &msg, 0);
 708}
 709
 710int rtnl_dump_request_n(struct rtnl_handle *rth, struct nlmsghdr *n)
 711{
 712        struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK };
 713        struct iovec iov = {
 714                .iov_base = n,
 715                .iov_len = n->nlmsg_len
 716        };
 717        struct msghdr msg = {
 718                .msg_name = &nladdr,
 719                .msg_namelen = sizeof(nladdr),
 720                .msg_iov = &iov,
 721                .msg_iovlen = 1,
 722        };
 723
 724        n->nlmsg_flags = NLM_F_DUMP|NLM_F_REQUEST;
 725        n->nlmsg_pid = 0;
 726        n->nlmsg_seq = rth->dump = ++rth->seq;
 727
 728        return sendmsg(rth->fd, &msg, 0);
 729}
 730
 731static int rtnl_dump_done(struct nlmsghdr *h,
 732                          const struct rtnl_dump_filter_arg *a)
 733{
 734        int len;
 735
 736        if (h->nlmsg_len < NLMSG_LENGTH(sizeof(int))) {
 737                fprintf(stderr, "DONE truncated\n");
 738                return -1;
 739        }
 740
 741        len = *(int *)NLMSG_DATA(h);
 742
 743        if (len < 0) {
 744                errno = -len;
 745
 746                if (a->errhndlr && (a->errhndlr(h, a->arg2) & RTNL_SUPPRESS_NLMSG_DONE_NLERR))
 747                        return 0;
 748
 749                /* check for any messages returned from kernel */
 750                if (nl_dump_ext_ack_done(h, sizeof(int), len))
 751                        return len;
 752
 753                switch (errno) {
 754                case ENOENT:
 755                case EOPNOTSUPP:
 756                        return -1;
 757                case EMSGSIZE:
 758                        fprintf(stderr,
 759                                "Error: Buffer too small for object.\n");
 760                        break;
 761                default:
 762                        perror("RTNETLINK answers");
 763                }
 764                return len;
 765        }
 766
 767        /* check for any messages returned from kernel */
 768        nl_dump_ext_ack(h, NULL);
 769
 770        return 0;
 771}
 772
 773static int rtnl_dump_error(const struct rtnl_handle *rth,
 774                            struct nlmsghdr *h,
 775                            const struct rtnl_dump_filter_arg *a)
 776{
 777
 778        if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) {
 779                fprintf(stderr, "ERROR truncated\n");
 780        } else {
 781                const struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(h);
 782
 783                errno = -err->error;
 784                if (rth->proto == NETLINK_SOCK_DIAG &&
 785                    (errno == ENOENT ||
 786                     errno == EOPNOTSUPP))
 787                        return -1;
 788
 789                if (a->errhndlr && (a->errhndlr(h, a->arg2) & RTNL_SUPPRESS_NLMSG_ERROR_NLERR))
 790                        return 0;
 791
 792                if (!(rth->flags & RTNL_HANDLE_F_SUPPRESS_NLERR))
 793                        perror("RTNETLINK answers");
 794        }
 795
 796        return -1;
 797}
 798
 799static int __rtnl_recvmsg(int fd, struct msghdr *msg, int flags)
 800{
 801        int len;
 802
 803        do {
 804                len = recvmsg(fd, msg, flags);
 805        } while (len < 0 && (errno == EINTR || errno == EAGAIN));
 806
 807        if (len < 0) {
 808                fprintf(stderr, "netlink receive error %s (%d)\n",
 809                        strerror(errno), errno);
 810                return -errno;
 811        }
 812
 813        if (len == 0) {
 814                fprintf(stderr, "EOF on netlink\n");
 815                return -ENODATA;
 816        }
 817
 818        return len;
 819}
 820
 821static int rtnl_recvmsg(int fd, struct msghdr *msg, char **answer)
 822{
 823        struct iovec *iov = msg->msg_iov;
 824        char *buf;
 825        int len;
 826
 827        iov->iov_base = NULL;
 828        iov->iov_len = 0;
 829
 830        len = __rtnl_recvmsg(fd, msg, MSG_PEEK | MSG_TRUNC);
 831        if (len < 0)
 832                return len;
 833
 834        if (len < 32768)
 835                len = 32768;
 836        buf = malloc(len);
 837        if (!buf) {
 838                fprintf(stderr, "malloc error: not enough buffer\n");
 839                return -ENOMEM;
 840        }
 841
 842        iov->iov_base = buf;
 843        iov->iov_len = len;
 844
 845        len = __rtnl_recvmsg(fd, msg, 0);
 846        if (len < 0) {
 847                free(buf);
 848                return len;
 849        }
 850
 851        if (answer)
 852                *answer = buf;
 853        else
 854                free(buf);
 855
 856        return len;
 857}
 858
 859static int rtnl_dump_filter_l(struct rtnl_handle *rth,
 860                              const struct rtnl_dump_filter_arg *arg)
 861{
 862        struct sockaddr_nl nladdr;
 863        struct iovec iov;
 864        struct msghdr msg = {
 865                .msg_name = &nladdr,
 866                .msg_namelen = sizeof(nladdr),
 867                .msg_iov = &iov,
 868                .msg_iovlen = 1,
 869        };
 870        char *buf;
 871        int dump_intr = 0;
 872
 873        while (1) {
 874                int status;
 875                const struct rtnl_dump_filter_arg *a;
 876                int found_done = 0;
 877                int msglen = 0;
 878
 879                status = rtnl_recvmsg(rth->fd, &msg, &buf);
 880                if (status < 0)
 881                        return status;
 882
 883                if (rth->dump_fp)
 884                        fwrite(buf, 1, NLMSG_ALIGN(status), rth->dump_fp);
 885
 886                for (a = arg; a->filter; a++) {
 887                        struct nlmsghdr *h = (struct nlmsghdr *)buf;
 888
 889                        msglen = status;
 890
 891                        while (NLMSG_OK(h, msglen)) {
 892                                int err = 0;
 893
 894                                h->nlmsg_flags &= ~a->nc_flags;
 895
 896                                if (nladdr.nl_pid != 0 ||
 897                                    h->nlmsg_pid != rth->local.nl_pid ||
 898                                    h->nlmsg_seq != rth->dump)
 899                                        goto skip_it;
 900
 901                                if (h->nlmsg_flags & NLM_F_DUMP_INTR)
 902                                        dump_intr = 1;
 903
 904                                if (h->nlmsg_type == NLMSG_DONE) {
 905                                        err = rtnl_dump_done(h, a);
 906                                        if (err < 0) {
 907                                                free(buf);
 908                                                return -1;
 909                                        }
 910
 911                                        found_done = 1;
 912                                        break; /* process next filter */
 913                                }
 914
 915                                if (h->nlmsg_type == NLMSG_ERROR) {
 916                                        err = rtnl_dump_error(rth, h, a);
 917                                        if (err < 0) {
 918                                                free(buf);
 919                                                return -1;
 920                                        }
 921
 922                                        goto skip_it;
 923                                }
 924
 925                                if (!rth->dump_fp) {
 926                                        err = a->filter(h, a->arg1);
 927                                        if (err < 0) {
 928                                                free(buf);
 929                                                return err;
 930                                        }
 931                                }
 932
 933skip_it:
 934                                h = NLMSG_NEXT(h, msglen);
 935                        }
 936                }
 937                free(buf);
 938
 939                if (found_done) {
 940                        if (dump_intr)
 941                                fprintf(stderr,
 942                                        "Dump was interrupted and may be inconsistent.\n");
 943                        return 0;
 944                }
 945
 946                if (msg.msg_flags & MSG_TRUNC) {
 947                        fprintf(stderr, "Message truncated\n");
 948                        continue;
 949                }
 950                if (msglen) {
 951                        fprintf(stderr, "!!!Remnant of size %d\n", msglen);
 952                        exit(1);
 953                }
 954        }
 955}
 956
 957int rtnl_dump_filter_nc(struct rtnl_handle *rth,
 958                        rtnl_filter_t filter,
 959                        void *arg1, __u16 nc_flags)
 960{
 961        const struct rtnl_dump_filter_arg a[] = {
 962                {
 963                        .filter = filter, .arg1 = arg1,
 964                        .nc_flags = nc_flags,
 965                },
 966                { },
 967        };
 968
 969        return rtnl_dump_filter_l(rth, a);
 970}
 971
 972int rtnl_dump_filter_errhndlr_nc(struct rtnl_handle *rth,
 973                     rtnl_filter_t filter,
 974                     void *arg1,
 975                     rtnl_err_hndlr_t errhndlr,
 976                     void *arg2,
 977                     __u16 nc_flags)
 978{
 979        const struct rtnl_dump_filter_arg a[] = {
 980                {
 981                        .filter = filter, .arg1 = arg1,
 982                        .errhndlr = errhndlr, .arg2 = arg2,
 983                        .nc_flags = nc_flags,
 984                },
 985                { },
 986        };
 987
 988        return rtnl_dump_filter_l(rth, a);
 989}
 990
 991static void rtnl_talk_error(struct nlmsghdr *h, struct nlmsgerr *err,
 992                            nl_ext_ack_fn_t errfn)
 993{
 994        if (nl_dump_ext_ack(h, errfn))
 995                return;
 996
 997        fprintf(stderr, "RTNETLINK answers: %s\n",
 998                strerror(-err->error));
 999}
1000
1001
1002static int __rtnl_talk_iov(struct rtnl_handle *rtnl, struct iovec *iov,
1003                           size_t iovlen, struct nlmsghdr **answer,
1004                           bool show_rtnl_err, nl_ext_ack_fn_t errfn)
1005{
1006        struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK };
1007        struct iovec riov;
1008        struct msghdr msg = {
1009                .msg_name = &nladdr,
1010                .msg_namelen = sizeof(nladdr),
1011                .msg_iov = iov,
1012                .msg_iovlen = iovlen,
1013        };
1014        unsigned int seq = 0;
1015        struct nlmsghdr *h;
1016        int i, status;
1017        char *buf;
1018
1019        for (i = 0; i < iovlen; i++) {
1020                h = iov[i].iov_base;
1021                h->nlmsg_seq = seq = ++rtnl->seq;
1022                if (answer == NULL)
1023                        h->nlmsg_flags |= NLM_F_ACK;
1024        }
1025
1026        status = sendmsg(rtnl->fd, &msg, 0);
1027        if (status < 0) {
1028                perror("Cannot talk to rtnetlink");
1029                return -1;
1030        }
1031
1032        /* change msg to use the response iov */
1033        msg.msg_iov = &riov;
1034        msg.msg_iovlen = 1;
1035        i = 0;
1036        while (1) {
1037next:
1038                status = rtnl_recvmsg(rtnl->fd, &msg, &buf);
1039                ++i;
1040
1041                if (status < 0)
1042                        return status;
1043
1044                if (msg.msg_namelen != sizeof(nladdr)) {
1045                        fprintf(stderr,
1046                                "sender address length == %d\n",
1047                                msg.msg_namelen);
1048                        exit(1);
1049                }
1050                for (h = (struct nlmsghdr *)buf; status >= sizeof(*h); ) {
1051                        int len = h->nlmsg_len;
1052                        int l = len - sizeof(*h);
1053
1054                        if (l < 0 || len > status) {
1055                                if (msg.msg_flags & MSG_TRUNC) {
1056                                        fprintf(stderr, "Truncated message\n");
1057                                        free(buf);
1058                                        return -1;
1059                                }
1060                                fprintf(stderr,
1061                                        "!!!malformed message: len=%d\n",
1062                                        len);
1063                                exit(1);
1064                        }
1065
1066                        if (nladdr.nl_pid != 0 ||
1067                            h->nlmsg_pid != rtnl->local.nl_pid ||
1068                            h->nlmsg_seq > seq || h->nlmsg_seq < seq - iovlen) {
1069                                /* Don't forget to skip that message. */
1070                                status -= NLMSG_ALIGN(len);
1071                                h = (struct nlmsghdr *)((char *)h + NLMSG_ALIGN(len));
1072                                continue;
1073                        }
1074
1075                        if (h->nlmsg_type == NLMSG_ERROR) {
1076                                struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(h);
1077                                int error = err->error;
1078
1079                                if (l < sizeof(struct nlmsgerr)) {
1080                                        fprintf(stderr, "ERROR truncated\n");
1081                                        free(buf);
1082                                        return -1;
1083                                }
1084
1085                                if (!error) {
1086                                        /* check messages from kernel */
1087                                        nl_dump_ext_ack(h, errfn);
1088                                } else {
1089                                        errno = -error;
1090
1091                                        if (rtnl->proto != NETLINK_SOCK_DIAG &&
1092                                            show_rtnl_err)
1093                                                rtnl_talk_error(h, err, errfn);
1094                                }
1095
1096                                if (i < iovlen) {
1097                                        free(buf);
1098                                        goto next;
1099                                }
1100
1101                                if (error) {
1102                                        free(buf);
1103                                        return -i;
1104                                }
1105
1106                                if (answer)
1107                                        *answer = (struct nlmsghdr *)buf;
1108                                else
1109                                        free(buf);
1110                                return 0;
1111                        }
1112
1113                        if (answer) {
1114                                *answer = (struct nlmsghdr *)buf;
1115                                return 0;
1116                        }
1117
1118                        fprintf(stderr, "Unexpected reply!!!\n");
1119
1120                        status -= NLMSG_ALIGN(len);
1121                        h = (struct nlmsghdr *)((char *)h + NLMSG_ALIGN(len));
1122                }
1123                free(buf);
1124
1125                if (msg.msg_flags & MSG_TRUNC) {
1126                        fprintf(stderr, "Message truncated\n");
1127                        continue;
1128                }
1129
1130                if (status) {
1131                        fprintf(stderr, "!!!Remnant of size %d\n", status);
1132                        exit(1);
1133                }
1134        }
1135}
1136
1137static int __rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n,
1138                       struct nlmsghdr **answer,
1139                       bool show_rtnl_err, nl_ext_ack_fn_t errfn)
1140{
1141        struct iovec iov = {
1142                .iov_base = n,
1143                .iov_len = n->nlmsg_len
1144        };
1145
1146        return __rtnl_talk_iov(rtnl, &iov, 1, answer, show_rtnl_err, errfn);
1147}
1148
1149int rtnl_echo_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, int json,
1150                   int (*print_info)(struct nlmsghdr *n, void *arg))
1151{
1152        struct nlmsghdr *answer;
1153        int ret;
1154
1155        n->nlmsg_flags |= NLM_F_ECHO | NLM_F_ACK;
1156
1157        ret = rtnl_talk(rtnl, n, &answer);
1158        if (ret)
1159                return ret;
1160
1161        new_json_obj(json);
1162        open_json_object(NULL);
1163        print_info(answer, stdout);
1164        close_json_object();
1165        delete_json_obj();
1166        free(answer);
1167
1168        return 0;
1169}
1170
1171int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n,
1172              struct nlmsghdr **answer)
1173{
1174        return __rtnl_talk(rtnl, n, answer, true, NULL);
1175}
1176
1177int rtnl_talk_suppress_rtnl_errmsg(struct rtnl_handle *rtnl, struct nlmsghdr *n,
1178                                   struct nlmsghdr **answer)
1179{
1180        return __rtnl_talk(rtnl, n, answer, false, NULL);
1181}
1182
1183int rtnl_listen_all_nsid(struct rtnl_handle *rth)
1184{
1185        unsigned int on = 1;
1186
1187        if (setsockopt(rth->fd, SOL_NETLINK, NETLINK_LISTEN_ALL_NSID, &on,
1188                       sizeof(on)) < 0) {
1189                perror("NETLINK_LISTEN_ALL_NSID");
1190                return -1;
1191        }
1192        rth->flags |= RTNL_HANDLE_F_LISTEN_ALL_NSID;
1193        return 0;
1194}
1195
1196int rtnl_listen(struct rtnl_handle *rtnl,
1197                rtnl_listen_filter_t handler,
1198                void *jarg)
1199{
1200        int status;
1201        struct nlmsghdr *h;
1202        struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK };
1203        struct iovec iov;
1204        struct msghdr msg = {
1205                .msg_name = &nladdr,
1206                .msg_namelen = sizeof(nladdr),
1207                .msg_iov = &iov,
1208                .msg_iovlen = 1,
1209        };
1210        char   buf[16384];
1211        char   cmsgbuf[BUFSIZ];
1212
1213        iov.iov_base = buf;
1214        while (1) {
1215                struct rtnl_ctrl_data ctrl;
1216                struct cmsghdr *cmsg;
1217
1218                if (rtnl->flags & RTNL_HANDLE_F_LISTEN_ALL_NSID) {
1219                        msg.msg_control = &cmsgbuf;
1220                        msg.msg_controllen = sizeof(cmsgbuf);
1221                }
1222
1223                iov.iov_len = sizeof(buf);
1224                status = recvmsg(rtnl->fd, &msg, 0);
1225
1226                if (status < 0) {
1227                        if (errno == EINTR || errno == EAGAIN)
1228                                continue;
1229                        fprintf(stderr, "netlink receive error %s (%d)\n",
1230                                strerror(errno), errno);
1231                        if (errno == ENOBUFS)
1232                                continue;
1233                        return -1;
1234                }
1235                if (status == 0) {
1236                        fprintf(stderr, "EOF on netlink\n");
1237                        return -1;
1238                }
1239                if (msg.msg_namelen != sizeof(nladdr)) {
1240                        fprintf(stderr,
1241                                "Sender address length == %d\n",
1242                                msg.msg_namelen);
1243                        exit(1);
1244                }
1245
1246                if (rtnl->flags & RTNL_HANDLE_F_LISTEN_ALL_NSID) {
1247                        memset(&ctrl, 0, sizeof(ctrl));
1248                        ctrl.nsid = -1;
1249                        for (cmsg = CMSG_FIRSTHDR(&msg); cmsg;
1250                             cmsg = CMSG_NXTHDR(&msg, cmsg))
1251                                if (cmsg->cmsg_level == SOL_NETLINK &&
1252                                    cmsg->cmsg_type == NETLINK_LISTEN_ALL_NSID &&
1253                                    cmsg->cmsg_len == CMSG_LEN(sizeof(int))) {
1254                                        int *data = (int *)CMSG_DATA(cmsg);
1255
1256                                        ctrl.nsid = *data;
1257                                }
1258                }
1259
1260                for (h = (struct nlmsghdr *)buf; status >= sizeof(*h); ) {
1261                        int err;
1262                        int len = h->nlmsg_len;
1263                        int l = len - sizeof(*h);
1264
1265                        if (l < 0 || len > status) {
1266                                if (msg.msg_flags & MSG_TRUNC) {
1267                                        fprintf(stderr, "Truncated message\n");
1268                                        return -1;
1269                                }
1270                                fprintf(stderr,
1271                                        "!!!malformed message: len=%d\n",
1272                                        len);
1273                                exit(1);
1274                        }
1275
1276                        err = handler(&ctrl, h, jarg);
1277                        if (err < 0)
1278                                return err;
1279
1280                        status -= NLMSG_ALIGN(len);
1281                        h = (struct nlmsghdr *)((char *)h + NLMSG_ALIGN(len));
1282                }
1283                if (msg.msg_flags & MSG_TRUNC) {
1284                        fprintf(stderr, "Message truncated\n");
1285                        continue;
1286                }
1287                if (status) {
1288                        fprintf(stderr, "!!!Remnant of size %d\n", status);
1289                        exit(1);
1290                }
1291        }
1292}
1293
1294int rtnl_from_file(FILE *rtnl, rtnl_listen_filter_t handler,
1295                   void *jarg)
1296{
1297        size_t status;
1298        char buf[16384];
1299        struct nlmsghdr *h = (struct nlmsghdr *)buf;
1300
1301        while (1) {
1302                int err, len;
1303                int l;
1304
1305                status = fread(&buf, 1, sizeof(*h), rtnl);
1306
1307                if (status == 0 && feof(rtnl))
1308                        return 0;
1309                if (status != sizeof(*h)) {
1310                        if (ferror(rtnl))
1311                                perror("rtnl_from_file: fread");
1312                        if (feof(rtnl))
1313                                fprintf(stderr, "rtnl-from_file: truncated message\n");
1314                        return -1;
1315                }
1316
1317                len = h->nlmsg_len;
1318                l = len - sizeof(*h);
1319
1320                if (l < 0 || len > sizeof(buf)) {
1321                        fprintf(stderr, "!!!malformed message: len=%d @%lu\n",
1322                                len, ftell(rtnl));
1323                        return -1;
1324                }
1325
1326                status = fread(NLMSG_DATA(h), 1, NLMSG_ALIGN(l), rtnl);
1327
1328                if (status != NLMSG_ALIGN(l)) {
1329                        if (ferror(rtnl))
1330                                perror("rtnl_from_file: fread");
1331                        if (feof(rtnl))
1332                                fprintf(stderr, "rtnl-from_file: truncated message\n");
1333                        return -1;
1334                }
1335
1336                err = handler(NULL, h, jarg);
1337                if (err < 0)
1338                        return err;
1339        }
1340}
1341
1342int addattr(struct nlmsghdr *n, int maxlen, int type)
1343{
1344        return addattr_l(n, maxlen, type, NULL, 0);
1345}
1346
1347int addattr8(struct nlmsghdr *n, int maxlen, int type, __u8 data)
1348{
1349        return addattr_l(n, maxlen, type, &data, sizeof(__u8));
1350}
1351
1352int addattr16(struct nlmsghdr *n, int maxlen, int type, __u16 data)
1353{
1354        return addattr_l(n, maxlen, type, &data, sizeof(__u16));
1355}
1356
1357int addattr32(struct nlmsghdr *n, int maxlen, int type, __u32 data)
1358{
1359        return addattr_l(n, maxlen, type, &data, sizeof(__u32));
1360}
1361
1362int addattr64(struct nlmsghdr *n, int maxlen, int type, __u64 data)
1363{
1364        return addattr_l(n, maxlen, type, &data, sizeof(__u64));
1365}
1366
1367int addattrstrz(struct nlmsghdr *n, int maxlen, int type, const char *str)
1368{
1369        return addattr_l(n, maxlen, type, str, strlen(str)+1);
1370}
1371
1372int addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data,
1373              int alen)
1374{
1375        int len = RTA_LENGTH(alen);
1376        struct rtattr *rta;
1377
1378        if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen) {
1379                fprintf(stderr,
1380                        "addattr_l ERROR: message exceeded bound of %d\n",
1381                        maxlen);
1382                return -1;
1383        }
1384        rta = NLMSG_TAIL(n);
1385        rta->rta_type = type;
1386        rta->rta_len = len;
1387        if (alen)
1388                memcpy(RTA_DATA(rta), data, alen);
1389        n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len);
1390        return 0;
1391}
1392
1393int addraw_l(struct nlmsghdr *n, int maxlen, const void *data, int len)
1394{
1395        if (NLMSG_ALIGN(n->nlmsg_len) + NLMSG_ALIGN(len) > maxlen) {
1396                fprintf(stderr,
1397                        "addraw_l ERROR: message exceeded bound of %d\n",
1398                        maxlen);
1399                return -1;
1400        }
1401
1402        memcpy(NLMSG_TAIL(n), data, len);
1403        memset((void *) NLMSG_TAIL(n) + len, 0, NLMSG_ALIGN(len) - len);
1404        n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + NLMSG_ALIGN(len);
1405        return 0;
1406}
1407
1408struct rtattr *addattr_nest(struct nlmsghdr *n, int maxlen, int type)
1409{
1410        struct rtattr *nest = NLMSG_TAIL(n);
1411
1412        addattr_l(n, maxlen, type, NULL, 0);
1413        return nest;
1414}
1415
1416int addattr_nest_end(struct nlmsghdr *n, struct rtattr *nest)
1417{
1418        nest->rta_len = (void *)NLMSG_TAIL(n) - (void *)nest;
1419        return n->nlmsg_len;
1420}
1421
1422struct rtattr *addattr_nest_compat(struct nlmsghdr *n, int maxlen, int type,
1423                                   const void *data, int len)
1424{
1425        struct rtattr *start = NLMSG_TAIL(n);
1426
1427        addattr_l(n, maxlen, type, data, len);
1428        addattr_nest(n, maxlen, type);
1429        return start;
1430}
1431
1432int addattr_nest_compat_end(struct nlmsghdr *n, struct rtattr *start)
1433{
1434        struct rtattr *nest = (void *)start + NLMSG_ALIGN(start->rta_len);
1435
1436        start->rta_len = (void *)NLMSG_TAIL(n) - (void *)start;
1437        addattr_nest_end(n, nest);
1438        return n->nlmsg_len;
1439}
1440
1441int rta_addattr32(struct rtattr *rta, int maxlen, int type, __u32 data)
1442{
1443        int len = RTA_LENGTH(4);
1444        struct rtattr *subrta;
1445
1446        if (RTA_ALIGN(rta->rta_len) + len > maxlen) {
1447                fprintf(stderr,
1448                        "rta_addattr32: Error! max allowed bound %d exceeded\n",
1449                        maxlen);
1450                return -1;
1451        }
1452        subrta = (struct rtattr *)(((char *)rta) + RTA_ALIGN(rta->rta_len));
1453        subrta->rta_type = type;
1454        subrta->rta_len = len;
1455        memcpy(RTA_DATA(subrta), &data, 4);
1456        rta->rta_len = NLMSG_ALIGN(rta->rta_len) + len;
1457        return 0;
1458}
1459
1460int rta_addattr_l(struct rtattr *rta, int maxlen, int type,
1461                  const void *data, int alen)
1462{
1463        struct rtattr *subrta;
1464        int len = RTA_LENGTH(alen);
1465
1466        if (RTA_ALIGN(rta->rta_len) + RTA_ALIGN(len) > maxlen) {
1467                fprintf(stderr,
1468                        "rta_addattr_l: Error! max allowed bound %d exceeded\n",
1469                        maxlen);
1470                return -1;
1471        }
1472        subrta = (struct rtattr *)(((char *)rta) + RTA_ALIGN(rta->rta_len));
1473        subrta->rta_type = type;
1474        subrta->rta_len = len;
1475        if (alen)
1476                memcpy(RTA_DATA(subrta), data, alen);
1477        rta->rta_len = NLMSG_ALIGN(rta->rta_len) + RTA_ALIGN(len);
1478        return 0;
1479}
1480
1481int rta_addattr8(struct rtattr *rta, int maxlen, int type, __u8 data)
1482{
1483        return rta_addattr_l(rta, maxlen, type, &data, sizeof(__u8));
1484}
1485
1486int rta_addattr16(struct rtattr *rta, int maxlen, int type, __u16 data)
1487{
1488        return rta_addattr_l(rta, maxlen, type, &data, sizeof(__u16));
1489}
1490
1491int rta_addattr64(struct rtattr *rta, int maxlen, int type, __u64 data)
1492{
1493        return rta_addattr_l(rta, maxlen, type, &data, sizeof(__u64));
1494}
1495
1496struct rtattr *rta_nest(struct rtattr *rta, int maxlen, int type)
1497{
1498        struct rtattr *nest = RTA_TAIL(rta);
1499
1500        rta_addattr_l(rta, maxlen, type, NULL, 0);
1501        nest->rta_type |= NLA_F_NESTED;
1502
1503        return nest;
1504}
1505
1506int rta_nest_end(struct rtattr *rta, struct rtattr *nest)
1507{
1508        nest->rta_len = (void *)RTA_TAIL(rta) - (void *)nest;
1509
1510        return rta->rta_len;
1511}
1512
1513int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)
1514{
1515        return parse_rtattr_flags(tb, max, rta, len, 0);
1516}
1517
1518int parse_rtattr_flags(struct rtattr *tb[], int max, struct rtattr *rta,
1519                       int len, unsigned short flags)
1520{
1521        unsigned short type;
1522
1523        memset(tb, 0, sizeof(struct rtattr *) * (max + 1));
1524        while (RTA_OK(rta, len)) {
1525                type = rta->rta_type & ~flags;
1526                if ((type <= max) && (!tb[type]))
1527                        tb[type] = rta;
1528                rta = RTA_NEXT(rta, len);
1529        }
1530        if (len)
1531                fprintf(stderr, "!!!Deficit %d, rta_len=%d\n",
1532                        len, rta->rta_len);
1533        return 0;
1534}
1535
1536struct rtattr *parse_rtattr_one(int type, struct rtattr *rta, int len)
1537{
1538        while (RTA_OK(rta, len)) {
1539                if (rta->rta_type == type)
1540                        return rta;
1541                rta = RTA_NEXT(rta, len);
1542        }
1543
1544        if (len)
1545                fprintf(stderr, "!!!Deficit %d, rta_len=%d\n",
1546                        len, rta->rta_len);
1547        return NULL;
1548}
1549
1550int __parse_rtattr_nested_compat(struct rtattr *tb[], int max,
1551                                 struct rtattr *rta,
1552                                 int len)
1553{
1554        if (RTA_PAYLOAD(rta) < len)
1555                return -1;
1556        if (RTA_PAYLOAD(rta) >= RTA_ALIGN(len) + sizeof(struct rtattr)) {
1557                rta = RTA_DATA(rta) + RTA_ALIGN(len);
1558                return parse_rtattr_nested(tb, max, rta);
1559        }
1560        memset(tb, 0, sizeof(struct rtattr *) * (max + 1));
1561        return 0;
1562}
1563
1564static const char *get_nla_type_str(unsigned int attr)
1565{
1566        switch (attr) {
1567#define C(x) case NL_ATTR_TYPE_ ## x: return #x
1568        C(U8);
1569        C(U16);
1570        C(U32);
1571        C(U64);
1572        C(STRING);
1573        C(FLAG);
1574        C(NESTED);
1575        C(NESTED_ARRAY);
1576        C(NUL_STRING);
1577        C(BINARY);
1578        C(S8);
1579        C(S16);
1580        C(S32);
1581        C(S64);
1582        C(BITFIELD32);
1583        default:
1584                return "unknown";
1585        }
1586}
1587
1588void nl_print_policy(const struct rtattr *attr, FILE *fp)
1589{
1590        const struct rtattr *pos;
1591
1592        rtattr_for_each_nested(pos, attr) {
1593                const struct rtattr *attr;
1594
1595                fprintf(fp, " policy[%u]:", pos->rta_type & ~NLA_F_NESTED);
1596
1597                rtattr_for_each_nested(attr, pos) {
1598                        struct rtattr *tp[NL_POLICY_TYPE_ATTR_MAX + 1];
1599
1600                        parse_rtattr_nested(tp, ARRAY_SIZE(tp) - 1, attr);
1601
1602                        if (tp[NL_POLICY_TYPE_ATTR_TYPE])
1603                                fprintf(fp, "attr[%u]: type=%s",
1604                                        attr->rta_type & ~NLA_F_NESTED,
1605                                        get_nla_type_str(rta_getattr_u32(tp[NL_POLICY_TYPE_ATTR_TYPE])));
1606
1607                        if (tp[NL_POLICY_TYPE_ATTR_POLICY_IDX])
1608                                fprintf(fp, " policy:%u",
1609                                        rta_getattr_u32(tp[NL_POLICY_TYPE_ATTR_POLICY_IDX]));
1610
1611                        if (tp[NL_POLICY_TYPE_ATTR_POLICY_MAXTYPE])
1612                                fprintf(fp, " maxattr:%u",
1613                                        rta_getattr_u32(tp[NL_POLICY_TYPE_ATTR_POLICY_MAXTYPE]));
1614
1615                        if (tp[NL_POLICY_TYPE_ATTR_MIN_VALUE_S] && tp[NL_POLICY_TYPE_ATTR_MAX_VALUE_S])
1616                                fprintf(fp, " range:[%lld,%lld]",
1617                                        (signed long long)rta_getattr_u64(tp[NL_POLICY_TYPE_ATTR_MIN_VALUE_S]),
1618                                        (signed long long)rta_getattr_u64(tp[NL_POLICY_TYPE_ATTR_MAX_VALUE_S]));
1619
1620                        if (tp[NL_POLICY_TYPE_ATTR_MIN_VALUE_U] && tp[NL_POLICY_TYPE_ATTR_MAX_VALUE_U])
1621                                fprintf(fp, " range:[%llu,%llu]",
1622                                        (unsigned long long)rta_getattr_u64(tp[NL_POLICY_TYPE_ATTR_MIN_VALUE_U]),
1623                                        (unsigned long long)rta_getattr_u64(tp[NL_POLICY_TYPE_ATTR_MAX_VALUE_U]));
1624
1625                        if (tp[NL_POLICY_TYPE_ATTR_MIN_LENGTH])
1626                                fprintf(fp, " min len:%u",
1627                                        rta_getattr_u32(tp[NL_POLICY_TYPE_ATTR_MIN_LENGTH]));
1628
1629                        if (tp[NL_POLICY_TYPE_ATTR_MAX_LENGTH])
1630                                fprintf(fp, " max len:%u",
1631                                        rta_getattr_u32(tp[NL_POLICY_TYPE_ATTR_MAX_LENGTH]));
1632                }
1633        }
1634}
1635
1636int rtnl_tunneldump_req(struct rtnl_handle *rth, int family, int ifindex,
1637                        __u8 flags)
1638{
1639        struct {
1640                struct nlmsghdr nlh;
1641                struct tunnel_msg tmsg;
1642                char buf[256];
1643        } req = {
1644                .nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct tunnel_msg)),
1645                .nlh.nlmsg_type = RTM_GETTUNNEL,
1646                .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
1647                .nlh.nlmsg_seq = rth->dump = ++rth->seq,
1648                .tmsg.family = family,
1649                .tmsg.flags = flags,
1650                .tmsg.ifindex = ifindex,
1651        };
1652
1653        return send(rth->fd, &req, sizeof(req), 0);
1654}
1655