| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309 |
- // SPDX-License-Identifier: LGPL-2.1-or-later
- /*
- *
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * Copyright (C) 2013-2014 Intel Corporation. All rights reserved.
- *
- *
- */
- #ifdef HAVE_CONFIG_H
- #include <config.h>
- #endif
- #include <glib.h>
- #include <stdbool.h>
- #include <unistd.h>
- #include <errno.h>
- #include "lib/bluetooth.h"
- #include "btio/btio.h"
- #include "lib/sdp.h"
- #include "lib/sdp_lib.h"
- #include "src/sdp-client.h"
- #include "src/sdpd.h"
- #include "src/log.h"
- #include "hal-msg.h"
- #include "ipc-common.h"
- #include "ipc.h"
- #include "utils.h"
- #include "bluetooth.h"
- #include "socket.h"
- #define RFCOMM_CHANNEL_MAX 30
- #define OPP_DEFAULT_CHANNEL 9
- #define HSP_AG_DEFAULT_CHANNEL 12
- #define HFP_AG_DEFAULT_CHANNEL 13
- #define PBAP_DEFAULT_CHANNEL 15
- #define MAP_MAS_DEFAULT_CHANNEL 16
- #define SVC_HINT_OBEX 0x10
- /* Hardcoded MAP stuff needed for MAS SMS Instance.*/
- #define DEFAULT_MAS_INSTANCE 0x00
- #define MAP_MSG_TYPE_SMS_GSM 0x02
- #define MAP_MSG_TYPE_SMS_CDMA 0x04
- #define DEFAULT_MAS_MSG_TYPE (MAP_MSG_TYPE_SMS_GSM | MAP_MSG_TYPE_SMS_CDMA)
- static struct ipc *hal_ipc = NULL;
- struct rfcomm_sock {
- int channel; /* RFCOMM channel */
- BtIOSecLevel sec_level;
- /* for socket to BT */
- int bt_sock;
- guint bt_watch;
- /* for socket to HAL */
- int jv_sock;
- guint jv_watch;
- bdaddr_t dst;
- uint32_t service_handle;
- uint8_t *buf;
- int buf_size;
- };
- struct rfcomm_channel {
- bool reserved;
- struct rfcomm_sock *rfsock;
- };
- static bdaddr_t adapter_addr;
- static uint8_t hal_mode = HAL_MODE_SOCKET_DEFAULT;
- static const uint8_t zero_uuid[16] = { 0 };
- /* Simple list of RFCOMM connected sockets */
- static GList *connections = NULL;
- static struct rfcomm_channel servers[RFCOMM_CHANNEL_MAX + 1];
- static uint32_t test_sdp_record_uuid16 = 0;
- static uint32_t test_sdp_record_uuid32 = 0;
- static uint32_t test_sdp_record_uuid128 = 0;
- static int rfsock_set_buffer(struct rfcomm_sock *rfsock)
- {
- socklen_t len = sizeof(int);
- int rcv, snd, size, err;
- err = getsockopt(rfsock->bt_sock, SOL_SOCKET, SO_RCVBUF, &rcv, &len);
- if (err < 0) {
- int err = -errno;
- error("getsockopt(SO_RCVBUF): %s", strerror(-err));
- return err;
- }
- err = getsockopt(rfsock->bt_sock, SOL_SOCKET, SO_SNDBUF, &snd, &len);
- if (err < 0) {
- int err = -errno;
- error("getsockopt(SO_SNDBUF): %s", strerror(-err));
- return err;
- }
- size = MAX(rcv, snd);
- DBG("Set buffer size %d", size);
- rfsock->buf = g_malloc(size);
- rfsock->buf_size = size;
- return 0;
- }
- static void cleanup_rfsock(gpointer data)
- {
- struct rfcomm_sock *rfsock = data;
- DBG("rfsock %p bt_sock %d jv_sock %d", rfsock, rfsock->bt_sock,
- rfsock->jv_sock);
- if (rfsock->jv_sock >= 0)
- if (close(rfsock->jv_sock) < 0)
- error("close() fd %d failed: %s", rfsock->jv_sock,
- strerror(errno));
- if (rfsock->bt_sock >= 0)
- if (close(rfsock->bt_sock) < 0)
- error("close() fd %d: failed: %s", rfsock->bt_sock,
- strerror(errno));
- if (rfsock->bt_watch > 0)
- if (!g_source_remove(rfsock->bt_watch))
- error("bt_watch source was not found");
- if (rfsock->jv_watch > 0)
- if (!g_source_remove(rfsock->jv_watch))
- error("stack_watch source was not found");
- if (rfsock->service_handle)
- bt_adapter_remove_record(rfsock->service_handle);
- if (rfsock->buf)
- g_free(rfsock->buf);
- g_free(rfsock);
- }
- static struct rfcomm_sock *create_rfsock(int bt_sock, int *hal_sock)
- {
- int fds[2] = {-1, -1};
- struct rfcomm_sock *rfsock;
- if (socketpair(AF_LOCAL, SOCK_STREAM, 0, fds) < 0) {
- error("socketpair(): %s", strerror(errno));
- *hal_sock = -1;
- return NULL;
- }
- rfsock = g_new0(struct rfcomm_sock, 1);
- rfsock->jv_sock = fds[0];
- *hal_sock = fds[1];
- rfsock->bt_sock = bt_sock;
- DBG("rfsock %p", rfsock);
- if (bt_sock < 0)
- return rfsock;
- if (rfsock_set_buffer(rfsock) < 0) {
- cleanup_rfsock(rfsock);
- return NULL;
- }
- return rfsock;
- }
- static sdp_record_t *create_rfcomm_record(uint8_t chan, uuid_t *uuid,
- const char *svc_name,
- bool has_obex)
- {
- sdp_list_t *svclass_id;
- sdp_list_t *seq, *proto_seq, *pbg_seq;
- sdp_list_t *proto[3];
- uuid_t l2cap_uuid, rfcomm_uuid, obex_uuid, pbg_uuid;
- sdp_data_t *channel;
- sdp_record_t *record;
- record = sdp_record_alloc();
- if (!record)
- return NULL;
- record->handle = sdp_next_handle();
- svclass_id = sdp_list_append(NULL, uuid);
- sdp_set_service_classes(record, svclass_id);
- sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
- proto[0] = sdp_list_append(NULL, &l2cap_uuid);
- seq = sdp_list_append(NULL, proto[0]);
- sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
- proto[1] = sdp_list_append(NULL, &rfcomm_uuid);
- channel = sdp_data_alloc(SDP_UINT8, &chan);
- proto[1] = sdp_list_append(proto[1], channel);
- seq = sdp_list_append(seq, proto[1]);
- if (has_obex) {
- sdp_uuid16_create(&obex_uuid, OBEX_UUID);
- proto[2] = sdp_list_append(NULL, &obex_uuid);
- seq = sdp_list_append(seq, proto[2]);
- }
- proto_seq = sdp_list_append(NULL, seq);
- sdp_set_access_protos(record, proto_seq);
- sdp_uuid16_create(&pbg_uuid, PUBLIC_BROWSE_GROUP);
- pbg_seq = sdp_list_append(NULL, &pbg_uuid);
- sdp_set_browse_groups(record, pbg_seq);
- if (svc_name)
- sdp_set_info_attr(record, svc_name, NULL, NULL);
- sdp_data_free(channel);
- sdp_list_free(proto[0], NULL);
- sdp_list_free(proto[1], NULL);
- if (has_obex)
- sdp_list_free(proto[2], NULL);
- sdp_list_free(seq, NULL);
- sdp_list_free(proto_seq, NULL);
- sdp_list_free(pbg_seq, NULL);
- sdp_list_free(svclass_id, NULL);
- return record;
- }
- static sdp_record_t *create_opp_record(uint8_t chan, const char *svc_name)
- {
- uint8_t formats[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0xff };
- uint8_t dtd = SDP_UINT8;
- uuid_t uuid;
- sdp_list_t *seq;
- sdp_profile_desc_t profile[1];
- void *dtds[sizeof(formats)], *values[sizeof(formats)];
- sdp_data_t *formats_list;
- sdp_record_t *record;
- size_t i;
- sdp_uuid16_create(&uuid, OBEX_OBJPUSH_SVCLASS_ID);
- record = create_rfcomm_record(chan, &uuid, svc_name, true);
- if (!record)
- return NULL;
- sdp_uuid16_create(&profile[0].uuid, OBEX_OBJPUSH_PROFILE_ID);
- profile[0].version = 0x0100;
- seq = sdp_list_append(NULL, profile);
- sdp_set_profile_descs(record, seq);
- for (i = 0; i < sizeof(formats); i++) {
- dtds[i] = &dtd;
- values[i] = &formats[i];
- }
- formats_list = sdp_seq_alloc(dtds, values, sizeof(formats));
- sdp_attr_add(record, SDP_ATTR_SUPPORTED_FORMATS_LIST, formats_list);
- sdp_list_free(seq, NULL);
- return record;
- }
- static sdp_record_t *create_pbap_record(uint8_t chan, const char *svc_name)
- {
- sdp_list_t *seq;
- sdp_profile_desc_t profile[1];
- uint8_t formats = 0x01;
- sdp_record_t *record;
- uuid_t uuid;
- sdp_uuid16_create(&uuid, PBAP_PSE_SVCLASS_ID);
- record = create_rfcomm_record(chan, &uuid, svc_name, true);
- if (!record)
- return NULL;
- sdp_uuid16_create(&profile[0].uuid, PBAP_PROFILE_ID);
- profile[0].version = 0x0101;
- seq = sdp_list_append(NULL, profile);
- sdp_set_profile_descs(record, seq);
- sdp_attr_add_new(record, SDP_ATTR_SUPPORTED_REPOSITORIES, SDP_UINT8,
- &formats);
- sdp_list_free(seq, NULL);
- return record;
- }
- static sdp_record_t *create_mas_record(uint8_t chan, const char *svc_name)
- {
- sdp_list_t *seq;
- sdp_profile_desc_t profile[1];
- uint8_t minst, mtype;
- sdp_record_t *record;
- uuid_t uuid;
- int cnt, ret;
- switch (hal_mode) {
- case HAL_MODE_SOCKET_DYNAMIC_MAP:
- /*
- * Service name for MAP is passed as XXYYname
- * XX - instance
- * YY - message type
- */
- ret = sscanf(svc_name, "%02hhx%02hhx%n", &minst, &mtype, &cnt);
- if (ret != 2 || cnt != 4)
- return NULL;
- svc_name += 4;
- break;
- case HAL_MODE_SOCKET_DEFAULT:
- minst = DEFAULT_MAS_INSTANCE;
- mtype = DEFAULT_MAS_MSG_TYPE;
- break;
- default:
- return NULL;
- }
- sdp_uuid16_create(&uuid, MAP_MSE_SVCLASS_ID);
- record = create_rfcomm_record(chan, &uuid, svc_name, true);
- if (!record)
- return NULL;
- sdp_uuid16_create(&profile[0].uuid, MAP_PROFILE_ID);
- profile[0].version = 0x0101;
- seq = sdp_list_append(NULL, profile);
- sdp_set_profile_descs(record, seq);
- sdp_attr_add_new(record, SDP_ATTR_MAS_INSTANCE_ID, SDP_UINT8, &minst);
- sdp_attr_add_new(record, SDP_ATTR_SUPPORTED_MESSAGE_TYPES, SDP_UINT8,
- &mtype);
- sdp_list_free(seq, NULL);
- return record;
- }
- static sdp_record_t *create_spp_record(uint8_t chan, const char *svc_name)
- {
- sdp_record_t *record;
- uuid_t uuid;
- sdp_uuid16_create(&uuid, SERIAL_PORT_SVCLASS_ID);
- record = create_rfcomm_record(chan, &uuid, svc_name, false);
- if (!record)
- return NULL;
- return record;
- }
- static sdp_record_t *create_app_record(uint8_t chan,
- const uint8_t *app_uuid,
- const char *svc_name)
- {
- sdp_record_t *record;
- uuid_t uuid;
- sdp_uuid128_create(&uuid, app_uuid);
- sdp_uuid128_to_uuid(&uuid);
- record = create_rfcomm_record(chan, &uuid, svc_name, false);
- if (!record)
- return NULL;
- return record;
- }
- static const struct profile_info {
- uint8_t uuid[16];
- uint8_t channel;
- uint8_t svc_hint;
- BtIOSecLevel sec_level;
- sdp_record_t * (*create_record)(uint8_t chan, const char *svc_name);
- } profiles[] = {
- {
- .uuid = {
- 0x00, 0x00, 0x11, 0x08, 0x00, 0x00, 0x10, 0x00,
- 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB
- },
- .channel = HSP_AG_DEFAULT_CHANNEL,
- .svc_hint = 0,
- .sec_level = BT_IO_SEC_MEDIUM,
- .create_record = NULL
- }, {
- .uuid = {
- 0x00, 0x00, 0x11, 0x1F, 0x00, 0x00, 0x10, 0x00,
- 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB
- },
- .channel = HFP_AG_DEFAULT_CHANNEL,
- .svc_hint = 0,
- .sec_level = BT_IO_SEC_MEDIUM,
- .create_record = NULL
- }, {
- .uuid = {
- 0x00, 0x00, 0x11, 0x2F, 0x00, 0x00, 0x10, 0x00,
- 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB
- },
- .channel = PBAP_DEFAULT_CHANNEL,
- .svc_hint = SVC_HINT_OBEX,
- .sec_level = BT_IO_SEC_MEDIUM,
- .create_record = create_pbap_record
- }, {
- .uuid = {
- 0x00, 0x00, 0x11, 0x05, 0x00, 0x00, 0x10, 0x00,
- 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB
- },
- .channel = OPP_DEFAULT_CHANNEL,
- .svc_hint = SVC_HINT_OBEX,
- .sec_level = BT_IO_SEC_LOW,
- .create_record = create_opp_record
- }, {
- .uuid = {
- 0x00, 0x00, 0x11, 0x32, 0x00, 0x00, 0x10, 0x00,
- 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB
- },
- .channel = MAP_MAS_DEFAULT_CHANNEL,
- .svc_hint = SVC_HINT_OBEX,
- .sec_level = BT_IO_SEC_MEDIUM,
- .create_record = create_mas_record
- }, {
- .uuid = {
- 0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x10, 0x00,
- 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB
- },
- .channel = 0,
- .svc_hint = 0,
- .sec_level = BT_IO_SEC_MEDIUM,
- .create_record = create_spp_record
- },
- };
- static uint32_t sdp_service_register(uint8_t channel, const uint8_t *uuid,
- const struct profile_info *profile,
- const void *svc_name)
- {
- sdp_record_t *record = NULL;
- uint8_t svc_hint = 0;
- if (profile && profile->create_record) {
- record = profile->create_record(channel, svc_name);
- svc_hint = profile->svc_hint;
- } else if (uuid) {
- record = create_app_record(channel, uuid, svc_name);
- }
- if (!record)
- return 0;
- if (bt_adapter_add_record(record, svc_hint) < 0) {
- error("Failed to register on SDP record");
- sdp_record_free(record);
- return 0;
- }
- return record->handle;
- }
- static int bt_sock_send_fd(int sock_fd, const void *buf, int len, int send_fd)
- {
- ssize_t ret;
- struct msghdr msg;
- struct cmsghdr *cmsg;
- struct iovec iv;
- char cmsgbuf[CMSG_SPACE(sizeof(int))];
- DBG("len %d sock_fd %d send_fd %d", len, sock_fd, send_fd);
- if (sock_fd == -1 || send_fd == -1)
- return -1;
- memset(&msg, 0, sizeof(msg));
- memset(cmsgbuf, 0, sizeof(cmsgbuf));
- msg.msg_control = cmsgbuf;
- msg.msg_controllen = sizeof(cmsgbuf);
- cmsg = CMSG_FIRSTHDR(&msg);
- cmsg->cmsg_level = SOL_SOCKET;
- cmsg->cmsg_type = SCM_RIGHTS;
- cmsg->cmsg_len = CMSG_LEN(sizeof(send_fd));
- memcpy(CMSG_DATA(cmsg), &send_fd, sizeof(send_fd));
- iv.iov_base = (unsigned char *) buf;
- iv.iov_len = len;
- msg.msg_iov = &iv;
- msg.msg_iovlen = 1;
- ret = sendmsg(sock_fd, &msg, MSG_NOSIGNAL);
- if (ret < 0) {
- error("sendmsg(): sock_fd %d send_fd %d: %s",
- sock_fd, send_fd, strerror(errno));
- return ret;
- }
- return ret;
- }
- static const struct profile_info *get_profile_by_uuid(const uint8_t *uuid)
- {
- unsigned int i;
- for (i = 0; i < G_N_ELEMENTS(profiles); i++) {
- if (!memcmp(profiles[i].uuid, uuid, 16))
- return &profiles[i];
- }
- return NULL;
- }
- static int try_write_all(int fd, unsigned char *buf, int len)
- {
- int sent = 0;
- while (len > 0) {
- int written;
- written = write(fd, buf, len);
- if (written < 0) {
- if (errno == EINTR || errno == EAGAIN)
- continue;
- return -1;
- }
- if (!written)
- return 0;
- len -= written; buf += written; sent += written;
- }
- return sent;
- }
- static gboolean jv_sock_client_event_cb(GIOChannel *io, GIOCondition cond,
- gpointer data)
- {
- struct rfcomm_sock *rfsock = data;
- int len, sent;
- if (cond & G_IO_HUP) {
- DBG("Socket %d hang up", g_io_channel_unix_get_fd(io));
- goto fail;
- }
- if (cond & (G_IO_ERR | G_IO_NVAL)) {
- error("Socket %d error", g_io_channel_unix_get_fd(io));
- goto fail;
- }
- len = read(rfsock->jv_sock, rfsock->buf, rfsock->buf_size);
- if (len <= 0) {
- error("read(): %s", strerror(errno));
- /* Read again */
- return TRUE;
- }
- sent = try_write_all(rfsock->bt_sock, rfsock->buf, len);
- if (sent < 0) {
- error("write(): %s", strerror(errno));
- goto fail;
- }
- return TRUE;
- fail:
- DBG("rfsock %p jv_sock %d cond %d", rfsock, rfsock->jv_sock, cond);
- connections = g_list_remove(connections, rfsock);
- cleanup_rfsock(rfsock);
- return FALSE;
- }
- static gboolean bt_sock_event_cb(GIOChannel *io, GIOCondition cond,
- gpointer data)
- {
- struct rfcomm_sock *rfsock = data;
- int len, sent;
- if (cond & G_IO_HUP) {
- DBG("Socket %d hang up", g_io_channel_unix_get_fd(io));
- goto fail;
- }
- if (cond & (G_IO_ERR | G_IO_NVAL)) {
- error("Socket %d error", g_io_channel_unix_get_fd(io));
- goto fail;
- }
- len = read(rfsock->bt_sock, rfsock->buf, rfsock->buf_size);
- if (len <= 0) {
- error("read(): %s", strerror(errno));
- /* Read again */
- return TRUE;
- }
- sent = try_write_all(rfsock->jv_sock, rfsock->buf, len);
- if (sent < 0) {
- error("write(): %s", strerror(errno));
- goto fail;
- }
- return TRUE;
- fail:
- DBG("rfsock %p bt_sock %d cond %d", rfsock, rfsock->bt_sock, cond);
- connections = g_list_remove(connections, rfsock);
- cleanup_rfsock(rfsock);
- return FALSE;
- }
- static bool sock_send_accept(struct rfcomm_sock *rfsock, bdaddr_t *bdaddr,
- int fd_accepted)
- {
- struct hal_sock_connect_signal cmd;
- int len;
- DBG("");
- cmd.size = sizeof(cmd);
- bdaddr2android(bdaddr, cmd.bdaddr);
- cmd.channel = rfsock->channel;
- cmd.status = 0;
- len = bt_sock_send_fd(rfsock->jv_sock, &cmd, sizeof(cmd), fd_accepted);
- if (len != sizeof(cmd)) {
- error("Error sending accept signal");
- return false;
- }
- return true;
- }
- static gboolean jv_sock_server_event_cb(GIOChannel *io, GIOCondition cond,
- gpointer data)
- {
- struct rfcomm_sock *rfsock = data;
- DBG("rfsock %p jv_sock %d cond %d", rfsock, rfsock->jv_sock, cond);
- if (cond & G_IO_NVAL)
- return FALSE;
- if (cond & (G_IO_ERR | G_IO_HUP)) {
- servers[rfsock->channel].rfsock = NULL;
- cleanup_rfsock(rfsock);
- }
- return FALSE;
- }
- static void accept_cb(GIOChannel *io, GError *err, gpointer user_data)
- {
- struct rfcomm_sock *rfsock = user_data;
- struct rfcomm_sock *new_rfsock;
- GIOChannel *jv_io;
- GError *gerr = NULL;
- bdaddr_t dst;
- char address[18];
- int new_sock;
- int hal_sock;
- guint id;
- GIOCondition cond;
- if (err) {
- error("%s", err->message);
- return;
- }
- bt_io_get(io, &gerr,
- BT_IO_OPT_DEST_BDADDR, &dst,
- BT_IO_OPT_INVALID);
- if (gerr) {
- error("%s", gerr->message);
- g_error_free(gerr);
- g_io_channel_shutdown(io, TRUE, NULL);
- return;
- }
- ba2str(&dst, address);
- DBG("Incoming connection from %s on channel %d (rfsock %p)", address,
- rfsock->channel, rfsock);
- new_sock = g_io_channel_unix_get_fd(io);
- new_rfsock = create_rfsock(new_sock, &hal_sock);
- if (!new_rfsock) {
- g_io_channel_shutdown(io, TRUE, NULL);
- return;
- }
- DBG("new rfsock %p bt_sock %d jv_sock %d hal_sock %d", new_rfsock,
- new_rfsock->bt_sock, new_rfsock->jv_sock, hal_sock);
- if (!sock_send_accept(rfsock, &dst, hal_sock)) {
- cleanup_rfsock(new_rfsock);
- return;
- }
- connections = g_list_append(connections, new_rfsock);
- /* Handle events from Android */
- cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
- jv_io = g_io_channel_unix_new(new_rfsock->jv_sock);
- id = g_io_add_watch(jv_io, cond, jv_sock_client_event_cb, new_rfsock);
- g_io_channel_unref(jv_io);
- new_rfsock->jv_watch = id;
- /* Handle rfcomm events */
- cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
- id = g_io_add_watch(io, cond, bt_sock_event_cb, new_rfsock);
- g_io_channel_set_close_on_unref(io, FALSE);
- new_rfsock->bt_watch = id;
- }
- static int find_free_channel(void)
- {
- int ch;
- /* channel 0 is reserver so we don't use it */
- for (ch = 1; ch <= RFCOMM_CHANNEL_MAX; ch++) {
- struct rfcomm_channel *srv = &servers[ch];
- if (!srv->reserved && srv->rfsock == NULL)
- return ch;
- }
- return 0;
- }
- static BtIOSecLevel get_sec_level(uint8_t flags)
- {
- /*
- * HAL_SOCK_FLAG_AUTH should require MITM but in our case setting
- * security to BT_IO_SEC_HIGH would also require 16-digits PIN code
- * for pre-2.1 devices which is not what Android expects. For this
- * reason we ignore this flag to not break apps which use "secure"
- * sockets (have both auth and encrypt flags set, there is no public
- * API in Android which should provide proper high security socket).
- */
- return flags & HAL_SOCK_FLAG_ENCRYPT ? BT_IO_SEC_MEDIUM :
- BT_IO_SEC_LOW;
- }
- static uint8_t rfcomm_listen(int chan, const uint8_t *name, const uint8_t *uuid,
- uint8_t flags, int *hal_sock)
- {
- const struct profile_info *profile;
- struct rfcomm_sock *rfsock = NULL;
- BtIOSecLevel sec_level;
- GIOChannel *io, *jv_io;
- GIOCondition cond;
- GError *err = NULL;
- guint id;
- uuid_t uu;
- char uuid_str[32];
- sdp_uuid128_create(&uu, uuid);
- sdp_uuid2strn(&uu, uuid_str, sizeof(uuid_str));
- DBG("chan %d flags 0x%02x uuid %s name %s", chan, flags, uuid_str,
- name);
- if ((!memcmp(uuid, zero_uuid, sizeof(zero_uuid)) && chan <= 0) ||
- (chan > RFCOMM_CHANNEL_MAX)) {
- error("Invalid rfcomm listen params");
- return HAL_STATUS_INVALID;
- }
- profile = get_profile_by_uuid(uuid);
- if (!profile) {
- sec_level = get_sec_level(flags);
- } else {
- if (!profile->create_record)
- return HAL_STATUS_INVALID;
- chan = profile->channel;
- sec_level = profile->sec_level;
- }
- if (chan <= 0)
- chan = find_free_channel();
- if (!chan) {
- error("No free channels");
- return HAL_STATUS_BUSY;
- }
- if (servers[chan].rfsock != NULL) {
- error("Channel already registered (%d)", chan);
- return HAL_STATUS_BUSY;
- }
- DBG("chan %d sec_level %d", chan, sec_level);
- rfsock = create_rfsock(-1, hal_sock);
- if (!rfsock)
- return HAL_STATUS_FAILED;
- rfsock->channel = chan;
- io = bt_io_listen(accept_cb, NULL, rfsock, NULL, &err,
- BT_IO_OPT_SOURCE_BDADDR, &adapter_addr,
- BT_IO_OPT_CHANNEL, chan,
- BT_IO_OPT_SEC_LEVEL, sec_level,
- BT_IO_OPT_INVALID);
- if (!io) {
- error("Failed listen: %s", err->message);
- g_error_free(err);
- goto failed;
- }
- rfsock->bt_sock = g_io_channel_unix_get_fd(io);
- g_io_channel_set_close_on_unref(io, FALSE);
- g_io_channel_unref(io);
- /* Handle events from Android */
- cond = G_IO_HUP | G_IO_ERR | G_IO_NVAL;
- jv_io = g_io_channel_unix_new(rfsock->jv_sock);
- id = g_io_add_watch_full(jv_io, G_PRIORITY_HIGH, cond,
- jv_sock_server_event_cb, rfsock,
- NULL);
- g_io_channel_unref(jv_io);
- rfsock->jv_watch = id;
- DBG("rfsock %p bt_sock %d jv_sock %d hal_sock %d", rfsock,
- rfsock->bt_sock,
- rfsock->jv_sock,
- *hal_sock);
- if (write(rfsock->jv_sock, &chan, sizeof(chan)) != sizeof(chan)) {
- error("Error sending RFCOMM channel");
- goto failed;
- }
- rfsock->service_handle = sdp_service_register(chan, uuid, profile,
- name);
- servers[chan].rfsock = rfsock;
- return HAL_STATUS_SUCCESS;
- failed:
- cleanup_rfsock(rfsock);
- close(*hal_sock);
- return HAL_STATUS_FAILED;
- }
- static uint32_t add_test_record(uuid_t *uuid)
- {
- sdp_record_t *record;
- sdp_list_t *svclass_id;
- sdp_list_t *seq, *pbg_seq, *proto_seq, *ap_seq;
- sdp_list_t *proto, *proto1, *aproto;
- uuid_t l2cap_uuid, pbg_uuid, ap_uuid;
- record = sdp_record_alloc();
- if (!record)
- return 0;
- record->handle = sdp_next_handle();
- svclass_id = sdp_list_append(NULL, uuid);
- sdp_set_service_classes(record, svclass_id);
- sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
- proto = sdp_list_append(NULL, &l2cap_uuid);
- seq = sdp_list_append(NULL, proto);
- proto_seq = sdp_list_append(NULL, seq);
- sdp_set_access_protos(record, proto_seq);
- sdp_uuid16_create(&pbg_uuid, PUBLIC_BROWSE_GROUP);
- pbg_seq = sdp_list_append(NULL, &pbg_uuid);
- sdp_set_browse_groups(record, pbg_seq);
- /* Additional Protocol Descriptor List */
- sdp_uuid16_create(&ap_uuid, L2CAP_UUID);
- proto1 = sdp_list_append(NULL, &ap_uuid);
- ap_seq = sdp_list_append(NULL, proto1);
- aproto = sdp_list_append(NULL, ap_seq);
- sdp_set_add_access_protos(record, aproto);
- sdp_set_service_id(record, *uuid);
- sdp_set_record_state(record, 0);
- sdp_set_service_ttl(record, 0);
- sdp_set_service_avail(record, 0);
- sdp_set_url_attr(record, "http://www.bluez.org",
- "http://www.bluez.org", "http://www.bluez.org");
- sdp_list_free(proto, NULL);
- sdp_list_free(seq, NULL);
- sdp_list_free(proto_seq, NULL);
- sdp_list_free(pbg_seq, NULL);
- sdp_list_free(svclass_id, NULL);
- if (bt_adapter_add_record(record, 0) < 0) {
- sdp_record_free(record);
- return 0;
- }
- return record->handle;
- }
- static void test_sdp_cleanup(void)
- {
- if (test_sdp_record_uuid16) {
- bt_adapter_remove_record(test_sdp_record_uuid16);
- test_sdp_record_uuid16 = 0;
- }
- if (test_sdp_record_uuid32) {
- bt_adapter_remove_record(test_sdp_record_uuid32);
- test_sdp_record_uuid32 = 0;
- }
- if (test_sdp_record_uuid128) {
- bt_adapter_remove_record(test_sdp_record_uuid128);
- test_sdp_record_uuid128 = 0;
- }
- }
- static void test_sdp_init(void)
- {
- char uuid128[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
- uuid_t u;
- sdp_uuid16_create(&u, 0xffff);
- test_sdp_record_uuid16 = add_test_record(&u);
- sdp_uuid32_create(&u, 0xffffffff);
- test_sdp_record_uuid32 = add_test_record(&u);
- sdp_uuid128_create(&u, uuid128);
- test_sdp_record_uuid128 = add_test_record(&u);
- }
- static uint8_t l2cap_listen(int chan, const uint8_t *name, const uint8_t *uuid,
- uint8_t flags, int *hal_sock)
- {
- /* TODO be more strict here? */
- if (strcmp("BlueZ", (const char *) name)) {
- error("socket: Only SDP test supported on L2CAP");
- return HAL_STATUS_UNSUPPORTED;
- }
- test_sdp_cleanup();
- test_sdp_init();
- *hal_sock = -1;
- return HAL_STATUS_SUCCESS;
- }
- static void handle_listen(const void *buf, uint16_t len)
- {
- const struct hal_cmd_socket_listen *cmd = buf;
- uint8_t status;
- int hal_sock;
- switch (cmd->type) {
- case HAL_SOCK_RFCOMM:
- status = rfcomm_listen(cmd->channel, cmd->name, cmd->uuid,
- cmd->flags, &hal_sock);
- break;
- case HAL_SOCK_L2CAP:
- status = l2cap_listen(cmd->channel, cmd->name, cmd->uuid,
- cmd->flags, &hal_sock);
- break;
- case HAL_SOCK_SCO:
- status = HAL_STATUS_UNSUPPORTED;
- break;
- default:
- status = HAL_STATUS_INVALID;
- break;
- }
- if (status != HAL_STATUS_SUCCESS)
- goto failed;
- ipc_send_rsp_full(hal_ipc, HAL_SERVICE_ID_SOCKET, HAL_OP_SOCKET_LISTEN,
- 0, NULL, hal_sock);
- close(hal_sock);
- return;
- failed:
- ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_SOCKET, HAL_OP_SOCKET_LISTEN,
- status);
- }
- static bool sock_send_connect(struct rfcomm_sock *rfsock, bdaddr_t *bdaddr)
- {
- struct hal_sock_connect_signal cmd;
- int len;
- DBG("");
- memset(&cmd, 0, sizeof(cmd));
- cmd.size = sizeof(cmd);
- bdaddr2android(bdaddr, cmd.bdaddr);
- cmd.channel = rfsock->channel;
- cmd.status = 0;
- len = write(rfsock->jv_sock, &cmd, sizeof(cmd));
- if (len < 0) {
- error("%s", strerror(errno));
- return false;
- }
- if (len != sizeof(cmd)) {
- error("Error sending connect signal");
- return false;
- }
- return true;
- }
- static void connect_cb(GIOChannel *io, GError *err, gpointer user_data)
- {
- struct rfcomm_sock *rfsock = user_data;
- bdaddr_t *dst = &rfsock->dst;
- GIOChannel *jv_io;
- char address[18];
- guint id;
- GIOCondition cond;
- if (err) {
- error("%s", err->message);
- goto fail;
- }
- ba2str(dst, address);
- DBG("Connected to %s on channel %d (rfsock %p)", address,
- rfsock->channel, rfsock);
- if (!sock_send_connect(rfsock, dst))
- goto fail;
- /* Handle events from Android */
- cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
- jv_io = g_io_channel_unix_new(rfsock->jv_sock);
- id = g_io_add_watch(jv_io, cond, jv_sock_client_event_cb, rfsock);
- g_io_channel_unref(jv_io);
- rfsock->jv_watch = id;
- /* Handle rfcomm events */
- cond = G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL;
- id = g_io_add_watch(io, cond, bt_sock_event_cb, rfsock);
- g_io_channel_set_close_on_unref(io, FALSE);
- rfsock->bt_watch = id;
- return;
- fail:
- connections = g_list_remove(connections, rfsock);
- cleanup_rfsock(rfsock);
- }
- static bool do_rfcomm_connect(struct rfcomm_sock *rfsock, int chan)
- {
- GIOChannel *io;
- GError *gerr = NULL;
- DBG("rfsock %p sec_level %d chan %d", rfsock, rfsock->sec_level, chan);
- io = bt_io_connect(connect_cb, rfsock, NULL, &gerr,
- BT_IO_OPT_SOURCE_BDADDR, &adapter_addr,
- BT_IO_OPT_DEST_BDADDR, &rfsock->dst,
- BT_IO_OPT_CHANNEL, chan,
- BT_IO_OPT_SEC_LEVEL, rfsock->sec_level,
- BT_IO_OPT_INVALID);
- if (!io) {
- error("Failed connect: %s", gerr->message);
- g_error_free(gerr);
- return false;
- }
- g_io_channel_set_close_on_unref(io, FALSE);
- g_io_channel_unref(io);
- if (write(rfsock->jv_sock, &chan, sizeof(chan)) != sizeof(chan)) {
- error("Error sending RFCOMM channel");
- return false;
- }
- rfsock->bt_sock = g_io_channel_unix_get_fd(io);
- rfsock_set_buffer(rfsock);
- rfsock->channel = chan;
- connections = g_list_append(connections, rfsock);
- return true;
- }
- static void sdp_search_cb(sdp_list_t *recs, int err, gpointer data)
- {
- struct rfcomm_sock *rfsock = data;
- sdp_list_t *list;
- int chan;
- DBG("");
- if (err < 0) {
- error("Unable to get SDP record: %s", strerror(-err));
- goto fail;
- }
- if (!recs || !recs->data) {
- error("No SDP records found");
- goto fail;
- }
- for (list = recs; list != NULL; list = list->next) {
- sdp_record_t *rec = list->data;
- sdp_list_t *protos;
- if (sdp_get_access_protos(rec, &protos) < 0) {
- error("Unable to get proto list");
- goto fail;
- }
- chan = sdp_get_proto_port(protos, RFCOMM_UUID);
- sdp_list_foreach(protos, (sdp_list_func_t) sdp_list_free,
- NULL);
- sdp_list_free(protos, NULL);
- if (chan)
- break;
- }
- if (chan <= 0) {
- error("Could not get RFCOMM channel %d", chan);
- goto fail;
- }
- DBG("Got RFCOMM channel %d", chan);
- if (do_rfcomm_connect(rfsock, chan))
- return;
- fail:
- cleanup_rfsock(rfsock);
- }
- static uint8_t connect_rfcomm(const bdaddr_t *addr, int chan,
- const uint8_t *uuid, uint8_t flags,
- int *hal_sock)
- {
- struct rfcomm_sock *rfsock;
- char address[18];
- uuid_t uu;
- char uuid_str[32];
- sdp_uuid128_create(&uu, uuid);
- sdp_uuid2strn(&uu, uuid_str, sizeof(uuid_str));
- ba2str(addr, address);
- DBG("addr %s chan %d flags 0x%02x uuid %s", address, chan, flags,
- uuid_str);
- if ((!memcmp(uuid, zero_uuid, sizeof(zero_uuid)) && chan <= 0) ||
- !bacmp(addr, BDADDR_ANY)) {
- error("Invalid rfcomm connect params");
- return HAL_STATUS_INVALID;
- }
- rfsock = create_rfsock(-1, hal_sock);
- if (!rfsock)
- return HAL_STATUS_FAILED;
- DBG("rfsock %p jv_sock %d hal_sock %d", rfsock, rfsock->jv_sock,
- *hal_sock);
- rfsock->sec_level = get_sec_level(flags);
- bacpy(&rfsock->dst, addr);
- if (!memcmp(uuid, zero_uuid, sizeof(zero_uuid))) {
- if (!do_rfcomm_connect(rfsock, chan))
- goto failed;
- } else {
- if (bt_search_service(&adapter_addr, &rfsock->dst, &uu,
- sdp_search_cb, rfsock, NULL, 0) < 0) {
- error("Failed to search SDP records");
- goto failed;
- }
- }
- return HAL_STATUS_SUCCESS;
- failed:
- cleanup_rfsock(rfsock);
- close(*hal_sock);
- return HAL_STATUS_FAILED;
- }
- static void handle_connect(const void *buf, uint16_t len)
- {
- const struct hal_cmd_socket_connect *cmd = buf;
- bdaddr_t bdaddr;
- uint8_t status;
- int hal_sock;
- DBG("");
- android2bdaddr(cmd->bdaddr, &bdaddr);
- switch (cmd->type) {
- case HAL_SOCK_RFCOMM:
- status = connect_rfcomm(&bdaddr, cmd->channel, cmd->uuid,
- cmd->flags, &hal_sock);
- break;
- case HAL_SOCK_SCO:
- case HAL_SOCK_L2CAP:
- status = HAL_STATUS_UNSUPPORTED;
- break;
- default:
- status = HAL_STATUS_INVALID;
- break;
- }
- if (status != HAL_STATUS_SUCCESS)
- goto failed;
- ipc_send_rsp_full(hal_ipc, HAL_SERVICE_ID_SOCKET, HAL_OP_SOCKET_CONNECT,
- 0, NULL, hal_sock);
- close(hal_sock);
- return;
- failed:
- ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_SOCKET, HAL_OP_SOCKET_CONNECT,
- status);
- }
- static const struct ipc_handler cmd_handlers[] = {
- /* HAL_OP_SOCKET_LISTEN */
- { handle_listen, false, sizeof(struct hal_cmd_socket_listen) },
- /* HAL_OP_SOCKET_CONNECT */
- { handle_connect, false, sizeof(struct hal_cmd_socket_connect) },
- };
- void bt_socket_register(struct ipc *ipc, const bdaddr_t *addr, uint8_t mode)
- {
- size_t i;
- DBG("");
- hal_mode = mode;
- /*
- * make sure channels assigned for profiles are reserved and not used
- * for app services
- */
- for (i = 0; i < G_N_ELEMENTS(profiles); i++)
- if (profiles[i].channel)
- servers[profiles[i].channel].reserved = true;
- bacpy(&adapter_addr, addr);
- hal_ipc = ipc;
- ipc_register(hal_ipc, HAL_SERVICE_ID_SOCKET, cmd_handlers,
- G_N_ELEMENTS(cmd_handlers));
- }
- void bt_socket_unregister(void)
- {
- int ch;
- DBG("");
- test_sdp_cleanup();
- g_list_free_full(connections, cleanup_rfsock);
- for (ch = 0; ch <= RFCOMM_CHANNEL_MAX; ch++)
- if (servers[ch].rfsock)
- cleanup_rfsock(servers[ch].rfsock);
- memset(servers, 0, sizeof(servers));
- ipc_unregister(hal_ipc, HAL_SERVICE_ID_SOCKET);
- hal_ipc = NULL;
- }
|