/* * 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_Connection.c * \brief * * Project: NFC-FRI * */ /*include files*/ #include #include #include #include #include #include #include #include /* Function definition */ static NFCSTATUS phFriNfc_Llcp_Send_ReceiveReady_Frame(phFriNfc_LlcpTransport_Socket_t* pLlcpSocket); static NFCSTATUS phFriNfc_Llcp_Send_ReceiveNotReady_Frame(phFriNfc_LlcpTransport_Socket_t* pLlcpSocket); static NFCSTATUS static_performSendInfo(phFriNfc_LlcpTransport_Socket_t * psLlcpSocket); /********** End Function definition ***********/ NFCSTATUS phFriNfc_LlcpConnTransport_Send( phFriNfc_Llcp_t *Llcp, phFriNfc_Llcp_sPacketHeader_t *psHeader, phFriNfc_Llcp_sPacketSequence_t *psSequence, phNfc_sData_t *psInfo, phFriNfc_Llcp_Send_CB_t pfSend_CB, phFriNfc_LlcpTransport_t* psTransport ) { NFCSTATUS result = phFriNfc_Llcp_Send(Llcp, psHeader, psSequence, psInfo, pfSend_CB, psTransport); if (result == NFCSTATUS_PENDING) { psTransport->bSendPending = TRUE; } return result; } /* TODO: comment functionphFriNfc_LlcpTransport_ConnectionOriented_SendLlcp_CB */ static void phFriNfc_LlcpTransport_ConnectionOriented_SendLlcp_CB(void* pContext, NFCSTATUS status) { phFriNfc_LlcpTransport_t *psTransport; phFriNfc_LlcpTransport_Socket_t psTempLlcpSocket; phFriNfc_LlcpTransport_Socket_t *psLocalLlcpSocket = NULL; phNfc_sData_t sFrmrBuffer; uint8_t index; uint8_t socketFound = FALSE; NFCSTATUS result; /* Get Send CB context */ psTransport = (phFriNfc_LlcpTransport_t*)pContext; if(status == NFCSTATUS_SUCCESS) { /* Test the socket */ switch(psTransport->pSocketTable[psTransport->socketIndex].eSocket_State) { case phFriNfc_LlcpTransportSocket_eSocketAccepted: { /* Set socket state to Connected */ psTransport->pSocketTable[psTransport->socketIndex].eSocket_State = phFriNfc_LlcpTransportSocket_eSocketConnected; /* Call the Accept Callback */ psTransport->pSocketTable[psTransport->socketIndex].pfSocketAccept_Cb(psTransport->pSocketTable[psTransport->socketIndex].pAcceptContext,status); psTransport->pSocketTable[psTransport->socketIndex].pfSocketAccept_Cb = NULL; psTransport->pSocketTable[psTransport->socketIndex].pAcceptContext = NULL; }break; case phFriNfc_LlcpTransportSocket_eSocketRejected: { /* Store the Llcp socket in a local Llcp socket */ psTempLlcpSocket = psTransport->pSocketTable[psTransport->socketIndex]; /* Reset the socket and set the socket state to default */ result = phFriNfc_LlcpTransport_Close(&psTransport->pSocketTable[psTransport->socketIndex]); /* Call the Reject Callback */ psTempLlcpSocket.pfSocketSend_Cb(psTempLlcpSocket.pRejectContext,status); psTempLlcpSocket.pfSocketSend_Cb = NULL; }break; case phFriNfc_LlcpTransportSocket_eSocketConnected: { if(!psTransport->pSocketTable[psTransport->socketIndex].bSocketSendPending && psTransport->pSocketTable[psTransport->socketIndex].pfSocketSend_Cb != NULL) { psTransport->pSocketTable[psTransport->socketIndex].pfSocketSend_Cb(psTransport->pSocketTable[psTransport->socketIndex].pSendContext,status); psTransport->pSocketTable[psTransport->socketIndex].pfSocketSend_Cb = NULL; } }break; default: /* Nothing to do */ break; } } else { /* Send CB error */ if(!psTransport->pSocketTable[psTransport->socketIndex].bSocketSendPending && psTransport->pSocketTable[psTransport->socketIndex].pfSocketSend_Cb != NULL) { psTransport->pSocketTable[psTransport->socketIndex].pfSocketSend_Cb(psTransport->pSocketTable[psTransport->socketIndex].pSendContext,status); psTransport->pSocketTable[psTransport->socketIndex].pfSocketSend_Cb = NULL; } } } NFCSTATUS phFriNfc_LlcpTransport_ConnectionOriented_HandlePendingOperations(phFriNfc_LlcpTransport_Socket_t *pSocket) { NFCSTATUS result = NFCSTATUS_FAILED; phFriNfc_LlcpTransport_t *psTransport = pSocket->psTransport; /* I FRAME */ if(pSocket->bSocketSendPending == TRUE) { /* Test the RW window */ if(CHECK_SEND_RW(pSocket)) { result = static_performSendInfo(pSocket); } } /* RR FRAME */ else if(pSocket->bSocketRRPending == TRUE) { /* Reset RR pending */ pSocket->bSocketRRPending = FALSE; /* Send RR Frame */ result = phFriNfc_Llcp_Send_ReceiveReady_Frame(pSocket); } /* RNR Frame */ else if(pSocket->bSocketRNRPending == TRUE) { /* Reset RNR pending */ pSocket->bSocketRNRPending = FALSE; /* Send RNR Frame */ result = phFriNfc_Llcp_Send_ReceiveNotReady_Frame(pSocket); } /* CC Frame */ else if(pSocket->bSocketAcceptPending == TRUE) { /* Reset Accept pending */ pSocket->bSocketAcceptPending = FALSE; /* Fill the psLlcpHeader stuture with the DSAP,CC PTYPE and the SSAP */ pSocket->sLlcpHeader.dsap = pSocket->socket_dSap; pSocket->sLlcpHeader.ptype = PHFRINFC_LLCP_PTYPE_CC; pSocket->sLlcpHeader.ssap = pSocket->socket_sSap; /* Send Pending */ pSocket->psTransport->bSendPending = TRUE; /* Set the socket state to accepted */ pSocket->eSocket_State = phFriNfc_LlcpTransportSocket_eSocketAccepted; /* Send a CC Frame */ result = phFriNfc_LlcpTransport_LinkSend(psTransport, &pSocket->sLlcpHeader, NULL, &pSocket->sSocketSendBuffer, phFriNfc_LlcpTransport_ConnectionOriented_SendLlcp_CB, psTransport); } /* CONNECT FRAME */ else if(pSocket->bSocketConnectPending == TRUE) { /* Reset Accept pending */ pSocket->bSocketConnectPending = FALSE; /* Send Pending */ pSocket->psTransport->bSendPending = TRUE; /* Set the socket in connecting state */ pSocket->eSocket_State = phFriNfc_LlcpTransportSocket_eSocketConnecting; /* send CONNECT */ result = phFriNfc_LlcpTransport_LinkSend(psTransport, &pSocket->sLlcpHeader, NULL, &pSocket->sSocketSendBuffer, phFriNfc_LlcpTransport_ConnectionOriented_SendLlcp_CB, psTransport); } /* DISC FRAME */ else if(pSocket->bSocketDiscPending == TRUE) { /* Reset Disc Pending */ pSocket->bSocketDiscPending = FALSE; /* Send Pending */ pSocket->psTransport->bSendPending = TRUE; /* Set the socket in connecting state */ pSocket->eSocket_State = phFriNfc_LlcpTransportSocket_eSocketDisconnecting; /* Send DISC */ result = phFriNfc_LlcpTransport_LinkSend(psTransport, &pSocket->sLlcpHeader, NULL, &pSocket->sSocketSendBuffer, phFriNfc_LlcpTransport_ConnectionOriented_SendLlcp_CB, psTransport); /* Call ErrCB due to a DISC */ pSocket->pSocketErrCb(pSocket->pContext, PHFRINFC_LLCP_ERR_DISCONNECTED); } return result; } static NFCSTATUS static_performSendInfo(phFriNfc_LlcpTransport_Socket_t * psLlcpSocket) { phFriNfc_LlcpTransport_t *psTransport = psLlcpSocket->psTransport; NFCSTATUS status; /* Set transport send pending */ psTransport->bSendPending = TRUE; /* Set the Header */ psLlcpSocket->sLlcpHeader.dsap = psLlcpSocket->socket_dSap; psLlcpSocket->sLlcpHeader.ptype = PHFRINFC_LLCP_PTYPE_I; psLlcpSocket->sLlcpHeader.ssap = psLlcpSocket->socket_sSap; /* Set Sequence Numbers */ psLlcpSocket->sSequence.ns = psLlcpSocket->socket_VS; psLlcpSocket->sSequence.nr = psLlcpSocket->socket_VR; /* Update the VRA */ psLlcpSocket->socket_VRA = psLlcpSocket->socket_VR; /* Store the index of the socket */ psTransport->socketIndex = psLlcpSocket->index; /* Send I_PDU */ status = phFriNfc_LlcpTransport_LinkSend(psTransport, &psLlcpSocket->sLlcpHeader, &psLlcpSocket->sSequence, &psLlcpSocket->sSocketSendBuffer, phFriNfc_LlcpTransport_ConnectionOriented_SendLlcp_CB, psLlcpSocket->psTransport); /* Update VS */ psLlcpSocket->socket_VS = (psLlcpSocket->socket_VS+1)%16; /* Reset Send Pending */ psLlcpSocket->bSocketSendPending = FALSE; return status; } static void phFriNfc_LlcpTransport_ConnectionOriented_Abort(phFriNfc_LlcpTransport_Socket_t * pLlcpSocket) { if (pLlcpSocket->pfSocketSend_Cb != NULL) { pLlcpSocket->pfSocketSend_Cb(pLlcpSocket->pSendContext, NFCSTATUS_ABORTED); pLlcpSocket->pfSocketSend_Cb = NULL; } pLlcpSocket->pSendContext = NULL; if (pLlcpSocket->pfSocketRecv_Cb != NULL) { pLlcpSocket->pfSocketRecv_Cb(pLlcpSocket->pRecvContext, NFCSTATUS_ABORTED); pLlcpSocket->pfSocketRecv_Cb = NULL; } pLlcpSocket->pRecvContext = NULL; if (pLlcpSocket->pfSocketAccept_Cb != NULL) { pLlcpSocket->pfSocketAccept_Cb(pLlcpSocket->pAcceptContext, NFCSTATUS_ABORTED); pLlcpSocket->pfSocketAccept_Cb = NULL; } pLlcpSocket->pAcceptContext = NULL; if (pLlcpSocket->pfSocketConnect_Cb != NULL) { pLlcpSocket->pfSocketConnect_Cb(pLlcpSocket->pConnectContext, 0, NFCSTATUS_ABORTED); pLlcpSocket->pfSocketConnect_Cb = NULL; } pLlcpSocket->pConnectContext = NULL; if (pLlcpSocket->pfSocketDisconnect_Cb != NULL) { pLlcpSocket->pfSocketDisconnect_Cb(pLlcpSocket->pDisonnectContext, NFCSTATUS_ABORTED); pLlcpSocket->pfSocketDisconnect_Cb = NULL; } pLlcpSocket->pDisonnectContext = NULL; pLlcpSocket->pfSocketRecvFrom_Cb = NULL; pLlcpSocket->pfSocketListen_Cb = NULL; pLlcpSocket->pListenContext = NULL; } static NFCSTATUS phFriNfc_Llcp_Send_ReceiveReady_Frame(phFriNfc_LlcpTransport_Socket_t* pLlcpSocket) { NFCSTATUS status = NFCSTATUS_SUCCESS; /* Test if a send is pending */ if(pLlcpSocket->psTransport->bSendPending == TRUE) { pLlcpSocket->bSocketRRPending = TRUE; status = NFCSTATUS_PENDING; } else { /* Set transport to pending */ pLlcpSocket->psTransport->bSendPending = TRUE; /* Set the header of the RR frame */ pLlcpSocket->sLlcpHeader.dsap = pLlcpSocket->socket_dSap; pLlcpSocket->sLlcpHeader.ptype = PHFRINFC_LLCP_PTYPE_RR; pLlcpSocket->sLlcpHeader.ssap = pLlcpSocket->socket_sSap; /* Set sequence number for RR Frame */ pLlcpSocket->sSequence.ns = 0; pLlcpSocket->sSequence.nr = pLlcpSocket->socket_VR; /* Update VRA */ pLlcpSocket->socket_VRA = (uint8_t)pLlcpSocket->sSequence.nr; /* Store the index of the socket */ pLlcpSocket->psTransport->socketIndex = pLlcpSocket->index; /* Send RR frame */ status = phFriNfc_LlcpTransport_LinkSend(pLlcpSocket->psTransport, &pLlcpSocket->sLlcpHeader, &pLlcpSocket->sSequence, NULL, phFriNfc_LlcpTransport_ConnectionOriented_SendLlcp_CB, pLlcpSocket->psTransport); } return status; } static NFCSTATUS phFriNfc_Llcp_Send_ReceiveNotReady_Frame(phFriNfc_LlcpTransport_Socket_t* pLlcpSocket) { NFCSTATUS status = NFCSTATUS_SUCCESS; /* Test if a send is pending */ if(pLlcpSocket->psTransport->bSendPending == TRUE) { pLlcpSocket->bSocketRNRPending = TRUE; status = NFCSTATUS_PENDING; } else { /* Set transport to pending */ pLlcpSocket->psTransport->bSendPending = TRUE; /* Set the header of the RNR frame */ pLlcpSocket->sLlcpHeader.dsap = pLlcpSocket->socket_dSap; pLlcpSocket->sLlcpHeader.ptype = PHFRINFC_LLCP_PTYPE_RNR; pLlcpSocket->sLlcpHeader.ssap = pLlcpSocket->socket_sSap; /* Set sequence number for RNR Frame */ pLlcpSocket->sSequence.ns = 0x00; pLlcpSocket->sSequence.nr = pLlcpSocket->socket_VR; /* Update VRA */ pLlcpSocket->socket_VRA = (uint8_t)pLlcpSocket->sSequence.nr; /* Store the index of the socket */ pLlcpSocket->psTransport->socketIndex = pLlcpSocket->index; /* Send RNR frame */ status = phFriNfc_LlcpTransport_LinkSend(pLlcpSocket->psTransport, &pLlcpSocket->sLlcpHeader, &pLlcpSocket->sSequence, NULL, phFriNfc_LlcpTransport_ConnectionOriented_SendLlcp_CB, pLlcpSocket->psTransport); } return status; } static NFCSTATUS phFriNfc_Llcp_GetSocket_Params(phNfc_sData_t *psParamsTLV, phNfc_sData_t *psServiceName, uint8_t *pRemoteRW_Size, uint16_t *pRemoteMIU) { NFCSTATUS status = NFCSTATUS_SUCCESS; phNfc_sData_t sValueBuffer; uint32_t offset = 0; uint8_t type; /* Check for NULL pointers */ if ((psParamsTLV == NULL) || (pRemoteRW_Size == NULL) || (pRemoteMIU == NULL)) { return PHNFCSTVAL(CID_FRI_NFC_LLCP, NFCSTATUS_INVALID_PARAMETER); } else { /* Decode TLV */ while (offset < psParamsTLV->length) { status = phFriNfc_Llcp_DecodeTLV(psParamsTLV, &offset, &type,&sValueBuffer); if (status != NFCSTATUS_SUCCESS) { /* Error: Ill-formed TLV */ return status; } switch(type) { case PHFRINFC_LLCP_TLV_TYPE_SN: { /* Test if a SN is present in the TLV */ if(sValueBuffer.length == 0) { /* Error : Ill-formed SN parameter TLV */ break; } /* Get the Service Name */ *psServiceName = sValueBuffer; }break; case PHFRINFC_LLCP_TLV_TYPE_RW: { /* Check length */ if (sValueBuffer.length != PHFRINFC_LLCP_TLV_LENGTH_RW) { /* Error : Ill-formed MIUX parameter TLV */ break; } *pRemoteRW_Size = sValueBuffer.buffer[0]; }break; case PHFRINFC_LLCP_TLV_TYPE_MIUX: { /* Check length */ if (sValueBuffer.length != PHFRINFC_LLCP_TLV_LENGTH_MIUX) { /* Error : Ill-formed MIUX parameter TLV */ break; } *pRemoteMIU = PHFRINFC_LLCP_MIU_DEFAULT + (((sValueBuffer.buffer[0] << 8) | sValueBuffer.buffer[1]) & PHFRINFC_LLCP_TLV_MIUX_MASK); }break; default: { /* Error : Unknown type */ break; } } } } return status; } /* TODO: comment function Handle_ConnectFrame */ static void Handle_ConnectionFrame(phFriNfc_LlcpTransport_t *psTransport, phNfc_sData_t *psData, uint8_t dsap, uint8_t ssap) { NFCSTATUS status = NFCSTATUS_SUCCESS; uint8_t index; uint8_t socketFound = FALSE; phFriNfc_LlcpTransport_Socket_t *pLlcpSocket = NULL; phFriNfc_LlcpTransport_Socket_t *psLocalLlcpSocket = NULL; pphFriNfc_LlcpTransportSocketListenCb_t pListen_Cb = NULL; void *pListenContext = NULL; phNfc_sData_t sServiceName; uint8_t remoteRW = PHFRINFC_LLCP_RW_DEFAULT; uint16_t remoteMIU = PHFRINFC_LLCP_MIU_DEFAULT; status = phFriNfc_Llcp_GetSocket_Params(psData, &sServiceName, &remoteRW, &remoteMIU); if(status != NFCSTATUS_SUCCESS) { /* Incorrect TLV */ /* send FRMR */ status = phFriNfc_LlcpTransport_SendFrameReject(psTransport, dsap, PHFRINFC_LLCP_PTYPE_CONNECT, ssap, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); } else { if(dsap == PHFRINFC_LLCP_SAP_SDP) { /* Search a socket with the SN */ for(index=0;indexpSocketTable[index].bSocketListenPending && (sServiceName.length == psTransport->pSocketTable[index].sServiceName.length) && !memcmp(sServiceName.buffer,psTransport->pSocketTable[index].sServiceName.buffer,sServiceName.length)) { /* socket with the SN found */ socketFound = TRUE; psLocalLlcpSocket = &psTransport->pSocketTable[index]; /* Get the new ssap number, it is the ssap number of the socket found */ dsap = psLocalLlcpSocket->socket_sSap; /* Get the ListenCB of the socket */ pListen_Cb = psLocalLlcpSocket->pfSocketListen_Cb; pListenContext = psLocalLlcpSocket->pListenContext; break; } } } else { /* Search a socket with the DSAP */ for(index=0;indexpSocketTable[index].bSocketListenPending && psTransport->pSocketTable[index].socket_sSap == dsap) { /* socket with the SN found */ socketFound = TRUE; psLocalLlcpSocket = &psTransport->pSocketTable[index]; /* Get the Listen CB and the Context of the socket */ pListen_Cb = psLocalLlcpSocket->pfSocketListen_Cb; pListenContext = psLocalLlcpSocket->pListenContext; break; } } } } /* Test if a socket has beeen found */ if(socketFound) { /* Reset the FLAG socketFound*/ socketFound = FALSE; /* Search a socket free and no socket connect on this DSAP*/ for(index=0;indexpSocketTable[index].eSocket_State == phFriNfc_LlcpTransportSocket_eSocketDefault && socketFound != TRUE) { socketFound = TRUE; psTransport->pSocketTable[index].index = index; psTransport->socketIndex = psTransport->pSocketTable[index].index; /* Create a communication socket */ pLlcpSocket = &psTransport->pSocketTable[index]; /* Set the communication option of the Remote Socket */ pLlcpSocket->remoteMIU = remoteMIU; pLlcpSocket->remoteRW = remoteRW; /* Set SSAP/DSAP of the new socket created for the communication with the remote */ pLlcpSocket->socket_dSap = ssap; pLlcpSocket->socket_sSap = dsap; /* Set the state and the type of the new socket */ pLlcpSocket->eSocket_State = phFriNfc_LlcpTransportSocket_eSocketBound; pLlcpSocket->eSocket_Type = phFriNfc_LlcpTransport_eConnectionOriented; } else if(((psTransport->pSocketTable[index].eSocket_State == phFriNfc_LlcpTransportSocket_eSocketConnected) || (psTransport->pSocketTable[index].eSocket_State == phFriNfc_LlcpTransportSocket_eSocketAccepted)) && ((psTransport->pSocketTable[index].socket_sSap == ssap)&&(psTransport->pSocketTable[index].socket_dSap == dsap))) { socketFound = FALSE; if(pLlcpSocket != NULL) { /* Reset Socket Information */ pLlcpSocket->remoteMIU = 0; pLlcpSocket->remoteRW = 0; /* Set SSAP/DSAP of the new socket created for the communication with the remote */ pLlcpSocket->socket_dSap = 0; pLlcpSocket->socket_sSap = 0; /* Set the state and the type of the new socket */ pLlcpSocket->eSocket_State = phFriNfc_LlcpTransportSocket_eSocketDefault; pLlcpSocket->eSocket_Type = phFriNfc_LlcpTransport_eDefaultType; break; } } } /* Test if a socket has been found */ if(socketFound) { /* Call the Listen CB */ pListen_Cb(pListenContext,pLlcpSocket); } else { /* No more socket are available */ /* Send a DM (0x21) */ status = phFriNfc_LlcpTransport_SendDisconnectMode (psTransport, ssap, dsap, PHFRINFC_LLCP_DM_OPCODE_SOCKET_NOT_AVAILABLE); } } else { /* Service Name not found or Port number not found */ /* Send a DM (0x02) */ status = phFriNfc_LlcpTransport_SendDisconnectMode (psTransport, ssap, dsap, PHFRINFC_LLCP_DM_OPCODE_SAP_NOT_FOUND); } } /* TODO: comment function Handle_ConnectFrame */ static void Handle_ConnectionCompleteFrame(phFriNfc_LlcpTransport_t *psTransport, phNfc_sData_t *psData, uint8_t dsap, uint8_t ssap) { NFCSTATUS status = NFCSTATUS_SUCCESS; uint8_t index; uint8_t remoteRW = PHFRINFC_LLCP_RW_DEFAULT; uint16_t remoteMIU = PHFRINFC_LLCP_MIU_DEFAULT; uint8_t socketFound = FALSE; phFriNfc_LlcpTransport_Socket_t* psLocalLlcpSocket = NULL; status = phFriNfc_Llcp_GetSocket_Params(psData, NULL, &remoteRW, &remoteMIU); if(status != NFCSTATUS_SUCCESS) { /* Incorrect TLV */ /* send FRMR */ status = phFriNfc_LlcpTransport_SendFrameReject(psTransport, dsap, PHFRINFC_LLCP_PTYPE_CC, ssap, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); } else { /* Search a socket in connecting state and with the good SSAP */ for(index=0;indexpSocketTable[index].eSocket_State == phFriNfc_LlcpTransportSocket_eSocketConnecting && psTransport->pSocketTable[index].socket_sSap == dsap) { /* socket with the SN found */ socketFound = TRUE; /* Update the DSAP value with the incomming Socket sSap */ psTransport->pSocketTable[index].socket_dSap = ssap; /* Store a pointer to the socket found */ psLocalLlcpSocket = &psTransport->pSocketTable[index]; break; } } /* Test if a socket has been found */ if(socketFound) { /* Set the socket state to connected */ psLocalLlcpSocket->eSocket_State = phFriNfc_LlcpTransportSocket_eSocketConnected; /* Reset the socket_VS,socket_VR,socket_VSA and socket_VRA variables */ psLocalLlcpSocket->socket_VR = 0; psLocalLlcpSocket->socket_VRA = 0; psLocalLlcpSocket->socket_VS = 0; psLocalLlcpSocket->socket_VSA = 0; /* Store the Remote parameters (MIU,RW) */ psLocalLlcpSocket->remoteMIU = remoteMIU; psLocalLlcpSocket->remoteRW = remoteRW; /* Call the Connect CB and reset callback info */ psLocalLlcpSocket->pfSocketConnect_Cb(psLocalLlcpSocket->pConnectContext,0x00,NFCSTATUS_SUCCESS); psLocalLlcpSocket->pfSocketConnect_Cb = NULL; psLocalLlcpSocket->pConnectContext = NULL; } else { /* No socket Active */ /* CC Frame not handled */ } } } /* TODO: comment function Handle_DisconnectFrame */ static void Handle_DisconnectFrame(phFriNfc_LlcpTransport_t *psTransport, uint8_t dsap, uint8_t ssap) { NFCSTATUS status = NFCSTATUS_SUCCESS; uint8_t index; uint8_t socketFound = FALSE; phFriNfc_LlcpTransport_Socket_t* psLocalLlcpSocket = NULL; /* Search a socket in connected state and the good SSAP */ for(index=0;indexpSocketTable[index].eSocket_State == phFriNfc_LlcpTransportSocket_eSocketConnected && psTransport->pSocketTable[index].socket_sSap == dsap) { /* socket found */ socketFound = TRUE; /* Store a pointer to the socket found */ psLocalLlcpSocket = &psTransport->pSocketTable[index]; break; } } /* Test if a socket has been found */ if(socketFound) { /* Test if a send IFRAME is pending with this socket */ if((psLocalLlcpSocket->bSocketSendPending == TRUE) || (psLocalLlcpSocket->bSocketRecvPending == TRUE)) { /* Call the send CB, a disconnect abort the send request */ if (psLocalLlcpSocket->pfSocketSend_Cb != NULL && psLocalLlcpSocket->bSocketSendPending == TRUE) { /* Copy CB + context in local variables */ pphFriNfc_LlcpTransportSocketSendCb_t pfSendCb = psLocalLlcpSocket->pfSocketSend_Cb; void* pSendContext = psLocalLlcpSocket->pSendContext; /* Reset CB + context */ psLocalLlcpSocket->pfSocketSend_Cb = NULL; psLocalLlcpSocket->pSendContext = NULL; /* Perform callback */ pfSendCb(pSendContext, NFCSTATUS_FAILED); } /* Call the send CB, a disconnect abort the receive request */ if (psLocalLlcpSocket->pfSocketRecv_Cb != NULL && psLocalLlcpSocket->bSocketRecvPending == TRUE) { /* Copy CB + context in local variables */ pphFriNfc_LlcpTransportSocketRecvCb_t pfRecvCb = psLocalLlcpSocket->pfSocketRecv_Cb; void* pRecvContext = psLocalLlcpSocket->pRecvContext; /* Reset CB + context */ psLocalLlcpSocket->pfSocketRecv_Cb = NULL; psLocalLlcpSocket->pRecvContext = NULL; /* Perform callback */ pfRecvCb(pRecvContext, NFCSTATUS_FAILED); } psLocalLlcpSocket->bSocketRecvPending = FALSE; psLocalLlcpSocket->bSocketSendPending = FALSE; } /* Update the socket state */ psLocalLlcpSocket->eSocket_State = phFriNfc_LlcpTransportSocket_eSocketDisconnecting; /* Send a DM*/ /* TODO: use a socket internal flag to save */ status = phFriNfc_LlcpTransport_SendDisconnectMode(psTransport, ssap, dsap, PHFRINFC_LLCP_DM_OPCODE_DISCONNECTED); /* Call ErrCB due to a DISC */ psTransport->pSocketTable[index].pSocketErrCb(psTransport->pSocketTable[index].pContext, PHFRINFC_LLCP_ERR_DISCONNECTED); } else { /* No socket Active */ /* DISC Frame not handled */ } } /* TODO: comment function Handle_ConnectFrame */ static void Handle_DisconnetModeFrame(phFriNfc_LlcpTransport_t *psTransport, phNfc_sData_t *psData, uint8_t dsap, uint8_t ssap) { NFCSTATUS status = NFCSTATUS_SUCCESS; uint8_t index; uint8_t socketFound = FALSE; uint8_t dmOpCode; phFriNfc_LlcpTransport_Socket_t *psLocalLlcpSocket = NULL; /* Test if the DM buffer is correct */ if(psData->length != PHFRINFC_LLCP_DM_LENGTH) { /* send FRMR */ status = phFriNfc_LlcpTransport_SendFrameReject(psTransport, dsap, PHFRINFC_LLCP_PTYPE_DM, ssap, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); } else { /* Search a socket waiting for a DM (Disconnecting State) */ for(index=0;indexpSocketTable[index].eSocket_State == phFriNfc_LlcpTransportSocket_eSocketDisconnecting || psTransport->pSocketTable[index].eSocket_State == phFriNfc_LlcpTransportSocket_eSocketConnecting) && psTransport->pSocketTable[index].socket_sSap == dsap) { /* socket found */ socketFound = TRUE; /* Store a pointer to the socket found */ psLocalLlcpSocket = &psTransport->pSocketTable[index]; break; } } /* Test if a socket has been found */ if(socketFound) { /* Set dmOpcode */ dmOpCode = psData->buffer[0]; switch(dmOpCode) { case PHFRINFC_LLCP_DM_OPCODE_DISCONNECTED: { /* Set the socket state to disconnected */ psLocalLlcpSocket->eSocket_State = phFriNfc_LlcpTransportSocket_eSocketCreated; /* Call Disconnect CB */ if (psLocalLlcpSocket->pfSocketDisconnect_Cb != NULL) { psLocalLlcpSocket->pfSocketDisconnect_Cb(psLocalLlcpSocket->pDisonnectContext,NFCSTATUS_SUCCESS); psLocalLlcpSocket->pfSocketDisconnect_Cb = NULL; } }break; case PHFRINFC_LLCP_DM_OPCODE_CONNECT_REJECTED: case PHFRINFC_LLCP_DM_OPCODE_CONNECT_NOT_ACCEPTED: case PHFRINFC_LLCP_DM_OPCODE_SAP_NOT_ACTIVE: case PHFRINFC_LLCP_DM_OPCODE_SAP_NOT_FOUND: case PHFRINFC_LLCP_DM_OPCODE_SOCKET_NOT_AVAILABLE: { /* Set the socket state to bound */ psLocalLlcpSocket->eSocket_State = phFriNfc_LlcpTransportSocket_eSocketCreated; if(psLocalLlcpSocket->pfSocketConnect_Cb != NULL) { /* Call Connect CB */ psLocalLlcpSocket->pfSocketConnect_Cb(psLocalLlcpSocket->pConnectContext,dmOpCode,NFCSTATUS_FAILED); psLocalLlcpSocket->pfSocketConnect_Cb = NULL; } }break; } } } } /* TODO: comment function Handle_Receive_IFrame */ static void Handle_Receive_IFrame(phFriNfc_LlcpTransport_t *psTransport, phNfc_sData_t *psData, uint8_t dsap, uint8_t ssap) { NFCSTATUS status = NFCSTATUS_SUCCESS; phFriNfc_LlcpTransport_Socket_t* psLocalLlcpSocket = NULL; phFriNfc_Llcp_sPacketSequence_t sLlcpLocalSequence; uint32_t dataLengthAvailable = 0; uint32_t dataLengthWrite = 0; uint8_t index; uint8_t socketFound = FALSE; uint8_t WFlag = 0; uint8_t IFlag = 0; uint8_t RFlag = 0; uint8_t SFlag = 0; uint8_t nr_val; uint32_t offset = 0; uint32_t rw_offset; /* Get NS and NR Value of the I Frame*/ phFriNfc_Llcp_Buffer2Sequence( psData->buffer, offset, &sLlcpLocalSequence); /* Update the buffer pointer */ psData->buffer = psData->buffer + PHFRINFC_LLCP_PACKET_SEQUENCE_SIZE; /* Update the length value (without the header length) */ psData->length = psData->length - PHFRINFC_LLCP_PACKET_SEQUENCE_SIZE; /* Search a socket waiting for an I FRAME (Connected State) */ for(index=0;indexpSocketTable[index].eSocket_State == phFriNfc_LlcpTransportSocket_eSocketConnected) || (psTransport->pSocketTable[index].eSocket_State == phFriNfc_LlcpTransportSocket_eSocketAccepted)) && psTransport->pSocketTable[index].socket_sSap == dsap && psTransport->pSocketTable[index].socket_dSap == ssap) { /* socket found */ socketFound = TRUE; /* Store a pointer to the socket found */ psLocalLlcpSocket = &psTransport->pSocketTable[index]; break; } } /* Test if a socket has been found */ if(socketFound) { /* Test NS */ /*if(sLlcpLocalSequence.ns != psLocalLlcpSocket->socket_VR) { SFlag = TRUE; }*/ /* Calculate offset of current frame in RW, and check validity */ if(sLlcpLocalSequence.ns >= psLocalLlcpSocket->socket_VRA) { rw_offset = sLlcpLocalSequence.ns - psLocalLlcpSocket->socket_VRA; } else { rw_offset = 16 - (psLocalLlcpSocket->socket_VRA - sLlcpLocalSequence.ns); } if(rw_offset >= psLocalLlcpSocket->localRW) { /* FRMR 0x01 */ SFlag = TRUE; } /* Check Info length */ if(psData->length > (uint32_t)(psLocalLlcpSocket->localMIUX + PHFRINFC_LLCP_MIU_DEFAULT)) { IFlag = TRUE; } /* Test NR */ nr_val = (uint8_t)sLlcpLocalSequence.nr; do { if(nr_val == psLocalLlcpSocket->socket_VS) { break; } nr_val = (nr_val+1)%16; if(nr_val == psLocalLlcpSocket->socket_VSA) { /* FRMR 0x02 */ RFlag = TRUE; break; } }while(nr_val != sLlcpLocalSequence.nr); if( WFlag != 0 || IFlag != 0 || RFlag != 0 || SFlag != 0) { /* Send FRMR */ status = phFriNfc_LlcpTransport_SendFrameReject(psTransport, dsap, PHFRINFC_LLCP_PTYPE_I, ssap, &sLlcpLocalSequence, WFlag, IFlag, RFlag, SFlag, psLocalLlcpSocket->socket_VS, psLocalLlcpSocket->socket_VSA, psLocalLlcpSocket->socket_VR, psLocalLlcpSocket->socket_VRA); } else { /* Update VSA */ psLocalLlcpSocket->socket_VSA = (uint8_t)sLlcpLocalSequence.nr; /* Test if the Linear Buffer length is null */ if(psLocalLlcpSocket->bufferLinearLength == 0) { /* Test if a Receive is pending and RW empty */ if(psLocalLlcpSocket->bSocketRecvPending == TRUE && (psLocalLlcpSocket->indexRwWrite == psLocalLlcpSocket->indexRwRead)) { /* Reset Flag */ psLocalLlcpSocket->bSocketRecvPending = FALSE; /* Save I_FRAME into the Receive Buffer */ memcpy(psLocalLlcpSocket->sSocketRecvBuffer->buffer,psData->buffer,psData->length); psLocalLlcpSocket->sSocketRecvBuffer->length = psData->length; /* Update VR */ psLocalLlcpSocket->socket_VR = (psLocalLlcpSocket->socket_VR+1)%16; /* Call the Receive CB */ psLocalLlcpSocket->pfSocketRecv_Cb(psLocalLlcpSocket->pRecvContext, NFCSTATUS_SUCCESS); psLocalLlcpSocket->pfSocketRecv_Cb = NULL; /* Test if a send is pending with this socket */ if(psLocalLlcpSocket->bSocketSendPending == TRUE && CHECK_SEND_RW(psLocalLlcpSocket)) { /* Test if a send is pending at LLC layer */ if(psTransport->bSendPending != TRUE) { status = static_performSendInfo(psLocalLlcpSocket); } } else { /* RR */ status = phFriNfc_Llcp_Send_ReceiveReady_Frame(psLocalLlcpSocket); } } else { /* Test if RW is full */ if((psLocalLlcpSocket->indexRwWrite - psLocalLlcpSocket->indexRwRead)localRW) { if(psLocalLlcpSocket->sSocketRwBufferTable[(psLocalLlcpSocket->indexRwWrite%psLocalLlcpSocket->localRW)].length == 0) { /* Save I_FRAME into the RW Buffers */ memcpy(psLocalLlcpSocket->sSocketRwBufferTable[(psLocalLlcpSocket->indexRwWrite%psLocalLlcpSocket->localRW)].buffer,psData->buffer,psData->length); psLocalLlcpSocket->sSocketRwBufferTable[(psLocalLlcpSocket->indexRwWrite%psLocalLlcpSocket->localRW)].length = psData->length; if(psLocalLlcpSocket->ReceiverBusyCondition != TRUE) { /* Receiver Busy condition */ psLocalLlcpSocket->ReceiverBusyCondition = TRUE; /* Send RNR */ status = phFriNfc_Llcp_Send_ReceiveNotReady_Frame(psLocalLlcpSocket); } /* Update the RW write index */ psLocalLlcpSocket->indexRwWrite++; } } } } else { /* Copy the buffer into the RW buffer */ memcpy(psLocalLlcpSocket->sSocketRwBufferTable[(psLocalLlcpSocket->indexRwWrite%psLocalLlcpSocket->localRW)].buffer,psData->buffer,psData->length); /* Update the length */ psLocalLlcpSocket->sSocketRwBufferTable[(psLocalLlcpSocket->indexRwWrite%psLocalLlcpSocket->localRW)].length = psData->length; /* Test the length of the available place in the linear buffer */ dataLengthAvailable = phFriNfc_Llcp_CyclicFifoAvailable(&psLocalLlcpSocket->sCyclicFifoBuffer); if(dataLengthAvailable >= psLocalLlcpSocket->sSocketRwBufferTable[(psLocalLlcpSocket->indexRwWrite%psLocalLlcpSocket->localRW)].length) { /* Store Data into the linear buffer */ dataLengthWrite = phFriNfc_Llcp_CyclicFifoWrite(&psLocalLlcpSocket->sCyclicFifoBuffer, psLocalLlcpSocket->sSocketRwBufferTable[(psLocalLlcpSocket->indexRwWrite%psLocalLlcpSocket->localRW)].buffer, psLocalLlcpSocket->sSocketRwBufferTable[(psLocalLlcpSocket->indexRwWrite%psLocalLlcpSocket->localRW)].length); /* Update VR */ psLocalLlcpSocket->socket_VR = (psLocalLlcpSocket->socket_VR+1)%16; /* Update the length */ psLocalLlcpSocket->sSocketRwBufferTable[(psLocalLlcpSocket->indexRwWrite%psLocalLlcpSocket->localRW)].length = 0x00; /* Test if a Receive Pending*/ if(psLocalLlcpSocket->bSocketRecvPending == TRUE) { /* Reset Flag */ psLocalLlcpSocket->bSocketRecvPending = FALSE; phFriNfc_LlcpTransport_ConnectionOriented_Recv(psLocalLlcpSocket, psLocalLlcpSocket->sSocketRecvBuffer, psLocalLlcpSocket->pfSocketRecv_Cb, psLocalLlcpSocket->pRecvContext); } /* Test if a send is pending with this socket */ if((psLocalLlcpSocket->bSocketSendPending == TRUE) && CHECK_SEND_RW(psLocalLlcpSocket)) { /* Test if a send is pending at LLC layer */ if(psTransport->bSendPending != TRUE) { status = static_performSendInfo(psLocalLlcpSocket); } } else { /* RR */ status = phFriNfc_Llcp_Send_ReceiveReady_Frame(psLocalLlcpSocket); } } else { if(psLocalLlcpSocket->ReceiverBusyCondition != TRUE) { /* Receiver Busy condition */ psLocalLlcpSocket->ReceiverBusyCondition = TRUE; /* Send RNR */ status = phFriNfc_Llcp_Send_ReceiveNotReady_Frame(psLocalLlcpSocket); } /* Update the RW write index */ psLocalLlcpSocket->indexRwWrite++; } } } } else { /* No active socket*/ /* I FRAME not Handled */ } } static void Handle_ReceiveReady_Frame(phFriNfc_LlcpTransport_t *psTransport, phNfc_sData_t *psData, uint8_t dsap, uint8_t ssap) { NFCSTATUS status = NFCSTATUS_SUCCESS; uint8_t index; uint8_t socketFound = FALSE; uint8_t WFlag = 0; uint8_t IFlag = 0; uint8_t RFlag = 0; uint8_t SFlag = 0; uint32_t offset = 0; uint8_t nr_val; phFriNfc_LlcpTransport_Socket_t* psLocalLlcpSocket = NULL; phFriNfc_Llcp_sPacketSequence_t sLlcpLocalSequence; /* Get NS and NR Value of the I Frame*/ phFriNfc_Llcp_Buffer2Sequence( psData->buffer, offset, &sLlcpLocalSequence); /* Search a socket waiting for an RR FRAME (Connected State) */ for(index=0;indexpSocketTable[index].eSocket_State == phFriNfc_LlcpTransportSocket_eSocketConnected && psTransport->pSocketTable[index].socket_sSap == dsap && psTransport->pSocketTable[index].socket_dSap == ssap) { /* socket found */ socketFound = TRUE; /* Store a pointer to the socket found */ psLocalLlcpSocket = &psTransport->pSocketTable[index]; psLocalLlcpSocket->index = psTransport->pSocketTable[index].index; break; } } /* Test if a socket has been found */ if(socketFound) { /* Test NR */ nr_val = (uint8_t)sLlcpLocalSequence.nr; do { if(nr_val == psLocalLlcpSocket->socket_VS) { break; } nr_val = (nr_val+1)%16; if(nr_val == psLocalLlcpSocket->socket_VSA) { RFlag = TRUE; break; } }while(nr_val != sLlcpLocalSequence.nr); /* Test if Info field present */ if(psData->length > 1) { WFlag = TRUE; IFlag = TRUE; } if (WFlag || IFlag || RFlag || SFlag) { /* Send FRMR */ status = phFriNfc_LlcpTransport_SendFrameReject(psTransport, dsap, PHFRINFC_LLCP_PTYPE_RR, ssap, &sLlcpLocalSequence, WFlag, IFlag, RFlag, SFlag, psLocalLlcpSocket->socket_VS, psLocalLlcpSocket->socket_VSA, psLocalLlcpSocket->socket_VR, psLocalLlcpSocket->socket_VRA); } else { /* Test Receiver Busy condition */ if(psLocalLlcpSocket->RemoteBusyConditionInfo == TRUE) { /* Notify the upper layer */ psLocalLlcpSocket->pSocketErrCb(psLocalLlcpSocket->pContext,PHFRINFC_LLCP_ERR_NOT_BUSY_CONDITION); psLocalLlcpSocket->RemoteBusyConditionInfo = FALSE; } /* Update VSA */ psLocalLlcpSocket->socket_VSA = (uint8_t)sLlcpLocalSequence.nr; /* Test if a send is pendind */ if(psLocalLlcpSocket->bSocketSendPending == TRUE) { /* Test the RW window */ if(CHECK_SEND_RW(psLocalLlcpSocket)) { /* Test if a send is pending at LLC layer */ if(psTransport->bSendPending != TRUE) { status = static_performSendInfo(psLocalLlcpSocket); } } } } } else { /* No active socket*/ /* RR Frame not handled*/ } } static void Handle_ReceiveNotReady_Frame(phFriNfc_LlcpTransport_t *psTransport, phNfc_sData_t *psData, uint8_t dsap, uint8_t ssap) { NFCSTATUS status = NFCSTATUS_SUCCESS; uint8_t index; uint8_t socketFound = FALSE; bool_t bWFlag = 0; bool_t bIFlag = 0; bool_t bRFlag = 0; bool_t bSFlag = 0; uint32_t offset = 0; uint8_t nr_val; phFriNfc_LlcpTransport_Socket_t* psLocalLlcpSocket = NULL; phFriNfc_Llcp_sPacketSequence_t sLlcpLocalSequence; /* Get NS and NR Value of the I Frame*/ phFriNfc_Llcp_Buffer2Sequence( psData->buffer, offset, &sLlcpLocalSequence); /* Search a socket waiting for an RNR FRAME (Connected State) */ for(index=0;indexpSocketTable[index].eSocket_State == phFriNfc_LlcpTransportSocket_eSocketConnected && psTransport->pSocketTable[index].socket_sSap == dsap && psTransport->pSocketTable[index].socket_dSap == ssap) { /* socket found */ socketFound = TRUE; /* Store a pointer to the socket found */ psLocalLlcpSocket = &psTransport->pSocketTable[index]; break; } } /* Test if a socket has been found */ if(socketFound) { /* Test NR */ nr_val = (uint8_t)sLlcpLocalSequence.nr; do { if(nr_val == psLocalLlcpSocket->socket_VS) { break; } nr_val = (nr_val+1)%16; if(nr_val == psLocalLlcpSocket->socket_VSA) { /* FRMR 0x02 */ bRFlag = TRUE; break; } }while(nr_val != sLlcpLocalSequence.nr); /* Test if Info field present */ if(psData->length > 1) { /* Send FRMR */ bWFlag = TRUE; bIFlag = TRUE; } if( bWFlag != 0 || bIFlag != 0 || bRFlag != 0 || bSFlag != 0) { /* Send FRMR */ status = phFriNfc_LlcpTransport_SendFrameReject(psTransport, dsap, PHFRINFC_LLCP_PTYPE_RNR, ssap, &sLlcpLocalSequence, bWFlag, bIFlag, bRFlag, bSFlag, psLocalLlcpSocket->socket_VS, psLocalLlcpSocket->socket_VSA, psLocalLlcpSocket->socket_VR, psLocalLlcpSocket->socket_VRA); } else { /* Notify the upper layer */ psLocalLlcpSocket->pSocketErrCb(psTransport->pSocketTable[index].pContext,PHFRINFC_LLCP_ERR_BUSY_CONDITION); psLocalLlcpSocket->RemoteBusyConditionInfo = TRUE; /* Update VSA */ psLocalLlcpSocket->socket_VSA = (uint8_t)sLlcpLocalSequence.nr; /* Test if a send is pendind */ if(psLocalLlcpSocket->bSocketSendPending == TRUE && CHECK_SEND_RW(psLocalLlcpSocket)) { /* Test if a send is pending at LLC layer */ if(psTransport->bSendPending != TRUE) { status = static_performSendInfo(psLocalLlcpSocket); } } } } else { /* No active socket*/ /* RNR Frame not handled*/ } } static void Handle_FrameReject_Frame(phFriNfc_LlcpTransport_t *psTransport, uint8_t dsap, uint8_t ssap) { NFCSTATUS status = NFCSTATUS_SUCCESS; uint8_t index; uint8_t socketFound = FALSE; /* Search a socket waiting for a FRAME */ for(index=0;indexpSocketTable[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_eSocketDisconnected; /* 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]); } else { /* No active socket*/ /* FRMR Frame not handled*/ } } /* TODO: comment function Handle_ConnectionOriented_IncommingFrame */ void Handle_ConnectionOriented_IncommingFrame(phFriNfc_LlcpTransport_t *psTransport, phNfc_sData_t *psData, uint8_t dsap, uint8_t ptype, uint8_t ssap) { phFriNfc_Llcp_sPacketSequence_t sSequence = {0,0}; switch(ptype) { case PHFRINFC_LLCP_PTYPE_CONNECT: { Handle_ConnectionFrame(psTransport, psData, dsap, ssap); }break; case PHFRINFC_LLCP_PTYPE_DISC: { Handle_DisconnectFrame(psTransport, dsap, ssap); }break; case PHFRINFC_LLCP_PTYPE_CC: { Handle_ConnectionCompleteFrame(psTransport, psData, dsap, ssap); }break; case PHFRINFC_LLCP_PTYPE_DM: { Handle_DisconnetModeFrame(psTransport, psData, dsap, ssap); }break; case PHFRINFC_LLCP_PTYPE_FRMR: { Handle_FrameReject_Frame(psTransport, dsap, ssap); }break; case PHFRINFC_LLCP_PTYPE_I: { Handle_Receive_IFrame(psTransport, psData, dsap, ssap); }break; case PHFRINFC_LLCP_PTYPE_RR: { Handle_ReceiveReady_Frame(psTransport, psData, dsap, ssap); }break; case PHFRINFC_LLCP_PTYPE_RNR: { Handle_ReceiveNotReady_Frame(psTransport, psData, dsap, ssap); }break; case PHFRINFC_LLCP_PTYPE_RESERVED1: case PHFRINFC_LLCP_PTYPE_RESERVED2: case PHFRINFC_LLCP_PTYPE_RESERVED3: { phFriNfc_LlcpTransport_SendFrameReject( psTransport, dsap, ptype, ssap, &sSequence, TRUE, FALSE, FALSE, FALSE, 0, 0, 0, 0); }break; } } /** * \ingroup grp_lib_nfc * \brief Get the local options of a socket. * * 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_ConnectionOriented_SocketGetLocalOptions(phFriNfc_LlcpTransport_Socket_t *pLlcpSocket, phLibNfc_Llcp_sSocketOptions_t *psLocalOptions) { NFCSTATUS status = NFCSTATUS_SUCCESS; /* Get Local MIUX */ psLocalOptions->miu = pLlcpSocket->sSocketOption.miu; /* Get Local Receive Window */ psLocalOptions->rw = pLlcpSocket->sSocketOption.rw; return status; } /** * \ingroup grp_lib_nfc * \brief Get the local options of a socket. * * 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_ConnectionOriented_SocketGetRemoteOptions(phFriNfc_LlcpTransport_Socket_t* pLlcpSocket, phLibNfc_Llcp_sSocketOptions_t* psRemoteOptions) { NFCSTATUS status = NFCSTATUS_SUCCESS; /* Get Remote MIUX */ psRemoteOptions->miu = pLlcpSocket->remoteMIU; /* Get Remote Receive Window */ psRemoteOptions->rw = pLlcpSocket->remoteRW; return status; } /** * \ingroup grp_fri_nfc * \brief Listen for incoming connection requests on a socket. * * 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_ConnectionOriented_Listen(phFriNfc_LlcpTransport_Socket_t* pLlcpSocket, pphFriNfc_LlcpTransportSocketListenCb_t pListen_Cb, void* pContext) { NFCSTATUS status = NFCSTATUS_SUCCESS; uint8_t index; /* Store the listen callback */ pLlcpSocket->pfSocketListen_Cb = pListen_Cb; /* store the context */ pLlcpSocket->pListenContext = pContext; /* Set RecvPending to TRUE */ pLlcpSocket->bSocketListenPending = TRUE; /* Set the socket state*/ pLlcpSocket->eSocket_State = phFriNfc_LlcpTransportSocket_eSocketRegistered; return status; } /** * \ingroup grp_fri_nfc * \brief Accept an incoming connection request for a socket. * * 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] pAccept_RspCb The callback to be called when the Accept 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_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_ConnectionOriented_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; uint32_t offset = 0; uint8_t miux[2]; uint8_t i; /* Store the options in the socket */ memcpy(&pLlcpSocket->sSocketOption, psOptions, sizeof(phFriNfc_LlcpTransport_sSocketOptions_t)); /* Set socket local params (MIUX & RW) */ pLlcpSocket ->localMIUX = (pLlcpSocket->sSocketOption.miu - PHFRINFC_LLCP_MIU_DEFAULT) & PHFRINFC_LLCP_TLV_MIUX_MASK; pLlcpSocket ->localRW = pLlcpSocket->sSocketOption.rw & PHFRINFC_LLCP_TLV_RW_MASK; /* Set the pointer and the length for the Receive Window Buffer */ for(i=0;ilocalRW;i++) { pLlcpSocket->sSocketRwBufferTable[i].buffer = psWorkingBuffer->buffer + (i*pLlcpSocket->sSocketOption.miu); pLlcpSocket->sSocketRwBufferTable[i].length = 0; } /* Set the pointer and the length for the Send Buffer */ pLlcpSocket->sSocketSendBuffer.buffer = psWorkingBuffer->buffer + pLlcpSocket->bufferRwMaxLength; pLlcpSocket->sSocketSendBuffer.length = pLlcpSocket->bufferSendMaxLength; /* Set the pointer and the length for the Linear Buffer */ pLlcpSocket->sSocketLinearBuffer.buffer = psWorkingBuffer->buffer + pLlcpSocket->bufferRwMaxLength + pLlcpSocket->bufferSendMaxLength; pLlcpSocket->sSocketLinearBuffer.length = pLlcpSocket->bufferLinearLength; if(pLlcpSocket->sSocketLinearBuffer.length != 0) { /* Init Cyclic Fifo */ phFriNfc_Llcp_CyclicFifoInit(&pLlcpSocket->sCyclicFifoBuffer, pLlcpSocket->sSocketLinearBuffer.buffer, pLlcpSocket->sSocketLinearBuffer.length); } pLlcpSocket->pSocketErrCb = pErr_Cb; pLlcpSocket->pContext = pContext; /* store the pointer to the Accept callback */ pLlcpSocket->pfSocketAccept_Cb = pAccept_RspCb; pLlcpSocket->pAcceptContext = pContext; /* Reset the socket_VS,socket_VR,socket_VSA and socket_VRA variables */ pLlcpSocket->socket_VR = 0; pLlcpSocket->socket_VRA = 0; pLlcpSocket->socket_VS = 0; pLlcpSocket->socket_VSA = 0; /* MIUX */ if(pLlcpSocket->localMIUX != PHFRINFC_LLCP_MIUX_DEFAULT) { /* Encode MIUX value */ phFriNfc_Llcp_EncodeMIUX(pLlcpSocket->localMIUX, miux); /* Encode MIUX in TLV format */ status = phFriNfc_Llcp_EncodeTLV(&pLlcpSocket->sSocketSendBuffer, &offset, PHFRINFC_LLCP_TLV_TYPE_MIUX, PHFRINFC_LLCP_TLV_LENGTH_MIUX, miux); if(status != NFCSTATUS_SUCCESS) { /* Call the CB */ status = PHNFCSTVAL(CID_FRI_NFC_LLCP_TRANSPORT, NFCSTATUS_FAILED); goto clean_and_return; } } /* Receive Window */ if(pLlcpSocket->sSocketOption.rw != PHFRINFC_LLCP_RW_DEFAULT) { /* Encode RW value */ phFriNfc_Llcp_EncodeRW(&pLlcpSocket->sSocketOption.rw); /* Encode RW in TLV format */ status = phFriNfc_Llcp_EncodeTLV(&pLlcpSocket->sSocketSendBuffer, &offset, PHFRINFC_LLCP_TLV_TYPE_RW, PHFRINFC_LLCP_TLV_LENGTH_RW, &pLlcpSocket->sSocketOption.rw); if(status != NFCSTATUS_SUCCESS) { /* Call the CB */ status = PHNFCSTVAL(CID_FRI_NFC_LLCP_TRANSPORT, NFCSTATUS_FAILED); goto clean_and_return; } } /* Test if a send is pending */ if(pLlcpSocket->psTransport->bSendPending == TRUE) { pLlcpSocket->bSocketAcceptPending = TRUE; /* Update Send Buffer length value */ pLlcpSocket->sSocketSendBuffer.length = offset; status = NFCSTATUS_PENDING; } else { /* Fill the psLlcpHeader stuture with the DSAP,CC PTYPE and the SSAP */ pLlcpSocket->sLlcpHeader.dsap = pLlcpSocket->socket_dSap; pLlcpSocket->sLlcpHeader.ptype = PHFRINFC_LLCP_PTYPE_CC; pLlcpSocket->sLlcpHeader.ssap = pLlcpSocket->socket_sSap; /* Set the socket state to accepted */ pLlcpSocket->eSocket_State = phFriNfc_LlcpTransportSocket_eSocketAccepted; /* Update Send Buffer length value */ pLlcpSocket->sSocketSendBuffer.length = offset; /* Store the index of the socket */ pLlcpSocket->psTransport->socketIndex = pLlcpSocket->index; /* Send a CC Frame */ status = phFriNfc_LlcpTransport_LinkSend(pLlcpSocket->psTransport, &pLlcpSocket->sLlcpHeader, NULL, &pLlcpSocket->sSocketSendBuffer, phFriNfc_LlcpTransport_ConnectionOriented_SendLlcp_CB, pLlcpSocket->psTransport); } clean_and_return: if(status != NFCSTATUS_PENDING) { LLCP_PRINT("Release Accept callback"); pLlcpSocket->pfSocketAccept_Cb = NULL; pLlcpSocket->pAcceptContext = NULL; } return status; } /** * \ingroup grp_fri_nfc * \brief Reject an incoming connection request for a socket. * * 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. * * \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 phLibNfc_LlcpTransport_ConnectionOriented_Reject( phFriNfc_LlcpTransport_Socket_t* pLlcpSocket, pphFriNfc_LlcpTransportSocketRejectCb_t pReject_RspCb, void *pContext) { NFCSTATUS status = NFCSTATUS_SUCCESS; /* Set the state of the socket */ pLlcpSocket->eSocket_State = phFriNfc_LlcpTransportSocket_eSocketRejected; /* Store the Reject callback */ pLlcpSocket->pfSocketSend_Cb = pReject_RspCb; pLlcpSocket->pRejectContext = pContext; /* Store the index of the socket */ pLlcpSocket->psTransport->socketIndex = pLlcpSocket->index; /* Send a DM*/ status = phFriNfc_LlcpTransport_SendDisconnectMode(pLlcpSocket->psTransport, pLlcpSocket->socket_dSap, pLlcpSocket->socket_sSap, PHFRINFC_LLCP_DM_OPCODE_CONNECT_REJECTED); return status; } /** * \ingroup grp_fri_nfc * \brief Try to establish connection with a socket on a remote SAP. * * 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] 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_FAILED Operation failed. */ NFCSTATUS phFriNfc_LlcpTransport_ConnectionOriented_Connect( phFriNfc_LlcpTransport_Socket_t* pLlcpSocket, uint8_t nSap, phNfc_sData_t* psUri, pphFriNfc_LlcpTransportSocketConnectCb_t pConnect_RspCb, void* pContext) { NFCSTATUS status = NFCSTATUS_SUCCESS; uint32_t offset = 0; uint8_t miux[2]; /* Test if a nSap is present */ if(nSap != PHFRINFC_LLCP_SAP_DEFAULT) { /* Set DSAP port number with the nSap value */ pLlcpSocket->socket_dSap = nSap; } else { /* Set DSAP port number with the SDP port number */ pLlcpSocket->socket_dSap = PHFRINFC_LLCP_SAP_SDP; } /* Store the Connect callback and context */ pLlcpSocket->pfSocketConnect_Cb = pConnect_RspCb; pLlcpSocket->pConnectContext = pContext; /* Set the socket Header */ pLlcpSocket->sLlcpHeader.dsap = pLlcpSocket->socket_dSap; pLlcpSocket->sLlcpHeader.ptype = PHFRINFC_LLCP_PTYPE_CONNECT; pLlcpSocket->sLlcpHeader.ssap = pLlcpSocket->socket_sSap; /* MIUX */ if(pLlcpSocket->localMIUX != PHFRINFC_LLCP_MIUX_DEFAULT) { /* Encode MIUX value */ phFriNfc_Llcp_EncodeMIUX(pLlcpSocket->localMIUX, miux); /* Encode MIUX in TLV format */ status = phFriNfc_Llcp_EncodeTLV(&pLlcpSocket->sSocketSendBuffer, &offset, PHFRINFC_LLCP_TLV_TYPE_MIUX, PHFRINFC_LLCP_TLV_LENGTH_MIUX, miux); if(status != NFCSTATUS_SUCCESS) { status = PHNFCSTVAL(CID_FRI_NFC_LLCP_TRANSPORT, NFCSTATUS_FAILED); goto clean_and_return; } } /* Receive Window */ if(pLlcpSocket->sSocketOption.rw != PHFRINFC_LLCP_RW_DEFAULT) { /* Encode RW value */ phFriNfc_Llcp_EncodeRW(&pLlcpSocket->sSocketOption.rw); /* Encode RW in TLV format */ status = phFriNfc_Llcp_EncodeTLV(&pLlcpSocket->sSocketSendBuffer, &offset, PHFRINFC_LLCP_TLV_TYPE_RW, PHFRINFC_LLCP_TLV_LENGTH_RW, &pLlcpSocket->sSocketOption.rw); if(status != NFCSTATUS_SUCCESS) { status = PHNFCSTVAL(CID_FRI_NFC_LLCP_TRANSPORT, NFCSTATUS_FAILED); goto clean_and_return; } } /* Test if a Service Name is present */ if(psUri != NULL) { /* Encode SN in TLV format */ status = phFriNfc_Llcp_EncodeTLV(&pLlcpSocket->sSocketSendBuffer, &offset, PHFRINFC_LLCP_TLV_TYPE_SN, (uint8_t)psUri->length, psUri->buffer); if(status != NFCSTATUS_SUCCESS) { status = PHNFCSTVAL(CID_FRI_NFC_LLCP_TRANSPORT, NFCSTATUS_FAILED); goto clean_and_return; } } /* Test if a send is pending */ if(pLlcpSocket->psTransport->bSendPending == TRUE) { pLlcpSocket->bSocketConnectPending = TRUE; /* Update Send Buffer length value */ pLlcpSocket->sSocketSendBuffer.length = offset; status = NFCSTATUS_PENDING; } else { /* Update Send Buffer length value */ pLlcpSocket->sSocketSendBuffer.length = offset; /* Set the socket in connecting state */ pLlcpSocket->eSocket_State = phFriNfc_LlcpTransportSocket_eSocketConnecting; /* Store the index of the socket */ pLlcpSocket->psTransport->socketIndex = pLlcpSocket->index; status = phFriNfc_LlcpTransport_LinkSend(pLlcpSocket->psTransport, &pLlcpSocket->sLlcpHeader, NULL, &pLlcpSocket->sSocketSendBuffer, phFriNfc_LlcpTransport_ConnectionOriented_SendLlcp_CB, pLlcpSocket->psTransport); } clean_and_return: if(status != NFCSTATUS_PENDING) { LLCP_PRINT("Release Connect callback"); pLlcpSocket->pfSocketConnect_Cb = NULL; pLlcpSocket->pConnectContext = NULL; } return status; } /** * \ingroup grp_lib_nfc * \brief Disconnect a currently connected socket. * * 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 phLibNfc_LlcpTransport_ConnectionOriented_Disconnect(phFriNfc_LlcpTransport_Socket_t* pLlcpSocket, pphLibNfc_LlcpSocketDisconnectCb_t pDisconnect_RspCb, void* pContext) { NFCSTATUS status = NFCSTATUS_SUCCESS; /* Store the Disconnect callback and context*/ pLlcpSocket->pfSocketDisconnect_Cb = pDisconnect_RspCb; pLlcpSocket->pDisonnectContext = pContext; /* Set the socket in connecting state */ pLlcpSocket->eSocket_State = phFriNfc_LlcpTransportSocket_eSocketDisconnecting; /* Test if a send IFRAME is pending with this socket */ if((pLlcpSocket->bSocketSendPending == TRUE) || (pLlcpSocket->bSocketRecvPending == TRUE)) { pLlcpSocket->bSocketSendPending = FALSE; pLlcpSocket->bSocketRecvPending = FALSE; /* Call the send CB, a disconnect abort the send request */ if (pLlcpSocket->pfSocketSend_Cb != NULL) { /* Copy CB + context in local variables */ pphFriNfc_LlcpTransportSocketSendCb_t pfSendCb = pLlcpSocket->pfSocketSend_Cb; void* pSendContext = pLlcpSocket->pSendContext; /* Reset CB + context */ pLlcpSocket->pfSocketSend_Cb = NULL; pLlcpSocket->pSendContext = NULL; /* Perform callback */ pfSendCb(pSendContext, NFCSTATUS_FAILED); } /* Call the send CB, a disconnect abort the receive request */ if (pLlcpSocket->pfSocketRecv_Cb != NULL) { /* Copy CB + context in local variables */ pphFriNfc_LlcpTransportSocketRecvCb_t pfRecvCb = pLlcpSocket->pfSocketRecv_Cb; void* pRecvContext = pLlcpSocket->pRecvContext; /* Reset CB + context */ pLlcpSocket->pfSocketRecv_Cb = NULL; pLlcpSocket->pRecvContext = NULL; /* Perform callback */ pfRecvCb(pRecvContext, NFCSTATUS_FAILED); } } /* Set the socket Header */ pLlcpSocket->sLlcpHeader.dsap = pLlcpSocket->socket_dSap; pLlcpSocket->sLlcpHeader.ptype = PHFRINFC_LLCP_PTYPE_DISC; pLlcpSocket->sLlcpHeader.ssap = pLlcpSocket->socket_sSap; /* Test if a send is pending */ if( pLlcpSocket->psTransport->bSendPending == TRUE) { pLlcpSocket->bSocketDiscPending = TRUE; status = NFCSTATUS_PENDING; } else { /* Store the index of the socket */ pLlcpSocket->psTransport->socketIndex = pLlcpSocket->index; status = phFriNfc_LlcpTransport_LinkSend(pLlcpSocket->psTransport, &pLlcpSocket->sLlcpHeader, NULL, NULL, phFriNfc_LlcpTransport_ConnectionOriented_SendLlcp_CB, pLlcpSocket->psTransport); if(status != NFCSTATUS_PENDING) { LLCP_PRINT("Release Disconnect callback"); pLlcpSocket->pfSocketConnect_Cb = NULL; pLlcpSocket->pConnectContext = NULL; } } return status; } /* TODO: comment function phFriNfc_LlcpTransport_Connectionless_SendTo_CB */ static void phFriNfc_LlcpTransport_ConnectionOriented_DisconnectClose_CB(void* pContext, NFCSTATUS status) { phFriNfc_LlcpTransport_Socket_t *pLlcpSocket = (phFriNfc_LlcpTransport_Socket_t*)pContext; if(status == NFCSTATUS_SUCCESS) { /* Reset the pointer to the socket closed */ pLlcpSocket->eSocket_State = phFriNfc_LlcpTransportSocket_eSocketDefault; pLlcpSocket->eSocket_Type = phFriNfc_LlcpTransport_eDefaultType; pLlcpSocket->pContext = NULL; pLlcpSocket->pSocketErrCb = NULL; pLlcpSocket->socket_sSap = PHFRINFC_LLCP_SAP_DEFAULT; pLlcpSocket->socket_dSap = PHFRINFC_LLCP_SAP_DEFAULT; pLlcpSocket->bSocketRecvPending = FALSE; pLlcpSocket->bSocketSendPending = FALSE; pLlcpSocket->bSocketListenPending = FALSE; pLlcpSocket->bSocketDiscPending = FALSE; pLlcpSocket->socket_VS = 0; pLlcpSocket->socket_VSA = 0; pLlcpSocket->socket_VR = 0; pLlcpSocket->socket_VRA = 0; pLlcpSocket->indexRwRead = 0; pLlcpSocket->indexRwWrite = 0; phFriNfc_LlcpTransport_ConnectionOriented_Abort(pLlcpSocket); memset(&pLlcpSocket->sSocketOption, 0x00, sizeof(phFriNfc_LlcpTransport_sSocketOptions_t)); if (pLlcpSocket->sServiceName.buffer != NULL) { phOsalNfc_FreeMemory(pLlcpSocket->sServiceName.buffer); } pLlcpSocket->sServiceName.buffer = NULL; pLlcpSocket->sServiceName.length = 0; } else { /* Disconnect close Error */ } } /** * \ingroup grp_fri_nfc * \brief Close a socket on a LLCP-connected device. * * 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_ConnectionOriented_Close(phFriNfc_LlcpTransport_Socket_t* pLlcpSocket) { NFCSTATUS status = NFCSTATUS_SUCCESS; if(pLlcpSocket->eSocket_State == phFriNfc_LlcpTransportSocket_eSocketConnected) { status = phLibNfc_LlcpTransport_ConnectionOriented_Disconnect(pLlcpSocket, phFriNfc_LlcpTransport_ConnectionOriented_DisconnectClose_CB, pLlcpSocket); } else { LLCP_PRINT("Socket not connected, no need to disconnect"); /* Reset the pointer to the socket closed */ pLlcpSocket->eSocket_State = phFriNfc_LlcpTransportSocket_eSocketDefault; pLlcpSocket->eSocket_Type = phFriNfc_LlcpTransport_eDefaultType; pLlcpSocket->pContext = NULL; pLlcpSocket->pSocketErrCb = NULL; pLlcpSocket->socket_sSap = PHFRINFC_LLCP_SAP_DEFAULT; pLlcpSocket->socket_dSap = PHFRINFC_LLCP_SAP_DEFAULT; pLlcpSocket->bSocketRecvPending = FALSE; pLlcpSocket->bSocketSendPending = FALSE; pLlcpSocket->bSocketListenPending = FALSE; pLlcpSocket->bSocketDiscPending = FALSE; pLlcpSocket->RemoteBusyConditionInfo = FALSE; pLlcpSocket->ReceiverBusyCondition = FALSE; pLlcpSocket->socket_VS = 0; pLlcpSocket->socket_VSA = 0; pLlcpSocket->socket_VR = 0; pLlcpSocket->socket_VRA = 0; pLlcpSocket->indexRwRead = 0; pLlcpSocket->indexRwWrite = 0; phFriNfc_LlcpTransport_ConnectionOriented_Abort(pLlcpSocket); memset(&pLlcpSocket->sSocketOption, 0x00, sizeof(phFriNfc_LlcpTransport_sSocketOptions_t)); if (pLlcpSocket->sServiceName.buffer != NULL) { phOsalNfc_FreeMemory(pLlcpSocket->sServiceName.buffer); } pLlcpSocket->sServiceName.buffer = NULL; pLlcpSocket->sServiceName.length = 0; } return NFCSTATUS_SUCCESS; } /** * \ingroup grp_fri_nfc * \brief Send data on a socket. * * 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_ConnectionOriented_Send(phFriNfc_LlcpTransport_Socket_t* pLlcpSocket, phNfc_sData_t* psBuffer, pphFriNfc_LlcpTransportSocketSendCb_t pSend_RspCb, void* pContext) { NFCSTATUS status = NFCSTATUS_SUCCESS; /* Test the RW window */ if(!CHECK_SEND_RW(pLlcpSocket)) { /* Store the Send CB and context */ pLlcpSocket->pfSocketSend_Cb = pSend_RspCb; pLlcpSocket->pSendContext = pContext; /* Set Send pending */ pLlcpSocket->bSocketSendPending = TRUE; /* Store send buffer pointer */ pLlcpSocket->sSocketSendBuffer = *psBuffer; /* Set status */ status = NFCSTATUS_PENDING; } else { /* Store send buffer pointer */ pLlcpSocket->sSocketSendBuffer = *psBuffer; /* Store the Send CB and context */ pLlcpSocket->pfSocketSend_Cb = pSend_RspCb; pLlcpSocket->pSendContext = pContext; /* Test if a send is pending */ if(pLlcpSocket->psTransport->bSendPending == TRUE) { /* Set Send pending */ pLlcpSocket->bSocketSendPending = TRUE; /* Set status */ status = NFCSTATUS_PENDING; } else { /* Store the Send CB and context */ pLlcpSocket->pfSocketSend_Cb = pSend_RspCb; pLlcpSocket->pSendContext = pContext; status = static_performSendInfo(pLlcpSocket); if(status != NFCSTATUS_PENDING) { LLCP_PRINT("Release Send callback"); pLlcpSocket->pfSocketSend_Cb = NULL; pLlcpSocket->pSendContext = NULL; } } } return status; } /** * \ingroup grp_fri_nfc * \brief Read data on a socket. * * 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_ConnectionOriented_Recv( phFriNfc_LlcpTransport_Socket_t* pLlcpSocket, phNfc_sData_t* psBuffer, pphFriNfc_LlcpTransportSocketRecvCb_t pRecv_RspCb, void* pContext) { NFCSTATUS status = NFCSTATUS_SUCCESS; uint32_t dataLengthStored = 0; uint32_t dataLengthAvailable = 0; uint32_t dataLengthRead = 0; uint32_t dataLengthWrite = 0; bool_t dataBufferized = FALSE; /* Test if the WorkingBuffer Length is null */ if(pLlcpSocket->bufferLinearLength == 0) { if (pLlcpSocket->eSocket_State != phFriNfc_LlcpTransportSocket_eSocketConnected) { return NFCSTATUS_FAILED; } /* Test If data is present in the RW Buffer */ if(pLlcpSocket->indexRwRead != pLlcpSocket->indexRwWrite) { if(pLlcpSocket->sSocketRwBufferTable[(pLlcpSocket->indexRwRead%pLlcpSocket->localRW)].length != 0) { /* Save I_FRAME into the Receive Buffer */ memcpy(psBuffer->buffer,pLlcpSocket->sSocketRwBufferTable[(pLlcpSocket->indexRwRead%pLlcpSocket->localRW)].buffer,pLlcpSocket->sSocketRwBufferTable[(pLlcpSocket->indexRwRead%pLlcpSocket->localRW)].length); psBuffer->length = pLlcpSocket->sSocketRwBufferTable[(pLlcpSocket->indexRwRead%pLlcpSocket->localRW)].length; dataBufferized = TRUE; /* Update VR */ pLlcpSocket->socket_VR = (pLlcpSocket->socket_VR+1)%16; /* Update RW Buffer length */ pLlcpSocket->sSocketRwBufferTable[(pLlcpSocket->indexRwRead%pLlcpSocket->localRW)].length = 0; /* Update Value Rw Read Index*/ pLlcpSocket->indexRwRead++; } } if(dataBufferized == TRUE) { /* Call the Receive CB */ pRecv_RspCb(pContext,NFCSTATUS_SUCCESS); if(pLlcpSocket->ReceiverBusyCondition == TRUE) { /* Reset the ReceiverBusyCondition Flag */ pLlcpSocket->ReceiverBusyCondition = FALSE; /* RR */ /* TODO: report status? */ phFriNfc_Llcp_Send_ReceiveReady_Frame(pLlcpSocket); } } else { /* Set Receive pending */ pLlcpSocket->bSocketRecvPending = TRUE; /* Store the buffer pointer */ pLlcpSocket->sSocketRecvBuffer = psBuffer; /* Store the Recv CB and context */ pLlcpSocket->pfSocketRecv_Cb = pRecv_RspCb; pLlcpSocket->pRecvContext = pContext; /* Set status */ status = NFCSTATUS_PENDING; } } else { /* Test if data is present in the linear buffer*/ dataLengthStored = phFriNfc_Llcp_CyclicFifoUsage(&pLlcpSocket->sCyclicFifoBuffer); if(dataLengthStored != 0) { if(psBuffer->length > dataLengthStored) { psBuffer->length = dataLengthStored; } /* Read data from the linear buffer */ dataLengthRead = phFriNfc_Llcp_CyclicFifoFifoRead(&pLlcpSocket->sCyclicFifoBuffer, psBuffer->buffer, psBuffer->length); if(dataLengthRead != 0) { /* Test If data is present in the RW Buffer */ while(pLlcpSocket->indexRwRead != pLlcpSocket->indexRwWrite) { /* Get the data length available in the linear buffer */ dataLengthAvailable = phFriNfc_Llcp_CyclicFifoAvailable(&pLlcpSocket->sCyclicFifoBuffer); /* Exit if not enough memory available in linear buffer */ if(dataLengthAvailable < pLlcpSocket->sSocketRwBufferTable[(pLlcpSocket->indexRwRead%pLlcpSocket->localRW)].length) { break; } /* Write data into the linear buffer */ dataLengthWrite = phFriNfc_Llcp_CyclicFifoWrite(&pLlcpSocket->sCyclicFifoBuffer, pLlcpSocket->sSocketRwBufferTable[(pLlcpSocket->indexRwRead%pLlcpSocket->localRW)].buffer, pLlcpSocket->sSocketRwBufferTable[(pLlcpSocket->indexRwRead%pLlcpSocket->localRW)].length); /* Update VR */ pLlcpSocket->socket_VR = (pLlcpSocket->socket_VR+1)%16; /* Set flag bufferized to TRUE */ dataBufferized = TRUE; /* Update RW Buffer length */ pLlcpSocket->sSocketRwBufferTable[(pLlcpSocket->indexRwRead%pLlcpSocket->localRW)].length = 0; /* Update Value Rw Read Index*/ pLlcpSocket->indexRwRead++; } /* Test if data has been bufferized after a read access */ if(dataBufferized == TRUE) { /* Get the data length available in the linear buffer */ dataLengthAvailable = phFriNfc_Llcp_CyclicFifoAvailable(&pLlcpSocket->sCyclicFifoBuffer); if((dataLengthAvailable >= pLlcpSocket->sSocketOption.miu) && (pLlcpSocket->ReceiverBusyCondition == TRUE)) { /* Reset the ReceiverBusyCondition Flag */ pLlcpSocket->ReceiverBusyCondition = FALSE; /* RR */ /* TODO: report status? */ phFriNfc_Llcp_Send_ReceiveReady_Frame(pLlcpSocket); } } /* Call the Receive CB */ pRecv_RspCb(pContext,NFCSTATUS_SUCCESS); } else { /* Call the Receive CB */ status = NFCSTATUS_FAILED; } } else { if (pLlcpSocket->eSocket_State != phFriNfc_LlcpTransportSocket_eSocketConnected) { status = NFCSTATUS_FAILED; } else { /* Set Receive pending */ pLlcpSocket->bSocketRecvPending = TRUE; /* Store the buffer pointer */ pLlcpSocket->sSocketRecvBuffer = psBuffer; /* Store the Recv CB and context */ pLlcpSocket->pfSocketRecv_Cb = pRecv_RspCb; pLlcpSocket->pRecvContext = pContext; /* Set status */ status = NFCSTATUS_PENDING; } } } if(status != NFCSTATUS_PENDING) { /* Note: The receive callback must be released to avoid being called at abort */ LLCP_PRINT("Release Receive callback"); pLlcpSocket->pfSocketRecv_Cb = NULL; pLlcpSocket->pRecvContext = NULL; } return status; }