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