1 /*
2 * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
3 *
4 * HDF is dual licensed: you can use it either under the terms of
5 * the GPL, or the BSD license, at your option.
6 * See the LICENSE file in the root of this repository for complete details.
7 */
8
9 #include <net/cfg80211.h>
10 #include <net/regulatory.h>
11
12
13 #include <typedefs.h>
14 #include <ethernet.h>
15 #include <bcmutils.h>
16
17 #include <securec.h>
18
19 #include "wifi_mac80211_ops.h"
20 #include "hdf_wlan_utils.h"
21 #include "wifi_module.h"
22
23 #include "osal_mem.h"
24 #include "hdf_wifi_event.h"
25 #include "hdf_log.h"
26
27 #include "net_device_adapter.h"
28 #include "hdf_public_ap6275s.h"
29
30 #define HDF_LOG_TAG bcmdhd
31
32 struct net_device *g_save_kernel_net = NULL;
33
34 /*--------------------------------------------------------------------------------------------------*/
35 /* public */
36 /*--------------------------------------------------------------------------------------------------*/
37 #define MAX_NUM_OF_ASSOCIATED_DEV 64
38 #define WLC_GET_ASSOCLIST 159
39
40 #define ETH_MAC_LEN 6
41
42 typedef struct maclist {
43 uint32 count; /**< number of MAC addresses */
44 struct ether_addr ea[1]; /**< variable length array of MAC addresses */
45 } maclist_t;
46
ChangDelSta(struct net_device * dev,const uint8_t * macAddr,uint8_t addrLen)47 int ChangDelSta(struct net_device *dev, const uint8_t *macAddr, uint8_t addrLen)
48 {
49 int ret;
50 struct NetDevice *netDev = GetHdfNetDeviceByLinuxInf(dev);
51 ret = HdfWifiEventDelSta(netDev, macAddr, ETH_MAC_LEN);
52 return ret;
53 }
54
ChangNewSta(struct net_device * dev,const uint8_t * macAddr,uint8_t addrLen,const struct station_info * info)55 int ChangNewSta(struct net_device *dev, const uint8_t *macAddr, uint8_t addrLen,
56 const struct station_info *info)
57 {
58 int ret;
59 struct NetDevice *netDev = NULL;
60 struct StationInfo Info = {0};
61
62 Info.assocReqIes = info->assoc_req_ies;
63 Info.assocReqIesLen = info->assoc_req_ies_len;
64
65 netDev = GetHdfNetDeviceByLinuxInf(dev);
66
67 ret = HdfWifiEventNewSta(netDev, macAddr, addrLen, &Info);
68 return ret;
69 }
70
71
wl_get_all_sta(struct net_device * ndev,uint32_t * num)72 int32_t wl_get_all_sta(struct net_device *ndev, uint32_t *num)
73 {
74 int ret = 0;
75 char mac_buf[MAX_NUM_OF_ASSOCIATED_DEV * sizeof(struct ether_addr) + sizeof(uint)] = {0};
76 struct maclist *assoc_maclist = (struct maclist *)mac_buf;
77 assoc_maclist->count = MAX_NUM_OF_ASSOCIATED_DEV;
78 ret = wldev_ioctl_get(ndev, WLC_GET_ASSOCLIST, assoc_maclist, sizeof(mac_buf));
79 *num = assoc_maclist->count;
80 return 0;
81 }
82
83 #define MAX_NUM_OF_ASSOCLIST 64
84 #define CMD_ASSOC_CLIENTS "ASSOCLIST"
85
wl_get_all_sta_info(struct net_device * ndev,char * mac,uint32_t num)86 int wl_get_all_sta_info(struct net_device *ndev, char* mac, uint32_t num)
87 {
88 int bytes_written = 0;
89 int error = 0;
90 int len = 0;
91 int i;
92 char mac_buf[MAX_NUM_OF_ASSOCLIST *sizeof(struct ether_addr) + sizeof(uint)] = {0};
93 struct maclist *assoc_maclist = (struct maclist *)mac_buf;
94 assoc_maclist->count = (MAX_NUM_OF_ASSOCLIST);
95 error = wldev_ioctl_get(ndev, WLC_GET_ASSOCLIST, assoc_maclist, sizeof(mac_buf));
96 if (error) {
97 return -1;
98 }
99 assoc_maclist->count = assoc_maclist->count;
100 bytes_written = snprintf_s(mac, num, num, "%s listcount: %d Stations:",
101 CMD_ASSOC_CLIENTS, assoc_maclist->count);
102 for (i = 0; i < assoc_maclist->count; i++) {
103 len = snprintf_s(mac + bytes_written, num - bytes_written, num - bytes_written, " " MACDBG,
104 MAC2STRDBG(assoc_maclist->ea[i].octet));
105 /* A return value of '(total_len - bytes_written)' or more means that the
106 * output was truncated
107 */
108 if ((len > 0) && (len < (num - bytes_written))) {
109 bytes_written += len;
110 } else {
111 bytes_written = -1;
112 break;
113 }
114 }
115
116 return bytes_written;
117 }
118
119
120 #if 1
121
122 #define RATE_OFFSET 2
123 #define CAP_OFFSET 2
124 // Copy from nl80211_check_ap_rate_selectors() in nl80211.c
bdh6_nl80211_check_ap_rate_selectors(struct cfg80211_ap_settings * params,const u8 * rates)125 static void bdh6_nl80211_check_ap_rate_selectors(struct cfg80211_ap_settings *params, const u8 *rates)
126 {
127 int i;
128
129 if (!rates)
130 return;
131
132 for (i = 0; i < rates[1]; i++) {
133 if (rates[RATE_OFFSET + i] == BSS_MEMBERSHIP_SELECTOR_HT_PHY)
134 params->ht_required = true;
135 if (rates[RATE_OFFSET + i] == BSS_MEMBERSHIP_SELECTOR_VHT_PHY)
136 params->vht_required = true;
137 }
138 }
139
140
141 // Copy from nl80211_calculate_ap_params() in nl80211.c
bdh6_nl80211_calculate_ap_params(struct cfg80211_ap_settings * params)142 static void bdh6_nl80211_calculate_ap_params(struct cfg80211_ap_settings *params)
143 {
144 const struct cfg80211_beacon_data *bcn = ¶ms->beacon;
145 size_t ies_len = bcn->tail_len;
146 const u8 *ies = bcn->tail;
147 const u8 *rates;
148 const u8 *cap;
149
150 rates = cfg80211_find_ie(WLAN_EID_SUPP_RATES, ies, ies_len);
151 HDF_LOGE("lijg: find beacon tail WLAN_EID_SUPP_RATES=%p", rates);
152 bdh6_nl80211_check_ap_rate_selectors(params, rates);
153
154 rates = cfg80211_find_ie(WLAN_EID_EXT_SUPP_RATES, ies, ies_len);
155 HDF_LOGE("lijg: find beacon tail WLAN_EID_EXT_SUPP_RATES=%p", rates);
156 bdh6_nl80211_check_ap_rate_selectors(params, rates);
157
158 cap = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, ies, ies_len);
159 HDF_LOGE("lijg: find beacon tail WLAN_EID_HT_CAPABILITY=%p", cap);
160 if (cap && cap[1] >= sizeof(*params->ht_cap))
161 params->ht_cap = (void *)(cap + CAP_OFFSET);
162 cap = cfg80211_find_ie(WLAN_EID_VHT_CAPABILITY, ies, ies_len);
163 HDF_LOGE("lijg: find beacon tail WLAN_EID_VHT_CAPABILITY=%p", cap);
164 if (cap && cap[1] >= sizeof(*params->vht_cap))
165 params->vht_cap = (void *)(cap + CAP_OFFSET);
166 }
167
168 #endif
169
170
171 static struct ieee80211_channel g_ap_ieee80211_channel;
172
173 static struct cfg80211_ap_settings g_ap_setting_info;
174 static u8 g_ap_ssid[IEEE80211_MAX_SSID_LEN];
175 static int start_ap_flag = 0;
176
SetupWireLessDev(struct net_device * netDev,struct WlanAPConf * apSettings)177 static int32_t SetupWireLessDev(struct net_device *netDev, struct WlanAPConf *apSettings)
178 {
179 struct wireless_dev *wdev = NULL;
180 struct ieee80211_channel *chan = NULL;
181
182 wdev = netDev->ieee80211_ptr;
183 if (wdev == NULL) {
184 HDF_LOGE("%s: wdev is null", __func__);
185 return -1;
186 }
187
188 wdev->iftype = NL80211_IFTYPE_AP;
189 wdev->preset_chandef.width = (enum nl80211_channel_type)apSettings->width;
190 wdev->preset_chandef.center_freq1 = apSettings->centerFreq1;
191 wdev->preset_chandef.center_freq2 = apSettings->centerFreq2;
192
193 chan = ieee80211_get_channel(wdev->wiphy, apSettings->centerFreq1);
194 if (chan) {
195 wdev->preset_chandef.chan = chan;
196 HDF_LOGE("%s: use valid channel %u", __func__, chan->center_freq);
197 } else if (wdev->preset_chandef.chan == NULL) {
198 wdev->preset_chandef.chan = &g_ap_ieee80211_channel;
199 wdev->preset_chandef.chan->hw_value = apSettings->channel;
200 wdev->preset_chandef.chan->band = apSettings->band; // IEEE80211_BAND_2GHZ;
201 wdev->preset_chandef.chan->center_freq = apSettings->centerFreq1;
202 HDF_LOGE("%s: fill new channel %u", __func__, wdev->preset_chandef.chan->center_freq);
203 }
204
205 g_ap_setting_info.chandef = wdev->preset_chandef;
206
207 return HDF_SUCCESS;
208 }
209
210 /*--------------------------------------------------------------------------------------------------*/
211 /* HdfMac80211APOps */
212 /*--------------------------------------------------------------------------------------------------*/
WalConfigAp(NetDevice * netDev,struct WlanAPConf * apConf)213 int32_t WalConfigAp(NetDevice *netDev, struct WlanAPConf *apConf)
214 {
215 int32_t ret = 0;
216
217 struct net_device *netdev = NULL;
218 struct wiphy *wiphy = NULL;
219 netdev = GetLinuxInfByNetDevice(netDev);
220 if (!netdev) {
221 HDF_LOGE("%s: net_device is NULL", __func__);
222 return -1;
223 }
224
225 wiphy = get_linux_wiphy_ndev(netdev);
226 if (!wiphy) {
227 HDF_LOGE("%s: wiphy is NULL", __func__);
228 return -1;
229 }
230
231 memset_s(&g_ap_setting_info, sizeof(g_ap_setting_info), 0x00, sizeof(g_ap_setting_info));
232 ret = SetupWireLessDev(netdev, apConf);
233 if (ret != 0) {
234 HDF_LOGE("%s: set up wireless device failed!", __func__);
235 return HDF_FAILURE;
236 }
237
238 HDF_LOGE("%s: before iftype = %d!", __func__, netdev->ieee80211_ptr->iftype);
239 netdev->ieee80211_ptr->iftype = NL80211_IFTYPE_AP;
240 HDF_LOGE("%s: after iftype = %d!", __func__, netdev->ieee80211_ptr->iftype);
241
242 g_ap_setting_info.ssid_len = apConf->ssidConf.ssidLen;
243 memcpy_s(&g_ap_ssid[0], IEEE80211_MAX_SSID_LEN, &apConf->ssidConf.ssid[0], apConf->ssidConf.ssidLen);
244 g_ap_setting_info.ssid = &g_ap_ssid[0];
245
246 ret = (int32_t)wl_cfg80211_ops.change_virtual_intf(wiphy, netdev,
247 (enum nl80211_iftype)netdev->ieee80211_ptr->iftype, NULL);
248 if (ret < 0) {
249 HDF_LOGE("%s: set mode failed!", __func__);
250 }
251
252 return HDF_SUCCESS;
253 }
254
WalSetCountryCode(NetDevice * netDev,const char * code,uint32_t len)255 int32_t WalSetCountryCode(NetDevice *netDev, const char *code, uint32_t len)
256 {
257 int32_t ret = 0;
258 struct net_device *netdev = NULL;
259 netdev = GetLinuxInfByNetDevice(netDev);
260 if (!netdev) {
261 HDF_LOGE("%s: net_device is NULL", __func__);
262 return -1;
263 }
264
265 HDF_LOGE("%s: start...", __func__);
266 ret = (int32_t)wl_cfg80211_set_country_code(netdev, (char*)code, false, true, len);
267 if (ret < 0) {
268 HDF_LOGE("%s: set_country_code failed!", __func__);
269 }
270
271 return ret;
272 }
273
WalStopAp(NetDevice * netDev)274 int32_t WalStopAp(NetDevice *netDev)
275 {
276 int32_t ret = 0;
277 struct net_device *netdev = NULL;
278 struct wiphy *wiphy = NULL;
279 netdev = GetLinuxInfByNetDevice(netDev);
280 if (!netdev) {
281 HDF_LOGE("%s: net_device is NULL", __func__);
282 return -1;
283 }
284
285 wiphy = get_linux_wiphy_ndev(netdev);
286 if (!wiphy) {
287 HDF_LOGE("%s: wiphy is NULL", __func__);
288 return -1;
289 }
290
291 HDF_LOGE("%s: start...", __func__);
292 ret = (int32_t)wl_cfg80211_ops.stop_ap(wiphy, netdev);
293 return ret;
294 }
295
WalStartAp(NetDevice * netDev)296 int32_t WalStartAp(NetDevice *netDev)
297 {
298 int32_t ret = 0;
299
300 struct net_device *netdev = NULL;
301 struct wiphy *wiphy = NULL;
302 struct wireless_dev *wdev = NULL;
303
304 if (start_ap_flag) {
305 WalStopAp(netDev);
306 HDF_LOGE("do not start up, because start_ap_flag=%d", start_ap_flag);
307 }
308
309 netdev = GetLinuxInfByNetDevice(netDev);
310 if (!netdev) {
311 HDF_LOGE("%s: net_device is NULL", __func__);
312 return -1;
313 }
314
315 wiphy = get_linux_wiphy_ndev(netdev);
316 if (!wiphy) {
317 HDF_LOGE("%s: wiphy is NULL", __func__);
318 return -1;
319 }
320 wdev = netdev->ieee80211_ptr;
321 ret = (int32_t)wl_cfg80211_ops.start_ap(wiphy, netdev, &g_ap_setting_info);
322 if (ret < 0) {
323 HDF_LOGE("%s: start_ap failed!", __func__);
324 } else {
325 wdev->preset_chandef = g_ap_setting_info.chandef;
326 wdev->beacon_interval = g_ap_setting_info.beacon_interval;
327 wdev->chandef = g_ap_setting_info.chandef;
328 wdev->ssid_len = g_ap_setting_info.ssid_len;
329 memcpy_s(wdev->ssid, IEEE80211_MAX_SSID_LEN, g_ap_setting_info.ssid, wdev->ssid_len);
330 start_ap_flag = 1;
331 }
332 return ret;
333 }
334
335
WalInitBeacon(struct WlanBeaconConf * param)336 static void WalInitBeacon(struct WlanBeaconConf *param)
337 {
338 if (g_ap_setting_info.beacon.head != NULL) {
339 OsalMemFree((uint8_t *)g_ap_setting_info.beacon.head);
340 g_ap_setting_info.beacon.head = NULL;
341 }
342 if (g_ap_setting_info.beacon.tail != NULL) {
343 OsalMemFree((uint8_t *)g_ap_setting_info.beacon.tail);
344 g_ap_setting_info.beacon.tail = NULL;
345 }
346
347 if (param->headIEs && param->headIEsLength > 0) {
348 g_ap_setting_info.beacon.head = OsalMemCalloc(param->headIEsLength);
349 memcpy_s((uint8_t *)g_ap_setting_info.beacon.head, param->headIEsLength, param->headIEs, param->headIEsLength);
350 g_ap_setting_info.beacon.head_len = param->headIEsLength;
351 }
352
353 if (param->tailIEs && param->tailIEsLength > 0) {
354 g_ap_setting_info.beacon.tail = OsalMemCalloc(param->tailIEsLength);
355 memcpy_s((uint8_t *)g_ap_setting_info.beacon.tail, param->tailIEsLength, param->tailIEs, param->tailIEsLength);
356 g_ap_setting_info.beacon.tail_len = param->tailIEsLength;
357 }
358
359 g_ap_setting_info.dtim_period = param->DTIMPeriod;
360 g_ap_setting_info.hidden_ssid = param->hiddenSSID;
361 g_ap_setting_info.beacon_interval = param->interval;
362 g_ap_setting_info.beacon.beacon_ies = NULL;
363 g_ap_setting_info.beacon.proberesp_ies = NULL;
364 g_ap_setting_info.beacon.assocresp_ies = NULL;
365 g_ap_setting_info.beacon.probe_resp = NULL;
366
367 g_ap_setting_info.beacon.beacon_ies_len = 0X00;
368 g_ap_setting_info.beacon.proberesp_ies_len = 0X00;
369 g_ap_setting_info.beacon.assocresp_ies_len = 0X00;
370 g_ap_setting_info.beacon.probe_resp_len = 0X00;
371 }
372
WalChangeBeacon(NetDevice * netDev,struct WlanBeaconConf * param)373 int32_t WalChangeBeacon(NetDevice *netDev, struct WlanBeaconConf *param)
374 {
375 int32_t ret = 0;
376 struct cfg80211_beacon_data info;
377 struct net_device *netdev = NULL;
378 struct wiphy *wiphy = NULL;
379 netdev = GetLinuxInfByNetDevice(netDev);
380 if (!netdev) {
381 HDF_LOGE("%s: net_device is NULL", __func__);
382 return -1;
383 }
384
385 wiphy = get_linux_wiphy_ndev(netdev);
386 if (!wiphy) {
387 HDF_LOGE("%s: wiphy is NULL", __func__);
388 return -1;
389 }
390 memset_s(&info, sizeof(info), 0x00, sizeof(info));
391
392 WalInitBeacon(param);
393 info.head = param->headIEs;
394 info.head_len = (size_t)param->headIEsLength;
395 info.tail = param->tailIEs;
396 info.tail_len = (size_t)param->tailIEsLength;
397
398 info.beacon_ies = NULL;
399 info.proberesp_ies = NULL;
400 info.assocresp_ies = NULL;
401 info.probe_resp = NULL;
402
403 info.beacon_ies_len = 0X00;
404 info.proberesp_ies_len = 0X00;
405 info.assocresp_ies_len = 0X00;
406 info.probe_resp_len = 0X00;
407
408 bdh6_nl80211_calculate_ap_params(&g_ap_setting_info);
409 ret = WalStartAp(netDev);
410 HDF_LOGE("call start_ap ret=%d", ret);
411
412 ret = (int32_t)wl_cfg80211_ops.change_beacon(wiphy, netdev, &info);
413 if (ret < 0) {
414 HDF_LOGE("%s: change_beacon failed!", __func__);
415 }
416
417 return HDF_SUCCESS;
418 }
419
WalDelStation(NetDevice * netDev,const uint8_t * macAddr)420 int32_t WalDelStation(NetDevice *netDev, const uint8_t *macAddr)
421 {
422 int32_t ret = 0;
423 struct net_device *netdev = NULL;
424 struct wiphy *wiphy = NULL;
425 struct station_del_parameters del_param = {macAddr, 10, 0};
426 netdev = GetLinuxInfByNetDevice(netDev);
427 if (!netdev) {
428 HDF_LOGE("%s: net_device is NULL", __func__);
429 return -1;
430 }
431
432 wiphy = get_linux_wiphy_ndev(netdev);
433 if (!wiphy) {
434 HDF_LOGE("%s: wiphy is NULL", __func__);
435 return -1;
436 }
437
438 (void)macAddr;
439 HDF_LOGE("%s: start...", __func__);
440
441 ret = (int32_t)wl_cfg80211_ops.del_station(wiphy, netdev, &del_param);
442 if (ret < 0) {
443 HDF_LOGE("%s: del_station failed!", __func__);
444 }
445
446 return ret;
447 }
448
WalGetAssociatedStasCount(NetDevice * netDev,uint32_t * num)449 int32_t WalGetAssociatedStasCount(NetDevice *netDev, uint32_t *num)
450 {
451 int32_t ret = 0;
452 struct net_device *netdev = NULL;
453 netdev = GetLinuxInfByNetDevice(netDev);
454 if (!netdev) {
455 HDF_LOGE("%s: net_device is NULL", __func__);
456 return -1;
457 }
458
459 HDF_LOGE("%s: start...", __func__);
460
461 ret = (int32_t)wl_get_all_sta(netdev, num);
462 if (ret < 0) {
463 HDF_LOGE("%s: wl_get_all_sta failed!", __func__);
464 }
465
466 return ret;
467 }
468
WalGetAssociatedStasInfo(NetDevice * netDev,WifiStaInfo * staInfo,uint32_t num)469 int32_t WalGetAssociatedStasInfo(NetDevice *netDev, WifiStaInfo *staInfo, uint32_t num)
470 {
471 int32_t ret = 0;
472 struct net_device *netdev = NULL;
473 netdev = GetLinuxInfByNetDevice(netDev);
474 if (!netdev) {
475 HDF_LOGE("%s: net_device is NULL", __func__);
476 return -1;
477 }
478
479 HDF_LOGE("%s: start...", __func__);
480 ret = (int32_t)wl_get_all_sta_info(netdev, staInfo->mac, num);
481 if (ret < 0) {
482 HDF_LOGE("%s: wl_get_all_sta_info failed!", __func__);
483 }
484
485 return ret;
486 }
487 /*--------------------------------------------------------------------------------------------------*/
488 /*--------------------------------------------------------------------------------------------------*/
489 /*--------------------------------------------------------------------------------------------------*/
490
491 struct HdfMac80211APOps g_bdh6_apOps = {
492 .ConfigAp = WalConfigAp,
493 .StartAp = WalStartAp,
494 .StopAp = WalStopAp,
495 .ConfigBeacon = WalChangeBeacon,
496 .DelStation = WalDelStation,
497 .SetCountryCode = WalSetCountryCode,
498 .GetAssociatedStasCount = WalGetAssociatedStasCount,
499 .GetAssociatedStasInfo = WalGetAssociatedStasInfo
500 };
501