?? rfcomm.c
字號(hào):
static void create_crctable(u8 table[]);static rfcomm_con* get_new_rfcomm_con(void);static rfcomm_con* get_rfcomm_con(u8 line);static s32 get_connected_dlci(rfcomm_con *rfcomm);/****************** GLOBAL VARIABLE DECLARATION SECTION *********************//****************** LOCAL VARIABLE DECLARATION SECTION **********************//* The crctable for the FEC field */static u8 crctable[256];/* One RFCOMM connection for each ttyBTx */rfcomm_con rfcomm_con_list[BT_NBR_DATAPORTS];#ifdef __KERNEL__static struct timer_list rfcomm_timer;#endif#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)static struct wait_queue *rfcomm_disconnect_wq = NULL;#elsestatic wait_queue_head_t rfcomm_disconnect_wq;#endif /* LINUX_VERSION_CODE */rpn_values rpn_val;/****************** FUNCTION DEFINITION SECTION *****************************//**************************************************************************** * Functions reachable outside this file ****************************************************************************/void rfcomm_reset_con(u8 line){ s32 j; /* check if valid line number */ if (line >= BT_NBR_DATAPORTS) { D_ERR(FNC"invalid line!\n"); return; } D_CTRL(FNC"line %d\n", line); rfcomm_con_list[line].magic = RFCOMM_MAGIC; rfcomm_con_list[line].line = line; rfcomm_con_list[line].credit_flow = 0; for (j = 0; j < 62; j++) { rfcomm_con_list[line].dlci[j].local_credits = 0; rfcomm_con_list[line].dlci[j].state = DISCONNECTED; rfcomm_con_list[line].dlci[j].mtu = DEF_RFCOMM_MTU; rfcomm_con_list[line].dlci[j].initiated = FALSE; rfcomm_con_list[line].dlci[j].initiator = FALSE; } rfcomm_con_list[line].initiator = FALSE; rfcomm_con_list[line].l2cap = NULL;}s32rfcomm_module_init(void){#ifdef __KERNEL__#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) init_waitqueue_head(&rfcomm_disconnect_wq);#endif /* LINUX_VERSION_CODE */#endif /* __KERNEL__ */ return 0;}voidrfcomm_init(void){ s32 i; protocol_layer this_layer; DSYS("Initialising RFCOMM\n"); create_crctable(crctable); /* Set the confirm and indication functions for the L2CAP-layer */ this_layer.con_ind = rfcomm_connect_ind; this_layer.con_pnd = rfcomm_connect_pnd; this_layer.conf_ind = rfcomm_config_ind; this_layer.disc_ind = rfcomm_disconnect_ind; this_layer.con_cfm = rfcomm_connect_cfm; this_layer.conf_cfm = rfcomm_config_cfm; this_layer.disc_cfm = rfcomm_disconnect_cfm; this_layer.receive_data = rfcomm_receive_data; /* Register RFCOMM in the L2CAP layer*/ l2cap_register_upper(RFCOMM_LAYER, &this_layer); /* Initiate rfcomm lines */ for (i = 0; i < BT_NBR_DATAPORTS; i++) { rfcomm_reset_con(i); } /* Set the values in the rpn octets */ rpn_val.bit_rate = 7; /* Irrelevent here */ rpn_val.data_bits = 3; /* 8 databits */ rpn_val.stop_bit = 0; /*One stopbit */ rpn_val.parity = 0; rpn_val.parity_type = 0; rpn_val.res1 = 0; rpn_val.xon_input = 0; rpn_val.xon_output = 0; rpn_val.rtr_input = 0; rpn_val.rtr_output = 0; rpn_val.rtc_input = 0; rpn_val.rtc_output = 0; rpn_val.res2 = 0; rpn_val.xon_u8 = 0x11; rpn_val.xoff_u8 = 0x13; memset(&rpn_val.pm, 0 , 2); /* Set the mask to zero */ #ifdef CONFIG_BLUETOOTH_USE_SECURITY_MANAGER rfcomm_sec_man_init();#endif}s32rfcomm_set_mtu(rfcomm_con *rfcomm, u8 dlci, u32 new_mtu){ DSYS(FNC"MTU set to:%d\n", new_mtu); if (rfcomm->dlci[dlci].state == DISCONNECTED) { rfcomm->dlci[dlci].mtu = new_mtu; return 0; } else { return -1; }}static char* state2name(u8 state){ switch(state) { case DISCONNECTED : return "DISCONNECTED"; case CONNECTING : return "CONNECTING"; case NEGOTIATING : return "NEGOTIATING"; case CONNECTED : return "CONNECTED"; case DISCONNECTING : return "DISCONNECTING"; default : return "Invalid State"; }}void rfcomm_close(void){ s32 i; DSYS("Shutting down RFCOMM\n"); /* First try disconnecting */ for (i = 0; i < BT_NBR_DATAPORTS; i++) { rfcomm_con *rfcomm = get_rfcomm_con(i); /* fixme -- handle the case where only the control channel is left on a rfcomm session */ if (get_connected_dlci(rfcomm) > 0) { DSYS(FNC"Now disconnecting rfcomm line %d\n", i); rfcomm_disconnect_req(i); } } /* If still connections left, terminate them */ for (i = 0; i < BT_NBR_DATAPORTS; i++) { rfcomm_reset_con(i); }}/* This function creates an rfcomm connection over the control channel DCLI 0 */ s32 rfcomm_connect_req(u8* bd_addr, u8 server_chn, u8 line){ rfcomm_con *rfcomm; u8 tmp_dlci; s32 retval = 0; D_CTRL(FNC"server channel:%d, line:%d\n", server_chn, line); if (!(rfcomm = get_rfcomm_con(line))) { D_ERR(FNC"%d is an invalid line\n", line); return -MSGCODE(MSG_LAYER_RFCOMM, RFCOMM_INVALID_LINE); } if (rfcomm->dlci[0].state == DISCONNECTED) { rfcomm->initiator = TRUE; } rfcomm->line = line; rfcomm->server_chn = server_chn; tmp_dlci = (server_chn << 1) | (~rfcomm->initiator & 0x1); if (!(rfcomm->l2cap)) { rfcomm->dlci[0].state = CONNECTING; /* we don't have a l2cap connection yet */ if ((retval = l2ca_connect_req(bd_addr, RFCOMM_LAYER)) < 0) { D_ERR(FNC"l2ca_connect_req failed\n"); return retval; } } else if (!((rfcomm->l2cap)->current_state == OPEN)) { D_ERR(FNC"L2CAP_CON exists but is not in OPEN state (yet?)\n"); /* FIXME: Should we really return no error here? */ return 0; } else if (rfcomm->dlci[0].state != CONNECTED) { /* we have an l2cap channel (server ch) */ D_CTRL(FNC"we already have an l2cap channel)\n"); /* fixme -- strange case ... */ if (rfcomm->dlci[0].state != DISCONNECTED) { D_ERR(FNC"DLCI:0 neither CONNECTED nor DISCONNECTED\n"); return -1; } else { rfcomm->dlci[0].state = CONNECTING; /* Establish the control channel */ return send_sabm(rfcomm, 0); } } else if (rfcomm->dlci[tmp_dlci].state != DISCONNECTED) { D_ERR(FNC"trying to connect a non DISCONNECTED server channel (%d)\n",server_chn); return -MSGCODE(MSG_LAYER_RFCOMM, RFCOMM_SRVCHN_CONNECTED); } else { D_CTRL(FNC"We are negotiating rfcomm (pn msg)\n"); rfcomm->dlci[tmp_dlci].state = NEGOTIATING; /* must fit i l2cap mtu */ D_CTRL(FNC"negotiate mtu : %d bytes\n", rfcomm->l2cap->remote_mtu - 5); return send_pn_msg(rfcomm, 7, rfcomm->dlci[tmp_dlci].mtu, 0, 0, tmp_dlci, TRUE); } return 0;}/* fixme -- this should be on dlci/rfcomm con basis not line ... */s32rfcomm_disconnect_req(u8 line){ rfcomm_con *rfcomm; s32 tmp; D_CTRL("rfcomm_disconnect_req %d\n", line); if(line >= BT_NBR_DATAPORTS) { D_ERR("rfcomm_disconnect_req : Invalid line\n"); return -MSGCODE(MSG_LAYER_RFCOMM, RFCOMM_INVALID_LINE); } if (!(rfcomm = &rfcomm_con_list[line])) { D_ERR("rfcomm_disconnect_req : no rfcomm con\n"); return -EINVAL; } tmp = get_connected_dlci(rfcomm); if (tmp > 0) { l2cap_con *l2cap = rfcomm->l2cap; rfcomm->dlci[tmp].state = DISCONNECTING; send_disc(rfcomm, tmp);#ifdef __KERNEL__ start_wq_timer(&rfcomm_timer, RFCOMM_CON_TIMEOUT, &rfcomm_disconnect_wq);#endif /* FIXME -- check that we haven't already received disconnect 'acknowledge' */ interruptible_sleep_on(&rfcomm_disconnect_wq); /* Check that rfcomm session really disconnected */ /* FIXME -- add timer obj with status in rfcomm obj */ /* check control channel */ if (rfcomm->dlci[0].state != DISCONNECTED) { D_ERR("Rfcomm disconnect failed, reset session\n");#ifdef __KERNEL__ bt_unregister_rfcomm(rfcomm->line); bt_disconnect_cfm(CREATE_RFCOMM_ID(rfcomm->line, 0), rfcomm->l2cap->c_result);#endif rfcomm_reset_con(rfcomm->line); } /* Now rfcomm is disconnected, disconnect l2cap */ return l2ca_disconnect_req(l2cap); } else D_WARN("rfcomm_disconnect_req : line not connected !\n"); return 0;} /* The lower protocol layer, L2CAP, indicates that a new connection has been established at a lower layer. RFCOMM should ask the control block whether to accept or reject the connection and then reply to L2CAP with l2cap_connect_rsp. */void rfcomm_connect_ind(l2cap_con *l2cap){ rfcomm_con *rfcomm; D_CTRL("rfcomm_connect_ind\n"); if (!(rfcomm = get_new_rfcomm_con())) { D_ERR("rfcomm_connect_ind: error: couldn't find free tty\n"); /* fixme -- respond neg ! */ return; } else { if (l2ca_connect_rsp(l2cap, RES_SUCCESS, STAT_NOINFO)) { D_ERR("rfcomm_connect_ind: l2ca_connect_rsp failed\n"); return; } rfcomm->initiator = FALSE; rfcomm->dlci[0].state = CONNECTING; rfcomm->l2cap = l2cap; l2cap->upper_con = (void*) rfcomm; }}/* only client receives connect pnd */void rfcomm_connect_pnd(l2cap_con *l2cap, s32 status){ printk("rfcomm_connect_pnd : reason %d\n", status); }void rfcomm_connect_cfm(l2cap_con *l2cap, s32 status){ s32 i = 0; s32 stop = FALSE; rfcomm_con *rfcomm = NULL; D_CTRL(FNC"status %d\n", status); /* FIXME -- use bt session list (which holds pointers to all layers con objs) to see which rfcomm that was trying to connect */ /* Find the connecting rfcomm_con */ while ((i < BT_NBR_DATAPORTS) && (!stop)) { if ((rfcomm_con_list[i].dlci[0].state == CONNECTING) && (rfcomm_con_list[i].initiator == TRUE)) { rfcomm = &rfcomm_con_list[i]; stop = TRUE; } i++; } if (status) { /* reset this rfcomm connection !*/ rfcomm_reset_con(rfcomm->line); bt_connect_cfm(CREATE_RFCOMM_ID(rfcomm->line,0), status); return; } if (rfcomm != NULL) { rfcomm->l2cap = l2cap; l2cap->upper_con = (void*) rfcomm; if (!l2ca_local_conf_done(l2cap)) { /* still haven't sent config request yet */ /* Zero indicates that default values will be used */ if (l2ca_config_req(l2cap, 0, NULL, 0, 0)) { D_ERR(FNC"l2ca_config_req failed\n"); } } else DSYS(FNC"already have sent back a pos response\n"); } else { D_ERR(FNC"couldn't find the correct rfcomm_con object\n"); }}/* The lower protocol layer, L2CAP, indicates that it has received a configuration indication signal and RFCOMM should reply with proper configuration parameters to the L2CAP layer, with a l2cap_config_rsp messages and then send a own configuration request messages. */void rfcomm_config_ind(l2cap_con* l2cap){ /* FIXME Check whether the received params are acceptable, accept all for now */ D_CTRL("rfcomm_config_ind : remote cid %d\n", l2cap->remote_cid); /* check if we have sent a pos response yet */ if (!l2ca_remote_conf_done(l2cap)){ /* still haven't sent a pos configure response*/ if (l2ca_config_rsp(l2cap, l2cap->remote_mtu, NULL, CONF_SUCCESS)) { D_ERR(FNC"l2ca_config_rsp failed\n"); } } else DSYS(FNC"already have sent back a pos response\n"); /* check if we received a pos response on a previous conf req */ if (((rfcomm_con*) l2cap->upper_con)->initiator == FALSE) { /* check if we received a pos response on a previous config req */ if (!l2ca_local_conf_done(l2cap)) { l2cap->local_mtu=l2cap->remote_mtu; DSYS(FNC"Local l2cap mtu set to %d\n", l2cap->local_mtu); if (l2ca_config_req(l2cap, 0, NULL, 0, 0)) { D_ERR(FNC"l2ca_config_req failed\n"); } } else DSYS(FNC"already ready with config req\n"); } }/* The lower protocol layer, L2CAP, indicates that the configuration procedure has succeeded */void rfcomm_config_cfm(l2cap_con *l2cap, s32 status){ rfcomm_con *rfcomm; rfcomm = (rfcomm_con *) l2cap->upper_con; D_CTRL(FNC"\n"); if (status) { DSYS(FNC"l2cap configuration failed\n"); /* notify usermode and reset connection */ bt_connect_cfm(CREATE_RFCOMM_ID(rfcomm->line,0), status); rfcomm_reset_con(rfcomm->line); return; } else { DSYS(FNC"l2cap is now open\n"); if (rfcomm->initiator && rfcomm->dlci[0].state == CONNECTING) { D_CTRL("sending sabm\n"); send_sabm(rfcomm, 0); } else if (!rfcomm->initiator && ((l2cap->remote_mtu-5) < DEF_RFCOMM_MTU) ) { s32 j; DSYS(FNC"Setting RFCOMM frame size to %d\n", l2cap->remote_mtu-5); for (j = 0; j < 62; j++) { rfcomm->dlci[j].mtu = (l2cap->remote_mtu-5); } } } }
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -