le.c revision 281688
1/* 2 * le.c 3 * 4 * Copyright (c) 2015 Takanori Watanabe <takawata@freebsd.org> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 * $Id: hccontrol.c,v 1.5 2003/09/05 00:38:24 max Exp $ 29 * $FreeBSD: head/usr.sbin/bluetooth/hccontrol/le.c 281688 2015-04-18 09:08:47Z takawata $ 30 */ 31 32#include <sys/types.h> 33#include <sys/ioctl.h> 34#include <sys/sysctl.h> 35#include <sys/bitstring.h> 36#include <sys/select.h> 37#include <assert.h> 38#include <err.h> 39#include <errno.h> 40#include <netgraph/ng_message.h> 41#include <errno.h> 42#include <stdio.h> 43#include <stdlib.h> 44#include <string.h> 45#include <unistd.h> 46#define L2CAP_SOCKET_CHECKED 47#include <bluetooth.h> 48#include "hccontrol.h" 49 50static int le_set_scan_param(int s, int argc, char *argv[]); 51static int le_set_scan_enable(int s, int argc, char *argv[]); 52static int parse_param(int argc, char *argv[], char *buf, int *len); 53static int le_set_scan_response(int s, int argc, char *argv[]); 54static int le_read_supported_status(int s, int argc, char *argv[]); 55static int le_read_local_supported_features(int s, int argc ,char *argv[]); 56static int set_le_event_mask(int s, uint64_t mask); 57static int set_event_mask(int s, uint64_t mask); 58static int le_enable(int s, int argc, char *argv[]); 59 60static int 61le_set_scan_param(int s, int argc, char *argv[]) 62{ 63 int type; 64 int interval; 65 int window; 66 int adrtype; 67 int policy; 68 int e, n; 69 70 ng_hci_le_set_scan_parameters_cp cp; 71 ng_hci_le_set_scan_parameters_rp rp; 72 73 if (argc != 5) 74 return USAGE; 75 76 if (strcmp(argv[0], "active") == 0) 77 type = 1; 78 else if (strcmp(argv[0], "passive") == 0) 79 type = 0; 80 else 81 return USAGE; 82 83 interval = (int)(atof(argv[1])/0.625); 84 interval = (interval < 4)? 4: interval; 85 window = (int)(atof(argv[2])/0.625); 86 window = (window < 4) ? 4 : interval; 87 88 if (strcmp(argv[3], "public") == 0) 89 adrtype = 0; 90 else if (strcmp(argv[0], "random") == 0) 91 adrtype = 1; 92 else 93 return USAGE; 94 95 if (strcmp(argv[4], "all") == 0) 96 policy = 0; 97 else if (strcmp(argv[4], "whitelist") == 0) 98 policy = 1; 99 else 100 return USAGE; 101 102 cp.le_scan_type = type; 103 cp.le_scan_interval = interval; 104 cp.own_address_type = adrtype; 105 cp.le_scan_window = window; 106 cp.scanning_filter_policy = policy; 107 n = sizeof(rp); 108 e = hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE, 109 NG_HCI_OCF_LE_SET_SCAN_PARAMETERS), 110 (void *)&cp, sizeof(cp), (void *)&rp, &n); 111 112 return 0; 113} 114 115static int 116le_set_scan_enable(int s, int argc, char *argv[]) 117{ 118 ng_hci_le_set_scan_enable_cp cp; 119 ng_hci_le_set_scan_enable_rp rp; 120 int e, n, enable = 0; 121 122 if (argc != 1) 123 return USAGE; 124 125 if (strcmp(argv[0], "enable") == 0) 126 enable = 1; 127 else if (strcmp(argv[0], "disable") != 0) 128 return USAGE; 129 130 n = sizeof(rp); 131 cp.le_scan_enable = enable; 132 cp.filter_duplicates = 0; 133 e = hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE, 134 NG_HCI_OCF_LE_SET_SCAN_ENABLE), 135 (void *)&cp, sizeof(cp), (void *)&rp, &n); 136 137 if (e != 0 || rp.status != 0) 138 return ERROR; 139 140 return OK; 141} 142 143static int 144parse_param(int argc, char *argv[], char *buf, int *len) 145{ 146 char *buflast = buf + (*len); 147 char *curbuf = buf; 148 char *token,*lenpos; 149 int ch; 150 int datalen; 151 uint16_t value; 152 optreset = 1; 153 optind = 0; 154 while ((ch = getopt(argc, argv , "n:f:u:")) != -1) { 155 switch(ch){ 156 case 'n': 157 datalen = strlen(optarg); 158 if ((curbuf + datalen + 2) >= buflast) 159 goto done; 160 curbuf[0] = datalen + 1; 161 curbuf[1] = 8; 162 curbuf += 2; 163 memcpy(curbuf, optarg, datalen); 164 curbuf += datalen; 165 break; 166 case 'f': 167 if (curbuf+3 > buflast) 168 goto done; 169 curbuf[0] = 2; 170 curbuf[1] = 1; 171 curbuf[2] = atoi(optarg); 172 curbuf += 3; 173 break; 174 case 'u': 175 lenpos = buf; 176 if ((buf+2) >= buflast) 177 goto done; 178 curbuf[1] = 2; 179 *lenpos = 1; 180 curbuf += 2; 181 while ((token = strsep(&optarg, ",")) != NULL) { 182 value = strtol(token, NULL, 16); 183 if ((curbuf+2) >= buflast) 184 break; 185 curbuf[0] = value &0xff; 186 curbuf[1] = (value>>8)&0xff; 187 curbuf += 2; 188 } 189 190 } 191 } 192done: 193 *len = curbuf - buf; 194 195 return OK; 196} 197 198static int 199le_set_scan_response(int s, int argc, char *argv[]) 200{ 201 ng_hci_le_set_scan_response_data_cp cp; 202 ng_hci_le_set_scan_response_data_rp rp; 203 int n; 204 int e; 205 int len; 206 char buf[NG_HCI_ADVERTISING_DATA_SIZE]; 207 208 len = sizeof(buf); 209 parse_param(argc, argv, buf, &len); 210 memset(cp.scan_response_data, 0, sizeof(cp.scan_response_data)); 211 cp.scan_response_data_length = len; 212 memcpy(cp.scan_response_data, buf, len); 213 n = sizeof(rp); 214 e = hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE, 215 NG_HCI_OCF_LE_SET_SCAN_RESPONSE_DATA), 216 (void *)&cp, sizeof(cp), (void *)&rp, &n); 217 218 printf("SET SCAN RESPONSE %d %d %d\n", e, rp.status, n); 219 220 return OK; 221} 222 223static int 224le_read_local_supported_features(int s, int argc ,char *argv[]) 225{ 226 ng_hci_le_read_local_supported_features_rp rp; 227 int e; 228 int n = sizeof(rp); 229 230 e = hci_simple_request(s, 231 NG_HCI_OPCODE(NG_HCI_OGF_LE, 232 NG_HCI_OCF_LE_READ_LOCAL_SUPPORTED_FEATURES), 233 (void *)&rp, &n); 234 235 printf("LOCAL SUPPORTED: %d %d %lu\n", e, rp.status, 236 rp.le_features); 237 238 return 0; 239} 240 241static int 242le_read_supported_status(int s, int argc, char *argv[]) 243{ 244 ng_hci_le_read_supported_status_rp rp; 245 int e; 246 int n = sizeof(rp); 247 248 e = hci_simple_request(s, NG_HCI_OPCODE( 249 NG_HCI_OGF_LE, 250 NG_HCI_OCF_LE_READ_SUPPORTED_STATUS), 251 (void *)&rp, &n); 252 253 printf("LE_STATUS: %d %d %lx\n", e, rp.status, rp.le_status); 254 255 return 0; 256} 257 258static int 259set_le_event_mask(int s, uint64_t mask) 260{ 261 ng_hci_le_set_event_mask_cp semc; 262 ng_hci_le_set_event_mask_rp rp; 263 int i, n ,e; 264 265 n = sizeof(rp); 266 267 for (i=0; i < NG_HCI_LE_EVENT_MASK_SIZE; i++) { 268 semc.event_mask[i] = mask&0xff; 269 mask >>= 8; 270 } 271 e = hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE, 272 NG_HCI_OCF_LE_SET_EVENT_MASK), 273 (void *)&semc, sizeof(semc), (void *)&rp, &n); 274 275 return 0; 276} 277 278static int 279set_event_mask(int s, uint64_t mask) 280{ 281 ng_hci_set_event_mask_cp semc; 282 ng_hci_set_event_mask_rp rp; 283 int i, n, e; 284 285 n = sizeof(rp); 286 287 for (i=0; i < NG_HCI_EVENT_MASK_SIZE; i++) { 288 semc.event_mask[i] = mask&0xff; 289 mask >>= 8; 290 } 291 e = hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND, 292 NG_HCI_OCF_SET_EVENT_MASK), 293 (void *)&semc, sizeof(semc), (void *)&rp, &n); 294 295 return 0; 296} 297 298static 299int le_enable(int s, int argc, char *argv[]) 300{ 301 if (argc != 1) 302 return USAGE; 303 304 if (strcasecmp(argv[0], "enable") == 0) { 305 set_event_mask(s, NG_HCI_EVENT_MASK_DEFAULT | 306 NG_HCI_EVENT_MASK_LE); 307 set_le_event_mask(s, NG_HCI_LE_EVENT_MASK_ALL); 308 } else if (strcasecmp(argv[0], "disble") == 0) 309 set_event_mask(s, NG_HCI_EVENT_MASK_DEFAULT); 310 else 311 return USAGE; 312 313 return OK; 314} 315 316struct hci_command le_commands[] = { 317{ 318 "le_enable", 319 "le_enable [enable|disable] \n" 320 "Enable LE event ", 321 &le_enable, 322}, 323 { 324 "le_read_local_supported_features", 325 "le_read_local_supported_features\n" 326 "read local supported features mask", 327 &le_read_local_supported_features, 328 }, 329 { 330 "le_read_supported_status", 331 "le_read_supported_status\n" 332 "read supported status" 333 , 334 &le_read_supported_status, 335 }, 336 { 337 "le_set_scan_response", 338 "le_set_scan_response -n $name -f $flag -u $uuid16,$uuid16 \n" 339 "set LE scan response data" 340 , 341 &le_set_scan_response, 342 }, 343 { 344 "le_set_scan_enable", 345 "le_set_scan_enable [enable|disable] \n" 346 "enable or disable LE device scan", 347 &le_set_scan_enable 348 }, 349 { 350 "le_set_scan_param", 351 "le_set_scan_param [active|passive] interval(ms) window(ms) [public|random] [all|whitelist] \n" 352 "set LE device scan parameter", 353 &le_set_scan_param 354 }, 355}; 356