update to use the new Service Discovery API
This commit is contained in:
parent
d2379b2f18
commit
ab1f45acf7
|
@ -1,13 +1,11 @@
|
|||
# $NetBSD: Makefile,v 1.4 2009/05/12 13:11:18 plunky Exp $
|
||||
# $NetBSD: Makefile,v 1.5 2009/05/12 21:50:38 plunky Exp $
|
||||
#
|
||||
|
||||
PROG= btpand
|
||||
MAN= btpand.8
|
||||
SRCS= btpand.c bnep.c channel.c client.c packet.c server.c sdp.c tap.c
|
||||
SRCS= btpand.c bnep.c channel.c client.c packet.c server.c tap.c
|
||||
|
||||
DPADD+= ${LIBBLUETOOTH} ${LIBEVENT} ${LIBUTIL}
|
||||
LDADD+= -lbluetooth -levent -lutil
|
||||
|
||||
CPPFLAGS+= -DSDP_COMPAT
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/* $NetBSD: btpand.c,v 1.3 2009/05/12 21:08:30 plunky Exp $ */
|
||||
/* $NetBSD: btpand.c,v 1.4 2009/05/12 21:50:38 plunky Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2008 Iain Hibbert
|
||||
* Copyright (c) 2008-2009 Iain Hibbert
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
@ -26,8 +26,8 @@
|
|||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__COPYRIGHT("@(#) Copyright (c) 2008 Iain Hibbert. All rights reserved.");
|
||||
__RCSID("$NetBSD: btpand.c,v 1.3 2009/05/12 21:08:30 plunky Exp $");
|
||||
__COPYRIGHT("@(#) Copyright (c) 2008-2009 Iain Hibbert. All rights reserved.");
|
||||
__RCSID("$NetBSD: btpand.c,v 1.4 2009/05/12 21:50:38 plunky Exp $");
|
||||
|
||||
#include <sys/wait.h>
|
||||
|
||||
|
@ -47,24 +47,35 @@ __RCSID("$NetBSD: btpand.c,v 1.3 2009/05/12 21:08:30 plunky Exp $");
|
|||
/* global variables */
|
||||
const char * control_path; /* -c <path> */
|
||||
const char * interface_name; /* -i <ifname> */
|
||||
const char * service_name; /* -s <service> */
|
||||
const char * service_type; /* -s <service> */
|
||||
uint16_t service_class;
|
||||
const char * service_name;
|
||||
const char * service_desc;
|
||||
|
||||
bdaddr_t local_bdaddr; /* -d <addr> */
|
||||
bdaddr_t remote_bdaddr; /* -a <addr> */
|
||||
uint16_t l2cap_psm; /* -p <psm> */
|
||||
int l2cap_mode; /* -m <mode> */
|
||||
|
||||
int server_limit; /* -n <limit> */
|
||||
|
||||
static const struct {
|
||||
const char * name;
|
||||
const char * type;
|
||||
uint16_t class;
|
||||
const char * name;
|
||||
const char * desc;
|
||||
} services[] = {
|
||||
{ "PANU", SDP_SERVICE_CLASS_PANU, "Personal Area Networking User" },
|
||||
{ "NAP", SDP_SERVICE_CLASS_NAP, "Network Acess Point" },
|
||||
{ "GN", SDP_SERVICE_CLASS_GN, "Group Network" },
|
||||
{ "PANU", SDP_SERVICE_CLASS_PANU,
|
||||
"Personal Ad-hoc User Service",
|
||||
"Personal Ad-hoc User Service"
|
||||
},
|
||||
{ "NAP", SDP_SERVICE_CLASS_NAP,
|
||||
"Network Acess Point",
|
||||
"Personal Ad-hoc Network Service"
|
||||
},
|
||||
{ "GN", SDP_SERVICE_CLASS_GN,
|
||||
"Group Ad-hoc Network",
|
||||
"Personal Group Ad-hoc Network Service"
|
||||
},
|
||||
};
|
||||
|
||||
static void main_exit(int);
|
||||
|
@ -139,18 +150,21 @@ main(int argc, char *argv[])
|
|||
|| ul > 0xffff || L2CAP_PSM_INVALID(ul))
|
||||
errx(EXIT_FAILURE, "%s: invalid PSM", optarg);
|
||||
|
||||
l2cap_psm = ul;
|
||||
l2cap_psm = (uint16_t)ul;
|
||||
break;
|
||||
|
||||
case 's': /* service */
|
||||
case 'S': /* service (no SDP) */
|
||||
for (ul = 0; strcasecmp(optarg, services[ul].name); ul++) {
|
||||
for (ul = 0; strcasecmp(optarg, services[ul].type); ul++) {
|
||||
if (ul == __arraycount(services))
|
||||
errx(EXIT_FAILURE, "%s: unknown service", optarg);
|
||||
}
|
||||
|
||||
if (ch == 's')
|
||||
if (ch == 's') {
|
||||
service_type = services[ul].type;
|
||||
service_name = services[ul].name;
|
||||
service_desc = services[ul].desc;
|
||||
}
|
||||
|
||||
service_class = services[ul].class;
|
||||
break;
|
||||
|
@ -169,7 +183,7 @@ main(int argc, char *argv[])
|
|||
usage();
|
||||
|
||||
if (!bdaddr_any(&remote_bdaddr) && (server_limit != 0 ||
|
||||
control_path != 0 || (service_name != NULL && l2cap_psm != 0)))
|
||||
control_path != 0 || (service_type != NULL && l2cap_psm != 0)))
|
||||
usage();
|
||||
|
||||
/* default options */
|
||||
|
@ -261,7 +275,7 @@ static void
|
|||
usage(void)
|
||||
{
|
||||
const char *p = getprogname();
|
||||
int n = strlen(p);
|
||||
size_t n = strlen(p);
|
||||
|
||||
fprintf(stderr,
|
||||
"usage: %s [-i ifname] [-m mode] -a address -d device\n"
|
||||
|
@ -283,8 +297,8 @@ usage(void)
|
|||
"Known services:\n"
|
||||
"", p, n, "", p, n, "");
|
||||
|
||||
for (n = 0; n < (int)__arraycount(services); n++)
|
||||
fprintf(stderr, "\t%s\t%s\n", services[n].name, services[n].desc);
|
||||
for (n = 0; n < __arraycount(services); n++)
|
||||
fprintf(stderr, "\t%s\t%s\n", services[n].type, services[n].name);
|
||||
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/* $NetBSD: btpand.h,v 1.2 2009/05/12 21:08:30 plunky Exp $ */
|
||||
/* $NetBSD: btpand.h,v 1.3 2009/05/12 21:50:38 plunky Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2008 Iain Hibbert
|
||||
* Copyright (c) 2008-2009 Iain Hibbert
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
@ -135,7 +135,9 @@ struct pkthdr {
|
|||
|
||||
/* global variables */
|
||||
extern const char * control_path;
|
||||
extern const char * service_type;
|
||||
extern const char * service_name;
|
||||
extern const char * service_desc;
|
||||
extern const char * interface_name;
|
||||
extern bdaddr_t local_bdaddr;
|
||||
extern bdaddr_t remote_bdaddr;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/* $NetBSD: client.c,v 1.3 2009/05/12 21:08:30 plunky Exp $ */
|
||||
/* $NetBSD: client.c,v 1.4 2009/05/12 21:50:38 plunky Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2008 Iain Hibbert
|
||||
* Copyright (c) 2008-2009 Iain Hibbert
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
@ -26,7 +26,7 @@
|
|||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__RCSID("$NetBSD: client.c,v 1.3 2009/05/12 21:08:30 plunky Exp $");
|
||||
__RCSID("$NetBSD: client.c,v 1.4 2009/05/12 21:50:38 plunky Exp $");
|
||||
|
||||
#include <bluetooth.h>
|
||||
#include <errno.h>
|
||||
|
@ -35,7 +35,6 @@ __RCSID("$NetBSD: client.c,v 1.3 2009/05/12 21:08:30 plunky Exp $");
|
|||
|
||||
#include "btpand.h"
|
||||
#include "bnep.h"
|
||||
#include "sdp.h"
|
||||
|
||||
static void client_down(channel_t *);
|
||||
static void client_query(void);
|
||||
|
@ -52,7 +51,7 @@ client_init(void)
|
|||
if (bdaddr_any(&remote_bdaddr))
|
||||
return;
|
||||
|
||||
if (service_name)
|
||||
if (service_type)
|
||||
client_query();
|
||||
|
||||
fd = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
|
||||
|
@ -144,64 +143,83 @@ client_down(channel_t *chan)
|
|||
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);
|
||||
uint8_t buf[12]; /* enough for SSP and AIL both */
|
||||
sdp_session_t ss;
|
||||
sdp_data_t ssp, ail, rsp, rec, value, pdl, seq;
|
||||
uintmax_t psm;
|
||||
uint16_t attr;
|
||||
bool rv;
|
||||
|
||||
ss = sdp_open(&local_bdaddr, &remote_bdaddr);
|
||||
if (ss == NULL || (errno = sdp_error(ss)) != 0) {
|
||||
log_err("%s: %m", service_name);
|
||||
if (ss == NULL) {
|
||||
log_err("%s: %m", service_type);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
log_info("Searching for %s service at %s",
|
||||
service_name, bt_ntoa(&remote_bdaddr, NULL));
|
||||
service_type, 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);
|
||||
}
|
||||
seq.next = buf;
|
||||
seq.end = buf + sizeof(buf);
|
||||
|
||||
sdp_close(ss);
|
||||
/*
|
||||
* build ServiceSearchPattern (9 bytes)
|
||||
*
|
||||
* uuid16 "service_class"
|
||||
* uuid16 L2CAP
|
||||
* uuid16 BNEP
|
||||
*/
|
||||
ssp.next = seq.next;
|
||||
sdp_put_uuid16(&seq, service_class);
|
||||
sdp_put_uuid16(&seq, SDP_UUID_PROTOCOL_L2CAP);
|
||||
sdp_put_uuid16(&seq, SDP_UUID_PROTOCOL_BNEP);
|
||||
ssp.end = seq.next;
|
||||
|
||||
if (attr.flags != SDP_ATTR_OK
|
||||
|| attr.attr != SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST) {
|
||||
log_err("%s service not found", service_name);
|
||||
/*
|
||||
* build AttributeIDList (3 bytes)
|
||||
*
|
||||
* uint16 ProtocolDescriptorList
|
||||
*/
|
||||
ail.next = seq.next;
|
||||
sdp_put_uint16(&seq, SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST);
|
||||
ail.end = seq.next;
|
||||
|
||||
rv = sdp_service_search_attribute(ss, &ssp, &ail, &rsp);
|
||||
if (!rv) {
|
||||
log_err("%s: %m", service_type);
|
||||
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
|
||||
* we expect the response to contain a list of records
|
||||
* containing a ProtocolDescriptorList. Find the first
|
||||
* one containing L2CAP and BNEP protocols and extract
|
||||
* the PSM.
|
||||
*/
|
||||
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;
|
||||
rv = false;
|
||||
while (!rv && sdp_get_seq(&rsp, &rec)) {
|
||||
if (!sdp_get_attr(&rec, &attr, &value)
|
||||
|| attr != SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST)
|
||||
continue;
|
||||
|
||||
sdp_get_alt(&value, &value); /* drop any alt header */
|
||||
while (!rv && sdp_get_seq(&value, &pdl)) {
|
||||
if (sdp_get_seq(&pdl, &seq)
|
||||
&& sdp_match_uuid16(&seq, SDP_UUID_PROTOCOL_L2CAP)
|
||||
&& sdp_get_uint(&seq, &psm)
|
||||
&& sdp_get_seq(&pdl, &seq)
|
||||
&& sdp_match_uuid16(&seq, SDP_UUID_PROTOCOL_BNEP))
|
||||
rv = true;
|
||||
}
|
||||
}
|
||||
|
||||
log_err("%s query failed", service_name);
|
||||
exit(EXIT_FAILURE);
|
||||
sdp_close(ss);
|
||||
|
||||
if (!rv) {
|
||||
log_err("%s query failed", service_type);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
l2cap_psm = (uint16_t)psm;
|
||||
log_info("Found PSM %u for service %s", l2cap_psm, service_type);
|
||||
}
|
||||
|
|
|
@ -1,207 +0,0 @@
|
|||
/* $NetBSD: sdp.c,v 1.2 2008/12/06 20:01:14 plunky Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2008 Iain Hibbert
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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 AUTHOR ``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 AUTHOR 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: sdp.c,v 1.2 2008/12/06 20:01:14 plunky Exp $");
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "sdp.h"
|
||||
|
||||
/*
|
||||
* SDP data stream manipulation routines
|
||||
*/
|
||||
|
||||
/* Bluetooth Base UUID */
|
||||
static const uuid_t BASE_UUID = {
|
||||
0x00000000,
|
||||
0x0000,
|
||||
0x1000,
|
||||
0x80,
|
||||
0x00,
|
||||
{ 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb }
|
||||
};
|
||||
|
||||
/*
|
||||
* _sdp_match_uuid16(ptr, limit, uuid)
|
||||
*
|
||||
* examine SDP data stream at ptr for a UUID, and return
|
||||
* true if it matches the supplied short alias bluetooth UUID.
|
||||
* limit is the first address past the end of valid data.
|
||||
*/
|
||||
bool
|
||||
_sdp_match_uuid16(uint8_t **ptr, uint8_t *limit, uint16_t uuid)
|
||||
{
|
||||
uint8_t *p = *ptr;
|
||||
uuid_t u1, u2;
|
||||
|
||||
memcpy(&u1, &BASE_UUID, sizeof(uuid_t));
|
||||
u1.time_low = uuid;
|
||||
|
||||
if (!_sdp_get_uuid(&p, limit, &u2)
|
||||
|| !uuid_equal(&u1, &u2, NULL))
|
||||
return false;
|
||||
|
||||
*ptr = p;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* _sdp_get_uuid(ptr, limit, uuid)
|
||||
*
|
||||
* examine SDP data stream at ptr for a UUID, and extract
|
||||
* to given storage, advancing ptr.
|
||||
* limit is the first address past the end of valid data.
|
||||
*/
|
||||
bool
|
||||
_sdp_get_uuid(uint8_t **ptr, uint8_t *limit, uuid_t *uuid)
|
||||
{
|
||||
uint8_t *p = *ptr;
|
||||
|
||||
if (p + 1 > limit)
|
||||
return false;
|
||||
|
||||
switch (*p++) {
|
||||
case SDP_DATA_UUID16:
|
||||
if (p + 2 > limit)
|
||||
return false;
|
||||
|
||||
memcpy(uuid, &BASE_UUID, sizeof(uuid_t));
|
||||
uuid->time_low = be16dec(p);
|
||||
p += 2;
|
||||
break;
|
||||
|
||||
case SDP_DATA_UUID32:
|
||||
if (p + 4 > limit)
|
||||
return false;
|
||||
|
||||
memcpy(uuid, &BASE_UUID, sizeof(uuid_t));
|
||||
uuid->time_low = be32dec(p);
|
||||
p += 4;
|
||||
break;
|
||||
|
||||
case SDP_DATA_UUID128:
|
||||
if (p + 16 > limit)
|
||||
return false;
|
||||
|
||||
uuid_dec_be(p, uuid);
|
||||
p += 16;
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
*ptr = p;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* _sdp_get_seq(ptr, limit, seq)
|
||||
*
|
||||
* examine SDP data stream at ptr for a sequence. return
|
||||
* seq pointer if found and advance ptr to next object.
|
||||
* limit is the first address past the end of valid data.
|
||||
*/
|
||||
bool
|
||||
_sdp_get_seq(uint8_t **ptr, uint8_t *limit, uint8_t **seq)
|
||||
{
|
||||
uint8_t *p = *ptr;
|
||||
int32_t l;
|
||||
|
||||
if (p + 1 > limit)
|
||||
return false;
|
||||
|
||||
switch (*p++) {
|
||||
case SDP_DATA_SEQ8:
|
||||
if (p + 1 > limit)
|
||||
return false;
|
||||
|
||||
l = *p;
|
||||
p += 1;
|
||||
break;
|
||||
|
||||
case SDP_DATA_SEQ16:
|
||||
if (p + 2 > limit)
|
||||
return false;
|
||||
|
||||
l = be16dec(p);
|
||||
p += 2;
|
||||
break;
|
||||
|
||||
case SDP_DATA_SEQ32:
|
||||
if (p + 4 > limit)
|
||||
return false;
|
||||
|
||||
l = be32dec(p);
|
||||
p += 4;
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
if (p + l > limit)
|
||||
return false;
|
||||
|
||||
*seq = p;
|
||||
*ptr = p + l;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* _sdp_get_uint16(ptr, limit, value)
|
||||
*
|
||||
* examine SDP data stream at ptr for a uint16_t, and
|
||||
* extract to given storage, advancing ptr.
|
||||
* limit is the first address past the end of valid data.
|
||||
*/
|
||||
bool
|
||||
_sdp_get_uint16(uint8_t **ptr, uint8_t *limit, uint16_t *value)
|
||||
{
|
||||
uint8_t *p = *ptr;
|
||||
uint16_t v;
|
||||
|
||||
if (p + 1 > limit)
|
||||
return false;
|
||||
|
||||
switch (*p++) {
|
||||
case SDP_DATA_UINT16:
|
||||
if (p + 2 > limit)
|
||||
return false;
|
||||
|
||||
v = be16dec(p);
|
||||
p += 2;
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
*value = v;
|
||||
*ptr = p;
|
||||
return true;
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
/* $NetBSD: sdp.h,v 1.2 2008/12/06 20:01:15 plunky Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2008 Iain Hibbert
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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 AUTHOR ``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 AUTHOR 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 <bluetooth.h>
|
||||
#include <sdp.h>
|
||||
#include <stdbool.h>
|
||||
#include <uuid.h>
|
||||
|
||||
bool _sdp_match_uuid16(uint8_t **, uint8_t *, uint16_t);
|
||||
bool _sdp_get_uuid(uint8_t **, uint8_t *, uuid_t *);
|
||||
bool _sdp_get_seq(uint8_t **, uint8_t *, uint8_t **);
|
||||
bool _sdp_get_uint16(uint8_t **, uint8_t *, uint16_t *);
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: server.c,v 1.3 2009/05/12 21:08:30 plunky Exp $ */
|
||||
/* $NetBSD: server.c,v 1.4 2009/05/12 21:50:38 plunky Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2008-2009 Iain Hibbert
|
||||
|
@ -26,10 +26,12 @@
|
|||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__RCSID("$NetBSD: server.c,v 1.3 2009/05/12 21:08:30 plunky Exp $");
|
||||
__RCSID("$NetBSD: server.c,v 1.4 2009/05/12 21:50:38 plunky Exp $");
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include <net/ethertypes.h>
|
||||
|
||||
#include <bluetooth.h>
|
||||
#include <errno.h>
|
||||
#include <sdp.h>
|
||||
|
@ -41,13 +43,20 @@ __RCSID("$NetBSD: server.c,v 1.3 2009/05/12 21:08:30 plunky Exp $");
|
|||
static struct event server_ev;
|
||||
static int server_count;
|
||||
|
||||
static void * server_ss;
|
||||
static sdp_session_t server_ss;
|
||||
static uint32_t server_handle;
|
||||
static sdp_data_t server_record;
|
||||
|
||||
static char * server_ipv4_subnet;
|
||||
static char * server_ipv6_subnet;
|
||||
static uint16_t server_proto[] = { ETHERTYPE_IP, ETHERTYPE_ARP, ETHERTYPE_IPV6 };
|
||||
static size_t server_nproto = __arraycount(server_proto);
|
||||
|
||||
static void server_open(void);
|
||||
static void server_read(int, short, void *);
|
||||
static void server_down(channel_t *);
|
||||
static void server_update(void);
|
||||
static void server_mkrecord(void);
|
||||
|
||||
void
|
||||
server_init(void)
|
||||
|
@ -247,35 +256,114 @@ server_down(channel_t *chan)
|
|||
static void
|
||||
server_update(void)
|
||||
{
|
||||
sdp_nap_profile_t p;
|
||||
int rv;
|
||||
bool rv;
|
||||
|
||||
if (service_name == NULL)
|
||||
if (service_type == NULL)
|
||||
return;
|
||||
|
||||
if (server_ss == NULL) {
|
||||
server_ss = sdp_open_local(control_path);
|
||||
if (server_ss == NULL || sdp_error(server_ss) != 0) {
|
||||
if (server_ss == NULL) {
|
||||
log_err("failed to contact SDP server");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
memset(&p, 0, sizeof(p));
|
||||
p.psm = l2cap_psm;
|
||||
p.load_factor = (UINT8_MAX - server_count * UINT8_MAX / server_limit);
|
||||
p.security_description = (l2cap_mode == 0 ? 0x0000 : 0x0001);
|
||||
server_mkrecord();
|
||||
|
||||
if (server_handle)
|
||||
rv = sdp_change_service(server_ss, server_handle,
|
||||
(uint8_t *)&p, sizeof(p));
|
||||
if (server_handle == 0)
|
||||
rv = sdp_record_insert(server_ss, &local_bdaddr,
|
||||
&server_handle, &server_record);
|
||||
else
|
||||
rv = sdp_register_service(server_ss, service_class,
|
||||
&local_bdaddr, (uint8_t *)&p, sizeof(p), &server_handle);
|
||||
rv = sdp_record_update(server_ss, server_handle,
|
||||
&server_record);
|
||||
|
||||
if (rv != 0) {
|
||||
errno = sdp_error(server_ss);
|
||||
log_err("%s: %m", service_name);
|
||||
if (!rv) {
|
||||
log_err("%s: %m", service_type);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
server_mkrecord(void)
|
||||
{
|
||||
static uint8_t data[256]; /* tis enough */
|
||||
sdp_data_t buf;
|
||||
size_t i;
|
||||
|
||||
buf.next = data;
|
||||
buf.end = data + sizeof(data);
|
||||
|
||||
sdp_put_uint16(&buf, SDP_ATTR_SERVICE_RECORD_HANDLE);
|
||||
sdp_put_uint32(&buf, 0x00000000);
|
||||
|
||||
sdp_put_uint16(&buf, SDP_ATTR_SERVICE_CLASS_ID_LIST);
|
||||
sdp_put_seq(&buf, 3);
|
||||
sdp_put_uuid16(&buf, service_class);
|
||||
|
||||
sdp_put_uint16(&buf, SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST);
|
||||
sdp_put_seq(&buf, 8 + 10 + 3 * server_nproto);
|
||||
sdp_put_seq(&buf, 6);
|
||||
sdp_put_uuid16(&buf, SDP_UUID_PROTOCOL_L2CAP);
|
||||
sdp_put_uint16(&buf, l2cap_psm);
|
||||
sdp_put_seq(&buf, 8 + 3 * server_nproto);
|
||||
sdp_put_uuid16(&buf, SDP_UUID_PROTOCOL_BNEP);
|
||||
sdp_put_uint16(&buf, 0x0100); /* v1.0 */
|
||||
sdp_put_seq(&buf, 3 * server_nproto);
|
||||
for (i = 0; i < server_nproto; i++)
|
||||
sdp_put_uint16(&buf, server_proto[i]);
|
||||
|
||||
sdp_put_uint16(&buf, SDP_ATTR_BROWSE_GROUP_LIST);
|
||||
sdp_put_seq(&buf, 3);
|
||||
sdp_put_uuid16(&buf, SDP_SERVICE_CLASS_PUBLIC_BROWSE_GROUP);
|
||||
|
||||
sdp_put_uint16(&buf, SDP_ATTR_LANGUAGE_BASE_ATTRIBUTE_ID_LIST);
|
||||
sdp_put_seq(&buf, 9);
|
||||
sdp_put_uint16(&buf, 0x656e); /* "en" */
|
||||
sdp_put_uint16(&buf, 106); /* UTF-8 */
|
||||
sdp_put_uint16(&buf, SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID);
|
||||
|
||||
sdp_put_uint16(&buf, SDP_ATTR_SERVICE_AVAILABILITY);
|
||||
sdp_put_uint8(&buf, (UINT8_MAX - server_count * UINT8_MAX / server_limit));
|
||||
|
||||
sdp_put_uint16(&buf, SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST);
|
||||
sdp_put_seq(&buf, 8);
|
||||
sdp_put_seq(&buf, 6);
|
||||
sdp_put_uuid16(&buf, service_class);
|
||||
sdp_put_uint16(&buf, 0x0100); /* v1.0 */
|
||||
|
||||
sdp_put_uint16(&buf, SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID
|
||||
+ SDP_ATTR_SERVICE_NAME_OFFSET);
|
||||
sdp_put_str(&buf, service_name, -1);
|
||||
|
||||
sdp_put_uint16(&buf, SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID
|
||||
+ SDP_ATTR_SERVICE_DESCRIPTION_OFFSET);
|
||||
sdp_put_str(&buf, service_desc, -1);
|
||||
|
||||
sdp_put_uint16(&buf, SDP_ATTR_SECURITY_DESCRIPTION);
|
||||
sdp_put_uint16(&buf, (l2cap_mode == 0) ? 0x0000 : 0x0001);
|
||||
|
||||
if (service_class == SDP_SERVICE_CLASS_NAP) {
|
||||
sdp_put_uint16(&buf, SDP_ATTR_NET_ACCESS_TYPE);
|
||||
sdp_put_uint16(&buf, 0x0004); /* 10Mb Ethernet */
|
||||
|
||||
sdp_put_uint16(&buf, SDP_ATTR_MAX_NET_ACCESS_RATE);
|
||||
sdp_put_uint32(&buf, 10000); /* 10Mb/s (?) */
|
||||
}
|
||||
|
||||
if (service_class == SDP_SERVICE_CLASS_NAP
|
||||
|| service_class == SDP_SERVICE_CLASS_GN) {
|
||||
if (server_ipv4_subnet) {
|
||||
sdp_put_uint16(&buf, SDP_ATTR_IPV4_SUBNET);
|
||||
sdp_put_str(&buf, server_ipv4_subnet, -1);
|
||||
}
|
||||
|
||||
if (server_ipv6_subnet) {
|
||||
sdp_put_uint16(&buf, SDP_ATTR_IPV6_SUBNET);
|
||||
sdp_put_str(&buf, server_ipv6_subnet, -1);
|
||||
}
|
||||
}
|
||||
|
||||
server_record.next = data;
|
||||
server_record.end = buf.next;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue