diff --git a/ChangeLog b/ChangeLog index 5e6e9c202..1bf7d0a12 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,26 @@ +2004-10-11 Dan Williams + + * src/NetworkManagerAP.c + - (nm_ap_new, nm_ap_new_from_ap): Don't crash when we don't have + enough RAM to allocate new AP structures, but return NULL instead + + * src/NetworkManagerAPList.[ch] + - (nm_ap_list_is_empty): new function + - (nm_ap_list_combine): new function, combine two access point lists + - (nm_ap_list_copy_keys): new function, copy keys from one list + into another + + * src/NetworkManagerDevice.[ch] + - Rename some functions to be clearer: + nm_device_get_best_ap_frozen -> nm_device_is_best_ap_frozen + nm_device_just_activated -> nm_device_is_just_activated + nm_device_activating -> nm_device_is_activating + nm_device_now_scanning -> nm_device_is_scanning + - Cache the last 4 scans so that the access point list is more stable. + We combine the lastest two scans and use that as the AP list, + and diff that combined list against the combination of the earliest + two cached scans for the WirelessNetworkAppeared/Dissappeared signals + 2004-10-08 John (J5) Palmieri * info-daemon/NWManagerInfo.h diff --git a/src/NetworkManagerAP.c b/src/NetworkManagerAP.c index 4637af6ca..f274d551b 100644 --- a/src/NetworkManagerAP.c +++ b/src/NetworkManagerAP.c @@ -59,7 +59,10 @@ NMAccessPoint * nm_ap_new (void) ap = g_new0 (NMAccessPoint, 1); if (!ap) - syslog( LOG_ERR, "nm_ap_new() could not allocate a new user access point info structure. Not enough memory?" ); + { + syslog (LOG_ERR, "nm_ap_new() could not allocate a new user access point info structure. Not enough memory?"); + return (NULL); + } ap->refcount = 1; @@ -85,7 +88,10 @@ NMAccessPoint * nm_ap_new_from_ap (NMAccessPoint *src_ap) new_ap = nm_ap_new(); if (!new_ap) - syslog( LOG_ERR, "nm_ap_new_from_uap() could not allocate a new user access point info structure. Not enough memory?" ); + { + syslog (LOG_ERR, "nm_ap_new_from_uap() could not allocate a new user access point structure. Not enough memory?"); + return (NULL); + } new_ap->refcount = 1; @@ -399,7 +405,7 @@ void nm_ap_set_trusted (NMAccessPoint *ap, gboolean trusted) * Return the encryption method the user specified for this access point. * */ -NMAPEncMethod nm_ap_get_enc_method (NMAccessPoint *ap) +const NMAPEncMethod nm_ap_get_enc_method (NMAccessPoint *ap) { g_return_val_if_fail (ap != NULL, TRUE); diff --git a/src/NetworkManagerAP.h b/src/NetworkManagerAP.h index 5d9707194..3018648e9 100644 --- a/src/NetworkManagerAP.h +++ b/src/NetworkManagerAP.h @@ -77,6 +77,6 @@ void nm_ap_set_matched (NMAccessPoint *ap, gboolean matched); gboolean nm_ap_get_trusted (NMAccessPoint *ap); void nm_ap_set_trusted (NMAccessPoint *ap, gboolean trusted); -NMAPEncMethod nm_ap_get_enc_method (NMAccessPoint *ap); +const NMAPEncMethod nm_ap_get_enc_method (NMAccessPoint *ap); #endif diff --git a/src/NetworkManagerAPList.c b/src/NetworkManagerAPList.c index 032be1411..f2556b44e 100644 --- a/src/NetworkManagerAPList.c +++ b/src/NetworkManagerAPList.c @@ -116,6 +116,19 @@ void nm_ap_list_unref (NMAccessPointList *list) } +/* + * nm_ap_list_is_empty + * + * Returns whether or not the access point list has any access points + * in it. + * + */ +gboolean nm_ap_list_is_empty (NMAccessPointList *list) +{ + return ((list->ap_list == NULL)); +} + + /* * nm_ap_list_append_ap * @@ -291,6 +304,94 @@ void nm_ap_list_populate (NMAccessPointList *list, NMData *data) } +/* + * nm_ap_list_combine + * + * Combine two access point lists into one. This is a simple OR operation, where each + * unique access point in either list is present in the final, combined list. + * + * NOTE: locks NMAccessPointList arguments + */ +NMAccessPointList * nm_ap_list_combine (NMAccessPointList *list1, NMAccessPointList *list2) +{ + NMAccessPointList *final_list = NULL; + NMAPListIter *iter; + NMAccessPoint *ap; + + final_list = nm_ap_list_new (NETWORK_TYPE_DEVICE); + if (!final_list) + return (NULL); + + /* Add all APs in the first list */ + if (list1 && (iter = nm_ap_list_iter_new (list1))) + { + while ((ap = nm_ap_list_iter_next (iter))) + { + NMAccessPoint *new_ap = nm_ap_new_from_ap (ap); + if (new_ap) + nm_ap_list_append_ap (final_list, new_ap); + } + nm_ap_list_iter_free (iter); + } + + /* Add all APs in the second list not already added from the first */ + if (list2 && (iter = nm_ap_list_iter_new (list2))) + { + while ((ap = nm_ap_list_iter_next (iter))) + { + if (!nm_ap_list_get_ap_by_essid (final_list, nm_ap_get_essid (ap))) + { + NMAccessPoint *new_ap = nm_ap_new_from_ap (ap); + if (new_ap) + nm_ap_list_append_ap (final_list, new_ap); + } + } + nm_ap_list_iter_free (iter); + } + + if (nm_ap_list_is_empty (final_list)) + { + nm_ap_list_unref (final_list); + final_list = NULL; + } + + return (final_list); +} + + +/* + * nm_ap_list_copy_keys + * + * Update the keys and encryption methods in one access point list from + * access points in another list, if the APs in the first list are present + * in the second. + * + */ +void nm_ap_list_copy_keys (NMAccessPointList *dest, NMAccessPointList *source) +{ + NMAPListIter *iter; + NMAccessPoint *dest_ap; + + g_return_if_fail (dest != NULL); + g_return_if_fail (source != NULL); + + if ((iter = nm_ap_list_iter_new (dest))) + { + while ((dest_ap = nm_ap_list_iter_next (iter))) + { + NMAccessPoint *src_ap = NULL; + + if ((src_ap = nm_ap_list_get_ap_by_essid (source, nm_ap_get_essid (dest_ap)))) + { + nm_ap_set_invalid (dest_ap, nm_ap_get_invalid (src_ap)); + nm_ap_set_enc_key_source (dest_ap, nm_ap_get_enc_key_source (src_ap), nm_ap_get_enc_method (src_ap)); + } + } + nm_ap_list_iter_free (iter); + } +} + + /* * nm_ap_list_diff * @@ -327,7 +428,6 @@ void nm_ap_list_diff (NMData *data, NMDevice *dev, NMAccessPointList *old, NMAcc { nm_ap_set_matched (old_ap, TRUE); nm_ap_set_matched (new_ap, TRUE); - nm_ap_set_invalid (new_ap, nm_ap_get_invalid (old_ap)); } else nm_dbus_signal_wireless_network_change (data->dbus_connection, dev, old_ap, TRUE); diff --git a/src/NetworkManagerAPList.h b/src/NetworkManagerAPList.h index ecdc6b085..980728f9e 100644 --- a/src/NetworkManagerAPList.h +++ b/src/NetworkManagerAPList.h @@ -41,6 +41,8 @@ NMAccessPointList * nm_ap_list_new (NMNetworkType type); void nm_ap_list_ref (NMAccessPointList *list); void nm_ap_list_unref (NMAccessPointList *list); +gboolean nm_ap_list_is_empty (NMAccessPointList *list); + void nm_ap_list_append_ap (NMAccessPointList *list, NMAccessPoint *ap); void nm_ap_list_remove_ap (NMAccessPointList *list, NMAccessPoint *ap); @@ -50,6 +52,8 @@ void nm_ap_list_update_network (NMAccessPointList *list, const char *network, void nm_ap_list_populate (NMAccessPointList *list, NMData *data); +void nm_ap_list_copy_keys (NMAccessPointList *dest, NMAccessPointList *source); +NMAccessPointList * nm_ap_list_combine (NMAccessPointList *list1, NMAccessPointList *list2); void nm_ap_list_diff (NMData *data, NMDevice *dev, NMAccessPointList *old, NMAccessPointList *new); gboolean nm_ap_list_lock (NMAccessPointList *list); diff --git a/src/NetworkManagerDbus.c b/src/NetworkManagerDbus.c index 3c9bd9a58..f6f4fd436 100644 --- a/src/NetworkManagerDbus.c +++ b/src/NetworkManagerDbus.c @@ -1254,9 +1254,9 @@ static DBusHandlerResult nm_dbus_nm_message_handler (DBusConnection *connection, { if ((reply_message = dbus_message_new_method_return (message))) { - if (data->active_device && nm_device_activating (data->active_device)) + if (data->active_device && nm_device_is_activating (data->active_device)) { - if (nm_device_is_wireless (data->active_device) && nm_device_now_scanning (data->active_device)) + if (nm_device_is_wireless (data->active_device) && nm_device_is_scanning (data->active_device)) dbus_message_append_args (reply_message, DBUS_TYPE_STRING, "scanning", DBUS_TYPE_INVALID); else dbus_message_append_args (reply_message, DBUS_TYPE_STRING, "connecting", DBUS_TYPE_INVALID); diff --git a/src/NetworkManagerDevice.c b/src/NetworkManagerDevice.c index 918557ade..48ade7308 100644 --- a/src/NetworkManagerDevice.c +++ b/src/NetworkManagerDevice.c @@ -55,7 +55,17 @@ typedef struct NMDeviceWirelessOptions gint8 strength; GMutex *scan_mutex; + /* We keep a couple lists around since wireless cards + * are a bit flakey and don't report the same access + * points every time. The lists get merged and diffed + * to figure out the "real" list, but the latest_ap_list + * is always the most-current scan. + */ NMAccessPointList *ap_list; + NMAccessPointList *cached_ap_list1; + NMAccessPointList *cached_ap_list2; + NMAccessPointList *cached_ap_list3; + NMAccessPointList *cached_ap_list4; NMAccessPoint *best_ap; GMutex *best_ap_mutex; @@ -366,7 +376,16 @@ void nm_device_unref (NMDevice *dev) if (nm_device_is_wireless (dev)) { g_mutex_free (dev->options.wireless.scan_mutex); - nm_ap_list_unref (dev->options.wireless.ap_list); + if (dev->options.wireless.ap_list) + nm_ap_list_unref (dev->options.wireless.ap_list); + if (dev->options.wireless.cached_ap_list1) + nm_ap_list_unref (dev->options.wireless.cached_ap_list1); + if (dev->options.wireless.cached_ap_list2) + nm_ap_list_unref (dev->options.wireless.cached_ap_list2); + if (dev->options.wireless.cached_ap_list3) + nm_ap_list_unref (dev->options.wireless.cached_ap_list3); + if (dev->options.wireless.cached_ap_list4) + nm_ap_list_unref (dev->options.wireless.cached_ap_list4); nm_ap_unref (dev->options.wireless.best_ap); g_mutex_free (dev->options.wireless.best_ap_mutex); } @@ -1463,13 +1482,13 @@ static gpointer nm_device_activation_worker (gpointer user_data) /* - * nm_device_just_activated + * nm_device_is_just_activated * * Check if the device was just activated successfully or not. If so, clear * its just_activated flag and return TRUE. If its not activated yet, return FALSE. * */ -gboolean nm_device_just_activated (NMDevice *dev) +gboolean nm_device_is_just_activated (NMDevice *dev) { g_return_val_if_fail (dev != NULL, FALSE); @@ -1484,12 +1503,12 @@ gboolean nm_device_just_activated (NMDevice *dev) /* - * nm_device_activating + * nm_device_is_activating * * Return whether or not the device is currently activating itself. * */ -gboolean nm_device_activating (NMDevice *dev) +gboolean nm_device_is_activating (NMDevice *dev) { g_return_val_if_fail (dev != NULL, FALSE); @@ -1507,7 +1526,7 @@ void nm_device_activation_cancel (NMDevice *dev) { g_return_if_fail (dev != NULL); - if (nm_device_activating (dev)) + if (nm_device_is_activating (dev)) { syslog (LOG_DEBUG, "nm_device_activation_cancel(%s): cancelling...", nm_device_get_iface (dev)); dev->quit_activation = TRUE; @@ -1517,7 +1536,7 @@ void nm_device_activation_cancel (NMDevice *dev) * The other problem with waiting here is that we hold up dbus traffic * that we should respond to. */ - while (nm_device_activating (dev)) + while (nm_device_is_activating (dev)) g_usleep (G_USEC_PER_SEC / 2); } } @@ -1556,14 +1575,14 @@ gboolean nm_device_deactivate (NMDevice *dev, gboolean just_added) /* - * nm_device_now_scanning + * nm_device_is_scanning * * Returns whether the device is scanning, awaiting an access point to connect to. * Note that this does NOT get set when the device is actually scanning, just * when it is waiting for a valid access point to connect to. * */ -gboolean nm_device_now_scanning (NMDevice *dev) +gboolean nm_device_is_scanning (NMDevice *dev) { g_return_val_if_fail (dev != NULL, FALSE); g_return_val_if_fail (nm_device_is_wireless (dev), FALSE); @@ -1751,7 +1770,7 @@ void nm_device_unfreeze_best_ap (NMDevice *dev) dev->options.wireless.freeze_best_ap = FALSE; } -gboolean nm_device_get_best_ap_frozen (NMDevice *dev) +gboolean nm_device_is_best_ap_frozen (NMDevice *dev) { g_return_val_if_fail (dev != NULL, FALSE); g_return_val_if_fail (nm_device_is_wireless (dev), FALSE); @@ -1832,7 +1851,7 @@ void nm_device_update_best_ap (NMDevice *dev) * not, we can "unfreeze" the best ap if its been frozen already). * If it is, we don't change the best ap here. */ - if (nm_device_get_best_ap_frozen (dev)) + if (nm_device_is_best_ap_frozen (dev)) { NMAccessPoint *best_ap = nm_device_get_best_ap (dev); @@ -1929,7 +1948,8 @@ static void nm_device_do_normal_scan (NMDevice *dev) wireless_scan_head scan_results = { NULL, 0 }; wireless_scan *tmp_ap; int err; - NMAccessPointList *old_ap_list = nm_device_ap_list_get (dev); + NMAccessPointList *old_ap_list = NULL; + NMAccessPointList *temp_list; err = iw_scan (iwlib_socket, nm_device_get_iface (dev), WIRELESS_EXT, &scan_results); if ((err == -1) && (errno == ENODATA)) @@ -1947,15 +1967,23 @@ static void nm_device_do_normal_scan (NMDevice *dev) } } - /* Clear out the ap list for this device in preparation for any new ones */ - dev->options.wireless.ap_list = nm_ap_list_new (NETWORK_TYPE_DEVICE); - if (!(dev->options.wireless.ap_list)) + /* New list for current scan data */ + temp_list = nm_ap_list_new (NETWORK_TYPE_DEVICE); + if (!temp_list) { nm_dispose_scan_results (scan_results.result); close (iwlib_socket); return; } + /* Shift all previous cached scan results and dispose of the oldest one. */ + if (dev->options.wireless.cached_ap_list4) + nm_ap_list_unref (dev->options.wireless.cached_ap_list4); + dev->options.wireless.cached_ap_list4 = dev->options.wireless.cached_ap_list3; + dev->options.wireless.cached_ap_list3 = dev->options.wireless.cached_ap_list2; + dev->options.wireless.cached_ap_list2 = dev->options.wireless.cached_ap_list1; + dev->options.wireless.cached_ap_list1 = temp_list; + /* Iterate over scan results and pick a "most" preferred access point. */ tmp_ap = scan_results.result; while (tmp_ap) @@ -1984,24 +2012,39 @@ static void nm_device_do_normal_scan (NMDevice *dev) if (tmp_ap->b.has_freq) nm_ap_set_freq (nm_ap, tmp_ap->b.freq); - /* Merge settings from wireless networks, mainly Keys */ + /* Merge settings from user-approved wireless networks, mainly encryption keys */ if ((list_ap = nm_ap_list_get_ap_by_essid (data->allowed_ap_list, nm_ap_get_essid (nm_ap)))) { nm_ap_set_timestamp (nm_ap, nm_ap_get_timestamp (list_ap)); nm_ap_set_enc_key_source (nm_ap, nm_ap_get_enc_key_source (list_ap), nm_ap_get_enc_method (list_ap)); } /* Add the AP to the device's AP list */ - nm_device_ap_list_add_ap (dev, nm_ap); + nm_ap_list_append_ap (dev->options.wireless.cached_ap_list1, nm_ap); } tmp_ap = tmp_ap->next; } nm_dispose_scan_results (scan_results.result); close (iwlib_socket); + /* Dispose of the old list of available access points the card knows about */ + if (nm_device_ap_list_get (dev)) + nm_ap_list_unref (nm_device_ap_list_get (dev)); + + /* Compose the current access point list for the card based on the past two scans. This + * is to achieve some stability in the list, since cards don't necessarily return the same + * access point list each scan even if you are standing in the same place. + * Once we have the list, copy in any relevant information from our Allowed list. + */ + dev->options.wireless.ap_list = nm_ap_list_combine (dev->options.wireless.cached_ap_list1, dev->options.wireless.cached_ap_list2); + nm_ap_list_copy_keys (nm_device_ap_list_get (dev), dev->app_data->allowed_ap_list); + + /* Generate the "old" list from the 3rd and 4th oldest scans we've done */ + old_ap_list = nm_ap_list_combine (dev->options.wireless.cached_ap_list3, dev->options.wireless.cached_ap_list4); + /* Now do a diff of the old and new networks that we can see, and * signal any changes over dbus, but only if we are active device. */ - if (dev == data->active_device) + if (dev == dev->app_data->active_device) nm_ap_list_diff (dev->app_data, dev, old_ap_list, nm_device_ap_list_get (dev)); if (old_ap_list) nm_ap_list_unref (old_ap_list); diff --git a/src/NetworkManagerDevice.h b/src/NetworkManagerDevice.h index 93626cb2d..585ca8ab3 100644 --- a/src/NetworkManagerDevice.h +++ b/src/NetworkManagerDevice.h @@ -72,7 +72,7 @@ void nm_device_update_best_ap (NMDevice *dev); gboolean nm_device_need_ap_switch (NMDevice *dev); void nm_device_freeze_best_ap (NMDevice *dev); void nm_device_unfreeze_best_ap (NMDevice *dev); -gboolean nm_device_get_best_ap_frozen (NMDevice *dev); +gboolean nm_device_is_best_ap_frozen (NMDevice *dev); char * nm_device_get_path_for_ap (NMDevice *dev, NMAccessPoint *ap); @@ -81,11 +81,11 @@ void nm_device_set_enc_key (NMDevice *dev, const char *key); gboolean nm_device_activation_begin (NMDevice *dev); void nm_device_activation_cancel (NMDevice *dev); -gboolean nm_device_just_activated (NMDevice *dev); -gboolean nm_device_activating (NMDevice *dev); +gboolean nm_device_is_just_activated (NMDevice *dev); +gboolean nm_device_is_activating (NMDevice *dev); gboolean nm_device_deactivate (NMDevice *dev, gboolean just_added); -gboolean nm_device_now_scanning (NMDevice *dev); +gboolean nm_device_is_scanning (NMDevice *dev); void nm_device_set_user_key_for_network (NMDevice *dev, struct NMAccessPointList *invalid_list, unsigned char *network, unsigned char *key, diff --git a/src/NetworkManagerPolicy.c b/src/NetworkManagerPolicy.c index 30754e4a8..c1cdbe449 100644 --- a/src/NetworkManagerPolicy.c +++ b/src/NetworkManagerPolicy.c @@ -277,12 +277,12 @@ gboolean nm_state_modification_monitor (gpointer user_data) } else if (best_dev && nm_device_is_wireless (best_dev)) { - if (!nm_device_activating (best_dev) && nm_device_need_ap_switch (best_dev)) + if (!nm_device_is_activating (best_dev) && nm_device_need_ap_switch (best_dev)) { syslog (LOG_INFO, " SWITCH: need to associate with new access point"); do_switch = TRUE; } - else if (!nm_device_activating (best_dev) && (nm_device_get_ip4_address (best_dev) == 0)) + else if (!nm_device_is_activating (best_dev) && (nm_device_get_ip4_address (best_dev) == 0)) { syslog (LOG_INFO, " SWITCH: need to get an IP address"); do_switch = TRUE; @@ -323,7 +323,7 @@ gboolean nm_state_modification_monitor (gpointer user_data) else syslog (LOG_ERR, "nm_state_modification_monitor() could not get device list mutex"); } - else if (data->active_device && nm_device_just_activated (data->active_device)) + else if (data->active_device && nm_device_is_just_activated (data->active_device)) { nm_dbus_signal_device_status_change (data->dbus_connection, data->active_device, DEVICE_NOW_ACTIVE); syslog (LOG_INFO, "nm_state_modification_monitor() activated device %s", nm_device_get_iface (data->active_device));