blob: 1deadad9a285bdb61d842fe6c237452b986b53dd [file] [log] [blame]
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -03001/*
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
Samuel Ortiz52858b52011-12-14 16:43:05 +010024#define pr_fmt(fmt) KBUILD_MODNAME ": %s: " fmt, __func__
Joe Perches20c239c2011-11-29 11:37:33 -080025
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -030026#include <net/genetlink.h>
27#include <linux/nfc.h>
28#include <linux/slab.h>
29
30#include "nfc.h"
Samuel Ortiz30cc4582013-04-26 11:49:40 +020031#include "llcp.h"
Thierry Escande52feb442012-10-17 14:43:39 +020032
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -030033static struct genl_multicast_group nfc_genl_event_mcgrp = {
34 .name = NFC_GENL_MCAST_EVENT_NAME,
35};
36
H Hartley Sweetene5fe4cf2012-05-07 12:31:28 +020037static struct genl_family nfc_genl_family = {
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -030038 .id = GENL_ID_GENERATE,
39 .hdrsize = 0,
40 .name = NFC_GENL_NAME,
41 .version = NFC_GENL_VERSION,
42 .maxattr = NFC_ATTR_MAX,
43};
44
45static const struct nla_policy nfc_genl_policy[NFC_ATTR_MAX + 1] = {
46 [NFC_ATTR_DEVICE_INDEX] = { .type = NLA_U32 },
47 [NFC_ATTR_DEVICE_NAME] = { .type = NLA_STRING,
48 .len = NFC_DEVICE_NAME_MAXSIZE },
49 [NFC_ATTR_PROTOCOLS] = { .type = NLA_U32 },
Samuel Ortiz1ed28f62011-12-14 16:43:09 +010050 [NFC_ATTR_COMM_MODE] = { .type = NLA_U8 },
51 [NFC_ATTR_RF_MODE] = { .type = NLA_U8 },
Samuel Ortizc970a1a2012-03-05 01:03:34 +010052 [NFC_ATTR_DEVICE_POWERED] = { .type = NLA_U8 },
Samuel Ortizfe7c5802012-05-15 15:57:06 +020053 [NFC_ATTR_IM_PROTOCOLS] = { .type = NLA_U32 },
54 [NFC_ATTR_TM_PROTOCOLS] = { .type = NLA_U32 },
Thierry Escande8af362d2013-02-15 10:42:52 +010055 [NFC_ATTR_LLC_PARAM_LTO] = { .type = NLA_U8 },
56 [NFC_ATTR_LLC_PARAM_RW] = { .type = NLA_U8 },
57 [NFC_ATTR_LLC_PARAM_MIUX] = { .type = NLA_U16 },
Thierry Escanded9b8d8e2013-02-15 10:43:06 +010058 [NFC_ATTR_LLC_SDP] = { .type = NLA_NESTED },
Eric Lapuyade9674da82013-04-29 17:13:27 +020059 [NFC_ATTR_FIRMWARE_NAME] = { .type = NLA_STRING,
60 .len = NFC_FIRMWARE_NAME_MAXSIZE },
Thierry Escanded9b8d8e2013-02-15 10:43:06 +010061};
62
63static const struct nla_policy nfc_sdp_genl_policy[NFC_SDP_ATTR_MAX + 1] = {
64 [NFC_SDP_ATTR_URI] = { .type = NLA_STRING },
65 [NFC_SDP_ATTR_SAP] = { .type = NLA_U8 },
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -030066};
67
68static int nfc_genl_send_target(struct sk_buff *msg, struct nfc_target *target,
Samuel Ortiz0a40acb2012-03-05 01:03:53 +010069 struct netlink_callback *cb, int flags)
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -030070{
71 void *hdr;
72
Eric W. Biederman15e47302012-09-07 20:12:54 +000073 hdr = genlmsg_put(msg, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
Samuel Ortiz0a40acb2012-03-05 01:03:53 +010074 &nfc_genl_family, flags, NFC_CMD_GET_TARGET);
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -030075 if (!hdr)
76 return -EMSGSIZE;
77
78 genl_dump_check_consistent(cb, hdr, &nfc_genl_family);
79
David S. Miller1e6428d2012-03-29 23:23:57 -040080 if (nla_put_u32(msg, NFC_ATTR_TARGET_INDEX, target->idx) ||
81 nla_put_u32(msg, NFC_ATTR_PROTOCOLS, target->supported_protocols) ||
82 nla_put_u16(msg, NFC_ATTR_TARGET_SENS_RES, target->sens_res) ||
83 nla_put_u8(msg, NFC_ATTR_TARGET_SEL_RES, target->sel_res))
84 goto nla_put_failure;
85 if (target->nfcid1_len > 0 &&
86 nla_put(msg, NFC_ATTR_TARGET_NFCID1, target->nfcid1_len,
87 target->nfcid1))
88 goto nla_put_failure;
89 if (target->sensb_res_len > 0 &&
90 nla_put(msg, NFC_ATTR_TARGET_SENSB_RES, target->sensb_res_len,
91 target->sensb_res))
92 goto nla_put_failure;
93 if (target->sensf_res_len > 0 &&
94 nla_put(msg, NFC_ATTR_TARGET_SENSF_RES, target->sensf_res_len,
95 target->sensf_res))
96 goto nla_put_failure;
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -030097
98 return genlmsg_end(msg, hdr);
99
100nla_put_failure:
101 genlmsg_cancel(msg, hdr);
102 return -EMSGSIZE;
103}
104
105static struct nfc_dev *__get_device_from_cb(struct netlink_callback *cb)
106{
107 struct nfc_dev *dev;
108 int rc;
109 u32 idx;
110
111 rc = nlmsg_parse(cb->nlh, GENL_HDRLEN + nfc_genl_family.hdrsize,
Samuel Ortiz0a40acb2012-03-05 01:03:53 +0100112 nfc_genl_family.attrbuf,
113 nfc_genl_family.maxattr,
114 nfc_genl_policy);
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300115 if (rc < 0)
116 return ERR_PTR(rc);
117
118 if (!nfc_genl_family.attrbuf[NFC_ATTR_DEVICE_INDEX])
119 return ERR_PTR(-EINVAL);
120
121 idx = nla_get_u32(nfc_genl_family.attrbuf[NFC_ATTR_DEVICE_INDEX]);
122
123 dev = nfc_get_device(idx);
124 if (!dev)
125 return ERR_PTR(-ENODEV);
126
127 return dev;
128}
129
130static int nfc_genl_dump_targets(struct sk_buff *skb,
Samuel Ortiz0a40acb2012-03-05 01:03:53 +0100131 struct netlink_callback *cb)
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300132{
133 int i = cb->args[0];
134 struct nfc_dev *dev = (struct nfc_dev *) cb->args[1];
135 int rc;
136
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300137 if (!dev) {
138 dev = __get_device_from_cb(cb);
139 if (IS_ERR(dev))
140 return PTR_ERR(dev);
141
142 cb->args[1] = (long) dev;
143 }
144
Eric Lapuyaded4ccb132012-05-07 12:31:15 +0200145 device_lock(&dev->dev);
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300146
147 cb->seq = dev->targets_generation;
148
149 while (i < dev->n_targets) {
150 rc = nfc_genl_send_target(skb, &dev->targets[i], cb,
Samuel Ortiz0a40acb2012-03-05 01:03:53 +0100151 NLM_F_MULTI);
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300152 if (rc < 0)
153 break;
154
155 i++;
156 }
157
Eric Lapuyaded4ccb132012-05-07 12:31:15 +0200158 device_unlock(&dev->dev);
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300159
160 cb->args[0] = i;
161
162 return skb->len;
163}
164
165static int nfc_genl_dump_targets_done(struct netlink_callback *cb)
166{
167 struct nfc_dev *dev = (struct nfc_dev *) cb->args[1];
168
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300169 if (dev)
170 nfc_put_device(dev);
171
172 return 0;
173}
174
175int nfc_genl_targets_found(struct nfc_dev *dev)
176{
177 struct sk_buff *msg;
178 void *hdr;
179
Eric W. Biederman15e47302012-09-07 20:12:54 +0000180 dev->genl_data.poll_req_portid = 0;
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300181
Thomas Graf58050fc2012-06-28 03:57:45 +0000182 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300183 if (!msg)
184 return -ENOMEM;
185
186 hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0,
Samuel Ortiz0a40acb2012-03-05 01:03:53 +0100187 NFC_EVENT_TARGETS_FOUND);
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300188 if (!hdr)
189 goto free_msg;
190
David S. Miller1e6428d2012-03-29 23:23:57 -0400191 if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx))
192 goto nla_put_failure;
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300193
194 genlmsg_end(msg, hdr);
195
196 return genlmsg_multicast(msg, 0, nfc_genl_event_mcgrp.id, GFP_ATOMIC);
197
198nla_put_failure:
199 genlmsg_cancel(msg, hdr);
200free_msg:
201 nlmsg_free(msg);
202 return -EMSGSIZE;
203}
204
Samuel Ortiz8112a5c2012-04-10 19:43:04 +0200205int nfc_genl_target_lost(struct nfc_dev *dev, u32 target_idx)
206{
207 struct sk_buff *msg;
208 void *hdr;
209
Thomas Graf58050fc2012-06-28 03:57:45 +0000210 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Samuel Ortiz8112a5c2012-04-10 19:43:04 +0200211 if (!msg)
212 return -ENOMEM;
213
214 hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0,
215 NFC_EVENT_TARGET_LOST);
216 if (!hdr)
217 goto free_msg;
218
John W. Linville59ef43e2012-04-18 14:17:13 -0400219 if (nla_put_string(msg, NFC_ATTR_DEVICE_NAME, nfc_device_name(dev)) ||
220 nla_put_u32(msg, NFC_ATTR_TARGET_INDEX, target_idx))
221 goto nla_put_failure;
Samuel Ortiz8112a5c2012-04-10 19:43:04 +0200222
223 genlmsg_end(msg, hdr);
224
225 genlmsg_multicast(msg, 0, nfc_genl_event_mcgrp.id, GFP_KERNEL);
226
227 return 0;
228
229nla_put_failure:
230 genlmsg_cancel(msg, hdr);
231free_msg:
232 nlmsg_free(msg);
233 return -EMSGSIZE;
234}
235
Samuel Ortizfc40a8c2012-06-01 13:21:13 +0200236int nfc_genl_tm_activated(struct nfc_dev *dev, u32 protocol)
237{
238 struct sk_buff *msg;
239 void *hdr;
240
Thomas Graf58050fc2012-06-28 03:57:45 +0000241 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Samuel Ortizfc40a8c2012-06-01 13:21:13 +0200242 if (!msg)
243 return -ENOMEM;
244
245 hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0,
246 NFC_EVENT_TM_ACTIVATED);
247 if (!hdr)
248 goto free_msg;
249
250 if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx))
251 goto nla_put_failure;
252 if (nla_put_u32(msg, NFC_ATTR_TM_PROTOCOLS, protocol))
253 goto nla_put_failure;
254
255 genlmsg_end(msg, hdr);
256
257 genlmsg_multicast(msg, 0, nfc_genl_event_mcgrp.id, GFP_KERNEL);
258
259 return 0;
260
261nla_put_failure:
262 genlmsg_cancel(msg, hdr);
263free_msg:
264 nlmsg_free(msg);
265 return -EMSGSIZE;
266}
267
268int nfc_genl_tm_deactivated(struct nfc_dev *dev)
269{
270 struct sk_buff *msg;
271 void *hdr;
272
Thomas Graf58050fc2012-06-28 03:57:45 +0000273 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Samuel Ortizfc40a8c2012-06-01 13:21:13 +0200274 if (!msg)
275 return -ENOMEM;
276
277 hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0,
278 NFC_EVENT_TM_DEACTIVATED);
279 if (!hdr)
280 goto free_msg;
281
282 if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx))
283 goto nla_put_failure;
284
285 genlmsg_end(msg, hdr);
286
287 genlmsg_multicast(msg, 0, nfc_genl_event_mcgrp.id, GFP_KERNEL);
288
289 return 0;
290
291nla_put_failure:
292 genlmsg_cancel(msg, hdr);
293free_msg:
294 nlmsg_free(msg);
295 return -EMSGSIZE;
296}
297
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300298int nfc_genl_device_added(struct nfc_dev *dev)
299{
300 struct sk_buff *msg;
301 void *hdr;
302
Thomas Graf58050fc2012-06-28 03:57:45 +0000303 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300304 if (!msg)
305 return -ENOMEM;
306
307 hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0,
Samuel Ortiz0a40acb2012-03-05 01:03:53 +0100308 NFC_EVENT_DEVICE_ADDED);
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300309 if (!hdr)
310 goto free_msg;
311
David S. Miller1e6428d2012-03-29 23:23:57 -0400312 if (nla_put_string(msg, NFC_ATTR_DEVICE_NAME, nfc_device_name(dev)) ||
313 nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx) ||
314 nla_put_u32(msg, NFC_ATTR_PROTOCOLS, dev->supported_protocols) ||
315 nla_put_u8(msg, NFC_ATTR_DEVICE_POWERED, dev->dev_up))
316 goto nla_put_failure;
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300317
318 genlmsg_end(msg, hdr);
319
320 genlmsg_multicast(msg, 0, nfc_genl_event_mcgrp.id, GFP_KERNEL);
321
322 return 0;
323
324nla_put_failure:
325 genlmsg_cancel(msg, hdr);
326free_msg:
327 nlmsg_free(msg);
328 return -EMSGSIZE;
329}
330
331int nfc_genl_device_removed(struct nfc_dev *dev)
332{
333 struct sk_buff *msg;
334 void *hdr;
335
Thomas Graf58050fc2012-06-28 03:57:45 +0000336 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300337 if (!msg)
338 return -ENOMEM;
339
340 hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0,
Samuel Ortiz0a40acb2012-03-05 01:03:53 +0100341 NFC_EVENT_DEVICE_REMOVED);
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300342 if (!hdr)
343 goto free_msg;
344
David S. Miller1e6428d2012-03-29 23:23:57 -0400345 if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx))
346 goto nla_put_failure;
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300347
348 genlmsg_end(msg, hdr);
349
350 genlmsg_multicast(msg, 0, nfc_genl_event_mcgrp.id, GFP_KERNEL);
351
352 return 0;
353
354nla_put_failure:
355 genlmsg_cancel(msg, hdr);
356free_msg:
357 nlmsg_free(msg);
358 return -EMSGSIZE;
359}
360
Thierry Escanded9b8d8e2013-02-15 10:43:06 +0100361int nfc_genl_llc_send_sdres(struct nfc_dev *dev, struct hlist_head *sdres_list)
362{
363 struct sk_buff *msg;
364 struct nlattr *sdp_attr, *uri_attr;
365 struct nfc_llcp_sdp_tlv *sdres;
366 struct hlist_node *n;
367 void *hdr;
368 int rc = -EMSGSIZE;
369 int i;
370
371 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
372 if (!msg)
373 return -ENOMEM;
374
375 hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0,
376 NFC_EVENT_LLC_SDRES);
377 if (!hdr)
378 goto free_msg;
379
380 if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx))
381 goto nla_put_failure;
382
383 sdp_attr = nla_nest_start(msg, NFC_ATTR_LLC_SDP);
384 if (sdp_attr == NULL) {
385 rc = -ENOMEM;
386 goto nla_put_failure;
387 }
388
389 i = 1;
390 hlist_for_each_entry_safe(sdres, n, sdres_list, node) {
391 pr_debug("uri: %s, sap: %d\n", sdres->uri, sdres->sap);
392
393 uri_attr = nla_nest_start(msg, i++);
394 if (uri_attr == NULL) {
395 rc = -ENOMEM;
396 goto nla_put_failure;
397 }
398
399 if (nla_put_u8(msg, NFC_SDP_ATTR_SAP, sdres->sap))
400 goto nla_put_failure;
401
402 if (nla_put_string(msg, NFC_SDP_ATTR_URI, sdres->uri))
403 goto nla_put_failure;
404
405 nla_nest_end(msg, uri_attr);
406
407 hlist_del(&sdres->node);
408
409 nfc_llcp_free_sdp_tlv(sdres);
410 }
411
412 nla_nest_end(msg, sdp_attr);
413
414 genlmsg_end(msg, hdr);
415
416 return genlmsg_multicast(msg, 0, nfc_genl_event_mcgrp.id, GFP_ATOMIC);
417
418nla_put_failure:
419 genlmsg_cancel(msg, hdr);
420
421free_msg:
422 nlmsg_free(msg);
423
424 nfc_llcp_free_sdp_tlv_list(sdres_list);
425
426 return rc;
427}
428
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300429static int nfc_genl_send_device(struct sk_buff *msg, struct nfc_dev *dev,
Eric W. Biederman15e47302012-09-07 20:12:54 +0000430 u32 portid, u32 seq,
Samuel Ortiz0a40acb2012-03-05 01:03:53 +0100431 struct netlink_callback *cb,
432 int flags)
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300433{
434 void *hdr;
435
Eric W. Biederman15e47302012-09-07 20:12:54 +0000436 hdr = genlmsg_put(msg, portid, seq, &nfc_genl_family, flags,
Samuel Ortiz0a40acb2012-03-05 01:03:53 +0100437 NFC_CMD_GET_DEVICE);
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300438 if (!hdr)
439 return -EMSGSIZE;
440
441 if (cb)
442 genl_dump_check_consistent(cb, hdr, &nfc_genl_family);
443
David S. Miller1e6428d2012-03-29 23:23:57 -0400444 if (nla_put_string(msg, NFC_ATTR_DEVICE_NAME, nfc_device_name(dev)) ||
445 nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx) ||
446 nla_put_u32(msg, NFC_ATTR_PROTOCOLS, dev->supported_protocols) ||
Samuel Ortiz390a1bd2012-12-19 19:11:32 +0100447 nla_put_u32(msg, NFC_ATTR_SE, dev->supported_se) ||
Thierry Escande7ad39392012-10-05 11:19:58 +0200448 nla_put_u8(msg, NFC_ATTR_DEVICE_POWERED, dev->dev_up) ||
449 nla_put_u8(msg, NFC_ATTR_RF_MODE, dev->rf_mode))
David S. Miller1e6428d2012-03-29 23:23:57 -0400450 goto nla_put_failure;
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300451
452 return genlmsg_end(msg, hdr);
453
454nla_put_failure:
455 genlmsg_cancel(msg, hdr);
456 return -EMSGSIZE;
457}
458
459static int nfc_genl_dump_devices(struct sk_buff *skb,
Samuel Ortiz0a40acb2012-03-05 01:03:53 +0100460 struct netlink_callback *cb)
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300461{
462 struct class_dev_iter *iter = (struct class_dev_iter *) cb->args[0];
463 struct nfc_dev *dev = (struct nfc_dev *) cb->args[1];
464 bool first_call = false;
465
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300466 if (!iter) {
467 first_call = true;
468 iter = kmalloc(sizeof(struct class_dev_iter), GFP_KERNEL);
469 if (!iter)
470 return -ENOMEM;
471 cb->args[0] = (long) iter;
472 }
473
474 mutex_lock(&nfc_devlist_mutex);
475
476 cb->seq = nfc_devlist_generation;
477
478 if (first_call) {
479 nfc_device_iter_init(iter);
480 dev = nfc_device_iter_next(iter);
481 }
482
483 while (dev) {
484 int rc;
485
Eric W. Biederman15e47302012-09-07 20:12:54 +0000486 rc = nfc_genl_send_device(skb, dev, NETLINK_CB(cb->skb).portid,
Samuel Ortiz0a40acb2012-03-05 01:03:53 +0100487 cb->nlh->nlmsg_seq, cb, NLM_F_MULTI);
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300488 if (rc < 0)
489 break;
490
491 dev = nfc_device_iter_next(iter);
492 }
493
494 mutex_unlock(&nfc_devlist_mutex);
495
496 cb->args[1] = (long) dev;
497
498 return skb->len;
499}
500
501static int nfc_genl_dump_devices_done(struct netlink_callback *cb)
502{
503 struct class_dev_iter *iter = (struct class_dev_iter *) cb->args[0];
504
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300505 nfc_device_iter_exit(iter);
506 kfree(iter);
507
508 return 0;
509}
510
Samuel Ortiz1ed28f62011-12-14 16:43:09 +0100511int nfc_genl_dep_link_up_event(struct nfc_dev *dev, u32 target_idx,
Samuel Ortiz0a40acb2012-03-05 01:03:53 +0100512 u8 comm_mode, u8 rf_mode)
Samuel Ortiz1ed28f62011-12-14 16:43:09 +0100513{
514 struct sk_buff *msg;
515 void *hdr;
516
517 pr_debug("DEP link is up\n");
518
Thomas Graf58050fc2012-06-28 03:57:45 +0000519 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
Samuel Ortiz1ed28f62011-12-14 16:43:09 +0100520 if (!msg)
521 return -ENOMEM;
522
Samuel Ortiz0a40acb2012-03-05 01:03:53 +0100523 hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0, NFC_CMD_DEP_LINK_UP);
Samuel Ortiz1ed28f62011-12-14 16:43:09 +0100524 if (!hdr)
525 goto free_msg;
526
David S. Miller1e6428d2012-03-29 23:23:57 -0400527 if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx))
528 goto nla_put_failure;
529 if (rf_mode == NFC_RF_INITIATOR &&
530 nla_put_u32(msg, NFC_ATTR_TARGET_INDEX, target_idx))
531 goto nla_put_failure;
532 if (nla_put_u8(msg, NFC_ATTR_COMM_MODE, comm_mode) ||
533 nla_put_u8(msg, NFC_ATTR_RF_MODE, rf_mode))
534 goto nla_put_failure;
Samuel Ortiz1ed28f62011-12-14 16:43:09 +0100535
536 genlmsg_end(msg, hdr);
537
538 dev->dep_link_up = true;
539
540 genlmsg_multicast(msg, 0, nfc_genl_event_mcgrp.id, GFP_ATOMIC);
541
542 return 0;
543
544nla_put_failure:
545 genlmsg_cancel(msg, hdr);
546free_msg:
547 nlmsg_free(msg);
548 return -EMSGSIZE;
549}
550
551int nfc_genl_dep_link_down_event(struct nfc_dev *dev)
552{
553 struct sk_buff *msg;
554 void *hdr;
555
556 pr_debug("DEP link is down\n");
557
Thomas Graf58050fc2012-06-28 03:57:45 +0000558 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
Samuel Ortiz1ed28f62011-12-14 16:43:09 +0100559 if (!msg)
560 return -ENOMEM;
561
562 hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0,
Samuel Ortiz0a40acb2012-03-05 01:03:53 +0100563 NFC_CMD_DEP_LINK_DOWN);
Samuel Ortiz1ed28f62011-12-14 16:43:09 +0100564 if (!hdr)
565 goto free_msg;
566
David S. Miller1e6428d2012-03-29 23:23:57 -0400567 if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx))
568 goto nla_put_failure;
Samuel Ortiz1ed28f62011-12-14 16:43:09 +0100569
570 genlmsg_end(msg, hdr);
571
572 genlmsg_multicast(msg, 0, nfc_genl_event_mcgrp.id, GFP_ATOMIC);
573
574 return 0;
575
576nla_put_failure:
577 genlmsg_cancel(msg, hdr);
578free_msg:
579 nlmsg_free(msg);
580 return -EMSGSIZE;
581}
582
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300583static int nfc_genl_get_device(struct sk_buff *skb, struct genl_info *info)
584{
585 struct sk_buff *msg;
586 struct nfc_dev *dev;
587 u32 idx;
588 int rc = -ENOBUFS;
589
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300590 if (!info->attrs[NFC_ATTR_DEVICE_INDEX])
591 return -EINVAL;
592
593 idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]);
594
595 dev = nfc_get_device(idx);
596 if (!dev)
597 return -ENODEV;
598
Thomas Graf58050fc2012-06-28 03:57:45 +0000599 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300600 if (!msg) {
601 rc = -ENOMEM;
602 goto out_putdev;
603 }
604
Eric W. Biederman15e47302012-09-07 20:12:54 +0000605 rc = nfc_genl_send_device(msg, dev, info->snd_portid, info->snd_seq,
Samuel Ortiz0a40acb2012-03-05 01:03:53 +0100606 NULL, 0);
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300607 if (rc < 0)
608 goto out_free;
609
610 nfc_put_device(dev);
611
612 return genlmsg_reply(msg, info);
613
614out_free:
615 nlmsg_free(msg);
616out_putdev:
617 nfc_put_device(dev);
618 return rc;
619}
620
Ilan Elias8b3fe7b2011-09-18 11:19:33 +0300621static int nfc_genl_dev_up(struct sk_buff *skb, struct genl_info *info)
622{
623 struct nfc_dev *dev;
624 int rc;
625 u32 idx;
626
Ilan Elias8b3fe7b2011-09-18 11:19:33 +0300627 if (!info->attrs[NFC_ATTR_DEVICE_INDEX])
628 return -EINVAL;
629
630 idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]);
631
632 dev = nfc_get_device(idx);
633 if (!dev)
634 return -ENODEV;
635
636 rc = nfc_dev_up(dev);
637
638 nfc_put_device(dev);
639 return rc;
640}
641
642static int nfc_genl_dev_down(struct sk_buff *skb, struct genl_info *info)
643{
644 struct nfc_dev *dev;
645 int rc;
646 u32 idx;
647
Ilan Elias8b3fe7b2011-09-18 11:19:33 +0300648 if (!info->attrs[NFC_ATTR_DEVICE_INDEX])
649 return -EINVAL;
650
651 idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]);
652
653 dev = nfc_get_device(idx);
654 if (!dev)
655 return -ENODEV;
656
657 rc = nfc_dev_down(dev);
658
659 nfc_put_device(dev);
660 return rc;
661}
662
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300663static int nfc_genl_start_poll(struct sk_buff *skb, struct genl_info *info)
664{
665 struct nfc_dev *dev;
666 int rc;
667 u32 idx;
Samuel Ortizfe7c5802012-05-15 15:57:06 +0200668 u32 im_protocols = 0, tm_protocols = 0;
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300669
Samuel Ortiz1ed28f62011-12-14 16:43:09 +0100670 pr_debug("Poll start\n");
671
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300672 if (!info->attrs[NFC_ATTR_DEVICE_INDEX] ||
Samuel Ortizfe7c5802012-05-15 15:57:06 +0200673 ((!info->attrs[NFC_ATTR_IM_PROTOCOLS] &&
674 !info->attrs[NFC_ATTR_PROTOCOLS]) &&
Szymon Janc0f450772012-10-17 15:23:39 +0200675 !info->attrs[NFC_ATTR_TM_PROTOCOLS]))
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300676 return -EINVAL;
677
678 idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]);
Samuel Ortizfe7c5802012-05-15 15:57:06 +0200679
680 if (info->attrs[NFC_ATTR_TM_PROTOCOLS])
681 tm_protocols = nla_get_u32(info->attrs[NFC_ATTR_TM_PROTOCOLS]);
Samuel Ortizfe7c5802012-05-15 15:57:06 +0200682
683 if (info->attrs[NFC_ATTR_IM_PROTOCOLS])
684 im_protocols = nla_get_u32(info->attrs[NFC_ATTR_IM_PROTOCOLS]);
Samuel Ortiz5e50ee32012-05-31 11:48:58 +0200685 else if (info->attrs[NFC_ATTR_PROTOCOLS])
686 im_protocols = nla_get_u32(info->attrs[NFC_ATTR_PROTOCOLS]);
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300687
688 dev = nfc_get_device(idx);
689 if (!dev)
690 return -ENODEV;
691
692 mutex_lock(&dev->genl_data.genl_data_mutex);
693
Samuel Ortizfe7c5802012-05-15 15:57:06 +0200694 rc = nfc_start_poll(dev, im_protocols, tm_protocols);
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300695 if (!rc)
Eric W. Biederman15e47302012-09-07 20:12:54 +0000696 dev->genl_data.poll_req_portid = info->snd_portid;
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300697
698 mutex_unlock(&dev->genl_data.genl_data_mutex);
699
700 nfc_put_device(dev);
701 return rc;
702}
703
704static int nfc_genl_stop_poll(struct sk_buff *skb, struct genl_info *info)
705{
706 struct nfc_dev *dev;
707 int rc;
708 u32 idx;
709
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300710 if (!info->attrs[NFC_ATTR_DEVICE_INDEX])
711 return -EINVAL;
712
713 idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]);
714
715 dev = nfc_get_device(idx);
716 if (!dev)
717 return -ENODEV;
718
Samuel Ortiza831b912012-06-28 16:41:57 +0200719 device_lock(&dev->dev);
720
721 if (!dev->polling) {
722 device_unlock(&dev->dev);
723 return -EINVAL;
724 }
725
726 device_unlock(&dev->dev);
727
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300728 mutex_lock(&dev->genl_data.genl_data_mutex);
729
Eric W. Biederman15e47302012-09-07 20:12:54 +0000730 if (dev->genl_data.poll_req_portid != info->snd_portid) {
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300731 rc = -EBUSY;
732 goto out;
733 }
734
735 rc = nfc_stop_poll(dev);
Eric W. Biederman15e47302012-09-07 20:12:54 +0000736 dev->genl_data.poll_req_portid = 0;
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300737
738out:
739 mutex_unlock(&dev->genl_data.genl_data_mutex);
740 nfc_put_device(dev);
741 return rc;
742}
743
Samuel Ortiz1ed28f62011-12-14 16:43:09 +0100744static int nfc_genl_dep_link_up(struct sk_buff *skb, struct genl_info *info)
745{
746 struct nfc_dev *dev;
747 int rc, tgt_idx;
748 u32 idx;
Samuel Ortiz47807d32012-03-05 01:03:50 +0100749 u8 comm;
Samuel Ortiz1ed28f62011-12-14 16:43:09 +0100750
751 pr_debug("DEP link up\n");
752
753 if (!info->attrs[NFC_ATTR_DEVICE_INDEX] ||
Samuel Ortiz47807d32012-03-05 01:03:50 +0100754 !info->attrs[NFC_ATTR_COMM_MODE])
Samuel Ortiz1ed28f62011-12-14 16:43:09 +0100755 return -EINVAL;
756
757 idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]);
758 if (!info->attrs[NFC_ATTR_TARGET_INDEX])
759 tgt_idx = NFC_TARGET_IDX_ANY;
760 else
761 tgt_idx = nla_get_u32(info->attrs[NFC_ATTR_TARGET_INDEX]);
762
763 comm = nla_get_u8(info->attrs[NFC_ATTR_COMM_MODE]);
Samuel Ortiz1ed28f62011-12-14 16:43:09 +0100764
765 if (comm != NFC_COMM_ACTIVE && comm != NFC_COMM_PASSIVE)
766 return -EINVAL;
767
Samuel Ortiz1ed28f62011-12-14 16:43:09 +0100768 dev = nfc_get_device(idx);
769 if (!dev)
770 return -ENODEV;
771
Samuel Ortiz47807d32012-03-05 01:03:50 +0100772 rc = nfc_dep_link_up(dev, tgt_idx, comm);
Samuel Ortiz1ed28f62011-12-14 16:43:09 +0100773
774 nfc_put_device(dev);
775
776 return rc;
777}
778
779static int nfc_genl_dep_link_down(struct sk_buff *skb, struct genl_info *info)
780{
781 struct nfc_dev *dev;
782 int rc;
783 u32 idx;
784
785 if (!info->attrs[NFC_ATTR_DEVICE_INDEX])
786 return -EINVAL;
787
788 idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]);
789
790 dev = nfc_get_device(idx);
791 if (!dev)
792 return -ENODEV;
793
794 rc = nfc_dep_link_down(dev);
795
796 nfc_put_device(dev);
797 return rc;
798}
799
Thierry Escande52feb442012-10-17 14:43:39 +0200800static int nfc_genl_send_params(struct sk_buff *msg,
801 struct nfc_llcp_local *local,
802 u32 portid, u32 seq)
803{
804 void *hdr;
805
806 hdr = genlmsg_put(msg, portid, seq, &nfc_genl_family, 0,
807 NFC_CMD_LLC_GET_PARAMS);
808 if (!hdr)
809 return -EMSGSIZE;
810
811 if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, local->dev->idx) ||
812 nla_put_u8(msg, NFC_ATTR_LLC_PARAM_LTO, local->lto) ||
813 nla_put_u8(msg, NFC_ATTR_LLC_PARAM_RW, local->rw) ||
814 nla_put_u16(msg, NFC_ATTR_LLC_PARAM_MIUX, be16_to_cpu(local->miux)))
815 goto nla_put_failure;
816
817 return genlmsg_end(msg, hdr);
818
819nla_put_failure:
820
821 genlmsg_cancel(msg, hdr);
822 return -EMSGSIZE;
823}
824
825static int nfc_genl_llc_get_params(struct sk_buff *skb, struct genl_info *info)
826{
827 struct nfc_dev *dev;
828 struct nfc_llcp_local *local;
829 int rc = 0;
830 struct sk_buff *msg = NULL;
831 u32 idx;
832
833 if (!info->attrs[NFC_ATTR_DEVICE_INDEX])
834 return -EINVAL;
835
836 idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]);
837
838 dev = nfc_get_device(idx);
839 if (!dev)
840 return -ENODEV;
841
842 device_lock(&dev->dev);
843
844 local = nfc_llcp_find_local(dev);
845 if (!local) {
846 rc = -ENODEV;
847 goto exit;
848 }
849
850 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
851 if (!msg) {
852 rc = -ENOMEM;
853 goto exit;
854 }
855
856 rc = nfc_genl_send_params(msg, local, info->snd_portid, info->snd_seq);
857
858exit:
859 device_unlock(&dev->dev);
860
861 nfc_put_device(dev);
862
863 if (rc < 0) {
864 if (msg)
865 nlmsg_free(msg);
866
867 return rc;
868 }
869
870 return genlmsg_reply(msg, info);
871}
872
873static int nfc_genl_llc_set_params(struct sk_buff *skb, struct genl_info *info)
874{
875 struct nfc_dev *dev;
876 struct nfc_llcp_local *local;
877 u8 rw = 0;
878 u16 miux = 0;
879 u32 idx;
880 int rc = 0;
881
882 if (!info->attrs[NFC_ATTR_DEVICE_INDEX] ||
883 (!info->attrs[NFC_ATTR_LLC_PARAM_LTO] &&
884 !info->attrs[NFC_ATTR_LLC_PARAM_RW] &&
885 !info->attrs[NFC_ATTR_LLC_PARAM_MIUX]))
886 return -EINVAL;
887
888 if (info->attrs[NFC_ATTR_LLC_PARAM_RW]) {
889 rw = nla_get_u8(info->attrs[NFC_ATTR_LLC_PARAM_RW]);
890
891 if (rw > LLCP_MAX_RW)
892 return -EINVAL;
893 }
894
895 if (info->attrs[NFC_ATTR_LLC_PARAM_MIUX]) {
896 miux = nla_get_u16(info->attrs[NFC_ATTR_LLC_PARAM_MIUX]);
897
898 if (miux > LLCP_MAX_MIUX)
899 return -EINVAL;
900 }
901
902 idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]);
903
904 dev = nfc_get_device(idx);
905 if (!dev)
906 return -ENODEV;
907
908 device_lock(&dev->dev);
909
910 local = nfc_llcp_find_local(dev);
911 if (!local) {
912 nfc_put_device(dev);
913 rc = -ENODEV;
914 goto exit;
915 }
916
917 if (info->attrs[NFC_ATTR_LLC_PARAM_LTO]) {
918 if (dev->dep_link_up) {
919 rc = -EINPROGRESS;
920 goto exit;
921 }
922
923 local->lto = nla_get_u8(info->attrs[NFC_ATTR_LLC_PARAM_LTO]);
924 }
925
926 if (info->attrs[NFC_ATTR_LLC_PARAM_RW])
927 local->rw = rw;
928
929 if (info->attrs[NFC_ATTR_LLC_PARAM_MIUX])
930 local->miux = cpu_to_be16(miux);
931
932exit:
933 device_unlock(&dev->dev);
934
935 nfc_put_device(dev);
936
937 return rc;
938}
939
Thierry Escanded9b8d8e2013-02-15 10:43:06 +0100940static int nfc_genl_llc_sdreq(struct sk_buff *skb, struct genl_info *info)
941{
942 struct nfc_dev *dev;
943 struct nfc_llcp_local *local;
944 struct nlattr *attr, *sdp_attrs[NFC_SDP_ATTR_MAX+1];
945 u32 idx;
946 u8 tid;
947 char *uri;
948 int rc = 0, rem;
949 size_t uri_len, tlvs_len;
950 struct hlist_head sdreq_list;
951 struct nfc_llcp_sdp_tlv *sdreq;
952
953 if (!info->attrs[NFC_ATTR_DEVICE_INDEX] ||
954 !info->attrs[NFC_ATTR_LLC_SDP])
955 return -EINVAL;
956
957 idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]);
958
959 dev = nfc_get_device(idx);
960 if (!dev) {
961 rc = -ENODEV;
962 goto exit;
963 }
964
965 device_lock(&dev->dev);
966
967 if (dev->dep_link_up == false) {
968 rc = -ENOLINK;
969 goto exit;
970 }
971
972 local = nfc_llcp_find_local(dev);
973 if (!local) {
974 nfc_put_device(dev);
975 rc = -ENODEV;
976 goto exit;
977 }
978
979 INIT_HLIST_HEAD(&sdreq_list);
980
981 tlvs_len = 0;
982
983 nla_for_each_nested(attr, info->attrs[NFC_ATTR_LLC_SDP], rem) {
984 rc = nla_parse_nested(sdp_attrs, NFC_SDP_ATTR_MAX, attr,
985 nfc_sdp_genl_policy);
986
987 if (rc != 0) {
988 rc = -EINVAL;
989 goto exit;
990 }
991
992 if (!sdp_attrs[NFC_SDP_ATTR_URI])
993 continue;
994
995 uri_len = nla_len(sdp_attrs[NFC_SDP_ATTR_URI]);
996 if (uri_len == 0)
997 continue;
998
999 uri = nla_data(sdp_attrs[NFC_SDP_ATTR_URI]);
1000 if (uri == NULL || *uri == 0)
1001 continue;
1002
1003 tid = local->sdreq_next_tid++;
1004
1005 sdreq = nfc_llcp_build_sdreq_tlv(tid, uri, uri_len);
1006 if (sdreq == NULL) {
1007 rc = -ENOMEM;
1008 goto exit;
1009 }
1010
1011 tlvs_len += sdreq->tlv_len;
1012
1013 hlist_add_head(&sdreq->node, &sdreq_list);
1014 }
1015
1016 if (hlist_empty(&sdreq_list)) {
1017 rc = -EINVAL;
1018 goto exit;
1019 }
1020
1021 rc = nfc_llcp_send_snl_sdreq(local, &sdreq_list, tlvs_len);
1022exit:
1023 device_unlock(&dev->dev);
1024
1025 nfc_put_device(dev);
1026
1027 return rc;
1028}
1029
Eric Lapuyade9674da82013-04-29 17:13:27 +02001030static int nfc_genl_fw_upload(struct sk_buff *skb, struct genl_info *info)
1031{
1032 struct nfc_dev *dev;
1033 int rc;
1034 u32 idx;
1035 char firmware_name[NFC_FIRMWARE_NAME_MAXSIZE + 1];
1036
1037 if (!info->attrs[NFC_ATTR_DEVICE_INDEX])
1038 return -EINVAL;
1039
1040 idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]);
1041
1042 dev = nfc_get_device(idx);
1043 if (!dev)
1044 return -ENODEV;
1045
1046 nla_strlcpy(firmware_name, info->attrs[NFC_ATTR_FIRMWARE_NAME],
1047 sizeof(firmware_name));
1048
1049 rc = nfc_fw_upload(dev, firmware_name);
1050
1051 nfc_put_device(dev);
1052 return rc;
1053}
1054
1055int nfc_genl_fw_upload_done(struct nfc_dev *dev, const char *firmware_name)
1056{
1057 struct sk_buff *msg;
1058 void *hdr;
1059
1060 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1061 if (!msg)
1062 return -ENOMEM;
1063
1064 hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0,
1065 NFC_CMD_FW_UPLOAD);
1066 if (!hdr)
1067 goto free_msg;
1068
1069 if (nla_put_string(msg, NFC_ATTR_FIRMWARE_NAME, firmware_name) ||
1070 nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx))
1071 goto nla_put_failure;
1072
1073 genlmsg_end(msg, hdr);
1074
1075 genlmsg_multicast(msg, 0, nfc_genl_event_mcgrp.id, GFP_KERNEL);
1076
1077 return 0;
1078
1079nla_put_failure:
1080 genlmsg_cancel(msg, hdr);
1081free_msg:
1082 nlmsg_free(msg);
1083 return -EMSGSIZE;
1084}
1085
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -03001086static struct genl_ops nfc_genl_ops[] = {
1087 {
1088 .cmd = NFC_CMD_GET_DEVICE,
1089 .doit = nfc_genl_get_device,
1090 .dumpit = nfc_genl_dump_devices,
1091 .done = nfc_genl_dump_devices_done,
1092 .policy = nfc_genl_policy,
1093 },
1094 {
Ilan Elias8b3fe7b2011-09-18 11:19:33 +03001095 .cmd = NFC_CMD_DEV_UP,
1096 .doit = nfc_genl_dev_up,
1097 .policy = nfc_genl_policy,
1098 },
1099 {
1100 .cmd = NFC_CMD_DEV_DOWN,
1101 .doit = nfc_genl_dev_down,
1102 .policy = nfc_genl_policy,
1103 },
1104 {
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -03001105 .cmd = NFC_CMD_START_POLL,
1106 .doit = nfc_genl_start_poll,
1107 .policy = nfc_genl_policy,
1108 },
1109 {
1110 .cmd = NFC_CMD_STOP_POLL,
1111 .doit = nfc_genl_stop_poll,
1112 .policy = nfc_genl_policy,
1113 },
1114 {
Samuel Ortiz1ed28f62011-12-14 16:43:09 +01001115 .cmd = NFC_CMD_DEP_LINK_UP,
1116 .doit = nfc_genl_dep_link_up,
1117 .policy = nfc_genl_policy,
1118 },
1119 {
1120 .cmd = NFC_CMD_DEP_LINK_DOWN,
1121 .doit = nfc_genl_dep_link_down,
1122 .policy = nfc_genl_policy,
1123 },
1124 {
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -03001125 .cmd = NFC_CMD_GET_TARGET,
1126 .dumpit = nfc_genl_dump_targets,
1127 .done = nfc_genl_dump_targets_done,
1128 .policy = nfc_genl_policy,
1129 },
Thierry Escande52feb442012-10-17 14:43:39 +02001130 {
1131 .cmd = NFC_CMD_LLC_GET_PARAMS,
1132 .doit = nfc_genl_llc_get_params,
1133 .policy = nfc_genl_policy,
1134 },
1135 {
1136 .cmd = NFC_CMD_LLC_SET_PARAMS,
1137 .doit = nfc_genl_llc_set_params,
1138 .policy = nfc_genl_policy,
1139 },
Thierry Escanded9b8d8e2013-02-15 10:43:06 +01001140 {
1141 .cmd = NFC_CMD_LLC_SDREQ,
1142 .doit = nfc_genl_llc_sdreq,
1143 .policy = nfc_genl_policy,
1144 },
Eric Lapuyade9674da82013-04-29 17:13:27 +02001145 {
1146 .cmd = NFC_CMD_FW_UPLOAD,
1147 .doit = nfc_genl_fw_upload,
1148 .policy = nfc_genl_policy,
1149 },
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -03001150};
1151
Szymon Janc3c0cc8a2012-09-26 14:17:12 +02001152
1153struct urelease_work {
1154 struct work_struct w;
John W. Linvillec4876062012-09-28 11:11:16 -04001155 int portid;
Szymon Janc3c0cc8a2012-09-26 14:17:12 +02001156};
1157
1158static void nfc_urelease_event_work(struct work_struct *work)
1159{
1160 struct urelease_work *w = container_of(work, struct urelease_work, w);
1161 struct class_dev_iter iter;
1162 struct nfc_dev *dev;
1163
John W. Linvillec4876062012-09-28 11:11:16 -04001164 pr_debug("portid %d\n", w->portid);
Szymon Janc3c0cc8a2012-09-26 14:17:12 +02001165
1166 mutex_lock(&nfc_devlist_mutex);
1167
1168 nfc_device_iter_init(&iter);
1169 dev = nfc_device_iter_next(&iter);
1170
1171 while (dev) {
1172 mutex_lock(&dev->genl_data.genl_data_mutex);
1173
John W. Linvillec4876062012-09-28 11:11:16 -04001174 if (dev->genl_data.poll_req_portid == w->portid) {
Szymon Janc3c0cc8a2012-09-26 14:17:12 +02001175 nfc_stop_poll(dev);
John W. Linvillec4876062012-09-28 11:11:16 -04001176 dev->genl_data.poll_req_portid = 0;
Szymon Janc3c0cc8a2012-09-26 14:17:12 +02001177 }
1178
1179 mutex_unlock(&dev->genl_data.genl_data_mutex);
1180
1181 dev = nfc_device_iter_next(&iter);
1182 }
1183
1184 nfc_device_iter_exit(&iter);
1185
1186 mutex_unlock(&nfc_devlist_mutex);
1187
1188 kfree(w);
1189}
1190
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -03001191static int nfc_genl_rcv_nl_event(struct notifier_block *this,
Samuel Ortiz0a40acb2012-03-05 01:03:53 +01001192 unsigned long event, void *ptr)
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -03001193{
1194 struct netlink_notify *n = ptr;
Szymon Janc3c0cc8a2012-09-26 14:17:12 +02001195 struct urelease_work *w;
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -03001196
1197 if (event != NETLINK_URELEASE || n->protocol != NETLINK_GENERIC)
1198 goto out;
1199
Eric W. Biederman15e47302012-09-07 20:12:54 +00001200 pr_debug("NETLINK_URELEASE event from id %d\n", n->portid);
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -03001201
Szymon Janc3c0cc8a2012-09-26 14:17:12 +02001202 w = kmalloc(sizeof(*w), GFP_ATOMIC);
1203 if (w) {
1204 INIT_WORK((struct work_struct *) w, nfc_urelease_event_work);
John W. Linvillec4876062012-09-28 11:11:16 -04001205 w->portid = n->portid;
Szymon Janc3c0cc8a2012-09-26 14:17:12 +02001206 schedule_work((struct work_struct *) w);
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -03001207 }
1208
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -03001209out:
1210 return NOTIFY_DONE;
1211}
1212
1213void nfc_genl_data_init(struct nfc_genl_data *genl_data)
1214{
Eric W. Biederman15e47302012-09-07 20:12:54 +00001215 genl_data->poll_req_portid = 0;
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -03001216 mutex_init(&genl_data->genl_data_mutex);
1217}
1218
1219void nfc_genl_data_exit(struct nfc_genl_data *genl_data)
1220{
1221 mutex_destroy(&genl_data->genl_data_mutex);
1222}
1223
1224static struct notifier_block nl_notifier = {
1225 .notifier_call = nfc_genl_rcv_nl_event,
1226};
1227
1228/**
1229 * nfc_genl_init() - Initialize netlink interface
1230 *
1231 * This initialization function registers the nfc netlink family.
1232 */
1233int __init nfc_genl_init(void)
1234{
1235 int rc;
1236
1237 rc = genl_register_family_with_ops(&nfc_genl_family, nfc_genl_ops,
Samuel Ortiz0a40acb2012-03-05 01:03:53 +01001238 ARRAY_SIZE(nfc_genl_ops));
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -03001239 if (rc)
1240 return rc;
1241
1242 rc = genl_register_mc_group(&nfc_genl_family, &nfc_genl_event_mcgrp);
1243
1244 netlink_register_notifier(&nl_notifier);
1245
1246 return rc;
1247}
1248
1249/**
1250 * nfc_genl_exit() - Deinitialize netlink interface
1251 *
1252 * This exit function unregisters the nfc netlink family.
1253 */
1254void nfc_genl_exit(void)
1255{
1256 netlink_unregister_notifier(&nl_notifier);
1257 genl_unregister_family(&nfc_genl_family);
1258}