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