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
28bdde081dSKishen Maloor #ifndef IPPROTO_MPTCP
29bdde081dSKishen Maloor #define IPPROTO_MPTCP 262
30bdde081dSKishen Maloor #endif
31eedbc685SPaolo Abeni 
syntax(char * argv[])32eedbc685SPaolo Abeni static void syntax(char *argv[])
33eedbc685SPaolo Abeni {
3465ebc667SGeliang Tang 	fprintf(stderr, "%s add|ann|rem|csf|dsf|get|set|del|flush|dump|events|listen|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");
42ca188a25SKishen Maloor 	fprintf(stderr, "\tset [<ip>] [id <nr>] flags [no]backup|[no]fullmesh [port <nr>] [token <token>] [rip <ip>] [rport <port>]\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");
47bdde081dSKishen Maloor 	fprintf(stderr, "\tlisten <local-ip> <local-port>\n");
48eedbc685SPaolo Abeni 	exit(0);
49eedbc685SPaolo Abeni }
50eedbc685SPaolo Abeni 
init_genl_req(char * data,int family,int cmd,int version)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 
nl_error(struct nlmsghdr * nh)69*1dc88d24SMatthieu Baerts static int 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 
75*1dc88d24SMatthieu Baerts 	if (len < sizeof(struct nlmsgerr)) {
76eedbc685SPaolo Abeni 		error(1, 0, "netlink error message truncated %d min %ld", len,
77eedbc685SPaolo Abeni 		      sizeof(struct nlmsgerr));
78*1dc88d24SMatthieu Baerts 		return -1;
79*1dc88d24SMatthieu Baerts 	}
80eedbc685SPaolo Abeni 
81*1dc88d24SMatthieu Baerts 	if (err->error) {
82eedbc685SPaolo Abeni 		/* check messages from kernel */
83eedbc685SPaolo Abeni 		struct rtattr *attrs = (struct rtattr *)NLMSG_DATA(nh);
84eedbc685SPaolo Abeni 
85*1dc88d24SMatthieu Baerts 		fprintf(stderr, "netlink error %d (%s)\n",
86*1dc88d24SMatthieu Baerts 			err->error, strerror(-err->error));
87*1dc88d24SMatthieu Baerts 
88eedbc685SPaolo Abeni 		while (RTA_OK(attrs, len)) {
89eedbc685SPaolo Abeni 			if (attrs->rta_type == NLMSGERR_ATTR_MSG)
90eedbc685SPaolo Abeni 				fprintf(stderr, "netlink ext ack msg: %s\n",
91eedbc685SPaolo Abeni 					(char *)RTA_DATA(attrs));
92eedbc685SPaolo Abeni 			if (attrs->rta_type == NLMSGERR_ATTR_OFFS) {
93eedbc685SPaolo Abeni 				memcpy(&off, RTA_DATA(attrs), 4);
94eedbc685SPaolo Abeni 				fprintf(stderr, "netlink err off %d\n",
95eedbc685SPaolo Abeni 					(int)off);
96eedbc685SPaolo Abeni 			}
97eedbc685SPaolo Abeni 			attrs = RTA_NEXT(attrs, len);
98eedbc685SPaolo Abeni 		}
99*1dc88d24SMatthieu Baerts 		return -1;
100eedbc685SPaolo Abeni 	}
101*1dc88d24SMatthieu Baerts 
102*1dc88d24SMatthieu Baerts 	return 0;
103eedbc685SPaolo Abeni }
104eedbc685SPaolo Abeni 
capture_events(int fd,int event_group)105b3e5fd65SKishen Maloor static int capture_events(int fd, int event_group)
106b3e5fd65SKishen Maloor {
107b3e5fd65SKishen Maloor 	u_int8_t buffer[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
108b3e5fd65SKishen Maloor 			NLMSG_ALIGN(sizeof(struct genlmsghdr)) + 1024];
109b3e5fd65SKishen Maloor 	struct genlmsghdr *ghdr;
110b3e5fd65SKishen Maloor 	struct rtattr *attrs;
111b3e5fd65SKishen Maloor 	struct nlmsghdr *nh;
112b3e5fd65SKishen Maloor 	int ret = 0;
113b3e5fd65SKishen Maloor 	int res_len;
114b3e5fd65SKishen Maloor 	int msg_len;
115b3e5fd65SKishen Maloor 	fd_set rfds;
116b3e5fd65SKishen Maloor 
117b3e5fd65SKishen Maloor 	if (setsockopt(fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP,
118b3e5fd65SKishen Maloor 		       &event_group, sizeof(event_group)) < 0)
119b3e5fd65SKishen Maloor 		error(1, errno, "could not join the " MPTCP_PM_EVENTS " mcast group");
120b3e5fd65SKishen Maloor 
121b3e5fd65SKishen Maloor 	do {
122b3e5fd65SKishen Maloor 		FD_ZERO(&rfds);
123b3e5fd65SKishen Maloor 		FD_SET(fd, &rfds);
124b3e5fd65SKishen Maloor 		res_len = NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
125b3e5fd65SKishen Maloor 		  NLMSG_ALIGN(sizeof(struct genlmsghdr)) + 1024;
126b3e5fd65SKishen Maloor 
127b3e5fd65SKishen Maloor 		ret = select(FD_SETSIZE, &rfds, NULL, NULL, NULL);
128b3e5fd65SKishen Maloor 
129b3e5fd65SKishen Maloor 		if (ret < 0)
130b3e5fd65SKishen Maloor 			error(1, ret, "error in select() on NL socket");
131b3e5fd65SKishen Maloor 
132b3e5fd65SKishen Maloor 		res_len = recv(fd, buffer, res_len, 0);
133b3e5fd65SKishen Maloor 		if (res_len < 0)
134b3e5fd65SKishen Maloor 			error(1, res_len, "error on recv() from NL socket");
135b3e5fd65SKishen Maloor 
136b3e5fd65SKishen Maloor 		nh = (struct nlmsghdr *)buffer;
137b3e5fd65SKishen Maloor 
138b3e5fd65SKishen Maloor 		for (; NLMSG_OK(nh, res_len); nh = NLMSG_NEXT(nh, res_len)) {
139b3e5fd65SKishen Maloor 			if (nh->nlmsg_type == NLMSG_ERROR)
140b3e5fd65SKishen Maloor 				error(1, NLMSG_ERROR, "received invalid NL message");
141b3e5fd65SKishen Maloor 
142b3e5fd65SKishen Maloor 			ghdr = (struct genlmsghdr *)NLMSG_DATA(nh);
143b3e5fd65SKishen Maloor 
144b3e5fd65SKishen Maloor 			if (ghdr->cmd == 0)
145b3e5fd65SKishen Maloor 				continue;
146b3e5fd65SKishen Maloor 
147b3e5fd65SKishen Maloor 			fprintf(stderr, "type:%d", ghdr->cmd);
148b3e5fd65SKishen Maloor 
149b3e5fd65SKishen Maloor 			msg_len = nh->nlmsg_len - NLMSG_LENGTH(GENL_HDRLEN);
150b3e5fd65SKishen Maloor 
151b3e5fd65SKishen Maloor 			attrs = (struct rtattr *) ((char *) ghdr + GENL_HDRLEN);
152b3e5fd65SKishen Maloor 			while (RTA_OK(attrs, msg_len)) {
153b3e5fd65SKishen Maloor 				if (attrs->rta_type == MPTCP_ATTR_TOKEN)
154b3e5fd65SKishen Maloor 					fprintf(stderr, ",token:%u", *(__u32 *)RTA_DATA(attrs));
155b3e5fd65SKishen Maloor 				else if (attrs->rta_type == MPTCP_ATTR_FAMILY)
156b3e5fd65SKishen Maloor 					fprintf(stderr, ",family:%u", *(__u16 *)RTA_DATA(attrs));
157b3e5fd65SKishen Maloor 				else if (attrs->rta_type == MPTCP_ATTR_LOC_ID)
158b3e5fd65SKishen Maloor 					fprintf(stderr, ",loc_id:%u", *(__u8 *)RTA_DATA(attrs));
159b3e5fd65SKishen Maloor 				else if (attrs->rta_type == MPTCP_ATTR_REM_ID)
160b3e5fd65SKishen Maloor 					fprintf(stderr, ",rem_id:%u", *(__u8 *)RTA_DATA(attrs));
161b3e5fd65SKishen Maloor 				else if (attrs->rta_type == MPTCP_ATTR_SADDR4) {
162b3e5fd65SKishen Maloor 					u_int32_t saddr4 = ntohl(*(__u32 *)RTA_DATA(attrs));
163b3e5fd65SKishen Maloor 
164b3e5fd65SKishen Maloor 					fprintf(stderr, ",saddr4:%u.%u.%u.%u", saddr4 >> 24,
165b3e5fd65SKishen Maloor 					       (saddr4 >> 16) & 0xFF, (saddr4 >> 8) & 0xFF,
166b3e5fd65SKishen Maloor 					       (saddr4 & 0xFF));
167b3e5fd65SKishen Maloor 				} else if (attrs->rta_type == MPTCP_ATTR_SADDR6) {
168b3e5fd65SKishen Maloor 					char buf[INET6_ADDRSTRLEN];
169b3e5fd65SKishen Maloor 
170b3e5fd65SKishen Maloor 					if (inet_ntop(AF_INET6, RTA_DATA(attrs), buf,
171b3e5fd65SKishen Maloor 						      sizeof(buf)) != NULL)
172b3e5fd65SKishen Maloor 						fprintf(stderr, ",saddr6:%s", buf);
173b3e5fd65SKishen Maloor 				} else if (attrs->rta_type == MPTCP_ATTR_DADDR4) {
174b3e5fd65SKishen Maloor 					u_int32_t daddr4 = ntohl(*(__u32 *)RTA_DATA(attrs));
175b3e5fd65SKishen Maloor 
176b3e5fd65SKishen Maloor 					fprintf(stderr, ",daddr4:%u.%u.%u.%u", daddr4 >> 24,
177b3e5fd65SKishen Maloor 					       (daddr4 >> 16) & 0xFF, (daddr4 >> 8) & 0xFF,
178b3e5fd65SKishen Maloor 					       (daddr4 & 0xFF));
179b3e5fd65SKishen Maloor 				} else if (attrs->rta_type == MPTCP_ATTR_DADDR6) {
180b3e5fd65SKishen Maloor 					char buf[INET6_ADDRSTRLEN];
181b3e5fd65SKishen Maloor 
182b3e5fd65SKishen Maloor 					if (inet_ntop(AF_INET6, RTA_DATA(attrs), buf,
183b3e5fd65SKishen Maloor 						      sizeof(buf)) != NULL)
184b3e5fd65SKishen Maloor 						fprintf(stderr, ",daddr6:%s", buf);
185b3e5fd65SKishen Maloor 				} else if (attrs->rta_type == MPTCP_ATTR_SPORT)
186b3e5fd65SKishen Maloor 					fprintf(stderr, ",sport:%u",
187b3e5fd65SKishen Maloor 						ntohs(*(__u16 *)RTA_DATA(attrs)));
188b3e5fd65SKishen Maloor 				else if (attrs->rta_type == MPTCP_ATTR_DPORT)
189b3e5fd65SKishen Maloor 					fprintf(stderr, ",dport:%u",
190b3e5fd65SKishen Maloor 						ntohs(*(__u16 *)RTA_DATA(attrs)));
191b3e5fd65SKishen Maloor 				else if (attrs->rta_type == MPTCP_ATTR_BACKUP)
192b3e5fd65SKishen Maloor 					fprintf(stderr, ",backup:%u", *(__u8 *)RTA_DATA(attrs));
193b3e5fd65SKishen Maloor 				else if (attrs->rta_type == MPTCP_ATTR_ERROR)
194b3e5fd65SKishen Maloor 					fprintf(stderr, ",error:%u", *(__u8 *)RTA_DATA(attrs));
195b3e5fd65SKishen Maloor 				else if (attrs->rta_type == MPTCP_ATTR_SERVER_SIDE)
196b3e5fd65SKishen Maloor 					fprintf(stderr, ",server_side:%u", *(__u8 *)RTA_DATA(attrs));
197b3e5fd65SKishen Maloor 
198b3e5fd65SKishen Maloor 				attrs = RTA_NEXT(attrs, msg_len);
199b3e5fd65SKishen Maloor 			}
200b3e5fd65SKishen Maloor 		}
201b3e5fd65SKishen Maloor 		fprintf(stderr, "\n");
202b3e5fd65SKishen Maloor 	} while (1);
203b3e5fd65SKishen Maloor 
204b3e5fd65SKishen Maloor 	return 0;
205b3e5fd65SKishen Maloor }
206b3e5fd65SKishen Maloor 
207*1dc88d24SMatthieu Baerts /* do a netlink command and, if max > 0, fetch the reply ; nh's size >1024B */
do_nl_req(int fd,struct nlmsghdr * nh,int len,int max)208eedbc685SPaolo Abeni static int do_nl_req(int fd, struct nlmsghdr *nh, int len, int max)
209eedbc685SPaolo Abeni {
210eedbc685SPaolo Abeni 	struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK };
211eedbc685SPaolo Abeni 	socklen_t addr_len;
212eedbc685SPaolo Abeni 	void *data = nh;
213eedbc685SPaolo Abeni 	int rem, ret;
214eedbc685SPaolo Abeni 	int err = 0;
215eedbc685SPaolo Abeni 
216*1dc88d24SMatthieu Baerts 	/* If no expected answer, ask for an ACK to look for errors if any */
217*1dc88d24SMatthieu Baerts 	if (max == 0) {
218*1dc88d24SMatthieu Baerts 		nh->nlmsg_flags |= NLM_F_ACK;
219*1dc88d24SMatthieu Baerts 		max = 1024;
220*1dc88d24SMatthieu Baerts 	}
221*1dc88d24SMatthieu Baerts 
222eedbc685SPaolo Abeni 	nh->nlmsg_len = len;
223eedbc685SPaolo Abeni 	ret = sendto(fd, data, len, 0, (void *)&nladdr, sizeof(nladdr));
224eedbc685SPaolo Abeni 	if (ret != len)
225eedbc685SPaolo Abeni 		error(1, errno, "send netlink: %uB != %uB\n", ret, len);
226eedbc685SPaolo Abeni 
227eedbc685SPaolo Abeni 	addr_len = sizeof(nladdr);
228eedbc685SPaolo Abeni 	rem = ret = recvfrom(fd, data, max, 0, (void *)&nladdr, &addr_len);
229eedbc685SPaolo Abeni 	if (ret < 0)
230eedbc685SPaolo Abeni 		error(1, errno, "recv netlink: %uB\n", ret);
231eedbc685SPaolo Abeni 
232eedbc685SPaolo Abeni 	/* Beware: the NLMSG_NEXT macro updates the 'rem' argument */
233eedbc685SPaolo Abeni 	for (; NLMSG_OK(nh, rem); nh = NLMSG_NEXT(nh, rem)) {
234*1dc88d24SMatthieu Baerts 		if (nh->nlmsg_type == NLMSG_DONE)
235*1dc88d24SMatthieu Baerts 			break;
236*1dc88d24SMatthieu Baerts 
237*1dc88d24SMatthieu Baerts 		if (nh->nlmsg_type == NLMSG_ERROR && nl_error(nh))
238eedbc685SPaolo Abeni 			err = 1;
239eedbc685SPaolo Abeni 	}
240eedbc685SPaolo Abeni 	if (err)
241eedbc685SPaolo Abeni 		error(1, 0, "bailing out due to netlink error[s]");
242eedbc685SPaolo Abeni 	return ret;
243eedbc685SPaolo Abeni }
244eedbc685SPaolo Abeni 
genl_parse_getfamily(struct nlmsghdr * nlh,int * pm_family,int * events_mcast_grp)245b3e5fd65SKishen Maloor static int genl_parse_getfamily(struct nlmsghdr *nlh, int *pm_family,
246b3e5fd65SKishen Maloor 				int *events_mcast_grp)
247eedbc685SPaolo Abeni {
248eedbc685SPaolo Abeni 	struct genlmsghdr *ghdr = NLMSG_DATA(nlh);
249eedbc685SPaolo Abeni 	int len = nlh->nlmsg_len;
250eedbc685SPaolo Abeni 	struct rtattr *attrs;
251b3e5fd65SKishen Maloor 	struct rtattr *grps;
252b3e5fd65SKishen Maloor 	struct rtattr *grp;
253b3e5fd65SKishen Maloor 	int got_events_grp;
254b3e5fd65SKishen Maloor 	int got_family;
255b3e5fd65SKishen Maloor 	int grps_len;
256b3e5fd65SKishen Maloor 	int grp_len;
257eedbc685SPaolo Abeni 
258eedbc685SPaolo Abeni 	if (nlh->nlmsg_type != GENL_ID_CTRL)
259eedbc685SPaolo Abeni 		error(1, errno, "Not a controller message, len=%d type=0x%x\n",
260eedbc685SPaolo Abeni 		      nlh->nlmsg_len, nlh->nlmsg_type);
261eedbc685SPaolo Abeni 
262eedbc685SPaolo Abeni 	len -= NLMSG_LENGTH(GENL_HDRLEN);
263eedbc685SPaolo Abeni 
264eedbc685SPaolo Abeni 	if (len < 0)
265eedbc685SPaolo Abeni 		error(1, errno, "wrong controller message len %d\n", len);
266eedbc685SPaolo Abeni 
267eedbc685SPaolo Abeni 	if (ghdr->cmd != CTRL_CMD_NEWFAMILY)
268eedbc685SPaolo Abeni 		error(1, errno, "Unknown controller command %d\n", ghdr->cmd);
269eedbc685SPaolo Abeni 
270eedbc685SPaolo Abeni 	attrs = (struct rtattr *) ((char *) ghdr + GENL_HDRLEN);
271b3e5fd65SKishen Maloor 	got_family = 0;
272b3e5fd65SKishen Maloor 	got_events_grp = 0;
273b3e5fd65SKishen Maloor 
274eedbc685SPaolo Abeni 	while (RTA_OK(attrs, len)) {
275b3e5fd65SKishen Maloor 		if (attrs->rta_type == CTRL_ATTR_FAMILY_ID) {
276b3e5fd65SKishen Maloor 			*pm_family = *(__u16 *)RTA_DATA(attrs);
277b3e5fd65SKishen Maloor 			got_family = 1;
278b3e5fd65SKishen Maloor 		} else if (attrs->rta_type == CTRL_ATTR_MCAST_GROUPS) {
279b3e5fd65SKishen Maloor 			grps = RTA_DATA(attrs);
280b3e5fd65SKishen Maloor 			grps_len = RTA_PAYLOAD(attrs);
281b3e5fd65SKishen Maloor 
282b3e5fd65SKishen Maloor 			while (RTA_OK(grps, grps_len)) {
283b3e5fd65SKishen Maloor 				grp = RTA_DATA(grps);
284b3e5fd65SKishen Maloor 				grp_len = RTA_PAYLOAD(grps);
285b3e5fd65SKishen Maloor 				got_events_grp = 0;
286b3e5fd65SKishen Maloor 
287b3e5fd65SKishen Maloor 				while (RTA_OK(grp, grp_len)) {
288b3e5fd65SKishen Maloor 					if (grp->rta_type == CTRL_ATTR_MCAST_GRP_ID)
289b3e5fd65SKishen Maloor 						*events_mcast_grp = *(__u32 *)RTA_DATA(grp);
290b3e5fd65SKishen Maloor 					else if (grp->rta_type == CTRL_ATTR_MCAST_GRP_NAME &&
291b3e5fd65SKishen Maloor 						 !strcmp(RTA_DATA(grp), MPTCP_PM_EVENTS))
292b3e5fd65SKishen Maloor 						got_events_grp = 1;
293b3e5fd65SKishen Maloor 
294b3e5fd65SKishen Maloor 					grp = RTA_NEXT(grp, grp_len);
295b3e5fd65SKishen Maloor 				}
296b3e5fd65SKishen Maloor 
297b3e5fd65SKishen Maloor 				if (got_events_grp)
298b3e5fd65SKishen Maloor 					break;
299b3e5fd65SKishen Maloor 
300b3e5fd65SKishen Maloor 				grps = RTA_NEXT(grps, grps_len);
301b3e5fd65SKishen Maloor 			}
302b3e5fd65SKishen Maloor 		}
303b3e5fd65SKishen Maloor 
304b3e5fd65SKishen Maloor 		if (got_family && got_events_grp)
305b3e5fd65SKishen Maloor 			return 0;
306b3e5fd65SKishen Maloor 
307eedbc685SPaolo Abeni 		attrs = RTA_NEXT(attrs, len);
308eedbc685SPaolo Abeni 	}
309eedbc685SPaolo Abeni 
310eedbc685SPaolo Abeni 	error(1, errno, "can't find CTRL_ATTR_FAMILY_ID attr");
311eedbc685SPaolo Abeni 	return -1;
312eedbc685SPaolo Abeni }
313eedbc685SPaolo Abeni 
resolve_mptcp_pm_netlink(int fd,int * pm_family,int * events_mcast_grp)314b3e5fd65SKishen Maloor static int resolve_mptcp_pm_netlink(int fd, int *pm_family, int *events_mcast_grp)
315eedbc685SPaolo Abeni {
316eedbc685SPaolo Abeni 	char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
317eedbc685SPaolo Abeni 		  NLMSG_ALIGN(sizeof(struct genlmsghdr)) +
318eedbc685SPaolo Abeni 		  1024];
319eedbc685SPaolo Abeni 	struct nlmsghdr *nh;
320eedbc685SPaolo Abeni 	struct rtattr *rta;
321eedbc685SPaolo Abeni 	int namelen;
322eedbc685SPaolo Abeni 	int off = 0;
323eedbc685SPaolo Abeni 
324eedbc685SPaolo Abeni 	memset(data, 0, sizeof(data));
325eedbc685SPaolo Abeni 	nh = (void *)data;
326eedbc685SPaolo Abeni 	off = init_genl_req(data, GENL_ID_CTRL, CTRL_CMD_GETFAMILY, 0);
327eedbc685SPaolo Abeni 
328eedbc685SPaolo Abeni 	rta = (void *)(data + off);
329eedbc685SPaolo Abeni 	namelen = strlen(MPTCP_PM_NAME) + 1;
330eedbc685SPaolo Abeni 	rta->rta_type = CTRL_ATTR_FAMILY_NAME;
331eedbc685SPaolo Abeni 	rta->rta_len = RTA_LENGTH(namelen);
332eedbc685SPaolo Abeni 	memcpy(RTA_DATA(rta), MPTCP_PM_NAME, namelen);
333eedbc685SPaolo Abeni 	off += NLMSG_ALIGN(rta->rta_len);
334eedbc685SPaolo Abeni 
335eedbc685SPaolo Abeni 	do_nl_req(fd, nh, off, sizeof(data));
336b3e5fd65SKishen Maloor 	return genl_parse_getfamily((void *)data, pm_family, events_mcast_grp);
337eedbc685SPaolo Abeni }
338eedbc685SPaolo Abeni 
dsf(int fd,int pm_family,int argc,char * argv[])33957cc361bSKishen Maloor int dsf(int fd, int pm_family, int argc, char *argv[])
34057cc361bSKishen Maloor {
34157cc361bSKishen Maloor 	char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
34257cc361bSKishen Maloor 		  NLMSG_ALIGN(sizeof(struct genlmsghdr)) +
34357cc361bSKishen Maloor 		  1024];
34457cc361bSKishen Maloor 	struct rtattr *rta, *addr;
34557cc361bSKishen Maloor 	u_int16_t family, port;
34657cc361bSKishen Maloor 	struct nlmsghdr *nh;
34757cc361bSKishen Maloor 	u_int32_t token;
34857cc361bSKishen Maloor 	int addr_start;
34957cc361bSKishen Maloor 	int off = 0;
35057cc361bSKishen Maloor 	int arg;
35157cc361bSKishen Maloor 
35257cc361bSKishen Maloor 	const char *params[5];
35357cc361bSKishen Maloor 
35457cc361bSKishen Maloor 	memset(params, 0, 5 * sizeof(const char *));
35557cc361bSKishen Maloor 
35657cc361bSKishen Maloor 	memset(data, 0, sizeof(data));
35757cc361bSKishen Maloor 	nh = (void *)data;
35857cc361bSKishen Maloor 	off = init_genl_req(data, pm_family, MPTCP_PM_CMD_SUBFLOW_DESTROY,
35957cc361bSKishen Maloor 			    MPTCP_PM_VER);
36057cc361bSKishen Maloor 
36157cc361bSKishen Maloor 	if (argc < 12)
36257cc361bSKishen Maloor 		syntax(argv);
36357cc361bSKishen Maloor 
36457cc361bSKishen Maloor 	/* Params recorded in this order:
36557cc361bSKishen Maloor 	 * <local-ip>, <local-port>, <remote-ip>, <remote-port>, <token>
36657cc361bSKishen Maloor 	 */
36757cc361bSKishen Maloor 	for (arg = 2; arg < argc; arg++) {
36857cc361bSKishen Maloor 		if (!strcmp(argv[arg], "lip")) {
36957cc361bSKishen Maloor 			if (++arg >= argc)
37057cc361bSKishen Maloor 				error(1, 0, " missing local IP");
37157cc361bSKishen Maloor 
37257cc361bSKishen Maloor 			params[0] = argv[arg];
37357cc361bSKishen Maloor 		} else if (!strcmp(argv[arg], "lport")) {
37457cc361bSKishen Maloor 			if (++arg >= argc)
37557cc361bSKishen Maloor 				error(1, 0, " missing local port");
37657cc361bSKishen Maloor 
37757cc361bSKishen Maloor 			params[1] = argv[arg];
37857cc361bSKishen Maloor 		} else if (!strcmp(argv[arg], "rip")) {
37957cc361bSKishen Maloor 			if (++arg >= argc)
38057cc361bSKishen Maloor 				error(1, 0, " missing remote IP");
38157cc361bSKishen Maloor 
38257cc361bSKishen Maloor 			params[2] = argv[arg];
38357cc361bSKishen Maloor 		} else if (!strcmp(argv[arg], "rport")) {
38457cc361bSKishen Maloor 			if (++arg >= argc)
38557cc361bSKishen Maloor 				error(1, 0, " missing remote port");
38657cc361bSKishen Maloor 
38757cc361bSKishen Maloor 			params[3] = argv[arg];
38857cc361bSKishen Maloor 		} else if (!strcmp(argv[arg], "token")) {
38957cc361bSKishen Maloor 			if (++arg >= argc)
39057cc361bSKishen Maloor 				error(1, 0, " missing token");
39157cc361bSKishen Maloor 
39257cc361bSKishen Maloor 			params[4] = argv[arg];
39357cc361bSKishen Maloor 		} else
39457cc361bSKishen Maloor 			error(1, 0, "unknown keyword %s", argv[arg]);
39557cc361bSKishen Maloor 	}
39657cc361bSKishen Maloor 
39757cc361bSKishen Maloor 	for (arg = 0; arg < 4; arg = arg + 2) {
39857cc361bSKishen Maloor 		/*  addr header */
39957cc361bSKishen Maloor 		addr_start = off;
40057cc361bSKishen Maloor 		addr = (void *)(data + off);
40157cc361bSKishen Maloor 		addr->rta_type = NLA_F_NESTED |
40257cc361bSKishen Maloor 			((arg == 0) ? MPTCP_PM_ATTR_ADDR : MPTCP_PM_ATTR_ADDR_REMOTE);
40357cc361bSKishen Maloor 		addr->rta_len = RTA_LENGTH(0);
40457cc361bSKishen Maloor 		off += NLMSG_ALIGN(addr->rta_len);
40557cc361bSKishen Maloor 
40657cc361bSKishen Maloor 		/*  addr data */
40757cc361bSKishen Maloor 		rta = (void *)(data + off);
40857cc361bSKishen Maloor 		if (inet_pton(AF_INET, params[arg], RTA_DATA(rta))) {
40957cc361bSKishen Maloor 			family = AF_INET;
41057cc361bSKishen Maloor 			rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR4;
41157cc361bSKishen Maloor 			rta->rta_len = RTA_LENGTH(4);
41257cc361bSKishen Maloor 		} else if (inet_pton(AF_INET6, params[arg], RTA_DATA(rta))) {
41357cc361bSKishen Maloor 			family = AF_INET6;
41457cc361bSKishen Maloor 			rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR6;
41557cc361bSKishen Maloor 			rta->rta_len = RTA_LENGTH(16);
41657cc361bSKishen Maloor 		} else
41757cc361bSKishen Maloor 			error(1, errno, "can't parse ip %s", params[arg]);
41857cc361bSKishen Maloor 		off += NLMSG_ALIGN(rta->rta_len);
41957cc361bSKishen Maloor 
42057cc361bSKishen Maloor 		/* family */
42157cc361bSKishen Maloor 		rta = (void *)(data + off);
42257cc361bSKishen Maloor 		rta->rta_type = MPTCP_PM_ADDR_ATTR_FAMILY;
42357cc361bSKishen Maloor 		rta->rta_len = RTA_LENGTH(2);
42457cc361bSKishen Maloor 		memcpy(RTA_DATA(rta), &family, 2);
42557cc361bSKishen Maloor 		off += NLMSG_ALIGN(rta->rta_len);
42657cc361bSKishen Maloor 
42757cc361bSKishen Maloor 		/*  port */
42857cc361bSKishen Maloor 		port = atoi(params[arg + 1]);
42957cc361bSKishen Maloor 		rta = (void *)(data + off);
43057cc361bSKishen Maloor 		rta->rta_type = MPTCP_PM_ADDR_ATTR_PORT;
43157cc361bSKishen Maloor 		rta->rta_len = RTA_LENGTH(2);
43257cc361bSKishen Maloor 		memcpy(RTA_DATA(rta), &port, 2);
43357cc361bSKishen Maloor 		off += NLMSG_ALIGN(rta->rta_len);
43457cc361bSKishen Maloor 
43557cc361bSKishen Maloor 		addr->rta_len = off - addr_start;
43657cc361bSKishen Maloor 	}
43757cc361bSKishen Maloor 
43857cc361bSKishen Maloor 	/* token */
43961d96580SMatthieu Baerts 	token = strtoul(params[4], NULL, 10);
44057cc361bSKishen Maloor 	rta = (void *)(data + off);
44157cc361bSKishen Maloor 	rta->rta_type = MPTCP_PM_ATTR_TOKEN;
44257cc361bSKishen Maloor 	rta->rta_len = RTA_LENGTH(4);
44357cc361bSKishen Maloor 	memcpy(RTA_DATA(rta), &token, 4);
44457cc361bSKishen Maloor 	off += NLMSG_ALIGN(rta->rta_len);
44557cc361bSKishen Maloor 
44657cc361bSKishen Maloor 	do_nl_req(fd, nh, off, 0);
44757cc361bSKishen Maloor 
44857cc361bSKishen Maloor 	return 0;
44957cc361bSKishen Maloor }
45057cc361bSKishen Maloor 
csf(int fd,int pm_family,int argc,char * argv[])451cf8d0a6dSKishen Maloor int csf(int fd, int pm_family, int argc, char *argv[])
452cf8d0a6dSKishen Maloor {
453cf8d0a6dSKishen Maloor 	char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
454cf8d0a6dSKishen Maloor 		  NLMSG_ALIGN(sizeof(struct genlmsghdr)) +
455cf8d0a6dSKishen Maloor 		  1024];
456cf8d0a6dSKishen Maloor 	const char *params[5];
457cf8d0a6dSKishen Maloor 	struct nlmsghdr *nh;
458cf8d0a6dSKishen Maloor 	struct rtattr *addr;
459cf8d0a6dSKishen Maloor 	struct rtattr *rta;
460cf8d0a6dSKishen Maloor 	u_int16_t family;
461cf8d0a6dSKishen Maloor 	u_int32_t token;
462cf8d0a6dSKishen Maloor 	u_int16_t port;
463cf8d0a6dSKishen Maloor 	int addr_start;
464cf8d0a6dSKishen Maloor 	u_int8_t id;
465cf8d0a6dSKishen Maloor 	int off = 0;
466cf8d0a6dSKishen Maloor 	int arg;
467cf8d0a6dSKishen Maloor 
468cf8d0a6dSKishen Maloor 	memset(params, 0, 5 * sizeof(const char *));
469cf8d0a6dSKishen Maloor 
470cf8d0a6dSKishen Maloor 	memset(data, 0, sizeof(data));
471cf8d0a6dSKishen Maloor 	nh = (void *)data;
472cf8d0a6dSKishen Maloor 	off = init_genl_req(data, pm_family, MPTCP_PM_CMD_SUBFLOW_CREATE,
473cf8d0a6dSKishen Maloor 			    MPTCP_PM_VER);
474cf8d0a6dSKishen Maloor 
475cf8d0a6dSKishen Maloor 	if (argc < 12)
476cf8d0a6dSKishen Maloor 		syntax(argv);
477cf8d0a6dSKishen Maloor 
478cf8d0a6dSKishen Maloor 	/* Params recorded in this order:
479cf8d0a6dSKishen Maloor 	 * <local-ip>, <local-id>, <remote-ip>, <remote-port>, <token>
480cf8d0a6dSKishen Maloor 	 */
481cf8d0a6dSKishen Maloor 	for (arg = 2; arg < argc; arg++) {
482cf8d0a6dSKishen Maloor 		if (!strcmp(argv[arg], "lip")) {
483cf8d0a6dSKishen Maloor 			if (++arg >= argc)
484cf8d0a6dSKishen Maloor 				error(1, 0, " missing local IP");
485cf8d0a6dSKishen Maloor 
486cf8d0a6dSKishen Maloor 			params[0] = argv[arg];
487cf8d0a6dSKishen Maloor 		} else if (!strcmp(argv[arg], "lid")) {
488cf8d0a6dSKishen Maloor 			if (++arg >= argc)
489cf8d0a6dSKishen Maloor 				error(1, 0, " missing local id");
490cf8d0a6dSKishen Maloor 
491cf8d0a6dSKishen Maloor 			params[1] = argv[arg];
492cf8d0a6dSKishen Maloor 		} else if (!strcmp(argv[arg], "rip")) {
493cf8d0a6dSKishen Maloor 			if (++arg >= argc)
494cf8d0a6dSKishen Maloor 				error(1, 0, " missing remote ip");
495cf8d0a6dSKishen Maloor 
496cf8d0a6dSKishen Maloor 			params[2] = argv[arg];
497cf8d0a6dSKishen Maloor 		} else if (!strcmp(argv[arg], "rport")) {
498cf8d0a6dSKishen Maloor 			if (++arg >= argc)
499cf8d0a6dSKishen Maloor 				error(1, 0, " missing remote port");
500cf8d0a6dSKishen Maloor 
501cf8d0a6dSKishen Maloor 			params[3] = argv[arg];
502cf8d0a6dSKishen Maloor 		} else if (!strcmp(argv[arg], "token")) {
503cf8d0a6dSKishen Maloor 			if (++arg >= argc)
504cf8d0a6dSKishen Maloor 				error(1, 0, " missing token");
505cf8d0a6dSKishen Maloor 
506cf8d0a6dSKishen Maloor 			params[4] = argv[arg];
507cf8d0a6dSKishen Maloor 		} else
508cf8d0a6dSKishen Maloor 			error(1, 0, "unknown param %s", argv[arg]);
509cf8d0a6dSKishen Maloor 	}
510cf8d0a6dSKishen Maloor 
511cf8d0a6dSKishen Maloor 	for (arg = 0; arg < 4; arg = arg + 2) {
512cf8d0a6dSKishen Maloor 		/*  addr header */
513cf8d0a6dSKishen Maloor 		addr_start = off;
514cf8d0a6dSKishen Maloor 		addr = (void *)(data + off);
515cf8d0a6dSKishen Maloor 		addr->rta_type = NLA_F_NESTED |
516cf8d0a6dSKishen Maloor 			((arg == 0) ? MPTCP_PM_ATTR_ADDR : MPTCP_PM_ATTR_ADDR_REMOTE);
517cf8d0a6dSKishen Maloor 		addr->rta_len = RTA_LENGTH(0);
518cf8d0a6dSKishen Maloor 		off += NLMSG_ALIGN(addr->rta_len);
519cf8d0a6dSKishen Maloor 
520cf8d0a6dSKishen Maloor 		/*  addr data */
521cf8d0a6dSKishen Maloor 		rta = (void *)(data + off);
522cf8d0a6dSKishen Maloor 		if (inet_pton(AF_INET, params[arg], RTA_DATA(rta))) {
523cf8d0a6dSKishen Maloor 			family = AF_INET;
524cf8d0a6dSKishen Maloor 			rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR4;
525cf8d0a6dSKishen Maloor 			rta->rta_len = RTA_LENGTH(4);
526cf8d0a6dSKishen Maloor 		} else if (inet_pton(AF_INET6, params[arg], RTA_DATA(rta))) {
527cf8d0a6dSKishen Maloor 			family = AF_INET6;
528cf8d0a6dSKishen Maloor 			rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR6;
529cf8d0a6dSKishen Maloor 			rta->rta_len = RTA_LENGTH(16);
530cf8d0a6dSKishen Maloor 		} else
531cf8d0a6dSKishen Maloor 			error(1, errno, "can't parse ip %s", params[arg]);
532cf8d0a6dSKishen Maloor 		off += NLMSG_ALIGN(rta->rta_len);
533cf8d0a6dSKishen Maloor 
534cf8d0a6dSKishen Maloor 		/* family */
535cf8d0a6dSKishen Maloor 		rta = (void *)(data + off);
536cf8d0a6dSKishen Maloor 		rta->rta_type = MPTCP_PM_ADDR_ATTR_FAMILY;
537cf8d0a6dSKishen Maloor 		rta->rta_len = RTA_LENGTH(2);
538cf8d0a6dSKishen Maloor 		memcpy(RTA_DATA(rta), &family, 2);
539cf8d0a6dSKishen Maloor 		off += NLMSG_ALIGN(rta->rta_len);
540cf8d0a6dSKishen Maloor 
541cf8d0a6dSKishen Maloor 		if (arg == 2) {
542cf8d0a6dSKishen Maloor 			/*  port */
543cf8d0a6dSKishen Maloor 			port = atoi(params[arg + 1]);
544cf8d0a6dSKishen Maloor 			rta = (void *)(data + off);
545cf8d0a6dSKishen Maloor 			rta->rta_type = MPTCP_PM_ADDR_ATTR_PORT;
546cf8d0a6dSKishen Maloor 			rta->rta_len = RTA_LENGTH(2);
547cf8d0a6dSKishen Maloor 			memcpy(RTA_DATA(rta), &port, 2);
548cf8d0a6dSKishen Maloor 			off += NLMSG_ALIGN(rta->rta_len);
549cf8d0a6dSKishen Maloor 		}
550cf8d0a6dSKishen Maloor 
551cf8d0a6dSKishen Maloor 		if (arg == 0) {
552cf8d0a6dSKishen Maloor 			/* id */
553cf8d0a6dSKishen Maloor 			id = atoi(params[arg + 1]);
554cf8d0a6dSKishen Maloor 			rta = (void *)(data + off);
555cf8d0a6dSKishen Maloor 			rta->rta_type = MPTCP_PM_ADDR_ATTR_ID;
556cf8d0a6dSKishen Maloor 			rta->rta_len = RTA_LENGTH(1);
557cf8d0a6dSKishen Maloor 			memcpy(RTA_DATA(rta), &id, 1);
558cf8d0a6dSKishen Maloor 			off += NLMSG_ALIGN(rta->rta_len);
559cf8d0a6dSKishen Maloor 		}
560cf8d0a6dSKishen Maloor 
561cf8d0a6dSKishen Maloor 		addr->rta_len = off - addr_start;
562cf8d0a6dSKishen Maloor 	}
563cf8d0a6dSKishen Maloor 
564cf8d0a6dSKishen Maloor 	/* token */
56561d96580SMatthieu Baerts 	token = strtoul(params[4], NULL, 10);
566cf8d0a6dSKishen Maloor 	rta = (void *)(data + off);
567cf8d0a6dSKishen Maloor 	rta->rta_type = MPTCP_PM_ATTR_TOKEN;
568cf8d0a6dSKishen Maloor 	rta->rta_len = RTA_LENGTH(4);
569cf8d0a6dSKishen Maloor 	memcpy(RTA_DATA(rta), &token, 4);
570cf8d0a6dSKishen Maloor 	off += NLMSG_ALIGN(rta->rta_len);
571cf8d0a6dSKishen Maloor 
572cf8d0a6dSKishen Maloor 	do_nl_req(fd, nh, off, 0);
573cf8d0a6dSKishen Maloor 
574cf8d0a6dSKishen Maloor 	return 0;
575cf8d0a6dSKishen Maloor }
576cf8d0a6dSKishen Maloor 
remove_addr(int fd,int pm_family,int argc,char * argv[])577ecd2a77dSKishen Maloor int remove_addr(int fd, int pm_family, int argc, char *argv[])
578ecd2a77dSKishen Maloor {
579ecd2a77dSKishen Maloor 	char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
580ecd2a77dSKishen Maloor 		  NLMSG_ALIGN(sizeof(struct genlmsghdr)) +
581ecd2a77dSKishen Maloor 		  1024];
582ecd2a77dSKishen Maloor 	struct nlmsghdr *nh;
583ecd2a77dSKishen Maloor 	struct rtattr *rta;
584ecd2a77dSKishen Maloor 	u_int32_t token;
585ecd2a77dSKishen Maloor 	u_int8_t id;
586ecd2a77dSKishen Maloor 	int off = 0;
587ecd2a77dSKishen Maloor 	int arg;
588ecd2a77dSKishen Maloor 
589ecd2a77dSKishen Maloor 	memset(data, 0, sizeof(data));
590ecd2a77dSKishen Maloor 	nh = (void *)data;
591ecd2a77dSKishen Maloor 	off = init_genl_req(data, pm_family, MPTCP_PM_CMD_REMOVE,
592ecd2a77dSKishen Maloor 			    MPTCP_PM_VER);
593ecd2a77dSKishen Maloor 
594ecd2a77dSKishen Maloor 	if (argc < 6)
595ecd2a77dSKishen Maloor 		syntax(argv);
596ecd2a77dSKishen Maloor 
597ecd2a77dSKishen Maloor 	for (arg = 2; arg < argc; arg++) {
598ecd2a77dSKishen Maloor 		if (!strcmp(argv[arg], "id")) {
599ecd2a77dSKishen Maloor 			if (++arg >= argc)
600ecd2a77dSKishen Maloor 				error(1, 0, " missing id value");
601ecd2a77dSKishen Maloor 
602ecd2a77dSKishen Maloor 			id = atoi(argv[arg]);
603ecd2a77dSKishen Maloor 			rta = (void *)(data + off);
604ecd2a77dSKishen Maloor 			rta->rta_type = MPTCP_PM_ATTR_LOC_ID;
605ecd2a77dSKishen Maloor 			rta->rta_len = RTA_LENGTH(1);
606ecd2a77dSKishen Maloor 			memcpy(RTA_DATA(rta), &id, 1);
607ecd2a77dSKishen Maloor 			off += NLMSG_ALIGN(rta->rta_len);
608ecd2a77dSKishen Maloor 		} else if (!strcmp(argv[arg], "token")) {
609ecd2a77dSKishen Maloor 			if (++arg >= argc)
610ecd2a77dSKishen Maloor 				error(1, 0, " missing token value");
611ecd2a77dSKishen Maloor 
61261d96580SMatthieu Baerts 			token = strtoul(argv[arg], NULL, 10);
613ecd2a77dSKishen Maloor 			rta = (void *)(data + off);
614ecd2a77dSKishen Maloor 			rta->rta_type = MPTCP_PM_ATTR_TOKEN;
615ecd2a77dSKishen Maloor 			rta->rta_len = RTA_LENGTH(4);
616ecd2a77dSKishen Maloor 			memcpy(RTA_DATA(rta), &token, 4);
617ecd2a77dSKishen Maloor 			off += NLMSG_ALIGN(rta->rta_len);
618ecd2a77dSKishen Maloor 		} else
619ecd2a77dSKishen Maloor 			error(1, 0, "unknown keyword %s", argv[arg]);
620ecd2a77dSKishen Maloor 	}
621ecd2a77dSKishen Maloor 
622ecd2a77dSKishen Maloor 	do_nl_req(fd, nh, off, 0);
623ecd2a77dSKishen Maloor 	return 0;
624ecd2a77dSKishen Maloor }
625ecd2a77dSKishen Maloor 
announce_addr(int fd,int pm_family,int argc,char * argv[])6269a0b3650SKishen Maloor int announce_addr(int fd, int pm_family, int argc, char *argv[])
6279a0b3650SKishen Maloor {
6289a0b3650SKishen Maloor 	char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
6299a0b3650SKishen Maloor 		  NLMSG_ALIGN(sizeof(struct genlmsghdr)) +
6309a0b3650SKishen Maloor 		  1024];
6319a0b3650SKishen Maloor 	u_int32_t flags = MPTCP_PM_ADDR_FLAG_SIGNAL;
6329a0b3650SKishen Maloor 	u_int32_t token = UINT_MAX;
6339a0b3650SKishen Maloor 	struct rtattr *rta, *addr;
6349a0b3650SKishen Maloor 	u_int32_t id = UINT_MAX;
6359a0b3650SKishen Maloor 	struct nlmsghdr *nh;
6369a0b3650SKishen Maloor 	u_int16_t family;
6379a0b3650SKishen Maloor 	int addr_start;
6389a0b3650SKishen Maloor 	int off = 0;
6399a0b3650SKishen Maloor 	int arg;
6409a0b3650SKishen Maloor 
6419a0b3650SKishen Maloor 	memset(data, 0, sizeof(data));
6429a0b3650SKishen Maloor 	nh = (void *)data;
6439a0b3650SKishen Maloor 	off = init_genl_req(data, pm_family, MPTCP_PM_CMD_ANNOUNCE,
6449a0b3650SKishen Maloor 			    MPTCP_PM_VER);
6459a0b3650SKishen Maloor 
6469a0b3650SKishen Maloor 	if (argc < 7)
6479a0b3650SKishen Maloor 		syntax(argv);
6489a0b3650SKishen Maloor 
6499a0b3650SKishen Maloor 	/* local-ip header */
6509a0b3650SKishen Maloor 	addr_start = off;
6519a0b3650SKishen Maloor 	addr = (void *)(data + off);
6529a0b3650SKishen Maloor 	addr->rta_type = NLA_F_NESTED | MPTCP_PM_ATTR_ADDR;
6539a0b3650SKishen Maloor 	addr->rta_len = RTA_LENGTH(0);
6549a0b3650SKishen Maloor 	off += NLMSG_ALIGN(addr->rta_len);
6559a0b3650SKishen Maloor 
6569a0b3650SKishen Maloor 	/* local-ip data */
6579a0b3650SKishen Maloor 	/* record addr type */
6589a0b3650SKishen Maloor 	rta = (void *)(data + off);
6599a0b3650SKishen Maloor 	if (inet_pton(AF_INET, argv[2], RTA_DATA(rta))) {
6609a0b3650SKishen Maloor 		family = AF_INET;
6619a0b3650SKishen Maloor 		rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR4;
6629a0b3650SKishen Maloor 		rta->rta_len = RTA_LENGTH(4);
6639a0b3650SKishen Maloor 	} else if (inet_pton(AF_INET6, argv[2], RTA_DATA(rta))) {
6649a0b3650SKishen Maloor 		family = AF_INET6;
6659a0b3650SKishen Maloor 		rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR6;
6669a0b3650SKishen Maloor 		rta->rta_len = RTA_LENGTH(16);
6679a0b3650SKishen Maloor 	} else
6689a0b3650SKishen Maloor 		error(1, errno, "can't parse ip %s", argv[2]);
6699a0b3650SKishen Maloor 	off += NLMSG_ALIGN(rta->rta_len);
6709a0b3650SKishen Maloor 
6719a0b3650SKishen Maloor 	/* addr family */
6729a0b3650SKishen Maloor 	rta = (void *)(data + off);
6739a0b3650SKishen Maloor 	rta->rta_type = MPTCP_PM_ADDR_ATTR_FAMILY;
6749a0b3650SKishen Maloor 	rta->rta_len = RTA_LENGTH(2);
6759a0b3650SKishen Maloor 	memcpy(RTA_DATA(rta), &family, 2);
6769a0b3650SKishen Maloor 	off += NLMSG_ALIGN(rta->rta_len);
6779a0b3650SKishen Maloor 
6789a0b3650SKishen Maloor 	for (arg = 3; arg < argc; arg++) {
6799a0b3650SKishen Maloor 		if (!strcmp(argv[arg], "id")) {
6809a0b3650SKishen Maloor 			/* local-id */
6819a0b3650SKishen Maloor 			if (++arg >= argc)
6829a0b3650SKishen Maloor 				error(1, 0, " missing id value");
6839a0b3650SKishen Maloor 
6849a0b3650SKishen Maloor 			id = atoi(argv[arg]);
6859a0b3650SKishen Maloor 			rta = (void *)(data + off);
6869a0b3650SKishen Maloor 			rta->rta_type = MPTCP_PM_ADDR_ATTR_ID;
6879a0b3650SKishen Maloor 			rta->rta_len = RTA_LENGTH(1);
6889a0b3650SKishen Maloor 			memcpy(RTA_DATA(rta), &id, 1);
6899a0b3650SKishen Maloor 			off += NLMSG_ALIGN(rta->rta_len);
6909a0b3650SKishen Maloor 		} else if (!strcmp(argv[arg], "dev")) {
6919a0b3650SKishen Maloor 			/* for the if_index */
6929a0b3650SKishen Maloor 			int32_t ifindex;
6939a0b3650SKishen Maloor 
6949a0b3650SKishen Maloor 			if (++arg >= argc)
6959a0b3650SKishen Maloor 				error(1, 0, " missing dev name");
6969a0b3650SKishen Maloor 
6979a0b3650SKishen Maloor 			ifindex = if_nametoindex(argv[arg]);
6989a0b3650SKishen Maloor 			if (!ifindex)
6999a0b3650SKishen Maloor 				error(1, errno, "unknown device %s", argv[arg]);
7009a0b3650SKishen Maloor 
7019a0b3650SKishen Maloor 			rta = (void *)(data + off);
7029a0b3650SKishen Maloor 			rta->rta_type = MPTCP_PM_ADDR_ATTR_IF_IDX;
7039a0b3650SKishen Maloor 			rta->rta_len = RTA_LENGTH(4);
7049a0b3650SKishen Maloor 			memcpy(RTA_DATA(rta), &ifindex, 4);
7059a0b3650SKishen Maloor 			off += NLMSG_ALIGN(rta->rta_len);
7069a0b3650SKishen Maloor 		} else if (!strcmp(argv[arg], "port")) {
7079a0b3650SKishen Maloor 			/* local-port (optional) */
7089a0b3650SKishen Maloor 			u_int16_t port;
7099a0b3650SKishen Maloor 
7109a0b3650SKishen Maloor 			if (++arg >= argc)
7119a0b3650SKishen Maloor 				error(1, 0, " missing port value");
7129a0b3650SKishen Maloor 
7139a0b3650SKishen Maloor 			port = atoi(argv[arg]);
7149a0b3650SKishen Maloor 			rta = (void *)(data + off);
7159a0b3650SKishen Maloor 			rta->rta_type = MPTCP_PM_ADDR_ATTR_PORT;
7169a0b3650SKishen Maloor 			rta->rta_len = RTA_LENGTH(2);
7179a0b3650SKishen Maloor 			memcpy(RTA_DATA(rta), &port, 2);
7189a0b3650SKishen Maloor 			off += NLMSG_ALIGN(rta->rta_len);
7199a0b3650SKishen Maloor 		} else if (!strcmp(argv[arg], "token")) {
7209a0b3650SKishen Maloor 			/* MPTCP connection token */
7219a0b3650SKishen Maloor 			if (++arg >= argc)
7229a0b3650SKishen Maloor 				error(1, 0, " missing token value");
7239a0b3650SKishen Maloor 
72461d96580SMatthieu Baerts 			token = strtoul(argv[arg], NULL, 10);
7259a0b3650SKishen Maloor 		} else
7269a0b3650SKishen Maloor 			error(1, 0, "unknown keyword %s", argv[arg]);
7279a0b3650SKishen Maloor 	}
7289a0b3650SKishen Maloor 
7299a0b3650SKishen Maloor 	/* addr flags */
7309a0b3650SKishen Maloor 	rta = (void *)(data + off);
7319a0b3650SKishen Maloor 	rta->rta_type = MPTCP_PM_ADDR_ATTR_FLAGS;
7329a0b3650SKishen Maloor 	rta->rta_len = RTA_LENGTH(4);
7339a0b3650SKishen Maloor 	memcpy(RTA_DATA(rta), &flags, 4);
7349a0b3650SKishen Maloor 	off += NLMSG_ALIGN(rta->rta_len);
7359a0b3650SKishen Maloor 
7369a0b3650SKishen Maloor 	addr->rta_len = off - addr_start;
7379a0b3650SKishen Maloor 
7389a0b3650SKishen Maloor 	if (id == UINT_MAX || token == UINT_MAX)
7399a0b3650SKishen Maloor 		error(1, 0, " missing mandatory inputs");
7409a0b3650SKishen Maloor 
7419a0b3650SKishen Maloor 	/* token */
7429a0b3650SKishen Maloor 	rta = (void *)(data + off);
7439a0b3650SKishen Maloor 	rta->rta_type = MPTCP_PM_ATTR_TOKEN;
7449a0b3650SKishen Maloor 	rta->rta_len = RTA_LENGTH(4);
7459a0b3650SKishen Maloor 	memcpy(RTA_DATA(rta), &token, 4);
7469a0b3650SKishen Maloor 	off += NLMSG_ALIGN(rta->rta_len);
7479a0b3650SKishen Maloor 
7489a0b3650SKishen Maloor 	do_nl_req(fd, nh, off, 0);
7499a0b3650SKishen Maloor 
7509a0b3650SKishen Maloor 	return 0;
7519a0b3650SKishen Maloor }
7529a0b3650SKishen Maloor 
add_addr(int fd,int pm_family,int argc,char * argv[])753eedbc685SPaolo Abeni int add_addr(int fd, int pm_family, int argc, char *argv[])
754eedbc685SPaolo Abeni {
755eedbc685SPaolo Abeni 	char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
756eedbc685SPaolo Abeni 		  NLMSG_ALIGN(sizeof(struct genlmsghdr)) +
757eedbc685SPaolo Abeni 		  1024];
758eedbc685SPaolo Abeni 	struct rtattr *rta, *nest;
759eedbc685SPaolo Abeni 	struct nlmsghdr *nh;
760d4a7726aSGeliang Tang 	u_int32_t flags = 0;
761eedbc685SPaolo Abeni 	u_int16_t family;
762eedbc685SPaolo Abeni 	int nest_start;
763eedbc685SPaolo Abeni 	u_int8_t id;
764eedbc685SPaolo Abeni 	int off = 0;
765eedbc685SPaolo Abeni 	int arg;
766eedbc685SPaolo Abeni 
767eedbc685SPaolo Abeni 	memset(data, 0, sizeof(data));
768eedbc685SPaolo Abeni 	nh = (void *)data;
769eedbc685SPaolo Abeni 	off = init_genl_req(data, pm_family, MPTCP_PM_CMD_ADD_ADDR,
770eedbc685SPaolo Abeni 			    MPTCP_PM_VER);
771eedbc685SPaolo Abeni 
772eedbc685SPaolo Abeni 	if (argc < 3)
773eedbc685SPaolo Abeni 		syntax(argv);
774eedbc685SPaolo Abeni 
775eedbc685SPaolo Abeni 	nest_start = off;
776eedbc685SPaolo Abeni 	nest = (void *)(data + off);
777eedbc685SPaolo Abeni 	nest->rta_type = NLA_F_NESTED | MPTCP_PM_ATTR_ADDR;
778eedbc685SPaolo Abeni 	nest->rta_len = RTA_LENGTH(0);
779eedbc685SPaolo Abeni 	off += NLMSG_ALIGN(nest->rta_len);
780eedbc685SPaolo Abeni 
781eedbc685SPaolo Abeni 	/* addr data */
782eedbc685SPaolo Abeni 	rta = (void *)(data + off);
783eedbc685SPaolo Abeni 	if (inet_pton(AF_INET, argv[2], RTA_DATA(rta))) {
784eedbc685SPaolo Abeni 		family = AF_INET;
785eedbc685SPaolo Abeni 		rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR4;
786eedbc685SPaolo Abeni 		rta->rta_len = RTA_LENGTH(4);
787eedbc685SPaolo Abeni 	} else if (inet_pton(AF_INET6, argv[2], RTA_DATA(rta))) {
788eedbc685SPaolo Abeni 		family = AF_INET6;
789eedbc685SPaolo Abeni 		rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR6;
790eedbc685SPaolo Abeni 		rta->rta_len = RTA_LENGTH(16);
791eedbc685SPaolo Abeni 	} else
792eedbc685SPaolo Abeni 		error(1, errno, "can't parse ip %s", argv[2]);
793eedbc685SPaolo Abeni 	off += NLMSG_ALIGN(rta->rta_len);
794eedbc685SPaolo Abeni 
795eedbc685SPaolo Abeni 	/* family */
796eedbc685SPaolo Abeni 	rta = (void *)(data + off);
797eedbc685SPaolo Abeni 	rta->rta_type = MPTCP_PM_ADDR_ATTR_FAMILY;
798eedbc685SPaolo Abeni 	rta->rta_len = RTA_LENGTH(2);
799eedbc685SPaolo Abeni 	memcpy(RTA_DATA(rta), &family, 2);
800eedbc685SPaolo Abeni 	off += NLMSG_ALIGN(rta->rta_len);
801eedbc685SPaolo Abeni 
802eedbc685SPaolo Abeni 	for (arg = 3; arg < argc; arg++) {
803eedbc685SPaolo Abeni 		if (!strcmp(argv[arg], "flags")) {
804eedbc685SPaolo Abeni 			char *tok, *str;
805eedbc685SPaolo Abeni 
806eedbc685SPaolo Abeni 			/* flags */
807eedbc685SPaolo Abeni 			if (++arg >= argc)
808eedbc685SPaolo Abeni 				error(1, 0, " missing flags value");
809eedbc685SPaolo Abeni 
810eedbc685SPaolo Abeni 			/* do not support flag list yet */
811eedbc685SPaolo Abeni 			for (str = argv[arg]; (tok = strtok(str, ","));
812eedbc685SPaolo Abeni 			     str = NULL) {
813eedbc685SPaolo Abeni 				if (!strcmp(tok, "subflow"))
814eedbc685SPaolo Abeni 					flags |= MPTCP_PM_ADDR_FLAG_SUBFLOW;
815eedbc685SPaolo Abeni 				else if (!strcmp(tok, "signal"))
816eedbc685SPaolo Abeni 					flags |= MPTCP_PM_ADDR_FLAG_SIGNAL;
817eedbc685SPaolo Abeni 				else if (!strcmp(tok, "backup"))
818eedbc685SPaolo Abeni 					flags |= MPTCP_PM_ADDR_FLAG_BACKUP;
819371b9037SGeliang Tang 				else if (!strcmp(tok, "fullmesh"))
820371b9037SGeliang Tang 					flags |= MPTCP_PM_ADDR_FLAG_FULLMESH;
821eedbc685SPaolo Abeni 				else
822eedbc685SPaolo Abeni 					error(1, errno,
823eedbc685SPaolo Abeni 					      "unknown flag %s", argv[arg]);
824eedbc685SPaolo Abeni 			}
825eedbc685SPaolo Abeni 
826371b9037SGeliang Tang 			if (flags & MPTCP_PM_ADDR_FLAG_SIGNAL &&
827371b9037SGeliang Tang 			    flags & MPTCP_PM_ADDR_FLAG_FULLMESH) {
828371b9037SGeliang Tang 				error(1, errno, "error flag fullmesh");
829371b9037SGeliang Tang 			}
830371b9037SGeliang Tang 
831eedbc685SPaolo Abeni 			rta = (void *)(data + off);
832eedbc685SPaolo Abeni 			rta->rta_type = MPTCP_PM_ADDR_ATTR_FLAGS;
833eedbc685SPaolo Abeni 			rta->rta_len = RTA_LENGTH(4);
834eedbc685SPaolo Abeni 			memcpy(RTA_DATA(rta), &flags, 4);
835eedbc685SPaolo Abeni 			off += NLMSG_ALIGN(rta->rta_len);
836eedbc685SPaolo Abeni 		} else if (!strcmp(argv[arg], "id")) {
837eedbc685SPaolo Abeni 			if (++arg >= argc)
838eedbc685SPaolo Abeni 				error(1, 0, " missing id value");
839eedbc685SPaolo Abeni 
840eedbc685SPaolo Abeni 			id = atoi(argv[arg]);
841eedbc685SPaolo Abeni 			rta = (void *)(data + off);
842eedbc685SPaolo Abeni 			rta->rta_type = MPTCP_PM_ADDR_ATTR_ID;
843eedbc685SPaolo Abeni 			rta->rta_len = RTA_LENGTH(1);
844eedbc685SPaolo Abeni 			memcpy(RTA_DATA(rta), &id, 1);
845eedbc685SPaolo Abeni 			off += NLMSG_ALIGN(rta->rta_len);
846eedbc685SPaolo Abeni 		} else if (!strcmp(argv[arg], "dev")) {
847eedbc685SPaolo Abeni 			int32_t ifindex;
848eedbc685SPaolo Abeni 
849eedbc685SPaolo Abeni 			if (++arg >= argc)
850eedbc685SPaolo Abeni 				error(1, 0, " missing dev name");
851eedbc685SPaolo Abeni 
852eedbc685SPaolo Abeni 			ifindex = if_nametoindex(argv[arg]);
853eedbc685SPaolo Abeni 			if (!ifindex)
854eedbc685SPaolo Abeni 				error(1, errno, "unknown device %s", argv[arg]);
855eedbc685SPaolo Abeni 
856eedbc685SPaolo Abeni 			rta = (void *)(data + off);
857eedbc685SPaolo Abeni 			rta->rta_type = MPTCP_PM_ADDR_ATTR_IF_IDX;
858eedbc685SPaolo Abeni 			rta->rta_len = RTA_LENGTH(4);
859eedbc685SPaolo Abeni 			memcpy(RTA_DATA(rta), &ifindex, 4);
860eedbc685SPaolo Abeni 			off += NLMSG_ALIGN(rta->rta_len);
861d4a7726aSGeliang Tang 		} else if (!strcmp(argv[arg], "port")) {
862d4a7726aSGeliang Tang 			u_int16_t port;
863d4a7726aSGeliang Tang 
864d4a7726aSGeliang Tang 			if (++arg >= argc)
865d4a7726aSGeliang Tang 				error(1, 0, " missing port value");
866d4a7726aSGeliang Tang 			if (!(flags & MPTCP_PM_ADDR_FLAG_SIGNAL))
867d4a7726aSGeliang Tang 				error(1, 0, " flags must be signal when using port");
868d4a7726aSGeliang Tang 
869d4a7726aSGeliang Tang 			port = atoi(argv[arg]);
870d4a7726aSGeliang Tang 			rta = (void *)(data + off);
871d4a7726aSGeliang Tang 			rta->rta_type = MPTCP_PM_ADDR_ATTR_PORT;
872d4a7726aSGeliang Tang 			rta->rta_len = RTA_LENGTH(2);
873d4a7726aSGeliang Tang 			memcpy(RTA_DATA(rta), &port, 2);
874d4a7726aSGeliang Tang 			off += NLMSG_ALIGN(rta->rta_len);
875eedbc685SPaolo Abeni 		} else
876eedbc685SPaolo Abeni 			error(1, 0, "unknown keyword %s", argv[arg]);
877eedbc685SPaolo Abeni 	}
878eedbc685SPaolo Abeni 	nest->rta_len = off - nest_start;
879eedbc685SPaolo Abeni 
880eedbc685SPaolo Abeni 	do_nl_req(fd, nh, off, 0);
881eedbc685SPaolo Abeni 	return 0;
882eedbc685SPaolo Abeni }
883eedbc685SPaolo Abeni 
del_addr(int fd,int pm_family,int argc,char * argv[])884eedbc685SPaolo Abeni int del_addr(int fd, int pm_family, int argc, char *argv[])
885eedbc685SPaolo Abeni {
886eedbc685SPaolo Abeni 	char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
887eedbc685SPaolo Abeni 		  NLMSG_ALIGN(sizeof(struct genlmsghdr)) +
888eedbc685SPaolo Abeni 		  1024];
889eedbc685SPaolo Abeni 	struct rtattr *rta, *nest;
890eedbc685SPaolo Abeni 	struct nlmsghdr *nh;
8912d121c9aSGeliang Tang 	u_int16_t family;
892eedbc685SPaolo Abeni 	int nest_start;
893eedbc685SPaolo Abeni 	u_int8_t id;
894eedbc685SPaolo Abeni 	int off = 0;
895eedbc685SPaolo Abeni 
896eedbc685SPaolo Abeni 	memset(data, 0, sizeof(data));
897eedbc685SPaolo Abeni 	nh = (void *)data;
898eedbc685SPaolo Abeni 	off = init_genl_req(data, pm_family, MPTCP_PM_CMD_DEL_ADDR,
899eedbc685SPaolo Abeni 			    MPTCP_PM_VER);
900eedbc685SPaolo Abeni 
9012d121c9aSGeliang Tang 	/* the only argument is the address id (nonzero) */
9022d121c9aSGeliang Tang 	if (argc != 3 && argc != 4)
903eedbc685SPaolo Abeni 		syntax(argv);
904eedbc685SPaolo Abeni 
905eedbc685SPaolo Abeni 	id = atoi(argv[2]);
9062d121c9aSGeliang Tang 	/* zero id with the IP address */
9072d121c9aSGeliang Tang 	if (!id && argc != 4)
9082d121c9aSGeliang Tang 		syntax(argv);
909eedbc685SPaolo Abeni 
910eedbc685SPaolo Abeni 	nest_start = off;
911eedbc685SPaolo Abeni 	nest = (void *)(data + off);
912eedbc685SPaolo Abeni 	nest->rta_type = NLA_F_NESTED | MPTCP_PM_ATTR_ADDR;
913eedbc685SPaolo Abeni 	nest->rta_len =  RTA_LENGTH(0);
914eedbc685SPaolo Abeni 	off += NLMSG_ALIGN(nest->rta_len);
915eedbc685SPaolo Abeni 
916eedbc685SPaolo Abeni 	/* build a dummy addr with only the ID set */
917eedbc685SPaolo Abeni 	rta = (void *)(data + off);
918eedbc685SPaolo Abeni 	rta->rta_type = MPTCP_PM_ADDR_ATTR_ID;
919eedbc685SPaolo Abeni 	rta->rta_len = RTA_LENGTH(1);
920eedbc685SPaolo Abeni 	memcpy(RTA_DATA(rta), &id, 1);
921eedbc685SPaolo Abeni 	off += NLMSG_ALIGN(rta->rta_len);
9222d121c9aSGeliang Tang 
9232d121c9aSGeliang Tang 	if (!id) {
9242d121c9aSGeliang Tang 		/* addr data */
9252d121c9aSGeliang Tang 		rta = (void *)(data + off);
9262d121c9aSGeliang Tang 		if (inet_pton(AF_INET, argv[3], RTA_DATA(rta))) {
9272d121c9aSGeliang Tang 			family = AF_INET;
9282d121c9aSGeliang Tang 			rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR4;
9292d121c9aSGeliang Tang 			rta->rta_len = RTA_LENGTH(4);
9302d121c9aSGeliang Tang 		} else if (inet_pton(AF_INET6, argv[3], RTA_DATA(rta))) {
9312d121c9aSGeliang Tang 			family = AF_INET6;
9322d121c9aSGeliang Tang 			rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR6;
9332d121c9aSGeliang Tang 			rta->rta_len = RTA_LENGTH(16);
9342d121c9aSGeliang Tang 		} else {
9352d121c9aSGeliang Tang 			error(1, errno, "can't parse ip %s", argv[3]);
9362d121c9aSGeliang Tang 		}
9372d121c9aSGeliang Tang 		off += NLMSG_ALIGN(rta->rta_len);
9382d121c9aSGeliang Tang 
9392d121c9aSGeliang Tang 		/* family */
9402d121c9aSGeliang Tang 		rta = (void *)(data + off);
9412d121c9aSGeliang Tang 		rta->rta_type = MPTCP_PM_ADDR_ATTR_FAMILY;
9422d121c9aSGeliang Tang 		rta->rta_len = RTA_LENGTH(2);
9432d121c9aSGeliang Tang 		memcpy(RTA_DATA(rta), &family, 2);
9442d121c9aSGeliang Tang 		off += NLMSG_ALIGN(rta->rta_len);
9452d121c9aSGeliang Tang 	}
946eedbc685SPaolo Abeni 	nest->rta_len = off - nest_start;
947eedbc685SPaolo Abeni 
948eedbc685SPaolo Abeni 	do_nl_req(fd, nh, off, 0);
949eedbc685SPaolo Abeni 	return 0;
950eedbc685SPaolo Abeni }
951eedbc685SPaolo Abeni 
print_addr(struct rtattr * attrs,int len)952eedbc685SPaolo Abeni static void print_addr(struct rtattr *attrs, int len)
953eedbc685SPaolo Abeni {
954eedbc685SPaolo Abeni 	uint16_t family = 0;
955d4a7726aSGeliang Tang 	uint16_t port = 0;
956eedbc685SPaolo Abeni 	char str[1024];
957eedbc685SPaolo Abeni 	uint32_t flags;
958eedbc685SPaolo Abeni 	uint8_t id;
959eedbc685SPaolo Abeni 
960eedbc685SPaolo Abeni 	while (RTA_OK(attrs, len)) {
961eedbc685SPaolo Abeni 		if (attrs->rta_type == MPTCP_PM_ADDR_ATTR_FAMILY)
962eedbc685SPaolo Abeni 			memcpy(&family, RTA_DATA(attrs), 2);
963d4a7726aSGeliang Tang 		if (attrs->rta_type == MPTCP_PM_ADDR_ATTR_PORT)
964d4a7726aSGeliang Tang 			memcpy(&port, RTA_DATA(attrs), 2);
965eedbc685SPaolo Abeni 		if (attrs->rta_type == MPTCP_PM_ADDR_ATTR_ADDR4) {
966eedbc685SPaolo Abeni 			if (family != AF_INET)
967eedbc685SPaolo Abeni 				error(1, errno, "wrong IP (v4) for family %d",
968eedbc685SPaolo Abeni 				      family);
969eedbc685SPaolo Abeni 			inet_ntop(AF_INET, RTA_DATA(attrs), str, sizeof(str));
970eedbc685SPaolo Abeni 			printf("%s", str);
971d4a7726aSGeliang Tang 			if (port)
972d4a7726aSGeliang Tang 				printf(" %d", port);
973eedbc685SPaolo Abeni 		}
974eedbc685SPaolo Abeni 		if (attrs->rta_type == MPTCP_PM_ADDR_ATTR_ADDR6) {
975eedbc685SPaolo Abeni 			if (family != AF_INET6)
976eedbc685SPaolo Abeni 				error(1, errno, "wrong IP (v6) for family %d",
977eedbc685SPaolo Abeni 				      family);
978eedbc685SPaolo Abeni 			inet_ntop(AF_INET6, RTA_DATA(attrs), str, sizeof(str));
979eedbc685SPaolo Abeni 			printf("%s", str);
980d4a7726aSGeliang Tang 			if (port)
981d4a7726aSGeliang Tang 				printf(" %d", port);
982eedbc685SPaolo Abeni 		}
983eedbc685SPaolo Abeni 		if (attrs->rta_type == MPTCP_PM_ADDR_ATTR_ID) {
984eedbc685SPaolo Abeni 			memcpy(&id, RTA_DATA(attrs), 1);
985eedbc685SPaolo Abeni 			printf("id %d ", id);
986eedbc685SPaolo Abeni 		}
987eedbc685SPaolo Abeni 		if (attrs->rta_type == MPTCP_PM_ADDR_ATTR_FLAGS) {
988eedbc685SPaolo Abeni 			memcpy(&flags, RTA_DATA(attrs), 4);
989eedbc685SPaolo Abeni 
990eedbc685SPaolo Abeni 			printf("flags ");
991eedbc685SPaolo Abeni 			if (flags & MPTCP_PM_ADDR_FLAG_SIGNAL) {
992eedbc685SPaolo Abeni 				printf("signal");
993eedbc685SPaolo Abeni 				flags &= ~MPTCP_PM_ADDR_FLAG_SIGNAL;
994eedbc685SPaolo Abeni 				if (flags)
995eedbc685SPaolo Abeni 					printf(",");
996eedbc685SPaolo Abeni 			}
997eedbc685SPaolo Abeni 
998eedbc685SPaolo Abeni 			if (flags & MPTCP_PM_ADDR_FLAG_SUBFLOW) {
999eedbc685SPaolo Abeni 				printf("subflow");
1000eedbc685SPaolo Abeni 				flags &= ~MPTCP_PM_ADDR_FLAG_SUBFLOW;
1001eedbc685SPaolo Abeni 				if (flags)
1002eedbc685SPaolo Abeni 					printf(",");
1003eedbc685SPaolo Abeni 			}
1004eedbc685SPaolo Abeni 
1005eedbc685SPaolo Abeni 			if (flags & MPTCP_PM_ADDR_FLAG_BACKUP) {
1006eedbc685SPaolo Abeni 				printf("backup");
1007eedbc685SPaolo Abeni 				flags &= ~MPTCP_PM_ADDR_FLAG_BACKUP;
1008eedbc685SPaolo Abeni 				if (flags)
1009eedbc685SPaolo Abeni 					printf(",");
1010eedbc685SPaolo Abeni 			}
1011eedbc685SPaolo Abeni 
1012371b9037SGeliang Tang 			if (flags & MPTCP_PM_ADDR_FLAG_FULLMESH) {
1013371b9037SGeliang Tang 				printf("fullmesh");
1014371b9037SGeliang Tang 				flags &= ~MPTCP_PM_ADDR_FLAG_FULLMESH;
1015371b9037SGeliang Tang 				if (flags)
1016371b9037SGeliang Tang 					printf(",");
1017371b9037SGeliang Tang 			}
1018371b9037SGeliang Tang 
101969c6ce7bSPaolo Abeni 			if (flags & MPTCP_PM_ADDR_FLAG_IMPLICIT) {
102069c6ce7bSPaolo Abeni 				printf("implicit");
102169c6ce7bSPaolo Abeni 				flags &= ~MPTCP_PM_ADDR_FLAG_IMPLICIT;
102269c6ce7bSPaolo Abeni 				if (flags)
102369c6ce7bSPaolo Abeni 					printf(",");
102469c6ce7bSPaolo Abeni 			}
102569c6ce7bSPaolo Abeni 
1026eedbc685SPaolo Abeni 			/* bump unknown flags, if any */
1027eedbc685SPaolo Abeni 			if (flags)
1028eedbc685SPaolo Abeni 				printf("0x%x", flags);
1029eedbc685SPaolo Abeni 			printf(" ");
1030eedbc685SPaolo Abeni 		}
1031eedbc685SPaolo Abeni 		if (attrs->rta_type == MPTCP_PM_ADDR_ATTR_IF_IDX) {
1032eedbc685SPaolo Abeni 			char name[IF_NAMESIZE], *ret;
1033eedbc685SPaolo Abeni 			int32_t ifindex;
1034eedbc685SPaolo Abeni 
1035eedbc685SPaolo Abeni 			memcpy(&ifindex, RTA_DATA(attrs), 4);
1036eedbc685SPaolo Abeni 			ret = if_indextoname(ifindex, name);
1037eedbc685SPaolo Abeni 			if (ret)
1038eedbc685SPaolo Abeni 				printf("dev %s ", ret);
1039eedbc685SPaolo Abeni 			else
1040eedbc685SPaolo Abeni 				printf("dev unknown/%d", ifindex);
1041eedbc685SPaolo Abeni 		}
1042eedbc685SPaolo Abeni 
1043eedbc685SPaolo Abeni 		attrs = RTA_NEXT(attrs, len);
1044eedbc685SPaolo Abeni 	}
1045eedbc685SPaolo Abeni 	printf("\n");
1046eedbc685SPaolo Abeni }
1047eedbc685SPaolo Abeni 
print_addrs(struct nlmsghdr * nh,int pm_family,int total_len)1048eedbc685SPaolo Abeni static void print_addrs(struct nlmsghdr *nh, int pm_family, int total_len)
1049eedbc685SPaolo Abeni {
1050eedbc685SPaolo Abeni 	struct rtattr *attrs;
1051eedbc685SPaolo Abeni 
1052eedbc685SPaolo Abeni 	for (; NLMSG_OK(nh, total_len); nh = NLMSG_NEXT(nh, total_len)) {
1053eedbc685SPaolo Abeni 		int len = nh->nlmsg_len;
1054eedbc685SPaolo Abeni 
1055eedbc685SPaolo Abeni 		if (nh->nlmsg_type == NLMSG_DONE)
1056eedbc685SPaolo Abeni 			break;
1057eedbc685SPaolo Abeni 		if (nh->nlmsg_type == NLMSG_ERROR)
1058eedbc685SPaolo Abeni 			nl_error(nh);
1059eedbc685SPaolo Abeni 		if (nh->nlmsg_type != pm_family)
1060eedbc685SPaolo Abeni 			continue;
1061eedbc685SPaolo Abeni 
1062eedbc685SPaolo Abeni 		len -= NLMSG_LENGTH(GENL_HDRLEN);
1063eedbc685SPaolo Abeni 		attrs = (struct rtattr *) ((char *) NLMSG_DATA(nh) +
1064eedbc685SPaolo Abeni 					   GENL_HDRLEN);
1065eedbc685SPaolo Abeni 		while (RTA_OK(attrs, len)) {
1066eedbc685SPaolo Abeni 			if (attrs->rta_type ==
1067eedbc685SPaolo Abeni 			    (MPTCP_PM_ATTR_ADDR | NLA_F_NESTED))
1068eedbc685SPaolo Abeni 				print_addr((void *)RTA_DATA(attrs),
1069eedbc685SPaolo Abeni 					   attrs->rta_len);
1070eedbc685SPaolo Abeni 			attrs = RTA_NEXT(attrs, len);
1071eedbc685SPaolo Abeni 		}
1072eedbc685SPaolo Abeni 	}
1073eedbc685SPaolo Abeni }
1074eedbc685SPaolo Abeni 
get_addr(int fd,int pm_family,int argc,char * argv[])1075eedbc685SPaolo Abeni int get_addr(int fd, int pm_family, int argc, char *argv[])
1076eedbc685SPaolo Abeni {
1077eedbc685SPaolo Abeni 	char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
1078eedbc685SPaolo Abeni 		  NLMSG_ALIGN(sizeof(struct genlmsghdr)) +
1079eedbc685SPaolo Abeni 		  1024];
1080eedbc685SPaolo Abeni 	struct rtattr *rta, *nest;
1081eedbc685SPaolo Abeni 	struct nlmsghdr *nh;
1082eedbc685SPaolo Abeni 	int nest_start;
1083eedbc685SPaolo Abeni 	u_int8_t id;
1084eedbc685SPaolo Abeni 	int off = 0;
1085eedbc685SPaolo Abeni 
1086eedbc685SPaolo Abeni 	memset(data, 0, sizeof(data));
1087eedbc685SPaolo Abeni 	nh = (void *)data;
1088eedbc685SPaolo Abeni 	off = init_genl_req(data, pm_family, MPTCP_PM_CMD_GET_ADDR,
1089eedbc685SPaolo Abeni 			    MPTCP_PM_VER);
1090eedbc685SPaolo Abeni 
1091eedbc685SPaolo Abeni 	/* the only argument is the address id */
1092eedbc685SPaolo Abeni 	if (argc != 3)
1093eedbc685SPaolo Abeni 		syntax(argv);
1094eedbc685SPaolo Abeni 
1095eedbc685SPaolo Abeni 	id = atoi(argv[2]);
1096eedbc685SPaolo Abeni 
1097eedbc685SPaolo Abeni 	nest_start = off;
1098eedbc685SPaolo Abeni 	nest = (void *)(data + off);
1099eedbc685SPaolo Abeni 	nest->rta_type = NLA_F_NESTED | MPTCP_PM_ATTR_ADDR;
1100eedbc685SPaolo Abeni 	nest->rta_len =  RTA_LENGTH(0);
1101eedbc685SPaolo Abeni 	off += NLMSG_ALIGN(nest->rta_len);
1102eedbc685SPaolo Abeni 
1103eedbc685SPaolo Abeni 	/* build a dummy addr with only the ID set */
1104eedbc685SPaolo Abeni 	rta = (void *)(data + off);
1105eedbc685SPaolo Abeni 	rta->rta_type = MPTCP_PM_ADDR_ATTR_ID;
1106eedbc685SPaolo Abeni 	rta->rta_len = RTA_LENGTH(1);
1107eedbc685SPaolo Abeni 	memcpy(RTA_DATA(rta), &id, 1);
1108eedbc685SPaolo Abeni 	off += NLMSG_ALIGN(rta->rta_len);
1109eedbc685SPaolo Abeni 	nest->rta_len = off - nest_start;
1110eedbc685SPaolo Abeni 
1111eedbc685SPaolo Abeni 	print_addrs(nh, pm_family, do_nl_req(fd, nh, off, sizeof(data)));
1112eedbc685SPaolo Abeni 	return 0;
1113eedbc685SPaolo Abeni }
1114eedbc685SPaolo Abeni 
dump_addrs(int fd,int pm_family,int argc,char * argv[])1115eedbc685SPaolo Abeni int dump_addrs(int fd, int pm_family, int argc, char *argv[])
1116eedbc685SPaolo Abeni {
1117eedbc685SPaolo Abeni 	char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
1118eedbc685SPaolo Abeni 		  NLMSG_ALIGN(sizeof(struct genlmsghdr)) +
1119eedbc685SPaolo Abeni 		  1024];
1120eedbc685SPaolo Abeni 	pid_t pid = getpid();
1121eedbc685SPaolo Abeni 	struct nlmsghdr *nh;
1122eedbc685SPaolo Abeni 	int off = 0;
1123eedbc685SPaolo Abeni 
1124eedbc685SPaolo Abeni 	memset(data, 0, sizeof(data));
1125eedbc685SPaolo Abeni 	nh = (void *)data;
1126eedbc685SPaolo Abeni 	off = init_genl_req(data, pm_family, MPTCP_PM_CMD_GET_ADDR,
1127eedbc685SPaolo Abeni 			    MPTCP_PM_VER);
1128eedbc685SPaolo Abeni 	nh->nlmsg_flags |= NLM_F_DUMP;
1129eedbc685SPaolo Abeni 	nh->nlmsg_seq = 1;
1130eedbc685SPaolo Abeni 	nh->nlmsg_pid = pid;
1131eedbc685SPaolo Abeni 	nh->nlmsg_len = off;
1132eedbc685SPaolo Abeni 
1133eedbc685SPaolo Abeni 	print_addrs(nh, pm_family, do_nl_req(fd, nh, off, sizeof(data)));
1134eedbc685SPaolo Abeni 	return 0;
1135eedbc685SPaolo Abeni }
1136eedbc685SPaolo Abeni 
flush_addrs(int fd,int pm_family,int argc,char * argv[])1137eedbc685SPaolo Abeni int flush_addrs(int fd, int pm_family, int argc, char *argv[])
1138eedbc685SPaolo Abeni {
1139eedbc685SPaolo Abeni 	char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
1140eedbc685SPaolo Abeni 		  NLMSG_ALIGN(sizeof(struct genlmsghdr)) +
1141eedbc685SPaolo Abeni 		  1024];
1142eedbc685SPaolo Abeni 	struct nlmsghdr *nh;
1143eedbc685SPaolo Abeni 	int off = 0;
1144eedbc685SPaolo Abeni 
1145eedbc685SPaolo Abeni 	memset(data, 0, sizeof(data));
1146eedbc685SPaolo Abeni 	nh = (void *)data;
1147eedbc685SPaolo Abeni 	off = init_genl_req(data, pm_family, MPTCP_PM_CMD_FLUSH_ADDRS,
1148eedbc685SPaolo Abeni 			    MPTCP_PM_VER);
1149eedbc685SPaolo Abeni 
1150eedbc685SPaolo Abeni 	do_nl_req(fd, nh, off, 0);
1151eedbc685SPaolo Abeni 	return 0;
1152eedbc685SPaolo Abeni }
1153eedbc685SPaolo Abeni 
print_limits(struct nlmsghdr * nh,int pm_family,int total_len)1154eedbc685SPaolo Abeni static void print_limits(struct nlmsghdr *nh, int pm_family, int total_len)
1155eedbc685SPaolo Abeni {
1156eedbc685SPaolo Abeni 	struct rtattr *attrs;
1157eedbc685SPaolo Abeni 	uint32_t max;
1158eedbc685SPaolo Abeni 
1159eedbc685SPaolo Abeni 	for (; NLMSG_OK(nh, total_len); nh = NLMSG_NEXT(nh, total_len)) {
1160eedbc685SPaolo Abeni 		int len = nh->nlmsg_len;
1161eedbc685SPaolo Abeni 
1162eedbc685SPaolo Abeni 		if (nh->nlmsg_type == NLMSG_DONE)
1163eedbc685SPaolo Abeni 			break;
1164eedbc685SPaolo Abeni 		if (nh->nlmsg_type == NLMSG_ERROR)
1165eedbc685SPaolo Abeni 			nl_error(nh);
1166eedbc685SPaolo Abeni 		if (nh->nlmsg_type != pm_family)
1167eedbc685SPaolo Abeni 			continue;
1168eedbc685SPaolo Abeni 
1169eedbc685SPaolo Abeni 		len -= NLMSG_LENGTH(GENL_HDRLEN);
1170eedbc685SPaolo Abeni 		attrs = (struct rtattr *) ((char *) NLMSG_DATA(nh) +
1171eedbc685SPaolo Abeni 					   GENL_HDRLEN);
1172eedbc685SPaolo Abeni 		while (RTA_OK(attrs, len)) {
1173eedbc685SPaolo Abeni 			int type = attrs->rta_type;
1174eedbc685SPaolo Abeni 
1175eedbc685SPaolo Abeni 			if (type != MPTCP_PM_ATTR_RCV_ADD_ADDRS &&
1176eedbc685SPaolo Abeni 			    type != MPTCP_PM_ATTR_SUBFLOWS)
1177eedbc685SPaolo Abeni 				goto next;
1178eedbc685SPaolo Abeni 
1179eedbc685SPaolo Abeni 			memcpy(&max, RTA_DATA(attrs), 4);
1180eedbc685SPaolo Abeni 			printf("%s %u\n", type == MPTCP_PM_ATTR_SUBFLOWS ?
1181eedbc685SPaolo Abeni 					  "subflows" : "accept", max);
1182eedbc685SPaolo Abeni 
1183eedbc685SPaolo Abeni next:
1184eedbc685SPaolo Abeni 			attrs = RTA_NEXT(attrs, len);
1185eedbc685SPaolo Abeni 		}
1186eedbc685SPaolo Abeni 	}
1187eedbc685SPaolo Abeni }
1188eedbc685SPaolo Abeni 
get_set_limits(int fd,int pm_family,int argc,char * argv[])1189eedbc685SPaolo Abeni int get_set_limits(int fd, int pm_family, int argc, char *argv[])
1190eedbc685SPaolo Abeni {
1191eedbc685SPaolo Abeni 	char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
1192eedbc685SPaolo Abeni 		  NLMSG_ALIGN(sizeof(struct genlmsghdr)) +
1193eedbc685SPaolo Abeni 		  1024];
1194eedbc685SPaolo Abeni 	uint32_t rcv_addr = 0, subflows = 0;
1195eedbc685SPaolo Abeni 	int cmd, len = sizeof(data);
1196eedbc685SPaolo Abeni 	struct nlmsghdr *nh;
1197eedbc685SPaolo Abeni 	int off = 0;
1198eedbc685SPaolo Abeni 
1199eedbc685SPaolo Abeni 	/* limit */
1200eedbc685SPaolo Abeni 	if (argc == 4) {
1201eedbc685SPaolo Abeni 		rcv_addr = atoi(argv[2]);
1202eedbc685SPaolo Abeni 		subflows = atoi(argv[3]);
1203eedbc685SPaolo Abeni 		cmd = MPTCP_PM_CMD_SET_LIMITS;
1204eedbc685SPaolo Abeni 	} else {
1205eedbc685SPaolo Abeni 		cmd = MPTCP_PM_CMD_GET_LIMITS;
1206eedbc685SPaolo Abeni 	}
1207eedbc685SPaolo Abeni 
1208eedbc685SPaolo Abeni 	memset(data, 0, sizeof(data));
1209eedbc685SPaolo Abeni 	nh = (void *)data;
1210eedbc685SPaolo Abeni 	off = init_genl_req(data, pm_family, cmd, MPTCP_PM_VER);
1211eedbc685SPaolo Abeni 
1212eedbc685SPaolo Abeni 	/* limit */
1213eedbc685SPaolo Abeni 	if (cmd == MPTCP_PM_CMD_SET_LIMITS) {
1214eedbc685SPaolo Abeni 		struct rtattr *rta = (void *)(data + off);
1215eedbc685SPaolo Abeni 
1216eedbc685SPaolo Abeni 		rta->rta_type = MPTCP_PM_ATTR_RCV_ADD_ADDRS;
1217eedbc685SPaolo Abeni 		rta->rta_len = RTA_LENGTH(4);
1218eedbc685SPaolo Abeni 		memcpy(RTA_DATA(rta), &rcv_addr, 4);
1219eedbc685SPaolo Abeni 		off += NLMSG_ALIGN(rta->rta_len);
1220eedbc685SPaolo Abeni 
1221eedbc685SPaolo Abeni 		rta = (void *)(data + off);
1222eedbc685SPaolo Abeni 		rta->rta_type = MPTCP_PM_ATTR_SUBFLOWS;
1223eedbc685SPaolo Abeni 		rta->rta_len = RTA_LENGTH(4);
1224eedbc685SPaolo Abeni 		memcpy(RTA_DATA(rta), &subflows, 4);
1225eedbc685SPaolo Abeni 		off += NLMSG_ALIGN(rta->rta_len);
1226eedbc685SPaolo Abeni 
1227eedbc685SPaolo Abeni 		/* do not expect a reply */
1228eedbc685SPaolo Abeni 		len = 0;
1229eedbc685SPaolo Abeni 	}
1230eedbc685SPaolo Abeni 
1231eedbc685SPaolo Abeni 	len = do_nl_req(fd, nh, off, len);
1232eedbc685SPaolo Abeni 	if (cmd == MPTCP_PM_CMD_GET_LIMITS)
1233eedbc685SPaolo Abeni 		print_limits(nh, pm_family, len);
1234eedbc685SPaolo Abeni 	return 0;
1235eedbc685SPaolo Abeni }
1236eedbc685SPaolo Abeni 
add_listener(int argc,char * argv[])1237bdde081dSKishen Maloor int add_listener(int argc, char *argv[])
1238bdde081dSKishen Maloor {
1239bdde081dSKishen Maloor 	struct sockaddr_storage addr;
1240bdde081dSKishen Maloor 	struct sockaddr_in6 *a6;
1241bdde081dSKishen Maloor 	struct sockaddr_in *a4;
1242bdde081dSKishen Maloor 	u_int16_t family;
1243bdde081dSKishen Maloor 	int enable = 1;
1244bdde081dSKishen Maloor 	int sock;
1245bdde081dSKishen Maloor 	int err;
1246bdde081dSKishen Maloor 
1247bdde081dSKishen Maloor 	if (argc < 4)
1248bdde081dSKishen Maloor 		syntax(argv);
1249bdde081dSKishen Maloor 
1250bdde081dSKishen Maloor 	memset(&addr, 0, sizeof(struct sockaddr_storage));
1251bdde081dSKishen Maloor 	a4 = (struct sockaddr_in *)&addr;
1252bdde081dSKishen Maloor 	a6 = (struct sockaddr_in6 *)&addr;
1253bdde081dSKishen Maloor 
1254bdde081dSKishen Maloor 	if (inet_pton(AF_INET, argv[2], &a4->sin_addr)) {
1255bdde081dSKishen Maloor 		family = AF_INET;
1256bdde081dSKishen Maloor 		a4->sin_family = family;
1257bdde081dSKishen Maloor 		a4->sin_port = htons(atoi(argv[3]));
1258bdde081dSKishen Maloor 	} else if (inet_pton(AF_INET6, argv[2], &a6->sin6_addr)) {
1259bdde081dSKishen Maloor 		family = AF_INET6;
1260bdde081dSKishen Maloor 		a6->sin6_family = family;
1261bdde081dSKishen Maloor 		a6->sin6_port = htons(atoi(argv[3]));
1262bdde081dSKishen Maloor 	} else
1263bdde081dSKishen Maloor 		error(1, errno, "can't parse ip %s", argv[2]);
1264bdde081dSKishen Maloor 
1265bdde081dSKishen Maloor 	sock = socket(family, SOCK_STREAM, IPPROTO_MPTCP);
1266bdde081dSKishen Maloor 	if (sock < 0)
1267bdde081dSKishen Maloor 		error(1, errno, "can't create listener sock\n");
1268bdde081dSKishen Maloor 
1269bdde081dSKishen Maloor 	if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable))) {
1270bdde081dSKishen Maloor 		close(sock);
1271bdde081dSKishen Maloor 		error(1, errno, "can't set SO_REUSEADDR on listener sock\n");
1272bdde081dSKishen Maloor 	}
1273bdde081dSKishen Maloor 
1274bdde081dSKishen Maloor 	err = bind(sock, (struct sockaddr *)&addr,
1275bdde081dSKishen Maloor 		   ((family == AF_INET) ? sizeof(struct sockaddr_in) :
1276bdde081dSKishen Maloor 		    sizeof(struct sockaddr_in6)));
1277bdde081dSKishen Maloor 
1278bdde081dSKishen Maloor 	if (err == 0 && listen(sock, 30) == 0)
1279bdde081dSKishen Maloor 		pause();
1280bdde081dSKishen Maloor 
1281bdde081dSKishen Maloor 	close(sock);
1282bdde081dSKishen Maloor 	return 0;
1283bdde081dSKishen Maloor }
1284bdde081dSKishen Maloor 
set_flags(int fd,int pm_family,int argc,char * argv[])12856e8b244aSGeliang Tang int set_flags(int fd, int pm_family, int argc, char *argv[])
12866e8b244aSGeliang Tang {
12876e8b244aSGeliang Tang 	char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
12886e8b244aSGeliang Tang 		  NLMSG_ALIGN(sizeof(struct genlmsghdr)) +
12896e8b244aSGeliang Tang 		  1024];
12906e8b244aSGeliang Tang 	struct rtattr *rta, *nest;
12916e8b244aSGeliang Tang 	struct nlmsghdr *nh;
12926e8b244aSGeliang Tang 	u_int32_t flags = 0;
1293ca188a25SKishen Maloor 	u_int32_t token = 0;
1294ca188a25SKishen Maloor 	u_int16_t rport = 0;
12956e8b244aSGeliang Tang 	u_int16_t family;
1296ca188a25SKishen Maloor 	void *rip = NULL;
12976e8b244aSGeliang Tang 	int nest_start;
1298a224a847SGeliang Tang 	int use_id = 0;
1299a224a847SGeliang Tang 	u_int8_t id;
13006e8b244aSGeliang Tang 	int off = 0;
1301a224a847SGeliang Tang 	int arg = 2;
13026e8b244aSGeliang Tang 
13036e8b244aSGeliang Tang 	memset(data, 0, sizeof(data));
13046e8b244aSGeliang Tang 	nh = (void *)data;
13056e8b244aSGeliang Tang 	off = init_genl_req(data, pm_family, MPTCP_PM_CMD_SET_FLAGS,
13066e8b244aSGeliang Tang 			    MPTCP_PM_VER);
13076e8b244aSGeliang Tang 
13086e8b244aSGeliang Tang 	if (argc < 3)
13096e8b244aSGeliang Tang 		syntax(argv);
13106e8b244aSGeliang Tang 
13116e8b244aSGeliang Tang 	nest_start = off;
13126e8b244aSGeliang Tang 	nest = (void *)(data + off);
13136e8b244aSGeliang Tang 	nest->rta_type = NLA_F_NESTED | MPTCP_PM_ATTR_ADDR;
13146e8b244aSGeliang Tang 	nest->rta_len = RTA_LENGTH(0);
13156e8b244aSGeliang Tang 	off += NLMSG_ALIGN(nest->rta_len);
13166e8b244aSGeliang Tang 
1317a224a847SGeliang Tang 	if (!strcmp(argv[arg], "id")) {
1318a224a847SGeliang Tang 		if (++arg >= argc)
1319a224a847SGeliang Tang 			error(1, 0, " missing id value");
1320a224a847SGeliang Tang 
1321a224a847SGeliang Tang 		use_id = 1;
1322a224a847SGeliang Tang 		id = atoi(argv[arg]);
1323a224a847SGeliang Tang 		rta = (void *)(data + off);
1324a224a847SGeliang Tang 		rta->rta_type = MPTCP_PM_ADDR_ATTR_ID;
1325a224a847SGeliang Tang 		rta->rta_len = RTA_LENGTH(1);
1326a224a847SGeliang Tang 		memcpy(RTA_DATA(rta), &id, 1);
1327a224a847SGeliang Tang 		off += NLMSG_ALIGN(rta->rta_len);
1328a224a847SGeliang Tang 	} else {
13296e8b244aSGeliang Tang 		/* addr data */
13306e8b244aSGeliang Tang 		rta = (void *)(data + off);
1331a224a847SGeliang Tang 		if (inet_pton(AF_INET, argv[arg], RTA_DATA(rta))) {
13326e8b244aSGeliang Tang 			family = AF_INET;
13336e8b244aSGeliang Tang 			rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR4;
13346e8b244aSGeliang Tang 			rta->rta_len = RTA_LENGTH(4);
1335a224a847SGeliang Tang 		} else if (inet_pton(AF_INET6, argv[arg], RTA_DATA(rta))) {
13366e8b244aSGeliang Tang 			family = AF_INET6;
13376e8b244aSGeliang Tang 			rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR6;
13386e8b244aSGeliang Tang 			rta->rta_len = RTA_LENGTH(16);
13396e8b244aSGeliang Tang 		} else {
1340a224a847SGeliang Tang 			error(1, errno, "can't parse ip %s", argv[arg]);
13416e8b244aSGeliang Tang 		}
13426e8b244aSGeliang Tang 		off += NLMSG_ALIGN(rta->rta_len);
13436e8b244aSGeliang Tang 
13446e8b244aSGeliang Tang 		/* family */
13456e8b244aSGeliang Tang 		rta = (void *)(data + off);
13466e8b244aSGeliang Tang 		rta->rta_type = MPTCP_PM_ADDR_ATTR_FAMILY;
13476e8b244aSGeliang Tang 		rta->rta_len = RTA_LENGTH(2);
13486e8b244aSGeliang Tang 		memcpy(RTA_DATA(rta), &family, 2);
13496e8b244aSGeliang Tang 		off += NLMSG_ALIGN(rta->rta_len);
1350a224a847SGeliang Tang 	}
13516e8b244aSGeliang Tang 
1352a224a847SGeliang Tang 	if (++arg >= argc)
1353a224a847SGeliang Tang 		error(1, 0, " missing flags keyword");
1354a224a847SGeliang Tang 
1355a224a847SGeliang Tang 	for (; arg < argc; arg++) {
1356ca188a25SKishen Maloor 		if (!strcmp(argv[arg], "token")) {
1357ca188a25SKishen Maloor 			if (++arg >= argc)
1358ca188a25SKishen Maloor 				error(1, 0, " missing token value");
1359ca188a25SKishen Maloor 
1360ca188a25SKishen Maloor 			/* token */
136161d96580SMatthieu Baerts 			token = strtoul(argv[arg], NULL, 10);
1362ca188a25SKishen Maloor 		} else if (!strcmp(argv[arg], "flags")) {
13636e8b244aSGeliang Tang 			char *tok, *str;
13646e8b244aSGeliang Tang 
13656e8b244aSGeliang Tang 			/* flags */
13666e8b244aSGeliang Tang 			if (++arg >= argc)
13676e8b244aSGeliang Tang 				error(1, 0, " missing flags value");
13686e8b244aSGeliang Tang 
13696e8b244aSGeliang Tang 			for (str = argv[arg]; (tok = strtok(str, ","));
13706e8b244aSGeliang Tang 			     str = NULL) {
13716e8b244aSGeliang Tang 				if (!strcmp(tok, "backup"))
13726e8b244aSGeliang Tang 					flags |= MPTCP_PM_ADDR_FLAG_BACKUP;
1373c25d29beSGeliang Tang 				else if (!strcmp(tok, "fullmesh"))
1374c25d29beSGeliang Tang 					flags |= MPTCP_PM_ADDR_FLAG_FULLMESH;
1375c25d29beSGeliang Tang 				else if (strcmp(tok, "nobackup") &&
1376c25d29beSGeliang Tang 					 strcmp(tok, "nofullmesh"))
13776e8b244aSGeliang Tang 					error(1, errno,
13786e8b244aSGeliang Tang 					      "unknown flag %s", argv[arg]);
13796e8b244aSGeliang Tang 			}
13806e8b244aSGeliang Tang 
13816e8b244aSGeliang Tang 			rta = (void *)(data + off);
13826e8b244aSGeliang Tang 			rta->rta_type = MPTCP_PM_ADDR_ATTR_FLAGS;
13836e8b244aSGeliang Tang 			rta->rta_len = RTA_LENGTH(4);
13846e8b244aSGeliang Tang 			memcpy(RTA_DATA(rta), &flags, 4);
13856e8b244aSGeliang Tang 			off += NLMSG_ALIGN(rta->rta_len);
1386d6a676e0SGeliang Tang 		} else if (!strcmp(argv[arg], "port")) {
1387d6a676e0SGeliang Tang 			u_int16_t port;
1388d6a676e0SGeliang Tang 
1389a224a847SGeliang Tang 			if (use_id)
1390a224a847SGeliang Tang 				error(1, 0, " port can't be used with id");
1391a224a847SGeliang Tang 
1392d6a676e0SGeliang Tang 			if (++arg >= argc)
1393d6a676e0SGeliang Tang 				error(1, 0, " missing port value");
1394d6a676e0SGeliang Tang 
1395d6a676e0SGeliang Tang 			port = atoi(argv[arg]);
1396d6a676e0SGeliang Tang 			rta = (void *)(data + off);
1397d6a676e0SGeliang Tang 			rta->rta_type = MPTCP_PM_ADDR_ATTR_PORT;
1398d6a676e0SGeliang Tang 			rta->rta_len = RTA_LENGTH(2);
1399d6a676e0SGeliang Tang 			memcpy(RTA_DATA(rta), &port, 2);
1400d6a676e0SGeliang Tang 			off += NLMSG_ALIGN(rta->rta_len);
1401ca188a25SKishen Maloor 		} else if (!strcmp(argv[arg], "rport")) {
1402ca188a25SKishen Maloor 			if (++arg >= argc)
1403ca188a25SKishen Maloor 				error(1, 0, " missing remote port");
1404ca188a25SKishen Maloor 
1405ca188a25SKishen Maloor 			rport = atoi(argv[arg]);
1406ca188a25SKishen Maloor 		} else if (!strcmp(argv[arg], "rip")) {
1407ca188a25SKishen Maloor 			if (++arg >= argc)
1408ca188a25SKishen Maloor 				error(1, 0, " missing remote ip");
1409ca188a25SKishen Maloor 
1410ca188a25SKishen Maloor 			rip = argv[arg];
14116e8b244aSGeliang Tang 		} else {
14126e8b244aSGeliang Tang 			error(1, 0, "unknown keyword %s", argv[arg]);
14136e8b244aSGeliang Tang 		}
14146e8b244aSGeliang Tang 	}
14156e8b244aSGeliang Tang 	nest->rta_len = off - nest_start;
14166e8b244aSGeliang Tang 
1417ca188a25SKishen Maloor 	/* token */
1418ca188a25SKishen Maloor 	if (token) {
1419ca188a25SKishen Maloor 		rta = (void *)(data + off);
1420ca188a25SKishen Maloor 		rta->rta_type = MPTCP_PM_ATTR_TOKEN;
1421ca188a25SKishen Maloor 		rta->rta_len = RTA_LENGTH(4);
1422ca188a25SKishen Maloor 		memcpy(RTA_DATA(rta), &token, 4);
1423ca188a25SKishen Maloor 		off += NLMSG_ALIGN(rta->rta_len);
1424ca188a25SKishen Maloor 	}
1425ca188a25SKishen Maloor 
1426ca188a25SKishen Maloor 	/* remote addr/port */
1427ca188a25SKishen Maloor 	if (rip) {
1428ca188a25SKishen Maloor 		nest_start = off;
1429ca188a25SKishen Maloor 		nest = (void *)(data + off);
1430ca188a25SKishen Maloor 		nest->rta_type = NLA_F_NESTED | MPTCP_PM_ATTR_ADDR_REMOTE;
1431ca188a25SKishen Maloor 		nest->rta_len = RTA_LENGTH(0);
1432ca188a25SKishen Maloor 		off += NLMSG_ALIGN(nest->rta_len);
1433ca188a25SKishen Maloor 
1434ca188a25SKishen Maloor 		/* addr data */
1435ca188a25SKishen Maloor 		rta = (void *)(data + off);
1436ca188a25SKishen Maloor 		if (inet_pton(AF_INET, rip, RTA_DATA(rta))) {
1437ca188a25SKishen Maloor 			family = AF_INET;
1438ca188a25SKishen Maloor 			rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR4;
1439ca188a25SKishen Maloor 			rta->rta_len = RTA_LENGTH(4);
1440ca188a25SKishen Maloor 		} else if (inet_pton(AF_INET6, rip, RTA_DATA(rta))) {
1441ca188a25SKishen Maloor 			family = AF_INET6;
1442ca188a25SKishen Maloor 			rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR6;
1443ca188a25SKishen Maloor 			rta->rta_len = RTA_LENGTH(16);
1444ca188a25SKishen Maloor 		} else {
1445ca188a25SKishen Maloor 			error(1, errno, "can't parse ip %s", (char *)rip);
1446ca188a25SKishen Maloor 		}
1447ca188a25SKishen Maloor 		off += NLMSG_ALIGN(rta->rta_len);
1448ca188a25SKishen Maloor 
1449ca188a25SKishen Maloor 		/* family */
1450ca188a25SKishen Maloor 		rta = (void *)(data + off);
1451ca188a25SKishen Maloor 		rta->rta_type = MPTCP_PM_ADDR_ATTR_FAMILY;
1452ca188a25SKishen Maloor 		rta->rta_len = RTA_LENGTH(2);
1453ca188a25SKishen Maloor 		memcpy(RTA_DATA(rta), &family, 2);
1454ca188a25SKishen Maloor 		off += NLMSG_ALIGN(rta->rta_len);
1455ca188a25SKishen Maloor 
1456ca188a25SKishen Maloor 		if (rport) {
1457ca188a25SKishen Maloor 			rta = (void *)(data + off);
1458ca188a25SKishen Maloor 			rta->rta_type = MPTCP_PM_ADDR_ATTR_PORT;
1459ca188a25SKishen Maloor 			rta->rta_len = RTA_LENGTH(2);
1460ca188a25SKishen Maloor 			memcpy(RTA_DATA(rta), &rport, 2);
1461ca188a25SKishen Maloor 			off += NLMSG_ALIGN(rta->rta_len);
1462ca188a25SKishen Maloor 		}
1463ca188a25SKishen Maloor 
1464ca188a25SKishen Maloor 		nest->rta_len = off - nest_start;
1465ca188a25SKishen Maloor 	}
1466ca188a25SKishen Maloor 
14676e8b244aSGeliang Tang 	do_nl_req(fd, nh, off, 0);
14686e8b244aSGeliang Tang 	return 0;
14696e8b244aSGeliang Tang }
14706e8b244aSGeliang Tang 
main(int argc,char * argv[])1471eedbc685SPaolo Abeni int main(int argc, char *argv[])
1472eedbc685SPaolo Abeni {
1473b3e5fd65SKishen Maloor 	int events_mcast_grp;
1474b3e5fd65SKishen Maloor 	int pm_family;
1475b3e5fd65SKishen Maloor 	int fd;
1476eedbc685SPaolo Abeni 
1477eedbc685SPaolo Abeni 	if (argc < 2)
1478eedbc685SPaolo Abeni 		syntax(argv);
1479eedbc685SPaolo Abeni 
1480eedbc685SPaolo Abeni 	fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
1481eedbc685SPaolo Abeni 	if (fd == -1)
1482eedbc685SPaolo Abeni 		error(1, errno, "socket netlink");
1483eedbc685SPaolo Abeni 
1484b3e5fd65SKishen Maloor 	resolve_mptcp_pm_netlink(fd, &pm_family, &events_mcast_grp);
1485eedbc685SPaolo Abeni 
1486eedbc685SPaolo Abeni 	if (!strcmp(argv[1], "add"))
1487eedbc685SPaolo Abeni 		return add_addr(fd, pm_family, argc, argv);
14889a0b3650SKishen Maloor 	else if (!strcmp(argv[1], "ann"))
14899a0b3650SKishen Maloor 		return announce_addr(fd, pm_family, argc, argv);
1490ecd2a77dSKishen Maloor 	else if (!strcmp(argv[1], "rem"))
1491ecd2a77dSKishen Maloor 		return remove_addr(fd, pm_family, argc, argv);
1492cf8d0a6dSKishen Maloor 	else if (!strcmp(argv[1], "csf"))
1493cf8d0a6dSKishen Maloor 		return csf(fd, pm_family, argc, argv);
149457cc361bSKishen Maloor 	else if (!strcmp(argv[1], "dsf"))
149557cc361bSKishen Maloor 		return dsf(fd, pm_family, argc, argv);
1496eedbc685SPaolo Abeni 	else if (!strcmp(argv[1], "del"))
1497eedbc685SPaolo Abeni 		return del_addr(fd, pm_family, argc, argv);
1498eedbc685SPaolo Abeni 	else if (!strcmp(argv[1], "flush"))
1499eedbc685SPaolo Abeni 		return flush_addrs(fd, pm_family, argc, argv);
1500eedbc685SPaolo Abeni 	else if (!strcmp(argv[1], "get"))
1501eedbc685SPaolo Abeni 		return get_addr(fd, pm_family, argc, argv);
1502eedbc685SPaolo Abeni 	else if (!strcmp(argv[1], "dump"))
1503eedbc685SPaolo Abeni 		return dump_addrs(fd, pm_family, argc, argv);
1504eedbc685SPaolo Abeni 	else if (!strcmp(argv[1], "limits"))
1505eedbc685SPaolo Abeni 		return get_set_limits(fd, pm_family, argc, argv);
15066e8b244aSGeliang Tang 	else if (!strcmp(argv[1], "set"))
15076e8b244aSGeliang Tang 		return set_flags(fd, pm_family, argc, argv);
1508b3e5fd65SKishen Maloor 	else if (!strcmp(argv[1], "events"))
1509b3e5fd65SKishen Maloor 		return capture_events(fd, events_mcast_grp);
1510bdde081dSKishen Maloor 	else if (!strcmp(argv[1], "listen"))
1511bdde081dSKishen Maloor 		return add_listener(argc, argv);
1512eedbc685SPaolo Abeni 
1513eedbc685SPaolo Abeni 	fprintf(stderr, "unknown sub-command: %s", argv[1]);
1514eedbc685SPaolo Abeni 	syntax(argv);
1515eedbc685SPaolo Abeni 	return 0;
1516eedbc685SPaolo Abeni }
1517