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> 42*9287f06dSTakanori 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[]); 64*9287f06dSTakanori Watanabe static int le_scan(int s, int argc, char *argv[]); 65*9287f06dSTakanori Watanabe static void handle_le_event(ng_hci_event_pkt_t* e, bool verbose); 66bcff2d91STakanori Watanabe 679c3471faSMarcelo Araujo static int 689c3471faSMarcelo Araujo le_set_scan_param(int s, int argc, char *argv[]) 69bcff2d91STakanori Watanabe { 70bcff2d91STakanori Watanabe int type; 71bcff2d91STakanori Watanabe int interval; 72bcff2d91STakanori Watanabe int window; 73bcff2d91STakanori Watanabe int adrtype; 74bcff2d91STakanori Watanabe int policy; 75eb2aebeaSTakanori Watanabe int n; 76bcff2d91STakanori Watanabe 77bcff2d91STakanori Watanabe ng_hci_le_set_scan_parameters_cp cp; 78bcff2d91STakanori Watanabe ng_hci_le_set_scan_parameters_rp rp; 79bcff2d91STakanori Watanabe 809c3471faSMarcelo Araujo if (argc != 5) 81eb2aebeaSTakanori Watanabe return (USAGE); 82bcff2d91STakanori Watanabe 839c3471faSMarcelo Araujo if (strcmp(argv[0], "active") == 0) 84bcff2d91STakanori Watanabe type = 1; 859c3471faSMarcelo Araujo else if (strcmp(argv[0], "passive") == 0) 86bcff2d91STakanori Watanabe type = 0; 879c3471faSMarcelo Araujo else 88eb2aebeaSTakanori Watanabe return (USAGE); 89bcff2d91STakanori Watanabe 90bcff2d91STakanori Watanabe interval = (int)(atof(argv[1])/0.625); 91bcff2d91STakanori Watanabe interval = (interval < 4)? 4: interval; 92bcff2d91STakanori Watanabe window = (int)(atof(argv[2])/0.625); 93bcff2d91STakanori Watanabe window = (window < 4) ? 4 : interval; 94bcff2d91STakanori Watanabe 959c3471faSMarcelo Araujo if (strcmp(argv[3], "public") == 0) 96bcff2d91STakanori Watanabe adrtype = 0; 9705e526fbSTakanori Watanabe else if (strcmp(argv[3], "random") == 0) 98bcff2d91STakanori Watanabe adrtype = 1; 999c3471faSMarcelo Araujo else 100eb2aebeaSTakanori Watanabe return (USAGE); 101bcff2d91STakanori Watanabe 1029c3471faSMarcelo Araujo if (strcmp(argv[4], "all") == 0) 103bcff2d91STakanori Watanabe policy = 0; 1049c3471faSMarcelo Araujo else if (strcmp(argv[4], "whitelist") == 0) 105bcff2d91STakanori Watanabe policy = 1; 1069c3471faSMarcelo Araujo else 107eb2aebeaSTakanori Watanabe return (USAGE); 108bcff2d91STakanori Watanabe 109bcff2d91STakanori Watanabe cp.le_scan_type = type; 110bcff2d91STakanori Watanabe cp.le_scan_interval = interval; 111bcff2d91STakanori Watanabe cp.own_address_type = adrtype; 112bcff2d91STakanori Watanabe cp.le_scan_window = window; 113bcff2d91STakanori Watanabe cp.scanning_filter_policy = policy; 114bcff2d91STakanori Watanabe n = sizeof(rp); 115bcff2d91STakanori Watanabe 116eb2aebeaSTakanori Watanabe if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE, 117eb2aebeaSTakanori Watanabe NG_HCI_OCF_LE_SET_SCAN_PARAMETERS), 118eb2aebeaSTakanori Watanabe (void *)&cp, sizeof(cp), (void *)&rp, &n) == ERROR) 119eb2aebeaSTakanori Watanabe return (ERROR); 120eb2aebeaSTakanori Watanabe 121eb2aebeaSTakanori Watanabe if (rp.status != 0x00) { 122eb2aebeaSTakanori Watanabe fprintf(stdout, "Status: %s [%#02x]\n", 123eb2aebeaSTakanori Watanabe hci_status2str(rp.status), rp.status); 124eb2aebeaSTakanori Watanabe return (FAILED); 125eb2aebeaSTakanori Watanabe } 126eb2aebeaSTakanori Watanabe 127eb2aebeaSTakanori Watanabe return (OK); 128bcff2d91STakanori Watanabe } 129bcff2d91STakanori Watanabe 1309c3471faSMarcelo Araujo static int 1319c3471faSMarcelo Araujo le_set_scan_enable(int s, int argc, char *argv[]) 132bcff2d91STakanori Watanabe { 133bcff2d91STakanori Watanabe ng_hci_le_set_scan_enable_cp cp; 134bcff2d91STakanori Watanabe ng_hci_le_set_scan_enable_rp rp; 135eb2aebeaSTakanori Watanabe int n, enable = 0; 136bcff2d91STakanori Watanabe 137bcff2d91STakanori Watanabe if (argc != 1) 138eb2aebeaSTakanori Watanabe return (USAGE); 139bcff2d91STakanori Watanabe 1409c3471faSMarcelo Araujo if (strcmp(argv[0], "enable") == 0) 141bcff2d91STakanori Watanabe enable = 1; 1429c3471faSMarcelo Araujo else if (strcmp(argv[0], "disable") != 0) 143eb2aebeaSTakanori Watanabe return (USAGE); 1449c3471faSMarcelo Araujo 145bcff2d91STakanori Watanabe n = sizeof(rp); 146bcff2d91STakanori Watanabe cp.le_scan_enable = enable; 147bcff2d91STakanori Watanabe cp.filter_duplicates = 0; 148eb2aebeaSTakanori Watanabe if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE, 149bcff2d91STakanori Watanabe NG_HCI_OCF_LE_SET_SCAN_ENABLE), 150eb2aebeaSTakanori Watanabe (void *)&cp, sizeof(cp), 151eb2aebeaSTakanori Watanabe (void *)&rp, &n) == ERROR) 152eb2aebeaSTakanori Watanabe return (ERROR); 153bcff2d91STakanori Watanabe 154eb2aebeaSTakanori Watanabe if (rp.status != 0x00) { 155eb2aebeaSTakanori Watanabe fprintf(stdout, "Status: %s [%#02x]\n", 156eb2aebeaSTakanori Watanabe hci_status2str(rp.status), rp.status); 157eb2aebeaSTakanori Watanabe return (FAILED); 158eb2aebeaSTakanori Watanabe } 159bcff2d91STakanori Watanabe 160eb2aebeaSTakanori Watanabe fprintf(stdout, "LE Scan: %s\n", 161eb2aebeaSTakanori Watanabe enable? "Enabled" : "Disabled"); 162eb2aebeaSTakanori Watanabe 163eb2aebeaSTakanori Watanabe return (OK); 164bcff2d91STakanori Watanabe } 1659c3471faSMarcelo Araujo 1669c3471faSMarcelo Araujo static int 1679c3471faSMarcelo Araujo parse_param(int argc, char *argv[], char *buf, int *len) 168bcff2d91STakanori Watanabe { 169bcff2d91STakanori Watanabe char *buflast = buf + (*len); 170bcff2d91STakanori Watanabe char *curbuf = buf; 171bcff2d91STakanori Watanabe char *token,*lenpos; 172bcff2d91STakanori Watanabe int ch; 173bcff2d91STakanori Watanabe int datalen; 174bcff2d91STakanori Watanabe uint16_t value; 175bcff2d91STakanori Watanabe optreset = 1; 176bcff2d91STakanori Watanabe optind = 0; 177bcff2d91STakanori Watanabe while ((ch = getopt(argc, argv , "n:f:u:")) != -1) { 178bcff2d91STakanori Watanabe switch(ch){ 179bcff2d91STakanori Watanabe case 'n': 180bcff2d91STakanori Watanabe datalen = strlen(optarg); 1819c3471faSMarcelo Araujo if ((curbuf + datalen + 2) >= buflast) 182bcff2d91STakanori Watanabe goto done; 183bcff2d91STakanori Watanabe curbuf[0] = datalen + 1; 184bcff2d91STakanori Watanabe curbuf[1] = 8; 185bcff2d91STakanori Watanabe curbuf += 2; 186bcff2d91STakanori Watanabe memcpy(curbuf, optarg, datalen); 187bcff2d91STakanori Watanabe curbuf += datalen; 188bcff2d91STakanori Watanabe break; 189bcff2d91STakanori Watanabe case 'f': 1909c3471faSMarcelo Araujo if (curbuf+3 > buflast) 191bcff2d91STakanori Watanabe goto done; 192bcff2d91STakanori Watanabe curbuf[0] = 2; 193bcff2d91STakanori Watanabe curbuf[1] = 1; 19432f32669SHans Petter Selasky curbuf[2] = (uint8_t)strtol(optarg, NULL, 16); 195bcff2d91STakanori Watanabe curbuf += 3; 196bcff2d91STakanori Watanabe break; 197bcff2d91STakanori Watanabe case 'u': 198bcff2d91STakanori Watanabe if ((buf+2) >= buflast) 199bcff2d91STakanori Watanabe goto done; 20032f32669SHans Petter Selasky lenpos = curbuf; 201bcff2d91STakanori Watanabe curbuf[1] = 2; 202bcff2d91STakanori Watanabe *lenpos = 1; 203bcff2d91STakanori Watanabe curbuf += 2; 204bcff2d91STakanori Watanabe while ((token = strsep(&optarg, ",")) != NULL) { 205bcff2d91STakanori Watanabe value = strtol(token, NULL, 16); 206bcff2d91STakanori Watanabe if ((curbuf+2) >= buflast) 207bcff2d91STakanori Watanabe break; 208bcff2d91STakanori Watanabe curbuf[0] = value &0xff; 209bcff2d91STakanori Watanabe curbuf[1] = (value>>8)&0xff; 210bcff2d91STakanori Watanabe curbuf += 2; 21132f32669SHans Petter Selasky *lenpos += 2; 212bcff2d91STakanori Watanabe } 213bcff2d91STakanori Watanabe 214bcff2d91STakanori Watanabe } 215bcff2d91STakanori Watanabe } 216bcff2d91STakanori Watanabe done: 217bcff2d91STakanori Watanabe *len = curbuf - buf; 218bcff2d91STakanori Watanabe 219eb2aebeaSTakanori Watanabe return (OK); 220bcff2d91STakanori Watanabe } 221bcff2d91STakanori Watanabe 2229c3471faSMarcelo Araujo static int 2239c3471faSMarcelo Araujo le_set_scan_response(int s, int argc, char *argv[]) 224bcff2d91STakanori Watanabe { 225bcff2d91STakanori Watanabe ng_hci_le_set_scan_response_data_cp cp; 226bcff2d91STakanori Watanabe ng_hci_le_set_scan_response_data_rp rp; 227bcff2d91STakanori Watanabe int n; 228bcff2d91STakanori Watanabe int len; 229bcff2d91STakanori Watanabe char buf[NG_HCI_ADVERTISING_DATA_SIZE]; 2309c3471faSMarcelo Araujo 231bcff2d91STakanori Watanabe len = sizeof(buf); 232bcff2d91STakanori Watanabe parse_param(argc, argv, buf, &len); 233bcff2d91STakanori Watanabe memset(cp.scan_response_data, 0, sizeof(cp.scan_response_data)); 234bcff2d91STakanori Watanabe cp.scan_response_data_length = len; 235bcff2d91STakanori Watanabe memcpy(cp.scan_response_data, buf, len); 236bcff2d91STakanori Watanabe n = sizeof(rp); 237eb2aebeaSTakanori Watanabe if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE, 238bcff2d91STakanori Watanabe NG_HCI_OCF_LE_SET_SCAN_RESPONSE_DATA), 239eb2aebeaSTakanori Watanabe (void *)&cp, sizeof(cp), 240eb2aebeaSTakanori Watanabe (void *)&rp, &n) == ERROR) 241eb2aebeaSTakanori Watanabe return (ERROR); 242bcff2d91STakanori Watanabe 243eb2aebeaSTakanori Watanabe if (rp.status != 0x00) { 244eb2aebeaSTakanori Watanabe fprintf(stdout, "Status: %s [%#02x]\n", 245eb2aebeaSTakanori Watanabe hci_status2str(rp.status), rp.status); 246eb2aebeaSTakanori Watanabe return (FAILED); 247eb2aebeaSTakanori Watanabe } 248bcff2d91STakanori Watanabe 249eb2aebeaSTakanori Watanabe return (OK); 250bcff2d91STakanori Watanabe } 251bcff2d91STakanori Watanabe 2529c3471faSMarcelo Araujo static int 2539c3471faSMarcelo Araujo le_read_local_supported_features(int s, int argc ,char *argv[]) 254bcff2d91STakanori Watanabe { 255bcff2d91STakanori Watanabe ng_hci_le_read_local_supported_features_rp rp; 256bcff2d91STakanori Watanabe int n = sizeof(rp); 2579c3471faSMarcelo Araujo 258ea011491SHans Petter Selasky union { 259ea011491SHans Petter Selasky uint64_t raw; 260ea011491SHans Petter Selasky uint8_t octets[8]; 261ea011491SHans Petter Selasky } le_features; 262ea011491SHans Petter Selasky 263ea011491SHans Petter Selasky char buffer[2048]; 264ea011491SHans Petter Selasky 265ea011491SHans Petter Selasky if (hci_simple_request(s, 266bcff2d91STakanori Watanabe NG_HCI_OPCODE(NG_HCI_OGF_LE, 267bcff2d91STakanori Watanabe NG_HCI_OCF_LE_READ_LOCAL_SUPPORTED_FEATURES), 268ea011491SHans Petter Selasky (void *)&rp, &n) == ERROR) 269ea011491SHans Petter Selasky return (ERROR); 2709c3471faSMarcelo Araujo 271ea011491SHans Petter Selasky if (rp.status != 0x00) { 272ea011491SHans Petter Selasky fprintf(stdout, "Status: %s [%#02x]\n", 273ea011491SHans Petter Selasky hci_status2str(rp.status), rp.status); 274ea011491SHans Petter Selasky return (FAILED); 275ea011491SHans Petter Selasky } 276bcff2d91STakanori Watanabe 277ea011491SHans Petter Selasky le_features.raw = rp.le_features; 278ea011491SHans Petter Selasky 279ea011491SHans Petter Selasky fprintf(stdout, "LE Features: "); 280ea011491SHans Petter Selasky for(int i = 0; i < 8; i++) 281ea011491SHans Petter Selasky fprintf(stdout, " %#02x", le_features.octets[i]); 282ea011491SHans Petter Selasky fprintf(stdout, "\n%s\n", hci_le_features2str(le_features.octets, 283ea011491SHans Petter Selasky buffer, sizeof(buffer))); 284ea011491SHans Petter Selasky fprintf(stdout, "\n"); 285ea011491SHans Petter Selasky 286eb2aebeaSTakanori Watanabe return (OK); 287bcff2d91STakanori Watanabe } 2889c3471faSMarcelo Araujo 2899c3471faSMarcelo Araujo static int 29021eefd31SHans Petter Selasky le_read_supported_states(int s, int argc, char *argv[]) 291bcff2d91STakanori Watanabe { 29221eefd31SHans Petter Selasky ng_hci_le_read_supported_states_rp rp; 293bcff2d91STakanori Watanabe int n = sizeof(rp); 2949c3471faSMarcelo Araujo 29521eefd31SHans Petter Selasky if (hci_simple_request(s, NG_HCI_OPCODE( 2969c3471faSMarcelo Araujo NG_HCI_OGF_LE, 29721eefd31SHans Petter Selasky NG_HCI_OCF_LE_READ_SUPPORTED_STATES), 29821eefd31SHans Petter Selasky (void *)&rp, &n) == ERROR) 29921eefd31SHans Petter Selasky return (ERROR); 3009c3471faSMarcelo Araujo 30121eefd31SHans Petter Selasky if (rp.status != 0x00) { 30221eefd31SHans Petter Selasky fprintf(stdout, "Status: %s [%#02x]\n", 30321eefd31SHans Petter Selasky hci_status2str(rp.status), rp.status); 30421eefd31SHans Petter Selasky return (FAILED); 30521eefd31SHans Petter Selasky } 306bcff2d91STakanori Watanabe 30721eefd31SHans Petter Selasky fprintf(stdout, "LE States: %jx\n", rp.le_states); 30821eefd31SHans Petter Selasky 30921eefd31SHans Petter Selasky return (OK); 310bcff2d91STakanori Watanabe } 311bcff2d91STakanori Watanabe 3129c3471faSMarcelo Araujo static int 3139c3471faSMarcelo Araujo set_le_event_mask(int s, uint64_t mask) 314bcff2d91STakanori Watanabe { 315bcff2d91STakanori Watanabe ng_hci_le_set_event_mask_cp semc; 316bcff2d91STakanori Watanabe ng_hci_le_set_event_mask_rp rp; 317eb2aebeaSTakanori Watanabe int i, n; 318bcff2d91STakanori Watanabe 319bcff2d91STakanori Watanabe n = sizeof(rp); 320bcff2d91STakanori Watanabe 321bcff2d91STakanori Watanabe for (i=0; i < NG_HCI_LE_EVENT_MASK_SIZE; i++) { 322bcff2d91STakanori Watanabe semc.event_mask[i] = mask&0xff; 323bcff2d91STakanori Watanabe mask >>= 8; 324bcff2d91STakanori Watanabe } 325eb2aebeaSTakanori Watanabe if(hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE, 3269c3471faSMarcelo Araujo NG_HCI_OCF_LE_SET_EVENT_MASK), 327eb2aebeaSTakanori Watanabe (void *)&semc, sizeof(semc), (void *)&rp, &n) == ERROR) 328eb2aebeaSTakanori Watanabe return (ERROR); 329bcff2d91STakanori Watanabe 330eb2aebeaSTakanori Watanabe if (rp.status != 0x00) { 331eb2aebeaSTakanori Watanabe fprintf(stdout, "Status: %s [%#02x]\n", 332eb2aebeaSTakanori Watanabe hci_status2str(rp.status), rp.status); 333eb2aebeaSTakanori Watanabe return (FAILED); 334eb2aebeaSTakanori Watanabe } 335eb2aebeaSTakanori Watanabe 336eb2aebeaSTakanori Watanabe return (OK); 337bcff2d91STakanori Watanabe } 338bcff2d91STakanori Watanabe 3399c3471faSMarcelo Araujo static int 3409c3471faSMarcelo Araujo set_event_mask(int s, uint64_t mask) 341bcff2d91STakanori Watanabe { 342bcff2d91STakanori Watanabe ng_hci_set_event_mask_cp semc; 343bcff2d91STakanori Watanabe ng_hci_set_event_mask_rp rp; 344eb2aebeaSTakanori Watanabe int i, n; 345bcff2d91STakanori Watanabe 346bcff2d91STakanori Watanabe n = sizeof(rp); 347bcff2d91STakanori Watanabe 348bcff2d91STakanori Watanabe for (i=0; i < NG_HCI_EVENT_MASK_SIZE; i++) { 349bcff2d91STakanori Watanabe semc.event_mask[i] = mask&0xff; 350bcff2d91STakanori Watanabe mask >>= 8; 351bcff2d91STakanori Watanabe } 352eb2aebeaSTakanori Watanabe if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND, 3539c3471faSMarcelo Araujo NG_HCI_OCF_SET_EVENT_MASK), 354eb2aebeaSTakanori Watanabe (void *)&semc, sizeof(semc), (void *)&rp, &n) == ERROR) 355eb2aebeaSTakanori Watanabe return (ERROR); 356bcff2d91STakanori Watanabe 357eb2aebeaSTakanori Watanabe if (rp.status != 0x00) { 358eb2aebeaSTakanori Watanabe fprintf(stdout, "Status: %s [%#02x]\n", 359eb2aebeaSTakanori Watanabe hci_status2str(rp.status), rp.status); 360eb2aebeaSTakanori Watanabe return (FAILED); 361eb2aebeaSTakanori Watanabe } 362eb2aebeaSTakanori Watanabe 363eb2aebeaSTakanori Watanabe return (OK); 364bcff2d91STakanori Watanabe } 365bcff2d91STakanori Watanabe 3669c3471faSMarcelo Araujo static 3679c3471faSMarcelo Araujo int le_enable(int s, int argc, char *argv[]) 368bcff2d91STakanori Watanabe { 369eb2aebeaSTakanori Watanabe int result; 370eb2aebeaSTakanori Watanabe 3719c3471faSMarcelo Araujo if (argc != 1) 372eb2aebeaSTakanori Watanabe return (USAGE); 373bcff2d91STakanori Watanabe 374bcff2d91STakanori Watanabe if (strcasecmp(argv[0], "enable") == 0) { 375eb2aebeaSTakanori Watanabe result = set_event_mask(s, NG_HCI_EVENT_MASK_DEFAULT | 376bcff2d91STakanori Watanabe NG_HCI_EVENT_MASK_LE); 377eb2aebeaSTakanori Watanabe if (result != OK) 378eb2aebeaSTakanori Watanabe return result; 379eb2aebeaSTakanori Watanabe result = set_le_event_mask(s, NG_HCI_LE_EVENT_MASK_ALL); 380eb2aebeaSTakanori Watanabe if (result == OK) { 381eb2aebeaSTakanori Watanabe fprintf(stdout, "LE enabled\n"); 382eb2aebeaSTakanori Watanabe return (OK); 383eb2aebeaSTakanori Watanabe } else 384eb2aebeaSTakanori Watanabe return result; 385eb2aebeaSTakanori Watanabe } else if (strcasecmp(argv[0], "disable") == 0) { 386eb2aebeaSTakanori Watanabe result = set_event_mask(s, NG_HCI_EVENT_MASK_DEFAULT); 387eb2aebeaSTakanori Watanabe if (result == OK) { 388eb2aebeaSTakanori Watanabe fprintf(stdout, "LE disabled\n"); 389eb2aebeaSTakanori Watanabe return (OK); 390eb2aebeaSTakanori Watanabe } else 391eb2aebeaSTakanori Watanabe return result; 392eb2aebeaSTakanori Watanabe } else 393eb2aebeaSTakanori Watanabe return (USAGE); 394bcff2d91STakanori Watanabe } 395bcff2d91STakanori Watanabe 396c3f60abcSHans Petter Selasky static int 397c3f60abcSHans Petter Selasky le_set_advertising_enable(int s, int argc, char *argv[]) 398c3f60abcSHans Petter Selasky { 399c3f60abcSHans Petter Selasky ng_hci_le_set_advertise_enable_cp cp; 400c3f60abcSHans Petter Selasky ng_hci_le_set_advertise_enable_rp rp; 401c3f60abcSHans Petter Selasky int n, enable = 0; 402c3f60abcSHans Petter Selasky 403c3f60abcSHans Petter Selasky if (argc != 1) 404c3f60abcSHans Petter Selasky return USAGE; 405c3f60abcSHans Petter Selasky 406c3f60abcSHans Petter Selasky if (strcmp(argv[0], "enable") == 0) 407c3f60abcSHans Petter Selasky enable = 1; 408c3f60abcSHans Petter Selasky else if (strcmp(argv[0], "disable") != 0) 409c3f60abcSHans Petter Selasky return USAGE; 410c3f60abcSHans Petter Selasky 411c3f60abcSHans Petter Selasky n = sizeof(rp); 412c3f60abcSHans Petter Selasky cp.advertising_enable = enable; 413c3f60abcSHans Petter Selasky if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE, 414c3f60abcSHans Petter Selasky NG_HCI_OCF_LE_SET_ADVERTISE_ENABLE), 415c3f60abcSHans Petter Selasky (void *)&cp, sizeof(cp), (void *)&rp, &n) == ERROR) 416c3f60abcSHans Petter Selasky return (ERROR); 417c3f60abcSHans Petter Selasky 418c3f60abcSHans Petter Selasky if (rp.status != 0x00) { 419c3f60abcSHans Petter Selasky fprintf(stdout, "Status: %s [%#02x]\n", 420c3f60abcSHans Petter Selasky hci_status2str(rp.status), rp.status); 421c3f60abcSHans Petter Selasky return (FAILED); 422c3f60abcSHans Petter Selasky } 423c3f60abcSHans Petter Selasky fprintf(stdout, "LE Advertising %s\n", (enable ? "enabled" : "disabled")); 424c3f60abcSHans Petter Selasky 425c3f60abcSHans Petter Selasky return (OK); 426c3f60abcSHans Petter Selasky } 427c3f60abcSHans Petter Selasky 428c3f60abcSHans Petter Selasky static int 429c3f60abcSHans Petter Selasky le_set_advertising_param(int s, int argc, char *argv[]) 430c3f60abcSHans Petter Selasky { 431c3f60abcSHans Petter Selasky ng_hci_le_set_advertising_parameters_cp cp; 432c3f60abcSHans Petter Selasky ng_hci_le_set_advertising_parameters_rp rp; 433c3f60abcSHans Petter Selasky 434c3f60abcSHans Petter Selasky int n, ch; 435c3f60abcSHans Petter Selasky 436c3f60abcSHans Petter Selasky cp.advertising_interval_min = 0x800; 437c3f60abcSHans Petter Selasky cp.advertising_interval_max = 0x800; 438c3f60abcSHans Petter Selasky cp.advertising_type = 0; 439c3f60abcSHans Petter Selasky cp.own_address_type = 0; 440c3f60abcSHans Petter Selasky cp.direct_address_type = 0; 441c3f60abcSHans Petter Selasky 442c3f60abcSHans Petter Selasky cp.advertising_channel_map = 7; 443c3f60abcSHans Petter Selasky cp.advertising_filter_policy = 0; 444c3f60abcSHans Petter Selasky 445c3f60abcSHans Petter Selasky optreset = 1; 446c3f60abcSHans Petter Selasky optind = 0; 447c3f60abcSHans Petter Selasky while ((ch = getopt(argc, argv , "m:M:t:o:p:a:c:f:")) != -1) { 448c3f60abcSHans Petter Selasky switch(ch) { 449c3f60abcSHans Petter Selasky case 'm': 450c3f60abcSHans Petter Selasky cp.advertising_interval_min = 451c3f60abcSHans Petter Selasky (uint16_t)(strtod(optarg, NULL)/0.625); 452c3f60abcSHans Petter Selasky break; 453c3f60abcSHans Petter Selasky case 'M': 454c3f60abcSHans Petter Selasky cp.advertising_interval_max = 455c3f60abcSHans Petter Selasky (uint16_t)(strtod(optarg, NULL)/0.625); 456c3f60abcSHans Petter Selasky break; 457c3f60abcSHans Petter Selasky case 't': 458c3f60abcSHans Petter Selasky cp.advertising_type = 459c3f60abcSHans Petter Selasky (uint8_t)strtod(optarg, NULL); 460c3f60abcSHans Petter Selasky break; 461c3f60abcSHans Petter Selasky case 'o': 462c3f60abcSHans Petter Selasky cp.own_address_type = 463c3f60abcSHans Petter Selasky (uint8_t)strtod(optarg, NULL); 464c3f60abcSHans Petter Selasky break; 465c3f60abcSHans Petter Selasky case 'p': 466c3f60abcSHans Petter Selasky cp.direct_address_type = 467c3f60abcSHans Petter Selasky (uint8_t)strtod(optarg, NULL); 468c3f60abcSHans Petter Selasky break; 469c3f60abcSHans Petter Selasky case 'a': 470c3f60abcSHans Petter Selasky if (!bt_aton(optarg, &cp.direct_address)) { 471c3f60abcSHans Petter Selasky struct hostent *he = NULL; 472c3f60abcSHans Petter Selasky 473c3f60abcSHans Petter Selasky if ((he = bt_gethostbyname(optarg)) == NULL) 474c3f60abcSHans Petter Selasky return (USAGE); 475c3f60abcSHans Petter Selasky 476c3f60abcSHans Petter Selasky memcpy(&cp.direct_address, he->h_addr, sizeof(cp.direct_address)); 477c3f60abcSHans Petter Selasky } 478c3f60abcSHans Petter Selasky break; 479c3f60abcSHans Petter Selasky case 'c': 480c3f60abcSHans Petter Selasky cp.advertising_channel_map = 481c3f60abcSHans Petter Selasky (uint8_t)strtod(optarg, NULL); 482c3f60abcSHans Petter Selasky break; 483c3f60abcSHans Petter Selasky case 'f': 484c3f60abcSHans Petter Selasky cp.advertising_filter_policy = 485c3f60abcSHans Petter Selasky (uint8_t)strtod(optarg, NULL); 486c3f60abcSHans Petter Selasky break; 487c3f60abcSHans Petter Selasky } 488c3f60abcSHans Petter Selasky } 489c3f60abcSHans Petter Selasky 490c3f60abcSHans Petter Selasky n = sizeof(rp); 491c3f60abcSHans Petter Selasky if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE, 492c3f60abcSHans Petter Selasky NG_HCI_OCF_LE_SET_ADVERTISING_PARAMETERS), 493c3f60abcSHans Petter Selasky (void *)&cp, sizeof(cp), (void *)&rp, &n) == ERROR) 494c3f60abcSHans Petter Selasky return (ERROR); 495c3f60abcSHans Petter Selasky 496c3f60abcSHans Petter Selasky if (rp.status != 0x00) { 497c3f60abcSHans Petter Selasky fprintf(stdout, "Status: %s [%#02x]\n", 498c3f60abcSHans Petter Selasky hci_status2str(rp.status), rp.status); 499c3f60abcSHans Petter Selasky return (FAILED); 500c3f60abcSHans Petter Selasky } 501c3f60abcSHans Petter Selasky 502c3f60abcSHans Petter Selasky return (OK); 503c3f60abcSHans Petter Selasky } 504c3f60abcSHans Petter Selasky 505c3f60abcSHans Petter Selasky static int 506c3f60abcSHans Petter Selasky le_read_advertising_channel_tx_power(int s, int argc, char *argv[]) 507c3f60abcSHans Petter Selasky { 508c3f60abcSHans Petter Selasky ng_hci_le_read_advertising_channel_tx_power_rp rp; 509c3f60abcSHans Petter Selasky int n; 510c3f60abcSHans Petter Selasky 511c3f60abcSHans Petter Selasky n = sizeof(rp); 512c3f60abcSHans Petter Selasky 513c3f60abcSHans Petter Selasky if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE, 514c3f60abcSHans Petter Selasky NG_HCI_OCF_LE_READ_ADVERTISING_CHANNEL_TX_POWER), 515c3f60abcSHans Petter Selasky (void *)&rp, &n) == ERROR) 516c3f60abcSHans Petter Selasky return (ERROR); 517c3f60abcSHans Petter Selasky 518c3f60abcSHans Petter Selasky if (rp.status != 0x00) { 519c3f60abcSHans Petter Selasky fprintf(stdout, "Status: %s [%#02x]\n", 520c3f60abcSHans Petter Selasky hci_status2str(rp.status), rp.status); 521c3f60abcSHans Petter Selasky return (FAILED); 522c3f60abcSHans Petter Selasky } 523c3f60abcSHans Petter Selasky 524c3f60abcSHans Petter Selasky fprintf(stdout, "Advertising transmit power level: %d dBm\n", 525c3f60abcSHans Petter Selasky (int8_t)rp.transmit_power_level); 526c3f60abcSHans Petter Selasky 527c3f60abcSHans Petter Selasky return (OK); 528c3f60abcSHans Petter Selasky } 529c3f60abcSHans Petter Selasky 530c3f60abcSHans Petter Selasky static int 531c3f60abcSHans Petter Selasky le_set_advertising_data(int s, int argc, char *argv[]) 532c3f60abcSHans Petter Selasky { 533c3f60abcSHans Petter Selasky ng_hci_le_set_advertising_data_cp cp; 534c3f60abcSHans Petter Selasky ng_hci_le_set_advertising_data_rp rp; 535c3f60abcSHans Petter Selasky int n, len; 536c3f60abcSHans Petter Selasky 537c3f60abcSHans Petter Selasky n = sizeof(rp); 538c3f60abcSHans Petter Selasky 539c3f60abcSHans Petter Selasky char buf[NG_HCI_ADVERTISING_DATA_SIZE]; 540c3f60abcSHans Petter Selasky 541c3f60abcSHans Petter Selasky len = sizeof(buf); 542c3f60abcSHans Petter Selasky parse_param(argc, argv, buf, &len); 543c3f60abcSHans Petter Selasky memset(cp.advertising_data, 0, sizeof(cp.advertising_data)); 544c3f60abcSHans Petter Selasky cp.advertising_data_length = len; 5457b2f84dbSHans Petter Selasky memcpy(cp.advertising_data, buf, len); 546c3f60abcSHans Petter Selasky 547c3f60abcSHans Petter Selasky if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE, 548c3f60abcSHans Petter Selasky NG_HCI_OCF_LE_SET_ADVERTISING_DATA), 549c3f60abcSHans Petter Selasky (void *)&cp, sizeof(cp), (void *)&rp, &n) == ERROR) 550c3f60abcSHans Petter Selasky return (ERROR); 551c3f60abcSHans Petter Selasky 552c3f60abcSHans Petter Selasky if (rp.status != 0x00) { 553c3f60abcSHans Petter Selasky fprintf(stdout, "Status: %s [%#02x]\n", 554c3f60abcSHans Petter Selasky hci_status2str(rp.status), rp.status); 555c3f60abcSHans Petter Selasky return (FAILED); 556c3f60abcSHans Petter Selasky } 557c3f60abcSHans Petter Selasky 558c3f60abcSHans Petter Selasky return (OK); 559c3f60abcSHans Petter Selasky } 5601f5d883dSTakanori Watanabe static int 5611f5d883dSTakanori Watanabe le_read_buffer_size(int s, int argc, char *argv[]) 5621f5d883dSTakanori Watanabe { 5631f5d883dSTakanori Watanabe union { 5641f5d883dSTakanori Watanabe ng_hci_le_read_buffer_size_rp v1; 5651f5d883dSTakanori Watanabe ng_hci_le_read_buffer_size_rp_v2 v2; 5661f5d883dSTakanori Watanabe } rp; 5671f5d883dSTakanori Watanabe 5681f5d883dSTakanori Watanabe int n, ch; 5691f5d883dSTakanori Watanabe uint8_t v; 5701f5d883dSTakanori Watanabe uint16_t cmd; 5711f5d883dSTakanori Watanabe 5721f5d883dSTakanori Watanabe optreset = 1; 5731f5d883dSTakanori Watanabe optind = 0; 5741f5d883dSTakanori Watanabe 5751f5d883dSTakanori Watanabe /* Default to version 1*/ 5761f5d883dSTakanori Watanabe v = 1; 5771f5d883dSTakanori Watanabe cmd = NG_HCI_OCF_LE_READ_BUFFER_SIZE; 5781f5d883dSTakanori Watanabe 5791f5d883dSTakanori Watanabe while ((ch = getopt(argc, argv , "v:")) != -1) { 5801f5d883dSTakanori Watanabe switch(ch) { 5811f5d883dSTakanori Watanabe case 'v': 5821f5d883dSTakanori Watanabe v = (uint8_t)strtol(optarg, NULL, 16); 5831f5d883dSTakanori Watanabe if (v == 2) 5841f5d883dSTakanori Watanabe cmd = NG_HCI_OCF_LE_READ_BUFFER_SIZE_V2; 5851f5d883dSTakanori Watanabe else if (v > 2) 5861f5d883dSTakanori Watanabe return (USAGE); 5871f5d883dSTakanori Watanabe break; 5881f5d883dSTakanori Watanabe default: 5891f5d883dSTakanori Watanabe v = 1; 5901f5d883dSTakanori Watanabe } 5911f5d883dSTakanori Watanabe } 5921f5d883dSTakanori Watanabe 5931f5d883dSTakanori Watanabe n = sizeof(rp); 5941f5d883dSTakanori Watanabe if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE, cmd), 5951f5d883dSTakanori Watanabe (void *)&rp, &n) == ERROR) 5961f5d883dSTakanori Watanabe return (ERROR); 5971f5d883dSTakanori Watanabe 5981f5d883dSTakanori Watanabe if (rp.v1.status != 0x00) { 5991f5d883dSTakanori Watanabe fprintf(stdout, "Status: %s [%#02x]\n", 6001f5d883dSTakanori Watanabe hci_status2str(rp.v1.status), rp.v1.status); 6011f5d883dSTakanori Watanabe return (FAILED); 6021f5d883dSTakanori Watanabe } 6031f5d883dSTakanori Watanabe 6041f5d883dSTakanori Watanabe fprintf(stdout, "ACL data packet length: %d\n", 6051f5d883dSTakanori Watanabe rp.v1.hc_le_data_packet_length); 6061f5d883dSTakanori Watanabe fprintf(stdout, "Number of ACL data packets: %d\n", 6071f5d883dSTakanori Watanabe rp.v1.hc_total_num_le_data_packets); 6081f5d883dSTakanori Watanabe 6091f5d883dSTakanori Watanabe if (v == 2) { 6101f5d883dSTakanori Watanabe fprintf(stdout, "ISO data packet length: %d\n", 6111f5d883dSTakanori Watanabe rp.v2.hc_iso_data_packet_length); 6121f5d883dSTakanori Watanabe fprintf(stdout, "Number of ISO data packets: %d\n", 6131f5d883dSTakanori Watanabe rp.v2.hc_total_num_iso_data_packets); 6141f5d883dSTakanori Watanabe } 6151f5d883dSTakanori Watanabe 6161f5d883dSTakanori Watanabe return (OK); 6171f5d883dSTakanori Watanabe } 618c3f60abcSHans Petter Selasky 619*9287f06dSTakanori Watanabe static int 620*9287f06dSTakanori Watanabe le_scan(int s, int argc, char *argv[]) 621*9287f06dSTakanori Watanabe { 622*9287f06dSTakanori Watanabe int n, bufsize, scancount, numscans; 623*9287f06dSTakanori Watanabe bool verbose; 624*9287f06dSTakanori Watanabe uint8_t active = 0; 625*9287f06dSTakanori Watanabe char ch; 626*9287f06dSTakanori Watanabe 627*9287f06dSTakanori Watanabe char b[512]; 628*9287f06dSTakanori Watanabe ng_hci_event_pkt_t *e = (ng_hci_event_pkt_t *) b; 629*9287f06dSTakanori Watanabe 630*9287f06dSTakanori Watanabe ng_hci_le_set_scan_parameters_cp scan_param_cp; 631*9287f06dSTakanori Watanabe ng_hci_le_set_scan_parameters_rp scan_param_rp; 632*9287f06dSTakanori Watanabe 633*9287f06dSTakanori Watanabe ng_hci_le_set_scan_enable_cp scan_enable_cp; 634*9287f06dSTakanori Watanabe ng_hci_le_set_scan_enable_rp scan_enable_rp; 635*9287f06dSTakanori Watanabe 636*9287f06dSTakanori Watanabe optreset = 1; 637*9287f06dSTakanori Watanabe optind = 0; 638*9287f06dSTakanori Watanabe verbose = false; 639*9287f06dSTakanori Watanabe numscans = 1; 640*9287f06dSTakanori Watanabe 641*9287f06dSTakanori Watanabe while ((ch = getopt(argc, argv , "an:v")) != -1) { 642*9287f06dSTakanori Watanabe switch(ch) { 643*9287f06dSTakanori Watanabe case 'a': 644*9287f06dSTakanori Watanabe active = 1; 645*9287f06dSTakanori Watanabe break; 646*9287f06dSTakanori Watanabe case 'n': 647*9287f06dSTakanori Watanabe numscans = (uint8_t)strtol(optarg, NULL, 10); 648*9287f06dSTakanori Watanabe break; 649*9287f06dSTakanori Watanabe case 'v': 650*9287f06dSTakanori Watanabe verbose = true; 651*9287f06dSTakanori Watanabe break; 652*9287f06dSTakanori Watanabe } 653*9287f06dSTakanori Watanabe } 654*9287f06dSTakanori Watanabe 655*9287f06dSTakanori Watanabe scan_param_cp.le_scan_type = active; 656*9287f06dSTakanori Watanabe scan_param_cp.le_scan_interval = (uint16_t)(100/0.625); 657*9287f06dSTakanori Watanabe scan_param_cp.le_scan_window = (uint16_t)(50/0.625); 658*9287f06dSTakanori Watanabe /* Address type public */ 659*9287f06dSTakanori Watanabe scan_param_cp.own_address_type = 0; 660*9287f06dSTakanori Watanabe /* 'All' filter policy */ 661*9287f06dSTakanori Watanabe scan_param_cp.scanning_filter_policy = 0; 662*9287f06dSTakanori Watanabe n = sizeof(scan_param_rp); 663*9287f06dSTakanori Watanabe 664*9287f06dSTakanori Watanabe if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE, 665*9287f06dSTakanori Watanabe NG_HCI_OCF_LE_SET_SCAN_PARAMETERS), 666*9287f06dSTakanori Watanabe (void *)&scan_param_cp, sizeof(scan_param_cp), 667*9287f06dSTakanori Watanabe (void *)&scan_param_rp, &n) == ERROR) 668*9287f06dSTakanori Watanabe return (ERROR); 669*9287f06dSTakanori Watanabe 670*9287f06dSTakanori Watanabe if (scan_param_rp.status != 0x00) { 671*9287f06dSTakanori Watanabe fprintf(stdout, "LE_Set_Scan_Parameters failed. Status: %s [%#02x]\n", 672*9287f06dSTakanori Watanabe hci_status2str(scan_param_rp.status), 673*9287f06dSTakanori Watanabe scan_param_rp.status); 674*9287f06dSTakanori Watanabe return (FAILED); 675*9287f06dSTakanori Watanabe } 676*9287f06dSTakanori Watanabe 677*9287f06dSTakanori Watanabe /* Enable scanning */ 678*9287f06dSTakanori Watanabe n = sizeof(scan_enable_rp); 679*9287f06dSTakanori Watanabe scan_enable_cp.le_scan_enable = 1; 680*9287f06dSTakanori Watanabe scan_enable_cp.filter_duplicates = 1; 681*9287f06dSTakanori Watanabe if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE, 682*9287f06dSTakanori Watanabe NG_HCI_OCF_LE_SET_SCAN_ENABLE), 683*9287f06dSTakanori Watanabe (void *)&scan_enable_cp, sizeof(scan_enable_cp), 684*9287f06dSTakanori Watanabe (void *)&scan_enable_rp, &n) == ERROR) 685*9287f06dSTakanori Watanabe return (ERROR); 686*9287f06dSTakanori Watanabe 687*9287f06dSTakanori Watanabe if (scan_enable_rp.status != 0x00) { 688*9287f06dSTakanori Watanabe fprintf(stdout, "LE_Scan_Enable enable failed. Status: %s [%#02x]\n", 689*9287f06dSTakanori Watanabe hci_status2str(scan_enable_rp.status), 690*9287f06dSTakanori Watanabe scan_enable_rp.status); 691*9287f06dSTakanori Watanabe return (FAILED); 692*9287f06dSTakanori Watanabe } 693*9287f06dSTakanori Watanabe 694*9287f06dSTakanori Watanabe scancount = 0; 695*9287f06dSTakanori Watanabe while (scancount < numscans) { 696*9287f06dSTakanori Watanabe /* wait for scan events */ 697*9287f06dSTakanori Watanabe bufsize = sizeof(b); 698*9287f06dSTakanori Watanabe if (hci_recv(s, b, &bufsize) == ERROR) { 699*9287f06dSTakanori Watanabe return (ERROR); 700*9287f06dSTakanori Watanabe } 701*9287f06dSTakanori Watanabe 702*9287f06dSTakanori Watanabe if (bufsize < sizeof(*e)) { 703*9287f06dSTakanori Watanabe errno = EIO; 704*9287f06dSTakanori Watanabe return (ERROR); 705*9287f06dSTakanori Watanabe } 706*9287f06dSTakanori Watanabe scancount++; 707*9287f06dSTakanori Watanabe if (e->event == NG_HCI_EVENT_LE) { 708*9287f06dSTakanori Watanabe fprintf(stdout, "Scan %d\n", scancount); 709*9287f06dSTakanori Watanabe handle_le_event(e, verbose); 710*9287f06dSTakanori Watanabe } 711*9287f06dSTakanori Watanabe } 712*9287f06dSTakanori Watanabe 713*9287f06dSTakanori Watanabe fprintf(stdout, "Scan complete\n"); 714*9287f06dSTakanori Watanabe 715*9287f06dSTakanori Watanabe /* Disable scanning */ 716*9287f06dSTakanori Watanabe n = sizeof(scan_enable_rp); 717*9287f06dSTakanori Watanabe scan_enable_cp.le_scan_enable = 0; 718*9287f06dSTakanori Watanabe if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE, 719*9287f06dSTakanori Watanabe NG_HCI_OCF_LE_SET_SCAN_ENABLE), 720*9287f06dSTakanori Watanabe (void *)&scan_enable_cp, sizeof(scan_enable_cp), 721*9287f06dSTakanori Watanabe (void *)&scan_enable_rp, &n) == ERROR) 722*9287f06dSTakanori Watanabe return (ERROR); 723*9287f06dSTakanori Watanabe 724*9287f06dSTakanori Watanabe if (scan_enable_rp.status != 0x00) { 725*9287f06dSTakanori Watanabe fprintf(stdout, "LE_Scan_Enable disable failed. Status: %s [%#02x]\n", 726*9287f06dSTakanori Watanabe hci_status2str(scan_enable_rp.status), 727*9287f06dSTakanori Watanabe scan_enable_rp.status); 728*9287f06dSTakanori Watanabe return (FAILED); 729*9287f06dSTakanori Watanabe } 730*9287f06dSTakanori Watanabe 731*9287f06dSTakanori Watanabe return (OK); 732*9287f06dSTakanori Watanabe } 733*9287f06dSTakanori Watanabe 734*9287f06dSTakanori Watanabe static void handle_le_event(ng_hci_event_pkt_t* e, bool verbose) 735*9287f06dSTakanori Watanabe { 736*9287f06dSTakanori Watanabe int rc; 737*9287f06dSTakanori Watanabe ng_hci_le_ep *leer = 738*9287f06dSTakanori Watanabe (ng_hci_le_ep *)(e + 1); 739*9287f06dSTakanori Watanabe ng_hci_le_advertising_report_ep *advrep = 740*9287f06dSTakanori Watanabe (ng_hci_le_advertising_report_ep *)(leer + 1); 741*9287f06dSTakanori Watanabe ng_hci_le_advreport *reports = 742*9287f06dSTakanori Watanabe (ng_hci_le_advreport *)(advrep + 1); 743*9287f06dSTakanori Watanabe 744*9287f06dSTakanori Watanabe if (leer->subevent_code == NG_HCI_LEEV_ADVREP) { 745*9287f06dSTakanori Watanabe fprintf(stdout, "Scan result, num_reports: %d\n", 746*9287f06dSTakanori Watanabe advrep->num_reports); 747*9287f06dSTakanori Watanabe for(rc = 0; rc < advrep->num_reports; rc++) { 748*9287f06dSTakanori Watanabe uint8_t length = (uint8_t)reports[rc].length_data; 749*9287f06dSTakanori Watanabe fprintf(stdout, "\tBD_ADDR %s \n", 750*9287f06dSTakanori Watanabe hci_bdaddr2str(&reports[rc].bdaddr)); 751*9287f06dSTakanori Watanabe fprintf(stdout, "\tAddress type: %s\n", 752*9287f06dSTakanori Watanabe hci_addrtype2str(reports[rc].addr_type)); 753*9287f06dSTakanori Watanabe if (length > 0 && verbose) { 754*9287f06dSTakanori Watanabe dump_adv_data(length, reports[rc].data); 755*9287f06dSTakanori Watanabe print_adv_data(length, reports[rc].data); 756*9287f06dSTakanori Watanabe fprintf(stdout, 757*9287f06dSTakanori Watanabe "\tRSSI: %d dBm\n", 758*9287f06dSTakanori Watanabe (int8_t)reports[rc].data[length]); 759*9287f06dSTakanori Watanabe fprintf(stdout, "\n"); 760*9287f06dSTakanori Watanabe } 761*9287f06dSTakanori Watanabe } 762*9287f06dSTakanori Watanabe } 763*9287f06dSTakanori Watanabe } 764*9287f06dSTakanori Watanabe 765bcff2d91STakanori Watanabe struct hci_command le_commands[] = { 766bcff2d91STakanori Watanabe { 767bcff2d91STakanori Watanabe "le_enable", 768bcff2d91STakanori Watanabe "le_enable [enable|disable] \n" 769bcff2d91STakanori Watanabe "Enable LE event ", 770bcff2d91STakanori Watanabe &le_enable, 771bcff2d91STakanori Watanabe }, 772bcff2d91STakanori Watanabe { 773bcff2d91STakanori Watanabe "le_read_local_supported_features", 774bcff2d91STakanori Watanabe "le_read_local_supported_features\n" 775bcff2d91STakanori Watanabe "read local supported features mask", 776bcff2d91STakanori Watanabe &le_read_local_supported_features, 777bcff2d91STakanori Watanabe }, 778bcff2d91STakanori Watanabe { 77921eefd31SHans Petter Selasky "le_read_supported_states", 78021eefd31SHans Petter Selasky "le_read_supported_states\n" 781bcff2d91STakanori Watanabe "read supported status" 782bcff2d91STakanori Watanabe , 78321eefd31SHans Petter Selasky &le_read_supported_states, 784bcff2d91STakanori Watanabe }, 785bcff2d91STakanori Watanabe { 786bcff2d91STakanori Watanabe "le_set_scan_response", 787bcff2d91STakanori Watanabe "le_set_scan_response -n $name -f $flag -u $uuid16,$uuid16 \n" 788bcff2d91STakanori Watanabe "set LE scan response data" 789bcff2d91STakanori Watanabe , 790bcff2d91STakanori Watanabe &le_set_scan_response, 791bcff2d91STakanori Watanabe }, 792bcff2d91STakanori Watanabe { 793bcff2d91STakanori Watanabe "le_set_scan_enable", 794bcff2d91STakanori Watanabe "le_set_scan_enable [enable|disable] \n" 795bcff2d91STakanori Watanabe "enable or disable LE device scan", 796bcff2d91STakanori Watanabe &le_set_scan_enable 797bcff2d91STakanori Watanabe }, 798bcff2d91STakanori Watanabe { 799bcff2d91STakanori Watanabe "le_set_scan_param", 800bcff2d91STakanori Watanabe "le_set_scan_param [active|passive] interval(ms) window(ms) [public|random] [all|whitelist] \n" 801bcff2d91STakanori Watanabe "set LE device scan parameter", 802bcff2d91STakanori Watanabe &le_set_scan_param 803bcff2d91STakanori Watanabe }, 804c3f60abcSHans Petter Selasky { 805c3f60abcSHans Petter Selasky "le_set_advertising_enable", 806c3f60abcSHans Petter Selasky "le_set_advertising_enable [enable|disable] \n" 807c3f60abcSHans Petter Selasky "start or stop advertising", 808c3f60abcSHans Petter Selasky &le_set_advertising_enable 809c3f60abcSHans Petter Selasky }, 810c3f60abcSHans Petter Selasky { 811c3f60abcSHans Petter Selasky "le_read_advertising_channel_tx_power", 812c3f60abcSHans Petter Selasky "le_read_advertising_channel_tx_power\n" 813c3f60abcSHans Petter Selasky "read host advertising transmit poser level (dBm)", 814c3f60abcSHans Petter Selasky &le_read_advertising_channel_tx_power 815c3f60abcSHans Petter Selasky }, 816c3f60abcSHans Petter Selasky { 817c3f60abcSHans Petter Selasky "le_set_advertising_param", 818c3f60abcSHans Petter Selasky "le_set_advertising_param [-m min_interval(ms)] [-M max_interval(ms)]\n" 819c3f60abcSHans Petter Selasky "[-t advertising_type] [-o own_address_type] [-p peer_address_type]\n" 820c3f60abcSHans Petter Selasky "[-c advertising_channel_map] [-f advertising_filter_policy]\n" 821c3f60abcSHans Petter Selasky "[-a peer_address]\n" 822c3f60abcSHans Petter Selasky "set LE device advertising parameters", 823c3f60abcSHans Petter Selasky &le_set_advertising_param 824c3f60abcSHans Petter Selasky }, 825c3f60abcSHans Petter Selasky { 826c3f60abcSHans Petter Selasky "le_set_advertising_data", 827c3f60abcSHans Petter Selasky "le_set_advertising_data -n $name -f $flag -u $uuid16,$uuid16 \n" 828c3f60abcSHans Petter Selasky "set LE device advertising packed data", 829c3f60abcSHans Petter Selasky &le_set_advertising_data 830c3f60abcSHans Petter Selasky }, 8311f5d883dSTakanori Watanabe { 8321f5d883dSTakanori Watanabe "le_read_buffer_size", 8331f5d883dSTakanori Watanabe "le_read_buffer_size [-v 1|2]\n" 8341f5d883dSTakanori Watanabe "Read the maximum size of ACL and ISO data packets", 8351f5d883dSTakanori Watanabe &le_read_buffer_size 8361f5d883dSTakanori Watanabe }, 837*9287f06dSTakanori Watanabe { 838*9287f06dSTakanori Watanabe "le_scan", 839*9287f06dSTakanori Watanabe "le_scan [-a] [-v] [-n number_of_scans]\n" 840*9287f06dSTakanori Watanabe "Do an LE scan", 841*9287f06dSTakanori Watanabe &le_scan 842*9287f06dSTakanori Watanabe }, 843bcff2d91STakanori Watanabe }; 844