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