Skip to content

Commit

Permalink
Merge tag 'nfc-next-3.7-2' of git://git.kernel.org/pub/scm/linux/kern…
Browse files Browse the repository at this point in the history
…el/git/sameo/nfc-3.0

So says Samuel Ortiz <sameo@linux.intel.com>:

The 2nd NFC pull request for 3.7.

- A couple of wrong context sleep fixes.
- An LLCP rwlock intizialisation fix.
- A missing mutex unlocking for pn533.
- LLCP raw sockets support. This is going to be used for NFC sniffing.
- A build fix for llc_shdlc. It fixes a build error triggered by code that's
  living in wireless-next.

Signed-off-by: John W. Linville <linville@tuxdriver.com>
  • Loading branch information
John W. Linville committed Sep 28, 2012
2 parents 8a14e8b + 50b78b2 commit 97ea6d0
Show file tree
Hide file tree
Showing 7 changed files with 202 additions and 25 deletions.
15 changes: 8 additions & 7 deletions drivers/nfc/pn533.c
Original file line number Diff line number Diff line change
Expand Up @@ -716,7 +716,7 @@ static int pn533_send_cmd_frame_async(struct pn533 *dev,
void *arg, gfp_t flags)
{
struct pn533_cmd *cmd;
int rc;
int rc = 0;

nfc_dev_dbg(&dev->interface->dev, "%s", __func__);

Expand All @@ -729,16 +729,16 @@ static int pn533_send_cmd_frame_async(struct pn533 *dev,
if (!rc)
dev->cmd_pending = 1;

mutex_unlock(&dev->cmd_lock);

return rc;
goto unlock;
}

nfc_dev_dbg(&dev->interface->dev, "%s Queueing command", __func__);

cmd = kzalloc(sizeof(struct pn533_cmd), flags);
if (!cmd)
return -ENOMEM;
if (!cmd) {
rc = -ENOMEM;
goto unlock;
}

INIT_LIST_HEAD(&cmd->queue);
cmd->out_frame = out_frame;
Expand All @@ -750,9 +750,10 @@ static int pn533_send_cmd_frame_async(struct pn533 *dev,

list_add_tail(&cmd->queue, &dev->cmd_queue);

unlock:
mutex_unlock(&dev->cmd_lock);

return 0;
return rc;
}

struct pn533_sync_cmd_response {
Expand Down
11 changes: 11 additions & 0 deletions include/linux/nfc.h
Original file line number Diff line number Diff line change
Expand Up @@ -183,4 +183,15 @@ struct sockaddr_nfc_llcp {

#define NFC_HEADER_SIZE 1

/**
* Pseudo-header info for raw socket packets
* First byte is the adapter index
* Second byte contains flags
* - 0x01 - Direction (0=RX, 1=TX)
* - 0x02-0x80 - Reserved
**/
#define NFC_LLCP_RAW_HEADER_SIZE 2
#define NFC_LLCP_DIRECTION_RX 0x00
#define NFC_LLCP_DIRECTION_TX 0x01

#endif /*__LINUX_NFC_H */
2 changes: 2 additions & 0 deletions net/nfc/llcp/commands.c
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,8 @@ int nfc_llcp_send_symm(struct nfc_dev *dev)

skb = llcp_add_header(skb, 0, 0, LLCP_PDU_SYMM);

nfc_llcp_send_to_raw_sock(local, skb, NFC_LLCP_DIRECTION_TX);

return nfc_data_exchange(dev, local->target_idx, skb,
nfc_llcp_recv, local);
}
Expand Down
60 changes: 53 additions & 7 deletions net/nfc/llcp/llcp.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local, bool listen)
sk_for_each_safe(sk, node, tmp, &local->sockets.head) {
llcp_sock = nfc_llcp_sock(sk);

lock_sock(sk);
bh_lock_sock(sk);

if (sk->sk_state == LLCP_CONNECTED)
nfc_put_device(llcp_sock->dev);
Expand All @@ -68,26 +68,26 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local, bool listen)
list_for_each_entry_safe(lsk, n, &llcp_sock->accept_queue,
accept_queue) {
accept_sk = &lsk->sk;
lock_sock(accept_sk);
bh_lock_sock(accept_sk);

nfc_llcp_accept_unlink(accept_sk);

accept_sk->sk_state = LLCP_CLOSED;

release_sock(accept_sk);
bh_unlock_sock(accept_sk);

sock_orphan(accept_sk);
}

if (listen == true) {
release_sock(sk);
bh_unlock_sock(sk);
continue;
}
}

