0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include <linux/slab.h>
0012
0013 #include "ccid.h"
0014 #include "ccids/lib/tfrc.h"
0015
0016 static struct ccid_operations *ccids[] = {
0017 &ccid2_ops,
0018 #ifdef CONFIG_IP_DCCP_CCID3
0019 &ccid3_ops,
0020 #endif
0021 };
0022
0023 static struct ccid_operations *ccid_by_number(const u8 id)
0024 {
0025 int i;
0026
0027 for (i = 0; i < ARRAY_SIZE(ccids); i++)
0028 if (ccids[i]->ccid_id == id)
0029 return ccids[i];
0030 return NULL;
0031 }
0032
0033
0034 bool ccid_support_check(u8 const *ccid_array, u8 array_len)
0035 {
0036 while (array_len > 0)
0037 if (ccid_by_number(ccid_array[--array_len]) == NULL)
0038 return false;
0039 return true;
0040 }
0041
0042
0043
0044
0045
0046
0047
0048
0049 int ccid_get_builtin_ccids(u8 **ccid_array, u8 *array_len)
0050 {
0051 *ccid_array = kmalloc(ARRAY_SIZE(ccids), gfp_any());
0052 if (*ccid_array == NULL)
0053 return -ENOBUFS;
0054
0055 for (*array_len = 0; *array_len < ARRAY_SIZE(ccids); *array_len += 1)
0056 (*ccid_array)[*array_len] = ccids[*array_len]->ccid_id;
0057 return 0;
0058 }
0059
0060 int ccid_getsockopt_builtin_ccids(struct sock *sk, int len,
0061 char __user *optval, int __user *optlen)
0062 {
0063 u8 *ccid_array, array_len;
0064 int err = 0;
0065
0066 if (ccid_get_builtin_ccids(&ccid_array, &array_len))
0067 return -ENOBUFS;
0068
0069 if (put_user(array_len, optlen))
0070 err = -EFAULT;
0071 else if (len > 0 && copy_to_user(optval, ccid_array,
0072 len > array_len ? array_len : len))
0073 err = -EFAULT;
0074
0075 kfree(ccid_array);
0076 return err;
0077 }
0078
0079 static __printf(3, 4) struct kmem_cache *ccid_kmem_cache_create(int obj_size, char *slab_name_fmt, const char *fmt,...)
0080 {
0081 struct kmem_cache *slab;
0082 va_list args;
0083
0084 va_start(args, fmt);
0085 vsnprintf(slab_name_fmt, CCID_SLAB_NAME_LENGTH, fmt, args);
0086 va_end(args);
0087
0088 slab = kmem_cache_create(slab_name_fmt, sizeof(struct ccid) + obj_size, 0,
0089 SLAB_HWCACHE_ALIGN, NULL);
0090 return slab;
0091 }
0092
0093 static void ccid_kmem_cache_destroy(struct kmem_cache *slab)
0094 {
0095 kmem_cache_destroy(slab);
0096 }
0097
0098 static int __init ccid_activate(struct ccid_operations *ccid_ops)
0099 {
0100 int err = -ENOBUFS;
0101
0102 ccid_ops->ccid_hc_rx_slab =
0103 ccid_kmem_cache_create(ccid_ops->ccid_hc_rx_obj_size,
0104 ccid_ops->ccid_hc_rx_slab_name,
0105 "ccid%u_hc_rx_sock",
0106 ccid_ops->ccid_id);
0107 if (ccid_ops->ccid_hc_rx_slab == NULL)
0108 goto out;
0109
0110 ccid_ops->ccid_hc_tx_slab =
0111 ccid_kmem_cache_create(ccid_ops->ccid_hc_tx_obj_size,
0112 ccid_ops->ccid_hc_tx_slab_name,
0113 "ccid%u_hc_tx_sock",
0114 ccid_ops->ccid_id);
0115 if (ccid_ops->ccid_hc_tx_slab == NULL)
0116 goto out_free_rx_slab;
0117
0118 pr_info("DCCP: Activated CCID %d (%s)\n",
0119 ccid_ops->ccid_id, ccid_ops->ccid_name);
0120 err = 0;
0121 out:
0122 return err;
0123 out_free_rx_slab:
0124 ccid_kmem_cache_destroy(ccid_ops->ccid_hc_rx_slab);
0125 ccid_ops->ccid_hc_rx_slab = NULL;
0126 goto out;
0127 }
0128
0129 static void ccid_deactivate(struct ccid_operations *ccid_ops)
0130 {
0131 ccid_kmem_cache_destroy(ccid_ops->ccid_hc_tx_slab);
0132 ccid_ops->ccid_hc_tx_slab = NULL;
0133 ccid_kmem_cache_destroy(ccid_ops->ccid_hc_rx_slab);
0134 ccid_ops->ccid_hc_rx_slab = NULL;
0135
0136 pr_info("DCCP: Deactivated CCID %d (%s)\n",
0137 ccid_ops->ccid_id, ccid_ops->ccid_name);
0138 }
0139
0140 struct ccid *ccid_new(const u8 id, struct sock *sk, bool rx)
0141 {
0142 struct ccid_operations *ccid_ops = ccid_by_number(id);
0143 struct ccid *ccid = NULL;
0144
0145 if (ccid_ops == NULL)
0146 goto out;
0147
0148 ccid = kmem_cache_alloc(rx ? ccid_ops->ccid_hc_rx_slab :
0149 ccid_ops->ccid_hc_tx_slab, gfp_any());
0150 if (ccid == NULL)
0151 goto out;
0152 ccid->ccid_ops = ccid_ops;
0153 if (rx) {
0154 memset(ccid + 1, 0, ccid_ops->ccid_hc_rx_obj_size);
0155 if (ccid->ccid_ops->ccid_hc_rx_init != NULL &&
0156 ccid->ccid_ops->ccid_hc_rx_init(ccid, sk) != 0)
0157 goto out_free_ccid;
0158 } else {
0159 memset(ccid + 1, 0, ccid_ops->ccid_hc_tx_obj_size);
0160 if (ccid->ccid_ops->ccid_hc_tx_init != NULL &&
0161 ccid->ccid_ops->ccid_hc_tx_init(ccid, sk) != 0)
0162 goto out_free_ccid;
0163 }
0164 out:
0165 return ccid;
0166 out_free_ccid:
0167 kmem_cache_free(rx ? ccid_ops->ccid_hc_rx_slab :
0168 ccid_ops->ccid_hc_tx_slab, ccid);
0169 ccid = NULL;
0170 goto out;
0171 }
0172
0173 void ccid_hc_rx_delete(struct ccid *ccid, struct sock *sk)
0174 {
0175 if (ccid != NULL) {
0176 if (ccid->ccid_ops->ccid_hc_rx_exit != NULL)
0177 ccid->ccid_ops->ccid_hc_rx_exit(sk);
0178 kmem_cache_free(ccid->ccid_ops->ccid_hc_rx_slab, ccid);
0179 }
0180 }
0181
0182 void ccid_hc_tx_delete(struct ccid *ccid, struct sock *sk)
0183 {
0184 if (ccid != NULL) {
0185 if (ccid->ccid_ops->ccid_hc_tx_exit != NULL)
0186 ccid->ccid_ops->ccid_hc_tx_exit(sk);
0187 kmem_cache_free(ccid->ccid_ops->ccid_hc_tx_slab, ccid);
0188 }
0189 }
0190
0191 int __init ccid_initialize_builtins(void)
0192 {
0193 int i, err = tfrc_lib_init();
0194
0195 if (err)
0196 return err;
0197
0198 for (i = 0; i < ARRAY_SIZE(ccids); i++) {
0199 err = ccid_activate(ccids[i]);
0200 if (err)
0201 goto unwind_registrations;
0202 }
0203 return 0;
0204
0205 unwind_registrations:
0206 while(--i >= 0)
0207 ccid_deactivate(ccids[i]);
0208 tfrc_lib_exit();
0209 return err;
0210 }
0211
0212 void ccid_cleanup_builtins(void)
0213 {
0214 int i;
0215
0216 for (i = 0; i < ARRAY_SIZE(ccids); i++)
0217 ccid_deactivate(ccids[i]);
0218 tfrc_lib_exit();
0219 }