blob: 4a98c3100adb50d8651f23c584dcaaa1490c181a [file] [log] [blame]
developere53f0872021-07-23 11:13:49 +08001/* Copyright (C) 2021 Mediatek Inc. */
2#define _GNU_SOURCE
3
4#include "mt76-vendor.h"
5
developer6f8cffd2021-09-29 19:48:25 +08006static struct nla_policy
developere53f0872021-07-23 11:13:49 +08007amnt_ctrl_policy[NUM_MTK_VENDOR_ATTRS_AMNT_CTRL] = {
8 [MTK_VENDOR_ATTR_AMNT_CTRL_SET] = {.type = NLA_NESTED },
9 [MTK_VENDOR_ATTR_AMNT_CTRL_DUMP] = { .type = NLA_NESTED },
10};
11
developer6f8cffd2021-09-29 19:48:25 +080012static struct nla_policy
developere53f0872021-07-23 11:13:49 +080013amnt_dump_policy[NUM_MTK_VENDOR_ATTRS_AMNT_DUMP] = {
14 [MTK_VENDOR_ATTR_AMNT_DUMP_INDEX] = {.type = NLA_U8 },
15 [MTK_VENDOR_ATTR_AMNT_DUMP_LEN] = { .type = NLA_U8 },
16 [MTK_VENDOR_ATTR_AMNT_DUMP_RESULT] = { .type = NLA_NESTED },
17};
18
19static int mt76_amnt_set_attr(struct nl_msg *msg, int argc, char **argv)
20{
21 void *tb1, *tb2;
22 u8 a[ETH_ALEN], idx;
23 int i = 0, matches;
24
25 idx = strtoul(argv[0], NULL, 0);
26 matches = sscanf(argv[1], "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
27 a, a+1, a+2, a+3, a+4, a+5);
28
29 if (matches != ETH_ALEN)
30 return -EINVAL;
31
32 tb1 = nla_nest_start(msg, MTK_VENDOR_ATTR_AMNT_CTRL_SET | NLA_F_NESTED);
developer6f8cffd2021-09-29 19:48:25 +080033 if (!tb1)
34 return -ENOMEM;
35
developere53f0872021-07-23 11:13:49 +080036 nla_put_u8(msg, MTK_VENDOR_ATTR_AMNT_SET_INDEX, idx);
37
38 tb2 = nla_nest_start(msg, MTK_VENDOR_ATTR_AMNT_SET_MACADDR | NLA_F_NESTED);
developer6f8cffd2021-09-29 19:48:25 +080039 if (!tb2) {
40 nla_nest_end(msg, tb1);
41 return -ENOMEM;
42 }
43
developere53f0872021-07-23 11:13:49 +080044 for (i = 0; i < ETH_ALEN; i++)
45 nla_put_u8(msg, i, a[i]);
46
47 nla_nest_end(msg, tb2);
48 nla_nest_end(msg, tb1);
developer6f8cffd2021-09-29 19:48:25 +080049
developere53f0872021-07-23 11:13:49 +080050 return 0;
51}
52
53int mt76_amnt_set(int idx, int argc, char **argv)
54{
55 struct nl_msg *msg;
56 void *data;
57 int ret;
58
59 if (argc < 1)
60 return 1;
61
62 if (unl_genl_init(&unl, "nl80211") < 0) {
63 fprintf(stderr, "Failed to connect to nl80211\n");
64 return 2;
65 }
66
67 msg = unl_genl_msg(&unl, NL80211_CMD_VENDOR, false);
68
69 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, idx) ||
70 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, MTK_NL80211_VENDOR_ID) ||
71 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD, MTK_NL80211_VENDOR_SUBCMD_AMNT_CTRL))
72 return false;
73
74 data = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA | NLA_F_NESTED);
developer0497a7b2021-10-04 10:00:27 +080075 if (!data)
76 return -ENOMEM;
developere53f0872021-07-23 11:13:49 +080077
78 mt76_amnt_set_attr(msg, argc, argv);
79
80 nla_nest_end(msg, data);
81
82 ret = unl_genl_request(&unl, msg, NULL, NULL);
83 if (ret)
84 fprintf(stderr, "nl80211 call failed: %s\n", strerror(-ret));
85
86 unl_free(&unl);
87
88 return ret;
89}
90
91static int mt76_amnt_dump_cb(struct nl_msg *msg, void *arg)
92{
93 struct nlattr *tb1[NUM_MTK_VENDOR_ATTRS_AMNT_CTRL];
94 struct nlattr *tb2[NUM_MTK_VENDOR_ATTRS_AMNT_DUMP];
95 struct nlattr *attr;
96 struct nlattr *data;
97 struct nlattr *cur;
98 struct amnt_data *res;
99 int len = 0, rem;
100
101 attr = unl_find_attr(&unl, msg, NL80211_ATTR_VENDOR_DATA);
102 if (!attr) {
103 fprintf(stderr, "Testdata attribute not found\n");
104 return NL_SKIP;
105 }
106
107 nla_parse_nested(tb1, MTK_VENDOR_ATTR_AMNT_CTRL_MAX,
108 attr, amnt_ctrl_policy);
109
110 if (!tb1[MTK_VENDOR_ATTR_AMNT_CTRL_DUMP])
111 return NL_SKIP;
112
113 nla_parse_nested(tb2, NUM_MTK_VENDOR_ATTRS_AMNT_DUMP,
114 tb1[MTK_VENDOR_ATTR_AMNT_CTRL_DUMP], amnt_dump_policy);
115
116 if (!tb2[MTK_VENDOR_ATTR_AMNT_DUMP_LEN])
117 return NL_SKIP;
118
119 len = nla_get_u8(tb2[MTK_VENDOR_ATTR_AMNT_DUMP_LEN]);
120 if (!len)
121 return 0;
122
123 if (!tb2[MTK_VENDOR_ATTR_AMNT_DUMP_RESULT])
124 return NL_SKIP;
125
126 data = tb2[MTK_VENDOR_ATTR_AMNT_DUMP_RESULT];
127 nla_for_each_nested(cur,data, rem) {
128 res = (struct amnt_data *) nla_data(cur);
129 printf("[vendor] amnt_idx: %d, addr=%x:%x:%x:%x:%x:%x, rssi=%d/%d/%d/%d, last_seen=%u\n",
130 res->idx,
131 res->addr[0], res->addr[1], res->addr[2],
132 res->addr[3], res->addr[4], res->addr[5],
133 res->rssi[0], res->rssi[1], res->rssi[2],
134 res->rssi[3], res->last_seen);
135 }
136 return 0;
137}
138
139int mt76_amnt_dump(int idx, int argc, char **argv)
140{
developer0497a7b2021-10-04 10:00:27 +0800141 struct nl_msg *msg;
142 void *data, *tb1;
143 int ret = -EINVAL;
144 u8 amnt_idx;
developere53f0872021-07-23 11:13:49 +0800145
146 if (argc < 1)
147 return 1;
148
149 if (unl_genl_init(&unl, "nl80211") < 0) {
150 fprintf(stderr, "Failed to connect to nl80211\n");
151 return 2;
152 }
153
154 msg = unl_genl_msg(&unl, NL80211_CMD_VENDOR, true);
155
156 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, idx) ||
157 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, MTK_NL80211_VENDOR_ID) ||
158 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD, MTK_NL80211_VENDOR_SUBCMD_AMNT_CTRL))
159 return false;
160
161 data = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA | NLA_F_NESTED);
developer0497a7b2021-10-04 10:00:27 +0800162 if (!data)
163 goto out;
developere53f0872021-07-23 11:13:49 +0800164
165 tb1 = nla_nest_start(msg, MTK_VENDOR_ATTR_AMNT_CTRL_DUMP | NLA_F_NESTED);
developer0497a7b2021-10-04 10:00:27 +0800166 if (!tb1)
167 goto out;
developere53f0872021-07-23 11:13:49 +0800168
169 amnt_idx = strtoul(argv[0], NULL, 0);
170 nla_put_u8(msg, MTK_VENDOR_ATTR_AMNT_DUMP_INDEX, amnt_idx);
171
172 nla_nest_end(msg, tb1);
173
174 nla_nest_end(msg, data);
175
176 ret = unl_genl_request(&unl, msg, mt76_amnt_dump_cb, NULL);
177 if (ret)
178 fprintf(stderr, "nl80211 call failed: %s\n", strerror(-ret));
179
developer0497a7b2021-10-04 10:00:27 +0800180out:
developere53f0872021-07-23 11:13:49 +0800181 unl_free(&unl);
182
183 return ret;
developer6f8cffd2021-09-29 19:48:25 +0800184}