| /* |
| * Copyright (C) 2008 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| /*-------------------------------------------------------------------*/ |
| #include "includes.h" |
| #include "scanmerge.h" |
| #include "shlist.h" |
| |
| #define IS_HIDDEN_AP(a) (((a)->ssid_len == 0) || ((a)->ssid[0] == '\0')) |
| |
| scan_ssid_t *scan_get_ssid( scan_result_t *res_ptr ) |
| { |
| static scan_ssid_t ssid_temp; |
| #ifdef WPA_SUPPLICANT_VER_0_6_X |
| const u8 *res_ie; |
| |
| res_ie = wpa_scan_get_ie(res_ptr, WLAN_EID_SSID); |
| if (!res_ie) |
| return NULL; |
| ssid_temp.ssid_len = (size_t)res_ie[1]; |
| os_memcpy(ssid_temp.ssid, (res_ie + 2), ssid_temp.ssid_len); |
| #else |
| ssid_temp.ssid_len = res_ptr->ssid_len; |
| os_memcpy(ssid_temp.ssid, res_ptr->ssid, ssid_temp.ssid_len); |
| #endif |
| return &ssid_temp; |
| } |
| |
| /*----------------------------------------------------------------------------- |
| Routine Name: scan_init |
| Routine Description: Inits scan merge list |
| Arguments: |
| mydrv - pointer to private driver data structure |
| Return Value: |
| -----------------------------------------------------------------------------*/ |
| void scan_init( struct wpa_driver_ti_data *mydrv ) |
| { |
| mydrv->last_scan = -1; |
| shListInitList(&(mydrv->scan_merge_list)); |
| } |
| |
| /*----------------------------------------------------------------------------- |
| Routine Name: scan_free |
| Routine Description: Frees scan structure private data |
| Arguments: |
| ptr - pointer to private data structure |
| Return Value: |
| -----------------------------------------------------------------------------*/ |
| static void scan_free( void *ptr ) |
| { |
| os_free(ptr); |
| } |
| |
| /*----------------------------------------------------------------------------- |
| Routine Name: scan_exit |
| Routine Description: Cleans scan merge list |
| Arguments: |
| mydrv - pointer to private driver data structure |
| Return Value: |
| -----------------------------------------------------------------------------*/ |
| void scan_exit( struct wpa_driver_ti_data *mydrv ) |
| { |
| shListDelAllItems(&(mydrv->scan_merge_list), scan_free); |
| } |
| |
| /*----------------------------------------------------------------------------- |
| Routine Name: scan_count |
| Routine Description: Gives number of list elements |
| Arguments: |
| mydrv - pointer to private driver data structure |
| Return Value: Number of elements in the list |
| -----------------------------------------------------------------------------*/ |
| unsigned long scan_count( struct wpa_driver_ti_data *mydrv ) |
| { |
| return shListGetCount(&(mydrv->scan_merge_list)); |
| } |
| |
| /*----------------------------------------------------------------------------- |
| Routine Name: scan_equal |
| Routine Description: Compares bssid of scan result and scan merge structure |
| Arguments: |
| val - pointer to scan result structure |
| idata - pointer to scan merge structure |
| Return Value: 1 - if equal, 0 - if not |
| -----------------------------------------------------------------------------*/ |
| static int scan_equal( void *val, void *idata ) |
| { |
| scan_ssid_t n_ssid, l_ssid, *p_ssid; |
| scan_result_t *new_res = (scan_result_t *)val; |
| scan_result_t *lst_res = |
| (scan_result_t *)(&(((scan_merge_t *)idata)->scanres)); |
| int ret; |
| size_t len; |
| |
| p_ssid = scan_get_ssid(new_res); |
| if (!p_ssid) |
| return 0; |
| os_memcpy(&n_ssid, p_ssid, sizeof(scan_ssid_t)); |
| p_ssid = scan_get_ssid(lst_res); |
| if (!p_ssid) |
| return 0; |
| os_memcpy(&l_ssid, p_ssid, sizeof(scan_ssid_t)); |
| |
| len = (IS_HIDDEN_AP(&n_ssid) || IS_HIDDEN_AP(&l_ssid)) ? |
| 0 : n_ssid.ssid_len; |
| ret = ((l_ssid.ssid_len != n_ssid.ssid_len) && (len != 0)) || |
| (os_memcmp(new_res->bssid, lst_res->bssid, ETH_ALEN) || |
| os_memcmp(n_ssid.ssid, l_ssid.ssid, len)); |
| return !ret; |
| } |
| |
| /*----------------------------------------------------------------------------- |
| Routine Name: copy_scan_res |
| Routine Description: copies scan result structure to scan merge list item |
| Arguments: |
| dst - pointer to scan result structure in the list |
| src - source pointer to scan result structure |
| Return Value: NONE |
| -----------------------------------------------------------------------------*/ |
| void copy_scan_res( scan_result_t *dst, scan_result_t *src ) |
| { |
| #ifdef WPA_SUPPLICANT_VER_0_5_X |
| if( IS_HIDDEN_AP(src) ) { |
| os_memcpy(src->ssid, dst->ssid, dst->ssid_len); |
| src->ssid_len = dst->ssid_len; |
| } |
| #endif |
| os_memcpy(dst, src, sizeof(scan_result_t)); |
| } |
| |
| /*----------------------------------------------------------------------------- |
| Routine Name: scan_add |
| Routine Description: adds scan result structure to scan merge list |
| Arguments: |
| head - pointer to scan merge list head |
| res_ptr - pointer to scan result structure |
| Return Value: Pointer to scan merge item |
| -----------------------------------------------------------------------------*/ |
| static scan_merge_t *scan_add( SHLIST *head, scan_result_t *res_ptr ) |
| { |
| scan_merge_t *scan_ptr; |
| unsigned size = 0; |
| |
| #ifdef WPA_SUPPLICANT_VER_0_6_X |
| size += res_ptr->ie_len; |
| #endif |
| scan_ptr = (scan_merge_t *)os_malloc(sizeof(scan_merge_t) + size); |
| if( !scan_ptr ) |
| return( NULL ); |
| os_memcpy(&(scan_ptr->scanres), res_ptr, sizeof(scan_result_t) + size); |
| scan_ptr->count = SCAN_MERGE_COUNT; |
| shListInsLastItem(head, (void *)scan_ptr); |
| return scan_ptr; |
| } |
| |
| /*----------------------------------------------------------------------------- |
| Routine Name: scan_find |
| Routine Description: Looks for scan merge item in scan results array |
| Arguments: |
| scan_ptr - pointer to scan merge item |
| results - pointer to scan results array |
| number_items - current number of items |
| Return Value: 1 - if item was found, 0 - otherwise |
| -----------------------------------------------------------------------------*/ |
| static int scan_find( scan_merge_t *scan_ptr, scan_result_t *results, |
| unsigned int number_items ) |
| { |
| unsigned int i; |
| |
| for(i=0;( i < number_items );i++) { |
| if( scan_equal(&(results[i]), scan_ptr) ) |
| return 1; |
| } |
| return 0; |
| } |
| |
| #ifdef WPA_SUPPLICANT_VER_0_6_X |
| /*----------------------------------------------------------------------------- |
| Routine Name: scan_dup |
| Routine Description: Create copy of scan results entry |
| Arguments: |
| res_ptr - pointer to scan result item |
| Return Value: pointer to new scan result item, or NULL |
| -----------------------------------------------------------------------------*/ |
| static scan_result_t *scan_dup( scan_result_t *res_ptr ) |
| { |
| unsigned size; |
| scan_result_t *new_ptr; |
| |
| if (!res_ptr) |
| return NULL; |
| |
| size = sizeof(scan_result_t) + res_ptr->ie_len; |
| new_ptr = os_malloc(size); |
| if (!new_ptr) |
| return NULL; |
| if (res_ptr) { |
| os_memcpy(new_ptr, res_ptr, size); |
| } |
| return new_ptr; |
| } |
| #endif |
| |
| /*----------------------------------------------------------------------------- |
| Routine Name: scan_merge |
| Routine Description: Merges current scan results with previous |
| Arguments: |
| mydrv - pointer to private driver data structure |
| results - pointer to scan results array |
| number_items - current number of items |
| max_size - maximum namber of items |
| Return Value: Merged number of items |
| -----------------------------------------------------------------------------*/ |
| #ifdef WPA_SUPPLICANT_VER_0_6_X |
| unsigned int scan_merge( struct wpa_driver_ti_data *mydrv, |
| scan_result_t **results, int force_flag, |
| unsigned int number_items, unsigned int max_size ) |
| #else |
| unsigned int scan_merge( struct wpa_driver_ti_data *mydrv, |
| scan_result_t *results, int force_flag, |
| unsigned int number_items, unsigned int max_size ) |
| #endif |
| { |
| SHLIST *head = &(mydrv->scan_merge_list); |
| SHLIST *item, *del_item; |
| scan_result_t *res_ptr; |
| scan_merge_t *scan_ptr; |
| unsigned int i; |
| |
| /* Prepare items for removal */ |
| item = shListGetFirstItem(head); |
| while( item != NULL ) { |
| scan_ptr = (scan_merge_t *)(item->data); |
| if( scan_ptr->count != 0 ) |
| scan_ptr->count--; |
| item = shListGetNextItem(head, item); |
| } |
| |
| for(i=0;( i < number_items );i++) { /* Find/Add new items */ |
| #ifdef WPA_SUPPLICANT_VER_0_6_X |
| res_ptr = results[i]; |
| #else |
| res_ptr = &(results[i]); |
| #endif |
| item = shListFindItem( head, res_ptr, scan_equal ); |
| if( item ) { |
| #ifdef WPA_SUPPLICANT_VER_0_6_X |
| scan_ssid_t *p_ssid; |
| scan_result_t *new_ptr; |
| #endif |
| scan_ptr = (scan_merge_t *)(item->data); |
| copy_scan_res(&(scan_ptr->scanres), res_ptr); |
| scan_ptr->count = SCAN_MERGE_COUNT; |
| #ifdef WPA_SUPPLICANT_VER_0_6_X |
| p_ssid = scan_get_ssid(res_ptr); |
| if (p_ssid && IS_HIDDEN_AP(p_ssid)) { |
| new_ptr = scan_dup(res_ptr); |
| if (new_ptr) { |
| results[i] = new_ptr; |
| os_free(res_ptr); |
| } |
| } |
| #endif |
| } |
| else { |
| scan_add(head, res_ptr); |
| } |
| } |
| |
| item = shListGetFirstItem( head ); /* Add/Remove missing items */ |
| while( item != NULL ) { |
| del_item = NULL; |
| scan_ptr = (scan_merge_t *)(item->data); |
| if( scan_ptr->count != SCAN_MERGE_COUNT ) { |
| if( !force_flag && ((scan_ptr->count == 0) || |
| (mydrv->last_scan == SCAN_TYPE_NORMAL_ACTIVE)) ) { |
| del_item = item; |
| } |
| else { |
| if( number_items < max_size ) { |
| #ifdef WPA_SUPPLICANT_VER_0_6_X |
| res_ptr = scan_dup(&(scan_ptr->scanres)); |
| if (res_ptr) { |
| results[number_items] = res_ptr; |
| number_items++; |
| } |
| #else |
| os_memcpy(&(results[number_items]), |
| &(scan_ptr->scanres), sizeof(scan_result_t)); |
| number_items++; |
| #endif |
| } |
| } |
| } |
| item = shListGetNextItem(head, item); |
| shListDelItem(head, del_item, scan_free); |
| } |
| |
| return( number_items ); |
| } |
| |
| /*----------------------------------------------------------------------------- |
| Routine Name: scan_get_by_bssid |
| Routine Description: Gets scan_result pointer to item by bssid |
| Arguments: |
| mydrv - pointer to private driver data structure |
| bssid - pointer to bssid value |
| Return Value: pointer to scan_result item |
| -----------------------------------------------------------------------------*/ |
| scan_result_t *scan_get_by_bssid( struct wpa_driver_ti_data *mydrv, u8 *bssid ) |
| { |
| SHLIST *head = &(mydrv->scan_merge_list); |
| SHLIST *item; |
| scan_result_t *cur_res; |
| scan_ssid_t *p_ssid; |
| |
| item = shListGetFirstItem(head); |
| if( item == NULL ) |
| return( NULL ); |
| do { |
| cur_res = (scan_result_t *)&(((scan_merge_t *)(item->data))->scanres); |
| p_ssid = scan_get_ssid(cur_res); |
| if( (!os_memcmp(cur_res->bssid, bssid, ETH_ALEN)) && |
| (!IS_HIDDEN_AP(p_ssid)) ) { |
| return( cur_res ); |
| } |
| item = shListGetNextItem(head, item); |
| } while( item != NULL ); |
| |
| return( NULL ); |
| } |