prop_dictionary_t cfg_query(bdaddr_t *laddr, bdaddr_t *raddr, const char *service) { prop_dictionary_t dict; sdp_session_t ss; size_t i; dict = prop_dictionary_create(); if (dict == NULL) err(EXIT_FAILURE, "prop_dictionary_create()"); for (i = 0; i < __arraycount(cfgtype); i++) { if (strcasecmp(service, cfgtype[i].name) == 0) { ss = sdp_open(laddr, raddr); if (ss == NULL) err(EXIT_FAILURE, "SDP connection failed"); if (!cfg_search(ss, i, dict)) errx(EXIT_FAILURE, "service %s not found", service); sdp_close(ss); return dict; } } printf("Known config types:\n"); for (i = 0; i < __arraycount(cfgtype); i++) printf("\t%s\t%s\n", cfgtype[i].name, cfgtype[i].description); exit(EXIT_FAILURE); }
int main() { sdp_open(); sdp_add_keyboard(); sleep(60); sdp_remove(); return(1); }
static int bt_query(struct l2cap_info *info, uint16_t service_class) { sdp_attr_t values[BT_NUM_VALUES]; uint8_t buffer[BT_NUM_VALUES][BT_BUF_SIZE]; void *ss; int psm = -1; int n; memset(buffer, 0, sizeof(buffer)); memset(values, 0, sizeof(values)); ss = sdp_open(&info->laddr, &info->raddr); if (ss == NULL || sdp_error(ss) != 0) { DPRINTF("Could not open SDP\n"); return (psm); } /* Initialize attribute values array */ for (n = 0; n != BT_NUM_VALUES; n++) { values[n].flags = SDP_ATTR_INVALID; values[n].vlen = BT_BUF_SIZE; values[n].value = buffer[n]; } /* Do SDP Service Search Attribute Request */ n = sdp_search(ss, 1, &service_class, 1, bt_attrs, BT_NUM_VALUES, values); if (n != 0) { DPRINTF("SDP search failed\n"); goto done; } /* Print attributes values */ for (n = 0; n != BT_NUM_VALUES; n++) { if (values[n].flags != SDP_ATTR_OK) break; if (values[n].attr != SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST) continue; psm = bt_find_psm(values[n].value, values[n].value + values[n].vlen); if (psm > -1) break; } done: sdp_close(ss); return (psm); }
int add_hid(int hid_mode) { int handle = 0x0; int ret = sdp_open(); if (ret == 0) { if ((handle = is_hid_sdp_record_registered()) == 0) { sdp_record = sdp_register_hid(hid_mode); if (sdp_record == NULL) { LOGE("Error register sdp record: %d\n", ret); sdp_close(sdp_session); return ret; } } else { LOGD("Nothing done; already registered\n"); sdp_close(sdp_session); return handle; } sdp_close(sdp_session); } return sdp_record->handle; }
/* Execute commands */ static int do_sdp_command(bdaddr_p bdaddr, char const *control, int local, int argc, char **argv) { char *cmd = argv[0]; struct sdp_command *c = NULL; void *xs = NULL; int e, help; help = 0; if (strcasecmp(cmd, "help") == 0) { argc --; argv ++; if (argc <= 0) { fprintf(stdout, "Supported commands:\n"); print_sdp_command(sdp_commands); fprintf(stdout, "\nFor more information use " \ "'help command'\n"); return (OK); } help = 1; cmd = argv[0]; } c = find_sdp_command(cmd, sdp_commands); if (c == NULL) { fprintf(stdout, "Unknown command: \"%s\"\n", cmd); return (ERROR); } if (!help) { if (!local) { if (memcmp(bdaddr, NG_HCI_BDADDR_ANY, sizeof(*bdaddr)) == 0) usage(); xs = sdp_open(NG_HCI_BDADDR_ANY, bdaddr); } else xs = sdp_open_local(control); if (xs == NULL) errx(1, "Could not create SDP session object"); if (sdp_error(xs) == 0) e = (c->handler)(xs, -- argc, ++ argv); else e = ERROR; } else e = USAGE; switch (e) { case OK: case FAILED: break; case ERROR: fprintf(stdout, "Could not execute command \"%s\". %s\n", cmd, strerror(sdp_error(xs))); break; case USAGE: fprintf(stdout, "Usage: %s\n%s\n", c->command, c->description); break; default: assert(0); break; } sdp_close(xs); return (e); } /* do_sdp_command */
static int find_service_channel(bdaddr_t *adapter, bdaddr_t *device, int only_gnapplet, uint16_t svclass_id) { int i, channel = -1; char name[64]; void *ss = NULL; uint32_t attrs[] = { SDP_ATTR_RANGE( SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST, SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST), SDP_ATTR_RANGE( SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_NAME_OFFSET, SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_NAME_OFFSET), }; /* Buffer for the attributes */ static uint8_t buffer[NRECS * attrs_len][BSIZE]; /* SDP attributes */ static sdp_attr_t values[NRECS * attrs_len]; /* Initialize attribute values array */ for (i = 0; i < values_len; i ++) { values[i].flags = SDP_ATTR_INVALID; values[i].attr = 0; values[i].vlen = BSIZE; values[i].value = buffer[i]; } if ((ss = sdp_open(adapter, device)) == NULL) return -1; if (sdp_error(ss) != 0) goto end; if (sdp_search(ss, 1, &svclass_id, attrs_len, attrs, values_len, values) != 0) goto end; for (i = 0; i < values_len; i++) { union { uint8_t uint8; uint16_t uint16; uint32_t uint32; uint64_t uint64; int128_t int128; } value; uint8_t *start, *end; uint32_t type, len; if (values[i].flags != SDP_ATTR_OK) break; start = values[i].value; end = values[i].value + values[i].vlen; switch (values[i].attr) { case SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST: SDP_GET8(type, start); switch (type) { case SDP_DATA_SEQ8: SDP_GET8(len, start); break; case SDP_DATA_SEQ16: SDP_GET16(len, start); break; case SDP_DATA_SEQ32: SDP_GET32(len, start); break; default: goto end; break; } SDP_GET8(type, start); switch (type) { case SDP_DATA_SEQ8: SDP_GET8(len, start); break; case SDP_DATA_SEQ16: SDP_GET16(len, start); break; case SDP_DATA_SEQ32: SDP_GET32(len, start); break; default: goto end; } while (start < end) { SDP_GET8(type, start); switch (type) { case SDP_DATA_UUID16: SDP_GET16(value.uint16, start); break; case SDP_DATA_UUID32: SDP_GET32(value.uint32, start); break; case SDP_DATA_UUID128: SDP_GET_UUID128(&value.int128, start); break; default: goto end; } if (value.uint16 == 3) { SDP_GET8(type, start); switch (type) { case SDP_DATA_UINT8: case SDP_DATA_INT8: SDP_GET8(value.uint8, start); channel = value.uint8; break; case SDP_DATA_UINT16: case SDP_DATA_INT16: SDP_GET16(value.uint16, start); channel = value.uint16; break; case SDP_DATA_UINT32: case SDP_DATA_INT32: SDP_GET32(value.uint32, start); channel = value.uint32; break; default: goto end; } } else { SDP_GET8(type, start); switch (type) { case SDP_DATA_SEQ8: case SDP_DATA_UINT8: case SDP_DATA_INT8: case SDP_DATA_BOOL: SDP_GET8(value.uint8, start); break; case SDP_DATA_SEQ16: case SDP_DATA_UINT16: case SDP_DATA_INT16: case SDP_DATA_UUID16: SDP_GET16(value.uint16, start); break; case SDP_DATA_SEQ32: case SDP_DATA_UINT32: case SDP_DATA_INT32: case SDP_DATA_UUID32: SDP_GET32(value.uint32, start); break; case SDP_DATA_UINT64: case SDP_DATA_INT64: SDP_GET64(value.uint64, start); break; case SDP_DATA_UINT128: case SDP_DATA_INT128: SDP_GET128(&value.int128, start); break; default: goto end; } } } start += len; break; case SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_NAME_OFFSET: if (channel == -1) break; SDP_GET8(type, start); switch (type) { case SDP_DATA_STR8: case SDP_DATA_URL8: SDP_GET8(len, start); snprintf(name, sizeof(name), "%*.*s", len, len, (char *) start); start += len; break; case SDP_DATA_STR16: case SDP_DATA_URL16: SDP_GET16(len, start); snprintf(name, sizeof(name), "%*.*s", len, len, (char *) start); start += len; break; case SDP_DATA_STR32: case SDP_DATA_URL32: SDP_GET32(len, start); snprintf(name, sizeof(name), "%*.*s", len, len, (char *) start); start += len; break; default: goto end; } if (name == NULL) break; if (only_gnapplet != 0) { if (strcmp(name, "gnapplet") == 0) goto end; else { channel = -1; break; } } if (strstr(name, "Nokia PC Suite") != NULL) { channel = -1; break; } if (strstr(name, "Bluetooth Serial Port") != NULL) { channel = -1; break; } if (strstr(name, "m-Router Connectivity") != NULL) { channel = -1; break; } goto end; } } end: sdp_close(ss); return channel; }
int main(int argc, char *argv[]) { int i; if (argc == 1) { printf("version : %s\n", HIDEMU_VERSION); return 0; } if(hci_get_route(NULL) < 0) { printf("Bluetooth off\n"); return -1; } if (DBG_CONSOLE) { for (i = 0; i < argc; i++) { printf("arg[%d]=%s\n", i, argv[i]); } } if (argc == ADD_HID_ARGS && (strncmp(argv[1], ADD_HID_GENERIC, strlen(argv[1])) == 0)) { int handle = add_hid(HID_MODE_GENERIC); printf("handle: 0x%X\n", handle); if (sdp_record != NULL) { sdp_record_free(sdp_record); } } else if (argc == ADD_HID_ARGS && (strncmp(argv[1], ADD_HID_BDREMOTE, strlen(argv[1])) == 0)) { int handle = add_hid(HID_MODE_BDREMOTE); printf("handle: 0x%X\n", handle); if (sdp_record != NULL) { sdp_record_free(sdp_record); } } else if (argc == ADD_HID_ARGS && (strncmp(argv[1], ADD_HID_PS3KEYPAD, strlen(argv[1])) == 0)) { int handle = add_hid(HID_MODE_PS3KEYPAD); printf("handle: 0x%X\n", handle); if (sdp_record != NULL) { sdp_record_free(sdp_record); } } else if (argc == DEL_HID_ARGS && (strncmp(argv[1], DEL_HID, strlen(argv[1])) == 0) && !strncasecmp(argv[2], "0x", 2)) { int handle = strtol(argv[2]+2, NULL, 16); printf("Removed handle: 0x%X\n", handle); if (!sdp_session) { sdp_open(sdp_session); } sdp_remove(handle); sdp_close(sdp_session); } else if (argc == READ_CLASS_ARGS && (strncmp(argv[1], READ_CLASS, strlen(argv[1])) == 0)) { uint8_t cls[3]; if (read_device_class(0, cls) == 0) { printf("class: 0x%02x%02x%02x\n", cls[2], cls[1], cls[0]); } } else if (argc == SPOOF_CLASS_ARGS && (strncmp(argv[1], SPOOF_CLASS, strlen(argv[1])) == 0)) { if (spoof_device_class(0, argv[2]) == 0) { printf("class spoofed.\n"); } } else { printf("Invalid arguments\n"); LOGE("Invalid arguments\n"); } return 0; }
static void client_query(void) { uint8_t buffer[512]; sdp_attr_t attr; uint32_t range; void *ss; int rv; uint8_t *seq0, *seq1; attr.flags = SDP_ATTR_INVALID; attr.attr = 0; attr.vlen = sizeof(buffer); attr.value = buffer; range = SDP_ATTR_RANGE(SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST, SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST); ss = sdp_open(&local_bdaddr, &remote_bdaddr); if (ss == NULL || (errno = sdp_error(ss)) != 0) { log_err("%s: %m", service_name); exit(EXIT_FAILURE); } log_info("Searching for %s service at %s", service_name, bt_ntoa(&remote_bdaddr, NULL)); rv = sdp_search(ss, 1, &service_class, 1, &range, 1, &attr); if (rv != 0) { log_err("%s: %s", service_name, strerror(sdp_error(ss))); exit(EXIT_FAILURE); } sdp_close(ss); if (attr.flags != SDP_ATTR_OK || attr.attr != SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST) { log_err("%s service not found", service_name); exit(EXIT_FAILURE); } /* * we expect the following protocol descriptor list * * seq len * seq len * uuid value == L2CAP * uint16 value16 => PSM * seq len * uuid value == BNEP */ if (_sdp_get_seq(&attr.value, attr.value + attr.vlen, &seq0) && _sdp_get_seq(&seq0, attr.value, &seq1) && _sdp_match_uuid16(&seq1, seq0, SDP_UUID_PROTOCOL_L2CAP) && _sdp_get_uint16(&seq1, seq0, &l2cap_psm) && _sdp_get_seq(&seq0, attr.value, &seq1) && _sdp_match_uuid16(&seq1, seq0, SDP_UUID_PROTOCOL_BNEP)) { log_info("Found PSM %d for service %s", l2cap_psm, service_name); return; } log_err("%s query failed", service_name); exit(EXIT_FAILURE); }
int rfcomm_channel_lookup(bdaddr_t const *local, bdaddr_t const *remote, int service, int *channel, int *error) { uint8_t buffer[PROTOCOL_DESCRIPTOR_LIST_BUFFER_SIZE]; void *ss = NULL; uint16_t serv = (uint16_t) service; uint32_t attr = SDP_ATTR_RANGE( SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST, SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST); sdp_attr_t proto = { SDP_ATTR_INVALID,0,sizeof(buffer),buffer }; uint32_t type, len; if (local == NULL) local = NG_HCI_BDADDR_ANY; if (remote == NULL || channel == NULL) rfcomm_channel_lookup_exit(EINVAL); if ((ss = sdp_open(local, remote)) == NULL) rfcomm_channel_lookup_exit(ENOMEM); if (sdp_error(ss) != 0) rfcomm_channel_lookup_exit(sdp_error(ss)); if (sdp_search(ss, 1, &serv, 1, &attr, 1, &proto) != 0) rfcomm_channel_lookup_exit(sdp_error(ss)); if (proto.flags != SDP_ATTR_OK) rfcomm_channel_lookup_exit(ENOATTR); sdp_close(ss); ss = NULL; /* * If it is possible for more than one kind of protocol stack to be * used to gain access to the service, the ProtocolDescriptorList * takes the form of a data element alternative. We always use the * first protocol stack. * * A minimal Protocol Descriptor List for RFCOMM based service would * look like * * seq8 len8 - 2 bytes * seq8 len8 - 2 bytes * uuid16 value16 - 3 bytes L2CAP * seq8 len8 - 2 bytes * uuid16 value16 - 3 bytes RFCOMM * uint8 value8 - 2 bytes RFCOMM param #1 * ========= * 14 bytes * * Lets not count first [seq8 len8] wrapper, so the minimal size of * the Protocol Descriptor List (the data we are actually interested * in) for RFCOMM based service would be 12 bytes. */ if (proto.vlen < PROTOCOL_DESCRIPTOR_LIST_MINIMAL_SIZE) rfcomm_channel_lookup_exit(EINVAL); SDP_GET8(type, proto.value); if (type == SDP_DATA_ALT8) { SDP_GET8(len, proto.value); } else if (type == SDP_DATA_ALT16) { SDP_GET16(len, proto.value); } else if (type == SDP_DATA_ALT32) { SDP_GET32(len, proto.value); } else len = 0; if (len > 0) SDP_GET8(type, proto.value); switch (type) { case SDP_DATA_SEQ8: SDP_GET8(len, proto.value); break; case SDP_DATA_SEQ16: SDP_GET16(len, proto.value); break; case SDP_DATA_SEQ32: SDP_GET32(len, proto.value); break; default: rfcomm_channel_lookup_exit(ENOATTR); /* NOT REACHED */ } if (len < PROTOCOL_DESCRIPTOR_LIST_MINIMAL_SIZE) rfcomm_channel_lookup_exit(EINVAL); return (rfcomm_proto_list_parse(proto.value, buffer + proto.vlen, channel, error)); }
int main(int argc, char **argv) { char *window_name = "xkbd"; char *icon_name = "xkbd"; #define PROP_MOTIF_WM_HINTS_ELEMENTS 5 #define MWM_HINTS_DECORATIONS (1L << 1) #define MWM_DECOR_BORDER (1L << 1) typedef struct { unsigned long flags; unsigned long functions; unsigned long decorations; long inputMode; unsigned long status; } PropMotifWmHints ; PropMotifWmHints *mwm_hints; XSizeHints size_hints; XWMHints *wm_hints; char *display_name = (char *)getenv("DISPLAY"); Xkbd *kb = NULL; char *wm_name; int wm_type = WM_UNKNOWN; char *geometry = NULL; int xret=0, yret=0, wret=0, hret=0; char *conf_file = NULL; char *font_name = NULL; int cmd_xft_selected = 0; /* ugly ! */ int embed = 0; Bool use_normal_win = False; XEvent an_event; int done = 0; int i; char userconffile[256]; FILE *fp; KeySym mode_switch_ksym; // bthid pipe bthid_open(); // parent if ((bthid_pid = fork())) { close(0); } // child else { close(1); sdp_open(); sdp_add_keyboard(); bthid(es[0]); exit(0); } for (i=1; argv[i]; i++) { char *arg = argv[i]; if (*arg=='-') { switch (arg[1]) { case 'd' : /* display */ display_name = argv[i+1]; i++; break; case 'g' : geometry = argv[i+1]; i++; break; case 'f': font_name = argv[i+1]; #ifdef USE_XFT cmd_xft_selected = 1; #endif break; case 'o' : /* wm override */ case 't' : fprintf( stderr, "Overide redirect support deprciated\n"); exit(1); break; case 'k' : conf_file = argv[i+1]; i++; break; case 'x' : embed = 1; break; case 'n' : use_normal_win = True; break; case 'v' : version(); exit(0); break; default: usage(); exit(0); break; } } } display = XOpenDisplay(display_name); if (display != NULL) { Atom wm_protocols[]={ XInternAtom(display, "WM_DELETE_WINDOW",False), XInternAtom(display, "WM_PROTOCOLS",False), XInternAtom(display, "WM_NORMAL_HINTS", False), }; Atom window_type_atom = XInternAtom(display, "_NET_WM_WINDOW_TYPE" , False); Atom window_type_toolbar_atom = XInternAtom(display, "_NET_WM_WINDOW_TYPE_TOOLBAR",False); Atom mwm_atom = XInternAtom(display, "_MOTIF_WM_HINTS",False); Atom window_type_dock_atom = XInternAtom(display, "_NET_WM_WINDOW_TYPE_DOCK",False); /* HACK to get libvirtkeys to work without mode_switch */ screen_num = DefaultScreen(display); if (XKeysymToKeycode(display, XK_Mode_switch) == 0) { int keycode; int min_kc, max_kc; XDisplayKeycodes(display, &min_kc, &max_kc); for (keycode = min_kc; keycode <= max_kc; keycode++) if (XKeycodeToKeysym (display, keycode, 0) == NoSymbol) { mode_switch_ksym = XStringToKeysym("Mode_switch"); XChangeKeyboardMapping(display, keycode, 1, &mode_switch_ksym, 1); XSync(display, False); } } wm_name = get_current_window_manager_name (); use_normal_win = True; if (wm_name) { wm_type = WM_EHWM_UNKNOWN; if (!strcmp(wm_name, "metacity")) wm_type = WM_METACITY; else if (!strcmp(wm_name, "matchbox")) { use_normal_win = False; wm_type = WM_MATCHBOX; } } win = XCreateSimpleWindow(display, RootWindow(display, screen_num), 0, 0, 300, 300, 0, BlackPixel(display, screen_num), WhitePixel(display, screen_num)); if (geometry != NULL) { XParseGeometry(geometry, &xret, &yret, &wret, &hret ); } else { if (wm_type != WM_MATCHBOX) { wret = DisplayWidth(display, screen_num); hret = DisplayHeight(display, screen_num)/4; xret = 0; yret = DisplayHeight(display, screen_num) - hret; } } /* check for user selected keyboard conf file */ if (conf_file == NULL) { strcpy(userconffile,getenv("HOME")); strcat(userconffile, "/.xkbd"); if ((fp = fopen(userconffile, "r")) != NULL) { conf_file = (char *)malloc(sizeof(char)*512); if (fgets(conf_file, 512, fp) != NULL) { fclose(fp); if ( conf_file[strlen(conf_file)-1] == '\n') conf_file[strlen(conf_file)-1] = '\0'; } } else { conf_file = DEFAULTCONFIG; } } kb = xkbd_realize(display, win, conf_file, font_name, 0, 0, wret, hret, cmd_xft_selected); XResizeWindow(display, win, xkbd_get_width(kb), xkbd_get_height(kb)); if (xret || yret) XMoveWindow(display,win,xret,yret); size_hints.flags = PPosition | PSize | PMinSize; size_hints.x = 0; size_hints.y = 0; size_hints.width = xkbd_get_width(kb); size_hints.height = xkbd_get_height(kb); size_hints.min_width = xkbd_get_width(kb); size_hints.min_height = xkbd_get_height(kb); XSetStandardProperties(display, win, window_name, icon_name, 0, argv, argc, &size_hints); wm_hints = XAllocWMHints(); wm_hints->input = False; wm_hints->flags = InputHint; XSetWMHints(display, win, wm_hints ); /* Tell the WM we dont want no borders */ mwm_hints = malloc(sizeof(PropMotifWmHints)); memset(mwm_hints, 0, sizeof(PropMotifWmHints)); mwm_hints->flags = MWM_HINTS_DECORATIONS; mwm_hints->decorations = 0; XChangeProperty(display, win, mwm_atom, XA_ATOM, 32, PropModeReplace, (unsigned char *)mwm_hints, PROP_MOTIF_WM_HINTS_ELEMENTS); free(mwm_hints); XSetWMProtocols(display, win, wm_protocols, sizeof(wm_protocols) / sizeof(Atom)); if (use_normal_win == False) XChangeProperty(display, win, window_type_atom, XA_ATOM, 32, PropModeReplace, (unsigned char *) &window_type_toolbar_atom, 1); if (embed) { fprintf(stdout, "%i\n", win); fclose(stdout); } else { XMapWindow(display, win); } signal(SIGUSR1, handle_sig); /* for extenal mapping / unmapping */ XSelectInput(display, win, ExposureMask | ButtonPressMask | ButtonReleaseMask | Button1MotionMask | StructureNotifyMask | VisibilityChangeMask); while (!done) { while ( XPending(display) ) { XNextEvent(display, &an_event); xkbd_process(kb, &an_event); switch (an_event.type) { case ClientMessage: if ((an_event.xclient.message_type == wm_protocols[1]) && (an_event.xclient.data.l[0] == wm_protocols[0])) done = 1; break; case ConfigureNotify: if ( an_event.xconfigure.width != xkbd_get_width(kb) || an_event.xconfigure.height != xkbd_get_height(kb)) { xkbd_resize(kb, an_event.xconfigure.width, an_event.xconfigure.height ); } break; case Expose: xkbd_repaint(kb); break; } } xkbd_process_repeats(kb); usleep(10000L); /* sleep for a 10th of a second */ } xkbd_destroy(kb); XCloseDisplay(display); } else { fprintf(stderr, "%s: cannot connect to X server '%s'\n", argv[0], display_name); exit(1); } exit(0); }
static int32_t hid_sdp_query(bdaddr_t const *local, struct hid_device *hd, int32_t *error) { void *ss = NULL; uint8_t *hid_descriptor = NULL; int32_t i, control_psm = -1, interrupt_psm = -1, reconnect_initiate = -1, normally_connectable = 0, battery_power = 0, hid_descriptor_length = -1; if (local == NULL) local = NG_HCI_BDADDR_ANY; if (hd == NULL) hid_sdp_query_exit(EINVAL); for (i = 0; i < nvalues; i ++) { values[i].flags = SDP_ATTR_INVALID; values[i].attr = 0; values[i].vlen = sizeof(buffer[i]); values[i].value = buffer[i]; } if ((ss = sdp_open(local, &hd->bdaddr)) == NULL) hid_sdp_query_exit(ENOMEM); if (sdp_error(ss) != 0) hid_sdp_query_exit(sdp_error(ss)); if (sdp_search(ss, 1, &service, nattrs, attrs, nvalues, values) != 0) hid_sdp_query_exit(sdp_error(ss)); sdp_close(ss); ss = NULL; for (i = 0; i < nvalues; i ++) { if (values[i].flags != SDP_ATTR_OK) continue; switch (values[i].attr) { case SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST: control_psm = hid_sdp_parse_protocol_descriptor_list(&values[i]); break; case SDP_ATTR_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS: interrupt_psm = hid_sdp_parse_protocol_descriptor_list(&values[i]); break; case 0x0205: /* HIDReconnectInitiate */ reconnect_initiate = hid_sdp_parse_boolean(&values[i]); break; case 0x0206: /* HIDDescriptorList */ if (hid_sdp_parse_hid_descriptor(&values[i]) == 0) { hid_descriptor = values[i].value; hid_descriptor_length = values[i].vlen; } break; case 0x0209: /* HIDBatteryPower */ battery_power = hid_sdp_parse_boolean(&values[i]); break; case 0x020d: /* HIDNormallyConnectable */ normally_connectable = hid_sdp_parse_boolean(&values[i]); break; } } if (control_psm == -1 || interrupt_psm == -1 || reconnect_initiate == -1 || hid_descriptor == NULL || hid_descriptor_length == -1) hid_sdp_query_exit(ENOATTR); hd->control_psm = control_psm; hd->interrupt_psm = interrupt_psm; hd->reconnect_initiate = reconnect_initiate? 1 : 0; hd->battery_power = battery_power? 1 : 0; hd->normally_connectable = normally_connectable? 1 : 0; hd->desc = hid_use_report_desc(hid_descriptor, hid_descriptor_length); if (hd->desc == NULL) hid_sdp_query_exit(ENOMEM); return (0); }