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