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:
Коммит
2e48686835
|
@ -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);
|
||||
|
|
|
@ -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 */
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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,
|
||||
|
|
119
net/nfc/core.c
119
net/nfc/core.c
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 ---- */
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче