Skip to content

Commit

Permalink
NFC: Extend netlink interface for LTO, RW, and MIUX parameters support
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Thierry Escande authored and Samuel Ortiz committed Oct 28, 2012
1 parent f31652a commit 52feb44
Show file tree
Hide file tree
Showing 6 changed files with 189 additions and 19 deletions.
15 changes: 15 additions & 0 deletions include/uapi/linux/nfc.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,13 @@
* target mode.
* @NFC_EVENT_DEVICE_DEACTIVATED: event emitted when the adapter is deactivated
* from target mode.
* @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.
*/
enum nfc_commands {
NFC_CMD_UNSPEC,
Expand All @@ -77,6 +84,8 @@ enum nfc_commands {
NFC_EVENT_TARGET_LOST,
NFC_EVENT_TM_ACTIVATED,
NFC_EVENT_TM_DEACTIVATED,
NFC_CMD_LLC_GET_PARAMS,
NFC_CMD_LLC_SET_PARAMS,
/* private: internal use only */
__NFC_CMD_AFTER_LAST
};
Expand All @@ -102,6 +111,9 @@ enum nfc_commands {
* @NFC_ATTR_RF_MODE: Initiator or target
* @NFC_ATTR_IM_PROTOCOLS: Initiator mode protocols to poll for
* @NFC_ATTR_TM_PROTOCOLS: Target mode protocols to listen for
* @NFC_ATTR_LLC_PARAM_LTO: Link TimeOut parameter
* @NFC_ATTR_LLC_PARAM_RW: Receive Window size parameter
* @NFC_ATTR_LLC_PARAM_MIUX: MIU eXtension parameter
*/
enum nfc_attrs {
NFC_ATTR_UNSPEC,
Expand All @@ -119,6 +131,9 @@ enum nfc_attrs {
NFC_ATTR_DEVICE_POWERED,
NFC_ATTR_IM_PROTOCOLS,
NFC_ATTR_TM_PROTOCOLS,
NFC_ATTR_LLC_PARAM_LTO,
NFC_ATTR_LLC_PARAM_RW,
NFC_ATTR_LLC_PARAM_MIUX,
/* private: internal use only */
__NFC_ATTR_AFTER_LAST
};
Expand Down
18 changes: 6 additions & 12 deletions net/nfc/llcp/commands.c
Original file line number Diff line number Diff line change
Expand Up @@ -316,8 +316,7 @@ int nfc_llcp_send_connect(struct nfc_llcp_sock *sock)
struct sk_buff *skb;
u8 *service_name_tlv = NULL, service_name_tlv_length;
u8 *miux_tlv = NULL, miux_tlv_length;
u8 *rw_tlv = NULL, rw_tlv_length, rw;
__be16 miux;
u8 *rw_tlv = NULL, rw_tlv_length;
int err;
u16 size = 0;

Expand All @@ -335,13 +334,11 @@ int nfc_llcp_send_connect(struct nfc_llcp_sock *sock)
size += service_name_tlv_length;
}

miux = cpu_to_be16(LLCP_MAX_MIUX);
miux_tlv = nfc_llcp_build_tlv(LLCP_TLV_MIUX, (u8 *)&miux, 0,
miux_tlv = nfc_llcp_build_tlv(LLCP_TLV_MIUX, (u8 *)&local->miux, 0,
&miux_tlv_length);
size += miux_tlv_length;

rw = LLCP_MAX_RW;
rw_tlv = nfc_llcp_build_tlv(LLCP_TLV_RW, &rw, 0, &rw_tlv_length);
rw_tlv = nfc_llcp_build_tlv(LLCP_TLV_RW, &local->rw, 0, &rw_tlv_length);
size += rw_tlv_length;

pr_debug("SKB size %d SN length %zu\n", size, sock->service_name_len);
Expand Down Expand Up @@ -378,8 +375,7 @@ int nfc_llcp_send_cc(struct nfc_llcp_sock *sock)
struct nfc_llcp_local *local;
struct sk_buff *skb;
u8 *miux_tlv = NULL, miux_tlv_length;
u8 *rw_tlv = NULL, rw_tlv_length, rw;
__be16 miux;
u8 *rw_tlv = NULL, rw_tlv_length;
int err;
u16 size = 0;

Expand All @@ -389,13 +385,11 @@ int nfc_llcp_send_cc(struct nfc_llcp_sock *sock)
if (local == NULL)
return -ENODEV;

miux = cpu_to_be16(LLCP_MAX_MIUX);
miux_tlv = nfc_llcp_build_tlv(LLCP_TLV_MIUX, (u8 *)&miux, 0,
miux_tlv = nfc_llcp_build_tlv(LLCP_TLV_MIUX, (u8 *)&local->miux, 0,
&miux_tlv_length);
size += miux_tlv_length;

rw = LLCP_MAX_RW;
rw_tlv = nfc_llcp_build_tlv(LLCP_TLV_RW, &rw, 0, &rw_tlv_length);
rw_tlv = nfc_llcp_build_tlv(LLCP_TLV_RW, &local->rw, 0, &rw_tlv_length);
size += rw_tlv_length;

skb = llcp_allocate_pdu(sock, LLCP_PDU_CC, size);
Expand Down
14 changes: 7 additions & 7 deletions net/nfc/llcp/llcp.c
Original file line number Diff line number Diff line change
Expand Up @@ -467,10 +467,9 @@ static u8 nfc_llcp_reserve_sdp_ssap(struct nfc_llcp_local *local)
static int nfc_llcp_build_gb(struct nfc_llcp_local *local)
{
u8 *gb_cur, *version_tlv, version, version_length;
u8 *lto_tlv, lto, lto_length;
u8 *lto_tlv, lto_length;
u8 *wks_tlv, wks_length;
u8 *miux_tlv, miux_length;
__be16 miux;
u8 gb_len = 0;
int ret = 0;

Expand All @@ -479,18 +478,15 @@ static int nfc_llcp_build_gb(struct nfc_llcp_local *local)
1, &version_length);
gb_len += version_length;

/* 1500 ms */
lto = 150;
lto_tlv = nfc_llcp_build_tlv(LLCP_TLV_LTO, &lto, 1, &lto_length);
lto_tlv = nfc_llcp_build_tlv(LLCP_TLV_LTO, &local->lto, 1, &lto_length);
gb_len += lto_length;

pr_debug("Local wks 0x%lx\n", local->local_wks);
wks_tlv = nfc_llcp_build_tlv(LLCP_TLV_WKS, (u8 *)&local->local_wks, 2,
&wks_length);
gb_len += wks_length;

miux = cpu_to_be16(LLCP_MAX_MIUX);
miux_tlv = nfc_llcp_build_tlv(LLCP_TLV_MIUX, (u8 *)&miux, 0,
miux_tlv = nfc_llcp_build_tlv(LLCP_TLV_MIUX, (u8 *)&local->miux, 0,
&miux_length);
gb_len += miux_length;

Expand Down Expand Up @@ -1383,6 +1379,10 @@ int nfc_llcp_register_device(struct nfc_dev *ndev)
rwlock_init(&local->connecting_sockets.lock);
rwlock_init(&local->raw_sockets.lock);

local->lto = 150; /* 1500 ms */
local->rw = LLCP_MAX_RW;
local->miux = cpu_to_be16(LLCP_MAX_MIUX);

nfc_llcp_build_gb(local);

local->remote_miu = LLCP_DEFAULT_MIU;
Expand Down
3 changes: 3 additions & 0 deletions net/nfc/llcp/llcp.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ struct nfc_llcp_local {
u32 target_idx;
u8 rf_mode;
u8 comm_mode;
u8 lto;
u8 rw;
__be16 miux;
unsigned long local_wks; /* Well known services */
unsigned long local_sdp; /* Local services */
unsigned long local_sap; /* Local SAPs, not available for discovery */
Expand Down
152 changes: 152 additions & 0 deletions net/nfc/netlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@

#include "nfc.h"

#include "llcp/llcp.h"

static struct genl_multicast_group nfc_genl_event_mcgrp = {
.name = NFC_GENL_MCAST_EVENT_NAME,
};
Expand Down Expand Up @@ -716,6 +718,146 @@ static int nfc_genl_dep_link_down(struct sk_buff *skb, struct genl_info *info)
return rc;
}

static int nfc_genl_send_params(struct sk_buff *msg,
struct nfc_llcp_local *local,
u32 portid, u32 seq)
{
void *hdr;

hdr = genlmsg_put(msg, portid, seq, &nfc_genl_family, 0,
NFC_CMD_LLC_GET_PARAMS);
if (!hdr)
return -EMSGSIZE;

if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, local->dev->idx) ||
nla_put_u8(msg, NFC_ATTR_LLC_PARAM_LTO, local->lto) ||
nla_put_u8(msg, NFC_ATTR_LLC_PARAM_RW, local->rw) ||
nla_put_u16(msg, NFC_ATTR_LLC_PARAM_MIUX, be16_to_cpu(local->miux)))
goto nla_put_failure;

return genlmsg_end(msg, hdr);

nla_put_failure:

genlmsg_cancel(msg, hdr);
return -EMSGSIZE;
}

static int nfc_genl_llc_get_params(struct sk_buff *skb, struct genl_info *info)
{
struct nfc_dev *dev;
struct nfc_llcp_local *local;
int rc = 0;
struct sk_buff *msg = NULL;
u32 idx;

if (!info->attrs[NFC_ATTR_DEVICE_INDEX])
return -EINVAL;

idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]);

dev = nfc_get_device(idx);
if (!dev)
return -ENODEV;

device_lock(&dev->dev);

local = nfc_llcp_find_local(dev);
if (!local) {
rc = -ENODEV;
goto exit;
}

msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
if (!msg) {
rc = -ENOMEM;
goto exit;
}

rc = nfc_genl_send_params(msg, local, info->snd_portid, info->snd_seq);

exit:
device_unlock(&dev->dev);

nfc_put_device(dev);

if (rc < 0) {
if (msg)
nlmsg_free(msg);

return rc;
}

return genlmsg_reply(msg, info);
}

static int nfc_genl_llc_set_params(struct sk_buff *skb, struct genl_info *info)
{
struct nfc_dev *dev;
struct nfc_llcp_local *local;
u8 rw = 0;
u16 miux = 0;
u32 idx;
int rc = 0;

if (!info->attrs[NFC_ATTR_DEVICE_INDEX] ||
(!info->attrs[NFC_ATTR_LLC_PARAM_LTO] &&
!info->attrs[NFC_ATTR_LLC_PARAM_RW] &&
!info->attrs[NFC_ATTR_LLC_PARAM_MIUX]))
return -EINVAL;

if (info->attrs[NFC_ATTR_LLC_PARAM_RW]) {
rw = nla_get_u8(info->attrs[NFC_ATTR_LLC_PARAM_RW]);

if (rw > LLCP_MAX_RW)
return -EINVAL;
}

if (info->attrs[NFC_ATTR_LLC_PARAM_MIUX]) {
miux = nla_get_u16(info->attrs[NFC_ATTR_LLC_PARAM_MIUX]);

if (miux > LLCP_MAX_MIUX)
return -EINVAL;
}

idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]);

