xref: /OK3568_Linux_fs/external/rkwifibt/drivers/rtl8188fu/os_dep/linux/nlrtw.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /******************************************************************************
2*4882a593Smuzhiyun  *
3*4882a593Smuzhiyun  * Copyright(c) 2007 - 2020 Realtek Corporation.
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * This program is free software; you can redistribute it and/or modify it
6*4882a593Smuzhiyun  * under the terms of version 2 of the GNU General Public License as
7*4882a593Smuzhiyun  * published by the Free Software Foundation.
8*4882a593Smuzhiyun  *
9*4882a593Smuzhiyun  * This program is distributed in the hope that it will be useful, but WITHOUT
10*4882a593Smuzhiyun  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11*4882a593Smuzhiyun  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12*4882a593Smuzhiyun  * more details.
13*4882a593Smuzhiyun  *
14*4882a593Smuzhiyun  *****************************************************************************/
15*4882a593Smuzhiyun #define _RTW_NLRTW_C_
16*4882a593Smuzhiyun 
17*4882a593Smuzhiyun #include <drv_types.h>
18*4882a593Smuzhiyun #include "nlrtw.h"
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun #ifdef CONFIG_RTW_NLRTW
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun #include <net/netlink.h>
23*4882a593Smuzhiyun #include <net/genetlink.h>
24*4882a593Smuzhiyun #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0))
25*4882a593Smuzhiyun #include <uapi/linux/netlink.h>
26*4882a593Smuzhiyun #endif
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun 
29*4882a593Smuzhiyun enum nlrtw_cmds {
30*4882a593Smuzhiyun 	NLRTW_CMD_UNSPEC,
31*4882a593Smuzhiyun 
32*4882a593Smuzhiyun 	NLRTW_CMD_CHANNEL_UTILIZATION,
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun 	__NLRTW_CMD_AFTER_LAST,
35*4882a593Smuzhiyun 	NLRTW_CMD_MAX = __NLRTW_CMD_AFTER_LAST - 1
36*4882a593Smuzhiyun };
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun enum nlrtw_attrs {
39*4882a593Smuzhiyun 	NLRTW_ATTR_UNSPEC,
40*4882a593Smuzhiyun 
41*4882a593Smuzhiyun 	NLRTW_ATTR_WIPHY_NAME,
42*4882a593Smuzhiyun 	NLRTW_ATTR_CHANNEL_UTILIZATIONS,
43*4882a593Smuzhiyun 	NLRTW_ATTR_CHANNEL_UTILIZATION_THRESHOLD,
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun 	__NLRTW_ATTR_AFTER_LAST,
46*4882a593Smuzhiyun 	NUM_NLRTW_ATTR = __NLRTW_ATTR_AFTER_LAST,
47*4882a593Smuzhiyun 	NLRTW_ATTR_MAX = __NLRTW_ATTR_AFTER_LAST - 1
48*4882a593Smuzhiyun };
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun enum nlrtw_ch_util_attrs {
51*4882a593Smuzhiyun 	__NLRTW_ATTR_CHANNEL_UTILIZATION_INVALID,
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun 	NLRTW_ATTR_CHANNEL_UTILIZATION_VALUE,
54*4882a593Smuzhiyun 	NLRTW_ATTR_CHANNEL_UTILIZATION_BSSID,
55*4882a593Smuzhiyun 
56*4882a593Smuzhiyun 	__NLRTW_ATTR_CHANNEL_UTILIZATION_AFTER_LAST,
57*4882a593Smuzhiyun 	NUM_NLRTW_ATTR_CHANNEL_UTILIZATION = __NLRTW_ATTR_CHANNEL_UTILIZATION_AFTER_LAST,
58*4882a593Smuzhiyun 	NLRTW_ATTR_CHANNEL_UTILIZATION_MAX = __NLRTW_ATTR_CHANNEL_UTILIZATION_AFTER_LAST - 1
59*4882a593Smuzhiyun };
60*4882a593Smuzhiyun 
nlrtw_ch_util_set(struct sk_buff * skb,struct genl_info * info)61*4882a593Smuzhiyun static int nlrtw_ch_util_set(struct sk_buff *skb, struct genl_info *info)
62*4882a593Smuzhiyun {
63*4882a593Smuzhiyun 	unsigned int msg;
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun 	if (!info->attrs[NLRTW_ATTR_CHANNEL_UTILIZATION_THRESHOLD])
66*4882a593Smuzhiyun 		return -EINVAL;
67*4882a593Smuzhiyun 	msg = nla_get_u8(info->attrs[NLRTW_ATTR_CHANNEL_UTILIZATION_THRESHOLD]);
68*4882a593Smuzhiyun 
69*4882a593Smuzhiyun 	return 0;
70*4882a593Smuzhiyun }
71*4882a593Smuzhiyun 
72*4882a593Smuzhiyun static struct nla_policy nlrtw_genl_policy[NUM_NLRTW_ATTR] = {
73*4882a593Smuzhiyun 	[NLRTW_ATTR_CHANNEL_UTILIZATION_THRESHOLD] = { .type = NLA_U8 },
74*4882a593Smuzhiyun };
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun static struct genl_ops nlrtw_genl_ops[] = {
77*4882a593Smuzhiyun 	{
78*4882a593Smuzhiyun 		.cmd = NLRTW_CMD_CHANNEL_UTILIZATION,
79*4882a593Smuzhiyun 		.flags = 0,
80*4882a593Smuzhiyun 		.policy = nlrtw_genl_policy,
81*4882a593Smuzhiyun 		.doit = nlrtw_ch_util_set,
82*4882a593Smuzhiyun 		.dumpit = NULL,
83*4882a593Smuzhiyun 	},
84*4882a593Smuzhiyun };
85*4882a593Smuzhiyun 
86*4882a593Smuzhiyun enum nlrtw_multicast_groups {
87*4882a593Smuzhiyun 	NLRTW_MCGRP_DEFAULT,
88*4882a593Smuzhiyun };
89*4882a593Smuzhiyun static struct genl_multicast_group nlrtw_genl_mcgrp[] = {
90*4882a593Smuzhiyun 	[NLRTW_MCGRP_DEFAULT] = { .name = "nlrtw_default" },
91*4882a593Smuzhiyun };
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun /* family definition */
94*4882a593Smuzhiyun static struct genl_family nlrtw_genl_family = {
95*4882a593Smuzhiyun 	.hdrsize = 0,
96*4882a593Smuzhiyun 	.name = "nlrtw_"DRV_NAME,
97*4882a593Smuzhiyun 	.version = 1,
98*4882a593Smuzhiyun 	.maxattr = NLRTW_ATTR_MAX,
99*4882a593Smuzhiyun 
100*4882a593Smuzhiyun 	.netnsok = true,
101*4882a593Smuzhiyun #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 12)
102*4882a593Smuzhiyun 	.module = THIS_MODULE,
103*4882a593Smuzhiyun #endif
104*4882a593Smuzhiyun #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)
105*4882a593Smuzhiyun 	.ops = nlrtw_genl_ops,
106*4882a593Smuzhiyun 	.n_ops = ARRAY_SIZE(nlrtw_genl_ops),
107*4882a593Smuzhiyun 	.mcgrps = nlrtw_genl_mcgrp,
108*4882a593Smuzhiyun 	.n_mcgrps = ARRAY_SIZE(nlrtw_genl_mcgrp),
109*4882a593Smuzhiyun #endif
110*4882a593Smuzhiyun };
111*4882a593Smuzhiyun 
nlrtw_multicast(const struct genl_family * family,struct sk_buff * skb,u32 portid,unsigned int group,gfp_t flags)112*4882a593Smuzhiyun static inline int nlrtw_multicast(const struct genl_family *family,
113*4882a593Smuzhiyun 				  struct sk_buff *skb, u32 portid,
114*4882a593Smuzhiyun 				  unsigned int group, gfp_t flags)
115*4882a593Smuzhiyun {
116*4882a593Smuzhiyun 	int ret;
117*4882a593Smuzhiyun #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)
118*4882a593Smuzhiyun 	ret = genlmsg_multicast(&nlrtw_genl_family, skb, portid, group, flags);
119*4882a593Smuzhiyun #else
120*4882a593Smuzhiyun 	ret = genlmsg_multicast(skb, portid, nlrtw_genl_mcgrp[group].id, flags);
121*4882a593Smuzhiyun #endif
122*4882a593Smuzhiyun 	return ret;
123*4882a593Smuzhiyun }
124*4882a593Smuzhiyun 
rtw_nlrtw_ch_util_rpt(_adapter * adapter,u8 n_rpts,u8 * val,u8 ** mac_addr)125*4882a593Smuzhiyun int rtw_nlrtw_ch_util_rpt(_adapter *adapter, u8 n_rpts, u8 *val, u8 **mac_addr)
126*4882a593Smuzhiyun {
127*4882a593Smuzhiyun 	struct sk_buff *skb = NULL;
128*4882a593Smuzhiyun 	void *msg_header = NULL;
129*4882a593Smuzhiyun 	struct nlattr *nl_ch_util, *nl_ch_utils;
130*4882a593Smuzhiyun 	struct wiphy *wiphy;
131*4882a593Smuzhiyun 	u8 i;
132*4882a593Smuzhiyun 	int ret;
133*4882a593Smuzhiyun 
134*4882a593Smuzhiyun 	wiphy = adapter_to_wiphy(adapter);
135*4882a593Smuzhiyun 	if (!wiphy)
136*4882a593Smuzhiyun 		return -EINVAL;
137*4882a593Smuzhiyun 
138*4882a593Smuzhiyun 	/* allocate memory */
139*4882a593Smuzhiyun 	skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
140*4882a593Smuzhiyun 	if (!skb) {
141*4882a593Smuzhiyun 		nlmsg_free(skb);
142*4882a593Smuzhiyun 		return -ENOMEM;
143*4882a593Smuzhiyun 	}
144*4882a593Smuzhiyun 
145*4882a593Smuzhiyun 	/* create the message headers */
146*4882a593Smuzhiyun 	msg_header = genlmsg_put(skb, 0, 0, &nlrtw_genl_family, 0,
147*4882a593Smuzhiyun 				 NLRTW_CMD_CHANNEL_UTILIZATION);
148*4882a593Smuzhiyun 	if (!msg_header) {
149*4882a593Smuzhiyun 		ret = -ENOMEM;
150*4882a593Smuzhiyun 		goto err_out;
151*4882a593Smuzhiyun 	}
152*4882a593Smuzhiyun 
153*4882a593Smuzhiyun 	/* add attributes */
154*4882a593Smuzhiyun 	ret = nla_put_string(skb, NLRTW_ATTR_WIPHY_NAME, wiphy_name(wiphy));
155*4882a593Smuzhiyun 
156*4882a593Smuzhiyun 	nl_ch_utils = nla_nest_start(skb, NLRTW_ATTR_CHANNEL_UTILIZATIONS);
157*4882a593Smuzhiyun 	if (!nl_ch_utils) {
158*4882a593Smuzhiyun 		ret = -EMSGSIZE;
159*4882a593Smuzhiyun 		goto err_out;
160*4882a593Smuzhiyun 	}
161*4882a593Smuzhiyun 
162*4882a593Smuzhiyun 	for (i = 0; i < n_rpts; i++) {
163*4882a593Smuzhiyun 		nl_ch_util = nla_nest_start(skb, i);
164*4882a593Smuzhiyun 		if (!nl_ch_util) {
165*4882a593Smuzhiyun 			ret = -EMSGSIZE;
166*4882a593Smuzhiyun 			goto err_out;
167*4882a593Smuzhiyun 		}
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun 		ret = nla_put(skb, NLRTW_ATTR_CHANNEL_UTILIZATION_BSSID, ETH_ALEN, *(mac_addr + i));
170*4882a593Smuzhiyun 		if (ret != 0)
171*4882a593Smuzhiyun 			goto err_out;
172*4882a593Smuzhiyun 
173*4882a593Smuzhiyun 		ret = nla_put_u8(skb, NLRTW_ATTR_CHANNEL_UTILIZATION_VALUE, *(val + i));
174*4882a593Smuzhiyun 		if (ret != 0)
175*4882a593Smuzhiyun 			goto err_out;
176*4882a593Smuzhiyun 
177*4882a593Smuzhiyun 		nla_nest_end(skb, nl_ch_util);
178*4882a593Smuzhiyun 	}
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun 	nla_nest_end(skb, nl_ch_utils);
181*4882a593Smuzhiyun 
182*4882a593Smuzhiyun 	/* finalize the message */
183*4882a593Smuzhiyun 	genlmsg_end(skb, msg_header);
184*4882a593Smuzhiyun 
185*4882a593Smuzhiyun 	ret = nlrtw_multicast(&nlrtw_genl_family, skb, 0, NLRTW_MCGRP_DEFAULT, GFP_KERNEL);
186*4882a593Smuzhiyun 	if (ret == -ESRCH) {
187*4882a593Smuzhiyun 		RTW_INFO("[%s] return ESRCH(No such process)."
188*4882a593Smuzhiyun 			 " Maybe no process waits for this msg\n", __func__);
189*4882a593Smuzhiyun 		return ret;
190*4882a593Smuzhiyun 	} else if (ret != 0) {
191*4882a593Smuzhiyun 		RTW_INFO("[%s] ret = %d\n", __func__, ret);
192*4882a593Smuzhiyun 		return ret;
193*4882a593Smuzhiyun 	}
194*4882a593Smuzhiyun 
195*4882a593Smuzhiyun 	return 0;
196*4882a593Smuzhiyun err_out:
197*4882a593Smuzhiyun 	nlmsg_free(skb);
198*4882a593Smuzhiyun 	return ret;
199*4882a593Smuzhiyun }
200*4882a593Smuzhiyun 
rtw_nlrtw_init(void)201*4882a593Smuzhiyun int rtw_nlrtw_init(void)
202*4882a593Smuzhiyun {
203*4882a593Smuzhiyun 	int err;
204*4882a593Smuzhiyun 
205*4882a593Smuzhiyun #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)
206*4882a593Smuzhiyun 	err = genl_register_family(&nlrtw_genl_family);
207*4882a593Smuzhiyun 	if (err)
208*4882a593Smuzhiyun 		return err;
209*4882a593Smuzhiyun #else
210*4882a593Smuzhiyun 	err = genl_register_family_with_ops(&nlrtw_genl_family, nlrtw_genl_ops, ARRAY_SIZE(nlrtw_genl_ops));
211*4882a593Smuzhiyun 	if (err)
212*4882a593Smuzhiyun 		return err;
213*4882a593Smuzhiyun 
214*4882a593Smuzhiyun 	err = genl_register_mc_group(&nlrtw_genl_family, &nlrtw_genl_mcgrp[0]);
215*4882a593Smuzhiyun 	if (err) {
216*4882a593Smuzhiyun 		genl_unregister_family(&nlrtw_genl_family);
217*4882a593Smuzhiyun 		return err;
218*4882a593Smuzhiyun 	}
219*4882a593Smuzhiyun #endif
220*4882a593Smuzhiyun 	RTW_INFO("[%s] %s\n", __func__, nlrtw_genl_family.name);
221*4882a593Smuzhiyun 	return 0;
222*4882a593Smuzhiyun }
223*4882a593Smuzhiyun 
rtw_nlrtw_deinit(void)224*4882a593Smuzhiyun int rtw_nlrtw_deinit(void)
225*4882a593Smuzhiyun {
226*4882a593Smuzhiyun 	int err;
227*4882a593Smuzhiyun 
228*4882a593Smuzhiyun 	err = genl_unregister_family(&nlrtw_genl_family);
229*4882a593Smuzhiyun 	RTW_INFO("[%s] err = %d\n", __func__, err);
230*4882a593Smuzhiyun 
231*4882a593Smuzhiyun 	return err;
232*4882a593Smuzhiyun }
233*4882a593Smuzhiyun #endif /* CONFIG_RTW_NLRTW */
234