nfa_cho_sm.c revision b58ba0e89a3767e6174c42d3e90540d1eae10f81
1/******************************************************************************
2 *
3 *  Copyright (C) 2010-2012 Broadcom Corporation
4 *
5 *  Licensed under the Apache License, Version 2.0 (the "License");
6 *  you may not use this file except in compliance with the License.
7 *  You may obtain a copy of the License at:
8 *
9 *  http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  See the License for the specific language governing permissions and
15 *  limitations under the License.
16 *
17 ******************************************************************************/
18
19/******************************************************************************
20 *
21 *  This is the state implementation file for the NFA Connection Handover.
22 *
23 ******************************************************************************/
24#include <string.h>
25#include "nfc_api.h"
26#include "llcp_api.h"
27#include "llcp_defs.h"
28#include "nfa_sys.h"
29#include "nfa_sys_int.h"
30#include "nfa_cho_api.h"
31#include "nfa_cho_int.h"
32#include "nfa_mem_co.h"
33
34/*****************************************************************************
35**  Global Variables
36*****************************************************************************/
37
38/*****************************************************************************
39**  Static Functions
40*****************************************************************************/
41static void nfa_cho_sm_disabled (tNFA_CHO_INT_EVT event, tNFA_CHO_INT_EVENT_DATA *p_data);
42static void nfa_cho_sm_idle (tNFA_CHO_INT_EVT event, tNFA_CHO_INT_EVENT_DATA *p_data);
43static void nfa_cho_sm_w4_cc (tNFA_CHO_INT_EVT event, tNFA_CHO_INT_EVENT_DATA *p_data);
44static void nfa_cho_sm_connected (tNFA_CHO_INT_EVT event, tNFA_CHO_INT_EVENT_DATA *p_data);
45static void nfa_cho_proc_rx_handover_msg (void);
46
47/* debug functions type */
48#if (BT_TRACE_VERBOSE == TRUE)
49static char *nfa_cho_state_code (tNFA_CHO_STATE state_code);
50static char *nfa_cho_evt_code (tNFA_CHO_INT_EVT evt_code);
51#endif
52
53/*****************************************************************************
54**  Constants
55*****************************************************************************/
56
57/*******************************************************************************
58**
59** Function         nfa_cho_sm_llcp_cback
60**
61** Description      Processing event from LLCP
62**
63**
64** Returns          None
65**
66*******************************************************************************/
67void nfa_cho_sm_llcp_cback (tLLCP_SAP_CBACK_DATA *p_data)
68{
69    tNFA_CHO_RX_NDEF_STATUS rx_status;
70
71    CHO_TRACE_DEBUG2 ("nfa_cho_sm_llcp_cback (): event:0x%02X, local_sap:0x%02X",
72                       p_data->hdr.event, p_data->hdr.local_sap);
73
74    switch (p_data->hdr.event)
75    {
76    case LLCP_SAP_EVT_DATA_IND:
77        /* check if we received complete Handover Message */
78        rx_status = nfa_cho_reassemble_ho_msg (p_data->data_ind.local_sap,
79                                               p_data->data_ind.remote_sap);
80
81        if (rx_status == NFA_CHO_RX_NDEF_COMPLETE)
82        {
83            nfa_cho_sm_execute (NFA_CHO_RX_HANDOVER_MSG_EVT, NULL);
84        }
85        break;
86
87    case LLCP_SAP_EVT_CONNECT_IND:
88        nfa_cho_sm_execute (NFA_CHO_LLCP_CONNECT_IND_EVT, (tNFA_CHO_INT_EVENT_DATA *) p_data);
89        break;
90
91    case LLCP_SAP_EVT_CONNECT_RESP:
92        nfa_cho_sm_execute (NFA_CHO_LLCP_CONNECT_RESP_EVT, (tNFA_CHO_INT_EVENT_DATA *) p_data);
93        break;
94
95    case LLCP_SAP_EVT_DISCONNECT_IND:
96        nfa_cho_sm_execute (NFA_CHO_LLCP_DISCONNECT_IND_EVT, (tNFA_CHO_INT_EVENT_DATA *) p_data);
97        break;
98
99    case LLCP_SAP_EVT_DISCONNECT_RESP:
100        nfa_cho_sm_execute (NFA_CHO_LLCP_DISCONNECT_RESP_EVT, (tNFA_CHO_INT_EVENT_DATA *) p_data);
101        break;
102
103    case LLCP_SAP_EVT_CONGEST:
104        nfa_cho_sm_execute (NFA_CHO_LLCP_CONGEST_EVT, (tNFA_CHO_INT_EVENT_DATA *) p_data);
105        break;
106
107    case LLCP_SAP_EVT_LINK_STATUS:
108        nfa_cho_sm_execute (NFA_CHO_LLCP_LINK_STATUS_EVT, (tNFA_CHO_INT_EVENT_DATA *) p_data);
109        break;
110
111    default:
112        CHO_TRACE_ERROR1 ("Unknown event:0x%02X", p_data->hdr.event);
113        return;
114    }
115}
116
117/*******************************************************************************
118**
119** Function         nfa_cho_sm_disabled
120**
121** Description      Process event in disabled state
122**
123** Returns          None
124**
125*******************************************************************************/
126static void nfa_cho_sm_disabled (tNFA_CHO_INT_EVT event, tNFA_CHO_INT_EVENT_DATA *p_data)
127{
128    tNFA_CHO_EVT_DATA evt_data;
129    UINT16            remote_link_miu;
130
131    switch (event)
132    {
133    case NFA_CHO_API_REG_EVT:
134
135        evt_data.status = nfa_cho_proc_api_reg (p_data);
136
137        if (evt_data.status == NFA_STATUS_OK)
138        {
139            nfa_cho_cb.state = NFA_CHO_ST_IDLE;
140        }
141        p_data->api_reg.p_cback (NFA_CHO_REG_EVT, &evt_data);
142
143        if (evt_data.status == NFA_STATUS_OK)
144        {
145            /* check if LLCP is already activated */
146            LLCP_GetLinkMIU (&nfa_cho_cb.local_link_miu, &remote_link_miu);
147
148            if (nfa_cho_cb.local_link_miu > 0)
149            {
150                nfa_cho_cb.flags |= NFA_CHO_FLAGS_LLCP_ACTIVATED;
151
152                /* Notify application LLCP link activated */
153                evt_data.activated.is_initiator = FALSE;
154                nfa_cho_cb.p_cback (NFA_CHO_ACTIVATED_EVT, &evt_data);
155            }
156        }
157        break;
158
159    default:
160        CHO_TRACE_ERROR0 ("Unknown event");
161        break;
162    }
163}
164
165/*******************************************************************************
166**
167** Function         nfa_cho_sm_idle
168**
169** Description      Process event in idle state
170**
171** Returns          None
172**
173*******************************************************************************/
174static void nfa_cho_sm_idle (tNFA_CHO_INT_EVT event, tNFA_CHO_INT_EVENT_DATA *p_data)
175{
176    UINT16                  remote_link_miu;
177    tNFA_CHO_EVT_DATA       evt_data;
178    tLLCP_CONNECTION_PARAMS params;
179
180    switch (event)
181    {
182    case NFA_CHO_API_REG_EVT:
183        evt_data.status = NFA_STATUS_FAILED;
184        p_data->api_reg.p_cback (NFA_CHO_REG_EVT, &evt_data);
185        break;
186
187    case NFA_CHO_API_DEREG_EVT:
188        nfa_cho_proc_api_dereg ();
189        nfa_cho_cb.state = NFA_CHO_ST_DISABLED;
190        break;
191
192    case NFA_CHO_API_CONNECT_EVT:
193        /* if LLCP activated then create data link connection */
194        if (nfa_cho_cb.flags & NFA_CHO_FLAGS_LLCP_ACTIVATED)
195        {
196            if (nfa_cho_create_connection () == NFA_STATUS_OK)
197            {
198                /* waiting for connection confirm */
199                nfa_cho_cb.state = NFA_CHO_ST_W4_CC;
200            }
201            else
202            {
203                evt_data.disconnected.reason = NFA_CHO_DISC_REASON_CONNECTION_FAIL;
204                nfa_cho_cb.p_cback (NFA_CHO_DISCONNECTED_EVT, &evt_data);
205            }
206        }
207        else
208        {
209            evt_data.disconnected.reason = NFA_CHO_DISC_REASON_LINK_DEACTIVATED;
210            nfa_cho_cb.p_cback (NFA_CHO_DISCONNECTED_EVT, &evt_data);
211        }
212        break;
213
214    case NFA_CHO_API_DISCONNECT_EVT:
215        /* Nothing to disconnect */
216        nfa_cho_process_disconnection (NFA_CHO_DISC_REASON_API_REQUEST);
217        break;
218
219    case NFA_CHO_LLCP_CONNECT_IND_EVT:
220
221        /* accept connection request */
222        params.miu = (UINT16) (nfa_cho_cb.local_link_miu >= NFA_CHO_MIU ? NFA_CHO_MIU : nfa_cho_cb.local_link_miu);
223        params.rw  = NFA_CHO_RW;
224        params.sn[0] = 0;
225
226        LLCP_ConnectCfm (p_data->llcp_cback_data.connect_ind.local_sap,
227                         p_data->llcp_cback_data.connect_ind.remote_sap,
228                         &params);
229
230        nfa_cho_cb.remote_miu = p_data->llcp_cback_data.connect_ind.miu;
231        nfa_cho_cb.remote_sap = p_data->llcp_cback_data.connect_ind.remote_sap;
232        nfa_cho_cb.local_sap  = p_data->llcp_cback_data.connect_ind.local_sap;
233
234        nfa_cho_cb.substate  = NFA_CHO_SUBSTATE_W4_REMOTE_HR;
235        nfa_cho_cb.state     = NFA_CHO_ST_CONNECTED;
236        nfa_cho_cb.congested = FALSE;
237
238        evt_data.connected.initial_role = NFA_CHO_ROLE_SELECTOR;
239        nfa_cho_cb.p_cback (NFA_CHO_CONNECTED_EVT, &evt_data);
240        break;
241
242    case NFA_CHO_LLCP_LINK_STATUS_EVT:
243        /*
244        **  LLCP sends NFA_CHO_LLCP_DISCONNECT_IND_EVT for all data link connection
245        **  before sending NFA_CHO_LLCP_LINK_STATUS_EVT for deactivation.
246        **  This event can be received only in this state.
247        */
248
249        if (p_data->llcp_cback_data.link_status.is_activated == TRUE)
250        {
251            nfa_cho_cb.flags |= NFA_CHO_FLAGS_LLCP_ACTIVATED;
252
253            /* store local link MIU to decide MIU of data link connection later */
254            LLCP_GetLinkMIU (&nfa_cho_cb.local_link_miu, &remote_link_miu);
255
256            /* Notify application LLCP link activated */
257            evt_data.activated.is_initiator = p_data->llcp_cback_data.link_status.is_initiator;
258            nfa_cho_cb.p_cback (NFA_CHO_ACTIVATED_EVT, &evt_data);
259        }
260        else
261        {
262            /* the other flags had been cleared by NFA_CHO_LLCP_DISCONNECT_IND_EVT */
263            nfa_cho_cb.flags &= ~NFA_CHO_FLAGS_LLCP_ACTIVATED;
264
265            /* Notify application LLCP link deactivated */
266            evt_data.status = NFA_STATUS_OK;
267            nfa_cho_cb.p_cback (NFA_CHO_DEACTIVATED_EVT, &evt_data);
268        }
269        break;
270
271    case NFA_CHO_API_SEND_HR_EVT:
272        GKI_freebuf (p_data->api_send_hr.p_ndef);
273        break;
274
275    case NFA_CHO_API_SEND_HS_EVT:
276        GKI_freebuf (p_data->api_send_hs.p_ndef);
277        break;
278
279    case NFA_CHO_NDEF_TYPE_HANDLER_EVT:
280        nfa_cho_proc_ndef_type_handler_evt (p_data);
281        break;
282
283    default:
284        CHO_TRACE_ERROR0 ("Unknown event");
285        break;
286    }
287}
288
289/*******************************************************************************
290**
291** Function         nfa_cho_sm_w4_cc
292**
293** Description      Process event in waiting for connection confirm state
294**
295** Returns          None
296**
297*******************************************************************************/
298static void nfa_cho_sm_w4_cc (tNFA_CHO_INT_EVT event, tNFA_CHO_INT_EVENT_DATA *p_data)
299{
300    tNFA_CHO_EVT_DATA       evt_data;
301    tLLCP_CONNECTION_PARAMS params;
302
303    switch (event)
304    {
305    case NFA_CHO_API_REG_EVT:
306        evt_data.status = NFA_STATUS_FAILED;
307        p_data->api_reg.p_cback (NFA_CHO_REG_EVT, &evt_data);
308        break;
309
310    case NFA_CHO_API_DEREG_EVT:
311        nfa_cho_proc_api_dereg ();
312        nfa_cho_cb.state = NFA_CHO_ST_DISABLED;
313        break;
314
315    case NFA_CHO_API_CONNECT_EVT:
316        evt_data.disconnected.reason = NFA_CHO_DISC_REASON_ALEADY_CONNECTED;
317        nfa_cho_cb.p_cback (NFA_CHO_DISCONNECTED_EVT, &evt_data);
318        break;
319
320    case NFA_CHO_API_DISCONNECT_EVT:
321        /* disconnect collision connection accepted by local device */
322        if (nfa_cho_cb.flags & NFA_CHO_FLAGS_CONN_COLLISION)
323        {
324            LLCP_DisconnectReq (nfa_cho_cb.collision_local_sap,
325                                nfa_cho_cb.collision_remote_sap,
326                                FALSE);
327
328            /* clear collision flag */
329            nfa_cho_cb.flags &= ~NFA_CHO_FLAGS_CONN_COLLISION;
330        }
331
332        nfa_cho_cb.state = NFA_CHO_ST_IDLE;
333
334        /* we cannot send DISC because we don't know remote SAP */
335        nfa_cho_process_disconnection (NFA_CHO_DISC_REASON_API_REQUEST);
336        break;
337
338    case NFA_CHO_LLCP_CONNECT_RESP_EVT:
339        /* peer accepted connection request */
340        nfa_cho_cb.state     = NFA_CHO_ST_CONNECTED;
341        nfa_cho_cb.substate  = NFA_CHO_SUBSTATE_W4_LOCAL_HR;
342        nfa_cho_cb.congested = FALSE;
343
344        /* store data link connection parameters */
345        nfa_cho_cb.remote_miu = p_data->llcp_cback_data.connect_resp.miu;
346        nfa_cho_cb.remote_sap = p_data->llcp_cback_data.connect_resp.remote_sap;
347        nfa_cho_cb.local_sap  = nfa_cho_cb.client_sap;
348
349        evt_data.connected.initial_role = NFA_CHO_ROLE_REQUESTER;
350        nfa_cho_cb.p_cback (NFA_CHO_CONNECTED_EVT, &evt_data);
351        break;
352
353    case NFA_CHO_LLCP_CONNECT_IND_EVT:
354        /* if already collision of connection */
355        if (nfa_cho_cb.flags & NFA_CHO_FLAGS_CONN_COLLISION)
356        {
357            LLCP_ConnectReject (p_data->llcp_cback_data.connect_ind.local_sap,
358                                p_data->llcp_cback_data.connect_ind.remote_sap,
359                                LLCP_SAP_DM_REASON_TEMP_REJECT_THIS);
360        }
361        else
362        {
363            /*
364            ** accept connection request and set collision flag
365            ** wait for accepting connection request from peer or Hr message
366            */
367            params.miu = (UINT16) (nfa_cho_cb.local_link_miu >= NFA_CHO_MIU ? NFA_CHO_MIU : nfa_cho_cb.local_link_miu);
368            params.rw  = NFA_CHO_RW;
369            params.sn[0] = 0;
370
371            LLCP_ConnectCfm (p_data->llcp_cback_data.connect_ind.local_sap,
372                             p_data->llcp_cback_data.connect_ind.remote_sap,
373                             &params);
374
375            nfa_cho_cb.flags |= NFA_CHO_FLAGS_CONN_COLLISION;
376
377            nfa_cho_cb.collision_remote_miu = p_data->llcp_cback_data.connect_ind.miu;
378            nfa_cho_cb.collision_remote_sap = p_data->llcp_cback_data.connect_ind.remote_sap;
379            nfa_cho_cb.collision_local_sap  = p_data->llcp_cback_data.connect_ind.local_sap;
380            nfa_cho_cb.collision_congested  = FALSE;
381        }
382        break;
383
384    case NFA_CHO_RX_HANDOVER_MSG_EVT:
385        /* peer device sent handover message before accepting connection */
386        /* clear collision flag */
387        nfa_cho_cb.flags &= ~NFA_CHO_FLAGS_CONN_COLLISION;
388
389        nfa_cho_cb.remote_miu = nfa_cho_cb.collision_remote_miu;
390        nfa_cho_cb.remote_sap = nfa_cho_cb.collision_remote_sap;
391        nfa_cho_cb.local_sap  = nfa_cho_cb.collision_local_sap;
392        nfa_cho_cb.congested  = nfa_cho_cb.collision_congested;
393
394        nfa_cho_cb.substate  = NFA_CHO_SUBSTATE_W4_REMOTE_HR;
395        nfa_cho_cb.state     = NFA_CHO_ST_CONNECTED;
396
397        evt_data.connected.initial_role = NFA_CHO_ROLE_SELECTOR;
398        nfa_cho_cb.p_cback (NFA_CHO_CONNECTED_EVT, &evt_data);
399
400        /* process handover message in nfa_cho_cb.p_rx_ndef_msg */
401        nfa_cho_proc_rx_handover_msg ();
402        break;
403
404    case NFA_CHO_LLCP_DISCONNECT_RESP_EVT:
405        /*
406        ** if peer rejected our connection request or there is no handover service in peer
407        ** but we already accepted connection from peer
408        */
409        if (nfa_cho_cb.flags & NFA_CHO_FLAGS_CONN_COLLISION)
410        {
411            /* clear collision flag */
412            nfa_cho_cb.flags &= ~NFA_CHO_FLAGS_CONN_COLLISION;
413
414            nfa_cho_cb.remote_miu = nfa_cho_cb.collision_remote_miu;
415            nfa_cho_cb.remote_sap = nfa_cho_cb.collision_remote_sap;
416            nfa_cho_cb.local_sap  = nfa_cho_cb.collision_local_sap;
417            nfa_cho_cb.congested  = nfa_cho_cb.collision_congested;
418
419            nfa_cho_cb.substate  = NFA_CHO_SUBSTATE_W4_REMOTE_HR;
420            nfa_cho_cb.state     = NFA_CHO_ST_CONNECTED;
421
422            evt_data.connected.initial_role = NFA_CHO_ROLE_SELECTOR;
423            nfa_cho_cb.p_cback (NFA_CHO_CONNECTED_EVT, &evt_data);
424        }
425        else
426        {
427            nfa_cho_cb.state = NFA_CHO_ST_IDLE;
428            nfa_cho_process_disconnection (NFA_CHO_DISC_REASON_CONNECTION_FAIL);
429        }
430        break;
431
432    case NFA_CHO_LLCP_DISCONNECT_IND_EVT:
433        /* if peer disconnects collision connection */
434        if (  (nfa_cho_cb.flags & NFA_CHO_FLAGS_CONN_COLLISION)
435            &&(p_data->llcp_cback_data.disconnect_ind.local_sap == nfa_cho_cb.collision_local_sap)
436            &&(p_data->llcp_cback_data.disconnect_ind.remote_sap == nfa_cho_cb.collision_remote_sap)  )
437        {
438            /* clear collision flag */
439            nfa_cho_cb.flags &= ~NFA_CHO_FLAGS_CONN_COLLISION;
440        }
441        else    /* Link failure before peer accepts or rejects connection request */
442        {
443            nfa_cho_cb.state = NFA_CHO_ST_IDLE;
444            nfa_cho_process_disconnection (NFA_CHO_DISC_REASON_CONNECTION_FAIL);
445        }
446        break;
447
448    case NFA_CHO_LLCP_CONGEST_EVT:
449        /* if collision connection is congested */
450        if (  (p_data->llcp_cback_data.congest.link_type == LLCP_LINK_TYPE_DATA_LINK_CONNECTION)
451            &&(nfa_cho_cb.flags & NFA_CHO_FLAGS_CONN_COLLISION))
452        {
453            nfa_cho_cb.collision_congested = p_data->llcp_cback_data.congest.is_congested;
454        }
455        break;
456
457    case NFA_CHO_API_SEND_HR_EVT:
458        GKI_freebuf (p_data->api_send_hr.p_ndef);
459        break;
460
461    case NFA_CHO_API_SEND_HS_EVT:
462        GKI_freebuf (p_data->api_send_hs.p_ndef);
463        break;
464
465    case NFA_CHO_NDEF_TYPE_HANDLER_EVT:
466        nfa_cho_proc_ndef_type_handler_evt (p_data);
467        break;
468
469    default:
470        CHO_TRACE_ERROR0 ("Unknown event");
471        break;
472    }
473}
474
475/*******************************************************************************
476**
477** Function         nfa_cho_sm_connected
478**
479** Description      Process event in connected state
480**
481** Returns          None
482**
483*******************************************************************************/
484static void nfa_cho_sm_connected (tNFA_CHO_INT_EVT event, tNFA_CHO_INT_EVENT_DATA *p_data)
485{
486    tNFA_CHO_EVT_DATA evt_data;
487    tNFA_STATUS       status;
488
489    switch (event)
490    {
491    case NFA_CHO_API_REG_EVT:
492        evt_data.status = NFA_STATUS_FAILED;
493        p_data->api_reg.p_cback (NFA_CHO_REG_EVT, &evt_data);
494        break;
495
496    case NFA_CHO_API_DEREG_EVT:
497        nfa_cho_proc_api_dereg ();
498        nfa_cho_cb.state = NFA_CHO_ST_DISABLED;
499        break;
500
501    case NFA_CHO_API_CONNECT_EVT:
502        /* it could be race condition, let app know outgoing connection failed */
503        evt_data.disconnected.reason = NFA_CHO_DISC_REASON_ALEADY_CONNECTED;
504        nfa_cho_cb.p_cback (NFA_CHO_DISCONNECTED_EVT, &evt_data);
505        break;
506
507    case NFA_CHO_API_DISCONNECT_EVT:
508        /* disconnect collision connection accepted by local device */
509        if (nfa_cho_cb.flags & NFA_CHO_FLAGS_CONN_COLLISION)
510        {
511            LLCP_DisconnectReq (nfa_cho_cb.collision_local_sap,
512                                nfa_cho_cb.collision_remote_sap,
513                                FALSE);
514
515            /* clear collision flag */
516            nfa_cho_cb.flags &= ~NFA_CHO_FLAGS_CONN_COLLISION;
517        }
518
519        LLCP_DisconnectReq (nfa_cho_cb.local_sap,
520                            nfa_cho_cb.remote_sap,
521                            FALSE);
522
523        /* store disconnect reason */
524        nfa_cho_cb.disc_reason = NFA_CHO_DISC_REASON_API_REQUEST;
525        break;
526
527    case NFA_CHO_API_SEND_HR_EVT:
528        if (nfa_cho_cb.substate == NFA_CHO_SUBSTATE_W4_LOCAL_HR)
529        {
530            /* Send Handover Request Message */
531            status = nfa_cho_send_hr (&p_data->api_send_hr);
532
533            if (status == NFA_STATUS_OK)
534            {
535                nfa_cho_cb.substate = NFA_CHO_SUBSTATE_W4_REMOTE_HS;
536                /* start timer for Handover Select Message */
537                nfa_sys_start_timer (&nfa_cho_cb.timer, 0, NFA_CHO_TIMEOUT_FOR_HS);
538            }
539            else
540            {
541                CHO_TRACE_ERROR0 ("NFA CHO failed to send Hr");
542                nfa_cho_notify_tx_fail_evt (status);
543            }
544        }
545        else
546        {
547            CHO_TRACE_ERROR0 ("NFA CHO got unexpected NFA_CHO_API_SEND_HR_EVT");
548            nfa_cho_notify_tx_fail_evt (NFA_STATUS_SEMANTIC_ERROR);
549        }
550        GKI_freebuf (p_data->api_send_hr.p_ndef);
551        break;
552
553    case NFA_CHO_API_SEND_HS_EVT:
554        if (nfa_cho_cb.substate == NFA_CHO_SUBSTATE_W4_LOCAL_HS)
555        {
556            /* send Handover Select Message */
557            status = nfa_cho_send_hs (&p_data->api_send_hs);
558            if (status == NFA_STATUS_OK)
559            {
560                nfa_cho_cb.substate = NFA_CHO_SUBSTATE_W4_REMOTE_HR;
561            }
562            else
563            {
564                CHO_TRACE_ERROR0 ("NFA CHO failed to send Hs");
565                nfa_cho_notify_tx_fail_evt (status);
566            }
567        }
568        else
569        {
570            CHO_TRACE_ERROR0 ("NFA CHO got unexpected NFA_CHO_API_SEND_HS_EVT");
571            nfa_cho_notify_tx_fail_evt (NFA_STATUS_SEMANTIC_ERROR);
572        }
573        GKI_freebuf (p_data->api_send_hs.p_ndef);
574        break;
575
576    case NFA_CHO_API_SEL_ERR_EVT:
577        /* application detected error */
578        if (nfa_cho_cb.substate == NFA_CHO_SUBSTATE_W4_LOCAL_HS)
579        {
580            /* Send Handover Select Error record */
581            status = nfa_cho_send_hs_error (p_data->api_sel_err.error_reason,
582                                            p_data->api_sel_err.error_data);
583            if (status == NFA_STATUS_OK)
584            {
585                nfa_cho_cb.substate = NFA_CHO_SUBSTATE_W4_REMOTE_HR;
586            }
587            else
588            {
589                CHO_TRACE_ERROR0 ("Failed to send Hs Error record");
590                nfa_cho_notify_tx_fail_evt (status);
591            }
592        }
593        else
594        {
595            CHO_TRACE_ERROR0 ("NFA CHO got unexpected NFA_CHO_API_SEL_ERR_EVT");
596            nfa_cho_notify_tx_fail_evt (NFA_STATUS_SEMANTIC_ERROR);
597        }
598        break;
599
600    case NFA_CHO_LLCP_CONNECT_RESP_EVT:
601        /* peer accepted connection after we accepted and received Hr */
602        /* disconnect data link connection created by local device    */
603        LLCP_DisconnectReq (p_data->llcp_cback_data.connect_resp.local_sap,
604                            p_data->llcp_cback_data.connect_resp.remote_sap,
605                            FALSE);
606        break;
607
608    case NFA_CHO_LLCP_CONNECT_IND_EVT:
609        LLCP_ConnectReject (p_data->llcp_cback_data.connect_ind.local_sap,
610                            p_data->llcp_cback_data.connect_ind.remote_sap,
611                            LLCP_SAP_DM_REASON_TEMP_REJECT_THIS);
612        break;
613
614    case NFA_CHO_RX_HANDOVER_MSG_EVT:
615        /* process handover message in nfa_cho_cb.p_rx_ndef_msg */
616        nfa_cho_proc_rx_handover_msg ();
617        break;
618
619    case NFA_CHO_LLCP_DISCONNECT_IND_EVT:
620        if (  (p_data->llcp_cback_data.disconnect_ind.local_sap  == nfa_cho_cb.local_sap)
621            &&(p_data->llcp_cback_data.disconnect_ind.remote_sap == nfa_cho_cb.remote_sap)  )
622        {
623            nfa_cho_cb.state = NFA_CHO_ST_IDLE;
624            nfa_cho_process_disconnection (NFA_CHO_DISC_REASON_PEER_REQUEST);
625        }
626        else  /* if disconnection of collision conneciton */
627        {
628            nfa_cho_cb.flags &= ~NFA_CHO_FLAGS_CONN_COLLISION;
629        }
630        break;
631
632    case NFA_CHO_LLCP_DISCONNECT_RESP_EVT:
633        if (  (p_data->llcp_cback_data.disconnect_ind.local_sap  == nfa_cho_cb.local_sap)
634            &&(p_data->llcp_cback_data.disconnect_ind.remote_sap == nfa_cho_cb.remote_sap)  )
635        {
636            nfa_cho_cb.state = NFA_CHO_ST_IDLE;
637            nfa_cho_process_disconnection (nfa_cho_cb.disc_reason);
638        }
639        else  /* if disconnection of collision conneciton */
640        {
641            nfa_cho_cb.flags &= ~NFA_CHO_FLAGS_CONN_COLLISION;
642        }
643        break;
644
645    case NFA_CHO_LLCP_CONGEST_EVT:
646        /* if data link connection is congested */
647        if ( (p_data->llcp_cback_data.congest.link_type  == LLCP_LINK_TYPE_DATA_LINK_CONNECTION)
648           &&(p_data->llcp_cback_data.congest.local_sap  == nfa_cho_cb.local_sap)
649           &&(p_data->llcp_cback_data.congest.remote_sap == nfa_cho_cb.remote_sap)  )
650        {
651            nfa_cho_cb.congested = p_data->llcp_cback_data.congest.is_congested;
652
653            if (!nfa_cho_cb.congested)
654            {
655                /* send remaining message if any */
656                if (  (nfa_cho_cb.p_tx_ndef_msg)
657                    &&(nfa_cho_cb.tx_ndef_sent_size < nfa_cho_cb.tx_ndef_cur_size)  )
658                {
659                    nfa_cho_send_handover_msg ();
660                }
661            }
662        }
663        break;
664
665    case NFA_CHO_TIMEOUT_EVT:
666        if (nfa_cho_cb.substate == NFA_CHO_SUBSTATE_W4_REMOTE_HS)
667        {
668            CHO_TRACE_ERROR0 ("Failed to receive Hs message");
669        }
670        else if (nfa_cho_cb.substate == NFA_CHO_SUBSTATE_W4_REMOTE_HR)
671        {
672            /* we didn't get complete Hr, don't need to notify application */
673            CHO_TRACE_ERROR0 ("Failed to receive Hr message");
674        }
675
676        /* store disconnect reason and disconnect */
677        nfa_cho_cb.disc_reason = NFA_CHO_DISC_REASON_TIMEOUT;
678        LLCP_DisconnectReq (nfa_cho_cb.local_sap,
679                            nfa_cho_cb.remote_sap,
680                            FALSE);
681        break;
682
683    case NFA_CHO_NDEF_TYPE_HANDLER_EVT:
684        nfa_cho_proc_ndef_type_handler_evt (p_data);
685        break;
686
687    default:
688        CHO_TRACE_ERROR0 ("Unknown event");
689        break;
690    }
691}
692/*******************************************************************************
693**
694** Function         nfa_cho_sm_execute
695**
696** Description      Process event in state machine
697**
698** Returns          None
699**
700*******************************************************************************/
701void nfa_cho_sm_execute (tNFA_CHO_INT_EVT event, tNFA_CHO_INT_EVENT_DATA *p_data)
702{
703#if (BT_TRACE_VERBOSE == TRUE)
704    CHO_TRACE_DEBUG2 ("nfa_cho_sm_execute (): State[%s], Event[%s]",
705                       nfa_cho_state_code (nfa_cho_cb.state),
706                       nfa_cho_evt_code (event));
707#else
708    CHO_TRACE_DEBUG2 ("nfa_cho_sm_execute (): State[%d], Event[%d]",
709                       nfa_cho_cb.state, event);
710#endif
711
712
713    switch (nfa_cho_cb.state)
714    {
715    case NFA_CHO_ST_DISABLED:
716        nfa_cho_sm_disabled (event, p_data);
717        break;
718
719    case NFA_CHO_ST_IDLE:
720        nfa_cho_sm_idle (event, p_data);
721        break;
722
723    case NFA_CHO_ST_W4_CC:
724        nfa_cho_sm_w4_cc (event, p_data);
725        break;
726
727    case NFA_CHO_ST_CONNECTED:
728        nfa_cho_sm_connected (event, p_data);
729        break;
730
731    default:
732        CHO_TRACE_ERROR0 ("Unknown state");
733        break;
734    }
735}
736
737/*******************************************************************************
738**
739** Function         nfa_cho_resolve_collision
740**
741** Description      Resolve collision by random number in Hr
742**
743** Returns          None
744**
745*******************************************************************************/
746void nfa_cho_resolve_collision (BOOLEAN *p_free_hr)
747{
748    tNFA_CHO_ROLE_TYPE role;
749    tNFA_STATUS        status;
750
751    /* resolve collistion by random number */
752    role = nfa_cho_get_local_device_role (nfa_cho_cb.rx_ndef_cur_size,
753                                          nfa_cho_cb.p_rx_ndef_msg);
754
755    /* if local device becomes selector */
756    if (role == NFA_CHO_ROLE_SELECTOR)
757    {
758        /* peer device is winner so clean up any collision */
759        if (nfa_cho_cb.flags & NFA_CHO_FLAGS_CONN_COLLISION)
760        {
761            /* disconnect data link connection created by local device */
762            LLCP_DisconnectReq (nfa_cho_cb.local_sap,
763                                nfa_cho_cb.remote_sap,
764                                FALSE);
765
766            nfa_cho_cb.remote_miu = nfa_cho_cb.collision_remote_miu;
767            nfa_cho_cb.remote_sap = nfa_cho_cb.collision_remote_sap;
768            nfa_cho_cb.local_sap  = nfa_cho_cb.collision_local_sap;
769            nfa_cho_cb.congested  = nfa_cho_cb.collision_congested;
770        }
771
772        nfa_cho_cb.substate = NFA_CHO_SUBSTATE_W4_LOCAL_HS;
773
774        nfa_cho_proc_hr (nfa_cho_cb.rx_ndef_cur_size,
775                         nfa_cho_cb.p_rx_ndef_msg);
776
777        *p_free_hr = TRUE;
778    }
779    /* if both random numbers are equal */
780    else if (role == NFA_CHO_ROLE_UNDECIDED)
781    {
782        /* send Hr with new random number */
783        if (nfa_cho_cb.p_tx_ndef_msg)
784        {
785            status = nfa_cho_update_random_number (nfa_cho_cb.p_tx_ndef_msg);
786
787            if (status == NFA_STATUS_OK)
788            {
789                nfa_cho_cb.tx_ndef_sent_size = 0;
790                status = nfa_cho_send_handover_msg ();
791            }
792        }
793        else
794        {
795            status = NFA_STATUS_FAILED;
796        }
797
798        if (status == NFA_STATUS_FAILED)
799        {
800            CHO_TRACE_ERROR0 ("Failed to send Hr record with new random number");
801
802            nfa_cho_cb.disc_reason = NFA_CHO_DISC_REASON_INTERNAL_ERROR;
803
804            /* disconnect and notify application */
805            LLCP_DisconnectReq (nfa_cho_cb.local_sap,
806                                nfa_cho_cb.remote_sap,
807                                FALSE);
808        }
809        else
810        {
811            /* restart timer */
812            nfa_sys_start_timer (&nfa_cho_cb.timer, 0, NFA_CHO_TIMEOUT_FOR_HS);
813
814            /* Don't free previous tx NDEF message because we are reusing it */
815            *p_free_hr = FALSE;
816        }
817    }
818    else /* if (role == NFA_CHO_ROLE_REQUESTER) */
819    {
820        /* wait for "Hs" record */
821        *p_free_hr = TRUE;
822    }
823}
824
825/*******************************************************************************
826**
827** Function         nfa_cho_check_disconnect_collision
828**
829** Description      Disconnect any collision connection
830**
831** Returns          None
832**
833*******************************************************************************/
834void nfa_cho_check_disconnect_collision (void)
835{
836    if (nfa_cho_cb.flags & NFA_CHO_FLAGS_CONN_COLLISION)
837    {
838        /* disconnect collision connection */
839        LLCP_DisconnectReq (nfa_cho_cb.collision_local_sap,
840                            nfa_cho_cb.collision_remote_sap,
841                            FALSE);
842    }
843}
844
845/*******************************************************************************
846**
847** Function         nfa_cho_proc_rx_handover_msg
848**
849** Description      Process received Handover Message
850**
851** Returns          None
852**
853*******************************************************************************/
854void nfa_cho_proc_rx_handover_msg (void)
855{
856    tNFA_CHO_MSG_TYPE msg_type;
857    BOOLEAN           free_tx_ndef_msg = TRUE;
858
859    /* get message type before processing to check collision */
860    msg_type = nfa_cho_get_msg_type (nfa_cho_cb.rx_ndef_cur_size,
861                                     nfa_cho_cb.p_rx_ndef_msg);
862
863    if (nfa_cho_cb.substate == NFA_CHO_SUBSTATE_W4_REMOTE_HS)
864    {
865        /* if we sent "Hr" but received "Hr", collision */
866        if (msg_type == NFA_CHO_MSG_HR)
867        {
868            nfa_cho_resolve_collision (&free_tx_ndef_msg);
869        }
870        else if (msg_type == NFA_CHO_MSG_HS)
871        {
872            /* parse and report application */
873            nfa_cho_proc_hs (nfa_cho_cb.rx_ndef_cur_size,
874                             nfa_cho_cb.p_rx_ndef_msg);
875
876            nfa_cho_cb.substate = NFA_CHO_SUBSTATE_W4_LOCAL_HR;
877        }
878        else
879        {
880            CHO_TRACE_ERROR0 ("nfa_cho_proc_rx_handover_msg (): Unknown Message Type");
881
882            nfa_cho_check_disconnect_collision ();
883
884            nfa_cho_cb.disc_reason = NFA_CHO_DISC_REASON_UNKNOWN_MSG;
885
886            LLCP_DisconnectReq (nfa_cho_cb.local_sap,
887                                nfa_cho_cb.remote_sap,
888                                FALSE);
889        }
890    }
891    else if (nfa_cho_cb.substate == NFA_CHO_SUBSTATE_W4_REMOTE_HR)
892    {
893        if (msg_type == NFA_CHO_MSG_HR)
894        {
895            /* parse and notify NFA_CHO_REQ_EVT to application */
896            nfa_cho_proc_hr (nfa_cho_cb.rx_ndef_cur_size,
897                             nfa_cho_cb.p_rx_ndef_msg);
898
899            /* In case of parsing error, let peer got timeout (1 sec) */
900
901            /* wait for application selection */
902            nfa_cho_cb.substate = NFA_CHO_SUBSTATE_W4_LOCAL_HS;
903        }
904        else
905        {
906            CHO_TRACE_ERROR0 ("nfa_cho_proc_rx_handover_msg (): Expecting Handover Request");
907
908            nfa_cho_check_disconnect_collision ();
909
910            nfa_cho_cb.disc_reason = NFA_CHO_DISC_REASON_SEMANTIC_ERROR;
911
912            LLCP_DisconnectReq (nfa_cho_cb.local_sap,
913                                nfa_cho_cb.remote_sap,
914                                FALSE);
915        }
916    }
917    else
918    {
919        CHO_TRACE_ERROR1 ("nfa_cho_proc_rx_handover_msg (): Unexpected data in substate (0x%x)", nfa_cho_cb.substate);
920
921        nfa_cho_check_disconnect_collision ();
922
923        nfa_cho_cb.disc_reason = NFA_CHO_DISC_REASON_SEMANTIC_ERROR;
924
925        LLCP_DisconnectReq (nfa_cho_cb.local_sap,
926                            nfa_cho_cb.remote_sap,
927                            FALSE);
928    }
929
930    if ((free_tx_ndef_msg) && (nfa_cho_cb.p_tx_ndef_msg))
931    {
932        GKI_freebuf (nfa_cho_cb.p_tx_ndef_msg);
933        nfa_cho_cb.p_tx_ndef_msg = NULL;
934    }
935
936    /* processing rx message is done, free buffer for rx handover message */
937    if (nfa_cho_cb.p_rx_ndef_msg)
938    {
939        GKI_freebuf (nfa_cho_cb.p_rx_ndef_msg);
940        nfa_cho_cb.p_rx_ndef_msg = NULL;
941    }
942}
943
944#if (BT_TRACE_VERBOSE == TRUE)
945/*******************************************************************************
946**
947** Function         nfa_cho_state_code
948**
949** Description
950**
951** Returns          string of state
952**
953*******************************************************************************/
954static char *nfa_cho_state_code (tNFA_CHO_STATE state_code)
955{
956    switch (state_code)
957    {
958    case NFA_CHO_ST_DISABLED:
959        return "DISABLED";
960    case NFA_CHO_ST_IDLE:
961        return "IDLE";
962    case NFA_CHO_ST_CONNECTED:
963        return "CONNECTED";
964    default:
965        return "unknown state";
966    }
967}
968
969/*******************************************************************************
970**
971** Function         nfa_cho_evt_code
972**
973** Description
974**
975** Returns          string of event
976**
977*******************************************************************************/
978char *nfa_cho_evt_code (tNFA_CHO_INT_EVT evt_code)
979{
980    switch (evt_code)
981    {
982    case NFA_CHO_API_REG_EVT:
983        return "API_REG";
984    case NFA_CHO_API_DEREG_EVT:
985        return "API_DEREG";
986    case NFA_CHO_API_CONNECT_EVT:
987        return "API_CONNECT";
988    case NFA_CHO_API_DISCONNECT_EVT:
989        return "API_DISCONNECT";
990    case NFA_CHO_API_SEND_HR_EVT:
991        return "API_SEND_HR";
992    case NFA_CHO_API_SEND_HS_EVT:
993        return "API_SEND_HS";
994    case NFA_CHO_API_SEL_ERR_EVT:
995        return "API_SEL_ERR";
996
997    case NFA_CHO_RX_HANDOVER_MSG_EVT:
998        return "RX_HANDOVER_MSG";
999
1000    case NFA_CHO_LLCP_CONNECT_IND_EVT:
1001        return "LLCP_CONNECT_IND";
1002    case NFA_CHO_LLCP_CONNECT_RESP_EVT:
1003        return "LLCP_CONNECT_RESP";
1004    case NFA_CHO_LLCP_DISCONNECT_IND_EVT:
1005        return "LLCP_DISCONNECT_IND";
1006    case NFA_CHO_LLCP_DISCONNECT_RESP_EVT:
1007        return "LLCP_DISCONNECT_RESP";
1008    case NFA_CHO_LLCP_CONGEST_EVT:
1009        return "LLCP_CONGEST";
1010    case NFA_CHO_LLCP_LINK_STATUS_EVT:
1011        return "LLCP_LINK_STATUS";
1012
1013    case NFA_CHO_NDEF_TYPE_HANDLER_EVT:
1014        return "NDEF_TYPE_HANDLER";
1015    case NFA_CHO_TIMEOUT_EVT:
1016        return "TIMEOUT";
1017
1018    default:
1019        return "unknown event";
1020    }
1021}
1022#endif  /* Debug Functions */
1023