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 
25 static 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] [id <nr>] [dev <name>] <ip>\n");
29 	fprintf(stderr, "\tdel <id>\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 
38 static 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 
56 static 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  */
87 static 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 
119 static 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 
148 static 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 
173 int 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
240 					error(1, errno,
241 					      "unknown flag %s", argv[arg]);
242 			}
243 
244 			rta = (void *)(data + off);
245 			rta->rta_type = MPTCP_PM_ADDR_ATTR_FLAGS;
246 			rta->rta_len = RTA_LENGTH(4);
247 			memcpy(RTA_DATA(rta), &flags, 4);
248 			off += NLMSG_ALIGN(rta->rta_len);
249 		} else if (!strcmp(argv[arg], "id")) {
250 			if (++arg >= argc)
251 				error(1, 0, " missing id value");
252 
253 			id = atoi(argv[arg]);
254 			rta = (void *)(data + off);
255 			rta->rta_type = MPTCP_PM_ADDR_ATTR_ID;
256 			rta->rta_len = RTA_LENGTH(1);
257 			memcpy(RTA_DATA(rta), &id, 1);
258 			off += NLMSG_ALIGN(rta->rta_len);
259 		} else if (!strcmp(argv[arg], "dev")) {
260 			int32_t ifindex;
261 
262 			if (++arg >= argc)
263 				error(1, 0, " missing dev name");
264 
265 			ifindex = if_nametoindex(argv[arg]);
266 			if (!ifindex)
267 				error(1, errno, "unknown device %s", argv[arg]);
268 
269 			rta = (void *)(data + off);
270 			rta->rta_type = MPTCP_PM_ADDR_ATTR_IF_IDX;
271 			rta->rta_len = RTA_LENGTH(4);
272 			memcpy(RTA_DATA(rta), &ifindex, 4);
273 			off += NLMSG_ALIGN(rta->rta_len);
274 		} else if (!strcmp(argv[arg], "port")) {
275 			u_int16_t port;
276 
277 			if (++arg >= argc)
278 				error(1, 0, " missing port value");
279 			if (!(flags & MPTCP_PM_ADDR_FLAG_SIGNAL))
280 				error(1, 0, " flags must be signal when using port");
281 
282 			port = atoi(argv[arg]);
283 			rta = (void *)(data + off);
284 			rta->rta_type = MPTCP_PM_ADDR_ATTR_PORT;
285 			rta->rta_len = RTA_LENGTH(2);
286 			memcpy(RTA_DATA(rta), &port, 2);
287 			off += NLMSG_ALIGN(rta->rta_len);
288 		} else
289 			error(1, 0, "unknown keyword %s", argv[arg]);
290 	}
291 	nest->rta_len = off - nest_start;
292 
293 	do_nl_req(fd, nh, off, 0);
294 	return 0;
295 }
296 
297 int del_addr(int fd, int pm_family, int argc, char *argv[])
298 {
299 	char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
300 		  NLMSG_ALIGN(sizeof(struct genlmsghdr)) +
301 		  1024];
302 	struct rtattr *rta, *nest;
303 	struct nlmsghdr *nh;
304 	int nest_start;
305 	u_int8_t id;
306 	int off = 0;
307 
308 	memset(data, 0, sizeof(data));
309 	nh = (void *)data;
310 	off = init_genl_req(data, pm_family, MPTCP_PM_CMD_DEL_ADDR,
311 			    MPTCP_PM_VER);
312 
313 	/* the only argument is the address id */
314 	if (argc != 3)
315 		syntax(argv);
316 
317 	id = atoi(argv[2]);
318 
319 	nest_start = off;
320 	nest = (void *)(data + off);
321 	nest->rta_type = NLA_F_NESTED | MPTCP_PM_ATTR_ADDR;
322 	nest->rta_len =  RTA_LENGTH(0);
323 	off += NLMSG_ALIGN(nest->rta_len);
324 
325 	/* build a dummy addr with only the ID set */
326 	rta = (void *)(data + off);
327 	rta->rta_type = MPTCP_PM_ADDR_ATTR_ID;
328 	rta->rta_len = RTA_LENGTH(1);
329 	memcpy(RTA_DATA(rta), &id, 1);
330 	off += NLMSG_ALIGN(rta->rta_len);
331 	nest->rta_len = off - nest_start;
332 
333 	do_nl_req(fd, nh, off, 0);
334 	return 0;
335 }
336 
337 static void print_addr(struct rtattr *attrs, int len)
338 {
339 	uint16_t family = 0;
340 	uint16_t port = 0;
341 	char str[1024];
342 	uint32_t flags;
343 	uint8_t id;
344 
345 	while (RTA_OK(attrs, len)) {
346 		if (attrs->rta_type == MPTCP_PM_ADDR_ATTR_FAMILY)
347 			memcpy(&family, RTA_DATA(attrs), 2);
348 		if (attrs->rta_type == MPTCP_PM_ADDR_ATTR_PORT)
349 			memcpy(&port, RTA_DATA(attrs), 2);
350 		if (attrs->rta_type == MPTCP_PM_ADDR_ATTR_ADDR4) {
351 			if (family != AF_INET)
352 				error(1, errno, "wrong IP (v4) for family %d",
353 				      family);
354 			inet_ntop(AF_INET, RTA_DATA(attrs), str, sizeof(str));
355 			printf("%s", str);
356 			if (port)
357 				printf(" %d", port);
358 		}
359 		if (attrs->rta_type == MPTCP_PM_ADDR_ATTR_ADDR6) {
360 			if (family != AF_INET6)
361 				error(1, errno, "wrong IP (v6) for family %d",
362 				      family);
363 			inet_ntop(AF_INET6, RTA_DATA(attrs), str, sizeof(str));
364 			printf("%s", str);
365 			if (port)
366 				printf(" %d", port);
367 		}
368 		if (attrs->rta_type == MPTCP_PM_ADDR_ATTR_ID) {
369 			memcpy(&id, RTA_DATA(attrs), 1);
370 			printf("id %d ", id);
371 		}
372 		if (attrs->rta_type == MPTCP_PM_ADDR_ATTR_FLAGS) {
373 			memcpy(&flags, RTA_DATA(attrs), 4);
374 
375 			printf("flags ");
376 			if (flags & MPTCP_PM_ADDR_FLAG_SIGNAL) {
377 				printf("signal");
378 				flags &= ~MPTCP_PM_ADDR_FLAG_SIGNAL;
379 				if (flags)
380 					printf(",");
381 			}
382 
383 			if (flags & MPTCP_PM_ADDR_FLAG_SUBFLOW) {
384 				printf("subflow");
385 				flags &= ~MPTCP_PM_ADDR_FLAG_SUBFLOW;
386 				if (flags)
387 					printf(",");
388 			}
389 
390 			if (flags & MPTCP_PM_ADDR_FLAG_BACKUP) {
391 				printf("backup");
392 				flags &= ~MPTCP_PM_ADDR_FLAG_BACKUP;
393 				if (flags)
394 					printf(",");
395 			}
396 
397 			/* bump unknown flags, if any */
398 			if (flags)
399 				printf("0x%x", flags);
400 			printf(" ");
401 		}
402 		if (attrs->rta_type == MPTCP_PM_ADDR_ATTR_IF_IDX) {
403 			char name[IF_NAMESIZE], *ret;
404 			int32_t ifindex;
405 
406 			memcpy(&ifindex, RTA_DATA(attrs), 4);
407 			ret = if_indextoname(ifindex, name);
408 			if (ret)
409 				printf("dev %s ", ret);
410 			else
411 				printf("dev unknown/%d", ifindex);
412 		}
413 
414 		attrs = RTA_NEXT(attrs, len);
415 	}
416 	printf("\n");
417 }
418 
419 static void print_addrs(struct nlmsghdr *nh, int pm_family, int total_len)
420 {
421 	struct rtattr *attrs;
422 
423 	for (; NLMSG_OK(nh, total_len); nh = NLMSG_NEXT(nh, total_len)) {
424 		int len = nh->nlmsg_len;
425 
426 		if (nh->nlmsg_type == NLMSG_DONE)
427 			break;
428 		if (nh->nlmsg_type == NLMSG_ERROR)
429 			nl_error(nh);
430 		if (nh->nlmsg_type != pm_family)
431 			continue;
432 
433 		len -= NLMSG_LENGTH(GENL_HDRLEN);
434 		attrs = (struct rtattr *) ((char *) NLMSG_DATA(nh) +
435 					   GENL_HDRLEN);
436 		while (RTA_OK(attrs, len)) {
437 			if (attrs->rta_type ==
438 			    (MPTCP_PM_ATTR_ADDR | NLA_F_NESTED))
439 				print_addr((void *)RTA_DATA(attrs),
440 					   attrs->rta_len);
441 			attrs = RTA_NEXT(attrs, len);
442 		}
443 	}
444 }
445 
446 int get_addr(int fd, int pm_family, int argc, char *argv[])
447 {
448 	char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
449 		  NLMSG_ALIGN(sizeof(struct genlmsghdr)) +
450 		  1024];
451 	struct rtattr *rta, *nest;
452 	struct nlmsghdr *nh;
453 	int nest_start;
454 	u_int8_t id;
455 	int off = 0;
456 
457 	memset(data, 0, sizeof(data));
458 	nh = (void *)data;
459 	off = init_genl_req(data, pm_family, MPTCP_PM_CMD_GET_ADDR,
460 			    MPTCP_PM_VER);
461 
462 	/* the only argument is the address id */
463 	if (argc != 3)
464 		syntax(argv);
465 
466 	id = atoi(argv[2]);
467 
468 	nest_start = off;
469 	nest = (void *)(data + off);
470 	nest->rta_type = NLA_F_NESTED | MPTCP_PM_ATTR_ADDR;
471 	nest->rta_len =  RTA_LENGTH(0);
472 	off += NLMSG_ALIGN(nest->rta_len);
473 
474 	/* build a dummy addr with only the ID set */
475 	rta = (void *)(data + off);
476 	rta->rta_type = MPTCP_PM_ADDR_ATTR_ID;
477 	rta->rta_len = RTA_LENGTH(1);
478 	memcpy(RTA_DATA(rta), &id, 1);
479 	off += NLMSG_ALIGN(rta->rta_len);
480 	nest->rta_len = off - nest_start;
481 
482 	print_addrs(nh, pm_family, do_nl_req(fd, nh, off, sizeof(data)));
483 	return 0;
484 }
485 
486 int dump_addrs(int fd, int pm_family, int argc, char *argv[])
487 {
488 	char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
489 		  NLMSG_ALIGN(sizeof(struct genlmsghdr)) +
490 		  1024];
491 	pid_t pid = getpid();
492 	struct nlmsghdr *nh;
493 	int off = 0;
494 
495 	memset(data, 0, sizeof(data));
496 	nh = (void *)data;
497 	off = init_genl_req(data, pm_family, MPTCP_PM_CMD_GET_ADDR,
498 			    MPTCP_PM_VER);
499 	nh->nlmsg_flags |= NLM_F_DUMP;
500 	nh->nlmsg_seq = 1;
501 	nh->nlmsg_pid = pid;
502 	nh->nlmsg_len = off;
503 
504 	print_addrs(nh, pm_family, do_nl_req(fd, nh, off, sizeof(data)));
505 	return 0;
506 }
507 
508 int flush_addrs(int fd, int pm_family, int argc, char *argv[])
509 {
510 	char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
511 		  NLMSG_ALIGN(sizeof(struct genlmsghdr)) +
512 		  1024];
513 	struct nlmsghdr *nh;
514 	int off = 0;
515 
516 	memset(data, 0, sizeof(data));
517 	nh = (void *)data;
518 	off = init_genl_req(data, pm_family, MPTCP_PM_CMD_FLUSH_ADDRS,
519 			    MPTCP_PM_VER);
520 
521 	do_nl_req(fd, nh, off, 0);
522 	return 0;
523 }
524 
525 static void print_limits(struct nlmsghdr *nh, int pm_family, int total_len)
526 {
527 	struct rtattr *attrs;
528 	uint32_t max;
529 
530 	for (; NLMSG_OK(nh, total_len); nh = NLMSG_NEXT(nh, total_len)) {
531 		int len = nh->nlmsg_len;
532 
533 		if (nh->nlmsg_type == NLMSG_DONE)
534 			break;
535 		if (nh->nlmsg_type == NLMSG_ERROR)
536 			nl_error(nh);
537 		if (nh->nlmsg_type != pm_family)
538 			continue;
539 
540 		len -= NLMSG_LENGTH(GENL_HDRLEN);
541 		attrs = (struct rtattr *) ((char *) NLMSG_DATA(nh) +
542 					   GENL_HDRLEN);
543 		while (RTA_OK(attrs, len)) {
544 			int type = attrs->rta_type;
545 
546 			if (type != MPTCP_PM_ATTR_RCV_ADD_ADDRS &&
547 			    type != MPTCP_PM_ATTR_SUBFLOWS)
548 				goto next;
549 
550 			memcpy(&max, RTA_DATA(attrs), 4);
551 			printf("%s %u\n", type == MPTCP_PM_ATTR_SUBFLOWS ?
552 					  "subflows" : "accept", max);
553 
554 next:
555 			attrs = RTA_NEXT(attrs, len);
556 		}
557 	}
558 }
559 
560 int get_set_limits(int fd, int pm_family, int argc, char *argv[])
561 {
562 	char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
563 		  NLMSG_ALIGN(sizeof(struct genlmsghdr)) +
564 		  1024];
565 	uint32_t rcv_addr = 0, subflows = 0;
566 	int cmd, len = sizeof(data);
567 	struct nlmsghdr *nh;
568 	int off = 0;
569 
570 	/* limit */
571 	if (argc == 4) {
572 		rcv_addr = atoi(argv[2]);
573 		subflows = atoi(argv[3]);
574 		cmd = MPTCP_PM_CMD_SET_LIMITS;
575 	} else {
576 		cmd = MPTCP_PM_CMD_GET_LIMITS;
577 	}
578 
579 	memset(data, 0, sizeof(data));
580 	nh = (void *)data;
581 	off = init_genl_req(data, pm_family, cmd, MPTCP_PM_VER);
582 
583 	/* limit */
584 	if (cmd == MPTCP_PM_CMD_SET_LIMITS) {
585 		struct rtattr *rta = (void *)(data + off);
586 
587 		rta->rta_type = MPTCP_PM_ATTR_RCV_ADD_ADDRS;
588 		rta->rta_len = RTA_LENGTH(4);
589 		memcpy(RTA_DATA(rta), &rcv_addr, 4);
590 		off += NLMSG_ALIGN(rta->rta_len);
591 
592 		rta = (void *)(data + off);
593 		rta->rta_type = MPTCP_PM_ATTR_SUBFLOWS;
594 		rta->rta_len = RTA_LENGTH(4);
595 		memcpy(RTA_DATA(rta), &subflows, 4);
596 		off += NLMSG_ALIGN(rta->rta_len);
597 
598 		/* do not expect a reply */
599 		len = 0;
600 	}
601 
602 	len = do_nl_req(fd, nh, off, len);
603 	if (cmd == MPTCP_PM_CMD_GET_LIMITS)
604 		print_limits(nh, pm_family, len);
605 	return 0;
606 }
607 
608 int set_flags(int fd, int pm_family, int argc, char *argv[])
609 {
610 	char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
611 		  NLMSG_ALIGN(sizeof(struct genlmsghdr)) +
612 		  1024];
613 	struct rtattr *rta, *nest;
614 	struct nlmsghdr *nh;
615 	u_int32_t flags = 0;
616 	u_int16_t family;
617 	int nest_start;
618 	int off = 0;
619 	int arg;
620 
621 	memset(data, 0, sizeof(data));
622 	nh = (void *)data;
623 	off = init_genl_req(data, pm_family, MPTCP_PM_CMD_SET_FLAGS,
624 			    MPTCP_PM_VER);
625 
626 	if (argc < 3)
627 		syntax(argv);
628 
629 	nest_start = off;
630 	nest = (void *)(data + off);
631 	nest->rta_type = NLA_F_NESTED | MPTCP_PM_ATTR_ADDR;
632 	nest->rta_len = RTA_LENGTH(0);
633 	off += NLMSG_ALIGN(nest->rta_len);
634 
635 	/* addr data */
636 	rta = (void *)(data + off);
637 	if (inet_pton(AF_INET, argv[2], RTA_DATA(rta))) {
638 		family = AF_INET;
639 		rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR4;
640 		rta->rta_len = RTA_LENGTH(4);
641 	} else if (inet_pton(AF_INET6, argv[2], RTA_DATA(rta))) {
642 		family = AF_INET6;
643 		rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR6;
644 		rta->rta_len = RTA_LENGTH(16);
645 	} else {
646 		error(1, errno, "can't parse ip %s", argv[2]);
647 	}
648 	off += NLMSG_ALIGN(rta->rta_len);
649 
650 	/* family */
651 	rta = (void *)(data + off);
652 	rta->rta_type = MPTCP_PM_ADDR_ATTR_FAMILY;
653 	rta->rta_len = RTA_LENGTH(2);
654 	memcpy(RTA_DATA(rta), &family, 2);
655 	off += NLMSG_ALIGN(rta->rta_len);
656 
657 	for (arg = 3; arg < argc; arg++) {
658 		if (!strcmp(argv[arg], "flags")) {
659 			char *tok, *str;
660 
661 			/* flags */
662 			if (++arg >= argc)
663 				error(1, 0, " missing flags value");
664 
665 			/* do not support flag list yet */
666 			for (str = argv[arg]; (tok = strtok(str, ","));
667 			     str = NULL) {
668 				if (!strcmp(tok, "backup"))
669 					flags |= MPTCP_PM_ADDR_FLAG_BACKUP;
670 				else if (strcmp(tok, "nobackup"))
671 					error(1, errno,
672 					      "unknown flag %s", argv[arg]);
673 			}
674 
675 			rta = (void *)(data + off);
676 			rta->rta_type = MPTCP_PM_ADDR_ATTR_FLAGS;
677 			rta->rta_len = RTA_LENGTH(4);
678 			memcpy(RTA_DATA(rta), &flags, 4);
679 			off += NLMSG_ALIGN(rta->rta_len);
680 		} else {
681 			error(1, 0, "unknown keyword %s", argv[arg]);
682 		}
683 	}
684 	nest->rta_len = off - nest_start;
685 
686 	do_nl_req(fd, nh, off, 0);
687 	return 0;
688 }
689 
690 int main(int argc, char *argv[])
691 {
692 	int fd, pm_family;
693 
694 	if (argc < 2)
695 		syntax(argv);
696 
697 	fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
698 	if (fd == -1)
699 		error(1, errno, "socket netlink");
700 
701 	pm_family = resolve_mptcp_pm_netlink(fd);
702 
703 	if (!strcmp(argv[1], "add"))
704 		return add_addr(fd, pm_family, argc, argv);
705 	else if (!strcmp(argv[1], "del"))
706 		return del_addr(fd, pm_family, argc, argv);
707 	else if (!strcmp(argv[1], "flush"))
708 		return flush_addrs(fd, pm_family, argc, argv);
709 	else if (!strcmp(argv[1], "get"))
710 		return get_addr(fd, pm_family, argc, argv);
711 	else if (!strcmp(argv[1], "dump"))
712 		return dump_addrs(fd, pm_family, argc, argv);
713 	else if (!strcmp(argv[1], "limits"))
714 		return get_set_limits(fd, pm_family, argc, argv);
715 	else if (!strcmp(argv[1], "set"))
716 		return set_flags(fd, pm_family, argc, argv);
717 
718 	fprintf(stderr, "unknown sub-command: %s", argv[1]);
719 	syntax(argv);
720 	return 0;
721 }
722