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