diff options
Diffstat (limited to 'stack/rfcomm/rfc_ts_frames.c')
-rw-r--r-- | stack/rfcomm/rfc_ts_frames.c | 908 |
1 files changed, 908 insertions, 0 deletions
diff --git a/stack/rfcomm/rfc_ts_frames.c b/stack/rfcomm/rfc_ts_frames.c new file mode 100644 index 0000000..4690200 --- /dev/null +++ b/stack/rfcomm/rfc_ts_frames.c @@ -0,0 +1,908 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This file contains functions to send TS 07.10 frames + * + ******************************************************************************/ +#include "bt_target.h" +#include "gki.h" +#include "rfcdefs.h" +#include "port_api.h" +#include "l2c_api.h" +#include "port_int.h" +#include "rfc_int.h" + +/******************************************************************************* +** +** Function rfc_send_sabme +** +** Description This function sends SABME frame. +** +*******************************************************************************/ +void rfc_send_sabme (tRFC_MCB *p_mcb, UINT8 dlci) +{ + BT_HDR *p_buf; + UINT8 *p_data; + UINT8 cr = RFCOMM_CR(p_mcb->is_initiator, TRUE); + + if ((p_buf = (BT_HDR *)GKI_getpoolbuf (RFCOMM_CMD_POOL_ID)) == NULL) + return; + + p_buf->offset = L2CAP_MIN_OFFSET; + p_data = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET; + + /* SABME frame, command, PF = 1, dlci */ + *p_data++ = RFCOMM_EA | cr | (dlci << RFCOMM_SHIFT_DLCI); + *p_data++ = RFCOMM_SABME | RFCOMM_PF; + *p_data++ = RFCOMM_EA | 0; + + *p_data = RFCOMM_SABME_FCS ((UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET, cr, dlci); + + p_buf->len = 4; + + rfc_check_send_cmd(p_mcb, p_buf); +} + + +/******************************************************************************* +** +** Function rfc_send_ua +** +** Description This function sends UA frame. +** +*******************************************************************************/ +void rfc_send_ua (tRFC_MCB *p_mcb, UINT8 dlci) +{ + BT_HDR *p_buf; + UINT8 *p_data; + UINT8 cr = RFCOMM_CR(p_mcb->is_initiator, FALSE); + + if ((p_buf = (BT_HDR *)GKI_getpoolbuf (RFCOMM_CMD_POOL_ID)) == NULL) + return; + + p_buf->offset = L2CAP_MIN_OFFSET; + p_data = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET; + + /* ua frame, response, PF = 1, dlci */ + *p_data++ = RFCOMM_EA | cr | (dlci << RFCOMM_SHIFT_DLCI); + *p_data++ = RFCOMM_UA | RFCOMM_PF; + *p_data++ = RFCOMM_EA | 0; + + *p_data = RFCOMM_UA_FCS ((UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET, cr, dlci); + + p_buf->len = 4; + + rfc_check_send_cmd(p_mcb, p_buf); +} + + +/******************************************************************************* +** +** Function rfc_send_dm +** +** Description This function sends DM frame. +** +*******************************************************************************/ +void rfc_send_dm (tRFC_MCB *p_mcb, UINT8 dlci, BOOLEAN pf) +{ + BT_HDR *p_buf; + UINT8 *p_data; + UINT8 cr = RFCOMM_CR(p_mcb->is_initiator, FALSE); + + if ((p_buf = (BT_HDR *)GKI_getpoolbuf (RFCOMM_CMD_POOL_ID)) == NULL) + return; + + p_buf->offset = L2CAP_MIN_OFFSET; + p_data = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET; + + /* DM frame, response, PF = 1, dlci */ + *p_data++ = RFCOMM_EA | cr | (dlci << RFCOMM_SHIFT_DLCI); + *p_data++ = RFCOMM_DM | ((pf) ? RFCOMM_PF : 0); + *p_data++ = RFCOMM_EA | 0; + + *p_data = RFCOMM_DM_FCS ((UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET, cr, dlci); + + p_buf->len = 4; + + rfc_check_send_cmd(p_mcb, p_buf); +} + + +/******************************************************************************* +** +** Function rfc_send_disc +** +** Description This function sends DISC frame. +** +*******************************************************************************/ +void rfc_send_disc (tRFC_MCB *p_mcb, UINT8 dlci) +{ + BT_HDR *p_buf; + UINT8 *p_data; + UINT8 cr = RFCOMM_CR(p_mcb->is_initiator, TRUE); + + if ((p_buf = (BT_HDR *)GKI_getpoolbuf (RFCOMM_CMD_POOL_ID)) == NULL) + return; + + p_buf->offset = L2CAP_MIN_OFFSET; + p_data = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET; + + /* DISC frame, command, PF = 1, dlci */ + *p_data++ = RFCOMM_EA | cr | (dlci << RFCOMM_SHIFT_DLCI); + *p_data++ = RFCOMM_DISC | RFCOMM_PF; + *p_data++ = RFCOMM_EA | 0; + + *p_data = RFCOMM_DISC_FCS ((UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET, cr, dlci); + + p_buf->len = 4; + + rfc_check_send_cmd(p_mcb, p_buf); +} + + +/******************************************************************************* +** +** Function rfc_send_buf_uih +** +** Description This function sends UIH frame. +** +*******************************************************************************/ +void rfc_send_buf_uih (tRFC_MCB *p_mcb, UINT8 dlci, BT_HDR *p_buf) +{ + UINT8 *p_data; + UINT8 cr = RFCOMM_CR(p_mcb->is_initiator, TRUE); + UINT8 credits; + + p_buf->offset -= RFCOMM_CTRL_FRAME_LEN; + if (p_buf->len > 127) + p_buf->offset--; + + if (dlci) + credits = (UINT8)p_buf->layer_specific; + else + credits = 0; + + if (credits) + p_buf->offset--; + + p_data = (UINT8 *)(p_buf + 1) + p_buf->offset; + + /* UIH frame, command, PF = 0, dlci */ + *p_data++ = RFCOMM_EA | cr | (dlci << RFCOMM_SHIFT_DLCI); + *p_data++ = RFCOMM_UIH | ((credits) ? RFCOMM_PF : 0); + if (p_buf->len <= 127) + { + *p_data++ = RFCOMM_EA | (p_buf->len << 1); + p_buf->len += 3; + } + else + { + *p_data++ = (p_buf->len & 0x7f) << 1; + *p_data++ = p_buf->len >> RFCOMM_SHIFT_LENGTH2; + p_buf->len += 4; + } + + if (credits) + { + *p_data++ = credits; + p_buf->len++; + } + + p_data = (UINT8 *)(p_buf + 1) + p_buf->offset + p_buf->len++; + + *p_data = RFCOMM_UIH_FCS ((UINT8 *)(p_buf + 1) + p_buf->offset, dlci); + + if (dlci == RFCOMM_MX_DLCI) + { + rfc_check_send_cmd(p_mcb, p_buf); + } + else + { + + L2CA_DataWrite (p_mcb->lcid, p_buf); + } +} + + +/******************************************************************************* +** +** Function rfc_send_pn +** +** Description This function sends DLC Parameters Negotiation Frame. +** +*******************************************************************************/ +void rfc_send_pn (tRFC_MCB *p_mcb, UINT8 dlci, BOOLEAN is_command, UINT16 mtu, UINT8 cl, UINT8 k) +{ + BT_HDR *p_buf; + UINT8 *p_data; + + if ((p_buf = (BT_HDR *)GKI_getpoolbuf (RFCOMM_CMD_POOL_ID)) == NULL) + return; + + p_buf->offset = L2CAP_MIN_OFFSET + RFCOMM_CTRL_FRAME_LEN; + p_data = (UINT8 *)(p_buf + 1) + p_buf->offset; + + *p_data++ = RFCOMM_EA | RFCOMM_I_CR(is_command) | RFCOMM_MX_PN; + *p_data++ = RFCOMM_EA | (RFCOMM_MX_PN_LEN << 1); + + *p_data++ = dlci; + *p_data++ = RFCOMM_PN_FRAM_TYPE_UIH | cl; + + /* It appeared that we need to reply with the same priority bits as we received. + ** We will use the fact that we reply in the same context so rx_frame can still be used. + */ + if (is_command) + *p_data++ = RFCOMM_PN_PRIORITY_0; + else + *p_data++ = rfc_cb.rfc.rx_frame.u.pn.priority; + + *p_data++ = RFCOMM_T1_DSEC; + *p_data++ = mtu & 0xFF; + *p_data++ = mtu >> 8; + *p_data++ = RFCOMM_N2; + *p_data = k; + + /* Total length is sizeof PN data + mx header 2 */ + p_buf->len = RFCOMM_MX_PN_LEN + 2; + + rfc_send_buf_uih (p_mcb, RFCOMM_MX_DLCI, p_buf); +} + + +/******************************************************************************* +** +** Function rfc_send_fcon +** +** Description This function sends Flow Control On Command. +** +*******************************************************************************/ +void rfc_send_fcon (tRFC_MCB *p_mcb, BOOLEAN is_command) +{ + BT_HDR *p_buf; + UINT8 *p_data; + + if ((p_buf = (BT_HDR *)GKI_getpoolbuf (RFCOMM_CMD_POOL_ID)) == NULL) + return; + + p_buf->offset = L2CAP_MIN_OFFSET + RFCOMM_CTRL_FRAME_LEN; + p_data = (UINT8 *)(p_buf + 1) + p_buf->offset; + + *p_data++ = RFCOMM_EA | RFCOMM_I_CR(is_command) | RFCOMM_MX_FCON; + *p_data++ = RFCOMM_EA | (RFCOMM_MX_FCON_LEN << 1); + + /* Total length is sizeof FCON data + mx header 2 */ + p_buf->len = RFCOMM_MX_FCON_LEN + 2; + + rfc_send_buf_uih (p_mcb, RFCOMM_MX_DLCI, p_buf); +} + + +/******************************************************************************* +** +** Function rfc_send_fcoff +** +** Description This function sends Flow Control Off Command. +** +*******************************************************************************/ +void rfc_send_fcoff (tRFC_MCB *p_mcb, BOOLEAN is_command) +{ + BT_HDR *p_buf; + UINT8 *p_data; + + if ((p_buf = (BT_HDR *)GKI_getpoolbuf (RFCOMM_CMD_POOL_ID)) == NULL) + return; + + p_buf->offset = L2CAP_MIN_OFFSET + RFCOMM_CTRL_FRAME_LEN; + p_data = (UINT8 *)(p_buf + 1) + p_buf->offset; + + *p_data++ = RFCOMM_EA | RFCOMM_I_CR(is_command) | RFCOMM_MX_FCOFF; + *p_data++ = RFCOMM_EA | (RFCOMM_MX_FCOFF_LEN << 1); + + /* Total length is sizeof FCOFF data + mx header 2 */ + p_buf->len = RFCOMM_MX_FCOFF_LEN + 2; + + rfc_send_buf_uih (p_mcb, RFCOMM_MX_DLCI, p_buf); +} + + +/******************************************************************************* +** +** Function rfc_send_msc +** +** Description This function sends Modem Status Command Frame. +** +*******************************************************************************/ +void rfc_send_msc (tRFC_MCB *p_mcb, UINT8 dlci, BOOLEAN is_command, + tPORT_CTRL *p_pars) +{ + BT_HDR *p_buf; + UINT8 *p_data; + UINT8 signals; + UINT8 break_duration; + UINT8 len; + + signals = p_pars->modem_signal; + break_duration = p_pars->break_signal; + + if ((p_buf = (BT_HDR *)GKI_getpoolbuf (RFCOMM_CMD_POOL_ID)) == NULL) + return; + + p_buf->offset = L2CAP_MIN_OFFSET + RFCOMM_CTRL_FRAME_LEN; + p_data = (UINT8 *)(p_buf + 1) + p_buf->offset; + + if (break_duration) + len = RFCOMM_MX_MSC_LEN_WITH_BREAK; + else + len = RFCOMM_MX_MSC_LEN_NO_BREAK; + + *p_data++ = RFCOMM_EA | RFCOMM_I_CR(is_command) | RFCOMM_MX_MSC; + *p_data++ = RFCOMM_EA | (len << 1); + + *p_data++ = RFCOMM_EA | RFCOMM_CR_MASK | (dlci << RFCOMM_SHIFT_DLCI); + *p_data++ = RFCOMM_EA | + ((p_pars->fc) ? RFCOMM_MSC_FC : 0) | + ((signals & MODEM_SIGNAL_DTRDSR) ? RFCOMM_MSC_RTC : 0) | + ((signals & MODEM_SIGNAL_RTSCTS) ? RFCOMM_MSC_RTR : 0) | + ((signals & MODEM_SIGNAL_RI) ? RFCOMM_MSC_IC : 0) | + ((signals & MODEM_SIGNAL_DCD) ? RFCOMM_MSC_DV : 0); + + if (break_duration) + { + *p_data++ = RFCOMM_EA | RFCOMM_MSC_BREAK_PRESENT_MASK | + (break_duration << RFCOMM_MSC_SHIFT_BREAK); + } + + /* Total length is sizeof MSC data + mx header 2 */ + p_buf->len = len + 2; + + rfc_send_buf_uih (p_mcb, RFCOMM_MX_DLCI, p_buf); +} + + +/******************************************************************************* +** +** Function rfc_send_rls +** +** Description This function sends Remote Line Status Command Frame. +** +*******************************************************************************/ +void rfc_send_rls (tRFC_MCB *p_mcb, UINT8 dlci, BOOLEAN is_command, UINT8 status) +{ + BT_HDR *p_buf; + UINT8 *p_data; + + if ((p_buf = (BT_HDR *)GKI_getpoolbuf (RFCOMM_CMD_POOL_ID)) == NULL) + return; + + p_buf->offset = L2CAP_MIN_OFFSET + RFCOMM_CTRL_FRAME_LEN; + p_data = (UINT8 *)(p_buf + 1) + p_buf->offset; + + *p_data++ = RFCOMM_EA | RFCOMM_I_CR(is_command) | RFCOMM_MX_RLS; + *p_data++ = RFCOMM_EA | (RFCOMM_MX_RLS_LEN << 1); + + *p_data++ = RFCOMM_EA | RFCOMM_CR_MASK | (dlci << RFCOMM_SHIFT_DLCI); + *p_data++ = RFCOMM_RLS_ERROR | status; + + /* Total length is sizeof RLS data + mx header 2 */ + p_buf->len = RFCOMM_MX_RLS_LEN + 2; + + rfc_send_buf_uih (p_mcb, RFCOMM_MX_DLCI, p_buf); +} + + +/******************************************************************************* +** +** Function rfc_send_nsc +** +** Description This function sends Non Supported Command Response. +** +*******************************************************************************/ +void rfc_send_nsc (tRFC_MCB *p_mcb) +{ + BT_HDR *p_buf; + UINT8 *p_data; + + if ((p_buf = (BT_HDR *)GKI_getpoolbuf (RFCOMM_CMD_POOL_ID)) == NULL) + return; + + p_buf->offset = L2CAP_MIN_OFFSET + RFCOMM_CTRL_FRAME_LEN; + p_data = (UINT8 *)(p_buf + 1) + p_buf->offset; + + *p_data++ = RFCOMM_EA | RFCOMM_I_CR(FALSE) | RFCOMM_MX_NSC; + *p_data++ = RFCOMM_EA | (RFCOMM_MX_NSC_LEN << 1); + + *p_data++ = rfc_cb.rfc.rx_frame.ea | + (rfc_cb.rfc.rx_frame.cr << RFCOMM_SHIFT_CR) | + rfc_cb.rfc.rx_frame.type; + + /* Total length is sizeof NSC data + mx header 2 */ + p_buf->len = RFCOMM_MX_NSC_LEN + 2; + + rfc_send_buf_uih (p_mcb, RFCOMM_MX_DLCI, p_buf); +} + + +/******************************************************************************* +** +** Function rfc_send_rpn +** +** Description This function sends Remote Port Negotiation Command +** +*******************************************************************************/ +void rfc_send_rpn (tRFC_MCB *p_mcb, UINT8 dlci, BOOLEAN is_command, + tPORT_STATE *p_pars, UINT16 mask) +{ + BT_HDR *p_buf; + UINT8 *p_data; + + if ((p_buf = (BT_HDR *)GKI_getpoolbuf (RFCOMM_CMD_POOL_ID)) == NULL) + return; + + p_buf->offset = L2CAP_MIN_OFFSET + RFCOMM_CTRL_FRAME_LEN; + p_data = (UINT8 *)(p_buf + 1) + p_buf->offset; + + *p_data++ = RFCOMM_EA | RFCOMM_I_CR(is_command) | RFCOMM_MX_RPN; + + if (!p_pars) + { + *p_data++ = RFCOMM_EA | (RFCOMM_MX_RPN_REQ_LEN << 1); + + *p_data++ = RFCOMM_EA | RFCOMM_CR_MASK | (dlci << RFCOMM_SHIFT_DLCI); + + p_buf->len = RFCOMM_MX_RPN_REQ_LEN + 2; + } + else + { + *p_data++ = RFCOMM_EA | (RFCOMM_MX_RPN_LEN << 1); + + *p_data++ = RFCOMM_EA | RFCOMM_CR_MASK | (dlci << RFCOMM_SHIFT_DLCI); + *p_data++ = p_pars->baud_rate; + *p_data++ = (p_pars->byte_size << RFCOMM_RPN_BITS_SHIFT) + | (p_pars->stop_bits << RFCOMM_RPN_STOP_BITS_SHIFT) + | (p_pars->parity << RFCOMM_RPN_PARITY_SHIFT) + | (p_pars->parity_type << RFCOMM_RPN_PARITY_TYPE_SHIFT); + *p_data++ = p_pars->fc_type; + *p_data++ = p_pars->xon_char; + *p_data++ = p_pars->xoff_char; + *p_data++ = (mask & 0xFF); + *p_data++ = (mask >> 8); + + /* Total length is sizeof RPN data + mx header 2 */ + p_buf->len = RFCOMM_MX_RPN_LEN + 2; + } + + rfc_send_buf_uih (p_mcb, RFCOMM_MX_DLCI, p_buf); +} + + +/******************************************************************************* +** +** Function rfc_send_test +** +** Description This function sends Test frame. +** +*******************************************************************************/ +void rfc_send_test (tRFC_MCB *p_mcb, BOOLEAN is_command, BT_HDR *p_buf) +{ + UINT8 *p_data; + UINT16 xx; + UINT8 *p_src, *p_dest; + + /* Shift buffer to give space for header */ + if (p_buf->offset < (L2CAP_MIN_OFFSET + RFCOMM_MIN_OFFSET + 2)) + { + p_src = (UINT8 *) (p_buf + 1) + p_buf->offset + p_buf->len - 1; + p_dest = (UINT8 *) (p_buf + 1) + L2CAP_MIN_OFFSET + RFCOMM_MIN_OFFSET + 2 + p_buf->len - 1; + + for (xx = 0; xx < p_buf->len; xx++) + *p_dest-- = *p_src--; + + p_buf->offset = L2CAP_MIN_OFFSET + RFCOMM_MIN_OFFSET + 2; + } + + /* Adjust offset by number of bytes we are going to fill */ + p_buf->offset -= 2; + p_data = (UINT8 *)(p_buf + 1) + p_buf->offset; + + *p_data++ = RFCOMM_EA | RFCOMM_I_CR(is_command) | RFCOMM_MX_TEST; + *p_data++ = RFCOMM_EA | (p_buf->len << 1); + + p_buf->len += 2; + + rfc_send_buf_uih (p_mcb, RFCOMM_MX_DLCI, p_buf); +} + +/******************************************************************************* +** +** Function rfc_send_credit +** +** Description This function sends a flow control credit in UIH frame. +** +*******************************************************************************/ +void rfc_send_credit(tRFC_MCB *p_mcb, UINT8 dlci, UINT8 credit) +{ + BT_HDR *p_buf; + UINT8 *p_data; + UINT8 cr = RFCOMM_CR(p_mcb->is_initiator, TRUE); + + if ((p_buf = (BT_HDR *)GKI_getpoolbuf (RFCOMM_CMD_POOL_ID)) == NULL) + return; + + p_buf->offset = L2CAP_MIN_OFFSET; + p_data = (UINT8 *)(p_buf + 1) + p_buf->offset; + + *p_data++ = RFCOMM_EA | cr | (dlci << RFCOMM_SHIFT_DLCI); + *p_data++ = RFCOMM_UIH | RFCOMM_PF; + *p_data++ = RFCOMM_EA | 0; + *p_data++ = credit; + *p_data = RFCOMM_UIH_FCS ((UINT8 *)(p_buf + 1) + p_buf->offset, dlci); + + p_buf->len = 5; + + rfc_check_send_cmd(p_mcb, p_buf); +} + + +/******************************************************************************* +** +** Function rfc_parse_data +** +** Description This function processes data packet received from L2CAP +** +*******************************************************************************/ +UINT8 rfc_parse_data (tRFC_MCB *p_mcb, MX_FRAME *p_frame, BT_HDR *p_buf) +{ + UINT8 ead, eal, fcs; + UINT8 *p_data = (UINT8 *)(p_buf + 1) + p_buf->offset; + UINT8 *p_start = p_data; + UINT16 len; + + if (p_buf->len < RFCOMM_CTRL_FRAME_LEN) + { + RFCOMM_TRACE_ERROR1 ("Bad Length1: %d", p_buf->len); + return (RFC_EVENT_BAD_FRAME); + } + + RFCOMM_PARSE_CTRL_FIELD (ead, p_frame->cr, p_frame->dlci, p_data); + if( !ead ) + { + RFCOMM_TRACE_ERROR0 ("Bad Address(EA must be 1)"); + return (RFC_EVENT_BAD_FRAME); + } + RFCOMM_PARSE_TYPE_FIELD (p_frame->type, p_frame->pf, p_data); + RFCOMM_PARSE_LEN_FIELD (eal, len, p_data); + + p_buf->len -= (3 + !ead + !eal + 1); /* Additional 1 for FCS */ + p_buf->offset += (3 + !ead + !eal); + + /* handle credit if credit based flow control */ + if ((p_mcb->flow == PORT_FC_CREDIT) && (p_frame->type == RFCOMM_UIH) && + (p_frame->dlci != RFCOMM_MX_DLCI) && (p_frame->pf == 1)) + { + p_frame->credit = *p_data++; + p_buf->len--; + p_buf->offset++; + } + else + p_frame->credit = 0; + + if (p_buf->len != len) + { + RFCOMM_TRACE_ERROR2 ("Bad Length2 %d %d", p_buf->len, len); + return (RFC_EVENT_BAD_FRAME); + } + + fcs = *(p_data + len); + + /* All control frames that we are sending are sent with P=1, expect */ + /* reply with F=1 */ + /* According to TS 07.10 spec ivalid frames are discarded without */ + /* notification to the sender */ + switch (p_frame->type) + { + case RFCOMM_SABME: + if (RFCOMM_FRAME_IS_RSP(p_mcb->is_initiator, p_frame->cr) + || !p_frame->pf || len || !RFCOMM_VALID_DLCI (p_frame->dlci) + || !rfc_check_fcs (RFCOMM_CTRL_FRAME_LEN, p_start, fcs)) + { + RFCOMM_TRACE_ERROR0 ("Bad SABME"); + return (RFC_EVENT_BAD_FRAME); + } + else + return (RFC_EVENT_SABME); + + case RFCOMM_UA: + if (RFCOMM_FRAME_IS_CMD(p_mcb->is_initiator, p_frame->cr) + || !p_frame->pf || len || !RFCOMM_VALID_DLCI (p_frame->dlci) + || !rfc_check_fcs (RFCOMM_CTRL_FRAME_LEN, p_start, fcs)) + { + RFCOMM_TRACE_ERROR0 ("Bad UA"); + return (RFC_EVENT_BAD_FRAME); + } + else + return (RFC_EVENT_UA); + + case RFCOMM_DM: + if (RFCOMM_FRAME_IS_CMD(p_mcb->is_initiator, p_frame->cr) + || len || !RFCOMM_VALID_DLCI(p_frame->dlci) + || !rfc_check_fcs (RFCOMM_CTRL_FRAME_LEN, p_start, fcs)) + { + RFCOMM_TRACE_ERROR0 ("Bad DM"); + return (RFC_EVENT_BAD_FRAME); + } + else + return (RFC_EVENT_DM); + + case RFCOMM_DISC: + if (RFCOMM_FRAME_IS_RSP(p_mcb->is_initiator, p_frame->cr) + || !p_frame->pf || len || !RFCOMM_VALID_DLCI(p_frame->dlci) + || !rfc_check_fcs (RFCOMM_CTRL_FRAME_LEN, p_start, fcs)) + { + RFCOMM_TRACE_ERROR0 ("Bad DISC"); + return (RFC_EVENT_BAD_FRAME); + } + else + return (RFC_EVENT_DISC); + + case RFCOMM_UIH: + if (!RFCOMM_VALID_DLCI(p_frame->dlci)) + { + RFCOMM_TRACE_ERROR0 ("Bad UIH - invalid DLCI"); + return (RFC_EVENT_BAD_FRAME); + } + else if (!rfc_check_fcs (2, p_start, fcs)) + { + RFCOMM_TRACE_ERROR0 ("Bad UIH - FCS"); + return (RFC_EVENT_BAD_FRAME); + } + else if (RFCOMM_FRAME_IS_RSP(p_mcb->is_initiator, p_frame->cr)) + { + /* we assume that this is ok to allow bad implementations to work */ + RFCOMM_TRACE_ERROR0 ("Bad UIH - response"); + return (RFC_EVENT_UIH); + } + else + return (RFC_EVENT_UIH); + } + + return (RFC_EVENT_BAD_FRAME); +} + + +/******************************************************************************* +** +** Function rfc_process_mx_message +** +** Description This function processes UIH frames received on the +** multiplexer control channel. +** +*******************************************************************************/ +void rfc_process_mx_message (tRFC_MCB *p_mcb, BT_HDR *p_buf) +{ + UINT8 *p_data = (UINT8 *)(p_buf + 1) + p_buf->offset; + MX_FRAME *p_rx_frame = &rfc_cb.rfc.rx_frame; + UINT16 length = p_buf->len; + UINT8 ea, cr, mx_len; + BOOLEAN is_command; + + p_rx_frame->ea = *p_data & RFCOMM_EA; + p_rx_frame->cr = (*p_data & RFCOMM_CR_MASK) >> RFCOMM_SHIFT_CR; + p_rx_frame->type = *p_data++ & ~(RFCOMM_CR_MASK | RFCOMM_EA_MASK); + + if (!p_rx_frame->ea || !length) + { + RFCOMM_TRACE_ERROR2 ("Illegal MX Frame ea:%d len:%d", p_rx_frame->ea, length); + GKI_freebuf (p_buf); + return; + } + + length--; + + is_command = p_rx_frame->cr; + + ea = *p_data & RFCOMM_EA; + + mx_len = *p_data++ >> RFCOMM_SHIFT_LENGTH1; + length--; + + if (!ea) + { + mx_len += *p_data++ << RFCOMM_SHIFT_LENGTH2; + length --; + } + + if (mx_len != length) + { + RFCOMM_TRACE_ERROR0 ("Bad MX frame"); + GKI_freebuf (p_buf); + return; + } + + switch (p_rx_frame->type) + { + case RFCOMM_MX_PN: + if (length != RFCOMM_MX_PN_LEN) + break; + + p_rx_frame->dlci = *p_data++ & RFCOMM_PN_DLCI_MASK; + p_rx_frame->u.pn.frame_type = *p_data & RFCOMM_PN_FRAME_TYPE_MASK; + p_rx_frame->u.pn.conv_layer = *p_data++ & RFCOMM_PN_CONV_LAYER_MASK; + p_rx_frame->u.pn.priority = *p_data++ & RFCOMM_PN_PRIORITY_MASK; + p_rx_frame->u.pn.t1 = *p_data++; + p_rx_frame->u.pn.mtu = *p_data + (*(p_data + 1) << 8); + p_data += 2; + p_rx_frame->u.pn.n2 = *p_data++; + p_rx_frame->u.pn.k = *p_data++ & RFCOMM_PN_K_MASK; + + if (!p_rx_frame->dlci + || !RFCOMM_VALID_DLCI (p_rx_frame->dlci) + || (p_rx_frame->u.pn.mtu < RFCOMM_MIN_MTU) + || (p_rx_frame->u.pn.mtu > RFCOMM_MAX_MTU)) + { + RFCOMM_TRACE_ERROR0 ("Bad PN frame"); + break; + } + + GKI_freebuf (p_buf); + + rfc_process_pn (p_mcb, is_command, p_rx_frame); + return; + + case RFCOMM_MX_TEST: + if (!length) + break; + + p_rx_frame->u.test.p_data = p_data; + p_rx_frame->u.test.data_len = length; + + p_buf->offset += 2; + p_buf->len -= 2; + + if (is_command) + rfc_send_test (p_mcb, FALSE, p_buf); + else + rfc_process_test_rsp (p_mcb, p_buf); + return; + + case RFCOMM_MX_FCON: + if (length != RFCOMM_MX_FCON_LEN) + break; + + GKI_freebuf (p_buf); + + rfc_process_fcon (p_mcb, is_command); + return; + + case RFCOMM_MX_FCOFF: + if (length != RFCOMM_MX_FCOFF_LEN) + break; + + GKI_freebuf (p_buf); + + rfc_process_fcoff (p_mcb, is_command); + return; + + case RFCOMM_MX_MSC: + + ea = *p_data & RFCOMM_EA; + cr = (*p_data & RFCOMM_CR_MASK) >> RFCOMM_SHIFT_CR; + p_rx_frame->dlci = *p_data++ >> RFCOMM_SHIFT_DLCI; + + if (!ea || !cr || !p_rx_frame->dlci + || !RFCOMM_VALID_DLCI (p_rx_frame->dlci)) + { + RFCOMM_TRACE_ERROR0 ("Bad MSC frame"); + break; + } + + p_rx_frame->u.msc.signals = *p_data++; + + if (mx_len == RFCOMM_MX_MSC_LEN_WITH_BREAK) + { + p_rx_frame->u.msc.break_present = *p_data & RFCOMM_MSC_BREAK_PRESENT_MASK; + p_rx_frame->u.msc.break_duration = (*p_data & RFCOMM_MSC_BREAK_MASK) >> RFCOMM_MSC_SHIFT_BREAK; + } + else + { + p_rx_frame->u.msc.break_present = FALSE; + p_rx_frame->u.msc.break_duration = 0; + } + GKI_freebuf (p_buf); + + rfc_process_msc (p_mcb, is_command, p_rx_frame); + return; + + case RFCOMM_MX_NSC: + if ((length != RFCOMM_MX_NSC_LEN) || !is_command) + break; + + p_rx_frame->u.nsc.ea = *p_data & RFCOMM_EA; + p_rx_frame->u.nsc.cr = (*p_data & RFCOMM_CR_MASK) >> RFCOMM_SHIFT_CR; + p_rx_frame->u.nsc.type = *p_data++ >> RFCOMM_SHIFT_DLCI; + + GKI_freebuf (p_buf); + + rfc_process_nsc (p_mcb, p_rx_frame); + return; + + case RFCOMM_MX_RPN: + if ((length != RFCOMM_MX_RPN_REQ_LEN) && (length != RFCOMM_MX_RPN_LEN)) + break; + + ea = *p_data & RFCOMM_EA; + cr = (*p_data & RFCOMM_CR_MASK) >> RFCOMM_SHIFT_CR; + p_rx_frame->dlci = *p_data++ >> RFCOMM_SHIFT_DLCI; + + if (!ea || !cr || !p_rx_frame->dlci + || !RFCOMM_VALID_DLCI (p_rx_frame->dlci)) + { + RFCOMM_TRACE_ERROR0 ("Bad RPN frame"); + break; + } + + p_rx_frame->u.rpn.is_request = (length == RFCOMM_MX_RPN_REQ_LEN); + + if (!p_rx_frame->u.rpn.is_request) + { + p_rx_frame->u.rpn.baud_rate = *p_data++; + p_rx_frame->u.rpn.byte_size = (*p_data >> RFCOMM_RPN_BITS_SHIFT) & RFCOMM_RPN_BITS_MASK; + p_rx_frame->u.rpn.stop_bits = (*p_data >> RFCOMM_RPN_STOP_BITS_SHIFT) & RFCOMM_RPN_STOP_BITS_MASK; + p_rx_frame->u.rpn.parity = (*p_data >> RFCOMM_RPN_PARITY_SHIFT) & RFCOMM_RPN_PARITY_MASK; + p_rx_frame->u.rpn.parity_type = (*p_data++ >> RFCOMM_RPN_PARITY_TYPE_SHIFT) & RFCOMM_RPN_PARITY_TYPE_MASK; + + p_rx_frame->u.rpn.fc_type = *p_data++ & RFCOMM_FC_MASK; + p_rx_frame->u.rpn.xon_char = *p_data++; + p_rx_frame->u.rpn.xoff_char = *p_data++; + p_rx_frame->u.rpn.param_mask = (*p_data + (*(p_data + 1) << 8)) & RFCOMM_RPN_PM_MASK; + } + GKI_freebuf (p_buf); + + rfc_process_rpn (p_mcb, is_command, p_rx_frame->u.rpn.is_request, p_rx_frame); + return; + + case RFCOMM_MX_RLS: + if (length != RFCOMM_MX_RLS_LEN) + break; + + ea = *p_data & RFCOMM_EA; + cr = (*p_data & RFCOMM_CR_MASK) >> RFCOMM_SHIFT_CR; + + p_rx_frame->dlci = *p_data++ >> RFCOMM_SHIFT_DLCI; + p_rx_frame->u.rls.line_status = (*p_data & ~0x01); + + if (!ea || !cr || !p_rx_frame->dlci + || !RFCOMM_VALID_DLCI (p_rx_frame->dlci)) + { + RFCOMM_TRACE_ERROR0 ("Bad RPN frame"); + break; + } + + GKI_freebuf (p_buf); + + rfc_process_rls (p_mcb, is_command, p_rx_frame); + return; + } + + GKI_freebuf (p_buf); + + if (is_command) + rfc_send_nsc (p_mcb); +} + |