dev = nfc_get_device(idx);
if (!dev)
return -ENODEV;

device_lock(&dev->dev);

local = nfc_llcp_find_local(dev);
if (!local) {
nfc_put_device(dev);
rc = -ENODEV;
goto exit;
}

if (info->attrs[NFC_ATTR_LLC_PARAM_LTO]) {
if (dev->dep_link_up) {
rc = -EINPROGRESS;
goto exit;
}

local->lto = nla_get_u8(info->attrs[NFC_ATTR_LLC_PARAM_LTO]);
}

if (info->attrs[NFC_ATTR_LLC_PARAM_RW])
local->rw = rw;

if (info->attrs[NFC_ATTR_LLC_PARAM_MIUX])
local->miux = cpu_to_be16(miux);

exit:
device_unlock(&dev->dev);

nfc_put_device(dev);

return rc;
}

static struct genl_ops nfc_genl_ops[] = {
{
.cmd = NFC_CMD_GET_DEVICE,
Expand Down Expand Up @@ -760,6 +902,16 @@ static struct genl_ops nfc_genl_ops[] = {
.done = nfc_genl_dump_targets_done,
.policy = nfc_genl_policy,
},
{
.cmd = NFC_CMD_LLC_GET_PARAMS,
.doit = nfc_genl_llc_get_params,
.policy = nfc_genl_policy,
},
{
.cmd = NFC_CMD_LLC_SET_PARAMS,
.doit = nfc_genl_llc_set_params,
.policy = nfc_genl_policy,
},
};


Expand Down
6 changes: 6 additions & 0 deletions net/nfc/nfc.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ void nfc_llcp_unregister_device(struct nfc_dev *dev);
int nfc_llcp_set_remote_gb(struct nfc_dev *dev, u8 *gb, u8 gb_len);
u8 *nfc_llcp_general_bytes(struct nfc_dev *dev, size_t *general_bytes_len);
int nfc_llcp_data_received(struct nfc_dev *dev, struct sk_buff *skb);
struct nfc_llcp_local *nfc_llcp_find_local(struct nfc_dev *dev);
int __init nfc_llcp_init(void);
void nfc_llcp_exit(void);

Expand Down Expand Up @@ -97,6 +98,11 @@ static inline int nfc_llcp_data_received(struct nfc_dev *dev,
return 0;
}

static inline struct nfc_llcp_local *nfc_llcp_find_local(struct nfc_dev *dev)
{
return NULL;
}

static inline int nfc_llcp_init(void)
{
return 0;
Expand Down

0 comments on commit 52feb44

Please sign in to comment.