sk->sk_state = LLCP_CLOSED;

release_sock(sk);
bh_unlock_sock(sk);

sock_orphan(sk);

Expand Down Expand Up @@ -558,6 +558,46 @@ static void nfc_llcp_set_nrns(struct nfc_llcp_sock *sock, struct sk_buff *pdu)
sock->recv_ack_n = (sock->recv_n - 1) % 16;
}

void nfc_llcp_send_to_raw_sock(struct nfc_llcp_local *local,
struct sk_buff *skb, u8 direction)
{
struct hlist_node *node;
struct sk_buff *skb_copy = NULL, *nskb;
struct sock *sk;
u8 *data;

read_lock(&local->raw_sockets.lock);

sk_for_each(sk, node, &local->raw_sockets.head) {
if (sk->sk_state != LLCP_BOUND)
continue;

if (skb_copy == NULL) {
skb_copy = __pskb_copy(skb, NFC_LLCP_RAW_HEADER_SIZE,
GFP_ATOMIC);

if (skb_copy == NULL)
continue;

data = skb_push(skb_copy, NFC_LLCP_RAW_HEADER_SIZE);

data[0] = local->dev ? local->dev->idx : 0xFF;
data[1] = direction;
}

nskb = skb_clone(skb_copy, GFP_ATOMIC);
if (!nskb)
continue;

if (sock_queue_rcv_skb(sk, nskb))
kfree_skb(nskb);
}

read_unlock(&local->raw_sockets.lock);

kfree_skb(skb_copy);
}

static void nfc_llcp_tx_work(struct work_struct *work)
{
struct nfc_llcp_local *local = container_of(work, struct nfc_llcp_local,
Expand All @@ -578,6 +618,9 @@ static void nfc_llcp_tx_work(struct work_struct *work)
DUMP_PREFIX_OFFSET, 16, 1,
skb->data, skb->len, true);

nfc_llcp_send_to_raw_sock(local, skb,
NFC_LLCP_DIRECTION_TX);

ret = nfc_data_exchange(local->dev, local->target_idx,
skb, nfc_llcp_recv, local);

Expand Down Expand Up @@ -1022,6 +1065,8 @@ 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);

nfc_llcp_send_to_raw_sock(local, skb, NFC_LLCP_DIRECTION_RX);

