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/bitstring.h> 36bcff2d91STakanori Watanabe #include <sys/select.h> 37bcff2d91STakanori Watanabe #include <assert.h> 38bcff2d91STakanori Watanabe #include <err.h> 39bcff2d91STakanori Watanabe #include <errno.h> 40bcff2d91STakanori Watanabe #include <netgraph/ng_message.h> 41bcff2d91STakanori Watanabe #include <errno.h> 42bcff2d91STakanori Watanabe #include <stdio.h> 43bcff2d91STakanori Watanabe #include <stdlib.h> 44bcff2d91STakanori Watanabe #include <string.h> 45bcff2d91STakanori Watanabe #include <unistd.h> 46*4cae2db2STakanori Watanabe #include <stdint.h> 47bcff2d91STakanori Watanabe #define L2CAP_SOCKET_CHECKED 48bcff2d91STakanori Watanabe #include <bluetooth.h> 49bcff2d91STakanori Watanabe #include "hccontrol.h" 509c3471faSMarcelo Araujo 51bcff2d91STakanori Watanabe static int le_set_scan_param(int s, int argc, char *argv[]); 52bcff2d91STakanori Watanabe static int le_set_scan_enable(int s, int argc, char *argv[]); 53bcff2d91STakanori Watanabe static int parse_param(int argc, char *argv[], char *buf, int *len); 54bcff2d91STakanori Watanabe static int le_set_scan_response(int s, int argc, char *argv[]); 55bcff2d91STakanori Watanabe static int le_read_supported_status(int s, int argc, char *argv[]); 56bcff2d91STakanori Watanabe static int le_read_local_supported_features(int s, int argc ,char *argv[]); 57bcff2d91STakanori Watanabe static int set_le_event_mask(int s, uint64_t mask); 58bcff2d91STakanori Watanabe static int set_event_mask(int s, uint64_t mask); 59bcff2d91STakanori Watanabe static int le_enable(int s, int argc, char *argv[]); 60bcff2d91STakanori Watanabe 619c3471faSMarcelo Araujo static int 629c3471faSMarcelo Araujo le_set_scan_param(int s, int argc, char *argv[]) 63bcff2d91STakanori Watanabe { 64bcff2d91STakanori Watanabe int type; 65bcff2d91STakanori Watanabe int interval; 66bcff2d91STakanori Watanabe int window; 67bcff2d91STakanori Watanabe int adrtype; 68bcff2d91STakanori Watanabe int policy; 699c3471faSMarcelo Araujo int e, n; 70bcff2d91STakanori Watanabe 71bcff2d91STakanori Watanabe ng_hci_le_set_scan_parameters_cp cp; 72bcff2d91STakanori Watanabe ng_hci_le_set_scan_parameters_rp rp; 73bcff2d91STakanori Watanabe 749c3471faSMarcelo Araujo if (argc != 5) 75bcff2d91STakanori Watanabe return USAGE; 76bcff2d91STakanori Watanabe 779c3471faSMarcelo Araujo if (strcmp(argv[0], "active") == 0) 78bcff2d91STakanori Watanabe type = 1; 799c3471faSMarcelo Araujo else if (strcmp(argv[0], "passive") == 0) 80bcff2d91STakanori Watanabe type = 0; 819c3471faSMarcelo Araujo else 82bcff2d91STakanori Watanabe return USAGE; 83bcff2d91STakanori Watanabe 84bcff2d91STakanori Watanabe interval = (int)(atof(argv[1])/0.625); 85bcff2d91STakanori Watanabe interval = (interval < 4)? 4: interval; 86bcff2d91STakanori Watanabe window = (int)(atof(argv[2])/0.625); 87bcff2d91STakanori Watanabe window = (window < 4) ? 4 : interval; 88bcff2d91STakanori Watanabe 899c3471faSMarcelo Araujo if (strcmp(argv[3], "public") == 0) 90bcff2d91STakanori Watanabe adrtype = 0; 919c3471faSMarcelo Araujo else if (strcmp(argv[0], "random") == 0) 92bcff2d91STakanori Watanabe adrtype = 1; 939c3471faSMarcelo Araujo else 94bcff2d91STakanori Watanabe return USAGE; 95bcff2d91STakanori Watanabe 969c3471faSMarcelo Araujo if (strcmp(argv[4], "all") == 0) 97bcff2d91STakanori Watanabe policy = 0; 989c3471faSMarcelo Araujo else if (strcmp(argv[4], "whitelist") == 0) 99bcff2d91STakanori Watanabe policy = 1; 1009c3471faSMarcelo Araujo else 101bcff2d91STakanori Watanabe return USAGE; 102bcff2d91STakanori Watanabe 103bcff2d91STakanori Watanabe cp.le_scan_type = type; 104bcff2d91STakanori Watanabe cp.le_scan_interval = interval; 105bcff2d91STakanori Watanabe cp.own_address_type = adrtype; 106bcff2d91STakanori Watanabe cp.le_scan_window = window; 107bcff2d91STakanori Watanabe cp.scanning_filter_policy = policy; 108bcff2d91STakanori Watanabe n = sizeof(rp); 109bcff2d91STakanori Watanabe e = hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE, 110bcff2d91STakanori Watanabe NG_HCI_OCF_LE_SET_SCAN_PARAMETERS), 111bcff2d91STakanori Watanabe (void *)&cp, sizeof(cp), (void *)&rp, &n); 112bcff2d91STakanori Watanabe 113bcff2d91STakanori Watanabe return 0; 114bcff2d91STakanori Watanabe } 115bcff2d91STakanori Watanabe 1169c3471faSMarcelo Araujo static int 1179c3471faSMarcelo Araujo le_set_scan_enable(int s, int argc, char *argv[]) 118bcff2d91STakanori Watanabe { 119bcff2d91STakanori Watanabe ng_hci_le_set_scan_enable_cp cp; 120bcff2d91STakanori Watanabe ng_hci_le_set_scan_enable_rp rp; 121bcff2d91STakanori Watanabe int e, n, enable = 0; 122bcff2d91STakanori Watanabe 123bcff2d91STakanori Watanabe if (argc != 1) 124bcff2d91STakanori Watanabe return USAGE; 125bcff2d91STakanori Watanabe 1269c3471faSMarcelo Araujo if (strcmp(argv[0], "enable") == 0) 127bcff2d91STakanori Watanabe enable = 1; 1289c3471faSMarcelo Araujo else if (strcmp(argv[0], "disable") != 0) 129bcff2d91STakanori Watanabe return USAGE; 1309c3471faSMarcelo Araujo 131bcff2d91STakanori Watanabe n = sizeof(rp); 132bcff2d91STakanori Watanabe cp.le_scan_enable = enable; 133bcff2d91STakanori Watanabe cp.filter_duplicates = 0; 134bcff2d91STakanori Watanabe e = hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE, 135bcff2d91STakanori Watanabe NG_HCI_OCF_LE_SET_SCAN_ENABLE), 136bcff2d91STakanori Watanabe (void *)&cp, sizeof(cp), (void *)&rp, &n); 137bcff2d91STakanori Watanabe 1389c3471faSMarcelo Araujo if (e != 0 || rp.status != 0) 139bcff2d91STakanori Watanabe return ERROR; 140bcff2d91STakanori Watanabe 1419c3471faSMarcelo Araujo return OK; 142bcff2d91STakanori Watanabe } 1439c3471faSMarcelo Araujo 1449c3471faSMarcelo Araujo static int 1459c3471faSMarcelo Araujo parse_param(int argc, char *argv[], char *buf, int *len) 146bcff2d91STakanori Watanabe { 147bcff2d91STakanori Watanabe char *buflast = buf + (*len); 148bcff2d91STakanori Watanabe char *curbuf = buf; 149bcff2d91STakanori Watanabe char *token,*lenpos; 150bcff2d91STakanori Watanabe int ch; 151bcff2d91STakanori Watanabe int datalen; 152bcff2d91STakanori Watanabe uint16_t value; 153bcff2d91STakanori Watanabe optreset = 1; 154bcff2d91STakanori Watanabe optind = 0; 155bcff2d91STakanori Watanabe while ((ch = getopt(argc, argv , "n:f:u:")) != -1) { 156bcff2d91STakanori Watanabe switch(ch){ 157bcff2d91STakanori Watanabe case 'n': 158bcff2d91STakanori Watanabe datalen = strlen(optarg); 1599c3471faSMarcelo Araujo if ((curbuf + datalen + 2) >= buflast) 160bcff2d91STakanori Watanabe goto done; 161bcff2d91STakanori Watanabe curbuf[0] = datalen + 1; 162bcff2d91STakanori Watanabe curbuf[1] = 8; 163bcff2d91STakanori Watanabe curbuf += 2; 164bcff2d91STakanori Watanabe memcpy(curbuf, optarg, datalen); 165bcff2d91STakanori Watanabe curbuf += datalen; 166bcff2d91STakanori Watanabe break; 167bcff2d91STakanori Watanabe case 'f': 1689c3471faSMarcelo Araujo if (curbuf+3 > buflast) 169bcff2d91STakanori Watanabe goto done; 170bcff2d91STakanori Watanabe curbuf[0] = 2; 171bcff2d91STakanori Watanabe curbuf[1] = 1; 172bcff2d91STakanori Watanabe curbuf[2] = atoi(optarg); 173bcff2d91STakanori Watanabe curbuf += 3; 174bcff2d91STakanori Watanabe break; 175bcff2d91STakanori Watanabe case 'u': 176bcff2d91STakanori Watanabe lenpos = buf; 177bcff2d91STakanori Watanabe if ((buf+2) >= buflast) 178bcff2d91STakanori Watanabe goto done; 179bcff2d91STakanori Watanabe curbuf[1] = 2; 180bcff2d91STakanori Watanabe *lenpos = 1; 181bcff2d91STakanori Watanabe curbuf += 2; 182bcff2d91STakanori Watanabe while ((token = strsep(&optarg, ",")) != NULL) { 183bcff2d91STakanori Watanabe value = strtol(token, NULL, 16); 184bcff2d91STakanori Watanabe if ((curbuf+2) >= buflast) 185bcff2d91STakanori Watanabe break; 186bcff2d91STakanori Watanabe curbuf[0] = value &0xff; 187bcff2d91STakanori Watanabe curbuf[1] = (value>>8)&0xff; 188bcff2d91STakanori Watanabe curbuf += 2; 189bcff2d91STakanori Watanabe } 190bcff2d91STakanori Watanabe 191bcff2d91STakanori Watanabe } 192bcff2d91STakanori Watanabe } 193bcff2d91STakanori Watanabe done: 194bcff2d91STakanori Watanabe *len = curbuf - buf; 195bcff2d91STakanori Watanabe 196bcff2d91STakanori Watanabe return OK; 197bcff2d91STakanori Watanabe } 198bcff2d91STakanori Watanabe 1999c3471faSMarcelo Araujo static int 2009c3471faSMarcelo Araujo le_set_scan_response(int s, int argc, char *argv[]) 201bcff2d91STakanori Watanabe { 202bcff2d91STakanori Watanabe ng_hci_le_set_scan_response_data_cp cp; 203bcff2d91STakanori Watanabe ng_hci_le_set_scan_response_data_rp rp; 204bcff2d91STakanori Watanabe int n; 205bcff2d91STakanori Watanabe int e; 206bcff2d91STakanori Watanabe int len; 207bcff2d91STakanori Watanabe char buf[NG_HCI_ADVERTISING_DATA_SIZE]; 2089c3471faSMarcelo Araujo 209bcff2d91STakanori Watanabe len = sizeof(buf); 210bcff2d91STakanori Watanabe parse_param(argc, argv, buf, &len); 211bcff2d91STakanori Watanabe memset(cp.scan_response_data, 0, sizeof(cp.scan_response_data)); 212bcff2d91STakanori Watanabe cp.scan_response_data_length = len; 213bcff2d91STakanori Watanabe memcpy(cp.scan_response_data, buf, len); 214bcff2d91STakanori Watanabe n = sizeof(rp); 215bcff2d91STakanori Watanabe e = hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE, 216bcff2d91STakanori Watanabe NG_HCI_OCF_LE_SET_SCAN_RESPONSE_DATA), 217bcff2d91STakanori Watanabe (void *)&cp, sizeof(cp), (void *)&rp, &n); 218bcff2d91STakanori Watanabe 2199c3471faSMarcelo Araujo printf("SET SCAN RESPONSE %d %d %d\n", e, rp.status, n); 220bcff2d91STakanori Watanabe 221bcff2d91STakanori Watanabe return OK; 222bcff2d91STakanori Watanabe } 223bcff2d91STakanori Watanabe 2249c3471faSMarcelo Araujo static int 2259c3471faSMarcelo Araujo le_read_local_supported_features(int s, int argc ,char *argv[]) 226bcff2d91STakanori Watanabe { 227bcff2d91STakanori Watanabe ng_hci_le_read_local_supported_features_rp rp; 228bcff2d91STakanori Watanabe int e; 229bcff2d91STakanori Watanabe int n = sizeof(rp); 2309c3471faSMarcelo Araujo 231bcff2d91STakanori Watanabe e = hci_simple_request(s, 232bcff2d91STakanori Watanabe NG_HCI_OPCODE(NG_HCI_OGF_LE, 233bcff2d91STakanori Watanabe NG_HCI_OCF_LE_READ_LOCAL_SUPPORTED_FEATURES), 234bcff2d91STakanori Watanabe (void *)&rp, &n); 2359c3471faSMarcelo Araujo 2364315b1cbSTakanori Watanabe printf("LOCAL SUPPORTED: %d %d %jx\n", e, rp.status, 237*4cae2db2STakanori Watanabe (uintmax_t) rp.le_features); 238bcff2d91STakanori Watanabe 239bcff2d91STakanori Watanabe return 0; 240bcff2d91STakanori Watanabe } 2419c3471faSMarcelo Araujo 2429c3471faSMarcelo Araujo static int 2439c3471faSMarcelo Araujo le_read_supported_status(int s, int argc, char *argv[]) 244bcff2d91STakanori Watanabe { 245bcff2d91STakanori Watanabe ng_hci_le_read_supported_status_rp rp; 246bcff2d91STakanori Watanabe int e; 247bcff2d91STakanori Watanabe int n = sizeof(rp); 2489c3471faSMarcelo Araujo 2499c3471faSMarcelo Araujo e = hci_simple_request(s, NG_HCI_OPCODE( 2509c3471faSMarcelo Araujo NG_HCI_OGF_LE, 251bf9b5107STakanori Watanabe NG_HCI_OCF_LE_READ_SUPPORTED_STATUS), 252bcff2d91STakanori Watanabe (void *)&rp, &n); 2539c3471faSMarcelo Araujo 254*4cae2db2STakanori Watanabe printf("LE_STATUS: %d %d %jx\n", e, rp.status, (uintmax_t)rp.le_status); 255bcff2d91STakanori Watanabe 256bcff2d91STakanori Watanabe return 0; 257bcff2d91STakanori Watanabe } 258bcff2d91STakanori Watanabe 2599c3471faSMarcelo Araujo static int 2609c3471faSMarcelo Araujo set_le_event_mask(int s, uint64_t mask) 261bcff2d91STakanori Watanabe { 262bcff2d91STakanori Watanabe ng_hci_le_set_event_mask_cp semc; 263bcff2d91STakanori Watanabe ng_hci_le_set_event_mask_rp rp; 264bcff2d91STakanori Watanabe int i, n ,e; 265bcff2d91STakanori Watanabe 266bcff2d91STakanori Watanabe n = sizeof(rp); 267bcff2d91STakanori Watanabe 268bcff2d91STakanori Watanabe for (i=0; i < NG_HCI_LE_EVENT_MASK_SIZE; i++) { 269bcff2d91STakanori Watanabe semc.event_mask[i] = mask&0xff; 270bcff2d91STakanori Watanabe mask >>= 8; 271bcff2d91STakanori Watanabe } 2729c3471faSMarcelo Araujo e = hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE, 2739c3471faSMarcelo Araujo NG_HCI_OCF_LE_SET_EVENT_MASK), 2749c3471faSMarcelo Araujo (void *)&semc, sizeof(semc), (void *)&rp, &n); 275bcff2d91STakanori Watanabe 276bcff2d91STakanori Watanabe return 0; 277bcff2d91STakanori Watanabe } 278bcff2d91STakanori Watanabe 2799c3471faSMarcelo Araujo static int 2809c3471faSMarcelo Araujo set_event_mask(int s, uint64_t mask) 281bcff2d91STakanori Watanabe { 282bcff2d91STakanori Watanabe ng_hci_set_event_mask_cp semc; 283bcff2d91STakanori Watanabe ng_hci_set_event_mask_rp rp; 284bcff2d91STakanori Watanabe int i, n, e; 285bcff2d91STakanori Watanabe 286bcff2d91STakanori Watanabe n = sizeof(rp); 287bcff2d91STakanori Watanabe 288bcff2d91STakanori Watanabe for (i=0; i < NG_HCI_EVENT_MASK_SIZE; i++) { 289bcff2d91STakanori Watanabe semc.event_mask[i] = mask&0xff; 290bcff2d91STakanori Watanabe mask >>= 8; 291bcff2d91STakanori Watanabe } 2929c3471faSMarcelo Araujo e = hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND, 2939c3471faSMarcelo Araujo NG_HCI_OCF_SET_EVENT_MASK), 2949c3471faSMarcelo Araujo (void *)&semc, sizeof(semc), (void *)&rp, &n); 295bcff2d91STakanori Watanabe 296bcff2d91STakanori Watanabe return 0; 297bcff2d91STakanori Watanabe } 298bcff2d91STakanori Watanabe 2999c3471faSMarcelo Araujo static 3009c3471faSMarcelo Araujo int le_enable(int s, int argc, char *argv[]) 301bcff2d91STakanori Watanabe { 3029c3471faSMarcelo Araujo if (argc != 1) 303bcff2d91STakanori Watanabe return USAGE; 304bcff2d91STakanori Watanabe 305bcff2d91STakanori Watanabe if (strcasecmp(argv[0], "enable") == 0) { 306bcff2d91STakanori Watanabe set_event_mask(s, NG_HCI_EVENT_MASK_DEFAULT | 307bcff2d91STakanori Watanabe NG_HCI_EVENT_MASK_LE); 308bcff2d91STakanori Watanabe set_le_event_mask(s, NG_HCI_LE_EVENT_MASK_ALL); 3099c3471faSMarcelo Araujo } else if (strcasecmp(argv[0], "disble") == 0) 310bcff2d91STakanori Watanabe set_event_mask(s, NG_HCI_EVENT_MASK_DEFAULT); 3119c3471faSMarcelo Araujo else 312bcff2d91STakanori Watanabe return USAGE; 313bcff2d91STakanori Watanabe 314bcff2d91STakanori Watanabe return OK; 315bcff2d91STakanori Watanabe } 316bcff2d91STakanori Watanabe 317bcff2d91STakanori Watanabe struct hci_command le_commands[] = { 318bcff2d91STakanori Watanabe { 319bcff2d91STakanori Watanabe "le_enable", 320bcff2d91STakanori Watanabe "le_enable [enable|disable] \n" 321bcff2d91STakanori Watanabe "Enable LE event ", 322bcff2d91STakanori Watanabe &le_enable, 323bcff2d91STakanori Watanabe }, 324bcff2d91STakanori Watanabe { 325bcff2d91STakanori Watanabe "le_read_local_supported_features", 326bcff2d91STakanori Watanabe "le_read_local_supported_features\n" 327bcff2d91STakanori Watanabe "read local supported features mask", 328bcff2d91STakanori Watanabe &le_read_local_supported_features, 329bcff2d91STakanori Watanabe }, 330bcff2d91STakanori Watanabe { 331bcff2d91STakanori Watanabe "le_read_supported_status", 332bcff2d91STakanori Watanabe "le_read_supported_status\n" 333bcff2d91STakanori Watanabe "read supported status" 334bcff2d91STakanori Watanabe , 335bcff2d91STakanori Watanabe &le_read_supported_status, 336bcff2d91STakanori Watanabe }, 337bcff2d91STakanori Watanabe { 338bcff2d91STakanori Watanabe "le_set_scan_response", 339bcff2d91STakanori Watanabe "le_set_scan_response -n $name -f $flag -u $uuid16,$uuid16 \n" 340bcff2d91STakanori Watanabe "set LE scan response data" 341bcff2d91STakanori Watanabe , 342bcff2d91STakanori Watanabe &le_set_scan_response, 343bcff2d91STakanori Watanabe }, 344bcff2d91STakanori Watanabe { 345bcff2d91STakanori Watanabe "le_set_scan_enable", 346bcff2d91STakanori Watanabe "le_set_scan_enable [enable|disable] \n" 347bcff2d91STakanori Watanabe "enable or disable LE device scan", 348bcff2d91STakanori Watanabe &le_set_scan_enable 349bcff2d91STakanori Watanabe }, 350bcff2d91STakanori Watanabe { 351bcff2d91STakanori Watanabe "le_set_scan_param", 352bcff2d91STakanori Watanabe "le_set_scan_param [active|passive] interval(ms) window(ms) [public|random] [all|whitelist] \n" 353bcff2d91STakanori Watanabe "set LE device scan parameter", 354bcff2d91STakanori Watanabe &le_set_scan_param 355bcff2d91STakanori Watanabe }, 356bcff2d91STakanori Watanabe }; 357