Commit | Line | Data |
---|---|---|
6fa3eb70 S |
1 | /* |
2 | ** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/mgmt/aaa_fsm.c#2 $ | |
3 | */ | |
4 | ||
5 | /*! \file "aaa_fsm.c" | |
6 | \brief This file defines the FSM for AAA MODULE. | |
7 | ||
8 | This file defines the FSM for AAA MODULE. | |
9 | */ | |
10 | ||
11 | ||
12 | ||
13 | /* | |
14 | ** $Log: aaa_fsm.c $ | |
15 | * | |
16 | * 07 17 2012 yuche.tsai | |
17 | * NULL | |
18 | * Compile no error before trial run. | |
19 | * | |
20 | * 06 13 2012 yuche.tsai | |
21 | * NULL | |
22 | * Update maintrunk driver. | |
23 | * Add support for driver compose assoc request frame. | |
24 | * | |
25 | * 03 02 2012 terry.wu | |
26 | * NULL | |
27 | * Sync CFG80211 modification from branch 2,2. | |
28 | * | |
29 | * 02 22 2012 yuche.tsai | |
30 | * NULL | |
31 | * Solve sigma test 5.1.3 issue, assoc response should have P2P IE. | |
32 | * | |
33 | * 12 02 2011 yuche.tsai | |
34 | * NULL | |
35 | * Resolve inorder issue under AP mode. | |
36 | * | |
37 | * data frame may TX before assoc response frame. | |
38 | * | |
39 | * 11 18 2011 yuche.tsai | |
40 | * NULL | |
41 | * CONFIG P2P support RSSI query, default turned off. | |
42 | * | |
43 | * 06 17 2011 terry.wu | |
44 | * NULL | |
45 | * Add BoW 11N support. | |
46 | * | |
47 | * 06 02 2011 eddie.chen | |
48 | * [WCXRP00000759] [MT6620 Wi-Fi][DRV] Update RCPI in AAA | |
49 | * Update RCPI when receiving Assoc request. | |
50 | * | |
51 | * 04 21 2011 terry.wu | |
52 | * [WCXRP00000674] [MT6620 Wi-Fi][Driver] Refine AAA authSendAuthFrame | |
53 | * Add network type parameter to authSendAuthFrame. | |
54 | * | |
55 | * 04 15 2011 chinghwa.yu | |
56 | * [WCXRP00000065] Update BoW design and settings | |
57 | * Add BOW short range mode. | |
58 | * | |
59 | * 04 09 2011 chinghwa.yu | |
60 | * [WCXRP00000065] Update BoW design and settings | |
61 | * Change Link connection event procedure and change skb length check to 1512 bytes. | |
62 | * | |
63 | * 03 09 2011 wh.su | |
64 | * [WCXRP00000530] [MT6620 Wi-Fi] [Driver] skip doing p2pRunEventAAAComplete after send assoc response Tx Done | |
65 | * Skip to call p2pRunEventAAAComplete to avoid indicate STA connect twice. | |
66 | * | |
67 | * 03 04 2011 terry.wu | |
68 | * [WCXRP00000515] [MT6620 Wi-Fi][Driver] Surpress compiler warning which is identified by GNU compiler collection | |
69 | * Remove unused variable. | |
70 | * | |
71 | * 02 16 2011 yuche.tsai | |
72 | * [WCXRP00000429] [Volunteer Patch][MT6620][Driver] Hot Spot Client Limit Issue | |
73 | * Add more check after RX assoc frame under Hot-Spot mode. | |
74 | * | |
75 | * 02 09 2011 yuche.tsai | |
76 | * [WCXRP00000429] [Volunteer Patch][MT6620][Driver] Hot Spot Client Limit Issue | |
77 | * Fix Client Limit Issue. | |
78 | * | |
79 | * 01 25 2011 yuche.tsai | |
80 | * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. | |
81 | * Change Station Type in Station Record, Modify MACRO definition for getting station type & network type index & Role. | |
82 | * | |
83 | * 01 15 2011 puff.wen | |
84 | * NULL | |
85 | * [On behalf of Frog] Add CFG_ENABLE_WIFI_DIRECT to p2pRunEventAAAComplete | |
86 | * | |
87 | * 01 14 2011 yuche.tsai | |
88 | * [WCXRP00000352] [Volunteer Patch][MT6620][Driver] P2P Statsion Record Client List Issue | |
89 | * Modify AAA flow according to CM's comment. | |
90 | * | |
91 | * 09 03 2010 kevin.huang | |
92 | * NULL | |
93 | * Refine #include sequence and solve recursive/nested #include issue | |
94 | * | |
95 | * 08 29 2010 yuche.tsai | |
96 | * NULL | |
97 | * Fix Compile warning, type cast from UINT_32 to UINT_16. | |
98 | * | |
99 | * 08 26 2010 yuche.tsai | |
100 | * NULL | |
101 | * In P2P AT GO test mode under WinXP, we would not indicate connected event to host. | |
102 | * | |
103 | * 08 24 2010 cm.chang | |
104 | * NULL | |
105 | * Support RLM initail channel of Ad-hoc, P2P and BOW | |
106 | * | |
107 | * 08 23 2010 chinghwa.yu | |
108 | * NULL | |
109 | * Update for BOW. | |
110 | * | |
111 | * 08 20 2010 kevin.huang | |
112 | * NULL | |
113 | * Modify AAA Module for changing STA STATE 3 at p2p/bowRunEventAAAComplete() | |
114 | * | |
115 | * 08 17 2010 yuche.tsai | |
116 | * NULL | |
117 | * Fix bug while enabling P2P GO. | |
118 | * | |
119 | * 08 16 2010 kevin.huang | |
120 | * NULL | |
121 | * Refine AAA functions | |
122 | * | |
123 | * 07 08 2010 cp.wu | |
124 | * | |
125 | * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. | |
126 | * | |
127 | * 06 21 2010 cp.wu | |
128 | * [WPD00003833][MT6620 and MT5931] Driver migration | |
129 | * refine TX-DONE callback. | |
130 | * | |
131 | * 06 21 2010 yuche.tsai | |
132 | * [WPD00003839][MT6620 5931][P2P] Feature migration | |
133 | * modify due to P2P functino call prototype change. | |
134 | * | |
135 | * 06 17 2010 yuche.tsai | |
136 | * [WPD00003839][MT6620 5931][P2P] Feature migration | |
137 | * First draft for migration P2P FSM from FW to Driver. | |
138 | * | |
139 | * 04 02 2010 kevin.huang | |
140 | * [BORA00000603][WIFISYS] [New Feature] AAA Module Support | |
141 | * Modify CFG flags | |
142 | * | |
143 | * 02 26 2010 kevin.huang | |
144 | * [BORA00000603][WIFISYS] [New Feature] AAA Module Support | |
145 | * add support of Driver STA_RECORD_T activation | |
146 | * | |
147 | * 02 04 2010 kevin.huang | |
148 | * [BORA00000603][WIFISYS] [New Feature] AAA Module Support | |
149 | * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup | |
150 | */ | |
151 | ||
152 | /******************************************************************************* | |
153 | * C O M P I L E R F L A G S | |
154 | ******************************************************************************** | |
155 | */ | |
156 | ||
157 | /******************************************************************************* | |
158 | * E X T E R N A L R E F E R E N C E S | |
159 | ******************************************************************************** | |
160 | */ | |
161 | #include "precomp.h" | |
162 | ||
163 | /******************************************************************************* | |
164 | * C O N S T A N T S | |
165 | ******************************************************************************** | |
166 | */ | |
167 | ||
168 | /******************************************************************************* | |
169 | * D A T A T Y P E S | |
170 | ******************************************************************************** | |
171 | */ | |
172 | ||
173 | /******************************************************************************* | |
174 | * P U B L I C D A T A | |
175 | ******************************************************************************** | |
176 | */ | |
177 | ||
178 | /******************************************************************************* | |
179 | * P R I V A T E D A T A | |
180 | ******************************************************************************** | |
181 | */ | |
182 | ||
183 | /******************************************************************************* | |
184 | * M A C R O S | |
185 | ******************************************************************************** | |
186 | */ | |
187 | ||
188 | /******************************************************************************* | |
189 | * F U N C T I O N D E C L A R A T I O N S | |
190 | ******************************************************************************** | |
191 | */ | |
192 | ||
193 | /******************************************************************************* | |
194 | * F U N C T I O N S | |
195 | ******************************************************************************** | |
196 | */ | |
197 | #if 0 | |
198 | /*----------------------------------------------------------------------------*/ | |
199 | /*! | |
200 | * @brief This function will send Event to AIS/BOW/P2P | |
201 | * | |
202 | * @param[in] rJoinStatus To indicate JOIN success or failure. | |
203 | * @param[in] prStaRec Pointer to the STA_RECORD_T | |
204 | * @param[in] prSwRfb Pointer to the SW_RFB_T | |
205 | ||
206 | * @return none | |
207 | */ | |
208 | /*----------------------------------------------------------------------------*/ | |
209 | WLAN_STATUS | |
210 | aaaFsmSendEventJoinComplete ( | |
211 | WLAN_STATUS rJoinStatus, | |
212 | P_STA_RECORD_T prStaRec, | |
213 | P_SW_RFB_T prSwRfb | |
214 | ) | |
215 | { | |
216 | P_MSG_SAA_JOIN_COMP_T prJoinCompMsg; | |
217 | ||
218 | ||
219 | ASSERT(prStaRec); | |
220 | ||
221 | prJoinCompMsg = cnmMemAlloc(RAM_TYPE_TCM, sizeof(MSG_SAA_JOIN_COMP_T)); | |
222 | if (!prJoinCompMsg) { | |
223 | return WLAN_STATUS_RESOURCES; | |
224 | } | |
225 | ||
226 | if (IS_STA_IN_AIS(prStaRec)) { | |
227 | prJoinCompMsg->rMsgHdr.eMsgId = MID_SAA_AIS_JOIN_COMPLETE; | |
228 | } | |
229 | else if (IS_STA_IN_P2P(prStaRec)) { | |
230 | prJoinCompMsg->rMsgHdr.eMsgId = MID_SAA_P2P_JOIN_COMPLETE; | |
231 | } | |
232 | else if (IS_STA_IN_BOW(prStaRec)) { | |
233 | prJoinCompMsg->rMsgHdr.eMsgId = MID_SAA_BOW_JOIN_COMPLETE; | |
234 | } | |
235 | else { | |
236 | ASSERT(0); | |
237 | } | |
238 | ||
239 | prJoinCompMsg->rJoinStatus = rJoinStatus; | |
240 | prJoinCompMsg->prStaRec = prStaRec; | |
241 | prJoinCompMsg->prSwRfb = prSwRfb; | |
242 | ||
243 | mboxSendMsg(MBOX_ID_0, | |
244 | (P_MSG_HDR_T)prJoinCompMsg, | |
245 | MSG_SEND_METHOD_BUF); | |
246 | ||
247 | return WLAN_STATUS_SUCCESS; | |
248 | ||
249 | } /* end of saaFsmSendEventJoinComplete() */ | |
250 | ||
251 | /*----------------------------------------------------------------------------*/ | |
252 | /*! | |
253 | * @brief This function will handle the Start Event to AAA FSM. | |
254 | * | |
255 | * @param[in] prMsgHdr Message of Join Request for a particular STA. | |
256 | * | |
257 | * @return none | |
258 | */ | |
259 | /*----------------------------------------------------------------------------*/ | |
260 | VOID | |
261 | aaaFsmRunEventStart ( | |
262 | IN P_MSG_HDR_T prMsgHdr | |
263 | ) | |
264 | { | |
265 | P_MSG_SAA_JOIN_REQ_T prJoinReqMsg; | |
266 | P_STA_RECORD_T prStaRec; | |
267 | P_AIS_BSS_INFO_T prAisBssInfo; | |
268 | ||
269 | ||
270 | ASSERT(prMsgHdr); | |
271 | ||
272 | prJoinReqMsg = (P_MSG_SAA_JOIN_REQ_T)prMsgHdr; | |
273 | prStaRec = prJoinReqMsg->prStaRec; | |
274 | ||
275 | ASSERT(prStaRec); | |
276 | ||
277 | DBGLOG(SAA, LOUD, ("EVENT-START: Trigger SAA FSM\n")); | |
278 | ||
279 | cnmMemFree(prMsgHdr); | |
280 | ||
281 | //4 <1> Validation of SAA Start Event | |
282 | if (!IS_AP_STA(prStaRec->eStaType)) { | |
283 | ||
284 | DBGLOG(SAA, ERROR, ("EVENT-START: STA Type - %d was not supported.\n", prStaRec->eStaType)); | |
285 | ||
286 | /* Ignore the return value because don't care the prSwRfb */ | |
287 | saaFsmSendEventJoinComplete(WLAN_STATUS_FAILURE, prStaRec, NULL); | |
288 | ||
289 | return; | |
290 | } | |
291 | ||
292 | //4 <2> The previous JOIN process is not completed ? | |
293 | if (prStaRec->eAuthAssocState != AA_STATE_IDLE) { | |
294 | DBGLOG(SAA, ERROR, ("EVENT-START: Reentry of SAA Module.\n")); | |
295 | prStaRec->eAuthAssocState = AA_STATE_IDLE; | |
296 | } | |
297 | ||
298 | //4 <3> Reset Status Code and Time | |
299 | /* Update Station Record - Status/Reason Code */ | |
300 | prStaRec->u2StatusCode = STATUS_CODE_SUCCESSFUL; | |
301 | ||
302 | /* Update the record join time. */ | |
303 | GET_CURRENT_SYSTIME(&prStaRec->rLastJoinTime); | |
304 | ||
305 | prStaRec->ucTxAuthAssocRetryCount = 0; | |
306 | ||
307 | if (prStaRec->prChallengeText) { | |
308 | cnmMemFree(prStaRec->prChallengeText); | |
309 | prStaRec->prChallengeText = (P_IE_CHALLENGE_TEXT_T)NULL; | |
310 | } | |
311 | ||
312 | cnmTimerStopTimer(&prStaRec->rTxReqDoneOrRxRespTimer); | |
313 | ||
314 | prStaRec->ucStaState = STA_STATE_1; | |
315 | ||
316 | /* Trigger SAA MODULE */ | |
317 | saaFsmSteps(prStaRec, SAA_STATE_SEND_AUTH1, (P_SW_RFB_T)NULL); | |
318 | ||
319 | return; | |
320 | } /* end of saaFsmRunEventStart() */ | |
321 | #endif | |
322 | ||
323 | ||
324 | #if CFG_SUPPORT_AAA | |
325 | /*----------------------------------------------------------------------------*/ | |
326 | /*! | |
327 | * @brief This function will process the Rx Auth Request Frame and then | |
328 | * trigger AAA FSM. | |
329 | * | |
330 | * @param[in] prAdapter Pointer to the Adapter structure. | |
331 | * @param[in] prSwRfb Pointer to the SW_RFB_T structure. | |
332 | * | |
333 | * @return (none) | |
334 | */ | |
335 | /*----------------------------------------------------------------------------*/ | |
336 | VOID | |
337 | aaaFsmRunEventRxAuth ( | |
338 | IN P_ADAPTER_T prAdapter, | |
339 | IN P_SW_RFB_T prSwRfb | |
340 | ) | |
341 | { | |
342 | P_BSS_INFO_T prBssInfo; | |
343 | P_STA_RECORD_T prStaRec = (P_STA_RECORD_T)NULL; | |
344 | UINT_16 u2StatusCode; | |
345 | BOOLEAN fgReplyAuth = FALSE; | |
346 | ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex; | |
347 | ||
348 | ||
349 | ASSERT(prAdapter); | |
350 | ||
351 | do { | |
352 | ||
353 | ||
354 | //4 <1> Check P2P network conditions | |
355 | #if CFG_ENABLE_WIFI_DIRECT | |
356 | if(prAdapter->fgIsP2PRegistered){ | |
357 | prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); | |
358 | ||
359 | if (prBssInfo->fgIsNetActive) { | |
360 | ||
361 | //4 <1.1> Validate Auth Frame by Auth Algorithm/Transation Seq | |
362 | if (WLAN_STATUS_SUCCESS == | |
363 | authProcessRxAuth1Frame(prAdapter, | |
364 | prSwRfb, | |
365 | prBssInfo->aucBSSID, | |
366 | AUTH_ALGORITHM_NUM_OPEN_SYSTEM, | |
367 | AUTH_TRANSACTION_SEQ_1, | |
368 | &u2StatusCode)) { | |
369 | ||
370 | if (STATUS_CODE_SUCCESSFUL == u2StatusCode) { | |
371 | //4 <1.2> Validate Auth Frame for Network Specific Conditions | |
372 | fgReplyAuth = p2pFuncValidateAuth( | |
373 | prAdapter, | |
374 | prSwRfb, | |
375 | &prStaRec, | |
376 | &u2StatusCode); | |
377 | } | |
378 | else { | |
379 | fgReplyAuth = TRUE; | |
380 | } | |
381 | eNetTypeIndex = NETWORK_TYPE_P2P_INDEX; | |
382 | break; | |
383 | } | |
384 | } | |
385 | } | |
386 | #endif /* CFG_ENABLE_WIFI_DIRECT */ | |
387 | ||
388 | //4 <2> Check BOW network conditions | |
389 | #if CFG_ENABLE_BT_OVER_WIFI | |
390 | { | |
391 | prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX]); | |
392 | ||
393 | if ((prBssInfo->fgIsNetActive) && | |
394 | (OP_MODE_BOW == prBssInfo->eCurrentOPMode)) { | |
395 | ||
396 | //4 <2.1> Validate Auth Frame by Auth Algorithm/Transation Seq | |
397 | /* Check if for this BSSID */ | |
398 | if (WLAN_STATUS_SUCCESS == | |
399 | authProcessRxAuth1Frame(prAdapter, | |
400 | prSwRfb, | |
401 | prBssInfo->aucBSSID, | |
402 | AUTH_ALGORITHM_NUM_OPEN_SYSTEM, | |
403 | AUTH_TRANSACTION_SEQ_1, | |
404 | &u2StatusCode)) { | |
405 | ||
406 | if (STATUS_CODE_SUCCESSFUL == u2StatusCode) { | |
407 | ||
408 | //4 <2.2> Validate Auth Frame for Network Specific Conditions | |
409 | fgReplyAuth = bowValidateAuth(prAdapter, prSwRfb, &prStaRec, &u2StatusCode); | |
410 | ||
411 | } | |
412 | else { | |
413 | ||
414 | fgReplyAuth = TRUE; | |
415 | } | |
416 | eNetTypeIndex = NETWORK_TYPE_BOW_INDEX; | |
417 | /* TODO(Kevin): Allocate a STA_RECORD_T for new client */ | |
418 | break; | |
419 | } | |
420 | } | |
421 | } | |
422 | #endif /* CFG_ENABLE_BT_OVER_WIFI */ | |
423 | ||
424 | return; | |
425 | } while (FALSE); | |
426 | ||
427 | if(prStaRec) { | |
428 | /* update RCPI */ | |
429 | prStaRec->ucRCPI = prSwRfb->prHifRxHdr->ucRcpi; | |
430 | } | |
431 | ||
432 | //4 <3> Update STA_RECORD_T and reply Auth_2(Response to Auth_1) Frame | |
433 | if (fgReplyAuth) { | |
434 | ||
435 | if (prStaRec) { | |
436 | ||
437 | if (u2StatusCode == STATUS_CODE_SUCCESSFUL) { | |
438 | if (prStaRec->eAuthAssocState != AA_STATE_IDLE) { | |
439 | DBGLOG(AAA, WARN, ("Previous AuthAssocState (%d) != IDLE.\n", | |
440 | prStaRec->eAuthAssocState)); | |
441 | } | |
442 | ||
443 | prStaRec->eAuthAssocState = AAA_STATE_SEND_AUTH2; | |
444 | } | |
445 | else { | |
446 | prStaRec->eAuthAssocState = AA_STATE_IDLE; | |
447 | ||
448 | /* NOTE(Kevin): Change to STATE_1 */ | |
449 | cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); | |
450 | } | |
451 | ||
452 | /* Update the record join time. */ | |
453 | GET_CURRENT_SYSTIME(&prStaRec->rUpdateTime); | |
454 | ||
455 | /* Update Station Record - Status/Reason Code */ | |
456 | prStaRec->u2StatusCode = u2StatusCode; | |
457 | ||
458 | prStaRec->ucAuthAlgNum = AUTH_ALGORITHM_NUM_OPEN_SYSTEM; | |
459 | } | |
460 | else { | |
461 | /* NOTE(Kevin): We should have STA_RECORD_T if the status code was successful */ | |
462 | ASSERT(!(u2StatusCode == STATUS_CODE_SUCCESSFUL)); | |
463 | } | |
464 | ||
465 | /* NOTE: Ignore the return status for AAA */ | |
466 | //4 <4> Reply Auth | |
467 | authSendAuthFrame(prAdapter, | |
468 | prStaRec, | |
469 | eNetTypeIndex, | |
470 | prSwRfb, | |
471 | AUTH_TRANSACTION_SEQ_2, | |
472 | u2StatusCode); | |
473 | ||
474 | } | |
475 | ||
476 | return; | |
477 | } /* end of aaaFsmRunEventRxAuth() */ | |
478 | ||
479 | ||
480 | /*----------------------------------------------------------------------------*/ | |
481 | /*! | |
482 | * @brief This function will process the Rx (Re)Association Request Frame and then | |
483 | * trigger AAA FSM. | |
484 | * | |
485 | * @param[in] prAdapter Pointer to the Adapter structure. | |
486 | * @param[in] prSwRfb Pointer to the SW_RFB_T structure. | |
487 | * | |
488 | * @retval WLAN_STATUS_SUCCESS Always return success | |
489 | */ | |
490 | /*----------------------------------------------------------------------------*/ | |
491 | WLAN_STATUS | |
492 | aaaFsmRunEventRxAssoc ( | |
493 | IN P_ADAPTER_T prAdapter, | |
494 | IN P_SW_RFB_T prSwRfb | |
495 | ) | |
496 | { | |
497 | P_BSS_INFO_T prBssInfo; | |
498 | P_STA_RECORD_T prStaRec = (P_STA_RECORD_T)NULL; | |
499 | UINT_16 u2StatusCode = STATUS_CODE_RESERVED; | |
500 | BOOLEAN fgReplyAssocResp = FALSE; | |
501 | ||
502 | ||
503 | ASSERT(prAdapter); | |
504 | ||
505 | do { | |
506 | ||
507 | //4 <1> Check if we have the STA_RECORD_T for incoming Assoc Req | |
508 | prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); | |
509 | ||
510 | /* We should have the corresponding Sta Record. */ | |
511 | if ((!prStaRec) || (!prStaRec->fgIsInUse)) { | |
512 | ASSERT(0); // Only for debug phase | |
513 | break; | |
514 | } | |
515 | ||
516 | if (!IS_CLIENT_STA(prStaRec)) { | |
517 | break; | |
518 | } | |
519 | ||
520 | if (prStaRec->ucStaState == STA_STATE_3) { | |
521 | /* Do Reassocation */ | |
522 | } | |
523 | else if ((prStaRec->ucStaState == STA_STATE_2) && | |
524 | (prStaRec->eAuthAssocState == AAA_STATE_SEND_AUTH2)) { | |
525 | /* Normal case */ | |
526 | } | |
527 | else { | |
528 | DBGLOG(AAA, WARN, ("Previous AuthAssocState (%d) != SEND_AUTH2.\n", | |
529 | prStaRec->eAuthAssocState)); | |
530 | break; | |
531 | } | |
532 | ||
533 | /* update RCPI */ | |
534 | prStaRec->ucRCPI = prSwRfb->prHifRxHdr->ucRcpi; | |
535 | ||
536 | //4 <2> Check P2P network conditions | |
537 | #if CFG_ENABLE_WIFI_DIRECT | |
538 | if ((prAdapter->fgIsP2PRegistered) && (IS_STA_IN_P2P(prStaRec))) { | |
539 | ||
540 | prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); | |
541 | ||
542 | if (prBssInfo->fgIsNetActive) { | |
543 | ||
544 | //4 <2.1> Validate Assoc Req Frame and get Status Code | |
545 | /* Check if for this BSSID */ | |
546 | if (WLAN_STATUS_SUCCESS == | |
547 | assocProcessRxAssocReqFrame(prAdapter, | |
548 | prSwRfb, | |
549 | &u2StatusCode)) { | |
550 | ||
551 | if (STATUS_CODE_SUCCESSFUL == u2StatusCode) { | |
552 | //4 <2.2> Validate Assoc Req Frame for Network Specific Conditions | |
553 | fgReplyAssocResp = p2pFuncValidateAssocReq( | |
554 | prAdapter, | |
555 | prSwRfb, | |
556 | (PUINT_16)&u2StatusCode); | |
557 | } | |
558 | else { | |
559 | fgReplyAssocResp = TRUE; | |
560 | } | |
561 | ||
562 | break; | |
563 | } | |
564 | } | |
565 | } | |
566 | #endif /* CFG_ENABLE_WIFI_DIRECT */ | |
567 | ||
568 | //4 <3> Check BOW network conditions | |
569 | #if CFG_ENABLE_BT_OVER_WIFI | |
570 | if (IS_STA_IN_BOW(prStaRec)) { | |
571 | ||
572 | prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX]); | |
573 | ||
574 | if ((prBssInfo->fgIsNetActive) && | |
575 | (OP_MODE_BOW == prBssInfo->eCurrentOPMode)){ | |
576 | ||
577 | //4 <3.1> Validate Auth Frame by Auth Algorithm/Transation Seq | |
578 | /* Check if for this BSSID */ | |
579 | if (WLAN_STATUS_SUCCESS == | |
580 | assocProcessRxAssocReqFrame(prAdapter, | |
581 | prSwRfb, | |
582 | &u2StatusCode)) { | |
583 | ||
584 | if (STATUS_CODE_SUCCESSFUL == u2StatusCode) { | |
585 | ||
586 | //4 <3.2> Validate Auth Frame for Network Specific Conditions | |
587 | fgReplyAssocResp = bowValidateAssocReq(prAdapter, prSwRfb, &u2StatusCode); | |
588 | ||
589 | } | |
590 | else { | |
591 | ||
592 | fgReplyAssocResp = TRUE; | |
593 | } | |
594 | ||
595 | /* TODO(Kevin): Allocate a STA_RECORD_T for new client */ | |
596 | break; | |
597 | } | |
598 | } | |
599 | } | |
600 | #endif /* CFG_ENABLE_BT_OVER_WIFI */ | |
601 | ||
602 | return WLAN_STATUS_SUCCESS; // To release the SW_RFB_T | |
603 | } while (FALSE); | |
604 | ||
605 | ||
606 | //4 <4> Update STA_RECORD_T and reply Assoc Resp Frame | |
607 | if (fgReplyAssocResp) { | |
608 | UINT_16 u2IELength; | |
609 | PUINT_8 pucIE; | |
610 | ||
611 | if ((((P_WLAN_ASSOC_REQ_FRAME_T)(prSwRfb->pvHeader))->u2FrameCtrl & MASK_FRAME_TYPE) == | |
612 | MAC_FRAME_REASSOC_REQ) { | |
613 | ||
614 | u2IELength = prSwRfb->u2PacketLen - | |
615 | (UINT_16)OFFSET_OF(WLAN_REASSOC_REQ_FRAME_T, aucInfoElem[0]); | |
616 | ||
617 | pucIE = ((P_WLAN_REASSOC_REQ_FRAME_T)(prSwRfb->pvHeader))->aucInfoElem; | |
618 | } | |
619 | else { | |
620 | u2IELength = prSwRfb->u2PacketLen - | |
621 | (UINT_16)OFFSET_OF(WLAN_ASSOC_REQ_FRAME_T, aucInfoElem[0]); | |
622 | ||
623 | pucIE = ((P_WLAN_ASSOC_REQ_FRAME_T)(prSwRfb->pvHeader))->aucInfoElem; | |
624 | } | |
625 | ||
626 | rlmProcessAssocReq(prAdapter, prSwRfb, pucIE, u2IELength); | |
627 | ||
628 | //4 <4.1> Assign Association ID | |
629 | if (u2StatusCode == STATUS_CODE_SUCCESSFUL) { | |
630 | ||
631 | #if CFG_ENABLE_WIFI_DIRECT | |
632 | if ((prAdapter->fgIsP2PRegistered) && (IS_STA_IN_P2P(prStaRec))) { | |
633 | if (p2pRunEventAAAComplete(prAdapter, prStaRec) == WLAN_STATUS_SUCCESS) { | |
634 | prStaRec->u2AssocId = bssAssignAssocID(prStaRec); | |
635 | //prStaRec->eAuthAssocState = AA_STATE_IDLE; | |
636 | prStaRec->eAuthAssocState = AAA_STATE_SEND_ASSOC2; // NOTE(Kevin): for TX done | |
637 | ||
638 | /* NOTE(Kevin): Method A: Change to STATE_3 before handle TX Done */ | |
639 | //cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); | |
640 | } | |
641 | else { | |
642 | /* Client List FULL. */ | |
643 | u2StatusCode = STATUS_CODE_REQ_DECLINED; | |
644 | ||
645 | prStaRec->u2AssocId = 0; /* Invalid Assocation ID */ | |
646 | ||
647 | /* If (Re)association fail, the peer can try Assocation w/o Auth immediately */ | |
648 | prStaRec->eAuthAssocState = AAA_STATE_SEND_AUTH2; | |
649 | ||
650 | /* NOTE(Kevin): Better to change state here, not at TX Done */ | |
651 | cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_2); | |
652 | } | |
653 | } | |
654 | #endif | |
655 | ||
656 | #if CFG_ENABLE_BT_OVER_WIFI | |
657 | if ((IS_STA_IN_BOW(prStaRec))) { | |
658 | ||
659 | // if (bowRunEventAAAComplete(prAdapter, prStaRec) == WLAN_STATUS_SUCCESS) { | |
660 | prStaRec->u2AssocId = bssAssignAssocID(prStaRec); | |
661 | prStaRec->eAuthAssocState = AAA_STATE_SEND_ASSOC2; // NOTE(Kevin): for TX done | |
662 | ||
663 | /* NOTE(Kevin): Method A: Change to STATE_3 before handle TX Done */ | |
664 | //cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); | |
665 | } | |
666 | #if 0 | |
667 | else { | |
668 | /* Client List FULL. */ | |
669 | u2StatusCode = STATUS_CODE_REQ_DECLINED; | |
670 | ||
671 | prStaRec->u2AssocId = 0; /* Invalid Assocation ID */ | |
672 | ||
673 | /* If (Re)association fail, the peer can try Assocation w/o Auth immediately */ | |
674 | prStaRec->eAuthAssocState = AAA_STATE_SEND_AUTH2; | |
675 | ||
676 | /* NOTE(Kevin): Better to change state here, not at TX Done */ | |
677 | cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_2); | |
678 | } | |
679 | } | |
680 | #endif | |
681 | #endif | |
682 | } | |
683 | else { | |
684 | prStaRec->u2AssocId = 0; /* Invalid Assocation ID */ | |
685 | ||
686 | /* If (Re)association fail, the peer can try Assocation w/o Auth immediately */ | |
687 | prStaRec->eAuthAssocState = AAA_STATE_SEND_AUTH2; | |
688 | ||
689 | /* NOTE(Kevin): Better to change state here, not at TX Done */ | |
690 | cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_2); | |
691 | } | |
692 | ||
693 | /* Update the record join time. */ | |
694 | GET_CURRENT_SYSTIME(&prStaRec->rUpdateTime); | |
695 | ||
696 | /* Update Station Record - Status/Reason Code */ | |
697 | prStaRec->u2StatusCode = u2StatusCode; | |
698 | ||
699 | /* NOTE: Ignore the return status for AAA */ | |
700 | //4 <4.2> Reply Assoc Resp | |
701 | assocSendReAssocRespFrame(prAdapter, prStaRec); | |
702 | ||
703 | } | |
704 | ||
705 | return WLAN_STATUS_SUCCESS; | |
706 | ||
707 | } /* end of aaaFsmRunEventRxAssoc() */ | |
708 | ||
709 | ||
710 | /*----------------------------------------------------------------------------*/ | |
711 | /*! | |
712 | * @brief This function will handle TxDone(Auth2/AssocReq) Event of AAA FSM. | |
713 | * | |
714 | * @param[in] prAdapter Pointer to the Adapter structure. | |
715 | * @param[in] prMsduInfo Pointer to the MSDU_INFO_T. | |
716 | * @param[in] rTxDoneStatus Return TX status of the Auth1/Auth3/AssocReq frame. | |
717 | * | |
718 | * @retval WLAN_STATUS_SUCCESS | |
719 | */ | |
720 | /*----------------------------------------------------------------------------*/ | |
721 | WLAN_STATUS | |
722 | aaaFsmRunEventTxDone ( | |
723 | IN P_ADAPTER_T prAdapter, | |
724 | IN P_MSDU_INFO_T prMsduInfo, | |
725 | IN ENUM_TX_RESULT_CODE_T rTxDoneStatus | |
726 | ) | |
727 | { | |
728 | P_STA_RECORD_T prStaRec; | |
729 | P_BSS_INFO_T prBssInfo; | |
730 | ||
731 | ||
732 | ASSERT(prAdapter); | |
733 | ASSERT(prMsduInfo); | |
734 | ||
735 | DBGLOG(AAA, LOUD, ("EVENT-TX DONE: Current Time = %lu\n", | |
736 | (unsigned long)kalGetTimeTick())); | |
737 | ||
738 | prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); | |
739 | ||
740 | if ((!prStaRec) || (!prStaRec->fgIsInUse)) { | |
741 | return WLAN_STATUS_SUCCESS; /* For the case of replying ERROR STATUS CODE */ | |
742 | } | |
743 | ||
744 | ASSERT(prStaRec->ucNetTypeIndex < NETWORK_TYPE_INDEX_NUM); | |
745 | ||
746 | prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]); | |
747 | ||
748 | switch (prStaRec->eAuthAssocState) { | |
749 | case AAA_STATE_SEND_AUTH2: | |
750 | { | |
751 | /* Strictly check the outgoing frame is matched with current AA STATE */ | |
752 | if (authCheckTxAuthFrame(prAdapter, | |
753 | prMsduInfo, | |
754 | AUTH_TRANSACTION_SEQ_2) != WLAN_STATUS_SUCCESS) { | |
755 | break; | |
756 | } | |
757 | ||
758 | if (STATUS_CODE_SUCCESSFUL == prStaRec->u2StatusCode) { | |
759 | if (TX_RESULT_SUCCESS == rTxDoneStatus) { | |
760 | ||
761 | /* NOTE(Kevin): Change to STATE_2 at TX Done */ | |
762 | cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_2); | |
763 | } | |
764 | else { | |
765 | ||
766 | prStaRec->eAuthAssocState = AA_STATE_IDLE; | |
767 | ||
768 | /* NOTE(Kevin): Change to STATE_1 */ | |
769 | cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); | |
770 | ||
771 | #if CFG_ENABLE_WIFI_DIRECT | |
772 | if ((prAdapter->fgIsP2PRegistered) && | |
773 | (IS_STA_IN_P2P(prStaRec))) { | |
774 | p2pRunEventAAATxFail(prAdapter, prStaRec); | |
775 | } | |
776 | #endif /* CFG_ENABLE_WIFI_DIRECT */ | |
777 | ||
778 | #if CFG_ENABLE_BT_OVER_WIFI | |
779 | if (IS_STA_IN_BOW(prStaRec)) { | |
780 | bowRunEventAAATxFail(prAdapter, prStaRec); | |
781 | } | |
782 | #endif /* CFG_ENABLE_BT_OVER_WIFI */ | |
783 | } | |
784 | ||
785 | } | |
786 | /* NOTE(Kevin): Ignore the TX Done Event of Auth Frame with Error Status Code */ | |
787 | ||
788 | } | |
789 | break; | |
790 | ||
791 | case AAA_STATE_SEND_ASSOC2: | |
792 | { | |
793 | /* Strictly check the outgoing frame is matched with current SAA STATE */ | |
794 | if (assocCheckTxReAssocRespFrame(prAdapter, prMsduInfo) != WLAN_STATUS_SUCCESS) { | |
795 | break; | |
796 | } | |
797 | ||
798 | if (STATUS_CODE_SUCCESSFUL == prStaRec->u2StatusCode) { | |
799 | if (TX_RESULT_SUCCESS == rTxDoneStatus) { | |
800 | ||
801 | prStaRec->eAuthAssocState = AA_STATE_IDLE; | |
802 | ||
803 | /* NOTE(Kevin): Change to STATE_3 at TX Done */ | |
804 | #if CFG_ENABLE_WIFI_DIRECT | |
805 | if ((prAdapter->fgIsP2PRegistered) && | |
806 | (IS_STA_IN_P2P(prStaRec))) { | |
807 | p2pRunEventAAASuccess(prAdapter, prStaRec); | |
808 | } | |
809 | #endif /* CFG_ENABLE_WIFI_DIRECT */ | |
810 | ||
811 | #if CFG_ENABLE_BT_OVER_WIFI | |
812 | ||
813 | if (IS_STA_IN_BOW(prStaRec)) | |
814 | { | |
815 | bowRunEventAAAComplete(prAdapter, prStaRec); | |
816 | } | |
817 | #endif /* CFG_ENABLE_BT_OVER_WIFI */ | |
818 | ||
819 | } | |
820 | else { | |
821 | ||
822 | prStaRec->eAuthAssocState = AAA_STATE_SEND_AUTH2; | |
823 | ||
824 | /* NOTE(Kevin): Change to STATE_2 */ | |
825 | cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_2); | |
826 | ||
827 | #if CFG_ENABLE_WIFI_DIRECT | |
828 | if ((prAdapter->fgIsP2PRegistered) && | |
829 | (IS_STA_IN_P2P(prStaRec))) { | |
830 | p2pRunEventAAATxFail(prAdapter, prStaRec); | |
831 | } | |
832 | #endif /* CFG_ENABLE_WIFI_DIRECT */ | |
833 | ||
834 | #if CFG_ENABLE_BT_OVER_WIFI | |
835 | if (IS_STA_IN_BOW(prStaRec)) { | |
836 | bowRunEventAAATxFail(prAdapter, prStaRec); | |
837 | } | |
838 | #endif /* CFG_ENABLE_BT_OVER_WIFI */ | |
839 | ||
840 | } | |
841 | } | |
842 | /* NOTE(Kevin): Ignore the TX Done Event of Auth Frame with Error Status Code */ | |
843 | } | |
844 | break; | |
845 | ||
846 | default: | |
847 | break; /* Ignore other cases */ | |
848 | } | |
849 | ||
850 | ||
851 | return WLAN_STATUS_SUCCESS; | |
852 | ||
853 | } /* end of aaaFsmRunEventTxDone() */ | |
854 | #endif /* CFG_SUPPORT_AAA */ | |
855 | ||
856 | ||
857 | #if 0 /* TODO(Kevin): for abort event, just reset the STA_RECORD_T. */ | |
858 | /*----------------------------------------------------------------------------*/ | |
859 | /*! | |
860 | * \brief This function will send ABORT Event to JOIN FSM. | |
861 | * | |
862 | * \param[in] prAdapter Pointer to the Adapter structure. | |
863 | * | |
864 | * \return none | |
865 | */ | |
866 | /*----------------------------------------------------------------------------*/ | |
867 | VOID | |
868 | saaFsmRunEventAbort ( | |
869 | IN P_MSG_HDR_T prMsgHdr | |
870 | ) | |
871 | { | |
872 | P_JOIN_INFO_T prJoinInfo; | |
873 | P_STA_RECORD_T prStaRec; | |
874 | ||
875 | DEBUGFUNC("joinFsmRunEventAbort"); | |
876 | ||
877 | ||
878 | ASSERT(prAdapter); | |
879 | prJoinInfo = &prAdapter->rJoinInfo; | |
880 | ||
881 | DBGLOG(JOIN, EVENT, ("JOIN EVENT: ABORT\n")); | |
882 | ||
883 | ||
884 | /* NOTE(Kevin): when reach here, the ARB_STATE should be in ARB_STATE_JOIN. */ | |
885 | ASSERT(prJoinInfo->prBssDesc); | |
886 | ||
887 | //4 <1> Update Flags and Elements of JOIN Module. | |
888 | /* Reset Send Auth/(Re)Assoc Frame Count */ | |
889 | prJoinInfo->ucTxAuthAssocRetryCount = 0; | |
890 | ||
891 | /* Cancel all JOIN relative Timer */ | |
892 | ARB_CANCEL_TIMER(prAdapter, | |
893 | prJoinInfo->rTxRequestTimer); | |
894 | ||
895 | ARB_CANCEL_TIMER(prAdapter, | |
896 | prJoinInfo->rRxResponseTimer); | |
897 | ||
898 | ARB_CANCEL_TIMER(prAdapter, | |
899 | prJoinInfo->rJoinTimer); | |
900 | ||
901 | //4 <2> Update the associated STA_RECORD_T during JOIN. | |
902 | /* Get a Station Record if possible, TA == BSSID for AP */ | |
903 | prStaRec = staRecGetStaRecordByAddr(prAdapter, | |
904 | prJoinInfo->prBssDesc->aucBSSID); | |
905 | if (prStaRec) { | |
906 | ||
907 | /* Update Station Record - Class 1 Flag */ | |
908 | prStaRec->ucStaState = STA_STATE_1; | |
909 | } | |
910 | #if DBG | |
911 | else { | |
912 | ASSERT(0); /* Shouldn't happened, because we already add this STA_RECORD_T at JOIN_STATE_INIT */ | |
913 | } | |
914 | #endif /* DBG */ | |
915 | ||
916 | //4 <3> Pull back to IDLE. | |
917 | joinFsmSteps(prAdapter, JOIN_STATE_IDLE); | |
918 | ||
919 | //4 <4> If we are in Roaming, recover the settings of previous BSS. | |
920 | /* NOTE: JOIN FAIL - | |
921 | * Restore original setting from current BSS_INFO_T. | |
922 | */ | |
923 | if (prAdapter->eConnectionState == MEDIA_STATE_CONNECTED) { | |
924 | joinAdoptParametersFromCurrentBss(prAdapter); | |
925 | } | |
926 | ||
927 | return; | |
928 | } /* end of joinFsmRunEventAbort() */ | |
929 | #endif | |
930 | ||
931 | ||
932 | /* TODO(Kevin): following code will be modified and move to AIS FSM */ | |
933 | #if 0 | |
934 | /*----------------------------------------------------------------------------*/ | |
935 | /*! | |
936 | * \brief This function will send Join Timeout Event to JOIN FSM. | |
937 | * | |
938 | * \param[in] prAdapter Pointer to the Adapter structure. | |
939 | * | |
940 | * \retval WLAN_STATUS_FAILURE Fail because of Join Timeout | |
941 | */ | |
942 | /*----------------------------------------------------------------------------*/ | |
943 | WLAN_STATUS | |
944 | joinFsmRunEventJoinTimeOut ( | |
945 | IN P_ADAPTER_T prAdapter | |
946 | ) | |
947 | { | |
948 | P_JOIN_INFO_T prJoinInfo; | |
949 | P_STA_RECORD_T prStaRec; | |
950 | ||
951 | DEBUGFUNC("joinFsmRunEventJoinTimeOut"); | |
952 | ||
953 | ||
954 | ASSERT(prAdapter); | |
955 | prJoinInfo = &prAdapter->rJoinInfo; | |
956 | ||
957 | DBGLOG(JOIN, EVENT, ("JOIN EVENT: JOIN TIMEOUT\n")); | |
958 | ||
959 | /* Get a Station Record if possible, TA == BSSID for AP */ | |
960 | prStaRec = staRecGetStaRecordByAddr(prAdapter, | |
961 | prJoinInfo->prBssDesc->aucBSSID); | |
962 | ||
963 | /* We have renew this Sta Record when in JOIN_STATE_INIT */ | |
964 | ASSERT(prStaRec); | |
965 | ||
966 | /* Record the Status Code of Authentication Request */ | |
967 | prStaRec->u2StatusCode = STATUS_CODE_JOIN_TIMEOUT; | |
968 | ||
969 | /* Increase Failure Count */ | |
970 | prStaRec->ucJoinFailureCount++; | |
971 | ||
972 | /* Reset Send Auth/(Re)Assoc Frame Count */ | |
973 | prJoinInfo->ucTxAuthAssocRetryCount = 0; | |
974 | ||
975 | /* Cancel other JOIN relative Timer */ | |
976 | ARB_CANCEL_TIMER(prAdapter, | |
977 | prJoinInfo->rTxRequestTimer); | |
978 | ||
979 | ARB_CANCEL_TIMER(prAdapter, | |
980 | prJoinInfo->rRxResponseTimer); | |
981 | ||
982 | /* Restore original setting from current BSS_INFO_T */ | |
983 | if (prAdapter->eConnectionState == MEDIA_STATE_CONNECTED) { | |
984 | joinAdoptParametersFromCurrentBss(prAdapter); | |
985 | } | |
986 | ||
987 | /* Pull back to IDLE */ | |
988 | joinFsmSteps(prAdapter, JOIN_STATE_IDLE); | |
989 | ||
990 | return WLAN_STATUS_FAILURE; | |
991 | ||
992 | } /* end of joinFsmRunEventJoinTimeOut() */ | |
993 | ||
994 | /*----------------------------------------------------------------------------*/ | |
995 | /*! | |
996 | * \brief This function will adopt the parameters from Peer BSS. | |
997 | * | |
998 | * \param[in] prAdapter Pointer to the Adapter structure. | |
999 | * | |
1000 | * \return (none) | |
1001 | */ | |
1002 | /*----------------------------------------------------------------------------*/ | |
1003 | VOID | |
1004 | joinAdoptParametersFromPeerBss ( | |
1005 | IN P_ADAPTER_T prAdapter | |
1006 | ) | |
1007 | { | |
1008 | P_JOIN_INFO_T prJoinInfo; | |
1009 | P_BSS_DESC_T prBssDesc; | |
1010 | ||
1011 | DEBUGFUNC("joinAdoptParametersFromPeerBss"); | |
1012 | ||
1013 | ||
1014 | ASSERT(prAdapter); | |
1015 | prJoinInfo = &prAdapter->rJoinInfo; | |
1016 | prBssDesc = prJoinInfo->prBssDesc; | |
1017 | ||
1018 | //4 <1> Adopt Peer BSS' PHY TYPE | |
1019 | prAdapter->eCurrentPhyType = prBssDesc->ePhyType; | |
1020 | ||
1021 | DBGLOG(JOIN, INFO, ("Target BSS[%s]'s PhyType = %s\n", | |
1022 | prBssDesc->aucSSID, (prBssDesc->ePhyType == PHY_TYPE_ERP_INDEX) ? "ERP" : "HR_DSSS")); | |
1023 | ||
1024 | ||
1025 | //4 <2> Adopt Peer BSS' Frequency(Band/Channel) | |
1026 | DBGLOG(JOIN, INFO, ("Target BSS's Channel = %d, Band = %d\n", | |
1027 | prBssDesc->ucChannelNum, prBssDesc->eBand)); | |
1028 | ||
1029 | nicSwitchChannel(prAdapter, | |
1030 | prBssDesc->eBand, | |
1031 | prBssDesc->ucChannelNum, | |
1032 | 10); | |
1033 | ||
1034 | prJoinInfo->fgIsParameterAdopted = TRUE; | |
1035 | ||
1036 | return; | |
1037 | } /* end of joinAdoptParametersFromPeerBss() */ | |
1038 | ||
1039 | ||
1040 | /*----------------------------------------------------------------------------*/ | |
1041 | /*! | |
1042 | * \brief This function will adopt the parameters from current associated BSS. | |
1043 | * | |
1044 | * \param[in] prAdapter Pointer to the Adapter structure. | |
1045 | * | |
1046 | * \return (none) | |
1047 | */ | |
1048 | /*----------------------------------------------------------------------------*/ | |
1049 | VOID | |
1050 | joinAdoptParametersFromCurrentBss ( | |
1051 | IN P_ADAPTER_T prAdapter | |
1052 | ) | |
1053 | { | |
1054 | //P_JOIN_INFO_T prJoinInfo = &prAdapter->rJoinInfo; | |
1055 | P_BSS_INFO_T prBssInfo; | |
1056 | ||
1057 | ||
1058 | ASSERT(prAdapter); | |
1059 | prBssInfo = &prAdapter->rBssInfo; | |
1060 | ||
1061 | //4 <1> Adopt current BSS' PHY TYPE | |
1062 | prAdapter->eCurrentPhyType = prBssInfo->ePhyType; | |
1063 | ||
1064 | //4 <2> Adopt current BSS' Frequency(Band/Channel) | |
1065 | DBGLOG(JOIN, INFO, ("Current BSS's Channel = %d, Band = %d\n", | |
1066 | prBssInfo->ucChnl, prBssInfo->eBand)); | |
1067 | ||
1068 | nicSwitchChannel(prAdapter, | |
1069 | prBssInfo->eBand, | |
1070 | prBssInfo->ucChnl, | |
1071 | 10); | |
1072 | return; | |
1073 | } /* end of joinAdoptParametersFromCurrentBss() */ | |
1074 | ||
1075 | ||
1076 | /*----------------------------------------------------------------------------*/ | |
1077 | /*! | |
1078 | * \brief This function will update all the SW variables and HW MCR registers after | |
1079 | * the association with target BSS. | |
1080 | * | |
1081 | * \param[in] prAdapter Pointer to the Adapter structure. | |
1082 | * | |
1083 | * \return (none) | |
1084 | */ | |
1085 | /*----------------------------------------------------------------------------*/ | |
1086 | VOID | |
1087 | joinComplete ( | |
1088 | IN P_ADAPTER_T prAdapter | |
1089 | ) | |
1090 | { | |
1091 | P_JOIN_INFO_T prJoinInfo; | |
1092 | P_BSS_DESC_T prBssDesc; | |
1093 | P_PEER_BSS_INFO_T prPeerBssInfo; | |
1094 | P_BSS_INFO_T prBssInfo; | |
1095 | P_CONNECTION_SETTINGS_T prConnSettings; | |
1096 | P_STA_RECORD_T prStaRec; | |
1097 | P_TX_CTRL_T prTxCtrl; | |
1098 | #if CFG_SUPPORT_802_11D | |
1099 | P_IE_COUNTRY_T prIECountry; | |
1100 | #endif | |
1101 | ||
1102 | DEBUGFUNC("joinComplete"); | |
1103 | ||
1104 | ||
1105 | ASSERT(prAdapter); | |
1106 | prJoinInfo = &prAdapter->rJoinInfo; | |
1107 | prBssDesc = prJoinInfo->prBssDesc; | |
1108 | prPeerBssInfo = &prAdapter->rPeerBssInfo; | |
1109 | prBssInfo = &prAdapter->rBssInfo; | |
1110 | prConnSettings = &prAdapter->rConnSettings; | |
1111 | prTxCtrl = &prAdapter->rTxCtrl; | |
1112 | ||
1113 | //4 <1> Update Connecting & Connected Flag of BSS_DESC_T. | |
1114 | /* Remove previous AP's Connection Flags if have */ | |
1115 | scanRemoveConnectionFlagOfBssDescByBssid(prAdapter, prBssInfo->aucBSSID); | |
1116 | ||
1117 | prBssDesc->fgIsConnected = TRUE; /* Mask as Connected */ | |
1118 | ||
1119 | if (prBssDesc->fgIsHiddenSSID) { | |
1120 | /* NOTE(Kevin): This is for the case of Passive Scan and the target BSS didn't | |
1121 | * broadcast SSID on its Beacon Frame. | |
1122 | */ | |
1123 | COPY_SSID(prBssDesc->aucSSID, | |
1124 | prBssDesc->ucSSIDLen, | |
1125 | prAdapter->rConnSettings.aucSSID, | |
1126 | prAdapter->rConnSettings.ucSSIDLen); | |
1127 | ||
1128 | if (prBssDesc->ucSSIDLen) { | |
1129 | prBssDesc->fgIsHiddenSSID = FALSE; | |
1130 | } | |
1131 | #if DBG | |
1132 | else { | |
1133 | ASSERT(0); | |
1134 | } | |
1135 | #endif /* DBG */ | |
1136 | ||
1137 | DBGLOG(JOIN, INFO, ("Hidden SSID! - Update SSID : %s\n", prBssDesc->aucSSID)); | |
1138 | } | |
1139 | ||
1140 | ||
1141 | //4 <2> Update BSS_INFO_T from BSS_DESC_T | |
1142 | //4 <2.A> PHY Type | |
1143 | prBssInfo->ePhyType = prBssDesc->ePhyType; | |
1144 | ||
1145 | //4 <2.B> BSS Type | |
1146 | prBssInfo->eBSSType = BSS_TYPE_INFRASTRUCTURE; | |
1147 | ||
1148 | //4 <2.C> BSSID | |
1149 | COPY_MAC_ADDR(prBssInfo->aucBSSID, prBssDesc->aucBSSID); | |
1150 | ||
1151 | DBGLOG(JOIN, INFO, ("JOIN to BSSID: ["MACSTR"]\n", MAC2STR(prBssDesc->aucBSSID))); | |
1152 | ||
1153 | ||
1154 | //4 <2.D> SSID | |
1155 | COPY_SSID(prBssInfo->aucSSID, | |
1156 | prBssInfo->ucSSIDLen, | |
1157 | prBssDesc->aucSSID, | |
1158 | prBssDesc->ucSSIDLen); | |
1159 | ||
1160 | //4 <2.E> Channel / Band information. | |
1161 | prBssInfo->eBand = prBssDesc->eBand; | |
1162 | prBssInfo->ucChnl = prBssDesc->ucChannelNum; | |
1163 | ||
1164 | //4 <2.F> RSN/WPA information. | |
1165 | secFsmRunEventStart(prAdapter); | |
1166 | prBssInfo->u4RsnSelectedPairwiseCipher = prBssDesc->u4RsnSelectedPairwiseCipher; | |
1167 | prBssInfo->u4RsnSelectedGroupCipher = prBssDesc->u4RsnSelectedGroupCipher; | |
1168 | prBssInfo->u4RsnSelectedAKMSuite = prBssDesc->u4RsnSelectedAKMSuite; | |
1169 | ||
1170 | if (secRsnKeyHandshakeEnabled()) { | |
1171 | prBssInfo->fgIsWPAorWPA2Enabled = TRUE; | |
1172 | } | |
1173 | else { | |
1174 | prBssInfo->fgIsWPAorWPA2Enabled = FALSE; | |
1175 | } | |
1176 | ||
1177 | //4 <2.G> Beacon interval. | |
1178 | prBssInfo->u2BeaconInterval = prBssDesc->u2BeaconInterval; | |
1179 | ||
1180 | //4 <2.H> DTIM period. | |
1181 | prBssInfo->ucDtimPeriod = prBssDesc->ucDTIMPeriod; | |
1182 | ||
1183 | //4 <2.I> ERP Information | |
1184 | if ((prBssInfo->ePhyType == PHY_TYPE_ERP_INDEX) && // Our BSS's PHY_TYPE is ERP now. | |
1185 | (prBssDesc->fgIsERPPresent)) { | |
1186 | ||
1187 | prBssInfo->fgIsERPPresent = TRUE; | |
1188 | prBssInfo->ucERP = prBssDesc->ucERP; /* Save the ERP for later check */ | |
1189 | } | |
1190 | else { /* Some AP, may send ProbeResp without ERP IE. Thus prBssDesc->fgIsERPPresent is FALSE. */ | |
1191 | prBssInfo->fgIsERPPresent = FALSE; | |
1192 | prBssInfo->ucERP = 0; | |
1193 | } | |
1194 | ||
1195 | #if CFG_SUPPORT_802_11D | |
1196 | //4 <2.J> Country inforamtion of the associated AP | |
1197 | if (prConnSettings->fgMultiDomainCapabilityEnabled) { | |
1198 | DOMAIN_INFO_ENTRY rDomainInfo; | |
1199 | if (domainGetDomainInfoByScanResult(prAdapter, &rDomainInfo)) { | |
1200 | if (prBssDesc->prIECountry) { | |
1201 | prIECountry = prBssDesc->prIECountry; | |
1202 | ||
1203 | domainParseCountryInfoElem(prIECountry, &prBssInfo->rDomainInfo); | |
1204 | ||
1205 | /* use the domain get from the BSS info */ | |
1206 | prBssInfo->fgIsCountryInfoPresent = TRUE; | |
1207 | nicSetupOpChnlList(prAdapter, prBssInfo->rDomainInfo.u2CountryCode, FALSE); | |
1208 | } else { | |
1209 | /* use the domain get from the scan result */ | |
1210 | prBssInfo->fgIsCountryInfoPresent = TRUE; | |
1211 | nicSetupOpChnlList(prAdapter, rDomainInfo.u2CountryCode, FALSE); | |
1212 | } | |
1213 | } | |
1214 | } | |
1215 | #endif | |
1216 | ||
1217 | //4 <2.K> Signal Power of the associated AP | |
1218 | prBssInfo->rRcpi = prBssDesc->rRcpi; | |
1219 | prBssInfo->rRssi = RCPI_TO_dBm(prBssInfo->rRcpi); | |
1220 | GET_CURRENT_SYSTIME(&prBssInfo->rRssiLastUpdateTime); | |
1221 | ||
1222 | //4 <2.L> Capability Field of the associated AP | |
1223 | prBssInfo->u2CapInfo = prBssDesc->u2CapInfo; | |
1224 | ||
1225 | DBGLOG(JOIN, INFO, ("prBssInfo-> fgIsERPPresent = %d, ucERP = %02x, rRcpi = %d, rRssi = %ld\n", | |
1226 | prBssInfo->fgIsERPPresent, prBssInfo->ucERP, prBssInfo->rRcpi, prBssInfo->rRssi)); | |
1227 | ||
1228 | ||
1229 | //4 <3> Update BSS_INFO_T from PEER_BSS_INFO_T & NIC RATE FUNC | |
1230 | //4 <3.A> Association ID | |
1231 | prBssInfo->u2AssocId = prPeerBssInfo->u2AssocId; | |
1232 | ||
1233 | //4 <3.B> WMM Infomation | |
1234 | if (prAdapter->fgIsEnableWMM && | |
1235 | (prPeerBssInfo->rWmmInfo.ucWmmFlag & WMM_FLAG_SUPPORT_WMM)) { | |
1236 | ||
1237 | prBssInfo->fgIsWmmAssoc = TRUE; | |
1238 | prTxCtrl->rTxQForVoipAccess = TXQ_AC3; | |
1239 | ||
1240 | qosWmmInfoInit(&prBssInfo->rWmmInfo, (prBssInfo->ePhyType == PHY_TYPE_HR_DSSS_INDEX) ? TRUE : FALSE); | |
1241 | ||
1242 | if (prPeerBssInfo->rWmmInfo.ucWmmFlag & WMM_FLAG_AC_PARAM_PRESENT) { | |
1243 | kalMemCopy(&prBssInfo->rWmmInfo, | |
1244 | &prPeerBssInfo->rWmmInfo, | |
1245 | sizeof(WMM_INFO_T)); | |
1246 | } | |
1247 | else { | |
1248 | kalMemCopy(&prBssInfo->rWmmInfo, | |
1249 | &prPeerBssInfo->rWmmInfo, | |
1250 | sizeof(WMM_INFO_T) - sizeof(prPeerBssInfo->rWmmInfo.arWmmAcParams)); | |
1251 | } | |
1252 | } | |
1253 | else { | |
1254 | prBssInfo->fgIsWmmAssoc = FALSE; | |
1255 | prTxCtrl->rTxQForVoipAccess = TXQ_AC1; | |
1256 | ||
1257 | kalMemZero(&prBssInfo->rWmmInfo, sizeof(WMM_INFO_T)); | |
1258 | } | |
1259 | ||
1260 | ||
1261 | //4 <3.C> Operational Rate Set & BSS Basic Rate Set | |
1262 | prBssInfo->u2OperationalRateSet = prPeerBssInfo->u2OperationalRateSet; | |
1263 | prBssInfo->u2BSSBasicRateSet = prPeerBssInfo->u2BSSBasicRateSet; | |
1264 | ||
1265 | ||
1266 | //4 <3.D> Short Preamble | |
1267 | if (prBssInfo->fgIsERPPresent) { | |
1268 | ||
1269 | /* NOTE(Kevin 2007/12/24): Truth Table. | |
1270 | * Short Preamble Bit in | |
1271 | * <AssocReq> <AssocResp w/i ERP> <BARKER(Long)> Final Driver Setting(Short) | |
1272 | * TRUE FALSE FALSE FALSE(shouldn't have such case, use the AssocResp) | |
1273 | * TRUE FALSE TRUE FALSE | |
1274 | * FALSE FALSE FALSE FALSE(shouldn't have such case, use the AssocResp) | |
1275 | * FALSE FALSE TRUE FALSE | |
1276 | * TRUE TRUE FALSE TRUE(follow ERP) | |
1277 | * TRUE TRUE TRUE FALSE(follow ERP) | |
1278 | * FALSE TRUE FALSE FALSE(shouldn't have such case, and we should set to FALSE) | |
1279 | * FALSE TRUE TRUE FALSE(we should set to FALSE) | |
1280 | */ | |
1281 | if ((prPeerBssInfo->fgIsShortPreambleAllowed) && | |
1282 | ((prConnSettings->ePreambleType == PREAMBLE_TYPE_SHORT) || /* Short Preamble Option Enable is TRUE */ | |
1283 | ((prConnSettings->ePreambleType == PREAMBLE_TYPE_AUTO) && | |
1284 | (prBssDesc->u2CapInfo & CAP_INFO_SHORT_PREAMBLE)))) { | |
1285 | ||
1286 | prBssInfo->fgIsShortPreambleAllowed = TRUE; | |
1287 | ||
1288 | if (prBssInfo->ucERP & ERP_INFO_BARKER_PREAMBLE_MODE) { | |
1289 | prBssInfo->fgUseShortPreamble = FALSE; | |
1290 | } | |
1291 | else { | |
1292 | prBssInfo->fgUseShortPreamble = TRUE; | |
1293 | } | |
1294 | } | |
1295 | else { | |
1296 | prBssInfo->fgIsShortPreambleAllowed = FALSE; | |
1297 | prBssInfo->fgUseShortPreamble = FALSE; | |
1298 | } | |
1299 | } | |
1300 | else { | |
1301 | /* NOTE(Kevin 2007/12/24): Truth Table. | |
1302 | * Short Preamble Bit in | |
1303 | * <AssocReq> <AssocResp w/o ERP> Final Driver Setting(Short) | |
1304 | * TRUE FALSE FALSE | |
1305 | * FALSE FALSE FALSE | |
1306 | * TRUE TRUE TRUE | |
1307 | * FALSE TRUE(status success) TRUE | |
1308 | * --> Honor the result of prPeerBssInfo. | |
1309 | */ | |
1310 | ||
1311 | prBssInfo->fgIsShortPreambleAllowed = prBssInfo->fgUseShortPreamble = | |
1312 | prPeerBssInfo->fgIsShortPreambleAllowed; | |
1313 | } | |
1314 | ||
1315 | DBGLOG(JOIN, INFO, ("prBssInfo->fgIsShortPreambleAllowed = %d, prBssInfo->fgUseShortPreamble = %d\n", | |
1316 | prBssInfo->fgIsShortPreambleAllowed, prBssInfo->fgUseShortPreamble)); | |
1317 | ||
1318 | ||
1319 | //4 <3.E> Short Slot Time | |
1320 | prBssInfo->fgUseShortSlotTime = | |
1321 | prPeerBssInfo->fgUseShortSlotTime; /* AP support Short Slot Time */ | |
1322 | ||
1323 | DBGLOG(JOIN, INFO, ("prBssInfo->fgUseShortSlotTime = %d\n", | |
1324 | prBssInfo->fgUseShortSlotTime)); | |
1325 | ||
1326 | nicSetSlotTime(prAdapter, | |
1327 | prBssInfo->ePhyType, | |
1328 | ((prConnSettings->fgIsShortSlotTimeOptionEnable && | |
1329 | prBssInfo->fgUseShortSlotTime) ? TRUE : FALSE)); | |
1330 | ||
1331 | ||
1332 | //4 <3.F> Update Tx Rate for Control Frame | |
1333 | bssUpdateTxRateForControlFrame(prAdapter); | |
1334 | ||
1335 | ||
1336 | //4 <3.G> Save the available Auth Types during Roaming (Design for Fast BSS Transition). | |
1337 | //if (prAdapter->fgIsEnableRoaming) /* NOTE(Kevin): Always prepare info for roaming */ | |
1338 | { | |
1339 | ||
1340 | if (prJoinInfo->ucCurrAuthAlgNum == AUTH_ALGORITHM_NUM_OPEN_SYSTEM) { | |
1341 | prJoinInfo->ucRoamingAuthTypes |= AUTH_TYPE_OPEN_SYSTEM; | |
1342 | } | |
1343 | else if (prJoinInfo->ucCurrAuthAlgNum == AUTH_ALGORITHM_NUM_SHARED_KEY) { | |
1344 | prJoinInfo->ucRoamingAuthTypes |= AUTH_TYPE_SHARED_KEY; | |
1345 | } | |
1346 | ||
1347 | prBssInfo->ucRoamingAuthTypes = prJoinInfo->ucRoamingAuthTypes; | |
1348 | ||
1349 | ||
1350 | /* Set the stable time of the associated BSS. We won't do roaming decision | |
1351 | * during the stable time. | |
1352 | */ | |
1353 | SET_EXPIRATION_TIME(prBssInfo->rRoamingStableExpirationTime, | |
1354 | SEC_TO_SYSTIME(ROAMING_STABLE_TIMEOUT_SEC)); | |
1355 | } | |
1356 | ||
1357 | ||
1358 | //4 <3.H> Update Parameter for TX Fragmentation Threshold | |
1359 | #if CFG_TX_FRAGMENT | |
1360 | txFragInfoUpdate(prAdapter); | |
1361 | #endif /* CFG_TX_FRAGMENT */ | |
1362 | ||
1363 | ||
1364 | //4 <4> Update STA_RECORD_T | |
1365 | /* Get a Station Record if possible */ | |
1366 | prStaRec = staRecGetStaRecordByAddr(prAdapter, | |
1367 | prBssDesc->aucBSSID); | |
1368 | ||
1369 | if (prStaRec) { | |
1370 | UINT_16 u2OperationalRateSet, u2DesiredRateSet; | |
1371 | ||
1372 | //4 <4.A> Desired Rate Set | |
1373 | u2OperationalRateSet = (rPhyAttributes[prBssInfo->ePhyType].u2SupportedRateSet & | |
1374 | prBssInfo->u2OperationalRateSet); | |
1375 | ||
1376 | u2DesiredRateSet = (u2OperationalRateSet & prConnSettings->u2DesiredRateSet); | |
1377 | if (u2DesiredRateSet) { | |
1378 | prStaRec->u2DesiredRateSet = u2DesiredRateSet; | |
1379 | } | |
1380 | else { | |
1381 | /* For Error Handling - The Desired Rate Set is not covered in Operational Rate Set. */ | |
1382 | prStaRec->u2DesiredRateSet = u2OperationalRateSet; | |
1383 | } | |
1384 | ||
1385 | /* Try to set the best initial rate for this entry */ | |
1386 | if (!rateGetBestInitialRateIndex(prStaRec->u2DesiredRateSet, | |
1387 | prStaRec->rRcpi, | |
1388 | &prStaRec->ucCurrRate1Index)) { | |
1389 | ||
1390 | if (!rateGetLowestRateIndexFromRateSet(prStaRec->u2DesiredRateSet, | |
1391 | &prStaRec->ucCurrRate1Index)) { | |
1392 | ASSERT(0); | |
1393 | } | |
1394 | } | |
1395 | ||
1396 | DBGLOG(JOIN, INFO, ("prStaRec->ucCurrRate1Index = %d\n", | |
1397 | prStaRec->ucCurrRate1Index)); | |
1398 | ||
1399 | //4 <4.B> Preamble Mode | |
1400 | prStaRec->fgIsShortPreambleOptionEnable = | |
1401 | prBssInfo->fgUseShortPreamble; | |
1402 | ||
1403 | //4 <4.C> QoS Flag | |
1404 | prStaRec->fgIsQoS = prBssInfo->fgIsWmmAssoc; | |
1405 | } | |
1406 | #if DBG | |
1407 | else { | |
1408 | ASSERT(0); | |
1409 | } | |
1410 | #endif /* DBG */ | |
1411 | ||
1412 | ||
1413 | //4 <5> Update NIC | |
1414 | //4 <5.A> Update BSSID & Operation Mode | |
1415 | nicSetupBSS(prAdapter, prBssInfo); | |
1416 | ||
1417 | //4 <5.B> Update WLAN Table. | |
1418 | if (nicSetHwBySta(prAdapter, prStaRec) == FALSE) { | |
1419 | ASSERT(FALSE); | |
1420 | } | |
1421 | ||
1422 | //4 <5.C> Update Desired Rate Set for BT. | |
1423 | #if CFG_TX_FRAGMENT | |
1424 | if (prConnSettings->fgIsEnableTxAutoFragmentForBT) { | |
1425 | txRateSetInitForBT(prAdapter, prStaRec); | |
1426 | } | |
1427 | #endif /* CFG_TX_FRAGMENT */ | |
1428 | ||
1429 | //4 <5.D> TX AC Parameter and TX/RX Queue Control | |
1430 | if (prBssInfo->fgIsWmmAssoc) { | |
1431 | ||
1432 | #if CFG_TX_AGGREGATE_HW_FIFO | |
1433 | nicTxAggregateTXQ(prAdapter, FALSE); | |
1434 | #endif /* CFG_TX_AGGREGATE_HW_FIFO */ | |
1435 | ||
1436 | qosUpdateWMMParametersAndAssignAllowedACI(prAdapter, &prBssInfo->rWmmInfo); | |
1437 | } | |
1438 | else { | |
1439 | ||
1440 | #if CFG_TX_AGGREGATE_HW_FIFO | |
1441 | nicTxAggregateTXQ(prAdapter, TRUE); | |
1442 | #endif /* CFG_TX_AGGREGATE_HW_FIFO */ | |
1443 | ||
1444 | nicTxNonQoSAssignDefaultAdmittedTXQ(prAdapter); | |
1445 | ||
1446 | nicTxNonQoSUpdateTXQParameters(prAdapter, | |
1447 | prBssInfo->ePhyType); | |
1448 | } | |
1449 | ||
1450 | #if CFG_TX_STOP_WRITE_TX_FIFO_UNTIL_JOIN | |
1451 | { | |
1452 | prTxCtrl->fgBlockTxDuringJoin = FALSE; | |
1453 | ||
1454 | #if !CFG_TX_AGGREGATE_HW_FIFO /* TX FIFO AGGREGATE already do flush once */ | |
1455 | nicTxFlushStopQueues(prAdapter, (UINT_8)TXQ_DATA_MASK, (UINT_8)NULL); | |
1456 | #endif /* CFG_TX_AGGREGATE_HW_FIFO */ | |
1457 | ||
1458 | nicTxRetransmitOfSendWaitQue(prAdapter); | |
1459 | ||
1460 | if (prTxCtrl->fgIsPacketInOsSendQueue) { | |
1461 | nicTxRetransmitOfOsSendQue(prAdapter); | |
1462 | } | |
1463 | ||
1464 | #if CFG_SDIO_TX_ENHANCE | |
1465 | halTxLeftClusteredMpdu(prAdapter); | |
1466 | #endif /* CFG_SDIO_TX_ENHANCE */ | |
1467 | ||
1468 | } | |
1469 | #endif /* CFG_TX_STOP_WRITE_TX_FIFO_UNTIL_JOIN */ | |
1470 | ||
1471 | ||
1472 | //4 <6> Setup CONNECTION flag. | |
1473 | prAdapter->eConnectionState = MEDIA_STATE_CONNECTED; | |
1474 | prAdapter->eConnectionStateIndicated = MEDIA_STATE_CONNECTED; | |
1475 | ||
1476 | if (prJoinInfo->fgIsReAssoc) { | |
1477 | prAdapter->fgBypassPortCtrlForRoaming = TRUE; | |
1478 | } | |
1479 | else { | |
1480 | prAdapter->fgBypassPortCtrlForRoaming = FALSE; | |
1481 | } | |
1482 | ||
1483 | kalIndicateStatusAndComplete(prAdapter->prGlueInfo, | |
1484 | WLAN_STATUS_MEDIA_CONNECT, | |
1485 | (PVOID)NULL, | |
1486 | 0); | |
1487 | ||
1488 | return; | |
1489 | } /* end of joinComplete() */ | |
1490 | #endif | |
1491 |