switch (ptype) {
case LLCP_PDU_SYMM:
pr_debug("SYMM\n");
Expand Down Expand Up @@ -1156,8 +1201,9 @@ int nfc_llcp_register_device(struct nfc_dev *ndev)

INIT_WORK(&local->timeout_work, nfc_llcp_timeout_work);

local->sockets.lock = __RW_LOCK_UNLOCKED(local->sockets.lock);
local->connecting_sockets.lock = __RW_LOCK_UNLOCKED(local->connecting_sockets.lock);
rwlock_init(&local->sockets.lock);
rwlock_init(&local->connecting_sockets.lock);
rwlock_init(&local->raw_sockets.lock);

nfc_llcp_build_gb(local);

Expand Down
3 changes: 3 additions & 0 deletions net/nfc/llcp/llcp.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ struct nfc_llcp_local {
/* sockets array */
struct llcp_sock_list sockets;
struct llcp_sock_list connecting_sockets;
struct llcp_sock_list raw_sockets;
};

struct nfc_llcp_sock {
Expand Down Expand Up @@ -184,6 +185,8 @@ u8 nfc_llcp_get_sdp_ssap(struct nfc_llcp_local *local,
u8 nfc_llcp_get_local_ssap(struct nfc_llcp_local *local);
void nfc_llcp_put_ssap(struct nfc_llcp_local *local, u8 ssap);
int nfc_llcp_queue_i_frames(struct nfc_llcp_sock *sock);
void nfc_llcp_send_to_raw_sock(struct nfc_llcp_local *local,
struct sk_buff *skb, u8 direction);

/* Sock API */
struct sock *nfc_llcp_sock_alloc(struct socket *sock, int type, gfp_t gfp);
Expand Down
90 changes: 86 additions & 4 deletions net/nfc/llcp/sock.c
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,60 @@ static int llcp_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
return ret;
}

static int llcp_raw_sock_bind(struct socket *sock, struct sockaddr *addr,
int alen)
{
struct sock *sk = sock->sk;
struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk);
struct nfc_llcp_local *local;
struct nfc_dev *dev;
struct sockaddr_nfc_llcp llcp_addr;
int len, ret = 0;

if (!addr || addr->sa_family != AF_NFC)
return -EINVAL;

pr_debug("sk %p addr %p family %d\n", sk, addr, addr->sa_family);

memset(&llcp_addr, 0, sizeof(llcp_addr));
len = min_t(unsigned int, sizeof(llcp_addr), alen);
memcpy(&llcp_addr, addr, len);

lock_sock(sk);

if (sk->sk_state != LLCP_CLOSED) {
ret = -EBADFD;
goto error;
}

dev = nfc_get_device(llcp_addr.dev_idx);
if (dev == NULL) {
ret = -ENODEV;
goto error;
}

local = nfc_llcp_find_local(dev);
if (local == NULL) {
ret = -ENODEV;
goto put_dev;
}

llcp_sock->dev = dev;
llcp_sock->local = nfc_llcp_local_get(local);
llcp_sock->nfc_protocol = llcp_addr.nfc_protocol;

nfc_llcp_sock_link(&local->raw_sockets, sk);

sk->sk_state = LLCP_BOUND;

put_dev:
nfc_put_device(dev);

error:
release_sock(sk);
return ret;
}

static int llcp_sock_listen(struct socket *sock, int backlog)
{
struct sock *sk = sock->sk;
Expand Down Expand Up @@ -418,7 +472,10 @@ static int llcp_sock_release(struct socket *sock)

release_sock(sk);

nfc_llcp_sock_unlink(&local->sockets, sk);
if (sock->type == SOCK_RAW)
nfc_llcp_sock_unlink(&local->raw_sockets, sk);
else
nfc_llcp_sock_unlink(&local->sockets, sk);

out:
sock_orphan(sk);
Expand Down Expand Up @@ -614,7 +671,7 @@ static int llcp_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
if (!(flags & MSG_PEEK)) {

/* SOCK_STREAM: re-queue skb if it contains unreceived data */
if (sk->sk_type == SOCK_STREAM) {
if (sk->sk_type == SOCK_STREAM || sk->sk_type == SOCK_RAW) {
skb_pull(skb, copied);
if (skb->len) {
skb_queue_head(&sk->sk_receive_queue, skb);
Expand Down Expand Up @@ -655,6 +712,26 @@ static const struct proto_ops llcp_sock_ops = {
.mmap = sock_no_mmap,
};

static const struct proto_ops llcp_rawsock_ops = {
.family = PF_NFC,
.owner = THIS_MODULE,
.bind = llcp_raw_sock_bind,
.connect = sock_no_connect,
.release = llcp_sock_release,
.socketpair = sock_no_socketpair,
.accept = sock_no_accept,
.getname = llcp_sock_getname,
.poll = llcp_sock_poll,
.ioctl = sock_no_ioctl,
.listen = sock_no_listen,
.shutdown = sock_no_shutdown,
.setsockopt = sock_no_setsockopt,
.getsockopt = sock_no_getsockopt,
.sendmsg = sock_no_sendmsg,
.recvmsg = llcp_sock_recvmsg,
.mmap = sock_no_mmap,
};

static void llcp_sock_destruct(struct sock *sk)
{
struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk);
Expand Down Expand Up @@ -732,10 +809,15 @@ static int llcp_sock_create(struct net *net, struct socket *sock,

pr_debug("%p\n", sock);

if (sock->type != SOCK_STREAM && sock->type != SOCK_DGRAM)
if (sock->type != SOCK_STREAM &&
sock->type != SOCK_DGRAM &&
sock->type != SOCK_RAW)
return -ESOCKTNOSUPPORT;

sock->ops = &llcp_sock_ops;
if (sock->type == SOCK_RAW)
sock->ops = &llcp_rawsock_ops;
else
sock->ops = &llcp_sock_ops;

sk = nfc_llcp_sock_alloc(sock, sock->type, GFP_ATOMIC);
if (sk == NULL)
Expand Down
Loading

0 comments on commit 97ea6d0

Please sign in to comment.