|
@@ -52,8 +52,6 @@
|
|
|
#define BRCMF_PNO_SCAN_COMPLETE 1
|
|
|
#define BRCMF_PNO_SCAN_INCOMPLETE 0
|
|
|
|
|
|
-#define BRCMF_IFACE_MAX_CNT 3
|
|
|
-
|
|
|
#define WPA_OUI "\x00\x50\xF2" /* WPA OUI */
|
|
|
#define WPA_OUI_TYPE 1
|
|
|
#define RSN_OUI "\x00\x0F\xAC" /* RSN OUI */
|
|
@@ -2398,27 +2396,80 @@ brcmf_cfg80211_reconfigure_wep(struct brcmf_if *ifp)
|
|
|
brcmf_err("set wsec error (%d)\n", err);
|
|
|
}
|
|
|
|
|
|
+static void brcmf_convert_sta_flags(u32 fw_sta_flags, struct station_info *si)
|
|
|
+{
|
|
|
+ struct nl80211_sta_flag_update *sfu;
|
|
|
+
|
|
|
+ brcmf_dbg(TRACE, "flags %08x\n", fw_sta_flags);
|
|
|
+ si->filled |= BIT(NL80211_STA_INFO_STA_FLAGS);
|
|
|
+ sfu = &si->sta_flags;
|
|
|
+ sfu->mask = BIT(NL80211_STA_FLAG_WME) |
|
|
|
+ BIT(NL80211_STA_FLAG_AUTHENTICATED) |
|
|
|
+ BIT(NL80211_STA_FLAG_ASSOCIATED) |
|
|
|
+ BIT(NL80211_STA_FLAG_AUTHORIZED);
|
|
|
+ if (fw_sta_flags & BRCMF_STA_WME)
|
|
|
+ sfu->set |= BIT(NL80211_STA_FLAG_WME);
|
|
|
+ if (fw_sta_flags & BRCMF_STA_AUTHE)
|
|
|
+ sfu->set |= BIT(NL80211_STA_FLAG_AUTHENTICATED);
|
|
|
+ if (fw_sta_flags & BRCMF_STA_ASSOC)
|
|
|
+ sfu->set |= BIT(NL80211_STA_FLAG_ASSOCIATED);
|
|
|
+ if (fw_sta_flags & BRCMF_STA_AUTHO)
|
|
|
+ sfu->set |= BIT(NL80211_STA_FLAG_AUTHORIZED);
|
|
|
+}
|
|
|
+
|
|
|
+static void brcmf_fill_bss_param(struct brcmf_if *ifp, struct station_info *si)
|
|
|
+{
|
|
|
+ struct {
|
|
|
+ __le32 len;
|
|
|
+ struct brcmf_bss_info_le bss_le;
|
|
|
+ } *buf;
|
|
|
+ u16 capability;
|
|
|
+ int err;
|
|
|
+
|
|
|
+ buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
|
|
|
+ if (!buf)
|
|
|
+ return;
|
|
|
+
|
|
|
+ buf->len = cpu_to_le32(WL_BSS_INFO_MAX);
|
|
|
+ err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO, buf,
|
|
|
+ WL_BSS_INFO_MAX);
|
|
|
+ if (err) {
|
|
|
+ brcmf_err("Failed to get bss info (%d)\n", err);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ si->filled |= BIT(NL80211_STA_INFO_BSS_PARAM);
|
|
|
+ si->bss_param.beacon_interval = le16_to_cpu(buf->bss_le.beacon_period);
|
|
|
+ si->bss_param.dtim_period = buf->bss_le.dtim_period;
|
|
|
+ capability = le16_to_cpu(buf->bss_le.capability);
|
|
|
+ if (capability & IEEE80211_HT_STBC_PARAM_DUAL_CTS_PROT)
|
|
|
+ si->bss_param.flags |= BSS_PARAM_FLAGS_CTS_PROT;
|
|
|
+ if (capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
|
|
|
+ si->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_PREAMBLE;
|
|
|
+ if (capability & WLAN_CAPABILITY_SHORT_SLOT_TIME)
|
|
|
+ si->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_SLOT_TIME;
|
|
|
+}
|
|
|
+
|
|
|
static s32
|
|
|
brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
|
|
|
const u8 *mac, struct station_info *sinfo)
|
|
|
{
|
|
|
struct brcmf_if *ifp = netdev_priv(ndev);
|
|
|
- struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
|
|
|
- struct brcmf_scb_val_le scb_val;
|
|
|
- int rssi;
|
|
|
- s32 rate;
|
|
|
s32 err = 0;
|
|
|
- u8 *bssid = profile->bssid;
|
|
|
struct brcmf_sta_info_le sta_info_le;
|
|
|
- u32 beacon_period;
|
|
|
- u32 dtim_period;
|
|
|
+ u32 sta_flags;
|
|
|
+ u32 is_tdls_peer;
|
|
|
|
|
|
brcmf_dbg(TRACE, "Enter, MAC %pM\n", mac);
|
|
|
if (!check_vif_up(ifp->vif))
|
|
|
return -EIO;
|
|
|
|
|
|
- if (brcmf_is_apmode(ifp->vif)) {
|
|
|
- memcpy(&sta_info_le, mac, ETH_ALEN);
|
|
|
+ memset(&sta_info_le, 0, sizeof(sta_info_le));
|
|
|
+ memcpy(&sta_info_le, mac, ETH_ALEN);
|
|
|
+ err = brcmf_fil_iovar_data_get(ifp, "tdls_sta_info",
|
|
|
+ &sta_info_le,
|
|
|
+ sizeof(sta_info_le));
|
|
|
+ is_tdls_peer = !err;
|
|
|
+ if (err) {
|
|
|
err = brcmf_fil_iovar_data_get(ifp, "sta_info",
|
|
|
&sta_info_le,
|
|
|
sizeof(sta_info_le));
|
|
@@ -2426,73 +2477,48 @@ brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
|
|
|
brcmf_err("GET STA INFO failed, %d\n", err);
|
|
|
goto done;
|
|
|
}
|
|
|
- sinfo->filled = BIT(NL80211_STA_INFO_INACTIVE_TIME);
|
|
|
- sinfo->inactive_time = le32_to_cpu(sta_info_le.idle) * 1000;
|
|
|
- if (le32_to_cpu(sta_info_le.flags) & BRCMF_STA_ASSOC) {
|
|
|
- sinfo->filled |= BIT(NL80211_STA_INFO_CONNECTED_TIME);
|
|
|
- sinfo->connected_time = le32_to_cpu(sta_info_le.in);
|
|
|
- }
|
|
|
- brcmf_dbg(TRACE, "STA idle time : %d ms, connected time :%d sec\n",
|
|
|
- sinfo->inactive_time, sinfo->connected_time);
|
|
|
- } else if (ifp->vif->wdev.iftype == NL80211_IFTYPE_STATION) {
|
|
|
- if (memcmp(mac, bssid, ETH_ALEN)) {
|
|
|
- brcmf_err("Wrong Mac address cfg_mac-%pM wl_bssid-%pM\n",
|
|
|
- mac, bssid);
|
|
|
- err = -ENOENT;
|
|
|
- goto done;
|
|
|
- }
|
|
|
- /* Report the current tx rate */
|
|
|
- err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_RATE, &rate);
|
|
|
- if (err) {
|
|
|
- brcmf_err("Could not get rate (%d)\n", err);
|
|
|
- goto done;
|
|
|
- } else {
|
|
|
+ }
|
|
|
+ brcmf_dbg(TRACE, "version %d\n", le16_to_cpu(sta_info_le.ver));
|
|
|
+ sinfo->filled = BIT(NL80211_STA_INFO_INACTIVE_TIME);
|
|
|
+ sinfo->inactive_time = le32_to_cpu(sta_info_le.idle) * 1000;
|
|
|
+ sta_flags = le32_to_cpu(sta_info_le.flags);
|
|
|
+ brcmf_convert_sta_flags(sta_flags, sinfo);
|
|
|
+ sinfo->sta_flags.mask |= BIT(NL80211_STA_FLAG_TDLS_PEER);
|
|
|
+ if (is_tdls_peer)
|
|
|
+ sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_TDLS_PEER);
|
|
|
+ else
|
|
|
+ sinfo->sta_flags.set &= ~BIT(NL80211_STA_FLAG_TDLS_PEER);
|
|
|
+ if (sta_flags & BRCMF_STA_ASSOC) {
|
|
|
+ sinfo->filled |= BIT(NL80211_STA_INFO_CONNECTED_TIME);
|
|
|
+ sinfo->connected_time = le32_to_cpu(sta_info_le.in);
|
|
|
+ brcmf_fill_bss_param(ifp, sinfo);
|
|
|
+ }
|
|
|
+ if (sta_flags & BRCMF_STA_SCBSTATS) {
|
|
|
+ sinfo->filled |= BIT(NL80211_STA_INFO_TX_FAILED);
|
|
|
+ sinfo->tx_failed = le32_to_cpu(sta_info_le.tx_failures);
|
|
|
+ sinfo->filled |= BIT(NL80211_STA_INFO_TX_PACKETS);
|
|
|
+ sinfo->tx_packets = le32_to_cpu(sta_info_le.tx_pkts);
|
|
|
+ sinfo->tx_packets += le32_to_cpu(sta_info_le.tx_mcast_pkts);
|
|
|
+ sinfo->filled |= BIT(NL80211_STA_INFO_RX_PACKETS);
|
|
|
+ sinfo->rx_packets = le32_to_cpu(sta_info_le.rx_ucast_pkts);
|
|
|
+ sinfo->rx_packets += le32_to_cpu(sta_info_le.rx_mcast_pkts);
|
|
|
+ if (sinfo->tx_packets) {
|
|
|
sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE);
|
|
|
- sinfo->txrate.legacy = rate * 5;
|
|
|
- brcmf_dbg(CONN, "Rate %d Mbps\n", rate / 2);
|
|
|
+ sinfo->txrate.legacy = le32_to_cpu(sta_info_le.tx_rate);
|
|
|
+ sinfo->txrate.legacy /= 100;
|
|
|
}
|
|
|
-
|
|
|
- if (test_bit(BRCMF_VIF_STATUS_CONNECTED,
|
|
|
- &ifp->vif->sme_state)) {
|
|
|
- memset(&scb_val, 0, sizeof(scb_val));
|
|
|
- err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_RSSI,
|
|
|
- &scb_val, sizeof(scb_val));
|
|
|
- if (err) {
|
|
|
- brcmf_err("Could not get rssi (%d)\n", err);
|
|
|
- goto done;
|
|
|
- } else {
|
|
|
- rssi = le32_to_cpu(scb_val.val);
|
|
|
- sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
|
|
|
- sinfo->signal = rssi;
|
|
|
- brcmf_dbg(CONN, "RSSI %d dBm\n", rssi);
|
|
|
- }
|
|
|
- err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_BCNPRD,
|
|
|
- &beacon_period);
|
|
|
- if (err) {
|
|
|
- brcmf_err("Could not get beacon period (%d)\n",
|
|
|
- err);
|
|
|
- goto done;
|
|
|
- } else {
|
|
|
- sinfo->bss_param.beacon_interval =
|
|
|
- beacon_period;
|
|
|
- brcmf_dbg(CONN, "Beacon peroid %d\n",
|
|
|
- beacon_period);
|
|
|
- }
|
|
|
- err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_DTIMPRD,
|
|
|
- &dtim_period);
|
|
|
- if (err) {
|
|
|
- brcmf_err("Could not get DTIM period (%d)\n",
|
|
|
- err);
|
|
|
- goto done;
|
|
|
- } else {
|
|
|
- sinfo->bss_param.dtim_period = dtim_period;
|
|
|
- brcmf_dbg(CONN, "DTIM peroid %d\n",
|
|
|
- dtim_period);
|
|
|
- }
|
|
|
- sinfo->filled |= BIT(NL80211_STA_INFO_BSS_PARAM);
|
|
|
+ if (sinfo->rx_packets) {
|
|
|
+ sinfo->filled |= BIT(NL80211_STA_INFO_RX_BITRATE);
|
|
|
+ sinfo->rxrate.legacy = le32_to_cpu(sta_info_le.rx_rate);
|
|
|
+ sinfo->rxrate.legacy /= 100;
|
|
|
}
|
|
|
- } else
|
|
|
- err = -EPERM;
|
|
|
+ if (le16_to_cpu(sta_info_le.ver) >= 4) {
|
|
|
+ sinfo->filled |= BIT(NL80211_STA_INFO_TX_BYTES);
|
|
|
+ sinfo->tx_bytes = le64_to_cpu(sta_info_le.tx_tot_bytes);
|
|
|
+ sinfo->filled |= BIT(NL80211_STA_INFO_RX_BYTES);
|
|
|
+ sinfo->rx_bytes = le64_to_cpu(sta_info_le.rx_tot_bytes);
|
|
|
+ }
|
|
|
+ }
|
|
|
done:
|
|
|
brcmf_dbg(TRACE, "Exit\n");
|
|
|
return err;
|
|
@@ -5640,53 +5666,6 @@ static int brcmf_setup_wiphybands(struct wiphy *wiphy)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static const struct ieee80211_iface_limit brcmf_iface_limits_mbss[] = {
|
|
|
- {
|
|
|
- .max = 1,
|
|
|
- .types = BIT(NL80211_IFTYPE_STATION) |
|
|
|
- BIT(NL80211_IFTYPE_ADHOC)
|
|
|
- },
|
|
|
- {
|
|
|
- .max = 4,
|
|
|
- .types = BIT(NL80211_IFTYPE_AP)
|
|
|
- },
|
|
|
- {
|
|
|
- .max = 1,
|
|
|
- .types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
|
|
|
- BIT(NL80211_IFTYPE_P2P_GO)
|
|
|
- },
|
|
|
- {
|
|
|
- .max = 1,
|
|
|
- .types = BIT(NL80211_IFTYPE_P2P_DEVICE)
|
|
|
- }
|
|
|
-};
|
|
|
-
|
|
|
-static const struct ieee80211_iface_limit brcmf_iface_limits_sbss[] = {
|
|
|
- {
|
|
|
- .max = 2,
|
|
|
- .types = BIT(NL80211_IFTYPE_STATION) |
|
|
|
- BIT(NL80211_IFTYPE_ADHOC) |
|
|
|
- BIT(NL80211_IFTYPE_AP)
|
|
|
- },
|
|
|
- {
|
|
|
- .max = 1,
|
|
|
- .types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
|
|
|
- BIT(NL80211_IFTYPE_P2P_GO)
|
|
|
- },
|
|
|
- {
|
|
|
- .max = 1,
|
|
|
- .types = BIT(NL80211_IFTYPE_P2P_DEVICE)
|
|
|
- }
|
|
|
-};
|
|
|
-static struct ieee80211_iface_combination brcmf_iface_combos[] = {
|
|
|
- {
|
|
|
- .max_interfaces = BRCMF_IFACE_MAX_CNT,
|
|
|
- .num_different_channels = 1,
|
|
|
- .n_limits = ARRAY_SIZE(brcmf_iface_limits_sbss),
|
|
|
- .limits = brcmf_iface_limits_sbss,
|
|
|
- }
|
|
|
-};
|
|
|
-
|
|
|
static const struct ieee80211_txrx_stypes
|
|
|
brcmf_txrx_stypes[NUM_NL80211_IFTYPES] = {
|
|
|
[NL80211_IFTYPE_STATION] = {
|
|
@@ -5716,6 +5695,67 @@ brcmf_txrx_stypes[NUM_NL80211_IFTYPES] = {
|
|
|
}
|
|
|
};
|
|
|
|
|
|
+static int brcmf_setup_ifmodes(struct wiphy *wiphy, struct brcmf_if *ifp)
|
|
|
+{
|
|
|
+ struct ieee80211_iface_combination *combo = NULL;
|
|
|
+ struct ieee80211_iface_limit *limits = NULL;
|
|
|
+ int i = 0, max_iface_cnt;
|
|
|
+
|
|
|
+ combo = kzalloc(sizeof(*combo), GFP_KERNEL);
|
|
|
+ if (!combo)
|
|
|
+ goto err;
|
|
|
+
|
|
|
+ limits = kzalloc(sizeof(*limits) * 4, GFP_KERNEL);
|
|
|
+ if (!limits)
|
|
|
+ goto err;
|
|
|
+
|
|
|
+ wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
|
|
|
+ BIT(NL80211_IFTYPE_ADHOC) |
|
|
|
+ BIT(NL80211_IFTYPE_AP);
|
|
|
+
|
|
|
+ if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MCHAN))
|
|
|
+ combo->num_different_channels = 2;
|
|
|
+ else
|
|
|
+ combo->num_different_channels = 1;
|
|
|
+
|
|
|
+ if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS)) {
|
|
|
+ limits[i].max = 1;
|
|
|
+ limits[i++].types = BIT(NL80211_IFTYPE_STATION);
|
|
|
+ limits[i].max = 4;
|
|
|
+ limits[i++].types = BIT(NL80211_IFTYPE_AP);
|
|
|
+ max_iface_cnt = 5;
|
|
|
+ } else {
|
|
|
+ limits[i].max = 2;
|
|
|
+ limits[i++].types = BIT(NL80211_IFTYPE_STATION) |
|
|
|
+ BIT(NL80211_IFTYPE_AP);
|
|
|
+ max_iface_cnt = 2;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_P2P)) {
|
|
|
+ wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_CLIENT) |
|
|
|
+ BIT(NL80211_IFTYPE_P2P_GO) |
|
|
|
+ BIT(NL80211_IFTYPE_P2P_DEVICE);
|
|
|
+ limits[i].max = 1;
|
|
|
+ limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
|
|
|
+ BIT(NL80211_IFTYPE_P2P_GO);
|
|
|
+ limits[i].max = 1;
|
|
|
+ limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE);
|
|
|
+ max_iface_cnt += 2;
|
|
|
+ }
|
|
|
+ combo->max_interfaces = max_iface_cnt;
|
|
|
+ combo->limits = limits;
|
|
|
+ combo->n_limits = i;
|
|
|
+
|
|
|
+ wiphy->iface_combinations = combo;
|
|
|
+ wiphy->n_iface_combinations = 1;
|
|
|
+ return 0;
|
|
|
+
|
|
|
+err:
|
|
|
+ kfree(limits);
|
|
|
+ kfree(combo);
|
|
|
+ return -ENOMEM;
|
|
|
+}
|
|
|
+
|
|
|
static void brcmf_wiphy_pno_params(struct wiphy *wiphy)
|
|
|
{
|
|
|
/* scheduled scan settings */
|
|
@@ -5746,7 +5786,6 @@ static void brcmf_wiphy_wowl_params(struct wiphy *wiphy)
|
|
|
static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp)
|
|
|
{
|
|
|
struct ieee80211_supported_band *band;
|
|
|
- struct ieee80211_iface_combination ifc_combo;
|
|
|
__le32 bandlist[3];
|
|
|
u32 n_bands;
|
|
|
int err, i;
|
|
@@ -5754,24 +5793,11 @@ static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp)
|
|
|
wiphy->max_scan_ssids = WL_NUM_SCAN_MAX;
|
|
|
wiphy->max_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
|
|
|
wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX;
|
|
|
- wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
|
|
|
- BIT(NL80211_IFTYPE_ADHOC) |
|
|
|
- BIT(NL80211_IFTYPE_AP) |
|
|
|
- BIT(NL80211_IFTYPE_P2P_CLIENT) |
|
|
|
- BIT(NL80211_IFTYPE_P2P_GO) |
|
|
|
- BIT(NL80211_IFTYPE_P2P_DEVICE);
|
|
|
- /* need VSDB firmware feature for concurrent channels */
|
|
|
- ifc_combo = brcmf_iface_combos[0];
|
|
|
- if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MCHAN))
|
|
|
- ifc_combo.num_different_channels = 2;
|
|
|
- if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS)) {
|
|
|
- ifc_combo.n_limits = ARRAY_SIZE(brcmf_iface_limits_mbss),
|
|
|
- ifc_combo.limits = brcmf_iface_limits_mbss;
|
|
|
- }
|
|
|
- wiphy->iface_combinations = kmemdup(&ifc_combo,
|
|
|
- sizeof(ifc_combo),
|
|
|
- GFP_KERNEL);
|
|
|
- wiphy->n_iface_combinations = ARRAY_SIZE(brcmf_iface_combos);
|
|
|
+
|
|
|
+ err = brcmf_setup_ifmodes(wiphy, ifp);
|
|
|
+ if (err)
|
|
|
+ return err;
|
|
|
+
|
|
|
wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
|
|
|
wiphy->cipher_suites = __wl_cipher_suites;
|
|
|
wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites);
|
|
@@ -6036,6 +6062,8 @@ static void brcmf_free_wiphy(struct wiphy *wiphy)
|
|
|
if (!wiphy)
|
|
|
return;
|
|
|
|
|
|
+ if (wiphy->iface_combinations)
|
|
|
+ kfree(wiphy->iface_combinations->limits);
|
|
|
kfree(wiphy->iface_combinations);
|
|
|
if (wiphy->bands[IEEE80211_BAND_2GHZ]) {
|
|
|
kfree(wiphy->bands[IEEE80211_BAND_2GHZ]->channels);
|
|
@@ -6071,6 +6099,7 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
|
|
|
brcmf_err("Could not allocate wiphy device\n");
|
|
|
return NULL;
|
|
|
}
|
|
|
+ memcpy(wiphy->perm_addr, drvr->mac, ETH_ALEN);
|
|
|
set_wiphy_dev(wiphy, busdev);
|
|
|
|
|
|
cfg = wiphy_priv(wiphy);
|
|
@@ -6178,10 +6207,8 @@ void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg)
|
|
|
if (!cfg)
|
|
|
return;
|
|
|
|
|
|
- WARN_ON(!list_empty(&cfg->vif_list));
|
|
|
- wiphy_unregister(cfg->wiphy);
|
|
|
brcmf_btcoex_detach(cfg);
|
|
|
- brcmf_p2p_detach(&cfg->p2p);
|
|
|
+ wiphy_unregister(cfg->wiphy);
|
|
|
wl_deinit_priv(cfg);
|
|
|
brcmf_free_wiphy(cfg->wiphy);
|
|
|
}
|