* [WEXT 11/12]: Create IW_REQUEST_FLAG_COMPAT and set it as needed.
From: David Miller @ 2007-12-22 4:57 UTC (permalink / raw)
To: linux-wireless; +Cc: netdev
[WEXT]: Create IW_REQUEST_FLAG_COMPAT and set it as needed.
Now low-level WEXT ioctl handlers can do compat handling
when necessary.
Signed-off-by: David S. Miller <davem@davemloft.net>
---
include/net/iw_handler.h | 2 +-
net/wireless/wext.c | 73 +++++++++++++++++++++-------------------------
2 files changed, 34 insertions(+), 41 deletions(-)
diff --git a/include/net/iw_handler.h b/include/net/iw_handler.h
index 369d50e..c99a8ee 100644
--- a/include/net/iw_handler.h
+++ b/include/net/iw_handler.h
@@ -256,7 +256,7 @@
#define EIWCOMMIT EINPROGRESS
/* Flags available in struct iw_request_info */
-#define IW_REQUEST_FLAG_NONE 0x0000 /* No flag so far */
+#define IW_REQUEST_FLAG_COMPAT 0x0001 /* Compat ioctl call */
/* Type of headers we know about (basically union iwreq_data) */
#define IW_HEADER_TYPE_NULL 0 /* Not available */
diff --git a/net/wireless/wext.c b/net/wireless/wext.c
index 5869b70..b7f5973 100644
--- a/net/wireless/wext.c
+++ b/net/wireless/wext.c
@@ -866,10 +866,10 @@ out:
static int ioctl_standard_call(struct net_device * dev,
struct iwreq * iwr,
unsigned int cmd,
+ struct iw_request_info *info,
iw_handler handler)
{
const struct iw_ioctl_description * descr;
- struct iw_request_info info;
int ret = -EINVAL;
/* Get the description of the IOCTL */
@@ -877,15 +877,11 @@ static int ioctl_standard_call(struct net_device * dev,
return -EOPNOTSUPP;
descr = &(standard_ioctl[cmd - SIOCIWFIRST]);
- /* Prepare the call */
- info.cmd = cmd;
- info.flags = 0;
-
/* Check if we have a pointer to user space data or not */
if (descr->header_type != IW_HEADER_TYPE_POINT) {
/* No extra arguments. Trivial to handle */
- ret = handler(dev, &info, &(iwr->u), NULL);
+ ret = handler(dev, info, &(iwr->u), NULL);
/* Generate an event to notify listeners of the change */
if ((descr->flags & IW_DESCR_FLAG_EVENT) &&
@@ -893,7 +889,7 @@ static int ioctl_standard_call(struct net_device * dev,
wireless_send_event(dev, cmd, &(iwr->u), NULL);
} else {
ret = ioctl_standard_iw_point(&iwr->u.data, cmd, descr,
- handler, dev, &info);
+ handler, dev, info);
}
/* Call commit handler if needed and defined */
@@ -1016,25 +1012,21 @@ out:
}
static int ioctl_private_call(struct net_device *dev, struct iwreq *iwr,
- unsigned int cmd, iw_handler handler)
+ unsigned int cmd, struct iw_request_info *info,
+ iw_handler handler)
{
int extra_size = 0, ret = -EINVAL;
const struct iw_priv_args *descr;
- struct iw_request_info info;
extra_size = get_priv_descr_and_size(dev, cmd, &descr);
- /* Prepare the call */
- info.cmd = cmd;
- info.flags = 0;
-
/* Check if we have a pointer to user space data or not. */
if (extra_size == 0) {
/* No extra arguments. Trivial to handle */
- ret = handler(dev, &info, &(iwr->u), (char *) &(iwr->u));
+ ret = handler(dev, info, &(iwr->u), (char *) &(iwr->u));
} else {
ret = ioctl_private_iw_point(&iwr->u.data, cmd, descr,
- handler, dev, &info, extra_size);
+ handler, dev, info, extra_size);
}
/* Call commit handler if needed and defined */
@@ -1046,7 +1038,8 @@ static int ioctl_private_call(struct net_device *dev, struct iwreq *iwr,
/* ---------------------------------------------------------------- */
typedef int (*wext_ioctl_func)(struct net_device *, struct iwreq *,
- unsigned int, iw_handler);
+ unsigned int, struct iw_request_info *,
+ iw_handler);
/*
* Main IOCTl dispatcher.
@@ -1054,6 +1047,7 @@ typedef int (*wext_ioctl_func)(struct net_device *, struct iwreq *,
*/
static int wireless_process_ioctl(struct net *net, struct ifreq *ifr,
unsigned int cmd,
+ struct iw_request_info *info,
wext_ioctl_func standard,
wext_ioctl_func private)
{
@@ -1072,11 +1066,11 @@ static int wireless_process_ioctl(struct net *net, struct ifreq *ifr,
* Note that 'cmd' is already filtered in dev_ioctl() with
* (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) */
if (cmd == SIOCGIWSTATS)
- return standard(dev, iwr, cmd,
+ return standard(dev, iwr, cmd, info,
&iw_handler_get_iwstats);
if (cmd == SIOCGIWPRIV && dev->wireless_handlers)
- return standard(dev, iwr, cmd,
+ return standard(dev, iwr, cmd, info,
&iw_handler_get_private);
/* Basic check */
@@ -1088,9 +1082,9 @@ static int wireless_process_ioctl(struct net *net, struct ifreq *ifr,
if (handler) {
/* Standard and private are not the same */
if (cmd < SIOCIWFIRSTPRIV)
- return standard(dev, iwr, cmd, handler);
+ return standard(dev, iwr, cmd, info, handler);
else
- return private(dev, iwr, cmd, handler);
+ return private(dev, iwr, cmd, info, handler);
}
/* Old driver API : call driver ioctl handler */
if (dev->do_ioctl)
@@ -1112,7 +1106,7 @@ static int wext_permission_check(unsigned int cmd)
/* entry point from dev ioctl */
static int wext_ioctl_dispatch(struct net *net, struct ifreq *ifr,
- unsigned int cmd,
+ unsigned int cmd, struct iw_request_info *info,
wext_ioctl_func standard,
wext_ioctl_func private)
{
@@ -1123,7 +1117,7 @@ static int wext_ioctl_dispatch(struct net *net, struct ifreq *ifr,
dev_load(net, ifr->ifr_name);
rtnl_lock();
- ret = wireless_process_ioctl(net, ifr, cmd, standard, private);
+ ret = wireless_process_ioctl(net, ifr, cmd, info, standard, private);
rtnl_unlock();
return ret;
@@ -1132,10 +1126,12 @@ static int wext_ioctl_dispatch(struct net *net, struct ifreq *ifr,
int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd,
void __user *arg)
{
- int ret = wext_ioctl_dispatch(net, ifr, cmd,
- ioctl_standard_call,
- ioctl_private_call);
+ struct iw_request_info info = { .cmd = cmd, .flags = 0 };
+ int ret;
+ ret = wext_ioctl_dispatch(net, ifr, cmd, &info,
+ ioctl_standard_call,
+ ioctl_private_call);
if (ret > 0 &&
IW_IS_GET(cmd) &&
copy_to_user(arg, ifr, sizeof(struct iwreq)))
@@ -1148,28 +1144,25 @@ int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd,
static int compat_standard_call(struct net_device * dev,
struct iwreq * iwr,
unsigned int cmd,
+ struct iw_request_info *info,
iw_handler handler)
{
const struct iw_ioctl_description *descr;
struct compat_iw_point *iwp_compat;
- struct iw_request_info info;
struct iw_point iwp;
int err;
descr = standard_ioctl + (cmd - SIOCIWFIRST);
if (descr->header_type != IW_HEADER_TYPE_POINT)
- return ioctl_standard_call(dev, iwr, cmd, handler);
+ return ioctl_standard_call(dev, iwr, cmd, info, handler);
iwp_compat = (struct compat_iw_point *) &iwr->u.data;
iwp.pointer = compat_ptr(iwp_compat->pointer);
iwp.length = iwp_compat->length;
iwp.flags = iwp_compat->flags;
- info.cmd = cmd;
- info.flags = 0;
-
- err = ioctl_standard_iw_point(&iwp, cmd, descr, handler, dev, &info);
+ err = ioctl_standard_iw_point(&iwp, cmd, descr, handler, dev, info);
iwp_compat->pointer = ptr_to_compat(iwp.pointer);
iwp_compat->length = iwp.length;
@@ -1179,22 +1172,18 @@ static int compat_standard_call(struct net_device * dev,
}
static int compat_private_call(struct net_device *dev, struct iwreq *iwr,
- unsigned int cmd, iw_handler handler)
+ unsigned int cmd, struct iw_request_info *info,
+ iw_handler handler)
{
const struct iw_priv_args *descr;
- struct iw_request_info info;
int ret, extra_size;
extra_size = get_priv_descr_and_size(dev, cmd, &descr);
- /* Prepare the call */
- info.cmd = cmd;
- info.flags = 0;
-
/* Check if we have a pointer to user space data or not. */
if (extra_size == 0) {
/* No extra arguments. Trivial to handle */
- ret = handler(dev, &info, &(iwr->u), (char *) &(iwr->u));
+ ret = handler(dev, info, &(iwr->u), (char *) &(iwr->u));
} else {
struct compat_iw_point *iwp_compat;
struct iw_point iwp;
@@ -1205,7 +1194,7 @@ static int compat_private_call(struct net_device *dev, struct iwreq *iwr,
iwp.flags = iwp_compat->flags;
ret = ioctl_private_iw_point(&iwp, cmd, descr,
- handler, dev, &info, extra_size);
+ handler, dev, info, extra_size);
iwp_compat->pointer = ptr_to_compat(iwp.pointer);
iwp_compat->length = iwp.length;
@@ -1223,6 +1212,7 @@ int compat_wext_handle_ioctl(struct net *net, unsigned int cmd,
unsigned long arg)
{
void __user *argp = (void __user *)arg;
+ struct iw_request_info info;
struct iwreq iwr;
char *colon;
int ret;
@@ -1235,7 +1225,10 @@ int compat_wext_handle_ioctl(struct net *net, unsigned int cmd,
if (colon)
*colon = 0;
- ret = wext_ioctl_dispatch(net, (struct ifreq *) &iwr, cmd,
+ info.cmd = cmd;
+ info.flags = IW_REQUEST_FLAG_COMPAT;
+
+ ret = wext_ioctl_dispatch(net, (struct ifreq *) &iwr, cmd, &info,
compat_standard_call,
compat_private_call);
--
1.5.4.rc1
^ permalink raw reply related
* [WEXT 10/12]: Remove compat handling from fs/compat_ioctl.c
From: David Miller @ 2007-12-22 4:57 UTC (permalink / raw)
To: linux-wireless-u79uwXL29TY76Z2rM5mHXA; +Cc: netdev-u79uwXL29TY76Z2rM5mHXA
[WEXT]: Remove compat handling from fs/compat_ioctl.c
No longer used.
Signed-off-by: David S. Miller <davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org>
---
fs/compat_ioctl.c | 107 +----------------------------------------------------
1 files changed, 1 insertions(+), 106 deletions(-)
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index e98e950..809dc56 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -56,7 +56,6 @@
#include <linux/syscalls.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
-#include <linux/wireless.h>
#include <linux/atalk.h>
#include <linux/loop.h>
@@ -1756,58 +1755,6 @@ static int do_i2c_smbus_ioctl(unsigned int fd, unsigned int cmd, unsigned long a
return sys_ioctl(fd, cmd, (unsigned long)tdata);
}
-static int do_wireless_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
- struct iwreq __user *iwr;
- struct iwreq __user *iwr_u;
- struct iw_point __user *iwp;
- struct compat_iw_point __user *iwp_u;
- compat_caddr_t pointer_u;
- void __user *pointer;
- __u16 length, flags;
- int ret;
-
- iwr_u = compat_ptr(arg);
- iwp_u = (struct compat_iw_point __user *) &iwr_u->u.data;
- iwr = compat_alloc_user_space(sizeof(*iwr));
- if (iwr == NULL)
- return -ENOMEM;
-
- iwp = &iwr->u.data;
-
- if (!access_ok(VERIFY_WRITE, iwr, sizeof(*iwr)))
- return -EFAULT;
-
- if (__copy_in_user(&iwr->ifr_ifrn.ifrn_name[0],
- &iwr_u->ifr_ifrn.ifrn_name[0],
- sizeof(iwr->ifr_ifrn.ifrn_name)))
- return -EFAULT;
-
- if (__get_user(pointer_u, &iwp_u->pointer) ||
- __get_user(length, &iwp_u->length) ||
- __get_user(flags, &iwp_u->flags))
- return -EFAULT;
-
- if (__put_user(compat_ptr(pointer_u), &iwp->pointer) ||
- __put_user(length, &iwp->length) ||
- __put_user(flags, &iwp->flags))
- return -EFAULT;
-
- ret = sys_ioctl(fd, cmd, (unsigned long) iwr);
-
- if (__get_user(pointer, &iwp->pointer) ||
- __get_user(length, &iwp->length) ||
- __get_user(flags, &iwp->flags))
- return -EFAULT;
-
- if (__put_user(ptr_to_compat(pointer), &iwp_u->pointer) ||
- __put_user(length, &iwp_u->length) ||
- __put_user(flags, &iwp_u->flags))
- return -EFAULT;
-
- return ret;
-}
-
/* Since old style bridge ioctl's endup using SIOCDEVPRIVATE
* for some operations; this forces use of the newer bridge-utils that
* use compatiable ioctls
@@ -2521,36 +2468,6 @@ COMPATIBLE_IOCTL(I2C_TENBIT)
COMPATIBLE_IOCTL(I2C_PEC)
COMPATIBLE_IOCTL(I2C_RETRIES)
COMPATIBLE_IOCTL(I2C_TIMEOUT)
-/* wireless */
-COMPATIBLE_IOCTL(SIOCSIWCOMMIT)
-COMPATIBLE_IOCTL(SIOCGIWNAME)
-COMPATIBLE_IOCTL(SIOCSIWNWID)
-COMPATIBLE_IOCTL(SIOCGIWNWID)
-COMPATIBLE_IOCTL(SIOCSIWFREQ)
-COMPATIBLE_IOCTL(SIOCGIWFREQ)
-COMPATIBLE_IOCTL(SIOCSIWMODE)
-COMPATIBLE_IOCTL(SIOCGIWMODE)
-COMPATIBLE_IOCTL(SIOCSIWSENS)
-COMPATIBLE_IOCTL(SIOCGIWSENS)
-COMPATIBLE_IOCTL(SIOCSIWRANGE)
-COMPATIBLE_IOCTL(SIOCSIWPRIV)
-COMPATIBLE_IOCTL(SIOCSIWSTATS)
-COMPATIBLE_IOCTL(SIOCSIWAP)
-COMPATIBLE_IOCTL(SIOCGIWAP)
-COMPATIBLE_IOCTL(SIOCSIWRATE)
-COMPATIBLE_IOCTL(SIOCGIWRATE)
-COMPATIBLE_IOCTL(SIOCSIWRTS)
-COMPATIBLE_IOCTL(SIOCGIWRTS)
-COMPATIBLE_IOCTL(SIOCSIWFRAG)
-COMPATIBLE_IOCTL(SIOCGIWFRAG)
-COMPATIBLE_IOCTL(SIOCSIWTXPOW)
-COMPATIBLE_IOCTL(SIOCGIWTXPOW)
-COMPATIBLE_IOCTL(SIOCSIWRETRY)
-COMPATIBLE_IOCTL(SIOCGIWRETRY)
-COMPATIBLE_IOCTL(SIOCSIWPOWER)
-COMPATIBLE_IOCTL(SIOCGIWPOWER)
-COMPATIBLE_IOCTL(SIOCSIWAUTH)
-COMPATIBLE_IOCTL(SIOCGIWAUTH)
/* hiddev */
COMPATIBLE_IOCTL(HIDIOCGVERSION)
COMPATIBLE_IOCTL(HIDIOCAPPLICATION)
@@ -2775,29 +2692,7 @@ COMPATIBLE_IOCTL(USBDEVFS_IOCTL32)
HANDLE_IOCTL(I2C_FUNCS, w_long)
HANDLE_IOCTL(I2C_RDWR, do_i2c_rdwr_ioctl)
HANDLE_IOCTL(I2C_SMBUS, do_i2c_smbus_ioctl)
-/* wireless */
-HANDLE_IOCTL(SIOCGIWRANGE, do_wireless_ioctl)
-HANDLE_IOCTL(SIOCGIWPRIV, do_wireless_ioctl)
-HANDLE_IOCTL(SIOCGIWSTATS, do_wireless_ioctl)
-HANDLE_IOCTL(SIOCSIWSPY, do_wireless_ioctl)
-HANDLE_IOCTL(SIOCGIWSPY, do_wireless_ioctl)
-HANDLE_IOCTL(SIOCSIWTHRSPY, do_wireless_ioctl)
-HANDLE_IOCTL(SIOCGIWTHRSPY, do_wireless_ioctl)
-HANDLE_IOCTL(SIOCSIWMLME, do_wireless_ioctl)
-HANDLE_IOCTL(SIOCGIWAPLIST, do_wireless_ioctl)
-HANDLE_IOCTL(SIOCSIWSCAN, do_wireless_ioctl)
-HANDLE_IOCTL(SIOCGIWSCAN, do_wireless_ioctl)
-HANDLE_IOCTL(SIOCSIWESSID, do_wireless_ioctl)
-HANDLE_IOCTL(SIOCGIWESSID, do_wireless_ioctl)
-HANDLE_IOCTL(SIOCSIWNICKN, do_wireless_ioctl)
-HANDLE_IOCTL(SIOCGIWNICKN, do_wireless_ioctl)
-HANDLE_IOCTL(SIOCSIWENCODE, do_wireless_ioctl)
-HANDLE_IOCTL(SIOCGIWENCODE, do_wireless_ioctl)
-HANDLE_IOCTL(SIOCSIWGENIE, do_wireless_ioctl)
-HANDLE_IOCTL(SIOCGIWGENIE, do_wireless_ioctl)
-HANDLE_IOCTL(SIOCSIWENCODEEXT, do_wireless_ioctl)
-HANDLE_IOCTL(SIOCGIWENCODEEXT, do_wireless_ioctl)
-HANDLE_IOCTL(SIOCSIWPMKSA, do_wireless_ioctl)
+/* bridge */
HANDLE_IOCTL(SIOCSIFBR, old_bridge_ioctl)
HANDLE_IOCTL(SIOCGIFBR, old_bridge_ioctl)
/* Not implemented in the native kernel */
--
1.5.4.rc1
^ permalink raw reply related
* [WEXT 9/12]: Dispatch and handle compat ioctls entirely in net/wireless/wext.c
From: David Miller @ 2007-12-22 4:56 UTC (permalink / raw)
To: linux-wireless; +Cc: netdev
[WEXT]: Dispatch and handle compat ioctls entirely in net/wireless/wext.c
Next we can kill the hacks in fs/compat_ioctl.c and also
dispatch compat ioctls down into the driver and 80211 protocol
helper layers in order to handle iw_point objects embedded in
stream replies which need to be translated.
Signed-off-by: David S. Miller <davem@davemloft.net>
---
fs/compat_ioctl.c | 6 ---
include/linux/wireless.h | 9 ++++
include/net/wext.h | 7 +++
net/socket.c | 10 ++++
net/wireless/wext.c | 104 ++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 130 insertions(+), 6 deletions(-)
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index e8b7c3a..e98e950 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -1756,12 +1756,6 @@ static int do_i2c_smbus_ioctl(unsigned int fd, unsigned int cmd, unsigned long a
return sys_ioctl(fd, cmd, (unsigned long)tdata);
}
-struct compat_iw_point {
- compat_caddr_t pointer;
- __u16 length;
- __u16 flags;
-};
-
static int do_wireless_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
{
struct iwreq __user *iwr;
diff --git a/include/linux/wireless.h b/include/linux/wireless.h
index 0987aa7..2088524 100644
--- a/include/linux/wireless.h
+++ b/include/linux/wireless.h
@@ -76,6 +76,7 @@
#include <linux/types.h> /* for "caddr_t" et al */
#include <linux/socket.h> /* for "struct sockaddr" et al */
#include <linux/if.h> /* for IFNAMSIZ and co... */
+#include <linux/compat.h>
#endif /* __KERNEL__ */
/***************************** VERSION *****************************/
@@ -669,6 +670,14 @@ struct iw_point
__u16 flags; /* Optional params */
};
+#if defined(__KERNEL__) && defined(CONFIG_COMPAT)
+struct compat_iw_point {
+ compat_caddr_t pointer;
+ __u16 length;
+ __u16 flags;
+};
+#endif
+
/*
* A frequency
* For numbers lower than 10^9, we encode the number in 'm' and
diff --git a/include/net/wext.h b/include/net/wext.h
index 80b31d8..6d76a39 100644
--- a/include/net/wext.h
+++ b/include/net/wext.h
@@ -12,6 +12,8 @@ extern int wext_proc_init(struct net *net);
extern void wext_proc_exit(struct net *net);
extern int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd,
void __user *arg);
+extern int compat_wext_handle_ioctl(struct net *net, unsigned int cmd,
+ unsigned long arg);
#else
static inline int wext_proc_init(struct net *net)
{
@@ -26,6 +28,11 @@ static inline int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned
{
return -EINVAL;
}
+static inline int compat_wext_handle_ioctl(struct net *net, unsigned int cmd,
+ unsigned long arg)
+{
+ return -EINVAL;
+}
#endif
#endif /* __NET_WEXT_H */
diff --git a/net/socket.c b/net/socket.c
index 74784df..475f08f 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -90,6 +90,7 @@
#include <asm/unistd.h>
#include <net/compat.h>
+#include <net/wext.h>
#include <net/sock.h>
#include <linux/netfilter.h>
@@ -2207,10 +2208,19 @@ static long compat_sock_ioctl(struct file *file, unsigned cmd,
{
struct socket *sock = file->private_data;
int ret = -ENOIOCTLCMD;
+ struct sock *sk;
+ struct net *net;
+
+ sk = sock->sk;
+ net = sk->sk_net;
if (sock->ops->compat_ioctl)
ret = sock->ops->compat_ioctl(sock, cmd, arg);
+ if (ret == -ENOIOCTLCMD &&
+ (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST))
+ ret = compat_wext_handle_ioctl(net, cmd, arg);
+
return ret;
}
#endif
diff --git a/net/wireless/wext.c b/net/wireless/wext.c
index 03b0051..5869b70 100644
--- a/net/wireless/wext.c
+++ b/net/wireless/wext.c
@@ -1144,6 +1144,110 @@ int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd,
return ret;
}
+#ifdef CONFIG_COMPAT
+static int compat_standard_call(struct net_device * dev,
+ struct iwreq * iwr,
+ unsigned int cmd,
+ iw_handler handler)
+{
+ const struct iw_ioctl_description *descr;
+ struct compat_iw_point *iwp_compat;
+ struct iw_request_info info;
+ struct iw_point iwp;
+ int err;
+
+ descr = standard_ioctl + (cmd - SIOCIWFIRST);
+
+ if (descr->header_type != IW_HEADER_TYPE_POINT)
+ return ioctl_standard_call(dev, iwr, cmd, handler);
+
+ iwp_compat = (struct compat_iw_point *) &iwr->u.data;
+ iwp.pointer = compat_ptr(iwp_compat->pointer);
+ iwp.length = iwp_compat->length;
+ iwp.flags = iwp_compat->flags;
+
+ info.cmd = cmd;
+ info.flags = 0;
+
+ err = ioctl_standard_iw_point(&iwp, cmd, descr, handler, dev, &info);
+
+ iwp_compat->pointer = ptr_to_compat(iwp.pointer);
+ iwp_compat->length = iwp.length;
+ iwp_compat->flags = iwp.flags;
+
+ return err;
+}
+
+static int compat_private_call(struct net_device *dev, struct iwreq *iwr,
+ unsigned int cmd, iw_handler handler)
+{
+ const struct iw_priv_args *descr;
+ struct iw_request_info info;
+ int ret, extra_size;
+
+ extra_size = get_priv_descr_and_size(dev, cmd, &descr);
+
+ /* Prepare the call */
+ info.cmd = cmd;
+ info.flags = 0;
+
+ /* Check if we have a pointer to user space data or not. */
+ if (extra_size == 0) {
+ /* No extra arguments. Trivial to handle */
+ ret = handler(dev, &info, &(iwr->u), (char *) &(iwr->u));
+ } else {
+ struct compat_iw_point *iwp_compat;
+ struct iw_point iwp;
+
+ iwp_compat = (struct compat_iw_point *) &iwr->u.data;
+ iwp.pointer = compat_ptr(iwp_compat->pointer);
+ iwp.length = iwp_compat->length;
+ iwp.flags = iwp_compat->flags;
+
+ ret = ioctl_private_iw_point(&iwp, cmd, descr,
+ handler, dev, &info, extra_size);
+
+ iwp_compat->pointer = ptr_to_compat(iwp.pointer);
+ iwp_compat->length = iwp.length;
+ iwp_compat->flags = iwp.flags;
+ }
+
+ /* Call commit handler if needed and defined */
+ if (ret == -EIWCOMMIT)
+ ret = call_commit_handler(dev);
+
+ return ret;
+}
+
+int compat_wext_handle_ioctl(struct net *net, unsigned int cmd,
+ unsigned long arg)
+{
+ void __user *argp = (void __user *)arg;
+ struct iwreq iwr;
+ char *colon;
+ int ret;
+
+ if (copy_from_user(&iwr, argp, sizeof(struct iwreq)))
+ return -EFAULT;
+
+ iwr.ifr_name[IFNAMSIZ-1] = 0;
+ colon = strchr(iwr.ifr_name, ':');
+ if (colon)
+ *colon = 0;
+
+ ret = wext_ioctl_dispatch(net, (struct ifreq *) &iwr, cmd,
+ compat_standard_call,
+ compat_private_call);
+
+ if (ret > 0 &&
+ IW_IS_GET(cmd) &&
+ copy_to_user(argp, &iwr, sizeof(struct iwreq)))
+ return -EFAULT;
+
+ return ret;
+}
+#endif
+
/************************* EVENT PROCESSING *************************/
/*
* Process events generated by the wireless layer or the driver.
--
1.5.4.rc1
^ permalink raw reply related
* [WEXT 8/12]: Pull top-level ioctl dispatch logic into helper function.
From: David Miller @ 2007-12-22 4:56 UTC (permalink / raw)
To: linux-wireless-u79uwXL29TY76Z2rM5mHXA; +Cc: netdev-u79uwXL29TY76Z2rM5mHXA
[WEXT]: Pull top-level ioctl dispatch logic into helper function.
Signed-off-by: David S. Miller <davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org>
---
net/wireless/wext.c | 26 ++++++++++++++++++++------
1 files changed, 20 insertions(+), 6 deletions(-)
diff --git a/net/wireless/wext.c b/net/wireless/wext.c
index 18fa13c..03b0051 100644
--- a/net/wireless/wext.c
+++ b/net/wireless/wext.c
@@ -1111,8 +1111,10 @@ static int wext_permission_check(unsigned int cmd)
}
/* entry point from dev ioctl */
-int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd,
- void __user *arg)
+static int wext_ioctl_dispatch(struct net *net, struct ifreq *ifr,
+ unsigned int cmd,
+ wext_ioctl_func standard,
+ wext_ioctl_func private)
{
int ret = wext_permission_check(cmd);
@@ -1121,12 +1123,24 @@ int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd,
dev_load(net, ifr->ifr_name);
rtnl_lock();
- ret = wireless_process_ioctl(net, ifr, cmd,
- ioctl_standard_call,
- ioctl_private_call);
+ ret = wireless_process_ioctl(net, ifr, cmd, standard, private);
rtnl_unlock();
- if (IW_IS_GET(cmd) && copy_to_user(arg, ifr, sizeof(struct iwreq)))
+
+ return ret;
+}
+
+int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd,
+ void __user *arg)
+{
+ int ret = wext_ioctl_dispatch(net, ifr, cmd,
+ ioctl_standard_call,
+ ioctl_private_call);
+
+ if (ret > 0 &&
+ IW_IS_GET(cmd) &&
+ copy_to_user(arg, ifr, sizeof(struct iwreq)))
return -EFAULT;
+
return ret;
}
--
1.5.4.rc1
^ permalink raw reply related
* [WEXT 7/12]: Pass iwreq pointer down into standard/private handlers.
From: David Miller @ 2007-12-22 4:55 UTC (permalink / raw)
To: linux-wireless-u79uwXL29TY76Z2rM5mHXA; +Cc: netdev-u79uwXL29TY76Z2rM5mHXA
[WEXT]: Pass iwreq pointer down into standard/private handlers.
They have no need to see the object as an ifreq.
Signed-off-by: David S. Miller <davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org>
---
net/wireless/wext.c | 17 ++++++++---------
1 files changed, 8 insertions(+), 9 deletions(-)
diff --git a/net/wireless/wext.c b/net/wireless/wext.c
index ad982c0..18fa13c 100644
--- a/net/wireless/wext.c
+++ b/net/wireless/wext.c
@@ -864,11 +864,10 @@ out:
* user space and kernel space.
*/
static int ioctl_standard_call(struct net_device * dev,
- struct ifreq * ifr,
+ struct iwreq * iwr,
unsigned int cmd,
iw_handler handler)
{
- struct iwreq * iwr = (struct iwreq *) ifr;
const struct iw_ioctl_description * descr;
struct iw_request_info info;
int ret = -EINVAL;
@@ -1016,10 +1015,9 @@ out:
return err;
}
-static int ioctl_private_call(struct net_device *dev, struct ifreq *ifr,
+static int ioctl_private_call(struct net_device *dev, struct iwreq *iwr,
unsigned int cmd, iw_handler handler)
{
- struct iwreq *iwr = (struct iwreq *) ifr;
int extra_size = 0, ret = -EINVAL;
const struct iw_priv_args *descr;
struct iw_request_info info;
@@ -1047,7 +1045,7 @@ static int ioctl_private_call(struct net_device *dev, struct ifreq *ifr,
}
/* ---------------------------------------------------------------- */
-typedef int (*wext_ioctl_func)(struct net_device *, struct ifreq *,
+typedef int (*wext_ioctl_func)(struct net_device *, struct iwreq *,
unsigned int, iw_handler);
/*
@@ -1059,6 +1057,7 @@ static int wireless_process_ioctl(struct net *net, struct ifreq *ifr,
wext_ioctl_func standard,
wext_ioctl_func private)
{
+ struct iwreq *iwr = (struct iwreq *) ifr;
struct net_device *dev;
iw_handler handler;
@@ -1073,11 +1072,11 @@ static int wireless_process_ioctl(struct net *net, struct ifreq *ifr,
* Note that 'cmd' is already filtered in dev_ioctl() with
* (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) */
if (cmd == SIOCGIWSTATS)
- return standard(dev, ifr, cmd,
+ return standard(dev, iwr, cmd,
&iw_handler_get_iwstats);
if (cmd == SIOCGIWPRIV && dev->wireless_handlers)
- return standard(dev, ifr, cmd,
+ return standard(dev, iwr, cmd,
&iw_handler_get_private);
/* Basic check */
@@ -1089,9 +1088,9 @@ static int wireless_process_ioctl(struct net *net, struct ifreq *ifr,
if (handler) {
/* Standard and private are not the same */
if (cmd < SIOCIWFIRSTPRIV)
- return standard(dev, ifr, cmd, handler);
+ return standard(dev, iwr, cmd, handler);
else
- return private(dev, ifr, cmd, handler);
+ return private(dev, iwr, cmd, handler);
}
/* Old driver API : call driver ioctl handler */
if (dev->do_ioctl)
--
1.5.4.rc1
^ permalink raw reply related
* [WEXT 6/12]: Parameterize the standard/private handlers.
From: David Miller @ 2007-12-22 4:55 UTC (permalink / raw)
To: linux-wireless; +Cc: netdev
[WEXT]: Parameterize the standard/private handlers.
The WEXT standard and private handlers to use are now
arguments to wireless_process_ioctl().
Signed-off-by: David S. Miller <davem@davemloft.net>
---
net/wireless/wext.c | 24 ++++++++++++++++--------
1 files changed, 16 insertions(+), 8 deletions(-)
diff --git a/net/wireless/wext.c b/net/wireless/wext.c
index f183c1d..ad982c0 100644
--- a/net/wireless/wext.c
+++ b/net/wireless/wext.c
@@ -1047,11 +1047,17 @@ static int ioctl_private_call(struct net_device *dev, struct ifreq *ifr,
}
/* ---------------------------------------------------------------- */
+typedef int (*wext_ioctl_func)(struct net_device *, struct ifreq *,
+ unsigned int, iw_handler);
+
/*
* Main IOCTl dispatcher.
* Check the type of IOCTL and call the appropriate wrapper...
*/
-static int wireless_process_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd)
+static int wireless_process_ioctl(struct net *net, struct ifreq *ifr,
+ unsigned int cmd,
+ wext_ioctl_func standard,
+ wext_ioctl_func private)
{
struct net_device *dev;
iw_handler handler;
@@ -1067,12 +1073,12 @@ static int wireless_process_ioctl(struct net *net, struct ifreq *ifr, unsigned i
* Note that 'cmd' is already filtered in dev_ioctl() with
* (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) */
if (cmd == SIOCGIWSTATS)
- return ioctl_standard_call(dev, ifr, cmd,
- &iw_handler_get_iwstats);
+ return standard(dev, ifr, cmd,
+ &iw_handler_get_iwstats);
if (cmd == SIOCGIWPRIV && dev->wireless_handlers)
- return ioctl_standard_call(dev, ifr, cmd,
- &iw_handler_get_private);
+ return standard(dev, ifr, cmd,
+ &iw_handler_get_private);
/* Basic check */
if (!netif_device_present(dev))
@@ -1083,9 +1089,9 @@ static int wireless_process_ioctl(struct net *net, struct ifreq *ifr, unsigned i
if (handler) {
/* Standard and private are not the same */
if (cmd < SIOCIWFIRSTPRIV)
- return ioctl_standard_call(dev, ifr, cmd, handler);
+ return standard(dev, ifr, cmd, handler);
else
- return ioctl_private_call(dev, ifr, cmd, handler);
+ return private(dev, ifr, cmd, handler);
}
/* Old driver API : call driver ioctl handler */
if (dev->do_ioctl)
@@ -1116,7 +1122,9 @@ int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd,
dev_load(net, ifr->ifr_name);
rtnl_lock();
- ret = wireless_process_ioctl(net, ifr, cmd);
+ ret = wireless_process_ioctl(net, ifr, cmd,
+ ioctl_standard_call,
+ ioctl_private_call);
rtnl_unlock();
if (IW_IS_GET(cmd) && copy_to_user(arg, ifr, sizeof(struct iwreq)))
return -EFAULT;
--
1.5.4.rc1
^ permalink raw reply related
* [WEXT 5/12]: Pull ioctl permission checking out into helper function.
From: David Miller @ 2007-12-22 4:54 UTC (permalink / raw)
To: linux-wireless-u79uwXL29TY76Z2rM5mHXA; +Cc: netdev-u79uwXL29TY76Z2rM5mHXA
[WEXT]: Pull ioctl permission checking out into helper function.
Signed-off-by: David S. Miller <davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org>
---
net/wireless/wext.c | 22 +++++++++++++++-------
1 files changed, 15 insertions(+), 7 deletions(-)
diff --git a/net/wireless/wext.c b/net/wireless/wext.c
index 9c3d83f..f183c1d 100644
--- a/net/wireless/wext.c
+++ b/net/wireless/wext.c
@@ -1093,18 +1093,26 @@ static int wireless_process_ioctl(struct net *net, struct ifreq *ifr, unsigned i
return -EOPNOTSUPP;
}
+/* If command is `set a parameter', or `get the encoding parameters',
+ * check if the user has the right to do it.
+ */
+static int wext_permission_check(unsigned int cmd)
+{
+ if ((IW_IS_SET(cmd) || cmd == SIOCGIWENCODE || cmd == SIOCGIWENCODEEXT)
+ && !capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ return 0;
+}
+
/* entry point from dev ioctl */
int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd,
void __user *arg)
{
- int ret;
+ int ret = wext_permission_check(cmd);
- /* If command is `set a parameter', or
- * `get the encoding parameters', check if
- * the user has the right to do it */
- if ((IW_IS_SET(cmd) || cmd == SIOCGIWENCODE || cmd == SIOCGIWENCODEEXT)
- && !capable(CAP_NET_ADMIN))
- return -EPERM;
+ if (ret)
+ return ret;
dev_load(net, ifr->ifr_name);
rtnl_lock();
--
1.5.4.rc1
^ permalink raw reply related
* [WEXT 4/12]: Extract private call iw_point handling into seperate functions.
From: David Miller @ 2007-12-22 4:54 UTC (permalink / raw)
To: linux-wireless-u79uwXL29TY76Z2rM5mHXA; +Cc: netdev-u79uwXL29TY76Z2rM5mHXA
[WEXT]: Extract private call iw_point handling into seperate functions.
Signed-off-by: David S. Miller <davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org>
---
net/wireless/wext.c | 141 +++++++++++++++++++++++++++------------------------
1 files changed, 74 insertions(+), 67 deletions(-)
diff --git a/net/wireless/wext.c b/net/wireless/wext.c
index a6369f3..9c3d83f 100644
--- a/net/wireless/wext.c
+++ b/net/wireless/wext.c
@@ -922,25 +922,22 @@ static int ioctl_standard_call(struct net_device * dev,
* a iw_handler but process it in your ioctl handler (i.e. use the
* old driver API).
*/
-static int ioctl_private_call(struct net_device *dev, struct ifreq *ifr,
- unsigned int cmd, iw_handler handler)
+static int get_priv_descr_and_size(struct net_device *dev, unsigned int cmd,
+ const struct iw_priv_args **descrp)
{
- struct iwreq * iwr = (struct iwreq *) ifr;
- const struct iw_priv_args * descr = NULL;
- struct iw_request_info info;
- int extra_size = 0;
- int i;
- int ret = -EINVAL;
+ const struct iw_priv_args *descr;
+ int i, extra_size;
- /* Get the description of the IOCTL */
- for (i = 0; i < dev->wireless_handlers->num_private_args; i++)
+ descr = NULL;
+ for (i = 0; i < dev->wireless_handlers->num_private_args; i++) {
if (cmd == dev->wireless_handlers->private_args[i].cmd) {
- descr = &(dev->wireless_handlers->private_args[i]);
+ descr = &dev->wireless_handlers->private_args[i];
break;
}
+ }
- /* Compute the size of the set/get arguments */
- if (descr != NULL) {
+ extra_size = 0;
+ if (descr) {
if (IW_IS_SET(cmd)) {
int offset = 0; /* For sub-ioctls */
/* Check for sub-ioctl handler */
@@ -965,72 +962,82 @@ static int ioctl_private_call(struct net_device *dev, struct ifreq *ifr,
extra_size = 0;
}
}
+ *descrp = descr;
+ return extra_size;
+}
- /* Prepare the call */
- info.cmd = cmd;
- info.flags = 0;
+static int ioctl_private_iw_point(struct iw_point *iwp, unsigned int cmd,
+ const struct iw_priv_args *descr,
+ iw_handler handler, struct net_device *dev,
+ struct iw_request_info *info, int extra_size)
+{
+ char *extra;
+ int err;
- /* Check if we have a pointer to user space data or not. */
- if (extra_size == 0) {
- /* No extra arguments. Trivial to handle */
- ret = handler(dev, &info, &(iwr->u), (char *) &(iwr->u));
- } else {
- char * extra;
- int err;
+ /* Check what user space is giving us */
+ if (IW_IS_SET(cmd)) {
+ if (!iwp->pointer && iwp->length != 0)
+ return -EFAULT;
- /* Check what user space is giving us */
- if (IW_IS_SET(cmd)) {
- /* Check NULL pointer */
- if ((iwr->u.data.pointer == NULL) &&
- (iwr->u.data.length != 0))
- return -EFAULT;
+ if (iwp->length > (descr->set_args & IW_PRIV_SIZE_MASK))
+ return -E2BIG;
+ } else if (!iwp->pointer)
+ return -EFAULT;
- /* Does it fits within bounds ? */
- if (iwr->u.data.length > (descr->set_args &
- IW_PRIV_SIZE_MASK))
- return -E2BIG;
- } else if (iwr->u.data.pointer == NULL)
- return -EFAULT;
+ extra = kmalloc(extra_size, GFP_KERNEL);
+ if (!extra)
+ return -ENOMEM;
- /* Always allocate for max space. Easier, and won't last
- * long... */
- extra = kmalloc(extra_size, GFP_KERNEL);
- if (extra == NULL)
- return -ENOMEM;
-
- /* If it is a SET, get all the extra data in here */
- if (IW_IS_SET(cmd) && (iwr->u.data.length != 0)) {
- err = copy_from_user(extra, iwr->u.data.pointer,
- extra_size);
- if (err) {
- kfree(extra);
- return -EFAULT;
- }
+ /* If it is a SET, get all the extra data in here */
+ if (IW_IS_SET(cmd) && (iwp->length != 0)) {
+ if (copy_from_user(extra, iwp->pointer, extra_size)) {
+ err = -EFAULT;
+ goto out;
}
+ }
- /* Call the handler */
- ret = handler(dev, &info, &(iwr->u), extra);
+ /* Call the handler */
+ err = handler(dev, info, (union iwreq_data *) iwp, extra);
- /* If we have something to return to the user */
- if (!ret && IW_IS_GET(cmd)) {
+ /* If we have something to return to the user */
+ if (!err && IW_IS_GET(cmd)) {
+ /* Adjust for the actual length if it's variable,
+ * avoid leaking kernel bits outside.
+ */
+ if (!(descr->get_args & IW_PRIV_SIZE_FIXED))
+ extra_size = adjust_priv_size(descr->get_args, iwp);
- /* Adjust for the actual length if it's variable,
- * avoid leaking kernel bits outside. */
- if (!(descr->get_args & IW_PRIV_SIZE_FIXED)) {
- extra_size = adjust_priv_size(descr->get_args,
- &(iwr->u.data));
- }
+ if (copy_to_user(iwp->pointer, extra, extra_size))
+ err = -EFAULT;
+ }
- err = copy_to_user(iwr->u.data.pointer, extra,
- extra_size);
- if (err)
- ret = -EFAULT;
- }
+out:
+ kfree(extra);
+ return err;
+}
- /* Cleanup - I told you it wasn't that long ;-) */
- kfree(extra);
- }
+static int ioctl_private_call(struct net_device *dev, struct ifreq *ifr,
+ unsigned int cmd, iw_handler handler)
+{
+ struct iwreq *iwr = (struct iwreq *) ifr;
+ int extra_size = 0, ret = -EINVAL;
+ const struct iw_priv_args *descr;
+ struct iw_request_info info;
+
+ extra_size = get_priv_descr_and_size(dev, cmd, &descr);
+
+ /* Prepare the call */
+ info.cmd = cmd;
+ info.flags = 0;
+ /* Check if we have a pointer to user space data or not. */
+ if (extra_size == 0) {
+ /* No extra arguments. Trivial to handle */
+ ret = handler(dev, &info, &(iwr->u), (char *) &(iwr->u));
+ } else {
+ ret = ioctl_private_iw_point(&iwr->u.data, cmd, descr,
+ handler, dev, &info, extra_size);
+ }
/* Call commit handler if needed and defined */
if (ret == -EIWCOMMIT)
--
1.5.4.rc1
^ permalink raw reply related
* [WEXT 3/12]: Extract standard call iw_point handling into seperate function.
From: David Miller @ 2007-12-22 4:54 UTC (permalink / raw)
To: linux-wireless; +Cc: netdev
[WEXT]: Extract standard call iw_point handling into seperate function.
Signed-off-by: David S. Miller <davem@davemloft.net>
---
net/wireless/wext.c | 258 ++++++++++++++++++++++++++------------------------
1 files changed, 134 insertions(+), 124 deletions(-)
diff --git a/net/wireless/wext.c b/net/wireless/wext.c
index 3ca9c3a..a6369f3 100644
--- a/net/wireless/wext.c
+++ b/net/wireless/wext.c
@@ -726,6 +726,138 @@ void wext_proc_exit(struct net *net)
*/
/* ---------------------------------------------------------------- */
+static int ioctl_standard_iw_point(struct iw_point *iwp, unsigned int cmd,
+ const struct iw_ioctl_description *descr,
+ iw_handler handler, struct net_device *dev,
+ struct iw_request_info *info)
+{
+ int err, extra_size, user_length = 0, essid_compat = 0;
+ char *extra;
+
+ /* Calculate space needed by arguments. Always allocate
+ * for max space.
+ */
+ extra_size = descr->max_tokens * descr->token_size;
+
+ /* Check need for ESSID compatibility for WE < 21 */
+ switch (cmd) {
+ case SIOCSIWESSID:
+ case SIOCGIWESSID:
+ case SIOCSIWNICKN:
+ case SIOCGIWNICKN:
+ if (iwp->length == descr->max_tokens + 1)
+ essid_compat = 1;
+ else if (IW_IS_SET(cmd) && (iwp->length != 0)) {
+ char essid[IW_ESSID_MAX_SIZE + 1];
+
+ err = copy_from_user(essid, iwp->pointer,
+ iwp->length *
+ descr->token_size);
+ if (err)
+ return -EFAULT;
+
+ if (essid[iwp->length - 1] == '\0')
+ essid_compat = 1;
+ }
+ break;
+ default:
+ break;
+ }
+
+ iwp->length -= essid_compat;
+
+ /* Check what user space is giving us */
+ if (IW_IS_SET(cmd)) {
+ /* Check NULL pointer */
+ if (!iwp->pointer && iwp->length != 0)
+ return -EFAULT;
+ /* Check if number of token fits within bounds */
+ if (iwp->length > descr->max_tokens)
+ return -E2BIG;
+ if (iwp->length < descr->min_tokens)
+ return -EINVAL;
+ } else {
+ /* Check NULL pointer */
+ if (!iwp->pointer)
+ return -EFAULT;
+ /* Save user space buffer size for checking */
+ user_length = iwp->length;
+
+ /* Don't check if user_length > max to allow forward
+ * compatibility. The test user_length < min is
+ * implied by the test at the end.
+ */
+
+ /* Support for very large requests */
+ if ((descr->flags & IW_DESCR_FLAG_NOMAX) &&
+ (user_length > descr->max_tokens)) {
+ /* Allow userspace to GET more than max so
+ * we can support any size GET requests.
+ * There is still a limit : -ENOMEM.
+ */
+ extra_size = user_length * descr->token_size;
+
+ /* Note : user_length is originally a __u16,
+ * and token_size is controlled by us,
+ * so extra_size won't get negative and
+ * won't overflow...
+ */
+ }
+ }
+
+ /* kzalloc() ensures NULL-termination for essid_compat. */
+ extra = kzalloc(extra_size, GFP_KERNEL);
+ if (!extra)
+ return -ENOMEM;
+
+ /* If it is a SET, get all the extra data in here */
+ if (IW_IS_SET(cmd) && (iwp->length != 0)) {
+ if (copy_from_user(extra, iwp->pointer,
+ iwp->length *
+ descr->token_size)) {
+ err = -EFAULT;
+ goto out;
+ }
+ }
+
+ err = handler(dev, info, (union iwreq_data *) iwp, extra);
+
+ iwp->length += essid_compat;
+
+ /* If we have something to return to the user */
+ if (!err && IW_IS_GET(cmd)) {
+ /* Check if there is enough buffer up there */
+ if (user_length < iwp->length) {
+ err = -E2BIG;
+ goto out;
+ }
+
+ if (copy_to_user(iwp->pointer, extra,
+ iwp->length *
+ descr->token_size)) {
+ err = -EFAULT;
+ goto out;
+ }
+ }
+
+ /* Generate an event to notify listeners of the change */
+ if ((descr->flags & IW_DESCR_FLAG_EVENT) && err == -EIWCOMMIT) {
+ union iwreq_data *data = (union iwreq_data *) iwp;
+
+ if (descr->flags & IW_DESCR_FLAG_RESTRICT)
+ /* If the event is restricted, don't
+ * export the payload.
+ */
+ wireless_send_event(dev, cmd, data, NULL);
+ else
+ wireless_send_event(dev, cmd, data, extra);
+ }
+
+out:
+ kfree(extra);
+ return err;
+}
+
/*
* Wrapper to call a standard Wireless Extension handler.
* We do various checks and also take care of moving data between
@@ -761,130 +893,8 @@ static int ioctl_standard_call(struct net_device * dev,
((ret == 0) || (ret == -EIWCOMMIT)))
wireless_send_event(dev, cmd, &(iwr->u), NULL);
} else {
- char * extra;
- int extra_size;
- int user_length = 0;
- int err;
- int essid_compat = 0;
-
- /* Calculate space needed by arguments. Always allocate
- * for max space. Easier, and won't last long... */
- extra_size = descr->max_tokens * descr->token_size;
-
- /* Check need for ESSID compatibility for WE < 21 */
- switch (cmd) {
- case SIOCSIWESSID:
- case SIOCGIWESSID:
- case SIOCSIWNICKN:
- case SIOCGIWNICKN:
- if (iwr->u.data.length == descr->max_tokens + 1)
- essid_compat = 1;
- else if (IW_IS_SET(cmd) && (iwr->u.data.length != 0)) {
- char essid[IW_ESSID_MAX_SIZE + 1];
-
- err = copy_from_user(essid, iwr->u.data.pointer,
- iwr->u.data.length *
- descr->token_size);
- if (err)
- return -EFAULT;
-
- if (essid[iwr->u.data.length - 1] == '\0')
- essid_compat = 1;
- }
- break;
- default:
- break;
- }
-
- iwr->u.data.length -= essid_compat;
-
- /* Check what user space is giving us */
- if (IW_IS_SET(cmd)) {
- /* Check NULL pointer */
- if ((iwr->u.data.pointer == NULL) &&
- (iwr->u.data.length != 0))
- return -EFAULT;
- /* Check if number of token fits within bounds */
- if (iwr->u.data.length > descr->max_tokens)
- return -E2BIG;
- if (iwr->u.data.length < descr->min_tokens)
- return -EINVAL;
- } else {
- /* Check NULL pointer */
- if (iwr->u.data.pointer == NULL)
- return -EFAULT;
- /* Save user space buffer size for checking */
- user_length = iwr->u.data.length;
-
- /* Don't check if user_length > max to allow forward
- * compatibility. The test user_length < min is
- * implied by the test at the end. */
-
- /* Support for very large requests */
- if ((descr->flags & IW_DESCR_FLAG_NOMAX) &&
- (user_length > descr->max_tokens)) {
- /* Allow userspace to GET more than max so
- * we can support any size GET requests.
- * There is still a limit : -ENOMEM. */
- extra_size = user_length * descr->token_size;
- /* Note : user_length is originally a __u16,
- * and token_size is controlled by us,
- * so extra_size won't get negative and
- * won't overflow... */
- }
- }
-
- /* Create the kernel buffer */
- /* kzalloc ensures NULL-termination for essid_compat */
- extra = kzalloc(extra_size, GFP_KERNEL);
- if (extra == NULL)
- return -ENOMEM;
-
- /* If it is a SET, get all the extra data in here */
- if (IW_IS_SET(cmd) && (iwr->u.data.length != 0)) {
- err = copy_from_user(extra, iwr->u.data.pointer,
- iwr->u.data.length *
- descr->token_size);
- if (err) {
- kfree(extra);
- return -EFAULT;
- }
- }
-
- /* Call the handler */
- ret = handler(dev, &info, &(iwr->u), extra);
-
- iwr->u.data.length += essid_compat;
-
- /* If we have something to return to the user */
- if (!ret && IW_IS_GET(cmd)) {
- /* Check if there is enough buffer up there */
- if (user_length < iwr->u.data.length) {
- kfree(extra);
- return -E2BIG;
- }
-
- err = copy_to_user(iwr->u.data.pointer, extra,
- iwr->u.data.length *
- descr->token_size);
- if (err)
- ret = -EFAULT;
- }
-
- /* Generate an event to notify listeners of the change */
- if ((descr->flags & IW_DESCR_FLAG_EVENT) &&
- ((ret == 0) || (ret == -EIWCOMMIT))) {
- if (descr->flags & IW_DESCR_FLAG_RESTRICT)
- /* If the event is restricted, don't
- * export the payload */
- wireless_send_event(dev, cmd, &(iwr->u), NULL);
- else
- wireless_send_event(dev, cmd, &(iwr->u),
- extra);
- }
-
- /* Cleanup - I told you it wasn't that long ;-) */
- kfree(extra);
+ ret = ioctl_standard_iw_point(&iwr->u.data, cmd, descr,
+ handler, dev, &info);
}
/* Call commit handler if needed and defined */
--
1.5.4.rc1
^ permalink raw reply related
* [WEXT 2/12]: Make adjust_priv_size() take a "struct iw_point *".
From: David Miller @ 2007-12-22 4:53 UTC (permalink / raw)
To: linux-wireless-u79uwXL29TY76Z2rM5mHXA; +Cc: netdev-u79uwXL29TY76Z2rM5mHXA
[WEXT]: Make adjust_priv_size() take a "struct iw_point *".
Signed-off-by: David S. Miller <davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org>
---
net/wireless/wext.c | 6 +++---
1 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/net/wireless/wext.c b/net/wireless/wext.c
index 677be28..3ca9c3a 100644
--- a/net/wireless/wext.c
+++ b/net/wireless/wext.c
@@ -526,9 +526,9 @@ static int get_priv_size(__u16 args)
/*
* Re-calculate the size of private arguments
*/
-static int adjust_priv_size(__u16 args, union iwreq_data *wrqu)
+static int adjust_priv_size(__u16 args, struct iw_point *iwp)
{
- int num = wrqu->data.length;
+ int num = iwp->length;
int max = args & IW_PRIV_SIZE_MASK;
int type = (args & IW_PRIV_TYPE_MASK) >> 12;
@@ -1008,7 +1008,7 @@ static int ioctl_private_call(struct net_device *dev, struct ifreq *ifr,
* avoid leaking kernel bits outside. */
if (!(descr->get_args & IW_PRIV_SIZE_FIXED)) {
extra_size = adjust_priv_size(descr->get_args,
- &(iwr->u));
+ &(iwr->u.data));
}
err = copy_to_user(iwr->u.data.pointer, extra,
--
1.5.4.rc1
^ permalink raw reply related
* [WEXT 1/12]: Remove inline from get_priv_size() and adjust_priv_size().
From: David Miller @ 2007-12-22 4:53 UTC (permalink / raw)
To: linux-wireless-u79uwXL29TY76Z2rM5mHXA; +Cc: netdev-u79uwXL29TY76Z2rM5mHXA
[WEXT]: Remove inline from get_priv_size() and adjust_priv_size().
The compiler inlines when appropriate.
Signed-off-by: David S. Miller <davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org>
---
net/wireless/wext.c | 5 ++---
1 files changed, 2 insertions(+), 3 deletions(-)
diff --git a/net/wireless/wext.c b/net/wireless/wext.c
index 47e80cc..677be28 100644
--- a/net/wireless/wext.c
+++ b/net/wireless/wext.c
@@ -514,7 +514,7 @@ static int call_commit_handler(struct net_device *dev)
/*
* Calculate size of private arguments
*/
-static inline int get_priv_size(__u16 args)
+static int get_priv_size(__u16 args)
{
int num = args & IW_PRIV_SIZE_MASK;
int type = (args & IW_PRIV_TYPE_MASK) >> 12;
@@ -526,8 +526,7 @@ static inline int get_priv_size(__u16 args)
/*
* Re-calculate the size of private arguments
*/
-static inline int adjust_priv_size(__u16 args,
- union iwreq_data * wrqu)
+static int adjust_priv_size(__u16 args, union iwreq_data *wrqu)
{
int num = wrqu->data.length;
int max = args & IW_PRIV_SIZE_MASK;
--
1.5.4.rc1
^ permalink raw reply related
* [WEXT 0/12]: Un-crapify compat handling.
From: David Miller @ 2007-12-22 4:52 UTC (permalink / raw)
To: linux-wireless-u79uwXL29TY76Z2rM5mHXA; +Cc: netdev-u79uwXL29TY76Z2rM5mHXA
This set of 12 patches pulls all of the existing compat
handling for WEXT ioctls out of fs/compat_ioctl.c and
allows implementations down in the driver layers to
handle compat issues properly when necessary.
In particular it fixes the bug where iw_point objects
were not being size translated properly in scan
streams and similar.
Currently I've only made sure this compiles properly.
I'm half-way done with a dummy wireless driver that
can be used purely to validate WEXT ioctl handling
correctness in the core wireless layers.
^ permalink raw reply
* Re: [PATCH] Reduce locking in TX path of forcedth driver
From: Jeff Garzik @ 2007-12-22 3:51 UTC (permalink / raw)
To: Stephen Hemminger; +Cc: netdev, therbert, Ayaz Abdulla
In-Reply-To: <20071221185435.2884f118@deepthought>
(Stephen, your mailer is snipping CC's, please fix....)
(Tom, you failed to CC the maintainer at NVIDIA, please fix...)
Stephen Hemminger wrote:
> On Fri, 21 Dec 2007 17:41:34 -0800 (PST)
> therbert@google.com (Tom Herbert) wrote:
>
>> Reduce the amount of locking in the TX path. Instead of using both netif_tx_lock and dev->priv->lock on transmitting, a single private lock (dev->priv->tx_lock) is used. This method is similar to that of the e1000 driver, including the logic to stop the queue in the start xmit functions, and the logic to wake the queue in the TX done functions. We see some performance improvement with this patch.
>>
>> Signed-off-by: Tom Herbert <therbert@google.com>
>
>
>>
>> + spin_lock_init(&np->tx_lock);
>> +
>> + dev->features |= NETIF_F_LLTX;
>> +
>
> NAK - lockless transmit is not desirable for real devices.
>
> use netif_tx_lock() instead of your private lock
True enough, though also note that (a) the forcedeth driver has many
problems in the locking department, and (b) anyone interested in working
on this problem should start with the existing -- working -- work in
progress that has already been posted to netdev a couple times:
Branch 'fe' of
git://git.kernel.org/pub/scm/linux/kernel/git/jgarzik/netdev-2.6.git
forcedeth (as it exists unmodified in upstream) tries so hard to be
lockless... that it winds up taking a ton of locks all over the place,
completely failing to reach its own goal.
Jeff
^ permalink raw reply
* Re: [ETH]: Combine format_addr() with print_mac().
From: Michael Chan @ 2007-12-22 3:58 UTC (permalink / raw)
To: Joe Perches; +Cc: David Miller, netdev, anilgv, michaelc, david.somayajulu
In-Reply-To: <1198276619.18877.42.camel@localhost>
On Fri, 2007-12-21 at 14:36 -0800, Joe Perches wrote:
> On Fri, 2007-12-21 at 14:05 -0800, Michael Chan wrote:
> > diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c
> > index 6b2e454..f760d41 100644
> > --- a/net/ethernet/eth.c
> > +++ b/net/ethernet/eth.c
> > @@ -359,10 +359,33 @@ struct net_device *alloc_etherdev_mq(int sizeof_priv, unsigned int queue_count)
> > }
> > EXPORT_SYMBOL(alloc_etherdev_mq);
> >
> > +static ssize_t _format_mac_addr(char *buf, const unsigned char *addr, int len)
> > +{
> > + int i;
> > + char *cp = buf;
> > +
> > + for (i = 0; i < len; i++) {
> > + cp += sprintf(cp, "%02x", addr[i]);
> > + if (i == len - 1)
> > + break;
> > + *cp++ = ':';
> > + }
> > + return cp - buf;
> > +}
> > +
> > +ssize_t format_mac_addr(char *buf, const unsigned char *addr, int len)
> > +{
> > + ssize_t l;
> > +
> > + l = _format_mac_addr(buf, addr, len);
> > + strcpy(buf + l, "\n");
> > + return l + 1;
> > +}
> > +EXPORT_SYMBOL(format_mac_addr);
> > +
> > char *print_mac(char *buf, const u8 *addr)
> > {
> > - sprintf(buf, MAC_FMT,
> > - addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
> > + _format_mac_addr(buf, addr, ETH_ALEN);
> > return buf;
> > }
> > EXPORT_SYMBOL(print_mac);
>
> I think const unsigned char *addr should be const u8 *addr
The dev_addr is declared as unsigned char* in struct net_device. To be
consistent, can we change print_mac() and MAC_BUF to use unsigned char*?
They are really the same.
> ssize_t? shouldn't it be size_t?
I'm just keeping the prototype unchanged as originally defined in net-
sysfs.c
> Indexing buf by int len is unchecked.
> That could lead to unintended buffer overruns.
> Maybe add a buflen argument and use snprintf?
Again, I kept the semantics the same as the original, but will be happy
to add a buflen for better checking.
>
> I had a patch that added some type-safety to print_mac
> and prevented this unintended buffer overrun.
>
> It seems it wasn't applied.
>
> ---------------------------------------
>
> Subject: Re: [PATCH net-2.6.24] introduce MAC_FMT/MAC_ARG
> Date: Mon, 24 Sep 2007 10:28:36 -0700
>
> Here is a patch that adds some type safety to print_mac
> by using a struct print_mac_buf * instead of char *.
>
> It also reduces the defconfig vmlinux size by 8 bytes.
>
> Signed-off-by: Joe Perches <joe@perches.com>
>
> --
>
> include/linux/if_ether.h | 12 ++++++++++--
> net/ethernet/eth.c | 6 +++---
> 2 files changed, 13 insertions(+), 5 deletions(-)
>
> diff --git a/include/linux/if_ether.h b/include/linux/if_ether.h
> index 57abca1..620d6b1 100644
> --- a/include/linux/if_ether.h
> +++ b/include/linux/if_ether.h
> @@ -126,7 +126,15 @@ extern struct ctl_table ether_table[];
> * Display a 6 byte device address (MAC) in a readable format.
> */
> #define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x"
> -extern char *print_mac(char *buf, const u8 *addr);
> -#define DECLARE_MAC_BUF(var) char var[18] __maybe_unused
> +
> +struct print_mac_buf {
> + char formatted_mac_addr[18];
> +};
> +
> +#define DECLARE_MAC_BUF(var) \
> + struct print_mac_buf __maybe_unused _##var; \
> + struct print_mac_buf __maybe_unused *var = &_##var
> +
> +extern char *print_mac(struct print_mac_buf *buf, const u8 *addr);
>
> #endif /* _LINUX_IF_ETHER_H */
> diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c
> index 2aaf6fa..ad82613 100644
> --- a/net/ethernet/eth.c
> +++ b/net/ethernet/eth.c
> @@ -338,10 +338,10 @@ struct net_device *alloc_etherdev_mq(int
> sizeof_priv, unsigned int queue_count)
> }
> EXPORT_SYMBOL(alloc_etherdev_mq);
>
> -char *print_mac(char *buf, const u8 *addr)
> +char *print_mac(struct print_mac_buf *buf, const u8 *addr)
> {
> - sprintf(buf, MAC_FMT,
> + sprintf(buf->formatted_mac_addr, MAC_FMT,
> addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
> - return buf;
> + return buf->formatted_mac_addr;
> }
> EXPORT_SYMBOL(print_mac);
>
>
>
>
^ permalink raw reply
* Re: [PATCH] Reduce locking in TX path of forcedth driver
From: Stephen Hemminger @ 2007-12-22 2:54 UTC (permalink / raw)
To: netdev
In-Reply-To: <20071222014134.A28994161A0@localhost>
On Fri, 21 Dec 2007 17:41:34 -0800 (PST)
therbert@google.com (Tom Herbert) wrote:
> Reduce the amount of locking in the TX path. Instead of using both netif_tx_lock and dev->priv->lock on transmitting, a single private lock (dev->priv->tx_lock) is used. This method is similar to that of the e1000 driver, including the logic to stop the queue in the start xmit functions, and the logic to wake the queue in the TX done functions. We see some performance improvement with this patch.
>
> Signed-off-by: Tom Herbert <therbert@google.com>
>
> + spin_lock_init(&np->tx_lock);
> +
> + dev->features |= NETIF_F_LLTX;
> +
NAK - lockless transmit is not desirable for real devices.
use netif_tx_lock() instead of your private lock
--
Stephen Hemminger <stephen.hemminger@vyatta.com>
^ permalink raw reply
* (unknown),
From: Masahide NAKAMURA @ 2007-12-22 1:48 UTC (permalink / raw)
To: davem, herbert; +Cc: netdev, usagi-core, Masahide NAKAMURA
Subject: [XFRM] Documentaion: Fix error example at XFRMOUTSTATEMODEERROR. (Re: [XFRM]: Fix outbound statistics.)
Hello,
On Fri, 21 Dec 2007 23:11:11 +0800
Herbert Xu <herbert@gondor.apana.org.au> wrote:
> On Fri, Dec 21, 2007 at 11:25:00PM +0900, Masahide NAKAMURA wrote:
> >
> > do {
> > err = xfrm_state_check_space(x, skb);
> > - if (err)
> > + if (err) {
> > + XFRM_INC_STATS(LINUX_MIB_XFRMOUTERROR);
> > goto error_nolock;
> > + }
> >
> > err = x->outer_mode->output(x, skb);
> > - if (err)
> > + if (err) {
> > + XFRM_INC_STATS(LINUX_MIB_XFRMOUTSTATEMODEERROR);
>
> BTW, none of our existing mode output functions actually return
> an error. I noticed that the description for this field is actually
> "Transformation mode specific error, e.g. Outer header space is not
> enough". This is slightly misleading as output header space is
> checked by xfrm_state_check_space so if there's an error that's
> where it'll show up.
Thanks for comment, Herbert.
I fix the documentation to remove "e.g. Outer header space is not enough"
from XFRMSTATEMODEERROR.
About error code from xfrm_state_check_space(), I still map it XFRMOUTERROR
(other errors) this time because I think the error here is not a length
error by protocol (e.g MTU related things) but an internal buffer management.
Any comments for the statistics are still welcomed.
David, please apply the following patch, too.
[XFRM] Documentaion: Fix error example at XFRMOUTSTATEMODEERROR.
Signed-off-by: Masahide NAKAMURA <nakam@linux-ipv6.org>
---
Documentation/networking/xfrm_proc.txt | 1 -
1 files changed, 0 insertions(+), 1 deletions(-)
diff --git a/Documentation/networking/xfrm_proc.txt b/Documentation/networking/xfrm_proc.txt
index ec9045b..53c1a58 100644
--- a/Documentation/networking/xfrm_proc.txt
+++ b/Documentation/networking/xfrm_proc.txt
@@ -60,7 +60,6 @@ XfrmOutStateProtoError:
Transformation protocol specific error
XfrmOutStateModeError:
Transformation mode specific error
- e.g. Outer header space is not enough
XfrmOutStateExpired:
State is expired
XfrmOutPolBlock:
--
1.4.4.2
^ permalink raw reply related
* [PATCH] Reduce locking in TX path of forcedth driver
From: Tom Herbert @ 2007-12-22 1:41 UTC (permalink / raw)
To: jeff; +Cc: netdev, therbert
Reduce the amount of locking in the TX path. Instead of using both netif_tx_lock and dev->priv->lock on transmitting, a single private lock (dev->priv->tx_lock) is used. This method is similar to that of the e1000 driver, including the logic to stop the queue in the start xmit functions, and the logic to wake the queue in the TX done functions. We see some performance improvement with this patch.
Signed-off-by: Tom Herbert <therbert@google.com>
--- linux-2.6/drivers/net/forcedeth.c.orig 2007-12-21 16:26:15.743639000 -0800
+++ linux-2.6/drivers/net/forcedeth.c 2007-12-21 16:51:19.001325000 -0800
@@ -525,6 +525,12 @@ union ring_type {
#define RING_MAX_DESC_VER_1 1024
#define RING_MAX_DESC_VER_2_3 16384
+/*
+ * Maxmimum number of fragments that a single packet could need in
+ * transmit.
+ */
+#define MAX_TX_FRAGS (MAX_SKB_FRAGS + (65535 >> NV_TX2_TSO_MAX_SHIFT))
+
/* rx/tx mac addr + type + vlan + align + slack*/
#define NV_RX_HEADERS (64)
/* even more slack. */
@@ -738,9 +744,8 @@ struct nv_skb_map {
* critical parts:
* - rx is (pseudo-) lockless: it relies on the single-threading provided
* by the arch code for interrupts.
- * - tx setup is lockless: it relies on netif_tx_lock. Actual submission
- * needs dev->priv->lock :-(
- * - set_multicast_list: preparation lockless, relies on netif_tx_lock.
+ * - tx uses dev->priv->tx_lock and not netif_tx_lock. TX done processing
+ * only acquires dev->priv->tx_lock when the queue needs to be awoken.
*/
/* in dev: base, irq */
@@ -806,6 +811,7 @@ struct fe_priv {
/*
* tx specific fields.
*/
+ spinlock_t tx_lock;
union ring_type get_tx, put_tx, first_tx, last_tx;
struct nv_skb_map *get_tx_ctx, *put_tx_ctx;
struct nv_skb_map *first_tx_ctx, *last_tx_ctx;
@@ -814,7 +820,6 @@ struct fe_priv {
union ring_type tx_ring;
u32 tx_flags;
int tx_ring_size;
- int tx_stop;
/* vlan fields */
struct vlan_group *vlangrp;
@@ -1775,9 +1780,16 @@ static inline u32 nv_get_empty_tx_slots(
return (u32)(np->tx_ring_size - ((np->tx_ring_size + (np->put_tx_ctx - np->get_tx_ctx)) % np->tx_ring_size));
}
+static inline u32 nv_get_used_tx_slots(struct fe_priv *np)
+{
+ return (u32)((np->tx_ring_size + (np->put_tx_ctx - np->get_tx_ctx)) %
+ np->tx_ring_size);
+}
+
+#define TX_WAKE_THRESHOLD(np) ((np)->tx_ring_size / 4)
+
/*
* nv_start_xmit: dev->hard_start_xmit function
- * Called with netif_tx_lock held.
*/
static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
@@ -1790,7 +1802,7 @@ static int nv_start_xmit(struct sk_buff
u32 bcnt;
u32 size = skb->len-skb->data_len;
u32 entries = (size >> NV_TX2_TSO_MAX_SHIFT) + ((size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0);
- u32 empty_slots;
+ unsigned long irq_flags;
struct ring_desc* put_tx;
struct ring_desc* start_tx;
struct ring_desc* prev_tx;
@@ -1802,12 +1814,22 @@ static int nv_start_xmit(struct sk_buff
((skb_shinfo(skb)->frags[i].size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0);
}
- empty_slots = nv_get_empty_tx_slots(np);
- if (unlikely(empty_slots <= entries)) {
- spin_lock_irq(&np->lock);
- netif_stop_queue(dev);
- np->tx_stop = 1;
- spin_unlock_irq(&np->lock);
+ local_irq_save(irq_flags);
+ if (!spin_trylock(&np->tx_lock)) {
+ /* Collision - tell upper layer to requeue */
+ local_irq_restore(irq_flags);
+ return NETDEV_TX_LOCKED;
+ }
+
+ if (unlikely(nv_get_empty_tx_slots(np) <= entries)) {
+ if (!netif_queue_stopped(dev)) {
+ netif_stop_queue(dev);
+
+ /* This is a hard error, log it. */
+ printk(KERN_ERR "%s: BUG! Tx Ring full when "
+ "queue awake\n", dev->name);
+ }
+ spin_unlock_irqrestore(&np->tx_lock, irq_flags);
return NETDEV_TX_BUSY;
}
@@ -1858,6 +1880,12 @@ static int nv_start_xmit(struct sk_buff
} while (size);
}
+ /*
+ * Make put_tx_ctx visible to nx_tx_done as soon as possible,
+ * this might avoid an unnecessary queue wakeup.
+ */
+ smp_mb();
+
/* set last fragment flag */
prev_tx->flaglen |= cpu_to_le32(tx_flags_extra);
@@ -1870,14 +1898,10 @@ static int nv_start_xmit(struct sk_buff
tx_flags_extra = skb->ip_summed == CHECKSUM_PARTIAL ?
NV_TX2_CHECKSUM_L3 | NV_TX2_CHECKSUM_L4 : 0;
- spin_lock_irq(&np->lock);
-
/* set tx flags */
start_tx->flaglen |= cpu_to_le32(tx_flags | tx_flags_extra);
np->put_tx.orig = put_tx;
- spin_unlock_irq(&np->lock);
-
dprintk(KERN_DEBUG "%s: nv_start_xmit: entries %d queued for transmission. tx_flags_extra: %x\n",
dev->name, entries, tx_flags_extra);
{
@@ -1892,6 +1916,14 @@ static int nv_start_xmit(struct sk_buff
dev->trans_start = jiffies;
writel(NVREG_TXRXCTL_KICK|np->txrxctl_bits, get_hwbase(dev) + NvRegTxRxControl);
+
+ if (unlikely(nv_get_empty_tx_slots(np) <= (MAX_TX_FRAGS + 1))) {
+ netif_stop_queue(dev);
+ if (nv_get_empty_tx_slots(np) > TX_WAKE_THRESHOLD(np))
+ netif_wake_queue(dev);
+ }
+
+ spin_unlock_irqrestore(&np->tx_lock, irq_flags);
return NETDEV_TX_OK;
}
@@ -1902,11 +1934,11 @@ static int nv_start_xmit_optimized(struc
u32 tx_flags_extra;
unsigned int fragments = skb_shinfo(skb)->nr_frags;
unsigned int i;
+ unsigned long irq_flags;
u32 offset = 0;
u32 bcnt;
u32 size = skb->len-skb->data_len;
u32 entries = (size >> NV_TX2_TSO_MAX_SHIFT) + ((size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0);
- u32 empty_slots;
struct ring_desc_ex* put_tx;
struct ring_desc_ex* start_tx;
struct ring_desc_ex* prev_tx;
@@ -1918,12 +1950,22 @@ static int nv_start_xmit_optimized(struc
((skb_shinfo(skb)->frags[i].size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0);
}
- empty_slots = nv_get_empty_tx_slots(np);
- if (unlikely(empty_slots <= entries)) {
- spin_lock_irq(&np->lock);
- netif_stop_queue(dev);
- np->tx_stop = 1;
- spin_unlock_irq(&np->lock);
+ local_irq_save(irq_flags);
+ if (!spin_trylock(&np->tx_lock)) {
+ /* Collision - tell upper layer to requeue */
+ local_irq_restore(irq_flags);
+ return NETDEV_TX_LOCKED;
+ }
+
+ if (unlikely(nv_get_empty_tx_slots(np) <= entries)) {
+ if (!netif_queue_stopped(dev)) {
+ netif_stop_queue(dev);
+
+ /* This is a hard error, log it. */
+ printk(KERN_ERR "%s: BUG! Tx Ring full when "
+ "queue awake\n", dev->name);
+ }
+ spin_unlock_irqrestore(&np->tx_lock, irq_flags);
return NETDEV_TX_BUSY;
}
@@ -1976,6 +2018,12 @@ static int nv_start_xmit_optimized(struc
} while (size);
}
+ /*
+ * Make put_tx_ctx visible to nx_tx_done as soon as possible,
+ * this might avoid an unnecessary queue wakeup.
+ */
+ smp_mb();
+
/* set last fragment flag */
prev_tx->flaglen |= cpu_to_le32(NV_TX2_LASTPACKET);
@@ -1998,14 +2046,10 @@ static int nv_start_xmit_optimized(struc
start_tx->txvlan = 0;
}
- spin_lock_irq(&np->lock);
-
/* set tx flags */
start_tx->flaglen |= cpu_to_le32(tx_flags | tx_flags_extra);
np->put_tx.ex = put_tx;
- spin_unlock_irq(&np->lock);
-
dprintk(KERN_DEBUG "%s: nv_start_xmit_optimized: entries %d queued for transmission. tx_flags_extra: %x\n",
dev->name, entries, tx_flags_extra);
{
@@ -2020,6 +2064,14 @@ static int nv_start_xmit_optimized(struc
dev->trans_start = jiffies;
writel(NVREG_TXRXCTL_KICK|np->txrxctl_bits, get_hwbase(dev) + NvRegTxRxControl);
+
+ if (unlikely(nv_get_empty_tx_slots(np) <= (MAX_TX_FRAGS + 1))) {
+ netif_stop_queue(dev);
+ if (nv_get_empty_tx_slots(np) > TX_WAKE_THRESHOLD(np))
+ netif_wake_queue(dev);
+ }
+
+ spin_unlock_irqrestore(&np->tx_lock, irq_flags);
return NETDEV_TX_OK;
}
@@ -2032,7 +2084,6 @@ static void nv_tx_done(struct net_device
{
struct fe_priv *np = netdev_priv(dev);
u32 flags;
- struct ring_desc* orig_get_tx = np->get_tx.orig;
while ((np->get_tx.orig != np->put_tx.orig) &&
!((flags = le32_to_cpu(np->get_tx.orig->flaglen)) & NV_TX_VALID)) {
@@ -2081,9 +2132,22 @@ static void nv_tx_done(struct net_device
if (unlikely(np->get_tx_ctx++ == np->last_tx_ctx))
np->get_tx_ctx = np->first_tx_ctx;
}
- if (unlikely((np->tx_stop == 1) && (np->get_tx.orig != orig_get_tx))) {
- np->tx_stop = 0;
- netif_wake_queue(dev);
+
+ /*
+ * Need to make the get_tx_ctx update visible to nv_start_xmit()
+ * before checking for netif_queue_stopped(). Without the
+ * memory barrier, there is a small possibility that nv_start_xmit()
+ * will miss it and cause the queue to be stopped forever.
+ */
+ smp_mb();
+
+ if (unlikely(netif_queue_stopped(dev) &&
+ (nv_get_empty_tx_slots(np) > TX_WAKE_THRESHOLD(np)))) {
+ spin_lock(&np->tx_lock);
+ if (netif_queue_stopped(dev) &&
+ (nv_get_empty_tx_slots(np) > TX_WAKE_THRESHOLD(np)))
+ netif_wake_queue(dev);
+ spin_unlock(&np->tx_lock);
}
}
@@ -2091,7 +2155,6 @@ static void nv_tx_done_optimized(struct
{
struct fe_priv *np = netdev_priv(dev);
u32 flags;
- struct ring_desc_ex* orig_get_tx = np->get_tx.ex;
while ((np->get_tx.ex != np->put_tx.ex) &&
!((flags = le32_to_cpu(np->get_tx.ex->flaglen)) & NV_TX_VALID) &&
@@ -2116,15 +2179,27 @@ static void nv_tx_done_optimized(struct
if (unlikely(np->get_tx_ctx++ == np->last_tx_ctx))
np->get_tx_ctx = np->first_tx_ctx;
}
- if (unlikely((np->tx_stop == 1) && (np->get_tx.ex != orig_get_tx))) {
- np->tx_stop = 0;
- netif_wake_queue(dev);
+
+ /*
+ * Need to make the get_tx_ctx update visible to nv_start_xmit()
+ * before checking for netif_queue_stopped(). Without the
+ * memory barrier, there is a small possibility that nv_start_xmit()
+ * will miss it and cause the queue to be stopped forever.
+ */
+ smp_mb();
+
+ if (unlikely(netif_queue_stopped(dev) &&
+ (nv_get_empty_tx_slots(np) > TX_WAKE_THRESHOLD(np)))) {
+ spin_lock(&np->tx_lock);
+ if (netif_queue_stopped(dev) &&
+ (nv_get_empty_tx_slots(np) > TX_WAKE_THRESHOLD(np)))
+ netif_wake_queue(dev);
+ spin_unlock(&np->tx_lock);
}
}
/*
* nv_tx_timeout: dev->tx_timeout function
- * Called with netif_tx_lock held.
*/
static void nv_tx_timeout(struct net_device *dev)
{
@@ -2186,6 +2261,7 @@ static void nv_tx_timeout(struct net_dev
}
spin_lock_irq(&np->lock);
+ spin_lock(&np->tx_lock);
/* 1) stop tx engine */
nv_stop_tx(dev);
@@ -2208,6 +2284,7 @@ static void nv_tx_timeout(struct net_dev
/* 4) restart tx engine */
nv_start_tx(dev);
+ spin_unlock(&np->tx_lock);
spin_unlock_irq(&np->lock);
}
@@ -2565,8 +2642,8 @@ static int nv_change_mtu(struct net_devi
* Changing the MTU is a rare event, it shouldn't matter.
*/
nv_disable_irq(dev);
- netif_tx_lock_bh(dev);
spin_lock(&np->lock);
+ spin_lock(&np->tx_lock);
/* stop engines */
nv_stop_rx(dev);
nv_stop_tx(dev);
@@ -2592,8 +2669,8 @@ static int nv_change_mtu(struct net_devi
/* restart rx engine */
nv_start_rx(dev);
nv_start_tx(dev);
+ spin_unlock(&np->tx_lock);
spin_unlock(&np->lock);
- netif_tx_unlock_bh(dev);
nv_enable_irq(dev);
}
return 0;
@@ -2628,8 +2705,8 @@ static int nv_set_mac_address(struct net
memcpy(dev->dev_addr, macaddr->sa_data, ETH_ALEN);
if (netif_running(dev)) {
- netif_tx_lock_bh(dev);
spin_lock_irq(&np->lock);
+ spin_lock(&np->tx_lock);
/* stop rx engine */
nv_stop_rx(dev);
@@ -2639,8 +2716,8 @@ static int nv_set_mac_address(struct net
/* restart rx engine */
nv_start_rx(dev);
+ spin_unlock(&np->tx_lock);
spin_unlock_irq(&np->lock);
- netif_tx_unlock_bh(dev);
} else {
nv_copy_mac_to_hw(dev);
}
@@ -2649,7 +2726,6 @@ static int nv_set_mac_address(struct net
/*
* nv_set_multicast: dev->set_multicast function
- * Called with netif_tx_lock held.
*/
static void nv_set_multicast(struct net_device *dev)
{
@@ -2698,6 +2774,7 @@ static void nv_set_multicast(struct net_
addr[0] |= NVREG_MCASTADDRA_FORCE;
pff |= NVREG_PFF_ALWAYS;
spin_lock_irq(&np->lock);
+ spin_lock(&np->tx_lock);
nv_stop_rx(dev);
writel(addr[0], base + NvRegMulticastAddrA);
writel(addr[1], base + NvRegMulticastAddrB);
@@ -2707,6 +2784,7 @@ static void nv_set_multicast(struct net_
dprintk(KERN_INFO "%s: reconfiguration for multicast lists.\n",
dev->name);
nv_start_rx(dev);
+ spin_unlock(&np->tx_lock);
spin_unlock_irq(&np->lock);
}
@@ -3652,8 +3730,8 @@ static void nv_do_nic_poll(unsigned long
np->recover_error = 0;
printk(KERN_INFO "forcedeth: MAC in recoverable error state\n");
if (netif_running(dev)) {
- netif_tx_lock_bh(dev);
spin_lock(&np->lock);
+ spin_lock(&np->tx_lock);
/* stop engines */
nv_stop_rx(dev);
nv_stop_tx(dev);
@@ -3679,8 +3757,8 @@ static void nv_do_nic_poll(unsigned long
/* restart rx engine */
nv_start_rx(dev);
nv_start_tx(dev);
+ spin_unlock(&np->tx_lock);
spin_unlock(&np->lock);
- netif_tx_unlock_bh(dev);
}
}
@@ -3883,13 +3961,13 @@ static int nv_set_settings(struct net_de
netif_carrier_off(dev);
if (netif_running(dev)) {
nv_disable_irq(dev);
- netif_tx_lock_bh(dev);
spin_lock(&np->lock);
+ spin_lock(&np->tx_lock);
/* stop engines */
nv_stop_rx(dev);
nv_stop_tx(dev);
+ spin_unlock(&np->tx_lock);
spin_unlock(&np->lock);
- netif_tx_unlock_bh(dev);
}
if (ecmd->autoneg == AUTONEG_ENABLE) {
@@ -4034,13 +4112,13 @@ static int nv_nway_reset(struct net_devi
netif_carrier_off(dev);
if (netif_running(dev)) {
nv_disable_irq(dev);
- netif_tx_lock_bh(dev);
spin_lock(&np->lock);
+ spin_lock(&np->tx_lock);
/* stop engines */
nv_stop_rx(dev);
nv_stop_tx(dev);
+ spin_unlock(&np->tx_lock);
spin_unlock(&np->lock);
- netif_tx_unlock_bh(dev);
printk(KERN_INFO "%s: link down.\n", dev->name);
}
@@ -4147,8 +4225,8 @@ static int nv_set_ringparam(struct net_d
if (netif_running(dev)) {
nv_disable_irq(dev);
- netif_tx_lock_bh(dev);
spin_lock(&np->lock);
+ spin_lock(&np->tx_lock);
/* stop engines */
nv_stop_rx(dev);
nv_stop_tx(dev);
@@ -4197,8 +4275,8 @@ static int nv_set_ringparam(struct net_d
/* restart engines */
nv_start_rx(dev);
nv_start_tx(dev);
+ spin_unlock(&np->tx_lock);
spin_unlock(&np->lock);
- netif_tx_unlock_bh(dev);
nv_enable_irq(dev);
}
return 0;
@@ -4234,13 +4312,13 @@ static int nv_set_pauseparam(struct net_
netif_carrier_off(dev);
if (netif_running(dev)) {
nv_disable_irq(dev);
- netif_tx_lock_bh(dev);
spin_lock(&np->lock);
+ spin_lock(&np->tx_lock);
/* stop engines */
nv_stop_rx(dev);
nv_stop_tx(dev);
+ spin_unlock(&np->tx_lock);
spin_unlock(&np->lock);
- netif_tx_unlock_bh(dev);
}
np->pause_flags &= ~(NV_PAUSEFRAME_RX_REQ|NV_PAUSEFRAME_TX_REQ);
@@ -4629,8 +4707,8 @@ static void nv_self_test(struct net_devi
#ifdef CONFIG_FORCEDETH_NAPI
napi_disable(&np->napi);
#endif
- netif_tx_lock_bh(dev);
spin_lock_irq(&np->lock);
+ spin_unlock(&np->lock);
nv_disable_hw_interrupts(dev, np->irqmask);
if (!(np->msi_flags & NV_MSI_X_ENABLED)) {
writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus);
@@ -4644,8 +4722,8 @@ static void nv_self_test(struct net_devi
/* drain rx queue */
nv_drain_rx(dev);
nv_drain_tx(dev);
+ spin_unlock(&np->tx_lock);
spin_unlock_irq(&np->lock);
- netif_tx_unlock_bh(dev);
}
if (!nv_register_test(dev)) {
@@ -5064,6 +5142,10 @@ static int __devinit nv_probe(struct pci
/* copy of driver data */
np->driver_data = id->driver_data;
+ spin_lock_init(&np->tx_lock);
+
+ dev->features |= NETIF_F_LLTX;
+
/* handle different descriptor versions */
if (id->driver_data & DEV_HAS_HIGH_DMA) {
/* packet format 3: supports 40-bit addressing */
^ permalink raw reply
* [RFC PATCH v9 06/18] LSM: Add inet_sys_snd_skb() LSM hook (fwd)
From: James Morris @ 2007-12-22 0:51 UTC (permalink / raw)
To: netdev; +Cc: Paul Moore, David S. Miller, Herbert Xu
This is part of a large patchset which finally "fixes" labeled networking,
which we're hoping to get into 2.6.25.
Thread @ http://thread.gmane.org/gmane.linux.kernel.lsm/4894
The patch below is the only one which is not self-contained & impacts on
core networking code.
If anyone has any objections or comments on this patch, please let us
know.
---------- Forwarded message ----------
Date: Fri, 21 Dec 2007 12:09:28 -0500
From: Paul Moore <paul.moore@hp.com>
To: selinux@tycho.nsa.gov, linux-security-module@vger.kernel.org
Cc: vyekkirala@trustedcs.com, chanson@trustedcs.com
Subject: [RFC PATCH v9 06/18] LSM: Add inet_sys_snd_skb() LSM hook
Add an inet_sys_snd_skb() LSM hook to allow the LSM to provide packet level
access control for all outbound packets. Using the existing postroute_last
netfilter hook turns out to be problematic as it is can be invoked multiple
times for a single packet, e.g. individual IPsec transforms, adding unwanted
overhead and complicating the security policy.
Signed-off-by: Paul Moore <paul.moore@hp.com>
---
include/linux/security.h | 11 +++++++++++
net/ipv4/ip_output.c | 7 +++++++
net/ipv6/ip6_output.c | 5 +++++
security/dummy.c | 8 +++++++-
security/security.c | 6 ++++++
5 files changed, 36 insertions(+), 1 deletions(-)
diff --git a/include/linux/security.h b/include/linux/security.h
index db19c92..1b8d332 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -876,6 +876,10 @@ struct request_sock;
* Sets the connection's peersid to the secmark on skb.
* @req_classify_flow:
* Sets the flow's sid to the openreq sid.
+ * @inet_sys_snd_skb:
+ * Check permissions on outgoing network packets.
+ * @skb is the packet to check
+ * @family is the packet's address family
*
* Security hooks for XFRM operations.
*
@@ -1416,6 +1420,7 @@ struct security_operations {
void (*inet_csk_clone)(struct sock *newsk, const struct request_sock *req);
void (*inet_conn_established)(struct sock *sk, struct sk_buff *skb);
void (*req_classify_flow)(const struct request_sock *req, struct flowi *fl);
+ int (*inet_sys_snd_skb)(struct sk_buff *skb, int family);
#endif /* CONFIG_SECURITY_NETWORK */
#ifdef CONFIG_SECURITY_NETWORK_XFRM
@@ -2328,6 +2333,7 @@ void security_sk_free(struct sock *sk);
void security_sk_clone(const struct sock *sk, struct sock *newsk);
void security_sk_classify_flow(struct sock *sk, struct flowi *fl);
void security_req_classify_flow(const struct request_sock *req, struct flowi *fl);
+int security_inet_sys_snd_skb(struct sk_buff *skb, int family);
void security_sock_graft(struct sock*sk, struct socket *parent);
int security_inet_conn_request(struct sock *sk,
struct sk_buff *skb, struct request_sock *req);
@@ -2471,6 +2477,11 @@ static inline void security_req_classify_flow(const struct request_sock *req, st
{
}
+static inline int security_inet_sys_snd_skb(struct sk_buff *skb, int family)
+{
+ return 0;
+}
+
static inline void security_sock_graft(struct sock* sk, struct socket *parent)
{
}
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index fd99fbd..82a7297 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -204,6 +204,8 @@ static inline int ip_skb_dst_mtu(struct sk_buff *skb)
static int ip_finish_output(struct sk_buff *skb)
{
+ int err;
+
#if defined(CONFIG_NETFILTER) && defined(CONFIG_XFRM)
/* Policy lookup after SNAT yielded a new policy */
if (skb->dst->xfrm != NULL) {
@@ -211,6 +213,11 @@ static int ip_finish_output(struct sk_buff *skb)
return dst_output(skb);
}
#endif
+
+ err = security_inet_sys_snd_skb(skb, AF_INET);
+ if (err)
+ return err;
+
if (skb->len > ip_skb_dst_mtu(skb) && !skb_is_gso(skb))
return ip_fragment(skb, ip_finish_output2);
else
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 6338a9c..44ddf32 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -72,8 +72,13 @@ static __inline__ void ipv6_select_ident(struct sk_buff *skb, struct frag_hdr *f
static int ip6_output_finish(struct sk_buff *skb)
{
+ int err;
struct dst_entry *dst = skb->dst;
+ err = security_inet_sys_snd_skb(skb, AF_INET6);
+ if (err)
+ return err;
+
if (dst->hh)
return neigh_hh_output(dst->hh, skb);
else if (dst->neighbour)
diff --git a/security/dummy.c b/security/dummy.c
index 0b62f95..384979a 100644
--- a/security/dummy.c
+++ b/security/dummy.c
@@ -848,6 +848,11 @@ static inline void dummy_req_classify_flow(const struct request_sock *req,
struct flowi *fl)
{
}
+
+static inline int dummy_inet_sys_snd_skb(struct sk_buff *skb, int family)
+{
+ return 0;
+}
#endif /* CONFIG_SECURITY_NETWORK */
#ifdef CONFIG_SECURITY_NETWORK_XFRM
@@ -1122,7 +1127,8 @@ void security_fixup_ops (struct security_operations *ops)
set_to_dummy_if_null(ops, inet_csk_clone);
set_to_dummy_if_null(ops, inet_conn_established);
set_to_dummy_if_null(ops, req_classify_flow);
- #endif /* CONFIG_SECURITY_NETWORK */
+ set_to_dummy_if_null(ops, inet_sys_snd_skb);
+#endif /* CONFIG_SECURITY_NETWORK */
#ifdef CONFIG_SECURITY_NETWORK_XFRM
set_to_dummy_if_null(ops, xfrm_policy_alloc_security);
set_to_dummy_if_null(ops, xfrm_policy_clone_security);
diff --git a/security/security.c b/security/security.c
index 3bdcada..7f55459 100644
--- a/security/security.c
+++ b/security/security.c
@@ -961,6 +961,12 @@ void security_req_classify_flow(const struct request_sock *req, struct flowi *fl
}
EXPORT_SYMBOL(security_req_classify_flow);
+int security_inet_sys_snd_skb(struct sk_buff *skb, int family)
+{
+ return security_ops->inet_sys_snd_skb(skb, family);
+}
+EXPORT_SYMBOL(security_inet_sys_snd_skb);
+
void security_sock_graft(struct sock *sk, struct socket *parent)
{
security_ops->sock_graft(sk, parent);
-
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* Re: [PATCH 2/2] phylib: add module owner to the mii_bus structure
From: Stephen Hemminger @ 2007-12-21 23:37 UTC (permalink / raw)
To: netdev
In-Reply-To: <1198245451-13929-1-git-send-email-ionut.nicu@freescale.com>
On Fri, 21 Dec 2007 15:57:31 +0200
Ionut Nicu <ionut.nicu@freescale.com> wrote:
> Prevent unloading mii bus driver module when other modules have references to some
> phydevs on that bus. Added a new member (module owner) to struct mii_bus and added
> code to increment the mii bus owner module usage count on phy_connect and decrement
> it on phy_disconnect
>
> Set the module owner in the ucc_geth_mdio driver.
>
> Signed-off-by: Ionut Nicu <ionut.nicu@freescale.com>
> ---
> drivers/net/phy/phy_device.c | 9 ++++++++-
> drivers/net/ucc_geth_mii.c | 3 +++
> include/linux/phy.h | 4 ++++
> 3 files changed, 15 insertions(+), 1 deletions(-)
>
> diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
> index 5b9e175..7dc5480 100644
> --- a/drivers/net/phy/phy_device.c
> +++ b/drivers/net/phy/phy_device.c
> @@ -178,6 +178,10 @@ struct phy_device * phy_connect(struct net_device *dev, const char *phy_id,
> if (phydev->irq > 0)
> phy_start_interrupts(phydev);
>
> + /* Increment the usage count of the mii bus owner */
> + if (!try_module_get(phydev->bus->owner))
> + return ERR_PTR(-EFAULT);
Shouldn't you get a handle before the first usage (start_interrupts)?
> +
> return phydev;
> }
> EXPORT_SYMBOL(phy_connect);
> @@ -192,9 +196,12 @@ void phy_disconnect(struct phy_device *phydev)
> phy_stop_interrupts(phydev);
>
> phy_stop_machine(phydev);
> -
> +
> phydev->adjust_link = NULL;
>
> + /* Decrement the reference count for the mii bus owner */
> + module_put(phydev->bus->owner);
> +
> phy_detach(phydev);
> }
> EXPORT_SYMBOL(phy_disconnect);
> diff --git a/drivers/net/ucc_geth_mii.c b/drivers/net/ucc_geth_mii.c
> index a3af4ea..84c7295 100644
> --- a/drivers/net/ucc_geth_mii.c
> +++ b/drivers/net/ucc_geth_mii.c
> @@ -217,6 +217,9 @@ static int uec_mdio_probe(struct of_device *ofdev, const struct of_device_id *ma
> }
> }
>
> + /* register ourselves as the owner of this bus */
> + new_bus->owner = THIS_MODULE;
> +
> err = mdiobus_register(new_bus);
> if (0 != err) {
> printk(KERN_ERR "%s: Cannot register as MDIO bus\n",
> diff --git a/include/linux/phy.h b/include/linux/phy.h
> index 554836e..04ff6a5 100644
> --- a/include/linux/phy.h
> +++ b/include/linux/phy.h
> @@ -82,6 +82,10 @@ struct mii_bus {
> const char *name;
> int id;
> void *priv;
> +
> + /* The module that owns this bus */
> + struct module *owner;
> +
> int (*read)(struct mii_bus *bus, int phy_id, int regnum);
> int (*write)(struct mii_bus *bus, int phy_id, int regnum, u16 val);
> int (*reset)(struct mii_bus *bus);
--
Stephen Hemminger <stephen.hemminger@vyatta.com>
^ permalink raw reply
* Re: [PATCH 2/4] [CORE]: datagram: basic memory accounting functions
From: Hideo AOKI @ 2007-12-22 0:22 UTC (permalink / raw)
To: David Miller
Cc: herbert, netdev, tyasui, mhiramat, satoshi.oshima.fk, billfink,
andi, johnpol, shemminger, yoshfuji, yumiko.sugita.yf
In-Reply-To: <20071220.203105.209276041.davem@davemloft.net>
David Miller wrote:
> From: Hideo AOKI <haoki@redhat.com>
> Date: Thu, 20 Dec 2007 23:18:54 -0500
>
>>> Also, the memory accounting is done at different parts in
>>> the socket code paths for stream vs. datagram. This is why
>>> everything is inconsistent, and, a mess.
>> Could you tell me more detailed information?
>
> I think the core thing is that TCP and INET protocols call into
> the memory accounting internally, either inside their own code
> paths or with inet_*() helpers.
>
> This is versus what we really want is everything happening via generic
> sk_foo() helpers.
>
> If that's what's happening already, great, just consolidate the
> datagram vs. stream stuff and it should be good.
Thank you for the explanation.
I'll do my best.
Regards,
Hideo
--
Hitachi Computer Products (America) Inc.
^ permalink raw reply
* Re: BNX2 warning
From: David Miller @ 2007-12-21 23:05 UTC (permalink / raw)
To: mchan; +Cc: netdev
In-Reply-To: <1198262055.28427.2.camel@dell>
From: "Michael Chan" <mchan@broadcom.com>
Date: Fri, 21 Dec 2007 10:34:15 -0800
> [BNX2]: Fix compiler warning.
>
> Change bnx2_init_napi() to void.
>
> Warning was noted by DaveM.
>
> Signed-off-by: Michael Chan <mchan@broadcom.com>
Applied, thanks!
^ permalink raw reply
* Re: [PATCH 2/2] XFRM: Drop packets when replay counter would overflow
From: David Miller @ 2007-12-21 22:59 UTC (permalink / raw)
To: paul.moore; +Cc: netdev, linux-audit, latten
In-Reply-To: <20071221141500.11660.12287.stgit@flek.lan>
From: Paul Moore <paul.moore@hp.com>
Date: Fri, 21 Dec 2007 09:15:00 -0500
> According to RFC4303, section 3.3.3 we need to drop outgoing packets which
> cause the replay counter to overflow:
>
> 3.3.3. Sequence Number Generation
>
> The sender's counter is initialized to 0 when an SA is established.
> The sender increments the sequence number (or ESN) counter for this
> SA and inserts the low-order 32 bits of the value into the Sequence
> Number field. Thus, the first packet sent using a given SA will
> contain a sequence number of 1.
>
> If anti-replay is enabled (the default), the sender checks to ensure
> that the counter has not cycled before inserting the new value in the
> Sequence Number field. In other words, the sender MUST NOT send a
> packet on an SA if doing so would cause the sequence number to cycle.
> An attempt to transmit a packet that would result in sequence number
> overflow is an auditable event. The audit log entry for this event
> SHOULD include the SPI value, current date/time, Source Address,
> Destination Address, and (in IPv6) the cleartext Flow ID.
>
> Signed-off-by: Paul Moore <paul.moore@hp.com>
Applied.
^ permalink raw reply
* Re: [PATCH 1/2] XFRM: RFC4303 compliant auditing
From: David Miller @ 2007-12-21 22:58 UTC (permalink / raw)
To: paul.moore; +Cc: netdev, linux-audit, latten
In-Reply-To: <20071221141454.11660.83572.stgit@flek.lan>
From: Paul Moore <paul.moore@hp.com>
Date: Fri, 21 Dec 2007 09:14:55 -0500
> This patch adds a number of new IPsec audit events to meet the auditing
> requirements of RFC4303. This includes audit hooks for the following events:
>
> * Could not find a valid SA [sections 2.1, 3.4.2]
> . xfrm_audit_state_notfound()
> . xfrm_audit_state_notfound_simple()
>
> * Sequence number overflow [section 3.3.3]
> . xfrm_audit_state_replay_overflow()
>
> * Replayed packet [section 3.4.3]
> . xfrm_audit_state_replay()
>
> * Integrity check failure [sections 3.4.4.1, 3.4.4.2]
> . xfrm_audit_state_icvfail()
>
> While RFC4304 deals only with ESP most of the changes in this patch apply to
> IPsec in general, i.e. both AH and ESP. The one case, integrity check
> failure, where ESP specific code had to be modified the same was done to the
> AH code for the sake of consistency.
>
> Signed-off-by: Paul Moore <paul.moore@hp.com>
Applied.
^ permalink raw reply
* Re: [ETH]: Combine format_addr() with print_mac().
From: Joe Perches @ 2007-12-21 22:36 UTC (permalink / raw)
To: Michael Chan; +Cc: davem, netdev, anilgv, michaelc, david.somayajulu
In-Reply-To: <1198274738.5578.2.camel@dell>
On Fri, 2007-12-21 at 14:05 -0800, Michael Chan wrote:
> [ETH]: Combine format_addr() with print_mac().
> print_mac() used by most net drivers and format_addr() used by
> net-sysfs.c are very similar and they can be integrated.
> format_addr() is also identically redefined in the qla4xxx iscsi
> driver.
> diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c
> index 6b2e454..f760d41 100644
> --- a/net/ethernet/eth.c
> +++ b/net/ethernet/eth.c
> @@ -359,10 +359,33 @@ struct net_device *alloc_etherdev_mq(int sizeof_priv, unsigned int queue_count)
> }
> EXPORT_SYMBOL(alloc_etherdev_mq);
>
> +static ssize_t _format_mac_addr(char *buf, const unsigned char *addr, int len)
> +{
> + int i;
> + char *cp = buf;
> +
> + for (i = 0; i < len; i++) {
> + cp += sprintf(cp, "%02x", addr[i]);
> + if (i == len - 1)
> + break;
> + *cp++ = ':';
> + }
> + return cp - buf;
> +}
> +
> +ssize_t format_mac_addr(char *buf, const unsigned char *addr, int len)
> +{
> + ssize_t l;
> +
> + l = _format_mac_addr(buf, addr, len);
> + strcpy(buf + l, "\n");
> + return l + 1;
> +}
> +EXPORT_SYMBOL(format_mac_addr);
> +
> char *print_mac(char *buf, const u8 *addr)
> {
> - sprintf(buf, MAC_FMT,
> - addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
> + _format_mac_addr(buf, addr, ETH_ALEN);
> return buf;
> }
> EXPORT_SYMBOL(print_mac);
I think const unsigned char *addr should be const u8 *addr
ssize_t? shouldn't it be size_t?
Indexing buf by int len is unchecked.
That could lead to unintended buffer overruns.
Maybe add a buflen argument and use snprintf?
I had a patch that added some type-safety to print_mac
and prevented this unintended buffer overrun.
It seems it wasn't applied.
---------------------------------------
Subject: Re: [PATCH net-2.6.24] introduce MAC_FMT/MAC_ARG
Date: Mon, 24 Sep 2007 10:28:36 -0700
Here is a patch that adds some type safety to print_mac
by using a struct print_mac_buf * instead of char *.
It also reduces the defconfig vmlinux size by 8 bytes.
Signed-off-by: Joe Perches <joe@perches.com>
--
include/linux/if_ether.h | 12 ++++++++++--
net/ethernet/eth.c | 6 +++---
2 files changed, 13 insertions(+), 5 deletions(-)
diff --git a/include/linux/if_ether.h b/include/linux/if_ether.h
index 57abca1..620d6b1 100644
--- a/include/linux/if_ether.h
+++ b/include/linux/if_ether.h
@@ -126,7 +126,15 @@ extern struct ctl_table ether_table[];
* Display a 6 byte device address (MAC) in a readable format.
*/
#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x"
-extern char *print_mac(char *buf, const u8 *addr);
-#define DECLARE_MAC_BUF(var) char var[18] __maybe_unused
+
+struct print_mac_buf {
+ char formatted_mac_addr[18];
+};
+
+#define DECLARE_MAC_BUF(var) \
+ struct print_mac_buf __maybe_unused _##var; \
+ struct print_mac_buf __maybe_unused *var = &_##var
+
+extern char *print_mac(struct print_mac_buf *buf, const u8 *addr);
#endif /* _LINUX_IF_ETHER_H */
diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c
index 2aaf6fa..ad82613 100644
--- a/net/ethernet/eth.c
+++ b/net/ethernet/eth.c
@@ -338,10 +338,10 @@ struct net_device *alloc_etherdev_mq(int
sizeof_priv, unsigned int queue_count)
}
EXPORT_SYMBOL(alloc_etherdev_mq);
-char *print_mac(char *buf, const u8 *addr)
+char *print_mac(struct print_mac_buf *buf, const u8 *addr)
{
- sprintf(buf, MAC_FMT,
+ sprintf(buf->formatted_mac_addr, MAC_FMT,
addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
- return buf;
+ return buf->formatted_mac_addr;
}
EXPORT_SYMBOL(print_mac);
^ permalink raw reply related
* [ETH]: Combine format_addr() with print_mac().
From: Michael Chan @ 2007-12-21 22:05 UTC (permalink / raw)
To: davem; +Cc: netdev, anilgv, joe, michaelc, david.somayajulu
[ETH]: Combine format_addr() with print_mac().
print_mac() used by most net drivers and format_addr() used by
net-sysfs.c are very similar and they can be integrated.
format_addr() is also identically redefined in the qla4xxx iscsi
driver.
Export a new function format_mac_addr() to be used by net-sysfs,
qla4xxx and others in the future. Both print_mac() and
format_mac_addr() call _format_mac_addr() to do the formatting.
Signed-off-by: Michael Chan <mchan@broadcom.com>
Cc: Joe Perches <joe@perches.com>
Cc: Mike Christie <michaelc@cs.wisc.edu>
Cc: David Somayajulu <david.somayajulu@qlogic.com>
diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c
index 89460d2..0f4562b 100644
--- a/drivers/scsi/qla4xxx/ql4_os.c
+++ b/drivers/scsi/qla4xxx/ql4_os.c
@@ -173,18 +173,6 @@ static void qla4xxx_conn_stop(struct iscsi_cls_conn *conn, int flag)
printk(KERN_ERR "iscsi: invalid stop flag %d\n", flag);
}
-static ssize_t format_addr(char *buf, const unsigned char *addr, int len)
-{
- int i;
- char *cp = buf;
-
- for (i = 0; i < len; i++)
- cp += sprintf(cp, "%02x%c", addr[i],
- i == (len - 1) ? '\n' : ':');
- return cp - buf;
-}
-
-
static int qla4xxx_host_get_param(struct Scsi_Host *shost,
enum iscsi_host_param param, char *buf)
{
@@ -193,7 +181,7 @@ static int qla4xxx_host_get_param(struct Scsi_Host *shost,
switch (param) {
case ISCSI_HOST_PARAM_HWADDRESS:
- len = format_addr(buf, ha->my_mac, MAC_ADDR_LEN);
+ len = format_mac_addr(buf, ha->my_mac, MAC_ADDR_LEN);
break;
case ISCSI_HOST_PARAM_IPADDRESS:
len = sprintf(buf, "%d.%d.%d.%d\n", ha->ip_address[0],
diff --git a/include/linux/if_ether.h b/include/linux/if_ether.h
index cc002cb..d20512c 100644
--- a/include/linux/if_ether.h
+++ b/include/linux/if_ether.h
@@ -124,10 +124,11 @@ int eth_header_parse(const struct sk_buff *skb, unsigned char *haddr);
extern struct ctl_table ether_table[];
#endif
+extern ssize_t format_mac_addr(char *buf, const unsigned char *addr, int len);
+
/*
* Display a 6 byte device address (MAC) in a readable format.
*/
-#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x"
extern char *print_mac(char *buf, const u8 *addr);
#define DECLARE_MAC_BUF(var) char var[18] __maybe_unused
diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c
index e41f4b9..e72993b 100644
--- a/net/core/net-sysfs.c
+++ b/net/core/net-sysfs.c
@@ -95,17 +95,6 @@ NETDEVICE_SHOW(type, fmt_dec);
NETDEVICE_SHOW(link_mode, fmt_dec);
/* use same locking rules as GIFHWADDR ioctl's */
-static ssize_t format_addr(char *buf, const unsigned char *addr, int len)
-{
- int i;
- char *cp = buf;
-
- for (i = 0; i < len; i++)
- cp += sprintf(cp, "%02x%c", addr[i],
- i == (len - 1) ? '\n' : ':');
- return cp - buf;
-}
-
static ssize_t show_address(struct device *dev, struct device_attribute *attr,
char *buf)
{
@@ -114,7 +103,7 @@ static ssize_t show_address(struct device *dev, struct device_attribute *attr,
read_lock(&dev_base_lock);
if (dev_isalive(net))
- ret = format_addr(buf, net->dev_addr, net->addr_len);
+ ret = format_mac_addr(buf, net->dev_addr, net->addr_len);
read_unlock(&dev_base_lock);
return ret;
}
@@ -124,7 +113,7 @@ static ssize_t show_broadcast(struct device *dev,
{
struct net_device *net = to_net_dev(dev);
if (dev_isalive(net))
- return format_addr(buf, net->broadcast, net->addr_len);
+ return format_mac_addr(buf, net->broadcast, net->addr_len);
return -EINVAL;
}
diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c
index 6b2e454..f760d41 100644
--- a/net/ethernet/eth.c
+++ b/net/ethernet/eth.c
@@ -359,10 +359,33 @@ struct net_device *alloc_etherdev_mq(int sizeof_priv, unsigned int queue_count)
}
EXPORT_SYMBOL(alloc_etherdev_mq);
+static ssize_t _format_mac_addr(char *buf, const unsigned char *addr, int len)
+{
+ int i;
+ char *cp = buf;
+
+ for (i = 0; i < len; i++) {
+ cp += sprintf(cp, "%02x", addr[i]);
+ if (i == len - 1)
+ break;
+ *cp++ = ':';
+ }
+ return cp - buf;
+}
+
+ssize_t format_mac_addr(char *buf, const unsigned char *addr, int len)
+{
+ ssize_t l;
+
+ l = _format_mac_addr(buf, addr, len);
+ strcpy(buf + l, "\n");
+ return l + 1;
+}
+EXPORT_SYMBOL(format_mac_addr);
+
char *print_mac(char *buf, const u8 *addr)
{
- sprintf(buf, MAC_FMT,
- addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
+ _format_mac_addr(buf, addr, ETH_ALEN);
return buf;
}
EXPORT_SYMBOL(print_mac);
^ 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