18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2011 Instituto Nokia de Tecnologia 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Authors: 68c2ecf20Sopenharmony_ci * Lauro Ramos Venancio <lauro.venancio@openbossa.org> 78c2ecf20Sopenharmony_ci * Aloisio Almeida Jr <aloisio.almeida@openbossa.org> 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Vendor commands implementation based on net/wireless/nl80211.c 108c2ecf20Sopenharmony_ci * which is: 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net> 138c2ecf20Sopenharmony_ci * Copyright 2013-2014 Intel Mobile Communications GmbH 148c2ecf20Sopenharmony_ci */ 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": %s: " fmt, __func__ 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include <net/genetlink.h> 198c2ecf20Sopenharmony_ci#include <linux/nfc.h> 208c2ecf20Sopenharmony_ci#include <linux/slab.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#include "nfc.h" 238c2ecf20Sopenharmony_ci#include "llcp.h" 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistatic const struct genl_multicast_group nfc_genl_mcgrps[] = { 268c2ecf20Sopenharmony_ci { .name = NFC_GENL_MCAST_EVENT_NAME, }, 278c2ecf20Sopenharmony_ci}; 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_cistatic struct genl_family nfc_genl_family; 308c2ecf20Sopenharmony_cistatic const struct nla_policy nfc_genl_policy[NFC_ATTR_MAX + 1] = { 318c2ecf20Sopenharmony_ci [NFC_ATTR_DEVICE_INDEX] = { .type = NLA_U32 }, 328c2ecf20Sopenharmony_ci [NFC_ATTR_DEVICE_NAME] = { .type = NLA_STRING, 338c2ecf20Sopenharmony_ci .len = NFC_DEVICE_NAME_MAXSIZE }, 348c2ecf20Sopenharmony_ci [NFC_ATTR_PROTOCOLS] = { .type = NLA_U32 }, 358c2ecf20Sopenharmony_ci [NFC_ATTR_TARGET_INDEX] = { .type = NLA_U32 }, 368c2ecf20Sopenharmony_ci [NFC_ATTR_COMM_MODE] = { .type = NLA_U8 }, 378c2ecf20Sopenharmony_ci [NFC_ATTR_RF_MODE] = { .type = NLA_U8 }, 388c2ecf20Sopenharmony_ci [NFC_ATTR_DEVICE_POWERED] = { .type = NLA_U8 }, 398c2ecf20Sopenharmony_ci [NFC_ATTR_IM_PROTOCOLS] = { .type = NLA_U32 }, 408c2ecf20Sopenharmony_ci [NFC_ATTR_TM_PROTOCOLS] = { .type = NLA_U32 }, 418c2ecf20Sopenharmony_ci [NFC_ATTR_LLC_PARAM_LTO] = { .type = NLA_U8 }, 428c2ecf20Sopenharmony_ci [NFC_ATTR_LLC_PARAM_RW] = { .type = NLA_U8 }, 438c2ecf20Sopenharmony_ci [NFC_ATTR_LLC_PARAM_MIUX] = { .type = NLA_U16 }, 448c2ecf20Sopenharmony_ci [NFC_ATTR_LLC_SDP] = { .type = NLA_NESTED }, 458c2ecf20Sopenharmony_ci [NFC_ATTR_FIRMWARE_NAME] = { .type = NLA_STRING, 468c2ecf20Sopenharmony_ci .len = NFC_FIRMWARE_NAME_MAXSIZE }, 478c2ecf20Sopenharmony_ci [NFC_ATTR_SE_INDEX] = { .type = NLA_U32 }, 488c2ecf20Sopenharmony_ci [NFC_ATTR_SE_APDU] = { .type = NLA_BINARY }, 498c2ecf20Sopenharmony_ci [NFC_ATTR_VENDOR_ID] = { .type = NLA_U32 }, 508c2ecf20Sopenharmony_ci [NFC_ATTR_VENDOR_SUBCMD] = { .type = NLA_U32 }, 518c2ecf20Sopenharmony_ci [NFC_ATTR_VENDOR_DATA] = { .type = NLA_BINARY }, 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci}; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_cistatic const struct nla_policy nfc_sdp_genl_policy[NFC_SDP_ATTR_MAX + 1] = { 568c2ecf20Sopenharmony_ci [NFC_SDP_ATTR_URI] = { .type = NLA_STRING, 578c2ecf20Sopenharmony_ci .len = U8_MAX - 4 }, 588c2ecf20Sopenharmony_ci [NFC_SDP_ATTR_SAP] = { .type = NLA_U8 }, 598c2ecf20Sopenharmony_ci}; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_cistatic int nfc_genl_send_target(struct sk_buff *msg, struct nfc_target *target, 628c2ecf20Sopenharmony_ci struct netlink_callback *cb, int flags) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci void *hdr; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci hdr = genlmsg_put(msg, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, 678c2ecf20Sopenharmony_ci &nfc_genl_family, flags, NFC_CMD_GET_TARGET); 688c2ecf20Sopenharmony_ci if (!hdr) 698c2ecf20Sopenharmony_ci return -EMSGSIZE; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci genl_dump_check_consistent(cb, hdr); 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci if (nla_put_u32(msg, NFC_ATTR_TARGET_INDEX, target->idx) || 748c2ecf20Sopenharmony_ci nla_put_u32(msg, NFC_ATTR_PROTOCOLS, target->supported_protocols) || 758c2ecf20Sopenharmony_ci nla_put_u16(msg, NFC_ATTR_TARGET_SENS_RES, target->sens_res) || 768c2ecf20Sopenharmony_ci nla_put_u8(msg, NFC_ATTR_TARGET_SEL_RES, target->sel_res)) 778c2ecf20Sopenharmony_ci goto nla_put_failure; 788c2ecf20Sopenharmony_ci if (target->nfcid1_len > 0 && 798c2ecf20Sopenharmony_ci nla_put(msg, NFC_ATTR_TARGET_NFCID1, target->nfcid1_len, 808c2ecf20Sopenharmony_ci target->nfcid1)) 818c2ecf20Sopenharmony_ci goto nla_put_failure; 828c2ecf20Sopenharmony_ci if (target->sensb_res_len > 0 && 838c2ecf20Sopenharmony_ci nla_put(msg, NFC_ATTR_TARGET_SENSB_RES, target->sensb_res_len, 848c2ecf20Sopenharmony_ci target->sensb_res)) 858c2ecf20Sopenharmony_ci goto nla_put_failure; 868c2ecf20Sopenharmony_ci if (target->sensf_res_len > 0 && 878c2ecf20Sopenharmony_ci nla_put(msg, NFC_ATTR_TARGET_SENSF_RES, target->sensf_res_len, 888c2ecf20Sopenharmony_ci target->sensf_res)) 898c2ecf20Sopenharmony_ci goto nla_put_failure; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci if (target->is_iso15693) { 928c2ecf20Sopenharmony_ci if (nla_put_u8(msg, NFC_ATTR_TARGET_ISO15693_DSFID, 938c2ecf20Sopenharmony_ci target->iso15693_dsfid) || 948c2ecf20Sopenharmony_ci nla_put(msg, NFC_ATTR_TARGET_ISO15693_UID, 958c2ecf20Sopenharmony_ci sizeof(target->iso15693_uid), target->iso15693_uid)) 968c2ecf20Sopenharmony_ci goto nla_put_failure; 978c2ecf20Sopenharmony_ci } 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci genlmsg_end(msg, hdr); 1008c2ecf20Sopenharmony_ci return 0; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_cinla_put_failure: 1038c2ecf20Sopenharmony_ci genlmsg_cancel(msg, hdr); 1048c2ecf20Sopenharmony_ci return -EMSGSIZE; 1058c2ecf20Sopenharmony_ci} 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_cistatic struct nfc_dev *__get_device_from_cb(struct netlink_callback *cb) 1088c2ecf20Sopenharmony_ci{ 1098c2ecf20Sopenharmony_ci const struct genl_dumpit_info *info = genl_dumpit_info(cb); 1108c2ecf20Sopenharmony_ci struct nfc_dev *dev; 1118c2ecf20Sopenharmony_ci u32 idx; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci if (!info->attrs[NFC_ATTR_DEVICE_INDEX]) 1148c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]); 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci dev = nfc_get_device(idx); 1198c2ecf20Sopenharmony_ci if (!dev) 1208c2ecf20Sopenharmony_ci return ERR_PTR(-ENODEV); 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci return dev; 1238c2ecf20Sopenharmony_ci} 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_cistatic int nfc_genl_dump_targets(struct sk_buff *skb, 1268c2ecf20Sopenharmony_ci struct netlink_callback *cb) 1278c2ecf20Sopenharmony_ci{ 1288c2ecf20Sopenharmony_ci int i = cb->args[0]; 1298c2ecf20Sopenharmony_ci struct nfc_dev *dev = (struct nfc_dev *) cb->args[1]; 1308c2ecf20Sopenharmony_ci int rc; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci if (!dev) { 1338c2ecf20Sopenharmony_ci dev = __get_device_from_cb(cb); 1348c2ecf20Sopenharmony_ci if (IS_ERR(dev)) 1358c2ecf20Sopenharmony_ci return PTR_ERR(dev); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci cb->args[1] = (long) dev; 1388c2ecf20Sopenharmony_ci } 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci device_lock(&dev->dev); 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci cb->seq = dev->targets_generation; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci while (i < dev->n_targets) { 1458c2ecf20Sopenharmony_ci rc = nfc_genl_send_target(skb, &dev->targets[i], cb, 1468c2ecf20Sopenharmony_ci NLM_F_MULTI); 1478c2ecf20Sopenharmony_ci if (rc < 0) 1488c2ecf20Sopenharmony_ci break; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci i++; 1518c2ecf20Sopenharmony_ci } 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci device_unlock(&dev->dev); 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci cb->args[0] = i; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci return skb->len; 1588c2ecf20Sopenharmony_ci} 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_cistatic int nfc_genl_dump_targets_done(struct netlink_callback *cb) 1618c2ecf20Sopenharmony_ci{ 1628c2ecf20Sopenharmony_ci struct nfc_dev *dev = (struct nfc_dev *) cb->args[1]; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci if (dev) 1658c2ecf20Sopenharmony_ci nfc_put_device(dev); 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci return 0; 1688c2ecf20Sopenharmony_ci} 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ciint nfc_genl_targets_found(struct nfc_dev *dev) 1718c2ecf20Sopenharmony_ci{ 1728c2ecf20Sopenharmony_ci struct sk_buff *msg; 1738c2ecf20Sopenharmony_ci void *hdr; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci dev->genl_data.poll_req_portid = 0; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); 1788c2ecf20Sopenharmony_ci if (!msg) 1798c2ecf20Sopenharmony_ci return -ENOMEM; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0, 1828c2ecf20Sopenharmony_ci NFC_EVENT_TARGETS_FOUND); 1838c2ecf20Sopenharmony_ci if (!hdr) 1848c2ecf20Sopenharmony_ci goto free_msg; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx)) 1878c2ecf20Sopenharmony_ci goto nla_put_failure; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci genlmsg_end(msg, hdr); 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci return genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_ATOMIC); 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_cinla_put_failure: 1948c2ecf20Sopenharmony_cifree_msg: 1958c2ecf20Sopenharmony_ci nlmsg_free(msg); 1968c2ecf20Sopenharmony_ci return -EMSGSIZE; 1978c2ecf20Sopenharmony_ci} 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ciint nfc_genl_target_lost(struct nfc_dev *dev, u32 target_idx) 2008c2ecf20Sopenharmony_ci{ 2018c2ecf20Sopenharmony_ci struct sk_buff *msg; 2028c2ecf20Sopenharmony_ci void *hdr; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 2058c2ecf20Sopenharmony_ci if (!msg) 2068c2ecf20Sopenharmony_ci return -ENOMEM; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0, 2098c2ecf20Sopenharmony_ci NFC_EVENT_TARGET_LOST); 2108c2ecf20Sopenharmony_ci if (!hdr) 2118c2ecf20Sopenharmony_ci goto free_msg; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci if (nla_put_string(msg, NFC_ATTR_DEVICE_NAME, nfc_device_name(dev)) || 2148c2ecf20Sopenharmony_ci nla_put_u32(msg, NFC_ATTR_TARGET_INDEX, target_idx)) 2158c2ecf20Sopenharmony_ci goto nla_put_failure; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci genlmsg_end(msg, hdr); 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_KERNEL); 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci return 0; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_cinla_put_failure: 2248c2ecf20Sopenharmony_cifree_msg: 2258c2ecf20Sopenharmony_ci nlmsg_free(msg); 2268c2ecf20Sopenharmony_ci return -EMSGSIZE; 2278c2ecf20Sopenharmony_ci} 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ciint nfc_genl_tm_activated(struct nfc_dev *dev, u32 protocol) 2308c2ecf20Sopenharmony_ci{ 2318c2ecf20Sopenharmony_ci struct sk_buff *msg; 2328c2ecf20Sopenharmony_ci void *hdr; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 2358c2ecf20Sopenharmony_ci if (!msg) 2368c2ecf20Sopenharmony_ci return -ENOMEM; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0, 2398c2ecf20Sopenharmony_ci NFC_EVENT_TM_ACTIVATED); 2408c2ecf20Sopenharmony_ci if (!hdr) 2418c2ecf20Sopenharmony_ci goto free_msg; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx)) 2448c2ecf20Sopenharmony_ci goto nla_put_failure; 2458c2ecf20Sopenharmony_ci if (nla_put_u32(msg, NFC_ATTR_TM_PROTOCOLS, protocol)) 2468c2ecf20Sopenharmony_ci goto nla_put_failure; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci genlmsg_end(msg, hdr); 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_KERNEL); 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci return 0; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_cinla_put_failure: 2558c2ecf20Sopenharmony_cifree_msg: 2568c2ecf20Sopenharmony_ci nlmsg_free(msg); 2578c2ecf20Sopenharmony_ci return -EMSGSIZE; 2588c2ecf20Sopenharmony_ci} 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ciint nfc_genl_tm_deactivated(struct nfc_dev *dev) 2618c2ecf20Sopenharmony_ci{ 2628c2ecf20Sopenharmony_ci struct sk_buff *msg; 2638c2ecf20Sopenharmony_ci void *hdr; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 2668c2ecf20Sopenharmony_ci if (!msg) 2678c2ecf20Sopenharmony_ci return -ENOMEM; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0, 2708c2ecf20Sopenharmony_ci NFC_EVENT_TM_DEACTIVATED); 2718c2ecf20Sopenharmony_ci if (!hdr) 2728c2ecf20Sopenharmony_ci goto free_msg; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx)) 2758c2ecf20Sopenharmony_ci goto nla_put_failure; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci genlmsg_end(msg, hdr); 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_KERNEL); 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci return 0; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_cinla_put_failure: 2848c2ecf20Sopenharmony_cifree_msg: 2858c2ecf20Sopenharmony_ci nlmsg_free(msg); 2868c2ecf20Sopenharmony_ci return -EMSGSIZE; 2878c2ecf20Sopenharmony_ci} 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_cistatic int nfc_genl_setup_device_added(struct nfc_dev *dev, struct sk_buff *msg) 2908c2ecf20Sopenharmony_ci{ 2918c2ecf20Sopenharmony_ci if (nla_put_string(msg, NFC_ATTR_DEVICE_NAME, nfc_device_name(dev)) || 2928c2ecf20Sopenharmony_ci nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx) || 2938c2ecf20Sopenharmony_ci nla_put_u32(msg, NFC_ATTR_PROTOCOLS, dev->supported_protocols) || 2948c2ecf20Sopenharmony_ci nla_put_u8(msg, NFC_ATTR_DEVICE_POWERED, dev->dev_up) || 2958c2ecf20Sopenharmony_ci nla_put_u8(msg, NFC_ATTR_RF_MODE, dev->rf_mode)) 2968c2ecf20Sopenharmony_ci return -1; 2978c2ecf20Sopenharmony_ci return 0; 2988c2ecf20Sopenharmony_ci} 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ciint nfc_genl_device_added(struct nfc_dev *dev) 3018c2ecf20Sopenharmony_ci{ 3028c2ecf20Sopenharmony_ci struct sk_buff *msg; 3038c2ecf20Sopenharmony_ci void *hdr; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 3068c2ecf20Sopenharmony_ci if (!msg) 3078c2ecf20Sopenharmony_ci return -ENOMEM; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0, 3108c2ecf20Sopenharmony_ci NFC_EVENT_DEVICE_ADDED); 3118c2ecf20Sopenharmony_ci if (!hdr) 3128c2ecf20Sopenharmony_ci goto free_msg; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci if (nfc_genl_setup_device_added(dev, msg)) 3158c2ecf20Sopenharmony_ci goto nla_put_failure; 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci genlmsg_end(msg, hdr); 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_KERNEL); 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci return 0; 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_cinla_put_failure: 3248c2ecf20Sopenharmony_cifree_msg: 3258c2ecf20Sopenharmony_ci nlmsg_free(msg); 3268c2ecf20Sopenharmony_ci return -EMSGSIZE; 3278c2ecf20Sopenharmony_ci} 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ciint nfc_genl_device_removed(struct nfc_dev *dev) 3308c2ecf20Sopenharmony_ci{ 3318c2ecf20Sopenharmony_ci struct sk_buff *msg; 3328c2ecf20Sopenharmony_ci void *hdr; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 3358c2ecf20Sopenharmony_ci if (!msg) 3368c2ecf20Sopenharmony_ci return -ENOMEM; 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0, 3398c2ecf20Sopenharmony_ci NFC_EVENT_DEVICE_REMOVED); 3408c2ecf20Sopenharmony_ci if (!hdr) 3418c2ecf20Sopenharmony_ci goto free_msg; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx)) 3448c2ecf20Sopenharmony_ci goto nla_put_failure; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci genlmsg_end(msg, hdr); 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_KERNEL); 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci return 0; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_cinla_put_failure: 3538c2ecf20Sopenharmony_cifree_msg: 3548c2ecf20Sopenharmony_ci nlmsg_free(msg); 3558c2ecf20Sopenharmony_ci return -EMSGSIZE; 3568c2ecf20Sopenharmony_ci} 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ciint nfc_genl_llc_send_sdres(struct nfc_dev *dev, struct hlist_head *sdres_list) 3598c2ecf20Sopenharmony_ci{ 3608c2ecf20Sopenharmony_ci struct sk_buff *msg; 3618c2ecf20Sopenharmony_ci struct nlattr *sdp_attr, *uri_attr; 3628c2ecf20Sopenharmony_ci struct nfc_llcp_sdp_tlv *sdres; 3638c2ecf20Sopenharmony_ci struct hlist_node *n; 3648c2ecf20Sopenharmony_ci void *hdr; 3658c2ecf20Sopenharmony_ci int rc = -EMSGSIZE; 3668c2ecf20Sopenharmony_ci int i; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 3698c2ecf20Sopenharmony_ci if (!msg) 3708c2ecf20Sopenharmony_ci return -ENOMEM; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0, 3738c2ecf20Sopenharmony_ci NFC_EVENT_LLC_SDRES); 3748c2ecf20Sopenharmony_ci if (!hdr) 3758c2ecf20Sopenharmony_ci goto free_msg; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx)) 3788c2ecf20Sopenharmony_ci goto nla_put_failure; 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci sdp_attr = nla_nest_start_noflag(msg, NFC_ATTR_LLC_SDP); 3818c2ecf20Sopenharmony_ci if (sdp_attr == NULL) { 3828c2ecf20Sopenharmony_ci rc = -ENOMEM; 3838c2ecf20Sopenharmony_ci goto nla_put_failure; 3848c2ecf20Sopenharmony_ci } 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci i = 1; 3878c2ecf20Sopenharmony_ci hlist_for_each_entry_safe(sdres, n, sdres_list, node) { 3888c2ecf20Sopenharmony_ci pr_debug("uri: %s, sap: %d\n", sdres->uri, sdres->sap); 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci uri_attr = nla_nest_start_noflag(msg, i++); 3918c2ecf20Sopenharmony_ci if (uri_attr == NULL) { 3928c2ecf20Sopenharmony_ci rc = -ENOMEM; 3938c2ecf20Sopenharmony_ci goto nla_put_failure; 3948c2ecf20Sopenharmony_ci } 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci if (nla_put_u8(msg, NFC_SDP_ATTR_SAP, sdres->sap)) 3978c2ecf20Sopenharmony_ci goto nla_put_failure; 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci if (nla_put_string(msg, NFC_SDP_ATTR_URI, sdres->uri)) 4008c2ecf20Sopenharmony_ci goto nla_put_failure; 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci nla_nest_end(msg, uri_attr); 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci hlist_del(&sdres->node); 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci nfc_llcp_free_sdp_tlv(sdres); 4078c2ecf20Sopenharmony_ci } 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci nla_nest_end(msg, sdp_attr); 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci genlmsg_end(msg, hdr); 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci return genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_ATOMIC); 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_cinla_put_failure: 4168c2ecf20Sopenharmony_cifree_msg: 4178c2ecf20Sopenharmony_ci nlmsg_free(msg); 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci nfc_llcp_free_sdp_tlv_list(sdres_list); 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci return rc; 4228c2ecf20Sopenharmony_ci} 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ciint nfc_genl_se_added(struct nfc_dev *dev, u32 se_idx, u16 type) 4258c2ecf20Sopenharmony_ci{ 4268c2ecf20Sopenharmony_ci struct sk_buff *msg; 4278c2ecf20Sopenharmony_ci void *hdr; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 4308c2ecf20Sopenharmony_ci if (!msg) 4318c2ecf20Sopenharmony_ci return -ENOMEM; 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0, 4348c2ecf20Sopenharmony_ci NFC_EVENT_SE_ADDED); 4358c2ecf20Sopenharmony_ci if (!hdr) 4368c2ecf20Sopenharmony_ci goto free_msg; 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx) || 4398c2ecf20Sopenharmony_ci nla_put_u32(msg, NFC_ATTR_SE_INDEX, se_idx) || 4408c2ecf20Sopenharmony_ci nla_put_u8(msg, NFC_ATTR_SE_TYPE, type)) 4418c2ecf20Sopenharmony_ci goto nla_put_failure; 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci genlmsg_end(msg, hdr); 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_KERNEL); 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci return 0; 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_cinla_put_failure: 4508c2ecf20Sopenharmony_cifree_msg: 4518c2ecf20Sopenharmony_ci nlmsg_free(msg); 4528c2ecf20Sopenharmony_ci return -EMSGSIZE; 4538c2ecf20Sopenharmony_ci} 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ciint nfc_genl_se_removed(struct nfc_dev *dev, u32 se_idx) 4568c2ecf20Sopenharmony_ci{ 4578c2ecf20Sopenharmony_ci struct sk_buff *msg; 4588c2ecf20Sopenharmony_ci void *hdr; 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 4618c2ecf20Sopenharmony_ci if (!msg) 4628c2ecf20Sopenharmony_ci return -ENOMEM; 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0, 4658c2ecf20Sopenharmony_ci NFC_EVENT_SE_REMOVED); 4668c2ecf20Sopenharmony_ci if (!hdr) 4678c2ecf20Sopenharmony_ci goto free_msg; 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx) || 4708c2ecf20Sopenharmony_ci nla_put_u32(msg, NFC_ATTR_SE_INDEX, se_idx)) 4718c2ecf20Sopenharmony_ci goto nla_put_failure; 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci genlmsg_end(msg, hdr); 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_KERNEL); 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci return 0; 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_cinla_put_failure: 4808c2ecf20Sopenharmony_cifree_msg: 4818c2ecf20Sopenharmony_ci nlmsg_free(msg); 4828c2ecf20Sopenharmony_ci return -EMSGSIZE; 4838c2ecf20Sopenharmony_ci} 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ciint nfc_genl_se_transaction(struct nfc_dev *dev, u8 se_idx, 4868c2ecf20Sopenharmony_ci struct nfc_evt_transaction *evt_transaction) 4878c2ecf20Sopenharmony_ci{ 4888c2ecf20Sopenharmony_ci struct nfc_se *se; 4898c2ecf20Sopenharmony_ci struct sk_buff *msg; 4908c2ecf20Sopenharmony_ci void *hdr; 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 4938c2ecf20Sopenharmony_ci if (!msg) 4948c2ecf20Sopenharmony_ci return -ENOMEM; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0, 4978c2ecf20Sopenharmony_ci NFC_EVENT_SE_TRANSACTION); 4988c2ecf20Sopenharmony_ci if (!hdr) 4998c2ecf20Sopenharmony_ci goto free_msg; 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci se = nfc_find_se(dev, se_idx); 5028c2ecf20Sopenharmony_ci if (!se) 5038c2ecf20Sopenharmony_ci goto free_msg; 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx) || 5068c2ecf20Sopenharmony_ci nla_put_u32(msg, NFC_ATTR_SE_INDEX, se_idx) || 5078c2ecf20Sopenharmony_ci nla_put_u8(msg, NFC_ATTR_SE_TYPE, se->type) || 5088c2ecf20Sopenharmony_ci nla_put(msg, NFC_ATTR_SE_AID, evt_transaction->aid_len, 5098c2ecf20Sopenharmony_ci evt_transaction->aid) || 5108c2ecf20Sopenharmony_ci nla_put(msg, NFC_ATTR_SE_PARAMS, evt_transaction->params_len, 5118c2ecf20Sopenharmony_ci evt_transaction->params)) 5128c2ecf20Sopenharmony_ci goto nla_put_failure; 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci /* evt_transaction is no more used */ 5158c2ecf20Sopenharmony_ci devm_kfree(&dev->dev, evt_transaction); 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci genlmsg_end(msg, hdr); 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_KERNEL); 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci return 0; 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_cinla_put_failure: 5248c2ecf20Sopenharmony_cifree_msg: 5258c2ecf20Sopenharmony_ci /* evt_transaction is no more used */ 5268c2ecf20Sopenharmony_ci devm_kfree(&dev->dev, evt_transaction); 5278c2ecf20Sopenharmony_ci nlmsg_free(msg); 5288c2ecf20Sopenharmony_ci return -EMSGSIZE; 5298c2ecf20Sopenharmony_ci} 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ciint nfc_genl_se_connectivity(struct nfc_dev *dev, u8 se_idx) 5328c2ecf20Sopenharmony_ci{ 5338c2ecf20Sopenharmony_ci struct nfc_se *se; 5348c2ecf20Sopenharmony_ci struct sk_buff *msg; 5358c2ecf20Sopenharmony_ci void *hdr; 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 5388c2ecf20Sopenharmony_ci if (!msg) 5398c2ecf20Sopenharmony_ci return -ENOMEM; 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0, 5428c2ecf20Sopenharmony_ci NFC_EVENT_SE_CONNECTIVITY); 5438c2ecf20Sopenharmony_ci if (!hdr) 5448c2ecf20Sopenharmony_ci goto free_msg; 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci se = nfc_find_se(dev, se_idx); 5478c2ecf20Sopenharmony_ci if (!se) 5488c2ecf20Sopenharmony_ci goto free_msg; 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx) || 5518c2ecf20Sopenharmony_ci nla_put_u32(msg, NFC_ATTR_SE_INDEX, se_idx) || 5528c2ecf20Sopenharmony_ci nla_put_u8(msg, NFC_ATTR_SE_TYPE, se->type)) 5538c2ecf20Sopenharmony_ci goto nla_put_failure; 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci genlmsg_end(msg, hdr); 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_KERNEL); 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci return 0; 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_cinla_put_failure: 5628c2ecf20Sopenharmony_cifree_msg: 5638c2ecf20Sopenharmony_ci nlmsg_free(msg); 5648c2ecf20Sopenharmony_ci return -EMSGSIZE; 5658c2ecf20Sopenharmony_ci} 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_cistatic int nfc_genl_send_device(struct sk_buff *msg, struct nfc_dev *dev, 5688c2ecf20Sopenharmony_ci u32 portid, u32 seq, 5698c2ecf20Sopenharmony_ci struct netlink_callback *cb, 5708c2ecf20Sopenharmony_ci int flags) 5718c2ecf20Sopenharmony_ci{ 5728c2ecf20Sopenharmony_ci void *hdr; 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci hdr = genlmsg_put(msg, portid, seq, &nfc_genl_family, flags, 5758c2ecf20Sopenharmony_ci NFC_CMD_GET_DEVICE); 5768c2ecf20Sopenharmony_ci if (!hdr) 5778c2ecf20Sopenharmony_ci return -EMSGSIZE; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci if (cb) 5808c2ecf20Sopenharmony_ci genl_dump_check_consistent(cb, hdr); 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci if (nfc_genl_setup_device_added(dev, msg)) 5838c2ecf20Sopenharmony_ci goto nla_put_failure; 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci genlmsg_end(msg, hdr); 5868c2ecf20Sopenharmony_ci return 0; 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_cinla_put_failure: 5898c2ecf20Sopenharmony_ci genlmsg_cancel(msg, hdr); 5908c2ecf20Sopenharmony_ci return -EMSGSIZE; 5918c2ecf20Sopenharmony_ci} 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_cistatic int nfc_genl_dump_devices(struct sk_buff *skb, 5948c2ecf20Sopenharmony_ci struct netlink_callback *cb) 5958c2ecf20Sopenharmony_ci{ 5968c2ecf20Sopenharmony_ci struct class_dev_iter *iter = (struct class_dev_iter *) cb->args[0]; 5978c2ecf20Sopenharmony_ci struct nfc_dev *dev = (struct nfc_dev *) cb->args[1]; 5988c2ecf20Sopenharmony_ci bool first_call = false; 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci if (!iter) { 6018c2ecf20Sopenharmony_ci first_call = true; 6028c2ecf20Sopenharmony_ci iter = kmalloc(sizeof(struct class_dev_iter), GFP_KERNEL); 6038c2ecf20Sopenharmony_ci if (!iter) 6048c2ecf20Sopenharmony_ci return -ENOMEM; 6058c2ecf20Sopenharmony_ci cb->args[0] = (long) iter; 6068c2ecf20Sopenharmony_ci } 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci mutex_lock(&nfc_devlist_mutex); 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci cb->seq = nfc_devlist_generation; 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci if (first_call) { 6138c2ecf20Sopenharmony_ci nfc_device_iter_init(iter); 6148c2ecf20Sopenharmony_ci dev = nfc_device_iter_next(iter); 6158c2ecf20Sopenharmony_ci } 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci while (dev) { 6188c2ecf20Sopenharmony_ci int rc; 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci rc = nfc_genl_send_device(skb, dev, NETLINK_CB(cb->skb).portid, 6218c2ecf20Sopenharmony_ci cb->nlh->nlmsg_seq, cb, NLM_F_MULTI); 6228c2ecf20Sopenharmony_ci if (rc < 0) 6238c2ecf20Sopenharmony_ci break; 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci dev = nfc_device_iter_next(iter); 6268c2ecf20Sopenharmony_ci } 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci mutex_unlock(&nfc_devlist_mutex); 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci cb->args[1] = (long) dev; 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci return skb->len; 6338c2ecf20Sopenharmony_ci} 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_cistatic int nfc_genl_dump_devices_done(struct netlink_callback *cb) 6368c2ecf20Sopenharmony_ci{ 6378c2ecf20Sopenharmony_ci struct class_dev_iter *iter = (struct class_dev_iter *) cb->args[0]; 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci if (iter) { 6408c2ecf20Sopenharmony_ci nfc_device_iter_exit(iter); 6418c2ecf20Sopenharmony_ci kfree(iter); 6428c2ecf20Sopenharmony_ci } 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci return 0; 6458c2ecf20Sopenharmony_ci} 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ciint nfc_genl_dep_link_up_event(struct nfc_dev *dev, u32 target_idx, 6488c2ecf20Sopenharmony_ci u8 comm_mode, u8 rf_mode) 6498c2ecf20Sopenharmony_ci{ 6508c2ecf20Sopenharmony_ci struct sk_buff *msg; 6518c2ecf20Sopenharmony_ci void *hdr; 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci pr_debug("DEP link is up\n"); 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); 6568c2ecf20Sopenharmony_ci if (!msg) 6578c2ecf20Sopenharmony_ci return -ENOMEM; 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0, NFC_CMD_DEP_LINK_UP); 6608c2ecf20Sopenharmony_ci if (!hdr) 6618c2ecf20Sopenharmony_ci goto free_msg; 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx)) 6648c2ecf20Sopenharmony_ci goto nla_put_failure; 6658c2ecf20Sopenharmony_ci if (rf_mode == NFC_RF_INITIATOR && 6668c2ecf20Sopenharmony_ci nla_put_u32(msg, NFC_ATTR_TARGET_INDEX, target_idx)) 6678c2ecf20Sopenharmony_ci goto nla_put_failure; 6688c2ecf20Sopenharmony_ci if (nla_put_u8(msg, NFC_ATTR_COMM_MODE, comm_mode) || 6698c2ecf20Sopenharmony_ci nla_put_u8(msg, NFC_ATTR_RF_MODE, rf_mode)) 6708c2ecf20Sopenharmony_ci goto nla_put_failure; 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci genlmsg_end(msg, hdr); 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci dev->dep_link_up = true; 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_ATOMIC); 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci return 0; 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_cinla_put_failure: 6818c2ecf20Sopenharmony_cifree_msg: 6828c2ecf20Sopenharmony_ci nlmsg_free(msg); 6838c2ecf20Sopenharmony_ci return -EMSGSIZE; 6848c2ecf20Sopenharmony_ci} 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ciint nfc_genl_dep_link_down_event(struct nfc_dev *dev) 6878c2ecf20Sopenharmony_ci{ 6888c2ecf20Sopenharmony_ci struct sk_buff *msg; 6898c2ecf20Sopenharmony_ci void *hdr; 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci pr_debug("DEP link is down\n"); 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); 6948c2ecf20Sopenharmony_ci if (!msg) 6958c2ecf20Sopenharmony_ci return -ENOMEM; 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0, 6988c2ecf20Sopenharmony_ci NFC_CMD_DEP_LINK_DOWN); 6998c2ecf20Sopenharmony_ci if (!hdr) 7008c2ecf20Sopenharmony_ci goto free_msg; 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx)) 7038c2ecf20Sopenharmony_ci goto nla_put_failure; 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci genlmsg_end(msg, hdr); 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_ATOMIC); 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci return 0; 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_cinla_put_failure: 7128c2ecf20Sopenharmony_cifree_msg: 7138c2ecf20Sopenharmony_ci nlmsg_free(msg); 7148c2ecf20Sopenharmony_ci return -EMSGSIZE; 7158c2ecf20Sopenharmony_ci} 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_cistatic int nfc_genl_get_device(struct sk_buff *skb, struct genl_info *info) 7188c2ecf20Sopenharmony_ci{ 7198c2ecf20Sopenharmony_ci struct sk_buff *msg; 7208c2ecf20Sopenharmony_ci struct nfc_dev *dev; 7218c2ecf20Sopenharmony_ci u32 idx; 7228c2ecf20Sopenharmony_ci int rc = -ENOBUFS; 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci if (!info->attrs[NFC_ATTR_DEVICE_INDEX]) 7258c2ecf20Sopenharmony_ci return -EINVAL; 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]); 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci dev = nfc_get_device(idx); 7308c2ecf20Sopenharmony_ci if (!dev) 7318c2ecf20Sopenharmony_ci return -ENODEV; 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 7348c2ecf20Sopenharmony_ci if (!msg) { 7358c2ecf20Sopenharmony_ci rc = -ENOMEM; 7368c2ecf20Sopenharmony_ci goto out_putdev; 7378c2ecf20Sopenharmony_ci } 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci rc = nfc_genl_send_device(msg, dev, info->snd_portid, info->snd_seq, 7408c2ecf20Sopenharmony_ci NULL, 0); 7418c2ecf20Sopenharmony_ci if (rc < 0) 7428c2ecf20Sopenharmony_ci goto out_free; 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci nfc_put_device(dev); 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci return genlmsg_reply(msg, info); 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ciout_free: 7498c2ecf20Sopenharmony_ci nlmsg_free(msg); 7508c2ecf20Sopenharmony_ciout_putdev: 7518c2ecf20Sopenharmony_ci nfc_put_device(dev); 7528c2ecf20Sopenharmony_ci return rc; 7538c2ecf20Sopenharmony_ci} 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_cistatic int nfc_genl_dev_up(struct sk_buff *skb, struct genl_info *info) 7568c2ecf20Sopenharmony_ci{ 7578c2ecf20Sopenharmony_ci struct nfc_dev *dev; 7588c2ecf20Sopenharmony_ci int rc; 7598c2ecf20Sopenharmony_ci u32 idx; 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci if (!info->attrs[NFC_ATTR_DEVICE_INDEX]) 7628c2ecf20Sopenharmony_ci return -EINVAL; 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]); 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci dev = nfc_get_device(idx); 7678c2ecf20Sopenharmony_ci if (!dev) 7688c2ecf20Sopenharmony_ci return -ENODEV; 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci rc = nfc_dev_up(dev); 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_ci nfc_put_device(dev); 7738c2ecf20Sopenharmony_ci return rc; 7748c2ecf20Sopenharmony_ci} 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_cistatic int nfc_genl_dev_down(struct sk_buff *skb, struct genl_info *info) 7778c2ecf20Sopenharmony_ci{ 7788c2ecf20Sopenharmony_ci struct nfc_dev *dev; 7798c2ecf20Sopenharmony_ci int rc; 7808c2ecf20Sopenharmony_ci u32 idx; 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci if (!info->attrs[NFC_ATTR_DEVICE_INDEX]) 7838c2ecf20Sopenharmony_ci return -EINVAL; 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]); 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci dev = nfc_get_device(idx); 7888c2ecf20Sopenharmony_ci if (!dev) 7898c2ecf20Sopenharmony_ci return -ENODEV; 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci rc = nfc_dev_down(dev); 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci nfc_put_device(dev); 7948c2ecf20Sopenharmony_ci return rc; 7958c2ecf20Sopenharmony_ci} 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_cistatic int nfc_genl_start_poll(struct sk_buff *skb, struct genl_info *info) 7988c2ecf20Sopenharmony_ci{ 7998c2ecf20Sopenharmony_ci struct nfc_dev *dev; 8008c2ecf20Sopenharmony_ci int rc; 8018c2ecf20Sopenharmony_ci u32 idx; 8028c2ecf20Sopenharmony_ci u32 im_protocols = 0, tm_protocols = 0; 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci pr_debug("Poll start\n"); 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci if (!info->attrs[NFC_ATTR_DEVICE_INDEX] || 8078c2ecf20Sopenharmony_ci ((!info->attrs[NFC_ATTR_IM_PROTOCOLS] && 8088c2ecf20Sopenharmony_ci !info->attrs[NFC_ATTR_PROTOCOLS]) && 8098c2ecf20Sopenharmony_ci !info->attrs[NFC_ATTR_TM_PROTOCOLS])) 8108c2ecf20Sopenharmony_ci return -EINVAL; 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]); 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci if (info->attrs[NFC_ATTR_TM_PROTOCOLS]) 8158c2ecf20Sopenharmony_ci tm_protocols = nla_get_u32(info->attrs[NFC_ATTR_TM_PROTOCOLS]); 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci if (info->attrs[NFC_ATTR_IM_PROTOCOLS]) 8188c2ecf20Sopenharmony_ci im_protocols = nla_get_u32(info->attrs[NFC_ATTR_IM_PROTOCOLS]); 8198c2ecf20Sopenharmony_ci else if (info->attrs[NFC_ATTR_PROTOCOLS]) 8208c2ecf20Sopenharmony_ci im_protocols = nla_get_u32(info->attrs[NFC_ATTR_PROTOCOLS]); 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci dev = nfc_get_device(idx); 8238c2ecf20Sopenharmony_ci if (!dev) 8248c2ecf20Sopenharmony_ci return -ENODEV; 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci mutex_lock(&dev->genl_data.genl_data_mutex); 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci rc = nfc_start_poll(dev, im_protocols, tm_protocols); 8298c2ecf20Sopenharmony_ci if (!rc) 8308c2ecf20Sopenharmony_ci dev->genl_data.poll_req_portid = info->snd_portid; 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci mutex_unlock(&dev->genl_data.genl_data_mutex); 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci nfc_put_device(dev); 8358c2ecf20Sopenharmony_ci return rc; 8368c2ecf20Sopenharmony_ci} 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_cistatic int nfc_genl_stop_poll(struct sk_buff *skb, struct genl_info *info) 8398c2ecf20Sopenharmony_ci{ 8408c2ecf20Sopenharmony_ci struct nfc_dev *dev; 8418c2ecf20Sopenharmony_ci int rc; 8428c2ecf20Sopenharmony_ci u32 idx; 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci if (!info->attrs[NFC_ATTR_DEVICE_INDEX]) 8458c2ecf20Sopenharmony_ci return -EINVAL; 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]); 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci dev = nfc_get_device(idx); 8508c2ecf20Sopenharmony_ci if (!dev) 8518c2ecf20Sopenharmony_ci return -ENODEV; 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci device_lock(&dev->dev); 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_ci if (!dev->polling) { 8568c2ecf20Sopenharmony_ci device_unlock(&dev->dev); 8578c2ecf20Sopenharmony_ci nfc_put_device(dev); 8588c2ecf20Sopenharmony_ci return -EINVAL; 8598c2ecf20Sopenharmony_ci } 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_ci device_unlock(&dev->dev); 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ci mutex_lock(&dev->genl_data.genl_data_mutex); 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_ci if (dev->genl_data.poll_req_portid != info->snd_portid) { 8668c2ecf20Sopenharmony_ci rc = -EBUSY; 8678c2ecf20Sopenharmony_ci goto out; 8688c2ecf20Sopenharmony_ci } 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci rc = nfc_stop_poll(dev); 8718c2ecf20Sopenharmony_ci dev->genl_data.poll_req_portid = 0; 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ciout: 8748c2ecf20Sopenharmony_ci mutex_unlock(&dev->genl_data.genl_data_mutex); 8758c2ecf20Sopenharmony_ci nfc_put_device(dev); 8768c2ecf20Sopenharmony_ci return rc; 8778c2ecf20Sopenharmony_ci} 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_cistatic int nfc_genl_activate_target(struct sk_buff *skb, struct genl_info *info) 8808c2ecf20Sopenharmony_ci{ 8818c2ecf20Sopenharmony_ci struct nfc_dev *dev; 8828c2ecf20Sopenharmony_ci u32 device_idx, target_idx, protocol; 8838c2ecf20Sopenharmony_ci int rc; 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_ci if (!info->attrs[NFC_ATTR_DEVICE_INDEX] || 8868c2ecf20Sopenharmony_ci !info->attrs[NFC_ATTR_TARGET_INDEX] || 8878c2ecf20Sopenharmony_ci !info->attrs[NFC_ATTR_PROTOCOLS]) 8888c2ecf20Sopenharmony_ci return -EINVAL; 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_ci device_idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]); 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci dev = nfc_get_device(device_idx); 8938c2ecf20Sopenharmony_ci if (!dev) 8948c2ecf20Sopenharmony_ci return -ENODEV; 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci target_idx = nla_get_u32(info->attrs[NFC_ATTR_TARGET_INDEX]); 8978c2ecf20Sopenharmony_ci protocol = nla_get_u32(info->attrs[NFC_ATTR_PROTOCOLS]); 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_ci nfc_deactivate_target(dev, target_idx, NFC_TARGET_MODE_SLEEP); 9008c2ecf20Sopenharmony_ci rc = nfc_activate_target(dev, target_idx, protocol); 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci nfc_put_device(dev); 9038c2ecf20Sopenharmony_ci return rc; 9048c2ecf20Sopenharmony_ci} 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_cistatic int nfc_genl_deactivate_target(struct sk_buff *skb, 9078c2ecf20Sopenharmony_ci struct genl_info *info) 9088c2ecf20Sopenharmony_ci{ 9098c2ecf20Sopenharmony_ci struct nfc_dev *dev; 9108c2ecf20Sopenharmony_ci u32 device_idx, target_idx; 9118c2ecf20Sopenharmony_ci int rc; 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci if (!info->attrs[NFC_ATTR_DEVICE_INDEX] || 9148c2ecf20Sopenharmony_ci !info->attrs[NFC_ATTR_TARGET_INDEX]) 9158c2ecf20Sopenharmony_ci return -EINVAL; 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci device_idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]); 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci dev = nfc_get_device(device_idx); 9208c2ecf20Sopenharmony_ci if (!dev) 9218c2ecf20Sopenharmony_ci return -ENODEV; 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ci target_idx = nla_get_u32(info->attrs[NFC_ATTR_TARGET_INDEX]); 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci rc = nfc_deactivate_target(dev, target_idx, NFC_TARGET_MODE_SLEEP); 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_ci nfc_put_device(dev); 9288c2ecf20Sopenharmony_ci return rc; 9298c2ecf20Sopenharmony_ci} 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_cistatic int nfc_genl_dep_link_up(struct sk_buff *skb, struct genl_info *info) 9328c2ecf20Sopenharmony_ci{ 9338c2ecf20Sopenharmony_ci struct nfc_dev *dev; 9348c2ecf20Sopenharmony_ci int rc, tgt_idx; 9358c2ecf20Sopenharmony_ci u32 idx; 9368c2ecf20Sopenharmony_ci u8 comm; 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_ci pr_debug("DEP link up\n"); 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci if (!info->attrs[NFC_ATTR_DEVICE_INDEX] || 9418c2ecf20Sopenharmony_ci !info->attrs[NFC_ATTR_COMM_MODE]) 9428c2ecf20Sopenharmony_ci return -EINVAL; 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]); 9458c2ecf20Sopenharmony_ci if (!info->attrs[NFC_ATTR_TARGET_INDEX]) 9468c2ecf20Sopenharmony_ci tgt_idx = NFC_TARGET_IDX_ANY; 9478c2ecf20Sopenharmony_ci else 9488c2ecf20Sopenharmony_ci tgt_idx = nla_get_u32(info->attrs[NFC_ATTR_TARGET_INDEX]); 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_ci comm = nla_get_u8(info->attrs[NFC_ATTR_COMM_MODE]); 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci if (comm != NFC_COMM_ACTIVE && comm != NFC_COMM_PASSIVE) 9538c2ecf20Sopenharmony_ci return -EINVAL; 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_ci dev = nfc_get_device(idx); 9568c2ecf20Sopenharmony_ci if (!dev) 9578c2ecf20Sopenharmony_ci return -ENODEV; 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_ci rc = nfc_dep_link_up(dev, tgt_idx, comm); 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci nfc_put_device(dev); 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_ci return rc; 9648c2ecf20Sopenharmony_ci} 9658c2ecf20Sopenharmony_ci 9668c2ecf20Sopenharmony_cistatic int nfc_genl_dep_link_down(struct sk_buff *skb, struct genl_info *info) 9678c2ecf20Sopenharmony_ci{ 9688c2ecf20Sopenharmony_ci struct nfc_dev *dev; 9698c2ecf20Sopenharmony_ci int rc; 9708c2ecf20Sopenharmony_ci u32 idx; 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci if (!info->attrs[NFC_ATTR_DEVICE_INDEX] || 9738c2ecf20Sopenharmony_ci !info->attrs[NFC_ATTR_TARGET_INDEX]) 9748c2ecf20Sopenharmony_ci return -EINVAL; 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_ci idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]); 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_ci dev = nfc_get_device(idx); 9798c2ecf20Sopenharmony_ci if (!dev) 9808c2ecf20Sopenharmony_ci return -ENODEV; 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci rc = nfc_dep_link_down(dev); 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_ci nfc_put_device(dev); 9858c2ecf20Sopenharmony_ci return rc; 9868c2ecf20Sopenharmony_ci} 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_cistatic int nfc_genl_send_params(struct sk_buff *msg, 9898c2ecf20Sopenharmony_ci struct nfc_llcp_local *local, 9908c2ecf20Sopenharmony_ci u32 portid, u32 seq) 9918c2ecf20Sopenharmony_ci{ 9928c2ecf20Sopenharmony_ci void *hdr; 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_ci hdr = genlmsg_put(msg, portid, seq, &nfc_genl_family, 0, 9958c2ecf20Sopenharmony_ci NFC_CMD_LLC_GET_PARAMS); 9968c2ecf20Sopenharmony_ci if (!hdr) 9978c2ecf20Sopenharmony_ci return -EMSGSIZE; 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, local->dev->idx) || 10008c2ecf20Sopenharmony_ci nla_put_u8(msg, NFC_ATTR_LLC_PARAM_LTO, local->lto) || 10018c2ecf20Sopenharmony_ci nla_put_u8(msg, NFC_ATTR_LLC_PARAM_RW, local->rw) || 10028c2ecf20Sopenharmony_ci nla_put_u16(msg, NFC_ATTR_LLC_PARAM_MIUX, be16_to_cpu(local->miux))) 10038c2ecf20Sopenharmony_ci goto nla_put_failure; 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_ci genlmsg_end(msg, hdr); 10068c2ecf20Sopenharmony_ci return 0; 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_cinla_put_failure: 10098c2ecf20Sopenharmony_ci genlmsg_cancel(msg, hdr); 10108c2ecf20Sopenharmony_ci return -EMSGSIZE; 10118c2ecf20Sopenharmony_ci} 10128c2ecf20Sopenharmony_ci 10138c2ecf20Sopenharmony_cistatic int nfc_genl_llc_get_params(struct sk_buff *skb, struct genl_info *info) 10148c2ecf20Sopenharmony_ci{ 10158c2ecf20Sopenharmony_ci struct nfc_dev *dev; 10168c2ecf20Sopenharmony_ci struct nfc_llcp_local *local; 10178c2ecf20Sopenharmony_ci int rc = 0; 10188c2ecf20Sopenharmony_ci struct sk_buff *msg = NULL; 10198c2ecf20Sopenharmony_ci u32 idx; 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_ci if (!info->attrs[NFC_ATTR_DEVICE_INDEX] || 10228c2ecf20Sopenharmony_ci !info->attrs[NFC_ATTR_FIRMWARE_NAME]) 10238c2ecf20Sopenharmony_ci return -EINVAL; 10248c2ecf20Sopenharmony_ci 10258c2ecf20Sopenharmony_ci idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]); 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci dev = nfc_get_device(idx); 10288c2ecf20Sopenharmony_ci if (!dev) 10298c2ecf20Sopenharmony_ci return -ENODEV; 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_ci device_lock(&dev->dev); 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci local = nfc_llcp_find_local(dev); 10348c2ecf20Sopenharmony_ci if (!local) { 10358c2ecf20Sopenharmony_ci rc = -ENODEV; 10368c2ecf20Sopenharmony_ci goto exit; 10378c2ecf20Sopenharmony_ci } 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_ci msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 10408c2ecf20Sopenharmony_ci if (!msg) { 10418c2ecf20Sopenharmony_ci rc = -ENOMEM; 10428c2ecf20Sopenharmony_ci goto put_local; 10438c2ecf20Sopenharmony_ci } 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_ci rc = nfc_genl_send_params(msg, local, info->snd_portid, info->snd_seq); 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_ciput_local: 10488c2ecf20Sopenharmony_ci nfc_llcp_local_put(local); 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_ciexit: 10518c2ecf20Sopenharmony_ci device_unlock(&dev->dev); 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_ci nfc_put_device(dev); 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_ci if (rc < 0) { 10568c2ecf20Sopenharmony_ci if (msg) 10578c2ecf20Sopenharmony_ci nlmsg_free(msg); 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_ci return rc; 10608c2ecf20Sopenharmony_ci } 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_ci return genlmsg_reply(msg, info); 10638c2ecf20Sopenharmony_ci} 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_cistatic int nfc_genl_llc_set_params(struct sk_buff *skb, struct genl_info *info) 10668c2ecf20Sopenharmony_ci{ 10678c2ecf20Sopenharmony_ci struct nfc_dev *dev; 10688c2ecf20Sopenharmony_ci struct nfc_llcp_local *local; 10698c2ecf20Sopenharmony_ci u8 rw = 0; 10708c2ecf20Sopenharmony_ci u16 miux = 0; 10718c2ecf20Sopenharmony_ci u32 idx; 10728c2ecf20Sopenharmony_ci int rc = 0; 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_ci if (!info->attrs[NFC_ATTR_DEVICE_INDEX] || 10758c2ecf20Sopenharmony_ci (!info->attrs[NFC_ATTR_LLC_PARAM_LTO] && 10768c2ecf20Sopenharmony_ci !info->attrs[NFC_ATTR_LLC_PARAM_RW] && 10778c2ecf20Sopenharmony_ci !info->attrs[NFC_ATTR_LLC_PARAM_MIUX])) 10788c2ecf20Sopenharmony_ci return -EINVAL; 10798c2ecf20Sopenharmony_ci 10808c2ecf20Sopenharmony_ci if (info->attrs[NFC_ATTR_LLC_PARAM_RW]) { 10818c2ecf20Sopenharmony_ci rw = nla_get_u8(info->attrs[NFC_ATTR_LLC_PARAM_RW]); 10828c2ecf20Sopenharmony_ci 10838c2ecf20Sopenharmony_ci if (rw > LLCP_MAX_RW) 10848c2ecf20Sopenharmony_ci return -EINVAL; 10858c2ecf20Sopenharmony_ci } 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_ci if (info->attrs[NFC_ATTR_LLC_PARAM_MIUX]) { 10888c2ecf20Sopenharmony_ci miux = nla_get_u16(info->attrs[NFC_ATTR_LLC_PARAM_MIUX]); 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_ci if (miux > LLCP_MAX_MIUX) 10918c2ecf20Sopenharmony_ci return -EINVAL; 10928c2ecf20Sopenharmony_ci } 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_ci idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]); 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_ci dev = nfc_get_device(idx); 10978c2ecf20Sopenharmony_ci if (!dev) 10988c2ecf20Sopenharmony_ci return -ENODEV; 10998c2ecf20Sopenharmony_ci 11008c2ecf20Sopenharmony_ci device_lock(&dev->dev); 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_ci local = nfc_llcp_find_local(dev); 11038c2ecf20Sopenharmony_ci if (!local) { 11048c2ecf20Sopenharmony_ci rc = -ENODEV; 11058c2ecf20Sopenharmony_ci goto exit; 11068c2ecf20Sopenharmony_ci } 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_ci if (info->attrs[NFC_ATTR_LLC_PARAM_LTO]) { 11098c2ecf20Sopenharmony_ci if (dev->dep_link_up) { 11108c2ecf20Sopenharmony_ci rc = -EINPROGRESS; 11118c2ecf20Sopenharmony_ci goto put_local; 11128c2ecf20Sopenharmony_ci } 11138c2ecf20Sopenharmony_ci 11148c2ecf20Sopenharmony_ci local->lto = nla_get_u8(info->attrs[NFC_ATTR_LLC_PARAM_LTO]); 11158c2ecf20Sopenharmony_ci } 11168c2ecf20Sopenharmony_ci 11178c2ecf20Sopenharmony_ci if (info->attrs[NFC_ATTR_LLC_PARAM_RW]) 11188c2ecf20Sopenharmony_ci local->rw = rw; 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_ci if (info->attrs[NFC_ATTR_LLC_PARAM_MIUX]) 11218c2ecf20Sopenharmony_ci local->miux = cpu_to_be16(miux); 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_ciput_local: 11248c2ecf20Sopenharmony_ci nfc_llcp_local_put(local); 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_ciexit: 11278c2ecf20Sopenharmony_ci device_unlock(&dev->dev); 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_ci nfc_put_device(dev); 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ci return rc; 11328c2ecf20Sopenharmony_ci} 11338c2ecf20Sopenharmony_ci 11348c2ecf20Sopenharmony_cistatic int nfc_genl_llc_sdreq(struct sk_buff *skb, struct genl_info *info) 11358c2ecf20Sopenharmony_ci{ 11368c2ecf20Sopenharmony_ci struct nfc_dev *dev; 11378c2ecf20Sopenharmony_ci struct nfc_llcp_local *local; 11388c2ecf20Sopenharmony_ci struct nlattr *attr, *sdp_attrs[NFC_SDP_ATTR_MAX+1]; 11398c2ecf20Sopenharmony_ci u32 idx; 11408c2ecf20Sopenharmony_ci u8 tid; 11418c2ecf20Sopenharmony_ci char *uri; 11428c2ecf20Sopenharmony_ci int rc = 0, rem; 11438c2ecf20Sopenharmony_ci size_t uri_len, tlvs_len; 11448c2ecf20Sopenharmony_ci struct hlist_head sdreq_list; 11458c2ecf20Sopenharmony_ci struct nfc_llcp_sdp_tlv *sdreq; 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_ci if (!info->attrs[NFC_ATTR_DEVICE_INDEX] || 11488c2ecf20Sopenharmony_ci !info->attrs[NFC_ATTR_LLC_SDP]) 11498c2ecf20Sopenharmony_ci return -EINVAL; 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_ci idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]); 11528c2ecf20Sopenharmony_ci 11538c2ecf20Sopenharmony_ci dev = nfc_get_device(idx); 11548c2ecf20Sopenharmony_ci if (!dev) 11558c2ecf20Sopenharmony_ci return -ENODEV; 11568c2ecf20Sopenharmony_ci 11578c2ecf20Sopenharmony_ci device_lock(&dev->dev); 11588c2ecf20Sopenharmony_ci 11598c2ecf20Sopenharmony_ci if (dev->dep_link_up == false) { 11608c2ecf20Sopenharmony_ci rc = -ENOLINK; 11618c2ecf20Sopenharmony_ci goto exit; 11628c2ecf20Sopenharmony_ci } 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_ci local = nfc_llcp_find_local(dev); 11658c2ecf20Sopenharmony_ci if (!local) { 11668c2ecf20Sopenharmony_ci rc = -ENODEV; 11678c2ecf20Sopenharmony_ci goto exit; 11688c2ecf20Sopenharmony_ci } 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_ci INIT_HLIST_HEAD(&sdreq_list); 11718c2ecf20Sopenharmony_ci 11728c2ecf20Sopenharmony_ci tlvs_len = 0; 11738c2ecf20Sopenharmony_ci 11748c2ecf20Sopenharmony_ci nla_for_each_nested(attr, info->attrs[NFC_ATTR_LLC_SDP], rem) { 11758c2ecf20Sopenharmony_ci rc = nla_parse_nested_deprecated(sdp_attrs, NFC_SDP_ATTR_MAX, 11768c2ecf20Sopenharmony_ci attr, nfc_sdp_genl_policy, 11778c2ecf20Sopenharmony_ci info->extack); 11788c2ecf20Sopenharmony_ci 11798c2ecf20Sopenharmony_ci if (rc != 0) { 11808c2ecf20Sopenharmony_ci rc = -EINVAL; 11818c2ecf20Sopenharmony_ci goto put_local; 11828c2ecf20Sopenharmony_ci } 11838c2ecf20Sopenharmony_ci 11848c2ecf20Sopenharmony_ci if (!sdp_attrs[NFC_SDP_ATTR_URI]) 11858c2ecf20Sopenharmony_ci continue; 11868c2ecf20Sopenharmony_ci 11878c2ecf20Sopenharmony_ci uri_len = nla_len(sdp_attrs[NFC_SDP_ATTR_URI]); 11888c2ecf20Sopenharmony_ci if (uri_len == 0) 11898c2ecf20Sopenharmony_ci continue; 11908c2ecf20Sopenharmony_ci 11918c2ecf20Sopenharmony_ci uri = nla_data(sdp_attrs[NFC_SDP_ATTR_URI]); 11928c2ecf20Sopenharmony_ci if (uri == NULL || *uri == 0) 11938c2ecf20Sopenharmony_ci continue; 11948c2ecf20Sopenharmony_ci 11958c2ecf20Sopenharmony_ci tid = local->sdreq_next_tid++; 11968c2ecf20Sopenharmony_ci 11978c2ecf20Sopenharmony_ci sdreq = nfc_llcp_build_sdreq_tlv(tid, uri, uri_len); 11988c2ecf20Sopenharmony_ci if (sdreq == NULL) { 11998c2ecf20Sopenharmony_ci rc = -ENOMEM; 12008c2ecf20Sopenharmony_ci goto put_local; 12018c2ecf20Sopenharmony_ci } 12028c2ecf20Sopenharmony_ci 12038c2ecf20Sopenharmony_ci tlvs_len += sdreq->tlv_len; 12048c2ecf20Sopenharmony_ci 12058c2ecf20Sopenharmony_ci hlist_add_head(&sdreq->node, &sdreq_list); 12068c2ecf20Sopenharmony_ci } 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_ci if (hlist_empty(&sdreq_list)) { 12098c2ecf20Sopenharmony_ci rc = -EINVAL; 12108c2ecf20Sopenharmony_ci goto put_local; 12118c2ecf20Sopenharmony_ci } 12128c2ecf20Sopenharmony_ci 12138c2ecf20Sopenharmony_ci rc = nfc_llcp_send_snl_sdreq(local, &sdreq_list, tlvs_len); 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_ciput_local: 12168c2ecf20Sopenharmony_ci nfc_llcp_local_put(local); 12178c2ecf20Sopenharmony_ci 12188c2ecf20Sopenharmony_ciexit: 12198c2ecf20Sopenharmony_ci device_unlock(&dev->dev); 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_ci nfc_put_device(dev); 12228c2ecf20Sopenharmony_ci 12238c2ecf20Sopenharmony_ci return rc; 12248c2ecf20Sopenharmony_ci} 12258c2ecf20Sopenharmony_ci 12268c2ecf20Sopenharmony_cistatic int nfc_genl_fw_download(struct sk_buff *skb, struct genl_info *info) 12278c2ecf20Sopenharmony_ci{ 12288c2ecf20Sopenharmony_ci struct nfc_dev *dev; 12298c2ecf20Sopenharmony_ci int rc; 12308c2ecf20Sopenharmony_ci u32 idx; 12318c2ecf20Sopenharmony_ci char firmware_name[NFC_FIRMWARE_NAME_MAXSIZE + 1]; 12328c2ecf20Sopenharmony_ci 12338c2ecf20Sopenharmony_ci if (!info->attrs[NFC_ATTR_DEVICE_INDEX] || !info->attrs[NFC_ATTR_FIRMWARE_NAME]) 12348c2ecf20Sopenharmony_ci return -EINVAL; 12358c2ecf20Sopenharmony_ci 12368c2ecf20Sopenharmony_ci idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]); 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_ci dev = nfc_get_device(idx); 12398c2ecf20Sopenharmony_ci if (!dev) 12408c2ecf20Sopenharmony_ci return -ENODEV; 12418c2ecf20Sopenharmony_ci 12428c2ecf20Sopenharmony_ci nla_strlcpy(firmware_name, info->attrs[NFC_ATTR_FIRMWARE_NAME], 12438c2ecf20Sopenharmony_ci sizeof(firmware_name)); 12448c2ecf20Sopenharmony_ci 12458c2ecf20Sopenharmony_ci rc = nfc_fw_download(dev, firmware_name); 12468c2ecf20Sopenharmony_ci 12478c2ecf20Sopenharmony_ci nfc_put_device(dev); 12488c2ecf20Sopenharmony_ci return rc; 12498c2ecf20Sopenharmony_ci} 12508c2ecf20Sopenharmony_ci 12518c2ecf20Sopenharmony_ciint nfc_genl_fw_download_done(struct nfc_dev *dev, const char *firmware_name, 12528c2ecf20Sopenharmony_ci u32 result) 12538c2ecf20Sopenharmony_ci{ 12548c2ecf20Sopenharmony_ci struct sk_buff *msg; 12558c2ecf20Sopenharmony_ci void *hdr; 12568c2ecf20Sopenharmony_ci 12578c2ecf20Sopenharmony_ci msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); 12588c2ecf20Sopenharmony_ci if (!msg) 12598c2ecf20Sopenharmony_ci return -ENOMEM; 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_ci hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0, 12628c2ecf20Sopenharmony_ci NFC_CMD_FW_DOWNLOAD); 12638c2ecf20Sopenharmony_ci if (!hdr) 12648c2ecf20Sopenharmony_ci goto free_msg; 12658c2ecf20Sopenharmony_ci 12668c2ecf20Sopenharmony_ci if (nla_put_string(msg, NFC_ATTR_FIRMWARE_NAME, firmware_name) || 12678c2ecf20Sopenharmony_ci nla_put_u32(msg, NFC_ATTR_FIRMWARE_DOWNLOAD_STATUS, result) || 12688c2ecf20Sopenharmony_ci nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx)) 12698c2ecf20Sopenharmony_ci goto nla_put_failure; 12708c2ecf20Sopenharmony_ci 12718c2ecf20Sopenharmony_ci genlmsg_end(msg, hdr); 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_ci genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_ATOMIC); 12748c2ecf20Sopenharmony_ci 12758c2ecf20Sopenharmony_ci return 0; 12768c2ecf20Sopenharmony_ci 12778c2ecf20Sopenharmony_cinla_put_failure: 12788c2ecf20Sopenharmony_cifree_msg: 12798c2ecf20Sopenharmony_ci nlmsg_free(msg); 12808c2ecf20Sopenharmony_ci return -EMSGSIZE; 12818c2ecf20Sopenharmony_ci} 12828c2ecf20Sopenharmony_ci 12838c2ecf20Sopenharmony_cistatic int nfc_genl_enable_se(struct sk_buff *skb, struct genl_info *info) 12848c2ecf20Sopenharmony_ci{ 12858c2ecf20Sopenharmony_ci struct nfc_dev *dev; 12868c2ecf20Sopenharmony_ci int rc; 12878c2ecf20Sopenharmony_ci u32 idx, se_idx; 12888c2ecf20Sopenharmony_ci 12898c2ecf20Sopenharmony_ci if (!info->attrs[NFC_ATTR_DEVICE_INDEX] || 12908c2ecf20Sopenharmony_ci !info->attrs[NFC_ATTR_SE_INDEX]) 12918c2ecf20Sopenharmony_ci return -EINVAL; 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_ci idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]); 12948c2ecf20Sopenharmony_ci se_idx = nla_get_u32(info->attrs[NFC_ATTR_SE_INDEX]); 12958c2ecf20Sopenharmony_ci 12968c2ecf20Sopenharmony_ci dev = nfc_get_device(idx); 12978c2ecf20Sopenharmony_ci if (!dev) 12988c2ecf20Sopenharmony_ci return -ENODEV; 12998c2ecf20Sopenharmony_ci 13008c2ecf20Sopenharmony_ci rc = nfc_enable_se(dev, se_idx); 13018c2ecf20Sopenharmony_ci 13028c2ecf20Sopenharmony_ci nfc_put_device(dev); 13038c2ecf20Sopenharmony_ci return rc; 13048c2ecf20Sopenharmony_ci} 13058c2ecf20Sopenharmony_ci 13068c2ecf20Sopenharmony_cistatic int nfc_genl_disable_se(struct sk_buff *skb, struct genl_info *info) 13078c2ecf20Sopenharmony_ci{ 13088c2ecf20Sopenharmony_ci struct nfc_dev *dev; 13098c2ecf20Sopenharmony_ci int rc; 13108c2ecf20Sopenharmony_ci u32 idx, se_idx; 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_ci if (!info->attrs[NFC_ATTR_DEVICE_INDEX] || 13138c2ecf20Sopenharmony_ci !info->attrs[NFC_ATTR_SE_INDEX]) 13148c2ecf20Sopenharmony_ci return -EINVAL; 13158c2ecf20Sopenharmony_ci 13168c2ecf20Sopenharmony_ci idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]); 13178c2ecf20Sopenharmony_ci se_idx = nla_get_u32(info->attrs[NFC_ATTR_SE_INDEX]); 13188c2ecf20Sopenharmony_ci 13198c2ecf20Sopenharmony_ci dev = nfc_get_device(idx); 13208c2ecf20Sopenharmony_ci if (!dev) 13218c2ecf20Sopenharmony_ci return -ENODEV; 13228c2ecf20Sopenharmony_ci 13238c2ecf20Sopenharmony_ci rc = nfc_disable_se(dev, se_idx); 13248c2ecf20Sopenharmony_ci 13258c2ecf20Sopenharmony_ci nfc_put_device(dev); 13268c2ecf20Sopenharmony_ci return rc; 13278c2ecf20Sopenharmony_ci} 13288c2ecf20Sopenharmony_ci 13298c2ecf20Sopenharmony_cistatic int nfc_genl_send_se(struct sk_buff *msg, struct nfc_dev *dev, 13308c2ecf20Sopenharmony_ci u32 portid, u32 seq, 13318c2ecf20Sopenharmony_ci struct netlink_callback *cb, 13328c2ecf20Sopenharmony_ci int flags) 13338c2ecf20Sopenharmony_ci{ 13348c2ecf20Sopenharmony_ci void *hdr; 13358c2ecf20Sopenharmony_ci struct nfc_se *se, *n; 13368c2ecf20Sopenharmony_ci 13378c2ecf20Sopenharmony_ci list_for_each_entry_safe(se, n, &dev->secure_elements, list) { 13388c2ecf20Sopenharmony_ci hdr = genlmsg_put(msg, portid, seq, &nfc_genl_family, flags, 13398c2ecf20Sopenharmony_ci NFC_CMD_GET_SE); 13408c2ecf20Sopenharmony_ci if (!hdr) 13418c2ecf20Sopenharmony_ci goto nla_put_failure; 13428c2ecf20Sopenharmony_ci 13438c2ecf20Sopenharmony_ci if (cb) 13448c2ecf20Sopenharmony_ci genl_dump_check_consistent(cb, hdr); 13458c2ecf20Sopenharmony_ci 13468c2ecf20Sopenharmony_ci if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx) || 13478c2ecf20Sopenharmony_ci nla_put_u32(msg, NFC_ATTR_SE_INDEX, se->idx) || 13488c2ecf20Sopenharmony_ci nla_put_u8(msg, NFC_ATTR_SE_TYPE, se->type)) 13498c2ecf20Sopenharmony_ci goto nla_put_failure; 13508c2ecf20Sopenharmony_ci 13518c2ecf20Sopenharmony_ci genlmsg_end(msg, hdr); 13528c2ecf20Sopenharmony_ci } 13538c2ecf20Sopenharmony_ci 13548c2ecf20Sopenharmony_ci return 0; 13558c2ecf20Sopenharmony_ci 13568c2ecf20Sopenharmony_cinla_put_failure: 13578c2ecf20Sopenharmony_ci genlmsg_cancel(msg, hdr); 13588c2ecf20Sopenharmony_ci return -EMSGSIZE; 13598c2ecf20Sopenharmony_ci} 13608c2ecf20Sopenharmony_ci 13618c2ecf20Sopenharmony_cistatic int nfc_genl_dump_ses(struct sk_buff *skb, 13628c2ecf20Sopenharmony_ci struct netlink_callback *cb) 13638c2ecf20Sopenharmony_ci{ 13648c2ecf20Sopenharmony_ci struct class_dev_iter *iter = (struct class_dev_iter *) cb->args[0]; 13658c2ecf20Sopenharmony_ci struct nfc_dev *dev = (struct nfc_dev *) cb->args[1]; 13668c2ecf20Sopenharmony_ci bool first_call = false; 13678c2ecf20Sopenharmony_ci 13688c2ecf20Sopenharmony_ci if (!iter) { 13698c2ecf20Sopenharmony_ci first_call = true; 13708c2ecf20Sopenharmony_ci iter = kmalloc(sizeof(struct class_dev_iter), GFP_KERNEL); 13718c2ecf20Sopenharmony_ci if (!iter) 13728c2ecf20Sopenharmony_ci return -ENOMEM; 13738c2ecf20Sopenharmony_ci cb->args[0] = (long) iter; 13748c2ecf20Sopenharmony_ci } 13758c2ecf20Sopenharmony_ci 13768c2ecf20Sopenharmony_ci mutex_lock(&nfc_devlist_mutex); 13778c2ecf20Sopenharmony_ci 13788c2ecf20Sopenharmony_ci cb->seq = nfc_devlist_generation; 13798c2ecf20Sopenharmony_ci 13808c2ecf20Sopenharmony_ci if (first_call) { 13818c2ecf20Sopenharmony_ci nfc_device_iter_init(iter); 13828c2ecf20Sopenharmony_ci dev = nfc_device_iter_next(iter); 13838c2ecf20Sopenharmony_ci } 13848c2ecf20Sopenharmony_ci 13858c2ecf20Sopenharmony_ci while (dev) { 13868c2ecf20Sopenharmony_ci int rc; 13878c2ecf20Sopenharmony_ci 13888c2ecf20Sopenharmony_ci rc = nfc_genl_send_se(skb, dev, NETLINK_CB(cb->skb).portid, 13898c2ecf20Sopenharmony_ci cb->nlh->nlmsg_seq, cb, NLM_F_MULTI); 13908c2ecf20Sopenharmony_ci if (rc < 0) 13918c2ecf20Sopenharmony_ci break; 13928c2ecf20Sopenharmony_ci 13938c2ecf20Sopenharmony_ci dev = nfc_device_iter_next(iter); 13948c2ecf20Sopenharmony_ci } 13958c2ecf20Sopenharmony_ci 13968c2ecf20Sopenharmony_ci mutex_unlock(&nfc_devlist_mutex); 13978c2ecf20Sopenharmony_ci 13988c2ecf20Sopenharmony_ci cb->args[1] = (long) dev; 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_ci return skb->len; 14018c2ecf20Sopenharmony_ci} 14028c2ecf20Sopenharmony_ci 14038c2ecf20Sopenharmony_cistatic int nfc_genl_dump_ses_done(struct netlink_callback *cb) 14048c2ecf20Sopenharmony_ci{ 14058c2ecf20Sopenharmony_ci struct class_dev_iter *iter = (struct class_dev_iter *) cb->args[0]; 14068c2ecf20Sopenharmony_ci 14078c2ecf20Sopenharmony_ci if (iter) { 14088c2ecf20Sopenharmony_ci nfc_device_iter_exit(iter); 14098c2ecf20Sopenharmony_ci kfree(iter); 14108c2ecf20Sopenharmony_ci } 14118c2ecf20Sopenharmony_ci 14128c2ecf20Sopenharmony_ci return 0; 14138c2ecf20Sopenharmony_ci} 14148c2ecf20Sopenharmony_ci 14158c2ecf20Sopenharmony_cistatic int nfc_se_io(struct nfc_dev *dev, u32 se_idx, 14168c2ecf20Sopenharmony_ci u8 *apdu, size_t apdu_length, 14178c2ecf20Sopenharmony_ci se_io_cb_t cb, void *cb_context) 14188c2ecf20Sopenharmony_ci{ 14198c2ecf20Sopenharmony_ci struct nfc_se *se; 14208c2ecf20Sopenharmony_ci int rc; 14218c2ecf20Sopenharmony_ci 14228c2ecf20Sopenharmony_ci pr_debug("%s se index %d\n", dev_name(&dev->dev), se_idx); 14238c2ecf20Sopenharmony_ci 14248c2ecf20Sopenharmony_ci device_lock(&dev->dev); 14258c2ecf20Sopenharmony_ci 14268c2ecf20Sopenharmony_ci if (!device_is_registered(&dev->dev)) { 14278c2ecf20Sopenharmony_ci rc = -ENODEV; 14288c2ecf20Sopenharmony_ci goto error; 14298c2ecf20Sopenharmony_ci } 14308c2ecf20Sopenharmony_ci 14318c2ecf20Sopenharmony_ci if (!dev->dev_up) { 14328c2ecf20Sopenharmony_ci rc = -ENODEV; 14338c2ecf20Sopenharmony_ci goto error; 14348c2ecf20Sopenharmony_ci } 14358c2ecf20Sopenharmony_ci 14368c2ecf20Sopenharmony_ci if (!dev->ops->se_io) { 14378c2ecf20Sopenharmony_ci rc = -EOPNOTSUPP; 14388c2ecf20Sopenharmony_ci goto error; 14398c2ecf20Sopenharmony_ci } 14408c2ecf20Sopenharmony_ci 14418c2ecf20Sopenharmony_ci se = nfc_find_se(dev, se_idx); 14428c2ecf20Sopenharmony_ci if (!se) { 14438c2ecf20Sopenharmony_ci rc = -EINVAL; 14448c2ecf20Sopenharmony_ci goto error; 14458c2ecf20Sopenharmony_ci } 14468c2ecf20Sopenharmony_ci 14478c2ecf20Sopenharmony_ci if (se->state != NFC_SE_ENABLED) { 14488c2ecf20Sopenharmony_ci rc = -ENODEV; 14498c2ecf20Sopenharmony_ci goto error; 14508c2ecf20Sopenharmony_ci } 14518c2ecf20Sopenharmony_ci 14528c2ecf20Sopenharmony_ci rc = dev->ops->se_io(dev, se_idx, apdu, 14538c2ecf20Sopenharmony_ci apdu_length, cb, cb_context); 14548c2ecf20Sopenharmony_ci 14558c2ecf20Sopenharmony_ci device_unlock(&dev->dev); 14568c2ecf20Sopenharmony_ci return rc; 14578c2ecf20Sopenharmony_ci 14588c2ecf20Sopenharmony_cierror: 14598c2ecf20Sopenharmony_ci device_unlock(&dev->dev); 14608c2ecf20Sopenharmony_ci kfree(cb_context); 14618c2ecf20Sopenharmony_ci return rc; 14628c2ecf20Sopenharmony_ci} 14638c2ecf20Sopenharmony_ci 14648c2ecf20Sopenharmony_cistruct se_io_ctx { 14658c2ecf20Sopenharmony_ci u32 dev_idx; 14668c2ecf20Sopenharmony_ci u32 se_idx; 14678c2ecf20Sopenharmony_ci}; 14688c2ecf20Sopenharmony_ci 14698c2ecf20Sopenharmony_cistatic void se_io_cb(void *context, u8 *apdu, size_t apdu_len, int err) 14708c2ecf20Sopenharmony_ci{ 14718c2ecf20Sopenharmony_ci struct se_io_ctx *ctx = context; 14728c2ecf20Sopenharmony_ci struct sk_buff *msg; 14738c2ecf20Sopenharmony_ci void *hdr; 14748c2ecf20Sopenharmony_ci 14758c2ecf20Sopenharmony_ci msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 14768c2ecf20Sopenharmony_ci if (!msg) { 14778c2ecf20Sopenharmony_ci kfree(ctx); 14788c2ecf20Sopenharmony_ci return; 14798c2ecf20Sopenharmony_ci } 14808c2ecf20Sopenharmony_ci 14818c2ecf20Sopenharmony_ci hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0, 14828c2ecf20Sopenharmony_ci NFC_CMD_SE_IO); 14838c2ecf20Sopenharmony_ci if (!hdr) 14848c2ecf20Sopenharmony_ci goto free_msg; 14858c2ecf20Sopenharmony_ci 14868c2ecf20Sopenharmony_ci if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, ctx->dev_idx) || 14878c2ecf20Sopenharmony_ci nla_put_u32(msg, NFC_ATTR_SE_INDEX, ctx->se_idx) || 14888c2ecf20Sopenharmony_ci nla_put(msg, NFC_ATTR_SE_APDU, apdu_len, apdu)) 14898c2ecf20Sopenharmony_ci goto nla_put_failure; 14908c2ecf20Sopenharmony_ci 14918c2ecf20Sopenharmony_ci genlmsg_end(msg, hdr); 14928c2ecf20Sopenharmony_ci 14938c2ecf20Sopenharmony_ci genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_KERNEL); 14948c2ecf20Sopenharmony_ci 14958c2ecf20Sopenharmony_ci kfree(ctx); 14968c2ecf20Sopenharmony_ci 14978c2ecf20Sopenharmony_ci return; 14988c2ecf20Sopenharmony_ci 14998c2ecf20Sopenharmony_cinla_put_failure: 15008c2ecf20Sopenharmony_cifree_msg: 15018c2ecf20Sopenharmony_ci nlmsg_free(msg); 15028c2ecf20Sopenharmony_ci kfree(ctx); 15038c2ecf20Sopenharmony_ci 15048c2ecf20Sopenharmony_ci return; 15058c2ecf20Sopenharmony_ci} 15068c2ecf20Sopenharmony_ci 15078c2ecf20Sopenharmony_cistatic int nfc_genl_se_io(struct sk_buff *skb, struct genl_info *info) 15088c2ecf20Sopenharmony_ci{ 15098c2ecf20Sopenharmony_ci struct nfc_dev *dev; 15108c2ecf20Sopenharmony_ci struct se_io_ctx *ctx; 15118c2ecf20Sopenharmony_ci u32 dev_idx, se_idx; 15128c2ecf20Sopenharmony_ci u8 *apdu; 15138c2ecf20Sopenharmony_ci size_t apdu_len; 15148c2ecf20Sopenharmony_ci int rc; 15158c2ecf20Sopenharmony_ci 15168c2ecf20Sopenharmony_ci if (!info->attrs[NFC_ATTR_DEVICE_INDEX] || 15178c2ecf20Sopenharmony_ci !info->attrs[NFC_ATTR_SE_INDEX] || 15188c2ecf20Sopenharmony_ci !info->attrs[NFC_ATTR_SE_APDU]) 15198c2ecf20Sopenharmony_ci return -EINVAL; 15208c2ecf20Sopenharmony_ci 15218c2ecf20Sopenharmony_ci dev_idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]); 15228c2ecf20Sopenharmony_ci se_idx = nla_get_u32(info->attrs[NFC_ATTR_SE_INDEX]); 15238c2ecf20Sopenharmony_ci 15248c2ecf20Sopenharmony_ci dev = nfc_get_device(dev_idx); 15258c2ecf20Sopenharmony_ci if (!dev) 15268c2ecf20Sopenharmony_ci return -ENODEV; 15278c2ecf20Sopenharmony_ci 15288c2ecf20Sopenharmony_ci if (!dev->ops || !dev->ops->se_io) { 15298c2ecf20Sopenharmony_ci rc = -EOPNOTSUPP; 15308c2ecf20Sopenharmony_ci goto put_dev; 15318c2ecf20Sopenharmony_ci } 15328c2ecf20Sopenharmony_ci 15338c2ecf20Sopenharmony_ci apdu_len = nla_len(info->attrs[NFC_ATTR_SE_APDU]); 15348c2ecf20Sopenharmony_ci if (apdu_len == 0) { 15358c2ecf20Sopenharmony_ci rc = -EINVAL; 15368c2ecf20Sopenharmony_ci goto put_dev; 15378c2ecf20Sopenharmony_ci } 15388c2ecf20Sopenharmony_ci 15398c2ecf20Sopenharmony_ci apdu = nla_data(info->attrs[NFC_ATTR_SE_APDU]); 15408c2ecf20Sopenharmony_ci if (!apdu) { 15418c2ecf20Sopenharmony_ci rc = -EINVAL; 15428c2ecf20Sopenharmony_ci goto put_dev; 15438c2ecf20Sopenharmony_ci } 15448c2ecf20Sopenharmony_ci 15458c2ecf20Sopenharmony_ci ctx = kzalloc(sizeof(struct se_io_ctx), GFP_KERNEL); 15468c2ecf20Sopenharmony_ci if (!ctx) { 15478c2ecf20Sopenharmony_ci rc = -ENOMEM; 15488c2ecf20Sopenharmony_ci goto put_dev; 15498c2ecf20Sopenharmony_ci } 15508c2ecf20Sopenharmony_ci 15518c2ecf20Sopenharmony_ci ctx->dev_idx = dev_idx; 15528c2ecf20Sopenharmony_ci ctx->se_idx = se_idx; 15538c2ecf20Sopenharmony_ci 15548c2ecf20Sopenharmony_ci rc = nfc_se_io(dev, se_idx, apdu, apdu_len, se_io_cb, ctx); 15558c2ecf20Sopenharmony_ci 15568c2ecf20Sopenharmony_ciput_dev: 15578c2ecf20Sopenharmony_ci nfc_put_device(dev); 15588c2ecf20Sopenharmony_ci return rc; 15598c2ecf20Sopenharmony_ci} 15608c2ecf20Sopenharmony_ci 15618c2ecf20Sopenharmony_cistatic int nfc_genl_vendor_cmd(struct sk_buff *skb, 15628c2ecf20Sopenharmony_ci struct genl_info *info) 15638c2ecf20Sopenharmony_ci{ 15648c2ecf20Sopenharmony_ci struct nfc_dev *dev; 15658c2ecf20Sopenharmony_ci struct nfc_vendor_cmd *cmd; 15668c2ecf20Sopenharmony_ci u32 dev_idx, vid, subcmd; 15678c2ecf20Sopenharmony_ci u8 *data; 15688c2ecf20Sopenharmony_ci size_t data_len; 15698c2ecf20Sopenharmony_ci int i, err; 15708c2ecf20Sopenharmony_ci 15718c2ecf20Sopenharmony_ci if (!info->attrs[NFC_ATTR_DEVICE_INDEX] || 15728c2ecf20Sopenharmony_ci !info->attrs[NFC_ATTR_VENDOR_ID] || 15738c2ecf20Sopenharmony_ci !info->attrs[NFC_ATTR_VENDOR_SUBCMD]) 15748c2ecf20Sopenharmony_ci return -EINVAL; 15758c2ecf20Sopenharmony_ci 15768c2ecf20Sopenharmony_ci dev_idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]); 15778c2ecf20Sopenharmony_ci vid = nla_get_u32(info->attrs[NFC_ATTR_VENDOR_ID]); 15788c2ecf20Sopenharmony_ci subcmd = nla_get_u32(info->attrs[NFC_ATTR_VENDOR_SUBCMD]); 15798c2ecf20Sopenharmony_ci 15808c2ecf20Sopenharmony_ci dev = nfc_get_device(dev_idx); 15818c2ecf20Sopenharmony_ci if (!dev) 15828c2ecf20Sopenharmony_ci return -ENODEV; 15838c2ecf20Sopenharmony_ci 15848c2ecf20Sopenharmony_ci if (!dev->vendor_cmds || !dev->n_vendor_cmds) { 15858c2ecf20Sopenharmony_ci err = -ENODEV; 15868c2ecf20Sopenharmony_ci goto put_dev; 15878c2ecf20Sopenharmony_ci } 15888c2ecf20Sopenharmony_ci 15898c2ecf20Sopenharmony_ci if (info->attrs[NFC_ATTR_VENDOR_DATA]) { 15908c2ecf20Sopenharmony_ci data = nla_data(info->attrs[NFC_ATTR_VENDOR_DATA]); 15918c2ecf20Sopenharmony_ci data_len = nla_len(info->attrs[NFC_ATTR_VENDOR_DATA]); 15928c2ecf20Sopenharmony_ci if (data_len == 0) { 15938c2ecf20Sopenharmony_ci err = -EINVAL; 15948c2ecf20Sopenharmony_ci goto put_dev; 15958c2ecf20Sopenharmony_ci } 15968c2ecf20Sopenharmony_ci } else { 15978c2ecf20Sopenharmony_ci data = NULL; 15988c2ecf20Sopenharmony_ci data_len = 0; 15998c2ecf20Sopenharmony_ci } 16008c2ecf20Sopenharmony_ci 16018c2ecf20Sopenharmony_ci for (i = 0; i < dev->n_vendor_cmds; i++) { 16028c2ecf20Sopenharmony_ci cmd = &dev->vendor_cmds[i]; 16038c2ecf20Sopenharmony_ci 16048c2ecf20Sopenharmony_ci if (cmd->vendor_id != vid || cmd->subcmd != subcmd) 16058c2ecf20Sopenharmony_ci continue; 16068c2ecf20Sopenharmony_ci 16078c2ecf20Sopenharmony_ci dev->cur_cmd_info = info; 16088c2ecf20Sopenharmony_ci err = cmd->doit(dev, data, data_len); 16098c2ecf20Sopenharmony_ci dev->cur_cmd_info = NULL; 16108c2ecf20Sopenharmony_ci goto put_dev; 16118c2ecf20Sopenharmony_ci } 16128c2ecf20Sopenharmony_ci 16138c2ecf20Sopenharmony_ci err = -EOPNOTSUPP; 16148c2ecf20Sopenharmony_ci 16158c2ecf20Sopenharmony_ciput_dev: 16168c2ecf20Sopenharmony_ci nfc_put_device(dev); 16178c2ecf20Sopenharmony_ci return err; 16188c2ecf20Sopenharmony_ci} 16198c2ecf20Sopenharmony_ci 16208c2ecf20Sopenharmony_ci/* message building helper */ 16218c2ecf20Sopenharmony_cistatic inline void *nfc_hdr_put(struct sk_buff *skb, u32 portid, u32 seq, 16228c2ecf20Sopenharmony_ci int flags, u8 cmd) 16238c2ecf20Sopenharmony_ci{ 16248c2ecf20Sopenharmony_ci /* since there is no private header just add the generic one */ 16258c2ecf20Sopenharmony_ci return genlmsg_put(skb, portid, seq, &nfc_genl_family, flags, cmd); 16268c2ecf20Sopenharmony_ci} 16278c2ecf20Sopenharmony_ci 16288c2ecf20Sopenharmony_cistatic struct sk_buff * 16298c2ecf20Sopenharmony_ci__nfc_alloc_vendor_cmd_skb(struct nfc_dev *dev, int approxlen, 16308c2ecf20Sopenharmony_ci u32 portid, u32 seq, 16318c2ecf20Sopenharmony_ci enum nfc_attrs attr, 16328c2ecf20Sopenharmony_ci u32 oui, u32 subcmd, gfp_t gfp) 16338c2ecf20Sopenharmony_ci{ 16348c2ecf20Sopenharmony_ci struct sk_buff *skb; 16358c2ecf20Sopenharmony_ci void *hdr; 16368c2ecf20Sopenharmony_ci 16378c2ecf20Sopenharmony_ci skb = nlmsg_new(approxlen + 100, gfp); 16388c2ecf20Sopenharmony_ci if (!skb) 16398c2ecf20Sopenharmony_ci return NULL; 16408c2ecf20Sopenharmony_ci 16418c2ecf20Sopenharmony_ci hdr = nfc_hdr_put(skb, portid, seq, 0, NFC_CMD_VENDOR); 16428c2ecf20Sopenharmony_ci if (!hdr) { 16438c2ecf20Sopenharmony_ci kfree_skb(skb); 16448c2ecf20Sopenharmony_ci return NULL; 16458c2ecf20Sopenharmony_ci } 16468c2ecf20Sopenharmony_ci 16478c2ecf20Sopenharmony_ci if (nla_put_u32(skb, NFC_ATTR_DEVICE_INDEX, dev->idx)) 16488c2ecf20Sopenharmony_ci goto nla_put_failure; 16498c2ecf20Sopenharmony_ci if (nla_put_u32(skb, NFC_ATTR_VENDOR_ID, oui)) 16508c2ecf20Sopenharmony_ci goto nla_put_failure; 16518c2ecf20Sopenharmony_ci if (nla_put_u32(skb, NFC_ATTR_VENDOR_SUBCMD, subcmd)) 16528c2ecf20Sopenharmony_ci goto nla_put_failure; 16538c2ecf20Sopenharmony_ci 16548c2ecf20Sopenharmony_ci ((void **)skb->cb)[0] = dev; 16558c2ecf20Sopenharmony_ci ((void **)skb->cb)[1] = hdr; 16568c2ecf20Sopenharmony_ci 16578c2ecf20Sopenharmony_ci return skb; 16588c2ecf20Sopenharmony_ci 16598c2ecf20Sopenharmony_cinla_put_failure: 16608c2ecf20Sopenharmony_ci kfree_skb(skb); 16618c2ecf20Sopenharmony_ci return NULL; 16628c2ecf20Sopenharmony_ci} 16638c2ecf20Sopenharmony_ci 16648c2ecf20Sopenharmony_cistruct sk_buff *__nfc_alloc_vendor_cmd_reply_skb(struct nfc_dev *dev, 16658c2ecf20Sopenharmony_ci enum nfc_attrs attr, 16668c2ecf20Sopenharmony_ci u32 oui, u32 subcmd, 16678c2ecf20Sopenharmony_ci int approxlen) 16688c2ecf20Sopenharmony_ci{ 16698c2ecf20Sopenharmony_ci if (WARN_ON(!dev->cur_cmd_info)) 16708c2ecf20Sopenharmony_ci return NULL; 16718c2ecf20Sopenharmony_ci 16728c2ecf20Sopenharmony_ci return __nfc_alloc_vendor_cmd_skb(dev, approxlen, 16738c2ecf20Sopenharmony_ci dev->cur_cmd_info->snd_portid, 16748c2ecf20Sopenharmony_ci dev->cur_cmd_info->snd_seq, attr, 16758c2ecf20Sopenharmony_ci oui, subcmd, GFP_KERNEL); 16768c2ecf20Sopenharmony_ci} 16778c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__nfc_alloc_vendor_cmd_reply_skb); 16788c2ecf20Sopenharmony_ci 16798c2ecf20Sopenharmony_ciint nfc_vendor_cmd_reply(struct sk_buff *skb) 16808c2ecf20Sopenharmony_ci{ 16818c2ecf20Sopenharmony_ci struct nfc_dev *dev = ((void **)skb->cb)[0]; 16828c2ecf20Sopenharmony_ci void *hdr = ((void **)skb->cb)[1]; 16838c2ecf20Sopenharmony_ci 16848c2ecf20Sopenharmony_ci /* clear CB data for netlink core to own from now on */ 16858c2ecf20Sopenharmony_ci memset(skb->cb, 0, sizeof(skb->cb)); 16868c2ecf20Sopenharmony_ci 16878c2ecf20Sopenharmony_ci if (WARN_ON(!dev->cur_cmd_info)) { 16888c2ecf20Sopenharmony_ci kfree_skb(skb); 16898c2ecf20Sopenharmony_ci return -EINVAL; 16908c2ecf20Sopenharmony_ci } 16918c2ecf20Sopenharmony_ci 16928c2ecf20Sopenharmony_ci genlmsg_end(skb, hdr); 16938c2ecf20Sopenharmony_ci return genlmsg_reply(skb, dev->cur_cmd_info); 16948c2ecf20Sopenharmony_ci} 16958c2ecf20Sopenharmony_ciEXPORT_SYMBOL(nfc_vendor_cmd_reply); 16968c2ecf20Sopenharmony_ci 16978c2ecf20Sopenharmony_cistatic const struct genl_ops nfc_genl_ops[] = { 16988c2ecf20Sopenharmony_ci { 16998c2ecf20Sopenharmony_ci .cmd = NFC_CMD_GET_DEVICE, 17008c2ecf20Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 17018c2ecf20Sopenharmony_ci .doit = nfc_genl_get_device, 17028c2ecf20Sopenharmony_ci .dumpit = nfc_genl_dump_devices, 17038c2ecf20Sopenharmony_ci .done = nfc_genl_dump_devices_done, 17048c2ecf20Sopenharmony_ci }, 17058c2ecf20Sopenharmony_ci { 17068c2ecf20Sopenharmony_ci .cmd = NFC_CMD_DEV_UP, 17078c2ecf20Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 17088c2ecf20Sopenharmony_ci .doit = nfc_genl_dev_up, 17098c2ecf20Sopenharmony_ci .flags = GENL_ADMIN_PERM, 17108c2ecf20Sopenharmony_ci }, 17118c2ecf20Sopenharmony_ci { 17128c2ecf20Sopenharmony_ci .cmd = NFC_CMD_DEV_DOWN, 17138c2ecf20Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 17148c2ecf20Sopenharmony_ci .doit = nfc_genl_dev_down, 17158c2ecf20Sopenharmony_ci .flags = GENL_ADMIN_PERM, 17168c2ecf20Sopenharmony_ci }, 17178c2ecf20Sopenharmony_ci { 17188c2ecf20Sopenharmony_ci .cmd = NFC_CMD_START_POLL, 17198c2ecf20Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 17208c2ecf20Sopenharmony_ci .doit = nfc_genl_start_poll, 17218c2ecf20Sopenharmony_ci .flags = GENL_ADMIN_PERM, 17228c2ecf20Sopenharmony_ci }, 17238c2ecf20Sopenharmony_ci { 17248c2ecf20Sopenharmony_ci .cmd = NFC_CMD_STOP_POLL, 17258c2ecf20Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 17268c2ecf20Sopenharmony_ci .doit = nfc_genl_stop_poll, 17278c2ecf20Sopenharmony_ci .flags = GENL_ADMIN_PERM, 17288c2ecf20Sopenharmony_ci }, 17298c2ecf20Sopenharmony_ci { 17308c2ecf20Sopenharmony_ci .cmd = NFC_CMD_DEP_LINK_UP, 17318c2ecf20Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 17328c2ecf20Sopenharmony_ci .doit = nfc_genl_dep_link_up, 17338c2ecf20Sopenharmony_ci .flags = GENL_ADMIN_PERM, 17348c2ecf20Sopenharmony_ci }, 17358c2ecf20Sopenharmony_ci { 17368c2ecf20Sopenharmony_ci .cmd = NFC_CMD_DEP_LINK_DOWN, 17378c2ecf20Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 17388c2ecf20Sopenharmony_ci .doit = nfc_genl_dep_link_down, 17398c2ecf20Sopenharmony_ci .flags = GENL_ADMIN_PERM, 17408c2ecf20Sopenharmony_ci }, 17418c2ecf20Sopenharmony_ci { 17428c2ecf20Sopenharmony_ci .cmd = NFC_CMD_GET_TARGET, 17438c2ecf20Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | 17448c2ecf20Sopenharmony_ci GENL_DONT_VALIDATE_DUMP_STRICT, 17458c2ecf20Sopenharmony_ci .dumpit = nfc_genl_dump_targets, 17468c2ecf20Sopenharmony_ci .done = nfc_genl_dump_targets_done, 17478c2ecf20Sopenharmony_ci }, 17488c2ecf20Sopenharmony_ci { 17498c2ecf20Sopenharmony_ci .cmd = NFC_CMD_LLC_GET_PARAMS, 17508c2ecf20Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 17518c2ecf20Sopenharmony_ci .doit = nfc_genl_llc_get_params, 17528c2ecf20Sopenharmony_ci }, 17538c2ecf20Sopenharmony_ci { 17548c2ecf20Sopenharmony_ci .cmd = NFC_CMD_LLC_SET_PARAMS, 17558c2ecf20Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 17568c2ecf20Sopenharmony_ci .doit = nfc_genl_llc_set_params, 17578c2ecf20Sopenharmony_ci .flags = GENL_ADMIN_PERM, 17588c2ecf20Sopenharmony_ci }, 17598c2ecf20Sopenharmony_ci { 17608c2ecf20Sopenharmony_ci .cmd = NFC_CMD_LLC_SDREQ, 17618c2ecf20Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 17628c2ecf20Sopenharmony_ci .doit = nfc_genl_llc_sdreq, 17638c2ecf20Sopenharmony_ci .flags = GENL_ADMIN_PERM, 17648c2ecf20Sopenharmony_ci }, 17658c2ecf20Sopenharmony_ci { 17668c2ecf20Sopenharmony_ci .cmd = NFC_CMD_FW_DOWNLOAD, 17678c2ecf20Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 17688c2ecf20Sopenharmony_ci .doit = nfc_genl_fw_download, 17698c2ecf20Sopenharmony_ci .flags = GENL_ADMIN_PERM, 17708c2ecf20Sopenharmony_ci }, 17718c2ecf20Sopenharmony_ci { 17728c2ecf20Sopenharmony_ci .cmd = NFC_CMD_ENABLE_SE, 17738c2ecf20Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 17748c2ecf20Sopenharmony_ci .doit = nfc_genl_enable_se, 17758c2ecf20Sopenharmony_ci .flags = GENL_ADMIN_PERM, 17768c2ecf20Sopenharmony_ci }, 17778c2ecf20Sopenharmony_ci { 17788c2ecf20Sopenharmony_ci .cmd = NFC_CMD_DISABLE_SE, 17798c2ecf20Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 17808c2ecf20Sopenharmony_ci .doit = nfc_genl_disable_se, 17818c2ecf20Sopenharmony_ci .flags = GENL_ADMIN_PERM, 17828c2ecf20Sopenharmony_ci }, 17838c2ecf20Sopenharmony_ci { 17848c2ecf20Sopenharmony_ci .cmd = NFC_CMD_GET_SE, 17858c2ecf20Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 17868c2ecf20Sopenharmony_ci .dumpit = nfc_genl_dump_ses, 17878c2ecf20Sopenharmony_ci .done = nfc_genl_dump_ses_done, 17888c2ecf20Sopenharmony_ci }, 17898c2ecf20Sopenharmony_ci { 17908c2ecf20Sopenharmony_ci .cmd = NFC_CMD_SE_IO, 17918c2ecf20Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 17928c2ecf20Sopenharmony_ci .doit = nfc_genl_se_io, 17938c2ecf20Sopenharmony_ci .flags = GENL_ADMIN_PERM, 17948c2ecf20Sopenharmony_ci }, 17958c2ecf20Sopenharmony_ci { 17968c2ecf20Sopenharmony_ci .cmd = NFC_CMD_ACTIVATE_TARGET, 17978c2ecf20Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 17988c2ecf20Sopenharmony_ci .doit = nfc_genl_activate_target, 17998c2ecf20Sopenharmony_ci .flags = GENL_ADMIN_PERM, 18008c2ecf20Sopenharmony_ci }, 18018c2ecf20Sopenharmony_ci { 18028c2ecf20Sopenharmony_ci .cmd = NFC_CMD_VENDOR, 18038c2ecf20Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 18048c2ecf20Sopenharmony_ci .doit = nfc_genl_vendor_cmd, 18058c2ecf20Sopenharmony_ci .flags = GENL_ADMIN_PERM, 18068c2ecf20Sopenharmony_ci }, 18078c2ecf20Sopenharmony_ci { 18088c2ecf20Sopenharmony_ci .cmd = NFC_CMD_DEACTIVATE_TARGET, 18098c2ecf20Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 18108c2ecf20Sopenharmony_ci .doit = nfc_genl_deactivate_target, 18118c2ecf20Sopenharmony_ci .flags = GENL_ADMIN_PERM, 18128c2ecf20Sopenharmony_ci }, 18138c2ecf20Sopenharmony_ci}; 18148c2ecf20Sopenharmony_ci 18158c2ecf20Sopenharmony_cistatic struct genl_family nfc_genl_family __ro_after_init = { 18168c2ecf20Sopenharmony_ci .hdrsize = 0, 18178c2ecf20Sopenharmony_ci .name = NFC_GENL_NAME, 18188c2ecf20Sopenharmony_ci .version = NFC_GENL_VERSION, 18198c2ecf20Sopenharmony_ci .maxattr = NFC_ATTR_MAX, 18208c2ecf20Sopenharmony_ci .policy = nfc_genl_policy, 18218c2ecf20Sopenharmony_ci .module = THIS_MODULE, 18228c2ecf20Sopenharmony_ci .ops = nfc_genl_ops, 18238c2ecf20Sopenharmony_ci .n_ops = ARRAY_SIZE(nfc_genl_ops), 18248c2ecf20Sopenharmony_ci .mcgrps = nfc_genl_mcgrps, 18258c2ecf20Sopenharmony_ci .n_mcgrps = ARRAY_SIZE(nfc_genl_mcgrps), 18268c2ecf20Sopenharmony_ci}; 18278c2ecf20Sopenharmony_ci 18288c2ecf20Sopenharmony_ci 18298c2ecf20Sopenharmony_cistruct urelease_work { 18308c2ecf20Sopenharmony_ci struct work_struct w; 18318c2ecf20Sopenharmony_ci u32 portid; 18328c2ecf20Sopenharmony_ci}; 18338c2ecf20Sopenharmony_ci 18348c2ecf20Sopenharmony_cistatic void nfc_urelease_event_work(struct work_struct *work) 18358c2ecf20Sopenharmony_ci{ 18368c2ecf20Sopenharmony_ci struct urelease_work *w = container_of(work, struct urelease_work, w); 18378c2ecf20Sopenharmony_ci struct class_dev_iter iter; 18388c2ecf20Sopenharmony_ci struct nfc_dev *dev; 18398c2ecf20Sopenharmony_ci 18408c2ecf20Sopenharmony_ci pr_debug("portid %d\n", w->portid); 18418c2ecf20Sopenharmony_ci 18428c2ecf20Sopenharmony_ci mutex_lock(&nfc_devlist_mutex); 18438c2ecf20Sopenharmony_ci 18448c2ecf20Sopenharmony_ci nfc_device_iter_init(&iter); 18458c2ecf20Sopenharmony_ci dev = nfc_device_iter_next(&iter); 18468c2ecf20Sopenharmony_ci 18478c2ecf20Sopenharmony_ci while (dev) { 18488c2ecf20Sopenharmony_ci mutex_lock(&dev->genl_data.genl_data_mutex); 18498c2ecf20Sopenharmony_ci 18508c2ecf20Sopenharmony_ci if (dev->genl_data.poll_req_portid == w->portid) { 18518c2ecf20Sopenharmony_ci nfc_stop_poll(dev); 18528c2ecf20Sopenharmony_ci dev->genl_data.poll_req_portid = 0; 18538c2ecf20Sopenharmony_ci } 18548c2ecf20Sopenharmony_ci 18558c2ecf20Sopenharmony_ci mutex_unlock(&dev->genl_data.genl_data_mutex); 18568c2ecf20Sopenharmony_ci 18578c2ecf20Sopenharmony_ci dev = nfc_device_iter_next(&iter); 18588c2ecf20Sopenharmony_ci } 18598c2ecf20Sopenharmony_ci 18608c2ecf20Sopenharmony_ci nfc_device_iter_exit(&iter); 18618c2ecf20Sopenharmony_ci 18628c2ecf20Sopenharmony_ci mutex_unlock(&nfc_devlist_mutex); 18638c2ecf20Sopenharmony_ci 18648c2ecf20Sopenharmony_ci kfree(w); 18658c2ecf20Sopenharmony_ci} 18668c2ecf20Sopenharmony_ci 18678c2ecf20Sopenharmony_cistatic int nfc_genl_rcv_nl_event(struct notifier_block *this, 18688c2ecf20Sopenharmony_ci unsigned long event, void *ptr) 18698c2ecf20Sopenharmony_ci{ 18708c2ecf20Sopenharmony_ci struct netlink_notify *n = ptr; 18718c2ecf20Sopenharmony_ci struct urelease_work *w; 18728c2ecf20Sopenharmony_ci 18738c2ecf20Sopenharmony_ci if (event != NETLINK_URELEASE || n->protocol != NETLINK_GENERIC) 18748c2ecf20Sopenharmony_ci goto out; 18758c2ecf20Sopenharmony_ci 18768c2ecf20Sopenharmony_ci pr_debug("NETLINK_URELEASE event from id %d\n", n->portid); 18778c2ecf20Sopenharmony_ci 18788c2ecf20Sopenharmony_ci w = kmalloc(sizeof(*w), GFP_ATOMIC); 18798c2ecf20Sopenharmony_ci if (w) { 18808c2ecf20Sopenharmony_ci INIT_WORK((struct work_struct *) w, nfc_urelease_event_work); 18818c2ecf20Sopenharmony_ci w->portid = n->portid; 18828c2ecf20Sopenharmony_ci schedule_work((struct work_struct *) w); 18838c2ecf20Sopenharmony_ci } 18848c2ecf20Sopenharmony_ci 18858c2ecf20Sopenharmony_ciout: 18868c2ecf20Sopenharmony_ci return NOTIFY_DONE; 18878c2ecf20Sopenharmony_ci} 18888c2ecf20Sopenharmony_ci 18898c2ecf20Sopenharmony_civoid nfc_genl_data_init(struct nfc_genl_data *genl_data) 18908c2ecf20Sopenharmony_ci{ 18918c2ecf20Sopenharmony_ci genl_data->poll_req_portid = 0; 18928c2ecf20Sopenharmony_ci mutex_init(&genl_data->genl_data_mutex); 18938c2ecf20Sopenharmony_ci} 18948c2ecf20Sopenharmony_ci 18958c2ecf20Sopenharmony_civoid nfc_genl_data_exit(struct nfc_genl_data *genl_data) 18968c2ecf20Sopenharmony_ci{ 18978c2ecf20Sopenharmony_ci mutex_destroy(&genl_data->genl_data_mutex); 18988c2ecf20Sopenharmony_ci} 18998c2ecf20Sopenharmony_ci 19008c2ecf20Sopenharmony_cistatic struct notifier_block nl_notifier = { 19018c2ecf20Sopenharmony_ci .notifier_call = nfc_genl_rcv_nl_event, 19028c2ecf20Sopenharmony_ci}; 19038c2ecf20Sopenharmony_ci 19048c2ecf20Sopenharmony_ci/** 19058c2ecf20Sopenharmony_ci * nfc_genl_init() - Initialize netlink interface 19068c2ecf20Sopenharmony_ci * 19078c2ecf20Sopenharmony_ci * This initialization function registers the nfc netlink family. 19088c2ecf20Sopenharmony_ci */ 19098c2ecf20Sopenharmony_ciint __init nfc_genl_init(void) 19108c2ecf20Sopenharmony_ci{ 19118c2ecf20Sopenharmony_ci int rc; 19128c2ecf20Sopenharmony_ci 19138c2ecf20Sopenharmony_ci rc = genl_register_family(&nfc_genl_family); 19148c2ecf20Sopenharmony_ci if (rc) 19158c2ecf20Sopenharmony_ci return rc; 19168c2ecf20Sopenharmony_ci 19178c2ecf20Sopenharmony_ci netlink_register_notifier(&nl_notifier); 19188c2ecf20Sopenharmony_ci 19198c2ecf20Sopenharmony_ci return 0; 19208c2ecf20Sopenharmony_ci} 19218c2ecf20Sopenharmony_ci 19228c2ecf20Sopenharmony_ci/** 19238c2ecf20Sopenharmony_ci * nfc_genl_exit() - Deinitialize netlink interface 19248c2ecf20Sopenharmony_ci * 19258c2ecf20Sopenharmony_ci * This exit function unregisters the nfc netlink family. 19268c2ecf20Sopenharmony_ci */ 19278c2ecf20Sopenharmony_civoid nfc_genl_exit(void) 19288c2ecf20Sopenharmony_ci{ 19298c2ecf20Sopenharmony_ci netlink_unregister_notifier(&nl_notifier); 19308c2ecf20Sopenharmony_ci genl_unregister_family(&nfc_genl_family); 19318c2ecf20Sopenharmony_ci} 1932