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