2011-07-02 02:31:34 +04:00
/*
* Copyright ( C ) 2011 Instituto Nokia de Tecnologia
*
* Authors :
* Lauro Ramos Venancio < lauro . venancio @ openbossa . org >
* Aloisio Almeida Jr < aloisio . almeida @ openbossa . org >
*
* 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 .
*/
2011-12-14 19:43:05 +04:00
# define pr_fmt(fmt) KBUILD_MODNAME ": %s: " fmt, __func__
2011-11-29 23:37:33 +04:00
2011-07-02 02:31:34 +04:00
# include <net/genetlink.h>
# include <linux/nfc.h>
# include <linux/slab.h>
# include "nfc.h"
2013-04-26 13:49:40 +04:00
# include "llcp.h"
2012-10-17 16:43:39 +04:00
2013-11-19 18:19:39 +04:00
static const struct genl_multicast_group nfc_genl_mcgrps [ ] = {
{ . name = NFC_GENL_MCAST_EVENT_NAME , } ,
2011-07-02 02:31:34 +04:00
} ;
2012-05-07 14:31:28 +04:00
static struct genl_family nfc_genl_family = {
2011-07-02 02:31:34 +04:00
. id = GENL_ID_GENERATE ,
. hdrsize = 0 ,
. name = NFC_GENL_NAME ,
. version = NFC_GENL_VERSION ,
. maxattr = NFC_ATTR_MAX ,
} ;
static const struct nla_policy nfc_genl_policy [ NFC_ATTR_MAX + 1 ] = {
[ NFC_ATTR_DEVICE_INDEX ] = { . type = NLA_U32 } ,
[ NFC_ATTR_DEVICE_NAME ] = { . type = NLA_STRING ,
. len = NFC_DEVICE_NAME_MAXSIZE } ,
[ NFC_ATTR_PROTOCOLS ] = { . type = NLA_U32 } ,
2011-12-14 19:43:09 +04:00
[ NFC_ATTR_COMM_MODE ] = { . type = NLA_U8 } ,
[ NFC_ATTR_RF_MODE ] = { . type = NLA_U8 } ,
2012-03-05 04:03:34 +04:00
[ NFC_ATTR_DEVICE_POWERED ] = { . type = NLA_U8 } ,
2012-05-15 17:57:06 +04:00
[ NFC_ATTR_IM_PROTOCOLS ] = { . type = NLA_U32 } ,
[ NFC_ATTR_TM_PROTOCOLS ] = { . type = NLA_U32 } ,
2013-02-15 13:42:52 +04:00
[ NFC_ATTR_LLC_PARAM_LTO ] = { . type = NLA_U8 } ,
[ NFC_ATTR_LLC_PARAM_RW ] = { . type = NLA_U8 } ,
[ NFC_ATTR_LLC_PARAM_MIUX ] = { . type = NLA_U16 } ,
2013-02-15 13:43:06 +04:00
[ NFC_ATTR_LLC_SDP ] = { . type = NLA_NESTED } ,
2013-04-29 19:13:27 +04:00
[ NFC_ATTR_FIRMWARE_NAME ] = { . type = NLA_STRING ,
. len = NFC_FIRMWARE_NAME_MAXSIZE } ,
2013-08-28 02:47:24 +04:00
[ NFC_ATTR_SE_APDU ] = { . type = NLA_BINARY } ,
2013-02-15 13:43:06 +04:00
} ;
static const struct nla_policy nfc_sdp_genl_policy [ NFC_SDP_ATTR_MAX + 1 ] = {
[ NFC_SDP_ATTR_URI ] = { . type = NLA_STRING } ,
[ NFC_SDP_ATTR_SAP ] = { . type = NLA_U8 } ,
2011-07-02 02:31:34 +04:00
} ;
static int nfc_genl_send_target ( struct sk_buff * msg , struct nfc_target * target ,
2012-03-05 04:03:53 +04:00
struct netlink_callback * cb , int flags )
2011-07-02 02:31:34 +04:00
{
void * hdr ;
2012-09-08 00:12:54 +04:00
hdr = genlmsg_put ( msg , NETLINK_CB ( cb - > skb ) . portid , cb - > nlh - > nlmsg_seq ,
2012-03-05 04:03:53 +04:00
& nfc_genl_family , flags , NFC_CMD_GET_TARGET ) ;
2011-07-02 02:31:34 +04:00
if ( ! hdr )
return - EMSGSIZE ;
genl_dump_check_consistent ( cb , hdr , & nfc_genl_family ) ;
2012-03-30 07:23:57 +04:00
if ( nla_put_u32 ( msg , NFC_ATTR_TARGET_INDEX , target - > idx ) | |
nla_put_u32 ( msg , NFC_ATTR_PROTOCOLS , target - > supported_protocols ) | |
nla_put_u16 ( msg , NFC_ATTR_TARGET_SENS_RES , target - > sens_res ) | |
nla_put_u8 ( msg , NFC_ATTR_TARGET_SEL_RES , target - > sel_res ) )
goto nla_put_failure ;
if ( target - > nfcid1_len > 0 & &
nla_put ( msg , NFC_ATTR_TARGET_NFCID1 , target - > nfcid1_len ,
target - > nfcid1 ) )
goto nla_put_failure ;
if ( target - > sensb_res_len > 0 & &
nla_put ( msg , NFC_ATTR_TARGET_SENSB_RES , target - > sensb_res_len ,
target - > sensb_res ) )
goto nla_put_failure ;
if ( target - > sensf_res_len > 0 & &
nla_put ( msg , NFC_ATTR_TARGET_SENSF_RES , target - > sensf_res_len ,
target - > sensf_res ) )
goto nla_put_failure ;
2011-07-02 02:31:34 +04:00
return genlmsg_end ( msg , hdr ) ;
nla_put_failure :
genlmsg_cancel ( msg , hdr ) ;
return - EMSGSIZE ;
}
static struct nfc_dev * __get_device_from_cb ( struct netlink_callback * cb )
{
struct nfc_dev * dev ;
int rc ;
u32 idx ;
rc = nlmsg_parse ( cb - > nlh , GENL_HDRLEN + nfc_genl_family . hdrsize ,
2012-03-05 04:03:53 +04:00
nfc_genl_family . attrbuf ,
nfc_genl_family . maxattr ,
nfc_genl_policy ) ;
2011-07-02 02:31:34 +04:00
if ( rc < 0 )
return ERR_PTR ( rc ) ;
if ( ! nfc_genl_family . attrbuf [ NFC_ATTR_DEVICE_INDEX ] )
return ERR_PTR ( - EINVAL ) ;
idx = nla_get_u32 ( nfc_genl_family . attrbuf [ NFC_ATTR_DEVICE_INDEX ] ) ;
dev = nfc_get_device ( idx ) ;
if ( ! dev )
return ERR_PTR ( - ENODEV ) ;
return dev ;
}
static int nfc_genl_dump_targets ( struct sk_buff * skb ,
2012-03-05 04:03:53 +04:00
struct netlink_callback * cb )
2011-07-02 02:31:34 +04:00
{
int i = cb - > args [ 0 ] ;
struct nfc_dev * dev = ( struct nfc_dev * ) cb - > args [ 1 ] ;
int rc ;
if ( ! dev ) {
dev = __get_device_from_cb ( cb ) ;
if ( IS_ERR ( dev ) )
return PTR_ERR ( dev ) ;
cb - > args [ 1 ] = ( long ) dev ;
}
2012-05-07 14:31:15 +04:00
device_lock ( & dev - > dev ) ;
2011-07-02 02:31:34 +04:00
cb - > seq = dev - > targets_generation ;
while ( i < dev - > n_targets ) {
rc = nfc_genl_send_target ( skb , & dev - > targets [ i ] , cb ,
2012-03-05 04:03:53 +04:00
NLM_F_MULTI ) ;
2011-07-02 02:31:34 +04:00
if ( rc < 0 )
break ;
i + + ;
}
2012-05-07 14:31:15 +04:00
device_unlock ( & dev - > dev ) ;
2011-07-02 02:31:34 +04:00
cb - > args [ 0 ] = i ;
return skb - > len ;
}
static int nfc_genl_dump_targets_done ( struct netlink_callback * cb )
{
struct nfc_dev * dev = ( struct nfc_dev * ) cb - > args [ 1 ] ;
if ( dev )
nfc_put_device ( dev ) ;
return 0 ;
}
int nfc_genl_targets_found ( struct nfc_dev * dev )
{
struct sk_buff * msg ;
void * hdr ;
2012-09-08 00:12:54 +04:00
dev - > genl_data . poll_req_portid = 0 ;
2011-07-02 02:31:34 +04:00
2012-06-28 07:57:45 +04:00
msg = nlmsg_new ( NLMSG_DEFAULT_SIZE , GFP_ATOMIC ) ;
2011-07-02 02:31:34 +04:00
if ( ! msg )
return - ENOMEM ;
hdr = genlmsg_put ( msg , 0 , 0 , & nfc_genl_family , 0 ,
2012-03-05 04:03:53 +04:00
NFC_EVENT_TARGETS_FOUND ) ;
2011-07-02 02:31:34 +04:00
if ( ! hdr )
goto free_msg ;
2012-03-30 07:23:57 +04:00
if ( nla_put_u32 ( msg , NFC_ATTR_DEVICE_INDEX , dev - > idx ) )
goto nla_put_failure ;
2011-07-02 02:31:34 +04:00
genlmsg_end ( msg , hdr ) ;
2013-11-19 18:19:39 +04:00
return genlmsg_multicast ( & nfc_genl_family , msg , 0 , 0 , GFP_ATOMIC ) ;
2011-07-02 02:31:34 +04:00
nla_put_failure :
genlmsg_cancel ( msg , hdr ) ;
free_msg :
nlmsg_free ( msg ) ;
return - EMSGSIZE ;
}
2012-04-10 21:43:04 +04:00
int nfc_genl_target_lost ( struct nfc_dev * dev , u32 target_idx )
{
struct sk_buff * msg ;
void * hdr ;
2012-06-28 07:57:45 +04:00
msg = nlmsg_new ( NLMSG_DEFAULT_SIZE , GFP_KERNEL ) ;
2012-04-10 21:43:04 +04:00
if ( ! msg )
return - ENOMEM ;
hdr = genlmsg_put ( msg , 0 , 0 , & nfc_genl_family , 0 ,
NFC_EVENT_TARGET_LOST ) ;
if ( ! hdr )
goto free_msg ;
2012-04-18 22:17:13 +04:00
if ( nla_put_string ( msg , NFC_ATTR_DEVICE_NAME , nfc_device_name ( dev ) ) | |
nla_put_u32 ( msg , NFC_ATTR_TARGET_INDEX , target_idx ) )
goto nla_put_failure ;
2012-04-10 21:43:04 +04:00
genlmsg_end ( msg , hdr ) ;
2013-11-19 18:19:39 +04:00
genlmsg_multicast ( & nfc_genl_family , msg , 0 , 0 , GFP_KERNEL ) ;
2012-04-10 21:43:04 +04:00
return 0 ;
2012-06-01 15:21:13 +04:00
nla_put_failure :
genlmsg_cancel ( msg , hdr ) ;
free_msg :
nlmsg_free ( msg ) ;
return - EMSGSIZE ;
}
int nfc_genl_tm_activated ( struct nfc_dev * dev , u32 protocol )
{
struct sk_buff * msg ;
void * hdr ;
2012-06-28 07:57:45 +04:00
msg = nlmsg_new ( NLMSG_DEFAULT_SIZE , GFP_KERNEL ) ;
2012-06-01 15:21:13 +04:00
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 ) ;
2013-11-19 18:19:39 +04:00
genlmsg_multicast ( & nfc_genl_family , msg , 0 , 0 , GFP_KERNEL ) ;
2012-06-01 15:21:13 +04:00
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 ;
2012-06-28 07:57:45 +04:00
msg = nlmsg_new ( NLMSG_DEFAULT_SIZE , GFP_KERNEL ) ;
2012-06-01 15:21:13 +04:00
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 ) ;
2013-11-19 18:19:39 +04:00
genlmsg_multicast ( & nfc_genl_family , msg , 0 , 0 , GFP_KERNEL ) ;
2012-06-01 15:21:13 +04:00
return 0 ;
2012-04-10 21:43:04 +04:00
nla_put_failure :
genlmsg_cancel ( msg , hdr ) ;
free_msg :
nlmsg_free ( msg ) ;
return - EMSGSIZE ;
}
2011-07-02 02:31:34 +04:00
int nfc_genl_device_added ( struct nfc_dev * dev )
{
struct sk_buff * msg ;
void * hdr ;
2012-06-28 07:57:45 +04:00
msg = nlmsg_new ( NLMSG_DEFAULT_SIZE , GFP_KERNEL ) ;
2011-07-02 02:31:34 +04:00
if ( ! msg )
return - ENOMEM ;
hdr = genlmsg_put ( msg , 0 , 0 , & nfc_genl_family , 0 ,
2012-03-05 04:03:53 +04:00
NFC_EVENT_DEVICE_ADDED ) ;
2011-07-02 02:31:34 +04:00
if ( ! hdr )
goto free_msg ;
2012-03-30 07:23:57 +04:00
if ( nla_put_string ( msg , NFC_ATTR_DEVICE_NAME , nfc_device_name ( dev ) ) | |
nla_put_u32 ( msg , NFC_ATTR_DEVICE_INDEX , dev - > idx ) | |
nla_put_u32 ( msg , NFC_ATTR_PROTOCOLS , dev - > supported_protocols ) | |
nla_put_u8 ( msg , NFC_ATTR_DEVICE_POWERED , dev - > dev_up ) )
goto nla_put_failure ;
2011-07-02 02:31:34 +04:00
genlmsg_end ( msg , hdr ) ;
2013-11-19 18:19:39 +04:00
genlmsg_multicast ( & nfc_genl_family , msg , 0 , 0 , GFP_KERNEL ) ;
2011-07-02 02:31:34 +04:00
return 0 ;
nla_put_failure :
genlmsg_cancel ( msg , hdr ) ;
free_msg :
nlmsg_free ( msg ) ;
return - EMSGSIZE ;
}
int nfc_genl_device_removed ( struct nfc_dev * dev )
{
struct sk_buff * msg ;
void * hdr ;
2012-06-28 07:57:45 +04:00
msg = nlmsg_new ( NLMSG_DEFAULT_SIZE , GFP_KERNEL ) ;
2011-07-02 02:31:34 +04:00
if ( ! msg )
return - ENOMEM ;
hdr = genlmsg_put ( msg , 0 , 0 , & nfc_genl_family , 0 ,
2012-03-05 04:03:53 +04:00
NFC_EVENT_DEVICE_REMOVED ) ;
2011-07-02 02:31:34 +04:00
if ( ! hdr )
goto free_msg ;
2012-03-30 07:23:57 +04:00
if ( nla_put_u32 ( msg , NFC_ATTR_DEVICE_INDEX , dev - > idx ) )
goto nla_put_failure ;
2011-07-02 02:31:34 +04:00
genlmsg_end ( msg , hdr ) ;
2013-11-19 18:19:39 +04:00
genlmsg_multicast ( & nfc_genl_family , msg , 0 , 0 , GFP_KERNEL ) ;
2011-07-02 02:31:34 +04:00
return 0 ;
nla_put_failure :
genlmsg_cancel ( msg , hdr ) ;
free_msg :
nlmsg_free ( msg ) ;
return - EMSGSIZE ;
}
2013-02-15 13:43:06 +04:00
int nfc_genl_llc_send_sdres ( struct nfc_dev * dev , struct hlist_head * sdres_list )
{
struct sk_buff * msg ;
struct nlattr * sdp_attr , * uri_attr ;
struct nfc_llcp_sdp_tlv * sdres ;
struct hlist_node * n ;
void * hdr ;
int rc = - EMSGSIZE ;
int i ;
msg = nlmsg_new ( NLMSG_DEFAULT_SIZE , GFP_KERNEL ) ;
if ( ! msg )
return - ENOMEM ;
hdr = genlmsg_put ( msg , 0 , 0 , & nfc_genl_family , 0 ,
NFC_EVENT_LLC_SDRES ) ;
if ( ! hdr )
goto free_msg ;
if ( nla_put_u32 ( msg , NFC_ATTR_DEVICE_INDEX , dev - > idx ) )
goto nla_put_failure ;
sdp_attr = nla_nest_start ( msg , NFC_ATTR_LLC_SDP ) ;
if ( sdp_attr = = NULL ) {
rc = - ENOMEM ;
goto nla_put_failure ;
}
i = 1 ;
hlist_for_each_entry_safe ( sdres , n , sdres_list , node ) {
pr_debug ( " uri: %s, sap: %d \n " , sdres - > uri , sdres - > sap ) ;
uri_attr = nla_nest_start ( msg , i + + ) ;
if ( uri_attr = = NULL ) {
rc = - ENOMEM ;
goto nla_put_failure ;
}
if ( nla_put_u8 ( msg , NFC_SDP_ATTR_SAP , sdres - > sap ) )
goto nla_put_failure ;
if ( nla_put_string ( msg , NFC_SDP_ATTR_URI , sdres - > uri ) )
goto nla_put_failure ;
nla_nest_end ( msg , uri_attr ) ;
hlist_del ( & sdres - > node ) ;
nfc_llcp_free_sdp_tlv ( sdres ) ;
}
nla_nest_end ( msg , sdp_attr ) ;
genlmsg_end ( msg , hdr ) ;
2013-11-19 18:19:39 +04:00
return genlmsg_multicast ( & nfc_genl_family , msg , 0 , 0 , GFP_ATOMIC ) ;
2013-02-15 13:43:06 +04:00
nla_put_failure :
genlmsg_cancel ( msg , hdr ) ;
free_msg :
nlmsg_free ( msg ) ;
nfc_llcp_free_sdp_tlv_list ( sdres_list ) ;
return rc ;
}
2013-05-10 17:47:37 +04:00
int nfc_genl_se_added ( struct nfc_dev * dev , u32 se_idx , u16 type )
{
struct sk_buff * msg ;
void * hdr ;
msg = nlmsg_new ( NLMSG_DEFAULT_SIZE , GFP_KERNEL ) ;
if ( ! msg )
return - ENOMEM ;
hdr = genlmsg_put ( msg , 0 , 0 , & nfc_genl_family , 0 ,
NFC_EVENT_SE_ADDED ) ;
if ( ! hdr )
goto free_msg ;
if ( nla_put_u32 ( msg , NFC_ATTR_DEVICE_INDEX , dev - > idx ) | |
nla_put_u32 ( msg , NFC_ATTR_SE_INDEX , se_idx ) | |
nla_put_u8 ( msg , NFC_ATTR_SE_TYPE , type ) )
goto nla_put_failure ;
genlmsg_end ( msg , hdr ) ;
2013-11-19 18:19:39 +04:00
genlmsg_multicast ( & nfc_genl_family , msg , 0 , 0 , GFP_KERNEL ) ;
2013-05-10 17:47:37 +04:00
return 0 ;
nla_put_failure :
genlmsg_cancel ( msg , hdr ) ;
free_msg :
nlmsg_free ( msg ) ;
return - EMSGSIZE ;
}
int nfc_genl_se_removed ( struct nfc_dev * dev , u32 se_idx )
{
struct sk_buff * msg ;
void * hdr ;
msg = nlmsg_new ( NLMSG_DEFAULT_SIZE , GFP_KERNEL ) ;
if ( ! msg )
return - ENOMEM ;
hdr = genlmsg_put ( msg , 0 , 0 , & nfc_genl_family , 0 ,
NFC_EVENT_SE_REMOVED ) ;
if ( ! hdr )
goto free_msg ;
if ( nla_put_u32 ( msg , NFC_ATTR_DEVICE_INDEX , dev - > idx ) | |
nla_put_u32 ( msg , NFC_ATTR_SE_INDEX , se_idx ) )
goto nla_put_failure ;
genlmsg_end ( msg , hdr ) ;
2013-11-19 18:19:39 +04:00
genlmsg_multicast ( & nfc_genl_family , msg , 0 , 0 , GFP_KERNEL ) ;
2013-05-10 17:47:37 +04:00
return 0 ;
nla_put_failure :
genlmsg_cancel ( msg , hdr ) ;
free_msg :
nlmsg_free ( msg ) ;
return - EMSGSIZE ;
}
2011-07-02 02:31:34 +04:00
static int nfc_genl_send_device ( struct sk_buff * msg , struct nfc_dev * dev ,
2012-09-08 00:12:54 +04:00
u32 portid , u32 seq ,
2012-03-05 04:03:53 +04:00
struct netlink_callback * cb ,
int flags )
2011-07-02 02:31:34 +04:00
{
void * hdr ;
2012-09-08 00:12:54 +04:00
hdr = genlmsg_put ( msg , portid , seq , & nfc_genl_family , flags ,
2012-03-05 04:03:53 +04:00
NFC_CMD_GET_DEVICE ) ;
2011-07-02 02:31:34 +04:00
if ( ! hdr )
return - EMSGSIZE ;
if ( cb )
genl_dump_check_consistent ( cb , hdr , & nfc_genl_family ) ;
2012-03-30 07:23:57 +04:00
if ( nla_put_string ( msg , NFC_ATTR_DEVICE_NAME , nfc_device_name ( dev ) ) | |
nla_put_u32 ( msg , NFC_ATTR_DEVICE_INDEX , dev - > idx ) | |
nla_put_u32 ( msg , NFC_ATTR_PROTOCOLS , dev - > supported_protocols ) | |
2012-10-05 13:19:58 +04:00
nla_put_u8 ( msg , NFC_ATTR_DEVICE_POWERED , dev - > dev_up ) | |
nla_put_u8 ( msg , NFC_ATTR_RF_MODE , dev - > rf_mode ) )
2012-03-30 07:23:57 +04:00
goto nla_put_failure ;
2011-07-02 02:31:34 +04:00
return genlmsg_end ( msg , hdr ) ;
nla_put_failure :
genlmsg_cancel ( msg , hdr ) ;
return - EMSGSIZE ;
}
static int nfc_genl_dump_devices ( struct sk_buff * skb ,
2012-03-05 04:03:53 +04:00
struct netlink_callback * cb )
2011-07-02 02:31:34 +04:00
{
struct class_dev_iter * iter = ( struct class_dev_iter * ) cb - > args [ 0 ] ;
struct nfc_dev * dev = ( struct nfc_dev * ) cb - > args [ 1 ] ;
bool first_call = false ;
if ( ! iter ) {
first_call = true ;
iter = kmalloc ( sizeof ( struct class_dev_iter ) , GFP_KERNEL ) ;
if ( ! iter )
return - ENOMEM ;
cb - > args [ 0 ] = ( long ) iter ;
}
mutex_lock ( & nfc_devlist_mutex ) ;
cb - > seq = nfc_devlist_generation ;
if ( first_call ) {
nfc_device_iter_init ( iter ) ;
dev = nfc_device_iter_next ( iter ) ;
}
while ( dev ) {
int rc ;
2012-09-08 00:12:54 +04:00
rc = nfc_genl_send_device ( skb , dev , NETLINK_CB ( cb - > skb ) . portid ,
2012-03-05 04:03:53 +04:00
cb - > nlh - > nlmsg_seq , cb , NLM_F_MULTI ) ;
2011-07-02 02:31:34 +04:00
if ( rc < 0 )
break ;
dev = nfc_device_iter_next ( iter ) ;
}
mutex_unlock ( & nfc_devlist_mutex ) ;
cb - > args [ 1 ] = ( long ) dev ;
return skb - > len ;
}
static int nfc_genl_dump_devices_done ( struct netlink_callback * cb )
{
struct class_dev_iter * iter = ( struct class_dev_iter * ) cb - > args [ 0 ] ;
nfc_device_iter_exit ( iter ) ;
kfree ( iter ) ;
return 0 ;
}
2011-12-14 19:43:09 +04:00
int nfc_genl_dep_link_up_event ( struct nfc_dev * dev , u32 target_idx ,
2012-03-05 04:03:53 +04:00
u8 comm_mode , u8 rf_mode )
2011-12-14 19:43:09 +04:00
{
struct sk_buff * msg ;
void * hdr ;
pr_debug ( " DEP link is up \n " ) ;
2012-06-28 07:57:45 +04:00
msg = nlmsg_new ( NLMSG_DEFAULT_SIZE , GFP_ATOMIC ) ;
2011-12-14 19:43:09 +04:00
if ( ! msg )
return - ENOMEM ;
2012-03-05 04:03:53 +04:00
hdr = genlmsg_put ( msg , 0 , 0 , & nfc_genl_family , 0 , NFC_CMD_DEP_LINK_UP ) ;
2011-12-14 19:43:09 +04:00
if ( ! hdr )
goto free_msg ;
2012-03-30 07:23:57 +04:00
if ( nla_put_u32 ( msg , NFC_ATTR_DEVICE_INDEX , dev - > idx ) )
goto nla_put_failure ;
if ( rf_mode = = NFC_RF_INITIATOR & &
nla_put_u32 ( msg , NFC_ATTR_TARGET_INDEX , target_idx ) )
goto nla_put_failure ;
if ( nla_put_u8 ( msg , NFC_ATTR_COMM_MODE , comm_mode ) | |
nla_put_u8 ( msg , NFC_ATTR_RF_MODE , rf_mode ) )
goto nla_put_failure ;
2011-12-14 19:43:09 +04:00
genlmsg_end ( msg , hdr ) ;
dev - > dep_link_up = true ;
2013-11-19 18:19:39 +04:00
genlmsg_multicast ( & nfc_genl_family , msg , 0 , 0 , GFP_ATOMIC ) ;
2011-12-14 19:43:09 +04:00
return 0 ;
nla_put_failure :
genlmsg_cancel ( msg , hdr ) ;
free_msg :
nlmsg_free ( msg ) ;
return - EMSGSIZE ;
}
int nfc_genl_dep_link_down_event ( struct nfc_dev * dev )
{
struct sk_buff * msg ;
void * hdr ;
pr_debug ( " DEP link is down \n " ) ;
2012-06-28 07:57:45 +04:00
msg = nlmsg_new ( NLMSG_DEFAULT_SIZE , GFP_ATOMIC ) ;
2011-12-14 19:43:09 +04:00
if ( ! msg )
return - ENOMEM ;
hdr = genlmsg_put ( msg , 0 , 0 , & nfc_genl_family , 0 ,
2012-03-05 04:03:53 +04:00
NFC_CMD_DEP_LINK_DOWN ) ;
2011-12-14 19:43:09 +04:00
if ( ! hdr )
goto free_msg ;
2012-03-30 07:23:57 +04:00
if ( nla_put_u32 ( msg , NFC_ATTR_DEVICE_INDEX , dev - > idx ) )
goto nla_put_failure ;
2011-12-14 19:43:09 +04:00
genlmsg_end ( msg , hdr ) ;
2013-11-19 18:19:39 +04:00
genlmsg_multicast ( & nfc_genl_family , msg , 0 , 0 , GFP_ATOMIC ) ;
2011-12-14 19:43:09 +04:00
return 0 ;
nla_put_failure :
genlmsg_cancel ( msg , hdr ) ;
free_msg :
nlmsg_free ( msg ) ;
return - EMSGSIZE ;
}
2011-07-02 02:31:34 +04:00
static int nfc_genl_get_device ( struct sk_buff * skb , struct genl_info * info )
{
struct sk_buff * msg ;
struct nfc_dev * dev ;
u32 idx ;
int rc = - ENOBUFS ;
if ( ! info - > attrs [ NFC_ATTR_DEVICE_INDEX ] )
return - EINVAL ;
idx = nla_get_u32 ( info - > attrs [ NFC_ATTR_DEVICE_INDEX ] ) ;
dev = nfc_get_device ( idx ) ;
if ( ! dev )
return - ENODEV ;
2012-06-28 07:57:45 +04:00
msg = nlmsg_new ( NLMSG_DEFAULT_SIZE , GFP_KERNEL ) ;
2011-07-02 02:31:34 +04:00
if ( ! msg ) {
rc = - ENOMEM ;
goto out_putdev ;
}
2012-09-08 00:12:54 +04:00
rc = nfc_genl_send_device ( msg , dev , info - > snd_portid , info - > snd_seq ,
2012-03-05 04:03:53 +04:00
NULL , 0 ) ;
2011-07-02 02:31:34 +04:00
if ( rc < 0 )
goto out_free ;
nfc_put_device ( dev ) ;
return genlmsg_reply ( msg , info ) ;
out_free :
nlmsg_free ( msg ) ;
out_putdev :
nfc_put_device ( dev ) ;
return rc ;
}
2011-09-18 12:19:33 +04:00
static int nfc_genl_dev_up ( struct sk_buff * skb , struct genl_info * info )
{
struct nfc_dev * dev ;
int rc ;
u32 idx ;
if ( ! info - > attrs [ NFC_ATTR_DEVICE_INDEX ] )
return - EINVAL ;
idx = nla_get_u32 ( info - > attrs [ NFC_ATTR_DEVICE_INDEX ] ) ;
dev = nfc_get_device ( idx ) ;
if ( ! dev )
return - ENODEV ;
rc = nfc_dev_up ( dev ) ;
nfc_put_device ( dev ) ;
return rc ;
}
static int nfc_genl_dev_down ( struct sk_buff * skb , struct genl_info * info )
{
struct nfc_dev * dev ;
int rc ;
u32 idx ;
if ( ! info - > attrs [ NFC_ATTR_DEVICE_INDEX ] )
return - EINVAL ;
idx = nla_get_u32 ( info - > attrs [ NFC_ATTR_DEVICE_INDEX ] ) ;
dev = nfc_get_device ( idx ) ;
if ( ! dev )
return - ENODEV ;
rc = nfc_dev_down ( dev ) ;
nfc_put_device ( dev ) ;
return rc ;
}
2011-07-02 02:31:34 +04:00
static int nfc_genl_start_poll ( struct sk_buff * skb , struct genl_info * info )
{
struct nfc_dev * dev ;
int rc ;
u32 idx ;
2012-05-15 17:57:06 +04:00
u32 im_protocols = 0 , tm_protocols = 0 ;
2011-07-02 02:31:34 +04:00
2011-12-14 19:43:09 +04:00
pr_debug ( " Poll start \n " ) ;
2011-07-02 02:31:34 +04:00
if ( ! info - > attrs [ NFC_ATTR_DEVICE_INDEX ] | |
2012-05-15 17:57:06 +04:00
( ( ! info - > attrs [ NFC_ATTR_IM_PROTOCOLS ] & &
! info - > attrs [ NFC_ATTR_PROTOCOLS ] ) & &
2012-10-17 17:23:39 +04:00
! info - > attrs [ NFC_ATTR_TM_PROTOCOLS ] ) )
2011-07-02 02:31:34 +04:00
return - EINVAL ;
idx = nla_get_u32 ( info - > attrs [ NFC_ATTR_DEVICE_INDEX ] ) ;
2012-05-15 17:57:06 +04:00
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 ] ) ;
2012-05-31 13:48:58 +04:00
else if ( info - > attrs [ NFC_ATTR_PROTOCOLS ] )
im_protocols = nla_get_u32 ( info - > attrs [ NFC_ATTR_PROTOCOLS ] ) ;
2011-07-02 02:31:34 +04:00
dev = nfc_get_device ( idx ) ;
if ( ! dev )
return - ENODEV ;
mutex_lock ( & dev - > genl_data . genl_data_mutex ) ;
2012-05-15 17:57:06 +04:00
rc = nfc_start_poll ( dev , im_protocols , tm_protocols ) ;
2011-07-02 02:31:34 +04:00
if ( ! rc )
2012-09-08 00:12:54 +04:00
dev - > genl_data . poll_req_portid = info - > snd_portid ;
2011-07-02 02:31:34 +04:00
mutex_unlock ( & dev - > genl_data . genl_data_mutex ) ;
nfc_put_device ( dev ) ;
return rc ;
}
static int nfc_genl_stop_poll ( struct sk_buff * skb , struct genl_info * info )
{
struct nfc_dev * dev ;
int rc ;
u32 idx ;
if ( ! info - > attrs [ NFC_ATTR_DEVICE_INDEX ] )
return - EINVAL ;
idx = nla_get_u32 ( info - > attrs [ NFC_ATTR_DEVICE_INDEX ] ) ;
dev = nfc_get_device ( idx ) ;
if ( ! dev )
return - ENODEV ;
2012-06-28 18:41:57 +04:00
device_lock ( & dev - > dev ) ;
if ( ! dev - > polling ) {
device_unlock ( & dev - > dev ) ;
return - EINVAL ;
}
device_unlock ( & dev - > dev ) ;
2011-07-02 02:31:34 +04:00
mutex_lock ( & dev - > genl_data . genl_data_mutex ) ;
2012-09-08 00:12:54 +04:00
if ( dev - > genl_data . poll_req_portid ! = info - > snd_portid ) {
2011-07-02 02:31:34 +04:00
rc = - EBUSY ;
goto out ;
}
rc = nfc_stop_poll ( dev ) ;
2012-09-08 00:12:54 +04:00
dev - > genl_data . poll_req_portid = 0 ;
2011-07-02 02:31:34 +04:00
out :
mutex_unlock ( & dev - > genl_data . genl_data_mutex ) ;
nfc_put_device ( dev ) ;
return rc ;
}
2011-12-14 19:43:09 +04:00
static int nfc_genl_dep_link_up ( struct sk_buff * skb , struct genl_info * info )
{
struct nfc_dev * dev ;
int rc , tgt_idx ;
u32 idx ;
2012-03-05 04:03:50 +04:00
u8 comm ;
2011-12-14 19:43:09 +04:00
pr_debug ( " DEP link up \n " ) ;
if ( ! info - > attrs [ NFC_ATTR_DEVICE_INDEX ] | |
2012-03-05 04:03:50 +04:00
! info - > attrs [ NFC_ATTR_COMM_MODE ] )
2011-12-14 19:43:09 +04:00
return - EINVAL ;
idx = nla_get_u32 ( info - > attrs [ NFC_ATTR_DEVICE_INDEX ] ) ;
if ( ! info - > attrs [ NFC_ATTR_TARGET_INDEX ] )
tgt_idx = NFC_TARGET_IDX_ANY ;
else
tgt_idx = nla_get_u32 ( info - > attrs [ NFC_ATTR_TARGET_INDEX ] ) ;
comm = nla_get_u8 ( info - > attrs [ NFC_ATTR_COMM_MODE ] ) ;
if ( comm ! = NFC_COMM_ACTIVE & & comm ! = NFC_COMM_PASSIVE )
return - EINVAL ;
dev = nfc_get_device ( idx ) ;
if ( ! dev )
return - ENODEV ;
2012-03-05 04:03:50 +04:00
rc = nfc_dep_link_up ( dev , tgt_idx , comm ) ;
2011-12-14 19:43:09 +04:00
nfc_put_device ( dev ) ;
return rc ;
}
static int nfc_genl_dep_link_down ( struct sk_buff * skb , struct genl_info * info )
{
struct nfc_dev * dev ;
int rc ;
u32 idx ;
if ( ! info - > attrs [ NFC_ATTR_DEVICE_INDEX ] )
return - EINVAL ;
idx = nla_get_u32 ( info - > attrs [ NFC_ATTR_DEVICE_INDEX ] ) ;
dev = nfc_get_device ( idx ) ;
if ( ! dev )
return - ENODEV ;
rc = nfc_dep_link_down ( dev ) ;
nfc_put_device ( dev ) ;
return rc ;
}
2012-10-17 16:43:39 +04:00
static int nfc_genl_send_params ( struct sk_buff * msg ,
struct nfc_llcp_local * local ,
u32 portid , u32 seq )
{
void * hdr ;
hdr = genlmsg_put ( msg , portid , seq , & nfc_genl_family , 0 ,
NFC_CMD_LLC_GET_PARAMS ) ;
if ( ! hdr )
return - EMSGSIZE ;
if ( nla_put_u32 ( msg , NFC_ATTR_DEVICE_INDEX , local - > dev - > idx ) | |
nla_put_u8 ( msg , NFC_ATTR_LLC_PARAM_LTO , local - > lto ) | |
nla_put_u8 ( msg , NFC_ATTR_LLC_PARAM_RW , local - > rw ) | |
nla_put_u16 ( msg , NFC_ATTR_LLC_PARAM_MIUX , be16_to_cpu ( local - > miux ) ) )
goto nla_put_failure ;
return genlmsg_end ( msg , hdr ) ;
nla_put_failure :
genlmsg_cancel ( msg , hdr ) ;
return - EMSGSIZE ;
}
static int nfc_genl_llc_get_params ( struct sk_buff * skb , struct genl_info * info )
{
struct nfc_dev * dev ;
struct nfc_llcp_local * local ;
int rc = 0 ;
struct sk_buff * msg = NULL ;
u32 idx ;
if ( ! info - > attrs [ NFC_ATTR_DEVICE_INDEX ] )
return - EINVAL ;
idx = nla_get_u32 ( info - > attrs [ NFC_ATTR_DEVICE_INDEX ] ) ;
dev = nfc_get_device ( idx ) ;
if ( ! dev )
return - ENODEV ;
device_lock ( & dev - > dev ) ;
local = nfc_llcp_find_local ( dev ) ;
if ( ! local ) {
rc = - ENODEV ;
goto exit ;
}
msg = nlmsg_new ( NLMSG_DEFAULT_SIZE , GFP_KERNEL ) ;
if ( ! msg ) {
rc = - ENOMEM ;
goto exit ;
}
rc = nfc_genl_send_params ( msg , local , info - > snd_portid , info - > snd_seq ) ;
exit :
device_unlock ( & dev - > dev ) ;
nfc_put_device ( dev ) ;
if ( rc < 0 ) {
if ( msg )
nlmsg_free ( msg ) ;
return rc ;
}
return genlmsg_reply ( msg , info ) ;
}
static int nfc_genl_llc_set_params ( struct sk_buff * skb , struct genl_info * info )
{
struct nfc_dev * dev ;
struct nfc_llcp_local * local ;
u8 rw = 0 ;
u16 miux = 0 ;
u32 idx ;
int rc = 0 ;
if ( ! info - > attrs [ NFC_ATTR_DEVICE_INDEX ] | |
( ! info - > attrs [ NFC_ATTR_LLC_PARAM_LTO ] & &
! info - > attrs [ NFC_ATTR_LLC_PARAM_RW ] & &
! info - > attrs [ NFC_ATTR_LLC_PARAM_MIUX ] ) )
return - EINVAL ;
if ( info - > attrs [ NFC_ATTR_LLC_PARAM_RW ] ) {
rw = nla_get_u8 ( info - > attrs [ NFC_ATTR_LLC_PARAM_RW ] ) ;
if ( rw > LLCP_MAX_RW )
return - EINVAL ;
}
if ( info - > attrs [ NFC_ATTR_LLC_PARAM_MIUX ] ) {
miux = nla_get_u16 ( info - > attrs [ NFC_ATTR_LLC_PARAM_MIUX ] ) ;
if ( miux > LLCP_MAX_MIUX )
return - EINVAL ;
}
idx = nla_get_u32 ( info - > attrs [ NFC_ATTR_DEVICE_INDEX ] ) ;
dev = nfc_get_device ( idx ) ;
if ( ! dev )
return - ENODEV ;
device_lock ( & dev - > dev ) ;
local = nfc_llcp_find_local ( dev ) ;
if ( ! local ) {
nfc_put_device ( dev ) ;
rc = - ENODEV ;
goto exit ;
}
if ( info - > attrs [ NFC_ATTR_LLC_PARAM_LTO ] ) {
if ( dev - > dep_link_up ) {
rc = - EINPROGRESS ;
goto exit ;
}
local - > lto = nla_get_u8 ( info - > attrs [ NFC_ATTR_LLC_PARAM_LTO ] ) ;
}
if ( info - > attrs [ NFC_ATTR_LLC_PARAM_RW ] )
local - > rw = rw ;
if ( info - > attrs [ NFC_ATTR_LLC_PARAM_MIUX ] )
local - > miux = cpu_to_be16 ( miux ) ;
exit :
device_unlock ( & dev - > dev ) ;
nfc_put_device ( dev ) ;
return rc ;
}
2013-02-15 13:43:06 +04:00
static int nfc_genl_llc_sdreq ( struct sk_buff * skb , struct genl_info * info )
{
struct nfc_dev * dev ;
struct nfc_llcp_local * local ;
struct nlattr * attr , * sdp_attrs [ NFC_SDP_ATTR_MAX + 1 ] ;
u32 idx ;
u8 tid ;
char * uri ;
int rc = 0 , rem ;
size_t uri_len , tlvs_len ;
struct hlist_head sdreq_list ;
struct nfc_llcp_sdp_tlv * sdreq ;
if ( ! info - > attrs [ NFC_ATTR_DEVICE_INDEX ] | |
! info - > attrs [ NFC_ATTR_LLC_SDP ] )
return - EINVAL ;
idx = nla_get_u32 ( info - > attrs [ NFC_ATTR_DEVICE_INDEX ] ) ;
dev = nfc_get_device ( idx ) ;
if ( ! dev ) {
rc = - ENODEV ;
goto exit ;
}
device_lock ( & dev - > dev ) ;
if ( dev - > dep_link_up = = false ) {
rc = - ENOLINK ;
goto exit ;
}
local = nfc_llcp_find_local ( dev ) ;
if ( ! local ) {
nfc_put_device ( dev ) ;
rc = - ENODEV ;
goto exit ;
}
INIT_HLIST_HEAD ( & sdreq_list ) ;
tlvs_len = 0 ;
nla_for_each_nested ( attr , info - > attrs [ NFC_ATTR_LLC_SDP ] , rem ) {
rc = nla_parse_nested ( sdp_attrs , NFC_SDP_ATTR_MAX , attr ,
nfc_sdp_genl_policy ) ;
if ( rc ! = 0 ) {
rc = - EINVAL ;
goto exit ;
}
if ( ! sdp_attrs [ NFC_SDP_ATTR_URI ] )
continue ;
uri_len = nla_len ( sdp_attrs [ NFC_SDP_ATTR_URI ] ) ;
if ( uri_len = = 0 )
continue ;
uri = nla_data ( sdp_attrs [ NFC_SDP_ATTR_URI ] ) ;
if ( uri = = NULL | | * uri = = 0 )
continue ;
tid = local - > sdreq_next_tid + + ;
sdreq = nfc_llcp_build_sdreq_tlv ( tid , uri , uri_len ) ;
if ( sdreq = = NULL ) {
rc = - ENOMEM ;
goto exit ;
}
tlvs_len + = sdreq - > tlv_len ;
hlist_add_head ( & sdreq - > node , & sdreq_list ) ;
}
if ( hlist_empty ( & sdreq_list ) ) {
rc = - EINVAL ;
goto exit ;
}
rc = nfc_llcp_send_snl_sdreq ( local , & sdreq_list , tlvs_len ) ;
exit :
device_unlock ( & dev - > dev ) ;
nfc_put_device ( dev ) ;
return rc ;
}
2013-07-31 03:19:43 +04:00
static int nfc_genl_fw_download ( struct sk_buff * skb , struct genl_info * info )
2013-04-29 19:13:27 +04:00
{
struct nfc_dev * dev ;
int rc ;
u32 idx ;
char firmware_name [ NFC_FIRMWARE_NAME_MAXSIZE + 1 ] ;
if ( ! info - > attrs [ NFC_ATTR_DEVICE_INDEX ] )
return - EINVAL ;
idx = nla_get_u32 ( info - > attrs [ NFC_ATTR_DEVICE_INDEX ] ) ;
dev = nfc_get_device ( idx ) ;
if ( ! dev )
return - ENODEV ;
nla_strlcpy ( firmware_name , info - > attrs [ NFC_ATTR_FIRMWARE_NAME ] ,
sizeof ( firmware_name ) ) ;
2013-07-31 03:19:43 +04:00
rc = nfc_fw_download ( dev , firmware_name ) ;
2013-04-29 19:13:27 +04:00
nfc_put_device ( dev ) ;
return rc ;
}
2013-07-19 16:57:55 +04:00
int nfc_genl_fw_download_done ( struct nfc_dev * dev , const char * firmware_name ,
u32 result )
2013-04-29 19:13:27 +04:00
{
struct sk_buff * msg ;
void * hdr ;
msg = nlmsg_new ( NLMSG_DEFAULT_SIZE , GFP_KERNEL ) ;
if ( ! msg )
return - ENOMEM ;
hdr = genlmsg_put ( msg , 0 , 0 , & nfc_genl_family , 0 ,
2013-07-31 03:19:43 +04:00
NFC_CMD_FW_DOWNLOAD ) ;
2013-04-29 19:13:27 +04:00
if ( ! hdr )
goto free_msg ;
if ( nla_put_string ( msg , NFC_ATTR_FIRMWARE_NAME , firmware_name ) | |
2013-07-19 16:57:55 +04:00
nla_put_u32 ( msg , NFC_ATTR_FIRMWARE_DOWNLOAD_STATUS , result ) | |
2013-04-29 19:13:27 +04:00
nla_put_u32 ( msg , NFC_ATTR_DEVICE_INDEX , dev - > idx ) )
goto nla_put_failure ;
genlmsg_end ( msg , hdr ) ;
2013-11-19 18:19:39 +04:00
genlmsg_multicast ( & nfc_genl_family , msg , 0 , 0 , GFP_KERNEL ) ;
2013-04-29 19:13:27 +04:00
return 0 ;
nla_put_failure :
genlmsg_cancel ( msg , hdr ) ;
free_msg :
nlmsg_free ( msg ) ;
return - EMSGSIZE ;
}
2013-05-10 19:07:32 +04:00
static int nfc_genl_enable_se ( struct sk_buff * skb , struct genl_info * info )
{
struct nfc_dev * dev ;
int rc ;
u32 idx , se_idx ;
if ( ! info - > attrs [ NFC_ATTR_DEVICE_INDEX ] | |
! info - > attrs [ NFC_ATTR_SE_INDEX ] )
return - EINVAL ;
idx = nla_get_u32 ( info - > attrs [ NFC_ATTR_DEVICE_INDEX ] ) ;
se_idx = nla_get_u32 ( info - > attrs [ NFC_ATTR_SE_INDEX ] ) ;
dev = nfc_get_device ( idx ) ;
if ( ! dev )
return - ENODEV ;
rc = nfc_enable_se ( dev , se_idx ) ;
nfc_put_device ( dev ) ;
return rc ;
}
static int nfc_genl_disable_se ( struct sk_buff * skb , struct genl_info * info )
{
struct nfc_dev * dev ;
int rc ;
u32 idx , se_idx ;
if ( ! info - > attrs [ NFC_ATTR_DEVICE_INDEX ] | |
! info - > attrs [ NFC_ATTR_SE_INDEX ] )
return - EINVAL ;
idx = nla_get_u32 ( info - > attrs [ NFC_ATTR_DEVICE_INDEX ] ) ;
se_idx = nla_get_u32 ( info - > attrs [ NFC_ATTR_SE_INDEX ] ) ;
dev = nfc_get_device ( idx ) ;
if ( ! dev )
return - ENODEV ;
rc = nfc_disable_se ( dev , se_idx ) ;
nfc_put_device ( dev ) ;
return rc ;
}
2013-07-24 20:10:50 +04:00
static int nfc_genl_send_se ( struct sk_buff * msg , struct nfc_dev * dev ,
u32 portid , u32 seq ,
struct netlink_callback * cb ,
int flags )
{
void * hdr ;
struct nfc_se * se , * n ;
list_for_each_entry_safe ( se , n , & dev - > secure_elements , list ) {
hdr = genlmsg_put ( msg , portid , seq , & nfc_genl_family , flags ,
NFC_CMD_GET_SE ) ;
if ( ! hdr )
goto nla_put_failure ;
if ( cb )
genl_dump_check_consistent ( cb , hdr , & nfc_genl_family ) ;
if ( nla_put_u32 ( msg , NFC_ATTR_DEVICE_INDEX , dev - > idx ) | |
nla_put_u32 ( msg , NFC_ATTR_SE_INDEX , se - > idx ) | |
nla_put_u8 ( msg , NFC_ATTR_SE_TYPE , se - > type ) )
goto nla_put_failure ;
if ( genlmsg_end ( msg , hdr ) < 0 )
goto nla_put_failure ;
}
return 0 ;
nla_put_failure :
genlmsg_cancel ( msg , hdr ) ;
return - EMSGSIZE ;
}
static int nfc_genl_dump_ses ( struct sk_buff * skb ,
struct netlink_callback * cb )
{
struct class_dev_iter * iter = ( struct class_dev_iter * ) cb - > args [ 0 ] ;
struct nfc_dev * dev = ( struct nfc_dev * ) cb - > args [ 1 ] ;
bool first_call = false ;
if ( ! iter ) {
first_call = true ;
iter = kmalloc ( sizeof ( struct class_dev_iter ) , GFP_KERNEL ) ;
if ( ! iter )
return - ENOMEM ;
cb - > args [ 0 ] = ( long ) iter ;
}
mutex_lock ( & nfc_devlist_mutex ) ;
cb - > seq = nfc_devlist_generation ;
if ( first_call ) {
nfc_device_iter_init ( iter ) ;
dev = nfc_device_iter_next ( iter ) ;
}
while ( dev ) {
int rc ;
rc = nfc_genl_send_se ( skb , dev , NETLINK_CB ( cb - > skb ) . portid ,
cb - > nlh - > nlmsg_seq , cb , NLM_F_MULTI ) ;
if ( rc < 0 )
break ;
dev = nfc_device_iter_next ( iter ) ;
}
mutex_unlock ( & nfc_devlist_mutex ) ;
cb - > args [ 1 ] = ( long ) dev ;
return skb - > len ;
}
static int nfc_genl_dump_ses_done ( struct netlink_callback * cb )
{
struct class_dev_iter * iter = ( struct class_dev_iter * ) cb - > args [ 0 ] ;
nfc_device_iter_exit ( iter ) ;
kfree ( iter ) ;
return 0 ;
}
2013-08-28 02:47:24 +04:00
struct se_io_ctx {
u32 dev_idx ;
u32 se_idx ;
} ;
2013-10-07 16:18:44 +04:00
static void se_io_cb ( void * context , u8 * apdu , size_t apdu_len , int err )
2013-08-28 02:47:24 +04:00
{
struct se_io_ctx * ctx = context ;
struct sk_buff * msg ;
void * hdr ;
msg = nlmsg_new ( NLMSG_DEFAULT_SIZE , GFP_KERNEL ) ;
if ( ! msg ) {
kfree ( ctx ) ;
return ;
}
hdr = genlmsg_put ( msg , 0 , 0 , & nfc_genl_family , 0 ,
NFC_CMD_SE_IO ) ;
if ( ! hdr )
goto free_msg ;
if ( nla_put_u32 ( msg , NFC_ATTR_DEVICE_INDEX , ctx - > dev_idx ) | |
nla_put_u32 ( msg , NFC_ATTR_SE_INDEX , ctx - > se_idx ) | |
nla_put ( msg , NFC_ATTR_SE_APDU , apdu_len , apdu ) )
goto nla_put_failure ;
genlmsg_end ( msg , hdr ) ;
2013-11-19 18:19:39 +04:00
genlmsg_multicast ( & nfc_genl_family , msg , 0 , 0 , GFP_KERNEL ) ;
2013-08-28 02:47:24 +04:00
kfree ( ctx ) ;
return ;
nla_put_failure :
genlmsg_cancel ( msg , hdr ) ;
free_msg :
nlmsg_free ( msg ) ;
kfree ( ctx ) ;
return ;
}
static int nfc_genl_se_io ( struct sk_buff * skb , struct genl_info * info )
{
struct nfc_dev * dev ;
struct se_io_ctx * ctx ;
u32 dev_idx , se_idx ;
u8 * apdu ;
size_t apdu_len ;
if ( ! info - > attrs [ NFC_ATTR_DEVICE_INDEX ] | |
! info - > attrs [ NFC_ATTR_SE_INDEX ] | |
! info - > attrs [ NFC_ATTR_SE_APDU ] )
return - EINVAL ;
dev_idx = nla_get_u32 ( info - > attrs [ NFC_ATTR_DEVICE_INDEX ] ) ;
se_idx = nla_get_u32 ( info - > attrs [ NFC_ATTR_SE_INDEX ] ) ;
dev = nfc_get_device ( dev_idx ) ;
if ( ! dev )
return - ENODEV ;
if ( ! dev - > ops | | ! dev - > ops - > se_io )
return - ENOTSUPP ;
apdu_len = nla_len ( info - > attrs [ NFC_ATTR_SE_APDU ] ) ;
if ( apdu_len = = 0 )
return - EINVAL ;
apdu = nla_data ( info - > attrs [ NFC_ATTR_SE_APDU ] ) ;
if ( ! apdu )
return - EINVAL ;
ctx = kzalloc ( sizeof ( struct se_io_ctx ) , GFP_KERNEL ) ;
if ( ! ctx )
return - ENOMEM ;
ctx - > dev_idx = dev_idx ;
ctx - > se_idx = se_idx ;
return dev - > ops - > se_io ( dev , se_idx , apdu , apdu_len , se_io_cb , ctx ) ;
}
2013-11-14 20:14:46 +04:00
static const struct genl_ops nfc_genl_ops [ ] = {
2011-07-02 02:31:34 +04:00
{
. cmd = NFC_CMD_GET_DEVICE ,
. doit = nfc_genl_get_device ,
. dumpit = nfc_genl_dump_devices ,
. done = nfc_genl_dump_devices_done ,
. policy = nfc_genl_policy ,
2011-09-18 12:19:33 +04:00
} ,
{
. cmd = NFC_CMD_DEV_UP ,
. doit = nfc_genl_dev_up ,
. policy = nfc_genl_policy ,
} ,
{
. cmd = NFC_CMD_DEV_DOWN ,
. doit = nfc_genl_dev_down ,
. policy = nfc_genl_policy ,
2011-07-02 02:31:34 +04:00
} ,
{
. cmd = NFC_CMD_START_POLL ,
. doit = nfc_genl_start_poll ,
. policy = nfc_genl_policy ,
} ,
{
. cmd = NFC_CMD_STOP_POLL ,
. doit = nfc_genl_stop_poll ,
. policy = nfc_genl_policy ,
} ,
2011-12-14 19:43:09 +04:00
{
. cmd = NFC_CMD_DEP_LINK_UP ,
. doit = nfc_genl_dep_link_up ,
. policy = nfc_genl_policy ,
} ,
{
. cmd = NFC_CMD_DEP_LINK_DOWN ,
. doit = nfc_genl_dep_link_down ,
. policy = nfc_genl_policy ,
} ,
2011-07-02 02:31:34 +04:00
{
. cmd = NFC_CMD_GET_TARGET ,
. dumpit = nfc_genl_dump_targets ,
. done = nfc_genl_dump_targets_done ,
. policy = nfc_genl_policy ,
} ,
2012-10-17 16:43:39 +04:00
{
. cmd = NFC_CMD_LLC_GET_PARAMS ,
. doit = nfc_genl_llc_get_params ,
. policy = nfc_genl_policy ,
} ,
{
. cmd = NFC_CMD_LLC_SET_PARAMS ,
. doit = nfc_genl_llc_set_params ,
. policy = nfc_genl_policy ,
} ,
2013-02-15 13:43:06 +04:00
{
. cmd = NFC_CMD_LLC_SDREQ ,
. doit = nfc_genl_llc_sdreq ,
. policy = nfc_genl_policy ,
} ,
2013-04-29 19:13:27 +04:00
{
2013-07-31 03:19:43 +04:00
. cmd = NFC_CMD_FW_DOWNLOAD ,
. doit = nfc_genl_fw_download ,
2013-04-29 19:13:27 +04:00
. policy = nfc_genl_policy ,
} ,
2013-05-10 19:07:32 +04:00
{
. cmd = NFC_CMD_ENABLE_SE ,
. doit = nfc_genl_enable_se ,
. policy = nfc_genl_policy ,
} ,
{
. cmd = NFC_CMD_DISABLE_SE ,
. doit = nfc_genl_disable_se ,
. policy = nfc_genl_policy ,
} ,
2013-07-24 20:10:50 +04:00
{
. cmd = NFC_CMD_GET_SE ,
. dumpit = nfc_genl_dump_ses ,
. done = nfc_genl_dump_ses_done ,
. policy = nfc_genl_policy ,
} ,
2013-08-28 02:47:24 +04:00
{
. cmd = NFC_CMD_SE_IO ,
. doit = nfc_genl_se_io ,
. policy = nfc_genl_policy ,
} ,
2011-07-02 02:31:34 +04:00
} ;
2012-09-26 16:17:12 +04:00
struct urelease_work {
struct work_struct w ;
2012-09-28 19:11:16 +04:00
int portid ;
2012-09-26 16:17:12 +04:00
} ;
static void nfc_urelease_event_work ( struct work_struct * work )
2011-07-02 02:31:34 +04:00
{
2012-09-26 16:17:12 +04:00
struct urelease_work * w = container_of ( work , struct urelease_work , w ) ;
2011-07-02 02:31:34 +04:00
struct class_dev_iter iter ;
struct nfc_dev * dev ;
2012-09-28 19:11:16 +04:00
pr_debug ( " portid %d \n " , w - > portid ) ;
2011-07-02 02:31:34 +04:00
2012-09-26 16:17:12 +04:00
mutex_lock ( & nfc_devlist_mutex ) ;
2011-07-02 02:31:34 +04:00
nfc_device_iter_init ( & iter ) ;
dev = nfc_device_iter_next ( & iter ) ;
while ( dev ) {
2012-09-26 16:17:12 +04:00
mutex_lock ( & dev - > genl_data . genl_data_mutex ) ;
2012-09-28 19:11:16 +04:00
if ( dev - > genl_data . poll_req_portid = = w - > portid ) {
2011-07-02 02:31:34 +04:00
nfc_stop_poll ( dev ) ;
2012-09-08 00:12:54 +04:00
dev - > genl_data . poll_req_portid = 0 ;
2011-07-02 02:31:34 +04:00
}
2012-09-26 16:17:12 +04:00
mutex_unlock ( & dev - > genl_data . genl_data_mutex ) ;
2011-07-02 02:31:34 +04:00
dev = nfc_device_iter_next ( & iter ) ;
}
nfc_device_iter_exit ( & iter ) ;
2012-09-26 16:17:12 +04:00
mutex_unlock ( & nfc_devlist_mutex ) ;
kfree ( w ) ;
}
static int nfc_genl_rcv_nl_event ( struct notifier_block * this ,
unsigned long event , void * ptr )
{
struct netlink_notify * n = ptr ;
struct urelease_work * w ;
if ( event ! = NETLINK_URELEASE | | n - > protocol ! = NETLINK_GENERIC )
goto out ;
2012-09-28 19:11:16 +04:00
pr_debug ( " NETLINK_URELEASE event from id %d \n " , n - > portid ) ;
2012-09-26 16:17:12 +04:00
w = kmalloc ( sizeof ( * w ) , GFP_ATOMIC ) ;
if ( w ) {
INIT_WORK ( ( struct work_struct * ) w , nfc_urelease_event_work ) ;
2012-09-28 19:11:16 +04:00
w - > portid = n - > portid ;
2012-09-26 16:17:12 +04:00
schedule_work ( ( struct work_struct * ) w ) ;
}
2011-07-02 02:31:34 +04:00
out :
return NOTIFY_DONE ;
}
void nfc_genl_data_init ( struct nfc_genl_data * genl_data )
{
2012-09-08 00:12:54 +04:00
genl_data - > poll_req_portid = 0 ;
2011-07-02 02:31:34 +04:00
mutex_init ( & genl_data - > genl_data_mutex ) ;
}
void nfc_genl_data_exit ( struct nfc_genl_data * genl_data )
{
mutex_destroy ( & genl_data - > genl_data_mutex ) ;
}
static struct notifier_block nl_notifier = {
. notifier_call = nfc_genl_rcv_nl_event ,
} ;
/**
* nfc_genl_init ( ) - Initialize netlink interface
*
* This initialization function registers the nfc netlink family .
*/
int __init nfc_genl_init ( void )
{
int rc ;
2013-11-19 18:19:39 +04:00
rc = genl_register_family_with_ops_groups ( & nfc_genl_family ,
nfc_genl_ops ,
nfc_genl_mcgrps ) ;
2011-07-02 02:31:34 +04:00
if ( rc )
return rc ;
netlink_register_notifier ( & nl_notifier ) ;
2013-11-19 18:19:39 +04:00
return 0 ;
2011-07-02 02:31:34 +04:00
}
/**
* nfc_genl_exit ( ) - Deinitialize netlink interface
*
* This exit function unregisters the nfc netlink family .
*/
void nfc_genl_exit ( void )
{
netlink_unregister_notifier ( & nl_notifier ) ;
genl_unregister_family ( & nfc_genl_family ) ;
}