xref: /linux/net/nfc/hci/llc.c (revision a4a755c422242c27cb0f7900ac00cf33ac17b1ce)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Link Layer Control manager
4  *
5  * Copyright (C) 2012  Intel Corporation. All rights reserved.
6  */
7 
8 #include <net/nfc/llc.h>
9 
10 #include "llc.h"
11 
12 static LIST_HEAD(llc_engines);
13 
14 int __init nfc_llc_init(void)
15 {
16 	int r;
17 
18 	r = nfc_llc_nop_register();
19 	if (r)
20 		goto exit;
21 
22 	r = nfc_llc_shdlc_register();
23 	if (r)
24 		goto exit;
25 
26 	return 0;
27 
28 exit:
29 	nfc_llc_exit();
30 	return r;
31 }
32 
33 static void nfc_llc_del_engine(struct nfc_llc_engine *llc_engine)
34 {
35 	list_del(&llc_engine->entry);
36 	kfree_const(llc_engine->name);
37 	kfree(llc_engine);
38 }
39 
40 void nfc_llc_exit(void)
41 {
42 	struct nfc_llc_engine *llc_engine, *n;
43 
44 	list_for_each_entry_safe(llc_engine, n, &llc_engines, entry)
45 		nfc_llc_del_engine(llc_engine);
46 }
47 
48 int nfc_llc_register(const char *name, const struct nfc_llc_ops *ops)
49 {
50 	struct nfc_llc_engine *llc_engine;
51 
52 	llc_engine = kzalloc(sizeof(struct nfc_llc_engine), GFP_KERNEL);
53 	if (llc_engine == NULL)
54 		return -ENOMEM;
55 
56 	llc_engine->name = kstrdup_const(name, GFP_KERNEL);
57 	if (llc_engine->name == NULL) {
58 		kfree(llc_engine);
59 		return -ENOMEM;
60 	}
61 	llc_engine->ops = ops;
62 
63 	INIT_LIST_HEAD(&llc_engine->entry);
64 	list_add_tail(&llc_engine->entry, &llc_engines);
65 
66 	return 0;
67 }
68 
69 static struct nfc_llc_engine *nfc_llc_name_to_engine(const char *name)
70 {
71 	struct nfc_llc_engine *llc_engine;
72 
73 	list_for_each_entry(llc_engine, &llc_engines, entry) {
74 		if (strcmp(llc_engine->name, name) == 0)
75 			return llc_engine;
76 	}
77 
78 	return NULL;
79 }
80 
81 void nfc_llc_unregister(const char *name)
82 {
83 	struct nfc_llc_engine *llc_engine;
84 
85 	llc_engine = nfc_llc_name_to_engine(name);
86 	if (llc_engine == NULL)
87 		return;
88 
89 	nfc_llc_del_engine(llc_engine);
90 }
91 
92 struct nfc_llc *nfc_llc_allocate(const char *name, struct nfc_hci_dev *hdev,
93 				 xmit_to_drv_t xmit_to_drv,
94 				 rcv_to_hci_t rcv_to_hci, int tx_headroom,
95 				 int tx_tailroom, llc_failure_t llc_failure)
96 {
97 	struct nfc_llc_engine *llc_engine;
98 	struct nfc_llc *llc;
99 
100 	llc_engine = nfc_llc_name_to_engine(name);
101 	if (llc_engine == NULL)
102 		return NULL;
103 
104 	llc = kzalloc(sizeof(struct nfc_llc), GFP_KERNEL);
105 	if (llc == NULL)
106 		return NULL;
107 
108 	llc->data = llc_engine->ops->init(hdev, xmit_to_drv, rcv_to_hci,
109 					  tx_headroom, tx_tailroom,
110 					  &llc->rx_headroom, &llc->rx_tailroom,
111 					  llc_failure);
112 	if (llc->data == NULL) {
113 		kfree(llc);
114 		return NULL;
115 	}
116 	llc->ops = llc_engine->ops;
117 
118 	return llc;
119 }
120 
121 void nfc_llc_free(struct nfc_llc *llc)
122 {
123 	llc->ops->deinit(llc);
124 	kfree(llc);
125 }
126 
127 int nfc_llc_start(struct nfc_llc *llc)
128 {
129 	return llc->ops->start(llc);
130 }
131 EXPORT_SYMBOL(nfc_llc_start);
132 
133 int nfc_llc_stop(struct nfc_llc *llc)
134 {
135 	return llc->ops->stop(llc);
136 }
137 EXPORT_SYMBOL(nfc_llc_stop);
138 
139 void nfc_llc_rcv_from_drv(struct nfc_llc *llc, struct sk_buff *skb)
140 {
141 	llc->ops->rcv_from_drv(llc, skb);
142 }
143 
144 int nfc_llc_xmit_from_hci(struct nfc_llc *llc, struct sk_buff *skb)
145 {
146 	return llc->ops->xmit_from_hci(llc, skb);
147 }
148 
149 void *nfc_llc_get_data(struct nfc_llc *llc)
150 {
151 	return llc->data;
152 }
153