2019-05-19 16:51:43 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
2011-12-14 19:43:12 +04:00
/*
* Copyright ( C ) 2011 Intel Corporation . All rights reserved .
*/
# 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 <net/nfc/nfc.h>
2013-04-26 13:49:40 +04:00
# include "nfc.h"
2011-12-14 19:43:12 +04:00
# include "llcp.h"
static u8 llcp_tlv_length [ LLCP_TLV_MAX ] = {
0 ,
1 , /* VERSION */
2 , /* MIUX */
2 , /* WKS */
1 , /* LTO */
1 , /* RW */
0 , /* SN */
1 , /* OPT */
0 , /* SDREQ */
2 , /* SDRES */
} ;
static u8 llcp_tlv8 ( u8 * tlv , u8 type )
{
if ( tlv [ 0 ] ! = type | | tlv [ 1 ] ! = llcp_tlv_length [ tlv [ 0 ] ] )
return 0 ;
return tlv [ 2 ] ;
}
2012-05-14 19:38:54 +04:00
static u16 llcp_tlv16 ( u8 * tlv , u8 type )
2011-12-14 19:43:12 +04:00
{
if ( tlv [ 0 ] ! = type | | tlv [ 1 ] ! = llcp_tlv_length [ tlv [ 0 ] ] )
return 0 ;
return be16_to_cpu ( * ( ( __be16 * ) ( tlv + 2 ) ) ) ;
}
static u8 llcp_tlv_version ( u8 * tlv )
{
return llcp_tlv8 ( tlv , LLCP_TLV_VERSION ) ;
}
static u16 llcp_tlv_miux ( u8 * tlv )
{
2012-05-14 19:38:54 +04:00
return llcp_tlv16 ( tlv , LLCP_TLV_MIUX ) & 0x7ff ;
2011-12-14 19:43:12 +04:00
}
static u16 llcp_tlv_wks ( u8 * tlv )
{
return llcp_tlv16 ( tlv , LLCP_TLV_WKS ) ;
}
static u16 llcp_tlv_lto ( u8 * tlv )
{
return llcp_tlv8 ( tlv , LLCP_TLV_LTO ) ;
}
static u8 llcp_tlv_opt ( u8 * tlv )
{
return llcp_tlv8 ( tlv , LLCP_TLV_OPT ) ;
}
static u8 llcp_tlv_rw ( u8 * tlv )
{
return llcp_tlv8 ( tlv , LLCP_TLV_RW ) & 0xf ;
}
u8 * nfc_llcp_build_tlv ( u8 type , u8 * value , u8 value_length , u8 * tlv_length )
{
u8 * tlv , length ;
pr_debug ( " type %d \n " , type ) ;
if ( type > = LLCP_TLV_MAX )
return NULL ;
length = llcp_tlv_length [ type ] ;
if ( length = = 0 & & value_length = = 0 )
return NULL ;
2012-04-10 21:43:15 +04:00
else if ( length = = 0 )
2011-12-14 19:43:12 +04:00
length = value_length ;
* tlv_length = 2 + length ;
tlv = kzalloc ( 2 + length , GFP_KERNEL ) ;
if ( tlv = = NULL )
return tlv ;
tlv [ 0 ] = type ;
tlv [ 1 ] = length ;
memcpy ( tlv + 2 , value , length ) ;
return tlv ;
}
2013-02-15 13:43:05 +04:00
struct nfc_llcp_sdp_tlv * nfc_llcp_build_sdres_tlv ( u8 tid , u8 sap )
{
struct nfc_llcp_sdp_tlv * sdres ;
u8 value [ 2 ] ;
sdres = kzalloc ( sizeof ( struct nfc_llcp_sdp_tlv ) , GFP_KERNEL ) ;
if ( sdres = = NULL )
return NULL ;
value [ 0 ] = tid ;
value [ 1 ] = sap ;
sdres - > tlv = nfc_llcp_build_tlv ( LLCP_TLV_SDRES , value , 2 ,
& sdres - > tlv_len ) ;
if ( sdres - > tlv = = NULL ) {
kfree ( sdres ) ;
return NULL ;
}
sdres - > tid = tid ;
sdres - > sap = sap ;
INIT_HLIST_NODE ( & sdres - > node ) ;
return sdres ;
}
2013-02-15 13:43:06 +04:00
struct nfc_llcp_sdp_tlv * nfc_llcp_build_sdreq_tlv ( u8 tid , char * uri ,
size_t uri_len )
{
struct nfc_llcp_sdp_tlv * sdreq ;
pr_debug ( " uri: %s, len: %zu \n " , uri , uri_len ) ;
2018-02-15 02:45:07 +03:00
/* sdreq->tlv_len is u8, takes uri_len, + 3 for header, + 1 for NULL */
if ( WARN_ON_ONCE ( uri_len > U8_MAX - 4 ) )
return NULL ;
2013-02-15 13:43:06 +04:00
sdreq = kzalloc ( sizeof ( struct nfc_llcp_sdp_tlv ) , GFP_KERNEL ) ;
if ( sdreq = = NULL )
return NULL ;
sdreq - > tlv_len = uri_len + 3 ;
if ( uri [ uri_len - 1 ] = = 0 )
sdreq - > tlv_len - - ;
sdreq - > tlv = kzalloc ( sdreq - > tlv_len + 1 , GFP_KERNEL ) ;
if ( sdreq - > tlv = = NULL ) {
kfree ( sdreq ) ;
return NULL ;
}
sdreq - > tlv [ 0 ] = LLCP_TLV_SDREQ ;
sdreq - > tlv [ 1 ] = sdreq - > tlv_len - 2 ;
sdreq - > tlv [ 2 ] = tid ;
sdreq - > tid = tid ;
sdreq - > uri = sdreq - > tlv + 3 ;
memcpy ( sdreq - > uri , uri , uri_len ) ;
2013-03-04 18:43:32 +04:00
sdreq - > time = jiffies ;
2013-02-15 13:43:06 +04:00
INIT_HLIST_NODE ( & sdreq - > node ) ;
return sdreq ;
}
2013-02-15 13:43:05 +04:00
void nfc_llcp_free_sdp_tlv ( struct nfc_llcp_sdp_tlv * sdp )
{
kfree ( sdp - > tlv ) ;
kfree ( sdp ) ;
}
2013-02-15 13:43:06 +04:00
void nfc_llcp_free_sdp_tlv_list ( struct hlist_head * head )
{
struct nfc_llcp_sdp_tlv * sdp ;
struct hlist_node * n ;
hlist_for_each_entry_safe ( sdp , n , head , node ) {
hlist_del ( & sdp - > node ) ;
nfc_llcp_free_sdp_tlv ( sdp ) ;
}
}
2012-05-08 00:03:34 +04:00
int nfc_llcp_parse_gb_tlv ( struct nfc_llcp_local * local ,
u8 * tlv_array , u16 tlv_array_len )
2011-12-14 19:43:12 +04:00
{
u8 * tlv = tlv_array , type , length , offset = 0 ;
pr_debug ( " TLV array length %d \n " , tlv_array_len ) ;
if ( local = = NULL )
return - ENODEV ;
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_VERSION :
local - > remote_version = llcp_tlv_version ( tlv ) ;
break ;
case LLCP_TLV_MIUX :
local - > remote_miu = llcp_tlv_miux ( tlv ) + 128 ;
break ;
case LLCP_TLV_WKS :
local - > remote_wks = llcp_tlv_wks ( tlv ) ;
break ;
case LLCP_TLV_LTO :
local - > remote_lto = llcp_tlv_lto ( tlv ) * 10 ;
break ;
case LLCP_TLV_OPT :
local - > remote_opt = llcp_tlv_opt ( tlv ) ;
break ;
2012-05-08 00:03:34 +04:00
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 ) {
2012-05-14 19:37:32 +04:00
case LLCP_TLV_MIUX :
2013-02-22 04:12:28 +04:00
sock - > remote_miu = llcp_tlv_miux ( tlv ) + 128 ;
2012-05-14 19:37:32 +04:00
break ;
2011-12-14 19:43:12 +04:00
case LLCP_TLV_RW :
2013-02-22 04:12:28 +04:00
sock - > remote_rw = llcp_tlv_rw ( tlv ) ;
2011-12-14 19:43:12 +04:00
break ;
2012-03-05 04:03:49 +04:00
case LLCP_TLV_SN :
break ;
2011-12-14 19:43:12 +04:00
default :
pr_err ( " Invalid gt tlv value 0x%x \n " , type ) ;
break ;
}
offset + = length + 2 ;
tlv + = length + 2 ;
}
2013-02-22 04:12:28 +04:00
pr_debug ( " sock %p rw %d miu %d \n " , sock ,
sock - > remote_rw , sock - > remote_miu ) ;
2011-12-14 19:43:12 +04:00
return 0 ;
}
static struct sk_buff * llcp_add_header ( struct sk_buff * pdu ,
2012-03-05 04:03:52 +04:00
u8 dsap , u8 ssap , u8 ptype )
2011-12-14 19:43:12 +04:00
{
u8 header [ 2 ] ;
pr_debug ( " ptype 0x%x dsap 0x%x ssap 0x%x \n " , ptype , dsap , ssap ) ;
header [ 0 ] = ( u8 ) ( ( dsap < < 2 ) | ( ptype > > 2 ) ) ;
header [ 1 ] = ( u8 ) ( ( ptype < < 6 ) | ssap ) ;
pr_debug ( " header 0x%x 0x%x \n " , header [ 0 ] , header [ 1 ] ) ;
networking: introduce and use skb_put_data()
A common pattern with skb_put() is to just want to memcpy()
some data into the new space, introduce skb_put_data() for
this.
An spatch similar to the one for skb_put_zero() converts many
of the places using it:
@@
identifier p, p2;
expression len, skb, data;
type t, t2;
@@
(
-p = skb_put(skb, len);
+p = skb_put_data(skb, data, len);
|
-p = (t)skb_put(skb, len);
+p = skb_put_data(skb, data, len);
)
(
p2 = (t2)p;
-memcpy(p2, data, len);
|
-memcpy(p, data, len);
)
@@
type t, t2;
identifier p, p2;
expression skb, data;
@@
t *p;
...
(
-p = skb_put(skb, sizeof(t));
+p = skb_put_data(skb, data, sizeof(t));
|
-p = (t *)skb_put(skb, sizeof(t));
+p = skb_put_data(skb, data, sizeof(t));
)
(
p2 = (t2)p;
-memcpy(p2, data, sizeof(*p));
|
-memcpy(p, data, sizeof(*p));
)
@@
expression skb, len, data;
@@
-memcpy(skb_put(skb, len), data, len);
+skb_put_data(skb, data, len);
(again, manually post-processed to retain some comments)
Reviewed-by: Stephen Hemminger <stephen@networkplumber.org>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-06-16 15:29:20 +03:00
skb_put_data ( pdu , header , LLCP_HEADER_SIZE ) ;
2011-12-14 19:43:12 +04:00
return pdu ;
}
2012-03-05 04:03:52 +04:00
static struct sk_buff * llcp_add_tlv ( struct sk_buff * pdu , u8 * tlv ,
u8 tlv_length )
2011-12-14 19:43:12 +04:00
{
/* XXX Add an skb length check */
if ( tlv = = NULL )
return NULL ;
networking: introduce and use skb_put_data()
A common pattern with skb_put() is to just want to memcpy()
some data into the new space, introduce skb_put_data() for
this.
An spatch similar to the one for skb_put_zero() converts many
of the places using it:
@@
identifier p, p2;
expression len, skb, data;
type t, t2;
@@
(
-p = skb_put(skb, len);
+p = skb_put_data(skb, data, len);
|
-p = (t)skb_put(skb, len);
+p = skb_put_data(skb, data, len);
)
(
p2 = (t2)p;
-memcpy(p2, data, len);
|
-memcpy(p, data, len);
)
@@
type t, t2;
identifier p, p2;
expression skb, data;
@@
t *p;
...
(
-p = skb_put(skb, sizeof(t));
+p = skb_put_data(skb, data, sizeof(t));
|
-p = (t *)skb_put(skb, sizeof(t));
+p = skb_put_data(skb, data, sizeof(t));
)
(
p2 = (t2)p;
-memcpy(p2, data, sizeof(*p));
|
-memcpy(p, data, sizeof(*p));
)
@@
expression skb, len, data;
@@
-memcpy(skb_put(skb, len), data, len);
+skb_put_data(skb, data, len);
(again, manually post-processed to retain some comments)
Reviewed-by: Stephen Hemminger <stephen@networkplumber.org>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-06-16 15:29:20 +03:00
skb_put_data ( pdu , tlv , tlv_length ) ;
2011-12-14 19:43:12 +04:00
return pdu ;
}
static struct sk_buff * llcp_allocate_pdu ( struct nfc_llcp_sock * sock ,
2012-03-05 04:03:52 +04:00
u8 cmd , u16 size )
2011-12-14 19:43:12 +04:00
{
struct sk_buff * skb ;
int err ;
if ( sock - > ssap = = 0 )
return NULL ;
skb = nfc_alloc_send_skb ( sock - > dev , & sock - > sk , MSG_DONTWAIT ,
2012-03-05 04:03:52 +04:00
size + LLCP_HEADER_SIZE , & err ) ;
2011-12-14 19:43:12 +04:00
if ( skb = = NULL ) {
pr_err ( " Could not allocate PDU \n " ) ;
return NULL ;
}
skb = llcp_add_header ( skb , sock - > dsap , sock - > ssap , cmd ) ;
return skb ;
}
2013-06-04 13:34:50 +04:00
int nfc_llcp_send_disconnect ( struct nfc_llcp_sock * sock )
2011-12-14 19:43:12 +04:00
{
struct sk_buff * skb ;
struct nfc_dev * dev ;
struct nfc_llcp_local * local ;
pr_debug ( " Sending DISC \n " ) ;
local = sock - > local ;
if ( local = = NULL )
return - ENODEV ;
dev = sock - > dev ;
if ( dev = = NULL )
return - ENODEV ;
2012-10-05 03:09:07 +04:00
skb = llcp_allocate_pdu ( sock , LLCP_PDU_DISC , 0 ) ;
2011-12-14 19:43:12 +04:00
if ( skb = = NULL )
return - ENOMEM ;
skb_queue_tail ( & local - > tx_queue , skb ) ;
return 0 ;
}
int nfc_llcp_send_symm ( struct nfc_dev * dev )
{
struct sk_buff * skb ;
struct nfc_llcp_local * local ;
u16 size = 0 ;
pr_debug ( " Sending SYMM \n " ) ;
local = nfc_llcp_find_local ( dev ) ;
if ( local = = NULL )
return - ENODEV ;
size + = LLCP_HEADER_SIZE ;
size + = dev - > tx_headroom + dev - > tx_tailroom + NFC_HEADER_SIZE ;
skb = alloc_skb ( size , GFP_KERNEL ) ;
if ( skb = = NULL )
return - ENOMEM ;
skb_reserve ( skb , dev - > tx_headroom + NFC_HEADER_SIZE ) ;
skb = llcp_add_header ( skb , 0 , 0 , LLCP_PDU_SYMM ) ;
2012-11-27 18:44:24 +04:00
__net_timestamp ( skb ) ;
2014-05-05 14:43:31 +04:00
nfc_llcp_send_to_raw_sock ( local , skb , NFC_DIRECTION_TX ) ;
2012-09-26 20:16:44 +04:00
2011-12-14 19:43:12 +04:00
return nfc_data_exchange ( dev , local - > target_idx , skb ,
2012-03-05 04:03:52 +04:00
nfc_llcp_recv , local ) ;
2011-12-14 19:43:12 +04:00
}
int nfc_llcp_send_connect ( struct nfc_llcp_sock * sock )
{
struct nfc_llcp_local * local ;
struct sk_buff * skb ;
u8 * service_name_tlv = NULL , service_name_tlv_length ;
2012-03-05 04:03:43 +04:00
u8 * miux_tlv = NULL , miux_tlv_length ;
2013-02-22 14:38:05 +04:00
u8 * rw_tlv = NULL , rw_tlv_length , rw ;
2011-12-14 19:43:12 +04:00
int err ;
2014-12-02 23:27:57 +03:00
u16 size = 0 ;
__be16 miux ;
2011-12-14 19:43:12 +04:00
pr_debug ( " Sending CONNECT \n " ) ;
local = sock - > local ;
if ( local = = NULL )
return - ENODEV ;
if ( sock - > service_name ! = NULL ) {
service_name_tlv = nfc_llcp_build_tlv ( LLCP_TLV_SN ,
2012-03-05 04:03:52 +04:00
sock - > service_name ,
sock - > service_name_len ,
& service_name_tlv_length ) ;
2019-02-22 10:37:58 +03:00
if ( ! service_name_tlv ) {
err = - ENOMEM ;
goto error_tlv ;
}
2011-12-14 19:43:12 +04:00
size + = service_name_tlv_length ;
}
2013-02-22 14:38:05 +04:00
/* If the socket parameters are not set, use the local ones */
2013-03-20 19:06:12 +04:00
miux = be16_to_cpu ( sock - > miux ) > LLCP_MAX_MIUX ?
local - > miux : sock - > miux ;
2013-02-22 14:38:05 +04:00
rw = sock - > rw > LLCP_MAX_RW ? local - > rw : sock - > rw ;
miux_tlv = nfc_llcp_build_tlv ( LLCP_TLV_MIUX , ( u8 * ) & miux , 0 ,
2012-03-05 04:03:52 +04:00
& miux_tlv_length ) ;
2019-02-22 10:37:58 +03:00
if ( ! miux_tlv ) {
err = - ENOMEM ;
goto error_tlv ;
}
2012-03-05 04:03:43 +04:00
size + = miux_tlv_length ;
2013-02-22 14:38:05 +04:00
rw_tlv = nfc_llcp_build_tlv ( LLCP_TLV_RW , & rw , 0 , & rw_tlv_length ) ;
2019-02-22 10:37:58 +03:00
if ( ! rw_tlv ) {
err = - ENOMEM ;
goto error_tlv ;
}
2012-03-05 04:03:43 +04:00
size + = rw_tlv_length ;
2011-12-14 19:43:12 +04:00
pr_debug ( " SKB size %d SN length %zu \n " , size , sock - > service_name_len ) ;
skb = llcp_allocate_pdu ( sock , LLCP_PDU_CONNECT , size ) ;
if ( skb = = NULL ) {
err = - ENOMEM ;
goto error_tlv ;
}
2016-06-29 11:48:22 +03:00
llcp_add_tlv ( skb , service_name_tlv , service_name_tlv_length ) ;
llcp_add_tlv ( skb , miux_tlv , miux_tlv_length ) ;
llcp_add_tlv ( skb , rw_tlv , rw_tlv_length ) ;
2012-03-05 04:03:43 +04:00
2011-12-14 19:43:12 +04:00
skb_queue_tail ( & local - > tx_queue , skb ) ;
2016-06-29 11:48:23 +03:00
err = 0 ;
2011-12-14 19:43:12 +04:00
error_tlv :
2016-06-29 11:48:23 +03:00
if ( err )
pr_err ( " error %d \n " , err ) ;
2011-12-14 19:43:12 +04:00
kfree ( service_name_tlv ) ;
2012-03-05 04:03:43 +04:00
kfree ( miux_tlv ) ;
kfree ( rw_tlv ) ;
2011-12-14 19:43:12 +04:00
return err ;
}
int nfc_llcp_send_cc ( struct nfc_llcp_sock * sock )
{
struct nfc_llcp_local * local ;
struct sk_buff * skb ;
2012-03-05 04:03:43 +04:00
u8 * miux_tlv = NULL , miux_tlv_length ;
2013-02-22 14:38:05 +04:00
u8 * rw_tlv = NULL , rw_tlv_length , rw ;
2012-03-05 04:03:43 +04:00
int err ;
2014-12-02 23:27:57 +03:00
u16 size = 0 ;
__be16 miux ;
2011-12-14 19:43:12 +04:00
pr_debug ( " Sending CC \n " ) ;
local = sock - > local ;
if ( local = = NULL )
return - ENODEV ;
2013-02-22 14:38:05 +04:00
/* If the socket parameters are not set, use the local ones */
2013-03-20 19:06:12 +04:00
miux = be16_to_cpu ( sock - > miux ) > LLCP_MAX_MIUX ?
local - > miux : sock - > miux ;
2013-02-22 14:38:05 +04:00
rw = sock - > rw > LLCP_MAX_RW ? local - > rw : sock - > rw ;
miux_tlv = nfc_llcp_build_tlv ( LLCP_TLV_MIUX , ( u8 * ) & miux , 0 ,
2012-03-05 04:03:52 +04:00
& miux_tlv_length ) ;
2019-02-22 10:37:58 +03:00
if ( ! miux_tlv ) {
err = - ENOMEM ;
goto error_tlv ;
}
2012-03-05 04:03:43 +04:00
size + = miux_tlv_length ;
2013-02-22 14:38:05 +04:00
rw_tlv = nfc_llcp_build_tlv ( LLCP_TLV_RW , & rw , 0 , & rw_tlv_length ) ;
2019-02-22 10:37:58 +03:00
if ( ! rw_tlv ) {
err = - ENOMEM ;
goto error_tlv ;
}
2012-03-05 04:03:43 +04:00
size + = rw_tlv_length ;
skb = llcp_allocate_pdu ( sock , LLCP_PDU_CC , size ) ;
if ( skb = = NULL ) {
err = - ENOMEM ;
goto error_tlv ;
}
2016-06-29 11:48:22 +03:00
llcp_add_tlv ( skb , miux_tlv , miux_tlv_length ) ;
llcp_add_tlv ( skb , rw_tlv , rw_tlv_length ) ;
2011-12-14 19:43:12 +04:00
skb_queue_tail ( & local - > tx_queue , skb ) ;
2016-06-29 11:48:23 +03:00
err = 0 ;
2012-03-05 04:03:43 +04:00
error_tlv :
2016-06-29 11:48:23 +03:00
if ( err )
pr_err ( " error %d \n " , err ) ;
2012-03-05 04:03:43 +04:00
kfree ( miux_tlv ) ;
kfree ( rw_tlv ) ;
return err ;
2011-12-14 19:43:12 +04:00
}
2013-02-15 13:43:05 +04:00
static struct sk_buff * nfc_llcp_allocate_snl ( struct nfc_llcp_local * local ,
size_t tlv_length )
2012-10-05 03:13:24 +04:00
{
struct sk_buff * skb ;
struct nfc_dev * dev ;
u16 size = 0 ;
if ( local = = NULL )
2013-02-15 13:43:05 +04:00
return ERR_PTR ( - ENODEV ) ;
2012-10-05 03:13:24 +04:00
dev = local - > dev ;
if ( dev = = NULL )
2013-02-15 13:43:05 +04:00
return ERR_PTR ( - ENODEV ) ;
2012-10-05 03:13:24 +04:00
size + = LLCP_HEADER_SIZE ;
size + = dev - > tx_headroom + dev - > tx_tailroom + NFC_HEADER_SIZE ;
2013-02-15 13:43:05 +04:00
size + = tlv_length ;
2012-10-05 03:13:24 +04:00
skb = alloc_skb ( size , GFP_KERNEL ) ;
2013-02-15 13:43:05 +04:00
if ( skb = = NULL )
return ERR_PTR ( - ENOMEM ) ;
2012-10-05 03:13:24 +04:00
skb_reserve ( skb , dev - > tx_headroom + NFC_HEADER_SIZE ) ;
skb = llcp_add_header ( skb , LLCP_SAP_SDP , LLCP_SAP_SDP , LLCP_PDU_SNL ) ;
2013-02-15 13:43:05 +04:00
return skb ;
}
2012-10-05 03:13:24 +04:00
2013-02-15 13:43:05 +04:00
int nfc_llcp_send_snl_sdres ( struct nfc_llcp_local * local ,
struct hlist_head * tlv_list , size_t tlvs_len )
{
struct nfc_llcp_sdp_tlv * sdp ;
struct hlist_node * n ;
struct sk_buff * skb ;
skb = nfc_llcp_allocate_snl ( local , tlvs_len ) ;
if ( IS_ERR ( skb ) )
return PTR_ERR ( skb ) ;
hlist_for_each_entry_safe ( sdp , n , tlv_list , node ) {
networking: introduce and use skb_put_data()
A common pattern with skb_put() is to just want to memcpy()
some data into the new space, introduce skb_put_data() for
this.
An spatch similar to the one for skb_put_zero() converts many
of the places using it:
@@
identifier p, p2;
expression len, skb, data;
type t, t2;
@@
(
-p = skb_put(skb, len);
+p = skb_put_data(skb, data, len);
|
-p = (t)skb_put(skb, len);
+p = skb_put_data(skb, data, len);
)
(
p2 = (t2)p;
-memcpy(p2, data, len);
|
-memcpy(p, data, len);
)
@@
type t, t2;
identifier p, p2;
expression skb, data;
@@
t *p;
...
(
-p = skb_put(skb, sizeof(t));
+p = skb_put_data(skb, data, sizeof(t));
|
-p = (t *)skb_put(skb, sizeof(t));
+p = skb_put_data(skb, data, sizeof(t));
)
(
p2 = (t2)p;
-memcpy(p2, data, sizeof(*p));
|
-memcpy(p, data, sizeof(*p));
)
@@
expression skb, len, data;
@@
-memcpy(skb_put(skb, len), data, len);
+skb_put_data(skb, data, len);
(again, manually post-processed to retain some comments)
Reviewed-by: Stephen Hemminger <stephen@networkplumber.org>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-06-16 15:29:20 +03:00
skb_put_data ( skb , sdp - > tlv , sdp - > tlv_len ) ;
2012-10-05 03:13:24 +04:00
2013-02-15 13:43:05 +04:00
hlist_del ( & sdp - > node ) ;
nfc_llcp_free_sdp_tlv ( sdp ) ;
}
skb_queue_tail ( & local - > tx_queue , skb ) ;
2012-10-05 03:13:24 +04:00
return 0 ;
}
2013-02-15 13:43:06 +04:00
int nfc_llcp_send_snl_sdreq ( struct nfc_llcp_local * local ,
struct hlist_head * tlv_list , size_t tlvs_len )
{
struct nfc_llcp_sdp_tlv * sdreq ;
struct hlist_node * n ;
struct sk_buff * skb ;
skb = nfc_llcp_allocate_snl ( local , tlvs_len ) ;
if ( IS_ERR ( skb ) )
return PTR_ERR ( skb ) ;
mutex_lock ( & local - > sdreq_lock ) ;
2013-03-04 18:43:32 +04:00
if ( hlist_empty ( & local - > pending_sdreqs ) )
mod_timer ( & local - > sdreq_timer ,
jiffies + msecs_to_jiffies ( 3 * local - > remote_lto ) ) ;
2013-02-15 13:43:06 +04:00
hlist_for_each_entry_safe ( sdreq , n , tlv_list , node ) {
pr_debug ( " tid %d for %s \n " , sdreq - > tid , sdreq - > uri ) ;
networking: introduce and use skb_put_data()
A common pattern with skb_put() is to just want to memcpy()
some data into the new space, introduce skb_put_data() for
this.
An spatch similar to the one for skb_put_zero() converts many
of the places using it:
@@
identifier p, p2;
expression len, skb, data;
type t, t2;
@@
(
-p = skb_put(skb, len);
+p = skb_put_data(skb, data, len);
|
-p = (t)skb_put(skb, len);
+p = skb_put_data(skb, data, len);
)
(
p2 = (t2)p;
-memcpy(p2, data, len);
|
-memcpy(p, data, len);
)
@@
type t, t2;
identifier p, p2;
expression skb, data;
@@
t *p;
...
(
-p = skb_put(skb, sizeof(t));
+p = skb_put_data(skb, data, sizeof(t));
|
-p = (t *)skb_put(skb, sizeof(t));
+p = skb_put_data(skb, data, sizeof(t));
)
(
p2 = (t2)p;
-memcpy(p2, data, sizeof(*p));
|
-memcpy(p, data, sizeof(*p));
)
@@
expression skb, len, data;
@@
-memcpy(skb_put(skb, len), data, len);
+skb_put_data(skb, data, len);
(again, manually post-processed to retain some comments)
Reviewed-by: Stephen Hemminger <stephen@networkplumber.org>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-06-16 15:29:20 +03:00
skb_put_data ( skb , sdreq - > tlv , sdreq - > tlv_len ) ;
2013-02-15 13:43:06 +04:00
hlist_del ( & sdreq - > node ) ;
hlist_add_head ( & sdreq - > node , & local - > pending_sdreqs ) ;
}
mutex_unlock ( & local - > sdreq_lock ) ;
skb_queue_tail ( & local - > tx_queue , skb ) ;
return 0 ;
}
2011-12-14 19:43:12 +04:00
int nfc_llcp_send_dm ( struct nfc_llcp_local * local , u8 ssap , u8 dsap , u8 reason )
{
struct sk_buff * skb ;
struct nfc_dev * dev ;
u16 size = 1 ; /* Reason code */
pr_debug ( " Sending DM reason 0x%x \n " , reason ) ;
if ( local = = NULL )
return - ENODEV ;
dev = local - > dev ;
if ( dev = = NULL )
return - ENODEV ;
size + = LLCP_HEADER_SIZE ;
size + = dev - > tx_headroom + dev - > tx_tailroom + NFC_HEADER_SIZE ;
skb = alloc_skb ( size , GFP_KERNEL ) ;
if ( skb = = NULL )
return - ENOMEM ;
skb_reserve ( skb , dev - > tx_headroom + NFC_HEADER_SIZE ) ;
2012-04-10 21:43:16 +04:00
skb = llcp_add_header ( skb , dsap , ssap , LLCP_PDU_DM ) ;
2011-12-14 19:43:12 +04:00
networking: introduce and use skb_put_data()
A common pattern with skb_put() is to just want to memcpy()
some data into the new space, introduce skb_put_data() for
this.
An spatch similar to the one for skb_put_zero() converts many
of the places using it:
@@
identifier p, p2;
expression len, skb, data;
type t, t2;
@@
(
-p = skb_put(skb, len);
+p = skb_put_data(skb, data, len);
|
-p = (t)skb_put(skb, len);
+p = skb_put_data(skb, data, len);
)
(
p2 = (t2)p;
-memcpy(p2, data, len);
|
-memcpy(p, data, len);
)
@@
type t, t2;
identifier p, p2;
expression skb, data;
@@
t *p;
...
(
-p = skb_put(skb, sizeof(t));
+p = skb_put_data(skb, data, sizeof(t));
|
-p = (t *)skb_put(skb, sizeof(t));
+p = skb_put_data(skb, data, sizeof(t));
)
(
p2 = (t2)p;
-memcpy(p2, data, sizeof(*p));
|
-memcpy(p, data, sizeof(*p));
)
@@
expression skb, len, data;
@@
-memcpy(skb_put(skb, len), data, len);
+skb_put_data(skb, data, len);
(again, manually post-processed to retain some comments)
Reviewed-by: Stephen Hemminger <stephen@networkplumber.org>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-06-16 15:29:20 +03:00
skb_put_data ( skb , & reason , 1 ) ;
2011-12-14 19:43:12 +04:00
skb_queue_head ( & local - > tx_queue , skb ) ;
return 0 ;
}
2012-03-05 04:03:37 +04:00
int nfc_llcp_send_i_frame ( struct nfc_llcp_sock * sock ,
2012-03-05 04:03:52 +04:00
struct msghdr * msg , size_t len )
2012-03-05 04:03:37 +04:00
{
struct sk_buff * pdu ;
2012-03-05 04:03:44 +04:00
struct sock * sk = & sock - > sk ;
struct nfc_llcp_local * local ;
size_t frag_len = 0 , remaining_len ;
u8 * msg_data , * msg_ptr ;
2013-04-02 12:25:14 +04:00
u16 remote_miu ;
2012-03-05 04:03:37 +04:00
2012-03-05 04:03:44 +04:00
pr_debug ( " Send I frame len %zd \n " , len ) ;
2012-03-05 04:03:37 +04:00
2012-03-05 04:03:44 +04:00
local = sock - > local ;
if ( local = = NULL )
return - ENODEV ;
2012-03-05 04:03:37 +04:00
2012-11-02 02:33:00 +04:00
/* Remote is ready but has not acknowledged our frames */
if ( ( sock - > remote_ready & &
2013-02-22 04:12:28 +04:00
skb_queue_len ( & sock - > tx_pending_queue ) > = sock - > remote_rw & &
skb_queue_len ( & sock - > tx_queue ) > = 2 * sock - > remote_rw ) ) {
2012-11-02 02:33:00 +04:00
pr_err ( " Pending queue is full %d frames \n " ,
skb_queue_len ( & sock - > tx_pending_queue ) ) ;
return - ENOBUFS ;
}
/* Remote is not ready and we've been queueing enough frames */
if ( ( ! sock - > remote_ready & &
2013-02-22 04:12:28 +04:00
skb_queue_len ( & sock - > tx_queue ) > = 2 * sock - > remote_rw ) ) {
2012-11-02 02:33:00 +04:00
pr_err ( " Tx queue is full %d frames \n " ,
skb_queue_len ( & sock - > tx_queue ) ) ;
return - ENOBUFS ;
}
2016-01-29 22:24:24 +03:00
msg_data = kmalloc ( len , GFP_USER | __GFP_NOWARN ) ;
2012-03-05 04:03:44 +04:00
if ( msg_data = = NULL )
return - ENOMEM ;
2012-03-05 04:03:37 +04:00
2014-04-07 05:25:44 +04:00
if ( memcpy_from_msg ( msg_data , msg , len ) ) {
2012-03-05 04:03:52 +04:00
kfree ( msg_data ) ;
return - EFAULT ;
2012-03-05 04:03:37 +04:00
}
2012-03-05 04:03:44 +04:00
remaining_len = len ;
msg_ptr = msg_data ;
2013-03-25 14:24:21 +04:00
do {
2013-04-02 12:25:14 +04:00
remote_miu = sock - > remote_miu > LLCP_MAX_MIU ?
2013-11-30 19:59:23 +04:00
LLCP_DEFAULT_MIU : sock - > remote_miu ;
2013-04-02 12:25:14 +04:00
frag_len = min_t ( size_t , remote_miu , remaining_len ) ;
2012-03-05 04:03:37 +04:00
2012-03-05 04:03:44 +04:00
pr_debug ( " Fragment %zd bytes remaining %zd " ,
frag_len , remaining_len ) ;
2012-03-05 04:03:37 +04:00
2012-03-05 04:03:44 +04:00
pdu = llcp_allocate_pdu ( sock , LLCP_PDU_I ,
frag_len + LLCP_SEQUENCE_SIZE ) ;
2013-11-30 19:14:57 +04:00
if ( pdu = = NULL ) {
kfree ( msg_data ) ;
2012-03-05 04:03:44 +04:00
return - ENOMEM ;
2013-11-30 19:14:57 +04:00
}
2012-03-05 04:03:44 +04:00
skb_put ( pdu , LLCP_SEQUENCE_SIZE ) ;
2013-03-25 14:24:21 +04:00
if ( likely ( frag_len > 0 ) )
networking: introduce and use skb_put_data()
A common pattern with skb_put() is to just want to memcpy()
some data into the new space, introduce skb_put_data() for
this.
An spatch similar to the one for skb_put_zero() converts many
of the places using it:
@@
identifier p, p2;
expression len, skb, data;
type t, t2;
@@
(
-p = skb_put(skb, len);
+p = skb_put_data(skb, data, len);
|
-p = (t)skb_put(skb, len);
+p = skb_put_data(skb, data, len);
)
(
p2 = (t2)p;
-memcpy(p2, data, len);
|
-memcpy(p, data, len);
)
@@
type t, t2;
identifier p, p2;
expression skb, data;
@@
t *p;
...
(
-p = skb_put(skb, sizeof(t));
+p = skb_put_data(skb, data, sizeof(t));
|
-p = (t *)skb_put(skb, sizeof(t));
+p = skb_put_data(skb, data, sizeof(t));
)
(
p2 = (t2)p;
-memcpy(p2, data, sizeof(*p));
|
-memcpy(p, data, sizeof(*p));
)
@@
expression skb, len, data;
@@
-memcpy(skb_put(skb, len), data, len);
+skb_put_data(skb, data, len);
(again, manually post-processed to retain some comments)
Reviewed-by: Stephen Hemminger <stephen@networkplumber.org>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-06-16 15:29:20 +03:00
skb_put_data ( pdu , msg_ptr , frag_len ) ;
2012-03-05 04:03:44 +04:00
2012-05-10 21:45:52 +04:00
skb_queue_tail ( & sock - > tx_queue , pdu ) ;
2012-03-05 04:03:44 +04:00
lock_sock ( sk ) ;
nfc_llcp_queue_i_frames ( sock ) ;
release_sock ( sk ) ;
remaining_len - = frag_len ;
2012-04-10 21:43:03 +04:00
msg_ptr + = frag_len ;
2013-03-25 14:24:21 +04:00
} while ( remaining_len > 0 ) ;
2012-03-05 04:03:37 +04:00
2012-03-05 04:03:44 +04:00
kfree ( msg_data ) ;
2012-03-05 04:03:37 +04:00
2012-05-07 14:31:21 +04:00
return len ;
2012-03-05 04:03:37 +04:00
}
2012-03-05 04:03:42 +04:00
2012-10-16 17:01:40 +04:00
int nfc_llcp_send_ui_frame ( struct nfc_llcp_sock * sock , u8 ssap , u8 dsap ,
struct msghdr * msg , size_t len )
{
struct sk_buff * pdu ;
struct nfc_llcp_local * local ;
size_t frag_len = 0 , remaining_len ;
2012-10-29 17:02:17 +04:00
u8 * msg_ptr , * msg_data ;
2013-04-02 12:25:14 +04:00
u16 remote_miu ;
2012-10-16 17:01:40 +04:00
int err ;
pr_debug ( " Send UI frame len %zd \n " , len ) ;
local = sock - > local ;
if ( local = = NULL )
return - ENODEV ;
2016-01-29 22:24:24 +03:00
msg_data = kmalloc ( len , GFP_USER | __GFP_NOWARN ) ;
2012-10-29 17:02:17 +04:00
if ( msg_data = = NULL )
return - ENOMEM ;
2014-04-07 05:25:44 +04:00
if ( memcpy_from_msg ( msg_data , msg , len ) ) {
2012-10-29 17:02:17 +04:00
kfree ( msg_data ) ;
return - EFAULT ;
}
2012-10-16 17:01:40 +04:00
remaining_len = len ;
2012-10-29 17:02:17 +04:00
msg_ptr = msg_data ;
2012-10-16 17:01:40 +04:00
2013-03-25 14:24:21 +04:00
do {
2013-04-02 12:25:14 +04:00
remote_miu = sock - > remote_miu > LLCP_MAX_MIU ?
local - > remote_miu : sock - > remote_miu ;
frag_len = min_t ( size_t , remote_miu , remaining_len ) ;
2012-10-16 17:01:40 +04:00
pr_debug ( " Fragment %zd bytes remaining %zd " ,
frag_len , remaining_len ) ;
2018-07-18 12:57:27 +03:00
pdu = nfc_alloc_send_skb ( sock - > dev , & sock - > sk , 0 ,
2012-10-16 17:01:40 +04:00
frag_len + LLCP_HEADER_SIZE , & err ) ;
if ( pdu = = NULL ) {
2018-07-18 12:57:27 +03:00
pr_err ( " Could not allocate PDU (error=%d) \n " , err ) ;
len - = remaining_len ;
if ( len = = 0 )
len = err ;
break ;
2012-10-16 17:01:40 +04:00
}
pdu = llcp_add_header ( pdu , dsap , ssap , LLCP_PDU_UI ) ;
2013-03-25 14:24:21 +04:00
if ( likely ( frag_len > 0 ) )
networking: introduce and use skb_put_data()
A common pattern with skb_put() is to just want to memcpy()
some data into the new space, introduce skb_put_data() for
this.
An spatch similar to the one for skb_put_zero() converts many
of the places using it:
@@
identifier p, p2;
expression len, skb, data;
type t, t2;
@@
(
-p = skb_put(skb, len);
+p = skb_put_data(skb, data, len);
|
-p = (t)skb_put(skb, len);
+p = skb_put_data(skb, data, len);
)
(
p2 = (t2)p;
-memcpy(p2, data, len);
|
-memcpy(p, data, len);
)
@@
type t, t2;
identifier p, p2;
expression skb, data;
@@
t *p;
...
(
-p = skb_put(skb, sizeof(t));
+p = skb_put_data(skb, data, sizeof(t));
|
-p = (t *)skb_put(skb, sizeof(t));
+p = skb_put_data(skb, data, sizeof(t));
)
(
p2 = (t2)p;
-memcpy(p2, data, sizeof(*p));
|
-memcpy(p, data, sizeof(*p));
)
@@
expression skb, len, data;
@@
-memcpy(skb_put(skb, len), data, len);
+skb_put_data(skb, data, len);
(again, manually post-processed to retain some comments)
Reviewed-by: Stephen Hemminger <stephen@networkplumber.org>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-06-16 15:29:20 +03:00
skb_put_data ( pdu , msg_ptr , frag_len ) ;
2012-10-16 17:01:40 +04:00
/* 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 ;
2013-03-25 14:24:21 +04:00
} while ( remaining_len > 0 ) ;
2012-10-16 17:01:40 +04:00
2012-10-29 17:02:17 +04:00
kfree ( msg_data ) ;
2012-10-16 17:01:40 +04:00
return len ;
}
2012-03-05 04:03:42 +04:00
int nfc_llcp_send_rr ( struct nfc_llcp_sock * sock )
{
struct sk_buff * skb ;
struct nfc_llcp_local * local ;
pr_debug ( " Send rr nr %d \n " , sock - > recv_n ) ;
local = sock - > local ;
if ( local = = NULL )
return - ENODEV ;
skb = llcp_allocate_pdu ( sock , LLCP_PDU_RR , LLCP_SEQUENCE_SIZE ) ;
if ( skb = = NULL )
return - ENOMEM ;
skb_put ( skb , LLCP_SEQUENCE_SIZE ) ;
2012-04-10 21:43:14 +04:00
skb - > data [ 2 ] = sock - > recv_n ;
2012-03-05 04:03:42 +04:00
skb_queue_head ( & local - > tx_queue , skb ) ;
return 0 ;
}