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 @@ ...@@ -2,7 +2,7 @@
# Makefile for nfc devices # 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_PN533) += pn533.o
obj-$(CONFIG_NFC_WILINK) += nfcwilink.o obj-$(CONFIG_NFC_WILINK) += nfcwilink.o
......
...@@ -84,6 +84,10 @@ MODULE_DEVICE_TABLE(usb, pn533_table); ...@@ -84,6 +84,10 @@ MODULE_DEVICE_TABLE(usb, pn533_table);
#define PN533_LISTEN_TIME 2 #define PN533_LISTEN_TIME 2
/* frame definitions */ /* 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_TAIL_SIZE 2
#define PN533_FRAME_SIZE(f) (sizeof(struct pn533_frame) + f->datalen + \ #define PN533_FRAME_SIZE(f) (sizeof(struct pn533_frame) + f->datalen + \
PN533_FRAME_TAIL_SIZE) PN533_FRAME_TAIL_SIZE)
...@@ -1165,8 +1169,7 @@ static void pn533_poll_create_mod_list(struct pn533 *dev, ...@@ -1165,8 +1169,7 @@ static void pn533_poll_create_mod_list(struct pn533 *dev,
pn533_poll_add_mod(dev, PN533_LISTEN_MOD); pn533_poll_add_mod(dev, PN533_LISTEN_MOD);
} }
static int pn533_start_poll_complete(struct pn533 *dev, void *arg, static int pn533_start_poll_complete(struct pn533 *dev, u8 *params, int params_len)
u8 *params, int params_len)
{ {
struct pn533_poll_response *resp; struct pn533_poll_response *resp;
int rc; int rc;
...@@ -1304,8 +1307,7 @@ static void pn533_wq_tg_get_data(struct work_struct *work) ...@@ -1304,8 +1307,7 @@ static void pn533_wq_tg_get_data(struct work_struct *work)
} }
#define ATR_REQ_GB_OFFSET 17 #define ATR_REQ_GB_OFFSET 17
static int pn533_init_target_complete(struct pn533 *dev, void *arg, static int pn533_init_target_complete(struct pn533 *dev, u8 *params, int params_len)
u8 *params, int params_len)
{ {
struct pn533_cmd_init_target_response *resp; struct pn533_cmd_init_target_response *resp;
u8 frame, comm_mode = NFC_COMM_PASSIVE, *gb; u8 frame, comm_mode = NFC_COMM_PASSIVE, *gb;
...@@ -1402,9 +1404,9 @@ static int pn533_poll_complete(struct pn533 *dev, void *arg, ...@@ -1402,9 +1404,9 @@ static int pn533_poll_complete(struct pn533 *dev, void *arg,
if (cur_mod->len == 0) { if (cur_mod->len == 0) {
del_timer(&dev->listen_timer); 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 { } else {
rc = pn533_start_poll_complete(dev, arg, params, params_len); rc = pn533_start_poll_complete(dev, params, params_len);
if (!rc) if (!rc)
return rc; return rc;
} }
...@@ -2373,9 +2375,9 @@ static int pn533_probe(struct usb_interface *interface, ...@@ -2373,9 +2375,9 @@ static int pn533_probe(struct usb_interface *interface,
goto error; 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->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); dev->out_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!dev->in_frame || !dev->out_frame || 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 @@ ...@@ -24,6 +24,12 @@
#include <net/nfc/nfc.h> #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_dev;
struct nfc_hci_ops { struct nfc_hci_ops {
...@@ -38,15 +44,21 @@ struct nfc_hci_ops { ...@@ -38,15 +44,21 @@ struct nfc_hci_ops {
int (*xmit) (struct nfc_hci_dev *hdev, struct sk_buff *skb); int (*xmit) (struct nfc_hci_dev *hdev, struct sk_buff *skb);
int (*start_poll) (struct nfc_hci_dev *hdev, int (*start_poll) (struct nfc_hci_dev *hdev,
u32 im_protocols, u32 tm_protocols); 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, int (*target_from_gate) (struct nfc_hci_dev *hdev, u8 gate,
struct nfc_target *target); struct nfc_target *target);
int (*complete_target_discovered) (struct nfc_hci_dev *hdev, u8 gate, int (*complete_target_discovered) (struct nfc_hci_dev *hdev, u8 gate,
struct nfc_target *target); 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, struct nfc_target *target, struct sk_buff *skb,
data_exchange_cb_t cb, void *cb_context); 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, int (*check_presence)(struct nfc_hci_dev *hdev,
struct nfc_target *target); struct nfc_target *target);
void (*event_received)(struct nfc_hci_dev *hdev, u8 gate, u8 event,
struct sk_buff *skb);
}; };
/* Pipes */ /* Pipes */
...@@ -114,6 +126,9 @@ struct nfc_hci_dev { ...@@ -114,6 +126,9 @@ struct nfc_hci_dev {
int async_cb_type; int async_cb_type;
data_exchange_cb_t async_cb; data_exchange_cb_t async_cb;
void *async_cb_context; void *async_cb_context;
u8 *gb;
size_t gb_len;
}; };
/* hci device allocation */ /* hci device allocation */
...@@ -219,5 +234,6 @@ int nfc_hci_send_response(struct nfc_hci_dev *hdev, u8 gate, u8 response, ...@@ -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); const u8 *param, size_t param_len);
int nfc_hci_send_event(struct nfc_hci_dev *hdev, u8 gate, u8 event, int nfc_hci_send_event(struct nfc_hci_dev *hdev, u8 gate, u8 event,
const u8 *param, size_t param_len); const u8 *param, size_t param_len);
int nfc_hci_target_discovered(struct nfc_hci_dev *hdev, u8 gate);
#endif /* __NET_HCI_H */ #endif /* __NET_HCI_H */
...@@ -95,7 +95,7 @@ struct nfc_genl_data { ...@@ -95,7 +95,7 @@ struct nfc_genl_data {
}; };
struct nfc_dev { struct nfc_dev {
unsigned int idx; int idx;
u32 target_next_idx; u32 target_next_idx;
struct nfc_target *targets; struct nfc_target *targets;
int n_targets; int n_targets;
......
...@@ -60,6 +60,13 @@ ...@@ -60,6 +60,13 @@
* target mode. * target mode.
* @NFC_EVENT_DEVICE_DEACTIVATED: event emitted when the adapter is deactivated * @NFC_EVENT_DEVICE_DEACTIVATED: event emitted when the adapter is deactivated
* from target mode. * 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 { enum nfc_commands {
NFC_CMD_UNSPEC, NFC_CMD_UNSPEC,
...@@ -77,6 +84,8 @@ enum nfc_commands { ...@@ -77,6 +84,8 @@ enum nfc_commands {
NFC_EVENT_TARGET_LOST, NFC_EVENT_TARGET_LOST,
NFC_EVENT_TM_ACTIVATED, NFC_EVENT_TM_ACTIVATED,
NFC_EVENT_TM_DEACTIVATED, NFC_EVENT_TM_DEACTIVATED,
NFC_CMD_LLC_GET_PARAMS,
NFC_CMD_LLC_SET_PARAMS,
/* private: internal use only */ /* private: internal use only */
__NFC_CMD_AFTER_LAST __NFC_CMD_AFTER_LAST
}; };
...@@ -102,6 +111,9 @@ enum nfc_commands { ...@@ -102,6 +111,9 @@ enum nfc_commands {
* @NFC_ATTR_RF_MODE: Initiator or target * @NFC_ATTR_RF_MODE: Initiator or target
* @NFC_ATTR_IM_PROTOCOLS: Initiator mode protocols to poll for * @NFC_ATTR_IM_PROTOCOLS: Initiator mode protocols to poll for
* @NFC_ATTR_TM_PROTOCOLS: Target mode protocols to listen 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 { enum nfc_attrs {
NFC_ATTR_UNSPEC, NFC_ATTR_UNSPEC,
...@@ -119,6 +131,9 @@ enum nfc_attrs { ...@@ -119,6 +131,9 @@ enum nfc_attrs {
NFC_ATTR_DEVICE_POWERED, NFC_ATTR_DEVICE_POWERED,
NFC_ATTR_IM_PROTOCOLS, NFC_ATTR_IM_PROTOCOLS,
NFC_ATTR_TM_PROTOCOLS, NFC_ATTR_TM_PROTOCOLS,
NFC_ATTR_LLC_PARAM_LTO,
NFC_ATTR_LLC_PARAM_RW,
NFC_ATTR_LLC_PARAM_MIUX,
/* private: internal use only */ /* private: internal use only */
__NFC_ATTR_AFTER_LAST __NFC_ATTR_AFTER_LAST
}; };
......
...@@ -3,8 +3,8 @@ ...@@ -3,8 +3,8 @@
# #
menuconfig NFC menuconfig NFC
depends on NET && EXPERIMENTAL depends on NET
tristate "NFC subsystem support (EXPERIMENTAL)" tristate "NFC subsystem support"
default n default n
help help
Say Y here if you want to build support for NFC (Near field Say Y here if you want to build support for NFC (Near field
......
...@@ -40,6 +40,9 @@ ...@@ -40,6 +40,9 @@
int nfc_devlist_generation; int nfc_devlist_generation;
DEFINE_MUTEX(nfc_devlist_mutex); DEFINE_MUTEX(nfc_devlist_mutex);
/* NFC device ID bitmap */
static DEFINE_IDA(nfc_index_ida);
/** /**
* nfc_dev_up - turn on the NFC device * nfc_dev_up - turn on the NFC device
* *
...@@ -181,6 +184,7 @@ int nfc_stop_poll(struct nfc_dev *dev) ...@@ -181,6 +184,7 @@ int nfc_stop_poll(struct nfc_dev *dev)
dev->ops->stop_poll(dev); dev->ops->stop_poll(dev);
dev->polling = false; dev->polling = false;
dev->rf_mode = NFC_RF_NONE;
error: error:
device_unlock(&dev->dev); device_unlock(&dev->dev);
...@@ -194,7 +198,7 @@ static struct nfc_target *nfc_find_target(struct nfc_dev *dev, u32 target_idx) ...@@ -194,7 +198,7 @@ static struct nfc_target *nfc_find_target(struct nfc_dev *dev, u32 target_idx)
if (dev->n_targets == 0) if (dev->n_targets == 0)
return NULL; 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) if (dev->targets[i].idx == target_idx)
return &dev->targets[i]; return &dev->targets[i];
} }
...@@ -274,12 +278,14 @@ int nfc_dep_link_down(struct nfc_dev *dev) ...@@ -274,12 +278,14 @@ int nfc_dep_link_down(struct nfc_dev *dev)
if (!rc) { if (!rc) {
dev->dep_link_up = false; dev->dep_link_up = false;
dev->active_target = NULL; dev->active_target = NULL;
dev->rf_mode = NFC_RF_NONE;
nfc_llcp_mac_is_down(dev); nfc_llcp_mac_is_down(dev);
nfc_genl_dep_link_down_event(dev); nfc_genl_dep_link_down_event(dev);
} }
error: error:
device_unlock(&dev->dev); device_unlock(&dev->dev);
return rc; return rc;
} }
...@@ -503,6 +509,7 @@ EXPORT_SYMBOL(nfc_tm_activated); ...@@ -503,6 +509,7 @@ EXPORT_SYMBOL(nfc_tm_activated);
int nfc_tm_deactivated(struct nfc_dev *dev) int nfc_tm_deactivated(struct nfc_dev *dev)
{ {
dev->dep_link_up = false; dev->dep_link_up = false;
dev->rf_mode = NFC_RF_NONE;
return nfc_genl_tm_deactivated(dev); return nfc_genl_tm_deactivated(dev);
} }
...@@ -697,6 +704,8 @@ static void nfc_check_pres_work(struct work_struct *work) ...@@ -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) { if (dev->active_target && timer_pending(&dev->check_pres_timer) == 0) {
rc = dev->ops->check_presence(dev, dev->active_target); rc = dev->ops->check_presence(dev, dev->active_target);
if (rc == -EOPNOTSUPP)
goto exit;
if (!rc) { if (!rc) {
mod_timer(&dev->check_pres_timer, jiffies + mod_timer(&dev->check_pres_timer, jiffies +
msecs_to_jiffies(NFC_CHECK_PRES_FREQ_MS)); msecs_to_jiffies(NFC_CHECK_PRES_FREQ_MS));
...@@ -708,6 +717,7 @@ static void nfc_check_pres_work(struct work_struct *work) ...@@ -708,6 +717,7 @@ static void nfc_check_pres_work(struct work_struct *work)
} }
} }
exit:
device_unlock(&dev->dev); device_unlock(&dev->dev);
} }
...@@ -753,7 +763,6 @@ struct nfc_dev *nfc_allocate_device(struct nfc_ops *ops, ...@@ -753,7 +763,6 @@ struct nfc_dev *nfc_allocate_device(struct nfc_ops *ops,
u32 supported_protocols, u32 supported_protocols,
int tx_headroom, int tx_tailroom) int tx_headroom, int tx_tailroom)
{ {
static atomic_t dev_no = ATOMIC_INIT(0);
struct nfc_dev *dev; struct nfc_dev *dev;
if (!ops->start_poll || !ops->stop_poll || !ops->activate_target || if (!ops->start_poll || !ops->stop_poll || !ops->activate_target ||
...@@ -767,11 +776,6 @@ struct nfc_dev *nfc_allocate_device(struct nfc_ops *ops, ...@@ -767,11 +776,6 @@ struct nfc_dev *nfc_allocate_device(struct nfc_ops *ops,
if (!dev) if (!dev)
return NULL; 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->ops = ops;
dev->supported_protocols = supported_protocols; dev->supported_protocols = supported_protocols;
dev->tx_headroom = tx_headroom; dev->tx_headroom = tx_headroom;
...@@ -779,6 +783,7 @@ struct nfc_dev *nfc_allocate_device(struct nfc_ops *ops, ...@@ -779,6 +783,7 @@ struct nfc_dev *nfc_allocate_device(struct nfc_ops *ops,
nfc_genl_data_init(&dev->genl_data); nfc_genl_data_init(&dev->genl_data);
dev->rf_mode = NFC_RF_NONE;
/* first generation must not be 0 */ /* first generation must not be 0 */
dev->targets_generation = 1; dev->targets_generation = 1;
...@@ -806,6 +811,14 @@ int nfc_register_device(struct nfc_dev *dev) ...@@ -806,6 +811,14 @@ int nfc_register_device(struct nfc_dev *dev)
pr_debug("dev_name=%s\n", dev_name(&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); mutex_lock(&nfc_devlist_mutex);
nfc_devlist_generation++; nfc_devlist_generation++;
rc = device_add(&dev->dev); rc = device_add(&dev->dev);
...@@ -834,10 +847,12 @@ EXPORT_SYMBOL(nfc_register_device); ...@@ -834,10 +847,12 @@ EXPORT_SYMBOL(nfc_register_device);
*/ */
void nfc_unregister_device(struct nfc_dev *dev) void nfc_unregister_device(struct nfc_dev *dev)
{ {
int rc; int rc, id;
pr_debug("dev_name=%s\n", dev_name(&dev->dev)); pr_debug("dev_name=%s\n", dev_name(&dev->dev));
id = dev->idx;
mutex_lock(&nfc_devlist_mutex); mutex_lock(&nfc_devlist_mutex);
nfc_devlist_generation++; nfc_devlist_generation++;
...@@ -856,6 +871,8 @@ void nfc_unregister_device(struct nfc_dev *dev) ...@@ -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", pr_debug("The userspace won't be notified that the device %s was removed\n",
dev_name(&dev->dev)); dev_name(&dev->dev));
ida_simple_remove(&nfc_index_ida, id);
} }
EXPORT_SYMBOL(nfc_unregister_device); EXPORT_SYMBOL(nfc_unregister_device);
......
...@@ -257,7 +257,9 @@ static u8 nfc_hci_create_pipe(struct nfc_hci_dev *hdev, u8 dest_host, ...@@ -257,7 +257,9 @@ static u8 nfc_hci_create_pipe(struct nfc_hci_dev *hdev, u8 dest_host,
*result = nfc_hci_execute_cmd(hdev, NFC_HCI_ADMIN_PIPE, *result = nfc_hci_execute_cmd(hdev, NFC_HCI_ADMIN_PIPE,
NFC_HCI_ADM_CREATE_PIPE, NFC_HCI_ADM_CREATE_PIPE,
(u8 *) &params, sizeof(params), &skb); (u8 *) &params, sizeof(params), &skb);
if (*result == 0) { if (*result < 0)
return NFC_HCI_INVALID_PIPE;
resp = (struct hci_create_pipe_resp *)skb->data; resp = (struct hci_create_pipe_resp *)skb->data;
pipe = resp->pipe; pipe = resp->pipe;
kfree_skb(skb); kfree_skb(skb);
...@@ -265,8 +267,6 @@ static u8 nfc_hci_create_pipe(struct nfc_hci_dev *hdev, u8 dest_host, ...@@ -265,8 +267,6 @@ static u8 nfc_hci_create_pipe(struct nfc_hci_dev *hdev, u8 dest_host,
pr_debug("pipe created=%d\n", pipe); pr_debug("pipe created=%d\n", pipe);
return pipe; return pipe;
} else
return NFC_HCI_INVALID_PIPE;
} }
static int nfc_hci_delete_pipe(struct nfc_hci_dev *hdev, u8 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) ...@@ -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) static int nfc_hci_clear_all_pipes(struct nfc_hci_dev *hdev)
{ {
int r;
u8 param[2]; u8 param[2];
/* TODO: Find out what the identity reference data is /* 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) ...@@ -288,10 +286,8 @@ static int nfc_hci_clear_all_pipes(struct nfc_hci_dev *hdev)
pr_debug("\n"); pr_debug("\n");
r = nfc_hci_execute_cmd(hdev, NFC_HCI_ADMIN_PIPE, return nfc_hci_execute_cmd(hdev, NFC_HCI_ADMIN_PIPE,
NFC_HCI_ADM_CLEAR_ALL_PIPE, param, 2, NULL); NFC_HCI_ADM_CLEAR_ALL_PIPE, param, 2, NULL);
return 0;
} }
int nfc_hci_disconnect_gate(struct nfc_hci_dev *hdev, u8 gate) int nfc_hci_disconnect_gate(struct nfc_hci_dev *hdev, u8 gate)
......
...@@ -65,9 +65,10 @@ static void nfc_hci_msg_tx_work(struct work_struct *work) ...@@ -65,9 +65,10 @@ static void nfc_hci_msg_tx_work(struct work_struct *work)
-ETIME); -ETIME);
kfree(hdev->cmd_pending_msg); kfree(hdev->cmd_pending_msg);
hdev->cmd_pending_msg = NULL; hdev->cmd_pending_msg = NULL;
} else } else {
goto exit; goto exit;
} }
}
next_msg: next_msg:
if (list_empty(&hdev->msg_tx_queue)) if (list_empty(&hdev->msg_tx_queue))
...@@ -182,7 +183,7 @@ static u32 nfc_hci_sak_to_protocol(u8 sak) ...@@ -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 nfc_target *targets;
struct sk_buff *atqa_skb = NULL; struct sk_buff *atqa_skb = NULL;
...@@ -263,6 +264,8 @@ static int nfc_hci_target_discovered(struct nfc_hci_dev *hdev, u8 gate) ...@@ -263,6 +264,8 @@ static int nfc_hci_target_discovered(struct nfc_hci_dev *hdev, u8 gate)
break; break;
} }
/* if driver set the new gate, we will skip the old one */
if (targets->hci_reader_gate == 0x00)
targets->hci_reader_gate = gate; targets->hci_reader_gate = gate;
r = nfc_targets_found(hdev->ndev, targets, 1); 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) ...@@ -275,6 +278,7 @@ static int nfc_hci_target_discovered(struct nfc_hci_dev *hdev, u8 gate)
return r; return r;
} }
EXPORT_SYMBOL(nfc_hci_target_discovered);
void nfc_hci_event_received(struct nfc_hci_dev *hdev, u8 pipe, u8 event, void nfc_hci_event_received(struct nfc_hci_dev *hdev, u8 pipe, u8 event,
struct sk_buff *skb) struct sk_buff *skb)
...@@ -307,8 +311,13 @@ void nfc_hci_event_received(struct nfc_hci_dev *hdev, u8 pipe, u8 event, ...@@ -307,8 +311,13 @@ void nfc_hci_event_received(struct nfc_hci_dev *hdev, u8 pipe, u8 event,
nfc_hci_pipe2gate(hdev, pipe)); nfc_hci_pipe2gate(hdev, pipe));
break; break;
default: default:
/* TODO: Unknown events are hardware specific if (hdev->ops->event_received) {
* pass them to the driver (needs a new hci_ops) */ hdev->ops->event_received(hdev,
nfc_hci_pipe2gate(hdev, pipe),
event, skb);
return;
}
break; break;
} }
...@@ -527,7 +536,8 @@ static int hci_start_poll(struct nfc_dev *nfc_dev, ...@@ -527,7 +536,8 @@ static int hci_start_poll(struct nfc_dev *nfc_dev,
return hdev->ops->start_poll(hdev, im_protocols, tm_protocols); return hdev->ops->start_poll(hdev, im_protocols, tm_protocols);
else else
return nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE, 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) static void hci_stop_poll(struct nfc_dev *nfc_dev)
...@@ -538,6 +548,28 @@ 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); 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, static int hci_activate_target(struct nfc_dev *nfc_dev,
struct nfc_target *target, u32 protocol) struct nfc_target *target, u32 protocol)
{ {
...@@ -586,8 +618,8 @@ static int hci_transceive(struct nfc_dev *nfc_dev, struct nfc_target *target, ...@@ -586,8 +618,8 @@ static int hci_transceive(struct nfc_dev *nfc_dev, struct nfc_target *target,
switch (target->hci_reader_gate) { switch (target->hci_reader_gate) {
case NFC_HCI_RF_READER_A_GATE: case NFC_HCI_RF_READER_A_GATE:
case NFC_HCI_RF_READER_B_GATE: case NFC_HCI_RF_READER_B_GATE:
if (hdev->ops->data_exchange) { if (hdev->ops->im_transceive) {
r = hdev->ops->data_exchange(hdev, target, skb, cb, r = hdev->ops->im_transceive(hdev, target, skb, cb,
cb_context); cb_context);
if (r <= 0) /* handled */ if (r <= 0) /* handled */
break; break;
...@@ -604,14 +636,14 @@ static int hci_transceive(struct nfc_dev *nfc_dev, struct nfc_target *target, ...@@ -604,14 +636,14 @@ static int hci_transceive(struct nfc_dev *nfc_dev, struct nfc_target *target,
skb->len, hci_transceive_cb, hdev); skb->len, hci_transceive_cb, hdev);
break; break;
default: default:
if (hdev->ops->data_exchange) { if (hdev->ops->im_transceive) {
r = hdev->ops->data_exchange(hdev, target, skb, cb, r = hdev->ops->im_transceive(hdev, target, skb, cb,
cb_context); cb_context);
if (r == 1) if (r == 1)
r = -ENOTSUPP; r = -ENOTSUPP;
} } else {
else
r = -ENOTSUPP; r = -ENOTSUPP;
}
break; break;
} }
...@@ -620,6 +652,16 @@ static int hci_transceive(struct nfc_dev *nfc_dev, struct nfc_target *target, ...@@ -620,6 +652,16 @@ static int hci_transceive(struct nfc_dev *nfc_dev, struct nfc_target *target,
return r; 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, static int hci_check_presence(struct nfc_dev *nfc_dev,
struct nfc_target *target) struct nfc_target *target)
{ {
...@@ -723,9 +765,12 @@ static struct nfc_ops hci_nfc_ops = { ...@@ -723,9 +765,12 @@ static struct nfc_ops hci_nfc_ops = {
.dev_down = hci_dev_down, .dev_down = hci_dev_down,
.start_poll = hci_start_poll, .start_poll = hci_start_poll,
.stop_poll = hci_stop_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, .activate_target = hci_activate_target,
.deactivate_target = hci_deactivate_target, .deactivate_target = hci_deactivate_target,
.im_transceive = hci_transceive, .im_transceive = hci_transceive,
.tm_send = hci_tm_send,
.check_presence = hci_check_presence, .check_presence = hci_check_presence,
}; };
...@@ -848,7 +893,7 @@ void nfc_hci_driver_failure(struct nfc_hci_dev *hdev, int err) ...@@ -848,7 +893,7 @@ void nfc_hci_driver_failure(struct nfc_hci_dev *hdev, int err)
} }
EXPORT_SYMBOL(nfc_hci_driver_failure); 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); nfc_llc_rcv_from_drv(hdev->llc, skb);
} }
......
...@@ -72,7 +72,7 @@ int nfc_llc_register(const char *name, struct nfc_llc_ops *ops) ...@@ -72,7 +72,7 @@ int nfc_llc_register(const char *name, struct nfc_llc_ops *ops)
llc_engine->ops = ops; llc_engine->ops = ops;
INIT_LIST_HEAD(&llc_engine->entry); INIT_LIST_HEAD(&llc_engine->entry);
list_add_tail (&llc_engine->entry, &llc_engines); list_add_tail(&llc_engine->entry, &llc_engines);
return 0; return 0;
} }
......
...@@ -634,9 +634,9 @@ static void llc_shdlc_sm_work(struct work_struct *work) ...@@ -634,9 +634,9 @@ static void llc_shdlc_sm_work(struct work_struct *work)
r = llc_shdlc_connect_initiate(shdlc); r = llc_shdlc_connect_initiate(shdlc);
else else
r = -ETIME; r = -ETIME;
if (r < 0) if (r < 0) {
llc_shdlc_connect_complete(shdlc, r); llc_shdlc_connect_complete(shdlc, r);
else { } else {
mod_timer(&shdlc->connect_timer, jiffies + mod_timer(&shdlc->connect_timer, jiffies +
msecs_to_jiffies(SHDLC_CONNECT_VALUE_MS)); msecs_to_jiffies(SHDLC_CONNECT_VALUE_MS));
...@@ -682,9 +682,8 @@ static void llc_shdlc_sm_work(struct work_struct *work) ...@@ -682,9 +682,8 @@ static void llc_shdlc_sm_work(struct work_struct *work)
llc_shdlc_handle_send_queue(shdlc); llc_shdlc_handle_send_queue(shdlc);
} }
if (shdlc->hard_fault) { if (shdlc->hard_fault)
shdlc->llc_failure(shdlc->hdev, shdlc->hard_fault); shdlc->llc_failure(shdlc->hdev, shdlc->hard_fault);
}
break; break;
default: default:
break; break;
......
config NFC_LLCP config NFC_LLCP
depends on NFC && EXPERIMENTAL depends on NFC
bool "NFC LLCP support (EXPERIMENTAL)" bool "NFC LLCP support"
default n default n
help help
Say Y here if you want to build support for a kernel NFC LLCP 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) ...@@ -261,7 +261,6 @@ int nfc_llcp_disconnect(struct nfc_llcp_sock *sock)
struct sk_buff *skb; struct sk_buff *skb;
struct nfc_dev *dev; struct nfc_dev *dev;
struct nfc_llcp_local *local; struct nfc_llcp_local *local;
u16 size = 0;
pr_debug("Sending DISC\n"); pr_debug("Sending DISC\n");
...@@ -273,17 +272,10 @@ int nfc_llcp_disconnect(struct nfc_llcp_sock *sock) ...@@ -273,17 +272,10 @@ int nfc_llcp_disconnect(struct nfc_llcp_sock *sock)
if (dev == NULL) if (dev == NULL)
return -ENODEV; return -ENODEV;
size += LLCP_HEADER_SIZE; skb = llcp_allocate_pdu(sock, LLCP_PDU_DISC, 0);
size += dev->tx_headroom + dev->tx_tailroom + NFC_HEADER_SIZE;
skb = alloc_skb(size, GFP_ATOMIC);
if (skb == NULL) if (skb == NULL)
return -ENOMEM; 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); skb_queue_tail(&local->tx_queue, skb);
return 0; return 0;
...@@ -324,8 +316,7 @@ int nfc_llcp_send_connect(struct nfc_llcp_sock *sock) ...@@ -324,8 +316,7 @@ int nfc_llcp_send_connect(struct nfc_llcp_sock *sock)
struct sk_buff *skb; struct sk_buff *skb;
u8 *service_name_tlv = NULL, service_name_tlv_length; u8 *service_name_tlv = NULL, service_name_tlv_length;
u8 *miux_tlv = NULL, miux_tlv_length; u8 *miux_tlv = NULL, miux_tlv_length;
u8 *rw_tlv = NULL, rw_tlv_length, rw; u8 *rw_tlv = NULL, rw_tlv_length;
__be16 miux;
int err; int err;
u16 size = 0; u16 size = 0;
...@@ -343,13 +334,11 @@ int nfc_llcp_send_connect(struct nfc_llcp_sock *sock) ...@@ -343,13 +334,11 @@ int nfc_llcp_send_connect(struct nfc_llcp_sock *sock)
size += service_name_tlv_length; size += service_name_tlv_length;
} }
miux = cpu_to_be16(LLCP_MAX_MIUX); miux_tlv = nfc_llcp_build_tlv(LLCP_TLV_MIUX, (u8 *)&local->miux, 0,
miux_tlv = nfc_llcp_build_tlv(LLCP_TLV_MIUX, (u8 *)&miux, 0,
&miux_tlv_length); &miux_tlv_length);
size += miux_tlv_length; size += miux_tlv_length;
rw = LLCP_MAX_RW; rw_tlv = nfc_llcp_build_tlv(LLCP_TLV_RW, &local->rw, 0, &rw_tlv_length);
rw_tlv = nfc_llcp_build_tlv(LLCP_TLV_RW, &rw, 0, &rw_tlv_length);
size += rw_tlv_length; size += rw_tlv_length;
pr_debug("SKB size %d SN length %zu\n", size, sock->service_name_len); 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) ...@@ -386,8 +375,7 @@ int nfc_llcp_send_cc(struct nfc_llcp_sock *sock)
struct nfc_llcp_local *local; struct nfc_llcp_local *local;
struct sk_buff *skb; struct sk_buff *skb;
u8 *miux_tlv = NULL, miux_tlv_length; u8 *miux_tlv = NULL, miux_tlv_length;
u8 *rw_tlv = NULL, rw_tlv_length, rw; u8 *rw_tlv = NULL, rw_tlv_length;
__be16 miux;
int err; int err;
u16 size = 0; u16 size = 0;
...@@ -397,13 +385,11 @@ int nfc_llcp_send_cc(struct nfc_llcp_sock *sock) ...@@ -397,13 +385,11 @@ int nfc_llcp_send_cc(struct nfc_llcp_sock *sock)
if (local == NULL) if (local == NULL)
return -ENODEV; return -ENODEV;
miux = cpu_to_be16(LLCP_MAX_MIUX); miux_tlv = nfc_llcp_build_tlv(LLCP_TLV_MIUX, (u8 *)&local->miux, 0,
miux_tlv = nfc_llcp_build_tlv(LLCP_TLV_MIUX, (u8 *)&miux, 0,
&miux_tlv_length); &miux_tlv_length);
size += miux_tlv_length; size += miux_tlv_length;
rw = LLCP_MAX_RW; rw_tlv = nfc_llcp_build_tlv(LLCP_TLV_RW, &local->rw, 0, &rw_tlv_length);
rw_tlv = nfc_llcp_build_tlv(LLCP_TLV_RW, &rw, 0, &rw_tlv_length);
size += rw_tlv_length; size += rw_tlv_length;
skb = llcp_allocate_pdu(sock, LLCP_PDU_CC, size); skb = llcp_allocate_pdu(sock, LLCP_PDU_CC, size);
...@@ -428,6 +414,52 @@ int nfc_llcp_send_cc(struct nfc_llcp_sock *sock) ...@@ -428,6 +414,52 @@ int nfc_llcp_send_cc(struct nfc_llcp_sock *sock)
return err; 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) int nfc_llcp_send_dm(struct nfc_llcp_local *local, u8 ssap, u8 dsap, u8 reason)
{ {
struct sk_buff *skb; struct sk_buff *skb;
...@@ -541,6 +573,52 @@ int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock, ...@@ -541,6 +573,52 @@ int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock,
return len; 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) int nfc_llcp_send_rr(struct nfc_llcp_sock *sock)
{ {
struct sk_buff *skb; struct sk_buff *skb;
......
This diff is collapsed.
...@@ -64,6 +64,9 @@ struct nfc_llcp_local { ...@@ -64,6 +64,9 @@ struct nfc_llcp_local {
u32 target_idx; u32 target_idx;
u8 rf_mode; u8 rf_mode;
u8 comm_mode; u8 comm_mode;
u8 lto;
u8 rw;
__be16 miux;
unsigned long local_wks; /* Well known services */ unsigned long local_wks; /* Well known services */
unsigned long local_sdp; /* Local services */ unsigned long local_sdp; /* Local services */
unsigned long local_sap; /* Local SAPs, not available for discovery */ unsigned long local_sap; /* Local SAPs, not available for discovery */
...@@ -124,6 +127,13 @@ struct nfc_llcp_sock { ...@@ -124,6 +127,13 @@ struct nfc_llcp_sock {
struct sock *parent; 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_sock(sk) ((struct nfc_llcp_sock *) (sk))
#define nfc_llcp_dev(sk) (nfc_llcp_sock((sk))->dev) #define nfc_llcp_dev(sk) (nfc_llcp_sock((sk))->dev)
...@@ -209,10 +219,13 @@ int nfc_llcp_disconnect(struct nfc_llcp_sock *sock); ...@@ -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_symm(struct nfc_dev *dev);
int nfc_llcp_send_connect(struct nfc_llcp_sock *sock); int nfc_llcp_send_connect(struct nfc_llcp_sock *sock);
int nfc_llcp_send_cc(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_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_disconnect(struct nfc_llcp_sock *sock);
int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock, int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock,
struct msghdr *msg, size_t len); 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); int nfc_llcp_send_rr(struct nfc_llcp_sock *sock);
/* Socket API */ /* Socket API */
......
...@@ -205,8 +205,8 @@ static int llcp_sock_listen(struct socket *sock, int backlog) ...@@ -205,8 +205,8 @@ static int llcp_sock_listen(struct socket *sock, int backlog)
lock_sock(sk); lock_sock(sk);
if ((sock->type != SOCK_SEQPACKET && sock->type != SOCK_STREAM) if ((sock->type != SOCK_SEQPACKET && sock->type != SOCK_STREAM) ||
|| sk->sk_state != LLCP_BOUND) { sk->sk_state != LLCP_BOUND) {
ret = -EBADFD; ret = -EBADFD;
goto error; goto error;
} }
...@@ -608,6 +608,25 @@ static int llcp_sock_sendmsg(struct kiocb *iocb, struct socket *sock, ...@@ -608,6 +608,25 @@ static int llcp_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
lock_sock(sk); 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) { if (sk->sk_state != LLCP_CONNECTED) {
release_sock(sk); release_sock(sk);
return -ENOTCONN; return -ENOTCONN;
...@@ -663,11 +682,28 @@ static int llcp_sock_recvmsg(struct kiocb *iocb, struct socket *sock, ...@@ -663,11 +682,28 @@ static int llcp_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
return -EFAULT; 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 */ /* Mark read part of skb as used */
if (!(flags & MSG_PEEK)) { if (!(flags & MSG_PEEK)) {
/* SOCK_STREAM: re-queue skb if it contains unreceived data */ /* 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); skb_pull(skb, copied);
if (skb->len) { if (skb->len) {
skb_queue_head(&sk->sk_receive_queue, skb); skb_queue_head(&sk->sk_receive_queue, skb);
......
config NFC_NCI config NFC_NCI
depends on NFC && EXPERIMENTAL depends on NFC
tristate "NCI protocol support (EXPERIMENTAL)" tristate "NCI protocol support"
default n default n
help help
NCI (NFC Controller Interface) is a communication protocol between 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) ...@@ -205,10 +205,10 @@ static void nci_rf_discover_req(struct nci_dev *ndev, unsigned long opt)
cmd.num_disc_configs = 0; cmd.num_disc_configs = 0;
if ((cmd.num_disc_configs < NCI_MAX_NUM_RF_CONFIGS) && if ((cmd.num_disc_configs < NCI_MAX_NUM_RF_CONFIGS) &&
(protocols & NFC_PROTO_JEWEL_MASK (protocols & NFC_PROTO_JEWEL_MASK ||
|| protocols & NFC_PROTO_MIFARE_MASK protocols & NFC_PROTO_MIFARE_MASK ||
|| protocols & NFC_PROTO_ISO14443_MASK protocols & NFC_PROTO_ISO14443_MASK ||
|| protocols & NFC_PROTO_NFC_DEP_MASK)) { protocols & NFC_PROTO_NFC_DEP_MASK)) {
cmd.disc_configs[cmd.num_disc_configs].rf_tech_and_mode = cmd.disc_configs[cmd.num_disc_configs].rf_tech_and_mode =
NCI_NFC_A_PASSIVE_POLL_MODE; NCI_NFC_A_PASSIVE_POLL_MODE;
cmd.disc_configs[cmd.num_disc_configs].frequency = 1; 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) ...@@ -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) && if ((cmd.num_disc_configs < NCI_MAX_NUM_RF_CONFIGS) &&
(protocols & NFC_PROTO_FELICA_MASK (protocols & NFC_PROTO_FELICA_MASK ||
|| protocols & NFC_PROTO_NFC_DEP_MASK)) { protocols & NFC_PROTO_NFC_DEP_MASK)) {
cmd.disc_configs[cmd.num_disc_configs].rf_tech_and_mode = cmd.disc_configs[cmd.num_disc_configs].rf_tech_and_mode =
NCI_NFC_F_PASSIVE_POLL_MODE; NCI_NFC_F_PASSIVE_POLL_MODE;
cmd.disc_configs[cmd.num_disc_configs].frequency = 1; 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) ...@@ -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_dev *ndev = nfc_get_drvdata(nfc_dev);
struct nci_set_config_param param; struct nci_set_config_param param;
__u8 local_gb[NFC_MAX_GT_LEN]; __u8 local_gb[NFC_MAX_GT_LEN];
int i, rc = 0; int i;
param.val = nfc_get_local_general_bytes(nfc_dev, &param.len); param.val = nfc_get_local_general_bytes(nfc_dev, &param.len);
if ((param.val == NULL) || (param.len == 0)) 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; return -EINVAL;
for (i = 0; i < param.len; i++) for (i = 0; i < param.len; i++)
...@@ -429,10 +429,8 @@ static int nci_set_local_general_bytes(struct nfc_dev *nfc_dev) ...@@ -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.id = NCI_PN_ATR_REQ_GEN_BYTES;
param.val = local_gb; param.val = local_gb;
rc = nci_request(ndev, nci_set_config_req, (unsigned long)&param, return nci_request(ndev, nci_set_config_req, (unsigned long)&param,
msecs_to_jiffies(NCI_SET_CONFIG_TIMEOUT)); msecs_to_jiffies(NCI_SET_CONFIG_TIMEOUT));
return rc;
} }
static int nci_start_poll(struct nfc_dev *nfc_dev, static int nci_start_poll(struct nfc_dev *nfc_dev,
...@@ -579,7 +577,6 @@ static void nci_deactivate_target(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, static int nci_dep_link_up(struct nfc_dev *nfc_dev, struct nfc_target *target,
__u8 comm_mode, __u8 *gb, size_t gb_len) __u8 comm_mode, __u8 *gb, size_t gb_len)
{ {
...@@ -806,8 +803,8 @@ int nci_recv_frame(struct sk_buff *skb) ...@@ -806,8 +803,8 @@ int nci_recv_frame(struct sk_buff *skb)
pr_debug("len %d\n", skb->len); pr_debug("len %d\n", skb->len);
if (!ndev || (!test_bit(NCI_UP, &ndev->flags) if (!ndev || (!test_bit(NCI_UP, &ndev->flags) &&
&& !test_bit(NCI_INIT, &ndev->flags))) { !test_bit(NCI_INIT, &ndev->flags))) {
kfree_skb(skb); kfree_skb(skb);
return -ENXIO; return -ENXIO;
} }
......
...@@ -29,6 +29,8 @@ ...@@ -29,6 +29,8 @@
#include "nfc.h" #include "nfc.h"
#include "llcp/llcp.h"
static struct genl_multicast_group nfc_genl_event_mcgrp = { static struct genl_multicast_group nfc_genl_event_mcgrp = {
.name = NFC_GENL_MCAST_EVENT_NAME, .name = NFC_GENL_MCAST_EVENT_NAME,
}; };
...@@ -364,7 +366,8 @@ static int nfc_genl_send_device(struct sk_buff *msg, struct nfc_dev *dev, ...@@ -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)) || 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_DEVICE_INDEX, dev->idx) ||
nla_put_u32(msg, NFC_ATTR_PROTOCOLS, dev->supported_protocols) || 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; goto nla_put_failure;
return genlmsg_end(msg, hdr); return genlmsg_end(msg, hdr);
...@@ -715,6 +718,146 @@ static int nfc_genl_dep_link_down(struct sk_buff *skb, struct genl_info *info) ...@@ -715,6 +718,146 @@ static int nfc_genl_dep_link_down(struct sk_buff *skb, struct genl_info *info)
return rc; 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[] = { static struct genl_ops nfc_genl_ops[] = {
{ {
.cmd = NFC_CMD_GET_DEVICE, .cmd = NFC_CMD_GET_DEVICE,
...@@ -759,6 +902,16 @@ static struct genl_ops nfc_genl_ops[] = { ...@@ -759,6 +902,16 @@ static struct genl_ops nfc_genl_ops[] = {
.done = nfc_genl_dump_targets_done, .done = nfc_genl_dump_targets_done,
.policy = nfc_genl_policy, .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); ...@@ -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); 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); 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); 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); int __init nfc_llcp_init(void);
void nfc_llcp_exit(void); void nfc_llcp_exit(void);
...@@ -97,6 +98,11 @@ static inline int nfc_llcp_data_received(struct nfc_dev *dev, ...@@ -97,6 +98,11 @@ static inline int nfc_llcp_data_received(struct nfc_dev *dev,
return 0; 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) static inline int nfc_llcp_init(void)
{ {
return 0; return 0;
......
...@@ -256,7 +256,6 @@ static int rawsock_recvmsg(struct kiocb *iocb, struct socket *sock, ...@@ -256,7 +256,6 @@ static int rawsock_recvmsg(struct kiocb *iocb, struct socket *sock,
return rc ? : copied; return rc ? : copied;
} }
static const struct proto_ops rawsock_ops = { static const struct proto_ops rawsock_ops = {
.family = PF_NFC, .family = PF_NFC,
.owner = THIS_MODULE, .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