aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2008-06-03 12:14:03 -0400
committerDavid S. Miller <davem@davemloft.net>2008-06-16 21:32:46 -0400
commit87de87d5e47f94b4ea647a5bd1bc8dc1f7930db4 (patch)
tree09e0f3b084466a7abca17356cce7c39b7b1a8783
parenta67fa76d8be4e24e2d61cd76438a893d4c2886f7 (diff)
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>
-rw-r--r--fs/compat_ioctl.c6
-rw-r--r--include/linux/wireless.h13
-rw-r--r--include/net/wext.h7
-rw-r--r--net/socket.c10
-rw-r--r--net/wireless/wext.c104
5 files changed, 134 insertions, 6 deletions
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index 97dba0d92348..8ab850bf2eee 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -1757,12 +1757,6 @@ static int do_i2c_smbus_ioctl(unsigned int fd, unsigned int cmd, unsigned long a
1757 return sys_ioctl(fd, cmd, (unsigned long)tdata); 1757 return sys_ioctl(fd, cmd, (unsigned long)tdata);
1758} 1758}
1759 1759
1760struct compat_iw_point {
1761 compat_caddr_t pointer;
1762 __u16 length;
1763 __u16 flags;
1764};
1765
1766static int do_wireless_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) 1760static int do_wireless_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
1767{ 1761{
1768 struct iwreq __user *iwr; 1762 struct iwreq __user *iwr;
diff --git a/include/linux/wireless.h b/include/linux/wireless.h
index 4a95a0e5eeca..79d846875825 100644
--- a/include/linux/wireless.h
+++ b/include/linux/wireless.h
@@ -677,6 +677,19 @@ struct iw_point
677 __u16 flags; /* Optional params */ 677 __u16 flags; /* Optional params */
678}; 678};
679 679
680#ifdef __KERNEL__
681#ifdef CONFIG_COMPAT
682
683#include <linux/compat.h>
684
685struct compat_iw_point {
686 compat_caddr_t pointer;
687 __u16 length;
688 __u16 flags;
689};
690#endif
691#endif
692
680/* 693/*
681 * A frequency 694 * A frequency
682 * For numbers lower than 10^9, we encode the number in 'm' and 695 * 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 80b31d826b7a..6d76a39a9c5b 100644
--- a/include/net/wext.h
+++ b/include/net/wext.h
@@ -12,6 +12,8 @@ extern int wext_proc_init(struct net *net);
12extern void wext_proc_exit(struct net *net); 12extern void wext_proc_exit(struct net *net);
13extern int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd, 13extern int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd,
14 void __user *arg); 14 void __user *arg);
15extern int compat_wext_handle_ioctl(struct net *net, unsigned int cmd,
16 unsigned long arg);
15#else 17#else
16static inline int wext_proc_init(struct net *net) 18static inline int wext_proc_init(struct net *net)
17{ 19{
@@ -26,6 +28,11 @@ static inline int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned
26{ 28{
27 return -EINVAL; 29 return -EINVAL;
28} 30}
31static inline int compat_wext_handle_ioctl(struct net *net, unsigned int cmd,
32 unsigned long arg)
33{
34 return -EINVAL;
35}
29#endif 36#endif
30 37
31#endif /* __NET_WEXT_H */ 38#endif /* __NET_WEXT_H */
diff --git a/net/socket.c b/net/socket.c
index 66c4a8cf6db9..81fe82513046 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -90,6 +90,7 @@
90#include <asm/unistd.h> 90#include <asm/unistd.h>
91 91
92#include <net/compat.h> 92#include <net/compat.h>
93#include <net/wext.h>
93 94
94#include <net/sock.h> 95#include <net/sock.h>
95#include <linux/netfilter.h> 96#include <linux/netfilter.h>
@@ -2210,10 +2211,19 @@ static long compat_sock_ioctl(struct file *file, unsigned cmd,
2210{ 2211{
2211 struct socket *sock = file->private_data; 2212 struct socket *sock = file->private_data;
2212 int ret = -ENOIOCTLCMD; 2213 int ret = -ENOIOCTLCMD;
2214 struct sock *sk;
2215 struct net *net;
2216
2217 sk = sock->sk;
2218 net = sock_net(sk);
2213 2219
2214 if (sock->ops->compat_ioctl) 2220 if (sock->ops->compat_ioctl)
2215 ret = sock->ops->compat_ioctl(sock, cmd, arg); 2221 ret = sock->ops->compat_ioctl(sock, cmd, arg);
2216 2222
2223 if (ret == -ENOIOCTLCMD &&
2224 (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST))
2225 ret = compat_wext_handle_ioctl(net, cmd, arg);
2226
2217 return ret; 2227 return ret;
2218} 2228}
2219#endif 2229#endif
diff --git a/net/wireless/wext.c b/net/wireless/wext.c
index 09022cbb58ba..1a4636a9fcde 100644
--- a/net/wireless/wext.c
+++ b/net/wireless/wext.c
@@ -1112,6 +1112,110 @@ int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd,
1112 return ret; 1112 return ret;
1113} 1113}
1114 1114
1115#ifdef CONFIG_COMPAT
1116static int compat_standard_call(struct net_device *dev,
1117 struct iwreq *iwr,
1118 unsigned int cmd,
1119 iw_handler handler)
1120{
1121 const struct iw_ioctl_description *descr;
1122 struct compat_iw_point *iwp_compat;
1123 struct iw_request_info info;
1124 struct iw_point iwp;
1125 int err;
1126
1127 descr = standard_ioctl + (cmd - SIOCIWFIRST);
1128
1129 if (descr->header_type != IW_HEADER_TYPE_POINT)
1130 return ioctl_standard_call(dev, iwr, cmd, handler);
1131
1132 iwp_compat = (struct compat_iw_point *) &iwr->u.data;
1133 iwp.pointer = compat_ptr(iwp_compat->pointer);
1134 iwp.length = iwp_compat->length;
1135 iwp.flags = iwp_compat->flags;
1136
1137 info.cmd = cmd;
1138 info.flags = 0;
1139
1140 err = ioctl_standard_iw_point(&iwp, cmd, descr, handler, dev, &info);
1141
1142 iwp_compat->pointer = ptr_to_compat(iwp.pointer);
1143 iwp_compat->length = iwp.length;
1144 iwp_compat->flags = iwp.flags;
1145
1146 return err;
1147}
1148
1149static int compat_private_call(struct net_device *dev, struct iwreq *iwr,
1150 unsigned int cmd, iw_handler handler)
1151{
1152 const struct iw_priv_args *descr;
1153 struct iw_request_info info;
1154 int ret, extra_size;
1155
1156 extra_size = get_priv_descr_and_size(dev, cmd, &descr);
1157
1158 /* Prepare the call */
1159 info.cmd = cmd;
1160 info.flags = 0;
1161
1162 /* Check if we have a pointer to user space data or not. */
1163 if (extra_size == 0) {
1164 /* No extra arguments. Trivial to handle */
1165 ret = handler(dev, &info, &(iwr->u), (char *) &(iwr->u));
1166 } else {
1167 struct compat_iw_point *iwp_compat;
1168 struct iw_point iwp;
1169
1170 iwp_compat = (struct compat_iw_point *) &iwr->u.data;
1171 iwp.pointer = compat_ptr(iwp_compat->pointer);
1172 iwp.length = iwp_compat->length;
1173 iwp.flags = iwp_compat->flags;
1174
1175 ret = ioctl_private_iw_point(&iwp, cmd, descr,
1176 handler, dev, &info, extra_size);
1177
1178 iwp_compat->pointer = ptr_to_compat(iwp.pointer);
1179 iwp_compat->length = iwp.length;
1180 iwp_compat->flags = iwp.flags;
1181 }
1182
1183 /* Call commit handler if needed and defined */
1184 if (ret == -EIWCOMMIT)
1185 ret = call_commit_handler(dev);
1186
1187 return ret;
1188}
1189
1190int compat_wext_handle_ioctl(struct net *net, unsigned int cmd,
1191 unsigned long arg)
1192{
1193 void __user *argp = (void __user *)arg;
1194 struct iwreq iwr;
1195 char *colon;
1196 int ret;
1197
1198 if (copy_from_user(&iwr, argp, sizeof(struct iwreq)))
1199 return -EFAULT;
1200
1201 iwr.ifr_name[IFNAMSIZ-1] = 0;
1202 colon = strchr(iwr.ifr_name, ':');
1203 if (colon)
1204 *colon = 0;
1205
1206 ret = wext_ioctl_dispatch(net, (struct ifreq *) &iwr, cmd,
1207 compat_standard_call,
1208 compat_private_call);
1209
1210 if (ret >= 0 &&
1211 IW_IS_GET(cmd) &&
1212 copy_to_user(argp, &iwr, sizeof(struct iwreq)))
1213 return -EFAULT;
1214
1215 return ret;
1216}
1217#endif
1218
1115/************************* EVENT PROCESSING *************************/ 1219/************************* EVENT PROCESSING *************************/
1116/* 1220/*
1117 * Process events generated by the wireless layer or the driver. 1221 * Process events generated by the wireless layer or the driver.