?? rfcomm.c
字號:
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); /* Zero the parametermask after respons */ memset(&rpn_val.pm, 0, 2); } } break; } case RLS: /* Remote line status */ { u8 tmp_dlci; u8 err_code; D_CTRL(FNC"Received Remote line status\n"); if (mcc_short_pkt->h.type.cr == MCC_CMD) { tmp_dlci = mcc_short_pkt->value[0] >> 2; err_code = mcc_short_pkt->value[1]; rfcomm_rls_msg(rfcomm, MCC_RSP, tmp_dlci, err_code); } break; } case PN: /* DLC parameter negotiation */ { pn_msg *pn_pkt; D_CTRL(FNC"Received DLC parameter negotiation, PN\n"); if (longpkt) { /* If a long length field is used, then move the payload pointer one byte ahead */ data++; } pn_pkt = (pn_msg*) data; if (pn_pkt->mcc_s_head.type.cr == MCC_CMD) { u8 tmp_dlci; u16 frame_size; u8 credit, nbrof_credits; /* If the incoming messages is a command we send back a response */ tmp_dlci = pn_pkt->dlci; frame_size = le16_to_cpuu(&pn_pkt->frame_size); frame_size = MIN(frame_size, rfcomm->l2cap->local_mtu - RFCOMM_MAX_HDR_SIZE); credit = pn_pkt->credit_flow; nbrof_credits = pn_pkt->credits; if (credit) { DSYS(FNC"Using credit flow control, initiating credits are %d on dlci %d\n", nbrof_credits, tmp_dlci); rfcomm->credit_flow = TRUE; rfcomm->dlci[tmp_dlci].local_credits = nbrof_credits; D_CTRL(FNC"Local credits:%d\n", rfcomm->dlci[tmp_dlci].local_credits); rfcomm->dlci[tmp_dlci].remote_credits = START_CREDITS; D_CTRL(FNC"Remote credits: %d\n",rfcomm->dlci[tmp_dlci].remote_credits); send_pn_msg(rfcomm, pn_pkt->prior, frame_size, credit ^ 1, START_CREDITS, tmp_dlci, MCC_RSP); } else { send_pn_msg(rfcomm, pn_pkt->prior, frame_size, 0, 0, tmp_dlci, MCC_RSP); } rfcomm->dlci[tmp_dlci].mtu = frame_size; D_CTRL(FNC"process_mcc : mtu set to %d\n", rfcomm->dlci[tmp_dlci].mtu); } else { u8 tmp_dlci; tmp_dlci = pn_pkt->dlci; D_CTRL(FNC"received PN response with:\n"); D_CTRL(FNC"Frame size:%d\n", le16_to_cpuu(&pn_pkt->frame_size)); D_CTRL(FNC"credit_flow:%d\n", pn_pkt->credit_flow); D_CTRL(FNC"credits:%d\n", pn_pkt->credits); rfcomm->dlci[tmp_dlci].mtu = le16_to_cpuu(&pn_pkt->frame_size); if (pn_pkt->credit_flow == 0xe) { DSYS(FNC"Credit flow control used\n"); rfcomm->credit_flow = TRUE; rfcomm->dlci[tmp_dlci].local_credits = pn_pkt->credits; D_CTRL(FNC"Local credits:%d\n", rfcomm->dlci[tmp_dlci].local_credits); } D_CTRL(FNC"process_mcc : mtu set on dlci:%d to %d\n", tmp_dlci, rfcomm->dlci[tmp_dlci].mtu); if (rfcomm->dlci[tmp_dlci].state == NEGOTIATING) { send_sabm(rfcomm, tmp_dlci); } } break; } case NSC: /* Non supported command resonse */ D_CTRL(FNC"Received Non supported command response\n"); break; default: /* Non supported command received */ D_REC(FNC"Received a non supported command\n"); send_nsc_msg(rfcomm, mcc_short_pkt->h.type, MCC_RSP); break; }}/* Sending packet functions *//* Creates a UA packet and puts it at the beginning of the pkt pointer */ s32 send_ua(rfcomm_con *rfcomm, u8 dlci){ bt_tx_buf *tx_buf; short_frame *ua_pkt; u32 rfcomm_frame_size; D_CTRL("send_ua: Creating UA packet to DLCI %d\n",dlci); rfcomm_frame_size = sizeof(short_frame) + FCS_SIZE; tx_buf = subscribe_bt_buf(sizeof(rfcomm_tx_buf) + rfcomm_frame_size); if (!tx_buf) { D_ERR("send_ua : didn't get a valid tx_buf\n"); return -ENOMEM; } tx_buf->cur_len = rfcomm_frame_size; ua_pkt = (short_frame*) (tx_buf->data + sizeof(rfcomm_tx_buf)); /* Always one in the address field */ ua_pkt->h.addr.ea = 1; /* If we are the responder the cr bit should be set in a response */ ua_pkt->h.addr.cr = ((~(rfcomm->initiator)) & 0x1); /* The control channel is on DLCI 0, i.e. d-bit should not be set */ ua_pkt->h.addr.d = (dlci) & 0x1; ua_pkt->h.addr.server_chn = (dlci) >> 0x1; /* In RFCOMM the F-bit should always be set when sending UA packets */ ua_pkt->h.control = SET_PF(UA); /* The UA packet has length zero, and then the ea bit in the length field should be set */ ua_pkt->h.length.ea = 1; ua_pkt->h.length.len = 0; ua_pkt->data[0] = crc_calc((u8*) ua_pkt, LONG_CRC_CHECK); return l2cap_send_data(tx_buf,rfcomm->l2cap);}/* Creates a DM packet and puts it at the beginning of the pkt pointer */s32 send_dm(rfcomm_con *rfcomm, u8 dlci){ bt_tx_buf *tx_buf; short_frame *dm_pkt; u32 rfcomm_frame_size; D_CTRL("send_dm: Creating DM packet to DLCI %d\n",dlci); rfcomm_frame_size = sizeof(short_frame) + FCS_SIZE; tx_buf = subscribe_bt_buf(sizeof(rfcomm_tx_buf) + rfcomm_frame_size); if (!tx_buf) { D_ERR("send_dm : didn't get a valid tx_buf\n"); return -ENOMEM; } tx_buf->cur_len = rfcomm_frame_size; dm_pkt = (short_frame*) (tx_buf->data + sizeof(rfcomm_tx_buf)); /* Always one in the address field */ dm_pkt->h.addr.ea = 1; /* If we are the responder the cr bit should be set in a response */ dm_pkt->h.addr.cr = ((~(rfcomm->initiator)) & 0x1); /* The control channel is on DLCI 0, i.e. d-bit should not be set */ dm_pkt->h.addr.d = dlci & 0x1; dm_pkt->h.addr.server_chn = dlci >> 0x1; /* In RFCOMM the F-bit should always be set when sending DM packets */ dm_pkt->h.control = SET_PF(DM); /* The DM packet has length zero, and then the ea bit in the length field should be set */ dm_pkt->h.length.ea = 1; dm_pkt->h.length.len = 0; dm_pkt->data[0] = crc_calc((u8*) dm_pkt, LONG_CRC_CHECK); return l2cap_send_data(tx_buf,rfcomm->l2cap);}s32 send_sabm(rfcomm_con *rfcomm, u8 dlci){ bt_tx_buf *tx_buf; short_frame *sabm_pkt; u32 rfcomm_frame_size; D_CTRL("send_sabm: Creating SABM packet to DLCI %d\n",dlci); rfcomm_frame_size = sizeof(short_frame) + FCS_SIZE; tx_buf = subscribe_bt_buf(sizeof(rfcomm_tx_buf) + rfcomm_frame_size); if (!tx_buf) { D_ERR("send_sabm : didn't get a valid tx_buf\n"); return -ENOMEM; } tx_buf->cur_len = rfcomm_frame_size; sabm_pkt = (short_frame*) (tx_buf->data + sizeof(rfcomm_tx_buf)); /* Always one in the address field */ sabm_pkt->h.addr.ea = 1; /* If we are the responder the cr bit should be set in a response */ sabm_pkt->h.addr.cr = ((rfcomm->initiator) & 0x1); sabm_pkt->h.addr.d = dlci & 0x1; sabm_pkt->h.addr.server_chn = dlci >> 0x1; /* In RFCOMM the F-bit should always be set when sending SABM packets */ sabm_pkt->h.control = SET_PF(SABM); /* The SABM packet has length zero, and then the ea bit in the length field should be set */ sabm_pkt->h.length.ea = 1; sabm_pkt->h.length.len = 0; sabm_pkt->data[0] = crc_calc((u8*) sabm_pkt, LONG_CRC_CHECK); return l2cap_send_data(tx_buf,rfcomm->l2cap);}s32 send_disc(rfcomm_con *rfcomm, u8 dlci){ bt_tx_buf *tx_buf; short_frame *disc_pkt; u32 rfcomm_frame_size; D_CTRL("send_disc: Creating DISC packet to DLCI %d\n",dlci); rfcomm_frame_size = sizeof(short_frame) + FCS_SIZE; tx_buf = subscribe_bt_buf(sizeof(rfcomm_tx_buf) + rfcomm_frame_size); if (!tx_buf) { D_ERR("send_disc : didn't get a valid tx_buf\n"); return -ENOMEM; } tx_buf->cur_len = rfcomm_frame_size; disc_pkt = (short_frame*) (tx_buf->data + sizeof(rfcomm_tx_buf)); /* Always one in the address field */ disc_pkt->h.addr.ea = 1; /* If we are the responder the cr bit should be set in a response */ disc_pkt->h.addr.cr = ((rfcomm->initiator) & 0x1); disc_pkt->h.addr.d = dlci & 0x1; disc_pkt->h.addr.server_chn = dlci >> 0x1; /* In RFCOMM the F-bit should always be set when sending DISC packets */ disc_pkt->h.control = SET_PF(DISC); /* The DISC packet has length zero, and then the ea bit in the length field should be set */ disc_pkt->h.length.ea = 1; disc_pkt->h.length.len = 0; disc_pkt->data[0] = crc_calc((u8*) disc_pkt, LONG_CRC_CHECK); return l2cap_send_data(tx_buf,rfcomm->l2cap);} /* Creates a UIH packet and puts it at the beginning of the pkt pointer The funtion returns how many bytes the UIH packet consist of */s32 send_uih(u8 *data, u32 len, rfcomm_con *rfcomm, u8 dlci){ bt_tx_buf *tx_buf; u32 rfcomm_frame_size; u8 send_credit = 0; s32 retval = 0; D_CTRL(FNC"Creating UIH packet with %d bytes data to DLCI %d\n", len, dlci); if (!rfcomm->l2cap->link_up) { D_ERR(FNC"could not send data, baseband down\n");#ifdef __KERNEL__ return 0;#else return -1; /* FIXME - see comment in rfcomm_send_data */#endif } if (rfcomm->credit_flow &&(rfcomm->dlci[dlci].remote_credits < MIN_CREDITS)) { D_SND(FNC"Sending more credits to remote port\n"); send_credit = 1; } if (len > SHORT_PAYLOAD_SIZE) { long_frame *l_pkt; rfcomm_frame_size = sizeof(long_frame) + len + FCS_SIZE + send_credit; /* Check for space in buffer, don't forget the size of the L2CAP and HCI headers */ if (buf_write_room() < (rfcomm_frame_size + sizeof(rfcomm_tx_buf))) { return 0; } tx_buf = subscribe_bt_buf(sizeof(rfcomm_tx_buf) + rfcomm_frame_size); if (!tx_buf) { D_ERR(FNC"didn't get a valid tx_buf\n"); return -ENOMEM; } tx_buf->cur_len = rfcomm_frame_size; l_pkt = (long_frame*) (tx_buf->data + sizeof(rfcomm_tx_buf)); set_uih_hdr((void*) l_pkt, dlci, len, rfcomm->initiator); if (send_credit) { u8 newcredits = MAX_CREDITS - rfcomm->dlci[dlci].remote_credits; l_pkt->h.control = SET_PF(UIH); l_pkt->data[0] = (newcredits); rfcomm->dlci[dlci].remote_credits += newcredits; D_SND(FNC": Remote credits: %d\n",rfcomm->dlci[dlci].remote_credits); memcpy(l_pkt->data + 1, data, len); } else { memcpy(l_pkt->data, data, len); } l_pkt->data[len + send_credit] = crc_calc((u8*) l_pkt, SHORT_CRC_CHECK); swap_long_frame(l_pkt); } else { short_frame *s_pkt; rfcomm_frame_size = sizeof(short_frame) + len + FCS_SIZE + send_credit; /* Check for space in buffer, don't forget the size of the L2CAP and HCI headers */ if (buf_write_room() < (rfcomm_frame_size + sizeof(rfcomm_tx_buf))) { return 0; } tx_buf = subscribe_bt_buf(sizeof(rfcomm_tx_buf) + rfcomm_frame_size); if (!tx_buf) { D_ERR(FNC"didn't get a valid tx_buf\n"); return -ENOMEM; } tx_buf->cur_len = rfcomm_frame_size; s_pkt = (short_frame*) (tx_buf->data + sizeof(rfcomm_tx_buf)); /* Always one */ set_uih_hdr((void*) s_pkt, dlci, len, rfcomm->initiator); if (send_credit) { u8 newcredits = MAX_CREDITS - rfcomm->dlci[dlci].remote_credits; s_pkt->h.control = SET_PF(UIH); s_pkt->data[0] = (newcredits); rfcomm->dlci[dlci].remote_credits += newcredits; D_SND(FNC": Remote credits: %d\n",rfcomm->dlci[dlci].remote_credits); memcpy(s_pkt->data + 1, data, len); } else { memcpy(s_pkt->data, data, len); } s_pkt->data[len + send_credit] = crc_calc((u8*) s_pkt, SHORT_CRC_CHECK); } /* FIXME - How should we propagate result up to higher layers ? through len or success/no success? */ tx_buf->line = rfcomm->line; if((retval = l2cap_send_data(tx_buf, rfcomm->l2cap)) < 0) { return retval; } return len;}s32rfcomm_send_credits(rfcomm_con *rfcomm, u8 dlci, u8 credits){ bt_tx_buf *tx_buf; short_frame *uih_pkt; u32 rfcomm_frame_size; D_CTRL(FNC"give %d credits to dlci %d\n", credits, dlci); rfcomm_frame_size = (sizeof(short_frame) + 1 + FCS_SIZE); tx_buf = subscribe_bt_buf(sizeof(rfcomm_tx_buf) + rfcomm_frame_size); if (!tx_buf) { D_ERR("rfcomm_fcon_msg : didn't get a valid tx_buf\n"); return -ENOMEM; } tx_buf->cur_len = rfcomm_frame_size; uih_pkt = (short_frame*) (tx_buf->data + sizeof(rfcomm_tx_buf)); set_uih_hdr(uih_pkt, dlci, 0, (~rfcomm->initiator)^1); uih_pkt->h.control = SET_PF(UIH); uih_pkt->data[0] = credits; uih_pkt->data[1] = crc_calc((u8*) uih_pkt, SHORT_CRC_CHECK); return l2cap_send_data(tx_buf, rfcomm->l2cap);}/* Sends Multiplexer command packets funktions *//* Sends a test messages with a specific test pattern. */s32 rfcomm_test_msg(rfcomm_con *rfcomm, u8 *test_pattern, u32 len, u8 cr){ bt_tx_buf *tx_buf;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -