1/* 2 * l2cap.c 3 * 4 * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 * $Id: l2cap.c,v 1.5 2003/05/16 19:52:37 max Exp $ 29 * $FreeBSD$ 30 */ 31 32#include <sys/ioctl.h> 33#include <bluetooth.h> 34#include <errno.h> 35#include <stdio.h> 36#include <stdlib.h> 37#include <string.h> 38#include "l2control.h" 39 40#define SIZE(x) (sizeof((x))/sizeof((x)[0])) 41 42/* Print BDADDR */ 43static char * 44bdaddrpr(bdaddr_t const *ba) 45{ 46 extern int numeric_bdaddr; 47 static char str[24]; 48 struct hostent *he = NULL; 49 50 if (memcmp(ba, NG_HCI_BDADDR_ANY, sizeof(*ba)) == 0) { 51 str[0] = '*'; 52 str[1] = 0; 53 54 return (str); 55 } 56 57 if (!numeric_bdaddr && 58 (he = bt_gethostbyaddr((char *)ba, sizeof(*ba), AF_BLUETOOTH)) != NULL) { 59 strlcpy(str, he->h_name, sizeof(str)); 60 61 return (str); 62 } 63 64 bt_ntoa(ba, str); 65 66 return (str); 67} /* bdaddrpr */ 68 69/* Send read_node_flags command to the node */ 70static int 71l2cap_read_node_flags(int s, int argc, char **argv) 72{ 73 struct ng_btsocket_l2cap_raw_node_flags r; 74 75 memset(&r, 0, sizeof(r)); 76 if (ioctl(s, SIOC_L2CAP_NODE_GET_FLAGS, &r, sizeof(r)) < 0) 77 return (ERROR); 78 79 fprintf(stdout, "Connectionless traffic flags:\n"); 80 fprintf(stdout, "\tSDP: %s\n", 81 (r.flags & NG_L2CAP_CLT_SDP_DISABLED)? "disabled" : "enabled"); 82 fprintf(stdout, "\tRFCOMM: %s\n", 83 (r.flags & NG_L2CAP_CLT_RFCOMM_DISABLED)? "disabled":"enabled"); 84 fprintf(stdout, "\tTCP: %s\n", 85 (r.flags & NG_L2CAP_CLT_TCP_DISABLED)? "disabled" : "enabled"); 86 87 return (OK); 88} /* l2cap_read_node_flags */ 89 90/* Send read_debug_level command to the node */ 91static int 92l2cap_read_debug_level(int s, int argc, char **argv) 93{ 94 struct ng_btsocket_l2cap_raw_node_debug r; 95 96 memset(&r, 0, sizeof(r)); 97 if (ioctl(s, SIOC_L2CAP_NODE_GET_DEBUG, &r, sizeof(r)) < 0) 98 return (ERROR); 99 100 fprintf(stdout, "Debug level: %d\n", r.debug); 101 102 return (OK); 103} /* l2cap_read_debug_level */ 104 105/* Send write_debug_level command to the node */ 106static int 107l2cap_write_debug_level(int s, int argc, char **argv) 108{ 109 struct ng_btsocket_l2cap_raw_node_debug r; 110 111 memset(&r, 0, sizeof(r)); 112 switch (argc) { 113 case 1: 114 r.debug = atoi(argv[0]); 115 break; 116 117 default: 118 return (USAGE); 119 } 120 121 if (ioctl(s, SIOC_L2CAP_NODE_SET_DEBUG, &r, sizeof(r)) < 0) 122 return (ERROR); 123 124 return (OK); 125} /* l2cap_write_debug_level */ 126 127/* Send read_connection_list command to the node */ 128static int 129l2cap_read_connection_list(int s, int argc, char **argv) 130{ 131 static char const * const state[] = { 132 /* NG_L2CAP_CON_CLOSED */ "CLOSED", 133 /* NG_L2CAP_W4_LP_CON_CFM */ "W4_LP_CON_CFM", 134 /* NG_L2CAP_CON_OPEN */ "OPEN" 135 }; 136#define con_state2str(x) ((x) >= SIZE(state)? "UNKNOWN" : state[(x)]) 137 138 struct ng_btsocket_l2cap_raw_con_list r; 139 int n, error = OK; 140 141 memset(&r, 0, sizeof(r)); 142 r.num_connections = NG_L2CAP_MAX_CON_NUM; 143 r.connections = calloc(NG_L2CAP_MAX_CON_NUM, 144 sizeof(ng_l2cap_node_con_ep)); 145 if (r.connections == NULL) { 146 errno = ENOMEM; 147 return (ERROR); 148 } 149 150 if (ioctl(s, SIOC_L2CAP_NODE_GET_CON_LIST, &r, sizeof(r)) < 0) { 151 error = ERROR; 152 goto out; 153 } 154 155 fprintf(stdout, "L2CAP connections:\n"); 156 fprintf(stdout, 157"Remote BD_ADDR Handle Flags Pending State\n"); 158 for (n = 0; n < r.num_connections; n++) { 159 fprintf(stdout, 160 "%-17.17s " \ 161 "%6d " \ 162 "%c%c%c%c%c " \ 163 "%7d " \ 164 "%s\n", 165 bdaddrpr(&r.connections[n].remote), 166 r.connections[n].con_handle, 167 ((r.connections[n].flags & NG_L2CAP_CON_OUTGOING)? 'O' : 'I'), 168 ((r.connections[n].flags & NG_L2CAP_CON_LP_TIMO)? 'L' : ' '), 169 ((r.connections[n].flags & NG_L2CAP_CON_AUTO_DISCON_TIMO)? 'D' : ' '), 170 ((r.connections[n].flags & NG_L2CAP_CON_TX)? 'T' : ' '), 171 ((r.connections[n].flags & NG_L2CAP_CON_RX)? 'R' : ' '), 172 r.connections[n].pending, 173 con_state2str(r.connections[n].state)); 174 } 175out: 176 free(r.connections); 177 178 return (error); 179} /* l2cap_read_connection_list */ 180 181/* Send read_channel_list command to the node */ 182static int 183l2cap_read_channel_list(int s, int argc, char **argv) 184{ 185 static char const * const state[] = { 186 /* NG_L2CAP_CLOSED */ "CLOSED", 187 /* NG_L2CAP_W4_L2CAP_CON_RSP */ "W4_L2CAP_CON_RSP", 188 /* NG_L2CAP_W4_L2CA_CON_RSP */ "W4_L2CA_CON_RSP", 189 /* NG_L2CAP_CONFIG */ "CONFIG", 190 /* NG_L2CAP_OPEN */ "OPEN", 191 /* NG_L2CAP_W4_L2CAP_DISCON_RSP */ "W4_L2CAP_DISCON_RSP", 192 /* NG_L2CAP_W4_L2CA_DISCON_RSP */ "W4_L2CA_DISCON_RSP" 193 }; 194#define ch_state2str(x) ((x) >= SIZE(state)? "UNKNOWN" : state[(x)]) 195 196 struct ng_btsocket_l2cap_raw_chan_list r; 197 int n, error = OK; 198 199 memset(&r, 0, sizeof(r)); 200 r.num_channels = NG_L2CAP_MAX_CHAN_NUM; 201 r.channels = calloc(NG_L2CAP_MAX_CHAN_NUM, 202 sizeof(ng_l2cap_node_chan_ep)); 203 if (r.channels == NULL) { 204 errno = ENOMEM; 205 return (ERROR); 206 } 207 208 if (ioctl(s, SIOC_L2CAP_NODE_GET_CHAN_LIST, &r, sizeof(r)) < 0) { 209 error = ERROR; 210 goto out; 211 } 212 213 fprintf(stdout, "L2CAP channels:\n"); 214 fprintf(stdout, 215"Remote BD_ADDR SCID/ DCID PSM IMTU/ OMTU State\n"); 216 for (n = 0; n < r.num_channels; n++) { 217 fprintf(stdout, 218 "%-17.17s " \ 219 "%5d/%5d %5d " \ 220 "%5d/%5d " \ 221 "%s\n", 222 bdaddrpr(&r.channels[n].remote), 223 r.channels[n].scid, r.channels[n].dcid, 224 r.channels[n].psm, r.channels[n].imtu, 225 r.channels[n].omtu, 226 ch_state2str(r.channels[n].state)); 227 } 228out: 229 free(r.channels); 230 231 return (error); 232} /* l2cap_read_channel_list */ 233 234/* Send read_auto_disconnect_timeout command to the node */ 235static int 236l2cap_read_auto_disconnect_timeout(int s, int argc, char **argv) 237{ 238 struct ng_btsocket_l2cap_raw_auto_discon_timo r; 239 240 memset(&r, 0, sizeof(r)); 241 if (ioctl(s, SIOC_L2CAP_NODE_GET_AUTO_DISCON_TIMO, &r, sizeof(r)) < 0) 242 return (ERROR); 243 244 if (r.timeout != 0) 245 fprintf(stdout, "Auto disconnect timeout: %d sec\n", r.timeout); 246 else 247 fprintf(stdout, "Auto disconnect disabled\n"); 248 249 return (OK); 250} /* l2cap_read_auto_disconnect_timeout */ 251 252/* Send write_auto_disconnect_timeout command to the node */ 253static int 254l2cap_write_auto_disconnect_timeout(int s, int argc, char **argv) 255{ 256 struct ng_btsocket_l2cap_raw_auto_discon_timo r; 257 258 memset(&r, 0, sizeof(r)); 259 switch (argc) { 260 case 1: 261 r.timeout = atoi(argv[0]); 262 break; 263 264 default: 265 return (USAGE); 266 } 267 268 if (ioctl(s, SIOC_L2CAP_NODE_SET_AUTO_DISCON_TIMO, &r, sizeof(r)) < 0) 269 return (ERROR); 270 271 return (OK); 272} /* l2cap_write_auto_disconnect_timeout */ 273 274struct l2cap_command l2cap_commands[] = { 275{ 276"read_node_flags", 277"Get L2CAP node flags", 278&l2cap_read_node_flags 279}, 280{ 281"read_debug_level", 282"Get L2CAP node debug level", 283&l2cap_read_debug_level 284}, 285{ 286"write_debug_level <level>", 287"Set L2CAP node debug level", 288&l2cap_write_debug_level 289}, 290{ 291"read_connection_list", 292"Read list of the L2CAP connections", 293&l2cap_read_connection_list 294}, 295{ 296"read_channel_list", 297"Read list of the L2CAP channels", 298&l2cap_read_channel_list 299}, 300{ 301"read_auto_disconnect_timeout", 302"Get L2CAP node auto disconnect timeout (in sec)", 303&l2cap_read_auto_disconnect_timeout 304}, 305{ 306"write_auto_disconnect_timeout <timeout>", 307"Set L2CAP node auto disconnect timeout (in sec)", 308&l2cap_write_auto_disconnect_timeout 309}, 310{ 311NULL, 312}}; 313 314