aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLauro Ramos Venancio <lauro.venancio@openbossa.org>2011-07-01 18:31:34 -0400
committerJohn W. Linville <linville@tuxdriver.com>2011-07-05 15:26:57 -0400
commit4d12b8b129f170d0fc3188de1e51a2a1b0f87730 (patch)
treee37bbec5da917fee80706516c56fb41fcd03a1b5
parent3e256b8f8dfa309a80b5dece388d85d9a9801a29 (diff)
NFC: add nfc generic netlink interface
The NFC generic netlink interface exports the NFC control operations to the user space. Signed-off-by: Lauro Ramos Venancio <lauro.venancio@openbossa.org> Signed-off-by: Aloisio Almeida Jr <aloisio.almeida@openbossa.org> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com> Reviewed-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--include/linux/nfc.h112
-rw-r--r--include/net/nfc.h21
-rw-r--r--net/nfc/Makefile2
-rw-r--r--net/nfc/core.c93
-rw-r--r--net/nfc/netlink.c537
-rw-r--r--net/nfc/nfc.h11
6 files changed, 773 insertions, 3 deletions
diff --git a/include/linux/nfc.h b/include/linux/nfc.h
new file mode 100644
index 000000000000..1170476d270a
--- /dev/null
+++ b/include/linux/nfc.h
@@ -0,0 +1,112 @@
1/*
2 * Copyright (C) 2011 Instituto Nokia de Tecnologia
3 *
4 * Authors:
5 * Lauro Ramos Venancio <lauro.venancio@openbossa.org>
6 * Aloisio Almeida Jr <aloisio.almeida@openbossa.org>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the
20 * Free Software Foundation, Inc.,
21 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 */
23
24#ifndef __LINUX_NFC_H
25#define __LINUX_NFC_H
26
27#define NFC_GENL_NAME "nfc"
28#define NFC_GENL_VERSION 1
29
30#define NFC_GENL_MCAST_EVENT_NAME "events"
31
32/**
33 * enum nfc_commands - supported nfc commands
34 *
35 * @NFC_CMD_UNSPEC: unspecified command
36 *
37 * @NFC_CMD_GET_DEVICE: request information about a device (requires
38 * %NFC_ATTR_DEVICE_INDEX) or dump request to get a list of all nfc devices
39 * @NFC_CMD_START_POLL: start polling for targets using the given protocols
40 * (requires %NFC_ATTR_DEVICE_INDEX and %NFC_ATTR_PROTOCOLS)
41 * @NFC_CMD_STOP_POLL: stop polling for targets (requires
42 * %NFC_ATTR_DEVICE_INDEX)
43 * @NFC_CMD_GET_TARGET: dump all targets found by the previous poll (requires
44 * %NFC_ATTR_DEVICE_INDEX)
45 * @NFC_EVENT_TARGETS_FOUND: event emitted when a new target is found
46 * (it sends %NFC_ATTR_DEVICE_INDEX)
47 * @NFC_EVENT_DEVICE_ADDED: event emitted when a new device is registred
48 * (it sends %NFC_ATTR_DEVICE_NAME, %NFC_ATTR_DEVICE_INDEX and
49 * %NFC_ATTR_PROTOCOLS)
50 * @NFC_EVENT_DEVICE_REMOVED: event emitted when a device is removed
51 * (it sends %NFC_ATTR_DEVICE_INDEX)
52 */
53enum nfc_commands {
54 NFC_CMD_UNSPEC,
55 NFC_CMD_GET_DEVICE,
56 NFC_CMD_START_POLL,
57 NFC_CMD_STOP_POLL,
58 NFC_CMD_GET_TARGET,
59 NFC_EVENT_TARGETS_FOUND,
60 NFC_EVENT_DEVICE_ADDED,
61 NFC_EVENT_DEVICE_REMOVED,
62/* private: internal use only */
63 __NFC_CMD_AFTER_LAST
64};
65#define NFC_CMD_MAX (__NFC_CMD_AFTER_LAST - 1)
66
67/**
68 * enum nfc_attrs - supported nfc attributes
69 *
70 * @NFC_ATTR_UNSPEC: unspecified attribute
71 *
72 * @NFC_ATTR_DEVICE_INDEX: index of nfc device
73 * @NFC_ATTR_DEVICE_NAME: device name, max 8 chars
74 * @NFC_ATTR_PROTOCOLS: nfc protocols - bitwise or-ed combination from
75 * NFC_PROTO_*_MASK constants
76 * @NFC_ATTR_TARGET_INDEX: index of the nfc target
77 * @NFC_ATTR_TARGET_SENS_RES: NFC-A targets extra information such as NFCID
78 * @NFC_ATTR_TARGET_SEL_RES: NFC-A targets extra information (useful if the
79 * target is not NFC-Forum compliant)
80 */
81enum nfc_attrs {
82 NFC_ATTR_UNSPEC,
83 NFC_ATTR_DEVICE_INDEX,
84 NFC_ATTR_DEVICE_NAME,
85 NFC_ATTR_PROTOCOLS,
86 NFC_ATTR_TARGET_INDEX,
87 NFC_ATTR_TARGET_SENS_RES,
88 NFC_ATTR_TARGET_SEL_RES,
89/* private: internal use only */
90 __NFC_ATTR_AFTER_LAST
91};
92#define NFC_ATTR_MAX (__NFC_ATTR_AFTER_LAST - 1)
93
94#define NFC_DEVICE_NAME_MAXSIZE 8
95
96/* NFC protocols */
97#define NFC_PROTO_JEWEL 1
98#define NFC_PROTO_MIFARE 2
99#define NFC_PROTO_FELICA 3
100#define NFC_PROTO_ISO14443 4
101#define NFC_PROTO_NFC_DEP 5
102
103#define NFC_PROTO_MAX 6
104
105/* NFC protocols masks used in bitsets */
106#define NFC_PROTO_JEWEL_MASK (1 << NFC_PROTO_JEWEL)
107#define NFC_PROTO_MIFARE_MASK (1 << NFC_PROTO_MIFARE)
108#define NFC_PROTO_FELICA_MASK (1 << NFC_PROTO_FELICA)
109#define NFC_PROTO_ISO14443_MASK (1 << NFC_PROTO_ISO14443)
110#define NFC_PROTO_NFC_DEP_MASK (1 << NFC_PROTO_NFC_DEP)
111
112#endif /*__LINUX_NFC_H */
diff --git a/include/net/nfc.h b/include/net/nfc.h
index c57b579c8301..cc0130312f70 100644
--- a/include/net/nfc.h
+++ b/include/net/nfc.h
@@ -58,10 +58,28 @@ struct nfc_ops {
58 void *cb_context); 58 void *cb_context);
59}; 59};
60 60
61struct nfc_target {
62 u32 idx;
63 u32 supported_protocols;
64 u16 sens_res;
65 u8 sel_res;
66};
67
68struct nfc_genl_data {
69 u32 poll_req_pid;
70 struct mutex genl_data_mutex;
71};
72
61struct nfc_dev { 73struct nfc_dev {
62 unsigned idx; 74 unsigned idx;
75 unsigned target_idx;
76 struct nfc_target *targets;
77 int n_targets;
78 int targets_generation;
79 spinlock_t targets_lock;
63 struct device dev; 80 struct device dev;
64 bool polling; 81 bool polling;
82 struct nfc_genl_data genl_data;
65 u32 supported_protocols; 83 u32 supported_protocols;
66 84
67 struct nfc_ops *ops; 85 struct nfc_ops *ops;
@@ -132,4 +150,7 @@ static inline const char *nfc_device_name(struct nfc_dev *dev)
132 150
133struct sk_buff *nfc_alloc_skb(unsigned int size, gfp_t gfp); 151struct sk_buff *nfc_alloc_skb(unsigned int size, gfp_t gfp);
134 152
153int nfc_targets_found(struct nfc_dev *dev, struct nfc_target *targets,
154 int ntargets);
155
135#endif /* __NET_NFC_H */ 156#endif /* __NET_NFC_H */
diff --git a/net/nfc/Makefile b/net/nfc/Makefile
index 28bee5958687..fa6fc16246d6 100644
--- a/net/nfc/Makefile
+++ b/net/nfc/Makefile
@@ -4,4 +4,4 @@
4 4
5obj-$(CONFIG_NFC) += nfc.o 5obj-$(CONFIG_NFC) += nfc.o
6 6
7nfc-objs := core.o 7nfc-objs := core.o netlink.o
diff --git a/net/nfc/core.c b/net/nfc/core.c
index 19f8035a1ba9..c70f607455c5 100644
--- a/net/nfc/core.c
+++ b/net/nfc/core.c
@@ -233,12 +233,60 @@ struct sk_buff *nfc_alloc_skb(unsigned int size, gfp_t gfp)
233} 233}
234EXPORT_SYMBOL(nfc_alloc_skb); 234EXPORT_SYMBOL(nfc_alloc_skb);
235 235
236/**
237 * nfc_targets_found - inform that targets were found
238 *
239 * @dev: The nfc device that found the targets
240 * @targets: array of nfc targets found
241 * @ntargets: targets array size
242 *
243 * The device driver must call this function when one or many nfc targets
244 * are found. After calling this function, the device driver must stop
245 * polling for targets.
246 */
247int nfc_targets_found(struct nfc_dev *dev, struct nfc_target *targets,
248 int n_targets)
249{
250 int i;
251
252 nfc_dbg("dev_name=%s n_targets=%d", dev_name(&dev->dev), n_targets);
253
254 dev->polling = false;
255
256 for (i = 0; i < n_targets; i++)
257 targets[i].idx = dev->target_idx++;
258
259 spin_lock_bh(&dev->targets_lock);
260
261 dev->targets_generation++;
262
263 kfree(dev->targets);
264 dev->targets = kmemdup(targets, n_targets * sizeof(struct nfc_target),
265 GFP_ATOMIC);
266
267 if (!dev->targets) {
268 dev->n_targets = 0;
269 spin_unlock_bh(&dev->targets_lock);
270 return -ENOMEM;
271 }
272
273 dev->n_targets = n_targets;
274 spin_unlock_bh(&dev->targets_lock);
275
276 nfc_genl_targets_found(dev);
277
278 return 0;
279}
280EXPORT_SYMBOL(nfc_targets_found);
281
236static void nfc_release(struct device *d) 282static void nfc_release(struct device *d)
237{ 283{
238 struct nfc_dev *dev = to_nfc_dev(d); 284 struct nfc_dev *dev = to_nfc_dev(d);
239 285
240 nfc_dbg("dev_name=%s", dev_name(&dev->dev)); 286 nfc_dbg("dev_name=%s", dev_name(&dev->dev));
241 287
288 nfc_genl_data_exit(&dev->genl_data);
289 kfree(dev->targets);
242 kfree(dev); 290 kfree(dev);
243} 291}
244 292
@@ -298,6 +346,12 @@ struct nfc_dev *nfc_allocate_device(struct nfc_ops *ops,
298 dev->ops = ops; 346 dev->ops = ops;
299 dev->supported_protocols = supported_protocols; 347 dev->supported_protocols = supported_protocols;
300 348
349 spin_lock_init(&dev->targets_lock);
350 nfc_genl_data_init(&dev->genl_data);
351
352 /* first generation must not be 0 */
353 dev->targets_generation = 1;
354
301 return dev; 355 return dev;
302} 356}
303EXPORT_SYMBOL(nfc_allocate_device); 357EXPORT_SYMBOL(nfc_allocate_device);
@@ -318,7 +372,16 @@ int nfc_register_device(struct nfc_dev *dev)
318 rc = device_add(&dev->dev); 372 rc = device_add(&dev->dev);
319 mutex_unlock(&nfc_devlist_mutex); 373 mutex_unlock(&nfc_devlist_mutex);
320 374
321 return rc; 375 if (rc < 0)
376 return rc;
377
378 rc = nfc_genl_device_added(dev);
379 if (rc)
380 nfc_dbg("The userspace won't be notified that the device %s was"
381 " added", dev_name(&dev->dev));
382
383
384 return 0;
322} 385}
323EXPORT_SYMBOL(nfc_register_device); 386EXPORT_SYMBOL(nfc_register_device);
324 387
@@ -329,6 +392,8 @@ EXPORT_SYMBOL(nfc_register_device);
329 */ 392 */
330void nfc_unregister_device(struct nfc_dev *dev) 393void nfc_unregister_device(struct nfc_dev *dev)
331{ 394{
395 int rc;
396
332 nfc_dbg("dev_name=%s", dev_name(&dev->dev)); 397 nfc_dbg("dev_name=%s", dev_name(&dev->dev));
333 398
334 mutex_lock(&nfc_devlist_mutex); 399 mutex_lock(&nfc_devlist_mutex);
@@ -341,18 +406,42 @@ void nfc_unregister_device(struct nfc_dev *dev)
341 device_unlock(&dev->dev); 406 device_unlock(&dev->dev);
342 407
343 mutex_unlock(&nfc_devlist_mutex); 408 mutex_unlock(&nfc_devlist_mutex);
409
410 rc = nfc_genl_device_removed(dev);
411 if (rc)
412 nfc_dbg("The userspace won't be notified that the device %s"
413 " was removed", dev_name(&dev->dev));
414
344} 415}
345EXPORT_SYMBOL(nfc_unregister_device); 416EXPORT_SYMBOL(nfc_unregister_device);
346 417
347static int __init nfc_init(void) 418static int __init nfc_init(void)
348{ 419{
420 int rc;
421
349 nfc_info("NFC Core ver %s", VERSION); 422 nfc_info("NFC Core ver %s", VERSION);
350 423
351 return class_register(&nfc_class); 424 rc = class_register(&nfc_class);
425 if (rc)
426 return rc;
427
428 rc = nfc_genl_init();
429 if (rc)
430 goto err_genl;
431
432 /* the first generation must not be 0 */
433 nfc_devlist_generation = 1;
434
435 return 0;
436
437err_genl:
438 class_unregister(&nfc_class);
439 return rc;
352} 440}
353 441
354static void __exit nfc_exit(void) 442static void __exit nfc_exit(void)
355{ 443{
444 nfc_genl_exit();
356 class_unregister(&nfc_class); 445 class_unregister(&nfc_class);
357} 446}
358 447
diff --git a/net/nfc/netlink.c b/net/nfc/netlink.c
new file mode 100644
index 000000000000..ccdff7953f7d
--- /dev/null
+++ b/net/nfc/netlink.c
@@ -0,0 +1,537 @@
1/*
2 * Copyright (C) 2011 Instituto Nokia de Tecnologia
3 *
4 * Authors:
5 * Lauro Ramos Venancio <lauro.venancio@openbossa.org>
6 * Aloisio Almeida Jr <aloisio.almeida@openbossa.org>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the
20 * Free Software Foundation, Inc.,
21 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 */
23
24#include <net/genetlink.h>
25#include <linux/nfc.h>
26#include <linux/slab.h>
27
28#include "nfc.h"
29
30static struct genl_multicast_group nfc_genl_event_mcgrp = {
31 .name = NFC_GENL_MCAST_EVENT_NAME,
32};
33
34struct genl_family nfc_genl_family = {
35 .id = GENL_ID_GENERATE,
36 .hdrsize = 0,
37 .name = NFC_GENL_NAME,
38 .version = NFC_GENL_VERSION,
39 .maxattr = NFC_ATTR_MAX,
40};
41
42static const struct nla_policy nfc_genl_policy[NFC_ATTR_MAX + 1] = {
43 [NFC_ATTR_DEVICE_INDEX] = { .type = NLA_U32 },
44 [NFC_ATTR_DEVICE_NAME] = { .type = NLA_STRING,
45 .len = NFC_DEVICE_NAME_MAXSIZE },
46 [NFC_ATTR_PROTOCOLS] = { .type = NLA_U32 },
47};
48
49static int nfc_genl_send_target(struct sk_buff *msg, struct nfc_target *target,
50 struct netlink_callback *cb, int flags)
51{
52 void *hdr;
53
54 nfc_dbg("entry");
55
56 hdr = genlmsg_put(msg, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq,
57 &nfc_genl_family, flags, NFC_CMD_GET_TARGET);
58 if (!hdr)
59 return -EMSGSIZE;
60
61 genl_dump_check_consistent(cb, hdr, &nfc_genl_family);
62
63 NLA_PUT_U32(msg, NFC_ATTR_TARGET_INDEX, target->idx);
64 NLA_PUT_U32(msg, NFC_ATTR_PROTOCOLS,
65 target->supported_protocols);
66 NLA_PUT_U16(msg, NFC_ATTR_TARGET_SENS_RES, target->sens_res);
67 NLA_PUT_U8(msg, NFC_ATTR_TARGET_SEL_RES, target->sel_res);
68
69 return genlmsg_end(msg, hdr);
70
71nla_put_failure:
72 genlmsg_cancel(msg, hdr);
73 return -EMSGSIZE;
74}
75
76static struct nfc_dev *__get_device_from_cb(struct netlink_callback *cb)
77{
78 struct nfc_dev *dev;
79 int rc;
80 u32 idx;
81
82 rc = nlmsg_parse(cb->nlh, GENL_HDRLEN + nfc_genl_family.hdrsize,
83 nfc_genl_family.attrbuf,
84 nfc_genl_family.maxattr,
85 nfc_genl_policy);
86 if (rc < 0)
87 return ERR_PTR(rc);
88
89 if (!nfc_genl_family.attrbuf[NFC_ATTR_DEVICE_INDEX])
90 return ERR_PTR(-EINVAL);
91
92 idx = nla_get_u32(nfc_genl_family.attrbuf[NFC_ATTR_DEVICE_INDEX]);
93
94 dev = nfc_get_device(idx);
95 if (!dev)
96 return ERR_PTR(-ENODEV);
97
98 return dev;
99}
100
101static int nfc_genl_dump_targets(struct sk_buff *skb,
102 struct netlink_callback *cb)
103{
104 int i = cb->args[0];
105 struct nfc_dev *dev = (struct nfc_dev *) cb->args[1];
106 int rc;
107
108 nfc_dbg("entry");
109
110 if (!dev) {
111 dev = __get_device_from_cb(cb);
112 if (IS_ERR(dev))
113 return PTR_ERR(dev);
114
115 cb->args[1] = (long) dev;
116 }
117
118 spin_lock_bh(&dev->targets_lock);
119
120 cb->seq = dev->targets_generation;
121
122 while (i < dev->n_targets) {
123 rc = nfc_genl_send_target(skb, &dev->targets[i], cb,
124 NLM_F_MULTI);
125 if (rc < 0)
126 break;
127
128 i++;
129 }
130
131 spin_unlock_bh(&dev->targets_lock);
132
133 cb->args[0] = i;
134
135 return skb->len;
136}
137
138static int nfc_genl_dump_targets_done(struct netlink_callback *cb)
139{
140 struct nfc_dev *dev = (struct nfc_dev *) cb->args[1];
141
142 nfc_dbg("entry");
143
144 if (dev)
145 nfc_put_device(dev);
146
147 return 0;
148}
149
150int nfc_genl_targets_found(struct nfc_dev *dev)
151{
152 struct sk_buff *msg;
153 void *hdr;
154
155 nfc_dbg("entry");
156
157 dev->genl_data.poll_req_pid = 0;
158
159 msg = nlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC);
160 if (!msg)
161 return -ENOMEM;
162
163 hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0,
164 NFC_EVENT_TARGETS_FOUND);
165 if (!hdr)
166 goto free_msg;
167
168 NLA_PUT_U32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx);
169
170 genlmsg_end(msg, hdr);
171
172 return genlmsg_multicast(msg, 0, nfc_genl_event_mcgrp.id, GFP_ATOMIC);
173
174nla_put_failure:
175 genlmsg_cancel(msg, hdr);
176free_msg:
177 nlmsg_free(msg);
178 return -EMSGSIZE;
179}
180
181int nfc_genl_device_added(struct nfc_dev *dev)
182{
183 struct sk_buff *msg;
184 void *hdr;
185
186 nfc_dbg("entry");
187
188 msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
189 if (!msg)
190 return -ENOMEM;
191
192 hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0,
193 NFC_EVENT_DEVICE_ADDED);
194 if (!hdr)
195 goto free_msg;
196
197 NLA_PUT_STRING(msg, NFC_ATTR_DEVICE_NAME, nfc_device_name(dev));
198 NLA_PUT_U32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx);
199 NLA_PUT_U32(msg, NFC_ATTR_PROTOCOLS, dev->supported_protocols);
200
201 genlmsg_end(msg, hdr);
202
203 genlmsg_multicast(msg, 0, nfc_genl_event_mcgrp.id, GFP_KERNEL);
204
205 return 0;
206
207nla_put_failure:
208 genlmsg_cancel(msg, hdr);
209free_msg:
210 nlmsg_free(msg);
211 return -EMSGSIZE;
212}
213
214int nfc_genl_device_removed(struct nfc_dev *dev)
215{
216 struct sk_buff *msg;
217 void *hdr;
218
219 nfc_dbg("entry");
220
221 msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
222 if (!msg)
223 return -ENOMEM;
224
225 hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0,
226 NFC_EVENT_DEVICE_REMOVED);
227 if (!hdr)
228 goto free_msg;
229
230 NLA_PUT_U32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx);
231
232 genlmsg_end(msg, hdr);
233
234 genlmsg_multicast(msg, 0, nfc_genl_event_mcgrp.id, GFP_KERNEL);
235
236 return 0;
237
238nla_put_failure:
239 genlmsg_cancel(msg, hdr);
240free_msg:
241 nlmsg_free(msg);
242 return -EMSGSIZE;
243}
244
245static int nfc_genl_send_device(struct sk_buff *msg, struct nfc_dev *dev,
246 u32 pid, u32 seq,
247 struct netlink_callback *cb,
248 int flags)
249{
250 void *hdr;
251
252 nfc_dbg("entry");
253
254 hdr = genlmsg_put(msg, pid, seq, &nfc_genl_family, flags,
255 NFC_CMD_GET_DEVICE);
256 if (!hdr)
257 return -EMSGSIZE;
258
259 if (cb)
260 genl_dump_check_consistent(cb, hdr, &nfc_genl_family);
261
262 NLA_PUT_STRING(msg, NFC_ATTR_DEVICE_NAME, nfc_device_name(dev));
263 NLA_PUT_U32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx);
264 NLA_PUT_U32(msg, NFC_ATTR_PROTOCOLS, dev->supported_protocols);
265
266 return genlmsg_end(msg, hdr);
267
268nla_put_failure:
269 genlmsg_cancel(msg, hdr);
270 return -EMSGSIZE;
271}
272
273static int nfc_genl_dump_devices(struct sk_buff *skb,
274 struct netlink_callback *cb)
275{
276 struct class_dev_iter *iter = (struct class_dev_iter *) cb->args[0];
277 struct nfc_dev *dev = (struct nfc_dev *) cb->args[1];
278 bool first_call = false;
279
280 nfc_dbg("entry");
281
282 if (!iter) {
283 first_call = true;
284 iter = kmalloc(sizeof(struct class_dev_iter), GFP_KERNEL);
285 if (!iter)
286 return -ENOMEM;
287 cb->args[0] = (long) iter;
288 }
289
290 mutex_lock(&nfc_devlist_mutex);
291
292 cb->seq = nfc_devlist_generation;
293
294 if (first_call) {
295 nfc_device_iter_init(iter);
296 dev = nfc_device_iter_next(iter);
297 }
298
299 while (dev) {
300 int rc;
301
302 rc = nfc_genl_send_device(skb, dev, NETLINK_CB(cb->skb).pid,
303 cb->nlh->nlmsg_seq,
304 cb, NLM_F_MULTI);
305 if (rc < 0)
306 break;
307
308 dev = nfc_device_iter_next(iter);
309 }
310
311 mutex_unlock(&nfc_devlist_mutex);
312
313 cb->args[1] = (long) dev;
314
315 return skb->len;
316}
317
318static int nfc_genl_dump_devices_done(struct netlink_callback *cb)
319{
320 struct class_dev_iter *iter = (struct class_dev_iter *) cb->args[0];
321
322 nfc_dbg("entry");
323
324 nfc_device_iter_exit(iter);
325 kfree(iter);
326
327 return 0;
328}
329
330static int nfc_genl_get_device(struct sk_buff *skb, struct genl_info *info)
331{
332 struct sk_buff *msg;
333 struct nfc_dev *dev;
334 u32 idx;
335 int rc = -ENOBUFS;
336
337 nfc_dbg("entry");
338
339 if (!info->attrs[NFC_ATTR_DEVICE_INDEX])
340 return -EINVAL;
341
342 idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]);
343
344 dev = nfc_get_device(idx);
345 if (!dev)
346 return -ENODEV;
347
348 msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
349 if (!msg) {
350 rc = -ENOMEM;
351 goto out_putdev;
352 }
353
354 rc = nfc_genl_send_device(msg, dev, info->snd_pid, info->snd_seq,
355 NULL, 0);
356 if (rc < 0)
357 goto out_free;
358
359 nfc_put_device(dev);
360
361 return genlmsg_reply(msg, info);
362
363out_free:
364 nlmsg_free(msg);
365out_putdev:
366 nfc_put_device(dev);
367 return rc;
368}
369
370static int nfc_genl_start_poll(struct sk_buff *skb, struct genl_info *info)
371{
372 struct nfc_dev *dev;
373 int rc;
374 u32 idx;
375 u32 protocols;
376
377 nfc_dbg("entry");
378
379 if (!info->attrs[NFC_ATTR_DEVICE_INDEX] ||
380 !info->attrs[NFC_ATTR_PROTOCOLS])
381 return -EINVAL;
382
383 idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]);
384 protocols = nla_get_u32(info->attrs[NFC_ATTR_PROTOCOLS]);
385
386 dev = nfc_get_device(idx);
387 if (!dev)
388 return -ENODEV;
389
390 mutex_lock(&dev->genl_data.genl_data_mutex);
391
392 rc = nfc_start_poll(dev, protocols);
393 if (!rc)
394 dev->genl_data.poll_req_pid = info->snd_pid;
395
396 mutex_unlock(&dev->genl_data.genl_data_mutex);
397
398 nfc_put_device(dev);
399 return rc;
400}
401
402static int nfc_genl_stop_poll(struct sk_buff *skb, struct genl_info *info)
403{
404 struct nfc_dev *dev;
405 int rc;
406 u32 idx;
407
408 nfc_dbg("entry");
409
410 if (!info->attrs[NFC_ATTR_DEVICE_INDEX])
411 return -EINVAL;
412
413 idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]);
414
415 dev = nfc_get_device(idx);
416 if (!dev)
417 return -ENODEV;
418
419 mutex_lock(&dev->genl_data.genl_data_mutex);
420
421 if (dev->genl_data.poll_req_pid != info->snd_pid) {
422 rc = -EBUSY;
423 goto out;
424 }
425
426 rc = nfc_stop_poll(dev);
427 dev->genl_data.poll_req_pid = 0;
428
429out:
430 mutex_unlock(&dev->genl_data.genl_data_mutex);
431 nfc_put_device(dev);
432 return rc;
433}
434
435static struct genl_ops nfc_genl_ops[] = {
436 {
437 .cmd = NFC_CMD_GET_DEVICE,
438 .doit = nfc_genl_get_device,
439 .dumpit = nfc_genl_dump_devices,
440 .done = nfc_genl_dump_devices_done,
441 .policy = nfc_genl_policy,
442 },
443 {
444 .cmd = NFC_CMD_START_POLL,
445 .doit = nfc_genl_start_poll,
446 .policy = nfc_genl_policy,
447 },
448 {
449 .cmd = NFC_CMD_STOP_POLL,
450 .doit = nfc_genl_stop_poll,
451 .policy = nfc_genl_policy,
452 },
453 {
454 .cmd = NFC_CMD_GET_TARGET,
455 .dumpit = nfc_genl_dump_targets,
456 .done = nfc_genl_dump_targets_done,
457 .policy = nfc_genl_policy,
458 },
459};
460
461static int nfc_genl_rcv_nl_event(struct notifier_block *this,
462 unsigned long event, void *ptr)
463{
464 struct netlink_notify *n = ptr;
465 struct class_dev_iter iter;
466 struct nfc_dev *dev;
467
468 if (event != NETLINK_URELEASE || n->protocol != NETLINK_GENERIC)
469 goto out;
470
471 nfc_dbg("NETLINK_URELEASE event from id %d", n->pid);
472
473 nfc_device_iter_init(&iter);
474 dev = nfc_device_iter_next(&iter);
475
476 while (dev) {
477 mutex_lock(&dev->genl_data.genl_data_mutex);
478 if (dev->genl_data.poll_req_pid == n->pid) {
479 nfc_stop_poll(dev);
480 dev->genl_data.poll_req_pid = 0;
481 }
482 mutex_unlock(&dev->genl_data.genl_data_mutex);
483 dev = nfc_device_iter_next(&iter);
484 }
485
486 nfc_device_iter_exit(&iter);
487
488out:
489 return NOTIFY_DONE;
490}
491
492void nfc_genl_data_init(struct nfc_genl_data *genl_data)
493{
494 genl_data->poll_req_pid = 0;
495 mutex_init(&genl_data->genl_data_mutex);
496}
497
498void nfc_genl_data_exit(struct nfc_genl_data *genl_data)
499{
500 mutex_destroy(&genl_data->genl_data_mutex);
501}
502
503static struct notifier_block nl_notifier = {
504 .notifier_call = nfc_genl_rcv_nl_event,
505};
506
507/**
508 * nfc_genl_init() - Initialize netlink interface
509 *
510 * This initialization function registers the nfc netlink family.
511 */
512int __init nfc_genl_init(void)
513{
514 int rc;
515
516 rc = genl_register_family_with_ops(&nfc_genl_family, nfc_genl_ops,
517 ARRAY_SIZE(nfc_genl_ops));
518 if (rc)
519 return rc;
520
521 rc = genl_register_mc_group(&nfc_genl_family, &nfc_genl_event_mcgrp);
522
523 netlink_register_notifier(&nl_notifier);
524
525 return rc;
526}
527
528/**
529 * nfc_genl_exit() - Deinitialize netlink interface
530 *
531 * This exit function unregisters the nfc netlink family.
532 */
533void nfc_genl_exit(void)
534{
535 netlink_unregister_notifier(&nl_notifier);
536 genl_unregister_family(&nfc_genl_family);
537}
diff --git a/net/nfc/nfc.h b/net/nfc/nfc.h
index 55f83f86fe2c..2b31e808e6fb 100644
--- a/net/nfc/nfc.h
+++ b/net/nfc/nfc.h
@@ -36,6 +36,17 @@ int nfc_printk(const char *level, const char *fmt, ...);
36extern int nfc_devlist_generation; 36extern int nfc_devlist_generation;
37extern struct mutex nfc_devlist_mutex; 37extern struct mutex nfc_devlist_mutex;
38 38
39int __init nfc_genl_init(void);
40void nfc_genl_exit(void);
41
42void nfc_genl_data_init(struct nfc_genl_data *genl_data);
43void nfc_genl_data_exit(struct nfc_genl_data *genl_data);
44
45int nfc_genl_targets_found(struct nfc_dev *dev);
46
47int nfc_genl_device_added(struct nfc_dev *dev);
48int nfc_genl_device_removed(struct nfc_dev *dev);
49
39struct nfc_dev *nfc_get_device(unsigned idx); 50struct nfc_dev *nfc_get_device(unsigned idx);
40 51
41static inline void nfc_put_device(struct nfc_dev *dev) 52static inline void nfc_put_device(struct nfc_dev *dev)