Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next into for-davem

This commit is contained in:
John W. Linville
2013-04-24 10:54:20 -04:00
257 changed files with 9944 additions and 5676 deletions

View File

@@ -27,6 +27,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/rfkill.h>
#include <linux/nfc.h>
#include <net/genetlink.h>
@@ -58,6 +59,11 @@ int nfc_dev_up(struct nfc_dev *dev)
device_lock(&dev->dev);
if (dev->rfkill && rfkill_blocked(dev->rfkill)) {
rc = -ERFKILL;
goto error;
}
if (!device_is_registered(&dev->dev)) {
rc = -ENODEV;
goto error;
@@ -117,6 +123,24 @@ error:
return rc;
}
static int nfc_rfkill_set_block(void *data, bool blocked)
{
struct nfc_dev *dev = data;
pr_debug("%s blocked %d", dev_name(&dev->dev), blocked);
if (!blocked)
return 0;
nfc_dev_down(dev);
return 0;
}
static const struct rfkill_ops nfc_rfkill_ops = {
.set_block = nfc_rfkill_set_block,
};
/**
* nfc_start_poll - start polling for nfc targets
*
@@ -143,6 +167,11 @@ int nfc_start_poll(struct nfc_dev *dev, u32 im_protocols, u32 tm_protocols)
goto error;
}
if (!dev->dev_up) {
rc = -ENODEV;
goto error;
}
if (dev->polling) {
rc = -EBUSY;
goto error;
@@ -835,6 +864,15 @@ int nfc_register_device(struct nfc_dev *dev)
pr_debug("The userspace won't be notified that the device %s was added\n",
dev_name(&dev->dev));
dev->rfkill = rfkill_alloc(dev_name(&dev->dev), &dev->dev,
RFKILL_TYPE_NFC, &nfc_rfkill_ops, dev);
if (dev->rfkill) {
if (rfkill_register(dev->rfkill) < 0) {
rfkill_destroy(dev->rfkill);
dev->rfkill = NULL;
}
}
return 0;
}
EXPORT_SYMBOL(nfc_register_device);
@@ -852,6 +890,11 @@ void nfc_unregister_device(struct nfc_dev *dev)
id = dev->idx;
if (dev->rfkill) {
rfkill_unregister(dev->rfkill);
rfkill_destroy(dev->rfkill);
}
if (dev->ops->check_presence) {
device_lock(&dev->dev);
dev->shutting_down = true;

View File

@@ -420,7 +420,8 @@ int nfc_llcp_send_connect(struct nfc_llcp_sock *sock)
}
/* If the socket parameters are not set, use the local ones */
miux = sock->miux > LLCP_MAX_MIUX ? local->miux : sock->miux;
miux = be16_to_cpu(sock->miux) > LLCP_MAX_MIUX ?
local->miux : sock->miux;
rw = sock->rw > LLCP_MAX_RW ? local->rw : sock->rw;
miux_tlv = nfc_llcp_build_tlv(LLCP_TLV_MIUX, (u8 *)&miux, 0,
@@ -475,7 +476,8 @@ int nfc_llcp_send_cc(struct nfc_llcp_sock *sock)
return -ENODEV;
/* If the socket parameters are not set, use the local ones */
miux = sock->miux > LLCP_MAX_MIUX ? local->miux : sock->miux;
miux = be16_to_cpu(sock->miux) > LLCP_MAX_MIUX ?
local->miux : sock->miux;
rw = sock->rw > LLCP_MAX_RW ? local->rw : sock->rw;
miux_tlv = nfc_llcp_build_tlv(LLCP_TLV_MIUX, (u8 *)&miux, 0,
@@ -656,6 +658,7 @@ int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock,
struct nfc_llcp_local *local;
size_t frag_len = 0, remaining_len;
u8 *msg_data, *msg_ptr;
u16 remote_miu;
pr_debug("Send I frame len %zd\n", len);
@@ -692,9 +695,11 @@ int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock,
remaining_len = len;
msg_ptr = msg_data;
while (remaining_len > 0) {
do {
remote_miu = sock->remote_miu > LLCP_MAX_MIU ?
local->remote_miu : sock->remote_miu;
frag_len = min_t(size_t, sock->remote_miu, remaining_len);
frag_len = min_t(size_t, remote_miu, remaining_len);
pr_debug("Fragment %zd bytes remaining %zd",
frag_len, remaining_len);
@@ -706,7 +711,8 @@ int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock,
skb_put(pdu, LLCP_SEQUENCE_SIZE);
memcpy(skb_put(pdu, frag_len), msg_ptr, frag_len);
if (likely(frag_len > 0))
memcpy(skb_put(pdu, frag_len), msg_ptr, frag_len);
skb_queue_tail(&sock->tx_queue, pdu);
@@ -718,7 +724,7 @@ int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock,
remaining_len -= frag_len;
msg_ptr += frag_len;
}
} while (remaining_len > 0);
kfree(msg_data);
@@ -732,6 +738,7 @@ int nfc_llcp_send_ui_frame(struct nfc_llcp_sock *sock, u8 ssap, u8 dsap,
struct nfc_llcp_local *local;
size_t frag_len = 0, remaining_len;
u8 *msg_ptr, *msg_data;
u16 remote_miu;
int err;
pr_debug("Send UI frame len %zd\n", len);
@@ -752,9 +759,11 @@ int nfc_llcp_send_ui_frame(struct nfc_llcp_sock *sock, u8 ssap, u8 dsap,
remaining_len = len;
msg_ptr = msg_data;
while (remaining_len > 0) {
do {
remote_miu = sock->remote_miu > LLCP_MAX_MIU ?
local->remote_miu : sock->remote_miu;
frag_len = min_t(size_t, sock->remote_miu, remaining_len);
frag_len = min_t(size_t, remote_miu, remaining_len);
pr_debug("Fragment %zd bytes remaining %zd",
frag_len, remaining_len);
@@ -768,14 +777,15 @@ int nfc_llcp_send_ui_frame(struct nfc_llcp_sock *sock, u8 ssap, u8 dsap,
pdu = llcp_add_header(pdu, dsap, ssap, LLCP_PDU_UI);
memcpy(skb_put(pdu, frag_len), msg_ptr, frag_len);
if (likely(frag_len > 0))
memcpy(skb_put(pdu, frag_len), msg_ptr, frag_len);
/* No need to check for the peer RW for UI frames */
skb_queue_tail(&local->tx_queue, pdu);
remaining_len -= frag_len;
msg_ptr += frag_len;
}
} while (remaining_len > 0);
kfree(msg_data);

View File

@@ -31,6 +31,8 @@ static u8 llcp_magic[3] = {0x46, 0x66, 0x6d};
static struct list_head llcp_devices;
static void nfc_llcp_rx_skb(struct nfc_llcp_local *local, struct sk_buff *skb);
void nfc_llcp_sock_link(struct llcp_sock_list *l, struct sock *sk)
{
write_lock(&l->lock);
@@ -45,6 +47,12 @@ void nfc_llcp_sock_unlink(struct llcp_sock_list *l, struct sock *sk)
write_unlock(&l->lock);
}
void nfc_llcp_socket_remote_param_init(struct nfc_llcp_sock *sock)
{
sock->remote_rw = LLCP_DEFAULT_RW;
sock->remote_miu = LLCP_MAX_MIU + 1;
}
static void nfc_llcp_socket_purge(struct nfc_llcp_sock *sock)
{
struct nfc_llcp_local *local = sock->local;
@@ -68,7 +76,7 @@ static void nfc_llcp_socket_purge(struct nfc_llcp_sock *sock)
}
}
static void nfc_llcp_socket_release(struct nfc_llcp_local *local, bool listen,
static void nfc_llcp_socket_release(struct nfc_llcp_local *local, bool device,
int err)
{
struct sock *sk;
@@ -108,21 +116,6 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local, bool listen,
bh_unlock_sock(accept_sk);
}
if (listen == true) {
bh_unlock_sock(sk);
continue;
}
}
/*
* If we have a connection less socket bound, we keep it alive
* if the device is still present.
*/
if (sk->sk_state == LLCP_BOUND && sk->sk_type == SOCK_DGRAM &&
listen == true) {
bh_unlock_sock(sk);
continue;
}
if (err)
@@ -137,11 +130,8 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local, bool listen,
write_unlock(&local->sockets.lock);
/*
* If we want to keep the listening sockets alive,
* we don't touch the RAW ones.
*/
if (listen == true)
/* If we still have a device, we keep the RAW sockets alive */
if (device == true)
return;
write_lock(&local->raw_sockets.lock);
@@ -173,9 +163,9 @@ struct nfc_llcp_local *nfc_llcp_local_get(struct nfc_llcp_local *local)
return local;
}
static void local_cleanup(struct nfc_llcp_local *local, bool listen)
static void local_cleanup(struct nfc_llcp_local *local)
{
nfc_llcp_socket_release(local, listen, ENXIO);
nfc_llcp_socket_release(local, false, ENXIO);
del_timer_sync(&local->link_timer);
skb_queue_purge(&local->tx_queue);
cancel_work_sync(&local->tx_work);
@@ -194,7 +184,7 @@ static void local_release(struct kref *ref)
local = container_of(ref, struct nfc_llcp_local, ref);
list_del(&local->list);
local_cleanup(local, false);
local_cleanup(local);
kfree(local);
}
@@ -1116,6 +1106,12 @@ static void nfc_llcp_recv_disc(struct nfc_llcp_local *local,
dsap = nfc_llcp_dsap(skb);
ssap = nfc_llcp_ssap(skb);
if ((dsap == 0) && (ssap == 0)) {
pr_debug("Connection termination");
nfc_dep_link_down(local->dev);
return;
}
llcp_sock = nfc_llcp_sock_get(local, dsap, ssap);
if (llcp_sock == NULL) {
nfc_llcp_send_dm(local, dsap, ssap, LLCP_DM_NOCONN);
@@ -1349,19 +1345,54 @@ exit:
nfc_llcp_send_snl_sdres(local, &llc_sdres_list, sdres_tlvs_len);
}
static void nfc_llcp_rx_work(struct work_struct *work)
static void nfc_llcp_recv_agf(struct nfc_llcp_local *local, struct sk_buff *skb)
{
struct nfc_llcp_local *local = container_of(work, struct nfc_llcp_local,
rx_work);
u8 dsap, ssap, ptype;
struct sk_buff *skb;
u8 ptype;
u16 pdu_len;
struct sk_buff *new_skb;
skb = local->rx_pending;
if (skb == NULL) {
pr_debug("No pending SKB\n");
if (skb->len <= LLCP_HEADER_SIZE) {
pr_err("Malformed AGF PDU\n");
return;
}
skb_pull(skb, LLCP_HEADER_SIZE);
while (skb->len > LLCP_AGF_PDU_HEADER_SIZE) {
pdu_len = skb->data[0] << 8 | skb->data[1];
skb_pull(skb, LLCP_AGF_PDU_HEADER_SIZE);
if (pdu_len < LLCP_HEADER_SIZE || pdu_len > skb->len) {
pr_err("Malformed AGF PDU\n");
return;
}
ptype = nfc_llcp_ptype(skb);
if (ptype == LLCP_PDU_SYMM || ptype == LLCP_PDU_AGF)
goto next;
new_skb = nfc_alloc_recv_skb(pdu_len, GFP_KERNEL);
if (new_skb == NULL) {
pr_err("Could not allocate PDU\n");
return;
}
memcpy(skb_put(new_skb, pdu_len), skb->data, pdu_len);
nfc_llcp_rx_skb(local, new_skb);
kfree_skb(new_skb);
next:
skb_pull(skb, pdu_len);
}
}
static void nfc_llcp_rx_skb(struct nfc_llcp_local *local, struct sk_buff *skb)
{
u8 dsap, ssap, ptype;
ptype = nfc_llcp_ptype(skb);
dsap = nfc_llcp_dsap(skb);
ssap = nfc_llcp_ssap(skb);
@@ -1372,10 +1403,6 @@ static void nfc_llcp_rx_work(struct work_struct *work)
print_hex_dump(KERN_DEBUG, "LLCP Rx: ", DUMP_PREFIX_OFFSET,
16, 1, skb->data, skb->len, true);
__net_timestamp(skb);
nfc_llcp_send_to_raw_sock(local, skb, NFC_LLCP_DIRECTION_RX);
switch (ptype) {
case LLCP_PDU_SYMM:
pr_debug("SYMM\n");
@@ -1418,7 +1445,30 @@ static void nfc_llcp_rx_work(struct work_struct *work)
nfc_llcp_recv_hdlc(local, skb);
break;
case LLCP_PDU_AGF:
pr_debug("AGF frame\n");
nfc_llcp_recv_agf(local, skb);
break;
}
}
static void nfc_llcp_rx_work(struct work_struct *work)
{
struct nfc_llcp_local *local = container_of(work, struct nfc_llcp_local,
rx_work);
struct sk_buff *skb;
skb = local->rx_pending;
if (skb == NULL) {
pr_debug("No pending SKB\n");
return;
}
__net_timestamp(skb);
nfc_llcp_send_to_raw_sock(local, skb, NFC_LLCP_DIRECTION_RX);
nfc_llcp_rx_skb(local, skb);
schedule_work(&local->tx_work);
kfree_skb(local->rx_pending);
@@ -1466,6 +1516,9 @@ void nfc_llcp_mac_is_down(struct nfc_dev *dev)
if (local == NULL)
return;
local->remote_miu = LLCP_DEFAULT_MIU;
local->remote_lto = LLCP_DEFAULT_LTO;
/* Close and purge all existing sockets */
nfc_llcp_socket_release(local, true, 0);
}
@@ -1553,7 +1606,7 @@ void nfc_llcp_unregister_device(struct nfc_dev *dev)
return;
}
local_cleanup(local, false);
local_cleanup(local);
nfc_llcp_local_put(local);
}

View File

@@ -31,6 +31,7 @@ enum llcp_state {
#define LLCP_MAX_LTO 0xff
#define LLCP_MAX_RW 15
#define LLCP_MAX_MIUX 0x7ff
#define LLCP_MAX_MIU (LLCP_MAX_MIUX + 128)
#define LLCP_WKS_NUM_SAP 16
#define LLCP_SDP_NUM_SAP 16
@@ -124,7 +125,7 @@ struct nfc_llcp_sock {
char *service_name;
size_t service_name_len;
u8 rw;
u16 miux;
__be16 miux;
/* Remote link parameters */
@@ -162,6 +163,7 @@ struct nfc_llcp_ui_cb {
#define LLCP_HEADER_SIZE 2
#define LLCP_SEQUENCE_SIZE 1
#define LLCP_AGF_PDU_HEADER_SIZE 2
/* LLCP versions: 1.1 is 1.0 plus SDP */
#define LLCP_VERSION_10 0x10
@@ -210,6 +212,7 @@ struct nfc_llcp_ui_cb {
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);
void nfc_llcp_socket_remote_param_init(struct nfc_llcp_sock *sock);
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);

View File

@@ -279,7 +279,7 @@ static int nfc_llcp_setsockopt(struct socket *sock, int level, int optname,
break;
}
llcp_sock->miux = (u16) opt;
llcp_sock->miux = cpu_to_be16((u16) opt);
break;
@@ -299,9 +299,12 @@ static int nfc_llcp_setsockopt(struct socket *sock, int level, int optname,
static int nfc_llcp_getsockopt(struct socket *sock, int level, int optname,
char __user *optval, int __user *optlen)
{
struct nfc_llcp_local *local;
struct sock *sk = sock->sk;
struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk);
int len, err = 0;
u16 miux, remote_miu;
u8 rw;
pr_debug("%p optname %d\n", sk, optname);
@@ -311,19 +314,48 @@ static int nfc_llcp_getsockopt(struct socket *sock, int level, int optname,
if (get_user(len, optlen))
return -EFAULT;
local = llcp_sock->local;
if (!local)
return -ENODEV;
len = min_t(u32, len, sizeof(u32));
lock_sock(sk);
switch (optname) {
case NFC_LLCP_RW:
if (put_user(llcp_sock->rw, (u32 __user *) optval))
rw = llcp_sock->rw > LLCP_MAX_RW ? local->rw : llcp_sock->rw;
if (put_user(rw, (u32 __user *) optval))
err = -EFAULT;
break;
case NFC_LLCP_MIUX:
if (put_user(llcp_sock->miux, (u32 __user *) optval))
miux = be16_to_cpu(llcp_sock->miux) > LLCP_MAX_MIUX ?
be16_to_cpu(local->miux) : be16_to_cpu(llcp_sock->miux);
if (put_user(miux, (u32 __user *) optval))
err = -EFAULT;
break;
case NFC_LLCP_REMOTE_MIU:
remote_miu = llcp_sock->remote_miu > LLCP_MAX_MIU ?
local->remote_miu : llcp_sock->remote_miu;
if (put_user(remote_miu, (u32 __user *) optval))
err = -EFAULT;
break;
case NFC_LLCP_REMOTE_LTO:
if (put_user(local->remote_lto / 10, (u32 __user *) optval))
err = -EFAULT;
break;
case NFC_LLCP_REMOTE_RW:
if (put_user(llcp_sock->remote_rw, (u32 __user *) optval))
err = -EFAULT;
break;
@@ -925,13 +957,12 @@ 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_MAX_RW + 1;
llcp_sock->miux = LLCP_MAX_MIUX + 1;
llcp_sock->remote_rw = LLCP_DEFAULT_RW;
llcp_sock->remote_miu = LLCP_DEFAULT_MIU;
llcp_sock->miux = cpu_to_be16(LLCP_MAX_MIUX + 1);
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;
llcp_sock->reserved_ssap = LLCP_SAP_MAX;
nfc_llcp_socket_remote_param_init(llcp_sock);
skb_queue_head_init(&llcp_sock->tx_queue);
skb_queue_head_init(&llcp_sock->tx_pending_queue);
INIT_LIST_HEAD(&llcp_sock->accept_queue);