2004-12-15 Dan Williams <dcbw@redhat.com>

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


git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@341 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
This commit is contained in:
Dan Williams
2004-12-16 04:24:20 +00:00
parent e26e7e9983
commit cd475e6d0c
20 changed files with 636 additions and 103 deletions

View File

@@ -1,3 +1,15 @@
2004-12-15 Dan Williams <dcbw@redhat.com>
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 <dcbw@redhat.com>
* Rework the DHCP code again to revert to sending full ethernet frames

View File

@@ -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
*/

View File

@@ -3,7 +3,9 @@ INCLUDES = -I${top_srcdir} -I${top_srcdir}/src
AM_CPPFLAGS = \
$(NM_CFLAGS) \
-DBINDIR=\"$(bindir)\" \
-DDATADIR=\"$(datadir)\"
-DDATADIR=\"$(datadir)\" \
-DARP_DEBUG \
-DDEBUG
noinst_LIBRARIES = libdhcpc.a

View File

@@ -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;

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);
@@ -87,6 +89,7 @@ int nm_device_dhcp_request (NMDevice *dev)
{
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)
{
case RET_DHCP_BOUND:
nm_device_dhcp_configure (dev);
nm_device_update_ip4_address (dev);
nm_device_dhcp_setup_timeouts (dev);
}
else
{
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);

View File

@@ -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);
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;
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 == -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);
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);
}
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 "<hidden>" 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, "<hidden>")))
{
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);

View File

@@ -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);

View File

@@ -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

View File

@@ -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;

View File

@@ -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);

303
src/autoip.c Normal file
View File

@@ -0,0 +1,303 @@
// Based upon http://www.zeroconf.org/AVH-IPv4LL.c
// Merged into NetworkManager by Tom Parker <palfrey@tevp.net>
// Original copyright continues below
//
// ----------------------------------
// Simple IPv4 Link-Local addressing (see <http://www.zeroconf.org/>)
// @(#)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 <http://www.gnu.org/copyleft/lesser.html>
//
// 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 <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/poll.h>
#include <arpa/inet.h>
#include <netinet/ether.h>
#include <net/if.h>
#include <linux/sockios.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <syslog.h>
#include <glib.h>
#include <unistd.h>
#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);
}

View File

@@ -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)
{
}

View File

@@ -25,8 +25,13 @@
#include <stdio.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <signal.h>
/* get strnlen */
#define __USE_GNU
#include <string.h>
#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
*

View File

@@ -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
*

View File

@@ -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)
{
}