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 */
47static int
48hci_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 */
62static int
63hci_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 */
72static int
73hci_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 */
87static int
88hci_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 */
109static int
110hci_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 */
137static int
138hci_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 */
152static int
153hci_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 */
173static int
174hci_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 */
195static int
196hci_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 */
205static int
206hci_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 */
215static int
216hci_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	}
267out:
268	free(r.entries);
269
270	return (error);
271} /* hci_read_neightbor_cache */
272
273/* Send Read_Connection_List command to the node */
274static int
275hci_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	}
327out:
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 */
334int
335hci_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 */
349int
350hci_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 */
376int
377hci_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 */
391int
392hci_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 */
418int
419hci_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 */
433int
434hci_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 */
460int
461hci_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
486struct 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{
618NULL,
619}};
620
621