📄 rfcomm.c
字号:
{ rfcomm_con *rfcomm; short_frame *short_pkt; long_frame *long_pkt; u8* uih_data_start; u32 uih_len; u8 tmp_dlci; RF_DATA(FNC"rfcomm_receive_data:",data,len); D_REC(FNC"%d bytes, our cid is %d\n",len, l2cap->remote_cid); short_pkt = (short_frame*) data; tmp_dlci = (((short_pkt->h.addr.server_chn & 0x1f) << 1) | (short_pkt->h.addr.d & 0x1)); switch (CLR_PF(short_pkt->h.control)) { case SABM: D_CTRL(FNC"SABM-packet received\n"); if (crc_check((u8*) short_pkt, LONG_CRC_CHECK, short_pkt->data[0]) < 0) { break; } /* If the SABM command wants to open the control channel, we have to create a new rfcomm_con object */ if ((tmp_dlci) == 0) { D_CTRL(FNC"server channel == 0\n"); rfcomm = ((rfcomm_con*) l2cap->upper_con); D_CTRL(FNC"setting l2cap_con, no serv.channel yet\n"); rfcomm->dlci[0].state = CONNECTED; D_CTRL(FNC"sending back UA - control channel\n"); send_ua((rfcomm_con*) l2cap->upper_con, tmp_dlci); bt_connect_ind(CREATE_RFCOMM_ID(rfcomm->line, 0)); } /* If the channel isn't the control channel, we know that the object exist. If we haven't opened any other channel than the control channel we open the new channel here */ else if (valid_dlci(tmp_dlci)) { rfcomm = ((rfcomm_con*) l2cap->upper_con); D_REC(FNC"setting server channel %d\n", short_pkt->h.addr.server_chn);#ifdef CONFIG_BLUETOOTH_USE_SECURITY_MANAGER rfcomm_check_allowed_security(rfcomm->l2cap->remote_bd, tmp_dlci, rfcomm); /* fixme -- check result and send neg response if not allowed */ #else bt_connect_ind(CREATE_RFCOMM_ID(rfcomm->line, tmp_dlci)); rfcomm->dlci[tmp_dlci].state = CONNECTED; /* registers in bt driver */ bt_register_rfcomm(rfcomm, tmp_dlci); /* wake up any blocking connect/waits */ bt_connect_cfm(CREATE_RFCOMM_ID(rfcomm->line, tmp_dlci), 0 /* status ok*/ ); D_CTRL(FNC"sending back UA - other channel\n"); send_ua(rfcomm, tmp_dlci);#endif /* CONFIG_BLUETOOTH_USE_SECURITY_MANAGER */ } else { D_CTRL(FNC"no server on channel %d, sending DM\n", tmp_dlci); send_dm(((rfcomm_con*) l2cap->upper_con),tmp_dlci); } break; case UA: rfcomm = ((rfcomm_con*) l2cap->upper_con); if (rfcomm->magic != RFCOMM_MAGIC) { D_ERR(FNC"Invalid magic number\n"); break; } D_CTRL(FNC"UA packet received on line %d\n", rfcomm->line); if (rfcomm->dlci[0].state == CONNECTING) { /* Now we are the initiating side and we have got a respons to our SABM command. We then send a PN messages to negotiat the frame length */ rfcomm->dlci[0].state = CONNECTED; tmp_dlci = ((rfcomm->server_chn << 1) | ((~rfcomm->initiator) & 0x1)); /* must fit in l2cap mtu incl rfcomm hdrs */ send_pn_msg(rfcomm, 7, rfcomm->dlci[tmp_dlci].mtu, 0, 0, tmp_dlci, TRUE); rfcomm->dlci[tmp_dlci].state = NEGOTIATING; } else if (rfcomm->dlci[tmp_dlci].state == NEGOTIATING) { rfcomm->dlci[tmp_dlci].state = CONNECTED; /* registers in bt driver */ bt_register_rfcomm(rfcomm, tmp_dlci); /* wake up any blocking connect/waits */ bt_connect_cfm(CREATE_RFCOMM_ID(rfcomm->line, tmp_dlci), 0 /* status ok*/ ); D_CTRL(FNC"successfully connected on DLCI:%d\n", tmp_dlci); /* FIXME: Should we always do this ? */ rfcomm_msc_msg(rfcomm, EA | RTC | RTR | DV, MCC_CMD, tmp_dlci); rfcomm->dlci[tmp_dlci].initiator = TRUE; } else if (rfcomm->dlci[tmp_dlci].state == DISCONNECTING) { if (tmp_dlci == 0) { /* Control channel */#ifdef __KERNEL__ release_wq_timer(&rfcomm_timer);#endif DSYS(FNC"RFCOMM disconnected ctrl ch (local) on line [%d]\n", rfcomm->line); rfcomm->dlci[0].state = DISCONNECTED; /* this will take down l2cap aswell */ wake_up_interruptible(&rfcomm_disconnect_wq); } else { /* Data channel */ s32 tmp; rfcomm->dlci[tmp_dlci].state = DISCONNECTED; tmp = get_connected_dlci(rfcomm); if (tmp >= 0) { rfcomm->dlci[tmp].state = DISCONNECTING; send_disc(rfcomm, tmp); } else { D_ERR("Could not find connected DLCI\n"); } } } else if (rfcomm->dlci[tmp_dlci].state == DISCONNECTED) { rfcomm->dlci[tmp_dlci].state = CONNECTED; } else { D_WARN(FNC" Something wrong receiving UA packet\n"); } break; /* Disconnect mode, 'NAK on SABM/DISC' */ case DM: D_CTRL(FNC"DM packet received\n"); rfcomm = ((rfcomm_con*) l2cap->upper_con); rfcomm->dlci[tmp_dlci].state = DISCONNECTED; /* Notify upper tty */ /* bt_disconnect_ind() ? */ break; case DISC: D_CTRL(FNC"DISC packet received\n"); if (crc_check(data, LONG_CRC_CHECK, short_pkt->data[0]) < 0) { break; } rfcomm = ((rfcomm_con*) l2cap->upper_con); /* When the serverchannel is closing the whole connection should be removed */ if (rfcomm->dlci[tmp_dlci].state == DISCONNECTED) { send_dm(rfcomm, tmp_dlci); } else if ((short_pkt->h.addr.server_chn) == 0) { rfcomm->dlci[0].state = DISCONNECTED; DSYS("RFCOMM control ch disconnected (remotely) [line:%d]\n", rfcomm->line); send_ua(rfcomm, 0); } else { rfcomm->dlci[tmp_dlci].state = DISCONNECTED; send_ua(rfcomm, tmp_dlci); D_CTRL("dlci %d was disconnected\n", tmp_dlci); bt_disconnect_ind(CREATE_RFCOMM_ID(rfcomm->line, tmp_dlci));#ifdef __KERNEL__ bt_unregister_rfcomm(rfcomm->line);#endif } break; case UIH: rfcomm = ((rfcomm_con*) l2cap->upper_con); if ((short_pkt->h.length.ea) == 0) { /* Then we cast the rfcomm packet to a long rfcomm packet */ D_REC(FNC"Long UIH packet received\n"); long_pkt = (long_frame*) data; swap_long_frame(long_pkt); uih_len = long_pkt->h.length.bits.len; uih_data_start = long_pkt->h.data; D_REC(FNC"long packet length %d\n", uih_len); if (uih_len > (len - 5)) { D_WARN(FNC", Long packet length doesn't match, setting length to l2cap len - 5\n"); uih_len = len - 5; } } else { D_REC(FNC"Short UIH pkt received\n"); uih_len = short_pkt->h.length.len; uih_data_start = short_pkt->data; if (uih_len > (len - 4)) { D_WARN(FNC", Short packet length doesn't match, setting length to l2cap len - 4\n"); uih_len = len - 4; } } if (GET_PF(short_pkt->h.control)) { D_REC(FNC" %d more credits on dlci:%d...\n", *uih_data_start, tmp_dlci); rfcomm->dlci[tmp_dlci].local_credits += uih_data_start[0];#ifdef __KERNEL__ bt_feedstack();#endif D_REC(FNC"Local_credits:%d\n", rfcomm->dlci[tmp_dlci].local_credits); uih_data_start++; if (uih_len == 0) { break; } /* feed uih data to tty if any */ } if (crc_check(data, SHORT_CRC_CHECK, *(uih_data_start + uih_len)) < 0) { break; } if (short_pkt->h.addr.server_chn == 0) { D_REC(FNC"UIH on serv_channel 0\n"); process_mcc(data, len, rfcomm, !(short_pkt->h.length.ea)); } else { u32 con_id = CREATE_RFCOMM_ID(rfcomm->line, tmp_dlci); if (rfcomm->credit_flow) { --rfcomm->dlci[tmp_dlci].remote_credits; D_CTRL(FNC": Remote credits: %d\n",rfcomm->dlci[tmp_dlci].remote_credits); if (rfcomm->dlci[tmp_dlci].remote_credits < MIN_CREDITS) { u8 newcredits = MAX_CREDITS - rfcomm->dlci[tmp_dlci].remote_credits; rfcomm_send_credits(rfcomm, tmp_dlci, newcredits); rfcomm->dlci[tmp_dlci].remote_credits += newcredits; D_SND(FNC"Remote credits: %d\n",rfcomm->dlci[tmp_dlci].remote_credits); } } bt_receive_top(con_id, uih_data_start, uih_len); } break; default: D_REC(FNC"illegal packet\n"); break; }}/* Copies the tty data into the stack and creates headers and FCS, then the packet is sent to the lower layer L2CAP. The packet must not be larger than the actual MTU for the L2CAP layer. */s32 rfcomm_send_data(u32 con_id, u8 *data, u32 count){ u32 c; u32 total = 0; u8 line; u8 dlci; rfcomm_con *rfcomm; line = GET_LINE(con_id); dlci = GET_RFCOMMDLCI(con_id); if (dlci == 0) { D_ERR(FNC"Not allowed to send data on DLCI 0\n"); return -MSGCODE(MSG_LAYER_RFCOMM, RFCOMM_NO_DATA_ALLOWED); } rfcomm = &rfcomm_con_list[line]; RF_DATA(FNC, data, count); if (rfcomm == NULL) { D_ERR(FNC" ERROR rfcomm_con == NULL\n"); return -MSGCODE(MSG_LAYER_RFCOMM, RFCOMM_NO_CONNECTION); } else if (rfcomm->magic != RFCOMM_MAGIC) { D_ERR(FNC"ERROR magic test failed\n"); return -MSGCODE(MSG_LAYER_RFCOMM, RFCOMM_BAD_MAGIC_NUMBER); } else if(rfcomm->dlci[0].state == FLOW_STOPPED) { D_SND(FNC"Flow stopped on all channels, returning zero\n"); return 0; } else if (rfcomm->dlci[dlci].state == FLOW_STOPPED) { D_SND(FNC"Flow stopped, returning zero\n"); return 0; } /* Check whether there are any data channels connected */ else if (rfcomm->dlci[dlci].state == CONNECTED) { D_SND(FNC"trying to send %d bytes\n", count); while (count) { if (rfcomm->credit_flow &&(rfcomm->dlci[dlci].local_credits <= 0)) { D_SND(FNC"Flow stopped, no credits returning %d\n", total); return total; } /* As long as there are anything to send we try to send it. We split the data into parts not bigger than the current MTU size. */ c = MIN(count, rfcomm->dlci[dlci].mtu); /* FIXME: Optimize c! If we try to send 200 bytes and there are only 150 bytes space in buffer, set c to 150 - sizeof(rfcomm_tx_buf) */ c = send_uih(data, c, rfcomm, dlci); if (c < 0) { return c; /* error */ } else if (c == 0) { return total; } else { if (rfcomm->credit_flow) { --rfcomm->dlci[dlci].local_credits; D_SND(FNC"Local credits:%d\n", rfcomm->dlci[dlci].local_credits); } total += c; data += c; count -= c; } } D_SND(FNC"sent %d bytes\n", total); return total; } else { D_ERR(FNC"DLCI %d not connected\n", dlci);#ifdef __KERNEL__ /* FIXME - should we return an _error_ if rfcomm isn't up yet or only tell user process that 0 bytes was written ??? */ return 0;#else return -1;#endif }}s32rfcomm_flow_stop(u8 line, u8 dlci){ if (rfcomm_con_list[line].credit_flow &&(rfcomm_con_list[line].dlci[dlci].local_credits <= 0)) { return TRUE; } else if (rfcomm_con_list[line].dlci[dlci].state == FLOW_STOPPED) { return TRUE; } else if (rfcomm_con_list[line].dlci[0].state == FLOW_STOPPED) { return TRUE; } else { return FALSE; }}void rfcomm_send_testdata(u32 count, u8 line){ static u8 testdata[1024]; static s32 testdata_init = 0; s32 i; u32 con_id = CREATE_RFCOMM_ID(line, PPP_DLCI); DSYS("rfcomm_send_testdata: sending %d bytes\n",count); if (!testdata_init) { for (i = 0; i < 1024; i++) { testdata[i] = (i%25)+ 65; } } rfcomm_send_data(con_id, testdata, count);}/* Parses a multiplexer control channel packet */void process_mcc(u8* data, u32 len, rfcomm_con *rfcomm, s32 longpkt){ mcc_short_frame *mcc_short_pkt; D_CTRL("process_mcc\n"); if (longpkt) { mcc_short_pkt = (mcc_short_frame*)(((long_frame*)data)->data); } else { mcc_short_pkt = (mcc_short_frame*)(((short_frame*)data)->data); } switch (mcc_short_pkt->h.type.type) { case TEST: if (mcc_short_pkt->h.type.cr == MCC_RSP) { D_CTRL(FNC"Received test command\n"); } else { if ((mcc_short_pkt->h.length.ea) == 0) { mcc_long_frame *mcc_long_pkt; mcc_long_pkt = (mcc_long_frame*) mcc_short_pkt; swap_mcc_long_frame(mcc_long_pkt); rfcomm_test_msg(rfcomm, mcc_long_pkt->value, mcc_long_pkt->h.length.bits.len, MCC_RSP); } else { rfcomm_test_msg(rfcomm, mcc_short_pkt->value, mcc_short_pkt->h.length.len, MCC_RSP); } } break; case FCON: /* Flow control on command */ D_CTRL(FNC"Received Flow control on command\n"); if (mcc_short_pkt->h.type.cr == MCC_CMD) { rfcomm->dlci[0].state = CONNECTED; rfcomm_fcon_msg(rfcomm, MCC_RSP); } break; case FCOFF: /* Flow control off command */ D_CTRL(FNC"Received Flow control off command\n"); if (mcc_short_pkt->h.type.cr == MCC_CMD) { rfcomm->dlci[0].state = FLOW_STOPPED; rfcomm_fcoff_msg(rfcomm, MCC_RSP); } break; case MSC: /* Modem status command */ { u8 dlci; u8 v24_sigs; dlci = (mcc_short_pkt->value[0]) >> 2; v24_sigs = mcc_short_pkt->value[1]; if (rfcomm->dlci[dlci].state == DISCONNECTED) { send_dm(rfcomm, dlci); break; } if (mcc_short_pkt->h.type.cr == MCC_CMD) { D_CTRL(FNC"Received Modem status command\n"); if (v24_sigs & 2) { D_CTRL(FNC"Device unable to accept frames\n"); rfcomm->dlci[dlci].state = FLOW_STOPPED; } else { rfcomm->dlci[dlci].state = CONNECTED; D_CTRL(FNC"Flow ON, dlci %d\n", dlci); } rfcomm_msc_msg(rfcomm, v24_sigs, MCC_RSP, dlci); if (!(rfcomm->dlci[dlci].initiated) && !(rfcomm->dlci[dlci].initiator)) { rfcomm_msc_msg(rfcomm, EA | RTR | RTC | DV, MCC_CMD, dlci); rfcomm->dlci[dlci].initiated = TRUE; } } else { D_CTRL(FNC"Received Modem status response\n"); if (v24_sigs & 2) { D_CTRL(FNC"Flow stop accepted\n"); } } break; } case RPN: /* Remote port negotiation command */ { u8 tmp_dlci; tmp_dlci = (mcc_short_pkt->value[0]) >> 2; if (mcc_short_pkt->h.type.cr == MCC_CMD) { if (mcc_short_pkt->h.length.len == 1) { D_CTRL(FNC"Received Remote port negotiation command\n"); rfcomm_rpn_msg(rfcomm, MCC_RSP, tmp_dlci, 0); } else { /* Accept the other sides settings (accept all for now) */ D_CTRL(FNC"Received Remote port negotiation respons\n"); memcpy(&rpn_val, &mcc_short_pkt->value[1], 8); rfcomm_rpn_msg(rfcomm, MCC_RSP, tmp_dlci, 0);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -