xref: /OK3568_Linux_fs/external/rkwifibt/drivers/rtl8188fu/os_dep/linux/nlrtw.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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 
34 	__NLRTW_CMD_AFTER_LAST,
35 	NLRTW_CMD_MAX = __NLRTW_CMD_AFTER_LAST - 1
36 };
37 
38 enum nlrtw_attrs {
39 	NLRTW_ATTR_UNSPEC,
40 
41 	NLRTW_ATTR_WIPHY_NAME,
42 	NLRTW_ATTR_CHANNEL_UTILIZATIONS,
43 	NLRTW_ATTR_CHANNEL_UTILIZATION_THRESHOLD,
44 
45 	__NLRTW_ATTR_AFTER_LAST,
46 	NUM_NLRTW_ATTR = __NLRTW_ATTR_AFTER_LAST,
47 	NLRTW_ATTR_MAX = __NLRTW_ATTR_AFTER_LAST - 1
48 };
49 
50 enum nlrtw_ch_util_attrs {
51 	__NLRTW_ATTR_CHANNEL_UTILIZATION_INVALID,
52 
53 	NLRTW_ATTR_CHANNEL_UTILIZATION_VALUE,
54 	NLRTW_ATTR_CHANNEL_UTILIZATION_BSSID,
55 
56 	__NLRTW_ATTR_CHANNEL_UTILIZATION_AFTER_LAST,
57 	NUM_NLRTW_ATTR_CHANNEL_UTILIZATION = __NLRTW_ATTR_CHANNEL_UTILIZATION_AFTER_LAST,
58 	NLRTW_ATTR_CHANNEL_UTILIZATION_MAX = __NLRTW_ATTR_CHANNEL_UTILIZATION_AFTER_LAST - 1
59 };
60 
nlrtw_ch_util_set(struct sk_buff * skb,struct genl_info * info)61 static int nlrtw_ch_util_set(struct sk_buff *skb, struct genl_info *info)
62 {
63 	unsigned int msg;
64 
65 	if (!info->attrs[NLRTW_ATTR_CHANNEL_UTILIZATION_THRESHOLD])
66 		return -EINVAL;
67 	msg = nla_get_u8(info->attrs[NLRTW_ATTR_CHANNEL_UTILIZATION_THRESHOLD]);
68 
69 	return 0;
70 }
71 
72 static struct nla_policy nlrtw_genl_policy[NUM_NLRTW_ATTR] = {
73 	[NLRTW_ATTR_CHANNEL_UTILIZATION_THRESHOLD] = { .type = NLA_U8 },
74 };
75 
76 static struct genl_ops nlrtw_genl_ops[] = {
77 	{
78 		.cmd = NLRTW_CMD_CHANNEL_UTILIZATION,
79 		.flags = 0,
80 		.policy = nlrtw_genl_policy,
81 		.doit = nlrtw_ch_util_set,
82 		.dumpit = NULL,
83 	},
84 };
85 
86 enum nlrtw_multicast_groups {
87 	NLRTW_MCGRP_DEFAULT,
88 };
89 static struct genl_multicast_group nlrtw_genl_mcgrp[] = {
90 	[NLRTW_MCGRP_DEFAULT] = { .name = "nlrtw_default" },
91 };
92 
93 /* family definition */
94 static struct genl_family nlrtw_genl_family = {
95 	.hdrsize = 0,
96 	.name = "nlrtw_"DRV_NAME,
97 	.version = 1,
98 	.maxattr = NLRTW_ATTR_MAX,
99 
100 	.netnsok = true,
101 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 12)
102 	.module = THIS_MODULE,
103 #endif
104 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)
105 	.ops = nlrtw_genl_ops,
106 	.n_ops = ARRAY_SIZE(nlrtw_genl_ops),
107 	.mcgrps = nlrtw_genl_mcgrp,
108 	.n_mcgrps = ARRAY_SIZE(nlrtw_genl_mcgrp),
109 #endif
110 };
111 
nlrtw_multicast(const struct genl_family * family,struct sk_buff * skb,u32 portid,unsigned int group,gfp_t flags)112 static inline int nlrtw_multicast(const struct genl_family *family,
113 				  struct sk_buff *skb, u32 portid,
114 				  unsigned int group, gfp_t flags)
115 {
116 	int ret;
117 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)
118 	ret = genlmsg_multicast(&nlrtw_genl_family, skb, portid, group, flags);
119 #else
120 	ret = genlmsg_multicast(skb, portid, nlrtw_genl_mcgrp[group].id, flags);
121 #endif
122 	return ret;
123 }
124 
rtw_nlrtw_ch_util_rpt(_adapter * adapter,u8 n_rpts,u8 * val,u8 ** mac_addr)125 int rtw_nlrtw_ch_util_rpt(_adapter *adapter, u8 n_rpts, u8 *val, u8 **mac_addr)
126 {
127 	struct sk_buff *skb = NULL;
128 	void *msg_header = NULL;
129 	struct nlattr *nl_ch_util, *nl_ch_utils;
130 	struct wiphy *wiphy;
131 	u8 i;
132 	int ret;
133 
134 	wiphy = adapter_to_wiphy(adapter);
135 	if (!wiphy)
136 		return -EINVAL;
137 
138 	/* allocate memory */
139 	skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
140 	if (!skb) {
141 		nlmsg_free(skb);
142 		return -ENOMEM;
143 	}
144 
145 	/* create the message headers */
146 	msg_header = genlmsg_put(skb, 0, 0, &nlrtw_genl_family, 0,
147 				 NLRTW_CMD_CHANNEL_UTILIZATION);
148 	if (!msg_header) {
149 		ret = -ENOMEM;
150 		goto err_out;
151 	}
152 
153 	/* add attributes */
154 	ret = nla_put_string(skb, NLRTW_ATTR_WIPHY_NAME, wiphy_name(wiphy));
155 
156 	nl_ch_utils = nla_nest_start(skb, NLRTW_ATTR_CHANNEL_UTILIZATIONS);
157 	if (!nl_ch_utils) {
158 		ret = -EMSGSIZE;
159 		goto err_out;
160 	}
161 
162 	for (i = 0; i < n_rpts; i++) {
163 		nl_ch_util = nla_nest_start(skb, i);
164 		if (!nl_ch_util) {
165 			ret = -EMSGSIZE;
166 			goto err_out;
167 		}
168 
169 		ret = nla_put(skb, NLRTW_ATTR_CHANNEL_UTILIZATION_BSSID, ETH_ALEN, *(mac_addr + i));
170 		if (ret != 0)
171 			goto err_out;
172 
173 		ret = nla_put_u8(skb, NLRTW_ATTR_CHANNEL_UTILIZATION_VALUE, *(val + i));
174 		if (ret != 0)
175 			goto err_out;
176 
177 		nla_nest_end(skb, nl_ch_util);
178 	}
179 
180 	nla_nest_end(skb, nl_ch_utils);
181 
182 	/* finalize the message */
183 	genlmsg_end(skb, msg_header);
184 
185 	ret = nlrtw_multicast(&nlrtw_genl_family, skb, 0, NLRTW_MCGRP_DEFAULT, GFP_KERNEL);
186 	if (ret == -ESRCH) {
187 		RTW_INFO("[%s] return ESRCH(No such process)."
188 			 " Maybe no process waits for this msg\n", __func__);
189 		return ret;
190 	} else if (ret != 0) {
191 		RTW_INFO("[%s] ret = %d\n", __func__, ret);
192 		return ret;
193 	}
194 
195 	return 0;
196 err_out:
197 	nlmsg_free(skb);
198 	return ret;
199 }
200 
rtw_nlrtw_init(void)201 int rtw_nlrtw_init(void)
202 {
203 	int err;
204 
205 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)
206 	err = genl_register_family(&nlrtw_genl_family);
207 	if (err)
208 		return err;
209 #else
210 	err = genl_register_family_with_ops(&nlrtw_genl_family, nlrtw_genl_ops, ARRAY_SIZE(nlrtw_genl_ops));
211 	if (err)
212 		return err;
213 
214 	err = genl_register_mc_group(&nlrtw_genl_family, &nlrtw_genl_mcgrp[0]);
215 	if (err) {
216 		genl_unregister_family(&nlrtw_genl_family);
217 		return err;
218 	}
219 #endif
220 	RTW_INFO("[%s] %s\n", __func__, nlrtw_genl_family.name);
221 	return 0;
222 }
223 
rtw_nlrtw_deinit(void)224 int rtw_nlrtw_deinit(void)
225 {
226 	int err;
227 
228 	err = genl_unregister_family(&nlrtw_genl_family);
229 	RTW_INFO("[%s] err = %d\n", __func__, err);
230 
231 	return err;
232 }
233 #endif /* CONFIG_RTW_NLRTW */
234