xref: /freebsd/usr.sbin/bluetooth/hccontrol/node.c (revision beb45c4f)
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 incoming 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