1 /******************************************************************************
2 *
3 * Copyright(c) 2007 - 2020 Realtek Corporation.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 *****************************************************************************/
15 #define _RTW_NLRTW_C_
16
17 #include <drv_types.h>
18 #include "nlrtw.h"
19
20 #ifdef CONFIG_RTW_NLRTW
21
22 #include <net/netlink.h>
23 #include <net/genetlink.h>
24 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0))
25 #include <uapi/linux/netlink.h>
26 #endif
27
28
29 enum nlrtw_cmds {
30 NLRTW_CMD_UNSPEC,
31
32 NLRTW_CMD_CHANNEL_UTILIZATION,
33 NLRTW_CMD_REG_CHANGE,
34 NLRTW_CMD_REG_BEACON_HINT,
35 NLRTW_CMD_RADAR_EVENT,
36 NLRTW_CMD_RADIO_OPMODE,
37
38 __NLRTW_CMD_AFTER_LAST,
39 NLRTW_CMD_MAX = __NLRTW_CMD_AFTER_LAST - 1
40 };
41
42 enum nlrtw_attrs {
43 NLRTW_ATTR_UNSPEC,
44
45 NLRTW_ATTR_WIPHY_NAME,
46 NLRTW_ATTR_CHANNEL_UTILIZATIONS,
47 NLRTW_ATTR_CHANNEL_UTILIZATION_THRESHOLD,
48 NLRTW_ATTR_CHANNEL_CENTER,
49 NLRTW_ATTR_CHANNEL_WIDTH,
50 NLRTW_ATTR_RADAR_EVENT,
51 NLRTW_ATTR_OP_CLASS,
52 NLRTW_ATTR_OP_CHANNEL,
53 NLRTW_ATTR_OP_TXPWR_MAX,
54 NLRTW_ATTR_IF_OPMODES,
55
56 __NLRTW_ATTR_AFTER_LAST,
57 NUM_NLRTW_ATTR = __NLRTW_ATTR_AFTER_LAST,
58 NLRTW_ATTR_MAX = __NLRTW_ATTR_AFTER_LAST - 1
59 };
60
61 enum nlrtw_ch_util_attrs {
62 __NLRTW_ATTR_CHANNEL_UTILIZATION_INVALID,
63
64 NLRTW_ATTR_CHANNEL_UTILIZATION_VALUE,
65 NLRTW_ATTR_CHANNEL_UTILIZATION_BSSID,
66
67 __NLRTW_ATTR_CHANNEL_UTILIZATION_AFTER_LAST,
68 NUM_NLRTW_ATTR_CHANNEL_UTILIZATION = __NLRTW_ATTR_CHANNEL_UTILIZATION_AFTER_LAST,
69 NLRTW_ATTR_CHANNEL_UTILIZATION_MAX = __NLRTW_ATTR_CHANNEL_UTILIZATION_AFTER_LAST - 1
70 };
71
72 enum nlrtw_radar_event {
73 NLRTW_RADAR_DETECTED,
74 NLRTW_RADAR_CAC_FINISHED,
75 NLRTW_RADAR_CAC_ABORTED,
76 NLRTW_RADAR_NOP_FINISHED,
77 NLRTW_RADAR_NOP_STARTED, /* NON_OCP started not by local radar detection */
78 };
79
80 enum nlrtw_if_opmode_attrs {
81 NLRTW_IF_OPMODE_UNSPEC,
82
83 NLRTW_IF_OPMODE_MACADDR,
84 NLRTW_IF_OPMODE_OP_CLASS,
85 NLRTW_IF_OPMODE_OP_CHANNEL,
86
87 __NLRTW_IF_OPMODE_ATTR_AFTER_LAST,
88 NUM_NLRTW_IF_OPMODE_ATTR = __NLRTW_IF_OPMODE_ATTR_AFTER_LAST,
89 NLRTW_IF_OPMODE_ATTR_MAX = __NLRTW_IF_OPMODE_ATTR_AFTER_LAST - 1
90 };
91
nlrtw_ch_util_set(struct sk_buff * skb,struct genl_info * info)92 static int nlrtw_ch_util_set(struct sk_buff *skb, struct genl_info *info)
93 {
94 unsigned int msg;
95
96 if (!info->attrs[NLRTW_ATTR_CHANNEL_UTILIZATION_THRESHOLD])
97 return -EINVAL;
98 msg = nla_get_u8(info->attrs[NLRTW_ATTR_CHANNEL_UTILIZATION_THRESHOLD]);
99
100 return 0;
101 }
102
103 static struct nla_policy nlrtw_genl_policy[NUM_NLRTW_ATTR] = {
104 [NLRTW_ATTR_CHANNEL_UTILIZATION_THRESHOLD] = { .type = NLA_U8 },
105 };
106
107 static struct genl_ops nlrtw_genl_ops[] = {
108 {
109 .cmd = NLRTW_CMD_CHANNEL_UTILIZATION,
110 .flags = 0,
111 #if LINUX_VERSION_CODE < KERNEL_VERSION(5, 2, 0)
112 .policy = nlrtw_genl_policy,
113 #endif
114 .doit = nlrtw_ch_util_set,
115 .dumpit = NULL,
116 },
117 };
118
119 enum nlrtw_multicast_groups {
120 NLRTW_MCGRP_DEFAULT,
121 };
122 static struct genl_multicast_group nlrtw_genl_mcgrp[] = {
123 [NLRTW_MCGRP_DEFAULT] = { .name = "nlrtw_default" },
124 };
125
126 /* family definition */
127 static struct genl_family nlrtw_genl_family = {
128 .hdrsize = 0,
129 .name = "nlrtw_"DRV_NAME,
130 .version = 1,
131 .maxattr = NLRTW_ATTR_MAX,
132 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0)
133 .policy = nlrtw_genl_policy,
134 #endif
135 .netnsok = true,
136 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 12)
137 .module = THIS_MODULE,
138 #endif
139 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)
140 .ops = nlrtw_genl_ops,
141 .n_ops = ARRAY_SIZE(nlrtw_genl_ops),
142 .mcgrps = nlrtw_genl_mcgrp,
143 .n_mcgrps = ARRAY_SIZE(nlrtw_genl_mcgrp),
144 #endif
145 };
146
nlrtw_multicast(const struct genl_family * family,struct sk_buff * skb,u32 portid,unsigned int group,gfp_t flags)147 static inline int nlrtw_multicast(const struct genl_family *family,
148 struct sk_buff *skb, u32 portid,
149 unsigned int group, gfp_t flags)
150 {
151 int ret;
152 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)
153 ret = genlmsg_multicast(&nlrtw_genl_family, skb, portid, group, flags);
154 #else
155 ret = genlmsg_multicast(skb, portid, nlrtw_genl_mcgrp[group].id, flags);
156 #endif
157 return ret;
158 }
159
rtw_nlrtw_ch_util_rpt(_adapter * adapter,u8 n_rpts,u8 * val,u8 ** mac_addr)160 int rtw_nlrtw_ch_util_rpt(_adapter *adapter, u8 n_rpts, u8 *val, u8 **mac_addr)
161 {
162 struct sk_buff *skb = NULL;
163 void *msg_header = NULL;
164 struct nlattr *nl_ch_util, *nl_ch_utils;
165 struct wiphy *wiphy;
166 u8 i;
167 int ret;
168
169 wiphy = adapter_to_wiphy(adapter);
170 if (!wiphy)
171 return -EINVAL;
172
173 /* allocate memory */
174 skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
175 if (!skb) {
176 nlmsg_free(skb);
177 return -ENOMEM;
178 }
179
180 /* create the message headers */
181 msg_header = genlmsg_put(skb, 0, 0, &nlrtw_genl_family, 0,
182 NLRTW_CMD_CHANNEL_UTILIZATION);
183 if (!msg_header) {
184 ret = -ENOMEM;
185 goto err_out;
186 }
187
188 /* add attributes */
189 ret = nla_put_string(skb, NLRTW_ATTR_WIPHY_NAME, wiphy_name(wiphy));
190
191 nl_ch_utils = nla_nest_start(skb, NLRTW_ATTR_CHANNEL_UTILIZATIONS);
192 if (!nl_ch_utils) {
193 ret = -EMSGSIZE;
194 goto err_out;
195 }
196
197 for (i = 0; i < n_rpts; i++) {
198 nl_ch_util = nla_nest_start(skb, i);
199 if (!nl_ch_util) {
200 ret = -EMSGSIZE;
201 goto err_out;
202 }
203
204 ret = nla_put(skb, NLRTW_ATTR_CHANNEL_UTILIZATION_BSSID, ETH_ALEN, *(mac_addr + i));
205 if (ret != 0)
206 goto err_out;
207
208 ret = nla_put_u8(skb, NLRTW_ATTR_CHANNEL_UTILIZATION_VALUE, *(val + i));
209 if (ret != 0)
210 goto err_out;
211
212 nla_nest_end(skb, nl_ch_util);
213 }
214
215 nla_nest_end(skb, nl_ch_utils);
216
217 /* finalize the message */
218 genlmsg_end(skb, msg_header);
219
220 ret = nlrtw_multicast(&nlrtw_genl_family, skb, 0, NLRTW_MCGRP_DEFAULT, GFP_KERNEL);
221 if (ret == -ESRCH) {
222 RTW_INFO("[%s] return ESRCH(No such process)."
223 " Maybe no process waits for this msg\n", __func__);
224 return ret;
225 } else if (ret != 0) {
226 RTW_INFO("[%s] ret = %d\n", __func__, ret);
227 return ret;
228 }
229
230 return 0;
231 err_out:
232 nlmsg_free(skb);
233 return ret;
234 }
235
rtw_nlrtw_reg_change_event(_adapter * adapter)236 int rtw_nlrtw_reg_change_event(_adapter *adapter)
237 {
238 struct sk_buff *skb = NULL;
239 void *msg_header = NULL;
240 struct wiphy *wiphy;
241 u8 i;
242 int ret;
243
244 wiphy = adapter_to_wiphy(adapter);
245 if (!wiphy) {
246 ret = -EINVAL;
247 goto err_out;
248 }
249
250 /* allocate memory */
251 skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
252 if (!skb) {
253 ret = -ENOMEM;
254 goto err_out;
255 }
256
257 /* create the message headers */
258 msg_header = genlmsg_put(skb, 0, 0, &nlrtw_genl_family, 0, NLRTW_CMD_REG_CHANGE);
259 if (!msg_header) {
260 ret = -ENOMEM;
261 goto err_out;
262 }
263
264 /* add attributes */
265 ret = nla_put_string(skb, NLRTW_ATTR_WIPHY_NAME, wiphy_name(wiphy));
266 if (ret)
267 goto err_out;
268
269 /* finalize the message */
270 genlmsg_end(skb, msg_header);
271
272 ret = nlrtw_multicast(&nlrtw_genl_family, skb, 0, NLRTW_MCGRP_DEFAULT, GFP_KERNEL);
273 if (ret == -ESRCH) {
274 RTW_DBG(FUNC_WIPHY_FMT" return -ESRCH(No such process)."
275 " Maybe no process waits for this msg\n", FUNC_WIPHY_ARG(wiphy));
276 return ret;
277 } else if (ret != 0) {
278 RTW_WARN(FUNC_WIPHY_FMT" return %d\n", FUNC_WIPHY_ARG(wiphy), ret);
279 return ret;
280 }
281
282 return 0;
283
284 err_out:
285 if (skb)
286 nlmsg_free(skb);
287 return ret;
288 }
289
rtw_nlrtw_reg_beacon_hint_event(_adapter * adapter)290 int rtw_nlrtw_reg_beacon_hint_event(_adapter *adapter)
291 {
292 struct sk_buff *skb = NULL;
293 void *msg_header = NULL;
294 struct wiphy *wiphy;
295 u8 i;
296 int ret;
297
298 wiphy = adapter_to_wiphy(adapter);
299 if (!wiphy) {
300 ret = -EINVAL;
301 goto err_out;
302 }
303
304 /* allocate memory */
305 skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
306 if (!skb) {
307 ret = -ENOMEM;
308 goto err_out;
309 }
310
311 /* create the message headers */
312 msg_header = genlmsg_put(skb, 0, 0, &nlrtw_genl_family, 0, NLRTW_CMD_REG_BEACON_HINT);
313 if (!msg_header) {
314 ret = -ENOMEM;
315 goto err_out;
316 }
317
318 /* add attributes */
319 ret = nla_put_string(skb, NLRTW_ATTR_WIPHY_NAME, wiphy_name(wiphy));
320 if (ret)
321 goto err_out;
322
323 /* finalize the message */
324 genlmsg_end(skb, msg_header);
325
326 ret = nlrtw_multicast(&nlrtw_genl_family, skb, 0, NLRTW_MCGRP_DEFAULT, GFP_KERNEL);
327 if (ret == -ESRCH) {
328 RTW_DBG(FUNC_WIPHY_FMT" return -ESRCH(No such process)."
329 " Maybe no process waits for this msg\n", FUNC_WIPHY_ARG(wiphy));
330 return ret;
331 } else if (ret != 0) {
332 RTW_WARN(FUNC_WIPHY_FMT" return %d\n", FUNC_WIPHY_ARG(wiphy), ret);
333 return ret;
334 }
335
336 return 0;
337
338 err_out:
339 if (skb)
340 nlmsg_free(skb);
341 return ret;
342 }
343
344 #ifdef CONFIG_DFS_MASTER
_rtw_nlrtw_radar_event(_adapter * adapter,enum nlrtw_radar_event evt_type,u8 cch,u8 bw)345 static int _rtw_nlrtw_radar_event(_adapter *adapter, enum nlrtw_radar_event evt_type, u8 cch, u8 bw)
346 {
347 struct sk_buff *skb = NULL;
348 void *msg_header = NULL;
349 struct wiphy *wiphy;
350 u8 i;
351 int ret;
352
353 wiphy = adapter_to_wiphy(adapter);
354 if (!wiphy) {
355 ret = -EINVAL;
356 goto err_out;
357 }
358
359 /* allocate memory */
360 skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
361 if (!skb) {
362 ret = -ENOMEM;
363 goto err_out;
364 }
365
366 /* create the message headers */
367 msg_header = genlmsg_put(skb, 0, 0, &nlrtw_genl_family, 0, NLRTW_CMD_RADAR_EVENT);
368 if (!msg_header) {
369 ret = -ENOMEM;
370 goto err_out;
371 }
372
373 /* add attributes */
374 ret = nla_put_string(skb, NLRTW_ATTR_WIPHY_NAME, wiphy_name(wiphy));
375 if (ret)
376 goto err_out;
377
378 ret = nla_put_u8(skb, NLRTW_ATTR_RADAR_EVENT, (uint8_t)evt_type);
379 if (ret != 0)
380 goto err_out;
381
382 ret = nla_put_u8(skb, NLRTW_ATTR_CHANNEL_CENTER, cch);
383 if (ret != 0)
384 goto err_out;
385
386 ret = nla_put_u8(skb, NLRTW_ATTR_CHANNEL_WIDTH, bw);
387 if (ret != 0)
388 goto err_out;
389
390 /* finalize the message */
391 genlmsg_end(skb, msg_header);
392
393 ret = nlrtw_multicast(&nlrtw_genl_family, skb, 0, NLRTW_MCGRP_DEFAULT, GFP_KERNEL);
394 if (ret == -ESRCH) {
395 RTW_DBG(FUNC_WIPHY_FMT" return -ESRCH(No such process)."
396 " Maybe no process waits for this msg\n", FUNC_WIPHY_ARG(wiphy));
397 return ret;
398 } else if (ret != 0) {
399 RTW_WARN(FUNC_WIPHY_FMT" return %d\n", FUNC_WIPHY_ARG(wiphy), ret);
400 return ret;
401 }
402
403 return 0;
404
405 err_out:
406 if (skb)
407 nlmsg_free(skb);
408 return ret;
409 }
410
rtw_nlrtw_radar_detect_event(_adapter * adapter,u8 cch,u8 bw)411 int rtw_nlrtw_radar_detect_event(_adapter *adapter, u8 cch, u8 bw)
412 {
413 return _rtw_nlrtw_radar_event(adapter, NLRTW_RADAR_DETECTED, cch, bw);
414 }
415
rtw_nlrtw_cac_finish_event(_adapter * adapter,u8 cch,u8 bw)416 int rtw_nlrtw_cac_finish_event(_adapter *adapter, u8 cch, u8 bw)
417 {
418 return _rtw_nlrtw_radar_event(adapter, NLRTW_RADAR_CAC_FINISHED, cch, bw);
419 }
420
rtw_nlrtw_cac_abort_event(_adapter * adapter,u8 cch,u8 bw)421 int rtw_nlrtw_cac_abort_event(_adapter *adapter, u8 cch, u8 bw)
422 {
423 return _rtw_nlrtw_radar_event(adapter, NLRTW_RADAR_CAC_ABORTED, cch, bw);
424 }
425
rtw_nlrtw_nop_finish_event(_adapter * adapter,u8 cch,u8 bw)426 int rtw_nlrtw_nop_finish_event(_adapter *adapter, u8 cch, u8 bw)
427 {
428 return _rtw_nlrtw_radar_event(adapter, NLRTW_RADAR_NOP_FINISHED, cch, bw);
429 }
430
rtw_nlrtw_nop_start_event(_adapter * adapter,u8 cch,u8 bw)431 int rtw_nlrtw_nop_start_event(_adapter *adapter, u8 cch, u8 bw)
432 {
433 return _rtw_nlrtw_radar_event(adapter, NLRTW_RADAR_NOP_STARTED, cch, bw);
434 }
435 #endif /* CONFIG_DFS_MASTER */
436
rtw_nlrtw_radio_opmode_notify(struct rf_ctl_t * rfctl)437 int rtw_nlrtw_radio_opmode_notify(struct rf_ctl_t *rfctl)
438 {
439 struct dvobj_priv *dvobj = rfctl_to_dvobj(rfctl);
440 _adapter *iface;
441 struct sk_buff *skb = NULL;
442 void *msg_header = NULL;
443 struct nlattr *nl_if_opmodes, *nl_if_opmode;
444 struct wiphy *wiphy;
445 u16 op_txpwr_max_u16;
446 u8 i;
447 int ret;
448
449 wiphy = dvobj_to_wiphy(dvobj);
450 if (!wiphy) {
451 ret = -EINVAL;
452 goto err_out;
453 }
454
455 /* allocate memory */
456 skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
457 if (!skb) {
458 ret = -ENOMEM;
459 goto err_out;
460 }
461
462 /* create the message headers */
463 msg_header = genlmsg_put(skb, 0, 0, &nlrtw_genl_family, 0, NLRTW_CMD_RADIO_OPMODE);
464 if (!msg_header) {
465 ret = -ENOBUFS;
466 goto err_out;
467 }
468
469 /* add attributes */
470 ret = nla_put_string(skb, NLRTW_ATTR_WIPHY_NAME, wiphy_name(wiphy));
471 if (ret)
472 goto err_out;
473
474 ret = nla_put_u8(skb, NLRTW_ATTR_OP_CLASS, rfctl->op_class);
475 if (ret != 0)
476 goto err_out;
477
478 ret = nla_put_u8(skb, NLRTW_ATTR_OP_CHANNEL, rfctl->op_ch);
479 if (ret != 0)
480 goto err_out;
481
482 *((s16 *)&op_txpwr_max_u16) = rfctl->op_txpwr_max;
483 ret = nla_put_u16(skb, NLRTW_ATTR_OP_TXPWR_MAX, op_txpwr_max_u16);
484 if (ret != 0)
485 goto err_out;
486
487 if (0)
488 RTW_INFO("radio: %u,%u %d\n", rfctl->op_class, rfctl->op_ch, rfctl->op_txpwr_max);
489
490 nl_if_opmodes = nla_nest_start(skb, NLRTW_ATTR_IF_OPMODES);
491 if (!nl_if_opmodes) {
492 ret = -ENOBUFS;
493 goto err_out;
494 }
495
496 for (i = 0; i < dvobj->iface_nums; i++) {
497 if (!dvobj->padapters[i])
498 continue;
499 iface = dvobj->padapters[i];
500
501 if (!rfctl->if_op_class[i] || !rfctl->if_op_ch[i])
502 continue;
503
504 if (0)
505 RTW_INFO(ADPT_FMT": %u,%u\n", ADPT_ARG(iface), rfctl->if_op_class[i], rfctl->if_op_ch[i]);
506
507 nl_if_opmode = nla_nest_start(skb, i + 1);
508 if (!nl_if_opmode) {
509 ret = -ENOBUFS;
510 goto err_out;
511 }
512
513 ret = nla_put(skb, NLRTW_IF_OPMODE_MACADDR, ETH_ALEN, adapter_mac_addr(iface));
514 if (ret != 0)
515 goto err_out;
516
517 ret = nla_put_u8(skb, NLRTW_IF_OPMODE_OP_CLASS, rfctl->if_op_class[i]);
518 if (ret != 0)
519 goto err_out;
520
521 ret = nla_put_u8(skb, NLRTW_IF_OPMODE_OP_CHANNEL, rfctl->if_op_ch[i]);
522 if (ret != 0)
523 goto err_out;
524
525 nla_nest_end(skb, nl_if_opmode);
526 }
527
528 nla_nest_end(skb, nl_if_opmodes);
529
530 /* finalize the message */
531 genlmsg_end(skb, msg_header);
532
533 ret = nlrtw_multicast(&nlrtw_genl_family, skb, 0, NLRTW_MCGRP_DEFAULT, GFP_KERNEL);
534 if (ret == -ESRCH) {
535 RTW_DBG(FUNC_WIPHY_FMT" return -ESRCH(No such process)."
536 " Maybe no process waits for this msg\n", FUNC_WIPHY_ARG(wiphy));
537 return ret;
538 } else if (ret != 0) {
539 RTW_WARN(FUNC_WIPHY_FMT" return %d\n", FUNC_WIPHY_ARG(wiphy), ret);
540 return ret;
541 }
542
543 return 0;
544
545 err_out:
546 if (skb)
547 nlmsg_free(skb);
548 return ret;
549 }
550
rtw_nlrtw_init(void)551 int rtw_nlrtw_init(void)
552 {
553 int err;
554
555 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)
556 err = genl_register_family(&nlrtw_genl_family);
557 if (err)
558 return err;
559 #else
560 err = genl_register_family_with_ops(&nlrtw_genl_family, nlrtw_genl_ops, ARRAY_SIZE(nlrtw_genl_ops));
561 if (err)
562 return err;
563
564 err = genl_register_mc_group(&nlrtw_genl_family, &nlrtw_genl_mcgrp[0]);
565 if (err) {
566 genl_unregister_family(&nlrtw_genl_family);
567 return err;
568 }
569 #endif
570 RTW_INFO("[%s] %s\n", __func__, nlrtw_genl_family.name);
571 return 0;
572 }
573
rtw_nlrtw_deinit(void)574 int rtw_nlrtw_deinit(void)
575 {
576 int err;
577
578 err = genl_unregister_family(&nlrtw_genl_family);
579 RTW_INFO("[%s] err = %d\n", __func__, err);
580
581 return err;
582 }
583 #endif /* CONFIG_RTW_NLRTW */
584