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