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