2014-10-20 10:06:23 +00:00
/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4; tab-width: 4 -*- */
/*
* panu_demo . c
* Copyright ( C ) 2014 Ole Reinhardt < ole . reinhardt @ kernelconcepts . de >
2014-10-28 01:16:57 +00:00
*
2014-10-20 10:06:23 +00:00
*/
# include "btstack-config.h"
# include <stdint.h>
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
2014-10-27 11:50:12 +00:00
# include <sys/socket.h>
# include <linux/in.h>
# include <linux/if.h>
# include <linux/if_tun.h>
# include <net/if_arp.h>
# include <sys/ioctl.h>
# include <sys/types.h>
# include <sys/stat.h>
# include <fcntl.h>
# include <unistd.h>
# include <errno.h>
2014-10-20 10:06:23 +00:00
# include <btstack/hci_cmds.h>
# include <btstack/run_loop.h>
2014-12-12 08:42:35 +00:00
# include <btstack/sdp_util.h>
2014-10-20 10:06:23 +00:00
# include "hci.h"
# include "btstack_memory.h"
# include "hci_dump.h"
# include "l2cap.h"
# include "sdp_parser.h"
2014-10-27 11:50:12 +00:00
# include "sdp_client.h"
# include "sdp_query_util.h"
# include "pan.h"
2014-10-20 10:06:23 +00:00
2014-10-27 11:50:12 +00:00
static int record_id = - 1 ;
static uint16_t bnep_protocol_id = 0x000f ;
static uint16_t bnep_l2cap_psm = 0 ;
2014-12-04 09:40:43 +00:00
static uint32_t bnep_remote_uuid = 0 ;
2014-10-27 11:50:12 +00:00
static uint16_t bnep_version = 0 ;
2014-10-28 01:16:57 +00:00
static uint16_t bnep_cid = 0 ;
2014-10-20 10:06:23 +00:00
static uint8_t attribute_value [ 1000 ] ;
2014-11-18 21:37:23 +00:00
static const unsigned int attribute_value_buffer_size = sizeof ( attribute_value ) ;
2014-10-20 10:06:23 +00:00
//static bd_addr_t remote = {0x04,0x0C,0xCE,0xE4,0x85,0xD3};
static bd_addr_t remote = { 0xE0 , 0x06 , 0xE6 , 0xBB , 0x95 , 0x79 } ;
2014-10-27 11:50:12 +00:00
static int tap_fd = - 1 ;
static char tap_dev_name [ 16 ] = " bnep%d " ;
static uint8_t network_buffer [ BNEP_MTU_MIN ] ;
static size_t network_buffer_len = 0 ;
static data_source_t tap_dev_ds ;
/*************** TUN / TAP interface routines *********************
* *
* https : //www.kernel.org/doc/Documentation/networking/tuntap.txt *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int tap_alloc ( char * dev , bd_addr_t bd_addr )
{
struct ifreq ifr ;
int fd_dev ;
int fd_socket ;
int err ;
if ( ( fd_dev = open ( " /dev/net/tun " , O_RDWR ) ) < 0 ) {
fprintf ( stderr , " TAP: Error opening /dev/net/tun: %s \n " , strerror ( errno ) ) ;
return - 1 ;
}
memset ( & ifr , 0 , sizeof ( ifr ) ) ;
2014-10-20 10:06:23 +00:00
2014-10-27 11:50:12 +00:00
/* Flags: IFF_TUN - TUN device (no Ethernet headers)
* IFF_TAP - TAP device
*
* IFF_NO_PI - Do not provide packet information
*/
ifr . ifr_flags = IFF_TAP | IFF_NO_PI ;
if ( * dev ) {
strncpy ( ifr . ifr_name , dev , IFNAMSIZ ) ;
}
if ( ( err = ioctl ( fd_dev , TUNSETIFF , ( void * ) & ifr ) ) < 0 ) {
fprintf ( stderr , " TAP: Error setting device name: %s \n " , strerror ( errno ) ) ;
close ( fd_dev ) ;
return - 1 ;
}
strcpy ( dev , ifr . ifr_name ) ;
fd_socket = socket ( PF_INET , SOCK_DGRAM , IPPROTO_IP ) ;
if ( fd_socket < 0 ) {
close ( fd_dev ) ;
fprintf ( stderr , " TAP: Error opening netlink socket: %s \n " , strerror ( errno ) ) ;
return - 1 ;
}
/* Configure the MAC address of the newly created bnep(x) device to the local bd_address */
memset ( & ifr , 0 , sizeof ( struct ifreq ) ) ;
strcpy ( ifr . ifr_name , dev ) ;
memcpy ( ifr . ifr_hwaddr . sa_data , bd_addr , sizeof ( bd_addr_t ) ) ;
ifr . ifr_hwaddr . sa_family = ARPHRD_ETHER ;
if ( ioctl ( fd_socket , SIOCSIFHWADDR , & ifr ) = = - 1 ) {
close ( fd_dev ) ;
close ( fd_socket ) ;
fprintf ( stderr , " TAP: Error setting hw addr: %s \n " , strerror ( errno ) ) ;
exit ( 1 ) ;
return - 1 ;
}
/* Bring the interface up */
if ( ioctl ( fd_socket , SIOCGIFFLAGS , & ifr ) = = - 1 ) {
close ( fd_dev ) ;
close ( fd_socket ) ;
fprintf ( stderr , " TAP: Error reading interface flags: %s \n " , strerror ( errno ) ) ;
return - 1 ;
}
if ( ( ifr . ifr_flags & IFF_UP ) = = 0 ) {
ifr . ifr_flags | = IFF_UP ;
if ( ioctl ( fd_socket , SIOCSIFFLAGS , & ifr ) = = - 1 ) {
close ( fd_dev ) ;
close ( fd_socket ) ;
fprintf ( stderr , " TAP: Error set IFF_UP: %s \n " , strerror ( errno ) ) ;
return - 1 ;
}
}
close ( fd_socket ) ;
return fd_dev ;
}
int process_tap_dev_data ( struct data_source * ds )
{
ssize_t len ;
len = read ( ds - > fd , network_buffer , sizeof ( network_buffer ) ) ;
if ( len > 0 ) {
network_buffer_len = len ;
} else {
fprintf ( stderr , " TAP: Error while reading: %s \n " , strerror ( errno ) ) ;
}
2014-10-28 01:16:57 +00:00
if ( bnep_can_send_packet_now ( bnep_cid ) ) {
bnep_send ( bnep_cid , network_buffer , network_buffer_len ) ;
network_buffer_len = 0 ;
} else {
/* park the current network packet */
run_loop_remove_data_source ( & tap_dev_ds ) ;
}
2014-10-27 11:50:12 +00:00
return 0 ;
}
/*************** PANU client routines *********************/
2014-10-20 10:06:23 +00:00
char * get_string_from_data_element ( uint8_t * element ) {
de_size_t de_size = de_get_size_type ( element ) ;
int pos = de_get_header_size ( element ) ;
int len = 0 ;
switch ( de_size ) {
case DE_SIZE_VAR_8 :
len = element [ 1 ] ;
break ;
case DE_SIZE_VAR_16 :
len = READ_NET_16 ( element , 1 ) ;
break ;
default :
break ;
}
char * str = ( char * ) malloc ( len + 1 ) ;
memcpy ( str , & element [ pos ] , len ) ;
str [ len ] = ' \0 ' ;
return str ;
}
/* SDP parser callback */
static void handle_sdp_client_query_result ( sdp_query_event_t * event )
{
sdp_query_attribute_value_event_t * value_event ;
sdp_query_complete_event_t * complete_event ;
2014-10-27 11:50:12 +00:00
des_iterator_t des_list_it ;
des_iterator_t prot_it ;
2014-11-18 21:37:29 +00:00
char * str ;
2014-10-20 10:06:23 +00:00
switch ( event - > type ) {
case SDP_QUERY_ATTRIBUTE_VALUE :
value_event = ( sdp_query_attribute_value_event_t * ) event ;
/* Handle new SDP record */
if ( value_event - > record_id ! = record_id ) {
record_id = value_event - > record_id ;
printf ( " SDP Record: Nr: %d \n " , record_id ) ;
}
if ( value_event - > attribute_length < = attribute_value_buffer_size ) {
attribute_value [ value_event - > data_offset ] = value_event - > data ;
if ( ( uint16_t ) ( value_event - > data_offset + 1 ) = = value_event - > attribute_length ) {
2014-10-27 11:50:12 +00:00
switch ( value_event - > attribute_id ) {
case SDP_ServiceClassIDList :
if ( de_get_element_type ( attribute_value ) ! = DE_DES ) break ;
for ( des_iterator_init ( & des_list_it , attribute_value ) ; des_iterator_has_more ( & des_list_it ) ; des_iterator_next ( & des_list_it ) ) {
uint8_t * element = des_iterator_get_element ( & des_list_it ) ;
if ( de_get_element_type ( element ) ! = DE_UUID ) continue ;
2014-12-04 09:40:43 +00:00
uint32_t uuid = de_get_uuid32 ( element ) ;
2014-10-27 11:50:12 +00:00
switch ( uuid ) {
case BNEP_UUID_PANU :
case BNEP_UUID_NAP :
case BNEP_UUID_GN :
printf ( " SDP Attribute 0x%04x: BNEP PAN protocol UUID: %04x \n " , value_event - > attribute_id , uuid ) ;
bnep_remote_uuid = uuid ;
break ;
default :
break ;
}
}
break ;
2014-10-20 10:06:23 +00:00
case 0x0100 :
case 0x0101 :
2014-11-18 21:37:29 +00:00
str = get_string_from_data_element ( attribute_value ) ;
printf ( " SDP Attribute: 0x%04x: %s \n " , value_event - > attribute_id , str ) ;
free ( str ) ;
2014-10-20 10:06:23 +00:00
break ;
2014-10-27 11:50:12 +00:00
case 0x0004 : {
2014-10-20 10:06:23 +00:00
printf ( " SDP Attribute: 0x%04x \n " , value_event - > attribute_id ) ;
for ( des_iterator_init ( & des_list_it , attribute_value ) ; des_iterator_has_more ( & des_list_it ) ; des_iterator_next ( & des_list_it ) ) {
uint8_t * des_element ;
uint8_t * element ;
2014-12-04 09:40:43 +00:00
uint32_t uuid ;
2014-10-20 10:06:23 +00:00
if ( des_iterator_get_type ( & des_list_it ) ! = DE_DES ) continue ;
des_element = des_iterator_get_element ( & des_list_it ) ;
des_iterator_init ( & prot_it , des_element ) ;
element = des_iterator_get_element ( & prot_it ) ;
if ( de_get_element_type ( element ) ! = DE_UUID ) continue ;
2014-12-04 09:40:43 +00:00
uuid = de_get_uuid32 ( element ) ;
2014-10-20 10:06:23 +00:00
switch ( uuid ) {
case 0x0100 :
if ( ! des_iterator_has_more ( & prot_it ) ) continue ;
des_iterator_next ( & prot_it ) ;
2014-10-27 11:50:12 +00:00
de_element_get_uint16 ( des_iterator_get_element ( & prot_it ) , & bnep_l2cap_psm ) ;
2014-10-20 10:06:23 +00:00
break ;
case 0x000f :
if ( ! des_iterator_has_more ( & prot_it ) ) continue ;
des_iterator_next ( & prot_it ) ;
de_element_get_uint16 ( des_iterator_get_element ( & prot_it ) , & bnep_version ) ;
break ;
default :
break ;
}
}
2014-10-27 11:50:12 +00:00
printf ( " l2cap_psm 0x%04x, bnep_version 0x%04x \n " , bnep_l2cap_psm , bnep_version ) ;
2014-10-28 01:16:57 +00:00
2014-10-20 10:06:23 +00:00
/* Create BNEP connection */
2014-10-27 11:50:12 +00:00
bnep_connect ( NULL , & remote , bnep_l2cap_psm , bnep_remote_uuid ) ;
2014-10-20 10:06:23 +00:00
}
break ;
default :
break ;
}
}
} else {
fprintf ( stderr , " SDP attribute value buffer size exceeded: available %d, required %d \n " , attribute_value_buffer_size , value_event - > attribute_length ) ;
}
break ;
case SDP_QUERY_COMPLETE :
complete_event = ( sdp_query_complete_event_t * ) event ;
fprintf ( stderr , " General query done with status %d. \n " , complete_event - > status ) ;
break ;
}
}
static void packet_handler ( void * connection , uint8_t packet_type , uint16_t channel , uint8_t * packet , uint16_t size )
{
2014-10-27 11:50:12 +00:00
int rc ;
uint8_t event ;
2014-10-20 10:06:23 +00:00
bd_addr_t event_addr ;
uint16_t uuid_source ;
uint16_t uuid_dest ;
uint16_t mtu ;
2014-10-27 11:50:12 +00:00
2014-10-20 10:06:23 +00:00
switch ( packet_type ) {
case HCI_EVENT_PACKET :
2014-10-27 11:50:12 +00:00
event = packet [ 0 ] ;
switch ( event ) {
2014-10-20 10:06:23 +00:00
case BTSTACK_EVENT_STATE :
/* BT Stack activated, get started */
if ( packet [ 2 ] = = HCI_STATE_WORKING ) {
/* Send a general query for BNEP Protocol ID */
printf ( " Start SDP BNEP query. \n " ) ;
sdp_general_query_for_uuid ( remote , bnep_protocol_id ) ;
}
break ;
case HCI_EVENT_COMMAND_COMPLETE :
if ( COMMAND_COMPLETE_EVENT ( packet , hci_read_bd_addr ) ) {
bt_flip_addr ( event_addr , & packet [ 6 ] ) ;
printf ( " BD-ADDR: %s \n " , bd_addr_to_str ( event_addr ) ) ;
break ;
}
break ;
case HCI_EVENT_PIN_CODE_REQUEST :
// inform about pin code request
printf ( " Pin code request - using '0000' \n " ) ;
bt_flip_addr ( event_addr , & packet [ 2 ] ) ;
hci_send_cmd ( & hci_pin_code_request_reply , & event_addr , 4 , " 0000 " ) ;
break ;
case HCI_EVENT_USER_CONFIRMATION_REQUEST :
// inform about user confirmation request
printf ( " SSP User Confirmation Request with numeric value '%06u' \n " , READ_BT_32 ( packet , 8 ) ) ;
printf ( " SSP User Confirmation Auto accept \n " ) ;
break ;
case BNEP_EVENT_INCOMING_CONNECTION :
2014-11-19 01:01:22 +00:00
// data: event(8), len(8), bnep source uuid (16), bnep destination uuid (16), remote_address (48)
uuid_source = READ_BT_16 ( packet , 2 ) ;
uuid_dest = READ_BT_16 ( packet , 4 ) ;
mtu = READ_BT_16 ( packet , 6 ) ;
2014-10-28 01:16:57 +00:00
bnep_cid = channel ;
2014-11-19 01:01:22 +00:00
memcpy ( & event_addr , & packet [ 8 ] , sizeof ( bd_addr_t ) ) ;
2014-10-27 11:50:12 +00:00
printf ( " BNEP connection from %s source UUID 0x%04x dest UUID: 0x%04x, max frame size: %u \n " , bd_addr_to_str ( event_addr ) , uuid_source , uuid_dest , mtu ) ;
2014-11-19 01:01:16 +00:00
/* Create the tap interface */
tap_fd = tap_alloc ( tap_dev_name , * hci_local_bd_addr ( ) ) ;
if ( tap_fd < 0 ) {
printf ( " Creating BNEP tap device failed: %s \n " , strerror ( errno ) ) ;
} else {
printf ( " BNEP device \" %s \" allocated. \n " , tap_dev_name ) ;
/* Create and register a new runloop data source */
tap_dev_ds . fd = tap_fd ;
tap_dev_ds . process = process_tap_dev_data ;
run_loop_add_data_source ( & tap_dev_ds ) ;
}
2014-10-20 10:06:23 +00:00
break ;
case BNEP_EVENT_OPEN_CHANNEL_COMPLETE :
if ( packet [ 2 ] ) {
printf ( " BNEP channel open failed, status %02x \n " , packet [ 2 ] ) ;
} else {
// data: event(8), len(8), status (8), bnep source uuid (16), bnep destination uuid (16), remote_address (48)
uuid_source = READ_BT_16 ( packet , 3 ) ;
uuid_dest = READ_BT_16 ( packet , 5 ) ;
mtu = READ_BT_16 ( packet , 7 ) ;
2014-10-28 01:16:57 +00:00
bnep_cid = channel ;
2014-10-27 11:50:12 +00:00
//bt_flip_addr(event_addr, &packet[9]);
memcpy ( & event_addr , & packet [ 9 ] , sizeof ( bd_addr_t ) ) ;
printf ( " BNEP connection open succeeded to %s source UUID 0x%04x dest UUID: 0x%04x, max frame size %u \n " , bd_addr_to_str ( event_addr ) , uuid_source , uuid_dest , mtu ) ;
/* Create the tap interface */
tap_fd = tap_alloc ( tap_dev_name , * hci_local_bd_addr ( ) ) ;
if ( tap_fd < 0 ) {
printf ( " Creating BNEP tap device failed: %s \n " , strerror ( errno ) ) ;
} else {
2014-10-28 01:16:57 +00:00
printf ( " BNEP device \" %s \" allocated. \n " , tap_dev_name ) ;
2014-10-27 11:50:12 +00:00
/* Create and register a new runloop data source */
tap_dev_ds . fd = tap_fd ;
tap_dev_ds . process = process_tap_dev_data ;
run_loop_add_data_source ( & tap_dev_ds ) ;
}
2014-10-20 10:06:23 +00:00
}
break ;
2014-11-13 00:28:01 +00:00
case BNEP_EVENT_CHANNEL_TIMEOUT :
printf ( " BNEP channel timeout! Channel will be closed \n " ) ;
break ;
2014-10-20 10:06:23 +00:00
case BNEP_EVENT_CHANNEL_CLOSED :
printf ( " BNEP channel closed \n " ) ;
2014-10-27 11:50:12 +00:00
run_loop_remove_data_source ( & tap_dev_ds ) ;
if ( tap_fd > 0 ) {
close ( tap_fd ) ;
tap_fd = - 1 ;
}
2014-10-20 10:06:23 +00:00
break ;
2014-10-28 01:16:57 +00:00
case BNEP_EVENT_READY_TO_SEND :
/* Check for parked network packets and send it out now */
if ( network_buffer_len > 0 ) {
bnep_send ( bnep_cid , network_buffer , network_buffer_len ) ;
network_buffer_len = 0 ;
/* Re-add the tap device data source */
run_loop_add_data_source ( & tap_dev_ds ) ;
}
break ;
2014-10-20 10:06:23 +00:00
default :
break ;
}
2014-10-27 11:50:12 +00:00
break ;
case BNEP_DATA_PACKET :
/* Write out the ethernet frame to the tap device */
if ( tap_fd > 0 ) {
rc = write ( tap_fd , packet , size ) ;
if ( rc < 0 ) {
fprintf ( stderr , " TAP: Could not write to TAP device: %s \n " , strerror ( errno ) ) ;
} else
if ( rc ! = size ) {
fprintf ( stderr , " TAP: Package written only partially %d of %d bytes \n " , rc , size ) ;
}
}
break ;
2014-10-20 10:06:23 +00:00
default :
break ;
}
}
2014-11-14 20:42:29 +00:00
int btstack_main ( int argc , const char * argv [ ] ) ;
int btstack_main ( int argc , const char * argv [ ] ) {
2014-10-20 10:06:23 +00:00
printf ( " Client HCI init done \n " ) ;
/* Initialize L2CAP */
l2cap_init ( ) ;
l2cap_register_packet_handler ( packet_handler ) ;
/* Initialise BNEP */
bnep_init ( ) ;
bnep_register_packet_handler ( packet_handler ) ;
2014-11-19 01:01:16 +00:00
bnep_register_service ( NULL , BNEP_UUID_PANU , 1691 ) ; /* Minimum L2CAP MTU for bnep is 1691 bytes */
2014-10-20 10:06:23 +00:00
/* Turn on the device */
hci_power_control ( HCI_POWER_ON ) ;
/* Initialise SDP */
sdp_parser_init ( ) ;
sdp_parser_register_callback ( handle_sdp_client_query_result ) ;
/* Start mainloop */
run_loop_execute ( ) ;
return 0 ;
}