Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+134 -6
-6
fs/compat_ioctl.c
··· 1757 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 1760 static int do_wireless_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) 1767 1761 { 1768 1762 struct iwreq __user *iwr;
+13
include/linux/wireless.h
··· 677 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 694 * A frequency 682 695 * For numbers lower than 10^9, we encode the number in 'm' and
+7
include/net/wext.h
··· 12 12 extern void wext_proc_exit(struct net *net); 13 13 extern int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd, 14 14 void __user *arg); 15 + extern int compat_wext_handle_ioctl(struct net *net, unsigned int cmd, 16 + unsigned long arg); 15 17 #else 16 18 static inline int wext_proc_init(struct net *net) 17 19 { ··· 25 23 } 26 24 static inline int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd, 27 25 void __user *arg) 26 + { 27 + return -EINVAL; 28 + } 29 + static inline int compat_wext_handle_ioctl(struct net *net, unsigned int cmd, 30 + unsigned long arg) 28 31 { 29 32 return -EINVAL; 30 33 }
+10
net/socket.c
··· 90 90 #include <asm/unistd.h> 91 91 92 92 #include <net/compat.h> 93 + #include <net/wext.h> 93 94 94 95 #include <net/sock.h> 95 96 #include <linux/netfilter.h> ··· 2211 2210 { 2212 2211 struct socket *sock = file->private_data; 2213 2212 int ret = -ENOIOCTLCMD; 2213 + struct sock *sk; 2214 + struct net *net; 2215 + 2216 + sk = sock->sk; 2217 + net = sock_net(sk); 2214 2218 2215 2219 if (sock->ops->compat_ioctl) 2216 2220 ret = sock->ops->compat_ioctl(sock, cmd, arg); 2221 + 2222 + if (ret == -ENOIOCTLCMD && 2223 + (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST)) 2224 + ret = compat_wext_handle_ioctl(net, cmd, arg); 2217 2225 2218 2226 return ret; 2219 2227 }
+104
net/wireless/wext.c
··· 1112 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 1219 /************************* EVENT PROCESSING *************************/ 1116 1220 /* 1117 1221 * Process events generated by the wireless layer or the driver.