static void configure_device(int dev_id) { struct device_opts *device_opts; struct hci_dev_req dr; struct hci_dev_info di; char mode[14]; int dd; device_opts = get_device_opts(dev_id); if (hci_devinfo(dev_id, &di) < 0) return; if (hci_test_bit(HCI_RAW, &di.flags)) return; /* Set default discoverable timeout if not set */ if (!(device_opts->flags & (1 << HCID_SET_DISCOVTO))) device_opts->discovto = HCID_DEFAULT_DISCOVERABLE_TIMEOUT; /* Set scan mode */ if (read_device_mode(&di.bdaddr, mode, sizeof(mode)) == 0) { if (!strcmp(mode, "off") && hcid.offmode == HCID_OFFMODE_NOSCAN) { device_opts->mode = MODE_OFF; device_opts->scan = SCAN_DISABLED; } else if (!strcmp(mode, "connectable")) { device_opts->mode = MODE_CONNECTABLE; device_opts->scan = SCAN_PAGE; } else if (!strcmp(mode, "discoverable")) { /* Set discoverable only if timeout is 0 */ if (!get_discoverable_timeout(dev_id)) { device_opts->scan = SCAN_PAGE | SCAN_INQUIRY; device_opts->mode = MODE_DISCOVERABLE; } else { device_opts->scan = SCAN_PAGE; device_opts->mode = MODE_CONNECTABLE; } } else if (!strcmp(mode, "limited")) { /* Set discoverable only if timeout is 0 */ if (!get_discoverable_timeout(dev_id)) { device_opts->scan = SCAN_PAGE | SCAN_INQUIRY; device_opts->mode = MODE_LIMITED; } else { device_opts->scan = SCAN_PAGE; device_opts->mode = MODE_CONNECTABLE; } } } /* Do configuration in the separate process */ switch (fork()) { case 0: atexit(at_child_exit); break; case -1: error("Fork failed. Can't init device hci%d: %s (%d)", dev_id, strerror(errno), errno); default: return; } dd = hci_open_dev(dev_id); if (dd < 0) { error("Can't open device hci%d: %s (%d)", dev_id, strerror(errno), errno); exit(1); } memset(&dr, 0, sizeof(dr)); dr.dev_id = dev_id; /* Set packet type */ if ((device_opts->flags & (1 << HCID_SET_PTYPE))) { dr.dev_opt = device_opts->pkt_type; if (ioctl(dd, HCISETPTYPE, (unsigned long) &dr) < 0) { error("Can't set packet type on hci%d: %s (%d)", dev_id, strerror(errno), errno); } } /* Set link mode */ if ((device_opts->flags & (1 << HCID_SET_LM))) { dr.dev_opt = device_opts->link_mode; if (ioctl(dd, HCISETLINKMODE, (unsigned long) &dr) < 0) { error("Can't set link mode on hci%d: %s (%d)", dev_id, strerror(errno), errno); } } /* Set link policy */ if ((device_opts->flags & (1 << HCID_SET_LP))) { dr.dev_opt = device_opts->link_policy; if (ioctl(dd, HCISETLINKPOL, (unsigned long) &dr) < 0) { error("Can't set link policy on hci%d: %s (%d)", dev_id, strerror(errno), errno); } } /* Set device name */ if ((device_opts->flags & (1 << HCID_SET_NAME)) && device_opts->name) { change_local_name_cp cp; memset(cp.name, 0, sizeof(cp.name)); expand_name((char *) cp.name, sizeof(cp.name), device_opts->name, dev_id); hci_send_cmd(dd, OGF_HOST_CTL, OCF_CHANGE_LOCAL_NAME, CHANGE_LOCAL_NAME_CP_SIZE, &cp); } /* Set device class */ if ((device_opts->flags & (1 << HCID_SET_CLASS))) { write_class_of_dev_cp cp; uint32_t class; uint8_t cls[3]; if (read_local_class(&di.bdaddr, cls) < 0) { class = htobl(device_opts->class); cls[2] = get_service_classes(&di.bdaddr); memcpy(cp.dev_class, &class, 3); } else { if (!(device_opts->scan & SCAN_INQUIRY))
int do_configure_device(int hdev) { struct device_opts *device_opts; struct hci_dev_req dr; struct hci_dev_info di; int s; set_title("hci%d config", hdev); if ((s = hci_open_dev(hdev)) < 0) { syslog(LOG_ERR, "Can't open device hci%d: %s (%d)", hdev, strerror(errno), errno); exit(1); } di.dev_id = hdev; if (ioctl(s, HCIGETDEVINFO, (void *) &di) < 0) exit(1); if (hci_test_bit(HCI_RAW, &di.flags)) exit(0); dr.dev_id = hdev; device_opts = get_device_opts(s, hdev); /* Set scan mode */ dr.dev_opt = device_opts->scan; if (ioctl(s, HCISETSCAN, (unsigned long) &dr) < 0) { syslog(LOG_ERR, "Can't set scan mode on hci%d: %s (%d)", hdev, strerror(errno), errno); } /* Set authentication */ if (device_opts->auth) dr.dev_opt = AUTH_ENABLED; else dr.dev_opt = AUTH_DISABLED; if (ioctl(s, HCISETAUTH, (unsigned long) &dr) < 0) { syslog(LOG_ERR, "Can't set auth on hci%d: %s (%d)", hdev, strerror(errno), errno); } /* Set encryption */ if (device_opts->encrypt) dr.dev_opt = ENCRYPT_P2P; else dr.dev_opt = ENCRYPT_DISABLED; if (ioctl(s, HCISETENCRYPT, (unsigned long) &dr) < 0) { syslog(LOG_ERR, "Can't set encrypt on hci%d: %s (%d)", hdev, strerror(errno), errno); } /* Set device name */ if ((device_opts->flags & (1 << HCID_SET_NAME)) && device_opts->name) { change_local_name_cp cp; write_ext_inquiry_response_cp ip; uint8_t len; memset(cp.name, 0, sizeof(cp.name)); expand_name((char *) cp.name, sizeof(cp.name), device_opts->name, hdev); ip.fec = 0x00; memset(ip.data, 0, sizeof(ip.data)); len = strlen((char *) cp.name); if (len > 48) { len = 48; ip.data[1] = 0x08; } else ip.data[1] = 0x09; ip.data[0] = len + 1; memcpy(ip.data + 2, cp.name, len); hci_send_cmd(s, OGF_HOST_CTL, OCF_CHANGE_LOCAL_NAME, CHANGE_LOCAL_NAME_CP_SIZE, &cp); if (di.features[6] & LMP_EXT_INQ) hci_send_cmd(s, OGF_HOST_CTL, OCF_WRITE_EXT_INQUIRY_RESPONSE, WRITE_EXT_INQUIRY_RESPONSE_CP_SIZE, &ip); } /* Set device class */ if ((device_opts->flags & (1 << HCID_SET_CLASS))) { uint32_t class = htobl(device_opts->class); write_class_of_dev_cp cp; memcpy(cp.dev_class, &class, 3); hci_send_cmd(s, OGF_HOST_CTL, OCF_WRITE_CLASS_OF_DEV, WRITE_CLASS_OF_DEV_CP_SIZE, &cp); }