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 */ 43 static char * 44 bdaddrpr(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 */ 70 static int 71 l2cap_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 */ 91 static int 92 l2cap_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 */ 106 static int 107 l2cap_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 */ 128 static int 129 l2cap_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 } 175 out: 176 free(r.connections); 177 178 return (error); 179 } /* l2cap_read_connection_list */ 180 181 /* Send read_channel_list command to the node */ 182 static int 183 l2cap_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 } 228 out: 229 free(r.channels); 230 231 return (error); 232 } /* l2cap_read_channel_list */ 233 234 /* Send read_auto_disconnect_timeout command to the node */ 235 static int 236 l2cap_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 */ 253 static int 254 l2cap_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 274 struct 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 { 311 NULL, 312 }}; 313 314