diff options
author | Andre Eisenbach <andre@broadcom.com> | 2012-02-22 13:18:21 -0800 |
---|---|---|
committer | Matthew Xie <mattx@google.com> | 2012-07-14 11:19:11 -0700 |
commit | e448862a47c08eb23185aaed574b39264f5005fc (patch) | |
tree | 2bc6246e3091315e77224fd798ea2fe8074ef972 /stack/obx/obx_utils.c | |
parent | a2ca4b83ab8bbbfd8d5f6693e927ed4b82094624 (diff) | |
download | external_bluetooth_bluedroid-e448862a47c08eb23185aaed574b39264f5005fc.zip external_bluetooth_bluedroid-e448862a47c08eb23185aaed574b39264f5005fc.tar.gz external_bluetooth_bluedroid-e448862a47c08eb23185aaed574b39264f5005fc.tar.bz2 |
Initial Bluedroid stack commit
Diffstat (limited to 'stack/obx/obx_utils.c')
-rw-r--r-- | stack/obx/obx_utils.c | 979 |
1 files changed, 979 insertions, 0 deletions
diff --git a/stack/obx/obx_utils.c b/stack/obx/obx_utils.c new file mode 100644 index 0000000..785df18 --- /dev/null +++ b/stack/obx/obx_utils.c @@ -0,0 +1,979 @@ +/***************************************************************************** +** +** Name: obx_utils.c +** +** File: OBEX common utility functions +** +** Copyright (c) 2003-2011, Broadcom Corp., All Rights Reserved. +** Broadcom Bluetooth Core. Proprietary and confidential. +** +*****************************************************************************/ +#include <string.h> +#include <stdio.h> +#include "wcassert.h" + + +#include "bt_target.h" +#include "obx_int.h" +#include "port_api.h" +#include "sdpdefs.h" +#include "l2c_api.h" + +const tOBX_EVENT obx_sm_evt_to_api_evt[OBX_MAX_EVT_MAP_NUM] = +{ + OBX_CONNECT_REQ_EVT, + OBX_SESSION_REQ_EVT, /* A Crease Session or Resume Session request is received by the server. Call OBX_SessionRsp(). */ + OBX_DISCONNECT_REQ_EVT, + OBX_PUT_REQ_EVT, + OBX_GET_REQ_EVT, + OBX_SETPATH_REQ_EVT, + OBX_ACTION_REQ_EVT, /* An Action request is received by the server. Call OBX_ActionRsp(). */ + OBX_ABORT_REQ_EVT +}; + + +const UINT8 obx_rsp_code[] = +{ + OBX_RSP_CONTINUE, /* 0x10 Continue */ + OBX_RSP_OK, /* 0x20 OK, Success */ + OBX_RSP_CREATED, /* 0x21 Created */ + OBX_RSP_ACCEPTED, /* 0x22 Accepted */ + OBX_RSP_NON_AUTH_INFO, /* 0x23 Non-Authoritative Information */ + OBX_RSP_NO_CONTENT, /* 0x24 No Content */ + OBX_RSP_RESET_CONTENT, /* 0x25 Reset Content */ + OBX_RSP_PART_CONTENT, /* 0x26 Partial Content */ + OBX_RSP_MULTI_CHOICES, /* 0x30 Multiple Choices */ + OBX_RSP_MVD_PERM, /* 0x31 Moved Permanently */ + OBX_RSP_MVD_TEMP, /* 0x32 Moved temporarily */ + OBX_RSP_SEE_OTHER, /* 0x33 See Other */ + OBX_RSP_NOT_MODIFIED, /* 0x34 Not modified */ + OBX_RSP_USE_PROXY, /* 0x35 Use Proxy */ + OBX_RSP_BAD_REQUEST, /* 0x40 Bad Request - server couldn't understand request */ + OBX_RSP_UNAUTHORIZED, /* 0x41 Unauthorized */ + OBX_RSP_PAYMENT_REQD, /* 0x42 Payment required */ + OBX_RSP_FORBIDDEN, /* 0x43 Forbidden - operation is understood but refused */ + OBX_RSP_NOT_FOUND, /* 0x44 Not Found */ + OBX_RSP_NOT_ALLOWED, /* 0x45 Method not allowed */ + OBX_RSP_NOT_ACCEPTABLE, /* 0x46 Not Acceptable */ + OBX_RSP_PROXY_AUTH_REQD, /* 0x47 Proxy Authentication required */ + OBX_RSP_REQUEST_TIMEOUT, /* 0x48 Request Time Out */ + OBX_RSP_CONFLICT, /* 0x49 Conflict */ + OBX_RSP_GONE, /* 0x4A Gone */ + OBX_RSP_LENGTH_REQD, /* 0x4B Length Required */ + OBX_RSP_PRECONDTN_FAILED, /* 0x4C Precondition failed */ + OBX_RSP_REQ_ENT_2_LARGE, /* 0x4D Requested entity too large */ + OBX_RSP_REQ_URL_2_LARGE, /* 0x4E Request URL too large */ + OBX_RSP_UNSUPTD_TYPE, /* 0x4F Unsupported media type */ + OBX_RSP_INTRNL_SRVR_ERR, /* 0x50 Internal Server Error */ + OBX_RSP_NOT_IMPLEMENTED, /* 0x51 Not Implemented */ + OBX_RSP_BAD_GATEWAY, /* 0x52 Bad Gateway */ + OBX_RSP_SERVICE_UNAVL, /* 0x53 Service Unavailable */ + OBX_RSP_GATEWAY_TIMEOUT, /* 0x54 Gateway Timeout */ + OBX_RSP_HTTP_VER_NOT_SUPTD, /* 0x55 HTTP version not supported */ + OBX_RSP_DATABASE_FULL, /* 0x60 Database Full */ + OBX_RSP_DATABASE_LOCKED, /* 0x61 Database Locked */ + OBX_RSP_DEFAULT +}; + +static void obx_read_mtu(BT_HDR *p_pkt, tOBX_HANDLE handle, tOBX_CONN_EVT *p_evt); + +/******************************************************************************* +** Function obx_read_srm +** Description read the SRM and SRM_PARAM headers from the packet received from +** peer and set the control block data member accordingly +** Return UINT8 +*******************************************************************************/ +UINT8 obx_read_srm (tOBX_SRM *p_srm, BOOLEAN is_client, BT_HDR *p_pkt) +{ + UINT8 srm, srmp = 0, ret_srmp=0; + UINT8 old_srm = *p_srm; + BOOLEAN allowed = FALSE, clear = TRUE; + + OBX_TRACE_DEBUG1("obx_read_srm srm:0x%x", *p_srm ); + if (*p_srm) + { + /* if the SRM enable request is not granted in the next packet, the request is not valid any more + * clear the requesting flag */ + *p_srm &= ~OBX_SRM_REQING; + + if (OBX_Read1ByteHdr(p_pkt, OBX_HI_SRM, &srm)) + { + if (srm == OBX_HV_SRM_ENABLE) + { + if (is_client) + { + if (old_srm & OBX_SRM_REQING) + { + *p_srm |= OBX_SRM_ENGAGE; + allowed = TRUE; + } + } + else /* is server */ + { + *p_srm |= OBX_SRM_REQING; + allowed = TRUE; + } + } + OBX_TRACE_DEBUG3("SRM :0x%x srm:0x%x old_srm:0x%x", srm, *p_srm, old_srm ); + } + + if (!allowed) + allowed = old_srm & OBX_SRM_PARAM_AL; + + if (OBX_Read1ByteHdr(p_pkt, OBX_HI_SRM_PARAM, &srmp)) + { + if ((srmp == OBX_HV_SRM_PARAM_WAIT) && allowed) + { + ret_srmp = OBX_SRMP_WAIT; + *p_srm |= OBX_SRM_PARAM_AL; + clear = FALSE; + } + } + OBX_TRACE_DEBUG4("SRM_PARAM :0x%x srm:0x%x allowed:%d clear:%d", srmp, *p_srm, allowed, clear ); + + /* once the SRMP header is not used, it should be ignored for the rest of the transaction */ + if (clear) + *p_srm &= ~OBX_SRM_PARAM_AL; + } + + return ret_srmp; +} + +/******************************************************************************* +** Function obx_add_timeout +** Description add the timeout triplet +** +** Return UINT8 +*******************************************************************************/ +UINT8 obx_add_timeout (tOBX_TRIPLET *p_trip, UINT32 timeout, tOBX_SESS_EVT *p_param) +{ + UINT8 *p; + UINT8 ret = 0; + + if (timeout != OBX_INFINITE_TIMEOUT) + { + p_trip->tag = OBX_TAG_SESS_PARAM_TOUT; + p_trip->len = OBX_TIMEOUT_SIZE; + p = p_trip->p_array; + UINT32_TO_BE_STREAM(p, timeout); + ret = 1; + } + p_param->timeout = timeout; + return ret; +} + +/******************************************************************************* +** Function obx_read_timeout +** Description add the timeout triplet +** +** Return void +*******************************************************************************/ +void obx_read_timeout (tOBX_TRIPLET *p_trip, UINT8 num, UINT32 *p_timeout, UINT8 *p_toa) +{ + UINT8 ind; + UINT8 *p; + UINT32 tmp; + + p = p_toa; + BE_STREAM_TO_UINT32(tmp, p); + OBX_TRACE_DEBUG2("obx_read_timeout %d/%d", *p_timeout, tmp); + if (*p_timeout == 0) + *p_timeout = tmp; + ind = obx_read_triplet(p_trip, num, OBX_TAG_SESS_PARAM_TOUT); + if ((ind != num) && (p_trip[ind].len == OBX_TIMEOUT_SIZE)) + { + p = p_trip[ind].p_array; + BE_STREAM_TO_UINT32(tmp, p); + if (tmp < (*p_timeout)) + { + (*p_timeout) = tmp; + OBX_TRACE_DEBUG1("new timeout %d", tmp); + } + } + UINT32_TO_BE_STREAM(p_toa, (*p_timeout)); +} + +#if (OBX_CLIENT_INCLUDED == TRUE) +/******************************************************************************* +** Function obx_verify_response +** Description +** Return OBX_BAD_SM_EVT, if bad. +*******************************************************************************/ +UINT8 obx_verify_response(UINT8 opcode, tOBX_RX_HDR *p_rxh) +{ + UINT8 final = (opcode & OBX_FINAL) ? TRUE : FALSE; + int xx = 0; + UINT8 res_code = opcode & ~OBX_FINAL; + + p_rxh->sm_evt = OBX_BAD_SM_EVT; + + /* response packet must have the final bit set */ + if (final == TRUE) + { + if (res_code == OBX_RSP_CONTINUE) + { + p_rxh->sm_evt = OBX_CONT_CFM_CEVT; + } + else + { + /* figure out the kind of response, Continue, OK, or Error */ + while(obx_rsp_code[xx] != OBX_RSP_DEFAULT) + { + if (obx_rsp_code[xx] == res_code) + break; + xx++; + } + + if (obx_rsp_code[xx] != OBX_RSP_DEFAULT) + { + if (obx_rsp_code[xx] <= OBX_MAX_OK_RSP) + p_rxh->sm_evt = OBX_OK_CFM_CEVT; + else + p_rxh->sm_evt = OBX_FAIL_CFM_CEVT; + } + /* else bad response code */ + } + if (p_rxh->sm_evt != OBX_BAD_SM_EVT) + { + p_rxh->code = opcode; + } + } + /* + else final bit not set in response packet -> bad response code + */ + + return p_rxh->sm_evt; +} + +/******************************************************************************* +** +** Function obx_cl_proc_pkt +** +** Description process a packet received from the connected server +** verify that the response is valid +** fill in event parameters +** call csm to process the event +** +** Returns void +** +*******************************************************************************/ +void obx_cl_proc_pkt (tOBX_CL_CB *p_cb, BT_HDR *p_pkt) +{ + tOBX_RX_HDR *p_rxh; + UINT32 conn_id; + BOOLEAN pass = FALSE; + UINT8 xx; + tOBX_TRIPLET triplet[OBX_MAX_NUM_AUTH_TRIPLET]; + UINT8 num_trip = OBX_MAX_NUM_AUTH_TRIPLET; + tOBX_CL_EVENT sm_evt; + UINT8 ssn; + + OBX_TRACE_DEBUG3("obx_cl_proc_pkt 0x%x srm:0x%x, sess_st:%d", p_pkt, p_cb->srm, p_cb->sess_st); + OBX_TRACE_DEBUG1("csm offset:%d", p_cb->param.sess.obj_offset); + + p_rxh = (tOBX_RX_HDR *)(p_pkt + 1); + p_cb->rsp_code = p_rxh->code & ~OBX_FINAL; + + p_pkt->event = OBX_PUT_RSP_EVT; /* any response */ + /* setup callback event param + memset(&p_cb->param, 0, sizeof(tOBX_EVT_PARAM)); */ + + if (p_cb->state == OBX_CS_CONNECT_REQ_SENT ) + { + /* when a response packet is received in conn_rs state, + * it must be a connect response packet */ + p_pkt->event = OBX_CONNECT_RSP_EVT; + p_cb->param.conn.handle = p_cb->ll_cb.port.handle; + obx_read_mtu(p_pkt, p_cb->ll_cb.port.handle, &(p_cb->param.conn)); + p_cb->ll_cb.port.tx_mtu = p_cb->param.conn.mtu; + + /* save Connection ID */ + if (OBX_Read4ByteHdr(p_pkt, OBX_HI_CONN_ID, &conn_id) == TRUE) + p_cb->conn_id = conn_id; + OBX_TRACE_DEBUG1("Connection ID: 0x%x", p_cb->conn_id ); + } + + if (p_cb->sess_st == OBX_SESS_ACTIVE) + { + /* verify the session sequence number */ + if (OBX_Read1ByteHdr (p_pkt, OBX_HI_SESSION_SN, &ssn)) + { + OBX_TRACE_DEBUG1("ssn:%d", ssn); + p_cb->param.ssn = ssn; + } + } + + sm_evt = p_rxh->sm_evt; + + if (p_cb->wait_auth == TRUE) + { + /* this can only happen for CONNECT */ + if (p_cb->rsp_code == OBX_RSP_OK) + { + /* successful according to server */ + /* verify the digest */ + p_cb->wait_auth = FALSE; + /* The coverity complaints on this function is not correct. + * The value in triplet[] is set/initialized by OBX_ReadTriplet if num_trip returns TRUE. + * leave this unnecessary memset here */ + memset(triplet,0,sizeof(triplet)); + if (OBX_ReadTriplet(p_pkt, OBX_HI_AUTH_RSP, triplet, &num_trip)) + { + for (xx=0; xx<num_trip; xx++) + { + if (triplet[xx].tag == OBX_DIGEST_RSP_TAG) + { + if (memcmp (p_cb->p_auth, triplet[xx].p_array, OBX_DIGEST_SIZE) == 0) + pass = TRUE; + break; + } + } + } + if (pass == FALSE) + { + OBX_TRACE_ERROR0("Failed - server does not provide good digest" ); + p_cb->wait_auth = OBX_WAIT_AUTH_FAIL; + p_cb->rsp_code = OBX_RSP_FAILED; + } + } + } + if (p_cb->p_auth) + GKI_freebuf(p_cb->p_auth); + p_cb->p_auth = NULL; + + p_cb->srmp = obx_read_srm (&p_cb->srm, TRUE, p_pkt); + obx_csm_event(p_cb, sm_evt, p_pkt); +} + +/******************************************************************************* +** +** Function obx_cl_prepend_msg +** +** Description This function is used by API functions to add the data in the +** reserved space in the OBEX packet +** +** Returns void. +** +*******************************************************************************/ +BT_HDR * obx_cl_prepend_msg(tOBX_CL_CB *p_cb, BT_HDR *p_pkt, UINT8 * p_data, UINT16 data_len) +{ + UINT8 *p; + UINT16 len; + + if (p_pkt == NULL) + { + p_pkt = OBX_HdrInit(OBX_HANDLE_NULL, OBX_MIN_MTU); + len = data_len; + } + else + { + len = p_pkt->len + data_len; + } + + WC_ASSERT(p_pkt->offset >= data_len); + p = (UINT8 *)(p_pkt + 1) + p_pkt->offset - data_len; + memcpy(p, p_data, data_len); + p++; + /* adjust the packet len */ + UINT16_TO_BE_STREAM(p, len); + p_pkt->len += data_len; + p_pkt->offset -= data_len; + p_pkt->layer_specific -= data_len; + + return p_pkt; +} +#endif /* OBX_CLIENT_INCLUDED */ + +#if (OBX_SERVER_INCLUDED == TRUE) +/******************************************************************************* +** Function obx_verify_request +** Description +** Return OBX_BAD_SM_EVT, if bad. +*******************************************************************************/ +UINT8 obx_verify_request(UINT8 opcode, tOBX_RX_HDR *p_rxh) +{ + UINT8 final = (opcode & OBX_FINAL) ? TRUE : FALSE; + UINT8 req_code = opcode & ~OBX_FINAL; + p_rxh->sm_evt = OBX_BAD_SM_EVT; + + OBX_TRACE_DEBUG2("obx_verify_request opcode 0x%x: final:%d", opcode, final); + switch (req_code) + { + case OBX_REQ_CONNECT: + /* this request must have the final bit set */ + if (final == TRUE) + p_rxh->sm_evt = OBX_CONNECT_REQ_SEVT; + break; + + case OBX_REQ_SESSION: + /* this request must have the final bit set */ + if (final == TRUE) + p_rxh->sm_evt = OBX_SESSION_REQ_SEVT; + break; + + case OBX_REQ_ACTION: + /* this request must have the final bit set */ + if (final == TRUE) + p_rxh->sm_evt = OBX_ACTION_REQ_SEVT; + break; + + case OBX_REQ_DISCONNECT: + /* this request must have the final bit set */ + if (final == TRUE) + p_rxh->sm_evt = OBX_DISCNT_REQ_SEVT; + break; + + case OBX_REQ_PUT: + p_rxh->sm_evt = OBX_PUT_REQ_SEVT; + break; + + case OBX_REQ_GET: + p_rxh->sm_evt = OBX_GET_REQ_SEVT; + break; + + case OBX_REQ_SETPATH: + /* this request must have the final bit set */ + if (final == TRUE) + p_rxh->sm_evt = OBX_SETPATH_REQ_SEVT; + break; + + case OBX_REQ_ABORT: + /* this request must have the final bit set */ + if (final == TRUE) + p_rxh->sm_evt = OBX_ABORT_REQ_SEVT; + break; + } + + if (p_rxh->sm_evt != OBX_BAD_SM_EVT) + { + p_rxh->code = opcode; + } + return p_rxh->sm_evt; +} + +/******************************************************************************* +** +** Function obx_is_get_or_put_cont +** +** Returns TRUE, if it's a GET/PUT continuing continuing +** TRUE, if it's an ABORT +** +*******************************************************************************/ +BOOLEAN obx_is_get_or_put_cont (tOBX_SR_SESS_CB *p_scb, UINT8 req_code) +{ + BOOLEAN is_cont = FALSE; + + if (req_code == OBX_REQ_ABORT) + { + is_cont = TRUE; + } + else if (req_code == OBX_REQ_PUT) + { + if (p_scb->state == OBX_SS_PUT_TRANSACTION || p_scb->state == OBX_SS_PUT_SRM) + { + is_cont = TRUE; + } + } + else if (req_code == OBX_REQ_GET) + { + if (p_scb->state == OBX_SS_GET_TRANSACTION || p_scb->state == OBX_SS_GET_SRM) + { + is_cont = TRUE; + } + } + + return is_cont; +} + +/******************************************************************************* +** +** Function obx_sr_proc_pkt +** +** Description process a packet received from the connected client +** verify that the request is valid +** fill in event parameters +** call ssm to process the event +** +** Returns TRUE, if abort +** +*******************************************************************************/ +BOOLEAN obx_sr_proc_pkt (tOBX_SR_SESS_CB *p_scb, BT_HDR *p_pkt) +{ + tOBX_RX_HDR *p_rxh; + UINT8 *p_body; + UINT16 len; + BOOLEAN end; + UINT32 conn_id = 0; + UINT8 req_code; + BOOLEAN final; + UINT8 ssn, tmp_ssn; + UINT8 num_hdrs, num_body, num_ssn; + UINT8 rsp_code = OBX_RSP_OK; + UINT8 num_id; + BOOLEAN chk_add = FALSE; + + p_rxh = (tOBX_RX_HDR *)(p_pkt + 1); + final = (p_rxh->code & OBX_FINAL) ? TRUE : FALSE; + req_code = p_rxh->code & ~OBX_FINAL; + p_scb->api_evt = (UINT8)p_pkt->event; + memset(&p_scb->param, 0, sizeof(tOBX_EVT_PARAM)); + p_scb->param.get.final = final; + + num_id = OBX_Read4ByteHdr (p_pkt, OBX_HI_CONN_ID, &conn_id); + + OBX_TRACE_DEBUG6("obx_sr_proc_pkt 0x%x srm:0x%x sess_st:%d req_code:0x%x, sm_evt:%d ssn:%d", + p_pkt, p_scb->srm, p_scb->sess_st, req_code, p_rxh->sm_evt, p_scb->ssn); + + num_ssn = OBX_Read1ByteHdr (p_pkt, OBX_HI_SESSION_SN, &ssn); + if (p_scb->srm & OBX_SRM_ABORT) + { + /* OBX_SRM_ABORT bit is set by server only when PUT req /w SRM is rejected before transaction actually ends + * this means we need to ignore follow packets until the next transaction starts */ + if (req_code == OBX_REQ_PUT) + { + /* check if this is the put for the previous transaction */ + num_hdrs = OBX_ReadNumHdrs(p_pkt, &num_body); + OBX_TRACE_DEBUG4("num_hdrs:%d num_body:%d num_id:%d num_ssn:%d", num_hdrs, num_body, num_id, num_ssn); + num_body += num_ssn; + num_body += num_id; + if (num_hdrs <= num_body) + { + p_scb->ssn = ssn+1; + /* it is left-over, drop it. */ + if (p_pkt) + GKI_freebuf (p_pkt); + p_scb->api_evt = OBX_NULL_EVT; + return TRUE; + } + } + /* clear the SRM bits; leave only the enabled bit */ + p_scb->srm &= OBX_SRM_ENABLE; + } + + if ((p_scb->sess_st == OBX_SESS_ACTIVE) && (req_code != OBX_REQ_SESSION) && (req_code != OBX_REQ_ABORT)) + { + rsp_code = OBX_RSP_BAD_REQUEST; + /* verify the session sequence number */ + if (num_ssn) + { + OBX_TRACE_DEBUG2("ssn pkt/cb=%d/%d", ssn, p_scb->ssn); + if (ssn == p_scb->ssn) + { + p_scb->param.ssn = p_scb->ssn; + rsp_code = OBX_RSP_OK; + } + else if (p_scb->srmp & OBX_SRMP_SESS_FST) + { + tmp_ssn = ssn+1; + if (tmp_ssn == p_scb->ssn) + { + p_scb->param.ssn = ssn; + p_scb->ssn = ssn; + rsp_code = OBX_RSP_OK; + } + } + } + p_scb->srmp &= ~OBX_SRMP_SESS_FST; + } + + /* fill event parameter */ + if (req_code == OBX_REQ_CONNECT) + { + p_scb->param.conn.handle = p_scb->handle; + obx_read_mtu(p_pkt, p_scb->ll_cb.comm.handle, &(p_scb->param.conn)); + + p_scb->ll_cb.port.tx_mtu = p_scb->param.conn.mtu; + /* verify the target header and connection ID + * in obx_sa_connect_ind() for OBX_SS_NOT_CONNECTED */ + /* verify the connection ID in obx_sa_auth_ind() for OBX_SS_WAIT_AUTH */ + chk_add = TRUE; + } + else if (req_code == OBX_REQ_SESSION) + { + /* do nothing */ + if (conn_id != 0) + { + OBX_TRACE_ERROR1("Session command should not use Connection ID: 0x%x", conn_id); + p_rxh->sm_evt = OBX_BAD_REQ_SEVT; + } + } + else + { + OBX_TRACE_DEBUG3("Connection ID: 0x%x/0x%x state:%d", p_scb->conn_id, conn_id, p_scb->state ); + /* verify the connection ID */ + if ( (conn_id == p_scb->conn_id) || + (conn_id == 0 && p_scb->conn_id != 0 && obx_is_get_or_put_cont(p_scb, req_code))) + { + /* match: both non-exist or both exist and equal */ + /* connection ID header does not exist, but control block uses connection ID, + * if this is continuation packets for PUT and GET, it's OK */ + if (req_code == OBX_REQ_PUT) + { + p_scb->param.put.final = final; + + /* determine the PUT type */ + p_scb->param.put.type = OBX_PT_PUT; + if (p_scb->state == OBX_SS_CONNECTED && final == TRUE) + { + if (OBX_ReadBodyHdr(p_pkt, &p_body, &len, &end) == FALSE) + { + /* final is set, no BODY or End-of-Body + * -> Delete request */ + p_scb->param.put.type = OBX_PT_DELETE; + } + else if (end == TRUE && len == 0) + { + /* an empty End-of-Body header + * -> Create-Empty request */ + p_scb->param.put.type = OBX_PT_CREATE; + } + } + OBX_TRACE_EVENT1("Put request type: %d", p_scb->param.put.type); + } + else if (req_code == OBX_REQ_SETPATH) + { + p_scb->param.sp.flag = *((UINT8 *)(p_pkt + 1) + p_pkt->offset + OBX_SETPATH_FLAG_OFFSET); + } + } + else + { + /* does not have good connection ID */ + p_rxh->sm_evt = OBX_BAD_REQ_SEVT; + p_scb->api_evt = OBX_NULL_EVT; + } + } + + /* process the SRM header */ + p_scb->srmp |= obx_read_srm (&p_scb->srm, FALSE, p_pkt); + + if (p_rxh->sm_evt != OBX_BAD_REQ_SEVT && req_code != OBX_REQ_ABORT) + { + p_scb->cur_op = req_code; + if (final) + p_scb->cur_op |= OBX_FINAL; + } + + if (rsp_code != OBX_RSP_OK) + { + p_rxh->sm_evt = OBX_BAD_REQ_SEVT; + } + + OBX_TRACE_DEBUG2("rsp_code:0x%x, sm_evt:%d", rsp_code, p_rxh->sm_evt); + + obx_ssm_event(p_scb, p_rxh->sm_evt, p_pkt); + if (chk_add) + { + if (p_scb->ll_cb.comm.p_send_fn == (tOBX_SEND_FN *)obx_rfc_snd_msg) + obx_add_port(p_scb->handle); + } + return FALSE; +} + +/******************************************************************************* +** +** Function obx_sr_prepend_msg +** +** Description This function is used by API functions to add the data in the +** reserved space in the OBEX packet +** +** Returns void. +** +*******************************************************************************/ +BT_HDR * obx_sr_prepend_msg(BT_HDR *p_pkt, UINT8 * p_data, UINT16 data_len) +{ + UINT8 *p; + UINT16 len; + + if (p_pkt == NULL) + { + p_pkt = OBX_HdrInit(OBX_HANDLE_NULL, OBX_MIN_MTU); + len = data_len; + } + else + { + len = p_pkt->len + data_len; + } + + WC_ASSERT(p_pkt->offset >= data_len); + p = (UINT8 *)(p_pkt + 1) + p_pkt->offset - data_len; + memcpy(p, p_data, data_len); + p++; + /* adjust the packet len */ + UINT16_TO_BE_STREAM(p, len); + p_pkt->len += data_len; + p_pkt->offset -= data_len; + p_pkt->layer_specific -= data_len; + + return p_pkt; +} +#endif /* OBX_SERVER_INCLUDED */ + +/******************************************************************************* +** +** Function obx_read_mtu +** +** Description This function is used to access the MTU in CONNECT packets +** +** Returns void. +** +*******************************************************************************/ +void obx_read_mtu(BT_HDR *p_pkt, tOBX_HANDLE handle, tOBX_CONN_EVT *p_evt) +{ + UINT8 *p = (UINT8 *)(p_pkt + 1) + p_pkt->offset + OBX_CONNECT_MTU_OFFSET; + + BE_STREAM_TO_UINT16(p_evt->mtu, p); + if (p_evt->mtu > OBX_MAX_MTU) + p_evt->mtu = OBX_MAX_MTU; + if (p_evt->mtu == 0) + p_evt->mtu = OBX_MIN_MTU; + + /* Get the Bd_Addr */ + OBX_GetPeerAddr (handle, p_evt->peer_addr); +} + +/******************************************************************************* +** +** Function obx_free_buf +** +** Description This function is used to free the GKI buffers of the given +** lower layer control block +** +** Returns void. +** +*******************************************************************************/ +void obx_free_buf(tOBX_LL_CB *p_ll_cb) +{ + void *p_pkt; + + + if (p_ll_cb->comm.p_send_fn == (tOBX_SEND_FN *)obx_rfc_snd_msg) + { + if (p_ll_cb->port.p_rxmsg) + { + OBX_TRACE_WARNING0("obx_free_buf release p_rxmsg"); + GKI_freebuf(p_ll_cb->port.p_rxmsg); + p_ll_cb->port.p_rxmsg = 0; + } + } + + if (!GKI_queue_is_empty(&p_ll_cb->comm.rx_q)) + { + while((p_pkt = GKI_dequeue (&p_ll_cb->comm.rx_q)) != NULL) + { + OBX_TRACE_WARNING0("obx_free_buf release rx_q"); + GKI_freebuf(p_pkt); + } + } + + if (p_ll_cb->comm.p_txmsg) + { + OBX_TRACE_WARNING0("obx_free_buf release p_txmsg"); + GKI_freebuf(p_ll_cb->comm.p_txmsg); + p_ll_cb->comm.p_txmsg = 0; + } +} + +/******************************************************************************* +** +** Function obx_flow_control +** +** Description If we had flowed control the peer, enable the data path now +** +** Returns void. +** +*******************************************************************************/ +void obx_flow_control(tOBX_COMM_CB *p_comm) +{ + OBX_TRACE_DEBUG1 ("obx_flow_control stopped:%d", p_comm->stopped ); + if (p_comm->stopped) + { + if (p_comm->p_send_fn == (tOBX_SEND_FN *)obx_rfc_snd_msg) + { + PORT_FlowControl(p_comm->id, TRUE); + } + else + { + L2CA_FlowControl(p_comm->id, TRUE); + } + p_comm->stopped = FALSE; + } +} + +/***************************************************************************** +* Function: obx_read_triplet +* Purpose: Read the application parameters with the given tag +*****************************************************************************/ +UINT8 obx_read_triplet(tOBX_TRIPLET *p_trip, UINT8 num_trip, UINT8 tag) +{ + UINT8 xx = 0; + + for (xx=0; xx<num_trip; xx++, p_trip++) + { + if (p_trip->tag == tag) + { + break; + } + } + + return xx; +} +/***************************************************************************** +* Function: obx_read_obj_offset +* Purpose: Read the application parameters with the object offset tag +*****************************************************************************/ +UINT32 obx_read_obj_offset(tOBX_TRIPLET *p_trip, UINT8 num_trip) +{ + UINT32 obj_offset = 0; + UINT8 ind; + UINT8 *p = NULL, *pe; + UINT8 extra = 0, xx; + + ind = obx_read_triplet(p_trip, num_trip, OBX_TAG_SESS_PARAM_OBJ_OFF); + if (ind != num_trip) + { + if (p_trip[ind].len == 4) + { + p = p_trip[ind].p_array; + } + else if (p_trip[ind].len > 4) + { + extra = p_trip[ind].len - 4; + } + + if (extra) + { + /* the TLV is bigger than 4 bytes + * if the MSBs are all 0, we can still handle it with UINT32 */ + pe = p_trip[ind].p_array; + for (xx=0; xx<extra; xx++) + { + if (*pe == 0) + pe++; + else + break; + } + if (xx == extra) + p = pe; + } + + if (p) + BE_STREAM_TO_UINT32(obj_offset, p); + } + + return obj_offset; +} + +/******************************************************************************* +** +** Function obxu_dump_hex +** +** Description This function dumps hex data +** +*/ +#if (BT_USE_TRACES == TRUE) +void obxu_dump_hex (UINT8 *p, char *p_title, UINT16 len) +{ + UINT16 xx, yy; + char buff1[100], buff2[20]; + + if (p_title) + OBX_TRACE_DEBUG1 ("%s:", p_title); + + memset (buff2, ' ', 16); + buff2[16] = 0; + + yy = sprintf (buff1, "%04x: ", 0); + for (xx = 0; xx < len; xx++) + { + if ( (xx) && ((xx & 15) == 0) ) + { + OBX_TRACE_DEBUG2 (" %s %s", buff1, buff2); + yy = sprintf(buff1, "%04x: ", xx); + memset (buff2, ' ', 16); + } + yy += sprintf (&buff1[yy], "%02x ", *p); + + if ((*p >= ' ') && (*p <= 'z')) + buff2[xx & 15] = *p; + else + buff2[xx & 15] = '.'; + + p++; + } + + /* Pad out the remainder */ + for ( ; ; xx++) + { + if ((xx & 15) == 0) + { + OBX_TRACE_DEBUG2 (" %s %s", buff1, buff2); + break; + } + yy += sprintf (&buff1[yy], " "); + } + +} +#endif + +/******************************************************************************* +** +** Function OBX_GetPeerAddr +** +** Description This function is called to learn the Bluetooth address of the +** connected device. +** +** Returns L2CAP channel ID. +** +*******************************************************************************/ +UINT16 OBX_GetPeerAddr(tOBX_HANDLE shandle, BD_ADDR bd_addr) +{ + UINT16 lcid = 0; +#if (OBX_SERVER_INCLUDED == TRUE) + tOBX_SR_SESS_CB *p_scb; +#endif +#if (OBX_CLIENT_INCLUDED == TRUE) + tOBX_CL_CB *p_cb; + + if (shandle & OBX_CL_HANDLE_MASK) + { + p_cb = obx_cl_get_cb(shandle); + if (p_cb) + { + if (p_cb->ll_cb.comm.p_send_fn == (tOBX_SEND_FN *)obx_rfc_snd_msg) + { + PORT_CheckConnection(p_cb->ll_cb.port.port_handle, p_cb->peer_addr, &lcid); + memcpy (bd_addr, p_cb->peer_addr, BD_ADDR_LEN); + lcid = p_cb->ll_cb.comm.id; + } + else if (p_cb->ll_cb.comm.id) + { + /* GetPeerAddr for l2c */ + memcpy (bd_addr, p_cb->peer_addr, BD_ADDR_LEN); + lcid = p_cb->ll_cb.comm.id; + } + } + } +#endif + +#if (OBX_SERVER_INCLUDED == TRUE) + if ((shandle & OBX_CL_HANDLE_MASK) == 0) + { + p_scb = obx_sr_get_scb(shandle); + if (p_scb) + { + if (p_scb->ll_cb.comm.p_send_fn == (tOBX_SEND_FN *)obx_rfc_snd_msg) + { + PORT_CheckConnection(p_scb->ll_cb.port.port_handle, bd_addr, &lcid); + } + else if (p_scb->ll_cb.comm.id) + { + /* GetPeerAddr for l2c */ + memcpy (bd_addr, p_scb->peer_addr, BD_ADDR_LEN); + lcid = p_scb->ll_cb.comm.id; + } + } + } +#endif + + return lcid; +} |