mirror of
https://git.kernel.org/pub/scm/bluetooth/bluez.git
synced 2024-11-15 16:24:28 +08:00
28ce42b050
g_file_get_contents allocates memory. It needs to be freed on any function exit.
315 lines
6.6 KiB
C
315 lines
6.6 KiB
C
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
/*
|
|
*
|
|
* BlueZ - Bluetooth protocol stack for Linux
|
|
*
|
|
* Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
|
|
*
|
|
*
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif
|
|
|
|
#include <errno.h>
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "lib/bluetooth.h"
|
|
#include "lib/sdp.h"
|
|
|
|
#include "gdbus/gdbus.h"
|
|
|
|
#include "src/dbus-common.h"
|
|
#include "src/plugin.h"
|
|
#include "src/adapter.h"
|
|
#include "src/log.h"
|
|
|
|
/* http://www.bluetooth.org/Technical/AssignedNumbers/baseband.htm */
|
|
|
|
#define MAJOR_CLASS_MISCELLANEOUS 0x00
|
|
#define MAJOR_CLASS_COMPUTER 0x01
|
|
|
|
#define MINOR_CLASS_UNCATEGORIZED 0x00
|
|
#define MINOR_CLASS_DESKTOP 0x01
|
|
#define MINOR_CLASS_SERVER 0x02
|
|
#define MINOR_CLASS_LAPTOP 0x03
|
|
#define MINOR_CLASS_HANDHELD 0x04
|
|
#define MINOR_CLASS_PALM_SIZED 0x05
|
|
#define MINOR_CLASS_WEARABLE 0x06
|
|
#define MINOR_CLASS_TABLET 0x07
|
|
|
|
static uint8_t major_class = MAJOR_CLASS_MISCELLANEOUS;
|
|
static uint8_t minor_class = MINOR_CLASS_UNCATEGORIZED;
|
|
|
|
static char *pretty_hostname = NULL;
|
|
static char *static_hostname = NULL;
|
|
|
|
/*
|
|
* Fallback to static hostname only if empty pretty hostname was already
|
|
* received.
|
|
*/
|
|
static const char *get_hostname(void)
|
|
{
|
|
if (pretty_hostname) {
|
|
if (g_str_equal(pretty_hostname, "") == FALSE)
|
|
return pretty_hostname;
|
|
|
|
if (static_hostname &&
|
|
g_str_equal(static_hostname, "") == FALSE)
|
|
return static_hostname;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static void update_name(struct btd_adapter *adapter, gpointer user_data)
|
|
{
|
|
const char *hostname = get_hostname();
|
|
|
|
if (hostname == NULL)
|
|
return;
|
|
|
|
if (btd_adapter_is_default(adapter)) {
|
|
DBG("name: %s", hostname);
|
|
|
|
adapter_set_name(adapter, hostname);
|
|
} else {
|
|
uint16_t index = btd_adapter_get_index(adapter);
|
|
char *str;
|
|
|
|
/* Avoid "some device #0" names, start at #1 */
|
|
str = g_strdup_printf("%s #%u", hostname, index + 1);
|
|
|
|
DBG("name: %s", str);
|
|
|
|
adapter_set_name(adapter, str);
|
|
|
|
g_free(str);
|
|
}
|
|
}
|
|
|
|
static void update_class(struct btd_adapter *adapter, gpointer user_data)
|
|
{
|
|
if (major_class == MAJOR_CLASS_MISCELLANEOUS)
|
|
return;
|
|
|
|
DBG("major: 0x%02x minor: 0x%02x", major_class, minor_class);
|
|
|
|
btd_adapter_set_class(adapter, major_class, minor_class);
|
|
}
|
|
|
|
static const struct {
|
|
const char *chassis;
|
|
uint8_t major_class;
|
|
uint8_t minor_class;
|
|
} chassis_table[] = {
|
|
{ "desktop", MAJOR_CLASS_COMPUTER, MINOR_CLASS_DESKTOP },
|
|
{ "server", MAJOR_CLASS_COMPUTER, MINOR_CLASS_SERVER },
|
|
{ "laptop", MAJOR_CLASS_COMPUTER, MINOR_CLASS_LAPTOP },
|
|
{ "handset", MAJOR_CLASS_COMPUTER, MINOR_CLASS_HANDHELD },
|
|
{ "tablet", MAJOR_CLASS_COMPUTER, MINOR_CLASS_TABLET },
|
|
{ }
|
|
};
|
|
|
|
static void property_changed(GDBusProxy *proxy, const char *name,
|
|
DBusMessageIter *iter, void *user_data)
|
|
{
|
|
if (g_str_equal(name, "PrettyHostname") == TRUE) {
|
|
if (iter == NULL) {
|
|
g_dbus_proxy_refresh_property(proxy, name);
|
|
return;
|
|
}
|
|
|
|
if (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_STRING) {
|
|
const char *str;
|
|
|
|
dbus_message_iter_get_basic(iter, &str);
|
|
|
|
DBG("pretty hostname: %s", str);
|
|
|
|
g_free(pretty_hostname);
|
|
pretty_hostname = g_strdup(str);
|
|
|
|
adapter_foreach(update_name, NULL);
|
|
}
|
|
} else if (g_str_equal(name, "StaticHostname") == TRUE) {
|
|
if (iter == NULL) {
|
|
g_dbus_proxy_refresh_property(proxy, name);
|
|
return;
|
|
}
|
|
|
|
if (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_STRING) {
|
|
const char *str;
|
|
|
|
dbus_message_iter_get_basic(iter, &str);
|
|
|
|
DBG("static hostname: %s", str);
|
|
|
|
g_free(static_hostname);
|
|
static_hostname = g_strdup(str);
|
|
|
|
adapter_foreach(update_name, NULL);
|
|
}
|
|
} else if (g_str_equal(name, "Chassis") == TRUE) {
|
|
if (iter == NULL) {
|
|
g_dbus_proxy_refresh_property(proxy, name);
|
|
return;
|
|
}
|
|
|
|
if (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_STRING) {
|
|
const char *str;
|
|
int i;
|
|
|
|
dbus_message_iter_get_basic(iter, &str);
|
|
|
|
DBG("chassis: %s", str);
|
|
|
|
for (i = 0; chassis_table[i].chassis; i++) {
|
|
if (strcmp(chassis_table[i].chassis, str))
|
|
continue;
|
|
|
|
major_class = chassis_table[i].major_class;
|
|
minor_class = chassis_table[i].minor_class;
|
|
|
|
adapter_foreach(update_class, NULL);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static int hostname_probe(struct btd_adapter *adapter)
|
|
{
|
|
DBG("");
|
|
|
|
update_name(adapter, NULL);
|
|
update_class(adapter, NULL);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void hostname_remove(struct btd_adapter *adapter)
|
|
{
|
|
DBG("");
|
|
}
|
|
|
|
static struct btd_adapter_driver hostname_driver = {
|
|
.name = "hostname",
|
|
.probe = hostname_probe,
|
|
.remove = hostname_remove,
|
|
};
|
|
|
|
static void read_dmi_fallback(void)
|
|
{
|
|
char *contents;
|
|
int i, type;
|
|
const char *str;
|
|
|
|
if (g_file_get_contents("/sys/class/dmi/id/chassis_type",
|
|
&contents, NULL, NULL) == FALSE)
|
|
return;
|
|
|
|
type = atoi(contents);
|
|
g_free(contents);
|
|
if (type < 0 || type > 0x1D)
|
|
return;
|
|
|
|
/* from systemd hostname chassis list */
|
|
switch (type) {
|
|
case 0x3:
|
|
case 0x4:
|
|
case 0x6:
|
|
case 0x7:
|
|
str = "desktop";
|
|
break;
|
|
case 0x8:
|
|
case 0x9:
|
|
case 0xA:
|
|
case 0xE:
|
|
str = "laptop";
|
|
break;
|
|
case 0xB:
|
|
str = "handset";
|
|
break;
|
|
case 0x11:
|
|
case 0x1C:
|
|
str = "server";
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
|
|
DBG("chassis: %s", str);
|
|
|
|
for (i = 0; chassis_table[i].chassis; i++) {
|
|
if (!strcmp(chassis_table[i].chassis, str)) {
|
|
major_class = chassis_table[i].major_class;
|
|
minor_class = chassis_table[i].minor_class;
|
|
break;
|
|
}
|
|
}
|
|
|
|
DBG("major: 0x%02x minor: 0x%02x", major_class, minor_class);
|
|
}
|
|
|
|
static GDBusClient *hostname_client = NULL;
|
|
static GDBusProxy *hostname_proxy = NULL;
|
|
|
|
static int hostname_init(void)
|
|
{
|
|
DBusConnection *conn = btd_get_dbus_connection();
|
|
int err;
|
|
|
|
read_dmi_fallback();
|
|
|
|
hostname_client = g_dbus_client_new(conn, "org.freedesktop.hostname1",
|
|
"/org/freedesktop/hostname1");
|
|
if (!hostname_client)
|
|
return -EIO;
|
|
|
|
hostname_proxy = g_dbus_proxy_new(hostname_client,
|
|
"/org/freedesktop/hostname1",
|
|
"org.freedesktop.hostname1");
|
|
if (!hostname_proxy) {
|
|
g_dbus_client_unref(hostname_client);
|
|
hostname_client = NULL;
|
|
return -EIO;
|
|
}
|
|
|
|
g_dbus_proxy_set_property_watch(hostname_proxy, property_changed, NULL);
|
|
|
|
err = btd_register_adapter_driver(&hostname_driver);
|
|
if (err < 0) {
|
|
g_dbus_proxy_unref(hostname_proxy);
|
|
hostname_proxy = NULL;
|
|
g_dbus_client_unref(hostname_client);
|
|
hostname_client = NULL;
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
static void hostname_exit(void)
|
|
{
|
|
btd_unregister_adapter_driver(&hostname_driver);
|
|
|
|
if (hostname_proxy) {
|
|
g_dbus_proxy_unref(hostname_proxy);
|
|
hostname_proxy = NULL;
|
|
}
|
|
|
|
if (hostname_client) {
|
|
g_dbus_client_unref(hostname_client);
|
|
hostname_client = NULL;
|
|
}
|
|
|
|
g_free(pretty_hostname);
|
|
g_free(static_hostname);
|
|
}
|
|
|
|
BLUETOOTH_PLUGIN_DEFINE(hostname, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
|
|
hostname_init, hostname_exit)
|