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