17c657876b63cb1d8a2ec06f8fc6c37bb8412e66cArnaldo Carvalho de Melo/*
27c657876b63cb1d8a2ec06f8fc6c37bb8412e66cArnaldo Carvalho de Melo *  net/dccp/ccid.c
37c657876b63cb1d8a2ec06f8fc6c37bb8412e66cArnaldo Carvalho de Melo *
47c657876b63cb1d8a2ec06f8fc6c37bb8412e66cArnaldo Carvalho de Melo *  An implementation of the DCCP protocol
57c657876b63cb1d8a2ec06f8fc6c37bb8412e66cArnaldo Carvalho de Melo *  Arnaldo Carvalho de Melo <acme@conectiva.com.br>
67c657876b63cb1d8a2ec06f8fc6c37bb8412e66cArnaldo Carvalho de Melo *
77c657876b63cb1d8a2ec06f8fc6c37bb8412e66cArnaldo Carvalho de Melo *  CCID infrastructure
87c657876b63cb1d8a2ec06f8fc6c37bb8412e66cArnaldo Carvalho de Melo *
97c657876b63cb1d8a2ec06f8fc6c37bb8412e66cArnaldo Carvalho de Melo *	This program is free software; you can redistribute it and/or modify it
107c657876b63cb1d8a2ec06f8fc6c37bb8412e66cArnaldo Carvalho de Melo *	under the terms of the GNU General Public License version 2 as
117c657876b63cb1d8a2ec06f8fc6c37bb8412e66cArnaldo Carvalho de Melo *	published by the Free Software Foundation.
127c657876b63cb1d8a2ec06f8fc6c37bb8412e66cArnaldo Carvalho de Melo */
137c657876b63cb1d8a2ec06f8fc6c37bb8412e66cArnaldo Carvalho de Melo
145a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
155a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo
167c657876b63cb1d8a2ec06f8fc6c37bb8412e66cArnaldo Carvalho de Melo#include "ccid.h"
17129fa44785a399248ae2466b6cb5c655e96668f7Gerrit Renker#include "ccids/lib/tfrc.h"
187c657876b63cb1d8a2ec06f8fc6c37bb8412e66cArnaldo Carvalho de Melo
19ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renkerstatic struct ccid_operations *ccids[] = {
20ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renker	&ccid2_ops,
21ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renker#ifdef CONFIG_IP_DCCP_CCID3
22ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renker	&ccid3_ops,
23ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renker#endif
24ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renker};
25ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renker
26ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renkerstatic struct ccid_operations *ccid_by_number(const u8 id)
27ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renker{
28ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renker	int i;
29ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renker
30ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renker	for (i = 0; i < ARRAY_SIZE(ccids); i++)
31ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renker		if (ccids[i]->ccid_id == id)
32ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renker			return ccids[i];
33ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renker	return NULL;
34ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renker}
35ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renker
36ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renker/* check that up to @array_len members in @ccid_array are supported */
37ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renkerbool ccid_support_check(u8 const *ccid_array, u8 array_len)
38ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renker{
39ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renker	while (array_len > 0)
40ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renker		if (ccid_by_number(ccid_array[--array_len]) == NULL)
41ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renker			return false;
42ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renker	return true;
43ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renker}
44ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renker
45ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renker/**
46ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renker * ccid_get_builtin_ccids  -  Populate a list of built-in CCIDs
47ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renker * @ccid_array: pointer to copy into
48ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renker * @array_len: value to return length into
492c53040f018b6c36a46eec75b9b937aaa5f78e6dBen Hutchings *
50ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renker * This function allocates memory - caller must see that it is freed after use.
51ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renker */
52ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renkerint ccid_get_builtin_ccids(u8 **ccid_array, u8 *array_len)
53ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renker{
54ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renker	*ccid_array = kmalloc(ARRAY_SIZE(ccids), gfp_any());
55ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renker	if (*ccid_array == NULL)
56ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renker		return -ENOBUFS;
57ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renker
58ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renker	for (*array_len = 0; *array_len < ARRAY_SIZE(ccids); *array_len += 1)
59ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renker		(*ccid_array)[*array_len] = ccids[*array_len]->ccid_id;
60ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renker	return 0;
61ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renker}
62ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renker
63ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renkerint ccid_getsockopt_builtin_ccids(struct sock *sk, int len,
64ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renker				  char __user *optval, int __user *optlen)
65ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renker{
66ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renker	u8 *ccid_array, array_len;
67ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renker	int err = 0;
68ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renker
69ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renker	if (ccid_get_builtin_ccids(&ccid_array, &array_len))
70ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renker		return -ENOBUFS;
71ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renker
7269a6a0b38a139ccceef32222108caca8a9b0b795Gerrit Renker	if (put_user(array_len, optlen))
7369a6a0b38a139ccceef32222108caca8a9b0b795Gerrit Renker		err = -EFAULT;
7469a6a0b38a139ccceef32222108caca8a9b0b795Gerrit Renker	else if (len > 0 && copy_to_user(optval, ccid_array,
7569a6a0b38a139ccceef32222108caca8a9b0b795Gerrit Renker					 len > array_len ? array_len : len))
76ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renker		err = -EFAULT;
77ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renker
78ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renker	kfree(ccid_array);
79ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renker	return err;
80ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renker}
81ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renker
82de4ef86cfce60d2250111f34f8a084e769f23b16Neil Hormanstatic struct kmem_cache *ccid_kmem_cache_create(int obj_size, char *slab_name_fmt, const char *fmt,...)
837c657876b63cb1d8a2ec06f8fc6c37bb8412e66cArnaldo Carvalho de Melo{
84e18b890bb0881bbab6f4f1a6cd20d9c60d66b003Christoph Lameter	struct kmem_cache *slab;
8591f0ebf7b6d5cb2b6e818d48587566144821babeArnaldo Carvalho de Melo	va_list args;
8691f0ebf7b6d5cb2b6e818d48587566144821babeArnaldo Carvalho de Melo
8791f0ebf7b6d5cb2b6e818d48587566144821babeArnaldo Carvalho de Melo	va_start(args, fmt);
888ed030dd0aa400d18c63861c2c6deb7c38f4eddeGerrit Renker	vsnprintf(slab_name_fmt, CCID_SLAB_NAME_LENGTH, fmt, args);
8991f0ebf7b6d5cb2b6e818d48587566144821babeArnaldo Carvalho de Melo	va_end(args);
9091f0ebf7b6d5cb2b6e818d48587566144821babeArnaldo Carvalho de Melo
91de4ef86cfce60d2250111f34f8a084e769f23b16Neil Horman	slab = kmem_cache_create(slab_name_fmt, sizeof(struct ccid) + obj_size, 0,
9220c2df83d25c6a95affe6157a4c9cac4cf5ffaacPaul Mundt				 SLAB_HWCACHE_ALIGN, NULL);
9391f0ebf7b6d5cb2b6e818d48587566144821babeArnaldo Carvalho de Melo	return slab;
9491f0ebf7b6d5cb2b6e818d48587566144821babeArnaldo Carvalho de Melo}
9591f0ebf7b6d5cb2b6e818d48587566144821babeArnaldo Carvalho de Melo
96e18b890bb0881bbab6f4f1a6cd20d9c60d66b003Christoph Lameterstatic void ccid_kmem_cache_destroy(struct kmem_cache *slab)
9791f0ebf7b6d5cb2b6e818d48587566144821babeArnaldo Carvalho de Melo{
98de4ef86cfce60d2250111f34f8a084e769f23b16Neil Horman	if (slab != NULL)
9991f0ebf7b6d5cb2b6e818d48587566144821babeArnaldo Carvalho de Melo		kmem_cache_destroy(slab);
10091f0ebf7b6d5cb2b6e818d48587566144821babeArnaldo Carvalho de Melo}
10191f0ebf7b6d5cb2b6e818d48587566144821babeArnaldo Carvalho de Melo
102e500f488c27659bb6f5d313b336621f3daa67701Fabian Frederickstatic int __init ccid_activate(struct ccid_operations *ccid_ops)
10391f0ebf7b6d5cb2b6e818d48587566144821babeArnaldo Carvalho de Melo{
10491f0ebf7b6d5cb2b6e818d48587566144821babeArnaldo Carvalho de Melo	int err = -ENOBUFS;
10591f0ebf7b6d5cb2b6e818d48587566144821babeArnaldo Carvalho de Melo
10691f0ebf7b6d5cb2b6e818d48587566144821babeArnaldo Carvalho de Melo	ccid_ops->ccid_hc_rx_slab =
10791f0ebf7b6d5cb2b6e818d48587566144821babeArnaldo Carvalho de Melo			ccid_kmem_cache_create(ccid_ops->ccid_hc_rx_obj_size,
108de4ef86cfce60d2250111f34f8a084e769f23b16Neil Horman					       ccid_ops->ccid_hc_rx_slab_name,
10984a97b0af8c29aa5a47cc5271968a9c6004fb91eGerrit Renker					       "ccid%u_hc_rx_sock",
11084a97b0af8c29aa5a47cc5271968a9c6004fb91eGerrit Renker					       ccid_ops->ccid_id);
11191f0ebf7b6d5cb2b6e818d48587566144821babeArnaldo Carvalho de Melo	if (ccid_ops->ccid_hc_rx_slab == NULL)
11291f0ebf7b6d5cb2b6e818d48587566144821babeArnaldo Carvalho de Melo		goto out;
11391f0ebf7b6d5cb2b6e818d48587566144821babeArnaldo Carvalho de Melo
11491f0ebf7b6d5cb2b6e818d48587566144821babeArnaldo Carvalho de Melo	ccid_ops->ccid_hc_tx_slab =
11591f0ebf7b6d5cb2b6e818d48587566144821babeArnaldo Carvalho de Melo			ccid_kmem_cache_create(ccid_ops->ccid_hc_tx_obj_size,
116de4ef86cfce60d2250111f34f8a084e769f23b16Neil Horman					       ccid_ops->ccid_hc_tx_slab_name,
11784a97b0af8c29aa5a47cc5271968a9c6004fb91eGerrit Renker					       "ccid%u_hc_tx_sock",
11884a97b0af8c29aa5a47cc5271968a9c6004fb91eGerrit Renker					       ccid_ops->ccid_id);
11991f0ebf7b6d5cb2b6e818d48587566144821babeArnaldo Carvalho de Melo	if (ccid_ops->ccid_hc_tx_slab == NULL)
12091f0ebf7b6d5cb2b6e818d48587566144821babeArnaldo Carvalho de Melo		goto out_free_rx_slab;
1217c657876b63cb1d8a2ec06f8fc6c37bb8412e66cArnaldo Carvalho de Melo
1221fd9d2081a9d8d77e5afccd5aafd28310cab3bfcGerrit Renker	pr_info("DCCP: Activated CCID %d (%s)\n",
12391f0ebf7b6d5cb2b6e818d48587566144821babeArnaldo Carvalho de Melo		ccid_ops->ccid_id, ccid_ops->ccid_name);
124ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renker	err = 0;
12591f0ebf7b6d5cb2b6e818d48587566144821babeArnaldo Carvalho de Meloout:
1267c657876b63cb1d8a2ec06f8fc6c37bb8412e66cArnaldo Carvalho de Melo	return err;
12791f0ebf7b6d5cb2b6e818d48587566144821babeArnaldo Carvalho de Meloout_free_rx_slab:
12891f0ebf7b6d5cb2b6e818d48587566144821babeArnaldo Carvalho de Melo	ccid_kmem_cache_destroy(ccid_ops->ccid_hc_rx_slab);
12991f0ebf7b6d5cb2b6e818d48587566144821babeArnaldo Carvalho de Melo	ccid_ops->ccid_hc_rx_slab = NULL;
13091f0ebf7b6d5cb2b6e818d48587566144821babeArnaldo Carvalho de Melo	goto out;
1317c657876b63cb1d8a2ec06f8fc6c37bb8412e66cArnaldo Carvalho de Melo}
1327c657876b63cb1d8a2ec06f8fc6c37bb8412e66cArnaldo Carvalho de Melo
133ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renkerstatic void ccid_deactivate(struct ccid_operations *ccid_ops)
1347c657876b63cb1d8a2ec06f8fc6c37bb8412e66cArnaldo Carvalho de Melo{
13591f0ebf7b6d5cb2b6e818d48587566144821babeArnaldo Carvalho de Melo	ccid_kmem_cache_destroy(ccid_ops->ccid_hc_tx_slab);
13691f0ebf7b6d5cb2b6e818d48587566144821babeArnaldo Carvalho de Melo	ccid_ops->ccid_hc_tx_slab = NULL;
13791f0ebf7b6d5cb2b6e818d48587566144821babeArnaldo Carvalho de Melo	ccid_kmem_cache_destroy(ccid_ops->ccid_hc_rx_slab);
13891f0ebf7b6d5cb2b6e818d48587566144821babeArnaldo Carvalho de Melo	ccid_ops->ccid_hc_rx_slab = NULL;
13991f0ebf7b6d5cb2b6e818d48587566144821babeArnaldo Carvalho de Melo
1401fd9d2081a9d8d77e5afccd5aafd28310cab3bfcGerrit Renker	pr_info("DCCP: Deactivated CCID %d (%s)\n",
14191f0ebf7b6d5cb2b6e818d48587566144821babeArnaldo Carvalho de Melo		ccid_ops->ccid_id, ccid_ops->ccid_name);
1427c657876b63cb1d8a2ec06f8fc6c37bb8412e66cArnaldo Carvalho de Melo}
1437c657876b63cb1d8a2ec06f8fc6c37bb8412e66cArnaldo Carvalho de Melo
144e5fd56ca4eb3a130882bbef69d6952ef6aca5c8dGerrit Renkerstruct ccid *ccid_new(const u8 id, struct sock *sk, bool rx)
1457c657876b63cb1d8a2ec06f8fc6c37bb8412e66cArnaldo Carvalho de Melo{
146ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renker	struct ccid_operations *ccid_ops = ccid_by_number(id);
14791f0ebf7b6d5cb2b6e818d48587566144821babeArnaldo Carvalho de Melo	struct ccid *ccid = NULL;
1487c657876b63cb1d8a2ec06f8fc6c37bb8412e66cArnaldo Carvalho de Melo
14991f0ebf7b6d5cb2b6e818d48587566144821babeArnaldo Carvalho de Melo	if (ccid_ops == NULL)
150ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renker		goto out;
1517c657876b63cb1d8a2ec06f8fc6c37bb8412e66cArnaldo Carvalho de Melo
15291f0ebf7b6d5cb2b6e818d48587566144821babeArnaldo Carvalho de Melo	ccid = kmem_cache_alloc(rx ? ccid_ops->ccid_hc_rx_slab :
153e5fd56ca4eb3a130882bbef69d6952ef6aca5c8dGerrit Renker				     ccid_ops->ccid_hc_tx_slab, gfp_any());
15491f0ebf7b6d5cb2b6e818d48587566144821babeArnaldo Carvalho de Melo	if (ccid == NULL)
155ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renker		goto out;
15691f0ebf7b6d5cb2b6e818d48587566144821babeArnaldo Carvalho de Melo	ccid->ccid_ops = ccid_ops;
15791f0ebf7b6d5cb2b6e818d48587566144821babeArnaldo Carvalho de Melo	if (rx) {
15891f0ebf7b6d5cb2b6e818d48587566144821babeArnaldo Carvalho de Melo		memset(ccid + 1, 0, ccid_ops->ccid_hc_rx_obj_size);
15991f0ebf7b6d5cb2b6e818d48587566144821babeArnaldo Carvalho de Melo		if (ccid->ccid_ops->ccid_hc_rx_init != NULL &&
16091f0ebf7b6d5cb2b6e818d48587566144821babeArnaldo Carvalho de Melo		    ccid->ccid_ops->ccid_hc_rx_init(ccid, sk) != 0)
16191f0ebf7b6d5cb2b6e818d48587566144821babeArnaldo Carvalho de Melo			goto out_free_ccid;
16291f0ebf7b6d5cb2b6e818d48587566144821babeArnaldo Carvalho de Melo	} else {
16391f0ebf7b6d5cb2b6e818d48587566144821babeArnaldo Carvalho de Melo		memset(ccid + 1, 0, ccid_ops->ccid_hc_tx_obj_size);
16491f0ebf7b6d5cb2b6e818d48587566144821babeArnaldo Carvalho de Melo		if (ccid->ccid_ops->ccid_hc_tx_init != NULL &&
16591f0ebf7b6d5cb2b6e818d48587566144821babeArnaldo Carvalho de Melo		    ccid->ccid_ops->ccid_hc_tx_init(ccid, sk) != 0)
16691f0ebf7b6d5cb2b6e818d48587566144821babeArnaldo Carvalho de Melo			goto out_free_ccid;
16791f0ebf7b6d5cb2b6e818d48587566144821babeArnaldo Carvalho de Melo	}
1687c657876b63cb1d8a2ec06f8fc6c37bb8412e66cArnaldo Carvalho de Meloout:
1697c657876b63cb1d8a2ec06f8fc6c37bb8412e66cArnaldo Carvalho de Melo	return ccid;
17091f0ebf7b6d5cb2b6e818d48587566144821babeArnaldo Carvalho de Meloout_free_ccid:
17191f0ebf7b6d5cb2b6e818d48587566144821babeArnaldo Carvalho de Melo	kmem_cache_free(rx ? ccid_ops->ccid_hc_rx_slab :
17291f0ebf7b6d5cb2b6e818d48587566144821babeArnaldo Carvalho de Melo			ccid_ops->ccid_hc_tx_slab, ccid);
1737c657876b63cb1d8a2ec06f8fc6c37bb8412e66cArnaldo Carvalho de Melo	ccid = NULL;
1747c657876b63cb1d8a2ec06f8fc6c37bb8412e66cArnaldo Carvalho de Melo	goto out;
1757c657876b63cb1d8a2ec06f8fc6c37bb8412e66cArnaldo Carvalho de Melo}
1767c657876b63cb1d8a2ec06f8fc6c37bb8412e66cArnaldo Carvalho de Melo
17791f0ebf7b6d5cb2b6e818d48587566144821babeArnaldo Carvalho de Melovoid ccid_hc_rx_delete(struct ccid *ccid, struct sock *sk)
17891f0ebf7b6d5cb2b6e818d48587566144821babeArnaldo Carvalho de Melo{
179e5fd56ca4eb3a130882bbef69d6952ef6aca5c8dGerrit Renker	if (ccid != NULL) {
180e5fd56ca4eb3a130882bbef69d6952ef6aca5c8dGerrit Renker		if (ccid->ccid_ops->ccid_hc_rx_exit != NULL)
181e5fd56ca4eb3a130882bbef69d6952ef6aca5c8dGerrit Renker			ccid->ccid_ops->ccid_hc_rx_exit(sk);
182e5fd56ca4eb3a130882bbef69d6952ef6aca5c8dGerrit Renker		kmem_cache_free(ccid->ccid_ops->ccid_hc_rx_slab, ccid);
183e5fd56ca4eb3a130882bbef69d6952ef6aca5c8dGerrit Renker	}
18491f0ebf7b6d5cb2b6e818d48587566144821babeArnaldo Carvalho de Melo}
1857c657876b63cb1d8a2ec06f8fc6c37bb8412e66cArnaldo Carvalho de Melo
18691f0ebf7b6d5cb2b6e818d48587566144821babeArnaldo Carvalho de Melovoid ccid_hc_tx_delete(struct ccid *ccid, struct sock *sk)
18791f0ebf7b6d5cb2b6e818d48587566144821babeArnaldo Carvalho de Melo{
188e5fd56ca4eb3a130882bbef69d6952ef6aca5c8dGerrit Renker	if (ccid != NULL) {
189e5fd56ca4eb3a130882bbef69d6952ef6aca5c8dGerrit Renker		if (ccid->ccid_ops->ccid_hc_tx_exit != NULL)
190e5fd56ca4eb3a130882bbef69d6952ef6aca5c8dGerrit Renker			ccid->ccid_ops->ccid_hc_tx_exit(sk);
191e5fd56ca4eb3a130882bbef69d6952ef6aca5c8dGerrit Renker		kmem_cache_free(ccid->ccid_ops->ccid_hc_tx_slab, ccid);
192e5fd56ca4eb3a130882bbef69d6952ef6aca5c8dGerrit Renker	}
1937c657876b63cb1d8a2ec06f8fc6c37bb8412e66cArnaldo Carvalho de Melo}
1947c657876b63cb1d8a2ec06f8fc6c37bb8412e66cArnaldo Carvalho de Melo
195ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renkerint __init ccid_initialize_builtins(void)
196ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renker{
197129fa44785a399248ae2466b6cb5c655e96668f7Gerrit Renker	int i, err = tfrc_lib_init();
198129fa44785a399248ae2466b6cb5c655e96668f7Gerrit Renker
199129fa44785a399248ae2466b6cb5c655e96668f7Gerrit Renker	if (err)
200129fa44785a399248ae2466b6cb5c655e96668f7Gerrit Renker		return err;
201ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renker
202ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renker	for (i = 0; i < ARRAY_SIZE(ccids); i++) {
203ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renker		err = ccid_activate(ccids[i]);
204ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renker		if (err)
205ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renker			goto unwind_registrations;
206ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renker	}
207ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renker	return 0;
208ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renker
209ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renkerunwind_registrations:
210ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renker	while(--i >= 0)
211ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renker		ccid_deactivate(ccids[i]);
212129fa44785a399248ae2466b6cb5c655e96668f7Gerrit Renker	tfrc_lib_exit();
213ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renker	return err;
214ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renker}
215ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renker
216ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renkervoid ccid_cleanup_builtins(void)
217ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renker{
218ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renker	int i;
219ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renker
220ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renker	for (i = 0; i < ARRAY_SIZE(ccids); i++)
221ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renker		ccid_deactivate(ccids[i]);
222129fa44785a399248ae2466b6cb5c655e96668f7Gerrit Renker	tfrc_lib_exit();
223ddebc973c56b51b4e5d84d606f0430d81b895d67Gerrit Renker}
224