1*7c657876SArnaldo Carvalho de Melo /* 2*7c657876SArnaldo Carvalho de Melo * net/dccp/ccid.c 3*7c657876SArnaldo Carvalho de Melo * 4*7c657876SArnaldo Carvalho de Melo * An implementation of the DCCP protocol 5*7c657876SArnaldo Carvalho de Melo * Arnaldo Carvalho de Melo <acme@conectiva.com.br> 6*7c657876SArnaldo Carvalho de Melo * 7*7c657876SArnaldo Carvalho de Melo * CCID infrastructure 8*7c657876SArnaldo Carvalho de Melo * 9*7c657876SArnaldo Carvalho de Melo * This program is free software; you can redistribute it and/or modify it 10*7c657876SArnaldo Carvalho de Melo * under the terms of the GNU General Public License version 2 as 11*7c657876SArnaldo Carvalho de Melo * published by the Free Software Foundation. 12*7c657876SArnaldo Carvalho de Melo */ 13*7c657876SArnaldo Carvalho de Melo 14*7c657876SArnaldo Carvalho de Melo #include "ccid.h" 15*7c657876SArnaldo Carvalho de Melo 16*7c657876SArnaldo Carvalho de Melo static struct ccid *ccids[CCID_MAX]; 17*7c657876SArnaldo Carvalho de Melo #if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT) 18*7c657876SArnaldo Carvalho de Melo static atomic_t ccids_lockct = ATOMIC_INIT(0); 19*7c657876SArnaldo Carvalho de Melo static DEFINE_SPINLOCK(ccids_lock); 20*7c657876SArnaldo Carvalho de Melo 21*7c657876SArnaldo Carvalho de Melo /* 22*7c657876SArnaldo Carvalho de Melo * The strategy is: modifications ccids vector are short, do not sleep and 23*7c657876SArnaldo Carvalho de Melo * veeery rare, but read access should be free of any exclusive locks. 24*7c657876SArnaldo Carvalho de Melo */ 25*7c657876SArnaldo Carvalho de Melo static void ccids_write_lock(void) 26*7c657876SArnaldo Carvalho de Melo { 27*7c657876SArnaldo Carvalho de Melo spin_lock(&ccids_lock); 28*7c657876SArnaldo Carvalho de Melo while (atomic_read(&ccids_lockct) != 0) { 29*7c657876SArnaldo Carvalho de Melo spin_unlock(&ccids_lock); 30*7c657876SArnaldo Carvalho de Melo yield(); 31*7c657876SArnaldo Carvalho de Melo spin_lock(&ccids_lock); 32*7c657876SArnaldo Carvalho de Melo } 33*7c657876SArnaldo Carvalho de Melo } 34*7c657876SArnaldo Carvalho de Melo 35*7c657876SArnaldo Carvalho de Melo static inline void ccids_write_unlock(void) 36*7c657876SArnaldo Carvalho de Melo { 37*7c657876SArnaldo Carvalho de Melo spin_unlock(&ccids_lock); 38*7c657876SArnaldo Carvalho de Melo } 39*7c657876SArnaldo Carvalho de Melo 40*7c657876SArnaldo Carvalho de Melo static inline void ccids_read_lock(void) 41*7c657876SArnaldo Carvalho de Melo { 42*7c657876SArnaldo Carvalho de Melo atomic_inc(&ccids_lockct); 43*7c657876SArnaldo Carvalho de Melo spin_unlock_wait(&ccids_lock); 44*7c657876SArnaldo Carvalho de Melo } 45*7c657876SArnaldo Carvalho de Melo 46*7c657876SArnaldo Carvalho de Melo static inline void ccids_read_unlock(void) 47*7c657876SArnaldo Carvalho de Melo { 48*7c657876SArnaldo Carvalho de Melo atomic_dec(&ccids_lockct); 49*7c657876SArnaldo Carvalho de Melo } 50*7c657876SArnaldo Carvalho de Melo 51*7c657876SArnaldo Carvalho de Melo #else 52*7c657876SArnaldo Carvalho de Melo #define ccids_write_lock() do { } while(0) 53*7c657876SArnaldo Carvalho de Melo #define ccids_write_unlock() do { } while(0) 54*7c657876SArnaldo Carvalho de Melo #define ccids_read_lock() do { } while(0) 55*7c657876SArnaldo Carvalho de Melo #define ccids_read_unlock() do { } while(0) 56*7c657876SArnaldo Carvalho de Melo #endif 57*7c657876SArnaldo Carvalho de Melo 58*7c657876SArnaldo Carvalho de Melo int ccid_register(struct ccid *ccid) 59*7c657876SArnaldo Carvalho de Melo { 60*7c657876SArnaldo Carvalho de Melo int err; 61*7c657876SArnaldo Carvalho de Melo 62*7c657876SArnaldo Carvalho de Melo if (ccid->ccid_init == NULL) 63*7c657876SArnaldo Carvalho de Melo return -1; 64*7c657876SArnaldo Carvalho de Melo 65*7c657876SArnaldo Carvalho de Melo ccids_write_lock(); 66*7c657876SArnaldo Carvalho de Melo err = -EEXIST; 67*7c657876SArnaldo Carvalho de Melo if (ccids[ccid->ccid_id] == NULL) { 68*7c657876SArnaldo Carvalho de Melo ccids[ccid->ccid_id] = ccid; 69*7c657876SArnaldo Carvalho de Melo err = 0; 70*7c657876SArnaldo Carvalho de Melo } 71*7c657876SArnaldo Carvalho de Melo ccids_write_unlock(); 72*7c657876SArnaldo Carvalho de Melo if (err == 0) 73*7c657876SArnaldo Carvalho de Melo pr_info("CCID: Registered CCID %d (%s)\n", 74*7c657876SArnaldo Carvalho de Melo ccid->ccid_id, ccid->ccid_name); 75*7c657876SArnaldo Carvalho de Melo return err; 76*7c657876SArnaldo Carvalho de Melo } 77*7c657876SArnaldo Carvalho de Melo 78*7c657876SArnaldo Carvalho de Melo EXPORT_SYMBOL_GPL(ccid_register); 79*7c657876SArnaldo Carvalho de Melo 80*7c657876SArnaldo Carvalho de Melo int ccid_unregister(struct ccid *ccid) 81*7c657876SArnaldo Carvalho de Melo { 82*7c657876SArnaldo Carvalho de Melo ccids_write_lock(); 83*7c657876SArnaldo Carvalho de Melo ccids[ccid->ccid_id] = NULL; 84*7c657876SArnaldo Carvalho de Melo ccids_write_unlock(); 85*7c657876SArnaldo Carvalho de Melo pr_info("CCID: Unregistered CCID %d (%s)\n", 86*7c657876SArnaldo Carvalho de Melo ccid->ccid_id, ccid->ccid_name); 87*7c657876SArnaldo Carvalho de Melo return 0; 88*7c657876SArnaldo Carvalho de Melo } 89*7c657876SArnaldo Carvalho de Melo 90*7c657876SArnaldo Carvalho de Melo EXPORT_SYMBOL_GPL(ccid_unregister); 91*7c657876SArnaldo Carvalho de Melo 92*7c657876SArnaldo Carvalho de Melo struct ccid *ccid_init(unsigned char id, struct sock *sk) 93*7c657876SArnaldo Carvalho de Melo { 94*7c657876SArnaldo Carvalho de Melo struct ccid *ccid; 95*7c657876SArnaldo Carvalho de Melo 96*7c657876SArnaldo Carvalho de Melo #ifdef CONFIG_KMOD 97*7c657876SArnaldo Carvalho de Melo if (ccids[id] == NULL) 98*7c657876SArnaldo Carvalho de Melo request_module("net-dccp-ccid-%d", id); 99*7c657876SArnaldo Carvalho de Melo #endif 100*7c657876SArnaldo Carvalho de Melo ccids_read_lock(); 101*7c657876SArnaldo Carvalho de Melo 102*7c657876SArnaldo Carvalho de Melo ccid = ccids[id]; 103*7c657876SArnaldo Carvalho de Melo if (ccid == NULL) 104*7c657876SArnaldo Carvalho de Melo goto out; 105*7c657876SArnaldo Carvalho de Melo 106*7c657876SArnaldo Carvalho de Melo if (!try_module_get(ccid->ccid_owner)) 107*7c657876SArnaldo Carvalho de Melo goto out_err; 108*7c657876SArnaldo Carvalho de Melo 109*7c657876SArnaldo Carvalho de Melo if (ccid->ccid_init(sk) != 0) 110*7c657876SArnaldo Carvalho de Melo goto out_module_put; 111*7c657876SArnaldo Carvalho de Melo out: 112*7c657876SArnaldo Carvalho de Melo ccids_read_unlock(); 113*7c657876SArnaldo Carvalho de Melo return ccid; 114*7c657876SArnaldo Carvalho de Melo out_module_put: 115*7c657876SArnaldo Carvalho de Melo module_put(ccid->ccid_owner); 116*7c657876SArnaldo Carvalho de Melo out_err: 117*7c657876SArnaldo Carvalho de Melo ccid = NULL; 118*7c657876SArnaldo Carvalho de Melo goto out; 119*7c657876SArnaldo Carvalho de Melo } 120*7c657876SArnaldo Carvalho de Melo 121*7c657876SArnaldo Carvalho de Melo EXPORT_SYMBOL_GPL(ccid_init); 122*7c657876SArnaldo Carvalho de Melo 123*7c657876SArnaldo Carvalho de Melo void ccid_exit(struct ccid *ccid, struct sock *sk) 124*7c657876SArnaldo Carvalho de Melo { 125*7c657876SArnaldo Carvalho de Melo if (ccid == NULL) 126*7c657876SArnaldo Carvalho de Melo return; 127*7c657876SArnaldo Carvalho de Melo 128*7c657876SArnaldo Carvalho de Melo ccids_read_lock(); 129*7c657876SArnaldo Carvalho de Melo 130*7c657876SArnaldo Carvalho de Melo if (ccids[ccid->ccid_id] != NULL) { 131*7c657876SArnaldo Carvalho de Melo if (ccid->ccid_exit != NULL) 132*7c657876SArnaldo Carvalho de Melo ccid->ccid_exit(sk); 133*7c657876SArnaldo Carvalho de Melo module_put(ccid->ccid_owner); 134*7c657876SArnaldo Carvalho de Melo } 135*7c657876SArnaldo Carvalho de Melo 136*7c657876SArnaldo Carvalho de Melo ccids_read_unlock(); 137*7c657876SArnaldo Carvalho de Melo } 138*7c657876SArnaldo Carvalho de Melo 139*7c657876SArnaldo Carvalho de Melo EXPORT_SYMBOL_GPL(ccid_exit); 140