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 | |
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>
-rw-r--r-- | include/linux/nfc.h | 14 | ||||
-rw-r--r-- | include/net/nfc/nfc.h | 11 | ||||
-rw-r--r-- | net/nfc/core.c | 77 | ||||
-rw-r--r-- | net/nfc/netlink.c | 144 | ||||
-rw-r--r-- | net/nfc/nfc.h | 9 |
5 files changed, 255 insertions, 0 deletions
diff --git a/include/linux/nfc.h b/include/linux/nfc.h index 36cb955b05cc..34d8303111f0 100644 --- a/include/linux/nfc.h +++ b/include/linux/nfc.h | |||
@@ -62,6 +62,8 @@ enum nfc_commands { | |||
62 | NFC_CMD_GET_DEVICE, | 62 | NFC_CMD_GET_DEVICE, |
63 | NFC_CMD_DEV_UP, | 63 | NFC_CMD_DEV_UP, |
64 | NFC_CMD_DEV_DOWN, | 64 | NFC_CMD_DEV_DOWN, |
65 | NFC_CMD_DEP_LINK_UP, | ||
66 | NFC_CMD_DEP_LINK_DOWN, | ||
65 | NFC_CMD_START_POLL, | 67 | NFC_CMD_START_POLL, |
66 | NFC_CMD_STOP_POLL, | 68 | NFC_CMD_STOP_POLL, |
67 | NFC_CMD_GET_TARGET, | 69 | NFC_CMD_GET_TARGET, |
@@ -86,6 +88,8 @@ enum nfc_commands { | |||
86 | * @NFC_ATTR_TARGET_SENS_RES: NFC-A targets extra information such as NFCID | 88 | * @NFC_ATTR_TARGET_SENS_RES: NFC-A targets extra information such as NFCID |
87 | * @NFC_ATTR_TARGET_SEL_RES: NFC-A targets extra information (useful if the | 89 | * @NFC_ATTR_TARGET_SEL_RES: NFC-A targets extra information (useful if the |
88 | * target is not NFC-Forum compliant) | 90 | * target is not NFC-Forum compliant) |
91 | * @NFC_ATTR_COMM_MODE: Passive or active mode | ||
92 | * @NFC_ATTR_RF_MODE: Initiator or target | ||
89 | */ | 93 | */ |
90 | enum nfc_attrs { | 94 | enum nfc_attrs { |
91 | NFC_ATTR_UNSPEC, | 95 | NFC_ATTR_UNSPEC, |
@@ -95,6 +99,8 @@ enum nfc_attrs { | |||
95 | NFC_ATTR_TARGET_INDEX, | 99 | NFC_ATTR_TARGET_INDEX, |
96 | NFC_ATTR_TARGET_SENS_RES, | 100 | NFC_ATTR_TARGET_SENS_RES, |
97 | NFC_ATTR_TARGET_SEL_RES, | 101 | NFC_ATTR_TARGET_SEL_RES, |
102 | NFC_ATTR_COMM_MODE, | ||
103 | NFC_ATTR_RF_MODE, | ||
98 | /* private: internal use only */ | 104 | /* private: internal use only */ |
99 | __NFC_ATTR_AFTER_LAST | 105 | __NFC_ATTR_AFTER_LAST |
100 | }; | 106 | }; |
@@ -111,6 +117,14 @@ enum nfc_attrs { | |||
111 | 117 | ||
112 | #define NFC_PROTO_MAX 6 | 118 | #define NFC_PROTO_MAX 6 |
113 | 119 | ||
120 | /* NFC communication modes */ | ||
121 | #define NFC_COMM_ACTIVE 0 | ||
122 | #define NFC_COMM_PASSIVE 1 | ||
123 | |||
124 | /* NFC RF modes */ | ||
125 | #define NFC_RF_INITIATOR 0 | ||
126 | #define NFC_RF_TARGET 1 | ||
127 | |||
114 | /* NFC protocols masks used in bitsets */ | 128 | /* NFC protocols masks used in bitsets */ |
115 | #define NFC_PROTO_JEWEL_MASK (1 << NFC_PROTO_JEWEL) | 129 | #define NFC_PROTO_JEWEL_MASK (1 << NFC_PROTO_JEWEL) |
116 | #define NFC_PROTO_MIFARE_MASK (1 << NFC_PROTO_MIFARE) | 130 | #define NFC_PROTO_MIFARE_MASK (1 << NFC_PROTO_MIFARE) |
diff --git a/include/net/nfc/nfc.h b/include/net/nfc/nfc.h index 3a3304c094d7..bf82d292d68c 100644 --- a/include/net/nfc/nfc.h +++ b/include/net/nfc/nfc.h | |||
@@ -52,6 +52,9 @@ struct nfc_ops { | |||
52 | int (*dev_down)(struct nfc_dev *dev); | 52 | int (*dev_down)(struct nfc_dev *dev); |
53 | int (*start_poll)(struct nfc_dev *dev, u32 protocols); | 53 | int (*start_poll)(struct nfc_dev *dev, u32 protocols); |
54 | void (*stop_poll)(struct nfc_dev *dev); | 54 | void (*stop_poll)(struct nfc_dev *dev); |
55 | int (*dep_link_up)(struct nfc_dev *dev, int target_idx, | ||
56 | u8 comm_mode, u8 rf_mode); | ||
57 | int (*dep_link_down)(struct nfc_dev *dev); | ||
55 | int (*activate_target)(struct nfc_dev *dev, u32 target_idx, | 58 | int (*activate_target)(struct nfc_dev *dev, u32 target_idx, |
56 | u32 protocol); | 59 | u32 protocol); |
57 | void (*deactivate_target)(struct nfc_dev *dev, u32 target_idx); | 60 | void (*deactivate_target)(struct nfc_dev *dev, u32 target_idx); |
@@ -60,6 +63,9 @@ struct nfc_ops { | |||
60 | void *cb_context); | 63 | void *cb_context); |
61 | }; | 64 | }; |
62 | 65 | ||
66 | #define NFC_TARGET_IDX_ANY -1 | ||
67 | #define NFC_MAX_GT_LEN 48 | ||
68 | |||
63 | struct nfc_target { | 69 | struct nfc_target { |
64 | u32 idx; | 70 | u32 idx; |
65 | u32 supported_protocols; | 71 | u32 supported_protocols; |
@@ -83,6 +89,8 @@ struct nfc_dev { | |||
83 | bool dev_up; | 89 | bool dev_up; |
84 | bool polling; | 90 | bool polling; |
85 | bool remote_activated; | 91 | bool remote_activated; |
92 | bool dep_link_up; | ||
93 | u32 dep_rf_mode; | ||
86 | struct nfc_genl_data genl_data; | 94 | struct nfc_genl_data genl_data; |
87 | u32 supported_protocols; | 95 | u32 supported_protocols; |
88 | 96 | ||
@@ -165,4 +173,7 @@ struct sk_buff *nfc_alloc_recv_skb(unsigned int size, gfp_t gfp); | |||
165 | int nfc_targets_found(struct nfc_dev *dev, struct nfc_target *targets, | 173 | int nfc_targets_found(struct nfc_dev *dev, struct nfc_target *targets, |
166 | int ntargets); | 174 | int ntargets); |
167 | 175 | ||
176 | int nfc_dep_link_is_up(struct nfc_dev *dev, u32 target_idx, | ||
177 | u8 comm_mode, u8 rf_mode); | ||
178 | |||
168 | #endif /* __NET_NFC_H */ | 179 | #endif /* __NET_NFC_H */ |
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); |