162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/* net/atm/svc.c - ATM SVC sockets */
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/string.h>
962306a36Sopenharmony_ci#include <linux/net.h>		/* struct socket, struct proto_ops */
1062306a36Sopenharmony_ci#include <linux/errno.h>	/* error codes */
1162306a36Sopenharmony_ci#include <linux/kernel.h>	/* printk */
1262306a36Sopenharmony_ci#include <linux/skbuff.h>
1362306a36Sopenharmony_ci#include <linux/wait.h>
1462306a36Sopenharmony_ci#include <linux/sched/signal.h>
1562306a36Sopenharmony_ci#include <linux/fcntl.h>	/* O_NONBLOCK */
1662306a36Sopenharmony_ci#include <linux/init.h>
1762306a36Sopenharmony_ci#include <linux/atm.h>		/* ATM stuff */
1862306a36Sopenharmony_ci#include <linux/atmsap.h>
1962306a36Sopenharmony_ci#include <linux/atmsvc.h>
2062306a36Sopenharmony_ci#include <linux/atmdev.h>
2162306a36Sopenharmony_ci#include <linux/bitops.h>
2262306a36Sopenharmony_ci#include <net/sock.h>		/* for sock_no_* */
2362306a36Sopenharmony_ci#include <linux/uaccess.h>
2462306a36Sopenharmony_ci#include <linux/export.h>
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#include "resources.h"
2762306a36Sopenharmony_ci#include "common.h"		/* common for PVCs and SVCs */
2862306a36Sopenharmony_ci#include "signaling.h"
2962306a36Sopenharmony_ci#include "addr.h"
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci#ifdef CONFIG_COMPAT
3262306a36Sopenharmony_ci/* It actually takes struct sockaddr_atmsvc, not struct atm_iobuf */
3362306a36Sopenharmony_ci#define COMPAT_ATM_ADDPARTY _IOW('a', ATMIOC_SPECIAL + 4, struct compat_atm_iobuf)
3462306a36Sopenharmony_ci#endif
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_cistatic int svc_create(struct net *net, struct socket *sock, int protocol,
3762306a36Sopenharmony_ci		      int kern);
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci/*
4062306a36Sopenharmony_ci * Note: since all this is still nicely synchronized with the signaling demon,
4162306a36Sopenharmony_ci *       there's no need to protect sleep loops with clis. If signaling is
4262306a36Sopenharmony_ci *       moved into the kernel, that would change.
4362306a36Sopenharmony_ci */
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_cistatic int svc_shutdown(struct socket *sock, int how)
4762306a36Sopenharmony_ci{
4862306a36Sopenharmony_ci	return 0;
4962306a36Sopenharmony_ci}
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_cistatic void svc_disconnect(struct atm_vcc *vcc)
5262306a36Sopenharmony_ci{
5362306a36Sopenharmony_ci	DEFINE_WAIT(wait);
5462306a36Sopenharmony_ci	struct sk_buff *skb;
5562306a36Sopenharmony_ci	struct sock *sk = sk_atm(vcc);
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	pr_debug("%p\n", vcc);
5862306a36Sopenharmony_ci	if (test_bit(ATM_VF_REGIS, &vcc->flags)) {
5962306a36Sopenharmony_ci		sigd_enq(vcc, as_close, NULL, NULL, NULL);
6062306a36Sopenharmony_ci		for (;;) {
6162306a36Sopenharmony_ci			prepare_to_wait(sk_sleep(sk), &wait, TASK_UNINTERRUPTIBLE);
6262306a36Sopenharmony_ci			if (test_bit(ATM_VF_RELEASED, &vcc->flags) || !sigd)
6362306a36Sopenharmony_ci				break;
6462306a36Sopenharmony_ci			schedule();
6562306a36Sopenharmony_ci		}
6662306a36Sopenharmony_ci		finish_wait(sk_sleep(sk), &wait);
6762306a36Sopenharmony_ci	}
6862306a36Sopenharmony_ci	/* beware - socket is still in use by atmsigd until the last
6962306a36Sopenharmony_ci	   as_indicate has been answered */
7062306a36Sopenharmony_ci	while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) {
7162306a36Sopenharmony_ci		atm_return(vcc, skb->truesize);
7262306a36Sopenharmony_ci		pr_debug("LISTEN REL\n");
7362306a36Sopenharmony_ci		sigd_enq2(NULL, as_reject, vcc, NULL, NULL, &vcc->qos, 0);
7462306a36Sopenharmony_ci		dev_kfree_skb(skb);
7562306a36Sopenharmony_ci	}
7662306a36Sopenharmony_ci	clear_bit(ATM_VF_REGIS, &vcc->flags);
7762306a36Sopenharmony_ci	/* ... may retry later */
7862306a36Sopenharmony_ci}
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_cistatic int svc_release(struct socket *sock)
8162306a36Sopenharmony_ci{
8262306a36Sopenharmony_ci	struct sock *sk = sock->sk;
8362306a36Sopenharmony_ci	struct atm_vcc *vcc;
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	if (sk) {
8662306a36Sopenharmony_ci		vcc = ATM_SD(sock);
8762306a36Sopenharmony_ci		pr_debug("%p\n", vcc);
8862306a36Sopenharmony_ci		clear_bit(ATM_VF_READY, &vcc->flags);
8962306a36Sopenharmony_ci		/*
9062306a36Sopenharmony_ci		 * VCC pointer is used as a reference,
9162306a36Sopenharmony_ci		 * so we must not free it (thereby subjecting it to re-use)
9262306a36Sopenharmony_ci		 * before all pending connections are closed
9362306a36Sopenharmony_ci		 */
9462306a36Sopenharmony_ci		svc_disconnect(vcc);
9562306a36Sopenharmony_ci		vcc_release(sock);
9662306a36Sopenharmony_ci	}
9762306a36Sopenharmony_ci	return 0;
9862306a36Sopenharmony_ci}
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_cistatic int svc_bind(struct socket *sock, struct sockaddr *sockaddr,
10162306a36Sopenharmony_ci		    int sockaddr_len)
10262306a36Sopenharmony_ci{
10362306a36Sopenharmony_ci	DEFINE_WAIT(wait);
10462306a36Sopenharmony_ci	struct sock *sk = sock->sk;
10562306a36Sopenharmony_ci	struct sockaddr_atmsvc *addr;
10662306a36Sopenharmony_ci	struct atm_vcc *vcc;
10762306a36Sopenharmony_ci	int error;
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	if (sockaddr_len != sizeof(struct sockaddr_atmsvc))
11062306a36Sopenharmony_ci		return -EINVAL;
11162306a36Sopenharmony_ci	lock_sock(sk);
11262306a36Sopenharmony_ci	if (sock->state == SS_CONNECTED) {
11362306a36Sopenharmony_ci		error = -EISCONN;
11462306a36Sopenharmony_ci		goto out;
11562306a36Sopenharmony_ci	}
11662306a36Sopenharmony_ci	if (sock->state != SS_UNCONNECTED) {
11762306a36Sopenharmony_ci		error = -EINVAL;
11862306a36Sopenharmony_ci		goto out;
11962306a36Sopenharmony_ci	}
12062306a36Sopenharmony_ci	vcc = ATM_SD(sock);
12162306a36Sopenharmony_ci	addr = (struct sockaddr_atmsvc *) sockaddr;
12262306a36Sopenharmony_ci	if (addr->sas_family != AF_ATMSVC) {
12362306a36Sopenharmony_ci		error = -EAFNOSUPPORT;
12462306a36Sopenharmony_ci		goto out;
12562306a36Sopenharmony_ci	}
12662306a36Sopenharmony_ci	clear_bit(ATM_VF_BOUND, &vcc->flags);
12762306a36Sopenharmony_ci	    /* failing rebind will kill old binding */
12862306a36Sopenharmony_ci	/* @@@ check memory (de)allocation on rebind */
12962306a36Sopenharmony_ci	if (!test_bit(ATM_VF_HASQOS, &vcc->flags)) {
13062306a36Sopenharmony_ci		error = -EBADFD;
13162306a36Sopenharmony_ci		goto out;
13262306a36Sopenharmony_ci	}
13362306a36Sopenharmony_ci	vcc->local = *addr;
13462306a36Sopenharmony_ci	set_bit(ATM_VF_WAITING, &vcc->flags);
13562306a36Sopenharmony_ci	sigd_enq(vcc, as_bind, NULL, NULL, &vcc->local);
13662306a36Sopenharmony_ci	for (;;) {
13762306a36Sopenharmony_ci		prepare_to_wait(sk_sleep(sk), &wait, TASK_UNINTERRUPTIBLE);
13862306a36Sopenharmony_ci		if (!test_bit(ATM_VF_WAITING, &vcc->flags) || !sigd)
13962306a36Sopenharmony_ci			break;
14062306a36Sopenharmony_ci		schedule();
14162306a36Sopenharmony_ci	}
14262306a36Sopenharmony_ci	finish_wait(sk_sleep(sk), &wait);
14362306a36Sopenharmony_ci	clear_bit(ATM_VF_REGIS, &vcc->flags); /* doesn't count */
14462306a36Sopenharmony_ci	if (!sigd) {
14562306a36Sopenharmony_ci		error = -EUNATCH;
14662306a36Sopenharmony_ci		goto out;
14762306a36Sopenharmony_ci	}
14862306a36Sopenharmony_ci	if (!sk->sk_err)
14962306a36Sopenharmony_ci		set_bit(ATM_VF_BOUND, &vcc->flags);
15062306a36Sopenharmony_ci	error = -sk->sk_err;
15162306a36Sopenharmony_ciout:
15262306a36Sopenharmony_ci	release_sock(sk);
15362306a36Sopenharmony_ci	return error;
15462306a36Sopenharmony_ci}
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_cistatic int svc_connect(struct socket *sock, struct sockaddr *sockaddr,
15762306a36Sopenharmony_ci		       int sockaddr_len, int flags)
15862306a36Sopenharmony_ci{
15962306a36Sopenharmony_ci	DEFINE_WAIT(wait);
16062306a36Sopenharmony_ci	struct sock *sk = sock->sk;
16162306a36Sopenharmony_ci	struct sockaddr_atmsvc *addr;
16262306a36Sopenharmony_ci	struct atm_vcc *vcc = ATM_SD(sock);
16362306a36Sopenharmony_ci	int error;
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	pr_debug("%p\n", vcc);
16662306a36Sopenharmony_ci	lock_sock(sk);
16762306a36Sopenharmony_ci	if (sockaddr_len != sizeof(struct sockaddr_atmsvc)) {
16862306a36Sopenharmony_ci		error = -EINVAL;
16962306a36Sopenharmony_ci		goto out;
17062306a36Sopenharmony_ci	}
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	switch (sock->state) {
17362306a36Sopenharmony_ci	default:
17462306a36Sopenharmony_ci		error = -EINVAL;
17562306a36Sopenharmony_ci		goto out;
17662306a36Sopenharmony_ci	case SS_CONNECTED:
17762306a36Sopenharmony_ci		error = -EISCONN;
17862306a36Sopenharmony_ci		goto out;
17962306a36Sopenharmony_ci	case SS_CONNECTING:
18062306a36Sopenharmony_ci		if (test_bit(ATM_VF_WAITING, &vcc->flags)) {
18162306a36Sopenharmony_ci			error = -EALREADY;
18262306a36Sopenharmony_ci			goto out;
18362306a36Sopenharmony_ci		}
18462306a36Sopenharmony_ci		sock->state = SS_UNCONNECTED;
18562306a36Sopenharmony_ci		if (sk->sk_err) {
18662306a36Sopenharmony_ci			error = -sk->sk_err;
18762306a36Sopenharmony_ci			goto out;
18862306a36Sopenharmony_ci		}
18962306a36Sopenharmony_ci		break;
19062306a36Sopenharmony_ci	case SS_UNCONNECTED:
19162306a36Sopenharmony_ci		addr = (struct sockaddr_atmsvc *) sockaddr;
19262306a36Sopenharmony_ci		if (addr->sas_family != AF_ATMSVC) {
19362306a36Sopenharmony_ci			error = -EAFNOSUPPORT;
19462306a36Sopenharmony_ci			goto out;
19562306a36Sopenharmony_ci		}
19662306a36Sopenharmony_ci		if (!test_bit(ATM_VF_HASQOS, &vcc->flags)) {
19762306a36Sopenharmony_ci			error = -EBADFD;
19862306a36Sopenharmony_ci			goto out;
19962306a36Sopenharmony_ci		}
20062306a36Sopenharmony_ci		if (vcc->qos.txtp.traffic_class == ATM_ANYCLASS ||
20162306a36Sopenharmony_ci		    vcc->qos.rxtp.traffic_class == ATM_ANYCLASS) {
20262306a36Sopenharmony_ci			error = -EINVAL;
20362306a36Sopenharmony_ci			goto out;
20462306a36Sopenharmony_ci		}
20562306a36Sopenharmony_ci		if (!vcc->qos.txtp.traffic_class &&
20662306a36Sopenharmony_ci		    !vcc->qos.rxtp.traffic_class) {
20762306a36Sopenharmony_ci			error = -EINVAL;
20862306a36Sopenharmony_ci			goto out;
20962306a36Sopenharmony_ci		}
21062306a36Sopenharmony_ci		vcc->remote = *addr;
21162306a36Sopenharmony_ci		set_bit(ATM_VF_WAITING, &vcc->flags);
21262306a36Sopenharmony_ci		sigd_enq(vcc, as_connect, NULL, NULL, &vcc->remote);
21362306a36Sopenharmony_ci		if (flags & O_NONBLOCK) {
21462306a36Sopenharmony_ci			sock->state = SS_CONNECTING;
21562306a36Sopenharmony_ci			error = -EINPROGRESS;
21662306a36Sopenharmony_ci			goto out;
21762306a36Sopenharmony_ci		}
21862306a36Sopenharmony_ci		error = 0;
21962306a36Sopenharmony_ci		prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
22062306a36Sopenharmony_ci		while (test_bit(ATM_VF_WAITING, &vcc->flags) && sigd) {
22162306a36Sopenharmony_ci			schedule();
22262306a36Sopenharmony_ci			if (!signal_pending(current)) {
22362306a36Sopenharmony_ci				prepare_to_wait(sk_sleep(sk), &wait,
22462306a36Sopenharmony_ci						TASK_INTERRUPTIBLE);
22562306a36Sopenharmony_ci				continue;
22662306a36Sopenharmony_ci			}
22762306a36Sopenharmony_ci			pr_debug("*ABORT*\n");
22862306a36Sopenharmony_ci			/*
22962306a36Sopenharmony_ci			 * This is tricky:
23062306a36Sopenharmony_ci			 *   Kernel ---close--> Demon
23162306a36Sopenharmony_ci			 *   Kernel <--close--- Demon
23262306a36Sopenharmony_ci			 * or
23362306a36Sopenharmony_ci			 *   Kernel ---close--> Demon
23462306a36Sopenharmony_ci			 *   Kernel <--error--- Demon
23562306a36Sopenharmony_ci			 * or
23662306a36Sopenharmony_ci			 *   Kernel ---close--> Demon
23762306a36Sopenharmony_ci			 *   Kernel <--okay---- Demon
23862306a36Sopenharmony_ci			 *   Kernel <--close--- Demon
23962306a36Sopenharmony_ci			 */
24062306a36Sopenharmony_ci			sigd_enq(vcc, as_close, NULL, NULL, NULL);
24162306a36Sopenharmony_ci			while (test_bit(ATM_VF_WAITING, &vcc->flags) && sigd) {
24262306a36Sopenharmony_ci				prepare_to_wait(sk_sleep(sk), &wait,
24362306a36Sopenharmony_ci						TASK_INTERRUPTIBLE);
24462306a36Sopenharmony_ci				schedule();
24562306a36Sopenharmony_ci			}
24662306a36Sopenharmony_ci			if (!sk->sk_err)
24762306a36Sopenharmony_ci				while (!test_bit(ATM_VF_RELEASED, &vcc->flags) &&
24862306a36Sopenharmony_ci				       sigd) {
24962306a36Sopenharmony_ci					prepare_to_wait(sk_sleep(sk), &wait,
25062306a36Sopenharmony_ci							TASK_INTERRUPTIBLE);
25162306a36Sopenharmony_ci					schedule();
25262306a36Sopenharmony_ci				}
25362306a36Sopenharmony_ci			clear_bit(ATM_VF_REGIS, &vcc->flags);
25462306a36Sopenharmony_ci			clear_bit(ATM_VF_RELEASED, &vcc->flags);
25562306a36Sopenharmony_ci			clear_bit(ATM_VF_CLOSE, &vcc->flags);
25662306a36Sopenharmony_ci			    /* we're gone now but may connect later */
25762306a36Sopenharmony_ci			error = -EINTR;
25862306a36Sopenharmony_ci			break;
25962306a36Sopenharmony_ci		}
26062306a36Sopenharmony_ci		finish_wait(sk_sleep(sk), &wait);
26162306a36Sopenharmony_ci		if (error)
26262306a36Sopenharmony_ci			goto out;
26362306a36Sopenharmony_ci		if (!sigd) {
26462306a36Sopenharmony_ci			error = -EUNATCH;
26562306a36Sopenharmony_ci			goto out;
26662306a36Sopenharmony_ci		}
26762306a36Sopenharmony_ci		if (sk->sk_err) {
26862306a36Sopenharmony_ci			error = -sk->sk_err;
26962306a36Sopenharmony_ci			goto out;
27062306a36Sopenharmony_ci		}
27162306a36Sopenharmony_ci	}
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	vcc->qos.txtp.max_pcr = SELECT_TOP_PCR(vcc->qos.txtp);
27462306a36Sopenharmony_ci	vcc->qos.txtp.pcr = 0;
27562306a36Sopenharmony_ci	vcc->qos.txtp.min_pcr = 0;
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	error = vcc_connect(sock, vcc->itf, vcc->vpi, vcc->vci);
27862306a36Sopenharmony_ci	if (!error)
27962306a36Sopenharmony_ci		sock->state = SS_CONNECTED;
28062306a36Sopenharmony_ci	else
28162306a36Sopenharmony_ci		(void)svc_disconnect(vcc);
28262306a36Sopenharmony_ciout:
28362306a36Sopenharmony_ci	release_sock(sk);
28462306a36Sopenharmony_ci	return error;
28562306a36Sopenharmony_ci}
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_cistatic int svc_listen(struct socket *sock, int backlog)
28862306a36Sopenharmony_ci{
28962306a36Sopenharmony_ci	DEFINE_WAIT(wait);
29062306a36Sopenharmony_ci	struct sock *sk = sock->sk;
29162306a36Sopenharmony_ci	struct atm_vcc *vcc = ATM_SD(sock);
29262306a36Sopenharmony_ci	int error;
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	pr_debug("%p\n", vcc);
29562306a36Sopenharmony_ci	lock_sock(sk);
29662306a36Sopenharmony_ci	/* let server handle listen on unbound sockets */
29762306a36Sopenharmony_ci	if (test_bit(ATM_VF_SESSION, &vcc->flags)) {
29862306a36Sopenharmony_ci		error = -EINVAL;
29962306a36Sopenharmony_ci		goto out;
30062306a36Sopenharmony_ci	}
30162306a36Sopenharmony_ci	if (test_bit(ATM_VF_LISTEN, &vcc->flags)) {
30262306a36Sopenharmony_ci		error = -EADDRINUSE;
30362306a36Sopenharmony_ci		goto out;
30462306a36Sopenharmony_ci	}
30562306a36Sopenharmony_ci	set_bit(ATM_VF_WAITING, &vcc->flags);
30662306a36Sopenharmony_ci	sigd_enq(vcc, as_listen, NULL, NULL, &vcc->local);
30762306a36Sopenharmony_ci	for (;;) {
30862306a36Sopenharmony_ci		prepare_to_wait(sk_sleep(sk), &wait, TASK_UNINTERRUPTIBLE);
30962306a36Sopenharmony_ci		if (!test_bit(ATM_VF_WAITING, &vcc->flags) || !sigd)
31062306a36Sopenharmony_ci			break;
31162306a36Sopenharmony_ci		schedule();
31262306a36Sopenharmony_ci	}
31362306a36Sopenharmony_ci	finish_wait(sk_sleep(sk), &wait);
31462306a36Sopenharmony_ci	if (!sigd) {
31562306a36Sopenharmony_ci		error = -EUNATCH;
31662306a36Sopenharmony_ci		goto out;
31762306a36Sopenharmony_ci	}
31862306a36Sopenharmony_ci	set_bit(ATM_VF_LISTEN, &vcc->flags);
31962306a36Sopenharmony_ci	vcc_insert_socket(sk);
32062306a36Sopenharmony_ci	sk->sk_max_ack_backlog = backlog > 0 ? backlog : ATM_BACKLOG_DEFAULT;
32162306a36Sopenharmony_ci	error = -sk->sk_err;
32262306a36Sopenharmony_ciout:
32362306a36Sopenharmony_ci	release_sock(sk);
32462306a36Sopenharmony_ci	return error;
32562306a36Sopenharmony_ci}
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_cistatic int svc_accept(struct socket *sock, struct socket *newsock, int flags,
32862306a36Sopenharmony_ci		      bool kern)
32962306a36Sopenharmony_ci{
33062306a36Sopenharmony_ci	struct sock *sk = sock->sk;
33162306a36Sopenharmony_ci	struct sk_buff *skb;
33262306a36Sopenharmony_ci	struct atmsvc_msg *msg;
33362306a36Sopenharmony_ci	struct atm_vcc *old_vcc = ATM_SD(sock);
33462306a36Sopenharmony_ci	struct atm_vcc *new_vcc;
33562306a36Sopenharmony_ci	int error;
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	lock_sock(sk);
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	error = svc_create(sock_net(sk), newsock, 0, kern);
34062306a36Sopenharmony_ci	if (error)
34162306a36Sopenharmony_ci		goto out;
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	new_vcc = ATM_SD(newsock);
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	pr_debug("%p -> %p\n", old_vcc, new_vcc);
34662306a36Sopenharmony_ci	while (1) {
34762306a36Sopenharmony_ci		DEFINE_WAIT(wait);
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci		prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
35062306a36Sopenharmony_ci		while (!(skb = skb_dequeue(&sk->sk_receive_queue)) &&
35162306a36Sopenharmony_ci		       sigd) {
35262306a36Sopenharmony_ci			if (test_bit(ATM_VF_RELEASED, &old_vcc->flags))
35362306a36Sopenharmony_ci				break;
35462306a36Sopenharmony_ci			if (test_bit(ATM_VF_CLOSE, &old_vcc->flags)) {
35562306a36Sopenharmony_ci				error = -sk->sk_err;
35662306a36Sopenharmony_ci				break;
35762306a36Sopenharmony_ci			}
35862306a36Sopenharmony_ci			if (flags & O_NONBLOCK) {
35962306a36Sopenharmony_ci				error = -EAGAIN;
36062306a36Sopenharmony_ci				break;
36162306a36Sopenharmony_ci			}
36262306a36Sopenharmony_ci			release_sock(sk);
36362306a36Sopenharmony_ci			schedule();
36462306a36Sopenharmony_ci			lock_sock(sk);
36562306a36Sopenharmony_ci			if (signal_pending(current)) {
36662306a36Sopenharmony_ci				error = -ERESTARTSYS;
36762306a36Sopenharmony_ci				break;
36862306a36Sopenharmony_ci			}
36962306a36Sopenharmony_ci			prepare_to_wait(sk_sleep(sk), &wait,
37062306a36Sopenharmony_ci					TASK_INTERRUPTIBLE);
37162306a36Sopenharmony_ci		}
37262306a36Sopenharmony_ci		finish_wait(sk_sleep(sk), &wait);
37362306a36Sopenharmony_ci		if (error)
37462306a36Sopenharmony_ci			goto out;
37562306a36Sopenharmony_ci		if (!skb) {
37662306a36Sopenharmony_ci			error = -EUNATCH;
37762306a36Sopenharmony_ci			goto out;
37862306a36Sopenharmony_ci		}
37962306a36Sopenharmony_ci		msg = (struct atmsvc_msg *)skb->data;
38062306a36Sopenharmony_ci		new_vcc->qos = msg->qos;
38162306a36Sopenharmony_ci		set_bit(ATM_VF_HASQOS, &new_vcc->flags);
38262306a36Sopenharmony_ci		new_vcc->remote = msg->svc;
38362306a36Sopenharmony_ci		new_vcc->local = msg->local;
38462306a36Sopenharmony_ci		new_vcc->sap = msg->sap;
38562306a36Sopenharmony_ci		error = vcc_connect(newsock, msg->pvc.sap_addr.itf,
38662306a36Sopenharmony_ci				    msg->pvc.sap_addr.vpi,
38762306a36Sopenharmony_ci				    msg->pvc.sap_addr.vci);
38862306a36Sopenharmony_ci		dev_kfree_skb(skb);
38962306a36Sopenharmony_ci		sk_acceptq_removed(sk);
39062306a36Sopenharmony_ci		if (error) {
39162306a36Sopenharmony_ci			sigd_enq2(NULL, as_reject, old_vcc, NULL, NULL,
39262306a36Sopenharmony_ci				  &old_vcc->qos, error);
39362306a36Sopenharmony_ci			error = error == -EAGAIN ? -EBUSY : error;
39462306a36Sopenharmony_ci			goto out;
39562306a36Sopenharmony_ci		}
39662306a36Sopenharmony_ci		/* wait should be short, so we ignore the non-blocking flag */
39762306a36Sopenharmony_ci		set_bit(ATM_VF_WAITING, &new_vcc->flags);
39862306a36Sopenharmony_ci		sigd_enq(new_vcc, as_accept, old_vcc, NULL, NULL);
39962306a36Sopenharmony_ci		for (;;) {
40062306a36Sopenharmony_ci			prepare_to_wait(sk_sleep(sk_atm(new_vcc)), &wait,
40162306a36Sopenharmony_ci					TASK_UNINTERRUPTIBLE);
40262306a36Sopenharmony_ci			if (!test_bit(ATM_VF_WAITING, &new_vcc->flags) || !sigd)
40362306a36Sopenharmony_ci				break;
40462306a36Sopenharmony_ci			release_sock(sk);
40562306a36Sopenharmony_ci			schedule();
40662306a36Sopenharmony_ci			lock_sock(sk);
40762306a36Sopenharmony_ci		}
40862306a36Sopenharmony_ci		finish_wait(sk_sleep(sk_atm(new_vcc)), &wait);
40962306a36Sopenharmony_ci		if (!sigd) {
41062306a36Sopenharmony_ci			error = -EUNATCH;
41162306a36Sopenharmony_ci			goto out;
41262306a36Sopenharmony_ci		}
41362306a36Sopenharmony_ci		if (!sk_atm(new_vcc)->sk_err)
41462306a36Sopenharmony_ci			break;
41562306a36Sopenharmony_ci		if (sk_atm(new_vcc)->sk_err != ERESTARTSYS) {
41662306a36Sopenharmony_ci			error = -sk_atm(new_vcc)->sk_err;
41762306a36Sopenharmony_ci			goto out;
41862306a36Sopenharmony_ci		}
41962306a36Sopenharmony_ci	}
42062306a36Sopenharmony_ci	newsock->state = SS_CONNECTED;
42162306a36Sopenharmony_ciout:
42262306a36Sopenharmony_ci	release_sock(sk);
42362306a36Sopenharmony_ci	return error;
42462306a36Sopenharmony_ci}
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_cistatic int svc_getname(struct socket *sock, struct sockaddr *sockaddr,
42762306a36Sopenharmony_ci		       int peer)
42862306a36Sopenharmony_ci{
42962306a36Sopenharmony_ci	struct sockaddr_atmsvc *addr;
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	addr = (struct sockaddr_atmsvc *) sockaddr;
43262306a36Sopenharmony_ci	memcpy(addr, peer ? &ATM_SD(sock)->remote : &ATM_SD(sock)->local,
43362306a36Sopenharmony_ci	       sizeof(struct sockaddr_atmsvc));
43462306a36Sopenharmony_ci	return sizeof(struct sockaddr_atmsvc);
43562306a36Sopenharmony_ci}
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ciint svc_change_qos(struct atm_vcc *vcc, struct atm_qos *qos)
43862306a36Sopenharmony_ci{
43962306a36Sopenharmony_ci	struct sock *sk = sk_atm(vcc);
44062306a36Sopenharmony_ci	DEFINE_WAIT(wait);
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci	set_bit(ATM_VF_WAITING, &vcc->flags);
44362306a36Sopenharmony_ci	sigd_enq2(vcc, as_modify, NULL, NULL, &vcc->local, qos, 0);
44462306a36Sopenharmony_ci	for (;;) {
44562306a36Sopenharmony_ci		prepare_to_wait(sk_sleep(sk), &wait, TASK_UNINTERRUPTIBLE);
44662306a36Sopenharmony_ci		if (!test_bit(ATM_VF_WAITING, &vcc->flags) ||
44762306a36Sopenharmony_ci		    test_bit(ATM_VF_RELEASED, &vcc->flags) || !sigd) {
44862306a36Sopenharmony_ci			break;
44962306a36Sopenharmony_ci		}
45062306a36Sopenharmony_ci		schedule();
45162306a36Sopenharmony_ci	}
45262306a36Sopenharmony_ci	finish_wait(sk_sleep(sk), &wait);
45362306a36Sopenharmony_ci	if (!sigd)
45462306a36Sopenharmony_ci		return -EUNATCH;
45562306a36Sopenharmony_ci	return -sk->sk_err;
45662306a36Sopenharmony_ci}
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_cistatic int svc_setsockopt(struct socket *sock, int level, int optname,
45962306a36Sopenharmony_ci			  sockptr_t optval, unsigned int optlen)
46062306a36Sopenharmony_ci{
46162306a36Sopenharmony_ci	struct sock *sk = sock->sk;
46262306a36Sopenharmony_ci	struct atm_vcc *vcc = ATM_SD(sock);
46362306a36Sopenharmony_ci	int value, error = 0;
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci	lock_sock(sk);
46662306a36Sopenharmony_ci	switch (optname) {
46762306a36Sopenharmony_ci	case SO_ATMSAP:
46862306a36Sopenharmony_ci		if (level != SOL_ATM || optlen != sizeof(struct atm_sap)) {
46962306a36Sopenharmony_ci			error = -EINVAL;
47062306a36Sopenharmony_ci			goto out;
47162306a36Sopenharmony_ci		}
47262306a36Sopenharmony_ci		if (copy_from_sockptr(&vcc->sap, optval, optlen)) {
47362306a36Sopenharmony_ci			error = -EFAULT;
47462306a36Sopenharmony_ci			goto out;
47562306a36Sopenharmony_ci		}
47662306a36Sopenharmony_ci		set_bit(ATM_VF_HASSAP, &vcc->flags);
47762306a36Sopenharmony_ci		break;
47862306a36Sopenharmony_ci	case SO_MULTIPOINT:
47962306a36Sopenharmony_ci		if (level != SOL_ATM || optlen != sizeof(int)) {
48062306a36Sopenharmony_ci			error = -EINVAL;
48162306a36Sopenharmony_ci			goto out;
48262306a36Sopenharmony_ci		}
48362306a36Sopenharmony_ci		if (copy_from_sockptr(&value, optval, sizeof(int))) {
48462306a36Sopenharmony_ci			error = -EFAULT;
48562306a36Sopenharmony_ci			goto out;
48662306a36Sopenharmony_ci		}
48762306a36Sopenharmony_ci		if (value == 1)
48862306a36Sopenharmony_ci			set_bit(ATM_VF_SESSION, &vcc->flags);
48962306a36Sopenharmony_ci		else if (value == 0)
49062306a36Sopenharmony_ci			clear_bit(ATM_VF_SESSION, &vcc->flags);
49162306a36Sopenharmony_ci		else
49262306a36Sopenharmony_ci			error = -EINVAL;
49362306a36Sopenharmony_ci		break;
49462306a36Sopenharmony_ci	default:
49562306a36Sopenharmony_ci		error = vcc_setsockopt(sock, level, optname, optval, optlen);
49662306a36Sopenharmony_ci	}
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ciout:
49962306a36Sopenharmony_ci	release_sock(sk);
50062306a36Sopenharmony_ci	return error;
50162306a36Sopenharmony_ci}
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_cistatic int svc_getsockopt(struct socket *sock, int level, int optname,
50462306a36Sopenharmony_ci			  char __user *optval, int __user *optlen)
50562306a36Sopenharmony_ci{
50662306a36Sopenharmony_ci	struct sock *sk = sock->sk;
50762306a36Sopenharmony_ci	int error = 0, len;
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	lock_sock(sk);
51062306a36Sopenharmony_ci	if (!__SO_LEVEL_MATCH(optname, level) || optname != SO_ATMSAP) {
51162306a36Sopenharmony_ci		error = vcc_getsockopt(sock, level, optname, optval, optlen);
51262306a36Sopenharmony_ci		goto out;
51362306a36Sopenharmony_ci	}
51462306a36Sopenharmony_ci	if (get_user(len, optlen)) {
51562306a36Sopenharmony_ci		error = -EFAULT;
51662306a36Sopenharmony_ci		goto out;
51762306a36Sopenharmony_ci	}
51862306a36Sopenharmony_ci	if (len != sizeof(struct atm_sap)) {
51962306a36Sopenharmony_ci		error = -EINVAL;
52062306a36Sopenharmony_ci		goto out;
52162306a36Sopenharmony_ci	}
52262306a36Sopenharmony_ci	if (copy_to_user(optval, &ATM_SD(sock)->sap, sizeof(struct atm_sap))) {
52362306a36Sopenharmony_ci		error = -EFAULT;
52462306a36Sopenharmony_ci		goto out;
52562306a36Sopenharmony_ci	}
52662306a36Sopenharmony_ciout:
52762306a36Sopenharmony_ci	release_sock(sk);
52862306a36Sopenharmony_ci	return error;
52962306a36Sopenharmony_ci}
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_cistatic int svc_addparty(struct socket *sock, struct sockaddr *sockaddr,
53262306a36Sopenharmony_ci			int sockaddr_len, int flags)
53362306a36Sopenharmony_ci{
53462306a36Sopenharmony_ci	DEFINE_WAIT(wait);
53562306a36Sopenharmony_ci	struct sock *sk = sock->sk;
53662306a36Sopenharmony_ci	struct atm_vcc *vcc = ATM_SD(sock);
53762306a36Sopenharmony_ci	int error;
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci	lock_sock(sk);
54062306a36Sopenharmony_ci	set_bit(ATM_VF_WAITING, &vcc->flags);
54162306a36Sopenharmony_ci	sigd_enq(vcc, as_addparty, NULL, NULL,
54262306a36Sopenharmony_ci		 (struct sockaddr_atmsvc *) sockaddr);
54362306a36Sopenharmony_ci	if (flags & O_NONBLOCK) {
54462306a36Sopenharmony_ci		error = -EINPROGRESS;
54562306a36Sopenharmony_ci		goto out;
54662306a36Sopenharmony_ci	}
54762306a36Sopenharmony_ci	pr_debug("added wait queue\n");
54862306a36Sopenharmony_ci	for (;;) {
54962306a36Sopenharmony_ci		prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
55062306a36Sopenharmony_ci		if (!test_bit(ATM_VF_WAITING, &vcc->flags) || !sigd)
55162306a36Sopenharmony_ci			break;
55262306a36Sopenharmony_ci		schedule();
55362306a36Sopenharmony_ci	}
55462306a36Sopenharmony_ci	finish_wait(sk_sleep(sk), &wait);
55562306a36Sopenharmony_ci	error = -xchg(&sk->sk_err_soft, 0);
55662306a36Sopenharmony_ciout:
55762306a36Sopenharmony_ci	release_sock(sk);
55862306a36Sopenharmony_ci	return error;
55962306a36Sopenharmony_ci}
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_cistatic int svc_dropparty(struct socket *sock, int ep_ref)
56262306a36Sopenharmony_ci{
56362306a36Sopenharmony_ci	DEFINE_WAIT(wait);
56462306a36Sopenharmony_ci	struct sock *sk = sock->sk;
56562306a36Sopenharmony_ci	struct atm_vcc *vcc = ATM_SD(sock);
56662306a36Sopenharmony_ci	int error;
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci	lock_sock(sk);
56962306a36Sopenharmony_ci	set_bit(ATM_VF_WAITING, &vcc->flags);
57062306a36Sopenharmony_ci	sigd_enq2(vcc, as_dropparty, NULL, NULL, NULL, NULL, ep_ref);
57162306a36Sopenharmony_ci	for (;;) {
57262306a36Sopenharmony_ci		prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
57362306a36Sopenharmony_ci		if (!test_bit(ATM_VF_WAITING, &vcc->flags) || !sigd)
57462306a36Sopenharmony_ci			break;
57562306a36Sopenharmony_ci		schedule();
57662306a36Sopenharmony_ci	}
57762306a36Sopenharmony_ci	finish_wait(sk_sleep(sk), &wait);
57862306a36Sopenharmony_ci	if (!sigd) {
57962306a36Sopenharmony_ci		error = -EUNATCH;
58062306a36Sopenharmony_ci		goto out;
58162306a36Sopenharmony_ci	}
58262306a36Sopenharmony_ci	error = -xchg(&sk->sk_err_soft, 0);
58362306a36Sopenharmony_ciout:
58462306a36Sopenharmony_ci	release_sock(sk);
58562306a36Sopenharmony_ci	return error;
58662306a36Sopenharmony_ci}
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_cistatic int svc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
58962306a36Sopenharmony_ci{
59062306a36Sopenharmony_ci	int error, ep_ref;
59162306a36Sopenharmony_ci	struct sockaddr_atmsvc sa;
59262306a36Sopenharmony_ci	struct atm_vcc *vcc = ATM_SD(sock);
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci	switch (cmd) {
59562306a36Sopenharmony_ci	case ATM_ADDPARTY:
59662306a36Sopenharmony_ci		if (!test_bit(ATM_VF_SESSION, &vcc->flags))
59762306a36Sopenharmony_ci			return -EINVAL;
59862306a36Sopenharmony_ci		if (copy_from_user(&sa, (void __user *) arg, sizeof(sa)))
59962306a36Sopenharmony_ci			return -EFAULT;
60062306a36Sopenharmony_ci		error = svc_addparty(sock, (struct sockaddr *)&sa, sizeof(sa),
60162306a36Sopenharmony_ci				     0);
60262306a36Sopenharmony_ci		break;
60362306a36Sopenharmony_ci	case ATM_DROPPARTY:
60462306a36Sopenharmony_ci		if (!test_bit(ATM_VF_SESSION, &vcc->flags))
60562306a36Sopenharmony_ci			return -EINVAL;
60662306a36Sopenharmony_ci		if (copy_from_user(&ep_ref, (void __user *) arg, sizeof(int)))
60762306a36Sopenharmony_ci			return -EFAULT;
60862306a36Sopenharmony_ci		error = svc_dropparty(sock, ep_ref);
60962306a36Sopenharmony_ci		break;
61062306a36Sopenharmony_ci	default:
61162306a36Sopenharmony_ci		error = vcc_ioctl(sock, cmd, arg);
61262306a36Sopenharmony_ci	}
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci	return error;
61562306a36Sopenharmony_ci}
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ci#ifdef CONFIG_COMPAT
61862306a36Sopenharmony_cistatic int svc_compat_ioctl(struct socket *sock, unsigned int cmd,
61962306a36Sopenharmony_ci			    unsigned long arg)
62062306a36Sopenharmony_ci{
62162306a36Sopenharmony_ci	/* The definition of ATM_ADDPARTY uses the size of struct atm_iobuf.
62262306a36Sopenharmony_ci	   But actually it takes a struct sockaddr_atmsvc, which doesn't need
62362306a36Sopenharmony_ci	   compat handling. So all we have to do is fix up cmd... */
62462306a36Sopenharmony_ci	if (cmd == COMPAT_ATM_ADDPARTY)
62562306a36Sopenharmony_ci		cmd = ATM_ADDPARTY;
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci	if (cmd == ATM_ADDPARTY || cmd == ATM_DROPPARTY)
62862306a36Sopenharmony_ci		return svc_ioctl(sock, cmd, arg);
62962306a36Sopenharmony_ci	else
63062306a36Sopenharmony_ci		return vcc_compat_ioctl(sock, cmd, arg);
63162306a36Sopenharmony_ci}
63262306a36Sopenharmony_ci#endif /* CONFIG_COMPAT */
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_cistatic const struct proto_ops svc_proto_ops = {
63562306a36Sopenharmony_ci	.family =	PF_ATMSVC,
63662306a36Sopenharmony_ci	.owner =	THIS_MODULE,
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ci	.release =	svc_release,
63962306a36Sopenharmony_ci	.bind =		svc_bind,
64062306a36Sopenharmony_ci	.connect =	svc_connect,
64162306a36Sopenharmony_ci	.socketpair =	sock_no_socketpair,
64262306a36Sopenharmony_ci	.accept =	svc_accept,
64362306a36Sopenharmony_ci	.getname =	svc_getname,
64462306a36Sopenharmony_ci	.poll =		vcc_poll,
64562306a36Sopenharmony_ci	.ioctl =	svc_ioctl,
64662306a36Sopenharmony_ci#ifdef CONFIG_COMPAT
64762306a36Sopenharmony_ci	.compat_ioctl =	svc_compat_ioctl,
64862306a36Sopenharmony_ci#endif
64962306a36Sopenharmony_ci	.gettstamp =	sock_gettstamp,
65062306a36Sopenharmony_ci	.listen =	svc_listen,
65162306a36Sopenharmony_ci	.shutdown =	svc_shutdown,
65262306a36Sopenharmony_ci	.setsockopt =	svc_setsockopt,
65362306a36Sopenharmony_ci	.getsockopt =	svc_getsockopt,
65462306a36Sopenharmony_ci	.sendmsg =	vcc_sendmsg,
65562306a36Sopenharmony_ci	.recvmsg =	vcc_recvmsg,
65662306a36Sopenharmony_ci	.mmap =		sock_no_mmap,
65762306a36Sopenharmony_ci};
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_cistatic int svc_create(struct net *net, struct socket *sock, int protocol,
66162306a36Sopenharmony_ci		      int kern)
66262306a36Sopenharmony_ci{
66362306a36Sopenharmony_ci	int error;
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci	if (!net_eq(net, &init_net))
66662306a36Sopenharmony_ci		return -EAFNOSUPPORT;
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_ci	sock->ops = &svc_proto_ops;
66962306a36Sopenharmony_ci	error = vcc_create(net, sock, protocol, AF_ATMSVC, kern);
67062306a36Sopenharmony_ci	if (error)
67162306a36Sopenharmony_ci		return error;
67262306a36Sopenharmony_ci	ATM_SD(sock)->local.sas_family = AF_ATMSVC;
67362306a36Sopenharmony_ci	ATM_SD(sock)->remote.sas_family = AF_ATMSVC;
67462306a36Sopenharmony_ci	return 0;
67562306a36Sopenharmony_ci}
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_cistatic const struct net_proto_family svc_family_ops = {
67862306a36Sopenharmony_ci	.family = PF_ATMSVC,
67962306a36Sopenharmony_ci	.create = svc_create,
68062306a36Sopenharmony_ci	.owner = THIS_MODULE,
68162306a36Sopenharmony_ci};
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci/*
68562306a36Sopenharmony_ci *	Initialize the ATM SVC protocol family
68662306a36Sopenharmony_ci */
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_ciint __init atmsvc_init(void)
68962306a36Sopenharmony_ci{
69062306a36Sopenharmony_ci	return sock_register(&svc_family_ops);
69162306a36Sopenharmony_ci}
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_civoid atmsvc_exit(void)
69462306a36Sopenharmony_ci{
69562306a36Sopenharmony_ci	sock_unregister(PF_ATMSVC);
69662306a36Sopenharmony_ci}
697