1107120Sjulian/* 2107120Sjulian * l2cap.c 3107120Sjulian * 4107120Sjulian * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com> 5107120Sjulian * All rights reserved. 6107120Sjulian * 7107120Sjulian * Redistribution and use in source and binary forms, with or without 8107120Sjulian * modification, are permitted provided that the following conditions 9107120Sjulian * are met: 10107120Sjulian * 1. Redistributions of source code must retain the above copyright 11107120Sjulian * notice, this list of conditions and the following disclaimer. 12107120Sjulian * 2. Redistributions in binary form must reproduce the above copyright 13107120Sjulian * notice, this list of conditions and the following disclaimer in the 14107120Sjulian * documentation and/or other materials provided with the distribution. 15107120Sjulian * 16107120Sjulian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17107120Sjulian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18107120Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19107120Sjulian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20107120Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21107120Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22107120Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23107120Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24107120Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25107120Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26107120Sjulian * SUCH DAMAGE. 27107120Sjulian * 28121054Semax * $Id: l2cap.c,v 1.5 2003/05/16 19:52:37 max Exp $ 29107120Sjulian * $FreeBSD$ 30107120Sjulian */ 31107120Sjulian 32107120Sjulian#include <sys/ioctl.h> 33121054Semax#include <bluetooth.h> 34107120Sjulian#include <errno.h> 35107120Sjulian#include <stdio.h> 36107120Sjulian#include <stdlib.h> 37107120Sjulian#include <string.h> 38107120Sjulian#include "l2control.h" 39107120Sjulian 40107120Sjulian#define SIZE(x) (sizeof((x))/sizeof((x)[0])) 41107120Sjulian 42121054Semax/* Print BDADDR */ 43121054Semaxstatic char * 44121054Semaxbdaddrpr(bdaddr_t const *ba) 45121054Semax{ 46121054Semax extern int numeric_bdaddr; 47121054Semax static char str[24]; 48121054Semax struct hostent *he = NULL; 49121054Semax 50121054Semax if (memcmp(ba, NG_HCI_BDADDR_ANY, sizeof(*ba)) == 0) { 51121054Semax str[0] = '*'; 52121054Semax str[1] = 0; 53121054Semax 54121054Semax return (str); 55121054Semax } 56121054Semax 57121054Semax if (!numeric_bdaddr && 58121054Semax (he = bt_gethostbyaddr((char *)ba, sizeof(*ba), AF_BLUETOOTH)) != NULL) { 59121054Semax strlcpy(str, he->h_name, sizeof(str)); 60121054Semax 61121054Semax return (str); 62121054Semax } 63121054Semax 64121054Semax bt_ntoa(ba, str); 65121054Semax 66121054Semax return (str); 67121054Semax} /* bdaddrpr */ 68121054Semax 69107120Sjulian/* Send read_node_flags command to the node */ 70107120Sjulianstatic int 71107120Sjulianl2cap_read_node_flags(int s, int argc, char **argv) 72107120Sjulian{ 73107120Sjulian struct ng_btsocket_l2cap_raw_node_flags r; 74107120Sjulian 75107120Sjulian memset(&r, 0, sizeof(r)); 76107120Sjulian if (ioctl(s, SIOC_L2CAP_NODE_GET_FLAGS, &r, sizeof(r)) < 0) 77107120Sjulian return (ERROR); 78107120Sjulian 79107120Sjulian fprintf(stdout, "Connectionless traffic flags:\n"); 80107120Sjulian fprintf(stdout, "\tSDP: %s\n", 81107120Sjulian (r.flags & NG_L2CAP_CLT_SDP_DISABLED)? "disabled" : "enabled"); 82107120Sjulian fprintf(stdout, "\tRFCOMM: %s\n", 83107120Sjulian (r.flags & NG_L2CAP_CLT_RFCOMM_DISABLED)? "disabled":"enabled"); 84107120Sjulian fprintf(stdout, "\tTCP: %s\n", 85107120Sjulian (r.flags & NG_L2CAP_CLT_TCP_DISABLED)? "disabled" : "enabled"); 86107120Sjulian 87107120Sjulian return (OK); 88107120Sjulian} /* l2cap_read_node_flags */ 89107120Sjulian 90107120Sjulian/* Send read_debug_level command to the node */ 91107120Sjulianstatic int 92107120Sjulianl2cap_read_debug_level(int s, int argc, char **argv) 93107120Sjulian{ 94107120Sjulian struct ng_btsocket_l2cap_raw_node_debug r; 95107120Sjulian 96107120Sjulian memset(&r, 0, sizeof(r)); 97107120Sjulian if (ioctl(s, SIOC_L2CAP_NODE_GET_DEBUG, &r, sizeof(r)) < 0) 98107120Sjulian return (ERROR); 99107120Sjulian 100107120Sjulian fprintf(stdout, "Debug level: %d\n", r.debug); 101107120Sjulian 102107120Sjulian return (OK); 103107120Sjulian} /* l2cap_read_debug_level */ 104107120Sjulian 105107120Sjulian/* Send write_debug_level command to the node */ 106107120Sjulianstatic int 107107120Sjulianl2cap_write_debug_level(int s, int argc, char **argv) 108107120Sjulian{ 109107120Sjulian struct ng_btsocket_l2cap_raw_node_debug r; 110107120Sjulian 111107120Sjulian memset(&r, 0, sizeof(r)); 112107120Sjulian switch (argc) { 113107120Sjulian case 1: 114107120Sjulian r.debug = atoi(argv[0]); 115107120Sjulian break; 116107120Sjulian 117107120Sjulian default: 118107120Sjulian return (USAGE); 119107120Sjulian } 120107120Sjulian 121107120Sjulian if (ioctl(s, SIOC_L2CAP_NODE_SET_DEBUG, &r, sizeof(r)) < 0) 122107120Sjulian return (ERROR); 123107120Sjulian 124107120Sjulian return (OK); 125107120Sjulian} /* l2cap_write_debug_level */ 126107120Sjulian 127107120Sjulian/* Send read_connection_list command to the node */ 128107120Sjulianstatic int 129107120Sjulianl2cap_read_connection_list(int s, int argc, char **argv) 130107120Sjulian{ 131107120Sjulian static char const * const state[] = { 132107120Sjulian /* NG_L2CAP_CON_CLOSED */ "CLOSED", 133107120Sjulian /* NG_L2CAP_W4_LP_CON_CFM */ "W4_LP_CON_CFM", 134107120Sjulian /* NG_L2CAP_CON_OPEN */ "OPEN" 135107120Sjulian }; 136107120Sjulian#define con_state2str(x) ((x) >= SIZE(state)? "UNKNOWN" : state[(x)]) 137107120Sjulian 138107120Sjulian struct ng_btsocket_l2cap_raw_con_list r; 139107120Sjulian int n, error = OK; 140107120Sjulian 141107120Sjulian memset(&r, 0, sizeof(r)); 142107120Sjulian r.num_connections = NG_L2CAP_MAX_CON_NUM; 143107120Sjulian r.connections = calloc(NG_L2CAP_MAX_CON_NUM, 144107120Sjulian sizeof(ng_l2cap_node_con_ep)); 145107120Sjulian if (r.connections == NULL) { 146107120Sjulian errno = ENOMEM; 147107120Sjulian return (ERROR); 148107120Sjulian } 149107120Sjulian 150107120Sjulian if (ioctl(s, SIOC_L2CAP_NODE_GET_CON_LIST, &r, sizeof(r)) < 0) { 151107120Sjulian error = ERROR; 152107120Sjulian goto out; 153107120Sjulian } 154107120Sjulian 155107120Sjulian fprintf(stdout, "L2CAP connections:\n"); 156107120Sjulian fprintf(stdout, 157107120Sjulian"Remote BD_ADDR Handle Flags Pending State\n"); 158107120Sjulian for (n = 0; n < r.num_connections; n++) { 159107120Sjulian fprintf(stdout, 160121054Semax "%-17.17s " \ 161114879Sjulian "%6d " \ 162114879Sjulian "%c%c%c%c%c " \ 163107120Sjulian "%7d " \ 164107120Sjulian "%s\n", 165121054Semax bdaddrpr(&r.connections[n].remote), 166107120Sjulian r.connections[n].con_handle, 167114879Sjulian ((r.connections[n].flags & NG_L2CAP_CON_OUTGOING)? 'O' : 'I'), 168114879Sjulian ((r.connections[n].flags & NG_L2CAP_CON_LP_TIMO)? 'L' : ' '), 169114879Sjulian ((r.connections[n].flags & NG_L2CAP_CON_AUTO_DISCON_TIMO)? 'D' : ' '), 170114879Sjulian ((r.connections[n].flags & NG_L2CAP_CON_TX)? 'T' : ' '), 171114879Sjulian ((r.connections[n].flags & NG_L2CAP_CON_RX)? 'R' : ' '), 172107120Sjulian r.connections[n].pending, 173107120Sjulian con_state2str(r.connections[n].state)); 174107120Sjulian } 175107120Sjulianout: 176107120Sjulian free(r.connections); 177107120Sjulian 178107120Sjulian return (error); 179107120Sjulian} /* l2cap_read_connection_list */ 180107120Sjulian 181107120Sjulian/* Send read_channel_list command to the node */ 182107120Sjulianstatic int 183107120Sjulianl2cap_read_channel_list(int s, int argc, char **argv) 184107120Sjulian{ 185107120Sjulian static char const * const state[] = { 186107120Sjulian /* NG_L2CAP_CLOSED */ "CLOSED", 187107120Sjulian /* NG_L2CAP_W4_L2CAP_CON_RSP */ "W4_L2CAP_CON_RSP", 188107120Sjulian /* NG_L2CAP_W4_L2CA_CON_RSP */ "W4_L2CA_CON_RSP", 189107120Sjulian /* NG_L2CAP_CONFIG */ "CONFIG", 190107120Sjulian /* NG_L2CAP_OPEN */ "OPEN", 191107120Sjulian /* NG_L2CAP_W4_L2CAP_DISCON_RSP */ "W4_L2CAP_DISCON_RSP", 192107120Sjulian /* NG_L2CAP_W4_L2CA_DISCON_RSP */ "W4_L2CA_DISCON_RSP" 193107120Sjulian }; 194107120Sjulian#define ch_state2str(x) ((x) >= SIZE(state)? "UNKNOWN" : state[(x)]) 195107120Sjulian 196107120Sjulian struct ng_btsocket_l2cap_raw_chan_list r; 197107120Sjulian int n, error = OK; 198107120Sjulian 199107120Sjulian memset(&r, 0, sizeof(r)); 200107120Sjulian r.num_channels = NG_L2CAP_MAX_CHAN_NUM; 201107120Sjulian r.channels = calloc(NG_L2CAP_MAX_CHAN_NUM, 202107120Sjulian sizeof(ng_l2cap_node_chan_ep)); 203107120Sjulian if (r.channels == NULL) { 204107120Sjulian errno = ENOMEM; 205107120Sjulian return (ERROR); 206107120Sjulian } 207107120Sjulian 208107120Sjulian if (ioctl(s, SIOC_L2CAP_NODE_GET_CHAN_LIST, &r, sizeof(r)) < 0) { 209107120Sjulian error = ERROR; 210107120Sjulian goto out; 211107120Sjulian } 212107120Sjulian 213107120Sjulian fprintf(stdout, "L2CAP channels:\n"); 214107120Sjulian fprintf(stdout, 215107120Sjulian"Remote BD_ADDR SCID/ DCID PSM IMTU/ OMTU State\n"); 216107120Sjulian for (n = 0; n < r.num_channels; n++) { 217107120Sjulian fprintf(stdout, 218121054Semax "%-17.17s " \ 219107120Sjulian "%5d/%5d %5d " \ 220107120Sjulian "%5d/%5d " \ 221107120Sjulian "%s\n", 222121054Semax bdaddrpr(&r.channels[n].remote), 223107120Sjulian r.channels[n].scid, r.channels[n].dcid, 224107120Sjulian r.channels[n].psm, r.channels[n].imtu, 225107120Sjulian r.channels[n].omtu, 226107120Sjulian ch_state2str(r.channels[n].state)); 227107120Sjulian } 228107120Sjulianout: 229107120Sjulian free(r.channels); 230107120Sjulian 231107120Sjulian return (error); 232107120Sjulian} /* l2cap_read_channel_list */ 233107120Sjulian 234114879Sjulian/* Send read_auto_disconnect_timeout command to the node */ 235114879Sjulianstatic int 236114879Sjulianl2cap_read_auto_disconnect_timeout(int s, int argc, char **argv) 237114879Sjulian{ 238114879Sjulian struct ng_btsocket_l2cap_raw_auto_discon_timo r; 239114879Sjulian 240114879Sjulian memset(&r, 0, sizeof(r)); 241114879Sjulian if (ioctl(s, SIOC_L2CAP_NODE_GET_AUTO_DISCON_TIMO, &r, sizeof(r)) < 0) 242114879Sjulian return (ERROR); 243114879Sjulian 244114879Sjulian if (r.timeout != 0) 245114879Sjulian fprintf(stdout, "Auto disconnect timeout: %d sec\n", r.timeout); 246114879Sjulian else 247114879Sjulian fprintf(stdout, "Auto disconnect disabled\n"); 248114879Sjulian 249114879Sjulian return (OK); 250114879Sjulian} /* l2cap_read_auto_disconnect_timeout */ 251114879Sjulian 252114879Sjulian/* Send write_auto_disconnect_timeout command to the node */ 253114879Sjulianstatic int 254114879Sjulianl2cap_write_auto_disconnect_timeout(int s, int argc, char **argv) 255114879Sjulian{ 256114879Sjulian struct ng_btsocket_l2cap_raw_auto_discon_timo r; 257114879Sjulian 258114879Sjulian memset(&r, 0, sizeof(r)); 259114879Sjulian switch (argc) { 260114879Sjulian case 1: 261114879Sjulian r.timeout = atoi(argv[0]); 262114879Sjulian break; 263114879Sjulian 264114879Sjulian default: 265114879Sjulian return (USAGE); 266114879Sjulian } 267114879Sjulian 268114879Sjulian if (ioctl(s, SIOC_L2CAP_NODE_SET_AUTO_DISCON_TIMO, &r, sizeof(r)) < 0) 269114879Sjulian return (ERROR); 270114879Sjulian 271114879Sjulian return (OK); 272114879Sjulian} /* l2cap_write_auto_disconnect_timeout */ 273114879Sjulian 274107120Sjulianstruct l2cap_command l2cap_commands[] = { 275107120Sjulian{ 276107120Sjulian"read_node_flags", 277107120Sjulian"Get L2CAP node flags", 278107120Sjulian&l2cap_read_node_flags 279107120Sjulian}, 280107120Sjulian{ 281107120Sjulian"read_debug_level", 282107120Sjulian"Get L2CAP node debug level", 283107120Sjulian&l2cap_read_debug_level 284107120Sjulian}, 285107120Sjulian{ 286107120Sjulian"write_debug_level <level>", 287107120Sjulian"Set L2CAP node debug level", 288107120Sjulian&l2cap_write_debug_level 289107120Sjulian}, 290107120Sjulian{ 291107120Sjulian"read_connection_list", 292107120Sjulian"Read list of the L2CAP connections", 293107120Sjulian&l2cap_read_connection_list 294107120Sjulian}, 295107120Sjulian{ 296107120Sjulian"read_channel_list", 297107120Sjulian"Read list of the L2CAP channels", 298107120Sjulian&l2cap_read_channel_list 299107120Sjulian}, 300107120Sjulian{ 301114879Sjulian"read_auto_disconnect_timeout", 302114879Sjulian"Get L2CAP node auto disconnect timeout (in sec)", 303114879Sjulian&l2cap_read_auto_disconnect_timeout 304114879Sjulian}, 305114879Sjulian{ 306114879Sjulian"write_auto_disconnect_timeout <timeout>", 307114879Sjulian"Set L2CAP node auto disconnect timeout (in sec)", 308114879Sjulian&l2cap_write_auto_disconnect_timeout 309114879Sjulian}, 310114879Sjulian{ 311107120SjulianNULL, 312107120Sjulian}}; 313107120Sjulian 314