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