162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* net/atm/pvc.c - ATM PVC sockets */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/net.h> /* struct socket, struct proto_ops */ 862306a36Sopenharmony_ci#include <linux/atm.h> /* ATM stuff */ 962306a36Sopenharmony_ci#include <linux/atmdev.h> /* ATM devices */ 1062306a36Sopenharmony_ci#include <linux/errno.h> /* error codes */ 1162306a36Sopenharmony_ci#include <linux/kernel.h> /* printk */ 1262306a36Sopenharmony_ci#include <linux/init.h> 1362306a36Sopenharmony_ci#include <linux/skbuff.h> 1462306a36Sopenharmony_ci#include <linux/bitops.h> 1562306a36Sopenharmony_ci#include <linux/export.h> 1662306a36Sopenharmony_ci#include <net/sock.h> /* for sock_no_* */ 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#include "resources.h" /* devs and vccs */ 1962306a36Sopenharmony_ci#include "common.h" /* common for PVCs and SVCs */ 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_cistatic int pvc_shutdown(struct socket *sock, int how) 2362306a36Sopenharmony_ci{ 2462306a36Sopenharmony_ci return 0; 2562306a36Sopenharmony_ci} 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cistatic int pvc_bind(struct socket *sock, struct sockaddr *sockaddr, 2862306a36Sopenharmony_ci int sockaddr_len) 2962306a36Sopenharmony_ci{ 3062306a36Sopenharmony_ci struct sock *sk = sock->sk; 3162306a36Sopenharmony_ci struct sockaddr_atmpvc *addr; 3262306a36Sopenharmony_ci struct atm_vcc *vcc; 3362306a36Sopenharmony_ci int error; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci if (sockaddr_len != sizeof(struct sockaddr_atmpvc)) 3662306a36Sopenharmony_ci return -EINVAL; 3762306a36Sopenharmony_ci addr = (struct sockaddr_atmpvc *)sockaddr; 3862306a36Sopenharmony_ci if (addr->sap_family != AF_ATMPVC) 3962306a36Sopenharmony_ci return -EAFNOSUPPORT; 4062306a36Sopenharmony_ci lock_sock(sk); 4162306a36Sopenharmony_ci vcc = ATM_SD(sock); 4262306a36Sopenharmony_ci if (!test_bit(ATM_VF_HASQOS, &vcc->flags)) { 4362306a36Sopenharmony_ci error = -EBADFD; 4462306a36Sopenharmony_ci goto out; 4562306a36Sopenharmony_ci } 4662306a36Sopenharmony_ci if (test_bit(ATM_VF_PARTIAL, &vcc->flags)) { 4762306a36Sopenharmony_ci if (vcc->vpi != ATM_VPI_UNSPEC) 4862306a36Sopenharmony_ci addr->sap_addr.vpi = vcc->vpi; 4962306a36Sopenharmony_ci if (vcc->vci != ATM_VCI_UNSPEC) 5062306a36Sopenharmony_ci addr->sap_addr.vci = vcc->vci; 5162306a36Sopenharmony_ci } 5262306a36Sopenharmony_ci error = vcc_connect(sock, addr->sap_addr.itf, addr->sap_addr.vpi, 5362306a36Sopenharmony_ci addr->sap_addr.vci); 5462306a36Sopenharmony_ciout: 5562306a36Sopenharmony_ci release_sock(sk); 5662306a36Sopenharmony_ci return error; 5762306a36Sopenharmony_ci} 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_cistatic int pvc_connect(struct socket *sock, struct sockaddr *sockaddr, 6062306a36Sopenharmony_ci int sockaddr_len, int flags) 6162306a36Sopenharmony_ci{ 6262306a36Sopenharmony_ci return pvc_bind(sock, sockaddr, sockaddr_len); 6362306a36Sopenharmony_ci} 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_cistatic int pvc_setsockopt(struct socket *sock, int level, int optname, 6662306a36Sopenharmony_ci sockptr_t optval, unsigned int optlen) 6762306a36Sopenharmony_ci{ 6862306a36Sopenharmony_ci struct sock *sk = sock->sk; 6962306a36Sopenharmony_ci int error; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci lock_sock(sk); 7262306a36Sopenharmony_ci error = vcc_setsockopt(sock, level, optname, optval, optlen); 7362306a36Sopenharmony_ci release_sock(sk); 7462306a36Sopenharmony_ci return error; 7562306a36Sopenharmony_ci} 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_cistatic int pvc_getsockopt(struct socket *sock, int level, int optname, 7862306a36Sopenharmony_ci char __user *optval, int __user *optlen) 7962306a36Sopenharmony_ci{ 8062306a36Sopenharmony_ci struct sock *sk = sock->sk; 8162306a36Sopenharmony_ci int error; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci lock_sock(sk); 8462306a36Sopenharmony_ci error = vcc_getsockopt(sock, level, optname, optval, optlen); 8562306a36Sopenharmony_ci release_sock(sk); 8662306a36Sopenharmony_ci return error; 8762306a36Sopenharmony_ci} 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_cistatic int pvc_getname(struct socket *sock, struct sockaddr *sockaddr, 9062306a36Sopenharmony_ci int peer) 9162306a36Sopenharmony_ci{ 9262306a36Sopenharmony_ci struct sockaddr_atmpvc *addr; 9362306a36Sopenharmony_ci struct atm_vcc *vcc = ATM_SD(sock); 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci if (!vcc->dev || !test_bit(ATM_VF_ADDR, &vcc->flags)) 9662306a36Sopenharmony_ci return -ENOTCONN; 9762306a36Sopenharmony_ci addr = (struct sockaddr_atmpvc *)sockaddr; 9862306a36Sopenharmony_ci memset(addr, 0, sizeof(*addr)); 9962306a36Sopenharmony_ci addr->sap_family = AF_ATMPVC; 10062306a36Sopenharmony_ci addr->sap_addr.itf = vcc->dev->number; 10162306a36Sopenharmony_ci addr->sap_addr.vpi = vcc->vpi; 10262306a36Sopenharmony_ci addr->sap_addr.vci = vcc->vci; 10362306a36Sopenharmony_ci return sizeof(struct sockaddr_atmpvc); 10462306a36Sopenharmony_ci} 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_cistatic const struct proto_ops pvc_proto_ops = { 10762306a36Sopenharmony_ci .family = PF_ATMPVC, 10862306a36Sopenharmony_ci .owner = THIS_MODULE, 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci .release = vcc_release, 11162306a36Sopenharmony_ci .bind = pvc_bind, 11262306a36Sopenharmony_ci .connect = pvc_connect, 11362306a36Sopenharmony_ci .socketpair = sock_no_socketpair, 11462306a36Sopenharmony_ci .accept = sock_no_accept, 11562306a36Sopenharmony_ci .getname = pvc_getname, 11662306a36Sopenharmony_ci .poll = vcc_poll, 11762306a36Sopenharmony_ci .ioctl = vcc_ioctl, 11862306a36Sopenharmony_ci#ifdef CONFIG_COMPAT 11962306a36Sopenharmony_ci .compat_ioctl = vcc_compat_ioctl, 12062306a36Sopenharmony_ci#endif 12162306a36Sopenharmony_ci .gettstamp = sock_gettstamp, 12262306a36Sopenharmony_ci .listen = sock_no_listen, 12362306a36Sopenharmony_ci .shutdown = pvc_shutdown, 12462306a36Sopenharmony_ci .setsockopt = pvc_setsockopt, 12562306a36Sopenharmony_ci .getsockopt = pvc_getsockopt, 12662306a36Sopenharmony_ci .sendmsg = vcc_sendmsg, 12762306a36Sopenharmony_ci .recvmsg = vcc_recvmsg, 12862306a36Sopenharmony_ci .mmap = sock_no_mmap, 12962306a36Sopenharmony_ci}; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_cistatic int pvc_create(struct net *net, struct socket *sock, int protocol, 13362306a36Sopenharmony_ci int kern) 13462306a36Sopenharmony_ci{ 13562306a36Sopenharmony_ci if (net != &init_net) 13662306a36Sopenharmony_ci return -EAFNOSUPPORT; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci sock->ops = &pvc_proto_ops; 13962306a36Sopenharmony_ci return vcc_create(net, sock, protocol, PF_ATMPVC, kern); 14062306a36Sopenharmony_ci} 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_cistatic const struct net_proto_family pvc_family_ops = { 14362306a36Sopenharmony_ci .family = PF_ATMPVC, 14462306a36Sopenharmony_ci .create = pvc_create, 14562306a36Sopenharmony_ci .owner = THIS_MODULE, 14662306a36Sopenharmony_ci}; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci/* 15062306a36Sopenharmony_ci * Initialize the ATM PVC protocol family 15162306a36Sopenharmony_ci */ 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ciint __init atmpvc_init(void) 15562306a36Sopenharmony_ci{ 15662306a36Sopenharmony_ci return sock_register(&pvc_family_ops); 15762306a36Sopenharmony_ci} 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_civoid atmpvc_exit(void) 16062306a36Sopenharmony_ci{ 16162306a36Sopenharmony_ci sock_unregister(PF_ATMPVC); 16262306a36Sopenharmony_ci} 163