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: stable/10/usr.sbin/bluetooth/hccontrol/node.c 361154 2020-05-18 08:43:05Z hselasky $
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 */
43static int
44hci_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 */
58static int
59hci_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 */
68static int
69hci_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 */
83static int
84hci_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 */
105static int
106hci_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 */
133static int
134hci_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 */
148static int
149hci_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[2048];
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 */
169static int
170hci_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 */
191static int
192hci_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 */
201static int
202hci_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 */
211static int
212hci_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	}
254out:
255	free(r.entries);
256
257	return (error);
258} /* hci_read_neightbor_cache */
259
260/* Send Read_Connection_List command to the node */
261static int
262hci_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	}
314out:
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 */
321int
322hci_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 */
336int
337hci_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 */
363int
364hci_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 */
378int
379hci_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 */
405int
406hci_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 */
420int
421hci_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 */
447int
448hci_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
473struct 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 incoming 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{
605NULL,
606}};
607
608