Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

NFC: Extend netlink interface for LTO, RW, and MIUX parameters support

NFC_CMD_LLC_GET_PARAMS: request LTO, RW, and MIUX parameters for a device

NFC_CMD_LLC_SET_PARAMS: set one or more of LTO, RW, and MIUX parameters for
a device. LTO must be set before the link is up otherwise -EINPROGRESS is
returned. RW and MIUX can be set at anytime and will be passed in subsequent
CONNECT and CC messages. If one of the passed parameters is wrong none is
set and -EINVAL is returned.

Signed-off-by: Thierry Escande <thierry.escande@linux.intel.com>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>

authored by

Thierry Escande and committed by
Samuel Ortiz
52feb444 f31652a5

+189 -19
+15
include/uapi/linux/nfc.h
··· 60 60 * target mode. 61 61 * @NFC_EVENT_DEVICE_DEACTIVATED: event emitted when the adapter is deactivated 62 62 * from target mode. 63 + * @NFC_CMD_LLC_GET_PARAMS: request LTO, RW, and MIUX parameters for a device 64 + * @NFC_CMD_LLC_SET_PARAMS: set one or more of LTO, RW, and MIUX parameters for 65 + * a device. LTO must be set before the link is up otherwise -EINPROGRESS 66 + * is returned. RW and MIUX can be set at anytime and will be passed in 67 + * subsequent CONNECT and CC messages. 68 + * If one of the passed parameters is wrong none is set and -EINVAL is 69 + * returned. 63 70 */ 64 71 enum nfc_commands { 65 72 NFC_CMD_UNSPEC, ··· 84 77 NFC_EVENT_TARGET_LOST, 85 78 NFC_EVENT_TM_ACTIVATED, 86 79 NFC_EVENT_TM_DEACTIVATED, 80 + NFC_CMD_LLC_GET_PARAMS, 81 + NFC_CMD_LLC_SET_PARAMS, 87 82 /* private: internal use only */ 88 83 __NFC_CMD_AFTER_LAST 89 84 }; ··· 111 102 * @NFC_ATTR_RF_MODE: Initiator or target 112 103 * @NFC_ATTR_IM_PROTOCOLS: Initiator mode protocols to poll for 113 104 * @NFC_ATTR_TM_PROTOCOLS: Target mode protocols to listen for 105 + * @NFC_ATTR_LLC_PARAM_LTO: Link TimeOut parameter 106 + * @NFC_ATTR_LLC_PARAM_RW: Receive Window size parameter 107 + * @NFC_ATTR_LLC_PARAM_MIUX: MIU eXtension parameter 114 108 */ 115 109 enum nfc_attrs { 116 110 NFC_ATTR_UNSPEC, ··· 131 119 NFC_ATTR_DEVICE_POWERED, 132 120 NFC_ATTR_IM_PROTOCOLS, 133 121 NFC_ATTR_TM_PROTOCOLS, 122 + NFC_ATTR_LLC_PARAM_LTO, 123 + NFC_ATTR_LLC_PARAM_RW, 124 + NFC_ATTR_LLC_PARAM_MIUX, 134 125 /* private: internal use only */ 135 126 __NFC_ATTR_AFTER_LAST 136 127 };
+6 -12
net/nfc/llcp/commands.c
··· 316 316 struct sk_buff *skb; 317 317 u8 *service_name_tlv = NULL, service_name_tlv_length; 318 318 u8 *miux_tlv = NULL, miux_tlv_length; 319 - u8 *rw_tlv = NULL, rw_tlv_length, rw; 320 - __be16 miux; 319 + u8 *rw_tlv = NULL, rw_tlv_length; 321 320 int err; 322 321 u16 size = 0; 323 322 ··· 334 335 size += service_name_tlv_length; 335 336 } 336 337 337 - miux = cpu_to_be16(LLCP_MAX_MIUX); 338 - miux_tlv = nfc_llcp_build_tlv(LLCP_TLV_MIUX, (u8 *)&miux, 0, 338 + miux_tlv = nfc_llcp_build_tlv(LLCP_TLV_MIUX, (u8 *)&local->miux, 0, 339 339 &miux_tlv_length); 340 340 size += miux_tlv_length; 341 341 342 - rw = LLCP_MAX_RW; 343 - rw_tlv = nfc_llcp_build_tlv(LLCP_TLV_RW, &rw, 0, &rw_tlv_length); 342 + rw_tlv = nfc_llcp_build_tlv(LLCP_TLV_RW, &local->rw, 0, &rw_tlv_length); 344 343 size += rw_tlv_length; 345 344 346 345 pr_debug("SKB size %d SN length %zu\n", size, sock->service_name_len); ··· 375 378 struct nfc_llcp_local *local; 376 379 struct sk_buff *skb; 377 380 u8 *miux_tlv = NULL, miux_tlv_length; 378 - u8 *rw_tlv = NULL, rw_tlv_length, rw; 379 - __be16 miux; 381 + u8 *rw_tlv = NULL, rw_tlv_length; 380 382 int err; 381 383 u16 size = 0; 382 384 ··· 385 389 if (local == NULL) 386 390 return -ENODEV; 387 391 388 - miux = cpu_to_be16(LLCP_MAX_MIUX); 389 - miux_tlv = nfc_llcp_build_tlv(LLCP_TLV_MIUX, (u8 *)&miux, 0, 392 + miux_tlv = nfc_llcp_build_tlv(LLCP_TLV_MIUX, (u8 *)&local->miux, 0, 390 393 &miux_tlv_length); 391 394 size += miux_tlv_length; 392 395 393 - rw = LLCP_MAX_RW; 394 - rw_tlv = nfc_llcp_build_tlv(LLCP_TLV_RW, &rw, 0, &rw_tlv_length); 396 + rw_tlv = nfc_llcp_build_tlv(LLCP_TLV_RW, &local->rw, 0, &rw_tlv_length); 395 397 size += rw_tlv_length; 396 398 397 399 skb = llcp_allocate_pdu(sock, LLCP_PDU_CC, size);
+7 -7
net/nfc/llcp/llcp.c
··· 467 467 static int nfc_llcp_build_gb(struct nfc_llcp_local *local) 468 468 { 469 469 u8 *gb_cur, *version_tlv, version, version_length; 470 - u8 *lto_tlv, lto, lto_length; 470 + u8 *lto_tlv, lto_length; 471 471 u8 *wks_tlv, wks_length; 472 472 u8 *miux_tlv, miux_length; 473 - __be16 miux; 474 473 u8 gb_len = 0; 475 474 int ret = 0; 476 475 ··· 478 479 1, &version_length); 479 480 gb_len += version_length; 480 481 481 - /* 1500 ms */ 482 - lto = 150; 483 - lto_tlv = nfc_llcp_build_tlv(LLCP_TLV_LTO, &lto, 1, &lto_length); 482 + lto_tlv = nfc_llcp_build_tlv(LLCP_TLV_LTO, &local->lto, 1, &lto_length); 484 483 gb_len += lto_length; 485 484 486 485 pr_debug("Local wks 0x%lx\n", local->local_wks); ··· 486 489 &wks_length); 487 490 gb_len += wks_length; 488 491 489 - miux = cpu_to_be16(LLCP_MAX_MIUX); 490 - miux_tlv = nfc_llcp_build_tlv(LLCP_TLV_MIUX, (u8 *)&miux, 0, 492 + miux_tlv = nfc_llcp_build_tlv(LLCP_TLV_MIUX, (u8 *)&local->miux, 0, 491 493 &miux_length); 492 494 gb_len += miux_length; 493 495 ··· 1378 1382 rwlock_init(&local->sockets.lock); 1379 1383 rwlock_init(&local->connecting_sockets.lock); 1380 1384 rwlock_init(&local->raw_sockets.lock); 1385 + 1386 + local->lto = 150; /* 1500 ms */ 1387 + local->rw = LLCP_MAX_RW; 1388 + local->miux = cpu_to_be16(LLCP_MAX_MIUX); 1381 1389 1382 1390 nfc_llcp_build_gb(local); 1383 1391
+3
net/nfc/llcp/llcp.h
··· 64 64 u32 target_idx; 65 65 u8 rf_mode; 66 66 u8 comm_mode; 67 + u8 lto; 68 + u8 rw; 69 + __be16 miux; 67 70 unsigned long local_wks; /* Well known services */ 68 71 unsigned long local_sdp; /* Local services */ 69 72 unsigned long local_sap; /* Local SAPs, not available for discovery */
+152
net/nfc/netlink.c
··· 29 29 30 30 #include "nfc.h" 31 31 32 + #include "llcp/llcp.h" 33 + 32 34 static struct genl_multicast_group nfc_genl_event_mcgrp = { 33 35 .name = NFC_GENL_MCAST_EVENT_NAME, 34 36 }; ··· 718 716 return rc; 719 717 } 720 718 719 + static int nfc_genl_send_params(struct sk_buff *msg, 720 + struct nfc_llcp_local *local, 721 + u32 portid, u32 seq) 722 + { 723 + void *hdr; 724 + 725 + hdr = genlmsg_put(msg, portid, seq, &nfc_genl_family, 0, 726 + NFC_CMD_LLC_GET_PARAMS); 727 + if (!hdr) 728 + return -EMSGSIZE; 729 + 730 + if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, local->dev->idx) || 731 + nla_put_u8(msg, NFC_ATTR_LLC_PARAM_LTO, local->lto) || 732 + nla_put_u8(msg, NFC_ATTR_LLC_PARAM_RW, local->rw) || 733 + nla_put_u16(msg, NFC_ATTR_LLC_PARAM_MIUX, be16_to_cpu(local->miux))) 734 + goto nla_put_failure; 735 + 736 + return genlmsg_end(msg, hdr); 737 + 738 + nla_put_failure: 739 + 740 + genlmsg_cancel(msg, hdr); 741 + return -EMSGSIZE; 742 + } 743 + 744 + static int nfc_genl_llc_get_params(struct sk_buff *skb, struct genl_info *info) 745 + { 746 + struct nfc_dev *dev; 747 + struct nfc_llcp_local *local; 748 + int rc = 0; 749 + struct sk_buff *msg = NULL; 750 + u32 idx; 751 + 752 + if (!info->attrs[NFC_ATTR_DEVICE_INDEX]) 753 + return -EINVAL; 754 + 755 + idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]); 756 + 757 + dev = nfc_get_device(idx); 758 + if (!dev) 759 + return -ENODEV; 760 + 761 + device_lock(&dev->dev); 762 + 763 + local = nfc_llcp_find_local(dev); 764 + if (!local) { 765 + rc = -ENODEV; 766 + goto exit; 767 + } 768 + 769 + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 770 + if (!msg) { 771 + rc = -ENOMEM; 772 + goto exit; 773 + } 774 + 775 + rc = nfc_genl_send_params(msg, local, info->snd_portid, info->snd_seq); 776 + 777 + exit: 778 + device_unlock(&dev->dev); 779 + 780 + nfc_put_device(dev); 781 + 782 + if (rc < 0) { 783 + if (msg) 784 + nlmsg_free(msg); 785 + 786 + return rc; 787 + } 788 + 789 + return genlmsg_reply(msg, info); 790 + } 791 + 792 + static int nfc_genl_llc_set_params(struct sk_buff *skb, struct genl_info *info) 793 + { 794 + struct nfc_dev *dev; 795 + struct nfc_llcp_local *local; 796 + u8 rw = 0; 797 + u16 miux = 0; 798 + u32 idx; 799 + int rc = 0; 800 + 801 + if (!info->attrs[NFC_ATTR_DEVICE_INDEX] || 802 + (!info->attrs[NFC_ATTR_LLC_PARAM_LTO] && 803 + !info->attrs[NFC_ATTR_LLC_PARAM_RW] && 804 + !info->attrs[NFC_ATTR_LLC_PARAM_MIUX])) 805 + return -EINVAL; 806 + 807 + if (info->attrs[NFC_ATTR_LLC_PARAM_RW]) { 808 + rw = nla_get_u8(info->attrs[NFC_ATTR_LLC_PARAM_RW]); 809 + 810 + if (rw > LLCP_MAX_RW) 811 + return -EINVAL; 812 + } 813 + 814 + if (info->attrs[NFC_ATTR_LLC_PARAM_MIUX]) { 815 + miux = nla_get_u16(info->attrs[NFC_ATTR_LLC_PARAM_MIUX]); 816 + 817 + if (miux > LLCP_MAX_MIUX) 818 + return -EINVAL; 819 + } 820 + 821 + idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]); 822 + 823 + dev = nfc_get_device(idx); 824 + if (!dev) 825 + return -ENODEV; 826 + 827 + device_lock(&dev->dev); 828 + 829 + local = nfc_llcp_find_local(dev); 830 + if (!local) { 831 + nfc_put_device(dev); 832 + rc = -ENODEV; 833 + goto exit; 834 + } 835 + 836 + if (info->attrs[NFC_ATTR_LLC_PARAM_LTO]) { 837 + if (dev->dep_link_up) { 838 + rc = -EINPROGRESS; 839 + goto exit; 840 + } 841 + 842 + local->lto = nla_get_u8(info->attrs[NFC_ATTR_LLC_PARAM_LTO]); 843 + } 844 + 845 + if (info->attrs[NFC_ATTR_LLC_PARAM_RW]) 846 + local->rw = rw; 847 + 848 + if (info->attrs[NFC_ATTR_LLC_PARAM_MIUX]) 849 + local->miux = cpu_to_be16(miux); 850 + 851 + exit: 852 + device_unlock(&dev->dev); 853 + 854 + nfc_put_device(dev); 855 + 856 + return rc; 857 + } 858 + 721 859 static struct genl_ops nfc_genl_ops[] = { 722 860 { 723 861 .cmd = NFC_CMD_GET_DEVICE, ··· 900 758 .cmd = NFC_CMD_GET_TARGET, 901 759 .dumpit = nfc_genl_dump_targets, 902 760 .done = nfc_genl_dump_targets_done, 761 + .policy = nfc_genl_policy, 762 + }, 763 + { 764 + .cmd = NFC_CMD_LLC_GET_PARAMS, 765 + .doit = nfc_genl_llc_get_params, 766 + .policy = nfc_genl_policy, 767 + }, 768 + { 769 + .cmd = NFC_CMD_LLC_SET_PARAMS, 770 + .doit = nfc_genl_llc_set_params, 903 771 .policy = nfc_genl_policy, 904 772 }, 905 773 };
+6
net/nfc/nfc.h
··· 56 56 int nfc_llcp_set_remote_gb(struct nfc_dev *dev, u8 *gb, u8 gb_len); 57 57 u8 *nfc_llcp_general_bytes(struct nfc_dev *dev, size_t *general_bytes_len); 58 58 int nfc_llcp_data_received(struct nfc_dev *dev, struct sk_buff *skb); 59 + struct nfc_llcp_local *nfc_llcp_find_local(struct nfc_dev *dev); 59 60 int __init nfc_llcp_init(void); 60 61 void nfc_llcp_exit(void); 61 62 ··· 96 95 struct sk_buff *skb) 97 96 { 98 97 return 0; 98 + } 99 + 100 + static inline struct nfc_llcp_local *nfc_llcp_find_local(struct nfc_dev *dev) 101 + { 102 + return NULL; 99 103 } 100 104 101 105 static inline int nfc_llcp_init(void)