xref: /aosp_15_r20/external/iw/mpath.c (revision 92022041c981f431db0b590d0c3272306d0ea2a2)
1*92022041SSam Saccone #include <net/if.h>
2*92022041SSam Saccone #include <errno.h>
3*92022041SSam Saccone #include <string.h>
4*92022041SSam Saccone 
5*92022041SSam Saccone #include <netlink/genl/genl.h>
6*92022041SSam Saccone #include <netlink/genl/family.h>
7*92022041SSam Saccone #include <netlink/genl/ctrl.h>
8*92022041SSam Saccone #include <netlink/msg.h>
9*92022041SSam Saccone #include <netlink/attr.h>
10*92022041SSam Saccone 
11*92022041SSam Saccone #include "nl80211.h"
12*92022041SSam Saccone #include "iw.h"
13*92022041SSam Saccone 
14*92022041SSam Saccone SECTION(mpath);
15*92022041SSam Saccone 
16*92022041SSam Saccone enum plink_state {
17*92022041SSam Saccone 	LISTEN,
18*92022041SSam Saccone 	OPN_SNT,
19*92022041SSam Saccone 	OPN_RCVD,
20*92022041SSam Saccone 	CNF_RCVD,
21*92022041SSam Saccone 	ESTAB,
22*92022041SSam Saccone 	HOLDING,
23*92022041SSam Saccone 	BLOCKED
24*92022041SSam Saccone };
25*92022041SSam Saccone 
26*92022041SSam Saccone 
print_mpath_handler(struct nl_msg * msg,void * arg)27*92022041SSam Saccone static int print_mpath_handler(struct nl_msg *msg, void *arg)
28*92022041SSam Saccone {
29*92022041SSam Saccone 	struct nlattr *tb[NL80211_ATTR_MAX + 1];
30*92022041SSam Saccone 	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
31*92022041SSam Saccone 	struct nlattr *pinfo[NL80211_MPATH_INFO_MAX + 1];
32*92022041SSam Saccone 	char dst[20], next_hop[20], dev[20];
33*92022041SSam Saccone 	static struct nla_policy mpath_policy[NL80211_MPATH_INFO_MAX + 1] = {
34*92022041SSam Saccone 		[NL80211_MPATH_INFO_FRAME_QLEN] = { .type = NLA_U32 },
35*92022041SSam Saccone 		[NL80211_MPATH_INFO_SN] = { .type = NLA_U32 },
36*92022041SSam Saccone 		[NL80211_MPATH_INFO_METRIC] = { .type = NLA_U32 },
37*92022041SSam Saccone 		[NL80211_MPATH_INFO_EXPTIME] = { .type = NLA_U32 },
38*92022041SSam Saccone 		[NL80211_MPATH_INFO_DISCOVERY_TIMEOUT] = { .type = NLA_U32 },
39*92022041SSam Saccone 		[NL80211_MPATH_INFO_DISCOVERY_RETRIES] = { .type = NLA_U8 },
40*92022041SSam Saccone 		[NL80211_MPATH_INFO_FLAGS] = { .type = NLA_U8 },
41*92022041SSam Saccone 		[NL80211_MPATH_INFO_HOP_COUNT] = { .type = NLA_U8 },
42*92022041SSam Saccone 		[NL80211_MPATH_INFO_PATH_CHANGE] = { .type = NLA_U32 },
43*92022041SSam Saccone 	};
44*92022041SSam Saccone 
45*92022041SSam Saccone 	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
46*92022041SSam Saccone 		  genlmsg_attrlen(gnlh, 0), NULL);
47*92022041SSam Saccone 
48*92022041SSam Saccone 	/*
49*92022041SSam Saccone 	 * TODO: validate the interface and mac address!
50*92022041SSam Saccone 	 * Otherwise, there's a race condition as soon as
51*92022041SSam Saccone 	 * the kernel starts sending mpath notifications.
52*92022041SSam Saccone 	 */
53*92022041SSam Saccone 
54*92022041SSam Saccone 	if (!tb[NL80211_ATTR_MPATH_INFO]) {
55*92022041SSam Saccone 		fprintf(stderr, "mpath info missing!\n");
56*92022041SSam Saccone 		return NL_SKIP;
57*92022041SSam Saccone 	}
58*92022041SSam Saccone 	if (nla_parse_nested(pinfo, NL80211_MPATH_INFO_MAX,
59*92022041SSam Saccone 			     tb[NL80211_ATTR_MPATH_INFO],
60*92022041SSam Saccone 			     mpath_policy)) {
61*92022041SSam Saccone 		fprintf(stderr, "failed to parse nested attributes!\n");
62*92022041SSam Saccone 		return NL_SKIP;
63*92022041SSam Saccone 	}
64*92022041SSam Saccone 
65*92022041SSam Saccone 	mac_addr_n2a(dst, nla_data(tb[NL80211_ATTR_MAC]));
66*92022041SSam Saccone 	mac_addr_n2a(next_hop, nla_data(tb[NL80211_ATTR_MPATH_NEXT_HOP]));
67*92022041SSam Saccone 	if_indextoname(nla_get_u32(tb[NL80211_ATTR_IFINDEX]), dev);
68*92022041SSam Saccone 	printf("%s %s %s", dst, next_hop, dev);
69*92022041SSam Saccone 	if (pinfo[NL80211_MPATH_INFO_SN])
70*92022041SSam Saccone 		printf("\t%u",
71*92022041SSam Saccone 			nla_get_u32(pinfo[NL80211_MPATH_INFO_SN]));
72*92022041SSam Saccone 	if (pinfo[NL80211_MPATH_INFO_METRIC])
73*92022041SSam Saccone 		printf("\t%u",
74*92022041SSam Saccone 			nla_get_u32(pinfo[NL80211_MPATH_INFO_METRIC]));
75*92022041SSam Saccone 	if (pinfo[NL80211_MPATH_INFO_FRAME_QLEN])
76*92022041SSam Saccone 		printf("\t%u",
77*92022041SSam Saccone 			nla_get_u32(pinfo[NL80211_MPATH_INFO_FRAME_QLEN]));
78*92022041SSam Saccone 	if (pinfo[NL80211_MPATH_INFO_EXPTIME])
79*92022041SSam Saccone 		printf("\t%u",
80*92022041SSam Saccone 			nla_get_u32(pinfo[NL80211_MPATH_INFO_EXPTIME]));
81*92022041SSam Saccone 	if (pinfo[NL80211_MPATH_INFO_DISCOVERY_TIMEOUT])
82*92022041SSam Saccone 		printf("\t%u",
83*92022041SSam Saccone 		nla_get_u32(pinfo[NL80211_MPATH_INFO_DISCOVERY_TIMEOUT]));
84*92022041SSam Saccone 	if (pinfo[NL80211_MPATH_INFO_DISCOVERY_RETRIES])
85*92022041SSam Saccone 		printf("\t%u",
86*92022041SSam Saccone 		nla_get_u8(pinfo[NL80211_MPATH_INFO_DISCOVERY_RETRIES]));
87*92022041SSam Saccone 	if (pinfo[NL80211_MPATH_INFO_FLAGS])
88*92022041SSam Saccone 		printf("\t0x%x",
89*92022041SSam Saccone 			nla_get_u8(pinfo[NL80211_MPATH_INFO_FLAGS]));
90*92022041SSam Saccone 	if (pinfo[NL80211_MPATH_INFO_HOP_COUNT])
91*92022041SSam Saccone 		printf("\t%u",
92*92022041SSam Saccone 		       nla_get_u8(pinfo[NL80211_MPATH_INFO_HOP_COUNT]));
93*92022041SSam Saccone 	if (pinfo[NL80211_MPATH_INFO_PATH_CHANGE])
94*92022041SSam Saccone 		printf("\t%u",
95*92022041SSam Saccone 		       nla_get_u32(pinfo[NL80211_MPATH_INFO_PATH_CHANGE]));
96*92022041SSam Saccone 
97*92022041SSam Saccone 	printf("\n");
98*92022041SSam Saccone 	return NL_SKIP;
99*92022041SSam Saccone }
100*92022041SSam Saccone 
handle_mpath_probe(struct nl80211_state * state,struct nl_msg * msg,int argc,char ** argv,enum id_input id)101*92022041SSam Saccone static int handle_mpath_probe(struct nl80211_state *state,
102*92022041SSam Saccone 			      struct nl_msg *msg,
103*92022041SSam Saccone 			      int argc, char **argv,
104*92022041SSam Saccone 			      enum id_input id)
105*92022041SSam Saccone {
106*92022041SSam Saccone 	unsigned char dst[ETH_ALEN];
107*92022041SSam Saccone 	unsigned char *frame;
108*92022041SSam Saccone 	size_t frame_len;
109*92022041SSam Saccone 
110*92022041SSam Saccone 	if (argc < 3)
111*92022041SSam Saccone 		return 1;
112*92022041SSam Saccone 
113*92022041SSam Saccone 	if (mac_addr_a2n(dst, argv[0])) {
114*92022041SSam Saccone 		fprintf(stderr, "invalid mac address\n");
115*92022041SSam Saccone 		return 2;
116*92022041SSam Saccone 	}
117*92022041SSam Saccone 
118*92022041SSam Saccone 	if (strcmp("frame", argv[1]) != 0)
119*92022041SSam Saccone 		return 1;
120*92022041SSam Saccone 
121*92022041SSam Saccone 	frame = parse_hex(argv[2], &frame_len);
122*92022041SSam Saccone 	if (!frame) {
123*92022041SSam Saccone 		fprintf(stderr, "invalid frame pattern: %p\n", frame);
124*92022041SSam Saccone 		return 2;
125*92022041SSam Saccone 	}
126*92022041SSam Saccone 
127*92022041SSam Saccone 	NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, dst);
128*92022041SSam Saccone 	NLA_PUT(msg, NL80211_ATTR_FRAME, frame_len, frame);
129*92022041SSam Saccone 
130*92022041SSam Saccone 	return 0;
131*92022041SSam Saccone  nla_put_failure:
132*92022041SSam Saccone 	return -ENOBUFS;
133*92022041SSam Saccone }
134*92022041SSam Saccone COMMAND(mpath, probe, "<destination MAC address> frame <frame>",
135*92022041SSam Saccone 	NL80211_CMD_PROBE_MESH_LINK, 0, CIB_NETDEV, handle_mpath_probe,
136*92022041SSam Saccone 	"Inject ethernet frame to given peer overriding the next hop\n"
137*92022041SSam Saccone 	"lookup from mpath table.\n."
138*92022041SSam Saccone 	"Example: iw dev wlan0 mpath probe xx:xx:xx:xx:xx:xx frame 01:xx:xx:00\n");
139*92022041SSam Saccone 
handle_mpath_get(struct nl80211_state * state,struct nl_msg * msg,int argc,char ** argv,enum id_input id)140*92022041SSam Saccone static int handle_mpath_get(struct nl80211_state *state,
141*92022041SSam Saccone 			    struct nl_msg *msg,
142*92022041SSam Saccone 			    int argc, char **argv,
143*92022041SSam Saccone 			    enum id_input id)
144*92022041SSam Saccone {
145*92022041SSam Saccone 	unsigned char dst[ETH_ALEN];
146*92022041SSam Saccone 
147*92022041SSam Saccone 	if (argc < 1)
148*92022041SSam Saccone 		return 1;
149*92022041SSam Saccone 
150*92022041SSam Saccone 	if (mac_addr_a2n(dst, argv[0])) {
151*92022041SSam Saccone 		fprintf(stderr, "invalid mac address\n");
152*92022041SSam Saccone 		return 2;
153*92022041SSam Saccone 	}
154*92022041SSam Saccone 	argc--;
155*92022041SSam Saccone 	argv++;
156*92022041SSam Saccone 
157*92022041SSam Saccone 	if (argc)
158*92022041SSam Saccone 		return 1;
159*92022041SSam Saccone 
160*92022041SSam Saccone 	NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, dst);
161*92022041SSam Saccone 
162*92022041SSam Saccone 	register_handler(print_mpath_handler, NULL);
163*92022041SSam Saccone 
164*92022041SSam Saccone 	return 0;
165*92022041SSam Saccone  nla_put_failure:
166*92022041SSam Saccone 	return -ENOBUFS;
167*92022041SSam Saccone }
168*92022041SSam Saccone COMMAND(mpath, get, "<MAC address>",
169*92022041SSam Saccone 	NL80211_CMD_GET_MPATH, 0, CIB_NETDEV, handle_mpath_get,
170*92022041SSam Saccone 	"Get information on mesh path to the given node.");
171*92022041SSam Saccone COMMAND(mpath, del, "<MAC address>",
172*92022041SSam Saccone 	NL80211_CMD_DEL_MPATH, 0, CIB_NETDEV, handle_mpath_get,
173*92022041SSam Saccone 	"Remove the mesh path to the given node.");
174*92022041SSam Saccone 
handle_mpath_set(struct nl80211_state * state,struct nl_msg * msg,int argc,char ** argv,enum id_input id)175*92022041SSam Saccone static int handle_mpath_set(struct nl80211_state *state,
176*92022041SSam Saccone 			    struct nl_msg *msg,
177*92022041SSam Saccone 			    int argc, char **argv,
178*92022041SSam Saccone 			    enum id_input id)
179*92022041SSam Saccone {
180*92022041SSam Saccone 	unsigned char dst[ETH_ALEN];
181*92022041SSam Saccone 	unsigned char next_hop[ETH_ALEN];
182*92022041SSam Saccone 
183*92022041SSam Saccone 	if (argc < 3)
184*92022041SSam Saccone 		return 1;
185*92022041SSam Saccone 
186*92022041SSam Saccone 	if (mac_addr_a2n(dst, argv[0])) {
187*92022041SSam Saccone 		fprintf(stderr, "invalid destination mac address\n");
188*92022041SSam Saccone 		return 2;
189*92022041SSam Saccone 	}
190*92022041SSam Saccone 	argc--;
191*92022041SSam Saccone 	argv++;
192*92022041SSam Saccone 
193*92022041SSam Saccone 	if (strcmp("next_hop", argv[0]) != 0)
194*92022041SSam Saccone 		return 1;
195*92022041SSam Saccone 	argc--;
196*92022041SSam Saccone 	argv++;
197*92022041SSam Saccone 
198*92022041SSam Saccone 	if (mac_addr_a2n(next_hop, argv[0])) {
199*92022041SSam Saccone 		fprintf(stderr, "invalid next hop mac address\n");
200*92022041SSam Saccone 		return 2;
201*92022041SSam Saccone 	}
202*92022041SSam Saccone 	argc--;
203*92022041SSam Saccone 	argv++;
204*92022041SSam Saccone 
205*92022041SSam Saccone 	if (argc)
206*92022041SSam Saccone 		return 1;
207*92022041SSam Saccone 
208*92022041SSam Saccone 	NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, dst);
209*92022041SSam Saccone 	NLA_PUT(msg, NL80211_ATTR_MPATH_NEXT_HOP, ETH_ALEN, next_hop);
210*92022041SSam Saccone 
211*92022041SSam Saccone 	register_handler(print_mpath_handler, NULL);
212*92022041SSam Saccone 	return 0;
213*92022041SSam Saccone  nla_put_failure:
214*92022041SSam Saccone 	return -ENOBUFS;
215*92022041SSam Saccone }
216*92022041SSam Saccone COMMAND(mpath, new, "<destination MAC address> next_hop <next hop MAC address>",
217*92022041SSam Saccone 	NL80211_CMD_NEW_MPATH, 0, CIB_NETDEV, handle_mpath_set,
218*92022041SSam Saccone 	"Create a new mesh path (instead of relying on automatic discovery).");
219*92022041SSam Saccone COMMAND(mpath, set, "<destination MAC address> next_hop <next hop MAC address>",
220*92022041SSam Saccone 	NL80211_CMD_SET_MPATH, 0, CIB_NETDEV, handle_mpath_set,
221*92022041SSam Saccone 	"Set an existing mesh path's next hop.");
222*92022041SSam Saccone 
handle_mpath_dump(struct nl80211_state * state,struct nl_msg * msg,int argc,char ** argv,enum id_input id)223*92022041SSam Saccone static int handle_mpath_dump(struct nl80211_state *state,
224*92022041SSam Saccone 			     struct nl_msg *msg,
225*92022041SSam Saccone 			     int argc, char **argv,
226*92022041SSam Saccone 			     enum id_input id)
227*92022041SSam Saccone {
228*92022041SSam Saccone 	printf("DEST ADDR         NEXT HOP          IFACE\tSN\tMETRIC\tQLEN\t"
229*92022041SSam Saccone 	       "EXPTIME\tDTIM\tDRET\tFLAGS\tHOP_COUNT\tPATH_CHANGE\n");
230*92022041SSam Saccone 	register_handler(print_mpath_handler, NULL);
231*92022041SSam Saccone 	return 0;
232*92022041SSam Saccone }
233*92022041SSam Saccone COMMAND(mpath, dump, NULL,
234*92022041SSam Saccone 	NL80211_CMD_GET_MPATH, NLM_F_DUMP, CIB_NETDEV, handle_mpath_dump,
235*92022041SSam Saccone 	"List known mesh paths.");
236