📄 l2cap.c
字号:
#ifdef CONFIG_BLUETOOTH_L2CAP_USE_TIMERS disable_rtx(con);#endif ENTERSTATE(con, CONFIG); PRINTSTATE(con); l2ca_connect_cfm(con, conrsp->result); break; case RES_PENDING: /* wake up when real con resp comes */ l2ca_connect_pnd(con, conrsp->status);#ifdef CONFIG_BLUETOOTH_L2CAP_USE_TIMERS /* Disable RTX timer and start ERTX */ disable_rtx(con); start_ertx(con, ERTX_TIMEOUT);#endif D_STATE(__FUNCTION__ ": connection pending\n"); break; case RES_PSMNEG: DSYS(__FUNCTION__ ": connection refused, psm 0x%x not supp\n", con->psm); failure = 1; break; case RES_SECNEG: DSYS(__FUNCTION__ ": connection refused, security block\n"); failure = 1; break; case RES_NOSRC: DSYS(__FUNCTION__ ": connection refused, no resources\n"); failure = 1; break; default: D_ERR(__FUNCTION__ ": SIG_CONRSP\n"); break; } if (failure) {#ifdef CONFIG_BLUETOOTH_L2CAP_USE_TIMERS disable_rtx(con); disable_ertx(con);#endif l2ca_connect_cfm(con, MSGCODE(MSG_LAYER_L2CAP, conrsp->result)); l2ca_wakeup("Got connect rsp neg", con); ENTERSTATE(con, CLOSED); delete_con(con); } break; case SIG_CONFRSP: D_STATE(__FUNCTION__ ": Got configuration response\n"); confrsp = (sig_confrsp *)rsp->data; confrsp->src_cid = le16_to_cpu(confrsp->src_cid); confrsp->flags = le16_to_cpu(confrsp->flags); confrsp->result = le16_to_cpu(confrsp->result); opt_len = rsp->len - sizeof(sig_confrsp); PRINTPKT(__FUNCTION__ ": config response", rsp->data, rsp->len); /* check that remote CID is in list */ if ((con = get_lcon(confrsp->src_cid)) == NULL) return; if (con->current_state != CONFIG) { D_ERR(__FUNCTION__ ": SIG_CONFRSP invalid state\n"); PRINTSTATE(con); return; } /* match id with request */ if (!id_matched(con, rsp->id)) { D_ERR(__FUNCTION__ ": ID doesn't match ! [%d:%d]\n", con->sig_id_sent, rsp->id); return; } switch (confrsp->result) { case CONF_SUCCESS:#ifdef CONFIG_BLUETOOTH_L2CAP_USE_TIMERS disable_rtx(con);#endif con->conf_req_ready = TRUE; if (!con->conf_rsp_ready) { /* Upper layers still haven't replied pos */ D_STATE(__FUNCTION__": Still haven't replied pos on other sides conf req\n"); return ; } else { ENTERSTATE(con, OPEN); PRINTSTATE(con); DSYS("l2cap channel (%d,%d) [%s] connected\n", con->local_cid, con->remote_cid, psm2str(con->psm)); /* notify upper layers that we successfully opened a connection ! */ l2ca_config_cfm(con, confrsp->result); /* reset variable */ con->conf_req_sent = 0; return; } case CONF_FAILURE: /* store remote side configuration */ parse_options(con, confrsp->options, opt_len); D_STATE(__FUNCTION__ ": config failure, unacceptable params\n"); l2ca_config_cfm(con, confrsp->result); break; case CONF_REJ: D_STATE(__FUNCTION__ ": connection refused, no reason\n"); l2ca_config_cfm(con, confrsp->result); break; case CONF_UNKNOWN: D_STATE(__FUNCTION__ ": connection refused, unknown options\n"); l2ca_config_cfm(con, confrsp->result); break; default: D_ERR(__FUNCTION__ ": SIG_CONFRSP\n"); break; } /* If we end up here, config failed */#ifdef CONFIG_BLUETOOTH_L2CAP_USE_TIMERS disable_rtx(con);#endif if (con->current_state != CONFIG) D_ERR(__FUNCTION__ ": SIG_CONFRSP invalid state\n"); PRINTSTATE(con); /* print failed options */ if (opt_len > 0) print_data("Options not accepted\n", confrsp->options, rsp->len - sizeof(sig_confrsp)); break; case SIG_DISCRSP: D_STATE(__FUNCTION__ ": Got disconnect response\n"); discrsp = (sig_discrsp *)rsp->data; discrsp->dst_cid = le16_to_cpu(discrsp->dst_cid); discrsp->src_cid = le16_to_cpu(discrsp->src_cid); PRINTPKT(__FUNCTION__ ": disconnect response", rsp->data, rsp->len); /* find connection */ if ((con = get_lcon(discrsp->src_cid)) == NULL) return; if (con->current_state != W4_L2CAP_DISCONNECT_RSP) { D_ERR(__FUNCTION__ ": SIG_DISCRSP invalid state\n"); PRINTSTATE(con); return; } /* match id with request */ if (!id_matched(con, rsp->id)) { D_ERR(__FUNCTION__ ": ID doesn't match ! [%d:%d]\n", con->sig_id_sent, rsp->id); return; } con->c_status = CSTATUS_SUCCESS; #ifdef CONFIG_BLUETOOTH_L2CAP_USE_TIMERS disable_rtx(con);#endif con->c_result = RES_SUCCESS; l2ca_disconnect_cfm(con); l2ca_wakeup("l2cap disc rsp", con); break; case SIG_ECHORSP: { l2cap_con *tempcon; D_STATE(__FUNCTION__ ": Got echo response\n"); if ((tempcon = get_con_hcihdl(hci_handle))==NULL) { D_STATE(__FUNCTION__": Echo rsp, could not find connection\n"); return; } echo = (sig_echo_pkt *)(rsp->data); opt_len = rsp->len; if (opt_len > 0) PRINTPKT(__FUNCTION__ ": optional data ", echo->data, rsp->len-sizeof(sig_echo_pkt));#ifdef CONFIG_BLUETOOTH_L2CAP_USE_TIMERS disable_rtx(tempcon);#endif /* now wake up l2ca_ping */ tempcon->c_status = CSTATUS_SUCCESS; tempcon->c_result = RES_SUCCESS; l2ca_wakeup("echo resp received", tempcon); break; } case SIG_INFORSP: { l2cap_con *tempcon; if ((tempcon = get_con_hcihdl(hci_handle))==NULL) { D_STATE(__FUNCTION__": Echo rsp, could not find connection\n"); return; } info = (sig_info_rsp *)(rsp->data); info->type = le16_to_cpu(info->type); info->result = le16_to_cpu(info->result); D_STATE(__FUNCTION__ ": Got info response: result %d\n", info->result);#ifdef CONFIG_BLUETOOTH_L2CAP_USE_TIMERS disable_rtx(tempcon);#endif /* now wake up l2ca_ping */ tempcon->c_status = RES_SUCCESS; l2ca_wakeup("info resp received", tempcon); break; } default: /* Not a valid command */ DSYS(__FUNCTION__ ": Invalid command 0x%x\n", rsp->code); l2cap_cmdrej(hci_handle, CMDREJ_NOTUNDERSTOOD, NULL, 0); break; }}/*******************************************************************//*-------------------------- EVENTS -------------------------------*//*******************************************************************//* Events are all incoming messages to the L2CA layer along with the timeouts. Events are partitioned into five categories : 1. Indications and confirms from lower layers 2. Signal requests and responses from peers 3. L2CAP to L2CAP Data 4. Requests and responses from upper layers 5. Events caused by timers *//*******************************************************************//* (E1) Lower layer to l2cap *//****************************//* Indicates the lower protocol has successfully established connection */void lp_connect_ind(BD_ADDR bd_addr){ PRINTPKT(__FUNCTION__ ": from: ", bd_addr, 6); /* Check BD_ADDR */ if (!bd_addr[0] && !bd_addr[1] && !bd_addr[2] && !bd_addr[3] && !bd_addr[4] && !bd_addr[5]) { D_ERR(__FUNCTION__ ": no BD addr\n"); return; } /* FIXME - add check with control block if this bd_addr is allowed */ /* We are server and creates an l2cap connection object which we set hci handle when we received lp_connect_cfm */ /* Denying a connection at this state does not allow SDP queries when max amount of connections is reached*/ if (hci_ctrl.nbr_of_connections < bt_max_connections) { D_CON(__FUNCTION__ ": Accepting connection\n"); l2cap_create_con(bd_addr); lp_connect_rsp(bd_addr, 1); } else { D_CON(__FUNCTION__ ": Denying connection. Current connections: %d, max connections: %d\n", hci_ctrl.nbr_of_connections, bt_max_connections); lp_connect_rsp(bd_addr, 0); }} /* is called when we accept a _new_ baseband connection */void l2cap_create_con(BD_ADDR bd){ l2cap_con *con; D_RCV(__FUNCTION__ "\n"); PRINTPKT(__FUNCTION__ ": bd ", bd, 6); /* create a new l2cap connection obj and insert it in list */ /* HACK! - remote CID = 0 indicates that remote cid has not ' been set yet */ con = create_con(0 /* not yet set*/ , get_cid(), 0/*not yet set*/); /* Check connection */ if (con == NULL) { D_ERR(__FUNCTION__ ": no connection created"); return; } con->link_up = TRUE; memcpy(con->remote_bd, bd, 6); /* have not received l2cap connection req yet */ ENTERSTATE(con, CLOSED); insert_con(con); return;}/* Confirms the request to establish a baseband connection*/ s32lp_connect_cfm(u8 *bd_addr, u32 status, u16 con_hdl){ l2cap_con *con; u8 rev_bd[6]; s32 i; D_STATE(__FUNCTION__ ": %s (hci_handle : %d)\n", get_err_msg(status), con_hdl); /* reverse byte order */ for (i = 0; i < 6; i++) { rev_bd[5-i] = bd_addr[i]; } D_STATE(__FUNCTION__ ": bd %s\n", bd2str(rev_bd)); /* FIXME -- use bt session list to notify upper layers that con failed !!! */ /* search for the corresponding l2cap connection */ if ((con = get_con(bd_addr, CLOSED)) == NULL) { D_ERR(__FUNCTION__ ": couldn't find l2cap con!\n"); return 0; } con->c_status = status; con->c_result = status; if (status == 0) { /* pos cfm */ con->hci_hdl = con_hdl; con->link_up = TRUE; /* see if there is someone to wakeup */ l2ca_wakeup("lp_connect_cfm (pos)", con); if (con->c_flags & FLAG_RETURNNOW) { D_STATE(__FUNCTION__" Return NOW\n"); /* clear flag & set status */ con->c_flags &= ~FLAG_RETURNNOW; return 0; } if (!(con->initiator)) { D_STATE("We are server\n"); /* now wait for a connection request */ } else { D_STATE("We are client\n"); PRINTPKT(__FUNCTION__ ": HCI connected to ", bd_addr, 6); ENTERSTATE(con, W4_L2CAP_CONNECT_RSP); PRINTSTATE(con); l2ca_wakeup(__FUNCTION__, con); } return 1; } else { /* neg cfm */ D_STATE(__FUNCTION__ ": (neg) %s\n",get_err_msg(status)); con->link_up = FALSE; l2ca_wakeup(__FUNCTION__ " (neg)", con); if (con->c_flags & FLAG_RETURNNOW) { con->c_flags &= ~FLAG_RETURNNOW; return 0; } if (con->initiator) { /* only notify upper layers if we are initiator */ l2ca_connect_cfm(con, MSGCODE(MSG_LAYER_HCI, status)); } else { /* delete connection if non-initiator */ delete_con(con); } return 0; }} /* Indicates that one of the baseband connections has been shutdown */s32lp_disconnect_ind(u32 con_hdl){ l2cap_con *con; s32 found = 0; /* temp link down */ DSYS(__FUNCTION__": Connection handle %d disconnected\n", con_hdl); /* find & notify/remove l2cap connection(s) on this hci handle */ SHOW_LIST(); while (((con = get_con_hcihdl(con_hdl)) != NULL)) { D_STATE("l2cap connection (%d:%d) found on handle %d\n", con->local_cid, con->remote_cid, con_hdl); D_STATE("now closing it...\n"); PRINTSTATE(con); /* flag phys link as down */ con->link_up = FALSE;#ifdef CONFIG_BLUETOOTH_L2CAP_USE_TIMERS /* cancel any outstanding timers */ disable_rtx(con); disable_ertx(con);#endif /* if not connected yet simply remove it */ if (con->current_state == CLOSED) { D_STATE("connection closed, remove it!\n"); delete_con(con); } else { ENTERSTATE(con, W4_L2CA_DISCONNECT_RSP); DSYS("closing l2cap con (%d,%d)\n", con->local_cid, con->remote_cid); /* notify upper layers that phys link is down */ get_upper(con->psm)->disc_ind(con); } found = 1; } D_CON(__FUNCTION__ ": no more l2cap cons on this handle\n"); /* flush old buffers waiting to be sent on this handle */ btmem_flushhandle((u16)con_hdl); return found;}/* FIXME - lp_qos_violation_ind() *//* FIXME - lp_qos_cfm() */ /********************************************************************//* (E2) l2cap to l2cap signalling *//*********************************//* is handled in signal_handler() *//******************************************************************//* (E3) L2CAP to L2CAP Data*//**************************/void process_frame(l2cap_con *con, u8 *data, u32 len){ PRINTPKT(__FUNCTION__ ": ", data, len); if (len > (con->local_mtu)) { DSYS("l2cap process_frame : len > local_mtu (%ld/%d)\n", (long)(len - L2CAP_HDRSIZE), con->local_mtu); l2cap_cmdrej(con->hci_hdl, CMDREJ_MTUEXCEEDED, NULL, 0); return; } get_upper(con->psm)->receive_data(con, data, len);}/**************************************************************//* (E4) Upper layers to l2cap *//*****************************/s32 l2ca_connect_req(BD_ADDR bd, u16 psm){ l2cap_con *con; l2cap_con *tmpcon;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -