linux/tools/testing/selftests/net/mptcp/pm_nl_ctl.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2
   3#include <errno.h>
   4#include <error.h>
   5#include <stdio.h>
   6#include <stdlib.h>
   7#include <string.h>
   8#include <unistd.h>
   9
  10#include <sys/socket.h>
  11#include <sys/types.h>
  12
  13#include <arpa/inet.h>
  14#include <net/if.h>
  15
  16#include <linux/rtnetlink.h>
  17#include <linux/genetlink.h>
  18
  19#include "linux/mptcp.h"
  20
  21#ifndef MPTCP_PM_NAME
  22#define MPTCP_PM_NAME           "mptcp_pm"
  23#endif
  24
  25static void syntax(char *argv[])
  26{
  27        fprintf(stderr, "%s add|get|set|del|flush|dump|accept [<args>]\n", argv[0]);
  28        fprintf(stderr, "\tadd [flags signal|subflow|backup|fullmesh] [id <nr>] [dev <name>] <ip>\n");
  29        fprintf(stderr, "\tdel <id> [<ip>]\n");
  30        fprintf(stderr, "\tget <id>\n");
  31        fprintf(stderr, "\tset <ip> [flags backup|nobackup]\n");
  32        fprintf(stderr, "\tflush\n");
  33        fprintf(stderr, "\tdump\n");
  34        fprintf(stderr, "\tlimits [<rcv addr max> <subflow max>]\n");
  35        exit(0);
  36}
  37
  38static int init_genl_req(char *data, int family, int cmd, int version)
  39{
  40        struct nlmsghdr *nh = (void *)data;
  41        struct genlmsghdr *gh;
  42        int off = 0;
  43
  44        nh->nlmsg_type = family;
  45        nh->nlmsg_flags = NLM_F_REQUEST;
  46        nh->nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
  47        off += NLMSG_ALIGN(sizeof(*nh));
  48
  49        gh = (void *)(data + off);
  50        gh->cmd = cmd;
  51        gh->version = version;
  52        off += NLMSG_ALIGN(sizeof(*gh));
  53        return off;
  54}
  55
  56static void nl_error(struct nlmsghdr *nh)
  57{
  58        struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(nh);
  59        int len = nh->nlmsg_len - sizeof(*nh);
  60        uint32_t off;
  61
  62        if (len < sizeof(struct nlmsgerr))
  63                error(1, 0, "netlink error message truncated %d min %ld", len,
  64                      sizeof(struct nlmsgerr));
  65
  66        if (!err->error) {
  67                /* check messages from kernel */
  68                struct rtattr *attrs = (struct rtattr *)NLMSG_DATA(nh);
  69
  70                while (RTA_OK(attrs, len)) {
  71                        if (attrs->rta_type == NLMSGERR_ATTR_MSG)
  72                                fprintf(stderr, "netlink ext ack msg: %s\n",
  73                                        (char *)RTA_DATA(attrs));
  74                        if (attrs->rta_type == NLMSGERR_ATTR_OFFS) {
  75                                memcpy(&off, RTA_DATA(attrs), 4);
  76                                fprintf(stderr, "netlink err off %d\n",
  77                                        (int)off);
  78                        }
  79                        attrs = RTA_NEXT(attrs, len);
  80                }
  81        } else {
  82                fprintf(stderr, "netlink error %d", err->error);
  83        }
  84}
  85
  86/* do a netlink command and, if max > 0, fetch the reply  */
  87static int do_nl_req(int fd, struct nlmsghdr *nh, int len, int max)
  88{
  89        struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK };
  90        socklen_t addr_len;
  91        void *data = nh;
  92        int rem, ret;
  93        int err = 0;
  94
  95        nh->nlmsg_len = len;
  96        ret = sendto(fd, data, len, 0, (void *)&nladdr, sizeof(nladdr));
  97        if (ret != len)
  98                error(1, errno, "send netlink: %uB != %uB\n", ret, len);
  99        if (max == 0)
 100                return 0;
 101
 102        addr_len = sizeof(nladdr);
 103        rem = ret = recvfrom(fd, data, max, 0, (void *)&nladdr, &addr_len);
 104        if (ret < 0)
 105                error(1, errno, "recv netlink: %uB\n", ret);
 106
 107        /* Beware: the NLMSG_NEXT macro updates the 'rem' argument */
 108        for (; NLMSG_OK(nh, rem); nh = NLMSG_NEXT(nh, rem)) {
 109                if (nh->nlmsg_type == NLMSG_ERROR) {
 110                        nl_error(nh);
 111                        err = 1;
 112                }
 113        }
 114        if (err)
 115                error(1, 0, "bailing out due to netlink error[s]");
 116        return ret;
 117}
 118
 119static int genl_parse_getfamily(struct nlmsghdr *nlh)
 120{
 121        struct genlmsghdr *ghdr = NLMSG_DATA(nlh);
 122        int len = nlh->nlmsg_len;
 123        struct rtattr *attrs;
 124
 125        if (nlh->nlmsg_type != GENL_ID_CTRL)
 126                error(1, errno, "Not a controller message, len=%d type=0x%x\n",
 127                      nlh->nlmsg_len, nlh->nlmsg_type);
 128
 129        len -= NLMSG_LENGTH(GENL_HDRLEN);
 130
 131        if (len < 0)
 132                error(1, errno, "wrong controller message len %d\n", len);
 133
 134        if (ghdr->cmd != CTRL_CMD_NEWFAMILY)
 135                error(1, errno, "Unknown controller command %d\n", ghdr->cmd);
 136
 137        attrs = (struct rtattr *) ((char *) ghdr + GENL_HDRLEN);
 138        while (RTA_OK(attrs, len)) {
 139                if (attrs->rta_type == CTRL_ATTR_FAMILY_ID)
 140                        return *(__u16 *)RTA_DATA(attrs);
 141                attrs = RTA_NEXT(attrs, len);
 142        }
 143
 144        error(1, errno, "can't find CTRL_ATTR_FAMILY_ID attr");
 145        return -1;
 146}
 147
 148static int resolve_mptcp_pm_netlink(int fd)
 149{
 150        char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
 151                  NLMSG_ALIGN(sizeof(struct genlmsghdr)) +
 152                  1024];
 153        struct nlmsghdr *nh;
 154        struct rtattr *rta;
 155        int namelen;
 156        int off = 0;
 157
 158        memset(data, 0, sizeof(data));
 159        nh = (void *)data;
 160        off = init_genl_req(data, GENL_ID_CTRL, CTRL_CMD_GETFAMILY, 0);
 161
 162        rta = (void *)(data + off);
 163        namelen = strlen(MPTCP_PM_NAME) + 1;
 164        rta->rta_type = CTRL_ATTR_FAMILY_NAME;
 165        rta->rta_len = RTA_LENGTH(namelen);
 166        memcpy(RTA_DATA(rta), MPTCP_PM_NAME, namelen);
 167        off += NLMSG_ALIGN(rta->rta_len);
 168
 169        do_nl_req(fd, nh, off, sizeof(data));
 170        return genl_parse_getfamily((void *)data);
 171}
 172
 173int add_addr(int fd, int pm_family, int argc, char *argv[])
 174{
 175        char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
 176                  NLMSG_ALIGN(sizeof(struct genlmsghdr)) +
 177                  1024];
 178        struct rtattr *rta, *nest;
 179        struct nlmsghdr *nh;
 180        u_int32_t flags = 0;
 181        u_int16_t family;
 182        int nest_start;
 183        u_int8_t id;
 184        int off = 0;
 185        int arg;
 186
 187        memset(data, 0, sizeof(data));
 188        nh = (void *)data;
 189        off = init_genl_req(data, pm_family, MPTCP_PM_CMD_ADD_ADDR,
 190                            MPTCP_PM_VER);
 191
 192        if (argc < 3)
 193                syntax(argv);
 194
 195        nest_start = off;
 196        nest = (void *)(data + off);
 197        nest->rta_type = NLA_F_NESTED | MPTCP_PM_ATTR_ADDR;
 198        nest->rta_len = RTA_LENGTH(0);
 199        off += NLMSG_ALIGN(nest->rta_len);
 200
 201        /* addr data */
 202        rta = (void *)(data + off);
 203        if (inet_pton(AF_INET, argv[2], RTA_DATA(rta))) {
 204                family = AF_INET;
 205                rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR4;
 206                rta->rta_len = RTA_LENGTH(4);
 207        } else if (inet_pton(AF_INET6, argv[2], RTA_DATA(rta))) {
 208                family = AF_INET6;
 209                rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR6;
 210                rta->rta_len = RTA_LENGTH(16);
 211        } else
 212                error(1, errno, "can't parse ip %s", argv[2]);
 213        off += NLMSG_ALIGN(rta->rta_len);
 214
 215        /* family */
 216        rta = (void *)(data + off);
 217        rta->rta_type = MPTCP_PM_ADDR_ATTR_FAMILY;
 218        rta->rta_len = RTA_LENGTH(2);
 219        memcpy(RTA_DATA(rta), &family, 2);
 220        off += NLMSG_ALIGN(rta->rta_len);
 221
 222        for (arg = 3; arg < argc; arg++) {
 223                if (!strcmp(argv[arg], "flags")) {
 224                        char *tok, *str;
 225
 226                        /* flags */
 227                        if (++arg >= argc)
 228                                error(1, 0, " missing flags value");
 229
 230                        /* do not support flag list yet */
 231                        for (str = argv[arg]; (tok = strtok(str, ","));
 232                             str = NULL) {
 233                                if (!strcmp(tok, "subflow"))
 234                                        flags |= MPTCP_PM_ADDR_FLAG_SUBFLOW;
 235                                else if (!strcmp(tok, "signal"))
 236                                        flags |= MPTCP_PM_ADDR_FLAG_SIGNAL;
 237                                else if (!strcmp(tok, "backup"))
 238                                        flags |= MPTCP_PM_ADDR_FLAG_BACKUP;
 239                                else if (!strcmp(tok, "fullmesh"))
 240                                        flags |= MPTCP_PM_ADDR_FLAG_FULLMESH;
 241                                else
 242                                        error(1, errno,
 243                                              "unknown flag %s", argv[arg]);
 244                        }
 245
 246                        if (flags & MPTCP_PM_ADDR_FLAG_SIGNAL &&
 247                            flags & MPTCP_PM_ADDR_FLAG_FULLMESH) {
 248                                error(1, errno, "error flag fullmesh");
 249                        }
 250
 251                        rta = (void *)(data + off);
 252                        rta->rta_type = MPTCP_PM_ADDR_ATTR_FLAGS;
 253                        rta->rta_len = RTA_LENGTH(4);
 254                        memcpy(RTA_DATA(rta), &flags, 4);
 255                        off += NLMSG_ALIGN(rta->rta_len);
 256                } else if (!strcmp(argv[arg], "id")) {
 257                        if (++arg >= argc)
 258                                error(1, 0, " missing id value");
 259
 260                        id = atoi(argv[arg]);
 261                        rta = (void *)(data + off);
 262                        rta->rta_type = MPTCP_PM_ADDR_ATTR_ID;
 263                        rta->rta_len = RTA_LENGTH(1);
 264                        memcpy(RTA_DATA(rta), &id, 1);
 265                        off += NLMSG_ALIGN(rta->rta_len);
 266                } else if (!strcmp(argv[arg], "dev")) {
 267                        int32_t ifindex;
 268
 269                        if (++arg >= argc)
 270                                error(1, 0, " missing dev name");
 271
 272                        ifindex = if_nametoindex(argv[arg]);
 273                        if (!ifindex)
 274                                error(1, errno, "unknown device %s", argv[arg]);
 275
 276                        rta = (void *)(data + off);
 277                        rta->rta_type = MPTCP_PM_ADDR_ATTR_IF_IDX;
 278                        rta->rta_len = RTA_LENGTH(4);
 279                        memcpy(RTA_DATA(rta), &ifindex, 4);
 280                        off += NLMSG_ALIGN(rta->rta_len);
 281                } else if (!strcmp(argv[arg], "port")) {
 282                        u_int16_t port;
 283
 284                        if (++arg >= argc)
 285                                error(1, 0, " missing port value");
 286                        if (!(flags & MPTCP_PM_ADDR_FLAG_SIGNAL))
 287                                error(1, 0, " flags must be signal when using port");
 288
 289                        port = atoi(argv[arg]);
 290                        rta = (void *)(data + off);
 291                        rta->rta_type = MPTCP_PM_ADDR_ATTR_PORT;
 292                        rta->rta_len = RTA_LENGTH(2);
 293                        memcpy(RTA_DATA(rta), &port, 2);
 294                        off += NLMSG_ALIGN(rta->rta_len);
 295                } else
 296                        error(1, 0, "unknown keyword %s", argv[arg]);
 297        }
 298        nest->rta_len = off - nest_start;
 299
 300        do_nl_req(fd, nh, off, 0);
 301        return 0;
 302}
 303
 304int del_addr(int fd, int pm_family, int argc, char *argv[])
 305{
 306        char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
 307                  NLMSG_ALIGN(sizeof(struct genlmsghdr)) +
 308                  1024];
 309        struct rtattr *rta, *nest;
 310        struct nlmsghdr *nh;
 311        u_int16_t family;
 312        int nest_start;
 313        u_int8_t id;
 314        int off = 0;
 315
 316        memset(data, 0, sizeof(data));
 317        nh = (void *)data;
 318        off = init_genl_req(data, pm_family, MPTCP_PM_CMD_DEL_ADDR,
 319                            MPTCP_PM_VER);
 320
 321        /* the only argument is the address id (nonzero) */
 322        if (argc != 3 && argc != 4)
 323                syntax(argv);
 324
 325        id = atoi(argv[2]);
 326        /* zero id with the IP address */
 327        if (!id && argc != 4)
 328                syntax(argv);
 329
 330        nest_start = off;
 331        nest = (void *)(data + off);
 332        nest->rta_type = NLA_F_NESTED | MPTCP_PM_ATTR_ADDR;
 333        nest->rta_len =  RTA_LENGTH(0);
 334        off += NLMSG_ALIGN(nest->rta_len);
 335
 336        /* build a dummy addr with only the ID set */
 337        rta = (void *)(data + off);
 338        rta->rta_type = MPTCP_PM_ADDR_ATTR_ID;
 339        rta->rta_len = RTA_LENGTH(1);
 340        memcpy(RTA_DATA(rta), &id, 1);
 341        off += NLMSG_ALIGN(rta->rta_len);
 342
 343        if (!id) {
 344                /* addr data */
 345                rta = (void *)(data + off);
 346                if (inet_pton(AF_INET, argv[3], RTA_DATA(rta))) {
 347                        family = AF_INET;
 348                        rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR4;
 349                        rta->rta_len = RTA_LENGTH(4);
 350                } else if (inet_pton(AF_INET6, argv[3], RTA_DATA(rta))) {
 351                        family = AF_INET6;
 352                        rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR6;
 353                        rta->rta_len = RTA_LENGTH(16);
 354                } else {
 355                        error(1, errno, "can't parse ip %s", argv[3]);
 356                }
 357                off += NLMSG_ALIGN(rta->rta_len);
 358
 359                /* family */
 360                rta = (void *)(data + off);
 361                rta->rta_type = MPTCP_PM_ADDR_ATTR_FAMILY;
 362                rta->rta_len = RTA_LENGTH(2);
 363                memcpy(RTA_DATA(rta), &family, 2);
 364                off += NLMSG_ALIGN(rta->rta_len);
 365        }
 366        nest->rta_len = off - nest_start;
 367
 368        do_nl_req(fd, nh, off, 0);
 369        return 0;
 370}
 371
 372static void print_addr(struct rtattr *attrs, int len)
 373{
 374        uint16_t family = 0;
 375        uint16_t port = 0;
 376        char str[1024];
 377        uint32_t flags;
 378        uint8_t id;
 379
 380        while (RTA_OK(attrs, len)) {
 381                if (attrs->rta_type == MPTCP_PM_ADDR_ATTR_FAMILY)
 382                        memcpy(&family, RTA_DATA(attrs), 2);
 383                if (attrs->rta_type == MPTCP_PM_ADDR_ATTR_PORT)
 384                        memcpy(&port, RTA_DATA(attrs), 2);
 385                if (attrs->rta_type == MPTCP_PM_ADDR_ATTR_ADDR4) {
 386                        if (family != AF_INET)
 387                                error(1, errno, "wrong IP (v4) for family %d",
 388                                      family);
 389                        inet_ntop(AF_INET, RTA_DATA(attrs), str, sizeof(str));
 390                        printf("%s", str);
 391                        if (port)
 392                                printf(" %d", port);
 393                }
 394                if (attrs->rta_type == MPTCP_PM_ADDR_ATTR_ADDR6) {
 395                        if (family != AF_INET6)
 396                                error(1, errno, "wrong IP (v6) for family %d",
 397                                      family);
 398                        inet_ntop(AF_INET6, RTA_DATA(attrs), str, sizeof(str));
 399                        printf("%s", str);
 400                        if (port)
 401                                printf(" %d", port);
 402                }
 403                if (attrs->rta_type == MPTCP_PM_ADDR_ATTR_ID) {
 404                        memcpy(&id, RTA_DATA(attrs), 1);
 405                        printf("id %d ", id);
 406                }
 407                if (attrs->rta_type == MPTCP_PM_ADDR_ATTR_FLAGS) {
 408                        memcpy(&flags, RTA_DATA(attrs), 4);
 409
 410                        printf("flags ");
 411                        if (flags & MPTCP_PM_ADDR_FLAG_SIGNAL) {
 412                                printf("signal");
 413                                flags &= ~MPTCP_PM_ADDR_FLAG_SIGNAL;
 414                                if (flags)
 415                                        printf(",");
 416                        }
 417
 418                        if (flags & MPTCP_PM_ADDR_FLAG_SUBFLOW) {
 419                                printf("subflow");
 420                                flags &= ~MPTCP_PM_ADDR_FLAG_SUBFLOW;
 421                                if (flags)
 422                                        printf(",");
 423                        }
 424
 425                        if (flags & MPTCP_PM_ADDR_FLAG_BACKUP) {
 426                                printf("backup");
 427                                flags &= ~MPTCP_PM_ADDR_FLAG_BACKUP;
 428                                if (flags)
 429                                        printf(",");
 430                        }
 431
 432                        if (flags & MPTCP_PM_ADDR_FLAG_FULLMESH) {
 433                                printf("fullmesh");
 434                                flags &= ~MPTCP_PM_ADDR_FLAG_FULLMESH;
 435                                if (flags)
 436                                        printf(",");
 437                        }
 438
 439                        /* bump unknown flags, if any */
 440                        if (flags)
 441                                printf("0x%x", flags);
 442                        printf(" ");
 443                }
 444                if (attrs->rta_type == MPTCP_PM_ADDR_ATTR_IF_IDX) {
 445                        char name[IF_NAMESIZE], *ret;
 446                        int32_t ifindex;
 447
 448                        memcpy(&ifindex, RTA_DATA(attrs), 4);
 449                        ret = if_indextoname(ifindex, name);
 450                        if (ret)
 451                                printf("dev %s ", ret);
 452                        else
 453                                printf("dev unknown/%d", ifindex);
 454                }
 455
 456                attrs = RTA_NEXT(attrs, len);
 457        }
 458        printf("\n");
 459}
 460
 461static void print_addrs(struct nlmsghdr *nh, int pm_family, int total_len)
 462{
 463        struct rtattr *attrs;
 464
 465        for (; NLMSG_OK(nh, total_len); nh = NLMSG_NEXT(nh, total_len)) {
 466                int len = nh->nlmsg_len;
 467
 468                if (nh->nlmsg_type == NLMSG_DONE)
 469                        break;
 470                if (nh->nlmsg_type == NLMSG_ERROR)
 471                        nl_error(nh);
 472                if (nh->nlmsg_type != pm_family)
 473                        continue;
 474
 475                len -= NLMSG_LENGTH(GENL_HDRLEN);
 476                attrs = (struct rtattr *) ((char *) NLMSG_DATA(nh) +
 477                                           GENL_HDRLEN);
 478                while (RTA_OK(attrs, len)) {
 479                        if (attrs->rta_type ==
 480                            (MPTCP_PM_ATTR_ADDR | NLA_F_NESTED))
 481                                print_addr((void *)RTA_DATA(attrs),
 482                                           attrs->rta_len);
 483                        attrs = RTA_NEXT(attrs, len);
 484                }
 485        }
 486}
 487
 488int get_addr(int fd, int pm_family, int argc, char *argv[])
 489{
 490        char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
 491                  NLMSG_ALIGN(sizeof(struct genlmsghdr)) +
 492                  1024];
 493        struct rtattr *rta, *nest;
 494        struct nlmsghdr *nh;
 495        int nest_start;
 496        u_int8_t id;
 497        int off = 0;
 498
 499        memset(data, 0, sizeof(data));
 500        nh = (void *)data;
 501        off = init_genl_req(data, pm_family, MPTCP_PM_CMD_GET_ADDR,
 502                            MPTCP_PM_VER);
 503
 504        /* the only argument is the address id */
 505        if (argc != 3)
 506                syntax(argv);
 507
 508        id = atoi(argv[2]);
 509
 510        nest_start = off;
 511        nest = (void *)(data + off);
 512        nest->rta_type = NLA_F_NESTED | MPTCP_PM_ATTR_ADDR;
 513        nest->rta_len =  RTA_LENGTH(0);
 514        off += NLMSG_ALIGN(nest->rta_len);
 515
 516        /* build a dummy addr with only the ID set */
 517        rta = (void *)(data + off);
 518        rta->rta_type = MPTCP_PM_ADDR_ATTR_ID;
 519        rta->rta_len = RTA_LENGTH(1);
 520        memcpy(RTA_DATA(rta), &id, 1);
 521        off += NLMSG_ALIGN(rta->rta_len);
 522        nest->rta_len = off - nest_start;
 523
 524        print_addrs(nh, pm_family, do_nl_req(fd, nh, off, sizeof(data)));
 525        return 0;
 526}
 527
 528int dump_addrs(int fd, int pm_family, int argc, char *argv[])
 529{
 530        char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
 531                  NLMSG_ALIGN(sizeof(struct genlmsghdr)) +
 532                  1024];
 533        pid_t pid = getpid();
 534        struct nlmsghdr *nh;
 535        int off = 0;
 536
 537        memset(data, 0, sizeof(data));
 538        nh = (void *)data;
 539        off = init_genl_req(data, pm_family, MPTCP_PM_CMD_GET_ADDR,
 540                            MPTCP_PM_VER);
 541        nh->nlmsg_flags |= NLM_F_DUMP;
 542        nh->nlmsg_seq = 1;
 543        nh->nlmsg_pid = pid;
 544        nh->nlmsg_len = off;
 545
 546        print_addrs(nh, pm_family, do_nl_req(fd, nh, off, sizeof(data)));
 547        return 0;
 548}
 549
 550int flush_addrs(int fd, int pm_family, int argc, char *argv[])
 551{
 552        char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
 553                  NLMSG_ALIGN(sizeof(struct genlmsghdr)) +
 554                  1024];
 555        struct nlmsghdr *nh;
 556        int off = 0;
 557
 558        memset(data, 0, sizeof(data));
 559        nh = (void *)data;
 560        off = init_genl_req(data, pm_family, MPTCP_PM_CMD_FLUSH_ADDRS,
 561                            MPTCP_PM_VER);
 562
 563        do_nl_req(fd, nh, off, 0);
 564        return 0;
 565}
 566
 567static void print_limits(struct nlmsghdr *nh, int pm_family, int total_len)
 568{
 569        struct rtattr *attrs;
 570        uint32_t max;
 571
 572        for (; NLMSG_OK(nh, total_len); nh = NLMSG_NEXT(nh, total_len)) {
 573                int len = nh->nlmsg_len;
 574
 575                if (nh->nlmsg_type == NLMSG_DONE)
 576                        break;
 577                if (nh->nlmsg_type == NLMSG_ERROR)
 578                        nl_error(nh);
 579                if (nh->nlmsg_type != pm_family)
 580                        continue;
 581
 582                len -= NLMSG_LENGTH(GENL_HDRLEN);
 583                attrs = (struct rtattr *) ((char *) NLMSG_DATA(nh) +
 584                                           GENL_HDRLEN);
 585                while (RTA_OK(attrs, len)) {
 586                        int type = attrs->rta_type;
 587
 588                        if (type != MPTCP_PM_ATTR_RCV_ADD_ADDRS &&
 589                            type != MPTCP_PM_ATTR_SUBFLOWS)
 590                                goto next;
 591
 592                        memcpy(&max, RTA_DATA(attrs), 4);
 593                        printf("%s %u\n", type == MPTCP_PM_ATTR_SUBFLOWS ?
 594                                          "subflows" : "accept", max);
 595
 596next:
 597                        attrs = RTA_NEXT(attrs, len);
 598                }
 599        }
 600}
 601
 602int get_set_limits(int fd, int pm_family, int argc, char *argv[])
 603{
 604        char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
 605                  NLMSG_ALIGN(sizeof(struct genlmsghdr)) +
 606                  1024];
 607        uint32_t rcv_addr = 0, subflows = 0;
 608        int cmd, len = sizeof(data);
 609        struct nlmsghdr *nh;
 610        int off = 0;
 611
 612        /* limit */
 613        if (argc == 4) {
 614                rcv_addr = atoi(argv[2]);
 615                subflows = atoi(argv[3]);
 616                cmd = MPTCP_PM_CMD_SET_LIMITS;
 617        } else {
 618                cmd = MPTCP_PM_CMD_GET_LIMITS;
 619        }
 620
 621        memset(data, 0, sizeof(data));
 622        nh = (void *)data;
 623        off = init_genl_req(data, pm_family, cmd, MPTCP_PM_VER);
 624
 625        /* limit */
 626        if (cmd == MPTCP_PM_CMD_SET_LIMITS) {
 627                struct rtattr *rta = (void *)(data + off);
 628
 629                rta->rta_type = MPTCP_PM_ATTR_RCV_ADD_ADDRS;
 630                rta->rta_len = RTA_LENGTH(4);
 631                memcpy(RTA_DATA(rta), &rcv_addr, 4);
 632                off += NLMSG_ALIGN(rta->rta_len);
 633
 634                rta = (void *)(data + off);
 635                rta->rta_type = MPTCP_PM_ATTR_SUBFLOWS;
 636                rta->rta_len = RTA_LENGTH(4);
 637                memcpy(RTA_DATA(rta), &subflows, 4);
 638                off += NLMSG_ALIGN(rta->rta_len);
 639
 640                /* do not expect a reply */
 641                len = 0;
 642        }
 643
 644        len = do_nl_req(fd, nh, off, len);
 645        if (cmd == MPTCP_PM_CMD_GET_LIMITS)
 646                print_limits(nh, pm_family, len);
 647        return 0;
 648}
 649
 650int set_flags(int fd, int pm_family, int argc, char *argv[])
 651{
 652        char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
 653                  NLMSG_ALIGN(sizeof(struct genlmsghdr)) +
 654                  1024];
 655        struct rtattr *rta, *nest;
 656        struct nlmsghdr *nh;
 657        u_int32_t flags = 0;
 658        u_int16_t family;
 659        int nest_start;
 660        int off = 0;
 661        int arg;
 662
 663        memset(data, 0, sizeof(data));
 664        nh = (void *)data;
 665        off = init_genl_req(data, pm_family, MPTCP_PM_CMD_SET_FLAGS,
 666                            MPTCP_PM_VER);
 667
 668        if (argc < 3)
 669                syntax(argv);
 670
 671        nest_start = off;
 672        nest = (void *)(data + off);
 673        nest->rta_type = NLA_F_NESTED | MPTCP_PM_ATTR_ADDR;
 674        nest->rta_len = RTA_LENGTH(0);
 675        off += NLMSG_ALIGN(nest->rta_len);
 676
 677        /* addr data */
 678        rta = (void *)(data + off);
 679        if (inet_pton(AF_INET, argv[2], RTA_DATA(rta))) {
 680                family = AF_INET;
 681                rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR4;
 682                rta->rta_len = RTA_LENGTH(4);
 683        } else if (inet_pton(AF_INET6, argv[2], RTA_DATA(rta))) {
 684                family = AF_INET6;
 685                rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR6;
 686                rta->rta_len = RTA_LENGTH(16);
 687        } else {
 688                error(1, errno, "can't parse ip %s", argv[2]);
 689        }
 690        off += NLMSG_ALIGN(rta->rta_len);
 691
 692        /* family */
 693        rta = (void *)(data + off);
 694        rta->rta_type = MPTCP_PM_ADDR_ATTR_FAMILY;
 695        rta->rta_len = RTA_LENGTH(2);
 696        memcpy(RTA_DATA(rta), &family, 2);
 697        off += NLMSG_ALIGN(rta->rta_len);
 698
 699        for (arg = 3; arg < argc; arg++) {
 700                if (!strcmp(argv[arg], "flags")) {
 701                        char *tok, *str;
 702
 703                        /* flags */
 704                        if (++arg >= argc)
 705                                error(1, 0, " missing flags value");
 706
 707                        /* do not support flag list yet */
 708                        for (str = argv[arg]; (tok = strtok(str, ","));
 709                             str = NULL) {
 710                                if (!strcmp(tok, "backup"))
 711                                        flags |= MPTCP_PM_ADDR_FLAG_BACKUP;
 712                                else if (strcmp(tok, "nobackup"))
 713                                        error(1, errno,
 714                                              "unknown flag %s", argv[arg]);
 715                        }
 716
 717                        rta = (void *)(data + off);
 718                        rta->rta_type = MPTCP_PM_ADDR_ATTR_FLAGS;
 719                        rta->rta_len = RTA_LENGTH(4);
 720                        memcpy(RTA_DATA(rta), &flags, 4);
 721                        off += NLMSG_ALIGN(rta->rta_len);
 722                } else {
 723                        error(1, 0, "unknown keyword %s", argv[arg]);
 724                }
 725        }
 726        nest->rta_len = off - nest_start;
 727
 728        do_nl_req(fd, nh, off, 0);
 729        return 0;
 730}
 731
 732int main(int argc, char *argv[])
 733{
 734        int fd, pm_family;
 735
 736        if (argc < 2)
 737                syntax(argv);
 738
 739        fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
 740        if (fd == -1)
 741                error(1, errno, "socket netlink");
 742
 743        pm_family = resolve_mptcp_pm_netlink(fd);
 744
 745        if (!strcmp(argv[1], "add"))
 746                return add_addr(fd, pm_family, argc, argv);
 747        else if (!strcmp(argv[1], "del"))
 748                return del_addr(fd, pm_family, argc, argv);
 749        else if (!strcmp(argv[1], "flush"))
 750                return flush_addrs(fd, pm_family, argc, argv);
 751        else if (!strcmp(argv[1], "get"))
 752                return get_addr(fd, pm_family, argc, argv);
 753        else if (!strcmp(argv[1], "dump"))
 754                return dump_addrs(fd, pm_family, argc, argv);
 755        else if (!strcmp(argv[1], "limits"))
 756                return get_set_limits(fd, pm_family, argc, argv);
 757        else if (!strcmp(argv[1], "set"))
 758                return set_flags(fd, pm_family, argc, argv);
 759
 760        fprintf(stderr, "unknown sub-command: %s", argv[1]);
 761        syntax(argv);
 762        return 0;
 763}
 764