diff --git a/ChangeLog b/ChangeLog index 5fd0c7526b..0fad9ca84a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +2004-12-15 Dan Williams + + Patch from Tom Parker + * Add autoip/Link Local Addressing support when we fail to get a DHCP + address + + * Longer pause after setting ESSID on cards that support a larger number + of channels to give the card time to find the right channel + + * Add system hook to restart mDNSResponder (or whatever the local implementation + of Multicast DNS is) when we activate interfaces + 2004-12-15 Dan Williams * Rework the DHCP code again to revert to sending full ethernet frames diff --git a/NetworkManager.h b/NetworkManager.h index f8b0da1850..e51e5efa9c 100644 --- a/NetworkManager.h +++ b/NetworkManager.h @@ -59,7 +59,7 @@ typedef enum NMDeviceType /* * Wireless network types */ -typedef enum +typedef enum NMNetworkType { NETWORK_TYPE_UNKNOWN = 0, NETWORK_TYPE_ALLOWED, @@ -93,6 +93,17 @@ typedef enum NMDriverSupportLevel } NMDriverSupportLevel; +/* + * Wireless network modes + */ +typedef enum NMNetworkMode +{ + NETWORK_MODE_UNKNOWN = 0, + NETWORK_MODE_INFRA, + NETWORK_MODE_ADHOC +} NMNetworkMode; + + /* * Info-daemon specific preference locations */ diff --git a/dhcpcd/Makefile.am b/dhcpcd/Makefile.am index 2d89513d09..ded3a32428 100644 --- a/dhcpcd/Makefile.am +++ b/dhcpcd/Makefile.am @@ -1,9 +1,11 @@ INCLUDES = -I${top_srcdir} -I${top_srcdir}/src -AM_CPPFLAGS = \ - $(NM_CFLAGS) \ - -DBINDIR=\"$(bindir)\" \ - -DDATADIR=\"$(datadir)\" +AM_CPPFLAGS = \ + $(NM_CFLAGS) \ + -DBINDIR=\"$(bindir)\" \ + -DDATADIR=\"$(datadir)\" \ + -DARP_DEBUG \ + -DDEBUG noinst_LIBRARIES = libdhcpc.a diff --git a/dhcpcd/arp.c b/dhcpcd/arp.c index 76248b09db..6bb88c929d 100644 --- a/dhcpcd/arp.c +++ b/dhcpcd/arp.c @@ -28,21 +28,6 @@ #include "client.h" #include "arp.h" -typedef struct arpMessage -{ - struct packed_ether_header ethhdr; - u_short htype; /* hardware type (must be ARPHRD_ETHER) */ - u_short ptype; /* protocol type (must be ETHERTYPE_IP) */ - u_char hlen; /* hardware address length (must be 6) */ - u_char plen; /* protocol address length (must be 4) */ - u_short operation; /* ARP opcode */ - u_char sHaddr[ETH_ALEN]; /* sender's hardware address */ - u_char sInaddr[4]; /* sender's IP address */ - u_char tHaddr[ETH_ALEN]; /* target's hardware address */ - u_char tInaddr[4]; /* target's IP address */ - u_char pad[18]; /* pad for min. Ethernet payload (60 bytes) */ -} __attribute__((packed)) arpMessage; - #define BasicArpLen(A) (sizeof(A) - (sizeof(A.ethhdr) + sizeof(A.pad))) extern int DebugFlag; diff --git a/dhcpcd/arp.h b/dhcpcd/arp.h index 9f6758324f..cb8cd21332 100644 --- a/dhcpcd/arp.h +++ b/dhcpcd/arp.h @@ -23,6 +23,24 @@ #ifndef ARP_H #define ARP_H +#include "client.h" + +typedef struct arpMessage +{ + struct packed_ether_header ethhdr; + u_short htype; /* hardware type (must be ARPHRD_ETHER) */ + u_short ptype; /* protocol type (must be ETHERTYPE_IP) */ + u_char hlen; /* hardware address length (must be 6) */ + u_char plen; /* protocol address length (must be 4) */ + u_short operation; /* ARP opcode */ + u_char sHaddr[ETH_ALEN]; /* sender's hardware address */ + u_char sInaddr[4]; /* sender's IP address */ + u_char tHaddr[ETH_ALEN]; /* target's hardware address */ + u_char tInaddr[4]; /* target's IP address */ + u_char pad[18]; /* pad for min. Ethernet payload (60 bytes) */ +} __attribute__((packed)) arpMessage; + + #ifdef ARPCHECK int arpCheck(const dhcp_interface *iface); #endif diff --git a/dhcpcd/client.c b/dhcpcd/client.c index 8868fe49a5..ba050934ff 100644 --- a/dhcpcd/client.c +++ b/dhcpcd/client.c @@ -48,8 +48,11 @@ #include "arp.h" #include "udpipgen.h" +#ifdef DEBUG int DebugFlag = 1; -#define DEBUG +#else +int DebugFlag = 0; +#endif typedef struct dhcp_response_return { @@ -984,6 +987,8 @@ int dhcp_inform(dhcp_interface *iface) return RET_DHCP_SUCCESS; } +#ifdef DEBUG + /*****************************************************************************/ char *get_dhcp_option_name (int i) { @@ -1080,3 +1085,4 @@ void debug_dump_dhcp_options (struct sockaddr_ll *saddr, dhcpMessage *dhcp_msg, saddr->sll_addr[4], saddr->sll_addr[5]); } +#endif diff --git a/src/Makefile.am b/src/Makefile.am index e2f7cedae2..de7e2db99a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -7,7 +7,8 @@ AM_CPPFLAGS = \ -DDBUS_API_SUBJECT_TO_CHANGE \ -DG_DISABLE_DEPRECATED \ -DBINDIR=\"$(bindir)\" \ - -DDATADIR=\"$(datadir)\" + -DDATADIR=\"$(datadir)\" \ + -DARP_DEBUG bin_PROGRAMS = NetworkManager @@ -34,7 +35,8 @@ NetworkManager_SOURCES = \ NetworkManagerWireless.c \ NetworkManagerWireless.h \ NetworkManagerSystem.c \ - NetworkManagerSystem.h + NetworkManagerSystem.h \ + autoip.c if !WITH_GCRYPT NetworkManager_SOURCES += gnome-keyring-md5.c gnome-keyring-md5.h diff --git a/src/NetworkManagerAP.c b/src/NetworkManagerAP.c index aec48c0d11..47cc1f2628 100644 --- a/src/NetworkManagerAP.c +++ b/src/NetworkManagerAP.c @@ -32,6 +32,7 @@ struct NMAccessPoint guint refcount; char *essid; struct ether_addr *address; + NMNetworkMode mode; gint8 strength; double freq; guint16 rate; @@ -66,6 +67,7 @@ NMAccessPoint * nm_ap_new (void) return (NULL); } + ap->mode = NETWORK_MODE_INFRA; ap->refcount = 1; return (ap); @@ -102,6 +104,7 @@ NMAccessPoint * nm_ap_new_from_ap (NMAccessPoint *src_ap) memcpy (new_addr, src_ap->address, sizeof (struct ether_addr)); new_ap->address = new_addr; } + new_ap->mode = NETWORK_MODE_INFRA; new_ap->strength = src_ap->strength; new_ap->freq = src_ap->freq; new_ap->rate = src_ap->rate; @@ -295,6 +298,25 @@ void nm_ap_set_address (NMAccessPoint *ap, const struct ether_addr * addr) } +/* + * Get/set functions for mode (ie Ad-Hoc, Infrastructure, etc) + * + */ +NMNetworkMode nm_ap_get_mode (NMAccessPoint *ap) +{ + g_return_val_if_fail (ap != NULL, NETWORK_MODE_UNKNOWN); + + return (ap->mode); +} + +void nm_ap_set_mode (NMAccessPoint *ap, const NMNetworkMode mode) +{ + g_return_if_fail (ap != NULL); + + ap->mode = mode; +} + + /* * Get/set functions for strength * @@ -306,7 +328,7 @@ gint8 nm_ap_get_strength (NMAccessPoint *ap) return (ap->strength); } -void nm_ap_set_strength (NMAccessPoint *ap, gint8 strength) +void nm_ap_set_strength (NMAccessPoint *ap, const gint8 strength) { g_return_if_fail (ap != NULL); @@ -325,7 +347,7 @@ double nm_ap_get_freq (NMAccessPoint *ap) return (ap->freq); } -void nm_ap_set_freq (NMAccessPoint *ap, double freq) +void nm_ap_set_freq (NMAccessPoint *ap, const double freq) { g_return_if_fail (ap != NULL); diff --git a/src/NetworkManagerAP.h b/src/NetworkManagerAP.h index 065301ee15..f78595431b 100644 --- a/src/NetworkManagerAP.h +++ b/src/NetworkManagerAP.h @@ -50,6 +50,9 @@ void nm_ap_set_encrypted (NMAccessPoint *ap, gboolean encrypted); struct ether_addr * nm_ap_get_address (NMAccessPoint *ap); void nm_ap_set_address (NMAccessPoint *ap, const struct ether_addr *addr); +NMNetworkMode nm_ap_get_mode (NMAccessPoint *ap); +void nm_ap_set_mode (NMAccessPoint *ap, const NMNetworkMode mode); + gint8 nm_ap_get_strength (NMAccessPoint *ap); void nm_ap_set_strength (NMAccessPoint *ap, gint8 strength); diff --git a/src/NetworkManagerDHCP.c b/src/NetworkManagerDHCP.c index 986efcaf59..07d0970abe 100644 --- a/src/NetworkManagerDHCP.c +++ b/src/NetworkManagerDHCP.c @@ -32,6 +32,8 @@ #include "NetworkManagerSystem.h" #include "../dhcpcd/client.h" +extern gboolean get_autoip (NMDevice *dev, struct in_addr *out_ip); + /* * nm_device_dhcp_configure @@ -55,7 +57,7 @@ static void nm_device_dhcp_configure (NMDevice *dev) nm_system_device_set_ip4_netmask (dev, temp); } - if (dhcp_interface_dhcp_field_exists (dev->dhcp_iface, subnetMask)) + if (dhcp_interface_dhcp_field_exists (dev->dhcp_iface, broadcastAddr)) { memcpy (&temp, dhcp_interface_get_dhcp_field (dev->dhcp_iface, broadcastAddr), dhcp_individual_value_len (broadcastAddr)); nm_system_device_set_ip4_broadcast (dev, temp); @@ -85,8 +87,9 @@ static void nm_device_dhcp_configure (NMDevice *dev) */ int nm_device_dhcp_request (NMDevice *dev) { - dhcp_client_options opts; - int err; + dhcp_client_options opts; + int err; + struct in_addr ip; g_return_val_if_fail (dev != NULL, RET_DHCP_ERROR); @@ -104,16 +107,32 @@ int nm_device_dhcp_request (NMDevice *dev) /* Start off in DHCP INIT state, get a completely new IP address * and settings. */ - if ((err = dhcp_init (dev->dhcp_iface)) == RET_DHCP_BOUND) + err = dhcp_init (dev->dhcp_iface); + switch (err) { - nm_device_dhcp_configure (dev); - nm_device_update_ip4_address (dev); - nm_device_dhcp_setup_timeouts (dev); - } - else - { - dhcp_interface_free (dev->dhcp_iface); - dev->dhcp_iface = NULL; + case RET_DHCP_BOUND: + nm_device_dhcp_configure (dev); + nm_device_update_ip4_address (dev); + nm_device_dhcp_setup_timeouts (dev); + break; + + default: + /* DHCP didn't work, so use Link Local addressing */ + dhcp_interface_free (dev->dhcp_iface); + dev->dhcp_iface = NULL; + if (get_autoip (dev, &ip)) + { + #define LINKLOCAL_BCAST 0xa9feffff + int temp = ip.s_addr; + + nm_system_device_set_ip4_address (dev, temp); + temp = ntohl (0xFFFF0000); + nm_system_device_set_ip4_netmask (dev, temp); + temp = ntohl (LINKLOCAL_BCAST); + nm_system_device_set_ip4_broadcast (dev, temp); + err = RET_DHCP_BOUND; + } + break; } return (err); diff --git a/src/NetworkManagerDevice.c b/src/NetworkManagerDevice.c index 5f05d702f1..73df5a189c 100644 --- a/src/NetworkManagerDevice.c +++ b/src/NetworkManagerDevice.c @@ -238,9 +238,15 @@ NMDevice *nm_device_new (const char *iface, const char *udi, gboolean test_dev, dev->type = nm_device_test_wireless_extensions (dev) ? DEVICE_TYPE_WIRELESS_ETHERNET : DEVICE_TYPE_WIRED_ETHERNET; + /* Have to bring the device up before checking link status and other stuff */ + nm_device_bring_up (dev); + /* Initialize wireless-specific options */ if (nm_device_is_wireless (dev)) { + iwrange range; + int sk; + if (!(dev->options.wireless.scan_mutex = g_mutex_new ())) { g_free (dev->iface); @@ -266,17 +272,23 @@ NMDevice *nm_device_new (const char *iface, const char *udi, gboolean test_dev, dev->options.wireless.supports_wireless_scan = nm_device_supports_wireless_scan (dev); /* Perform an initial wireless scan */ - nm_device_set_mode_managed (dev); + nm_device_set_mode (dev, NETWORK_MODE_INFRA); nm_device_do_wireless_scan (dev); nm_device_update_best_ap (dev); + + dev->options.wireless.num_freqs = 14; /* Default, fake something like 802.11b */ + if ((sk = iw_sockets_open ()) >= 0) + { + if (iw_get_range_info (sk, nm_device_get_iface (dev), &range) >= 0) + dev->options.wireless.num_freqs = range.num_frequency; + close (sk); + } } dev->driver_support_level = nm_get_driver_support_level (dev->app_data->hal_ctx, dev); if (nm_device_get_driver_support_level (dev) != NM_DRIVER_UNSUPPORTED) { - /* Have to bring the device up before checking link status. */ - nm_device_bring_up (dev); nm_device_update_link_active (dev, TRUE); nm_device_update_ip4_address (dev); @@ -360,6 +372,28 @@ int nm_device_open_sock (void) } +/* + * Return the amount of time we should wait for the device + * to get a link, based on the # of frequencies it has to + * scan. + */ +int nm_device_get_association_pause_value (NMDevice *dev) +{ + g_return_val_if_fail (dev != NULL, 5); + g_return_val_if_fail (nm_device_is_wireless (dev), -1); + + /* If the card supports more than 14 channels, we should probably wait + * around 10s so it can scan them all. After we set the ESSID on the card, the card + * has to scan all channels to find our requested AP (which can take a long time + * if it is an A/B/G chipset like the Atheros 5212, for example). + */ + if (dev->options.wireless.num_freqs > 14) + return 10; + else + return 5; +} + + /* * Get/set functions for UDI */ @@ -485,7 +519,9 @@ static gboolean nm_device_wireless_link_active (NMDevice *dev) * seems to be whether the card has a valid access point MAC address. * Is there a better way? */ - iwlib_socket = iw_sockets_open (); + if ((iwlib_socket = iw_sockets_open ()) < 0) + return (FALSE); + if (iw_get_ext (iwlib_socket, nm_device_get_iface (dev), SIOCGIWAP, &wrq) >= 0) { NMAccessPoint *best_ap; @@ -1152,58 +1188,54 @@ gboolean nm_device_is_up (NMDevice *dev) /* - * nm_device_set_mode_managed + * nm_device_set_mode * - * Set managed/infrastructure mode on a device (currently wireless only) + * Set managed/infrastructure/adhoc mode on a device (currently wireless only) * */ -void nm_device_set_mode_managed (NMDevice *dev) +gboolean nm_device_set_mode (NMDevice *dev, const NMNetworkMode mode) { int sk; - struct iwreq wreq; + gboolean success = FALSE; - g_return_if_fail (dev != NULL); - g_return_if_fail (nm_device_is_wireless (dev)); + g_return_val_if_fail (dev != NULL, FALSE); + g_return_val_if_fail (nm_device_is_wireless (dev), FALSE); + g_return_val_if_fail ((mode == NETWORK_MODE_INFRA) || (mode == NETWORK_MODE_ADHOC), FALSE); /* Force the card into Managed/Infrastructure mode */ sk = iw_sockets_open (); if (sk >= 0) { - int err; - wreq.u.mode = IW_MODE_INFRA; - err = iw_set_ext (sk, nm_device_get_iface (dev), SIOCSIWMODE, &wreq); - if (err == -1) - syslog (LOG_ERR, "nm_device_set_mode_managed (%s): error setting card to Infrastructure mode. errno = %d", nm_device_get_iface (dev), errno); + struct iwreq wreq; + int err; + gboolean mode_good = FALSE; + + switch (mode) + { + case NETWORK_MODE_INFRA: + wreq.u.mode = IW_MODE_INFRA; + mode_good = TRUE; + break; + case NETWORK_MODE_ADHOC: + wreq.u.mode = IW_MODE_ADHOC; + mode_good = TRUE; + break; + default: + mode_good = FALSE; + break; + } + if (mode_good) + { + err = iw_set_ext (sk, nm_device_get_iface (dev), SIOCSIWMODE, &wreq); + if (err == 0) + success = TRUE; + else + syslog (LOG_ERR, "nm_device_set_mode_managed (%s): error setting card to Infrastructure mode. errno = %d", nm_device_get_iface (dev), errno); + } close (sk); } -} - -/* - * nm_device_set_mode_adhoc - * - * Set Ad Hoc mode on a device (currently wireless only) - * - */ -void nm_device_set_mode_adhoc (NMDevice *dev) -{ - int sk; - struct iwreq wreq; - - g_return_if_fail (dev != NULL); - g_return_if_fail (nm_device_is_wireless (dev)); - - /* Force the card into Adhoc mode */ - sk = iw_sockets_open (); - if (sk >= 0) - { - int err; - wreq.u.mode = IW_MODE_ADHOC; - err = iw_set_ext (sk, nm_device_get_iface (dev), SIOCSIWMODE, &wreq); - if (err == -1) - syslog (LOG_ERR, "nm_device_set_mode_adhoc (%s): error setting card to Ad Hoc mode. errno = %d", nm_device_get_iface (dev), errno); - close (sk); - } + return (success); } @@ -1273,13 +1305,13 @@ gboolean nm_device_activation_begin (NMDevice *dev) /* - * nm_device_activation_should_cancel + * nm_device_activation_handle_cancel * * Check whether we should stop activation, and if so clean up flags * and other random things. * */ -static gboolean nm_device_activation_should_cancel (NMDevice *dev) +static gboolean nm_device_activation_handle_cancel (NMDevice *dev) { g_return_val_if_fail (dev != NULL, TRUE); @@ -1322,13 +1354,14 @@ static gboolean nm_device_set_wireless_config (NMDevice *dev, NMAccessPoint *ap, g_usleep (G_USEC_PER_SEC * 4); nm_device_bring_up (dev); g_usleep (G_USEC_PER_SEC * 2); - nm_device_set_mode_managed (dev); + nm_device_set_mode (dev, NETWORK_MODE_INFRA); nm_device_set_essid (dev, " "); /* Disable encryption, then re-enable and set correct key on the card * if we are going to encrypt traffic. */ essid = nm_ap_get_essid (ap); + nm_device_set_mode (dev, nm_ap_get_mode (ap)); nm_device_set_enc_key (dev, NULL, NM_DEVICE_AUTH_METHOD_NONE); if (nm_ap_get_encrypted (ap) && nm_ap_get_enc_key_source (ap)) { @@ -1344,8 +1377,11 @@ static gboolean nm_device_set_wireless_config (NMDevice *dev, NMAccessPoint *ap, ((auth == NM_DEVICE_AUTH_METHOD_OPEN_SYSTEM) ? "Open System" : ((auth == NM_DEVICE_AUTH_METHOD_SHARED_KEY) ? "Shared Key" : "unknown"))); - /* Bring the device up and pause to allow card to associate */ - g_usleep (G_USEC_PER_SEC * 5); + /* Bring the device up and pause to allow card to associate. After we set the ESSID + * on the card, the card has to scan all channels to find our requested AP (which can + * take a long time if it is an A/B/G chipset like the Atheros 5212, for example). + */ + g_usleep (G_USEC_PER_SEC * nm_device_get_association_pause_value (dev)); nm_device_update_link_active (dev, FALSE); success = TRUE; @@ -1403,7 +1439,7 @@ static gboolean nm_device_activate_wireless (NMDevice *dev) get_ap: /* If we were told to quit activation, stop the thread and return */ - if (nm_device_activation_should_cancel (dev)) + if (nm_device_activation_handle_cancel (dev)) goto out; /* Get a valid "best" access point we should connect to */ @@ -1414,7 +1450,7 @@ get_ap: g_usleep (G_USEC_PER_SEC * 2); /* If we were told to quit activation, stop the thread and return */ - if (nm_device_activation_should_cancel (dev)) + if (nm_device_activation_handle_cancel (dev)) goto out; } @@ -1465,7 +1501,7 @@ get_ap: syslog (LOG_DEBUG, "nm_device_activation_worker(%s): user key received.", nm_device_get_iface (dev)); /* If we were told to quit activation, stop the thread and return */ - if (nm_device_activation_should_cancel (dev)) + if (nm_device_activation_handle_cancel (dev)) { nm_ap_unref (best_ap); goto out; @@ -1484,7 +1520,7 @@ get_ap: int ip_success = FALSE; /* If we were told to quit activation, stop the thread and return */ - if (nm_device_activation_should_cancel (dev)) + if (nm_device_activation_handle_cancel (dev)) goto out; nm_device_set_wireless_config (dev, best_ap, auth); @@ -1587,6 +1623,9 @@ static gboolean nm_device_activation_configure_ip (NMDevice *dev) success = nm_system_device_setup_static_ip4_config (dev); } + if (success) + nm_system_restart_mdns_responder (); + return (success); } @@ -1620,7 +1659,7 @@ static gpointer nm_device_activation_worker (gpointer user_data) syslog (LOG_DEBUG, "Activation (%s) IP configuration/DHCP returned = %d\n", nm_device_get_iface (dev), success); /* If we were told to quit activation, stop the thread and return */ - if (nm_device_activation_should_cancel (dev)) + if (nm_device_activation_handle_cancel (dev)) goto out; if (!success) @@ -1640,7 +1679,7 @@ static gpointer nm_device_activation_worker (gpointer user_data) syslog (LOG_DEBUG, "Activation (%s) IP configuration/DHCP successful!\n", nm_device_get_iface (dev)); /* If we were told to quit activation, stop the thread and return */ - if (nm_device_activation_should_cancel (dev)) + if (nm_device_activation_handle_cancel (dev)) { syslog (LOG_DEBUG, "Activation (%s) told to cancel. Ending activation...\n", nm_device_get_iface (dev)); goto out; @@ -1714,6 +1753,20 @@ gboolean nm_device_is_activating (NMDevice *dev) } +/* + * nm_device_activation_should_cancel + * + * Return whether or not we've been told to cancel activation + * + */ +gboolean nm_device_activation_should_cancel (NMDevice *dev) +{ + g_return_val_if_fail (dev != NULL, FALSE); + + return (dev->quit_activation); +} + + /* * nm_device_did_activation_fail * @@ -2243,7 +2296,7 @@ gboolean nm_device_wireless_network_exists (NMDevice *dev, const char *network, g_usleep (G_USEC_PER_SEC * 4); /* Force the card into Managed/Infrastructure mode */ - nm_device_set_mode_managed (dev); + nm_device_set_mode (dev, NETWORK_MODE_INFRA); if ((ap = nm_ap_list_get_ap_by_essid (nm_device_ap_list_get (dev), network)) && !nm_ap_get_encrypted (ap)) { @@ -2296,9 +2349,12 @@ gboolean nm_device_wireless_network_exists (NMDevice *dev, const char *network, break; } - /* Bring the device up and pause to allow card to associate */ + /* Pause to allow card to associate. After we set the ESSID on the card, the card + * has to scan all channels to find our requested AP (which can take a long time + * if it is an A/B/G chipset like the Atheros 5212, for example). + */ nm_device_set_essid (dev, network); - g_usleep (G_USEC_PER_SEC * 3); + g_usleep (G_USEC_PER_SEC * nm_device_get_association_pause_value (dev)); nm_device_update_link_active (dev, FALSE); nm_device_get_ap_address (dev, &addr); @@ -2445,9 +2501,10 @@ static void nm_device_do_normal_scan (NMDevice *dev) { /* Card hasn't had time yet to compile full access point list. * Give it some more time and scan again. If that doesn't work - * give up. + * give up. Cards that need to scan more channels (Atheros 5212 + * based cards, for example) need more time here. */ - g_usleep (G_USEC_PER_SEC / 2); + g_usleep ((G_USEC_PER_SEC * nm_device_get_association_pause_value (dev)) / 2); err = iw_scan (iwlib_socket, (char *)nm_device_get_iface (dev), WIRELESS_EXT, &scan_results); if (err == -1) { @@ -2481,7 +2538,13 @@ static void nm_device_do_normal_scan (NMDevice *dev) NMAccessPoint *nm_ap = nm_ap_new (); /* Copy over info from scan to local structure */ - if (!tmp_ap->b.has_essid || (tmp_ap->b.essid && !strlen (tmp_ap->b.essid))) + + /* NOTE: some Cisco products actually broadcast "" as their ESSID when they + * are set to not broadcast it, rather than just broadcasting a blank ESSID. + */ + if ( !tmp_ap->b.has_essid + || (tmp_ap->b.essid && !strlen (tmp_ap->b.essid)) + || (tmp_ap->b.essid && !strcmp (tmp_ap->b.essid, ""))) { nm_ap_set_essid (nm_ap, NULL); have_blank_essids = TRUE; @@ -2497,6 +2560,26 @@ static void nm_device_do_normal_scan (NMDevice *dev) if (tmp_ap->has_ap_addr) nm_ap_set_address (nm_ap, (const struct ether_addr *)(tmp_ap->ap_addr.sa_data)); + if (tmp_ap->b.has_mode) + { + NMNetworkMode mode = NETWORK_MODE_INFRA; + switch (tmp_ap->b.mode) + { + case IW_MODE_INFRA: + mode = NETWORK_MODE_INFRA; + break; + case IW_MODE_ADHOC: + mode = NETWORK_MODE_ADHOC; + break; + default: + mode = NETWORK_MODE_INFRA; + break; + } + nm_ap_set_mode (nm_ap, mode); + } + else + nm_ap_set_mode (nm_ap, NETWORK_MODE_INFRA); + nm_ap_set_strength (nm_ap, nm_wireless_qual_to_percent (dev, &(tmp_ap->stats.qual))); if (tmp_ap->b.has_freq) @@ -2615,7 +2698,6 @@ static void nm_device_do_pseudo_scan (NMDevice *dev) /* Save the MAC address */ nm_device_get_ap_address (dev, &save_ap_addr); - nm_device_set_essid (dev, nm_ap_get_essid (ap)); if (nm_ap_get_enc_key_source (ap)) { char *hashed_key = nm_ap_get_enc_key_hashed (ap); @@ -2624,9 +2706,10 @@ static void nm_device_do_pseudo_scan (NMDevice *dev) } else nm_device_set_enc_key (dev, NULL, NM_DEVICE_AUTH_METHOD_NONE); + nm_device_set_essid (dev, nm_ap_get_essid (ap)); /* Wait a bit for association */ - g_usleep (G_USEC_PER_SEC); + g_usleep (G_USEC_PER_SEC * nm_device_get_association_pause_value (dev)); /* Do we have a valid MAC address? */ nm_device_get_ap_address (dev, &cur_ap_addr); diff --git a/src/NetworkManagerDevice.h b/src/NetworkManagerDevice.h index cb54fbd662..c46eaf3f43 100644 --- a/src/NetworkManagerDevice.h +++ b/src/NetworkManagerDevice.h @@ -79,8 +79,7 @@ void nm_device_do_wireless_scan (NMDevice *dev); gboolean nm_device_wireless_network_exists (NMDevice *dev, const char *network, const char *key, NMEncKeyType key_type, struct ether_addr *addr, gboolean *encrypted); -void nm_device_set_mode_managed (NMDevice *dev); -void nm_device_set_mode_adhoc (NMDevice *dev); +gboolean nm_device_set_mode (NMDevice *dev, const NMNetworkMode mode); gint8 nm_device_get_signal_strength (NMDevice *dev); void nm_device_update_signal_strength (NMDevice *dev); @@ -104,6 +103,7 @@ void nm_device_set_enc_key (NMDevice *dev, const char *key, NMDeviceAuthMeth gboolean nm_device_activation_begin (NMDevice *dev); void nm_device_activation_cancel (NMDevice *dev); +gboolean nm_device_activation_should_cancel (NMDevice *dev); gboolean nm_device_is_just_activated (NMDevice *dev); gboolean nm_device_is_activating (NMDevice *dev); gboolean nm_device_did_activation_fail (NMDevice *dev); diff --git a/src/NetworkManagerDevicePrivate.h b/src/NetworkManagerDevicePrivate.h index 2ad22ff62b..c7288b88b5 100644 --- a/src/NetworkManagerDevicePrivate.h +++ b/src/NetworkManagerDevicePrivate.h @@ -42,6 +42,7 @@ typedef struct NMDeviceWirelessOptions guint8 noise; gint8 strength; gint8 invalid_strength_counter; + gint8 num_freqs; GMutex *scan_mutex; /* We keep a couple lists around since wireless cards diff --git a/src/NetworkManagerSystem.c b/src/NetworkManagerSystem.c index 88d216b449..5c94363ef5 100644 --- a/src/NetworkManagerSystem.c +++ b/src/NetworkManagerSystem.c @@ -112,7 +112,7 @@ gboolean nm_system_device_set_ip4_netmask (NMDevice *dev, int ip4_netmask) p->sin_family = AF_INET; p->sin_addr.s_addr = ip4_netmask; if (ioctl (sk, SIOCSIFNETMASK, &ifr) == -1) - syslog (LOG_ERR,"nm_system_device_set_ip4_netmask (%s): failed to set IPv4 netmask!", iface); + syslog (LOG_ERR,"nm_system_device_set_ip4_netmask (%s): failed to set IPv4 netmask! errno = %s", iface, strerror (errno)); else success = TRUE; diff --git a/src/NetworkManagerSystem.h b/src/NetworkManagerSystem.h index 2e0930d45e..836139b28e 100644 --- a/src/NetworkManagerSystem.h +++ b/src/NetworkManagerSystem.h @@ -43,6 +43,7 @@ void nm_system_delete_default_route (void); void nm_system_kill_all_dhcp_daemons (void); void nm_system_update_dns (void); void nm_system_load_device_modules (void); +void nm_system_restart_mdns_responder (void); /* Prototyps for system-layer network functions (ie setting IP address, etc) */ gboolean nm_system_device_set_ip4_address (NMDevice *dev, int ip4_address); diff --git a/src/autoip.c b/src/autoip.c new file mode 100644 index 0000000000..983d99dd51 --- /dev/null +++ b/src/autoip.c @@ -0,0 +1,303 @@ +// Based upon http://www.zeroconf.org/AVH-IPv4LL.c +// Merged into NetworkManager by Tom Parker +// Original copyright continues below +// +// ---------------------------------- +// Simple IPv4 Link-Local addressing (see ) +// @(#)llip.c, 1.5, Copyright 2003 by Arthur van Hoff (avh@strangeberry.com) +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// See +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../dhcpcd/arp.h" +#include "NetworkManager.h" +#include "NetworkManagerDevice.h" +#include "NetworkManagerMain.h" + +// Times here are in seconds +#define LINKLOCAL_ADDR 0xa9fe0000 +#define LINKLOCAL_BCAST 0xa9feffff +#define PROBE_NUM 3 +#define PROBE_MIN 1 +#define PROBE_MAX 2 +#define ANNOUNCE_NUM 3 +#define ANNOUNCE_INTERVAL 2 +#define ANNOUNCE_WAIT 2 + +#define FAILURE_TIMEOUT 14 + +// Times here are in seconds +#define ARP_DEFAULT_LEASETIME 100 + +static struct in_addr null_ip = {0}; +static struct ether_addr null_addr = {{0, 0, 0, 0, 0, 0}}; +static struct ether_addr broadcast_addr = {{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}}; + +/** + * Pick a random link local IP address. + */ +static void pick(struct in_addr *ip) +{ + ip->s_addr = htonl (LINKLOCAL_ADDR | ((abs(random()) % 0xFD00) + 0x0100)); +} + +/** + * Send out an ARP packet. + */ +static gboolean arp(int fd, struct sockaddr *saddr, int op, + struct ether_addr *source_addr, struct in_addr source_ip, + struct ether_addr *target_addr, struct in_addr target_ip) +{ + struct arpMessage p; + gboolean success = FALSE; + + memset (&p, 0, sizeof (p)); + + /* ether header */ + p.ethhdr.ether_type = htons (ETHERTYPE_ARP); + memcpy (p.ethhdr.ether_shost, source_addr, ETH_ALEN); + memcpy (p.ethhdr.ether_dhost, &broadcast_addr, ETH_ALEN); + + /* arp request */ + p.htype = htons (ARPHRD_ETHER); + p.ptype = htons (ETHERTYPE_IP); + p.hlen = ETH_ALEN; + p.plen = 4; + p.operation = htons (op); + memcpy (&p.sHaddr, source_addr, ETH_ALEN); + memcpy (&p.sInaddr, &source_ip, sizeof (p.sInaddr)); + memcpy (&p.tHaddr, target_addr, ETH_ALEN); + memcpy (&p.tInaddr, &target_ip, sizeof (p.tInaddr)); + + /* send it */ + if (sendto (fd, &p, sizeof (p), 0, saddr, sizeof (*saddr)) < 0) + syslog (LOG_ERR, "autoip ARP sendto() failed."); + else + success = TRUE; + + return (success); +} + +/*****************************************************************************/ +/* Subtract the `struct timeval' values X and Y, + storing the result in RESULT. + Return 1 if the difference is negative, otherwise 0. */ +static int timeval_subtract (struct timeval *result, struct timeval *x, struct timeval *y) +{ + /* Perform the carry for the later subtraction by updating Y. */ + if (x->tv_usec < y->tv_usec) + { + int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1; + y->tv_usec -= 1000000 * nsec; + y->tv_sec += nsec; + } + if (x->tv_usec - y->tv_usec > 1000000) + { + int nsec = (x->tv_usec - y->tv_usec) / 1000000; + y->tv_usec += 1000000 * nsec; + y->tv_sec -= nsec; + } + + /* Compute the time remaining to wait. + `tv_usec' is certainly positive. */ + result->tv_sec = x->tv_sec - y->tv_sec; + result->tv_usec = x->tv_usec - y->tv_usec; + + /* Return 1 if result is negative. */ + return x->tv_sec < y->tv_sec; +} +/*****************************************************************************/ +/* "timeout" should be the future point in time when we wish to stop + * checking for data on the socket. + */ +static int peekfd (NMDevice *dev, int sk, struct timeval *timeout) +{ + struct timeval diff; + struct timeval now; + + /* Wake up each second to check whether or not we've been told + * to stop with iface->cease and check our timeout. + */ + gettimeofday (&now, NULL); +// syslog (LOG_INFO, "autoip waiting for data, overall timeout = {%ds, %dus}\n", (int)timeout->tv_sec, (int)timeout->tv_usec); + while (timeval_subtract (&diff, timeout, &now) == 0) + { + fd_set fs; + struct timeval wait = {1, 0}; +// syslog (LOG_INFO, "autoip waiting for data, remaining timeout = {%ds, %dus}\n", (int)diff.tv_sec, (int)diff.tv_usec); + + FD_ZERO (&fs); + FD_SET (sk, &fs); + + if (select (sk+1, &fs, NULL, NULL, &wait) == -1) + return RET_DHCP_ERROR; + if (FD_ISSET(sk, &fs)) + return RET_DHCP_SUCCESS; + if (nm_device_activation_should_cancel (dev)) + return RET_DHCP_CEASED; + gettimeofday (&now, NULL); + }; + return RET_DHCP_TIMEOUT; +} + + +gboolean get_autoip (NMDevice *dev, struct in_addr *out_ip) +{ + struct sockaddr saddr; + arpMessage p; + struct ifreq ifr; + struct ether_addr addr; + struct in_addr ip = {0}; + int fd; + int timeout = 0; + int nprobes = 0; + int nannounce = 0; + gboolean success = FALSE; + + g_return_val_if_fail (dev != NULL, FALSE); + g_return_val_if_fail (out_ip != NULL, FALSE); + + out_ip->s_addr = 0; + + /* initialize saddr */ + memset (&saddr, 0, sizeof (saddr)); + strncpy (saddr.sa_data, nm_device_get_iface (dev), sizeof (saddr.sa_data)); + + /* open an ARP socket */ + if ((fd = socket (PF_PACKET, SOCK_PACKET, htons (ETH_P_ARP))) < 0) + { + syslog (LOG_ERR, "%s: Couldn't open network control socket.", nm_device_get_iface (dev)); + goto out; + } + + /* bind to the ARP socket */ + if (bind (fd, &saddr, sizeof (saddr)) < 0) + { + syslog (LOG_ERR, "%s: Couldn't bind to the device.", nm_device_get_iface (dev)); + goto out; + } + + nm_device_get_hw_address (dev, addr.ether_addr_octet); + + /* initialize pseudo random selection of IP addresses */ + srandom ( (addr.ether_addr_octet[ETHER_ADDR_LEN-4] << 24) | + (addr.ether_addr_octet[ETHER_ADDR_LEN-3] << 16) | + (addr.ether_addr_octet[ETHER_ADDR_LEN-2] << 8) | + (addr.ether_addr_octet[ETHER_ADDR_LEN-1] << 0)); + + /* pick an ip address */ + if (ip.s_addr == 0) + pick (&ip); + + while (1) + { + struct timeval timeout; + int err; + + /* Make sure we haven't been told to quit */ + if (nm_device_activation_should_cancel (dev)) + goto out; + + if (nprobes < PROBE_NUM) + { + syslog (LOG_INFO, "autoip: Sending probe #%d for IP address %s.", nprobes, inet_ntoa (ip)); + arp (fd, &saddr, ARPOP_REQUEST, &addr, null_ip, &null_addr, ip); + nprobes++; + gettimeofday (&timeout, NULL); + if (nprobes == PROBE_NUM) + { + /* Link local specifies a different interval between + * the end of probe requests and announce packets. + */ + timeout.tv_sec += ANNOUNCE_WAIT; + } + else + { + /* FIXME: we need to randomize the timeout _between_ MIN and MAX */ + timeout.tv_sec += PROBE_MIN; + timeout.tv_usec += (random () % 200000); + } + } + else if (nannounce < ANNOUNCE_NUM) + { + syslog (LOG_INFO, "autoip: Sending announce #%d for IP address %s.", nannounce, inet_ntoa (ip)); + arp (fd, &saddr, ARPOP_REQUEST, &addr, ip, &addr, ip); + nannounce++; + gettimeofday (&timeout, NULL); + timeout.tv_sec += ANNOUNCE_INTERVAL; + timeout.tv_usec += (random () % 200000); + } + else + { + /* Use our address! */ + memcpy (out_ip, &ip, sizeof (ip)); + success = TRUE; + goto out; + } + + syslog (LOG_INFO, "autoip: Waiting for reply..."); + err = peekfd (dev, fd, &timeout); + if ((err == RET_DHCP_ERROR) || (err == RET_DHCP_CEASED)) + goto out; + + /* There's some data waiting for us */ + if (err == RET_DHCP_SUCCESS) + { + syslog (LOG_INFO, "autoip: Got some data to check for reply packet."); + + /* read ARP packet */ + if (recv (fd, &p, sizeof (p), 0) < 0) + { + syslog (LOG_ERR, "autoip: packet receive failure, ignoring it."); + continue; + } + + #ifdef ARP_DEBUG + syslog (LOG_ERR, "autoip: (%s) recv arp type=%d, op=%d, ", nm_device_get_iface (dev), ntohs(p.ethhdr.ether_type), ntohs(p.operation)); + syslog (LOG_ERR, "source=%s %s,", (char *)(p.sHaddr), p.sInaddr); + syslog (LOG_ERR, "target=%s %s\n", (char *)(p.tHaddr), p.tInaddr); + #endif + + if ( (ntohs (p.ethhdr.ether_type) == ETHERTYPE_ARP) + && (ntohs (p.operation) == ARPOP_REPLY) + && ((uint32_t)(*p.tInaddr) == ip.s_addr) + && (memcmp (&addr, &p.tHaddr, ETH_ALEN) != 0)) + { + #ifdef ARP_DEBUG + syslog(LOG_ERR, "autoip: (%s) ARP conflict for IP address %s.\n", nm_device_get_iface (dev), inet_ntoa(ip)); + #endif + + /* Ok, start all over again */ + pick (&ip); + nprobes = 0; + nannounce = 0; + } + } + } + +out: + if (fd >= 0) + close (fd); + return (success); +} diff --git a/src/backends/NetworkManagerDebian.c b/src/backends/NetworkManagerDebian.c index 8029396a9c..4524b1bf39 100644 --- a/src/backends/NetworkManagerDebian.c +++ b/src/backends/NetworkManagerDebian.c @@ -442,3 +442,14 @@ void nm_system_load_device_modules (void) return; } + +/* + * nm_system_restart_mdns_responder + * + * Restart the multicast DNS responder so that it knows about new + * network interfaces and IP addresses. + * + */ +void nm_system_restart_mdns_responder (void) +{ +} diff --git a/src/backends/NetworkManagerGentoo.c b/src/backends/NetworkManagerGentoo.c index 54588e6991..d0cf2ab559 100644 --- a/src/backends/NetworkManagerGentoo.c +++ b/src/backends/NetworkManagerGentoo.c @@ -25,8 +25,13 @@ #include #include +#include #include + +/* get strnlen */ +#define __USE_GNU #include + #include "NetworkManagerSystem.h" #include "NetworkManagerUtils.h" @@ -56,7 +61,7 @@ void nm_system_init (void) gboolean nm_system_device_run_dhcp (NMDevice *dev) { char buf [500]; - char *iface; + const char *iface; int err; g_return_val_if_fail (dev != NULL, FALSE); @@ -168,7 +173,7 @@ gboolean nm_system_device_setup_static_ip4_config (NMDevice *dev) struct in_addr ip_addr, net_addr, broad_addr, gate_addr; int i, err; guint32 prefix = IPBITS; - char *iface; + const char *iface; char *buf; char *addr, *netmask, *broadcast, *gateway; @@ -269,6 +274,20 @@ void nm_system_load_device_modules (void) { } + + +/* + * nm_system_restart_mdns_responder + * + * Restart the multicast DNS responder so that it knows about new + * network interfaces and IP addresses. + * + */ +void nm_system_restart_mdns_responder (void) +{ +} + + /* * nm_system_device_update_config_info * diff --git a/src/backends/NetworkManagerRedHat.c b/src/backends/NetworkManagerRedHat.c index 0a148b95d6..941469b4e7 100644 --- a/src/backends/NetworkManagerRedHat.c +++ b/src/backends/NetworkManagerRedHat.c @@ -328,6 +328,31 @@ void nm_system_load_device_modules (void) } +/* + * nm_system_restart_mdns_responder + * + * Restart the multicast DNS responder so that it knows about new + * network interfaces and IP addresses. + * + */ +void nm_system_restart_mdns_responder (void) +{ + FILE *fp = NULL; + + if ((fp = fopen ("/var/run/mDNSResponder.pid", "rt"))) + { + int pid; + int res = fscanf (fp, "%d", &pid); + fclose (fp); + if (res == 1) + { + syslog (LOG_INFO, "Restarting mDNSResponder.\n"); + kill (pid, SIGUSR1); + } + } +} + + /* * nm_system_device_update_config_info * diff --git a/src/backends/NetworkManagerSlackware.c b/src/backends/NetworkManagerSlackware.c index be01b62fee..6f16da87af 100644 --- a/src/backends/NetworkManagerSlackware.c +++ b/src/backends/NetworkManagerSlackware.c @@ -243,4 +243,14 @@ void nm_system_load_device_modules (void) } +/* + * nm_system_restart_mdns_responder + * + * Restart the multicast DNS responder so that it knows about new + * network interfaces and IP addresses. + * + */ +void nm_system_restart_mdns_responder (void) +{ +}