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