1bcff2d91STakanori Watanabe /* 2bcff2d91STakanori Watanabe * le.c 3bcff2d91STakanori Watanabe * 4bcff2d91STakanori Watanabe * Copyright (c) 2015 Takanori Watanabe <takawata@freebsd.org> 5bcff2d91STakanori Watanabe * All rights reserved. 6bcff2d91STakanori Watanabe * 7bcff2d91STakanori Watanabe * Redistribution and use in source and binary forms, with or without 8bcff2d91STakanori Watanabe * modification, are permitted provided that the following conditions 9bcff2d91STakanori Watanabe * are met: 10bcff2d91STakanori Watanabe * 1. Redistributions of source code must retain the above copyright 11bcff2d91STakanori Watanabe * notice, this list of conditions and the following disclaimer. 12bcff2d91STakanori Watanabe * 2. Redistributions in binary form must reproduce the above copyright 13bcff2d91STakanori Watanabe * notice, this list of conditions and the following disclaimer in the 14bcff2d91STakanori Watanabe * documentation and/or other materials provided with the distribution. 15bcff2d91STakanori Watanabe * 16bcff2d91STakanori Watanabe * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17bcff2d91STakanori Watanabe * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18bcff2d91STakanori Watanabe * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19bcff2d91STakanori Watanabe * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20bcff2d91STakanori Watanabe * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21bcff2d91STakanori Watanabe * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22bcff2d91STakanori Watanabe * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23bcff2d91STakanori Watanabe * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24bcff2d91STakanori Watanabe * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25bcff2d91STakanori Watanabe * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26bcff2d91STakanori Watanabe * SUCH DAMAGE. 27bcff2d91STakanori Watanabe * 28bcff2d91STakanori Watanabe * $Id: hccontrol.c,v 1.5 2003/09/05 00:38:24 max Exp $ 29bcff2d91STakanori Watanabe * $FreeBSD$ 30bcff2d91STakanori Watanabe */ 31bcff2d91STakanori Watanabe 32bcff2d91STakanori Watanabe #include <sys/types.h> 33bcff2d91STakanori Watanabe #include <sys/ioctl.h> 34bcff2d91STakanori Watanabe #include <sys/sysctl.h> 35bcff2d91STakanori Watanabe #include <sys/select.h> 36bcff2d91STakanori Watanabe #include <assert.h> 378907f744SAlan Somers #include <bitstring.h> 38bcff2d91STakanori Watanabe #include <err.h> 39bcff2d91STakanori Watanabe #include <errno.h> 40bcff2d91STakanori Watanabe #include <netgraph/ng_message.h> 41bcff2d91STakanori Watanabe #include <errno.h> 429287f06dSTakanori Watanabe #include <stdbool.h> 43bcff2d91STakanori Watanabe #include <stdio.h> 44bcff2d91STakanori Watanabe #include <stdlib.h> 45bcff2d91STakanori Watanabe #include <string.h> 46bcff2d91STakanori Watanabe #include <unistd.h> 474cae2db2STakanori Watanabe #include <stdint.h> 48bcff2d91STakanori Watanabe #define L2CAP_SOCKET_CHECKED 49bcff2d91STakanori Watanabe #include <bluetooth.h> 50bcff2d91STakanori Watanabe #include "hccontrol.h" 519c3471faSMarcelo Araujo 52bcff2d91STakanori Watanabe static int le_set_scan_param(int s, int argc, char *argv[]); 53bcff2d91STakanori Watanabe static int le_set_scan_enable(int s, int argc, char *argv[]); 54bcff2d91STakanori Watanabe static int parse_param(int argc, char *argv[], char *buf, int *len); 55bcff2d91STakanori Watanabe static int le_set_scan_response(int s, int argc, char *argv[]); 5621eefd31SHans Petter Selasky static int le_read_supported_states(int s, int argc, char *argv[]); 57bcff2d91STakanori Watanabe static int le_read_local_supported_features(int s, int argc ,char *argv[]); 58bcff2d91STakanori Watanabe static int set_le_event_mask(int s, uint64_t mask); 59bcff2d91STakanori Watanabe static int set_event_mask(int s, uint64_t mask); 60bcff2d91STakanori Watanabe static int le_enable(int s, int argc, char *argv[]); 61c3f60abcSHans Petter Selasky static int le_set_advertising_enable(int s, int argc, char *argv[]); 62c3f60abcSHans Petter Selasky static int le_set_advertising_param(int s, int argc, char *argv[]); 63c3f60abcSHans Petter Selasky static int le_read_advertising_channel_tx_power(int s, int argc, char *argv[]); 649287f06dSTakanori Watanabe static int le_scan(int s, int argc, char *argv[]); 659287f06dSTakanori Watanabe static void handle_le_event(ng_hci_event_pkt_t* e, bool verbose); 6611fb4bdbSTakanori Watanabe static int le_read_white_list_size(int s, int argc, char *argv[]); 6711fb4bdbSTakanori Watanabe static int le_clear_white_list(int s, int argc, char *argv[]); 6811fb4bdbSTakanori Watanabe static int le_add_device_to_white_list(int s, int argc, char *argv[]); 6911fb4bdbSTakanori Watanabe static int le_remove_device_from_white_list(int s, int argc, char *argv[]); 703ac41cceSTakanori Watanabe static int le_connect(int s, int argc, char *argv[]); 713ac41cceSTakanori Watanabe static void handle_le_connection_event(ng_hci_event_pkt_t* e, bool verbose); 72bcff2d91STakanori Watanabe 739c3471faSMarcelo Araujo static int 749c3471faSMarcelo Araujo le_set_scan_param(int s, int argc, char *argv[]) 75bcff2d91STakanori Watanabe { 76bcff2d91STakanori Watanabe int type; 77bcff2d91STakanori Watanabe int interval; 78bcff2d91STakanori Watanabe int window; 79bcff2d91STakanori Watanabe int adrtype; 80bcff2d91STakanori Watanabe int policy; 81eb2aebeaSTakanori Watanabe int n; 82bcff2d91STakanori Watanabe 83bcff2d91STakanori Watanabe ng_hci_le_set_scan_parameters_cp cp; 84bcff2d91STakanori Watanabe ng_hci_le_set_scan_parameters_rp rp; 85bcff2d91STakanori Watanabe 869c3471faSMarcelo Araujo if (argc != 5) 87eb2aebeaSTakanori Watanabe return (USAGE); 88bcff2d91STakanori Watanabe 899c3471faSMarcelo Araujo if (strcmp(argv[0], "active") == 0) 90bcff2d91STakanori Watanabe type = 1; 919c3471faSMarcelo Araujo else if (strcmp(argv[0], "passive") == 0) 92bcff2d91STakanori Watanabe type = 0; 939c3471faSMarcelo Araujo else 94eb2aebeaSTakanori Watanabe return (USAGE); 95bcff2d91STakanori Watanabe 96bcff2d91STakanori Watanabe interval = (int)(atof(argv[1])/0.625); 97bcff2d91STakanori Watanabe interval = (interval < 4)? 4: interval; 98bcff2d91STakanori Watanabe window = (int)(atof(argv[2])/0.625); 99bcff2d91STakanori Watanabe window = (window < 4) ? 4 : interval; 100bcff2d91STakanori Watanabe 1019c3471faSMarcelo Araujo if (strcmp(argv[3], "public") == 0) 102bcff2d91STakanori Watanabe adrtype = 0; 10305e526fbSTakanori Watanabe else if (strcmp(argv[3], "random") == 0) 104bcff2d91STakanori Watanabe adrtype = 1; 1059c3471faSMarcelo Araujo else 106eb2aebeaSTakanori Watanabe return (USAGE); 107bcff2d91STakanori Watanabe 1089c3471faSMarcelo Araujo if (strcmp(argv[4], "all") == 0) 109bcff2d91STakanori Watanabe policy = 0; 1109c3471faSMarcelo Araujo else if (strcmp(argv[4], "whitelist") == 0) 111bcff2d91STakanori Watanabe policy = 1; 1129c3471faSMarcelo Araujo else 113eb2aebeaSTakanori Watanabe return (USAGE); 114bcff2d91STakanori Watanabe 115bcff2d91STakanori Watanabe cp.le_scan_type = type; 116bcff2d91STakanori Watanabe cp.le_scan_interval = interval; 117bcff2d91STakanori Watanabe cp.own_address_type = adrtype; 118bcff2d91STakanori Watanabe cp.le_scan_window = window; 119bcff2d91STakanori Watanabe cp.scanning_filter_policy = policy; 120bcff2d91STakanori Watanabe n = sizeof(rp); 121bcff2d91STakanori Watanabe 122eb2aebeaSTakanori Watanabe if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE, 123eb2aebeaSTakanori Watanabe NG_HCI_OCF_LE_SET_SCAN_PARAMETERS), 124eb2aebeaSTakanori Watanabe (void *)&cp, sizeof(cp), (void *)&rp, &n) == ERROR) 125eb2aebeaSTakanori Watanabe return (ERROR); 126eb2aebeaSTakanori Watanabe 127eb2aebeaSTakanori Watanabe if (rp.status != 0x00) { 128eb2aebeaSTakanori Watanabe fprintf(stdout, "Status: %s [%#02x]\n", 129eb2aebeaSTakanori Watanabe hci_status2str(rp.status), rp.status); 130eb2aebeaSTakanori Watanabe return (FAILED); 131eb2aebeaSTakanori Watanabe } 132eb2aebeaSTakanori Watanabe 133eb2aebeaSTakanori Watanabe return (OK); 134bcff2d91STakanori Watanabe } 135bcff2d91STakanori Watanabe 1369c3471faSMarcelo Araujo static int 1379c3471faSMarcelo Araujo le_set_scan_enable(int s, int argc, char *argv[]) 138bcff2d91STakanori Watanabe { 139bcff2d91STakanori Watanabe ng_hci_le_set_scan_enable_cp cp; 140bcff2d91STakanori Watanabe ng_hci_le_set_scan_enable_rp rp; 141eb2aebeaSTakanori Watanabe int n, enable = 0; 142bcff2d91STakanori Watanabe 143bcff2d91STakanori Watanabe if (argc != 1) 144eb2aebeaSTakanori Watanabe return (USAGE); 145bcff2d91STakanori Watanabe 1469c3471faSMarcelo Araujo if (strcmp(argv[0], "enable") == 0) 147bcff2d91STakanori Watanabe enable = 1; 1489c3471faSMarcelo Araujo else if (strcmp(argv[0], "disable") != 0) 149eb2aebeaSTakanori Watanabe return (USAGE); 1509c3471faSMarcelo Araujo 151bcff2d91STakanori Watanabe n = sizeof(rp); 152bcff2d91STakanori Watanabe cp.le_scan_enable = enable; 153bcff2d91STakanori Watanabe cp.filter_duplicates = 0; 154eb2aebeaSTakanori Watanabe if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE, 155bcff2d91STakanori Watanabe NG_HCI_OCF_LE_SET_SCAN_ENABLE), 156eb2aebeaSTakanori Watanabe (void *)&cp, sizeof(cp), 157eb2aebeaSTakanori Watanabe (void *)&rp, &n) == ERROR) 158eb2aebeaSTakanori Watanabe return (ERROR); 159bcff2d91STakanori Watanabe 160eb2aebeaSTakanori Watanabe if (rp.status != 0x00) { 161eb2aebeaSTakanori Watanabe fprintf(stdout, "Status: %s [%#02x]\n", 162eb2aebeaSTakanori Watanabe hci_status2str(rp.status), rp.status); 163eb2aebeaSTakanori Watanabe return (FAILED); 164eb2aebeaSTakanori Watanabe } 165bcff2d91STakanori Watanabe 166eb2aebeaSTakanori Watanabe fprintf(stdout, "LE Scan: %s\n", 167eb2aebeaSTakanori Watanabe enable? "Enabled" : "Disabled"); 168eb2aebeaSTakanori Watanabe 169eb2aebeaSTakanori Watanabe return (OK); 170bcff2d91STakanori Watanabe } 1719c3471faSMarcelo Araujo 1729c3471faSMarcelo Araujo static int 1739c3471faSMarcelo Araujo parse_param(int argc, char *argv[], char *buf, int *len) 174bcff2d91STakanori Watanabe { 175bcff2d91STakanori Watanabe char *buflast = buf + (*len); 176bcff2d91STakanori Watanabe char *curbuf = buf; 177bcff2d91STakanori Watanabe char *token,*lenpos; 178bcff2d91STakanori Watanabe int ch; 179bcff2d91STakanori Watanabe int datalen; 180bcff2d91STakanori Watanabe uint16_t value; 181bcff2d91STakanori Watanabe optreset = 1; 182bcff2d91STakanori Watanabe optind = 0; 183bcff2d91STakanori Watanabe while ((ch = getopt(argc, argv , "n:f:u:")) != -1) { 184bcff2d91STakanori Watanabe switch(ch){ 185bcff2d91STakanori Watanabe case 'n': 186bcff2d91STakanori Watanabe datalen = strlen(optarg); 1879c3471faSMarcelo Araujo if ((curbuf + datalen + 2) >= buflast) 188bcff2d91STakanori Watanabe goto done; 189bcff2d91STakanori Watanabe curbuf[0] = datalen + 1; 190bcff2d91STakanori Watanabe curbuf[1] = 8; 191bcff2d91STakanori Watanabe curbuf += 2; 192bcff2d91STakanori Watanabe memcpy(curbuf, optarg, datalen); 193bcff2d91STakanori Watanabe curbuf += datalen; 194bcff2d91STakanori Watanabe break; 195bcff2d91STakanori Watanabe case 'f': 1969c3471faSMarcelo Araujo if (curbuf+3 > buflast) 197bcff2d91STakanori Watanabe goto done; 198bcff2d91STakanori Watanabe curbuf[0] = 2; 199bcff2d91STakanori Watanabe curbuf[1] = 1; 20032f32669SHans Petter Selasky curbuf[2] = (uint8_t)strtol(optarg, NULL, 16); 201bcff2d91STakanori Watanabe curbuf += 3; 202bcff2d91STakanori Watanabe break; 203bcff2d91STakanori Watanabe case 'u': 204bcff2d91STakanori Watanabe if ((buf+2) >= buflast) 205bcff2d91STakanori Watanabe goto done; 20632f32669SHans Petter Selasky lenpos = curbuf; 207bcff2d91STakanori Watanabe curbuf[1] = 2; 208bcff2d91STakanori Watanabe *lenpos = 1; 209bcff2d91STakanori Watanabe curbuf += 2; 210bcff2d91STakanori Watanabe while ((token = strsep(&optarg, ",")) != NULL) { 211bcff2d91STakanori Watanabe value = strtol(token, NULL, 16); 212bcff2d91STakanori Watanabe if ((curbuf+2) >= buflast) 213bcff2d91STakanori Watanabe break; 214bcff2d91STakanori Watanabe curbuf[0] = value &0xff; 215bcff2d91STakanori Watanabe curbuf[1] = (value>>8)&0xff; 216bcff2d91STakanori Watanabe curbuf += 2; 21732f32669SHans Petter Selasky *lenpos += 2; 218bcff2d91STakanori Watanabe } 219bcff2d91STakanori Watanabe 220bcff2d91STakanori Watanabe } 221bcff2d91STakanori Watanabe } 222bcff2d91STakanori Watanabe done: 223bcff2d91STakanori Watanabe *len = curbuf - buf; 224bcff2d91STakanori Watanabe 225eb2aebeaSTakanori Watanabe return (OK); 226bcff2d91STakanori Watanabe } 227bcff2d91STakanori Watanabe 2289c3471faSMarcelo Araujo static int 2299c3471faSMarcelo Araujo le_set_scan_response(int s, int argc, char *argv[]) 230bcff2d91STakanori Watanabe { 231bcff2d91STakanori Watanabe ng_hci_le_set_scan_response_data_cp cp; 232bcff2d91STakanori Watanabe ng_hci_le_set_scan_response_data_rp rp; 233bcff2d91STakanori Watanabe int n; 234bcff2d91STakanori Watanabe int len; 235bcff2d91STakanori Watanabe char buf[NG_HCI_ADVERTISING_DATA_SIZE]; 2369c3471faSMarcelo Araujo 237bcff2d91STakanori Watanabe len = sizeof(buf); 238bcff2d91STakanori Watanabe parse_param(argc, argv, buf, &len); 239bcff2d91STakanori Watanabe memset(cp.scan_response_data, 0, sizeof(cp.scan_response_data)); 240bcff2d91STakanori Watanabe cp.scan_response_data_length = len; 241bcff2d91STakanori Watanabe memcpy(cp.scan_response_data, buf, len); 242bcff2d91STakanori Watanabe n = sizeof(rp); 243eb2aebeaSTakanori Watanabe if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE, 244bcff2d91STakanori Watanabe NG_HCI_OCF_LE_SET_SCAN_RESPONSE_DATA), 245eb2aebeaSTakanori Watanabe (void *)&cp, sizeof(cp), 246eb2aebeaSTakanori Watanabe (void *)&rp, &n) == ERROR) 247eb2aebeaSTakanori Watanabe return (ERROR); 248bcff2d91STakanori Watanabe 249eb2aebeaSTakanori Watanabe if (rp.status != 0x00) { 250eb2aebeaSTakanori Watanabe fprintf(stdout, "Status: %s [%#02x]\n", 251eb2aebeaSTakanori Watanabe hci_status2str(rp.status), rp.status); 252eb2aebeaSTakanori Watanabe return (FAILED); 253eb2aebeaSTakanori Watanabe } 254bcff2d91STakanori Watanabe 255eb2aebeaSTakanori Watanabe return (OK); 256bcff2d91STakanori Watanabe } 257bcff2d91STakanori Watanabe 2589c3471faSMarcelo Araujo static int 2599c3471faSMarcelo Araujo le_read_local_supported_features(int s, int argc ,char *argv[]) 260bcff2d91STakanori Watanabe { 261bcff2d91STakanori Watanabe ng_hci_le_read_local_supported_features_rp rp; 262bcff2d91STakanori Watanabe int n = sizeof(rp); 2639c3471faSMarcelo Araujo 264ea011491SHans Petter Selasky union { 265ea011491SHans Petter Selasky uint64_t raw; 266ea011491SHans Petter Selasky uint8_t octets[8]; 267ea011491SHans Petter Selasky } le_features; 268ea011491SHans Petter Selasky 269ea011491SHans Petter Selasky char buffer[2048]; 270ea011491SHans Petter Selasky 271ea011491SHans Petter Selasky if (hci_simple_request(s, 272bcff2d91STakanori Watanabe NG_HCI_OPCODE(NG_HCI_OGF_LE, 273bcff2d91STakanori Watanabe NG_HCI_OCF_LE_READ_LOCAL_SUPPORTED_FEATURES), 274ea011491SHans Petter Selasky (void *)&rp, &n) == ERROR) 275ea011491SHans Petter Selasky return (ERROR); 2769c3471faSMarcelo Araujo 277ea011491SHans Petter Selasky if (rp.status != 0x00) { 278ea011491SHans Petter Selasky fprintf(stdout, "Status: %s [%#02x]\n", 279ea011491SHans Petter Selasky hci_status2str(rp.status), rp.status); 280ea011491SHans Petter Selasky return (FAILED); 281ea011491SHans Petter Selasky } 282bcff2d91STakanori Watanabe 283ea011491SHans Petter Selasky le_features.raw = rp.le_features; 284ea011491SHans Petter Selasky 285ea011491SHans Petter Selasky fprintf(stdout, "LE Features: "); 286ea011491SHans Petter Selasky for(int i = 0; i < 8; i++) 287ea011491SHans Petter Selasky fprintf(stdout, " %#02x", le_features.octets[i]); 288ea011491SHans Petter Selasky fprintf(stdout, "\n%s\n", hci_le_features2str(le_features.octets, 289ea011491SHans Petter Selasky buffer, sizeof(buffer))); 290ea011491SHans Petter Selasky fprintf(stdout, "\n"); 291ea011491SHans Petter Selasky 292eb2aebeaSTakanori Watanabe return (OK); 293bcff2d91STakanori Watanabe } 2949c3471faSMarcelo Araujo 2959c3471faSMarcelo Araujo static int 29621eefd31SHans Petter Selasky le_read_supported_states(int s, int argc, char *argv[]) 297bcff2d91STakanori Watanabe { 29821eefd31SHans Petter Selasky ng_hci_le_read_supported_states_rp rp; 299bcff2d91STakanori Watanabe int n = sizeof(rp); 3009c3471faSMarcelo Araujo 30121eefd31SHans Petter Selasky if (hci_simple_request(s, NG_HCI_OPCODE( 3029c3471faSMarcelo Araujo NG_HCI_OGF_LE, 30321eefd31SHans Petter Selasky NG_HCI_OCF_LE_READ_SUPPORTED_STATES), 30421eefd31SHans Petter Selasky (void *)&rp, &n) == ERROR) 30521eefd31SHans Petter Selasky return (ERROR); 3069c3471faSMarcelo Araujo 30721eefd31SHans Petter Selasky if (rp.status != 0x00) { 30821eefd31SHans Petter Selasky fprintf(stdout, "Status: %s [%#02x]\n", 30921eefd31SHans Petter Selasky hci_status2str(rp.status), rp.status); 31021eefd31SHans Petter Selasky return (FAILED); 31121eefd31SHans Petter Selasky } 312bcff2d91STakanori Watanabe 31321eefd31SHans Petter Selasky fprintf(stdout, "LE States: %jx\n", rp.le_states); 31421eefd31SHans Petter Selasky 31521eefd31SHans Petter Selasky return (OK); 316bcff2d91STakanori Watanabe } 317bcff2d91STakanori Watanabe 3189c3471faSMarcelo Araujo static int 3199c3471faSMarcelo Araujo set_le_event_mask(int s, uint64_t mask) 320bcff2d91STakanori Watanabe { 321bcff2d91STakanori Watanabe ng_hci_le_set_event_mask_cp semc; 322bcff2d91STakanori Watanabe ng_hci_le_set_event_mask_rp rp; 323eb2aebeaSTakanori Watanabe int i, n; 324bcff2d91STakanori Watanabe 325bcff2d91STakanori Watanabe n = sizeof(rp); 326bcff2d91STakanori Watanabe 327bcff2d91STakanori Watanabe for (i=0; i < NG_HCI_LE_EVENT_MASK_SIZE; i++) { 328bcff2d91STakanori Watanabe semc.event_mask[i] = mask&0xff; 329bcff2d91STakanori Watanabe mask >>= 8; 330bcff2d91STakanori Watanabe } 331eb2aebeaSTakanori Watanabe if(hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE, 3329c3471faSMarcelo Araujo NG_HCI_OCF_LE_SET_EVENT_MASK), 333eb2aebeaSTakanori Watanabe (void *)&semc, sizeof(semc), (void *)&rp, &n) == ERROR) 334eb2aebeaSTakanori Watanabe return (ERROR); 335bcff2d91STakanori Watanabe 336eb2aebeaSTakanori Watanabe if (rp.status != 0x00) { 337eb2aebeaSTakanori Watanabe fprintf(stdout, "Status: %s [%#02x]\n", 338eb2aebeaSTakanori Watanabe hci_status2str(rp.status), rp.status); 339eb2aebeaSTakanori Watanabe return (FAILED); 340eb2aebeaSTakanori Watanabe } 341eb2aebeaSTakanori Watanabe 342eb2aebeaSTakanori Watanabe return (OK); 343bcff2d91STakanori Watanabe } 344bcff2d91STakanori Watanabe 3459c3471faSMarcelo Araujo static int 3469c3471faSMarcelo Araujo set_event_mask(int s, uint64_t mask) 347bcff2d91STakanori Watanabe { 348bcff2d91STakanori Watanabe ng_hci_set_event_mask_cp semc; 349bcff2d91STakanori Watanabe ng_hci_set_event_mask_rp rp; 350eb2aebeaSTakanori Watanabe int i, n; 351bcff2d91STakanori Watanabe 352bcff2d91STakanori Watanabe n = sizeof(rp); 353bcff2d91STakanori Watanabe 354bcff2d91STakanori Watanabe for (i=0; i < NG_HCI_EVENT_MASK_SIZE; i++) { 355bcff2d91STakanori Watanabe semc.event_mask[i] = mask&0xff; 356bcff2d91STakanori Watanabe mask >>= 8; 357bcff2d91STakanori Watanabe } 358eb2aebeaSTakanori Watanabe if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND, 3599c3471faSMarcelo Araujo NG_HCI_OCF_SET_EVENT_MASK), 360eb2aebeaSTakanori Watanabe (void *)&semc, sizeof(semc), (void *)&rp, &n) == ERROR) 361eb2aebeaSTakanori Watanabe return (ERROR); 362bcff2d91STakanori Watanabe 363eb2aebeaSTakanori Watanabe if (rp.status != 0x00) { 364eb2aebeaSTakanori Watanabe fprintf(stdout, "Status: %s [%#02x]\n", 365eb2aebeaSTakanori Watanabe hci_status2str(rp.status), rp.status); 366eb2aebeaSTakanori Watanabe return (FAILED); 367eb2aebeaSTakanori Watanabe } 368eb2aebeaSTakanori Watanabe 369eb2aebeaSTakanori Watanabe return (OK); 370bcff2d91STakanori Watanabe } 371bcff2d91STakanori Watanabe 3729c3471faSMarcelo Araujo static 3739c3471faSMarcelo Araujo int le_enable(int s, int argc, char *argv[]) 374bcff2d91STakanori Watanabe { 375eb2aebeaSTakanori Watanabe int result; 376eb2aebeaSTakanori Watanabe 3779c3471faSMarcelo Araujo if (argc != 1) 378eb2aebeaSTakanori Watanabe return (USAGE); 379bcff2d91STakanori Watanabe 380bcff2d91STakanori Watanabe if (strcasecmp(argv[0], "enable") == 0) { 381eb2aebeaSTakanori Watanabe result = set_event_mask(s, NG_HCI_EVENT_MASK_DEFAULT | 382bcff2d91STakanori Watanabe NG_HCI_EVENT_MASK_LE); 383eb2aebeaSTakanori Watanabe if (result != OK) 384eb2aebeaSTakanori Watanabe return result; 385eb2aebeaSTakanori Watanabe result = set_le_event_mask(s, NG_HCI_LE_EVENT_MASK_ALL); 386eb2aebeaSTakanori Watanabe if (result == OK) { 387eb2aebeaSTakanori Watanabe fprintf(stdout, "LE enabled\n"); 388eb2aebeaSTakanori Watanabe return (OK); 389eb2aebeaSTakanori Watanabe } else 390eb2aebeaSTakanori Watanabe return result; 391eb2aebeaSTakanori Watanabe } else if (strcasecmp(argv[0], "disable") == 0) { 392eb2aebeaSTakanori Watanabe result = set_event_mask(s, NG_HCI_EVENT_MASK_DEFAULT); 393eb2aebeaSTakanori Watanabe if (result == OK) { 394eb2aebeaSTakanori Watanabe fprintf(stdout, "LE disabled\n"); 395eb2aebeaSTakanori Watanabe return (OK); 396eb2aebeaSTakanori Watanabe } else 397eb2aebeaSTakanori Watanabe return result; 398eb2aebeaSTakanori Watanabe } else 399eb2aebeaSTakanori Watanabe return (USAGE); 400bcff2d91STakanori Watanabe } 401bcff2d91STakanori Watanabe 402c3f60abcSHans Petter Selasky static int 403c3f60abcSHans Petter Selasky le_set_advertising_enable(int s, int argc, char *argv[]) 404c3f60abcSHans Petter Selasky { 405c3f60abcSHans Petter Selasky ng_hci_le_set_advertise_enable_cp cp; 406c3f60abcSHans Petter Selasky ng_hci_le_set_advertise_enable_rp rp; 407c3f60abcSHans Petter Selasky int n, enable = 0; 408c3f60abcSHans Petter Selasky 409c3f60abcSHans Petter Selasky if (argc != 1) 410c3f60abcSHans Petter Selasky return USAGE; 411c3f60abcSHans Petter Selasky 412c3f60abcSHans Petter Selasky if (strcmp(argv[0], "enable") == 0) 413c3f60abcSHans Petter Selasky enable = 1; 414c3f60abcSHans Petter Selasky else if (strcmp(argv[0], "disable") != 0) 415c3f60abcSHans Petter Selasky return USAGE; 416c3f60abcSHans Petter Selasky 417c3f60abcSHans Petter Selasky n = sizeof(rp); 418c3f60abcSHans Petter Selasky cp.advertising_enable = enable; 419c3f60abcSHans Petter Selasky if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE, 420c3f60abcSHans Petter Selasky NG_HCI_OCF_LE_SET_ADVERTISE_ENABLE), 421c3f60abcSHans Petter Selasky (void *)&cp, sizeof(cp), (void *)&rp, &n) == ERROR) 422c3f60abcSHans Petter Selasky return (ERROR); 423c3f60abcSHans Petter Selasky 424c3f60abcSHans Petter Selasky if (rp.status != 0x00) { 425c3f60abcSHans Petter Selasky fprintf(stdout, "Status: %s [%#02x]\n", 426c3f60abcSHans Petter Selasky hci_status2str(rp.status), rp.status); 427c3f60abcSHans Petter Selasky return (FAILED); 428c3f60abcSHans Petter Selasky } 429c3f60abcSHans Petter Selasky fprintf(stdout, "LE Advertising %s\n", (enable ? "enabled" : "disabled")); 430c3f60abcSHans Petter Selasky 431c3f60abcSHans Petter Selasky return (OK); 432c3f60abcSHans Petter Selasky } 433c3f60abcSHans Petter Selasky 434c3f60abcSHans Petter Selasky static int 435c3f60abcSHans Petter Selasky le_set_advertising_param(int s, int argc, char *argv[]) 436c3f60abcSHans Petter Selasky { 437c3f60abcSHans Petter Selasky ng_hci_le_set_advertising_parameters_cp cp; 438c3f60abcSHans Petter Selasky ng_hci_le_set_advertising_parameters_rp rp; 439c3f60abcSHans Petter Selasky 440c3f60abcSHans Petter Selasky int n, ch; 441c3f60abcSHans Petter Selasky 442c3f60abcSHans Petter Selasky cp.advertising_interval_min = 0x800; 443c3f60abcSHans Petter Selasky cp.advertising_interval_max = 0x800; 444c3f60abcSHans Petter Selasky cp.advertising_type = 0; 445c3f60abcSHans Petter Selasky cp.own_address_type = 0; 446c3f60abcSHans Petter Selasky cp.direct_address_type = 0; 447c3f60abcSHans Petter Selasky 448c3f60abcSHans Petter Selasky cp.advertising_channel_map = 7; 449c3f60abcSHans Petter Selasky cp.advertising_filter_policy = 0; 450c3f60abcSHans Petter Selasky 451c3f60abcSHans Petter Selasky optreset = 1; 452c3f60abcSHans Petter Selasky optind = 0; 453c3f60abcSHans Petter Selasky while ((ch = getopt(argc, argv , "m:M:t:o:p:a:c:f:")) != -1) { 454c3f60abcSHans Petter Selasky switch(ch) { 455c3f60abcSHans Petter Selasky case 'm': 456c3f60abcSHans Petter Selasky cp.advertising_interval_min = 457c3f60abcSHans Petter Selasky (uint16_t)(strtod(optarg, NULL)/0.625); 458c3f60abcSHans Petter Selasky break; 459c3f60abcSHans Petter Selasky case 'M': 460c3f60abcSHans Petter Selasky cp.advertising_interval_max = 461c3f60abcSHans Petter Selasky (uint16_t)(strtod(optarg, NULL)/0.625); 462c3f60abcSHans Petter Selasky break; 463c3f60abcSHans Petter Selasky case 't': 464c3f60abcSHans Petter Selasky cp.advertising_type = 465c3f60abcSHans Petter Selasky (uint8_t)strtod(optarg, NULL); 466c3f60abcSHans Petter Selasky break; 467c3f60abcSHans Petter Selasky case 'o': 468c3f60abcSHans Petter Selasky cp.own_address_type = 469c3f60abcSHans Petter Selasky (uint8_t)strtod(optarg, NULL); 470c3f60abcSHans Petter Selasky break; 471c3f60abcSHans Petter Selasky case 'p': 472c3f60abcSHans Petter Selasky cp.direct_address_type = 473c3f60abcSHans Petter Selasky (uint8_t)strtod(optarg, NULL); 474c3f60abcSHans Petter Selasky break; 475c3f60abcSHans Petter Selasky case 'a': 476c3f60abcSHans Petter Selasky if (!bt_aton(optarg, &cp.direct_address)) { 477c3f60abcSHans Petter Selasky struct hostent *he = NULL; 478c3f60abcSHans Petter Selasky 479c3f60abcSHans Petter Selasky if ((he = bt_gethostbyname(optarg)) == NULL) 480c3f60abcSHans Petter Selasky return (USAGE); 481c3f60abcSHans Petter Selasky 482c3f60abcSHans Petter Selasky memcpy(&cp.direct_address, he->h_addr, sizeof(cp.direct_address)); 483c3f60abcSHans Petter Selasky } 484c3f60abcSHans Petter Selasky break; 485c3f60abcSHans Petter Selasky case 'c': 486c3f60abcSHans Petter Selasky cp.advertising_channel_map = 487c3f60abcSHans Petter Selasky (uint8_t)strtod(optarg, NULL); 488c3f60abcSHans Petter Selasky break; 489c3f60abcSHans Petter Selasky case 'f': 490c3f60abcSHans Petter Selasky cp.advertising_filter_policy = 491c3f60abcSHans Petter Selasky (uint8_t)strtod(optarg, NULL); 492c3f60abcSHans Petter Selasky break; 493c3f60abcSHans Petter Selasky } 494c3f60abcSHans Petter Selasky } 495c3f60abcSHans Petter Selasky 496c3f60abcSHans Petter Selasky n = sizeof(rp); 497c3f60abcSHans Petter Selasky if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE, 498c3f60abcSHans Petter Selasky NG_HCI_OCF_LE_SET_ADVERTISING_PARAMETERS), 499c3f60abcSHans Petter Selasky (void *)&cp, sizeof(cp), (void *)&rp, &n) == ERROR) 500c3f60abcSHans Petter Selasky return (ERROR); 501c3f60abcSHans Petter Selasky 502c3f60abcSHans Petter Selasky if (rp.status != 0x00) { 503c3f60abcSHans Petter Selasky fprintf(stdout, "Status: %s [%#02x]\n", 504c3f60abcSHans Petter Selasky hci_status2str(rp.status), rp.status); 505c3f60abcSHans Petter Selasky return (FAILED); 506c3f60abcSHans Petter Selasky } 507c3f60abcSHans Petter Selasky 508c3f60abcSHans Petter Selasky return (OK); 509c3f60abcSHans Petter Selasky } 510c3f60abcSHans Petter Selasky 511c3f60abcSHans Petter Selasky static int 512c3f60abcSHans Petter Selasky le_read_advertising_channel_tx_power(int s, int argc, char *argv[]) 513c3f60abcSHans Petter Selasky { 514c3f60abcSHans Petter Selasky ng_hci_le_read_advertising_channel_tx_power_rp rp; 515c3f60abcSHans Petter Selasky int n; 516c3f60abcSHans Petter Selasky 517c3f60abcSHans Petter Selasky n = sizeof(rp); 518c3f60abcSHans Petter Selasky 519c3f60abcSHans Petter Selasky if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE, 520c3f60abcSHans Petter Selasky NG_HCI_OCF_LE_READ_ADVERTISING_CHANNEL_TX_POWER), 521c3f60abcSHans Petter Selasky (void *)&rp, &n) == ERROR) 522c3f60abcSHans Petter Selasky return (ERROR); 523c3f60abcSHans Petter Selasky 524c3f60abcSHans Petter Selasky if (rp.status != 0x00) { 525c3f60abcSHans Petter Selasky fprintf(stdout, "Status: %s [%#02x]\n", 526c3f60abcSHans Petter Selasky hci_status2str(rp.status), rp.status); 527c3f60abcSHans Petter Selasky return (FAILED); 528c3f60abcSHans Petter Selasky } 529c3f60abcSHans Petter Selasky 530c3f60abcSHans Petter Selasky fprintf(stdout, "Advertising transmit power level: %d dBm\n", 531c3f60abcSHans Petter Selasky (int8_t)rp.transmit_power_level); 532c3f60abcSHans Petter Selasky 533c3f60abcSHans Petter Selasky return (OK); 534c3f60abcSHans Petter Selasky } 535c3f60abcSHans Petter Selasky 536c3f60abcSHans Petter Selasky static int 537c3f60abcSHans Petter Selasky le_set_advertising_data(int s, int argc, char *argv[]) 538c3f60abcSHans Petter Selasky { 539c3f60abcSHans Petter Selasky ng_hci_le_set_advertising_data_cp cp; 540c3f60abcSHans Petter Selasky ng_hci_le_set_advertising_data_rp rp; 541c3f60abcSHans Petter Selasky int n, len; 542c3f60abcSHans Petter Selasky 543c3f60abcSHans Petter Selasky n = sizeof(rp); 544c3f60abcSHans Petter Selasky 545c3f60abcSHans Petter Selasky char buf[NG_HCI_ADVERTISING_DATA_SIZE]; 546c3f60abcSHans Petter Selasky 547c3f60abcSHans Petter Selasky len = sizeof(buf); 548c3f60abcSHans Petter Selasky parse_param(argc, argv, buf, &len); 549c3f60abcSHans Petter Selasky memset(cp.advertising_data, 0, sizeof(cp.advertising_data)); 550c3f60abcSHans Petter Selasky cp.advertising_data_length = len; 5517b2f84dbSHans Petter Selasky memcpy(cp.advertising_data, buf, len); 552c3f60abcSHans Petter Selasky 553c3f60abcSHans Petter Selasky if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE, 554c3f60abcSHans Petter Selasky NG_HCI_OCF_LE_SET_ADVERTISING_DATA), 555c3f60abcSHans Petter Selasky (void *)&cp, sizeof(cp), (void *)&rp, &n) == ERROR) 556c3f60abcSHans Petter Selasky return (ERROR); 557c3f60abcSHans Petter Selasky 558c3f60abcSHans Petter Selasky if (rp.status != 0x00) { 559c3f60abcSHans Petter Selasky fprintf(stdout, "Status: %s [%#02x]\n", 560c3f60abcSHans Petter Selasky hci_status2str(rp.status), rp.status); 561c3f60abcSHans Petter Selasky return (FAILED); 562c3f60abcSHans Petter Selasky } 563c3f60abcSHans Petter Selasky 564c3f60abcSHans Petter Selasky return (OK); 565c3f60abcSHans Petter Selasky } 5661f5d883dSTakanori Watanabe static int 5671f5d883dSTakanori Watanabe le_read_buffer_size(int s, int argc, char *argv[]) 5681f5d883dSTakanori Watanabe { 5691f5d883dSTakanori Watanabe union { 5701f5d883dSTakanori Watanabe ng_hci_le_read_buffer_size_rp v1; 5711f5d883dSTakanori Watanabe ng_hci_le_read_buffer_size_rp_v2 v2; 5721f5d883dSTakanori Watanabe } rp; 5731f5d883dSTakanori Watanabe 5741f5d883dSTakanori Watanabe int n, ch; 5751f5d883dSTakanori Watanabe uint8_t v; 5761f5d883dSTakanori Watanabe uint16_t cmd; 5771f5d883dSTakanori Watanabe 5781f5d883dSTakanori Watanabe optreset = 1; 5791f5d883dSTakanori Watanabe optind = 0; 5801f5d883dSTakanori Watanabe 5811f5d883dSTakanori Watanabe /* Default to version 1*/ 5821f5d883dSTakanori Watanabe v = 1; 5831f5d883dSTakanori Watanabe cmd = NG_HCI_OCF_LE_READ_BUFFER_SIZE; 5841f5d883dSTakanori Watanabe 5851f5d883dSTakanori Watanabe while ((ch = getopt(argc, argv , "v:")) != -1) { 5861f5d883dSTakanori Watanabe switch(ch) { 5871f5d883dSTakanori Watanabe case 'v': 5881f5d883dSTakanori Watanabe v = (uint8_t)strtol(optarg, NULL, 16); 5891f5d883dSTakanori Watanabe if (v == 2) 5901f5d883dSTakanori Watanabe cmd = NG_HCI_OCF_LE_READ_BUFFER_SIZE_V2; 5911f5d883dSTakanori Watanabe else if (v > 2) 5921f5d883dSTakanori Watanabe return (USAGE); 5931f5d883dSTakanori Watanabe break; 5941f5d883dSTakanori Watanabe default: 5951f5d883dSTakanori Watanabe v = 1; 5961f5d883dSTakanori Watanabe } 5971f5d883dSTakanori Watanabe } 5981f5d883dSTakanori Watanabe 5991f5d883dSTakanori Watanabe n = sizeof(rp); 6001f5d883dSTakanori Watanabe if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE, cmd), 6011f5d883dSTakanori Watanabe (void *)&rp, &n) == ERROR) 6021f5d883dSTakanori Watanabe return (ERROR); 6031f5d883dSTakanori Watanabe 6041f5d883dSTakanori Watanabe if (rp.v1.status != 0x00) { 6051f5d883dSTakanori Watanabe fprintf(stdout, "Status: %s [%#02x]\n", 6061f5d883dSTakanori Watanabe hci_status2str(rp.v1.status), rp.v1.status); 6071f5d883dSTakanori Watanabe return (FAILED); 6081f5d883dSTakanori Watanabe } 6091f5d883dSTakanori Watanabe 6101f5d883dSTakanori Watanabe fprintf(stdout, "ACL data packet length: %d\n", 6111f5d883dSTakanori Watanabe rp.v1.hc_le_data_packet_length); 6121f5d883dSTakanori Watanabe fprintf(stdout, "Number of ACL data packets: %d\n", 6131f5d883dSTakanori Watanabe rp.v1.hc_total_num_le_data_packets); 6141f5d883dSTakanori Watanabe 6151f5d883dSTakanori Watanabe if (v == 2) { 6161f5d883dSTakanori Watanabe fprintf(stdout, "ISO data packet length: %d\n", 6171f5d883dSTakanori Watanabe rp.v2.hc_iso_data_packet_length); 6181f5d883dSTakanori Watanabe fprintf(stdout, "Number of ISO data packets: %d\n", 6191f5d883dSTakanori Watanabe rp.v2.hc_total_num_iso_data_packets); 6201f5d883dSTakanori Watanabe } 6211f5d883dSTakanori Watanabe 6221f5d883dSTakanori Watanabe return (OK); 6231f5d883dSTakanori Watanabe } 624c3f60abcSHans Petter Selasky 6259287f06dSTakanori Watanabe static int 6269287f06dSTakanori Watanabe le_scan(int s, int argc, char *argv[]) 6279287f06dSTakanori Watanabe { 6289287f06dSTakanori Watanabe int n, bufsize, scancount, numscans; 6299287f06dSTakanori Watanabe bool verbose; 6309287f06dSTakanori Watanabe uint8_t active = 0; 6319287f06dSTakanori Watanabe char ch; 6329287f06dSTakanori Watanabe 6339287f06dSTakanori Watanabe char b[512]; 6349287f06dSTakanori Watanabe ng_hci_event_pkt_t *e = (ng_hci_event_pkt_t *) b; 6359287f06dSTakanori Watanabe 6369287f06dSTakanori Watanabe ng_hci_le_set_scan_parameters_cp scan_param_cp; 6379287f06dSTakanori Watanabe ng_hci_le_set_scan_parameters_rp scan_param_rp; 6389287f06dSTakanori Watanabe 6399287f06dSTakanori Watanabe ng_hci_le_set_scan_enable_cp scan_enable_cp; 6409287f06dSTakanori Watanabe ng_hci_le_set_scan_enable_rp scan_enable_rp; 6419287f06dSTakanori Watanabe 6429287f06dSTakanori Watanabe optreset = 1; 6439287f06dSTakanori Watanabe optind = 0; 6449287f06dSTakanori Watanabe verbose = false; 6459287f06dSTakanori Watanabe numscans = 1; 6469287f06dSTakanori Watanabe 6479287f06dSTakanori Watanabe while ((ch = getopt(argc, argv , "an:v")) != -1) { 6489287f06dSTakanori Watanabe switch(ch) { 6499287f06dSTakanori Watanabe case 'a': 6509287f06dSTakanori Watanabe active = 1; 6519287f06dSTakanori Watanabe break; 6529287f06dSTakanori Watanabe case 'n': 6539287f06dSTakanori Watanabe numscans = (uint8_t)strtol(optarg, NULL, 10); 6549287f06dSTakanori Watanabe break; 6559287f06dSTakanori Watanabe case 'v': 6569287f06dSTakanori Watanabe verbose = true; 6579287f06dSTakanori Watanabe break; 6589287f06dSTakanori Watanabe } 6599287f06dSTakanori Watanabe } 6609287f06dSTakanori Watanabe 6619287f06dSTakanori Watanabe scan_param_cp.le_scan_type = active; 6629287f06dSTakanori Watanabe scan_param_cp.le_scan_interval = (uint16_t)(100/0.625); 6639287f06dSTakanori Watanabe scan_param_cp.le_scan_window = (uint16_t)(50/0.625); 6649287f06dSTakanori Watanabe /* Address type public */ 6659287f06dSTakanori Watanabe scan_param_cp.own_address_type = 0; 6669287f06dSTakanori Watanabe /* 'All' filter policy */ 6679287f06dSTakanori Watanabe scan_param_cp.scanning_filter_policy = 0; 6689287f06dSTakanori Watanabe n = sizeof(scan_param_rp); 6699287f06dSTakanori Watanabe 6709287f06dSTakanori Watanabe if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE, 6719287f06dSTakanori Watanabe NG_HCI_OCF_LE_SET_SCAN_PARAMETERS), 6729287f06dSTakanori Watanabe (void *)&scan_param_cp, sizeof(scan_param_cp), 6739287f06dSTakanori Watanabe (void *)&scan_param_rp, &n) == ERROR) 6749287f06dSTakanori Watanabe return (ERROR); 6759287f06dSTakanori Watanabe 6769287f06dSTakanori Watanabe if (scan_param_rp.status != 0x00) { 6779287f06dSTakanori Watanabe fprintf(stdout, "LE_Set_Scan_Parameters failed. Status: %s [%#02x]\n", 6789287f06dSTakanori Watanabe hci_status2str(scan_param_rp.status), 6799287f06dSTakanori Watanabe scan_param_rp.status); 6809287f06dSTakanori Watanabe return (FAILED); 6819287f06dSTakanori Watanabe } 6829287f06dSTakanori Watanabe 6839287f06dSTakanori Watanabe /* Enable scanning */ 6849287f06dSTakanori Watanabe n = sizeof(scan_enable_rp); 6859287f06dSTakanori Watanabe scan_enable_cp.le_scan_enable = 1; 6869287f06dSTakanori Watanabe scan_enable_cp.filter_duplicates = 1; 6879287f06dSTakanori Watanabe if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE, 6889287f06dSTakanori Watanabe NG_HCI_OCF_LE_SET_SCAN_ENABLE), 6899287f06dSTakanori Watanabe (void *)&scan_enable_cp, sizeof(scan_enable_cp), 6909287f06dSTakanori Watanabe (void *)&scan_enable_rp, &n) == ERROR) 6919287f06dSTakanori Watanabe return (ERROR); 6929287f06dSTakanori Watanabe 6939287f06dSTakanori Watanabe if (scan_enable_rp.status != 0x00) { 6949287f06dSTakanori Watanabe fprintf(stdout, "LE_Scan_Enable enable failed. Status: %s [%#02x]\n", 6959287f06dSTakanori Watanabe hci_status2str(scan_enable_rp.status), 6969287f06dSTakanori Watanabe scan_enable_rp.status); 6979287f06dSTakanori Watanabe return (FAILED); 6989287f06dSTakanori Watanabe } 6999287f06dSTakanori Watanabe 7009287f06dSTakanori Watanabe scancount = 0; 7019287f06dSTakanori Watanabe while (scancount < numscans) { 7029287f06dSTakanori Watanabe /* wait for scan events */ 7039287f06dSTakanori Watanabe bufsize = sizeof(b); 7049287f06dSTakanori Watanabe if (hci_recv(s, b, &bufsize) == ERROR) { 7059287f06dSTakanori Watanabe return (ERROR); 7069287f06dSTakanori Watanabe } 7079287f06dSTakanori Watanabe 7089287f06dSTakanori Watanabe if (bufsize < sizeof(*e)) { 7099287f06dSTakanori Watanabe errno = EIO; 7109287f06dSTakanori Watanabe return (ERROR); 7119287f06dSTakanori Watanabe } 7129287f06dSTakanori Watanabe scancount++; 7139287f06dSTakanori Watanabe if (e->event == NG_HCI_EVENT_LE) { 7149287f06dSTakanori Watanabe fprintf(stdout, "Scan %d\n", scancount); 7159287f06dSTakanori Watanabe handle_le_event(e, verbose); 7169287f06dSTakanori Watanabe } 7179287f06dSTakanori Watanabe } 7189287f06dSTakanori Watanabe 7199287f06dSTakanori Watanabe fprintf(stdout, "Scan complete\n"); 7209287f06dSTakanori Watanabe 7219287f06dSTakanori Watanabe /* Disable scanning */ 7229287f06dSTakanori Watanabe n = sizeof(scan_enable_rp); 7239287f06dSTakanori Watanabe scan_enable_cp.le_scan_enable = 0; 7249287f06dSTakanori Watanabe if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE, 7259287f06dSTakanori Watanabe NG_HCI_OCF_LE_SET_SCAN_ENABLE), 7269287f06dSTakanori Watanabe (void *)&scan_enable_cp, sizeof(scan_enable_cp), 7279287f06dSTakanori Watanabe (void *)&scan_enable_rp, &n) == ERROR) 7289287f06dSTakanori Watanabe return (ERROR); 7299287f06dSTakanori Watanabe 7309287f06dSTakanori Watanabe if (scan_enable_rp.status != 0x00) { 7319287f06dSTakanori Watanabe fprintf(stdout, "LE_Scan_Enable disable failed. Status: %s [%#02x]\n", 7329287f06dSTakanori Watanabe hci_status2str(scan_enable_rp.status), 7339287f06dSTakanori Watanabe scan_enable_rp.status); 7349287f06dSTakanori Watanabe return (FAILED); 7359287f06dSTakanori Watanabe } 7369287f06dSTakanori Watanabe 7379287f06dSTakanori Watanabe return (OK); 7389287f06dSTakanori Watanabe } 7399287f06dSTakanori Watanabe 7409287f06dSTakanori Watanabe static void handle_le_event(ng_hci_event_pkt_t* e, bool verbose) 7419287f06dSTakanori Watanabe { 7429287f06dSTakanori Watanabe int rc; 7439287f06dSTakanori Watanabe ng_hci_le_ep *leer = 7449287f06dSTakanori Watanabe (ng_hci_le_ep *)(e + 1); 7459287f06dSTakanori Watanabe ng_hci_le_advertising_report_ep *advrep = 7469287f06dSTakanori Watanabe (ng_hci_le_advertising_report_ep *)(leer + 1); 7479287f06dSTakanori Watanabe ng_hci_le_advreport *reports = 7489287f06dSTakanori Watanabe (ng_hci_le_advreport *)(advrep + 1); 7499287f06dSTakanori Watanabe 7509287f06dSTakanori Watanabe if (leer->subevent_code == NG_HCI_LEEV_ADVREP) { 7519287f06dSTakanori Watanabe fprintf(stdout, "Scan result, num_reports: %d\n", 7529287f06dSTakanori Watanabe advrep->num_reports); 7539287f06dSTakanori Watanabe for(rc = 0; rc < advrep->num_reports; rc++) { 7549287f06dSTakanori Watanabe uint8_t length = (uint8_t)reports[rc].length_data; 7559287f06dSTakanori Watanabe fprintf(stdout, "\tBD_ADDR %s \n", 7569287f06dSTakanori Watanabe hci_bdaddr2str(&reports[rc].bdaddr)); 7579287f06dSTakanori Watanabe fprintf(stdout, "\tAddress type: %s\n", 7589287f06dSTakanori Watanabe hci_addrtype2str(reports[rc].addr_type)); 7599287f06dSTakanori Watanabe if (length > 0 && verbose) { 7609287f06dSTakanori Watanabe dump_adv_data(length, reports[rc].data); 7619287f06dSTakanori Watanabe print_adv_data(length, reports[rc].data); 7629287f06dSTakanori Watanabe fprintf(stdout, 7639287f06dSTakanori Watanabe "\tRSSI: %d dBm\n", 7649287f06dSTakanori Watanabe (int8_t)reports[rc].data[length]); 7659287f06dSTakanori Watanabe fprintf(stdout, "\n"); 7669287f06dSTakanori Watanabe } 7679287f06dSTakanori Watanabe } 7689287f06dSTakanori Watanabe } 7699287f06dSTakanori Watanabe } 7709287f06dSTakanori Watanabe 77111fb4bdbSTakanori Watanabe static int 77211fb4bdbSTakanori Watanabe le_read_white_list_size(int s, int argc, char *argv[]) 77311fb4bdbSTakanori Watanabe { 77411fb4bdbSTakanori Watanabe ng_hci_le_read_white_list_size_rp rp; 77511fb4bdbSTakanori Watanabe int n; 77611fb4bdbSTakanori Watanabe 77711fb4bdbSTakanori Watanabe n = sizeof(rp); 77811fb4bdbSTakanori Watanabe 77911fb4bdbSTakanori Watanabe if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE, 78011fb4bdbSTakanori Watanabe NG_HCI_OCF_LE_READ_WHITE_LIST_SIZE), 78111fb4bdbSTakanori Watanabe (void *)&rp, &n) == ERROR) 78211fb4bdbSTakanori Watanabe return (ERROR); 78311fb4bdbSTakanori Watanabe 78411fb4bdbSTakanori Watanabe if (rp.status != 0x00) { 78511fb4bdbSTakanori Watanabe fprintf(stdout, "Status: %s [%#02x]\n", 78611fb4bdbSTakanori Watanabe hci_status2str(rp.status), rp.status); 78711fb4bdbSTakanori Watanabe return (FAILED); 78811fb4bdbSTakanori Watanabe } 78911fb4bdbSTakanori Watanabe 79011fb4bdbSTakanori Watanabe fprintf(stdout, "White list size: %d\n", 79111fb4bdbSTakanori Watanabe (uint8_t)rp.white_list_size); 79211fb4bdbSTakanori Watanabe 79311fb4bdbSTakanori Watanabe return (OK); 79411fb4bdbSTakanori Watanabe } 79511fb4bdbSTakanori Watanabe 79611fb4bdbSTakanori Watanabe static int 79711fb4bdbSTakanori Watanabe le_clear_white_list(int s, int argc, char *argv[]) 79811fb4bdbSTakanori Watanabe { 79911fb4bdbSTakanori Watanabe ng_hci_le_clear_white_list_rp rp; 80011fb4bdbSTakanori Watanabe int n; 80111fb4bdbSTakanori Watanabe 80211fb4bdbSTakanori Watanabe n = sizeof(rp); 80311fb4bdbSTakanori Watanabe 80411fb4bdbSTakanori Watanabe if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE, 80511fb4bdbSTakanori Watanabe NG_HCI_OCF_LE_CLEAR_WHITE_LIST), 80611fb4bdbSTakanori Watanabe (void *)&rp, &n) == ERROR) 80711fb4bdbSTakanori Watanabe return (ERROR); 80811fb4bdbSTakanori Watanabe 80911fb4bdbSTakanori Watanabe if (rp.status != 0x00) { 81011fb4bdbSTakanori Watanabe fprintf(stdout, "Status: %s [%#02x]\n", 81111fb4bdbSTakanori Watanabe hci_status2str(rp.status), rp.status); 81211fb4bdbSTakanori Watanabe return (FAILED); 81311fb4bdbSTakanori Watanabe } 81411fb4bdbSTakanori Watanabe 81511fb4bdbSTakanori Watanabe fprintf(stdout, "White list cleared\n"); 81611fb4bdbSTakanori Watanabe 81711fb4bdbSTakanori Watanabe return (OK); 81811fb4bdbSTakanori Watanabe } 81911fb4bdbSTakanori Watanabe 82011fb4bdbSTakanori Watanabe static int 82111fb4bdbSTakanori Watanabe le_add_device_to_white_list(int s, int argc, char *argv[]) 82211fb4bdbSTakanori Watanabe { 82311fb4bdbSTakanori Watanabe ng_hci_le_add_device_to_white_list_cp cp; 82411fb4bdbSTakanori Watanabe ng_hci_le_add_device_to_white_list_rp rp; 82511fb4bdbSTakanori Watanabe int n; 82611fb4bdbSTakanori Watanabe char ch; 82711fb4bdbSTakanori Watanabe optreset = 1; 82811fb4bdbSTakanori Watanabe optind = 0; 82911fb4bdbSTakanori Watanabe bool addr_set = false; 83011fb4bdbSTakanori Watanabe 83111fb4bdbSTakanori Watanabe n = sizeof(rp); 83211fb4bdbSTakanori Watanabe 83311fb4bdbSTakanori Watanabe cp.address_type = 0x00; 83411fb4bdbSTakanori Watanabe 83511fb4bdbSTakanori Watanabe while ((ch = getopt(argc, argv , "t:a:")) != -1) { 83611fb4bdbSTakanori Watanabe switch(ch) { 83711fb4bdbSTakanori Watanabe case 't': 83811fb4bdbSTakanori Watanabe if (strcmp(optarg, "public") == 0) 83911fb4bdbSTakanori Watanabe cp.address_type = 0x00; 84011fb4bdbSTakanori Watanabe else if (strcmp(optarg, "random") == 0) 84111fb4bdbSTakanori Watanabe cp.address_type = 0x01; 84211fb4bdbSTakanori Watanabe else 84311fb4bdbSTakanori Watanabe return (USAGE); 84411fb4bdbSTakanori Watanabe break; 84511fb4bdbSTakanori Watanabe case 'a': 84611fb4bdbSTakanori Watanabe addr_set = true; 84711fb4bdbSTakanori Watanabe if (!bt_aton(optarg, &cp.address)) { 84811fb4bdbSTakanori Watanabe struct hostent *he = NULL; 84911fb4bdbSTakanori Watanabe 85011fb4bdbSTakanori Watanabe if ((he = bt_gethostbyname(optarg)) == NULL) 85111fb4bdbSTakanori Watanabe return (USAGE); 85211fb4bdbSTakanori Watanabe 85311fb4bdbSTakanori Watanabe memcpy(&cp.address, he->h_addr, 85411fb4bdbSTakanori Watanabe sizeof(cp.address)); 85511fb4bdbSTakanori Watanabe } 85611fb4bdbSTakanori Watanabe break; 85711fb4bdbSTakanori Watanabe } 85811fb4bdbSTakanori Watanabe } 85911fb4bdbSTakanori Watanabe 86011fb4bdbSTakanori Watanabe if (addr_set == false) 86111fb4bdbSTakanori Watanabe return (USAGE); 86211fb4bdbSTakanori Watanabe 86311fb4bdbSTakanori Watanabe if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE, 86411fb4bdbSTakanori Watanabe NG_HCI_OCF_LE_ADD_DEVICE_TO_WHITE_LIST), 86511fb4bdbSTakanori Watanabe (void *)&cp, sizeof(cp), (void *)&rp, &n) == ERROR) 86611fb4bdbSTakanori Watanabe return (ERROR); 86711fb4bdbSTakanori Watanabe 86811fb4bdbSTakanori Watanabe if (rp.status != 0x00) { 86911fb4bdbSTakanori Watanabe fprintf(stdout, "Status: %s [%#02x]\n", 87011fb4bdbSTakanori Watanabe hci_status2str(rp.status), rp.status); 87111fb4bdbSTakanori Watanabe return (FAILED); 87211fb4bdbSTakanori Watanabe } 87311fb4bdbSTakanori Watanabe 87411fb4bdbSTakanori Watanabe fprintf(stdout, "Address added to white list\n"); 87511fb4bdbSTakanori Watanabe 87611fb4bdbSTakanori Watanabe return (OK); 87711fb4bdbSTakanori Watanabe } 87811fb4bdbSTakanori Watanabe 87911fb4bdbSTakanori Watanabe static int 88011fb4bdbSTakanori Watanabe le_remove_device_from_white_list(int s, int argc, char *argv[]) 88111fb4bdbSTakanori Watanabe { 88211fb4bdbSTakanori Watanabe ng_hci_le_remove_device_from_white_list_cp cp; 88311fb4bdbSTakanori Watanabe ng_hci_le_remove_device_from_white_list_rp rp; 88411fb4bdbSTakanori Watanabe int n; 88511fb4bdbSTakanori Watanabe char ch; 88611fb4bdbSTakanori Watanabe optreset = 1; 88711fb4bdbSTakanori Watanabe optind = 0; 88811fb4bdbSTakanori Watanabe bool addr_set = false; 88911fb4bdbSTakanori Watanabe 89011fb4bdbSTakanori Watanabe n = sizeof(rp); 89111fb4bdbSTakanori Watanabe 89211fb4bdbSTakanori Watanabe cp.address_type = 0x00; 89311fb4bdbSTakanori Watanabe 89411fb4bdbSTakanori Watanabe while ((ch = getopt(argc, argv , "t:a:")) != -1) { 89511fb4bdbSTakanori Watanabe switch(ch) { 89611fb4bdbSTakanori Watanabe case 't': 89711fb4bdbSTakanori Watanabe if (strcmp(optarg, "public") == 0) 89811fb4bdbSTakanori Watanabe cp.address_type = 0x00; 89911fb4bdbSTakanori Watanabe else if (strcmp(optarg, "random") == 0) 90011fb4bdbSTakanori Watanabe cp.address_type = 0x01; 90111fb4bdbSTakanori Watanabe else 90211fb4bdbSTakanori Watanabe return (USAGE); 90311fb4bdbSTakanori Watanabe break; 90411fb4bdbSTakanori Watanabe case 'a': 90511fb4bdbSTakanori Watanabe addr_set = true; 90611fb4bdbSTakanori Watanabe if (!bt_aton(optarg, &cp.address)) { 90711fb4bdbSTakanori Watanabe struct hostent *he = NULL; 90811fb4bdbSTakanori Watanabe 90911fb4bdbSTakanori Watanabe if ((he = bt_gethostbyname(optarg)) == NULL) 91011fb4bdbSTakanori Watanabe return (USAGE); 91111fb4bdbSTakanori Watanabe 91211fb4bdbSTakanori Watanabe memcpy(&cp.address, he->h_addr, 91311fb4bdbSTakanori Watanabe sizeof(cp.address)); 91411fb4bdbSTakanori Watanabe } 91511fb4bdbSTakanori Watanabe break; 91611fb4bdbSTakanori Watanabe } 91711fb4bdbSTakanori Watanabe } 91811fb4bdbSTakanori Watanabe 91911fb4bdbSTakanori Watanabe if (addr_set == false) 92011fb4bdbSTakanori Watanabe return (USAGE); 92111fb4bdbSTakanori Watanabe 92211fb4bdbSTakanori Watanabe if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE, 92311fb4bdbSTakanori Watanabe NG_HCI_OCF_LE_ADD_DEVICE_TO_WHITE_LIST), 92411fb4bdbSTakanori Watanabe (void *)&cp, sizeof(cp), (void *)&rp, &n) == ERROR) 92511fb4bdbSTakanori Watanabe return (ERROR); 92611fb4bdbSTakanori Watanabe 92711fb4bdbSTakanori Watanabe if (rp.status != 0x00) { 92811fb4bdbSTakanori Watanabe fprintf(stdout, "Status: %s [%#02x]\n", 92911fb4bdbSTakanori Watanabe hci_status2str(rp.status), rp.status); 93011fb4bdbSTakanori Watanabe return (FAILED); 93111fb4bdbSTakanori Watanabe } 93211fb4bdbSTakanori Watanabe 93311fb4bdbSTakanori Watanabe fprintf(stdout, "Address removed from white list\n"); 93411fb4bdbSTakanori Watanabe 93511fb4bdbSTakanori Watanabe return (OK); 93611fb4bdbSTakanori Watanabe } 93711fb4bdbSTakanori Watanabe 9383ac41cceSTakanori Watanabe static int 9393ac41cceSTakanori Watanabe le_connect(int s, int argc, char *argv[]) 9403ac41cceSTakanori Watanabe { 9413ac41cceSTakanori Watanabe ng_hci_le_create_connection_cp cp; 9423ac41cceSTakanori Watanabe ng_hci_status_rp rp; 9433ac41cceSTakanori Watanabe char b[512]; 9443ac41cceSTakanori Watanabe ng_hci_event_pkt_t *e = (ng_hci_event_pkt_t *) b; 9453ac41cceSTakanori Watanabe 9463ac41cceSTakanori Watanabe int n, scancount, bufsize; 9473ac41cceSTakanori Watanabe char ch; 9483ac41cceSTakanori Watanabe bool addr_set = false; 9493ac41cceSTakanori Watanabe bool verbose = false; 9503ac41cceSTakanori Watanabe 9513ac41cceSTakanori Watanabe optreset = 1; 9523ac41cceSTakanori Watanabe optind = 0; 9533ac41cceSTakanori Watanabe 9543ac41cceSTakanori Watanabe /* minimal scan interval (2.5ms) */ 9553ac41cceSTakanori Watanabe cp.scan_interval = htole16(4); 9563ac41cceSTakanori Watanabe cp.scan_window = htole16(4); 9573ac41cceSTakanori Watanabe 9583ac41cceSTakanori Watanabe /* Don't use the whitelist */ 9593ac41cceSTakanori Watanabe cp.filter_policy = 0x00; 9603ac41cceSTakanori Watanabe 9613ac41cceSTakanori Watanabe /* Default to public peer address */ 9623ac41cceSTakanori Watanabe cp.peer_addr_type = 0x00; 9633ac41cceSTakanori Watanabe 9643ac41cceSTakanori Watanabe /* Own address type public */ 9653ac41cceSTakanori Watanabe cp.own_address_type = 0x00; 9663ac41cceSTakanori Watanabe 9673ac41cceSTakanori Watanabe /* 18.75ms min connection interval */ 9683ac41cceSTakanori Watanabe cp.conn_interval_min = htole16(0x000F); 9693ac41cceSTakanori Watanabe /* 18.75ms max connection interval */ 9703ac41cceSTakanori Watanabe cp.conn_interval_max = htole16(0x000F); 9713ac41cceSTakanori Watanabe 9723ac41cceSTakanori Watanabe /* 0 events connection latency */ 9733ac41cceSTakanori Watanabe cp.conn_latency = htole16(0x0000); 9743ac41cceSTakanori Watanabe 9753ac41cceSTakanori Watanabe /* 32s supervision timeout */ 9763ac41cceSTakanori Watanabe cp.supervision_timeout = htole16(0x0C80); 9773ac41cceSTakanori Watanabe 9783ac41cceSTakanori Watanabe /* Min CE Length 0.625 ms */ 9793ac41cceSTakanori Watanabe cp.min_ce_length = htole16(1); 9803ac41cceSTakanori Watanabe /* Max CE Length 0.625 ms */ 9813ac41cceSTakanori Watanabe cp.max_ce_length = htole16(1); 9823ac41cceSTakanori Watanabe 9833ac41cceSTakanori Watanabe while ((ch = getopt(argc, argv , "a:t:v")) != -1) { 9843ac41cceSTakanori Watanabe switch(ch) { 9853ac41cceSTakanori Watanabe case 't': 9863ac41cceSTakanori Watanabe if (strcmp(optarg, "public") == 0) 9873ac41cceSTakanori Watanabe cp.peer_addr_type = 0x00; 9883ac41cceSTakanori Watanabe else if (strcmp(optarg, "random") == 0) 9893ac41cceSTakanori Watanabe cp.peer_addr_type = 0x01; 9903ac41cceSTakanori Watanabe else 9913ac41cceSTakanori Watanabe return (USAGE); 9923ac41cceSTakanori Watanabe break; 9933ac41cceSTakanori Watanabe case 'a': 9943ac41cceSTakanori Watanabe addr_set = true; 9953ac41cceSTakanori Watanabe if (!bt_aton(optarg, &cp.peer_addr)) { 9963ac41cceSTakanori Watanabe struct hostent *he = NULL; 9973ac41cceSTakanori Watanabe 9983ac41cceSTakanori Watanabe if ((he = bt_gethostbyname(optarg)) == NULL) 9993ac41cceSTakanori Watanabe return (USAGE); 10003ac41cceSTakanori Watanabe 10013ac41cceSTakanori Watanabe memcpy(&cp.peer_addr, he->h_addr, 10023ac41cceSTakanori Watanabe sizeof(cp.peer_addr)); 10033ac41cceSTakanori Watanabe } 10043ac41cceSTakanori Watanabe break; 10053ac41cceSTakanori Watanabe case 'v': 10063ac41cceSTakanori Watanabe verbose = true; 10073ac41cceSTakanori Watanabe break; 10083ac41cceSTakanori Watanabe } 10093ac41cceSTakanori Watanabe } 10103ac41cceSTakanori Watanabe 10113ac41cceSTakanori Watanabe if (addr_set == false) 10123ac41cceSTakanori Watanabe return (USAGE); 10133ac41cceSTakanori Watanabe 10143ac41cceSTakanori Watanabe n = sizeof(rp); 10153ac41cceSTakanori Watanabe if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE, 10163ac41cceSTakanori Watanabe NG_HCI_OCF_LE_CREATE_CONNECTION), 10173ac41cceSTakanori Watanabe (void *)&cp, sizeof(cp), (void *)&rp, &n) == ERROR) 10183ac41cceSTakanori Watanabe return (ERROR); 10193ac41cceSTakanori Watanabe 10203ac41cceSTakanori Watanabe if (rp.status != 0x00) { 10213ac41cceSTakanori Watanabe fprintf(stdout, 10223ac41cceSTakanori Watanabe "Create connection failed. Status: %s [%#02x]\n", 10233ac41cceSTakanori Watanabe hci_status2str(rp.status), rp.status); 10243ac41cceSTakanori Watanabe return (FAILED); 10253ac41cceSTakanori Watanabe } 10263ac41cceSTakanori Watanabe 10273ac41cceSTakanori Watanabe scancount = 0; 10283ac41cceSTakanori Watanabe while (scancount < 3) { 10293ac41cceSTakanori Watanabe /* wait for connection events */ 10303ac41cceSTakanori Watanabe bufsize = sizeof(b); 10313ac41cceSTakanori Watanabe if (hci_recv(s, b, &bufsize) == ERROR) { 10323ac41cceSTakanori Watanabe return (ERROR); 10333ac41cceSTakanori Watanabe } 10343ac41cceSTakanori Watanabe 10353ac41cceSTakanori Watanabe if (bufsize < sizeof(*e)) { 10363ac41cceSTakanori Watanabe errno = EIO; 10373ac41cceSTakanori Watanabe return (ERROR); 10383ac41cceSTakanori Watanabe } 10393ac41cceSTakanori Watanabe scancount++; 10403ac41cceSTakanori Watanabe if (e->event == NG_HCI_EVENT_LE) { 10413ac41cceSTakanori Watanabe handle_le_connection_event(e, verbose); 10423ac41cceSTakanori Watanabe break; 10433ac41cceSTakanori Watanabe } 10443ac41cceSTakanori Watanabe } 10453ac41cceSTakanori Watanabe 10463ac41cceSTakanori Watanabe return (OK); 10473ac41cceSTakanori Watanabe } 10483ac41cceSTakanori Watanabe 10493ac41cceSTakanori Watanabe static void handle_le_connection_event(ng_hci_event_pkt_t* e, bool verbose) 10503ac41cceSTakanori Watanabe { 10513ac41cceSTakanori Watanabe ng_hci_le_ep *ev_pkt; 10523ac41cceSTakanori Watanabe ng_hci_le_connection_complete_ep *conn_event; 10533ac41cceSTakanori Watanabe 10543ac41cceSTakanori Watanabe ev_pkt = (ng_hci_le_ep *)(e + 1); 10553ac41cceSTakanori Watanabe 10563ac41cceSTakanori Watanabe if (ev_pkt->subevent_code == NG_HCI_LEEV_CON_COMPL) { 10573ac41cceSTakanori Watanabe conn_event =(ng_hci_le_connection_complete_ep *)(ev_pkt + 1); 10583ac41cceSTakanori Watanabe fprintf(stdout, "Handle: %d\n", le16toh(conn_event->handle)); 10593ac41cceSTakanori Watanabe if (verbose) { 10603ac41cceSTakanori Watanabe fprintf(stdout, 10613ac41cceSTakanori Watanabe "Status: %s\n", 10623ac41cceSTakanori Watanabe hci_status2str(conn_event->status)); 10633ac41cceSTakanori Watanabe fprintf(stdout, 10643ac41cceSTakanori Watanabe "Role: %s\n", 10653ac41cceSTakanori Watanabe hci_role2str(conn_event->role)); 10663ac41cceSTakanori Watanabe fprintf(stdout, 10673ac41cceSTakanori Watanabe "Address Type: %s\n", 10683ac41cceSTakanori Watanabe hci_addrtype2str(conn_event->address_type)); 10693ac41cceSTakanori Watanabe fprintf(stdout, 10703ac41cceSTakanori Watanabe "Address: %s\n", 10713ac41cceSTakanori Watanabe hci_bdaddr2str(&conn_event->address)); 10723ac41cceSTakanori Watanabe fprintf(stdout, 10733ac41cceSTakanori Watanabe "Interval: %.2fms\n", 10743ac41cceSTakanori Watanabe 6.25 * le16toh(conn_event->interval)); 10753ac41cceSTakanori Watanabe fprintf(stdout, 10763ac41cceSTakanori Watanabe "Latency: %d events\n", conn_event->latency); 10773ac41cceSTakanori Watanabe fprintf(stdout, 10783ac41cceSTakanori Watanabe "Supervision timeout: %dms\n", 10793ac41cceSTakanori Watanabe 10 * le16toh(conn_event->supervision_timeout)); 10803ac41cceSTakanori Watanabe fprintf(stdout, 1081*f8143ed7STakanori Watanabe "Master clock accuracy: %s\n", 10823ac41cceSTakanori Watanabe hci_mc_accuracy2str( 10833ac41cceSTakanori Watanabe conn_event->master_clock_accuracy)); 10843ac41cceSTakanori Watanabe } 10853ac41cceSTakanori Watanabe } 10863ac41cceSTakanori Watanabe return; 10873ac41cceSTakanori Watanabe } 10883ac41cceSTakanori Watanabe 1089bcff2d91STakanori Watanabe struct hci_command le_commands[] = { 1090bcff2d91STakanori Watanabe { 1091bcff2d91STakanori Watanabe "le_enable", 1092bcff2d91STakanori Watanabe "le_enable [enable|disable] \n" 1093bcff2d91STakanori Watanabe "Enable LE event ", 1094bcff2d91STakanori Watanabe &le_enable, 1095bcff2d91STakanori Watanabe }, 1096bcff2d91STakanori Watanabe { 1097bcff2d91STakanori Watanabe "le_read_local_supported_features", 1098bcff2d91STakanori Watanabe "le_read_local_supported_features\n" 1099bcff2d91STakanori Watanabe "read local supported features mask", 1100bcff2d91STakanori Watanabe &le_read_local_supported_features, 1101bcff2d91STakanori Watanabe }, 1102bcff2d91STakanori Watanabe { 110321eefd31SHans Petter Selasky "le_read_supported_states", 110421eefd31SHans Petter Selasky "le_read_supported_states\n" 1105bcff2d91STakanori Watanabe "read supported status" 1106bcff2d91STakanori Watanabe , 110721eefd31SHans Petter Selasky &le_read_supported_states, 1108bcff2d91STakanori Watanabe }, 1109bcff2d91STakanori Watanabe { 1110bcff2d91STakanori Watanabe "le_set_scan_response", 1111bcff2d91STakanori Watanabe "le_set_scan_response -n $name -f $flag -u $uuid16,$uuid16 \n" 1112bcff2d91STakanori Watanabe "set LE scan response data" 1113bcff2d91STakanori Watanabe , 1114bcff2d91STakanori Watanabe &le_set_scan_response, 1115bcff2d91STakanori Watanabe }, 1116bcff2d91STakanori Watanabe { 1117bcff2d91STakanori Watanabe "le_set_scan_enable", 1118bcff2d91STakanori Watanabe "le_set_scan_enable [enable|disable] \n" 1119bcff2d91STakanori Watanabe "enable or disable LE device scan", 1120bcff2d91STakanori Watanabe &le_set_scan_enable 1121bcff2d91STakanori Watanabe }, 1122bcff2d91STakanori Watanabe { 1123bcff2d91STakanori Watanabe "le_set_scan_param", 1124bcff2d91STakanori Watanabe "le_set_scan_param [active|passive] interval(ms) window(ms) [public|random] [all|whitelist] \n" 1125bcff2d91STakanori Watanabe "set LE device scan parameter", 1126bcff2d91STakanori Watanabe &le_set_scan_param 1127bcff2d91STakanori Watanabe }, 1128c3f60abcSHans Petter Selasky { 1129c3f60abcSHans Petter Selasky "le_set_advertising_enable", 1130c3f60abcSHans Petter Selasky "le_set_advertising_enable [enable|disable] \n" 1131c3f60abcSHans Petter Selasky "start or stop advertising", 1132c3f60abcSHans Petter Selasky &le_set_advertising_enable 1133c3f60abcSHans Petter Selasky }, 1134c3f60abcSHans Petter Selasky { 1135c3f60abcSHans Petter Selasky "le_read_advertising_channel_tx_power", 1136c3f60abcSHans Petter Selasky "le_read_advertising_channel_tx_power\n" 1137c3f60abcSHans Petter Selasky "read host advertising transmit poser level (dBm)", 1138c3f60abcSHans Petter Selasky &le_read_advertising_channel_tx_power 1139c3f60abcSHans Petter Selasky }, 1140c3f60abcSHans Petter Selasky { 1141c3f60abcSHans Petter Selasky "le_set_advertising_param", 1142c3f60abcSHans Petter Selasky "le_set_advertising_param [-m min_interval(ms)] [-M max_interval(ms)]\n" 1143c3f60abcSHans Petter Selasky "[-t advertising_type] [-o own_address_type] [-p peer_address_type]\n" 1144c3f60abcSHans Petter Selasky "[-c advertising_channel_map] [-f advertising_filter_policy]\n" 1145c3f60abcSHans Petter Selasky "[-a peer_address]\n" 1146c3f60abcSHans Petter Selasky "set LE device advertising parameters", 1147c3f60abcSHans Petter Selasky &le_set_advertising_param 1148c3f60abcSHans Petter Selasky }, 1149c3f60abcSHans Petter Selasky { 1150c3f60abcSHans Petter Selasky "le_set_advertising_data", 1151c3f60abcSHans Petter Selasky "le_set_advertising_data -n $name -f $flag -u $uuid16,$uuid16 \n" 1152c3f60abcSHans Petter Selasky "set LE device advertising packed data", 1153c3f60abcSHans Petter Selasky &le_set_advertising_data 1154c3f60abcSHans Petter Selasky }, 11551f5d883dSTakanori Watanabe { 11561f5d883dSTakanori Watanabe "le_read_buffer_size", 11571f5d883dSTakanori Watanabe "le_read_buffer_size [-v 1|2]\n" 11581f5d883dSTakanori Watanabe "Read the maximum size of ACL and ISO data packets", 11591f5d883dSTakanori Watanabe &le_read_buffer_size 11601f5d883dSTakanori Watanabe }, 11619287f06dSTakanori Watanabe { 11629287f06dSTakanori Watanabe "le_scan", 11639287f06dSTakanori Watanabe "le_scan [-a] [-v] [-n number_of_scans]\n" 11649287f06dSTakanori Watanabe "Do an LE scan", 11659287f06dSTakanori Watanabe &le_scan 11669287f06dSTakanori Watanabe }, 116711fb4bdbSTakanori Watanabe { 116811fb4bdbSTakanori Watanabe "le_read_white_list_size", 116911fb4bdbSTakanori Watanabe "le_read_white_list_size\n" 117011fb4bdbSTakanori Watanabe "Read total number of white list entries that can be stored", 117111fb4bdbSTakanori Watanabe &le_read_white_list_size 117211fb4bdbSTakanori Watanabe }, 117311fb4bdbSTakanori Watanabe { 117411fb4bdbSTakanori Watanabe "le_clear_white_list", 117511fb4bdbSTakanori Watanabe "le_clear_white_list\n" 117611fb4bdbSTakanori Watanabe "Clear the white list in the controller", 117711fb4bdbSTakanori Watanabe &le_clear_white_list 117811fb4bdbSTakanori Watanabe }, 117911fb4bdbSTakanori Watanabe { 118011fb4bdbSTakanori Watanabe "le_add_device_to_white_list", 118111fb4bdbSTakanori Watanabe "le_add_device_to_white_list\n" 118211fb4bdbSTakanori Watanabe "[-t public|random] -a address\n" 118311fb4bdbSTakanori Watanabe "Add device to the white list", 118411fb4bdbSTakanori Watanabe &le_add_device_to_white_list 118511fb4bdbSTakanori Watanabe }, 118611fb4bdbSTakanori Watanabe { 118711fb4bdbSTakanori Watanabe "le_remove_device_from_white_list", 118811fb4bdbSTakanori Watanabe "le_remove_device_from_white_list\n" 118911fb4bdbSTakanori Watanabe "[-t public|random] -a address\n" 119011fb4bdbSTakanori Watanabe "Remove device from the white list", 119111fb4bdbSTakanori Watanabe &le_remove_device_from_white_list 119211fb4bdbSTakanori Watanabe }, 11933ac41cceSTakanori Watanabe { 11943ac41cceSTakanori Watanabe "le_connect", 11953ac41cceSTakanori Watanabe "le_connect -a address [-t public|random] [-v]\n" 11963ac41cceSTakanori Watanabe "Connect to an LE device", 11973ac41cceSTakanori Watanabe &le_connect 11983ac41cceSTakanori Watanabe }, 1199bcff2d91STakanori Watanabe }; 1200