diff options
author | Samuel Ortiz <sameo@linux.intel.com> | 2011-12-14 10:43:09 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-12-14 14:50:12 -0500 |
commit | 1ed28f610653e9b18433c6d87e9d333b7e3e886e (patch) | |
tree | 176dbd0bfee9c16ef615d6178a26cd1b125e7527 /net/nfc | |
parent | db81a62451b24eaef59f41e6fb312a88e1a83454 (diff) |
NFC: Add a DEP link control netlink command
NFC-DEP (Data Exchange Protocol) is an NFC MAC layer.
This command allows to enable and disable the DEP link on to which e.g.
LLCP can run.
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/nfc')
-rw-r--r-- | net/nfc/core.c | 77 | ||||
-rw-r--r-- | net/nfc/netlink.c | 144 | ||||
-rw-r--r-- | net/nfc/nfc.h | 9 |
3 files changed, 230 insertions, 0 deletions
diff --git a/net/nfc/core.c b/net/nfc/core.c index f53f88ada687..785f1f20c7ba 100644 --- a/net/nfc/core.c +++ b/net/nfc/core.c | |||
@@ -181,6 +181,83 @@ error: | |||
181 | return rc; | 181 | return rc; |
182 | } | 182 | } |
183 | 183 | ||
184 | int nfc_dep_link_up(struct nfc_dev *dev, int target_index, | ||
185 | u8 comm_mode, u8 rf_mode) | ||
186 | { | ||
187 | int rc = 0; | ||
188 | |||
189 | pr_debug("dev_name=%s comm:%d rf:%d\n", | ||
190 | dev_name(&dev->dev), comm_mode, rf_mode); | ||
191 | |||
192 | if (!dev->ops->dep_link_up) | ||
193 | return -EOPNOTSUPP; | ||
194 | |||
195 | device_lock(&dev->dev); | ||
196 | |||
197 | if (!device_is_registered(&dev->dev)) { | ||
198 | rc = -ENODEV; | ||
199 | goto error; | ||
200 | } | ||
201 | |||
202 | if (dev->dep_link_up == true) { | ||
203 | rc = -EALREADY; | ||
204 | goto error; | ||
205 | } | ||
206 | |||
207 | rc = dev->ops->dep_link_up(dev, target_index, comm_mode, rf_mode); | ||
208 | |||
209 | error: | ||
210 | device_unlock(&dev->dev); | ||
211 | return rc; | ||
212 | } | ||
213 | |||
214 | int nfc_dep_link_down(struct nfc_dev *dev) | ||
215 | { | ||
216 | int rc = 0; | ||
217 | |||
218 | pr_debug("dev_name=%s\n", dev_name(&dev->dev)); | ||
219 | |||
220 | if (!dev->ops->dep_link_down) | ||
221 | return -EOPNOTSUPP; | ||
222 | |||
223 | device_lock(&dev->dev); | ||
224 | |||
225 | if (!device_is_registered(&dev->dev)) { | ||
226 | rc = -ENODEV; | ||
227 | goto error; | ||
228 | } | ||
229 | |||
230 | if (dev->dep_link_up == false) { | ||
231 | rc = -EALREADY; | ||
232 | goto error; | ||
233 | } | ||
234 | |||
235 | if (dev->dep_rf_mode == NFC_RF_TARGET) { | ||
236 | rc = -EOPNOTSUPP; | ||
237 | goto error; | ||
238 | } | ||
239 | |||
240 | rc = dev->ops->dep_link_down(dev); | ||
241 | if (!rc) { | ||
242 | dev->dep_link_up = false; | ||
243 | nfc_genl_dep_link_down_event(dev); | ||
244 | } | ||
245 | |||
246 | error: | ||
247 | device_unlock(&dev->dev); | ||
248 | return rc; | ||
249 | } | ||
250 | |||
251 | int nfc_dep_link_is_up(struct nfc_dev *dev, u32 target_idx, | ||
252 | u8 comm_mode, u8 rf_mode) | ||
253 | { | ||
254 | dev->dep_link_up = true; | ||
255 | dev->dep_rf_mode = rf_mode; | ||
256 | |||
257 | return nfc_genl_dep_link_up_event(dev, target_idx, comm_mode, rf_mode); | ||
258 | } | ||
259 | EXPORT_SYMBOL(nfc_dep_link_is_up); | ||
260 | |||
184 | /** | 261 | /** |
185 | * nfc_activate_target - prepare the target for data exchange | 262 | * nfc_activate_target - prepare the target for data exchange |
186 | * | 263 | * |
diff --git a/net/nfc/netlink.c b/net/nfc/netlink.c index 1d76d38c4a24..43a1c47756a7 100644 --- a/net/nfc/netlink.c +++ b/net/nfc/netlink.c | |||
@@ -46,6 +46,8 @@ static const struct nla_policy nfc_genl_policy[NFC_ATTR_MAX + 1] = { | |||
46 | [NFC_ATTR_DEVICE_NAME] = { .type = NLA_STRING, | 46 | [NFC_ATTR_DEVICE_NAME] = { .type = NLA_STRING, |
47 | .len = NFC_DEVICE_NAME_MAXSIZE }, | 47 | .len = NFC_DEVICE_NAME_MAXSIZE }, |
48 | [NFC_ATTR_PROTOCOLS] = { .type = NLA_U32 }, | 48 | [NFC_ATTR_PROTOCOLS] = { .type = NLA_U32 }, |
49 | [NFC_ATTR_COMM_MODE] = { .type = NLA_U8 }, | ||
50 | [NFC_ATTR_RF_MODE] = { .type = NLA_U8 }, | ||
49 | }; | 51 | }; |
50 | 52 | ||
51 | static int nfc_genl_send_target(struct sk_buff *msg, struct nfc_target *target, | 53 | static int nfc_genl_send_target(struct sk_buff *msg, struct nfc_target *target, |
@@ -311,6 +313,75 @@ static int nfc_genl_dump_devices_done(struct netlink_callback *cb) | |||
311 | return 0; | 313 | return 0; |
312 | } | 314 | } |
313 | 315 | ||
316 | int nfc_genl_dep_link_up_event(struct nfc_dev *dev, u32 target_idx, | ||
317 | u8 comm_mode, u8 rf_mode) | ||
318 | { | ||
319 | struct sk_buff *msg; | ||
320 | void *hdr; | ||
321 | |||
322 | pr_debug("DEP link is up\n"); | ||
323 | |||
324 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC); | ||
325 | if (!msg) | ||
326 | return -ENOMEM; | ||
327 | |||
328 | hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0, | ||
329 | NFC_CMD_DEP_LINK_UP); | ||
330 | if (!hdr) | ||
331 | goto free_msg; | ||
332 | |||
333 | NLA_PUT_U32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx); | ||
334 | if (rf_mode == NFC_RF_INITIATOR) | ||
335 | NLA_PUT_U32(msg, NFC_ATTR_TARGET_INDEX, target_idx); | ||
336 | NLA_PUT_U8(msg, NFC_ATTR_COMM_MODE, comm_mode); | ||
337 | NLA_PUT_U8(msg, NFC_ATTR_RF_MODE, rf_mode); | ||
338 | |||
339 | genlmsg_end(msg, hdr); | ||
340 | |||
341 | dev->dep_link_up = true; | ||
342 | |||
343 | genlmsg_multicast(msg, 0, nfc_genl_event_mcgrp.id, GFP_ATOMIC); | ||
344 | |||
345 | return 0; | ||
346 | |||
347 | nla_put_failure: | ||
348 | genlmsg_cancel(msg, hdr); | ||
349 | free_msg: | ||
350 | nlmsg_free(msg); | ||
351 | return -EMSGSIZE; | ||
352 | } | ||
353 | |||
354 | int nfc_genl_dep_link_down_event(struct nfc_dev *dev) | ||
355 | { | ||
356 | struct sk_buff *msg; | ||
357 | void *hdr; | ||
358 | |||
359 | pr_debug("DEP link is down\n"); | ||
360 | |||
361 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC); | ||
362 | if (!msg) | ||
363 | return -ENOMEM; | ||
364 | |||
365 | hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0, | ||
366 | NFC_CMD_DEP_LINK_DOWN); | ||
367 | if (!hdr) | ||
368 | goto free_msg; | ||
369 | |||
370 | NLA_PUT_U32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx); | ||
371 | |||
372 | genlmsg_end(msg, hdr); | ||
373 | |||
374 | genlmsg_multicast(msg, 0, nfc_genl_event_mcgrp.id, GFP_ATOMIC); | ||
375 | |||
376 | return 0; | ||
377 | |||
378 | nla_put_failure: | ||
379 | genlmsg_cancel(msg, hdr); | ||
380 | free_msg: | ||
381 | nlmsg_free(msg); | ||
382 | return -EMSGSIZE; | ||
383 | } | ||
384 | |||
314 | static int nfc_genl_get_device(struct sk_buff *skb, struct genl_info *info) | 385 | static int nfc_genl_get_device(struct sk_buff *skb, struct genl_info *info) |
315 | { | 386 | { |
316 | struct sk_buff *msg; | 387 | struct sk_buff *msg; |
@@ -398,6 +469,8 @@ static int nfc_genl_start_poll(struct sk_buff *skb, struct genl_info *info) | |||
398 | u32 idx; | 469 | u32 idx; |
399 | u32 protocols; | 470 | u32 protocols; |
400 | 471 | ||
472 | pr_debug("Poll start\n"); | ||
473 | |||
401 | if (!info->attrs[NFC_ATTR_DEVICE_INDEX] || | 474 | if (!info->attrs[NFC_ATTR_DEVICE_INDEX] || |
402 | !info->attrs[NFC_ATTR_PROTOCOLS]) | 475 | !info->attrs[NFC_ATTR_PROTOCOLS]) |
403 | return -EINVAL; | 476 | return -EINVAL; |
@@ -452,6 +525,67 @@ out: | |||
452 | return rc; | 525 | return rc; |
453 | } | 526 | } |
454 | 527 | ||
528 | static int nfc_genl_dep_link_up(struct sk_buff *skb, struct genl_info *info) | ||
529 | { | ||
530 | struct nfc_dev *dev; | ||
531 | int rc, tgt_idx; | ||
532 | u32 idx; | ||
533 | u8 comm, rf; | ||
534 | |||
535 | pr_debug("DEP link up\n"); | ||
536 | |||
537 | if (!info->attrs[NFC_ATTR_DEVICE_INDEX] || | ||
538 | !info->attrs[NFC_ATTR_COMM_MODE] || | ||
539 | !info->attrs[NFC_ATTR_RF_MODE]) | ||
540 | return -EINVAL; | ||
541 | |||
542 | idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]); | ||
543 | if (!info->attrs[NFC_ATTR_TARGET_INDEX]) | ||
544 | tgt_idx = NFC_TARGET_IDX_ANY; | ||
545 | else | ||
546 | tgt_idx = nla_get_u32(info->attrs[NFC_ATTR_TARGET_INDEX]); | ||
547 | |||
548 | comm = nla_get_u8(info->attrs[NFC_ATTR_COMM_MODE]); | ||
549 | rf = nla_get_u8(info->attrs[NFC_ATTR_RF_MODE]); | ||
550 | |||
551 | if (comm != NFC_COMM_ACTIVE && comm != NFC_COMM_PASSIVE) | ||
552 | return -EINVAL; | ||
553 | |||
554 | if (rf != NFC_RF_INITIATOR && comm != NFC_RF_TARGET) | ||
555 | return -EINVAL; | ||
556 | |||
557 | dev = nfc_get_device(idx); | ||
558 | if (!dev) | ||
559 | return -ENODEV; | ||
560 | |||
561 | rc = nfc_dep_link_up(dev, tgt_idx, comm, rf); | ||
562 | |||
563 | nfc_put_device(dev); | ||
564 | |||
565 | return rc; | ||
566 | } | ||
567 | |||
568 | static int nfc_genl_dep_link_down(struct sk_buff *skb, struct genl_info *info) | ||
569 | { | ||
570 | struct nfc_dev *dev; | ||
571 | int rc; | ||
572 | u32 idx; | ||
573 | |||
574 | if (!info->attrs[NFC_ATTR_DEVICE_INDEX]) | ||
575 | return -EINVAL; | ||
576 | |||
577 | idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]); | ||
578 | |||
579 | dev = nfc_get_device(idx); | ||
580 | if (!dev) | ||
581 | return -ENODEV; | ||
582 | |||
583 | rc = nfc_dep_link_down(dev); | ||
584 | |||
585 | nfc_put_device(dev); | ||
586 | return rc; | ||
587 | } | ||
588 | |||
455 | static struct genl_ops nfc_genl_ops[] = { | 589 | static struct genl_ops nfc_genl_ops[] = { |
456 | { | 590 | { |
457 | .cmd = NFC_CMD_GET_DEVICE, | 591 | .cmd = NFC_CMD_GET_DEVICE, |
@@ -481,6 +615,16 @@ static struct genl_ops nfc_genl_ops[] = { | |||
481 | .policy = nfc_genl_policy, | 615 | .policy = nfc_genl_policy, |
482 | }, | 616 | }, |
483 | { | 617 | { |
618 | .cmd = NFC_CMD_DEP_LINK_UP, | ||
619 | .doit = nfc_genl_dep_link_up, | ||
620 | .policy = nfc_genl_policy, | ||
621 | }, | ||
622 | { | ||
623 | .cmd = NFC_CMD_DEP_LINK_DOWN, | ||
624 | .doit = nfc_genl_dep_link_down, | ||
625 | .policy = nfc_genl_policy, | ||
626 | }, | ||
627 | { | ||
484 | .cmd = NFC_CMD_GET_TARGET, | 628 | .cmd = NFC_CMD_GET_TARGET, |
485 | .dumpit = nfc_genl_dump_targets, | 629 | .dumpit = nfc_genl_dump_targets, |
486 | .done = nfc_genl_dump_targets_done, | 630 | .done = nfc_genl_dump_targets_done, |
diff --git a/net/nfc/nfc.h b/net/nfc/nfc.h index 67d605015304..4d0fb125d033 100644 --- a/net/nfc/nfc.h +++ b/net/nfc/nfc.h | |||
@@ -68,6 +68,10 @@ int nfc_genl_targets_found(struct nfc_dev *dev); | |||
68 | int nfc_genl_device_added(struct nfc_dev *dev); | 68 | int nfc_genl_device_added(struct nfc_dev *dev); |
69 | int nfc_genl_device_removed(struct nfc_dev *dev); | 69 | int nfc_genl_device_removed(struct nfc_dev *dev); |
70 | 70 | ||
71 | int nfc_genl_dep_link_up_event(struct nfc_dev *dev, u32 target_idx, | ||
72 | u8 comm_mode, u8 rf_mode); | ||
73 | int nfc_genl_dep_link_down_event(struct nfc_dev *dev); | ||
74 | |||
71 | struct nfc_dev *nfc_get_device(unsigned idx); | 75 | struct nfc_dev *nfc_get_device(unsigned idx); |
72 | 76 | ||
73 | static inline void nfc_put_device(struct nfc_dev *dev) | 77 | static inline void nfc_put_device(struct nfc_dev *dev) |
@@ -102,6 +106,11 @@ int nfc_start_poll(struct nfc_dev *dev, u32 protocols); | |||
102 | 106 | ||
103 | int nfc_stop_poll(struct nfc_dev *dev); | 107 | int nfc_stop_poll(struct nfc_dev *dev); |
104 | 108 | ||
109 | int nfc_dep_link_up(struct nfc_dev *dev, int target_idx, | ||
110 | u8 comm_mode, u8 rf_mode); | ||
111 | |||
112 | int nfc_dep_link_down(struct nfc_dev *dev); | ||
113 | |||
105 | int nfc_activate_target(struct nfc_dev *dev, u32 target_idx, u32 protocol); | 114 | int nfc_activate_target(struct nfc_dev *dev, u32 target_idx, u32 protocol); |
106 | 115 | ||
107 | int nfc_deactivate_target(struct nfc_dev *dev, u32 target_idx); | 116 | int nfc_deactivate_target(struct nfc_dev *dev, u32 target_idx); |