2007-02-09 17:24:33 +03:00
/*
2005-04-17 02:20:36 +04:00
BNEP implementation for Linux Bluetooth stack ( BlueZ ) .
Copyright ( C ) 2001 - 2002 Inventel Systemes
Written 2001 - 2002 by
David Libault < david . libault @ inventel . fr >
Copyright ( C ) 2002 Maxim Krasnyansky < maxk @ qualcomm . com >
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License version 2 as
published by the Free Software Foundation ;
THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS
OR IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS .
IN NO EVENT SHALL THE COPYRIGHT HOLDER ( S ) AND AUTHOR ( S ) BE LIABLE FOR ANY
2007-02-09 17:24:33 +03:00
CLAIM , OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES , OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE , DATA OR PROFITS , WHETHER IN AN
ACTION OF CONTRACT , NEGLIGENCE OR OTHER TORTIOUS ACTION , ARISING OUT OF
2005-04-17 02:20:36 +04:00
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE .
2007-02-09 17:24:33 +03:00
ALL LIABILITY , INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS ,
COPYRIGHTS , TRADEMARKS OR OTHER RIGHTS , RELATING TO USE OF THIS
2005-04-17 02:20:36 +04:00
SOFTWARE IS DISCLAIMED .
*/
2012-05-23 11:04:22 +04:00
# include <linux/export.h>
2005-04-17 02:20:36 +04:00
# include <linux/file.h>
# include "bnep.h"
2012-07-25 20:27:35 +04:00
static struct bt_sock_list bnep_sk_list = {
. lock = __RW_LOCK_UNLOCKED ( bnep_sk_list . lock )
} ;
2005-04-17 02:20:36 +04:00
static int bnep_sock_release ( struct socket * sock )
{
struct sock * sk = sock - > sk ;
BT_DBG ( " sock %p sk %p " , sock , sk ) ;
if ( ! sk )
return 0 ;
2012-07-25 20:27:35 +04:00
bt_sock_unlink ( & bnep_sk_list , sk ) ;
2005-04-17 02:20:36 +04:00
sock_orphan ( sk ) ;
sock_put ( sk ) ;
return 0 ;
}
2018-08-17 04:33:23 +03:00
static int do_bnep_sock_ioctl ( struct socket * sock , unsigned int cmd , void __user * argp )
2005-04-17 02:20:36 +04:00
{
struct bnep_connlist_req cl ;
struct bnep_connadd_req ca ;
struct bnep_conndel_req cd ;
struct bnep_conninfo ci ;
struct socket * nsock ;
2015-04-03 13:14:55 +03:00
__u32 supp_feat = BIT ( BNEP_SETUP_RESPONSE ) ;
2005-04-17 02:20:36 +04:00
int err ;
2018-08-17 04:33:23 +03:00
BT_DBG ( " cmd %x arg %p " , cmd , argp ) ;
2005-04-17 02:20:36 +04:00
switch ( cmd ) {
case BNEPCONNADD :
if ( ! capable ( CAP_NET_ADMIN ) )
2012-09-21 02:37:25 +04:00
return - EPERM ;
2005-04-17 02:20:36 +04:00
if ( copy_from_user ( & ca , argp , sizeof ( ca ) ) )
return - EFAULT ;
2007-02-09 17:24:33 +03:00
2005-04-17 02:20:36 +04:00
nsock = sockfd_lookup ( ca . sock , & err ) ;
if ( ! nsock )
return err ;
if ( nsock - > sk - > sk_state ! = BT_CONNECTED ) {
2008-01-08 09:38:42 +03:00
sockfd_put ( nsock ) ;
2005-04-17 02:20:36 +04:00
return - EBADFD ;
}
2011-02-14 13:54:31 +03:00
ca . device [ sizeof ( ca . device ) - 1 ] = 0 ;
2005-04-17 02:20:36 +04:00
err = bnep_add_connection ( & ca , nsock ) ;
if ( ! err ) {
2007-02-09 17:24:33 +03:00
if ( copy_to_user ( argp , & ca , sizeof ( ca ) ) )
2005-04-17 02:20:36 +04:00
err = - EFAULT ;
} else
2008-01-08 09:38:42 +03:00
sockfd_put ( nsock ) ;
2005-04-17 02:20:36 +04:00
return err ;
2007-02-09 17:24:33 +03:00
2005-04-17 02:20:36 +04:00
case BNEPCONNDEL :
if ( ! capable ( CAP_NET_ADMIN ) )
2012-09-21 02:37:25 +04:00
return - EPERM ;
2005-04-17 02:20:36 +04:00
if ( copy_from_user ( & cd , argp , sizeof ( cd ) ) )
return - EFAULT ;
2007-02-09 17:24:33 +03:00
2005-04-17 02:20:36 +04:00
return bnep_del_connection ( & cd ) ;
case BNEPGETCONNLIST :
if ( copy_from_user ( & cl , argp , sizeof ( cl ) ) )
return - EFAULT ;
if ( cl . cnum < = 0 )
return - EINVAL ;
2007-02-09 17:24:33 +03:00
2005-04-17 02:20:36 +04:00
err = bnep_get_connlist ( & cl ) ;
if ( ! err & & copy_to_user ( argp , & cl , sizeof ( cl ) ) )
return - EFAULT ;
return err ;
case BNEPGETCONNINFO :
if ( copy_from_user ( & ci , argp , sizeof ( ci ) ) )
return - EFAULT ;
err = bnep_get_conninfo ( & ci ) ;
if ( ! err & & copy_to_user ( argp , & ci , sizeof ( ci ) ) )
return - EFAULT ;
return err ;
2015-04-03 13:14:53 +03:00
case BNEPGETSUPPFEAT :
if ( copy_to_user ( argp , & supp_feat , sizeof ( supp_feat ) ) )
return - EFAULT ;
return 0 ;
2005-04-17 02:20:36 +04:00
default :
return - EINVAL ;
}
return 0 ;
}
2018-08-17 04:33:23 +03:00
static int bnep_sock_ioctl ( struct socket * sock , unsigned int cmd , unsigned long arg )
{
return do_bnep_sock_ioctl ( sock , cmd , ( void __user * ) arg ) ;
}
2006-10-15 19:30:22 +04:00
# ifdef CONFIG_COMPAT
static int bnep_sock_compat_ioctl ( struct socket * sock , unsigned int cmd , unsigned long arg )
{
2018-08-17 04:33:23 +03:00
void __user * argp = compat_ptr ( arg ) ;
2006-10-15 19:30:22 +04:00
if ( cmd = = BNEPGETCONNLIST ) {
struct bnep_connlist_req cl ;
2018-08-17 04:33:23 +03:00
unsigned __user * p = argp ;
2012-02-26 15:04:52 +04:00
u32 uci ;
2006-10-15 19:30:22 +04:00
int err ;
2018-08-17 04:33:23 +03:00
if ( get_user ( cl . cnum , p ) | | get_user ( uci , p + 1 ) )
2006-10-15 19:30:22 +04:00
return - EFAULT ;
cl . ci = compat_ptr ( uci ) ;
if ( cl . cnum < = 0 )
return - EINVAL ;
2007-02-09 17:24:33 +03:00
2006-10-15 19:30:22 +04:00
err = bnep_get_connlist ( & cl ) ;
2018-08-17 04:33:23 +03:00
if ( ! err & & put_user ( cl . cnum , p ) )
2006-10-15 19:30:22 +04:00
err = - EFAULT ;
return err ;
}
2018-08-17 04:33:23 +03:00
return do_bnep_sock_ioctl ( sock , cmd , argp ) ;
2006-10-15 19:30:22 +04:00
}
# endif
2005-12-22 23:49:22 +03:00
static const struct proto_ops bnep_sock_ops = {
2006-10-15 19:30:22 +04:00
. family = PF_BLUETOOTH ,
. owner = THIS_MODULE ,
. release = bnep_sock_release ,
. ioctl = bnep_sock_ioctl ,
# ifdef CONFIG_COMPAT
. compat_ioctl = bnep_sock_compat_ioctl ,
# endif
. bind = sock_no_bind ,
. getname = sock_no_getname ,
. sendmsg = sock_no_sendmsg ,
. recvmsg = sock_no_recvmsg ,
. listen = sock_no_listen ,
. shutdown = sock_no_shutdown ,
. connect = sock_no_connect ,
. socketpair = sock_no_socketpair ,
. accept = sock_no_accept ,
. mmap = sock_no_mmap
2005-04-17 02:20:36 +04:00
} ;
static struct proto bnep_proto = {
. name = " BNEP " ,
. owner = THIS_MODULE ,
. obj_size = sizeof ( struct bt_sock )
} ;
2009-11-06 09:18:14 +03:00
static int bnep_sock_create ( struct net * net , struct socket * sock , int protocol ,
int kern )
2005-04-17 02:20:36 +04:00
{
struct sock * sk ;
BT_DBG ( " sock %p " , sock ) ;
if ( sock - > type ! = SOCK_RAW )
return - ESOCKTNOSUPPORT ;
2015-05-09 05:09:13 +03:00
sk = sk_alloc ( net , PF_BLUETOOTH , GFP_ATOMIC , & bnep_proto , kern ) ;
2005-04-17 02:20:36 +04:00
if ( ! sk )
return - ENOMEM ;
sock_init_data ( sock , sk ) ;
sock - > ops = & bnep_sock_ops ;
sock - > state = SS_UNCONNECTED ;
sock_reset_flag ( sk , SOCK_ZAPPED ) ;
sk - > sk_protocol = protocol ;
sk - > sk_state = BT_OPEN ;
2012-07-25 20:27:35 +04:00
bt_sock_link ( & bnep_sk_list , sk ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2009-10-05 09:58:39 +04:00
static const struct net_proto_family bnep_sock_family_ops = {
2005-04-17 02:20:36 +04:00
. family = PF_BLUETOOTH ,
. owner = THIS_MODULE ,
. create = bnep_sock_create
} ;
int __init bnep_sock_init ( void )
{
int err ;
err = proto_register ( & bnep_proto , 0 ) ;
if ( err < 0 )
return err ;
err = bt_sock_register ( BTPROTO_BNEP , & bnep_sock_family_ops ) ;
2012-07-25 20:27:35 +04:00
if ( err < 0 ) {
BT_ERR ( " Can't register BNEP socket " ) ;
2005-04-17 02:20:36 +04:00
goto error ;
2012-07-25 20:27:35 +04:00
}
2013-04-05 03:14:33 +04:00
err = bt_procfs_init ( & init_net , " bnep " , & bnep_sk_list , NULL ) ;
2012-07-25 20:27:35 +04:00
if ( err < 0 ) {
BT_ERR ( " Failed to create BNEP proc file " ) ;
bt_sock_unregister ( BTPROTO_BNEP ) ;
goto error ;
}
BT_INFO ( " BNEP socket layer initialized " ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
error :
proto_unregister ( & bnep_proto ) ;
return err ;
}
2008-03-06 05:47:40 +03:00
void __exit bnep_sock_cleanup ( void )
2005-04-17 02:20:36 +04:00
{
2012-07-25 20:27:35 +04:00
bt_procfs_cleanup ( & init_net , " bnep " ) ;
2013-02-24 22:36:51 +04:00
bt_sock_unregister ( BTPROTO_BNEP ) ;
2005-04-17 02:20:36 +04:00
proto_unregister ( & bnep_proto ) ;
}