Ejemplo n.º 1
0
/**
* @brief Start low energy scan
*
* @param device_id
*
* @return 
*/
static int start_lescan(int device_id)
{
  int device_handle = 0;
  if((device_handle = hci_open_dev(device_id)) < 0)
  {
    perror("Could not open device");
    return -1;
  }
  uint8_t filter_policy = 0x00;
  uint16_t interval = htobs(0x0010);
  uint16_t window = htobs(0x0010);

  int err = hci_le_set_scan_parameters(device_handle, 0x01, interval, window, 0x00, filter_policy, 1000);
  if (err < 0) {
  	perror("Set scan parameters failed");
	return -1;
  }

  err = hci_le_set_scan_enable(device_handle, 0x01, 0, 1000);
  if (err < 0) {
 	perror("Enable scan failed");
	return -1;
  }
  return device_handle;
}
int main(int argc, char **argv)
{
    int dev_id;
    int err, opt, dd;
    uint8_t own_type = 0x00;
    uint8_t scan_type = 0x01;
    uint8_t filter_type = 0;
    uint8_t filter_policy = 0x00;
    uint16_t interval = htobs(0x0010);
    uint16_t window = htobs(0x0010);
    // uint8_t filter_dup = 1;
    uint8_t filter_dup = 0; // don't filter duplicate

    dev_id = hci_get_route(NULL);
    dd = hci_open_dev( dev_id );
    if (dev_id < 0 || dd < 0) {
        perror("opening socket");
        exit(1);
    }



    err = hci_le_set_scan_parameters(dd, scan_type, interval, window,
            own_type, filter_policy, 1000);

    if (err < 0) {
        perror("Set scan parameters failed");
    }

    err = hci_le_set_scan_enable(dd, 0x01, filter_dup, 1000);

    if (err < 0) {
        perror("Enable scan failed");
        exit(1);
    }

    printf("LE Scan ... \n");

    err = print_advertising_devices(dd, filter_type);

    if (err < 0) {
        perror("Could not receive advertising events");
        exit(1);
    }

    err = hci_le_set_scan_enable(dd, 0x00, filter_dup, 1000);
    if (err < 0) {
        perror("Disable scan failed");
        exit(1);
    }

    hci_close_dev(dd);
   
    return 0;
}
Ejemplo n.º 3
0
VALUE method_scan(int argc, VALUE *argv, VALUE klass)
{
  VALUE rb_device_id;
  int device_id;
  int device_handle;
  uint8_t scan_type = 0x01; //passive
  uint8_t own_type = 0x00; // I think this specifies not to use a random MAC
  uint8_t filter_dups = 0x00;
  uint8_t filter_policy = 0x00; // ?
  uint16_t interval = htobs(0x0005);
  uint16_t window = htobs(0x0005);

  struct hci_filter new_filter;
  socklen_t filter_size;

  // which device was specified?
  rb_scan_args(argc, argv, "01", &rb_device_id);
  if (rb_device_id == Qnil) {
    device_id = hci_get_route(NULL);
  } else {
    device_id = NUM2INT(rb_device_id);
  }
  // open the device
  if ( (device_handle = hci_open_dev(device_id)) < 0) {
    rb_raise(rb_eException, "Could not open device");
  }
  device_handles[device_id] = device_handle;
 
  // save the old filter so we can restore it later
  filter_size = sizeof(stored_filters[0]);
  if (getsockopt(device_handle, SOL_HCI, HCI_FILTER, &stored_filters[device_id], &filter_size) < 0) {
    rb_raise(rb_eException, "Could not get socket options");
  }

  // new filter to only look for event packets
  hci_filter_clear(&new_filter);
  hci_filter_set_ptype(HCI_EVENT_PKT, &new_filter);
  hci_filter_set_event(EVT_LE_META_EVENT, &new_filter);
  if (setsockopt(device_handle, SOL_HCI, HCI_FILTER, &new_filter, sizeof(new_filter)) < 0) {
    rb_raise(rb_eException, "Could not set socket options");
  }

  // set the params
  hci_le_set_scan_parameters(device_handle, scan_type, interval, window, own_type, filter_policy, 1000);
  hci_le_set_scan_enable(device_handle, 0x01, filter_dups, 1000);

  // perform the scan and make sure device gets put back into a proper state
  // even in the case of being interrupted by a ruby exception
  rb_ensure(perform_scan, INT2FIX(device_id), stop_scan, INT2FIX(device_id));
  return Qnil;
}
Ejemplo n.º 4
0
void Bluetooth::scanStart()
{
    int stat;
    const int TIMEOUT = 1000;

    stat = hci_le_set_scan_parameters(_sock, 0x01, htobs(0x0010), htobs(0x0010), 0x00, 0x00, TIMEOUT);
    if (stat < 0) {
	printf("ERROR hci_le_set_scan_parameters\n");
	return;
    }

    stat = hci_le_set_scan_enable(_sock, 1, 1, TIMEOUT);
    if (stat < 0) {
	printf("ERROR hci_le_set_scan_enable\n");
	return;
    }  
}
void start_hci_scan(struct hci_state current_hci_state)
{
  if(hci_le_set_scan_parameters(current_hci_state.device_handle, 0x01, htobs(0x0010), htobs(0x0010), 0x00, 0x00, 1000) < 0) 
  {
    current_hci_state.has_error = TRUE;
    snprintf(current_hci_state.error_message, sizeof(current_hci_state.error_message), "Failed to set scan parameters: %s", strerror(errno));
    return;
  }

  if(hci_le_set_scan_enable(current_hci_state.device_handle, 0x01, 1, 1000) < 0) 
  {
    current_hci_state.has_error = TRUE;
    snprintf(current_hci_state.error_message, sizeof(current_hci_state.error_message), "Failed to enable scan: %s", strerror(errno));
    return;
  }

  current_hci_state.state = HCI_STATE_SCANNING;

  // Save the current HCI filter
  socklen_t olen = sizeof(current_hci_state.original_filter);
  if(getsockopt(current_hci_state.device_handle, SOL_HCI, HCI_FILTER, &current_hci_state.original_filter, &olen) < 0) 
  {
    current_hci_state.has_error = TRUE;
    snprintf(current_hci_state.error_message, sizeof(current_hci_state.error_message), "Could not get socket options: %s", strerror(errno));
    return;
  }

  // Create and set the new filter
  struct hci_filter new_filter;

  hci_filter_clear(&new_filter);
  hci_filter_set_ptype(HCI_EVENT_PKT, &new_filter);
  hci_filter_set_event(EVT_LE_META_EVENT, &new_filter);

  if(setsockopt(current_hci_state.device_handle, SOL_HCI, HCI_FILTER, &new_filter, sizeof(new_filter)) < 0) 
  {
    current_hci_state.has_error = TRUE;
    snprintf(current_hci_state.error_message, sizeof(current_hci_state.error_message), "Could not set socket options: %s", strerror(errno));
    return;
  }

  current_hci_state.state = HCI_STATE_FILTERING;
}
Ejemplo n.º 6
0
static int ble_scan_enable(int device_desc) {
	uint16_t interval = htobs(DISCOV_LE_SCAN_INT);
	uint16_t window = htobs(DISCOV_LE_SCAN_WIN);
	uint8_t own_address_type = 0x00;
	uint8_t filter_policy = 0x00;

	int ret = hci_le_set_scan_parameters(device_desc, LE_SCAN_ACTIVE, interval, window, own_address_type, filter_policy, 10000);
	if (ret < 0) {
		fprintf(stderr, "ERROR: Set scan parameters failed (are you root?).\n");
		return 1;
	}

	ret = hci_le_set_scan_enable(device_desc, 0x01, 1, 10000);
	if (ret < 0) {
		fprintf(stderr, "ERROR: Enable scan failed.\n");
		return 1;
	}

	return 0;
}
Ejemplo n.º 7
0
int do_lescan() {
    int dev_id, sock;
    int ret;

    if (!strncmp(g_src, "hci", 3))
        dev_id = atoi(g_src + 3);
    else
        dev_id = hci_get_route(NULL);
    sock = hci_open_dev(dev_id);
    if (dev_id < 0 || sock < 0) {
        perror("opening socket");
        exit(1);
    }

    uint8_t own_type = 0x00;
    uint16_t interval = htobs(0x0012);
    uint16_t window = htobs(0x0012);
    uint8_t scan_type = 0x01;
    uint8_t filter_dup = 1;
    uint8_t filter_type = 0;
    ret = hci_le_set_scan_parameters(sock, scan_type, interval, window,
            own_type, 0x00, 1000);
    if (ret) {
        perror("hci_le_set_scan_parameters");
        exit(1);
    }

    ret = hci_le_set_scan_enable(sock, 0x01, filter_dup, 1000);
    if (ret) {
        perror("hci_le_set_scan_enable");
        exit(1);
    }

    print_advertising_devices(sock, filter_type);

    ret = hci_le_set_scan_enable(sock, 0x00, filter_dup, 1000);

    close(sock);
    return 0;
}
Ejemplo n.º 8
0
char *hci_LE_get_RSSI(hci_socket_t *hci_socket, hci_controller_t *hci_controller,
		      int8_t *file_descriptor,
		      bt_address_t *mac, uint16_t max_rsp, uint8_t scan_type, uint16_t scan_interval,
		      uint16_t scan_window, uint8_t own_add_type, uint8_t scan_filter_policy) {

	if (!hci_controller) {
		print_trace(TRACE_ERROR, "hci_LE_get_RSSI : invalid controller reference.\n");
		return NULL;
	}

	if (hci_controller->interrupted) {
		hci_resolve_interruption(hci_socket, hci_controller);
	}

	if (hci_controller->state != HCI_STATE_OPEN) {
		print_trace(TRACE_ERROR, "hci_LE_get_RSSI : busy or closed controller.\n");
		return NULL;
	}

	// Resulting string :
	char *res = NULL;

	FILE *file = NULL;

	print_trace(TRACE_INFO, "1. Opening socket...");
	char new_socket = 0;
	char socket_err = 0;
	check_hci_socket_ptr(&hci_socket, hci_controller, &new_socket, &socket_err);
	if (socket_err) {
		return NULL;
	}

	print_trace(TRACE_INFO, " [DONE]\n");

	struct pollfd p;
	// Initializing the connection poll on our HCI socket :
	p.fd = hci_socket->sock;
	p.events = POLLIN;
	unsigned char buf[HCI_MAX_EVENT_SIZE]; 

	hci_event_hdr event_header;
	unsigned char *event_parameter;

	struct hci_filter flt;	
	struct hci_filter old_flt;

	// Creating our filter :
	hci_compute_filter(&flt, EVT_CMD_COMPLETE,
			   EVT_LE_META_EVENT,
			   EVT_LE_ADVERTISING_REPORT,
			   0);

	//hci_filter_all_events(&flt);

	/* Saving the old filter.
	   This can be helpful in a case where we want to use a same socket for different purposes
	   (even with multiple threads), we can replace the old filter and re-use it later.
	*/
	print_trace(TRACE_INFO, "2. Saving old filter...");
	char saved_flt = 1;
	if (!new_socket) {
		if (get_hci_socket_filter(*hci_socket, &old_flt) < 0) {
			saved_flt = 0;
		}
	}
	print_trace(TRACE_INFO, " [DONE]\n");

	// Applying the new filter :
	print_trace(TRACE_INFO, "3. Applying new filter...");
	if (set_hci_socket_filter(*hci_socket, &flt) < 0) {
		goto end;
	}
	print_trace(TRACE_INFO, " [DONE]\n");

	print_trace(TRACE_INFO, "4. Setting scan parameters...");
	hci_change_state(hci_controller, HCI_STATE_WRITING);
	pthread_mutex_lock(&hci_controller_mutex);
	if (hci_le_set_scan_parameters(hci_socket->sock, scan_type, scan_interval, // cf p 1066 spec
				      scan_window, own_add_type, scan_filter_policy, 2*HCI_CONTROLLER_DEFAULT_TIMEOUT) < 0) { 
		// last parameter is timeout (for reaching the controler) 0 = infinity.
		print_trace(TRACE_ERROR, " [ERROR] \n");
		perror("set_scan_parameters");
		goto end;
	}
	print_trace(TRACE_INFO, " [DONE]\n");
	hci_change_state(hci_controller, HCI_STATE_OPEN);
	pthread_mutex_unlock(&hci_controller_mutex);

	print_trace(TRACE_INFO, "5. Enabling scan...");
	pthread_mutex_lock(&hci_controller_mutex);
	hci_change_state(hci_controller, HCI_STATE_SCANNING);
	if (hci_le_set_scan_enable(hci_socket->sock, htobs(0x01), htobs(0x00), 2*HCI_CONTROLLER_DEFAULT_TIMEOUT) < 0) { // Duplicate filtering ? (cf p1069)
		print_trace(TRACE_ERROR, " [ERROR] \n");
		perror("set_scan_enable");
		goto end;
	}
	print_trace(TRACE_INFO, " [DONE]\n"); 
	pthread_mutex_unlock(&hci_controller_mutex);

	char canceled = 0;
	int k = 0;

	print_trace(TRACE_INFO, "6. Checking response events...\n");

	int8_t n = 0;
	int16_t len = 0;

	res = calloc(6*max_rsp, sizeof(char));
	res[0] = '\0';

	while(!canceled && (!(max_rsp > 0) || (k < max_rsp))) {
		p.revents = 0;
		n = 0;
		len = 0;

		// Polling the BT device for an event :
		while ((n = poll(&p, 1, 5000)) < 0) {
			if (errno == EAGAIN || EINTR) {
				continue;
			}
			perror("hci_LE_get_RSSI : error while polling the socket");
			canceled = 1;
		}
		if (canceled) {
			break;
		}

		if (!n) {
			errno = ETIMEDOUT;
			perror("hci_LE_get_RSSI : error while polling the socket");
			break;
		}

		while ((len = read(hci_socket->sock, buf, sizeof(buf))) < 0) {
			if (errno == EAGAIN || errno == EINTR)
				continue;
			perror("hci_LE_get_RSSI : error while reading the socket");
			canceled = 1;
		}
		if (canceled) {
			break;
		}

		if (len == 0) {
			print_trace(TRACE_WARNING, "hci_LE_get_RSSI : nothing to read on the socket.\n");
			break;
		}

		// WHAT IS buf[0] ? Maybe a parameter added by "read()" ???
		event_header.evt = buf[1];
		event_header.plen = buf[2];
			
		event_parameter = (void *)(buf + HCI_EVENT_HDR_SIZE + 1);
		uint8_t subevent_code = *(event_parameter);
		event_parameter = (void *)(event_parameter + 1);
		int num_reports = *event_parameter;
		event_parameter = (void *)(event_parameter + 1);

		switch (event_header.evt) {
		case EVT_LE_META_EVENT: // Code 0x3E
			switch (subevent_code) {
			case EVT_LE_ADVERTISING_REPORT:
				for (uint16_t i = 0; i < num_reports; i++) {
					bt_device_t bt_device;
					
					// Address field :
					bt_address_t *rsp_mac = (bt_address_t *)(event_parameter +
									 num_reports*(1+1) +
									 6*i); // @ on 6 bytes.
					if (!bt_already_registered_device(*rsp_mac)) {
						uint8_t *address_type;
						// Address type field :
						address_type = (uint8_t *)(event_parameter + 1*num_reports + i);
						bt_device.mac = *rsp_mac;
						bt_device.add_type = *address_type;
						strcpy(bt_device.custom_name, "UNKNOWN");
						bt_register_device(bt_device);
					} else {
						bt_device = bt_get_device(*rsp_mac);
					}

					if (mac != NULL && !(bt_compare_addresses(mac, rsp_mac))) {
						continue;
					}

					// Length_data field :
					uint8_t *length_data = (uint8_t *)(event_parameter +
									   num_reports*(1+1+6) + i);

					// RSSI field :
					int8_t *rssi = (int8_t *)(event_parameter + 
								  (1+1+6+1+(*length_data))*num_reports + i); // rssi on 1byte
					if (*rssi == 127) {
						print_trace(TRACE_WARNING, "hci_LE_get_rssi : RSSI measure unavailable.\n");
					} else if (*rssi >= 21) {
						print_trace(TRACE_ERROR, "hci_LE_get_rssi : error while reading RSSI measure.\n");
					}

					// Display info :
					bt_device_display(bt_device);

					if (file_descriptor && *file_descriptor >= 0) {
						char rssi_string[RSSI_STRING_LENGTH] = {0};
						snprintf(rssi_string, RSSI_STRING_LENGTH, "%i \n", *rssi);
						if (write(*file_descriptor, rssi_string, RSSI_STRING_LENGTH) < RSSI_STRING_LENGTH) {
							print_trace(TRACE_WARNING, "Unable to write rssi value into given fd\n");
						}
					}
					if (file) {
						fprintf(file, "%i\n", *rssi);
					}
					char rssi_string_val[5] = {0};
					snprintf(rssi_string_val, 5, "%i ;", *rssi);
					strcat(res, rssi_string_val);
					k++;
				}
				break;
					
			default:
				print_trace(TRACE_WARNING, "hci_LE_get_rssi : an unknown LE sub-event occured : 0x%X \n",
					    subevent_code);
				break;
			}
			break;
		default:
			print_trace(TRACE_WARNING, "hci_LE_get_rssi : an unknown LE sub-event occured : 0x%X \n",
				    subevent_code);
			break;
		}
	}

	print_trace(TRACE_INFO, "Scan complete !\n");
	
	print_trace(TRACE_INFO, "7. Disabling scan...");
	pthread_mutex_lock(&hci_controller_mutex);
	if (hci_le_set_scan_enable(hci_socket->sock, htobs(0x00), htobs(0x00), 2*HCI_CONTROLLER_DEFAULT_TIMEOUT) < 0) {
		print_trace(TRACE_ERROR, " [ERROR] \n");
		perror("set_scan_disable");
		hci_controller->interrupted = 1;
		goto end;
	}
	print_trace(TRACE_INFO, " [DONE]\n"); 
	hci_change_state(hci_controller, HCI_STATE_OPEN);
	pthread_mutex_unlock(&hci_controller_mutex);

 end :	
	if (!hci_controller->interrupted) {
		hci_change_state(hci_controller, HCI_STATE_OPEN);
	}
	pthread_mutex_trylock(&hci_controller_mutex);
	pthread_mutex_unlock(&hci_controller_mutex);
	
	if (new_socket) {
		close_hci_socket(hci_socket);
		free(hci_socket);
	} else {			
		// Restoring the old filter :
		if (saved_flt) {
			set_hci_socket_filter(*hci_socket, &old_flt);
		}
	}

	if (file) {
		fclose(file);
	}

	return res;
}
Ejemplo n.º 9
0
int main(int argc, const char* argv[])
{
  char *hciDeviceIdOverride = NULL;
  int hciDeviceId = 0;
  int hciSocket;
  struct hci_dev_info hciDevInfo;

  struct hci_filter oldHciFilter;
  struct hci_filter newHciFilter;
  socklen_t oldHciFilterLen;

  int previousAdapterState = -1;
  int currentAdapterState;
  const char* adapterState = NULL;

  fd_set rfds;
  struct timeval tv;
  int selectRetval;

  unsigned char hciEventBuf[HCI_MAX_EVENT_SIZE];
  int hciEventLen;
  evt_le_meta_event *leMetaEvent;
  le_advertising_info *leAdvertisingInfo;
  char btAddress[18];
  int i;
  int scanning = 0;
  int8_t rssi;

  memset(&hciDevInfo, 0x00, sizeof(hciDevInfo));

  // setup signal handlers
  signal(SIGINT, signalHandler);
  signal(SIGKILL, signalHandler);
  signal(SIGUSR1, signalHandler);
  signal(SIGUSR2, signalHandler);
  signal(SIGHUP, signalHandler);

  prctl(PR_SET_PDEATHSIG, SIGKILL);

  // remove buffering
  setbuf(stdin, NULL);
  setbuf(stdout, NULL);
  setbuf(stderr, NULL);

  hciDeviceIdOverride = getenv("NOBLE_HCI_DEVICE_ID");
  if (hciDeviceIdOverride != NULL) {
    hciDeviceId = atoi(hciDeviceIdOverride);
  } else {
    // if no env variable given, use the first available device
    hciDeviceId = hci_get_route(NULL);
  }

  if (hciDeviceId < 0) {
    hciDeviceId = 0; // use device 0, if device id is invalid
  }

  // setup HCI socket
  hciSocket = hci_open_dev(hciDeviceId);

  if (hciSocket == -1) {
    printf("adapterState unsupported\n");
    return -1;
  }
  hciDevInfo.dev_id = hciDeviceId;

  // get old HCI filter
  oldHciFilterLen = sizeof(oldHciFilter);
  getsockopt(hciSocket, SOL_HCI, HCI_FILTER, &oldHciFilter, &oldHciFilterLen);

  // setup new HCI filter
  hci_filter_clear(&newHciFilter);
  hci_filter_set_ptype(HCI_EVENT_PKT, &newHciFilter);
  hci_filter_set_event(EVT_LE_META_EVENT, &newHciFilter);
  setsockopt(hciSocket, SOL_HCI, HCI_FILTER, &newHciFilter, sizeof(newHciFilter));

  while(1) {
    FD_ZERO(&rfds);
    FD_SET(hciSocket, &rfds);

    tv.tv_sec = 1;
    tv.tv_usec = 0;

    // get HCI dev info for adapter state
    ioctl(hciSocket, HCIGETDEVINFO, (void *)&hciDevInfo);
    currentAdapterState = hci_test_bit(HCI_UP, &hciDevInfo.flags);

    if (previousAdapterState != currentAdapterState) {
      previousAdapterState = currentAdapterState;

      if (!currentAdapterState) {
        adapterState = "poweredOff";
      } else if (hci_le_set_scan_parameters(hciSocket, 0x01, htobs(0x0010), htobs(0x0010), 0x00, 0, 1000) < 0) {
        if (EPERM == errno) {
          adapterState = "unauthorized";
        } else if (EIO == errno) {
          adapterState = "unsupported";
        } else {
          adapterState = "unknown";
        }
      } else {
        adapterState = "poweredOn";
      }

      printf("adapterState %s\n", adapterState);
    }

    selectRetval = select(hciSocket + 1, &rfds, NULL, NULL, &tv);

    if (-1 == selectRetval) {
      if (SIGINT == lastSignal || SIGKILL == lastSignal) {
        // done
        break;
      } else if (SIGUSR1 == lastSignal) {
        // start scan, filter
        scanning = 1;

        hci_le_set_scan_enable(hciSocket, 0x00, 1, 1000);
        hci_le_set_scan_enable(hciSocket, 0x01, 1, 1000);
      } else if (SIGUSR2 == lastSignal) {
        // start scan, no filter
        scanning = 1;

        hci_le_set_scan_enable(hciSocket, 0x00, 0, 1000);
        hci_le_set_scan_enable(hciSocket, 0x01, 0, 1000);
      } else if (SIGHUP == lastSignal) {
        // stop scan
        scanning = 0;

        hci_le_set_scan_enable(hciSocket, 0x00, 0, 1000);
      }
    } else if (selectRetval) {
      // read event
      hciEventLen = read(hciSocket, hciEventBuf, sizeof(hciEventBuf));
      leMetaEvent = (evt_le_meta_event *)(hciEventBuf + (1 + HCI_EVENT_HDR_SIZE));
      hciEventLen -= (1 + HCI_EVENT_HDR_SIZE);

      if (!scanning) {
        // ignore, not scanning
        continue;
      }

      if (leMetaEvent->subevent != 0x02) {
        continue;
      }

      leAdvertisingInfo = (le_advertising_info *)(leMetaEvent->data + 1);
      ba2str(&leAdvertisingInfo->bdaddr, btAddress);

      printf("event %s,%s,", btAddress, (leAdvertisingInfo->bdaddr_type == LE_PUBLIC_ADDRESS) ? "public" : "random");

      for (i = 0; i < leAdvertisingInfo->length; i++) {
          printf("%02x", leAdvertisingInfo->data[i]);
      }

      rssi = *(leAdvertisingInfo->data + leAdvertisingInfo->length);

      printf(",%d\n", rssi);
    }
  }

  // restore original filter
  setsockopt(hciSocket, SOL_HCI, HCI_FILTER, &oldHciFilter, sizeof(oldHciFilter));

  // disable LE scan
  hci_le_set_scan_enable(hciSocket, 0x00, 0, 1000);

  close(hciSocket);

  return 0;
}
Ejemplo n.º 10
0
static int cmd_lescan(int dev_id)
{
  int hci_dev = 0;
  int err = 0, opt = 0, dd = 0;

  uint8_t own_type = 0x00;
  uint8_t scan_type = 0x01;
  uint8_t filter_type = 0;
  uint8_t filter_policy = 0x00;
  uint8_t filter_dup = 1;

  uint16_t interval = htobs(0x0010);
  uint16_t window = htobs(0x0010);

  if (dev_id < 0) {
    dev_id = hci_get_route(NULL);
  }

  if (dev_id < 0) {
    return -1;
  }

  if((hci_dev = hci_open_dev(dev_id)) < 0) {
    printf("Opening hci device failed\n");
    return -2;
  }

  err = hci_le_set_scan_parameters(hci_dev, scan_type, interval, window, own_type, filter_policy, 2000);
  if (err < 0) {
    printf("Setting scan parameters failed %d\n", err);
    return -3;
  }

  err = hci_le_set_scan_enable(hci_dev, 0x01, filter_dup, 1000);
  if (err < 0) {
    printf("Enabling the scan failed\n");
    return -4;
  }

  struct sigaction sa;
  sa.sa_flags = SA_NOCLDSTOP;
  sa.sa_handler = signal_handler;
  sigaction(SIGINT, &sa, NULL);
  unsigned char buf[HCI_MAX_EVENT_SIZE], *ptr;
  int len, sl_no = 0;

  socklen_t olen = sizeof(old_filter);

  if (getsockopt(hci_dev, SOL_HCI, HCI_FILTER, &old_filter, &olen) < 0) {
    printf("getsockopt failed\n");
    btcmd_stop_scanning(hci_dev);
    return -5;
  }

  struct hci_filter filter;
  hci_filter_clear(&filter);
  hci_filter_set_ptype(HCI_EVENT_PKT, &filter);
  hci_filter_set_event(EVT_LE_META_EVENT, &filter);

  if (setsockopt(hci_dev, SOL_HCI, HCI_FILTER, &filter, sizeof(filter)) < 0) {
    printf("setsockopt failed\n");
    btcmd_stop_scanning(hci_dev);
    return -6;
  }

  finish_scanning = 0;

  while(1) {
    le_advertising_info *info;
    evt_le_meta_event *meta;
    char addr[20];

    while ((len = read(hci_dev, buf, sizeof(buf))) < 0) {
      set_state(STATE_SCANNING);
      if (errno == EINTR && finish_scanning) {
        len = 0;
        goto done;
      }
      if (errno == EAGAIN) {
        continue;
      }
      /* anything else, just end the loop */
      goto done;
    }

    ptr = buf + (1 + HCI_EVENT_HDR_SIZE);
    len -= (1 + HCI_EVENT_HDR_SIZE);

    meta = (void *) ptr;

    if (meta->subevent != 0x02) {
      goto done;
    }

    info = (le_advertising_info *) (meta->data + 1);

    memset(addr, 0, sizeof(addr));

    address2string(&info->bdaddr, addr);
    /* Socket gives same BT address twice, and we need to eliminate
     * duplicate entries
     */
    static int duplicate = 0;
    if (duplicate == 0) {
      printf("%s\n", addr);
      duplicate = 1;
    } else if (duplicate) {
      duplicate = 0;
    }
  } /* while (1) */

done:
    btcmd_stop_scanning(hci_dev);
    set_state(STATE_DISCONNECTED);

    return 0;
}