selftests: mptcp: add set_flags command in pm_nl_ctl
[linux-2.6-microblaze.git] / tools / testing / selftests / net / mptcp / pm_nl_ctl.c
index b24a2f1..abc269e 100644 (file)
 
 static void syntax(char *argv[])
 {
-       fprintf(stderr, "%s add|get|del|flush|dump|accept [<args>]\n", argv[0]);
+       fprintf(stderr, "%s add|get|set|del|flush|dump|accept [<args>]\n", argv[0]);
        fprintf(stderr, "\tadd [flags signal|subflow|backup] [id <nr>] [dev <name>] <ip>\n");
        fprintf(stderr, "\tdel <id>\n");
        fprintf(stderr, "\tget <id>\n");
+       fprintf(stderr, "\tset <ip> [flags backup|nobackup]\n");
        fprintf(stderr, "\tflush\n");
        fprintf(stderr, "\tdump\n");
        fprintf(stderr, "\tlimits [<rcv addr max> <subflow max>]\n");
@@ -584,6 +585,88 @@ int get_set_limits(int fd, int pm_family, int argc, char *argv[])
        return 0;
 }
 
+int set_flags(int fd, int pm_family, int argc, char *argv[])
+{
+       char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
+                 NLMSG_ALIGN(sizeof(struct genlmsghdr)) +
+                 1024];
+       struct rtattr *rta, *nest;
+       struct nlmsghdr *nh;
+       u_int32_t flags = 0;
+       u_int16_t family;
+       int nest_start;
+       int off = 0;
+       int arg;
+
+       memset(data, 0, sizeof(data));
+       nh = (void *)data;
+       off = init_genl_req(data, pm_family, MPTCP_PM_CMD_SET_FLAGS,
+                           MPTCP_PM_VER);
+
+       if (argc < 3)
+               syntax(argv);
+
+       nest_start = off;
+       nest = (void *)(data + off);
+       nest->rta_type = NLA_F_NESTED | MPTCP_PM_ATTR_ADDR;
+       nest->rta_len = RTA_LENGTH(0);
+       off += NLMSG_ALIGN(nest->rta_len);
+
+       /* addr data */
+       rta = (void *)(data + off);
+       if (inet_pton(AF_INET, argv[2], RTA_DATA(rta))) {
+               family = AF_INET;
+               rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR4;
+               rta->rta_len = RTA_LENGTH(4);
+       } else if (inet_pton(AF_INET6, argv[2], RTA_DATA(rta))) {
+               family = AF_INET6;
+               rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR6;
+               rta->rta_len = RTA_LENGTH(16);
+       } else {
+               error(1, errno, "can't parse ip %s", argv[2]);
+       }
+       off += NLMSG_ALIGN(rta->rta_len);
+
+       /* family */
+       rta = (void *)(data + off);
+       rta->rta_type = MPTCP_PM_ADDR_ATTR_FAMILY;
+       rta->rta_len = RTA_LENGTH(2);
+       memcpy(RTA_DATA(rta), &family, 2);
+       off += NLMSG_ALIGN(rta->rta_len);
+
+       for (arg = 3; arg < argc; arg++) {
+               if (!strcmp(argv[arg], "flags")) {
+                       char *tok, *str;
+
+                       /* flags */
+                       if (++arg >= argc)
+                               error(1, 0, " missing flags value");
+
+                       /* do not support flag list yet */
+                       for (str = argv[arg]; (tok = strtok(str, ","));
+                            str = NULL) {
+                               if (!strcmp(tok, "backup"))
+                                       flags |= MPTCP_PM_ADDR_FLAG_BACKUP;
+                               else if (strcmp(tok, "nobackup"))
+                                       error(1, errno,
+                                             "unknown flag %s", argv[arg]);
+                       }
+
+                       rta = (void *)(data + off);
+                       rta->rta_type = MPTCP_PM_ADDR_ATTR_FLAGS;
+                       rta->rta_len = RTA_LENGTH(4);
+                       memcpy(RTA_DATA(rta), &flags, 4);
+                       off += NLMSG_ALIGN(rta->rta_len);
+               } else {
+                       error(1, 0, "unknown keyword %s", argv[arg]);
+               }
+       }
+       nest->rta_len = off - nest_start;
+
+       do_nl_req(fd, nh, off, 0);
+       return 0;
+}
+
 int main(int argc, char *argv[])
 {
        int fd, pm_family;
@@ -609,6 +692,8 @@ int main(int argc, char *argv[])
                return dump_addrs(fd, pm_family, argc, argv);
        else if (!strcmp(argv[1], "limits"))
                return get_set_limits(fd, pm_family, argc, argv);
+       else if (!strcmp(argv[1], "set"))
+               return set_flags(fd, pm_family, argc, argv);
 
        fprintf(stderr, "unknown sub-command: %s", argv[1]);
        syntax(argv);