blob: 1180b3e58a0abe940e6fdba4fc887ed4b4b80a7b [file] [log] [blame]
Thomas Gleixner1ccea772019-05-19 15:51:43 +02001// SPDX-License-Identifier: GPL-2.0-or-later
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -03002/*
3 * Copyright (C) 2011 Instituto Nokia de Tecnologia
4 *
5 * Authors:
6 * Lauro Ramos Venancio <lauro.venancio@openbossa.org>
7 * Aloisio Almeida Jr <aloisio.almeida@openbossa.org>
8 *
Samuel Ortiz9e580952014-10-14 02:19:46 +02009 * Vendor commands implementation based on net/wireless/nl80211.c
10 * which is:
11 *
12 * Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net>
13 * Copyright 2013-2014 Intel Mobile Communications GmbH
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -030014 */
15
Samuel Ortiz52858b52011-12-14 16:43:05 +010016#define pr_fmt(fmt) KBUILD_MODNAME ": %s: " fmt, __func__
Joe Perches20c239c2011-11-29 11:37:33 -080017
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -030018#include <net/genetlink.h>
19#include <linux/nfc.h>
20#include <linux/slab.h>
21
22#include "nfc.h"
Samuel Ortiz30cc4582013-04-26 11:49:40 +020023#include "llcp.h"
Thierry Escande52feb442012-10-17 14:43:39 +020024
Johannes Berg2a94fe42013-11-19 15:19:39 +010025static const struct genl_multicast_group nfc_genl_mcgrps[] = {
26 { .name = NFC_GENL_MCAST_EVENT_NAME, },
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -030027};
28
Johannes Berg489111e2016-10-24 14:40:03 +020029static struct genl_family nfc_genl_family;
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -030030static const struct nla_policy nfc_genl_policy[NFC_ATTR_MAX + 1] = {
31 [NFC_ATTR_DEVICE_INDEX] = { .type = NLA_U32 },
32 [NFC_ATTR_DEVICE_NAME] = { .type = NLA_STRING,
33 .len = NFC_DEVICE_NAME_MAXSIZE },
34 [NFC_ATTR_PROTOCOLS] = { .type = NLA_U32 },
Samuel Ortiz1ed28f62011-12-14 16:43:09 +010035 [NFC_ATTR_COMM_MODE] = { .type = NLA_U8 },
36 [NFC_ATTR_RF_MODE] = { .type = NLA_U8 },
Samuel Ortizc970a1a2012-03-05 01:03:34 +010037 [NFC_ATTR_DEVICE_POWERED] = { .type = NLA_U8 },
Samuel Ortizfe7c5802012-05-15 15:57:06 +020038 [NFC_ATTR_IM_PROTOCOLS] = { .type = NLA_U32 },
39 [NFC_ATTR_TM_PROTOCOLS] = { .type = NLA_U32 },
Thierry Escande8af362d2013-02-15 10:42:52 +010040 [NFC_ATTR_LLC_PARAM_LTO] = { .type = NLA_U8 },
41 [NFC_ATTR_LLC_PARAM_RW] = { .type = NLA_U8 },
42 [NFC_ATTR_LLC_PARAM_MIUX] = { .type = NLA_U16 },
Thierry Escanded9b8d8e2013-02-15 10:43:06 +010043 [NFC_ATTR_LLC_SDP] = { .type = NLA_NESTED },
Eric Lapuyade9674da82013-04-29 17:13:27 +020044 [NFC_ATTR_FIRMWARE_NAME] = { .type = NLA_STRING,
45 .len = NFC_FIRMWARE_NAME_MAXSIZE },
Samuel Ortiz5ce3f322013-08-28 00:47:24 +020046 [NFC_ATTR_SE_APDU] = { .type = NLA_BINARY },
Christophe Ricard29e76922015-08-19 21:26:43 +020047 [NFC_ATTR_VENDOR_DATA] = { .type = NLA_BINARY },
48
Thierry Escanded9b8d8e2013-02-15 10:43:06 +010049};
50
51static const struct nla_policy nfc_sdp_genl_policy[NFC_SDP_ATTR_MAX + 1] = {
Kees Cookfe9c8422018-02-14 15:45:07 -080052 [NFC_SDP_ATTR_URI] = { .type = NLA_STRING,
53 .len = U8_MAX - 4 },
Thierry Escanded9b8d8e2013-02-15 10:43:06 +010054 [NFC_SDP_ATTR_SAP] = { .type = NLA_U8 },
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -030055};
56
57static int nfc_genl_send_target(struct sk_buff *msg, struct nfc_target *target,
Samuel Ortiz0a40acb2012-03-05 01:03:53 +010058 struct netlink_callback *cb, int flags)
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -030059{
60 void *hdr;
61
Eric W. Biederman15e47302012-09-07 20:12:54 +000062 hdr = genlmsg_put(msg, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
Samuel Ortiz0a40acb2012-03-05 01:03:53 +010063 &nfc_genl_family, flags, NFC_CMD_GET_TARGET);
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -030064 if (!hdr)
65 return -EMSGSIZE;
66
Michal Kubecek0a833c22017-11-15 13:09:32 +010067 genl_dump_check_consistent(cb, hdr);
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -030068
David S. Miller1e6428d2012-03-29 23:23:57 -040069 if (nla_put_u32(msg, NFC_ATTR_TARGET_INDEX, target->idx) ||
70 nla_put_u32(msg, NFC_ATTR_PROTOCOLS, target->supported_protocols) ||
71 nla_put_u16(msg, NFC_ATTR_TARGET_SENS_RES, target->sens_res) ||
72 nla_put_u8(msg, NFC_ATTR_TARGET_SEL_RES, target->sel_res))
73 goto nla_put_failure;
74 if (target->nfcid1_len > 0 &&
75 nla_put(msg, NFC_ATTR_TARGET_NFCID1, target->nfcid1_len,
76 target->nfcid1))
77 goto nla_put_failure;
78 if (target->sensb_res_len > 0 &&
79 nla_put(msg, NFC_ATTR_TARGET_SENSB_RES, target->sensb_res_len,
80 target->sensb_res))
81 goto nla_put_failure;
82 if (target->sensf_res_len > 0 &&
83 nla_put(msg, NFC_ATTR_TARGET_SENSF_RES, target->sensf_res_len,
84 target->sensf_res))
85 goto nla_put_failure;
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -030086
Mark A. Greerf5f68722014-01-14 17:52:11 -070087 if (target->is_iso15693) {
88 if (nla_put_u8(msg, NFC_ATTR_TARGET_ISO15693_DSFID,
89 target->iso15693_dsfid) ||
90 nla_put(msg, NFC_ATTR_TARGET_ISO15693_UID,
91 sizeof(target->iso15693_uid), target->iso15693_uid))
92 goto nla_put_failure;
93 }
94
Johannes Berg053c0952015-01-16 22:09:00 +010095 genlmsg_end(msg, hdr);
96 return 0;
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -030097
98nla_put_failure:
99 genlmsg_cancel(msg, hdr);
100 return -EMSGSIZE;
101}
102
103static struct nfc_dev *__get_device_from_cb(struct netlink_callback *cb)
104{
Johannes Bergc90c39d2016-10-24 14:40:01 +0200105 struct nlattr **attrbuf = genl_family_attrbuf(&nfc_genl_family);
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300106 struct nfc_dev *dev;
107 int rc;
108 u32 idx;
109
Johannes Berg8cb08172019-04-26 14:07:28 +0200110 rc = nlmsg_parse_deprecated(cb->nlh,
111 GENL_HDRLEN + nfc_genl_family.hdrsize,
112 attrbuf, nfc_genl_family.maxattr,
113 nfc_genl_policy, NULL);
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300114 if (rc < 0)
115 return ERR_PTR(rc);
116
Johannes Bergc90c39d2016-10-24 14:40:01 +0200117 if (!attrbuf[NFC_ATTR_DEVICE_INDEX])
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300118 return ERR_PTR(-EINVAL);
119
Johannes Bergc90c39d2016-10-24 14:40:01 +0200120 idx = nla_get_u32(attrbuf[NFC_ATTR_DEVICE_INDEX]);
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300121
122 dev = nfc_get_device(idx);
123 if (!dev)
124 return ERR_PTR(-ENODEV);
125
126 return dev;
127}
128
129static int nfc_genl_dump_targets(struct sk_buff *skb,
Samuel Ortiz0a40acb2012-03-05 01:03:53 +0100130 struct netlink_callback *cb)
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300131{
132 int i = cb->args[0];
133 struct nfc_dev *dev = (struct nfc_dev *) cb->args[1];
134 int rc;
135
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300136 if (!dev) {
137 dev = __get_device_from_cb(cb);
138 if (IS_ERR(dev))
139 return PTR_ERR(dev);
140
141 cb->args[1] = (long) dev;
142 }
143
Eric Lapuyaded4ccb132012-05-07 12:31:15 +0200144 device_lock(&dev->dev);
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300145
146 cb->seq = dev->targets_generation;
147
148 while (i < dev->n_targets) {
149 rc = nfc_genl_send_target(skb, &dev->targets[i], cb,
Samuel Ortiz0a40acb2012-03-05 01:03:53 +0100150 NLM_F_MULTI);
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300151 if (rc < 0)
152 break;
153
154 i++;
155 }
156
Eric Lapuyaded4ccb132012-05-07 12:31:15 +0200157 device_unlock(&dev->dev);
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300158
159 cb->args[0] = i;
160
161 return skb->len;
162}
163
164static int nfc_genl_dump_targets_done(struct netlink_callback *cb)
165{
166 struct nfc_dev *dev = (struct nfc_dev *) cb->args[1];
167
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300168 if (dev)
169 nfc_put_device(dev);
170
171 return 0;
172}
173
174int nfc_genl_targets_found(struct nfc_dev *dev)
175{
176 struct sk_buff *msg;
177 void *hdr;
178
Eric W. Biederman15e47302012-09-07 20:12:54 +0000179 dev->genl_data.poll_req_portid = 0;
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300180
Thomas Graf58050fc2012-06-28 03:57:45 +0000181 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300182 if (!msg)
183 return -ENOMEM;
184
185 hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0,
Samuel Ortiz0a40acb2012-03-05 01:03:53 +0100186 NFC_EVENT_TARGETS_FOUND);
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300187 if (!hdr)
188 goto free_msg;
189
David S. Miller1e6428d2012-03-29 23:23:57 -0400190 if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx))
191 goto nla_put_failure;
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300192
193 genlmsg_end(msg, hdr);
194
Johannes Berg2a94fe42013-11-19 15:19:39 +0100195 return genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_ATOMIC);
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300196
197nla_put_failure:
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300198free_msg:
199 nlmsg_free(msg);
200 return -EMSGSIZE;
201}
202
Samuel Ortiz8112a5c2012-04-10 19:43:04 +0200203int nfc_genl_target_lost(struct nfc_dev *dev, u32 target_idx)
204{
205 struct sk_buff *msg;
206 void *hdr;
207
Thomas Graf58050fc2012-06-28 03:57:45 +0000208 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Samuel Ortiz8112a5c2012-04-10 19:43:04 +0200209 if (!msg)
210 return -ENOMEM;
211
212 hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0,
213 NFC_EVENT_TARGET_LOST);
214 if (!hdr)
215 goto free_msg;
216
John W. Linville59ef43e2012-04-18 14:17:13 -0400217 if (nla_put_string(msg, NFC_ATTR_DEVICE_NAME, nfc_device_name(dev)) ||
218 nla_put_u32(msg, NFC_ATTR_TARGET_INDEX, target_idx))
219 goto nla_put_failure;
Samuel Ortiz8112a5c2012-04-10 19:43:04 +0200220
221 genlmsg_end(msg, hdr);
222
Johannes Berg2a94fe42013-11-19 15:19:39 +0100223 genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_KERNEL);
Samuel Ortiz8112a5c2012-04-10 19:43:04 +0200224
225 return 0;
226
227nla_put_failure:
Samuel Ortiz8112a5c2012-04-10 19:43:04 +0200228free_msg:
229 nlmsg_free(msg);
230 return -EMSGSIZE;
231}
232
Samuel Ortizfc40a8c2012-06-01 13:21:13 +0200233int nfc_genl_tm_activated(struct nfc_dev *dev, u32 protocol)
234{
235 struct sk_buff *msg;
236 void *hdr;
237
Thomas Graf58050fc2012-06-28 03:57:45 +0000238 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Samuel Ortizfc40a8c2012-06-01 13:21:13 +0200239 if (!msg)
240 return -ENOMEM;
241
242 hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0,
243 NFC_EVENT_TM_ACTIVATED);
244 if (!hdr)
245 goto free_msg;
246
247 if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx))
248 goto nla_put_failure;
249 if (nla_put_u32(msg, NFC_ATTR_TM_PROTOCOLS, protocol))
250 goto nla_put_failure;
251
252 genlmsg_end(msg, hdr);
253
Johannes Berg2a94fe42013-11-19 15:19:39 +0100254 genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_KERNEL);
Samuel Ortizfc40a8c2012-06-01 13:21:13 +0200255
256 return 0;
257
258nla_put_failure:
Samuel Ortizfc40a8c2012-06-01 13:21:13 +0200259free_msg:
260 nlmsg_free(msg);
261 return -EMSGSIZE;
262}
263
264int nfc_genl_tm_deactivated(struct nfc_dev *dev)
265{
266 struct sk_buff *msg;
267 void *hdr;
268
Thomas Graf58050fc2012-06-28 03:57:45 +0000269 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Samuel Ortizfc40a8c2012-06-01 13:21:13 +0200270 if (!msg)
271 return -ENOMEM;
272
273 hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0,
274 NFC_EVENT_TM_DEACTIVATED);
275 if (!hdr)
276 goto free_msg;
277
278 if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx))
279 goto nla_put_failure;
280
281 genlmsg_end(msg, hdr);
282
Johannes Berg2a94fe42013-11-19 15:19:39 +0100283 genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_KERNEL);
Samuel Ortizfc40a8c2012-06-01 13:21:13 +0200284
285 return 0;
286
287nla_put_failure:
Samuel Ortizfc40a8c2012-06-01 13:21:13 +0200288free_msg:
289 nlmsg_free(msg);
290 return -EMSGSIZE;
291}
292
OGAWA Hirofumi85a25662017-02-04 10:15:55 +0900293static int nfc_genl_setup_device_added(struct nfc_dev *dev, struct sk_buff *msg)
294{
295 if (nla_put_string(msg, NFC_ATTR_DEVICE_NAME, nfc_device_name(dev)) ||
296 nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx) ||
297 nla_put_u32(msg, NFC_ATTR_PROTOCOLS, dev->supported_protocols) ||
298 nla_put_u8(msg, NFC_ATTR_DEVICE_POWERED, dev->dev_up) ||
299 nla_put_u8(msg, NFC_ATTR_RF_MODE, dev->rf_mode))
300 return -1;
301 return 0;
302}
303
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300304int nfc_genl_device_added(struct nfc_dev *dev)
305{
306 struct sk_buff *msg;
307 void *hdr;
308
Thomas Graf58050fc2012-06-28 03:57:45 +0000309 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300310 if (!msg)
311 return -ENOMEM;
312
313 hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0,
Samuel Ortiz0a40acb2012-03-05 01:03:53 +0100314 NFC_EVENT_DEVICE_ADDED);
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300315 if (!hdr)
316 goto free_msg;
317
OGAWA Hirofumi85a25662017-02-04 10:15:55 +0900318 if (nfc_genl_setup_device_added(dev, msg))
David S. Miller1e6428d2012-03-29 23:23:57 -0400319 goto nla_put_failure;
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300320
321 genlmsg_end(msg, hdr);
322
Johannes Berg2a94fe42013-11-19 15:19:39 +0100323 genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_KERNEL);
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300324
325 return 0;
326
327nla_put_failure:
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300328free_msg:
329 nlmsg_free(msg);
330 return -EMSGSIZE;
331}
332
333int nfc_genl_device_removed(struct nfc_dev *dev)
334{
335 struct sk_buff *msg;
336 void *hdr;
337
Thomas Graf58050fc2012-06-28 03:57:45 +0000338 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300339 if (!msg)
340 return -ENOMEM;
341
342 hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0,
Samuel Ortiz0a40acb2012-03-05 01:03:53 +0100343 NFC_EVENT_DEVICE_REMOVED);
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300344 if (!hdr)
345 goto free_msg;
346
David S. Miller1e6428d2012-03-29 23:23:57 -0400347 if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx))
348 goto nla_put_failure;
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300349
350 genlmsg_end(msg, hdr);
351
Johannes Berg2a94fe42013-11-19 15:19:39 +0100352 genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_KERNEL);
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300353
354 return 0;
355
356nla_put_failure:
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300357free_msg:
358 nlmsg_free(msg);
359 return -EMSGSIZE;
360}
361
Thierry Escanded9b8d8e2013-02-15 10:43:06 +0100362int nfc_genl_llc_send_sdres(struct nfc_dev *dev, struct hlist_head *sdres_list)
363{
364 struct sk_buff *msg;
365 struct nlattr *sdp_attr, *uri_attr;
366 struct nfc_llcp_sdp_tlv *sdres;
367 struct hlist_node *n;
368 void *hdr;
369 int rc = -EMSGSIZE;
370 int i;
371
372 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
373 if (!msg)
374 return -ENOMEM;
375
376 hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0,
377 NFC_EVENT_LLC_SDRES);
378 if (!hdr)
379 goto free_msg;
380
381 if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx))
382 goto nla_put_failure;
383
Michal Kubecekae0be8d2019-04-26 11:13:06 +0200384 sdp_attr = nla_nest_start_noflag(msg, NFC_ATTR_LLC_SDP);
Thierry Escanded9b8d8e2013-02-15 10:43:06 +0100385 if (sdp_attr == NULL) {
386 rc = -ENOMEM;
387 goto nla_put_failure;
388 }
389
390 i = 1;
391 hlist_for_each_entry_safe(sdres, n, sdres_list, node) {
392 pr_debug("uri: %s, sap: %d\n", sdres->uri, sdres->sap);
393
Michal Kubecekae0be8d2019-04-26 11:13:06 +0200394 uri_attr = nla_nest_start_noflag(msg, i++);
Thierry Escanded9b8d8e2013-02-15 10:43:06 +0100395 if (uri_attr == NULL) {
396 rc = -ENOMEM;
397 goto nla_put_failure;
398 }
399
400 if (nla_put_u8(msg, NFC_SDP_ATTR_SAP, sdres->sap))
401 goto nla_put_failure;
402
403 if (nla_put_string(msg, NFC_SDP_ATTR_URI, sdres->uri))
404 goto nla_put_failure;
405
406 nla_nest_end(msg, uri_attr);
407
408 hlist_del(&sdres->node);
409
410 nfc_llcp_free_sdp_tlv(sdres);
411 }
412
413 nla_nest_end(msg, sdp_attr);
414
415 genlmsg_end(msg, hdr);
416
Johannes Berg2a94fe42013-11-19 15:19:39 +0100417 return genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_ATOMIC);
Thierry Escanded9b8d8e2013-02-15 10:43:06 +0100418
419nla_put_failure:
Thierry Escanded9b8d8e2013-02-15 10:43:06 +0100420free_msg:
421 nlmsg_free(msg);
422
423 nfc_llcp_free_sdp_tlv_list(sdres_list);
424
425 return rc;
426}
427
Samuel Ortiz2757c3722013-05-10 15:47:37 +0200428int nfc_genl_se_added(struct nfc_dev *dev, u32 se_idx, u16 type)
429{
430 struct sk_buff *msg;
431 void *hdr;
432
433 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
434 if (!msg)
435 return -ENOMEM;
436
437 hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0,
438 NFC_EVENT_SE_ADDED);
439 if (!hdr)
440 goto free_msg;
441
442 if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx) ||
443 nla_put_u32(msg, NFC_ATTR_SE_INDEX, se_idx) ||
444 nla_put_u8(msg, NFC_ATTR_SE_TYPE, type))
445 goto nla_put_failure;
446
447 genlmsg_end(msg, hdr);
448
Johannes Berg2a94fe42013-11-19 15:19:39 +0100449 genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_KERNEL);
Samuel Ortiz2757c3722013-05-10 15:47:37 +0200450
451 return 0;
452
453nla_put_failure:
Samuel Ortiz2757c3722013-05-10 15:47:37 +0200454free_msg:
455 nlmsg_free(msg);
456 return -EMSGSIZE;
457}
458
459int nfc_genl_se_removed(struct nfc_dev *dev, u32 se_idx)
460{
461 struct sk_buff *msg;
462 void *hdr;
463
464 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
465 if (!msg)
466 return -ENOMEM;
467
468 hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0,
469 NFC_EVENT_SE_REMOVED);
470 if (!hdr)
471 goto free_msg;
472
473 if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx) ||
474 nla_put_u32(msg, NFC_ATTR_SE_INDEX, se_idx))
475 goto nla_put_failure;
476
477 genlmsg_end(msg, hdr);
478
Johannes Berg2a94fe42013-11-19 15:19:39 +0100479 genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_KERNEL);
Samuel Ortiz2757c3722013-05-10 15:47:37 +0200480
481 return 0;
482
483nla_put_failure:
Samuel Ortiz2757c3722013-05-10 15:47:37 +0200484free_msg:
485 nlmsg_free(msg);
486 return -EMSGSIZE;
487}
488
Christophe Ricard447b27c2015-02-01 22:26:16 +0100489int nfc_genl_se_transaction(struct nfc_dev *dev, u8 se_idx,
490 struct nfc_evt_transaction *evt_transaction)
491{
492 struct nfc_se *se;
493 struct sk_buff *msg;
494 void *hdr;
495
496 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
497 if (!msg)
498 return -ENOMEM;
499
500 hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0,
501 NFC_EVENT_SE_TRANSACTION);
502 if (!hdr)
503 goto free_msg;
504
505 se = nfc_find_se(dev, se_idx);
506 if (!se)
507 goto free_msg;
508
509 if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx) ||
510 nla_put_u32(msg, NFC_ATTR_SE_INDEX, se_idx) ||
511 nla_put_u8(msg, NFC_ATTR_SE_TYPE, se->type) ||
512 nla_put(msg, NFC_ATTR_SE_AID, evt_transaction->aid_len,
513 evt_transaction->aid) ||
514 nla_put(msg, NFC_ATTR_SE_PARAMS, evt_transaction->params_len,
515 evt_transaction->params))
516 goto nla_put_failure;
517
518 /* evt_transaction is no more used */
519 devm_kfree(&dev->dev, evt_transaction);
520
521 genlmsg_end(msg, hdr);
522
523 genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_KERNEL);
524
525 return 0;
526
527nla_put_failure:
Christophe Ricard447b27c2015-02-01 22:26:16 +0100528free_msg:
529 /* evt_transaction is no more used */
530 devm_kfree(&dev->dev, evt_transaction);
531 nlmsg_free(msg);
532 return -EMSGSIZE;
533}
534
Christophe Ricard9afec6d2015-12-23 23:45:18 +0100535int nfc_genl_se_connectivity(struct nfc_dev *dev, u8 se_idx)
536{
537 struct nfc_se *se;
538 struct sk_buff *msg;
539 void *hdr;
540
541 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
542 if (!msg)
543 return -ENOMEM;
544
545 hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0,
546 NFC_EVENT_SE_CONNECTIVITY);
547 if (!hdr)
548 goto free_msg;
549
550 se = nfc_find_se(dev, se_idx);
551 if (!se)
552 goto free_msg;
553
554 if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx) ||
555 nla_put_u32(msg, NFC_ATTR_SE_INDEX, se_idx) ||
556 nla_put_u8(msg, NFC_ATTR_SE_TYPE, se->type))
557 goto nla_put_failure;
558
559 genlmsg_end(msg, hdr);
560
561 genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_KERNEL);
562
563 return 0;
564
565nla_put_failure:
Christophe Ricard9afec6d2015-12-23 23:45:18 +0100566free_msg:
567 nlmsg_free(msg);
568 return -EMSGSIZE;
569}
570
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300571static int nfc_genl_send_device(struct sk_buff *msg, struct nfc_dev *dev,
Eric W. Biederman15e47302012-09-07 20:12:54 +0000572 u32 portid, u32 seq,
Samuel Ortiz0a40acb2012-03-05 01:03:53 +0100573 struct netlink_callback *cb,
574 int flags)
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300575{
576 void *hdr;
577
Eric W. Biederman15e47302012-09-07 20:12:54 +0000578 hdr = genlmsg_put(msg, portid, seq, &nfc_genl_family, flags,
Samuel Ortiz0a40acb2012-03-05 01:03:53 +0100579 NFC_CMD_GET_DEVICE);
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300580 if (!hdr)
581 return -EMSGSIZE;
582
583 if (cb)
Michal Kubecek0a833c22017-11-15 13:09:32 +0100584 genl_dump_check_consistent(cb, hdr);
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300585
OGAWA Hirofumi85a25662017-02-04 10:15:55 +0900586 if (nfc_genl_setup_device_added(dev, msg))
David S. Miller1e6428d2012-03-29 23:23:57 -0400587 goto nla_put_failure;
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300588
Johannes Berg053c0952015-01-16 22:09:00 +0100589 genlmsg_end(msg, hdr);
590 return 0;
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300591
592nla_put_failure:
593 genlmsg_cancel(msg, hdr);
594 return -EMSGSIZE;
595}
596
597static int nfc_genl_dump_devices(struct sk_buff *skb,
Samuel Ortiz0a40acb2012-03-05 01:03:53 +0100598 struct netlink_callback *cb)
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300599{
600 struct class_dev_iter *iter = (struct class_dev_iter *) cb->args[0];
601 struct nfc_dev *dev = (struct nfc_dev *) cb->args[1];
602 bool first_call = false;
603
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300604 if (!iter) {
605 first_call = true;
606 iter = kmalloc(sizeof(struct class_dev_iter), GFP_KERNEL);
607 if (!iter)
608 return -ENOMEM;
609 cb->args[0] = (long) iter;
610 }
611
612 mutex_lock(&nfc_devlist_mutex);
613
614 cb->seq = nfc_devlist_generation;
615
616 if (first_call) {
617 nfc_device_iter_init(iter);
618 dev = nfc_device_iter_next(iter);
619 }
620
621 while (dev) {
622 int rc;
623
Eric W. Biederman15e47302012-09-07 20:12:54 +0000624 rc = nfc_genl_send_device(skb, dev, NETLINK_CB(cb->skb).portid,
Samuel Ortiz0a40acb2012-03-05 01:03:53 +0100625 cb->nlh->nlmsg_seq, cb, NLM_F_MULTI);
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300626 if (rc < 0)
627 break;
628
629 dev = nfc_device_iter_next(iter);
630 }
631
632 mutex_unlock(&nfc_devlist_mutex);
633
634 cb->args[1] = (long) dev;
635
636 return skb->len;
637}
638
639static int nfc_genl_dump_devices_done(struct netlink_callback *cb)
640{
641 struct class_dev_iter *iter = (struct class_dev_iter *) cb->args[0];
642
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300643 nfc_device_iter_exit(iter);
644 kfree(iter);
645
646 return 0;
647}
648
Samuel Ortiz1ed28f62011-12-14 16:43:09 +0100649int nfc_genl_dep_link_up_event(struct nfc_dev *dev, u32 target_idx,
Samuel Ortiz0a40acb2012-03-05 01:03:53 +0100650 u8 comm_mode, u8 rf_mode)
Samuel Ortiz1ed28f62011-12-14 16:43:09 +0100651{
652 struct sk_buff *msg;
653 void *hdr;
654
655 pr_debug("DEP link is up\n");
656
Thomas Graf58050fc2012-06-28 03:57:45 +0000657 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
Samuel Ortiz1ed28f62011-12-14 16:43:09 +0100658 if (!msg)
659 return -ENOMEM;
660
Samuel Ortiz0a40acb2012-03-05 01:03:53 +0100661 hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0, NFC_CMD_DEP_LINK_UP);
Samuel Ortiz1ed28f62011-12-14 16:43:09 +0100662 if (!hdr)
663 goto free_msg;
664
David S. Miller1e6428d2012-03-29 23:23:57 -0400665 if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx))
666 goto nla_put_failure;
667 if (rf_mode == NFC_RF_INITIATOR &&
668 nla_put_u32(msg, NFC_ATTR_TARGET_INDEX, target_idx))
669 goto nla_put_failure;
670 if (nla_put_u8(msg, NFC_ATTR_COMM_MODE, comm_mode) ||
671 nla_put_u8(msg, NFC_ATTR_RF_MODE, rf_mode))
672 goto nla_put_failure;
Samuel Ortiz1ed28f62011-12-14 16:43:09 +0100673
674 genlmsg_end(msg, hdr);
675
676 dev->dep_link_up = true;
677
Johannes Berg2a94fe42013-11-19 15:19:39 +0100678 genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_ATOMIC);
Samuel Ortiz1ed28f62011-12-14 16:43:09 +0100679
680 return 0;
681
682nla_put_failure:
Samuel Ortiz1ed28f62011-12-14 16:43:09 +0100683free_msg:
684 nlmsg_free(msg);
685 return -EMSGSIZE;
686}
687
688int nfc_genl_dep_link_down_event(struct nfc_dev *dev)
689{
690 struct sk_buff *msg;
691 void *hdr;
692
693 pr_debug("DEP link is down\n");
694
Thomas Graf58050fc2012-06-28 03:57:45 +0000695 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
Samuel Ortiz1ed28f62011-12-14 16:43:09 +0100696 if (!msg)
697 return -ENOMEM;
698
699 hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0,
Samuel Ortiz0a40acb2012-03-05 01:03:53 +0100700 NFC_CMD_DEP_LINK_DOWN);
Samuel Ortiz1ed28f62011-12-14 16:43:09 +0100701 if (!hdr)
702 goto free_msg;
703
David S. Miller1e6428d2012-03-29 23:23:57 -0400704 if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx))
705 goto nla_put_failure;
Samuel Ortiz1ed28f62011-12-14 16:43:09 +0100706
707 genlmsg_end(msg, hdr);
708
Johannes Berg2a94fe42013-11-19 15:19:39 +0100709 genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_ATOMIC);
Samuel Ortiz1ed28f62011-12-14 16:43:09 +0100710
711 return 0;
712
713nla_put_failure:
Samuel Ortiz1ed28f62011-12-14 16:43:09 +0100714free_msg:
715 nlmsg_free(msg);
716 return -EMSGSIZE;
717}
718
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300719static int nfc_genl_get_device(struct sk_buff *skb, struct genl_info *info)
720{
721 struct sk_buff *msg;
722 struct nfc_dev *dev;
723 u32 idx;
724 int rc = -ENOBUFS;
725
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300726 if (!info->attrs[NFC_ATTR_DEVICE_INDEX])
727 return -EINVAL;
728
729 idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]);
730
731 dev = nfc_get_device(idx);
732 if (!dev)
733 return -ENODEV;
734
Thomas Graf58050fc2012-06-28 03:57:45 +0000735 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300736 if (!msg) {
737 rc = -ENOMEM;
738 goto out_putdev;
739 }
740
Eric W. Biederman15e47302012-09-07 20:12:54 +0000741 rc = nfc_genl_send_device(msg, dev, info->snd_portid, info->snd_seq,
Samuel Ortiz0a40acb2012-03-05 01:03:53 +0100742 NULL, 0);
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300743 if (rc < 0)
744 goto out_free;
745
746 nfc_put_device(dev);
747
748 return genlmsg_reply(msg, info);
749
750out_free:
751 nlmsg_free(msg);
752out_putdev:
753 nfc_put_device(dev);
754 return rc;
755}
756
Ilan Elias8b3fe7b2011-09-18 11:19:33 +0300757static int nfc_genl_dev_up(struct sk_buff *skb, struct genl_info *info)
758{
759 struct nfc_dev *dev;
760 int rc;
761 u32 idx;
762
Ilan Elias8b3fe7b2011-09-18 11:19:33 +0300763 if (!info->attrs[NFC_ATTR_DEVICE_INDEX])
764 return -EINVAL;
765
766 idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]);
767
768 dev = nfc_get_device(idx);
769 if (!dev)
770 return -ENODEV;
771
772 rc = nfc_dev_up(dev);
773
774 nfc_put_device(dev);
775 return rc;
776}
777
778static int nfc_genl_dev_down(struct sk_buff *skb, struct genl_info *info)
779{
780 struct nfc_dev *dev;
781 int rc;
782 u32 idx;
783
Ilan Elias8b3fe7b2011-09-18 11:19:33 +0300784 if (!info->attrs[NFC_ATTR_DEVICE_INDEX])
785 return -EINVAL;
786
787 idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]);
788
789 dev = nfc_get_device(idx);
790 if (!dev)
791 return -ENODEV;
792
793 rc = nfc_dev_down(dev);
794
795 nfc_put_device(dev);
796 return rc;
797}
798
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300799static int nfc_genl_start_poll(struct sk_buff *skb, struct genl_info *info)
800{
801 struct nfc_dev *dev;
802 int rc;
803 u32 idx;
Samuel Ortizfe7c5802012-05-15 15:57:06 +0200804 u32 im_protocols = 0, tm_protocols = 0;
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300805
Samuel Ortiz1ed28f62011-12-14 16:43:09 +0100806 pr_debug("Poll start\n");
807
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300808 if (!info->attrs[NFC_ATTR_DEVICE_INDEX] ||
Samuel Ortizfe7c5802012-05-15 15:57:06 +0200809 ((!info->attrs[NFC_ATTR_IM_PROTOCOLS] &&
810 !info->attrs[NFC_ATTR_PROTOCOLS]) &&
Szymon Janc0f450772012-10-17 15:23:39 +0200811 !info->attrs[NFC_ATTR_TM_PROTOCOLS]))
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300812 return -EINVAL;
813
814 idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]);
Samuel Ortizfe7c5802012-05-15 15:57:06 +0200815
816 if (info->attrs[NFC_ATTR_TM_PROTOCOLS])
817 tm_protocols = nla_get_u32(info->attrs[NFC_ATTR_TM_PROTOCOLS]);
Samuel Ortizfe7c5802012-05-15 15:57:06 +0200818
819 if (info->attrs[NFC_ATTR_IM_PROTOCOLS])
820 im_protocols = nla_get_u32(info->attrs[NFC_ATTR_IM_PROTOCOLS]);
Samuel Ortiz5e50ee32012-05-31 11:48:58 +0200821 else if (info->attrs[NFC_ATTR_PROTOCOLS])
822 im_protocols = nla_get_u32(info->attrs[NFC_ATTR_PROTOCOLS]);
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300823
824 dev = nfc_get_device(idx);
825 if (!dev)
826 return -ENODEV;
827
828 mutex_lock(&dev->genl_data.genl_data_mutex);
829
Samuel Ortizfe7c5802012-05-15 15:57:06 +0200830 rc = nfc_start_poll(dev, im_protocols, tm_protocols);
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300831 if (!rc)
Eric W. Biederman15e47302012-09-07 20:12:54 +0000832 dev->genl_data.poll_req_portid = info->snd_portid;
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300833
834 mutex_unlock(&dev->genl_data.genl_data_mutex);
835
836 nfc_put_device(dev);
837 return rc;
838}
839
840static int nfc_genl_stop_poll(struct sk_buff *skb, struct genl_info *info)
841{
842 struct nfc_dev *dev;
843 int rc;
844 u32 idx;
845
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300846 if (!info->attrs[NFC_ATTR_DEVICE_INDEX])
847 return -EINVAL;
848
849 idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]);
850
851 dev = nfc_get_device(idx);
852 if (!dev)
853 return -ENODEV;
854
Samuel Ortiza831b912012-06-28 16:41:57 +0200855 device_lock(&dev->dev);
856
857 if (!dev->polling) {
858 device_unlock(&dev->dev);
859 return -EINVAL;
860 }
861
862 device_unlock(&dev->dev);
863
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300864 mutex_lock(&dev->genl_data.genl_data_mutex);
865
Eric W. Biederman15e47302012-09-07 20:12:54 +0000866 if (dev->genl_data.poll_req_portid != info->snd_portid) {
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300867 rc = -EBUSY;
868 goto out;
869 }
870
871 rc = nfc_stop_poll(dev);
Eric W. Biederman15e47302012-09-07 20:12:54 +0000872 dev->genl_data.poll_req_portid = 0;
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300873
874out:
875 mutex_unlock(&dev->genl_data.genl_data_mutex);
876 nfc_put_device(dev);
877 return rc;
878}
879
Christophe Ricard3682f492014-12-02 21:27:50 +0100880static int nfc_genl_activate_target(struct sk_buff *skb, struct genl_info *info)
881{
882 struct nfc_dev *dev;
883 u32 device_idx, target_idx, protocol;
884 int rc;
885
Mateusz Jurczyka0323b92017-05-24 12:42:26 +0200886 if (!info->attrs[NFC_ATTR_DEVICE_INDEX] ||
887 !info->attrs[NFC_ATTR_TARGET_INDEX] ||
888 !info->attrs[NFC_ATTR_PROTOCOLS])
Christophe Ricard3682f492014-12-02 21:27:50 +0100889 return -EINVAL;
890
891 device_idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]);
892
893 dev = nfc_get_device(device_idx);
894 if (!dev)
895 return -ENODEV;
896
897 target_idx = nla_get_u32(info->attrs[NFC_ATTR_TARGET_INDEX]);
898 protocol = nla_get_u32(info->attrs[NFC_ATTR_PROTOCOLS]);
899
Christophe Ricard96d45812015-10-25 22:54:43 +0100900 nfc_deactivate_target(dev, target_idx, NFC_TARGET_MODE_SLEEP);
Christophe Ricard3682f492014-12-02 21:27:50 +0100901 rc = nfc_activate_target(dev, target_idx, protocol);
902
903 nfc_put_device(dev);
Andy Shevchenko32671832017-03-22 21:20:58 +0200904 return rc;
Christophe Ricard3682f492014-12-02 21:27:50 +0100905}
906
Mark Greer4d63adf2017-06-15 20:34:22 -0700907static int nfc_genl_deactivate_target(struct sk_buff *skb,
908 struct genl_info *info)
909{
910 struct nfc_dev *dev;
911 u32 device_idx, target_idx;
912 int rc;
913
914 if (!info->attrs[NFC_ATTR_DEVICE_INDEX])
915 return -EINVAL;
916
917 device_idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]);
918
919 dev = nfc_get_device(device_idx);
920 if (!dev)
921 return -ENODEV;
922
923 target_idx = nla_get_u32(info->attrs[NFC_ATTR_TARGET_INDEX]);
924
925 rc = nfc_deactivate_target(dev, target_idx, NFC_TARGET_MODE_SLEEP);
926
927 nfc_put_device(dev);
928 return rc;
929}
930
Samuel Ortiz1ed28f62011-12-14 16:43:09 +0100931static int nfc_genl_dep_link_up(struct sk_buff *skb, struct genl_info *info)
932{
933 struct nfc_dev *dev;
934 int rc, tgt_idx;
935 u32 idx;
Samuel Ortiz47807d32012-03-05 01:03:50 +0100936 u8 comm;
Samuel Ortiz1ed28f62011-12-14 16:43:09 +0100937
938 pr_debug("DEP link up\n");
939
940 if (!info->attrs[NFC_ATTR_DEVICE_INDEX] ||
Samuel Ortiz47807d32012-03-05 01:03:50 +0100941 !info->attrs[NFC_ATTR_COMM_MODE])
Samuel Ortiz1ed28f62011-12-14 16:43:09 +0100942 return -EINVAL;
943
944 idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]);
945 if (!info->attrs[NFC_ATTR_TARGET_INDEX])
946 tgt_idx = NFC_TARGET_IDX_ANY;
947 else
948 tgt_idx = nla_get_u32(info->attrs[NFC_ATTR_TARGET_INDEX]);
949
950 comm = nla_get_u8(info->attrs[NFC_ATTR_COMM_MODE]);
Samuel Ortiz1ed28f62011-12-14 16:43:09 +0100951
952 if (comm != NFC_COMM_ACTIVE && comm != NFC_COMM_PASSIVE)
953 return -EINVAL;
954
Samuel Ortiz1ed28f62011-12-14 16:43:09 +0100955 dev = nfc_get_device(idx);
956 if (!dev)
957 return -ENODEV;
958
Samuel Ortiz47807d32012-03-05 01:03:50 +0100959 rc = nfc_dep_link_up(dev, tgt_idx, comm);
Samuel Ortiz1ed28f62011-12-14 16:43:09 +0100960
961 nfc_put_device(dev);
962
963 return rc;
964}
965
966static int nfc_genl_dep_link_down(struct sk_buff *skb, struct genl_info *info)
967{
968 struct nfc_dev *dev;
969 int rc;
970 u32 idx;
971
972 if (!info->attrs[NFC_ATTR_DEVICE_INDEX])
973 return -EINVAL;
974
975 idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]);
976
977 dev = nfc_get_device(idx);
978 if (!dev)
979 return -ENODEV;
980
981 rc = nfc_dep_link_down(dev);
982
983 nfc_put_device(dev);
984 return rc;
985}
986
Thierry Escande52feb442012-10-17 14:43:39 +0200987static int nfc_genl_send_params(struct sk_buff *msg,
988 struct nfc_llcp_local *local,
989 u32 portid, u32 seq)
990{
991 void *hdr;
992
993 hdr = genlmsg_put(msg, portid, seq, &nfc_genl_family, 0,
994 NFC_CMD_LLC_GET_PARAMS);
995 if (!hdr)
996 return -EMSGSIZE;
997
998 if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, local->dev->idx) ||
999 nla_put_u8(msg, NFC_ATTR_LLC_PARAM_LTO, local->lto) ||
1000 nla_put_u8(msg, NFC_ATTR_LLC_PARAM_RW, local->rw) ||
1001 nla_put_u16(msg, NFC_ATTR_LLC_PARAM_MIUX, be16_to_cpu(local->miux)))
1002 goto nla_put_failure;
1003
Johannes Berg053c0952015-01-16 22:09:00 +01001004 genlmsg_end(msg, hdr);
1005 return 0;
Thierry Escande52feb442012-10-17 14:43:39 +02001006
1007nla_put_failure:
Thierry Escande52feb442012-10-17 14:43:39 +02001008 genlmsg_cancel(msg, hdr);
1009 return -EMSGSIZE;
1010}
1011
1012static int nfc_genl_llc_get_params(struct sk_buff *skb, struct genl_info *info)
1013{
1014 struct nfc_dev *dev;
1015 struct nfc_llcp_local *local;
1016 int rc = 0;
1017 struct sk_buff *msg = NULL;
1018 u32 idx;
1019
1020 if (!info->attrs[NFC_ATTR_DEVICE_INDEX])
1021 return -EINVAL;
1022
1023 idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]);
1024
1025 dev = nfc_get_device(idx);
1026 if (!dev)
1027 return -ENODEV;
1028
1029 device_lock(&dev->dev);
1030
1031 local = nfc_llcp_find_local(dev);
1032 if (!local) {
1033 rc = -ENODEV;
1034 goto exit;
1035 }
1036
1037 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1038 if (!msg) {
1039 rc = -ENOMEM;
1040 goto exit;
1041 }
1042
1043 rc = nfc_genl_send_params(msg, local, info->snd_portid, info->snd_seq);
1044
1045exit:
1046 device_unlock(&dev->dev);
1047
1048 nfc_put_device(dev);
1049
1050 if (rc < 0) {
1051 if (msg)
1052 nlmsg_free(msg);
1053
1054 return rc;
1055 }
1056
1057 return genlmsg_reply(msg, info);
1058}
1059
1060static int nfc_genl_llc_set_params(struct sk_buff *skb, struct genl_info *info)
1061{
1062 struct nfc_dev *dev;
1063 struct nfc_llcp_local *local;
1064 u8 rw = 0;
1065 u16 miux = 0;
1066 u32 idx;
1067 int rc = 0;
1068
1069 if (!info->attrs[NFC_ATTR_DEVICE_INDEX] ||
1070 (!info->attrs[NFC_ATTR_LLC_PARAM_LTO] &&
1071 !info->attrs[NFC_ATTR_LLC_PARAM_RW] &&
1072 !info->attrs[NFC_ATTR_LLC_PARAM_MIUX]))
1073 return -EINVAL;
1074
1075 if (info->attrs[NFC_ATTR_LLC_PARAM_RW]) {
1076 rw = nla_get_u8(info->attrs[NFC_ATTR_LLC_PARAM_RW]);
1077
1078 if (rw > LLCP_MAX_RW)
1079 return -EINVAL;
1080 }
1081
1082 if (info->attrs[NFC_ATTR_LLC_PARAM_MIUX]) {
1083 miux = nla_get_u16(info->attrs[NFC_ATTR_LLC_PARAM_MIUX]);
1084
1085 if (miux > LLCP_MAX_MIUX)
1086 return -EINVAL;
1087 }
1088
1089 idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]);
1090
1091 dev = nfc_get_device(idx);
1092 if (!dev)
1093 return -ENODEV;
1094
1095 device_lock(&dev->dev);
1096
1097 local = nfc_llcp_find_local(dev);
1098 if (!local) {
1099 nfc_put_device(dev);
1100 rc = -ENODEV;
1101 goto exit;
1102 }
1103
1104 if (info->attrs[NFC_ATTR_LLC_PARAM_LTO]) {
1105 if (dev->dep_link_up) {
1106 rc = -EINPROGRESS;
1107 goto exit;
1108 }
1109
1110 local->lto = nla_get_u8(info->attrs[NFC_ATTR_LLC_PARAM_LTO]);
1111 }
1112
1113 if (info->attrs[NFC_ATTR_LLC_PARAM_RW])
1114 local->rw = rw;
1115
1116 if (info->attrs[NFC_ATTR_LLC_PARAM_MIUX])
1117 local->miux = cpu_to_be16(miux);
1118
1119exit:
1120 device_unlock(&dev->dev);
1121
1122 nfc_put_device(dev);
1123
1124 return rc;
1125}
1126
Thierry Escanded9b8d8e2013-02-15 10:43:06 +01001127static int nfc_genl_llc_sdreq(struct sk_buff *skb, struct genl_info *info)
1128{
1129 struct nfc_dev *dev;
1130 struct nfc_llcp_local *local;
1131 struct nlattr *attr, *sdp_attrs[NFC_SDP_ATTR_MAX+1];
1132 u32 idx;
1133 u8 tid;
1134 char *uri;
1135 int rc = 0, rem;
1136 size_t uri_len, tlvs_len;
1137 struct hlist_head sdreq_list;
1138 struct nfc_llcp_sdp_tlv *sdreq;
1139
1140 if (!info->attrs[NFC_ATTR_DEVICE_INDEX] ||
1141 !info->attrs[NFC_ATTR_LLC_SDP])
1142 return -EINVAL;
1143
1144 idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]);
1145
1146 dev = nfc_get_device(idx);
Julia Lawall9abebb82015-10-17 11:32:19 +02001147 if (!dev)
1148 return -ENODEV;
Thierry Escanded9b8d8e2013-02-15 10:43:06 +01001149
1150 device_lock(&dev->dev);
1151
1152 if (dev->dep_link_up == false) {
1153 rc = -ENOLINK;
1154 goto exit;
1155 }
1156
1157 local = nfc_llcp_find_local(dev);
1158 if (!local) {
1159 nfc_put_device(dev);
1160 rc = -ENODEV;
1161 goto exit;
1162 }
1163
1164 INIT_HLIST_HEAD(&sdreq_list);
1165
1166 tlvs_len = 0;
1167
1168 nla_for_each_nested(attr, info->attrs[NFC_ATTR_LLC_SDP], rem) {
Johannes Berg8cb08172019-04-26 14:07:28 +02001169 rc = nla_parse_nested_deprecated(sdp_attrs, NFC_SDP_ATTR_MAX,
1170 attr, nfc_sdp_genl_policy,
1171 info->extack);
Thierry Escanded9b8d8e2013-02-15 10:43:06 +01001172
1173 if (rc != 0) {
1174 rc = -EINVAL;
1175 goto exit;
1176 }
1177
1178 if (!sdp_attrs[NFC_SDP_ATTR_URI])
1179 continue;
1180
1181 uri_len = nla_len(sdp_attrs[NFC_SDP_ATTR_URI]);
1182 if (uri_len == 0)
1183 continue;
1184
1185 uri = nla_data(sdp_attrs[NFC_SDP_ATTR_URI]);
1186 if (uri == NULL || *uri == 0)
1187 continue;
1188
1189 tid = local->sdreq_next_tid++;
1190
1191 sdreq = nfc_llcp_build_sdreq_tlv(tid, uri, uri_len);
1192 if (sdreq == NULL) {
1193 rc = -ENOMEM;
1194 goto exit;
1195 }
1196
1197 tlvs_len += sdreq->tlv_len;
1198
1199 hlist_add_head(&sdreq->node, &sdreq_list);
1200 }
1201
1202 if (hlist_empty(&sdreq_list)) {
1203 rc = -EINVAL;
1204 goto exit;
1205 }
1206
1207 rc = nfc_llcp_send_snl_sdreq(local, &sdreq_list, tlvs_len);
1208exit:
1209 device_unlock(&dev->dev);
1210
1211 nfc_put_device(dev);
1212
1213 return rc;
1214}
1215
Samuel Ortiz9ea71872013-07-31 01:19:43 +02001216static int nfc_genl_fw_download(struct sk_buff *skb, struct genl_info *info)
Eric Lapuyade9674da82013-04-29 17:13:27 +02001217{
1218 struct nfc_dev *dev;
1219 int rc;
1220 u32 idx;
1221 char firmware_name[NFC_FIRMWARE_NAME_MAXSIZE + 1];
1222
1223 if (!info->attrs[NFC_ATTR_DEVICE_INDEX])
1224 return -EINVAL;
1225
1226 idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]);
1227
1228 dev = nfc_get_device(idx);
1229 if (!dev)
1230 return -ENODEV;
1231
1232 nla_strlcpy(firmware_name, info->attrs[NFC_ATTR_FIRMWARE_NAME],
1233 sizeof(firmware_name));
1234
Samuel Ortiz9ea71872013-07-31 01:19:43 +02001235 rc = nfc_fw_download(dev, firmware_name);
Eric Lapuyade9674da82013-04-29 17:13:27 +02001236
1237 nfc_put_device(dev);
1238 return rc;
1239}
1240
Eric Lapuyade352a5f52013-07-19 14:57:55 +02001241int nfc_genl_fw_download_done(struct nfc_dev *dev, const char *firmware_name,
1242 u32 result)
Eric Lapuyade9674da82013-04-29 17:13:27 +02001243{
1244 struct sk_buff *msg;
1245 void *hdr;
1246
1247 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1248 if (!msg)
1249 return -ENOMEM;
1250
1251 hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0,
Samuel Ortiz9ea71872013-07-31 01:19:43 +02001252 NFC_CMD_FW_DOWNLOAD);
Eric Lapuyade9674da82013-04-29 17:13:27 +02001253 if (!hdr)
1254 goto free_msg;
1255
1256 if (nla_put_string(msg, NFC_ATTR_FIRMWARE_NAME, firmware_name) ||
Eric Lapuyade352a5f52013-07-19 14:57:55 +02001257 nla_put_u32(msg, NFC_ATTR_FIRMWARE_DOWNLOAD_STATUS, result) ||
Eric Lapuyade9674da82013-04-29 17:13:27 +02001258 nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx))
1259 goto nla_put_failure;
1260
1261 genlmsg_end(msg, hdr);
1262
Johannes Berg2a94fe42013-11-19 15:19:39 +01001263 genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_KERNEL);
Eric Lapuyade9674da82013-04-29 17:13:27 +02001264
1265 return 0;
1266
1267nla_put_failure:
Eric Lapuyade9674da82013-04-29 17:13:27 +02001268free_msg:
1269 nlmsg_free(msg);
1270 return -EMSGSIZE;
1271}
1272
Samuel Ortizbe085652013-05-10 17:07:32 +02001273static int nfc_genl_enable_se(struct sk_buff *skb, struct genl_info *info)
1274{
1275 struct nfc_dev *dev;
1276 int rc;
1277 u32 idx, se_idx;
1278
1279 if (!info->attrs[NFC_ATTR_DEVICE_INDEX] ||
1280 !info->attrs[NFC_ATTR_SE_INDEX])
1281 return -EINVAL;
1282
1283 idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]);
1284 se_idx = nla_get_u32(info->attrs[NFC_ATTR_SE_INDEX]);
1285
1286 dev = nfc_get_device(idx);
1287 if (!dev)
1288 return -ENODEV;
1289
1290 rc = nfc_enable_se(dev, se_idx);
1291
1292 nfc_put_device(dev);
1293 return rc;
1294}
1295
1296static int nfc_genl_disable_se(struct sk_buff *skb, struct genl_info *info)
1297{
1298 struct nfc_dev *dev;
1299 int rc;
1300 u32 idx, se_idx;
1301
1302 if (!info->attrs[NFC_ATTR_DEVICE_INDEX] ||
1303 !info->attrs[NFC_ATTR_SE_INDEX])
1304 return -EINVAL;
1305
1306 idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]);
1307 se_idx = nla_get_u32(info->attrs[NFC_ATTR_SE_INDEX]);
1308
1309 dev = nfc_get_device(idx);
1310 if (!dev)
1311 return -ENODEV;
1312
1313 rc = nfc_disable_se(dev, se_idx);
1314
1315 nfc_put_device(dev);
1316 return rc;
1317}
1318
Samuel Ortizac22ac42013-07-24 18:10:50 +02001319static int nfc_genl_send_se(struct sk_buff *msg, struct nfc_dev *dev,
1320 u32 portid, u32 seq,
1321 struct netlink_callback *cb,
1322 int flags)
1323{
1324 void *hdr;
1325 struct nfc_se *se, *n;
1326
1327 list_for_each_entry_safe(se, n, &dev->secure_elements, list) {
1328 hdr = genlmsg_put(msg, portid, seq, &nfc_genl_family, flags,
1329 NFC_CMD_GET_SE);
1330 if (!hdr)
1331 goto nla_put_failure;
1332
1333 if (cb)
Michal Kubecek0a833c22017-11-15 13:09:32 +01001334 genl_dump_check_consistent(cb, hdr);
Samuel Ortizac22ac42013-07-24 18:10:50 +02001335
1336 if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx) ||
1337 nla_put_u32(msg, NFC_ATTR_SE_INDEX, se->idx) ||
1338 nla_put_u8(msg, NFC_ATTR_SE_TYPE, se->type))
1339 goto nla_put_failure;
1340
Johannes Berg053c0952015-01-16 22:09:00 +01001341 genlmsg_end(msg, hdr);
Samuel Ortizac22ac42013-07-24 18:10:50 +02001342 }
1343
1344 return 0;
1345
1346nla_put_failure:
1347 genlmsg_cancel(msg, hdr);
1348 return -EMSGSIZE;
1349}
1350
1351static int nfc_genl_dump_ses(struct sk_buff *skb,
1352 struct netlink_callback *cb)
1353{
1354 struct class_dev_iter *iter = (struct class_dev_iter *) cb->args[0];
1355 struct nfc_dev *dev = (struct nfc_dev *) cb->args[1];
1356 bool first_call = false;
1357
1358 if (!iter) {
1359 first_call = true;
1360 iter = kmalloc(sizeof(struct class_dev_iter), GFP_KERNEL);
1361 if (!iter)
1362 return -ENOMEM;
1363 cb->args[0] = (long) iter;
1364 }
1365
1366 mutex_lock(&nfc_devlist_mutex);
1367
1368 cb->seq = nfc_devlist_generation;
1369
1370 if (first_call) {
1371 nfc_device_iter_init(iter);
1372 dev = nfc_device_iter_next(iter);
1373 }
1374
1375 while (dev) {
1376 int rc;
1377
1378 rc = nfc_genl_send_se(skb, dev, NETLINK_CB(cb->skb).portid,
1379 cb->nlh->nlmsg_seq, cb, NLM_F_MULTI);
1380 if (rc < 0)
1381 break;
1382
1383 dev = nfc_device_iter_next(iter);
1384 }
1385
1386 mutex_unlock(&nfc_devlist_mutex);
1387
1388 cb->args[1] = (long) dev;
1389
1390 return skb->len;
1391}
1392
1393static int nfc_genl_dump_ses_done(struct netlink_callback *cb)
1394{
1395 struct class_dev_iter *iter = (struct class_dev_iter *) cb->args[0];
1396
1397 nfc_device_iter_exit(iter);
1398 kfree(iter);
1399
1400 return 0;
1401}
1402
Christophe Ricardcd96db62014-12-02 21:27:51 +01001403static int nfc_se_io(struct nfc_dev *dev, u32 se_idx,
1404 u8 *apdu, size_t apdu_length,
1405 se_io_cb_t cb, void *cb_context)
1406{
1407 struct nfc_se *se;
1408 int rc;
1409
1410 pr_debug("%s se index %d\n", dev_name(&dev->dev), se_idx);
1411
1412 device_lock(&dev->dev);
1413
1414 if (!device_is_registered(&dev->dev)) {
1415 rc = -ENODEV;
1416 goto error;
1417 }
1418
1419 if (!dev->dev_up) {
1420 rc = -ENODEV;
1421 goto error;
1422 }
1423
1424 if (!dev->ops->se_io) {
1425 rc = -EOPNOTSUPP;
1426 goto error;
1427 }
1428
1429 se = nfc_find_se(dev, se_idx);
1430 if (!se) {
1431 rc = -EINVAL;
1432 goto error;
1433 }
1434
1435 if (se->state != NFC_SE_ENABLED) {
1436 rc = -ENODEV;
1437 goto error;
1438 }
1439
1440 rc = dev->ops->se_io(dev, se_idx, apdu,
1441 apdu_length, cb, cb_context);
1442
1443error:
1444 device_unlock(&dev->dev);
1445 return rc;
1446}
1447
Samuel Ortiz5ce3f322013-08-28 00:47:24 +02001448struct se_io_ctx {
1449 u32 dev_idx;
1450 u32 se_idx;
1451};
1452
Samuel Ortizddc1a702013-10-07 14:18:44 +02001453static void se_io_cb(void *context, u8 *apdu, size_t apdu_len, int err)
Samuel Ortiz5ce3f322013-08-28 00:47:24 +02001454{
1455 struct se_io_ctx *ctx = context;
1456 struct sk_buff *msg;
1457 void *hdr;
1458
1459 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1460 if (!msg) {
1461 kfree(ctx);
1462 return;
1463 }
1464
1465 hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0,
1466 NFC_CMD_SE_IO);
1467 if (!hdr)
1468 goto free_msg;
1469
1470 if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, ctx->dev_idx) ||
1471 nla_put_u32(msg, NFC_ATTR_SE_INDEX, ctx->se_idx) ||
1472 nla_put(msg, NFC_ATTR_SE_APDU, apdu_len, apdu))
1473 goto nla_put_failure;
1474
1475 genlmsg_end(msg, hdr);
1476
Johannes Berg2a94fe42013-11-19 15:19:39 +01001477 genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_KERNEL);
Samuel Ortiz5ce3f322013-08-28 00:47:24 +02001478
1479 kfree(ctx);
1480
1481 return;
1482
1483nla_put_failure:
Samuel Ortiz5ce3f322013-08-28 00:47:24 +02001484free_msg:
1485 nlmsg_free(msg);
1486 kfree(ctx);
1487
1488 return;
1489}
1490
1491static int nfc_genl_se_io(struct sk_buff *skb, struct genl_info *info)
1492{
1493 struct nfc_dev *dev;
1494 struct se_io_ctx *ctx;
1495 u32 dev_idx, se_idx;
1496 u8 *apdu;
1497 size_t apdu_len;
1498
1499 if (!info->attrs[NFC_ATTR_DEVICE_INDEX] ||
1500 !info->attrs[NFC_ATTR_SE_INDEX] ||
1501 !info->attrs[NFC_ATTR_SE_APDU])
1502 return -EINVAL;
1503
1504 dev_idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]);
1505 se_idx = nla_get_u32(info->attrs[NFC_ATTR_SE_INDEX]);
1506
1507 dev = nfc_get_device(dev_idx);
1508 if (!dev)
1509 return -ENODEV;
1510
1511 if (!dev->ops || !dev->ops->se_io)
1512 return -ENOTSUPP;
1513
1514 apdu_len = nla_len(info->attrs[NFC_ATTR_SE_APDU]);
1515 if (apdu_len == 0)
1516 return -EINVAL;
1517
1518 apdu = nla_data(info->attrs[NFC_ATTR_SE_APDU]);
1519 if (!apdu)
1520 return -EINVAL;
1521
1522 ctx = kzalloc(sizeof(struct se_io_ctx), GFP_KERNEL);
1523 if (!ctx)
1524 return -ENOMEM;
1525
1526 ctx->dev_idx = dev_idx;
1527 ctx->se_idx = se_idx;
1528
Christophe Ricardcd96db62014-12-02 21:27:51 +01001529 return nfc_se_io(dev, se_idx, apdu, apdu_len, se_io_cb, ctx);
Samuel Ortiz5ce3f322013-08-28 00:47:24 +02001530}
1531
Samuel Ortiz9e580952014-10-14 02:19:46 +02001532static int nfc_genl_vendor_cmd(struct sk_buff *skb,
1533 struct genl_info *info)
1534{
1535 struct nfc_dev *dev;
1536 struct nfc_vendor_cmd *cmd;
1537 u32 dev_idx, vid, subcmd;
1538 u8 *data;
1539 size_t data_len;
Christophe Ricard29e76922015-08-19 21:26:43 +02001540 int i, err;
Samuel Ortiz9e580952014-10-14 02:19:46 +02001541
1542 if (!info->attrs[NFC_ATTR_DEVICE_INDEX] ||
1543 !info->attrs[NFC_ATTR_VENDOR_ID] ||
1544 !info->attrs[NFC_ATTR_VENDOR_SUBCMD])
1545 return -EINVAL;
1546
1547 dev_idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]);
1548 vid = nla_get_u32(info->attrs[NFC_ATTR_VENDOR_ID]);
1549 subcmd = nla_get_u32(info->attrs[NFC_ATTR_VENDOR_SUBCMD]);
1550
1551 dev = nfc_get_device(dev_idx);
1552 if (!dev || !dev->vendor_cmds || !dev->n_vendor_cmds)
1553 return -ENODEV;
1554
Christophe Ricardfe202fe2015-08-14 22:33:40 +02001555 if (info->attrs[NFC_ATTR_VENDOR_DATA]) {
1556 data = nla_data(info->attrs[NFC_ATTR_VENDOR_DATA]);
Samuel Ortiz9e580952014-10-14 02:19:46 +02001557 data_len = nla_len(info->attrs[NFC_ATTR_VENDOR_DATA]);
1558 if (data_len == 0)
1559 return -EINVAL;
1560 } else {
Christophe Ricardadca3c32015-08-17 08:33:43 +02001561 data = NULL;
Samuel Ortiz9e580952014-10-14 02:19:46 +02001562 data_len = 0;
1563 }
1564
1565 for (i = 0; i < dev->n_vendor_cmds; i++) {
1566 cmd = &dev->vendor_cmds[i];
1567
1568 if (cmd->vendor_id != vid || cmd->subcmd != subcmd)
1569 continue;
1570
Christophe Ricard29e76922015-08-19 21:26:43 +02001571 dev->cur_cmd_info = info;
1572 err = cmd->doit(dev, data, data_len);
1573 dev->cur_cmd_info = NULL;
1574 return err;
Samuel Ortiz9e580952014-10-14 02:19:46 +02001575 }
1576
1577 return -EOPNOTSUPP;
1578}
1579
Christophe Ricard29e76922015-08-19 21:26:43 +02001580/* message building helper */
1581static inline void *nfc_hdr_put(struct sk_buff *skb, u32 portid, u32 seq,
1582 int flags, u8 cmd)
1583{
1584 /* since there is no private header just add the generic one */
1585 return genlmsg_put(skb, portid, seq, &nfc_genl_family, flags, cmd);
1586}
1587
1588static struct sk_buff *
1589__nfc_alloc_vendor_cmd_skb(struct nfc_dev *dev, int approxlen,
1590 u32 portid, u32 seq,
1591 enum nfc_attrs attr,
1592 u32 oui, u32 subcmd, gfp_t gfp)
1593{
1594 struct sk_buff *skb;
1595 void *hdr;
1596
1597 skb = nlmsg_new(approxlen + 100, gfp);
1598 if (!skb)
1599 return NULL;
1600
1601 hdr = nfc_hdr_put(skb, portid, seq, 0, NFC_CMD_VENDOR);
1602 if (!hdr) {
1603 kfree_skb(skb);
1604 return NULL;
1605 }
1606
1607 if (nla_put_u32(skb, NFC_ATTR_DEVICE_INDEX, dev->idx))
1608 goto nla_put_failure;
1609 if (nla_put_u32(skb, NFC_ATTR_VENDOR_ID, oui))
1610 goto nla_put_failure;
1611 if (nla_put_u32(skb, NFC_ATTR_VENDOR_SUBCMD, subcmd))
1612 goto nla_put_failure;
1613
1614 ((void **)skb->cb)[0] = dev;
1615 ((void **)skb->cb)[1] = hdr;
1616
1617 return skb;
1618
1619nla_put_failure:
1620 kfree_skb(skb);
1621 return NULL;
1622}
1623
1624struct sk_buff *__nfc_alloc_vendor_cmd_reply_skb(struct nfc_dev *dev,
1625 enum nfc_attrs attr,
1626 u32 oui, u32 subcmd,
1627 int approxlen)
1628{
1629 if (WARN_ON(!dev->cur_cmd_info))
1630 return NULL;
1631
1632 return __nfc_alloc_vendor_cmd_skb(dev, approxlen,
1633 dev->cur_cmd_info->snd_portid,
1634 dev->cur_cmd_info->snd_seq, attr,
1635 oui, subcmd, GFP_KERNEL);
1636}
1637EXPORT_SYMBOL(__nfc_alloc_vendor_cmd_reply_skb);
1638
1639int nfc_vendor_cmd_reply(struct sk_buff *skb)
1640{
1641 struct nfc_dev *dev = ((void **)skb->cb)[0];
1642 void *hdr = ((void **)skb->cb)[1];
1643
1644 /* clear CB data for netlink core to own from now on */
1645 memset(skb->cb, 0, sizeof(skb->cb));
1646
1647 if (WARN_ON(!dev->cur_cmd_info)) {
1648 kfree_skb(skb);
1649 return -EINVAL;
1650 }
1651
1652 genlmsg_end(skb, hdr);
1653 return genlmsg_reply(skb, dev->cur_cmd_info);
1654}
1655EXPORT_SYMBOL(nfc_vendor_cmd_reply);
1656
Johannes Berg4534de82013-11-14 17:14:46 +01001657static const struct genl_ops nfc_genl_ops[] = {
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -03001658 {
1659 .cmd = NFC_CMD_GET_DEVICE,
Johannes Bergef6243a2019-04-26 14:07:31 +02001660 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -03001661 .doit = nfc_genl_get_device,
1662 .dumpit = nfc_genl_dump_devices,
1663 .done = nfc_genl_dump_devices_done,
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -03001664 },
1665 {
Ilan Elias8b3fe7b2011-09-18 11:19:33 +03001666 .cmd = NFC_CMD_DEV_UP,
Johannes Bergef6243a2019-04-26 14:07:31 +02001667 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Ilan Elias8b3fe7b2011-09-18 11:19:33 +03001668 .doit = nfc_genl_dev_up,
Ilan Elias8b3fe7b2011-09-18 11:19:33 +03001669 },
1670 {
1671 .cmd = NFC_CMD_DEV_DOWN,
Johannes Bergef6243a2019-04-26 14:07:31 +02001672 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Ilan Elias8b3fe7b2011-09-18 11:19:33 +03001673 .doit = nfc_genl_dev_down,
Ilan Elias8b3fe7b2011-09-18 11:19:33 +03001674 },
1675 {
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -03001676 .cmd = NFC_CMD_START_POLL,
Johannes Bergef6243a2019-04-26 14:07:31 +02001677 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -03001678 .doit = nfc_genl_start_poll,
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -03001679 },
1680 {
1681 .cmd = NFC_CMD_STOP_POLL,
Johannes Bergef6243a2019-04-26 14:07:31 +02001682 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -03001683 .doit = nfc_genl_stop_poll,
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -03001684 },
1685 {
Samuel Ortiz1ed28f62011-12-14 16:43:09 +01001686 .cmd = NFC_CMD_DEP_LINK_UP,
Johannes Bergef6243a2019-04-26 14:07:31 +02001687 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Samuel Ortiz1ed28f62011-12-14 16:43:09 +01001688 .doit = nfc_genl_dep_link_up,
Samuel Ortiz1ed28f62011-12-14 16:43:09 +01001689 },
1690 {
1691 .cmd = NFC_CMD_DEP_LINK_DOWN,
Johannes Bergef6243a2019-04-26 14:07:31 +02001692 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Samuel Ortiz1ed28f62011-12-14 16:43:09 +01001693 .doit = nfc_genl_dep_link_down,
Samuel Ortiz1ed28f62011-12-14 16:43:09 +01001694 },
1695 {
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -03001696 .cmd = NFC_CMD_GET_TARGET,
Johannes Bergef6243a2019-04-26 14:07:31 +02001697 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -03001698 .dumpit = nfc_genl_dump_targets,
1699 .done = nfc_genl_dump_targets_done,
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -03001700 },
Thierry Escande52feb442012-10-17 14:43:39 +02001701 {
1702 .cmd = NFC_CMD_LLC_GET_PARAMS,
Johannes Bergef6243a2019-04-26 14:07:31 +02001703 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Thierry Escande52feb442012-10-17 14:43:39 +02001704 .doit = nfc_genl_llc_get_params,
Thierry Escande52feb442012-10-17 14:43:39 +02001705 },
1706 {
1707 .cmd = NFC_CMD_LLC_SET_PARAMS,
Johannes Bergef6243a2019-04-26 14:07:31 +02001708 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Thierry Escande52feb442012-10-17 14:43:39 +02001709 .doit = nfc_genl_llc_set_params,
Thierry Escande52feb442012-10-17 14:43:39 +02001710 },
Thierry Escanded9b8d8e2013-02-15 10:43:06 +01001711 {
1712 .cmd = NFC_CMD_LLC_SDREQ,
Johannes Bergef6243a2019-04-26 14:07:31 +02001713 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Thierry Escanded9b8d8e2013-02-15 10:43:06 +01001714 .doit = nfc_genl_llc_sdreq,
Thierry Escanded9b8d8e2013-02-15 10:43:06 +01001715 },
Eric Lapuyade9674da82013-04-29 17:13:27 +02001716 {
Samuel Ortiz9ea71872013-07-31 01:19:43 +02001717 .cmd = NFC_CMD_FW_DOWNLOAD,
Johannes Bergef6243a2019-04-26 14:07:31 +02001718 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Samuel Ortiz9ea71872013-07-31 01:19:43 +02001719 .doit = nfc_genl_fw_download,
Eric Lapuyade9674da82013-04-29 17:13:27 +02001720 },
Samuel Ortizbe085652013-05-10 17:07:32 +02001721 {
1722 .cmd = NFC_CMD_ENABLE_SE,
Johannes Bergef6243a2019-04-26 14:07:31 +02001723 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Samuel Ortizbe085652013-05-10 17:07:32 +02001724 .doit = nfc_genl_enable_se,
Samuel Ortizbe085652013-05-10 17:07:32 +02001725 },
1726 {
1727 .cmd = NFC_CMD_DISABLE_SE,
Johannes Bergef6243a2019-04-26 14:07:31 +02001728 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Samuel Ortizbe085652013-05-10 17:07:32 +02001729 .doit = nfc_genl_disable_se,
Samuel Ortizbe085652013-05-10 17:07:32 +02001730 },
Samuel Ortizac22ac42013-07-24 18:10:50 +02001731 {
1732 .cmd = NFC_CMD_GET_SE,
Johannes Bergef6243a2019-04-26 14:07:31 +02001733 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Samuel Ortizac22ac42013-07-24 18:10:50 +02001734 .dumpit = nfc_genl_dump_ses,
1735 .done = nfc_genl_dump_ses_done,
Samuel Ortizac22ac42013-07-24 18:10:50 +02001736 },
Samuel Ortiz5ce3f322013-08-28 00:47:24 +02001737 {
1738 .cmd = NFC_CMD_SE_IO,
Johannes Bergef6243a2019-04-26 14:07:31 +02001739 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Samuel Ortiz5ce3f322013-08-28 00:47:24 +02001740 .doit = nfc_genl_se_io,
Samuel Ortiz5ce3f322013-08-28 00:47:24 +02001741 },
Christophe Ricard3682f492014-12-02 21:27:50 +01001742 {
1743 .cmd = NFC_CMD_ACTIVATE_TARGET,
Johannes Bergef6243a2019-04-26 14:07:31 +02001744 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Christophe Ricard3682f492014-12-02 21:27:50 +01001745 .doit = nfc_genl_activate_target,
Christophe Ricard3682f492014-12-02 21:27:50 +01001746 },
Samuel Ortiz9e580952014-10-14 02:19:46 +02001747 {
1748 .cmd = NFC_CMD_VENDOR,
Johannes Bergef6243a2019-04-26 14:07:31 +02001749 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Samuel Ortiz9e580952014-10-14 02:19:46 +02001750 .doit = nfc_genl_vendor_cmd,
Samuel Ortiz9e580952014-10-14 02:19:46 +02001751 },
Mark Greer4d63adf2017-06-15 20:34:22 -07001752 {
1753 .cmd = NFC_CMD_DEACTIVATE_TARGET,
Johannes Bergef6243a2019-04-26 14:07:31 +02001754 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Mark Greer4d63adf2017-06-15 20:34:22 -07001755 .doit = nfc_genl_deactivate_target,
Mark Greer4d63adf2017-06-15 20:34:22 -07001756 },
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -03001757};
1758
Johannes Berg56989f62016-10-24 14:40:05 +02001759static struct genl_family nfc_genl_family __ro_after_init = {
Johannes Berg489111e2016-10-24 14:40:03 +02001760 .hdrsize = 0,
1761 .name = NFC_GENL_NAME,
1762 .version = NFC_GENL_VERSION,
1763 .maxattr = NFC_ATTR_MAX,
Johannes Berg3b0f31f2019-03-21 22:51:02 +01001764 .policy = nfc_genl_policy,
Johannes Berg489111e2016-10-24 14:40:03 +02001765 .module = THIS_MODULE,
1766 .ops = nfc_genl_ops,
1767 .n_ops = ARRAY_SIZE(nfc_genl_ops),
1768 .mcgrps = nfc_genl_mcgrps,
1769 .n_mcgrps = ARRAY_SIZE(nfc_genl_mcgrps),
1770};
1771
Szymon Janc3c0cc8a2012-09-26 14:17:12 +02001772
1773struct urelease_work {
1774 struct work_struct w;
Richard Weinberger65bc4f92015-04-13 00:52:36 +02001775 u32 portid;
Szymon Janc3c0cc8a2012-09-26 14:17:12 +02001776};
1777
1778static void nfc_urelease_event_work(struct work_struct *work)
1779{
1780 struct urelease_work *w = container_of(work, struct urelease_work, w);
1781 struct class_dev_iter iter;
1782 struct nfc_dev *dev;
1783
John W. Linvillec4876062012-09-28 11:11:16 -04001784 pr_debug("portid %d\n", w->portid);
Szymon Janc3c0cc8a2012-09-26 14:17:12 +02001785
1786 mutex_lock(&nfc_devlist_mutex);
1787
1788 nfc_device_iter_init(&iter);
1789 dev = nfc_device_iter_next(&iter);
1790
1791 while (dev) {
1792 mutex_lock(&dev->genl_data.genl_data_mutex);
1793
John W. Linvillec4876062012-09-28 11:11:16 -04001794 if (dev->genl_data.poll_req_portid == w->portid) {
Szymon Janc3c0cc8a2012-09-26 14:17:12 +02001795 nfc_stop_poll(dev);
John W. Linvillec4876062012-09-28 11:11:16 -04001796 dev->genl_data.poll_req_portid = 0;
Szymon Janc3c0cc8a2012-09-26 14:17:12 +02001797 }
1798
1799 mutex_unlock(&dev->genl_data.genl_data_mutex);
1800
1801 dev = nfc_device_iter_next(&iter);
1802 }
1803
1804 nfc_device_iter_exit(&iter);
1805
1806 mutex_unlock(&nfc_devlist_mutex);
1807
1808 kfree(w);
1809}
1810
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -03001811static int nfc_genl_rcv_nl_event(struct notifier_block *this,
Samuel Ortiz0a40acb2012-03-05 01:03:53 +01001812 unsigned long event, void *ptr)
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -03001813{
1814 struct netlink_notify *n = ptr;
Szymon Janc3c0cc8a2012-09-26 14:17:12 +02001815 struct urelease_work *w;
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -03001816
1817 if (event != NETLINK_URELEASE || n->protocol != NETLINK_GENERIC)
1818 goto out;
1819
Eric W. Biederman15e47302012-09-07 20:12:54 +00001820 pr_debug("NETLINK_URELEASE event from id %d\n", n->portid);
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -03001821
Szymon Janc3c0cc8a2012-09-26 14:17:12 +02001822 w = kmalloc(sizeof(*w), GFP_ATOMIC);
1823 if (w) {
1824 INIT_WORK((struct work_struct *) w, nfc_urelease_event_work);
John W. Linvillec4876062012-09-28 11:11:16 -04001825 w->portid = n->portid;
Szymon Janc3c0cc8a2012-09-26 14:17:12 +02001826 schedule_work((struct work_struct *) w);
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -03001827 }
1828
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -03001829out:
1830 return NOTIFY_DONE;
1831}
1832
1833void nfc_genl_data_init(struct nfc_genl_data *genl_data)
1834{
Eric W. Biederman15e47302012-09-07 20:12:54 +00001835 genl_data->poll_req_portid = 0;
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -03001836 mutex_init(&genl_data->genl_data_mutex);
1837}
1838
1839void nfc_genl_data_exit(struct nfc_genl_data *genl_data)
1840{
1841 mutex_destroy(&genl_data->genl_data_mutex);
1842}
1843
1844static struct notifier_block nl_notifier = {
1845 .notifier_call = nfc_genl_rcv_nl_event,
1846};
1847
1848/**
1849 * nfc_genl_init() - Initialize netlink interface
1850 *
1851 * This initialization function registers the nfc netlink family.
1852 */
1853int __init nfc_genl_init(void)
1854{
1855 int rc;
1856
Johannes Berg489111e2016-10-24 14:40:03 +02001857 rc = genl_register_family(&nfc_genl_family);
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -03001858 if (rc)
1859 return rc;
1860
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -03001861 netlink_register_notifier(&nl_notifier);
1862
Johannes Berg2a94fe42013-11-19 15:19:39 +01001863 return 0;
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -03001864}
1865
1866/**
1867 * nfc_genl_exit() - Deinitialize netlink interface
1868 *
1869 * This exit function unregisters the nfc netlink family.
1870 */
1871void nfc_genl_exit(void)
1872{
1873 netlink_unregister_notifier(&nl_notifier);
1874 genl_unregister_family(&nfc_genl_family);
1875}