Forked from joanbm/broadcom-wl-fix-linux-5.10.patch
Created
January 25, 2021 23:15
-
-
Save razum2um/be1dd6bef759cb568b87bf7a774cbb92 to your computer and use it in GitHub Desktop.
Tentative patch for broadcom-wl 6.30.223.271 driver for Linux 5.10-rc1
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
From f3d652840f8dd959395065a1cf67ca40b04ec69b Mon Sep 17 00:00:00 2001 | |
From: Joan Bruguera <[email protected]> | |
Date: Tue, 13 Oct 2020 19:35:55 +0200 | |
Subject: [PATCH] Get rid of get_fs/set_fs calls in Broadcom WL driver. | |
Tentative patch for broadcom-wl 6.30.223.271 driver for Linux 5.10 (tested -rc1 up to 5.10.1) | |
Applies on top of all the patches applied to broadcom-wl-dkms 6.30.223.271-23 on Arch Linux. | |
NB: Some checks in wlc_ioctl_internal are likely superfluous, | |
but I'm not familiar enough with the driver to remove them with confidence. | |
See also: https://lwn.net/Articles/722267/ | |
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=47058bb54b57962b3958a936ddbc59355e4c5504 | |
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=5e6e9852d6f76e01b2e6803c74258afa5b432bc5 | |
Signed-off-by: Joan Bruguera <[email protected]> | |
--- | |
src/wl/sys/wl_cfg80211_hybrid.c | 25 ++------------------- | |
src/wl/sys/wl_iw.c | 25 ++------------------- | |
src/wl/sys/wl_linux.c | 40 ++++++++++++++++++++++++++++----- | |
src/wl/sys/wl_linux.h | 2 ++ | |
src/wl/sys/wlc_pub.h | 1 + | |
5 files changed, 42 insertions(+), 51 deletions(-) | |
diff --git a/src/wl/sys/wl_cfg80211_hybrid.c b/src/wl/sys/wl_cfg80211_hybrid.c | |
index 73c4b82..2e6df32 100644 | |
--- a/src/wl/sys/wl_cfg80211_hybrid.c | |
+++ b/src/wl/sys/wl_cfg80211_hybrid.c | |
@@ -38,6 +38,7 @@ | |
#include <wlioctl.h> | |
#include <proto/802.11.h> | |
#include <wl_cfg80211_hybrid.h> | |
+#include <wl_linux.h> | |
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0) | |
#include <linux/sched/signal.h> | |
@@ -443,30 +444,8 @@ static void key_endian_to_host(struct wl_wsec_key *key) | |
static s32 | |
wl_dev_ioctl(struct net_device *dev, u32 cmd, void *arg, u32 len) | |
{ | |
- struct ifreq ifr; | |
- struct wl_ioctl ioc; | |
- mm_segment_t fs; | |
- s32 err = 0; | |
- | |
BUG_ON(len < sizeof(int)); | |
- | |
- memset(&ioc, 0, sizeof(ioc)); | |
- ioc.cmd = cmd; | |
- ioc.buf = arg; | |
- ioc.len = len; | |
- strcpy(ifr.ifr_name, dev->name); | |
- ifr.ifr_data = (caddr_t)&ioc; | |
- | |
- fs = get_fs(); | |
- set_fs(KERNEL_DS); | |
-#if defined(WL_USE_NETDEV_OPS) | |
- err = dev->netdev_ops->ndo_do_ioctl(dev, &ifr, SIOCDEVPRIVATE); | |
-#else | |
- err = dev->do_ioctl(dev, &ifr, SIOCDEVPRIVATE); | |
-#endif | |
- set_fs(fs); | |
- | |
- return err; | |
+ return wlc_ioctl_internal(dev, cmd, arg, len); | |
} | |
static s32 | |
diff --git a/src/wl/sys/wl_iw.c b/src/wl/sys/wl_iw.c | |
index 9c3c74e..e346b15 100644 | |
--- a/src/wl/sys/wl_iw.c | |
+++ b/src/wl/sys/wl_iw.c | |
@@ -37,6 +37,7 @@ typedef const struct si_pub si_t; | |
#include <wl_dbg.h> | |
#include <wl_iw.h> | |
+#include <wl_linux.h> | |
extern bool wl_iw_conn_status_str(uint32 event_type, uint32 status, | |
uint32 reason, char* stringBuf, uint buflen); | |
@@ -103,29 +104,7 @@ dev_wlc_ioctl( | |
int len | |
) | |
{ | |
- struct ifreq ifr; | |
- wl_ioctl_t ioc; | |
- mm_segment_t fs; | |
- int ret; | |
- | |
- memset(&ioc, 0, sizeof(ioc)); | |
- ioc.cmd = cmd; | |
- ioc.buf = arg; | |
- ioc.len = len; | |
- | |
- strcpy(ifr.ifr_name, dev->name); | |
- ifr.ifr_data = (caddr_t) &ioc; | |
- | |
- fs = get_fs(); | |
- set_fs(KERNEL_DS); | |
-#if defined(WL_USE_NETDEV_OPS) | |
- ret = dev->netdev_ops->ndo_do_ioctl(dev, &ifr, SIOCDEVPRIVATE); | |
-#else | |
- ret = dev->do_ioctl(dev, &ifr, SIOCDEVPRIVATE); | |
-#endif | |
- set_fs(fs); | |
- | |
- return ret; | |
+ return wlc_ioctl_internal(dev, cmd, arg, len); | |
} | |
static int | |
diff --git a/src/wl/sys/wl_linux.c b/src/wl/sys/wl_linux.c | |
index cca7ee1..e491df7 100644 | |
--- a/src/wl/sys/wl_linux.c | |
+++ b/src/wl/sys/wl_linux.c | |
@@ -1647,10 +1647,7 @@ wl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | |
goto done2; | |
} | |
- if (get_fs().seg == KERNEL_DS.seg) | |
- buf = ioc.buf; | |
- | |
- else if (ioc.buf) { | |
+ if (ioc.buf) { | |
if (!(buf = (void *) MALLOC(wl->osh, MAX(ioc.len, WLC_IOCTL_MAXLEN)))) { | |
bcmerror = BCME_NORESOURCE; | |
goto done2; | |
@@ -1671,7 +1668,7 @@ wl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | |
WL_UNLOCK(wl); | |
done1: | |
- if (ioc.buf && (ioc.buf != buf)) { | |
+ if (ioc.buf) { | |
if (copy_to_user(ioc.buf, buf, ioc.len)) | |
bcmerror = BCME_BADADDR; | |
MFREE(wl->osh, buf, MAX(ioc.len, WLC_IOCTL_MAXLEN)); | |
@@ -1684,6 +1681,39 @@ done2: | |
return (OSL_ERROR(bcmerror)); | |
} | |
+int | |
+wlc_ioctl_internal(struct net_device *dev, int cmd, void *buf, int len) | |
+{ | |
+ wl_info_t *wl; | |
+ wl_if_t *wlif; | |
+ int bcmerror; | |
+ | |
+ if (!dev) | |
+ return -ENETDOWN; | |
+ | |
+ wl = WL_INFO(dev); | |
+ wlif = WL_DEV_IF(dev); | |
+ if (wlif == NULL || wl == NULL || wl->dev == NULL) | |
+ return -ENETDOWN; | |
+ | |
+ bcmerror = 0; | |
+ | |
+ WL_TRACE(("wl%d: wlc_ioctl_internal: cmd 0x%x\n", wl->pub->unit, cmd)); | |
+ | |
+ WL_LOCK(wl); | |
+ if (!capable(CAP_NET_ADMIN)) { | |
+ bcmerror = BCME_EPERM; | |
+ } else { | |
+ bcmerror = wlc_ioctl(wl->wlc, cmd, buf, len, wlif->wlcif); | |
+ } | |
+ WL_UNLOCK(wl); | |
+ | |
+ ASSERT(VALID_BCMERROR(bcmerror)); | |
+ if (bcmerror != 0) | |
+ wl->pub->bcmerror = bcmerror; | |
+ return (OSL_ERROR(bcmerror)); | |
+} | |
+ | |
static struct net_device_stats* | |
wl_get_stats(struct net_device *dev) | |
{ | |
diff --git a/src/wl/sys/wl_linux.h b/src/wl/sys/wl_linux.h | |
index 5b1048e..c8c1f41 100644 | |
--- a/src/wl/sys/wl_linux.h | |
+++ b/src/wl/sys/wl_linux.h | |
@@ -22,6 +22,7 @@ | |
#define _wl_linux_h_ | |
#include <wlc_types.h> | |
+#include <wlc_pub.h> | |
typedef struct wl_timer { | |
struct timer_list timer; | |
@@ -187,6 +188,7 @@ extern irqreturn_t wl_isr(int irq, void *dev_id, struct pt_regs *ptregs); | |
extern int __devinit wl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent); | |
extern void wl_free(wl_info_t *wl); | |
extern int wl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); | |
+extern int wlc_ioctl_internal(struct net_device *dev, int cmd, void *buf, int len); | |
extern struct net_device * wl_netdev_get(wl_info_t *wl); | |
#endif | |
diff --git a/src/wl/sys/wlc_pub.h b/src/wl/sys/wlc_pub.h | |
index 53a98b8..2b5a029 100644 | |
--- a/src/wl/sys/wlc_pub.h | |
+++ b/src/wl/sys/wlc_pub.h | |
@@ -24,6 +24,7 @@ | |
#include <wlc_types.h> | |
#include <wlc_utils.h> | |
+#include <siutils.h> | |
#include "proto/802.11.h" | |
#include "proto/bcmevent.h" | |
-- | |
2.28.0 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment