1/*
2 * Copyright (C) 2010 NXP Semiconductors
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/**
18 * \file  phFriNfc_Llcp.c
19 * \brief NFC LLCP core
20 *
21 * Project: NFC-FRI
22 *
23 */
24
25/*include files*/
26#include <phNfcLlcpTypes.h>
27#include <phOsalNfc_Timer.h>
28
29#include <phFriNfc_Llcp.h>
30#include <phFriNfc_LlcpUtils.h>
31
32/**
33 * \internal
34 * \name States of the LLC state machine.
35 *
36 */
37/*@{*/
38#define PHFRINFC_LLCP_STATE_RESET_INIT               0   /**< \internal Initial state.*/
39#define PHFRINFC_LLCP_STATE_CHECKED                  1   /**< \internal The tag has been checked for LLCP compliance.*/
40#define PHFRINFC_LLCP_STATE_ACTIVATION               2   /**< \internal The deactivation phase.*/
41#define PHFRINFC_LLCP_STATE_PAX                      3   /**< \internal Parameter exchange phase.*/
42#define PHFRINFC_LLCP_STATE_OPERATION_RECV           4   /**< \internal Normal operation phase (ready to receive).*/
43#define PHFRINFC_LLCP_STATE_OPERATION_SEND           5   /**< \internal Normal operation phase (ready to send).*/
44#define PHFRINFC_LLCP_STATE_DEACTIVATION             6   /**< \internal The deactivation phase.*/
45/*@}*/
46
47/**
48 * \internal
49 * \name Masks used for VERSION parsing.
50 *
51 */
52/*@{*/
53#define PHFRINFC_LLCP_VERSION_MAJOR_MASK            0xF0    /**< \internal Mask to apply to get major version number.*/
54#define PHFRINFC_LLCP_VERSION_MINOR_MASK            0x0F    /**< \internal Mask to apply to get major version number.*/
55/*@}*/
56
57/**
58 * \internal
59 * \name Invalid values for parameters.
60 *
61 */
62/*@{*/
63#define PHFRINFC_LLCP_INVALID_VERSION              0x00   /**< \internal Invalid VERSION value.*/
64/*@}*/
65
66/**
67 * \internal
68 * \name Internal constants.
69 *
70 */
71/*@{*/
72#define PHFRINFC_LLCP_MAX_PARAM_TLV_LENGTH \
73   (( PHFRINFC_LLCP_TLV_LENGTH_HEADER + PHFRINFC_LLCP_TLV_LENGTH_VERSION ) + \
74    ( PHFRINFC_LLCP_TLV_LENGTH_HEADER + PHFRINFC_LLCP_TLV_LENGTH_MIUX ) + \
75    ( PHFRINFC_LLCP_TLV_LENGTH_HEADER + PHFRINFC_LLCP_TLV_LENGTH_WKS ) + \
76    ( PHFRINFC_LLCP_TLV_LENGTH_HEADER + PHFRINFC_LLCP_TLV_LENGTH_LTO ) + \
77    ( PHFRINFC_LLCP_TLV_LENGTH_HEADER + PHFRINFC_LLCP_TLV_LENGTH_OPT ))   /**< \internal Maximum size of link params TLV.*/
78/*@}*/
79
80
81
82/* --------------------------- Internal functions ------------------------------ */
83
84static void phFriNfc_Llcp_Receive_CB( void               *pContext,
85                                      NFCSTATUS          status,
86                                      phNfc_sData_t      *psData);
87static NFCSTATUS phFriNfc_Llcp_HandleIncomingPacket( phFriNfc_Llcp_t    *Llcp,
88                                                     phNfc_sData_t      *psPacket );
89static void phFriNfc_Llcp_ResetLTO( phFriNfc_Llcp_t *Llcp );
90static NFCSTATUS phFriNfc_Llcp_InternalSend( phFriNfc_Llcp_t                    *Llcp,
91                                             phFriNfc_Llcp_sPacketHeader_t      *psHeader,
92                                             phFriNfc_Llcp_sPacketSequence_t    *psSequence,
93                                             phNfc_sData_t                      *psInfo );
94static bool_t phFriNfc_Llcp_HandlePendingSend ( phFriNfc_Llcp_t *Llcp );
95
96static phNfc_sData_t * phFriNfc_Llcp_AllocateAndCopy(phNfc_sData_t * pOrig)
97{
98   phNfc_sData_t * pDest = NULL;
99
100   if (pOrig == NULL)
101   {
102       return NULL;
103   }
104
105   pDest = phOsalNfc_GetMemory(sizeof(phNfc_sData_t));
106   if (pDest == NULL)
107   {
108      goto error;
109   }
110
111   pDest->buffer = phOsalNfc_GetMemory(pOrig->length);
112   if (pDest->buffer == NULL)
113   {
114      goto error;
115   }
116
117   memcpy(pDest->buffer, pOrig->buffer, pOrig->length);
118   pDest->length = pOrig->length;
119
120   return pDest;
121
122error:
123   if (pDest != NULL)
124   {
125      if (pDest->buffer != NULL)
126      {
127         phOsalNfc_FreeMemory(pDest->buffer);
128      }
129      phOsalNfc_FreeMemory(pDest);
130   }
131   return NULL;
132}
133
134static void phFriNfc_Llcp_Deallocate(phNfc_sData_t * pData)
135{
136   if (pData != NULL)
137   {
138      if (pData->buffer != NULL)
139      {
140         phOsalNfc_FreeMemory(pData->buffer);
141      }
142      else
143      {
144         LLCP_PRINT("Warning, deallocating empty buffer");
145      }
146      phOsalNfc_FreeMemory(pData);
147   }
148}
149
150static NFCSTATUS phFriNfc_Llcp_InternalDeactivate( phFriNfc_Llcp_t *Llcp )
151{
152   phFriNfc_Llcp_Send_CB_t pfSendCB;
153   void * pSendContext;
154   if ((Llcp->state == PHFRINFC_LLCP_STATE_OPERATION_RECV) ||
155       (Llcp->state == PHFRINFC_LLCP_STATE_OPERATION_SEND) ||
156       (Llcp->state == PHFRINFC_LLCP_STATE_PAX)            ||
157       (Llcp->state == PHFRINFC_LLCP_STATE_ACTIVATION))
158   {
159      /* Update state */
160      Llcp->state = PHFRINFC_LLCP_STATE_DEACTIVATION;
161
162      /* Stop timer */
163      phOsalNfc_Timer_Stop(Llcp->hSymmTimer);
164
165      Llcp->psSendHeader = NULL;
166      Llcp->psSendSequence = NULL;
167      /* Return delayed send operation in error, in any */
168      if (Llcp->psSendInfo != NULL)
169      {
170         phFriNfc_Llcp_Deallocate(Llcp->psSendInfo);
171         Llcp->psSendInfo = NULL;
172      }
173      if (Llcp->pfSendCB != NULL)
174      {
175         /* Get Callback params */
176         pfSendCB = Llcp->pfSendCB;
177         pSendContext = Llcp->pSendContext;
178         /* Reset callback params */
179         Llcp->pfSendCB = NULL;
180         Llcp->pSendContext = NULL;
181         /* Call the callback */
182         (pfSendCB)(pSendContext, NFCSTATUS_FAILED);
183      }
184
185      /* Notify service layer */
186      Llcp->pfLink_CB(Llcp->pLinkContext, phFriNfc_LlcpMac_eLinkDeactivated);
187
188      /* Forward check request to MAC layer */
189      return phFriNfc_LlcpMac_Deactivate(&Llcp->MAC);
190   }
191
192   return NFCSTATUS_SUCCESS;
193}
194
195
196static NFCSTATUS phFriNfc_Llcp_SendSymm( phFriNfc_Llcp_t *Llcp )
197{
198   phFriNfc_Llcp_sPacketHeader_t sHeader;
199
200   sHeader.dsap  = PHFRINFC_LLCP_SAP_LINK;
201   sHeader.ssap  = PHFRINFC_LLCP_SAP_LINK;
202   sHeader.ptype = PHFRINFC_LLCP_PTYPE_SYMM;
203   return phFriNfc_Llcp_InternalSend(Llcp, &sHeader, NULL, NULL);
204}
205
206
207static NFCSTATUS phFriNfc_Llcp_SendPax( phFriNfc_Llcp_t *Llcp, phFriNfc_Llcp_sLinkParameters_t *psLinkParams)
208{
209   uint8_t                       pTLVBuffer[PHFRINFC_LLCP_MAX_PARAM_TLV_LENGTH];
210   phNfc_sData_t                 sParamsTLV;
211   phFriNfc_Llcp_sPacketHeader_t sHeader;
212   NFCSTATUS                     result;
213
214   /* Prepare link parameters TLV */
215   sParamsTLV.buffer = pTLVBuffer;
216   sParamsTLV.length = PHFRINFC_LLCP_MAX_PARAM_TLV_LENGTH;
217   result = phFriNfc_Llcp_EncodeLinkParams(&sParamsTLV, psLinkParams, PHFRINFC_LLCP_VERSION);
218   if (result != NFCSTATUS_SUCCESS)
219   {
220      /* Error while encoding */
221      return NFCSTATUS_FAILED;
222   }
223
224   /* Check if ready to send */
225   if (Llcp->state != PHFRINFC_LLCP_STATE_OPERATION_SEND)
226   {
227      /* No send pending, send the PAX packet */
228      sHeader.dsap  = PHFRINFC_LLCP_SAP_LINK;
229      sHeader.ssap  = PHFRINFC_LLCP_SAP_LINK;
230      sHeader.ptype = PHFRINFC_LLCP_PTYPE_PAX;
231      return phFriNfc_Llcp_InternalSend(Llcp, &sHeader, NULL, &sParamsTLV);
232   }
233   else
234   {
235      /* Error: A send is already pending, cannot send PAX */
236      /* NOTE: this should not happen since PAX are sent before any other packet ! */
237      return NFCSTATUS_FAILED;
238   }
239}
240
241
242static NFCSTATUS phFriNfc_Llcp_SendDisconnect( phFriNfc_Llcp_t *Llcp )
243{
244   phFriNfc_Llcp_sPacketHeader_t sHeader;
245
246   /* Check if ready to send */
247   if (Llcp->state != PHFRINFC_LLCP_STATE_OPERATION_SEND)
248   {
249      /* No send pending, send the DISC packet */
250      sHeader.dsap  = PHFRINFC_LLCP_SAP_LINK;
251      sHeader.ssap  = PHFRINFC_LLCP_SAP_LINK;
252      sHeader.ptype = PHFRINFC_LLCP_PTYPE_DISC;
253      return phFriNfc_Llcp_InternalSend(Llcp, &sHeader, NULL, NULL);
254   }
255   else
256   {
257      /* A send is already pending, raise a flag to send DISC as soon as possible */
258      Llcp->bDiscPendingFlag = TRUE;
259      return NFCSTATUS_PENDING;
260   }
261}
262
263
264static void phFriNfc_Llcp_Timer_CB(uint32_t TimerId, void *pContext)
265{
266   phFriNfc_Llcp_t               *Llcp = (phFriNfc_Llcp_t*)pContext;
267
268   PHNFC_UNUSED_VARIABLE(TimerId);
269
270   /* Check current state */
271   if (Llcp->state == PHFRINFC_LLCP_STATE_OPERATION_RECV)
272   {
273      /* No data is coming before LTO, disconnecting */
274      phFriNfc_Llcp_InternalDeactivate(Llcp);
275   }
276   else if (Llcp->state == PHFRINFC_LLCP_STATE_OPERATION_SEND)
277   {
278      /* Send SYMM */
279      phFriNfc_Llcp_SendSymm(Llcp);
280   }
281   else
282   {
283      /* Nothing to do if not in Normal Operation state */
284   }
285}
286
287
288static NFCSTATUS phFriNfc_Llcp_HandleAggregatedPacket( phFriNfc_Llcp_t *Llcp,
289                                                       phNfc_sData_t *psRawPacket )
290{
291   phNfc_sData_t  sInfo;
292   phNfc_sData_t  sCurrentInfo;
293   uint16_t       length;
294   NFCSTATUS      status;
295
296   /* Get info field */
297   sInfo.buffer = psRawPacket->buffer + PHFRINFC_LLCP_PACKET_HEADER_SIZE;
298   sInfo.length = psRawPacket->length - PHFRINFC_LLCP_PACKET_HEADER_SIZE;
299
300   /* Check for empty info field */
301   if (sInfo.length == 0)
302   {
303      return NFCSTATUS_FAILED;
304   }
305
306   /* Check consistency */
307   while (sInfo.length != 0)
308   {
309      /* Check if enough room to read length */
310      if (sInfo.length < sizeof(sInfo.length))
311      {
312         return NFCSTATUS_FAILED;
313      }
314      /* Read length */
315      length = (sInfo.buffer[0] << 8) | sInfo.buffer[1];
316      /* Update info buffer */
317      sInfo.buffer += 2; /*Size of length field is 2*/
318      sInfo.length -= 2; /*Size of length field is 2*/
319      /* Check if declared length fits in remaining space */
320      if (length > sInfo.length)
321      {
322         return NFCSTATUS_FAILED;
323      }
324      /* Update info buffer */
325      sInfo.buffer += length;
326      sInfo.length -= length;
327   }
328
329   /* Get info field */
330   sInfo.buffer = psRawPacket->buffer + PHFRINFC_LLCP_PACKET_HEADER_SIZE;
331   sInfo.length = psRawPacket->length - PHFRINFC_LLCP_PACKET_HEADER_SIZE;
332
333   /* Handle aggregated packets */
334   while (sInfo.length != 0)
335   {
336      /* Read length */
337      length = (sInfo.buffer[0] << 8) | sInfo.buffer[1];
338      /* Update info buffer */
339      sInfo.buffer += 2;        /* Size of length field is 2 */
340      sInfo.length -= 2;    /*Size of length field is 2*/
341      /* Handle aggregated packet */
342      sCurrentInfo.buffer=sInfo.buffer;
343      sCurrentInfo.length=length;
344      status = phFriNfc_Llcp_HandleIncomingPacket(Llcp, &sCurrentInfo);
345      if ( (status != NFCSTATUS_SUCCESS) &&
346           (status != NFCSTATUS_PENDING) )
347      {
348         /* TODO: Error: invalid frame */
349      }
350      /* Update info buffer */
351      sInfo.buffer += length;
352      sInfo.length -= length;
353   }
354   return NFCSTATUS_SUCCESS;
355}
356
357
358static NFCSTATUS phFriNfc_Llcp_ParseLinkParams( phNfc_sData_t                    *psParamsTLV,
359                                                phFriNfc_Llcp_sLinkParameters_t  *psParsedParams,
360                                                uint8_t                          *pnParsedVersion )
361{
362   NFCSTATUS                        status;
363   uint8_t                          type;
364   phFriNfc_Llcp_sLinkParameters_t  sParams;
365   phNfc_sData_t                    sValueBuffer;
366   uint32_t                         offset = 0;
367   uint8_t                          version = PHFRINFC_LLCP_INVALID_VERSION;
368
369   /* Check for NULL pointers */
370   if ((psParamsTLV == NULL) || (psParsedParams == NULL) || (pnParsedVersion == NULL))
371   {
372      return PHNFCSTVAL(CID_FRI_NFC_LLCP, NFCSTATUS_INVALID_PARAMETER);
373   }
374
375   /* Prepare default param structure */
376   sParams.miu    = PHFRINFC_LLCP_MIU_DEFAULT;
377   sParams.wks    = PHFRINFC_LLCP_WKS_DEFAULT;
378   sParams.lto    = PHFRINFC_LLCP_LTO_DEFAULT;
379   sParams.option = PHFRINFC_LLCP_OPTION_DEFAULT;
380
381   /* Decode TLV */
382   while (offset < psParamsTLV->length)
383   {
384      status = phFriNfc_Llcp_DecodeTLV(psParamsTLV, &offset, &type, &sValueBuffer);
385      if (status != NFCSTATUS_SUCCESS)
386      {
387         /* Error: Ill-formed TLV */
388         return status;
389      }
390      switch(type)
391      {
392         case PHFRINFC_LLCP_TLV_TYPE_VERSION:
393         {
394            /* Check length */
395            if (sValueBuffer.length != PHFRINFC_LLCP_TLV_LENGTH_VERSION)
396            {
397               /* Error : Ill-formed VERSION parameter TLV */
398               break;
399            }
400            /* Get VERSION */
401            version = sValueBuffer.buffer[0];
402            break;
403         }
404         case PHFRINFC_LLCP_TLV_TYPE_MIUX:
405         {
406            /* Check length */
407            if (sValueBuffer.length != PHFRINFC_LLCP_TLV_LENGTH_MIUX)
408            {
409               /* Error : Ill-formed MIUX parameter TLV */
410               break;
411            }
412            /* Get MIU */
413            sParams.miu = (PHFRINFC_LLCP_MIU_DEFAULT + ((sValueBuffer.buffer[0] << 8) | sValueBuffer.buffer[1])) & PHFRINFC_LLCP_TLV_MIUX_MASK;
414            break;
415         }
416         case PHFRINFC_LLCP_TLV_TYPE_WKS:
417         {
418            /* Check length */
419            if (sValueBuffer.length != PHFRINFC_LLCP_TLV_LENGTH_WKS)
420            {
421               /* Error : Ill-formed MIUX parameter TLV */
422               break;
423            }
424            /* Get WKS */
425            sParams.wks = (sValueBuffer.buffer[0] << 8) | sValueBuffer.buffer[1];
426            /* Ignored bits must always be set */
427            sParams.wks |= PHFRINFC_LLCP_TLV_WKS_MASK;
428            break;
429         }
430         case PHFRINFC_LLCP_TLV_TYPE_LTO:
431         {
432            /* Check length */
433            if (sValueBuffer.length != PHFRINFC_LLCP_TLV_LENGTH_LTO)
434            {
435               /* Error : Ill-formed LTO parameter TLV */
436               break;
437            }
438            /* Get LTO */
439            sParams.lto = sValueBuffer.buffer[0];
440            break;
441         }
442         case PHFRINFC_LLCP_TLV_TYPE_OPT:
443         {
444            /* Check length */
445            if (sValueBuffer.length != PHFRINFC_LLCP_TLV_LENGTH_OPT)
446            {
447               /* Error : Ill-formed OPT parameter TLV */
448               break;;
449            }
450            /* Get OPT */
451            sParams.option = sValueBuffer.buffer[0] & PHFRINFC_LLCP_TLV_OPT_MASK;
452            break;
453         }
454         default:
455         {
456            /* Error : Unknown Type */
457            break;
458         }
459      }
460   }
461
462   /* Check if a VERSION parameter has been provided */
463   if (version == PHFRINFC_LLCP_INVALID_VERSION)
464   {
465      /* Error : Mandatory VERSION parameter not provided */
466      return PHNFCSTVAL(CID_FRI_NFC_LLCP, NFCSTATUS_INVALID_PARAMETER);
467   }
468
469   /* Save response */
470   *pnParsedVersion = version;
471   memcpy(psParsedParams, &sParams, sizeof(phFriNfc_Llcp_sLinkParameters_t));
472
473   return NFCSTATUS_SUCCESS;
474}
475
476
477static NFCSTATUS phFriNfc_Llcp_VersionAgreement( uint8_t localVersion,
478                                                 uint8_t remoteVersion,
479                                                 uint8_t *pNegociatedVersion )
480{
481   uint8_t     localMajor  = localVersion  & PHFRINFC_LLCP_VERSION_MAJOR_MASK;
482   uint8_t     localMinor  = localVersion  & PHFRINFC_LLCP_VERSION_MINOR_MASK;
483   uint8_t     remoteMajor = remoteVersion & PHFRINFC_LLCP_VERSION_MAJOR_MASK;
484   uint8_t     remoteMinor = remoteVersion & PHFRINFC_LLCP_VERSION_MINOR_MASK;
485   uint8_t     negociatedVersion;
486
487   /* Check for NULL pointers */
488   if (pNegociatedVersion == NULL)
489   {
490      return PHNFCSTVAL(CID_FRI_NFC_LLCP, NFCSTATUS_INVALID_PARAMETER);
491   }
492
493   /* Compare Major numbers */
494   if (localMajor == remoteMajor)
495   {
496      /* Version agreement succeed : use lowest version */
497      negociatedVersion = localMajor | ((remoteMinor<localMinor)?remoteMinor:localMinor);
498   }
499   else if (localMajor > remoteMajor)
500   {
501      /* Decide if versions are compatible */
502      /* Currently, there is no backward compatibility to handle */
503      return NFCSTATUS_FAILED;
504   }
505   else /* if (localMajor < remoteMajor) */
506   {
507      /* It is up to the remote host to decide if versions are compatible */
508      /* Set negociated version to our local version, the remote will
509         deacivate the link if its own version agreement fails */
510      negociatedVersion = localVersion;
511   }
512
513   /* Save response */
514   *pNegociatedVersion = negociatedVersion;
515
516   return NFCSTATUS_SUCCESS;
517}
518
519
520static NFCSTATUS phFriNfc_Llcp_InternalActivate( phFriNfc_Llcp_t *Llcp,
521                                                 phNfc_sData_t   *psParamsTLV)
522{
523   NFCSTATUS                        status;
524   phFriNfc_Llcp_sLinkParameters_t  sRemoteParams;
525   uint8_t                          remoteVersion;
526   uint8_t                          negociatedVersion;
527   const uint16_t nMaxHeaderSize =  PHFRINFC_LLCP_PACKET_HEADER_SIZE +
528                                    PHFRINFC_LLCP_PACKET_SEQUENCE_SIZE;
529
530   /* Parse parameters  */
531   status = phFriNfc_Llcp_ParseLinkParams(psParamsTLV, &sRemoteParams, &remoteVersion);
532   if (status != NFCSTATUS_SUCCESS)
533   {
534      /* Error: invalid parameters TLV */
535      status = NFCSTATUS_FAILED;
536   }
537   else
538   {
539      /* Version agreement procedure */
540      status = phFriNfc_Llcp_VersionAgreement(PHFRINFC_LLCP_VERSION , remoteVersion, &negociatedVersion);
541      if (status != NFCSTATUS_SUCCESS)
542      {
543         /* Error: version agreement failed */
544         status = NFCSTATUS_FAILED;
545      }
546      else
547      {
548         /* Save parameters */
549         Llcp->version = negociatedVersion;
550         memcpy(&Llcp->sRemoteParams, &sRemoteParams, sizeof(phFriNfc_Llcp_sLinkParameters_t));
551
552         /* Update remote MIU to match local Tx buffer size */
553         if (Llcp->nTxBufferLength < (Llcp->sRemoteParams.miu + nMaxHeaderSize))
554         {
555            Llcp->sRemoteParams.miu = Llcp->nTxBufferLength - nMaxHeaderSize;
556         }
557
558         /* Initiate Symmetry procedure by resetting LTO timer */
559         /* NOTE: this also updates current state */
560         phFriNfc_Llcp_ResetLTO(Llcp);
561      }
562   }
563   /* Notify upper layer, if Activation failed CB called by Deactivate */
564   if (status == NFCSTATUS_SUCCESS)
565   {
566      /* Link activated ! */
567      Llcp->pfLink_CB(Llcp->pLinkContext, phFriNfc_LlcpMac_eLinkActivated);
568   }
569
570   return status;
571}
572
573
574static NFCSTATUS phFriNfc_Llcp_HandleMACLinkActivated( phFriNfc_Llcp_t  *Llcp,
575                                                       phNfc_sData_t    *psParamsTLV)
576{
577   NFCSTATUS                     status = NFCSTATUS_SUCCESS;
578
579   /* Create the timer */
580   Llcp->hSymmTimer = phOsalNfc_Timer_Create();
581   if (Llcp->hSymmTimer == PH_OSALNFC_INVALID_TIMER_ID)
582   {
583      /* Error: unable to create timer */
584      return NFCSTATUS_INSUFFICIENT_RESOURCES;
585   }
586
587   /* Check if params received from MAC activation procedure */
588   if (psParamsTLV == NULL)
589   {
590      /* No params with selected MAC mapping, enter PAX mode for parameter exchange */
591      Llcp->state = PHFRINFC_LLCP_STATE_PAX;
592      /* Set default MIU for PAX exchange */
593      Llcp->sRemoteParams.miu = PHFRINFC_LLCP_MIU_DEFAULT;
594      /* If the local device is the initiator, it must initiate PAX exchange */
595      if (Llcp->eRole == phFriNfc_LlcpMac_ePeerTypeInitiator)
596      {
597         /* Send PAX */
598         status = phFriNfc_Llcp_SendPax(Llcp, &Llcp->sLocalParams);
599      }
600   }
601   else
602   {
603      /* Params exchanged during MAX activation, try LLC activation */
604      status = phFriNfc_Llcp_InternalActivate(Llcp, psParamsTLV);
605   }
606
607   if (status == NFCSTATUS_SUCCESS)
608   {
609      /* Start listening for incoming packets */
610      Llcp->sRxBuffer.length = Llcp->nRxBufferLength;
611      phFriNfc_LlcpMac_Receive(&Llcp->MAC, &Llcp->sRxBuffer, phFriNfc_Llcp_Receive_CB, Llcp);
612   }
613
614   return status;
615}
616
617
618static void phFriNfc_Llcp_HandleMACLinkDeactivated( phFriNfc_Llcp_t  *Llcp )
619{
620   uint8_t state = Llcp->state;
621
622   /* Delete the timer */
623   if (Llcp->hSymmTimer != PH_OSALNFC_INVALID_TIMER_ID)
624   {
625      phOsalNfc_Timer_Delete(Llcp->hSymmTimer);
626   }
627
628   /* Reset state */
629   Llcp->state = PHFRINFC_LLCP_STATE_RESET_INIT;
630
631   switch (state)
632   {
633      case PHFRINFC_LLCP_STATE_DEACTIVATION:
634      {
635         /* The service layer has already been notified, nothing more to do */
636         break;
637      }
638      default:
639      {
640         /* Notify service layer of link failure */
641         Llcp->pfLink_CB(Llcp->pLinkContext, phFriNfc_LlcpMac_eLinkDeactivated);
642         break;
643      }
644   }
645}
646
647
648static void phFriNfc_Llcp_ChkLlcp_CB( void       *pContext,
649                                      NFCSTATUS  status )
650{
651   /* Get monitor from context */
652   phFriNfc_Llcp_t *Llcp = (phFriNfc_Llcp_t*)pContext;
653
654   /* Update state */
655   Llcp->state = PHFRINFC_LLCP_STATE_CHECKED;
656
657   /* Invoke callback */
658   Llcp->pfChk_CB(Llcp->pChkContext, status);
659}
660
661static void phFriNfc_Llcp_LinkStatus_CB( void                              *pContext,
662                                         phFriNfc_LlcpMac_eLinkStatus_t    eLinkStatus,
663                                         phNfc_sData_t                     *psParamsTLV,
664                                         phFriNfc_LlcpMac_ePeerType_t      PeerRemoteDevType)
665{
666   NFCSTATUS status;
667
668   /* Get monitor from context */
669   phFriNfc_Llcp_t *Llcp = (phFriNfc_Llcp_t*)pContext;
670
671   /* Save the local peer role (initiator/target) */
672   Llcp->eRole = PeerRemoteDevType;
673
674   /* Check new link status */
675   switch(eLinkStatus)
676   {
677      case phFriNfc_LlcpMac_eLinkActivated:
678      {
679         /* Handle MAC link activation */
680         status = phFriNfc_Llcp_HandleMACLinkActivated(Llcp, psParamsTLV);
681         if (status != NFCSTATUS_SUCCESS)
682         {
683            /* Error: LLC link activation procedure failed, deactivate MAC link */
684            status = phFriNfc_Llcp_InternalDeactivate(Llcp);
685         }
686         break;
687      }
688      case phFriNfc_LlcpMac_eLinkDeactivated:
689      {
690         /* Handle MAC link deactivation (cannot fail) */
691         phFriNfc_Llcp_HandleMACLinkDeactivated(Llcp);
692         break;
693      }
694      default:
695      {
696         /* Warning: Unknown link status, should not happen */
697      }
698   }
699}
700
701
702static void phFriNfc_Llcp_ResetLTO( phFriNfc_Llcp_t *Llcp )
703{
704   uint32_t nDuration = 0;
705   uint8_t bIsReset = 0;
706
707   /* Stop timer */
708   phOsalNfc_Timer_Stop(Llcp->hSymmTimer);
709
710
711   /* Update state */
712   if (Llcp->state == PHFRINFC_LLCP_STATE_OPERATION_RECV)
713   {
714      Llcp->state = PHFRINFC_LLCP_STATE_OPERATION_SEND;
715   }
716   else if (Llcp->state == PHFRINFC_LLCP_STATE_OPERATION_SEND)
717   {
718      Llcp->state = PHFRINFC_LLCP_STATE_OPERATION_RECV;
719   }
720   else if (Llcp->state != PHFRINFC_LLCP_STATE_DEACTIVATION &&
721            Llcp->state != PHFRINFC_LLCP_STATE_RESET_INIT)
722   {
723      bIsReset = 1;
724      /* Not yet in OPERATION state, perform first reset */
725      if (Llcp->eRole == phFriNfc_LlcpMac_ePeerTypeInitiator)
726      {
727         Llcp->state = PHFRINFC_LLCP_STATE_OPERATION_SEND;
728      }
729      else
730      {
731         Llcp->state = PHFRINFC_LLCP_STATE_OPERATION_RECV;
732      }
733   }
734
735   /* Calculate timer duration */
736   /* NOTE: nDuration is in 1/100s, and timer system takes values in 1/1000s */
737   if (Llcp->state == PHFRINFC_LLCP_STATE_OPERATION_RECV)
738   {
739      /* Response must be received before LTO announced by remote peer */
740      nDuration = Llcp->sRemoteParams.lto * 10;
741   }
742   else
743   {
744      if (bIsReset)
745      {
746          /* Immediately bounce SYMM back - it'll take
747           * a while for the host to come up with something,
748           * and maybe the remote is faster.
749           */
750          nDuration = 1;
751      }
752      else
753      {
754          /* Must answer before the local announced LTO */
755          /* NOTE: to ensure the answer is completely sent before LTO, the
756                  timer is triggered _before_ LTO expiration */
757          /* TODO: make sure time scope is enough, and avoid use of magic number */
758          nDuration = (Llcp->sLocalParams.lto * 10) / 2;
759      }
760   }
761
762   LLCP_DEBUG("Starting LLCP timer with duration %d", nDuration);
763
764   /* Restart timer */
765   phOsalNfc_Timer_Start(
766      Llcp->hSymmTimer,
767      nDuration,
768      phFriNfc_Llcp_Timer_CB,
769      Llcp);
770}
771
772
773static NFCSTATUS phFriNfc_Llcp_HandleLinkPacket( phFriNfc_Llcp_t    *Llcp,
774                                                 phNfc_sData_t      *psPacket )
775{
776   NFCSTATUS                        result;
777   phFriNfc_Llcp_sPacketHeader_t    sHeader;
778
779   /* Parse header */
780   phFriNfc_Llcp_Buffer2Header(psPacket->buffer, 0, &sHeader);
781
782   /* Check packet type */
783   switch (sHeader.ptype)
784   {
785      case PHFRINFC_LLCP_PTYPE_SYMM:
786      {
787         /* Nothing to do, the LTO is handled upon all packet reception */
788         result = NFCSTATUS_SUCCESS;
789         break;
790      }
791
792      case PHFRINFC_LLCP_PTYPE_AGF:
793      {
794         /* Handle the aggregated packet */
795         result = phFriNfc_Llcp_HandleAggregatedPacket(Llcp, psPacket);
796         if (result != NFCSTATUS_SUCCESS)
797         {
798            /* Error: invalid info field, dropping frame */
799         }
800         break;
801      }
802
803      case PHFRINFC_LLCP_PTYPE_DISC:
804      {
805         /* Handle link disconnection request */
806         result = phFriNfc_Llcp_InternalDeactivate(Llcp);
807         break;
808      }
809
810
811      case PHFRINFC_LLCP_PTYPE_FRMR:
812      {
813         /* TODO: what to do upon reception of FRMR on Link SAP ? */
814         result = NFCSTATUS_SUCCESS;
815         break;
816      }
817
818      case PHFRINFC_LLCP_PTYPE_PAX:
819      {
820         /* Ignore PAX when in Normal Operation */
821         result = NFCSTATUS_SUCCESS;
822         break;
823      }
824
825      default:
826      {
827         /* Error: invalid ptype field, dropping packet */
828         break;
829      }
830   }
831
832   return result;
833}
834
835
836static NFCSTATUS phFriNfc_Llcp_HandleTransportPacket( phFriNfc_Llcp_t    *Llcp,
837                                                      phNfc_sData_t      *psPacket )
838{
839   phFriNfc_Llcp_Recv_CB_t          pfRecvCB;
840   void                             *pContext;
841   NFCSTATUS                        result = NFCSTATUS_SUCCESS;
842   phFriNfc_Llcp_sPacketHeader_t    sHeader;
843
844   /* Forward to upper layer */
845   if (Llcp->pfRecvCB != NULL)
846   {
847      /* Get callback details */
848      pfRecvCB = Llcp->pfRecvCB;
849      pContext = Llcp->pRecvContext;
850      /* Reset callback details */
851      Llcp->pfRecvCB = NULL;
852      Llcp->pRecvContext = NULL;
853      /* Call the callback */
854      (pfRecvCB)(pContext, psPacket, NFCSTATUS_SUCCESS);
855   }
856
857   return result;
858}
859
860
861static bool_t phFriNfc_Llcp_HandlePendingSend ( phFriNfc_Llcp_t *Llcp )
862{
863   phFriNfc_Llcp_sPacketHeader_t    sHeader;
864   phNfc_sData_t                    sInfoBuffer;
865   phFriNfc_Llcp_sPacketHeader_t    *psSendHeader = NULL;
866   phFriNfc_Llcp_sPacketSequence_t  *psSendSequence = NULL;
867   phNfc_sData_t                    *psSendInfo = NULL;
868   NFCSTATUS                        result;
869   uint8_t                          bDeallocate = FALSE;
870   uint8_t                          return_value = FALSE;
871   /* Handle pending disconnection request */
872   if (Llcp->bDiscPendingFlag == TRUE)
873   {
874      /* Last send si acheived, send the pending DISC packet */
875      sHeader.dsap  = PHFRINFC_LLCP_SAP_LINK;
876      sHeader.ssap  = PHFRINFC_LLCP_SAP_LINK;
877      sHeader.ptype = PHFRINFC_LLCP_PTYPE_DISC;
878      /* Set send params */
879      psSendHeader = &sHeader;
880      /* Reset flag */
881      Llcp->bDiscPendingFlag = FALSE;
882   }
883   /* Handle pending frame reject request */
884   else if (Llcp->bFrmrPendingFlag == TRUE)
885   {
886      /* Last send si acheived, send the pending FRMR packet */
887      sInfoBuffer.buffer = Llcp->pFrmrInfo;
888      sInfoBuffer.length = sizeof(Llcp->pFrmrInfo);
889      /* Set send params */
890      psSendHeader = &Llcp->sFrmrHeader;
891      psSendInfo   = &sInfoBuffer;
892      /* Reset flag */
893      Llcp->bFrmrPendingFlag = FALSE;
894   }
895   /* Handle pending service frame */
896   else if (Llcp->pfSendCB != NULL)
897   {
898      /* Set send params */
899      psSendHeader = Llcp->psSendHeader;
900      psSendSequence = Llcp->psSendSequence;
901      psSendInfo = Llcp->psSendInfo;
902      /* Reset pending send infos */
903      Llcp->psSendHeader = NULL;
904      Llcp->psSendSequence = NULL;
905      Llcp->psSendInfo = NULL;
906      bDeallocate = TRUE;
907   }
908
909   /* Perform send, if needed */
910   if (psSendHeader != NULL)
911   {
912      result = phFriNfc_Llcp_InternalSend(Llcp, psSendHeader, psSendSequence, psSendInfo);
913      if ((result != NFCSTATUS_SUCCESS) && (result != NFCSTATUS_PENDING))
914      {
915         /* Error: send failed, impossible to recover */
916         phFriNfc_Llcp_InternalDeactivate(Llcp);
917      }
918      return_value = TRUE;
919   } else if (Llcp->pfSendCB == NULL) {
920      // Nothing to send, send SYMM instead to allow peer to send something
921      // if it wants.
922      phFriNfc_Llcp_SendSymm(Llcp);
923      return_value = TRUE;
924   }
925
926clean_and_return:
927   if (bDeallocate)
928   {
929       phFriNfc_Llcp_Deallocate(psSendInfo);
930   }
931
932   return return_value;
933}
934
935static NFCSTATUS phFriNfc_Llcp_HandleIncomingPacket( phFriNfc_Llcp_t    *Llcp,
936                                                     phNfc_sData_t      *psPacket )
937{
938   NFCSTATUS                        status = NFCSTATUS_SUCCESS;
939   phFriNfc_Llcp_sPacketHeader_t    sHeader;
940
941   /* Parse header */
942   phFriNfc_Llcp_Buffer2Header(psPacket->buffer, 0, &sHeader);
943
944   /* Check destination */
945   if (sHeader.dsap == PHFRINFC_LLCP_SAP_LINK)
946   {
947      /* Handle packet as destinated to the Link SAP */
948      status = phFriNfc_Llcp_HandleLinkPacket(Llcp, psPacket);
949   }
950   else if (sHeader.dsap >= PHFRINFC_LLCP_SAP_NUMBER)
951   {
952     /* NOTE: this cannot happen since "psHeader->dsap" is only 6-bit wide */
953     status = NFCSTATUS_FAILED;
954   }
955   else
956   {
957      /* Handle packet as destinated to the SDP and transport SAPs */
958      status = phFriNfc_Llcp_HandleTransportPacket(Llcp, psPacket);
959   }
960   return status;
961}
962
963
964static void phFriNfc_Llcp_Receive_CB( void               *pContext,
965                                      NFCSTATUS          status,
966                                      phNfc_sData_t      *psData)
967{
968   /* Get monitor from context */
969   phFriNfc_Llcp_t               *Llcp = (phFriNfc_Llcp_t*)pContext;
970   NFCSTATUS                     result = NFCSTATUS_SUCCESS;
971   phFriNfc_Llcp_sPacketHeader_t sPacketHeader;
972
973   /* Check reception status and for pending disconnection */
974   if ((status != NFCSTATUS_SUCCESS) || (Llcp->bDiscPendingFlag == TRUE))
975   {
976	  LLCP_DEBUG("\nReceived LLCP packet error - status = 0x%04x", status);
977      /* Reset disconnection operation */
978      Llcp->bDiscPendingFlag = FALSE;
979      /* Deactivate the link */
980      phFriNfc_Llcp_InternalDeactivate(Llcp);
981      return;
982   }
983
984   /* Parse header */
985   phFriNfc_Llcp_Buffer2Header(psData->buffer, 0, &sPacketHeader);
986
987   if (sPacketHeader.ptype != PHFRINFC_LLCP_PTYPE_SYMM)
988   {
989      LLCP_PRINT_BUFFER("\nReceived LLCP packet :", psData->buffer, psData->length);
990   }
991   else
992   {
993      LLCP_PRINT("?");
994   }
995
996
997   /* Check new link status */
998   switch(Llcp->state)
999   {
1000      /* Handle packets in PAX-waiting state */
1001      case PHFRINFC_LLCP_STATE_PAX:
1002      {
1003         /* Check packet type */
1004         if (sPacketHeader.ptype == PHFRINFC_LLCP_PTYPE_PAX)
1005         {
1006            /* Params exchanged during MAC activation, try LLC activation */
1007            result = phFriNfc_Llcp_InternalActivate(Llcp, psData+PHFRINFC_LLCP_PACKET_HEADER_SIZE);
1008            /* If the local LLC is the target, it must answer the PAX */
1009            if (Llcp->eRole == phFriNfc_LlcpMac_ePeerTypeTarget)
1010            {
1011               /* Send PAX */
1012               result = phFriNfc_Llcp_SendPax(Llcp, &Llcp->sLocalParams);
1013            }
1014         }
1015         else
1016         {
1017            /* Warning: Received packet with unhandled type in PAX-waiting state, drop it */
1018         }
1019         break;
1020      }
1021
1022      /* Handle normal operation packets */
1023      case PHFRINFC_LLCP_STATE_OPERATION_RECV:
1024      case PHFRINFC_LLCP_STATE_OPERATION_SEND:
1025      {
1026         /* Handle Symmetry procedure by resetting LTO timer */
1027         phFriNfc_Llcp_ResetLTO(Llcp);
1028         /* Handle packet */
1029         result = phFriNfc_Llcp_HandleIncomingPacket(Llcp, psData);
1030         if ( (result != NFCSTATUS_SUCCESS) &&
1031              (result != NFCSTATUS_PENDING) )
1032         {
1033            /* TODO: Error: invalid frame */
1034         }
1035         /* Perform pending send request, if any */
1036         phFriNfc_Llcp_HandlePendingSend(Llcp);
1037         break;
1038      }
1039
1040      default:
1041      {
1042         /* Warning: Should not receive packets in other states, drop them */
1043      }
1044   }
1045
1046   /* Restart reception */
1047   Llcp->sRxBuffer.length = Llcp->nRxBufferLength;
1048   phFriNfc_LlcpMac_Receive(&Llcp->MAC, &Llcp->sRxBuffer, phFriNfc_Llcp_Receive_CB, Llcp);
1049}
1050
1051
1052static void phFriNfc_Llcp_Send_CB( void               *pContext,
1053                                   NFCSTATUS          status )
1054{
1055   /* Get monitor from context */
1056   phFriNfc_Llcp_t                  *Llcp = (phFriNfc_Llcp_t*)pContext;
1057   phFriNfc_Llcp_Send_CB_t          pfSendCB;
1058   void                             *pSendContext;
1059
1060   /* Call the upper layer callback if last packet sent was  */
1061   /* NOTE: if Llcp->psSendHeader is not NULL, this means that the send operation is still not initiated */
1062   if (Llcp->psSendHeader == NULL)
1063   {
1064      if (Llcp->pfSendCB != NULL)
1065      {
1066         /* Get Callback params */
1067         pfSendCB = Llcp->pfSendCB;
1068         pSendContext = Llcp->pSendContext;
1069         /* Reset callback params */
1070         Llcp->pfSendCB = NULL;
1071         Llcp->pSendContext = NULL;
1072         /* Call the callback */
1073         (pfSendCB)(pSendContext, status);
1074      }
1075   }
1076
1077   /* Check reception status */
1078   if (status != NFCSTATUS_SUCCESS)
1079   {
1080       /* Error: Reception failed, link must be down */
1081       phFriNfc_Llcp_InternalDeactivate(Llcp);
1082   }
1083}
1084
1085
1086static NFCSTATUS phFriNfc_Llcp_InternalSend( phFriNfc_Llcp_t                    *Llcp,
1087                                             phFriNfc_Llcp_sPacketHeader_t      *psHeader,
1088                                             phFriNfc_Llcp_sPacketSequence_t    *psSequence,
1089                                             phNfc_sData_t                      *psInfo )
1090{
1091   NFCSTATUS status;
1092   phNfc_sData_t  *psRawPacket = &Llcp->sTxBuffer; /* Use internal Tx buffer */
1093
1094   /* Handle Symmetry procedure */
1095   phFriNfc_Llcp_ResetLTO(Llcp);
1096
1097   /* Generate raw packet to send (aggregate header + sequence + info fields) */
1098   psRawPacket->length = 0;
1099   psRawPacket->length += phFriNfc_Llcp_Header2Buffer(psHeader, psRawPacket->buffer, psRawPacket->length);
1100   if (psSequence != NULL)
1101   {
1102      psRawPacket->length += phFriNfc_Llcp_Sequence2Buffer(psSequence, psRawPacket->buffer, psRawPacket->length);
1103   }
1104   if (psInfo != NULL)
1105   {
1106      memcpy(psRawPacket->buffer + psRawPacket->length, psInfo->buffer, psInfo->length);
1107      psRawPacket->length += psInfo->length;
1108   }
1109
1110   if (psHeader->ptype != PHFRINFC_LLCP_PTYPE_SYMM)
1111   {
1112      LLCP_PRINT_BUFFER("\nSending LLCP packet :", psRawPacket->buffer, psRawPacket->length);
1113   }
1114   else
1115   {
1116      LLCP_PRINT("!");
1117   }
1118
1119   /* Send raw packet */
1120   status = phFriNfc_LlcpMac_Send (
1121               &Llcp->MAC,
1122               psRawPacket,
1123               phFriNfc_Llcp_Send_CB,
1124               Llcp );
1125
1126   return status;
1127}
1128
1129/* ---------------------------- Public functions ------------------------------- */
1130
1131NFCSTATUS phFriNfc_Llcp_EncodeLinkParams( phNfc_sData_t                   *psRawBuffer,
1132                                          phFriNfc_Llcp_sLinkParameters_t *psLinkParams,
1133                                          uint8_t                         nVersion )
1134{
1135   uint32_t    nOffset = 0;
1136   uint16_t    miux;
1137   uint16_t    wks;
1138   uint8_t     pValue[2];
1139   NFCSTATUS   result = NFCSTATUS_SUCCESS;
1140
1141   /* Check parameters */
1142   if ((psRawBuffer == NULL) || (psLinkParams == NULL))
1143   {
1144      return NFCSTATUS_INVALID_PARAMETER;
1145   }
1146
1147   /* Encode mandatory VERSION field */
1148   if (result == NFCSTATUS_SUCCESS)
1149   {
1150      result = phFriNfc_Llcp_EncodeTLV(
1151                  psRawBuffer,
1152                  &nOffset,
1153                  PHFRINFC_LLCP_TLV_TYPE_VERSION,
1154                  PHFRINFC_LLCP_TLV_LENGTH_VERSION,
1155                  &nVersion);
1156   }
1157
1158   /* Encode mandatory VERSION field */
1159   if (result == NFCSTATUS_SUCCESS)
1160   {
1161      /* Encode MIUX field, if needed */
1162      if (psLinkParams->miu != PHFRINFC_LLCP_MIU_DEFAULT)
1163      {
1164         miux = (psLinkParams->miu - PHFRINFC_LLCP_MIU_DEFAULT) & PHFRINFC_LLCP_TLV_MIUX_MASK;
1165         pValue[0] = (miux >> 8) & 0xFF;
1166         pValue[1] =  miux       & 0xFF;
1167         result = phFriNfc_Llcp_EncodeTLV(
1168                     psRawBuffer,
1169                     &nOffset,
1170                     PHFRINFC_LLCP_TLV_TYPE_MIUX,
1171                     PHFRINFC_LLCP_TLV_LENGTH_MIUX,
1172                     pValue);
1173      }
1174   }
1175
1176   /* Encode WKS field */
1177   if (result == NFCSTATUS_SUCCESS)
1178   {
1179      wks = psLinkParams->wks | PHFRINFC_LLCP_TLV_WKS_MASK;
1180      pValue[0] = (wks >> 8) & 0xFF;
1181      pValue[1] =  wks       & 0xFF;
1182      result = phFriNfc_Llcp_EncodeTLV(
1183                  psRawBuffer,
1184                  &nOffset,
1185                  PHFRINFC_LLCP_TLV_TYPE_WKS,
1186                  PHFRINFC_LLCP_TLV_LENGTH_WKS,
1187                  pValue);
1188   }
1189
1190   /* Encode LTO field, if needed */
1191   if (result == NFCSTATUS_SUCCESS)
1192   {
1193      if (psLinkParams->lto != PHFRINFC_LLCP_LTO_DEFAULT)
1194      {
1195         result = phFriNfc_Llcp_EncodeTLV(
1196                     psRawBuffer,
1197                     &nOffset,
1198                     PHFRINFC_LLCP_TLV_TYPE_LTO,
1199                     PHFRINFC_LLCP_TLV_LENGTH_LTO,
1200                     &psLinkParams->lto);
1201      }
1202   }
1203
1204   /* Encode OPT field, if needed */
1205   if (result == NFCSTATUS_SUCCESS)
1206   {
1207      if (psLinkParams->option != PHFRINFC_LLCP_OPTION_DEFAULT)
1208      {
1209         result = phFriNfc_Llcp_EncodeTLV(
1210                     psRawBuffer,
1211                     &nOffset,
1212                     PHFRINFC_LLCP_TLV_TYPE_OPT,
1213                     PHFRINFC_LLCP_TLV_LENGTH_OPT,
1214                     &psLinkParams->option);
1215      }
1216   }
1217
1218   if (result != NFCSTATUS_SUCCESS)
1219   {
1220      /* Error: failed to encode TLV */
1221      return NFCSTATUS_FAILED;
1222   }
1223
1224   /* Save new buffer size */
1225   psRawBuffer->length = nOffset;
1226
1227   return result;
1228}
1229
1230
1231NFCSTATUS phFriNfc_Llcp_Reset( phFriNfc_Llcp_t                 *Llcp,
1232                               void                            *LowerDevice,
1233                               phFriNfc_Llcp_sLinkParameters_t *psLinkParams,
1234                               void                            *pRxBuffer,
1235                               uint16_t                        nRxBufferLength,
1236                               void                            *pTxBuffer,
1237                               uint16_t                        nTxBufferLength,
1238                               phFriNfc_Llcp_LinkStatus_CB_t   pfLink_CB,
1239                               void                            *pContext )
1240{
1241   const uint16_t nMaxHeaderSize =  PHFRINFC_LLCP_PACKET_HEADER_SIZE +
1242                                    PHFRINFC_LLCP_PACKET_SEQUENCE_SIZE;
1243   NFCSTATUS result;
1244
1245   /* Check parameters presence */
1246   if ((Llcp == NULL) || (LowerDevice == NULL) || (pfLink_CB == NULL) ||
1247       (pRxBuffer == NULL) || (pTxBuffer == NULL) )
1248   {
1249      return NFCSTATUS_INVALID_PARAMETER;
1250   }
1251
1252   /* Check parameters value */
1253   if (psLinkParams->miu < PHFRINFC_LLCP_MIU_DEFAULT)
1254   {
1255      return NFCSTATUS_INVALID_PARAMETER;
1256   }
1257
1258   /* Check if buffers are large enough to support minimal MIU */
1259   if ((nRxBufferLength < (nMaxHeaderSize + PHFRINFC_LLCP_MIU_DEFAULT)) ||
1260       (nTxBufferLength < (nMaxHeaderSize + PHFRINFC_LLCP_MIU_DEFAULT)) )
1261   {
1262      return NFCSTATUS_BUFFER_TOO_SMALL;
1263   }
1264
1265   /* Check compatibility between reception buffer size and announced MIU */
1266   if (nRxBufferLength < (nMaxHeaderSize + psLinkParams->miu))
1267   {
1268      return NFCSTATUS_BUFFER_TOO_SMALL;
1269   }
1270
1271   /* Start with a zero-filled monitor */
1272   memset(Llcp, 0x00, sizeof(phFriNfc_Llcp_t));
1273
1274   /* Reset the MAC Mapping layer */
1275   result = phFriNfc_LlcpMac_Reset(&Llcp->MAC, LowerDevice, phFriNfc_Llcp_LinkStatus_CB, Llcp);
1276   if (result != NFCSTATUS_SUCCESS) {
1277      return result;
1278   }
1279
1280   /* Save the working buffers */
1281   Llcp->sRxBuffer.buffer = pRxBuffer;
1282   Llcp->sRxBuffer.length = nRxBufferLength;
1283   Llcp->nRxBufferLength = nRxBufferLength;
1284   Llcp->sTxBuffer.buffer = pTxBuffer;
1285   Llcp->sTxBuffer.length = nTxBufferLength;
1286   Llcp->nTxBufferLength = nTxBufferLength;
1287
1288   /* Save the link status callback references */
1289   Llcp->pfLink_CB = pfLink_CB;
1290   Llcp->pLinkContext = pContext;
1291
1292   /* Save the local link parameters */
1293   memcpy(&Llcp->sLocalParams, psLinkParams, sizeof(phFriNfc_Llcp_sLinkParameters_t));
1294
1295   return NFCSTATUS_SUCCESS;
1296}
1297
1298
1299NFCSTATUS phFriNfc_Llcp_ChkLlcp( phFriNfc_Llcp_t               *Llcp,
1300                                 phHal_sRemoteDevInformation_t *psRemoteDevInfo,
1301                                 phFriNfc_Llcp_Check_CB_t      pfCheck_CB,
1302                                 void                          *pContext )
1303{
1304   /* Check parameters */
1305   if ( (Llcp == NULL) || (psRemoteDevInfo == NULL) || (pfCheck_CB == NULL) )
1306   {
1307      return PHNFCSTVAL(CID_FRI_NFC_LLCP, NFCSTATUS_INVALID_PARAMETER);
1308   }
1309
1310   /* Check current state */
1311   if( Llcp->state != PHFRINFC_LLCP_STATE_RESET_INIT ) {
1312      return PHNFCSTVAL(CID_FRI_NFC_LLCP, NFCSTATUS_INVALID_STATE);
1313   }
1314
1315   /* Save the compliance check callback */
1316   Llcp->pfChk_CB = pfCheck_CB;
1317   Llcp->pChkContext = pContext;
1318
1319   /* Forward check request to MAC layer */
1320   return phFriNfc_LlcpMac_ChkLlcp(&Llcp->MAC, psRemoteDevInfo, phFriNfc_Llcp_ChkLlcp_CB, (void*)Llcp);
1321}
1322
1323
1324NFCSTATUS phFriNfc_Llcp_Activate( phFriNfc_Llcp_t *Llcp )
1325{
1326   /* Check parameters */
1327   if (Llcp == NULL)
1328   {
1329      return PHNFCSTVAL(CID_FRI_NFC_LLCP, NFCSTATUS_INVALID_PARAMETER);
1330   }
1331
1332   /* Check current state */
1333   if( Llcp->state != PHFRINFC_LLCP_STATE_CHECKED ) {
1334      return PHNFCSTVAL(CID_FRI_NFC_LLCP, NFCSTATUS_INVALID_STATE);
1335   }
1336
1337   /* Update state */
1338   Llcp->state = PHFRINFC_LLCP_STATE_ACTIVATION;
1339
1340   /* Reset any headers to send */
1341   Llcp->psSendHeader = NULL;
1342   Llcp->psSendSequence = NULL;
1343
1344   /* Forward check request to MAC layer */
1345   return phFriNfc_LlcpMac_Activate(&Llcp->MAC);
1346}
1347
1348
1349NFCSTATUS phFriNfc_Llcp_Deactivate( phFriNfc_Llcp_t *Llcp )
1350{
1351   NFCSTATUS status;
1352
1353   /* Check parameters */
1354   if (Llcp == NULL)
1355   {
1356      return PHNFCSTVAL(CID_FRI_NFC_LLCP, NFCSTATUS_INVALID_PARAMETER);
1357   }
1358
1359   /* Check current state */
1360   if( (Llcp->state != PHFRINFC_LLCP_STATE_OPERATION_RECV) &&
1361       (Llcp->state != PHFRINFC_LLCP_STATE_OPERATION_SEND) ) {
1362      return PHNFCSTVAL(CID_FRI_NFC_LLCP, NFCSTATUS_INVALID_STATE);
1363   }
1364
1365   /* Send DISC packet */
1366   status = phFriNfc_Llcp_SendDisconnect(Llcp);
1367   if (status == NFCSTATUS_PENDING)
1368   {
1369      /* Wait for packet to be sent before deactivate link */
1370      return status;
1371   }
1372
1373   /* Perform actual deactivation */
1374   return phFriNfc_Llcp_InternalDeactivate(Llcp);
1375}
1376
1377
1378NFCSTATUS phFriNfc_Llcp_GetLocalInfo( phFriNfc_Llcp_t                   *Llcp,
1379                                      phFriNfc_Llcp_sLinkParameters_t   *pParams )
1380{
1381   /* Check parameters */
1382   if ((Llcp == NULL) || (pParams == NULL))
1383   {
1384      return PHNFCSTVAL(CID_FRI_NFC_LLCP, NFCSTATUS_INVALID_PARAMETER);
1385   }
1386
1387   /* Copy response */
1388   memcpy(pParams, &Llcp->sLocalParams, sizeof(phFriNfc_Llcp_sLinkParameters_t));
1389
1390   return NFCSTATUS_SUCCESS;
1391}
1392
1393
1394NFCSTATUS phFriNfc_Llcp_GetRemoteInfo( phFriNfc_Llcp_t                  *Llcp,
1395                                       phFriNfc_Llcp_sLinkParameters_t  *pParams )
1396{
1397   /* Check parameters */
1398   if ((Llcp == NULL) || (pParams == NULL))
1399   {
1400      return PHNFCSTVAL(CID_FRI_NFC_LLCP, NFCSTATUS_INVALID_PARAMETER);
1401   }
1402
1403   /* Copy response */
1404   memcpy(pParams, &Llcp->sRemoteParams, sizeof(phFriNfc_Llcp_sLinkParameters_t));
1405
1406   return NFCSTATUS_SUCCESS;
1407}
1408
1409
1410NFCSTATUS phFriNfc_Llcp_Send( phFriNfc_Llcp_t                  *Llcp,
1411                              phFriNfc_Llcp_sPacketHeader_t    *psHeader,
1412                              phFriNfc_Llcp_sPacketSequence_t  *psSequence,
1413                              phNfc_sData_t                    *psInfo,
1414                              phFriNfc_Llcp_Send_CB_t          pfSend_CB,
1415                              void                             *pContext )
1416{
1417   NFCSTATUS result;
1418   /* Check parameters */
1419   if ((Llcp == NULL) || (psHeader == NULL) || (pfSend_CB == NULL))
1420   {
1421      return PHNFCSTVAL(CID_FRI_NFC_LLCP, NFCSTATUS_INVALID_PARAMETER);
1422   }
1423
1424   /* Check if previous phFriNfc_Llcp_Send() has finished */
1425   if (Llcp->pfSendCB != NULL)
1426   {
1427      /* Error: a send operation is already running */
1428      return PHNFCSTVAL(CID_FRI_NFC_LLCP, NFCSTATUS_REJECTED);
1429   }
1430
1431   /* Save the callback parameters */
1432   Llcp->pfSendCB = pfSend_CB;
1433   Llcp->pSendContext = pContext;
1434
1435   if (Llcp->state == PHFRINFC_LLCP_STATE_OPERATION_SEND)
1436   {
1437      /* Ready to send */
1438      result = phFriNfc_Llcp_InternalSend(Llcp, psHeader, psSequence, psInfo);
1439   }
1440   else if (Llcp->state == PHFRINFC_LLCP_STATE_OPERATION_RECV)
1441   {
1442      /* Not ready to send, save send params for later use */
1443      Llcp->psSendHeader = psHeader;
1444      Llcp->psSendSequence = psSequence;
1445      Llcp->psSendInfo = phFriNfc_Llcp_AllocateAndCopy(psInfo);
1446      result = NFCSTATUS_PENDING;
1447   }
1448   else
1449   {
1450      /* Incorrect state for sending ! */
1451      result = PHNFCSTVAL(CID_FRI_NFC_LLCP, NFCSTATUS_INVALID_STATE);;
1452   }
1453
1454   if (result != NFCSTATUS_PENDING) {
1455       Llcp->pfSendCB = NULL;
1456   }
1457   return result;
1458}
1459
1460
1461NFCSTATUS phFriNfc_Llcp_Recv( phFriNfc_Llcp_t            *Llcp,
1462                              phFriNfc_Llcp_Recv_CB_t    pfRecv_CB,
1463                              void                       *pContext )
1464{
1465   NFCSTATUS result = NFCSTATUS_SUCCESS;
1466
1467   /* Check parameters */
1468   if ((Llcp == NULL) || (pfRecv_CB == NULL))
1469   {
1470      return PHNFCSTVAL(CID_FRI_NFC_LLCP, NFCSTATUS_INVALID_PARAMETER);
1471   }
1472
1473   /* Check if previous phFriNfc_Llcp_Recv() has finished */
1474   if (Llcp->pfRecvCB != NULL)
1475   {
1476      /* Error: a send operation is already running */
1477      return PHNFCSTVAL(CID_FRI_NFC_LLCP, NFCSTATUS_REJECTED);
1478   }
1479
1480   /* Save the callback parameters */
1481   Llcp->pfRecvCB = pfRecv_CB;
1482   Llcp->pRecvContext = pContext;
1483
1484   /* NOTE: nothing more to do, the receive function is called in background */
1485
1486   return result;
1487}
1488