xref: /linux/net/dccp/ccid.c (revision ddebc973c56b51b4e5d84d606f0430d81b895d67)
17c657876SArnaldo Carvalho de Melo /*
27c657876SArnaldo Carvalho de Melo  *  net/dccp/ccid.c
37c657876SArnaldo Carvalho de Melo  *
47c657876SArnaldo Carvalho de Melo  *  An implementation of the DCCP protocol
57c657876SArnaldo Carvalho de Melo  *  Arnaldo Carvalho de Melo <acme@conectiva.com.br>
67c657876SArnaldo Carvalho de Melo  *
77c657876SArnaldo Carvalho de Melo  *  CCID infrastructure
87c657876SArnaldo Carvalho de Melo  *
97c657876SArnaldo Carvalho de Melo  *	This program is free software; you can redistribute it and/or modify it
107c657876SArnaldo Carvalho de Melo  *	under the terms of the GNU General Public License version 2 as
117c657876SArnaldo Carvalho de Melo  *	published by the Free Software Foundation.
127c657876SArnaldo Carvalho de Melo  */
137c657876SArnaldo Carvalho de Melo 
147c657876SArnaldo Carvalho de Melo #include "ccid.h"
157c657876SArnaldo Carvalho de Melo 
16*ddebc973SGerrit Renker static struct ccid_operations *ccids[] = {
17*ddebc973SGerrit Renker 	&ccid2_ops,
18*ddebc973SGerrit Renker #ifdef CONFIG_IP_DCCP_CCID3
19*ddebc973SGerrit Renker 	&ccid3_ops,
20*ddebc973SGerrit Renker #endif
21*ddebc973SGerrit Renker };
22*ddebc973SGerrit Renker 
23*ddebc973SGerrit Renker static struct ccid_operations *ccid_by_number(const u8 id)
24*ddebc973SGerrit Renker {
25*ddebc973SGerrit Renker 	int i;
26*ddebc973SGerrit Renker 
27*ddebc973SGerrit Renker 	for (i = 0; i < ARRAY_SIZE(ccids); i++)
28*ddebc973SGerrit Renker 		if (ccids[i]->ccid_id == id)
29*ddebc973SGerrit Renker 			return ccids[i];
30*ddebc973SGerrit Renker 	return NULL;
31*ddebc973SGerrit Renker }
32*ddebc973SGerrit Renker 
33*ddebc973SGerrit Renker /* check that up to @array_len members in @ccid_array are supported */
34*ddebc973SGerrit Renker bool ccid_support_check(u8 const *ccid_array, u8 array_len)
35*ddebc973SGerrit Renker {
36*ddebc973SGerrit Renker 	while (array_len > 0)
37*ddebc973SGerrit Renker 		if (ccid_by_number(ccid_array[--array_len]) == NULL)
38*ddebc973SGerrit Renker 			return false;
39*ddebc973SGerrit Renker 	return true;
40*ddebc973SGerrit Renker }
41*ddebc973SGerrit Renker 
42*ddebc973SGerrit Renker /**
43*ddebc973SGerrit Renker  * ccid_get_builtin_ccids  -  Populate a list of built-in CCIDs
44*ddebc973SGerrit Renker  * @ccid_array: pointer to copy into
45*ddebc973SGerrit Renker  * @array_len: value to return length into
46*ddebc973SGerrit Renker  * This function allocates memory - caller must see that it is freed after use.
47*ddebc973SGerrit Renker  */
48*ddebc973SGerrit Renker int ccid_get_builtin_ccids(u8 **ccid_array, u8 *array_len)
49*ddebc973SGerrit Renker {
50*ddebc973SGerrit Renker 	*ccid_array = kmalloc(ARRAY_SIZE(ccids), gfp_any());
51*ddebc973SGerrit Renker 	if (*ccid_array == NULL)
52*ddebc973SGerrit Renker 		return -ENOBUFS;
53*ddebc973SGerrit Renker 
54*ddebc973SGerrit Renker 	for (*array_len = 0; *array_len < ARRAY_SIZE(ccids); *array_len += 1)
55*ddebc973SGerrit Renker 		(*ccid_array)[*array_len] = ccids[*array_len]->ccid_id;
56*ddebc973SGerrit Renker 	return 0;
57*ddebc973SGerrit Renker }
58*ddebc973SGerrit Renker 
59*ddebc973SGerrit Renker int ccid_getsockopt_builtin_ccids(struct sock *sk, int len,
60*ddebc973SGerrit Renker 				  char __user *optval, int __user *optlen)
61*ddebc973SGerrit Renker {
62*ddebc973SGerrit Renker 	u8 *ccid_array, array_len;
63*ddebc973SGerrit Renker 	int err = 0;
64*ddebc973SGerrit Renker 
65*ddebc973SGerrit Renker 	if (len < ARRAY_SIZE(ccids))
66*ddebc973SGerrit Renker 		return -EINVAL;
67*ddebc973SGerrit Renker 
68*ddebc973SGerrit Renker 	if (ccid_get_builtin_ccids(&ccid_array, &array_len))
69*ddebc973SGerrit Renker 		return -ENOBUFS;
70*ddebc973SGerrit Renker 
71*ddebc973SGerrit Renker 	if (put_user(array_len, optlen) ||
72*ddebc973SGerrit Renker 	    copy_to_user(optval, ccid_array, array_len))
73*ddebc973SGerrit Renker 		err = -EFAULT;
74*ddebc973SGerrit Renker 
75*ddebc973SGerrit Renker 	kfree(ccid_array);
76*ddebc973SGerrit Renker 	return err;
77*ddebc973SGerrit Renker }
78*ddebc973SGerrit Renker 
79*ddebc973SGerrit Renker #ifdef ___OLD_INTERFACE_TO_BE_REMOVED___
80d90ebcbfSGerrit Renker static u8 builtin_ccids[] = {
81d90ebcbfSGerrit Renker 	DCCPC_CCID2,		/* CCID2 is supported by default */
82d90ebcbfSGerrit Renker #if defined(CONFIG_IP_DCCP_CCID3) || defined(CONFIG_IP_DCCP_CCID3_MODULE)
83d90ebcbfSGerrit Renker 	DCCPC_CCID3,
84d90ebcbfSGerrit Renker #endif
85d90ebcbfSGerrit Renker };
86d90ebcbfSGerrit Renker 
8791f0ebf7SArnaldo Carvalho de Melo static struct ccid_operations *ccids[CCID_MAX];
887c657876SArnaldo Carvalho de Melo #if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT)
897c657876SArnaldo Carvalho de Melo static atomic_t ccids_lockct = ATOMIC_INIT(0);
907c657876SArnaldo Carvalho de Melo static DEFINE_SPINLOCK(ccids_lock);
917c657876SArnaldo Carvalho de Melo 
927c657876SArnaldo Carvalho de Melo /*
937c657876SArnaldo Carvalho de Melo  * The strategy is: modifications ccids vector are short, do not sleep and
947c657876SArnaldo Carvalho de Melo  * veeery rare, but read access should be free of any exclusive locks.
957c657876SArnaldo Carvalho de Melo  */
967c657876SArnaldo Carvalho de Melo static void ccids_write_lock(void)
977c657876SArnaldo Carvalho de Melo {
987c657876SArnaldo Carvalho de Melo 	spin_lock(&ccids_lock);
997c657876SArnaldo Carvalho de Melo 	while (atomic_read(&ccids_lockct) != 0) {
1007c657876SArnaldo Carvalho de Melo 		spin_unlock(&ccids_lock);
1017c657876SArnaldo Carvalho de Melo 		yield();
1027c657876SArnaldo Carvalho de Melo 		spin_lock(&ccids_lock);
1037c657876SArnaldo Carvalho de Melo 	}
1047c657876SArnaldo Carvalho de Melo }
1057c657876SArnaldo Carvalho de Melo 
1067c657876SArnaldo Carvalho de Melo static inline void ccids_write_unlock(void)
1077c657876SArnaldo Carvalho de Melo {
1087c657876SArnaldo Carvalho de Melo 	spin_unlock(&ccids_lock);
1097c657876SArnaldo Carvalho de Melo }
1107c657876SArnaldo Carvalho de Melo 
1117c657876SArnaldo Carvalho de Melo static inline void ccids_read_lock(void)
1127c657876SArnaldo Carvalho de Melo {
1137c657876SArnaldo Carvalho de Melo 	atomic_inc(&ccids_lockct);
114d725fdc8SOleg Nesterov 	smp_mb__after_atomic_inc();
1157c657876SArnaldo Carvalho de Melo 	spin_unlock_wait(&ccids_lock);
1167c657876SArnaldo Carvalho de Melo }
1177c657876SArnaldo Carvalho de Melo 
1187c657876SArnaldo Carvalho de Melo static inline void ccids_read_unlock(void)
1197c657876SArnaldo Carvalho de Melo {
1207c657876SArnaldo Carvalho de Melo 	atomic_dec(&ccids_lockct);
1217c657876SArnaldo Carvalho de Melo }
1227c657876SArnaldo Carvalho de Melo 
1237c657876SArnaldo Carvalho de Melo #else
1247c657876SArnaldo Carvalho de Melo #define ccids_write_lock() do { } while(0)
1257c657876SArnaldo Carvalho de Melo #define ccids_write_unlock() do { } while(0)
1267c657876SArnaldo Carvalho de Melo #define ccids_read_lock() do { } while(0)
1277c657876SArnaldo Carvalho de Melo #define ccids_read_unlock() do { } while(0)
1287c657876SArnaldo Carvalho de Melo #endif
129*ddebc973SGerrit Renker #endif /* ___OLD_INTERFACE_TO_BE_REMOVED___ */
1307c657876SArnaldo Carvalho de Melo 
131e18b890bSChristoph Lameter static struct kmem_cache *ccid_kmem_cache_create(int obj_size, const char *fmt,...)
1327c657876SArnaldo Carvalho de Melo {
133e18b890bSChristoph Lameter 	struct kmem_cache *slab;
13491f0ebf7SArnaldo Carvalho de Melo 	char slab_name_fmt[32], *slab_name;
13591f0ebf7SArnaldo Carvalho de Melo 	va_list args;
13691f0ebf7SArnaldo Carvalho de Melo 
13791f0ebf7SArnaldo Carvalho de Melo 	va_start(args, fmt);
13891f0ebf7SArnaldo Carvalho de Melo 	vsnprintf(slab_name_fmt, sizeof(slab_name_fmt), fmt, args);
13991f0ebf7SArnaldo Carvalho de Melo 	va_end(args);
14091f0ebf7SArnaldo Carvalho de Melo 
14191f0ebf7SArnaldo Carvalho de Melo 	slab_name = kstrdup(slab_name_fmt, GFP_KERNEL);
14291f0ebf7SArnaldo Carvalho de Melo 	if (slab_name == NULL)
14391f0ebf7SArnaldo Carvalho de Melo 		return NULL;
14491f0ebf7SArnaldo Carvalho de Melo 	slab = kmem_cache_create(slab_name, sizeof(struct ccid) + obj_size, 0,
14520c2df83SPaul Mundt 				 SLAB_HWCACHE_ALIGN, NULL);
14691f0ebf7SArnaldo Carvalho de Melo 	if (slab == NULL)
14791f0ebf7SArnaldo Carvalho de Melo 		kfree(slab_name);
14891f0ebf7SArnaldo Carvalho de Melo 	return slab;
14991f0ebf7SArnaldo Carvalho de Melo }
15091f0ebf7SArnaldo Carvalho de Melo 
151e18b890bSChristoph Lameter static void ccid_kmem_cache_destroy(struct kmem_cache *slab)
15291f0ebf7SArnaldo Carvalho de Melo {
15391f0ebf7SArnaldo Carvalho de Melo 	if (slab != NULL) {
15491f0ebf7SArnaldo Carvalho de Melo 		const char *name = kmem_cache_name(slab);
15591f0ebf7SArnaldo Carvalho de Melo 
15691f0ebf7SArnaldo Carvalho de Melo 		kmem_cache_destroy(slab);
15791f0ebf7SArnaldo Carvalho de Melo 		kfree(name);
15891f0ebf7SArnaldo Carvalho de Melo 	}
15991f0ebf7SArnaldo Carvalho de Melo }
16091f0ebf7SArnaldo Carvalho de Melo 
161*ddebc973SGerrit Renker #ifdef ___OLD_INTERFACE_TO_BE_REMOVED___
162d90ebcbfSGerrit Renker /* check that up to @array_len members in @ccid_array are supported */
163d90ebcbfSGerrit Renker bool ccid_support_check(u8 const *ccid_array, u8 array_len)
164d90ebcbfSGerrit Renker {
165d90ebcbfSGerrit Renker 	u8 i, j, found;
166d90ebcbfSGerrit Renker 
167d90ebcbfSGerrit Renker 	for (i = 0, found = 0; i < array_len; i++, found = 0) {
168d90ebcbfSGerrit Renker 		for (j = 0; !found && j < ARRAY_SIZE(builtin_ccids); j++)
169d90ebcbfSGerrit Renker 			found = (ccid_array[i] == builtin_ccids[j]);
170d90ebcbfSGerrit Renker 		if (!found)
171d90ebcbfSGerrit Renker 			return false;
172d90ebcbfSGerrit Renker 	}
173d90ebcbfSGerrit Renker 	return true;
174d90ebcbfSGerrit Renker }
175d90ebcbfSGerrit Renker 
176d90ebcbfSGerrit Renker /**
177d90ebcbfSGerrit Renker  * ccid_get_builtin_ccids  -  Provide copy of `builtin' CCID array
178d90ebcbfSGerrit Renker  * @ccid_array: pointer to copy into
179d90ebcbfSGerrit Renker  * @array_len: value to return length into
180d90ebcbfSGerrit Renker  * This function allocates memory - caller must see that it is freed after use.
181d90ebcbfSGerrit Renker  */
182d90ebcbfSGerrit Renker int ccid_get_builtin_ccids(u8 **ccid_array, u8 *array_len)
183d90ebcbfSGerrit Renker {
184d90ebcbfSGerrit Renker 	*ccid_array = kmemdup(builtin_ccids, sizeof(builtin_ccids), gfp_any());
185d90ebcbfSGerrit Renker 	if (*ccid_array == NULL)
186d90ebcbfSGerrit Renker 		return -ENOBUFS;
187d90ebcbfSGerrit Renker 	*array_len = ARRAY_SIZE(builtin_ccids);
188d90ebcbfSGerrit Renker 	return 0;
189d90ebcbfSGerrit Renker }
190d90ebcbfSGerrit Renker 
191d90ebcbfSGerrit Renker int ccid_getsockopt_builtin_ccids(struct sock *sk, int len,
192d90ebcbfSGerrit Renker 				    char __user *optval, int __user *optlen)
193d90ebcbfSGerrit Renker {
194d90ebcbfSGerrit Renker 	if (len < sizeof(builtin_ccids))
195d90ebcbfSGerrit Renker 		return -EINVAL;
196d90ebcbfSGerrit Renker 
197d90ebcbfSGerrit Renker 	if (put_user(sizeof(builtin_ccids), optlen) ||
198d90ebcbfSGerrit Renker 	    copy_to_user(optval, builtin_ccids, sizeof(builtin_ccids)))
199d90ebcbfSGerrit Renker 		return -EFAULT;
200d90ebcbfSGerrit Renker 	return 0;
201d90ebcbfSGerrit Renker }
202*ddebc973SGerrit Renker #endif /* ___OLD_INTERFACE_TO_BE_REMOVED___ */
203d90ebcbfSGerrit Renker 
204*ddebc973SGerrit Renker static int ccid_activate(struct ccid_operations *ccid_ops)
20591f0ebf7SArnaldo Carvalho de Melo {
20691f0ebf7SArnaldo Carvalho de Melo 	int err = -ENOBUFS;
20791f0ebf7SArnaldo Carvalho de Melo 
20891f0ebf7SArnaldo Carvalho de Melo 	ccid_ops->ccid_hc_rx_slab =
20991f0ebf7SArnaldo Carvalho de Melo 			ccid_kmem_cache_create(ccid_ops->ccid_hc_rx_obj_size,
21084a97b0aSGerrit Renker 					       "ccid%u_hc_rx_sock",
21184a97b0aSGerrit Renker 					       ccid_ops->ccid_id);
21291f0ebf7SArnaldo Carvalho de Melo 	if (ccid_ops->ccid_hc_rx_slab == NULL)
21391f0ebf7SArnaldo Carvalho de Melo 		goto out;
21491f0ebf7SArnaldo Carvalho de Melo 
21591f0ebf7SArnaldo Carvalho de Melo 	ccid_ops->ccid_hc_tx_slab =
21691f0ebf7SArnaldo Carvalho de Melo 			ccid_kmem_cache_create(ccid_ops->ccid_hc_tx_obj_size,
21784a97b0aSGerrit Renker 					       "ccid%u_hc_tx_sock",
21884a97b0aSGerrit Renker 					       ccid_ops->ccid_id);
21991f0ebf7SArnaldo Carvalho de Melo 	if (ccid_ops->ccid_hc_tx_slab == NULL)
22091f0ebf7SArnaldo Carvalho de Melo 		goto out_free_rx_slab;
2217c657876SArnaldo Carvalho de Melo 
222*ddebc973SGerrit Renker 	pr_info("CCID: Activated CCID %d (%s)\n",
22391f0ebf7SArnaldo Carvalho de Melo 		ccid_ops->ccid_id, ccid_ops->ccid_name);
224*ddebc973SGerrit Renker 	err = 0;
22591f0ebf7SArnaldo Carvalho de Melo out:
2267c657876SArnaldo Carvalho de Melo 	return err;
22791f0ebf7SArnaldo Carvalho de Melo out_free_rx_slab:
22891f0ebf7SArnaldo Carvalho de Melo 	ccid_kmem_cache_destroy(ccid_ops->ccid_hc_rx_slab);
22991f0ebf7SArnaldo Carvalho de Melo 	ccid_ops->ccid_hc_rx_slab = NULL;
23091f0ebf7SArnaldo Carvalho de Melo 	goto out;
2317c657876SArnaldo Carvalho de Melo }
2327c657876SArnaldo Carvalho de Melo 
233*ddebc973SGerrit Renker static void ccid_deactivate(struct ccid_operations *ccid_ops)
2347c657876SArnaldo Carvalho de Melo {
23591f0ebf7SArnaldo Carvalho de Melo 	ccid_kmem_cache_destroy(ccid_ops->ccid_hc_tx_slab);
23691f0ebf7SArnaldo Carvalho de Melo 	ccid_ops->ccid_hc_tx_slab = NULL;
23791f0ebf7SArnaldo Carvalho de Melo 	ccid_kmem_cache_destroy(ccid_ops->ccid_hc_rx_slab);
23891f0ebf7SArnaldo Carvalho de Melo 	ccid_ops->ccid_hc_rx_slab = NULL;
23991f0ebf7SArnaldo Carvalho de Melo 
240*ddebc973SGerrit Renker 	pr_info("CCID: Deactivated CCID %d (%s)\n",
24191f0ebf7SArnaldo Carvalho de Melo 		ccid_ops->ccid_id, ccid_ops->ccid_name);
2427c657876SArnaldo Carvalho de Melo }
2437c657876SArnaldo Carvalho de Melo 
24491f0ebf7SArnaldo Carvalho de Melo struct ccid *ccid_new(unsigned char id, struct sock *sk, int rx, gfp_t gfp)
2457c657876SArnaldo Carvalho de Melo {
246*ddebc973SGerrit Renker 	struct ccid_operations *ccid_ops = ccid_by_number(id);
24791f0ebf7SArnaldo Carvalho de Melo 	struct ccid *ccid = NULL;
2487c657876SArnaldo Carvalho de Melo 
24991f0ebf7SArnaldo Carvalho de Melo 	if (ccid_ops == NULL)
250*ddebc973SGerrit Renker 		goto out;
25191f0ebf7SArnaldo Carvalho de Melo 
25291f0ebf7SArnaldo Carvalho de Melo 	ccid = kmem_cache_alloc(rx ? ccid_ops->ccid_hc_rx_slab :
25391f0ebf7SArnaldo Carvalho de Melo 				     ccid_ops->ccid_hc_tx_slab, gfp);
25491f0ebf7SArnaldo Carvalho de Melo 	if (ccid == NULL)
255*ddebc973SGerrit Renker 		goto out;
25691f0ebf7SArnaldo Carvalho de Melo 	ccid->ccid_ops = ccid_ops;
25791f0ebf7SArnaldo Carvalho de Melo 	if (rx) {
25891f0ebf7SArnaldo Carvalho de Melo 		memset(ccid + 1, 0, ccid_ops->ccid_hc_rx_obj_size);
25991f0ebf7SArnaldo Carvalho de Melo 		if (ccid->ccid_ops->ccid_hc_rx_init != NULL &&
26091f0ebf7SArnaldo Carvalho de Melo 		    ccid->ccid_ops->ccid_hc_rx_init(ccid, sk) != 0)
26191f0ebf7SArnaldo Carvalho de Melo 			goto out_free_ccid;
26291f0ebf7SArnaldo Carvalho de Melo 	} else {
26391f0ebf7SArnaldo Carvalho de Melo 		memset(ccid + 1, 0, ccid_ops->ccid_hc_tx_obj_size);
26491f0ebf7SArnaldo Carvalho de Melo 		if (ccid->ccid_ops->ccid_hc_tx_init != NULL &&
26591f0ebf7SArnaldo Carvalho de Melo 		    ccid->ccid_ops->ccid_hc_tx_init(ccid, sk) != 0)
26691f0ebf7SArnaldo Carvalho de Melo 			goto out_free_ccid;
26791f0ebf7SArnaldo Carvalho de Melo 	}
26891f0ebf7SArnaldo Carvalho de Melo out:
2697c657876SArnaldo Carvalho de Melo 	return ccid;
27091f0ebf7SArnaldo Carvalho de Melo out_free_ccid:
27191f0ebf7SArnaldo Carvalho de Melo 	kmem_cache_free(rx ? ccid_ops->ccid_hc_rx_slab :
27291f0ebf7SArnaldo Carvalho de Melo 			ccid_ops->ccid_hc_tx_slab, ccid);
2737c657876SArnaldo Carvalho de Melo 	ccid = NULL;
2747c657876SArnaldo Carvalho de Melo 	goto out;
2757c657876SArnaldo Carvalho de Melo }
2767c657876SArnaldo Carvalho de Melo 
27791f0ebf7SArnaldo Carvalho de Melo EXPORT_SYMBOL_GPL(ccid_new);
2787c657876SArnaldo Carvalho de Melo 
27991f0ebf7SArnaldo Carvalho de Melo static void ccid_delete(struct ccid *ccid, struct sock *sk, int rx)
28091f0ebf7SArnaldo Carvalho de Melo {
28191f0ebf7SArnaldo Carvalho de Melo 	struct ccid_operations *ccid_ops;
28291f0ebf7SArnaldo Carvalho de Melo 
2837c657876SArnaldo Carvalho de Melo 	if (ccid == NULL)
2847c657876SArnaldo Carvalho de Melo 		return;
2857c657876SArnaldo Carvalho de Melo 
28691f0ebf7SArnaldo Carvalho de Melo 	ccid_ops = ccid->ccid_ops;
28791f0ebf7SArnaldo Carvalho de Melo 	if (rx) {
28891f0ebf7SArnaldo Carvalho de Melo 		if (ccid_ops->ccid_hc_rx_exit != NULL)
28991f0ebf7SArnaldo Carvalho de Melo 			ccid_ops->ccid_hc_rx_exit(sk);
29091f0ebf7SArnaldo Carvalho de Melo 		kmem_cache_free(ccid_ops->ccid_hc_rx_slab,  ccid);
29191f0ebf7SArnaldo Carvalho de Melo 	} else {
29291f0ebf7SArnaldo Carvalho de Melo 		if (ccid_ops->ccid_hc_tx_exit != NULL)
29391f0ebf7SArnaldo Carvalho de Melo 			ccid_ops->ccid_hc_tx_exit(sk);
29491f0ebf7SArnaldo Carvalho de Melo 		kmem_cache_free(ccid_ops->ccid_hc_tx_slab,  ccid);
2957c657876SArnaldo Carvalho de Melo 	}
2967c657876SArnaldo Carvalho de Melo }
2977c657876SArnaldo Carvalho de Melo 
29891f0ebf7SArnaldo Carvalho de Melo void ccid_hc_rx_delete(struct ccid *ccid, struct sock *sk)
29991f0ebf7SArnaldo Carvalho de Melo {
30091f0ebf7SArnaldo Carvalho de Melo 	ccid_delete(ccid, sk, 1);
30191f0ebf7SArnaldo Carvalho de Melo }
30291f0ebf7SArnaldo Carvalho de Melo 
30391f0ebf7SArnaldo Carvalho de Melo EXPORT_SYMBOL_GPL(ccid_hc_rx_delete);
30491f0ebf7SArnaldo Carvalho de Melo 
30591f0ebf7SArnaldo Carvalho de Melo void ccid_hc_tx_delete(struct ccid *ccid, struct sock *sk)
30691f0ebf7SArnaldo Carvalho de Melo {
30791f0ebf7SArnaldo Carvalho de Melo 	ccid_delete(ccid, sk, 0);
30891f0ebf7SArnaldo Carvalho de Melo }
30991f0ebf7SArnaldo Carvalho de Melo 
31091f0ebf7SArnaldo Carvalho de Melo EXPORT_SYMBOL_GPL(ccid_hc_tx_delete);
311*ddebc973SGerrit Renker 
312*ddebc973SGerrit Renker int __init ccid_initialize_builtins(void)
313*ddebc973SGerrit Renker {
314*ddebc973SGerrit Renker 	int i, err;
315*ddebc973SGerrit Renker 
316*ddebc973SGerrit Renker 	for (i = 0; i < ARRAY_SIZE(ccids); i++) {
317*ddebc973SGerrit Renker 		err = ccid_activate(ccids[i]);
318*ddebc973SGerrit Renker 		if (err)
319*ddebc973SGerrit Renker 			goto unwind_registrations;
320*ddebc973SGerrit Renker 	}
321*ddebc973SGerrit Renker 	return 0;
322*ddebc973SGerrit Renker 
323*ddebc973SGerrit Renker unwind_registrations:
324*ddebc973SGerrit Renker 	while(--i >= 0)
325*ddebc973SGerrit Renker 		ccid_deactivate(ccids[i]);
326*ddebc973SGerrit Renker 	return err;
327*ddebc973SGerrit Renker }
328*ddebc973SGerrit Renker 
329*ddebc973SGerrit Renker void ccid_cleanup_builtins(void)
330*ddebc973SGerrit Renker {
331*ddebc973SGerrit Renker 	int i;
332*ddebc973SGerrit Renker 
333*ddebc973SGerrit Renker 	for (i = 0; i < ARRAY_SIZE(ccids); i++)
334*ddebc973SGerrit Renker 		ccid_deactivate(ccids[i]);
335*ddebc973SGerrit Renker }
336