| // SPDX-License-Identifier: GPL-2.0-or-later |
| /* |
| * |
| * BlueZ - Bluetooth protocol stack for Linux |
| * |
| * Copyright (C) 2006-2010 Nokia Corporation |
| * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org> |
| * |
| * |
| */ |
| |
| #ifdef HAVE_CONFIG_H |
| #include <config.h> |
| #endif |
| |
| #define _GNU_SOURCE |
| #include <stdio.h> |
| #include <errno.h> |
| #include <ctype.h> |
| #include <fcntl.h> |
| #include <unistd.h> |
| #include <stdlib.h> |
| #include <time.h> |
| #include <limits.h> |
| #include <sys/file.h> |
| #include <sys/stat.h> |
| |
| #include <glib.h> |
| |
| #include "bluetooth/bluetooth.h" |
| #include "bluetooth/sdp.h" |
| #include "bluetooth/sdp_lib.h" |
| #include "bluetooth/uuid.h" |
| |
| #include "textfile.h" |
| #include "uuid-helper.h" |
| #include "storage.h" |
| |
| /* When all services should trust a remote device */ |
| #define GLOBAL_TRUST "[all]" |
| |
| struct match { |
| GSList *keys; |
| char *pattern; |
| }; |
| |
| int read_discoverable_timeout(const char *src, int *timeout) |
| { |
| char filename[PATH_MAX], *str; |
| |
| create_name(filename, PATH_MAX, src, "config"); |
| |
| str = textfile_get(filename, "discovto"); |
| if (!str) |
| return -ENOENT; |
| |
| if (sscanf(str, "%d", timeout) != 1) { |
| free(str); |
| return -ENOENT; |
| } |
| |
| free(str); |
| |
| return 0; |
| } |
| |
| int read_pairable_timeout(const char *src, int *timeout) |
| { |
| char filename[PATH_MAX], *str; |
| |
| create_name(filename, PATH_MAX, src, "config"); |
| |
| str = textfile_get(filename, "pairto"); |
| if (!str) |
| return -ENOENT; |
| |
| if (sscanf(str, "%d", timeout) != 1) { |
| free(str); |
| return -ENOENT; |
| } |
| |
| free(str); |
| |
| return 0; |
| } |
| |
| int read_on_mode(const char *src, char *mode, int length) |
| { |
| char filename[PATH_MAX], *str; |
| |
| create_name(filename, PATH_MAX, src, "config"); |
| |
| str = textfile_get(filename, "onmode"); |
| if (!str) |
| return -ENOENT; |
| |
| strncpy(mode, str, length); |
| mode[length - 1] = '\0'; |
| |
| free(str); |
| |
| return 0; |
| } |
| |
| int read_local_name(const bdaddr_t *bdaddr, char *name) |
| { |
| char filename[PATH_MAX], *str; |
| int len; |
| char addr[18]; |
| |
| ba2str(bdaddr, addr); |
| |
| create_filename(filename, PATH_MAX, "/%s/config", addr); |
| |
| str = textfile_get(filename, "name"); |
| if (!str) |
| return -ENOENT; |
| |
| len = strlen(str); |
| if (len > HCI_MAX_NAME_LENGTH) |
| str[HCI_MAX_NAME_LENGTH] = '\0'; |
| strcpy(name, str); |
| |
| free(str); |
| |
| return 0; |
| } |
| |
| sdp_record_t *record_from_string(const char *str) |
| { |
| sdp_record_t *rec; |
| int size, i, len; |
| uint8_t *pdata; |
| char tmp[3]; |
| |
| size = strlen(str)/2; |
| pdata = g_malloc0(size); |
| |
| tmp[2] = 0; |
| for (i = 0; i < size; i++) { |
| memcpy(tmp, str + (i * 2), 2); |
| pdata[i] = (uint8_t) strtol(tmp, NULL, 16); |
| } |
| |
| rec = sdp_extract_pdu(pdata, size, &len); |
| g_free(pdata); |
| |
| return rec; |
| } |
| |
| sdp_record_t *find_record_in_list(sdp_list_t *recs, const char *uuid) |
| { |
| sdp_list_t *seq; |
| |
| for (seq = recs; seq; seq = seq->next) { |
| sdp_record_t *rec = (sdp_record_t *) seq->data; |
| sdp_list_t *svcclass = NULL; |
| char *uuid_str; |
| |
| if (sdp_get_service_classes(rec, &svcclass) < 0) |
| continue; |
| |
| /* Extract the uuid */ |
| uuid_str = bt_uuid2string(svcclass->data); |
| if (!uuid_str) { |
| sdp_list_free(svcclass, free); |
| continue; |
| } |
| |
| if (!strcasecmp(uuid_str, uuid)) { |
| sdp_list_free(svcclass, free); |
| free(uuid_str); |
| return rec; |
| } |
| |
| sdp_list_free(svcclass, free); |
| free(uuid_str); |
| } |
| return NULL; |
| } |