| /* |
| * Copyright (C) 2010 NXP Semiconductors |
| * |
| * 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. |
| */ |
| |
| /** |
| * \file phFriNfc_LlcpTransport.c |
| * \brief |
| * |
| * Project: NFC-FRI |
| * |
| */ |
| |
| /*include files*/ |
| #include <cutils/log.h> |
| #include <phOsalNfc.h> |
| #include <phLibNfcStatus.h> |
| #include <phLibNfc.h> |
| #include <phNfcLlcpTypes.h> |
| #include <phFriNfc_Llcp.h> |
| #include <phFriNfc_LlcpTransport.h> |
| #include <phFriNfc_LlcpTransport_Connectionless.h> |
| #include <phFriNfc_LlcpTransport_Connection.h> |
| |
| /* local macros */ |
| |
| /* Check if (a <= x < b) */ |
| #define IS_BETWEEN(x, a, b) (((x)>=(a)) && ((x)<(b))) |
| |
| static NFCSTATUS phFriNfc_LlcpTransport_RegisterName(phFriNfc_LlcpTransport_Socket_t* pLlcpSocket, |
| uint8_t nSap, |
| phNfc_sData_t *psServiceName); |
| |
| static NFCSTATUS phFriNfc_LlcpTransport_DiscoverServicesEx(phFriNfc_LlcpTransport_t *psTransport); |
| |
| static void phFriNfc_LlcpTransport_Send_CB(void *pContext, |
| NFCSTATUS status); |
| |
| static NFCSTATUS phFriNfc_LlcpTransport_GetFreeSap(phFriNfc_LlcpTransport_t * psTransport, phNfc_sData_t *psServiceName, uint8_t * pnSap) |
| { |
| uint8_t i; |
| uint8_t sap; |
| uint8_t min_sap_range, max_sap_range; |
| phFriNfc_LlcpTransport_Socket_t* pSocketTable = psTransport->pSocketTable; |
| |
| /* Calculate authorized SAP range */ |
| if ((psServiceName != NULL) && (psServiceName->length > 0)) |
| { |
| /* Make sure that we will return the same SAP if service name was already used in the past */ |
| for(i=0 ; i<PHFRINFC_LLCP_SDP_ADVERTISED_NB ; i++) |
| { |
| if((psTransport->pCachedServiceNames[i].sServiceName.length > 0) && |
| (memcmp(psTransport->pCachedServiceNames[i].sServiceName.buffer, psServiceName->buffer, psServiceName->length) == 0)) |
| { |
| /* Service name matched in cached service names list */ |
| *pnSap = psTransport->pCachedServiceNames[i].nSap; |
| return NFCSTATUS_SUCCESS; |
| } |
| } |
| |
| /* SDP advertised service */ |
| min_sap_range = PHFRINFC_LLCP_SAP_SDP_ADVERTISED_FIRST; |
| max_sap_range = PHFRINFC_LLCP_SAP_SDP_UNADVERTISED_FIRST; |
| } |
| else |
| { |
| /* Non-SDP advertised service */ |
| min_sap_range = PHFRINFC_LLCP_SAP_SDP_UNADVERTISED_FIRST; |
| max_sap_range = PHFRINFC_LLCP_SAP_NUMBER; |
| } |
| |
| /* Try all possible SAPs */ |
| for(sap=min_sap_range ; sap<max_sap_range ; sap++) |
| { |
| /* Go through socket list to check if current SAP is in use */ |
| for(i=0 ; i<PHFRINFC_LLCP_NB_SOCKET_MAX ; i++) |
| { |
| if((pSocketTable[i].eSocket_State >= phFriNfc_LlcpTransportSocket_eSocketBound) && |
| (pSocketTable[i].socket_sSap == sap)) |
| { |
| /* SAP is already in use */ |
| break; |
| } |
| } |
| |
| if (i >= PHFRINFC_LLCP_NB_SOCKET_MAX) |
| { |
| /* No socket is using current SAP, proceed with binding */ |
| *pnSap = sap; |
| return NFCSTATUS_SUCCESS; |
| } |
| } |
| |
| /* If we reach this point, it means that no SAP is free */ |
| return NFCSTATUS_INSUFFICIENT_RESOURCES; |
| } |
| |
| static NFCSTATUS phFriNfc_LlcpTransport_EncodeSdreqTlv(phNfc_sData_t *psTlvData, |
| uint32_t *pOffset, |
| uint8_t nTid, |
| phNfc_sData_t *psServiceName) |
| { |
| NFCSTATUS result; |
| uint32_t nTlvOffset = *pOffset; |
| uint32_t nTlvStartOffset = nTlvOffset; |
| |
| /* Encode the TID */ |
| result = phFriNfc_Llcp_EncodeTLV(psTlvData, |
| &nTlvOffset, |
| PHFRINFC_LLCP_TLV_TYPE_SDREQ, |
| 1, |
| &nTid); |
| if (result != NFCSTATUS_SUCCESS) |
| { |
| goto clean_and_return; |
| } |
| |
| /* Encode the service name itself */ |
| result = phFriNfc_Llcp_AppendTLV(psTlvData, |
| nTlvStartOffset, |
| &nTlvOffset, |
| psServiceName->length, |
| psServiceName->buffer); |
| if (result != NFCSTATUS_SUCCESS) |
| { |
| goto clean_and_return; |
| } |
| |
| clean_and_return: |
| /* Save offset if no error occured */ |
| if (result == NFCSTATUS_SUCCESS) |
| { |
| *pOffset = nTlvOffset; |
| } |
| |
| return result; |
| } |
| |
| static NFCSTATUS phFriNfc_LlcpTransport_EncodeSdresTlv(phNfc_sData_t *psTlvData, |
| uint32_t *pOffset, |
| uint8_t nTid, |
| uint8_t nSap) |
| { |
| NFCSTATUS result; |
| uint32_t nTlvStartOffset = *pOffset; |
| |
| /* Encode the TID */ |
| result = phFriNfc_Llcp_EncodeTLV(psTlvData, |
| pOffset, |
| PHFRINFC_LLCP_TLV_TYPE_SDRES, |
| 1, |
| &nTid); |
| if (result != NFCSTATUS_SUCCESS) |
| { |
| goto clean_and_return; |
| } |
| |
| /* Encode the service name itself */ |
| result = phFriNfc_Llcp_AppendTLV(psTlvData, |
| nTlvStartOffset, |
| pOffset, |
| 1, |
| &nSap); |
| if (result != NFCSTATUS_SUCCESS) |
| { |
| goto clean_and_return; |
| } |
| |
| clean_and_return: |
| /* Restore previous offset if an error occured */ |
| if (result != NFCSTATUS_SUCCESS) |
| { |
| *pOffset = nTlvStartOffset; |
| } |
| |
| return result; |
| } |
| |
| static phFriNfc_LlcpTransport_Socket_t* phFriNfc_LlcpTransport_ServiceNameLoockup(phFriNfc_LlcpTransport_t *psTransport, |
| phNfc_sData_t *pServiceName) |
| { |
| uint32_t index; |
| uint8_t cacheIndex; |
| phFriNfc_Llcp_CachedServiceName_t * pCachedServiceName; |
| phFriNfc_LlcpTransport_Socket_t * pSocket; |
| |
| /* Search a socket with the SN */ |
| for(index=0;index<PHFRINFC_LLCP_NB_SOCKET_MAX;index++) |
| { |
| pSocket = &psTransport->pSocketTable[index]; |
| /* Test if the CO socket is in Listen state or the CL socket is bound |
| and if its SN is the good one */ |
| if((((pSocket->eSocket_Type == phFriNfc_LlcpTransport_eConnectionOriented) |
| && (pSocket->eSocket_State == phFriNfc_LlcpTransportSocket_eSocketRegistered)) |
| || ((pSocket->eSocket_Type == phFriNfc_LlcpTransport_eConnectionLess) |
| && (pSocket->eSocket_State == phFriNfc_LlcpTransportSocket_eSocketBound))) |
| && |
| (pServiceName->length == pSocket->sServiceName.length) |
| && !memcmp(pServiceName->buffer, pSocket->sServiceName.buffer, pServiceName->length)) |
| { |
| /* Add new entry to cached service name/sap if not already in table */ |
| for(cacheIndex=0;cacheIndex<PHFRINFC_LLCP_SDP_ADVERTISED_NB;cacheIndex++) |
| { |
| pCachedServiceName = &psTransport->pCachedServiceNames[cacheIndex]; |
| if (pCachedServiceName->sServiceName.buffer != NULL) |
| { |
| if ((pCachedServiceName->sServiceName.length == pServiceName->length) && |
| (memcmp(pCachedServiceName->sServiceName.buffer, pServiceName->buffer, pServiceName->length) == 0)) |
| { |
| /* Already registered */ |
| break; |
| } |
| } |
| else |
| { |
| /* Reached end of existing entries and not found the service name, |
| * => Add the new entry |
| */ |
| pCachedServiceName->nSap = pSocket->socket_sSap; |
| pCachedServiceName->sServiceName.buffer = phOsalNfc_GetMemory(pServiceName->length); |
| if (pCachedServiceName->sServiceName.buffer == NULL) |
| { |
| /* Unable to cache this entry, so report this service as not found */ |
| return NULL; |
| } |
| memcpy(pCachedServiceName->sServiceName.buffer, pServiceName->buffer, pServiceName->length); |
| pCachedServiceName->sServiceName.length = pServiceName->length; |
| break; |
| } |
| } |
| |
| return pSocket; |
| } |
| } |
| |
| return NULL; |
| } |
| |
| |
| static NFCSTATUS phFriNfc_LlcpTransport_DiscoveryAnswer(phFriNfc_LlcpTransport_t *psTransport) |
| { |
| NFCSTATUS result = NFCSTATUS_PENDING; |
| phNfc_sData_t sInfoBuffer; |
| uint32_t nTlvOffset; |
| uint8_t index; |
| uint8_t nTid, nSap; |
| |
| /* Test if a send is pending */ |
| if(!testAndSetSendPending(psTransport)) |
| { |
| /* Set the header */ |
| psTransport->sLlcpHeader.dsap = PHFRINFC_LLCP_SAP_SDP; |
| psTransport->sLlcpHeader.ptype = PHFRINFC_LLCP_PTYPE_SNL; |
| psTransport->sLlcpHeader.ssap = PHFRINFC_LLCP_SAP_SDP; |
| |
| /* Prepare the info buffer */ |
| sInfoBuffer.buffer = psTransport->pDiscoveryBuffer; |
| sInfoBuffer.length = sizeof(psTransport->pDiscoveryBuffer); |
| |
| /* Encode as many requests as possible */ |
| nTlvOffset = 0; |
| for(index=0 ; index<psTransport->nDiscoveryResListSize ; index++) |
| { |
| /* Get current TID/SAP and try to encode them in SNL frame */ |
| nTid = psTransport->nDiscoveryResTidList[index]; |
| nSap = psTransport->nDiscoveryResSapList[index]; |
| /* Encode response */ |
| result = phFriNfc_LlcpTransport_EncodeSdresTlv(&sInfoBuffer, |
| &nTlvOffset, |
| nTid, |
| nSap); |
| if (result != NFCSTATUS_SUCCESS) |
| { |
| /* Impossible to fit the entire response */ |
| /* TODO: support reponse framgentation */ |
| break; |
| } |
| } |
| |
| /* Reset list size to be able to handle a new request */ |
| psTransport->nDiscoveryResListSize = 0; |
| |
| /* Update buffer length to match real TLV size */ |
| sInfoBuffer.length = nTlvOffset; |
| |
| /* Send SNL frame */ |
| result = phFriNfc_Llcp_Send(psTransport->pLlcp, |
| &psTransport->sLlcpHeader, |
| NULL, |
| &sInfoBuffer, |
| phFriNfc_LlcpTransport_Send_CB, |
| psTransport); |
| } |
| else |
| { |
| /* Impossible to send now, this function will be called again on next opportunity */ |
| } |
| |
| return result; |
| } |
| |
| |
| static void Handle_Discovery_IncomingFrame(phFriNfc_LlcpTransport_t *psTransport, |
| phNfc_sData_t *psData) |
| { |
| NFCSTATUS result; |
| phNfc_sData_t sValue; |
| phNfc_sData_t sResponseData; |
| phNfc_sData_t sServiceName; |
| uint32_t nInTlvOffset; |
| uint8_t nType; |
| uint8_t nTid; |
| uint8_t nSap; |
| pphFriNfc_Cr_t pfSavedCb; |
| void *pfSavedContext; |
| phFriNfc_LlcpTransport_Socket_t *pSocket; |
| |
| |
| /* Prepare buffer */ |
| sResponseData.buffer = psTransport->pDiscoveryBuffer; |
| sResponseData.length = sizeof(psTransport->pDiscoveryBuffer); |
| |
| /* Parse all TLVs in frame */ |
| nInTlvOffset = 0; |
| while(nInTlvOffset < psData->length) |
| { |
| result = phFriNfc_Llcp_DecodeTLV(psData, |
| &nInTlvOffset, |
| &nType, |
| &sValue ); |
| switch(nType) |
| { |
| case PHFRINFC_LLCP_TLV_TYPE_SDREQ: |
| if (sValue.length < 2) |
| { |
| /* Erroneous request, ignore */ |
| break; |
| } |
| /* Decode TID */ |
| nTid = sValue.buffer[0]; |
| /* Decode service name */ |
| sServiceName.buffer = sValue.buffer + 1; |
| sServiceName.length = sValue.length - 1; |
| |
| /* Handle SDP service name */ |
| if((sServiceName.length == sizeof(PHFRINFC_LLCP_SERVICENAME_SDP)-1) |
| && !memcmp(sServiceName.buffer, PHFRINFC_LLCP_SERVICENAME_SDP, sServiceName.length)) |
| { |
| nSap = PHFRINFC_LLCP_SAP_SDP; |
| } |
| else |
| { |
| /* Match service name in socket list */ |
| pSocket = phFriNfc_LlcpTransport_ServiceNameLoockup(psTransport, &sServiceName); |
| if (pSocket != NULL) |
| { |
| nSap = pSocket->socket_sSap; |
| } |
| else |
| { |
| nSap = 0; |
| } |
| } |
| |
| /* Encode response */ |
| if (psTransport->nDiscoveryResListSize < PHFRINFC_LLCP_SNL_RESPONSE_MAX) |
| { |
| psTransport->nDiscoveryResSapList[psTransport->nDiscoveryResListSize] = nSap; |
| psTransport->nDiscoveryResTidList[psTransport->nDiscoveryResListSize] = nTid; |
| psTransport->nDiscoveryResListSize++; |
| } |
| else |
| { |
| /* Remote peer is sending more than max. allowed requests (max. 256 |
| different TID values), drop invalid requests to avoid buffer overflow |
| */ |
| } |
| break; |
| |
| case PHFRINFC_LLCP_TLV_TYPE_SDRES: |
| if (psTransport->pfDiscover_Cb == NULL) |
| { |
| /* Ignore response when no requests are pending */ |
| break; |
| } |
| if (sValue.length != 2) |
| { |
| /* Erroneous response, ignore it */ |
| break; |
| } |
| /* Decode TID and SAP */ |
| nTid = sValue.buffer[0]; |
| if (nTid >= psTransport->nDiscoveryListSize) |
| { |
| /* Unkown TID, ignore it */ |
| break; |
| } |
| nSap = sValue.buffer[1]; |
| /* Save response */ |
| psTransport->pnDiscoverySapList[nTid] = nSap; |
| /* Update response counter */ |
| psTransport->nDiscoveryResOffset++; |
| break; |
| |
| default: |
| /* Ignored */ |
| break; |
| } |
| } |
| |
| /* If discovery requests have been received, send response */ |
| if (psTransport->nDiscoveryResListSize > 0) |
| { |
| phFriNfc_LlcpTransport_DiscoveryAnswer(psTransport); |
| } |
| |
| /* If all discovery responses have been received, trigger callback (if any) */ |
| if ((psTransport->pfDiscover_Cb != NULL) && |
| (psTransport->nDiscoveryResOffset >= psTransport->nDiscoveryListSize)) |
| { |
| pfSavedCb = psTransport->pfDiscover_Cb; |
| pfSavedContext = psTransport->pDiscoverContext; |
| |
| psTransport->pfDiscover_Cb = NULL; |
| psTransport->pDiscoverContext = NULL; |
| |
| pfSavedCb(pfSavedContext, NFCSTATUS_SUCCESS); |
| } |
| } |
| |
| |
| /* TODO: comment function Transport recv CB */ |
| static void phFriNfc_LlcpTransport__Recv_CB(void *pContext, |
| phNfc_sData_t *psData, |
| NFCSTATUS status) |
| { |
| phFriNfc_Llcp_sPacketHeader_t sLlcpLocalHeader; |
| uint8_t dsap; |
| uint8_t ptype; |
| uint8_t ssap; |
| |
| phFriNfc_LlcpTransport_t* pLlcpTransport = (phFriNfc_LlcpTransport_t*)pContext; |
| |
| if(status != NFCSTATUS_SUCCESS) |
| { |
| pLlcpTransport->LinkStatusError = TRUE; |
| } |
| else |
| { |
| phFriNfc_Llcp_Buffer2Header( psData->buffer,0x00, &sLlcpLocalHeader); |
| |
| dsap = (uint8_t)sLlcpLocalHeader.dsap; |
| ptype = (uint8_t)sLlcpLocalHeader.ptype; |
| ssap = (uint8_t)sLlcpLocalHeader.ssap; |
| |
| /* Update the length value (without the header length) */ |
| psData->length = psData->length - PHFRINFC_LLCP_PACKET_HEADER_SIZE; |
| |
| /* Update the buffer pointer */ |
| psData->buffer = psData->buffer + PHFRINFC_LLCP_PACKET_HEADER_SIZE; |
| |
| switch(ptype) |
| { |
| /* Connectionless */ |
| case PHFRINFC_LLCP_PTYPE_UI: |
| { |
| Handle_Connectionless_IncommingFrame(pLlcpTransport, |
| psData, |
| dsap, |
| ssap); |
| }break; |
| |
| /* Service Discovery Protocol */ |
| case PHFRINFC_LLCP_PTYPE_SNL: |
| { |
| if ((ssap == PHFRINFC_LLCP_SAP_SDP) && (dsap == PHFRINFC_LLCP_SAP_SDP)) |
| { |
| Handle_Discovery_IncomingFrame(pLlcpTransport, |
| psData); |
| } |
| else |
| { |
| /* Ignore frame if source and destination are not the SDP service */ |
| } |
| }break; |
| |
| /* Connection oriented */ |
| /* NOTE: forward reserved PTYPE to enable FRMR sending */ |
| case PHFRINFC_LLCP_PTYPE_CONNECT: |
| case PHFRINFC_LLCP_PTYPE_CC: |
| case PHFRINFC_LLCP_PTYPE_DISC: |
| case PHFRINFC_LLCP_PTYPE_DM: |
| case PHFRINFC_LLCP_PTYPE_I: |
| case PHFRINFC_LLCP_PTYPE_RR: |
| case PHFRINFC_LLCP_PTYPE_RNR: |
| case PHFRINFC_LLCP_PTYPE_FRMR: |
| case PHFRINFC_LLCP_PTYPE_RESERVED1: |
| case PHFRINFC_LLCP_PTYPE_RESERVED2: |
| case PHFRINFC_LLCP_PTYPE_RESERVED3: |
| { |
| Handle_ConnectionOriented_IncommingFrame(pLlcpTransport, |
| psData, |
| dsap, |
| ptype, |
| ssap); |
| }break; |
| default: |
| { |
| |
| }break; |
| } |
| |
| /*Restart the Receive Loop */ |
| status = phFriNfc_Llcp_Recv(pLlcpTransport->pLlcp, |
| phFriNfc_LlcpTransport__Recv_CB, |
| pLlcpTransport); |
| } |
| } |
| |
| bool_t testAndSetSendPending(phFriNfc_LlcpTransport_t* transport) { |
| bool_t currentValue; |
| pthread_mutex_lock(&transport->mutex); |
| currentValue = transport->bSendPending; |
| transport->bSendPending = TRUE; |
| pthread_mutex_unlock(&transport->mutex); |
| return currentValue; |
| } |
| |
| void clearSendPending(phFriNfc_LlcpTransport_t* transport) { |
| pthread_mutex_lock(&transport->mutex); |
| transport->bSendPending = FALSE; |
| pthread_mutex_unlock(&transport->mutex); |
| } |
| |
| /* TODO: comment function Transport recv CB */ |
| static void phFriNfc_LlcpTransport_Send_CB(void *pContext, |
| NFCSTATUS status) |
| { |
| phFriNfc_LlcpTransport_t *psTransport = (phFriNfc_LlcpTransport_t*)pContext; |
| NFCSTATUS result = NFCSTATUS_FAILED; |
| phNfc_sData_t sFrmrBuffer; |
| phFriNfc_Llcp_LinkSend_CB_t pfSavedCb; |
| void *pSavedContext; |
| phFriNfc_LlcpTransport_Socket_t *pCurrentSocket = NULL; |
| uint8_t index; |
| |
| // Store callbacks and socket index, so they can safely be |
| // overwritten by any code in the callback itself. |
| pfSavedCb = psTransport->pfLinkSendCb; |
| pSavedContext = psTransport->pLinkSendContext; |
| psTransport->pfLinkSendCb = NULL; |
| psTransport->pLinkSendContext = NULL; |
| index = psTransport->socketIndex; |
| |
| /* 1 - Reset the FLAG send pending*/ |
| clearSendPending(psTransport); |
| |
| /* 2 - Handle pending error responses */ |
| if(psTransport->bFrmrPending) |
| { |
| if (!testAndSetSendPending(psTransport)) { |
| /* Reset FRMR pending */ |
| psTransport->bFrmrPending = FALSE; |
| |
| /* Send Frmr */ |
| sFrmrBuffer.buffer = psTransport->FrmrInfoBuffer; |
| sFrmrBuffer.length = 0x04; /* Size of FRMR Information field */ |
| |
| result = phFriNfc_Llcp_Send(psTransport->pLlcp, |
| &psTransport->sLlcpHeader, |
| NULL, |
| &sFrmrBuffer, |
| phFriNfc_LlcpTransport_Send_CB, |
| psTransport); |
| } |
| } |
| else if(psTransport->bDmPending) |
| { |
| /* Reset DM pending */ |
| psTransport->bDmPending = FALSE; |
| |
| /* Send DM pending */ |
| result = phFriNfc_LlcpTransport_SendDisconnectMode(psTransport, |
| psTransport->DmInfoBuffer[0], |
| psTransport->DmInfoBuffer[1], |
| psTransport->DmInfoBuffer[2]); |
| } |
| |
| /* 3 - Call the original callback */ |
| if (pfSavedCb != NULL) |
| { |
| (*pfSavedCb)(pSavedContext, index, status); |
| } |
| |
| |
| /* 4 - Handle pending send operations */ |
| |
| /* Check for pending discovery requests/responses */ |
| if (psTransport->nDiscoveryResListSize > 0) |
| { |
| phFriNfc_LlcpTransport_DiscoveryAnswer(psTransport); |
| } |
| if ( (psTransport->pfDiscover_Cb != NULL) && |
| (psTransport->nDiscoveryReqOffset < psTransport->nDiscoveryListSize) ) |
| { |
| result = phFriNfc_LlcpTransport_DiscoverServicesEx(psTransport); |
| } |
| |
| /* Init index */ |
| index = psTransport->socketIndex; |
| |
| /* Check all sockets for pending operation */ |
| do |
| { |
| /* Modulo-increment index */ |
| index = (index + 1) % PHFRINFC_LLCP_NB_SOCKET_MAX; |
| |
| pCurrentSocket = &psTransport->pSocketTable[index]; |
| |
| /* Dispatch to the corresponding transport layer */ |
| if (pCurrentSocket->eSocket_Type == phFriNfc_LlcpTransport_eConnectionOriented) |
| { |
| result = phFriNfc_LlcpTransport_ConnectionOriented_HandlePendingOperations(pCurrentSocket); |
| } |
| else if (pCurrentSocket->eSocket_Type == phFriNfc_LlcpTransport_eConnectionLess) |
| { |
| result = phFriNfc_LlcpTransport_Connectionless_HandlePendingOperations(pCurrentSocket); |
| } |
| |
| if (result != NFCSTATUS_FAILED) |
| { |
| /* Stop looping if pending operation has been found */ |
| break; |
| } |
| |
| } while(index != psTransport->socketIndex); |
| } |
| |
| |
| /* TODO: comment function Transport reset */ |
| NFCSTATUS phFriNfc_LlcpTransport_Reset (phFriNfc_LlcpTransport_t *pLlcpTransport, |
| phFriNfc_Llcp_t *pLlcp) |
| { |
| NFCSTATUS status = NFCSTATUS_SUCCESS; |
| uint8_t i; |
| |
| /* Check for NULL pointers */ |
| if(pLlcpTransport == NULL || pLlcp == NULL) |
| { |
| status = PHNFCSTVAL(CID_FRI_NFC_LLCP_TRANSPORT, NFCSTATUS_INVALID_PARAMETER); |
| } |
| else |
| { |
| /* Reset Transport structure */ |
| pLlcpTransport->pLlcp = pLlcp; |
| pLlcpTransport->LinkStatusError = FALSE; |
| pLlcpTransport->bSendPending = FALSE; |
| pLlcpTransport->bRecvPending = FALSE; |
| pLlcpTransport->bDmPending = FALSE; |
| pLlcpTransport->bFrmrPending = FALSE; |
| pLlcpTransport->socketIndex = FALSE; |
| pLlcpTransport->LinkStatusError = 0; |
| pLlcpTransport->pfDiscover_Cb = NULL; |
| |
| /* Initialize cached service name/sap table */ |
| memset(pLlcpTransport->pCachedServiceNames, 0x00, sizeof(phFriNfc_Llcp_CachedServiceName_t)*PHFRINFC_LLCP_SDP_ADVERTISED_NB); |
| |
| /* Reset all the socket info in the table */ |
| for(i=0;i<PHFRINFC_LLCP_NB_SOCKET_MAX;i++) |
| { |
| pLlcpTransport->pSocketTable[i].eSocket_State = phFriNfc_LlcpTransportSocket_eSocketDefault; |
| pLlcpTransport->pSocketTable[i].eSocket_Type = phFriNfc_LlcpTransport_eDefaultType; |
| pLlcpTransport->pSocketTable[i].index = i; |
| pLlcpTransport->pSocketTable[i].pContext = NULL; |
| pLlcpTransport->pSocketTable[i].pListenContext = NULL; |
| pLlcpTransport->pSocketTable[i].pAcceptContext = NULL; |
| pLlcpTransport->pSocketTable[i].pRejectContext = NULL; |
| pLlcpTransport->pSocketTable[i].pConnectContext = NULL; |
| pLlcpTransport->pSocketTable[i].pDisconnectContext = NULL; |
| pLlcpTransport->pSocketTable[i].pSendContext = NULL; |
| pLlcpTransport->pSocketTable[i].pRecvContext = NULL; |
| pLlcpTransport->pSocketTable[i].pSocketErrCb = NULL; |
| pLlcpTransport->pSocketTable[i].bufferLinearLength = 0; |
| pLlcpTransport->pSocketTable[i].bufferSendMaxLength = 0; |
| pLlcpTransport->pSocketTable[i].bufferRwMaxLength = 0; |
| pLlcpTransport->pSocketTable[i].ReceiverBusyCondition = FALSE; |
| pLlcpTransport->pSocketTable[i].RemoteBusyConditionInfo = FALSE; |
| pLlcpTransport->pSocketTable[i].socket_sSap = PHFRINFC_LLCP_SAP_DEFAULT; |
| pLlcpTransport->pSocketTable[i].socket_dSap = PHFRINFC_LLCP_SAP_DEFAULT; |
| pLlcpTransport->pSocketTable[i].bSocketRecvPending = FALSE; |
| pLlcpTransport->pSocketTable[i].bSocketSendPending = FALSE; |
| pLlcpTransport->pSocketTable[i].bSocketListenPending = FALSE; |
| pLlcpTransport->pSocketTable[i].bSocketDiscPending = FALSE; |
| pLlcpTransport->pSocketTable[i].bSocketConnectPending = FALSE; |
| pLlcpTransport->pSocketTable[i].bSocketAcceptPending = FALSE; |
| pLlcpTransport->pSocketTable[i].bSocketRRPending = FALSE; |
| pLlcpTransport->pSocketTable[i].bSocketRNRPending = FALSE; |
| pLlcpTransport->pSocketTable[i].psTransport = pLlcpTransport; |
| pLlcpTransport->pSocketTable[i].pfSocketSend_Cb = NULL; |
| pLlcpTransport->pSocketTable[i].pfSocketRecv_Cb = NULL; |
| pLlcpTransport->pSocketTable[i].pfSocketRecvFrom_Cb = NULL; |
| pLlcpTransport->pSocketTable[i].pfSocketListen_Cb = NULL; |
| pLlcpTransport->pSocketTable[i].pfSocketConnect_Cb = NULL; |
| pLlcpTransport->pSocketTable[i].pfSocketDisconnect_Cb = NULL; |
| pLlcpTransport->pSocketTable[i].socket_VS = 0; |
| pLlcpTransport->pSocketTable[i].socket_VSA = 0; |
| pLlcpTransport->pSocketTable[i].socket_VR = 0; |
| pLlcpTransport->pSocketTable[i].socket_VRA = 0; |
| pLlcpTransport->pSocketTable[i].remoteRW = 0; |
| pLlcpTransport->pSocketTable[i].localRW = 0; |
| pLlcpTransport->pSocketTable[i].remoteMIU = 0; |
| pLlcpTransport->pSocketTable[i].localMIUX = 0; |
| pLlcpTransport->pSocketTable[i].index = 0; |
| pLlcpTransport->pSocketTable[i].indexRwRead = 0; |
| pLlcpTransport->pSocketTable[i].indexRwWrite = 0; |
| |
| memset(&pLlcpTransport->pSocketTable[i].sSocketOption, 0x00, sizeof(phFriNfc_LlcpTransport_sSocketOptions_t)); |
| |
| if (pLlcpTransport->pSocketTable[i].sServiceName.buffer != NULL) { |
| phOsalNfc_FreeMemory(pLlcpTransport->pSocketTable[i].sServiceName.buffer); |
| } |
| pLlcpTransport->pSocketTable[i].sServiceName.buffer = NULL; |
| pLlcpTransport->pSocketTable[i].sServiceName.length = 0; |
| } |
| |
| /* Start The Receive Loop */ |
| status = phFriNfc_Llcp_Recv(pLlcpTransport->pLlcp, |
| phFriNfc_LlcpTransport__Recv_CB, |
| pLlcpTransport); |
| } |
| return status; |
| } |
| |
| /* TODO: comment function Transport CloseAll */ |
| NFCSTATUS phFriNfc_LlcpTransport_CloseAll (phFriNfc_LlcpTransport_t *pLlcpTransport) |
| { |
| NFCSTATUS status = NFCSTATUS_SUCCESS; |
| phFriNfc_Llcp_CachedServiceName_t * pCachedServiceName; |
| uint8_t i; |
| |
| /* Check for NULL pointers */ |
| if(pLlcpTransport == NULL) |
| { |
| status = PHNFCSTVAL(CID_FRI_NFC_LLCP_TRANSPORT, NFCSTATUS_INVALID_PARAMETER); |
| } |
| |
| /* Close all sockets */ |
| for(i=0;i<PHFRINFC_LLCP_NB_SOCKET_MAX;i++) |
| { |
| if(pLlcpTransport->pSocketTable[i].eSocket_Type == phFriNfc_LlcpTransport_eConnectionOriented) |
| { |
| switch(pLlcpTransport->pSocketTable[i].eSocket_State) |
| { |
| case phFriNfc_LlcpTransportSocket_eSocketConnected: |
| case phFriNfc_LlcpTransportSocket_eSocketConnecting: |
| case phFriNfc_LlcpTransportSocket_eSocketAccepted: |
| case phFriNfc_LlcpTransportSocket_eSocketDisconnected: |
| case phFriNfc_LlcpTransportSocket_eSocketDisconnecting: |
| case phFriNfc_LlcpTransportSocket_eSocketRejected: |
| phFriNfc_LlcpTransport_Close(&pLlcpTransport->pSocketTable[i]); |
| break; |
| default: |
| /* Do nothing */ |
| break; |
| } |
| } |
| else |
| { |
| phFriNfc_LlcpTransport_Close(&pLlcpTransport->pSocketTable[i]); |
| } |
| } |
| |
| /* Reset cached service name/sap table */ |
| for(i=0;i<PHFRINFC_LLCP_SDP_ADVERTISED_NB;i++) |
| { |
| pCachedServiceName = &pLlcpTransport->pCachedServiceNames[i]; |
| |
| pCachedServiceName->nSap = 0; |
| if (pCachedServiceName->sServiceName.buffer != NULL) |
| { |
| phOsalNfc_FreeMemory(pCachedServiceName->sServiceName.buffer); |
| pCachedServiceName->sServiceName.buffer = NULL; |
| } |
| pCachedServiceName->sServiceName.length = 0; |
| } |
| |
| return status; |
| } |
| |
| |
| /* TODO: comment function Transport LinkSend */ |
| NFCSTATUS phFriNfc_LlcpTransport_LinkSend( phFriNfc_LlcpTransport_t *LlcpTransport, |
| phFriNfc_Llcp_sPacketHeader_t *psHeader, |
| phFriNfc_Llcp_sPacketSequence_t *psSequence, |
| phNfc_sData_t *psInfo, |
| phFriNfc_Llcp_LinkSend_CB_t pfSend_CB, |
| uint8_t socketIndex, |
| void *pContext ) |
| { |
| NFCSTATUS status; |
| /* Check if a send is already ongoing */ |
| if (LlcpTransport->pfLinkSendCb != NULL) |
| { |
| return NFCSTATUS_BUSY; |
| } |
| /* Save callback details */ |
| LlcpTransport->pfLinkSendCb = pfSend_CB; |
| LlcpTransport->pLinkSendContext = pContext; |
| LlcpTransport->socketIndex = socketIndex; |
| |
| /* Call the link-level send function */ |
| status = phFriNfc_Llcp_Send(LlcpTransport->pLlcp, psHeader, psSequence, psInfo, phFriNfc_LlcpTransport_Send_CB, (void*)LlcpTransport); |
| if (status != NFCSTATUS_PENDING && status != NFCSTATUS_SUCCESS) { |
| // Clear out callbacks |
| LlcpTransport->pfLinkSendCb = NULL; |
| LlcpTransport->pLinkSendContext = NULL; |
| } |
| return status; |
| } |
| |
| |
| /* TODO: comment function Transport SendFrameReject */ |
| NFCSTATUS phFriNfc_LlcpTransport_SendFrameReject(phFriNfc_LlcpTransport_t *psTransport, |
| uint8_t dsap, |
| uint8_t rejectedPTYPE, |
| uint8_t ssap, |
| phFriNfc_Llcp_sPacketSequence_t* sLlcpSequence, |
| uint8_t WFlag, |
| uint8_t IFlag, |
| uint8_t RFlag, |
| uint8_t SFlag, |
| uint8_t vs, |
| uint8_t vsa, |
| uint8_t vr, |
| uint8_t vra) |
| { |
| NFCSTATUS status = NFCSTATUS_SUCCESS; |
| phNfc_sData_t sFrmrBuffer; |
| uint8_t flagValue; |
| uint8_t sequence = 0; |
| uint8_t index; |
| uint8_t socketFound = FALSE; |
| |
| /* Search a socket waiting for a FRAME */ |
| for(index=0;index<PHFRINFC_LLCP_NB_SOCKET_MAX;index++) |
| { |
| /* Test if the socket is in connected state and if its SSAP and DSAP are valid */ |
| if(psTransport->pSocketTable[index].socket_sSap == dsap |
| && psTransport->pSocketTable[index].socket_dSap == ssap) |
| { |
| /* socket found */ |
| socketFound = TRUE; |
| break; |
| } |
| } |
| |
| /* Test if a socket has been found */ |
| if(socketFound) |
| { |
| /* Set socket state to disconnected */ |
| psTransport->pSocketTable[index].eSocket_State = phFriNfc_LlcpTransportSocket_eSocketDefault; |
| |
| /* Call ErrCB due to a FRMR*/ |
| psTransport->pSocketTable[index].pSocketErrCb( psTransport->pSocketTable[index].pContext,PHFRINFC_LLCP_ERR_FRAME_REJECTED); |
| |
| /* Close the socket */ |
| status = phFriNfc_LlcpTransport_ConnectionOriented_Close(&psTransport->pSocketTable[index]); |
| |
| /* Set FRMR Header */ |
| psTransport->sLlcpHeader.dsap = ssap; |
| psTransport->sLlcpHeader.ptype = PHFRINFC_LLCP_PTYPE_FRMR; |
| psTransport->sLlcpHeader.ssap = dsap; |
| |
| /* Set FRMR Information Field */ |
| flagValue = (WFlag<<7) | (IFlag<<6) | (RFlag<<5) | (SFlag<<4) | rejectedPTYPE; |
| if (sLlcpSequence != NULL) |
| { |
| sequence = (uint8_t)((sLlcpSequence->ns<<4)|(sLlcpSequence->nr)); |
| } |
| |
| psTransport->FrmrInfoBuffer[0] = flagValue; |
| psTransport->FrmrInfoBuffer[1] = sequence; |
| psTransport->FrmrInfoBuffer[2] = (vs<<4)|vr ; |
| psTransport->FrmrInfoBuffer[3] = (vsa<<4)|vra ; |
| |
| /* Test if a send is pending */ |
| if(testAndSetSendPending(psTransport)) |
| { |
| psTransport->bFrmrPending = TRUE; |
| status = NFCSTATUS_PENDING; |
| } |
| else |
| { |
| sFrmrBuffer.buffer = psTransport->FrmrInfoBuffer; |
| sFrmrBuffer.length = 0x04; /* Size of FRMR Information field */ |
| |
| /* Send FRMR frame */ |
| status = phFriNfc_Llcp_Send(psTransport->pLlcp, |
| &psTransport->sLlcpHeader, |
| NULL, |
| &sFrmrBuffer, |
| phFriNfc_LlcpTransport_Send_CB, |
| psTransport); |
| } |
| } |
| else |
| { |
| /* No active socket*/ |
| /* FRMR Frame not handled*/ |
| } |
| return status; |
| } |
| |
| |
| /* TODO: comment function Transport SendDisconnectMode (NOTE: used only |
| * for requests not bound to a socket, like "service not found") |
| */ |
| NFCSTATUS phFriNfc_LlcpTransport_SendDisconnectMode(phFriNfc_LlcpTransport_t* psTransport, |
| uint8_t dsap, |
| uint8_t ssap, |
| uint8_t dmOpCode) |
| { |
| NFCSTATUS status = NFCSTATUS_SUCCESS; |
| |
| /* Test if a send is pending */ |
| if(testAndSetSendPending(psTransport)) |
| { |
| /* DM pending */ |
| psTransport->bDmPending = TRUE; |
| |
| /* Store DM Info */ |
| psTransport->DmInfoBuffer[0] = dsap; |
| psTransport->DmInfoBuffer[1] = ssap; |
| psTransport->DmInfoBuffer[2] = dmOpCode; |
| |
| status = NFCSTATUS_PENDING; |
| } |
| else |
| { |
| /* Set the header */ |
| psTransport->sDmHeader.dsap = dsap; |
| psTransport->sDmHeader.ptype = PHFRINFC_LLCP_PTYPE_DM; |
| psTransport->sDmHeader.ssap = ssap; |
| |
| /* Save Operation Code to be provided in DM frame payload */ |
| psTransport->DmInfoBuffer[2] = dmOpCode; |
| psTransport->sDmPayload.buffer = &psTransport->DmInfoBuffer[2]; |
| psTransport->sDmPayload.length = PHFRINFC_LLCP_DM_LENGTH; |
| |
| /* Send DM frame */ |
| status = phFriNfc_Llcp_Send(psTransport->pLlcp, |
| &psTransport->sDmHeader, |
| NULL, |
| &psTransport->sDmPayload, |
| phFriNfc_LlcpTransport_Send_CB, |
| psTransport); |
| } |
| |
| return status; |
| } |
| |
| |
| /** |
| * \ingroup grp_lib_nfc |
| * \brief <b>Get the local options of a socket</b>. |
| * |
| * This function returns the local options (maximum packet size and receive window size) used |
| * for a given connection-oriented socket. This function shall not be used with connectionless |
| * sockets. |
| * |
| * \param[out] pLlcpSocket A pointer to a phFriNfc_LlcpTransport_Socket_t. |
| * \param[in] psLocalOptions A pointer to be filled with the local options of the socket. |
| * |
| * \retval NFCSTATUS_SUCCESS Operation successful. |
| * \retval NFCSTATUS_INVALID_PARAMETER One or more of the supplied parameters |
| * could not be properly interpreted. |
| * \retval NFCSTATUS_INVALID_STATE The socket is not in a valid state, or not of |
| * a valid type to perform the requsted operation. |
| * \retval NFCSTATUS_NOT_INITIALISED Indicates stack is not yet initialized. |
| * \retval NFCSTATUS_SHUTDOWN Shutdown in progress. |
| * \retval NFCSTATUS_FAILED Operation failed. |
| */ |
| NFCSTATUS phFriNfc_LlcpTransport_SocketGetLocalOptions(phFriNfc_LlcpTransport_Socket_t *pLlcpSocket, |
| phLibNfc_Llcp_sSocketOptions_t *psLocalOptions) |
| { |
| NFCSTATUS status = NFCSTATUS_SUCCESS; |
| |
| /* Check for NULL pointers */ |
| if (pLlcpSocket == NULL || psLocalOptions == NULL) |
| { |
| status = PHNFCSTVAL(CID_FRI_NFC_LLCP_TRANSPORT, NFCSTATUS_INVALID_PARAMETER); |
| } |
| /* Test the socket type */ |
| else if(pLlcpSocket->eSocket_Type != phFriNfc_LlcpTransport_eConnectionOriented) |
| { |
| status = PHNFCSTVAL(CID_FRI_NFC_LLCP_TRANSPORT, NFCSTATUS_INVALID_PARAMETER); |
| } |
| /* Test the socket state */ |
| else if(pLlcpSocket->eSocket_State == phFriNfc_LlcpTransportSocket_eSocketDefault) |
| { |
| status = PHNFCSTVAL(CID_FRI_NFC_LLCP_TRANSPORT, NFCSTATUS_INVALID_STATE); |
| } |
| else |
| { |
| status = phFriNfc_LlcpTransport_ConnectionOriented_SocketGetLocalOptions(pLlcpSocket, |
| psLocalOptions); |
| } |
| |
| return status; |
| } |
| |
| |
| /** |
| * \ingroup grp_lib_nfc |
| * \brief <b>Get the local options of a socket</b>. |
| * |
| * This function returns the remote options (maximum packet size and receive window size) used |
| * for a given connection-oriented socket. This function shall not be used with connectionless |
| * sockets. |
| * |
| * \param[out] pLlcpSocket A pointer to a phFriNfc_LlcpTransport_Socket_t. |
| * \param[in] psRemoteOptions A pointer to be filled with the remote options of the socket. |
| * |
| * \retval NFCSTATUS_SUCCESS Operation successful. |
| * \retval NFCSTATUS_INVALID_PARAMETER One or more of the supplied parameters |
| * could not be properly interpreted. |
| * \retval NFCSTATUS_INVALID_STATE The socket is not in a valid state, or not of |
| * a valid type to perform the requsted operation. |
| * \retval NFCSTATUS_NOT_INITIALISED Indicates stack is not yet initialized. |
| * \retval NFCSTATUS_SHUTDOWN Shutdown in progress. |
| * \retval NFCSTATUS_FAILED Operation failed. |
| */ |
| NFCSTATUS phFriNfc_LlcpTransport_SocketGetRemoteOptions(phFriNfc_LlcpTransport_Socket_t* pLlcpSocket, |
| phLibNfc_Llcp_sSocketOptions_t* psRemoteOptions) |
| { |
| NFCSTATUS status = NFCSTATUS_SUCCESS; |
| |
| /* Check for NULL pointers */ |
| if (pLlcpSocket == NULL || psRemoteOptions == NULL) |
| { |
| status = PHNFCSTVAL(CID_FRI_NFC_LLCP_TRANSPORT, NFCSTATUS_INVALID_PARAMETER); |
| } |
| /* Test the socket type */ |
| else if(pLlcpSocket->eSocket_Type != phFriNfc_LlcpTransport_eConnectionOriented) |
| { |
| status = PHNFCSTVAL(CID_FRI_NFC_LLCP_TRANSPORT, NFCSTATUS_INVALID_PARAMETER); |
| } |
| /* Test the socket state */ |
| else if(pLlcpSocket->eSocket_State != phFriNfc_LlcpTransportSocket_eSocketConnected) |
| { |
| status = PHNFCSTVAL(CID_FRI_NFC_LLCP_TRANSPORT, NFCSTATUS_INVALID_STATE); |
| } |
| else |
| { |
| status = phFriNfc_LlcpTransport_ConnectionOriented_SocketGetRemoteOptions(pLlcpSocket, |
| psRemoteOptions); |
| } |
| |
| return status; |
| } |
| |
| |
| static NFCSTATUS phFriNfc_LlcpTransport_DiscoverServicesEx(phFriNfc_LlcpTransport_t *psTransport) |
| { |
| NFCSTATUS result = NFCSTATUS_PENDING; |
| phNfc_sData_t sInfoBuffer; |
| phNfc_sData_t *psServiceName; |
| uint32_t nTlvOffset; |
| |
| /* Test if a send is pending */ |
| if(!testAndSetSendPending(psTransport)) |
| { |
| /* Set the header */ |
| psTransport->sLlcpHeader.dsap = PHFRINFC_LLCP_SAP_SDP; |
| psTransport->sLlcpHeader.ptype = PHFRINFC_LLCP_PTYPE_SNL; |
| psTransport->sLlcpHeader.ssap = PHFRINFC_LLCP_SAP_SDP; |
| |
| /* Prepare the info buffer */ |
| sInfoBuffer.buffer = psTransport->pDiscoveryBuffer; |
| sInfoBuffer.length = sizeof(psTransport->pDiscoveryBuffer); |
| |
| /* Encode as many requests as possible */ |
| nTlvOffset = 0; |
| while(psTransport->nDiscoveryReqOffset < psTransport->nDiscoveryListSize) |
| { |
| /* Get current service name and try to encode it in SNL frame */ |
| psServiceName = &psTransport->psDiscoveryServiceNameList[psTransport->nDiscoveryReqOffset]; |
| result = phFriNfc_LlcpTransport_EncodeSdreqTlv(&sInfoBuffer, |
| &nTlvOffset, |
| psTransport->nDiscoveryReqOffset, |
| psServiceName); |
| if (result != NFCSTATUS_SUCCESS) |
| { |
| /* Impossible to fit more requests in a single frame, |
| * will be continued on next opportunity |
| */ |
| break; |
| } |
| |
| /* Update request counter */ |
| psTransport->nDiscoveryReqOffset++; |
| } |
| |
| /* Update buffer length to match real TLV size */ |
| sInfoBuffer.length = nTlvOffset; |
| |
| /* Send SNL frame */ |
| result = phFriNfc_Llcp_Send(psTransport->pLlcp, |
| &psTransport->sLlcpHeader, |
| NULL, |
| &sInfoBuffer, |
| phFriNfc_LlcpTransport_Send_CB, |
| psTransport); |
| } |
| else |
| { |
| /* Impossible to send now, this function will be called again on next opportunity */ |
| } |
| |
| return result; |
| } |
| |
| /*! |
| * \ingroup grp_fri_nfc |
| * \brief <b>Discover remote services SAP using SDP protocol</b>. |
| */ |
| NFCSTATUS phFriNfc_LlcpTransport_DiscoverServices( phFriNfc_LlcpTransport_t *pLlcpTransport, |
| phNfc_sData_t *psServiceNameList, |
| uint8_t *pnSapList, |
| uint8_t nListSize, |
| pphFriNfc_Cr_t pDiscover_Cb, |
| void *pContext ) |
| { |
| NFCSTATUS result = NFCSTATUS_FAILED; |
| |
| /* Save request details */ |
| pLlcpTransport->psDiscoveryServiceNameList = psServiceNameList; |
| pLlcpTransport->pnDiscoverySapList = pnSapList; |
| pLlcpTransport->nDiscoveryListSize = nListSize; |
| pLlcpTransport->pfDiscover_Cb = pDiscover_Cb; |
| pLlcpTransport->pDiscoverContext = pContext; |
| |
| /* Reset internal counters */ |
| pLlcpTransport->nDiscoveryReqOffset = 0; |
| pLlcpTransport->nDiscoveryResOffset = 0; |
| |
| /* Perform request */ |
| result = phFriNfc_LlcpTransport_DiscoverServicesEx(pLlcpTransport); |
| |
| return result; |
| } |
| |
| |
| /** |
| * \ingroup grp_fri_nfc |
| * \brief <b>Create a socket on a LLCP-connected device</b>. |
| * |
| * This function creates a socket for a given LLCP link. Sockets can be of two types : |
| * connection-oriented and connectionless. If the socket is connection-oriented, the caller |
| * must provide a working buffer to the socket in order to handle incoming data. This buffer |
| * must be large enough to fit the receive window (RW * MIU), the remaining space being |
| * used as a linear buffer to store incoming data as a stream. Data will be readable later |
| * using the phLibNfc_LlcpTransport_Recv function. |
| * The options and working buffer are not required if the socket is used as a listening socket, |
| * since it cannot be directly used for communication. |
| * |
| * \param[in] pLlcpSocketTable A pointer to a table of PHFRINFC_LLCP_NB_SOCKET_DEFAULT sockets. |
| * \param[in] eType The socket type. |
| * \param[in] psOptions The options to be used with the socket. |
| * \param[in] psWorkingBuffer A working buffer to be used by the library. |
| * \param[out] pLlcpSocket A pointer on the socket to be filled with a |
| socket found on the socket table. |
| * \param[in] pErr_Cb The callback to be called each time the socket |
| * is in error. |
| * \param[in] pContext Upper layer context to be returned in the callback. |
| * |
| * \retval NFCSTATUS_SUCCESS Operation successful. |
| * \retval NFCSTATUS_INVALID_PARAMETER One or more of the supplied parameters |
| * could not be properly interpreted. |
| * \retval NFCSTATUS_BUFFER_TOO_SMALL The working buffer is too small for the MIU and RW |
| * declared in the options. |
| * \retval NFCSTATUS_INSUFFICIENT_RESOURCES No more socket handle available. |
| * \retval NFCSTATUS_FAILED Operation failed. |
| * */ |
| NFCSTATUS phFriNfc_LlcpTransport_Socket(phFriNfc_LlcpTransport_t *pLlcpTransport, |
| phFriNfc_LlcpTransport_eSocketType_t eType, |
| phFriNfc_LlcpTransport_sSocketOptions_t *psOptions, |
| phNfc_sData_t *psWorkingBuffer, |
| phFriNfc_LlcpTransport_Socket_t **pLlcpSocket, |
| pphFriNfc_LlcpTransportSocketErrCb_t pErr_Cb, |
| void *pContext) |
| { |
| NFCSTATUS status = NFCSTATUS_SUCCESS; |
| phFriNfc_Llcp_sLinkParameters_t LlcpLinkParamInfo; |
| uint8_t index=0; |
| uint8_t cpt; |
| |
| /* Check for NULL pointers */ |
| if ( ((psOptions == NULL) && (eType == phFriNfc_LlcpTransport_eConnectionOriented)) |
| || ((psWorkingBuffer == NULL) && (eType == phFriNfc_LlcpTransport_eConnectionOriented)) |
| || (pLlcpSocket == NULL) |
| || (pErr_Cb == NULL) |
| || (pContext == NULL) |
| || (pLlcpTransport == NULL)) |
| { |
| status = PHNFCSTVAL(CID_FRI_NFC_LLCP_TRANSPORT, NFCSTATUS_INVALID_PARAMETER); |
| return status; |
| } |
| /* Test the socket type*/ |
| else if(eType != phFriNfc_LlcpTransport_eConnectionOriented && eType != phFriNfc_LlcpTransport_eConnectionLess) |
| { |
| status = PHNFCSTVAL(CID_FRI_NFC_LLCP_TRANSPORT, NFCSTATUS_INVALID_PARAMETER); |
| return status; |
| } |
| /* Connectionless sockets don't support options */ |
| else if ((psOptions != NULL) && (eType == phFriNfc_LlcpTransport_eConnectionLess)) |
| { |
| status = PHNFCSTVAL(CID_FRI_NFC_LLCP_TRANSPORT, NFCSTATUS_INVALID_PARAMETER); |
| return status; |
| } |
| |
| /* Get the local parameters of the LLCP Link */ |
| status = phFriNfc_Llcp_GetLocalInfo(pLlcpTransport->pLlcp,&LlcpLinkParamInfo); |
| if(status != NFCSTATUS_SUCCESS) |
| { |
| status = PHNFCSTVAL(CID_FRI_NFC_LLCP_TRANSPORT, NFCSTATUS_FAILED); |
| return status; |
| } |
| else |
| { |
| /* Search a socket free in the Socket Table*/ |
| do |
| { |
| if(pLlcpTransport->pSocketTable[index].eSocket_State == phFriNfc_LlcpTransportSocket_eSocketDefault) |
| { |
| /* Set the socket pointer to socket of the table */ |
| *pLlcpSocket = &pLlcpTransport->pSocketTable[index]; |
| |
| /* Store the socket info in the socket pointer */ |
| pLlcpTransport->pSocketTable[index].eSocket_Type = eType; |
| pLlcpTransport->pSocketTable[index].pSocketErrCb = pErr_Cb; |
| |
| /* Store the context of the upper layer */ |
| pLlcpTransport->pSocketTable[index].pContext = pContext; |
| |
| /* Set the pointers to the different working buffers */ |
| if (eType == phFriNfc_LlcpTransport_eConnectionOriented) |
| { |
| /* Test the socket options */ |
| if (psOptions->rw > PHFRINFC_LLCP_RW_MAX) |
| { |
| status = PHNFCSTVAL(CID_FRI_NFC_LLCP_TRANSPORT, NFCSTATUS_INVALID_PARAMETER); |
| return status; |
| } |
| |
| /* Set socket options */ |
| memcpy(&pLlcpTransport->pSocketTable[index].sSocketOption, psOptions, sizeof(phFriNfc_LlcpTransport_sSocketOptions_t)); |
| |
| /* Set socket local params (MIUX & RW) */ |
| pLlcpTransport->pSocketTable[index].localMIUX = (pLlcpTransport->pSocketTable[index].sSocketOption.miu - PHFRINFC_LLCP_MIU_DEFAULT) & PHFRINFC_LLCP_TLV_MIUX_MASK; |
| pLlcpTransport->pSocketTable[index].localRW = pLlcpTransport->pSocketTable[index].sSocketOption.rw & PHFRINFC_LLCP_TLV_RW_MASK; |
| |
| /* Set the Max length for the Send and Receive Window Buffer */ |
| pLlcpTransport->pSocketTable[index].bufferSendMaxLength = pLlcpTransport->pSocketTable[index].sSocketOption.miu; |
| pLlcpTransport->pSocketTable[index].bufferRwMaxLength = pLlcpTransport->pSocketTable[index].sSocketOption.miu * ((pLlcpTransport->pSocketTable[index].sSocketOption.rw & PHFRINFC_LLCP_TLV_RW_MASK)); |
| pLlcpTransport->pSocketTable[index].bufferLinearLength = psWorkingBuffer->length - pLlcpTransport->pSocketTable[index].bufferSendMaxLength - pLlcpTransport->pSocketTable[index].bufferRwMaxLength; |
| |
| /* Test the connection oriented buffers length */ |
| if((pLlcpTransport->pSocketTable[index].bufferSendMaxLength + pLlcpTransport->pSocketTable[index].bufferRwMaxLength) > psWorkingBuffer->length |
| || ((pLlcpTransport->pSocketTable[index].bufferLinearLength < PHFRINFC_LLCP_MIU_DEFAULT) && (pLlcpTransport->pSocketTable[index].bufferLinearLength != 0))) |
| { |
| status = PHNFCSTVAL(CID_FRI_NFC_LLCP_TRANSPORT, NFCSTATUS_BUFFER_TOO_SMALL); |
| return status; |
| } |
| |
| /* Set the pointer and the length for the Receive Window Buffer */ |
| for(cpt=0;cpt<pLlcpTransport->pSocketTable[index].localRW;cpt++) |
| { |
| pLlcpTransport->pSocketTable[index].sSocketRwBufferTable[cpt].buffer = psWorkingBuffer->buffer + (cpt*pLlcpTransport->pSocketTable[index].sSocketOption.miu); |
| pLlcpTransport->pSocketTable[index].sSocketRwBufferTable[cpt].length = 0; |
| } |
| |
| /* Set the pointer and the length for the Send Buffer */ |
| pLlcpTransport->pSocketTable[index].sSocketSendBuffer.buffer = psWorkingBuffer->buffer + pLlcpTransport->pSocketTable[index].bufferRwMaxLength; |
| pLlcpTransport->pSocketTable[index].sSocketSendBuffer.length = pLlcpTransport->pSocketTable[index].bufferSendMaxLength; |
| |
| /** Set the pointer and the length for the Linear Buffer */ |
| pLlcpTransport->pSocketTable[index].sSocketLinearBuffer.buffer = psWorkingBuffer->buffer + pLlcpTransport->pSocketTable[index].bufferRwMaxLength + pLlcpTransport->pSocketTable[index].bufferSendMaxLength; |
| pLlcpTransport->pSocketTable[index].sSocketLinearBuffer.length = pLlcpTransport->pSocketTable[index].bufferLinearLength; |
| |
| if(pLlcpTransport->pSocketTable[index].sSocketLinearBuffer.length != 0) |
| { |
| /* Init Cyclic Fifo */ |
| phFriNfc_Llcp_CyclicFifoInit(&pLlcpTransport->pSocketTable[index].sCyclicFifoBuffer, |
| pLlcpTransport->pSocketTable[index].sSocketLinearBuffer.buffer, |
| pLlcpTransport->pSocketTable[index].sSocketLinearBuffer.length); |
| } |
| } |
| /* Handle connectionless socket with buffering option */ |
| else if (eType == phFriNfc_LlcpTransport_eConnectionLess) |
| { |
| /* Determine how many packets can be bufferized in working buffer */ |
| if (psWorkingBuffer != NULL) |
| { |
| /* NOTE: the extra byte is used to store SSAP */ |
| pLlcpTransport->pSocketTable[index].localRW = psWorkingBuffer->length / (pLlcpTransport->pLlcp->sLocalParams.miu + 1); |
| } |
| else |
| { |
| pLlcpTransport->pSocketTable[index].localRW = 0; |
| } |
| |
| if (pLlcpTransport->pSocketTable[index].localRW > PHFRINFC_LLCP_RW_MAX) |
| { |
| pLlcpTransport->pSocketTable[index].localRW = PHFRINFC_LLCP_RW_MAX; |
| } |
| |
| /* Set the pointers and the lengths for buffering */ |
| for(cpt=0 ; cpt<pLlcpTransport->pSocketTable[index].localRW ; cpt++) |
| { |
| pLlcpTransport->pSocketTable[index].sSocketRwBufferTable[cpt].buffer = psWorkingBuffer->buffer + (cpt*(pLlcpTransport->pLlcp->sLocalParams.miu + 1)); |
| pLlcpTransport->pSocketTable[index].sSocketRwBufferTable[cpt].length = 0; |
| } |
| |
| /* Set other socket internals */ |
| pLlcpTransport->pSocketTable[index].indexRwRead = 0; |
| pLlcpTransport->pSocketTable[index].indexRwWrite = 0; |
| } |
| |
| /* Store index of the socket */ |
| pLlcpTransport->pSocketTable[index].index = index; |
| |
| /* Set the socket into created state */ |
| pLlcpTransport->pSocketTable[index].eSocket_State = phFriNfc_LlcpTransportSocket_eSocketCreated; |
| return status; |
| } |
| else |
| { |
| index++; |
| } |
| }while(index<PHFRINFC_LLCP_NB_SOCKET_MAX); |
| |
| status = PHNFCSTVAL(CID_FRI_NFC_LLCP_TRANSPORT, NFCSTATUS_INSUFFICIENT_RESOURCES); |
| } |
| return status; |
| } |
| |
| /** |
| * \ingroup grp_fri_nfc |
| * \brief <b>Close a socket on a LLCP-connected device</b>. |
| * |
| * This function closes a LLCP socket previously created using phFriNfc_LlcpTransport_Socket. |
| * If the socket was connected, it is first disconnected, and then closed. |
| * |
| * \param[in] pLlcpSocket A pointer to a phFriNfc_LlcpTransport_Socket_t. |
| |
| * \retval NFCSTATUS_SUCCESS Operation successful. |
| * \retval NFCSTATUS_INVALID_PARAMETER One or more of the supplied parameters |
| * could not be properly interpreted. |
| * \retval NFCSTATUS_FAILED Operation failed. |
| */ |
| NFCSTATUS phFriNfc_LlcpTransport_Close(phFriNfc_LlcpTransport_Socket_t* pLlcpSocket) |
| { |
| NFCSTATUS status = NFCSTATUS_SUCCESS; |
| |
| /* Check for NULL pointers */ |
| if( pLlcpSocket == NULL) |
| { |
| status = PHNFCSTVAL(CID_FRI_NFC_LLCP_TRANSPORT, NFCSTATUS_INVALID_PARAMETER); |
| } |
| else if(pLlcpSocket->eSocket_Type == phFriNfc_LlcpTransport_eConnectionOriented) |
| { |
| status = phFriNfc_LlcpTransport_ConnectionOriented_Close(pLlcpSocket); |
| } |
| else if(pLlcpSocket->eSocket_Type == phFriNfc_LlcpTransport_eConnectionLess) |
| { |
| status = phFriNfc_LlcpTransport_Connectionless_Close(pLlcpSocket); |
| } |
| else |
| { |
| status = PHNFCSTVAL(CID_FRI_NFC_LLCP_TRANSPORT, NFCSTATUS_INVALID_PARAMETER); |
| } |
| |
| return status; |
| } |
| |
| /** |
| * \ingroup grp_fri_nfc |
| * \brief <b>Bind a socket to a local SAP</b>. |
| * |
| * This function binds the socket to a local Service Access Point. |
| * |
| * \param[in] pLlcpSocket A pointer to a phFriNfc_LlcpTransport_Socket_t. |
| * \param[in] nSap The SAP number to bind with, or 0 for auto-bind to a free SAP. |
| * \param[in] psServiceName A pointer to Service Name, or NULL if no service name. |
| * |
| * \retval NFCSTATUS_SUCCESS Operation successful. |
| * \retval NFCSTATUS_INVALID_PARAMETER One or more of the supplied parameters |
| * could not be properly interpreted. |
| * \retval NFCSTATUS_INVALID_STATE The socket is not in a valid state, or not of |
| * a valid type to perform the requsted operation. |
| * \retval NFCSTATUS_ALREADY_REGISTERED The selected SAP is already bound to another |
| socket. |
| * \retval NFCSTATUS_FAILED Operation failed. |
| */ |
| |
| NFCSTATUS phFriNfc_LlcpTransport_Bind(phFriNfc_LlcpTransport_Socket_t *pLlcpSocket, |
| uint8_t nSap, |
| phNfc_sData_t *psServiceName) |
| { |
| NFCSTATUS status = NFCSTATUS_SUCCESS; |
| uint8_t i; |
| uint8_t min_sap_range; |
| uint8_t max_sap_range; |
| |
| /* Check for NULL pointers */ |
| if(pLlcpSocket == NULL) |
| { |
| status = PHNFCSTVAL(CID_FRI_NFC_LLCP_TRANSPORT, NFCSTATUS_INVALID_PARAMETER); |
| } |
| else if(pLlcpSocket->eSocket_State != phFriNfc_LlcpTransportSocket_eSocketCreated) |
| { |
| status = PHNFCSTVAL(CID_FRI_NFC_LLCP_TRANSPORT, NFCSTATUS_INVALID_STATE); |
| } |
| else |
| { |
| /* Calculate authorized SAP range */ |
| if ((psServiceName != NULL) && (psServiceName->length > 0)) |
| { |
| /* SDP advertised service */ |
| min_sap_range = PHFRINFC_LLCP_SAP_SDP_ADVERTISED_FIRST; |
| max_sap_range = PHFRINFC_LLCP_SAP_SDP_UNADVERTISED_FIRST; |
| } |
| else |
| { |
| /* Non-SDP advertised service */ |
| min_sap_range = PHFRINFC_LLCP_SAP_SDP_UNADVERTISED_FIRST; |
| max_sap_range = PHFRINFC_LLCP_SAP_NUMBER; |
| } |
| |
| /* Handle dynamic SAP allocation */ |
| if (nSap == 0) |
| { |
| status = phFriNfc_LlcpTransport_GetFreeSap(pLlcpSocket->psTransport, psServiceName, &nSap); |
| if (status != NFCSTATUS_SUCCESS) |
| { |
| return status; |
| } |
| } |
| |
| /* Test the SAP range */ |
| if(!IS_BETWEEN(nSap, min_sap_range, max_sap_range) && |
| !IS_BETWEEN(nSap, PHFRINFC_LLCP_SAP_WKS_FIRST, PHFRINFC_LLCP_SAP_SDP_ADVERTISED_FIRST)) |
| { |
| status = PHNFCSTVAL(CID_FRI_NFC_LLCP_TRANSPORT, NFCSTATUS_INVALID_PARAMETER); |
| } |
| else |
| { |
| /* Test if the nSap it is used by another socket */ |
| for(i=0;i<PHFRINFC_LLCP_NB_SOCKET_MAX;i++) |
| { |
| if(pLlcpSocket->psTransport->pSocketTable[i].socket_sSap == nSap) |
| { |
| return status = PHNFCSTVAL(CID_FRI_NFC_LLCP_TRANSPORT, NFCSTATUS_ALREADY_REGISTERED); |
| } |
| } |
| /* Set service name */ |
| status = phFriNfc_LlcpTransport_RegisterName(pLlcpSocket, nSap, psServiceName); |
| if (status != NFCSTATUS_SUCCESS) |
| { |
| return status; |
| } |
| /* Set the nSap value of the socket */ |
| pLlcpSocket->socket_sSap = nSap; |
| /* Set the socket state */ |
| pLlcpSocket->eSocket_State = phFriNfc_LlcpTransportSocket_eSocketBound; |
| } |
| } |
| return status; |
| } |
| |
| /*********************************************/ |
| /* ConnectionOriented */ |
| /*********************************************/ |
| |
| /** |
| * \ingroup grp_fri_nfc |
| * \brief <b>Listen for incoming connection requests on a socket</b>. |
| * |
| * This function switches a socket into a listening state and registers a callback on |
| * incoming connection requests. In this state, the socket is not able to communicate |
| * directly. The listening state is only available for connection-oriented sockets |
| * which are still not connected. The socket keeps listening until it is closed, and |
| * thus can trigger several times the pListen_Cb callback. |
| * |
| * |
| * \param[in] pLlcpSocket A pointer to a phFriNfc_LlcpTransport_Socket_t. |
| * \param[in] pListen_Cb The callback to be called each time the |
| * socket receive a connection request. |
| * \param[in] pContext Upper layer context to be returned in |
| * the callback. |
| * |
| * \retval NFCSTATUS_SUCCESS Operation successful. |
| * \retval NFCSTATUS_INVALID_PARAMETER One or more of the supplied parameters |
| * could not be properly interpreted. |
| * \retval NFCSTATUS_INVALID_STATE The socket is not in a valid state to switch |
| * to listening state. |
| * \retval NFCSTATUS_FAILED Operation failed. |
| */ |
| NFCSTATUS phFriNfc_LlcpTransport_Listen(phFriNfc_LlcpTransport_Socket_t* pLlcpSocket, |
| pphFriNfc_LlcpTransportSocketListenCb_t pListen_Cb, |
| void* pContext) |
| { |
| NFCSTATUS status = NFCSTATUS_SUCCESS; |
| |
| /* Check for NULL pointers */ |
| if(pLlcpSocket == NULL || pListen_Cb == NULL|| pContext == NULL ) |
| { |
| status = PHNFCSTVAL(CID_FRI_NFC_LLCP_TRANSPORT, NFCSTATUS_INVALID_PARAMETER); |
| } |
| /* Check for socket state */ |
| else if(pLlcpSocket->eSocket_State != phFriNfc_LlcpTransportSocket_eSocketBound) |
| { |
| status = PHNFCSTVAL(CID_FRI_NFC_LLCP_TRANSPORT, NFCSTATUS_INVALID_STATE); |
| } |
| /* Check for socket type */ |
| else if(pLlcpSocket->eSocket_Type != phFriNfc_LlcpTransport_eConnectionOriented) |
| { |
| status = PHNFCSTVAL(CID_FRI_NFC_LLCP_TRANSPORT, NFCSTATUS_INVALID_PARAMETER); |
| } |
| /* Test if a listen is not pending with this socket */ |
| else if(pLlcpSocket->bSocketListenPending) |
| { |
| status = PHNFCSTVAL(CID_FRI_NFC_LLCP_TRANSPORT, NFCSTATUS_INVALID_PARAMETER); |
| } |
| else |
| { |
| status = phFriNfc_LlcpTransport_ConnectionOriented_Listen(pLlcpSocket, |
| pListen_Cb, |
| pContext); |
| } |
| return status; |
| } |
| |
| |
| /** |
| * \ingroup grp_fri_nfc |
| * \brief <b>Register the socket service name</b>. |
| * |
| * This function changes the service name of the corresponding socket. |
| * |
| * \param[in] pLlcpSocket A pointer to a phFriNfc_LlcpTransport_Socket_t. |
| * \param[in] nSap SAP number associated to the service name. |
| * \param[in] psServiceName A pointer to a Service Name. |
| * |
| * \retval NFCSTATUS_SUCCESS Operation successful. |
| * \retval NFCSTATUS_INVALID_PARAMETER One or more of the supplied parameters |
| * could not be properly interpreted. |
| * \retval NFCSTATUS_FAILED Operation failed. |
| */ |
| static NFCSTATUS phFriNfc_LlcpTransport_RegisterName(phFriNfc_LlcpTransport_Socket_t* pLlcpSocket, |
| uint8_t nSap, |
| phNfc_sData_t *psServiceName) |
| { |
| phFriNfc_LlcpTransport_t * psTransport = pLlcpSocket->psTransport; |
| uint8_t index; |
| uint8_t bSnMatch, bSapMatch; |
| |
| /* Check in cache if sap has been used for different service name */ |
| for(index=0 ; index<PHFRINFC_LLCP_SDP_ADVERTISED_NB ; index++) |
| { |
| if(psTransport->pCachedServiceNames[index].sServiceName.length == 0) |
| { |
| /* Reached end of table */ |
| break; |
| } |
| |
| bSnMatch = (memcmp(psTransport->pCachedServiceNames[index].sServiceName.buffer, psServiceName->buffer, psServiceName->length) == 0); |
| bSapMatch = psTransport->pCachedServiceNames[index].nSap == nSap; |
| if(bSnMatch && bSapMatch) |
| { |
| /* Request match cache */ |
| break; |
| } |
| else if((bSnMatch && !bSapMatch) || (!bSnMatch && bSapMatch)) |
| { |
| /* Request mismatch with cache */ |
| return NFCSTATUS_INVALID_PARAMETER; |
| } |
| } |
| |
| /* Handle service with no name */ |
| if (psServiceName == NULL) |
| { |
| if (pLlcpSocket->sServiceName.buffer != NULL) |
| { |
| phOsalNfc_FreeMemory(pLlcpSocket->sServiceName.buffer); |
| } |
| pLlcpSocket->sServiceName.buffer = NULL; |
| pLlcpSocket->sServiceName.length = 0; |
| } |
| else |
| { |
| /* Check if name already in use */ |
| for(index=0;index<PHFRINFC_LLCP_NB_SOCKET_MAX;index++) |
| { |
| phFriNfc_LlcpTransport_Socket_t* pCurrentSocket = &pLlcpSocket->psTransport->pSocketTable[index]; |
| |
| if( (pCurrentSocket->eSocket_State != phFriNfc_LlcpTransportSocket_eSocketBound) |
| && (pCurrentSocket->eSocket_State != phFriNfc_LlcpTransportSocket_eSocketRegistered)) |
| { |
| /* Only bound or listening sockets may have a service name */ |
| continue; |
| } |
| if(pCurrentSocket->sServiceName.length != psServiceName->length) { |
| /* Service name do not match, check next */ |
| continue; |
| } |
| if(memcmp(pCurrentSocket->sServiceName.buffer, psServiceName->buffer, psServiceName->length) == 0) |
| { |
| /* Service name already in use */ |
| return NFCSTATUS_INVALID_PARAMETER; |
| } |
| } |
| |
| /* Store the listen socket SN */ |
| pLlcpSocket->sServiceName.length = psServiceName->length; |
| pLlcpSocket->sServiceName.buffer = phOsalNfc_GetMemory(psServiceName->length); |
| if (pLlcpSocket->sServiceName.buffer == NULL) |
| { |
| return NFCSTATUS_NOT_ENOUGH_MEMORY; |
| } |
| memcpy(pLlcpSocket->sServiceName.buffer, psServiceName->buffer, psServiceName->length); |
| } |
| |
| return NFCSTATUS_SUCCESS; |
| } |
| |
| /** |
| * \ingroup grp_fri_nfc |
| * \brief <b>Accept an incoming connection request for a socket</b>. |
| * |
| * This functions allows the client to accept an incoming connection request. |
| * It must be used with the socket provided within the listen callback. The socket |
| * is implicitly switched to the connected state when the function is called. |
| * |
| * \param[in] pLlcpSocket A pointer to a phFriNfc_LlcpTransport_Socket_t. |
| * \param[in] psOptions The options to be used with the socket. |
| * \param[in] psWorkingBuffer A working buffer to be used by the library. |
| * \param[in] pErr_Cb The callback to be called each time the accepted socket |
| * is in error. |
| * \param[in] pContext Upper layer context to be returned in the callback. |
| * |
| * \retval NFCSTATUS_SUCCESS Operation successful. |
| * \retval NFCSTATUS_INVALID_PARAMETER One or more of the supplied parameters |
| * could not be properly interpreted. |
| * \retval NFCSTATUS_BUFFER_TOO_SMALL The working buffer is too small for the MIU and RW |
| * declared in the options. |
| * \retval NFCSTATUS_FAILED Operation failed. |
| */ |
| NFCSTATUS phFriNfc_LlcpTransport_Accept(phFriNfc_LlcpTransport_Socket_t* pLlcpSocket, |
| phFriNfc_LlcpTransport_sSocketOptions_t* psOptions, |
| phNfc_sData_t* psWorkingBuffer, |
| pphFriNfc_LlcpTransportSocketErrCb_t pErr_Cb, |
| pphFriNfc_LlcpTransportSocketAcceptCb_t pAccept_RspCb, |
| void* pContext) |
| { |
| NFCSTATUS status = NFCSTATUS_SUCCESS; |
| |
| /* Check for NULL pointers */ |
| if(pLlcpSocket == NULL || psOptions == NULL || psWorkingBuffer == NULL || pErr_Cb == NULL || pContext == NULL) |
| { |
| status = PHNFCSTVAL(CID_FRI_NFC_LLCP_TRANSPORT, NFCSTATUS_INVALID_PARAMETER); |
| } |
| /* Check for socket state */ |
| else if(pLlcpSocket->eSocket_State != phFriNfc_LlcpTransportSocket_eSocketBound) |
| { |
| status = PHNFCSTVAL(CID_FRI_NFC_LLCP_TRANSPORT, NFCSTATUS_INVALID_STATE); |
| } |
| /* Check for socket type */ |
| else if(pLlcpSocket->eSocket_Type != phFriNfc_LlcpTransport_eConnectionOriented) |
| { |
| status = PHNFCSTVAL(CID_FRI_NFC_LLCP_TRANSPORT, NFCSTATUS_INVALID_PARAMETER); |
| } |
| /* Test the socket options */ |
| else if(psOptions->rw > PHFRINFC_LLCP_RW_MAX) |
| { |
| status = PHNFCSTVAL(CID_FRI_NFC_LLCP_TRANSPORT, NFCSTATUS_INVALID_PARAMETER); |
| } |
| else |
| { |
| /* Set the Max length for the Send and Receive Window Buffer */ |
| pLlcpSocket->bufferSendMaxLength = psOptions->miu; |
| pLlcpSocket->bufferRwMaxLength = psOptions->miu * ((psOptions->rw & PHFRINFC_LLCP_TLV_RW_MASK)); |
| pLlcpSocket->bufferLinearLength = psWorkingBuffer->length - pLlcpSocket->bufferSendMaxLength - pLlcpSocket->bufferRwMaxLength; |
| |
| /* Test the buffers length */ |
| if((pLlcpSocket->bufferSendMaxLength + pLlcpSocket->bufferRwMaxLength) > psWorkingBuffer->length |
| || ((pLlcpSocket->bufferLinearLength < PHFRINFC_LLCP_MIU_DEFAULT) && (pLlcpSocket->bufferLinearLength != 0))) |
| { |
| status = PHNFCSTVAL(CID_FRI_NFC_LLCP_TRANSPORT, NFCSTATUS_BUFFER_TOO_SMALL); |
| } |
| else |
| { |
| pLlcpSocket->psTransport->socketIndex = pLlcpSocket->index; |
| |
| status = phFriNfc_LlcpTransport_ConnectionOriented_Accept(pLlcpSocket, |
| psOptions, |
| psWorkingBuffer, |
| pErr_Cb, |
| pAccept_RspCb, |
| pContext); |
| } |
| } |
| return status; |
| } |
| |
| /** |
| * \ingroup grp_fri_nfc |
| * \brief <b>Reject an incoming connection request for a socket</b>. |
| * |
| * This functions allows the client to reject an incoming connection request. |
| * It must be used with the socket provided within the listen callback. The socket |
| * is implicitly closed when the function is called. |
| * |
| * \param[in] pLlcpSocket A pointer to a phFriNfc_LlcpTransport_Socket_t. |
| * \param[in] pReject_RspCb The callback to be call when the Reject operation is completed |
| * \param[in] pContext Upper layer context to be returned in the callback. |
| * |
| * \retval NFCSTATUS_SUCCESS Operation successful. |
| * \retval NFCSTATUS_INVALID_PARAMETER One or more of the supplied parameters |
| * could not be properly interpreted. |
| * \retval NFCSTATUS_FAILED Operation failed. |
| */ |
| NFCSTATUS phFriNfc_LlcpTransport_Reject( phFriNfc_LlcpTransport_Socket_t* pLlcpSocket, |
| pphFriNfc_LlcpTransportSocketRejectCb_t pReject_RspCb, |
| void *pContext) |
| { |
| NFCSTATUS status = NFCSTATUS_SUCCESS; |
| |
| /* Check for NULL pointers */ |
| if(pLlcpSocket == NULL) |
| { |
| status = PHNFCSTVAL(CID_FRI_NFC_LLCP_TRANSPORT, NFCSTATUS_INVALID_PARAMETER); |
| } |
| /* Check for socket state */ |
| else if(pLlcpSocket->eSocket_State != phFriNfc_LlcpTransportSocket_eSocketBound) |
| { |
| status = PHNFCSTVAL(CID_FRI_NFC_LLCP_TRANSPORT, NFCSTATUS_INVALID_STATE); |
| } |
| /* Check for socket type */ |
| else if(pLlcpSocket->eSocket_Type != phFriNfc_LlcpTransport_eConnectionOriented) |
| { |
| status = PHNFCSTVAL(CID_FRI_NFC_LLCP_TRANSPORT, NFCSTATUS_INVALID_PARAMETER); |
| } |
| else |
| { |
| status = phLibNfc_LlcpTransport_ConnectionOriented_Reject(pLlcpSocket, |
| pReject_RspCb, |
| pContext); |
| } |
| |
| return status; |
| } |
| |
| /** |
| * \ingroup grp_fri_nfc |
| * \brief <b>Try to establish connection with a socket on a remote SAP</b>. |
| * |
| * This function tries to connect to a given SAP on the remote peer. If the |
| * socket is not bound to a local SAP, it is implicitly bound to a free SAP. |
| * |
| * \param[in] pLlcpSocket A pointer to a phFriNfc_LlcpTransport_Socket_t. |
| * \param[in] nSap The destination SAP to connect to. |
| * \param[in] pConnect_RspCb The callback to be called when the connection |
| * operation is completed. |
| * \param[in] pContext Upper layer context to be returned in |
| * the callback. |
| * |
| * \retval NFCSTATUS_SUCCESS Operation successful. |
| * \retval NFCSTATUS_INVALID_PARAMETER One or more of the supplied parameters |
| * could not be properly interpreted. |
| * \retval NFCSTATUS_PENDING Connection operation is in progress, |
| * pConnect_RspCb will be called upon completion. |
| * \retval NFCSTATUS_INVALID_STATE The socket is not in a valid state, or not of |
| * a valid type to perform the requsted operation. |
| * \retval NFCSTATUS_FAILED Operation failed. |
| */ |
| NFCSTATUS phFriNfc_LlcpTransport_Connect( phFriNfc_LlcpTransport_Socket_t* pLlcpSocket, |
| uint8_t nSap, |
| pphFriNfc_LlcpTransportSocketConnectCb_t pConnect_RspCb, |
| void* pContext) |
| { |
| NFCSTATUS status = NFCSTATUS_SUCCESS; |
| uint8_t nLocalSap; |
| uint8_t i; |
| |
| /* Check for NULL pointers */ |
| if(pLlcpSocket == NULL || pConnect_RspCb == NULL || pContext == NULL) |
| { |
| status = PHNFCSTVAL(CID_FRI_NFC_LLCP_TRANSPORT, NFCSTATUS_INVALID_PARAMETER); |
| } |
| /* Test the port number value */ |
| else if(nSap<02 || nSap>63) |
| { |
| status = PHNFCSTVAL(CID_FRI_NFC_LLCP_TRANSPORT, NFCSTATUS_INVALID_PARAMETER); |
| } |
| /* Test if the socket is a connectionOriented socket */ |
| else if(pLlcpSocket->eSocket_Type != phFriNfc_LlcpTransport_eConnectionOriented) |
| { |
| status = PHNFCSTVAL(CID_FRI_NFC_LLCP_TRANSPORT, NFCSTATUS_INVALID_PARAMETER); |
| } |
| /* Test if the socket has a service name */ |
| else if(pLlcpSocket->sServiceName.length != 0) |
| { |
| status = PHNFCSTVAL(CID_FRI_NFC_LLCP_TRANSPORT, NFCSTATUS_INVALID_STATE); |
| } |
| /* Test if the socket is not in connecting or connected state*/ |
| else if(pLlcpSocket->eSocket_State != phFriNfc_LlcpTransportSocket_eSocketCreated && pLlcpSocket->eSocket_State != phFriNfc_LlcpTransportSocket_eSocketBound) |
| { |
| status = PHNFCSTVAL(CID_FRI_NFC_LLCP_TRANSPORT, NFCSTATUS_INVALID_STATE); |
| } |
| else |
| { |
| /* Implicit bind if socket is not already bound */ |
| if(pLlcpSocket->eSocket_State != phFriNfc_LlcpTransportSocket_eSocketBound) |
| { |
| /* Bind to a free sap */ |
| status = phFriNfc_LlcpTransport_GetFreeSap(pLlcpSocket->psTransport, NULL, &nLocalSap); |
| if (status != NFCSTATUS_SUCCESS) |
| { |
| return status; |
| } |
| pLlcpSocket->socket_sSap = nLocalSap; |
| } |
| |
| /* Test the SAP range for non SDP-advertised services */ |
| if(!IS_BETWEEN(pLlcpSocket->socket_sSap, PHFRINFC_LLCP_SAP_SDP_UNADVERTISED_FIRST, PHFRINFC_LLCP_SAP_NUMBER)) |
| { |
| status = PHNFCSTVAL(CID_FRI_NFC_LLCP_TRANSPORT, NFCSTATUS_INVALID_PARAMETER); |
| } |
| else |
| { |
| status = phFriNfc_LlcpTransport_ConnectionOriented_Connect(pLlcpSocket, |
| nSap, |
| NULL, |
| pConnect_RspCb, |
| pContext); |
| } |
| } |
| |
| return status; |
| } |
| |
| /** |
| * \ingroup grp_fri_nfc |
| * \brief <b>Try to establish connection with a socket on a remote service, given its URI</b>. |
| * |
| * This function tries to connect to a SAP designated by an URI. If the |
| * socket is not bound to a local SAP, it is implicitly bound to a free SAP. |
| * |
| * \param[in] pLlcpSocket A pointer to a phFriNfc_LlcpTransport_Socket_t. |
| * \param[in] psUri The URI corresponding to the destination SAP to connect to. |
| * \param[in] pConnect_RspCb The callback to be called when the connection |
| * operation is completed. |
| * \param[in] pContext Upper layer context to be returned in |
| * the callback. |
| * |
| * \retval NFCSTATUS_SUCCESS Operation successful. |
| * \retval NFCSTATUS_INVALID_PARAMETER One or more of the supplied parameters |
| * could not be properly interpreted. |
| * \retval NFCSTATUS_PENDING Connection operation is in progress, |
| * pConnect_RspCb will be called upon completion. |
| * \retval NFCSTATUS_INVALID_STATE The socket is not in a valid state, or not of |
| * a valid type to perform the requsted operation. |
| * \retval NFCSTATUS_NOT_INITIALISED Indicates stack is not yet initialized. |
| * \retval NFCSTATUS_SHUTDOWN Shutdown in progress. |
| * \retval NFCSTATUS_FAILED Operation failed. |
| */ |
| NFCSTATUS phFriNfc_LlcpTransport_ConnectByUri(phFriNfc_LlcpTransport_Socket_t* pLlcpSocket, |
| phNfc_sData_t* psUri, |
| pphFriNfc_LlcpTransportSocketConnectCb_t pConnect_RspCb, |
| void* pContext) |
| { |
| NFCSTATUS status = NFCSTATUS_SUCCESS; |
| uint8_t i; |
| uint8_t nLocalSap; |
| |
| /* Check for NULL pointers */ |
| if(pLlcpSocket == NULL || pConnect_RspCb == NULL || pContext == NULL) |
| { |
| status = PHNFCSTVAL(CID_FRI_NFC_LLCP_TRANSPORT, NFCSTATUS_INVALID_PARAMETER); |
| } |
| /* Test if the socket is a connectionOriented socket */ |
| else if(pLlcpSocket->eSocket_Type != phFriNfc_LlcpTransport_eConnectionOriented) |
| { |
| status = PHNFCSTVAL(CID_FRI_NFC_LLCP_TRANSPORT, NFCSTATUS_INVALID_PARAMETER); |
| } |
| /* Test if the socket is not in connect pending or connected state*/ |
| else if(pLlcpSocket->eSocket_State == phFriNfc_LlcpTransportSocket_eSocketConnecting || pLlcpSocket->eSocket_State == phFriNfc_LlcpTransportSocket_eSocketConnected) |
| { |
| status = PHNFCSTVAL(CID_FRI_NFC_LLCP_TRANSPORT, NFCSTATUS_INVALID_PARAMETER); |
| } |
| /* Test the length of the SN */ |
| else if(psUri->length > PHFRINFC_LLCP_SN_MAX_LENGTH) |
| { |
| status = PHNFCSTVAL(CID_FRI_NFC_LLCP_TRANSPORT, NFCSTATUS_INVALID_PARAMETER); |
| } |
| else |
| { |
| /* Implicit bind if socket is not already bound */ |
| if(pLlcpSocket->eSocket_State != phFriNfc_LlcpTransportSocket_eSocketBound) |
| { |
| /* Bind to a free sap */ |
| status = phFriNfc_LlcpTransport_GetFreeSap(pLlcpSocket->psTransport, NULL, &nLocalSap); |
| if (status != NFCSTATUS_SUCCESS) |
| { |
| return status; |
| } |
| pLlcpSocket->socket_sSap = nLocalSap; |
| } |
| |
| /* Test the SAP range for non SDP-advertised services */ |
| if(!IS_BETWEEN(pLlcpSocket->socket_sSap, PHFRINFC_LLCP_SAP_SDP_UNADVERTISED_FIRST, PHFRINFC_LLCP_SAP_NUMBER)) |
| { |
| status = PHNFCSTVAL(CID_FRI_NFC_LLCP_TRANSPORT, NFCSTATUS_INVALID_PARAMETER); |
| } |
| else |
| { |
| status = phFriNfc_LlcpTransport_ConnectionOriented_Connect(pLlcpSocket, |
| PHFRINFC_LLCP_SAP_DEFAULT, |
| psUri, |
| pConnect_RspCb, |
| pContext); |
| } |
| } |
| |
| return status; |
| } |
| |
| /** |
| * \ingroup grp_lib_nfc |
| * \brief <b>Disconnect a currently connected socket</b>. |
| * |
| * This function initiates the disconnection of a previously connected socket. |
| * |
| * \param[in] pLlcpSocket A pointer to a phFriNfc_LlcpTransport_Socket_t. |
| * \param[in] pDisconnect_RspCb The callback to be called when the |
| * operation is completed. |
| * \param[in] pContext Upper layer context to be returned in |
| * the callback. |
| * |
| * \retval NFCSTATUS_SUCCESS Operation successful. |
| * \retval NFCSTATUS_INVALID_PARAMETER One or more of the supplied parameters |
| * could not be properly interpreted. |
| * \retval NFCSTATUS_PENDING Disconnection operation is in progress, |
| * pDisconnect_RspCb will be called upon completion. |
| * \retval NFCSTATUS_INVALID_STATE The socket is not in a valid state, or not of |
| * a valid type to perform the requsted operation. |
| * \retval NFCSTATUS_NOT_INITIALISED Indicates stack is not yet initialized. |
| * \retval NFCSTATUS_SHUTDOWN Shutdown in progress. |
| * \retval NFCSTATUS_FAILED Operation failed. |
| */ |
| NFCSTATUS phFriNfc_LlcpTransport_Disconnect(phFriNfc_LlcpTransport_Socket_t* pLlcpSocket, |
| pphLibNfc_LlcpSocketDisconnectCb_t pDisconnect_RspCb, |
| void* pContext) |
| { |
| NFCSTATUS status = NFCSTATUS_SUCCESS; |
| |
| /* Check for NULL pointers */ |
| if(pLlcpSocket == NULL || pDisconnect_RspCb == NULL || pContext == NULL) |
| { |
| status = PHNFCSTVAL(CID_FRI_NFC_LLCP_TRANSPORT, NFCSTATUS_INVALID_PARAMETER); |
| } |
| /* Test if the socket is a connectionOriented socket */ |
| else if(pLlcpSocket->eSocket_Type != phFriNfc_LlcpTransport_eConnectionOriented) |
| { |
| status = PHNFCSTVAL(CID_FRI_NFC_LLCP_TRANSPORT, NFCSTATUS_INVALID_PARAMETER); |
| } |
| /* Test if the socket is connected state*/ |
| else if(pLlcpSocket->eSocket_State != phFriNfc_LlcpTransportSocket_eSocketConnected) |
| { |
| status = PHNFCSTVAL(CID_FRI_NFC_LLCP_TRANSPORT, NFCSTATUS_INVALID_PARAMETER); |
| } |
| else |
| { |
| status = phLibNfc_LlcpTransport_ConnectionOriented_Disconnect(pLlcpSocket, |
| pDisconnect_RspCb, |
| pContext); |
| } |
| |
| return status; |
| } |
| |
| /** |
| * \ingroup grp_fri_nfc |
| * \brief <b>Send data on a socket</b>. |
| * |
| * This function is used to write data on a socket. This function |
| * can only be called on a connection-oriented socket which is already |
| * in a connected state. |
| * |
| * |
| * \param[in] pLlcpSocket A pointer to a phFriNfc_LlcpTransport_Socket_t. |
| * \param[in] psBuffer The buffer containing the data to send. |
| * \param[in] pSend_RspCb The callback to be called when the |
| * operation is completed. |
| * \param[in] pContext Upper layer context to be returned in |
| * the callback. |
| * |
| * \retval NFCSTATUS_SUCCESS Operation successful. |
| * \retval NFCSTATUS_INVALID_PARAMETER One or more of the supplied parameters |
| * could not be properly interpreted. |
| * \retval NFCSTATUS_PENDING Reception operation is in progress, |
| * pSend_RspCb will be called upon completion. |
| * \retval NFCSTATUS_INVALID_STATE The socket is not in a valid state, or not of |
| * a valid type to perform the requsted operation. |
| * \retval NFCSTATUS_FAILED Operation failed. |
| */ |
| NFCSTATUS phFriNfc_LlcpTransport_Send(phFriNfc_LlcpTransport_Socket_t* pLlcpSocket, |
| phNfc_sData_t* psBuffer, |
| pphFriNfc_LlcpTransportSocketSendCb_t pSend_RspCb, |
| void* pContext) |
| { |
| NFCSTATUS status = NFCSTATUS_SUCCESS; |
| |
| /* Check for NULL pointers */ |
| if(pLlcpSocket == NULL || psBuffer == NULL || pSend_RspCb == NULL || pContext == NULL) |
| { |
| status = PHNFCSTVAL(CID_FRI_NFC_LLCP_TRANSPORT, NFCSTATUS_INVALID_PARAMETER); |
| } |
| /* Test if the socket is a connectionOriented socket */ |
| else if(pLlcpSocket->eSocket_Type != phFriNfc_LlcpTransport_eConnectionOriented) |
| { |
| status = PHNFCSTVAL(CID_FRI_NFC_LLCP_TRANSPORT, NFCSTATUS_INVALID_PARAMETER); |
| } |
| /* Test if the socket is in connected state */ |
| else if(pLlcpSocket->eSocket_State != phFriNfc_LlcpTransportSocket_eSocketConnected) |
| { |
| status = PHNFCSTVAL(CID_FRI_NFC_LLCP_TRANSPORT, NFCSTATUS_INVALID_STATE); |
| } |
| /* Test the length of the buffer */ |
| else if(psBuffer->length > pLlcpSocket->remoteMIU ) |
| { |
| status = PHNFCSTVAL(CID_FRI_NFC_LLCP_TRANSPORT, NFCSTATUS_INVALID_PARAMETER); |
| } |
| /* Test if a send is pending */ |
| else if(pLlcpSocket->pfSocketSend_Cb != NULL) |
| { |
| status = PHNFCSTVAL(CID_FRI_NFC_LLCP_TRANSPORT, NFCSTATUS_REJECTED); |
| } |
| else |
| { |
| status = phFriNfc_LlcpTransport_ConnectionOriented_Send(pLlcpSocket, |
| psBuffer, |
| pSend_RspCb, |
| pContext); |
| } |
| |
| return status; |
| } |
| |
| /** |
| * \ingroup grp_fri_nfc |
| * \brief <b>Read data on a socket</b>. |
| * |
| * This function is used to read data from a socket. It reads at most the |
| * size of the reception buffer, but can also return less bytes if less bytes |
| * are available. If no data is available, the function will be pending until |
| * more data comes, and the response will be sent by the callback. This function |
| * can only be called on a connection-oriented socket. |
| * |
| * |
| * \param[in] pLlcpSocket A pointer to a phFriNfc_LlcpTransport_Socket_t. |
| * \param[in] psBuffer The buffer receiving the data. |
| * \param[in] pRecv_RspCb The callback to be called when the |
| * operation is completed. |
| * \param[in] pContext Upper layer context to be returned in |
| * the callback. |
| * |
| * \retval NFCSTATUS_SUCCESS Operation successful. |
| * \retval NFCSTATUS_INVALID_PARAMETER One or more of the supplied parameters |
| * could not be properly interpreted. |
| * \retval NFCSTATUS_PENDING Reception operation is in progress, |
| * pRecv_RspCb will be called upon completion. |
| * \retval NFCSTATUS_INVALID_STATE The socket is not in a valid state, or not of |
| * a valid type to perform the requsted operation. |
| * \retval NFCSTATUS_FAILED Operation failed. |
| */ |
| NFCSTATUS phFriNfc_LlcpTransport_Recv( phFriNfc_LlcpTransport_Socket_t* pLlcpSocket, |
| phNfc_sData_t* psBuffer, |
| pphFriNfc_LlcpTransportSocketRecvCb_t pRecv_RspCb, |
| void* pContext) |
| { |
| NFCSTATUS status = NFCSTATUS_SUCCESS; |
| |
| /* Check for NULL pointers */ |
| if(pLlcpSocket == NULL || psBuffer == NULL || pRecv_RspCb == NULL || pContext == NULL) |
| { |
| status = PHNFCSTVAL(CID_FRI_NFC_LLCP_TRANSPORT, NFCSTATUS_INVALID_PARAMETER); |
| } |
| /* Test if the socket is a connectionOriented socket */ |
| else if(pLlcpSocket->eSocket_Type != phFriNfc_LlcpTransport_eConnectionOriented) |
| { |
| status = PHNFCSTVAL(CID_FRI_NFC_LLCP_TRANSPORT, NFCSTATUS_INVALID_PARAMETER); |
| } |
| /* Test if the socket is in connected state */ |
| else if(pLlcpSocket->eSocket_State == phFriNfc_LlcpTransportSocket_eSocketDefault) |
| { |
| status = PHNFCSTVAL(CID_FRI_NFC_LLCP_TRANSPORT, NFCSTATUS_INVALID_PARAMETER); |
| } |
| /* Test if a receive is pending */ |
| else if(pLlcpSocket->bSocketRecvPending == TRUE) |
| { |
| status = PHNFCSTVAL(CID_FRI_NFC_LLCP_TRANSPORT, NFCSTATUS_REJECTED); |
| } |
| else |
| { |
| status = phFriNfc_LlcpTransport_ConnectionOriented_Recv(pLlcpSocket, |
| psBuffer, |
| pRecv_RspCb, |
| pContext); |
| } |
| |
| return status; |
| } |
| |
| /*****************************************/ |
| /* ConnectionLess */ |
| /*****************************************/ |
| |
| /** |
| * \ingroup grp_fri_nfc |
| * \brief <b>Send data on a socket to a given destination SAP</b>. |
| * |
| * This function is used to write data on a socket to a given destination SAP. |
| * This function can only be called on a connectionless socket. |
| * |
| * |
| * \param[in] pLlcpSocket A pointer to a LlcpSocket created. |
| * \param[in] nSap The destination SAP. |
| * \param[in] psBuffer The buffer containing the data to send. |
| * \param[in] pSend_RspCb The callback to be called when the |
| * operation is completed. |
| * \param[in] pContext Upper layer context to be returned in |
| * the callback. |
| * |
| * \retval NFCSTATUS_SUCCESS Operation successful. |
| * \retval NFCSTATUS_INVALID_PARAMETER One or more of the supplied parameters |
| * could not be properly interpreted. |
| * \retval NFCSTATUS_PENDING Reception operation is in progress, |
| * pSend_RspCb will be called upon completion. |
| * \retval NFCSTATUS_INVALID_STATE The socket is not in a valid state, or not of |
| * a valid type to perform the requsted operation. |
| * \retval NFCSTATUS_FAILED Operation failed. |
| */ |
| NFCSTATUS phFriNfc_LlcpTransport_SendTo( phFriNfc_LlcpTransport_Socket_t *pLlcpSocket, |
| uint8_t nSap, |
| phNfc_sData_t *psBuffer, |
| pphFriNfc_LlcpTransportSocketSendCb_t pSend_RspCb, |
| void* pContext) |
| { |
| NFCSTATUS status = NFCSTATUS_SUCCESS; |
| phFriNfc_Llcp_sLinkParameters_t LlcpRemoteLinkParamInfo; |
| |
| if(pLlcpSocket == NULL || psBuffer == NULL || pSend_RspCb == NULL || pContext == NULL) |
| { |
| status = PHNFCSTVAL(CID_FRI_NFC_LLCP_TRANSPORT, NFCSTATUS_INVALID_PARAMETER); |
| } |
| /* Test the port number value */ |
| else if(nSap<2 || nSap>63) |
| { |
| status = PHNFCSTVAL(CID_FRI_NFC_LLCP_TRANSPORT, NFCSTATUS_INVALID_PARAMETER); |
| } |
| /* Test if the socket is a connectionless socket */ |
| else if(pLlcpSocket->eSocket_Type != phFriNfc_LlcpTransport_eConnectionLess) |
| { |
| status = PHNFCSTVAL(CID_FRI_NFC_LLCP_TRANSPORT, NFCSTATUS_INVALID_PARAMETER); |
| } |
| /* Test if the socket is in an updated state */ |
| else if(pLlcpSocket->eSocket_State != phFriNfc_LlcpTransportSocket_eSocketBound) |
| { |
| status = PHNFCSTVAL(CID_FRI_NFC_LLCP_TRANSPORT, NFCSTATUS_INVALID_STATE); |
| } |
| /* Test if a send is pending */ |
| else if(pLlcpSocket->pfSocketSend_Cb != NULL) |
| { |
| status = PHNFCSTVAL(CID_FRI_NFC_LLCP_TRANSPORT, NFCSTATUS_REJECTED); |
| } |
| else |
| { |
| /* Get the local parameters of the LLCP Link */ |
| status = phFriNfc_Llcp_GetRemoteInfo(pLlcpSocket->psTransport->pLlcp,&LlcpRemoteLinkParamInfo); |
| if(status != NFCSTATUS_SUCCESS) |
| { |
| status = PHNFCSTVAL(CID_FRI_NFC_LLCP_TRANSPORT, NFCSTATUS_FAILED); |
| } |
| /* Test the length of the socket buffer for ConnectionLess mode*/ |
| else if(psBuffer->length > LlcpRemoteLinkParamInfo.miu) |
| { |
| status = PHNFCSTVAL(CID_FRI_NFC_LLCP_TRANSPORT, NFCSTATUS_INVALID_PARAMETER); |
| } |
| /* Test if the link is in error state */ |
| else if(pLlcpSocket->psTransport->LinkStatusError) |
| { |
| status = PHNFCSTVAL(CID_FRI_NFC_LLCP_TRANSPORT, NFCSTATUS_REJECTED); |
| } |
| else |
| { |
| status = phFriNfc_LlcpTransport_Connectionless_SendTo(pLlcpSocket, |
| nSap, |
| psBuffer, |
| pSend_RspCb, |
| pContext); |
| } |
| } |
| |
| return status; |
| } |
| |
| |
| /** |
| * \ingroup grp_lib_nfc |
| * \brief <b>Read data on a socket and get the source SAP</b>. |
| * |
| * This function is the same as phLibNfc_Llcp_Recv, except that the callback includes |
| * the source SAP. This functions can only be called on a connectionless socket. |
| * |
| * |
| * \param[in] pLlcpSocket A pointer to a LlcpSocket created. |
| * \param[in] psBuffer The buffer receiving the data. |
| * \param[in] pRecv_RspCb The callback to be called when the |
| * operation is completed. |
| * \param[in] pContext Upper layer context to be returned in |
| * the callback. |
| * |
| * \retval NFCSTATUS_SUCCESS Operation successful. |
| * \retval NFCSTATUS_INVALID_PARAMETER One or more of the supplied parameters |
| * could not be properly interpreted. |
| * \retval NFCSTATUS_PENDING Reception operation is in progress, |
| * pRecv_RspCb will be called upon completion. |
| * \retval NFCSTATUS_INVALID_STATE The socket is not in a valid state, or not of |
| * a valid type to perform the requsted operation. |
| * \retval NFCSTATUS_NOT_INITIALISED Indicates stack is not yet initialized. |
| * \retval NFCSTATUS_SHUTDOWN Shutdown in progress. |
| * \retval NFCSTATUS_FAILED Operation failed. |
| */ |
| NFCSTATUS phFriNfc_LlcpTransport_RecvFrom( phFriNfc_LlcpTransport_Socket_t *pLlcpSocket, |
| phNfc_sData_t* psBuffer, |
| pphFriNfc_LlcpTransportSocketRecvFromCb_t pRecv_Cb, |
| void* pContext) |
| { |
| NFCSTATUS status = NFCSTATUS_SUCCESS; |
| if(pLlcpSocket == NULL || psBuffer == NULL || pRecv_Cb == NULL || pContext == NULL) |
| { |
| status = PHNFCSTVAL(CID_FRI_NFC_LLCP_TRANSPORT, NFCSTATUS_INVALID_PARAMETER); |
| } |
| /* Test if the socket is a connectionless socket */ |
| else if(pLlcpSocket->eSocket_Type != phFriNfc_LlcpTransport_eConnectionLess) |
| { |
| status = PHNFCSTVAL(CID_FRI_NFC_LLCP_TRANSPORT, NFCSTATUS_INVALID_PARAMETER); |
| } |
| /* Test if the socket is in an updated state */ |
| else if(pLlcpSocket->eSocket_State != phFriNfc_LlcpTransportSocket_eSocketBound) |
| { |
| status = PHNFCSTVAL(CID_FRI_NFC_LLCP_TRANSPORT, NFCSTATUS_INVALID_STATE); |
| } |
| else |
| { |
| if(pLlcpSocket->bSocketRecvPending) |
| { |
| status = PHNFCSTVAL(CID_FRI_NFC_LLCP_TRANSPORT, NFCSTATUS_REJECTED); |
| } |
| else |
| { |
| status = phLibNfc_LlcpTransport_Connectionless_RecvFrom(pLlcpSocket, |
| psBuffer, |
| pRecv_Cb, |
| pContext); |
| } |
| } |
| |
| return status; |
| } |