1 /*
2 * node.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: node.c,v 1.6 2003/07/22 21:14:02 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 <netgraph/ng_message.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <unistd.h>
41 #include "hccontrol.h"
42
43 /* Send Read_Node_State command to the node */
44 static int
hci_read_node_state(int s,int argc,char ** argv)45 hci_read_node_state(int s, int argc, char **argv)
46 {
47 struct ng_btsocket_hci_raw_node_state r;
48
49 memset(&r, 0, sizeof(r));
50 if (ioctl(s, SIOC_HCI_RAW_NODE_GET_STATE, &r, sizeof(r)) < 0)
51 return (ERROR);
52
53 fprintf(stdout, "State: %#x\n", r.state);
54
55 return (OK);
56 } /* hci_read_node_state */
57
58 /* Send Intitialize command to the node */
59 static int
hci_node_initialize(int s,int argc,char ** argv)60 hci_node_initialize(int s, int argc, char **argv)
61 {
62 if (ioctl(s, SIOC_HCI_RAW_NODE_INIT) < 0)
63 return (ERROR);
64
65 return (OK);
66 } /* hci_node_initialize */
67
68 /* Send Read_Debug_Level command to the node */
69 static int
hci_read_debug_level(int s,int argc,char ** argv)70 hci_read_debug_level(int s, int argc, char **argv)
71 {
72 struct ng_btsocket_hci_raw_node_debug r;
73
74 memset(&r, 0, sizeof(r));
75 if (ioctl(s, SIOC_HCI_RAW_NODE_GET_DEBUG, &r, sizeof(r)) < 0)
76 return (ERROR);
77
78 fprintf(stdout, "Debug level: %d\n", r.debug);
79
80 return (OK);
81 } /* hci_read_debug_level */
82
83 /* Send Write_Debug_Level command to the node */
84 static int
hci_write_debug_level(int s,int argc,char ** argv)85 hci_write_debug_level(int s, int argc, char **argv)
86 {
87 struct ng_btsocket_hci_raw_node_debug r;
88
89 memset(&r, 0, sizeof(r));
90 switch (argc) {
91 case 1:
92 r.debug = atoi(argv[0]);
93 break;
94
95 default:
96 return (USAGE);
97 }
98
99 if (ioctl(s, SIOC_HCI_RAW_NODE_SET_DEBUG, &r, sizeof(r)) < 0)
100 return (ERROR);
101
102 return (OK);
103 } /* hci_write_debug_level */
104
105 /* Send Read_Node_Buffer_Size command to the node */
106 static int
hci_read_node_buffer_size(int s,int argc,char ** argv)107 hci_read_node_buffer_size(int s, int argc, char **argv)
108 {
109 struct ng_btsocket_hci_raw_node_buffer r;
110
111 memset(&r, 0, sizeof(r));
112 if (ioctl(s, SIOC_HCI_RAW_NODE_GET_BUFFER, &r, sizeof(r)) < 0)
113 return (ERROR);
114
115 fprintf(stdout, "Number of free command buffers: %d\n",
116 r.buffer.cmd_free);
117 fprintf(stdout, "Max. ACL packet size: %d\n",
118 r.buffer.acl_size);
119 fprintf(stdout, "Numbef of free ACL buffers: %d\n",
120 r.buffer.acl_free);
121 fprintf(stdout, "Total number of ACL buffers: %d\n",
122 r.buffer.acl_pkts);
123 fprintf(stdout, "Max. SCO packet size: %d\n",
124 r.buffer.sco_size);
125 fprintf(stdout, "Numbef of free SCO buffers: %d\n",
126 r.buffer.sco_free);
127 fprintf(stdout, "Total number of SCO buffers: %d\n",
128 r.buffer.sco_pkts);
129
130 return (OK);
131 } /* hci_read_node_buffer_size */
132
133 /* Send Read_Node_BD_ADDR command to the node */
134 static int
hci_read_node_bd_addr(int s,int argc,char ** argv)135 hci_read_node_bd_addr(int s, int argc, char **argv)
136 {
137 struct ng_btsocket_hci_raw_node_bdaddr r;
138
139 memset(&r, 0, sizeof(r));
140 if (ioctl(s, SIOC_HCI_RAW_NODE_GET_BDADDR, &r, sizeof(r)) < 0)
141 return (ERROR);
142
143 fprintf(stdout, "BD_ADDR: %s\n", bt_ntoa(&r.bdaddr, NULL));
144
145 return (OK);
146 } /* hci_read_node_bd_addr */
147
148 /* Send Read_Node_Features command to the node */
149 static int
hci_read_node_features(int s,int argc,char ** argv)150 hci_read_node_features(int s, int argc, char **argv)
151 {
152 struct ng_btsocket_hci_raw_node_features r;
153 int n;
154 char buffer[1024];
155
156 memset(&r, 0, sizeof(r));
157 if (ioctl(s, SIOC_HCI_RAW_NODE_GET_FEATURES, &r, sizeof(r)) < 0)
158 return (ERROR);
159
160 fprintf(stdout, "Features: ");
161 for (n = 0; n < sizeof(r.features)/sizeof(r.features[0]); n++)
162 fprintf(stdout, "%#02x ", r.features[n]);
163 fprintf(stdout, "\n%s\n", hci_features2str(r.features,
164 buffer, sizeof(buffer)));
165
166 return (OK);
167 } /* hci_read_node_features */
168
169 /* Send Read_Node_Stat command to the node */
170 static int
hci_read_node_stat(int s,int argc,char ** argv)171 hci_read_node_stat(int s, int argc, char **argv)
172 {
173 struct ng_btsocket_hci_raw_node_stat r;
174
175 memset(&r, 0, sizeof(r));
176 if (ioctl(s, SIOC_HCI_RAW_NODE_GET_STAT, &r, sizeof(r)) < 0)
177 return (ERROR);
178
179 fprintf(stdout, "Commands sent: %d\n", r.stat.cmd_sent);
180 fprintf(stdout, "Events received: %d\n", r.stat.evnt_recv);
181 fprintf(stdout, "ACL packets received: %d\n", r.stat.acl_recv);
182 fprintf(stdout, "ACL packets sent: %d\n", r.stat.acl_sent);
183 fprintf(stdout, "SCO packets received: %d\n", r.stat.sco_recv);
184 fprintf(stdout, "SCO packets sent: %d\n", r.stat.sco_sent);
185 fprintf(stdout, "Bytes received: %d\n", r.stat.bytes_recv);
186 fprintf(stdout, "Bytes sent: %d\n", r.stat.bytes_sent);
187
188 return (OK);
189 } /* hci_read_node_stat */
190
191 /* Send Reset_Node_Stat command to the node */
192 static int
hci_reset_node_stat(int s,int argc,char ** argv)193 hci_reset_node_stat(int s, int argc, char **argv)
194 {
195 if (ioctl(s, SIOC_HCI_RAW_NODE_RESET_STAT) < 0)
196 return (ERROR);
197
198 return (OK);
199 } /* hci_reset_node_stat */
200
201 /* Send Flush_Neighbor_Cache command to the node */
202 static int
hci_flush_neighbor_cache(int s,int argc,char ** argv)203 hci_flush_neighbor_cache(int s, int argc, char **argv)
204 {
205 if (ioctl(s, SIOC_HCI_RAW_NODE_FLUSH_NEIGHBOR_CACHE) < 0)
206 return (ERROR);
207
208 return (OK);
209 } /* hci_flush_neighbor_cache */
210
211 /* Send Read_Neighbor_Cache command to the node */
212 static int
hci_read_neighbor_cache(int s,int argc,char ** argv)213 hci_read_neighbor_cache(int s, int argc, char **argv)
214 {
215 struct ng_btsocket_hci_raw_node_neighbor_cache r;
216 int n, error = OK;
217
218 memset(&r, 0, sizeof(r));
219 r.num_entries = NG_HCI_MAX_NEIGHBOR_NUM;
220 r.entries = calloc(NG_HCI_MAX_NEIGHBOR_NUM,
221 sizeof(ng_hci_node_neighbor_cache_entry_ep));
222 if (r.entries == NULL) {
223 errno = ENOMEM;
224 return (ERROR);
225 }
226
227 if (ioctl(s, SIOC_HCI_RAW_NODE_GET_NEIGHBOR_CACHE, &r,
228 sizeof(r)) < 0) {
229 error = ERROR;
230 goto out;
231 }
232
233 fprintf(stdout,
234 "BD_ADDR " \
235 "Features " \
236 "Clock offset " \
237 "Page scan " \
238 "Rep. scan\n");
239
240 for (n = 0; n < r.num_entries; n++) {
241 fprintf(stdout,
242 "%-17.17s " \
243 "%02x %02x %02x %02x %02x %02x %02x %02x " \
244 "%#12x " \
245 "%#9x " \
246 "%#9x\n",
247 hci_bdaddr2str(&r.entries[n].bdaddr),
248 r.entries[n].features[0], r.entries[n].features[1],
249 r.entries[n].features[2], r.entries[n].features[3],
250 r.entries[n].features[4], r.entries[n].features[5],
251 r.entries[n].features[6], r.entries[n].features[7],
252 r.entries[n].clock_offset, r.entries[n].page_scan_mode,
253 r.entries[n].page_scan_rep_mode);
254 }
255 out:
256 free(r.entries);
257
258 return (error);
259 } /* hci_read_neightbor_cache */
260
261 /* Send Read_Connection_List command to the node */
262 static int
hci_read_connection_list(int s,int argc,char ** argv)263 hci_read_connection_list(int s, int argc, char **argv)
264 {
265 struct ng_btsocket_hci_raw_con_list r;
266 int n, error = OK;
267
268 memset(&r, 0, sizeof(r));
269 r.num_connections = NG_HCI_MAX_CON_NUM;
270 r.connections = calloc(NG_HCI_MAX_CON_NUM, sizeof(ng_hci_node_con_ep));
271 if (r.connections == NULL) {
272 errno = ENOMEM;
273 return (ERROR);
274 }
275
276 if (ioctl(s, SIOC_HCI_RAW_NODE_GET_CON_LIST, &r, sizeof(r)) < 0) {
277 error = ERROR;
278 goto out;
279 }
280
281 fprintf(stdout,
282 "Remote BD_ADDR " \
283 "Handle " \
284 "Type " \
285 "Mode " \
286 "Role " \
287 "Encrypt " \
288 "Pending " \
289 "Queue " \
290 "State\n");
291
292 for (n = 0; n < r.num_connections; n++) {
293 fprintf(stdout,
294 "%-17.17s " \
295 "%6d " \
296 "%4.4s " \
297 "%4d " \
298 "%4.4s " \
299 "%7.7s " \
300 "%7d " \
301 "%5d " \
302 "%s\n",
303 hci_bdaddr2str(&r.connections[n].bdaddr),
304 r.connections[n].con_handle,
305 (r.connections[n].link_type == NG_HCI_LINK_ACL)?
306 "ACL" : "SCO",
307 r.connections[n].mode,
308 (r.connections[n].role == NG_HCI_ROLE_MASTER)?
309 "MAST" : "SLAV",
310 hci_encrypt2str(r.connections[n].encryption_mode, 1),
311 r.connections[n].pending,
312 r.connections[n].queue_len,
313 hci_con_state2str(r.connections[n].state));
314 }
315 out:
316 free(r.connections);
317
318 return (error);
319 } /* hci_read_connection_list */
320
321 /* Send Read_Node_Link_Policy_Settings_Mask command to the node */
322 int
hci_read_node_link_policy_settings_mask(int s,int argc,char ** argv)323 hci_read_node_link_policy_settings_mask(int s, int argc, char **argv)
324 {
325 struct ng_btsocket_hci_raw_node_link_policy_mask r;
326
327 memset(&r, 0, sizeof(r));
328 if (ioctl(s, SIOC_HCI_RAW_NODE_GET_LINK_POLICY_MASK, &r, sizeof(r)) < 0)
329 return (ERROR);
330
331 fprintf(stdout, "Link Policy Settings mask: %#04x\n", r.policy_mask);
332
333 return (OK);
334 } /* hci_read_node_link_policy_settings_mask */
335
336 /* Send Write_Node_Link_Policy_Settings_Mask command to the node */
337 int
hci_write_node_link_policy_settings_mask(int s,int argc,char ** argv)338 hci_write_node_link_policy_settings_mask(int s, int argc, char **argv)
339 {
340 struct ng_btsocket_hci_raw_node_link_policy_mask r;
341 int m;
342
343 memset(&r, 0, sizeof(r));
344
345 switch (argc) {
346 case 1:
347 if (sscanf(argv[0], "%x", &m) != 1)
348 return (USAGE);
349
350 r.policy_mask = (m & 0xffff);
351 break;
352
353 default:
354 return (USAGE);
355 }
356
357 if (ioctl(s, SIOC_HCI_RAW_NODE_SET_LINK_POLICY_MASK, &r, sizeof(r)) < 0)
358 return (ERROR);
359
360 return (OK);
361 } /* hci_write_node_link_policy_settings_mask */
362
363 /* Send Read_Node_Packet_Mask command to the node */
364 int
hci_read_node_packet_mask(int s,int argc,char ** argv)365 hci_read_node_packet_mask(int s, int argc, char **argv)
366 {
367 struct ng_btsocket_hci_raw_node_packet_mask r;
368
369 memset(&r, 0, sizeof(r));
370 if (ioctl(s, SIOC_HCI_RAW_NODE_GET_PACKET_MASK, &r, sizeof(r)) < 0)
371 return (ERROR);
372
373 fprintf(stdout, "Packet mask: %#04x\n", r.packet_mask);
374
375 return (OK);
376 } /* hci_read_node_packet_mask */
377
378 /* Send Write_Node_Packet_Mask command to the node */
379 int
hci_write_node_packet_mask(int s,int argc,char ** argv)380 hci_write_node_packet_mask(int s, int argc, char **argv)
381 {
382 struct ng_btsocket_hci_raw_node_packet_mask r;
383 int m;
384
385 memset(&r, 0, sizeof(r));
386
387 switch (argc) {
388 case 1:
389 if (sscanf(argv[0], "%x", &m) != 1)
390 return (USAGE);
391
392 r.packet_mask = (m & 0xffff);
393 break;
394
395 default:
396 return (USAGE);
397 }
398
399 if (ioctl(s, SIOC_HCI_RAW_NODE_SET_PACKET_MASK, &r, sizeof(r)) < 0)
400 return (ERROR);
401
402 return (OK);
403 } /* hci_write_node_packet_mask */
404
405 /* Send Read_Node_Role_Switch command to the node */
406 int
hci_read_node_role_switch(int s,int argc,char ** argv)407 hci_read_node_role_switch(int s, int argc, char **argv)
408 {
409 struct ng_btsocket_hci_raw_node_role_switch r;
410
411 memset(&r, 0, sizeof(r));
412 if (ioctl(s, SIOC_HCI_RAW_NODE_GET_ROLE_SWITCH, &r, sizeof(r)) < 0)
413 return (ERROR);
414
415 fprintf(stdout, "Role switch: %d\n", r.role_switch);
416
417 return (OK);
418 } /* hci_read_node_role_switch */
419
420 /* Send Write_Node_Role_Switch command to the node */
421 int
hci_write_node_role_switch(int s,int argc,char ** argv)422 hci_write_node_role_switch(int s, int argc, char **argv)
423 {
424 struct ng_btsocket_hci_raw_node_role_switch r;
425 int m;
426
427 memset(&r, 0, sizeof(r));
428
429 switch (argc) {
430 case 1:
431 if (sscanf(argv[0], "%d", &m) != 1)
432 return (USAGE);
433
434 r.role_switch = m? 1 : 0;
435 break;
436
437 default:
438 return (USAGE);
439 }
440
441 if (ioctl(s, SIOC_HCI_RAW_NODE_SET_ROLE_SWITCH, &r, sizeof(r)) < 0)
442 return (ERROR);
443
444 return (OK);
445 } /* hci_write_node_role_switch */
446
447 /* Send Read_Node_List command to the node */
448 int
hci_read_node_list(int s,int argc,char ** argv)449 hci_read_node_list(int s, int argc, char **argv)
450 {
451 struct ng_btsocket_hci_raw_node_list_names r;
452 int i;
453
454 r.num_names = MAX_NODE_NUM;
455 r.names = (struct nodeinfo*)calloc(MAX_NODE_NUM, sizeof(struct nodeinfo));
456 if (r.names == NULL)
457 return (ERROR);
458
459 if (ioctl(s, SIOC_HCI_RAW_NODE_LIST_NAMES, &r, sizeof(r)) < 0) {
460 free(r.names);
461 return (ERROR);
462 }
463
464 fprintf(stdout, "Name ID Num hooks\n");
465 for (i = 0; i < r.num_names; ++i)
466 fprintf(stdout, "%-15s %08x %9d\n",
467 r.names[i].name, r.names[i].id, r.names[i].hooks);
468
469 free(r.names);
470
471 return (OK);
472 } /* hci_read_node_list */
473
474 struct hci_command node_commands[] = {
475 {
476 "read_node_state",
477 "Get the HCI node state",
478 &hci_read_node_state
479 },
480 {
481 "initialize",
482 "Initialize the HCI node",
483 &hci_node_initialize
484 },
485 {
486 "read_debug_level",
487 "Read the HCI node debug level",
488 &hci_read_debug_level
489 },
490 {
491 "write_debug_level <level>",
492 "Write the HCI node debug level",
493 &hci_write_debug_level
494 },
495 {
496 "read_node_buffer_size",
497 "Read the HCI node buffer information. This will return current state of the\n"\
498 "HCI buffer for the HCI node",
499 &hci_read_node_buffer_size
500 },
501 {
502 "read_node_bd_addr",
503 "Read the HCI node BD_ADDR. Returns device BD_ADDR as cached by the HCI node",
504 &hci_read_node_bd_addr
505 },
506 {
507 "read_node_features",
508 "Read the HCI node features. This will return list of supported features as\n" \
509 "cached by the HCI node",
510 &hci_read_node_features
511 },
512 {
513 "read_node_stat",
514 "Read packets and bytes counters for the HCI node",
515 &hci_read_node_stat
516 },
517 {
518 "reset_node_stat",
519 "Reset packets and bytes counters for the HCI node",
520 &hci_reset_node_stat
521 },
522 {
523 "flush_neighbor_cache",
524 "Flush content of the HCI node neighbor cache",
525 &hci_flush_neighbor_cache
526 },
527 {
528 "read_neighbor_cache",
529 "Read content of the HCI node neighbor cache",
530 &hci_read_neighbor_cache
531 },
532 {
533 "read_connection_list",
534 "Read the baseband connection descriptors list for the HCI node",
535 &hci_read_connection_list
536 },
537 {
538 "read_node_link_policy_settings_mask",
539 "Read the value of the Link Policy Settinngs mask for the HCI node",
540 &hci_read_node_link_policy_settings_mask
541 },
542 {
543 "write_node_link_policy_settings_mask <policy_mask>",
544 "Write the value of the Link Policy Settings mask for the HCI node. By default\n" \
545 "all supported Link Policy modes (as reported by the local device features) are\n"\
546 "enabled. The particular Link Policy mode is enabled if local device supports\n"\
547 "it and correspinding bit in the mask was set\n\n" \
548 "\t<policy_mask> - xxxx; Link Policy mask\n" \
549 "\t\t0x0000 - Disable All LM Modes\n" \
550 "\t\t0x0001 - Enable Master Slave Switch\n" \
551 "\t\t0x0002 - Enable Hold Mode\n" \
552 "\t\t0x0004 - Enable Sniff Mode\n" \
553 "\t\t0x0008 - Enable Park Mode\n",
554 &hci_write_node_link_policy_settings_mask
555 },
556 {
557 "read_node_packet_mask",
558 "Read the value of the Packet mask for the HCI node",
559 &hci_read_node_packet_mask
560 },
561 {
562 "write_node_packet_mask <packet_mask>",
563 "Write the value of the Packet mask for the HCI node. By default all supported\n" \
564 "packet types (as reported by the local device features) are enabled. The\n" \
565 "particular packet type is enabled if local device supports it and corresponding\n" \
566 "bit in the mask was set\n\n" \
567 "\t<packet_mask> - xxxx; packet type mask\n" \
568 "" \
569 "\t\tACL packets\n" \
570 "\t\t-----------\n" \
571 "\t\t0x0008 DM1\n" \
572 "\t\t0x0010 DH1\n" \
573 "\t\t0x0400 DM3\n" \
574 "\t\t0x0800 DH3\n" \
575 "\t\t0x4000 DM5\n" \
576 "\t\t0x8000 DH5\n" \
577 "\n" \
578 "\t\tSCO packets\n" \
579 "\t\t-----------\n" \
580 "\t\t0x0020 HV1\n" \
581 "\t\t0x0040 HV2\n" \
582 "\t\t0x0080 HV3\n",
583 &hci_write_node_packet_mask
584 },
585 {
586 "read_node_role_switch",
587 "Read the value of the Role Switch parameter for the HCI node",
588 &hci_read_node_role_switch
589 },
590 {
591 "write_node_role_switch {0|1}",
592 "Write the value of the Role Switch parameter for the HCI node. By default,\n" \
593 "if Role Switch is supported, local device will try to perform Role Switch\n" \
594 "and become Master on incoming connection. Some devices do not support Role\n" \
595 "Switch and thus incomming connections from such devices will fail. Setting\n" \
596 "this parameter to zero will prevent Role Switch and thus accepting device\n" \
597 "will remain Slave",
598 &hci_write_node_role_switch
599 },
600 {
601 "read_node_list",
602 "Get a list of HCI nodes, their Netgraph IDs and connected hooks.",
603 &hci_read_node_list
604 },
605 {
606 NULL,
607 }};
608
609