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