Skip to content

Commit

Permalink
staging: brcm80211: simplification of brcmf_netdev_ioctl_priv()
Browse files Browse the repository at this point in the history
This function is only called from within the driver. Because of that
certain simplifications (not required to lock down user mem pages,
not required to check user permissions) could be performed.

Reviewed-by: Arend van Spriel <arend@broadcom.com>
Reviewed-by: Franky Lin <frankyl@broadcom.com>
Signed-off-by: Roland Vossen <rvossen@broadcom.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
  • Loading branch information
Roland Vossen authored and Greg Kroah-Hartman committed Sep 16, 2011
1 parent 9dd8eff commit 9af07ef
Show file tree
Hide file tree
Showing 3 changed files with 13 additions and 75 deletions.
14 changes: 2 additions & 12 deletions drivers/staging/brcm80211/brcmfmac/dhd.h
Original file line number Diff line number Diff line change
Expand Up @@ -715,7 +715,8 @@ extern struct brcmf_pub *brcmf_attach(struct brcmf_bus *bus,
extern int brcmf_net_attach(struct brcmf_pub *drvr, int idx);
extern int brcmf_netdev_wait_pend8021x(struct net_device *dev);

extern int brcmf_netdev_ioctl_priv(struct net_device *net, struct ifreq *ifr);
extern int brcmf_netdev_ioctl_priv(struct net_device *net,
struct brcmf_ioctl *ioc);

/* Indication from bus module regarding removal/absence of dongle */
extern void brcmf_detach(struct brcmf_pub *drvr);
Expand Down Expand Up @@ -771,17 +772,6 @@ extern void brcmf_c_pktfilter_offload_set(struct brcmf_pub *drvr, char *arg);
extern void brcmf_c_pktfilter_offload_enable(struct brcmf_pub *drvr, char *arg,
int enable, int master_mode);

/* Linux network driver ioctl encoding */
struct brcmf_c_ioctl {
uint cmd; /* common ioctl definition */
void __user *buf; /* pointer to user buffer */
uint len; /* length of user buffer */
bool set; /* get or set request (optional) */
uint used; /* bytes read or written (optional) */
uint needed; /* bytes needed (optional) */
uint driver; /* to identify target driver */
};

/* per-driver magic numbers */
#define BRCMF_IOCTL_MAGIC 0x00444944

Expand Down
69 changes: 10 additions & 59 deletions drivers/staging/brcm80211/brcmfmac/dhd_linux.c
Original file line number Diff line number Diff line change
Expand Up @@ -964,61 +964,19 @@ static int brcmf_netdev_ioctl_entry(struct net_device *net, struct ifreq *ifr,
return -EOPNOTSUPP;
}

/* called only from within this driver, handles cmd == SIOCDEVPRIVATE */
int brcmf_netdev_ioctl_priv(struct net_device *net, struct ifreq *ifr)
/* called only from within this driver */
int brcmf_netdev_ioctl_priv(struct net_device *net, struct brcmf_ioctl *ioc)
{
struct brcmf_c_ioctl ioc;
int bcmerror = 0;
int buflen = 0;
void *buf = NULL;
uint driver = 0;
bool is_set_key_cmd;
struct brcmf_info *drvr_priv = *(struct brcmf_info **) netdev_priv(net);
int ifidx;

ifidx = brcmf_net2idx(drvr_priv, net);

memset(&ioc, 0, sizeof(ioc));

/* Copy the ioc control structure part of ioctl request */
if (copy_from_user(&ioc, ifr->ifr_data, sizeof(struct brcmf_ioctl))) {
bcmerror = -EINVAL;
goto done;
}

/* Copy out any buffer passed */
if (ioc.buf) {
buflen = min_t(int, ioc.len, BRCMF_IOCTL_MAXLEN);
/* optimization for direct ioctl calls from kernel */
/*
if (segment_eq(get_fs(), KERNEL_DS)) {
buf = ioc.buf;
} else {
*/
{
buf = kmalloc(buflen, GFP_ATOMIC);
if (!buf) {
bcmerror = -ENOMEM;
goto done;
}
if (copy_from_user(buf, ioc.buf, buflen)) {
bcmerror = -EINVAL;
goto done;
}
}
}

/* To differentiate read 4 more byes */
if ((copy_from_user(&driver, (char __user *)ifr->ifr_data +
sizeof(struct brcmf_ioctl), sizeof(uint)) != 0)) {
bcmerror = -EINVAL;
goto done;
}

if (!capable(CAP_NET_ADMIN)) {
bcmerror = -EPERM;
goto done;
}
if (ioc->buf != NULL)
buflen = min_t(uint, ioc->len, BRCMF_IOCTL_MAXLEN);

/* send to dongle (must be up, and wl) */
if ((drvr_priv->pub.busstate != BRCMF_BUS_DATA)) {
Expand All @@ -1036,25 +994,18 @@ int brcmf_netdev_ioctl_priv(struct net_device *net, struct ifreq *ifr)
* Intercept BRCMF_C_SET_KEY IOCTL - serialize M4 send and
* set key IOCTL to prevent M4 encryption.
*/
is_set_key_cmd = ((ioc.cmd == BRCMF_C_SET_KEY) ||
((ioc.cmd == BRCMF_C_SET_VAR) &&
!(strncmp("wsec_key", ioc.buf, 9))) ||
((ioc.cmd == BRCMF_C_SET_VAR) &&
!(strncmp("bsscfg:wsec_key", ioc.buf, 15))));
is_set_key_cmd = ((ioc->cmd == BRCMF_C_SET_KEY) ||
((ioc->cmd == BRCMF_C_SET_VAR) &&
!(strncmp("wsec_key", ioc->buf, 9))) ||
((ioc->cmd == BRCMF_C_SET_VAR) &&
!(strncmp("bsscfg:wsec_key", ioc->buf, 15))));
if (is_set_key_cmd)
brcmf_netdev_wait_pend8021x(net);

bcmerror = brcmf_proto_ioctl(&drvr_priv->pub, ifidx,
(struct brcmf_ioctl *)&ioc, buf, buflen);
ioc, ioc->buf, buflen);

done:
if (!bcmerror && buf && ioc.buf) {
if (copy_to_user(ioc.buf, buf, buflen))
bcmerror = -EFAULT;
}

kfree(buf);

if (bcmerror > 0)
bcmerror = 0;

Expand Down
5 changes: 1 addition & 4 deletions drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,6 @@ static void convert_key_to_CPU(struct brcmf_wsec_key *key)
static s32
brcmf_dev_ioctl(struct net_device *dev, u32 cmd, void *arg, u32 len)
{
struct ifreq ifr;
struct brcmf_ioctl ioc;
mm_segment_t fs;
s32 err = 0;
Expand All @@ -281,12 +280,10 @@ brcmf_dev_ioctl(struct net_device *dev, u32 cmd, void *arg, u32 len)
ioc.cmd = cmd;
ioc.buf = arg;
ioc.len = len;
strcpy(ifr.ifr_name, dev->name);
ifr.ifr_data = (char __user *)&ioc;

fs = get_fs();
set_fs(get_ds());
err = brcmf_netdev_ioctl_priv(dev, &ifr);
err = brcmf_netdev_ioctl_priv(dev, &ioc);
set_fs(fs);

return err;
Expand Down

0 comments on commit 9af07ef

Please sign in to comment.