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