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