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