2011-02-04 01:50:35 +03:00
/*
BlueZ - Bluetooth protocol stack for Linux
Copyright ( C ) 2000 - 2001 Qualcomm Incorporated
Copyright ( C ) 2009 - 2010 Gustavo F . Padovan < gustavo @ padovan . org >
Copyright ( C ) 2010 Google Inc .
Written 2000 , 2001 by 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
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
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE .
ALL LIABILITY , INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS ,
COPYRIGHTS , TRADEMARKS OR OTHER RIGHTS , RELATING TO USE OF THIS
SOFTWARE IS DISCLAIMED .
*/
/* Bluetooth L2CAP sockets. */
# include <net/bluetooth/bluetooth.h>
2011-02-04 07:48:48 +03:00
# include <net/bluetooth/hci_core.h>
2011-02-04 01:50:35 +03:00
# include <net/bluetooth/l2cap.h>
2011-04-28 01:40:39 +04:00
static const struct proto_ops l2cap_sock_ops ;
2011-05-17 00:24:37 +04:00
static void l2cap_sock_init ( struct sock * sk , struct sock * parent ) ;
static struct sock * l2cap_sock_alloc ( struct net * net , struct socket * sock , int proto , gfp_t prio ) ;
2011-04-28 01:40:39 +04:00
2011-02-04 07:40:28 +03:00
static int l2cap_sock_bind ( struct socket * sock , struct sockaddr * addr , int alen )
{
struct sock * sk = sock - > sk ;
2011-04-13 01:31:57 +04:00
struct l2cap_chan * chan = l2cap_pi ( sk ) - > chan ;
2011-02-04 07:40:28 +03:00
struct sockaddr_l2 la ;
int len , err = 0 ;
BT_DBG ( " sk %p " , sk ) ;
if ( ! addr | | addr - > sa_family ! = AF_BLUETOOTH )
return - EINVAL ;
memset ( & la , 0 , sizeof ( la ) ) ;
len = min_t ( unsigned int , sizeof ( la ) , alen ) ;
memcpy ( & la , addr , len ) ;
2011-02-11 04:38:50 +03:00
if ( la . l2_cid & & la . l2_psm )
2011-02-04 07:40:28 +03:00
return - EINVAL ;
lock_sock ( sk ) ;
if ( sk - > sk_state ! = BT_OPEN ) {
err = - EBADFD ;
goto done ;
}
if ( la . l2_psm ) {
__u16 psm = __le16_to_cpu ( la . l2_psm ) ;
/* PSM must be odd and lsb of upper byte must be 0 */
if ( ( psm & 0x0101 ) ! = 0x0001 ) {
err = - EINVAL ;
goto done ;
}
/* Restrict usage of well-known PSMs */
if ( psm < 0x1001 & & ! capable ( CAP_NET_BIND_SERVICE ) ) {
err = - EACCES ;
goto done ;
}
}
2011-04-19 01:38:43 +04:00
if ( la . l2_cid )
err = l2cap_add_scid ( chan , la . l2_cid ) ;
else
err = l2cap_add_psm ( chan , & la . l2_bdaddr , la . l2_psm ) ;
2011-02-04 07:40:28 +03:00
2011-04-19 01:38:43 +04:00
if ( err < 0 )
goto done ;
2011-02-04 07:40:28 +03:00
2011-04-19 01:38:43 +04:00
if ( __le16_to_cpu ( la . l2_psm ) = = 0x0001 | |
__le16_to_cpu ( la . l2_psm ) = = 0x0003 )
chan - > sec_level = BT_SECURITY_SDP ;
2011-02-11 04:38:50 +03:00
2011-04-19 01:38:43 +04:00
bacpy ( & bt_sk ( sk ) - > src , & la . l2_bdaddr ) ;
sk - > sk_state = BT_BOUND ;
2011-02-04 07:40:28 +03:00
done :
release_sock ( sk ) ;
return err ;
}
2011-02-04 07:56:13 +03:00
static int l2cap_sock_connect ( struct socket * sock , struct sockaddr * addr , int alen , int flags )
{
struct sock * sk = sock - > sk ;
2011-04-14 00:20:49 +04:00
struct l2cap_chan * chan = l2cap_pi ( sk ) - > chan ;
2011-02-04 07:56:13 +03:00
struct sockaddr_l2 la ;
int len , err = 0 ;
BT_DBG ( " sk %p " , sk ) ;
if ( ! addr | | alen < sizeof ( addr - > sa_family ) | |
addr - > sa_family ! = AF_BLUETOOTH )
return - EINVAL ;
memset ( & la , 0 , sizeof ( la ) ) ;
len = min_t ( unsigned int , sizeof ( la ) , alen ) ;
memcpy ( & la , addr , len ) ;
2011-02-11 04:38:49 +03:00
if ( la . l2_cid & & la . l2_psm )
2011-02-04 07:56:13 +03:00
return - EINVAL ;
lock_sock ( sk ) ;
2011-05-03 00:13:55 +04:00
if ( chan - > chan_type = = L2CAP_CHAN_CONN_ORIENTED
2011-02-11 04:38:49 +03:00
& & ! ( la . l2_psm | | la . l2_cid ) ) {
2011-02-04 07:56:13 +03:00
err = - EINVAL ;
goto done ;
}
2011-04-14 00:20:49 +04:00
switch ( chan - > mode ) {
2011-02-04 07:56:13 +03:00
case L2CAP_MODE_BASIC :
break ;
case L2CAP_MODE_ERTM :
case L2CAP_MODE_STREAMING :
if ( ! disable_ertm )
break ;
/* fall through */
default :
err = - ENOTSUPP ;
goto done ;
}
switch ( sk - > sk_state ) {
case BT_CONNECT :
case BT_CONNECT2 :
case BT_CONFIG :
/* Already connecting */
goto wait ;
case BT_CONNECTED :
/* Already connected */
err = - EISCONN ;
goto done ;
case BT_OPEN :
case BT_BOUND :
/* Can connect */
break ;
default :
err = - EBADFD ;
goto done ;
}
/* PSM must be odd and lsb of upper byte must be 0 */
2011-05-03 00:13:55 +04:00
if ( ( __le16_to_cpu ( la . l2_psm ) & 0x0101 ) ! = 0x0001 & & ! la . l2_cid & &
chan - > chan_type ! = L2CAP_CHAN_RAW ) {
2011-02-04 07:56:13 +03:00
err = - EINVAL ;
goto done ;
}
/* Set destination address and psm */
bacpy ( & bt_sk ( sk ) - > dst , & la . l2_bdaddr ) ;
2011-04-14 02:50:45 +04:00
chan - > psm = la . l2_psm ;
chan - > dcid = la . l2_cid ;
2011-02-04 07:56:13 +03:00
2011-04-13 01:17:14 +04:00
err = l2cap_chan_connect ( l2cap_pi ( sk ) - > chan ) ;
2011-02-04 07:56:13 +03:00
if ( err )
goto done ;
wait :
err = bt_sock_wait_state ( sk , BT_CONNECTED ,
sock_sndtimeo ( sk , flags & O_NONBLOCK ) ) ;
done :
release_sock ( sk ) ;
return err ;
}
2011-02-04 07:40:28 +03:00
static int l2cap_sock_listen ( struct socket * sock , int backlog )
{
struct sock * sk = sock - > sk ;
2011-04-14 00:20:49 +04:00
struct l2cap_chan * chan = l2cap_pi ( sk ) - > chan ;
2011-02-04 07:40:28 +03:00
int err = 0 ;
BT_DBG ( " sk %p backlog %d " , sk , backlog ) ;
lock_sock ( sk ) ;
if ( ( sock - > type ! = SOCK_SEQPACKET & & sock - > type ! = SOCK_STREAM )
| | sk - > sk_state ! = BT_BOUND ) {
err = - EBADFD ;
goto done ;
}
2011-04-14 00:20:49 +04:00
switch ( chan - > mode ) {
2011-02-04 07:40:28 +03:00
case L2CAP_MODE_BASIC :
break ;
case L2CAP_MODE_ERTM :
case L2CAP_MODE_STREAMING :
if ( ! disable_ertm )
break ;
/* fall through */
default :
err = - ENOTSUPP ;
goto done ;
}
sk - > sk_max_ack_backlog = backlog ;
sk - > sk_ack_backlog = 0 ;
sk - > sk_state = BT_LISTEN ;
done :
release_sock ( sk ) ;
return err ;
}
2011-02-04 07:42:23 +03:00
static int l2cap_sock_accept ( struct socket * sock , struct socket * newsock , int flags )
{
DECLARE_WAITQUEUE ( wait , current ) ;
struct sock * sk = sock - > sk , * nsk ;
long timeo ;
int err = 0 ;
lock_sock_nested ( sk , SINGLE_DEPTH_NESTING ) ;
if ( sk - > sk_state ! = BT_LISTEN ) {
err = - EBADFD ;
goto done ;
}
timeo = sock_rcvtimeo ( sk , flags & O_NONBLOCK ) ;
BT_DBG ( " sk %p timeo %ld " , sk , timeo ) ;
/* Wait for an incoming connection. (wake-one). */
add_wait_queue_exclusive ( sk_sleep ( sk ) , & wait ) ;
while ( ! ( nsk = bt_accept_dequeue ( sk , newsock ) ) ) {
set_current_state ( TASK_INTERRUPTIBLE ) ;
if ( ! timeo ) {
err = - EAGAIN ;
break ;
}
release_sock ( sk ) ;
timeo = schedule_timeout ( timeo ) ;
lock_sock_nested ( sk , SINGLE_DEPTH_NESTING ) ;
if ( sk - > sk_state ! = BT_LISTEN ) {
err = - EBADFD ;
break ;
}
if ( signal_pending ( current ) ) {
err = sock_intr_errno ( timeo ) ;
break ;
}
}
set_current_state ( TASK_RUNNING ) ;
remove_wait_queue ( sk_sleep ( sk ) , & wait ) ;
if ( err )
goto done ;
newsock - > state = SS_CONNECTED ;
BT_DBG ( " new socket %p " , nsk ) ;
done :
release_sock ( sk ) ;
return err ;
}
2011-02-04 07:43:46 +03:00
static int l2cap_sock_getname ( struct socket * sock , struct sockaddr * addr , int * len , int peer )
{
struct sockaddr_l2 * la = ( struct sockaddr_l2 * ) addr ;
struct sock * sk = sock - > sk ;
2011-04-14 00:20:49 +04:00
struct l2cap_chan * chan = l2cap_pi ( sk ) - > chan ;
2011-02-04 07:43:46 +03:00
BT_DBG ( " sock %p, sk %p " , sock , sk ) ;
addr - > sa_family = AF_BLUETOOTH ;
* len = sizeof ( struct sockaddr_l2 ) ;
if ( peer ) {
2011-04-14 02:50:45 +04:00
la - > l2_psm = chan - > psm ;
2011-02-04 07:43:46 +03:00
bacpy ( & la - > l2_bdaddr , & bt_sk ( sk ) - > dst ) ;
2011-04-14 02:50:45 +04:00
la - > l2_cid = cpu_to_le16 ( chan - > dcid ) ;
2011-02-04 07:43:46 +03:00
} else {
2011-04-14 00:20:49 +04:00
la - > l2_psm = chan - > sport ;
2011-02-04 07:43:46 +03:00
bacpy ( & la - > l2_bdaddr , & bt_sk ( sk ) - > src ) ;
2011-04-14 02:50:45 +04:00
la - > l2_cid = cpu_to_le16 ( chan - > scid ) ;
2011-02-04 07:43:46 +03:00
}
return 0 ;
}
2011-02-04 07:52:55 +03:00
static int l2cap_sock_getsockopt_old ( struct socket * sock , int optname , char __user * optval , int __user * optlen )
{
struct sock * sk = sock - > sk ;
2011-04-13 01:31:57 +04:00
struct l2cap_chan * chan = l2cap_pi ( sk ) - > chan ;
2011-02-04 07:52:55 +03:00
struct l2cap_options opts ;
struct l2cap_conninfo cinfo ;
int len , err = 0 ;
u32 opt ;
BT_DBG ( " sk %p " , sk ) ;
if ( get_user ( len , optlen ) )
return - EFAULT ;
lock_sock ( sk ) ;
switch ( optname ) {
case L2CAP_OPTIONS :
2011-02-10 20:59:42 +03:00
memset ( & opts , 0 , sizeof ( opts ) ) ;
2011-04-14 00:20:49 +04:00
opts . imtu = chan - > imtu ;
opts . omtu = chan - > omtu ;
opts . flush_to = chan - > flush_to ;
opts . mode = chan - > mode ;
2011-04-13 22:57:03 +04:00
opts . fcs = chan - > fcs ;
opts . max_tx = chan - > max_tx ;
opts . txwin_size = ( __u16 ) chan - > tx_win ;
2011-02-04 07:52:55 +03:00
len = min_t ( unsigned int , len , sizeof ( opts ) ) ;
if ( copy_to_user ( optval , ( char * ) & opts , len ) )
err = - EFAULT ;
break ;
case L2CAP_LM :
2011-04-13 01:31:57 +04:00
switch ( chan - > sec_level ) {
2011-02-04 07:52:55 +03:00
case BT_SECURITY_LOW :
opt = L2CAP_LM_AUTH ;
break ;
case BT_SECURITY_MEDIUM :
opt = L2CAP_LM_AUTH | L2CAP_LM_ENCRYPT ;
break ;
case BT_SECURITY_HIGH :
opt = L2CAP_LM_AUTH | L2CAP_LM_ENCRYPT |
L2CAP_LM_SECURE ;
break ;
default :
opt = 0 ;
break ;
}
2011-04-13 01:31:57 +04:00
if ( chan - > role_switch )
2011-02-04 07:52:55 +03:00
opt | = L2CAP_LM_MASTER ;
2011-04-13 01:31:57 +04:00
if ( chan - > force_reliable )
2011-02-04 07:52:55 +03:00
opt | = L2CAP_LM_RELIABLE ;
if ( put_user ( opt , ( u32 __user * ) optval ) )
err = - EFAULT ;
break ;
case L2CAP_CONNINFO :
if ( sk - > sk_state ! = BT_CONNECTED & &
! ( sk - > sk_state = = BT_CONNECT2 & &
bt_sk ( sk ) - > defer_setup ) ) {
err = - ENOTCONN ;
break ;
}
2011-05-12 21:32:46 +04:00
memset ( & cinfo , 0 , sizeof ( cinfo ) ) ;
2011-04-14 03:23:55 +04:00
cinfo . hci_handle = chan - > conn - > hcon - > handle ;
memcpy ( cinfo . dev_class , chan - > conn - > hcon - > dev_class , 3 ) ;
2011-02-04 07:52:55 +03:00
len = min_t ( unsigned int , len , sizeof ( cinfo ) ) ;
if ( copy_to_user ( optval , ( char * ) & cinfo , len ) )
err = - EFAULT ;
break ;
default :
err = - ENOPROTOOPT ;
break ;
}
release_sock ( sk ) ;
return err ;
}
static int l2cap_sock_getsockopt ( struct socket * sock , int level , int optname , char __user * optval , int __user * optlen )
{
struct sock * sk = sock - > sk ;
2011-04-13 01:31:57 +04:00
struct l2cap_chan * chan = l2cap_pi ( sk ) - > chan ;
2011-02-04 07:52:55 +03:00
struct bt_security sec ;
2011-05-24 05:06:04 +04:00
struct bt_power pwr ;
2011-02-04 07:52:55 +03:00
int len , err = 0 ;
BT_DBG ( " sk %p " , sk ) ;
if ( level = = SOL_L2CAP )
return l2cap_sock_getsockopt_old ( sock , optname , optval , optlen ) ;
if ( level ! = SOL_BLUETOOTH )
return - ENOPROTOOPT ;
if ( get_user ( len , optlen ) )
return - EFAULT ;
lock_sock ( sk ) ;
switch ( optname ) {
case BT_SECURITY :
2011-05-03 00:13:55 +04:00
if ( chan - > chan_type ! = L2CAP_CHAN_CONN_ORIENTED & &
chan - > chan_type ! = L2CAP_CHAN_RAW ) {
2011-02-04 07:52:55 +03:00
err = - EINVAL ;
break ;
}
2011-04-13 01:31:57 +04:00
sec . level = chan - > sec_level ;
2011-02-04 07:52:55 +03:00
len = min_t ( unsigned int , len , sizeof ( sec ) ) ;
if ( copy_to_user ( optval , ( char * ) & sec , len ) )
err = - EFAULT ;
break ;
case BT_DEFER_SETUP :
if ( sk - > sk_state ! = BT_BOUND & & sk - > sk_state ! = BT_LISTEN ) {
err = - EINVAL ;
break ;
}
if ( put_user ( bt_sk ( sk ) - > defer_setup , ( u32 __user * ) optval ) )
err = - EFAULT ;
break ;
case BT_FLUSHABLE :
2011-04-13 01:31:57 +04:00
if ( put_user ( chan - > flushable , ( u32 __user * ) optval ) )
2011-02-04 07:52:55 +03:00
err = - EFAULT ;
break ;
2011-05-24 05:06:04 +04:00
case BT_POWER :
if ( sk - > sk_type ! = SOCK_SEQPACKET & & sk - > sk_type ! = SOCK_STREAM
& & sk - > sk_type ! = SOCK_RAW ) {
err = - EINVAL ;
break ;
}
pwr . force_active = chan - > force_active ;
len = min_t ( unsigned int , len , sizeof ( pwr ) ) ;
if ( copy_to_user ( optval , ( char * ) & pwr , len ) )
err = - EFAULT ;
break ;
2011-02-04 07:52:55 +03:00
default :
err = - ENOPROTOOPT ;
break ;
}
release_sock ( sk ) ;
return err ;
}
2011-02-04 07:48:48 +03:00
static int l2cap_sock_setsockopt_old ( struct socket * sock , int optname , char __user * optval , unsigned int optlen )
{
struct sock * sk = sock - > sk ;
2011-04-13 01:15:09 +04:00
struct l2cap_chan * chan = l2cap_pi ( sk ) - > chan ;
2011-02-04 07:48:48 +03:00
struct l2cap_options opts ;
int len , err = 0 ;
u32 opt ;
BT_DBG ( " sk %p " , sk ) ;
lock_sock ( sk ) ;
switch ( optname ) {
case L2CAP_OPTIONS :
if ( sk - > sk_state = = BT_CONNECTED ) {
err = - EINVAL ;
break ;
}
2011-04-14 00:20:49 +04:00
opts . imtu = chan - > imtu ;
opts . omtu = chan - > omtu ;
opts . flush_to = chan - > flush_to ;
opts . mode = chan - > mode ;
2011-04-13 22:57:03 +04:00
opts . fcs = chan - > fcs ;
opts . max_tx = chan - > max_tx ;
opts . txwin_size = ( __u16 ) chan - > tx_win ;
2011-02-04 07:48:48 +03:00
len = min_t ( unsigned int , sizeof ( opts ) , optlen ) ;
if ( copy_from_user ( ( char * ) & opts , optval , len ) ) {
err = - EFAULT ;
break ;
}
if ( opts . txwin_size > L2CAP_DEFAULT_TX_WINDOW ) {
err = - EINVAL ;
break ;
}
2011-04-14 00:20:49 +04:00
chan - > mode = opts . mode ;
switch ( chan - > mode ) {
2011-02-04 07:48:48 +03:00
case L2CAP_MODE_BASIC :
2011-04-13 01:15:09 +04:00
chan - > conf_state & = ~ L2CAP_CONF_STATE2_DEVICE ;
2011-02-04 07:48:48 +03:00
break ;
case L2CAP_MODE_ERTM :
case L2CAP_MODE_STREAMING :
if ( ! disable_ertm )
break ;
/* fall through */
default :
err = - EINVAL ;
break ;
}
2011-04-14 00:20:49 +04:00
chan - > imtu = opts . imtu ;
chan - > omtu = opts . omtu ;
2011-04-13 22:57:03 +04:00
chan - > fcs = opts . fcs ;
chan - > max_tx = opts . max_tx ;
chan - > tx_win = ( __u8 ) opts . txwin_size ;
2011-02-04 07:48:48 +03:00
break ;
case L2CAP_LM :
if ( get_user ( opt , ( u32 __user * ) optval ) ) {
err = - EFAULT ;
break ;
}
if ( opt & L2CAP_LM_AUTH )
2011-04-13 01:31:57 +04:00
chan - > sec_level = BT_SECURITY_LOW ;
2011-02-04 07:48:48 +03:00
if ( opt & L2CAP_LM_ENCRYPT )
2011-04-13 01:31:57 +04:00
chan - > sec_level = BT_SECURITY_MEDIUM ;
2011-02-04 07:48:48 +03:00
if ( opt & L2CAP_LM_SECURE )
2011-04-13 01:31:57 +04:00
chan - > sec_level = BT_SECURITY_HIGH ;
2011-02-04 07:48:48 +03:00
2011-04-13 01:31:57 +04:00
chan - > role_switch = ( opt & L2CAP_LM_MASTER ) ;
chan - > force_reliable = ( opt & L2CAP_LM_RELIABLE ) ;
2011-02-04 07:48:48 +03:00
break ;
default :
err = - ENOPROTOOPT ;
break ;
}
release_sock ( sk ) ;
return err ;
}
static int l2cap_sock_setsockopt ( struct socket * sock , int level , int optname , char __user * optval , unsigned int optlen )
{
struct sock * sk = sock - > sk ;
2011-04-13 01:31:57 +04:00
struct l2cap_chan * chan = l2cap_pi ( sk ) - > chan ;
2011-02-04 07:48:48 +03:00
struct bt_security sec ;
2011-05-24 05:06:04 +04:00
struct bt_power pwr ;
2011-02-04 07:48:48 +03:00
int len , err = 0 ;
u32 opt ;
BT_DBG ( " sk %p " , sk ) ;
if ( level = = SOL_L2CAP )
return l2cap_sock_setsockopt_old ( sock , optname , optval , optlen ) ;
if ( level ! = SOL_BLUETOOTH )
return - ENOPROTOOPT ;
lock_sock ( sk ) ;
switch ( optname ) {
case BT_SECURITY :
2011-05-03 00:13:55 +04:00
if ( chan - > chan_type ! = L2CAP_CHAN_CONN_ORIENTED & &
chan - > chan_type ! = L2CAP_CHAN_RAW ) {
2011-02-04 07:48:48 +03:00
err = - EINVAL ;
break ;
}
sec . level = BT_SECURITY_LOW ;
len = min_t ( unsigned int , sizeof ( sec ) , optlen ) ;
if ( copy_from_user ( ( char * ) & sec , optval , len ) ) {
err = - EFAULT ;
break ;
}
if ( sec . level < BT_SECURITY_LOW | |
sec . level > BT_SECURITY_HIGH ) {
err = - EINVAL ;
break ;
}
2011-04-13 01:31:57 +04:00
chan - > sec_level = sec . level ;
2011-02-04 07:48:48 +03:00
break ;
case BT_DEFER_SETUP :
if ( sk - > sk_state ! = BT_BOUND & & sk - > sk_state ! = BT_LISTEN ) {
err = - EINVAL ;
break ;
}
if ( get_user ( opt , ( u32 __user * ) optval ) ) {
err = - EFAULT ;
break ;
}
bt_sk ( sk ) - > defer_setup = opt ;
break ;
case BT_FLUSHABLE :
if ( get_user ( opt , ( u32 __user * ) optval ) ) {
err = - EFAULT ;
break ;
}
if ( opt > BT_FLUSHABLE_ON ) {
err = - EINVAL ;
break ;
}
if ( opt = = BT_FLUSHABLE_OFF ) {
2011-04-14 03:23:55 +04:00
struct l2cap_conn * conn = chan - > conn ;
2011-03-31 05:57:33 +04:00
/* proceed further only when we have l2cap_conn and
2011-02-04 07:48:48 +03:00
No Flush support in the LM */
if ( ! conn | | ! lmp_no_flush_capable ( conn - > hcon - > hdev ) ) {
err = - EINVAL ;
break ;
}
}
2011-04-13 01:31:57 +04:00
chan - > flushable = opt ;
2011-02-04 07:48:48 +03:00
break ;
2011-05-24 05:06:04 +04:00
case BT_POWER :
if ( chan - > chan_type ! = L2CAP_CHAN_CONN_ORIENTED & &
chan - > chan_type ! = L2CAP_CHAN_RAW ) {
err = - EINVAL ;
break ;
}
pwr . force_active = BT_POWER_FORCE_ACTIVE_ON ;
len = min_t ( unsigned int , sizeof ( pwr ) , optlen ) ;
if ( copy_from_user ( ( char * ) & pwr , optval , len ) ) {
err = - EFAULT ;
break ;
}
chan - > force_active = pwr . force_active ;
break ;
2011-02-04 07:48:48 +03:00
default :
err = - ENOPROTOOPT ;
break ;
}
release_sock ( sk ) ;
return err ;
}
2011-02-04 08:20:52 +03:00
static int l2cap_sock_sendmsg ( struct kiocb * iocb , struct socket * sock , struct msghdr * msg , size_t len )
{
struct sock * sk = sock - > sk ;
2011-04-14 00:20:49 +04:00
struct l2cap_chan * chan = l2cap_pi ( sk ) - > chan ;
2011-02-04 08:20:52 +03:00
int err ;
BT_DBG ( " sock %p, sk %p " , sock , sk ) ;
err = sock_error ( sk ) ;
if ( err )
return err ;
if ( msg - > msg_flags & MSG_OOB )
return - EOPNOTSUPP ;
lock_sock ( sk ) ;
if ( sk - > sk_state ! = BT_CONNECTED ) {
2011-04-29 01:50:17 +04:00
release_sock ( sk ) ;
return - ENOTCONN ;
2011-02-04 08:20:52 +03:00
}
2011-04-29 01:50:17 +04:00
err = l2cap_chan_send ( chan , msg , len ) ;
2011-02-04 08:20:52 +03:00
release_sock ( sk ) ;
return err ;
}
2011-02-04 07:48:48 +03:00
2011-02-04 08:02:31 +03:00
static int l2cap_sock_recvmsg ( struct kiocb * iocb , struct socket * sock , struct msghdr * msg , size_t len , int flags )
{
struct sock * sk = sock - > sk ;
lock_sock ( sk ) ;
if ( sk - > sk_state = = BT_CONNECT2 & & bt_sk ( sk ) - > defer_setup ) {
2011-04-14 03:23:55 +04:00
sk - > sk_state = BT_CONFIG ;
__l2cap_connect_rsp_defer ( l2cap_pi ( sk ) - > chan ) ;
2011-02-04 08:02:31 +03:00
release_sock ( sk ) ;
return 0 ;
}
release_sock ( sk ) ;
if ( sock - > type = = SOCK_STREAM )
return bt_sock_stream_recvmsg ( iocb , sock , msg , len , flags ) ;
return bt_sock_recvmsg ( iocb , sock , msg , len , flags ) ;
}
2011-02-04 08:26:01 +03:00
/* Kill socket (only if zapped and orphan)
* Must be called on unlocked socket .
*/
2011-05-17 01:23:24 +04:00
static void l2cap_sock_kill ( struct sock * sk )
2011-02-04 08:26:01 +03:00
{
if ( ! sock_flag ( sk , SOCK_ZAPPED ) | | sk - > sk_socket )
return ;
BT_DBG ( " sk %p state %d " , sk , sk - > sk_state ) ;
/* Kill poor orphan */
2011-04-25 22:10:41 +04:00
2011-04-28 01:26:32 +04:00
l2cap_chan_destroy ( l2cap_pi ( sk ) - > chan ) ;
2011-02-04 08:26:01 +03:00
sock_set_flag ( sk , SOCK_DEAD ) ;
sock_put ( sk ) ;
}
2011-02-04 08:08:36 +03:00
static int l2cap_sock_shutdown ( struct socket * sock , int how )
{
struct sock * sk = sock - > sk ;
2011-04-14 00:20:49 +04:00
struct l2cap_chan * chan = l2cap_pi ( sk ) - > chan ;
2011-02-04 08:08:36 +03:00
int err = 0 ;
BT_DBG ( " sock %p, sk %p " , sock , sk ) ;
if ( ! sk )
return 0 ;
lock_sock ( sk ) ;
if ( ! sk - > sk_shutdown ) {
2011-04-14 00:20:49 +04:00
if ( chan - > mode = = L2CAP_MODE_ERTM )
2011-02-04 08:08:36 +03:00
err = __l2cap_wait_ack ( sk ) ;
sk - > sk_shutdown = SHUTDOWN_MASK ;
2011-05-05 02:42:50 +04:00
l2cap_chan_close ( chan , 0 ) ;
2011-02-04 08:08:36 +03:00
if ( sock_flag ( sk , SOCK_LINGER ) & & sk - > sk_lingertime )
err = bt_sock_wait_state ( sk , BT_CLOSED ,
sk - > sk_lingertime ) ;
}
if ( ! err & & sk - > sk_err )
err = - sk - > sk_err ;
release_sock ( sk ) ;
return err ;
}
2011-02-04 07:36:42 +03:00
static int l2cap_sock_release ( struct socket * sock )
{
struct sock * sk = sock - > sk ;
int err ;
BT_DBG ( " sock %p, sk %p " , sock , sk ) ;
if ( ! sk )
return 0 ;
err = l2cap_sock_shutdown ( sock , 2 ) ;
sock_orphan ( sk ) ;
l2cap_sock_kill ( sk ) ;
return err ;
}
2011-05-17 00:24:37 +04:00
static struct l2cap_chan * l2cap_sock_new_connection_cb ( void * data )
{
struct sock * sk , * parent = data ;
sk = l2cap_sock_alloc ( sock_net ( parent ) , NULL , BTPROTO_L2CAP ,
GFP_ATOMIC ) ;
if ( ! sk )
return NULL ;
l2cap_sock_init ( sk , parent ) ;
return l2cap_pi ( sk ) - > chan ;
}
2011-05-17 00:57:22 +04:00
static int l2cap_sock_recv_cb ( void * data , struct sk_buff * skb )
{
struct sock * sk = data ;
return sock_queue_rcv_skb ( sk , skb ) ;
}
2011-05-17 01:23:24 +04:00
static void l2cap_sock_close_cb ( void * data )
{
struct sock * sk = data ;
l2cap_sock_kill ( sk ) ;
}
2011-05-17 00:24:37 +04:00
static struct l2cap_ops l2cap_chan_ops = {
. name = " L2CAP Socket Interface " ,
. new_connection = l2cap_sock_new_connection_cb ,
2011-05-17 00:57:22 +04:00
. recv = l2cap_sock_recv_cb ,
2011-05-17 01:23:24 +04:00
. close = l2cap_sock_close_cb ,
2011-05-17 00:24:37 +04:00
} ;
2011-02-04 01:50:35 +03:00
static void l2cap_sock_destruct ( struct sock * sk )
{
BT_DBG ( " sk %p " , sk ) ;
skb_queue_purge ( & sk - > sk_receive_queue ) ;
skb_queue_purge ( & sk - > sk_write_queue ) ;
}
2011-05-17 00:24:37 +04:00
static void l2cap_sock_init ( struct sock * sk , struct sock * parent )
2011-02-04 01:50:35 +03:00
{
struct l2cap_pinfo * pi = l2cap_pi ( sk ) ;
2011-04-13 01:15:09 +04:00
struct l2cap_chan * chan = pi - > chan ;
2011-02-04 01:50:35 +03:00
BT_DBG ( " sk %p " , sk ) ;
if ( parent ) {
2011-04-13 01:15:09 +04:00
struct l2cap_chan * pchan = l2cap_pi ( parent ) - > chan ;
2011-02-04 01:50:35 +03:00
sk - > sk_type = parent - > sk_type ;
bt_sk ( sk ) - > defer_setup = bt_sk ( parent ) - > defer_setup ;
2011-05-03 00:13:55 +04:00
chan - > chan_type = pchan - > chan_type ;
2011-04-14 00:20:49 +04:00
chan - > imtu = pchan - > imtu ;
chan - > omtu = pchan - > omtu ;
2011-04-13 01:15:09 +04:00
chan - > conf_state = pchan - > conf_state ;
2011-04-14 00:20:49 +04:00
chan - > mode = pchan - > mode ;
2011-04-13 22:57:03 +04:00
chan - > fcs = pchan - > fcs ;
chan - > max_tx = pchan - > max_tx ;
chan - > tx_win = pchan - > tx_win ;
2011-04-13 01:31:57 +04:00
chan - > sec_level = pchan - > sec_level ;
chan - > role_switch = pchan - > role_switch ;
chan - > force_reliable = pchan - > force_reliable ;
chan - > flushable = pchan - > flushable ;
2011-05-24 05:06:04 +04:00
chan - > force_active = pchan - > force_active ;
2011-02-04 01:50:35 +03:00
} else {
2011-05-03 00:13:55 +04:00
switch ( sk - > sk_type ) {
case SOCK_RAW :
chan - > chan_type = L2CAP_CHAN_RAW ;
break ;
case SOCK_DGRAM :
chan - > chan_type = L2CAP_CHAN_CONN_LESS ;
break ;
case SOCK_SEQPACKET :
case SOCK_STREAM :
chan - > chan_type = L2CAP_CHAN_CONN_ORIENTED ;
break ;
}
2011-04-14 00:20:49 +04:00
chan - > imtu = L2CAP_DEFAULT_MTU ;
chan - > omtu = 0 ;
2011-02-04 01:50:35 +03:00
if ( ! disable_ertm & & sk - > sk_type = = SOCK_STREAM ) {
2011-04-14 00:20:49 +04:00
chan - > mode = L2CAP_MODE_ERTM ;
2011-04-13 01:15:09 +04:00
chan - > conf_state | = L2CAP_CONF_STATE2_DEVICE ;
2011-02-04 01:50:35 +03:00
} else {
2011-04-14 00:20:49 +04:00
chan - > mode = L2CAP_MODE_BASIC ;
2011-02-04 01:50:35 +03:00
}
2011-04-13 22:57:03 +04:00
chan - > max_tx = L2CAP_DEFAULT_MAX_TX ;
chan - > fcs = L2CAP_FCS_CRC16 ;
chan - > tx_win = L2CAP_DEFAULT_TX_WINDOW ;
2011-04-13 01:31:57 +04:00
chan - > sec_level = BT_SECURITY_LOW ;
chan - > role_switch = 0 ;
chan - > force_reliable = 0 ;
chan - > flushable = BT_FLUSHABLE_OFF ;
2011-05-24 05:06:04 +04:00
chan - > force_active = BT_POWER_FORCE_ACTIVE_ON ;
2011-05-17 00:24:37 +04:00
2011-02-04 01:50:35 +03:00
}
/* Default config options */
2011-04-14 00:20:49 +04:00
chan - > flush_to = L2CAP_DEFAULT_FLUSH_TO ;
2011-05-17 00:24:37 +04:00
chan - > data = sk ;
chan - > ops = & l2cap_chan_ops ;
2011-02-04 01:50:35 +03:00
}
static struct proto l2cap_proto = {
. name = " L2CAP " ,
. owner = THIS_MODULE ,
. obj_size = sizeof ( struct l2cap_pinfo )
} ;
2011-05-17 00:24:37 +04:00
static struct sock * l2cap_sock_alloc ( struct net * net , struct socket * sock , int proto , gfp_t prio )
2011-02-04 01:50:35 +03:00
{
struct sock * sk ;
2011-05-16 23:42:01 +04:00
struct l2cap_chan * chan ;
2011-02-04 01:50:35 +03:00
sk = sk_alloc ( net , PF_BLUETOOTH , prio , & l2cap_proto ) ;
if ( ! sk )
return NULL ;
sock_init_data ( sock , sk ) ;
INIT_LIST_HEAD ( & bt_sk ( sk ) - > accept_q ) ;
sk - > sk_destruct = l2cap_sock_destruct ;
sk - > sk_sndtimeo = msecs_to_jiffies ( L2CAP_CONN_TIMEOUT ) ;
sock_reset_flag ( sk , SOCK_ZAPPED ) ;
sk - > sk_protocol = proto ;
sk - > sk_state = BT_OPEN ;
2011-05-16 23:42:01 +04:00
chan = l2cap_chan_create ( sk ) ;
if ( ! chan ) {
l2cap_sock_kill ( sk ) ;
return NULL ;
}
l2cap_pi ( sk ) - > chan = chan ;
2011-02-04 01:50:35 +03:00
return sk ;
}
static int l2cap_sock_create ( struct net * net , struct socket * sock , int protocol ,
int kern )
{
struct sock * sk ;
BT_DBG ( " sock %p " , sock ) ;
sock - > state = SS_UNCONNECTED ;
if ( sock - > type ! = SOCK_SEQPACKET & & sock - > type ! = SOCK_STREAM & &
sock - > type ! = SOCK_DGRAM & & sock - > type ! = SOCK_RAW )
return - ESOCKTNOSUPPORT ;
if ( sock - > type = = SOCK_RAW & & ! kern & & ! capable ( CAP_NET_RAW ) )
return - EPERM ;
sock - > ops = & l2cap_sock_ops ;
sk = l2cap_sock_alloc ( net , sock , protocol , GFP_ATOMIC ) ;
if ( ! sk )
return - ENOMEM ;
l2cap_sock_init ( sk , NULL ) ;
return 0 ;
}
2011-04-28 01:40:39 +04:00
static const struct proto_ops l2cap_sock_ops = {
2011-02-04 07:33:56 +03:00
. family = PF_BLUETOOTH ,
. owner = THIS_MODULE ,
. release = l2cap_sock_release ,
. bind = l2cap_sock_bind ,
. connect = l2cap_sock_connect ,
. listen = l2cap_sock_listen ,
. accept = l2cap_sock_accept ,
. getname = l2cap_sock_getname ,
. sendmsg = l2cap_sock_sendmsg ,
. recvmsg = l2cap_sock_recvmsg ,
. poll = bt_sock_poll ,
. ioctl = bt_sock_ioctl ,
. mmap = sock_no_mmap ,
. socketpair = sock_no_socketpair ,
. shutdown = l2cap_sock_shutdown ,
. setsockopt = l2cap_sock_setsockopt ,
. getsockopt = l2cap_sock_getsockopt
} ;
2011-02-04 01:50:35 +03:00
static const struct net_proto_family l2cap_sock_family_ops = {
. family = PF_BLUETOOTH ,
. owner = THIS_MODULE ,
. create = l2cap_sock_create ,
} ;
int __init l2cap_init_sockets ( void )
{
2011-02-18 01:16:55 +03:00
int err ;
2011-02-04 01:50:35 +03:00
2011-02-18 01:16:55 +03:00
err = proto_register ( & l2cap_proto , 0 ) ;
if ( err < 0 )
return err ;
2011-02-04 01:50:35 +03:00
2011-02-18 01:16:55 +03:00
err = bt_sock_register ( BTPROTO_L2CAP , & l2cap_sock_family_ops ) ;
if ( err < 0 )
goto error ;
2011-02-04 01:50:35 +03:00
2011-02-18 01:16:55 +03:00
BT_INFO ( " L2CAP socket layer initialized " ) ;
2011-02-04 01:50:35 +03:00
2011-02-18 01:16:55 +03:00
return 0 ;
2011-02-04 01:50:35 +03:00
error :
2011-02-18 01:16:55 +03:00
BT_ERR ( " L2CAP socket registration failed " ) ;
proto_unregister ( & l2cap_proto ) ;
return err ;
2011-02-04 01:50:35 +03:00
}
void l2cap_cleanup_sockets ( void )
{
2011-02-18 01:16:55 +03:00
if ( bt_sock_unregister ( BTPROTO_L2CAP ) < 0 )
BT_ERR ( " L2CAP socket unregistration failed " ) ;
2011-02-04 01:50:35 +03:00
2011-02-18 01:16:55 +03:00
proto_unregister ( & l2cap_proto ) ;
2011-02-04 01:50:35 +03:00
}