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