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 #define L2CAP_SOCKET_CHECKED 34 #include <bluetooth.h> 35 #include <errno.h> 36 #include <stdio.h> 37 #include <stdlib.h> 38 #include <string.h> 39 #include "l2control.h" 40 41 #define SIZE(x) (sizeof((x))/sizeof((x)[0])) 42 43 /* Print BDADDR */ 44 static char * 45 bdaddrpr(bdaddr_t const *ba) 46 { 47 extern int numeric_bdaddr; 48 static char str[24]; 49 struct hostent *he = NULL; 50 51 if (memcmp(ba, NG_HCI_BDADDR_ANY, sizeof(*ba)) == 0) { 52 str[0] = '*'; 53 str[1] = 0; 54 55 return (str); 56 } 57 58 if (!numeric_bdaddr && 59 (he = bt_gethostbyaddr((char *)ba, sizeof(*ba), AF_BLUETOOTH)) != NULL) { 60 strlcpy(str, he->h_name, sizeof(str)); 61 62 return (str); 63 } 64 65 bt_ntoa(ba, str); 66 67 return (str); 68 } /* bdaddrpr */ 69 70 /* Send read_node_flags command to the node */ 71 static int 72 l2cap_read_node_flags(int s, int argc, char **argv) 73 { 74 struct ng_btsocket_l2cap_raw_node_flags r; 75 76 memset(&r, 0, sizeof(r)); 77 if (ioctl(s, SIOC_L2CAP_NODE_GET_FLAGS, &r, sizeof(r)) < 0) 78 return (ERROR); 79 80 fprintf(stdout, "Connectionless traffic flags:\n"); 81 fprintf(stdout, "\tSDP: %s\n", 82 (r.flags & NG_L2CAP_CLT_SDP_DISABLED)? "disabled" : "enabled"); 83 fprintf(stdout, "\tRFCOMM: %s\n", 84 (r.flags & NG_L2CAP_CLT_RFCOMM_DISABLED)? "disabled":"enabled"); 85 fprintf(stdout, "\tTCP: %s\n", 86 (r.flags & NG_L2CAP_CLT_TCP_DISABLED)? "disabled" : "enabled"); 87 88 return (OK); 89 } /* l2cap_read_node_flags */ 90 91 /* Send read_debug_level command to the node */ 92 static int 93 l2cap_read_debug_level(int s, int argc, char **argv) 94 { 95 struct ng_btsocket_l2cap_raw_node_debug r; 96 97 memset(&r, 0, sizeof(r)); 98 if (ioctl(s, SIOC_L2CAP_NODE_GET_DEBUG, &r, sizeof(r)) < 0) 99 return (ERROR); 100 101 fprintf(stdout, "Debug level: %d\n", r.debug); 102 103 return (OK); 104 } /* l2cap_read_debug_level */ 105 106 /* Send write_debug_level command to the node */ 107 static int 108 l2cap_write_debug_level(int s, int argc, char **argv) 109 { 110 struct ng_btsocket_l2cap_raw_node_debug r; 111 112 memset(&r, 0, sizeof(r)); 113 switch (argc) { 114 case 1: 115 r.debug = atoi(argv[0]); 116 break; 117 118 default: 119 return (USAGE); 120 } 121 122 if (ioctl(s, SIOC_L2CAP_NODE_SET_DEBUG, &r, sizeof(r)) < 0) 123 return (ERROR); 124 125 return (OK); 126 } /* l2cap_write_debug_level */ 127 128 /* Send read_connection_list command to the node */ 129 static int 130 l2cap_read_connection_list(int s, int argc, char **argv) 131 { 132 static char const * const state[] = { 133 /* NG_L2CAP_CON_CLOSED */ "CLOSED", 134 /* NG_L2CAP_W4_LP_CON_CFM */ "W4_LP_CON_CFM", 135 /* NG_L2CAP_CON_OPEN */ "OPEN" 136 }; 137 #define con_state2str(x) ((x) >= SIZE(state)? "UNKNOWN" : state[(x)]) 138 139 struct ng_btsocket_l2cap_raw_con_list r; 140 int n, error = OK; 141 142 memset(&r, 0, sizeof(r)); 143 r.num_connections = NG_L2CAP_MAX_CON_NUM; 144 r.connections = calloc(NG_L2CAP_MAX_CON_NUM, 145 sizeof(ng_l2cap_node_con_ep)); 146 if (r.connections == NULL) { 147 errno = ENOMEM; 148 return (ERROR); 149 } 150 151 if (ioctl(s, SIOC_L2CAP_NODE_GET_CON_LIST, &r, sizeof(r)) < 0) { 152 error = ERROR; 153 goto out; 154 } 155 156 fprintf(stdout, "L2CAP connections:\n"); 157 fprintf(stdout, 158 "Remote BD_ADDR Handle Flags Pending State\n"); 159 for (n = 0; n < r.num_connections; n++) { 160 fprintf(stdout, 161 "%-17.17s " \ 162 "%6d " \ 163 "%c%c%c%c%c " \ 164 "%7d " \ 165 "%s\n", 166 bdaddrpr(&r.connections[n].remote), 167 r.connections[n].con_handle, 168 ((r.connections[n].flags & NG_L2CAP_CON_OUTGOING)? 'O' : 'I'), 169 ((r.connections[n].flags & NG_L2CAP_CON_LP_TIMO)? 'L' : ' '), 170 ((r.connections[n].flags & NG_L2CAP_CON_AUTO_DISCON_TIMO)? 'D' : ' '), 171 ((r.connections[n].flags & NG_L2CAP_CON_TX)? 'T' : ' '), 172 ((r.connections[n].flags & NG_L2CAP_CON_RX)? 'R' : ' '), 173 r.connections[n].pending, 174 con_state2str(r.connections[n].state)); 175 } 176 out: 177 free(r.connections); 178 179 return (error); 180 } /* l2cap_read_connection_list */ 181 182 /* Send read_channel_list command to the node */ 183 static int 184 l2cap_read_channel_list(int s, int argc, char **argv) 185 { 186 static char const * const state[] = { 187 /* NG_L2CAP_CLOSED */ "CLOSED", 188 /* NG_L2CAP_W4_L2CAP_CON_RSP */ "W4_L2CAP_CON_RSP", 189 /* NG_L2CAP_W4_L2CA_CON_RSP */ "W4_L2CA_CON_RSP", 190 /* NG_L2CAP_CONFIG */ "CONFIG", 191 /* NG_L2CAP_OPEN */ "OPEN", 192 /* NG_L2CAP_W4_L2CAP_DISCON_RSP */ "W4_L2CAP_DISCON_RSP", 193 /* NG_L2CAP_W4_L2CA_DISCON_RSP */ "W4_L2CA_DISCON_RSP" 194 }; 195 #define ch_state2str(x) ((x) >= SIZE(state)? "UNKNOWN" : state[(x)]) 196 197 struct ng_btsocket_l2cap_raw_chan_list r; 198 int n, error = OK; 199 200 memset(&r, 0, sizeof(r)); 201 r.num_channels = NG_L2CAP_MAX_CHAN_NUM; 202 r.channels = calloc(NG_L2CAP_MAX_CHAN_NUM, 203 sizeof(ng_l2cap_node_chan_ep)); 204 if (r.channels == NULL) { 205 errno = ENOMEM; 206 return (ERROR); 207 } 208 209 if (ioctl(s, SIOC_L2CAP_NODE_GET_CHAN_LIST, &r, sizeof(r)) < 0) { 210 error = ERROR; 211 goto out; 212 } 213 214 fprintf(stdout, "L2CAP channels:\n"); 215 fprintf(stdout, 216 "Remote BD_ADDR SCID/ DCID PSM IMTU/ OMTU State\n"); 217 for (n = 0; n < r.num_channels; n++) { 218 fprintf(stdout, 219 "%-17.17s " \ 220 "%5d/%5d %5d " \ 221 "%5d/%5d " \ 222 "%s\n", 223 bdaddrpr(&r.channels[n].remote), 224 r.channels[n].scid, r.channels[n].dcid, 225 r.channels[n].psm, r.channels[n].imtu, 226 r.channels[n].omtu, 227 ch_state2str(r.channels[n].state)); 228 } 229 out: 230 free(r.channels); 231 232 return (error); 233 } /* l2cap_read_channel_list */ 234 235 /* Send read_auto_disconnect_timeout command to the node */ 236 static int 237 l2cap_read_auto_disconnect_timeout(int s, int argc, char **argv) 238 { 239 struct ng_btsocket_l2cap_raw_auto_discon_timo r; 240 241 memset(&r, 0, sizeof(r)); 242 if (ioctl(s, SIOC_L2CAP_NODE_GET_AUTO_DISCON_TIMO, &r, sizeof(r)) < 0) 243 return (ERROR); 244 245 if (r.timeout != 0) 246 fprintf(stdout, "Auto disconnect timeout: %d sec\n", r.timeout); 247 else 248 fprintf(stdout, "Auto disconnect disabled\n"); 249 250 return (OK); 251 } /* l2cap_read_auto_disconnect_timeout */ 252 253 /* Send write_auto_disconnect_timeout command to the node */ 254 static int 255 l2cap_write_auto_disconnect_timeout(int s, int argc, char **argv) 256 { 257 struct ng_btsocket_l2cap_raw_auto_discon_timo r; 258 259 memset(&r, 0, sizeof(r)); 260 switch (argc) { 261 case 1: 262 r.timeout = atoi(argv[0]); 263 break; 264 265 default: 266 return (USAGE); 267 } 268 269 if (ioctl(s, SIOC_L2CAP_NODE_SET_AUTO_DISCON_TIMO, &r, sizeof(r)) < 0) 270 return (ERROR); 271 272 return (OK); 273 } /* l2cap_write_auto_disconnect_timeout */ 274 275 struct l2cap_command l2cap_commands[] = { 276 { 277 "read_node_flags", 278 "Get L2CAP node flags", 279 &l2cap_read_node_flags 280 }, 281 { 282 "read_debug_level", 283 "Get L2CAP node debug level", 284 &l2cap_read_debug_level 285 }, 286 { 287 "write_debug_level <level>", 288 "Set L2CAP node debug level", 289 &l2cap_write_debug_level 290 }, 291 { 292 "read_connection_list", 293 "Read list of the L2CAP connections", 294 &l2cap_read_connection_list 295 }, 296 { 297 "read_channel_list", 298 "Read list of the L2CAP channels", 299 &l2cap_read_channel_list 300 }, 301 { 302 "read_auto_disconnect_timeout", 303 "Get L2CAP node auto disconnect timeout (in sec)", 304 &l2cap_read_auto_disconnect_timeout 305 }, 306 { 307 "write_auto_disconnect_timeout <timeout>", 308 "Set L2CAP node auto disconnect timeout (in sec)", 309 &l2cap_write_auto_disconnect_timeout 310 }, 311 { 312 NULL, 313 }}; 314 315