/* * 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 ); }