519 lines
13 KiB
C
Raw Normal View History

/*
* 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,
}};