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