1/*-
2 * node.c
3 *
4 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
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 * $FreeBSD: stable/11/usr.sbin/bluetooth/hccontrol/node.c 361153 2020-05-18 08:42:10Z hselasky $
32 */
33
34#include <sys/ioctl.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 "hccontrol.h"
44
45/* Send Read_Node_State command to the node */
46static int
47hci_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 */
61static int
62hci_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 */
71static int
72hci_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 */
86static int
87hci_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 */
108static int
109hci_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 */
136static int
137hci_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 */
151static int
152hci_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 */
172static int
173hci_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 */
194static int
195hci_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 */
204static int
205hci_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 */
214static int
215hci_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
220	memset(&r, 0, sizeof(r));
221	r.num_entries = NG_HCI_MAX_NEIGHBOR_NUM;
222	r.entries = calloc(NG_HCI_MAX_NEIGHBOR_NUM,
223				sizeof(ng_hci_node_neighbor_cache_entry_ep));
224	if (r.entries == NULL) {
225		errno = ENOMEM;
226		return (ERROR);
227	}
228
229	if (ioctl(s, SIOC_HCI_RAW_NODE_GET_NEIGHBOR_CACHE, &r,
230			sizeof(r)) < 0) {
231		error = ERROR;
232		goto out;
233	}
234
235	fprintf(stdout,
236"BD_ADDR           " \
237"Features                " \
238"Clock offset " \
239"Page scan " \
240"Rep. scan\n");
241
242	for (n = 0; n < r.num_entries; n++) {
243		fprintf(stdout,
244"%-17.17s " \
245"%02x %02x %02x %02x %02x %02x %02x %02x " \
246"%#12x " \
247"%#9x " \
248"%#9x\n",
249			hci_bdaddr2str(&r.entries[n].bdaddr),
250			r.entries[n].features[0], r.entries[n].features[1],
251			r.entries[n].features[2], r.entries[n].features[3],
252			r.entries[n].features[4], r.entries[n].features[5],
253			r.entries[n].features[6], r.entries[n].features[7],
254			r.entries[n].clock_offset, r.entries[n].page_scan_mode,
255			r.entries[n].page_scan_rep_mode);
256	}
257out:
258	free(r.entries);
259
260	return (error);
261} /* hci_read_neightbor_cache */
262
263/* Send Read_Connection_List command to the node */
264static int
265hci_read_connection_list(int s, int argc, char **argv)
266{
267	struct ng_btsocket_hci_raw_con_list	r;
268	int					n, error = OK;
269
270	memset(&r, 0, sizeof(r));
271	r.num_connections = NG_HCI_MAX_CON_NUM;
272	r.connections = calloc(NG_HCI_MAX_CON_NUM, sizeof(ng_hci_node_con_ep));
273	if (r.connections == NULL) {
274		errno = ENOMEM;
275		return (ERROR);
276	}
277
278	if (ioctl(s, SIOC_HCI_RAW_NODE_GET_CON_LIST, &r, sizeof(r)) < 0) {
279		error = ERROR;
280		goto out;
281	}
282
283	fprintf(stdout,
284"Remote BD_ADDR    " \
285"Handle " \
286"Type " \
287"Mode " \
288"Role " \
289"Encrypt " \
290"Pending " \
291"Queue " \
292"State\n");
293
294	for (n = 0; n < r.num_connections; n++) {
295		fprintf(stdout,
296"%-17.17s " \
297"%6d " \
298"%4.4s " \
299"%4d " \
300"%4.4s " \
301"%7.7s " \
302"%7d " \
303"%5d " \
304"%s\n",
305			hci_bdaddr2str(&r.connections[n].bdaddr),
306			r.connections[n].con_handle,
307			(r.connections[n].link_type == NG_HCI_LINK_ACL)?
308				"ACL" : "SCO",
309			r.connections[n].mode,
310			(r.connections[n].role == NG_HCI_ROLE_MASTER)?
311				"MAST" : "SLAV",
312			hci_encrypt2str(r.connections[n].encryption_mode, 1),
313			r.connections[n].pending,
314			r.connections[n].queue_len,
315			hci_con_state2str(r.connections[n].state));
316	}
317out:
318	free(r.connections);
319
320	return (error);
321} /* hci_read_connection_list */
322
323/* Send Read_Node_Link_Policy_Settings_Mask command to the node */
324int
325hci_read_node_link_policy_settings_mask(int s, int argc, char **argv)
326{
327	struct ng_btsocket_hci_raw_node_link_policy_mask	r;
328
329	memset(&r, 0, sizeof(r));
330	if (ioctl(s, SIOC_HCI_RAW_NODE_GET_LINK_POLICY_MASK, &r, sizeof(r)) < 0)
331		return (ERROR);
332
333	fprintf(stdout, "Link Policy Settings mask: %#04x\n", r.policy_mask);
334
335	return (OK);
336} /* hci_read_node_link_policy_settings_mask */
337
338/* Send Write_Node_Link_Policy_Settings_Mask command to the node */
339int
340hci_write_node_link_policy_settings_mask(int s, int argc, char **argv)
341{
342	struct ng_btsocket_hci_raw_node_link_policy_mask	r;
343	int							m;
344
345	memset(&r, 0, sizeof(r));
346
347	switch (argc) {
348	case 1:
349		if (sscanf(argv[0], "%x", &m) != 1)
350			return (USAGE);
351
352		r.policy_mask = (m & 0xffff);
353		break;
354
355	default:
356		return (USAGE);
357	}
358
359	if (ioctl(s, SIOC_HCI_RAW_NODE_SET_LINK_POLICY_MASK, &r, sizeof(r)) < 0)
360		return (ERROR);
361
362	return (OK);
363} /* hci_write_node_link_policy_settings_mask */
364
365/* Send Read_Node_Packet_Mask command to the node */
366int
367hci_read_node_packet_mask(int s, int argc, char **argv)
368{
369	struct ng_btsocket_hci_raw_node_packet_mask	r;
370
371	memset(&r, 0, sizeof(r));
372	if (ioctl(s, SIOC_HCI_RAW_NODE_GET_PACKET_MASK, &r, sizeof(r)) < 0)
373		return (ERROR);
374
375	fprintf(stdout, "Packet mask: %#04x\n", r.packet_mask);
376
377	return (OK);
378} /* hci_read_node_packet_mask */
379
380/* Send Write_Node_Packet_Mask command to the node */
381int
382hci_write_node_packet_mask(int s, int argc, char **argv)
383{
384	struct ng_btsocket_hci_raw_node_packet_mask	r;
385	int						m;
386
387	memset(&r, 0, sizeof(r));
388
389	switch (argc) {
390	case 1:
391		if (sscanf(argv[0], "%x", &m) != 1)
392			return (USAGE);
393
394		r.packet_mask = (m & 0xffff);
395		break;
396
397	default:
398		return (USAGE);
399	}
400
401	if (ioctl(s, SIOC_HCI_RAW_NODE_SET_PACKET_MASK, &r, sizeof(r)) < 0)
402		return (ERROR);
403
404	return (OK);
405} /* hci_write_node_packet_mask */
406
407/* Send Read_Node_Role_Switch command to the node */
408int
409hci_read_node_role_switch(int s, int argc, char **argv)
410{
411	struct ng_btsocket_hci_raw_node_role_switch	r;
412
413	memset(&r, 0, sizeof(r));
414	if (ioctl(s, SIOC_HCI_RAW_NODE_GET_ROLE_SWITCH, &r, sizeof(r)) < 0)
415		return (ERROR);
416
417	fprintf(stdout, "Role switch: %d\n", r.role_switch);
418
419	return (OK);
420} /* hci_read_node_role_switch */
421
422/* Send Write_Node_Role_Switch command to the node */
423int
424hci_write_node_role_switch(int s, int argc, char **argv)
425{
426	struct ng_btsocket_hci_raw_node_role_switch	r;
427	int						m;
428
429	memset(&r, 0, sizeof(r));
430
431	switch (argc) {
432	case 1:
433		if (sscanf(argv[0], "%d", &m) != 1)
434			return (USAGE);
435
436		r.role_switch = m? 1 : 0;
437		break;
438
439	default:
440		return (USAGE);
441	}
442
443	if (ioctl(s, SIOC_HCI_RAW_NODE_SET_ROLE_SWITCH, &r, sizeof(r)) < 0)
444		return (ERROR);
445
446	return (OK);
447} /* hci_write_node_role_switch */
448
449/* Send Read_Node_List command to the node */
450int
451hci_read_node_list(int s, int argc, char **argv)
452{
453	struct ng_btsocket_hci_raw_node_list_names	r;
454	int						i;
455
456	r.num_names = MAX_NODE_NUM;
457	r.names = (struct nodeinfo*)calloc(MAX_NODE_NUM, sizeof(struct nodeinfo));
458	if (r.names == NULL)
459		return (ERROR);
460
461	if (ioctl(s, SIOC_HCI_RAW_NODE_LIST_NAMES, &r, sizeof(r)) < 0) {
462		free(r.names);
463		return (ERROR);
464	}
465
466	fprintf(stdout, "Name            ID       Num hooks\n");
467	for (i = 0; i < r.num_names; ++i)
468		fprintf(stdout, "%-15s %08x %9d\n",
469		    r.names[i].name, r.names[i].id, r.names[i].hooks);
470
471	free(r.names);
472
473	return (OK);
474} /* hci_read_node_list */
475
476struct hci_command	node_commands[] = {
477{
478"read_node_state",
479"Get the HCI node state",
480&hci_read_node_state
481},
482{
483"initialize",
484"Initialize the HCI node",
485&hci_node_initialize
486},
487{
488"read_debug_level",
489"Read the HCI node debug level",
490&hci_read_debug_level
491},
492{
493"write_debug_level <level>",
494"Write the HCI node debug level",
495&hci_write_debug_level
496},
497{
498"read_node_buffer_size",
499"Read the HCI node buffer information. This will return current state of the\n"\
500"HCI buffer for the HCI node",
501&hci_read_node_buffer_size
502},
503{
504"read_node_bd_addr",
505"Read the HCI node BD_ADDR. Returns device BD_ADDR as cached by the HCI node",
506&hci_read_node_bd_addr
507},
508{
509"read_node_features",
510"Read the HCI node features. This will return list of supported features as\n" \
511"cached by the HCI node",
512&hci_read_node_features
513},
514{
515"read_node_stat",
516"Read packets and bytes counters for the HCI node",
517&hci_read_node_stat
518},
519{
520"reset_node_stat",
521"Reset packets and bytes counters for the HCI node",
522&hci_reset_node_stat
523},
524{
525"flush_neighbor_cache",
526"Flush content of the HCI node neighbor cache",
527&hci_flush_neighbor_cache
528},
529{
530"read_neighbor_cache",
531"Read content of the HCI node neighbor cache",
532&hci_read_neighbor_cache
533},
534{
535"read_connection_list",
536"Read the baseband connection descriptors list for the HCI node",
537&hci_read_connection_list
538},
539{
540"read_node_link_policy_settings_mask",
541"Read the value of the Link Policy Settinngs mask for the HCI node",
542&hci_read_node_link_policy_settings_mask
543},
544{
545"write_node_link_policy_settings_mask <policy_mask>",
546"Write the value of the Link Policy Settings mask for the HCI node. By default\n" \
547"all supported Link Policy modes (as reported by the local device features) are\n"\
548"enabled. The particular Link Policy mode is enabled if local device supports\n"\
549"it and correspinding bit in the mask was set\n\n" \
550"\t<policy_mask> - xxxx; Link Policy mask\n" \
551"\t\t0x0000 - Disable All LM Modes\n" \
552"\t\t0x0001 - Enable Master Slave Switch\n" \
553"\t\t0x0002 - Enable Hold Mode\n" \
554"\t\t0x0004 - Enable Sniff Mode\n" \
555"\t\t0x0008 - Enable Park Mode\n",
556&hci_write_node_link_policy_settings_mask
557},
558{
559"read_node_packet_mask",
560"Read the value of the Packet mask for the HCI node",
561&hci_read_node_packet_mask
562},
563{
564"write_node_packet_mask <packet_mask>",
565"Write the value of the Packet mask for the HCI node. By default all supported\n" \
566"packet types (as reported by the local device features) are enabled. The\n" \
567"particular packet type is enabled if local device supports it and corresponding\n" \
568"bit in the mask was set\n\n" \
569"\t<packet_mask> - xxxx; packet type mask\n" \
570"" \
571"\t\tACL packets\n" \
572"\t\t-----------\n" \
573"\t\t0x0008 DM1\n" \
574"\t\t0x0010 DH1\n" \
575"\t\t0x0400 DM3\n" \
576"\t\t0x0800 DH3\n" \
577"\t\t0x4000 DM5\n" \
578"\t\t0x8000 DH5\n" \
579"\n" \
580"\t\tSCO packets\n" \
581"\t\t-----------\n" \
582"\t\t0x0020 HV1\n" \
583"\t\t0x0040 HV2\n" \
584"\t\t0x0080 HV3\n",
585&hci_write_node_packet_mask
586},
587{
588"read_node_role_switch",
589"Read the value of the Role Switch parameter for the HCI node",
590&hci_read_node_role_switch
591},
592{
593"write_node_role_switch {0|1}",
594"Write the value of the Role Switch parameter for the HCI node. By default,\n" \
595"if Role Switch is supported, local device will try to perform Role Switch\n" \
596"and become Master on incoming connection. Some devices do not support Role\n" \
597"Switch and thus incoming connections from such devices will fail. Setting\n" \
598"this parameter to zero will prevent Role Switch and thus accepting device\n" \
599"will remain Slave",
600&hci_write_node_role_switch
601},
602{
603"read_node_list",
604"Get a list of HCI nodes, their Netgraph IDs and connected hooks.",
605&hci_read_node_list
606},
607{
608NULL,
609}};
610
611