l2cap.c revision 107120
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.6 2002/09/04 21:30:40 max Exp $ 29 * $FreeBSD: head/usr.sbin/bluetooth/l2control/l2cap.c 107120 2002-11-20 23:01:59Z julian $ 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 */ 47static int 48l2cap_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, "BD_ADDR: %x:%x:%x:%x:%x:%x\n", 57 r.src.b[5], r.src.b[4], r.src.b[3], 58 r.src.b[2], r.src.b[1], r.src.b[0]); 59 fprintf(stdout, "Connectionless traffic flags:\n"); 60 fprintf(stdout, "\tSDP: %s\n", 61 (r.flags & NG_L2CAP_CLT_SDP_DISABLED)? "disabled" : "enabled"); 62 fprintf(stdout, "\tRFCOMM: %s\n", 63 (r.flags & NG_L2CAP_CLT_RFCOMM_DISABLED)? "disabled":"enabled"); 64 fprintf(stdout, "\tTCP: %s\n", 65 (r.flags & NG_L2CAP_CLT_TCP_DISABLED)? "disabled" : "enabled"); 66 67 return (OK); 68} /* l2cap_read_node_flags */ 69 70/* Send read_debug_level command to the node */ 71static int 72l2cap_read_debug_level(int s, int argc, char **argv) 73{ 74 struct ng_btsocket_l2cap_raw_node_debug r; 75 76 memset(&r, 0, sizeof(r)); 77 if (ioctl(s, SIOC_L2CAP_NODE_GET_DEBUG, &r, sizeof(r)) < 0) 78 return (ERROR); 79 80 fprintf(stdout, "BD_ADDR: %x:%x:%x:%x:%x:%x\n", 81 r.src.b[5], r.src.b[4], r.src.b[3], 82 r.src.b[2], r.src.b[1], r.src.b[0]); 83 fprintf(stdout, "Debug level: %d\n", r.debug); 84 85 return (OK); 86} /* l2cap_read_debug_level */ 87 88/* Send write_debug_level command to the node */ 89static int 90l2cap_write_debug_level(int s, int argc, char **argv) 91{ 92 struct ng_btsocket_l2cap_raw_node_debug r; 93 94 memset(&r, 0, sizeof(r)); 95 switch (argc) { 96 case 1: 97 r.debug = atoi(argv[0]); 98 break; 99 100 default: 101 return (USAGE); 102 } 103 104 if (ioctl(s, SIOC_L2CAP_NODE_SET_DEBUG, &r, sizeof(r)) < 0) 105 return (ERROR); 106 107 return (OK); 108} /* l2cap_write_debug_level */ 109 110/* Send read_connection_list command to the node */ 111static int 112l2cap_read_connection_list(int s, int argc, char **argv) 113{ 114 static char const * const state[] = { 115 /* NG_L2CAP_CON_CLOSED */ "CLOSED", 116 /* NG_L2CAP_W4_LP_CON_CFM */ "W4_LP_CON_CFM", 117 /* NG_L2CAP_CON_OPEN */ "OPEN" 118 }; 119#define con_state2str(x) ((x) >= SIZE(state)? "UNKNOWN" : state[(x)]) 120 121 struct ng_btsocket_l2cap_raw_con_list r; 122 int n, error = OK; 123 124 memset(&r, 0, sizeof(r)); 125 r.num_connections = NG_L2CAP_MAX_CON_NUM; 126 r.connections = calloc(NG_L2CAP_MAX_CON_NUM, 127 sizeof(ng_l2cap_node_con_ep)); 128 if (r.connections == NULL) { 129 errno = ENOMEM; 130 return (ERROR); 131 } 132 133 if (ioctl(s, SIOC_L2CAP_NODE_GET_CON_LIST, &r, sizeof(r)) < 0) { 134 error = ERROR; 135 goto out; 136 } 137 138 fprintf(stdout, "BD_ADDR: %x:%x:%x:%x:%x:%x\n", 139 r.src.b[5], r.src.b[4], r.src.b[3], 140 r.src.b[2], r.src.b[1], r.src.b[0]); 141 fprintf(stdout, "L2CAP connections:\n"); 142 fprintf(stdout, 143"Remote BD_ADDR Handle Flags Pending State\n"); 144 for (n = 0; n < r.num_connections; n++) { 145 fprintf(stdout, 146 "%02x:%02x:%02x:%02x:%02x:%02x " \ 147 " %5d " \ 148 "%2.2s %2.2s " \ 149 "%7d " \ 150 "%s\n", 151 r.connections[n].remote.b[5], 152 r.connections[n].remote.b[4], 153 r.connections[n].remote.b[3], 154 r.connections[n].remote.b[2], 155 r.connections[n].remote.b[1], 156 r.connections[n].remote.b[0], 157 r.connections[n].con_handle, 158 ((r.connections[n].flags & NG_L2CAP_CON_TX)? "TX" : ""), 159 ((r.connections[n].flags & NG_L2CAP_CON_RX)? "RX" : ""), 160 r.connections[n].pending, 161 con_state2str(r.connections[n].state)); 162 } 163out: 164 free(r.connections); 165 166 return (error); 167} /* l2cap_read_connection_list */ 168 169/* Send read_channel_list command to the node */ 170static int 171l2cap_read_channel_list(int s, int argc, char **argv) 172{ 173 static char const * const state[] = { 174 /* NG_L2CAP_CLOSED */ "CLOSED", 175 /* NG_L2CAP_W4_L2CAP_CON_RSP */ "W4_L2CAP_CON_RSP", 176 /* NG_L2CAP_W4_L2CA_CON_RSP */ "W4_L2CA_CON_RSP", 177 /* NG_L2CAP_CONFIG */ "CONFIG", 178 /* NG_L2CAP_OPEN */ "OPEN", 179 /* NG_L2CAP_W4_L2CAP_DISCON_RSP */ "W4_L2CAP_DISCON_RSP", 180 /* NG_L2CAP_W4_L2CA_DISCON_RSP */ "W4_L2CA_DISCON_RSP" 181 }; 182#define ch_state2str(x) ((x) >= SIZE(state)? "UNKNOWN" : state[(x)]) 183 184 struct ng_btsocket_l2cap_raw_chan_list r; 185 int n, error = OK; 186 187 memset(&r, 0, sizeof(r)); 188 r.num_channels = NG_L2CAP_MAX_CHAN_NUM; 189 r.channels = calloc(NG_L2CAP_MAX_CHAN_NUM, 190 sizeof(ng_l2cap_node_chan_ep)); 191 if (r.channels == NULL) { 192 errno = ENOMEM; 193 return (ERROR); 194 } 195 196 if (ioctl(s, SIOC_L2CAP_NODE_GET_CHAN_LIST, &r, sizeof(r)) < 0) { 197 error = ERROR; 198 goto out; 199 } 200 201 fprintf(stdout, "BD_ADDR: %x:%x:%x:%x:%x:%x\n", 202 r.src.b[5], r.src.b[4], r.src.b[3], 203 r.src.b[2], r.src.b[1], r.src.b[0]); 204 fprintf(stdout, "L2CAP channels:\n"); 205 fprintf(stdout, 206"Remote BD_ADDR SCID/ DCID PSM IMTU/ OMTU State\n"); 207 for (n = 0; n < r.num_channels; n++) { 208 fprintf(stdout, 209 "%02x:%02x:%02x:%02x:%02x:%02x " \ 210 "%5d/%5d %5d " \ 211 "%5d/%5d " \ 212 "%s\n", 213 r.channels[n].remote.b[5], r.channels[n].remote.b[4], 214 r.channels[n].remote.b[3], r.channels[n].remote.b[2], 215 r.channels[n].remote.b[1], r.channels[n].remote.b[0], 216 r.channels[n].scid, r.channels[n].dcid, 217 r.channels[n].psm, r.channels[n].imtu, 218 r.channels[n].omtu, 219 ch_state2str(r.channels[n].state)); 220 } 221out: 222 free(r.channels); 223 224 return (error); 225} /* l2cap_read_channel_list */ 226 227struct l2cap_command l2cap_commands[] = { 228{ 229"read_node_flags", 230"Get L2CAP node flags", 231&l2cap_read_node_flags 232}, 233{ 234"read_debug_level", 235"Get L2CAP node debug level", 236&l2cap_read_debug_level 237}, 238{ 239"write_debug_level <level>", 240"Set L2CAP node debug level", 241&l2cap_write_debug_level 242}, 243{ 244"read_connection_list", 245"Read list of the L2CAP connections", 246&l2cap_read_connection_list 247}, 248{ 249"read_channel_list", 250"Read list of the L2CAP channels", 251&l2cap_read_channel_list 252}, 253{ 254NULL, 255}}; 256 257