• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 = &params->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