xref: /openbmc/linux/net/atm/common.c (revision 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2)
1*1da177e4SLinus Torvalds /* net/atm/common.c - ATM sockets (common part for PVC and SVC) */
2*1da177e4SLinus Torvalds 
3*1da177e4SLinus Torvalds /* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
4*1da177e4SLinus Torvalds 
5*1da177e4SLinus Torvalds 
6*1da177e4SLinus Torvalds #include <linux/config.h>
7*1da177e4SLinus Torvalds #include <linux/module.h>
8*1da177e4SLinus Torvalds #include <linux/kmod.h>
9*1da177e4SLinus Torvalds #include <linux/net.h>		/* struct socket, struct proto_ops */
10*1da177e4SLinus Torvalds #include <linux/atm.h>		/* ATM stuff */
11*1da177e4SLinus Torvalds #include <linux/atmdev.h>
12*1da177e4SLinus Torvalds #include <linux/socket.h>	/* SOL_SOCKET */
13*1da177e4SLinus Torvalds #include <linux/errno.h>	/* error codes */
14*1da177e4SLinus Torvalds #include <linux/capability.h>
15*1da177e4SLinus Torvalds #include <linux/mm.h>		/* verify_area */
16*1da177e4SLinus Torvalds #include <linux/sched.h>
17*1da177e4SLinus Torvalds #include <linux/time.h>		/* struct timeval */
18*1da177e4SLinus Torvalds #include <linux/skbuff.h>
19*1da177e4SLinus Torvalds #include <linux/bitops.h>
20*1da177e4SLinus Torvalds #include <linux/init.h>
21*1da177e4SLinus Torvalds #include <net/sock.h>		/* struct sock */
22*1da177e4SLinus Torvalds 
23*1da177e4SLinus Torvalds #include <asm/uaccess.h>
24*1da177e4SLinus Torvalds #include <asm/atomic.h>
25*1da177e4SLinus Torvalds #include <asm/poll.h>
26*1da177e4SLinus Torvalds 
27*1da177e4SLinus Torvalds 
28*1da177e4SLinus Torvalds #include "resources.h"		/* atm_find_dev */
29*1da177e4SLinus Torvalds #include "common.h"		/* prototypes */
30*1da177e4SLinus Torvalds #include "protocols.h"		/* atm_init_<transport> */
31*1da177e4SLinus Torvalds #include "addr.h"		/* address registry */
32*1da177e4SLinus Torvalds #include "signaling.h"		/* for WAITING and sigd_attach */
33*1da177e4SLinus Torvalds 
34*1da177e4SLinus Torvalds 
35*1da177e4SLinus Torvalds #if 0
36*1da177e4SLinus Torvalds #define DPRINTK(format,args...) printk(KERN_DEBUG format,##args)
37*1da177e4SLinus Torvalds #else
38*1da177e4SLinus Torvalds #define DPRINTK(format,args...)
39*1da177e4SLinus Torvalds #endif
40*1da177e4SLinus Torvalds 
41*1da177e4SLinus Torvalds struct hlist_head vcc_hash[VCC_HTABLE_SIZE];
42*1da177e4SLinus Torvalds DEFINE_RWLOCK(vcc_sklist_lock);
43*1da177e4SLinus Torvalds 
44*1da177e4SLinus Torvalds static void __vcc_insert_socket(struct sock *sk)
45*1da177e4SLinus Torvalds {
46*1da177e4SLinus Torvalds 	struct atm_vcc *vcc = atm_sk(sk);
47*1da177e4SLinus Torvalds 	struct hlist_head *head = &vcc_hash[vcc->vci &
48*1da177e4SLinus Torvalds 					(VCC_HTABLE_SIZE - 1)];
49*1da177e4SLinus Torvalds 	sk->sk_hashent = vcc->vci & (VCC_HTABLE_SIZE - 1);
50*1da177e4SLinus Torvalds 	sk_add_node(sk, head);
51*1da177e4SLinus Torvalds }
52*1da177e4SLinus Torvalds 
53*1da177e4SLinus Torvalds void vcc_insert_socket(struct sock *sk)
54*1da177e4SLinus Torvalds {
55*1da177e4SLinus Torvalds 	write_lock_irq(&vcc_sklist_lock);
56*1da177e4SLinus Torvalds 	__vcc_insert_socket(sk);
57*1da177e4SLinus Torvalds 	write_unlock_irq(&vcc_sklist_lock);
58*1da177e4SLinus Torvalds }
59*1da177e4SLinus Torvalds 
60*1da177e4SLinus Torvalds static void vcc_remove_socket(struct sock *sk)
61*1da177e4SLinus Torvalds {
62*1da177e4SLinus Torvalds 	write_lock_irq(&vcc_sklist_lock);
63*1da177e4SLinus Torvalds 	sk_del_node_init(sk);
64*1da177e4SLinus Torvalds 	write_unlock_irq(&vcc_sklist_lock);
65*1da177e4SLinus Torvalds }
66*1da177e4SLinus Torvalds 
67*1da177e4SLinus Torvalds 
68*1da177e4SLinus Torvalds static struct sk_buff *alloc_tx(struct atm_vcc *vcc,unsigned int size)
69*1da177e4SLinus Torvalds {
70*1da177e4SLinus Torvalds 	struct sk_buff *skb;
71*1da177e4SLinus Torvalds 	struct sock *sk = sk_atm(vcc);
72*1da177e4SLinus Torvalds 
73*1da177e4SLinus Torvalds 	if (atomic_read(&sk->sk_wmem_alloc) && !atm_may_send(vcc, size)) {
74*1da177e4SLinus Torvalds 		DPRINTK("Sorry: wmem_alloc = %d, size = %d, sndbuf = %d\n",
75*1da177e4SLinus Torvalds 			atomic_read(&sk->sk_wmem_alloc), size,
76*1da177e4SLinus Torvalds 			sk->sk_sndbuf);
77*1da177e4SLinus Torvalds 		return NULL;
78*1da177e4SLinus Torvalds 	}
79*1da177e4SLinus Torvalds 	while (!(skb = alloc_skb(size,GFP_KERNEL))) schedule();
80*1da177e4SLinus Torvalds 	DPRINTK("AlTx %d += %d\n", atomic_read(&sk->sk_wmem_alloc),
81*1da177e4SLinus Torvalds 		skb->truesize);
82*1da177e4SLinus Torvalds 	atomic_add(skb->truesize, &sk->sk_wmem_alloc);
83*1da177e4SLinus Torvalds 	return skb;
84*1da177e4SLinus Torvalds }
85*1da177e4SLinus Torvalds 
86*1da177e4SLinus Torvalds 
87*1da177e4SLinus Torvalds EXPORT_SYMBOL(vcc_hash);
88*1da177e4SLinus Torvalds EXPORT_SYMBOL(vcc_sklist_lock);
89*1da177e4SLinus Torvalds EXPORT_SYMBOL(vcc_insert_socket);
90*1da177e4SLinus Torvalds 
91*1da177e4SLinus Torvalds static void vcc_sock_destruct(struct sock *sk)
92*1da177e4SLinus Torvalds {
93*1da177e4SLinus Torvalds 	if (atomic_read(&sk->sk_rmem_alloc))
94*1da177e4SLinus Torvalds 		printk(KERN_DEBUG "vcc_sock_destruct: rmem leakage (%d bytes) detected.\n", atomic_read(&sk->sk_rmem_alloc));
95*1da177e4SLinus Torvalds 
96*1da177e4SLinus Torvalds 	if (atomic_read(&sk->sk_wmem_alloc))
97*1da177e4SLinus Torvalds 		printk(KERN_DEBUG "vcc_sock_destruct: wmem leakage (%d bytes) detected.\n", atomic_read(&sk->sk_wmem_alloc));
98*1da177e4SLinus Torvalds }
99*1da177e4SLinus Torvalds 
100*1da177e4SLinus Torvalds static void vcc_def_wakeup(struct sock *sk)
101*1da177e4SLinus Torvalds {
102*1da177e4SLinus Torvalds 	read_lock(&sk->sk_callback_lock);
103*1da177e4SLinus Torvalds 	if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
104*1da177e4SLinus Torvalds 		wake_up(sk->sk_sleep);
105*1da177e4SLinus Torvalds 	read_unlock(&sk->sk_callback_lock);
106*1da177e4SLinus Torvalds }
107*1da177e4SLinus Torvalds 
108*1da177e4SLinus Torvalds static inline int vcc_writable(struct sock *sk)
109*1da177e4SLinus Torvalds {
110*1da177e4SLinus Torvalds 	struct atm_vcc *vcc = atm_sk(sk);
111*1da177e4SLinus Torvalds 
112*1da177e4SLinus Torvalds 	return (vcc->qos.txtp.max_sdu +
113*1da177e4SLinus Torvalds 	        atomic_read(&sk->sk_wmem_alloc)) <= sk->sk_sndbuf;
114*1da177e4SLinus Torvalds }
115*1da177e4SLinus Torvalds 
116*1da177e4SLinus Torvalds static void vcc_write_space(struct sock *sk)
117*1da177e4SLinus Torvalds {
118*1da177e4SLinus Torvalds 	read_lock(&sk->sk_callback_lock);
119*1da177e4SLinus Torvalds 
120*1da177e4SLinus Torvalds 	if (vcc_writable(sk)) {
121*1da177e4SLinus Torvalds 		if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
122*1da177e4SLinus Torvalds 			wake_up_interruptible(sk->sk_sleep);
123*1da177e4SLinus Torvalds 
124*1da177e4SLinus Torvalds 		sk_wake_async(sk, 2, POLL_OUT);
125*1da177e4SLinus Torvalds 	}
126*1da177e4SLinus Torvalds 
127*1da177e4SLinus Torvalds 	read_unlock(&sk->sk_callback_lock);
128*1da177e4SLinus Torvalds }
129*1da177e4SLinus Torvalds 
130*1da177e4SLinus Torvalds static struct proto vcc_proto = {
131*1da177e4SLinus Torvalds 	.name	  = "VCC",
132*1da177e4SLinus Torvalds 	.owner	  = THIS_MODULE,
133*1da177e4SLinus Torvalds 	.obj_size = sizeof(struct atm_vcc),
134*1da177e4SLinus Torvalds };
135*1da177e4SLinus Torvalds 
136*1da177e4SLinus Torvalds int vcc_create(struct socket *sock, int protocol, int family)
137*1da177e4SLinus Torvalds {
138*1da177e4SLinus Torvalds 	struct sock *sk;
139*1da177e4SLinus Torvalds 	struct atm_vcc *vcc;
140*1da177e4SLinus Torvalds 
141*1da177e4SLinus Torvalds 	sock->sk = NULL;
142*1da177e4SLinus Torvalds 	if (sock->type == SOCK_STREAM)
143*1da177e4SLinus Torvalds 		return -EINVAL;
144*1da177e4SLinus Torvalds 	sk = sk_alloc(family, GFP_KERNEL, &vcc_proto, 1);
145*1da177e4SLinus Torvalds 	if (!sk)
146*1da177e4SLinus Torvalds 		return -ENOMEM;
147*1da177e4SLinus Torvalds 	sock_init_data(sock, sk);
148*1da177e4SLinus Torvalds 	sk->sk_state_change = vcc_def_wakeup;
149*1da177e4SLinus Torvalds 	sk->sk_write_space = vcc_write_space;
150*1da177e4SLinus Torvalds 
151*1da177e4SLinus Torvalds 	vcc = atm_sk(sk);
152*1da177e4SLinus Torvalds 	vcc->dev = NULL;
153*1da177e4SLinus Torvalds 	memset(&vcc->local,0,sizeof(struct sockaddr_atmsvc));
154*1da177e4SLinus Torvalds 	memset(&vcc->remote,0,sizeof(struct sockaddr_atmsvc));
155*1da177e4SLinus Torvalds 	vcc->qos.txtp.max_sdu = 1 << 16; /* for meta VCs */
156*1da177e4SLinus Torvalds 	atomic_set(&sk->sk_wmem_alloc, 0);
157*1da177e4SLinus Torvalds 	atomic_set(&sk->sk_rmem_alloc, 0);
158*1da177e4SLinus Torvalds 	vcc->push = NULL;
159*1da177e4SLinus Torvalds 	vcc->pop = NULL;
160*1da177e4SLinus Torvalds 	vcc->push_oam = NULL;
161*1da177e4SLinus Torvalds 	vcc->vpi = vcc->vci = 0; /* no VCI/VPI yet */
162*1da177e4SLinus Torvalds 	vcc->atm_options = vcc->aal_options = 0;
163*1da177e4SLinus Torvalds 	sk->sk_destruct = vcc_sock_destruct;
164*1da177e4SLinus Torvalds 	return 0;
165*1da177e4SLinus Torvalds }
166*1da177e4SLinus Torvalds 
167*1da177e4SLinus Torvalds 
168*1da177e4SLinus Torvalds static void vcc_destroy_socket(struct sock *sk)
169*1da177e4SLinus Torvalds {
170*1da177e4SLinus Torvalds 	struct atm_vcc *vcc = atm_sk(sk);
171*1da177e4SLinus Torvalds 	struct sk_buff *skb;
172*1da177e4SLinus Torvalds 
173*1da177e4SLinus Torvalds 	set_bit(ATM_VF_CLOSE, &vcc->flags);
174*1da177e4SLinus Torvalds 	clear_bit(ATM_VF_READY, &vcc->flags);
175*1da177e4SLinus Torvalds 	if (vcc->dev) {
176*1da177e4SLinus Torvalds 		if (vcc->dev->ops->close)
177*1da177e4SLinus Torvalds 			vcc->dev->ops->close(vcc);
178*1da177e4SLinus Torvalds 		if (vcc->push)
179*1da177e4SLinus Torvalds 			vcc->push(vcc, NULL); /* atmarpd has no push */
180*1da177e4SLinus Torvalds 
181*1da177e4SLinus Torvalds 		vcc_remove_socket(sk);	/* no more receive */
182*1da177e4SLinus Torvalds 
183*1da177e4SLinus Torvalds 		while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) {
184*1da177e4SLinus Torvalds 			atm_return(vcc,skb->truesize);
185*1da177e4SLinus Torvalds 			kfree_skb(skb);
186*1da177e4SLinus Torvalds 		}
187*1da177e4SLinus Torvalds 
188*1da177e4SLinus Torvalds 		module_put(vcc->dev->ops->owner);
189*1da177e4SLinus Torvalds 		atm_dev_put(vcc->dev);
190*1da177e4SLinus Torvalds 	}
191*1da177e4SLinus Torvalds }
192*1da177e4SLinus Torvalds 
193*1da177e4SLinus Torvalds 
194*1da177e4SLinus Torvalds int vcc_release(struct socket *sock)
195*1da177e4SLinus Torvalds {
196*1da177e4SLinus Torvalds 	struct sock *sk = sock->sk;
197*1da177e4SLinus Torvalds 
198*1da177e4SLinus Torvalds 	if (sk) {
199*1da177e4SLinus Torvalds 		lock_sock(sk);
200*1da177e4SLinus Torvalds 		vcc_destroy_socket(sock->sk);
201*1da177e4SLinus Torvalds 		release_sock(sk);
202*1da177e4SLinus Torvalds 		sock_put(sk);
203*1da177e4SLinus Torvalds 	}
204*1da177e4SLinus Torvalds 
205*1da177e4SLinus Torvalds 	return 0;
206*1da177e4SLinus Torvalds }
207*1da177e4SLinus Torvalds 
208*1da177e4SLinus Torvalds 
209*1da177e4SLinus Torvalds void vcc_release_async(struct atm_vcc *vcc, int reply)
210*1da177e4SLinus Torvalds {
211*1da177e4SLinus Torvalds 	struct sock *sk = sk_atm(vcc);
212*1da177e4SLinus Torvalds 
213*1da177e4SLinus Torvalds 	set_bit(ATM_VF_CLOSE, &vcc->flags);
214*1da177e4SLinus Torvalds 	sk->sk_shutdown |= RCV_SHUTDOWN;
215*1da177e4SLinus Torvalds 	sk->sk_err = -reply;
216*1da177e4SLinus Torvalds 	clear_bit(ATM_VF_WAITING, &vcc->flags);
217*1da177e4SLinus Torvalds 	sk->sk_state_change(sk);
218*1da177e4SLinus Torvalds }
219*1da177e4SLinus Torvalds 
220*1da177e4SLinus Torvalds 
221*1da177e4SLinus Torvalds EXPORT_SYMBOL(vcc_release_async);
222*1da177e4SLinus Torvalds 
223*1da177e4SLinus Torvalds 
224*1da177e4SLinus Torvalds static int adjust_tp(struct atm_trafprm *tp,unsigned char aal)
225*1da177e4SLinus Torvalds {
226*1da177e4SLinus Torvalds 	int max_sdu;
227*1da177e4SLinus Torvalds 
228*1da177e4SLinus Torvalds 	if (!tp->traffic_class) return 0;
229*1da177e4SLinus Torvalds 	switch (aal) {
230*1da177e4SLinus Torvalds 		case ATM_AAL0:
231*1da177e4SLinus Torvalds 			max_sdu = ATM_CELL_SIZE-1;
232*1da177e4SLinus Torvalds 			break;
233*1da177e4SLinus Torvalds 		case ATM_AAL34:
234*1da177e4SLinus Torvalds 			max_sdu = ATM_MAX_AAL34_PDU;
235*1da177e4SLinus Torvalds 			break;
236*1da177e4SLinus Torvalds 		default:
237*1da177e4SLinus Torvalds 			printk(KERN_WARNING "ATM: AAL problems ... "
238*1da177e4SLinus Torvalds 			    "(%d)\n",aal);
239*1da177e4SLinus Torvalds 			/* fall through */
240*1da177e4SLinus Torvalds 		case ATM_AAL5:
241*1da177e4SLinus Torvalds 			max_sdu = ATM_MAX_AAL5_PDU;
242*1da177e4SLinus Torvalds 	}
243*1da177e4SLinus Torvalds 	if (!tp->max_sdu) tp->max_sdu = max_sdu;
244*1da177e4SLinus Torvalds 	else if (tp->max_sdu > max_sdu) return -EINVAL;
245*1da177e4SLinus Torvalds 	if (!tp->max_cdv) tp->max_cdv = ATM_MAX_CDV;
246*1da177e4SLinus Torvalds 	return 0;
247*1da177e4SLinus Torvalds }
248*1da177e4SLinus Torvalds 
249*1da177e4SLinus Torvalds 
250*1da177e4SLinus Torvalds static int check_ci(struct atm_vcc *vcc, short vpi, int vci)
251*1da177e4SLinus Torvalds {
252*1da177e4SLinus Torvalds 	struct hlist_head *head = &vcc_hash[vci &
253*1da177e4SLinus Torvalds 					(VCC_HTABLE_SIZE - 1)];
254*1da177e4SLinus Torvalds 	struct hlist_node *node;
255*1da177e4SLinus Torvalds 	struct sock *s;
256*1da177e4SLinus Torvalds 	struct atm_vcc *walk;
257*1da177e4SLinus Torvalds 
258*1da177e4SLinus Torvalds 	sk_for_each(s, node, head) {
259*1da177e4SLinus Torvalds 		walk = atm_sk(s);
260*1da177e4SLinus Torvalds 		if (walk->dev != vcc->dev)
261*1da177e4SLinus Torvalds 			continue;
262*1da177e4SLinus Torvalds 		if (test_bit(ATM_VF_ADDR, &walk->flags) && walk->vpi == vpi &&
263*1da177e4SLinus Torvalds 		    walk->vci == vci && ((walk->qos.txtp.traffic_class !=
264*1da177e4SLinus Torvalds 		    ATM_NONE && vcc->qos.txtp.traffic_class != ATM_NONE) ||
265*1da177e4SLinus Torvalds 		    (walk->qos.rxtp.traffic_class != ATM_NONE &&
266*1da177e4SLinus Torvalds 		    vcc->qos.rxtp.traffic_class != ATM_NONE)))
267*1da177e4SLinus Torvalds 			return -EADDRINUSE;
268*1da177e4SLinus Torvalds 	}
269*1da177e4SLinus Torvalds 
270*1da177e4SLinus Torvalds 	/* allow VCCs with same VPI/VCI iff they don't collide on
271*1da177e4SLinus Torvalds 	   TX/RX (but we may refuse such sharing for other reasons,
272*1da177e4SLinus Torvalds 	   e.g. if protocol requires to have both channels) */
273*1da177e4SLinus Torvalds 
274*1da177e4SLinus Torvalds 	return 0;
275*1da177e4SLinus Torvalds }
276*1da177e4SLinus Torvalds 
277*1da177e4SLinus Torvalds 
278*1da177e4SLinus Torvalds static int find_ci(struct atm_vcc *vcc, short *vpi, int *vci)
279*1da177e4SLinus Torvalds {
280*1da177e4SLinus Torvalds 	static short p;        /* poor man's per-device cache */
281*1da177e4SLinus Torvalds 	static int c;
282*1da177e4SLinus Torvalds 	short old_p;
283*1da177e4SLinus Torvalds 	int old_c;
284*1da177e4SLinus Torvalds 	int err;
285*1da177e4SLinus Torvalds 
286*1da177e4SLinus Torvalds 	if (*vpi != ATM_VPI_ANY && *vci != ATM_VCI_ANY) {
287*1da177e4SLinus Torvalds 		err = check_ci(vcc, *vpi, *vci);
288*1da177e4SLinus Torvalds 		return err;
289*1da177e4SLinus Torvalds 	}
290*1da177e4SLinus Torvalds 	/* last scan may have left values out of bounds for current device */
291*1da177e4SLinus Torvalds 	if (*vpi != ATM_VPI_ANY)
292*1da177e4SLinus Torvalds 		p = *vpi;
293*1da177e4SLinus Torvalds 	else if (p >= 1 << vcc->dev->ci_range.vpi_bits)
294*1da177e4SLinus Torvalds 		p = 0;
295*1da177e4SLinus Torvalds 	if (*vci != ATM_VCI_ANY)
296*1da177e4SLinus Torvalds 		c = *vci;
297*1da177e4SLinus Torvalds 	else if (c < ATM_NOT_RSV_VCI || c >= 1 << vcc->dev->ci_range.vci_bits)
298*1da177e4SLinus Torvalds 			c = ATM_NOT_RSV_VCI;
299*1da177e4SLinus Torvalds 	old_p = p;
300*1da177e4SLinus Torvalds 	old_c = c;
301*1da177e4SLinus Torvalds 	do {
302*1da177e4SLinus Torvalds 		if (!check_ci(vcc, p, c)) {
303*1da177e4SLinus Torvalds 			*vpi = p;
304*1da177e4SLinus Torvalds 			*vci = c;
305*1da177e4SLinus Torvalds 			return 0;
306*1da177e4SLinus Torvalds 		}
307*1da177e4SLinus Torvalds 		if (*vci == ATM_VCI_ANY) {
308*1da177e4SLinus Torvalds 			c++;
309*1da177e4SLinus Torvalds 			if (c >= 1 << vcc->dev->ci_range.vci_bits)
310*1da177e4SLinus Torvalds 				c = ATM_NOT_RSV_VCI;
311*1da177e4SLinus Torvalds 		}
312*1da177e4SLinus Torvalds 		if ((c == ATM_NOT_RSV_VCI || *vci != ATM_VCI_ANY) &&
313*1da177e4SLinus Torvalds 		    *vpi == ATM_VPI_ANY) {
314*1da177e4SLinus Torvalds 			p++;
315*1da177e4SLinus Torvalds 			if (p >= 1 << vcc->dev->ci_range.vpi_bits) p = 0;
316*1da177e4SLinus Torvalds 		}
317*1da177e4SLinus Torvalds 	}
318*1da177e4SLinus Torvalds 	while (old_p != p || old_c != c);
319*1da177e4SLinus Torvalds 	return -EADDRINUSE;
320*1da177e4SLinus Torvalds }
321*1da177e4SLinus Torvalds 
322*1da177e4SLinus Torvalds 
323*1da177e4SLinus Torvalds static int __vcc_connect(struct atm_vcc *vcc, struct atm_dev *dev, short vpi,
324*1da177e4SLinus Torvalds 			 int vci)
325*1da177e4SLinus Torvalds {
326*1da177e4SLinus Torvalds 	struct sock *sk = sk_atm(vcc);
327*1da177e4SLinus Torvalds 	int error;
328*1da177e4SLinus Torvalds 
329*1da177e4SLinus Torvalds 	if ((vpi != ATM_VPI_UNSPEC && vpi != ATM_VPI_ANY &&
330*1da177e4SLinus Torvalds 	    vpi >> dev->ci_range.vpi_bits) || (vci != ATM_VCI_UNSPEC &&
331*1da177e4SLinus Torvalds 	    vci != ATM_VCI_ANY && vci >> dev->ci_range.vci_bits))
332*1da177e4SLinus Torvalds 		return -EINVAL;
333*1da177e4SLinus Torvalds 	if (vci > 0 && vci < ATM_NOT_RSV_VCI && !capable(CAP_NET_BIND_SERVICE))
334*1da177e4SLinus Torvalds 		return -EPERM;
335*1da177e4SLinus Torvalds 	error = 0;
336*1da177e4SLinus Torvalds 	if (!try_module_get(dev->ops->owner))
337*1da177e4SLinus Torvalds 		return -ENODEV;
338*1da177e4SLinus Torvalds 	vcc->dev = dev;
339*1da177e4SLinus Torvalds 	write_lock_irq(&vcc_sklist_lock);
340*1da177e4SLinus Torvalds 	if ((error = find_ci(vcc, &vpi, &vci))) {
341*1da177e4SLinus Torvalds 		write_unlock_irq(&vcc_sklist_lock);
342*1da177e4SLinus Torvalds 		goto fail_module_put;
343*1da177e4SLinus Torvalds 	}
344*1da177e4SLinus Torvalds 	vcc->vpi = vpi;
345*1da177e4SLinus Torvalds 	vcc->vci = vci;
346*1da177e4SLinus Torvalds 	__vcc_insert_socket(sk);
347*1da177e4SLinus Torvalds 	write_unlock_irq(&vcc_sklist_lock);
348*1da177e4SLinus Torvalds 	switch (vcc->qos.aal) {
349*1da177e4SLinus Torvalds 		case ATM_AAL0:
350*1da177e4SLinus Torvalds 			error = atm_init_aal0(vcc);
351*1da177e4SLinus Torvalds 			vcc->stats = &dev->stats.aal0;
352*1da177e4SLinus Torvalds 			break;
353*1da177e4SLinus Torvalds 		case ATM_AAL34:
354*1da177e4SLinus Torvalds 			error = atm_init_aal34(vcc);
355*1da177e4SLinus Torvalds 			vcc->stats = &dev->stats.aal34;
356*1da177e4SLinus Torvalds 			break;
357*1da177e4SLinus Torvalds 		case ATM_NO_AAL:
358*1da177e4SLinus Torvalds 			/* ATM_AAL5 is also used in the "0 for default" case */
359*1da177e4SLinus Torvalds 			vcc->qos.aal = ATM_AAL5;
360*1da177e4SLinus Torvalds 			/* fall through */
361*1da177e4SLinus Torvalds 		case ATM_AAL5:
362*1da177e4SLinus Torvalds 			error = atm_init_aal5(vcc);
363*1da177e4SLinus Torvalds 			vcc->stats = &dev->stats.aal5;
364*1da177e4SLinus Torvalds 			break;
365*1da177e4SLinus Torvalds 		default:
366*1da177e4SLinus Torvalds 			error = -EPROTOTYPE;
367*1da177e4SLinus Torvalds 	}
368*1da177e4SLinus Torvalds 	if (!error) error = adjust_tp(&vcc->qos.txtp,vcc->qos.aal);
369*1da177e4SLinus Torvalds 	if (!error) error = adjust_tp(&vcc->qos.rxtp,vcc->qos.aal);
370*1da177e4SLinus Torvalds 	if (error)
371*1da177e4SLinus Torvalds 		goto fail;
372*1da177e4SLinus Torvalds 	DPRINTK("VCC %d.%d, AAL %d\n",vpi,vci,vcc->qos.aal);
373*1da177e4SLinus Torvalds 	DPRINTK("  TX: %d, PCR %d..%d, SDU %d\n",vcc->qos.txtp.traffic_class,
374*1da177e4SLinus Torvalds 	    vcc->qos.txtp.min_pcr,vcc->qos.txtp.max_pcr,vcc->qos.txtp.max_sdu);
375*1da177e4SLinus Torvalds 	DPRINTK("  RX: %d, PCR %d..%d, SDU %d\n",vcc->qos.rxtp.traffic_class,
376*1da177e4SLinus Torvalds 	    vcc->qos.rxtp.min_pcr,vcc->qos.rxtp.max_pcr,vcc->qos.rxtp.max_sdu);
377*1da177e4SLinus Torvalds 
378*1da177e4SLinus Torvalds 	if (dev->ops->open) {
379*1da177e4SLinus Torvalds 		if ((error = dev->ops->open(vcc)))
380*1da177e4SLinus Torvalds 			goto fail;
381*1da177e4SLinus Torvalds 	}
382*1da177e4SLinus Torvalds 	return 0;
383*1da177e4SLinus Torvalds 
384*1da177e4SLinus Torvalds fail:
385*1da177e4SLinus Torvalds 	vcc_remove_socket(sk);
386*1da177e4SLinus Torvalds fail_module_put:
387*1da177e4SLinus Torvalds 	module_put(dev->ops->owner);
388*1da177e4SLinus Torvalds 	/* ensure we get dev module ref count correct */
389*1da177e4SLinus Torvalds 	vcc->dev = NULL;
390*1da177e4SLinus Torvalds 	return error;
391*1da177e4SLinus Torvalds }
392*1da177e4SLinus Torvalds 
393*1da177e4SLinus Torvalds 
394*1da177e4SLinus Torvalds int vcc_connect(struct socket *sock, int itf, short vpi, int vci)
395*1da177e4SLinus Torvalds {
396*1da177e4SLinus Torvalds 	struct atm_dev *dev;
397*1da177e4SLinus Torvalds 	struct atm_vcc *vcc = ATM_SD(sock);
398*1da177e4SLinus Torvalds 	int error;
399*1da177e4SLinus Torvalds 
400*1da177e4SLinus Torvalds 	DPRINTK("vcc_connect (vpi %d, vci %d)\n",vpi,vci);
401*1da177e4SLinus Torvalds 	if (sock->state == SS_CONNECTED)
402*1da177e4SLinus Torvalds 		return -EISCONN;
403*1da177e4SLinus Torvalds 	if (sock->state != SS_UNCONNECTED)
404*1da177e4SLinus Torvalds 		return -EINVAL;
405*1da177e4SLinus Torvalds 	if (!(vpi || vci))
406*1da177e4SLinus Torvalds 		return -EINVAL;
407*1da177e4SLinus Torvalds 
408*1da177e4SLinus Torvalds 	if (vpi != ATM_VPI_UNSPEC && vci != ATM_VCI_UNSPEC)
409*1da177e4SLinus Torvalds 		clear_bit(ATM_VF_PARTIAL,&vcc->flags);
410*1da177e4SLinus Torvalds 	else
411*1da177e4SLinus Torvalds 		if (test_bit(ATM_VF_PARTIAL,&vcc->flags))
412*1da177e4SLinus Torvalds 			return -EINVAL;
413*1da177e4SLinus Torvalds 	DPRINTK("vcc_connect (TX: cl %d,bw %d-%d,sdu %d; "
414*1da177e4SLinus Torvalds 	    "RX: cl %d,bw %d-%d,sdu %d,AAL %s%d)\n",
415*1da177e4SLinus Torvalds 	    vcc->qos.txtp.traffic_class,vcc->qos.txtp.min_pcr,
416*1da177e4SLinus Torvalds 	    vcc->qos.txtp.max_pcr,vcc->qos.txtp.max_sdu,
417*1da177e4SLinus Torvalds 	    vcc->qos.rxtp.traffic_class,vcc->qos.rxtp.min_pcr,
418*1da177e4SLinus Torvalds 	    vcc->qos.rxtp.max_pcr,vcc->qos.rxtp.max_sdu,
419*1da177e4SLinus Torvalds 	    vcc->qos.aal == ATM_AAL5 ? "" : vcc->qos.aal == ATM_AAL0 ? "" :
420*1da177e4SLinus Torvalds 	    " ??? code ",vcc->qos.aal == ATM_AAL0 ? 0 : vcc->qos.aal);
421*1da177e4SLinus Torvalds 	if (!test_bit(ATM_VF_HASQOS, &vcc->flags))
422*1da177e4SLinus Torvalds 		return -EBADFD;
423*1da177e4SLinus Torvalds 	if (vcc->qos.txtp.traffic_class == ATM_ANYCLASS ||
424*1da177e4SLinus Torvalds 	    vcc->qos.rxtp.traffic_class == ATM_ANYCLASS)
425*1da177e4SLinus Torvalds 		return -EINVAL;
426*1da177e4SLinus Torvalds 	if (itf != ATM_ITF_ANY) {
427*1da177e4SLinus Torvalds 		dev = atm_dev_lookup(itf);
428*1da177e4SLinus Torvalds 		if (!dev)
429*1da177e4SLinus Torvalds 			return -ENODEV;
430*1da177e4SLinus Torvalds 		error = __vcc_connect(vcc, dev, vpi, vci);
431*1da177e4SLinus Torvalds 		if (error) {
432*1da177e4SLinus Torvalds 			atm_dev_put(dev);
433*1da177e4SLinus Torvalds 			return error;
434*1da177e4SLinus Torvalds 		}
435*1da177e4SLinus Torvalds 	} else {
436*1da177e4SLinus Torvalds 		struct list_head *p, *next;
437*1da177e4SLinus Torvalds 
438*1da177e4SLinus Torvalds 		dev = NULL;
439*1da177e4SLinus Torvalds 		spin_lock(&atm_dev_lock);
440*1da177e4SLinus Torvalds 		list_for_each_safe(p, next, &atm_devs) {
441*1da177e4SLinus Torvalds 			dev = list_entry(p, struct atm_dev, dev_list);
442*1da177e4SLinus Torvalds 			atm_dev_hold(dev);
443*1da177e4SLinus Torvalds 			spin_unlock(&atm_dev_lock);
444*1da177e4SLinus Torvalds 			if (!__vcc_connect(vcc, dev, vpi, vci))
445*1da177e4SLinus Torvalds 				break;
446*1da177e4SLinus Torvalds 			atm_dev_put(dev);
447*1da177e4SLinus Torvalds 			dev = NULL;
448*1da177e4SLinus Torvalds 			spin_lock(&atm_dev_lock);
449*1da177e4SLinus Torvalds 		}
450*1da177e4SLinus Torvalds 		spin_unlock(&atm_dev_lock);
451*1da177e4SLinus Torvalds 		if (!dev)
452*1da177e4SLinus Torvalds 			return -ENODEV;
453*1da177e4SLinus Torvalds 	}
454*1da177e4SLinus Torvalds 	if (vpi == ATM_VPI_UNSPEC || vci == ATM_VCI_UNSPEC)
455*1da177e4SLinus Torvalds 		set_bit(ATM_VF_PARTIAL,&vcc->flags);
456*1da177e4SLinus Torvalds 	if (test_bit(ATM_VF_READY,&ATM_SD(sock)->flags))
457*1da177e4SLinus Torvalds 		sock->state = SS_CONNECTED;
458*1da177e4SLinus Torvalds 	return 0;
459*1da177e4SLinus Torvalds }
460*1da177e4SLinus Torvalds 
461*1da177e4SLinus Torvalds 
462*1da177e4SLinus Torvalds int vcc_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
463*1da177e4SLinus Torvalds 		size_t size, int flags)
464*1da177e4SLinus Torvalds {
465*1da177e4SLinus Torvalds 	struct sock *sk = sock->sk;
466*1da177e4SLinus Torvalds 	struct atm_vcc *vcc;
467*1da177e4SLinus Torvalds 	struct sk_buff *skb;
468*1da177e4SLinus Torvalds 	int copied, error = -EINVAL;
469*1da177e4SLinus Torvalds 
470*1da177e4SLinus Torvalds 	if (sock->state != SS_CONNECTED)
471*1da177e4SLinus Torvalds 		return -ENOTCONN;
472*1da177e4SLinus Torvalds 	if (flags & ~MSG_DONTWAIT)		/* only handle MSG_DONTWAIT */
473*1da177e4SLinus Torvalds 		return -EOPNOTSUPP;
474*1da177e4SLinus Torvalds 	vcc = ATM_SD(sock);
475*1da177e4SLinus Torvalds 	if (test_bit(ATM_VF_RELEASED,&vcc->flags) ||
476*1da177e4SLinus Torvalds 	    test_bit(ATM_VF_CLOSE,&vcc->flags) ||
477*1da177e4SLinus Torvalds 	    !test_bit(ATM_VF_READY, &vcc->flags))
478*1da177e4SLinus Torvalds 		return 0;
479*1da177e4SLinus Torvalds 
480*1da177e4SLinus Torvalds 	skb = skb_recv_datagram(sk, flags, flags & MSG_DONTWAIT, &error);
481*1da177e4SLinus Torvalds 	if (!skb)
482*1da177e4SLinus Torvalds 		return error;
483*1da177e4SLinus Torvalds 
484*1da177e4SLinus Torvalds 	copied = skb->len;
485*1da177e4SLinus Torvalds 	if (copied > size) {
486*1da177e4SLinus Torvalds 		copied = size;
487*1da177e4SLinus Torvalds 		msg->msg_flags |= MSG_TRUNC;
488*1da177e4SLinus Torvalds 	}
489*1da177e4SLinus Torvalds 
490*1da177e4SLinus Torvalds         error = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
491*1da177e4SLinus Torvalds         if (error)
492*1da177e4SLinus Torvalds                 return error;
493*1da177e4SLinus Torvalds         sock_recv_timestamp(msg, sk, skb);
494*1da177e4SLinus Torvalds         DPRINTK("RcvM %d -= %d\n", atomic_read(&sk->rmem_alloc), skb->truesize);
495*1da177e4SLinus Torvalds         atm_return(vcc, skb->truesize);
496*1da177e4SLinus Torvalds         skb_free_datagram(sk, skb);
497*1da177e4SLinus Torvalds         return copied;
498*1da177e4SLinus Torvalds }
499*1da177e4SLinus Torvalds 
500*1da177e4SLinus Torvalds 
501*1da177e4SLinus Torvalds int vcc_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m,
502*1da177e4SLinus Torvalds 		size_t total_len)
503*1da177e4SLinus Torvalds {
504*1da177e4SLinus Torvalds 	struct sock *sk = sock->sk;
505*1da177e4SLinus Torvalds 	DEFINE_WAIT(wait);
506*1da177e4SLinus Torvalds 	struct atm_vcc *vcc;
507*1da177e4SLinus Torvalds 	struct sk_buff *skb;
508*1da177e4SLinus Torvalds 	int eff,error;
509*1da177e4SLinus Torvalds 	const void __user *buff;
510*1da177e4SLinus Torvalds 	int size;
511*1da177e4SLinus Torvalds 
512*1da177e4SLinus Torvalds 	lock_sock(sk);
513*1da177e4SLinus Torvalds 	if (sock->state != SS_CONNECTED) {
514*1da177e4SLinus Torvalds 		error = -ENOTCONN;
515*1da177e4SLinus Torvalds 		goto out;
516*1da177e4SLinus Torvalds 	}
517*1da177e4SLinus Torvalds 	if (m->msg_name) {
518*1da177e4SLinus Torvalds 		error = -EISCONN;
519*1da177e4SLinus Torvalds 		goto out;
520*1da177e4SLinus Torvalds 	}
521*1da177e4SLinus Torvalds 	if (m->msg_iovlen != 1) {
522*1da177e4SLinus Torvalds 		error = -ENOSYS; /* fix this later @@@ */
523*1da177e4SLinus Torvalds 		goto out;
524*1da177e4SLinus Torvalds 	}
525*1da177e4SLinus Torvalds 	buff = m->msg_iov->iov_base;
526*1da177e4SLinus Torvalds 	size = m->msg_iov->iov_len;
527*1da177e4SLinus Torvalds 	vcc = ATM_SD(sock);
528*1da177e4SLinus Torvalds 	if (test_bit(ATM_VF_RELEASED, &vcc->flags) ||
529*1da177e4SLinus Torvalds 	    test_bit(ATM_VF_CLOSE, &vcc->flags) ||
530*1da177e4SLinus Torvalds 	    !test_bit(ATM_VF_READY, &vcc->flags)) {
531*1da177e4SLinus Torvalds 		error = -EPIPE;
532*1da177e4SLinus Torvalds 		send_sig(SIGPIPE, current, 0);
533*1da177e4SLinus Torvalds 		goto out;
534*1da177e4SLinus Torvalds 	}
535*1da177e4SLinus Torvalds 	if (!size) {
536*1da177e4SLinus Torvalds 		error = 0;
537*1da177e4SLinus Torvalds 		goto out;
538*1da177e4SLinus Torvalds 	}
539*1da177e4SLinus Torvalds 	if (size < 0 || size > vcc->qos.txtp.max_sdu) {
540*1da177e4SLinus Torvalds 		error = -EMSGSIZE;
541*1da177e4SLinus Torvalds 		goto out;
542*1da177e4SLinus Torvalds 	}
543*1da177e4SLinus Torvalds 	/* verify_area is done by net/socket.c */
544*1da177e4SLinus Torvalds 	eff = (size+3) & ~3; /* align to word boundary */
545*1da177e4SLinus Torvalds 	prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
546*1da177e4SLinus Torvalds 	error = 0;
547*1da177e4SLinus Torvalds 	while (!(skb = alloc_tx(vcc,eff))) {
548*1da177e4SLinus Torvalds 		if (m->msg_flags & MSG_DONTWAIT) {
549*1da177e4SLinus Torvalds 			error = -EAGAIN;
550*1da177e4SLinus Torvalds 			break;
551*1da177e4SLinus Torvalds 		}
552*1da177e4SLinus Torvalds 		schedule();
553*1da177e4SLinus Torvalds 		if (signal_pending(current)) {
554*1da177e4SLinus Torvalds 			error = -ERESTARTSYS;
555*1da177e4SLinus Torvalds 			break;
556*1da177e4SLinus Torvalds 		}
557*1da177e4SLinus Torvalds 		if (test_bit(ATM_VF_RELEASED,&vcc->flags) ||
558*1da177e4SLinus Torvalds 		    test_bit(ATM_VF_CLOSE,&vcc->flags) ||
559*1da177e4SLinus Torvalds 		    !test_bit(ATM_VF_READY,&vcc->flags)) {
560*1da177e4SLinus Torvalds 			error = -EPIPE;
561*1da177e4SLinus Torvalds 			send_sig(SIGPIPE, current, 0);
562*1da177e4SLinus Torvalds 			break;
563*1da177e4SLinus Torvalds 		}
564*1da177e4SLinus Torvalds 		prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
565*1da177e4SLinus Torvalds 	}
566*1da177e4SLinus Torvalds 	finish_wait(sk->sk_sleep, &wait);
567*1da177e4SLinus Torvalds 	if (error)
568*1da177e4SLinus Torvalds 		goto out;
569*1da177e4SLinus Torvalds 	skb->dev = NULL; /* for paths shared with net_device interfaces */
570*1da177e4SLinus Torvalds 	ATM_SKB(skb)->atm_options = vcc->atm_options;
571*1da177e4SLinus Torvalds 	if (copy_from_user(skb_put(skb,size),buff,size)) {
572*1da177e4SLinus Torvalds 		kfree_skb(skb);
573*1da177e4SLinus Torvalds 		error = -EFAULT;
574*1da177e4SLinus Torvalds 		goto out;
575*1da177e4SLinus Torvalds 	}
576*1da177e4SLinus Torvalds 	if (eff != size) memset(skb->data+size,0,eff-size);
577*1da177e4SLinus Torvalds 	error = vcc->dev->ops->send(vcc,skb);
578*1da177e4SLinus Torvalds 	error = error ? error : size;
579*1da177e4SLinus Torvalds out:
580*1da177e4SLinus Torvalds 	release_sock(sk);
581*1da177e4SLinus Torvalds 	return error;
582*1da177e4SLinus Torvalds }
583*1da177e4SLinus Torvalds 
584*1da177e4SLinus Torvalds 
585*1da177e4SLinus Torvalds unsigned int vcc_poll(struct file *file, struct socket *sock, poll_table *wait)
586*1da177e4SLinus Torvalds {
587*1da177e4SLinus Torvalds 	struct sock *sk = sock->sk;
588*1da177e4SLinus Torvalds 	struct atm_vcc *vcc;
589*1da177e4SLinus Torvalds 	unsigned int mask;
590*1da177e4SLinus Torvalds 
591*1da177e4SLinus Torvalds 	poll_wait(file, sk->sk_sleep, wait);
592*1da177e4SLinus Torvalds 	mask = 0;
593*1da177e4SLinus Torvalds 
594*1da177e4SLinus Torvalds 	vcc = ATM_SD(sock);
595*1da177e4SLinus Torvalds 
596*1da177e4SLinus Torvalds 	/* exceptional events */
597*1da177e4SLinus Torvalds 	if (sk->sk_err)
598*1da177e4SLinus Torvalds 		mask = POLLERR;
599*1da177e4SLinus Torvalds 
600*1da177e4SLinus Torvalds 	if (test_bit(ATM_VF_RELEASED, &vcc->flags) ||
601*1da177e4SLinus Torvalds 	    test_bit(ATM_VF_CLOSE, &vcc->flags))
602*1da177e4SLinus Torvalds 		mask |= POLLHUP;
603*1da177e4SLinus Torvalds 
604*1da177e4SLinus Torvalds 	/* readable? */
605*1da177e4SLinus Torvalds 	if (!skb_queue_empty(&sk->sk_receive_queue))
606*1da177e4SLinus Torvalds 		mask |= POLLIN | POLLRDNORM;
607*1da177e4SLinus Torvalds 
608*1da177e4SLinus Torvalds 	/* writable? */
609*1da177e4SLinus Torvalds 	if (sock->state == SS_CONNECTING &&
610*1da177e4SLinus Torvalds 	    test_bit(ATM_VF_WAITING, &vcc->flags))
611*1da177e4SLinus Torvalds 		return mask;
612*1da177e4SLinus Torvalds 
613*1da177e4SLinus Torvalds 	if (vcc->qos.txtp.traffic_class != ATM_NONE &&
614*1da177e4SLinus Torvalds 	    vcc_writable(sk))
615*1da177e4SLinus Torvalds 		mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
616*1da177e4SLinus Torvalds 
617*1da177e4SLinus Torvalds 	return mask;
618*1da177e4SLinus Torvalds }
619*1da177e4SLinus Torvalds 
620*1da177e4SLinus Torvalds 
621*1da177e4SLinus Torvalds static int atm_change_qos(struct atm_vcc *vcc,struct atm_qos *qos)
622*1da177e4SLinus Torvalds {
623*1da177e4SLinus Torvalds 	int error;
624*1da177e4SLinus Torvalds 
625*1da177e4SLinus Torvalds 	/*
626*1da177e4SLinus Torvalds 	 * Don't let the QoS change the already connected AAL type nor the
627*1da177e4SLinus Torvalds 	 * traffic class.
628*1da177e4SLinus Torvalds 	 */
629*1da177e4SLinus Torvalds 	if (qos->aal != vcc->qos.aal ||
630*1da177e4SLinus Torvalds 	    qos->rxtp.traffic_class != vcc->qos.rxtp.traffic_class ||
631*1da177e4SLinus Torvalds 	    qos->txtp.traffic_class != vcc->qos.txtp.traffic_class)
632*1da177e4SLinus Torvalds 		return -EINVAL;
633*1da177e4SLinus Torvalds 	error = adjust_tp(&qos->txtp,qos->aal);
634*1da177e4SLinus Torvalds 	if (!error) error = adjust_tp(&qos->rxtp,qos->aal);
635*1da177e4SLinus Torvalds 	if (error) return error;
636*1da177e4SLinus Torvalds 	if (!vcc->dev->ops->change_qos) return -EOPNOTSUPP;
637*1da177e4SLinus Torvalds 	if (sk_atm(vcc)->sk_family == AF_ATMPVC)
638*1da177e4SLinus Torvalds 		return vcc->dev->ops->change_qos(vcc,qos,ATM_MF_SET);
639*1da177e4SLinus Torvalds 	return svc_change_qos(vcc,qos);
640*1da177e4SLinus Torvalds }
641*1da177e4SLinus Torvalds 
642*1da177e4SLinus Torvalds 
643*1da177e4SLinus Torvalds static int check_tp(struct atm_trafprm *tp)
644*1da177e4SLinus Torvalds {
645*1da177e4SLinus Torvalds 	/* @@@ Should be merged with adjust_tp */
646*1da177e4SLinus Torvalds 	if (!tp->traffic_class || tp->traffic_class == ATM_ANYCLASS) return 0;
647*1da177e4SLinus Torvalds 	if (tp->traffic_class != ATM_UBR && !tp->min_pcr && !tp->pcr &&
648*1da177e4SLinus Torvalds 	    !tp->max_pcr) return -EINVAL;
649*1da177e4SLinus Torvalds 	if (tp->min_pcr == ATM_MAX_PCR) return -EINVAL;
650*1da177e4SLinus Torvalds 	if (tp->min_pcr && tp->max_pcr && tp->max_pcr != ATM_MAX_PCR &&
651*1da177e4SLinus Torvalds 	    tp->min_pcr > tp->max_pcr) return -EINVAL;
652*1da177e4SLinus Torvalds 	/*
653*1da177e4SLinus Torvalds 	 * We allow pcr to be outside [min_pcr,max_pcr], because later
654*1da177e4SLinus Torvalds 	 * adjustment may still push it in the valid range.
655*1da177e4SLinus Torvalds 	 */
656*1da177e4SLinus Torvalds 	return 0;
657*1da177e4SLinus Torvalds }
658*1da177e4SLinus Torvalds 
659*1da177e4SLinus Torvalds 
660*1da177e4SLinus Torvalds static int check_qos(struct atm_qos *qos)
661*1da177e4SLinus Torvalds {
662*1da177e4SLinus Torvalds 	int error;
663*1da177e4SLinus Torvalds 
664*1da177e4SLinus Torvalds 	if (!qos->txtp.traffic_class && !qos->rxtp.traffic_class)
665*1da177e4SLinus Torvalds                 return -EINVAL;
666*1da177e4SLinus Torvalds 	if (qos->txtp.traffic_class != qos->rxtp.traffic_class &&
667*1da177e4SLinus Torvalds 	    qos->txtp.traffic_class && qos->rxtp.traffic_class &&
668*1da177e4SLinus Torvalds 	    qos->txtp.traffic_class != ATM_ANYCLASS &&
669*1da177e4SLinus Torvalds 	    qos->rxtp.traffic_class != ATM_ANYCLASS) return -EINVAL;
670*1da177e4SLinus Torvalds 	error = check_tp(&qos->txtp);
671*1da177e4SLinus Torvalds 	if (error) return error;
672*1da177e4SLinus Torvalds 	return check_tp(&qos->rxtp);
673*1da177e4SLinus Torvalds }
674*1da177e4SLinus Torvalds 
675*1da177e4SLinus Torvalds int vcc_setsockopt(struct socket *sock, int level, int optname,
676*1da177e4SLinus Torvalds 		   char __user *optval, int optlen)
677*1da177e4SLinus Torvalds {
678*1da177e4SLinus Torvalds 	struct atm_vcc *vcc;
679*1da177e4SLinus Torvalds 	unsigned long value;
680*1da177e4SLinus Torvalds 	int error;
681*1da177e4SLinus Torvalds 
682*1da177e4SLinus Torvalds 	if (__SO_LEVEL_MATCH(optname, level) && optlen != __SO_SIZE(optname))
683*1da177e4SLinus Torvalds 		return -EINVAL;
684*1da177e4SLinus Torvalds 
685*1da177e4SLinus Torvalds 	vcc = ATM_SD(sock);
686*1da177e4SLinus Torvalds 	switch (optname) {
687*1da177e4SLinus Torvalds 		case SO_ATMQOS:
688*1da177e4SLinus Torvalds 			{
689*1da177e4SLinus Torvalds 				struct atm_qos qos;
690*1da177e4SLinus Torvalds 
691*1da177e4SLinus Torvalds 				if (copy_from_user(&qos,optval,sizeof(qos)))
692*1da177e4SLinus Torvalds 					return -EFAULT;
693*1da177e4SLinus Torvalds 				error = check_qos(&qos);
694*1da177e4SLinus Torvalds 				if (error) return error;
695*1da177e4SLinus Torvalds 				if (sock->state == SS_CONNECTED)
696*1da177e4SLinus Torvalds 					return atm_change_qos(vcc,&qos);
697*1da177e4SLinus Torvalds 				if (sock->state != SS_UNCONNECTED)
698*1da177e4SLinus Torvalds 					return -EBADFD;
699*1da177e4SLinus Torvalds 				vcc->qos = qos;
700*1da177e4SLinus Torvalds 				set_bit(ATM_VF_HASQOS,&vcc->flags);
701*1da177e4SLinus Torvalds 				return 0;
702*1da177e4SLinus Torvalds 			}
703*1da177e4SLinus Torvalds 		case SO_SETCLP:
704*1da177e4SLinus Torvalds 			if (get_user(value,(unsigned long __user *)optval))
705*1da177e4SLinus Torvalds 				return -EFAULT;
706*1da177e4SLinus Torvalds 			if (value) vcc->atm_options |= ATM_ATMOPT_CLP;
707*1da177e4SLinus Torvalds 			else vcc->atm_options &= ~ATM_ATMOPT_CLP;
708*1da177e4SLinus Torvalds 			return 0;
709*1da177e4SLinus Torvalds 		default:
710*1da177e4SLinus Torvalds 			if (level == SOL_SOCKET) return -EINVAL;
711*1da177e4SLinus Torvalds 			break;
712*1da177e4SLinus Torvalds 	}
713*1da177e4SLinus Torvalds 	if (!vcc->dev || !vcc->dev->ops->setsockopt) return -EINVAL;
714*1da177e4SLinus Torvalds 	return vcc->dev->ops->setsockopt(vcc,level,optname,optval,optlen);
715*1da177e4SLinus Torvalds }
716*1da177e4SLinus Torvalds 
717*1da177e4SLinus Torvalds 
718*1da177e4SLinus Torvalds int vcc_getsockopt(struct socket *sock, int level, int optname,
719*1da177e4SLinus Torvalds 		   char __user *optval, int __user *optlen)
720*1da177e4SLinus Torvalds {
721*1da177e4SLinus Torvalds 	struct atm_vcc *vcc;
722*1da177e4SLinus Torvalds 	int len;
723*1da177e4SLinus Torvalds 
724*1da177e4SLinus Torvalds 	if (get_user(len, optlen))
725*1da177e4SLinus Torvalds 		return -EFAULT;
726*1da177e4SLinus Torvalds 	if (__SO_LEVEL_MATCH(optname, level) && len != __SO_SIZE(optname))
727*1da177e4SLinus Torvalds 		return -EINVAL;
728*1da177e4SLinus Torvalds 
729*1da177e4SLinus Torvalds 	vcc = ATM_SD(sock);
730*1da177e4SLinus Torvalds 	switch (optname) {
731*1da177e4SLinus Torvalds 		case SO_ATMQOS:
732*1da177e4SLinus Torvalds 			if (!test_bit(ATM_VF_HASQOS,&vcc->flags))
733*1da177e4SLinus Torvalds 				return -EINVAL;
734*1da177e4SLinus Torvalds 			return copy_to_user(optval,&vcc->qos,sizeof(vcc->qos)) ?
735*1da177e4SLinus Torvalds 			    -EFAULT : 0;
736*1da177e4SLinus Torvalds 		case SO_SETCLP:
737*1da177e4SLinus Torvalds 			return put_user(vcc->atm_options & ATM_ATMOPT_CLP ? 1 :
738*1da177e4SLinus Torvalds 			  0,(unsigned long __user *)optval) ? -EFAULT : 0;
739*1da177e4SLinus Torvalds 		case SO_ATMPVC:
740*1da177e4SLinus Torvalds 			{
741*1da177e4SLinus Torvalds 				struct sockaddr_atmpvc pvc;
742*1da177e4SLinus Torvalds 
743*1da177e4SLinus Torvalds 				if (!vcc->dev ||
744*1da177e4SLinus Torvalds 				    !test_bit(ATM_VF_ADDR,&vcc->flags))
745*1da177e4SLinus Torvalds 					return -ENOTCONN;
746*1da177e4SLinus Torvalds 				pvc.sap_family = AF_ATMPVC;
747*1da177e4SLinus Torvalds 				pvc.sap_addr.itf = vcc->dev->number;
748*1da177e4SLinus Torvalds 				pvc.sap_addr.vpi = vcc->vpi;
749*1da177e4SLinus Torvalds 				pvc.sap_addr.vci = vcc->vci;
750*1da177e4SLinus Torvalds 				return copy_to_user(optval,&pvc,sizeof(pvc)) ?
751*1da177e4SLinus Torvalds 				    -EFAULT : 0;
752*1da177e4SLinus Torvalds 			}
753*1da177e4SLinus Torvalds 		default:
754*1da177e4SLinus Torvalds 			if (level == SOL_SOCKET) return -EINVAL;
755*1da177e4SLinus Torvalds 			break;
756*1da177e4SLinus Torvalds 	}
757*1da177e4SLinus Torvalds 	if (!vcc->dev || !vcc->dev->ops->getsockopt) return -EINVAL;
758*1da177e4SLinus Torvalds 	return vcc->dev->ops->getsockopt(vcc, level, optname, optval, len);
759*1da177e4SLinus Torvalds }
760*1da177e4SLinus Torvalds 
761*1da177e4SLinus Torvalds static int __init atm_init(void)
762*1da177e4SLinus Torvalds {
763*1da177e4SLinus Torvalds 	int error;
764*1da177e4SLinus Torvalds 
765*1da177e4SLinus Torvalds 	if ((error = proto_register(&vcc_proto, 0)) < 0)
766*1da177e4SLinus Torvalds 		goto out;
767*1da177e4SLinus Torvalds 
768*1da177e4SLinus Torvalds 	if ((error = atmpvc_init()) < 0) {
769*1da177e4SLinus Torvalds 		printk(KERN_ERR "atmpvc_init() failed with %d\n", error);
770*1da177e4SLinus Torvalds 		goto out_unregister_vcc_proto;
771*1da177e4SLinus Torvalds 	}
772*1da177e4SLinus Torvalds 	if ((error = atmsvc_init()) < 0) {
773*1da177e4SLinus Torvalds 		printk(KERN_ERR "atmsvc_init() failed with %d\n", error);
774*1da177e4SLinus Torvalds 		goto out_atmpvc_exit;
775*1da177e4SLinus Torvalds 	}
776*1da177e4SLinus Torvalds         if ((error = atm_proc_init()) < 0) {
777*1da177e4SLinus Torvalds 		printk(KERN_ERR "atm_proc_init() failed with %d\n",error);
778*1da177e4SLinus Torvalds 		goto out_atmsvc_exit;
779*1da177e4SLinus Torvalds 	}
780*1da177e4SLinus Torvalds out:
781*1da177e4SLinus Torvalds 	return error;
782*1da177e4SLinus Torvalds out_atmsvc_exit:
783*1da177e4SLinus Torvalds 	atmsvc_exit();
784*1da177e4SLinus Torvalds out_atmpvc_exit:
785*1da177e4SLinus Torvalds 	atmsvc_exit();
786*1da177e4SLinus Torvalds out_unregister_vcc_proto:
787*1da177e4SLinus Torvalds 	proto_unregister(&vcc_proto);
788*1da177e4SLinus Torvalds 	goto out;
789*1da177e4SLinus Torvalds }
790*1da177e4SLinus Torvalds 
791*1da177e4SLinus Torvalds static void __exit atm_exit(void)
792*1da177e4SLinus Torvalds {
793*1da177e4SLinus Torvalds 	atm_proc_exit();
794*1da177e4SLinus Torvalds 	atmsvc_exit();
795*1da177e4SLinus Torvalds 	atmpvc_exit();
796*1da177e4SLinus Torvalds 	proto_unregister(&vcc_proto);
797*1da177e4SLinus Torvalds }
798*1da177e4SLinus Torvalds 
799*1da177e4SLinus Torvalds module_init(atm_init);
800*1da177e4SLinus Torvalds module_exit(atm_exit);
801*1da177e4SLinus Torvalds 
802*1da177e4SLinus Torvalds MODULE_LICENSE("GPL");
803*1da177e4SLinus Torvalds MODULE_ALIAS_NETPROTO(PF_ATMPVC);
804*1da177e4SLinus Torvalds MODULE_ALIAS_NETPROTO(PF_ATMSVC);
805