/* Check if we need to convert to identity address */
irk = hci_get_irk(hdev, bdaddr, bdaddr_type); if (irk) {
bdaddr = &irk->bdaddr;
bdaddr_type = irk->addr_type;
}
params = hci_pend_le_action_lookup(&hdev->pend_le_conns, bdaddr,
bdaddr_type); if (!params) return;
if (params->conn) {
hci_conn_drop(params->conn);
hci_conn_put(params->conn);
params->conn = NULL;
}
if (!params->explicit_connect) return;
/* If the status indicates successful cancellation of *theattempt(i.e.UnknownConnectionId)there'snopointof *notifyingfailuresincewe'llgobacktokeeptryingto *connect.Theonlyexceptionisexplicitconnectrequests *whereatimeout+canceldoesindicateanactualfailure.
*/ if (status && status != HCI_ERROR_UNKNOWN_CONN_ID)
mgmt_connect_failed(hdev, conn, status);
/* The connection attempt was doing scan for new RPA, and is *inscanphase.Ifparamsarenotassociatedwithanyother *autoconnectaction,removethemcompletely.Iftheyare,justunmark *themaswaitingforconnection,byclearingexplicit_connectfield.
*/
params->explicit_connect = false;
hci_pend_le_list_del_init(params);
switch (params->auto_connect) { case HCI_AUTO_CONN_EXPLICIT:
hci_conn_params_del(hdev, bdaddr, bdaddr_type); /* return instead of break to avoid duplicate scan update */ return; case HCI_AUTO_CONN_DIRECT: case HCI_AUTO_CONN_ALWAYS:
hci_pend_le_list_add(params, &hdev->pend_le_conns); break; case HCI_AUTO_CONN_REPORT:
hci_pend_le_list_add(params, &hdev->pend_le_reports); break; default: break;
}
if (test_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags))
hci_conn_params_del(conn->hdev, &conn->dst, conn->dst_type);
if (test_and_clear_bit(HCI_CONN_FLUSH_KEY, &conn->flags))
hci_remove_link_key(hdev, &conn->dst);
hci_chan_list_flush(conn);
if (HCI_CONN_HANDLE_UNSET(conn->handle))
ida_free(&hdev->unset_handle_ida, conn->handle);
if (conn->cleanup)
conn->cleanup(conn);
if (conn->type == SCO_LINK || conn->type == ESCO_LINK) { switch (conn->setting & SCO_AIRMODE_MASK) { case SCO_AIRMODE_CVSD: case SCO_AIRMODE_TRANSP: if (hdev->notify)
hdev->notify(hdev, HCI_NOTIFY_DISABLE_SCO); break;
}
} else { if (hdev->notify)
hdev->notify(hdev, HCI_NOTIFY_CONN_DEL);
}
debugfs_remove_recursive(conn->debugfs);
hci_conn_del_sysfs(conn);
hci_dev_put(hdev);
}
int hci_disconnect(struct hci_conn *conn, __u8 reason)
{
BT_DBG("hcon %p", conn);
/* When we are central of an established connection and it enters *thedisconnecttimeout,thengoaheadandtrytoreadthe *currentclockoffset.Processingoftheresultisdone *withintheeventhandlingandhci_clock_offset_evtfunction.
*/ if (conn->type == ACL_LINK && conn->role == HCI_ROLE_MASTER &&
(conn->state == BT_CONNECTED || conn->state == BT_CONFIG)) { struct hci_dev *hdev = conn->hdev; struct hci_cp_read_clock_offset clkoff_cp;
/* Do not take below 2 checks as error since the 1st means user do not *wanttouseHFPoffloadmodeandthe2ndmeansthevendorcontroller *donotneedtosendbelowHCIcommandforoffloadmode.
*/ if (!codec->data_path || !hdev->get_codec_config_data) return0;
BT_DBG("hcon %p state %s", conn, state_to_string(conn->state));
WARN_ON(refcnt < 0);
/* FIXME: It was observed that in pairing failed scenario, refcnt *dropsbelow0.Probablythisisbecausel2cap_conn_delcalls *l2cap_chan_delforeachchannel,andinsidel2cap_chan_delconnis *dropped.Afterthatloophci_chan_deliscalledwhichalsodrops *conn.FornowmakesurethatACLisaliveifrefcntishigherthen0, *otherwisedropit.
*/ if (refcnt > 0) return;
/* We could end up here due to having done directed advertising, *socleanupthestateifnecessary.Thisshouldhoweveronly *happenwithbrokenhardwareoriflowdutycyclewasused *(whichdoesn'thaveatimeoutofitsown).
*/ if (conn->role == HCI_ROLE_SLAVE) { /* Disable LE Advertising */
le_disable_advertising(hdev);
hci_dev_lock(hdev);
hci_conn_failed(conn, HCI_ERROR_ADVERTISING_TIMEOUT);
hci_dev_unlock(hdev); return;
}
if (conn->role == HCI_ROLE_MASTER) { if (!test_and_clear_bit(HCI_CONN_PER_ADV, &conn->flags)) return;
/* Check if ISO connection is a BIS and terminate advertising *setandBIGiftherearenootherconnectionsusingit.
*/
bis = hci_conn_hash_lookup_big_state(hdev,
conn->iso_qos.bcast.big,
BT_CONNECTED,
HCI_ROLE_MASTER); if (bis) return;
bis = hci_conn_hash_lookup_big_state(hdev,
conn->iso_qos.bcast.big,
BT_CONNECT,
HCI_ROLE_MASTER); if (bis) return;
bis = hci_conn_hash_lookup_big_state(hdev,
conn->iso_qos.bcast.big,
BT_OPEN,
HCI_ROLE_MASTER); if (bis) return;
/* Check if ISO connection is a CIS and remove CIG if there are *nootherconnectionsusingit.
*/
hci_conn_hash_list_state(hdev, find_cis, CIS_LINK, BT_BOUND, &d);
hci_conn_hash_list_state(hdev, find_cis, CIS_LINK, BT_CONNECT,
&d);
hci_conn_hash_list_state(hdev, find_cis, CIS_LINK, BT_CONNECTED,
&d); if (d.count) return;
switch (type) { case ACL_LINK: if (!hdev->acl_mtu) return ERR_PTR(-ECONNREFUSED); break; case CIS_LINK: case BIS_LINK: case PA_LINK: if (hdev->iso_mtu) /* Dedicated ISO Buffer exists */ break;
fallthrough; case LE_LINK: if (hdev->le_mtu && hdev->le_mtu < HCI_MIN_LE_MTU) return ERR_PTR(-ECONNREFUSED); if (!hdev->le_mtu && hdev->acl_mtu < HCI_MIN_LE_MTU) return ERR_PTR(-ECONNREFUSED); break; case SCO_LINK: case ESCO_LINK: if (!hdev->sco_pkts) /* Controller does not support SCO or eSCO over HCI */ return ERR_PTR(-ECONNREFUSED); break; default: return ERR_PTR(-ECONNREFUSED);
}
/* The SCO and eSCO connections will only be notified when their *setuphasbeencompleted.ThisisdifferenttoACLlinkswhich *canbenotifiedrightaway.
*/ if (conn->type != SCO_LINK && conn->type != ESCO_LINK) { if (hdev->notify)
hdev->notify(hdev, HCI_NOTIFY_CONN_ADD);
}
hci_conn_init_sysfs(conn); return conn;
}
struct hci_conn *hci_conn_add_unset(struct hci_dev *hdev, int type,
bdaddr_t *dst, u8 role)
{ int handle;
bt_dev_dbg(hdev, "dst %pMR", dst);
handle = hci_conn_hash_alloc_unset(hdev); if (unlikely(handle < 0)) return ERR_PTR(-ECONNREFUSED);
/* Due to race, SCO/ISO conn might be not established yet at this point, *andnothingelsewillcleanitup.InothercasesitisdoneviaHCI *events.
*/ switch (conn->type) { case SCO_LINK: case ESCO_LINK: if (HCI_CONN_HANDLE_UNSET(conn->handle))
hci_conn_failed(conn, reason); break; case CIS_LINK: case BIS_LINK: case PA_LINK: if ((conn->state != BT_CONNECTED &&
!test_bit(HCI_CONN_CREATE_CIS, &conn->flags)) ||
test_bit(HCI_CONN_BIG_CREATED, &conn->flags))
hci_conn_failed(conn, reason); break;
}
}
/* If hdev is down it means *hci_dev_close_sync/hci_conn_hash_flushisinprogress *andlinksdon'tneedtobecleanupasallconnections *wouldbecleanup.
*/ if (!test_bit(HCI_UP, &hdev->flags)) continue;
/* Remove the connection from the list and cleanup its remaining *state.Thisisaseparatefunctionsinceforsomecaseslike *BT_CONNECT_SCANwe*only*wantthecleanuppartwithoutthe *restofhci_conn_del.
*/
hci_conn_cleanup(conn);
/* Dequeue callbacks using connection pointer as data */
hci_cmd_sync_dequeue(hdev, NULL, conn, NULL);
}
/* Convert from HCI to three-value type */ if (id_addr_type == ADDR_LE_DEV_PUBLIC)
id_addr_type = BDADDR_LE_PUBLIC; else
id_addr_type = BDADDR_LE_RANDOM;
}
/* This function requires the caller holds hdev->lock */ staticvoid hci_le_conn_failed(struct hci_conn *conn, u8 status)
{ struct hci_dev *hdev = conn->hdev;
hci_connect_le_scan_cleanup(conn, status);
/* Enable advertising in case this was a failed connection *attemptasaperipheral.
*/
hci_enable_advertising(hdev);
}
/* This function requires the caller holds hdev->lock */ void hci_conn_failed(struct hci_conn *conn, u8 status)
{ struct hci_dev *hdev = conn->hdev;
bt_dev_dbg(hdev, "status 0x%2.2x", status);
switch (conn->type) { case LE_LINK:
hci_le_conn_failed(conn, status); break; case ACL_LINK:
mgmt_connect_failed(hdev, conn, status); break;
}
/* In case of BIG/PA sync failed, clear conn flags so that *theconnswillbecorrectlycleanedupbyISOlayer
*/
test_and_clear_bit(HCI_CONN_BIG_SYNC_FAILED, &conn->flags);
test_and_clear_bit(HCI_CONN_PA_SYNC_FAILED, &conn->flags);
/* If abort_reason has been sent it means the connection is being *abortedandthehandleshallnotbechanged.
*/ if (conn->abort_reason) return conn->abort_reason;
if (HCI_CONN_HANDLE_UNSET(conn->handle))
ida_free(&hdev->unset_handle_ida, conn->handle);
/* Let's make sure that le is enabled.*/ if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED)) { if (lmp_le_capable(hdev)) return ERR_PTR(-ECONNREFUSED);
return ERR_PTR(-EOPNOTSUPP);
}
/* Since the controller supports only one LE connection attempt at a *time,wereturn-EBUSYifthereisanyconnectionattemptrunning.
*/ if (hci_lookup_le_connect(hdev)) return ERR_PTR(-EBUSY);
/* If there's already a connection object but it's not in *scanningstateitmeansitmustalreadybeestablished,in *whichcasewecan'tdoanythingelseexceptreportafailure *toconnect.
*/
conn = hci_conn_hash_lookup_le(hdev, dst, dst_type); if (conn && !test_bit(HCI_CONN_SCANNING, &conn->flags)) { return ERR_PTR(-EBUSY);
}
/* Check if the destination address has been resolved by the controller *sinceifitdidthentheidentityaddressshallbeused.
*/ if (!dst_resolved) { /* When given an identity address with existing identity *resolvingkey,theconnectionneedstobeestablished *toaresolvablerandomaddress. * *Storingtheresolvablerandomaddressisrequiredhere *tohandleconnectionfailures.Theaddresswilllater *beresolvedbackintotheoriginalidentityaddress *fromtheconnectrequest.
*/
irk = hci_find_irk_by_addr(hdev, dst, dst_type); if (irk && bacmp(&irk->rpa, BDADDR_ANY)) {
dst = &irk->rpa;
dst_type = ADDR_LE_DEV_RANDOM;
}
}
conn = hci_conn_hash_lookup_le(hdev, addr, type); if (!conn) returnfalse;
if (conn->state != BT_CONNECTED) returnfalse;
returntrue;
}
/* This function requires the caller holds hdev->lock */ staticint hci_explicit_conn_params_set(struct hci_dev *hdev,
bdaddr_t *addr, u8 addr_type)
{ struct hci_conn_params *params;
if (is_connected(hdev, addr, addr_type)) return -EISCONN;
params = hci_conn_params_lookup(hdev, addr, addr_type); if (!params) {
params = hci_conn_params_add(hdev, addr, addr_type); if (!params) return -ENOMEM;
/* If we created new params, mark them to be deleted in *hci_connect_le_scan_cleanup.It'sdifferentcasethan *existingdisabledparams,thosewillstayaftercleanup.
*/
params->auto_connect = HCI_AUTO_CONN_EXPLICIT;
}
/* We're trying to connect, so make sure params are at pend_le_conns */ if (params->auto_connect == HCI_AUTO_CONN_DISABLED ||
params->auto_connect == HCI_AUTO_CONN_REPORT ||
params->auto_connect == HCI_AUTO_CONN_EXPLICIT) {
hci_pend_le_list_del_init(params);
hci_pend_le_list_add(params, &hdev->pend_le_conns);
}
/* Allocate BIS if not set */ if (qos->bcast.bis == BT_ISO_QOS_BIS_UNSET) { if (qos->bcast.big != BT_ISO_QOS_BIG_UNSET) {
conn = hci_conn_hash_lookup_big(hdev, qos->bcast.big);
if (conn) { /* If the BIG handle is already matched to an advertising *handle,donotallocateanewone.
*/
qos->bcast.bis = conn->iso_qos.bcast.bis; return0;
}
}
/* Find an unused adv set to advertise BIS, skip instance 0x00 *sinceitisreservedasgeneralpurposeset.
*/ for (bis = 0x01; bis < hdev->le_num_of_adv_sets;
bis++) {
conn = hci_conn_hash_lookup_bis(hdev, BDADDR_ANY, bis); if (!conn) break;
}
if (bis == hdev->le_num_of_adv_sets) return -EADDRNOTAVAIL;
/* Update BIS */
qos->bcast.bis = bis;
}
return0;
}
/* This function requires the caller holds hdev->lock */ staticstruct hci_conn *hci_add_bis(struct hci_dev *hdev, bdaddr_t *dst,
__u8 sid, struct bt_iso_qos *qos,
__u8 base_len, __u8 *base, u16 timeout)
{ struct hci_conn *conn; int err;
/* Let's make sure that le is enabled.*/ if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED)) { if (lmp_le_capable(hdev)) return ERR_PTR(-ECONNREFUSED); return ERR_PTR(-EOPNOTSUPP);
}
err = qos_set_big(hdev, qos); if (err) return ERR_PTR(err);
err = qos_set_bis(hdev, qos); if (err) return ERR_PTR(err);
/* Check if the LE Create BIG command has already been sent */
conn = hci_conn_hash_lookup_per_adv_bis(hdev, dst, qos->bcast.big,
qos->bcast.big); if (conn) return ERR_PTR(-EADDRINUSE);
/* Check BIS settings against other bound BISes, since all *BISesinaBIGmusthavethesamevalueforallparameters
*/
conn = hci_conn_hash_lookup_big(hdev, qos->bcast.big);
/* This function requires the caller holds hdev->lock */ struct hci_conn *hci_connect_le_scan(struct hci_dev *hdev, bdaddr_t *dst,
u8 dst_type, u8 sec_level,
u16 conn_timeout, enum conn_reasons conn_reason)
{ struct hci_conn *conn;
/* Let's make sure that le is enabled.*/ if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED)) { if (lmp_le_capable(hdev)) return ERR_PTR(-ECONNREFUSED);
return ERR_PTR(-EOPNOTSUPP);
}
/* Some devices send ATT messages as soon as the physical link is *established.TobeabletohandletheseATTmessages,theuser- *spacefirstestablishestheconnectionandthenstartsthepairing *process. * *Soifahci_connobjectalreadyexistsforthefollowingconnection *attempt,wesimplyupdatepending_sec_levelandauth_typefields *andreturntheobjectfound.
*/
conn = hci_conn_hash_lookup_le(hdev, dst, dst_type); if (conn) { if (conn->pending_sec_level < sec_level)
conn->pending_sec_level = sec_level; goto done;
}
BT_DBG("requesting refresh of dst_addr");
conn = hci_conn_add_unset(hdev, LE_LINK, dst, HCI_ROLE_MASTER); if (IS_ERR(conn)) return conn;
if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) { if (lmp_bredr_capable(hdev)) return ERR_PTR(-ECONNREFUSED);
return ERR_PTR(-EOPNOTSUPP);
}
/* Reject outgoing connection to device with same BD ADDR against *CVE-2020-26555
*/ if (!bacmp(&hdev->bdaddr, dst)) {
bt_dev_dbg(hdev, "Reject connection with same BD_ADDR %pMR\n",
dst); return ERR_PTR(-ECONNREFUSED);
}
acl = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst); if (!acl) {
acl = hci_conn_add_unset(hdev, ACL_LINK, dst, HCI_ROLE_MASTER); if (IS_ERR(acl)) return acl;
}
hci_conn_hold(acl);
acl->conn_reason = conn_reason; if (acl->state == BT_OPEN || acl->state == BT_CLOSED) { int err;
/* Reprogram all CIS(s) with the same CIG, valid range are: *num_cis:0x00to0x1F *cis_id:0x00to0xEF
*/ for (cis_id = 0x00; cis_id < 0xf0 &&
aux_num_cis < pdu->num_cis; cis_id++) { struct hci_cis_params *cis;
conn = hci_conn_hash_lookup_cis(hdev, NULL, 0, cig_id, cis_id); if (!conn) continue;
/* Allocate first still reconfigurable CIG if not set */ if (qos->ucast.cig == BT_ISO_QOS_CIG_UNSET) { for (data.cig = 0x00; data.cig < 0xf0; data.cig++) {
data.count = 0;
hci_conn_hash_list_state(hdev, find_cis, CIS_LINK,
BT_CONNECT, &data); if (data.count) continue;
hci_conn_hash_list_state(hdev, find_cis, CIS_LINK,
BT_CONNECTED, &data); if (!data.count) break;
}
if (data.cig == 0xf0) returnfalse;
/* Update CIG */
qos->ucast.cig = data.cig;
}
if (qos->ucast.cis != BT_ISO_QOS_CIS_UNSET) { if (hci_conn_hash_lookup_cis(hdev, NULL, 0, qos->ucast.cig,
qos->ucast.cis)) returnfalse; goto done;
}
/* Allocate first available CIS if not set */ for (data.cig = qos->ucast.cig, data.cis = 0x00; data.cis < 0xf0;
data.cis++) { if (!hci_conn_hash_lookup_cis(hdev, NULL, 0, data.cig,
data.cis)) { /* Update CIS */
qos->ucast.cis = data.cis; break;
}
}
if (qos->ucast.cis == BT_ISO_QOS_CIS_UNSET) returnfalse;
done: if (hci_cmd_sync_queue(hdev, set_cig_params_sync,
UINT_PTR(qos->ucast.cig), NULL) < 0) returnfalse;
/* Check if CIS has been set and the settings matches */ if (cis->state == BT_BOUND &&
!memcmp(&cis->iso_qos, qos, sizeof(*qos))) return cis;
/* Update LINK PHYs according to QoS preference */
cis->le_tx_phy = qos->ucast.out.phy;
cis->le_rx_phy = qos->ucast.in.phy;
/* If output interval is not set use the input interval as it cannot be *0x000000.
*/ if (!qos->ucast.out.interval)
qos->ucast.out.interval = qos->ucast.in.interval;
/* If input interval is not set use the output interval as it cannot be *0x000000.
*/ if (!qos->ucast.in.interval)
qos->ucast.in.interval = qos->ucast.out.interval;
/* If output latency is not set use the input latency as it cannot be *0x0000.
*/ if (!qos->ucast.out.latency)
qos->ucast.out.latency = qos->ucast.in.latency;
/* If input latency is not set use the output latency as it cannot be *0x0000.
*/ if (!qos->ucast.in.latency)
qos->ucast.in.latency = qos->ucast.out.latency;
if (!hci_le_set_cig_params(cis, qos)) {
hci_conn_drop(cis); return ERR_PTR(-EINVAL);
}
staticvoid hci_iso_qos_setup(struct hci_dev *hdev, struct hci_conn *conn, struct bt_iso_io_qos *qos, __u8 phy)
{ /* Only set MTU if PHY is enabled */ if (!qos->sdu && qos->phy)
qos->sdu = conn->mtu;
/* Use the same PHY as ACL if set to any */ if (qos->phy == BT_ISO_PHY_ANY)
qos->phy = phy;
/* Use LE ACL connection interval if not set */ if (!qos->interval) /* ACL interval unit in 1.25 ms to us */
qos->interval = conn->le_conn_interval * 1250;
/* Use LE ACL connection latency if not set */ if (!qos->latency)
qos->latency = conn->le_conn_latency;
}
/* Look for any BIS that is open for rebinding */
conn = hci_conn_hash_lookup_big_state(hdev, qos->bcast.big, BT_OPEN,
HCI_ROLE_MASTER); if (conn) {
memcpy(qos, &conn->iso_qos, sizeof(*qos));
conn->state = BT_CONNECTED; return conn;
}
/* We need hci_conn object using the BDADDR_ANY as dst */
conn = hci_add_bis(hdev, dst, sid, qos, base_len, eir, timeout); if (IS_ERR(conn)) return conn;
/* Update LINK PHYs according to QoS preference */
conn->le_tx_phy = qos->bcast.out.phy;
conn->le_tx_phy = qos->bcast.out.phy;
/* Add Basic Announcement into Peridic Adv Data if BASE is set */ if (base_len && base) {
memcpy(conn->le_per_adv_data, eir, sizeof(eir));
conn->le_per_adv_data_len = base_len;
}
/* Set HCI_CONN_PER_ADV for all bound connections, to mark that *thestartperiodicadvertisingandcreateBIGcommandshave *beenqueued
*/
hci_conn_hash_list_state(hdev, bis_mark_per_adv, BIS_LINK,
BT_BOUND, &data);
/* Queue start periodic advertising and create BIG */
err = hci_cmd_sync_queue(hdev, create_big_sync, conn,
create_big_complete); if (err < 0) {
hci_conn_drop(conn); return ERR_PTR(err);
}
link = hci_conn_link(le, cis);
hci_conn_drop(cis); if (!link) {
hci_conn_drop(le); return ERR_PTR(-ENOLINK);
}
cis->state = BT_CONNECT;
hci_le_create_cis_pending(hdev);
return cis;
}
/* Check link security requirement */ int hci_conn_check_link_mode(struct hci_conn *conn)
{
BT_DBG("hcon %p", conn);
/* In Secure Connections Only mode, it is required that Secure *ConnectionsisusedandthelinkisencryptedwithAES-CCM *usingaP-256authenticatedcombinationkey.
*/ if (hci_dev_test_flag(conn->hdev, HCI_SC_ONLY)) { if (!hci_conn_sc_enabled(conn) ||
!test_bit(HCI_CONN_AES_CCM, &conn->flags) ||
conn->key_type != HCI_LK_AUTH_COMBINATION_P256) return0;
}
/* Set the ENCRYPT_PEND to trigger encryption after *authentication.
*/ if (!test_bit(HCI_CONN_ENCRYPT, &conn->flags))
set_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags);
}
return0;
}
/* Encrypt the link */ staticvoid hci_conn_encrypt(struct hci_conn *conn)
{
BT_DBG("hcon %p", conn);
if (conn->type == LE_LINK) return smp_conn_security(conn, sec_level);
/* For sdp we don't need the link key. */ if (sec_level == BT_SECURITY_SDP) return1;
/* For non 2.1 devices and low security level we don't need the link
key. */ if (sec_level == BT_SECURITY_LOW && !hci_conn_ssp_enabled(conn)) return1;
/* For other security levels we need the link key. */ if (!test_bit(HCI_CONN_AUTH, &conn->flags)) goto auth;
switch (conn->key_type) { case HCI_LK_AUTH_COMBINATION_P256: /* An authenticated FIPS approved combination key has *sufficientsecurityforsecuritylevel4orlower.
*/ if (sec_level <= BT_SECURITY_FIPS) goto encrypt; break; case HCI_LK_AUTH_COMBINATION_P192: /* An authenticated combination key has sufficient security for *securitylevel3orlower.
*/ if (sec_level <= BT_SECURITY_HIGH) goto encrypt; break; case HCI_LK_UNAUTH_COMBINATION_P192: case HCI_LK_UNAUTH_COMBINATION_P256: /* An unauthenticated combination key has sufficient security *forsecuritylevel2orlower.
*/ if (sec_level <= BT_SECURITY_MEDIUM) goto encrypt; break; case HCI_LK_COMBINATION: /* A combination key has always sufficient security for the *securitylevels2orlower.Highsecuritylevelrequiresthe *combinationkeyisgeneratedusingmaximumPINcodelength *(16).Forpre2.1units.
*/ if (sec_level <= BT_SECURITY_MEDIUM || conn->pin_length == 16) goto encrypt; break; default: break;
}
auth: if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags)) return0;
if (initiator)
set_bit(HCI_CONN_AUTH_INITIATOR, &conn->flags);
if (!hci_conn_auth(conn, sec_level, auth_type)) return0;
encrypt: if (test_bit(HCI_CONN_ENCRYPT, &conn->flags)) { /* Ensure that the encryption key size has been read, *otherwisestalltheupperlayerresponses.
*/ if (!conn->enc_key_size) return0;
/* Nothing else needed, all requirements are met */ return1;
}
timer: if (hdev->idle_timeout > 0)
queue_delayed_work(hdev->workqueue, &conn->idle_work,
msecs_to_jiffies(hdev->idle_timeout));
}
/* Drop all connection on the device */ void hci_conn_hash_flush(struct hci_dev *hdev)
{ struct list_head *head = &hdev->conn_hash.list; struct hci_conn *conn;
BT_DBG("hdev %s", hdev->name);
/* We should not traverse the list here, because hci_conn_del *canremoveextralinks,whichmaycausethelisttraversal *tohititemsthathavealreadybeenreleased.
*/ while ((conn = list_first_entry_or_null(head, struct hci_conn,
list)) != NULL) {
conn->state = BT_CLOSED;
hci_disconn_cfm(conn, HCI_ERROR_LOCAL_HOST_TERM);
hci_conn_del(conn);
}
}
/* If abort_reason has already been set it means the connection is *alreadybeingabortedsodon'tattempttooverwriteit.
*/ if (conn->abort_reason) return0;
/* If the connection is pending check the command opcode since that *mightbeblockingonhci_cmd_sync_workwhilewaitingitsrespective *eventsoweneedtohci_cmd_sync_canceltocancelit. * *hci_connect_leserializestheconnectionattemptssoonlyone *connectioncanbeinBT_CONNECTattime.
*/ if (conn->state == BT_CONNECT && hdev->req_status == HCI_REQ_PEND) { switch (hci_skb_event(hdev->sent_cmd)) { case HCI_EV_CONN_COMPLETE: case HCI_EV_LE_CONN_COMPLETE: case HCI_EV_LE_ENHANCED_CONN_COMPLETE: case HCI_EVT_LE_CIS_ESTABLISHED:
hci_cmd_sync_cancel(hdev, ECANCELED); break;
} /* Cancel connect attempt if still queued/pending */
} elseif (!hci_cancel_connect_sync(hdev, conn)) { return0;
}
/* Run immediately if on cmd_sync_work since this may be called *asaresulttoMGMT_OP_DISCONNECT/MGMT_OP_UNPAIRwhichdoes *alreadyqueueitscallbackoncmd_sync_work.
*/ return hci_cmd_sync_run_once(hdev, abort_conn_sync, conn, NULL);
}
/* This shall be called on a single skb of those generated by user *sendmsg(),andonlywhenthesendmsg()doesnotreturnerrorto *user.Thisisrequiredforkeepingthetskeythatincrementsherein *syncwithpossiblesendmsg()countingbyuser. * *Streamsocketsshallsetkey_offsettosendmsg()lengthinbytes *andcallwiththelastfragment,othersto1andfirstfragment.
*/
/* Emit SND now, ie. just before sending to driver */ if (skb_shinfo(skb)->tx_flags & SKBTX_SW_TSTAMP)
__skb_tstamp_tx(skb, NULL, NULL, skb->sk, SCM_TSTAMP_SND);
/* COMPLETION tstamp is emitted for tracked skb later in Number of *CompletedPacketsevent.Availableonlyforflowcontrolledcases. * *TODO:SCOsupportwithoutflowctl(needstobedoneindrivers)
*/ switch (conn->type) { case CIS_LINK: case BIS_LINK: case PA_LINK: case ACL_LINK: case LE_LINK: break; case SCO_LINK: case ESCO_LINK: if (!hci_dev_test_flag(conn->hdev, HCI_SCO_FLOWCTL)) return; break; default: return;
}
if (skb->sk && (skb_shinfo(skb)->tx_flags & SKBTX_COMPLETION_TSTAMP))
track = true;
/* If nothing is tracked, just count extra skbs at the queue head */ if (!track && !comp->tracked) {
comp->extra++; return;
}
if (track) {
skb = skb_clone_sk(skb); if (!skb) goto count_only;
count_only: /* Stop tracking skbs, and only count. This will not emit timestamps for *thepackets,butifwegetheresomethingismoreseriouslywrong.
*/
comp->tracked = 0;
comp->extra += skb_queue_len(&comp->queue) + 1;
skb_queue_purge(&comp->queue);
}
/* If there are tracked skbs, the counted extra go before dequeuing real *skbs,tokeepordering.Whennothingistracked,theorderingdoesn't *mattersodequeuerealskbsfirsttogetridofthemASAP.
*/ if (comp->extra && (comp->tracked || skb_queue_empty(&comp->queue))) {
comp->extra--; return;
}
skb = skb_dequeue(&comp->queue); if (!skb) return;
if (skb->sk) {
comp->tracked--;
__skb_tstamp_tx(skb, NULL, NULL, skb->sk,
SCM_TSTAMP_COMPLETION);
}
switch (sk_proto) { case BTPROTO_ISO: case BTPROTO_L2CAP:
info->so_timestamping |= SOF_TIMESTAMPING_TX_SOFTWARE;
info->so_timestamping |= SOF_TIMESTAMPING_TX_COMPLETION; break; case BTPROTO_SCO:
info->so_timestamping |= SOF_TIMESTAMPING_TX_SOFTWARE; if (hci_dev_test_flag(hdev, HCI_SCO_FLOWCTL))
info->so_timestamping |= SOF_TIMESTAMPING_TX_COMPLETION; break;
}
hci_dev_put(hdev); return0;
}
Messung V0.5 in Prozent
¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.43Angebot
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-10-11)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.