brintos

brintos / linux-shallow public Read only

0
0
Text · 39.9 KiB · 994a556 Raw
1548 lines · c
1// SPDX-License-Identifier: GPL-2.02 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#include <limits.h>10 11#include <sys/socket.h>12#include <sys/types.h>13 14#include <arpa/inet.h>15#include <net/if.h>16 17#include <linux/rtnetlink.h>18#include <linux/genetlink.h>19 20#include "linux/mptcp.h"21 22#ifndef IPPROTO_MPTCP23#define IPPROTO_MPTCP 26224#endif25 26static void syntax(char *argv[])27{28	fprintf(stderr, "%s add|ann|rem|csf|dsf|get|set|del|flush|dump|events|listen|accept [<args>]\n", argv[0]);29	fprintf(stderr, "\tadd [flags signal|subflow|backup|fullmesh] [id <nr>] [dev <name>] <ip>\n");30	fprintf(stderr, "\tann <local-ip> id <local-id> token <token> [port <local-port>] [dev <name>]\n");31	fprintf(stderr, "\trem id <local-id> token <token>\n");32	fprintf(stderr, "\tcsf lip <local-ip> lid <local-id> rip <remote-ip> rport <remote-port> token <token>\n");33	fprintf(stderr, "\tdsf lip <local-ip> lport <local-port> rip <remote-ip> rport <remote-port> token <token>\n");34	fprintf(stderr, "\tdel <id> [<ip>]\n");35	fprintf(stderr, "\tget <id>\n");36	fprintf(stderr, "\tset [<ip>] [id <nr>] flags [no]backup|[no]fullmesh [port <nr>] [token <token>] [rip <ip>] [rport <port>]\n");37	fprintf(stderr, "\tflush\n");38	fprintf(stderr, "\tdump\n");39	fprintf(stderr, "\tlimits [<rcv addr max> <subflow max>]\n");40	fprintf(stderr, "\tevents\n");41	fprintf(stderr, "\tlisten <local-ip> <local-port>\n");42	exit(0);43}44 45static int init_genl_req(char *data, int family, int cmd, int version)46{47	struct nlmsghdr *nh = (void *)data;48	struct genlmsghdr *gh;49	int off = 0;50 51	nh->nlmsg_type = family;52	nh->nlmsg_flags = NLM_F_REQUEST;53	nh->nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);54	off += NLMSG_ALIGN(sizeof(*nh));55 56	gh = (void *)(data + off);57	gh->cmd = cmd;58	gh->version = version;59	off += NLMSG_ALIGN(sizeof(*gh));60	return off;61}62 63static int nl_error(struct nlmsghdr *nh)64{65	struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(nh);66	int len = nh->nlmsg_len - sizeof(*nh);67	uint32_t off;68 69	if (len < sizeof(struct nlmsgerr)) {70		error(1, 0, "netlink error message truncated %d min %ld", len,71		      sizeof(struct nlmsgerr));72		return -1;73	}74 75	if (err->error) {76		/* check messages from kernel */77		struct rtattr *attrs = (struct rtattr *)NLMSG_DATA(nh);78 79		fprintf(stderr, "netlink error %d (%s)\n",80			err->error, strerror(-err->error));81 82		while (RTA_OK(attrs, len)) {83			if (attrs->rta_type == NLMSGERR_ATTR_MSG)84				fprintf(stderr, "netlink ext ack msg: %s\n",85					(char *)RTA_DATA(attrs));86			if (attrs->rta_type == NLMSGERR_ATTR_OFFS) {87				memcpy(&off, RTA_DATA(attrs), 4);88				fprintf(stderr, "netlink err off %d\n",89					(int)off);90			}91			attrs = RTA_NEXT(attrs, len);92		}93		return -1;94	}95 96	return 0;97}98 99static int capture_events(int fd, int event_group)100{101	u_int8_t buffer[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +102			NLMSG_ALIGN(sizeof(struct genlmsghdr)) + 1024];103	struct genlmsghdr *ghdr;104	struct rtattr *attrs;105	struct nlmsghdr *nh;106	int ret = 0;107	int res_len;108	int msg_len;109	fd_set rfds;110 111	if (setsockopt(fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP,112		       &event_group, sizeof(event_group)) < 0)113		error(1, errno, "could not join the " MPTCP_PM_EV_GRP_NAME " mcast group");114 115	do {116		FD_ZERO(&rfds);117		FD_SET(fd, &rfds);118		res_len = NLMSG_ALIGN(sizeof(struct nlmsghdr)) +119		  NLMSG_ALIGN(sizeof(struct genlmsghdr)) + 1024;120 121		ret = select(FD_SETSIZE, &rfds, NULL, NULL, NULL);122 123		if (ret < 0)124			error(1, ret, "error in select() on NL socket");125 126		res_len = recv(fd, buffer, res_len, 0);127		if (res_len < 0)128			error(1, res_len, "error on recv() from NL socket");129 130		nh = (struct nlmsghdr *)buffer;131 132		for (; NLMSG_OK(nh, res_len); nh = NLMSG_NEXT(nh, res_len)) {133			if (nh->nlmsg_type == NLMSG_ERROR)134				error(1, NLMSG_ERROR, "received invalid NL message");135 136			ghdr = (struct genlmsghdr *)NLMSG_DATA(nh);137 138			if (ghdr->cmd == 0)139				continue;140 141			fprintf(stderr, "type:%d", ghdr->cmd);142 143			msg_len = nh->nlmsg_len - NLMSG_LENGTH(GENL_HDRLEN);144 145			attrs = (struct rtattr *) ((char *) ghdr + GENL_HDRLEN);146			while (RTA_OK(attrs, msg_len)) {147				if (attrs->rta_type == MPTCP_ATTR_TOKEN)148					fprintf(stderr, ",token:%u", *(__u32 *)RTA_DATA(attrs));149				else if (attrs->rta_type == MPTCP_ATTR_FAMILY)150					fprintf(stderr, ",family:%u", *(__u16 *)RTA_DATA(attrs));151				else if (attrs->rta_type == MPTCP_ATTR_LOC_ID)152					fprintf(stderr, ",loc_id:%u", *(__u8 *)RTA_DATA(attrs));153				else if (attrs->rta_type == MPTCP_ATTR_REM_ID)154					fprintf(stderr, ",rem_id:%u", *(__u8 *)RTA_DATA(attrs));155				else if (attrs->rta_type == MPTCP_ATTR_SADDR4) {156					u_int32_t saddr4 = ntohl(*(__u32 *)RTA_DATA(attrs));157 158					fprintf(stderr, ",saddr4:%u.%u.%u.%u", saddr4 >> 24,159					       (saddr4 >> 16) & 0xFF, (saddr4 >> 8) & 0xFF,160					       (saddr4 & 0xFF));161				} else if (attrs->rta_type == MPTCP_ATTR_SADDR6) {162					char buf[INET6_ADDRSTRLEN];163 164					if (inet_ntop(AF_INET6, RTA_DATA(attrs), buf,165						      sizeof(buf)) != NULL)166						fprintf(stderr, ",saddr6:%s", buf);167				} else if (attrs->rta_type == MPTCP_ATTR_DADDR4) {168					u_int32_t daddr4 = ntohl(*(__u32 *)RTA_DATA(attrs));169 170					fprintf(stderr, ",daddr4:%u.%u.%u.%u", daddr4 >> 24,171					       (daddr4 >> 16) & 0xFF, (daddr4 >> 8) & 0xFF,172					       (daddr4 & 0xFF));173				} else if (attrs->rta_type == MPTCP_ATTR_DADDR6) {174					char buf[INET6_ADDRSTRLEN];175 176					if (inet_ntop(AF_INET6, RTA_DATA(attrs), buf,177						      sizeof(buf)) != NULL)178						fprintf(stderr, ",daddr6:%s", buf);179				} else if (attrs->rta_type == MPTCP_ATTR_SPORT)180					fprintf(stderr, ",sport:%u",181						ntohs(*(__u16 *)RTA_DATA(attrs)));182				else if (attrs->rta_type == MPTCP_ATTR_DPORT)183					fprintf(stderr, ",dport:%u",184						ntohs(*(__u16 *)RTA_DATA(attrs)));185				else if (attrs->rta_type == MPTCP_ATTR_BACKUP)186					fprintf(stderr, ",backup:%u", *(__u8 *)RTA_DATA(attrs));187				else if (attrs->rta_type == MPTCP_ATTR_ERROR)188					fprintf(stderr, ",error:%u", *(__u8 *)RTA_DATA(attrs));189				else if (attrs->rta_type == MPTCP_ATTR_SERVER_SIDE)190					fprintf(stderr, ",server_side:%u", *(__u8 *)RTA_DATA(attrs));191 192				attrs = RTA_NEXT(attrs, msg_len);193			}194		}195		fprintf(stderr, "\n");196	} while (1);197 198	return 0;199}200 201/* do a netlink command and, if max > 0, fetch the reply ; nh's size >1024B */202static int do_nl_req(int fd, struct nlmsghdr *nh, int len, int max)203{204	struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK };205	socklen_t addr_len;206	void *data = nh;207	int rem, ret;208	int err = 0;209 210	/* If no expected answer, ask for an ACK to look for errors if any */211	if (max == 0) {212		nh->nlmsg_flags |= NLM_F_ACK;213		max = 1024;214	}215 216	nh->nlmsg_len = len;217	ret = sendto(fd, data, len, 0, (void *)&nladdr, sizeof(nladdr));218	if (ret != len)219		error(1, errno, "send netlink: %uB != %uB\n", ret, len);220 221	addr_len = sizeof(nladdr);222	rem = ret = recvfrom(fd, data, max, 0, (void *)&nladdr, &addr_len);223	if (ret < 0)224		error(1, errno, "recv netlink: %uB\n", ret);225 226	/* Beware: the NLMSG_NEXT macro updates the 'rem' argument */227	for (; NLMSG_OK(nh, rem); nh = NLMSG_NEXT(nh, rem)) {228		if (nh->nlmsg_type == NLMSG_DONE)229			break;230 231		if (nh->nlmsg_type == NLMSG_ERROR && nl_error(nh))232			err = 1;233	}234	if (err)235		error(1, 0, "bailing out due to netlink error[s]");236	return ret;237}238 239static int genl_parse_getfamily(struct nlmsghdr *nlh, int *pm_family,240				int *events_mcast_grp)241{242	struct genlmsghdr *ghdr = NLMSG_DATA(nlh);243	int len = nlh->nlmsg_len;244	struct rtattr *attrs;245	struct rtattr *grps;246	struct rtattr *grp;247	int got_events_grp;248	int got_family;249	int grps_len;250	int grp_len;251 252	if (nlh->nlmsg_type != GENL_ID_CTRL)253		error(1, errno, "Not a controller message, len=%d type=0x%x\n",254		      nlh->nlmsg_len, nlh->nlmsg_type);255 256	len -= NLMSG_LENGTH(GENL_HDRLEN);257 258	if (len < 0)259		error(1, errno, "wrong controller message len %d\n", len);260 261	if (ghdr->cmd != CTRL_CMD_NEWFAMILY)262		error(1, errno, "Unknown controller command %d\n", ghdr->cmd);263 264	attrs = (struct rtattr *) ((char *) ghdr + GENL_HDRLEN);265	got_family = 0;266	got_events_grp = 0;267 268	while (RTA_OK(attrs, len)) {269		if (attrs->rta_type == CTRL_ATTR_FAMILY_ID) {270			*pm_family = *(__u16 *)RTA_DATA(attrs);271			got_family = 1;272		} else if (attrs->rta_type == CTRL_ATTR_MCAST_GROUPS) {273			grps = RTA_DATA(attrs);274			grps_len = RTA_PAYLOAD(attrs);275 276			while (RTA_OK(grps, grps_len)) {277				grp = RTA_DATA(grps);278				grp_len = RTA_PAYLOAD(grps);279				got_events_grp = 0;280 281				while (RTA_OK(grp, grp_len)) {282					if (grp->rta_type == CTRL_ATTR_MCAST_GRP_ID)283						*events_mcast_grp = *(__u32 *)RTA_DATA(grp);284					else if (grp->rta_type == CTRL_ATTR_MCAST_GRP_NAME &&285						 !strcmp(RTA_DATA(grp), MPTCP_PM_EV_GRP_NAME))286						got_events_grp = 1;287 288					grp = RTA_NEXT(grp, grp_len);289				}290 291				if (got_events_grp)292					break;293 294				grps = RTA_NEXT(grps, grps_len);295			}296		}297 298		if (got_family && got_events_grp)299			return 0;300 301		attrs = RTA_NEXT(attrs, len);302	}303 304	error(1, errno, "can't find CTRL_ATTR_FAMILY_ID attr");305	return -1;306}307 308static int resolve_mptcp_pm_netlink(int fd, int *pm_family, int *events_mcast_grp)309{310	char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +311		  NLMSG_ALIGN(sizeof(struct genlmsghdr)) +312		  1024];313	struct nlmsghdr *nh;314	struct rtattr *rta;315	int namelen;316	int off = 0;317 318	memset(data, 0, sizeof(data));319	nh = (void *)data;320	off = init_genl_req(data, GENL_ID_CTRL, CTRL_CMD_GETFAMILY, 0);321 322	rta = (void *)(data + off);323	namelen = strlen(MPTCP_PM_NAME) + 1;324	rta->rta_type = CTRL_ATTR_FAMILY_NAME;325	rta->rta_len = RTA_LENGTH(namelen);326	memcpy(RTA_DATA(rta), MPTCP_PM_NAME, namelen);327	off += NLMSG_ALIGN(rta->rta_len);328 329	do_nl_req(fd, nh, off, sizeof(data));330	return genl_parse_getfamily((void *)data, pm_family, events_mcast_grp);331}332 333int dsf(int fd, int pm_family, int argc, char *argv[])334{335	char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +336		  NLMSG_ALIGN(sizeof(struct genlmsghdr)) +337		  1024];338	struct rtattr *rta, *addr;339	u_int16_t family, port;340	struct nlmsghdr *nh;341	u_int32_t token;342	int addr_start;343	int off = 0;344	int arg;345 346	const char *params[5];347 348	memset(params, 0, 5 * sizeof(const char *));349 350	memset(data, 0, sizeof(data));351	nh = (void *)data;352	off = init_genl_req(data, pm_family, MPTCP_PM_CMD_SUBFLOW_DESTROY,353			    MPTCP_PM_VER);354 355	if (argc < 12)356		syntax(argv);357 358	/* Params recorded in this order:359	 * <local-ip>, <local-port>, <remote-ip>, <remote-port>, <token>360	 */361	for (arg = 2; arg < argc; arg++) {362		if (!strcmp(argv[arg], "lip")) {363			if (++arg >= argc)364				error(1, 0, " missing local IP");365 366			params[0] = argv[arg];367		} else if (!strcmp(argv[arg], "lport")) {368			if (++arg >= argc)369				error(1, 0, " missing local port");370 371			params[1] = argv[arg];372		} else if (!strcmp(argv[arg], "rip")) {373			if (++arg >= argc)374				error(1, 0, " missing remote IP");375 376			params[2] = argv[arg];377		} else if (!strcmp(argv[arg], "rport")) {378			if (++arg >= argc)379				error(1, 0, " missing remote port");380 381			params[3] = argv[arg];382		} else if (!strcmp(argv[arg], "token")) {383			if (++arg >= argc)384				error(1, 0, " missing token");385 386			params[4] = argv[arg];387		} else388			error(1, 0, "unknown keyword %s", argv[arg]);389	}390 391	for (arg = 0; arg < 4; arg = arg + 2) {392		/*  addr header */393		addr_start = off;394		addr = (void *)(data + off);395		addr->rta_type = NLA_F_NESTED |396			((arg == 0) ? MPTCP_PM_ATTR_ADDR : MPTCP_PM_ATTR_ADDR_REMOTE);397		addr->rta_len = RTA_LENGTH(0);398		off += NLMSG_ALIGN(addr->rta_len);399 400		/*  addr data */401		rta = (void *)(data + off);402		if (inet_pton(AF_INET, params[arg], RTA_DATA(rta))) {403			family = AF_INET;404			rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR4;405			rta->rta_len = RTA_LENGTH(4);406		} else if (inet_pton(AF_INET6, params[arg], RTA_DATA(rta))) {407			family = AF_INET6;408			rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR6;409			rta->rta_len = RTA_LENGTH(16);410		} else411			error(1, errno, "can't parse ip %s", params[arg]);412		off += NLMSG_ALIGN(rta->rta_len);413 414		/* family */415		rta = (void *)(data + off);416		rta->rta_type = MPTCP_PM_ADDR_ATTR_FAMILY;417		rta->rta_len = RTA_LENGTH(2);418		memcpy(RTA_DATA(rta), &family, 2);419		off += NLMSG_ALIGN(rta->rta_len);420 421		/*  port */422		port = atoi(params[arg + 1]);423		rta = (void *)(data + off);424		rta->rta_type = MPTCP_PM_ADDR_ATTR_PORT;425		rta->rta_len = RTA_LENGTH(2);426		memcpy(RTA_DATA(rta), &port, 2);427		off += NLMSG_ALIGN(rta->rta_len);428 429		addr->rta_len = off - addr_start;430	}431 432	/* token */433	token = strtoul(params[4], NULL, 10);434	rta = (void *)(data + off);435	rta->rta_type = MPTCP_PM_ATTR_TOKEN;436	rta->rta_len = RTA_LENGTH(4);437	memcpy(RTA_DATA(rta), &token, 4);438	off += NLMSG_ALIGN(rta->rta_len);439 440	do_nl_req(fd, nh, off, 0);441 442	return 0;443}444 445int csf(int fd, int pm_family, int argc, char *argv[])446{447	char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +448		  NLMSG_ALIGN(sizeof(struct genlmsghdr)) +449		  1024];450	u_int32_t flags = MPTCP_PM_ADDR_FLAG_SUBFLOW;451	const char *params[5];452	struct nlmsghdr *nh;453	struct rtattr *addr;454	struct rtattr *rta;455	u_int16_t family;456	u_int32_t token;457	u_int16_t port;458	int addr_start;459	u_int8_t id;460	int off = 0;461	int arg;462 463	memset(params, 0, 5 * sizeof(const char *));464 465	memset(data, 0, sizeof(data));466	nh = (void *)data;467	off = init_genl_req(data, pm_family, MPTCP_PM_CMD_SUBFLOW_CREATE,468			    MPTCP_PM_VER);469 470	if (argc < 12)471		syntax(argv);472 473	/* Params recorded in this order:474	 * <local-ip>, <local-id>, <remote-ip>, <remote-port>, <token>475	 */476	for (arg = 2; arg < argc; arg++) {477		if (!strcmp(argv[arg], "lip")) {478			if (++arg >= argc)479				error(1, 0, " missing local IP");480 481			params[0] = argv[arg];482		} else if (!strcmp(argv[arg], "lid")) {483			if (++arg >= argc)484				error(1, 0, " missing local id");485 486			params[1] = argv[arg];487		} else if (!strcmp(argv[arg], "rip")) {488			if (++arg >= argc)489				error(1, 0, " missing remote ip");490 491			params[2] = argv[arg];492		} else if (!strcmp(argv[arg], "rport")) {493			if (++arg >= argc)494				error(1, 0, " missing remote port");495 496			params[3] = argv[arg];497		} else if (!strcmp(argv[arg], "token")) {498			if (++arg >= argc)499				error(1, 0, " missing token");500 501			params[4] = argv[arg];502		} else503			error(1, 0, "unknown param %s", argv[arg]);504	}505 506	for (arg = 0; arg < 4; arg = arg + 2) {507		/*  addr header */508		addr_start = off;509		addr = (void *)(data + off);510		addr->rta_type = NLA_F_NESTED |511			((arg == 0) ? MPTCP_PM_ATTR_ADDR : MPTCP_PM_ATTR_ADDR_REMOTE);512		addr->rta_len = RTA_LENGTH(0);513		off += NLMSG_ALIGN(addr->rta_len);514 515		/*  addr data */516		rta = (void *)(data + off);517		if (inet_pton(AF_INET, params[arg], RTA_DATA(rta))) {518			family = AF_INET;519			rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR4;520			rta->rta_len = RTA_LENGTH(4);521		} else if (inet_pton(AF_INET6, params[arg], RTA_DATA(rta))) {522			family = AF_INET6;523			rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR6;524			rta->rta_len = RTA_LENGTH(16);525		} else526			error(1, errno, "can't parse ip %s", params[arg]);527		off += NLMSG_ALIGN(rta->rta_len);528 529		/* family */530		rta = (void *)(data + off);531		rta->rta_type = MPTCP_PM_ADDR_ATTR_FAMILY;532		rta->rta_len = RTA_LENGTH(2);533		memcpy(RTA_DATA(rta), &family, 2);534		off += NLMSG_ALIGN(rta->rta_len);535 536		if (arg == 2) {537			/*  port */538			port = atoi(params[arg + 1]);539			rta = (void *)(data + off);540			rta->rta_type = MPTCP_PM_ADDR_ATTR_PORT;541			rta->rta_len = RTA_LENGTH(2);542			memcpy(RTA_DATA(rta), &port, 2);543			off += NLMSG_ALIGN(rta->rta_len);544		}545 546		if (arg == 0) {547			/* id */548			id = atoi(params[arg + 1]);549			rta = (void *)(data + off);550			rta->rta_type = MPTCP_PM_ADDR_ATTR_ID;551			rta->rta_len = RTA_LENGTH(1);552			memcpy(RTA_DATA(rta), &id, 1);553			off += NLMSG_ALIGN(rta->rta_len);554		}555 556		/* addr flags */557		rta = (void *)(data + off);558		rta->rta_type = MPTCP_PM_ADDR_ATTR_FLAGS;559		rta->rta_len = RTA_LENGTH(4);560		memcpy(RTA_DATA(rta), &flags, 4);561		off += NLMSG_ALIGN(rta->rta_len);562 563		addr->rta_len = off - addr_start;564	}565 566	/* token */567	token = strtoul(params[4], NULL, 10);568	rta = (void *)(data + off);569	rta->rta_type = MPTCP_PM_ATTR_TOKEN;570	rta->rta_len = RTA_LENGTH(4);571	memcpy(RTA_DATA(rta), &token, 4);572	off += NLMSG_ALIGN(rta->rta_len);573 574	do_nl_req(fd, nh, off, 0);575 576	return 0;577}578 579int remove_addr(int fd, int pm_family, int argc, char *argv[])580{581	char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +582		  NLMSG_ALIGN(sizeof(struct genlmsghdr)) +583		  1024];584	struct nlmsghdr *nh;585	struct rtattr *rta;586	u_int32_t token;587	u_int8_t id;588	int off = 0;589	int arg;590 591	memset(data, 0, sizeof(data));592	nh = (void *)data;593	off = init_genl_req(data, pm_family, MPTCP_PM_CMD_REMOVE,594			    MPTCP_PM_VER);595 596	if (argc < 6)597		syntax(argv);598 599	for (arg = 2; arg < argc; arg++) {600		if (!strcmp(argv[arg], "id")) {601			if (++arg >= argc)602				error(1, 0, " missing id value");603 604			id = atoi(argv[arg]);605			rta = (void *)(data + off);606			rta->rta_type = MPTCP_PM_ATTR_LOC_ID;607			rta->rta_len = RTA_LENGTH(1);608			memcpy(RTA_DATA(rta), &id, 1);609			off += NLMSG_ALIGN(rta->rta_len);610		} else if (!strcmp(argv[arg], "token")) {611			if (++arg >= argc)612				error(1, 0, " missing token value");613 614			token = strtoul(argv[arg], NULL, 10);615			rta = (void *)(data + off);616			rta->rta_type = MPTCP_PM_ATTR_TOKEN;617			rta->rta_len = RTA_LENGTH(4);618			memcpy(RTA_DATA(rta), &token, 4);619			off += NLMSG_ALIGN(rta->rta_len);620		} else621			error(1, 0, "unknown keyword %s", argv[arg]);622	}623 624	do_nl_req(fd, nh, off, 0);625	return 0;626}627 628int announce_addr(int fd, int pm_family, int argc, char *argv[])629{630	char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +631		  NLMSG_ALIGN(sizeof(struct genlmsghdr)) +632		  1024];633	u_int32_t flags = MPTCP_PM_ADDR_FLAG_SIGNAL;634	u_int32_t token = UINT_MAX;635	struct rtattr *rta, *addr;636	u_int32_t id = UINT_MAX;637	struct nlmsghdr *nh;638	u_int16_t family;639	int addr_start;640	int off = 0;641	int arg;642 643	memset(data, 0, sizeof(data));644	nh = (void *)data;645	off = init_genl_req(data, pm_family, MPTCP_PM_CMD_ANNOUNCE,646			    MPTCP_PM_VER);647 648	if (argc < 7)649		syntax(argv);650 651	/* local-ip header */652	addr_start = off;653	addr = (void *)(data + off);654	addr->rta_type = NLA_F_NESTED | MPTCP_PM_ATTR_ADDR;655	addr->rta_len = RTA_LENGTH(0);656	off += NLMSG_ALIGN(addr->rta_len);657 658	/* local-ip data */659	/* record addr type */660	rta = (void *)(data + off);661	if (inet_pton(AF_INET, argv[2], RTA_DATA(rta))) {662		family = AF_INET;663		rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR4;664		rta->rta_len = RTA_LENGTH(4);665	} else if (inet_pton(AF_INET6, argv[2], RTA_DATA(rta))) {666		family = AF_INET6;667		rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR6;668		rta->rta_len = RTA_LENGTH(16);669	} else670		error(1, errno, "can't parse ip %s", argv[2]);671	off += NLMSG_ALIGN(rta->rta_len);672 673	/* addr family */674	rta = (void *)(data + off);675	rta->rta_type = MPTCP_PM_ADDR_ATTR_FAMILY;676	rta->rta_len = RTA_LENGTH(2);677	memcpy(RTA_DATA(rta), &family, 2);678	off += NLMSG_ALIGN(rta->rta_len);679 680	for (arg = 3; arg < argc; arg++) {681		if (!strcmp(argv[arg], "id")) {682			/* local-id */683			if (++arg >= argc)684				error(1, 0, " missing id value");685 686			id = atoi(argv[arg]);687			rta = (void *)(data + off);688			rta->rta_type = MPTCP_PM_ADDR_ATTR_ID;689			rta->rta_len = RTA_LENGTH(1);690			memcpy(RTA_DATA(rta), &id, 1);691			off += NLMSG_ALIGN(rta->rta_len);692		} else if (!strcmp(argv[arg], "dev")) {693			/* for the if_index */694			int32_t ifindex;695 696			if (++arg >= argc)697				error(1, 0, " missing dev name");698 699			ifindex = if_nametoindex(argv[arg]);700			if (!ifindex)701				error(1, errno, "unknown device %s", argv[arg]);702 703			rta = (void *)(data + off);704			rta->rta_type = MPTCP_PM_ADDR_ATTR_IF_IDX;705			rta->rta_len = RTA_LENGTH(4);706			memcpy(RTA_DATA(rta), &ifindex, 4);707			off += NLMSG_ALIGN(rta->rta_len);708		} else if (!strcmp(argv[arg], "port")) {709			/* local-port (optional) */710			u_int16_t port;711 712			if (++arg >= argc)713				error(1, 0, " missing port value");714 715			port = atoi(argv[arg]);716			rta = (void *)(data + off);717			rta->rta_type = MPTCP_PM_ADDR_ATTR_PORT;718			rta->rta_len = RTA_LENGTH(2);719			memcpy(RTA_DATA(rta), &port, 2);720			off += NLMSG_ALIGN(rta->rta_len);721		} else if (!strcmp(argv[arg], "token")) {722			/* MPTCP connection token */723			if (++arg >= argc)724				error(1, 0, " missing token value");725 726			token = strtoul(argv[arg], NULL, 10);727		} else728			error(1, 0, "unknown keyword %s", argv[arg]);729	}730 731	/* addr flags */732	rta = (void *)(data + off);733	rta->rta_type = MPTCP_PM_ADDR_ATTR_FLAGS;734	rta->rta_len = RTA_LENGTH(4);735	memcpy(RTA_DATA(rta), &flags, 4);736	off += NLMSG_ALIGN(rta->rta_len);737 738	addr->rta_len = off - addr_start;739 740	if (id == UINT_MAX || token == UINT_MAX)741		error(1, 0, " missing mandatory inputs");742 743	/* token */744	rta = (void *)(data + off);745	rta->rta_type = MPTCP_PM_ATTR_TOKEN;746	rta->rta_len = RTA_LENGTH(4);747	memcpy(RTA_DATA(rta), &token, 4);748	off += NLMSG_ALIGN(rta->rta_len);749 750	do_nl_req(fd, nh, off, 0);751 752	return 0;753}754 755int add_addr(int fd, int pm_family, int argc, char *argv[])756{757	char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +758		  NLMSG_ALIGN(sizeof(struct genlmsghdr)) +759		  1024];760	struct rtattr *rta, *nest;761	struct nlmsghdr *nh;762	u_int32_t flags = 0;763	u_int16_t family;764	int nest_start;765	u_int8_t id;766	int off = 0;767	int arg;768 769	memset(data, 0, sizeof(data));770	nh = (void *)data;771	off = init_genl_req(data, pm_family, MPTCP_PM_CMD_ADD_ADDR,772			    MPTCP_PM_VER);773 774	if (argc < 3)775		syntax(argv);776 777	nest_start = off;778	nest = (void *)(data + off);779	nest->rta_type = NLA_F_NESTED | MPTCP_PM_ATTR_ADDR;780	nest->rta_len = RTA_LENGTH(0);781	off += NLMSG_ALIGN(nest->rta_len);782 783	/* addr data */784	rta = (void *)(data + off);785	if (inet_pton(AF_INET, argv[2], RTA_DATA(rta))) {786		family = AF_INET;787		rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR4;788		rta->rta_len = RTA_LENGTH(4);789	} else if (inet_pton(AF_INET6, argv[2], RTA_DATA(rta))) {790		family = AF_INET6;791		rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR6;792		rta->rta_len = RTA_LENGTH(16);793	} else794		error(1, errno, "can't parse ip %s", argv[2]);795	off += NLMSG_ALIGN(rta->rta_len);796 797	/* family */798	rta = (void *)(data + off);799	rta->rta_type = MPTCP_PM_ADDR_ATTR_FAMILY;800	rta->rta_len = RTA_LENGTH(2);801	memcpy(RTA_DATA(rta), &family, 2);802	off += NLMSG_ALIGN(rta->rta_len);803 804	for (arg = 3; arg < argc; arg++) {805		if (!strcmp(argv[arg], "flags")) {806			char *tok, *str;807 808			/* flags */809			if (++arg >= argc)810				error(1, 0, " missing flags value");811 812			/* do not support flag list yet */813			for (str = argv[arg]; (tok = strtok(str, ","));814			     str = NULL) {815				if (!strcmp(tok, "subflow"))816					flags |= MPTCP_PM_ADDR_FLAG_SUBFLOW;817				else if (!strcmp(tok, "signal"))818					flags |= MPTCP_PM_ADDR_FLAG_SIGNAL;819				else if (!strcmp(tok, "backup"))820					flags |= MPTCP_PM_ADDR_FLAG_BACKUP;821				else if (!strcmp(tok, "fullmesh"))822					flags |= MPTCP_PM_ADDR_FLAG_FULLMESH;823				else824					error(1, errno,825					      "unknown flag %s", argv[arg]);826			}827 828			if (flags & MPTCP_PM_ADDR_FLAG_SIGNAL &&829			    flags & MPTCP_PM_ADDR_FLAG_FULLMESH) {830				error(1, errno, "error flag fullmesh");831			}832 833			rta = (void *)(data + off);834			rta->rta_type = MPTCP_PM_ADDR_ATTR_FLAGS;835			rta->rta_len = RTA_LENGTH(4);836			memcpy(RTA_DATA(rta), &flags, 4);837			off += NLMSG_ALIGN(rta->rta_len);838		} else if (!strcmp(argv[arg], "id")) {839			if (++arg >= argc)840				error(1, 0, " missing id value");841 842			id = atoi(argv[arg]);843			rta = (void *)(data + off);844			rta->rta_type = MPTCP_PM_ADDR_ATTR_ID;845			rta->rta_len = RTA_LENGTH(1);846			memcpy(RTA_DATA(rta), &id, 1);847			off += NLMSG_ALIGN(rta->rta_len);848		} else if (!strcmp(argv[arg], "dev")) {849			int32_t ifindex;850 851			if (++arg >= argc)852				error(1, 0, " missing dev name");853 854			ifindex = if_nametoindex(argv[arg]);855			if (!ifindex)856				error(1, errno, "unknown device %s", argv[arg]);857 858			rta = (void *)(data + off);859			rta->rta_type = MPTCP_PM_ADDR_ATTR_IF_IDX;860			rta->rta_len = RTA_LENGTH(4);861			memcpy(RTA_DATA(rta), &ifindex, 4);862			off += NLMSG_ALIGN(rta->rta_len);863		} else if (!strcmp(argv[arg], "port")) {864			u_int16_t port;865 866			if (++arg >= argc)867				error(1, 0, " missing port value");868			if (!(flags & MPTCP_PM_ADDR_FLAG_SIGNAL))869				error(1, 0, " flags must be signal when using port");870 871			port = atoi(argv[arg]);872			rta = (void *)(data + off);873			rta->rta_type = MPTCP_PM_ADDR_ATTR_PORT;874			rta->rta_len = RTA_LENGTH(2);875			memcpy(RTA_DATA(rta), &port, 2);876			off += NLMSG_ALIGN(rta->rta_len);877		} else878			error(1, 0, "unknown keyword %s", argv[arg]);879	}880	nest->rta_len = off - nest_start;881 882	do_nl_req(fd, nh, off, 0);883	return 0;884}885 886int del_addr(int fd, int pm_family, int argc, char *argv[])887{888	char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +889		  NLMSG_ALIGN(sizeof(struct genlmsghdr)) +890		  1024];891	struct rtattr *rta, *nest;892	struct nlmsghdr *nh;893	u_int16_t family;894	int nest_start;895	u_int8_t id;896	int off = 0;897 898	memset(data, 0, sizeof(data));899	nh = (void *)data;900	off = init_genl_req(data, pm_family, MPTCP_PM_CMD_DEL_ADDR,901			    MPTCP_PM_VER);902 903	/* the only argument is the address id (nonzero) */904	if (argc != 3 && argc != 4)905		syntax(argv);906 907	id = atoi(argv[2]);908	/* zero id with the IP address */909	if (!id && argc != 4)910		syntax(argv);911 912	nest_start = off;913	nest = (void *)(data + off);914	nest->rta_type = NLA_F_NESTED | MPTCP_PM_ATTR_ADDR;915	nest->rta_len =  RTA_LENGTH(0);916	off += NLMSG_ALIGN(nest->rta_len);917 918	/* build a dummy addr with only the ID set */919	rta = (void *)(data + off);920	rta->rta_type = MPTCP_PM_ADDR_ATTR_ID;921	rta->rta_len = RTA_LENGTH(1);922	memcpy(RTA_DATA(rta), &id, 1);923	off += NLMSG_ALIGN(rta->rta_len);924 925	if (!id) {926		/* addr data */927		rta = (void *)(data + off);928		if (inet_pton(AF_INET, argv[3], RTA_DATA(rta))) {929			family = AF_INET;930			rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR4;931			rta->rta_len = RTA_LENGTH(4);932		} else if (inet_pton(AF_INET6, argv[3], RTA_DATA(rta))) {933			family = AF_INET6;934			rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR6;935			rta->rta_len = RTA_LENGTH(16);936		} else {937			error(1, errno, "can't parse ip %s", argv[3]);938		}939		off += NLMSG_ALIGN(rta->rta_len);940 941		/* family */942		rta = (void *)(data + off);943		rta->rta_type = MPTCP_PM_ADDR_ATTR_FAMILY;944		rta->rta_len = RTA_LENGTH(2);945		memcpy(RTA_DATA(rta), &family, 2);946		off += NLMSG_ALIGN(rta->rta_len);947	}948	nest->rta_len = off - nest_start;949 950	do_nl_req(fd, nh, off, 0);951	return 0;952}953 954static void print_addr(struct rtattr *attrs, int len)955{956	uint16_t family = 0;957	uint16_t port = 0;958	char str[1024];959	uint32_t flags;960	uint8_t id;961 962	while (RTA_OK(attrs, len)) {963		if (attrs->rta_type == MPTCP_PM_ADDR_ATTR_FAMILY)964			memcpy(&family, RTA_DATA(attrs), 2);965		if (attrs->rta_type == MPTCP_PM_ADDR_ATTR_PORT)966			memcpy(&port, RTA_DATA(attrs), 2);967		if (attrs->rta_type == MPTCP_PM_ADDR_ATTR_ADDR4) {968			if (family != AF_INET)969				error(1, errno, "wrong IP (v4) for family %d",970				      family);971			inet_ntop(AF_INET, RTA_DATA(attrs), str, sizeof(str));972			printf("%s", str);973			if (port)974				printf(" %d", port);975		}976		if (attrs->rta_type == MPTCP_PM_ADDR_ATTR_ADDR6) {977			if (family != AF_INET6)978				error(1, errno, "wrong IP (v6) for family %d",979				      family);980			inet_ntop(AF_INET6, RTA_DATA(attrs), str, sizeof(str));981			printf("%s", str);982			if (port)983				printf(" %d", port);984		}985		if (attrs->rta_type == MPTCP_PM_ADDR_ATTR_ID) {986			memcpy(&id, RTA_DATA(attrs), 1);987			printf("id %d ", id);988		}989		if (attrs->rta_type == MPTCP_PM_ADDR_ATTR_FLAGS) {990			memcpy(&flags, RTA_DATA(attrs), 4);991 992			printf("flags ");993			if (flags & MPTCP_PM_ADDR_FLAG_SIGNAL) {994				printf("signal");995				flags &= ~MPTCP_PM_ADDR_FLAG_SIGNAL;996				if (flags)997					printf(",");998			}999 1000			if (flags & MPTCP_PM_ADDR_FLAG_SUBFLOW) {1001				printf("subflow");1002				flags &= ~MPTCP_PM_ADDR_FLAG_SUBFLOW;1003				if (flags)1004					printf(",");1005			}1006 1007			if (flags & MPTCP_PM_ADDR_FLAG_BACKUP) {1008				printf("backup");1009				flags &= ~MPTCP_PM_ADDR_FLAG_BACKUP;1010				if (flags)1011					printf(",");1012			}1013 1014			if (flags & MPTCP_PM_ADDR_FLAG_FULLMESH) {1015				printf("fullmesh");1016				flags &= ~MPTCP_PM_ADDR_FLAG_FULLMESH;1017				if (flags)1018					printf(",");1019			}1020 1021			if (flags & MPTCP_PM_ADDR_FLAG_IMPLICIT) {1022				printf("implicit");1023				flags &= ~MPTCP_PM_ADDR_FLAG_IMPLICIT;1024				if (flags)1025					printf(",");1026			}1027 1028			/* bump unknown flags, if any */1029			if (flags)1030				printf("0x%x", flags);1031			printf(" ");1032		}1033		if (attrs->rta_type == MPTCP_PM_ADDR_ATTR_IF_IDX) {1034			char name[IF_NAMESIZE], *ret;1035			int32_t ifindex;1036 1037			memcpy(&ifindex, RTA_DATA(attrs), 4);1038			ret = if_indextoname(ifindex, name);1039			if (ret)1040				printf("dev %s ", ret);1041			else1042				printf("dev unknown/%d", ifindex);1043		}1044 1045		attrs = RTA_NEXT(attrs, len);1046	}1047	printf("\n");1048}1049 1050static void print_addrs(struct nlmsghdr *nh, int pm_family, int total_len)1051{1052	struct rtattr *attrs;1053 1054	for (; NLMSG_OK(nh, total_len); nh = NLMSG_NEXT(nh, total_len)) {1055		int len = nh->nlmsg_len;1056 1057		if (nh->nlmsg_type == NLMSG_DONE)1058			break;1059		if (nh->nlmsg_type == NLMSG_ERROR)1060			nl_error(nh);1061		if (nh->nlmsg_type != pm_family)1062			continue;1063 1064		len -= NLMSG_LENGTH(GENL_HDRLEN);1065		attrs = (struct rtattr *) ((char *) NLMSG_DATA(nh) +1066					   GENL_HDRLEN);1067		while (RTA_OK(attrs, len)) {1068			if (attrs->rta_type ==1069			    (MPTCP_PM_ATTR_ADDR | NLA_F_NESTED))1070				print_addr((void *)RTA_DATA(attrs),1071					   attrs->rta_len);1072			attrs = RTA_NEXT(attrs, len);1073		}1074	}1075}1076 1077int get_addr(int fd, int pm_family, int argc, char *argv[])1078{1079	char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +1080		  NLMSG_ALIGN(sizeof(struct genlmsghdr)) +1081		  1024];1082	struct rtattr *rta, *nest;1083	struct nlmsghdr *nh;1084	u_int32_t token = 0;1085	int nest_start;1086	u_int8_t id;1087	int off = 0;1088 1089	memset(data, 0, sizeof(data));1090	nh = (void *)data;1091	off = init_genl_req(data, pm_family, MPTCP_PM_CMD_GET_ADDR,1092			    MPTCP_PM_VER);1093 1094	/* the only argument is the address id */1095	if (argc != 3 && argc != 5)1096		syntax(argv);1097 1098	id = atoi(argv[2]);1099	if (argc == 5 && !strcmp(argv[3], "token"))1100		token = strtoul(argv[4], NULL, 10);1101 1102	nest_start = off;1103	nest = (void *)(data + off);1104	nest->rta_type = NLA_F_NESTED | MPTCP_PM_ATTR_ADDR;1105	nest->rta_len =  RTA_LENGTH(0);1106	off += NLMSG_ALIGN(nest->rta_len);1107 1108	/* build a dummy addr with only the ID set */1109	rta = (void *)(data + off);1110	rta->rta_type = MPTCP_PM_ADDR_ATTR_ID;1111	rta->rta_len = RTA_LENGTH(1);1112	memcpy(RTA_DATA(rta), &id, 1);1113	off += NLMSG_ALIGN(rta->rta_len);1114	nest->rta_len = off - nest_start;1115 1116	/* token */1117	if (token) {1118		rta = (void *)(data + off);1119		rta->rta_type = MPTCP_PM_ATTR_TOKEN;1120		rta->rta_len = RTA_LENGTH(4);1121		memcpy(RTA_DATA(rta), &token, 4);1122		off += NLMSG_ALIGN(rta->rta_len);1123	}1124 1125	print_addrs(nh, pm_family, do_nl_req(fd, nh, off, sizeof(data)));1126	return 0;1127}1128 1129int dump_addrs(int fd, int pm_family, int argc, char *argv[])1130{1131	char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +1132		  NLMSG_ALIGN(sizeof(struct genlmsghdr)) +1133		  1024];1134	pid_t pid = getpid();1135	struct nlmsghdr *nh;1136	u_int32_t token = 0;1137	struct rtattr *rta;1138	int off = 0;1139 1140	if (argc != 2 && argc != 4)1141		syntax(argv);1142 1143	if (argc == 4 && !strcmp(argv[2], "token"))1144		token = strtoul(argv[3], NULL, 10);1145 1146	memset(data, 0, sizeof(data));1147	nh = (void *)data;1148	off = init_genl_req(data, pm_family, MPTCP_PM_CMD_GET_ADDR,1149			    MPTCP_PM_VER);1150	nh->nlmsg_flags |= NLM_F_DUMP;1151	nh->nlmsg_seq = 1;1152	nh->nlmsg_pid = pid;1153	nh->nlmsg_len = off;1154 1155	/* token */1156	if (token) {1157		rta = (void *)(data + off);1158		rta->rta_type = MPTCP_PM_ATTR_TOKEN;1159		rta->rta_len = RTA_LENGTH(4);1160		memcpy(RTA_DATA(rta), &token, 4);1161		off += NLMSG_ALIGN(rta->rta_len);1162	}1163 1164	print_addrs(nh, pm_family, do_nl_req(fd, nh, off, sizeof(data)));1165	return 0;1166}1167 1168int flush_addrs(int fd, int pm_family, int argc, char *argv[])1169{1170	char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +1171		  NLMSG_ALIGN(sizeof(struct genlmsghdr)) +1172		  1024];1173	struct nlmsghdr *nh;1174	int off = 0;1175 1176	memset(data, 0, sizeof(data));1177	nh = (void *)data;1178	off = init_genl_req(data, pm_family, MPTCP_PM_CMD_FLUSH_ADDRS,1179			    MPTCP_PM_VER);1180 1181	do_nl_req(fd, nh, off, 0);1182	return 0;1183}1184 1185static void print_limits(struct nlmsghdr *nh, int pm_family, int total_len)1186{1187	struct rtattr *attrs;1188	uint32_t max;1189 1190	for (; NLMSG_OK(nh, total_len); nh = NLMSG_NEXT(nh, total_len)) {1191		int len = nh->nlmsg_len;1192 1193		if (nh->nlmsg_type == NLMSG_DONE)1194			break;1195		if (nh->nlmsg_type == NLMSG_ERROR)1196			nl_error(nh);1197		if (nh->nlmsg_type != pm_family)1198			continue;1199 1200		len -= NLMSG_LENGTH(GENL_HDRLEN);1201		attrs = (struct rtattr *) ((char *) NLMSG_DATA(nh) +1202					   GENL_HDRLEN);1203		while (RTA_OK(attrs, len)) {1204			int type = attrs->rta_type;1205 1206			if (type != MPTCP_PM_ATTR_RCV_ADD_ADDRS &&1207			    type != MPTCP_PM_ATTR_SUBFLOWS)1208				goto next;1209 1210			memcpy(&max, RTA_DATA(attrs), 4);1211			printf("%s %u\n", type == MPTCP_PM_ATTR_SUBFLOWS ?1212					  "subflows" : "accept", max);1213 1214next:1215			attrs = RTA_NEXT(attrs, len);1216		}1217	}1218}1219 1220int get_set_limits(int fd, int pm_family, int argc, char *argv[])1221{1222	char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +1223		  NLMSG_ALIGN(sizeof(struct genlmsghdr)) +1224		  1024];1225	uint32_t rcv_addr = 0, subflows = 0;1226	int cmd, len = sizeof(data);1227	struct nlmsghdr *nh;1228	int off = 0;1229 1230	/* limit */1231	if (argc == 4) {1232		rcv_addr = atoi(argv[2]);1233		subflows = atoi(argv[3]);1234		cmd = MPTCP_PM_CMD_SET_LIMITS;1235	} else {1236		cmd = MPTCP_PM_CMD_GET_LIMITS;1237	}1238 1239	memset(data, 0, sizeof(data));1240	nh = (void *)data;1241	off = init_genl_req(data, pm_family, cmd, MPTCP_PM_VER);1242 1243	/* limit */1244	if (cmd == MPTCP_PM_CMD_SET_LIMITS) {1245		struct rtattr *rta = (void *)(data + off);1246 1247		rta->rta_type = MPTCP_PM_ATTR_RCV_ADD_ADDRS;1248		rta->rta_len = RTA_LENGTH(4);1249		memcpy(RTA_DATA(rta), &rcv_addr, 4);1250		off += NLMSG_ALIGN(rta->rta_len);1251 1252		rta = (void *)(data + off);1253		rta->rta_type = MPTCP_PM_ATTR_SUBFLOWS;1254		rta->rta_len = RTA_LENGTH(4);1255		memcpy(RTA_DATA(rta), &subflows, 4);1256		off += NLMSG_ALIGN(rta->rta_len);1257 1258		/* do not expect a reply */1259		len = 0;1260	}1261 1262	len = do_nl_req(fd, nh, off, len);1263	if (cmd == MPTCP_PM_CMD_GET_LIMITS)1264		print_limits(nh, pm_family, len);1265	return 0;1266}1267 1268int add_listener(int argc, char *argv[])1269{1270	struct sockaddr_storage addr;1271	struct sockaddr_in6 *a6;1272	struct sockaddr_in *a4;1273	u_int16_t family = AF_UNSPEC;1274	int enable = 1;1275	int sock;1276	int err;1277 1278	if (argc < 4)1279		syntax(argv);1280 1281	memset(&addr, 0, sizeof(struct sockaddr_storage));1282	a4 = (struct sockaddr_in *)&addr;1283	a6 = (struct sockaddr_in6 *)&addr;1284 1285	if (inet_pton(AF_INET, argv[2], &a4->sin_addr)) {1286		family = AF_INET;1287		a4->sin_family = family;1288		a4->sin_port = htons(atoi(argv[3]));1289	} else if (inet_pton(AF_INET6, argv[2], &a6->sin6_addr)) {1290		family = AF_INET6;1291		a6->sin6_family = family;1292		a6->sin6_port = htons(atoi(argv[3]));1293	} else1294		error(1, errno, "can't parse ip %s", argv[2]);1295 1296	sock = socket(family, SOCK_STREAM, IPPROTO_MPTCP);1297	if (sock < 0)1298		error(1, errno, "can't create listener sock\n");1299 1300	if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable))) {1301		close(sock);1302		error(1, errno, "can't set SO_REUSEADDR on listener sock\n");1303	}1304 1305	err = bind(sock, (struct sockaddr *)&addr,1306		   ((family == AF_INET) ? sizeof(struct sockaddr_in) :1307		    sizeof(struct sockaddr_in6)));1308 1309	if (err == 0 && listen(sock, 30) == 0)1310		pause();1311 1312	close(sock);1313	return 0;1314}1315 1316int set_flags(int fd, int pm_family, int argc, char *argv[])1317{1318	char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +1319		  NLMSG_ALIGN(sizeof(struct genlmsghdr)) +1320		  1024];1321	struct rtattr *rta, *nest;1322	struct nlmsghdr *nh;1323	u_int32_t flags = 0;1324	u_int32_t token = 0;1325	u_int16_t rport = 0;1326	u_int16_t family;1327	void *rip = NULL;1328	int nest_start;1329	int use_id = 0;1330	u_int8_t id;1331	int off = 0;1332	int arg = 2;1333 1334	memset(data, 0, sizeof(data));1335	nh = (void *)data;1336	off = init_genl_req(data, pm_family, MPTCP_PM_CMD_SET_FLAGS,1337			    MPTCP_PM_VER);1338 1339	if (argc < 3)1340		syntax(argv);1341 1342	nest_start = off;1343	nest = (void *)(data + off);1344	nest->rta_type = NLA_F_NESTED | MPTCP_PM_ATTR_ADDR;1345	nest->rta_len = RTA_LENGTH(0);1346	off += NLMSG_ALIGN(nest->rta_len);1347 1348	if (!strcmp(argv[arg], "id")) {1349		if (++arg >= argc)1350			error(1, 0, " missing id value");1351 1352		use_id = 1;1353		id = atoi(argv[arg]);1354		rta = (void *)(data + off);1355		rta->rta_type = MPTCP_PM_ADDR_ATTR_ID;1356		rta->rta_len = RTA_LENGTH(1);1357		memcpy(RTA_DATA(rta), &id, 1);1358		off += NLMSG_ALIGN(rta->rta_len);1359	} else {1360		/* addr data */1361		rta = (void *)(data + off);1362		if (inet_pton(AF_INET, argv[arg], RTA_DATA(rta))) {1363			family = AF_INET;1364			rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR4;1365			rta->rta_len = RTA_LENGTH(4);1366		} else if (inet_pton(AF_INET6, argv[arg], RTA_DATA(rta))) {1367			family = AF_INET6;1368			rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR6;1369			rta->rta_len = RTA_LENGTH(16);1370		} else {1371			error(1, errno, "can't parse ip %s", argv[arg]);1372		}1373		off += NLMSG_ALIGN(rta->rta_len);1374 1375		/* family */1376		rta = (void *)(data + off);1377		rta->rta_type = MPTCP_PM_ADDR_ATTR_FAMILY;1378		rta->rta_len = RTA_LENGTH(2);1379		memcpy(RTA_DATA(rta), &family, 2);1380		off += NLMSG_ALIGN(rta->rta_len);1381	}1382 1383	if (++arg >= argc)1384		error(1, 0, " missing flags keyword");1385 1386	for (; arg < argc; arg++) {1387		if (!strcmp(argv[arg], "token")) {1388			if (++arg >= argc)1389				error(1, 0, " missing token value");1390 1391			/* token */1392			token = strtoul(argv[arg], NULL, 10);1393		} else if (!strcmp(argv[arg], "flags")) {1394			char *tok, *str;1395 1396			/* flags */1397			if (++arg >= argc)1398				error(1, 0, " missing flags value");1399 1400			for (str = argv[arg]; (tok = strtok(str, ","));1401			     str = NULL) {1402				if (!strcmp(tok, "backup"))1403					flags |= MPTCP_PM_ADDR_FLAG_BACKUP;1404				else if (!strcmp(tok, "fullmesh"))1405					flags |= MPTCP_PM_ADDR_FLAG_FULLMESH;1406				else if (strcmp(tok, "nobackup") &&1407					 strcmp(tok, "nofullmesh"))1408					error(1, errno,1409					      "unknown flag %s", argv[arg]);1410			}1411 1412			rta = (void *)(data + off);1413			rta->rta_type = MPTCP_PM_ADDR_ATTR_FLAGS;1414			rta->rta_len = RTA_LENGTH(4);1415			memcpy(RTA_DATA(rta), &flags, 4);1416			off += NLMSG_ALIGN(rta->rta_len);1417		} else if (!strcmp(argv[arg], "port")) {1418			u_int16_t port;1419 1420			if (use_id)1421				error(1, 0, " port can't be used with id");1422 1423			if (++arg >= argc)1424				error(1, 0, " missing port value");1425 1426			port = atoi(argv[arg]);1427			rta = (void *)(data + off);1428			rta->rta_type = MPTCP_PM_ADDR_ATTR_PORT;1429			rta->rta_len = RTA_LENGTH(2);1430			memcpy(RTA_DATA(rta), &port, 2);1431			off += NLMSG_ALIGN(rta->rta_len);1432		} else if (!strcmp(argv[arg], "rport")) {1433			if (++arg >= argc)1434				error(1, 0, " missing remote port");1435 1436			rport = atoi(argv[arg]);1437		} else if (!strcmp(argv[arg], "rip")) {1438			if (++arg >= argc)1439				error(1, 0, " missing remote ip");1440 1441			rip = argv[arg];1442		} else {1443			error(1, 0, "unknown keyword %s", argv[arg]);1444		}1445	}1446	nest->rta_len = off - nest_start;1447 1448	/* token */1449	if (token) {1450		rta = (void *)(data + off);1451		rta->rta_type = MPTCP_PM_ATTR_TOKEN;1452		rta->rta_len = RTA_LENGTH(4);1453		memcpy(RTA_DATA(rta), &token, 4);1454		off += NLMSG_ALIGN(rta->rta_len);1455	}1456 1457	/* remote addr/port */1458	if (rip) {1459		nest_start = off;1460		nest = (void *)(data + off);1461		nest->rta_type = NLA_F_NESTED | MPTCP_PM_ATTR_ADDR_REMOTE;1462		nest->rta_len = RTA_LENGTH(0);1463		off += NLMSG_ALIGN(nest->rta_len);1464 1465		/* addr data */1466		rta = (void *)(data + off);1467		if (inet_pton(AF_INET, rip, RTA_DATA(rta))) {1468			family = AF_INET;1469			rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR4;1470			rta->rta_len = RTA_LENGTH(4);1471		} else if (inet_pton(AF_INET6, rip, RTA_DATA(rta))) {1472			family = AF_INET6;1473			rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR6;1474			rta->rta_len = RTA_LENGTH(16);1475		} else {1476			error(1, errno, "can't parse ip %s", (char *)rip);1477		}1478		off += NLMSG_ALIGN(rta->rta_len);1479 1480		/* family */1481		rta = (void *)(data + off);1482		rta->rta_type = MPTCP_PM_ADDR_ATTR_FAMILY;1483		rta->rta_len = RTA_LENGTH(2);1484		memcpy(RTA_DATA(rta), &family, 2);1485		off += NLMSG_ALIGN(rta->rta_len);1486 1487		if (rport) {1488			rta = (void *)(data + off);1489			rta->rta_type = MPTCP_PM_ADDR_ATTR_PORT;1490			rta->rta_len = RTA_LENGTH(2);1491			memcpy(RTA_DATA(rta), &rport, 2);1492			off += NLMSG_ALIGN(rta->rta_len);1493		}1494 1495		nest->rta_len = off - nest_start;1496	}1497 1498	do_nl_req(fd, nh, off, 0);1499	return 0;1500}1501 1502int main(int argc, char *argv[])1503{1504	int events_mcast_grp;1505	int pm_family;1506	int fd;1507 1508	if (argc < 2)1509		syntax(argv);1510 1511	fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);1512	if (fd == -1)1513		error(1, errno, "socket netlink");1514 1515	resolve_mptcp_pm_netlink(fd, &pm_family, &events_mcast_grp);1516 1517	if (!strcmp(argv[1], "add"))1518		return add_addr(fd, pm_family, argc, argv);1519	else if (!strcmp(argv[1], "ann"))1520		return announce_addr(fd, pm_family, argc, argv);1521	else if (!strcmp(argv[1], "rem"))1522		return remove_addr(fd, pm_family, argc, argv);1523	else if (!strcmp(argv[1], "csf"))1524		return csf(fd, pm_family, argc, argv);1525	else if (!strcmp(argv[1], "dsf"))1526		return dsf(fd, pm_family, argc, argv);1527	else if (!strcmp(argv[1], "del"))1528		return del_addr(fd, pm_family, argc, argv);1529	else if (!strcmp(argv[1], "flush"))1530		return flush_addrs(fd, pm_family, argc, argv);1531	else if (!strcmp(argv[1], "get"))1532		return get_addr(fd, pm_family, argc, argv);1533	else if (!strcmp(argv[1], "dump"))1534		return dump_addrs(fd, pm_family, argc, argv);1535	else if (!strcmp(argv[1], "limits"))1536		return get_set_limits(fd, pm_family, argc, argv);1537	else if (!strcmp(argv[1], "set"))1538		return set_flags(fd, pm_family, argc, argv);1539	else if (!strcmp(argv[1], "events"))1540		return capture_events(fd, events_mcast_grp);1541	else if (!strcmp(argv[1], "listen"))1542		return add_listener(argc, argv);1543 1544	fprintf(stderr, "unknown sub-command: %s", argv[1]);1545	syntax(argv);1546	return 0;1547}1548