xref: /kernel/linux/linux-6.6/net/nfc/hci/llc.c (revision 62306a36)
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
12static LIST_HEAD(llc_engines);
13
14int __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
28exit:
29	nfc_llc_exit();
30	return r;
31}
32
33void nfc_llc_exit(void)
34{
35	struct nfc_llc_engine *llc_engine, *n;
36
37	list_for_each_entry_safe(llc_engine, n, &llc_engines, entry) {
38		list_del(&llc_engine->entry);
39		kfree(llc_engine->name);
40		kfree(llc_engine);
41	}
42}
43
44int nfc_llc_register(const char *name, const struct nfc_llc_ops *ops)
45{
46	struct nfc_llc_engine *llc_engine;
47
48	llc_engine = kzalloc(sizeof(struct nfc_llc_engine), GFP_KERNEL);
49	if (llc_engine == NULL)
50		return -ENOMEM;
51
52	llc_engine->name = kstrdup(name, GFP_KERNEL);
53	if (llc_engine->name == NULL) {
54		kfree(llc_engine);
55		return -ENOMEM;
56	}
57	llc_engine->ops = ops;
58
59	INIT_LIST_HEAD(&llc_engine->entry);
60	list_add_tail(&llc_engine->entry, &llc_engines);
61
62	return 0;
63}
64
65static struct nfc_llc_engine *nfc_llc_name_to_engine(const char *name)
66{
67	struct nfc_llc_engine *llc_engine;
68
69	list_for_each_entry(llc_engine, &llc_engines, entry) {
70		if (strcmp(llc_engine->name, name) == 0)
71			return llc_engine;
72	}
73
74	return NULL;
75}
76
77void nfc_llc_unregister(const char *name)
78{
79	struct nfc_llc_engine *llc_engine;
80
81	llc_engine = nfc_llc_name_to_engine(name);
82	if (llc_engine == NULL)
83		return;
84
85	list_del(&llc_engine->entry);
86	kfree(llc_engine->name);
87	kfree(llc_engine);
88}
89
90struct nfc_llc *nfc_llc_allocate(const char *name, struct nfc_hci_dev *hdev,
91				 xmit_to_drv_t xmit_to_drv,
92				 rcv_to_hci_t rcv_to_hci, int tx_headroom,
93				 int tx_tailroom, llc_failure_t llc_failure)
94{
95	struct nfc_llc_engine *llc_engine;
96	struct nfc_llc *llc;
97
98	llc_engine = nfc_llc_name_to_engine(name);
99	if (llc_engine == NULL)
100		return NULL;
101
102	llc = kzalloc(sizeof(struct nfc_llc), GFP_KERNEL);
103	if (llc == NULL)
104		return NULL;
105
106	llc->data = llc_engine->ops->init(hdev, xmit_to_drv, rcv_to_hci,
107					  tx_headroom, tx_tailroom,
108					  &llc->rx_headroom, &llc->rx_tailroom,
109					  llc_failure);
110	if (llc->data == NULL) {
111		kfree(llc);
112		return NULL;
113	}
114	llc->ops = llc_engine->ops;
115
116	return llc;
117}
118
119void nfc_llc_free(struct nfc_llc *llc)
120{
121	llc->ops->deinit(llc);
122	kfree(llc);
123}
124
125int nfc_llc_start(struct nfc_llc *llc)
126{
127	return llc->ops->start(llc);
128}
129EXPORT_SYMBOL(nfc_llc_start);
130
131int nfc_llc_stop(struct nfc_llc *llc)
132{
133	return llc->ops->stop(llc);
134}
135EXPORT_SYMBOL(nfc_llc_stop);
136
137void nfc_llc_rcv_from_drv(struct nfc_llc *llc, struct sk_buff *skb)
138{
139	llc->ops->rcv_from_drv(llc, skb);
140}
141
142int nfc_llc_xmit_from_hci(struct nfc_llc *llc, struct sk_buff *skb)
143{
144	return llc->ops->xmit_from_hci(llc, skb);
145}
146
147void *nfc_llc_get_data(struct nfc_llc *llc)
148{
149	return llc->data;
150}
151