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