Import 2.3.18pre1
[davej-history.git] / net / atm / common.c
blobcd1572010832d37cc6ab33433474196d20e95f0b
1 /* net/atm/common.c - ATM sockets (common part for PVC and SVC) */
3 /* Written 1995-1999 by Werner Almesberger, EPFL LRC/ICA */
6 #include <linux/config.h>
7 #include <linux/module.h>
8 #include <linux/net.h> /* struct socket, struct net_proto, struct
9 proto_ops */
10 #include <linux/atm.h> /* ATM stuff */
11 #include <linux/atmdev.h>
12 #include <linux/atmclip.h> /* CLIP_*ENCAP */
13 #include <linux/atmarp.h> /* manifest constants */
14 #include <linux/sonet.h> /* for ioctls */
15 #include <linux/socket.h> /* SOL_SOCKET */
16 #include <linux/errno.h> /* error codes */
17 #include <linux/capability.h>
18 #include <linux/mm.h> /* verify_area */
19 #include <linux/sched.h>
20 #include <linux/time.h> /* struct timeval */
21 #include <linux/skbuff.h>
22 #include <net/sock.h> /* struct sock */
24 #include <asm/uaccess.h>
25 #include <asm/poll.h>
27 #ifdef CONFIG_MMU_HACKS
28 #include <linux/mmuio.h>
29 #include <linux/uio.h>
30 #endif
32 #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
33 #include <linux/atmlec.h>
34 #include "lec.h"
35 #include "lec_arpc.h"
36 struct atm_lane_ops atm_lane_ops;
37 #endif
38 #ifdef CONFIG_ATM_LANE_MODULE
39 EXPORT_SYMBOL(atm_lane_ops);
40 #endif
42 #if defined(CONFIG_ATM_MPOA) || defined(CONFIG_ATM_MPOA_MODULE)
43 #include <linux/atmmpc.h>
44 #include "mpc.h"
45 struct atm_mpoa_ops atm_mpoa_ops;
46 #endif
47 #ifdef CONFIG_ATM_MPOA_MODULE
48 EXPORT_SYMBOL(atm_mpoa_ops);
49 #ifndef CONFIG_ATM_LANE_MODULE
50 EXPORT_SYMBOL(atm_lane_ops);
51 #endif
52 #endif
54 #if defined(CONFIG_ATM_TCP) || defined(CONFIG_ATM_TCP_MODULE)
55 #include <linux/atm_tcp.h>
56 #ifdef CONFIG_ATM_TCP_MODULE
57 struct atm_tcp_ops atm_tcp_ops;
58 EXPORT_SYMBOL(atm_tcp_ops);
59 #endif
60 #endif
62 #include "resources.h" /* atm_find_dev */
63 #include "common.h" /* prototypes */
64 #include "protocols.h" /* atm_init_<transport> */
65 #include "tunable.h" /* tunable parameters */
66 #include "addr.h" /* address registry */
67 #ifdef CONFIG_ATM_CLIP
68 #include <net/atmclip.h> /* for clip_create */
69 #endif
70 #include "signaling.h" /* for WAITING and sigd_attach */
73 #if 0
74 #define DPRINTK(format,args...) printk(KERN_DEBUG format,##args)
75 #else
76 #define DPRINTK(format,args...)
77 #endif
80 static struct sk_buff *alloc_tx(struct atm_vcc *vcc,unsigned int size)
82 struct sk_buff *skb;
84 if (atomic_read(&vcc->tx_inuse) && size+atomic_read(&vcc->tx_inuse)+
85 ATM_PDU_OVHD > vcc->tx_quota) {
86 DPRINTK("Sorry: tx_inuse = %d, size = %d, tx_quota = %ld\n",
87 atomic_read(&vcc->tx_inuse),size,vcc->tx_quota);
88 return NULL;
90 while (!(skb = alloc_skb(size,GFP_KERNEL))) schedule();
91 DPRINTK("AlTx %d += %d\n",atomic_read(&vcc->tx_inuse),skb->truesize);
92 atomic_add(skb->truesize+ATM_PDU_OVHD,&vcc->tx_inuse);
93 return skb;
97 int atm_create(struct socket *sock,int protocol,int family)
99 struct sock *sk;
100 struct atm_vcc *vcc;
102 sock->sk = NULL;
103 if (sock->type == SOCK_STREAM) return -EINVAL;
104 if (!(sk = alloc_atm_vcc_sk(family))) return -ENOMEM;
105 vcc = sk->protinfo.af_atm;
106 vcc->flags = ATM_VF_SCRX | ATM_VF_SCTX;
107 vcc->dev = NULL;
108 vcc->family = sock->ops->family;
109 vcc->alloc_tx = alloc_tx;
110 vcc->callback = NULL;
111 memset(&vcc->local,0,sizeof(struct sockaddr_atmsvc));
112 memset(&vcc->remote,0,sizeof(struct sockaddr_atmsvc));
113 vcc->tx_quota = ATM_TXBQ_DEF;
114 vcc->rx_quota = ATM_RXBQ_DEF;
115 atomic_set(&vcc->tx_inuse,0);
116 atomic_set(&vcc->rx_inuse,0);
117 vcc->push = NULL;
118 vcc->pop = NULL;
119 vcc->push_oam = NULL;
120 vcc->vpi = vcc->vci = 0; /* no VCI/VPI yet */
121 vcc->atm_options = vcc->aal_options = 0;
122 vcc->timestamp.tv_sec = vcc->timestamp.tv_usec = 0;
123 init_waitqueue_head(&vcc->sleep);
124 init_waitqueue_head(&vcc->wsleep);
125 skb_queue_head_init(&vcc->recvq);
126 skb_queue_head_init(&vcc->listenq);
127 sock->sk = sk;
128 return 0;
132 void atm_release_vcc_sk(struct sock *sk,int free_sk)
134 struct atm_vcc *vcc;
135 struct sk_buff *skb;
137 vcc = sk->protinfo.af_atm;
138 vcc->flags &= ~ATM_VF_READY;
139 if (vcc->dev) {
140 if (vcc->dev->ops->close) vcc->dev->ops->close(vcc);
141 if (vcc->push) vcc->push(vcc,NULL); /* atmarpd has no push */
142 while ((skb = skb_dequeue(&vcc->recvq))) {
143 atm_return(vcc,skb->truesize);
144 if (vcc->dev->ops->free_rx_skb)
145 vcc->dev->ops->free_rx_skb(vcc,skb);
146 else kfree_skb(skb);
148 if (atomic_read(&vcc->rx_inuse))
149 printk(KERN_WARNING "atm_release_vcc: strange ... "
150 "rx_inuse == %d after closing\n",
151 atomic_read(&vcc->rx_inuse));
152 bind_vcc(vcc,NULL);
154 if (free_sk) free_atm_vcc_sk(sk);
158 int atm_release(struct socket *sock)
160 if (sock->sk)
161 atm_release_vcc_sk(sock->sk,1);
162 return 0;
166 void atm_async_release_vcc(struct atm_vcc *vcc,int reply)
168 vcc->flags |= ATM_VF_CLOSE;
169 vcc->reply = reply;
170 /*vcc->flags &= ~ATM_VF_READY;*/
171 wake_up(&vcc->sleep);
175 EXPORT_SYMBOL(atm_async_release_vcc);
178 static int adjust_tp(struct atm_trafprm *tp,unsigned char aal)
180 int max_sdu;
182 if (!tp->traffic_class) return 0;
183 switch (aal) {
184 case ATM_AAL0:
185 max_sdu = ATM_CELL_SIZE-1;
186 break;
187 case ATM_AAL34:
188 max_sdu = ATM_MAX_AAL34_PDU;
189 break;
190 default:
191 printk(KERN_WARNING "ATM: AAL problems ... "
192 "(%d)\n",aal);
193 /* fall through */
194 case ATM_AAL5:
195 max_sdu = ATM_MAX_AAL5_PDU;
197 if (!tp->max_sdu) tp->max_sdu = max_sdu;
198 else if (tp->max_sdu > max_sdu) return -EINVAL;
199 if (!tp->max_cdv) tp->max_cdv = ATM_MAX_CDV;
200 return 0;
204 static int atm_do_connect_dev(struct atm_vcc *vcc,struct atm_dev *dev,int vpi,
205 int vci)
207 int error;
209 if ((vpi != ATM_VPI_UNSPEC && vpi != ATM_VPI_ANY &&
210 vpi >> dev->ci_range.vpi_bits) || (vci != ATM_VCI_UNSPEC &&
211 vci != ATM_VCI_ANY && vci >> dev->ci_range.vci_bits))
212 return -EINVAL;
213 if (vci > 0 && vci < ATM_NOT_RSV_VCI && !capable(CAP_NET_BIND_SERVICE))
214 return -EPERM;
215 error = 0;
216 switch (vcc->qos.aal) {
217 case ATM_AAL0:
218 error = atm_init_aal0(vcc);
219 vcc->stats = &dev->stats.aal0;
220 break;
221 case ATM_AAL34:
222 error = atm_init_aal34(vcc);
223 vcc->stats = &dev->stats.aal34;
224 break;
225 case ATM_NO_AAL:
226 /* ATM_AAL5 is also used in the "0 for default" case */
227 vcc->qos.aal = ATM_AAL5;
228 /* fall through */
229 case ATM_AAL5:
230 error = atm_init_aal5(vcc);
231 vcc->stats = &dev->stats.aal5;
232 break;
233 default:
234 error = -EPROTOTYPE;
236 if (!error) error = adjust_tp(&vcc->qos.txtp,vcc->qos.aal);
237 if (!error) error = adjust_tp(&vcc->qos.rxtp,vcc->qos.aal);
238 if (error) return error;
239 bind_vcc(vcc,dev);
240 DPRINTK("VCC %d.%d, AAL %d\n",vpi,vci,vcc->qos.aal);
241 DPRINTK(" TX: %d, PCR %d..%d, SDU %d\n",vcc->qos.txtp.traffic_class,
242 vcc->qos.txtp.min_pcr,vcc->qos.txtp.max_pcr,vcc->qos.txtp.max_sdu);
243 DPRINTK(" RX: %d, PCR %d..%d, SDU %d\n",vcc->qos.rxtp.traffic_class,
244 vcc->qos.rxtp.min_pcr,vcc->qos.rxtp.max_pcr,vcc->qos.rxtp.max_sdu);
245 if (dev->ops->open) {
246 error = dev->ops->open(vcc,vpi,vci);
247 if (error) {
248 bind_vcc(vcc,NULL);
249 return error;
252 return 0;
256 static int atm_do_connect(struct atm_vcc *vcc,int itf,int vpi,int vci)
258 struct atm_dev *dev;
260 dev = atm_find_dev(itf);
261 if (!dev) return -ENODEV;
262 return atm_do_connect_dev(vcc,dev,vpi,vci);
266 int atm_connect_vcc(struct atm_vcc *vcc,int itf,short vpi,int vci)
268 if (vpi != ATM_VPI_UNSPEC && vci != ATM_VCI_UNSPEC)
269 vcc->flags &= ~ATM_VF_PARTIAL;
270 else if (vcc->flags & ATM_VF_PARTIAL) return -EINVAL;
271 printk(KERN_DEBUG "atm_connect (TX: cl %d,bw %d-%d,sdu %d; "
272 "RX: cl %d,bw %d-%d,sdu %d,AAL %s%d)\n",
273 vcc->qos.txtp.traffic_class,vcc->qos.txtp.min_pcr,
274 vcc->qos.txtp.max_pcr,vcc->qos.txtp.max_sdu,
275 vcc->qos.rxtp.traffic_class,vcc->qos.rxtp.min_pcr,
276 vcc->qos.rxtp.max_pcr,vcc->qos.rxtp.max_sdu,
277 vcc->qos.aal == ATM_AAL5 ? "" : vcc->qos.aal == ATM_AAL0 ? "" :
278 " ??? code ",vcc->qos.aal == ATM_AAL0 ? 0 : vcc->qos.aal);
279 if (!(vcc->flags & ATM_VF_HASQOS)) return -EBADFD;
280 if (vcc->qos.txtp.traffic_class == ATM_ANYCLASS ||
281 vcc->qos.rxtp.traffic_class == ATM_ANYCLASS)
282 return -EINVAL;
283 if (itf != ATM_ITF_ANY) {
284 int error;
286 error = atm_do_connect(vcc,itf,vpi,vci);
287 if (error) return error;
289 else {
290 struct atm_dev *dev;
292 for (dev = atm_devs; dev; dev = dev->next)
293 if (!atm_do_connect_dev(vcc,dev,vpi,vci)) break;
294 if (!dev) return -ENODEV;
296 if (vpi == ATM_VPI_UNSPEC || vci == ATM_VCI_UNSPEC)
297 vcc->flags |= ATM_VF_PARTIAL;
298 return 0;
302 int atm_connect(struct socket *sock,int itf,short vpi,int vci)
304 int error;
306 DPRINTK("atm_connect (vpi %d, vci %d)\n",vpi,vci);
307 if (sock->state == SS_CONNECTED) return -EISCONN;
308 if (sock->state != SS_UNCONNECTED) return -EINVAL;
309 if (!(vpi || vci)) return -EINVAL;
310 error = atm_connect_vcc(ATM_SD(sock),itf,vpi,vci);
311 if (error) return error;
312 if (ATM_SD(sock)->flags & ATM_VF_READY) sock->state = SS_CONNECTED;
313 return 0;
317 int atm_recvmsg(struct socket *sock,struct msghdr *m,int total_len,
318 int flags,struct scm_cookie *scm)
320 struct atm_vcc *vcc;
321 struct sk_buff *skb;
322 unsigned long cpu_flags;
323 int eff_len,error;
325 void *buff;
326 int size;
328 if (sock->state != SS_CONNECTED) return -ENOTCONN;
329 if (flags & ~MSG_DONTWAIT) return -EOPNOTSUPP;
330 if (m->msg_iovlen != 1) return -ENOSYS; /* fix this later @@@ */
331 buff = m->msg_iov->iov_base;
332 size = m->msg_iov->iov_len;
333 vcc = ATM_SD(sock);
334 save_flags(cpu_flags);
335 cli();
336 while (!(skb = skb_dequeue(&vcc->recvq))) {
337 if (vcc->flags & (ATM_VF_RELEASED | ATM_VF_CLOSE)) {
338 restore_flags(cpu_flags);
339 return vcc->reply;
341 if (!(vcc->flags & ATM_VF_READY)) {
342 restore_flags(cpu_flags);
343 return 0;
345 if (flags & MSG_DONTWAIT) {
346 restore_flags(cpu_flags);
347 return -EAGAIN;
349 interruptible_sleep_on(&vcc->sleep);
350 if (signal_pending(current)) {
351 restore_flags(cpu_flags);
352 return -ERESTARTSYS;
355 restore_flags(cpu_flags);
356 vcc->timestamp = skb->stamp;
357 eff_len = skb->len > size ? size : skb->len;
358 if (vcc->dev->ops->feedback)
359 vcc->dev->ops->feedback(vcc,skb,(unsigned long) skb->data,
360 (unsigned long) buff,eff_len);
361 DPRINTK("RcvM %d -= %d\n",atomic_read(&vcc->rx_inuse),skb->truesize);
362 atm_return(vcc,skb->truesize);
363 if (ATM_SKB(skb)->iovcnt) { /* @@@ hack */
364 /* iovcnt set, use scatter-gather for receive */
365 int el, cnt;
366 struct iovec *iov = (struct iovec *)skb->data;
367 unsigned char *p = (unsigned char *)buff;
369 el = eff_len;
370 error = 0;
371 for (cnt = 0; (cnt < ATM_SKB(skb)->iovcnt) && el; cnt++) {
372 /*printk("s-g???: %p -> %p (%d)\n",iov->iov_base,p,iov->iov_len);*/
373 error = copy_to_user(p,iov->iov_base,
374 (iov->iov_len > el) ? el : iov->iov_len) ?
375 -EFAULT : 0;
376 if (error) break;
377 p += iov->iov_len;
378 el -= (iov->iov_len > el)?el:iov->iov_len;
379 iov++;
381 if (!vcc->dev->ops->free_rx_skb) kfree_skb(skb);
382 else vcc->dev->ops->free_rx_skb(vcc, skb);
383 return error ? error : eff_len;
385 #ifdef CONFIG_MMU_HACKS
386 if (vcc->flags & ATM_VF_SCRX) {
387 mmucp_tofs((unsigned long) buff,eff_len,skb,
388 (unsigned long) skb->data);
389 return eff_len;
391 else
392 #endif
394 error = copy_to_user(buff,skb->data,eff_len) ? -EFAULT : 0;
395 if (!vcc->dev->ops->free_rx_skb) kfree_skb(skb);
396 else vcc->dev->ops->free_rx_skb(vcc, skb);
398 return error ? error : eff_len;
402 int atm_sendmsg(struct socket *sock,struct msghdr *m,int total_len,
403 struct scm_cookie *scm)
405 struct atm_vcc *vcc;
406 struct sk_buff *skb;
407 int eff,error;
409 const void *buff;
410 int size;
412 if (sock->state != SS_CONNECTED) return -ENOTCONN;
413 if (m->msg_name) return -EISCONN;
414 if (m->msg_iovlen != 1) return -ENOSYS; /* fix this later @@@ */
415 buff = m->msg_iov->iov_base;
416 size = m->msg_iov->iov_len;
417 vcc = ATM_SD(sock);
418 if (vcc->flags & (ATM_VF_RELEASED | ATM_VF_CLOSE)) return vcc->reply;
419 if (!(vcc->flags & ATM_VF_READY)) return -EPIPE;
420 if (!size) return 0;
421 /* verify_area is done by net/socket.c */
422 #ifdef CONFIG_MMU_HACKS
423 if ((vcc->flags & ATM_VF_SCTX) && vcc->dev->ops->sg_send &&
424 vcc->dev->ops->sg_send(vcc,(unsigned long) buff,size)) {
425 int res,max_iov;
427 max_iov = 2+size/PAGE_SIZE;
429 * Doesn't use alloc_tx yet - this will change later. @@@
431 while (!(skb = alloc_skb(sizeof(struct iovec)*max_iov,
432 GFP_KERNEL))) {
433 if (m->msg_flags & MSG_DONTWAIT) return -EAGAIN;
434 interruptible_sleep_on(&vcc->wsleep);
435 if (signal_pending(current)) return -ERESTARTSYS;
437 skb_put(skb,size);
438 res = lock_user((unsigned long) buff,size,max_iov,
439 (struct iovec *) skb->data);
440 if (res < 0) {
441 kfree_skb(skb);
442 if (res != -EAGAIN) return res;
444 else {
445 DPRINTK("res is %d\n",res);
446 DPRINTK("Asnd %d += %d\n",vcc->tx_inuse,skb->truesize);
447 atomic_add(skb->truesize+ATM_PDU_OVHD,&vcc->tx_inuse);
448 ATM_SKB(skb)->iovcnt = res;
449 error = vcc->dev->ops->send(vcc,skb);
450 /* FIXME: security: may send up to 3 "garbage" bytes */
451 return error ? error : size;
454 #endif
455 eff = (size+3) & ~3; /* align to word boundary */
456 while (!(skb = vcc->alloc_tx(vcc,eff))) {
457 if (m->msg_flags & MSG_DONTWAIT) return -EAGAIN;
458 interruptible_sleep_on(&vcc->wsleep);
459 if (signal_pending(current)) return -ERESTARTSYS;
460 if (vcc->flags & (ATM_VF_RELEASED | ATM_VF_CLOSE))
461 return vcc->reply;
462 if (!(vcc->flags & ATM_VF_READY)) return -EPIPE;
464 ATM_SKB(skb)->iovcnt = 0;
465 ATM_SKB(skb)->atm_options = vcc->atm_options;
466 if (copy_from_user(skb_put(skb,size),buff,size)) {
467 kfree_skb(skb);
468 return -EFAULT;
470 if (eff != size) memset(skb->data+size,0,eff-size);
471 error = vcc->dev->ops->send(vcc,skb);
472 return error ? error : size;
476 unsigned int atm_poll(struct file *file,struct socket *sock,poll_table *wait)
478 struct atm_vcc *vcc;
479 unsigned int mask;
481 vcc = ATM_SD(sock);
482 poll_wait(file,&vcc->sleep,wait);
483 poll_wait(file,&vcc->wsleep,wait);
484 mask = 0;
485 if (skb_peek(&vcc->recvq) || skb_peek(&vcc->listenq))
486 mask |= POLLIN | POLLRDNORM;
487 if (vcc->flags & (ATM_VF_RELEASED | ATM_VF_CLOSE)) mask |= POLLHUP;
488 if (sock->state != SS_CONNECTING) {
489 if (vcc->qos.txtp.traffic_class != ATM_NONE &&
490 vcc->qos.txtp.max_sdu+atomic_read(&vcc->tx_inuse)+
491 ATM_PDU_OVHD <= vcc->tx_quota)
492 mask |= POLLOUT | POLLWRNORM;
494 else if (vcc->reply != WAITING) {
495 mask |= POLLOUT | POLLWRNORM;
496 if (vcc->reply) mask |= POLLERR;
498 return mask;
502 static int fetch_stats(struct atm_dev *dev,struct atm_dev_stats *arg,int zero)
504 unsigned long flags;
505 int error;
507 error = 0;
508 save_flags(flags);
509 cli();
510 if (arg)
511 error = copy_to_user(arg,&dev->stats,
512 sizeof(struct atm_dev_stats));
513 if (zero && !error)
514 memset(&dev->stats,0,sizeof(struct atm_dev_stats));
515 restore_flags(flags);
516 return error ? -EFAULT : 0;
520 int atm_ioctl(struct socket *sock,unsigned int cmd,unsigned long arg)
522 struct atm_dev *dev;
523 struct atm_vcc *vcc;
524 int *tmp_buf;
525 void *buf;
526 int error,len,size,number;
528 vcc = ATM_SD(sock);
529 switch (cmd) {
530 case TIOCOUTQ:
531 if (sock->state != SS_CONNECTED ||
532 !(vcc->flags & ATM_VF_READY)) return -EINVAL;
533 return put_user(vcc->tx_quota-
534 atomic_read(&vcc->tx_inuse)-ATM_PDU_OVHD,
535 (int *) arg) ? -EFAULT : 0;
536 case TIOCINQ:
538 struct sk_buff *skb;
540 if (sock->state != SS_CONNECTED)
541 return -EINVAL;
542 skb = skb_peek(&vcc->recvq);
543 return put_user(skb ? skb->len : 0,(int *) arg)
544 ? -EFAULT : 0;
546 case ATM_GETNAMES:
547 if (get_user(buf,
548 &((struct atm_iobuf *) arg)->buffer))
549 return -EFAULT;
550 if (get_user(len,
551 &((struct atm_iobuf *) arg)->length))
552 return -EFAULT;
553 size = 0;
554 for (dev = atm_devs; dev; dev = dev->next)
555 size += sizeof(int);
556 if (size > len) return -E2BIG;
557 tmp_buf = kmalloc(size,GFP_KERNEL);
558 if (!tmp_buf) return -ENOMEM;
559 for (dev = atm_devs; dev; dev = dev->next)
560 *tmp_buf++ = dev->number;
561 if (copy_to_user(buf,(char *) tmp_buf-size,size))
562 return -EFAULT;
563 return put_user(size,
564 &((struct atm_iobuf *) arg)->length) ? -EFAULT : 0;
565 case SIOCGSTAMP: /* borrowed from IP */
566 if (!vcc->timestamp.tv_sec) return -ENOENT;
567 vcc->timestamp.tv_sec += vcc->timestamp.tv_usec/1000000;
568 vcc->timestamp.tv_usec %= 1000000;
569 return copy_to_user((void *) arg,&vcc->timestamp,
570 sizeof(struct timeval)) ? -EFAULT : 0;
571 case ATM_SETSC:
572 if (arg & ~(ATM_VF_SCRX | ATM_VF_SCTX)) return -EINVAL;
573 /* @@@ race condition - should split flags into
574 "volatile" and non-volatile part */
575 vcc->flags = (vcc->flags & ~(ATM_VF_SCRX |
576 ATM_VF_SCTX)) | arg;
577 return 0;
578 case ATMSIGD_CTRL:
579 if (!capable(CAP_NET_ADMIN)) return -EPERM;
580 error = sigd_attach(vcc);
581 if (!error) sock->state = SS_CONNECTED;
582 return error;
583 #ifdef WE_DONT_SUPPORT_P2MP_YET
584 case ATM_CREATE_LEAF:
586 struct socket *session;
588 if (!(session = sockfd_lookup(arg,&error)))
589 return error;
590 if (sock->ops->family != PF_ATMSVC ||
591 session->ops->family != PF_ATMSVC)
592 return -EPROTOTYPE;
593 return create_leaf(sock,session);
595 #endif
596 #ifdef CONFIG_ATM_CLIP
597 case SIOCMKCLIP:
598 if (!capable(CAP_NET_ADMIN)) return -EPERM;
599 return clip_create(arg);
600 case ATMARPD_CTRL:
601 if (!capable(CAP_NET_ADMIN)) return -EPERM;
602 error = atm_init_atmarp(vcc);
603 if (!error) sock->state = SS_CONNECTED;
604 return error;
605 case ATMARP_MKIP:
606 if (!capable(CAP_NET_ADMIN)) return -EPERM;
607 return clip_mkip(vcc,arg);
608 case ATMARP_SETENTRY:
609 if (!capable(CAP_NET_ADMIN)) return -EPERM;
610 return clip_setentry(vcc,arg);
611 case ATMARP_ENCAP:
612 if (!capable(CAP_NET_ADMIN)) return -EPERM;
613 return clip_encap(vcc,arg);
614 #endif
615 #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
616 case ATMLEC_CTRL:
617 if (!capable(CAP_NET_ADMIN)) return -EPERM;
618 if (atm_lane_ops.lecd_attach == NULL)
619 atm_lane_init();
620 if (atm_lane_ops.lecd_attach == NULL) /* try again */
621 return -ENOSYS;
622 error = atm_lane_ops.lecd_attach(vcc, (int)arg);
623 if (error >= 0) sock->state = SS_CONNECTED;
624 return error;
625 case ATMLEC_MCAST:
626 if (!capable(CAP_NET_ADMIN)) return -EPERM;
627 return atm_lane_ops.mcast_attach(vcc, (int)arg);
628 case ATMLEC_DATA:
629 if (!capable(CAP_NET_ADMIN)) return -EPERM;
630 return atm_lane_ops.vcc_attach(vcc, (void*)arg);
631 #endif
632 #if defined(CONFIG_ATM_MPOA) || defined(CONFIG_ATM_MPOA_MODULE)
633 case ATMMPC_CTRL:
634 if (!capable(CAP_NET_ADMIN)) return -EPERM;
635 if (atm_mpoa_ops.mpoad_attach == NULL)
636 atm_mpoa_init();
637 if (atm_mpoa_ops.mpoad_attach == NULL) /* try again */
638 return -ENOSYS;
639 error = atm_mpoa_ops.mpoad_attach(vcc, (int)arg);
640 if (error >= 0) sock->state = SS_CONNECTED;
641 return error;
642 case ATMMPC_DATA:
643 if (!capable(CAP_NET_ADMIN)) return -EPERM;
644 return atm_mpoa_ops.vcc_attach(vcc, arg);
645 #endif
646 #if defined(CONFIG_ATM_TCP) || defined(CONFIG_ATM_TCP_MODULE)
647 case SIOCSIFATMTCP:
648 if (!capable(CAP_NET_ADMIN)) return -EPERM;
649 if (!atm_tcp_ops.attach) return -ENOPKG;
650 error = atm_tcp_ops.attach(vcc,(int) arg);
651 if (error >= 0) sock->state = SS_CONNECTED;
652 return error;
653 case ATMTCP_CREATE:
654 if (!capable(CAP_NET_ADMIN)) return -EPERM;
655 if (!atm_tcp_ops.create_persistent) return -ENOPKG;
656 return atm_tcp_ops.create_persistent((int) arg);
657 case ATMTCP_REMOVE:
658 if (!capable(CAP_NET_ADMIN)) return -EPERM;
659 if (!atm_tcp_ops.remove_persistent) return -ENOPKG;
660 return atm_tcp_ops.remove_persistent((int) arg);
661 #endif
662 default:
663 break;
665 if (get_user(buf,&((struct atmif_sioc *) arg)->arg)) return -EFAULT;
666 if (get_user(len,&((struct atmif_sioc *) arg)->length)) return -EFAULT;
667 if (get_user(number,&((struct atmif_sioc *) arg)->number))
668 return -EFAULT;
669 if (!(dev = atm_find_dev(number))) return -ENODEV;
670 size = 0;
671 switch (cmd) {
672 case ATM_GETTYPE:
673 size = strlen(dev->type)+1;
674 if (copy_to_user(buf,dev->type,size)) return -EFAULT;
675 break;
676 case ATM_GETESI:
677 size = ESI_LEN;
678 if (copy_to_user(buf,dev->esi,size)) return -EFAULT;
679 break;
680 case ATM_SETESI:
682 int i;
684 for (i = 0; i < ESI_LEN; i++)
685 if (dev->esi[i]) return -EEXIST;
687 /* fall through */
688 case ATM_SETESIF:
690 unsigned char esi[ESI_LEN];
692 if (!capable(CAP_NET_ADMIN)) return -EPERM;
693 if (copy_from_user(esi,buf,ESI_LEN))
694 return -EFAULT;
695 memcpy(dev->esi,esi,ESI_LEN);
696 return ESI_LEN;
698 case ATM_GETSTATZ:
699 if (!capable(CAP_NET_ADMIN)) return -EPERM;
700 /* fall through */
701 case ATM_GETSTAT:
702 size = sizeof(struct atm_dev_stats);
703 error = fetch_stats(dev,buf,cmd == ATM_GETSTATZ);
704 if (error) return error;
705 break;
706 case ATM_GETCIRANGE:
707 size = sizeof(struct atm_cirange);
708 if (copy_to_user(buf,&dev->ci_range,size))
709 return -EFAULT;
710 break;
711 case ATM_GETLINKRATE:
712 size = sizeof(int);
713 if (copy_to_user(buf,&dev->link_rate,size))
714 return -EFAULT;
715 break;
716 case ATM_RSTADDR:
717 if (!capable(CAP_NET_ADMIN)) return -EPERM;
718 reset_addr(dev);
719 break;
720 case ATM_ADDADDR:
721 case ATM_DELADDR:
722 if (!capable(CAP_NET_ADMIN)) return -EPERM;
724 struct sockaddr_atmsvc addr;
726 if (copy_from_user(&addr,buf,sizeof(addr)))
727 return -EFAULT;
728 if (cmd == ATM_ADDADDR)
729 return add_addr(dev,&addr);
730 else return del_addr(dev,&addr);
732 case ATM_GETADDR:
733 size = get_addr(dev,buf,len);
734 if (size < 0) return size;
735 /* may return 0, but later on size == 0 means "don't
736 write the length" */
737 return put_user(size,
738 &((struct atmif_sioc *) arg)->length) ? -EFAULT : 0;
739 case ATM_SETCIRANGE:
740 case SONET_GETSTATZ:
741 case SONET_SETDIAG:
742 case SONET_CLRDIAG:
743 case SONET_SETFRAMING:
744 if (!capable(CAP_NET_ADMIN)) return -EPERM;
745 /* fall through */
746 default:
747 if (!dev->ops->ioctl) return -EINVAL;
748 size = dev->ops->ioctl(dev,cmd,buf);
749 if (size < 0) return size;
751 if (!size) return 0;
752 return put_user(size,&((struct atmif_sioc *) arg)->length) ?
753 -EFAULT : 0;
757 int atm_change_qos(struct atm_vcc *vcc,struct atm_qos *qos)
759 if (!vcc->dev->ops->change_qos) return -EOPNOTSUPP;
760 if (vcc->family == AF_ATMPVC)
761 return vcc->dev->ops->change_qos(vcc,qos,ATM_MF_SET);
762 return svc_change_qos(vcc,qos);
766 static int check_tp(struct atm_trafprm *tp)
768 /* @@@ Should be merged with adjust_tp */
769 if (!tp->traffic_class || tp->traffic_class == ATM_ANYCLASS) return 0;
770 if (tp->traffic_class != ATM_UBR && !tp->min_pcr && !tp->pcr &&
771 !tp->max_pcr) return -EINVAL;
772 if (tp->min_pcr == ATM_MAX_PCR) return -EINVAL;
773 if (tp->min_pcr && tp->max_pcr && tp->max_pcr != ATM_MAX_PCR &&
774 tp->min_pcr > tp->max_pcr) return -EINVAL;
776 * We allow pcr to be outside [min_pcr,max_pcr], because later
777 * adjustment may still push it in the valid range.
779 return 0;
783 static int check_qos(struct atm_qos *qos)
785 int error;
787 if (!qos->txtp.traffic_class && !qos->rxtp.traffic_class)
788 return -EINVAL;
789 if (qos->txtp.traffic_class != qos->rxtp.traffic_class &&
790 qos->txtp.traffic_class && qos->rxtp.traffic_class &&
791 qos->txtp.traffic_class != ATM_ANYCLASS &&
792 qos->rxtp.traffic_class != ATM_ANYCLASS) return -EINVAL;
793 error = check_tp(&qos->txtp);
794 if (error) return error;
795 return check_tp(&qos->rxtp);
799 static int atm_do_setsockopt(struct socket *sock,int level,int optname,
800 void *optval,int optlen)
802 struct atm_vcc *vcc;
803 unsigned long value;
804 int error;
806 vcc = ATM_SD(sock);
807 switch (optname) {
808 case SO_SNDBUF:
809 if (get_user(value,(unsigned long *) optval))
810 return -EFAULT;
811 if (!value) value = ATM_TXBQ_DEF;
812 if (value < ATM_TXBQ_MIN) value = ATM_TXBQ_MIN;
813 if (value > ATM_TXBQ_MAX) value = ATM_TXBQ_MAX;
814 vcc->tx_quota = value;
815 return 0;
816 case SO_RCVBUF:
817 if (get_user(value,(unsigned long *) optval))
818 return -EFAULT;
819 if (!value) value = ATM_RXBQ_DEF;
820 if (value < ATM_RXBQ_MIN) value = ATM_RXBQ_MIN;
821 if (value > ATM_RXBQ_MAX) value = ATM_RXBQ_MAX;
822 vcc->rx_quota = value;
823 return 0;
824 case SO_ATMQOS:
826 struct atm_qos qos;
828 if (copy_from_user(&qos,optval,sizeof(qos)))
829 return -EFAULT;
830 error = check_qos(&qos);
831 if (error) return error;
832 if (sock->state == SS_CONNECTED)
833 return atm_change_qos(vcc,&qos);
834 if (sock->state != SS_UNCONNECTED)
835 return -EBADFD;
836 vcc->qos = qos;
837 vcc->flags |= ATM_VF_HASQOS;
838 return 0;
840 case SO_SETCLP:
841 if (get_user(value,(unsigned long *) optval))
842 return -EFAULT;
843 if (value) vcc->atm_options |= ATM_ATMOPT_CLP;
844 else vcc->atm_options &= ~ATM_ATMOPT_CLP;
845 return 0;
846 default:
847 if (level == SOL_SOCKET) return -EINVAL;
848 break;
850 if (!vcc->dev || !vcc->dev->ops->setsockopt) return -EINVAL;
851 return vcc->dev->ops->setsockopt(vcc,level,optname,optval,optlen);
855 static int atm_do_getsockopt(struct socket *sock,int level,int optname,
856 void *optval,int optlen)
858 struct atm_vcc *vcc;
860 vcc = ATM_SD(sock);
861 switch (optname) {
862 case SO_SNDBUF:
863 return put_user(vcc->tx_quota,(unsigned long *) optval)
864 ? -EFAULT : 0;
865 case SO_RCVBUF:
866 return put_user(vcc->rx_quota,(unsigned long *) optval)
867 ? -EFAULT : 0;
868 case SO_BCTXOPT:
869 /* fall through */
870 case SO_BCRXOPT:
871 printk(KERN_WARNING "Warning: SO_BCTXOPT/SO_BCRXOPT "
872 "are obsolete\n");
873 break;
874 case SO_ATMQOS:
875 if (!(vcc->flags & ATM_VF_HASQOS)) return -EINVAL;
876 return copy_to_user(optval,&vcc->qos,sizeof(vcc->qos)) ?
877 -EFAULT : 0;
878 case SO_SETCLP:
879 return put_user(vcc->atm_options & ATM_ATMOPT_CLP ? 1 :
880 0,(unsigned long *) optval) ? -EFAULT : 0;
881 case SO_ATMPVC:
883 struct sockaddr_atmpvc pvc;
885 if (!vcc->dev || !(vcc->flags & ATM_VF_ADDR))
886 return -ENOTCONN;
887 pvc.sap_family = AF_ATMPVC;
888 pvc.sap_addr.itf = vcc->dev->number;
889 pvc.sap_addr.vpi = vcc->vpi;
890 pvc.sap_addr.vci = vcc->vci;
891 return copy_to_user(optval,&pvc,sizeof(pvc)) ?
892 -EFAULT : 0;
894 default:
895 if (level == SOL_SOCKET) return -EINVAL;
896 break;
898 if (!vcc->dev || !vcc->dev->ops->getsockopt) return -EINVAL;
899 return vcc->dev->ops->getsockopt(vcc,level,optname,optval,optlen);
903 int atm_setsockopt(struct socket *sock,int level,int optname,char *optval,
904 int optlen)
906 if (__SO_LEVEL_MATCH(optname, level) && optlen != __SO_SIZE(optname))
907 return -EINVAL;
908 return atm_do_setsockopt(sock,level,optname,optval,optlen);
912 int atm_getsockopt(struct socket *sock,int level,int optname,
913 char *optval,int *optlen)
915 int len;
917 if (get_user(len,optlen)) return -EFAULT;
918 if (__SO_LEVEL_MATCH(optname, level) && len != __SO_SIZE(optname))
919 return -EINVAL;
920 return atm_do_getsockopt(sock,level,optname,optval,len);