15d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly/*
25d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly * Copyright (C) 2010 NXP Semiconductors
35d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly *
45d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly * Licensed under the Apache License, Version 2.0 (the "License");
55d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly * you may not use this file except in compliance with the License.
65d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly * You may obtain a copy of the License at
75d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly *
85d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly *      http://www.apache.org/licenses/LICENSE-2.0
95d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly *
105d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly * Unless required by applicable law or agreed to in writing, software
115d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly * distributed under the License is distributed on an "AS IS" BASIS,
125d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
135d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly * See the License for the specific language governing permissions and
145d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly * limitations under the License.
155d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly */
165d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
175d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly/**
185d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly * \file  phFriNfc_Llcp.c
195d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly * \brief NFC LLCP core
205d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly *
215d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly * Project: NFC-FRI
225d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly *
235d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly */
245d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
255d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly/*include files*/
265d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly#include <phNfcLlcpTypes.h>
275d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly#include <phOsalNfc_Timer.h>
285d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
295d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly#include <phFriNfc_Llcp.h>
305d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly#include <phFriNfc_LlcpUtils.h>
315d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
325d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly/**
335d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly * \internal
345d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly * \name States of the LLC state machine.
355d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly *
365d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly */
375d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly/*@{*/
385d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly#define PHFRINFC_LLCP_STATE_RESET_INIT               0   /**< \internal Initial state.*/
395d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly#define PHFRINFC_LLCP_STATE_CHECKED                  1   /**< \internal The tag has been checked for LLCP compliance.*/
405d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly#define PHFRINFC_LLCP_STATE_ACTIVATION               2   /**< \internal The deactivation phase.*/
415d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly#define PHFRINFC_LLCP_STATE_PAX                      3   /**< \internal Parameter exchange phase.*/
425d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly#define PHFRINFC_LLCP_STATE_OPERATION_RECV           4   /**< \internal Normal operation phase (ready to receive).*/
435d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly#define PHFRINFC_LLCP_STATE_OPERATION_SEND           5   /**< \internal Normal operation phase (ready to send).*/
445d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly#define PHFRINFC_LLCP_STATE_DEACTIVATION             6   /**< \internal The deactivation phase.*/
455d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly/*@}*/
465d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
475d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly/**
485d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly * \internal
495d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly * \name Masks used for VERSION parsing.
505d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly *
515d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly */
525d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly/*@{*/
535d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly#define PHFRINFC_LLCP_VERSION_MAJOR_MASK            0xF0    /**< \internal Mask to apply to get major version number.*/
545d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly#define PHFRINFC_LLCP_VERSION_MINOR_MASK            0x0F    /**< \internal Mask to apply to get major version number.*/
555d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly/*@}*/
565d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
575d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly/**
585d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly * \internal
595d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly * \name Invalid values for parameters.
605d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly *
615d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly */
625d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly/*@{*/
635d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly#define PHFRINFC_LLCP_INVALID_VERSION              0x00   /**< \internal Invalid VERSION value.*/
645d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly/*@}*/
655d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
665d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly/**
675d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly * \internal
685d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly * \name Internal constants.
695d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly *
705d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly */
715d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly/*@{*/
725d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly#define PHFRINFC_LLCP_MAX_PARAM_TLV_LENGTH \
735d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   (( PHFRINFC_LLCP_TLV_LENGTH_HEADER + PHFRINFC_LLCP_TLV_LENGTH_VERSION ) + \
745d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly    ( PHFRINFC_LLCP_TLV_LENGTH_HEADER + PHFRINFC_LLCP_TLV_LENGTH_MIUX ) + \
755d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly    ( PHFRINFC_LLCP_TLV_LENGTH_HEADER + PHFRINFC_LLCP_TLV_LENGTH_WKS ) + \
765d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly    ( PHFRINFC_LLCP_TLV_LENGTH_HEADER + PHFRINFC_LLCP_TLV_LENGTH_LTO ) + \
775d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly    ( PHFRINFC_LLCP_TLV_LENGTH_HEADER + PHFRINFC_LLCP_TLV_LENGTH_OPT ))   /**< \internal Maximum size of link params TLV.*/
785d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly/*@}*/
795d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
805d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
815d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
825d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly/* --------------------------- Internal functions ------------------------------ */
835d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
845d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pellystatic void phFriNfc_Llcp_Receive_CB( void               *pContext,
855d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly                                      NFCSTATUS          status,
865d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly                                      phNfc_sData_t      *psData);
875d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pellystatic NFCSTATUS phFriNfc_Llcp_HandleIncomingPacket( phFriNfc_Llcp_t    *Llcp,
885d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly                                                     phNfc_sData_t      *psPacket );
895d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pellystatic void phFriNfc_Llcp_ResetLTO( phFriNfc_Llcp_t *Llcp );
905d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pellystatic NFCSTATUS phFriNfc_Llcp_InternalSend( phFriNfc_Llcp_t                    *Llcp,
915d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly                                             phFriNfc_Llcp_sPacketHeader_t      *psHeader,
925d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly                                             phFriNfc_Llcp_sPacketSequence_t    *psSequence,
935d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly                                             phNfc_sData_t                      *psInfo );
945d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pellystatic bool_t phFriNfc_Llcp_HandlePendingSend ( phFriNfc_Llcp_t *Llcp );
955d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
96d9d57394761c70786f5058f82e7528bfaf1807a0Arnaud Ferirstatic phNfc_sData_t * phFriNfc_Llcp_AllocateAndCopy(phNfc_sData_t * pOrig)
97f3fc813f66fba3a24ca96007507073c045e17c4bSylvain Fonteneau{
98f3fc813f66fba3a24ca96007507073c045e17c4bSylvain Fonteneau   phNfc_sData_t * pDest = NULL;
99f3fc813f66fba3a24ca96007507073c045e17c4bSylvain Fonteneau
100f3fc813f66fba3a24ca96007507073c045e17c4bSylvain Fonteneau   if (pOrig == NULL)
101f3fc813f66fba3a24ca96007507073c045e17c4bSylvain Fonteneau   {
102f3fc813f66fba3a24ca96007507073c045e17c4bSylvain Fonteneau       return NULL;
103f3fc813f66fba3a24ca96007507073c045e17c4bSylvain Fonteneau   }
104f3fc813f66fba3a24ca96007507073c045e17c4bSylvain Fonteneau
105f3fc813f66fba3a24ca96007507073c045e17c4bSylvain Fonteneau   pDest = phOsalNfc_GetMemory(sizeof(phNfc_sData_t));
106f3fc813f66fba3a24ca96007507073c045e17c4bSylvain Fonteneau   if (pDest == NULL)
107f3fc813f66fba3a24ca96007507073c045e17c4bSylvain Fonteneau   {
108f3fc813f66fba3a24ca96007507073c045e17c4bSylvain Fonteneau      goto error;
109f3fc813f66fba3a24ca96007507073c045e17c4bSylvain Fonteneau   }
110f3fc813f66fba3a24ca96007507073c045e17c4bSylvain Fonteneau
111f3fc813f66fba3a24ca96007507073c045e17c4bSylvain Fonteneau   pDest->buffer = phOsalNfc_GetMemory(pOrig->length);
112f3fc813f66fba3a24ca96007507073c045e17c4bSylvain Fonteneau   if (pDest->buffer == NULL)
113f3fc813f66fba3a24ca96007507073c045e17c4bSylvain Fonteneau   {
114f3fc813f66fba3a24ca96007507073c045e17c4bSylvain Fonteneau      goto error;
115f3fc813f66fba3a24ca96007507073c045e17c4bSylvain Fonteneau   }
116f3fc813f66fba3a24ca96007507073c045e17c4bSylvain Fonteneau
117f3fc813f66fba3a24ca96007507073c045e17c4bSylvain Fonteneau   memcpy(pDest->buffer, pOrig->buffer, pOrig->length);
118f3fc813f66fba3a24ca96007507073c045e17c4bSylvain Fonteneau   pDest->length = pOrig->length;
119f3fc813f66fba3a24ca96007507073c045e17c4bSylvain Fonteneau
120f3fc813f66fba3a24ca96007507073c045e17c4bSylvain Fonteneau   return pDest;
121f3fc813f66fba3a24ca96007507073c045e17c4bSylvain Fonteneau
122f3fc813f66fba3a24ca96007507073c045e17c4bSylvain Fonteneauerror:
123f3fc813f66fba3a24ca96007507073c045e17c4bSylvain Fonteneau   if (pDest != NULL)
124f3fc813f66fba3a24ca96007507073c045e17c4bSylvain Fonteneau   {
125f3fc813f66fba3a24ca96007507073c045e17c4bSylvain Fonteneau      if (pDest->buffer != NULL)
126f3fc813f66fba3a24ca96007507073c045e17c4bSylvain Fonteneau      {
127f3fc813f66fba3a24ca96007507073c045e17c4bSylvain Fonteneau         phOsalNfc_FreeMemory(pDest->buffer);
128f3fc813f66fba3a24ca96007507073c045e17c4bSylvain Fonteneau      }
129f3fc813f66fba3a24ca96007507073c045e17c4bSylvain Fonteneau      phOsalNfc_FreeMemory(pDest);
130f3fc813f66fba3a24ca96007507073c045e17c4bSylvain Fonteneau   }
131f3fc813f66fba3a24ca96007507073c045e17c4bSylvain Fonteneau   return NULL;
132f3fc813f66fba3a24ca96007507073c045e17c4bSylvain Fonteneau}
133f3fc813f66fba3a24ca96007507073c045e17c4bSylvain Fonteneau
134f3fc813f66fba3a24ca96007507073c045e17c4bSylvain Fonteneaustatic void phFriNfc_Llcp_Deallocate(phNfc_sData_t * pData)
135f3fc813f66fba3a24ca96007507073c045e17c4bSylvain Fonteneau{
136f3fc813f66fba3a24ca96007507073c045e17c4bSylvain Fonteneau   if (pData != NULL)
137f3fc813f66fba3a24ca96007507073c045e17c4bSylvain Fonteneau   {
13840cdab11e00d801c1b9acfdcfe53455059c1b557Arnaud Ferir      if (pData->buffer != NULL)
13940cdab11e00d801c1b9acfdcfe53455059c1b557Arnaud Ferir      {
14040cdab11e00d801c1b9acfdcfe53455059c1b557Arnaud Ferir         phOsalNfc_FreeMemory(pData->buffer);
14140cdab11e00d801c1b9acfdcfe53455059c1b557Arnaud Ferir      }
14240cdab11e00d801c1b9acfdcfe53455059c1b557Arnaud Ferir      else
14340cdab11e00d801c1b9acfdcfe53455059c1b557Arnaud Ferir      {
14440cdab11e00d801c1b9acfdcfe53455059c1b557Arnaud Ferir         LLCP_PRINT("Warning, deallocating empty buffer");
14540cdab11e00d801c1b9acfdcfe53455059c1b557Arnaud Ferir      }
146f3fc813f66fba3a24ca96007507073c045e17c4bSylvain Fonteneau      phOsalNfc_FreeMemory(pData);
147f3fc813f66fba3a24ca96007507073c045e17c4bSylvain Fonteneau   }
148f3fc813f66fba3a24ca96007507073c045e17c4bSylvain Fonteneau}
149f3fc813f66fba3a24ca96007507073c045e17c4bSylvain Fonteneau
1505d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pellystatic NFCSTATUS phFriNfc_Llcp_InternalDeactivate( phFriNfc_Llcp_t *Llcp )
1515d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly{
1521ec4ace9cd3079abd7c0b30d0976591c8c0f441eArnaud Ferir   phFriNfc_Llcp_Send_CB_t pfSendCB;
1531ec4ace9cd3079abd7c0b30d0976591c8c0f441eArnaud Ferir   void * pSendContext;
1545d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   if ((Llcp->state == PHFRINFC_LLCP_STATE_OPERATION_RECV) ||
1555d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly       (Llcp->state == PHFRINFC_LLCP_STATE_OPERATION_SEND) ||
1565d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly       (Llcp->state == PHFRINFC_LLCP_STATE_PAX)            ||
1575d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly       (Llcp->state == PHFRINFC_LLCP_STATE_ACTIVATION))
1585d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   {
1595d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      /* Update state */
1605d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      Llcp->state = PHFRINFC_LLCP_STATE_DEACTIVATION;
1615d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
1625d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      /* Stop timer */
1635d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      phOsalNfc_Timer_Stop(Llcp->hSymmTimer);
1645d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
1653cbab5882f6d89a52068a3fa72a7223971d6b7fdMartijn Coenen      Llcp->psSendHeader = NULL;
1663cbab5882f6d89a52068a3fa72a7223971d6b7fdMartijn Coenen      Llcp->psSendSequence = NULL;
1671ec4ace9cd3079abd7c0b30d0976591c8c0f441eArnaud Ferir      /* Return delayed send operation in error, in any */
1681ec4ace9cd3079abd7c0b30d0976591c8c0f441eArnaud Ferir      if (Llcp->psSendInfo != NULL)
1691ec4ace9cd3079abd7c0b30d0976591c8c0f441eArnaud Ferir      {
1701ec4ace9cd3079abd7c0b30d0976591c8c0f441eArnaud Ferir         phFriNfc_Llcp_Deallocate(Llcp->psSendInfo);
17140cdab11e00d801c1b9acfdcfe53455059c1b557Arnaud Ferir         Llcp->psSendInfo = NULL;
1721ec4ace9cd3079abd7c0b30d0976591c8c0f441eArnaud Ferir      }
1731ec4ace9cd3079abd7c0b30d0976591c8c0f441eArnaud Ferir      if (Llcp->pfSendCB != NULL)
1741ec4ace9cd3079abd7c0b30d0976591c8c0f441eArnaud Ferir      {
1751ec4ace9cd3079abd7c0b30d0976591c8c0f441eArnaud Ferir         /* Get Callback params */
1761ec4ace9cd3079abd7c0b30d0976591c8c0f441eArnaud Ferir         pfSendCB = Llcp->pfSendCB;
1771ec4ace9cd3079abd7c0b30d0976591c8c0f441eArnaud Ferir         pSendContext = Llcp->pSendContext;
1781ec4ace9cd3079abd7c0b30d0976591c8c0f441eArnaud Ferir         /* Reset callback params */
1791ec4ace9cd3079abd7c0b30d0976591c8c0f441eArnaud Ferir         Llcp->pfSendCB = NULL;
1801ec4ace9cd3079abd7c0b30d0976591c8c0f441eArnaud Ferir         Llcp->pSendContext = NULL;
1811ec4ace9cd3079abd7c0b30d0976591c8c0f441eArnaud Ferir         /* Call the callback */
1821ec4ace9cd3079abd7c0b30d0976591c8c0f441eArnaud Ferir         (pfSendCB)(pSendContext, NFCSTATUS_FAILED);
1831ec4ace9cd3079abd7c0b30d0976591c8c0f441eArnaud Ferir      }
1841ec4ace9cd3079abd7c0b30d0976591c8c0f441eArnaud Ferir
1855d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      /* Notify service layer */
1865d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      Llcp->pfLink_CB(Llcp->pLinkContext, phFriNfc_LlcpMac_eLinkDeactivated);
1875d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
1885d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      /* Forward check request to MAC layer */
1895d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      return phFriNfc_LlcpMac_Deactivate(&Llcp->MAC);
1905d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   }
1915d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
1925d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   return NFCSTATUS_SUCCESS;
1935d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly}
1945d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
1955d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
1965d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pellystatic NFCSTATUS phFriNfc_Llcp_SendSymm( phFriNfc_Llcp_t *Llcp )
1975d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly{
1985d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   phFriNfc_Llcp_sPacketHeader_t sHeader;
1995d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
20054b847c7f7a5bc2e36ebe877ce832cdfefabc733Martijn Coenen   sHeader.dsap  = PHFRINFC_LLCP_SAP_LINK;
20154b847c7f7a5bc2e36ebe877ce832cdfefabc733Martijn Coenen   sHeader.ssap  = PHFRINFC_LLCP_SAP_LINK;
20254b847c7f7a5bc2e36ebe877ce832cdfefabc733Martijn Coenen   sHeader.ptype = PHFRINFC_LLCP_PTYPE_SYMM;
20354b847c7f7a5bc2e36ebe877ce832cdfefabc733Martijn Coenen   return phFriNfc_Llcp_InternalSend(Llcp, &sHeader, NULL, NULL);
2045d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly}
2055d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
2065d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
2075d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pellystatic NFCSTATUS phFriNfc_Llcp_SendPax( phFriNfc_Llcp_t *Llcp, phFriNfc_Llcp_sLinkParameters_t *psLinkParams)
2085d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly{
2095d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   uint8_t                       pTLVBuffer[PHFRINFC_LLCP_MAX_PARAM_TLV_LENGTH];
2105d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   phNfc_sData_t                 sParamsTLV;
2115d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   phFriNfc_Llcp_sPacketHeader_t sHeader;
2125d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   NFCSTATUS                     result;
2135d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
2145d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Prepare link parameters TLV */
2155d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   sParamsTLV.buffer = pTLVBuffer;
2165d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   sParamsTLV.length = PHFRINFC_LLCP_MAX_PARAM_TLV_LENGTH;
2175d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   result = phFriNfc_Llcp_EncodeLinkParams(&sParamsTLV, psLinkParams, PHFRINFC_LLCP_VERSION);
2185d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   if (result != NFCSTATUS_SUCCESS)
2195d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   {
2205d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      /* Error while encoding */
2215d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      return NFCSTATUS_FAILED;
2225d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   }
2235d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
2245d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Check if ready to send */
2255d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   if (Llcp->state != PHFRINFC_LLCP_STATE_OPERATION_SEND)
2265d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   {
2275d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      /* No send pending, send the PAX packet */
2285d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      sHeader.dsap  = PHFRINFC_LLCP_SAP_LINK;
2295d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      sHeader.ssap  = PHFRINFC_LLCP_SAP_LINK;
2305d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      sHeader.ptype = PHFRINFC_LLCP_PTYPE_PAX;
2315d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      return phFriNfc_Llcp_InternalSend(Llcp, &sHeader, NULL, &sParamsTLV);
2325d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   }
2335d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   else
2345d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   {
2355d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      /* Error: A send is already pending, cannot send PAX */
2365d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      /* NOTE: this should not happen since PAX are sent before any other packet ! */
2375d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      return NFCSTATUS_FAILED;
2385d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   }
2395d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly}
2405d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
2415d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
2425d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pellystatic NFCSTATUS phFriNfc_Llcp_SendDisconnect( phFriNfc_Llcp_t *Llcp )
2435d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly{
2445d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   phFriNfc_Llcp_sPacketHeader_t sHeader;
2455d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
2465d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Check if ready to send */
2475d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   if (Llcp->state != PHFRINFC_LLCP_STATE_OPERATION_SEND)
2485d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   {
2495d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      /* No send pending, send the DISC packet */
2505d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      sHeader.dsap  = PHFRINFC_LLCP_SAP_LINK;
2515d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      sHeader.ssap  = PHFRINFC_LLCP_SAP_LINK;
2525d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      sHeader.ptype = PHFRINFC_LLCP_PTYPE_DISC;
2535d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      return phFriNfc_Llcp_InternalSend(Llcp, &sHeader, NULL, NULL);
2545d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   }
2555d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   else
2565d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   {
2575d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      /* A send is already pending, raise a flag to send DISC as soon as possible */
2585d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      Llcp->bDiscPendingFlag = TRUE;
2595d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      return NFCSTATUS_PENDING;
2605d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   }
2615d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly}
2625d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
2635d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
2645d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pellystatic void phFriNfc_Llcp_Timer_CB(uint32_t TimerId, void *pContext)
2655d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly{
2665d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   phFriNfc_Llcp_t               *Llcp = (phFriNfc_Llcp_t*)pContext;
2675d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
2685d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   PHNFC_UNUSED_VARIABLE(TimerId);
2695d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
2705d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Check current state */
2715d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   if (Llcp->state == PHFRINFC_LLCP_STATE_OPERATION_RECV)
2725d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   {
2735d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      /* No data is coming before LTO, disconnecting */
2745d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      phFriNfc_Llcp_InternalDeactivate(Llcp);
2755d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   }
2765d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   else if (Llcp->state == PHFRINFC_LLCP_STATE_OPERATION_SEND)
2775d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   {
2785d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      /* Send SYMM */
2795d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      phFriNfc_Llcp_SendSymm(Llcp);
2805d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   }
2815d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   else
2825d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   {
2835d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      /* Nothing to do if not in Normal Operation state */
2845d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   }
2855d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly}
2865d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
2875d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
2885d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pellystatic NFCSTATUS phFriNfc_Llcp_HandleAggregatedPacket( phFriNfc_Llcp_t *Llcp,
2895d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly                                                       phNfc_sData_t *psRawPacket )
2905d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly{
2915d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   phNfc_sData_t  sInfo;
292b7e67c8dbd4aa5892815bfed4e7ff934cf49b904Sylvain Fonteneau   phNfc_sData_t  sCurrentInfo;
2935d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   uint16_t       length;
2945d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   NFCSTATUS      status;
2955d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
2965d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Get info field */
2975d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   sInfo.buffer = psRawPacket->buffer + PHFRINFC_LLCP_PACKET_HEADER_SIZE;
2985d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   sInfo.length = psRawPacket->length - PHFRINFC_LLCP_PACKET_HEADER_SIZE;
2995d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
3005d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Check for empty info field */
3015d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   if (sInfo.length == 0)
3025d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   {
3035d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      return NFCSTATUS_FAILED;
3045d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   }
3055d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
3065d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Check consistency */
3075d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   while (sInfo.length != 0)
3085d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   {
3095d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      /* Check if enough room to read length */
3105d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      if (sInfo.length < sizeof(sInfo.length))
3115d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      {
3125d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         return NFCSTATUS_FAILED;
3135d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      }
3145d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      /* Read length */
3155d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      length = (sInfo.buffer[0] << 8) | sInfo.buffer[1];
3165d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      /* Update info buffer */
317b7e67c8dbd4aa5892815bfed4e7ff934cf49b904Sylvain Fonteneau      sInfo.buffer += 2; /*Size of length field is 2*/
318b7e67c8dbd4aa5892815bfed4e7ff934cf49b904Sylvain Fonteneau      sInfo.length -= 2; /*Size of length field is 2*/
3195d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      /* Check if declared length fits in remaining space */
3205d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      if (length > sInfo.length)
3215d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      {
3225d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         return NFCSTATUS_FAILED;
3235d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      }
3245d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      /* Update info buffer */
3255d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      sInfo.buffer += length;
3265d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      sInfo.length -= length;
3275d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   }
3285d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
3295d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Get info field */
3305d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   sInfo.buffer = psRawPacket->buffer + PHFRINFC_LLCP_PACKET_HEADER_SIZE;
3315d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   sInfo.length = psRawPacket->length - PHFRINFC_LLCP_PACKET_HEADER_SIZE;
3325d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
3335d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Handle aggregated packets */
3345d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   while (sInfo.length != 0)
3355d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   {
3365d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      /* Read length */
3375d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      length = (sInfo.buffer[0] << 8) | sInfo.buffer[1];
3385d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      /* Update info buffer */
339b7e67c8dbd4aa5892815bfed4e7ff934cf49b904Sylvain Fonteneau      sInfo.buffer += 2;        /* Size of length field is 2 */
340b7e67c8dbd4aa5892815bfed4e7ff934cf49b904Sylvain Fonteneau      sInfo.length -= 2;    /*Size of length field is 2*/
3415d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      /* Handle aggregated packet */
342b7e67c8dbd4aa5892815bfed4e7ff934cf49b904Sylvain Fonteneau      sCurrentInfo.buffer=sInfo.buffer;
343b7e67c8dbd4aa5892815bfed4e7ff934cf49b904Sylvain Fonteneau      sCurrentInfo.length=length;
344b7e67c8dbd4aa5892815bfed4e7ff934cf49b904Sylvain Fonteneau      status = phFriNfc_Llcp_HandleIncomingPacket(Llcp, &sCurrentInfo);
3455d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      if ( (status != NFCSTATUS_SUCCESS) &&
3465d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly           (status != NFCSTATUS_PENDING) )
3475d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      {
3485d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         /* TODO: Error: invalid frame */
3495d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      }
3505d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      /* Update info buffer */
3515d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      sInfo.buffer += length;
3525d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      sInfo.length -= length;
3535d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   }
3545d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   return NFCSTATUS_SUCCESS;
3555d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly}
3565d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
3575d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
3585d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pellystatic NFCSTATUS phFriNfc_Llcp_ParseLinkParams( phNfc_sData_t                    *psParamsTLV,
3595d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly                                                phFriNfc_Llcp_sLinkParameters_t  *psParsedParams,
3605d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly                                                uint8_t                          *pnParsedVersion )
3615d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly{
3625d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   NFCSTATUS                        status;
3635d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   uint8_t                          type;
3645d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   phFriNfc_Llcp_sLinkParameters_t  sParams;
3655d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   phNfc_sData_t                    sValueBuffer;
3665d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   uint32_t                         offset = 0;
3675d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   uint8_t                          version = PHFRINFC_LLCP_INVALID_VERSION;
3685d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
3695d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Check for NULL pointers */
3705d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   if ((psParamsTLV == NULL) || (psParsedParams == NULL) || (pnParsedVersion == NULL))
3715d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   {
3725d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      return PHNFCSTVAL(CID_FRI_NFC_LLCP, NFCSTATUS_INVALID_PARAMETER);
3735d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   }
3745d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
3755d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Prepare default param structure */
3765d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   sParams.miu    = PHFRINFC_LLCP_MIU_DEFAULT;
3775d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   sParams.wks    = PHFRINFC_LLCP_WKS_DEFAULT;
3785d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   sParams.lto    = PHFRINFC_LLCP_LTO_DEFAULT;
3795d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   sParams.option = PHFRINFC_LLCP_OPTION_DEFAULT;
3805d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
3815d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Decode TLV */
3825d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   while (offset < psParamsTLV->length)
3835d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   {
3845d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      status = phFriNfc_Llcp_DecodeTLV(psParamsTLV, &offset, &type, &sValueBuffer);
3855d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      if (status != NFCSTATUS_SUCCESS)
3865d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      {
3875d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         /* Error: Ill-formed TLV */
3885d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         return status;
3895d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      }
3905d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      switch(type)
3915d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      {
3925d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         case PHFRINFC_LLCP_TLV_TYPE_VERSION:
3935d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         {
3945d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly            /* Check length */
3955d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly            if (sValueBuffer.length != PHFRINFC_LLCP_TLV_LENGTH_VERSION)
3965d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly            {
3975d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly               /* Error : Ill-formed VERSION parameter TLV */
39846dbed4e11700226e9b43ca17e5ad6f3d192bf63Sylvain Fonteneau               break;
3995d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly            }
4005d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly            /* Get VERSION */
4015d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly            version = sValueBuffer.buffer[0];
4025d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly            break;
4035d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         }
4045d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         case PHFRINFC_LLCP_TLV_TYPE_MIUX:
4055d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         {
4065d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly            /* Check length */
4075d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly            if (sValueBuffer.length != PHFRINFC_LLCP_TLV_LENGTH_MIUX)
4085d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly            {
4095d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly               /* Error : Ill-formed MIUX parameter TLV */
41046dbed4e11700226e9b43ca17e5ad6f3d192bf63Sylvain Fonteneau               break;
4115d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly            }
4125d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly            /* Get MIU */
41334ff48f6cd6595a899e05fbd56f4c84891840d3fNick Pelly            sParams.miu = (PHFRINFC_LLCP_MIU_DEFAULT + ((sValueBuffer.buffer[0] << 8) | sValueBuffer.buffer[1])) & PHFRINFC_LLCP_TLV_MIUX_MASK;
4145d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly            break;
4155d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         }
4165d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         case PHFRINFC_LLCP_TLV_TYPE_WKS:
4175d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         {
4185d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly            /* Check length */
4195d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly            if (sValueBuffer.length != PHFRINFC_LLCP_TLV_LENGTH_WKS)
4205d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly            {
4215d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly               /* Error : Ill-formed MIUX parameter TLV */
42246dbed4e11700226e9b43ca17e5ad6f3d192bf63Sylvain Fonteneau               break;
4235d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly            }
4245d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly            /* Get WKS */
4255d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly            sParams.wks = (sValueBuffer.buffer[0] << 8) | sValueBuffer.buffer[1];
4265d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly            /* Ignored bits must always be set */
4275d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly            sParams.wks |= PHFRINFC_LLCP_TLV_WKS_MASK;
4285d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly            break;
4295d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         }
4305d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         case PHFRINFC_LLCP_TLV_TYPE_LTO:
4315d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         {
4325d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly            /* Check length */
4335d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly            if (sValueBuffer.length != PHFRINFC_LLCP_TLV_LENGTH_LTO)
4345d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly            {
4355d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly               /* Error : Ill-formed LTO parameter TLV */
43646dbed4e11700226e9b43ca17e5ad6f3d192bf63Sylvain Fonteneau               break;
4375d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly            }
4385d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly            /* Get LTO */
4395d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly            sParams.lto = sValueBuffer.buffer[0];
4405d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly            break;
4415d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         }
4425d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         case PHFRINFC_LLCP_TLV_TYPE_OPT:
4435d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         {
4445d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly            /* Check length */
4455d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly            if (sValueBuffer.length != PHFRINFC_LLCP_TLV_LENGTH_OPT)
4465d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly            {
4475d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly               /* Error : Ill-formed OPT parameter TLV */
44846dbed4e11700226e9b43ca17e5ad6f3d192bf63Sylvain Fonteneau               break;;
4495d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly            }
4505d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly            /* Get OPT */
4515d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly            sParams.option = sValueBuffer.buffer[0] & PHFRINFC_LLCP_TLV_OPT_MASK;
4525d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly            break;
4535d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         }
4545d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         default:
4555d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         {
4565d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly            /* Error : Unknown Type */
45746dbed4e11700226e9b43ca17e5ad6f3d192bf63Sylvain Fonteneau            break;
4585d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         }
4595d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      }
4605d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   }
4615d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
4625d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Check if a VERSION parameter has been provided */
4635d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   if (version == PHFRINFC_LLCP_INVALID_VERSION)
4645d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   {
4655d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      /* Error : Mandatory VERSION parameter not provided */
4665d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      return PHNFCSTVAL(CID_FRI_NFC_LLCP, NFCSTATUS_INVALID_PARAMETER);
4675d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   }
4685d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
4695d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Save response */
4705d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   *pnParsedVersion = version;
4715d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   memcpy(psParsedParams, &sParams, sizeof(phFriNfc_Llcp_sLinkParameters_t));
4725d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
4735d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   return NFCSTATUS_SUCCESS;
4745d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly}
4755d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
4765d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
4775d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pellystatic NFCSTATUS phFriNfc_Llcp_VersionAgreement( uint8_t localVersion,
4785d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly                                                 uint8_t remoteVersion,
4795d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly                                                 uint8_t *pNegociatedVersion )
4805d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly{
4815d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   uint8_t     localMajor  = localVersion  & PHFRINFC_LLCP_VERSION_MAJOR_MASK;
4825d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   uint8_t     localMinor  = localVersion  & PHFRINFC_LLCP_VERSION_MINOR_MASK;
4835d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   uint8_t     remoteMajor = remoteVersion & PHFRINFC_LLCP_VERSION_MAJOR_MASK;
4845d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   uint8_t     remoteMinor = remoteVersion & PHFRINFC_LLCP_VERSION_MINOR_MASK;
4855d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   uint8_t     negociatedVersion;
4865d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
4875d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Check for NULL pointers */
4885d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   if (pNegociatedVersion == NULL)
4895d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   {
4905d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      return PHNFCSTVAL(CID_FRI_NFC_LLCP, NFCSTATUS_INVALID_PARAMETER);
4915d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   }
4925d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
4935d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Compare Major numbers */
4945d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   if (localMajor == remoteMajor)
4955d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   {
4965d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      /* Version agreement succeed : use lowest version */
4975d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      negociatedVersion = localMajor | ((remoteMinor<localMinor)?remoteMinor:localMinor);
4985d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   }
4995d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   else if (localMajor > remoteMajor)
5005d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   {
5015d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      /* Decide if versions are compatible */
5025d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      /* Currently, there is no backward compatibility to handle */
5035d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      return NFCSTATUS_FAILED;
5045d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   }
5055d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   else /* if (localMajor < remoteMajor) */
5065d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   {
5075d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      /* It is up to the remote host to decide if versions are compatible */
5085d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      /* Set negociated version to our local version, the remote will
5095d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         deacivate the link if its own version agreement fails */
5105d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      negociatedVersion = localVersion;
5115d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   }
5125d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
5135d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Save response */
5145d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   *pNegociatedVersion = negociatedVersion;
5155d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
5165d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   return NFCSTATUS_SUCCESS;
5175d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly}
5185d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
5195d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
5205d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pellystatic NFCSTATUS phFriNfc_Llcp_InternalActivate( phFriNfc_Llcp_t *Llcp,
5215d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly                                                 phNfc_sData_t   *psParamsTLV)
5225d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly{
5235d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   NFCSTATUS                        status;
5245d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   phFriNfc_Llcp_sLinkParameters_t  sRemoteParams;
5255d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   uint8_t                          remoteVersion;
5265d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   uint8_t                          negociatedVersion;
5275d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   const uint16_t nMaxHeaderSize =  PHFRINFC_LLCP_PACKET_HEADER_SIZE +
5285d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly                                    PHFRINFC_LLCP_PACKET_SEQUENCE_SIZE;
5295d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
5305d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Parse parameters  */
5315d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   status = phFriNfc_Llcp_ParseLinkParams(psParamsTLV, &sRemoteParams, &remoteVersion);
5325d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   if (status != NFCSTATUS_SUCCESS)
5335d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   {
5345d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      /* Error: invalid parameters TLV */
5355d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      status = NFCSTATUS_FAILED;
5365d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   }
5375d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   else
5385d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   {
5395d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      /* Version agreement procedure */
5405d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      status = phFriNfc_Llcp_VersionAgreement(PHFRINFC_LLCP_VERSION , remoteVersion, &negociatedVersion);
5415d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      if (status != NFCSTATUS_SUCCESS)
5425d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      {
5435d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         /* Error: version agreement failed */
5445d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         status = NFCSTATUS_FAILED;
5455d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      }
5465d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      else
5475d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      {
5485d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         /* Save parameters */
5495d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         Llcp->version = negociatedVersion;
5505d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         memcpy(&Llcp->sRemoteParams, &sRemoteParams, sizeof(phFriNfc_Llcp_sLinkParameters_t));
5515d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
5525d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         /* Update remote MIU to match local Tx buffer size */
5535d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         if (Llcp->nTxBufferLength < (Llcp->sRemoteParams.miu + nMaxHeaderSize))
5545d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         {
5555d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly            Llcp->sRemoteParams.miu = Llcp->nTxBufferLength - nMaxHeaderSize;
5565d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         }
5575d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
5585d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         /* Initiate Symmetry procedure by resetting LTO timer */
5595d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         /* NOTE: this also updates current state */
5605d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         phFriNfc_Llcp_ResetLTO(Llcp);
5615d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      }
5625d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   }
5635d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Notify upper layer, if Activation failed CB called by Deactivate */
5645d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   if (status == NFCSTATUS_SUCCESS)
5655d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   {
5665d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      /* Link activated ! */
5675d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      Llcp->pfLink_CB(Llcp->pLinkContext, phFriNfc_LlcpMac_eLinkActivated);
5685d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   }
5695d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
5705d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   return status;
5715d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly}
5725d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
5735d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
5745d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pellystatic NFCSTATUS phFriNfc_Llcp_HandleMACLinkActivated( phFriNfc_Llcp_t  *Llcp,
5755d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly                                                       phNfc_sData_t    *psParamsTLV)
5765d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly{
5775d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   NFCSTATUS                     status = NFCSTATUS_SUCCESS;
5785d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
5795d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Create the timer */
5805d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   Llcp->hSymmTimer = phOsalNfc_Timer_Create();
5815d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   if (Llcp->hSymmTimer == PH_OSALNFC_INVALID_TIMER_ID)
5825d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   {
5835d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      /* Error: unable to create timer */
5845d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      return NFCSTATUS_INSUFFICIENT_RESOURCES;
5855d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   }
5865d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
5875d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Check if params received from MAC activation procedure */
5885d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   if (psParamsTLV == NULL)
5895d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   {
5905d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      /* No params with selected MAC mapping, enter PAX mode for parameter exchange */
5915d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      Llcp->state = PHFRINFC_LLCP_STATE_PAX;
5925d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      /* Set default MIU for PAX exchange */
5935d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      Llcp->sRemoteParams.miu = PHFRINFC_LLCP_MIU_DEFAULT;
5945d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      /* If the local device is the initiator, it must initiate PAX exchange */
5955d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      if (Llcp->eRole == phFriNfc_LlcpMac_ePeerTypeInitiator)
5965d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      {
5975d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         /* Send PAX */
5985d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         status = phFriNfc_Llcp_SendPax(Llcp, &Llcp->sLocalParams);
5995d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      }
6005d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   }
6015d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   else
6025d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   {
6035d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      /* Params exchanged during MAX activation, try LLC activation */
6045d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      status = phFriNfc_Llcp_InternalActivate(Llcp, psParamsTLV);
6055d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   }
6065d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
6075d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   if (status == NFCSTATUS_SUCCESS)
6085d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   {
6095d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      /* Start listening for incoming packets */
6105d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      Llcp->sRxBuffer.length = Llcp->nRxBufferLength;
6115d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      phFriNfc_LlcpMac_Receive(&Llcp->MAC, &Llcp->sRxBuffer, phFriNfc_Llcp_Receive_CB, Llcp);
6125d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   }
6135d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
6145d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   return status;
6155d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly}
6165d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
6175d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
6185d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pellystatic void phFriNfc_Llcp_HandleMACLinkDeactivated( phFriNfc_Llcp_t  *Llcp )
6195d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly{
6205d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   uint8_t state = Llcp->state;
6215d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
6225d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Delete the timer */
6235d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   if (Llcp->hSymmTimer != PH_OSALNFC_INVALID_TIMER_ID)
6245d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   {
6255d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      phOsalNfc_Timer_Delete(Llcp->hSymmTimer);
6265d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   }
6275d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
6285d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Reset state */
6296bd5058796097ae40ed41c283a69e7874f2e9db2Martijn Coenen   Llcp->state = PHFRINFC_LLCP_STATE_RESET_INIT;
6305d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
6315d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   switch (state)
6325d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   {
6335d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      case PHFRINFC_LLCP_STATE_DEACTIVATION:
6345d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      {
6355d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         /* The service layer has already been notified, nothing more to do */
6365d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         break;
6375d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      }
6385d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      default:
6395d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      {
6405d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         /* Notify service layer of link failure */
6415d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         Llcp->pfLink_CB(Llcp->pLinkContext, phFriNfc_LlcpMac_eLinkDeactivated);
6425d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         break;
6435d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      }
6445d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   }
6455d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly}
6465d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
6475d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
6485d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pellystatic void phFriNfc_Llcp_ChkLlcp_CB( void       *pContext,
6495d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly                                      NFCSTATUS  status )
6505d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly{
6515d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Get monitor from context */
6525d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   phFriNfc_Llcp_t *Llcp = (phFriNfc_Llcp_t*)pContext;
6535d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
6545d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Update state */
6555d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   Llcp->state = PHFRINFC_LLCP_STATE_CHECKED;
6565d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
6575d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Invoke callback */
6585d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   Llcp->pfChk_CB(Llcp->pChkContext, status);
6595d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly}
6605d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
6615d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pellystatic void phFriNfc_Llcp_LinkStatus_CB( void                              *pContext,
6625d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly                                         phFriNfc_LlcpMac_eLinkStatus_t    eLinkStatus,
6635d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly                                         phNfc_sData_t                     *psParamsTLV,
66434ff48f6cd6595a899e05fbd56f4c84891840d3fNick Pelly                                         phFriNfc_LlcpMac_ePeerType_t      PeerRemoteDevType)
6655d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly{
6665d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   NFCSTATUS status;
6675d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
6685d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Get monitor from context */
6695d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   phFriNfc_Llcp_t *Llcp = (phFriNfc_Llcp_t*)pContext;
6705d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
6715d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Save the local peer role (initiator/target) */
6725d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   Llcp->eRole = PeerRemoteDevType;
6735d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
6745d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Check new link status */
6755d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   switch(eLinkStatus)
6765d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   {
6775d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      case phFriNfc_LlcpMac_eLinkActivated:
6785d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      {
6795d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         /* Handle MAC link activation */
6805d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         status = phFriNfc_Llcp_HandleMACLinkActivated(Llcp, psParamsTLV);
6815d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         if (status != NFCSTATUS_SUCCESS)
6825d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         {
6835d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly            /* Error: LLC link activation procedure failed, deactivate MAC link */
6845d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly            status = phFriNfc_Llcp_InternalDeactivate(Llcp);
6855d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         }
6865d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         break;
6875d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      }
6885d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      case phFriNfc_LlcpMac_eLinkDeactivated:
6895d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      {
6905d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         /* Handle MAC link deactivation (cannot fail) */
6915d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         phFriNfc_Llcp_HandleMACLinkDeactivated(Llcp);
6925d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         break;
6935d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      }
6945d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      default:
6955d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      {
6965d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         /* Warning: Unknown link status, should not happen */
6975d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      }
6985d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   }
6995d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly}
7005d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
7015d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
7025d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pellystatic void phFriNfc_Llcp_ResetLTO( phFriNfc_Llcp_t *Llcp )
7035d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly{
70465e86fce1fe9e3f9aff98861c5e1e9d9ba6df9d5Martijn Coenen   uint32_t nDuration = 0;
70565e86fce1fe9e3f9aff98861c5e1e9d9ba6df9d5Martijn Coenen   uint8_t bIsReset = 0;
7065d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
7075d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Stop timer */
7085d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   phOsalNfc_Timer_Stop(Llcp->hSymmTimer);
7095d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
7105d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
7115d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Update state */
7125d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   if (Llcp->state == PHFRINFC_LLCP_STATE_OPERATION_RECV)
7135d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   {
7145d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      Llcp->state = PHFRINFC_LLCP_STATE_OPERATION_SEND;
7155d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   }
7165d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   else if (Llcp->state == PHFRINFC_LLCP_STATE_OPERATION_SEND)
7175d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   {
7185d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      Llcp->state = PHFRINFC_LLCP_STATE_OPERATION_RECV;
7195d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   }
7206bd5058796097ae40ed41c283a69e7874f2e9db2Martijn Coenen   else if (Llcp->state != PHFRINFC_LLCP_STATE_DEACTIVATION &&
7216bd5058796097ae40ed41c283a69e7874f2e9db2Martijn Coenen            Llcp->state != PHFRINFC_LLCP_STATE_RESET_INIT)
7225d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   {
72365e86fce1fe9e3f9aff98861c5e1e9d9ba6df9d5Martijn Coenen      bIsReset = 1;
7245d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      /* Not yet in OPERATION state, perform first reset */
7255d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      if (Llcp->eRole == phFriNfc_LlcpMac_ePeerTypeInitiator)
7265d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      {
7275d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         Llcp->state = PHFRINFC_LLCP_STATE_OPERATION_SEND;
7285d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      }
7295d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      else
7305d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      {
7315d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         Llcp->state = PHFRINFC_LLCP_STATE_OPERATION_RECV;
7325d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      }
7335d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   }
7345d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
7355d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Calculate timer duration */
7365d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* NOTE: nDuration is in 1/100s, and timer system takes values in 1/1000s */
7375d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   if (Llcp->state == PHFRINFC_LLCP_STATE_OPERATION_RECV)
7385d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   {
7395d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      /* Response must be received before LTO announced by remote peer */
7405d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      nDuration = Llcp->sRemoteParams.lto * 10;
7415d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   }
7425d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   else
7435d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   {
74465e86fce1fe9e3f9aff98861c5e1e9d9ba6df9d5Martijn Coenen      if (bIsReset)
74565e86fce1fe9e3f9aff98861c5e1e9d9ba6df9d5Martijn Coenen      {
74665e86fce1fe9e3f9aff98861c5e1e9d9ba6df9d5Martijn Coenen          /* Immediately bounce SYMM back - it'll take
74765e86fce1fe9e3f9aff98861c5e1e9d9ba6df9d5Martijn Coenen           * a while for the host to come up with something,
74865e86fce1fe9e3f9aff98861c5e1e9d9ba6df9d5Martijn Coenen           * and maybe the remote is faster.
74965e86fce1fe9e3f9aff98861c5e1e9d9ba6df9d5Martijn Coenen           */
75065e86fce1fe9e3f9aff98861c5e1e9d9ba6df9d5Martijn Coenen          nDuration = 1;
75165e86fce1fe9e3f9aff98861c5e1e9d9ba6df9d5Martijn Coenen      }
75265e86fce1fe9e3f9aff98861c5e1e9d9ba6df9d5Martijn Coenen      else
75365e86fce1fe9e3f9aff98861c5e1e9d9ba6df9d5Martijn Coenen      {
75465e86fce1fe9e3f9aff98861c5e1e9d9ba6df9d5Martijn Coenen          /* Must answer before the local announced LTO */
75565e86fce1fe9e3f9aff98861c5e1e9d9ba6df9d5Martijn Coenen          /* NOTE: to ensure the answer is completely sent before LTO, the
75665e86fce1fe9e3f9aff98861c5e1e9d9ba6df9d5Martijn Coenen                  timer is triggered _before_ LTO expiration */
75765e86fce1fe9e3f9aff98861c5e1e9d9ba6df9d5Martijn Coenen          /* TODO: make sure time scope is enough, and avoid use of magic number */
75865e86fce1fe9e3f9aff98861c5e1e9d9ba6df9d5Martijn Coenen          nDuration = (Llcp->sLocalParams.lto * 10) / 2;
75965e86fce1fe9e3f9aff98861c5e1e9d9ba6df9d5Martijn Coenen      }
7605d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   }
7615d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
76257d24648f73cfface7409e664fe56d38f38636dfJeff Hamilton   LLCP_DEBUG("Starting LLCP timer with duration %d", nDuration);
76357d24648f73cfface7409e664fe56d38f38636dfJeff Hamilton
7645d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Restart timer */
7655d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   phOsalNfc_Timer_Start(
7665d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      Llcp->hSymmTimer,
7675d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      nDuration,
7685d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      phFriNfc_Llcp_Timer_CB,
7695d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      Llcp);
7705d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly}
7715d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
7725d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
7735d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pellystatic NFCSTATUS phFriNfc_Llcp_HandleLinkPacket( phFriNfc_Llcp_t    *Llcp,
7745d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly                                                 phNfc_sData_t      *psPacket )
7755d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly{
7765d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   NFCSTATUS                        result;
7775d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   phFriNfc_Llcp_sPacketHeader_t    sHeader;
7785d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
7795d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Parse header */
7805d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   phFriNfc_Llcp_Buffer2Header(psPacket->buffer, 0, &sHeader);
7815d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
7825d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Check packet type */
7835d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   switch (sHeader.ptype)
7845d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   {
7855d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      case PHFRINFC_LLCP_PTYPE_SYMM:
7865d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      {
7875d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         /* Nothing to do, the LTO is handled upon all packet reception */
7885d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         result = NFCSTATUS_SUCCESS;
7895d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         break;
7905d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      }
7915d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
7925d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      case PHFRINFC_LLCP_PTYPE_AGF:
7935d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      {
7945d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         /* Handle the aggregated packet */
7955d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         result = phFriNfc_Llcp_HandleAggregatedPacket(Llcp, psPacket);
7965d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         if (result != NFCSTATUS_SUCCESS)
7975d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         {
7985d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly            /* Error: invalid info field, dropping frame */
7995d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         }
8005d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         break;
8015d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      }
8025d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
8035d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      case PHFRINFC_LLCP_PTYPE_DISC:
8045d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      {
8055d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         /* Handle link disconnection request */
8065d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         result = phFriNfc_Llcp_InternalDeactivate(Llcp);
8075d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         break;
8085d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      }
8095d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
8105d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
8115d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      case PHFRINFC_LLCP_PTYPE_FRMR:
8125d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      {
8135d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         /* TODO: what to do upon reception of FRMR on Link SAP ? */
8145d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         result = NFCSTATUS_SUCCESS;
8155d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         break;
8165d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      }
8175d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
8185d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      case PHFRINFC_LLCP_PTYPE_PAX:
8195d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      {
8205d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         /* Ignore PAX when in Normal Operation */
8215d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         result = NFCSTATUS_SUCCESS;
8225d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         break;
8235d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      }
8245d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
8255d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      default:
8265d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      {
8275d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         /* Error: invalid ptype field, dropping packet */
8285d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         break;
8295d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      }
8305d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   }
8315d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
8325d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   return result;
8335d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly}
8345d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
8355d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
8365d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pellystatic NFCSTATUS phFriNfc_Llcp_HandleTransportPacket( phFriNfc_Llcp_t    *Llcp,
8375d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly                                                      phNfc_sData_t      *psPacket )
8385d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly{
8395d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   phFriNfc_Llcp_Recv_CB_t          pfRecvCB;
8405d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   void                             *pContext;
8415d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   NFCSTATUS                        result = NFCSTATUS_SUCCESS;
8425d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   phFriNfc_Llcp_sPacketHeader_t    sHeader;
8435d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
8445d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Forward to upper layer */
8455d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   if (Llcp->pfRecvCB != NULL)
8465d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   {
8475d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      /* Get callback details */
8485d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      pfRecvCB = Llcp->pfRecvCB;
8495d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      pContext = Llcp->pRecvContext;
8505d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      /* Reset callback details */
8515d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      Llcp->pfRecvCB = NULL;
8525d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      Llcp->pRecvContext = NULL;
8535d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      /* Call the callback */
8545d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      (pfRecvCB)(pContext, psPacket, NFCSTATUS_SUCCESS);
8555d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   }
8565d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
8575d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   return result;
8585d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly}
8595d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
8605d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
8615d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pellystatic bool_t phFriNfc_Llcp_HandlePendingSend ( phFriNfc_Llcp_t *Llcp )
8625d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly{
8635d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   phFriNfc_Llcp_sPacketHeader_t    sHeader;
8645d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   phNfc_sData_t                    sInfoBuffer;
8655d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   phFriNfc_Llcp_sPacketHeader_t    *psSendHeader = NULL;
8665d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   phFriNfc_Llcp_sPacketSequence_t  *psSendSequence = NULL;
8675d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   phNfc_sData_t                    *psSendInfo = NULL;
8685d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   NFCSTATUS                        result;
869f3fc813f66fba3a24ca96007507073c045e17c4bSylvain Fonteneau   uint8_t                          bDeallocate = FALSE;
870f3fc813f66fba3a24ca96007507073c045e17c4bSylvain Fonteneau   uint8_t                          return_value = FALSE;
8715d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Handle pending disconnection request */
8725d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   if (Llcp->bDiscPendingFlag == TRUE)
8735d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   {
8745d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      /* Last send si acheived, send the pending DISC packet */
8755d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      sHeader.dsap  = PHFRINFC_LLCP_SAP_LINK;
8765d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      sHeader.ssap  = PHFRINFC_LLCP_SAP_LINK;
8775d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      sHeader.ptype = PHFRINFC_LLCP_PTYPE_DISC;
8785d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      /* Set send params */
8795d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      psSendHeader = &sHeader;
8805d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      /* Reset flag */
8815d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      Llcp->bDiscPendingFlag = FALSE;
8825d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   }
8835d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Handle pending frame reject request */
8845d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   else if (Llcp->bFrmrPendingFlag == TRUE)
8855d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   {
8865d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      /* Last send si acheived, send the pending FRMR packet */
8875d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      sInfoBuffer.buffer = Llcp->pFrmrInfo;
8885d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      sInfoBuffer.length = sizeof(Llcp->pFrmrInfo);
8895d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      /* Set send params */
8905d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      psSendHeader = &Llcp->sFrmrHeader;
8915d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      psSendInfo   = &sInfoBuffer;
8925d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      /* Reset flag */
8935d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      Llcp->bFrmrPendingFlag = FALSE;
8945d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   }
8955d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Handle pending service frame */
8965d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   else if (Llcp->pfSendCB != NULL)
8975d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   {
8985d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      /* Set send params */
8995d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      psSendHeader = Llcp->psSendHeader;
9005d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      psSendSequence = Llcp->psSendSequence;
9015d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      psSendInfo = Llcp->psSendInfo;
9025d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      /* Reset pending send infos */
9035d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      Llcp->psSendHeader = NULL;
9045d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      Llcp->psSendSequence = NULL;
9055d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      Llcp->psSendInfo = NULL;
906f3fc813f66fba3a24ca96007507073c045e17c4bSylvain Fonteneau      bDeallocate = TRUE;
9075d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   }
9085d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
9095d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Perform send, if needed */
9105d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   if (psSendHeader != NULL)
9115d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   {
9125d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      result = phFriNfc_Llcp_InternalSend(Llcp, psSendHeader, psSendSequence, psSendInfo);
9135d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      if ((result != NFCSTATUS_SUCCESS) && (result != NFCSTATUS_PENDING))
9145d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      {
9155d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         /* Error: send failed, impossible to recover */
9165d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         phFriNfc_Llcp_InternalDeactivate(Llcp);
9175d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      }
918f3fc813f66fba3a24ca96007507073c045e17c4bSylvain Fonteneau      return_value = TRUE;
91954b847c7f7a5bc2e36ebe877ce832cdfefabc733Martijn Coenen   } else if (Llcp->pfSendCB == NULL) {
92054b847c7f7a5bc2e36ebe877ce832cdfefabc733Martijn Coenen      // Nothing to send, send SYMM instead to allow peer to send something
92154b847c7f7a5bc2e36ebe877ce832cdfefabc733Martijn Coenen      // if it wants.
92254b847c7f7a5bc2e36ebe877ce832cdfefabc733Martijn Coenen      phFriNfc_Llcp_SendSymm(Llcp);
92354b847c7f7a5bc2e36ebe877ce832cdfefabc733Martijn Coenen      return_value = TRUE;
924f3fc813f66fba3a24ca96007507073c045e17c4bSylvain Fonteneau   }
925f3fc813f66fba3a24ca96007507073c045e17c4bSylvain Fonteneau
926f3fc813f66fba3a24ca96007507073c045e17c4bSylvain Fonteneauclean_and_return:
927f3fc813f66fba3a24ca96007507073c045e17c4bSylvain Fonteneau   if (bDeallocate)
928f3fc813f66fba3a24ca96007507073c045e17c4bSylvain Fonteneau   {
929f3fc813f66fba3a24ca96007507073c045e17c4bSylvain Fonteneau       phFriNfc_Llcp_Deallocate(psSendInfo);
9305d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   }
9315d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
932f3fc813f66fba3a24ca96007507073c045e17c4bSylvain Fonteneau   return return_value;
9335d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly}
9345d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
9355d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pellystatic NFCSTATUS phFriNfc_Llcp_HandleIncomingPacket( phFriNfc_Llcp_t    *Llcp,
9365d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly                                                     phNfc_sData_t      *psPacket )
9375d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly{
9385d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   NFCSTATUS                        status = NFCSTATUS_SUCCESS;
9395d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   phFriNfc_Llcp_sPacketHeader_t    sHeader;
9405d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
9415d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Parse header */
9425d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   phFriNfc_Llcp_Buffer2Header(psPacket->buffer, 0, &sHeader);
9435d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
9445d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Check destination */
9455d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   if (sHeader.dsap == PHFRINFC_LLCP_SAP_LINK)
9465d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   {
9475d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      /* Handle packet as destinated to the Link SAP */
9485d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      status = phFriNfc_Llcp_HandleLinkPacket(Llcp, psPacket);
9495d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   }
9505d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   else if (sHeader.dsap >= PHFRINFC_LLCP_SAP_NUMBER)
9515d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   {
9525d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly     /* NOTE: this cannot happen since "psHeader->dsap" is only 6-bit wide */
9535d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly     status = NFCSTATUS_FAILED;
9545d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   }
9555d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   else
9565d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   {
9575d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      /* Handle packet as destinated to the SDP and transport SAPs */
9585d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      status = phFriNfc_Llcp_HandleTransportPacket(Llcp, psPacket);
9595d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   }
9605d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   return status;
9615d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly}
9625d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
9635d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
9645d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pellystatic void phFriNfc_Llcp_Receive_CB( void               *pContext,
9655d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly                                      NFCSTATUS          status,
9665d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly                                      phNfc_sData_t      *psData)
9675d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly{
9685d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Get monitor from context */
9695d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   phFriNfc_Llcp_t               *Llcp = (phFriNfc_Llcp_t*)pContext;
9705d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   NFCSTATUS                     result = NFCSTATUS_SUCCESS;
9715d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   phFriNfc_Llcp_sPacketHeader_t sPacketHeader;
9725d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
9735d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Check reception status and for pending disconnection */
9745d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   if ((status != NFCSTATUS_SUCCESS) || (Llcp->bDiscPendingFlag == TRUE))
9755d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   {
976bf52196cdecd0decc2f8deabb19bf5877794bc31daniel_Tomas	  LLCP_DEBUG("\nReceived LLCP packet error - status = 0x%04x", status);
9775d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      /* Reset disconnection operation */
9785d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      Llcp->bDiscPendingFlag = FALSE;
9795d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      /* Deactivate the link */
9805d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      phFriNfc_Llcp_InternalDeactivate(Llcp);
9815d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      return;
9825d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   }
9835d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
98435a9f321a9cb5db0e65b9579d11bee2ac9bb1c54Sylvain Fonteneau   /* Parse header */
98535a9f321a9cb5db0e65b9579d11bee2ac9bb1c54Sylvain Fonteneau   phFriNfc_Llcp_Buffer2Header(psData->buffer, 0, &sPacketHeader);
98635a9f321a9cb5db0e65b9579d11bee2ac9bb1c54Sylvain Fonteneau
987bf52196cdecd0decc2f8deabb19bf5877794bc31daniel_Tomas   if (sPacketHeader.ptype != PHFRINFC_LLCP_PTYPE_SYMM)
988bf52196cdecd0decc2f8deabb19bf5877794bc31daniel_Tomas   {
989bf52196cdecd0decc2f8deabb19bf5877794bc31daniel_Tomas      LLCP_PRINT_BUFFER("\nReceived LLCP packet :", psData->buffer, psData->length);
990bf52196cdecd0decc2f8deabb19bf5877794bc31daniel_Tomas   }
991bf52196cdecd0decc2f8deabb19bf5877794bc31daniel_Tomas   else
992bf52196cdecd0decc2f8deabb19bf5877794bc31daniel_Tomas   {
993bf52196cdecd0decc2f8deabb19bf5877794bc31daniel_Tomas      LLCP_PRINT("?");
994bf52196cdecd0decc2f8deabb19bf5877794bc31daniel_Tomas   }
995bf52196cdecd0decc2f8deabb19bf5877794bc31daniel_Tomas
996bf52196cdecd0decc2f8deabb19bf5877794bc31daniel_Tomas
9975d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Check new link status */
9985d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   switch(Llcp->state)
9995d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   {
10005d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      /* Handle packets in PAX-waiting state */
10015d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      case PHFRINFC_LLCP_STATE_PAX:
10025d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      {
10035d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         /* Check packet type */
10045d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         if (sPacketHeader.ptype == PHFRINFC_LLCP_PTYPE_PAX)
10055d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         {
10065d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly            /* Params exchanged during MAC activation, try LLC activation */
10075d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly            result = phFriNfc_Llcp_InternalActivate(Llcp, psData+PHFRINFC_LLCP_PACKET_HEADER_SIZE);
10085d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly            /* If the local LLC is the target, it must answer the PAX */
10095d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly            if (Llcp->eRole == phFriNfc_LlcpMac_ePeerTypeTarget)
10105d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly            {
10115d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly               /* Send PAX */
10125d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly               result = phFriNfc_Llcp_SendPax(Llcp, &Llcp->sLocalParams);
10135d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly            }
10145d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         }
10155d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         else
10165d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         {
10175d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly            /* Warning: Received packet with unhandled type in PAX-waiting state, drop it */
10185d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         }
10195d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         break;
10205d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      }
10215d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
10225d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      /* Handle normal operation packets */
10235d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      case PHFRINFC_LLCP_STATE_OPERATION_RECV:
10245d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      case PHFRINFC_LLCP_STATE_OPERATION_SEND:
10255d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      {
10265d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         /* Handle Symmetry procedure by resetting LTO timer */
10275d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         phFriNfc_Llcp_ResetLTO(Llcp);
10285d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         /* Handle packet */
10295d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         result = phFriNfc_Llcp_HandleIncomingPacket(Llcp, psData);
10305d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         if ( (result != NFCSTATUS_SUCCESS) &&
10315d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly              (result != NFCSTATUS_PENDING) )
10325d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         {
10335d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly            /* TODO: Error: invalid frame */
10345d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         }
10355d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         /* Perform pending send request, if any */
10365d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         phFriNfc_Llcp_HandlePendingSend(Llcp);
10375d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         break;
10385d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      }
10395d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
10405d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      default:
10415d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      {
10425d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         /* Warning: Should not receive packets in other states, drop them */
10435d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      }
10445d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   }
10455d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
10465d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Restart reception */
10475d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   Llcp->sRxBuffer.length = Llcp->nRxBufferLength;
10485d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   phFriNfc_LlcpMac_Receive(&Llcp->MAC, &Llcp->sRxBuffer, phFriNfc_Llcp_Receive_CB, Llcp);
10495d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly}
10505d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
10515d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
10525d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pellystatic void phFriNfc_Llcp_Send_CB( void               *pContext,
10535d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly                                   NFCSTATUS          status )
10545d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly{
10555d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Get monitor from context */
10565d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   phFriNfc_Llcp_t                  *Llcp = (phFriNfc_Llcp_t*)pContext;
10575d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   phFriNfc_Llcp_Send_CB_t          pfSendCB;
10585d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   void                             *pSendContext;
10595d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
10605d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Call the upper layer callback if last packet sent was  */
10615d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* NOTE: if Llcp->psSendHeader is not NULL, this means that the send operation is still not initiated */
10625d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   if (Llcp->psSendHeader == NULL)
10635d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   {
10645d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      if (Llcp->pfSendCB != NULL)
10655d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      {
10665d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         /* Get Callback params */
10675d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         pfSendCB = Llcp->pfSendCB;
10685d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         pSendContext = Llcp->pSendContext;
10695d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         /* Reset callback params */
10705d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         Llcp->pfSendCB = NULL;
10715d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         Llcp->pSendContext = NULL;
10725d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         /* Call the callback */
10735d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         (pfSendCB)(pSendContext, status);
10745d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      }
10755d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   }
107628ab3385d05d10437c6b1f0168bab6ed71bf4bfdSylvain Fonteneau
107728ab3385d05d10437c6b1f0168bab6ed71bf4bfdSylvain Fonteneau   /* Check reception status */
107828ab3385d05d10437c6b1f0168bab6ed71bf4bfdSylvain Fonteneau   if (status != NFCSTATUS_SUCCESS)
107928ab3385d05d10437c6b1f0168bab6ed71bf4bfdSylvain Fonteneau   {
108028ab3385d05d10437c6b1f0168bab6ed71bf4bfdSylvain Fonteneau       /* Error: Reception failed, link must be down */
108128ab3385d05d10437c6b1f0168bab6ed71bf4bfdSylvain Fonteneau       phFriNfc_Llcp_InternalDeactivate(Llcp);
108228ab3385d05d10437c6b1f0168bab6ed71bf4bfdSylvain Fonteneau   }
10835d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly}
10845d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
10855d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
10865d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pellystatic NFCSTATUS phFriNfc_Llcp_InternalSend( phFriNfc_Llcp_t                    *Llcp,
10875d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly                                             phFriNfc_Llcp_sPacketHeader_t      *psHeader,
10885d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly                                             phFriNfc_Llcp_sPacketSequence_t    *psSequence,
10895d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly                                             phNfc_sData_t                      *psInfo )
10905d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly{
10915d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   NFCSTATUS status;
10925d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   phNfc_sData_t  *psRawPacket = &Llcp->sTxBuffer; /* Use internal Tx buffer */
10935d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
10945d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Handle Symmetry procedure */
10955d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   phFriNfc_Llcp_ResetLTO(Llcp);
10965d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
10975d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Generate raw packet to send (aggregate header + sequence + info fields) */
10985d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   psRawPacket->length = 0;
10995d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   psRawPacket->length += phFriNfc_Llcp_Header2Buffer(psHeader, psRawPacket->buffer, psRawPacket->length);
11005d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   if (psSequence != NULL)
11015d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   {
11025d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      psRawPacket->length += phFriNfc_Llcp_Sequence2Buffer(psSequence, psRawPacket->buffer, psRawPacket->length);
11035d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   }
11045d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   if (psInfo != NULL)
11055d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   {
11065d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      memcpy(psRawPacket->buffer + psRawPacket->length, psInfo->buffer, psInfo->length);
11075d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      psRawPacket->length += psInfo->length;
11085d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   }
11095d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
11105d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   if (psHeader->ptype != PHFRINFC_LLCP_PTYPE_SYMM)
11115d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   {
11125d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      LLCP_PRINT_BUFFER("\nSending LLCP packet :", psRawPacket->buffer, psRawPacket->length);
11135d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   }
11145d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   else
11155d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   {
11165d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      LLCP_PRINT("!");
11175d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   }
11185d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
11195d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Send raw packet */
11205d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   status = phFriNfc_LlcpMac_Send (
11215d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly               &Llcp->MAC,
11225d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly               psRawPacket,
11235d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly               phFriNfc_Llcp_Send_CB,
11245d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly               Llcp );
11255d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
11265d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   return status;
11275d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly}
11285d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
11295d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly/* ---------------------------- Public functions ------------------------------- */
11305d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
11315d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick PellyNFCSTATUS phFriNfc_Llcp_EncodeLinkParams( phNfc_sData_t                   *psRawBuffer,
11325d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly                                          phFriNfc_Llcp_sLinkParameters_t *psLinkParams,
11335d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly                                          uint8_t                         nVersion )
11345d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly{
11355d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   uint32_t    nOffset = 0;
11365d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   uint16_t    miux;
11375d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   uint16_t    wks;
11385d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   uint8_t     pValue[2];
11395d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   NFCSTATUS   result = NFCSTATUS_SUCCESS;
11405d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
11415d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Check parameters */
11425d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   if ((psRawBuffer == NULL) || (psLinkParams == NULL))
11435d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   {
11445d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      return NFCSTATUS_INVALID_PARAMETER;
11455d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   }
11465d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
11475d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Encode mandatory VERSION field */
11485d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   if (result == NFCSTATUS_SUCCESS)
11495d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   {
11505d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      result = phFriNfc_Llcp_EncodeTLV(
11515d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly                  psRawBuffer,
11525d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly                  &nOffset,
11535d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly                  PHFRINFC_LLCP_TLV_TYPE_VERSION,
11545d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly                  PHFRINFC_LLCP_TLV_LENGTH_VERSION,
11555d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly                  &nVersion);
11565d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   }
11575d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
11585d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Encode mandatory VERSION field */
11595d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   if (result == NFCSTATUS_SUCCESS)
11605d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   {
11615d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      /* Encode MIUX field, if needed */
11625d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      if (psLinkParams->miu != PHFRINFC_LLCP_MIU_DEFAULT)
11635d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      {
11645d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         miux = (psLinkParams->miu - PHFRINFC_LLCP_MIU_DEFAULT) & PHFRINFC_LLCP_TLV_MIUX_MASK;
11655d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         pValue[0] = (miux >> 8) & 0xFF;
11665d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         pValue[1] =  miux       & 0xFF;
11675d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         result = phFriNfc_Llcp_EncodeTLV(
11685d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly                     psRawBuffer,
11695d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly                     &nOffset,
11705d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly                     PHFRINFC_LLCP_TLV_TYPE_MIUX,
11715d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly                     PHFRINFC_LLCP_TLV_LENGTH_MIUX,
11725d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly                     pValue);
11735d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      }
11745d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   }
11755d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
11765d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Encode WKS field */
11775d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   if (result == NFCSTATUS_SUCCESS)
11785d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   {
11795d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      wks = psLinkParams->wks | PHFRINFC_LLCP_TLV_WKS_MASK;
11805d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      pValue[0] = (wks >> 8) & 0xFF;
11815d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      pValue[1] =  wks       & 0xFF;
11825d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      result = phFriNfc_Llcp_EncodeTLV(
11835d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly                  psRawBuffer,
11845d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly                  &nOffset,
11855d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly                  PHFRINFC_LLCP_TLV_TYPE_WKS,
11865d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly                  PHFRINFC_LLCP_TLV_LENGTH_WKS,
11875d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly                  pValue);
11885d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   }
11895d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
11905d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Encode LTO field, if needed */
11915d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   if (result == NFCSTATUS_SUCCESS)
11925d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   {
11935d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      if (psLinkParams->lto != PHFRINFC_LLCP_LTO_DEFAULT)
11945d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      {
11955d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         result = phFriNfc_Llcp_EncodeTLV(
11965d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly                     psRawBuffer,
11975d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly                     &nOffset,
11985d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly                     PHFRINFC_LLCP_TLV_TYPE_LTO,
11995d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly                     PHFRINFC_LLCP_TLV_LENGTH_LTO,
12005d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly                     &psLinkParams->lto);
12015d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      }
12025d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   }
12035d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
12045d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Encode OPT field, if needed */
12055d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   if (result == NFCSTATUS_SUCCESS)
12065d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   {
12075d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      if (psLinkParams->option != PHFRINFC_LLCP_OPTION_DEFAULT)
12085d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      {
12095d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly         result = phFriNfc_Llcp_EncodeTLV(
12105d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly                     psRawBuffer,
12115d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly                     &nOffset,
12125d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly                     PHFRINFC_LLCP_TLV_TYPE_OPT,
12135d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly                     PHFRINFC_LLCP_TLV_LENGTH_OPT,
12145d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly                     &psLinkParams->option);
12155d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      }
12165d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   }
12175d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
12185d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   if (result != NFCSTATUS_SUCCESS)
12195d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   {
12205d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      /* Error: failed to encode TLV */
12215d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      return NFCSTATUS_FAILED;
12225d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   }
12235d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
12245d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Save new buffer size */
12255d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   psRawBuffer->length = nOffset;
12265d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
12275d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   return result;
12285d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly}
12295d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
12305d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
12315d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick PellyNFCSTATUS phFriNfc_Llcp_Reset( phFriNfc_Llcp_t                 *Llcp,
12325d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly                               void                            *LowerDevice,
12335d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly                               phFriNfc_Llcp_sLinkParameters_t *psLinkParams,
12345d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly                               void                            *pRxBuffer,
12355d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly                               uint16_t                        nRxBufferLength,
12365d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly                               void                            *pTxBuffer,
12375d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly                               uint16_t                        nTxBufferLength,
12385d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly                               phFriNfc_Llcp_LinkStatus_CB_t   pfLink_CB,
12395d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly                               void                            *pContext )
12405d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly{
12415d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   const uint16_t nMaxHeaderSize =  PHFRINFC_LLCP_PACKET_HEADER_SIZE +
12425d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly                                    PHFRINFC_LLCP_PACKET_SEQUENCE_SIZE;
12435d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   NFCSTATUS result;
12445d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
12455d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Check parameters presence */
12465d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   if ((Llcp == NULL) || (LowerDevice == NULL) || (pfLink_CB == NULL) ||
12475d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly       (pRxBuffer == NULL) || (pTxBuffer == NULL) )
12485d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   {
12495d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      return NFCSTATUS_INVALID_PARAMETER;
12505d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   }
12515d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
12525d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Check parameters value */
12535d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   if (psLinkParams->miu < PHFRINFC_LLCP_MIU_DEFAULT)
12545d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   {
12555d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      return NFCSTATUS_INVALID_PARAMETER;
12565d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   }
12575d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
12585d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Check if buffers are large enough to support minimal MIU */
12595d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   if ((nRxBufferLength < (nMaxHeaderSize + PHFRINFC_LLCP_MIU_DEFAULT)) ||
12605d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly       (nTxBufferLength < (nMaxHeaderSize + PHFRINFC_LLCP_MIU_DEFAULT)) )
12615d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   {
12625d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      return NFCSTATUS_BUFFER_TOO_SMALL;
12635d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   }
12645d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
12655d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Check compatibility between reception buffer size and announced MIU */
12665d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   if (nRxBufferLength < (nMaxHeaderSize + psLinkParams->miu))
12675d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   {
12685d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      return NFCSTATUS_BUFFER_TOO_SMALL;
12695d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   }
12705d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
12715d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Start with a zero-filled monitor */
12725d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   memset(Llcp, 0x00, sizeof(phFriNfc_Llcp_t));
12735d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
12745d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Reset the MAC Mapping layer */
12755d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   result = phFriNfc_LlcpMac_Reset(&Llcp->MAC, LowerDevice, phFriNfc_Llcp_LinkStatus_CB, Llcp);
12765d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   if (result != NFCSTATUS_SUCCESS) {
12775d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      return result;
12785d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   }
12795d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
12805d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Save the working buffers */
12815d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   Llcp->sRxBuffer.buffer = pRxBuffer;
12825d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   Llcp->sRxBuffer.length = nRxBufferLength;
12835d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   Llcp->nRxBufferLength = nRxBufferLength;
12845d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   Llcp->sTxBuffer.buffer = pTxBuffer;
12855d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   Llcp->sTxBuffer.length = nTxBufferLength;
12865d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   Llcp->nTxBufferLength = nTxBufferLength;
12875d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
12885d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Save the link status callback references */
12895d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   Llcp->pfLink_CB = pfLink_CB;
12905d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   Llcp->pLinkContext = pContext;
12915d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
12925d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Save the local link parameters */
12935d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   memcpy(&Llcp->sLocalParams, psLinkParams, sizeof(phFriNfc_Llcp_sLinkParameters_t));
12945d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
12955d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   return NFCSTATUS_SUCCESS;
12965d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly}
12975d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
12985d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
12995d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick PellyNFCSTATUS phFriNfc_Llcp_ChkLlcp( phFriNfc_Llcp_t               *Llcp,
13005d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly                                 phHal_sRemoteDevInformation_t *psRemoteDevInfo,
13015d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly                                 phFriNfc_Llcp_Check_CB_t      pfCheck_CB,
13025d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly                                 void                          *pContext )
13035d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly{
13045d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Check parameters */
13055d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   if ( (Llcp == NULL) || (psRemoteDevInfo == NULL) || (pfCheck_CB == NULL) )
13065d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   {
13075d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      return PHNFCSTVAL(CID_FRI_NFC_LLCP, NFCSTATUS_INVALID_PARAMETER);
13085d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   }
13095d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
13105d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Check current state */
13115d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   if( Llcp->state != PHFRINFC_LLCP_STATE_RESET_INIT ) {
13125d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      return PHNFCSTVAL(CID_FRI_NFC_LLCP, NFCSTATUS_INVALID_STATE);
13135d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   }
13145d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
13155d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Save the compliance check callback */
13165d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   Llcp->pfChk_CB = pfCheck_CB;
13175d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   Llcp->pChkContext = pContext;
13185d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
13195d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Forward check request to MAC layer */
13205d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   return phFriNfc_LlcpMac_ChkLlcp(&Llcp->MAC, psRemoteDevInfo, phFriNfc_Llcp_ChkLlcp_CB, (void*)Llcp);
13215d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly}
13225d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
13235d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
13245d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick PellyNFCSTATUS phFriNfc_Llcp_Activate( phFriNfc_Llcp_t *Llcp )
13255d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly{
13265d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Check parameters */
13275d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   if (Llcp == NULL)
13285d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   {
13295d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      return PHNFCSTVAL(CID_FRI_NFC_LLCP, NFCSTATUS_INVALID_PARAMETER);
13305d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   }
13315d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
13325d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Check current state */
13335d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   if( Llcp->state != PHFRINFC_LLCP_STATE_CHECKED ) {
13345d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      return PHNFCSTVAL(CID_FRI_NFC_LLCP, NFCSTATUS_INVALID_STATE);
13355d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   }
13365d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
13375d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Update state */
13385d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   Llcp->state = PHFRINFC_LLCP_STATE_ACTIVATION;
13395d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
13403cbab5882f6d89a52068a3fa72a7223971d6b7fdMartijn Coenen   /* Reset any headers to send */
13413cbab5882f6d89a52068a3fa72a7223971d6b7fdMartijn Coenen   Llcp->psSendHeader = NULL;
13423cbab5882f6d89a52068a3fa72a7223971d6b7fdMartijn Coenen   Llcp->psSendSequence = NULL;
13433cbab5882f6d89a52068a3fa72a7223971d6b7fdMartijn Coenen
13445d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Forward check request to MAC layer */
13455d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   return phFriNfc_LlcpMac_Activate(&Llcp->MAC);
13465d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly}
13475d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
13485d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
13495d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick PellyNFCSTATUS phFriNfc_Llcp_Deactivate( phFriNfc_Llcp_t *Llcp )
13505d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly{
13515d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   NFCSTATUS status;
13525d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
13535d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Check parameters */
13545d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   if (Llcp == NULL)
13555d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   {
13565d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      return PHNFCSTVAL(CID_FRI_NFC_LLCP, NFCSTATUS_INVALID_PARAMETER);
13575d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   }
13585d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
13595d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Check current state */
13605d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   if( (Llcp->state != PHFRINFC_LLCP_STATE_OPERATION_RECV) &&
13615d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly       (Llcp->state != PHFRINFC_LLCP_STATE_OPERATION_SEND) ) {
13625d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      return PHNFCSTVAL(CID_FRI_NFC_LLCP, NFCSTATUS_INVALID_STATE);
13635d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   }
13645d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
13655d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Send DISC packet */
13665d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   status = phFriNfc_Llcp_SendDisconnect(Llcp);
13675d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   if (status == NFCSTATUS_PENDING)
13685d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   {
13695d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      /* Wait for packet to be sent before deactivate link */
13705d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      return status;
13715d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   }
13725d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
13735d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Perform actual deactivation */
13745d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   return phFriNfc_Llcp_InternalDeactivate(Llcp);
13755d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly}
13765d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
13775d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
13785d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick PellyNFCSTATUS phFriNfc_Llcp_GetLocalInfo( phFriNfc_Llcp_t                   *Llcp,
13795d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly                                      phFriNfc_Llcp_sLinkParameters_t   *pParams )
13805d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly{
13815d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Check parameters */
13825d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   if ((Llcp == NULL) || (pParams == NULL))
13835d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   {
13845d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      return PHNFCSTVAL(CID_FRI_NFC_LLCP, NFCSTATUS_INVALID_PARAMETER);
13855d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   }
13865d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
13875d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Copy response */
13885d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   memcpy(pParams, &Llcp->sLocalParams, sizeof(phFriNfc_Llcp_sLinkParameters_t));
13895d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
13905d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   return NFCSTATUS_SUCCESS;
13915d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly}
13925d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
13935d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
13945d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick PellyNFCSTATUS phFriNfc_Llcp_GetRemoteInfo( phFriNfc_Llcp_t                  *Llcp,
13955d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly                                       phFriNfc_Llcp_sLinkParameters_t  *pParams )
13965d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly{
13975d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Check parameters */
13985d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   if ((Llcp == NULL) || (pParams == NULL))
13995d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   {
14005d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      return PHNFCSTVAL(CID_FRI_NFC_LLCP, NFCSTATUS_INVALID_PARAMETER);
14015d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   }
14025d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
14035d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Copy response */
14045d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   memcpy(pParams, &Llcp->sRemoteParams, sizeof(phFriNfc_Llcp_sLinkParameters_t));
14055d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
14065d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   return NFCSTATUS_SUCCESS;
14075d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly}
14085d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
14095d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
14105d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick PellyNFCSTATUS phFriNfc_Llcp_Send( phFriNfc_Llcp_t                  *Llcp,
14115d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly                              phFriNfc_Llcp_sPacketHeader_t    *psHeader,
14125d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly                              phFriNfc_Llcp_sPacketSequence_t  *psSequence,
14135d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly                              phNfc_sData_t                    *psInfo,
14145d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly                              phFriNfc_Llcp_Send_CB_t          pfSend_CB,
14155d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly                              void                             *pContext )
14165d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly{
14175d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   NFCSTATUS result;
14185d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Check parameters */
14195d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   if ((Llcp == NULL) || (psHeader == NULL) || (pfSend_CB == NULL))
14205d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   {
14215d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      return PHNFCSTVAL(CID_FRI_NFC_LLCP, NFCSTATUS_INVALID_PARAMETER);
14225d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   }
14235d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
14245d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Check if previous phFriNfc_Llcp_Send() has finished */
14255d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   if (Llcp->pfSendCB != NULL)
14265d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   {
14275d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      /* Error: a send operation is already running */
14285d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      return PHNFCSTVAL(CID_FRI_NFC_LLCP, NFCSTATUS_REJECTED);
14295d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   }
14305d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
14315d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Save the callback parameters */
14325d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   Llcp->pfSendCB = pfSend_CB;
14335d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   Llcp->pSendContext = pContext;
14345d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
14351927b9d35c5efe26676c1dae78e3d1ab906f7586Sylvain Fonteneau   if (Llcp->state == PHFRINFC_LLCP_STATE_OPERATION_SEND)
14361927b9d35c5efe26676c1dae78e3d1ab906f7586Sylvain Fonteneau   {
14371927b9d35c5efe26676c1dae78e3d1ab906f7586Sylvain Fonteneau      /* Ready to send */
14381927b9d35c5efe26676c1dae78e3d1ab906f7586Sylvain Fonteneau      result = phFriNfc_Llcp_InternalSend(Llcp, psHeader, psSequence, psInfo);
14391927b9d35c5efe26676c1dae78e3d1ab906f7586Sylvain Fonteneau   }
14401927b9d35c5efe26676c1dae78e3d1ab906f7586Sylvain Fonteneau   else if (Llcp->state == PHFRINFC_LLCP_STATE_OPERATION_RECV)
14415d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   {
14425d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      /* Not ready to send, save send params for later use */
14435d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      Llcp->psSendHeader = psHeader;
14445d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      Llcp->psSendSequence = psSequence;
1445f3fc813f66fba3a24ca96007507073c045e17c4bSylvain Fonteneau      Llcp->psSendInfo = phFriNfc_Llcp_AllocateAndCopy(psInfo);
14465d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      result = NFCSTATUS_PENDING;
14475d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   }
14485d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   else
14495d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   {
14501927b9d35c5efe26676c1dae78e3d1ab906f7586Sylvain Fonteneau      /* Incorrect state for sending ! */
14511927b9d35c5efe26676c1dae78e3d1ab906f7586Sylvain Fonteneau      result = PHNFCSTVAL(CID_FRI_NFC_LLCP, NFCSTATUS_INVALID_STATE);;
14525d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   }
145345101265f65461385bd7c81db0bfc84b334df8e0Martijn Coenen
145445101265f65461385bd7c81db0bfc84b334df8e0Martijn Coenen   if (result != NFCSTATUS_PENDING) {
145545101265f65461385bd7c81db0bfc84b334df8e0Martijn Coenen       Llcp->pfSendCB = NULL;
145645101265f65461385bd7c81db0bfc84b334df8e0Martijn Coenen   }
14575d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   return result;
14585d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly}
14595d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
14605d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
14615d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick PellyNFCSTATUS phFriNfc_Llcp_Recv( phFriNfc_Llcp_t            *Llcp,
14625d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly                              phFriNfc_Llcp_Recv_CB_t    pfRecv_CB,
14635d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly                              void                       *pContext )
14645d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly{
14655d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   NFCSTATUS result = NFCSTATUS_SUCCESS;
14665d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
14675d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Check parameters */
14685d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   if ((Llcp == NULL) || (pfRecv_CB == NULL))
14695d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   {
14705d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      return PHNFCSTVAL(CID_FRI_NFC_LLCP, NFCSTATUS_INVALID_PARAMETER);
14715d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   }
14725d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
14735d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Check if previous phFriNfc_Llcp_Recv() has finished */
14745d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   if (Llcp->pfRecvCB != NULL)
14755d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   {
14765d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      /* Error: a send operation is already running */
14775d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly      return PHNFCSTVAL(CID_FRI_NFC_LLCP, NFCSTATUS_REJECTED);
14785d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   }
14795d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
14805d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* Save the callback parameters */
14815d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   Llcp->pfRecvCB = pfRecv_CB;
14825d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   Llcp->pRecvContext = pContext;
14835d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
14845d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   /* NOTE: nothing more to do, the receive function is called in background */
14855d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly
14865d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly   return result;
14875d9927ba30ba449badb9f6df0fbeb4d6aedc6e2aNick Pelly}
1488