18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* net/atm/svc.c - ATM SVC sockets */ 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/string.h> 98c2ecf20Sopenharmony_ci#include <linux/net.h> /* struct socket, struct proto_ops */ 108c2ecf20Sopenharmony_ci#include <linux/errno.h> /* error codes */ 118c2ecf20Sopenharmony_ci#include <linux/kernel.h> /* printk */ 128c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 138c2ecf20Sopenharmony_ci#include <linux/wait.h> 148c2ecf20Sopenharmony_ci#include <linux/sched/signal.h> 158c2ecf20Sopenharmony_ci#include <linux/fcntl.h> /* O_NONBLOCK */ 168c2ecf20Sopenharmony_ci#include <linux/init.h> 178c2ecf20Sopenharmony_ci#include <linux/atm.h> /* ATM stuff */ 188c2ecf20Sopenharmony_ci#include <linux/atmsap.h> 198c2ecf20Sopenharmony_ci#include <linux/atmsvc.h> 208c2ecf20Sopenharmony_ci#include <linux/atmdev.h> 218c2ecf20Sopenharmony_ci#include <linux/bitops.h> 228c2ecf20Sopenharmony_ci#include <net/sock.h> /* for sock_no_* */ 238c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 248c2ecf20Sopenharmony_ci#include <linux/export.h> 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#include "resources.h" 278c2ecf20Sopenharmony_ci#include "common.h" /* common for PVCs and SVCs */ 288c2ecf20Sopenharmony_ci#include "signaling.h" 298c2ecf20Sopenharmony_ci#include "addr.h" 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cistatic int svc_create(struct net *net, struct socket *sock, int protocol, 328c2ecf20Sopenharmony_ci int kern); 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci/* 358c2ecf20Sopenharmony_ci * Note: since all this is still nicely synchronized with the signaling demon, 368c2ecf20Sopenharmony_ci * there's no need to protect sleep loops with clis. If signaling is 378c2ecf20Sopenharmony_ci * moved into the kernel, that would change. 388c2ecf20Sopenharmony_ci */ 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_cistatic int svc_shutdown(struct socket *sock, int how) 428c2ecf20Sopenharmony_ci{ 438c2ecf20Sopenharmony_ci return 0; 448c2ecf20Sopenharmony_ci} 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_cistatic void svc_disconnect(struct atm_vcc *vcc) 478c2ecf20Sopenharmony_ci{ 488c2ecf20Sopenharmony_ci DEFINE_WAIT(wait); 498c2ecf20Sopenharmony_ci struct sk_buff *skb; 508c2ecf20Sopenharmony_ci struct sock *sk = sk_atm(vcc); 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci pr_debug("%p\n", vcc); 538c2ecf20Sopenharmony_ci if (test_bit(ATM_VF_REGIS, &vcc->flags)) { 548c2ecf20Sopenharmony_ci sigd_enq(vcc, as_close, NULL, NULL, NULL); 558c2ecf20Sopenharmony_ci for (;;) { 568c2ecf20Sopenharmony_ci prepare_to_wait(sk_sleep(sk), &wait, TASK_UNINTERRUPTIBLE); 578c2ecf20Sopenharmony_ci if (test_bit(ATM_VF_RELEASED, &vcc->flags) || !sigd) 588c2ecf20Sopenharmony_ci break; 598c2ecf20Sopenharmony_ci schedule(); 608c2ecf20Sopenharmony_ci } 618c2ecf20Sopenharmony_ci finish_wait(sk_sleep(sk), &wait); 628c2ecf20Sopenharmony_ci } 638c2ecf20Sopenharmony_ci /* beware - socket is still in use by atmsigd until the last 648c2ecf20Sopenharmony_ci as_indicate has been answered */ 658c2ecf20Sopenharmony_ci while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) { 668c2ecf20Sopenharmony_ci atm_return(vcc, skb->truesize); 678c2ecf20Sopenharmony_ci pr_debug("LISTEN REL\n"); 688c2ecf20Sopenharmony_ci sigd_enq2(NULL, as_reject, vcc, NULL, NULL, &vcc->qos, 0); 698c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 708c2ecf20Sopenharmony_ci } 718c2ecf20Sopenharmony_ci clear_bit(ATM_VF_REGIS, &vcc->flags); 728c2ecf20Sopenharmony_ci /* ... may retry later */ 738c2ecf20Sopenharmony_ci} 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_cistatic int svc_release(struct socket *sock) 768c2ecf20Sopenharmony_ci{ 778c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 788c2ecf20Sopenharmony_ci struct atm_vcc *vcc; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci if (sk) { 818c2ecf20Sopenharmony_ci vcc = ATM_SD(sock); 828c2ecf20Sopenharmony_ci pr_debug("%p\n", vcc); 838c2ecf20Sopenharmony_ci clear_bit(ATM_VF_READY, &vcc->flags); 848c2ecf20Sopenharmony_ci /* 858c2ecf20Sopenharmony_ci * VCC pointer is used as a reference, 868c2ecf20Sopenharmony_ci * so we must not free it (thereby subjecting it to re-use) 878c2ecf20Sopenharmony_ci * before all pending connections are closed 888c2ecf20Sopenharmony_ci */ 898c2ecf20Sopenharmony_ci svc_disconnect(vcc); 908c2ecf20Sopenharmony_ci vcc_release(sock); 918c2ecf20Sopenharmony_ci } 928c2ecf20Sopenharmony_ci return 0; 938c2ecf20Sopenharmony_ci} 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_cistatic int svc_bind(struct socket *sock, struct sockaddr *sockaddr, 968c2ecf20Sopenharmony_ci int sockaddr_len) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci DEFINE_WAIT(wait); 998c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 1008c2ecf20Sopenharmony_ci struct sockaddr_atmsvc *addr; 1018c2ecf20Sopenharmony_ci struct atm_vcc *vcc; 1028c2ecf20Sopenharmony_ci int error; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci if (sockaddr_len != sizeof(struct sockaddr_atmsvc)) 1058c2ecf20Sopenharmony_ci return -EINVAL; 1068c2ecf20Sopenharmony_ci lock_sock(sk); 1078c2ecf20Sopenharmony_ci if (sock->state == SS_CONNECTED) { 1088c2ecf20Sopenharmony_ci error = -EISCONN; 1098c2ecf20Sopenharmony_ci goto out; 1108c2ecf20Sopenharmony_ci } 1118c2ecf20Sopenharmony_ci if (sock->state != SS_UNCONNECTED) { 1128c2ecf20Sopenharmony_ci error = -EINVAL; 1138c2ecf20Sopenharmony_ci goto out; 1148c2ecf20Sopenharmony_ci } 1158c2ecf20Sopenharmony_ci vcc = ATM_SD(sock); 1168c2ecf20Sopenharmony_ci addr = (struct sockaddr_atmsvc *) sockaddr; 1178c2ecf20Sopenharmony_ci if (addr->sas_family != AF_ATMSVC) { 1188c2ecf20Sopenharmony_ci error = -EAFNOSUPPORT; 1198c2ecf20Sopenharmony_ci goto out; 1208c2ecf20Sopenharmony_ci } 1218c2ecf20Sopenharmony_ci clear_bit(ATM_VF_BOUND, &vcc->flags); 1228c2ecf20Sopenharmony_ci /* failing rebind will kill old binding */ 1238c2ecf20Sopenharmony_ci /* @@@ check memory (de)allocation on rebind */ 1248c2ecf20Sopenharmony_ci if (!test_bit(ATM_VF_HASQOS, &vcc->flags)) { 1258c2ecf20Sopenharmony_ci error = -EBADFD; 1268c2ecf20Sopenharmony_ci goto out; 1278c2ecf20Sopenharmony_ci } 1288c2ecf20Sopenharmony_ci vcc->local = *addr; 1298c2ecf20Sopenharmony_ci set_bit(ATM_VF_WAITING, &vcc->flags); 1308c2ecf20Sopenharmony_ci sigd_enq(vcc, as_bind, NULL, NULL, &vcc->local); 1318c2ecf20Sopenharmony_ci for (;;) { 1328c2ecf20Sopenharmony_ci prepare_to_wait(sk_sleep(sk), &wait, TASK_UNINTERRUPTIBLE); 1338c2ecf20Sopenharmony_ci if (!test_bit(ATM_VF_WAITING, &vcc->flags) || !sigd) 1348c2ecf20Sopenharmony_ci break; 1358c2ecf20Sopenharmony_ci schedule(); 1368c2ecf20Sopenharmony_ci } 1378c2ecf20Sopenharmony_ci finish_wait(sk_sleep(sk), &wait); 1388c2ecf20Sopenharmony_ci clear_bit(ATM_VF_REGIS, &vcc->flags); /* doesn't count */ 1398c2ecf20Sopenharmony_ci if (!sigd) { 1408c2ecf20Sopenharmony_ci error = -EUNATCH; 1418c2ecf20Sopenharmony_ci goto out; 1428c2ecf20Sopenharmony_ci } 1438c2ecf20Sopenharmony_ci if (!sk->sk_err) 1448c2ecf20Sopenharmony_ci set_bit(ATM_VF_BOUND, &vcc->flags); 1458c2ecf20Sopenharmony_ci error = -sk->sk_err; 1468c2ecf20Sopenharmony_ciout: 1478c2ecf20Sopenharmony_ci release_sock(sk); 1488c2ecf20Sopenharmony_ci return error; 1498c2ecf20Sopenharmony_ci} 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_cistatic int svc_connect(struct socket *sock, struct sockaddr *sockaddr, 1528c2ecf20Sopenharmony_ci int sockaddr_len, int flags) 1538c2ecf20Sopenharmony_ci{ 1548c2ecf20Sopenharmony_ci DEFINE_WAIT(wait); 1558c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 1568c2ecf20Sopenharmony_ci struct sockaddr_atmsvc *addr; 1578c2ecf20Sopenharmony_ci struct atm_vcc *vcc = ATM_SD(sock); 1588c2ecf20Sopenharmony_ci int error; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci pr_debug("%p\n", vcc); 1618c2ecf20Sopenharmony_ci lock_sock(sk); 1628c2ecf20Sopenharmony_ci if (sockaddr_len != sizeof(struct sockaddr_atmsvc)) { 1638c2ecf20Sopenharmony_ci error = -EINVAL; 1648c2ecf20Sopenharmony_ci goto out; 1658c2ecf20Sopenharmony_ci } 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci switch (sock->state) { 1688c2ecf20Sopenharmony_ci default: 1698c2ecf20Sopenharmony_ci error = -EINVAL; 1708c2ecf20Sopenharmony_ci goto out; 1718c2ecf20Sopenharmony_ci case SS_CONNECTED: 1728c2ecf20Sopenharmony_ci error = -EISCONN; 1738c2ecf20Sopenharmony_ci goto out; 1748c2ecf20Sopenharmony_ci case SS_CONNECTING: 1758c2ecf20Sopenharmony_ci if (test_bit(ATM_VF_WAITING, &vcc->flags)) { 1768c2ecf20Sopenharmony_ci error = -EALREADY; 1778c2ecf20Sopenharmony_ci goto out; 1788c2ecf20Sopenharmony_ci } 1798c2ecf20Sopenharmony_ci sock->state = SS_UNCONNECTED; 1808c2ecf20Sopenharmony_ci if (sk->sk_err) { 1818c2ecf20Sopenharmony_ci error = -sk->sk_err; 1828c2ecf20Sopenharmony_ci goto out; 1838c2ecf20Sopenharmony_ci } 1848c2ecf20Sopenharmony_ci break; 1858c2ecf20Sopenharmony_ci case SS_UNCONNECTED: 1868c2ecf20Sopenharmony_ci addr = (struct sockaddr_atmsvc *) sockaddr; 1878c2ecf20Sopenharmony_ci if (addr->sas_family != AF_ATMSVC) { 1888c2ecf20Sopenharmony_ci error = -EAFNOSUPPORT; 1898c2ecf20Sopenharmony_ci goto out; 1908c2ecf20Sopenharmony_ci } 1918c2ecf20Sopenharmony_ci if (!test_bit(ATM_VF_HASQOS, &vcc->flags)) { 1928c2ecf20Sopenharmony_ci error = -EBADFD; 1938c2ecf20Sopenharmony_ci goto out; 1948c2ecf20Sopenharmony_ci } 1958c2ecf20Sopenharmony_ci if (vcc->qos.txtp.traffic_class == ATM_ANYCLASS || 1968c2ecf20Sopenharmony_ci vcc->qos.rxtp.traffic_class == ATM_ANYCLASS) { 1978c2ecf20Sopenharmony_ci error = -EINVAL; 1988c2ecf20Sopenharmony_ci goto out; 1998c2ecf20Sopenharmony_ci } 2008c2ecf20Sopenharmony_ci if (!vcc->qos.txtp.traffic_class && 2018c2ecf20Sopenharmony_ci !vcc->qos.rxtp.traffic_class) { 2028c2ecf20Sopenharmony_ci error = -EINVAL; 2038c2ecf20Sopenharmony_ci goto out; 2048c2ecf20Sopenharmony_ci } 2058c2ecf20Sopenharmony_ci vcc->remote = *addr; 2068c2ecf20Sopenharmony_ci set_bit(ATM_VF_WAITING, &vcc->flags); 2078c2ecf20Sopenharmony_ci sigd_enq(vcc, as_connect, NULL, NULL, &vcc->remote); 2088c2ecf20Sopenharmony_ci if (flags & O_NONBLOCK) { 2098c2ecf20Sopenharmony_ci sock->state = SS_CONNECTING; 2108c2ecf20Sopenharmony_ci error = -EINPROGRESS; 2118c2ecf20Sopenharmony_ci goto out; 2128c2ecf20Sopenharmony_ci } 2138c2ecf20Sopenharmony_ci error = 0; 2148c2ecf20Sopenharmony_ci prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); 2158c2ecf20Sopenharmony_ci while (test_bit(ATM_VF_WAITING, &vcc->flags) && sigd) { 2168c2ecf20Sopenharmony_ci schedule(); 2178c2ecf20Sopenharmony_ci if (!signal_pending(current)) { 2188c2ecf20Sopenharmony_ci prepare_to_wait(sk_sleep(sk), &wait, 2198c2ecf20Sopenharmony_ci TASK_INTERRUPTIBLE); 2208c2ecf20Sopenharmony_ci continue; 2218c2ecf20Sopenharmony_ci } 2228c2ecf20Sopenharmony_ci pr_debug("*ABORT*\n"); 2238c2ecf20Sopenharmony_ci /* 2248c2ecf20Sopenharmony_ci * This is tricky: 2258c2ecf20Sopenharmony_ci * Kernel ---close--> Demon 2268c2ecf20Sopenharmony_ci * Kernel <--close--- Demon 2278c2ecf20Sopenharmony_ci * or 2288c2ecf20Sopenharmony_ci * Kernel ---close--> Demon 2298c2ecf20Sopenharmony_ci * Kernel <--error--- Demon 2308c2ecf20Sopenharmony_ci * or 2318c2ecf20Sopenharmony_ci * Kernel ---close--> Demon 2328c2ecf20Sopenharmony_ci * Kernel <--okay---- Demon 2338c2ecf20Sopenharmony_ci * Kernel <--close--- Demon 2348c2ecf20Sopenharmony_ci */ 2358c2ecf20Sopenharmony_ci sigd_enq(vcc, as_close, NULL, NULL, NULL); 2368c2ecf20Sopenharmony_ci while (test_bit(ATM_VF_WAITING, &vcc->flags) && sigd) { 2378c2ecf20Sopenharmony_ci prepare_to_wait(sk_sleep(sk), &wait, 2388c2ecf20Sopenharmony_ci TASK_INTERRUPTIBLE); 2398c2ecf20Sopenharmony_ci schedule(); 2408c2ecf20Sopenharmony_ci } 2418c2ecf20Sopenharmony_ci if (!sk->sk_err) 2428c2ecf20Sopenharmony_ci while (!test_bit(ATM_VF_RELEASED, &vcc->flags) && 2438c2ecf20Sopenharmony_ci sigd) { 2448c2ecf20Sopenharmony_ci prepare_to_wait(sk_sleep(sk), &wait, 2458c2ecf20Sopenharmony_ci TASK_INTERRUPTIBLE); 2468c2ecf20Sopenharmony_ci schedule(); 2478c2ecf20Sopenharmony_ci } 2488c2ecf20Sopenharmony_ci clear_bit(ATM_VF_REGIS, &vcc->flags); 2498c2ecf20Sopenharmony_ci clear_bit(ATM_VF_RELEASED, &vcc->flags); 2508c2ecf20Sopenharmony_ci clear_bit(ATM_VF_CLOSE, &vcc->flags); 2518c2ecf20Sopenharmony_ci /* we're gone now but may connect later */ 2528c2ecf20Sopenharmony_ci error = -EINTR; 2538c2ecf20Sopenharmony_ci break; 2548c2ecf20Sopenharmony_ci } 2558c2ecf20Sopenharmony_ci finish_wait(sk_sleep(sk), &wait); 2568c2ecf20Sopenharmony_ci if (error) 2578c2ecf20Sopenharmony_ci goto out; 2588c2ecf20Sopenharmony_ci if (!sigd) { 2598c2ecf20Sopenharmony_ci error = -EUNATCH; 2608c2ecf20Sopenharmony_ci goto out; 2618c2ecf20Sopenharmony_ci } 2628c2ecf20Sopenharmony_ci if (sk->sk_err) { 2638c2ecf20Sopenharmony_ci error = -sk->sk_err; 2648c2ecf20Sopenharmony_ci goto out; 2658c2ecf20Sopenharmony_ci } 2668c2ecf20Sopenharmony_ci } 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci vcc->qos.txtp.max_pcr = SELECT_TOP_PCR(vcc->qos.txtp); 2698c2ecf20Sopenharmony_ci vcc->qos.txtp.pcr = 0; 2708c2ecf20Sopenharmony_ci vcc->qos.txtp.min_pcr = 0; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci error = vcc_connect(sock, vcc->itf, vcc->vpi, vcc->vci); 2738c2ecf20Sopenharmony_ci if (!error) 2748c2ecf20Sopenharmony_ci sock->state = SS_CONNECTED; 2758c2ecf20Sopenharmony_ci else 2768c2ecf20Sopenharmony_ci (void)svc_disconnect(vcc); 2778c2ecf20Sopenharmony_ciout: 2788c2ecf20Sopenharmony_ci release_sock(sk); 2798c2ecf20Sopenharmony_ci return error; 2808c2ecf20Sopenharmony_ci} 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_cistatic int svc_listen(struct socket *sock, int backlog) 2838c2ecf20Sopenharmony_ci{ 2848c2ecf20Sopenharmony_ci DEFINE_WAIT(wait); 2858c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 2868c2ecf20Sopenharmony_ci struct atm_vcc *vcc = ATM_SD(sock); 2878c2ecf20Sopenharmony_ci int error; 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci pr_debug("%p\n", vcc); 2908c2ecf20Sopenharmony_ci lock_sock(sk); 2918c2ecf20Sopenharmony_ci /* let server handle listen on unbound sockets */ 2928c2ecf20Sopenharmony_ci if (test_bit(ATM_VF_SESSION, &vcc->flags)) { 2938c2ecf20Sopenharmony_ci error = -EINVAL; 2948c2ecf20Sopenharmony_ci goto out; 2958c2ecf20Sopenharmony_ci } 2968c2ecf20Sopenharmony_ci if (test_bit(ATM_VF_LISTEN, &vcc->flags)) { 2978c2ecf20Sopenharmony_ci error = -EADDRINUSE; 2988c2ecf20Sopenharmony_ci goto out; 2998c2ecf20Sopenharmony_ci } 3008c2ecf20Sopenharmony_ci set_bit(ATM_VF_WAITING, &vcc->flags); 3018c2ecf20Sopenharmony_ci sigd_enq(vcc, as_listen, NULL, NULL, &vcc->local); 3028c2ecf20Sopenharmony_ci for (;;) { 3038c2ecf20Sopenharmony_ci prepare_to_wait(sk_sleep(sk), &wait, TASK_UNINTERRUPTIBLE); 3048c2ecf20Sopenharmony_ci if (!test_bit(ATM_VF_WAITING, &vcc->flags) || !sigd) 3058c2ecf20Sopenharmony_ci break; 3068c2ecf20Sopenharmony_ci schedule(); 3078c2ecf20Sopenharmony_ci } 3088c2ecf20Sopenharmony_ci finish_wait(sk_sleep(sk), &wait); 3098c2ecf20Sopenharmony_ci if (!sigd) { 3108c2ecf20Sopenharmony_ci error = -EUNATCH; 3118c2ecf20Sopenharmony_ci goto out; 3128c2ecf20Sopenharmony_ci } 3138c2ecf20Sopenharmony_ci set_bit(ATM_VF_LISTEN, &vcc->flags); 3148c2ecf20Sopenharmony_ci vcc_insert_socket(sk); 3158c2ecf20Sopenharmony_ci sk->sk_max_ack_backlog = backlog > 0 ? backlog : ATM_BACKLOG_DEFAULT; 3168c2ecf20Sopenharmony_ci error = -sk->sk_err; 3178c2ecf20Sopenharmony_ciout: 3188c2ecf20Sopenharmony_ci release_sock(sk); 3198c2ecf20Sopenharmony_ci return error; 3208c2ecf20Sopenharmony_ci} 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_cistatic int svc_accept(struct socket *sock, struct socket *newsock, int flags, 3238c2ecf20Sopenharmony_ci bool kern) 3248c2ecf20Sopenharmony_ci{ 3258c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 3268c2ecf20Sopenharmony_ci struct sk_buff *skb; 3278c2ecf20Sopenharmony_ci struct atmsvc_msg *msg; 3288c2ecf20Sopenharmony_ci struct atm_vcc *old_vcc = ATM_SD(sock); 3298c2ecf20Sopenharmony_ci struct atm_vcc *new_vcc; 3308c2ecf20Sopenharmony_ci int error; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci lock_sock(sk); 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci error = svc_create(sock_net(sk), newsock, 0, kern); 3358c2ecf20Sopenharmony_ci if (error) 3368c2ecf20Sopenharmony_ci goto out; 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci new_vcc = ATM_SD(newsock); 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci pr_debug("%p -> %p\n", old_vcc, new_vcc); 3418c2ecf20Sopenharmony_ci while (1) { 3428c2ecf20Sopenharmony_ci DEFINE_WAIT(wait); 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); 3458c2ecf20Sopenharmony_ci while (!(skb = skb_dequeue(&sk->sk_receive_queue)) && 3468c2ecf20Sopenharmony_ci sigd) { 3478c2ecf20Sopenharmony_ci if (test_bit(ATM_VF_RELEASED, &old_vcc->flags)) 3488c2ecf20Sopenharmony_ci break; 3498c2ecf20Sopenharmony_ci if (test_bit(ATM_VF_CLOSE, &old_vcc->flags)) { 3508c2ecf20Sopenharmony_ci error = -sk->sk_err; 3518c2ecf20Sopenharmony_ci break; 3528c2ecf20Sopenharmony_ci } 3538c2ecf20Sopenharmony_ci if (flags & O_NONBLOCK) { 3548c2ecf20Sopenharmony_ci error = -EAGAIN; 3558c2ecf20Sopenharmony_ci break; 3568c2ecf20Sopenharmony_ci } 3578c2ecf20Sopenharmony_ci release_sock(sk); 3588c2ecf20Sopenharmony_ci schedule(); 3598c2ecf20Sopenharmony_ci lock_sock(sk); 3608c2ecf20Sopenharmony_ci if (signal_pending(current)) { 3618c2ecf20Sopenharmony_ci error = -ERESTARTSYS; 3628c2ecf20Sopenharmony_ci break; 3638c2ecf20Sopenharmony_ci } 3648c2ecf20Sopenharmony_ci prepare_to_wait(sk_sleep(sk), &wait, 3658c2ecf20Sopenharmony_ci TASK_INTERRUPTIBLE); 3668c2ecf20Sopenharmony_ci } 3678c2ecf20Sopenharmony_ci finish_wait(sk_sleep(sk), &wait); 3688c2ecf20Sopenharmony_ci if (error) 3698c2ecf20Sopenharmony_ci goto out; 3708c2ecf20Sopenharmony_ci if (!skb) { 3718c2ecf20Sopenharmony_ci error = -EUNATCH; 3728c2ecf20Sopenharmony_ci goto out; 3738c2ecf20Sopenharmony_ci } 3748c2ecf20Sopenharmony_ci msg = (struct atmsvc_msg *)skb->data; 3758c2ecf20Sopenharmony_ci new_vcc->qos = msg->qos; 3768c2ecf20Sopenharmony_ci set_bit(ATM_VF_HASQOS, &new_vcc->flags); 3778c2ecf20Sopenharmony_ci new_vcc->remote = msg->svc; 3788c2ecf20Sopenharmony_ci new_vcc->local = msg->local; 3798c2ecf20Sopenharmony_ci new_vcc->sap = msg->sap; 3808c2ecf20Sopenharmony_ci error = vcc_connect(newsock, msg->pvc.sap_addr.itf, 3818c2ecf20Sopenharmony_ci msg->pvc.sap_addr.vpi, 3828c2ecf20Sopenharmony_ci msg->pvc.sap_addr.vci); 3838c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 3848c2ecf20Sopenharmony_ci sk_acceptq_removed(sk); 3858c2ecf20Sopenharmony_ci if (error) { 3868c2ecf20Sopenharmony_ci sigd_enq2(NULL, as_reject, old_vcc, NULL, NULL, 3878c2ecf20Sopenharmony_ci &old_vcc->qos, error); 3888c2ecf20Sopenharmony_ci error = error == -EAGAIN ? -EBUSY : error; 3898c2ecf20Sopenharmony_ci goto out; 3908c2ecf20Sopenharmony_ci } 3918c2ecf20Sopenharmony_ci /* wait should be short, so we ignore the non-blocking flag */ 3928c2ecf20Sopenharmony_ci set_bit(ATM_VF_WAITING, &new_vcc->flags); 3938c2ecf20Sopenharmony_ci sigd_enq(new_vcc, as_accept, old_vcc, NULL, NULL); 3948c2ecf20Sopenharmony_ci for (;;) { 3958c2ecf20Sopenharmony_ci prepare_to_wait(sk_sleep(sk_atm(new_vcc)), &wait, 3968c2ecf20Sopenharmony_ci TASK_UNINTERRUPTIBLE); 3978c2ecf20Sopenharmony_ci if (!test_bit(ATM_VF_WAITING, &new_vcc->flags) || !sigd) 3988c2ecf20Sopenharmony_ci break; 3998c2ecf20Sopenharmony_ci release_sock(sk); 4008c2ecf20Sopenharmony_ci schedule(); 4018c2ecf20Sopenharmony_ci lock_sock(sk); 4028c2ecf20Sopenharmony_ci } 4038c2ecf20Sopenharmony_ci finish_wait(sk_sleep(sk_atm(new_vcc)), &wait); 4048c2ecf20Sopenharmony_ci if (!sigd) { 4058c2ecf20Sopenharmony_ci error = -EUNATCH; 4068c2ecf20Sopenharmony_ci goto out; 4078c2ecf20Sopenharmony_ci } 4088c2ecf20Sopenharmony_ci if (!sk_atm(new_vcc)->sk_err) 4098c2ecf20Sopenharmony_ci break; 4108c2ecf20Sopenharmony_ci if (sk_atm(new_vcc)->sk_err != ERESTARTSYS) { 4118c2ecf20Sopenharmony_ci error = -sk_atm(new_vcc)->sk_err; 4128c2ecf20Sopenharmony_ci goto out; 4138c2ecf20Sopenharmony_ci } 4148c2ecf20Sopenharmony_ci } 4158c2ecf20Sopenharmony_ci newsock->state = SS_CONNECTED; 4168c2ecf20Sopenharmony_ciout: 4178c2ecf20Sopenharmony_ci release_sock(sk); 4188c2ecf20Sopenharmony_ci return error; 4198c2ecf20Sopenharmony_ci} 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_cistatic int svc_getname(struct socket *sock, struct sockaddr *sockaddr, 4228c2ecf20Sopenharmony_ci int peer) 4238c2ecf20Sopenharmony_ci{ 4248c2ecf20Sopenharmony_ci struct sockaddr_atmsvc *addr; 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci addr = (struct sockaddr_atmsvc *) sockaddr; 4278c2ecf20Sopenharmony_ci memcpy(addr, peer ? &ATM_SD(sock)->remote : &ATM_SD(sock)->local, 4288c2ecf20Sopenharmony_ci sizeof(struct sockaddr_atmsvc)); 4298c2ecf20Sopenharmony_ci return sizeof(struct sockaddr_atmsvc); 4308c2ecf20Sopenharmony_ci} 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ciint svc_change_qos(struct atm_vcc *vcc, struct atm_qos *qos) 4338c2ecf20Sopenharmony_ci{ 4348c2ecf20Sopenharmony_ci struct sock *sk = sk_atm(vcc); 4358c2ecf20Sopenharmony_ci DEFINE_WAIT(wait); 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci set_bit(ATM_VF_WAITING, &vcc->flags); 4388c2ecf20Sopenharmony_ci sigd_enq2(vcc, as_modify, NULL, NULL, &vcc->local, qos, 0); 4398c2ecf20Sopenharmony_ci for (;;) { 4408c2ecf20Sopenharmony_ci prepare_to_wait(sk_sleep(sk), &wait, TASK_UNINTERRUPTIBLE); 4418c2ecf20Sopenharmony_ci if (!test_bit(ATM_VF_WAITING, &vcc->flags) || 4428c2ecf20Sopenharmony_ci test_bit(ATM_VF_RELEASED, &vcc->flags) || !sigd) { 4438c2ecf20Sopenharmony_ci break; 4448c2ecf20Sopenharmony_ci } 4458c2ecf20Sopenharmony_ci schedule(); 4468c2ecf20Sopenharmony_ci } 4478c2ecf20Sopenharmony_ci finish_wait(sk_sleep(sk), &wait); 4488c2ecf20Sopenharmony_ci if (!sigd) 4498c2ecf20Sopenharmony_ci return -EUNATCH; 4508c2ecf20Sopenharmony_ci return -sk->sk_err; 4518c2ecf20Sopenharmony_ci} 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_cistatic int svc_setsockopt(struct socket *sock, int level, int optname, 4548c2ecf20Sopenharmony_ci sockptr_t optval, unsigned int optlen) 4558c2ecf20Sopenharmony_ci{ 4568c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 4578c2ecf20Sopenharmony_ci struct atm_vcc *vcc = ATM_SD(sock); 4588c2ecf20Sopenharmony_ci int value, error = 0; 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci lock_sock(sk); 4618c2ecf20Sopenharmony_ci switch (optname) { 4628c2ecf20Sopenharmony_ci case SO_ATMSAP: 4638c2ecf20Sopenharmony_ci if (level != SOL_ATM || optlen != sizeof(struct atm_sap)) { 4648c2ecf20Sopenharmony_ci error = -EINVAL; 4658c2ecf20Sopenharmony_ci goto out; 4668c2ecf20Sopenharmony_ci } 4678c2ecf20Sopenharmony_ci if (copy_from_sockptr(&vcc->sap, optval, optlen)) { 4688c2ecf20Sopenharmony_ci error = -EFAULT; 4698c2ecf20Sopenharmony_ci goto out; 4708c2ecf20Sopenharmony_ci } 4718c2ecf20Sopenharmony_ci set_bit(ATM_VF_HASSAP, &vcc->flags); 4728c2ecf20Sopenharmony_ci break; 4738c2ecf20Sopenharmony_ci case SO_MULTIPOINT: 4748c2ecf20Sopenharmony_ci if (level != SOL_ATM || optlen != sizeof(int)) { 4758c2ecf20Sopenharmony_ci error = -EINVAL; 4768c2ecf20Sopenharmony_ci goto out; 4778c2ecf20Sopenharmony_ci } 4788c2ecf20Sopenharmony_ci if (copy_from_sockptr(&value, optval, sizeof(int))) { 4798c2ecf20Sopenharmony_ci error = -EFAULT; 4808c2ecf20Sopenharmony_ci goto out; 4818c2ecf20Sopenharmony_ci } 4828c2ecf20Sopenharmony_ci if (value == 1) 4838c2ecf20Sopenharmony_ci set_bit(ATM_VF_SESSION, &vcc->flags); 4848c2ecf20Sopenharmony_ci else if (value == 0) 4858c2ecf20Sopenharmony_ci clear_bit(ATM_VF_SESSION, &vcc->flags); 4868c2ecf20Sopenharmony_ci else 4878c2ecf20Sopenharmony_ci error = -EINVAL; 4888c2ecf20Sopenharmony_ci break; 4898c2ecf20Sopenharmony_ci default: 4908c2ecf20Sopenharmony_ci error = vcc_setsockopt(sock, level, optname, optval, optlen); 4918c2ecf20Sopenharmony_ci } 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ciout: 4948c2ecf20Sopenharmony_ci release_sock(sk); 4958c2ecf20Sopenharmony_ci return error; 4968c2ecf20Sopenharmony_ci} 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_cistatic int svc_getsockopt(struct socket *sock, int level, int optname, 4998c2ecf20Sopenharmony_ci char __user *optval, int __user *optlen) 5008c2ecf20Sopenharmony_ci{ 5018c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 5028c2ecf20Sopenharmony_ci int error = 0, len; 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci lock_sock(sk); 5058c2ecf20Sopenharmony_ci if (!__SO_LEVEL_MATCH(optname, level) || optname != SO_ATMSAP) { 5068c2ecf20Sopenharmony_ci error = vcc_getsockopt(sock, level, optname, optval, optlen); 5078c2ecf20Sopenharmony_ci goto out; 5088c2ecf20Sopenharmony_ci } 5098c2ecf20Sopenharmony_ci if (get_user(len, optlen)) { 5108c2ecf20Sopenharmony_ci error = -EFAULT; 5118c2ecf20Sopenharmony_ci goto out; 5128c2ecf20Sopenharmony_ci } 5138c2ecf20Sopenharmony_ci if (len != sizeof(struct atm_sap)) { 5148c2ecf20Sopenharmony_ci error = -EINVAL; 5158c2ecf20Sopenharmony_ci goto out; 5168c2ecf20Sopenharmony_ci } 5178c2ecf20Sopenharmony_ci if (copy_to_user(optval, &ATM_SD(sock)->sap, sizeof(struct atm_sap))) { 5188c2ecf20Sopenharmony_ci error = -EFAULT; 5198c2ecf20Sopenharmony_ci goto out; 5208c2ecf20Sopenharmony_ci } 5218c2ecf20Sopenharmony_ciout: 5228c2ecf20Sopenharmony_ci release_sock(sk); 5238c2ecf20Sopenharmony_ci return error; 5248c2ecf20Sopenharmony_ci} 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_cistatic int svc_addparty(struct socket *sock, struct sockaddr *sockaddr, 5278c2ecf20Sopenharmony_ci int sockaddr_len, int flags) 5288c2ecf20Sopenharmony_ci{ 5298c2ecf20Sopenharmony_ci DEFINE_WAIT(wait); 5308c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 5318c2ecf20Sopenharmony_ci struct atm_vcc *vcc = ATM_SD(sock); 5328c2ecf20Sopenharmony_ci int error; 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci lock_sock(sk); 5358c2ecf20Sopenharmony_ci set_bit(ATM_VF_WAITING, &vcc->flags); 5368c2ecf20Sopenharmony_ci sigd_enq(vcc, as_addparty, NULL, NULL, 5378c2ecf20Sopenharmony_ci (struct sockaddr_atmsvc *) sockaddr); 5388c2ecf20Sopenharmony_ci if (flags & O_NONBLOCK) { 5398c2ecf20Sopenharmony_ci error = -EINPROGRESS; 5408c2ecf20Sopenharmony_ci goto out; 5418c2ecf20Sopenharmony_ci } 5428c2ecf20Sopenharmony_ci pr_debug("added wait queue\n"); 5438c2ecf20Sopenharmony_ci for (;;) { 5448c2ecf20Sopenharmony_ci prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); 5458c2ecf20Sopenharmony_ci if (!test_bit(ATM_VF_WAITING, &vcc->flags) || !sigd) 5468c2ecf20Sopenharmony_ci break; 5478c2ecf20Sopenharmony_ci schedule(); 5488c2ecf20Sopenharmony_ci } 5498c2ecf20Sopenharmony_ci finish_wait(sk_sleep(sk), &wait); 5508c2ecf20Sopenharmony_ci error = -xchg(&sk->sk_err_soft, 0); 5518c2ecf20Sopenharmony_ciout: 5528c2ecf20Sopenharmony_ci release_sock(sk); 5538c2ecf20Sopenharmony_ci return error; 5548c2ecf20Sopenharmony_ci} 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_cistatic int svc_dropparty(struct socket *sock, int ep_ref) 5578c2ecf20Sopenharmony_ci{ 5588c2ecf20Sopenharmony_ci DEFINE_WAIT(wait); 5598c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 5608c2ecf20Sopenharmony_ci struct atm_vcc *vcc = ATM_SD(sock); 5618c2ecf20Sopenharmony_ci int error; 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci lock_sock(sk); 5648c2ecf20Sopenharmony_ci set_bit(ATM_VF_WAITING, &vcc->flags); 5658c2ecf20Sopenharmony_ci sigd_enq2(vcc, as_dropparty, NULL, NULL, NULL, NULL, ep_ref); 5668c2ecf20Sopenharmony_ci for (;;) { 5678c2ecf20Sopenharmony_ci prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); 5688c2ecf20Sopenharmony_ci if (!test_bit(ATM_VF_WAITING, &vcc->flags) || !sigd) 5698c2ecf20Sopenharmony_ci break; 5708c2ecf20Sopenharmony_ci schedule(); 5718c2ecf20Sopenharmony_ci } 5728c2ecf20Sopenharmony_ci finish_wait(sk_sleep(sk), &wait); 5738c2ecf20Sopenharmony_ci if (!sigd) { 5748c2ecf20Sopenharmony_ci error = -EUNATCH; 5758c2ecf20Sopenharmony_ci goto out; 5768c2ecf20Sopenharmony_ci } 5778c2ecf20Sopenharmony_ci error = -xchg(&sk->sk_err_soft, 0); 5788c2ecf20Sopenharmony_ciout: 5798c2ecf20Sopenharmony_ci release_sock(sk); 5808c2ecf20Sopenharmony_ci return error; 5818c2ecf20Sopenharmony_ci} 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_cistatic int svc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) 5848c2ecf20Sopenharmony_ci{ 5858c2ecf20Sopenharmony_ci int error, ep_ref; 5868c2ecf20Sopenharmony_ci struct sockaddr_atmsvc sa; 5878c2ecf20Sopenharmony_ci struct atm_vcc *vcc = ATM_SD(sock); 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci switch (cmd) { 5908c2ecf20Sopenharmony_ci case ATM_ADDPARTY: 5918c2ecf20Sopenharmony_ci if (!test_bit(ATM_VF_SESSION, &vcc->flags)) 5928c2ecf20Sopenharmony_ci return -EINVAL; 5938c2ecf20Sopenharmony_ci if (copy_from_user(&sa, (void __user *) arg, sizeof(sa))) 5948c2ecf20Sopenharmony_ci return -EFAULT; 5958c2ecf20Sopenharmony_ci error = svc_addparty(sock, (struct sockaddr *)&sa, sizeof(sa), 5968c2ecf20Sopenharmony_ci 0); 5978c2ecf20Sopenharmony_ci break; 5988c2ecf20Sopenharmony_ci case ATM_DROPPARTY: 5998c2ecf20Sopenharmony_ci if (!test_bit(ATM_VF_SESSION, &vcc->flags)) 6008c2ecf20Sopenharmony_ci return -EINVAL; 6018c2ecf20Sopenharmony_ci if (copy_from_user(&ep_ref, (void __user *) arg, sizeof(int))) 6028c2ecf20Sopenharmony_ci return -EFAULT; 6038c2ecf20Sopenharmony_ci error = svc_dropparty(sock, ep_ref); 6048c2ecf20Sopenharmony_ci break; 6058c2ecf20Sopenharmony_ci default: 6068c2ecf20Sopenharmony_ci error = vcc_ioctl(sock, cmd, arg); 6078c2ecf20Sopenharmony_ci } 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci return error; 6108c2ecf20Sopenharmony_ci} 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT 6138c2ecf20Sopenharmony_cistatic int svc_compat_ioctl(struct socket *sock, unsigned int cmd, 6148c2ecf20Sopenharmony_ci unsigned long arg) 6158c2ecf20Sopenharmony_ci{ 6168c2ecf20Sopenharmony_ci /* The definition of ATM_ADDPARTY uses the size of struct atm_iobuf. 6178c2ecf20Sopenharmony_ci But actually it takes a struct sockaddr_atmsvc, which doesn't need 6188c2ecf20Sopenharmony_ci compat handling. So all we have to do is fix up cmd... */ 6198c2ecf20Sopenharmony_ci if (cmd == COMPAT_ATM_ADDPARTY) 6208c2ecf20Sopenharmony_ci cmd = ATM_ADDPARTY; 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci if (cmd == ATM_ADDPARTY || cmd == ATM_DROPPARTY) 6238c2ecf20Sopenharmony_ci return svc_ioctl(sock, cmd, arg); 6248c2ecf20Sopenharmony_ci else 6258c2ecf20Sopenharmony_ci return vcc_compat_ioctl(sock, cmd, arg); 6268c2ecf20Sopenharmony_ci} 6278c2ecf20Sopenharmony_ci#endif /* CONFIG_COMPAT */ 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_cistatic const struct proto_ops svc_proto_ops = { 6308c2ecf20Sopenharmony_ci .family = PF_ATMSVC, 6318c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci .release = svc_release, 6348c2ecf20Sopenharmony_ci .bind = svc_bind, 6358c2ecf20Sopenharmony_ci .connect = svc_connect, 6368c2ecf20Sopenharmony_ci .socketpair = sock_no_socketpair, 6378c2ecf20Sopenharmony_ci .accept = svc_accept, 6388c2ecf20Sopenharmony_ci .getname = svc_getname, 6398c2ecf20Sopenharmony_ci .poll = vcc_poll, 6408c2ecf20Sopenharmony_ci .ioctl = svc_ioctl, 6418c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT 6428c2ecf20Sopenharmony_ci .compat_ioctl = svc_compat_ioctl, 6438c2ecf20Sopenharmony_ci#endif 6448c2ecf20Sopenharmony_ci .gettstamp = sock_gettstamp, 6458c2ecf20Sopenharmony_ci .listen = svc_listen, 6468c2ecf20Sopenharmony_ci .shutdown = svc_shutdown, 6478c2ecf20Sopenharmony_ci .setsockopt = svc_setsockopt, 6488c2ecf20Sopenharmony_ci .getsockopt = svc_getsockopt, 6498c2ecf20Sopenharmony_ci .sendmsg = vcc_sendmsg, 6508c2ecf20Sopenharmony_ci .recvmsg = vcc_recvmsg, 6518c2ecf20Sopenharmony_ci .mmap = sock_no_mmap, 6528c2ecf20Sopenharmony_ci .sendpage = sock_no_sendpage, 6538c2ecf20Sopenharmony_ci}; 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_cistatic int svc_create(struct net *net, struct socket *sock, int protocol, 6578c2ecf20Sopenharmony_ci int kern) 6588c2ecf20Sopenharmony_ci{ 6598c2ecf20Sopenharmony_ci int error; 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci if (!net_eq(net, &init_net)) 6628c2ecf20Sopenharmony_ci return -EAFNOSUPPORT; 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci sock->ops = &svc_proto_ops; 6658c2ecf20Sopenharmony_ci error = vcc_create(net, sock, protocol, AF_ATMSVC, kern); 6668c2ecf20Sopenharmony_ci if (error) 6678c2ecf20Sopenharmony_ci return error; 6688c2ecf20Sopenharmony_ci ATM_SD(sock)->local.sas_family = AF_ATMSVC; 6698c2ecf20Sopenharmony_ci ATM_SD(sock)->remote.sas_family = AF_ATMSVC; 6708c2ecf20Sopenharmony_ci return 0; 6718c2ecf20Sopenharmony_ci} 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_cistatic const struct net_proto_family svc_family_ops = { 6748c2ecf20Sopenharmony_ci .family = PF_ATMSVC, 6758c2ecf20Sopenharmony_ci .create = svc_create, 6768c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 6778c2ecf20Sopenharmony_ci}; 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci/* 6818c2ecf20Sopenharmony_ci * Initialize the ATM SVC protocol family 6828c2ecf20Sopenharmony_ci */ 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ciint __init atmsvc_init(void) 6858c2ecf20Sopenharmony_ci{ 6868c2ecf20Sopenharmony_ci return sock_register(&svc_family_ops); 6878c2ecf20Sopenharmony_ci} 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_civoid atmsvc_exit(void) 6908c2ecf20Sopenharmony_ci{ 6918c2ecf20Sopenharmony_ci sock_unregister(PF_ATMSVC); 6928c2ecf20Sopenharmony_ci} 693