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