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

This commit is contained in:
John W. Linville 2012-06-11 14:46:04 -04:00
commit 2e48686835
16 changed files with 1119 additions and 405 deletions

View file

@ -45,6 +45,9 @@ static const struct usb_device_id pn533_table[] = {
};
MODULE_DEVICE_TABLE(usb, pn533_table);
/* How much time we spend listening for initiators */
#define PN533_LISTEN_TIME 2
/* frame definitions */
#define PN533_FRAME_TAIL_SIZE 2
#define PN533_FRAME_SIZE(f) (sizeof(struct pn533_frame) + f->datalen + \
@ -74,6 +77,10 @@ MODULE_DEVICE_TABLE(usb, pn533_table);
#define PN533_CMD_IN_RELEASE 0x52
#define PN533_CMD_IN_JUMP_FOR_DEP 0x56
#define PN533_CMD_TG_INIT_AS_TARGET 0x8c
#define PN533_CMD_TG_GET_DATA 0x86
#define PN533_CMD_TG_SET_DATA 0x8e
#define PN533_CMD_RESPONSE(cmd) (cmd + 1)
/* PN533 Return codes */
@ -81,6 +88,9 @@ MODULE_DEVICE_TABLE(usb, pn533_table);
#define PN533_CMD_MI_MASK 0x40
#define PN533_CMD_RET_SUCCESS 0x00
/* PN533 status codes */
#define PN533_STATUS_TARGET_RELEASED 0x29
struct pn533;
typedef int (*pn533_cmd_complete_t) (struct pn533 *dev, void *arg,
@ -97,8 +107,14 @@ struct pn533_fw_version {
};
/* PN533_CMD_RF_CONFIGURATION */
#define PN533_CFGITEM_TIMING 0x02
#define PN533_CFGITEM_MAX_RETRIES 0x05
#define PN533_CONFIG_TIMING_102 0xb
#define PN533_CONFIG_TIMING_204 0xc
#define PN533_CONFIG_TIMING_409 0xd
#define PN533_CONFIG_TIMING_819 0xe
#define PN533_CONFIG_MAX_RETRIES_NO_RETRY 0x00
#define PN533_CONFIG_MAX_RETRIES_ENDLESS 0xFF
@ -108,6 +124,12 @@ struct pn533_config_max_retries {
u8 mx_rty_passive_act;
} __packed;
struct pn533_config_timing {
u8 rfu;
u8 atr_res_timeout;
u8 dep_timeout;
} __packed;
/* PN533_CMD_IN_LIST_PASSIVE_TARGET */
/* felica commands opcode */
@ -144,6 +166,7 @@ enum {
PN533_POLL_MOD_424KBPS_FELICA,
PN533_POLL_MOD_106KBPS_JEWEL,
PN533_POLL_MOD_847KBPS_B,
PN533_LISTEN_MOD,
__PN533_POLL_MOD_AFTER_LAST,
};
@ -211,6 +234,9 @@ const struct pn533_poll_modulations poll_mod[] = {
},
.len = 3,
},
[PN533_LISTEN_MOD] = {
.len = 0,
},
};
/* PN533_CMD_IN_ATR */
@ -237,7 +263,7 @@ struct pn533_cmd_jump_dep {
u8 active;
u8 baud;
u8 next;
u8 gt[];
u8 data[];
} __packed;
struct pn533_cmd_jump_dep_response {
@ -253,6 +279,29 @@ struct pn533_cmd_jump_dep_response {
u8 gt[];
} __packed;
/* PN533_TG_INIT_AS_TARGET */
#define PN533_INIT_TARGET_PASSIVE 0x1
#define PN533_INIT_TARGET_DEP 0x2
#define PN533_INIT_TARGET_RESP_FRAME_MASK 0x3
#define PN533_INIT_TARGET_RESP_ACTIVE 0x1
#define PN533_INIT_TARGET_RESP_DEP 0x4
struct pn533_cmd_init_target {
u8 mode;
u8 mifare[6];
u8 felica[18];
u8 nfcid3[10];
u8 gb_len;
u8 gb[];
} __packed;
struct pn533_cmd_init_target_response {
u8 mode;
u8 cmd[];
} __packed;
struct pn533 {
struct usb_device *udev;
struct usb_interface *interface;
@ -270,22 +319,31 @@ struct pn533 {
struct workqueue_struct *wq;
struct work_struct cmd_work;
struct work_struct poll_work;
struct work_struct mi_work;
struct work_struct tg_work;
struct timer_list listen_timer;
struct pn533_frame *wq_in_frame;
int wq_in_error;
int cancel_listen;
pn533_cmd_complete_t cmd_complete;
void *cmd_complete_arg;
struct semaphore cmd_lock;
struct mutex cmd_lock;
u8 cmd;
struct pn533_poll_modulations *poll_mod_active[PN533_POLL_MOD_MAX + 1];
u8 poll_mod_count;
u8 poll_mod_curr;
u32 poll_protocols;
u32 listen_protocols;
u8 *gb;
size_t gb_len;
u8 tgt_available_prots;
u8 tgt_active_prot;
u8 tgt_mode;
};
struct pn533_frame {
@ -405,7 +463,7 @@ static void pn533_wq_cmd_complete(struct work_struct *work)
PN533_FRAME_CMD_PARAMS_LEN(in_frame));
if (rc != -EINPROGRESS)
up(&dev->cmd_lock);
mutex_unlock(&dev->cmd_lock);
}
static void pn533_recv_response(struct urb *urb)
@ -583,7 +641,7 @@ static int pn533_send_cmd_frame_async(struct pn533 *dev,
nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
if (down_trylock(&dev->cmd_lock))
if (!mutex_trylock(&dev->cmd_lock))
return -EBUSY;
rc = __pn533_send_cmd_frame_async(dev, out_frame, in_frame,
@ -593,7 +651,7 @@ static int pn533_send_cmd_frame_async(struct pn533 *dev,
return 0;
error:
up(&dev->cmd_lock);
mutex_unlock(&dev->cmd_lock);
return rc;
}
@ -963,6 +1021,11 @@ static int pn533_target_found(struct pn533 *dev,
return 0;
}
static inline void pn533_poll_next_mod(struct pn533 *dev)
{
dev->poll_mod_curr = (dev->poll_mod_curr + 1) % dev->poll_mod_count;
}
static void pn533_poll_reset_mod_list(struct pn533 *dev)
{
dev->poll_mod_count = 0;
@ -975,102 +1038,283 @@ static void pn533_poll_add_mod(struct pn533 *dev, u8 mod_index)
dev->poll_mod_count++;
}
static void pn533_poll_create_mod_list(struct pn533 *dev, u32 protocols)
static void pn533_poll_create_mod_list(struct pn533 *dev,
u32 im_protocols, u32 tm_protocols)
{
pn533_poll_reset_mod_list(dev);
if (protocols & NFC_PROTO_MIFARE_MASK
|| protocols & NFC_PROTO_ISO14443_MASK
|| protocols & NFC_PROTO_NFC_DEP_MASK)
if (im_protocols & NFC_PROTO_MIFARE_MASK
|| im_protocols & NFC_PROTO_ISO14443_MASK
|| im_protocols & NFC_PROTO_NFC_DEP_MASK)
pn533_poll_add_mod(dev, PN533_POLL_MOD_106KBPS_A);
if (protocols & NFC_PROTO_FELICA_MASK
|| protocols & NFC_PROTO_NFC_DEP_MASK) {
if (im_protocols & NFC_PROTO_FELICA_MASK
|| im_protocols & NFC_PROTO_NFC_DEP_MASK) {
pn533_poll_add_mod(dev, PN533_POLL_MOD_212KBPS_FELICA);
pn533_poll_add_mod(dev, PN533_POLL_MOD_424KBPS_FELICA);
}
if (protocols & NFC_PROTO_JEWEL_MASK)
if (im_protocols & NFC_PROTO_JEWEL_MASK)
pn533_poll_add_mod(dev, PN533_POLL_MOD_106KBPS_JEWEL);
if (protocols & NFC_PROTO_ISO14443_MASK)
if (im_protocols & NFC_PROTO_ISO14443_MASK)
pn533_poll_add_mod(dev, PN533_POLL_MOD_847KBPS_B);
}
static void pn533_start_poll_frame(struct pn533_frame *frame,
struct pn533_poll_modulations *mod)
{
pn533_tx_frame_init(frame, PN533_CMD_IN_LIST_PASSIVE_TARGET);
memcpy(PN533_FRAME_CMD_PARAMS_PTR(frame), &mod->data, mod->len);
frame->datalen += mod->len;
pn533_tx_frame_finish(frame);
if (tm_protocols)
pn533_poll_add_mod(dev, PN533_LISTEN_MOD);
}
static int pn533_start_poll_complete(struct pn533 *dev, void *arg,
u8 *params, int params_len)
u8 *params, int params_len)
{
struct pn533_poll_response *resp;
struct pn533_poll_modulations *next_mod;
int rc;
nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
if (params_len == -ENOENT) {
nfc_dev_dbg(&dev->interface->dev, "Polling operation has been"
" stopped");
goto stop_poll;
}
if (params_len < 0) {
nfc_dev_err(&dev->interface->dev, "Error %d when running poll",
params_len);
goto stop_poll;
}
resp = (struct pn533_poll_response *) params;
if (resp->nbtg) {
rc = pn533_target_found(dev, resp, params_len);
/* We must stop the poll after a valid target found */
if (rc == 0)
goto stop_poll;
if (rc != -EAGAIN)
nfc_dev_err(&dev->interface->dev, "The target found is"
" not valid - continuing to poll");
if (rc == 0) {
pn533_poll_reset_mod_list(dev);
return 0;
}
}
dev->poll_mod_curr = (dev->poll_mod_curr + 1) % dev->poll_mod_count;
return -EAGAIN;
}
next_mod = dev->poll_mod_active[dev->poll_mod_curr];
static int pn533_init_target_frame(struct pn533_frame *frame,
u8 *gb, size_t gb_len)
{
struct pn533_cmd_init_target *cmd;
size_t cmd_len;
u8 felica_params[18] = {0x1, 0xfe, /* DEP */
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, /* random */
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0xff, 0xff}; /* System code */
u8 mifare_params[6] = {0x1, 0x1, /* SENS_RES */
0x0, 0x0, 0x0,
0x40}; /* SEL_RES for DEP */
nfc_dev_dbg(&dev->interface->dev, "Polling next modulation (0x%x)",
dev->poll_mod_curr);
cmd_len = sizeof(struct pn533_cmd_init_target) + gb_len + 1;
cmd = kzalloc(cmd_len, GFP_KERNEL);
if (cmd == NULL)
return -ENOMEM;
pn533_start_poll_frame(dev->out_frame, next_mod);
pn533_tx_frame_init(frame, PN533_CMD_TG_INIT_AS_TARGET);
/* Don't need to down the semaphore again */
rc = __pn533_send_cmd_frame_async(dev, dev->out_frame, dev->in_frame,
dev->in_maxlen, pn533_start_poll_complete,
NULL, GFP_ATOMIC);
/* DEP support only */
cmd->mode |= PN533_INIT_TARGET_DEP;
/* Felica params */
memcpy(cmd->felica, felica_params, 18);
get_random_bytes(cmd->felica + 2, 6);
/* NFCID3 */
memset(cmd->nfcid3, 0, 10);
memcpy(cmd->nfcid3, cmd->felica, 8);
/* MIFARE params */
memcpy(cmd->mifare, mifare_params, 6);
/* General bytes */
cmd->gb_len = gb_len;
memcpy(cmd->gb, gb, gb_len);
/* Len Tk */
cmd->gb[gb_len] = 0;
memcpy(PN533_FRAME_CMD_PARAMS_PTR(frame), cmd, cmd_len);
frame->datalen += cmd_len;
pn533_tx_frame_finish(frame);
kfree(cmd);
return 0;
}
#define PN533_CMD_DATAEXCH_HEAD_LEN (sizeof(struct pn533_frame) + 3)
#define PN533_CMD_DATAEXCH_DATA_MAXLEN 262
static int pn533_tm_get_data_complete(struct pn533 *dev, void *arg,
u8 *params, int params_len)
{
struct sk_buff *skb_resp = arg;
struct pn533_frame *in_frame = (struct pn533_frame *) skb_resp->data;
nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
if (params_len < 0) {
nfc_dev_err(&dev->interface->dev,
"Error %d when starting as a target",
params_len);
return params_len;
}
if (params_len > 0 && params[0] != 0) {
nfc_tm_deactivated(dev->nfc_dev);
dev->tgt_mode = 0;
kfree_skb(skb_resp);
return 0;
}
skb_put(skb_resp, PN533_FRAME_SIZE(in_frame));
skb_pull(skb_resp, PN533_CMD_DATAEXCH_HEAD_LEN);
skb_trim(skb_resp, skb_resp->len - PN533_FRAME_TAIL_SIZE);
return nfc_tm_data_received(dev->nfc_dev, skb_resp);
}
static void pn533_wq_tg_get_data(struct work_struct *work)
{
struct pn533 *dev = container_of(work, struct pn533, tg_work);
struct pn533_frame *in_frame;
struct sk_buff *skb_resp;
size_t skb_resp_len;
nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
skb_resp_len = PN533_CMD_DATAEXCH_HEAD_LEN +
PN533_CMD_DATAEXCH_DATA_MAXLEN +
PN533_FRAME_TAIL_SIZE;
skb_resp = nfc_alloc_recv_skb(skb_resp_len, GFP_KERNEL);
if (!skb_resp)
return;
in_frame = (struct pn533_frame *)skb_resp->data;
pn533_tx_frame_init(dev->out_frame, PN533_CMD_TG_GET_DATA);
pn533_tx_frame_finish(dev->out_frame);
pn533_send_cmd_frame_async(dev, dev->out_frame, in_frame,
skb_resp_len,
pn533_tm_get_data_complete,
skb_resp, GFP_KERNEL);
return;
}
#define ATR_REQ_GB_OFFSET 17
static int pn533_init_target_complete(struct pn533 *dev, void *arg,
u8 *params, int params_len)
{
struct pn533_cmd_init_target_response *resp;
u8 frame, comm_mode = NFC_COMM_PASSIVE, *gb;
size_t gb_len;
int rc;
nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
if (params_len < 0) {
nfc_dev_err(&dev->interface->dev,
"Error %d when starting as a target",
params_len);
return params_len;
}
if (params_len < ATR_REQ_GB_OFFSET + 1)
return -EINVAL;
resp = (struct pn533_cmd_init_target_response *) params;
nfc_dev_dbg(&dev->interface->dev, "Target mode 0x%x param len %d\n",
resp->mode, params_len);
frame = resp->mode & PN533_INIT_TARGET_RESP_FRAME_MASK;
if (frame == PN533_INIT_TARGET_RESP_ACTIVE)
comm_mode = NFC_COMM_ACTIVE;
/* Again, only DEP */
if ((resp->mode & PN533_INIT_TARGET_RESP_DEP) == 0)
return -EOPNOTSUPP;
gb = resp->cmd + ATR_REQ_GB_OFFSET;
gb_len = params_len - (ATR_REQ_GB_OFFSET + 1);
rc = nfc_tm_activated(dev->nfc_dev, NFC_PROTO_NFC_DEP_MASK,
comm_mode, gb, gb_len);
if (rc < 0) {
nfc_dev_err(&dev->interface->dev,
"Error when signaling target activation");
return rc;
}
dev->tgt_mode = 1;
queue_work(dev->wq, &dev->tg_work);
return 0;
}
static void pn533_listen_mode_timer(unsigned long data)
{
struct pn533 *dev = (struct pn533 *) data;
nfc_dev_dbg(&dev->interface->dev, "Listen mode timeout");
/* An ack will cancel the last issued command (poll) */
pn533_send_ack(dev, GFP_ATOMIC);
dev->cancel_listen = 1;
mutex_unlock(&dev->cmd_lock);
pn533_poll_next_mod(dev);
queue_work(dev->wq, &dev->poll_work);
}
static int pn533_poll_complete(struct pn533 *dev, void *arg,
u8 *params, int params_len)
{
struct pn533_poll_modulations *cur_mod;
int rc;
nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
if (params_len == -ENOENT) {
if (dev->poll_mod_count != 0)
return 0;
nfc_dev_err(&dev->interface->dev,
"Polling operation has been stopped");
if (rc == -EPERM) {
nfc_dev_dbg(&dev->interface->dev, "Cannot poll next modulation"
" because poll has been stopped");
goto stop_poll;
}
if (rc) {
nfc_dev_err(&dev->interface->dev, "Error %d when trying to poll"
" next modulation", rc);
if (params_len < 0) {
nfc_dev_err(&dev->interface->dev,
"Error %d when running poll", params_len);
goto stop_poll;
}
/* Inform caller function to do not up the semaphore */
return -EINPROGRESS;
cur_mod = dev->poll_mod_active[dev->poll_mod_curr];
if (cur_mod->len == 0) {
del_timer(&dev->listen_timer);
return pn533_init_target_complete(dev, arg, params, params_len);
} else {
rc = pn533_start_poll_complete(dev, arg, params, params_len);
if (!rc)
return rc;
}
pn533_poll_next_mod(dev);
queue_work(dev->wq, &dev->poll_work);
return 0;
stop_poll:
pn533_poll_reset_mod_list(dev);
@ -1078,61 +1322,104 @@ stop_poll:
return 0;
}
static int pn533_start_poll(struct nfc_dev *nfc_dev, u32 protocols)
static void pn533_build_poll_frame(struct pn533 *dev,
struct pn533_frame *frame,
struct pn533_poll_modulations *mod)
{
struct pn533 *dev = nfc_get_drvdata(nfc_dev);
struct pn533_poll_modulations *start_mod;
nfc_dev_dbg(&dev->interface->dev, "mod len %d\n", mod->len);
if (mod->len == 0) {
/* Listen mode */
pn533_init_target_frame(frame, dev->gb, dev->gb_len);
} else {
/* Polling mode */
pn533_tx_frame_init(frame, PN533_CMD_IN_LIST_PASSIVE_TARGET);
memcpy(PN533_FRAME_CMD_PARAMS_PTR(frame), &mod->data, mod->len);
frame->datalen += mod->len;
pn533_tx_frame_finish(frame);
}
}
static int pn533_send_poll_frame(struct pn533 *dev)
{
struct pn533_poll_modulations *cur_mod;
int rc;
nfc_dev_dbg(&dev->interface->dev, "%s - protocols=0x%x", __func__,
protocols);
cur_mod = dev->poll_mod_active[dev->poll_mod_curr];
if (dev->poll_mod_count) {
nfc_dev_err(&dev->interface->dev, "Polling operation already"
" active");
return -EBUSY;
}
if (dev->tgt_active_prot) {
nfc_dev_err(&dev->interface->dev, "Cannot poll with a target"
" already activated");
return -EBUSY;
}
pn533_poll_create_mod_list(dev, protocols);
if (!dev->poll_mod_count) {
nfc_dev_err(&dev->interface->dev, "No valid protocols"
" specified");
rc = -EINVAL;
goto error;
}
nfc_dev_dbg(&dev->interface->dev, "It will poll %d modulations types",
dev->poll_mod_count);
dev->poll_mod_curr = 0;
start_mod = dev->poll_mod_active[dev->poll_mod_curr];
pn533_start_poll_frame(dev->out_frame, start_mod);
pn533_build_poll_frame(dev, dev->out_frame, cur_mod);
rc = pn533_send_cmd_frame_async(dev, dev->out_frame, dev->in_frame,
dev->in_maxlen, pn533_start_poll_complete,
dev->in_maxlen, pn533_poll_complete,
NULL, GFP_KERNEL);
if (rc)
nfc_dev_err(&dev->interface->dev, "Polling loop error %d", rc);
if (rc) {
nfc_dev_err(&dev->interface->dev, "Error %d when trying to"
" start poll", rc);
goto error;
return rc;
}
static void pn533_wq_poll(struct work_struct *work)
{
struct pn533 *dev = container_of(work, struct pn533, poll_work);
struct pn533_poll_modulations *cur_mod;
int rc;
cur_mod = dev->poll_mod_active[dev->poll_mod_curr];
nfc_dev_dbg(&dev->interface->dev,
"%s cancel_listen %d modulation len %d",
__func__, dev->cancel_listen, cur_mod->len);
if (dev->cancel_listen == 1) {
dev->cancel_listen = 0;
usb_kill_urb(dev->in_urb);
}
dev->poll_protocols = protocols;
rc = pn533_send_poll_frame(dev);
if (rc)
return;
return 0;
if (cur_mod->len == 0 && dev->poll_mod_count > 1)
mod_timer(&dev->listen_timer, jiffies + PN533_LISTEN_TIME * HZ);
error:
pn533_poll_reset_mod_list(dev);
return rc;
return;
}
static int pn533_start_poll(struct nfc_dev *nfc_dev,
u32 im_protocols, u32 tm_protocols)
{
struct pn533 *dev = nfc_get_drvdata(nfc_dev);
nfc_dev_dbg(&dev->interface->dev,
"%s: im protocols 0x%x tm protocols 0x%x",
__func__, im_protocols, tm_protocols);
if (dev->tgt_active_prot) {
nfc_dev_err(&dev->interface->dev,
"Cannot poll with a target already activated");
return -EBUSY;
}
if (dev->tgt_mode) {
nfc_dev_err(&dev->interface->dev,
"Cannot poll while already being activated");
return -EBUSY;
}
if (tm_protocols) {
dev->gb = nfc_get_local_general_bytes(nfc_dev, &dev->gb_len);
if (dev->gb == NULL)
tm_protocols = 0;
}
dev->poll_mod_curr = 0;
pn533_poll_create_mod_list(dev, im_protocols, tm_protocols);
dev->poll_protocols = im_protocols;
dev->listen_protocols = tm_protocols;
return pn533_send_poll_frame(dev);
}
static void pn533_stop_poll(struct nfc_dev *nfc_dev)
@ -1141,6 +1428,8 @@ static void pn533_stop_poll(struct nfc_dev *nfc_dev)
nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
del_timer(&dev->listen_timer);
if (!dev->poll_mod_count) {
nfc_dev_dbg(&dev->interface->dev, "Polling operation was not"
" running");
@ -1152,6 +1441,8 @@ static void pn533_stop_poll(struct nfc_dev *nfc_dev)
/* prevent pn533_start_poll_complete to issue a new poll meanwhile */
usb_kill_urb(dev->in_urb);
pn533_poll_reset_mod_list(dev);
}
static int pn533_activate_target_nfcdep(struct pn533 *dev)
@ -1349,13 +1640,29 @@ static int pn533_in_dep_link_up_complete(struct pn533 *dev, void *arg,
return 0;
}
static int pn533_mod_to_baud(struct pn533 *dev)
{
switch (dev->poll_mod_curr) {
case PN533_POLL_MOD_106KBPS_A:
return 0;
case PN533_POLL_MOD_212KBPS_FELICA:
return 1;
case PN533_POLL_MOD_424KBPS_FELICA:
return 2;
default:
return -EINVAL;
}
}
#define PASSIVE_DATA_LEN 5
static int pn533_dep_link_up(struct nfc_dev *nfc_dev, struct nfc_target *target,
u8 comm_mode, u8* gb, size_t gb_len)
{
struct pn533 *dev = nfc_get_drvdata(nfc_dev);
struct pn533_cmd_jump_dep *cmd;
u8 cmd_len;
int rc;
u8 cmd_len, *data_ptr;
u8 passive_data[PASSIVE_DATA_LEN] = {0x00, 0xff, 0xff, 0x00, 0x3};
int rc, baud;
nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
@ -1371,7 +1678,17 @@ static int pn533_dep_link_up(struct nfc_dev *nfc_dev, struct nfc_target *target,
return -EBUSY;
}
baud = pn533_mod_to_baud(dev);
if (baud < 0) {
nfc_dev_err(&dev->interface->dev,
"Invalid curr modulation %d", dev->poll_mod_curr);
return baud;
}
cmd_len = sizeof(struct pn533_cmd_jump_dep) + gb_len;
if (comm_mode == NFC_COMM_PASSIVE)
cmd_len += PASSIVE_DATA_LEN;
cmd = kzalloc(cmd_len, GFP_KERNEL);
if (cmd == NULL)
return -ENOMEM;
@ -1379,10 +1696,18 @@ static int pn533_dep_link_up(struct nfc_dev *nfc_dev, struct nfc_target *target,
pn533_tx_frame_init(dev->out_frame, PN533_CMD_IN_JUMP_FOR_DEP);
cmd->active = !comm_mode;
cmd->baud = 0;
cmd->next = 0;
cmd->baud = baud;
data_ptr = cmd->data;
if (comm_mode == NFC_COMM_PASSIVE && cmd->baud > 0) {
memcpy(data_ptr, passive_data, PASSIVE_DATA_LEN);
cmd->next |= 1;
data_ptr += PASSIVE_DATA_LEN;
}
if (gb != NULL && gb_len > 0) {
cmd->next = 4; /* We have some Gi */
memcpy(cmd->gt, gb, gb_len);
cmd->next |= 4; /* We have some Gi */
memcpy(data_ptr, gb, gb_len);
} else {
cmd->next = 0;
}
@ -1407,15 +1732,25 @@ out:
static int pn533_dep_link_down(struct nfc_dev *nfc_dev)
{
pn533_deactivate_target(nfc_dev, 0);
struct pn533 *dev = nfc_get_drvdata(nfc_dev);
pn533_poll_reset_mod_list(dev);
if (dev->tgt_mode || dev->tgt_active_prot) {
pn533_send_ack(dev, GFP_KERNEL);
usb_kill_urb(dev->in_urb);
}
dev->tgt_active_prot = 0;
dev->tgt_mode = 0;
skb_queue_purge(&dev->resp_q);
return 0;
}
#define PN533_CMD_DATAEXCH_HEAD_LEN (sizeof(struct pn533_frame) + 3)
#define PN533_CMD_DATAEXCH_DATA_MAXLEN 262
static int pn533_data_exchange_tx_frame(struct pn533 *dev, struct sk_buff *skb)
static int pn533_build_tx_frame(struct pn533 *dev, struct sk_buff *skb,
bool target)
{
int payload_len = skb->len;
struct pn533_frame *out_frame;
@ -1432,14 +1767,20 @@ static int pn533_data_exchange_tx_frame(struct pn533 *dev, struct sk_buff *skb)
return -ENOSYS;
}
skb_push(skb, PN533_CMD_DATAEXCH_HEAD_LEN);
out_frame = (struct pn533_frame *) skb->data;
if (target == true) {
skb_push(skb, PN533_CMD_DATAEXCH_HEAD_LEN);
out_frame = (struct pn533_frame *) skb->data;
pn533_tx_frame_init(out_frame, PN533_CMD_IN_DATA_EXCHANGE);
pn533_tx_frame_init(out_frame, PN533_CMD_IN_DATA_EXCHANGE);
tg = 1;
memcpy(PN533_FRAME_CMD_PARAMS_PTR(out_frame), &tg, sizeof(u8));
out_frame->datalen += sizeof(u8);
} else {
skb_push(skb, PN533_CMD_DATAEXCH_HEAD_LEN - 1);
out_frame = (struct pn533_frame *) skb->data;
pn533_tx_frame_init(out_frame, PN533_CMD_TG_SET_DATA);
}
tg = 1;
memcpy(PN533_FRAME_CMD_PARAMS_PTR(out_frame), &tg, sizeof(u8));
out_frame->datalen += sizeof(u8);
/* The data is already in the out_frame, just update the datalen */
out_frame->datalen += payload_len;
@ -1550,9 +1891,9 @@ error:
return 0;
}
static int pn533_data_exchange(struct nfc_dev *nfc_dev,
struct nfc_target *target, struct sk_buff *skb,
data_exchange_cb_t cb, void *cb_context)
static int pn533_transceive(struct nfc_dev *nfc_dev,
struct nfc_target *target, struct sk_buff *skb,
data_exchange_cb_t cb, void *cb_context)
{
struct pn533 *dev = nfc_get_drvdata(nfc_dev);
struct pn533_frame *out_frame, *in_frame;
@ -1570,7 +1911,7 @@ static int pn533_data_exchange(struct nfc_dev *nfc_dev,
goto error;
}
rc = pn533_data_exchange_tx_frame(dev, skb);
rc = pn533_build_tx_frame(dev, skb, true);
if (rc)
goto error;
@ -1618,6 +1959,63 @@ error:
return rc;
}
static int pn533_tm_send_complete(struct pn533 *dev, void *arg,
u8 *params, int params_len)
{
nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
if (params_len < 0) {
nfc_dev_err(&dev->interface->dev,
"Error %d when sending data",
params_len);
return params_len;
}
if (params_len > 0 && params[0] != 0) {
nfc_tm_deactivated(dev->nfc_dev);
dev->tgt_mode = 0;
return 0;
}
queue_work(dev->wq, &dev->tg_work);
return 0;
}
static int pn533_tm_send(struct nfc_dev *nfc_dev, struct sk_buff *skb)
{
struct pn533 *dev = nfc_get_drvdata(nfc_dev);
struct pn533_frame *out_frame;
int rc;
nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
rc = pn533_build_tx_frame(dev, skb, false);
if (rc)
goto error;
out_frame = (struct pn533_frame *) skb->data;
rc = pn533_send_cmd_frame_async(dev, out_frame, dev->in_frame,
dev->in_maxlen, pn533_tm_send_complete,
NULL, GFP_KERNEL);
if (rc) {
nfc_dev_err(&dev->interface->dev,
"Error %d when trying to send data", rc);
goto error;
}
return 0;
error:
kfree_skb(skb);
return rc;
}
static void pn533_wq_mi_recv(struct work_struct *work)
{
struct pn533 *dev = container_of(work, struct pn533, mi_work);
@ -1638,7 +2036,7 @@ static void pn533_wq_mi_recv(struct work_struct *work)
skb_reserve(skb_cmd, PN533_CMD_DATAEXCH_HEAD_LEN);
rc = pn533_data_exchange_tx_frame(dev, skb_cmd);
rc = pn533_build_tx_frame(dev, skb_cmd, true);
if (rc)
goto error_frame;
@ -1677,7 +2075,7 @@ error_cmd:
kfree(arg);
up(&dev->cmd_lock);
mutex_unlock(&dev->cmd_lock);
}
static int pn533_set_configuration(struct pn533 *dev, u8 cfgitem, u8 *cfgdata,
@ -1712,7 +2110,8 @@ struct nfc_ops pn533_nfc_ops = {
.stop_poll = pn533_stop_poll,
.activate_target = pn533_activate_target,
.deactivate_target = pn533_deactivate_target,
.data_exchange = pn533_data_exchange,
.im_transceive = pn533_transceive,
.tm_send = pn533_tm_send,
};
static int pn533_probe(struct usb_interface *interface,
@ -1723,6 +2122,7 @@ static int pn533_probe(struct usb_interface *interface,
struct usb_host_interface *iface_desc;
struct usb_endpoint_descriptor *endpoint;
struct pn533_config_max_retries max_retries;
struct pn533_config_timing timing;
int in_endpoint = 0;
int out_endpoint = 0;
int rc = -ENOMEM;
@ -1735,7 +2135,7 @@ static int pn533_probe(struct usb_interface *interface,
dev->udev = usb_get_dev(interface_to_usbdev(interface));
dev->interface = interface;
sema_init(&dev->cmd_lock, 1);
mutex_init(&dev->cmd_lock);
iface_desc = interface->cur_altsetting;
for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
@ -1779,12 +2179,18 @@ static int pn533_probe(struct usb_interface *interface,
INIT_WORK(&dev->cmd_work, pn533_wq_cmd_complete);
INIT_WORK(&dev->mi_work, pn533_wq_mi_recv);
INIT_WORK(&dev->tg_work, pn533_wq_tg_get_data);
INIT_WORK(&dev->poll_work, pn533_wq_poll);
dev->wq = alloc_workqueue("pn533",
WQ_NON_REENTRANT | WQ_UNBOUND | WQ_MEM_RECLAIM,
1);
if (dev->wq == NULL)
goto error;
init_timer(&dev->listen_timer);
dev->listen_timer.data = (unsigned long) dev;
dev->listen_timer.function = pn533_listen_mode_timer;
skb_queue_head_init(&dev->resp_q);
usb_set_intfdata(interface, dev);
@ -1830,13 +2236,29 @@ static int pn533_probe(struct usb_interface *interface,
if (rc) {
nfc_dev_err(&dev->interface->dev, "Error on setting MAX_RETRIES"
" config");
goto free_nfc_dev;
goto unregister_nfc_dev;
}
timing.rfu = PN533_CONFIG_TIMING_102;
timing.atr_res_timeout = PN533_CONFIG_TIMING_204;
timing.dep_timeout = PN533_CONFIG_TIMING_409;
rc = pn533_set_configuration(dev, PN533_CFGITEM_TIMING,
(u8 *) &timing, sizeof(timing));
if (rc) {
nfc_dev_err(&dev->interface->dev,
"Error on setting RF timings");
goto unregister_nfc_dev;
}
return 0;
unregister_nfc_dev:
nfc_unregister_device(dev->nfc_dev);
free_nfc_dev:
nfc_free_device(dev->nfc_dev);
destroy_wq:
destroy_workqueue(dev->wq);
error:
@ -1865,6 +2287,8 @@ static void pn533_disconnect(struct usb_interface *interface)
skb_queue_purge(&dev->resp_q);
del_timer(&dev->listen_timer);
kfree(dev->in_frame);
usb_free_urb(dev->in_urb);
kfree(dev->out_frame);

View file

@ -576,7 +576,8 @@ static int pn544_hci_xmit(struct nfc_shdlc *shdlc, struct sk_buff *skb)
return pn544_hci_i2c_write(client, skb->data, skb->len);
}
static int pn544_hci_start_poll(struct nfc_shdlc *shdlc, u32 protocols)
static int pn544_hci_start_poll(struct nfc_shdlc *shdlc,
u32 im_protocols, u32 tm_protocols)
{
struct nfc_hci_dev *hdev = nfc_shdlc_get_hci_dev(shdlc);
u8 phases = 0;
@ -584,7 +585,8 @@ static int pn544_hci_start_poll(struct nfc_shdlc *shdlc, u32 protocols)
u8 duration[2];
u8 activated;
pr_info(DRIVER_DESC ": %s protocols = %d\n", __func__, protocols);
pr_info(DRIVER_DESC ": %s protocols 0x%x 0x%x\n",
__func__, im_protocols, tm_protocols);
r = nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE,
NFC_HCI_EVT_END_OPERATION, NULL, 0);
@ -604,10 +606,10 @@ static int pn544_hci_start_poll(struct nfc_shdlc *shdlc, u32 protocols)
if (r < 0)
return r;
if (protocols & (NFC_PROTO_ISO14443_MASK | NFC_PROTO_MIFARE_MASK |
if (im_protocols & (NFC_PROTO_ISO14443_MASK | NFC_PROTO_MIFARE_MASK |
NFC_PROTO_JEWEL_MASK))
phases |= 1; /* Type A */
if (protocols & NFC_PROTO_FELICA_MASK) {
if (im_protocols & NFC_PROTO_FELICA_MASK) {
phases |= (1 << 2); /* Type F 212 */
phases |= (1 << 3); /* Type F 424 */
}

View file

@ -56,6 +56,10 @@
* %NFC_ATTR_PROTOCOLS)
* @NFC_EVENT_DEVICE_REMOVED: event emitted when a device is removed
* (it sends %NFC_ATTR_DEVICE_INDEX)
* @NFC_EVENT_TM_ACTIVATED: event emitted when the adapter is activated in
* target mode.
* @NFC_EVENT_DEVICE_DEACTIVATED: event emitted when the adapter is deactivated
* from target mode.
*/
enum nfc_commands {
NFC_CMD_UNSPEC,
@ -71,6 +75,8 @@ enum nfc_commands {
NFC_EVENT_DEVICE_ADDED,
NFC_EVENT_DEVICE_REMOVED,
NFC_EVENT_TARGET_LOST,
NFC_EVENT_TM_ACTIVATED,
NFC_EVENT_TM_DEACTIVATED,
/* private: internal use only */
__NFC_CMD_AFTER_LAST
};
@ -94,6 +100,8 @@ enum nfc_commands {
* @NFC_ATTR_TARGET_SENSF_RES: NFC-F targets extra information, max 18 bytes
* @NFC_ATTR_COMM_MODE: Passive or active mode
* @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
*/
enum nfc_attrs {
NFC_ATTR_UNSPEC,
@ -109,6 +117,8 @@ enum nfc_attrs {
NFC_ATTR_COMM_MODE,
NFC_ATTR_RF_MODE,
NFC_ATTR_DEVICE_POWERED,
NFC_ATTR_IM_PROTOCOLS,
NFC_ATTR_TM_PROTOCOLS,
/* private: internal use only */
__NFC_ATTR_AFTER_LAST
};
@ -118,6 +128,7 @@ enum nfc_attrs {
#define NFC_NFCID1_MAXSIZE 10
#define NFC_SENSB_RES_MAXSIZE 12
#define NFC_SENSF_RES_MAXSIZE 18
#define NFC_GB_MAXSIZE 48
/* NFC protocols */
#define NFC_PROTO_JEWEL 1
@ -135,6 +146,7 @@ enum nfc_attrs {
/* NFC RF modes */
#define NFC_RF_INITIATOR 0
#define NFC_RF_TARGET 1
#define NFC_RF_NONE 2
/* NFC protocols masks used in bitsets */
#define NFC_PROTO_JEWEL_MASK (1 << NFC_PROTO_JEWEL)

View file

@ -31,7 +31,8 @@ struct nfc_hci_ops {
void (*close) (struct nfc_hci_dev *hdev);
int (*hci_ready) (struct nfc_hci_dev *hdev);
int (*xmit) (struct nfc_hci_dev *hdev, struct sk_buff *skb);
int (*start_poll) (struct nfc_hci_dev *hdev, u32 protocols);
int (*start_poll) (struct nfc_hci_dev *hdev,
u32 im_protocols, u32 tm_protocols);
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,

View file

@ -53,7 +53,8 @@ struct nfc_target;
struct nfc_ops {
int (*dev_up)(struct nfc_dev *dev);
int (*dev_down)(struct nfc_dev *dev);
int (*start_poll)(struct nfc_dev *dev, u32 protocols);
int (*start_poll)(struct nfc_dev *dev,
u32 im_protocols, u32 tm_protocols);
void (*stop_poll)(struct nfc_dev *dev);
int (*dep_link_up)(struct nfc_dev *dev, struct nfc_target *target,
u8 comm_mode, u8 *gb, size_t gb_len);
@ -62,9 +63,10 @@ struct nfc_ops {
u32 protocol);
void (*deactivate_target)(struct nfc_dev *dev,
struct nfc_target *target);
int (*data_exchange)(struct nfc_dev *dev, struct nfc_target *target,
int (*im_transceive)(struct nfc_dev *dev, struct nfc_target *target,
struct sk_buff *skb, data_exchange_cb_t cb,
void *cb_context);
int (*tm_send)(struct nfc_dev *dev, struct sk_buff *skb);
int (*check_presence)(struct nfc_dev *dev, struct nfc_target *target);
};
@ -99,10 +101,10 @@ struct nfc_dev {
int targets_generation;
struct device dev;
bool dev_up;
u8 rf_mode;
bool polling;
struct nfc_target *active_target;
bool dep_link_up;
u32 dep_rf_mode;
struct nfc_genl_data genl_data;
u32 supported_protocols;
@ -188,6 +190,7 @@ struct sk_buff *nfc_alloc_recv_skb(unsigned int size, gfp_t gfp);
int nfc_set_remote_general_bytes(struct nfc_dev *dev,
u8 *gt, u8 gt_len);
u8 *nfc_get_local_general_bytes(struct nfc_dev *dev, size_t *gb_len);
int nfc_targets_found(struct nfc_dev *dev,
struct nfc_target *targets, int ntargets);
@ -196,4 +199,9 @@ int nfc_target_lost(struct nfc_dev *dev, u32 target_idx);
int nfc_dep_link_is_up(struct nfc_dev *dev, u32 target_idx,
u8 comm_mode, u8 rf_mode);
int nfc_tm_activated(struct nfc_dev *dev, u32 protocol, u8 comm_mode,
u8 *gb, size_t gb_len);
int nfc_tm_deactivated(struct nfc_dev *dev);
int nfc_tm_data_received(struct nfc_dev *dev, struct sk_buff *skb);
#endif /* __NET_NFC_H */

View file

@ -27,7 +27,8 @@ struct nfc_shdlc_ops {
void (*close) (struct nfc_shdlc *shdlc);
int (*hci_ready) (struct nfc_shdlc *shdlc);
int (*xmit) (struct nfc_shdlc *shdlc, struct sk_buff *skb);
int (*start_poll) (struct nfc_shdlc *shdlc, u32 protocols);
int (*start_poll) (struct nfc_shdlc *shdlc,
u32 im_protocols, u32 tm_protocols);
int (*target_from_gate) (struct nfc_shdlc *shdlc, u8 gate,
struct nfc_target *target);
int (*complete_target_discovered) (struct nfc_shdlc *shdlc, u8 gate,

View file

@ -121,14 +121,14 @@ error:
* The device remains polling for targets until a target is found or
* the nfc_stop_poll function is called.
*/
int nfc_start_poll(struct nfc_dev *dev, u32 protocols)
int nfc_start_poll(struct nfc_dev *dev, u32 im_protocols, u32 tm_protocols)
{
int rc;
pr_debug("dev_name=%s protocols=0x%x\n",
dev_name(&dev->dev), protocols);
pr_debug("dev_name %s initiator protocols 0x%x target protocols 0x%x\n",
dev_name(&dev->dev), im_protocols, tm_protocols);
if (!protocols)
if (!im_protocols && !tm_protocols)
return -EINVAL;
device_lock(&dev->dev);
@ -143,9 +143,11 @@ int nfc_start_poll(struct nfc_dev *dev, u32 protocols)
goto error;
}
rc = dev->ops->start_poll(dev, protocols);
if (!rc)
rc = dev->ops->start_poll(dev, im_protocols, tm_protocols);
if (!rc) {
dev->polling = true;
dev->rf_mode = NFC_RF_NONE;
}
error:
device_unlock(&dev->dev);
@ -235,8 +237,10 @@ int nfc_dep_link_up(struct nfc_dev *dev, int target_index, u8 comm_mode)
}
rc = dev->ops->dep_link_up(dev, target, comm_mode, gb, gb_len);
if (!rc)
if (!rc) {
dev->active_target = target;
dev->rf_mode = NFC_RF_INITIATOR;
}
error:
device_unlock(&dev->dev);
@ -264,11 +268,6 @@ int nfc_dep_link_down(struct nfc_dev *dev)
goto error;
}
if (dev->dep_rf_mode == NFC_RF_TARGET) {
rc = -EOPNOTSUPP;
goto error;
}
rc = dev->ops->dep_link_down(dev);
if (!rc) {
dev->dep_link_up = false;
@ -286,7 +285,6 @@ int nfc_dep_link_is_up(struct nfc_dev *dev, u32 target_idx,
u8 comm_mode, u8 rf_mode)
{
dev->dep_link_up = true;
dev->dep_rf_mode = rf_mode;
nfc_llcp_mac_is_up(dev, target_idx, comm_mode, rf_mode);
@ -330,6 +328,7 @@ int nfc_activate_target(struct nfc_dev *dev, u32 target_idx, u32 protocol)
rc = dev->ops->activate_target(dev, target, protocol);
if (!rc) {
dev->active_target = target;
dev->rf_mode = NFC_RF_INITIATOR;
if (dev->ops->check_presence)
mod_timer(&dev->check_pres_timer, jiffies +
@ -409,27 +408,30 @@ int nfc_data_exchange(struct nfc_dev *dev, u32 target_idx, struct sk_buff *skb,
goto error;
}
if (dev->active_target == NULL) {
if (dev->rf_mode == NFC_RF_INITIATOR && dev->active_target != NULL) {
if (dev->active_target->idx != target_idx) {
rc = -EADDRNOTAVAIL;
kfree_skb(skb);
goto error;
}
if (dev->ops->check_presence)
del_timer_sync(&dev->check_pres_timer);
rc = dev->ops->im_transceive(dev, dev->active_target, skb, cb,
cb_context);
if (!rc && dev->ops->check_presence)
mod_timer(&dev->check_pres_timer, jiffies +
msecs_to_jiffies(NFC_CHECK_PRES_FREQ_MS));
} else if (dev->rf_mode == NFC_RF_TARGET && dev->ops->tm_send != NULL) {
rc = dev->ops->tm_send(dev, skb);
} else {
rc = -ENOTCONN;
kfree_skb(skb);
goto error;
}
if (dev->active_target->idx != target_idx) {
rc = -EADDRNOTAVAIL;
kfree_skb(skb);
goto error;
}
if (dev->ops->check_presence)
del_timer_sync(&dev->check_pres_timer);
rc = dev->ops->data_exchange(dev, dev->active_target, skb, cb,
cb_context);
if (!rc && dev->ops->check_presence)
mod_timer(&dev->check_pres_timer, jiffies +
msecs_to_jiffies(NFC_CHECK_PRES_FREQ_MS));
error:
device_unlock(&dev->dev);
@ -447,6 +449,63 @@ int nfc_set_remote_general_bytes(struct nfc_dev *dev, u8 *gb, u8 gb_len)
}
EXPORT_SYMBOL(nfc_set_remote_general_bytes);
u8 *nfc_get_local_general_bytes(struct nfc_dev *dev, size_t *gb_len)
{
pr_debug("dev_name=%s\n", dev_name(&dev->dev));
return nfc_llcp_general_bytes(dev, gb_len);
}
EXPORT_SYMBOL(nfc_get_local_general_bytes);
int nfc_tm_data_received(struct nfc_dev *dev, struct sk_buff *skb)
{
/* Only LLCP target mode for now */
if (dev->dep_link_up == false) {
kfree_skb(skb);
return -ENOLINK;
}
return nfc_llcp_data_received(dev, skb);
}
EXPORT_SYMBOL(nfc_tm_data_received);
int nfc_tm_activated(struct nfc_dev *dev, u32 protocol, u8 comm_mode,
u8 *gb, size_t gb_len)
{
int rc;
device_lock(&dev->dev);
dev->polling = false;
if (gb != NULL) {
rc = nfc_set_remote_general_bytes(dev, gb, gb_len);
if (rc < 0)
goto out;
}
dev->rf_mode = NFC_RF_TARGET;
if (protocol == NFC_PROTO_NFC_DEP_MASK)
nfc_dep_link_is_up(dev, 0, comm_mode, NFC_RF_TARGET);
rc = nfc_genl_tm_activated(dev, protocol);
out:
device_unlock(&dev->dev);
return rc;
}
EXPORT_SYMBOL(nfc_tm_activated);
int nfc_tm_deactivated(struct nfc_dev *dev)
{
dev->dep_link_up = false;
return nfc_genl_tm_deactivated(dev);
}
EXPORT_SYMBOL(nfc_tm_deactivated);
/**
* nfc_alloc_send_skb - allocate a skb for data exchange responses
*
@ -678,7 +737,7 @@ struct nfc_dev *nfc_allocate_device(struct nfc_ops *ops,
struct nfc_dev *dev;
if (!ops->start_poll || !ops->stop_poll || !ops->activate_target ||
!ops->deactivate_target || !ops->data_exchange)
!ops->deactivate_target || !ops->im_transceive)
return NULL;
if (!supported_protocols)

View file

@ -481,12 +481,13 @@ static int hci_dev_down(struct nfc_dev *nfc_dev)
return 0;
}
static int hci_start_poll(struct nfc_dev *nfc_dev, u32 protocols)
static int hci_start_poll(struct nfc_dev *nfc_dev,
u32 im_protocols, u32 tm_protocols)
{
struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev);
if (hdev->ops->start_poll)
return hdev->ops->start_poll(hdev, protocols);
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);
@ -511,9 +512,9 @@ static void hci_deactivate_target(struct nfc_dev *nfc_dev,
{
}
static int hci_data_exchange(struct nfc_dev *nfc_dev, struct nfc_target *target,
struct sk_buff *skb, data_exchange_cb_t cb,
void *cb_context)
static int hci_transceive(struct nfc_dev *nfc_dev, struct nfc_target *target,
struct sk_buff *skb, data_exchange_cb_t cb,
void *cb_context)
{
struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev);
int r;
@ -579,7 +580,7 @@ static struct nfc_ops hci_nfc_ops = {
.stop_poll = hci_stop_poll,
.activate_target = hci_activate_target,
.deactivate_target = hci_deactivate_target,
.data_exchange = hci_data_exchange,
.im_transceive = hci_transceive,
.check_presence = hci_check_presence,
};

View file

@ -765,14 +765,16 @@ static int nfc_shdlc_xmit(struct nfc_hci_dev *hdev, struct sk_buff *skb)
return 0;
}
static int nfc_shdlc_start_poll(struct nfc_hci_dev *hdev, u32 protocols)
static int nfc_shdlc_start_poll(struct nfc_hci_dev *hdev,
u32 im_protocols, u32 tm_protocols)
{
struct nfc_shdlc *shdlc = nfc_hci_get_clientdata(hdev);
pr_debug("\n");
if (shdlc->ops->start_poll)
return shdlc->ops->start_poll(shdlc, protocols);
return shdlc->ops->start_poll(shdlc,
im_protocols, tm_protocols);
return 0;
}

View file

@ -51,7 +51,7 @@ static u8 llcp_tlv8(u8 *tlv, u8 type)
return tlv[2];
}
static u8 llcp_tlv16(u8 *tlv, u8 type)
static u16 llcp_tlv16(u8 *tlv, u8 type)
{
if (tlv[0] != type || tlv[1] != llcp_tlv_length[tlv[0]])
return 0;
@ -67,7 +67,7 @@ static u8 llcp_tlv_version(u8 *tlv)
static u16 llcp_tlv_miux(u8 *tlv)
{
return llcp_tlv16(tlv, LLCP_TLV_MIUX) & 0x7f;
return llcp_tlv16(tlv, LLCP_TLV_MIUX) & 0x7ff;
}
static u16 llcp_tlv_wks(u8 *tlv)
@ -117,8 +117,8 @@ u8 *nfc_llcp_build_tlv(u8 type, u8 *value, u8 value_length, u8 *tlv_length)
return tlv;
}
int nfc_llcp_parse_tlv(struct nfc_llcp_local *local,
u8 *tlv_array, u16 tlv_array_len)
int nfc_llcp_parse_gb_tlv(struct nfc_llcp_local *local,
u8 *tlv_array, u16 tlv_array_len)
{
u8 *tlv = tlv_array, type, length, offset = 0;
@ -149,8 +149,45 @@ int nfc_llcp_parse_tlv(struct nfc_llcp_local *local,
case LLCP_TLV_OPT:
local->remote_opt = llcp_tlv_opt(tlv);
break;
default:
pr_err("Invalid gt tlv value 0x%x\n", type);
break;
}
offset += length + 2;
tlv += length + 2;
}
pr_debug("version 0x%x miu %d lto %d opt 0x%x wks 0x%x\n",
local->remote_version, local->remote_miu,
local->remote_lto, local->remote_opt,
local->remote_wks);
return 0;
}
int nfc_llcp_parse_connection_tlv(struct nfc_llcp_sock *sock,
u8 *tlv_array, u16 tlv_array_len)
{
u8 *tlv = tlv_array, type, length, offset = 0;
pr_debug("TLV array length %d\n", tlv_array_len);
if (sock == NULL)
return -ENOTCONN;
while (offset < tlv_array_len) {
type = tlv[0];
length = tlv[1];
pr_debug("type 0x%x length %d\n", type, length);
switch (type) {
case LLCP_TLV_MIUX:
sock->miu = llcp_tlv_miux(tlv) + 128;
break;
case LLCP_TLV_RW:
local->remote_rw = llcp_tlv_rw(tlv);
sock->rw = llcp_tlv_rw(tlv);
break;
case LLCP_TLV_SN:
break;
@ -163,10 +200,7 @@ int nfc_llcp_parse_tlv(struct nfc_llcp_local *local,
tlv += length + 2;
}
pr_debug("version 0x%x miu %d lto %d opt 0x%x wks 0x%x rw %d\n",
local->remote_version, local->remote_miu,
local->remote_lto, local->remote_opt,
local->remote_wks, local->remote_rw);
pr_debug("sock %p rw %d miu %d\n", sock, sock->rw, sock->miu);
return 0;
}
@ -474,7 +508,7 @@ int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock,
while (remaining_len > 0) {
frag_len = min_t(size_t, local->remote_miu, remaining_len);
frag_len = min_t(size_t, sock->miu, remaining_len);
pr_debug("Fragment %zd bytes remaining %zd",
frag_len, remaining_len);

View file

@ -31,47 +31,41 @@ static u8 llcp_magic[3] = {0x46, 0x66, 0x6d};
static struct list_head llcp_devices;
void nfc_llcp_sock_link(struct llcp_sock_list *l, struct sock *sk)
{
write_lock(&l->lock);
sk_add_node(sk, &l->head);
write_unlock(&l->lock);
}
void nfc_llcp_sock_unlink(struct llcp_sock_list *l, struct sock *sk)
{
write_lock(&l->lock);
sk_del_node_init(sk);
write_unlock(&l->lock);
}
static void nfc_llcp_socket_release(struct nfc_llcp_local *local)
{
struct nfc_llcp_sock *parent, *s, *n;
struct sock *sk, *parent_sk;
int i;
struct sock *sk;
struct hlist_node *node, *tmp;
struct nfc_llcp_sock *llcp_sock;
mutex_lock(&local->socket_lock);
write_lock(&local->sockets.lock);
for (i = 0; i < LLCP_MAX_SAP; i++) {
parent = local->sockets[i];
if (parent == NULL)
continue;
sk_for_each_safe(sk, node, tmp, &local->sockets.head) {
llcp_sock = nfc_llcp_sock(sk);
/* Release all child sockets */
list_for_each_entry_safe(s, n, &parent->list, list) {
list_del_init(&s->list);
sk = &s->sk;
lock_sock(sk);
lock_sock(sk);
if (sk->sk_state == LLCP_CONNECTED)
nfc_put_device(llcp_sock->dev);
if (sk->sk_state == LLCP_CONNECTED)
nfc_put_device(s->dev);
sk->sk_state = LLCP_CLOSED;
release_sock(sk);
sock_orphan(sk);
s->local = NULL;
}
parent_sk = &parent->sk;
lock_sock(parent_sk);
if (parent_sk->sk_state == LLCP_LISTEN) {
if (sk->sk_state == LLCP_LISTEN) {
struct nfc_llcp_sock *lsk, *n;
struct sock *accept_sk;
list_for_each_entry_safe(lsk, n, &parent->accept_queue,
list_for_each_entry_safe(lsk, n, &llcp_sock->accept_queue,
accept_queue) {
accept_sk = &lsk->sk;
lock_sock(accept_sk);
@ -83,24 +77,53 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local)
release_sock(accept_sk);
sock_orphan(accept_sk);
lsk->local = NULL;
}
}
if (parent_sk->sk_state == LLCP_CONNECTED)
nfc_put_device(parent->dev);
sk->sk_state = LLCP_CLOSED;
parent_sk->sk_state = LLCP_CLOSED;
release_sock(sk);
release_sock(parent_sk);
sock_orphan(sk);
sock_orphan(parent_sk);
parent->local = NULL;
sk_del_node_init(sk);
}
mutex_unlock(&local->socket_lock);
write_unlock(&local->sockets.lock);
}
struct nfc_llcp_local *nfc_llcp_local_get(struct nfc_llcp_local *local)
{
kref_get(&local->ref);
return local;
}
static void local_release(struct kref *ref)
{
struct nfc_llcp_local *local;
local = container_of(ref, struct nfc_llcp_local, ref);
list_del(&local->list);
nfc_llcp_socket_release(local);
del_timer_sync(&local->link_timer);
skb_queue_purge(&local->tx_queue);
destroy_workqueue(local->tx_wq);
destroy_workqueue(local->rx_wq);
destroy_workqueue(local->timeout_wq);
kfree_skb(local->rx_pending);
kfree(local);
}
int nfc_llcp_local_put(struct nfc_llcp_local *local)
{
WARN_ON(local == NULL);
if (local == NULL)
return 0;
return kref_put(&local->ref, local_release);
}
static void nfc_llcp_clear_sdp(struct nfc_llcp_local *local)
@ -384,31 +407,9 @@ int nfc_llcp_set_remote_gb(struct nfc_dev *dev, u8 *gb, u8 gb_len)
return -EINVAL;
}
return nfc_llcp_parse_tlv(local,
&local->remote_gb[3],
local->remote_gb_len - 3);
}
static void nfc_llcp_tx_work(struct work_struct *work)
{
struct nfc_llcp_local *local = container_of(work, struct nfc_llcp_local,
tx_work);
struct sk_buff *skb;
skb = skb_dequeue(&local->tx_queue);
if (skb != NULL) {
pr_debug("Sending pending skb\n");
print_hex_dump(KERN_DEBUG, "LLCP Tx: ", DUMP_PREFIX_OFFSET,
16, 1, skb->data, skb->len, true);
nfc_data_exchange(local->dev, local->target_idx,
skb, nfc_llcp_recv, local);
} else {
nfc_llcp_send_symm(local->dev);
}
mod_timer(&local->link_timer,
jiffies + msecs_to_jiffies(local->remote_lto));
return nfc_llcp_parse_gb_tlv(local,
&local->remote_gb[3],
local->remote_gb_len - 3);
}
static u8 nfc_llcp_dsap(struct sk_buff *pdu)
@ -443,46 +444,146 @@ static void nfc_llcp_set_nrns(struct nfc_llcp_sock *sock, struct sk_buff *pdu)
sock->recv_ack_n = (sock->recv_n - 1) % 16;
}
static void nfc_llcp_tx_work(struct work_struct *work)
{
struct nfc_llcp_local *local = container_of(work, struct nfc_llcp_local,
tx_work);
struct sk_buff *skb;
struct sock *sk;
struct nfc_llcp_sock *llcp_sock;
skb = skb_dequeue(&local->tx_queue);
if (skb != NULL) {
sk = skb->sk;
llcp_sock = nfc_llcp_sock(sk);
if (llcp_sock != NULL) {
int ret;
pr_debug("Sending pending skb\n");
print_hex_dump(KERN_DEBUG, "LLCP Tx: ",
DUMP_PREFIX_OFFSET, 16, 1,
skb->data, skb->len, true);
ret = nfc_data_exchange(local->dev, local->target_idx,
skb, nfc_llcp_recv, local);
if (!ret && nfc_llcp_ptype(skb) == LLCP_PDU_I) {
skb = skb_get(skb);
skb_queue_tail(&llcp_sock->tx_pending_queue,
skb);
}
} else {
nfc_llcp_send_symm(local->dev);
}
} else {
nfc_llcp_send_symm(local->dev);
}
mod_timer(&local->link_timer,
jiffies + msecs_to_jiffies(2 * local->remote_lto));
}
static struct nfc_llcp_sock *nfc_llcp_connecting_sock_get(struct nfc_llcp_local *local,
u8 ssap)
{
struct sock *sk;
struct nfc_llcp_sock *llcp_sock;
struct hlist_node *node;
read_lock(&local->connecting_sockets.lock);
sk_for_each(sk, node, &local->connecting_sockets.head) {
llcp_sock = nfc_llcp_sock(sk);
if (llcp_sock->ssap == ssap) {
sock_hold(&llcp_sock->sk);
goto out;
}
}
llcp_sock = NULL;
out:
read_unlock(&local->connecting_sockets.lock);
return llcp_sock;
}
static struct nfc_llcp_sock *nfc_llcp_sock_get(struct nfc_llcp_local *local,
u8 ssap, u8 dsap)
{
struct nfc_llcp_sock *sock, *llcp_sock, *n;
struct sock *sk;
struct hlist_node *node;
struct nfc_llcp_sock *llcp_sock;
pr_debug("ssap dsap %d %d\n", ssap, dsap);
if (ssap == 0 && dsap == 0)
return NULL;
mutex_lock(&local->socket_lock);
sock = local->sockets[ssap];
if (sock == NULL) {
mutex_unlock(&local->socket_lock);
read_lock(&local->sockets.lock);
llcp_sock = NULL;
sk_for_each(sk, node, &local->sockets.head) {
llcp_sock = nfc_llcp_sock(sk);
if (llcp_sock->ssap == ssap &&
llcp_sock->dsap == dsap)
break;
}
read_unlock(&local->sockets.lock);
if (llcp_sock == NULL)
return NULL;
sock_hold(&llcp_sock->sk);
return llcp_sock;
}
static struct nfc_llcp_sock *nfc_llcp_sock_get_sn(struct nfc_llcp_local *local,
u8 *sn, size_t sn_len)
{
struct sock *sk;
struct hlist_node *node;
struct nfc_llcp_sock *llcp_sock;
pr_debug("sn %zd\n", sn_len);
if (sn == NULL || sn_len == 0)
return NULL;
read_lock(&local->sockets.lock);
llcp_sock = NULL;
sk_for_each(sk, node, &local->sockets.head) {
llcp_sock = nfc_llcp_sock(sk);
if (llcp_sock->sk.sk_state != LLCP_LISTEN)
continue;
if (llcp_sock->service_name == NULL ||
llcp_sock->service_name_len == 0)
continue;
if (llcp_sock->service_name_len != sn_len)
continue;
if (memcmp(sn, llcp_sock->service_name, sn_len) == 0)
break;
}
pr_debug("root dsap %d (%d)\n", sock->dsap, dsap);
read_unlock(&local->sockets.lock);
if (sock->dsap == dsap) {
sock_hold(&sock->sk);
mutex_unlock(&local->socket_lock);
return sock;
}
if (llcp_sock == NULL)
return NULL;
list_for_each_entry_safe(llcp_sock, n, &sock->list, list) {
pr_debug("llcp_sock %p sk %p dsap %d\n", llcp_sock,
&llcp_sock->sk, llcp_sock->dsap);
if (llcp_sock->dsap == dsap) {
sock_hold(&llcp_sock->sk);
mutex_unlock(&local->socket_lock);
return llcp_sock;
}
}
sock_hold(&llcp_sock->sk);
pr_err("Could not find socket for %d %d\n", ssap, dsap);
mutex_unlock(&local->socket_lock);
return NULL;
return llcp_sock;
}
static void nfc_llcp_sock_put(struct nfc_llcp_sock *sock)
@ -518,35 +619,19 @@ static void nfc_llcp_recv_connect(struct nfc_llcp_local *local,
{
struct sock *new_sk, *parent;
struct nfc_llcp_sock *sock, *new_sock;
u8 dsap, ssap, bound_sap, reason;
u8 dsap, ssap, reason;
dsap = nfc_llcp_dsap(skb);
ssap = nfc_llcp_ssap(skb);
pr_debug("%d %d\n", dsap, ssap);
nfc_llcp_parse_tlv(local, &skb->data[LLCP_HEADER_SIZE],
skb->len - LLCP_HEADER_SIZE);
if (dsap != LLCP_SAP_SDP) {
bound_sap = dsap;
mutex_lock(&local->socket_lock);
sock = local->sockets[dsap];
if (sock == NULL) {
mutex_unlock(&local->socket_lock);
sock = nfc_llcp_sock_get(local, dsap, LLCP_SAP_SDP);
if (sock == NULL || sock->sk.sk_state != LLCP_LISTEN) {
reason = LLCP_DM_NOBOUND;
goto fail;
}
sock_hold(&sock->sk);
mutex_unlock(&local->socket_lock);
lock_sock(&sock->sk);
if (sock->dsap == LLCP_SAP_SDP &&
sock->sk.sk_state == LLCP_LISTEN)
goto enqueue;
} else {
u8 *sn;
size_t sn_len;
@ -559,40 +644,15 @@ static void nfc_llcp_recv_connect(struct nfc_llcp_local *local,
pr_debug("Service name length %zu\n", sn_len);
mutex_lock(&local->socket_lock);
for (bound_sap = 0; bound_sap < LLCP_LOCAL_SAP_OFFSET;
bound_sap++) {
sock = local->sockets[bound_sap];
if (sock == NULL)
continue;
if (sock->service_name == NULL ||
sock->service_name_len == 0)
continue;
if (sock->service_name_len != sn_len)
continue;
if (sock->dsap == LLCP_SAP_SDP &&
sock->sk.sk_state == LLCP_LISTEN &&
!memcmp(sn, sock->service_name, sn_len)) {
pr_debug("Found service name at SAP %d\n",
bound_sap);
sock_hold(&sock->sk);
mutex_unlock(&local->socket_lock);
lock_sock(&sock->sk);
goto enqueue;
}
sock = nfc_llcp_sock_get_sn(local, sn, sn_len);
if (sock == NULL) {
reason = LLCP_DM_NOBOUND;
goto fail;
}
mutex_unlock(&local->socket_lock);
}
reason = LLCP_DM_NOBOUND;
goto fail;
lock_sock(&sock->sk);
enqueue:
parent = &sock->sk;
if (sk_acceptq_is_full(parent)) {
@ -612,15 +672,19 @@ enqueue:
new_sock = nfc_llcp_sock(new_sk);
new_sock->dev = local->dev;
new_sock->local = local;
new_sock->local = nfc_llcp_local_get(local);
new_sock->miu = local->remote_miu;
new_sock->nfc_protocol = sock->nfc_protocol;
new_sock->ssap = bound_sap;
new_sock->ssap = sock->ssap;
new_sock->dsap = ssap;
new_sock->parent = parent;
nfc_llcp_parse_connection_tlv(new_sock, &skb->data[LLCP_HEADER_SIZE],
skb->len - LLCP_HEADER_SIZE);
pr_debug("new sock %p sk %p\n", new_sock, &new_sock->sk);
list_add_tail(&new_sock->list, &sock->list);
nfc_llcp_sock_link(&local->sockets, new_sk);
nfc_llcp_accept_enqueue(&sock->sk, new_sk);
@ -654,12 +718,12 @@ int nfc_llcp_queue_i_frames(struct nfc_llcp_sock *sock)
pr_debug("Remote ready %d tx queue len %d remote rw %d",
sock->remote_ready, skb_queue_len(&sock->tx_pending_queue),
local->remote_rw);
sock->rw);
/* Try to queue some I frames for transmission */
while (sock->remote_ready &&
skb_queue_len(&sock->tx_pending_queue) < local->remote_rw) {
struct sk_buff *pdu, *pending_pdu;
skb_queue_len(&sock->tx_pending_queue) < sock->rw) {
struct sk_buff *pdu;
pdu = skb_dequeue(&sock->tx_queue);
if (pdu == NULL)
@ -668,10 +732,7 @@ int nfc_llcp_queue_i_frames(struct nfc_llcp_sock *sock)
/* Update N(S)/N(R) */
nfc_llcp_set_nrns(sock, pdu);
pending_pdu = skb_clone(pdu, GFP_KERNEL);
skb_queue_tail(&local->tx_queue, pdu);
skb_queue_tail(&sock->tx_pending_queue, pending_pdu);
nr_frames++;
}
@ -728,11 +789,21 @@ static void nfc_llcp_recv_hdlc(struct nfc_llcp_local *local,
llcp_sock->send_ack_n = nr;
skb_queue_walk_safe(&llcp_sock->tx_pending_queue, s, tmp)
if (nfc_llcp_ns(s) <= nr) {
skb_unlink(s, &llcp_sock->tx_pending_queue);
kfree_skb(s);
}
/* Remove and free all skbs until ns == nr */
skb_queue_walk_safe(&llcp_sock->tx_pending_queue, s, tmp) {
skb_unlink(s, &llcp_sock->tx_pending_queue);
kfree_skb(s);
if (nfc_llcp_ns(s) == nr)
break;
}
/* Re-queue the remaining skbs for transmission */
skb_queue_reverse_walk_safe(&llcp_sock->tx_pending_queue,
s, tmp) {
skb_unlink(s, &llcp_sock->tx_pending_queue);
skb_queue_head(&local->tx_queue, s);
}
}
if (ptype == LLCP_PDU_RR)
@ -740,7 +811,7 @@ static void nfc_llcp_recv_hdlc(struct nfc_llcp_local *local,
else if (ptype == LLCP_PDU_RNR)
llcp_sock->remote_ready = false;
if (nfc_llcp_queue_i_frames(llcp_sock) == 0)
if (nfc_llcp_queue_i_frames(llcp_sock) == 0 && ptype == LLCP_PDU_I)
nfc_llcp_send_rr(llcp_sock);
release_sock(sk);
@ -791,11 +862,7 @@ static void nfc_llcp_recv_cc(struct nfc_llcp_local *local, struct sk_buff *skb)
dsap = nfc_llcp_dsap(skb);
ssap = nfc_llcp_ssap(skb);
llcp_sock = nfc_llcp_sock_get(local, dsap, ssap);
if (llcp_sock == NULL)
llcp_sock = nfc_llcp_sock_get(local, dsap, LLCP_SAP_SDP);
llcp_sock = nfc_llcp_connecting_sock_get(local, dsap);
if (llcp_sock == NULL) {
pr_err("Invalid CC\n");
nfc_llcp_send_dm(local, dsap, ssap, LLCP_DM_NOCONN);
@ -803,11 +870,15 @@ static void nfc_llcp_recv_cc(struct nfc_llcp_local *local, struct sk_buff *skb)
return;
}
llcp_sock->dsap = ssap;
sk = &llcp_sock->sk;
nfc_llcp_parse_tlv(local, &skb->data[LLCP_HEADER_SIZE],
skb->len - LLCP_HEADER_SIZE);
/* Unlink from connecting and link to the client array */
nfc_llcp_sock_unlink(&local->connecting_sockets, sk);
nfc_llcp_sock_link(&local->sockets, sk);
llcp_sock->dsap = ssap;
nfc_llcp_parse_connection_tlv(llcp_sock, &skb->data[LLCP_HEADER_SIZE],
skb->len - LLCP_HEADER_SIZE);
sk->sk_state = LLCP_CONNECTED;
sk->sk_state_change(sk);
@ -891,6 +962,21 @@ void nfc_llcp_recv(void *data, struct sk_buff *skb, int err)
return;
}
int nfc_llcp_data_received(struct nfc_dev *dev, struct sk_buff *skb)
{
struct nfc_llcp_local *local;
local = nfc_llcp_find_local(dev);
if (local == NULL)
return -ENODEV;
local->rx_pending = skb_get(skb);
del_timer(&local->link_timer);
queue_work(local->rx_wq, &local->rx_work);
return 0;
}
void nfc_llcp_mac_is_down(struct nfc_dev *dev)
{
struct nfc_llcp_local *local;
@ -943,8 +1029,8 @@ int nfc_llcp_register_device(struct nfc_dev *ndev)
local->dev = ndev;
INIT_LIST_HEAD(&local->list);
kref_init(&local->ref);
mutex_init(&local->sdp_lock);
mutex_init(&local->socket_lock);
init_timer(&local->link_timer);
local->link_timer.data = (unsigned long) local;
local->link_timer.function = nfc_llcp_symm_timer;
@ -984,11 +1070,13 @@ int nfc_llcp_register_device(struct nfc_dev *ndev)
goto err_rx_wq;
}
local->sockets.lock = __RW_LOCK_UNLOCKED(local->sockets.lock);
local->connecting_sockets.lock = __RW_LOCK_UNLOCKED(local->connecting_sockets.lock);
nfc_llcp_build_gb(local);
local->remote_miu = LLCP_DEFAULT_MIU;
local->remote_lto = LLCP_DEFAULT_LTO;
local->remote_rw = LLCP_DEFAULT_RW;
list_add(&llcp_devices, &local->list);
@ -1015,14 +1103,7 @@ void nfc_llcp_unregister_device(struct nfc_dev *dev)
return;
}
list_del(&local->list);
nfc_llcp_socket_release(local);
del_timer_sync(&local->link_timer);
skb_queue_purge(&local->tx_queue);
destroy_workqueue(local->tx_wq);
destroy_workqueue(local->rx_wq);
kfree_skb(local->rx_pending);
kfree(local);
nfc_llcp_local_put(local);
}
int __init nfc_llcp_init(void)

View file

@ -40,12 +40,18 @@ enum llcp_state {
struct nfc_llcp_sock;
struct llcp_sock_list {
struct hlist_head head;
rwlock_t lock;
};
struct nfc_llcp_local {
struct list_head list;
struct nfc_dev *dev;
struct kref ref;
struct mutex sdp_lock;
struct mutex socket_lock;
struct timer_list link_timer;
struct sk_buff_head tx_queue;
@ -77,24 +83,26 @@ struct nfc_llcp_local {
u16 remote_lto;
u8 remote_opt;
u16 remote_wks;
u8 remote_rw;
/* sockets array */
struct nfc_llcp_sock *sockets[LLCP_MAX_SAP];
struct llcp_sock_list sockets;
struct llcp_sock_list connecting_sockets;
};
struct nfc_llcp_sock {
struct sock sk;
struct list_head list;
struct nfc_dev *dev;
struct nfc_llcp_local *local;
u32 target_idx;
u32 nfc_protocol;
/* Link parameters */
u8 ssap;
u8 dsap;
char *service_name;
size_t service_name_len;
u8 rw;
u16 miu;
/* Link variables */
u8 send_n;
@ -164,7 +172,11 @@ struct nfc_llcp_sock {
#define LLCP_DM_REJ 0x03
void nfc_llcp_sock_link(struct llcp_sock_list *l, struct sock *s);
void nfc_llcp_sock_unlink(struct llcp_sock_list *l, struct sock *s);
struct nfc_llcp_local *nfc_llcp_find_local(struct nfc_dev *dev);
struct nfc_llcp_local *nfc_llcp_local_get(struct nfc_llcp_local *local);
int nfc_llcp_local_put(struct nfc_llcp_local *local);
u8 nfc_llcp_get_sdp_ssap(struct nfc_llcp_local *local,
struct nfc_llcp_sock *sock);
u8 nfc_llcp_get_local_ssap(struct nfc_llcp_local *local);
@ -179,8 +191,10 @@ void nfc_llcp_accept_enqueue(struct sock *parent, struct sock *sk);
struct sock *nfc_llcp_accept_dequeue(struct sock *sk, struct socket *newsock);
/* TLV API */
int nfc_llcp_parse_tlv(struct nfc_llcp_local *local,
u8 *tlv_array, u16 tlv_array_len);
int nfc_llcp_parse_gb_tlv(struct nfc_llcp_local *local,
u8 *tlv_array, u16 tlv_array_len);
int nfc_llcp_parse_connection_tlv(struct nfc_llcp_sock *sock,
u8 *tlv_array, u16 tlv_array_len);
/* Commands API */
void nfc_llcp_recv(void *data, struct sk_buff *skb, int err);

View file

@ -111,7 +111,7 @@ static int llcp_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
}
llcp_sock->dev = dev;
llcp_sock->local = local;
llcp_sock->local = nfc_llcp_local_get(local);
llcp_sock->nfc_protocol = llcp_addr.nfc_protocol;
llcp_sock->service_name_len = min_t(unsigned int,
llcp_addr.service_name_len,
@ -124,7 +124,7 @@ static int llcp_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
if (llcp_sock->ssap == LLCP_MAX_SAP)
goto put_dev;
local->sockets[llcp_sock->ssap] = llcp_sock;
nfc_llcp_sock_link(&local->sockets, sk);
pr_debug("Socket bound to SAP %d\n", llcp_sock->ssap);
@ -379,15 +379,6 @@ static int llcp_sock_release(struct socket *sock)
goto out;
}
mutex_lock(&local->socket_lock);
if (llcp_sock == local->sockets[llcp_sock->ssap])
local->sockets[llcp_sock->ssap] = NULL;
else
list_del_init(&llcp_sock->list);
mutex_unlock(&local->socket_lock);
lock_sock(sk);
/* Send a DISC */
@ -412,14 +403,12 @@ static int llcp_sock_release(struct socket *sock)
}
}
/* Freeing the SAP */
if ((sk->sk_state == LLCP_CONNECTED
&& llcp_sock->ssap > LLCP_LOCAL_SAP_OFFSET) ||
sk->sk_state == LLCP_BOUND || sk->sk_state == LLCP_LISTEN)
nfc_llcp_put_ssap(llcp_sock->local, llcp_sock->ssap);
nfc_llcp_put_ssap(llcp_sock->local, llcp_sock->ssap);
release_sock(sk);
nfc_llcp_sock_unlink(&local->sockets, sk);
out:
sock_orphan(sk);
sock_put(sk);
@ -487,7 +476,8 @@ static int llcp_sock_connect(struct socket *sock, struct sockaddr *_addr,
}
llcp_sock->dev = dev;
llcp_sock->local = local;
llcp_sock->local = nfc_llcp_local_get(local);
llcp_sock->miu = llcp_sock->local->remote_miu;
llcp_sock->ssap = nfc_llcp_get_local_ssap(local);
if (llcp_sock->ssap == LLCP_SAP_MAX) {
ret = -ENOMEM;
@ -505,21 +495,26 @@ static int llcp_sock_connect(struct socket *sock, struct sockaddr *_addr,
llcp_sock->service_name_len,
GFP_KERNEL);
local->sockets[llcp_sock->ssap] = llcp_sock;
nfc_llcp_sock_link(&local->connecting_sockets, sk);
ret = nfc_llcp_send_connect(llcp_sock);
if (ret)
goto put_dev;
goto sock_unlink;
ret = sock_wait_state(sk, LLCP_CONNECTED,
sock_sndtimeo(sk, flags & O_NONBLOCK));
if (ret)
goto put_dev;
goto sock_unlink;
release_sock(sk);
return 0;
sock_unlink:
nfc_llcp_put_ssap(local, llcp_sock->ssap);
nfc_llcp_sock_unlink(&local->connecting_sockets, sk);
put_dev:
nfc_put_device(dev);
@ -684,13 +679,14 @@ struct sock *nfc_llcp_sock_alloc(struct socket *sock, int type, gfp_t gfp)
llcp_sock->ssap = 0;
llcp_sock->dsap = LLCP_SAP_SDP;
llcp_sock->rw = LLCP_DEFAULT_RW;
llcp_sock->miu = LLCP_DEFAULT_MIU;
llcp_sock->send_n = llcp_sock->send_ack_n = 0;
llcp_sock->recv_n = llcp_sock->recv_ack_n = 0;
llcp_sock->remote_ready = 1;
skb_queue_head_init(&llcp_sock->tx_queue);
skb_queue_head_init(&llcp_sock->tx_pending_queue);
skb_queue_head_init(&llcp_sock->tx_backlog_queue);
INIT_LIST_HEAD(&llcp_sock->list);
INIT_LIST_HEAD(&llcp_sock->accept_queue);
if (sock != NULL)
@ -701,8 +697,6 @@ struct sock *nfc_llcp_sock_alloc(struct socket *sock, int type, gfp_t gfp)
void nfc_llcp_sock_free(struct nfc_llcp_sock *sock)
{
struct nfc_llcp_local *local = sock->local;
kfree(sock->service_name);
skb_queue_purge(&sock->tx_queue);
@ -711,12 +705,9 @@ void nfc_llcp_sock_free(struct nfc_llcp_sock *sock)
list_del_init(&sock->accept_queue);
if (local != NULL && sock == local->sockets[sock->ssap])
local->sockets[sock->ssap] = NULL;
else
list_del_init(&sock->list);
sock->parent = NULL;
nfc_llcp_local_put(sock->local);
}
static int llcp_sock_create(struct net *net, struct socket *sock,

View file

@ -387,7 +387,8 @@ static int nci_dev_down(struct nfc_dev *nfc_dev)
return nci_close_device(ndev);
}
static int nci_start_poll(struct nfc_dev *nfc_dev, __u32 protocols)
static int nci_start_poll(struct nfc_dev *nfc_dev,
__u32 im_protocols, __u32 tm_protocols)
{
struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
int rc;
@ -413,11 +414,11 @@ static int nci_start_poll(struct nfc_dev *nfc_dev, __u32 protocols)
return -EBUSY;
}
rc = nci_request(ndev, nci_rf_discover_req, protocols,
rc = nci_request(ndev, nci_rf_discover_req, im_protocols,
msecs_to_jiffies(NCI_RF_DISC_TIMEOUT));
if (!rc)
ndev->poll_prots = protocols;
ndev->poll_prots = im_protocols;
return rc;
}
@ -521,9 +522,9 @@ static void nci_deactivate_target(struct nfc_dev *nfc_dev,
}
}
static int nci_data_exchange(struct nfc_dev *nfc_dev, struct nfc_target *target,
struct sk_buff *skb,
data_exchange_cb_t cb, void *cb_context)
static int nci_transceive(struct nfc_dev *nfc_dev, struct nfc_target *target,
struct sk_buff *skb,
data_exchange_cb_t cb, void *cb_context)
{
struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
int rc;
@ -556,7 +557,7 @@ static struct nfc_ops nci_nfc_ops = {
.stop_poll = nci_stop_poll,
.activate_target = nci_activate_target,
.deactivate_target = nci_deactivate_target,
.data_exchange = nci_data_exchange,
.im_transceive = nci_transceive,
};
/* ---- Interface to NCI drivers ---- */

View file

@ -49,6 +49,8 @@ static const struct nla_policy nfc_genl_policy[NFC_ATTR_MAX + 1] = {
[NFC_ATTR_COMM_MODE] = { .type = NLA_U8 },
[NFC_ATTR_RF_MODE] = { .type = NLA_U8 },
[NFC_ATTR_DEVICE_POWERED] = { .type = NLA_U8 },
[NFC_ATTR_IM_PROTOCOLS] = { .type = NLA_U32 },
[NFC_ATTR_TM_PROTOCOLS] = { .type = NLA_U32 },
};
static int nfc_genl_send_target(struct sk_buff *msg, struct nfc_target *target,
@ -219,6 +221,68 @@ free_msg:
return -EMSGSIZE;
}
int nfc_genl_tm_activated(struct nfc_dev *dev, u32 protocol)
{
struct sk_buff *msg;
void *hdr;
msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
if (!msg)
return -ENOMEM;
hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0,
NFC_EVENT_TM_ACTIVATED);
if (!hdr)
goto free_msg;
if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx))
goto nla_put_failure;
if (nla_put_u32(msg, NFC_ATTR_TM_PROTOCOLS, protocol))
goto nla_put_failure;
genlmsg_end(msg, hdr);
genlmsg_multicast(msg, 0, nfc_genl_event_mcgrp.id, GFP_KERNEL);
return 0;
nla_put_failure:
genlmsg_cancel(msg, hdr);
free_msg:
nlmsg_free(msg);
return -EMSGSIZE;
}
int nfc_genl_tm_deactivated(struct nfc_dev *dev)
{
struct sk_buff *msg;
void *hdr;
msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
if (!msg)
return -ENOMEM;
hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0,
NFC_EVENT_TM_DEACTIVATED);
if (!hdr)
goto free_msg;
if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx))
goto nla_put_failure;
genlmsg_end(msg, hdr);
genlmsg_multicast(msg, 0, nfc_genl_event_mcgrp.id, GFP_KERNEL);
return 0;
nla_put_failure:
genlmsg_cancel(msg, hdr);
free_msg:
nlmsg_free(msg);
return -EMSGSIZE;
}
int nfc_genl_device_added(struct nfc_dev *dev)
{
struct sk_buff *msg;
@ -519,16 +583,25 @@ static int nfc_genl_start_poll(struct sk_buff *skb, struct genl_info *info)
struct nfc_dev *dev;
int rc;
u32 idx;
u32 protocols;
u32 im_protocols = 0, tm_protocols = 0;
pr_debug("Poll start\n");
if (!info->attrs[NFC_ATTR_DEVICE_INDEX] ||
!info->attrs[NFC_ATTR_PROTOCOLS])
((!info->attrs[NFC_ATTR_IM_PROTOCOLS] &&
!info->attrs[NFC_ATTR_PROTOCOLS]) &&
!info->attrs[NFC_ATTR_TM_PROTOCOLS]))
return -EINVAL;
idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]);
protocols = nla_get_u32(info->attrs[NFC_ATTR_PROTOCOLS]);
if (info->attrs[NFC_ATTR_TM_PROTOCOLS])
tm_protocols = nla_get_u32(info->attrs[NFC_ATTR_TM_PROTOCOLS]);
if (info->attrs[NFC_ATTR_IM_PROTOCOLS])
im_protocols = nla_get_u32(info->attrs[NFC_ATTR_IM_PROTOCOLS]);
else if (info->attrs[NFC_ATTR_PROTOCOLS])
im_protocols = nla_get_u32(info->attrs[NFC_ATTR_PROTOCOLS]);
dev = nfc_get_device(idx);
if (!dev)
@ -536,7 +609,7 @@ static int nfc_genl_start_poll(struct sk_buff *skb, struct genl_info *info)
mutex_lock(&dev->genl_data.genl_data_mutex);
rc = nfc_start_poll(dev, protocols);
rc = nfc_start_poll(dev, im_protocols, tm_protocols);
if (!rc)
dev->genl_data.poll_req_pid = info->snd_pid;

View file

@ -55,6 +55,7 @@ int nfc_llcp_register_device(struct nfc_dev *dev);
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);
int __init nfc_llcp_init(void);
void nfc_llcp_exit(void);
@ -90,6 +91,12 @@ static inline u8 *nfc_llcp_general_bytes(struct nfc_dev *dev, size_t *gb_len)
return NULL;
}
static inline int nfc_llcp_data_received(struct nfc_dev *dev,
struct sk_buff *skb)
{
return 0;
}
static inline int nfc_llcp_init(void)
{
return 0;
@ -128,6 +135,9 @@ int nfc_genl_dep_link_up_event(struct nfc_dev *dev, u32 target_idx,
u8 comm_mode, u8 rf_mode);
int nfc_genl_dep_link_down_event(struct nfc_dev *dev);
int nfc_genl_tm_activated(struct nfc_dev *dev, u32 protocol);
int nfc_genl_tm_deactivated(struct nfc_dev *dev);
struct nfc_dev *nfc_get_device(unsigned int idx);
static inline void nfc_put_device(struct nfc_dev *dev)
@ -158,7 +168,7 @@ int nfc_dev_up(struct nfc_dev *dev);
int nfc_dev_down(struct nfc_dev *dev);
int nfc_start_poll(struct nfc_dev *dev, u32 protocols);
int nfc_start_poll(struct nfc_dev *dev, u32 im_protocols, u32 tm_protocols);
int nfc_stop_poll(struct nfc_dev *dev);