1eedbc685SPaolo Abeni // SPDX-License-Identifier: GPL-2.0 2eedbc685SPaolo Abeni 3eedbc685SPaolo Abeni #include <errno.h> 4eedbc685SPaolo Abeni #include <error.h> 5eedbc685SPaolo Abeni #include <stdio.h> 6eedbc685SPaolo Abeni #include <stdlib.h> 7eedbc685SPaolo Abeni #include <string.h> 8eedbc685SPaolo Abeni #include <unistd.h> 99a0b3650SKishen Maloor #include <limits.h> 10eedbc685SPaolo Abeni 11eedbc685SPaolo Abeni #include <sys/socket.h> 12eedbc685SPaolo Abeni #include <sys/types.h> 13eedbc685SPaolo Abeni 14eedbc685SPaolo Abeni #include <arpa/inet.h> 15eedbc685SPaolo Abeni #include <net/if.h> 16eedbc685SPaolo Abeni 17eedbc685SPaolo Abeni #include <linux/rtnetlink.h> 18eedbc685SPaolo Abeni #include <linux/genetlink.h> 19eedbc685SPaolo Abeni 20eedbc685SPaolo Abeni #include "linux/mptcp.h" 21eedbc685SPaolo Abeni 22eedbc685SPaolo Abeni #ifndef MPTCP_PM_NAME 23eedbc685SPaolo Abeni #define MPTCP_PM_NAME "mptcp_pm" 24eedbc685SPaolo Abeni #endif 25b3e5fd65SKishen Maloor #ifndef MPTCP_PM_EVENTS 26b3e5fd65SKishen Maloor #define MPTCP_PM_EVENTS "mptcp_pm_events" 27b3e5fd65SKishen Maloor #endif 28*bdde081dSKishen Maloor #ifndef IPPROTO_MPTCP 29*bdde081dSKishen Maloor #define IPPROTO_MPTCP 262 30*bdde081dSKishen Maloor #endif 31eedbc685SPaolo Abeni 32eedbc685SPaolo Abeni static void syntax(char *argv[]) 33eedbc685SPaolo Abeni { 346e8b244aSGeliang Tang fprintf(stderr, "%s add|get|set|del|flush|dump|accept [<args>]\n", argv[0]); 35371b9037SGeliang Tang fprintf(stderr, "\tadd [flags signal|subflow|backup|fullmesh] [id <nr>] [dev <name>] <ip>\n"); 369a0b3650SKishen Maloor fprintf(stderr, "\tann <local-ip> id <local-id> token <token> [port <local-port>] [dev <name>]\n"); 37ecd2a77dSKishen Maloor fprintf(stderr, "\trem id <local-id> token <token>\n"); 38cf8d0a6dSKishen Maloor fprintf(stderr, "\tcsf lip <local-ip> lid <local-id> rip <remote-ip> rport <remote-port> token <token>\n"); 3957cc361bSKishen Maloor fprintf(stderr, "\tdsf lip <local-ip> lport <local-port> rip <remote-ip> rport <remote-port> token <token>\n"); 402d121c9aSGeliang Tang fprintf(stderr, "\tdel <id> [<ip>]\n"); 41eedbc685SPaolo Abeni fprintf(stderr, "\tget <id>\n"); 42a224a847SGeliang Tang fprintf(stderr, "\tset [<ip>] [id <nr>] flags [no]backup|[no]fullmesh [port <nr>]\n"); 43eedbc685SPaolo Abeni fprintf(stderr, "\tflush\n"); 44eedbc685SPaolo Abeni fprintf(stderr, "\tdump\n"); 45eedbc685SPaolo Abeni fprintf(stderr, "\tlimits [<rcv addr max> <subflow max>]\n"); 46b3e5fd65SKishen Maloor fprintf(stderr, "\tevents\n"); 47*bdde081dSKishen Maloor fprintf(stderr, "\tlisten <local-ip> <local-port>\n"); 48eedbc685SPaolo Abeni exit(0); 49eedbc685SPaolo Abeni } 50eedbc685SPaolo Abeni 51eedbc685SPaolo Abeni static int init_genl_req(char *data, int family, int cmd, int version) 52eedbc685SPaolo Abeni { 53eedbc685SPaolo Abeni struct nlmsghdr *nh = (void *)data; 54eedbc685SPaolo Abeni struct genlmsghdr *gh; 55eedbc685SPaolo Abeni int off = 0; 56eedbc685SPaolo Abeni 57eedbc685SPaolo Abeni nh->nlmsg_type = family; 58eedbc685SPaolo Abeni nh->nlmsg_flags = NLM_F_REQUEST; 59eedbc685SPaolo Abeni nh->nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN); 60eedbc685SPaolo Abeni off += NLMSG_ALIGN(sizeof(*nh)); 61eedbc685SPaolo Abeni 62eedbc685SPaolo Abeni gh = (void *)(data + off); 63eedbc685SPaolo Abeni gh->cmd = cmd; 64eedbc685SPaolo Abeni gh->version = version; 65eedbc685SPaolo Abeni off += NLMSG_ALIGN(sizeof(*gh)); 66eedbc685SPaolo Abeni return off; 67eedbc685SPaolo Abeni } 68eedbc685SPaolo Abeni 69eedbc685SPaolo Abeni static void nl_error(struct nlmsghdr *nh) 70eedbc685SPaolo Abeni { 71eedbc685SPaolo Abeni struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(nh); 72eedbc685SPaolo Abeni int len = nh->nlmsg_len - sizeof(*nh); 73eedbc685SPaolo Abeni uint32_t off; 74eedbc685SPaolo Abeni 75eedbc685SPaolo Abeni if (len < sizeof(struct nlmsgerr)) 76eedbc685SPaolo Abeni error(1, 0, "netlink error message truncated %d min %ld", len, 77eedbc685SPaolo Abeni sizeof(struct nlmsgerr)); 78eedbc685SPaolo Abeni 79eedbc685SPaolo Abeni if (!err->error) { 80eedbc685SPaolo Abeni /* check messages from kernel */ 81eedbc685SPaolo Abeni struct rtattr *attrs = (struct rtattr *)NLMSG_DATA(nh); 82eedbc685SPaolo Abeni 83eedbc685SPaolo Abeni while (RTA_OK(attrs, len)) { 84eedbc685SPaolo Abeni if (attrs->rta_type == NLMSGERR_ATTR_MSG) 85eedbc685SPaolo Abeni fprintf(stderr, "netlink ext ack msg: %s\n", 86eedbc685SPaolo Abeni (char *)RTA_DATA(attrs)); 87eedbc685SPaolo Abeni if (attrs->rta_type == NLMSGERR_ATTR_OFFS) { 88eedbc685SPaolo Abeni memcpy(&off, RTA_DATA(attrs), 4); 89eedbc685SPaolo Abeni fprintf(stderr, "netlink err off %d\n", 90eedbc685SPaolo Abeni (int)off); 91eedbc685SPaolo Abeni } 92eedbc685SPaolo Abeni attrs = RTA_NEXT(attrs, len); 93eedbc685SPaolo Abeni } 94eedbc685SPaolo Abeni } else { 95eedbc685SPaolo Abeni fprintf(stderr, "netlink error %d", err->error); 96eedbc685SPaolo Abeni } 97eedbc685SPaolo Abeni } 98eedbc685SPaolo Abeni 99b3e5fd65SKishen Maloor static int capture_events(int fd, int event_group) 100b3e5fd65SKishen Maloor { 101b3e5fd65SKishen Maloor u_int8_t buffer[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + 102b3e5fd65SKishen Maloor NLMSG_ALIGN(sizeof(struct genlmsghdr)) + 1024]; 103b3e5fd65SKishen Maloor struct genlmsghdr *ghdr; 104b3e5fd65SKishen Maloor struct rtattr *attrs; 105b3e5fd65SKishen Maloor struct nlmsghdr *nh; 106b3e5fd65SKishen Maloor int ret = 0; 107b3e5fd65SKishen Maloor int res_len; 108b3e5fd65SKishen Maloor int msg_len; 109b3e5fd65SKishen Maloor fd_set rfds; 110b3e5fd65SKishen Maloor 111b3e5fd65SKishen Maloor if (setsockopt(fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, 112b3e5fd65SKishen Maloor &event_group, sizeof(event_group)) < 0) 113b3e5fd65SKishen Maloor error(1, errno, "could not join the " MPTCP_PM_EVENTS " mcast group"); 114b3e5fd65SKishen Maloor 115b3e5fd65SKishen Maloor do { 116b3e5fd65SKishen Maloor FD_ZERO(&rfds); 117b3e5fd65SKishen Maloor FD_SET(fd, &rfds); 118b3e5fd65SKishen Maloor res_len = NLMSG_ALIGN(sizeof(struct nlmsghdr)) + 119b3e5fd65SKishen Maloor NLMSG_ALIGN(sizeof(struct genlmsghdr)) + 1024; 120b3e5fd65SKishen Maloor 121b3e5fd65SKishen Maloor ret = select(FD_SETSIZE, &rfds, NULL, NULL, NULL); 122b3e5fd65SKishen Maloor 123b3e5fd65SKishen Maloor if (ret < 0) 124b3e5fd65SKishen Maloor error(1, ret, "error in select() on NL socket"); 125b3e5fd65SKishen Maloor 126b3e5fd65SKishen Maloor res_len = recv(fd, buffer, res_len, 0); 127b3e5fd65SKishen Maloor if (res_len < 0) 128b3e5fd65SKishen Maloor error(1, res_len, "error on recv() from NL socket"); 129b3e5fd65SKishen Maloor 130b3e5fd65SKishen Maloor nh = (struct nlmsghdr *)buffer; 131b3e5fd65SKishen Maloor 132b3e5fd65SKishen Maloor for (; NLMSG_OK(nh, res_len); nh = NLMSG_NEXT(nh, res_len)) { 133b3e5fd65SKishen Maloor if (nh->nlmsg_type == NLMSG_ERROR) 134b3e5fd65SKishen Maloor error(1, NLMSG_ERROR, "received invalid NL message"); 135b3e5fd65SKishen Maloor 136b3e5fd65SKishen Maloor ghdr = (struct genlmsghdr *)NLMSG_DATA(nh); 137b3e5fd65SKishen Maloor 138b3e5fd65SKishen Maloor if (ghdr->cmd == 0) 139b3e5fd65SKishen Maloor continue; 140b3e5fd65SKishen Maloor 141b3e5fd65SKishen Maloor fprintf(stderr, "type:%d", ghdr->cmd); 142b3e5fd65SKishen Maloor 143b3e5fd65SKishen Maloor msg_len = nh->nlmsg_len - NLMSG_LENGTH(GENL_HDRLEN); 144b3e5fd65SKishen Maloor 145b3e5fd65SKishen Maloor attrs = (struct rtattr *) ((char *) ghdr + GENL_HDRLEN); 146b3e5fd65SKishen Maloor while (RTA_OK(attrs, msg_len)) { 147b3e5fd65SKishen Maloor if (attrs->rta_type == MPTCP_ATTR_TOKEN) 148b3e5fd65SKishen Maloor fprintf(stderr, ",token:%u", *(__u32 *)RTA_DATA(attrs)); 149b3e5fd65SKishen Maloor else if (attrs->rta_type == MPTCP_ATTR_FAMILY) 150b3e5fd65SKishen Maloor fprintf(stderr, ",family:%u", *(__u16 *)RTA_DATA(attrs)); 151b3e5fd65SKishen Maloor else if (attrs->rta_type == MPTCP_ATTR_LOC_ID) 152b3e5fd65SKishen Maloor fprintf(stderr, ",loc_id:%u", *(__u8 *)RTA_DATA(attrs)); 153b3e5fd65SKishen Maloor else if (attrs->rta_type == MPTCP_ATTR_REM_ID) 154b3e5fd65SKishen Maloor fprintf(stderr, ",rem_id:%u", *(__u8 *)RTA_DATA(attrs)); 155b3e5fd65SKishen Maloor else if (attrs->rta_type == MPTCP_ATTR_SADDR4) { 156b3e5fd65SKishen Maloor u_int32_t saddr4 = ntohl(*(__u32 *)RTA_DATA(attrs)); 157b3e5fd65SKishen Maloor 158b3e5fd65SKishen Maloor fprintf(stderr, ",saddr4:%u.%u.%u.%u", saddr4 >> 24, 159b3e5fd65SKishen Maloor (saddr4 >> 16) & 0xFF, (saddr4 >> 8) & 0xFF, 160b3e5fd65SKishen Maloor (saddr4 & 0xFF)); 161b3e5fd65SKishen Maloor } else if (attrs->rta_type == MPTCP_ATTR_SADDR6) { 162b3e5fd65SKishen Maloor char buf[INET6_ADDRSTRLEN]; 163b3e5fd65SKishen Maloor 164b3e5fd65SKishen Maloor if (inet_ntop(AF_INET6, RTA_DATA(attrs), buf, 165b3e5fd65SKishen Maloor sizeof(buf)) != NULL) 166b3e5fd65SKishen Maloor fprintf(stderr, ",saddr6:%s", buf); 167b3e5fd65SKishen Maloor } else if (attrs->rta_type == MPTCP_ATTR_DADDR4) { 168b3e5fd65SKishen Maloor u_int32_t daddr4 = ntohl(*(__u32 *)RTA_DATA(attrs)); 169b3e5fd65SKishen Maloor 170b3e5fd65SKishen Maloor fprintf(stderr, ",daddr4:%u.%u.%u.%u", daddr4 >> 24, 171b3e5fd65SKishen Maloor (daddr4 >> 16) & 0xFF, (daddr4 >> 8) & 0xFF, 172b3e5fd65SKishen Maloor (daddr4 & 0xFF)); 173b3e5fd65SKishen Maloor } else if (attrs->rta_type == MPTCP_ATTR_DADDR6) { 174b3e5fd65SKishen Maloor char buf[INET6_ADDRSTRLEN]; 175b3e5fd65SKishen Maloor 176b3e5fd65SKishen Maloor if (inet_ntop(AF_INET6, RTA_DATA(attrs), buf, 177b3e5fd65SKishen Maloor sizeof(buf)) != NULL) 178b3e5fd65SKishen Maloor fprintf(stderr, ",daddr6:%s", buf); 179b3e5fd65SKishen Maloor } else if (attrs->rta_type == MPTCP_ATTR_SPORT) 180b3e5fd65SKishen Maloor fprintf(stderr, ",sport:%u", 181b3e5fd65SKishen Maloor ntohs(*(__u16 *)RTA_DATA(attrs))); 182b3e5fd65SKishen Maloor else if (attrs->rta_type == MPTCP_ATTR_DPORT) 183b3e5fd65SKishen Maloor fprintf(stderr, ",dport:%u", 184b3e5fd65SKishen Maloor ntohs(*(__u16 *)RTA_DATA(attrs))); 185b3e5fd65SKishen Maloor else if (attrs->rta_type == MPTCP_ATTR_BACKUP) 186b3e5fd65SKishen Maloor fprintf(stderr, ",backup:%u", *(__u8 *)RTA_DATA(attrs)); 187b3e5fd65SKishen Maloor else if (attrs->rta_type == MPTCP_ATTR_ERROR) 188b3e5fd65SKishen Maloor fprintf(stderr, ",error:%u", *(__u8 *)RTA_DATA(attrs)); 189b3e5fd65SKishen Maloor else if (attrs->rta_type == MPTCP_ATTR_SERVER_SIDE) 190b3e5fd65SKishen Maloor fprintf(stderr, ",server_side:%u", *(__u8 *)RTA_DATA(attrs)); 191b3e5fd65SKishen Maloor 192b3e5fd65SKishen Maloor attrs = RTA_NEXT(attrs, msg_len); 193b3e5fd65SKishen Maloor } 194b3e5fd65SKishen Maloor } 195b3e5fd65SKishen Maloor fprintf(stderr, "\n"); 196b3e5fd65SKishen Maloor } while (1); 197b3e5fd65SKishen Maloor 198b3e5fd65SKishen Maloor return 0; 199b3e5fd65SKishen Maloor } 200b3e5fd65SKishen Maloor 201eedbc685SPaolo Abeni /* do a netlink command and, if max > 0, fetch the reply */ 202eedbc685SPaolo Abeni static int do_nl_req(int fd, struct nlmsghdr *nh, int len, int max) 203eedbc685SPaolo Abeni { 204eedbc685SPaolo Abeni struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK }; 205eedbc685SPaolo Abeni socklen_t addr_len; 206eedbc685SPaolo Abeni void *data = nh; 207eedbc685SPaolo Abeni int rem, ret; 208eedbc685SPaolo Abeni int err = 0; 209eedbc685SPaolo Abeni 210eedbc685SPaolo Abeni nh->nlmsg_len = len; 211eedbc685SPaolo Abeni ret = sendto(fd, data, len, 0, (void *)&nladdr, sizeof(nladdr)); 212eedbc685SPaolo Abeni if (ret != len) 213eedbc685SPaolo Abeni error(1, errno, "send netlink: %uB != %uB\n", ret, len); 214eedbc685SPaolo Abeni if (max == 0) 215eedbc685SPaolo Abeni return 0; 216eedbc685SPaolo Abeni 217eedbc685SPaolo Abeni addr_len = sizeof(nladdr); 218eedbc685SPaolo Abeni rem = ret = recvfrom(fd, data, max, 0, (void *)&nladdr, &addr_len); 219eedbc685SPaolo Abeni if (ret < 0) 220eedbc685SPaolo Abeni error(1, errno, "recv netlink: %uB\n", ret); 221eedbc685SPaolo Abeni 222eedbc685SPaolo Abeni /* Beware: the NLMSG_NEXT macro updates the 'rem' argument */ 223eedbc685SPaolo Abeni for (; NLMSG_OK(nh, rem); nh = NLMSG_NEXT(nh, rem)) { 224eedbc685SPaolo Abeni if (nh->nlmsg_type == NLMSG_ERROR) { 225eedbc685SPaolo Abeni nl_error(nh); 226eedbc685SPaolo Abeni err = 1; 227eedbc685SPaolo Abeni } 228eedbc685SPaolo Abeni } 229eedbc685SPaolo Abeni if (err) 230eedbc685SPaolo Abeni error(1, 0, "bailing out due to netlink error[s]"); 231eedbc685SPaolo Abeni return ret; 232eedbc685SPaolo Abeni } 233eedbc685SPaolo Abeni 234b3e5fd65SKishen Maloor static int genl_parse_getfamily(struct nlmsghdr *nlh, int *pm_family, 235b3e5fd65SKishen Maloor int *events_mcast_grp) 236eedbc685SPaolo Abeni { 237eedbc685SPaolo Abeni struct genlmsghdr *ghdr = NLMSG_DATA(nlh); 238eedbc685SPaolo Abeni int len = nlh->nlmsg_len; 239eedbc685SPaolo Abeni struct rtattr *attrs; 240b3e5fd65SKishen Maloor struct rtattr *grps; 241b3e5fd65SKishen Maloor struct rtattr *grp; 242b3e5fd65SKishen Maloor int got_events_grp; 243b3e5fd65SKishen Maloor int got_family; 244b3e5fd65SKishen Maloor int grps_len; 245b3e5fd65SKishen Maloor int grp_len; 246eedbc685SPaolo Abeni 247eedbc685SPaolo Abeni if (nlh->nlmsg_type != GENL_ID_CTRL) 248eedbc685SPaolo Abeni error(1, errno, "Not a controller message, len=%d type=0x%x\n", 249eedbc685SPaolo Abeni nlh->nlmsg_len, nlh->nlmsg_type); 250eedbc685SPaolo Abeni 251eedbc685SPaolo Abeni len -= NLMSG_LENGTH(GENL_HDRLEN); 252eedbc685SPaolo Abeni 253eedbc685SPaolo Abeni if (len < 0) 254eedbc685SPaolo Abeni error(1, errno, "wrong controller message len %d\n", len); 255eedbc685SPaolo Abeni 256eedbc685SPaolo Abeni if (ghdr->cmd != CTRL_CMD_NEWFAMILY) 257eedbc685SPaolo Abeni error(1, errno, "Unknown controller command %d\n", ghdr->cmd); 258eedbc685SPaolo Abeni 259eedbc685SPaolo Abeni attrs = (struct rtattr *) ((char *) ghdr + GENL_HDRLEN); 260b3e5fd65SKishen Maloor got_family = 0; 261b3e5fd65SKishen Maloor got_events_grp = 0; 262b3e5fd65SKishen Maloor 263eedbc685SPaolo Abeni while (RTA_OK(attrs, len)) { 264b3e5fd65SKishen Maloor if (attrs->rta_type == CTRL_ATTR_FAMILY_ID) { 265b3e5fd65SKishen Maloor *pm_family = *(__u16 *)RTA_DATA(attrs); 266b3e5fd65SKishen Maloor got_family = 1; 267b3e5fd65SKishen Maloor } else if (attrs->rta_type == CTRL_ATTR_MCAST_GROUPS) { 268b3e5fd65SKishen Maloor grps = RTA_DATA(attrs); 269b3e5fd65SKishen Maloor grps_len = RTA_PAYLOAD(attrs); 270b3e5fd65SKishen Maloor 271b3e5fd65SKishen Maloor while (RTA_OK(grps, grps_len)) { 272b3e5fd65SKishen Maloor grp = RTA_DATA(grps); 273b3e5fd65SKishen Maloor grp_len = RTA_PAYLOAD(grps); 274b3e5fd65SKishen Maloor got_events_grp = 0; 275b3e5fd65SKishen Maloor 276b3e5fd65SKishen Maloor while (RTA_OK(grp, grp_len)) { 277b3e5fd65SKishen Maloor if (grp->rta_type == CTRL_ATTR_MCAST_GRP_ID) 278b3e5fd65SKishen Maloor *events_mcast_grp = *(__u32 *)RTA_DATA(grp); 279b3e5fd65SKishen Maloor else if (grp->rta_type == CTRL_ATTR_MCAST_GRP_NAME && 280b3e5fd65SKishen Maloor !strcmp(RTA_DATA(grp), MPTCP_PM_EVENTS)) 281b3e5fd65SKishen Maloor got_events_grp = 1; 282b3e5fd65SKishen Maloor 283b3e5fd65SKishen Maloor grp = RTA_NEXT(grp, grp_len); 284b3e5fd65SKishen Maloor } 285b3e5fd65SKishen Maloor 286b3e5fd65SKishen Maloor if (got_events_grp) 287b3e5fd65SKishen Maloor break; 288b3e5fd65SKishen Maloor 289b3e5fd65SKishen Maloor grps = RTA_NEXT(grps, grps_len); 290b3e5fd65SKishen Maloor } 291b3e5fd65SKishen Maloor } 292b3e5fd65SKishen Maloor 293b3e5fd65SKishen Maloor if (got_family && got_events_grp) 294b3e5fd65SKishen Maloor return 0; 295b3e5fd65SKishen Maloor 296eedbc685SPaolo Abeni attrs = RTA_NEXT(attrs, len); 297eedbc685SPaolo Abeni } 298eedbc685SPaolo Abeni 299eedbc685SPaolo Abeni error(1, errno, "can't find CTRL_ATTR_FAMILY_ID attr"); 300eedbc685SPaolo Abeni return -1; 301eedbc685SPaolo Abeni } 302eedbc685SPaolo Abeni 303b3e5fd65SKishen Maloor static int resolve_mptcp_pm_netlink(int fd, int *pm_family, int *events_mcast_grp) 304eedbc685SPaolo Abeni { 305eedbc685SPaolo Abeni char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + 306eedbc685SPaolo Abeni NLMSG_ALIGN(sizeof(struct genlmsghdr)) + 307eedbc685SPaolo Abeni 1024]; 308eedbc685SPaolo Abeni struct nlmsghdr *nh; 309eedbc685SPaolo Abeni struct rtattr *rta; 310eedbc685SPaolo Abeni int namelen; 311eedbc685SPaolo Abeni int off = 0; 312eedbc685SPaolo Abeni 313eedbc685SPaolo Abeni memset(data, 0, sizeof(data)); 314eedbc685SPaolo Abeni nh = (void *)data; 315eedbc685SPaolo Abeni off = init_genl_req(data, GENL_ID_CTRL, CTRL_CMD_GETFAMILY, 0); 316eedbc685SPaolo Abeni 317eedbc685SPaolo Abeni rta = (void *)(data + off); 318eedbc685SPaolo Abeni namelen = strlen(MPTCP_PM_NAME) + 1; 319eedbc685SPaolo Abeni rta->rta_type = CTRL_ATTR_FAMILY_NAME; 320eedbc685SPaolo Abeni rta->rta_len = RTA_LENGTH(namelen); 321eedbc685SPaolo Abeni memcpy(RTA_DATA(rta), MPTCP_PM_NAME, namelen); 322eedbc685SPaolo Abeni off += NLMSG_ALIGN(rta->rta_len); 323eedbc685SPaolo Abeni 324eedbc685SPaolo Abeni do_nl_req(fd, nh, off, sizeof(data)); 325b3e5fd65SKishen Maloor return genl_parse_getfamily((void *)data, pm_family, events_mcast_grp); 326eedbc685SPaolo Abeni } 327eedbc685SPaolo Abeni 32857cc361bSKishen Maloor int dsf(int fd, int pm_family, int argc, char *argv[]) 32957cc361bSKishen Maloor { 33057cc361bSKishen Maloor char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + 33157cc361bSKishen Maloor NLMSG_ALIGN(sizeof(struct genlmsghdr)) + 33257cc361bSKishen Maloor 1024]; 33357cc361bSKishen Maloor struct rtattr *rta, *addr; 33457cc361bSKishen Maloor u_int16_t family, port; 33557cc361bSKishen Maloor struct nlmsghdr *nh; 33657cc361bSKishen Maloor u_int32_t token; 33757cc361bSKishen Maloor int addr_start; 33857cc361bSKishen Maloor int off = 0; 33957cc361bSKishen Maloor int arg; 34057cc361bSKishen Maloor 34157cc361bSKishen Maloor const char *params[5]; 34257cc361bSKishen Maloor 34357cc361bSKishen Maloor memset(params, 0, 5 * sizeof(const char *)); 34457cc361bSKishen Maloor 34557cc361bSKishen Maloor memset(data, 0, sizeof(data)); 34657cc361bSKishen Maloor nh = (void *)data; 34757cc361bSKishen Maloor off = init_genl_req(data, pm_family, MPTCP_PM_CMD_SUBFLOW_DESTROY, 34857cc361bSKishen Maloor MPTCP_PM_VER); 34957cc361bSKishen Maloor 35057cc361bSKishen Maloor if (argc < 12) 35157cc361bSKishen Maloor syntax(argv); 35257cc361bSKishen Maloor 35357cc361bSKishen Maloor /* Params recorded in this order: 35457cc361bSKishen Maloor * <local-ip>, <local-port>, <remote-ip>, <remote-port>, <token> 35557cc361bSKishen Maloor */ 35657cc361bSKishen Maloor for (arg = 2; arg < argc; arg++) { 35757cc361bSKishen Maloor if (!strcmp(argv[arg], "lip")) { 35857cc361bSKishen Maloor if (++arg >= argc) 35957cc361bSKishen Maloor error(1, 0, " missing local IP"); 36057cc361bSKishen Maloor 36157cc361bSKishen Maloor params[0] = argv[arg]; 36257cc361bSKishen Maloor } else if (!strcmp(argv[arg], "lport")) { 36357cc361bSKishen Maloor if (++arg >= argc) 36457cc361bSKishen Maloor error(1, 0, " missing local port"); 36557cc361bSKishen Maloor 36657cc361bSKishen Maloor params[1] = argv[arg]; 36757cc361bSKishen Maloor } else if (!strcmp(argv[arg], "rip")) { 36857cc361bSKishen Maloor if (++arg >= argc) 36957cc361bSKishen Maloor error(1, 0, " missing remote IP"); 37057cc361bSKishen Maloor 37157cc361bSKishen Maloor params[2] = argv[arg]; 37257cc361bSKishen Maloor } else if (!strcmp(argv[arg], "rport")) { 37357cc361bSKishen Maloor if (++arg >= argc) 37457cc361bSKishen Maloor error(1, 0, " missing remote port"); 37557cc361bSKishen Maloor 37657cc361bSKishen Maloor params[3] = argv[arg]; 37757cc361bSKishen Maloor } else if (!strcmp(argv[arg], "token")) { 37857cc361bSKishen Maloor if (++arg >= argc) 37957cc361bSKishen Maloor error(1, 0, " missing token"); 38057cc361bSKishen Maloor 38157cc361bSKishen Maloor params[4] = argv[arg]; 38257cc361bSKishen Maloor } else 38357cc361bSKishen Maloor error(1, 0, "unknown keyword %s", argv[arg]); 38457cc361bSKishen Maloor } 38557cc361bSKishen Maloor 38657cc361bSKishen Maloor for (arg = 0; arg < 4; arg = arg + 2) { 38757cc361bSKishen Maloor /* addr header */ 38857cc361bSKishen Maloor addr_start = off; 38957cc361bSKishen Maloor addr = (void *)(data + off); 39057cc361bSKishen Maloor addr->rta_type = NLA_F_NESTED | 39157cc361bSKishen Maloor ((arg == 0) ? MPTCP_PM_ATTR_ADDR : MPTCP_PM_ATTR_ADDR_REMOTE); 39257cc361bSKishen Maloor addr->rta_len = RTA_LENGTH(0); 39357cc361bSKishen Maloor off += NLMSG_ALIGN(addr->rta_len); 39457cc361bSKishen Maloor 39557cc361bSKishen Maloor /* addr data */ 39657cc361bSKishen Maloor rta = (void *)(data + off); 39757cc361bSKishen Maloor if (inet_pton(AF_INET, params[arg], RTA_DATA(rta))) { 39857cc361bSKishen Maloor family = AF_INET; 39957cc361bSKishen Maloor rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR4; 40057cc361bSKishen Maloor rta->rta_len = RTA_LENGTH(4); 40157cc361bSKishen Maloor } else if (inet_pton(AF_INET6, params[arg], RTA_DATA(rta))) { 40257cc361bSKishen Maloor family = AF_INET6; 40357cc361bSKishen Maloor rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR6; 40457cc361bSKishen Maloor rta->rta_len = RTA_LENGTH(16); 40557cc361bSKishen Maloor } else 40657cc361bSKishen Maloor error(1, errno, "can't parse ip %s", params[arg]); 40757cc361bSKishen Maloor off += NLMSG_ALIGN(rta->rta_len); 40857cc361bSKishen Maloor 40957cc361bSKishen Maloor /* family */ 41057cc361bSKishen Maloor rta = (void *)(data + off); 41157cc361bSKishen Maloor rta->rta_type = MPTCP_PM_ADDR_ATTR_FAMILY; 41257cc361bSKishen Maloor rta->rta_len = RTA_LENGTH(2); 41357cc361bSKishen Maloor memcpy(RTA_DATA(rta), &family, 2); 41457cc361bSKishen Maloor off += NLMSG_ALIGN(rta->rta_len); 41557cc361bSKishen Maloor 41657cc361bSKishen Maloor /* port */ 41757cc361bSKishen Maloor port = atoi(params[arg + 1]); 41857cc361bSKishen Maloor rta = (void *)(data + off); 41957cc361bSKishen Maloor rta->rta_type = MPTCP_PM_ADDR_ATTR_PORT; 42057cc361bSKishen Maloor rta->rta_len = RTA_LENGTH(2); 42157cc361bSKishen Maloor memcpy(RTA_DATA(rta), &port, 2); 42257cc361bSKishen Maloor off += NLMSG_ALIGN(rta->rta_len); 42357cc361bSKishen Maloor 42457cc361bSKishen Maloor addr->rta_len = off - addr_start; 42557cc361bSKishen Maloor } 42657cc361bSKishen Maloor 42757cc361bSKishen Maloor /* token */ 42857cc361bSKishen Maloor token = atoi(params[4]); 42957cc361bSKishen Maloor rta = (void *)(data + off); 43057cc361bSKishen Maloor rta->rta_type = MPTCP_PM_ATTR_TOKEN; 43157cc361bSKishen Maloor rta->rta_len = RTA_LENGTH(4); 43257cc361bSKishen Maloor memcpy(RTA_DATA(rta), &token, 4); 43357cc361bSKishen Maloor off += NLMSG_ALIGN(rta->rta_len); 43457cc361bSKishen Maloor 43557cc361bSKishen Maloor do_nl_req(fd, nh, off, 0); 43657cc361bSKishen Maloor 43757cc361bSKishen Maloor return 0; 43857cc361bSKishen Maloor } 43957cc361bSKishen Maloor 440cf8d0a6dSKishen Maloor int csf(int fd, int pm_family, int argc, char *argv[]) 441cf8d0a6dSKishen Maloor { 442cf8d0a6dSKishen Maloor char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + 443cf8d0a6dSKishen Maloor NLMSG_ALIGN(sizeof(struct genlmsghdr)) + 444cf8d0a6dSKishen Maloor 1024]; 445cf8d0a6dSKishen Maloor const char *params[5]; 446cf8d0a6dSKishen Maloor struct nlmsghdr *nh; 447cf8d0a6dSKishen Maloor struct rtattr *addr; 448cf8d0a6dSKishen Maloor struct rtattr *rta; 449cf8d0a6dSKishen Maloor u_int16_t family; 450cf8d0a6dSKishen Maloor u_int32_t token; 451cf8d0a6dSKishen Maloor u_int16_t port; 452cf8d0a6dSKishen Maloor int addr_start; 453cf8d0a6dSKishen Maloor u_int8_t id; 454cf8d0a6dSKishen Maloor int off = 0; 455cf8d0a6dSKishen Maloor int arg; 456cf8d0a6dSKishen Maloor 457cf8d0a6dSKishen Maloor memset(params, 0, 5 * sizeof(const char *)); 458cf8d0a6dSKishen Maloor 459cf8d0a6dSKishen Maloor memset(data, 0, sizeof(data)); 460cf8d0a6dSKishen Maloor nh = (void *)data; 461cf8d0a6dSKishen Maloor off = init_genl_req(data, pm_family, MPTCP_PM_CMD_SUBFLOW_CREATE, 462cf8d0a6dSKishen Maloor MPTCP_PM_VER); 463cf8d0a6dSKishen Maloor 464cf8d0a6dSKishen Maloor if (argc < 12) 465cf8d0a6dSKishen Maloor syntax(argv); 466cf8d0a6dSKishen Maloor 467cf8d0a6dSKishen Maloor /* Params recorded in this order: 468cf8d0a6dSKishen Maloor * <local-ip>, <local-id>, <remote-ip>, <remote-port>, <token> 469cf8d0a6dSKishen Maloor */ 470cf8d0a6dSKishen Maloor for (arg = 2; arg < argc; arg++) { 471cf8d0a6dSKishen Maloor if (!strcmp(argv[arg], "lip")) { 472cf8d0a6dSKishen Maloor if (++arg >= argc) 473cf8d0a6dSKishen Maloor error(1, 0, " missing local IP"); 474cf8d0a6dSKishen Maloor 475cf8d0a6dSKishen Maloor params[0] = argv[arg]; 476cf8d0a6dSKishen Maloor } else if (!strcmp(argv[arg], "lid")) { 477cf8d0a6dSKishen Maloor if (++arg >= argc) 478cf8d0a6dSKishen Maloor error(1, 0, " missing local id"); 479cf8d0a6dSKishen Maloor 480cf8d0a6dSKishen Maloor params[1] = argv[arg]; 481cf8d0a6dSKishen Maloor } else if (!strcmp(argv[arg], "rip")) { 482cf8d0a6dSKishen Maloor if (++arg >= argc) 483cf8d0a6dSKishen Maloor error(1, 0, " missing remote ip"); 484cf8d0a6dSKishen Maloor 485cf8d0a6dSKishen Maloor params[2] = argv[arg]; 486cf8d0a6dSKishen Maloor } else if (!strcmp(argv[arg], "rport")) { 487cf8d0a6dSKishen Maloor if (++arg >= argc) 488cf8d0a6dSKishen Maloor error(1, 0, " missing remote port"); 489cf8d0a6dSKishen Maloor 490cf8d0a6dSKishen Maloor params[3] = argv[arg]; 491cf8d0a6dSKishen Maloor } else if (!strcmp(argv[arg], "token")) { 492cf8d0a6dSKishen Maloor if (++arg >= argc) 493cf8d0a6dSKishen Maloor error(1, 0, " missing token"); 494cf8d0a6dSKishen Maloor 495cf8d0a6dSKishen Maloor params[4] = argv[arg]; 496cf8d0a6dSKishen Maloor } else 497cf8d0a6dSKishen Maloor error(1, 0, "unknown param %s", argv[arg]); 498cf8d0a6dSKishen Maloor } 499cf8d0a6dSKishen Maloor 500cf8d0a6dSKishen Maloor for (arg = 0; arg < 4; arg = arg + 2) { 501cf8d0a6dSKishen Maloor /* addr header */ 502cf8d0a6dSKishen Maloor addr_start = off; 503cf8d0a6dSKishen Maloor addr = (void *)(data + off); 504cf8d0a6dSKishen Maloor addr->rta_type = NLA_F_NESTED | 505cf8d0a6dSKishen Maloor ((arg == 0) ? MPTCP_PM_ATTR_ADDR : MPTCP_PM_ATTR_ADDR_REMOTE); 506cf8d0a6dSKishen Maloor addr->rta_len = RTA_LENGTH(0); 507cf8d0a6dSKishen Maloor off += NLMSG_ALIGN(addr->rta_len); 508cf8d0a6dSKishen Maloor 509cf8d0a6dSKishen Maloor /* addr data */ 510cf8d0a6dSKishen Maloor rta = (void *)(data + off); 511cf8d0a6dSKishen Maloor if (inet_pton(AF_INET, params[arg], RTA_DATA(rta))) { 512cf8d0a6dSKishen Maloor family = AF_INET; 513cf8d0a6dSKishen Maloor rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR4; 514cf8d0a6dSKishen Maloor rta->rta_len = RTA_LENGTH(4); 515cf8d0a6dSKishen Maloor } else if (inet_pton(AF_INET6, params[arg], RTA_DATA(rta))) { 516cf8d0a6dSKishen Maloor family = AF_INET6; 517cf8d0a6dSKishen Maloor rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR6; 518cf8d0a6dSKishen Maloor rta->rta_len = RTA_LENGTH(16); 519cf8d0a6dSKishen Maloor } else 520cf8d0a6dSKishen Maloor error(1, errno, "can't parse ip %s", params[arg]); 521cf8d0a6dSKishen Maloor off += NLMSG_ALIGN(rta->rta_len); 522cf8d0a6dSKishen Maloor 523cf8d0a6dSKishen Maloor /* family */ 524cf8d0a6dSKishen Maloor rta = (void *)(data + off); 525cf8d0a6dSKishen Maloor rta->rta_type = MPTCP_PM_ADDR_ATTR_FAMILY; 526cf8d0a6dSKishen Maloor rta->rta_len = RTA_LENGTH(2); 527cf8d0a6dSKishen Maloor memcpy(RTA_DATA(rta), &family, 2); 528cf8d0a6dSKishen Maloor off += NLMSG_ALIGN(rta->rta_len); 529cf8d0a6dSKishen Maloor 530cf8d0a6dSKishen Maloor if (arg == 2) { 531cf8d0a6dSKishen Maloor /* port */ 532cf8d0a6dSKishen Maloor port = atoi(params[arg + 1]); 533cf8d0a6dSKishen Maloor rta = (void *)(data + off); 534cf8d0a6dSKishen Maloor rta->rta_type = MPTCP_PM_ADDR_ATTR_PORT; 535cf8d0a6dSKishen Maloor rta->rta_len = RTA_LENGTH(2); 536cf8d0a6dSKishen Maloor memcpy(RTA_DATA(rta), &port, 2); 537cf8d0a6dSKishen Maloor off += NLMSG_ALIGN(rta->rta_len); 538cf8d0a6dSKishen Maloor } 539cf8d0a6dSKishen Maloor 540cf8d0a6dSKishen Maloor if (arg == 0) { 541cf8d0a6dSKishen Maloor /* id */ 542cf8d0a6dSKishen Maloor id = atoi(params[arg + 1]); 543cf8d0a6dSKishen Maloor rta = (void *)(data + off); 544cf8d0a6dSKishen Maloor rta->rta_type = MPTCP_PM_ADDR_ATTR_ID; 545cf8d0a6dSKishen Maloor rta->rta_len = RTA_LENGTH(1); 546cf8d0a6dSKishen Maloor memcpy(RTA_DATA(rta), &id, 1); 547cf8d0a6dSKishen Maloor off += NLMSG_ALIGN(rta->rta_len); 548cf8d0a6dSKishen Maloor } 549cf8d0a6dSKishen Maloor 550cf8d0a6dSKishen Maloor addr->rta_len = off - addr_start; 551cf8d0a6dSKishen Maloor } 552cf8d0a6dSKishen Maloor 553cf8d0a6dSKishen Maloor /* token */ 554cf8d0a6dSKishen Maloor token = atoi(params[4]); 555cf8d0a6dSKishen Maloor rta = (void *)(data + off); 556cf8d0a6dSKishen Maloor rta->rta_type = MPTCP_PM_ATTR_TOKEN; 557cf8d0a6dSKishen Maloor rta->rta_len = RTA_LENGTH(4); 558cf8d0a6dSKishen Maloor memcpy(RTA_DATA(rta), &token, 4); 559cf8d0a6dSKishen Maloor off += NLMSG_ALIGN(rta->rta_len); 560cf8d0a6dSKishen Maloor 561cf8d0a6dSKishen Maloor do_nl_req(fd, nh, off, 0); 562cf8d0a6dSKishen Maloor 563cf8d0a6dSKishen Maloor return 0; 564cf8d0a6dSKishen Maloor } 565cf8d0a6dSKishen Maloor 566ecd2a77dSKishen Maloor int remove_addr(int fd, int pm_family, int argc, char *argv[]) 567ecd2a77dSKishen Maloor { 568ecd2a77dSKishen Maloor char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + 569ecd2a77dSKishen Maloor NLMSG_ALIGN(sizeof(struct genlmsghdr)) + 570ecd2a77dSKishen Maloor 1024]; 571ecd2a77dSKishen Maloor struct nlmsghdr *nh; 572ecd2a77dSKishen Maloor struct rtattr *rta; 573ecd2a77dSKishen Maloor u_int32_t token; 574ecd2a77dSKishen Maloor u_int8_t id; 575ecd2a77dSKishen Maloor int off = 0; 576ecd2a77dSKishen Maloor int arg; 577ecd2a77dSKishen Maloor 578ecd2a77dSKishen Maloor memset(data, 0, sizeof(data)); 579ecd2a77dSKishen Maloor nh = (void *)data; 580ecd2a77dSKishen Maloor off = init_genl_req(data, pm_family, MPTCP_PM_CMD_REMOVE, 581ecd2a77dSKishen Maloor MPTCP_PM_VER); 582ecd2a77dSKishen Maloor 583ecd2a77dSKishen Maloor if (argc < 6) 584ecd2a77dSKishen Maloor syntax(argv); 585ecd2a77dSKishen Maloor 586ecd2a77dSKishen Maloor for (arg = 2; arg < argc; arg++) { 587ecd2a77dSKishen Maloor if (!strcmp(argv[arg], "id")) { 588ecd2a77dSKishen Maloor if (++arg >= argc) 589ecd2a77dSKishen Maloor error(1, 0, " missing id value"); 590ecd2a77dSKishen Maloor 591ecd2a77dSKishen Maloor id = atoi(argv[arg]); 592ecd2a77dSKishen Maloor rta = (void *)(data + off); 593ecd2a77dSKishen Maloor rta->rta_type = MPTCP_PM_ATTR_LOC_ID; 594ecd2a77dSKishen Maloor rta->rta_len = RTA_LENGTH(1); 595ecd2a77dSKishen Maloor memcpy(RTA_DATA(rta), &id, 1); 596ecd2a77dSKishen Maloor off += NLMSG_ALIGN(rta->rta_len); 597ecd2a77dSKishen Maloor } else if (!strcmp(argv[arg], "token")) { 598ecd2a77dSKishen Maloor if (++arg >= argc) 599ecd2a77dSKishen Maloor error(1, 0, " missing token value"); 600ecd2a77dSKishen Maloor 601ecd2a77dSKishen Maloor token = atoi(argv[arg]); 602ecd2a77dSKishen Maloor rta = (void *)(data + off); 603ecd2a77dSKishen Maloor rta->rta_type = MPTCP_PM_ATTR_TOKEN; 604ecd2a77dSKishen Maloor rta->rta_len = RTA_LENGTH(4); 605ecd2a77dSKishen Maloor memcpy(RTA_DATA(rta), &token, 4); 606ecd2a77dSKishen Maloor off += NLMSG_ALIGN(rta->rta_len); 607ecd2a77dSKishen Maloor } else 608ecd2a77dSKishen Maloor error(1, 0, "unknown keyword %s", argv[arg]); 609ecd2a77dSKishen Maloor } 610ecd2a77dSKishen Maloor 611ecd2a77dSKishen Maloor do_nl_req(fd, nh, off, 0); 612ecd2a77dSKishen Maloor return 0; 613ecd2a77dSKishen Maloor } 614ecd2a77dSKishen Maloor 6159a0b3650SKishen Maloor int announce_addr(int fd, int pm_family, int argc, char *argv[]) 6169a0b3650SKishen Maloor { 6179a0b3650SKishen Maloor char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + 6189a0b3650SKishen Maloor NLMSG_ALIGN(sizeof(struct genlmsghdr)) + 6199a0b3650SKishen Maloor 1024]; 6209a0b3650SKishen Maloor u_int32_t flags = MPTCP_PM_ADDR_FLAG_SIGNAL; 6219a0b3650SKishen Maloor u_int32_t token = UINT_MAX; 6229a0b3650SKishen Maloor struct rtattr *rta, *addr; 6239a0b3650SKishen Maloor u_int32_t id = UINT_MAX; 6249a0b3650SKishen Maloor struct nlmsghdr *nh; 6259a0b3650SKishen Maloor u_int16_t family; 6269a0b3650SKishen Maloor int addr_start; 6279a0b3650SKishen Maloor int off = 0; 6289a0b3650SKishen Maloor int arg; 6299a0b3650SKishen Maloor 6309a0b3650SKishen Maloor memset(data, 0, sizeof(data)); 6319a0b3650SKishen Maloor nh = (void *)data; 6329a0b3650SKishen Maloor off = init_genl_req(data, pm_family, MPTCP_PM_CMD_ANNOUNCE, 6339a0b3650SKishen Maloor MPTCP_PM_VER); 6349a0b3650SKishen Maloor 6359a0b3650SKishen Maloor if (argc < 7) 6369a0b3650SKishen Maloor syntax(argv); 6379a0b3650SKishen Maloor 6389a0b3650SKishen Maloor /* local-ip header */ 6399a0b3650SKishen Maloor addr_start = off; 6409a0b3650SKishen Maloor addr = (void *)(data + off); 6419a0b3650SKishen Maloor addr->rta_type = NLA_F_NESTED | MPTCP_PM_ATTR_ADDR; 6429a0b3650SKishen Maloor addr->rta_len = RTA_LENGTH(0); 6439a0b3650SKishen Maloor off += NLMSG_ALIGN(addr->rta_len); 6449a0b3650SKishen Maloor 6459a0b3650SKishen Maloor /* local-ip data */ 6469a0b3650SKishen Maloor /* record addr type */ 6479a0b3650SKishen Maloor rta = (void *)(data + off); 6489a0b3650SKishen Maloor if (inet_pton(AF_INET, argv[2], RTA_DATA(rta))) { 6499a0b3650SKishen Maloor family = AF_INET; 6509a0b3650SKishen Maloor rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR4; 6519a0b3650SKishen Maloor rta->rta_len = RTA_LENGTH(4); 6529a0b3650SKishen Maloor } else if (inet_pton(AF_INET6, argv[2], RTA_DATA(rta))) { 6539a0b3650SKishen Maloor family = AF_INET6; 6549a0b3650SKishen Maloor rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR6; 6559a0b3650SKishen Maloor rta->rta_len = RTA_LENGTH(16); 6569a0b3650SKishen Maloor } else 6579a0b3650SKishen Maloor error(1, errno, "can't parse ip %s", argv[2]); 6589a0b3650SKishen Maloor off += NLMSG_ALIGN(rta->rta_len); 6599a0b3650SKishen Maloor 6609a0b3650SKishen Maloor /* addr family */ 6619a0b3650SKishen Maloor rta = (void *)(data + off); 6629a0b3650SKishen Maloor rta->rta_type = MPTCP_PM_ADDR_ATTR_FAMILY; 6639a0b3650SKishen Maloor rta->rta_len = RTA_LENGTH(2); 6649a0b3650SKishen Maloor memcpy(RTA_DATA(rta), &family, 2); 6659a0b3650SKishen Maloor off += NLMSG_ALIGN(rta->rta_len); 6669a0b3650SKishen Maloor 6679a0b3650SKishen Maloor for (arg = 3; arg < argc; arg++) { 6689a0b3650SKishen Maloor if (!strcmp(argv[arg], "id")) { 6699a0b3650SKishen Maloor /* local-id */ 6709a0b3650SKishen Maloor if (++arg >= argc) 6719a0b3650SKishen Maloor error(1, 0, " missing id value"); 6729a0b3650SKishen Maloor 6739a0b3650SKishen Maloor id = atoi(argv[arg]); 6749a0b3650SKishen Maloor rta = (void *)(data + off); 6759a0b3650SKishen Maloor rta->rta_type = MPTCP_PM_ADDR_ATTR_ID; 6769a0b3650SKishen Maloor rta->rta_len = RTA_LENGTH(1); 6779a0b3650SKishen Maloor memcpy(RTA_DATA(rta), &id, 1); 6789a0b3650SKishen Maloor off += NLMSG_ALIGN(rta->rta_len); 6799a0b3650SKishen Maloor } else if (!strcmp(argv[arg], "dev")) { 6809a0b3650SKishen Maloor /* for the if_index */ 6819a0b3650SKishen Maloor int32_t ifindex; 6829a0b3650SKishen Maloor 6839a0b3650SKishen Maloor if (++arg >= argc) 6849a0b3650SKishen Maloor error(1, 0, " missing dev name"); 6859a0b3650SKishen Maloor 6869a0b3650SKishen Maloor ifindex = if_nametoindex(argv[arg]); 6879a0b3650SKishen Maloor if (!ifindex) 6889a0b3650SKishen Maloor error(1, errno, "unknown device %s", argv[arg]); 6899a0b3650SKishen Maloor 6909a0b3650SKishen Maloor rta = (void *)(data + off); 6919a0b3650SKishen Maloor rta->rta_type = MPTCP_PM_ADDR_ATTR_IF_IDX; 6929a0b3650SKishen Maloor rta->rta_len = RTA_LENGTH(4); 6939a0b3650SKishen Maloor memcpy(RTA_DATA(rta), &ifindex, 4); 6949a0b3650SKishen Maloor off += NLMSG_ALIGN(rta->rta_len); 6959a0b3650SKishen Maloor } else if (!strcmp(argv[arg], "port")) { 6969a0b3650SKishen Maloor /* local-port (optional) */ 6979a0b3650SKishen Maloor u_int16_t port; 6989a0b3650SKishen Maloor 6999a0b3650SKishen Maloor if (++arg >= argc) 7009a0b3650SKishen Maloor error(1, 0, " missing port value"); 7019a0b3650SKishen Maloor 7029a0b3650SKishen Maloor port = atoi(argv[arg]); 7039a0b3650SKishen Maloor rta = (void *)(data + off); 7049a0b3650SKishen Maloor rta->rta_type = MPTCP_PM_ADDR_ATTR_PORT; 7059a0b3650SKishen Maloor rta->rta_len = RTA_LENGTH(2); 7069a0b3650SKishen Maloor memcpy(RTA_DATA(rta), &port, 2); 7079a0b3650SKishen Maloor off += NLMSG_ALIGN(rta->rta_len); 7089a0b3650SKishen Maloor } else if (!strcmp(argv[arg], "token")) { 7099a0b3650SKishen Maloor /* MPTCP connection token */ 7109a0b3650SKishen Maloor if (++arg >= argc) 7119a0b3650SKishen Maloor error(1, 0, " missing token value"); 7129a0b3650SKishen Maloor 7139a0b3650SKishen Maloor token = atoi(argv[arg]); 7149a0b3650SKishen Maloor } else 7159a0b3650SKishen Maloor error(1, 0, "unknown keyword %s", argv[arg]); 7169a0b3650SKishen Maloor } 7179a0b3650SKishen Maloor 7189a0b3650SKishen Maloor /* addr flags */ 7199a0b3650SKishen Maloor rta = (void *)(data + off); 7209a0b3650SKishen Maloor rta->rta_type = MPTCP_PM_ADDR_ATTR_FLAGS; 7219a0b3650SKishen Maloor rta->rta_len = RTA_LENGTH(4); 7229a0b3650SKishen Maloor memcpy(RTA_DATA(rta), &flags, 4); 7239a0b3650SKishen Maloor off += NLMSG_ALIGN(rta->rta_len); 7249a0b3650SKishen Maloor 7259a0b3650SKishen Maloor addr->rta_len = off - addr_start; 7269a0b3650SKishen Maloor 7279a0b3650SKishen Maloor if (id == UINT_MAX || token == UINT_MAX) 7289a0b3650SKishen Maloor error(1, 0, " missing mandatory inputs"); 7299a0b3650SKishen Maloor 7309a0b3650SKishen Maloor /* token */ 7319a0b3650SKishen Maloor rta = (void *)(data + off); 7329a0b3650SKishen Maloor rta->rta_type = MPTCP_PM_ATTR_TOKEN; 7339a0b3650SKishen Maloor rta->rta_len = RTA_LENGTH(4); 7349a0b3650SKishen Maloor memcpy(RTA_DATA(rta), &token, 4); 7359a0b3650SKishen Maloor off += NLMSG_ALIGN(rta->rta_len); 7369a0b3650SKishen Maloor 7379a0b3650SKishen Maloor do_nl_req(fd, nh, off, 0); 7389a0b3650SKishen Maloor 7399a0b3650SKishen Maloor return 0; 7409a0b3650SKishen Maloor } 7419a0b3650SKishen Maloor 742eedbc685SPaolo Abeni int add_addr(int fd, int pm_family, int argc, char *argv[]) 743eedbc685SPaolo Abeni { 744eedbc685SPaolo Abeni char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + 745eedbc685SPaolo Abeni NLMSG_ALIGN(sizeof(struct genlmsghdr)) + 746eedbc685SPaolo Abeni 1024]; 747eedbc685SPaolo Abeni struct rtattr *rta, *nest; 748eedbc685SPaolo Abeni struct nlmsghdr *nh; 749d4a7726aSGeliang Tang u_int32_t flags = 0; 750eedbc685SPaolo Abeni u_int16_t family; 751eedbc685SPaolo Abeni int nest_start; 752eedbc685SPaolo Abeni u_int8_t id; 753eedbc685SPaolo Abeni int off = 0; 754eedbc685SPaolo Abeni int arg; 755eedbc685SPaolo Abeni 756eedbc685SPaolo Abeni memset(data, 0, sizeof(data)); 757eedbc685SPaolo Abeni nh = (void *)data; 758eedbc685SPaolo Abeni off = init_genl_req(data, pm_family, MPTCP_PM_CMD_ADD_ADDR, 759eedbc685SPaolo Abeni MPTCP_PM_VER); 760eedbc685SPaolo Abeni 761eedbc685SPaolo Abeni if (argc < 3) 762eedbc685SPaolo Abeni syntax(argv); 763eedbc685SPaolo Abeni 764eedbc685SPaolo Abeni nest_start = off; 765eedbc685SPaolo Abeni nest = (void *)(data + off); 766eedbc685SPaolo Abeni nest->rta_type = NLA_F_NESTED | MPTCP_PM_ATTR_ADDR; 767eedbc685SPaolo Abeni nest->rta_len = RTA_LENGTH(0); 768eedbc685SPaolo Abeni off += NLMSG_ALIGN(nest->rta_len); 769eedbc685SPaolo Abeni 770eedbc685SPaolo Abeni /* addr data */ 771eedbc685SPaolo Abeni rta = (void *)(data + off); 772eedbc685SPaolo Abeni if (inet_pton(AF_INET, argv[2], RTA_DATA(rta))) { 773eedbc685SPaolo Abeni family = AF_INET; 774eedbc685SPaolo Abeni rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR4; 775eedbc685SPaolo Abeni rta->rta_len = RTA_LENGTH(4); 776eedbc685SPaolo Abeni } else if (inet_pton(AF_INET6, argv[2], RTA_DATA(rta))) { 777eedbc685SPaolo Abeni family = AF_INET6; 778eedbc685SPaolo Abeni rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR6; 779eedbc685SPaolo Abeni rta->rta_len = RTA_LENGTH(16); 780eedbc685SPaolo Abeni } else 781eedbc685SPaolo Abeni error(1, errno, "can't parse ip %s", argv[2]); 782eedbc685SPaolo Abeni off += NLMSG_ALIGN(rta->rta_len); 783eedbc685SPaolo Abeni 784eedbc685SPaolo Abeni /* family */ 785eedbc685SPaolo Abeni rta = (void *)(data + off); 786eedbc685SPaolo Abeni rta->rta_type = MPTCP_PM_ADDR_ATTR_FAMILY; 787eedbc685SPaolo Abeni rta->rta_len = RTA_LENGTH(2); 788eedbc685SPaolo Abeni memcpy(RTA_DATA(rta), &family, 2); 789eedbc685SPaolo Abeni off += NLMSG_ALIGN(rta->rta_len); 790eedbc685SPaolo Abeni 791eedbc685SPaolo Abeni for (arg = 3; arg < argc; arg++) { 792eedbc685SPaolo Abeni if (!strcmp(argv[arg], "flags")) { 793eedbc685SPaolo Abeni char *tok, *str; 794eedbc685SPaolo Abeni 795eedbc685SPaolo Abeni /* flags */ 796eedbc685SPaolo Abeni if (++arg >= argc) 797eedbc685SPaolo Abeni error(1, 0, " missing flags value"); 798eedbc685SPaolo Abeni 799eedbc685SPaolo Abeni /* do not support flag list yet */ 800eedbc685SPaolo Abeni for (str = argv[arg]; (tok = strtok(str, ",")); 801eedbc685SPaolo Abeni str = NULL) { 802eedbc685SPaolo Abeni if (!strcmp(tok, "subflow")) 803eedbc685SPaolo Abeni flags |= MPTCP_PM_ADDR_FLAG_SUBFLOW; 804eedbc685SPaolo Abeni else if (!strcmp(tok, "signal")) 805eedbc685SPaolo Abeni flags |= MPTCP_PM_ADDR_FLAG_SIGNAL; 806eedbc685SPaolo Abeni else if (!strcmp(tok, "backup")) 807eedbc685SPaolo Abeni flags |= MPTCP_PM_ADDR_FLAG_BACKUP; 808371b9037SGeliang Tang else if (!strcmp(tok, "fullmesh")) 809371b9037SGeliang Tang flags |= MPTCP_PM_ADDR_FLAG_FULLMESH; 810eedbc685SPaolo Abeni else 811eedbc685SPaolo Abeni error(1, errno, 812eedbc685SPaolo Abeni "unknown flag %s", argv[arg]); 813eedbc685SPaolo Abeni } 814eedbc685SPaolo Abeni 815371b9037SGeliang Tang if (flags & MPTCP_PM_ADDR_FLAG_SIGNAL && 816371b9037SGeliang Tang flags & MPTCP_PM_ADDR_FLAG_FULLMESH) { 817371b9037SGeliang Tang error(1, errno, "error flag fullmesh"); 818371b9037SGeliang Tang } 819371b9037SGeliang Tang 820eedbc685SPaolo Abeni rta = (void *)(data + off); 821eedbc685SPaolo Abeni rta->rta_type = MPTCP_PM_ADDR_ATTR_FLAGS; 822eedbc685SPaolo Abeni rta->rta_len = RTA_LENGTH(4); 823eedbc685SPaolo Abeni memcpy(RTA_DATA(rta), &flags, 4); 824eedbc685SPaolo Abeni off += NLMSG_ALIGN(rta->rta_len); 825eedbc685SPaolo Abeni } else if (!strcmp(argv[arg], "id")) { 826eedbc685SPaolo Abeni if (++arg >= argc) 827eedbc685SPaolo Abeni error(1, 0, " missing id value"); 828eedbc685SPaolo Abeni 829eedbc685SPaolo Abeni id = atoi(argv[arg]); 830eedbc685SPaolo Abeni rta = (void *)(data + off); 831eedbc685SPaolo Abeni rta->rta_type = MPTCP_PM_ADDR_ATTR_ID; 832eedbc685SPaolo Abeni rta->rta_len = RTA_LENGTH(1); 833eedbc685SPaolo Abeni memcpy(RTA_DATA(rta), &id, 1); 834eedbc685SPaolo Abeni off += NLMSG_ALIGN(rta->rta_len); 835eedbc685SPaolo Abeni } else if (!strcmp(argv[arg], "dev")) { 836eedbc685SPaolo Abeni int32_t ifindex; 837eedbc685SPaolo Abeni 838eedbc685SPaolo Abeni if (++arg >= argc) 839eedbc685SPaolo Abeni error(1, 0, " missing dev name"); 840eedbc685SPaolo Abeni 841eedbc685SPaolo Abeni ifindex = if_nametoindex(argv[arg]); 842eedbc685SPaolo Abeni if (!ifindex) 843eedbc685SPaolo Abeni error(1, errno, "unknown device %s", argv[arg]); 844eedbc685SPaolo Abeni 845eedbc685SPaolo Abeni rta = (void *)(data + off); 846eedbc685SPaolo Abeni rta->rta_type = MPTCP_PM_ADDR_ATTR_IF_IDX; 847eedbc685SPaolo Abeni rta->rta_len = RTA_LENGTH(4); 848eedbc685SPaolo Abeni memcpy(RTA_DATA(rta), &ifindex, 4); 849eedbc685SPaolo Abeni off += NLMSG_ALIGN(rta->rta_len); 850d4a7726aSGeliang Tang } else if (!strcmp(argv[arg], "port")) { 851d4a7726aSGeliang Tang u_int16_t port; 852d4a7726aSGeliang Tang 853d4a7726aSGeliang Tang if (++arg >= argc) 854d4a7726aSGeliang Tang error(1, 0, " missing port value"); 855d4a7726aSGeliang Tang if (!(flags & MPTCP_PM_ADDR_FLAG_SIGNAL)) 856d4a7726aSGeliang Tang error(1, 0, " flags must be signal when using port"); 857d4a7726aSGeliang Tang 858d4a7726aSGeliang Tang port = atoi(argv[arg]); 859d4a7726aSGeliang Tang rta = (void *)(data + off); 860d4a7726aSGeliang Tang rta->rta_type = MPTCP_PM_ADDR_ATTR_PORT; 861d4a7726aSGeliang Tang rta->rta_len = RTA_LENGTH(2); 862d4a7726aSGeliang Tang memcpy(RTA_DATA(rta), &port, 2); 863d4a7726aSGeliang Tang off += NLMSG_ALIGN(rta->rta_len); 864eedbc685SPaolo Abeni } else 865eedbc685SPaolo Abeni error(1, 0, "unknown keyword %s", argv[arg]); 866eedbc685SPaolo Abeni } 867eedbc685SPaolo Abeni nest->rta_len = off - nest_start; 868eedbc685SPaolo Abeni 869eedbc685SPaolo Abeni do_nl_req(fd, nh, off, 0); 870eedbc685SPaolo Abeni return 0; 871eedbc685SPaolo Abeni } 872eedbc685SPaolo Abeni 873eedbc685SPaolo Abeni int del_addr(int fd, int pm_family, int argc, char *argv[]) 874eedbc685SPaolo Abeni { 875eedbc685SPaolo Abeni char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + 876eedbc685SPaolo Abeni NLMSG_ALIGN(sizeof(struct genlmsghdr)) + 877eedbc685SPaolo Abeni 1024]; 878eedbc685SPaolo Abeni struct rtattr *rta, *nest; 879eedbc685SPaolo Abeni struct nlmsghdr *nh; 8802d121c9aSGeliang Tang u_int16_t family; 881eedbc685SPaolo Abeni int nest_start; 882eedbc685SPaolo Abeni u_int8_t id; 883eedbc685SPaolo Abeni int off = 0; 884eedbc685SPaolo Abeni 885eedbc685SPaolo Abeni memset(data, 0, sizeof(data)); 886eedbc685SPaolo Abeni nh = (void *)data; 887eedbc685SPaolo Abeni off = init_genl_req(data, pm_family, MPTCP_PM_CMD_DEL_ADDR, 888eedbc685SPaolo Abeni MPTCP_PM_VER); 889eedbc685SPaolo Abeni 8902d121c9aSGeliang Tang /* the only argument is the address id (nonzero) */ 8912d121c9aSGeliang Tang if (argc != 3 && argc != 4) 892eedbc685SPaolo Abeni syntax(argv); 893eedbc685SPaolo Abeni 894eedbc685SPaolo Abeni id = atoi(argv[2]); 8952d121c9aSGeliang Tang /* zero id with the IP address */ 8962d121c9aSGeliang Tang if (!id && argc != 4) 8972d121c9aSGeliang Tang syntax(argv); 898eedbc685SPaolo Abeni 899eedbc685SPaolo Abeni nest_start = off; 900eedbc685SPaolo Abeni nest = (void *)(data + off); 901eedbc685SPaolo Abeni nest->rta_type = NLA_F_NESTED | MPTCP_PM_ATTR_ADDR; 902eedbc685SPaolo Abeni nest->rta_len = RTA_LENGTH(0); 903eedbc685SPaolo Abeni off += NLMSG_ALIGN(nest->rta_len); 904eedbc685SPaolo Abeni 905eedbc685SPaolo Abeni /* build a dummy addr with only the ID set */ 906eedbc685SPaolo Abeni rta = (void *)(data + off); 907eedbc685SPaolo Abeni rta->rta_type = MPTCP_PM_ADDR_ATTR_ID; 908eedbc685SPaolo Abeni rta->rta_len = RTA_LENGTH(1); 909eedbc685SPaolo Abeni memcpy(RTA_DATA(rta), &id, 1); 910eedbc685SPaolo Abeni off += NLMSG_ALIGN(rta->rta_len); 9112d121c9aSGeliang Tang 9122d121c9aSGeliang Tang if (!id) { 9132d121c9aSGeliang Tang /* addr data */ 9142d121c9aSGeliang Tang rta = (void *)(data + off); 9152d121c9aSGeliang Tang if (inet_pton(AF_INET, argv[3], RTA_DATA(rta))) { 9162d121c9aSGeliang Tang family = AF_INET; 9172d121c9aSGeliang Tang rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR4; 9182d121c9aSGeliang Tang rta->rta_len = RTA_LENGTH(4); 9192d121c9aSGeliang Tang } else if (inet_pton(AF_INET6, argv[3], RTA_DATA(rta))) { 9202d121c9aSGeliang Tang family = AF_INET6; 9212d121c9aSGeliang Tang rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR6; 9222d121c9aSGeliang Tang rta->rta_len = RTA_LENGTH(16); 9232d121c9aSGeliang Tang } else { 9242d121c9aSGeliang Tang error(1, errno, "can't parse ip %s", argv[3]); 9252d121c9aSGeliang Tang } 9262d121c9aSGeliang Tang off += NLMSG_ALIGN(rta->rta_len); 9272d121c9aSGeliang Tang 9282d121c9aSGeliang Tang /* family */ 9292d121c9aSGeliang Tang rta = (void *)(data + off); 9302d121c9aSGeliang Tang rta->rta_type = MPTCP_PM_ADDR_ATTR_FAMILY; 9312d121c9aSGeliang Tang rta->rta_len = RTA_LENGTH(2); 9322d121c9aSGeliang Tang memcpy(RTA_DATA(rta), &family, 2); 9332d121c9aSGeliang Tang off += NLMSG_ALIGN(rta->rta_len); 9342d121c9aSGeliang Tang } 935eedbc685SPaolo Abeni nest->rta_len = off - nest_start; 936eedbc685SPaolo Abeni 937eedbc685SPaolo Abeni do_nl_req(fd, nh, off, 0); 938eedbc685SPaolo Abeni return 0; 939eedbc685SPaolo Abeni } 940eedbc685SPaolo Abeni 941eedbc685SPaolo Abeni static void print_addr(struct rtattr *attrs, int len) 942eedbc685SPaolo Abeni { 943eedbc685SPaolo Abeni uint16_t family = 0; 944d4a7726aSGeliang Tang uint16_t port = 0; 945eedbc685SPaolo Abeni char str[1024]; 946eedbc685SPaolo Abeni uint32_t flags; 947eedbc685SPaolo Abeni uint8_t id; 948eedbc685SPaolo Abeni 949eedbc685SPaolo Abeni while (RTA_OK(attrs, len)) { 950eedbc685SPaolo Abeni if (attrs->rta_type == MPTCP_PM_ADDR_ATTR_FAMILY) 951eedbc685SPaolo Abeni memcpy(&family, RTA_DATA(attrs), 2); 952d4a7726aSGeliang Tang if (attrs->rta_type == MPTCP_PM_ADDR_ATTR_PORT) 953d4a7726aSGeliang Tang memcpy(&port, RTA_DATA(attrs), 2); 954eedbc685SPaolo Abeni if (attrs->rta_type == MPTCP_PM_ADDR_ATTR_ADDR4) { 955eedbc685SPaolo Abeni if (family != AF_INET) 956eedbc685SPaolo Abeni error(1, errno, "wrong IP (v4) for family %d", 957eedbc685SPaolo Abeni family); 958eedbc685SPaolo Abeni inet_ntop(AF_INET, RTA_DATA(attrs), str, sizeof(str)); 959eedbc685SPaolo Abeni printf("%s", str); 960d4a7726aSGeliang Tang if (port) 961d4a7726aSGeliang Tang printf(" %d", port); 962eedbc685SPaolo Abeni } 963eedbc685SPaolo Abeni if (attrs->rta_type == MPTCP_PM_ADDR_ATTR_ADDR6) { 964eedbc685SPaolo Abeni if (family != AF_INET6) 965eedbc685SPaolo Abeni error(1, errno, "wrong IP (v6) for family %d", 966eedbc685SPaolo Abeni family); 967eedbc685SPaolo Abeni inet_ntop(AF_INET6, RTA_DATA(attrs), str, sizeof(str)); 968eedbc685SPaolo Abeni printf("%s", str); 969d4a7726aSGeliang Tang if (port) 970d4a7726aSGeliang Tang printf(" %d", port); 971eedbc685SPaolo Abeni } 972eedbc685SPaolo Abeni if (attrs->rta_type == MPTCP_PM_ADDR_ATTR_ID) { 973eedbc685SPaolo Abeni memcpy(&id, RTA_DATA(attrs), 1); 974eedbc685SPaolo Abeni printf("id %d ", id); 975eedbc685SPaolo Abeni } 976eedbc685SPaolo Abeni if (attrs->rta_type == MPTCP_PM_ADDR_ATTR_FLAGS) { 977eedbc685SPaolo Abeni memcpy(&flags, RTA_DATA(attrs), 4); 978eedbc685SPaolo Abeni 979eedbc685SPaolo Abeni printf("flags "); 980eedbc685SPaolo Abeni if (flags & MPTCP_PM_ADDR_FLAG_SIGNAL) { 981eedbc685SPaolo Abeni printf("signal"); 982eedbc685SPaolo Abeni flags &= ~MPTCP_PM_ADDR_FLAG_SIGNAL; 983eedbc685SPaolo Abeni if (flags) 984eedbc685SPaolo Abeni printf(","); 985eedbc685SPaolo Abeni } 986eedbc685SPaolo Abeni 987eedbc685SPaolo Abeni if (flags & MPTCP_PM_ADDR_FLAG_SUBFLOW) { 988eedbc685SPaolo Abeni printf("subflow"); 989eedbc685SPaolo Abeni flags &= ~MPTCP_PM_ADDR_FLAG_SUBFLOW; 990eedbc685SPaolo Abeni if (flags) 991eedbc685SPaolo Abeni printf(","); 992eedbc685SPaolo Abeni } 993eedbc685SPaolo Abeni 994eedbc685SPaolo Abeni if (flags & MPTCP_PM_ADDR_FLAG_BACKUP) { 995eedbc685SPaolo Abeni printf("backup"); 996eedbc685SPaolo Abeni flags &= ~MPTCP_PM_ADDR_FLAG_BACKUP; 997eedbc685SPaolo Abeni if (flags) 998eedbc685SPaolo Abeni printf(","); 999eedbc685SPaolo Abeni } 1000eedbc685SPaolo Abeni 1001371b9037SGeliang Tang if (flags & MPTCP_PM_ADDR_FLAG_FULLMESH) { 1002371b9037SGeliang Tang printf("fullmesh"); 1003371b9037SGeliang Tang flags &= ~MPTCP_PM_ADDR_FLAG_FULLMESH; 1004371b9037SGeliang Tang if (flags) 1005371b9037SGeliang Tang printf(","); 1006371b9037SGeliang Tang } 1007371b9037SGeliang Tang 100869c6ce7bSPaolo Abeni if (flags & MPTCP_PM_ADDR_FLAG_IMPLICIT) { 100969c6ce7bSPaolo Abeni printf("implicit"); 101069c6ce7bSPaolo Abeni flags &= ~MPTCP_PM_ADDR_FLAG_IMPLICIT; 101169c6ce7bSPaolo Abeni if (flags) 101269c6ce7bSPaolo Abeni printf(","); 101369c6ce7bSPaolo Abeni } 101469c6ce7bSPaolo Abeni 1015eedbc685SPaolo Abeni /* bump unknown flags, if any */ 1016eedbc685SPaolo Abeni if (flags) 1017eedbc685SPaolo Abeni printf("0x%x", flags); 1018eedbc685SPaolo Abeni printf(" "); 1019eedbc685SPaolo Abeni } 1020eedbc685SPaolo Abeni if (attrs->rta_type == MPTCP_PM_ADDR_ATTR_IF_IDX) { 1021eedbc685SPaolo Abeni char name[IF_NAMESIZE], *ret; 1022eedbc685SPaolo Abeni int32_t ifindex; 1023eedbc685SPaolo Abeni 1024eedbc685SPaolo Abeni memcpy(&ifindex, RTA_DATA(attrs), 4); 1025eedbc685SPaolo Abeni ret = if_indextoname(ifindex, name); 1026eedbc685SPaolo Abeni if (ret) 1027eedbc685SPaolo Abeni printf("dev %s ", ret); 1028eedbc685SPaolo Abeni else 1029eedbc685SPaolo Abeni printf("dev unknown/%d", ifindex); 1030eedbc685SPaolo Abeni } 1031eedbc685SPaolo Abeni 1032eedbc685SPaolo Abeni attrs = RTA_NEXT(attrs, len); 1033eedbc685SPaolo Abeni } 1034eedbc685SPaolo Abeni printf("\n"); 1035eedbc685SPaolo Abeni } 1036eedbc685SPaolo Abeni 1037eedbc685SPaolo Abeni static void print_addrs(struct nlmsghdr *nh, int pm_family, int total_len) 1038eedbc685SPaolo Abeni { 1039eedbc685SPaolo Abeni struct rtattr *attrs; 1040eedbc685SPaolo Abeni 1041eedbc685SPaolo Abeni for (; NLMSG_OK(nh, total_len); nh = NLMSG_NEXT(nh, total_len)) { 1042eedbc685SPaolo Abeni int len = nh->nlmsg_len; 1043eedbc685SPaolo Abeni 1044eedbc685SPaolo Abeni if (nh->nlmsg_type == NLMSG_DONE) 1045eedbc685SPaolo Abeni break; 1046eedbc685SPaolo Abeni if (nh->nlmsg_type == NLMSG_ERROR) 1047eedbc685SPaolo Abeni nl_error(nh); 1048eedbc685SPaolo Abeni if (nh->nlmsg_type != pm_family) 1049eedbc685SPaolo Abeni continue; 1050eedbc685SPaolo Abeni 1051eedbc685SPaolo Abeni len -= NLMSG_LENGTH(GENL_HDRLEN); 1052eedbc685SPaolo Abeni attrs = (struct rtattr *) ((char *) NLMSG_DATA(nh) + 1053eedbc685SPaolo Abeni GENL_HDRLEN); 1054eedbc685SPaolo Abeni while (RTA_OK(attrs, len)) { 1055eedbc685SPaolo Abeni if (attrs->rta_type == 1056eedbc685SPaolo Abeni (MPTCP_PM_ATTR_ADDR | NLA_F_NESTED)) 1057eedbc685SPaolo Abeni print_addr((void *)RTA_DATA(attrs), 1058eedbc685SPaolo Abeni attrs->rta_len); 1059eedbc685SPaolo Abeni attrs = RTA_NEXT(attrs, len); 1060eedbc685SPaolo Abeni } 1061eedbc685SPaolo Abeni } 1062eedbc685SPaolo Abeni } 1063eedbc685SPaolo Abeni 1064eedbc685SPaolo Abeni int get_addr(int fd, int pm_family, int argc, char *argv[]) 1065eedbc685SPaolo Abeni { 1066eedbc685SPaolo Abeni char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + 1067eedbc685SPaolo Abeni NLMSG_ALIGN(sizeof(struct genlmsghdr)) + 1068eedbc685SPaolo Abeni 1024]; 1069eedbc685SPaolo Abeni struct rtattr *rta, *nest; 1070eedbc685SPaolo Abeni struct nlmsghdr *nh; 1071eedbc685SPaolo Abeni int nest_start; 1072eedbc685SPaolo Abeni u_int8_t id; 1073eedbc685SPaolo Abeni int off = 0; 1074eedbc685SPaolo Abeni 1075eedbc685SPaolo Abeni memset(data, 0, sizeof(data)); 1076eedbc685SPaolo Abeni nh = (void *)data; 1077eedbc685SPaolo Abeni off = init_genl_req(data, pm_family, MPTCP_PM_CMD_GET_ADDR, 1078eedbc685SPaolo Abeni MPTCP_PM_VER); 1079eedbc685SPaolo Abeni 1080eedbc685SPaolo Abeni /* the only argument is the address id */ 1081eedbc685SPaolo Abeni if (argc != 3) 1082eedbc685SPaolo Abeni syntax(argv); 1083eedbc685SPaolo Abeni 1084eedbc685SPaolo Abeni id = atoi(argv[2]); 1085eedbc685SPaolo Abeni 1086eedbc685SPaolo Abeni nest_start = off; 1087eedbc685SPaolo Abeni nest = (void *)(data + off); 1088eedbc685SPaolo Abeni nest->rta_type = NLA_F_NESTED | MPTCP_PM_ATTR_ADDR; 1089eedbc685SPaolo Abeni nest->rta_len = RTA_LENGTH(0); 1090eedbc685SPaolo Abeni off += NLMSG_ALIGN(nest->rta_len); 1091eedbc685SPaolo Abeni 1092eedbc685SPaolo Abeni /* build a dummy addr with only the ID set */ 1093eedbc685SPaolo Abeni rta = (void *)(data + off); 1094eedbc685SPaolo Abeni rta->rta_type = MPTCP_PM_ADDR_ATTR_ID; 1095eedbc685SPaolo Abeni rta->rta_len = RTA_LENGTH(1); 1096eedbc685SPaolo Abeni memcpy(RTA_DATA(rta), &id, 1); 1097eedbc685SPaolo Abeni off += NLMSG_ALIGN(rta->rta_len); 1098eedbc685SPaolo Abeni nest->rta_len = off - nest_start; 1099eedbc685SPaolo Abeni 1100eedbc685SPaolo Abeni print_addrs(nh, pm_family, do_nl_req(fd, nh, off, sizeof(data))); 1101eedbc685SPaolo Abeni return 0; 1102eedbc685SPaolo Abeni } 1103eedbc685SPaolo Abeni 1104eedbc685SPaolo Abeni int dump_addrs(int fd, int pm_family, int argc, char *argv[]) 1105eedbc685SPaolo Abeni { 1106eedbc685SPaolo Abeni char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + 1107eedbc685SPaolo Abeni NLMSG_ALIGN(sizeof(struct genlmsghdr)) + 1108eedbc685SPaolo Abeni 1024]; 1109eedbc685SPaolo Abeni pid_t pid = getpid(); 1110eedbc685SPaolo Abeni struct nlmsghdr *nh; 1111eedbc685SPaolo Abeni int off = 0; 1112eedbc685SPaolo Abeni 1113eedbc685SPaolo Abeni memset(data, 0, sizeof(data)); 1114eedbc685SPaolo Abeni nh = (void *)data; 1115eedbc685SPaolo Abeni off = init_genl_req(data, pm_family, MPTCP_PM_CMD_GET_ADDR, 1116eedbc685SPaolo Abeni MPTCP_PM_VER); 1117eedbc685SPaolo Abeni nh->nlmsg_flags |= NLM_F_DUMP; 1118eedbc685SPaolo Abeni nh->nlmsg_seq = 1; 1119eedbc685SPaolo Abeni nh->nlmsg_pid = pid; 1120eedbc685SPaolo Abeni nh->nlmsg_len = off; 1121eedbc685SPaolo Abeni 1122eedbc685SPaolo Abeni print_addrs(nh, pm_family, do_nl_req(fd, nh, off, sizeof(data))); 1123eedbc685SPaolo Abeni return 0; 1124eedbc685SPaolo Abeni } 1125eedbc685SPaolo Abeni 1126eedbc685SPaolo Abeni int flush_addrs(int fd, int pm_family, int argc, char *argv[]) 1127eedbc685SPaolo Abeni { 1128eedbc685SPaolo Abeni char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + 1129eedbc685SPaolo Abeni NLMSG_ALIGN(sizeof(struct genlmsghdr)) + 1130eedbc685SPaolo Abeni 1024]; 1131eedbc685SPaolo Abeni struct nlmsghdr *nh; 1132eedbc685SPaolo Abeni int off = 0; 1133eedbc685SPaolo Abeni 1134eedbc685SPaolo Abeni memset(data, 0, sizeof(data)); 1135eedbc685SPaolo Abeni nh = (void *)data; 1136eedbc685SPaolo Abeni off = init_genl_req(data, pm_family, MPTCP_PM_CMD_FLUSH_ADDRS, 1137eedbc685SPaolo Abeni MPTCP_PM_VER); 1138eedbc685SPaolo Abeni 1139eedbc685SPaolo Abeni do_nl_req(fd, nh, off, 0); 1140eedbc685SPaolo Abeni return 0; 1141eedbc685SPaolo Abeni } 1142eedbc685SPaolo Abeni 1143eedbc685SPaolo Abeni static void print_limits(struct nlmsghdr *nh, int pm_family, int total_len) 1144eedbc685SPaolo Abeni { 1145eedbc685SPaolo Abeni struct rtattr *attrs; 1146eedbc685SPaolo Abeni uint32_t max; 1147eedbc685SPaolo Abeni 1148eedbc685SPaolo Abeni for (; NLMSG_OK(nh, total_len); nh = NLMSG_NEXT(nh, total_len)) { 1149eedbc685SPaolo Abeni int len = nh->nlmsg_len; 1150eedbc685SPaolo Abeni 1151eedbc685SPaolo Abeni if (nh->nlmsg_type == NLMSG_DONE) 1152eedbc685SPaolo Abeni break; 1153eedbc685SPaolo Abeni if (nh->nlmsg_type == NLMSG_ERROR) 1154eedbc685SPaolo Abeni nl_error(nh); 1155eedbc685SPaolo Abeni if (nh->nlmsg_type != pm_family) 1156eedbc685SPaolo Abeni continue; 1157eedbc685SPaolo Abeni 1158eedbc685SPaolo Abeni len -= NLMSG_LENGTH(GENL_HDRLEN); 1159eedbc685SPaolo Abeni attrs = (struct rtattr *) ((char *) NLMSG_DATA(nh) + 1160eedbc685SPaolo Abeni GENL_HDRLEN); 1161eedbc685SPaolo Abeni while (RTA_OK(attrs, len)) { 1162eedbc685SPaolo Abeni int type = attrs->rta_type; 1163eedbc685SPaolo Abeni 1164eedbc685SPaolo Abeni if (type != MPTCP_PM_ATTR_RCV_ADD_ADDRS && 1165eedbc685SPaolo Abeni type != MPTCP_PM_ATTR_SUBFLOWS) 1166eedbc685SPaolo Abeni goto next; 1167eedbc685SPaolo Abeni 1168eedbc685SPaolo Abeni memcpy(&max, RTA_DATA(attrs), 4); 1169eedbc685SPaolo Abeni printf("%s %u\n", type == MPTCP_PM_ATTR_SUBFLOWS ? 1170eedbc685SPaolo Abeni "subflows" : "accept", max); 1171eedbc685SPaolo Abeni 1172eedbc685SPaolo Abeni next: 1173eedbc685SPaolo Abeni attrs = RTA_NEXT(attrs, len); 1174eedbc685SPaolo Abeni } 1175eedbc685SPaolo Abeni } 1176eedbc685SPaolo Abeni } 1177eedbc685SPaolo Abeni 1178eedbc685SPaolo Abeni int get_set_limits(int fd, int pm_family, int argc, char *argv[]) 1179eedbc685SPaolo Abeni { 1180eedbc685SPaolo Abeni char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + 1181eedbc685SPaolo Abeni NLMSG_ALIGN(sizeof(struct genlmsghdr)) + 1182eedbc685SPaolo Abeni 1024]; 1183eedbc685SPaolo Abeni uint32_t rcv_addr = 0, subflows = 0; 1184eedbc685SPaolo Abeni int cmd, len = sizeof(data); 1185eedbc685SPaolo Abeni struct nlmsghdr *nh; 1186eedbc685SPaolo Abeni int off = 0; 1187eedbc685SPaolo Abeni 1188eedbc685SPaolo Abeni /* limit */ 1189eedbc685SPaolo Abeni if (argc == 4) { 1190eedbc685SPaolo Abeni rcv_addr = atoi(argv[2]); 1191eedbc685SPaolo Abeni subflows = atoi(argv[3]); 1192eedbc685SPaolo Abeni cmd = MPTCP_PM_CMD_SET_LIMITS; 1193eedbc685SPaolo Abeni } else { 1194eedbc685SPaolo Abeni cmd = MPTCP_PM_CMD_GET_LIMITS; 1195eedbc685SPaolo Abeni } 1196eedbc685SPaolo Abeni 1197eedbc685SPaolo Abeni memset(data, 0, sizeof(data)); 1198eedbc685SPaolo Abeni nh = (void *)data; 1199eedbc685SPaolo Abeni off = init_genl_req(data, pm_family, cmd, MPTCP_PM_VER); 1200eedbc685SPaolo Abeni 1201eedbc685SPaolo Abeni /* limit */ 1202eedbc685SPaolo Abeni if (cmd == MPTCP_PM_CMD_SET_LIMITS) { 1203eedbc685SPaolo Abeni struct rtattr *rta = (void *)(data + off); 1204eedbc685SPaolo Abeni 1205eedbc685SPaolo Abeni rta->rta_type = MPTCP_PM_ATTR_RCV_ADD_ADDRS; 1206eedbc685SPaolo Abeni rta->rta_len = RTA_LENGTH(4); 1207eedbc685SPaolo Abeni memcpy(RTA_DATA(rta), &rcv_addr, 4); 1208eedbc685SPaolo Abeni off += NLMSG_ALIGN(rta->rta_len); 1209eedbc685SPaolo Abeni 1210eedbc685SPaolo Abeni rta = (void *)(data + off); 1211eedbc685SPaolo Abeni rta->rta_type = MPTCP_PM_ATTR_SUBFLOWS; 1212eedbc685SPaolo Abeni rta->rta_len = RTA_LENGTH(4); 1213eedbc685SPaolo Abeni memcpy(RTA_DATA(rta), &subflows, 4); 1214eedbc685SPaolo Abeni off += NLMSG_ALIGN(rta->rta_len); 1215eedbc685SPaolo Abeni 1216eedbc685SPaolo Abeni /* do not expect a reply */ 1217eedbc685SPaolo Abeni len = 0; 1218eedbc685SPaolo Abeni } 1219eedbc685SPaolo Abeni 1220eedbc685SPaolo Abeni len = do_nl_req(fd, nh, off, len); 1221eedbc685SPaolo Abeni if (cmd == MPTCP_PM_CMD_GET_LIMITS) 1222eedbc685SPaolo Abeni print_limits(nh, pm_family, len); 1223eedbc685SPaolo Abeni return 0; 1224eedbc685SPaolo Abeni } 1225eedbc685SPaolo Abeni 1226*bdde081dSKishen Maloor int add_listener(int argc, char *argv[]) 1227*bdde081dSKishen Maloor { 1228*bdde081dSKishen Maloor struct sockaddr_storage addr; 1229*bdde081dSKishen Maloor struct sockaddr_in6 *a6; 1230*bdde081dSKishen Maloor struct sockaddr_in *a4; 1231*bdde081dSKishen Maloor u_int16_t family; 1232*bdde081dSKishen Maloor int enable = 1; 1233*bdde081dSKishen Maloor int sock; 1234*bdde081dSKishen Maloor int err; 1235*bdde081dSKishen Maloor 1236*bdde081dSKishen Maloor if (argc < 4) 1237*bdde081dSKishen Maloor syntax(argv); 1238*bdde081dSKishen Maloor 1239*bdde081dSKishen Maloor memset(&addr, 0, sizeof(struct sockaddr_storage)); 1240*bdde081dSKishen Maloor a4 = (struct sockaddr_in *)&addr; 1241*bdde081dSKishen Maloor a6 = (struct sockaddr_in6 *)&addr; 1242*bdde081dSKishen Maloor 1243*bdde081dSKishen Maloor if (inet_pton(AF_INET, argv[2], &a4->sin_addr)) { 1244*bdde081dSKishen Maloor family = AF_INET; 1245*bdde081dSKishen Maloor a4->sin_family = family; 1246*bdde081dSKishen Maloor a4->sin_port = htons(atoi(argv[3])); 1247*bdde081dSKishen Maloor } else if (inet_pton(AF_INET6, argv[2], &a6->sin6_addr)) { 1248*bdde081dSKishen Maloor family = AF_INET6; 1249*bdde081dSKishen Maloor a6->sin6_family = family; 1250*bdde081dSKishen Maloor a6->sin6_port = htons(atoi(argv[3])); 1251*bdde081dSKishen Maloor } else 1252*bdde081dSKishen Maloor error(1, errno, "can't parse ip %s", argv[2]); 1253*bdde081dSKishen Maloor 1254*bdde081dSKishen Maloor sock = socket(family, SOCK_STREAM, IPPROTO_MPTCP); 1255*bdde081dSKishen Maloor if (sock < 0) 1256*bdde081dSKishen Maloor error(1, errno, "can't create listener sock\n"); 1257*bdde081dSKishen Maloor 1258*bdde081dSKishen Maloor if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable))) { 1259*bdde081dSKishen Maloor close(sock); 1260*bdde081dSKishen Maloor error(1, errno, "can't set SO_REUSEADDR on listener sock\n"); 1261*bdde081dSKishen Maloor } 1262*bdde081dSKishen Maloor 1263*bdde081dSKishen Maloor err = bind(sock, (struct sockaddr *)&addr, 1264*bdde081dSKishen Maloor ((family == AF_INET) ? sizeof(struct sockaddr_in) : 1265*bdde081dSKishen Maloor sizeof(struct sockaddr_in6))); 1266*bdde081dSKishen Maloor 1267*bdde081dSKishen Maloor if (err == 0 && listen(sock, 30) == 0) 1268*bdde081dSKishen Maloor pause(); 1269*bdde081dSKishen Maloor 1270*bdde081dSKishen Maloor close(sock); 1271*bdde081dSKishen Maloor return 0; 1272*bdde081dSKishen Maloor } 1273*bdde081dSKishen Maloor 12746e8b244aSGeliang Tang int set_flags(int fd, int pm_family, int argc, char *argv[]) 12756e8b244aSGeliang Tang { 12766e8b244aSGeliang Tang char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + 12776e8b244aSGeliang Tang NLMSG_ALIGN(sizeof(struct genlmsghdr)) + 12786e8b244aSGeliang Tang 1024]; 12796e8b244aSGeliang Tang struct rtattr *rta, *nest; 12806e8b244aSGeliang Tang struct nlmsghdr *nh; 12816e8b244aSGeliang Tang u_int32_t flags = 0; 12826e8b244aSGeliang Tang u_int16_t family; 12836e8b244aSGeliang Tang int nest_start; 1284a224a847SGeliang Tang int use_id = 0; 1285a224a847SGeliang Tang u_int8_t id; 12866e8b244aSGeliang Tang int off = 0; 1287a224a847SGeliang Tang int arg = 2; 12886e8b244aSGeliang Tang 12896e8b244aSGeliang Tang memset(data, 0, sizeof(data)); 12906e8b244aSGeliang Tang nh = (void *)data; 12916e8b244aSGeliang Tang off = init_genl_req(data, pm_family, MPTCP_PM_CMD_SET_FLAGS, 12926e8b244aSGeliang Tang MPTCP_PM_VER); 12936e8b244aSGeliang Tang 12946e8b244aSGeliang Tang if (argc < 3) 12956e8b244aSGeliang Tang syntax(argv); 12966e8b244aSGeliang Tang 12976e8b244aSGeliang Tang nest_start = off; 12986e8b244aSGeliang Tang nest = (void *)(data + off); 12996e8b244aSGeliang Tang nest->rta_type = NLA_F_NESTED | MPTCP_PM_ATTR_ADDR; 13006e8b244aSGeliang Tang nest->rta_len = RTA_LENGTH(0); 13016e8b244aSGeliang Tang off += NLMSG_ALIGN(nest->rta_len); 13026e8b244aSGeliang Tang 1303a224a847SGeliang Tang if (!strcmp(argv[arg], "id")) { 1304a224a847SGeliang Tang if (++arg >= argc) 1305a224a847SGeliang Tang error(1, 0, " missing id value"); 1306a224a847SGeliang Tang 1307a224a847SGeliang Tang use_id = 1; 1308a224a847SGeliang Tang id = atoi(argv[arg]); 1309a224a847SGeliang Tang rta = (void *)(data + off); 1310a224a847SGeliang Tang rta->rta_type = MPTCP_PM_ADDR_ATTR_ID; 1311a224a847SGeliang Tang rta->rta_len = RTA_LENGTH(1); 1312a224a847SGeliang Tang memcpy(RTA_DATA(rta), &id, 1); 1313a224a847SGeliang Tang off += NLMSG_ALIGN(rta->rta_len); 1314a224a847SGeliang Tang } else { 13156e8b244aSGeliang Tang /* addr data */ 13166e8b244aSGeliang Tang rta = (void *)(data + off); 1317a224a847SGeliang Tang if (inet_pton(AF_INET, argv[arg], RTA_DATA(rta))) { 13186e8b244aSGeliang Tang family = AF_INET; 13196e8b244aSGeliang Tang rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR4; 13206e8b244aSGeliang Tang rta->rta_len = RTA_LENGTH(4); 1321a224a847SGeliang Tang } else if (inet_pton(AF_INET6, argv[arg], RTA_DATA(rta))) { 13226e8b244aSGeliang Tang family = AF_INET6; 13236e8b244aSGeliang Tang rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR6; 13246e8b244aSGeliang Tang rta->rta_len = RTA_LENGTH(16); 13256e8b244aSGeliang Tang } else { 1326a224a847SGeliang Tang error(1, errno, "can't parse ip %s", argv[arg]); 13276e8b244aSGeliang Tang } 13286e8b244aSGeliang Tang off += NLMSG_ALIGN(rta->rta_len); 13296e8b244aSGeliang Tang 13306e8b244aSGeliang Tang /* family */ 13316e8b244aSGeliang Tang rta = (void *)(data + off); 13326e8b244aSGeliang Tang rta->rta_type = MPTCP_PM_ADDR_ATTR_FAMILY; 13336e8b244aSGeliang Tang rta->rta_len = RTA_LENGTH(2); 13346e8b244aSGeliang Tang memcpy(RTA_DATA(rta), &family, 2); 13356e8b244aSGeliang Tang off += NLMSG_ALIGN(rta->rta_len); 1336a224a847SGeliang Tang } 13376e8b244aSGeliang Tang 1338a224a847SGeliang Tang if (++arg >= argc) 1339a224a847SGeliang Tang error(1, 0, " missing flags keyword"); 1340a224a847SGeliang Tang 1341a224a847SGeliang Tang for (; arg < argc; arg++) { 13426e8b244aSGeliang Tang if (!strcmp(argv[arg], "flags")) { 13436e8b244aSGeliang Tang char *tok, *str; 13446e8b244aSGeliang Tang 13456e8b244aSGeliang Tang /* flags */ 13466e8b244aSGeliang Tang if (++arg >= argc) 13476e8b244aSGeliang Tang error(1, 0, " missing flags value"); 13486e8b244aSGeliang Tang 13496e8b244aSGeliang Tang for (str = argv[arg]; (tok = strtok(str, ",")); 13506e8b244aSGeliang Tang str = NULL) { 13516e8b244aSGeliang Tang if (!strcmp(tok, "backup")) 13526e8b244aSGeliang Tang flags |= MPTCP_PM_ADDR_FLAG_BACKUP; 1353c25d29beSGeliang Tang else if (!strcmp(tok, "fullmesh")) 1354c25d29beSGeliang Tang flags |= MPTCP_PM_ADDR_FLAG_FULLMESH; 1355c25d29beSGeliang Tang else if (strcmp(tok, "nobackup") && 1356c25d29beSGeliang Tang strcmp(tok, "nofullmesh")) 13576e8b244aSGeliang Tang error(1, errno, 13586e8b244aSGeliang Tang "unknown flag %s", argv[arg]); 13596e8b244aSGeliang Tang } 13606e8b244aSGeliang Tang 13616e8b244aSGeliang Tang rta = (void *)(data + off); 13626e8b244aSGeliang Tang rta->rta_type = MPTCP_PM_ADDR_ATTR_FLAGS; 13636e8b244aSGeliang Tang rta->rta_len = RTA_LENGTH(4); 13646e8b244aSGeliang Tang memcpy(RTA_DATA(rta), &flags, 4); 13656e8b244aSGeliang Tang off += NLMSG_ALIGN(rta->rta_len); 1366d6a676e0SGeliang Tang } else if (!strcmp(argv[arg], "port")) { 1367d6a676e0SGeliang Tang u_int16_t port; 1368d6a676e0SGeliang Tang 1369a224a847SGeliang Tang if (use_id) 1370a224a847SGeliang Tang error(1, 0, " port can't be used with id"); 1371a224a847SGeliang Tang 1372d6a676e0SGeliang Tang if (++arg >= argc) 1373d6a676e0SGeliang Tang error(1, 0, " missing port value"); 1374d6a676e0SGeliang Tang 1375d6a676e0SGeliang Tang port = atoi(argv[arg]); 1376d6a676e0SGeliang Tang rta = (void *)(data + off); 1377d6a676e0SGeliang Tang rta->rta_type = MPTCP_PM_ADDR_ATTR_PORT; 1378d6a676e0SGeliang Tang rta->rta_len = RTA_LENGTH(2); 1379d6a676e0SGeliang Tang memcpy(RTA_DATA(rta), &port, 2); 1380d6a676e0SGeliang Tang off += NLMSG_ALIGN(rta->rta_len); 13816e8b244aSGeliang Tang } else { 13826e8b244aSGeliang Tang error(1, 0, "unknown keyword %s", argv[arg]); 13836e8b244aSGeliang Tang } 13846e8b244aSGeliang Tang } 13856e8b244aSGeliang Tang nest->rta_len = off - nest_start; 13866e8b244aSGeliang Tang 13876e8b244aSGeliang Tang do_nl_req(fd, nh, off, 0); 13886e8b244aSGeliang Tang return 0; 13896e8b244aSGeliang Tang } 13906e8b244aSGeliang Tang 1391eedbc685SPaolo Abeni int main(int argc, char *argv[]) 1392eedbc685SPaolo Abeni { 1393b3e5fd65SKishen Maloor int events_mcast_grp; 1394b3e5fd65SKishen Maloor int pm_family; 1395b3e5fd65SKishen Maloor int fd; 1396eedbc685SPaolo Abeni 1397eedbc685SPaolo Abeni if (argc < 2) 1398eedbc685SPaolo Abeni syntax(argv); 1399eedbc685SPaolo Abeni 1400eedbc685SPaolo Abeni fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC); 1401eedbc685SPaolo Abeni if (fd == -1) 1402eedbc685SPaolo Abeni error(1, errno, "socket netlink"); 1403eedbc685SPaolo Abeni 1404b3e5fd65SKishen Maloor resolve_mptcp_pm_netlink(fd, &pm_family, &events_mcast_grp); 1405eedbc685SPaolo Abeni 1406eedbc685SPaolo Abeni if (!strcmp(argv[1], "add")) 1407eedbc685SPaolo Abeni return add_addr(fd, pm_family, argc, argv); 14089a0b3650SKishen Maloor else if (!strcmp(argv[1], "ann")) 14099a0b3650SKishen Maloor return announce_addr(fd, pm_family, argc, argv); 1410ecd2a77dSKishen Maloor else if (!strcmp(argv[1], "rem")) 1411ecd2a77dSKishen Maloor return remove_addr(fd, pm_family, argc, argv); 1412cf8d0a6dSKishen Maloor else if (!strcmp(argv[1], "csf")) 1413cf8d0a6dSKishen Maloor return csf(fd, pm_family, argc, argv); 141457cc361bSKishen Maloor else if (!strcmp(argv[1], "dsf")) 141557cc361bSKishen Maloor return dsf(fd, pm_family, argc, argv); 1416eedbc685SPaolo Abeni else if (!strcmp(argv[1], "del")) 1417eedbc685SPaolo Abeni return del_addr(fd, pm_family, argc, argv); 1418eedbc685SPaolo Abeni else if (!strcmp(argv[1], "flush")) 1419eedbc685SPaolo Abeni return flush_addrs(fd, pm_family, argc, argv); 1420eedbc685SPaolo Abeni else if (!strcmp(argv[1], "get")) 1421eedbc685SPaolo Abeni return get_addr(fd, pm_family, argc, argv); 1422eedbc685SPaolo Abeni else if (!strcmp(argv[1], "dump")) 1423eedbc685SPaolo Abeni return dump_addrs(fd, pm_family, argc, argv); 1424eedbc685SPaolo Abeni else if (!strcmp(argv[1], "limits")) 1425eedbc685SPaolo Abeni return get_set_limits(fd, pm_family, argc, argv); 14266e8b244aSGeliang Tang else if (!strcmp(argv[1], "set")) 14276e8b244aSGeliang Tang return set_flags(fd, pm_family, argc, argv); 1428b3e5fd65SKishen Maloor else if (!strcmp(argv[1], "events")) 1429b3e5fd65SKishen Maloor return capture_events(fd, events_mcast_grp); 1430*bdde081dSKishen Maloor else if (!strcmp(argv[1], "listen")) 1431*bdde081dSKishen Maloor return add_listener(argc, argv); 1432eedbc685SPaolo Abeni 1433eedbc685SPaolo Abeni fprintf(stderr, "unknown sub-command: %s", argv[1]); 1434eedbc685SPaolo Abeni syntax(argv); 1435eedbc685SPaolo Abeni return 0; 1436eedbc685SPaolo Abeni } 1437