views:

18

answers:

0

Hi,

I have a question having to do with Bluetooth programming in C. I'm working on the Android platform, but anyone skilled with the Bluez stack should be able to lend some insight...

I am trying to write an application to capture Bluetooth packets from within an Android application, which is written in Java and runs in the Dalvik Virtual Machine. The code that interfaces with Bluetooth HCI is written in C in a JNI shared library.

My method is based on some code I borrowed from the "hcidump" utility, a packet sniffer:

dd = hci_open_dev(0);
if (dd < 0) {
    LOGE("Can't open device"); return -1;
}
if (hci_devinfo(dev, &di) < 0) {
    LOGE("Can't get device info"); return -1;
}

This section of the code works fine. Next:

opt = hci_test_bit(HCI_RAW, &di.flags);
if (ioctl(dd, HCISETRAW, opt) < 0) {
    if (errno == EACCES) {
        LOGE("Can't access device");
        LOGE("ERRNO == EACCES !!! ");
        ////return -1;
    }
}

The problem is, the call to ioctl fails and errno is set to EACCES, which means "Permission denied." I have root access on this device and I could presumably set permissions so it would work (if I knew how). BUT, at least part of it appears to work if I let the code continue:

hci_close_dev(dd);

LOGE("CONTINUING!");

/* Create HCI socket */
sk = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);

if (sk < 0) {
    LOGE("Can't create raw socket"); return -1;
}

opt = 1;
if (setsockopt(sk, SOL_HCI, HCI_DATA_DIR, &opt, sizeof(opt)) < 0) {
    LOGE("Can't enable data direction info"); return -1;
}

opt = 1;
if (setsockopt(sk, SOL_HCI, HCI_TIME_STAMP, &opt, sizeof(opt)) < 0) {
    LOGE("Can't enable time stamp"); return -1;
}

/* Setup filter */
hci_filter_clear(&flt);
hci_filter_all_ptypes(&flt);
hci_filter_all_events(&flt);
if (setsockopt(sk, SOL_HCI, HCI_FILTER, &flt, sizeof(flt)) < 0) {
    LOGE("Can't set filter"); return -1;
}

LOGE("About to try to bind socket!");

/* Bind socket to the HCI device */
addr.hci_family = AF_BLUETOOTH;
addr.hci_dev = dev;
if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
  char buf[100];
  sprintf(buf, "Can't attach to device hci%d. %s(%d)\n", dev, strerror(errno), errno);
  LOGE(buf);
  return -1;
}

LOGE("SUCCESFULLY BOUND SOCKET!");
return sk;

All of this code runs without any of the errors happening. Next, I get into my main loop which calls "poll" to receive data.

while (1) {
    LOGE("Polling!");
    int i, n = poll(fds, nfds, -1);
    LOGE("Finished poll!");
    if (n <= 0) {
        LOGE("Poll returned nothing -- continuing");
        continue;
    }
    // Process the data
}

Now (finally) I come to the weird thing: the call to "poll" NEVER prints out "Poll returned nothing -- continuing". Instead, it blocks until I press the button on my Bluetooth device and send some packets. Then, it says "Finished poll!", 7 bytes are printed by my loop, and then it returns to blocking at the "poll" call. This happens even if I hold down the button on the Bluetooth device, so a constant stream of packets are transmitted. Only the first 7 bytes appear, and then it blocks again. If I hold the button down for longer, poll will return (and the same packets will be printed) every 5 seconds, for as long as I hold the button down. If I leave the button up for more than 5 seconds and then press it, the same 7 bytes appear immediately, but then, as before, poll will block for either five seconds/until the next button press.

This behavior seems to me to mean that despite the "Permission denied" error, my program is managing to receive data from the device--but it isn't managing to print a continuous stream of all the raw data. (If I take the hcidump executable from which this code is derived and run it from a terminal, it prints the whole stream of many data packets for as long as the button is held down.)

Is this problem related to the permission denied problem, or is it separate? I could really use some help from an expert in low-level Bluetooth programming. Sorry for the long message, and many thanks for any help.

-- Tom