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