Commit e298c79e authored by John W. Linville's avatar John W. Linville

Merge tag 'nfc-next-3.8-1' of git://git.kernel.org/pub/scm/linux/kernel/git/sameo/nfc-3.0

This is the first NFC pull request for 3.8

With this one we have:

- pn544 p2p support.
- pn544 physical and HCI layers separation. We are getting the pn544 driver
  ready to support non i2c physical layers.
- LLCP SNL (Service Name Lookup). This is the NFC p2p service discovery
  protocol.
- LLCP datagram sockets (connection less) support.
- IDR library usage for NFC devices indexes assignement.
- NFC netlink extension for setting and getting LLCP link characteristics.
- Various code style fixes and cleanups spread over the pn533, LLCP, HCI and
  pn544 code.
parents d1f10302 52feb444
......@@ -2,7 +2,7 @@
# Makefile for nfc devices
#
obj-$(CONFIG_PN544_HCI_NFC) += pn544_hci.o
obj-$(CONFIG_PN544_HCI_NFC) += pn544/
obj-$(CONFIG_NFC_PN533) += pn533.o
obj-$(CONFIG_NFC_WILINK) += nfcwilink.o
......
......@@ -84,6 +84,10 @@ MODULE_DEVICE_TABLE(usb, pn533_table);
#define PN533_LISTEN_TIME 2
/* frame definitions */
#define PN533_NORMAL_FRAME_MAX_LEN 262 /* 6 (PREAMBLE, SOF, LEN, LCS, TFI)
254 (DATA)
2 (DCS, postamble) */
#define PN533_FRAME_TAIL_SIZE 2
#define PN533_FRAME_SIZE(f) (sizeof(struct pn533_frame) + f->datalen + \
PN533_FRAME_TAIL_SIZE)
......@@ -1165,8 +1169,7 @@ static void pn533_poll_create_mod_list(struct pn533 *dev,
pn533_poll_add_mod(dev, PN533_LISTEN_MOD);
}
static int pn533_start_poll_complete(struct pn533 *dev, void *arg,
u8 *params, int params_len)
static int pn533_start_poll_complete(struct pn533 *dev, u8 *params, int params_len)
{
struct pn533_poll_response *resp;
int rc;
......@@ -1304,8 +1307,7 @@ static void pn533_wq_tg_get_data(struct work_struct *work)
}
#define ATR_REQ_GB_OFFSET 17
static int pn533_init_target_complete(struct pn533 *dev, void *arg,
u8 *params, int params_len)
static int pn533_init_target_complete(struct pn533 *dev, u8 *params, int params_len)
{
struct pn533_cmd_init_target_response *resp;
u8 frame, comm_mode = NFC_COMM_PASSIVE, *gb;
......@@ -1402,9 +1404,9 @@ static int pn533_poll_complete(struct pn533 *dev, void *arg,
if (cur_mod->len == 0) {
del_timer(&dev->listen_timer);
return pn533_init_target_complete(dev, arg, params, params_len);
return pn533_init_target_complete(dev, params, params_len);
} else {
rc = pn533_start_poll_complete(dev, arg, params, params_len);
rc = pn533_start_poll_complete(dev, params, params_len);
if (!rc)
return rc;
}
......@@ -2373,9 +2375,9 @@ static int pn533_probe(struct usb_interface *interface,
goto error;
}
dev->in_frame = kmalloc(dev->in_maxlen, GFP_KERNEL);
dev->in_frame = kmalloc(PN533_NORMAL_FRAME_MAX_LEN, GFP_KERNEL);
dev->in_urb = usb_alloc_urb(0, GFP_KERNEL);
dev->out_frame = kmalloc(dev->out_maxlen, GFP_KERNEL);
dev->out_frame = kmalloc(PN533_NORMAL_FRAME_MAX_LEN, GFP_KERNEL);
dev->out_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!dev->in_frame || !dev->out_frame ||
......
#
# Makefile for PN544 HCI based NFC driver
#
obj-$(CONFIG_PN544_HCI_NFC) += pn544_i2c.o
pn544_i2c-y := pn544.o i2c.o
This diff is collapsed.
/*
* Copyright (C) 2011 - 2012 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef __LOCAL_PN544_H_
#define __LOCAL_PN544_H_
#include <net/nfc/hci.h>
#define DRIVER_DESC "HCI NFC driver for PN544"
int pn544_hci_probe(void *phy_id, struct nfc_phy_ops *phy_ops, char *llc_name,
int phy_headroom, int phy_tailroom, int phy_payload,
struct nfc_hci_dev **hdev);
void pn544_hci_remove(struct nfc_hci_dev *hdev);
#endif /* __LOCAL_PN544_H_ */
......@@ -24,6 +24,12 @@
#include <net/nfc/nfc.h>
struct nfc_phy_ops {
int (*write)(void *dev_id, struct sk_buff *skb);
int (*enable)(void *dev_id);
void (*disable)(void *dev_id);
};
struct nfc_hci_dev;
struct nfc_hci_ops {
......@@ -38,15 +44,21 @@ struct nfc_hci_ops {
int (*xmit) (struct nfc_hci_dev *hdev, struct sk_buff *skb);
int (*start_poll) (struct nfc_hci_dev *hdev,
u32 im_protocols, u32 tm_protocols);
int (*dep_link_up)(struct nfc_hci_dev *hdev, struct nfc_target *target,
u8 comm_mode, u8 *gb, size_t gb_len);
int (*dep_link_down)(struct nfc_hci_dev *hdev);
int (*target_from_gate) (struct nfc_hci_dev *hdev, u8 gate,
struct nfc_target *target);
int (*complete_target_discovered) (struct nfc_hci_dev *hdev, u8 gate,
struct nfc_target *target);
int (*data_exchange) (struct nfc_hci_dev *hdev,
int (*im_transceive) (struct nfc_hci_dev *hdev,
struct nfc_target *target, struct sk_buff *skb,
data_exchange_cb_t cb, void *cb_context);
int (*tm_send)(struct nfc_hci_dev *hdev, struct sk_buff *skb);
int (*check_presence)(struct nfc_hci_dev *hdev,
struct nfc_target *target);
void (*event_received)(struct nfc_hci_dev *hdev, u8 gate, u8 event,
struct sk_buff *skb);
};
/* Pipes */
......@@ -114,6 +126,9 @@ struct nfc_hci_dev {
int async_cb_type;
data_exchange_cb_t async_cb;
void *async_cb_context;
u8 *gb;
size_t gb_len;
};
/* hci device allocation */
......@@ -219,5 +234,6 @@ int nfc_hci_send_response(struct nfc_hci_dev *hdev, u8 gate, u8 response,
const u8 *param, size_t param_len);
int nfc_hci_send_event(struct nfc_hci_dev *hdev, u8 gate, u8 event,
const u8 *param, size_t param_len);
int nfc_hci_target_discovered(struct nfc_hci_dev *hdev, u8 gate);
#endif /* __NET_HCI_H */
......@@ -95,7 +95,7 @@ struct nfc_genl_data {
};
struct nfc_dev {
unsigned int idx;
int idx;
u32 target_next_idx;
struct nfc_target *targets;
int n_targets;
......
......@@ -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,
......@@ -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
};
......@@ -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,
......@@ -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
};
......
......@@ -3,8 +3,8 @@
#
menuconfig NFC
depends on NET && EXPERIMENTAL
tristate "NFC subsystem support (EXPERIMENTAL)"
depends on NET
tristate "NFC subsystem support"
default n
help
Say Y here if you want to build support for NFC (Near field
......
......@@ -40,6 +40,9 @@
int nfc_devlist_generation;
DEFINE_MUTEX(nfc_devlist_mutex);
/* NFC device ID bitmap */
static DEFINE_IDA(nfc_index_ida);
/**
* nfc_dev_up - turn on the NFC device
*
......@@ -181,6 +184,7 @@ int nfc_stop_poll(struct nfc_dev *dev)
dev->ops->stop_poll(dev);
dev->polling = false;
dev->rf_mode = NFC_RF_NONE;
error:
device_unlock(&dev->dev);
......@@ -194,7 +198,7 @@ static struct nfc_target *nfc_find_target(struct nfc_dev *dev, u32 target_idx)
if (dev->n_targets == 0)
return NULL;
for (i = 0; i < dev->n_targets ; i++) {
for (i = 0; i < dev->n_targets; i++) {
if (dev->targets[i].idx == target_idx)
return &dev->targets[i];
}
......@@ -274,12 +278,14 @@ int nfc_dep_link_down(struct nfc_dev *dev)
if (!rc) {
dev->dep_link_up = false;
dev->active_target = NULL;
dev->rf_mode = NFC_RF_NONE;
nfc_llcp_mac_is_down(dev);
nfc_genl_dep_link_down_event(dev);
}
error:
device_unlock(&dev->dev);
return rc;
}
......@@ -503,6 +509,7 @@ EXPORT_SYMBOL(nfc_tm_activated);
int nfc_tm_deactivated(struct nfc_dev *dev)
{
dev->dep_link_up = false;
dev->rf_mode = NFC_RF_NONE;
return nfc_genl_tm_deactivated(dev);
}
......@@ -697,6 +704,8 @@ static void nfc_check_pres_work(struct work_struct *work)
if (dev->active_target && timer_pending(&dev->check_pres_timer) == 0) {
rc = dev->ops->check_presence(dev, dev->active_target);
if (rc == -EOPNOTSUPP)
goto exit;
if (!rc) {
mod_timer(&dev->check_pres_timer, jiffies +
msecs_to_jiffies(NFC_CHECK_PRES_FREQ_MS));
......@@ -708,6 +717,7 @@ static void nfc_check_pres_work(struct work_struct *work)
}
}
exit:
device_unlock(&dev->dev);
}
......@@ -753,7 +763,6 @@ struct nfc_dev *nfc_allocate_device(struct nfc_ops *ops,
u32 supported_protocols,
int tx_headroom, int tx_tailroom)
{
static atomic_t dev_no = ATOMIC_INIT(0);
struct nfc_dev *dev;
if (!ops->start_poll || !ops->stop_poll || !ops->activate_target ||
......@@ -767,11 +776,6 @@ struct nfc_dev *nfc_allocate_device(struct nfc_ops *ops,
if (!dev)
return NULL;
dev->dev.class = &nfc_class;
dev->idx = atomic_inc_return(&dev_no) - 1;
dev_set_name(&dev->dev, "nfc%d", dev->idx);
device_initialize(&dev->dev);
dev->ops = ops;
dev->supported_protocols = supported_protocols;
dev->tx_headroom = tx_headroom;
......@@ -779,6 +783,7 @@ struct nfc_dev *nfc_allocate_device(struct nfc_ops *ops,
nfc_genl_data_init(&dev->genl_data);
dev->rf_mode = NFC_RF_NONE;
/* first generation must not be 0 */
dev->targets_generation = 1;
......@@ -806,6 +811,14 @@ int nfc_register_device(struct nfc_dev *dev)
pr_debug("dev_name=%s\n", dev_name(&dev->dev));
dev->idx = ida_simple_get(&nfc_index_ida, 0, 0, GFP_KERNEL);
if (dev->idx < 0)
return dev->idx;
dev->dev.class = &nfc_class;
dev_set_name(&dev->dev, "nfc%d", dev->idx);
device_initialize(&dev->dev);
mutex_lock(&nfc_devlist_mutex);
nfc_devlist_generation++;
rc = device_add(&dev->dev);
......@@ -834,10 +847,12 @@ EXPORT_SYMBOL(nfc_register_device);
*/
void nfc_unregister_device(struct nfc_dev *dev)
{
int rc;
int rc, id;
pr_debug("dev_name=%s\n", dev_name(&dev->dev));
id = dev->idx;
mutex_lock(&nfc_devlist_mutex);
nfc_devlist_generation++;
......@@ -856,6 +871,8 @@ void nfc_unregister_device(struct nfc_dev *dev)
pr_debug("The userspace won't be notified that the device %s was removed\n",
dev_name(&dev->dev));
ida_simple_remove(&nfc_index_ida, id);
}
EXPORT_SYMBOL(nfc_unregister_device);
......
......@@ -257,16 +257,16 @@ static u8 nfc_hci_create_pipe(struct nfc_hci_dev *hdev, u8 dest_host,
*result = nfc_hci_execute_cmd(hdev, NFC_HCI_ADMIN_PIPE,
NFC_HCI_ADM_CREATE_PIPE,
(u8 *) &params, sizeof(params), &skb);
if (*result == 0) {
resp = (struct hci_create_pipe_resp *)skb->data;
pipe = resp->pipe;
kfree_skb(skb);
if (*result < 0)
return NFC_HCI_INVALID_PIPE;
pr_debug("pipe created=%d\n", pipe);
resp = (struct hci_create_pipe_resp *)skb->data;
pipe = resp->pipe;
kfree_skb(skb);
return pipe;
} else
return NFC_HCI_INVALID_PIPE;
pr_debug("pipe created=%d\n", pipe);
return pipe;
}
static int nfc_hci_delete_pipe(struct nfc_hci_dev *hdev, u8 pipe)
......@@ -279,8 +279,6 @@ static int nfc_hci_delete_pipe(struct nfc_hci_dev *hdev, u8 pipe)
static int nfc_hci_clear_all_pipes(struct nfc_hci_dev *hdev)
{
int r;
u8 param[2];
/* TODO: Find out what the identity reference data is
......@@ -288,10 +286,8 @@ static int nfc_hci_clear_all_pipes(struct nfc_hci_dev *hdev)
pr_debug("\n");
r = nfc_hci_execute_cmd(hdev, NFC_HCI_ADMIN_PIPE,
NFC_HCI_ADM_CLEAR_ALL_PIPE, param, 2, NULL);
return 0;
return nfc_hci_execute_cmd(hdev, NFC_HCI_ADMIN_PIPE,
NFC_HCI_ADM_CLEAR_ALL_PIPE, param, 2, NULL);
}
int nfc_hci_disconnect_gate(struct nfc_hci_dev *hdev, u8 gate)
......
......@@ -65,8 +65,9 @@ static void nfc_hci_msg_tx_work(struct work_struct *work)
-ETIME);
kfree(hdev->cmd_pending_msg);
hdev->cmd_pending_msg = NULL;
} else
} else {
goto exit;
}
}
next_msg:
......@@ -182,7 +183,7 @@ static u32 nfc_hci_sak_to_protocol(u8 sak)
}
}
static int nfc_hci_target_discovered(struct nfc_hci_dev *hdev, u8 gate)
int nfc_hci_target_discovered(struct nfc_hci_dev *hdev, u8 gate)
{
struct nfc_target *targets;
struct sk_buff *atqa_skb = NULL;
......@@ -263,7 +264,9 @@ static int nfc_hci_target_discovered(struct nfc_hci_dev *hdev, u8 gate)
break;
}
targets->hci_reader_gate = gate;
/* if driver set the new gate, we will skip the old one */
if (targets->hci_reader_gate == 0x00)
targets->hci_reader_gate = gate;
r = nfc_targets_found(hdev->ndev, targets, 1);
......@@ -275,6 +278,7 @@ static int nfc_hci_target_discovered(struct nfc_hci_dev *hdev, u8 gate)
return r;
}
EXPORT_SYMBOL(nfc_hci_target_discovered);
void nfc_hci_event_received(struct nfc_hci_dev *hdev, u8 pipe, u8 event,
struct sk_buff *skb)
......@@ -307,8 +311,13 @@ void nfc_hci_event_received(struct nfc_hci_dev *hdev, u8 pipe, u8 event,
nfc_hci_pipe2gate(hdev, pipe));
break;
default:
/* TODO: Unknown events are hardware specific
* pass them to the driver (needs a new hci_ops) */
if (hdev->ops->event_received) {
hdev->ops->event_received(hdev,
nfc_hci_pipe2gate(hdev, pipe),
event, skb);
return;
}
break;
}
......@@ -527,7 +536,8 @@ static int hci_start_poll(struct nfc_dev *nfc_dev,
return hdev->ops->start_poll(hdev, im_protocols, tm_protocols);
else
return nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE,
NFC_HCI_EVT_READER_REQUESTED, NULL, 0);
NFC_HCI_EVT_READER_REQUESTED,
NULL, 0);
}
static void hci_stop_poll(struct nfc_dev *nfc_dev)
......@@ -538,6 +548,28 @@ static void hci_stop_poll(struct nfc_dev *nfc_dev)
NFC_HCI_EVT_END_OPERATION, NULL, 0);
}
static int hci_dep_link_up(struct nfc_dev *nfc_dev, struct nfc_target *target,
__u8 comm_mode, __u8 *gb, size_t gb_len)
{
struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev);
if (hdev->ops->dep_link_up)
return hdev->ops->dep_link_up(hdev, target, comm_mode,
gb, gb_len);
return 0;
}
static int hci_dep_link_down(struct nfc_dev *nfc_dev)
{
struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev);
if (hdev->ops->dep_link_down)
return hdev->ops->dep_link_down(hdev);
return 0;
}
static int hci_activate_target(struct nfc_dev *nfc_dev,
struct nfc_target *target, u32 protocol)
{
......@@ -586,8 +618,8 @@ static int hci_transceive(struct nfc_dev *nfc_dev, struct nfc_target *target,
switch (target->hci_reader_gate) {
case NFC_HCI_RF_READER_A_GATE:
case NFC_HCI_RF_READER_B_GATE:
if (hdev->ops->data_exchange) {
r = hdev->ops->data_exchange(hdev, target, skb, cb,
if (hdev->ops->im_transceive) {
r = hdev->ops->im_transceive(hdev, target, skb, cb,
cb_context);
if (r <= 0) /* handled */
break;
......@@ -604,14 +636,14 @@ static int hci_transceive(struct nfc_dev *nfc_dev, struct nfc_target *target,
skb->len, hci_transceive_cb, hdev);
break;
default:
if (hdev->ops->data_exchange) {
r = hdev->ops->data_exchange(hdev, target, skb, cb,
if (hdev->ops->im_transceive) {
r = hdev->ops->im_transceive(hdev, target, skb, cb,
cb_context);
if (r == 1)
r = -ENOTSUPP;
}
else
} else {
r = -ENOTSUPP;
}
break;
}
......@@ -620,6 +652,16 @@ static int hci_transceive(struct nfc_dev *nfc_dev, struct nfc_target *target,
return r;
}
static int hci_tm_send(struct nfc_dev *nfc_dev, struct sk_buff *skb)
{
struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev);
if (hdev->ops->tm_send)
return hdev->ops->tm_send(hdev, skb);
else
return -ENOTSUPP;
}
static int hci_check_presence(struct nfc_dev *nfc_dev,
struct nfc_target *target)
{
......@@ -723,9 +765,12 @@ static struct nfc_ops hci_nfc_ops = {
.dev_down = hci_dev_down,
.start_poll = hci_start_poll,
.stop_poll = hci_stop_poll,
.dep_link_up = hci_dep_link_up,
.dep_link_down = hci_dep_link_down,
.activate_target = hci_activate_target,
.deactivate_target = hci_deactivate_target,
.im_transceive = hci_transceive,
.tm_send = hci_tm_send,
.check_presence = hci_check_presence,
};
......@@ -848,7 +893,7 @@ void nfc_hci_driver_failure(struct nfc_hci_dev *hdev, int err)
}
EXPORT_SYMBOL(nfc_hci_driver_failure);
void inline nfc_hci_recv_frame(struct nfc_hci_dev *hdev, struct sk_buff *skb)
void nfc_hci_recv_frame(struct nfc_hci_dev *hdev, struct sk_buff *skb)
{
nfc_llc_rcv_from_drv(hdev->llc, skb);
}
......
......@@ -72,7 +72,7 @@ int nfc_llc_register(const char *name, struct nfc_llc_ops *ops)
llc_engine->ops = ops;
INIT_LIST_HEAD(&llc_engine->entry);
list_add_tail (&llc_engine->entry, &llc_engines);
list_add_tail(&llc_engine->entry, &llc_engines);
return 0;
}
......
......@@ -634,9 +634,9 @@ static void llc_shdlc_sm_work(struct work_struct *work)
r = llc_shdlc_connect_initiate(shdlc);
else
r = -ETIME;
if (r < 0)
if (r < 0) {
llc_shdlc_connect_complete(shdlc, r);
else {
} else {
mod_timer(&shdlc->connect_timer, jiffies +
msecs_to_jiffies(SHDLC_CONNECT_VALUE_MS));
......@@ -682,9 +682,8 @@ static void llc_shdlc_sm_work(struct work_struct *work)
llc_shdlc_handle_send_queue(shdlc);
}
if (shdlc->hard_fault) {
if (shdlc->hard_fault)
shdlc->llc_failure(shdlc->hdev, shdlc->hard_fault);
}
break;
default:
break;
......
config NFC_LLCP
depends on NFC && EXPERIMENTAL
bool "NFC LLCP support (EXPERIMENTAL)"
depends on NFC
bool "NFC LLCP support"
default n
help
Say Y here if you want to build support for a kernel NFC LLCP
......
......@@ -261,7 +261,6 @@ int nfc_llcp_disconnect(struct nfc_llcp_sock *sock)
struct sk_buff *skb;
struct nfc_dev *dev;
struct nfc_llcp_local *local;
u16 size = 0;
pr_debug("Sending DISC\n");
......@@ -273,17 +272,10 @@ int nfc_llcp_disconnect(struct nfc_llcp_sock *sock)
if (dev == NULL)
return -ENODEV;
size += LLCP_HEADER_SIZE;
size += dev->tx_headroom + dev->tx_tailroom + NFC_HEADER_SIZE;
skb = alloc_skb(size, GFP_ATOMIC);
skb = llcp_allocate_pdu(sock, LLCP_PDU_DISC, 0);
if (skb == NULL)
return -ENOMEM;
skb_reserve(skb, dev->tx_headroom + NFC_HEADER_SIZE);
skb = llcp_add_header(skb, sock->dsap, sock->ssap, LLCP_PDU_DISC);
skb_queue_tail(&local->tx_queue, skb);
return 0;
......@@ -324,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;
......@@ -343,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);
......@@ -386,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;
......@@ -397,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);
......@@ -428,6 +414,52 @@ int nfc_llcp_send_cc(struct nfc_llcp_sock *sock)
return err;
}
int nfc_llcp_send_snl(struct nfc_llcp_local *local, u8 tid, u8 sap)
{
struct sk_buff *skb;
struct nfc_dev *dev;
u8 *sdres_tlv = NULL, sdres_tlv_length, sdres[2];
u16 size = 0;
pr_debug("Sending SNL tid 0x%x sap 0x%x\n", tid, sap);
if (local == NULL)
return -ENODEV;
dev = local->dev;
if (dev == NULL)
return -ENODEV;
sdres[0] = tid;
sdres[1] = sap;
sdres_tlv = nfc_llcp_build_tlv(LLCP_TLV_SDRES, sdres, 0,
&sdres_tlv_length);
if (sdres_tlv == NULL)
return -ENOMEM;
size += LLCP_HEADER_SIZE;
size += dev->tx_headroom + dev->tx_tailroom + NFC_HEADER_SIZE;
size += sdres_tlv_length;
skb = alloc_skb(size, GFP_KERNEL);
if (skb == NULL) {
kfree(sdres_tlv);
return -ENOMEM;
}
skb_reserve(skb, dev->tx_headroom + NFC_HEADER_SIZE);
skb = llcp_add_header(skb, LLCP_SAP_SDP, LLCP_SAP_SDP, LLCP_PDU_SNL);
memcpy(skb_put(skb, sdres_tlv_length), sdres_tlv, sdres_tlv_length);
skb_queue_tail(&local->tx_queue, skb);
kfree(sdres_tlv);
return 0;
}
int nfc_llcp_send_dm(struct nfc_llcp_local *local, u8 ssap, u8 dsap, u8 reason)
{
struct sk_buff *skb;
......@@ -541,6 +573,52 @@ int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock,
return len;
}
int nfc_llcp_send_ui_frame(struct nfc_llcp_sock *sock, u8 ssap, u8 dsap,
struct msghdr *msg, size_t len)
{
struct sk_buff *pdu;
struct nfc_llcp_local *local;
size_t frag_len = 0, remaining_len;
u8 *msg_ptr;
int err;
pr_debug("Send UI frame len %zd\n", len);
local = sock->local;
if (local == NULL)
return -ENODEV;
remaining_len = len;
msg_ptr = (u8 *) msg->msg_iov;
while (remaining_len > 0) {
frag_len = min_t(size_t, sock->miu, remaining_len);
pr_debug("Fragment %zd bytes remaining %zd",
frag_len, remaining_len);
pdu = nfc_alloc_send_skb(sock->dev, &sock->sk, MSG_DONTWAIT,
frag_len + LLCP_HEADER_SIZE, &err);
if (pdu == NULL) {
pr_err("Could not allocate PDU\n");
continue;
}
pdu = llcp_add_header(pdu, dsap, ssap, LLCP_PDU_UI);
memcpy(skb_put(pdu, frag_len), msg_ptr, frag_len);
/* No need to check for the peer RW for UI frames */
skb_queue_tail(&local->tx_queue, pdu);
remaining_len -= frag_len;
msg_ptr += frag_len;
}
return len;
}
int nfc_llcp_send_rr(struct nfc_llcp_sock *sock)
{
struct sk_buff *skb;
......
This diff is collapsed.
......@@ -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 */
......@@ -124,6 +127,13 @@ struct nfc_llcp_sock {
struct sock *parent;
};
struct nfc_llcp_ui_cb {
__u8 dsap;
__u8 ssap;
};
#define nfc_llcp_ui_skb_cb(__skb) ((struct nfc_llcp_ui_cb *)&((__skb)->cb[0]))
#define nfc_llcp_sock(sk) ((struct nfc_llcp_sock *) (sk))
#define nfc_llcp_dev(sk) (nfc_llcp_sock((sk))->dev)
......@@ -209,10 +219,13 @@ int nfc_llcp_disconnect(struct nfc_llcp_sock *sock);
int nfc_llcp_send_symm(struct nfc_dev *dev);
int nfc_llcp_send_connect(struct nfc_llcp_sock *sock);
int nfc_llcp_send_cc(struct nfc_llcp_sock *sock);
int nfc_llcp_send_snl(struct nfc_llcp_local *local, u8 tid, u8 sap);
int nfc_llcp_send_dm(struct nfc_llcp_local *local, u8 ssap, u8 dsap, u8 reason);
int nfc_llcp_send_disconnect(struct nfc_llcp_sock *sock);
int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock,
struct msghdr *msg, size_t len);
int nfc_llcp_send_ui_frame(struct nfc_llcp_sock *sock, u8 ssap, u8 dsap,
struct msghdr *msg, size_t len);
int nfc_llcp_send_rr(struct nfc_llcp_sock *sock);
/* Socket API */
......
......@@ -205,8 +205,8 @@ static int llcp_sock_listen(struct socket *sock, int backlog)
lock_sock(sk);
if ((sock->type != SOCK_SEQPACKET && sock->type != SOCK_STREAM)
|| sk->sk_state != LLCP_BOUND) {
if ((sock->type != SOCK_SEQPACKET && sock->type != SOCK_STREAM) ||
sk->sk_state != LLCP_BOUND) {
ret = -EBADFD;
goto error;
}
......@@ -608,6 +608,25 @@ static int llcp_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
lock_sock(sk);
if (sk->sk_type == SOCK_DGRAM) {
struct sockaddr_nfc_llcp *addr =
(struct sockaddr_nfc_llcp *)msg->msg_name;
if (msg->msg_namelen < sizeof(*addr)) {
release_sock(sk);
pr_err("Invalid socket address length %d\n",
msg->msg_namelen);
return -EINVAL;
}
release_sock(sk);
return nfc_llcp_send_ui_frame(llcp_sock, addr->dsap, addr->ssap,
msg, len);
}
if (sk->sk_state != LLCP_CONNECTED) {
release_sock(sk);
return -ENOTCONN;
......@@ -663,11 +682,28 @@ static int llcp_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
return -EFAULT;
}
if (sk->sk_type == SOCK_DGRAM && msg->msg_name) {
struct nfc_llcp_ui_cb *ui_cb = nfc_llcp_ui_skb_cb(skb);
struct sockaddr_nfc_llcp sockaddr;
pr_debug("Datagram socket %d %d\n", ui_cb->dsap, ui_cb->ssap);
sockaddr.sa_family = AF_NFC;
sockaddr.nfc_protocol = NFC_PROTO_NFC_DEP;
sockaddr.dsap = ui_cb->dsap;
sockaddr.ssap = ui_cb->ssap;
memcpy(msg->msg_name, &sockaddr, sizeof(sockaddr));
msg->msg_namelen = sizeof(sockaddr);
}
/* Mark read part of skb as used */
if (!(flags & MSG_PEEK)) {
/* SOCK_STREAM: re-queue skb if it contains unreceived data */
if (sk->sk_type == SOCK_STREAM || sk->sk_type == SOCK_RAW) {
if (sk->sk_type == SOCK_STREAM ||
sk->sk_type == SOCK_DGRAM ||
sk->sk_type == SOCK_RAW) {
skb_pull(skb, copied);
if (skb->len) {
skb_queue_head(&sk->sk_receive_queue, skb);
......
config NFC_NCI
depends on NFC && EXPERIMENTAL
tristate "NCI protocol support (EXPERIMENTAL)"
depends on NFC
tristate "NCI protocol support"
default n
help
NCI (NFC Controller Interface) is a communication protocol between
......
......@@ -205,10 +205,10 @@ static void nci_rf_discover_req(struct nci_dev *ndev, unsigned long opt)
cmd.num_disc_configs = 0;
if ((cmd.num_disc_configs < NCI_MAX_NUM_RF_CONFIGS) &&
(protocols & NFC_PROTO_JEWEL_MASK
|| protocols & NFC_PROTO_MIFARE_MASK
|| protocols & NFC_PROTO_ISO14443_MASK
|| protocols & NFC_PROTO_NFC_DEP_MASK)) {
(protocols & NFC_PROTO_JEWEL_MASK ||
protocols & NFC_PROTO_MIFARE_MASK ||
protocols & NFC_PROTO_ISO14443_MASK ||
protocols & NFC_PROTO_NFC_DEP_MASK)) {
cmd.disc_configs[cmd.num_disc_configs].rf_tech_and_mode =
NCI_NFC_A_PASSIVE_POLL_MODE;
cmd.disc_configs[cmd.num_disc_configs].frequency = 1;
......@@ -224,8 +224,8 @@ static void nci_rf_discover_req(struct nci_dev *ndev, unsigned long opt)
}
if ((cmd.num_disc_configs < NCI_MAX_NUM_RF_CONFIGS) &&
(protocols & NFC_PROTO_FELICA_MASK
|| protocols & NFC_PROTO_NFC_DEP_MASK)) {
(protocols & NFC_PROTO_FELICA_MASK ||
protocols & NFC_PROTO_NFC_DEP_MASK)) {
cmd.disc_configs[cmd.num_disc_configs].rf_tech_and_mode =
NCI_NFC_F_PASSIVE_POLL_MODE;
cmd.disc_configs[cmd.num_disc_configs].frequency = 1;
......@@ -414,13 +414,13 @@ static int nci_set_local_general_bytes(struct nfc_dev *nfc_dev)
struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
struct nci_set_config_param param;
__u8 local_gb[NFC_MAX_GT_LEN];
int i, rc = 0;
int i;
param.val = nfc_get_local_general_bytes(nfc_dev, &param.len);
if ((param.val == NULL) || (param.len == 0))
return rc;
return 0;
if (param.len > NCI_MAX_PARAM_LEN)
if (param.len > NFC_MAX_GT_LEN)
return -EINVAL;
for (i = 0; i < param.len; i++)
......@@ -429,10 +429,8 @@ static int nci_set_local_general_bytes(struct nfc_dev *nfc_dev)
param.id = NCI_PN_ATR_REQ_GEN_BYTES;
param.val = local_gb;
rc = nci_request(ndev, nci_set_config_req, (unsigned long)&param,
msecs_to_jiffies(NCI_SET_CONFIG_TIMEOUT));
return rc;
return nci_request(ndev, nci_set_config_req, (unsigned long)&param,
msecs_to_jiffies(NCI_SET_CONFIG_TIMEOUT));
}
static int nci_start_poll(struct nfc_dev *nfc_dev,
......@@ -579,7 +577,6 @@ static void nci_deactivate_target(struct nfc_dev *nfc_dev,
}
}
static int nci_dep_link_up(struct nfc_dev *nfc_dev, struct nfc_target *target,
__u8 comm_mode, __u8 *gb, size_t gb_len)
{
......@@ -806,8 +803,8 @@ int nci_recv_frame(struct sk_buff *skb)
pr_debug("len %d\n", skb->len);
if (!ndev || (!test_bit(NCI_UP, &ndev->flags)
&& !test_bit(NCI_INIT, &ndev->flags))) {
if (!ndev || (!test_bit(NCI_UP, &ndev->flags) &&
!test_bit(NCI_INIT, &ndev->flags))) {
kfree_skb(skb);
return -ENXIO;
}
......
......@@ -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,
};
......@@ -364,7 +366,8 @@ static int nfc_genl_send_device(struct sk_buff *msg, struct nfc_dev *dev,
if (nla_put_string(msg, NFC_ATTR_DEVICE_NAME, nfc_device_name(dev)) ||
nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx) ||
nla_put_u32(msg, NFC_ATTR_PROTOCOLS, dev->supported_protocols) ||
nla_put_u8(msg, NFC_ATTR_DEVICE_POWERED, dev->dev_up))
nla_put_u8(msg, NFC_ATTR_DEVICE_POWERED, dev->dev_up) ||
nla_put_u8(msg, NFC_ATTR_RF_MODE, dev->rf_mode))
goto nla_put_failure;
return genlmsg_end(msg, hdr);
......@@ -590,7 +593,7 @@ static int nfc_genl_start_poll(struct sk_buff *skb, struct genl_info *info)
if (!info->attrs[NFC_ATTR_DEVICE_INDEX] ||
((!info->attrs[NFC_ATTR_IM_PROTOCOLS] &&
!info->attrs[NFC_ATTR_PROTOCOLS]) &&
!info->attrs[NFC_ATTR_TM_PROTOCOLS]))
!info->attrs[NFC_ATTR_TM_PROTOCOLS]))
return -EINVAL;
idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]);
......@@ -715,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,
......@@ -759,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,
},
};
......
......@@ -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);
......@@ -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;
......
......@@ -256,7 +256,6 @@ static int rawsock_recvmsg(struct kiocb *iocb, struct socket *sock,
return rc ? : copied;
}
static const struct proto_ops rawsock_ops = {
.family = PF_NFC,
.owner = THIS_MODULE,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment