From 87398b95137013cb6fa3062e10a98a2d5efe72d2 Mon Sep 17 00:00:00 2001 From: samr7 Date: Wed, 29 Oct 2008 05:51:15 +0000 Subject: Enhance reporting of RFCOMM/SCO EPROTONOSUPPORT failures. Test SCO MTUs when starting HfpService. Make hfconsole fail to start with an error if: - Bluetooth service is unavailable - Attempting to start it fails due to lack of RFCOMM/SCO support or bad SCO MTU Add a 'Version' property to net.sf.nohands.hfpd Make hfconsole fail to start if there is a version mismatch. Fix a miscellaneous bug in hfpdtext net.cpp git-svn-id: http://nohands.svn.sourceforge.net/svnroot/nohands/trunk@18 126591fb-c623-4b62-a76d-97a8e4f34109 --- libhfp/bt.cpp | 45 ++++++++++++++++++++++++++++++++++++++++----- libhfp/hfp.cpp | 44 +++++++++++++++++++++++++++++++++++++++++++- libhfp/rfcomm.cpp | 9 ++++++++- 3 files changed, 91 insertions(+), 7 deletions(-) (limited to 'libhfp') diff --git a/libhfp/bt.cpp b/libhfp/bt.cpp index 0b2c42d..3b1ee29 100644 --- a/libhfp/bt.cpp +++ b/libhfp/bt.cpp @@ -801,12 +801,46 @@ HciCancel(HciTask *taskp) } } +int HciAsyncTaskHandler:: +HciGetScoMtu(uint16_t &mtu, uint16_t &pkts) +{ + hci_dev_info di; + + if (m_hci_fh < 0) + return -ESHUTDOWN; + + di.dev_id = m_hci_id; + if (ioctl(m_hci_fh, HCIGETDEVINFO, (void *) &di) < 0) + return -errno; + + mtu = di.sco_mtu; + pkts = di.sco_pkts; + return 0; +} + +/* This only works as superuser */ +int HciAsyncTaskHandler:: +HciSetScoMtu(uint16_t mtu, uint16_t pkts) +{ + hci_dev_req dr; + + if (m_hci_fh < 0) + return -ESHUTDOWN; + + dr.dev_id = m_hci_id; + ((uint16_t *) &dr.dev_opt)[0] = htobs(mtu); + ((uint16_t *) &dr.dev_opt)[1] = htobs(pkts); + if (ioctl(m_hci_fh, HCISETSCOMTU, (void *) &dr) < 0) + return -errno; + + return 0; +} int HciAsyncTaskHandler:: HciInit(void) { struct hci_filter flt; - int did, fh; + int did, fh, err; assert(m_hci_fh == -1); assert(!m_hci_not); @@ -817,9 +851,9 @@ HciInit(void) return -ENODEV; fh = hci_open_dev(did); if (fh < 0) { - did = -errno; + err = -errno; m_ei->LogWarn("Could not open HCI: %s\n", strerror(errno)); - return did; + return err; } hci_filter_clear(&flt); @@ -831,11 +865,11 @@ HciInit(void) hci_filter_set_event(EVT_REMOTE_NAME_REQ_COMPLETE, &flt); if (setsockopt(fh, SOL_HCI, HCI_FILTER, &flt, sizeof(flt)) < 0) { - did = -errno; + err = -errno; m_ei->LogWarn("Could not set filter on HCI: %s\n", strerror(errno)); close(fh); - return did; + return err; } m_hci_not = m_ei->NewSocket(fh, false); @@ -855,6 +889,7 @@ HciInit(void) m_resubmit->Register(this, &HciAsyncTaskHandler::HciResubmit); m_hci_not->Register(this, &HciAsyncTaskHandler::HciDataReadyNot); + m_hci_id = did; m_hci_fh = fh; return 0; } diff --git a/libhfp/hfp.cpp b/libhfp/hfp.cpp index 83d2a75..d75385b 100644 --- a/libhfp/hfp.cpp +++ b/libhfp/hfp.cpp @@ -127,17 +127,59 @@ bool HfpService:: ScoListen(void) { struct sockaddr_sco saddr; - int sock = -1; + int sock = -1, res; + uint16_t mtu, pkts; assert(m_sco_listen == -1); + /* + * I'm not sure what the whole story is with this, but some + * Broadcom dongles cause the kernel to set its SCO MTU + * values to 16:0. This is unsuitable for us, we need bigger + * packets and more buffering, and we will refuse to listen + * if it is not available. + */ + res = GetHub()->HciGetScoMtu(mtu, pkts); + if (res) { + GetDi()->LogWarn("Get SCO MTU: %s\n", + strerror(-res)); + return false; + } + + if ((mtu < 48) || (pkts < 8)) { + if (GetHub()->HciSetScoMtu(64, 8) < 0) { + GetDi()->LogError("Unsuitable SCO MTU values %u:%u " + "detected\n", mtu, pkts); + GetDi()->LogError("To fix this, run, as superuser, " + "\"hciconfig hci0 scomtu 64:8\"\n"); + GetHub()->SetAutoRestart(false); + return false; + } + + mtu = 64; + pkts = 8; + } + + /* + * Somebody may have also forgotten to enable SCO support + * in the kernel, or the sco.ko module got lost. + */ sock = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO); if (sock < 0) { + sock = errno; + if (sock == EPROTONOSUPPORT) { + GetDi()->LogError("Your kernel is not configured with " + "support for SCO sockets.\n"); + GetHub()->SetAutoRestart(false); + return false; + } GetDi()->LogWarn("Create SCO socket: %s\n", strerror(errno)); return false; } + GetDi()->LogDebug("SCO MTU: %u:%u\n", mtu, pkts); + memset(&saddr, 0, sizeof(saddr)); saddr.sco_family = AF_BLUETOOTH; bacpy(&saddr.sco_bdaddr, BDADDR_ANY); diff --git a/libhfp/rfcomm.cpp b/libhfp/rfcomm.cpp index 30c7e76..8740734 100644 --- a/libhfp/rfcomm.cpp +++ b/libhfp/rfcomm.cpp @@ -164,7 +164,14 @@ RfcommListen(uint8_t channel) rsock = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM); if (rsock < 0) { - GetDi()->LogWarn("Create RFCOMM socket"); + rsock = errno; + if (rsock == EPROTONOSUPPORT) { + GetDi()->LogError("Your kernel is not configured with " + "support for RFCOMM sockets.\n"); + GetHub()->SetAutoRestart(false); + return false; + } + GetDi()->LogWarn("Create RFCOMM socket: %s", strerror(errno)); return false; } -- cgit v1.2.1