/*--------------------------------------------------------------------------- * OBEXH_BuildByteSeq() *--------------------------------------------------------------------------- * * Synopsis: Builds Byte Sequence and UNICODE style OBEX headers. Used by * both client and server functions. * * Return: TRUE if headers could be added. * FALSE if headers would exceed limits on buffer or transmit space. */ BOOL OBEXH_BuildByteSeq(ObexAppHandle *AppHndl, ObexHeaderType Type, const U8 *Value, U16 Len) { OS_LockObex(); #if XA_ERROR_CHECK == XA_ENABLED if (!AppHndl || !ObIsHeaderSpaceAvail(AppHndl, (U16)(Len+3)) || ((Type & 0xC0) != 0x40 && (Type & 0xC0) != 0)) { OS_UnlockObex(); return FALSE; } #endif /* XA_ERROR_CHECK == XA_ENABLED */ ASSERT(AppHndl && AppHndl->buffer != 0); ASSERT(ObIsHeaderSpaceAvail(AppHndl, (U16)(Len+3)) && ((Type & 0xC0) == 0x40 || (Type & 0xC0) == 0)); if (Type == OBEXH_END_BODY) { AppHndl->appHeaderIsEndBody = TRUE; } AppHndl->buffer[AppHndl->txLength++] = Type; AppHndl->buffer[AppHndl->txLength++] = (U8)((Len+3) >> 8); AppHndl->buffer[AppHndl->txLength++] = (U8) (Len+3); if (Len > 0) { ASSERT( Value != 0 ); OS_MemCopy(AppHndl->buffer+AppHndl->txLength, Value, Len); AppHndl->txLength += Len; } OS_UnlockObex(); return TRUE; }
/*--------------------------------------------------------------------------- * OBEXH_FlushHeaders() *--------------------------------------------------------------------------- * * Synopsis: This function is used to flush any constructed headers from * the header buffer. This function is used when OBEXH_Build...() * functions are used and the operation is cancelled before the * headers are sent or if the requested Operation fails to start. * * Return: void */ void OBEXH_FlushHeaders(ObexAppHandle *AppHndl) { ASSERT(AppHndl); OS_LockObex(); AppHndl->txLength = 0; OS_UnlockObex(); }
/*--------------------------------------------------------------------------- * OBEXH_Build1Byte() *--------------------------------------------------------------------------- * * Synopsis: Builds 1-byte style OBEX headers. Used by both client and * server functions. * * Return: TRUE if headers could be added. * FALSE if headers would exceed limits on buffer or transmit space. */ BOOL OBEXH_Build1Byte(ObexAppHandle *AppHndl, ObexHeaderType Type, U8 Value) { OS_LockObex(); #if XA_ERROR_CHECK == XA_ENABLED if (!AppHndl || !ObIsHeaderSpaceAvail(AppHndl, 2) || (Type & 0xC0) != 0x80) { OS_UnlockObex(); return FALSE; } #endif /* XA_ERROR_CHECK == XA_ENABLED */ ASSERT(AppHndl && AppHndl->buffer != 0); ASSERT(ObIsHeaderSpaceAvail(AppHndl, 2) && (Type & 0xC0) == 0x80); AppHndl->buffer[AppHndl->txLength++] = Type; AppHndl->buffer[AppHndl->txLength++] = Value; OS_UnlockObex(); return TRUE; }
/*--------------------------------------------------------------------------- * OBEXH_BuildEmptyEndBody() *--------------------------------------------------------------------------- * * Synopsis: Builds empty OBEX headers. Used by both client and * server functions. * * Return: TRUE if headers could be added. * FALSE if headers would exceed limits on buffer or transmit space. */ BOOL OBEXH_BuildEmptyEndBody(ObexAppHandle *AppHndl) { OS_LockObex(); #if XA_ERROR_CHECK == XA_ENABLED if (!AppHndl || !ObIsHeaderSpaceAvail(AppHndl, 1)) { OS_UnlockObex(); return FALSE; } #endif /* XA_ERROR_CHECK == XA_ENABLED */ ASSERT(AppHndl && AppHndl->buffer != 0); ASSERT(ObIsHeaderSpaceAvail(AppHndl, 1)); AppHndl->buffer[AppHndl->txLength++] = OBEXH_END_BODY; AppHndl->buffer[AppHndl->txLength++] = 0x00; AppHndl->buffer[AppHndl->txLength++] = 0x03; OS_UnlockObex(); return TRUE; }
/*--------------------------------------------------------------------------- * OBEXH_Build4Byte() *--------------------------------------------------------------------------- * * Synopsis: Builds 4-byte style OBEX headers. Used by both client and * server functions. * * Return: TRUE if headers could be added. * FALSE if headers would exceed limits on buffer or transmit space. */ BOOL OBEXH_Build4Byte(ObexAppHandle *AppHndl, ObexHeaderType Type, U32 Value) { OS_LockObex(); #if XA_ERROR_CHECK == XA_ENABLED if (!AppHndl || !ObIsHeaderSpaceAvail(AppHndl, 5) || ((Type & 0xC0) != 0xC0)) { OS_UnlockObex(); return FALSE; } #endif /* XA_ERROR_CHECK == XA_ENABLED */ ASSERT(AppHndl && AppHndl->buffer != 0); ASSERT(ObIsHeaderSpaceAvail(AppHndl, 5) && (Type & 0xC0) == 0xC0); AppHndl->buffer[AppHndl->txLength++] = Type; StoreBE32( AppHndl->buffer+AppHndl->txLength, Value); AppHndl->txLength += 4; OS_UnlockObex(); return TRUE; }
/*--------------------------------------------------------------------------- * OBEXH_GetAvailableTxHeaderLen() *--------------------------------------------------------------------------- * * Synopsis: Returns the amount of header space available for adding more * headers. This value is constrained by the OBEX Packet size, * the application provided header buffer size and any headers * which are already present in the buffer. * * Return: Available header buffer length in bytes. */ U16 OBEXH_GetAvailableTxHeaderLen(ObexAppHandle *AppHndl) { #if OBEX_SERVER_CONS_SIZE > 0 || OBEX_SESSION_SUPPORT == XA_ENABLED void *ObexApp = AppHndl; #endif /* OBEX_SERVER_CONS_SIZE > 0 || OBEX_SESSION_SUPPORT == XA_ENABLED */ U16 avail; ASSERT(AppHndl); OS_LockObex(); /* Just assume Connect to get a size that will always work. */ avail = ObParserMaxHbSize(&AppHndl->parser, OB_OPCODE_CONNECT); #if (OBEX_SERVER_CONS_SIZE > 0) || (OBEX_SESSION_SUPPORT == XA_ENABLED) if (IsServerParser(&AppHndl->parser)) { #if OBEX_ROLE_SERVER == XA_ENABLED avail -= OSC(protoTxLen); #endif /* OBEX_ROLE_SERVER == XA_ENABLED */ } #if OBEX_SESSION_SUPPORT == XA_ENABLED else { ASSERT(IsClientParser(&AppHndl->parser)); #if OBEX_ROLE_CLIENT == XA_ENABLED avail -= OCC(protoTxLen); #endif /* OBEX_ROLE_CLIENT == XA_ENABLED */ } #endif /* OBEX_SESSION_SUPPORT == XA_ENABLED */ #endif /* (OBEX_SERVER_CONS_SIZE > 0) || (OBEX_SESSION_SUPPORT == XA_ENABLED) */ avail = min(avail, AppHndl->length); avail -= AppHndl->txLength; OS_UnlockObex(); return avail; }
/*--------------------------------------------------------------------------- * OBEXH_ParseTlv *--------------------------------------------------------------------------- * * Synopsis: Sniffs out a TLV from the current header * * Return: TRUE if parsing was successful. * FALSE if an error occurred or no more TLVs are present. */ BOOL OBEXH_ParseTlv(ObexAppHandle *AppHndl, ObexTlv *tlv) { U8 *buffer; U16 len; U8 toUse; BOOL success = FALSE; CheckUnlockedParm(FALSE, AppHndl && tlv); OS_LockObex(); /* On the first OBxx_HEADER_RX indication there is no data available. * Use this event to initialize the parser. */ if (AppHndl->parser.dataLen == 0) { /* ASSERT that we are in the correct internal state to parse * this header, and that it is a byte sequence header */ ASSERT((AppHndl->parser).rxState == OBSC_RX_PUT_HEAD2); ASSERT(((AppHndl->parser).header & 0xC0) == 0x40); /* Initialize key fields */ AppHndl->tlv.state = 0; buffer = 0; len = 0; goto Done; } /* Use these locals as aliases for the AppHndl fields */ buffer = AppHndl->tlv.headerBuff; len = AppHndl->tlv.headerLen; if (buffer == 0) { buffer = AppHndl->parser.rxBuff; len = AppHndl->parser.dataLen; } while (len) { switch (AppHndl->tlv.state) { case 0: /* Buff points to option type */ AppHndl->tlv.tag = *buffer++; AppHndl->tlv.state = 1; len--; break; case 1: /* Buff points to option length */ AppHndl->tlv.length = *buffer++; AppHndl->tlv.state = 2; AppHndl->tlv.valuePos = 0; len--; /* No break; fall through to handle option data */ case 2: /* Update length of option data we currently need. */ toUse = min(AppHndl->tlv.length - AppHndl->tlv.valuePos, len); /* Fill in tlv values in case they are necessary */ tlv->tag = AppHndl->tlv.tag; tlv->length = AppHndl->tlv.length; /* Is reassembly both necessary and possible for this TLV? */ #if OBEX_TLV_BUFF_SIZE > 0 if ((toUse < AppHndl->tlv.length) && (AppHndl->tlv.length < OBEX_TLV_BUFF_SIZE)) { /* Append recevied data into our staging buffer */ OS_MemCopy(AppHndl->tlv.value + AppHndl->tlv.valuePos, buffer, toUse); AppHndl->tlv.valuePos += toUse; tlv->value = AppHndl->tlv.value; tlv->valueLen = AppHndl->tlv.length; len -= toUse; buffer += toUse; /* Indicate success ONLY if we have completed staging */ tlv->remainLen = (tlv->length - AppHndl->tlv.valuePos); success = (tlv->remainLen == 0); } else { #endif /* OBEX_TLV_BUFF_SIZE > 0 */ /* If reassembly is impossible or unnecessary, simply copy * tag information */ tlv->value = buffer; tlv->valueLen = toUse; AppHndl->tlv.valuePos += toUse; len -= toUse; buffer += toUse; /* Indicate "last" if we are indicating the last chunk of bytes * as counted by valuePos */ tlv->remainLen = (tlv->length - AppHndl->tlv.valuePos); /* Indicate success because staging isn't going to happen */ success = TRUE; #if OBEX_TLV_BUFF_SIZE > 0 } #endif /* OBEX_TLV_BUFF_SIZE > 0 */ if (success) { /* If we have reached the end of the tlv then reset state for * next time */ if (tlv->remainLen == 0) { AppHndl->tlv.state = 0; } goto Done; } break; } } /* If control gets here we have exhausted the buffer */ buffer = 0; Done: /* Reset buffer/length from locals and return success */ AppHndl->tlv.headerBuff = buffer; AppHndl->tlv.headerLen = len; OS_UnlockObex(); return success; }
/*--------------------------------------------------------------------------- * OBEXH_BuildAuthResponse *--------------------------------------------------------------------------- * * Synopsis: This function is used by applications to build an Authentication * response to a received Challenge. The header is constructed from * the fields in the ObexAuthResponse structure. * * Return: TRUE if header was successfully built. * FALSE if headers would exceed limits on buffer or transmit space. */ BOOL OBEXH_BuildAuthResponse(ObexAppHandle *AppHndl, ObexAuthResponse *Response, U8 *Nonce) { U8 len; xMD5Context context; //#if XA_DEBUG == XA_ENABLED U8 *orig; //#endif /* XA_DEBUG == XA_ENABLED */ OS_LockObex(); #if XA_ERROR_CHECK == XA_ENABLED if (!AppHndl || !Response || !Nonce) { OS_UnlockObex(); return FALSE; } #endif /* XA_ERROR_CHECK == XA_ENABLED */ ASSERT(AppHndl && Response && Nonce); len = CALC_RESPONSE_LEN(Response); //#if XA_DEBUG == XA_ENABLED orig = AppHndl->buffer + AppHndl->txLength; //#endif /* XA_DEBUG == XA_ENABLED */ #if XA_ERROR_CHECK == XA_ENABLED if (!ObIsHeaderSpaceAvail(AppHndl, (U16)(len+3))) { OS_UnlockObex(); return FALSE; } #endif ASSERT(ObIsHeaderSpaceAvail(AppHndl, (U16)(len+3))); /* Build the OBEX Response Header Identifier */ AppHndl->buffer[AppHndl->txLength++] = OBEXH_AUTH_RESP; AppHndl->buffer[AppHndl->txLength++] = (U8)((len+3) >> 8); AppHndl->buffer[AppHndl->txLength++] = (U8) (len+3); /* Build digest from nonce and password */ AppHndl->buffer[AppHndl->txLength++] = 0; /* Request Digest Code */ AppHndl->buffer[AppHndl->txLength++] = AUTH_NONCE_LEN; /* Digest Length (16 bytes) */ xMD5Init(&context); xMD5Update(&context, Nonce, AUTH_NONCE_LEN); xMD5Update(&context, (U8 *)":", 1); xMD5Update(&context, Response->password, Response->passwordLen); xMD5Final(AppHndl->buffer+AppHndl->txLength, &context); AppHndl->txLength += AUTH_NONCE_LEN; /* Add UserId */ if (Response->userIdLen) { AppHndl->buffer[AppHndl->txLength++] = 1; /* UserId */ AppHndl->buffer[AppHndl->txLength++] = Response->userIdLen; /* Realm Len */ OS_MemCopy(AppHndl->buffer+AppHndl->txLength, Response->userId, Response->userIdLen); AppHndl->txLength += Response->userIdLen; } /* Add Nonce */ AppHndl->buffer[AppHndl->txLength++] = 2; /* Nonce */ AppHndl->buffer[AppHndl->txLength++] = AUTH_NONCE_LEN; /* (16 bytes) */ OS_MemCopy(AppHndl->buffer+AppHndl->txLength, Nonce, AUTH_NONCE_LEN); AppHndl->txLength += AUTH_NONCE_LEN; //#if XA_DEBUG == XA_ENABLED ASSERT((orig + len + 3) == (AppHndl->buffer + AppHndl->txLength)); //#endif OS_UnlockObex(); return TRUE; }
/*--------------------------------------------------------------------------- * OBEXH_BuildAuthChallenge *--------------------------------------------------------------------------- * * Synopsis: OBEX applications use this function to build an Authentication * Challenge header. The header is constructed from the field * values in the ObexAuthChallenge structure. * * Return: TRUE if header was successfully built. * FALSE if headers would exceed limits on buffer or transmit space. */ BOOL OBEXH_BuildAuthChallenge(ObexAppHandle *AppHndl, ObexAuthChallenge *Challenge, U8 *NonceOut) { U8 len; //#if XA_DEBUG == XA_ENABLED U8 *orig; //#endif /* XA_DEBUG == XA_ENABLED */ OS_LockObex(); #if XA_ERROR_CHECK == XA_ENABLED if (!AppHndl || !Challenge ) { OS_UnlockObex(); return FALSE; } #endif /* XA_ERROR_CHECK == XA_ENABLED */ ASSERT(AppHndl && Challenge); len = CALC_CHALLENGE_LEN(Challenge); //#if XA_DEBUG == XA_ENABLED orig = AppHndl->buffer + AppHndl->txLength; //#endif /* XA_DEBUG == XA_ENABLED */ #if XA_ERROR_CHECK == XA_ENABLED if (!ObIsHeaderSpaceAvail(AppHndl, (U16)(len+3))) { OS_UnlockObex(); return FALSE; } #endif /* XA_ERROR_CHECK == XA_ENABLED */ ASSERT(ObIsHeaderSpaceAvail(AppHndl, (U16)(len+3))); /* Build the OBEX Challenge Header Identifier */ AppHndl->buffer[AppHndl->txLength++] = OBEXH_AUTH_CHAL; AppHndl->buffer[AppHndl->txLength++] = (U8)((len+3) >> 8); AppHndl->buffer[AppHndl->txLength++] = (U8) (len+3); /* Build nonce from challenge string */ AppHndl->buffer[AppHndl->txLength++] = 0; /* Nonce Code */ AppHndl->buffer[AppHndl->txLength++] = AUTH_NONCE_LEN; /* (16 bytes) */ MD5(AppHndl->buffer+AppHndl->txLength, Challenge->challenge, Challenge->challengeLen); if (NonceOut) OS_MemCopy(NonceOut, AppHndl->buffer+AppHndl->txLength, AUTH_NONCE_LEN); AppHndl->txLength += AUTH_NONCE_LEN; /* Add Options */ if (Challenge->options) { AppHndl->buffer[AppHndl->txLength++] = 1; /* Options Code */ AppHndl->buffer[AppHndl->txLength++] = 1; /* Options Len */ AppHndl->buffer[AppHndl->txLength++] = Challenge->options; /* Options */ } /* Add Realm */ if (Challenge->realmLen) { AppHndl->buffer[AppHndl->txLength++] = 2; /* Realm Code */ AppHndl->buffer[AppHndl->txLength++] = Challenge->realmLen; /* Realm Len */ OS_MemCopy(AppHndl->buffer+AppHndl->txLength, Challenge->realm, Challenge->realmLen); AppHndl->txLength += Challenge->realmLen; } //#if XA_DEBUG == XA_ENABLED ASSERT((orig + len + 3) == (AppHndl->buffer + AppHndl->txLength)); //#endif OS_UnlockObex(); return TRUE; }
/*--------------------------------------------------------------------------- * TcpCallback *--------------------------------------------------------------------------- * * Synopsis: Process events from the client and server transport. * */ static void TcpCallback(ObTcpCommonTransport *txp, U8 EventType, void *Parm1, U16 Parm2) { #if (OBEX_ROLE_SERVER == XA_ENABLED) || (OBEX_ALLOW_SERVER_TP_CONNECT == XA_ENABLED) I32 rcode; #endif /* (OBEX_ROLE_SERVER == XA_ENABLED) || (OBEX_ALLOW_SERVER_TP_CONNECT == XA_ENABLED) */ OS_LockObex(); switch (EventType) { #if (OBEX_ROLE_SERVER == XA_ENABLED) || (OBEX_ALLOW_SERVER_TP_CONNECT == XA_ENABLED) case TCP_EVENT_CONNECT_IND: /* TCP Server Event */ /* Accept the incoming connection to our server if it's idle. */ if (OBPROT_LinkTransport(txp->app, &txp->transport)) { ASSERT(txp->state == OCS_IDLE); txp->state = OCS_CONNECTING; /* Save the connection handle */ txp->conn = accept(((ObTcpServerTransport *)txp)->serverReg, 0, 0); ASSERT(txp->conn != INVALID_SOCKET); rcode = WSAAsyncSelect(txp->conn, asyncEventHandle, WM_SELECT, FD_WRITE|FD_CLOSE); ASSERT(rcode != SOCKET_ERROR); } else { /* Reject the connection, the parser is busy. */ txp->conn = accept(((ObTcpServerTransport *)txp)->serverReg, 0, 0); ASSERT(txp->conn != INVALID_SOCKET); closesocket(txp->conn); txp->conn = INVALID_SOCKET; } break; #endif /* (OBEX_ROLE_SERVER == XA_ENABLED) || (OBEX_ALLOW_SERVER_TP_CONNECT == XA_ENABLED) */ case TCP_EVENT_CONNECTED: /* Save the new connection handle (Client only) */ txp->conn = Parm2; txp->state = OCS_CONNECTED; /* Tell the application that the server has accepted a connection */ OBPROT_Connected(txp->app); break; case TCP_EVENT_DATA_IND: /* Pass data directly to the client parser */ OBPROT_ParseRx(txp->app, Parm1, Parm2); break; case TCP_EVENT_DISCON: txp->conn = INVALID_SOCKET; /* This can happen if TCPSTACK_ClientDisconnect() is called while * a connect is in progress. When disconnect is handled synchronously. */ if (txp->state == OCS_IDLE) break; txp->state = OCS_IDLE; txp->conn = INVALID_SOCKET; /* This call will deliver a disconnect indication to the app. */ OBPROT_Disconnected(txp->app, ODR_UNKNOWN); break; } OS_UnlockObex(); }