e16149e27c
(This is sometimes used in HID devices to provide manufacturer information)
249 lines
6.3 KiB
C
249 lines
6.3 KiB
C
/* $NetBSD: command.c,v 1.3 2009/12/05 16:54:13 plunky Exp $ */
|
|
|
|
/*-
|
|
* Copyright (c) 2009 The NetBSD Foundation, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* This code is derived from software contributed to The NetBSD Foundation
|
|
* by Iain Hibbert.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
|
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
|
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include <sys/cdefs.h>
|
|
__RCSID("$NetBSD: command.c,v 1.3 2009/12/05 16:54:13 plunky Exp $");
|
|
|
|
#include <bluetooth.h>
|
|
#include <err.h>
|
|
#include <sdp.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "sdpquery.h"
|
|
|
|
static sdp_session_t open_session(void);
|
|
static void build_ssp(sdp_data_t *, int, const char **);
|
|
|
|
static struct alias {
|
|
uint16_t uuid;
|
|
const char * name;
|
|
const char * desc;
|
|
} aliases[] = {
|
|
{ SDP_SERVICE_CLASS_ADVANCED_AUDIO_DISTRIBUTION,
|
|
"A2DP", "Advanced Audio Distribution Profile" },
|
|
{ SDP_UUID_PROTOCOL_BNEP,
|
|
"BNEP", "Bluetooth Network Encapsulation Protocol" },
|
|
{ SDP_SERVICE_CLASS_COMMON_ISDN_ACCESS,
|
|
"CIP", "Common ISDN Access Service" },
|
|
{ SDP_SERVICE_CLASS_CORDLESS_TELEPHONY,
|
|
"CTP", "Cordless Telephony Service" },
|
|
{ SDP_SERVICE_CLASS_DIALUP_NETWORKING,
|
|
"DUN", "Dial Up Networking Service" },
|
|
{ SDP_SERVICE_CLASS_FAX,
|
|
"FAX", "Fax Service" },
|
|
{ SDP_SERVICE_CLASS_OBEX_FILE_TRANSFER,
|
|
"FTRN", "File Transfer Service" },
|
|
{ SDP_SERVICE_CLASS_GN,
|
|
"GN", "Group ad-hoc Network Service" },
|
|
{ SDP_SERVICE_CLASS_HUMAN_INTERFACE_DEVICE,
|
|
"HID", "Human Interface Device Service" },
|
|
{ SDP_SERVICE_CLASS_HANDSFREE,
|
|
"HF", "Handsfree Service" },
|
|
{ SDP_SERVICE_CLASS_HEADSET,
|
|
"HSET", "Headset Service" },
|
|
{ SDP_UUID_PROTOCOL_L2CAP,
|
|
"L2CAP", "Logical Link Control and Adapatation Protocol" },
|
|
{ SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP,
|
|
"LAN", "Lan access using PPP Service" },
|
|
{ SDP_SERVICE_CLASS_NAP,
|
|
"NAP", "Network Access Point Service" },
|
|
{ SDP_UUID_PROTOCOL_OBEX,
|
|
"OBEX", "Object Exchange Protocol" },
|
|
{ SDP_SERVICE_CLASS_OBEX_OBJECT_PUSH,
|
|
"OPUSH", "Object Push Service" },
|
|
{ SDP_SERVICE_CLASS_PANU,
|
|
"PANU", "Personal Area Networking User Service" },
|
|
{ SDP_SERVICE_CLASS_PNP_INFORMATION,
|
|
"PNP", "PNP Information Service" },
|
|
{ SDP_UUID_PROTOCOL_RFCOMM,
|
|
"RFCOMM", "RFCOMM Protocol" },
|
|
{ SDP_UUID_PROTOCOL_SDP,
|
|
"SDP", "Service Discovery Protocol" },
|
|
{ SDP_SERVICE_CLASS_SERIAL_PORT,
|
|
"SP", "Serial Port Service" },
|
|
{ SDP_SERVICE_CLASS_IR_MC_SYNC,
|
|
"SYNC", "IrMC Sync Client Service" },
|
|
};
|
|
|
|
int
|
|
do_sdp_browse(int argc, const char **argv)
|
|
{
|
|
#define STR(x) __STRING(x)
|
|
const char *av = STR(SDP_SERVICE_CLASS_PUBLIC_BROWSE_GROUP);
|
|
#undef STR
|
|
|
|
if (argc > 1)
|
|
errx(EXIT_FAILURE, "Too many arguments");
|
|
|
|
if (argc == 0) {
|
|
argc = 1;
|
|
argv = &av;
|
|
}
|
|
|
|
return do_sdp_search(argc, argv);
|
|
}
|
|
|
|
int
|
|
do_sdp_record(int argc, const char **argv)
|
|
{
|
|
sdp_session_t ss;
|
|
sdp_data_t rsp;
|
|
char * ep;
|
|
unsigned long handle;
|
|
bool rv;
|
|
|
|
if (argc == 0)
|
|
errx(EXIT_FAILURE, "Record handle required");
|
|
|
|
ss = open_session();
|
|
|
|
for (; argc-- > 0; argv++) {
|
|
handle = strtoul(*argv, &ep, 0);
|
|
if (*argv[0] == '\0' || *ep != '\0' || handle > UINT32_MAX)
|
|
errx(EXIT_FAILURE, "Invalid handle: %s\n", *argv);
|
|
|
|
rv = sdp_service_attribute(ss, (uint32_t)handle, NULL, &rsp);
|
|
if (!rv)
|
|
warn("%s", *argv);
|
|
else
|
|
print_record(&rsp);
|
|
|
|
if (argc > 0)
|
|
printf("\n\n");
|
|
}
|
|
|
|
sdp_close(ss);
|
|
return EXIT_SUCCESS;
|
|
}
|
|
|
|
int
|
|
do_sdp_search(int argc, const char **argv)
|
|
{
|
|
sdp_session_t ss;
|
|
sdp_data_t ssp, rec, rsp;
|
|
bool rv;
|
|
|
|
if (argc < 1)
|
|
errx(EXIT_FAILURE, "UUID required");
|
|
|
|
if (argc > 12)
|
|
errx(EXIT_FAILURE, "Too many UUIDs");
|
|
|
|
build_ssp(&ssp, argc, argv);
|
|
|
|
ss = open_session();
|
|
|
|
rv = sdp_service_search_attribute(ss, &ssp, NULL, &rsp);
|
|
if (!rv)
|
|
err(EXIT_FAILURE, "sdp_service_search_attribute");
|
|
|
|
while (sdp_get_seq(&rsp, &rec)) {
|
|
if (!rv)
|
|
printf("\n\n");
|
|
else
|
|
rv = false;
|
|
|
|
print_record(&rec);
|
|
}
|
|
|
|
if (rsp.next != rsp.end) {
|
|
printf("\n\nAdditional Data:\n");
|
|
sdp_data_print(&rsp, 4);
|
|
}
|
|
|
|
sdp_close(ss);
|
|
|
|
return EXIT_SUCCESS;
|
|
}
|
|
|
|
static sdp_session_t
|
|
open_session(void)
|
|
{
|
|
sdp_session_t ss;
|
|
|
|
if (bdaddr_any(&remote_addr))
|
|
ss = sdp_open_local(control_socket);
|
|
else
|
|
ss = sdp_open(&local_addr, &remote_addr);
|
|
|
|
if (ss == NULL)
|
|
err(EXIT_FAILURE, "sdp_open");
|
|
|
|
return ss;
|
|
}
|
|
|
|
/*
|
|
* build ServiceSearchPattern from arglist
|
|
*/
|
|
static void
|
|
build_ssp(sdp_data_t *ssp, int argc, const char **argv)
|
|
{
|
|
static uint8_t data[12 * sizeof(uuid_t)];
|
|
char * ep;
|
|
uintmax_t umax;
|
|
uuid_t uuid;
|
|
uint32_t status;
|
|
int i;
|
|
|
|
ssp->next = data;
|
|
ssp->end = data + sizeof(data);
|
|
|
|
for (; argc-- > 0; argv++) {
|
|
uuid_from_string(*argv, &uuid, &status);
|
|
if (status != uuid_s_ok) {
|
|
umax = strtoumax(*argv, &ep, 0);
|
|
if (*argv[0] == '\0' || *ep != '\0') {
|
|
for (i = 0;; i++) {
|
|
if (i == __arraycount(aliases))
|
|
errx(EXIT_FAILURE,
|
|
"%s: Bad UUID", *argv);
|
|
|
|
if (strcasecmp(aliases[i].name,
|
|
*argv) == 0)
|
|
break;
|
|
}
|
|
|
|
umax = aliases[i].uuid;
|
|
} else if (umax > UINT32_MAX)
|
|
errx(EXIT_FAILURE, "%s: Bad UUID", *argv);
|
|
|
|
uuid = BLUETOOTH_BASE_UUID;
|
|
uuid.time_low = (uint32_t)umax;
|
|
}
|
|
|
|
sdp_put_uuid(ssp, &uuid);
|
|
}
|
|
|
|
ssp->end = ssp->next;
|
|
ssp->next = data;
|
|
}
|