• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 *****************************************************************************/
41 static void nfa_cho_sm_disabled (tNFA_CHO_INT_EVT event, tNFA_CHO_INT_EVENT_DATA *p_data);
42 static void nfa_cho_sm_idle (tNFA_CHO_INT_EVT event, tNFA_CHO_INT_EVENT_DATA *p_data);
43 static void nfa_cho_sm_w4_cc (tNFA_CHO_INT_EVT event, tNFA_CHO_INT_EVENT_DATA *p_data);
44 static void nfa_cho_sm_connected (tNFA_CHO_INT_EVT event, tNFA_CHO_INT_EVENT_DATA *p_data);
45 static void nfa_cho_proc_rx_handover_msg (void);
46 
47 /* debug functions type */
48 #if (BT_TRACE_VERBOSE == TRUE)
49 static char *nfa_cho_state_code (tNFA_CHO_STATE state_code);
50 static 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 *******************************************************************************/
nfa_cho_sm_llcp_cback(tLLCP_SAP_CBACK_DATA * p_data)67 void 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 *******************************************************************************/
nfa_cho_sm_disabled(tNFA_CHO_INT_EVT event,tNFA_CHO_INT_EVENT_DATA * p_data)126 static 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 *******************************************************************************/
nfa_cho_sm_idle(tNFA_CHO_INT_EVT event,tNFA_CHO_INT_EVENT_DATA * p_data)174 static 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 *******************************************************************************/
nfa_cho_sm_w4_cc(tNFA_CHO_INT_EVT event,tNFA_CHO_INT_EVENT_DATA * p_data)298 static 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 *******************************************************************************/
nfa_cho_sm_connected(tNFA_CHO_INT_EVT event,tNFA_CHO_INT_EVENT_DATA * p_data)484 static 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 *******************************************************************************/
nfa_cho_sm_execute(tNFA_CHO_INT_EVT event,tNFA_CHO_INT_EVENT_DATA * p_data)701 void 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 *******************************************************************************/
nfa_cho_resolve_collision(BOOLEAN * p_free_hr)746 void 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 *******************************************************************************/
nfa_cho_check_disconnect_collision(void)834 void 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 *******************************************************************************/
nfa_cho_proc_rx_handover_msg(void)854 void 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 *******************************************************************************/
nfa_cho_state_code(tNFA_CHO_STATE state_code)954 static 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 *******************************************************************************/
nfa_cho_evt_code(tNFA_CHO_INT_EVT evt_code)978 char *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