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