|
1 /* |
|
2 * Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of the License "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: Statemachine for establishing an adhoc network |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 #include "core_sub_operation_adhoc.h" |
|
20 #include "core_tx_rate_policies.h" |
|
21 #include "core_frame_dot11.h" |
|
22 #include "core_server.h" |
|
23 #include "core_tools.h" |
|
24 #include "am_debug.h" |
|
25 |
|
26 /** The channel definition for automatic channel selection. */ |
|
27 const u32_t AUTOMATIC_CHANNEL = 0; |
|
28 |
|
29 const u32_t CH_WEIGHT_1 = 4; |
|
30 const u32_t CH_WEIGHT_2 = 2; |
|
31 const u32_t CH_WEIGHT_3 = 1; |
|
32 |
|
33 // ======== MEMBER FUNCTIONS ======== |
|
34 |
|
35 // --------------------------------------------------------------------------- |
|
36 // --------------------------------------------------------------------------- |
|
37 // |
|
38 core_sub_operation_adhoc_c::core_sub_operation_adhoc_c( |
|
39 u32_t request_id, |
|
40 core_server_c* server, |
|
41 abs_core_driverif_c* drivers, |
|
42 abs_core_server_callback_c* adaptation, |
|
43 core_ap_data_c** ap_data ) : |
|
44 core_operation_base_c( core_operation_unspecified, request_id, server, drivers, adaptation, |
|
45 core_base_flag_drivers_needed ), |
|
46 ptr_ap_data_m( ap_data ), |
|
47 channel_m( 0 ) |
|
48 { |
|
49 DEBUG( "core_sub_operation_adhoc_c::core_sub_operation_adhoc_c()" ); |
|
50 } |
|
51 |
|
52 // --------------------------------------------------------------------------- |
|
53 // --------------------------------------------------------------------------- |
|
54 // |
|
55 core_sub_operation_adhoc_c::~core_sub_operation_adhoc_c() |
|
56 { |
|
57 DEBUG( "core_sub_operation_adhoc_c::~core_sub_operation_adhoc_c()" ); |
|
58 |
|
59 server_m->unregister_event_handler( this ); |
|
60 server_m->unregister_frame_handler( this ); |
|
61 ptr_ap_data_m = NULL; |
|
62 } |
|
63 |
|
64 // --------------------------------------------------------------------------- |
|
65 // --------------------------------------------------------------------------- |
|
66 // |
|
67 core_error_e core_sub_operation_adhoc_c::next_state() |
|
68 { |
|
69 DEBUG( "core_sub_operation_adhoc_c::next_state()" ); |
|
70 |
|
71 switch ( operation_state_m ) |
|
72 { |
|
73 case core_state_init: |
|
74 { |
|
75 core_tools_c::fillz( |
|
76 &noise_per_channel_m[0], |
|
77 SCAN_BAND_2DOT4GHZ_MAX_CHANNEL_EURO * sizeof( u32_t ) ); |
|
78 |
|
79 core_iap_data_c* iap = &(server_m->get_connection_data()->iap_data()); |
|
80 ASSERT( iap->adhoc_channel() <= SCAN_BAND_2DOT4GHZ_MAX_CHANNEL_FCC ); // FCC limitations: no ch 12 or 13 |
|
81 ASSERT( iap->ssid().length ); |
|
82 ASSERT( iap->ssid().length <= MAX_SSID_LEN ); |
|
83 ASSERT( iap->security_mode() == core_security_mode_allow_unsecure || |
|
84 iap->security_mode() == core_security_mode_wep ); |
|
85 |
|
86 channel_m = iap->adhoc_channel(); |
|
87 if ( channel_m != AUTOMATIC_CHANNEL ) |
|
88 { |
|
89 return goto_state( core_state_req_set_tx_rate_policies ); |
|
90 } |
|
91 |
|
92 /** |
|
93 * Do a broadcast scan to detect the channel with least traffic. |
|
94 */ |
|
95 operation_state_m = core_state_scan_start; |
|
96 |
|
97 server_m->get_scan_list().remove_entries_by_age( |
|
98 server_m->get_device_settings().scan_list_expiration_time ); |
|
99 |
|
100 server_m->register_event_handler( this ); |
|
101 server_m->register_frame_handler( this ); |
|
102 |
|
103 drivers_m->scan( |
|
104 request_id_m, |
|
105 core_scan_mode_passive, |
|
106 BROADCAST_SSID, |
|
107 server_m->get_device_settings().scan_rate, |
|
108 server_m->get_core_settings().all_valid_scan_channels(), |
|
109 server_m->get_device_settings().passive_scan_min_ch_time, |
|
110 server_m->get_device_settings().passive_scan_max_ch_time, |
|
111 false_t ); |
|
112 |
|
113 break; |
|
114 } |
|
115 case core_state_scan_start: |
|
116 { |
|
117 DEBUG( "core_sub_operation_adhoc_c::next_state() - scan request completed, waiting for scan completion" ); |
|
118 |
|
119 break; |
|
120 } |
|
121 case core_state_scan_complete: |
|
122 { |
|
123 server_m->unregister_frame_handler( this ); |
|
124 |
|
125 DEBUG( "core_sub_operation_adhoc_c::next_state() - selecting channel with least noise" ); |
|
126 |
|
127 /** |
|
128 * All channels are now checked and the noise marked. |
|
129 * Now, we have to found the smallest noise. |
|
130 */ |
|
131 u32_t tmp_best_noise( 0xFFFFFFFF ); |
|
132 u8_t tmp_best_channel( 0 ); |
|
133 for ( u8_t idx = 0; idx < SCAN_BAND_2DOT4GHZ_MAX_CHANNEL_FCC; ++idx ) // Only ch 1 - 11 |
|
134 { |
|
135 DEBUG2( "core_sub_operation_adhoc_c::next_state() - NoiseTable[%u] = %u", |
|
136 idx, noise_per_channel_m[idx] ); |
|
137 if ( noise_per_channel_m[idx] < tmp_best_noise ) |
|
138 { |
|
139 tmp_best_noise = noise_per_channel_m[idx]; |
|
140 tmp_best_channel = idx; |
|
141 } |
|
142 } |
|
143 channel_m = tmp_best_channel + 1; |
|
144 DEBUG1( "core_sub_operation_adhoc_c::next_state() - channel %u selected", |
|
145 channel_m ); |
|
146 |
|
147 return goto_state( core_state_req_set_tx_rate_policies ); |
|
148 } |
|
149 case core_state_req_set_tx_rate_policies: |
|
150 { |
|
151 operation_state_m = core_state_req_start_adhoc; |
|
152 |
|
153 core_tx_rate_policies_s policies; |
|
154 core_tx_rate_policy_mappings_s mappings; |
|
155 |
|
156 if ( server_m->get_core_settings().is_bt_connection_established() ) |
|
157 { |
|
158 DEBUG( "core_sub_operation_adhoc_c::next_state() - using 802.11bg BT TX rate policy" ); |
|
159 |
|
160 policies.policy_count = 1; |
|
161 policies.policy[0] = TX_RATE_POLICY_BLUETOOTH_BG; |
|
162 mappings.policy_for_best_effort = 0; |
|
163 mappings.policy_for_background = 0; |
|
164 mappings.policy_for_video = 0; |
|
165 mappings.policy_for_voice = 0; |
|
166 } |
|
167 else |
|
168 { |
|
169 DEBUG( "core_sub_operation_adhoc_c::next_state() - using 802.11bg default and voice TX rate policy" ); |
|
170 |
|
171 policies.policy_count = 2; |
|
172 policies.policy[0] = TX_RATE_POLICY_BG; |
|
173 policies.policy[1] = TX_RATE_POLICY_VOICE_BG; |
|
174 mappings.policy_for_best_effort = 0; |
|
175 mappings.policy_for_background = 0; |
|
176 mappings.policy_for_video = 0; |
|
177 mappings.policy_for_voice = 1; |
|
178 } |
|
179 |
|
180 /** |
|
181 * Fill in the default retry limits if not overridden by the policy. |
|
182 */ |
|
183 for ( u8_t idx( 0 ); idx < policies.policy_count; ++idx ) |
|
184 { |
|
185 if ( !policies.policy[idx].short_retry_limit ) |
|
186 { |
|
187 policies.policy[idx].short_retry_limit = |
|
188 server_m->get_device_settings().short_retry; |
|
189 } |
|
190 if ( ! policies.policy[idx].long_retry_limit ) |
|
191 { |
|
192 policies.policy[idx].long_retry_limit = |
|
193 server_m->get_device_settings().long_retry; |
|
194 } |
|
195 } |
|
196 |
|
197 DEBUG( "core_sub_operation_adhoc_c::next_state() - setting TX rate policies" ); |
|
198 |
|
199 drivers_m->set_tx_rate_policies( |
|
200 request_id_m, |
|
201 policies, |
|
202 mappings ); |
|
203 |
|
204 break; |
|
205 } |
|
206 case core_state_req_start_adhoc: |
|
207 { |
|
208 DEBUG( "core_sub_operation_adhoc_c::next_state() - TX rate policies set" ); |
|
209 |
|
210 operation_state_m = core_state_adhoc_started; |
|
211 |
|
212 core_encryption_mode_e encryption_mode = core_encryption_mode_disabled; |
|
213 if( server_m->get_connection_data()->iap_data().security_mode() == |
|
214 core_security_mode_wep ) |
|
215 { |
|
216 encryption_mode = core_encryption_mode_wep; |
|
217 } |
|
218 |
|
219 DEBUG1( "core_sub_operation_adhoc_c::next_state() - starting the adhoc on channel %u", |
|
220 channel_m ); |
|
221 |
|
222 server_m->register_frame_handler( this ); |
|
223 |
|
224 drivers_m->start_ibss( |
|
225 request_id_m, |
|
226 server_m->get_connection_data()->iap_data().ssid(), |
|
227 server_m->get_device_settings().beacon, |
|
228 channel_m, |
|
229 encryption_mode ); |
|
230 |
|
231 break; |
|
232 } |
|
233 case core_state_adhoc_started: |
|
234 { |
|
235 /** |
|
236 * If our own beacon has already been received, proceed to the |
|
237 * next state. |
|
238 */ |
|
239 if( *ptr_ap_data_m ) |
|
240 { |
|
241 return goto_state( core_state_adhoc_complete ); |
|
242 } |
|
243 |
|
244 return goto_state( core_state_adhoc_frame ); |
|
245 } |
|
246 case core_state_adhoc_frame: |
|
247 { |
|
248 DEBUG( "core_sub_operation_adhoc_c::next_state() - waiting for beacon frame" ); |
|
249 |
|
250 break; |
|
251 } |
|
252 case core_state_adhoc_complete: |
|
253 { |
|
254 server_m->unregister_frame_handler( this ); |
|
255 |
|
256 DEBUG( "core_sub_operation_adhoc_c::next_state() - all done" ); |
|
257 |
|
258 return core_error_ok; |
|
259 } |
|
260 default: |
|
261 { |
|
262 ASSERT( false_t ); |
|
263 } |
|
264 } |
|
265 |
|
266 return core_error_request_pending; |
|
267 } |
|
268 |
|
269 // --------------------------------------------------------------------------- |
|
270 // --------------------------------------------------------------------------- |
|
271 // |
|
272 core_error_e core_sub_operation_adhoc_c::cancel() |
|
273 { |
|
274 DEBUG( "core_sub_operation_adhoc_c::cancel() " ); |
|
275 |
|
276 switch ( operation_state_m ) |
|
277 { |
|
278 case core_state_adhoc_started: |
|
279 { |
|
280 /** The connection attempt failed, we are no longer connected. */ |
|
281 return next_state(); |
|
282 } |
|
283 default: |
|
284 { |
|
285 return failure_reason_m; |
|
286 } |
|
287 } |
|
288 } |
|
289 |
|
290 // --------------------------------------------------------------------------- |
|
291 // --------------------------------------------------------------------------- |
|
292 // |
|
293 void core_sub_operation_adhoc_c::user_cancel( |
|
294 bool_t do_graceful_cancel ) |
|
295 { |
|
296 DEBUG( "core_sub_operation_adhoc_c::user_cancel()" ); |
|
297 |
|
298 if ( !do_graceful_cancel ) |
|
299 { |
|
300 /** |
|
301 * If we are in a middle of a scan, we have to schedule our own |
|
302 * event. |
|
303 */ |
|
304 if ( operation_state_m == core_state_scan_start && |
|
305 server_m->event_handler() == this && |
|
306 server_m->frame_handler() == this ) |
|
307 { |
|
308 asynch_default_user_cancel(); |
|
309 |
|
310 return; |
|
311 } |
|
312 |
|
313 /** |
|
314 * If we are waiting for a beacon, we have to schedule our own |
|
315 * event. |
|
316 */ |
|
317 if ( operation_state_m == core_state_adhoc_frame ) |
|
318 { |
|
319 asynch_default_user_cancel(); |
|
320 |
|
321 return; |
|
322 } |
|
323 |
|
324 /** |
|
325 * Everything else is handled by the default implementation. |
|
326 */ |
|
327 core_operation_base_c::user_cancel( do_graceful_cancel ); |
|
328 } |
|
329 } |
|
330 |
|
331 // --------------------------------------------------------------------------- |
|
332 // --------------------------------------------------------------------------- |
|
333 // |
|
334 bool_t core_sub_operation_adhoc_c::receive_frame( |
|
335 const core_frame_dot11_c* frame, |
|
336 u8_t rcpi ) |
|
337 { |
|
338 DEBUG( "core_sub_operation_adhoc_c::receive_frame()" ); |
|
339 |
|
340 if ( frame->type() != core_frame_dot11_c::core_dot11_type_beacon && |
|
341 frame->type() != core_frame_dot11_c::core_dot11_type_probe_resp ) |
|
342 { |
|
343 DEBUG( "core_sub_operation_adhoc_c::receive_frame() - not a beacon or a probe" ); |
|
344 return false_t; |
|
345 } |
|
346 |
|
347 core_ap_data_c* ap_data = core_ap_data_c::instance( |
|
348 server_m->get_wpx_adaptation_instance(), |
|
349 frame, |
|
350 rcpi, |
|
351 true_t ); |
|
352 if ( ap_data ) |
|
353 { |
|
354 server_m->get_scan_list().update_entry( *ap_data ); |
|
355 |
|
356 if ( operation_state_m == core_state_scan_start ) |
|
357 { |
|
358 u8_t channel = ap_data->channel(); |
|
359 DEBUG1( "core_sub_operation_adhoc_c::next_state() - AP in channel %u", |
|
360 channel ); |
|
361 |
|
362 if ( channel && channel <= SCAN_BAND_2DOT4GHZ_MAX_CHANNEL_EURO ) |
|
363 { |
|
364 /** |
|
365 * Add the ch table as follows: |
|
366 * channel of the AP ==> increase by CH_WEIGHT_1 |
|
367 * channels +-1 ==> increase by CH_WEIGHT_2 |
|
368 * channels +-2 ==> increase by CH_WEIGHT_3 |
|
369 * |
|
370 * Note that the legal channels are 1 - 13 BUT the |
|
371 * array is 0 - 12! Beware edges! |
|
372 */ |
|
373 noise_per_channel_m[channel - 1] += CH_WEIGHT_1; |
|
374 if ( channel > 1 ) |
|
375 { |
|
376 noise_per_channel_m[channel - 2] += CH_WEIGHT_2; |
|
377 } |
|
378 if ( channel > 2) |
|
379 { |
|
380 noise_per_channel_m[channel - 3] += CH_WEIGHT_3; |
|
381 } |
|
382 if ( channel < SCAN_BAND_2DOT4GHZ_MAX_CHANNEL_EURO -2 ) |
|
383 { |
|
384 noise_per_channel_m[channel] += CH_WEIGHT_2; |
|
385 } |
|
386 if ( channel < SCAN_BAND_2DOT4GHZ_MAX_CHANNEL_EURO -3 ) |
|
387 { |
|
388 noise_per_channel_m[channel + 1] += CH_WEIGHT_3; |
|
389 } |
|
390 } |
|
391 } |
|
392 else if ( operation_state_m == core_state_adhoc_started || |
|
393 operation_state_m == core_state_adhoc_frame ) |
|
394 { |
|
395 if ( frame->type() == core_frame_dot11_c::core_dot11_type_beacon ) |
|
396 { |
|
397 DEBUG( "core_sub_operation_adhoc_c::next_state() - beacon received" ); |
|
398 |
|
399 ASSERT( !ap_data->is_infra() ); |
|
400 ASSERT( !*ptr_ap_data_m ); |
|
401 |
|
402 *ptr_ap_data_m = ap_data; |
|
403 |
|
404 /** |
|
405 * If we are just waiting for the beacon frame, we have to schedule |
|
406 * our own timer to proceed. |
|
407 */ |
|
408 if( operation_state_m == core_state_adhoc_frame ) |
|
409 { |
|
410 asynch_goto( core_state_adhoc_complete, CORE_TIMER_IMMEDIATELY ); |
|
411 } |
|
412 |
|
413 return true_t; |
|
414 } |
|
415 } |
|
416 |
|
417 delete ap_data; |
|
418 ap_data = NULL; |
|
419 } |
|
420 |
|
421 return true_t; |
|
422 } |
|
423 |
|
424 |
|
425 // --------------------------------------------------------------------------- |
|
426 // --------------------------------------------------------------------------- |
|
427 // |
|
428 bool_t core_sub_operation_adhoc_c::notify( |
|
429 core_am_indication_e indication ) |
|
430 { |
|
431 if ( operation_state_m == core_state_scan_start && |
|
432 indication == core_am_indication_wlan_scan_complete ) |
|
433 { |
|
434 server_m->unregister_event_handler( this ); |
|
435 |
|
436 DEBUG( "core_sub_operation_adhoc_c::notify() - scan complete" ); |
|
437 |
|
438 asynch_goto( core_state_scan_complete, CORE_TIMER_IMMEDIATELY ); |
|
439 |
|
440 return true_t; |
|
441 } |
|
442 |
|
443 return false_t; |
|
444 } |