• Main Page
  • Data Structures
  • Files
  • File List
  • Globals

dbus-handler.c

Go to the documentation of this file.
00001 
00027 #include <stdio.h>
00028 #include <stdlib.h>
00029 #include <unistd.h>
00030 #include <glib.h>
00031 #include <errno.h>
00032 #include <net/if.h>
00033 #include <net/ethernet.h>
00034 #include <linux/socket.h>
00035 #include <sys/ioctl.h>
00036 #include <osso-ic-dbus.h>
00037 #include <syslog.h>
00038 
00039 #define DBUS_API_SUBJECT_TO_CHANGE
00040 #include <dbus/dbus.h>
00041 #include <eap-dbus.h>
00042 #include <wlancond-dbus.h>
00043 #include <mce/mode-names.h>
00044 #ifdef USE_MCE_MODE
00045 #include <mce/dbus-names.h>
00046 #endif
00047 #include "log.h"
00048 #include "dbus.h"
00049 #include "dbus-helper.h"
00050 #include "dbus-handler.h"
00051 #include "common.h"
00052 #include "wpa.h"
00053 #include "wps.h"
00054 #include "wapi.h"
00055 
00056 #define WLANCOND_SHUTDOWN_DELAY 12 //12s
00057 #define WLANCOND_CONNECT_TIMEOUT 14 //14s
00058 #define WLANCOND_SCAN_TIMEOUT 8 //8s
00059 #define WLANCOND_RESCAN_DELAY 1
00060 #define WLANCOND_GPRS_TIMEOUT 2 //2s
00061 
00062 #define CALIBRATION_APPLICATION "/usr/bin/wl1271-cal"
00063 
00065 static char *scan_name_cache = NULL;
00067 static char *connect_name_cache = NULL;
00068 
00070 static int wlan_socket = -1;
00071 
00073 struct wlan_status_t wlan_status;
00074 
00075 static gboolean _flight_mode = FALSE;
00076 static gboolean power_down_after_scan = FALSE;
00077 static dbus_bool_t saved_inactivity = FALSE;
00078 
00080 static guint wlan_if_down_timer_id = 0;
00081 static guint wlan_connect_timer_id = 0;
00082 static guint wlan_gprs_timer_id = 0;
00083 
00085 gint debug_level = 0;
00086 
00087 #define WLAN_PREFIX_STR "wlan"
00088 
00091 void wlancond_print(guint priority, const char *debug, ...) {
00092         va_list args;
00093         char buffer[200];
00094 
00095         switch (debug_level) {
00096                 /* In debug level 0 only high prio printing (release) */
00097         case 0:
00098                 if (priority > WLANCOND_PRIO_MEDIUM) {
00099                         va_start(args, debug);
00100                         vsnprintf(buffer, sizeof(buffer), debug, args);
00101                         va_end(args);
00102 
00103                         syslog(LOG_INFO | LOG_DAEMON, "%s", buffer);
00104                         return;
00105                 }
00106                 break;
00107         case 1:
00108                 if (priority > WLANCOND_PRIO_LOW) {
00109                         va_start(args, debug);
00110                         vsnprintf(buffer, sizeof(buffer), debug, args);
00111                         va_end(args);
00112 
00113                         syslog(LOG_INFO | LOG_DAEMON, "%s", buffer);
00114                         return;
00115                 }
00116                 break;
00117                 /* Print everything */
00118         default:
00119                 va_start(args, debug);
00120                 vsnprintf(buffer, sizeof(buffer), debug, args);
00121                 va_end(args);
00122 
00123                 syslog(LOG_INFO | LOG_DAEMON, "%s", buffer);
00124                 return;
00125         }
00126 }
00130 int socket_open(void)
00131 {
00132         if (wlan_socket > 0)
00133                 return wlan_socket;
00134 
00135         wlan_socket = socket(AF_INET, SOCK_DGRAM, 0);
00136 
00137         if (wlan_socket < 0)
00138                 die("socket() failed");
00139 
00140         return wlan_socket;
00141 }
00142 
00143 static int get_own_mac(void)
00144 {
00145         struct ifreq req;
00146 
00147         memset(&req , 0, sizeof(req));
00148         memcpy(req.ifr_name, wlan_status.ifname, IFNAMSIZ);
00149 
00150         if (ioctl(socket_open(), SIOCGIFHWADDR, &req) < 0)
00151         {
00152                 return -1;
00153         }
00154 
00155         memcpy(wlan_status.own_mac, req.ifr_hwaddr.sa_data, ETH_ALEN);
00156 
00157         print_mac(WLANCOND_PRIO_LOW, "MAC:", (guchar*) wlan_status.own_mac);
00158 
00159         return 0;
00160 }
00161 
00167 static gint get_setting_int(const gchar* path)
00168 {
00169         gint value = -1;
00170         ConnSettingsValue *conn_setting_value;
00171 
00172         conn_setting_value = conn_settings_get(wlan_status.setting, path);
00173         if (conn_setting_value == NULL) {
00174                 return -1;
00175         }
00176 
00177         if (conn_setting_value->type == CONN_SETTINGS_VALUE_INT) {
00178                 value = conn_setting_value->value.int_val;
00179                 DLOG_DEBUG("User selected value %d for %s", value, path);
00180 
00181         }
00182 
00183         conn_settings_value_destroy(conn_setting_value);
00184 
00185         return value;
00186 }
00193 gboolean get_setting_bool(const gchar* path, gboolean *error)
00194 {
00195         gboolean value = FALSE;
00196         ConnSettingsValue *conn_setting_value;
00197 
00198         *error = TRUE;
00199 
00200         conn_setting_value = conn_settings_get(wlan_status.setting, path);
00201         if (conn_setting_value == NULL) {
00202                 return value;
00203         }
00204 
00205         if (conn_setting_value->type == CONN_SETTINGS_VALUE_BOOL) {
00206                 value = conn_setting_value->value.bool_val;
00207                 DLOG_DEBUG("User selected %s for %s", value==TRUE?
00208                                                 "true":"false", path);
00209                 *error = FALSE;
00210         }
00211 
00212         conn_settings_value_destroy(conn_setting_value);
00213 
00214         return value;
00215 }
00219 void init_logging(void) {
00220 
00221         wlan_status.setting = conn_settings_open(CONN_SETTINGS_CONNECTION, 
00222                                                  NULL);
00223 
00224         if (wlan_status.setting == NULL ) { 
00225                 DLOG_ERR("Opening connection settings failed");
00226                 return;
00227         }
00228         debug_level = get_setting_int(WLANCOND_DEBUG_LEVEL);
00229         if (debug_level < 0)
00230                 debug_level = 0;
00231 
00232         if (debug_level > 0) {
00233                 DLOG_DEBUG("Debug level increased to %d", debug_level);
00234         }
00235 }
00236 
00242 void update_own_ie(unsigned char* wpa_ie, guint wpa_ie_len) 
00243 {
00244         g_free(wlan_status.wpa_ie.ie);
00245         wlan_status.wpa_ie.ie = wpa_ie;
00246         wlan_status.wpa_ie.ie_len = wpa_ie_len;
00247 }
00248 
00253 guint get_encryption_info(void) 
00254 {
00255         guint auth_status = 0;
00256 
00257         if (wlan_status.pairwise_cipher & CIPHER_SUITE_CCMP) {
00258                 auth_status |= WLANCOND_WPA_AES;
00259         } else if (wlan_status.pairwise_cipher & CIPHER_SUITE_TKIP) {
00260                 auth_status |= WLANCOND_WPA_TKIP;
00261         } else if (wlan_status.pairwise_cipher & CIPHER_SUITE_SMS4) {
00262                 auth_status |= WLANCOND_WAPI_SMS4;
00263         } else if (wlan_status.pairwise_cipher & CIPHER_SUITE_WEP40 ||
00264                    wlan_status.pairwise_cipher & CIPHER_SUITE_WEP104) {
00265                 auth_status |= WLANCOND_WEP;
00266         } else {
00267                 auth_status |= WLANCOND_OPEN;
00268         }
00269         return auth_status;
00270 }
00271 
00275 int clean_dbus_handler(void)
00276 {
00277         if (wlan_socket > 0) {
00278                 close(wlan_socket);
00279                 wlan_socket = -1;
00280         }
00281         return 0;
00282 }
00287 void mode_change(dbus_uint32_t radio_mode) {
00288 
00289         gboolean mode = !!(radio_mode & MCE_RADIO_STATE_WLAN);
00290 
00291         DLOG_INFO("WLAN flight mode changed to \"%s\"", 
00292                         mode?"Normal":"Flight");
00293 
00294         if (!mode) {
00295                 int signal = NO_SIGNAL;
00296                 if (is_connected_state() == TRUE)
00297                         signal = DISCONNECTED_SIGNAL;
00298                 set_wlan_state(WLAN_NOT_INITIALIZED, signal, FALSE);
00299                 _flight_mode = TRUE;    
00300         }
00301         else {
00302                 _flight_mode = FALSE;           
00303         }
00304 }
00309 #ifdef USE_MCE_MODE
00310 static DBusHandlerResult mode_change_dbus(DBusMessage *message) {
00311 
00312         dbus_uint32_t mode;
00313 
00314         if (!dbus_message_get_args(message, NULL,
00315                                    DBUS_TYPE_UINT32, &mode,
00316                                    DBUS_TYPE_INVALID)) {
00317                 DLOG_ERR("Invalid arguments for device_mode_ind signal");
00318                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
00319         }
00320 
00321         mode_change(mode);
00322 
00323         return DBUS_HANDLER_RESULT_HANDLED;
00324 }
00325 #ifdef ACTIVITY_CHECK
00326 static DBusHandlerResult activity_check_dbus(DBusMessage *message) {
00327 
00328         if (!dbus_message_get_args(message, NULL,
00329                                    DBUS_TYPE_BOOLEAN, &saved_inactivity,
00330                                    DBUS_TYPE_INVALID)) {
00331                 DLOG_ERR("Invalid arguments for device_activity signal");
00332                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
00333         }
00334         activity_check(saved_inactivity);
00335 
00336         return DBUS_HANDLER_RESULT_HANDLED;
00337 }
00338 #endif
00339 #endif
00340 
00341 #ifdef ACTIVITY_CHECK
00342 
00345 void activity_check(dbus_bool_t inactivity) {
00346 
00347         if (get_wlan_state() != WLAN_CONNECTED) {
00348                 return;
00349         }
00350 
00351         if (inactivity == FALSE) {
00352                 //DLOG_DEBUG("WLAN activity mode changed to active");
00353                 if (nl80211_set_cqm(WLANCOND_CQM_THRESHOLD_ACTIVE, 
00354                                     WLANCOND_CQM_HYSTERESIS)) 
00355                         DLOG_ERR("nl80211 - CQM monitor setting failed");
00356 
00357                 /* No need to check traffic */
00358                 remove_iptables();
00359         } else {
00360                 //DLOG_DEBUG("WLAN activity mode changed to inactive");
00361                 if (nl80211_set_cqm(WLANCOND_CQM_THRESHOLD_IDLE, 
00362                                     WLANCOND_CQM_HYSTERESIS)) 
00363                         DLOG_ERR("nl80211 - CQM monitor setting failed");
00364                 
00365                 if (set_iptables() < 0)
00366                         DLOG_ERR("Setting iptables failed");
00367         }
00368         set_power_state(wlan_status.powersave);
00369 }
00370 
00374 gboolean get_inactivity_status(void)
00375 {
00376         return saved_inactivity;
00377 }
00378 #endif
00379 
00384 static DBusHandlerResult icd_check_signal_dbus(DBusMessage *message) {
00385 
00386         char *icd_name;
00387         char *icd_type;
00388         char *icd_state;
00389         DBusError dbus_error;
00390 
00391         if ((get_wlan_state() != WLAN_CONNECTED &&
00392              get_wlan_state() != WLAN_NO_ADDRESS) ||
00393             get_mode() != WLANCOND_INFRA) {
00394                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
00395         }
00396 
00397         dbus_error_init(&dbus_error);
00398         if (!dbus_message_get_args(message, &dbus_error,
00399                                    DBUS_TYPE_STRING, &icd_name,
00400                                    DBUS_TYPE_STRING, &icd_type,
00401                                    DBUS_TYPE_STRING, &icd_state,
00402                                    DBUS_TYPE_INVALID ) )
00403         {
00404                 DLOG_ERR("Could not get args from signal, '%s'",
00405                          dbus_error.message);
00406                 dbus_error_free(&dbus_error);
00407                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
00408         }
00409 
00410         if (icd_state != NULL && strncmp(icd_state, "CONNECTED", 9) == 0) {
00411 
00412                 set_wlan_state(WLAN_CONNECTED, NO_SIGNAL, TRUE);
00413 
00414                 DLOG_DEBUG("Going to power save");
00415 
00416                 if (set_power_state(wlan_status.powersave) == FALSE) {
00417                         DLOG_ERR("Failed to set power save");
00418                 }
00419 
00420         }
00421 
00422         //DLOG_DEBUG("Handled icd signal, icd_state:%s", icd_state);
00423 
00424         return DBUS_HANDLER_RESULT_HANDLED;
00425 }
00426 
00432 static DBusHandlerResult eap_check_signal_dbus(DBusMessage *message) {
00433 
00434         DBusError dbus_error;
00435         dbus_uint32_t status;
00436 
00437         dbus_error_init(&dbus_error);
00438         if (!dbus_message_get_args(message, &dbus_error,
00439                                    DBUS_TYPE_UINT32, &status,
00440                                    DBUS_TYPE_INVALID ) )
00441         {
00442                 DLOG_ERR("Could not get args from signal, '%s'",
00443                          dbus_error.message);
00444                 dbus_error_free(&dbus_error);
00445                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
00446         }
00447 
00448         if (status == EAP_SUCCESS) 
00449         {
00450                 /* Set powersave if IP layer is Ok */
00451                 if (get_wlan_state() != WLAN_NO_ADDRESS)
00452                         if (set_power_state(wlan_status.powersave) == FALSE)
00453                                 DLOG_ERR("Setting powersave failed (wpa)");
00454 
00455                 if (netlink_send_linkmode(WLANCOND_IF_READY) != 0)
00456                         DLOG_ERR("Setting oper state to ready failed");
00457 
00458                 /* Successfull connection, set retry count to 0 */
00459                 wlan_status.retry_count = 0;
00460         }
00461 
00462         return DBUS_HANDLER_RESULT_HANDLED;
00463 }
00464 
00468 gint run_calibration(void) {
00469         gchar *args[2];
00470         gint count = 0;
00471         args[count++] = (gchar*) CALIBRATION_APPLICATION;
00472         args[count++] = NULL;
00473 
00474         DLOG_DEBUG("Running calibration");
00475 
00476         if (!g_spawn_sync (NULL, args, NULL, G_SPAWN_STDOUT_TO_DEV_NULL |
00477                            G_SPAWN_STDERR_TO_DEV_NULL,
00478                            NULL, NULL, NULL, NULL, NULL, NULL)) {
00479                 return -1;
00480         }
00481 
00482         return 0;
00483 }
00487 #define KILL_SUPPLICANT "/usr/bin/killall"
00488 #define SUPPLICANT_NAME "eapd.real"
00489 void kill_supplicant(void) {
00490         
00491         DLOG_ERR("Supplicant error");
00492         
00493         system(KILL_SUPPLICANT " -9 " SUPPLICANT_NAME);
00494 }
00495 static void remove_wlan_gprs_timer(void)
00496 {
00497         if (wlan_gprs_timer_id) {
00498                 g_source_remove(wlan_gprs_timer_id);
00499                 wlan_gprs_timer_id = 0;
00500         }
00501 }
00507 static gboolean wlan_gprs_cb(void* data) {
00508 
00509         if (wlan_gprs_timer_id) {
00510                 wlan_gprs_timer_id = 0;
00511 
00512                 DLOG_DEBUG("GPRS became idle"); 
00513                 wlan_status.call_type &= ~CALL_GPRS;
00514                 set_tx_power(wlan_status.conn.power_level);
00515         }
00516         return FALSE;
00517 }
00523 static DBusHandlerResult gprs_datacounters_signal(DBusMessage *message) {
00524 
00525         if (!(wlan_status.call_type & CALL_GPRS)) {
00526                 DLOG_DEBUG("GPRS is active");
00527                 wlan_status.call_type |= CALL_GPRS;
00528                 set_tx_power(wlan_status.conn.power_level);
00529         }
00530         
00531         remove_wlan_gprs_timer();
00532         
00533         wlan_gprs_timer_id = g_timeout_add_seconds(
00534                 WLANCOND_GPRS_TIMEOUT,
00535                 wlan_gprs_cb,
00536                 NULL);
00537         
00538         return DBUS_HANDLER_RESULT_HANDLED;
00539 }
00545 static DBusHandlerResult csd_check_signal_dbus(DBusMessage *message) {
00546 
00547         DBusError error;
00548         char* network_code;
00549         char* country_code;
00550         struct timeval tv;
00551 
00552         dbus_error_init(&error);
00553 
00554         if (!dbus_message_get_args(message, &error,
00555                                    DBUS_TYPE_STRING, &network_code,
00556                                    DBUS_TYPE_STRING, &country_code,
00557                                    DBUS_TYPE_INVALID))
00558         {
00559                 DLOG_ERR("Could not get args from signal, '%s'",
00560                          error.message);
00561                 dbus_error_free(&error);
00562                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
00563         }
00564 
00565         DLOG_DEBUG("Handled csd signal, country code: %s", country_code);
00566 
00567         if (country_code == NULL || strlen(country_code) == 0) {
00568                 if (wlan_status.country_code != NULL && 
00569                     strlen(wlan_status.country_code) != 0) {
00570                         /* We lost the country information.
00571                            Update last valid country code timestamp */
00572                         if (wlan_status.calibration_needed == FALSE) {
00573                                 if (gettimeofday(&tv, NULL) <0)
00574                                         wlan_status.last_code = 0;
00575                                 else
00576                                         wlan_status.last_code = tv.tv_sec;      
00577                         }
00578                         g_free(wlan_status.country_code);
00579                         wlan_status.country_code = NULL;
00580                         wlan_status.calibration_needed = TRUE;
00581                         DLOG_INFO("Country information lost");
00582                 }
00583         } else if (wlan_status.country_code == NULL || 
00584                    strcmp(country_code, wlan_status.country_code)) {
00585                 /* The new code is different from the old.
00586                    Check if the last calibrated matches the new one.
00587                    Then we don't need to run calibration again.
00588                 */
00589                 if (wlan_status.last_calibrated_code && country_code && 
00590                     strcmp(wlan_status.last_calibrated_code, 
00591                            country_code) == 0) {
00592                         DLOG_DEBUG("Calibration is not needed");
00593                         wlan_status.calibration_needed = FALSE;
00594                 } else {
00595                         DLOG_DEBUG("Calibration is needed");
00596                         wlan_status.calibration_needed = TRUE;
00597                 }
00598                 g_free(wlan_status.country_code);
00599                 wlan_status.country_code = g_strdup(country_code);
00600                 /* Stop caching. If we loose the network we might be
00601                  caching wrong value */
00602                 wlan_status.last_code = 0;
00603                 DLOG_INFO("Country code changed to: %s", country_code);
00604         }
00605 
00606         return DBUS_HANDLER_RESULT_HANDLED;
00607 }
00612 static gboolean check_country_timeout(void) {
00613         struct timeval tv;
00614 
00615         /* Initial state after boot */
00616         if (wlan_status.last_code == 0)
00617                 return FALSE;
00618         
00619         if (gettimeofday(&tv, NULL) <0) 
00620                 return FALSE;
00621         
00622         if (tv.tv_sec > wlan_status.last_code + WLANCOND_COUNTRY_CACHE_TIME)
00623                 return FALSE;
00624 
00625         return TRUE;
00626 }
00627 
00632 static gint handle_country(void) {
00633         if (wlan_status.calibration_needed ||
00634             wlan_status.country_code == NULL) {
00635                 
00636                 if (wlan_status.country_code == NULL ||
00637                     strlen(wlan_status.country_code) == 0) {
00638                         /* Check if we can use cached value */
00639                         if (check_country_timeout() == TRUE) {
00640                                 DLOG_DEBUG("Cached code in use");
00641                                 return 0;
00642                         } else {
00643                                 DLOG_DEBUG("Cannot use cached code");
00644                         }
00645                 }
00646 
00647                 /* Read the code so we can check
00648                    if the code changes in CSD signal.
00649                 */
00650                 char* code = check_country_code();
00651                 
00652                 /* Run calibration if we got new code */
00653                 if (code != NULL)
00654                         if (run_calibration() < 0)
00655                                 DLOG_ERR("Fatal: Could not calibrate");
00656                 
00657                 g_free(wlan_status.country_code);
00658                 wlan_status.country_code = code;
00659                 g_free(wlan_status.last_calibrated_code);
00660                 wlan_status.last_calibrated_code = g_strdup(code);
00661                 wlan_status.calibration_needed = FALSE;
00662         }
00663         return 0;
00664 }
00668 int init_dbus_handler(void)
00669 {
00670         gboolean error;
00671 
00672         handle_country();
00673 
00674         if (get_own_mac() < 0) {
00675                 DLOG_ERR("Could not get own MAC address");
00676                 return -1;
00677         }
00678 
00679         wlan_status.allow_all_ciphers = get_setting_bool(
00680                 WLANCOND_ALLOW_ALL_CIPHERS, &error);
00681         
00682         return 0;
00683 }
00684 
00685 static gboolean in_flight_mode(void) {
00686         return _flight_mode;
00687 }
00688 
00689 void set_wlan_signal(gboolean high_or_low)
00690 {
00691         if (high_or_low == WLANCOND_HIGH) {
00692                 wlan_status.signal = WLANCOND_HIGH;
00693                 remove_roam_scan_timer();
00694         } else {
00695                 wlan_status.signal = WLANCOND_LOW;
00696         }
00697 }
00698 
00699 void remove_roam_scan_timer(void)
00700 {
00701         if (wlan_status.roam_scan_id) {
00702                 g_source_remove(wlan_status.roam_scan_id);
00703                 wlan_status.roam_scan_id = 0;
00704         }
00705 }
00706 
00707 void remove_connect_timer(void)
00708 {
00709         if (wlan_connect_timer_id) {
00710                 g_source_remove(wlan_connect_timer_id);
00711                 wlan_connect_timer_id = 0;
00712         }
00713 }
00714 
00715 static void remove_wlan_if_timer(void)
00716 {
00717         // Remove shutdown timer if exists
00718         if (wlan_if_down_timer_id) {
00719                 g_source_remove(wlan_if_down_timer_id);
00720                 wlan_if_down_timer_id = 0;
00721         }
00722 }
00723 
00724 void remove_scan_timer(void)
00725 {
00726         if (wlan_status.scan_id) {
00727                 g_source_remove(wlan_status.scan_id);
00728                 wlan_status.scan_id = 0;
00729         }
00730 }
00731 static void remove_rescan_timer(void)
00732 {
00733         if (wlan_status.rescan_id) {
00734                 g_source_remove(wlan_status.rescan_id);
00735                 wlan_status.rescan_id = 0;
00736         }
00737 }
00741 gboolean scan_retries_left(void) {
00742         guint scan_tries = WLANCOND_MAX_SCAN_TRIES;
00743 
00744         /* The following condition will retry every 
00745            WLANCOND_CONNECT_TIMEOUT seconds in case of an unsuccessful 
00746            connection but in case of WEP it will retry every 
00747            WLANCOND_CONNECT_TIMEOUT/2 seconds but 
00748            WLANCOND_MAX_SCAN_TRIES*2 times to give shared key and open 
00749            authentication 3,3 tries each as this is now done in user 
00750            space when using netlink library. */ 
00751         if ((wlan_status.conn.encryption & WLANCOND_ENCRYPT_METHOD_MASK) == 
00752             WLANCOND_WEP)
00753                 scan_tries = WLANCOND_MAX_SCAN_TRIES*2;
00754 
00755         if (++wlan_status.retry_count <= scan_tries)
00756                 return TRUE;
00757         else
00758                 return FALSE;
00759 }
00763 static gboolean no_connection_and_scan_retries_left(void) {
00764         guint scan_tries = WLANCOND_MAX_SCAN_TRIES*2;
00765 
00766         if (++wlan_status.retry_count <= scan_tries)
00767                 return TRUE;
00768         else
00769                 return FALSE;
00770 }
00776 static gboolean wlan_connect_timer_cb(void* data)
00777 {
00778         if (wlan_connect_timer_id && get_wlan_state() ==
00779             WLAN_INITIALIZED_FOR_CONNECTION) {
00780                 
00781                 wlan_connect_timer_id = 0;
00782 
00783                 DLOG_DEBUG("Association timeout, try: %d",
00784                            wlan_status.retry_count);
00785 
00786                 DLOG_DEBUG("Disconnecting previous connection");
00787                 mlme_command(wlan_status.conn.bssid, 
00788                              WLANCOND_NL80211_MLME_DISCONNECT, 
00789                              WLANCOND_REASON_LEAVING);
00790 
00791                 /* Remove the failed AP from the list */
00792                 roam_cache_key_t key = { wlan_status.conn.bssid,
00793                                          wlan_status.conn.channel };
00794                 remove_from_roam_cache(&key);
00795 
00796                 /* Set BSSID to 0 */
00797                 memset(wlan_status.conn.bssid, 0, ETH_ALEN);
00798 
00799                 /* Clear channel */
00800                 wlan_status.conn.channel = 0;
00801 
00802                 if (find_connection_and_associate(wlan_status.roam_cache,
00803                                                   FALSE, FALSE, FALSE) == 0)
00804                         return FALSE;
00805 
00806                 /* Try to scan again if retries left */
00807                 if (scan_retries_left()) {
00808                         if (scan(wlan_status.conn.ssid,
00809                                 wlan_status.conn.ssid_len, TRUE) == 0) {
00810                                 return FALSE;
00811                         }
00812                 }
00813 
00814                 set_wlan_state(WLAN_NOT_INITIALIZED, DISCONNECTED_SIGNAL,
00815                                FALSE);
00816                 return FALSE;
00817         }
00818 
00819         wlan_connect_timer_id = 0;
00820 
00821         //DLOG_DEBUG("Association OK");
00822 
00823         return FALSE;
00824 }
00825 
00831 static gboolean wlan_scan_cb(void* data)
00832 {
00833 
00834         wlan_status.scan_id = 0;
00835 
00836         DLOG_ERR("Scan failed, should not happen!");
00837 
00838         set_wlan_state(WLAN_NOT_INITIALIZED, DISCONNECTED_SIGNAL, FALSE);
00839 
00840         return FALSE;
00841 }
00847 static gboolean wlan_if_down_cb(void* data)
00848 {
00849 
00850         wlan_if_down_timer_id = 0;
00851 
00852         if (get_wlan_state() == WLAN_NOT_INITIALIZED) {
00853                 DLOG_DEBUG("Delayed shutdown occurred");
00854                 set_wlan_state(WLAN_NOT_INITIALIZED, NO_SIGNAL, FALSE);
00855                 return FALSE;
00856         }
00857 
00858         //DLOG_DEBUG("Delayed shutdown did not happen");
00859 
00860         return FALSE;
00861 }
00869 int mlme_command(guchar* addr, guint16 cmd, guint16 reason_code)
00870 {
00871         gint ret;
00872 
00873         if (!wlan_status.ifindex)
00874                 return -2;
00875 
00876         /* This following check for adhoc is because in netlink mlme_command
00877            is not supported for adhoc networks, mlme command returns not 
00878            supported error in case of adhoc. */
00879 
00880         if (wlan_status.conn.mode & WLANCOND_ADHOC) {
00881                 ret = nl80211_leave_adhoc(wlan_status.ifindex);
00882                 if (ret) {
00883                         DLOG_ERR("nl80211: Failed to Leave IBSS");
00884                         return -1;
00885                 }
00886         } else {
00887                 ret = nl80211_mlme_command(addr, cmd, reason_code, 
00888                                            wlan_status.ifindex);
00889                 if (ret) {
00890                         DLOG_ERR("nl80211: Failed to run MLME command, ret=%d",
00891                                 ret);
00892                         return -1;
00893                 }
00894         }
00895 
00896         return 0;
00897 }
00903 static int set_mode(guint32 mode)
00904 {
00905         int ret;
00906         guint32 threshold;
00907 
00908         ret = nl80211_set_op_mode(wlan_status.ifindex, mode);
00909 
00910         if (ret) {
00911                 DLOG_ERR("nl80211 - Operating mode setting failed");
00912                 return -1;
00913         }
00914 
00915         if (get_inactivity_status() == TRUE)
00916                 threshold = WLANCOND_CQM_THRESHOLD_IDLE;
00917         else
00918                 threshold = WLANCOND_CQM_THRESHOLD_ACTIVE;
00919         
00920         if (nl80211_set_cqm(threshold, WLANCOND_CQM_HYSTERESIS)) {
00921                 DLOG_ERR("nl80211 - CQM monitor setting failed");
00922                 return -1;
00923         }
00924 
00925         return 0;
00926 }
00930 static void remove_timers(void) {
00931                 /* Remove association timer */
00932                 remove_connect_timer();
00933 
00934                 /* Remove scan timer */
00935                 remove_scan_timer();
00936 
00937                 /* Remove rescan timer */
00938                 remove_rescan_timer();
00939 
00940                 // Remove shutdown timer if exists
00941                 remove_wlan_if_timer();
00942                 
00943                 // Remove GPRS timer */
00944                 remove_wlan_gprs_timer();
00945 }
00946 
00947 static void remove_connection_time_filters(void) {
00948         if (wlan_status.dbus_filters == FALSE)
00949                 return;
00950                 
00951         remove_icd_listener(get_dbus_connection());
00952 #ifdef ACTIVITY_CHECK
00953         remove_activity_listener(get_dbus_connection());
00954 #endif
00955         if (get_wpa_mode() == TRUE)
00956                 remove_eap_listener(get_dbus_connection());
00957 
00958         remove_gprs_listener(get_dbus_connection());
00959         
00960         wlan_status.dbus_filters = FALSE;
00961 }
00962 
00969 void set_wlan_state(int new_state, int send_signal, gboolean delay_shutdown)
00970 {
00971         const char *status_table[] =
00972         {
00973                 (char*)"WLAN_NOT_INITIALIZED",
00974                 (char*)"WLAN_INITIALIZED",
00975                 (char*)"WLAN_INITIALIZED_FOR_SCAN",
00976                 (char*)"WLAN_INITIALIZED_FOR_CONNECTION",
00977                 (char*)"WLAN_NO_ADDRESS",
00978                 (char*)"WLAN_CONNECTED"
00979         };
00980 
00981         switch (new_state) {
00982 
00983         case WLAN_NOT_INITIALIZED:
00984                 if (get_wlan_state() == WLAN_CONNECTED ||
00985                     get_wlan_state() == WLAN_NO_ADDRESS) {
00986                         mlme_command(wlan_status.conn.bssid,
00987                                      WLANCOND_NL80211_MLME_DISCONNECT,
00988                                      WLANCOND_REASON_LEAVING);
00989                 }
00990 
00991                 remove_iptables();
00992 
00993                 set_scan_state(SCAN_NOT_ACTIVE);
00994 
00995                 if (get_wlan_state() != WLAN_NOT_INITIALIZED &&
00996                     get_wlan_state() != WLAN_INITIALIZED_FOR_SCAN)
00997                         clear_wpa_mode();
00998 
00999                 wlan_status.retry_count = 0;
01000                 wlan_status.roam_scan = WLANCOND_MIN_ROAM_SCAN_INTERVAL;
01001                 wlan_status.ip_ok = FALSE;
01002                 wlan_status.last_scan = 0;
01003 
01004                 remove_timers();
01005 
01006                 set_wlan_signal(WLANCOND_HIGH);
01007 
01008                 if (delay_shutdown == FALSE) {
01009 
01010                         clean_roam_cache();
01011 
01012                         if (set_interface_state(socket_open(), CLEAR,
01013                                                 IFF_UP)<0) {
01014                                 DLOG_ERR("Could not set interface down");
01015                         }
01016 
01017                 } else {
01018 
01019                         DLOG_DEBUG("Delaying interface shutdown");
01020 
01021                         wlan_if_down_timer_id = g_timeout_add_seconds(
01022                                         WLANCOND_SHUTDOWN_DELAY,
01023                                         wlan_if_down_cb,
01024                                         NULL);
01025 
01026                 }
01027 
01028                 remove_connection_time_filters();
01029 
01030                 if (send_signal == DISCONNECTED_SIGNAL)
01031                         disconnected_signal();
01032 
01033                 break;
01034         case WLAN_INITIALIZED_FOR_CONNECTION:
01035                 /*
01036                    Set BSSID to 0, this state happens e.g when we drop from
01037                    the network
01038                 */
01039                 memset(wlan_status.conn.bssid, 0, ETH_ALEN);
01040 
01041                 /* Clear channel */
01042                 wlan_status.conn.channel = 0;
01043 
01044                 /* Remove association timer */
01045                 remove_connect_timer();
01046 
01047                 set_power_state(WLANCOND_POWER_ON);
01048 
01049                 break;
01050         case WLAN_CONNECTED:
01051 
01052                 /* With WPA we get signal when we can go to powersave */
01053                 if (get_wpa_mode() == FALSE)
01054                         set_power_state(wlan_status.powersave);
01055 
01056                 wlan_status.ip_ok = TRUE;
01057                 break;
01058         default:
01059                 break;
01060         }
01061         DLOG_DEBUG("Wlancond state change, old_state: %s, new_state: %s",
01062                 status_table[wlan_status.state], status_table[new_state]);
01063         wlan_status.state = new_state;
01064 }
01065 
01070 guint get_wlan_state(void)
01071 {
01072         return wlan_status.state;
01073 }
01074 
01079 void set_scan_state(guint new_state)
01080 {
01081         if (wlan_status.scan == new_state) {
01082                 return;
01083         }
01084         if (new_state == SCAN_NOT_ACTIVE) {
01085                 remove_scan_timer();
01086                 if (wlan_status.scan == SCAN_ACTIVE &&
01087                     scan_name_cache != NULL) {
01088                         DLOG_DEBUG("Sending empty results");
01089                         send_dbus_scan_results(NULL, scan_name_cache, 0);
01090                         g_free(scan_name_cache);
01091                         scan_name_cache = NULL;
01092                 }
01093         }
01094 
01095         DLOG_DEBUG("Wlancond scan change, old_state: %s, new_state: %s",
01096                    wlan_status.scan==SCAN_NOT_ACTIVE ? "SCAN_IDLE":"SCANNING",
01097                    new_state == SCAN_NOT_ACTIVE ? "SCAN_IDLE":"SCANNING");
01098         wlan_status.scan = new_state;
01099 }
01100 
01105 guint get_scan_state(void)
01106 {
01107         return wlan_status.scan;
01108 }
01113 guint get_mode(void)
01114 {
01115         return wlan_status.conn.mode;
01116 }
01117 
01122 static void set_network_latency(int latency) {
01123 
01124         DLOG_DEBUG("Setting network latency to %i", latency);
01125 
01126         if (wlan_status.latency_file == NULL) {
01127                 wlan_status.latency_file = fopen(WLANCOND_LATENCY_FILE, "w");
01128                 if (wlan_status.latency_file == NULL) {
01129                         DLOG_ERR("Cannot open: %s", WLANCOND_LATENCY_FILE);
01130                         return;
01131                 }
01132         }
01133         
01134         if (fwrite(&latency, sizeof(int), 1, wlan_status.latency_file) 
01135             != 1) {
01136                 DLOG_ERR("Could not write to: %s", WLANCOND_LATENCY_FILE);
01137         }
01138         
01139         fflush(wlan_status.latency_file);
01140 
01141         return;
01142 }
01143 
01144 gboolean can_adjust_psm(void) {
01145         /* Make sure we are properly connected, IP address OK and
01146            WPA auth OK */
01147         if (get_wlan_state() == WLAN_CONNECTED &&
01148             wlan_status.ip_ok == TRUE && 
01149             wlan_status.retry_count == 0)
01150                 return TRUE;
01151         
01152         return FALSE;
01153 }
01154 static gint compare_scan_entry(gconstpointer a, gconstpointer b)
01155 {
01156         const scan_results_t *scan_entry = a;
01157         const roam_cache_key_t *key = b;
01158         int ret;
01159         if ((ret = memcmp(scan_entry->bssid, key->bssid, ETH_ALEN)))
01160                 return ret;
01161         else
01162                 return scan_entry->channel - key->channel;
01163 }
01164 
01170 static gboolean is_uapsd_supported(unsigned char* mac) {
01171 
01172         GSList *list;
01173         unsigned char *ap_mac = mac;
01174 
01175         /* If no MAC is supplied use the current AP */
01176         if (ap_mac == NULL)
01177                 ap_mac = wlan_status.conn.bssid;
01178 
01179         roam_cache_key_t key = { ap_mac, wlan_status.conn.channel };
01180         list = g_slist_find_custom(wlan_status.roam_cache,
01181                                    &key,
01182                                    &compare_scan_entry);
01183         if (list == NULL)
01184                 return FALSE;
01185 
01186         struct scan_results_t *entry = list->data;
01187         if (entry->extra_cap_bits & WLANCOND_UAPSD_SUPPORTED)
01188                 return TRUE;
01189 
01190         return FALSE;
01191 }
01192 
01198 gboolean set_power_state(guint new_state)
01199 {
01200         gboolean power_state;
01201 
01202         if (new_state == WLANCOND_CAM_TIMEOUT) {
01203                 if ((wlan_status.call_type & CALL_VOIP) &&
01204                     is_uapsd_supported(NULL)) {
01205                         DLOG_DEBUG("Full PSM because of VOIP and U-APSD");
01206                         new_state = WLANCOND_FULL_POWERSAVE;
01207                 } else if (wlan_status.full_psm_enabled) {
01208                         /* If full psm is enabled in the settings */
01209                         new_state = WLANCOND_FULL_POWERSAVE;
01210                 } else if (wlan_status.high_traffic == FALSE &&
01211                            can_adjust_psm() == TRUE &&
01212                            get_inactivity_status() == TRUE) {
01213                         /* If the traffic is low and the user is inactive,
01214                            let's go to full PSM
01215                         */
01216                         new_state = WLANCOND_FULL_POWERSAVE;
01217                 }
01218         }
01219 
01220         if (wlan_status.power == new_state)
01221                 return TRUE;
01222 
01223         switch (new_state) {
01224         case WLANCOND_POWER_ON:
01225                 power_state = FALSE;
01226                 break;
01227         case WLANCOND_CAM_TIMEOUT:
01228                 set_network_latency(WLANCOND_DEFAULT_NETWORK_LATENCY);
01229                 power_state = TRUE;
01230                 break;
01231         case WLANCOND_FULL_POWERSAVE:
01232                 set_network_latency(WLANCOND_FULL_PSM_LATENCY);
01233                 power_state = TRUE;
01234                 break;
01235         default:
01236                 power_state = TRUE;
01237                 break;
01238         }
01239 
01240         if (nl80211_set_power_save(power_state, wlan_status.ifindex) != 0) {
01241                 DLOG_ERR("set power failed, state: %s", 
01242                          power_state?"true":"false");
01243                 return FALSE;
01244         }
01245         
01246         wlan_status.power = new_state;
01247 
01248         DLOG_DEBUG("New power state set: %i", new_state);
01249 
01250         return TRUE;
01251 }
01252 
01258 static int init_if(int sock)
01259 {
01260         if (!wlan_status.ifindex)
01261                 return -1;
01262 
01263         int previous_state = get_wlan_state();
01264 
01265         if (previous_state == WLAN_NOT_INITIALIZED) {
01266                 /* Check if interface is still up from delayed shutdown */
01267                 if (wlan_status.interface_up == FALSE) {
01268 
01269                         /* Start from the beginning */
01270                         if (handle_country() < 0)
01271                                 return -1;
01272 
01273                         if (set_interface_state(sock, SET, 
01274                                                 IFF_UP | IFF_RUNNING) < 0) {
01275                                 return -1;
01276                         }
01277                 }
01278 
01279                 set_power_state(WLANCOND_POWER_ON);
01280                 set_wlan_state(WLAN_INITIALIZED, NO_SIGNAL, FALSE);
01281         }
01282 
01283         return previous_state;
01284 }
01285 
01289 void save_device_interface(void)
01290 {
01291         strncpy(wlan_status.ifname, WLANCOND_IF_NAME, IFNAMSIZ);
01292         wlan_status.ifname[IFNAMSIZ] = '\0';
01293         wlan_status.ifindex = if_nametoindex(wlan_status.ifname);
01294         DLOG_DEBUG("WLAN interface Index %u", wlan_status.ifindex);
01295 }
01296 
01304 int set_interface_state(int sock, int dir, short flags)
01305 {
01306         struct ifreq ifr;
01307 
01308         memset(&ifr, 0, sizeof(ifr));
01309 
01310         strncpy(ifr.ifr_name, wlan_status.ifname, IFNAMSIZ);
01311 
01312         if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) {
01313                 DLOG_ERR("Could not get interface %s flags",
01314                          wlan_status.ifname);
01315                 return -1;
01316         }
01317         if (dir == SET) {
01318                 if (!add_context_listener(get_dbus_connection()))
01319                         DLOG_ERR("Adding context listener failed");
01320 
01321                 wlan_status.call_type = get_call_state();
01322 
01323                 ifr.ifr_flags |= flags;
01324         } else {
01325                 remove_context_listener(get_dbus_connection());
01326 
01327                 wlan_status.if_down_self = TRUE;
01328                 ifr.ifr_flags &= ~flags;
01329         }
01330 
01331         if (ioctl(sock, SIOCSIFFLAGS, &ifr) < 0) {
01332                 DLOG_ERR("Could not set interface %s flags",
01333                          wlan_status.ifname);
01334                 return -1;
01335         }
01336         
01337         wlan_status.interface_up = (dir == SET ? TRUE:FALSE);
01338         DLOG_DEBUG("%s is %s", wlan_status.ifname, 
01339                    wlan_status.interface_up == TRUE ? "UP":"DOWN");
01340 
01341         return 0;
01342 }
01343 
01350 gboolean set_tx_power(guint power)
01351 {
01352         int tx_power;
01353 
01354         if (wlan_status.call_type & (CALL_CELLULAR | CALL_GPRS)) {
01355                 if (power == WLANCOND_TX_POWER10)
01356                         tx_power = WLANCOND_TX_POWER10DBM;
01357                 else
01358                         tx_power = WLANCOND_TX_POWERLIMITED; 
01359         } else {
01360                 if (power == WLANCOND_TX_POWER10) {
01361                         tx_power = WLANCOND_TX_POWER10DBM;
01362                 } else if (power == WLANCOND_TX_POWER100) {
01363                         tx_power = WLANCOND_TX_POWER100DBM;
01364                 } else {
01365                         return FALSE;
01366                 }
01367         }
01368 
01369         if (nl80211_set_tx_power(tx_power, wlan_status.ifindex) != 0) {
01370                 DLOG_ERR("set tx power failed");
01371                 return FALSE;
01372         }
01373 
01374         return TRUE;
01375 }
01382 static int update_algorithms(guint32 encryption, 
01383                              struct scan_results_t *scan_results)
01384 {
01385         wlan_status.group_cipher = 0;
01386         wlan_status.pairwise_cipher = 0;
01387 
01388         // Open
01389         if ((encryption & WLANCOND_ENCRYPT_METHOD_MASK) == WLANCOND_OPEN) {
01390                 DLOG_DEBUG("Open mode");
01391                 wlan_status.pairwise_cipher = CIPHER_SUITE_NONE;
01392                 return 0;
01393         }
01394 
01395         // WEP
01396         if ((encryption & WLANCOND_ENCRYPT_METHOD_MASK) == WLANCOND_WEP) {
01397                 DLOG_DEBUG("WEP enabled");
01398                 wlan_status.pairwise_cipher = CIPHER_SUITE_WEP40;
01399                 return 0;
01400         }
01401 
01402         // WPA modes
01403         if ((encryption & WLANCOND_ENCRYPT_METHOD_MASK) == WLANCOND_WPA_PSK ||
01404             (encryption & WLANCOND_ENCRYPT_METHOD_MASK) == WLANCOND_WPA_EAP) {
01405                 if ((encryption & WLANCOND_ENCRYPT_ALG_MASK)
01406                     == WLANCOND_WPA_TKIP) {
01407                         DLOG_DEBUG("TKIP Selected for unicast");
01408                         wlan_status.pairwise_cipher = CIPHER_SUITE_TKIP;
01409                 } else if ((encryption & WLANCOND_ENCRYPT_ALG_MASK) ==
01410                            WLANCOND_WPA_AES) {
01411                         DLOG_DEBUG("AES selected for unicast");
01412                         wlan_status.pairwise_cipher = CIPHER_SUITE_CCMP;
01413                 } else if (wlan_status.allow_all_ciphers == TRUE) {
01414                         if (scan_results->extra_cap_bits & WLANCOND_WEP104) {
01415                                 DLOG_DEBUG("WEP104 selected for unicast");
01416                                 wlan_status.pairwise_cipher = CIPHER_SUITE_WEP104;
01417                         } else if (scan_results->extra_cap_bits & WLANCOND_WEP40) {
01418                                 DLOG_DEBUG("WEP40 selected for unicast");
01419                                 wlan_status.pairwise_cipher = CIPHER_SUITE_WEP40;
01420                         } else {
01421                                 DLOG_ERR("Not supported encryption %08x", encryption);
01422                                 return -1;
01423                         }
01424                 } else {
01425                         DLOG_ERR("Not supported encryption %08x", encryption);
01426                         return -1;
01427                 }
01428 
01429                 if ((encryption & WLANCOND_ENCRYPT_GROUP_ALG_MASK) ==
01430                     WLANCOND_WPA_TKIP_GROUP) {
01431                         DLOG_DEBUG("TKIP Selected for group key");
01432                         wlan_status.group_cipher = CIPHER_SUITE_TKIP;
01433                 } else if ((encryption & WLANCOND_ENCRYPT_GROUP_ALG_MASK) ==
01434                            (unsigned int)WLANCOND_WPA_AES_GROUP) {
01435                         DLOG_DEBUG("AES Selected for group key");
01436                         wlan_status.group_cipher = CIPHER_SUITE_CCMP;
01437 
01438                 } else if (wlan_status.allow_all_ciphers == TRUE) {
01439 
01440                         if (scan_results->extra_cap_bits & WLANCOND_WEP104_GROUP) {
01441                                 DLOG_DEBUG("WEP104 selected for group key");
01442                                 wlan_status.group_cipher = CIPHER_SUITE_WEP104;
01443                         } else if (scan_results->extra_cap_bits & WLANCOND_WEP40_GROUP) {
01444                                 DLOG_DEBUG("WEP40 selected for group key");
01445                                 wlan_status.group_cipher = CIPHER_SUITE_WEP40;
01446                         } else {
01447                                 DLOG_ERR("Not supported encryption %08x", encryption);
01448                                 return -1;
01449                         }
01450                 } else {
01451                         DLOG_ERR("Not supported encryption %08x", encryption);
01452                         return -1;
01453                 }
01454         } else if ((encryption & WLANCOND_ENCRYPT_METHOD_MASK) == 
01455                    WLANCOND_WAPI_PSK ||
01456                    (encryption & WLANCOND_ENCRYPT_METHOD_MASK) == 
01457                    WLANCOND_WAPI_CERT) {
01458                 if ((encryption & WLANCOND_ENCRYPT_ALG_MASK)
01459                     == WLANCOND_WAPI_SMS4) {
01460                         DLOG_DEBUG("SMS4 Selected for unicast");
01461                         wlan_status.pairwise_cipher = CIPHER_SUITE_SMS4;
01462                 } else {
01463                         DLOG_ERR("Not supported encryption %08x", encryption);
01464                         return -1;
01465                 }
01466 
01467                 if ((encryption & WLANCOND_ENCRYPT_GROUP_ALG_MASK) ==
01468                     WLANCOND_WAPI_SMS4_GROUP) {
01469                         DLOG_DEBUG("SMS4 Selected for multicast");
01470                         wlan_status.group_cipher = CIPHER_SUITE_SMS4;
01471                 } else {
01472                         DLOG_ERR("Not supported encryption %08x", encryption);
01473                         return -1;
01474                 }
01475         }       
01476 
01477         return 0;
01478 }
01482 void clean_roam_cache(void)
01483 {
01484         clean_scan_results(&wlan_status.roam_cache);
01485 }
01486 
01490 void clear_wpa_mode(void)
01491 {
01492         update_own_ie(NULL, 0);
01493 
01494         wlan_status.pairwise_cipher = CIPHER_SUITE_NONE;
01495         wlan_status.group_cipher = CIPHER_SUITE_NONE;
01496 
01497         /* Clean PMK cache */
01498         g_slist_foreach(wlan_status.pmk_cache, (GFunc)g_free, NULL);
01499         g_slist_free(wlan_status.pmk_cache);
01500         wlan_status.pmk_cache = NULL;
01501 }
01506 gboolean get_wpa_mode(void)
01507 {
01508         dbus_int32_t encryption = wlan_status.conn.encryption;
01509  
01510         if ((encryption & WLANCOND_ENCRYPT_METHOD_MASK) == WLANCOND_WPA_PSK ||
01511             (encryption & WLANCOND_ENCRYPT_METHOD_MASK) == WLANCOND_WPA_EAP ||
01512             (encryption & WLANCOND_ENCRYPT_METHOD_MASK) == WLANCOND_WAPI_PSK ||
01513             (encryption & WLANCOND_ENCRYPT_METHOD_MASK) == WLANCOND_WAPI_CERT) { 
01514                 return TRUE;
01515         }
01516         return FALSE;
01517 }
01518 
01519 static gint compare_pmk_entry(gconstpointer a, gconstpointer b)
01520 {
01521         const struct pmksa_cache_t *pmk_cache = a;
01522 
01523         return memcmp(pmk_cache->mac, b, ETH_ALEN);
01524 }
01525 
01531 static void add_to_pmksa_cache(unsigned char* pmkid, unsigned char* mac)
01532 {
01533         guint i = 0;
01534         GSList *list;
01535         gboolean entry_found = FALSE;
01536 
01537         for (list = wlan_status.pmk_cache; list != NULL &&
01538                      entry_found == FALSE; list = list->next) {
01539                 struct pmksa_cache_t *pmk_cache = list->data;
01540                 /* First find if we have already the cache entry */
01541                 if (memcmp(pmk_cache->mac, mac, ETH_ALEN) == 0) {
01542                         DLOG_DEBUG("Found old entry: %i", i);
01543                         /* Remove the old entry */
01544                         wlan_status.pmk_cache = g_slist_remove(
01545                                 wlan_status.pmk_cache, pmk_cache);
01546                         g_free(pmk_cache);
01547 
01548                         entry_found = TRUE;
01549                 } else {
01550                         i++;
01551                 }
01552         }
01553 
01554         if (i == PMK_CACHE_SIZE) {
01555                 DLOG_DEBUG("Cache full, remove oldest");
01556                 GSList *last_entry = g_slist_last(wlan_status.pmk_cache);
01557                 wlan_status.pmk_cache = g_slist_remove(wlan_status.pmk_cache,
01558                                                        last_entry->data);
01559                 g_free(last_entry->data);
01560         }
01561         print_mac(WLANCOND_PRIO_LOW, "Adding new entry:", mac);
01562 
01563         struct pmksa_cache_t *new_entry = g_malloc(sizeof(*new_entry));
01564         memcpy(new_entry->mac, mac, ETH_ALEN);
01565         memcpy(new_entry->pmkid, pmkid, WLANCOND_PMKID_LEN);
01566 
01567         wlan_status.pmk_cache = g_slist_prepend(wlan_status.pmk_cache,
01568                                                 new_entry);
01569         return;
01570 }
01571 
01578 gboolean remove_from_pmksa_cache(unsigned char* mac)
01579 {
01580         GSList *list = g_slist_find_custom(wlan_status.pmk_cache, mac,
01581                                            &compare_pmk_entry);
01582         if(!list)
01583                 return FALSE;
01584 
01585         struct pmksa_cache_t *entry = list->data;
01586 
01587         print_mac(WLANCOND_PRIO_MEDIUM, "Removing PMKSA entry for:", mac);
01588 
01589         wlan_status.pmk_cache = g_slist_remove(wlan_status.pmk_cache,
01590                                                entry);
01591 
01592         g_free(entry);
01593 
01594         return TRUE;
01595 }
01596 
01604 int find_pmkid_from_pmk_cache(unsigned char* mac,
01605                               unsigned char **pmkid)
01606 {
01607         GSList *list;
01608         int pmksa_found;
01609 
01610         if (check_pmksa_cache((unsigned char *)wlan_status.own_mac, ETH_ALEN,
01611                               mac, ETH_ALEN,
01612                               wlan_status.conn.authentication_type,
01613                               wlan_status.pairwise_cipher,
01614                               wlan_status.group_cipher,
01615                               &pmksa_found))
01616         {
01617                 DLOG_ERR("Error while querying the pmksa cache status "
01618                          "from eapd");
01619                 return -1;
01620         }
01621 
01622         if(!pmksa_found) {
01623                 DLOG_DEBUG("No cached pmksa found from eapd");
01624 
01625                 remove_from_pmksa_cache(mac);
01626                 *pmkid = NULL;
01627 
01628                 return 0;
01629         }
01630 
01631         list = g_slist_find_custom(wlan_status.pmk_cache, mac, &compare_pmk_entry);
01632         if (list != NULL) {
01633                 struct pmksa_cache_t *pmk_cache = list->data;
01634                 print_mac(WLANCOND_PRIO_MEDIUM, "Found PMKSA entry for:", mac);
01635                 *pmkid = pmk_cache->pmkid;
01636                 return 0;
01637         }
01638 
01639         DLOG_DEBUG("No cached pmksa found from eapd");
01640         *pmkid = NULL;
01641 
01642         return 0;
01643 }
01644 static void rescan_destroy_cb(gpointer data)
01645 {
01646         g_free(data);
01647 }
01653 #define MAX_SCAN_COUNT 3
01654 static gboolean rescan(void* data)
01655 {
01656         int ret;
01657 
01658         if (data) {
01659                 struct scan_cb_data *scan_data = data;
01660                 ret = nl80211_scan(&wlan_status, scan_data->ssid_len, 
01661                                    scan_data->ssid);
01662                 if (ret == -EBUSY) { 
01663                         if (scan_data->count++ >= MAX_SCAN_COUNT) {
01664                                 set_wlan_state(WLAN_NOT_INITIALIZED, 
01665                                                DISCONNECTED_SIGNAL, FALSE);     
01666                         } else {
01667                                 DLOG_ERR("Scan is busy, rescanning later");
01668                                 return TRUE;
01669                         }
01670                 } else if (ret != 0) {
01671                         DLOG_ERR("Scan failed in rescan");
01672                         set_wlan_state(WLAN_NOT_INITIALIZED, 
01673                                        DISCONNECTED_SIGNAL, FALSE);
01674                 }
01675         } else if (get_wlan_state() == WLAN_INITIALIZED_FOR_CONNECTION) {
01676                 scan(wlan_status.scan_ssid, wlan_status.scan_ssid_len, TRUE);
01677         }
01678         wlan_status.rescan_id = 0;
01679 
01680         return FALSE;
01681 }
01688 int scan(gchar *ssid, int ssid_len, gboolean add_timer)
01689 {
01690         int ret;
01691  
01692         if (get_scan_state() == SCAN_ACTIVE)
01693                 return 0;
01694 
01695         set_scan_state(SCAN_ACTIVE);
01696 
01697         ret = nl80211_scan(&wlan_status, ssid_len - 1, ssid);
01698 
01699         if (ret == -EBUSY) {
01700                 DLOG_ERR("Scan is busy, rescanning later");
01701                 struct scan_cb_data *scan_data = g_malloc(
01702                         sizeof(struct scan_cb_data));
01703                 memcpy(scan_data->ssid, ssid, ssid_len);
01704                 scan_data->ssid_len = ssid_len -1;
01705                 scan_data->count = 1;
01706                 wlan_status.rescan_id = g_timeout_add_seconds_full(
01707                         G_PRIORITY_DEFAULT,
01708                         WLANCOND_RESCAN_DELAY,
01709                         rescan,
01710                         scan_data,
01711                         rescan_destroy_cb);
01712         } else if (ret != 0) {
01713                 DLOG_ERR("Scan command failed: %d", ret);
01714                 set_wlan_state(WLAN_NOT_INITIALIZED, DISCONNECTED_SIGNAL, 
01715                                FALSE);
01716                 return -1;
01717         }
01718 
01719         if (ssid != wlan_status.scan_ssid) {
01720                 memset(wlan_status.scan_ssid, 0, sizeof(wlan_status.scan_ssid));
01721                 wlan_status.scan_ssid_len = ssid_len;
01722                 
01723                 if (ssid && ssid_len > 1)
01724                         memcpy(wlan_status.scan_ssid, ssid, ssid_len);
01725         }
01726         if (add_timer == TRUE) {
01727                 wlan_status.scan_id = g_timeout_add_seconds(
01728                         WLANCOND_SCAN_TIMEOUT,
01729                         wlan_scan_cb,
01730                         NULL);
01731         }
01732 
01733         DLOG_INFO("Scan issued");
01734 
01735         return 0;
01736 }
01737 
01738 static void init_conn_params(struct connect_params_t *conn_params)
01739 {
01740         memset(conn_params, 0, sizeof(*conn_params));
01741 }
01742 
01743 static void add_connection_time_filters(void) {
01744 
01745         if (wlan_status.dbus_filters == TRUE)
01746                 return;
01747 
01748         if (!add_icd_listener(get_dbus_connection()))
01749                 DLOG_ERR("Adding icd listener failed");
01750 
01751 #ifdef ACTIVITY_CHECK
01752         if (!add_activity_listener(get_dbus_connection()))
01753                 DLOG_ERR("Adding activity listener failed");
01754 
01755         saved_inactivity = get_activity();
01756 #endif
01757         if (get_wpa_mode() == TRUE)
01758                 if (!add_eap_listener(get_dbus_connection()))
01759                         DLOG_ERR("Adding eap listener failed");
01760 
01761         if (!add_gprs_listener(get_dbus_connection()))
01762                 DLOG_ERR("Adding GPRS listener failed");
01763         
01764         wlan_status.dbus_filters = TRUE;
01765 }
01766 
01774 static int check_connect_arguments(struct connect_params_t *conn, char* ssid,
01775                                    unsigned char** key)
01776 {
01777         guint i;
01778 
01779         if (conn->flags & WLANCOND_DISABLE_POWERSAVE) {
01780                 DLOG_DEBUG("Powersave disabled");
01781                 wlan_status.powersave = WLANCOND_POWER_ON;
01782         } else {
01783                 wlan_status.powersave = WLANCOND_CAM_TIMEOUT;
01784         }
01785 
01786         if (conn->power_level != WLANCOND_TX_POWER10 &&
01787             conn->power_level != WLANCOND_TX_POWER100) {
01788                 DLOG_ERR("Invalid power level");
01789                 return -1;
01790         }
01791 
01792         switch (conn->mode) {
01793         case WLANCOND_ADHOC:
01794         case WLANCOND_INFRA:
01795                 break;
01796         default:
01797                 DLOG_ERR("Operating mode undefined");
01798                 return -1;
01799         }
01800         /* Encryption settings */
01801         guint32 wpa2_mode = conn->encryption & WLANCOND_ENCRYPT_WPA2_MASK;
01802 
01803         DLOG_DEBUG("Encryption setting: %08x", conn->encryption);
01804         
01805         switch (conn->encryption & WLANCOND_ENCRYPT_METHOD_MASK) {
01806         case WLANCOND_OPEN:
01807                 break;
01808         case WLANCOND_WEP:
01809                 wlan_status.conn.wep_try_open_mode_first = TRUE;
01810                 break;
01811         case WLANCOND_WPA_PSK:
01812                 DLOG_DEBUG("%s PSK selected",
01813                            wpa2_mode!=0?"WPA2":"WPA");
01814                 if (wpa2_mode != 0)
01815                         conn->authentication_type = EAP_AUTH_TYPE_WPA2_PSK;
01816                 else
01817                         conn->authentication_type = EAP_AUTH_TYPE_WPA_PSK;
01818                 break;
01819         case WLANCOND_WPA_EAP:
01820                 DLOG_DEBUG("%s EAP selected", wpa2_mode!=0?"WPA2":"WPA");
01821                 if (wpa2_mode != 0)
01822                         conn->authentication_type = EAP_AUTH_TYPE_WPA2_EAP;
01823                 else
01824                         conn->authentication_type = EAP_AUTH_TYPE_WPA_EAP;
01825                 break;
01826         case WLANCOND_WAPI_PSK:
01827                 DLOG_DEBUG("WAPI PSK selected");
01828                 conn->authentication_type = EAP_AUTH_TYPE_WAPI_PSK;
01829                 break;  
01830         case WLANCOND_WAPI_CERT:
01831                 DLOG_DEBUG("WAPI CERT selected");
01832                 conn->authentication_type = EAP_AUTH_TYPE_WAPI_CERT;
01833                 break;
01834         default:
01835                 DLOG_DEBUG("Unsupported encryption mode");
01836                 return -1;
01837         }
01838         if ((conn->encryption & WLANCOND_WPS_MASK) != 0) {
01839                 DLOG_DEBUG("WPS selected");
01840                 conn->authentication_type = EAP_AUTH_TYPE_WFA_SC;
01841         }
01842 
01843         if (!ssid || conn->ssid_len <= 1 ||
01844             conn->ssid_len > WLANCOND_MAX_SSID_SIZE + 1) {
01845                 DLOG_DEBUG("Invalid SSID");
01846                 return -1;
01847         }
01848 
01849         for (i = 0; i < 4; i++) {
01850                 /* Only key lengths 5 and 13 are valid */
01851                 if (conn->key_len[i] == WLANCOND_MIN_KEY_LEN || 
01852                     conn->key_len[i] == WLANCOND_MAX_KEY_LEN) {
01853                         DLOG_DEBUG("Found key %d", i);
01854                         memcpy(&conn->key[i][0], key[i], conn->key_len[i]);
01855                 } else {
01856                         conn->key_len[i] = 0;
01857                 }
01858         }
01859         return 0;
01860 }
01861 
01868 static DBusHandlerResult settings_and_connect_request(
01869         DBusMessage    *message,
01870         DBusConnection *connection) {
01871 
01872         DBusMessage *reply = NULL;
01873         DBusError derror;
01874         struct connect_params_t *conn;
01875         char *ssid;
01876         unsigned char* key[4];
01877         dbus_int32_t old_mode;
01878         int res;
01879         gboolean autoconnect = FALSE;
01880         GSList *scan_results = NULL;            
01881 
01882         dbus_error_init(&derror);
01883 
01884         if (in_flight_mode()) {
01885                 reply = new_dbus_error(message, WLANCOND_ERROR_WLAN_DISABLED);
01886                 send_and_unref(connection, reply);
01887                 return DBUS_HANDLER_RESULT_HANDLED;
01888         }
01889 
01890         conn = &wlan_status.conn;
01891         /* Save previous mode */
01892         old_mode = conn->mode;
01893         init_conn_params(conn);
01894 
01895         if (dbus_message_get_args(
01896                     message, NULL,
01897                     DBUS_TYPE_INT32, &conn->power_level,
01898                     DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &ssid, &conn->ssid_len,
01899                     DBUS_TYPE_INT32, &conn->mode,
01900                     DBUS_TYPE_INT32, &conn->encryption,
01901                     DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &key[0], &conn->key_len[0],
01902                     DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &key[1], &conn->key_len[1],
01903                     DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &key[2], &conn->key_len[2],
01904                     DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &key[3], &conn->key_len[3],
01905                     DBUS_TYPE_INT32, &conn->default_key,
01906                     DBUS_TYPE_UINT32, &conn->adhoc_channel,
01907                     DBUS_TYPE_UINT32, &conn->flags,
01908                     DBUS_TYPE_INVALID) == FALSE)
01909         {
01910                 /* Try without flags */
01911                 if (dbus_message_get_args(
01912                             message, &derror,
01913                             DBUS_TYPE_INT32, &conn->power_level,
01914                             DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &ssid,
01915                             &conn->ssid_len,
01916                             DBUS_TYPE_INT32, &conn->mode,
01917                             DBUS_TYPE_INT32, &conn->encryption,
01918                             DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
01919                             &key[0], &conn->key_len[0],
01920                             DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
01921                             &key[1], &conn->key_len[1],
01922                             DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
01923                             &key[2], &conn->key_len[2],
01924                             DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
01925                             &key[3], &conn->key_len[3],
01926                             DBUS_TYPE_INT32, &conn->default_key,
01927                             DBUS_TYPE_UINT32, &conn->adhoc_channel,
01928                             DBUS_TYPE_INVALID) == FALSE) {
01929                         
01930                         DLOG_ERR("Failed to parse setting_and_connect: %s",
01931                                  derror.message);
01932                         dbus_error_free(&derror);
01933                         goto param_err;
01934                 }
01935         }
01936 
01937         if (check_connect_arguments(conn, ssid, key) < 0)
01938                 goto param_err;
01939 
01940         set_power_state(WLANCOND_POWER_ON);
01941 
01942         /* If we change mode, do it when interface is down.
01943            Also put interface down in WPS mode to clear old
01944            scan results.
01945         */
01946         if (old_mode != conn->mode ||
01947             conn->encryption & WLANCOND_WPS_PUSH_BUTTON) {
01948                 set_wlan_state(WLAN_NOT_INITIALIZED, NO_SIGNAL, FALSE);
01949         }
01950         if (nl80211_set_channel(wlan_status.ifindex, 
01951                                 WLANCOND_INITIAL_CHANNEL) < 0)
01952                 DLOG_ERR("Changing channel failed");
01953 
01954         /* Mode */
01955         if (set_mode(conn->mode) < 0) {
01956                 /* Restore old mode */
01957                 conn->mode = old_mode;
01958                 goto param_err;
01959         }
01960 
01961         if (init_if(socket_open()) < 0) {
01962                 reply = new_dbus_error(message, WLANCOND_ERROR_INIT_FAILED);
01963                 goto param_err;
01964         }
01965 
01966         remove_wlan_if_timer();
01967 
01968         if (set_tx_power(conn->power_level) != TRUE) {
01969                 reply = new_dbus_error(message, WLANCOND_ERROR_IOCTL_FAILED);
01970                 goto param_err;
01971         }
01972         
01973         if (conn->flags & WLANCOND_AUTOCONNECT) {
01974                 DLOG_DEBUG("Autoconnect attempt");
01975                 autoconnect = TRUE;
01976         }
01977 
01978         memcpy(conn->ssid, ssid, conn->ssid_len);
01979 
01980         if (get_wlan_state() == WLAN_CONNECTED ||
01981             get_wlan_state() == WLAN_NO_ADDRESS) {
01982                 DLOG_DEBUG("Disconnecting previous connection");
01983                 mlme_command(wlan_status.conn.bssid, 
01984                              WLANCOND_NL80211_MLME_DISCONNECT, 
01985                              WLANCOND_REASON_LEAVING);
01986         }
01987 
01988         set_scan_state(SCAN_NOT_ACTIVE);
01989         set_wlan_state(WLAN_INITIALIZED_FOR_CONNECTION, NO_SIGNAL, TRUE);
01990 
01991         /* Make a broadcast scan to catch all WPS PBC registrars */
01992         if (conn->encryption & WLANCOND_WPS_PUSH_BUTTON) {
01993                 DLOG_DEBUG("Broadcast scan for WPS");
01994                 if (scan(NULL, 0, TRUE) < 0) {
01995                         goto param_err;
01996                 }
01997         } else {
01998                 /* Try if our own cache has results */
01999                 if ((res = find_connection_and_associate(
02000                              wlan_status.roam_cache,
02001                              FALSE, FALSE, autoconnect)) != 0) {
02002                         
02003                         /* If res == ETOOWEAKAP, all APs were too weak for
02004                            autoconnection, no need to continue */
02005                         if (res == ETOOWEAKAP || res == ESUPPLICANT)
02006                                 goto param_err;
02007                         
02008                         /* Try if mac80211 has cached results */
02009                         DLOG_DEBUG("Checking mac80211 cache...");
02010 
02011                         wlan_status.scan_ssid_len = conn->ssid_len;
02012                         memcpy(wlan_status.scan_ssid, ssid, conn->ssid_len);
02013 
02014                         if (!nl80211_send_get_scan_results(&wlan_status, &scan_results))
02015                                 DLOG_DEBUG("No cached scan results");
02016 
02017                         if ((res = find_connection_and_associate(
02018                                      scan_results, 
02019                                      TRUE, FALSE, autoconnect)) != 0) {
02020                                 
02021                                 /* If res == ETOOWEAKAP, all APs were too weak 
02022                                    for autoconnection, no need to continue */
02023                                 if (res == ETOOWEAKAP || res == ESUPPLICANT)
02024                                         goto param_err;
02025 
02026                                 clean_scan_results(&scan_results);
02027                                 if (scan(conn->ssid, conn->ssid_len, TRUE) < 0)
02028                                         goto param_err;
02029                         }
02030                 }
02031         }
02032 
02033         clean_scan_results(&scan_results);
02034         g_free(connect_name_cache);
02035         connect_name_cache = g_strdup(dbus_message_get_sender(message));
02036 
02037         add_connection_time_filters();
02038 
02039         reply = new_dbus_method_return(message);
02040 
02041         gchar* ifname = wlan_status.ifname;
02042 
02043         append_dbus_args(reply,
02044                         DBUS_TYPE_STRING, &ifname,
02045                         DBUS_TYPE_INVALID);
02046 
02047         send_and_unref(connection, reply);
02048 
02049         return DBUS_HANDLER_RESULT_HANDLED;
02050 
02051 param_err:
02052         clean_scan_results(&scan_results);
02053         if (reply == NULL) {
02054                 DLOG_DEBUG("Parameter error in settings_and_connect");
02055                 reply = new_dbus_error(message, DBUS_ERROR_INVALID_ARGS);
02056         }
02057         send_and_unref(connection, reply);
02058         set_wlan_state(WLAN_NOT_INITIALIZED, DISCONNECTED_SIGNAL, TRUE);
02059 
02060         return DBUS_HANDLER_RESULT_HANDLED;
02061 }
02067 int associate(struct scan_results_t *scan_results)
02068 {
02069         struct connect_params_t *conn = &wlan_status.conn;
02070         gint ret;
02071         
02072         DLOG_INFO("Starting to associate");
02073 
02074         guint connection_timeout = WLANCOND_CONNECT_TIMEOUT;
02075 
02076         if (get_wlan_state() == WLAN_CONNECTED) {
02077                 DLOG_DEBUG("Disconnecting previous connection");
02078                 mlme_command(conn->bssid, WLANCOND_NL80211_MLME_DISCONNECT, 
02079                              WLANCOND_REASON_LEAVING);
02080                 if (get_wpa_mode() == TRUE)
02081                         disassociate_eap();
02082                 set_wlan_state(WLAN_INITIALIZED_FOR_CONNECTION, NO_SIGNAL, 
02083                                TRUE);
02084         }
02085 
02086         if (update_algorithms(conn->encryption, scan_results) < 0) {
02087                 return -1;
02088         }
02089 
02090         if (netlink_send_linkmode(WLANCOND_IF_DORMANT) != 0) {
02091                 DLOG_ERR("Setting oper state to dormant failed");
02092                 // Not fatal we can continue association
02093         }
02094 
02095         memcpy(conn->bssid, scan_results->bssid, ETH_ALEN);
02096         conn->channel = scan_results->channel;
02097 
02098         if (get_wpa_mode() == TRUE) {
02099                 if ((conn->encryption & WLANCOND_ENCRYPT_METHOD_MASK) == WLANCOND_WAPI_PSK ||
02100                    (conn->encryption & WLANCOND_ENCRYPT_METHOD_MASK) == WLANCOND_WAPI_CERT) {
02101                         if ((ret = generate_wapi_ie(conn->encryption, &wlan_status)) < 0) {
02102                                 DLOG_ERR("nl80211 - nl80211_encryption_method failed");
02103                                 return ret;
02104                         }
02105                 }
02106                 else if ((ret = nl80211_encryption_method(conn->encryption, 
02107                                                      &wlan_status)) < 0) {
02108                         DLOG_ERR("nl80211 - nl80211_encryption_method failed");
02109                         return ret;
02110                 }       
02111         }
02112 
02113         if (conn->mode & WLANCOND_ADHOC) {
02114                 if (conn->adhoc_channel != 0 && (conn->mode & WLANCOND_ADHOC)) {
02115                         if (conn->adhoc_channel < WLANCOND_MIN_WLAN_CHANNEL ||
02116                             conn->adhoc_channel > WLANCOND_MAX_WLAN_CHANNEL) {
02117                                 DLOG_ERR("Invalid ad-hoc channel: %d", 
02118                                          conn->adhoc_channel);
02119                                 return -1;
02120                         }
02121                         scan_results->channel = conn->adhoc_channel;
02122                 }
02123         } else {
02124                 if ((conn->encryption & WLANCOND_ENCRYPT_METHOD_MASK) == 
02125                     WLANCOND_WEP)
02126                         connection_timeout = WLANCOND_CONNECT_TIMEOUT/2;
02127                 else
02128                         connection_timeout = WLANCOND_CONNECT_TIMEOUT;
02129         }
02130 
02131         ret = nl80211_connect(scan_results, &wlan_status);      
02132         if (ret) {
02133                 DLOG_ERR("nl80211 - connect returned error");
02134                 return -1;
02135         }
02136 
02137         /* Set association timeout timer */
02138         wlan_connect_timer_id = g_timeout_add_seconds(
02139                 connection_timeout,
02140                 wlan_connect_timer_cb, NULL);
02141 
02142         return 0;
02143 }
02144 
02151 static DBusHandlerResult scan_request(DBusMessage    *message,
02152                                       DBusConnection *connection) {
02153 
02154         DBusMessage *reply = NULL;
02155         DBusMessageIter iter, array_iter;
02156         char *ssid;
02157         gint ssid_len;
02158         const char* sender;
02159         dbus_int32_t power_level;
02160         dbus_int32_t flags;
02161         gint previous_state = 0;
02162 
02163         if (in_flight_mode()) {
02164                 reply = new_dbus_error(message, WLANCOND_ERROR_WLAN_DISABLED);
02165                 send_and_unref(connection, reply);
02166                 return DBUS_HANDLER_RESULT_HANDLED;
02167         }
02168 
02169         sender = dbus_message_get_sender(message);
02170         if (sender == NULL) {
02171                 goto param_err;
02172         }
02173 
02174         DLOG_DEBUG("Got scan request from %s", sender);
02175 
02176         /* Do not scan if we are scanning already or if we are associating */
02177         if (get_scan_state() == SCAN_ACTIVE || wlan_connect_timer_id != 0) {
02178                 reply = new_dbus_error(message, WLANCOND_ERROR_ALREADY_ACTIVE);
02179                 send_and_unref(connection, reply);
02180                 return DBUS_HANDLER_RESULT_HANDLED;
02181         }
02182 
02183         if ((previous_state = init_if(socket_open())) < 0) {
02184                 reply = new_dbus_error(message, WLANCOND_ERROR_INIT_FAILED);
02185                 goto param_err;
02186         }
02187 
02188         if (previous_state == WLAN_NOT_INITIALIZED) {
02189                 set_wlan_state(WLAN_INITIALIZED_FOR_SCAN, NO_SIGNAL, TRUE);
02190         }
02191 
02192         dbus_message_iter_init(message, &iter);
02193 
02194         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_INT32)
02195                 goto param_err;
02196         dbus_message_iter_get_basic(&iter, &power_level);
02197 
02198         dbus_message_iter_next(&iter);
02199 
02200         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
02201                 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_BYTE)
02202                 goto param_err;
02203         dbus_message_iter_recurse(&iter, &array_iter);
02204         dbus_message_iter_get_fixed_array(&array_iter, &ssid, &ssid_len);
02205 
02206         if (ssid_len > WLANCOND_MAX_SSID_SIZE+1)
02207                 goto param_err;
02208 
02209         dbus_message_iter_next(&iter);
02210 
02211         power_down_after_scan = FALSE;
02212 
02213         if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_UINT32) {
02214                 dbus_message_iter_get_basic(&iter, &flags);
02215                 DLOG_DEBUG("Found flags: %08x", flags);
02216 
02217                 if (flags & WLANCOND_NO_DELAYED_SHUTDOWN)
02218                         power_down_after_scan = TRUE;
02219         }
02220 
02221         if (power_level != WLANCOND_TX_POWER10 &&
02222                         power_level != WLANCOND_TX_POWER100) {
02223                 DLOG_ERR("Invalid power level");
02224                 goto param_err;
02225         }
02226 
02227         if (set_tx_power(power_level) != TRUE) {
02228                 reply = new_dbus_error(message, WLANCOND_ERROR_IOCTL_FAILED);
02229                 goto param_err;
02230         }
02231 
02232         if (scan(ssid, ssid_len, TRUE) < 0) {
02233                 reply = new_dbus_error(message, WLANCOND_ERROR_IOCTL_FAILED);
02234                 goto param_err;
02235         }
02236 
02237         g_free(scan_name_cache);
02238         scan_name_cache = g_strdup(sender);
02239 
02240         reply = new_dbus_method_return(message);
02241         send_and_unref(connection, reply);
02242 
02243         return DBUS_HANDLER_RESULT_HANDLED;
02244 
02245 param_err:
02246         if (get_wlan_state() == WLAN_INITIALIZED_FOR_SCAN) {
02247                 set_wlan_state(WLAN_NOT_INITIALIZED, NO_SIGNAL, FALSE);
02248         }
02249         if (reply == NULL) {
02250                 DLOG_DEBUG("Parameter error in scan request");
02251                 reply = new_dbus_error(message, DBUS_ERROR_INVALID_ARGS);
02252         }
02253         send_and_unref(connection, reply);
02254         return DBUS_HANDLER_RESULT_HANDLED;
02255 }
02262 static int network_compare(gconstpointer a, gconstpointer b)
02263 {
02264         const struct scan_results_t *results_a = a;
02265         const struct scan_results_t *results_b = b;
02266 
02267         if (wlan_status.scan_ssid_len > 1) {
02268 
02269                 //DLOG_DEBUG("Scan ssid = %s", scan_ssid);
02270 
02271                 gint a_eq = strncmp(wlan_status.scan_ssid,
02272                                     results_a->ssid, WLANCOND_MAX_SSID_SIZE);
02273                 gint b_eq = strncmp(wlan_status.scan_ssid,
02274                                     results_b->ssid, WLANCOND_MAX_SSID_SIZE);
02275                 // Check if either network match the scan SSID
02276                 if (!a_eq && !b_eq) {
02277                         //DLOG_DEBUG("Both (%s, %s) match scan SSID",
02278                         //results_a->ssid, results_b->ssid);
02279                         return 0;
02280                 }
02281 
02282                 if (!a_eq && b_eq) {
02283                         //DLOG_DEBUG("%s is better than %s",
02284                         //results_a->ssid, results_b->ssid);
02285                         return -1;
02286                 }
02287 
02288                 if (a_eq && !b_eq) {
02289 
02290                         //DLOG_DEBUG("%s is better than %s",
02291                         //results_b->ssid, results_a->ssid);
02292                         return 1;
02293                 }
02294 
02295         }
02296         //DLOG_DEBUG("No scan ssid, returning just RSSI values");
02297 
02298         return (results_a->rssi > results_b->rssi) ?
02299                 -1 : (results_a->rssi < results_b->rssi) ? 1 : 0;
02300 }
02301 
02306 static void add_to_roam_cache(struct scan_results_t *scan_results)
02307 {
02308         GSList *list;
02309         roam_cache_key_t key = { scan_results->bssid, scan_results->channel };
02310         list = g_slist_find_custom(wlan_status.roam_cache, &key,
02311                                    &compare_scan_entry);
02312 
02313         if (list != NULL) {
02314                 struct scan_results_t *roam_cache_entry = list->data;
02315                 print_mac(WLANCOND_PRIO_LOW, "Found old entry for:",
02316                           scan_results->bssid);
02317                 
02318                 /* Remove the old entry */
02319                 wlan_status.roam_cache = g_slist_remove(
02320                                 wlan_status.roam_cache, roam_cache_entry);
02321 
02322                 clean_scan_results_item(roam_cache_entry, NULL);
02323         }
02324 
02325         print_mac(WLANCOND_PRIO_LOW, "New AP to roam cache:",
02326                   scan_results->bssid);
02327 
02328         struct scan_results_t *results_to_list = copy_scan_results(scan_results);
02329         wlan_status.roam_cache = g_slist_prepend(wlan_status.roam_cache,
02330                                                  results_to_list);
02331 
02332         return;
02333 }
02334 
02340 struct scan_results_t* copy_scan_results(struct scan_results_t *results) {
02341         
02342         struct scan_results_t *copy = g_slice_dup(struct scan_results_t, 
02343                                                   results);
02344         copy->wpa_ie = g_memdup(results->wpa_ie, results->wpa_ie_len);
02345         copy->uuid_e = g_memdup(results->uuid_e, MAX_UUID_E_LEN);
02346         
02347         return copy;
02348 }
02349 
02355 gboolean remove_from_roam_cache(roam_cache_key_t* const key)
02356 {
02357         GSList *list;
02358 
02359         list = g_slist_find_custom(wlan_status.roam_cache, key,
02360                                    &compare_scan_entry);
02361 
02362         if (list != NULL) {
02363                 struct scan_results_t *roam_cache_entry = list->data;
02364                 print_mac(WLANCOND_PRIO_LOW, "Found entry to be removed:",
02365                           key->bssid);
02366 
02367                 wlan_status.roam_cache = g_slist_remove(
02368                         wlan_status.roam_cache, roam_cache_entry);
02369 
02370                 clean_scan_results_item(roam_cache_entry, NULL);
02371 
02372                 return TRUE;
02373         }
02374 
02375         return FALSE;
02376 }
02377 
02383 gboolean decrease_signal_in_roam_cache(roam_cache_key_t* const key)
02384 {
02385         GSList *list;
02386 
02387         list = g_slist_find_custom(wlan_status.roam_cache, key,
02388                                    &compare_scan_entry);
02389 
02390         if (list != NULL) {
02391                 struct scan_results_t *roam_cache_entry = list->data;
02392                 print_mac(WLANCOND_PRIO_LOW, "Found entry to be decreased:",
02393                           key->bssid);
02394 
02395                 roam_cache_entry->rssi -= WLANCOND_RSSI_PENALTY;
02396 
02397                 return TRUE;
02398         }
02399 
02400         return FALSE;
02401 }
02408 static int check_group_cipher(guint32 c1, guint32 c2)
02409 {
02410         guint32 m1 = (c1 & WLANCOND_ENCRYPT_GROUP_ALG_MASK);
02411         guint32 m2 = (c2 & WLANCOND_ENCRYPT_GROUP_ALG_MASK);
02412 
02413         if (m1 == m2)
02414                 return 1;
02415         if (m2 == WLANCOND_WPA_TKIP_GROUP && (m1 & WLANCOND_WPA_TKIP_GROUP))
02416                 return 1;
02417         if (m2 == (unsigned int)WLANCOND_WPA_AES_GROUP &&
02418             (m1 & WLANCOND_WPA_AES_GROUP))
02419                 return 1;
02420         if (m2 == WLANCOND_WAPI_SMS4_GROUP && (m1 & WLANCOND_WAPI_SMS4_GROUP))
02421                 return 1;
02422 
02423         DLOG_DEBUG("Group ciphers don't match");
02424 
02425         return -1;
02426 }
02433 static int check_ciphers(guint32 c1, guint32 c2)
02434 {
02435         guint32 u1 = (c1 & WLANCOND_ENCRYPT_ALG_MASK);
02436         guint32 u2 = (c2 & WLANCOND_ENCRYPT_ALG_MASK);
02437 
02438         if (check_group_cipher(c1, c2) < 0) {
02439                 DLOG_DEBUG("Group cipher's don't match");
02440                 return -1;
02441         }
02442 
02443         if (u1 == u2)
02444                 return 1;
02445         if (u2 == WLANCOND_WPA_TKIP && (u1 & WLANCOND_WPA_TKIP))
02446                 return 1;
02447         if (u2 == WLANCOND_WPA_AES && (u1 & WLANCOND_WPA_AES))
02448                 return 1;
02449         if (u2 == WLANCOND_WAPI_SMS4 && (u1 & WLANCOND_WAPI_SMS4))
02450                 return 1;
02451 
02452         DLOG_DEBUG("Unicast ciphers don't match");
02453 
02454         return -1;
02455 }
02456 static gboolean wlan_roam_scan_cb(void* data)
02457 {
02458         wlan_status.roam_scan_id = 0;
02459         struct timeval tv;
02460 
02461         if (wlan_status.signal == WLANCOND_LOW &&
02462             get_wlan_state() == WLAN_CONNECTED) {
02463 
02464                 DLOG_DEBUG("Roam scan timeout, initiating new scan");
02465 
02466                 if (scan(wlan_status.conn.ssid, wlan_status.conn.ssid_len, 
02467                          TRUE) < 0) {
02468                         return FALSE;
02469                 }
02470                 if (gettimeofday(&tv, NULL) >= 0)
02471                         wlan_status.last_scan = tv.tv_sec;
02472         }
02473 
02474         return FALSE;
02475 }
02476 
02481 void schedule_scan(guint seconds) {
02482 
02483         /* Remove old timer */
02484         remove_roam_scan_timer();
02485         wlan_status.roam_scan_id = g_timeout_add_seconds(
02486                 seconds,
02487                 wlan_roam_scan_cb,
02488                 NULL);
02489 }
02490 
02494 static void reschedule_scan(void)
02495 {
02496         /*
02497            If we are active use shortest scan interval, otherwise
02498            use exponential backoff
02499         */
02500         if (get_inactivity_status() == FALSE) {
02501                 wlan_status.roam_scan = WLANCOND_MIN_ROAM_SCAN_INTERVAL;
02502         } else {
02503                 if (wlan_status.roam_scan <= WLANCOND_MIN_ROAM_SCAN_INTERVAL) {
02504                         wlan_status.roam_scan = WLANCOND_MIN_ROAM_SCAN_INTERVAL;
02505                 } else if (wlan_status.roam_scan >=
02506                                 WLANCOND_MAX_ROAM_SCAN_INTERVAL) {
02507                         wlan_status.roam_scan = WLANCOND_MAX_ROAM_SCAN_INTERVAL;
02508                 } else {
02509                         wlan_status.roam_scan = wlan_status.roam_scan * 2;
02510                 }
02511         }
02512 
02513         schedule_scan(wlan_status.roam_scan);
02514 }
02515 
02522 static gboolean check_capabilities(struct scan_results_t *scan_results,
02523                                    struct connect_params_t *conn)
02524 {
02525         // Check mode
02526         if ((scan_results->cap_bits & WLANCOND_MODE_MASK) != (guint32)conn->mode)
02527                 return FALSE;
02528         if ((scan_results->cap_bits & WLANCOND_ENCRYPT_METHOD_MASK) !=
02529             (guint32)(conn->encryption & WLANCOND_ENCRYPT_METHOD_MASK))
02530                 return FALSE;
02531         
02532         if ((scan_results->cap_bits & WLANCOND_ENCRYPT_WPA2_MASK) !=
02533             (guint32)(conn->encryption & WLANCOND_ENCRYPT_WPA2_MASK))
02534                 return FALSE;
02535 
02536         if (check_ciphers(scan_results->cap_bits, conn->encryption) < 0)
02537                 return FALSE;
02538         
02539         return TRUE;
02540 }
02547 static gboolean better_than_current_best(struct scan_results_t *current_best,
02548                                          struct scan_results_t *candidate) {
02549         gint current_best_rssi;
02550         gint candidate_rssi;
02551 
02552         /* 5 GHz APs get WLANCOND_5GHZ_BENEFIT */
02553         if (current_best->channel > 14)
02554                 current_best_rssi = current_best->rssi + WLANCOND_5GHZ_BENEFIT;
02555         else
02556                 current_best_rssi = current_best->rssi;
02557         
02558         if (candidate->channel > 14)
02559                 candidate_rssi = candidate->rssi + WLANCOND_5GHZ_BENEFIT;
02560         else
02561                 candidate_rssi = candidate->rssi;
02562         
02563         if (current_best_rssi > candidate_rssi)
02564                 return FALSE;
02565         
02566         return TRUE;
02567 }
02568 
02576 struct scan_results_t* find_connection(
02577         GSList* ap_list, struct connect_params_t *conn,
02578         gboolean update_roam_cache)
02579 {
02580         GSList *list;
02581         struct scan_results_t *best_connection = NULL;
02582         gint current_rssi = 0;
02583 
02584         /* If update roam cache, clean it first */
02585         if (update_roam_cache == TRUE)
02586                 clean_roam_cache();
02587 
02588         for (list = ap_list; list != NULL; list = list->next) {
02589                 struct scan_results_t *scan_results = list->data;
02590                 if (scan_results->ssid_len == conn->ssid_len &&
02591                     memcmp(scan_results->ssid, conn->ssid,
02592                            scan_results->ssid_len) == 0) {
02593                         print_mac(WLANCOND_PRIO_LOW, "Found AP:",
02594                                   scan_results->bssid);
02595                         
02596                         /* Find the current AP so that we know it's RSSI */
02597                         if (memcmp(scan_results->bssid, wlan_status.conn.bssid,
02598                             ETH_ALEN) == 0 &&
02599                             scan_results->channel == wlan_status.conn.channel) {
02600                                 current_rssi = scan_results->rssi;
02601                                 DLOG_DEBUG("Current AP: %d", current_rssi);
02602                         }
02603 
02604                         if (check_capabilities(scan_results, conn) ==
02605                             FALSE)
02606                                 continue;
02607                         
02608                         if (is_ap_in_black_list(scan_results->bssid) == TRUE) {
02609                                 DLOG_INFO("AP is in black list, discarded");
02610                                 continue;
02611                         }
02612 
02613                         /* At this point we know the connection is good,
02614                            add to the roam cache
02615                          */
02616                         if (update_roam_cache == TRUE) {
02617                                 add_to_roam_cache(scan_results);
02618                         }
02619 
02620                         if (best_connection == NULL ||
02621                             better_than_current_best(best_connection,
02622                                                      scan_results)) {
02623                                 DLOG_DEBUG("Best connection: %d (old %d)",
02624                                            scan_results->rssi,
02625                                            best_connection == NULL ?
02626                                            WLANCOND_MINIMUM_SIGNAL:
02627                                            best_connection->rssi);
02628                                     best_connection = scan_results;
02629                         }
02630                 }
02631         }
02632 
02633         /* Did not find any connection */
02634         if (best_connection == NULL)
02635                 return NULL;
02636 
02637         /* Check if we are already connected but the best connection is not
02638            worth changing
02639          */
02640         if (current_rssi != 0) {
02641                 if (best_connection->rssi < current_rssi +
02642                     WLANCOND_ROAM_THRESHOLD) {
02643                         DLOG_DEBUG("Best connection not good enough");
02644                         return NULL;
02645                 }
02646         }
02647 
02648         /* Check if the signal level is good enough for connection */
02649         if (best_connection->rssi < WLANCOND_MINIMUM_SIGNAL)
02650                 return NULL;
02651 
02652         return best_connection;
02653 }
02659 static dbus_uint32_t find_adhoc_channel(GSList *ap_list) {
02660 
02661         dbus_uint32_t used_channel_list = 0;
02662         dbus_uint32_t selected_channel = 0;
02663         GSList* list;
02664         guint32 i;
02665 
02666         /* Create a map of free channels */
02667         for (list = ap_list; list != NULL; list = list->next) {
02668                 struct scan_results_t *scan_results = list->data;
02669                 used_channel_list |= 1 << scan_results->channel;
02670         }
02671 
02672         for (i = 1; i <= 11; i++) {
02673                 if (!(used_channel_list & (1 << i))) {
02674                         selected_channel = i;
02675                         break;
02676                 }
02677         }
02678 
02679         if (selected_channel == 0) {
02680                 /* No free channel found, choose one randomly from
02681                  * channels 1 - 11. */
02682                 selected_channel = g_random_int_range(1, 12);
02683         }
02684 
02685         //DLOG_DEBUG("Selected adhoc channel: %d", selected_channel);
02686 
02687         return selected_channel;
02688 }
02696 static gboolean check_if_duplicate_entry(GSList *scan_results,
02697                                          GSList *entry) {
02698         
02699         GSList *list;
02700         struct scan_results_t *entry_result = entry->data;
02701         
02702         if (entry_result->uuid_e == NULL)
02703                 return FALSE;
02704 
02705         for (list = scan_results; list && list != entry; list = list->next) {
02706                 struct scan_results_t *result = list->data;     
02707                 if (result->cap_bits & WLANCOND_WPS_PUSH_BUTTON &&
02708                     result->cap_bits & WLANCOND_WPS_CONFIGURED && 
02709                     result->uuid_e && memcmp(result->uuid_e, 
02710                                              entry_result->uuid_e, 
02711                                              MAX_UUID_E_LEN) == 0) {
02712                         print_mac(WLANCOND_PRIO_MEDIUM, 
02713                                   "Found matching previous entry:", 
02714                                   result->bssid);
02715                         return TRUE;
02716                 }       
02717         }
02718         return FALSE;
02719 }       
02725 int find_connection_and_associate(GSList *scan_results,
02726                                   gboolean update_roam_cache,
02727                                   gboolean create_new_adhoc,
02728                                   gboolean autoconnect)
02729 {
02730         struct scan_results_t adhoc;
02731         struct connect_params_t *conn = &wlan_status.conn;
02732         guint wps_pbc_registrars = 0;
02733         GSList* list;
02734 
02735         /* Check for too many registrars in the WPS PBC
02736            method */
02737         if (conn->encryption & WLANCOND_WPS_PUSH_BUTTON) {
02738                 for (list = scan_results; list != NULL; list = list->next) {
02739                         struct scan_results_t *scan_result = list->data;
02740                         
02741                         if (scan_result->cap_bits & WLANCOND_WPS_PUSH_BUTTON
02742                             &&
02743                             scan_result->cap_bits & WLANCOND_WPS_CONFIGURED) 
02744                         {
02745                                 print_mac(WLANCOND_PRIO_MEDIUM, 
02746                                           "Found active PBC session from:", 
02747                                           scan_result->bssid);
02748                                 /* 
02749                                    Check if this is a duplicate of an earlier
02750                                    list entry.
02751                                 */
02752                                 if (check_if_duplicate_entry(scan_results, 
02753                                                              list) == FALSE) {
02754                                         if (++wps_pbc_registrars > 1) {
02755                                                 DLOG_ERR("Too many WPS PBC registrars");
02756                                                 return ETOOMANYREGISTRARS;
02757                                         }
02758                                 }
02759                         }
02760                 }
02761                 /* In case of WPS push button we double check for 
02762                    extra registrars */
02763                 if (wlan_status.retry_count < 1)
02764                         return ENEEDEXTRASCAN;
02765         }
02766 
02767         struct scan_results_t *connection = find_connection(
02768                 scan_results, &wlan_status.conn, update_roam_cache);
02769 
02770         if (connection == NULL && conn->mode == WLANCOND_ADHOC &&
02771             create_new_adhoc == TRUE) {
02772                 DLOG_DEBUG("No existing adhoc connection");
02773                 memset(&adhoc, 0, sizeof(adhoc));
02774                 connection = &adhoc;
02775                 memcpy(connection->ssid, conn->ssid, conn->ssid_len);
02776                 connection->channel = find_adhoc_channel(scan_results);
02777         }
02778 
02779         if (connection) {
02780                 if (autoconnect == TRUE && 
02781                     connection->rssi < WLANCOND_MINIMUM_AUTOCONNECT_RSSI) {
02782                         DLOG_WARN("RSSI too low for autoconnect");
02783                         return ETOOWEAKAP;
02784                 }
02785                 int ret = associate(connection);
02786                 if (ret < 0) {
02787                         memset(wlan_status.conn.bssid, 0, ETH_ALEN);
02788                         wlan_status.conn.channel = 0;
02789                 }
02790                 if (ret == ESUPPLICANT)
02791                         kill_supplicant();
02792                 return ret;
02793         }
02794         return -1;
02795 }
02799 static void registrar_error_signal(void)
02800 {
02801         DBusMessage *registrar_error;
02802 
02803         registrar_error = new_dbus_signal(
02804                 WLANCOND_SIG_PATH,
02805                 WLANCOND_SIG_INTERFACE,
02806                 WLANCOND_REGISTRAR_ERROR_SIG,
02807                 NULL);
02808         
02809         send_and_unref(get_dbus_connection(), registrar_error);
02810 }
02811 
02816 static void connect_from_scan_results(GSList *scan_results)
02817 {
02818         gboolean autoconnect = !!(wlan_status.conn.flags & WLANCOND_AUTOCONNECT);
02819 
02820         int status = find_connection_and_associate(
02821                 scan_results, TRUE, TRUE, autoconnect);
02822 
02823         clean_scan_results(&scan_results);
02824 
02825         if (status == 0)
02826                 return;
02827 
02828         DLOG_DEBUG("Could not find suitable network");
02829 
02830         if (get_wlan_state() == WLAN_INITIALIZED_FOR_CONNECTION) {      
02831                 /* In WPS too many registrars case we send
02832                    different signal
02833                 */
02834                 if (status == ETOOMANYREGISTRARS) {
02835                         set_wlan_state(WLAN_NOT_INITIALIZED,
02836                                        NO_SIGNAL, FALSE);
02837                         registrar_error_signal();
02838                 } else if (status != ETOOWEAKAP && status != ESUPPLICANT &&
02839                            /* Try rescanning if retries left */
02840                            no_connection_and_scan_retries_left()) {
02841                         DLOG_DEBUG("Rescanning");
02842                         wlan_status.rescan_id = g_timeout_add_seconds(
02843                                 WLANCOND_RESCAN_DELAY,
02844                                 rescan,
02845                                 NULL);
02846                 } else {
02847                         set_wlan_state(WLAN_NOT_INITIALIZED,
02848                                        DISCONNECTED_SIGNAL, FALSE);
02849                 }
02850                 return;
02851         }
02852 
02853         /* We are connected but would prefer better connection */
02854         reschedule_scan();
02855 }
02856 
02862 gboolean ask_scan_results(void)
02863 {
02864         GSList *scan_results_save = NULL;
02865         dbus_int32_t number_of_results;
02866 
02867         if (nl80211_send_get_scan_results(&wlan_status, &scan_results_save)) {
02868                 clean_scan_results(&scan_results_save);
02869                 return FALSE;
02870         }
02871         /* First send scan results if someone was expecting them */
02872         if (scan_name_cache != NULL) {  
02873                 
02874                 number_of_results = g_slist_length(scan_results_save);
02875 
02876                 /* Sort the list only if the amount of networks is very high and
02877                    we need to restrict the results */
02878                 if (number_of_results > WLANCOND_MAX_NETWORKS)
02879                         scan_results_save = g_slist_sort(scan_results_save,
02880                                                          network_compare);
02881 
02882                 send_dbus_scan_results(scan_results_save, scan_name_cache,
02883                                        number_of_results);
02884                 g_free(scan_name_cache);
02885                 scan_name_cache = NULL;
02886         }
02887         
02888         /* Try to associate if state is initialized_for_connection or
02889            signal level is low */
02890         if ((get_wlan_state() == WLAN_INITIALIZED_FOR_CONNECTION ||
02891              wlan_status.signal == WLANCOND_LOW) &&
02892             get_scan_state() == SCAN_ACTIVE) {
02893 
02894                 DLOG_DEBUG("Connect from scan");
02895 
02896                 set_scan_state(SCAN_NOT_ACTIVE);
02897 
02898                 connect_from_scan_results(scan_results_save);
02899 
02900                 return TRUE;
02901         }
02902 
02903         set_scan_state(SCAN_NOT_ACTIVE);
02904 
02905         if (get_wlan_state() == WLAN_INITIALIZED_FOR_SCAN &&
02906             power_down_after_scan == TRUE) {
02907                 set_interface_state(socket_open(), CLEAR, IFF_UP);
02908         }
02909 
02910         if (get_wlan_state() == WLAN_INITIALIZED_FOR_SCAN) {
02911                 /* Save scan results temporarily */
02912                 if (wlan_status.roam_cache) {
02913                         clean_roam_cache();
02914                 }
02915                 wlan_status.roam_cache = scan_results_save;
02916                 set_wlan_state(WLAN_NOT_INITIALIZED, NO_SIGNAL, TRUE);
02917         } else {
02918                 clean_scan_results(&scan_results_save);
02919         }
02920 
02921         return TRUE;
02922 }
02923 
02927 void nl80211_scan_ready(void) {
02928         remove_scan_timer();
02929 
02930         if (get_scan_state() == SCAN_ACTIVE) {
02931                 DLOG_INFO("Scan results ready -- scan active");
02932                 if (ask_scan_results() == FALSE) {
02933                         DLOG_ERR("Getting scan results failed");
02934 
02935                         set_wlan_state(WLAN_NOT_INITIALIZED,
02936                                         DISCONNECTED_SIGNAL,
02937                                         FALSE);
02938                 }
02939         } else {
02940                 DLOG_DEBUG("Scan results ready -- "
02941                            "not requested");
02942         }
02943 }
02944 
02951 static DBusHandlerResult disconnect_request(DBusMessage    *message,
02952                 DBusConnection *connection) {
02953         DBusMessage *reply;
02954 
02955         /* Set_wlan_state puts IF down */
02956         set_wlan_state(WLAN_NOT_INITIALIZED, DISCONNECTED_SIGNAL, FALSE);
02957 
02958         reply = new_dbus_method_return(message);
02959         send_and_unref(connection, reply);
02960 
02961         return DBUS_HANDLER_RESULT_HANDLED;
02962 }
02969 static DBusHandlerResult disassociate_request(DBusMessage    *message,
02970                 DBusConnection *connection) {
02971         DBusMessage *reply;
02972 
02973         if (get_wlan_state() != WLAN_CONNECTED &&
02974             get_wlan_state() != WLAN_NO_ADDRESS) {
02975                 DLOG_DEBUG("Not in correct state for disassociation");
02976 
02977                 reply = new_dbus_method_return(message);
02978                 send_and_unref(connection, reply);
02979                 return DBUS_HANDLER_RESULT_HANDLED;
02980         }
02981 
02982         mlme_command(wlan_status.conn.bssid, WLANCOND_NL80211_MLME_DISCONNECT,
02983                      WLANCOND_REASON_LEAVING);
02984 
02985         set_wlan_state(WLAN_INITIALIZED_FOR_CONNECTION, NO_SIGNAL, TRUE);
02986 
02987         DLOG_DEBUG("Disassociated, trying to find a new connection");
02988 
02989         scan(wlan_status.conn.ssid, wlan_status.conn.ssid_len, TRUE);
02990 
02991         reply = new_dbus_method_return(message);
02992         send_and_unref(connection, reply);
02993 
02994         return DBUS_HANDLER_RESULT_HANDLED;
02995 }
03002 static DBusHandlerResult status_request(DBusMessage    *message,
03003                                         DBusConnection *connection) {
03004         DBusMessage *reply = NULL;
03005         dbus_uint32_t sens = 0;
03006         dbus_uint32_t security = 0;
03007         dbus_uint32_t capability = 0;
03008         dbus_uint32_t channel = 0;
03009         GSList *list;
03010         struct scan_results_t *current_conn_ap = NULL;
03011         struct connect_params_t *conn = &wlan_status.conn;
03012         char *essid = conn->ssid;
03013         unsigned char *bssid = conn->bssid;
03014         guint8 power;
03015 
03016         if (get_wlan_state() != WLAN_CONNECTED &&
03017             get_wlan_state() != WLAN_NO_ADDRESS &&
03018             get_mode() != WLANCOND_ADHOC) {
03019                 reply = new_dbus_error(message, WLANCOND_ERROR_IOCTL_FAILED);
03020                 send_and_unref(connection, reply);
03021                 return DBUS_HANDLER_RESULT_HANDLED;
03022         }
03023 
03024         roam_cache_key_t key = { conn->bssid, conn->channel };
03025         list = g_slist_find_custom(wlan_status.roam_cache, &key, 
03026                                    &compare_scan_entry);
03027         if (list == NULL) {     
03028                 if (get_mode() != WLANCOND_ADHOC) {
03029                         DLOG_ERR("nl80211: MAC entry not found");
03030                         reply = new_dbus_error(message, WLANCOND_ERROR_FATAL);
03031                         goto param_err;
03032                 }
03033         } else {
03034                 current_conn_ap = list->data;
03035         }
03036 
03037         /* Link quality i.e. stats */
03038         if (nl80211_get_signal_info(&power, &wlan_status) !=0) {        
03039                 if (get_mode() != WLANCOND_ADHOC) {
03040                         DLOG_ERR("Could not get statistics");
03041                         reply = new_dbus_error(message, 
03042                                                WLANCOND_ERROR_IOCTL_FAILED);
03043                         goto param_err;
03044                 }
03045         } else {
03046                 sens = power - 0x100;
03047         }
03048         
03049         /* Channel */
03050         channel = conn->channel;
03051 
03052         if (channel < WLANCOND_MIN_WLAN_CHANNEL ||
03053             channel > WLANCOND_MAX_WLAN_CHANNEL) {
03054                 channel = 0;
03055                 DLOG_DEBUG("Got invalid channel");
03056         }
03057 
03058         /* Mode (Adhoc/Infra) */
03059         if (conn->mode == WLANCOND_ADHOC) {
03060                 capability |= WLANCOND_ADHOC;
03061         } else if (conn->mode == WLANCOND_INFRA) {
03062                 capability |= WLANCOND_INFRA;
03063         }
03064 
03065         /* encryption status */
03066         security = wlan_status.conn.encryption;
03067 
03068         /* Speed / Rate */
03069         if (current_conn_ap != NULL)
03070                 capability |= current_conn_ap->cap_bits & WLANCOND_RATE_MASK;
03071 
03072         reply = new_dbus_method_return(message);
03073 
03074         gchar* ifname = wlan_status.ifname;
03075 
03076         append_dbus_args(reply,
03077                          DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
03078                          &essid, conn->ssid_len-1,
03079                          DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &bssid, ETH_ALEN,
03080                          DBUS_TYPE_UINT32, &sens,
03081                          DBUS_TYPE_UINT32, &channel,
03082                          DBUS_TYPE_UINT32, &capability,
03083                          DBUS_TYPE_UINT32, &security,
03084                          DBUS_TYPE_STRING, &ifname,
03085                          DBUS_TYPE_INVALID);
03086 
03087         send_and_unref(connection, reply);
03088 
03089         return DBUS_HANDLER_RESULT_HANDLED;
03090 
03091 param_err:      
03092         set_wlan_state(WLAN_NOT_INITIALIZED, DISCONNECTED_SIGNAL, FALSE);
03093 
03094         if (reply == NULL) {
03095                 DLOG_DEBUG("Parameter error in status request");
03096                 reply = new_dbus_error(message, DBUS_ERROR_INVALID_ARGS);
03097         }
03098 
03099         send_and_unref(connection, reply);
03100 
03101         return DBUS_HANDLER_RESULT_HANDLED;
03102 }
03103 
03110 static DBusHandlerResult interface_request(DBusMessage    *message,
03111                 DBusConnection *connection) {
03112         DBusMessage *reply;
03113         gchar* ifname = wlan_status.ifname;
03114 
03115         reply = new_dbus_method_return(message);
03116 
03117         append_dbus_args(reply,
03118                          DBUS_TYPE_STRING, &ifname,
03119                          DBUS_TYPE_INVALID);
03120 
03121         send_and_unref(connection, reply);
03122 
03123         return DBUS_HANDLER_RESULT_HANDLED;
03124 }
03125 
03132 static DBusHandlerResult connection_status_request(
03133                 DBusMessage    *message,
03134                 DBusConnection *connection) {
03135 
03136         DBusMessage *reply;
03137         dbus_bool_t state = FALSE;
03138 
03139         guint state_v = get_wlan_state();
03140 
03141         if (state_v == WLAN_INITIALIZED ||
03142             state_v == WLAN_INITIALIZED_FOR_CONNECTION ||
03143             state_v == WLAN_NO_ADDRESS ||
03144             state_v == WLAN_CONNECTED)
03145                 state = TRUE;
03146 
03147         reply = new_dbus_method_return(message);
03148 
03149         append_dbus_args(reply,
03150                         DBUS_TYPE_BOOLEAN, &state,
03151                         DBUS_TYPE_INVALID);
03152 
03153         send_and_unref(connection, reply);
03154 
03155         return DBUS_HANDLER_RESULT_HANDLED;
03156 }
03163 static DBusHandlerResult set_pmksa_request(DBusMessage    *message,
03164                 DBusConnection *connection) {
03165 
03166         DBusMessage *reply = NULL;
03167         unsigned int pmkid_len, mac_len;
03168         unsigned char *pmkid;
03169         unsigned char *mac;
03170         dbus_uint32_t action;
03171         DBusError derror;
03172 
03173         dbus_error_init(&derror);
03174 
03175         if (dbus_message_get_args(
03176                     message, &derror,
03177                     DBUS_TYPE_UINT32, &action,
03178                     DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &pmkid, &pmkid_len,
03179                     DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &mac, &mac_len,
03180                     DBUS_TYPE_INVALID) == FALSE)
03181         {
03182                 DLOG_ERR("Failed to parse set_pmksa request: %s",
03183                          derror.message);
03184                 dbus_error_free(&derror);
03185                 goto param_err;
03186         }
03187 
03188         if (action != WLANCOND_PMKSA_ADD) {
03189                 DLOG_ERR("Invalid action");
03190                 goto param_err;
03191         }
03192 
03193         if (pmkid == NULL || pmkid_len != WLANCOND_PMKID_LEN || mac == NULL
03194             || mac_len != ETH_ALEN) {
03195                 DLOG_ERR("Invalid arguments");
03196                 goto param_err;
03197         }
03198 
03199         add_to_pmksa_cache(pmkid, mac);
03200 
03201         print_mac(WLANCOND_PRIO_LOW, "PMKSA added successfully for address:",
03202                   mac);
03203 
03204         reply = new_dbus_method_return(message);
03205         send_and_unref(connection, reply);
03206 
03207         return DBUS_HANDLER_RESULT_HANDLED;
03208 
03209 param_err:
03210         if (reply == NULL) {
03211                 DLOG_DEBUG("Parameter error in set_pmksa");
03212                 reply = new_dbus_error(message, DBUS_ERROR_INVALID_ARGS);
03213         }
03214         send_and_unref(connection, reply);
03215         return DBUS_HANDLER_RESULT_HANDLED;
03216 }
03217 
03224 static DBusHandlerResult set_powersave_request(DBusMessage    *message,
03225                 DBusConnection *connection) {
03226 
03227         DBusMessage *reply = NULL;
03228         DBusError error;
03229         dbus_bool_t onoff;
03230 
03231         dbus_error_init(&error);
03232 
03233         if (dbus_message_get_args(message, &error,
03234                                   DBUS_TYPE_BOOLEAN, &onoff,
03235                                   DBUS_TYPE_INVALID) == FALSE) {
03236                 DLOG_ERR("Failed to parse message: %s",
03237                          error.message);
03238                 dbus_error_free(&error);
03239                 
03240                 send_invalid_args(connection, message);
03241                 return DBUS_HANDLER_RESULT_HANDLED;
03242         }
03243 
03244         /* Powersave can be allowed only when we are properly connected
03245            or when the entity asking for connection wants powersave despite of
03246            the state */
03247         if (onoff == TRUE) {
03248                 if (get_wlan_state() == WLAN_NOT_INITIALIZED) {
03249                         set_wlan_state(WLAN_NOT_INITIALIZED,
03250                                        NO_SIGNAL, TRUE);
03251                 } else if (get_wlan_state() != WLAN_NO_ADDRESS ||
03252                            (connect_name_cache != NULL &&
03253                             strcmp(dbus_message_get_sender(message),
03254                                    connect_name_cache) == 0)) {
03255                         if (set_power_state(wlan_status.powersave) == FALSE) {
03256                                 DLOG_ERR("Setting powersave failed");
03257                                 // Not fatal
03258                         }
03259                 }
03260         } else {
03261                 // Go to full power
03262                 if (set_power_state(WLANCOND_POWER_ON) == FALSE) {
03263                         DLOG_ERR("Setting powersave failed");
03264                         // Not fatal
03265                 }
03266         }
03267 
03268         DLOG_DEBUG("WLAN powersave %s", onoff==TRUE?"on":"off");
03269 
03270         reply = new_dbus_method_return(message);
03271         send_and_unref(connection, reply);
03272 
03273         return DBUS_HANDLER_RESULT_HANDLED;
03274 }
03275 
03281 int wpa_ie_push(char* ap_mac_addr) {
03282 
03283         DBusMessage *msg;
03284         DBusMessage *reply;
03285         DBusError derr;
03286         struct connect_params_t *conn = &wlan_status.conn;
03287         dbus_bool_t autoconnect = !!(conn->flags & WLANCOND_AUTOCONNECT);
03288         char *ssid = conn->ssid;
03289         unsigned char *ap_wpa_ie;
03290         guint32 ap_wpa_ie_len;
03291         GSList *list;
03292         
03293         if (conn->authentication_type != EAP_AUTH_TYPE_WFA_SC) {
03294                 if (wlan_status.wpa_ie.ie_len == 0 ||
03295                     conn->ssid_len == 0) {
03296                         DLOG_ERR("WPA IE / SSID not valid");
03297                         return -1;
03298                 }
03299         }       
03300 
03301         roam_cache_key_t key = { (unsigned char*) ap_mac_addr, conn->channel };
03302         list = g_slist_find_custom(wlan_status.roam_cache, &key,
03303                                    &compare_scan_entry);
03304 
03305         if (list == NULL)
03306                 return -1;
03307 
03308         struct scan_results_t *current_ap_entry = list->data;
03309         ap_wpa_ie = current_ap_entry->wpa_ie;
03310         ap_wpa_ie_len = current_ap_entry->wpa_ie_len;
03311 
03312         dbus_error_init(&derr);
03313 
03314         msg = dbus_message_new_method_call(
03315                 EAP_SERVICE,
03316                 EAP_REQ_PATH,
03317                 EAP_REQ_INTERFACE,
03318                 EAP_WPA_IE_PUSH_REQ);
03319         
03320         if (msg == NULL) {
03321                 return -1;
03322         }
03323 
03324         dbus_message_set_auto_start(msg, FALSE);
03325 
03326         append_dbus_args(
03327                 msg,
03328                 DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
03329                 &wlan_status.wpa_ie.ie, wlan_status.wpa_ie.ie_len,
03330                 DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &ap_wpa_ie,
03331                 ap_wpa_ie_len,
03332                 DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
03333                 &ssid, conn->ssid_len -1,
03334                 DBUS_TYPE_UINT32, &wlan_status.pairwise_cipher,
03335                 DBUS_TYPE_UINT32, &wlan_status.group_cipher,
03336                 DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
03337                 &ap_mac_addr, ETH_ALEN,
03338                 DBUS_TYPE_UINT32, &conn->authentication_type,
03339                 DBUS_TYPE_BOOLEAN, &autoconnect,
03340                 DBUS_TYPE_INVALID);
03341         
03342         reply = dbus_connection_send_with_reply_and_block(
03343                 get_dbus_connection(), msg, -1, &derr);
03344 
03345         dbus_message_unref(msg);
03346         
03347         if (dbus_error_is_set(&derr)) {
03348                 DLOG_ERR("EAP returned error: %s", derr.name);
03349 
03350                 dbus_error_free(&derr);
03351                 if (reply)
03352                         dbus_message_unref(reply);
03353                 return -1;
03354         }
03355 
03356         dbus_message_unref(reply);
03357 
03358         return 0;
03359 }
03366 int wpa_mic_failure_event(dbus_bool_t key_type, dbus_bool_t is_fatal) {
03367         DBusMessage *msg;
03368         DBusMessage *reply;
03369         DBusError derr;
03370 
03371         msg = dbus_message_new_method_call(
03372                 EAP_SERVICE,
03373                 EAP_REQ_PATH,
03374                 EAP_REQ_INTERFACE,
03375                 EAP_WPA_MIC_FAILURE_REQ);
03376         
03377         if (msg == NULL) {
03378                 return -1;
03379         }
03380         
03381         append_dbus_args(msg,
03382                          DBUS_TYPE_BOOLEAN, &key_type,
03383                          DBUS_TYPE_BOOLEAN, &is_fatal,
03384                          DBUS_TYPE_INVALID);
03385         
03386         dbus_error_init(&derr);
03387 
03388         reply = dbus_connection_send_with_reply_and_block(
03389                 get_dbus_connection(), msg, -1, &derr);
03390         
03391         dbus_message_unref(msg);
03392 
03393         if (dbus_error_is_set(&derr)) {
03394                 DLOG_ERR("EAP returned error: %s", derr.name);
03395 
03396                 dbus_error_free(&derr);
03397                 if (reply)
03398                         dbus_message_unref(reply);
03399                 return -1;
03400         }
03401 
03402         dbus_message_unref(reply);
03403 
03404         return 0;
03405 }
03412 static void disassociate_cb(DBusPendingCall *pending,
03413                             void *user_data)
03414 {
03415         DBusMessage *reply;
03416         DBusError error;
03417 
03418         dbus_error_init (&error);
03419 
03420         reply = dbus_pending_call_steal_reply(pending);
03421 
03422         if (dbus_set_error_from_message(&error, reply)) {
03423 
03424                 DLOG_DEBUG("EAP disassociate call result:%s", error.name);
03425 
03426                 dbus_error_free(&error);
03427         }
03428 
03429         if (reply)
03430                 dbus_message_unref(reply);
03431         dbus_pending_call_unref(pending);
03432 }
03433 
03438 int disassociate_eap(void) {
03439         DBusMessage *msg;
03440         DBusPendingCall *pending;
03441 
03442         msg = dbus_message_new_method_call(
03443                 EAP_SERVICE,
03444                 EAP_REQ_PATH,
03445                 EAP_REQ_INTERFACE,
03446                 EAP_DISASSOCIATE_REQ);
03447         
03448         if (msg == NULL) {
03449                 return -1;
03450         }
03451 
03452         dbus_message_set_auto_start(msg, FALSE);
03453 
03454         if (!dbus_connection_send_with_reply(get_dbus_connection(),
03455                                              msg, &pending, -1))
03456                 die("Out of memory");
03457 
03458         if (!dbus_pending_call_set_notify (pending, disassociate_cb, NULL,
03459                                            NULL))
03460                 die("Out of memory");
03461 
03462         dbus_message_unref(msg);
03463 
03464         return 0;
03465 }
03466 
03481 int check_pmksa_cache(unsigned char* own_mac, int own_mac_len,
03482                       unsigned char* bssid, int bssid_len,
03483                       uint32_t authentication_type,
03484                       uint32_t pairwise_key_cipher_suite,
03485                       uint32_t group_key_cipher_suite,
03486                       int *status)
03487 {
03488         DBusMessage *msg = NULL;
03489         DBusMessage *reply = NULL;
03490         DBusError error;
03491         dbus_bool_t found;
03492 
03493         dbus_error_init (&error);
03494 
03495         msg = dbus_message_new_method_call(
03496                 EAP_SERVICE,
03497                 EAP_REQ_PATH,
03498                 EAP_REQ_INTERFACE,
03499                 EAP_CHECK_PMKSA_CACHE_REQ);
03500         
03501         if (msg == NULL)
03502                 return -1;
03503 
03504         dbus_message_set_auto_start(msg, FALSE);
03505         
03506         if (dbus_message_append_args(
03507                     msg,
03508                     DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &own_mac, own_mac_len,
03509                     DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &bssid, bssid_len,
03510                     DBUS_TYPE_UINT32, &authentication_type,
03511                     DBUS_TYPE_UINT32, &pairwise_key_cipher_suite,
03512                     DBUS_TYPE_UINT32, &group_key_cipher_suite,
03513                     DBUS_TYPE_INVALID) == FALSE)
03514         {
03515                 DLOG_ERR("Unable to add args to dbus method call.");
03516                 dbus_message_unref(msg);
03517                 return -1;
03518         }
03519         
03520         reply = dbus_connection_send_with_reply_and_block(
03521                 get_dbus_connection(), msg, -1, &error);
03522 
03523         dbus_message_unref(msg);
03524 
03525         if (dbus_error_is_set(&error)) {
03526                 DLOG_ERR("EAP returned error: %s", error.message);
03527                 dbus_error_free(&error);
03528 
03529                 goto error;
03530         }
03531 
03532         if (!dbus_message_get_args(reply, &error,
03533                                 DBUS_TYPE_BOOLEAN, &found,
03534                                 DBUS_TYPE_INVALID))
03535         {
03536                 DLOG_ERR("Error parsing the return value: %s", error.message);
03537                 if (dbus_error_is_set(&error))
03538                         dbus_error_free(&error);
03539 
03540                 goto error;
03541         }
03542 
03543         dbus_message_unref(reply);
03544 
03545         *status = found;
03546 
03547         return 0;
03548 
03549 error:
03550         if (reply)
03551                 dbus_message_unref(reply);
03552 
03553         return -1;
03554 }
03560 static void write_file(const char* file, guint value) {
03561         char buf[4];
03562         FILE *sysfsfile;
03563 
03564         sysfsfile = fopen(file, "w");
03565         if (sysfsfile == NULL)
03566                 return;
03567         snprintf(buf, 3, "%d", value);
03568         if (fwrite(buf, 3, 1, sysfsfile) != 1) {
03569                 DLOG_ERR("Could not write to: %s", file);
03570         }
03571         fclose(sysfsfile);
03572         return;
03573 }
03578 static void set_scan_params(guint scan_mode) {
03579         static guint current_scan_mode = 0;
03580 
03581         if (current_scan_mode == scan_mode)
03582                 return;
03583         
03584         current_scan_mode = scan_mode;
03585         
03586         if (scan_mode == SCAN_SPLIT) {
03587                 /* Scan size */
03588                 write_file(SCAN_SIZE_FILE, SCAN_SIZE_SPLIT);
03589                 /* Scan delay */
03590                 write_file(SCAN_DELAY_FILE, SCAN_DELAY_SPLIT);
03591         } else {
03592                 /* Scan size */
03593                 write_file(SCAN_SIZE_FILE, SCAN_SIZE_NORMAL);
03594                 /* Scan delay */
03595                 write_file(SCAN_DELAY_FILE, SCAN_DELAY_NORMAL);
03596         }
03597         return;
03598 }
03604 void set_call_type(const char *type)
03605 {
03606         guint previous_call_type;
03607 
03608         if (!type)
03609                 return;
03610         
03611         previous_call_type = wlan_status.call_type;
03612 
03613         wlan_status.call_type &= ~CALL_CELLULAR;
03614         wlan_status.call_type &= ~CALL_VOIP;
03615         
03616         if (!strcmp(type, "none")) {
03617                 set_scan_params(SCAN_NORMAL);           
03618                 DLOG_DEBUG("Call cleared");
03619         } else if (!strcmp(type, "cellular")) {
03620                 wlan_status.call_type |= CALL_CELLULAR;
03621                 set_tx_power(wlan_status.conn.power_level);
03622                 set_scan_params(SCAN_NORMAL);
03623                 DLOG_DEBUG("Reduced power level");
03624         } else {
03625                 wlan_status.call_type |= CALL_VOIP;
03626                 set_scan_params(SCAN_SPLIT);
03627                 DLOG_DEBUG("VOIP call");
03628         }
03629         
03630         /* We get multiple events for the call type so set the power
03631            only once when a call is released.
03632         */
03633         if ((previous_call_type & CALL_CELLULAR) && 
03634             (!strcmp(type, "none") ||
03635              (wlan_status.call_type & CALL_VOIP))) {
03636                 if (wlan_status.conn.power_level) {
03637                         set_tx_power(wlan_status.conn.power_level);
03638                         DLOG_DEBUG("Restored power level");
03639                 }
03640         }
03641         if (can_adjust_psm())
03642                 set_power_state(wlan_status.powersave);
03643 }
03651 int context_parser(DBusMessageIter *actit)
03652 {
03653         DBusMessageIter  cmdit;
03654         DBusMessageIter  argit;
03655         DBusMessageIter  valit;
03656         char            *argname;
03657         char            *argval;
03658         char            *variable;
03659         char            *value;
03660 
03661         do {
03662                 variable = value = NULL;
03663                 
03664                 dbus_message_iter_recurse(actit, &cmdit);
03665 
03666                 do {
03667                         if (dbus_message_iter_get_arg_type(&cmdit) !=
03668                             DBUS_TYPE_STRUCT)
03669                                 return FALSE;
03670 
03671                         dbus_message_iter_recurse(&cmdit, &argit);
03672 
03673                         if (dbus_message_iter_get_arg_type(&argit) !=
03674                             DBUS_TYPE_STRING)
03675                                 return FALSE;
03676 
03677                         dbus_message_iter_get_basic(&argit, (void *)&argname);
03678 
03679                         if (!dbus_message_iter_next(&argit))
03680                                 return FALSE;
03681 
03682                         if (dbus_message_iter_get_arg_type(&argit) !=
03683                             DBUS_TYPE_VARIANT)
03684                                 return FALSE;
03685 
03686                         dbus_message_iter_recurse(&argit, &valit);
03687 
03688                         if (dbus_message_iter_get_arg_type(&valit) !=
03689                             DBUS_TYPE_STRING)
03690                                 return FALSE;
03691 
03692                         dbus_message_iter_get_basic(&valit, (void *)&argval);
03693 
03694                         if (!strcmp(argname, "variable")) {
03695                                 variable = argval;
03696                         }
03697                         else if (!strcmp(argname, "value")) {
03698                                 value = argval;
03699                         }
03700 
03701                         if (variable && !strcmp(variable, "call_audio_type"))
03702                                 set_call_type(value);
03703 
03704                 } while (dbus_message_iter_next(&cmdit));
03705 
03706         } while (dbus_message_iter_next(actit));
03707 
03708         return TRUE;
03709 }
03710 
03716 static DBusHandlerResult handle_policy_actions(DBusMessage *msg)
03717 {
03718         dbus_uint32_t    txid;
03719         char            *actname;
03720         DBusMessageIter  msgit;
03721         DBusMessageIter  arrit;
03722         DBusMessageIter  entit;
03723         DBusMessageIter  actit;
03724         int              success = TRUE;
03725 
03726         dbus_message_iter_init(msg, &msgit);
03727 
03728         if (dbus_message_iter_get_arg_type(&msgit) != DBUS_TYPE_UINT32)
03729                 return DBUS_HANDLER_RESULT_HANDLED;
03730 
03731         dbus_message_iter_get_basic(&msgit, (void *)&txid);
03732 
03733         if (!dbus_message_iter_next(&msgit) ||
03734             dbus_message_iter_get_arg_type(&msgit) !=
03735             DBUS_TYPE_ARRAY) {
03736                 success = FALSE;
03737                 goto out;
03738         }
03739 
03740         dbus_message_iter_recurse(&msgit, &arrit);
03741 
03742         do {
03743                 if (dbus_message_iter_get_arg_type(&arrit) !=
03744                     DBUS_TYPE_DICT_ENTRY) {
03745                         success = FALSE;
03746                         continue;
03747                 }
03748 
03749                 dbus_message_iter_recurse(&arrit, &entit);
03750 
03751                 do {
03752                         if (dbus_message_iter_get_arg_type(&entit) !=
03753                             DBUS_TYPE_STRING) {
03754                                 success = FALSE;
03755                                 continue;
03756                         }
03757 
03758                         dbus_message_iter_get_basic(&entit, (void *)&actname);
03759 
03760                         if (!dbus_message_iter_next(&entit) ||
03761                             dbus_message_iter_get_arg_type(&entit)
03762                             != DBUS_TYPE_ARRAY) {
03763                                 success = FALSE;
03764                                 continue;
03765                         }
03766 
03767                         dbus_message_iter_recurse(&entit, &actit);
03768                         
03769                         if (dbus_message_iter_get_arg_type(&actit) !=
03770                             DBUS_TYPE_ARRAY) {
03771                                 success = FALSE;
03772                                 continue;
03773                         }
03774                         
03775                         if (!strcmp(actname, "com.nokia.policy.context"))
03776                                 success &= context_parser(&actit);
03777                         
03778                 } while (dbus_message_iter_next(&entit));
03779                 
03780         } while (dbus_message_iter_next(&arrit));
03781 
03782 out:
03783         if (!success)
03784                 DLOG_DEBUG("Failed to parse the policy actions message.");
03785 
03786         return DBUS_HANDLER_RESULT_HANDLED;
03787 }
03788 
03789 typedef DBusHandlerResult (*handler_func)(DBusMessage *message,
03790                 DBusConnection *connection);
03791 
03792 typedef struct {
03793         const char *interface;
03794         const char *name;
03795         handler_func func;
03796 } method_handler_t;
03797 
03798 static method_handler_t handlers[] = {
03799         { WLANCOND_REQ_INTERFACE, WLANCOND_SETTINGS_AND_CONNECT_REQ,
03800                 settings_and_connect_request},
03801         { WLANCOND_REQ_INTERFACE, WLANCOND_SCAN_REQ, scan_request},
03802         { WLANCOND_REQ_INTERFACE, WLANCOND_STATUS_REQ, status_request},
03803         { WLANCOND_REQ_INTERFACE, WLANCOND_INTERFACE_REQ, interface_request},
03804         { WLANCOND_REQ_INTERFACE, WLANCOND_CONNECTION_STATUS_REQ,
03805                 connection_status_request},
03806         { WLANCOND_REQ_INTERFACE, WLANCOND_SET_PMKSA_REQ, set_pmksa_request},
03807         { WLANCOND_REQ_INTERFACE, WLANCOND_SET_POWERSAVE_REQ,
03808                 set_powersave_request},
03809         { WLANCOND_REQ_INTERFACE, WLANCOND_DISCONNECT_REQ, disconnect_request},
03810         { WLANCOND_REQ_INTERFACE, WLANCOND_DISASSOCIATE_REQ,
03811                 disassociate_request},
03812         { NULL }
03813 };
03814 
03821 DBusHandlerResult wlancond_req_handler(DBusConnection     *connection,
03822                 DBusMessage        *message,
03823                 void               *user_data)
03824 {
03825         method_handler_t *handler;
03826 
03827         DLOG_DEBUG("Received %s.%s",
03828                    dbus_message_get_interface(message),
03829                    dbus_message_get_member(message));
03830 
03831         if (dbus_message_is_signal(message,
03832                                    ICD_DBUS_INTERFACE,
03833                                    ICD_STATUS_CHANGED_SIG))
03834                 return icd_check_signal_dbus(message);
03835         
03836         else if (dbus_message_is_signal(message,
03837                                    CSNET_OPER_IFACE,
03838                                    CSNET_OPERATOR_CHANGED_SIG))
03839                 return csd_check_signal_dbus(message);
03840 
03841         else if (dbus_message_is_signal(message,
03842                                    EAP_SIG_INTERFACE,
03843                                    EAP_AUTH_STATUS_SIG))
03844                 return eap_check_signal_dbus(message);  
03845         else if (dbus_message_is_signal(message, 
03846                                         POLICY_SERVICE_NAME,
03847                                         POLICY_ACTIONS_SIG))
03848                 return handle_policy_actions(message);  
03849         else if (dbus_message_is_signal(message,
03850                                         GPRS_DBUS_INTERFACE,
03851                                         GPRS_DBUS_DATACOUNTERS_SIG)) {
03852                 return gprs_datacounters_signal(message);
03853         }
03854 #ifdef USE_MCE_MODE
03855         else if (dbus_message_is_signal(message,
03856                                    MCE_SIGNAL_IF,
03857                                    MCE_RADIO_STATES_SIG)) {
03858                 return mode_change_dbus(message);
03859         }
03860 #ifdef ACTIVITY_CHECK
03861         else if (dbus_message_is_signal(message,
03862                                    MCE_SIGNAL_IF,
03863                                    MCE_INACTIVITY_SIG)) {
03864                 return activity_check_dbus(message);
03865         }
03866 #endif
03867 #endif
03868         /* The rest should be just method calls */
03869         else if (dbus_message_get_type(message) != DBUS_MESSAGE_TYPE_METHOD_CALL) {
03870                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
03871         }
03872         
03873         for (handler = handlers; handler->interface != NULL; handler++) {
03874                 if (dbus_message_is_method_call(message,
03875                                                 handler->interface,
03876                                                 handler->name)) {
03877                         DLOG_DEBUG("Received %s", handler->name);
03878                         return handler->func(message, connection);
03879                 }
03880         }
03881         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
03882 }
03883 
03884 static DBusObjectPathVTable wlancond_req_vtable = {
03885         .message_function    = wlancond_req_handler,
03886         .unregister_function = NULL
03887 };
03888 
03889 
03894 void init_dbus_handlers(DBusConnection *connection) {
03895         dbus_bool_t ret;
03896         ret = dbus_connection_register_object_path(connection,
03897                                                    WLANCOND_REQ_PATH,
03898                                                    &wlancond_req_vtable,
03899                                                    NULL);
03900         if (ret == FALSE)
03901                 DLOG_ERR("dbus_connection_register_object_path failed");
03902 
03903 #ifdef USE_MCE_MODE
03904         if (!add_mode_listener(connection))
03905                 DLOG_ERR("Adding mode listener failed");
03906 #endif
03907         if (!add_csd_listener(connection))
03908                 DLOG_ERR("Adding csd listener failed");
03909 }
03910 
03915 void destroy_dbus_handlers(DBusConnection *connection) {
03916         dbus_connection_unregister_object_path(connection, WLANCOND_REQ_PATH);
03917 }

Generated on Wed Aug 10 2011 16:02:33 for WLAN Connection Daemon by  doxygen 1.7.1