1 /*
2 * Copyright (c) 2022 Shenzhen Kaihong Digital Industry Development Co., Ltd.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
17 * USA.
18 */
19
20 #include "hdf_log.h"
21 #include "hdf_wifi_event.h"
22 #include "hdf_wlan_utils.h"
23 #include "osal_mem.h"
24 #include "osl.h"
25 #include "wifi_mac80211_ops.h"
26 #include "wifi_module.h"
27 #include <net/cfg80211.h>
28 #include <net/regulatory.h>
29
30 #include "eapol.h"
31 #include "hdf_wl_interface.h"
32 #include "net_device_adapter.h"
33 #include <bcmutils.h>
34 #include <ethernet.h>
35 #include <securec.h>
36 #include <typedefs.h>
37 #include <wl_cfgp2p.h>
38
39 enum wl_management_type {
40 WL_BEACON = 0x1,
41 WL_PROBE_RESP = 0x2,
42 WL_ASSOC_RESP = 0x4
43 };
44
45 #define HDF_LOG_TAG BDH6Driver
46 #define HISI_DRIVER_FLAGS_AP 0x00000040
47 #define HISI_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE 0x00000400
48 #define HISI_DRIVER_FLAGS_P2P_CONCURRENT 0x00000200
49 #define HISI_DRIVER_FLAGS_P2P_CAPABLE 0x00000800
50 #define WLAN_WPS_IE_MAX_SIZE 352
51
52 #if defined(WL_CFG80211_P2P_DEV_IF)
53 #define ndev_to_cfg(ndev) ((ndev)->ieee80211_ptr)
54 #else
55 #define ndev_to_cfg(ndev) (ndev)
56 #endif
57 #ifndef ERRNO_T
58 #define ERRNO_T
59 typedef int errno_t;
60 #endif
61 extern struct net_device_ops dhd_ops_pri;
62 extern struct cfg80211_ops wl_cfg80211_ops;
63 extern struct hdf_inf_map g_hdf_infmap[HDF_INF_MAX];
64 extern int g_hdf_ifidx;
65 extern int g_event_ifidx;
66
67 extern struct net_device *
68 GetLinuxInfByNetDevice(const struct NetDevice *netDevice);
69 extern struct wiphy *get_linux_wiphy_ndev(struct net_device *ndev);
70 extern struct wiphy *get_linux_wiphy_hdfdev(NetDevice *netDev);
71 int BDH6InitNetdev(struct NetDevice *netDevice, int private_data_size, int type,
72 int ifidx);
73 int get_dhd_priv_data_size(void);
74 struct NetDevice *get_hdf_netdev(int ifidx);
75 int get_scan_ifidx(const char *ifname);
76
77 extern s32 wl_cfg80211_set_wps_p2p_ie(struct net_device *net, char *buf,
78 int len, enum wl_management_type type);
79
80 struct net_device *get_krn_netdev(int ifidx);
81 struct NetDevice *get_real_netdev(NetDevice *netDev);
82 extern void rtnl_lock(void);
83 extern void rtnl_unlock(void);
84
85 static u64 p2p_cookie = 0;
86 int start_p2p_completed = 0;
87
WalRemainOnChannel(struct NetDevice * netDev,WifiOnChannel * onChannel)88 int32_t WalRemainOnChannel(struct NetDevice *netDev, WifiOnChannel *onChannel)
89 {
90 struct net_device *netdev = NULL;
91 struct wiphy *wiphy = NULL;
92 bcm_struct_cfgdev *cfgdev = NULL;
93 struct ieee80211_channel *channel = NULL;
94 unsigned int duration;
95 struct NetDevice *hnetdev = netDev;
96 int ret = 0;
97
98 netDev = get_real_netdev(netDev);
99 netdev = GetLinuxInfByNetDevice(netDev);
100 if (!netdev) {
101 HDF_LOGE("%s: net_device is NULL", __func__);
102 return -1;
103 }
104
105 wiphy = get_linux_wiphy_ndev(netdev);
106 if (!wiphy) {
107 HDF_LOGE("%s: wiphy is NULL", __func__);
108 return -1;
109 }
110 HDF_LOGE("%s: ifname=%s, freq=%u, duration=%u", __func__, hnetdev->name,
111 onChannel->freq, onChannel->duration);
112
113 channel = OsalMemCalloc(sizeof(struct ieee80211_channel));
114 cfgdev = ndev_to_cfg(netdev);
115 channel->center_freq = onChannel->freq; // remain_on_channel函数需要的参数
116 duration = (unsigned int)onChannel->duration;
117
118 ret = wl_cfg80211_ops.remain_on_channel(wiphy, cfgdev, channel, duration,
119 &p2p_cookie);
120 OsalMemFree(channel);
121 return ret;
122 }
123
WalCancelRemainOnChannel(struct NetDevice * netDev)124 int32_t WalCancelRemainOnChannel(struct NetDevice *netDev)
125 {
126 struct net_device *netdev = NULL;
127 bcm_struct_cfgdev *cfgdev = NULL;
128 struct wiphy *wiphy = NULL;
129 struct NetDevice *hnetdev = netDev;
130
131 netDev = get_real_netdev(netDev);
132 netdev = GetLinuxInfByNetDevice(netDev);
133 wiphy = get_linux_wiphy_ndev(netdev);
134 if (!wiphy) {
135 HDF_LOGE("%s: wiphy is NULL", __func__);
136 return -1;
137 }
138
139 HDF_LOGE("%s: ifname = %s", __func__, hnetdev->name);
140 if (!netdev) {
141 HDF_LOGE("%s: net_device is NULL", __func__);
142 return -1;
143 }
144
145 cfgdev = ndev_to_cfg(netdev);
146
147 return wl_cfg80211_ops.cancel_remain_on_channel(wiphy, cfgdev, p2p_cookie);
148 }
149
WalProbeReqReport(struct NetDevice * netDev,int32_t report)150 int32_t WalProbeReqReport(struct NetDevice *netDev, int32_t report)
151 {
152 (void)report;
153 HDF_LOGE("%s: ifname = %s, report=%d", __func__, netDev->name, report);
154 return HDF_SUCCESS;
155 }
156
WalAddIf(struct NetDevice * netDev,WifiIfAdd * ifAdd)157 int32_t WalAddIf(struct NetDevice *netDev, WifiIfAdd *ifAdd)
158 {
159 struct wiphy *wiphy = NULL;
160 struct wireless_dev *wdev = NULL;
161 int ret = 0;
162 struct net_device *p2p_netdev = NULL;
163 struct NetDevice *p2p_hnetdev = NULL;
164
165 if (netDev == NULL || ifAdd == NULL) {
166 HDF_LOGE("%s:NULL ptr!", __func__);
167 return -1;
168 }
169
170 HDF_LOGE("%s: ifname = %s, type=%u", __func__, netDev->name, ifAdd->type);
171 netDev = get_real_netdev(netDev);
172 if (g_hdf_infmap[HDF_INF_P2P1].hnetdev != NULL) {
173 HDF_LOGE("%s: ifidx=%d was used, failed add if", __func__,
174 HDF_INF_P2P1);
175 return -1;
176 }
177
178 ret = BDH6InitNetdev(netDev, get_dhd_priv_data_size(), ifAdd->type,
179 HDF_INF_P2P1);
180 if (ret != 0) {
181 HDF_LOGE("%s:BDH6InitNetdev p2p-p2p0-0 failed", __func__);
182 return HDF_FAILURE;
183 }
184
185 wiphy = get_linux_wiphy_hdfdev(netDev);
186 if (wiphy == NULL) {
187 HDF_LOGE("%s:get wlan0 wiphy failed", __func__);
188 return HDF_FAILURE;
189 }
190
191 p2p_hnetdev = get_hdf_netdev(g_hdf_ifidx);
192 p2p_netdev = get_krn_netdev(g_hdf_ifidx);
193
194 wdev = wl_cfg80211_ops.add_virtual_intf(wiphy, p2p_hnetdev->name,
195 NET_NAME_USER, ifAdd->type, NULL);
196 if (wdev == NULL || wdev == ERR_PTR(-ENODEV)) {
197 HDF_LOGE("%s:create wdev for %s %d failed", __func__, p2p_hnetdev->name,
198 ifAdd->type);
199 return HDF_FAILURE;
200 }
201 HDF_LOGE("%s:%s wdev->netdev=%p, %p", __func__, p2p_hnetdev->name,
202 wdev->netdev, p2p_netdev);
203 p2p_hnetdev->ieee80211Ptr = p2p_netdev->ieee80211_ptr;
204
205 // update mac addr to NetDevice object
206 memcpy_s(p2p_hnetdev->macAddr, MAC_ADDR_SIZE, p2p_netdev->dev_addr,
207 p2p_netdev->addr_len);
208 HDF_LOGE("%s: %s mac: %02x:%02x:%02x:%02x:%02x:%02x", __func__,
209 p2p_hnetdev->name, p2p_hnetdev->macAddr[0],
210 p2p_hnetdev->macAddr[1], p2p_hnetdev->macAddr[0x2],
211 p2p_hnetdev->macAddr[0x3], p2p_hnetdev->macAddr[0x4],
212 p2p_hnetdev->macAddr[0x5]);
213
214 return HDF_SUCCESS;
215 }
216
WalRemoveIf(struct NetDevice * netDev,WifiIfRemove * ifRemove)217 int32_t WalRemoveIf(struct NetDevice *netDev, WifiIfRemove *ifRemove)
218 {
219 int i = HDF_INF_WLAN0;
220 struct wiphy *wiphy = NULL;
221 struct wireless_dev *wdev = NULL;
222 struct NetDevice *p2p_hnetdev = NULL;
223 int ret = 0;
224 struct NetDevice *hnetdev = netDev;
225 netDev = get_real_netdev(netDev);
226
227 wiphy = get_linux_wiphy_hdfdev(netDev);
228 if (wiphy == NULL) {
229 HDF_LOGE("%s:get wlan0 wiphy failed", __func__);
230 return HDF_FAILURE;
231 }
232
233 HDF_LOGE("%s: ifname=%s, primary netdev %s, remove ifname=%s", __func__,
234 hnetdev->name, netDev->name, ifRemove->ifName);
235 for (; i < HDF_INF_MAX; i++) {
236 p2p_hnetdev = g_hdf_infmap[i].hnetdev;
237 if (p2p_hnetdev == NULL) {
238 continue;
239 }
240
241 if (strcmp(p2p_hnetdev->name, ifRemove->ifName) == 0) {
242 // check safely
243 if (i == HDF_INF_WLAN0) {
244 HDF_LOGE("%s: don't remove master interface %s", __func__,
245 ifRemove->ifName);
246 continue;
247 }
248 if (i != HDF_INF_P2P1) {
249 HDF_LOGE("%s: remove %s is not p2p interface (%d %d)", __func__,
250 ifRemove->ifName, i, HDF_INF_P2P1);
251 }
252
253 wdev = (struct wireless_dev *)p2p_hnetdev->ieee80211Ptr;
254 ret = (int32_t)wl_cfg80211_ops.change_virtual_intf(
255 wiphy, g_hdf_infmap[i].netdev, NL80211_IFTYPE_STATION, NULL);
256 HDF_LOGE("%s: change %s mode %d --> %d, ret=%d", __func__,
257 g_hdf_infmap[i].netdev->name, wdev->iftype,
258 NL80211_IFTYPE_STATION, ret);
259
260 rtnl_lock();
261 // clear private object
262 DestroyEapolData(p2p_hnetdev);
263 p2p_hnetdev->ieee80211Ptr = NULL;
264 // This func free wdev object and call unregister_netdevice() and
265 // NetDeviceDeInit()
266 ret = wl_cfg80211_ops.del_virtual_intf(wiphy, wdev);
267
268 g_hdf_infmap[i].hnetdev = NULL;
269 g_hdf_infmap[i].netdev = NULL;
270 g_hdf_infmap[i].wdev = NULL;
271 g_hdf_ifidx = HDF_INF_WLAN0;
272 g_event_ifidx = HDF_INF_P2P0;
273 rtnl_unlock();
274 break;
275 }
276 }
277
278 return ret;
279 }
280
WalSetApWpsP2pIe(struct NetDevice * netDev,WifiAppIe * appIe)281 int32_t WalSetApWpsP2pIe(struct NetDevice *netDev, WifiAppIe *appIe)
282 {
283 struct net_device *netdev = NULL;
284 enum wl_management_type type;
285
286 netDev = get_real_netdev(netDev);
287 netdev = GetLinuxInfByNetDevice(netDev);
288 type = appIe->appIeType;
289
290 HDF_LOGE("%s: primary netdev %s, type=%d", __func__, netDev->name, type);
291 if (!netdev) {
292 HDF_LOGE("%s: net_device is NULL", __func__);
293 return -1;
294 }
295
296 if (appIe->ieLen > WLAN_WPS_IE_MAX_SIZE) {
297 return -1;
298 }
299
300 return wl_cfg80211_set_wps_p2p_ie(netdev, appIe->ie, appIe->ieLen, type);
301 }
302
303 void cfg80211_init_wdev(struct wireless_dev *wdev);
304
hdf_start_p2p_device(void)305 int hdf_start_p2p_device(void)
306 {
307 int ret = HDF_SUCCESS;
308 struct wiphy *wiphy = NULL;
309 struct wireless_dev *wdev = NULL;
310 struct net_device *netdev = get_krn_netdev(HDF_INF_WLAN0);
311
312 if (start_p2p_completed == 1) {
313 HDF_LOGE("%s:start p2p completed already", __func__);
314 return 0;
315 }
316
317 // create wdev object for p2p-dev-wlan0 device, refer
318 // nl80211_new_interface()
319 wiphy = get_linux_wiphy_ndev(netdev);
320 if (wiphy == NULL) {
321 HDF_LOGE("%s:get wlan0 wiphy failed", __func__);
322 return HDF_FAILURE;
323 }
324
325 wdev = wl_cfg80211_ops.add_virtual_intf(
326 wiphy, "p2p-dev-wlan0", NET_NAME_USER, NL80211_IFTYPE_P2P_DEVICE, NULL);
327 if (wdev == NULL) {
328 HDF_LOGE("%s:create wdev for p2p-dev-wlan0 %d failed", __func__,
329 NL80211_IFTYPE_P2P_DEVICE);
330 return HDF_FAILURE;
331 }
332 cfg80211_init_wdev(wdev);
333 HDF_LOGE("%s:p2p-dev-wlan0 wdev->netdev=%p", __func__, wdev->netdev);
334
335 g_hdf_infmap[HDF_INF_P2P0].wdev = wdev; // free it for module released !!
336
337 ret = wl_cfg80211_ops.start_p2p_device(wiphy, NULL);
338 HDF_LOGE("call start_p2p_device ret = %d", ret);
339 g_event_ifidx = HDF_INF_P2P0;
340 start_p2p_completed = 1;
341
342 return ret;
343 }
344
WalGetDriverFlag(struct NetDevice * netDev,WifiGetDrvFlags ** params)345 int32_t WalGetDriverFlag(struct NetDevice *netDev, WifiGetDrvFlags **params)
346 {
347 struct wireless_dev *wdev = NULL;
348 WifiGetDrvFlags *getDrvFlag = NULL;
349 int iftype = 0;
350 int ifidx = 0;
351
352 HDF_LOGE("%s: primary netdev %s", __func__, netDev->name);
353 if (netDev == NULL || params == NULL) {
354 HDF_LOGE("%s:NULL ptr!", __func__);
355 return -1;
356 }
357 wdev = (struct wireless_dev *)((netDev)->ieee80211Ptr);
358 getDrvFlag = (WifiGetDrvFlags *)OsalMemCalloc(sizeof(WifiGetDrvFlags));
359 if (wdev) {
360 iftype = wdev->iftype;
361 } else {
362 ifidx = get_scan_ifidx(netDev->name);
363 if (ifidx == HDF_INF_P2P0) {
364 iftype = NL80211_IFTYPE_P2P_DEVICE;
365 }
366 }
367
368 switch (iftype) {
369 case NL80211_IFTYPE_P2P_CLIENT:
370 /* fall-through */
371 case NL80211_IFTYPE_P2P_GO:
372 getDrvFlag->drvFlags = (unsigned int)(HISI_DRIVER_FLAGS_AP);
373 g_event_ifidx = HDF_INF_P2P1;
374 break;
375 case NL80211_IFTYPE_P2P_DEVICE:
376 getDrvFlag->drvFlags =
377 (unsigned int)(HISI_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE |
378 HISI_DRIVER_FLAGS_P2P_CONCURRENT |
379 HISI_DRIVER_FLAGS_P2P_CAPABLE);
380 hdf_start_p2p_device();
381 break;
382 default:
383 getDrvFlag->drvFlags = 0;
384 }
385
386 *params = getDrvFlag;
387
388 HDF_LOGE("%s: %s iftype=%d, drvflag=%lu", __func__, netDev->name, iftype,
389 getDrvFlag->drvFlags);
390 return HDF_SUCCESS;
391 }
392
393 struct HdfMac80211P2POps g_bdh6_p2pOps = {
394 .RemainOnChannel = WalRemainOnChannel,
395 .CancelRemainOnChannel = WalCancelRemainOnChannel,
396 .ProbeReqReport = WalProbeReqReport,
397 .AddIf = WalAddIf,
398 .RemoveIf = WalRemoveIf,
399 .SetApWpsP2pIe = WalSetApWpsP2pIe,
400 .GetDriverFlag = WalGetDriverFlag,
401 };
402