diff options
| author | David S. Miller <davem@davemloft.net> | 2008-06-03 12:14:03 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2008-06-16 21:32:46 -0400 |
| commit | 87de87d5e47f94b4ea647a5bd1bc8dc1f7930db4 (patch) | |
| tree | 09e0f3b084466a7abca17356cce7c39b7b1a8783 | |
| parent | a67fa76d8be4e24e2d61cd76438a893d4c2886f7 (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.c | 6 | ||||
| -rw-r--r-- | include/linux/wireless.h | 13 | ||||
| -rw-r--r-- | include/net/wext.h | 7 | ||||
| -rw-r--r-- | net/socket.c | 10 | ||||
| -rw-r--r-- | net/wireless/wext.c | 104 |
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 | ||
| 1760 | struct compat_iw_point { | ||
| 1761 | compat_caddr_t pointer; | ||
| 1762 | __u16 length; | ||
| 1763 | __u16 flags; | ||
| 1764 | }; | ||
| 1765 | |||
| 1766 | static int do_wireless_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) | 1760 | static 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 | |||
| 685 | struct 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); | |||
| 12 | extern void wext_proc_exit(struct net *net); | 12 | extern void wext_proc_exit(struct net *net); |
| 13 | extern int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd, | 13 | extern int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd, |
| 14 | void __user *arg); | 14 | void __user *arg); |
| 15 | extern int compat_wext_handle_ioctl(struct net *net, unsigned int cmd, | ||
| 16 | unsigned long arg); | ||
| 15 | #else | 17 | #else |
| 16 | static inline int wext_proc_init(struct net *net) | 18 | static 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 | } |
| 31 | static 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 | ||
| 1116 | static 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 | |||
| 1149 | static 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 | |||
| 1190 | int 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. |
