1 /*
2 * hdf_mac80211_ap.c
3 *
4 * hdf driver
5 *
6 * Copyright (c) 2022 Shenzhen Kaihong Digital Industry Development Co., Ltd.
7 *
8 * This software is licensed under the terms of the GNU General Public
9 * License version 2, as published by the Free Software Foundation, and
10 * may be copied, distributed, and modified under those terms.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 */
18 #include <net/cfg80211.h>
19 #include <net/regulatory.h>
20 #include <typedefs.h>
21 #include <ethernet.h>
22 #include <bcmutils.h>
23 #include <securec.h>
24
25 #include "wifi_mac80211_ops.h"
26 #include "hdf_wlan_utils.h"
27 #include "wifi_module.h"
28
29 #include "osal_mem.h"
30 #include "hdf_wifi_event.h"
31 #include "hdf_log.h"
32
33 #include "net_device_adapter.h"
34 #include "hdf_public_ap6256.h"
35
36 #define HDF_LOG_TAG bcmdhd
37
38 struct net_device *g_save_kernel_net = NULL;
39 /*--------------------------------------------------------------------------------------------------*/
40 /* public */
41 /*--------------------------------------------------------------------------------------------------*/
42 #define MAX_NUM_OF_ASSOCIATED_DEV 64
43 #define WLC_GET_ASSOCLIST 159
44 #define ETH_MAC_LEN 6
45
46 struct cfg80211_ap_settings g_ap_setting_info;
47 typedef struct maclist {
48 uint32 count; /**< number of MAC addresses */
49 struct ether_addr ea[1]; /**< variable length array of MAC addresses */
50 } maclist_t;
51
ChangDelSta(struct net_device * dev,const uint8_t * macAddr,uint8_t addrLen)52 int ChangDelSta(struct net_device *dev, const uint8_t *macAddr, uint8_t addrLen)
53 {
54 int ret;
55 struct NetDevice *netDev = GetHdfNetDeviceByLinuxInf(dev);
56 ret = HdfWifiEventDelSta(netDev, macAddr, ETH_MAC_LEN);
57 return ret;
58 }
59
ChangNewSta(struct net_device * dev,const uint8_t * macAddr,uint8_t addrLen,const struct station_info * info)60 int ChangNewSta(struct net_device *dev, const uint8_t *macAddr, uint8_t addrLen,
61 const struct station_info *info)
62 {
63 int ret;
64 struct NetDevice *netDev = NULL;
65 struct StationInfo Info = {0};
66
67 Info.assocReqIes = info->assoc_req_ies;
68 Info.assocReqIesLen = info->assoc_req_ies_len;
69 netDev = GetHdfNetDeviceByLinuxInf(dev);
70 ret = HdfWifiEventNewSta(netDev, macAddr, addrLen, &Info);
71 return ret;
72 }
73
wl_get_all_sta(struct net_device * ndev,uint32_t * num)74 int32_t wl_get_all_sta(struct net_device *ndev, uint32_t *num)
75 {
76 int ret = 0;
77 char mac_buf[MAX_NUM_OF_ASSOCIATED_DEV *
78 sizeof(struct ether_addr) + sizeof(uint)] = {0};
79 struct maclist *assoc_maclist = (struct maclist *)mac_buf;
80 assoc_maclist->count = MAX_NUM_OF_ASSOCIATED_DEV;
81 ret = wldev_ioctl_get(ndev, WLC_GET_ASSOCLIST,
82 assoc_maclist, sizeof(mac_buf));
83 *num = assoc_maclist->count;
84 return 0;
85 }
86 #define MAX_NUM_OF_ASSOCLIST 64
87
88 #define RATE_OFFSET 2
89 #define CAP_OFFSET 3
90
bdh6_nl80211_check_ap_rate_selectors(struct cfg80211_ap_settings * params,const u8 * rates)91 static void bdh6_nl80211_check_ap_rate_selectors(struct cfg80211_ap_settings *params,
92 const u8 *rates)
93 {
94 int i;
95 if (!rates)
96 return;
97
98 for (i = 0; i < rates[1]; i++) {
99 if (rates[RATE_OFFSET + i] == BSS_MEMBERSHIP_SELECTOR_HT_PHY)
100 params->ht_required = true;
101 if (rates[RATE_OFFSET + i] == BSS_MEMBERSHIP_SELECTOR_VHT_PHY)
102 params->vht_required = true;
103 #if (LINUX_VERSION_CODE > KERNEL_VERSION(5, 10, 0))
104 if (rates[RATE_OFFSET + i] == BSS_MEMBERSHIP_SELECTOR_HE_PHY)
105 params->he_required = true;
106 #endif
107 }
108 }
109
bdh6_nl80211_calculate_ap_params(struct cfg80211_ap_settings * params)110 void bdh6_nl80211_calculate_ap_params(struct cfg80211_ap_settings *params)
111 {
112 const struct cfg80211_beacon_data *bcn = ¶ms->beacon;
113 size_t ies_len = bcn->tail_len;
114 const u8 *ies = bcn->tail;
115 const u8 *rates;
116 const u8 *cap;
117
118 rates = cfg80211_find_ie(WLAN_EID_SUPP_RATES, ies, ies_len);
119 HDF_LOGE("lijg: find beacon tail WLAN_EID_SUPP_RATES=%p", rates);
120 bdh6_nl80211_check_ap_rate_selectors(params, rates);
121
122 rates = cfg80211_find_ie(WLAN_EID_EXT_SUPP_RATES, ies, ies_len);
123 HDF_LOGE("lijg: find beacon tail WLAN_EID_EXT_SUPP_RATES=%p", rates);
124 bdh6_nl80211_check_ap_rate_selectors(params, rates);
125
126 cap = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, ies, ies_len);
127 HDF_LOGE("lijg: find beacon tail WLAN_EID_HT_CAPABILITY=%p", cap);
128 if (cap && cap[1] >= sizeof(*params->ht_cap))
129 params->ht_cap = (void *)(cap + RATE_OFFSET);
130 cap = cfg80211_find_ie(WLAN_EID_VHT_CAPABILITY, ies, ies_len);
131 HDF_LOGE("lijg: find beacon tail WLAN_EID_VHT_CAPABILITY=%p", cap);
132 if (cap && cap[1] >= sizeof(*params->vht_cap))
133 params->vht_cap = (void *)(cap + RATE_OFFSET);
134 #if (LINUX_VERSION_CODE > KERNEL_VERSION(5, 10, 0))
135 cap = cfg80211_find_ext_ie(WLAN_EID_EXT_HE_CAPABILITY, ies, ies_len);
136 HDF_LOGE("lijg: find beacon tail WLAN_EID_EXT_HE_CAPABILITY=%p", cap);
137 if (cap && cap[1] >= sizeof(*params->he_cap) + 1)
138 params->he_cap = (void *)(cap + CAP_OFFSET);
139 cap = cfg80211_find_ext_ie(WLAN_EID_EXT_HE_OPERATION, ies, ies_len);
140 HDF_LOGE("lijg: find beacon tail WLAN_EID_EXT_HE_OPERATION=%p", cap);
141 if (cap && cap[1] >= sizeof(*params->he_oper) + 1)
142 params->he_oper = (void *)(cap + CAP_OFFSET);
143 #endif
144 }
145
146
147 static struct ieee80211_channel g_ap_ieee80211_channel;
148 static u8 g_ap_ssid[IEEE80211_MAX_SSID_LEN];
149 static int start_ap_flag = 0;
150
SetupWireLessDev(struct net_device * netDev,struct WlanAPConf * apSettings)151 static int32_t SetupWireLessDev(struct net_device *netDev, struct WlanAPConf *apSettings)
152 {
153 struct wireless_dev *wdev = NULL;
154 struct ieee80211_channel *chan = NULL;
155
156 wdev = netDev->ieee80211_ptr;
157 if (wdev == NULL) {
158 HDF_LOGE("%s: wdev is null", __func__);
159 return -1;
160 }
161 HDF_LOGE("%s:%p, chan=%p, channel=%u, centfreq1=%u, centfreq2=%u, band=%u, width=%u", __func__,
162 wdev, wdev->preset_chandef.chan,
163 apSettings->channel, apSettings->centerFreq1, apSettings->centerFreq2, apSettings->band, apSettings->width);
164
165 wdev->iftype = NL80211_IFTYPE_AP;
166 wdev->preset_chandef.width = (enum nl80211_channel_type)apSettings->width;
167 wdev->preset_chandef.center_freq1 = apSettings->centerFreq1;
168 wdev->preset_chandef.center_freq2 = apSettings->centerFreq2;
169
170 chan = ieee80211_get_channel(wdev->wiphy, apSettings->centerFreq1);
171 if (chan) {
172 wdev->preset_chandef.chan = chan;
173 HDF_LOGE("%s: use valid channel %u", __func__, chan->center_freq);
174 } else if (wdev->preset_chandef.chan == NULL) {
175 wdev->preset_chandef.chan = &g_ap_ieee80211_channel;
176 wdev->preset_chandef.chan->hw_value = apSettings->channel;
177 wdev->preset_chandef.chan->band = apSettings->band; // IEEE80211_BAND_2GHZ;
178 wdev->preset_chandef.chan->center_freq = apSettings->centerFreq1;
179 HDF_LOGE("%s: fill new channel %u", __func__, wdev->preset_chandef.chan->center_freq);
180 }
181
182 g_ap_setting_info.chandef = wdev->preset_chandef;
183
184 return HDF_SUCCESS;
185 }
186
187 /*--------------------------------------------------------------------------------------------------*/
188 /* HdfMac80211APOps */
189 /*--------------------------------------------------------------------------------------------------*/
WalConfigAp(NetDevice * hnetDev,struct WlanAPConf * apConf)190 int32_t WalConfigAp(NetDevice *hnetDev, struct WlanAPConf *apConf)
191 {
192 int32_t ret = 0;
193 struct net_device *netdev = NULL;
194 struct NetDevice *netDev = NULL;
195 struct wiphy *wiphy = NULL;
196 netDev = get_real_netdev(hnetDev);
197 netdev = GetLinuxInfByNetDevice(netDev);
198 if (!netdev) {
199 HDF_LOGE("%s: net_device is NULL", __func__);
200 return -1;
201 }
202
203 wiphy = get_linux_wiphy_ndev(netdev);
204 if (!wiphy) {
205 HDF_LOGE("%s: wiphy is NULL", __func__);
206 return -1;
207 }
208
209 memset_s(&g_ap_setting_info, sizeof(g_ap_setting_info), 0, sizeof(g_ap_setting_info));
210 ret = SetupWireLessDev(netdev, apConf);
211 if (ret != 0) {
212 HDF_LOGE("%s: set up wireless device failed!", __func__);
213 return HDF_FAILURE;
214 }
215
216 HDF_LOGE("%s: before iftype = %d!", __func__, netdev->ieee80211_ptr->iftype);
217 netdev->ieee80211_ptr->iftype = NL80211_IFTYPE_AP;
218 HDF_LOGE("%s: after iftype = %d!", __func__, netdev->ieee80211_ptr->iftype);
219
220 g_ap_setting_info.ssid_len = apConf->ssidConf.ssidLen;
221 memcpy_s(&g_ap_ssid[0], IEEE80211_MAX_SSID_LEN, &apConf->ssidConf.ssid[0], apConf->ssidConf.ssidLen);
222 g_ap_setting_info.ssid = &g_ap_ssid[0];
223 ret = (int32_t)wl_cfg80211_ops.change_virtual_intf(wiphy, netdev,
224 (enum nl80211_iftype)netdev->ieee80211_ptr->iftype, NULL);
225 if (ret < 0) {
226 HDF_LOGE("%s: set mode failed!", __func__);
227 }
228
229 return HDF_SUCCESS;
230 }
231
WalSetCountryCode(NetDevice * hnetDev,const char * code,uint32_t len)232 int32_t WalSetCountryCode(NetDevice *hnetDev, const char *code, uint32_t len)
233 {
234 int32_t ret = 0;
235 struct net_device *netdev = NULL;
236 struct NetDevice *netDev = NULL;
237 netDev = get_real_netdev(hnetDev);
238 netdev = GetLinuxInfByNetDevice(netDev);
239 if (!netdev) {
240 HDF_LOGE("%s: net_device is NULL", __func__);
241 return -1;
242 }
243
244 ret = (int32_t)wl_cfg80211_set_country_code(netdev, (char*)code, false, true, len);
245 if (ret < 0) {
246 HDF_LOGE("%s: set_country_code failed!", __func__);
247 }
248 return ret;
249 }
250
WalStopAp(NetDevice * hnetDev)251 int32_t WalStopAp(NetDevice *hnetDev)
252 {
253 int32_t ret = 0;
254 struct net_device *netdev = NULL;
255 struct NetDevice *netDev = NULL;
256 struct wiphy *wiphy = NULL;
257 netDev = get_real_netdev(hnetDev);
258 netdev = GetLinuxInfByNetDevice(netDev);
259 if (!netdev) {
260 HDF_LOGE("%s: net_device is NULL", __func__);
261 return -1;
262 }
263
264 wiphy = get_linux_wiphy_ndev(netdev);
265 if (!wiphy) {
266 HDF_LOGE("%s: wiphy is NULL", __func__);
267 return -1;
268 }
269
270 HDF_LOGE("%s: start...", __func__);
271 ret = (int32_t)wl_cfg80211_ops.stop_ap(wiphy, netdev);
272 return ret;
273 }
274
WalStartAp(NetDevice * hnetDev)275 int32_t WalStartAp(NetDevice *hnetDev)
276 {
277 int32_t ret = 0;
278 struct net_device *netdev = NULL;
279 struct wiphy *wiphy = NULL;
280 struct wireless_dev *wdev = NULL;
281 struct NetDevice *netDev = NULL;
282 netDev = get_real_netdev(hnetDev);
283
284 if (start_ap_flag) {
285 WalStopAp(netDev);
286 HDF_LOGE("do not start up, because start_ap_flag=%d", start_ap_flag);
287 }
288
289 netdev = GetLinuxInfByNetDevice(netDev);
290 if (!netdev) {
291 HDF_LOGE("%s: net_device is NULL", __func__);
292 return -1;
293 }
294
295 wiphy = get_linux_wiphy_ndev(netdev);
296 if (!wiphy) {
297 HDF_LOGE("%s: wiphy is NULL", __func__);
298 return -1;
299 }
300 wdev = netdev->ieee80211_ptr;
301 HDF_LOGE("%s: start...", __func__);
302 ret = (int32_t)wl_cfg80211_ops.start_ap(wiphy, netdev, &g_ap_setting_info);
303 if (ret < 0) {
304 HDF_LOGE("%s: start_ap failed!", __func__);
305 } else {
306 wdev->preset_chandef = g_ap_setting_info.chandef;
307 wdev->beacon_interval = g_ap_setting_info.beacon_interval;
308 wdev->chandef = g_ap_setting_info.chandef;
309 wdev->ssid_len = g_ap_setting_info.ssid_len;
310 memcpy_s(wdev->ssid, wdev->ssid_len, g_ap_setting_info.ssid, wdev->ssid_len);
311 start_ap_flag = 1;
312 }
313 return ret;
314 }
315
WalDelStation(NetDevice * hnetDev,const uint8_t * macAddr)316 int32_t WalDelStation(NetDevice *hnetDev, const uint8_t *macAddr)
317 {
318 int32_t ret = 0;
319 struct net_device *netdev = NULL;
320 struct wiphy *wiphy = NULL;
321 struct NetDevice *netDev = NULL;
322 struct station_del_parameters del_param = {macAddr, 10, 0};
323 netDev = get_real_netdev(hnetDev);
324 netdev = GetLinuxInfByNetDevice(netDev);
325 if (!netdev) {
326 HDF_LOGE("%s: net_device is NULL", __func__);
327 return -1;
328 }
329
330 wiphy = get_linux_wiphy_ndev(netdev);
331 if (!wiphy) {
332 HDF_LOGE("%s: wiphy is NULL", __func__);
333 return -1;
334 }
335
336 (void)macAddr;
337 HDF_LOGE("%s: start...", __func__);
338
339 ret = (int32_t)wl_cfg80211_ops.del_station(wiphy, netdev, &del_param);
340 if (ret < 0) {
341 HDF_LOGE("%s: del_station failed!", __func__);
342 }
343 return ret;
344 }
345
WalGetAssociatedStasCount(NetDevice * hnetDev,uint32_t * num)346 int32_t WalGetAssociatedStasCount(NetDevice *hnetDev, uint32_t *num)
347 {
348 int32_t ret = 0;
349 struct net_device *netdev = NULL;
350 struct NetDevice *netDev = NULL;
351 netDev = get_real_netdev(hnetDev);
352 netdev = GetLinuxInfByNetDevice(netDev);
353 if (!netdev) {
354 HDF_LOGE("%s: net_device is NULL", __func__);
355 return -1;
356 }
357
358 ret = (int32_t)wl_get_all_sta(netdev, num);
359 if (ret < 0) {
360 HDF_LOGE("%s: wl_get_all_sta failed!", __func__);
361 }
362 return ret;
363 }
364
WalGetAssociatedStasInfo(NetDevice * hnetDev,WifiStaInfo * staInfo,uint32_t num)365 int32_t WalGetAssociatedStasInfo(NetDevice *hnetDev, WifiStaInfo *staInfo, uint32_t num)
366 {
367 struct net_device *netdev = NULL;
368 struct NetDevice *netDev = NULL;
369 int error = 0, i = 0;
370 netDev = get_real_netdev(hnetDev);
371 netdev = GetLinuxInfByNetDevice(netDev);
372 if (!netdev) {
373 HDF_LOGE("%s: net_device is NULL", __func__);
374 return -1;
375 }
376 HDF_LOGE("%s: start..., num=%u", __func__, num);
377 if (staInfo == NULL || num == 0) {
378 HDF_LOGE("%s: invalid parameter staInfo=%p, num=%u", __func__);
379 return -1;
380 }
381
382 char mac_buf[MAX_NUM_OF_ASSOCLIST *sizeof(struct ether_addr) + sizeof(uint)] = {0};
383 struct maclist *assoc_maclist = (struct maclist *)mac_buf;
384 assoc_maclist->count = (MAX_NUM_OF_ASSOCLIST);
385
386 error = wldev_ioctl_get(netdev, WLC_GET_ASSOCLIST, assoc_maclist, sizeof(mac_buf));
387 if (error) {
388 HDF_LOGE("%s: WLC_GET_ASSOCLIST ret=%d", __func__, error);
389 return -1;
390 }
391
392 if (num > assoc_maclist->count) {
393 HDF_LOGE("%s: num=%u is larger than assoc_num=%u", __func__, num, assoc_maclist->count);
394 num = assoc_maclist->count;
395 }
396
397 for (i = 0; i < num; i++) {
398 memcpy_s(staInfo[i].mac, ETHER_ADDR_LEN, assoc_maclist->ea[i].octet, ETHER_ADDR_LEN);
399 }
400
401 return HDF_SUCCESS;
402 }
403
404 struct HdfMac80211APOps g_bdh6_apOps = {
405 .ConfigAp = WalConfigAp,
406 .StartAp = WalStartAp,
407 .StopAp = WalStopAp,
408 .ConfigBeacon = WalChangeBeacon,
409 .DelStation = WalDelStation,
410 .SetCountryCode = WalSetCountryCode,
411 .GetAssociatedStasCount = WalGetAssociatedStasCount,
412 .GetAssociatedStasInfo = WalGetAssociatedStasInfo
413 };
414