summaryrefslogtreecommitdiffstats
path: root/stack/obx/obx_sapi.c
diff options
context:
space:
mode:
Diffstat (limited to 'stack/obx/obx_sapi.c')
-rw-r--r--stack/obx/obx_sapi.c591
1 files changed, 591 insertions, 0 deletions
diff --git a/stack/obx/obx_sapi.c b/stack/obx/obx_sapi.c
new file mode 100644
index 0000000..7815947
--- /dev/null
+++ b/stack/obx/obx_sapi.c
@@ -0,0 +1,591 @@
+/*****************************************************************************
+**
+** Name: obx_sapi.c
+**
+** File: OBEX Server Application Programming Interface functions
+**
+** Copyright (c) 2003-2009, Broadcom Corp., All Rights Reserved.
+** WIDCOMM Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#include <string.h>
+
+#include "bt_target.h"
+
+#if defined(OBX_INCLUDED) && (OBX_INCLUDED == TRUE)
+
+#include "wcassert.h"
+#include "btu.h"
+#include "port_api.h"
+#include "obx_int.h"
+#include "l2c_api.h"
+#include "btm_api.h"
+
+/*******************************************************************************
+**
+** Function OBX_StartServer
+**
+** Description This function is to register a server entity to OBEX.
+**
+** Returns OBX_SUCCESS, if successful.
+** OBX_NO_RESOURCES, if OBX does not have resources.
+**
+*******************************************************************************/
+tOBX_STATUS OBX_StartServer(tOBX_StartParams *p_params, tOBX_HANDLE *p_handle)
+{
+ tOBX_SR_CB *p_cb = NULL;
+ tOBX_STATUS status = OBX_NO_RESOURCES;
+// btla-specific ++
+ tOBX_SR_SESS_CB *p_scb = NULL;
+// btla-specific --
+ tOBX_HANDLE obx_handle;
+ UINT8 size;
+
+ WC_ASSERT(p_params);
+ WC_ASSERT(p_params->p_cback);
+ WC_ASSERT(p_handle);
+
+ if (p_params->max_sessions > OBX_MAX_SR_SESSION)
+ {
+ OBX_TRACE_ERROR2("OBX_StartServer bad max_sessions:%d (1-%d)",
+ p_params->max_sessions, OBX_MAX_SR_SESSION);
+ return OBX_BAD_PARAMS;
+ }
+
+ if (p_params->scn == 0 && L2C_INVALID_PSM(p_params->psm))
+ {
+ OBX_TRACE_ERROR2("OBX_StartServer bad scn:%d and psm:0x%x", p_params->scn, p_params->psm);
+ return OBX_BAD_PARAMS;
+ }
+
+ if (p_params->max_sessions == 0)
+ p_params->max_sessions = 1;
+
+ /* allocate a server control block */
+ obx_handle = obx_sr_alloc_cb(p_params);
+ if (obx_handle)
+ p_cb = &obx_cb.server[obx_handle-1];
+
+ if (p_cb != NULL)
+ {
+ p_scb = &obx_cb.sr_sess[p_cb->sess[0]-1];
+ p_scb->ll_cb.port.rx_mtu = p_params->mtu;
+ if (p_cb->scn)
+ {
+ /* open an RFCOMM port to listen for incoming messages */
+ /* allocate the port for the first session now. The others will be allocated when needed */
+ status = obx_open_port(&p_scb->ll_cb.port, BT_BD_ANY, p_cb->scn);
+ }
+ else
+ {
+ status = OBX_SUCCESS;
+ }
+
+ if (status == OBX_SUCCESS)
+ {
+ /* If authentication is needed for this server, save the parameters in control block */
+ if (p_params->authenticate)
+ {
+ p_cb->p_auth = (tOBX_AUTH_PARAMS *)GKI_getbuf(sizeof(tOBX_AUTH_PARAMS)+OBX_MAX_REALM_LEN+1);
+ if (p_cb->p_auth)
+ {
+ p_cb->p_auth->auth_option = p_params->auth_option;
+ /* adjust realm len, if the given realm is too big */
+ size = (p_params->realm_len>OBX_MAX_REALM_LEN) ? OBX_MAX_REALM_LEN : p_params->realm_len;
+ p_cb->p_auth->realm_len = size;
+ p_cb->p_auth->realm[0] = p_params->realm_charset;
+ if (p_params->realm_len && p_params->p_realm)
+ memcpy(&p_cb->p_auth->realm[1], p_params->p_realm, size);
+ }
+ else
+ status = OBX_NO_RESOURCES;
+ }
+ }
+
+ if (status == OBX_SUCCESS)
+ {
+ /* if everything is OK, save the other parameters for this server */
+ memset(p_cb->target.target, 0, OBX_MAX_TARGET_LEN);
+ if (p_params->p_target)
+ {
+ if (p_params->p_target->len)
+ {
+ /* OBX handles who, connection ID headers */
+ p_cb->target.len = p_params->p_target->len;
+ memcpy(p_cb->target.target, p_params->p_target->target, p_params->p_target->len);
+ }
+ else
+ {
+ /* the regular default server */
+ /* the user handles target, who headers.
+ * OBX handles connection ID header */
+ p_cb->target.len = OBX_DEFAULT_TARGET_LEN;
+ }
+ }
+ else
+ {
+ /* the one and only default server */
+ /* no target, who, connection id headers for this case */
+ p_cb->target.len = 0;
+ }
+
+// btla-specific ++
+ if (p_scb)
+ {
+ OBX_TRACE_DEBUG3("OBX_StartServer target len:%d, authenticate:%d handle:0x%x",
+ p_cb->target.len, p_params->authenticate, p_scb->ll_cb.port.handle);
+ p_cb->p_cback = p_params->p_cback;
+ p_scb->state = OBX_SS_NOT_CONNECTED;
+
+ /* give the handle to application */
+ *p_handle = p_scb->ll_cb.port.handle;
+ }
+// btla-specific --
+ }
+ else
+ {
+ /* otherwise, free the control block */
+ obx_sr_free_cb(obx_handle);
+ }
+ }
+
+ return status;
+}
+
+
+/*******************************************************************************
+**
+** Function OBX_StopServer
+**
+** Description This function is to stop this OBEX server from receiving any
+** more incoming requests.
+**
+** Returns OBX_SUCCESS, if successful.
+** OBX_BAD_HANDLE, if the handle is not valid.
+**
+*******************************************************************************/
+tOBX_STATUS OBX_StopServer(tOBX_HANDLE handle)
+{
+ tOBX_STATUS status = OBX_SUCCESS;
+ tOBX_SR_CB *p_cb = obx_sr_get_cb(handle);
+ tOBX_SR_SESS_CB *p_scb;
+ int xx;
+ tOBX_SPND_CB *p_spndcb;
+
+ if (p_cb)
+ {
+ /* Process suspended session if necessary */
+ if (p_cb->p_suspend)
+ {
+ for (xx=0, p_spndcb=p_cb->p_suspend; xx<p_cb->max_suspend; xx++, p_spndcb++)
+ {
+ if (p_spndcb->state)
+ {
+ btu_stop_timer (&p_spndcb->stle);
+ }
+ }
+ GKI_freebuf (p_cb->p_suspend);
+ }
+
+ for (xx=0; xx < p_cb->num_sess && p_cb->sess[xx]; xx ++)
+ {
+ p_scb = &obx_cb.sr_sess[p_cb->sess[xx]-1];
+ if (p_scb->ll_cb.comm.id)
+ {
+ OBX_DisconnectRsp(handle, OBX_RSP_SERVICE_UNAVL, NULL);
+ if (p_scb->ll_cb.comm.p_send_fn == (tOBX_SEND_FN *)obx_rfc_snd_msg)
+ RFCOMM_RemoveServer(p_scb->ll_cb.port.port_handle);
+ }
+ }
+
+ if (p_cb->psm)
+ L2CA_DEREGISTER (p_cb->psm);
+
+ obx_sr_free_cb (handle);
+ }
+ else
+ status = OBX_BAD_HANDLE;
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function OBX_AddSuspendedSession
+**
+** Description This function is to add the session information for a previously
+** suspended reliable session to the server control block
+**
+** Returns OBX_SUCCESS, if successful.
+** OBX_BAD_HANDLE, if the handle is not valid.
+**
+*******************************************************************************/
+tOBX_STATUS OBX_AddSuspendedSession(tOBX_HANDLE shandle, BD_ADDR peer_addr, UINT8 *p_sess_info,
+ UINT32 timeout, UINT8 ssn, UINT32 offset)
+{
+ tOBX_STATUS status = OBX_SUCCESS;
+ tOBX_SR_CB *p_cb = obx_sr_get_cb(shandle);
+ UINT16 size;
+ UINT8 xx;
+ tOBX_SPND_CB *p_spndcb;
+ INT32 ticks = 0x7FFFFFFF, remain_ticks;
+ BOOLEAN added = FALSE;
+ UINT8 saved_xx = 0;
+
+ OBX_TRACE_DEBUG2("OBX_AddSuspendedSession BDA: %06x%06x",
+ (peer_addr[0]<<16)+(peer_addr[1]<<8)+peer_addr[2],
+ (peer_addr[3]<<16)+(peer_addr[4]<<8)+peer_addr[5]);
+ if (p_cb && p_sess_info && p_cb->max_suspend)
+ {
+ if (p_cb->p_suspend == NULL)
+ {
+ size = p_cb->max_suspend * sizeof (tOBX_SPND_CB);
+ p_cb->p_suspend = (tOBX_SPND_CB *)GKI_getbuf( size);
+ memset (p_cb->p_suspend, 0, size);
+ }
+
+ if (p_cb->p_suspend)
+ {
+ for (xx=0, p_spndcb=p_cb->p_suspend; xx<p_cb->max_suspend; xx++, p_spndcb++)
+ {
+ OBX_TRACE_DEBUG4("[%d] state: %d, ssn:%d BDA: %08x", xx, p_spndcb->state, p_spndcb->ssn,
+ (p_spndcb->peer_addr[2]<<24)+(p_spndcb->peer_addr[3]<<16)+(p_spndcb->peer_addr[4]<<8)+p_spndcb->peer_addr[5]);
+ if (p_spndcb->state == OBX_SS_NULL || memcmp(p_spndcb->peer_addr, peer_addr, BD_ADDR_LEN) == 0)
+ {
+ added = TRUE;
+ break;
+ }
+ else if (p_spndcb->state != OBX_SS_NULL && ticks)
+ {
+ if (p_spndcb->stle.param == 0)
+ {
+ /* this entry has infinite timeout; just use it */
+ ticks = 0;
+ saved_xx = xx;
+ OBX_TRACE_DEBUG1("[%d] infinite timeout", xx );
+ }
+ /* find the entry the expires in the shortest time */
+ else
+ {
+ remain_ticks = btu_remaining_time(&p_spndcb->stle);
+ OBX_TRACE_DEBUG2("[%d] remain_ticks: %d", xx, remain_ticks );
+ if (remain_ticks < ticks)
+ {
+ ticks = remain_ticks;
+ saved_xx = xx;
+ }
+ }
+ }
+ }
+
+ if (!added)
+ {
+ /* if cannot use an empty/or reuse an existing entry, use the one expires soon */
+ added = TRUE;
+ xx = saved_xx; /* this is for debug trace; don't optimize */
+ p_spndcb = &p_cb->p_suspend[xx];
+ OBX_TRACE_DEBUG1("reuse entry [%d]", xx );
+ }
+
+ if (added)
+ {
+ memcpy (p_spndcb->sess_info, p_sess_info, OBX_SESSION_INFO_SIZE);
+ p_spndcb->state = p_sess_info[OBX_SESSION_INFO_ST_IDX];
+ p_spndcb->ssn = ssn;
+ p_spndcb->offset = offset;
+ OBX_TRACE_DEBUG6("[%d] timeout: %d state:%d ssn:%d offset:%d, BDA: %08x",
+ xx, timeout, p_spndcb->state, ssn, offset,
+ (peer_addr[2]<<24)+(peer_addr[3]<<16)+(peer_addr[4]<<8)+peer_addr[5]);
+ memcpy(p_spndcb->peer_addr, peer_addr, BD_ADDR_LEN);
+ if (timeout != OBX_INFINITE_TIMEOUT)
+ {
+ p_spndcb->stle.param = (UINT32)p_spndcb;
+ btu_start_timer(&p_spndcb->stle, BTU_TTYPE_OBX_SVR_SESS_TO, timeout);
+ OBX_TRACE_DEBUG2("timeout: %d ticks:%d", timeout, p_spndcb->stle.ticks);
+ }
+ else
+ p_spndcb->stle.param = 0;
+ }
+ }
+ }
+ else
+ status = OBX_BAD_HANDLE;
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function OBX_ConnectRsp
+**
+** Description This function is called to send the response to a Connect
+** Request from an OBEX client.
+**
+** Returns OBX_SUCCESS, if successful.
+** OBX_BAD_HANDLE, if the handle is not valid.
+**
+*******************************************************************************/
+tOBX_STATUS OBX_ConnectRsp(tOBX_HANDLE shandle, UINT8 rsp_code, BT_HDR *p_pkt)
+{
+ tOBX_STATUS status = OBX_SUCCESS;
+ tOBX_SR_SESS_CB *p_scb = obx_sr_get_scb(shandle);
+ tOBX_SR_CB *p_cb = obx_sr_get_cb(shandle);
+
+ if (p_scb)
+ {
+ p_pkt = obx_conn_rsp(p_cb, p_scb, rsp_code, p_pkt);
+
+ obx_ssm_event(p_scb, OBX_CONNECT_CFM_SEVT, p_pkt);
+ }
+ else
+ {
+ OBX_TRACE_DEBUG1("OBX_ConnectRsp Bad Handle: 0x%x", shandle);
+ status = OBX_BAD_HANDLE;
+ }
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function OBX_SessionRsp
+**
+** Description This function is called to respond to a request to create a reliable session.
+**
+**
+** Returns OBX_SUCCESS, if successful.
+** OBX_BAD_HANDLE, if the handle is not valid.
+**
+*******************************************************************************/
+tOBX_STATUS OBX_SessionRsp(tOBX_HANDLE shandle, UINT8 rsp_code, UINT8 ssn, UINT32 offset, BT_HDR *p_pkt)
+{
+ tOBX_STATUS status = OBX_SUCCESS;
+ tOBX_SR_SESS_CB *p_scb = obx_sr_get_scb(shandle);
+ UINT8 *p;
+ BT_HDR *p_rsp = NULL;
+ tOBX_TRIPLET triplet[5];
+ UINT8 data[12];
+ UINT8 num_trip = 0;
+ UINT32 timeout;
+ tOBX_SESS_ST old_sess_st;
+
+ OBX_TRACE_API0("OBX_SessionRsp");
+ if (p_scb)
+ {
+ old_sess_st = p_scb->sess_st;
+ p_rsp = OBX_HdrInit(p_scb->handle, OBX_MIN_MTU);
+ if (p_rsp)
+ {
+ p = (UINT8 *) (p_rsp + 1) + p_rsp->offset;
+ /* response packet always has the final bit set */
+ *p++ = (rsp_code | OBX_FINAL);
+ p_rsp->len = 3;
+ p = data;
+ if (rsp_code == OBX_RSP_OK)
+ {
+ switch (p_scb->sess_st)
+ {
+ case OBX_SESS_CREATE:
+ case OBX_SESS_RESUME:
+ GKI_freebuf (p_rsp);
+ if (p_pkt)
+ GKI_freebuf (p_pkt);
+ OBX_TRACE_DEBUG0("OBX_SessionRsp do not need to be called for CREATE and RESUME");
+ return OBX_SUCCESS;
+ case OBX_SESS_SUSPEND:
+ p_scb->sess_st = OBX_SESS_SUSPENDED;
+ p = &p_scb->sess_info[OBX_SESSION_INFO_TO_IDX];
+ BE_STREAM_TO_UINT32(timeout, p);
+ OBX_AddSuspendedSession(p_scb->handle, p_scb->peer_addr, p_scb->sess_info, timeout, ssn, offset);
+ break;
+ case OBX_SESS_CLOSE:
+ p_scb->sess_st = OBX_SESS_NONE;
+ break;
+ }
+
+ if (num_trip)
+ OBX_AddTriplet(p_rsp, OBX_HI_SESSION_PARAM, triplet, num_trip);
+ if (p_pkt)
+ {
+ p = (UINT8 *) (p_rsp + 1) + p_rsp->offset + p_rsp->len;
+ memcpy (p, ((UINT8 *) (p_pkt + 1) + p_pkt->offset), p_pkt->len);
+ p_rsp->len += p_pkt->len;
+ }
+ }
+ p = (UINT8 *) (p_rsp + 1) + p_rsp->offset + 1;
+ UINT16_TO_BE_STREAM(p, p_rsp->len);
+
+ p_rsp->event = OBX_SESSION_CFM_SEVT + 1;
+ }
+ OBX_TRACE_DEBUG3("Rsp sess_st:%d->%d status:%d", old_sess_st, p_scb->sess_st, status);
+
+ obx_ssm_event(p_scb, OBX_SESSION_CFM_SEVT, p_rsp);
+ /* clear the "previous" session state as required by earlier comment */
+ p_scb->param.sess.sess_st = 0;
+ }
+ else
+ status = OBX_BAD_HANDLE;
+
+ if (p_pkt)
+ {
+ GKI_freebuf (p_pkt);
+ }
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function obx_prepend_rsp_msg
+**
+** Description This function is called to add response code and connection ID
+** to the given OBEX message
+** Returns OBX_SUCCESS, if successful.
+** OBX_BAD_HANDLE, if the handle is not valid.
+**
+*******************************************************************************/
+tOBX_STATUS obx_prepend_rsp_msg(tOBX_HANDLE shandle, tOBX_SR_EVENT event, UINT8 rsp_code, BT_HDR *p_pkt)
+{
+ tOBX_STATUS status = OBX_SUCCESS;
+ tOBX_SR_SESS_CB *p_scb = obx_sr_get_scb(shandle);
+ UINT8 msg[OBX_HDR_OFFSET];
+ UINT8 *p = msg;
+
+ if (p_scb)
+ {
+ /* response packets always have the final bit set */
+ *p++ = (rsp_code | OBX_FINAL);
+ p += OBX_PKT_LEN_SIZE;
+
+ /* add session sequence number, if session is active */
+ if (p_scb->sess_st == OBX_SESS_ACTIVE || p_scb->sess_st == OBX_SESS_SUSPENDING)
+ {
+ *p++ = OBX_HI_SESSION_SN;
+ *p++ = (p_scb->ssn+1);
+ }
+
+ if (event == OBX_DISCNT_CFM_SEVT)
+ p_scb->conn_id = 0;
+
+ if (p_scb->srm & OBX_SRM_REQING)
+ {
+ p_scb->srm &= ~OBX_SRM_REQING;
+ if (rsp_code == OBX_RSP_CONTINUE)
+ {
+ p_scb->srm |= OBX_SRM_ENGAGE;
+ *p++ = OBX_HI_SRM;
+ *p++ = OBX_HV_SRM_ENABLE;
+
+ if (event == OBX_PUT_CFM_SEVT)
+ p_scb->srm |= OBX_SRM_NEXT;
+ }
+ }
+
+ p_pkt = obx_sr_prepend_msg(p_pkt, msg, (UINT16)(p - msg) );
+ /* this event code needs to be set up properly for flow control reasons */
+ p_pkt->event = event+1;
+ obx_ssm_event(p_scb, event, p_pkt);
+ }
+ else
+ status = OBX_BAD_HANDLE;
+
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function OBX_SetPathRsp
+**
+** Description This function is called to send the response to a Set Path
+** Request from an OBEX client.
+**
+** Returns OBX_SUCCESS, if successful.
+** OBX_BAD_HANDLE, if the handle is not valid.
+**
+*******************************************************************************/
+tOBX_STATUS OBX_SetPathRsp(tOBX_HANDLE shandle, UINT8 rsp_code, BT_HDR *p_pkt)
+{
+ return obx_prepend_rsp_msg(shandle, OBX_SETPATH_CFM_SEVT, rsp_code, p_pkt);
+}
+
+
+/*******************************************************************************
+**
+** Function OBX_PutRsp
+**
+** Description This function is called to send the response to a Put
+** Request from an OBEX client.
+**
+** Returns OBX_SUCCESS, if successful.
+** OBX_BAD_HANDLE, if the handle is not valid.
+**
+*******************************************************************************/
+tOBX_STATUS OBX_PutRsp(tOBX_HANDLE shandle, UINT8 rsp_code, BT_HDR *p_pkt)
+{
+ return obx_prepend_rsp_msg(shandle, OBX_PUT_CFM_SEVT, rsp_code, p_pkt);
+}
+
+
+/*******************************************************************************
+**
+** Function OBX_GetRsp
+**
+** Description This function is called to send the response to a Get
+** Request from an OBEX client.
+**
+** Returns OBX_SUCCESS, if successful.
+** OBX_BAD_HANDLE, if the handle is not valid.
+**
+*******************************************************************************/
+tOBX_STATUS OBX_GetRsp(tOBX_HANDLE shandle, UINT8 rsp_code, BT_HDR *p_pkt)
+{
+ return obx_prepend_rsp_msg(shandle, OBX_GET_CFM_SEVT, rsp_code, p_pkt);
+}
+
+
+/*******************************************************************************
+**
+** Function OBX_AbortRsp
+**
+** Description This function is called to send the response to an Abort
+** Request from an OBEX client.
+**
+** Returns OBX_SUCCESS, if successful.
+** OBX_BAD_HANDLE, if the handle is not valid.
+**
+*******************************************************************************/
+tOBX_STATUS OBX_AbortRsp(tOBX_HANDLE shandle, UINT8 rsp_code, BT_HDR *p_pkt)
+{
+ return obx_prepend_rsp_msg(shandle, OBX_ABORT_CFM_SEVT, rsp_code, p_pkt);
+}
+
+/*******************************************************************************
+**
+** Function OBX_ActionRsp
+**
+** Description This function is called to respond to an Action command Request
+** from an OBEX client.
+**
+** Returns OBX_SUCCESS, if successful.
+** OBX_BAD_HANDLE, if the handle is not valid.
+**
+*******************************************************************************/
+tOBX_STATUS OBX_ActionRsp(tOBX_HANDLE shandle, UINT8 rsp_code, BT_HDR *p_pkt)
+{
+ return obx_prepend_rsp_msg(shandle, OBX_ACTION_CFM_SEVT, rsp_code, p_pkt);
+}
+
+/*******************************************************************************
+**
+** Function OBX_DisconnectRsp
+**
+** Description This function is called to send the response to a Disconnect
+** Request from an OBEX client.
+** This function can also be used to force close the transport
+** to a connected client.
+**
+** Returns OBX_SUCCESS, if successful.
+** OBX_BAD_HANDLE, if the handle is not valid.
+**
+*******************************************************************************/
+tOBX_STATUS OBX_DisconnectRsp(tOBX_HANDLE shandle, UINT8 rsp_code, BT_HDR *p_pkt)
+{
+ return obx_prepend_rsp_msg(shandle, OBX_DISCNT_CFM_SEVT, rsp_code, p_pkt);
+}
+#endif