1 // SPDX-License-Identifier: GPL-2.0 2 /* ATM ioctl handling */ 3 4 /* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */ 5 /* 2003 John Levon <levon@movementarian.org> */ 6 7 #define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__ 8 9 #include <linux/module.h> 10 #include <linux/kmod.h> 11 #include <linux/net.h> /* struct socket, struct proto_ops */ 12 #include <linux/atm.h> /* ATM stuff */ 13 #include <linux/atmdev.h> 14 #include <linux/atmclip.h> /* CLIP_*ENCAP */ 15 #include <linux/atmarp.h> /* manifest constants */ 16 #include <linux/capability.h> 17 #include <linux/sonet.h> /* for ioctls */ 18 #include <linux/atmsvc.h> 19 #include <linux/atmmpc.h> 20 #include <net/atmclip.h> 21 #include <linux/atmlec.h> 22 #include <linux/mutex.h> 23 #include <asm/ioctls.h> 24 #include <net/compat.h> 25 26 #include "resources.h" 27 #include "signaling.h" /* for WAITING and sigd_attach */ 28 #include "common.h" 29 30 31 static DEFINE_MUTEX(ioctl_mutex); 32 static LIST_HEAD(ioctl_list); 33 34 35 void register_atm_ioctl(struct atm_ioctl *ioctl) 36 { 37 mutex_lock(&ioctl_mutex); 38 list_add_tail(&ioctl->list, &ioctl_list); 39 mutex_unlock(&ioctl_mutex); 40 } 41 EXPORT_SYMBOL(register_atm_ioctl); 42 43 void deregister_atm_ioctl(struct atm_ioctl *ioctl) 44 { 45 mutex_lock(&ioctl_mutex); 46 list_del(&ioctl->list); 47 mutex_unlock(&ioctl_mutex); 48 } 49 EXPORT_SYMBOL(deregister_atm_ioctl); 50 51 static int do_vcc_ioctl(struct socket *sock, unsigned int cmd, 52 unsigned long arg, int compat) 53 { 54 struct sock *sk = sock->sk; 55 struct atm_vcc *vcc; 56 int error; 57 struct list_head *pos; 58 void __user *argp = (void __user *)arg; 59 void __user *buf; 60 int __user *len; 61 62 vcc = ATM_SD(sock); 63 switch (cmd) { 64 case SIOCOUTQ: 65 if (sock->state != SS_CONNECTED || 66 !test_bit(ATM_VF_READY, &vcc->flags)) { 67 error = -EINVAL; 68 goto done; 69 } 70 error = put_user(sk->sk_sndbuf - sk_wmem_alloc_get(sk), 71 (int __user *)argp); 72 goto done; 73 case SIOCINQ: 74 { 75 struct sk_buff *skb; 76 int amount; 77 78 if (sock->state != SS_CONNECTED) { 79 error = -EINVAL; 80 goto done; 81 } 82 spin_lock_irq(&sk->sk_receive_queue.lock); 83 skb = skb_peek(&sk->sk_receive_queue); 84 amount = skb ? skb->len : 0; 85 spin_unlock_irq(&sk->sk_receive_queue.lock); 86 error = put_user(amount, (int __user *)argp); 87 goto done; 88 } 89 case ATM_SETSC: 90 net_warn_ratelimited("ATM_SETSC is obsolete; used by %s:%d\n", 91 current->comm, task_pid_nr(current)); 92 error = 0; 93 goto done; 94 case ATMSIGD_CTRL: 95 if (!capable(CAP_NET_ADMIN)) { 96 error = -EPERM; 97 goto done; 98 } 99 /* 100 * The user/kernel protocol for exchanging signalling 101 * info uses kernel pointers as opaque references, 102 * so the holder of the file descriptor can scribble 103 * on the kernel... so we should make sure that we 104 * have the same privileges that /proc/kcore needs 105 */ 106 if (!capable(CAP_SYS_RAWIO)) { 107 error = -EPERM; 108 goto done; 109 } 110 #ifdef CONFIG_COMPAT 111 /* WTF? I don't even want to _think_ about making this 112 work for 32-bit userspace. TBH I don't really want 113 to think about it at all. dwmw2. */ 114 if (compat) { 115 net_warn_ratelimited("32-bit task cannot be atmsigd\n"); 116 error = -EINVAL; 117 goto done; 118 } 119 #endif 120 error = sigd_attach(vcc); 121 if (!error) 122 sock->state = SS_CONNECTED; 123 goto done; 124 case ATM_SETBACKEND: 125 case ATM_NEWBACKENDIF: 126 { 127 atm_backend_t backend; 128 error = get_user(backend, (atm_backend_t __user *)argp); 129 if (error) 130 goto done; 131 switch (backend) { 132 case ATM_BACKEND_PPP: 133 request_module("pppoatm"); 134 break; 135 case ATM_BACKEND_BR2684: 136 request_module("br2684"); 137 break; 138 } 139 break; 140 } 141 case ATMMPC_CTRL: 142 case ATMMPC_DATA: 143 request_module("mpoa"); 144 break; 145 case ATMARPD_CTRL: 146 request_module("clip"); 147 break; 148 case ATMLEC_CTRL: 149 request_module("lec"); 150 break; 151 } 152 153 error = -ENOIOCTLCMD; 154 155 mutex_lock(&ioctl_mutex); 156 list_for_each(pos, &ioctl_list) { 157 struct atm_ioctl *ic = list_entry(pos, struct atm_ioctl, list); 158 if (try_module_get(ic->owner)) { 159 error = ic->ioctl(sock, cmd, arg); 160 module_put(ic->owner); 161 if (error != -ENOIOCTLCMD) 162 break; 163 } 164 } 165 mutex_unlock(&ioctl_mutex); 166 167 if (error != -ENOIOCTLCMD) 168 goto done; 169 170 if (cmd == ATM_GETNAMES) { 171 if (IS_ENABLED(CONFIG_COMPAT) && compat) { 172 #ifdef CONFIG_COMPAT 173 struct compat_atm_iobuf __user *ciobuf = argp; 174 compat_uptr_t cbuf; 175 len = &ciobuf->length; 176 if (get_user(cbuf, &ciobuf->buffer)) 177 return -EFAULT; 178 buf = compat_ptr(cbuf); 179 #endif 180 } else { 181 struct atm_iobuf __user *iobuf = argp; 182 len = &iobuf->length; 183 if (get_user(buf, &iobuf->buffer)) 184 return -EFAULT; 185 } 186 error = atm_getnames(buf, len); 187 } else { 188 int number; 189 190 if (IS_ENABLED(CONFIG_COMPAT) && compat) { 191 #ifdef CONFIG_COMPAT 192 struct compat_atmif_sioc __user *csioc = argp; 193 compat_uptr_t carg; 194 195 len = &csioc->length; 196 if (get_user(carg, &csioc->arg)) 197 return -EFAULT; 198 buf = compat_ptr(carg); 199 if (get_user(number, &csioc->number)) 200 return -EFAULT; 201 #endif 202 } else { 203 struct atmif_sioc __user *sioc = argp; 204 205 len = &sioc->length; 206 if (get_user(buf, &sioc->arg)) 207 return -EFAULT; 208 if (get_user(number, &sioc->number)) 209 return -EFAULT; 210 } 211 error = atm_dev_ioctl(cmd, buf, len, number, compat); 212 } 213 214 done: 215 return error; 216 } 217 218 int vcc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) 219 { 220 return do_vcc_ioctl(sock, cmd, arg, 0); 221 } 222 223 #ifdef CONFIG_COMPAT 224 /* 225 * FIXME: 226 * The compat_ioctl handling is duplicated, using both these conversion 227 * routines and the compat argument to the actual handlers. Both 228 * versions are somewhat incomplete and should be merged, e.g. by 229 * moving the ioctl number translation into the actual handlers and 230 * killing the conversion code. 231 * 232 * -arnd, November 2009 233 */ 234 #define ATM_GETLINKRATE32 _IOW('a', ATMIOC_ITF+1, struct compat_atmif_sioc) 235 #define ATM_GETNAMES32 _IOW('a', ATMIOC_ITF+3, struct compat_atm_iobuf) 236 #define ATM_GETTYPE32 _IOW('a', ATMIOC_ITF+4, struct compat_atmif_sioc) 237 #define ATM_GETESI32 _IOW('a', ATMIOC_ITF+5, struct compat_atmif_sioc) 238 #define ATM_GETADDR32 _IOW('a', ATMIOC_ITF+6, struct compat_atmif_sioc) 239 #define ATM_RSTADDR32 _IOW('a', ATMIOC_ITF+7, struct compat_atmif_sioc) 240 #define ATM_ADDADDR32 _IOW('a', ATMIOC_ITF+8, struct compat_atmif_sioc) 241 #define ATM_DELADDR32 _IOW('a', ATMIOC_ITF+9, struct compat_atmif_sioc) 242 #define ATM_GETCIRANGE32 _IOW('a', ATMIOC_ITF+10, struct compat_atmif_sioc) 243 #define ATM_SETCIRANGE32 _IOW('a', ATMIOC_ITF+11, struct compat_atmif_sioc) 244 #define ATM_SETESI32 _IOW('a', ATMIOC_ITF+12, struct compat_atmif_sioc) 245 #define ATM_SETESIF32 _IOW('a', ATMIOC_ITF+13, struct compat_atmif_sioc) 246 #define ATM_GETSTAT32 _IOW('a', ATMIOC_SARCOM+0, struct compat_atmif_sioc) 247 #define ATM_GETSTATZ32 _IOW('a', ATMIOC_SARCOM+1, struct compat_atmif_sioc) 248 #define ATM_GETLOOP32 _IOW('a', ATMIOC_SARCOM+2, struct compat_atmif_sioc) 249 #define ATM_SETLOOP32 _IOW('a', ATMIOC_SARCOM+3, struct compat_atmif_sioc) 250 #define ATM_QUERYLOOP32 _IOW('a', ATMIOC_SARCOM+4, struct compat_atmif_sioc) 251 252 static struct { 253 unsigned int cmd32; 254 unsigned int cmd; 255 } atm_ioctl_map[] = { 256 { ATM_GETLINKRATE32, ATM_GETLINKRATE }, 257 { ATM_GETNAMES32, ATM_GETNAMES }, 258 { ATM_GETTYPE32, ATM_GETTYPE }, 259 { ATM_GETESI32, ATM_GETESI }, 260 { ATM_GETADDR32, ATM_GETADDR }, 261 { ATM_RSTADDR32, ATM_RSTADDR }, 262 { ATM_ADDADDR32, ATM_ADDADDR }, 263 { ATM_DELADDR32, ATM_DELADDR }, 264 { ATM_GETCIRANGE32, ATM_GETCIRANGE }, 265 { ATM_SETCIRANGE32, ATM_SETCIRANGE }, 266 { ATM_SETESI32, ATM_SETESI }, 267 { ATM_SETESIF32, ATM_SETESIF }, 268 { ATM_GETSTAT32, ATM_GETSTAT }, 269 { ATM_GETSTATZ32, ATM_GETSTATZ }, 270 { ATM_GETLOOP32, ATM_GETLOOP }, 271 { ATM_SETLOOP32, ATM_SETLOOP }, 272 { ATM_QUERYLOOP32, ATM_QUERYLOOP }, 273 }; 274 275 #define NR_ATM_IOCTL ARRAY_SIZE(atm_ioctl_map) 276 277 static int do_atm_iobuf(struct socket *sock, unsigned int cmd, 278 unsigned long arg) 279 { 280 struct compat_atm_iobuf __user *iobuf32 = compat_ptr(arg); 281 u32 data; 282 283 if (get_user(data, &iobuf32->buffer)) 284 return -EFAULT; 285 286 return atm_getnames(&iobuf32->length, compat_ptr(data)); 287 } 288 289 static int do_atmif_sioc(struct socket *sock, unsigned int cmd, 290 unsigned long arg) 291 { 292 struct compat_atmif_sioc __user *sioc32 = compat_ptr(arg); 293 int number; 294 u32 data; 295 296 if (get_user(data, &sioc32->arg) || get_user(number, &sioc32->number)) 297 return -EFAULT; 298 return atm_dev_ioctl(cmd, compat_ptr(data), &sioc32->length, number, 0); 299 } 300 301 static int do_atm_ioctl(struct socket *sock, unsigned int cmd32, 302 unsigned long arg) 303 { 304 int i; 305 unsigned int cmd = 0; 306 307 switch (cmd32) { 308 case SONET_GETSTAT: 309 case SONET_GETSTATZ: 310 case SONET_GETDIAG: 311 case SONET_SETDIAG: 312 case SONET_CLRDIAG: 313 case SONET_SETFRAMING: 314 case SONET_GETFRAMING: 315 case SONET_GETFRSENSE: 316 return do_atmif_sioc(sock, cmd32, arg); 317 } 318 319 for (i = 0; i < NR_ATM_IOCTL; i++) { 320 if (cmd32 == atm_ioctl_map[i].cmd32) { 321 cmd = atm_ioctl_map[i].cmd; 322 break; 323 } 324 } 325 if (i == NR_ATM_IOCTL) 326 return -EINVAL; 327 328 switch (cmd) { 329 case ATM_GETNAMES: 330 return do_atm_iobuf(sock, cmd, arg); 331 332 case ATM_GETLINKRATE: 333 case ATM_GETTYPE: 334 case ATM_GETESI: 335 case ATM_GETADDR: 336 case ATM_RSTADDR: 337 case ATM_ADDADDR: 338 case ATM_DELADDR: 339 case ATM_GETCIRANGE: 340 case ATM_SETCIRANGE: 341 case ATM_SETESI: 342 case ATM_SETESIF: 343 case ATM_GETSTAT: 344 case ATM_GETSTATZ: 345 case ATM_GETLOOP: 346 case ATM_SETLOOP: 347 case ATM_QUERYLOOP: 348 return do_atmif_sioc(sock, cmd, arg); 349 } 350 351 return -EINVAL; 352 } 353 354 int vcc_compat_ioctl(struct socket *sock, unsigned int cmd, 355 unsigned long arg) 356 { 357 int ret; 358 359 ret = do_vcc_ioctl(sock, cmd, arg, 1); 360 if (ret != -ENOIOCTLCMD) 361 return ret; 362 363 return do_atm_ioctl(sock, cmd, arg); 364 } 365 #endif 366
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.