2011-12-14 19:43:12 +04:00
/*
* Copyright ( C ) 2011 Intel Corporation . All rights reserved .
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the
* Free Software Foundation , Inc . ,
* 59 Temple Place - Suite 330 , Boston , MA 02111 - 1307 , USA .
*/
# define pr_fmt(fmt) "llcp: %s: " fmt, __func__
# include <linux/init.h>
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/nfc.h>
# include "../nfc.h"
# include "llcp.h"
2012-05-07 14:31:19 +04:00
static int sock_wait_state ( struct sock * sk , int state , unsigned long timeo )
{
DECLARE_WAITQUEUE ( wait , current ) ;
int err = 0 ;
pr_debug ( " sk %p " , sk ) ;
add_wait_queue ( sk_sleep ( sk ) , & wait ) ;
set_current_state ( TASK_INTERRUPTIBLE ) ;
while ( sk - > sk_state ! = state ) {
if ( ! timeo ) {
err = - EINPROGRESS ;
break ;
}
if ( signal_pending ( current ) ) {
err = sock_intr_errno ( timeo ) ;
break ;
}
release_sock ( sk ) ;
timeo = schedule_timeout ( timeo ) ;
lock_sock ( sk ) ;
set_current_state ( TASK_INTERRUPTIBLE ) ;
err = sock_error ( sk ) ;
if ( err )
break ;
}
__set_current_state ( TASK_RUNNING ) ;
remove_wait_queue ( sk_sleep ( sk ) , & wait ) ;
return err ;
}
2011-12-14 19:43:12 +04:00
static struct proto llcp_sock_proto = {
. name = " NFC_LLCP " ,
. owner = THIS_MODULE ,
. obj_size = sizeof ( struct nfc_llcp_sock ) ,
} ;
static int llcp_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 ;
2012-06-29 14:03:55 +04:00
pr_debug ( " sk %p addr %p family %d \n " , sk , addr , addr - > sa_family ) ;
2011-12-14 19:43:12 +04:00
memset ( & llcp_addr , 0 , sizeof ( llcp_addr ) ) ;
len = min_t ( unsigned int , sizeof ( llcp_addr ) , alen ) ;
memcpy ( & llcp_addr , addr , len ) ;
/* This is going to be a listening socket, dsap must be 0 */
if ( llcp_addr . dsap ! = 0 )
return - EINVAL ;
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 ;
2012-05-04 13:24:16 +04:00
llcp_sock - > local = nfc_llcp_local_get ( local ) ;
2011-12-14 19:43:12 +04:00
llcp_sock - > nfc_protocol = llcp_addr . nfc_protocol ;
llcp_sock - > service_name_len = min_t ( unsigned int ,
2012-03-05 04:03:52 +04:00
llcp_addr . service_name_len ,
NFC_LLCP_MAX_SERVICE_NAME ) ;
2011-12-14 19:43:12 +04:00
llcp_sock - > service_name = kmemdup ( llcp_addr . service_name ,
2012-03-05 04:03:52 +04:00
llcp_sock - > service_name_len ,
GFP_KERNEL ) ;
2011-12-14 19:43:12 +04:00
llcp_sock - > ssap = nfc_llcp_get_sdp_ssap ( local , llcp_sock ) ;
2012-06-22 17:32:20 +04:00
if ( llcp_sock - > ssap = = LLCP_SAP_MAX ) {
ret = - EADDRINUSE ;
2011-12-14 19:43:12 +04:00
goto put_dev ;
2012-06-22 17:32:20 +04:00
}
2011-12-14 19:43:12 +04:00
2012-06-22 16:48:11 +04:00
llcp_sock - > reserved_ssap = llcp_sock - > ssap ;
2012-05-04 19:04:19 +04:00
nfc_llcp_sock_link ( & local - > sockets , sk ) ;
2011-12-14 19:43:12 +04:00
pr_debug ( " Socket bound to SAP %d \n " , llcp_sock - > ssap ) ;
sk - > sk_state = LLCP_BOUND ;
put_dev :
nfc_put_device ( dev ) ;
error :
release_sock ( sk ) ;
return ret ;
}
2012-09-26 20:16:44 +04:00
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 ;
}
2011-12-14 19:43:12 +04:00
static int llcp_sock_listen ( struct socket * sock , int backlog )
{
struct sock * sk = sock - > sk ;
int ret = 0 ;
pr_debug ( " sk %p backlog %d \n " , sk , backlog ) ;
lock_sock ( sk ) ;
2012-10-04 17:15:51 +04:00
if ( ( sock - > type ! = SOCK_SEQPACKET & & sock - > type ! = SOCK_STREAM ) | |
sk - > sk_state ! = LLCP_BOUND ) {
2011-12-14 19:43:12 +04:00
ret = - EBADFD ;
goto error ;
}
sk - > sk_max_ack_backlog = backlog ;
sk - > sk_ack_backlog = 0 ;
pr_debug ( " Socket listening \n " ) ;
sk - > sk_state = LLCP_LISTEN ;
error :
release_sock ( sk ) ;
return ret ;
}
void nfc_llcp_accept_unlink ( struct sock * sk )
{
struct nfc_llcp_sock * llcp_sock = nfc_llcp_sock ( sk ) ;
pr_debug ( " state %d \n " , sk - > sk_state ) ;
list_del_init ( & llcp_sock - > accept_queue ) ;
sk_acceptq_removed ( llcp_sock - > parent ) ;
llcp_sock - > parent = NULL ;
sock_put ( sk ) ;
}
void nfc_llcp_accept_enqueue ( struct sock * parent , struct sock * sk )
{
struct nfc_llcp_sock * llcp_sock = nfc_llcp_sock ( sk ) ;
struct nfc_llcp_sock * llcp_sock_parent = nfc_llcp_sock ( parent ) ;
/* Lock will be free from unlink */
sock_hold ( sk ) ;
list_add_tail ( & llcp_sock - > accept_queue ,
2012-03-05 04:03:52 +04:00
& llcp_sock_parent - > accept_queue ) ;
2011-12-14 19:43:12 +04:00
llcp_sock - > parent = parent ;
sk_acceptq_added ( parent ) ;
}
struct sock * nfc_llcp_accept_dequeue ( struct sock * parent ,
2012-03-05 04:03:52 +04:00
struct socket * newsock )
2011-12-14 19:43:12 +04:00
{
struct nfc_llcp_sock * lsk , * n , * llcp_parent ;
struct sock * sk ;
llcp_parent = nfc_llcp_sock ( parent ) ;
list_for_each_entry_safe ( lsk , n , & llcp_parent - > accept_queue ,
2012-03-05 04:03:52 +04:00
accept_queue ) {
2011-12-14 19:43:12 +04:00
sk = & lsk - > sk ;
lock_sock ( sk ) ;
if ( sk - > sk_state = = LLCP_CLOSED ) {
release_sock ( sk ) ;
nfc_llcp_accept_unlink ( sk ) ;
continue ;
}
if ( sk - > sk_state = = LLCP_CONNECTED | | ! newsock ) {
nfc_llcp_accept_unlink ( sk ) ;
if ( newsock )
sock_graft ( sk , newsock ) ;
release_sock ( sk ) ;
pr_debug ( " Returning sk state %d \n " , sk - > sk_state ) ;
return sk ;
}
release_sock ( sk ) ;
}
return NULL ;
}
static int llcp_sock_accept ( struct socket * sock , struct socket * newsock ,
2012-03-05 04:03:52 +04:00
int flags )
2011-12-14 19:43:12 +04:00
{
DECLARE_WAITQUEUE ( wait , current ) ;
struct sock * sk = sock - > sk , * new_sk ;
long timeo ;
int ret = 0 ;
pr_debug ( " parent %p \n " , sk ) ;
lock_sock_nested ( sk , SINGLE_DEPTH_NESTING ) ;
if ( sk - > sk_state ! = LLCP_LISTEN ) {
ret = - EBADFD ;
goto error ;
}
timeo = sock_rcvtimeo ( sk , flags & O_NONBLOCK ) ;
/* Wait for an incoming connection. */
add_wait_queue_exclusive ( sk_sleep ( sk ) , & wait ) ;
while ( ! ( new_sk = nfc_llcp_accept_dequeue ( sk , newsock ) ) ) {
set_current_state ( TASK_INTERRUPTIBLE ) ;
if ( ! timeo ) {
ret = - EAGAIN ;
break ;
}
if ( signal_pending ( current ) ) {
ret = sock_intr_errno ( timeo ) ;
break ;
}
release_sock ( sk ) ;
timeo = schedule_timeout ( timeo ) ;
lock_sock_nested ( sk , SINGLE_DEPTH_NESTING ) ;
}
__set_current_state ( TASK_RUNNING ) ;
remove_wait_queue ( sk_sleep ( sk ) , & wait ) ;
if ( ret )
goto error ;
newsock - > state = SS_CONNECTED ;
pr_debug ( " new socket %p \n " , new_sk ) ;
error :
release_sock ( sk ) ;
return ret ;
}
2012-06-21 19:41:42 +04:00
static int llcp_sock_getname ( struct socket * sock , struct sockaddr * uaddr ,
2011-12-14 19:43:12 +04:00
int * len , int peer )
{
struct sock * sk = sock - > sk ;
struct nfc_llcp_sock * llcp_sock = nfc_llcp_sock ( sk ) ;
2012-06-21 19:41:42 +04:00
DECLARE_SOCKADDR ( struct sockaddr_nfc_llcp * , llcp_addr , uaddr ) ;
2011-12-14 19:43:12 +04:00
2012-07-05 19:43:08 +04:00
if ( llcp_sock = = NULL | | llcp_sock - > dev = = NULL )
return - EBADFD ;
2012-06-21 19:41:42 +04:00
pr_debug ( " %p %d %d %d \n " , sk , llcp_sock - > target_idx ,
llcp_sock - > dsap , llcp_sock - > ssap ) ;
2011-12-14 19:43:12 +04:00
2012-06-21 19:41:42 +04:00
uaddr - > sa_family = AF_NFC ;
2011-12-14 19:43:12 +04:00
* len = sizeof ( struct sockaddr_nfc_llcp ) ;
llcp_addr - > dev_idx = llcp_sock - > dev - > idx ;
2012-06-21 19:41:42 +04:00
llcp_addr - > target_idx = llcp_sock - > target_idx ;
2011-12-14 19:43:12 +04:00
llcp_addr - > dsap = llcp_sock - > dsap ;
llcp_addr - > ssap = llcp_sock - > ssap ;
llcp_addr - > service_name_len = llcp_sock - > service_name_len ;
memcpy ( llcp_addr - > service_name , llcp_sock - > service_name ,
2012-03-05 04:03:52 +04:00
llcp_addr - > service_name_len ) ;
2011-12-14 19:43:12 +04:00
return 0 ;
}
static inline unsigned int llcp_accept_poll ( struct sock * parent )
{
struct nfc_llcp_sock * llcp_sock , * n , * parent_sock ;
struct sock * sk ;
parent_sock = nfc_llcp_sock ( parent ) ;
list_for_each_entry_safe ( llcp_sock , n , & parent_sock - > accept_queue ,
2012-03-05 04:03:52 +04:00
accept_queue ) {
2011-12-14 19:43:12 +04:00
sk = & llcp_sock - > sk ;
if ( sk - > sk_state = = LLCP_CONNECTED )
return POLLIN | POLLRDNORM ;
}
return 0 ;
}
static unsigned int llcp_sock_poll ( struct file * file , struct socket * sock ,
2012-03-05 04:03:52 +04:00
poll_table * wait )
2011-12-14 19:43:12 +04:00
{
struct sock * sk = sock - > sk ;
unsigned int mask = 0 ;
pr_debug ( " %p \n " , sk ) ;
sock_poll_wait ( file , sk_sleep ( sk ) , wait ) ;
if ( sk - > sk_state = = LLCP_LISTEN )
return llcp_accept_poll ( sk ) ;
if ( sk - > sk_err | | ! skb_queue_empty ( & sk - > sk_error_queue ) )
mask | = POLLERR ;
if ( ! skb_queue_empty ( & sk - > sk_receive_queue ) )
2012-05-07 14:31:20 +04:00
mask | = POLLIN | POLLRDNORM ;
2011-12-14 19:43:12 +04:00
if ( sk - > sk_state = = LLCP_CLOSED )
mask | = POLLHUP ;
2012-05-07 14:31:20 +04:00
if ( sk - > sk_shutdown & RCV_SHUTDOWN )
mask | = POLLRDHUP | POLLIN | POLLRDNORM ;
if ( sk - > sk_shutdown = = SHUTDOWN_MASK )
mask | = POLLHUP ;
if ( sock_writeable ( sk ) )
mask | = POLLOUT | POLLWRNORM | POLLWRBAND ;
else
set_bit ( SOCK_ASYNC_NOSPACE , & sk - > sk_socket - > flags ) ;
pr_debug ( " mask 0x%x \n " , mask ) ;
2011-12-14 19:43:12 +04:00
return mask ;
}
static int llcp_sock_release ( struct socket * sock )
{
struct sock * sk = sock - > sk ;
struct nfc_llcp_local * local ;
struct nfc_llcp_sock * llcp_sock = nfc_llcp_sock ( sk ) ;
2012-03-05 04:03:51 +04:00
int err = 0 ;
2011-12-14 19:43:12 +04:00
if ( ! sk )
return 0 ;
pr_debug ( " %p \n " , sk ) ;
local = llcp_sock - > local ;
2012-03-05 04:03:51 +04:00
if ( local = = NULL ) {
err = - ENODEV ;
goto out ;
}
2011-12-14 19:43:12 +04:00
lock_sock ( sk ) ;
/* Send a DISC */
if ( sk - > sk_state = = LLCP_CONNECTED )
nfc_llcp_disconnect ( llcp_sock ) ;
if ( sk - > sk_state = = LLCP_LISTEN ) {
struct nfc_llcp_sock * lsk , * n ;
struct sock * accept_sk ;
list_for_each_entry_safe ( lsk , n , & llcp_sock - > accept_queue ,
2012-03-05 04:03:52 +04:00
accept_queue ) {
2011-12-14 19:43:12 +04:00
accept_sk = & lsk - > sk ;
lock_sock ( accept_sk ) ;
nfc_llcp_disconnect ( lsk ) ;
nfc_llcp_accept_unlink ( accept_sk ) ;
release_sock ( accept_sk ) ;
sock_orphan ( accept_sk ) ;
}
}
2012-06-22 16:48:11 +04:00
if ( llcp_sock - > reserved_ssap < LLCP_SAP_MAX )
nfc_llcp_put_ssap ( llcp_sock - > local , llcp_sock - > ssap ) ;
2011-12-14 19:43:12 +04:00
release_sock ( sk ) ;
2012-09-26 20:16:44 +04:00
if ( sock - > type = = SOCK_RAW )
nfc_llcp_sock_unlink ( & local - > raw_sockets , sk ) ;
else
nfc_llcp_sock_unlink ( & local - > sockets , sk ) ;
2012-05-04 19:04:19 +04:00
2012-03-05 04:03:51 +04:00
out :
2011-12-14 19:43:12 +04:00
sock_orphan ( sk ) ;
sock_put ( sk ) ;
2012-03-05 04:03:51 +04:00
return err ;
2011-12-14 19:43:12 +04:00
}
static int llcp_sock_connect ( struct socket * sock , struct sockaddr * _addr ,
2012-03-05 04:03:52 +04:00
int len , int flags )
2011-12-14 19:43:12 +04:00
{
struct sock * sk = sock - > sk ;
struct nfc_llcp_sock * llcp_sock = nfc_llcp_sock ( sk ) ;
struct sockaddr_nfc_llcp * addr = ( struct sockaddr_nfc_llcp * ) _addr ;
struct nfc_dev * dev ;
struct nfc_llcp_local * local ;
int ret = 0 ;
pr_debug ( " sock %p sk %p flags 0x%x \n " , sock , sk , flags ) ;
if ( ! addr | | len < sizeof ( struct sockaddr_nfc ) | |
2012-10-04 13:51:11 +04:00
addr - > sa_family ! = AF_NFC )
2011-12-14 19:43:12 +04:00
return - EINVAL ;
2012-10-04 13:51:11 +04:00
if ( addr - > service_name_len = = 0 & & addr - > dsap = = 0 )
2011-12-14 19:43:12 +04:00
return - EINVAL ;
pr_debug ( " addr dev_idx=%u target_idx=%u protocol=%u \n " , addr - > dev_idx ,
2012-03-05 04:03:52 +04:00
addr - > target_idx , addr - > nfc_protocol ) ;
2011-12-14 19:43:12 +04:00
lock_sock ( sk ) ;
if ( sk - > sk_state = = LLCP_CONNECTED ) {
ret = - EISCONN ;
goto error ;
}
dev = nfc_get_device ( addr - > dev_idx ) ;
if ( dev = = NULL ) {
ret = - ENODEV ;
goto error ;
}
local = nfc_llcp_find_local ( dev ) ;
if ( local = = NULL ) {
ret = - ENODEV ;
goto put_dev ;
}
device_lock ( & dev - > dev ) ;
if ( dev - > dep_link_up = = false ) {
ret = - ENOLINK ;
device_unlock ( & dev - > dev ) ;
goto put_dev ;
}
device_unlock ( & dev - > dev ) ;
if ( local - > rf_mode = = NFC_RF_INITIATOR & &
2012-03-05 04:03:52 +04:00
addr - > target_idx ! = local - > target_idx ) {
2011-12-14 19:43:12 +04:00
ret = - ENOLINK ;
goto put_dev ;
}
llcp_sock - > dev = dev ;
2012-05-04 13:24:16 +04:00
llcp_sock - > local = nfc_llcp_local_get ( local ) ;
2012-05-14 19:37:32 +04:00
llcp_sock - > miu = llcp_sock - > local - > remote_miu ;
2011-12-14 19:43:12 +04:00
llcp_sock - > ssap = nfc_llcp_get_local_ssap ( local ) ;
if ( llcp_sock - > ssap = = LLCP_SAP_MAX ) {
ret = - ENOMEM ;
goto put_dev ;
}
2012-06-22 16:48:11 +04:00
llcp_sock - > reserved_ssap = llcp_sock - > ssap ;
2011-12-14 19:43:12 +04:00
if ( addr - > service_name_len = = 0 )
llcp_sock - > dsap = addr - > dsap ;
else
llcp_sock - > dsap = LLCP_SAP_SDP ;
llcp_sock - > nfc_protocol = addr - > nfc_protocol ;
llcp_sock - > service_name_len = min_t ( unsigned int ,
2012-03-05 04:03:52 +04:00
addr - > service_name_len ,
NFC_LLCP_MAX_SERVICE_NAME ) ;
2011-12-14 19:43:12 +04:00
llcp_sock - > service_name = kmemdup ( addr - > service_name ,
2012-03-05 04:03:52 +04:00
llcp_sock - > service_name_len ,
GFP_KERNEL ) ;
2011-12-14 19:43:12 +04:00
2012-05-04 19:04:19 +04:00
nfc_llcp_sock_link ( & local - > connecting_sockets , sk ) ;
2011-12-14 19:43:12 +04:00
ret = nfc_llcp_send_connect ( llcp_sock ) ;
if ( ret )
2012-05-04 19:04:19 +04:00
goto sock_unlink ;
2011-12-14 19:43:12 +04:00
2012-05-07 14:31:19 +04:00
ret = sock_wait_state ( sk , LLCP_CONNECTED ,
sock_sndtimeo ( sk , flags & O_NONBLOCK ) ) ;
if ( ret )
2012-05-04 19:04:19 +04:00
goto sock_unlink ;
2011-12-14 19:43:12 +04:00
release_sock ( sk ) ;
2012-05-07 14:31:19 +04:00
2011-12-14 19:43:12 +04:00
return 0 ;
2012-05-04 19:04:19 +04:00
sock_unlink :
nfc_llcp_put_ssap ( local , llcp_sock - > ssap ) ;
nfc_llcp_sock_unlink ( & local - > connecting_sockets , sk ) ;
2011-12-14 19:43:12 +04:00
put_dev :
nfc_put_device ( dev ) ;
error :
release_sock ( sk ) ;
return ret ;
}
2012-03-05 04:03:37 +04:00
static int llcp_sock_sendmsg ( struct kiocb * iocb , struct socket * sock ,
2012-03-05 04:03:52 +04:00
struct msghdr * msg , size_t len )
2012-03-05 04:03:37 +04:00
{
struct sock * sk = sock - > sk ;
struct nfc_llcp_sock * llcp_sock = nfc_llcp_sock ( sk ) ;
int ret ;
pr_debug ( " sock %p sk %p " , sock , sk ) ;
ret = sock_error ( sk ) ;
if ( ret )
return ret ;
if ( msg - > msg_flags & MSG_OOB )
return - EOPNOTSUPP ;
lock_sock ( sk ) ;
if ( sk - > sk_state ! = LLCP_CONNECTED ) {
release_sock ( sk ) ;
return - ENOTCONN ;
}
release_sock ( sk ) ;
return nfc_llcp_send_i_frame ( llcp_sock , msg , len ) ;
}
2011-12-14 19:43:12 +04:00
static int llcp_sock_recvmsg ( struct kiocb * iocb , struct socket * sock ,
struct msghdr * msg , size_t len , int flags )
{
int noblock = flags & MSG_DONTWAIT ;
struct sock * sk = sock - > sk ;
unsigned int copied , rlen ;
struct sk_buff * skb , * cskb ;
int err = 0 ;
pr_debug ( " %p %zu \n " , sk , len ) ;
lock_sock ( sk ) ;
if ( sk - > sk_state = = LLCP_CLOSED & &
2012-03-05 04:03:52 +04:00
skb_queue_empty ( & sk - > sk_receive_queue ) ) {
2011-12-14 19:43:12 +04:00
release_sock ( sk ) ;
return 0 ;
}
release_sock ( sk ) ;
if ( flags & ( MSG_OOB ) )
return - EOPNOTSUPP ;
skb = skb_recv_datagram ( sk , flags , noblock , & err ) ;
if ( ! skb ) {
pr_err ( " Recv datagram failed state %d %d %d " ,
2012-03-05 04:03:52 +04:00
sk - > sk_state , err , sock_error ( sk ) ) ;
2011-12-14 19:43:12 +04:00
if ( sk - > sk_shutdown & RCV_SHUTDOWN )
return 0 ;
return err ;
}
2012-03-05 04:03:52 +04:00
rlen = skb - > len ; /* real length of skb */
2011-12-14 19:43:12 +04:00
copied = min_t ( unsigned int , rlen , len ) ;
cskb = skb ;
if ( memcpy_toiovec ( msg - > msg_iov , cskb - > data , copied ) ) {
if ( ! ( flags & MSG_PEEK ) )
skb_queue_head ( & sk - > sk_receive_queue , skb ) ;
return - EFAULT ;
}
/* Mark read part of skb as used */
if ( ! ( flags & MSG_PEEK ) ) {
/* SOCK_STREAM: re-queue skb if it contains unreceived data */
2012-09-26 20:16:44 +04:00
if ( sk - > sk_type = = SOCK_STREAM | | sk - > sk_type = = SOCK_RAW ) {
2011-12-14 19:43:12 +04:00
skb_pull ( skb , copied ) ;
if ( skb - > len ) {
skb_queue_head ( & sk - > sk_receive_queue , skb ) ;
goto done ;
}
}
kfree_skb ( skb ) ;
}
/* XXX Queue backlogged skbs */
done :
/* SOCK_SEQPACKET: return real length if MSG_TRUNC is set */
if ( sk - > sk_type = = SOCK_SEQPACKET & & ( flags & MSG_TRUNC ) )
copied = rlen ;
return copied ;
}
static const struct proto_ops llcp_sock_ops = {
. family = PF_NFC ,
. owner = THIS_MODULE ,
. bind = llcp_sock_bind ,
. connect = llcp_sock_connect ,
. release = llcp_sock_release ,
. socketpair = sock_no_socketpair ,
. accept = llcp_sock_accept ,
. getname = llcp_sock_getname ,
. poll = llcp_sock_poll ,
. ioctl = sock_no_ioctl ,
. listen = llcp_sock_listen ,
. shutdown = sock_no_shutdown ,
. setsockopt = sock_no_setsockopt ,
. getsockopt = sock_no_getsockopt ,
2012-03-05 04:03:37 +04:00
. sendmsg = llcp_sock_sendmsg ,
2011-12-14 19:43:12 +04:00
. recvmsg = llcp_sock_recvmsg ,
. mmap = sock_no_mmap ,
} ;
2012-09-26 20:16:44 +04:00
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 ,
} ;
2011-12-14 19:43:12 +04:00
static void llcp_sock_destruct ( struct sock * sk )
{
struct nfc_llcp_sock * llcp_sock = nfc_llcp_sock ( sk ) ;
pr_debug ( " %p \n " , sk ) ;
if ( sk - > sk_state = = LLCP_CONNECTED )
nfc_put_device ( llcp_sock - > dev ) ;
skb_queue_purge ( & sk - > sk_receive_queue ) ;
nfc_llcp_sock_free ( llcp_sock ) ;
if ( ! sock_flag ( sk , SOCK_DEAD ) ) {
pr_err ( " Freeing alive NFC LLCP socket %p \n " , sk ) ;
return ;
}
}
struct sock * nfc_llcp_sock_alloc ( struct socket * sock , int type , gfp_t gfp )
{
struct sock * sk ;
struct nfc_llcp_sock * llcp_sock ;
sk = sk_alloc ( & init_net , PF_NFC , gfp , & llcp_sock_proto ) ;
if ( ! sk )
return NULL ;
llcp_sock = nfc_llcp_sock ( sk ) ;
sock_init_data ( sock , sk ) ;
sk - > sk_state = LLCP_CLOSED ;
sk - > sk_protocol = NFC_SOCKPROTO_LLCP ;
sk - > sk_type = type ;
sk - > sk_destruct = llcp_sock_destruct ;
llcp_sock - > ssap = 0 ;
llcp_sock - > dsap = LLCP_SAP_SDP ;
2012-05-08 00:03:34 +04:00
llcp_sock - > rw = LLCP_DEFAULT_RW ;
2012-05-14 19:37:32 +04:00
llcp_sock - > miu = LLCP_DEFAULT_MIU ;
2011-12-14 19:43:12 +04:00
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 ;
2012-06-22 16:48:11 +04:00
llcp_sock - > reserved_ssap = LLCP_SAP_MAX ;
2011-12-14 19:43:12 +04:00
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 - > accept_queue ) ;
if ( sock ! = NULL )
sock - > state = SS_UNCONNECTED ;
return sk ;
}
void nfc_llcp_sock_free ( struct nfc_llcp_sock * sock )
{
kfree ( sock - > service_name ) ;
skb_queue_purge ( & sock - > tx_queue ) ;
skb_queue_purge ( & sock - > tx_pending_queue ) ;
skb_queue_purge ( & sock - > tx_backlog_queue ) ;
list_del_init ( & sock - > accept_queue ) ;
2012-03-05 04:03:51 +04:00
2011-12-14 19:43:12 +04:00
sock - > parent = NULL ;
2012-05-04 13:24:16 +04:00
nfc_llcp_local_put ( sock - > local ) ;
2011-12-14 19:43:12 +04:00
}
static int llcp_sock_create ( struct net * net , struct socket * sock ,
2012-03-05 04:03:52 +04:00
const struct nfc_protocol * nfc_proto )
2011-12-14 19:43:12 +04:00
{
struct sock * sk ;
pr_debug ( " %p \n " , sock ) ;
2012-09-26 20:16:44 +04:00
if ( sock - > type ! = SOCK_STREAM & &
sock - > type ! = SOCK_DGRAM & &
sock - > type ! = SOCK_RAW )
2011-12-14 19:43:12 +04:00
return - ESOCKTNOSUPPORT ;
2012-09-26 20:16:44 +04:00
if ( sock - > type = = SOCK_RAW )
sock - > ops = & llcp_rawsock_ops ;
else
sock - > ops = & llcp_sock_ops ;
2011-12-14 19:43:12 +04:00
sk = nfc_llcp_sock_alloc ( sock , sock - > type , GFP_ATOMIC ) ;
if ( sk = = NULL )
return - ENOMEM ;
return 0 ;
}
static const struct nfc_protocol llcp_nfc_proto = {
. id = NFC_SOCKPROTO_LLCP ,
. proto = & llcp_sock_proto ,
. owner = THIS_MODULE ,
. create = llcp_sock_create
} ;
int __init nfc_llcp_sock_init ( void )
{
return nfc_proto_register ( & llcp_nfc_proto ) ;
}
void nfc_llcp_sock_exit ( void )
{
nfc_proto_unregister ( & llcp_nfc_proto ) ;
}