2007-02-09 23:24:33 +09:00
/*
2005-04-16 15:20:36 -07:00
BNEP implementation for Linux Bluetooth stack ( BlueZ ) .
Copyright ( C ) 2001 - 2002 Inventel Systemes
Written 2001 - 2002 by
2007-10-19 23:21:04 +02:00
Clément Moreau < clement . moreau @ inventel . fr >
2005-04-16 15:20:36 -07:00
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 23:24:33 +09: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-16 15:20:36 -07:00
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE .
2007-02-09 23:24:33 +09:00
ALL LIABILITY , INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS ,
COPYRIGHTS , TRADEMARKS OR OTHER RIGHTS , RELATING TO USE OF THIS
2005-04-16 15:20:36 -07:00
SOFTWARE IS DISCLAIMED .
*/
# include <linux/module.h>
2011-03-21 14:20:00 +01:00
# include <linux/kthread.h>
2005-04-16 15:20:36 -07:00
# include <linux/file.h>
# include <linux/etherdevice.h>
# include <asm/unaligned.h>
# include <net/bluetooth/bluetooth.h>
2013-10-13 09:49:57 -07:00
# include <net/bluetooth/l2cap.h>
2006-07-06 13:09:02 +02:00
# include <net/bluetooth/hci_core.h>
2005-04-16 15:20:36 -07:00
# include "bnep.h"
2008-08-07 22:26:54 +02:00
# define VERSION "1.3"
2011-12-19 14:08:01 +00:00
static bool compress_src = true ;
static bool compress_dst = true ;
2005-04-16 15:20:36 -07:00
static LIST_HEAD ( bnep_session_list ) ;
static DECLARE_RWSEM ( bnep_session_sem ) ;
static struct bnep_session * __bnep_get_session ( u8 * dst )
{
struct bnep_session * s ;
BT_DBG ( " " ) ;
2011-11-01 10:58:56 +02:00
list_for_each_entry ( s , & bnep_session_list , list )
bluetooth: Convert compare_ether_addr to ether_addr_equal
Use the new bool function ether_addr_equal to add
some clarity and reduce the likelihood for misuse
of compare_ether_addr for sorting.
Done via cocci script:
$ cat compare_ether_addr.cocci
@@
expression a,b;
@@
- !compare_ether_addr(a, b)
+ ether_addr_equal(a, b)
@@
expression a,b;
@@
- compare_ether_addr(a, b)
+ !ether_addr_equal(a, b)
@@
expression a,b;
@@
- !ether_addr_equal(a, b) == 0
+ ether_addr_equal(a, b)
@@
expression a,b;
@@
- !ether_addr_equal(a, b) != 0
+ !ether_addr_equal(a, b)
@@
expression a,b;
@@
- ether_addr_equal(a, b) == 0
+ !ether_addr_equal(a, b)
@@
expression a,b;
@@
- ether_addr_equal(a, b) != 0
+ ether_addr_equal(a, b)
@@
expression a,b;
@@
- !!ether_addr_equal(a, b)
+ ether_addr_equal(a, b)
Signed-off-by: Joe Perches <joe@perches.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2012-05-08 18:56:51 +00:00
if ( ether_addr_equal ( dst , s - > eh . h_source ) )
2005-04-16 15:20:36 -07:00
return s ;
2011-11-01 10:58:56 +02:00
2005-04-16 15:20:36 -07:00
return NULL ;
}
static void __bnep_link_session ( struct bnep_session * s )
{
2007-02-09 23:24:33 +09:00
list_add ( & s - > list , & bnep_session_list ) ;
2005-04-16 15:20:36 -07:00
}
static void __bnep_unlink_session ( struct bnep_session * s )
{
list_del ( & s - > list ) ;
}
static int bnep_send ( struct bnep_session * s , void * data , size_t len )
{
struct socket * sock = s - > sock ;
struct kvec iv = { data , len } ;
return kernel_sendmsg ( sock , & s - > msg , & iv , 1 , len ) ;
}
static int bnep_send_rsp ( struct bnep_session * s , u8 ctrl , u16 resp )
{
struct bnep_control_rsp rsp ;
rsp . type = BNEP_CONTROL ;
rsp . ctrl = ctrl ;
rsp . resp = htons ( resp ) ;
return bnep_send ( s , & rsp , sizeof ( rsp ) ) ;
}
# ifdef CONFIG_BT_BNEP_PROTO_FILTER
static inline void bnep_set_default_proto_filter ( struct bnep_session * s )
{
/* (IPv4, ARP) */
2006-11-08 00:27:36 -08:00
s - > proto_filter [ 0 ] . start = ETH_P_IP ;
s - > proto_filter [ 0 ] . end = ETH_P_ARP ;
2005-04-16 15:20:36 -07:00
/* (RARP, AppleTalk) */
2006-11-08 00:27:36 -08:00
s - > proto_filter [ 1 ] . start = ETH_P_RARP ;
s - > proto_filter [ 1 ] . end = ETH_P_AARP ;
2005-04-16 15:20:36 -07:00
/* (IPX, IPv6) */
2006-11-08 00:27:36 -08:00
s - > proto_filter [ 2 ] . start = ETH_P_IPX ;
s - > proto_filter [ 2 ] . end = ETH_P_IPV6 ;
2005-04-16 15:20:36 -07:00
}
# endif
2006-11-08 00:27:57 -08:00
static int bnep_ctrl_set_netfilter ( struct bnep_session * s , __be16 * data , int len )
2005-04-16 15:20:36 -07:00
{
int n ;
if ( len < 2 )
return - EILSEQ ;
2008-05-02 16:25:46 -07:00
n = get_unaligned_be16 ( data ) ;
2011-03-21 14:19:58 +01:00
data + + ;
len - = 2 ;
2005-04-16 15:20:36 -07:00
if ( len < n )
return - EILSEQ ;
BT_DBG ( " filter len %d " , n ) ;
# ifdef CONFIG_BT_BNEP_PROTO_FILTER
n / = 4 ;
if ( n < = BNEP_MAX_PROTO_FILTERS ) {
struct bnep_proto_filter * f = s - > proto_filter ;
int i ;
for ( i = 0 ; i < n ; i + + ) {
2008-05-02 16:25:46 -07:00
f [ i ] . start = get_unaligned_be16 ( data + + ) ;
f [ i ] . end = get_unaligned_be16 ( data + + ) ;
2005-04-16 15:20:36 -07:00
BT_DBG ( " proto filter start %d end %d " ,
f [ i ] . start , f [ i ] . end ) ;
}
if ( i < BNEP_MAX_PROTO_FILTERS )
memset ( f + i , 0 , sizeof ( * f ) ) ;
if ( n = = 0 )
bnep_set_default_proto_filter ( s ) ;
bnep_send_rsp ( s , BNEP_FILTER_NET_TYPE_RSP , BNEP_SUCCESS ) ;
} else {
bnep_send_rsp ( s , BNEP_FILTER_NET_TYPE_RSP , BNEP_FILTER_LIMIT_REACHED ) ;
}
# else
bnep_send_rsp ( s , BNEP_FILTER_NET_TYPE_RSP , BNEP_FILTER_UNSUPPORTED_REQ ) ;
# endif
return 0 ;
}
static int bnep_ctrl_set_mcfilter ( struct bnep_session * s , u8 * data , int len )
{
int n ;
if ( len < 2 )
return - EILSEQ ;
2008-05-02 16:25:46 -07:00
n = get_unaligned_be16 ( data ) ;
2011-03-21 14:19:58 +01:00
data + = 2 ;
len - = 2 ;
2005-04-16 15:20:36 -07:00
if ( len < n )
return - EILSEQ ;
BT_DBG ( " filter len %d " , n ) ;
# ifdef CONFIG_BT_BNEP_MC_FILTER
n / = ( ETH_ALEN * 2 ) ;
if ( n > 0 ) {
2011-03-21 14:19:57 +01:00
int i ;
2005-04-16 15:20:36 -07:00
s - > mc_filter = 0 ;
/* Always send broadcast */
set_bit ( bnep_mc_hash ( s - > dev - > broadcast ) , ( ulong * ) & s - > mc_filter ) ;
/* Add address ranges to the multicast hash */
for ( ; n > 0 ; n - - ) {
u8 a1 [ 6 ] , * a2 ;
2011-03-21 14:19:58 +01:00
memcpy ( a1 , data , ETH_ALEN ) ;
data + = ETH_ALEN ;
a2 = data ;
data + = ETH_ALEN ;
2007-02-09 23:24:33 +09:00
2012-09-25 12:49:43 +03:00
BT_DBG ( " mc filter %pMR -> %pMR " , a1 , a2 ) ;
2005-04-16 15:20:36 -07:00
/* Iterate from a1 to a2 */
set_bit ( bnep_mc_hash ( a1 ) , ( ulong * ) & s - > mc_filter ) ;
while ( memcmp ( a1 , a2 , 6 ) < 0 & & s - > mc_filter ! = ~ 0LL ) {
2011-03-21 14:19:57 +01:00
/* Increment a1 */
i = 5 ;
while ( i > = 0 & & + + a1 [ i - - ] = = 0 )
;
2005-04-16 15:20:36 -07:00
set_bit ( bnep_mc_hash ( a1 ) , ( ulong * ) & s - > mc_filter ) ;
}
}
}
BT_DBG ( " mc filter hash 0x%llx " , s - > mc_filter ) ;
bnep_send_rsp ( s , BNEP_FILTER_MULTI_ADDR_RSP , BNEP_SUCCESS ) ;
# else
bnep_send_rsp ( s , BNEP_FILTER_MULTI_ADDR_RSP , BNEP_FILTER_UNSUPPORTED_REQ ) ;
# endif
return 0 ;
}
static int bnep_rx_control ( struct bnep_session * s , void * data , int len )
{
u8 cmd = * ( u8 * ) data ;
int err = 0 ;
2011-03-21 14:19:58 +01:00
data + + ;
len - - ;
2005-04-16 15:20:36 -07:00
switch ( cmd ) {
case BNEP_CMD_NOT_UNDERSTOOD :
case BNEP_SETUP_CONN_RSP :
case BNEP_FILTER_NET_TYPE_RSP :
case BNEP_FILTER_MULTI_ADDR_RSP :
/* Ignore these for now */
break ;
case BNEP_FILTER_NET_TYPE_SET :
err = bnep_ctrl_set_netfilter ( s , data , len ) ;
break ;
case BNEP_FILTER_MULTI_ADDR_SET :
err = bnep_ctrl_set_mcfilter ( s , data , len ) ;
break ;
2009-12-03 15:12:51 +05:30
case BNEP_SETUP_CONN_REQ :
2015-04-03 12:14:55 +02:00
/* Successful response should be sent only once */
if ( test_bit ( BNEP_SETUP_RESPONSE , & s - > flags ) & &
! test_and_set_bit ( BNEP_SETUP_RSP_SENT , & s - > flags ) )
err = bnep_send_rsp ( s , BNEP_SETUP_CONN_RSP ,
BNEP_SUCCESS ) ;
else
err = bnep_send_rsp ( s , BNEP_SETUP_CONN_RSP ,
BNEP_CONN_NOT_ALLOWED ) ;
2009-12-03 15:12:51 +05:30
break ;
2005-04-16 15:20:36 -07:00
default : {
u8 pkt [ 3 ] ;
pkt [ 0 ] = BNEP_CONTROL ;
pkt [ 1 ] = BNEP_CMD_NOT_UNDERSTOOD ;
pkt [ 2 ] = cmd ;
2015-04-03 12:14:52 +02:00
err = bnep_send ( s , pkt , sizeof ( pkt ) ) ;
2005-04-16 15:20:36 -07:00
}
break ;
}
return err ;
}
static int bnep_rx_extension ( struct bnep_session * s , struct sk_buff * skb )
{
struct bnep_ext_hdr * h ;
int err = 0 ;
do {
h = ( void * ) skb - > data ;
if ( ! skb_pull ( skb , sizeof ( * h ) ) ) {
err = - EILSEQ ;
break ;
}
BT_DBG ( " type 0x%x len %d " , h - > type , h - > len ) ;
2007-02-09 23:24:33 +09:00
2005-04-16 15:20:36 -07:00
switch ( h - > type & BNEP_TYPE_MASK ) {
case BNEP_EXT_CONTROL :
bnep_rx_control ( s , skb - > data , skb - > len ) ;
break ;
default :
/* Unknown extension, skip it. */
break ;
}
if ( ! skb_pull ( skb , h - > len ) ) {
err = - EILSEQ ;
break ;
}
} while ( ! err & & ( h - > type & BNEP_EXT_HEADER ) ) ;
2007-02-09 23:24:33 +09:00
2005-04-16 15:20:36 -07:00
return err ;
}
static u8 __bnep_rx_hlen [ ] = {
ETH_HLEN , /* BNEP_GENERAL */
0 , /* BNEP_CONTROL */
2 , /* BNEP_COMPRESSED */
ETH_ALEN + 2 , /* BNEP_COMPRESSED_SRC_ONLY */
ETH_ALEN + 2 /* BNEP_COMPRESSED_DST_ONLY */
} ;
2012-05-23 04:04:18 -03:00
static int bnep_rx_frame ( struct bnep_session * s , struct sk_buff * skb )
2005-04-16 15:20:36 -07:00
{
struct net_device * dev = s - > dev ;
struct sk_buff * nskb ;
2015-04-03 12:14:54 +02:00
u8 type , ctrl_type ;
2005-04-16 15:20:36 -07:00
2009-01-07 17:23:17 -08:00
dev - > stats . rx_bytes + = skb - > len ;
2005-04-16 15:20:36 -07:00
2011-03-21 14:19:58 +01:00
type = * ( u8 * ) skb - > data ;
skb_pull ( skb , 1 ) ;
2015-04-03 12:14:54 +02:00
ctrl_type = * ( u8 * ) skb - > data ;
2005-04-16 15:20:36 -07:00
2011-03-21 14:19:57 +01:00
if ( ( type & BNEP_TYPE_MASK ) > = sizeof ( __bnep_rx_hlen ) )
2005-04-16 15:20:36 -07:00
goto badframe ;
2007-02-09 23:24:33 +09:00
2005-04-16 15:20:36 -07:00
if ( ( type & BNEP_TYPE_MASK ) = = BNEP_CONTROL ) {
2015-04-03 12:14:54 +02:00
if ( bnep_rx_control ( s , skb - > data , skb - > len ) < 0 ) {
dev - > stats . tx_errors + + ;
kfree_skb ( skb ) ;
return 0 ;
}
2005-04-16 15:20:36 -07:00
2015-04-03 12:14:54 +02:00
if ( ! ( type & BNEP_EXT_HEADER ) ) {
kfree_skb ( skb ) ;
return 0 ;
}
2005-04-16 15:20:36 -07:00
2015-04-03 12:14:54 +02:00
/* Verify and pull ctrl message since it's already processed */
switch ( ctrl_type ) {
case BNEP_SETUP_CONN_REQ :
/* Pull: ctrl type (1 b), len (1 b), data (len bytes) */
if ( ! skb_pull ( skb , 2 + * ( u8 * ) ( skb - > data + 1 ) * 2 ) )
goto badframe ;
break ;
case BNEP_FILTER_MULTI_ADDR_SET :
case BNEP_FILTER_NET_TYPE_SET :
/* Pull: ctrl type (1 b), len (2 b), data (len bytes) */
if ( ! skb_pull ( skb , 3 + * ( u16 * ) ( skb - > data + 1 ) * 2 ) )
goto badframe ;
break ;
default :
kfree_skb ( skb ) ;
return 0 ;
}
} else {
skb_reset_mac_header ( skb ) ;
/* Verify and pull out header */
if ( ! skb_pull ( skb , __bnep_rx_hlen [ type & BNEP_TYPE_MASK ] ) )
goto badframe ;
2005-04-16 15:20:36 -07:00
2015-04-03 12:14:54 +02:00
s - > eh . h_proto = get_unaligned ( ( __be16 * ) ( skb - > data - 2 ) ) ;
}
2005-04-16 15:20:36 -07:00
if ( type & BNEP_EXT_HEADER ) {
if ( bnep_rx_extension ( s , skb ) < 0 )
goto badframe ;
}
/* Strip 802.1p header */
2012-05-08 00:09:35 +02:00
if ( ntohs ( s - > eh . h_proto ) = = ETH_P_8021Q ) {
2005-04-16 15:20:36 -07:00
if ( ! skb_pull ( skb , 4 ) )
goto badframe ;
2006-11-08 00:27:57 -08:00
s - > eh . h_proto = get_unaligned ( ( __be16 * ) ( skb - > data - 2 ) ) ;
2005-04-16 15:20:36 -07:00
}
2007-02-09 23:24:33 +09:00
2005-04-16 15:20:36 -07:00
/* We have to alloc new skb and copy data here :(. Because original skb
* may not be modified and because of the alignment requirements . */
nskb = alloc_skb ( 2 + ETH_HLEN + skb - > len , GFP_KERNEL ) ;
if ( ! nskb ) {
2009-01-07 17:23:17 -08:00
dev - > stats . rx_dropped + + ;
2005-04-16 15:20:36 -07:00
kfree_skb ( skb ) ;
return - ENOMEM ;
}
skb_reserve ( nskb , 2 ) ;
/* Decompress header and construct ether frame */
switch ( type & BNEP_TYPE_MASK ) {
case BNEP_COMPRESSED :
memcpy ( __skb_put ( nskb , ETH_HLEN ) , & s - > eh , ETH_HLEN ) ;
break ;
2007-02-09 23:24:33 +09:00
2005-04-16 15:20:36 -07:00
case BNEP_COMPRESSED_SRC_ONLY :
memcpy ( __skb_put ( nskb , ETH_ALEN ) , s - > eh . h_dest , ETH_ALEN ) ;
2007-03-19 15:33:04 -07:00
memcpy ( __skb_put ( nskb , ETH_ALEN ) , skb_mac_header ( skb ) , ETH_ALEN ) ;
2006-11-08 00:27:57 -08:00
put_unaligned ( s - > eh . h_proto , ( __be16 * ) __skb_put ( nskb , 2 ) ) ;
2005-04-16 15:20:36 -07:00
break ;
case BNEP_COMPRESSED_DST_ONLY :
2007-03-19 15:33:04 -07:00
memcpy ( __skb_put ( nskb , ETH_ALEN ) , skb_mac_header ( skb ) ,
2011-03-21 14:19:58 +01:00
ETH_ALEN ) ;
2007-03-19 15:33:04 -07:00
memcpy ( __skb_put ( nskb , ETH_ALEN + 2 ) , s - > eh . h_source ,
2011-03-21 14:19:58 +01:00
ETH_ALEN + 2 ) ;
2005-04-16 15:20:36 -07:00
break ;
case BNEP_GENERAL :
2007-03-19 15:33:04 -07:00
memcpy ( __skb_put ( nskb , ETH_ALEN * 2 ) , skb_mac_header ( skb ) ,
2011-03-21 14:19:58 +01:00
ETH_ALEN * 2 ) ;
2006-11-08 00:27:57 -08:00
put_unaligned ( s - > eh . h_proto , ( __be16 * ) __skb_put ( nskb , 2 ) ) ;
2005-04-16 15:20:36 -07:00
break ;
}
2007-03-27 18:55:52 -03:00
skb_copy_from_linear_data ( skb , __skb_put ( nskb , skb - > len ) , skb - > len ) ;
2005-04-16 15:20:36 -07:00
kfree_skb ( skb ) ;
2007-02-09 23:24:33 +09:00
2009-01-07 17:23:17 -08:00
dev - > stats . rx_packets + + ;
2005-04-16 15:20:36 -07:00
nskb - > ip_summed = CHECKSUM_NONE ;
nskb - > protocol = eth_type_trans ( nskb , dev ) ;
netif_rx_ni ( nskb ) ;
return 0 ;
badframe :
2009-01-07 17:23:17 -08:00
dev - > stats . rx_errors + + ;
2005-04-16 15:20:36 -07:00
kfree_skb ( skb ) ;
return 0 ;
}
static u8 __bnep_tx_types [ ] = {
BNEP_GENERAL ,
BNEP_COMPRESSED_SRC_ONLY ,
BNEP_COMPRESSED_DST_ONLY ,
BNEP_COMPRESSED
} ;
2012-05-23 04:04:18 -03:00
static int bnep_tx_frame ( struct bnep_session * s , struct sk_buff * skb )
2005-04-16 15:20:36 -07:00
{
struct ethhdr * eh = ( void * ) skb - > data ;
struct socket * sock = s - > sock ;
struct kvec iv [ 3 ] ;
int len = 0 , il = 0 ;
u8 type = 0 ;
BT_DBG ( " skb %p dev %p type %d " , skb , skb - > dev , skb - > pkt_type ) ;
if ( ! skb - > dev ) {
/* Control frame sent by us */
goto send ;
}
iv [ il + + ] = ( struct kvec ) { & type , 1 } ;
len + + ;
bluetooth: Convert compare_ether_addr to ether_addr_equal
Use the new bool function ether_addr_equal to add
some clarity and reduce the likelihood for misuse
of compare_ether_addr for sorting.
Done via cocci script:
$ cat compare_ether_addr.cocci
@@
expression a,b;
@@
- !compare_ether_addr(a, b)
+ ether_addr_equal(a, b)
@@
expression a,b;
@@
- compare_ether_addr(a, b)
+ !ether_addr_equal(a, b)
@@
expression a,b;
@@
- !ether_addr_equal(a, b) == 0
+ ether_addr_equal(a, b)
@@
expression a,b;
@@
- !ether_addr_equal(a, b) != 0
+ !ether_addr_equal(a, b)
@@
expression a,b;
@@
- ether_addr_equal(a, b) == 0
+ !ether_addr_equal(a, b)
@@
expression a,b;
@@
- ether_addr_equal(a, b) != 0
+ ether_addr_equal(a, b)
@@
expression a,b;
@@
- !!ether_addr_equal(a, b)
+ ether_addr_equal(a, b)
Signed-off-by: Joe Perches <joe@perches.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2012-05-08 18:56:51 +00:00
if ( compress_src & & ether_addr_equal ( eh - > h_dest , s - > eh . h_source ) )
2005-04-16 15:20:36 -07:00
type | = 0x01 ;
bluetooth: Convert compare_ether_addr to ether_addr_equal
Use the new bool function ether_addr_equal to add
some clarity and reduce the likelihood for misuse
of compare_ether_addr for sorting.
Done via cocci script:
$ cat compare_ether_addr.cocci
@@
expression a,b;
@@
- !compare_ether_addr(a, b)
+ ether_addr_equal(a, b)
@@
expression a,b;
@@
- compare_ether_addr(a, b)
+ !ether_addr_equal(a, b)
@@
expression a,b;
@@
- !ether_addr_equal(a, b) == 0
+ ether_addr_equal(a, b)
@@
expression a,b;
@@
- !ether_addr_equal(a, b) != 0
+ !ether_addr_equal(a, b)
@@
expression a,b;
@@
- ether_addr_equal(a, b) == 0
+ !ether_addr_equal(a, b)
@@
expression a,b;
@@
- ether_addr_equal(a, b) != 0
+ ether_addr_equal(a, b)
@@
expression a,b;
@@
- !!ether_addr_equal(a, b)
+ ether_addr_equal(a, b)
Signed-off-by: Joe Perches <joe@perches.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2012-05-08 18:56:51 +00:00
if ( compress_dst & & ether_addr_equal ( eh - > h_source , s - > eh . h_dest ) )
2005-04-16 15:20:36 -07:00
type | = 0x02 ;
if ( type )
skb_pull ( skb , ETH_ALEN * 2 ) ;
type = __bnep_tx_types [ type ] ;
switch ( type ) {
case BNEP_COMPRESSED_SRC_ONLY :
iv [ il + + ] = ( struct kvec ) { eh - > h_source , ETH_ALEN } ;
len + = ETH_ALEN ;
break ;
2007-02-09 23:24:33 +09:00
2005-04-16 15:20:36 -07:00
case BNEP_COMPRESSED_DST_ONLY :
iv [ il + + ] = ( struct kvec ) { eh - > h_dest , ETH_ALEN } ;
len + = ETH_ALEN ;
break ;
}
send :
iv [ il + + ] = ( struct kvec ) { skb - > data , skb - > len } ;
len + = skb - > len ;
2007-02-09 23:24:33 +09:00
2005-04-16 15:20:36 -07:00
/* FIXME: linearize skb */
{
len = kernel_sendmsg ( sock , & s - > msg , iv , il , len ) ;
}
kfree_skb ( skb ) ;
if ( len > 0 ) {
2009-01-07 17:23:17 -08:00
s - > dev - > stats . tx_bytes + = len ;
s - > dev - > stats . tx_packets + + ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
return len ;
}
static int bnep_session ( void * arg )
{
struct bnep_session * s = arg ;
struct net_device * dev = s - > dev ;
struct sock * sk = s - > sock - > sk ;
struct sk_buff * skb ;
wait_queue_t wait ;
BT_DBG ( " " ) ;
set_user_nice ( current , - 15 ) ;
init_waitqueue_entry ( & wait , current ) ;
2010-04-20 13:03:51 +00:00
add_wait_queue ( sk_sleep ( sk ) , & wait ) ;
2011-07-24 00:11:07 -04:00
while ( 1 ) {
2005-04-16 15:20:36 -07:00
set_current_state ( TASK_INTERRUPTIBLE ) ;
2011-08-05 10:41:35 -04:00
if ( atomic_read ( & s - > terminate ) )
2011-07-24 00:11:07 -04:00
break ;
2011-03-21 14:19:58 +01:00
/* RX */
2005-04-16 15:20:36 -07:00
while ( ( skb = skb_dequeue ( & sk - > sk_receive_queue ) ) ) {
skb_orphan ( skb ) ;
2011-07-22 14:53:58 -07:00
if ( ! skb_linearize ( skb ) )
bnep_rx_frame ( s , skb ) ;
else
kfree_skb ( skb ) ;
2005-04-16 15:20:36 -07:00
}
if ( sk - > sk_state ! = BT_CONNECTED )
break ;
2007-02-09 23:24:33 +09:00
2011-03-21 14:19:58 +01:00
/* TX */
2005-04-16 15:20:36 -07:00
while ( ( skb = skb_dequeue ( & sk - > sk_write_queue ) ) )
if ( bnep_tx_frame ( s , skb ) )
break ;
netif_wake_queue ( dev ) ;
2007-02-09 23:24:33 +09:00
2005-04-16 15:20:36 -07:00
schedule ( ) ;
}
2011-07-24 00:11:07 -04:00
__set_current_state ( TASK_RUNNING ) ;
2010-04-20 13:03:51 +00:00
remove_wait_queue ( sk_sleep ( sk ) , & wait ) ;
2005-04-16 15:20:36 -07:00
/* Cleanup session */
down_write ( & bnep_session_sem ) ;
/* Delete network device */
unregister_netdev ( dev ) ;
2008-07-14 20:13:53 +02:00
/* Wakeup user-space polling for socket errors */
s - > sock - > sk - > sk_err = EUNATCH ;
2010-04-20 13:03:51 +00:00
wake_up_interruptible ( sk_sleep ( s - > sock - > sk ) ) ;
2008-07-14 20:13:53 +02:00
2005-04-16 15:20:36 -07:00
/* Release the socket */
fput ( s - > sock - > file ) ;
__bnep_unlink_session ( s ) ;
up_write ( & bnep_session_sem ) ;
free_netdev ( dev ) ;
2011-11-19 13:23:33 +01:00
module_put_and_exit ( 0 ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
2006-07-06 13:09:02 +02:00
static struct device * bnep_get_device ( struct bnep_session * session )
{
2015-02-03 10:01:13 +02:00
struct l2cap_conn * conn = l2cap_pi ( session - > sock - > sk ) - > chan - > conn ;
2006-07-06 13:09:02 +02:00
2015-02-03 10:01:13 +02:00
if ( ! conn | | ! conn - > hcon )
2006-07-06 13:09:02 +02:00
return NULL ;
2015-02-03 10:01:13 +02:00
return & conn - > hcon - > dev ;
2006-07-06 13:09:02 +02:00
}
2009-08-31 21:08:19 +00:00
static struct device_type bnep_type = {
. name = " bluetooth " ,
} ;
2005-04-16 15:20:36 -07:00
int bnep_add_connection ( struct bnep_connadd_req * req , struct socket * sock )
{
2015-04-03 12:14:55 +02:00
u32 valid_flags = BIT ( BNEP_SETUP_RESPONSE ) ;
2005-04-16 15:20:36 -07:00
struct net_device * dev ;
struct bnep_session * s , * ss ;
u8 dst [ ETH_ALEN ] , src [ ETH_ALEN ] ;
int err ;
BT_DBG ( " " ) ;
2014-12-19 06:20:59 +00:00
if ( ! l2cap_is_socket ( sock ) )
return - EBADFD ;
2015-04-01 13:51:54 -07:00
if ( req - > flags & ~ valid_flags )
return - EINVAL ;
2013-10-13 09:49:57 -07:00
baswap ( ( void * ) dst , & l2cap_pi ( sock - > sk ) - > chan - > dst ) ;
baswap ( ( void * ) src , & l2cap_pi ( sock - > sk ) - > chan - > src ) ;
2005-04-16 15:20:36 -07:00
/* session struct allocated as private part of net_device */
dev = alloc_netdev ( sizeof ( struct bnep_session ) ,
net: set name_assign_type in alloc_netdev()
Extend alloc_netdev{,_mq{,s}}() to take name_assign_type as argument, and convert
all users to pass NET_NAME_UNKNOWN.
Coccinelle patch:
@@
expression sizeof_priv, name, setup, txqs, rxqs, count;
@@
(
-alloc_netdev_mqs(sizeof_priv, name, setup, txqs, rxqs)
+alloc_netdev_mqs(sizeof_priv, name, NET_NAME_UNKNOWN, setup, txqs, rxqs)
|
-alloc_netdev_mq(sizeof_priv, name, setup, count)
+alloc_netdev_mq(sizeof_priv, name, NET_NAME_UNKNOWN, setup, count)
|
-alloc_netdev(sizeof_priv, name, setup)
+alloc_netdev(sizeof_priv, name, NET_NAME_UNKNOWN, setup)
)
v9: move comments here from the wrong commit
Signed-off-by: Tom Gundersen <teg@jklm.no>
Reviewed-by: David Herrmann <dh.herrmann@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2014-07-14 16:37:24 +02:00
( * req - > device ) ? req - > device : " bnep%d " ,
NET_NAME_UNKNOWN ,
bnep_net_setup ) ;
2006-03-21 23:53:16 -08:00
if ( ! dev )
return - ENOMEM ;
2005-04-16 15:20:36 -07:00
down_write ( & bnep_session_sem ) ;
ss = __bnep_get_session ( dst ) ;
if ( ss & & ss - > state = = BT_CONNECTED ) {
err = - EEXIST ;
goto failed ;
}
2008-11-12 23:39:10 -08:00
s = netdev_priv ( dev ) ;
2005-04-16 15:20:36 -07:00
/* This is rx header therefore addresses are swapped.
2011-03-21 14:19:58 +01:00
* ie . eh . h_dest is our local address . */
2005-04-16 15:20:36 -07:00
memcpy ( s - > eh . h_dest , & src , ETH_ALEN ) ;
memcpy ( s - > eh . h_source , & dst , ETH_ALEN ) ;
memcpy ( dev - > dev_addr , s - > eh . h_dest , ETH_ALEN ) ;
2006-07-06 13:09:02 +02:00
s - > dev = dev ;
2005-04-16 15:20:36 -07:00
s - > sock = sock ;
s - > role = req - > role ;
s - > state = BT_CONNECTED ;
2015-04-03 12:14:55 +02:00
s - > flags = req - > flags ;
2007-02-09 23:24:33 +09:00
2005-04-16 15:20:36 -07:00
s - > msg . msg_flags = MSG_NOSIGNAL ;
# ifdef CONFIG_BT_BNEP_MC_FILTER
/* Set default mc filter */
set_bit ( bnep_mc_hash ( dev - > broadcast ) , ( ulong * ) & s - > mc_filter ) ;
# endif
# ifdef CONFIG_BT_BNEP_PROTO_FILTER
/* Set default protocol filter */
bnep_set_default_proto_filter ( s ) ;
# endif
2006-07-06 13:09:02 +02:00
SET_NETDEV_DEV ( dev , bnep_get_device ( s ) ) ;
2009-08-31 21:08:19 +00:00
SET_NETDEV_DEVTYPE ( dev , & bnep_type ) ;
2006-07-06 13:09:02 +02:00
2005-04-16 15:20:36 -07:00
err = register_netdev ( dev ) ;
2011-03-21 14:19:58 +01:00
if ( err )
2005-04-16 15:20:36 -07:00
goto failed ;
__bnep_link_session ( s ) ;
2007-02-09 23:24:33 +09:00
2011-11-19 13:23:33 +01:00
__module_get ( THIS_MODULE ) ;
2011-03-21 14:20:00 +01:00
s - > task = kthread_run ( bnep_session , s , " kbnepd %s " , dev - > name ) ;
if ( IS_ERR ( s - > task ) ) {
2005-04-16 15:20:36 -07:00
/* Session thread start failed, gotta cleanup. */
2011-11-19 13:23:33 +01:00
module_put ( THIS_MODULE ) ;
2005-04-16 15:20:36 -07:00
unregister_netdev ( dev ) ;
__bnep_unlink_session ( s ) ;
2011-03-21 14:20:00 +01:00
err = PTR_ERR ( s - > task ) ;
2005-04-16 15:20:36 -07:00
goto failed ;
}
up_write ( & bnep_session_sem ) ;
strcpy ( req - > device , dev - > name ) ;
return 0 ;
failed :
up_write ( & bnep_session_sem ) ;
free_netdev ( dev ) ;
return err ;
}
int bnep_del_connection ( struct bnep_conndel_req * req )
{
2015-04-01 13:51:54 -07:00
u32 valid_flags = 0 ;
2005-04-16 15:20:36 -07:00
struct bnep_session * s ;
int err = 0 ;
BT_DBG ( " " ) ;
2015-04-01 13:51:54 -07:00
if ( req - > flags & ~ valid_flags )
return - EINVAL ;
2005-04-16 15:20:36 -07:00
down_read ( & bnep_session_sem ) ;
s = __bnep_get_session ( req - > dst ) ;
2011-08-05 10:41:35 -04:00
if ( s ) {
atomic_inc ( & s - > terminate ) ;
wake_up_process ( s - > task ) ;
} else
2005-04-16 15:20:36 -07:00
err = - ENOENT ;
up_read ( & bnep_session_sem ) ;
return err ;
}
static void __bnep_copy_ci ( struct bnep_conninfo * ci , struct bnep_session * s )
{
2015-04-03 12:14:55 +02:00
u32 valid_flags = BIT ( BNEP_SETUP_RESPONSE ) ;
2015-04-01 13:51:54 -07:00
2010-10-30 18:26:21 +04:00
memset ( ci , 0 , sizeof ( * ci ) ) ;
2005-04-16 15:20:36 -07:00
memcpy ( ci - > dst , s - > eh . h_source , ETH_ALEN ) ;
strcpy ( ci - > device , s - > dev - > name ) ;
2015-04-01 13:51:54 -07:00
ci - > flags = s - > flags & valid_flags ;
2005-04-16 15:20:36 -07:00
ci - > state = s - > state ;
ci - > role = s - > role ;
}
int bnep_get_connlist ( struct bnep_connlist_req * req )
{
2011-11-01 10:58:56 +02:00
struct bnep_session * s ;
2005-04-16 15:20:36 -07:00
int err = 0 , n = 0 ;
down_read ( & bnep_session_sem ) ;
2011-11-01 10:58:56 +02:00
list_for_each_entry ( s , & bnep_session_list , list ) {
2005-04-16 15:20:36 -07:00
struct bnep_conninfo ci ;
__bnep_copy_ci ( & ci , s ) ;
2007-02-09 23:24:33 +09:00
2005-04-16 15:20:36 -07:00
if ( copy_to_user ( req - > ci , & ci , sizeof ( ci ) ) ) {
err = - EFAULT ;
break ;
}
if ( + + n > = req - > cnum )
break ;
req - > ci + + ;
}
req - > cnum = n ;
up_read ( & bnep_session_sem ) ;
return err ;
}
int bnep_get_conninfo ( struct bnep_conninfo * ci )
{
struct bnep_session * s ;
int err = 0 ;
down_read ( & bnep_session_sem ) ;
s = __bnep_get_session ( ci - > dst ) ;
if ( s )
__bnep_copy_ci ( ci , s ) ;
else
err = - ENOENT ;
up_read ( & bnep_session_sem ) ;
return err ;
}
static int __init bnep_init ( void )
2007-02-09 23:24:33 +09:00
{
2005-04-16 15:20:36 -07:00
char flt [ 50 ] = " " ;
# ifdef CONFIG_BT_BNEP_PROTO_FILTER
strcat ( flt , " protocol " ) ;
# endif
# ifdef CONFIG_BT_BNEP_MC_FILTER
strcat ( flt , " multicast " ) ;
# endif
BT_INFO ( " BNEP (Ethernet Emulation) ver %s " , VERSION ) ;
if ( flt [ 0 ] )
BT_INFO ( " BNEP filters: %s " , flt ) ;
bnep_sock_init ( ) ;
return 0 ;
}
static void __exit bnep_exit ( void )
{
bnep_sock_cleanup ( ) ;
}
module_init ( bnep_init ) ;
module_exit ( bnep_exit ) ;
2008-08-07 22:26:54 +02:00
module_param ( compress_src , bool , 0644 ) ;
MODULE_PARM_DESC ( compress_src , " Compress sources headers " ) ;
module_param ( compress_dst , bool , 0644 ) ;
MODULE_PARM_DESC ( compress_dst , " Compress destination headers " ) ;
2008-08-18 13:23:53 +02:00
MODULE_AUTHOR ( " Marcel Holtmann <marcel@holtmann.org> " ) ;
2005-04-16 15:20:36 -07:00
MODULE_DESCRIPTION ( " Bluetooth BNEP ver " VERSION ) ;
MODULE_VERSION ( VERSION ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_ALIAS ( " bt-proto-4 " ) ;