1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* net/atm/svc.c - ATM SVC sockets */ |
3 | |
4 | /* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */ |
5 | |
6 | #define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__ |
7 | |
8 | #include <linux/string.h> |
9 | #include <linux/net.h> /* struct socket, struct proto_ops */ |
10 | #include <linux/errno.h> /* error codes */ |
11 | #include <linux/kernel.h> /* printk */ |
12 | #include <linux/skbuff.h> |
13 | #include <linux/wait.h> |
14 | #include <linux/sched/signal.h> |
15 | #include <linux/fcntl.h> /* O_NONBLOCK */ |
16 | #include <linux/init.h> |
17 | #include <linux/atm.h> /* ATM stuff */ |
18 | #include <linux/atmsap.h> |
19 | #include <linux/atmsvc.h> |
20 | #include <linux/atmdev.h> |
21 | #include <linux/bitops.h> |
22 | #include <net/sock.h> /* for sock_no_* */ |
23 | #include <linux/uaccess.h> |
24 | #include <linux/export.h> |
25 | |
26 | #include "resources.h" |
27 | #include "common.h" /* common for PVCs and SVCs */ |
28 | #include "signaling.h" |
29 | #include "addr.h" |
30 | |
31 | #ifdef CONFIG_COMPAT |
32 | /* It actually takes struct sockaddr_atmsvc, not struct atm_iobuf */ |
33 | #define COMPAT_ATM_ADDPARTY _IOW('a', ATMIOC_SPECIAL + 4, struct compat_atm_iobuf) |
34 | #endif |
35 | |
36 | static int svc_create(struct net *net, struct socket *sock, int protocol, |
37 | int kern); |
38 | |
39 | /* |
40 | * Note: since all this is still nicely synchronized with the signaling demon, |
41 | * there's no need to protect sleep loops with clis. If signaling is |
42 | * moved into the kernel, that would change. |
43 | */ |
44 | |
45 | |
46 | static int svc_shutdown(struct socket *sock, int how) |
47 | { |
48 | return 0; |
49 | } |
50 | |
51 | static void svc_disconnect(struct atm_vcc *vcc) |
52 | { |
53 | DEFINE_WAIT(wait); |
54 | struct sk_buff *skb; |
55 | struct sock *sk = sk_atm(vcc); |
56 | |
57 | pr_debug("%p\n" , vcc); |
58 | if (test_bit(ATM_VF_REGIS, &vcc->flags)) { |
59 | sigd_enq(vcc, type: as_close, NULL, NULL, NULL); |
60 | for (;;) { |
61 | prepare_to_wait(wq_head: sk_sleep(sk), wq_entry: &wait, TASK_UNINTERRUPTIBLE); |
62 | if (test_bit(ATM_VF_RELEASED, &vcc->flags) || !sigd) |
63 | break; |
64 | schedule(); |
65 | } |
66 | finish_wait(wq_head: sk_sleep(sk), wq_entry: &wait); |
67 | } |
68 | /* beware - socket is still in use by atmsigd until the last |
69 | as_indicate has been answered */ |
70 | while ((skb = skb_dequeue(list: &sk->sk_receive_queue)) != NULL) { |
71 | atm_return(vcc, truesize: skb->truesize); |
72 | pr_debug("LISTEN REL\n" ); |
73 | sigd_enq2(NULL, type: as_reject, listen_vcc: vcc, NULL, NULL, qos: &vcc->qos, reply: 0); |
74 | dev_kfree_skb(skb); |
75 | } |
76 | clear_bit(nr: ATM_VF_REGIS, addr: &vcc->flags); |
77 | /* ... may retry later */ |
78 | } |
79 | |
80 | static int svc_release(struct socket *sock) |
81 | { |
82 | struct sock *sk = sock->sk; |
83 | struct atm_vcc *vcc; |
84 | |
85 | if (sk) { |
86 | vcc = ATM_SD(sock); |
87 | pr_debug("%p\n" , vcc); |
88 | clear_bit(nr: ATM_VF_READY, addr: &vcc->flags); |
89 | /* |
90 | * VCC pointer is used as a reference, |
91 | * so we must not free it (thereby subjecting it to re-use) |
92 | * before all pending connections are closed |
93 | */ |
94 | svc_disconnect(vcc); |
95 | vcc_release(sock); |
96 | } |
97 | return 0; |
98 | } |
99 | |
100 | static int svc_bind(struct socket *sock, struct sockaddr *sockaddr, |
101 | int sockaddr_len) |
102 | { |
103 | DEFINE_WAIT(wait); |
104 | struct sock *sk = sock->sk; |
105 | struct sockaddr_atmsvc *addr; |
106 | struct atm_vcc *vcc; |
107 | int error; |
108 | |
109 | if (sockaddr_len != sizeof(struct sockaddr_atmsvc)) |
110 | return -EINVAL; |
111 | lock_sock(sk); |
112 | if (sock->state == SS_CONNECTED) { |
113 | error = -EISCONN; |
114 | goto out; |
115 | } |
116 | if (sock->state != SS_UNCONNECTED) { |
117 | error = -EINVAL; |
118 | goto out; |
119 | } |
120 | vcc = ATM_SD(sock); |
121 | addr = (struct sockaddr_atmsvc *) sockaddr; |
122 | if (addr->sas_family != AF_ATMSVC) { |
123 | error = -EAFNOSUPPORT; |
124 | goto out; |
125 | } |
126 | clear_bit(nr: ATM_VF_BOUND, addr: &vcc->flags); |
127 | /* failing rebind will kill old binding */ |
128 | /* @@@ check memory (de)allocation on rebind */ |
129 | if (!test_bit(ATM_VF_HASQOS, &vcc->flags)) { |
130 | error = -EBADFD; |
131 | goto out; |
132 | } |
133 | vcc->local = *addr; |
134 | set_bit(nr: ATM_VF_WAITING, addr: &vcc->flags); |
135 | sigd_enq(vcc, type: as_bind, NULL, NULL, svc: &vcc->local); |
136 | for (;;) { |
137 | prepare_to_wait(wq_head: sk_sleep(sk), wq_entry: &wait, TASK_UNINTERRUPTIBLE); |
138 | if (!test_bit(ATM_VF_WAITING, &vcc->flags) || !sigd) |
139 | break; |
140 | schedule(); |
141 | } |
142 | finish_wait(wq_head: sk_sleep(sk), wq_entry: &wait); |
143 | clear_bit(nr: ATM_VF_REGIS, addr: &vcc->flags); /* doesn't count */ |
144 | if (!sigd) { |
145 | error = -EUNATCH; |
146 | goto out; |
147 | } |
148 | if (!sk->sk_err) |
149 | set_bit(nr: ATM_VF_BOUND, addr: &vcc->flags); |
150 | error = -sk->sk_err; |
151 | out: |
152 | release_sock(sk); |
153 | return error; |
154 | } |
155 | |
156 | static int svc_connect(struct socket *sock, struct sockaddr *sockaddr, |
157 | int sockaddr_len, int flags) |
158 | { |
159 | DEFINE_WAIT(wait); |
160 | struct sock *sk = sock->sk; |
161 | struct sockaddr_atmsvc *addr; |
162 | struct atm_vcc *vcc = ATM_SD(sock); |
163 | int error; |
164 | |
165 | pr_debug("%p\n" , vcc); |
166 | lock_sock(sk); |
167 | if (sockaddr_len != sizeof(struct sockaddr_atmsvc)) { |
168 | error = -EINVAL; |
169 | goto out; |
170 | } |
171 | |
172 | switch (sock->state) { |
173 | default: |
174 | error = -EINVAL; |
175 | goto out; |
176 | case SS_CONNECTED: |
177 | error = -EISCONN; |
178 | goto out; |
179 | case SS_CONNECTING: |
180 | if (test_bit(ATM_VF_WAITING, &vcc->flags)) { |
181 | error = -EALREADY; |
182 | goto out; |
183 | } |
184 | sock->state = SS_UNCONNECTED; |
185 | if (sk->sk_err) { |
186 | error = -sk->sk_err; |
187 | goto out; |
188 | } |
189 | break; |
190 | case SS_UNCONNECTED: |
191 | addr = (struct sockaddr_atmsvc *) sockaddr; |
192 | if (addr->sas_family != AF_ATMSVC) { |
193 | error = -EAFNOSUPPORT; |
194 | goto out; |
195 | } |
196 | if (!test_bit(ATM_VF_HASQOS, &vcc->flags)) { |
197 | error = -EBADFD; |
198 | goto out; |
199 | } |
200 | if (vcc->qos.txtp.traffic_class == ATM_ANYCLASS || |
201 | vcc->qos.rxtp.traffic_class == ATM_ANYCLASS) { |
202 | error = -EINVAL; |
203 | goto out; |
204 | } |
205 | if (!vcc->qos.txtp.traffic_class && |
206 | !vcc->qos.rxtp.traffic_class) { |
207 | error = -EINVAL; |
208 | goto out; |
209 | } |
210 | vcc->remote = *addr; |
211 | set_bit(nr: ATM_VF_WAITING, addr: &vcc->flags); |
212 | sigd_enq(vcc, type: as_connect, NULL, NULL, svc: &vcc->remote); |
213 | if (flags & O_NONBLOCK) { |
214 | sock->state = SS_CONNECTING; |
215 | error = -EINPROGRESS; |
216 | goto out; |
217 | } |
218 | error = 0; |
219 | prepare_to_wait(wq_head: sk_sleep(sk), wq_entry: &wait, TASK_INTERRUPTIBLE); |
220 | while (test_bit(ATM_VF_WAITING, &vcc->flags) && sigd) { |
221 | schedule(); |
222 | if (!signal_pending(current)) { |
223 | prepare_to_wait(wq_head: sk_sleep(sk), wq_entry: &wait, |
224 | TASK_INTERRUPTIBLE); |
225 | continue; |
226 | } |
227 | pr_debug("*ABORT*\n" ); |
228 | /* |
229 | * This is tricky: |
230 | * Kernel ---close--> Demon |
231 | * Kernel <--close--- Demon |
232 | * or |
233 | * Kernel ---close--> Demon |
234 | * Kernel <--error--- Demon |
235 | * or |
236 | * Kernel ---close--> Demon |
237 | * Kernel <--okay---- Demon |
238 | * Kernel <--close--- Demon |
239 | */ |
240 | sigd_enq(vcc, type: as_close, NULL, NULL, NULL); |
241 | while (test_bit(ATM_VF_WAITING, &vcc->flags) && sigd) { |
242 | prepare_to_wait(wq_head: sk_sleep(sk), wq_entry: &wait, |
243 | TASK_INTERRUPTIBLE); |
244 | schedule(); |
245 | } |
246 | if (!sk->sk_err) |
247 | while (!test_bit(ATM_VF_RELEASED, &vcc->flags) && |
248 | sigd) { |
249 | prepare_to_wait(wq_head: sk_sleep(sk), wq_entry: &wait, |
250 | TASK_INTERRUPTIBLE); |
251 | schedule(); |
252 | } |
253 | clear_bit(nr: ATM_VF_REGIS, addr: &vcc->flags); |
254 | clear_bit(nr: ATM_VF_RELEASED, addr: &vcc->flags); |
255 | clear_bit(nr: ATM_VF_CLOSE, addr: &vcc->flags); |
256 | /* we're gone now but may connect later */ |
257 | error = -EINTR; |
258 | break; |
259 | } |
260 | finish_wait(wq_head: sk_sleep(sk), wq_entry: &wait); |
261 | if (error) |
262 | goto out; |
263 | if (!sigd) { |
264 | error = -EUNATCH; |
265 | goto out; |
266 | } |
267 | if (sk->sk_err) { |
268 | error = -sk->sk_err; |
269 | goto out; |
270 | } |
271 | } |
272 | |
273 | vcc->qos.txtp.max_pcr = SELECT_TOP_PCR(vcc->qos.txtp); |
274 | vcc->qos.txtp.pcr = 0; |
275 | vcc->qos.txtp.min_pcr = 0; |
276 | |
277 | error = vcc_connect(sock, itf: vcc->itf, vpi: vcc->vpi, vci: vcc->vci); |
278 | if (!error) |
279 | sock->state = SS_CONNECTED; |
280 | else |
281 | (void)svc_disconnect(vcc); |
282 | out: |
283 | release_sock(sk); |
284 | return error; |
285 | } |
286 | |
287 | static int svc_listen(struct socket *sock, int backlog) |
288 | { |
289 | DEFINE_WAIT(wait); |
290 | struct sock *sk = sock->sk; |
291 | struct atm_vcc *vcc = ATM_SD(sock); |
292 | int error; |
293 | |
294 | pr_debug("%p\n" , vcc); |
295 | lock_sock(sk); |
296 | /* let server handle listen on unbound sockets */ |
297 | if (test_bit(ATM_VF_SESSION, &vcc->flags)) { |
298 | error = -EINVAL; |
299 | goto out; |
300 | } |
301 | if (test_bit(ATM_VF_LISTEN, &vcc->flags)) { |
302 | error = -EADDRINUSE; |
303 | goto out; |
304 | } |
305 | set_bit(nr: ATM_VF_WAITING, addr: &vcc->flags); |
306 | sigd_enq(vcc, type: as_listen, NULL, NULL, svc: &vcc->local); |
307 | for (;;) { |
308 | prepare_to_wait(wq_head: sk_sleep(sk), wq_entry: &wait, TASK_UNINTERRUPTIBLE); |
309 | if (!test_bit(ATM_VF_WAITING, &vcc->flags) || !sigd) |
310 | break; |
311 | schedule(); |
312 | } |
313 | finish_wait(wq_head: sk_sleep(sk), wq_entry: &wait); |
314 | if (!sigd) { |
315 | error = -EUNATCH; |
316 | goto out; |
317 | } |
318 | set_bit(nr: ATM_VF_LISTEN, addr: &vcc->flags); |
319 | vcc_insert_socket(sk); |
320 | sk->sk_max_ack_backlog = backlog > 0 ? backlog : ATM_BACKLOG_DEFAULT; |
321 | error = -sk->sk_err; |
322 | out: |
323 | release_sock(sk); |
324 | return error; |
325 | } |
326 | |
327 | static int svc_accept(struct socket *sock, struct socket *newsock, int flags, |
328 | bool kern) |
329 | { |
330 | struct sock *sk = sock->sk; |
331 | struct sk_buff *skb; |
332 | struct atmsvc_msg *msg; |
333 | struct atm_vcc *old_vcc = ATM_SD(sock); |
334 | struct atm_vcc *new_vcc; |
335 | int error; |
336 | |
337 | lock_sock(sk); |
338 | |
339 | error = svc_create(net: sock_net(sk), sock: newsock, protocol: 0, kern); |
340 | if (error) |
341 | goto out; |
342 | |
343 | new_vcc = ATM_SD(sock: newsock); |
344 | |
345 | pr_debug("%p -> %p\n" , old_vcc, new_vcc); |
346 | while (1) { |
347 | DEFINE_WAIT(wait); |
348 | |
349 | prepare_to_wait(wq_head: sk_sleep(sk), wq_entry: &wait, TASK_INTERRUPTIBLE); |
350 | while (!(skb = skb_dequeue(list: &sk->sk_receive_queue)) && |
351 | sigd) { |
352 | if (test_bit(ATM_VF_RELEASED, &old_vcc->flags)) |
353 | break; |
354 | if (test_bit(ATM_VF_CLOSE, &old_vcc->flags)) { |
355 | error = -sk->sk_err; |
356 | break; |
357 | } |
358 | if (flags & O_NONBLOCK) { |
359 | error = -EAGAIN; |
360 | break; |
361 | } |
362 | release_sock(sk); |
363 | schedule(); |
364 | lock_sock(sk); |
365 | if (signal_pending(current)) { |
366 | error = -ERESTARTSYS; |
367 | break; |
368 | } |
369 | prepare_to_wait(wq_head: sk_sleep(sk), wq_entry: &wait, |
370 | TASK_INTERRUPTIBLE); |
371 | } |
372 | finish_wait(wq_head: sk_sleep(sk), wq_entry: &wait); |
373 | if (error) |
374 | goto out; |
375 | if (!skb) { |
376 | error = -EUNATCH; |
377 | goto out; |
378 | } |
379 | msg = (struct atmsvc_msg *)skb->data; |
380 | new_vcc->qos = msg->qos; |
381 | set_bit(nr: ATM_VF_HASQOS, addr: &new_vcc->flags); |
382 | new_vcc->remote = msg->svc; |
383 | new_vcc->local = msg->local; |
384 | new_vcc->sap = msg->sap; |
385 | error = vcc_connect(sock: newsock, itf: msg->pvc.sap_addr.itf, |
386 | vpi: msg->pvc.sap_addr.vpi, |
387 | vci: msg->pvc.sap_addr.vci); |
388 | dev_kfree_skb(skb); |
389 | sk_acceptq_removed(sk); |
390 | if (error) { |
391 | sigd_enq2(NULL, type: as_reject, listen_vcc: old_vcc, NULL, NULL, |
392 | qos: &old_vcc->qos, reply: error); |
393 | error = error == -EAGAIN ? -EBUSY : error; |
394 | goto out; |
395 | } |
396 | /* wait should be short, so we ignore the non-blocking flag */ |
397 | set_bit(nr: ATM_VF_WAITING, addr: &new_vcc->flags); |
398 | sigd_enq(vcc: new_vcc, type: as_accept, listen_vcc: old_vcc, NULL, NULL); |
399 | for (;;) { |
400 | prepare_to_wait(wq_head: sk_sleep(sk: sk_atm(vcc: new_vcc)), wq_entry: &wait, |
401 | TASK_UNINTERRUPTIBLE); |
402 | if (!test_bit(ATM_VF_WAITING, &new_vcc->flags) || !sigd) |
403 | break; |
404 | release_sock(sk); |
405 | schedule(); |
406 | lock_sock(sk); |
407 | } |
408 | finish_wait(wq_head: sk_sleep(sk: sk_atm(vcc: new_vcc)), wq_entry: &wait); |
409 | if (!sigd) { |
410 | error = -EUNATCH; |
411 | goto out; |
412 | } |
413 | if (!sk_atm(vcc: new_vcc)->sk_err) |
414 | break; |
415 | if (sk_atm(vcc: new_vcc)->sk_err != ERESTARTSYS) { |
416 | error = -sk_atm(vcc: new_vcc)->sk_err; |
417 | goto out; |
418 | } |
419 | } |
420 | newsock->state = SS_CONNECTED; |
421 | out: |
422 | release_sock(sk); |
423 | return error; |
424 | } |
425 | |
426 | static int svc_getname(struct socket *sock, struct sockaddr *sockaddr, |
427 | int peer) |
428 | { |
429 | struct sockaddr_atmsvc *addr; |
430 | |
431 | addr = (struct sockaddr_atmsvc *) sockaddr; |
432 | memcpy(addr, peer ? &ATM_SD(sock)->remote : &ATM_SD(sock)->local, |
433 | sizeof(struct sockaddr_atmsvc)); |
434 | return sizeof(struct sockaddr_atmsvc); |
435 | } |
436 | |
437 | int svc_change_qos(struct atm_vcc *vcc, struct atm_qos *qos) |
438 | { |
439 | struct sock *sk = sk_atm(vcc); |
440 | DEFINE_WAIT(wait); |
441 | |
442 | set_bit(nr: ATM_VF_WAITING, addr: &vcc->flags); |
443 | sigd_enq2(vcc, type: as_modify, NULL, NULL, svc: &vcc->local, qos, reply: 0); |
444 | for (;;) { |
445 | prepare_to_wait(wq_head: sk_sleep(sk), wq_entry: &wait, TASK_UNINTERRUPTIBLE); |
446 | if (!test_bit(ATM_VF_WAITING, &vcc->flags) || |
447 | test_bit(ATM_VF_RELEASED, &vcc->flags) || !sigd) { |
448 | break; |
449 | } |
450 | schedule(); |
451 | } |
452 | finish_wait(wq_head: sk_sleep(sk), wq_entry: &wait); |
453 | if (!sigd) |
454 | return -EUNATCH; |
455 | return -sk->sk_err; |
456 | } |
457 | |
458 | static int svc_setsockopt(struct socket *sock, int level, int optname, |
459 | sockptr_t optval, unsigned int optlen) |
460 | { |
461 | struct sock *sk = sock->sk; |
462 | struct atm_vcc *vcc = ATM_SD(sock); |
463 | int value, error = 0; |
464 | |
465 | lock_sock(sk); |
466 | switch (optname) { |
467 | case SO_ATMSAP: |
468 | if (level != SOL_ATM || optlen != sizeof(struct atm_sap)) { |
469 | error = -EINVAL; |
470 | goto out; |
471 | } |
472 | if (copy_from_sockptr(dst: &vcc->sap, src: optval, size: optlen)) { |
473 | error = -EFAULT; |
474 | goto out; |
475 | } |
476 | set_bit(nr: ATM_VF_HASSAP, addr: &vcc->flags); |
477 | break; |
478 | case SO_MULTIPOINT: |
479 | if (level != SOL_ATM || optlen != sizeof(int)) { |
480 | error = -EINVAL; |
481 | goto out; |
482 | } |
483 | if (copy_from_sockptr(dst: &value, src: optval, size: sizeof(int))) { |
484 | error = -EFAULT; |
485 | goto out; |
486 | } |
487 | if (value == 1) |
488 | set_bit(nr: ATM_VF_SESSION, addr: &vcc->flags); |
489 | else if (value == 0) |
490 | clear_bit(nr: ATM_VF_SESSION, addr: &vcc->flags); |
491 | else |
492 | error = -EINVAL; |
493 | break; |
494 | default: |
495 | error = vcc_setsockopt(sock, level, optname, optval, optlen); |
496 | } |
497 | |
498 | out: |
499 | release_sock(sk); |
500 | return error; |
501 | } |
502 | |
503 | static int svc_getsockopt(struct socket *sock, int level, int optname, |
504 | char __user *optval, int __user *optlen) |
505 | { |
506 | struct sock *sk = sock->sk; |
507 | int error = 0, len; |
508 | |
509 | lock_sock(sk); |
510 | if (!__SO_LEVEL_MATCH(optname, level) || optname != SO_ATMSAP) { |
511 | error = vcc_getsockopt(sock, level, optname, optval, optlen); |
512 | goto out; |
513 | } |
514 | if (get_user(len, optlen)) { |
515 | error = -EFAULT; |
516 | goto out; |
517 | } |
518 | if (len != sizeof(struct atm_sap)) { |
519 | error = -EINVAL; |
520 | goto out; |
521 | } |
522 | if (copy_to_user(to: optval, from: &ATM_SD(sock)->sap, n: sizeof(struct atm_sap))) { |
523 | error = -EFAULT; |
524 | goto out; |
525 | } |
526 | out: |
527 | release_sock(sk); |
528 | return error; |
529 | } |
530 | |
531 | static int svc_addparty(struct socket *sock, struct sockaddr *sockaddr, |
532 | int sockaddr_len, int flags) |
533 | { |
534 | DEFINE_WAIT(wait); |
535 | struct sock *sk = sock->sk; |
536 | struct atm_vcc *vcc = ATM_SD(sock); |
537 | int error; |
538 | |
539 | lock_sock(sk); |
540 | set_bit(nr: ATM_VF_WAITING, addr: &vcc->flags); |
541 | sigd_enq(vcc, type: as_addparty, NULL, NULL, |
542 | svc: (struct sockaddr_atmsvc *) sockaddr); |
543 | if (flags & O_NONBLOCK) { |
544 | error = -EINPROGRESS; |
545 | goto out; |
546 | } |
547 | pr_debug("added wait queue\n" ); |
548 | for (;;) { |
549 | prepare_to_wait(wq_head: sk_sleep(sk), wq_entry: &wait, TASK_INTERRUPTIBLE); |
550 | if (!test_bit(ATM_VF_WAITING, &vcc->flags) || !sigd) |
551 | break; |
552 | schedule(); |
553 | } |
554 | finish_wait(wq_head: sk_sleep(sk), wq_entry: &wait); |
555 | error = -xchg(&sk->sk_err_soft, 0); |
556 | out: |
557 | release_sock(sk); |
558 | return error; |
559 | } |
560 | |
561 | static int svc_dropparty(struct socket *sock, int ep_ref) |
562 | { |
563 | DEFINE_WAIT(wait); |
564 | struct sock *sk = sock->sk; |
565 | struct atm_vcc *vcc = ATM_SD(sock); |
566 | int error; |
567 | |
568 | lock_sock(sk); |
569 | set_bit(nr: ATM_VF_WAITING, addr: &vcc->flags); |
570 | sigd_enq2(vcc, type: as_dropparty, NULL, NULL, NULL, NULL, reply: ep_ref); |
571 | for (;;) { |
572 | prepare_to_wait(wq_head: sk_sleep(sk), wq_entry: &wait, TASK_INTERRUPTIBLE); |
573 | if (!test_bit(ATM_VF_WAITING, &vcc->flags) || !sigd) |
574 | break; |
575 | schedule(); |
576 | } |
577 | finish_wait(wq_head: sk_sleep(sk), wq_entry: &wait); |
578 | if (!sigd) { |
579 | error = -EUNATCH; |
580 | goto out; |
581 | } |
582 | error = -xchg(&sk->sk_err_soft, 0); |
583 | out: |
584 | release_sock(sk); |
585 | return error; |
586 | } |
587 | |
588 | static int svc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) |
589 | { |
590 | int error, ep_ref; |
591 | struct sockaddr_atmsvc sa; |
592 | struct atm_vcc *vcc = ATM_SD(sock); |
593 | |
594 | switch (cmd) { |
595 | case ATM_ADDPARTY: |
596 | if (!test_bit(ATM_VF_SESSION, &vcc->flags)) |
597 | return -EINVAL; |
598 | if (copy_from_user(to: &sa, from: (void __user *) arg, n: sizeof(sa))) |
599 | return -EFAULT; |
600 | error = svc_addparty(sock, sockaddr: (struct sockaddr *)&sa, sockaddr_len: sizeof(sa), |
601 | flags: 0); |
602 | break; |
603 | case ATM_DROPPARTY: |
604 | if (!test_bit(ATM_VF_SESSION, &vcc->flags)) |
605 | return -EINVAL; |
606 | if (copy_from_user(to: &ep_ref, from: (void __user *) arg, n: sizeof(int))) |
607 | return -EFAULT; |
608 | error = svc_dropparty(sock, ep_ref); |
609 | break; |
610 | default: |
611 | error = vcc_ioctl(sock, cmd, arg); |
612 | } |
613 | |
614 | return error; |
615 | } |
616 | |
617 | #ifdef CONFIG_COMPAT |
618 | static int svc_compat_ioctl(struct socket *sock, unsigned int cmd, |
619 | unsigned long arg) |
620 | { |
621 | /* The definition of ATM_ADDPARTY uses the size of struct atm_iobuf. |
622 | But actually it takes a struct sockaddr_atmsvc, which doesn't need |
623 | compat handling. So all we have to do is fix up cmd... */ |
624 | if (cmd == COMPAT_ATM_ADDPARTY) |
625 | cmd = ATM_ADDPARTY; |
626 | |
627 | if (cmd == ATM_ADDPARTY || cmd == ATM_DROPPARTY) |
628 | return svc_ioctl(sock, cmd, arg); |
629 | else |
630 | return vcc_compat_ioctl(sock, cmd, arg); |
631 | } |
632 | #endif /* CONFIG_COMPAT */ |
633 | |
634 | static const struct proto_ops svc_proto_ops = { |
635 | .family = PF_ATMSVC, |
636 | .owner = THIS_MODULE, |
637 | |
638 | .release = svc_release, |
639 | .bind = svc_bind, |
640 | .connect = svc_connect, |
641 | .socketpair = sock_no_socketpair, |
642 | .accept = svc_accept, |
643 | .getname = svc_getname, |
644 | .poll = vcc_poll, |
645 | .ioctl = svc_ioctl, |
646 | #ifdef CONFIG_COMPAT |
647 | .compat_ioctl = svc_compat_ioctl, |
648 | #endif |
649 | .gettstamp = sock_gettstamp, |
650 | .listen = svc_listen, |
651 | .shutdown = svc_shutdown, |
652 | .setsockopt = svc_setsockopt, |
653 | .getsockopt = svc_getsockopt, |
654 | .sendmsg = vcc_sendmsg, |
655 | .recvmsg = vcc_recvmsg, |
656 | .mmap = sock_no_mmap, |
657 | }; |
658 | |
659 | |
660 | static int svc_create(struct net *net, struct socket *sock, int protocol, |
661 | int kern) |
662 | { |
663 | int error; |
664 | |
665 | if (!net_eq(net1: net, net2: &init_net)) |
666 | return -EAFNOSUPPORT; |
667 | |
668 | sock->ops = &svc_proto_ops; |
669 | error = vcc_create(net, sock, protocol, AF_ATMSVC, kern); |
670 | if (error) |
671 | return error; |
672 | ATM_SD(sock)->local.sas_family = AF_ATMSVC; |
673 | ATM_SD(sock)->remote.sas_family = AF_ATMSVC; |
674 | return 0; |
675 | } |
676 | |
677 | static const struct net_proto_family svc_family_ops = { |
678 | .family = PF_ATMSVC, |
679 | .create = svc_create, |
680 | .owner = THIS_MODULE, |
681 | }; |
682 | |
683 | |
684 | /* |
685 | * Initialize the ATM SVC protocol family |
686 | */ |
687 | |
688 | int __init atmsvc_init(void) |
689 | { |
690 | return sock_register(fam: &svc_family_ops); |
691 | } |
692 | |
693 | void atmsvc_exit(void) |
694 | { |
695 | sock_unregister(PF_ATMSVC); |
696 | } |
697 | |