void btu_register_timer (TIMER_LIST_ENT *p_tle, UINT16 type, UINT32 timeout, tBTU_TIMER_CALLBACK timer_cb) { UINT8 i = 0; INT8 first = -1; for (; i < BTU_MAX_REG_TIMER; i++) { if (btu_cb.timer_reg[i].p_tle == NULL && first < 0) first = i; if (btu_cb.timer_reg[i].p_tle == p_tle) { btu_cb.timer_reg[i].timer_cb = timer_cb; btu_start_timer(p_tle, type, timeout); first = -1; break; } } if (first >= 0 && first < BTU_MAX_REG_TIMER) { btu_cb.timer_reg[first].timer_cb = timer_cb; btu_cb.timer_reg[first].p_tle = p_tle; btu_start_timer(p_tle, type, timeout); } }
/******************************************************************************* ** ** Function l2c_process_held_packets ** ** Description This function processes any L2CAP packets that arrived before ** the HCI connection complete arrived. It is a work around for ** badly behaved controllers. ** ** Returns void ** *******************************************************************************/ void l2c_process_held_packets (BOOLEAN timed_out) { BT_HDR *p_buf, *p_buf1; BUFFER_Q *p_rcv_hold_q = &l2cb.rcv_hold_q; if (!p_rcv_hold_q->count) return; if (!timed_out) { btu_stop_timer(&l2cb.rcv_hold_tle); L2CAP_TRACE_WARNING0("L2CAP HOLD CONTINUE"); } else { L2CAP_TRACE_WARNING0("L2CAP HOLD TIMEOUT"); } /* Update the timeouts in the hold queue */ for (p_buf = (BT_HDR *)GKI_getfirst (p_rcv_hold_q); p_buf; p_buf = p_buf1) { p_buf1 = (BT_HDR *)GKI_getnext (p_buf); if (!timed_out || (!p_buf->layer_specific) || (--p_buf->layer_specific == 0)) { GKI_remove_from_queue (p_rcv_hold_q, p_buf); p_buf->layer_specific = 0xFFFF; l2c_rcv_acl_data (p_buf); } } /* If anyone still in the queue, restart the timeout */ if (p_rcv_hold_q->count) btu_start_timer (&l2cb.rcv_hold_tle, BTU_TTYPE_L2CAP_HOLD, BT_1SEC_TIMEOUT); }
/******************************************************************************* ** ** Function l2c_process_held_packets ** ** Description This function processes any L2CAP packets that arrived before ** the HCI connection complete arrived. It is a work around for ** badly behaved controllers. ** ** Returns void ** *******************************************************************************/ void l2c_process_held_packets(BOOLEAN timed_out) { if (list_is_empty(l2cb.rcv_pending_q)) { return; } if (!timed_out) { btu_stop_timer(&l2cb.rcv_hold_tle); L2CAP_TRACE_WARNING("L2CAP HOLD CONTINUE"); } else { L2CAP_TRACE_WARNING("L2CAP HOLD TIMEOUT"); } for (const list_node_t *node = list_begin(l2cb.rcv_pending_q); node != list_end(l2cb.rcv_pending_q);) { BT_HDR *p_buf = list_node(node); node = list_next(node); if (!timed_out || (!p_buf->layer_specific) || (--p_buf->layer_specific == 0)) { list_remove(l2cb.rcv_pending_q, p_buf); p_buf->layer_specific = 0xFFFF; l2c_rcv_acl_data(p_buf); } } /* If anyone still in the queue, restart the timeout */ if (!list_is_empty(l2cb.rcv_pending_q)) { btu_start_timer (&l2cb.rcv_hold_tle, BTU_TTYPE_L2CAP_HOLD, BT_1SEC_TIMEOUT); } }
/******************************************************************************* ** ** Function avdt_ccb_ret_cmd ** ** Description This function is called to retransmit the currently ** pending command. The retransmission count is incremented. ** If the count reaches the maximum number of retransmissions, ** the event is treated as a response timeout. ** ** ** Returns void. ** *******************************************************************************/ void avdt_ccb_ret_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data) { UINT8 err_code = AVDT_ERR_TIMEOUT; BT_HDR *p_msg; p_ccb->ret_count++; if (p_ccb->ret_count == AVDT_RET_MAX) { /* command failed */ p_ccb->ret_count = 0; avdt_ccb_cmd_fail(p_ccb, (tAVDT_CCB_EVT *) &err_code); /* go to next queued command */ avdt_ccb_snd_cmd(p_ccb, p_data); } else { /* if command pending and we're not congested and not sending a fragment */ if ((!p_ccb->cong) && (p_ccb->p_curr_msg == NULL) && (p_ccb->p_curr_cmd != NULL)) { /* make copy of message in p_curr_cmd and send it */ if ((p_msg = (BT_HDR *) GKI_getpoolbuf(AVDT_CMD_POOL_ID)) != NULL) { memcpy(p_msg, p_ccb->p_curr_cmd, (sizeof(BT_HDR) + p_ccb->p_curr_cmd->offset + p_ccb->p_curr_cmd->len)); avdt_msg_send(p_ccb, p_msg); } } /* restart timer */ btu_start_timer(&p_ccb->timer_entry, BTU_TTYPE_AVDT_CCB_RET, avdt_cb.rcb.ret_tout); } }
/******************************************************************************* ** ** Function mca_ccb_snd_req ** ** Description This function builds a request and sends it to the peer. ** ** Returns void. ** *******************************************************************************/ void mca_ccb_snd_req(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data) { tMCA_CCB_MSG *p_msg = (tMCA_CCB_MSG *)p_data; BT_HDR *p_pkt; UINT8 *p, *p_start; BOOLEAN is_abort = FALSE; tMCA_DCB *p_dcb; MCA_TRACE_DEBUG ("mca_ccb_snd_req cong=%d req=%d", p_ccb->cong, p_msg->op_code); /* check for abort request */ if ((p_ccb->status == MCA_CCB_STAT_PENDING) && (p_msg->op_code == MCA_OP_MDL_ABORT_REQ)) { p_dcb = mca_dcb_by_hdl(p_ccb->p_tx_req->dcb_idx); /* the Abort API does not have the associated mdl_id. * Get the mdl_id in dcb to compose the request */ if (p_dcb) { p_msg->mdl_id = p_dcb->mdl_id; mca_dcb_event(p_dcb, MCA_DCB_API_CLOSE_EVT, NULL); } mca_free_buf ((void **)&p_ccb->p_tx_req); p_ccb->status = MCA_CCB_STAT_NORM; is_abort = TRUE; } /* no pending outgoing messages or it's an abort request for a pending data channel */ if ((!p_ccb->p_tx_req) || is_abort) { p_ccb->p_tx_req = p_msg; if (!p_ccb->cong) { p_pkt = (BT_HDR *)GKI_getbuf (MCA_CTRL_MTU); if (p_pkt) { p_pkt->offset = L2CAP_MIN_OFFSET; p = p_start = (UINT8*)(p_pkt + 1) + L2CAP_MIN_OFFSET; *p++ = p_msg->op_code; UINT16_TO_BE_STREAM (p, p_msg->mdl_id); if (p_msg->op_code == MCA_OP_MDL_CREATE_REQ) { *p++ = p_msg->mdep_id; *p++ = p_msg->param; } p_msg->hdr.layer_specific = TRUE; /* mark this message as sent */ p_pkt->len = p - p_start; L2CA_DataWrite (p_ccb->lcid, p_pkt); p_ccb->timer_entry.param = (TIMER_PARAM_TYPE) p_ccb; btu_start_timer(&p_ccb->timer_entry, BTU_TTYPE_MCA_CCB_RSP, p_ccb->p_rcb->reg.rsp_tout); } } /* else the L2CAP channel is congested. keep the message to be sent later */ } else { MCA_TRACE_WARNING ("dropping api req"); GKI_freebuf (p_data); } }
/******************************************************************************* ** ** Function rfc_port_timer_start ** ** Description Start RFC Timer ** *******************************************************************************/ void rfc_port_timer_start (tPORT *p_port, UINT16 timeout) { TIMER_LIST_ENT *p_tle = &p_port->rfc.tle; RFCOMM_TRACE_EVENT ("rfc_port_timer_start - timeout:%d", timeout); p_tle->param = (UINT32)p_port; btu_start_timer (p_tle, BTU_TTYPE_RFCOMM_PORT, timeout); }
/******************************************************************************* ** ** Function rfc_timer_start ** ** Description Start RFC Timer ** *******************************************************************************/ void rfc_timer_start (tRFC_MCB *p_mcb, UINT16 timeout) { TIMER_LIST_ENT *p_tle = &p_mcb->tle; RFCOMM_TRACE_EVENT ("rfc_timer_start - timeout:%d", timeout); p_tle->param = (UINT32)p_mcb; btu_start_timer (p_tle, BTU_TTYPE_RFCOMM_MFC, timeout); }
/******************************************************************************* ** ** Function BNEP_Init ** ** Description This function initializes the BNEP unit. It should be called ** before accessing any other APIs to initialize the control block ** ** Returns void ** *******************************************************************************/ void BNEP_Init (void) { memset (&bnep_cb, 0, sizeof (tBNEP_CB)); #if defined(BNEP_INITIAL_TRACE_LEVEL) bnep_cb.trace_level = BNEP_INITIAL_TRACE_LEVEL; #else bnep_cb.trace_level = BT_TRACE_LEVEL_NONE; /* No traces */ #endif /* Start a timer to read our BD address */ btu_start_timer (&bnep_cb.bnep_tle, BTU_TTYPE_BNEP, 2); }
/******************************************************************************* ** ** Function l2cble_init_direct_conn ** ** Description This function is to initate a direct connection ** ** Returns TRUE connection initiated, FALSE otherwise. ** *******************************************************************************/ BOOLEAN l2cble_init_direct_conn (tL2C_LCB *p_lcb) { tBTM_SEC_DEV_REC *p_dev_rec = btm_find_or_alloc_dev (p_lcb->remote_bd_addr); tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb; UINT16 scan_int, scan_win; BD_ADDR init_addr; UINT8 init_addr_type = BLE_ADDR_PUBLIC, own_addr_type = BLE_ADDR_PUBLIC; /* There can be only one BLE connection request outstanding at a time */ if (p_dev_rec == NULL) { BTM_TRACE_WARNING0 ("unknown device, can not initate connection"); return(FALSE); } scan_int = (p_cb->scan_int == BTM_BLE_CONN_PARAM_UNDEF) ? BTM_BLE_SCAN_FAST_INT : p_cb->scan_int; scan_win = (p_cb->scan_win == BTM_BLE_CONN_PARAM_UNDEF) ? BTM_BLE_SCAN_FAST_WIN : p_cb->scan_win; init_addr_type = p_lcb->ble_addr_type; memcpy(init_addr, p_lcb->remote_bd_addr, BD_ADDR_LEN); if (!btsnd_hcic_ble_create_ll_conn (scan_int,/* UINT16 scan_int */ scan_win, /* UINT16 scan_win */ FALSE, /* UINT8 white_list */ p_lcb->ble_addr_type, /* UINT8 addr_type_peer */ p_lcb->remote_bd_addr, /* BD_ADDR bda_peer */ BLE_ADDR_PUBLIC, /* UINT8 addr_type_own */ (UINT16) ((p_dev_rec->conn_params.min_conn_int != BTM_BLE_CONN_PARAM_UNDEF) ? p_dev_rec->conn_params.min_conn_int : BTM_BLE_CONN_INT_MIN), /* UINT16 conn_int_min */ (UINT16) ((p_dev_rec->conn_params.max_conn_int != BTM_BLE_CONN_PARAM_UNDEF) ? p_dev_rec->conn_params.max_conn_int : BTM_BLE_CONN_INT_MIN), /* UINT16 conn_int_max */ (UINT16) ((p_dev_rec->conn_params.slave_latency != BTM_BLE_CONN_PARAM_UNDEF) ? p_dev_rec->conn_params.slave_latency : 0), /* UINT16 conn_latency */ (UINT16) ((p_dev_rec->conn_params.supervision_tout != BTM_BLE_CONN_PARAM_UNDEF) ? p_dev_rec->conn_params.supervision_tout : BTM_BLE_CONN_SUP_TOUT_DEF), /* UINT16 conn_timeout */ 0, /* UINT16 min_len */ 0)) /* UINT16 max_len */ { l2cu_release_lcb (p_lcb); L2CAP_TRACE_ERROR0("initate direct connection fail, no resources"); return (FALSE); } else { p_lcb->link_state = LST_CONNECTING; memcpy (l2cb.ble_connecting_bda, p_lcb->remote_bd_addr, BD_ADDR_LEN); //Assigning below variable which is checked at LE conn cancel l2cb.is_ble_connecting=TRUE; btu_start_timer (&p_lcb->timer_entry, BTU_TTYPE_L2CAP_LINK, L2CAP_BLE_LINK_CONNECT_TOUT); btm_ble_set_conn_st (BLE_DIR_CONN); return (TRUE); } }
/******************************************************************************* ** ** Function BTM_ReadLocalDeviceNameFromController ** ** Description Get local device name from controller. Do not use cached ** name (used to get chip-id prior to btm reset complete). ** ** Returns BTM_CMD_STARTED if successful, otherwise an error ** *******************************************************************************/ tBTM_STATUS BTM_ReadLocalDeviceNameFromController (tBTM_CMPL_CB *p_rln_cmpl_cback) { /* Check if rln already in progress */ if (btm_cb.devcb.p_rln_cmpl_cb) return(BTM_NO_RESOURCES); /* Save callback */ btm_cb.devcb.p_rln_cmpl_cb = p_rln_cmpl_cback; btsnd_hcic_read_name(); btu_start_timer (&btm_cb.devcb.rln_timer, BTU_TTYPE_BTM_DEV_CTL, BTM_DEV_REPLY_TIMEOUT); return BTM_CMD_STARTED; }
/******************************************************************************* ** ** Function smp_br_data_received ** ** Description This function is called when data is received from L2CAP on ** SMP BR channel. ** ** Returns void ** *******************************************************************************/ static void smp_br_data_received(UINT16 channel, BD_ADDR bd_addr, BT_HDR *p_buf) { tSMP_CB *p_cb = &smp_cb; UINT8 *p = (UINT8 *)(p_buf + 1) + p_buf->offset; UINT8 cmd ; SMP_TRACE_EVENT ("SMDBG l2c %s", __func__); STREAM_TO_UINT8(cmd, p); /* sanity check */ if ((SMP_OPCODE_MAX < cmd) || (SMP_OPCODE_MIN > cmd)) { SMP_TRACE_WARNING( "Ignore received command with RESERVED code 0x%02x", cmd); GKI_freebuf(p_buf); return; } /* reject the pairing request if there is an on-going SMP pairing */ if (SMP_OPCODE_PAIRING_REQ == cmd) { if ((p_cb->state == SMP_STATE_IDLE) && (p_cb->br_state == SMP_BR_STATE_IDLE)) { p_cb->role = HCI_ROLE_SLAVE; p_cb->smp_over_br = TRUE; memcpy(&p_cb->pairing_bda[0], bd_addr, BD_ADDR_LEN); } else if (memcmp(&bd_addr[0], p_cb->pairing_bda, BD_ADDR_LEN)) { GKI_freebuf (p_buf); smp_reject_unexpected_pairing_command(bd_addr); return; } /* else, out of state pairing request received, passed into State Machine */ } if (memcmp(&bd_addr[0], p_cb->pairing_bda, BD_ADDR_LEN) == 0) { btu_stop_timer (&p_cb->rsp_timer_ent); btu_start_timer (&p_cb->rsp_timer_ent, BTU_TTYPE_SMP_PAIRING_CMD, SMP_WAIT_FOR_RSP_TOUT); p_cb->rcvd_cmd_code = cmd; p_cb->rcvd_cmd_len = (UINT8) p_buf->len; smp_br_state_machine_event(p_cb, cmd, p); } GKI_freebuf (p_buf); }
/******************************************************************************* ** ** Function sdp_config_cfm ** ** Description This function processes the L2CAP configuration confirmation ** event. ** ** Returns void ** *******************************************************************************/ static void sdp_config_cfm (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg) { tCONN_CB *p_ccb; SDP_TRACE_EVENT2 ("SDP - Rcvd cfg cfm, CID: 0x%x Result: %d", l2cap_cid, p_cfg->result); /* Find CCB based on CID */ if ((p_ccb = sdpu_find_ccb_by_cid (l2cap_cid)) == NULL) { SDP_TRACE_WARNING1 ("SDP - Rcvd L2CAP cfg ind, unknown CID: 0x%x", l2cap_cid); return; } /* For now, always accept configuration from the other side */ if (p_cfg->result == L2CAP_CFG_OK) { p_ccb->con_flags |= SDP_FLAGS_MY_CFG_DONE; if (p_ccb->con_flags & SDP_FLAGS_HIS_CFG_DONE) { p_ccb->con_state = SDP_STATE_CONNECTED; if (p_ccb->con_flags & SDP_FLAGS_IS_ORIG) sdp_disc_connected (p_ccb); else /* Start inactivity timer */ btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_SDP, SDP_INACT_TIMEOUT); } } else { /* If peer has rejected FCR and suggested basic then try basic */ if (p_cfg->fcr_present) { tL2CAP_CFG_INFO cfg = sdp_cb.l2cap_my_cfg; cfg.fcr_present = FALSE; L2CA_ConfigReq (l2cap_cid, &cfg); /* Remain in configure state */ return; } #if SDP_CLIENT_ENABLED == TRUE sdp_disconnect(p_ccb, SDP_CFG_FAILED); #endif } }
/******************************************************************************* ** ** Function avdt_ccb_chk_close ** ** Description This function checks for active streams on this CCB. ** If there are none, it starts an idle timer. ** ** ** Returns void. ** *******************************************************************************/ void avdt_ccb_chk_close(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data) { int i; tAVDT_SCB *p_scb = &avdt_cb.scb[0]; UNUSED(p_data); /* see if there are any active scbs associated with this ccb */ for (i = 0; i < AVDT_NUM_SEPS; i++, p_scb++) { if ((p_scb->allocated) && (p_scb->p_ccb == p_ccb)) { break; } } /* if no active scbs start idle timer */ if (i == AVDT_NUM_SEPS) { btu_start_timer(&p_ccb->timer_entry, BTU_TTYPE_AVDT_CCB_IDLE, avdt_cb.rcb.idle_tout); } }
/******************************************************************************* ** ** Function btm_ble_resume_bg_conn ** ** Description This function is to resume a background auto connection ** procedure. ** ** Parameters none. ** ** Returns none. ** *******************************************************************************/ BOOLEAN btm_ble_resume_bg_conn(tBTM_BLE_SEL_CBACK *p_sele_callback, BOOLEAN def_param) { tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb; BOOLEAN ret = FALSE; if (p_cb->bg_conn_state != BLE_BG_CONN_ACTIVE ) { if (def_param) { p_cb->scan_int = BTM_BLE_CONN_PARAM_UNDEF; p_cb->scan_win = BTM_BLE_CONN_PARAM_UNDEF; /* start scan param idle timer */ btu_start_timer(&p_cb->scan_param_idle_timer, BTU_TTYPE_BLE_SCAN_PARAM_IDLE, BTM_BLE_SCAN_PARAM_TOUT); } if (p_cb->bg_conn_type == BTM_BLE_CONN_AUTO) ret = btm_ble_start_auto_conn(TRUE); if (p_cb->bg_conn_type == BTM_BLE_CONN_SELECTIVE) { /* terminate selective connection mode if all devices are connected */ if (btm_ble_count_unconn_dev_in_whitelist() == 0) { btsnd_hcic_ble_set_scan_enable (BTM_BLE_SCAN_DISABLE, BTM_BLE_DUPLICATE_DISABLE); btm_cb.ble_ctr_cb.inq_var.proc_mode = BTM_BLE_INQUIRY_NONE; btm_cb.btm_inq_vars.inq_active = FALSE; } else if (!btm_cb.btm_inq_vars.inq_active) btm_ble_start_select_conn(TRUE, btm_cb.ble_ctr_cb.p_select_cback); } if (ret) p_cb->bg_conn_state = BLE_BG_CONN_ACTIVE; } return ret; }
/******************************************************************************* ** ** Function l2cble_init_direct_conn ** ** Description This function is to initate a direct connection ** ** Returns TRUE connection initiated, FALSE otherwise. ** *******************************************************************************/ BOOLEAN l2cble_init_direct_conn (tL2C_LCB *p_lcb) { tBTM_SEC_DEV_REC *p_dev_rec = btm_find_or_alloc_dev (p_lcb->remote_bd_addr); tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb; UINT16 scan_int, scan_win; BD_ADDR init_addr; UINT8 init_addr_type = BLE_ADDR_PUBLIC, own_addr_type = BLE_ADDR_PUBLIC; /* There can be only one BLE connection request outstanding at a time */ if (p_dev_rec == NULL) { L2CAP_TRACE_WARNING ("unknown device, can not initate connection"); return(FALSE); } scan_int = (p_cb->scan_int == BTM_BLE_CONN_PARAM_UNDEF) ? BTM_BLE_SCAN_FAST_INT : p_cb->scan_int; scan_win = (p_cb->scan_win == BTM_BLE_CONN_PARAM_UNDEF) ? BTM_BLE_SCAN_FAST_WIN : p_cb->scan_win; init_addr_type = p_lcb->ble_addr_type; memcpy(init_addr, p_lcb->remote_bd_addr, BD_ADDR_LEN); #if BLE_PRIVACY_SPT == TRUE /* if RPA offloading supported */ if (btm_ble_vendor_irk_list_load_dev(p_dev_rec)) btm_random_pseudo_to_public(init_addr, &init_addr_type); /* otherwise, if remote is RPA enabled, use latest RPA */ else if (p_dev_rec->ble.active_addr_type == BTM_BLE_ADDR_RRA) { init_addr_type = BLE_ADDR_RANDOM; memcpy(init_addr, p_dev_rec->ble.cur_rand_addr, BD_ADDR_LEN); } /* if privacy is on and current do not consider using reconnection address */ if (btm_cb.ble_ctr_cb.privacy ) /* && p_dev_rec->ble.use_reconn_addr */ own_addr_type = BLE_ADDR_RANDOM; #endif if (!btm_ble_topology_check(BTM_BLE_STATE_INIT)) { l2cu_release_lcb (p_lcb); L2CAP_TRACE_ERROR("initate direct connection fail, topology limitation"); return FALSE; } if (!btsnd_hcic_ble_create_ll_conn (scan_int,/* UINT16 scan_int */ scan_win, /* UINT16 scan_win */ FALSE, /* UINT8 white_list */ init_addr_type, /* UINT8 addr_type_peer */ init_addr, /* BD_ADDR bda_peer */ own_addr_type, /* UINT8 addr_type_own */ (UINT16) ((p_dev_rec->conn_params.min_conn_int != BTM_BLE_CONN_PARAM_UNDEF) ? p_dev_rec->conn_params.min_conn_int : BTM_BLE_CONN_INT_MIN_DEF), /* UINT16 conn_int_min */ (UINT16) ((p_dev_rec->conn_params.max_conn_int != BTM_BLE_CONN_PARAM_UNDEF) ? p_dev_rec->conn_params.max_conn_int : BTM_BLE_CONN_INT_MAX_DEF), /* UINT16 conn_int_max */ (UINT16) ((p_dev_rec->conn_params.slave_latency != BTM_BLE_CONN_PARAM_UNDEF) ? p_dev_rec->conn_params.slave_latency : BTM_BLE_CONN_SLAVE_LATENCY_DEF), /* UINT16 conn_latency */ (UINT16) ((p_dev_rec->conn_params.supervision_tout != BTM_BLE_CONN_PARAM_UNDEF) ? p_dev_rec->conn_params.supervision_tout : BTM_BLE_CONN_TIMEOUT_DEF), /* conn_timeout */ 0, /* UINT16 min_len */ 0)) /* UINT16 max_len */ { l2cu_release_lcb (p_lcb); L2CAP_TRACE_ERROR("initate direct connection fail, no resources"); return (FALSE); } else { p_lcb->link_state = LST_CONNECTING; l2cb.is_ble_connecting = TRUE; memcpy (l2cb.ble_connecting_bda, p_lcb->remote_bd_addr, BD_ADDR_LEN); btu_start_timer (&p_lcb->timer_entry, BTU_TTYPE_L2CAP_LINK, L2CAP_BLE_LINK_CONNECT_TOUT); btm_ble_set_conn_st (BLE_DIR_CONN); return (TRUE); } }
/******************************************************************************* ** ** Function l2c_ble_link_adjust_allocation ** ** Description This function is called when a link is created or removed ** to calculate the amount of packets each link may send to ** the HCI without an ack coming back. ** ** Currently, this is a simple allocation, dividing the ** number of Controller Packets by the number of links. In ** the future, QOS configuration should be examined. ** ** Returns void ** *******************************************************************************/ void l2c_ble_link_adjust_allocation (void) { UINT16 qq, yy, qq_remainder; tL2C_LCB *p_lcb; UINT16 hi_quota, low_quota; UINT16 num_lowpri_links = 0; UINT16 num_hipri_links = 0; UINT16 controller_xmit_quota = l2cb.num_lm_ble_bufs; UINT16 high_pri_link_quota = L2CAP_HIGH_PRI_MIN_XMIT_QUOTA_A; /* If no links active, reset buffer quotas and controller buffers */ if (l2cb.num_ble_links_active == 0) { l2cb.controller_le_xmit_window = l2cb.num_lm_ble_bufs; l2cb.ble_round_robin_quota = l2cb.ble_round_robin_unacked = 0; return; } /* First, count the links */ for (yy = 0, p_lcb = &l2cb.lcb_pool[0]; yy < MAX_L2CAP_LINKS; yy++, p_lcb++) { if (p_lcb->in_use && p_lcb->transport == BT_TRANSPORT_LE) { if (p_lcb->acl_priority == L2CAP_PRIORITY_HIGH) num_hipri_links++; else num_lowpri_links++; } } /* now adjust high priority link quota */ low_quota = num_lowpri_links ? 1 : 0; while ( (num_hipri_links * high_pri_link_quota + low_quota) > controller_xmit_quota ) high_pri_link_quota--; /* Work out the xmit quota and buffer quota high and low priorities */ hi_quota = num_hipri_links * high_pri_link_quota; low_quota = (hi_quota < controller_xmit_quota) ? controller_xmit_quota - hi_quota : 1; /* Work out and save the HCI xmit quota for each low priority link */ /* If each low priority link cannot have at least one buffer */ if (num_lowpri_links > low_quota) { l2cb.ble_round_robin_quota = low_quota; qq = qq_remainder = 0; } /* If each low priority link can have at least one buffer */ else if (num_lowpri_links > 0) { l2cb.ble_round_robin_quota = 0; l2cb.ble_round_robin_unacked = 0; qq = low_quota / num_lowpri_links; qq_remainder = low_quota % num_lowpri_links; } /* If no low priority link */ else { l2cb.ble_round_robin_quota = 0; l2cb.ble_round_robin_unacked = 0; qq = qq_remainder = 0; } L2CAP_TRACE_EVENT ("l2c_ble_link_adjust_allocation num_hipri: %u num_lowpri: %u low_quota: %u round_robin_quota: %u qq: %u", num_hipri_links, num_lowpri_links, low_quota, l2cb.ble_round_robin_quota, qq); /* Now, assign the quotas to each link */ for (yy = 0, p_lcb = &l2cb.lcb_pool[0]; yy < MAX_L2CAP_LINKS; yy++, p_lcb++) { if (p_lcb->in_use && p_lcb->transport == BT_TRANSPORT_LE) { if (p_lcb->acl_priority == L2CAP_PRIORITY_HIGH) { p_lcb->link_xmit_quota = high_pri_link_quota; } else { /* Safety check in case we switched to round-robin with something outstanding */ /* if sent_not_acked is added into round_robin_unacked then don't add it again */ /* l2cap keeps updating sent_not_acked for exiting from round robin */ if (( p_lcb->link_xmit_quota > 0 )&&( qq == 0 )) l2cb.ble_round_robin_unacked += p_lcb->sent_not_acked; p_lcb->link_xmit_quota = qq; if (qq_remainder > 0) { p_lcb->link_xmit_quota++; qq_remainder--; } } L2CAP_TRACE_EVENT("l2c_ble_link_adjust_allocation LCB %d Priority: %d XmitQuota: %d", yy, p_lcb->acl_priority, p_lcb->link_xmit_quota); L2CAP_TRACE_EVENT(" SentNotAcked: %d RRUnacked: %d", p_lcb->sent_not_acked, l2cb.round_robin_unacked); /* There is a special case where we have readjusted the link quotas and */ /* this link may have sent anything but some other link sent packets so */ /* so we may need a timer to kick off this link's transmissions. */ if ( (p_lcb->link_state == LST_CONNECTED) && (!list_is_empty(p_lcb->link_xmit_data_q)) && (p_lcb->sent_not_acked < p_lcb->link_xmit_quota) ) btu_start_timer (&p_lcb->timer_entry, BTU_TTYPE_L2CAP_LINK, L2CAP_LINK_FLOW_CONTROL_TOUT); } } }
/******************************************************************************* ** ** Function l2cble_init_direct_conn ** ** Description This function is to initate a direct connection ** ** Returns TRUE connection initiated, FALSE otherwise. ** *******************************************************************************/ BOOLEAN l2cble_init_direct_conn (tL2C_LCB *p_lcb) { tBTM_SEC_DEV_REC *p_dev_rec = btm_find_or_alloc_dev (p_lcb->remote_bd_addr); tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb; UINT16 scan_int; UINT16 scan_win; BD_ADDR peer_addr; UINT8 peer_addr_type = BLE_ADDR_PUBLIC; UINT8 own_addr_type = BLE_ADDR_PUBLIC; /* There can be only one BLE connection request outstanding at a time */ if (p_dev_rec == NULL) { L2CAP_TRACE_WARNING ("unknown device, can not initate connection"); return(FALSE); } scan_int = (p_cb->scan_int == BTM_BLE_SCAN_PARAM_UNDEF) ? BTM_BLE_SCAN_FAST_INT : p_cb->scan_int; scan_win = (p_cb->scan_win == BTM_BLE_SCAN_PARAM_UNDEF) ? BTM_BLE_SCAN_FAST_WIN : p_cb->scan_win; peer_addr_type = p_lcb->ble_addr_type; memcpy(peer_addr, p_lcb->remote_bd_addr, BD_ADDR_LEN); #if ( (defined BLE_PRIVACY_SPT) && (BLE_PRIVACY_SPT == TRUE)) own_addr_type = btm_cb.ble_ctr_cb.privacy_mode ? BLE_ADDR_RANDOM : BLE_ADDR_PUBLIC; if (p_dev_rec->ble.in_controller_list & BTM_RESOLVING_LIST_BIT) { if (btm_cb.ble_ctr_cb.privacy_mode >= BTM_PRIVACY_1_2) own_addr_type |= BLE_ADDR_TYPE_ID_BIT; btm_ble_enable_resolving_list(BTM_BLE_RL_INIT); btm_random_pseudo_to_identity_addr(peer_addr, &peer_addr_type); } else btm_ble_disable_resolving_list(BTM_BLE_RL_INIT, TRUE); #endif if (!btm_ble_topology_check(BTM_BLE_STATE_INIT)) { l2cu_release_lcb (p_lcb); L2CAP_TRACE_ERROR("initate direct connection fail, topology limitation"); return FALSE; } if (!btsnd_hcic_ble_create_ll_conn (scan_int,/* UINT16 scan_int */ scan_win, /* UINT16 scan_win */ FALSE, /* UINT8 white_list */ peer_addr_type, /* UINT8 addr_type_peer */ peer_addr, /* BD_ADDR bda_peer */ own_addr_type, /* UINT8 addr_type_own */ (UINT16) ((p_dev_rec->conn_params.min_conn_int != BTM_BLE_CONN_PARAM_UNDEF) ? p_dev_rec->conn_params.min_conn_int : BTM_BLE_CONN_INT_MIN_DEF), /* UINT16 conn_int_min */ (UINT16) ((p_dev_rec->conn_params.max_conn_int != BTM_BLE_CONN_PARAM_UNDEF) ? p_dev_rec->conn_params.max_conn_int : BTM_BLE_CONN_INT_MAX_DEF), /* UINT16 conn_int_max */ (UINT16) ((p_dev_rec->conn_params.slave_latency != BTM_BLE_CONN_PARAM_UNDEF) ? p_dev_rec->conn_params.slave_latency : BTM_BLE_CONN_SLAVE_LATENCY_DEF), /* UINT16 conn_latency */ (UINT16) ((p_dev_rec->conn_params.supervision_tout != BTM_BLE_CONN_PARAM_UNDEF) ? p_dev_rec->conn_params.supervision_tout : BTM_BLE_CONN_TIMEOUT_DEF), /* conn_timeout */ 0, /* UINT16 min_len */ 0)) /* UINT16 max_len */ { l2cu_release_lcb (p_lcb); L2CAP_TRACE_ERROR("initate direct connection fail, no resources"); return (FALSE); } else { p_lcb->link_state = LST_CONNECTING; l2cb.is_ble_connecting = TRUE; memcpy (l2cb.ble_connecting_bda, p_lcb->remote_bd_addr, BD_ADDR_LEN); btu_start_timer (&p_lcb->timer_entry, BTU_TTYPE_L2CAP_LINK, L2CAP_BLE_LINK_CONNECT_TOUT); btm_ble_set_conn_st (BLE_DIR_CONN); return (TRUE); } }
/******************************************************************************* ** ** Function sdp_config_ind ** ** Description This function processes the L2CAP configuration indication ** event. ** ** Returns void ** *******************************************************************************/ static void sdp_config_ind (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg) { tCONN_CB *p_ccb; /* Find CCB based on CID */ if ((p_ccb = sdpu_find_ccb_by_cid (l2cap_cid)) == NULL) { SDP_TRACE_WARNING1 ("SDP - Rcvd L2CAP cfg ind, unknown CID: 0x%x", l2cap_cid); return; } /* Remember the remote MTU size */ if (!p_cfg->mtu_present) { /* use min(L2CAP_DEFAULT_MTU,SDP_MTU_SIZE) for GKI buffer size reasons */ p_ccb->rem_mtu_size = (L2CAP_DEFAULT_MTU > SDP_MTU_SIZE)?SDP_MTU_SIZE:L2CAP_DEFAULT_MTU; } else { if (p_cfg->mtu > SDP_MTU_SIZE) p_ccb->rem_mtu_size = SDP_MTU_SIZE; else p_ccb->rem_mtu_size = p_cfg->mtu; } /* For now, always accept configuration from the other side */ p_cfg->flush_to_present = FALSE; p_cfg->mtu_present = FALSE; p_cfg->result = L2CAP_CFG_OK; /* Check peer config request against our rfcomm configuration */ if (p_cfg->fcr_present) { /* Reject the window size if it is bigger than we want it to be */ if (p_cfg->fcr.mode != L2CAP_FCR_BASIC_MODE) { if (sdp_cb.l2cap_my_cfg.fcr.mode != L2CAP_FCR_BASIC_MODE && p_cfg->fcr.tx_win_sz > sdp_cb.l2cap_my_cfg.fcr.tx_win_sz) { p_cfg->fcr.tx_win_sz = sdp_cb.l2cap_my_cfg.fcr.tx_win_sz; p_cfg->result = L2CAP_CFG_UNACCEPTABLE_PARAMS; SDP_TRACE_DEBUG0("sdp_config_ind(CONFIG) -> Please try again with SMALLER TX WINDOW"); } /* Reject if locally we want basic and they don't */ if (sdp_cb.l2cap_my_cfg.fcr.mode == L2CAP_FCR_BASIC_MODE) { /* Ask for a new setup */ p_cfg->fcr.mode = L2CAP_FCR_BASIC_MODE; p_cfg->result = L2CAP_CFG_UNACCEPTABLE_PARAMS; SDP_TRACE_DEBUG0("sdp_config_ind(CONFIG) -> Please try again with BASIC mode"); } /* Remain in configure state and give the peer our desired configuration */ if (p_cfg->result != L2CAP_CFG_OK) { SDP_TRACE_WARNING1 ("SDP - Rcvd cfg ind, Unacceptable Parameters sent cfg cfm, CID: 0x%x", l2cap_cid); L2CA_ConfigRsp (l2cap_cid, p_cfg); return; } } else /* We agree with peer's request */ p_cfg->fcr_present = FALSE; } L2CA_ConfigRsp (l2cap_cid, p_cfg); SDP_TRACE_EVENT1 ("SDP - Rcvd cfg ind, sent cfg cfm, CID: 0x%x", l2cap_cid); p_ccb->con_flags |= SDP_FLAGS_HIS_CFG_DONE; if (p_ccb->con_flags & SDP_FLAGS_MY_CFG_DONE) { p_ccb->con_state = SDP_STATE_CONNECTED; if (p_ccb->con_flags & SDP_FLAGS_IS_ORIG) sdp_disc_connected (p_ccb); else /* Start inactivity timer */ btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_SDP, SDP_INACT_TIMEOUT); } }
/******************************************************************************* ** ** Function hidh_l2cif_disconnect_ind ** ** Description This function handles a disconnect event from L2CAP. If ** requested to, we ack the disconnect before dropping the CCB ** ** Returns void ** *******************************************************************************/ static void hidh_l2cif_disconnect_ind (UINT16 l2cap_cid, BOOLEAN ack_needed) { UINT8 dhandle; tHID_CONN *p_hcon = NULL; UINT16 disc_res = HCI_SUCCESS; UINT16 hid_close_evt_reason; /* Find CCB based on CID */ if( (dhandle = find_conn_by_cid(l2cap_cid)) < HID_HOST_MAX_DEVICES ) p_hcon = &hh_cb.devices[dhandle].conn; if (p_hcon == NULL) { HIDH_TRACE_WARNING ("HID-Host Rcvd L2CAP disc, unknown CID: 0x%x", l2cap_cid); return; } if (ack_needed) L2CA_DisconnectRsp (l2cap_cid); HIDH_TRACE_EVENT ("HID-Host Rcvd L2CAP disc, CID: 0x%x", l2cap_cid); p_hcon->conn_state = HID_CONN_STATE_DISCONNECTING; if (l2cap_cid == p_hcon->ctrl_cid) p_hcon->ctrl_cid = 0; else p_hcon->intr_cid = 0; if ((p_hcon->ctrl_cid == 0) && (p_hcon->intr_cid == 0)) { hh_cb.devices[dhandle].state = HID_DEV_NO_CONN; p_hcon->conn_state = HID_CONN_STATE_UNUSED; if( !ack_needed ) disc_res = btm_get_acl_disc_reason_code(); HIDH_TRACE_EVENT ("HID-Host: acl disconnect reason %d", disc_res); #if (HID_HOST_MAX_CONN_RETRY > 0) if( (disc_res == HCI_ERR_CONNECTION_TOUT || disc_res == HCI_ERR_UNSPECIFIED) && (!(hh_cb.devices[dhandle].attr_mask & HID_RECONN_INIT)) && (hh_cb.devices[dhandle].attr_mask & HID_NORMALLY_CONNECTABLE)) { hh_cb.devices[dhandle].conn_tries = 0; hh_cb.devices[dhandle].conn.timer_entry.param = (UINT32) dhandle; HIDH_TRACE_EVENT ("HID-Host: starting timer for reconnection"); btu_start_timer (&(hh_cb.devices[dhandle].conn.timer_entry), BTU_TTYPE_HID_HOST_REPAGE_TO, HID_HOST_REPAGE_WIN); hh_cb.callback( dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE, disc_res, NULL); } else #endif { /* Set reason code for HID_HDEV_EVT_CLOSE */ hid_close_evt_reason = p_hcon->disc_reason; /* If we got baseband sent HCI_DISCONNECT_COMPLETE_EVT due to security failure, then set reason to HID_ERR_AUTH_FAILED */ if ((disc_res == HCI_ERR_AUTH_FAILURE) || (disc_res == HCI_ERR_KEY_MISSING) || (disc_res == HCI_ERR_HOST_REJECT_SECURITY) || (disc_res == HCI_ERR_PAIRING_NOT_ALLOWED) || (disc_res == HCI_ERR_UNIT_KEY_USED) || (disc_res == HCI_ERR_PAIRING_WITH_UNIT_KEY_NOT_SUPPORTED) || (disc_res == HCI_ERR_ENCRY_MODE_NOT_ACCEPTABLE) || (disc_res == HCI_ERR_REPEATED_ATTEMPTS)) { hid_close_evt_reason = HID_ERR_AUTH_FAILED; } HIDH_TRACE_EVENT ("HID-Host: disconnect ind, reason = %d", hid_close_evt_reason); hh_cb.callback( dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE, hid_close_evt_reason, NULL ) ; } } }
/******************************************************************************* ** ** Function l2c_rcv_acl_data ** ** Description This function is called from the HCI Interface when an ACL ** data packet is received. ** ** Returns void ** *******************************************************************************/ void l2c_rcv_acl_data (BT_HDR *p_msg) { UINT8 *p = (UINT8 *)(p_msg + 1) + p_msg->offset; UINT16 handle, hci_len; UINT8 pkt_type; tL2C_LCB *p_lcb; tL2C_CCB *p_ccb = NULL; UINT16 l2cap_len, rcv_cid, psm; /* Extract the handle */ STREAM_TO_UINT16 (handle, p); pkt_type = HCID_GET_EVENT (handle); handle = HCID_GET_HANDLE (handle); /* Since the HCI Transport is putting segmented packets back together, we */ /* should never get a valid packet with the type set to "continuation" */ if (pkt_type != L2CAP_PKT_CONTINUE) { /* Find the LCB based on the handle */ if ((p_lcb = l2cu_find_lcb_by_handle (handle)) == NULL) { UINT8 cmd_code; /* There is a slight possibility (specifically with USB) that we get an */ /* L2CAP connection request before we get the HCI connection complete. */ /* So for these types of messages, hold them for up to 2 seconds. */ STREAM_TO_UINT16 (hci_len, p); STREAM_TO_UINT16 (l2cap_len, p); STREAM_TO_UINT16 (rcv_cid, p); STREAM_TO_UINT8 (cmd_code, p); if ((p_msg->layer_specific == 0) && (rcv_cid == L2CAP_SIGNALLING_CID) && (cmd_code == L2CAP_CMD_INFO_REQ || cmd_code == L2CAP_CMD_CONN_REQ)) { L2CAP_TRACE_WARNING ("L2CAP - holding ACL for unknown handle:%d ls:%d" " cid:%d opcode:%d cur count:%d", handle, p_msg->layer_specific, rcv_cid, cmd_code, list_length(l2cb.rcv_pending_q)); p_msg->layer_specific = 2; list_append(l2cb.rcv_pending_q, p_msg); if (list_length(l2cb.rcv_pending_q) == 1) { btu_start_timer (&l2cb.rcv_hold_tle, BTU_TTYPE_L2CAP_HOLD, BT_1SEC_TIMEOUT); } return; } else { L2CAP_TRACE_ERROR ("L2CAP - rcvd ACL for unknown handle:%d ls:%d cid:%d" " opcode:%d cur count:%d", handle, p_msg->layer_specific, rcv_cid, cmd_code, list_length(l2cb.rcv_pending_q)); } GKI_freebuf (p_msg); return; } } else { L2CAP_TRACE_WARNING ("L2CAP - expected pkt start or complete, got: %d", pkt_type); GKI_freebuf (p_msg); return; } /* Extract the length and update the buffer header */ STREAM_TO_UINT16 (hci_len, p); p_msg->offset += 4; /* Extract the length and CID */ STREAM_TO_UINT16 (l2cap_len, p); STREAM_TO_UINT16 (rcv_cid, p); #if BLE_INCLUDED == TRUE /* for BLE channel, always notify connection when ACL data received on the link */ if (p_lcb && p_lcb->transport == BT_TRANSPORT_LE && p_lcb->link_state != LST_DISCONNECTING) /* only process fixed channel data as channel open indication when link is not in disconnecting mode */ { l2cble_notify_le_connection(p_lcb->remote_bd_addr); } #endif L2CAP_TRACE_DEBUG ("L2CAP - rcv_cid CID: 0x%04x\n", rcv_cid); /* Find the CCB for this CID */ if (rcv_cid >= L2CAP_BASE_APPL_CID) { if ((p_ccb = l2cu_find_ccb_by_cid (p_lcb, rcv_cid)) == NULL) { L2CAP_TRACE_WARNING ("L2CAP - unknown CID: 0x%04x", rcv_cid); GKI_freebuf (p_msg); return; } } if (hci_len >= L2CAP_PKT_OVERHEAD) { /* Must receive at least the L2CAP length and CID.*/ p_msg->len = hci_len - L2CAP_PKT_OVERHEAD; p_msg->offset += L2CAP_PKT_OVERHEAD; } else { L2CAP_TRACE_WARNING ("L2CAP - got incorrect hci header" ); GKI_freebuf (p_msg); return; } if (l2cap_len != p_msg->len) { L2CAP_TRACE_WARNING ("L2CAP - bad length in pkt. Exp: %d Act: %d", l2cap_len, p_msg->len); GKI_freebuf (p_msg); return; } /* Send the data through the channel state machine */ if (rcv_cid == L2CAP_SIGNALLING_CID) { //counter_add("l2cap.sig.rx.bytes", l2cap_len); //counter_add("l2cap.sig.rx.pkts", 1); #if (CLASSIC_BT_INCLUDED == TRUE) process_l2cap_cmd (p_lcb, p, l2cap_len); #endif ///CLASSIC_BT_INCLUDED == TRUE GKI_freebuf (p_msg); } else if (rcv_cid == L2CAP_CONNECTIONLESS_CID) { //counter_add("l2cap.ch2.rx.bytes", l2cap_len); //counter_add("l2cap.ch2.rx.pkts", 1); /* process_connectionless_data (p_lcb); */ STREAM_TO_UINT16 (psm, p); L2CAP_TRACE_DEBUG( "GOT CONNECTIONLESS DATA PSM:%d", psm ) ; #if (L2CAP_UCD_INCLUDED == TRUE) /* if it is not broadcast, check UCD registration */ if ( l2c_ucd_check_rx_pkts( p_lcb, p_msg ) ) { /* nothing to do */ } else #endif GKI_freebuf (p_msg); } #if (BLE_INCLUDED == TRUE) else if (rcv_cid == L2CAP_BLE_SIGNALLING_CID) { //counter_add("l2cap.ble.rx.bytes", l2cap_len); //counter_add("l2cap.ble.rx.pkts", 1); l2cble_process_sig_cmd (p_lcb, p, l2cap_len); GKI_freebuf (p_msg); } #endif #if (L2CAP_NUM_FIXED_CHNLS > 0) else if ((rcv_cid >= L2CAP_FIRST_FIXED_CHNL) && (rcv_cid <= L2CAP_LAST_FIXED_CHNL) && (l2cb.fixed_reg[rcv_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedData_Cb != NULL) ) { //counter_add("l2cap.fix.rx.bytes", l2cap_len); //counter_add("l2cap.fix.rx.pkts", 1); /* If no CCB for this channel, allocate one */ if (p_lcb && /* only process fixed channel data when link is open or wait for data indication */ (p_lcb->link_state != LST_DISCONNECTING) && l2cu_initialize_fixed_ccb (p_lcb, rcv_cid, &l2cb.fixed_reg[rcv_cid - L2CAP_FIRST_FIXED_CHNL].fixed_chnl_opts)) { p_ccb = p_lcb->p_fixed_ccbs[rcv_cid - L2CAP_FIRST_FIXED_CHNL]; if (p_ccb->peer_cfg.fcr.mode != L2CAP_FCR_BASIC_MODE) { #if (CLASSIC_BT_INCLUDED == TRUE) l2c_fcr_proc_pdu (p_ccb, p_msg); #endif ///CLASSIC_BT_INCLUDED == TRUE } else (*l2cb.fixed_reg[rcv_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedData_Cb) (rcv_cid, p_lcb->remote_bd_addr, p_msg); } else { GKI_freebuf (p_msg); } } #endif else { //counter_add("l2cap.dyn.rx.bytes", l2cap_len); //counter_add("l2cap.dyn.rx.pkts", 1); if (p_ccb == NULL) { GKI_freebuf (p_msg); } else { /* Basic mode packets go straight to the state machine */ if (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_BASIC_MODE) { #if (CLASSIC_BT_INCLUDED == TRUE) l2c_csm_execute (p_ccb, L2CEVT_L2CAP_DATA, p_msg); #endif ///CLASSIC_BT_INCLUDED == TRUE } else { /* eRTM or streaming mode, so we need to validate states first */ if ((p_ccb->chnl_state == CST_OPEN) || (p_ccb->chnl_state == CST_CONFIG)) { #if (CLASSIC_BT_INCLUDED == TRUE) l2c_fcr_proc_pdu (p_ccb, p_msg); #endif ///CLASSIC_BT_INCLUDED == TRUE } else { GKI_freebuf (p_msg); } } } } }
/******************************************************************************* ** ** Function smp_data_received ** ** Description This function is called when data is received from L2CAP on ** SMP channel. ** ** ** Returns void ** *******************************************************************************/ static void smp_data_received(UINT16 channel, BD_ADDR bd_addr, BT_HDR *p_buf) { tSMP_CB *p_cb = &smp_cb; UINT8 *p = (UINT8 *)(p_buf + 1) + p_buf->offset; UINT8 cmd ; SMP_TRACE_EVENT ("SMDBG l2c %s", __FUNCTION__); STREAM_TO_UINT8(cmd, p); /* sanity check */ if ((SMP_OPCODE_MAX < cmd) || (SMP_OPCODE_MIN > cmd)) { SMP_TRACE_WARNING( "Ignore received command with RESERVED code 0x%02x", cmd); GKI_freebuf (p_buf); return; } /* reject the pairing request if there is an on-going SMP pairing */ if (SMP_OPCODE_PAIRING_REQ == cmd || SMP_OPCODE_SEC_REQ == cmd) { if ((p_cb->state == SMP_STATE_IDLE) && (p_cb->br_state == SMP_BR_STATE_IDLE) && !(p_cb->flags & SMP_PAIR_FLAGS_WE_STARTED_DD)) { p_cb->role = L2CA_GetBleConnRole(bd_addr); memcpy(&p_cb->pairing_bda[0], bd_addr, BD_ADDR_LEN); } else if (memcmp(&bd_addr[0], p_cb->pairing_bda, BD_ADDR_LEN)) { GKI_freebuf (p_buf); smp_reject_unexpected_pairing_command(bd_addr); return; } /* else, out of state pairing request/security request received, passed into SM */ } if (memcmp(&bd_addr[0], p_cb->pairing_bda, BD_ADDR_LEN) == 0) { btu_stop_timer (&p_cb->rsp_timer_ent); btu_start_timer (&p_cb->rsp_timer_ent, BTU_TTYPE_SMP_PAIRING_CMD, SMP_WAIT_FOR_RSP_TOUT); if (cmd == SMP_OPCODE_CONFIRM) { SMP_TRACE_DEBUG ("in %s cmd = 0x%02x, peer_auth_req = 0x%02x," "loc_auth_req = 0x%02x", __FUNCTION__, cmd, p_cb->peer_auth_req, p_cb->loc_auth_req); if ((p_cb->peer_auth_req & SMP_SC_SUPPORT_BIT) && (p_cb->loc_auth_req & SMP_SC_SUPPORT_BIT)) { cmd = SMP_OPCODE_PAIR_COMMITM; } } p_cb->rcvd_cmd_code = cmd; p_cb->rcvd_cmd_len = (UINT8) p_buf->len; smp_sm_event(p_cb, cmd, p); } GKI_freebuf (p_buf); }
/******************************************************************************* ** ** Function BNEP_Connect ** ** Description This function creates a BNEP connection to a remote ** device. ** ** Parameters: p_rem_addr - BD_ADDR of the peer ** src_uuid - source uuid for the connection ** dst_uuid - destination uuid for the connection ** p_handle - pointer to return the handle for the connection ** ** Returns BNEP_SUCCESS if connection started ** BNEP_NO_RESOURCES if no resources ** *******************************************************************************/ tBNEP_RESULT BNEP_Connect (BD_ADDR p_rem_bda, tBT_UUID *src_uuid, tBT_UUID *dst_uuid, UINT16 *p_handle) { UINT16 cid; tBNEP_CONN *p_bcb = bnepu_find_bcb_by_bd_addr (p_rem_bda); BNEP_TRACE_API ("BNEP_Connect() BDA: %02x-%02x-%02x-%02x-%02x-%02x", p_rem_bda[0], p_rem_bda[1], p_rem_bda[2], p_rem_bda[3], p_rem_bda[4], p_rem_bda[5]); if (!bnep_cb.profile_registered) return BNEP_WRONG_STATE; /* Both source and destination UUID lengths should be same */ if (src_uuid->len != dst_uuid->len) return BNEP_CONN_FAILED_UUID_SIZE; #if (!defined (BNEP_SUPPORTS_ALL_UUID_LENGTHS) || BNEP_SUPPORTS_ALL_UUID_LENGTHS == FALSE) if (src_uuid->len != 2) return BNEP_CONN_FAILED_UUID_SIZE; #endif if (!p_bcb) { if ((p_bcb = bnepu_allocate_bcb (p_rem_bda)) == NULL) return (BNEP_NO_RESOURCES); } else if (p_bcb->con_state != BNEP_STATE_CONNECTED) return BNEP_WRONG_STATE; else { /* Backup current UUID values to restore if role change fails */ memcpy ((UINT8 *)&(p_bcb->prv_src_uuid), (UINT8 *)&(p_bcb->src_uuid), sizeof (tBT_UUID)); memcpy ((UINT8 *)&(p_bcb->prv_dst_uuid), (UINT8 *)&(p_bcb->dst_uuid), sizeof (tBT_UUID)); } /* We are the originator of this connection */ p_bcb->con_flags |= BNEP_FLAGS_IS_ORIG; memcpy ((UINT8 *)&(p_bcb->src_uuid), (UINT8 *)src_uuid, sizeof (tBT_UUID)); memcpy ((UINT8 *)&(p_bcb->dst_uuid), (UINT8 *)dst_uuid, sizeof (tBT_UUID)); if (p_bcb->con_state == BNEP_STATE_CONNECTED) { /* Transition to the next appropriate state, waiting for connection confirm. */ p_bcb->con_state = BNEP_STATE_SEC_CHECKING; BNEP_TRACE_API ("BNEP initiating security procedures for src uuid 0x%x", p_bcb->src_uuid.uu.uuid16); #if (defined (BNEP_DO_AUTH_FOR_ROLE_SWITCH) && BNEP_DO_AUTH_FOR_ROLE_SWITCH == TRUE) btm_sec_mx_access_request (p_bcb->rem_bda, BT_PSM_BNEP, TRUE, BTM_SEC_PROTO_BNEP, bnep_get_uuid32(src_uuid), &bnep_sec_check_complete, p_bcb); #else bnep_sec_check_complete (p_bcb->rem_bda, p_bcb, BTM_SUCCESS); #endif } else { /* Transition to the next appropriate state, waiting for connection confirm. */ p_bcb->con_state = BNEP_STATE_CONN_START; if ((cid = L2CA_ConnectReq (BT_PSM_BNEP, p_bcb->rem_bda)) != 0) { p_bcb->l2cap_cid = cid; } else { BNEP_TRACE_ERROR ("BNEP - Originate failed"); if (bnep_cb.p_conn_state_cb) (*bnep_cb.p_conn_state_cb) (p_bcb->handle, p_bcb->rem_bda, BNEP_CONN_FAILED, FALSE); bnepu_release_bcb (p_bcb); return BNEP_CONN_FAILED; } /* Start timer waiting for connect */ btu_start_timer (&p_bcb->conn_tle, BTU_TTYPE_BNEP, BNEP_CONN_TIMEOUT); } *p_handle = p_bcb->handle; return (BNEP_SUCCESS); }
/******************************************************************************* ** ** Function l2c_rcv_acl_data ** ** Description This function is called from the HCI Interface when an ACL ** data packet is received. ** ** Returns void ** *******************************************************************************/ void l2c_rcv_acl_data (BT_HDR *p_msg) { UINT8 *p = (UINT8 *)(p_msg + 1) + p_msg->offset; UINT16 handle, hci_len; UINT8 pkt_type; tL2C_LCB *p_lcb; tL2C_CCB *p_ccb = NULL; UINT16 l2cap_len, rcv_cid, psm; /* Extract the handle */ STREAM_TO_UINT16 (handle, p); pkt_type = HCID_GET_EVENT (handle); handle = HCID_GET_HANDLE (handle); /* Since the HCI Transport is putting segmented packets back together, we */ /* should never get a valid packet with the type set to "continuation" */ if (pkt_type != L2CAP_PKT_CONTINUE) { /* Find the LCB based on the handle */ if ((p_lcb = l2cu_find_lcb_by_handle (handle)) == NULL) { UINT8 cmd_code; /* There is a slight possibility (specifically with USB) that we get an */ /* L2CAP connection request before we get the HCI connection complete. */ /* So for these types of messages, hold them for up to 2 seconds. */ STREAM_TO_UINT16 (hci_len, p); STREAM_TO_UINT16 (l2cap_len, p); STREAM_TO_UINT16 (rcv_cid, p); STREAM_TO_UINT8 (cmd_code, p); if ((p_msg->layer_specific == 0) && (rcv_cid == L2CAP_SIGNALLING_CID) && (cmd_code == L2CAP_CMD_INFO_REQ || cmd_code == L2CAP_CMD_CONN_REQ)) { L2CAP_TRACE_WARNING5 ("L2CAP - holding ACL for unknown handle:%d ls:%d cid:%d opcode:%d cur count:%d", handle, p_msg->layer_specific, rcv_cid, cmd_code, l2cb.rcv_hold_q.count); p_msg->layer_specific = 2; GKI_enqueue (&l2cb.rcv_hold_q, p_msg); if (l2cb.rcv_hold_q.count == 1) btu_start_timer (&l2cb.rcv_hold_tle, BTU_TTYPE_L2CAP_HOLD, BT_1SEC_TIMEOUT); return; } else { L2CAP_TRACE_ERROR5 ("L2CAP - rcvd ACL for unknown handle:%d ls:%d cid:%d opcode:%d cur count:%d", handle, p_msg->layer_specific, rcv_cid, cmd_code, l2cb.rcv_hold_q.count); } GKI_freebuf (p_msg); return; } } else { L2CAP_TRACE_WARNING1 ("L2CAP - expected pkt start or complete, got: %d", pkt_type); GKI_freebuf (p_msg); return; } /* Extract the length and update the buffer header */ STREAM_TO_UINT16 (hci_len, p); p_msg->offset += 4; #if (L2CAP_HOST_FLOW_CTRL == TRUE) /* Send ack if we hit the threshold */ if (++p_lcb->link_pkts_unacked >= p_lcb->link_ack_thresh) btu_hcif_send_host_rdy_for_data(); #endif /* Extract the length and CID */ STREAM_TO_UINT16 (l2cap_len, p); STREAM_TO_UINT16 (rcv_cid, p); /* Find the CCB for this CID */ if (rcv_cid >= L2CAP_BASE_APPL_CID) { if ((p_ccb = l2cu_find_ccb_by_cid (p_lcb, rcv_cid)) == NULL) { L2CAP_TRACE_WARNING1 ("L2CAP - unknown CID: 0x%04x", rcv_cid); GKI_freebuf (p_msg); return; } } if (hci_len >= L2CAP_PKT_OVERHEAD) /* Must receive at least the L2CAP length and CID.*/ { p_msg->len = hci_len - L2CAP_PKT_OVERHEAD; p_msg->offset += L2CAP_PKT_OVERHEAD; } else { L2CAP_TRACE_WARNING0 ("L2CAP - got incorrect hci header" ); GKI_freebuf (p_msg); return; } if (l2cap_len != p_msg->len) { L2CAP_TRACE_WARNING2 ("L2CAP - bad length in pkt. Exp: %d Act: %d", l2cap_len, p_msg->len); GKI_freebuf (p_msg); return; } /* Send the data through the channel state machine */ if (rcv_cid == L2CAP_SIGNALLING_CID) { process_l2cap_cmd (p_lcb, p, l2cap_len); GKI_freebuf (p_msg); } else if (rcv_cid == L2CAP_CONNECTIONLESS_CID) { /* process_connectionless_data (p_lcb); */ STREAM_TO_UINT16 (psm, p); L2CAP_TRACE_DEBUG1( "GOT CONNECTIONLESS DATA PSM:%d", psm ) ; #if (TCS_BCST_SETUP_INCLUDED == TRUE && TCS_INCLUDED == TRUE) if (psm == TCS_PSM_INTERCOM || psm == TCS_PSM_CORDLESS) { p_msg->offset += L2CAP_BCST_OVERHEAD; p_msg->len -= L2CAP_BCST_OVERHEAD; tcs_proc_bcst_msg( p_lcb->remote_bd_addr, p_msg ) ; GKI_freebuf (p_msg); } else #endif #if (L2CAP_UCD_INCLUDED == TRUE) /* if it is not broadcast, check UCD registration */ if ( l2c_ucd_check_rx_pkts( p_lcb, p_msg ) ) { /* nothing to do */ } else #endif GKI_freebuf (p_msg); } #if (BLE_INCLUDED == TRUE) else if (rcv_cid == L2CAP_BLE_SIGNALLING_CID) { l2cble_process_sig_cmd (p_lcb, p, l2cap_len); GKI_freebuf (p_msg); } #endif #if (L2CAP_NUM_FIXED_CHNLS > 0) else if ((rcv_cid >= L2CAP_FIRST_FIXED_CHNL) && (rcv_cid <= L2CAP_LAST_FIXED_CHNL) && (l2cb.fixed_reg[rcv_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedData_Cb != NULL) ) { /* If no CCB for this channel, allocate one */ if (l2cu_initialize_fixed_ccb (p_lcb, rcv_cid, &l2cb.fixed_reg[rcv_cid - L2CAP_FIRST_FIXED_CHNL].fixed_chnl_opts)) { p_ccb = p_lcb->p_fixed_ccbs[rcv_cid - L2CAP_FIRST_FIXED_CHNL]; if (p_ccb->peer_cfg.fcr.mode != L2CAP_FCR_BASIC_MODE) l2c_fcr_proc_pdu (p_ccb, p_msg); else (*l2cb.fixed_reg[rcv_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedData_Cb)(p_lcb->remote_bd_addr, p_msg); } else GKI_freebuf (p_msg); } #endif else { if (p_ccb == NULL) GKI_freebuf (p_msg); else { /* Basic mode packets go straight to the state machine */ if (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_BASIC_MODE) l2c_csm_execute (p_ccb, L2CEVT_L2CAP_DATA, p_msg); else { /* eRTM or streaming mode, so we need to validate states first */ if ((p_ccb->chnl_state == CST_OPEN) || (p_ccb->chnl_state == CST_CONFIG)) l2c_fcr_proc_pdu (p_ccb, p_msg); else GKI_freebuf (p_msg); } } } }