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