summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--daemon/main.c2
-rw-r--r--hcid/hcid.conf.56
-rw-r--r--hcid/hcid.h3
-rw-r--r--hcid/kword.c1
-rw-r--r--hcid/lexer.l9
-rw-r--r--hcid/main.c2
-rw-r--r--hcid/parser.y14
-rw-r--r--sdpd/main.c2
-rw-r--r--sdpd/sdpd.h4
-rw-r--r--sdpd/server.c18
-rw-r--r--sdpd/service.c63
11 files changed, 112 insertions, 12 deletions
diff --git a/daemon/main.c b/daemon/main.c
index 1653ba75..fe0fa404 100644
--- a/daemon/main.c
+++ b/daemon/main.c
@@ -212,7 +212,7 @@ int main(int argc, char *argv[])
exit(1);
}
- if (start_sdp_server(0, SDP_SERVER_COMPAT) < 0) {
+ if (start_sdp_server(0, NULL, SDP_SERVER_COMPAT) < 0) {
cleanup_dbus();
g_main_loop_unref(main_loop);
exit(1);
diff --git a/hcid/hcid.conf.5 b/hcid/hcid.conf.5
index 1dad854d..cb5bcfa9 100644
--- a/hcid/hcid.conf.5
+++ b/hcid/hcid.conf.5
@@ -53,6 +53,12 @@ SetMode("off"). \fIdevdown\fP sets the adapter into down state (same what
\fIhciconfig hci0 down\fP does).
.TP
+\fBdeviceid\fP <vendor>:<product>:<version>
+
+This option allows to specify the vendor and product information of the
+Bluetooth device ID service record.
+
+.TP
\fBpasskey\fP "\fIpin\fP"
The default PIN for incoming connections if \fBsecurity\fP has been
diff --git a/hcid/hcid.h b/hcid/hcid.h
index 8983a899..86b21639 100644
--- a/hcid/hcid.h
+++ b/hcid/hcid.h
@@ -76,7 +76,7 @@ struct device_opts {
uint16_t link_mode;
uint16_t link_policy;
uint8_t scan;
- int discovto;
+ uint32_t discovto;
};
extern struct device_opts default_device;
@@ -94,6 +94,7 @@ struct hcid_opts {
int security;
int pairing;
int offmode;
+ char deviceid[15];
char *config_file;
diff --git a/hcid/kword.c b/hcid/kword.c
index 2a51a0b3..7d2c694c 100644
--- a/hcid/kword.c
+++ b/hcid/kword.c
@@ -49,6 +49,7 @@ struct kword cfg_keyword[] = {
{ "security", K_SECURITY },
{ "pairing", K_PAIRING },
{ "offmode", K_OFFMODE },
+ { "deviceid", K_DEVICEID },
{ "pkt_type", K_PTYPE },
{ "lm", K_LM },
{ "lp", K_LP },
diff --git a/hcid/lexer.l b/hcid/lexer.l
index a194f708..f4559494 100644
--- a/hcid/lexer.l
+++ b/hcid/lexer.l
@@ -63,7 +63,9 @@ path (\/{fname})+
string \".*\"
hci hci[0-9]+
hextuple [0-9a-zA-Z][0-9a-zA-Z]
+hexquad {hextuple}{hextuple}
bdaddr {hextuple}:{hextuple}:{hextuple}:{hextuple}:{hextuple}:{hextuple}
+id {hexquad}:{hexquad}
%x OPTION PARAM
@@ -117,7 +119,7 @@ bdaddr {hextuple}:{hextuple}:{hextuple}:{hextuple}:{hextuple}:{hextuple}
}
{string} {
- if(yyleng > sizeof(str_buf) - 1){
+ if (yyleng > sizeof(str_buf) - 1) {
yyerror("string too long");
return 0;
}
@@ -139,6 +141,11 @@ bdaddr {hextuple}:{hextuple}:{hextuple}:{hextuple}:{hextuple}:{hextuple}
return PATH;
}
+{id} {
+ yylval.str = yytext;
+ return ID;
+}
+
. {
return *yytext;
}
diff --git a/hcid/main.c b/hcid/main.c
index 641cc801..943d6cf4 100644
--- a/hcid/main.c
+++ b/hcid/main.c
@@ -783,7 +783,7 @@ int main(int argc, char *argv[])
if (sdp) {
set_sdp_server_enable();
- start_sdp_server(0, SDP_SERVER_COMPAT);
+ start_sdp_server(0, hcid.deviceid, SDP_SERVER_COMPAT);
}
notify_init();
diff --git a/hcid/parser.y b/hcid/parser.y
index aa16a5c7..4641a0ac 100644
--- a/hcid/parser.y
+++ b/hcid/parser.y
@@ -62,16 +62,16 @@ void yylex_destroy(void);
}
%token K_OPTIONS K_DEVICE
-%token K_AUTOINIT K_SECURITY K_PAIRING K_OFFMODE
+%token K_AUTOINIT K_SECURITY K_PAIRING K_OFFMODE K_DEVICEID
%token K_PTYPE K_NAME K_CLASS K_VOICE K_PAGETO K_LM K_LP K_ISCAN K_PSCAN K_DISCOVTO
%token K_PASSKEY
%token K_YES K_NO
-%token <str> WORD PATH STRING LIST HCI BDADDR
+%token <str> WORD PATH STRING LIST HCI BDADDR ID
%token <num> NUM
%type <num> bool pkt_type link_mode link_policy sec_mode pair_mode off_mode
-%type <str> dev_name hci bdaddr
+%type <str> dev_name dev_id hci bdaddr
%%
config: statement | config statement;
@@ -122,6 +122,10 @@ hcid_opt:
hcid.offmode = $2;
}
+ | K_DEVICEID dev_id {
+ strncpy((char *) hcid.deviceid, $2, 15);
+ }
+
| K_PASSKEY STRING {
strncpy((char *) hcid.pin_code, $2, 16);
hcid.pin_len = strlen($2);
@@ -172,6 +176,10 @@ off_mode:
}
;
+dev_id:
+ ID {
+ }
+ ;
device_options: '{' device_opts '}';
device_opts: | device_opt ';' | error ';' | device_opts device_opt ';';
diff --git a/sdpd/main.c b/sdpd/main.c
index 4027ae96..856c6cb3 100644
--- a/sdpd/main.c
+++ b/sdpd/main.c
@@ -139,7 +139,7 @@ int main(int argc, char *argv[])
event_loop = g_main_loop_new(NULL, FALSE);
- if (start_sdp_server(mtu, flags) < 0) {
+ if (start_sdp_server(mtu, NULL, flags) < 0) {
g_main_loop_unref(event_loop);
exit(1);
}
diff --git a/sdpd/sdpd.h b/sdpd/sdpd.h
index 8ec47b1a..13aa2c74 100644
--- a/sdpd/sdpd.h
+++ b/sdpd/sdpd.h
@@ -46,6 +46,8 @@ int service_remove_req(sdp_req_t *req, sdp_buf_t *rsp);
void register_public_browse_group(int public);
void register_server_service(int public);
+void register_device_id(const uint16_t vendor, const uint16_t product,
+ const uint16_t version);
typedef struct {
uint32_t timestamp;
@@ -80,7 +82,7 @@ uint32_t sdp_get_time();
#define SDP_SERVER_MASTER (1 << 1)
#define SDP_SERVER_PUBLIC (1 << 2)
-int start_sdp_server(uint16_t mtu, uint32_t flags);
+int start_sdp_server(uint16_t mtu, const char *did, uint32_t flags);
void stop_sdp_server(void);
int add_record_to_server(sdp_record_t *rec);
diff --git a/sdpd/server.c b/sdpd/server.c
index 2abcc6bc..fab17f00 100644
--- a/sdpd/server.c
+++ b/sdpd/server.c
@@ -31,6 +31,7 @@
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
+#include <stdlib.h>
#include <sys/stat.h>
#include <sys/socket.h>
@@ -215,7 +216,7 @@ static gboolean io_accept_event(GIOChannel *chan, GIOCondition cond, gpointer da
return TRUE;
}
-int start_sdp_server(uint16_t mtu, uint32_t flags)
+int start_sdp_server(uint16_t mtu, const char *did, uint32_t flags)
{
int compat = flags & SDP_SERVER_COMPAT;
int master = flags & SDP_SERVER_MASTER;
@@ -228,6 +229,21 @@ int start_sdp_server(uint16_t mtu, uint32_t flags)
return -1;
}
+ if (did && strlen(did) > 0) {
+ const char *ptr = did;
+ uint16_t vid = 0x0000, pid = 0x0000, ver = 0x0000;
+
+ vid = (uint16_t) strtol(ptr, NULL, 16);
+ ptr = strchr(ptr, ':');
+ if (ptr) {
+ pid = (uint16_t) strtol(ptr + 1, NULL, 16);
+ ptr = strchr(ptr + 1, ':');
+ if (ptr)
+ ver = (uint16_t) strtol(ptr + 1, NULL, 16);
+ register_device_id(vid, pid, ver);
+ }
+ }
+
l2cap_io = g_io_channel_unix_new(l2cap_sock);
g_io_channel_set_close_on_unref(l2cap_io, TRUE);
diff --git a/sdpd/service.c b/sdpd/service.c
index 69c5242b..8c8c3a73 100644
--- a/sdpd/service.c
+++ b/sdpd/service.c
@@ -102,7 +102,8 @@ void register_public_browse_group(int public)
sdp_attr_add(browse, SDP_ATTR_RECORD_HANDLE, sdpdata);
add_lang_attr(browse);
- sdp_set_info_attr(browse, "Public Browse Group Root", "BlueZ", "Root of public browse hierarchy");
+ sdp_set_info_attr(browse, "Public Browse Group Root", "BlueZ",
+ "Root of public browse hierarchy");
sdp_uuid16_create(&bgscid, BROWSE_GRP_DESC_SVCLASS_ID);
browselist = sdp_list_append(0, &bgscid);
@@ -140,7 +141,8 @@ void register_server_service(int public)
server->handle = SDP_SERVER_RECORD_HANDLE;
sdp_record_add(BDADDR_ANY, server);
- sdp_attr_add(server, SDP_ATTR_RECORD_HANDLE, sdp_data_alloc(SDP_UINT32, &server->handle));
+ sdp_attr_add(server, SDP_ATTR_RECORD_HANDLE,
+ sdp_data_alloc(SDP_UINT32, &server->handle));
/*
* Add all attributes to service record. (No need to commit since we
@@ -207,6 +209,63 @@ void register_server_service(int public)
update_db_timestamp();
}
+void register_device_id(const uint16_t vendor, const uint16_t product,
+ const uint16_t version)
+{
+ const uint16_t spec = 0x0102, source = 0x0002;
+ const uint8_t primary = 1;
+ sdp_list_t *class_list, *group_list, *profile_list;
+ uuid_t class_uuid, group_uuid;
+ sdp_data_t *sdp_data, *primary_data, *source_data;
+ sdp_data_t *spec_data, *vendor_data, *product_data, *version_data;
+ sdp_profile_desc_t profile;
+ sdp_record_t *record = sdp_record_alloc();
+
+ info("Adding device id record for %04x:%04x", vendor, product);
+
+ record->handle = sdp_next_handle();
+
+ sdp_record_add(BDADDR_ANY, record);
+ sdp_data = sdp_data_alloc(SDP_UINT32, &record->handle);
+ sdp_attr_add(record, SDP_ATTR_RECORD_HANDLE, sdp_data);
+
+ sdp_uuid16_create(&class_uuid, PNP_INFO_SVCLASS_ID);
+ class_list = sdp_list_append(0, &class_uuid);
+ sdp_set_service_classes(record, class_list);
+ sdp_list_free(class_list, NULL);
+
+ sdp_uuid16_create(&group_uuid, PUBLIC_BROWSE_GROUP);
+ group_list = sdp_list_append(NULL, &group_uuid);
+ sdp_set_browse_groups(record, group_list);
+ sdp_list_free(group_list, NULL);
+
+ sdp_uuid16_create(&profile.uuid, PNP_INFO_PROFILE_ID);
+ profile.version = spec;
+ profile_list = sdp_list_append(NULL, &profile);
+ sdp_set_profile_descs(record, profile_list);
+ sdp_list_free(profile_list, NULL);
+
+ spec_data = sdp_data_alloc(SDP_UINT16, &spec);
+ sdp_attr_add(record, 0x0200, spec_data);
+
+ vendor_data = sdp_data_alloc(SDP_UINT16, &vendor);
+ sdp_attr_add(record, 0x0201, vendor_data);
+
+ product_data = sdp_data_alloc(SDP_UINT16, &product);
+ sdp_attr_add(record, 0x0202, product_data);
+
+ version_data = sdp_data_alloc(SDP_UINT16, &version);
+ sdp_attr_add(record, 0x0203, version_data);
+
+ primary_data = sdp_data_alloc(SDP_BOOL, &primary);
+ sdp_attr_add(record, 0x0204, primary_data);
+
+ source_data = sdp_data_alloc(SDP_UINT16, &source);
+ sdp_attr_add(record, 0x0205, source_data);
+
+ update_db_timestamp();
+}
+
int add_record_to_server(sdp_record_t *rec)
{
sdp_data_t *data;