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
2007-10-20 01:21:04 +04:00
Clément Moreau < clement . moreau @ inventel . fr >
2005-04-17 02:20:36 +04: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 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 .
*/
# include <linux/etherdevice.h>
# include <net/bluetooth/bluetooth.h>
# include <net/bluetooth/hci_core.h>
# include <net/bluetooth/l2cap.h>
# include "bnep.h"
# define BNEP_TX_QUEUE_LEN 20
static int bnep_net_open ( struct net_device * dev )
{
netif_start_queue ( dev ) ;
return 0 ;
}
static int bnep_net_close ( struct net_device * dev )
{
netif_stop_queue ( dev ) ;
return 0 ;
}
static void bnep_net_set_mc_list ( struct net_device * dev )
{
# ifdef CONFIG_BT_BNEP_MC_FILTER
2008-11-13 10:39:10 +03:00
struct bnep_session * s = netdev_priv ( dev ) ;
2005-04-17 02:20:36 +04:00
struct sock * sk = s - > sock - > sk ;
struct bnep_set_filter_req * r ;
struct sk_buff * skb ;
int size ;
2010-02-08 07:30:35 +03:00
BT_DBG ( " %s mc_count %d " , dev - > name , netdev_mc_count ( dev ) ) ;
2005-04-17 02:20:36 +04:00
size = sizeof ( * r ) + ( BNEP_MAX_MULTICAST_FILTERS + 1 ) * ETH_ALEN * 2 ;
skb = alloc_skb ( size , GFP_ATOMIC ) ;
if ( ! skb ) {
BT_ERR ( " %s Multicast list allocation failed " , dev - > name ) ;
return ;
}
r = ( void * ) skb - > data ;
__skb_put ( skb , sizeof ( * r ) ) ;
r - > type = BNEP_CONTROL ;
r - > ctrl = BNEP_FILTER_MULTI_ADDR_SET ;
2007-02-09 17:24:33 +03:00
if ( dev - > flags & ( IFF_PROMISC | IFF_ALLMULTI ) ) {
2005-04-17 02:20:36 +04:00
u8 start [ ETH_ALEN ] = { 0x01 } ;
/* Request all addresses */
net: introduce __skb_put_[zero, data, u8]
follow Johannes Berg, semantic patch file as below,
@@
identifier p, p2;
expression len;
expression skb;
type t, t2;
@@
(
-p = __skb_put(skb, len);
+p = __skb_put_zero(skb, len);
|
-p = (t)__skb_put(skb, len);
+p = __skb_put_zero(skb, len);
)
... when != p
(
p2 = (t2)p;
-memset(p2, 0, len);
|
-memset(p, 0, len);
)
@@
identifier p;
expression len;
expression skb;
type t;
@@
(
-t p = __skb_put(skb, len);
+t p = __skb_put_zero(skb, len);
)
... when != p
(
-memset(p, 0, len);
)
@@
type t, t2;
identifier p, p2;
expression skb;
@@
t *p;
...
(
-p = __skb_put(skb, sizeof(t));
+p = __skb_put_zero(skb, sizeof(t));
|
-p = (t *)__skb_put(skb, sizeof(t));
+p = __skb_put_zero(skb, sizeof(t));
)
... when != p
(
p2 = (t2)p;
-memset(p2, 0, sizeof(*p));
|
-memset(p, 0, sizeof(*p));
)
@@
expression skb, len;
@@
-memset(__skb_put(skb, len), 0, len);
+__skb_put_zero(skb, len);
@@
expression skb, len, data;
@@
-memcpy(__skb_put(skb, len), data, len);
+__skb_put_data(skb, data, len);
@@
expression SKB, C, S;
typedef u8;
identifier fn = {__skb_put};
fresh identifier fn2 = fn ## "_u8";
@@
- *(u8 *)fn(SKB, S) = C;
+ fn2(SKB, C);
Signed-off-by: yuan linyu <Linyu.Yuan@alcatel-sbell.com.cn>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-06-18 17:48:17 +03:00
__skb_put_data ( skb , start , ETH_ALEN ) ;
__skb_put_data ( skb , dev - > broadcast , ETH_ALEN ) ;
2005-04-17 02:20:36 +04:00
r - > len = htons ( ETH_ALEN * 2 ) ;
} else {
2010-04-02 01:22:57 +04:00
struct netdev_hw_addr * ha ;
2005-04-17 02:20:36 +04:00
int i , len = skb - > len ;
if ( dev - > flags & IFF_BROADCAST ) {
net: introduce __skb_put_[zero, data, u8]
follow Johannes Berg, semantic patch file as below,
@@
identifier p, p2;
expression len;
expression skb;
type t, t2;
@@
(
-p = __skb_put(skb, len);
+p = __skb_put_zero(skb, len);
|
-p = (t)__skb_put(skb, len);
+p = __skb_put_zero(skb, len);
)
... when != p
(
p2 = (t2)p;
-memset(p2, 0, len);
|
-memset(p, 0, len);
)
@@
identifier p;
expression len;
expression skb;
type t;
@@
(
-t p = __skb_put(skb, len);
+t p = __skb_put_zero(skb, len);
)
... when != p
(
-memset(p, 0, len);
)
@@
type t, t2;
identifier p, p2;
expression skb;
@@
t *p;
...
(
-p = __skb_put(skb, sizeof(t));
+p = __skb_put_zero(skb, sizeof(t));
|
-p = (t *)__skb_put(skb, sizeof(t));
+p = __skb_put_zero(skb, sizeof(t));
)
... when != p
(
p2 = (t2)p;
-memset(p2, 0, sizeof(*p));
|
-memset(p, 0, sizeof(*p));
)
@@
expression skb, len;
@@
-memset(__skb_put(skb, len), 0, len);
+__skb_put_zero(skb, len);
@@
expression skb, len, data;
@@
-memcpy(__skb_put(skb, len), data, len);
+__skb_put_data(skb, data, len);
@@
expression SKB, C, S;
typedef u8;
identifier fn = {__skb_put};
fresh identifier fn2 = fn ## "_u8";
@@
- *(u8 *)fn(SKB, S) = C;
+ fn2(SKB, C);
Signed-off-by: yuan linyu <Linyu.Yuan@alcatel-sbell.com.cn>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-06-18 17:48:17 +03:00
__skb_put_data ( skb , dev - > broadcast , ETH_ALEN ) ;
__skb_put_data ( skb , dev - > broadcast , ETH_ALEN ) ;
2007-02-09 17:24:33 +03:00
}
2005-04-17 02:20:36 +04:00
/* FIXME: We should group addresses here. */
2010-03-01 08:09:14 +03:00
i = 0 ;
2010-04-02 01:22:57 +04:00
netdev_for_each_mc_addr ( ha , dev ) {
2010-03-01 08:09:14 +03:00
if ( i = = BNEP_MAX_MULTICAST_FILTERS )
break ;
net: introduce __skb_put_[zero, data, u8]
follow Johannes Berg, semantic patch file as below,
@@
identifier p, p2;
expression len;
expression skb;
type t, t2;
@@
(
-p = __skb_put(skb, len);
+p = __skb_put_zero(skb, len);
|
-p = (t)__skb_put(skb, len);
+p = __skb_put_zero(skb, len);
)
... when != p
(
p2 = (t2)p;
-memset(p2, 0, len);
|
-memset(p, 0, len);
)
@@
identifier p;
expression len;
expression skb;
type t;
@@
(
-t p = __skb_put(skb, len);
+t p = __skb_put_zero(skb, len);
)
... when != p
(
-memset(p, 0, len);
)
@@
type t, t2;
identifier p, p2;
expression skb;
@@
t *p;
...
(
-p = __skb_put(skb, sizeof(t));
+p = __skb_put_zero(skb, sizeof(t));
|
-p = (t *)__skb_put(skb, sizeof(t));
+p = __skb_put_zero(skb, sizeof(t));
)
... when != p
(
p2 = (t2)p;
-memset(p2, 0, sizeof(*p));
|
-memset(p, 0, sizeof(*p));
)
@@
expression skb, len;
@@
-memset(__skb_put(skb, len), 0, len);
+__skb_put_zero(skb, len);
@@
expression skb, len, data;
@@
-memcpy(__skb_put(skb, len), data, len);
+__skb_put_data(skb, data, len);
@@
expression SKB, C, S;
typedef u8;
identifier fn = {__skb_put};
fresh identifier fn2 = fn ## "_u8";
@@
- *(u8 *)fn(SKB, S) = C;
+ fn2(SKB, C);
Signed-off-by: yuan linyu <Linyu.Yuan@alcatel-sbell.com.cn>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-06-18 17:48:17 +03:00
__skb_put_data ( skb , ha - > addr , ETH_ALEN ) ;
__skb_put_data ( skb , ha - > addr , ETH_ALEN ) ;
2010-06-18 18:24:00 +04:00
i + + ;
2005-04-17 02:20:36 +04:00
}
r - > len = htons ( skb - > len - len ) ;
}
skb_queue_tail ( & sk - > sk_write_queue , skb ) ;
2010-04-20 17:03:51 +04:00
wake_up_interruptible ( sk_sleep ( sk ) ) ;
2005-04-17 02:20:36 +04:00
# endif
}
static int bnep_net_set_mac_addr ( struct net_device * dev , void * arg )
{
BT_DBG ( " %s " , dev - > name ) ;
return 0 ;
}
static void bnep_net_timeout ( struct net_device * dev )
{
BT_DBG ( " net_timeout " ) ;
netif_wake_queue ( dev ) ;
}
# ifdef CONFIG_BT_BNEP_MC_FILTER
2012-05-23 11:04:18 +04:00
static int bnep_net_mc_filter ( struct sk_buff * skb , struct bnep_session * s )
2005-04-17 02:20:36 +04:00
{
struct ethhdr * eh = ( void * ) skb - > data ;
if ( ( eh - > h_dest [ 0 ] & 1 ) & & ! test_bit ( bnep_mc_hash ( eh - > h_dest ) , ( ulong * ) & s - > mc_filter ) )
return 1 ;
return 0 ;
}
# endif
# ifdef CONFIG_BT_BNEP_PROTO_FILTER
/* Determine ether protocol. Based on eth_type_trans. */
2012-05-23 11:04:18 +04:00
static u16 bnep_net_eth_proto ( struct sk_buff * skb )
2005-04-17 02:20:36 +04:00
{
struct ethhdr * eh = ( void * ) skb - > data ;
2006-11-08 11:27:36 +03:00
u16 proto = ntohs ( eh - > h_proto ) ;
2007-02-09 17:24:33 +03:00
2013-03-28 08:38:25 +04:00
if ( proto > = ETH_P_802_3_MIN )
2006-11-08 11:27:36 +03:00
return proto ;
2007-02-09 17:24:33 +03:00
2006-11-08 11:27:36 +03:00
if ( get_unaligned ( ( __be16 * ) skb - > data ) = = htons ( 0xFFFF ) )
return ETH_P_802_3 ;
2007-02-09 17:24:33 +03:00
2006-11-08 11:27:36 +03:00
return ETH_P_802_2 ;
2005-04-17 02:20:36 +04:00
}
2012-05-23 11:04:18 +04:00
static int bnep_net_proto_filter ( struct sk_buff * skb , struct bnep_session * s )
2005-04-17 02:20:36 +04:00
{
u16 proto = bnep_net_eth_proto ( skb ) ;
struct bnep_proto_filter * f = s - > proto_filter ;
int i ;
2007-02-09 17:24:33 +03:00
2005-04-17 02:20:36 +04:00
for ( i = 0 ; i < BNEP_MAX_PROTO_FILTERS & & f [ i ] . end ; i + + ) {
if ( proto > = f [ i ] . start & & proto < = f [ i ] . end )
return 0 ;
}
BT_DBG ( " BNEP: filtered skb %p, proto 0x%.4x " , skb , proto ) ;
return 1 ;
}
# endif
2009-08-31 23:50:41 +04:00
static netdev_tx_t bnep_net_xmit ( struct sk_buff * skb ,
struct net_device * dev )
2005-04-17 02:20:36 +04:00
{
2008-11-13 10:39:10 +03:00
struct bnep_session * s = netdev_priv ( dev ) ;
2005-04-17 02:20:36 +04:00
struct sock * sk = s - > sock - > sk ;
BT_DBG ( " skb %p, dev %p " , skb , dev ) ;
# ifdef CONFIG_BT_BNEP_MC_FILTER
if ( bnep_net_mc_filter ( skb , s ) ) {
kfree_skb ( skb ) ;
2009-06-23 10:03:08 +04:00
return NETDEV_TX_OK ;
2005-04-17 02:20:36 +04:00
}
# endif
2007-02-09 17:24:33 +03:00
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_BT_BNEP_PROTO_FILTER
if ( bnep_net_proto_filter ( skb , s ) ) {
kfree_skb ( skb ) ;
2009-06-23 10:03:08 +04:00
return NETDEV_TX_OK ;
2005-04-17 02:20:36 +04:00
}
# endif
2007-02-09 17:24:33 +03:00
2005-04-17 02:20:36 +04:00
/*
* We cannot send L2CAP packets from here as we are potentially in a bh .
* So we have to queue them and wake up session thread which is sleeping
2010-04-20 17:03:51 +04:00
* on the sk_sleep ( sk ) .
2005-04-17 02:20:36 +04:00
*/
2016-05-03 17:33:13 +03:00
netif_trans_update ( dev ) ;
2005-04-17 02:20:36 +04:00
skb_queue_tail ( & sk - > sk_write_queue , skb ) ;
2010-04-20 17:03:51 +04:00
wake_up_interruptible ( sk_sleep ( sk ) ) ;
2005-04-17 02:20:36 +04:00
if ( skb_queue_len ( & sk - > sk_write_queue ) > = BNEP_TX_QUEUE_LEN ) {
BT_DBG ( " tx queue is full " ) ;
/* Stop queuing.
* Session thread will do netif_wake_queue ( ) */
netif_stop_queue ( dev ) ;
}
2009-06-23 10:03:08 +04:00
return NETDEV_TX_OK ;
2005-04-17 02:20:36 +04:00
}
2009-01-08 04:23:17 +03:00
static const struct net_device_ops bnep_netdev_ops = {
. ndo_open = bnep_net_open ,
. ndo_stop = bnep_net_close ,
. ndo_start_xmit = bnep_net_xmit ,
. ndo_validate_addr = eth_validate_addr ,
2011-08-16 10:29:01 +04:00
. ndo_set_rx_mode = bnep_net_set_mc_list ,
2009-01-08 04:23:17 +03:00
. ndo_set_mac_address = bnep_net_set_mac_addr ,
. ndo_tx_timeout = bnep_net_timeout ,
} ;
2005-04-17 02:20:36 +04:00
void bnep_net_setup ( struct net_device * dev )
{
2015-03-03 06:54:55 +03:00
eth_broadcast_addr ( dev - > broadcast ) ;
2005-04-17 02:20:36 +04:00
dev - > addr_len = ETH_ALEN ;
ether_setup ( dev ) ;
2016-10-21 06:25:27 +03:00
dev - > min_mtu = 0 ;
dev - > max_mtu = ETH_MAX_MTU ;
2011-07-26 10:05:38 +04:00
dev - > priv_flags & = ~ IFF_TX_SKB_SHARING ;
2009-01-08 04:23:17 +03:00
dev - > netdev_ops = & bnep_netdev_ops ;
2005-04-17 02:20:36 +04:00
dev - > watchdog_timeo = HZ * 2 ;
}