1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* net/atm/pvc.c - ATM PVC sockets */ |
3 | |
4 | /* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */ |
5 | |
6 | |
7 | #include <linux/net.h> /* struct socket, struct proto_ops */ |
8 | #include <linux/atm.h> /* ATM stuff */ |
9 | #include <linux/atmdev.h> /* ATM devices */ |
10 | #include <linux/errno.h> /* error codes */ |
11 | #include <linux/kernel.h> /* printk */ |
12 | #include <linux/init.h> |
13 | #include <linux/skbuff.h> |
14 | #include <linux/bitops.h> |
15 | #include <linux/export.h> |
16 | #include <net/sock.h> /* for sock_no_* */ |
17 | |
18 | #include "resources.h" /* devs and vccs */ |
19 | #include "common.h" /* common for PVCs and SVCs */ |
20 | |
21 | |
22 | static int pvc_shutdown(struct socket *sock, int how) |
23 | { |
24 | return 0; |
25 | } |
26 | |
27 | static int pvc_bind(struct socket *sock, struct sockaddr *sockaddr, |
28 | int sockaddr_len) |
29 | { |
30 | struct sock *sk = sock->sk; |
31 | struct sockaddr_atmpvc *addr; |
32 | struct atm_vcc *vcc; |
33 | int error; |
34 | |
35 | if (sockaddr_len != sizeof(struct sockaddr_atmpvc)) |
36 | return -EINVAL; |
37 | addr = (struct sockaddr_atmpvc *)sockaddr; |
38 | if (addr->sap_family != AF_ATMPVC) |
39 | return -EAFNOSUPPORT; |
40 | lock_sock(sk); |
41 | vcc = ATM_SD(sock); |
42 | if (!test_bit(ATM_VF_HASQOS, &vcc->flags)) { |
43 | error = -EBADFD; |
44 | goto out; |
45 | } |
46 | if (test_bit(ATM_VF_PARTIAL, &vcc->flags)) { |
47 | if (vcc->vpi != ATM_VPI_UNSPEC) |
48 | addr->sap_addr.vpi = vcc->vpi; |
49 | if (vcc->vci != ATM_VCI_UNSPEC) |
50 | addr->sap_addr.vci = vcc->vci; |
51 | } |
52 | error = vcc_connect(sock, itf: addr->sap_addr.itf, vpi: addr->sap_addr.vpi, |
53 | vci: addr->sap_addr.vci); |
54 | out: |
55 | release_sock(sk); |
56 | return error; |
57 | } |
58 | |
59 | static int pvc_connect(struct socket *sock, struct sockaddr *sockaddr, |
60 | int sockaddr_len, int flags) |
61 | { |
62 | return pvc_bind(sock, sockaddr, sockaddr_len); |
63 | } |
64 | |
65 | static int pvc_setsockopt(struct socket *sock, int level, int optname, |
66 | sockptr_t optval, unsigned int optlen) |
67 | { |
68 | struct sock *sk = sock->sk; |
69 | int error; |
70 | |
71 | lock_sock(sk); |
72 | error = vcc_setsockopt(sock, level, optname, optval, optlen); |
73 | release_sock(sk); |
74 | return error; |
75 | } |
76 | |
77 | static int pvc_getsockopt(struct socket *sock, int level, int optname, |
78 | char __user *optval, int __user *optlen) |
79 | { |
80 | struct sock *sk = sock->sk; |
81 | int error; |
82 | |
83 | lock_sock(sk); |
84 | error = vcc_getsockopt(sock, level, optname, optval, optlen); |
85 | release_sock(sk); |
86 | return error; |
87 | } |
88 | |
89 | static int pvc_getname(struct socket *sock, struct sockaddr *sockaddr, |
90 | int peer) |
91 | { |
92 | struct sockaddr_atmpvc *addr; |
93 | struct atm_vcc *vcc = ATM_SD(sock); |
94 | |
95 | if (!vcc->dev || !test_bit(ATM_VF_ADDR, &vcc->flags)) |
96 | return -ENOTCONN; |
97 | addr = (struct sockaddr_atmpvc *)sockaddr; |
98 | memset(addr, 0, sizeof(*addr)); |
99 | addr->sap_family = AF_ATMPVC; |
100 | addr->sap_addr.itf = vcc->dev->number; |
101 | addr->sap_addr.vpi = vcc->vpi; |
102 | addr->sap_addr.vci = vcc->vci; |
103 | return sizeof(struct sockaddr_atmpvc); |
104 | } |
105 | |
106 | static const struct proto_ops pvc_proto_ops = { |
107 | .family = PF_ATMPVC, |
108 | .owner = THIS_MODULE, |
109 | |
110 | .release = vcc_release, |
111 | .bind = pvc_bind, |
112 | .connect = pvc_connect, |
113 | .socketpair = sock_no_socketpair, |
114 | .accept = sock_no_accept, |
115 | .getname = pvc_getname, |
116 | .poll = vcc_poll, |
117 | .ioctl = vcc_ioctl, |
118 | #ifdef CONFIG_COMPAT |
119 | .compat_ioctl = vcc_compat_ioctl, |
120 | #endif |
121 | .gettstamp = sock_gettstamp, |
122 | .listen = sock_no_listen, |
123 | .shutdown = pvc_shutdown, |
124 | .setsockopt = pvc_setsockopt, |
125 | .getsockopt = pvc_getsockopt, |
126 | .sendmsg = vcc_sendmsg, |
127 | .recvmsg = vcc_recvmsg, |
128 | .mmap = sock_no_mmap, |
129 | }; |
130 | |
131 | |
132 | static int pvc_create(struct net *net, struct socket *sock, int protocol, |
133 | int kern) |
134 | { |
135 | if (net != &init_net) |
136 | return -EAFNOSUPPORT; |
137 | |
138 | sock->ops = &pvc_proto_ops; |
139 | return vcc_create(net, sock, protocol, PF_ATMPVC, kern); |
140 | } |
141 | |
142 | static const struct net_proto_family pvc_family_ops = { |
143 | .family = PF_ATMPVC, |
144 | .create = pvc_create, |
145 | .owner = THIS_MODULE, |
146 | }; |
147 | |
148 | |
149 | /* |
150 | * Initialize the ATM PVC protocol family |
151 | */ |
152 | |
153 | |
154 | int __init atmpvc_init(void) |
155 | { |
156 | return sock_register(fam: &pvc_family_ops); |
157 | } |
158 | |
159 | void atmpvc_exit(void) |
160 | { |
161 | sock_unregister(PF_ATMPVC); |
162 | } |
163 | |