Julian Elischer 878ed22696 The second try a committing the bluetooth code
Has been seen to work on several cards and communicating with
several mobile phones to use them as modems etc.

We are still talking with 3com to try get them to allow us to include
the firmware for their pccard in the driver but the driver is here..
In the mean time
it can be downloaded from the 3com website and loaded using the utility
bt3cfw(8) (supplied) (instructions in the man page)

Not yet linked to the build

Submitted by:	Maksim Yevmenkin <myevmenk@exodus.net>
Approved by:	re
2002-11-20 23:01:59 +00:00

519 lines
13 KiB
C

/*
* node.c
*
* Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: node.c,v 1.8 2002/11/12 22:33:17 max Exp $
* $FreeBSD$
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <bitstring.h>
#include <errno.h>
#include <ng_hci.h>
#include <ng_l2cap.h>
#include <ng_btsocket.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "hccontrol.h"
/* Send Read_Node_State command to the node */
static int
hci_read_node_state(int s, int argc, char **argv)
{
struct ng_btsocket_hci_raw_node_state r;
memset(&r, 0, sizeof(r));
if (ioctl(s, SIOC_HCI_RAW_NODE_GET_STATE, &r, sizeof(r)) < 0)
return (ERROR);
fprintf(stdout, "Node: %s\nState: %#x\n", r.hci_node, r.state);
return (OK);
} /* hci_read_node_state */
/* Send Intitialize command to the node */
static int
hci_node_initialize(int s, int argc, char **argv)
{
struct ng_btsocket_hci_raw_node_init r;
memset(&r, 0, sizeof(r));
if (ioctl(s, SIOC_HCI_RAW_NODE_INIT, &r, sizeof(r)) < 0)
return (ERROR);
return (OK);
} /* hci_node_initialize */
/* Send Read_Debug_Level command to the node */
static int
hci_read_debug_level(int s, int argc, char **argv)
{
struct ng_btsocket_hci_raw_node_debug r;
memset(&r, 0, sizeof(r));
if (ioctl(s, SIOC_HCI_RAW_NODE_GET_DEBUG, &r, sizeof(r)) < 0)
return (ERROR);
fprintf(stdout, "Node: %s\nDebug level: %d\n", r.hci_node, r.debug);
return (OK);
} /* hci_read_debug_level */
/* Send Write_Debug_Level command to the node */
static int
hci_write_debug_level(int s, int argc, char **argv)
{
struct ng_btsocket_hci_raw_node_debug r;
memset(&r, 0, sizeof(r));
switch (argc) {
case 1:
r.debug = atoi(argv[0]);
break;
default:
return (USAGE);
}
if (ioctl(s, SIOC_HCI_RAW_NODE_SET_DEBUG, &r, sizeof(r)) < 0)
return (ERROR);
return (OK);
} /* hci_write_debug_level */
/* Send Read_Node_Buffer_Size command to the node */
static int
hci_read_node_buffer_size(int s, int argc, char **argv)
{
struct ng_btsocket_hci_raw_node_buffer r;
memset(&r, 0, sizeof(r));
if (ioctl(s, SIOC_HCI_RAW_NODE_GET_BUFFER, &r, sizeof(r)) < 0)
return (ERROR);
fprintf(stdout, "Node: %s\n",
r.hci_node);
fprintf(stdout, "Number of free command buffers: %d\n",
r.buffer.cmd_free);
fprintf(stdout, "Max. ACL packet size: %d\n",
r.buffer.acl_size);
fprintf(stdout, "Numbef of free ACL buffers: %d\n",
r.buffer.acl_free);
fprintf(stdout, "Total number of ACL buffers: %d\n",
r.buffer.acl_pkts);
fprintf(stdout, "Max. SCO packet size: %d\n",
r.buffer.sco_size);
fprintf(stdout, "Numbef of free SCO buffers: %d\n",
r.buffer.sco_free);
fprintf(stdout, "Total number of SCO buffers: %d\n",
r.buffer.sco_pkts);
return (OK);
} /* hci_read_node_buffer_size */
/* Send Read_Node_BD_ADDR command to the node */
static int
hci_read_node_bd_addr(int s, int argc, char **argv)
{
struct ng_btsocket_hci_raw_node_bdaddr r;
memset(&r, 0, sizeof(r));
if (ioctl(s, SIOC_HCI_RAW_NODE_GET_BDADDR, &r, sizeof(r)) < 0)
return (ERROR);
fprintf(stdout, "Node: %s\n", r.hci_node);
fprintf(stdout, "BD_ADDR: %02x:%02x:%02x:%02x:%02x:%02x\n",
r.bdaddr.b[5], r.bdaddr.b[4], r.bdaddr.b[3],
r.bdaddr.b[2], r.bdaddr.b[1], r.bdaddr.b[0]);
return (OK);
} /* hci_read_node_bd_addr */
/* Send Read_Node_Features command to the node */
static int
hci_read_node_features(int s, int argc, char **argv)
{
struct ng_btsocket_hci_raw_node_features r;
int n;
char buffer[1024];
memset(&r, 0, sizeof(r));
if (ioctl(s, SIOC_HCI_RAW_NODE_GET_FEATURES, &r, sizeof(r)) < 0)
return (ERROR);
fprintf(stdout, "Node: %s\nFeatures: ", r.hci_node);
for (n = 0; n < sizeof(r.features)/sizeof(r.features[0]); n++)
fprintf(stdout, "%#02x ", r.features[n]);
fprintf(stdout, "\n%s\n", hci_features2str(r.features,
buffer, sizeof(buffer)));
return (OK);
} /* hci_read_node_features */
/* Send Read_Node_Stat command to the node */
static int
hci_read_node_stat(int s, int argc, char **argv)
{
struct ng_btsocket_hci_raw_node_stat r;
memset(&r, 0, sizeof(r));
if (ioctl(s, SIOC_HCI_RAW_NODE_GET_STAT, &r, sizeof(r)) < 0)
return (ERROR);
fprintf(stdout, "Node: %s\n", r.hci_node);
fprintf(stdout, "Commands sent: %d\n", r.stat.cmd_sent);
fprintf(stdout, "Events received: %d\n", r.stat.evnt_recv);
fprintf(stdout, "ACL packets received: %d\n", r.stat.acl_recv);
fprintf(stdout, "ACL packets sent: %d\n", r.stat.acl_sent);
fprintf(stdout, "SCO packets received: %d\n", r.stat.sco_recv);
fprintf(stdout, "SCO packets sent: %d\n", r.stat.sco_sent);
fprintf(stdout, "Bytes received: %d\n", r.stat.bytes_recv);
fprintf(stdout, "Bytes sent: %d\n", r.stat.bytes_sent);
return (OK);
} /* hci_read_node_stat */
/* Send Reset_Node_Stat command to the node */
static int
hci_reset_node_stat(int s, int argc, char **argv)
{
struct ng_btsocket_hci_raw_node_reset_stat r;
memset(&r, 0, sizeof(r));
if (ioctl(s, SIOC_HCI_RAW_NODE_RESET_STAT, &r, sizeof(r)) < 0)
return (ERROR);
return (OK);
} /* hci_reset_node_stat */
/* Send Flush_Neighbor_Cache command to the node */
static int
hci_flush_neighbor_cache(int s, int argc, char **argv)
{
struct ng_btsocket_hci_raw_node_flush_neighbor_cache r;
memset(&r, 0, sizeof(r));
if (ioctl(s, SIOC_HCI_RAW_NODE_FLUSH_NEIGHBOR_CACHE,
&r, sizeof(r)) < 0)
return (ERROR);
return (OK);
} /* hci_flush_neighbor_cache */
/* Send Read_Neighbor_Cache command to the node */
static int
hci_read_neighbor_cache(int s, int argc, char **argv)
{
struct ng_btsocket_hci_raw_node_neighbor_cache r;
int n, error = OK;
memset(&r, 0, sizeof(r));
r.num_entries = NG_HCI_MAX_NEIGHBOR_NUM;
r.entries = calloc(NG_HCI_MAX_NEIGHBOR_NUM,
sizeof(ng_hci_node_neighbor_cache_entry_ep));
if (r.entries == NULL) {
errno = ENOMEM;
return (ERROR);
}
if (ioctl(s, SIOC_HCI_RAW_NODE_GET_NEIGHBOR_CACHE, &r,
sizeof(r)) < 0) {
error = ERROR;
goto out;
}
fprintf(stdout, "Neighbor cache for the node: %s\n", r.hci_node);
fprintf(stdout,
"BD_ADDR " \
"Features " \
"Clock offset " \
"Page scan " \
"Rep. scan\n");
for (n = 0; n < r.num_entries; n++) {
fprintf(stdout,
"%02x:%02x:%02x:%02x:%02x:%02x " \
"%02x %02x %02x %02x %02x %02x %02x %02x " \
"%#12x " \
"%#9x " \
"%#9x\n",
r.entries[n].bdaddr.b[5], r.entries[n].bdaddr.b[4],
r.entries[n].bdaddr.b[3], r.entries[n].bdaddr.b[2],
r.entries[n].bdaddr.b[1], r.entries[n].bdaddr.b[0],
r.entries[n].features[0], r.entries[n].features[1],
r.entries[n].features[2], r.entries[n].features[3],
r.entries[n].features[4], r.entries[n].features[5],
r.entries[n].features[6], r.entries[n].features[7],
r.entries[n].clock_offset, r.entries[n].page_scan_mode,
r.entries[n].page_scan_rep_mode);
}
out:
free(r.entries);
return (error);
} /* hci_read_neightbor_cache */
/* Send Read_Connection_List command to the node */
static int
hci_read_connection_list(int s, int argc, char **argv)
{
struct ng_btsocket_hci_raw_con_list r;
int n, error = OK;
memset(&r, 0, sizeof(r));
r.num_connections = NG_HCI_MAX_CON_NUM;
r.connections = calloc(NG_HCI_MAX_CON_NUM, sizeof(ng_hci_node_con_ep));
if (r.connections == NULL) {
errno = ENOMEM;
return (ERROR);
}
if (ioctl(s, SIOC_HCI_RAW_NODE_GET_CON_LIST, &r, sizeof(r)) < 0) {
error = ERROR;
goto out;
}
fprintf(stdout, "Connections list for the node: %s\n", r.hci_node);
fprintf(stdout,
"Remote BD_ADDR " \
"Handle " \
"Type " \
"Mode " \
"Role " \
"Encrypt " \
"Pending " \
"Queue " \
"State\n");
for (n = 0; n < r.num_connections; n++) {
fprintf(stdout,
"%02x:%02x:%02x:%02x:%02x:%02x " \
"%6d " \
"%4.4s " \
"%4d " \
"%4.4s " \
"%7.7s " \
"%7d " \
"%5d " \
"%s\n",
r.connections[n].bdaddr.b[5],
r.connections[n].bdaddr.b[4],
r.connections[n].bdaddr.b[3],
r.connections[n].bdaddr.b[2],
r.connections[n].bdaddr.b[1],
r.connections[n].bdaddr.b[0],
r.connections[n].con_handle,
(r.connections[n].link_type == NG_HCI_LINK_ACL)?
"ACL" : "SCO",
r.connections[n].mode,
(r.connections[n].role == NG_HCI_ROLE_MASTER)?
"MAST" : "SLAV",
hci_encrypt2str(r.connections[n].encryption_mode, 1),
r.connections[n].pending,
r.connections[n].queue_len,
hci_con_state2str(r.connections[n].state));
}
out:
free(r.connections);
return (error);
} /* hci_read_connection_list */
/* Send Read_Link_Policy_Settings_Mask command to the node */
int
hci_read_link_policy_settings_mask(int s, int argc, char **argv)
{
struct ng_btsocket_hci_raw_node_link_policy_mask r;
memset(&r, 0, sizeof(r));
if (ioctl(s, SIOC_HCI_RAW_NODE_GET_LINK_POLICY_MASK, &r, sizeof(r)) < 0)
return (ERROR);
fprintf(stdout, "Node: %s\nLink Policy Settings mask: %#04x\n",
r.hci_node, r.policy_mask);
return (OK);
} /* hci_read_link_policy_settings_mask */
/* Send Write_Link_Policy_Settings_Mask command to the node */
int
hci_write_link_policy_settings_mask(int s, int argc, char **argv)
{
struct ng_btsocket_hci_raw_node_link_policy_mask r;
int m;
memset(&r, 0, sizeof(r));
switch (argc) {
case 1:
if (sscanf(argv[0], "%x", &m) != 1)
return (USAGE);
r.policy_mask = (m & 0xffff);
break;
default:
return (USAGE);
}
if (ioctl(s, SIOC_HCI_RAW_NODE_SET_LINK_POLICY_MASK, &r, sizeof(r)) < 0)
return (ERROR);
return (OK);
} /* hci_write_link_policy_settings_mask */
/* Send Read_Packet_Mask command to the node */
int
hci_read_packet_mask(int s, int argc, char **argv)
{
struct ng_btsocket_hci_raw_node_packet_mask r;
memset(&r, 0, sizeof(r));
if (ioctl(s, SIOC_HCI_RAW_NODE_GET_PACKET_MASK, &r, sizeof(r)) < 0)
return (ERROR);
fprintf(stdout, "Node: %s\nPacket mask: %#04x\n",
r.hci_node, r.packet_mask);
return (OK);
} /* hci_read_packet_mask */
/* Send Write_Packet_Mask command to the node */
int
hci_write_packet_mask(int s, int argc, char **argv)
{
struct ng_btsocket_hci_raw_node_packet_mask r;
int m;
memset(&r, 0, sizeof(r));
switch (argc) {
case 1:
if (sscanf(argv[0], "%x", &m) != 1)
return (USAGE);
r.packet_mask = (m & 0xffff);
break;
default:
return (USAGE);
}
if (ioctl(s, SIOC_HCI_RAW_NODE_SET_PACKET_MASK, &r, sizeof(r)) < 0)
return (ERROR);
return (OK);
} /* hci_write_packet_mask */
struct hci_command node_commands[] = {
{
"read_node_state",
"Get HCI node state",
&hci_read_node_state
},
{
"initialize",
"Initialize HCI node",
&hci_node_initialize
},
{
"read_debug_level",
"Read HCI node debug level",
&hci_read_debug_level
},
{
"write_debug_level <level>",
"Write HCI node debug level",
&hci_write_debug_level
},
{
"read_node_buffer_size",
"Read HCI node buffer information",
&hci_read_node_buffer_size
},
{
"read_node_bd_addr",
"Read HCI node BD_ADDR",
&hci_read_node_bd_addr
},
{
"read_node_features",
"Read HCI node features",
&hci_read_node_features
},
{
"read_node_stat",
"Read HCI node statistic information",
&hci_read_node_stat
},
{
"reset_node_stat",
"Reset HCI node statistic information",
&hci_reset_node_stat
},
{
"flush_neighbor_cache",
"Flush HCI node neighbor cache",
&hci_flush_neighbor_cache
},
{
"read_neighbor_cache",
"Read HCI node neighbor cache",
&hci_read_neighbor_cache
},
{
"read_connection_list",
"Read connection list",
&hci_read_connection_list
},
{
"read_node_link_policy_settings_mask",
"Read Link Policy Settinngs mask for the node",
&hci_read_link_policy_settings_mask
},
{
"write_node_link_policy_settings_mask <policy_mask>",
"Write Link Policy Settinngs mask for the node. Policy mask - xxxx",
&hci_write_link_policy_settings_mask
},
{
"read_node_packet_mask",
"Read Packet mask for the node",
&hci_read_packet_mask
},
{
"write_node_packet_mask <packet_mask>",
"Write Packet mask for the node. Packet mask - xxxx",
&hci_write_packet_mask
},
{
NULL,
}};