* [PATCH 0/3] brcmfmac: 160MHz fixes and DFS offload
From: Arend van Spriel @ 2019-07-11 8:45 UTC (permalink / raw)
To: Kalle Valo; +Cc: linux-wireless, Arend van Spriel
The 160MHz AP mode was not properly working and limited due to lack of
DFS offload. So this series include following changes:
* encode 160MHz channel definition to firmware format.
* adapt custom regulatory rule allowing 160MHz.
* enable DFS offloading for firmwares supporting it.
The series applies to the master branch of the wireless-drivers-next
repository.
Arend van Spriel (3):
brcmfmac: add 160MHz in chandef_to_chanspec()
brcmfmac: enable DFS_OFFLOAD extended feature if supported
brcmfmac: allow 160MHz in custom regulatory rules
.../broadcom/brcm80211/brcmfmac/cfg80211.c | 30 +++++++++++++++++++---
.../wireless/broadcom/brcm80211/brcmfmac/feature.c | 1 +
.../wireless/broadcom/brcm80211/brcmfmac/feature.h | 4 ++-
3 files changed, 31 insertions(+), 4 deletions(-)
--
1.9.1
^ permalink raw reply
* [PATCH 3/3] brcmfmac: allow 160MHz in custom regulatory rules
From: Arend van Spriel @ 2019-07-11 8:45 UTC (permalink / raw)
To: Kalle Valo; +Cc: linux-wireless, Arend van Spriel
In-Reply-To: <1562834732-31508-1-git-send-email-arend.vanspriel@broadcom.com>
The driver has custom regulatory rules which had maximum bandwidth
for 5GHz channels set to 80MHz. As a consequence the driver can
not use 160MHz in AP mode even when the device supports it. So
relax the rules allowing 160MHz. After wiphy_register() the channel
flags are updated according what the device actually supports.
Reviewed-by: Hante Meuleman <hante.meuleman@broadcom.com>
Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
Reviewed-by: Franky Lin <franky.lin@broadcom.com>
Signed-off-by: Arend van Spriel <arend.vanspriel@broadcom.com>
---
drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
index 3f72dc1..b692689 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
@@ -189,9 +189,9 @@ static bool check_vif_up(struct brcmf_cfg80211_vif *vif)
*/
REG_RULE(2484-10, 2484+10, 20, 6, 20, 0),
/* IEEE 802.11a, channel 36..64 */
- REG_RULE(5150-10, 5350+10, 80, 6, 20, 0),
+ REG_RULE(5150-10, 5350+10, 160, 6, 20, 0),
/* IEEE 802.11a, channel 100..165 */
- REG_RULE(5470-10, 5850+10, 80, 6, 20, 0), }
+ REG_RULE(5470-10, 5850+10, 160, 6, 20, 0), }
};
/* Note: brcmf_cipher_suites is an array of int defining which cipher suites
--
1.9.1
^ permalink raw reply related
* [PATCH 1/3] brcmfmac: add 160MHz in chandef_to_chanspec()
From: Arend van Spriel @ 2019-07-11 8:45 UTC (permalink / raw)
To: Kalle Valo; +Cc: linux-wireless, Arend van Spriel
In-Reply-To: <1562834732-31508-1-git-send-email-arend.vanspriel@broadcom.com>
The function chandef_to_chanspec() was not handling 160MHz bandwidth
resulting in wrong encoding of the channel. That resulting in firmware
rejecting the provided channel specification.
Reviewed-by: Hante Meuleman <hante.meuleman@broadcom.com>
Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
Reviewed-by: Franky Lin <franky.lin@broadcom.com>
Signed-off-by: Arend van Spriel <arend.vanspriel@broadcom.com>
---
.../wireless/broadcom/brcm80211/brcmfmac/cfg80211.c | 21 ++++++++++++++++++++-
1 file changed, 20 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
index b6d0df3..5168d42 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
@@ -276,8 +276,26 @@ static u16 chandef_to_chanspec(struct brcmu_d11inf *d11inf,
else
ch_inf.sb = BRCMU_CHAN_SB_UU;
break;
- case NL80211_CHAN_WIDTH_80P80:
case NL80211_CHAN_WIDTH_160:
+ ch_inf.bw = BRCMU_CHAN_BW_160;
+ if (primary_offset == -70)
+ ch_inf.sb = BRCMU_CHAN_SB_LLL;
+ else if (primary_offset == -50)
+ ch_inf.sb = BRCMU_CHAN_SB_LLU;
+ else if (primary_offset == -30)
+ ch_inf.sb = BRCMU_CHAN_SB_LUL;
+ else if (primary_offset == -10)
+ ch_inf.sb = BRCMU_CHAN_SB_LUU;
+ else if (primary_offset == 10)
+ ch_inf.sb = BRCMU_CHAN_SB_ULL;
+ else if (primary_offset == 30)
+ ch_inf.sb = BRCMU_CHAN_SB_ULU;
+ else if (primary_offset == 50)
+ ch_inf.sb = BRCMU_CHAN_SB_UUL;
+ else
+ ch_inf.sb = BRCMU_CHAN_SB_UUU;
+ break;
+ case NL80211_CHAN_WIDTH_80P80:
case NL80211_CHAN_WIDTH_5:
case NL80211_CHAN_WIDTH_10:
default:
@@ -296,6 +314,7 @@ static u16 chandef_to_chanspec(struct brcmu_d11inf *d11inf,
}
d11inf->encchspec(&ch_inf);
+ brcmf_dbg(TRACE, "chanspec: 0x%x\n", ch_inf.chspec);
return ch_inf.chspec;
}
--
1.9.1
^ permalink raw reply related
* [PATCH 2/3] brcmfmac: enable DFS_OFFLOAD extended feature if supported
From: Arend van Spriel @ 2019-07-11 8:45 UTC (permalink / raw)
To: Kalle Valo; +Cc: linux-wireless, Arend van Spriel
In-Reply-To: <1562834732-31508-1-git-send-email-arend.vanspriel@broadcom.com>
If the firmware supports 802.11h and the device can operate in 5GHz
band we can enable DFS_OFFLOAD extended feature.
Reviewed-by: Hante Meuleman <hante.meuleman@broadcom.com>
Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
Reviewed-by: Franky Lin <franky.lin@broadcom.com>
Signed-off-by: Arend van Spriel <arend.vanspriel@broadcom.com>
---
drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c | 5 +++++
drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c | 1 +
drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h | 4 +++-
3 files changed, 9 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
index 5168d42..3f72dc1 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
@@ -6733,6 +6733,11 @@ static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp)
}
}
+ if (wiphy->bands[NL80211_BAND_5GHZ] &&
+ brcmf_feat_is_enabled(ifp, BRCMF_FEAT_DOT11H))
+ wiphy_ext_feature_set(wiphy,
+ NL80211_EXT_FEATURE_DFS_OFFLOAD);
+
wiphy_read_of_freq_limits(wiphy);
return 0;
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c
index 73aff4e..2c3526a 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c
@@ -39,6 +39,7 @@ struct brcmf_feat_fwcap {
{ BRCMF_FEAT_P2P, "p2p" },
{ BRCMF_FEAT_MONITOR, "monitor" },
{ BRCMF_FEAT_MONITOR_FMT_RADIOTAP, "rtap" },
+ { BRCMF_FEAT_DOT11H, "802.11h" }
};
#ifdef DEBUG
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h
index f127eb2..736a817 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h
@@ -25,6 +25,7 @@
* MONITOR: firmware can pass monitor packets to host.
* MONITOR_FMT_RADIOTAP: firmware provides monitor packets with radiotap header
* MONITOR_FMT_HW_RX_HDR: firmware provides monitor packets with hw/ucode header
+ * DOT11H: firmware supports 802.11h
*/
#define BRCMF_FEAT_LIST \
BRCMF_FEAT_DEF(MBSS) \
@@ -43,7 +44,8 @@
BRCMF_FEAT_DEF(FWSUP) \
BRCMF_FEAT_DEF(MONITOR) \
BRCMF_FEAT_DEF(MONITOR_FMT_RADIOTAP) \
- BRCMF_FEAT_DEF(MONITOR_FMT_HW_RX_HDR)
+ BRCMF_FEAT_DEF(MONITOR_FMT_HW_RX_HDR) \
+ BRCMF_FEAT_DEF(DOT11H)
/*
* Quirks:
--
1.9.1
^ permalink raw reply related
* [PATCH 0/7] brcmfmac: rework probe/attach sequence
From: Arend van Spriel @ 2019-07-11 9:05 UTC (permalink / raw)
To: Kalle Valo; +Cc: linux-wireless, Arend van Spriel
The brcmfmac driver spews some error message upon unloading and Stefan
Wahren was wondering whether it could be cleaned up. Related to this
was a recent fix for NULL pointer deref. That fix introduced a construct
that added to the itch to rework the probe sequence. So this series
reverts commit 5cdb0ef6144f ("brcmfmac: fix NULL pointer derefence during
USB disconnect").
The changes in this series are:
* reorder brcmf_detach() code.
* avoid firmware interaction when bus is down.
* remove strlcpy() before issueing firmware version iovar.
This series applies to the master branch of the wireless-drivers-next
repository.
Arend van Spriel (7):
Revert "brcmfmac: fix NULL pointer derefence during USB disconnect"
brcmfmac: change the order of things in brcmf_detach()
brcmfmac: avoid firmware command in brcmf_netdev_open() when bus is
down
brcmfmac: clear events in brcmf_fweh_detach() will always fail
brcmfmac: avoid firmware commands when bus is down
brcmfmac: simply remove flowring if bus is down
brcmfmac: remove unnecessary strlcpy() upon obtaining "ver" iovar
.../wireless/broadcom/brcm80211/brcmfmac/bcdc.c | 11 ++------
.../wireless/broadcom/brcm80211/brcmfmac/bcdc.h | 6 ++---
.../broadcom/brcm80211/brcmfmac/cfg80211.c | 23 +++++++++--------
.../wireless/broadcom/brcm80211/brcmfmac/common.c | 1 -
.../wireless/broadcom/brcm80211/brcmfmac/core.c | 30 +++++++++++-----------
.../wireless/broadcom/brcm80211/brcmfmac/fweh.c | 9 -------
.../broadcom/brcm80211/brcmfmac/fwsignal.c | 16 +++---------
.../broadcom/brcm80211/brcmfmac/fwsignal.h | 3 +--
.../wireless/broadcom/brcm80211/brcmfmac/msgbuf.c | 7 +++++
.../wireless/broadcom/brcm80211/brcmfmac/proto.c | 10 ++------
.../wireless/broadcom/brcm80211/brcmfmac/proto.h | 3 +--
11 files changed, 47 insertions(+), 72 deletions(-)
--
1.9.1
^ permalink raw reply
* [PATCH 3/7] brcmfmac: avoid firmware command in brcmf_netdev_open() when bus is down
From: Arend van Spriel @ 2019-07-11 9:05 UTC (permalink / raw)
To: Kalle Valo; +Cc: linux-wireless, Arend van Spriel
In-Reply-To: <1562835912-1404-1-git-send-email-arend.vanspriel@broadcom.com>
No point in sending a firmware command when bus is down so make it
conditional checking the state.
Reviewed-by: Hante Meuleman <hante.meuleman@broadcom.com>
Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
Reviewed-by: Franky Lin <franky.lin@broadcom.com>
Signed-off-by: Arend van Spriel <arend.vanspriel@broadcom.com>
---
drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
index 80d54d2..705b8cc 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
@@ -579,7 +579,8 @@ static int brcmf_netdev_stop(struct net_device *ndev)
brcmf_cfg80211_down(ndev);
- brcmf_fil_iovar_data_set(ifp, "arp_hostip_clear", NULL, 0);
+ if (ifp->drvr->bus_if->state == BRCMF_BUS_UP)
+ brcmf_fil_iovar_data_set(ifp, "arp_hostip_clear", NULL, 0);
brcmf_net_setcarrier(ifp, false);
--
1.9.1
^ permalink raw reply related
* [PATCH 1/7] Revert "brcmfmac: fix NULL pointer derefence during USB disconnect"
From: Arend van Spriel @ 2019-07-11 9:05 UTC (permalink / raw)
To: Kalle Valo; +Cc: linux-wireless, Arend van Spriel
In-Reply-To: <1562835912-1404-1-git-send-email-arend.vanspriel@broadcom.com>
This reverts commit 5cdb0ef6144f47440850553579aa923c20a63f23. Subsequent
changes make rework the driver code fixing the issue differently.
Signed-off-by: Arend van Spriel <arend.vanspriel@broadcom.com>
---
drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c | 11 ++---------
drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.h | 6 ++----
drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c | 4 +---
.../net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c | 16 ++++------------
.../net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.h | 3 +--
drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.c | 10 ++--------
drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.h | 3 +--
7 files changed, 13 insertions(+), 40 deletions(-)
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c
index 322e913..2c95a08 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c
@@ -479,18 +479,11 @@ int brcmf_proto_bcdc_attach(struct brcmf_pub *drvr)
return -ENOMEM;
}
-void brcmf_proto_bcdc_detach_pre_delif(struct brcmf_pub *drvr)
-{
- struct brcmf_bcdc *bcdc = drvr->proto->pd;
-
- brcmf_fws_detach_pre_delif(bcdc->fws);
-}
-
-void brcmf_proto_bcdc_detach_post_delif(struct brcmf_pub *drvr)
+void brcmf_proto_bcdc_detach(struct brcmf_pub *drvr)
{
struct brcmf_bcdc *bcdc = drvr->proto->pd;
drvr->proto->pd = NULL;
- brcmf_fws_detach_post_delif(bcdc->fws);
+ brcmf_fws_detach(bcdc->fws);
kfree(bcdc);
}
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.h
index 102e693..b051d28 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.h
@@ -7,16 +7,14 @@
#ifdef CONFIG_BRCMFMAC_PROTO_BCDC
int brcmf_proto_bcdc_attach(struct brcmf_pub *drvr);
-void brcmf_proto_bcdc_detach_pre_delif(struct brcmf_pub *drvr);
-void brcmf_proto_bcdc_detach_post_delif(struct brcmf_pub *drvr);
+void brcmf_proto_bcdc_detach(struct brcmf_pub *drvr);
void brcmf_proto_bcdc_txflowblock(struct device *dev, bool state);
void brcmf_proto_bcdc_txcomplete(struct device *dev, struct sk_buff *txp,
bool success);
struct brcmf_fws_info *drvr_to_fws(struct brcmf_pub *drvr);
#else
static inline int brcmf_proto_bcdc_attach(struct brcmf_pub *drvr) { return 0; }
-static void brcmf_proto_bcdc_detach_pre_delif(struct brcmf_pub *drvr) {};
-static inline void brcmf_proto_bcdc_detach_post_delif(struct brcmf_pub *drvr) {}
+static inline void brcmf_proto_bcdc_detach(struct brcmf_pub *drvr) {}
#endif
#endif /* BRCMFMAC_BCDC_H */
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
index bf18491..fda6044 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
@@ -1314,8 +1314,6 @@ void brcmf_detach(struct device *dev)
brcmf_bus_change_state(bus_if, BRCMF_BUS_DOWN);
- brcmf_proto_detach_pre_delif(drvr);
-
/* make sure primary interface removed last */
for (i = BRCMF_MAX_IFS-1; i > -1; i--)
brcmf_remove_interface(drvr->iflist[i], false);
@@ -1325,7 +1323,7 @@ void brcmf_detach(struct device *dev)
brcmf_bus_stop(drvr->bus_if);
- brcmf_proto_detach_post_delif(drvr);
+ brcmf_proto_detach(drvr);
bus_if->drvr = NULL;
wiphy_free(drvr->wiphy);
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c
index b8452cb..2bd892d 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c
@@ -2432,25 +2432,17 @@ struct brcmf_fws_info *brcmf_fws_attach(struct brcmf_pub *drvr)
return fws;
fail:
- brcmf_fws_detach_pre_delif(fws);
- brcmf_fws_detach_post_delif(fws);
+ brcmf_fws_detach(fws);
return ERR_PTR(rc);
}
-void brcmf_fws_detach_pre_delif(struct brcmf_fws_info *fws)
+void brcmf_fws_detach(struct brcmf_fws_info *fws)
{
if (!fws)
return;
- if (fws->fws_wq) {
- destroy_workqueue(fws->fws_wq);
- fws->fws_wq = NULL;
- }
-}
-void brcmf_fws_detach_post_delif(struct brcmf_fws_info *fws)
-{
- if (!fws)
- return;
+ if (fws->fws_wq)
+ destroy_workqueue(fws->fws_wq);
/* cleanup */
brcmf_fws_lock(fws);
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.h
index 10184ee..b486d57 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.h
@@ -7,8 +7,7 @@
#define FWSIGNAL_H_
struct brcmf_fws_info *brcmf_fws_attach(struct brcmf_pub *drvr);
-void brcmf_fws_detach_pre_delif(struct brcmf_fws_info *fws);
-void brcmf_fws_detach_post_delif(struct brcmf_fws_info *fws);
+void brcmf_fws_detach(struct brcmf_fws_info *fws);
void brcmf_fws_debugfs_create(struct brcmf_pub *drvr);
bool brcmf_fws_queue_skbs(struct brcmf_fws_info *fws);
bool brcmf_fws_fc_active(struct brcmf_fws_info *fws);
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.c
index e3d1b07..2e911d4 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.c
@@ -56,22 +56,16 @@ int brcmf_proto_attach(struct brcmf_pub *drvr)
return -ENOMEM;
}
-void brcmf_proto_detach_post_delif(struct brcmf_pub *drvr)
+void brcmf_proto_detach(struct brcmf_pub *drvr)
{
brcmf_dbg(TRACE, "Enter\n");
if (drvr->proto) {
if (drvr->bus_if->proto_type == BRCMF_PROTO_BCDC)
- brcmf_proto_bcdc_detach_post_delif(drvr);
+ brcmf_proto_bcdc_detach(drvr);
else if (drvr->bus_if->proto_type == BRCMF_PROTO_MSGBUF)
brcmf_proto_msgbuf_detach(drvr);
kfree(drvr->proto);
drvr->proto = NULL;
}
}
-
-void brcmf_proto_detach_pre_delif(struct brcmf_pub *drvr)
-{
- if (drvr->proto && drvr->bus_if->proto_type == BRCMF_PROTO_BCDC)
- brcmf_proto_bcdc_detach_pre_delif(drvr);
-}
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.h
index 8d55fad..bd08d3a 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.h
@@ -43,8 +43,7 @@ struct brcmf_proto {
int brcmf_proto_attach(struct brcmf_pub *drvr);
-void brcmf_proto_detach_pre_delif(struct brcmf_pub *drvr);
-void brcmf_proto_detach_post_delif(struct brcmf_pub *drvr);
+void brcmf_proto_detach(struct brcmf_pub *drvr);
static inline int brcmf_proto_hdrpull(struct brcmf_pub *drvr, bool do_fws,
struct sk_buff *skb,
--
1.9.1
^ permalink raw reply related
* [PATCH 7/7] brcmfmac: remove unnecessary strlcpy() upon obtaining "ver" iovar
From: Arend van Spriel @ 2019-07-11 9:05 UTC (permalink / raw)
To: Kalle Valo; +Cc: linux-wireless, Arend van Spriel
In-Reply-To: <1562835912-1404-1-git-send-email-arend.vanspriel@broadcom.com>
Recently a strcpy() was replaced by strlcpy(). However, the strcpy()
was not needed in the first place. So removing that line of code.
Reviewed-by: Hante Meuleman <hante.meuleman@broadcom.com>
Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
Reviewed-by: Franky Lin <franky.lin@broadcom.com>
Signed-off-by: Arend van Spriel <arend.vanspriel@broadcom.com>
---
drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
index aa89d62..dec25e4 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
@@ -258,7 +258,6 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)
/* query for 'ver' to get version info from firmware */
memset(buf, 0, sizeof(buf));
- strlcpy(buf, "ver", sizeof(buf));
err = brcmf_fil_iovar_data_get(ifp, "ver", buf, sizeof(buf));
if (err < 0) {
bphy_err(drvr, "Retrieving version information failed, %d\n",
--
1.9.1
^ permalink raw reply related
* [PATCH 6/7] brcmfmac: simply remove flowring if bus is down
From: Arend van Spriel @ 2019-07-11 9:05 UTC (permalink / raw)
To: Kalle Valo; +Cc: linux-wireless, Arend van Spriel
In-Reply-To: <1562835912-1404-1-git-send-email-arend.vanspriel@broadcom.com>
When the bus is down, eg. due to rmmod, there is no need to
attempt to inform firmware about it.
Reviewed-by: Hante Meuleman <hante.meuleman@broadcom.com>
Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
Reviewed-by: Franky Lin <franky.lin@broadcom.com>
Signed-off-by: Arend van Spriel <arend.vanspriel@broadcom.com>
---
drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c
index 241747b..8428be8 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c
@@ -1398,6 +1398,13 @@ void brcmf_msgbuf_delete_flowring(struct brcmf_pub *drvr, u16 flowid)
u8 ifidx;
int err;
+ /* no need to submit if firmware can not be reached */
+ if (drvr->bus_if->state != BRCMF_BUS_UP) {
+ brcmf_dbg(MSGBUF, "bus down, flowring will be removed\n");
+ brcmf_msgbuf_remove_flowring(msgbuf, flowid);
+ return;
+ }
+
commonring = msgbuf->commonrings[BRCMF_H2D_MSGRING_CONTROL_SUBMIT];
brcmf_commonring_lock(commonring);
ret_ptr = brcmf_commonring_reserve_for_write(commonring);
--
1.9.1
^ permalink raw reply related
* [PATCH 2/7] brcmfmac: change the order of things in brcmf_detach()
From: Arend van Spriel @ 2019-07-11 9:05 UTC (permalink / raw)
To: Kalle Valo; +Cc: linux-wireless, Arend van Spriel
In-Reply-To: <1562835912-1404-1-git-send-email-arend.vanspriel@broadcom.com>
When brcmf_detach() from the bus layer upon rmmod we can no longer
communicate. Hence we will set the bus state to DOWN and cleanup
the event and protocol layer. The network interfaces need to be
deleted before brcmf_cfg80211_detach() because the latter does the
wiphy_unregister() which issues a warning if there are still network
devices linked to the wiphy instance.
Reviewed-by: Hante Meuleman <hante.meuleman@broadcom.com>
Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
Reviewed-by: Franky Lin <franky.lin@broadcom.com>
Signed-off-by: Arend van Spriel <arend.vanspriel@broadcom.com>
---
.../wireless/broadcom/brcm80211/brcmfmac/core.c | 27 +++++++++++-----------
1 file changed, 14 insertions(+), 13 deletions(-)
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
index fda6044..80d54d2 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
@@ -1307,25 +1307,26 @@ void brcmf_detach(struct device *dev)
unregister_inet6addr_notifier(&drvr->inet6addr_notifier);
#endif
- /* stop firmware event handling */
- brcmf_fweh_detach(drvr);
- if (drvr->config)
- brcmf_p2p_detach(&drvr->config->p2p);
-
brcmf_bus_change_state(bus_if, BRCMF_BUS_DOWN);
-
- /* make sure primary interface removed last */
- for (i = BRCMF_MAX_IFS-1; i > -1; i--)
- brcmf_remove_interface(drvr->iflist[i], false);
-
- brcmf_cfg80211_detach(drvr->config);
- drvr->config = NULL;
-
brcmf_bus_stop(drvr->bus_if);
+ brcmf_fweh_detach(drvr);
brcmf_proto_detach(drvr);
+ /* make sure primary interface removed last */
+ for (i = BRCMF_MAX_IFS - 1; i > -1; i--) {
+ if (drvr->iflist[i])
+ brcmf_del_if(drvr, drvr->iflist[i]->bsscfgidx, false);
+ }
+
+ if (drvr->config) {
+ brcmf_p2p_detach(&drvr->config->p2p);
+ brcmf_cfg80211_detach(drvr->config);
+ drvr->config = NULL;
+ }
+
bus_if->drvr = NULL;
+
wiphy_free(drvr->wiphy);
}
--
1.9.1
^ permalink raw reply related
* [PATCH 5/7] brcmfmac: avoid firmware commands when bus is down
From: Arend van Spriel @ 2019-07-11 9:05 UTC (permalink / raw)
To: Kalle Valo; +Cc: linux-wireless, Arend van Spriel
In-Reply-To: <1562835912-1404-1-git-send-email-arend.vanspriel@broadcom.com>
Upon rmmod a few attempts are made to inform firmware, but there is
no point as the bus is down and these will fail. Avoid them to keep
the logs clean.
Reported-by: Stefan Wahren <stefan.wahren@i2se.com>
Reviewed-by: Hante Meuleman <hante.meuleman@broadcom.com>
Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
Reviewed-by: Franky Lin <franky.lin@broadcom.com>
Signed-off-by: Arend van Spriel <arend.vanspriel@broadcom.com>
---
.../broadcom/brcm80211/brcmfmac/cfg80211.c | 23 ++++++++++++----------
1 file changed, 13 insertions(+), 10 deletions(-)
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
index b6d0df3..4e3e9d44 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
@@ -1267,17 +1267,21 @@ static void brcmf_link_down(struct brcmf_cfg80211_vif *vif, u16 reason)
{
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(vif->wdev.wiphy);
struct brcmf_pub *drvr = cfg->pub;
+ bool bus_up = drvr->bus_if->state == BRCMF_BUS_UP;
s32 err = 0;
brcmf_dbg(TRACE, "Enter\n");
if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state)) {
- brcmf_dbg(INFO, "Call WLC_DISASSOC to stop excess roaming\n");
- err = brcmf_fil_cmd_data_set(vif->ifp,
- BRCMF_C_DISASSOC, NULL, 0);
- if (err) {
- bphy_err(drvr, "WLC_DISASSOC failed (%d)\n", err);
+ if (bus_up) {
+ brcmf_dbg(INFO, "Call WLC_DISASSOC to stop excess roaming\n");
+ err = brcmf_fil_cmd_data_set(vif->ifp,
+ BRCMF_C_DISASSOC, NULL, 0);
+ if (err)
+ bphy_err(drvr, "WLC_DISASSOC failed (%d)\n",
+ err);
}
+
if ((vif->wdev.iftype == NL80211_IFTYPE_STATION) ||
(vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT))
cfg80211_disconnected(vif->wdev.netdev, reason, NULL, 0,
@@ -1287,7 +1291,8 @@ static void brcmf_link_down(struct brcmf_cfg80211_vif *vif, u16 reason)
clear_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_ENABLED, 0);
if (vif->profile.use_fwsup != BRCMF_PROFILE_FWSUP_NONE) {
- brcmf_set_pmk(vif->ifp, NULL, 0);
+ if (bus_up)
+ brcmf_set_pmk(vif->ifp, NULL, 0);
vif->profile.use_fwsup = BRCMF_PROFILE_FWSUP_NONE;
}
brcmf_dbg(TRACE, "Exit\n");
@@ -4985,18 +4990,16 @@ static int brcmf_cfg80211_get_channel(struct wiphy *wiphy,
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
struct net_device *ndev = wdev->netdev;
struct brcmf_pub *drvr = cfg->pub;
- struct brcmf_if *ifp;
struct brcmu_chan ch;
enum nl80211_band band = 0;
enum nl80211_chan_width width = 0;
u32 chanspec;
int freq, err;
- if (!ndev)
+ if (!ndev || drvr->bus_if->state != BRCMF_BUS_UP)
return -ENODEV;
- ifp = netdev_priv(ndev);
- err = brcmf_fil_iovar_int_get(ifp, "chanspec", &chanspec);
+ err = brcmf_fil_iovar_int_get(netdev_priv(ndev), "chanspec", &chanspec);
if (err) {
bphy_err(drvr, "chanspec failed (%d)\n", err);
return err;
--
1.9.1
^ permalink raw reply related
* [PATCH 4/7] brcmfmac: clear events in brcmf_fweh_detach() will always fail
From: Arend van Spriel @ 2019-07-11 9:05 UTC (permalink / raw)
To: Kalle Valo; +Cc: linux-wireless, Arend van Spriel
In-Reply-To: <1562835912-1404-1-git-send-email-arend.vanspriel@broadcom.com>
Clearing firmware events in brcmf_fweh_detach() is always failing
because it is called only upon driver remove and communication
with firmware is no longer possible.
Reviewed-by: Hante Meuleman <hante.meuleman@broadcom.com>
Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
Reviewed-by: Franky Lin <franky.lin@broadcom.com>
Signed-off-by: Arend van Spriel <arend.vanspriel@broadcom.com>
---
drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c | 9 ---------
1 file changed, 9 deletions(-)
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c
index adedd4f..79c8a85 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c
@@ -303,16 +303,7 @@ void brcmf_fweh_attach(struct brcmf_pub *drvr)
void brcmf_fweh_detach(struct brcmf_pub *drvr)
{
struct brcmf_fweh_info *fweh = &drvr->fweh;
- struct brcmf_if *ifp = brcmf_get_ifp(drvr, 0);
- s8 eventmask[BRCMF_EVENTING_MASK_LEN];
- if (ifp) {
- /* clear all events */
- memset(eventmask, 0, BRCMF_EVENTING_MASK_LEN);
- (void)brcmf_fil_iovar_data_set(ifp, "event_msgs",
- eventmask,
- BRCMF_EVENTING_MASK_LEN);
- }
/* cancel the worker */
cancel_work_sync(&fweh->event_work);
WARN_ON(!list_empty(&fweh->event_q));
--
1.9.1
^ permalink raw reply related
* Re: [PATCH 1/3] cfg80211: clean up cfg80211_inform_single_bss_frame_data()
From: Sergey Matyukevich @ 2019-07-11 9:31 UTC (permalink / raw)
To: Johannes Berg; +Cc: linux-wireless@vger.kernel.org, Johannes Berg
In-Reply-To: <20190703133823.10530-1-johannes@sipsolutions.net>
> From: Johannes Berg <johannes.berg@intel.com>
>
> cfg80211_inform_single_bss_frame_data() doesn't need the
> non_tx_data data argument since it's always NULL.
>
> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
For all 3 patches:
Reviewed-by: Sergey Matyukevich <sergey.matyukevich.os@quantenna.com>
Regards,
Sergey
^ permalink raw reply
* Re: [RFC 0/8] nl80211: add 6GHz band support
From: Arend Van Spriel @ 2019-07-11 11:30 UTC (permalink / raw)
To: Johannes Berg; +Cc: linux-wireless, Jouni Malinen, Tova Mussai
In-Reply-To: <48a43287e65e1d24082dea2cc32ca14998acb8d1.camel@sipsolutions.net>
On 6/28/2019 3:04 PM, Johannes Berg wrote:
> Hi Arend, all,
>
> Sorry. No, my thoughts aren't really more concrete, but Tova is starting
> to work on this now.
>
>> This came up in discussion with my colleagues today and I would say from
>> mac80211 perspective there is more to it than just scanning. In short
>> the 6GHz band is for HE-only operation so for example only HE rates may
>> be used. As the bitrates are in ieee80211_supported_band having a
>> separate 6GHz band seems to have a (slight?) advantage.
>
> Hmm, that's a good point too, I hadn't really looked _too_ much at 6GHz
> stuff.
>
> Jouni, what do you think?
>
> Perhaps we should just have both. I mean, we can treat this as a
> separate band, and still have code to handle operating classes properly,
> right?
I assume user-space does not necessarily need the band, but hostapd
needs to be aware that it is operating in 6GHz to setup the correct
(information) elements in the beacon. Obviously the operating classes
can be used there, but I don't think there is any issue with nl80211
exposing a 6G band.
Regards,
Arend
^ permalink raw reply
* Re: [PATCHv6 1/9] nl80211: New netlink command for TID specific configuration
From: Sergey Matyukevich @ 2019-07-11 12:51 UTC (permalink / raw)
To: Tamizh chelvam
Cc: johannes@sipsolutions.net, ath10k@lists.infradead.org,
linux-wireless@vger.kernel.org
In-Reply-To: <1560835632-17405-2-git-send-email-tamizhr@codeaurora.org>
> Add a new NL command, NL80211_CMD_SET_TID_CONFIG to support
> data TID specific configuration. This per TID configurations
> are passed in NL80211_ATTR_TID_CONFIG which is a nested
> attribute. This patch adds support to configure per TID
> noack policy through NL80211_TID_ATTR_CONFIG_NOACK attribute.
> Data TID value for this configuration will be passed through
> NL80211_TID_ATTR_CONFIG_TID attribute. When the user-space wants
> this configuration peer specific rather than being applied for
> all the connected stations, MAC address of the peer can be passed
> in NL80211_ATTR_MAC attribute. This patch introduced
> enum ieee80211_tid_conf_mask to notify the driver that which
> configuration modified.
> Driver supporting data TID specific noack policy configuration
> should be advertise through NL80211_EXT_FEATURE_PER_TID_NOACK_CONFIG
> and supporting per STA data TID noack policy configuration
> should be advertise through NL80211_EXT_FEATURE_PER_STA_NOACK_CONFIG
>
> Signed-off-by: Tamizh chelvam <tamizhr@codeaurora.org>
...
> +static int parse_tid_conf(struct cfg80211_registered_device *rdev,
> + struct nlattr *attrs[],
> + struct ieee80211_tid_cfg *tid_conf,
> + struct genl_info *info, const u8 *peer)
> +{
...
> +static int nl80211_set_tid_config(struct sk_buff *skb,
> + struct genl_info *info)
> +{
> + struct cfg80211_registered_device *rdev = info->user_ptr[0];
> + struct nlattr *attrs[NL80211_TID_ATTR_CONFIG_MAX + 1];
> + struct net_device *dev = info->user_ptr[1];
> + struct ieee80211_tid_config *tid_config;
> + struct nlattr *tid;
> + int conf_idx = 0, rem_conf;
> + int ret = -EINVAL;
> + u32 num_conf = 0;
> +
> + if (!info->attrs[NL80211_ATTR_TID_CONFIG])
> + return -EINVAL;
> +
> + if (!rdev->ops->set_tid_config)
> + return -EOPNOTSUPP;
> +
> + nla_for_each_nested(tid, info->attrs[NL80211_ATTR_TID_CONFIG],
> + rem_conf)
> + num_conf++;
> +
> + tid_config = kzalloc(struct_size(tid_config, tid_conf, num_conf),
> + GFP_KERNEL);
> + if (!tid_config)
> + return -ENOMEM;
> +
> + tid_config->n_tid_conf = num_conf;
> +
> + if (info->attrs[NL80211_ATTR_MAC])
> + tid_config->peer = nla_data(info->attrs[NL80211_ATTR_MAC]);
> +
> + nla_for_each_nested(tid, info->attrs[NL80211_ATTR_TID_CONFIG],
> + rem_conf) {
> + ret = nla_parse_nested_deprecated(attrs, NL80211_TID_ATTR_CONFIG_MAX,
> + tid, NULL, NULL);
> +
> + if (ret)
> + goto bad_tid_conf;
> +
> + if (!attrs[NL80211_TID_ATTR_CONFIG_TID]) {
> + ret = -EINVAL;
> + goto bad_tid_conf;
> + }
> +
> + ret = parse_tid_conf(rdev, attrs,
> + &tid_config->tid_conf[conf_idx],
> + tid_config->peer);
Argument 'info' is missing here from parse_tid_conf. IIUC, appropriate
fixup is included into patch #5. So it looks like rebase issue. But it
makes sense to fix it since this issue makes the patch set non-bisectable.
Regareds,
Sergey
^ permalink raw reply
* Re: [PATCHv6 5/9] nl80211: Add netlink attribute to configure TID specific tx rate
From: Sergey Matyukevich @ 2019-07-11 12:54 UTC (permalink / raw)
To: Tamizh chelvam
Cc: johannes@sipsolutions.net, ath10k@lists.infradead.org,
linux-wireless@vger.kernel.org
In-Reply-To: <1560835632-17405-6-git-send-email-tamizhr@codeaurora.org>
> Introduce NL80211_TID_ATTR_CONFIG_TX_RATES in nl80211_tid_attr_config
> to accept data TID specific TX bitrate configuration
> through NL80211_CMD_SET_TID_CONFIG command. TID for which the
> this configuration is to be applied is passed in
> NL80211_TID_ATTR_CONFIG_TID attribute. TX bitrate mask values passed
> in NL80211_ATTR_TX_RATES attribute and NL80211_TID_ATTR_CONFIG_TX_RATES
> attribute will have types of the TX rate should be applied.
> When the user-space wants this configuration peer specific
> rather than being applied for all the connected stations,
> MAC address of the peer can be passed in NL80211_ATTR_MAC attribute.
>
> Driver supporting this feature should advertise
> NL80211_EXT_FEATURE_PER_TID_TX_BITRATE_MASK and supporting per-STA data TID
> TX bitrate configuration should advertise
> NL80211_EXT_FEATURE_PER_STA_TX_BITRATE_MASK.
>
> Signed-off-by: Tamizh chelvam <tamizhr@codeaurora.org>
...
> if (info->attrs[NL80211_ATTR_TX_RATES]) {
> - err = nl80211_parse_tx_bitrate_mask(info, ¶ms.beacon_rate);
> + err = nl80211_parse_tx_bitrate_mask(info, info->attrs,
> + NL80211_ATTR_TX_RATES,
> + ¶ms.beacon_rate);
> if (err)
> return err;
>
Could you please clarify this change of nl80211_parse_tx_bitrate_mask arguments.
Unless I missing something, the appropriate change for nl80211_parse_tx_bitrate_mask
is not included into this patch set.
Regards,
Sergey
^ permalink raw reply
* Re: [PATCHv6 1/9] nl80211: New netlink command for TID specific configuration
From: Sergey Matyukevich @ 2019-07-11 13:13 UTC (permalink / raw)
To: Tamizh chelvam
Cc: johannes@sipsolutions.net, ath10k@lists.infradead.org,
linux-wireless@vger.kernel.org
In-Reply-To: <1560835632-17405-2-git-send-email-tamizhr@codeaurora.org>
> Add a new NL command, NL80211_CMD_SET_TID_CONFIG to support
> data TID specific configuration. This per TID configurations
> are passed in NL80211_ATTR_TID_CONFIG which is a nested
> attribute. This patch adds support to configure per TID
> noack policy through NL80211_TID_ATTR_CONFIG_NOACK attribute.
> Data TID value for this configuration will be passed through
> NL80211_TID_ATTR_CONFIG_TID attribute. When the user-space wants
> this configuration peer specific rather than being applied for
> all the connected stations, MAC address of the peer can be passed
> in NL80211_ATTR_MAC attribute. This patch introduced
> enum ieee80211_tid_conf_mask to notify the driver that which
> configuration modified.
> Driver supporting data TID specific noack policy configuration
> should be advertise through NL80211_EXT_FEATURE_PER_TID_NOACK_CONFIG
> and supporting per STA data TID noack policy configuration
> should be advertise through NL80211_EXT_FEATURE_PER_STA_NOACK_CONFIG
>
> Signed-off-by: Tamizh chelvam <tamizhr@codeaurora.org>
...
> diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
> index ff760ba..4881bfb6 100644
> --- a/net/wireless/nl80211.c
> +++ b/net/wireless/nl80211.c
> @@ -281,6 +281,13 @@ static int validate_ie_attr(const struct nlattr *attr,
> NLA_POLICY_NESTED_ARRAY(nl80211_psmr_peer_attr_policy),
> };
>
> +static const struct nla_policy
> +nl80211_tid_attr_config_policy[NL80211_TID_ATTR_CONFIG_MAX + 1] = {
> + [NL80211_TID_ATTR_CONFIG_TID] = { .type = NLA_U8 },
> + [NL80211_TID_ATTR_CONFIG_NOACK] =
> + NLA_POLICY_MAX(NLA_U8, NL80211_TID_CONFIG_DISABLE),
> +};
> +
IIUC, in the current version of the patch set no specific value of
NL80211_TID_ATTR_CONFIG_TID attribute is reserved for 'apply to all tids'
command. It could be left up to drivers. But we need some convention for
userspace tools (e.g. iw) anyway.
Regards,
Sergey
^ permalink raw reply
* Re: [PATCH 00/12] treewide: Fix GENMASK misuses
From: David Miller @ 2019-07-11 21:30 UTC (permalink / raw)
To: joe
Cc: akpm, venture, yuenn, benjaminfair, andrew, openbmc, linux-kernel,
linux-aspeed, linux-arm-kernel, linux-amlogic, netdev,
linux-mediatek, linux-stm32, linux-wireless, linux-media,
dri-devel, linux-iio, linux-mmc, devel, alsa-devel
In-Reply-To: <cover.1562734889.git.joe@perches.com>
From: Joe Perches <joe@perches.com>
Date: Tue, 9 Jul 2019 22:04:13 -0700
> These GENMASK uses are inverted argument order and the
> actual masks produced are incorrect. Fix them.
>
> Add checkpatch tests to help avoid more misuses too.
Patches #7 and #8 applied to 'net', with appropriate Fixes tags
added to #8.
^ permalink raw reply
* Re: [PATCH 09/11] rtw88: remove all RTW_MAX_POWER_INDEX macro
From: Brian Norris @ 2019-07-11 22:05 UTC (permalink / raw)
To: Tony Chuang; +Cc: Kalle Valo, linux-wireless
In-Reply-To: <1559116487-5244-10-git-send-email-yhchuang@realtek.com>
I realize this is already upstream, but I thought I'd ask here, since
I was going back and reviewing some of this:
On Wed, May 29, 2019 at 12:55 AM <yhchuang@realtek.com> wrote:
>
> From: Tzu-En Huang <tehuang@realtek.com>
>
> Since this macro definition has different values in different chipset,
> the current defined macro value is for 8822b. This will cause the
> settings of 8822c be incorrect.
^^ Is this actually correct, that 8822b was correct and 8822c was
wrong? Because I see RTW_MAX_POWER_INDEX used to be defined as 0x7f,
and rtw8822c_hw_spec.max_power_index also appears to be 0x7f. Which
would sound like 8822b (*b*, not c) was wrong, as it lists 0x3f.
Anyway, I'm going to assume you got the change right, and you just
mis-spoke in the description.
Regards,
Brian
> Remove RTW_MAX_POWER_INDEX and use max_power_index in struct rtw_chip_info
> to make sure the value of different chipset is right.
>
> Signed-off-by: Tzu-En Huang <tehuang@realtek.com>
> Signed-off-by: Yan-Hsuan Chuang <yhchuang@realtek.com>
^ permalink raw reply
* [PATCH -next] iwlwifi: dbg: work around clang bug by marking debug strings static
From: Nick Desaulniers @ 2019-07-12 0:17 UTC (permalink / raw)
To: kvalo
Cc: Nick Desaulniers, Arnd Bergmann, Nathan Chancellor, Johannes Berg,
Emmanuel Grumbach, Luca Coelho, Intel Linux Wireless,
David S. Miller, Shahar S Matityahu, Sara Sharon, linux-wireless,
netdev, linux-kernel, clang-built-linux
Commit r353569 in prerelease Clang-9 is producing a linkage failure:
ld: drivers/net/wireless/intel/iwlwifi/fw/dbg.o:
in function `_iwl_fw_dbg_apply_point':
dbg.c:(.text+0x827a): undefined reference to `__compiletime_assert_2387'
when the following configs are enabled:
- CONFIG_IWLWIFI
- CONFIG_IWLMVM
- CONFIG_KASAN
Work around the issue for now by marking the debug strings as `static`,
which they probably should be any ways.
Link: https://bugs.llvm.org/show_bug.cgi?id=42580
Link: https://github.com/ClangBuiltLinux/linux/issues/580
Reported-by: Arnd Bergmann <arnd@arndb.de>
Reported-by: Nathan Chancellor <natechancellor@gmail.com>
Signed-off-by: Nick Desaulniers <ndesaulniers@google.com>
---
drivers/net/wireless/intel/iwlwifi/fw/dbg.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c
index e411ac98290d..f8c90ea4e9b4 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c
+++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c
@@ -2438,7 +2438,7 @@ static void iwl_fw_dbg_info_apply(struct iwl_fw_runtime *fwrt,
{
u32 img_name_len = le32_to_cpu(dbg_info->img_name_len);
u32 dbg_cfg_name_len = le32_to_cpu(dbg_info->dbg_cfg_name_len);
- const char err_str[] =
+ static const char err_str[] =
"WRT: ext=%d. Invalid %s name length %d, expected %d\n";
if (img_name_len != IWL_FW_INI_MAX_IMG_NAME_LEN) {
@@ -2775,7 +2775,7 @@ static void _iwl_fw_dbg_apply_point(struct iwl_fw_runtime *fwrt,
struct iwl_ucode_tlv *tlv = iter;
void *ini_tlv = (void *)tlv->data;
u32 type = le32_to_cpu(tlv->type);
- const char invalid_ap_str[] =
+ static const char invalid_ap_str[] =
"WRT: ext=%d. Invalid apply point %d for %s\n";
switch (type) {
--
2.22.0.410.gd8fdbe21b5-goog
^ permalink raw reply related
* Re: [PATCH -next] iwlwifi: dbg: work around clang bug by marking debug strings static
From: Nick Desaulniers @ 2019-07-12 0:18 UTC (permalink / raw)
To: Kalle Valo
Cc: Arnd Bergmann, Nathan Chancellor, Johannes Berg,
Emmanuel Grumbach, Luca Coelho, Intel Linux Wireless,
David S. Miller, Shahar S Matityahu, Sara Sharon, linux-wireless,
netdev, LKML, clang-built-linux
In-Reply-To: <20190712001708.170259-1-ndesaulniers@google.com>
On Thu, Jul 11, 2019 at 5:17 PM Nick Desaulniers
<ndesaulniers@google.com> wrote:
>
> Commit r353569 in prerelease Clang-9 is producing a linkage failure:
>
> ld: drivers/net/wireless/intel/iwlwifi/fw/dbg.o:
> in function `_iwl_fw_dbg_apply_point':
> dbg.c:(.text+0x827a): undefined reference to `__compiletime_assert_2387'
>
> when the following configs are enabled:
> - CONFIG_IWLWIFI
> - CONFIG_IWLMVM
> - CONFIG_KASAN
>
> Work around the issue for now by marking the debug strings as `static`,
> which they probably should be any ways.
>
> Link: https://bugs.llvm.org/show_bug.cgi?id=42580
> Link: https://github.com/ClangBuiltLinux/linux/issues/580
> Reported-by: Arnd Bergmann <arnd@arndb.de>
> Reported-by: Nathan Chancellor <natechancellor@gmail.com>
> Signed-off-by: Nick Desaulniers <ndesaulniers@google.com>
Sorry, I forgot a very important:
Suggested-by: Eli Friedman <efriedma@quicinc.com>
> ---
> drivers/net/wireless/intel/iwlwifi/fw/dbg.c | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c
> index e411ac98290d..f8c90ea4e9b4 100644
> --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c
> +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c
> @@ -2438,7 +2438,7 @@ static void iwl_fw_dbg_info_apply(struct iwl_fw_runtime *fwrt,
> {
> u32 img_name_len = le32_to_cpu(dbg_info->img_name_len);
> u32 dbg_cfg_name_len = le32_to_cpu(dbg_info->dbg_cfg_name_len);
> - const char err_str[] =
> + static const char err_str[] =
> "WRT: ext=%d. Invalid %s name length %d, expected %d\n";
>
> if (img_name_len != IWL_FW_INI_MAX_IMG_NAME_LEN) {
> @@ -2775,7 +2775,7 @@ static void _iwl_fw_dbg_apply_point(struct iwl_fw_runtime *fwrt,
> struct iwl_ucode_tlv *tlv = iter;
> void *ini_tlv = (void *)tlv->data;
> u32 type = le32_to_cpu(tlv->type);
> - const char invalid_ap_str[] =
> + static const char invalid_ap_str[] =
> "WRT: ext=%d. Invalid apply point %d for %s\n";
>
> switch (type) {
> --
> 2.22.0.410.gd8fdbe21b5-goog
>
--
Thanks,
~Nick Desaulniers
^ permalink raw reply
* Re: [PATCH -next] iwlwifi: dbg: work around clang bug by marking debug strings static
From: Nathan Chancellor @ 2019-07-12 0:28 UTC (permalink / raw)
To: Nick Desaulniers
Cc: kvalo, Arnd Bergmann, Johannes Berg, Emmanuel Grumbach,
Luca Coelho, Intel Linux Wireless, David S. Miller,
Shahar S Matityahu, Sara Sharon, linux-wireless, netdev,
linux-kernel, clang-built-linux
In-Reply-To: <20190712001708.170259-1-ndesaulniers@google.com>
On Thu, Jul 11, 2019 at 05:17:06PM -0700, Nick Desaulniers wrote:
> Commit r353569 in prerelease Clang-9 is producing a linkage failure:
>
> ld: drivers/net/wireless/intel/iwlwifi/fw/dbg.o:
> in function `_iwl_fw_dbg_apply_point':
> dbg.c:(.text+0x827a): undefined reference to `__compiletime_assert_2387'
>
> when the following configs are enabled:
> - CONFIG_IWLWIFI
> - CONFIG_IWLMVM
> - CONFIG_KASAN
>
> Work around the issue for now by marking the debug strings as `static`,
> which they probably should be any ways.
>
> Link: https://bugs.llvm.org/show_bug.cgi?id=42580
> Link: https://github.com/ClangBuiltLinux/linux/issues/580
> Reported-by: Arnd Bergmann <arnd@arndb.de>
> Reported-by: Nathan Chancellor <natechancellor@gmail.com>
> Signed-off-by: Nick Desaulniers <ndesaulniers@google.com>
Applied on next-20190711 and I can confirm that this fixes the issue we
observed. Thanks to you for wrapping up the patch and sending it and to
Eli for giving the suggestion.
Reviewed-by: Nathan Chancellor <natechancellor@gmail.com>
Tested-by: Nathan Chancellor <natechancellor@gmail.com>
^ permalink raw reply
* [PATCH v2 00/16] wilc1000: move out of staging
From: Ajay.Kathat @ 2019-07-12 1:58 UTC (permalink / raw)
To: linux-wireless
Cc: gregkh, kvalo, johannes, Adham.Abozaeid, Venkateswara.Kaja,
Nicolas.Ferre, Claudiu.Beznea, Ajay.Kathat
From: Ajay Singh <ajay.kathat@microchip.com>
This patch series is to review and move wilc1000 driver out of staging.
Implemented the initial received review comments[1] and submitting the
driver again. During this cleanup deleted around 3.3k lines of code.
Below are the major items fixed in recent cleanup:
- remove use of shadow buffer to keep scan result.
- remove internal messaging flow to handle cfg80211_ops.
- make use of cfg80211 provided API.
- use structure for packing firmware commands.
- make use of kernel provided API and macros.
- remove unnecessary logs messages.
Please review and provide your inputs on pending items to mainline
this driver.
[1]. https://www.spinics.net/lists/linux-wireless/msg177877.html
Changes since v1:
- supported dynamically add/remove interfaces.
- included the latest code from staging.
Ajay Singh (16):
wilc1000: add wilc_hif.h
wilc1000: add wilc_hif.c
wilc1000: add wilc_wlan_if.h
wilc1000: add wilc_wlan_cfg.h
wilc1000: add wilc_wlan_cfg.c
wilc1000: add wilc_wfi_netdevice.h
wilc1000: add wilc_wfi_cfgoperations.h
wilc1000: add wilc_wfi_cfgoperations.c
wilc1000: add wilc_netdev.c
wilc1000: add wilc_mon.c
wilc1000: add wilc_spi.c
wilc1000: add wilc_wlan.c
wilc1000: add wilc_wlan.h
wilc1000: add wilc_sdio.c
wilc1000: updated DT device binding for wilc1000 device
wilc1000: add Makefile and Kconfig files for wilc1000 compilation
.../net/wireless}/microchip,wilc1000,sdio.txt | 0
.../net/wireless}/microchip,wilc1000,spi.txt | 0
drivers/net/wireless/Kconfig | 1 +
drivers/net/wireless/Makefile | 1 +
drivers/net/wireless/microchip/Kconfig | 15 +
drivers/net/wireless/microchip/Makefile | 2 +
drivers/net/wireless/microchip/wilc1000/Kconfig | 42 +
drivers/net/wireless/microchip/wilc1000/Makefile | 14 +
drivers/net/wireless/microchip/wilc1000/wilc_hif.c | 2089 ++++++++++++++++++++
drivers/net/wireless/microchip/wilc1000/wilc_hif.h | 235 +++
drivers/net/wireless/microchip/wilc1000/wilc_mon.c | 261 +++
.../net/wireless/microchip/wilc1000/wilc_netdev.c | 997 ++++++++++
.../net/wireless/microchip/wilc1000/wilc_sdio.c | 1139 +++++++++++
drivers/net/wireless/microchip/wilc1000/wilc_spi.c | 1134 +++++++++++
.../microchip/wilc1000/wilc_wfi_cfgoperations.c | 1980 +++++++++++++++++++
.../microchip/wilc1000/wilc_wfi_cfgoperations.h | 27 +
.../microchip/wilc1000/wilc_wfi_netdevice.h | 294 +++
.../net/wireless/microchip/wilc1000/wilc_wlan.c | 1354 +++++++++++++
.../net/wireless/microchip/wilc1000/wilc_wlan.h | 313 +++
.../wireless/microchip/wilc1000/wilc_wlan_cfg.c | 495 +++++
.../wireless/microchip/wilc1000/wilc_wlan_cfg.h | 54 +
.../net/wireless/microchip/wilc1000/wilc_wlan_if.h | 803 ++++++++
drivers/staging/Kconfig | 2 -
drivers/staging/Makefile | 1 -
24 files changed, 11250 insertions(+), 3 deletions(-)
rename {drivers/staging/wilc1000 => Documentation/devicetree/bindings/net/wireless}/microchip,wilc1000,sdio.txt (100%)
rename {drivers/staging/wilc1000 => Documentation/devicetree/bindings/net/wireless}/microchip,wilc1000,spi.txt (100%)
create mode 100644 drivers/net/wireless/microchip/Kconfig
create mode 100644 drivers/net/wireless/microchip/Makefile
create mode 100644 drivers/net/wireless/microchip/wilc1000/Kconfig
create mode 100644 drivers/net/wireless/microchip/wilc1000/Makefile
create mode 100644 drivers/net/wireless/microchip/wilc1000/wilc_hif.c
create mode 100644 drivers/net/wireless/microchip/wilc1000/wilc_hif.h
create mode 100644 drivers/net/wireless/microchip/wilc1000/wilc_mon.c
create mode 100644 drivers/net/wireless/microchip/wilc1000/wilc_netdev.c
create mode 100644 drivers/net/wireless/microchip/wilc1000/wilc_sdio.c
create mode 100644 drivers/net/wireless/microchip/wilc1000/wilc_spi.c
create mode 100644 drivers/net/wireless/microchip/wilc1000/wilc_wfi_cfgoperations.c
create mode 100644 drivers/net/wireless/microchip/wilc1000/wilc_wfi_cfgoperations.h
create mode 100644 drivers/net/wireless/microchip/wilc1000/wilc_wfi_netdevice.h
create mode 100644 drivers/net/wireless/microchip/wilc1000/wilc_wlan.c
create mode 100644 drivers/net/wireless/microchip/wilc1000/wilc_wlan.h
create mode 100644 drivers/net/wireless/microchip/wilc1000/wilc_wlan_cfg.c
create mode 100644 drivers/net/wireless/microchip/wilc1000/wilc_wlan_cfg.h
create mode 100644 drivers/net/wireless/microchip/wilc1000/wilc_wlan_if.h
--
2.7.4
^ permalink raw reply
* [PATCH v2 01/16] wilc1000: add wilc_hif.h
From: Ajay.Kathat @ 2019-07-12 1:58 UTC (permalink / raw)
To: linux-wireless
Cc: gregkh, kvalo, johannes, Adham.Abozaeid, Venkateswara.Kaja,
Nicolas.Ferre, Claudiu.Beznea, Ajay.Kathat
In-Reply-To: <1562896697-8002-1-git-send-email-ajay.kathat@microchip.com>
From: Ajay Singh <ajay.kathat@microchip.com>
Moved '/driver/staging/wilc1000/wilc_hif.h' to
'/driver/net/wireless/mirochip/wilc1000/wilc_hif.h'.
Signed-off-by: Ajay Singh <ajay.kathat@microchip.com>
---
drivers/net/wireless/microchip/wilc1000/wilc_hif.h | 235 +++++++++++++++++++++
1 file changed, 235 insertions(+)
create mode 100644 drivers/net/wireless/microchip/wilc1000/wilc_hif.h
diff --git a/drivers/net/wireless/microchip/wilc1000/wilc_hif.h b/drivers/net/wireless/microchip/wilc1000/wilc_hif.h
new file mode 100644
index 0000000..be1d249
--- /dev/null
+++ b/drivers/net/wireless/microchip/wilc1000/wilc_hif.h
@@ -0,0 +1,235 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries
+ * All rights reserved.
+ */
+
+#ifndef HOST_INT_H
+#define HOST_INT_H
+#include <linux/ieee80211.h>
+#include "wilc_wlan_if.h"
+
+enum {
+ WILC_IDLE_MODE = 0x0,
+ WILC_AP_MODE = 0x1,
+ WILC_STATION_MODE = 0x2,
+ WILC_GO_MODE = 0x3,
+ WILC_CLIENT_MODE = 0x4
+};
+
+#define WILC_MAX_NUM_STA 9
+#define WILC_MAX_NUM_SCANNED_CH 14
+#define WILC_MAX_NUM_PROBED_SSID 10
+
+#define WILC_TX_MIC_KEY_LEN 8
+#define WILC_RX_MIC_KEY_LEN 8
+
+#define WILC_MAX_NUM_PMKIDS 16
+#define WILC_ADD_STA_LENGTH 40
+#define WILC_NUM_CONCURRENT_IFC 2
+
+enum {
+ WILC_SET_CFG = 0,
+ WILC_GET_CFG
+};
+
+#define WILC_MAX_ASSOC_RESP_FRAME_SIZE 256
+
+struct assoc_resp {
+ __le16 capab_info;
+ __le16 status_code;
+ __le16 aid;
+} __packed;
+
+struct rf_info {
+ u8 link_speed;
+ s8 rssi;
+ u32 tx_cnt;
+ u32 rx_cnt;
+ u32 tx_fail_cnt;
+};
+
+enum host_if_state {
+ HOST_IF_IDLE = 0,
+ HOST_IF_SCANNING = 1,
+ HOST_IF_CONNECTING = 2,
+ HOST_IF_WAITING_CONN_RESP = 3,
+ HOST_IF_CONNECTED = 4,
+ HOST_IF_P2P_LISTEN = 5,
+ HOST_IF_FORCE_32BIT = 0xFFFFFFFF
+};
+
+struct wilc_pmkid {
+ u8 bssid[ETH_ALEN];
+ u8 pmkid[WLAN_PMKID_LEN];
+} __packed;
+
+struct wilc_pmkid_attr {
+ u8 numpmkid;
+ struct wilc_pmkid pmkidlist[WILC_MAX_NUM_PMKIDS];
+} __packed;
+
+struct cfg_param_attr {
+ u32 flag;
+ u16 short_retry_limit;
+ u16 long_retry_limit;
+ u16 frag_threshold;
+ u16 rts_threshold;
+};
+
+enum cfg_param {
+ WILC_CFG_PARAM_RETRY_SHORT = BIT(0),
+ WILC_CFG_PARAM_RETRY_LONG = BIT(1),
+ WILC_CFG_PARAM_FRAG_THRESHOLD = BIT(2),
+ WILC_CFG_PARAM_RTS_THRESHOLD = BIT(3)
+};
+
+enum scan_event {
+ SCAN_EVENT_NETWORK_FOUND = 0,
+ SCAN_EVENT_DONE = 1,
+ SCAN_EVENT_ABORTED = 2,
+ SCAN_EVENT_FORCE_32BIT = 0xFFFFFFFF
+};
+
+enum conn_event {
+ CONN_DISCONN_EVENT_CONN_RESP = 0,
+ CONN_DISCONN_EVENT_DISCONN_NOTIF = 1,
+ CONN_DISCONN_EVENT_FORCE_32BIT = 0xFFFFFFFF
+};
+
+enum {
+ WILC_HIF_SDIO = 0,
+ WILC_HIF_SPI = BIT(0)
+};
+
+enum {
+ WILC_MAC_STATUS_INIT = -1,
+ WILC_MAC_STATUS_DISCONNECTED = 0,
+ WILC_MAC_STATUS_CONNECTED = 1
+};
+
+struct wilc_rcvd_net_info {
+ s8 rssi;
+ u8 ch;
+ u16 frame_len;
+ struct ieee80211_mgmt *mgmt;
+};
+
+struct wilc_user_scan_req {
+ void (*scan_result)(enum scan_event evt,
+ struct wilc_rcvd_net_info *info, void *priv);
+ void *arg;
+ u32 ch_cnt;
+};
+
+struct wilc_conn_info {
+ u8 bssid[ETH_ALEN];
+ u8 security;
+ enum authtype auth_type;
+ u8 ch;
+ u8 *req_ies;
+ size_t req_ies_len;
+ u8 *resp_ies;
+ u16 resp_ies_len;
+ u16 status;
+ void (*conn_result)(enum conn_event evt, u8 status, void *priv_data);
+ void *arg;
+ void *param;
+};
+
+struct wilc_remain_ch {
+ u16 ch;
+ u32 duration;
+ void (*expired)(void *priv, u64 cookie);
+ void *arg;
+ u32 cookie;
+};
+
+struct wilc;
+struct host_if_drv {
+ struct wilc_user_scan_req usr_scan_req;
+ struct wilc_conn_info conn_info;
+ struct wilc_remain_ch remain_on_ch;
+ u64 p2p_timeout;
+
+ enum host_if_state hif_state;
+
+ u8 assoc_bssid[ETH_ALEN];
+
+ struct timer_list scan_timer;
+ struct wilc_vif *scan_timer_vif;
+
+ struct timer_list connect_timer;
+ struct wilc_vif *connect_timer_vif;
+
+ struct timer_list remain_on_ch_timer;
+ struct wilc_vif *remain_on_ch_timer_vif;
+
+ bool ifc_up;
+ u8 assoc_resp[WILC_MAX_ASSOC_RESP_FRAME_SIZE];
+};
+
+struct wilc_vif;
+int wilc_remove_wep_key(struct wilc_vif *vif, u8 index);
+int wilc_set_wep_default_keyid(struct wilc_vif *vif, u8 index);
+int wilc_add_wep_key_bss_sta(struct wilc_vif *vif, const u8 *key, u8 len,
+ u8 index);
+int wilc_add_wep_key_bss_ap(struct wilc_vif *vif, const u8 *key, u8 len,
+ u8 index, u8 mode, enum authtype auth_type);
+int wilc_add_ptk(struct wilc_vif *vif, const u8 *ptk, u8 ptk_key_len,
+ const u8 *mac_addr, const u8 *rx_mic, const u8 *tx_mic,
+ u8 mode, u8 cipher_mode, u8 index);
+s32 wilc_get_inactive_time(struct wilc_vif *vif, const u8 *mac,
+ u32 *out_val);
+int wilc_add_rx_gtk(struct wilc_vif *vif, const u8 *rx_gtk, u8 gtk_key_len,
+ u8 index, u32 key_rsc_len, const u8 *key_rsc,
+ const u8 *rx_mic, const u8 *tx_mic, u8 mode,
+ u8 cipher_mode);
+int wilc_set_pmkid_info(struct wilc_vif *vif, struct wilc_pmkid_attr *pmkid);
+int wilc_get_mac_address(struct wilc_vif *vif, u8 *mac_addr);
+int wilc_set_join_req(struct wilc_vif *vif, u8 *bssid, const u8 *ies,
+ size_t ies_len);
+int wilc_disconnect(struct wilc_vif *vif);
+int wilc_set_mac_chnl_num(struct wilc_vif *vif, u8 channel);
+int wilc_get_rssi(struct wilc_vif *vif, s8 *rssi_level);
+int wilc_scan(struct wilc_vif *vif, u8 scan_source, u8 scan_type,
+ u8 *ch_freq_list, u8 ch_list_len,
+ void (*scan_result_fn)(enum scan_event,
+ struct wilc_rcvd_net_info *, void *),
+ void *user_arg, struct cfg80211_scan_request *request);
+int wilc_hif_set_cfg(struct wilc_vif *vif,
+ struct cfg_param_attr *cfg_param);
+int wilc_init(struct net_device *dev, struct host_if_drv **hif_drv_handler);
+int wilc_deinit(struct wilc_vif *vif);
+int wilc_add_beacon(struct wilc_vif *vif, u32 interval, u32 dtim_period,
+ struct cfg80211_beacon_data *params);
+int wilc_del_beacon(struct wilc_vif *vif);
+int wilc_add_station(struct wilc_vif *vif, const u8 *mac,
+ struct station_parameters *params);
+int wilc_del_allstation(struct wilc_vif *vif, u8 mac_addr[][ETH_ALEN]);
+int wilc_del_station(struct wilc_vif *vif, const u8 *mac_addr);
+int wilc_edit_station(struct wilc_vif *vif, const u8 *mac,
+ struct station_parameters *params);
+int wilc_set_power_mgmt(struct wilc_vif *vif, bool enabled, u32 timeout);
+int wilc_setup_multicast_filter(struct wilc_vif *vif, u32 enabled, u32 count,
+ u8 *mc_list);
+int wilc_remain_on_channel(struct wilc_vif *vif, u64 cookie,
+ u32 duration, u16 chan,
+ void (*expired)(void *, u64),
+ void *user_arg);
+int wilc_listen_state_expired(struct wilc_vif *vif, u64 cookie);
+void wilc_frame_register(struct wilc_vif *vif, u16 frame_type, bool reg);
+int wilc_set_wfi_drv_handler(struct wilc_vif *vif, int index, u8 mode,
+ u8 ifc_id);
+int wilc_set_operation_mode(struct wilc_vif *vif, u32 mode);
+int wilc_get_statistics(struct wilc_vif *vif, struct rf_info *stats);
+void wilc_resolve_disconnect_aberration(struct wilc_vif *vif);
+int wilc_get_vif_idx(struct wilc_vif *vif);
+int wilc_set_tx_power(struct wilc_vif *vif, u8 tx_power);
+int wilc_get_tx_power(struct wilc_vif *vif, u8 *tx_power);
+void wilc_scan_complete_received(struct wilc *wilc, u8 *buffer, u32 length);
+void wilc_network_info_received(struct wilc *wilc, u8 *buffer, u32 length);
+void wilc_gnrl_async_info_received(struct wilc *wilc, u8 *buffer, u32 length);
+void *wilc_parse_join_bss_param(struct cfg80211_bss *bss,
+ struct cfg80211_crypto_settings *crypto);
+#endif
--
2.7.4
^ permalink raw reply related
* [PATCH v2 02/16] wilc1000: add wilc_hif.c
From: Ajay.Kathat @ 2019-07-12 1:58 UTC (permalink / raw)
To: linux-wireless
Cc: gregkh, kvalo, johannes, Adham.Abozaeid, Venkateswara.Kaja,
Nicolas.Ferre, Claudiu.Beznea, Ajay.Kathat
In-Reply-To: <1562896697-8002-1-git-send-email-ajay.kathat@microchip.com>
From: Ajay Singh <ajay.kathat@microchip.com>
Moved '/driver/staging/wilc1000/wilc_hif.c' to
'/drivers/net/wireless/microchip/wilc1000/wilc_hif.c'.
Signed-off-by: Ajay Singh <ajay.kathat@microchip.com>
---
drivers/net/wireless/microchip/wilc1000/wilc_hif.c | 2089 ++++++++++++++++++++
1 file changed, 2089 insertions(+)
create mode 100644 drivers/net/wireless/microchip/wilc1000/wilc_hif.c
diff --git a/drivers/net/wireless/microchip/wilc1000/wilc_hif.c b/drivers/net/wireless/microchip/wilc1000/wilc_hif.c
new file mode 100644
index 0000000..9345cab
--- /dev/null
+++ b/drivers/net/wireless/microchip/wilc1000/wilc_hif.c
@@ -0,0 +1,2089 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries.
+ * All rights reserved.
+ */
+
+#include "wilc_wfi_netdevice.h"
+
+#define WILC_HIF_SCAN_TIMEOUT_MS 5000
+#define WILC_HIF_CONNECT_TIMEOUT_MS 9500
+
+#define WILC_FALSE_FRMWR_CHANNEL 100
+#define WILC_MAX_RATES_SUPPORTED 12
+
+struct wilc_rcvd_mac_info {
+ u8 status;
+};
+
+struct wilc_set_multicast {
+ u32 enabled;
+ u32 cnt;
+ u8 *mc_list;
+};
+
+struct wilc_del_all_sta {
+ u8 assoc_sta;
+ u8 mac[WILC_MAX_NUM_STA][ETH_ALEN];
+};
+
+struct wilc_op_mode {
+ __le32 mode;
+};
+
+struct wilc_reg_frame {
+ bool reg;
+ u8 reg_id;
+ __le16 frame_type;
+} __packed;
+
+struct wilc_drv_handler {
+ __le32 handler;
+ u8 mode;
+} __packed;
+
+struct wilc_wep_key {
+ u8 index;
+ u8 key_len;
+ u8 key[0];
+} __packed;
+
+struct wilc_sta_wpa_ptk {
+ u8 mac_addr[ETH_ALEN];
+ u8 key_len;
+ u8 key[0];
+} __packed;
+
+struct wilc_ap_wpa_ptk {
+ u8 mac_addr[ETH_ALEN];
+ u8 index;
+ u8 key_len;
+ u8 key[0];
+} __packed;
+
+struct wilc_gtk_key {
+ u8 mac_addr[ETH_ALEN];
+ u8 rsc[8];
+ u8 index;
+ u8 key_len;
+ u8 key[0];
+} __packed;
+
+union wilc_message_body {
+ struct wilc_rcvd_net_info net_info;
+ struct wilc_rcvd_mac_info mac_info;
+ struct wilc_set_multicast mc_info;
+ struct wilc_remain_ch remain_on_ch;
+ char *data;
+};
+
+struct host_if_msg {
+ union wilc_message_body body;
+ struct wilc_vif *vif;
+ struct work_struct work;
+ void (*fn)(struct work_struct *ws);
+ struct completion work_comp;
+ bool is_sync;
+};
+
+struct wilc_noa_opp_enable {
+ u8 ct_window;
+ u8 cnt;
+ __le32 duration;
+ __le32 interval;
+ __le32 start_time;
+} __packed;
+
+struct wilc_noa_opp_disable {
+ u8 cnt;
+ __le32 duration;
+ __le32 interval;
+ __le32 start_time;
+} __packed;
+
+struct wilc_join_bss_param {
+ char ssid[IEEE80211_MAX_SSID_LEN];
+ u8 ssid_terminator;
+ u8 bss_type;
+ u8 ch;
+ __le16 cap_info;
+ u8 sa[ETH_ALEN];
+ u8 bssid[ETH_ALEN];
+ __le16 beacon_period;
+ u8 dtim_period;
+ u8 supp_rates[WILC_MAX_RATES_SUPPORTED + 1];
+ u8 wmm_cap;
+ u8 uapsd_cap;
+ u8 ht_capable;
+ u8 rsn_found;
+ u8 rsn_grp_policy;
+ u8 mode_802_11i;
+ u8 p_suites[3];
+ u8 akm_suites[3];
+ u8 rsn_cap[2];
+ u8 noa_enabled;
+ __le32 tsf_lo;
+ u8 idx;
+ u8 opp_enabled;
+ union {
+ struct wilc_noa_opp_disable opp_dis;
+ struct wilc_noa_opp_enable opp_en;
+ };
+} __packed;
+
+/* 'msg' should be free by the caller for syc */
+static struct host_if_msg*
+wilc_alloc_work(struct wilc_vif *vif, void (*work_fun)(struct work_struct *),
+ bool is_sync)
+{
+ struct host_if_msg *msg;
+
+ if (!work_fun)
+ return ERR_PTR(-EINVAL);
+
+ msg = kzalloc(sizeof(*msg), GFP_ATOMIC);
+ if (!msg)
+ return ERR_PTR(-ENOMEM);
+ msg->fn = work_fun;
+ msg->vif = vif;
+ msg->is_sync = is_sync;
+ if (is_sync)
+ init_completion(&msg->work_comp);
+
+ return msg;
+}
+
+static int wilc_enqueue_work(struct host_if_msg *msg)
+{
+ INIT_WORK(&msg->work, msg->fn);
+
+ if (!msg->vif || !msg->vif->wilc || !msg->vif->wilc->hif_workqueue)
+ return -EINVAL;
+
+ if (!queue_work(msg->vif->wilc->hif_workqueue, &msg->work))
+ return -EINVAL;
+
+ return 0;
+}
+
+/* The idx starts from 0 to (NUM_CONCURRENT_IFC - 1), but 0 index used as
+ * special purpose in wilc device, so we add 1 to the index to starts from 1.
+ * As a result, the returned index will be 1 to NUM_CONCURRENT_IFC.
+ */
+int wilc_get_vif_idx(struct wilc_vif *vif)
+{
+ return vif->idx + 1;
+}
+
+/* We need to minus 1 from idx which is from wilc device to get real index
+ * of wilc->vif[], because we add 1 when pass to wilc device in the function
+ * wilc_get_vif_idx.
+ * As a result, the index should be between 0 and (NUM_CONCURRENT_IFC - 1).
+ */
+static struct wilc_vif *wilc_get_vif_from_idx(struct wilc *wilc, int idx)
+{
+ int index = idx - 1;
+
+ if (index < 0 || index >= WILC_NUM_CONCURRENT_IFC)
+ return NULL;
+
+ return wilc->vif[index];
+}
+
+static int handle_scan_done(struct wilc_vif *vif, enum scan_event evt)
+{
+ int result = 0;
+ u8 abort_running_scan;
+ struct wid wid;
+ struct host_if_drv *hif_drv = vif->hif_drv;
+ struct wilc_user_scan_req *scan_req;
+
+ if (evt == SCAN_EVENT_ABORTED) {
+ abort_running_scan = 1;
+ wid.id = WID_ABORT_RUNNING_SCAN;
+ wid.type = WID_CHAR;
+ wid.val = (s8 *)&abort_running_scan;
+ wid.size = sizeof(char);
+
+ result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
+ if (result) {
+ netdev_err(vif->ndev, "Failed to set abort running\n");
+ result = -EFAULT;
+ }
+ }
+
+ if (!hif_drv) {
+ netdev_err(vif->ndev, "%s: hif driver is NULL\n", __func__);
+ return result;
+ }
+
+ scan_req = &hif_drv->usr_scan_req;
+ if (scan_req->scan_result) {
+ scan_req->scan_result(evt, NULL, scan_req->arg);
+ scan_req->scan_result = NULL;
+ }
+
+ return result;
+}
+
+int wilc_scan(struct wilc_vif *vif, u8 scan_source, u8 scan_type,
+ u8 *ch_freq_list, u8 ch_list_len,
+ void (*scan_result_fn)(enum scan_event,
+ struct wilc_rcvd_net_info *, void *),
+ void *user_arg, struct cfg80211_scan_request *request)
+{
+ int result = 0;
+ struct wid wid_list[5];
+ u32 index = 0;
+ u32 i, scan_timeout;
+ u8 *buffer;
+ u8 valuesize = 0;
+ u8 *search_ssid_vals = NULL;
+ struct host_if_drv *hif_drv = vif->hif_drv;
+
+ if (hif_drv->hif_state >= HOST_IF_SCANNING &&
+ hif_drv->hif_state < HOST_IF_CONNECTED) {
+ netdev_err(vif->ndev, "Already scan\n");
+ result = -EBUSY;
+ goto error;
+ }
+
+ if (vif->obtaining_ip || vif->connecting) {
+ netdev_err(vif->ndev, "Don't do obss scan\n");
+ result = -EBUSY;
+ goto error;
+ }
+
+ hif_drv->usr_scan_req.ch_cnt = 0;
+
+ if (request->n_ssids) {
+ for (i = 0; i < request->n_ssids; i++)
+ valuesize += ((request->ssids[i].ssid_len) + 1);
+ search_ssid_vals = kmalloc(valuesize + 1, GFP_KERNEL);
+ if (search_ssid_vals) {
+ wid_list[index].id = WID_SSID_PROBE_REQ;
+ wid_list[index].type = WID_STR;
+ wid_list[index].val = search_ssid_vals;
+ buffer = wid_list[index].val;
+
+ *buffer++ = request->n_ssids;
+
+ for (i = 0; i < request->n_ssids; i++) {
+ *buffer++ = request->ssids[i].ssid_len;
+ memcpy(buffer, request->ssids[i].ssid,
+ request->ssids[i].ssid_len);
+ buffer += request->ssids[i].ssid_len;
+ }
+ wid_list[index].size = (s32)(valuesize + 1);
+ index++;
+ }
+ }
+
+ wid_list[index].id = WID_INFO_ELEMENT_PROBE;
+ wid_list[index].type = WID_BIN_DATA;
+ wid_list[index].val = (s8 *)request->ie;
+ wid_list[index].size = request->ie_len;
+ index++;
+
+ wid_list[index].id = WID_SCAN_TYPE;
+ wid_list[index].type = WID_CHAR;
+ wid_list[index].size = sizeof(char);
+ wid_list[index].val = (s8 *)&scan_type;
+ index++;
+
+ if (scan_type == WILC_FW_PASSIVE_SCAN && request->duration) {
+ wid_list[index].id = WID_PASSIVE_SCAN_TIME;
+ wid_list[index].type = WID_SHORT;
+ wid_list[index].size = sizeof(u16);
+ wid_list[index].val = (s8 *)&request->duration;
+ index++;
+
+ scan_timeout = (request->duration * ch_list_len) + 500;
+ } else {
+ scan_timeout = WILC_HIF_SCAN_TIMEOUT_MS;
+ }
+
+ wid_list[index].id = WID_SCAN_CHANNEL_LIST;
+ wid_list[index].type = WID_BIN_DATA;
+
+ if (ch_freq_list && ch_list_len > 0) {
+ for (i = 0; i < ch_list_len; i++) {
+ if (ch_freq_list[i] > 0)
+ ch_freq_list[i] -= 1;
+ }
+ }
+
+ wid_list[index].val = ch_freq_list;
+ wid_list[index].size = ch_list_len;
+ index++;
+
+ wid_list[index].id = WID_START_SCAN_REQ;
+ wid_list[index].type = WID_CHAR;
+ wid_list[index].size = sizeof(char);
+ wid_list[index].val = (s8 *)&scan_source;
+ index++;
+
+ hif_drv->usr_scan_req.scan_result = scan_result_fn;
+ hif_drv->usr_scan_req.arg = user_arg;
+
+ result = wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list, index);
+ if (result) {
+ netdev_err(vif->ndev, "Failed to send scan parameters\n");
+ goto error;
+ }
+
+ hif_drv->scan_timer_vif = vif;
+ mod_timer(&hif_drv->scan_timer,
+ jiffies + msecs_to_jiffies(scan_timeout));
+
+error:
+
+ kfree(search_ssid_vals);
+
+ return result;
+}
+
+static int wilc_send_connect_wid(struct wilc_vif *vif)
+{
+ int result = 0;
+ struct wid wid_list[4];
+ u32 wid_cnt = 0;
+ struct host_if_drv *hif_drv = vif->hif_drv;
+ struct wilc_conn_info *conn_attr = &hif_drv->conn_info;
+ struct wilc_join_bss_param *bss_param = conn_attr->param;
+
+ wid_list[wid_cnt].id = WID_INFO_ELEMENT_ASSOCIATE;
+ wid_list[wid_cnt].type = WID_BIN_DATA;
+ wid_list[wid_cnt].val = conn_attr->req_ies;
+ wid_list[wid_cnt].size = conn_attr->req_ies_len;
+ wid_cnt++;
+
+ wid_list[wid_cnt].id = WID_11I_MODE;
+ wid_list[wid_cnt].type = WID_CHAR;
+ wid_list[wid_cnt].size = sizeof(char);
+ wid_list[wid_cnt].val = (s8 *)&conn_attr->security;
+ wid_cnt++;
+
+ wid_list[wid_cnt].id = WID_AUTH_TYPE;
+ wid_list[wid_cnt].type = WID_CHAR;
+ wid_list[wid_cnt].size = sizeof(char);
+ wid_list[wid_cnt].val = (s8 *)&conn_attr->auth_type;
+ wid_cnt++;
+
+ wid_list[wid_cnt].id = WID_JOIN_REQ_EXTENDED;
+ wid_list[wid_cnt].type = WID_STR;
+ wid_list[wid_cnt].size = sizeof(*bss_param);
+ wid_list[wid_cnt].val = (u8 *)bss_param;
+ wid_cnt++;
+
+ result = wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list, wid_cnt);
+ if (result) {
+ netdev_err(vif->ndev, "failed to send config packet\n");
+ goto error;
+ } else {
+ hif_drv->hif_state = HOST_IF_WAITING_CONN_RESP;
+ }
+
+ return 0;
+
+error:
+
+ kfree(conn_attr->req_ies);
+ conn_attr->req_ies = NULL;
+
+ return result;
+}
+
+static void handle_connect_timeout(struct work_struct *work)
+{
+ struct host_if_msg *msg = container_of(work, struct host_if_msg, work);
+ struct wilc_vif *vif = msg->vif;
+ int result;
+ struct wid wid;
+ u16 dummy_reason_code = 0;
+ struct host_if_drv *hif_drv = vif->hif_drv;
+
+ if (!hif_drv) {
+ netdev_err(vif->ndev, "%s: hif driver is NULL\n", __func__);
+ goto out;
+ }
+
+ hif_drv->hif_state = HOST_IF_IDLE;
+
+ if (hif_drv->conn_info.conn_result) {
+ hif_drv->conn_info.conn_result(CONN_DISCONN_EVENT_CONN_RESP,
+ WILC_MAC_STATUS_DISCONNECTED,
+ hif_drv->conn_info.arg);
+
+ } else {
+ netdev_err(vif->ndev, "%s: conn_result is NULL\n", __func__);
+ }
+
+ wid.id = WID_DISCONNECT;
+ wid.type = WID_CHAR;
+ wid.val = (s8 *)&dummy_reason_code;
+ wid.size = sizeof(char);
+
+ result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
+ if (result)
+ netdev_err(vif->ndev, "Failed to send disconnect\n");
+
+ hif_drv->conn_info.req_ies_len = 0;
+ kfree(hif_drv->conn_info.req_ies);
+ hif_drv->conn_info.req_ies = NULL;
+
+out:
+ kfree(msg);
+}
+
+void *wilc_parse_join_bss_param(struct cfg80211_bss *bss,
+ struct cfg80211_crypto_settings *crypto)
+{
+ struct wilc_join_bss_param *param;
+ struct ieee80211_p2p_noa_attr noa_attr;
+ u8 rates_len = 0;
+ const u8 *tim_elm, *ssid_elm, *rates_ie, *supp_rates_ie;
+ const u8 *ht_ie, *wpa_ie, *wmm_ie, *rsn_ie;
+ int ret;
+ const struct cfg80211_bss_ies *ies = rcu_dereference(bss->ies);
+
+ param = kzalloc(sizeof(*param), GFP_KERNEL);
+ if (!param)
+ return NULL;
+
+ param->beacon_period = cpu_to_le16(bss->beacon_interval);
+ param->cap_info = cpu_to_le16(bss->capability);
+ param->bss_type = WILC_FW_BSS_TYPE_INFRA;
+ param->ch = ieee80211_frequency_to_channel(bss->channel->center_freq);
+ ether_addr_copy(param->bssid, bss->bssid);
+
+ ssid_elm = cfg80211_find_ie(WLAN_EID_SSID, ies->data, ies->len);
+ if (ssid_elm) {
+ if (ssid_elm[1] <= IEEE80211_MAX_SSID_LEN)
+ memcpy(param->ssid, ssid_elm + 2, ssid_elm[1]);
+ }
+
+ tim_elm = cfg80211_find_ie(WLAN_EID_TIM, ies->data, ies->len);
+ if (tim_elm && tim_elm[1] >= 2)
+ param->dtim_period = tim_elm[3];
+
+ memset(param->p_suites, 0xFF, 3);
+ memset(param->akm_suites, 0xFF, 3);
+
+ rates_ie = cfg80211_find_ie(WLAN_EID_SUPP_RATES, ies->data, ies->len);
+ if (rates_ie) {
+ rates_len = rates_ie[1];
+ param->supp_rates[0] = rates_len;
+ memcpy(¶m->supp_rates[1], rates_ie + 2, rates_len);
+ }
+
+ supp_rates_ie = cfg80211_find_ie(WLAN_EID_EXT_SUPP_RATES, ies->data,
+ ies->len);
+ if (supp_rates_ie) {
+ if (supp_rates_ie[1] > (WILC_MAX_RATES_SUPPORTED - rates_len))
+ param->supp_rates[0] = WILC_MAX_RATES_SUPPORTED;
+ else
+ param->supp_rates[0] += supp_rates_ie[1];
+
+ memcpy(¶m->supp_rates[rates_len + 1], supp_rates_ie + 2,
+ (param->supp_rates[0] - rates_len));
+ }
+
+ ht_ie = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, ies->data, ies->len);
+ if (ht_ie)
+ param->ht_capable = true;
+
+ ret = cfg80211_get_p2p_attr(ies->data, ies->len,
+ IEEE80211_P2P_ATTR_ABSENCE_NOTICE,
+ (u8 *)&noa_attr, sizeof(noa_attr));
+ if (ret > 0) {
+ param->tsf_lo = cpu_to_le32(ies->tsf);
+ param->noa_enabled = 1;
+ param->idx = noa_attr.index;
+ if (noa_attr.oppps_ctwindow & IEEE80211_P2P_OPPPS_ENABLE_BIT) {
+ param->opp_enabled = 1;
+ param->opp_en.ct_window = noa_attr.oppps_ctwindow;
+ param->opp_en.cnt = noa_attr.desc[0].count;
+ param->opp_en.duration = noa_attr.desc[0].duration;
+ param->opp_en.interval = noa_attr.desc[0].interval;
+ param->opp_en.start_time = noa_attr.desc[0].start_time;
+ } else {
+ param->opp_enabled = 0;
+ param->opp_dis.cnt = noa_attr.desc[0].count;
+ param->opp_dis.duration = noa_attr.desc[0].duration;
+ param->opp_dis.interval = noa_attr.desc[0].interval;
+ param->opp_dis.start_time = noa_attr.desc[0].start_time;
+ }
+ }
+ wmm_ie = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT,
+ WLAN_OUI_TYPE_MICROSOFT_WMM,
+ ies->data, ies->len);
+ if (wmm_ie) {
+ struct ieee80211_wmm_param_ie *ie;
+
+ ie = (struct ieee80211_wmm_param_ie *)wmm_ie;
+ if ((ie->oui_subtype == 0 || ie->oui_subtype == 1) &&
+ ie->version == 1) {
+ param->wmm_cap = true;
+ if (ie->qos_info & BIT(7))
+ param->uapsd_cap = true;
+ }
+ }
+
+ wpa_ie = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT,
+ WLAN_OUI_TYPE_MICROSOFT_WPA,
+ ies->data, ies->len);
+ if (wpa_ie) {
+ param->mode_802_11i = 1;
+ param->rsn_found = true;
+ }
+
+ rsn_ie = cfg80211_find_ie(WLAN_EID_RSN, ies->data, ies->len);
+ if (rsn_ie) {
+ int offset = 8;
+
+ param->mode_802_11i = 2;
+ param->rsn_found = true;
+ //extract RSN capabilities
+ offset += (rsn_ie[offset] * 4) + 2;
+ offset += (rsn_ie[offset] * 4) + 2;
+ memcpy(param->rsn_cap, &rsn_ie[offset], 2);
+ }
+
+ if (param->rsn_found) {
+ int i;
+
+ param->rsn_grp_policy = crypto->cipher_group & 0xFF;
+ for (i = 0; i < crypto->n_ciphers_pairwise && i < 3; i++)
+ param->p_suites[i] = crypto->ciphers_pairwise[i] & 0xFF;
+
+ for (i = 0; i < crypto->n_akm_suites && i < 3; i++)
+ param->akm_suites[i] = crypto->akm_suites[i] & 0xFF;
+ }
+
+ return (void *)param;
+}
+
+static void handle_rcvd_ntwrk_info(struct work_struct *work)
+{
+ struct host_if_msg *msg = container_of(work, struct host_if_msg, work);
+ struct wilc_rcvd_net_info *rcvd_info = &msg->body.net_info;
+ struct wilc_user_scan_req *scan_req = &msg->vif->hif_drv->usr_scan_req;
+ const u8 *ch_elm;
+ u8 *ies;
+ int ies_len;
+ size_t offset;
+
+ if (ieee80211_is_probe_resp(rcvd_info->mgmt->frame_control))
+ offset = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
+ else if (ieee80211_is_beacon(rcvd_info->mgmt->frame_control))
+ offset = offsetof(struct ieee80211_mgmt, u.beacon.variable);
+ else
+ goto done;
+
+ ies = rcvd_info->mgmt->u.beacon.variable;
+ ies_len = rcvd_info->frame_len - offset;
+ if (ies_len <= 0)
+ goto done;
+
+ ch_elm = cfg80211_find_ie(WLAN_EID_DS_PARAMS, ies, ies_len);
+ if (ch_elm && ch_elm[1] > 0)
+ rcvd_info->ch = ch_elm[2];
+
+ if (scan_req->scan_result)
+ scan_req->scan_result(SCAN_EVENT_NETWORK_FOUND, rcvd_info,
+ scan_req->arg);
+
+done:
+ kfree(rcvd_info->mgmt);
+ kfree(msg);
+}
+
+static void host_int_get_assoc_res_info(struct wilc_vif *vif,
+ u8 *assoc_resp_info,
+ u32 max_assoc_resp_info_len,
+ u32 *rcvd_assoc_resp_info_len)
+{
+ int result;
+ struct wid wid;
+
+ wid.id = WID_ASSOC_RES_INFO;
+ wid.type = WID_STR;
+ wid.val = assoc_resp_info;
+ wid.size = max_assoc_resp_info_len;
+
+ result = wilc_send_config_pkt(vif, WILC_GET_CFG, &wid, 1);
+ if (result) {
+ *rcvd_assoc_resp_info_len = 0;
+ netdev_err(vif->ndev, "Failed to send association response\n");
+ return;
+ }
+
+ *rcvd_assoc_resp_info_len = wid.size;
+}
+
+static s32 wilc_parse_assoc_resp_info(u8 *buffer, u32 buffer_len,
+ struct wilc_conn_info *ret_conn_info)
+{
+ u8 *ies;
+ u16 ies_len;
+ struct assoc_resp *res = (struct assoc_resp *)buffer;
+
+ ret_conn_info->status = le16_to_cpu(res->status_code);
+ if (ret_conn_info->status == WLAN_STATUS_SUCCESS) {
+ ies = &buffer[sizeof(*res)];
+ ies_len = buffer_len - sizeof(*res);
+
+ ret_conn_info->resp_ies = kmemdup(ies, ies_len, GFP_KERNEL);
+ if (!ret_conn_info->resp_ies)
+ return -ENOMEM;
+
+ ret_conn_info->resp_ies_len = ies_len;
+ }
+
+ return 0;
+}
+
+static inline void host_int_parse_assoc_resp_info(struct wilc_vif *vif,
+ u8 mac_status)
+{
+ struct host_if_drv *hif_drv = vif->hif_drv;
+ struct wilc_conn_info *conn_info = &hif_drv->conn_info;
+
+ if (mac_status == WILC_MAC_STATUS_CONNECTED) {
+ u32 assoc_resp_info_len;
+
+ memset(hif_drv->assoc_resp, 0, WILC_MAX_ASSOC_RESP_FRAME_SIZE);
+
+ host_int_get_assoc_res_info(vif, hif_drv->assoc_resp,
+ WILC_MAX_ASSOC_RESP_FRAME_SIZE,
+ &assoc_resp_info_len);
+
+ if (assoc_resp_info_len != 0) {
+ s32 err = 0;
+
+ err = wilc_parse_assoc_resp_info(hif_drv->assoc_resp,
+ assoc_resp_info_len,
+ conn_info);
+ if (err)
+ netdev_err(vif->ndev,
+ "wilc_parse_assoc_resp_info() returned error %d\n",
+ err);
+ }
+ }
+
+ del_timer(&hif_drv->connect_timer);
+ conn_info->conn_result(CONN_DISCONN_EVENT_CONN_RESP, mac_status,
+ hif_drv->conn_info.arg);
+
+ if (mac_status == WILC_MAC_STATUS_CONNECTED &&
+ conn_info->status == WLAN_STATUS_SUCCESS) {
+ ether_addr_copy(hif_drv->assoc_bssid, conn_info->bssid);
+ wilc_set_power_mgmt(vif, 0, 0);
+
+ hif_drv->hif_state = HOST_IF_CONNECTED;
+
+ vif->obtaining_ip = true;
+ mod_timer(&vif->during_ip_timer,
+ jiffies + msecs_to_jiffies(10000));
+ } else {
+ hif_drv->hif_state = HOST_IF_IDLE;
+ }
+
+ kfree(conn_info->resp_ies);
+ conn_info->resp_ies = NULL;
+ conn_info->resp_ies_len = 0;
+
+ kfree(conn_info->req_ies);
+ conn_info->req_ies = NULL;
+ conn_info->req_ies_len = 0;
+}
+
+static inline void host_int_handle_disconnect(struct wilc_vif *vif)
+{
+ struct host_if_drv *hif_drv = vif->hif_drv;
+
+ if (hif_drv->usr_scan_req.scan_result) {
+ del_timer(&hif_drv->scan_timer);
+ handle_scan_done(vif, SCAN_EVENT_ABORTED);
+ }
+
+ if (hif_drv->conn_info.conn_result) {
+ vif->obtaining_ip = false;
+ wilc_set_power_mgmt(vif, 0, 0);
+
+ hif_drv->conn_info.conn_result(CONN_DISCONN_EVENT_DISCONN_NOTIF,
+ 0, hif_drv->conn_info.arg);
+ } else {
+ netdev_err(vif->ndev, "%s: conn_result is NULL\n", __func__);
+ }
+
+ eth_zero_addr(hif_drv->assoc_bssid);
+
+ hif_drv->conn_info.req_ies_len = 0;
+ kfree(hif_drv->conn_info.req_ies);
+ hif_drv->conn_info.req_ies = NULL;
+ hif_drv->hif_state = HOST_IF_IDLE;
+}
+
+static void handle_rcvd_gnrl_async_info(struct work_struct *work)
+{
+ struct host_if_msg *msg = container_of(work, struct host_if_msg, work);
+ struct wilc_vif *vif = msg->vif;
+ struct wilc_rcvd_mac_info *mac_info = &msg->body.mac_info;
+ struct host_if_drv *hif_drv = vif->hif_drv;
+
+ if (!hif_drv) {
+ netdev_err(vif->ndev, "%s: hif driver is NULL\n", __func__);
+ goto free_msg;
+ }
+
+ if (!hif_drv->conn_info.conn_result) {
+ netdev_err(vif->ndev, "%s: conn_result is NULL\n", __func__);
+ goto free_msg;
+ }
+
+ if (hif_drv->hif_state == HOST_IF_WAITING_CONN_RESP) {
+ host_int_parse_assoc_resp_info(vif, mac_info->status);
+ } else if (mac_info->status == WILC_MAC_STATUS_DISCONNECTED) {
+ if (hif_drv->hif_state == HOST_IF_CONNECTED) {
+ host_int_handle_disconnect(vif);
+ } else if (hif_drv->usr_scan_req.scan_result) {
+ del_timer(&hif_drv->scan_timer);
+ handle_scan_done(vif, SCAN_EVENT_ABORTED);
+ }
+ }
+
+free_msg:
+ kfree(msg);
+}
+
+int wilc_disconnect(struct wilc_vif *vif)
+{
+ struct wid wid;
+ struct host_if_drv *hif_drv = vif->hif_drv;
+ struct wilc_user_scan_req *scan_req;
+ struct wilc_conn_info *conn_info;
+ int result;
+ u16 dummy_reason_code = 0;
+
+ wid.id = WID_DISCONNECT;
+ wid.type = WID_CHAR;
+ wid.val = (s8 *)&dummy_reason_code;
+ wid.size = sizeof(char);
+
+ vif->obtaining_ip = false;
+ wilc_set_power_mgmt(vif, 0, 0);
+
+ result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
+ if (result) {
+ netdev_err(vif->ndev, "Failed to send disconnect\n");
+ return result;
+ }
+
+ scan_req = &hif_drv->usr_scan_req;
+ conn_info = &hif_drv->conn_info;
+
+ if (scan_req->scan_result) {
+ del_timer(&hif_drv->scan_timer);
+ scan_req->scan_result(SCAN_EVENT_ABORTED, NULL, scan_req->arg);
+ scan_req->scan_result = NULL;
+ }
+
+ if (conn_info->conn_result) {
+ if (hif_drv->hif_state == HOST_IF_WAITING_CONN_RESP)
+ del_timer(&hif_drv->connect_timer);
+
+ conn_info->conn_result(CONN_DISCONN_EVENT_DISCONN_NOTIF, 0,
+ conn_info->arg);
+ } else {
+ netdev_err(vif->ndev, "%s: conn_result is NULL\n", __func__);
+ }
+
+ hif_drv->hif_state = HOST_IF_IDLE;
+
+ eth_zero_addr(hif_drv->assoc_bssid);
+
+ conn_info->req_ies_len = 0;
+ kfree(conn_info->req_ies);
+ conn_info->req_ies = NULL;
+
+ return 0;
+}
+
+void wilc_resolve_disconnect_aberration(struct wilc_vif *vif)
+{
+ if (!vif->hif_drv)
+ return;
+ if (vif->hif_drv->hif_state == HOST_IF_WAITING_CONN_RESP ||
+ vif->hif_drv->hif_state == HOST_IF_CONNECTING)
+ wilc_disconnect(vif);
+}
+
+int wilc_get_statistics(struct wilc_vif *vif, struct rf_info *stats)
+{
+ struct wid wid_list[5];
+ u32 wid_cnt = 0, result;
+
+ wid_list[wid_cnt].id = WID_LINKSPEED;
+ wid_list[wid_cnt].type = WID_CHAR;
+ wid_list[wid_cnt].size = sizeof(char);
+ wid_list[wid_cnt].val = (s8 *)&stats->link_speed;
+ wid_cnt++;
+
+ wid_list[wid_cnt].id = WID_RSSI;
+ wid_list[wid_cnt].type = WID_CHAR;
+ wid_list[wid_cnt].size = sizeof(char);
+ wid_list[wid_cnt].val = (s8 *)&stats->rssi;
+ wid_cnt++;
+
+ wid_list[wid_cnt].id = WID_SUCCESS_FRAME_COUNT;
+ wid_list[wid_cnt].type = WID_INT;
+ wid_list[wid_cnt].size = sizeof(u32);
+ wid_list[wid_cnt].val = (s8 *)&stats->tx_cnt;
+ wid_cnt++;
+
+ wid_list[wid_cnt].id = WID_RECEIVED_FRAGMENT_COUNT;
+ wid_list[wid_cnt].type = WID_INT;
+ wid_list[wid_cnt].size = sizeof(u32);
+ wid_list[wid_cnt].val = (s8 *)&stats->rx_cnt;
+ wid_cnt++;
+
+ wid_list[wid_cnt].id = WID_FAILED_COUNT;
+ wid_list[wid_cnt].type = WID_INT;
+ wid_list[wid_cnt].size = sizeof(u32);
+ wid_list[wid_cnt].val = (s8 *)&stats->tx_fail_cnt;
+ wid_cnt++;
+
+ result = wilc_send_config_pkt(vif, WILC_GET_CFG, wid_list, wid_cnt);
+ if (result) {
+ netdev_err(vif->ndev, "Failed to send scan parameters\n");
+ return result;
+ }
+
+ if (stats->link_speed > TCP_ACK_FILTER_LINK_SPEED_THRESH &&
+ stats->link_speed != DEFAULT_LINK_SPEED)
+ wilc_enable_tcp_ack_filter(vif, true);
+ else if (stats->link_speed != DEFAULT_LINK_SPEED)
+ wilc_enable_tcp_ack_filter(vif, false);
+
+ return result;
+}
+
+static void handle_get_statistics(struct work_struct *work)
+{
+ struct host_if_msg *msg = container_of(work, struct host_if_msg, work);
+ struct wilc_vif *vif = msg->vif;
+ struct rf_info *stats = (struct rf_info *)msg->body.data;
+
+ wilc_get_statistics(vif, stats);
+
+ kfree(msg);
+}
+
+static void wilc_hif_pack_sta_param(u8 *cur_byte, const u8 *mac,
+ struct station_parameters *params)
+{
+ ether_addr_copy(cur_byte, mac);
+ cur_byte += ETH_ALEN;
+
+ put_unaligned_le16(params->aid, cur_byte);
+ cur_byte += 2;
+
+ *cur_byte++ = params->supported_rates_len;
+ if (params->supported_rates_len > 0)
+ memcpy(cur_byte, params->supported_rates,
+ params->supported_rates_len);
+ cur_byte += params->supported_rates_len;
+
+ if (params->ht_capa) {
+ *cur_byte++ = true;
+ memcpy(cur_byte, ¶ms->ht_capa,
+ sizeof(struct ieee80211_ht_cap));
+ } else {
+ *cur_byte++ = false;
+ }
+ cur_byte += sizeof(struct ieee80211_ht_cap);
+
+ put_unaligned_le16(params->sta_flags_mask, cur_byte);
+ cur_byte += 2;
+ put_unaligned_le16(params->sta_flags_set, cur_byte);
+}
+
+static int handle_remain_on_chan(struct wilc_vif *vif,
+ struct wilc_remain_ch *hif_remain_ch)
+{
+ int result;
+ u8 remain_on_chan_flag;
+ struct wid wid;
+ struct host_if_drv *hif_drv = vif->hif_drv;
+
+ if (hif_drv->usr_scan_req.scan_result)
+ return -EBUSY;
+
+ if (hif_drv->hif_state == HOST_IF_WAITING_CONN_RESP)
+ return -EBUSY;
+
+ if (vif->obtaining_ip || vif->connecting)
+ return -EBUSY;
+
+ remain_on_chan_flag = true;
+ wid.id = WID_REMAIN_ON_CHAN;
+ wid.type = WID_STR;
+ wid.size = 2;
+ wid.val = kmalloc(wid.size, GFP_KERNEL);
+ if (!wid.val)
+ return -ENOMEM;
+
+ wid.val[0] = remain_on_chan_flag;
+ wid.val[1] = (s8)hif_remain_ch->ch;
+
+ result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
+ kfree(wid.val);
+ if (result)
+ return -EBUSY;
+
+ hif_drv->remain_on_ch.arg = hif_remain_ch->arg;
+ hif_drv->remain_on_ch.expired = hif_remain_ch->expired;
+ hif_drv->remain_on_ch.ch = hif_remain_ch->ch;
+ hif_drv->remain_on_ch.cookie = hif_remain_ch->cookie;
+ hif_drv->remain_on_ch_timer_vif = vif;
+
+ return 0;
+}
+
+static int wilc_handle_roc_expired(struct wilc_vif *vif, u64 cookie)
+{
+ u8 remain_on_chan_flag;
+ struct wid wid;
+ int result;
+ struct host_if_drv *hif_drv = vif->hif_drv;
+ struct wilc_priv *priv = wdev_priv(vif->ndev->ieee80211_ptr);
+
+ if (priv->p2p_listen_state) {
+ remain_on_chan_flag = false;
+ wid.id = WID_REMAIN_ON_CHAN;
+ wid.type = WID_STR;
+ wid.size = 2;
+
+ wid.val = kmalloc(wid.size, GFP_KERNEL);
+ if (!wid.val)
+ return -ENOMEM;
+
+ wid.val[0] = remain_on_chan_flag;
+ wid.val[1] = WILC_FALSE_FRMWR_CHANNEL;
+
+ result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
+ kfree(wid.val);
+ if (result != 0) {
+ netdev_err(vif->ndev, "Failed to set remain channel\n");
+ return -EINVAL;
+ }
+
+ if (hif_drv->remain_on_ch.expired) {
+ hif_drv->remain_on_ch.expired(hif_drv->remain_on_ch.arg,
+ cookie);
+ }
+ } else {
+ netdev_dbg(vif->ndev, "Not in listen state\n");
+ }
+
+ return 0;
+}
+
+static void wilc_handle_listen_state_expired(struct work_struct *work)
+{
+ struct host_if_msg *msg = container_of(work, struct host_if_msg, work);
+
+ wilc_handle_roc_expired(msg->vif, msg->body.remain_on_ch.cookie);
+ kfree(msg);
+}
+
+static void listen_timer_cb(struct timer_list *t)
+{
+ struct host_if_drv *hif_drv = from_timer(hif_drv, t,
+ remain_on_ch_timer);
+ struct wilc_vif *vif = hif_drv->remain_on_ch_timer_vif;
+ int result;
+ struct host_if_msg *msg;
+
+ del_timer(&vif->hif_drv->remain_on_ch_timer);
+
+ msg = wilc_alloc_work(vif, wilc_handle_listen_state_expired, false);
+ if (IS_ERR(msg))
+ return;
+
+ msg->body.remain_on_ch.cookie = vif->hif_drv->remain_on_ch.cookie;
+
+ result = wilc_enqueue_work(msg);
+ if (result) {
+ netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__);
+ kfree(msg);
+ }
+}
+
+static void handle_set_mcast_filter(struct work_struct *work)
+{
+ struct host_if_msg *msg = container_of(work, struct host_if_msg, work);
+ struct wilc_vif *vif = msg->vif;
+ struct wilc_set_multicast *set_mc = &msg->body.mc_info;
+ int result;
+ struct wid wid;
+ u8 *cur_byte;
+
+ wid.id = WID_SETUP_MULTICAST_FILTER;
+ wid.type = WID_BIN;
+ wid.size = sizeof(struct wilc_set_multicast) + (set_mc->cnt * ETH_ALEN);
+ wid.val = kmalloc(wid.size, GFP_KERNEL);
+ if (!wid.val)
+ goto error;
+
+ cur_byte = wid.val;
+ put_unaligned_le32(set_mc->enabled, cur_byte);
+ cur_byte += 4;
+
+ put_unaligned_le32(set_mc->cnt, cur_byte);
+ cur_byte += 4;
+
+ if (set_mc->cnt > 0 && set_mc->mc_list)
+ memcpy(cur_byte, set_mc->mc_list, set_mc->cnt * ETH_ALEN);
+
+ result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
+ if (result)
+ netdev_err(vif->ndev, "Failed to send setup multicast\n");
+
+error:
+ kfree(set_mc->mc_list);
+ kfree(wid.val);
+ kfree(msg);
+}
+
+static void handle_scan_timer(struct work_struct *work)
+{
+ struct host_if_msg *msg = container_of(work, struct host_if_msg, work);
+
+ handle_scan_done(msg->vif, SCAN_EVENT_ABORTED);
+ kfree(msg);
+}
+
+static void handle_scan_complete(struct work_struct *work)
+{
+ struct host_if_msg *msg = container_of(work, struct host_if_msg, work);
+ struct wilc *wilc = msg->vif->wilc;
+
+ del_timer(&msg->vif->hif_drv->scan_timer);
+
+ if (!wilc_wlan_get_num_conn_ifcs(wilc))
+ wilc_chip_sleep_manually(wilc);
+
+ handle_scan_done(msg->vif, SCAN_EVENT_DONE);
+
+ kfree(msg);
+}
+
+static void timer_scan_cb(struct timer_list *t)
+{
+ struct host_if_drv *hif_drv = from_timer(hif_drv, t, scan_timer);
+ struct wilc_vif *vif = hif_drv->scan_timer_vif;
+ struct host_if_msg *msg;
+ int result;
+
+ msg = wilc_alloc_work(vif, handle_scan_timer, false);
+ if (IS_ERR(msg))
+ return;
+
+ result = wilc_enqueue_work(msg);
+ if (result)
+ kfree(msg);
+}
+
+static void timer_connect_cb(struct timer_list *t)
+{
+ struct host_if_drv *hif_drv = from_timer(hif_drv, t,
+ connect_timer);
+ struct wilc_vif *vif = hif_drv->connect_timer_vif;
+ struct host_if_msg *msg;
+ int result;
+
+ msg = wilc_alloc_work(vif, handle_connect_timeout, false);
+ if (IS_ERR(msg))
+ return;
+
+ result = wilc_enqueue_work(msg);
+ if (result)
+ kfree(msg);
+}
+
+int wilc_remove_wep_key(struct wilc_vif *vif, u8 index)
+{
+ struct wid wid;
+ int result;
+
+ wid.id = WID_REMOVE_WEP_KEY;
+ wid.type = WID_STR;
+ wid.size = sizeof(char);
+ wid.val = &index;
+
+ result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
+ if (result)
+ netdev_err(vif->ndev,
+ "Failed to send remove wep key config packet\n");
+ return result;
+}
+
+int wilc_set_wep_default_keyid(struct wilc_vif *vif, u8 index)
+{
+ struct wid wid;
+ int result;
+
+ wid.id = WID_KEY_ID;
+ wid.type = WID_CHAR;
+ wid.size = sizeof(char);
+ wid.val = &index;
+ result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
+ if (result)
+ netdev_err(vif->ndev,
+ "Failed to send wep default key config packet\n");
+
+ return result;
+}
+
+int wilc_add_wep_key_bss_sta(struct wilc_vif *vif, const u8 *key, u8 len,
+ u8 index)
+{
+ struct wid wid;
+ int result;
+ struct wilc_wep_key *wep_key;
+
+ wid.id = WID_ADD_WEP_KEY;
+ wid.type = WID_STR;
+ wid.size = sizeof(*wep_key) + len;
+ wep_key = kzalloc(wid.size, GFP_KERNEL);
+ if (!wep_key)
+ return -ENOMEM;
+
+ wid.val = (u8 *)wep_key;
+
+ wep_key->index = index;
+ wep_key->key_len = len;
+ memcpy(wep_key->key, key, len);
+
+ result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
+ if (result)
+ netdev_err(vif->ndev,
+ "Failed to add wep key config packet\n");
+
+ kfree(wep_key);
+ return result;
+}
+
+int wilc_add_wep_key_bss_ap(struct wilc_vif *vif, const u8 *key, u8 len,
+ u8 index, u8 mode, enum authtype auth_type)
+{
+ struct wid wid_list[3];
+ int result;
+ struct wilc_wep_key *wep_key;
+
+ wid_list[0].id = WID_11I_MODE;
+ wid_list[0].type = WID_CHAR;
+ wid_list[0].size = sizeof(char);
+ wid_list[0].val = &mode;
+
+ wid_list[1].id = WID_AUTH_TYPE;
+ wid_list[1].type = WID_CHAR;
+ wid_list[1].size = sizeof(char);
+ wid_list[1].val = (s8 *)&auth_type;
+
+ wid_list[2].id = WID_WEP_KEY_VALUE;
+ wid_list[2].type = WID_STR;
+ wid_list[2].size = sizeof(*wep_key) + len;
+ wep_key = kzalloc(wid_list[2].size, GFP_KERNEL);
+ if (!wep_key)
+ return -ENOMEM;
+
+ wid_list[2].val = (u8 *)wep_key;
+
+ wep_key->index = index;
+ wep_key->key_len = len;
+ memcpy(wep_key->key, key, len);
+ result = wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list,
+ ARRAY_SIZE(wid_list));
+ if (result)
+ netdev_err(vif->ndev,
+ "Failed to add wep ap key config packet\n");
+
+ kfree(wep_key);
+ return result;
+}
+
+int wilc_add_ptk(struct wilc_vif *vif, const u8 *ptk, u8 ptk_key_len,
+ const u8 *mac_addr, const u8 *rx_mic, const u8 *tx_mic,
+ u8 mode, u8 cipher_mode, u8 index)
+{
+ int result = 0;
+ u8 t_key_len = ptk_key_len + WILC_RX_MIC_KEY_LEN + WILC_TX_MIC_KEY_LEN;
+
+ if (mode == WILC_AP_MODE) {
+ struct wid wid_list[2];
+ struct wilc_ap_wpa_ptk *key_buf;
+
+ wid_list[0].id = WID_11I_MODE;
+ wid_list[0].type = WID_CHAR;
+ wid_list[0].size = sizeof(char);
+ wid_list[0].val = (s8 *)&cipher_mode;
+
+ key_buf = kzalloc(sizeof(*key_buf) + t_key_len, GFP_KERNEL);
+ if (!key_buf)
+ return -ENOMEM;
+
+ ether_addr_copy(key_buf->mac_addr, mac_addr);
+ key_buf->index = index;
+ key_buf->key_len = t_key_len;
+ memcpy(&key_buf->key[0], ptk, ptk_key_len);
+
+ if (rx_mic)
+ memcpy(&key_buf->key[ptk_key_len], rx_mic,
+ WILC_RX_MIC_KEY_LEN);
+
+ if (tx_mic)
+ memcpy(&key_buf->key[ptk_key_len + WILC_RX_MIC_KEY_LEN],
+ tx_mic, WILC_TX_MIC_KEY_LEN);
+
+ wid_list[1].id = WID_ADD_PTK;
+ wid_list[1].type = WID_STR;
+ wid_list[1].size = sizeof(*key_buf) + t_key_len;
+ wid_list[1].val = (u8 *)key_buf;
+ result = wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list,
+ ARRAY_SIZE(wid_list));
+ kfree(key_buf);
+ } else if (mode == WILC_STATION_MODE) {
+ struct wid wid;
+ struct wilc_sta_wpa_ptk *key_buf;
+
+ key_buf = kzalloc(sizeof(*key_buf) + t_key_len, GFP_KERNEL);
+ if (!key_buf)
+ return -ENOMEM;
+
+ ether_addr_copy(key_buf->mac_addr, mac_addr);
+ key_buf->key_len = t_key_len;
+ memcpy(&key_buf->key[0], ptk, ptk_key_len);
+
+ if (rx_mic)
+ memcpy(&key_buf->key[ptk_key_len], rx_mic,
+ WILC_RX_MIC_KEY_LEN);
+
+ if (tx_mic)
+ memcpy(&key_buf->key[ptk_key_len + WILC_RX_MIC_KEY_LEN],
+ tx_mic, WILC_TX_MIC_KEY_LEN);
+
+ wid.id = WID_ADD_PTK;
+ wid.type = WID_STR;
+ wid.size = sizeof(*key_buf) + t_key_len;
+ wid.val = (s8 *)key_buf;
+ result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
+ kfree(key_buf);
+ }
+
+ return result;
+}
+
+int wilc_add_rx_gtk(struct wilc_vif *vif, const u8 *rx_gtk, u8 gtk_key_len,
+ u8 index, u32 key_rsc_len, const u8 *key_rsc,
+ const u8 *rx_mic, const u8 *tx_mic, u8 mode,
+ u8 cipher_mode)
+{
+ int result = 0;
+ struct wilc_gtk_key *gtk_key;
+ int t_key_len = gtk_key_len + WILC_RX_MIC_KEY_LEN + WILC_TX_MIC_KEY_LEN;
+
+ gtk_key = kzalloc(sizeof(*gtk_key) + t_key_len, GFP_KERNEL);
+ if (!gtk_key)
+ return -ENOMEM;
+
+ /* fill bssid value only in station mode */
+ if (mode == WILC_STATION_MODE &&
+ vif->hif_drv->hif_state == HOST_IF_CONNECTED)
+ memcpy(gtk_key->mac_addr, vif->hif_drv->assoc_bssid, ETH_ALEN);
+
+ if (key_rsc)
+ memcpy(gtk_key->rsc, key_rsc, 8);
+ gtk_key->index = index;
+ gtk_key->key_len = t_key_len;
+ memcpy(>k_key->key[0], rx_gtk, gtk_key_len);
+
+ if (rx_mic)
+ memcpy(>k_key->key[gtk_key_len], rx_mic, WILC_RX_MIC_KEY_LEN);
+
+ if (tx_mic)
+ memcpy(>k_key->key[gtk_key_len + WILC_RX_MIC_KEY_LEN],
+ tx_mic, WILC_TX_MIC_KEY_LEN);
+
+ if (mode == WILC_AP_MODE) {
+ struct wid wid_list[2];
+
+ wid_list[0].id = WID_11I_MODE;
+ wid_list[0].type = WID_CHAR;
+ wid_list[0].size = sizeof(char);
+ wid_list[0].val = (s8 *)&cipher_mode;
+
+ wid_list[1].id = WID_ADD_RX_GTK;
+ wid_list[1].type = WID_STR;
+ wid_list[1].size = sizeof(*gtk_key) + t_key_len;
+ wid_list[1].val = (u8 *)gtk_key;
+
+ result = wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list,
+ ARRAY_SIZE(wid_list));
+ } else if (mode == WILC_STATION_MODE) {
+ struct wid wid;
+
+ wid.id = WID_ADD_RX_GTK;
+ wid.type = WID_STR;
+ wid.size = sizeof(*gtk_key) + t_key_len;
+ wid.val = (u8 *)gtk_key;
+ result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
+ }
+
+ kfree(gtk_key);
+ return result;
+}
+
+int wilc_set_pmkid_info(struct wilc_vif *vif, struct wilc_pmkid_attr *pmkid)
+{
+ struct wid wid;
+
+ wid.id = WID_PMKID_INFO;
+ wid.type = WID_STR;
+ wid.size = (pmkid->numpmkid * sizeof(struct wilc_pmkid)) + 1;
+ wid.val = (u8 *)pmkid;
+
+ return wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
+}
+
+int wilc_get_mac_address(struct wilc_vif *vif, u8 *mac_addr)
+{
+ int result;
+ struct wid wid;
+
+ wid.id = WID_MAC_ADDR;
+ wid.type = WID_STR;
+ wid.size = ETH_ALEN;
+ wid.val = mac_addr;
+
+ result = wilc_send_config_pkt(vif, WILC_GET_CFG, &wid, 1);
+ if (result)
+ netdev_err(vif->ndev, "Failed to get mac address\n");
+
+ return result;
+}
+
+int wilc_set_join_req(struct wilc_vif *vif, u8 *bssid, const u8 *ies,
+ size_t ies_len)
+{
+ int result;
+ struct host_if_drv *hif_drv = vif->hif_drv;
+ struct wilc_conn_info *conn_info = &hif_drv->conn_info;
+
+ if (bssid)
+ ether_addr_copy(conn_info->bssid, bssid);
+
+ if (ies) {
+ conn_info->req_ies_len = ies_len;
+ conn_info->req_ies = kmemdup(ies, ies_len, GFP_KERNEL);
+ if (!conn_info->req_ies)
+ return -ENOMEM;
+ }
+
+ result = wilc_send_connect_wid(vif);
+ if (result)
+ goto free_ies;
+
+ hif_drv->connect_timer_vif = vif;
+ mod_timer(&hif_drv->connect_timer,
+ jiffies + msecs_to_jiffies(WILC_HIF_CONNECT_TIMEOUT_MS));
+
+ return 0;
+
+free_ies:
+ kfree(conn_info->req_ies);
+
+ return result;
+}
+
+int wilc_set_mac_chnl_num(struct wilc_vif *vif, u8 channel)
+{
+ struct wid wid;
+ int result;
+
+ wid.id = WID_CURRENT_CHANNEL;
+ wid.type = WID_CHAR;
+ wid.size = sizeof(char);
+ wid.val = &channel;
+
+ result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
+ if (result)
+ netdev_err(vif->ndev, "Failed to set channel\n");
+
+ return result;
+}
+
+int wilc_set_wfi_drv_handler(struct wilc_vif *vif, int index, u8 mode,
+ u8 ifc_id)
+{
+ struct wid wid;
+ struct host_if_drv *hif_drv = vif->hif_drv;
+ int result;
+ struct wilc_drv_handler drv;
+
+ if (!hif_drv)
+ return -EFAULT;
+
+ wid.id = WID_SET_DRV_HANDLER;
+ wid.type = WID_STR;
+ wid.size = sizeof(drv);
+ wid.val = (u8 *)&drv;
+
+ drv.handler = cpu_to_le32(index);
+ drv.mode = (ifc_id | (mode << 1));
+
+ result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
+ if (result)
+ netdev_err(vif->ndev, "Failed to set driver handler\n");
+
+ return result;
+}
+
+int wilc_set_operation_mode(struct wilc_vif *vif, u32 mode)
+{
+ struct wid wid;
+ struct wilc_op_mode op_mode;
+ int result;
+
+ wid.id = WID_SET_OPERATION_MODE;
+ wid.type = WID_INT;
+ wid.size = sizeof(op_mode);
+ wid.val = (u8 *)&op_mode;
+
+ op_mode.mode = cpu_to_le32(mode);
+
+ result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
+ if (result)
+ netdev_err(vif->ndev, "Failed to set operation mode\n");
+
+ return result;
+}
+
+s32 wilc_get_inactive_time(struct wilc_vif *vif, const u8 *mac, u32 *out_val)
+{
+ struct wid wid;
+ s32 result;
+
+ wid.id = WID_SET_STA_MAC_INACTIVE_TIME;
+ wid.type = WID_STR;
+ wid.size = ETH_ALEN;
+ wid.val = kzalloc(wid.size, GFP_KERNEL);
+ if (!wid.val)
+ return -ENOMEM;
+
+ ether_addr_copy(wid.val, mac);
+ result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
+ kfree(wid.val);
+ if (result) {
+ netdev_err(vif->ndev, "Failed to set inactive mac\n");
+ return result;
+ }
+
+ wid.id = WID_GET_INACTIVE_TIME;
+ wid.type = WID_INT;
+ wid.val = (s8 *)out_val;
+ wid.size = sizeof(u32);
+ result = wilc_send_config_pkt(vif, WILC_GET_CFG, &wid, 1);
+ if (result)
+ netdev_err(vif->ndev, "Failed to get inactive time\n");
+
+ return result;
+}
+
+int wilc_get_rssi(struct wilc_vif *vif, s8 *rssi_level)
+{
+ struct wid wid;
+ int result;
+
+ if (!rssi_level) {
+ netdev_err(vif->ndev, "%s: RSSI level is NULL\n", __func__);
+ return -EFAULT;
+ }
+
+ wid.id = WID_RSSI;
+ wid.type = WID_CHAR;
+ wid.size = sizeof(char);
+ wid.val = rssi_level;
+ result = wilc_send_config_pkt(vif, WILC_GET_CFG, &wid, 1);
+ if (result)
+ netdev_err(vif->ndev, "Failed to get RSSI value\n");
+
+ return result;
+}
+
+static int wilc_get_stats_async(struct wilc_vif *vif, struct rf_info *stats)
+{
+ int result;
+ struct host_if_msg *msg;
+
+ msg = wilc_alloc_work(vif, handle_get_statistics, false);
+ if (IS_ERR(msg))
+ return PTR_ERR(msg);
+
+ msg->body.data = (char *)stats;
+
+ result = wilc_enqueue_work(msg);
+ if (result) {
+ netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__);
+ kfree(msg);
+ return result;
+ }
+
+ return result;
+}
+
+int wilc_hif_set_cfg(struct wilc_vif *vif, struct cfg_param_attr *param)
+{
+ struct wid wid_list[4];
+ int i = 0;
+
+ if (param->flag & WILC_CFG_PARAM_RETRY_SHORT) {
+ wid_list[i].id = WID_SHORT_RETRY_LIMIT;
+ wid_list[i].val = (s8 *)¶m->short_retry_limit;
+ wid_list[i].type = WID_SHORT;
+ wid_list[i].size = sizeof(u16);
+ i++;
+ }
+ if (param->flag & WILC_CFG_PARAM_RETRY_LONG) {
+ wid_list[i].id = WID_LONG_RETRY_LIMIT;
+ wid_list[i].val = (s8 *)¶m->long_retry_limit;
+ wid_list[i].type = WID_SHORT;
+ wid_list[i].size = sizeof(u16);
+ i++;
+ }
+ if (param->flag & WILC_CFG_PARAM_FRAG_THRESHOLD) {
+ wid_list[i].id = WID_FRAG_THRESHOLD;
+ wid_list[i].val = (s8 *)¶m->frag_threshold;
+ wid_list[i].type = WID_SHORT;
+ wid_list[i].size = sizeof(u16);
+ i++;
+ }
+ if (param->flag & WILC_CFG_PARAM_RTS_THRESHOLD) {
+ wid_list[i].id = WID_RTS_THRESHOLD;
+ wid_list[i].val = (s8 *)¶m->rts_threshold;
+ wid_list[i].type = WID_SHORT;
+ wid_list[i].size = sizeof(u16);
+ i++;
+ }
+
+ return wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list, i);
+}
+
+static void get_periodic_rssi(struct timer_list *t)
+{
+ struct wilc_vif *vif = from_timer(vif, t, periodic_rssi);
+
+ if (!vif->hif_drv) {
+ netdev_err(vif->ndev, "%s: hif driver is NULL", __func__);
+ return;
+ }
+
+ if (vif->hif_drv->hif_state == HOST_IF_CONNECTED)
+ wilc_get_stats_async(vif, &vif->periodic_stat);
+
+ mod_timer(&vif->periodic_rssi, jiffies + msecs_to_jiffies(5000));
+}
+
+int wilc_init(struct net_device *dev, struct host_if_drv **hif_drv_handler)
+{
+ struct host_if_drv *hif_drv;
+ struct wilc_vif *vif = netdev_priv(dev);
+ struct wilc *wilc = vif->wilc;
+
+ hif_drv = kzalloc(sizeof(*hif_drv), GFP_KERNEL);
+ if (!hif_drv)
+ return -ENOMEM;
+
+ *hif_drv_handler = hif_drv;
+
+ vif->hif_drv = hif_drv;
+ vif->obtaining_ip = false;
+
+ if (wilc->clients_count == 0)
+ mutex_init(&wilc->deinit_lock);
+
+ timer_setup(&vif->periodic_rssi, get_periodic_rssi, 0);
+ mod_timer(&vif->periodic_rssi, jiffies + msecs_to_jiffies(5000));
+
+ timer_setup(&hif_drv->scan_timer, timer_scan_cb, 0);
+ timer_setup(&hif_drv->connect_timer, timer_connect_cb, 0);
+ timer_setup(&hif_drv->remain_on_ch_timer, listen_timer_cb, 0);
+
+ hif_drv->hif_state = HOST_IF_IDLE;
+
+ hif_drv->p2p_timeout = 0;
+
+ wilc->clients_count++;
+
+ return 0;
+}
+
+int wilc_deinit(struct wilc_vif *vif)
+{
+ int result = 0;
+ struct host_if_drv *hif_drv = vif->hif_drv;
+
+ if (!hif_drv) {
+ netdev_err(vif->ndev, "%s: hif driver is NULL", __func__);
+ return -EFAULT;
+ }
+
+ mutex_lock(&vif->wilc->deinit_lock);
+
+ del_timer_sync(&hif_drv->scan_timer);
+ del_timer_sync(&hif_drv->connect_timer);
+ del_timer_sync(&vif->periodic_rssi);
+ del_timer_sync(&hif_drv->remain_on_ch_timer);
+
+ wilc_set_wfi_drv_handler(vif, 0, 0, 0);
+
+ if (hif_drv->usr_scan_req.scan_result) {
+ hif_drv->usr_scan_req.scan_result(SCAN_EVENT_ABORTED, NULL,
+ hif_drv->usr_scan_req.arg);
+ hif_drv->usr_scan_req.scan_result = NULL;
+ }
+
+ hif_drv->hif_state = HOST_IF_IDLE;
+
+ kfree(hif_drv);
+ vif->hif_drv = NULL;
+ vif->wilc->clients_count--;
+ mutex_unlock(&vif->wilc->deinit_lock);
+ return result;
+}
+
+void wilc_network_info_received(struct wilc *wilc, u8 *buffer, u32 length)
+{
+ int result;
+ struct host_if_msg *msg;
+ int id;
+ struct host_if_drv *hif_drv;
+ struct wilc_vif *vif;
+
+ id = get_unaligned_le32(&buffer[length - 4]);
+ vif = wilc_get_vif_from_idx(wilc, id);
+ if (!vif)
+ return;
+ hif_drv = vif->hif_drv;
+
+ if (!hif_drv) {
+ netdev_err(vif->ndev, "driver not init[%p]\n", hif_drv);
+ return;
+ }
+
+ msg = wilc_alloc_work(vif, handle_rcvd_ntwrk_info, false);
+ if (IS_ERR(msg))
+ return;
+
+ msg->body.net_info.frame_len = get_unaligned_le16(&buffer[6]) - 1;
+ msg->body.net_info.rssi = buffer[8];
+ msg->body.net_info.mgmt = kmemdup(&buffer[9],
+ msg->body.net_info.frame_len,
+ GFP_KERNEL);
+ if (!msg->body.net_info.mgmt) {
+ kfree(msg);
+ return;
+ }
+
+ result = wilc_enqueue_work(msg);
+ if (result) {
+ netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__);
+ kfree(msg->body.net_info.mgmt);
+ kfree(msg);
+ }
+}
+
+void wilc_gnrl_async_info_received(struct wilc *wilc, u8 *buffer, u32 length)
+{
+ int result;
+ struct host_if_msg *msg;
+ int id;
+ struct host_if_drv *hif_drv;
+ struct wilc_vif *vif;
+
+ mutex_lock(&wilc->deinit_lock);
+
+ id = get_unaligned_le32(&buffer[length - 4]);
+ vif = wilc_get_vif_from_idx(wilc, id);
+ if (!vif) {
+ mutex_unlock(&wilc->deinit_lock);
+ return;
+ }
+
+ hif_drv = vif->hif_drv;
+
+ if (!hif_drv) {
+ mutex_unlock(&wilc->deinit_lock);
+ return;
+ }
+
+ if (!hif_drv->conn_info.conn_result) {
+ netdev_err(vif->ndev, "%s: conn_result is NULL\n", __func__);
+ mutex_unlock(&wilc->deinit_lock);
+ return;
+ }
+
+ msg = wilc_alloc_work(vif, handle_rcvd_gnrl_async_info, false);
+ if (IS_ERR(msg)) {
+ mutex_unlock(&wilc->deinit_lock);
+ return;
+ }
+
+ msg->body.mac_info.status = buffer[7];
+ result = wilc_enqueue_work(msg);
+ if (result) {
+ netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__);
+ kfree(msg);
+ }
+
+ mutex_unlock(&wilc->deinit_lock);
+}
+
+void wilc_scan_complete_received(struct wilc *wilc, u8 *buffer, u32 length)
+{
+ int result;
+ int id;
+ struct host_if_drv *hif_drv;
+ struct wilc_vif *vif;
+
+ id = get_unaligned_le32(&buffer[length - 4]);
+ vif = wilc_get_vif_from_idx(wilc, id);
+ if (!vif)
+ return;
+ hif_drv = vif->hif_drv;
+
+ if (!hif_drv)
+ return;
+
+ if (hif_drv->usr_scan_req.scan_result) {
+ struct host_if_msg *msg;
+
+ msg = wilc_alloc_work(vif, handle_scan_complete, false);
+ if (IS_ERR(msg))
+ return;
+
+ result = wilc_enqueue_work(msg);
+ if (result) {
+ netdev_err(vif->ndev, "%s: enqueue work failed\n",
+ __func__);
+ kfree(msg);
+ }
+ }
+}
+
+int wilc_remain_on_channel(struct wilc_vif *vif, u64 cookie,
+ u32 duration, u16 chan,
+ void (*expired)(void *, u64),
+ void *user_arg)
+{
+ struct wilc_remain_ch roc;
+ int result;
+
+ roc.ch = chan;
+ roc.expired = expired;
+ roc.arg = user_arg;
+ roc.duration = duration;
+ roc.cookie = cookie;
+ result = handle_remain_on_chan(vif, &roc);
+ if (result)
+ netdev_err(vif->ndev, "%s: failed to set remain on channel\n",
+ __func__);
+
+ return result;
+}
+
+int wilc_listen_state_expired(struct wilc_vif *vif, u64 cookie)
+{
+ if (!vif->hif_drv) {
+ netdev_err(vif->ndev, "%s: hif driver is NULL", __func__);
+ return -EFAULT;
+ }
+
+ del_timer(&vif->hif_drv->remain_on_ch_timer);
+
+ return wilc_handle_roc_expired(vif, cookie);
+}
+
+void wilc_frame_register(struct wilc_vif *vif, u16 frame_type, bool reg)
+{
+ struct wid wid;
+ int result;
+ struct wilc_reg_frame reg_frame;
+
+ wid.id = WID_REGISTER_FRAME;
+ wid.type = WID_STR;
+ wid.size = sizeof(reg_frame);
+ wid.val = (u8 *)®_frame;
+
+ memset(®_frame, 0x0, sizeof(reg_frame));
+ reg_frame.reg = reg;
+
+ switch (frame_type) {
+ case IEEE80211_STYPE_ACTION:
+ reg_frame.reg_id = WILC_FW_ACTION_FRM_IDX;
+ break;
+
+ case IEEE80211_STYPE_PROBE_REQ:
+ reg_frame.reg_id = WILC_FW_PROBE_REQ_IDX;
+ break;
+
+ default:
+ break;
+ }
+ reg_frame.frame_type = cpu_to_le16(frame_type);
+ result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
+ if (result)
+ netdev_err(vif->ndev, "Failed to frame register\n");
+}
+
+int wilc_add_beacon(struct wilc_vif *vif, u32 interval, u32 dtim_period,
+ struct cfg80211_beacon_data *params)
+{
+ struct wid wid;
+ int result;
+ u8 *cur_byte;
+
+ wid.id = WID_ADD_BEACON;
+ wid.type = WID_BIN;
+ wid.size = params->head_len + params->tail_len + 16;
+ wid.val = kzalloc(wid.size, GFP_KERNEL);
+ if (!wid.val)
+ return -ENOMEM;
+
+ cur_byte = wid.val;
+ put_unaligned_le32(interval, cur_byte);
+ cur_byte += 4;
+ put_unaligned_le32(dtim_period, cur_byte);
+ cur_byte += 4;
+ put_unaligned_le32(params->head_len, cur_byte);
+ cur_byte += 4;
+
+ if (params->head_len > 0)
+ memcpy(cur_byte, params->head, params->head_len);
+ cur_byte += params->head_len;
+
+ put_unaligned_le32(params->tail_len, cur_byte);
+ cur_byte += 4;
+
+ if (params->tail_len > 0)
+ memcpy(cur_byte, params->tail, params->tail_len);
+
+ result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
+ if (result)
+ netdev_err(vif->ndev, "Failed to send add beacon\n");
+
+ kfree(wid.val);
+
+ return result;
+}
+
+int wilc_del_beacon(struct wilc_vif *vif)
+{
+ int result;
+ struct wid wid;
+ u8 del_beacon = 0;
+
+ wid.id = WID_DEL_BEACON;
+ wid.type = WID_CHAR;
+ wid.size = sizeof(char);
+ wid.val = &del_beacon;
+
+ result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
+ if (result)
+ netdev_err(vif->ndev, "Failed to send delete beacon\n");
+
+ return result;
+}
+
+int wilc_add_station(struct wilc_vif *vif, const u8 *mac,
+ struct station_parameters *params)
+{
+ struct wid wid;
+ int result;
+ u8 *cur_byte;
+
+ wid.id = WID_ADD_STA;
+ wid.type = WID_BIN;
+ wid.size = WILC_ADD_STA_LENGTH + params->supported_rates_len;
+ wid.val = kmalloc(wid.size, GFP_KERNEL);
+ if (!wid.val)
+ return -ENOMEM;
+
+ cur_byte = wid.val;
+ wilc_hif_pack_sta_param(cur_byte, mac, params);
+
+ result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
+ if (result != 0)
+ netdev_err(vif->ndev, "Failed to send add station\n");
+
+ kfree(wid.val);
+
+ return result;
+}
+
+int wilc_del_station(struct wilc_vif *vif, const u8 *mac_addr)
+{
+ struct wid wid;
+ int result;
+
+ wid.id = WID_REMOVE_STA;
+ wid.type = WID_BIN;
+ wid.size = ETH_ALEN;
+ wid.val = kzalloc(wid.size, GFP_KERNEL);
+ if (!wid.val)
+ return -ENOMEM;
+
+ if (!mac_addr)
+ eth_broadcast_addr(wid.val);
+ else
+ ether_addr_copy(wid.val, mac_addr);
+
+ result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
+ if (result)
+ netdev_err(vif->ndev, "Failed to del station\n");
+
+ kfree(wid.val);
+
+ return result;
+}
+
+int wilc_del_allstation(struct wilc_vif *vif, u8 mac_addr[][ETH_ALEN])
+{
+ struct wid wid;
+ int result;
+ int i;
+ u8 assoc_sta = 0;
+ struct wilc_del_all_sta del_sta;
+
+ memset(&del_sta, 0x0, sizeof(del_sta));
+ for (i = 0; i < WILC_MAX_NUM_STA; i++) {
+ if (!is_zero_ether_addr(mac_addr[i])) {
+ assoc_sta++;
+ ether_addr_copy(del_sta.mac[i], mac_addr[i]);
+ }
+ }
+
+ if (!assoc_sta)
+ return 0;
+
+ del_sta.assoc_sta = assoc_sta;
+
+ wid.id = WID_DEL_ALL_STA;
+ wid.type = WID_STR;
+ wid.size = (assoc_sta * ETH_ALEN) + 1;
+ wid.val = (u8 *)&del_sta;
+
+ result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
+ if (result)
+ netdev_err(vif->ndev, "Failed to send delete all station\n");
+
+ return result;
+}
+
+int wilc_edit_station(struct wilc_vif *vif, const u8 *mac,
+ struct station_parameters *params)
+{
+ struct wid wid;
+ int result;
+ u8 *cur_byte;
+
+ wid.id = WID_EDIT_STA;
+ wid.type = WID_BIN;
+ wid.size = WILC_ADD_STA_LENGTH + params->supported_rates_len;
+ wid.val = kmalloc(wid.size, GFP_KERNEL);
+ if (!wid.val)
+ return -ENOMEM;
+
+ cur_byte = wid.val;
+ wilc_hif_pack_sta_param(cur_byte, mac, params);
+
+ result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
+ if (result)
+ netdev_err(vif->ndev, "Failed to send edit station\n");
+
+ kfree(wid.val);
+ return result;
+}
+
+int wilc_set_power_mgmt(struct wilc_vif *vif, bool enabled, u32 timeout)
+{
+ struct wid wid;
+ int result;
+ s8 power_mode;
+
+ if (wilc_wlan_get_num_conn_ifcs(vif->wilc) == 2 && enabled)
+ return 0;
+
+ if (enabled)
+ power_mode = WILC_FW_MIN_FAST_PS;
+ else
+ power_mode = WILC_FW_NO_POWERSAVE;
+
+ wid.id = WID_POWER_MANAGEMENT;
+ wid.val = &power_mode;
+ wid.size = sizeof(char);
+ result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
+ if (result)
+ netdev_err(vif->ndev, "Failed to send power management\n");
+
+ return result;
+}
+
+int wilc_setup_multicast_filter(struct wilc_vif *vif, u32 enabled, u32 count,
+ u8 *mc_list)
+{
+ int result;
+ struct host_if_msg *msg;
+
+ msg = wilc_alloc_work(vif, handle_set_mcast_filter, false);
+ if (IS_ERR(msg))
+ return PTR_ERR(msg);
+
+ msg->body.mc_info.enabled = enabled;
+ msg->body.mc_info.cnt = count;
+ msg->body.mc_info.mc_list = mc_list;
+
+ result = wilc_enqueue_work(msg);
+ if (result) {
+ netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__);
+ kfree(msg);
+ }
+ return result;
+}
+
+int wilc_set_tx_power(struct wilc_vif *vif, u8 tx_power)
+{
+ struct wid wid;
+
+ wid.id = WID_TX_POWER;
+ wid.type = WID_CHAR;
+ wid.val = &tx_power;
+ wid.size = sizeof(char);
+
+ return wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
+}
+
+int wilc_get_tx_power(struct wilc_vif *vif, u8 *tx_power)
+{
+ struct wid wid;
+
+ wid.id = WID_TX_POWER;
+ wid.type = WID_CHAR;
+ wid.val = tx_power;
+ wid.size = sizeof(char);
+
+ return wilc_send_config_pkt(vif, WILC_GET_CFG, &wid, 1);
+}
--
2.7.4
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox