2008-07-09 Dan Williams <dcbw@redhat.com>
* callouts/Makefile.am callouts/nm-avahi-autoipd-action.c callouts/nm-avahi-autoipd.conf - avahi-autoipd callout to send options back to NM * src/autoip.c src/autoip.h - remove * src/nm-device.c src/nm-device-private.h src/nm-manager.c - Use avahi-autoipd for IPv4LL functionality rather than really crappy old custom stuff git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@3816 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
This commit is contained in:
17
ChangeLog
17
ChangeLog
@@ -1,3 +1,20 @@
|
|||||||
|
2008-07-09 Dan Williams <dcbw@redhat.com>
|
||||||
|
|
||||||
|
* callouts/Makefile.am
|
||||||
|
callouts/nm-avahi-autoipd-action.c
|
||||||
|
callouts/nm-avahi-autoipd.conf
|
||||||
|
- avahi-autoipd callout to send options back to NM
|
||||||
|
|
||||||
|
* src/autoip.c
|
||||||
|
src/autoip.h
|
||||||
|
- remove
|
||||||
|
|
||||||
|
* src/nm-device.c
|
||||||
|
src/nm-device-private.h
|
||||||
|
src/nm-manager.c
|
||||||
|
- Use avahi-autoipd for IPv4LL functionality rather than really crappy
|
||||||
|
old custom stuff
|
||||||
|
|
||||||
2008-07-07 Dan Williams <dcbw@redhat.com>
|
2008-07-07 Dan Williams <dcbw@redhat.com>
|
||||||
|
|
||||||
* system-settings/plugins/ifcfg-fedora/reader.c
|
* system-settings/plugins/ifcfg-fedora/reader.c
|
||||||
|
@@ -1,11 +1,13 @@
|
|||||||
dbusservicedir = $(DBUS_SYS_DIR)
|
dbusservicedir = $(DBUS_SYS_DIR)
|
||||||
dbusservice_DATA = \
|
dbusservice_DATA = \
|
||||||
nm-dhcp-client.conf \
|
nm-dhcp-client.conf \
|
||||||
nm-dispatcher.conf
|
nm-dispatcher.conf \
|
||||||
|
nm-avahi-autoipd.conf
|
||||||
|
|
||||||
libexec_PROGRAMS = \
|
libexec_PROGRAMS = \
|
||||||
nm-dhcp-client.action \
|
nm-dhcp-client.action \
|
||||||
nm-dispatcher.action
|
nm-dispatcher.action \
|
||||||
|
nm-avahi-autoipd.action
|
||||||
|
|
||||||
nm_dhcp_client_action_SOURCES = \
|
nm_dhcp_client_action_SOURCES = \
|
||||||
nm-dhcp-client-action.c
|
nm-dhcp-client-action.c
|
||||||
@@ -23,6 +25,22 @@ nm_dhcp_client_action_LDADD = \
|
|||||||
$(GTHREAD_LIBS)
|
$(GTHREAD_LIBS)
|
||||||
|
|
||||||
|
|
||||||
|
nm_avahi_autoipd_action_SOURCES = \
|
||||||
|
nm-avahi-autoipd-action.c
|
||||||
|
|
||||||
|
nm_avahi_autoipd_action_CPPFLAGS = \
|
||||||
|
$(DBUS_CFLAGS) \
|
||||||
|
$(GTHREAD_CFLAGS) \
|
||||||
|
-DDBUS_API_SUBJECT_TO_CHANGE \
|
||||||
|
-DG_DISABLE_DEPRECATED \
|
||||||
|
-DSYSCONFDIR=\"$(sysconfdir)\" \
|
||||||
|
-DLIBEXECDIR=\"$(libexecdir)\"
|
||||||
|
|
||||||
|
nm_avahi_autoipd_action_LDADD = \
|
||||||
|
$(DBUS_LIBS) \
|
||||||
|
$(GTHREAD_LIBS)
|
||||||
|
|
||||||
|
|
||||||
nm_dispatcher_action_SOURCES = \
|
nm_dispatcher_action_SOURCES = \
|
||||||
nm-dispatcher-action.c \
|
nm-dispatcher-action.c \
|
||||||
nm-dispatcher-action.h
|
nm-dispatcher-action.h
|
||||||
|
151
callouts/nm-avahi-autoipd-action.c
Normal file
151
callouts/nm-avahi-autoipd-action.c
Normal file
@@ -0,0 +1,151 @@
|
|||||||
|
/* NetworkManager -- Network link manager
|
||||||
|
*
|
||||||
|
* Dan Williams <dcbw@redhat.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program 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 General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* (C) Copyright 2008 Red Hat, Inc.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
#include <dbus/dbus.h>
|
||||||
|
#include <dbus/dbus-glib-lowlevel.h>
|
||||||
|
#include <dbus/dbus-glib.h>
|
||||||
|
|
||||||
|
#define NM_AVAHI_AUTOIPD_DBUS_SERVICE "org.freedesktop.nm_avahi_autoipd"
|
||||||
|
#define NM_AVAHI_AUTOIPD_DBUS_IFACE "org.freedesktop.nm_avahi_autoipd"
|
||||||
|
|
||||||
|
static DBusConnection *
|
||||||
|
dbus_init (void)
|
||||||
|
{
|
||||||
|
DBusConnection * connection;
|
||||||
|
DBusError error;
|
||||||
|
int ret, flags;
|
||||||
|
|
||||||
|
dbus_connection_set_change_sigpipe (TRUE);
|
||||||
|
|
||||||
|
dbus_error_init (&error);
|
||||||
|
connection = dbus_bus_get (DBUS_BUS_SYSTEM, &error);
|
||||||
|
if (dbus_error_is_set (&error)) {
|
||||||
|
fprintf (stderr, "Error: could not get the system bus. Make sure "
|
||||||
|
"the message bus daemon is running! Message: (%s) %s\n",
|
||||||
|
error.name,
|
||||||
|
error.message);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
dbus_connection_set_exit_on_disconnect (connection, FALSE);
|
||||||
|
|
||||||
|
#if (DBUS_VERSION_MAJOR == 0) && (DBUS_VERSION_MINOR < 60)
|
||||||
|
flags = DBUS_NAME_FLAG_PROHIBIT_REPLACEMENT;
|
||||||
|
#else
|
||||||
|
flags = DBUS_NAME_FLAG_DO_NOT_QUEUE;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
dbus_error_init (&error);
|
||||||
|
ret = dbus_bus_request_name (connection,
|
||||||
|
NM_AVAHI_AUTOIPD_DBUS_SERVICE,
|
||||||
|
flags,
|
||||||
|
&error);
|
||||||
|
if (dbus_error_is_set (&error)) {
|
||||||
|
fprintf (stderr, "Error: Could not acquire the NM DHCP client service. "
|
||||||
|
"Message: (%s) %s\n",
|
||||||
|
error.name,
|
||||||
|
error.message);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
|
||||||
|
fprintf (stderr, "Error: Could not acquire the NM DHCP client service "
|
||||||
|
"as it is already taken. Return: %d\n",
|
||||||
|
ret);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
return connection;
|
||||||
|
|
||||||
|
error:
|
||||||
|
if (dbus_error_is_set (&error))
|
||||||
|
dbus_error_free (&error);
|
||||||
|
if (connection)
|
||||||
|
dbus_connection_unref (connection);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main (int argc, char *argv[])
|
||||||
|
{
|
||||||
|
DBusConnection *connection;
|
||||||
|
DBusMessage *message;
|
||||||
|
dbus_bool_t result;
|
||||||
|
char *event, *iface, *address;
|
||||||
|
|
||||||
|
g_type_init ();
|
||||||
|
|
||||||
|
if (argc != 4) {
|
||||||
|
fprintf (stderr, "Error: expected 3 arguments (event, interface, address).\n");
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
event = argv[1];
|
||||||
|
iface = argv[2];
|
||||||
|
address = argv[3] ? argv[3] : "";
|
||||||
|
|
||||||
|
if (!event || !iface || !strlen (event) || !strlen (iface)) {
|
||||||
|
fprintf (stderr, "Error: unexpected arguments received from avahi-autoipd.\n");
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get a connection to the system bus */
|
||||||
|
connection = dbus_init ();
|
||||||
|
if (connection == NULL)
|
||||||
|
exit (1);
|
||||||
|
|
||||||
|
message = dbus_message_new_signal ("/", NM_AVAHI_AUTOIPD_DBUS_IFACE, "Event");
|
||||||
|
if (message == NULL) {
|
||||||
|
fprintf (stderr, "Error: not enough memory to send autoip Event signal.\n");
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dbus_message_append_args (message,
|
||||||
|
DBUS_TYPE_STRING, &event,
|
||||||
|
DBUS_TYPE_STRING, &iface,
|
||||||
|
DBUS_TYPE_STRING, &address,
|
||||||
|
DBUS_TYPE_INVALID)) {
|
||||||
|
fprintf (stderr, "Error: failed to construct autoip Event signal.\n");
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* queue the message */
|
||||||
|
result = dbus_connection_send (connection, message, NULL);
|
||||||
|
if (!result) {
|
||||||
|
fprintf (stderr, "Error: could not send send autoip Event signal.\n");
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
dbus_message_unref (message);
|
||||||
|
|
||||||
|
/* Send out the message */
|
||||||
|
dbus_connection_flush (connection);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
14
callouts/nm-avahi-autoipd.conf
Normal file
14
callouts/nm-avahi-autoipd.conf
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<!DOCTYPE busconfig PUBLIC
|
||||||
|
"-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
|
||||||
|
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
|
||||||
|
<busconfig>
|
||||||
|
<policy user="root">
|
||||||
|
<allow own="org.freedesktop.nm_avahi_autoipd"/>
|
||||||
|
<allow send_interface="org.freedesktop.nm_avahi_autoipd"/>
|
||||||
|
</policy>
|
||||||
|
<policy context="default">
|
||||||
|
<deny own="org.freedesktop.nm_avahi_autoipd"/>
|
||||||
|
<deny send_interface="org.freedesktop.nm_avahi_autoipd"/>
|
||||||
|
</policy>
|
||||||
|
</busconfig>
|
||||||
|
|
@@ -65,8 +65,6 @@ NetworkManager_SOURCES = \
|
|||||||
nm-gsm-device.h \
|
nm-gsm-device.h \
|
||||||
nm-cdma-device.c \
|
nm-cdma-device.c \
|
||||||
nm-cdma-device.h \
|
nm-cdma-device.h \
|
||||||
autoip.c \
|
|
||||||
autoip.h \
|
|
||||||
wpa.c \
|
wpa.c \
|
||||||
wpa.h \
|
wpa.h \
|
||||||
nm-netlink.c \
|
nm-netlink.c \
|
||||||
|
379
src/autoip.c
379
src/autoip.c
@@ -1,379 +0,0 @@
|
|||||||
// 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 <linux/sockios.h>
|
|
||||||
#include <sys/ioctl.h>
|
|
||||||
#include <sys/time.h>
|
|
||||||
#include <syslog.h>
|
|
||||||
#include <glib.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include "NetworkManager.h"
|
|
||||||
#include "nm-device.h"
|
|
||||||
#include "nm-device-ethernet.h"
|
|
||||||
#include "nm-device-wifi.h"
|
|
||||||
#include "NetworkManagerUtils.h"
|
|
||||||
#include "nm-utils.h"
|
|
||||||
#include "autoip.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
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct EtherHeader
|
|
||||||
{
|
|
||||||
u_int8_t ether_dhost[ETH_ALEN]; /* destination eth addr */
|
|
||||||
u_int8_t ether_shost[ETH_ALEN]; /* source ether addr */
|
|
||||||
u_int16_t ether_type; /* packet type ID field */
|
|
||||||
} __attribute__((packed)) EtherHeader;
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct ARPMessage
|
|
||||||
{
|
|
||||||
EtherHeader 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;
|
|
||||||
|
|
||||||
|
|
||||||
// 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) + (abs(random()) % 0x0100)));
|
|
||||||
|
|
||||||
/* Make sure we don't use 0xFF or 0x00 anywhere */
|
|
||||||
while (((ip->s_addr & 0x0000FF00) == 0xFF00) || ((ip->s_addr & 0x0000FF00) == 0x0000))
|
|
||||||
ip->s_addr = (ip->s_addr & 0xFFFF00FF) + (abs(random()) && 0xFFFF);
|
|
||||||
|
|
||||||
while (((ip->s_addr & 0x000000FF) == 0xFF) || ((ip->s_addr & 0x000000FF) == 0x00))
|
|
||||||
ip->s_addr = (ip->s_addr & 0xFFFFFF00) + (abs(random()) && 0xFF);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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)
|
|
||||||
nm_warning ("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;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum return_vals
|
|
||||||
{
|
|
||||||
RET_ERROR = 0,
|
|
||||||
RET_TIMEOUT,
|
|
||||||
RET_CEASED,
|
|
||||||
RET_SUCCESS
|
|
||||||
};
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
|
||||||
/* "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);
|
|
||||||
// nm_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};
|
|
||||||
// nm_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_ERROR;
|
|
||||||
if (FD_ISSET(sk, &fs))
|
|
||||||
return RET_SUCCESS;
|
|
||||||
gettimeofday (&now, NULL);
|
|
||||||
};
|
|
||||||
return RET_TIMEOUT;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
gboolean get_autoip (NMDevice *dev, struct in_addr *out_ip)
|
|
||||||
{
|
|
||||||
struct sockaddr saddr;
|
|
||||||
ARPMessage p;
|
|
||||||
struct ether_addr addr;
|
|
||||||
struct in_addr ip = {0};
|
|
||||||
int fd = -1;
|
|
||||||
int nprobes = 0;
|
|
||||||
int nannounce = 0;
|
|
||||||
gboolean success = FALSE;
|
|
||||||
const char *iface;
|
|
||||||
char buf[INET_ADDRSTRLEN+1];
|
|
||||||
|
|
||||||
memset(&buf, '\0', sizeof (buf));
|
|
||||||
|
|
||||||
g_return_val_if_fail (dev != NULL, FALSE);
|
|
||||||
g_return_val_if_fail (out_ip != NULL, FALSE);
|
|
||||||
|
|
||||||
out_ip->s_addr = 0;
|
|
||||||
iface = nm_device_get_iface (dev);
|
|
||||||
|
|
||||||
/* initialize saddr */
|
|
||||||
memset (&saddr, 0, sizeof (saddr));
|
|
||||||
strncpy (saddr.sa_data, iface, sizeof (saddr.sa_data));
|
|
||||||
|
|
||||||
if (NM_IS_DEVICE_ETHERNET (dev))
|
|
||||||
nm_device_ethernet_get_address (NM_DEVICE_ETHERNET (dev), &addr);
|
|
||||||
else if (NM_IS_DEVICE_WIFI (dev))
|
|
||||||
nm_device_wifi_get_address (NM_DEVICE_WIFI (dev), &addr);
|
|
||||||
else
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
/* open an ARP socket */
|
|
||||||
fd = socket (AF_PACKET, SOCK_PACKET, htons (ETH_P_ALL));
|
|
||||||
if (fd < 0) {
|
|
||||||
nm_warning ("%s: Couldn't open network control socket.", iface);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* bind to the ARP socket */
|
|
||||||
if (bind (fd, &saddr, sizeof (saddr)) < 0) {
|
|
||||||
nm_warning ("%s: Couldn't bind to the device.", iface);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 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;
|
|
||||||
|
|
||||||
if (nprobes < PROBE_NUM)
|
|
||||||
{
|
|
||||||
if (!inet_ntop (AF_INET, &ip, buf, INET_ADDRSTRLEN)) {
|
|
||||||
nm_warning ("%s: error converting IP4 address 0x%X",
|
|
||||||
__func__, ntohl (ip.s_addr));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
nm_info ("autoip: Sending probe #%d for IP address %s.", nprobes, buf);
|
|
||||||
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
|
|
||||||
{
|
|
||||||
unsigned int usecs_to_sleep = ((PROBE_MAX - PROBE_MIN) * 1000000) - 1;
|
|
||||||
|
|
||||||
/* We want to sleep between PROBE_MIN and PROBE_MAX seconds, exclusive */
|
|
||||||
timeout.tv_sec += PROBE_MIN;
|
|
||||||
timeout.tv_usec += 1 + (random () % usecs_to_sleep);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (nannounce < ANNOUNCE_NUM)
|
|
||||||
{
|
|
||||||
if (!inet_ntop (AF_INET, &ip, buf, INET_ADDRSTRLEN)) {
|
|
||||||
nm_warning ("%s: error converting IP4 address 0x%X",
|
|
||||||
__func__, ntohl (ip.s_addr));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
nm_info ("autoip: Sending announce #%d for IP address %s.", nannounce, buf);
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
nm_info ("autoip: Waiting for reply...");
|
|
||||||
err = peekfd (dev, fd, &timeout);
|
|
||||||
if ((err == RET_ERROR) || (err == RET_CEASED))
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
/* There's some data waiting for us */
|
|
||||||
if (err == RET_SUCCESS) {
|
|
||||||
nm_info ("autoip: Got some data to check for reply packet.");
|
|
||||||
|
|
||||||
/* read ARP packet */
|
|
||||||
if (recv (fd, &p, sizeof (p), 0) < 0) {
|
|
||||||
nm_warning ("autoip: packet receive failure, ignoring it.");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef ARP_DEBUG
|
|
||||||
nm_warning ("autoip: (%s) recv arp type=%d, op=%d, ", iface, ntohs(p.ethhdr.ether_type), ntohs(p.operation));
|
|
||||||
{
|
|
||||||
struct in_addr a;
|
|
||||||
memcpy (&(a.s_addr), &(p.sInaddr), sizeof (a.s_addr));
|
|
||||||
if (!inet_ntop (AF_INET, &a, buf, INET_ADDRSTRLEN)) {
|
|
||||||
nm_warning ("%s: error converting IP4 address 0x%X",
|
|
||||||
__func__, ntohl (a.s_addr));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
nm_warning (" source = %s %02X:%02X:%02X:%02X:%02X:%02X, ", buf,
|
|
||||||
p.sHaddr[0], p.sHaddr[1], p.sHaddr[2], p.sHaddr[3], p.sHaddr[4], p.sHaddr[5]);
|
|
||||||
memcpy (&(a.s_addr), &(p.tInaddr), sizeof (a.s_addr));
|
|
||||||
if (!inet_ntop (AF_INET, &a, buf, INET_ADDRSTRLEN)) {
|
|
||||||
nm_warning ("%s: error converting IP4 address 0x%X",
|
|
||||||
__func__, ntohl (a.s_addr));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
nm_warning (" target = %s %02X:%02X:%02X:%02X:%02X:%02X\n", buf,
|
|
||||||
p.tHaddr[0], p.tHaddr[1], p.tHaddr[2], p.tHaddr[3], p.tHaddr[4], p.tHaddr[5]);
|
|
||||||
}
|
|
||||||
#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
|
|
||||||
if (!inet_ntop (AF_INET, &ip, buf, INET_ADDRSTRLEN)) {
|
|
||||||
nm_warning ("%s: error converting IP4 address 0x%X",
|
|
||||||
__func__, ntohl (ip.s_addr));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
nm_warning ("autoip: (%s) ARP conflict for IP address %s.\n", iface, buf);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Ok, start all over again */
|
|
||||||
pick (&ip);
|
|
||||||
nprobes = 0;
|
|
||||||
nannounce = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
out:
|
|
||||||
if (fd >= 0)
|
|
||||||
close (fd);
|
|
||||||
return success;
|
|
||||||
}
|
|
@@ -1,8 +0,0 @@
|
|||||||
#ifndef _SRC_AUTOIP_H
|
|
||||||
#define _SRC_AUTOIP_H
|
|
||||||
|
|
||||||
#include "nm-device.h"
|
|
||||||
|
|
||||||
extern gboolean get_autoip (NMDevice *dev, struct in_addr *out_ip);
|
|
||||||
|
|
||||||
#endif /* _SRC_AUTOIP_H */
|
|
@@ -36,4 +36,8 @@ gboolean nm_device_hw_bring_up (NMDevice *self, gboolean wait);
|
|||||||
|
|
||||||
void nm_device_hw_take_down (NMDevice *self, gboolean wait);
|
void nm_device_hw_take_down (NMDevice *self, gboolean wait);
|
||||||
|
|
||||||
|
void nm_device_handle_autoip4_event (NMDevice *self,
|
||||||
|
const char *event,
|
||||||
|
const char *address);
|
||||||
|
|
||||||
#endif /* NM_DEVICE_PRIVATE_H */
|
#endif /* NM_DEVICE_PRIVATE_H */
|
||||||
|
359
src/nm-device.c
359
src/nm-device.c
@@ -1,4 +1,4 @@
|
|||||||
/* -*- Mode: C; tab-width: 5; indent-tabs-mode: t; c-basic-offset: 5 -*- */
|
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
|
||||||
/* NetworkManager -- Network link manager
|
/* NetworkManager -- Network link manager
|
||||||
*
|
*
|
||||||
* Dan Williams <dcbw@redhat.com>
|
* Dan Williams <dcbw@redhat.com>
|
||||||
@@ -17,7 +17,7 @@
|
|||||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
*
|
*
|
||||||
* (C) Copyright 2005 Red Hat, Inc.
|
* (C) Copyright 2005 - 2008 Red Hat, Inc.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
@@ -29,6 +29,10 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
#include "nm-device-interface.h"
|
#include "nm-device-interface.h"
|
||||||
#include "nm-device.h"
|
#include "nm-device.h"
|
||||||
@@ -40,7 +44,6 @@
|
|||||||
#include "nm-dbus-manager.h"
|
#include "nm-dbus-manager.h"
|
||||||
#include "nm-named-manager.h"
|
#include "nm-named-manager.h"
|
||||||
#include "nm-utils.h"
|
#include "nm-utils.h"
|
||||||
#include "autoip.h"
|
|
||||||
#include "nm-netlink.h"
|
#include "nm-netlink.h"
|
||||||
#include "nm-setting-ip4-config.h"
|
#include "nm-setting-ip4-config.h"
|
||||||
#include "nm-setting-connection.h"
|
#include "nm-setting-connection.h"
|
||||||
@@ -88,8 +91,15 @@ struct _NMDevicePrivate
|
|||||||
gulong dhcp_state_sigid;
|
gulong dhcp_state_sigid;
|
||||||
gulong dhcp_timeout_sigid;
|
gulong dhcp_timeout_sigid;
|
||||||
|
|
||||||
|
/* dnsmasq stuff for shared connections */
|
||||||
NMDnsMasqManager * dnsmasq_manager;
|
NMDnsMasqManager * dnsmasq_manager;
|
||||||
gulong dnsmasq_state_id;
|
gulong dnsmasq_state_id;
|
||||||
|
|
||||||
|
/* avahi-autoipd stuff */
|
||||||
|
GPid aipd_pid;
|
||||||
|
guint aipd_watch;
|
||||||
|
guint aipd_timeout;
|
||||||
|
guint32 aipd_addr;
|
||||||
};
|
};
|
||||||
|
|
||||||
static gboolean check_connection_compatible (NMDeviceInterface *device,
|
static gboolean check_connection_compatible (NMDeviceInterface *device,
|
||||||
@@ -521,6 +531,271 @@ nm_device_activate_schedule_stage2_device_config (NMDevice *self)
|
|||||||
nm_device_get_iface (self));
|
nm_device_get_iface (self));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
aipd_timeout_remove (NMDevice *self)
|
||||||
|
{
|
||||||
|
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
|
||||||
|
|
||||||
|
if (priv->aipd_timeout) {
|
||||||
|
g_source_remove (priv->aipd_timeout);
|
||||||
|
priv->aipd_timeout = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
aipd_cleanup (NMDevice *self)
|
||||||
|
{
|
||||||
|
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
|
||||||
|
|
||||||
|
if (priv->aipd_pid > 0) {
|
||||||
|
kill (priv->aipd_pid, SIGKILL);
|
||||||
|
priv->aipd_pid = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (priv->aipd_watch) {
|
||||||
|
g_source_remove (priv->aipd_watch);
|
||||||
|
priv->aipd_watch = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
aipd_timeout_remove (self);
|
||||||
|
|
||||||
|
priv->aipd_addr = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static NMIP4Config *
|
||||||
|
aipd_get_ip4_config (NMDevice *self)
|
||||||
|
{
|
||||||
|
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
|
||||||
|
NMIP4Config *config = NULL;
|
||||||
|
NMSettingIP4Address *addr;
|
||||||
|
|
||||||
|
g_return_val_if_fail (priv->aipd_addr > 0, NULL);
|
||||||
|
|
||||||
|
config = nm_ip4_config_new ();
|
||||||
|
addr = g_malloc0 (sizeof (NMSettingIP4Address));
|
||||||
|
addr->address = (guint32) priv->aipd_addr;
|
||||||
|
addr->prefix = 16;
|
||||||
|
nm_ip4_config_take_address (config, addr);
|
||||||
|
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
handle_autoip_change (NMDevice *self)
|
||||||
|
{
|
||||||
|
NMActRequest *req;
|
||||||
|
NMConnection *connection;
|
||||||
|
NMIP4Config *config;
|
||||||
|
|
||||||
|
config = aipd_get_ip4_config (self);
|
||||||
|
if (!config) {
|
||||||
|
nm_warning ("failed to get autoip config for rebind");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
req = nm_device_get_act_request (self);
|
||||||
|
g_assert (req);
|
||||||
|
connection = nm_act_request_get_connection (req);
|
||||||
|
g_assert (connection);
|
||||||
|
|
||||||
|
g_object_set_data (G_OBJECT (req), NM_ACT_REQUEST_IP4_CONFIG, config);
|
||||||
|
|
||||||
|
if (!nm_device_set_ip4_config (self, config)) {
|
||||||
|
nm_warning ("(%s): failed to update IP4 config in response to autoip event.",
|
||||||
|
nm_device_get_iface (self));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define IPV4LL_NETWORK (htonl (0xA9FE0000L))
|
||||||
|
#define IPV4LL_NETMASK (htonl (0xFFFF0000L))
|
||||||
|
|
||||||
|
void
|
||||||
|
nm_device_handle_autoip4_event (NMDevice *self,
|
||||||
|
const char *event,
|
||||||
|
const char *address)
|
||||||
|
{
|
||||||
|
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
|
||||||
|
NMActRequest *req;
|
||||||
|
NMConnection *connection = NULL;
|
||||||
|
NMSettingIP4Config *s_ip4 = NULL;
|
||||||
|
NMDeviceState state;
|
||||||
|
const char *iface;
|
||||||
|
|
||||||
|
g_return_if_fail (event != NULL);
|
||||||
|
|
||||||
|
req = nm_device_get_act_request (self);
|
||||||
|
if (!req)
|
||||||
|
return;
|
||||||
|
|
||||||
|
connection = nm_act_request_get_connection (req);
|
||||||
|
if (!connection)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Ignore if the connection isn't an AutoIP connection */
|
||||||
|
s_ip4 = (NMSettingIP4Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG);
|
||||||
|
if (!s_ip4 || !s_ip4->method || strcmp (s_ip4->method, NM_SETTING_IP4_CONFIG_METHOD_AUTOIP))
|
||||||
|
return;
|
||||||
|
|
||||||
|
iface = nm_device_get_iface (self);
|
||||||
|
state = nm_device_get_state (self);
|
||||||
|
|
||||||
|
if (strcmp (event, "BIND") == 0) {
|
||||||
|
struct in_addr ip;
|
||||||
|
|
||||||
|
if (inet_pton (AF_INET, address, &ip) <= 0) {
|
||||||
|
nm_warning ("(%s): invalid address %s received from avahi-autoipd.",
|
||||||
|
iface, address);
|
||||||
|
nm_device_state_changed (self, NM_DEVICE_STATE_FAILED);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((ip.s_addr & IPV4LL_NETMASK) != IPV4LL_NETWORK) {
|
||||||
|
nm_warning ("(%s): invalid address %s received from avahi-autoipd.",
|
||||||
|
iface, address);
|
||||||
|
nm_device_state_changed (self, NM_DEVICE_STATE_FAILED);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (state) {
|
||||||
|
case NM_DEVICE_STATE_IP_CONFIG:
|
||||||
|
if (priv->aipd_addr) {
|
||||||
|
nm_warning ("(%s): already have autoip address!", iface);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
priv->aipd_addr = ip.s_addr;
|
||||||
|
aipd_timeout_remove (self);
|
||||||
|
nm_device_activate_schedule_stage4_ip_config_get (self);
|
||||||
|
break;
|
||||||
|
case NM_DEVICE_STATE_ACTIVATED:
|
||||||
|
priv->aipd_addr = ip.s_addr;
|
||||||
|
if (!handle_autoip_change (self))
|
||||||
|
nm_device_state_changed (self, NM_DEVICE_STATE_FAILED);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
nm_warning ("(%s): unexpected avahi-autoip event %s for %s.",
|
||||||
|
iface, event, address);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
nm_warning ("%s: autoip address %s no longer valid because '%s'.",
|
||||||
|
iface, address, event);
|
||||||
|
|
||||||
|
/* The address is gone; terminate the connection or fail activation */
|
||||||
|
nm_device_state_changed (self, NM_DEVICE_STATE_FAILED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
aipd_watch_cb (GPid pid, gint status, gpointer user_data)
|
||||||
|
{
|
||||||
|
NMDevice *self = NM_DEVICE (user_data);
|
||||||
|
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
|
||||||
|
NMDeviceState state;
|
||||||
|
const char *iface;
|
||||||
|
|
||||||
|
if (!priv->aipd_watch)
|
||||||
|
return;
|
||||||
|
priv->aipd_watch = 0;
|
||||||
|
|
||||||
|
iface = nm_device_get_iface (self);
|
||||||
|
|
||||||
|
if (WIFEXITED (status))
|
||||||
|
nm_warning ("%s: avahi-autoipd exited with error code %d", iface, WEXITSTATUS (status));
|
||||||
|
else if (WIFSTOPPED (status))
|
||||||
|
nm_warning ("%s: avahi-autoipd stopped unexpectedly with signal %d", iface, WSTOPSIG (status));
|
||||||
|
else if (WIFSIGNALED (status))
|
||||||
|
nm_warning ("%s: avahi-autoipd died with signal %d", iface, WTERMSIG (status));
|
||||||
|
else
|
||||||
|
nm_warning ("%s: avahi-autoipd died from an unknown cause", iface);
|
||||||
|
|
||||||
|
aipd_cleanup (self);
|
||||||
|
|
||||||
|
state = nm_device_get_state (self);
|
||||||
|
if (nm_device_is_activating (self) || (state == NM_DEVICE_STATE_ACTIVATED))
|
||||||
|
nm_device_state_changed (self, NM_DEVICE_STATE_FAILED);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
aipd_timeout_cb (gpointer user_data)
|
||||||
|
{
|
||||||
|
NMDevice *self = NM_DEVICE (user_data);
|
||||||
|
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
|
||||||
|
|
||||||
|
if (!priv->aipd_timeout)
|
||||||
|
return FALSE;
|
||||||
|
priv->aipd_timeout = 0;
|
||||||
|
|
||||||
|
nm_info ("%s: avahi-autoipd timed out.", nm_device_get_iface (self));
|
||||||
|
aipd_cleanup (self);
|
||||||
|
|
||||||
|
if (nm_device_get_state (self) == NM_DEVICE_STATE_IP_CONFIG)
|
||||||
|
nm_device_activate_schedule_stage4_ip_config_timeout (self);
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
aipd_child_setup (gpointer user_data G_GNUC_UNUSED)
|
||||||
|
{
|
||||||
|
/* We are in the child process at this point.
|
||||||
|
* Give child it's own program group for signal
|
||||||
|
* separation.
|
||||||
|
*/
|
||||||
|
pid_t pid = getpid ();
|
||||||
|
setpgid (pid, pid);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
aipd_exec (NMDevice *self, GError **error)
|
||||||
|
{
|
||||||
|
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
|
||||||
|
char *argv[5];
|
||||||
|
gboolean success = FALSE;
|
||||||
|
const char **aipd_binary = NULL;
|
||||||
|
static const char *aipd_paths[] = {
|
||||||
|
"/usr/sbin/avahi-autoipd",
|
||||||
|
"/usr/local/sbin/avahi-autoipd",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
aipd_cleanup (self);
|
||||||
|
|
||||||
|
/* Find avahi-autoipd */
|
||||||
|
aipd_binary = aipd_paths;
|
||||||
|
while (*aipd_binary != NULL) {
|
||||||
|
if (g_file_test (*aipd_binary, G_FILE_TEST_EXISTS))
|
||||||
|
break;
|
||||||
|
aipd_binary++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!*aipd_binary) {
|
||||||
|
g_set_error (error, 0, 0, "%s", "couldn't find avahi-autoipd");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
argv[0] = (char *) (*aipd_binary);
|
||||||
|
argv[1] = "--script";
|
||||||
|
argv[2] = LIBEXECDIR "/nm-avahi-autoipd.action";
|
||||||
|
argv[3] = (char *) nm_device_get_iface (self);
|
||||||
|
argv[4] = NULL;
|
||||||
|
|
||||||
|
success = g_spawn_async ("/", argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD,
|
||||||
|
&aipd_child_setup, NULL, &(priv->aipd_pid), error);
|
||||||
|
if (!success)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
/* Monitor the child process so we know when it dies */
|
||||||
|
priv->aipd_watch = g_child_watch_add (priv->aipd_pid, aipd_watch_cb, self);
|
||||||
|
|
||||||
|
/* Start a timeout to bound the address attempt */
|
||||||
|
priv->aipd_timeout = g_timeout_add (20000, aipd_timeout_cb, self);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
static NMActStageReturn
|
static NMActStageReturn
|
||||||
real_act_stage3_ip_config_start (NMDevice *self)
|
real_act_stage3_ip_config_start (NMDevice *self)
|
||||||
@@ -528,6 +803,9 @@ real_act_stage3_ip_config_start (NMDevice *self)
|
|||||||
NMSettingIP4Config *s_ip4;
|
NMSettingIP4Config *s_ip4;
|
||||||
NMActRequest *req;
|
NMActRequest *req;
|
||||||
NMActStageReturn ret = NM_ACT_STAGE_RETURN_SUCCESS;
|
NMActStageReturn ret = NM_ACT_STAGE_RETURN_SUCCESS;
|
||||||
|
const char *iface;
|
||||||
|
|
||||||
|
iface = nm_device_get_iface (self);
|
||||||
|
|
||||||
req = nm_device_get_act_request (self);
|
req = nm_device_get_act_request (self);
|
||||||
s_ip4 = (NMSettingIP4Config *) nm_connection_get_setting (nm_act_request_get_connection (req),
|
s_ip4 = (NMSettingIP4Config *) nm_connection_get_setting (nm_act_request_get_connection (req),
|
||||||
@@ -544,12 +822,7 @@ real_act_stage3_ip_config_start (NMDevice *self)
|
|||||||
/* DHCP manager will cancel any transaction already in progress and we do not
|
/* DHCP manager will cancel any transaction already in progress and we do not
|
||||||
want to cancel this activation if we get "down" state from that. */
|
want to cancel this activation if we get "down" state from that. */
|
||||||
g_signal_handler_block (priv->dhcp_manager, priv->dhcp_state_sigid);
|
g_signal_handler_block (priv->dhcp_manager, priv->dhcp_state_sigid);
|
||||||
|
success = nm_dhcp_manager_begin_transaction (priv->dhcp_manager, iface, s_ip4, 45);
|
||||||
success = nm_dhcp_manager_begin_transaction (priv->dhcp_manager,
|
|
||||||
nm_device_get_iface (self),
|
|
||||||
s_ip4,
|
|
||||||
45);
|
|
||||||
|
|
||||||
g_signal_handler_unblock (priv->dhcp_manager, priv->dhcp_state_sigid);
|
g_signal_handler_unblock (priv->dhcp_manager, priv->dhcp_state_sigid);
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
@@ -559,6 +832,21 @@ real_act_stage3_ip_config_start (NMDevice *self)
|
|||||||
ret = NM_ACT_STAGE_RETURN_POSTPONE;
|
ret = NM_ACT_STAGE_RETURN_POSTPONE;
|
||||||
} else
|
} else
|
||||||
ret = NM_ACT_STAGE_RETURN_FAILURE;
|
ret = NM_ACT_STAGE_RETURN_FAILURE;
|
||||||
|
} else if (s_ip4 && !strcmp (s_ip4->method, NM_SETTING_IP4_CONFIG_METHOD_AUTOIP)) {
|
||||||
|
GError *error = NULL;
|
||||||
|
|
||||||
|
/* Start avahi-autoipd */
|
||||||
|
if (aipd_exec (self, &error)) {
|
||||||
|
nm_info ("Activation (%s) Stage 3 of 5 (IP Configure Start) started"
|
||||||
|
" avahi-autoipd...", iface);
|
||||||
|
ret = NM_ACT_STAGE_RETURN_POSTPONE;
|
||||||
|
} else {
|
||||||
|
nm_info ("Activation (%s) Stage 3 of 5 (IP Configure Start) failed"
|
||||||
|
" to start avahi-autoipd: %s", iface, error->message);
|
||||||
|
g_error_free (error);
|
||||||
|
aipd_cleanup (self);
|
||||||
|
ret = NM_ACT_STAGE_RETURN_FAILURE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@@ -625,35 +913,6 @@ nm_device_activate_schedule_stage3_ip_config_start (NMDevice *self)
|
|||||||
nm_device_get_iface (self));
|
nm_device_get_iface (self));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* nm_device_new_ip4_autoip_config
|
|
||||||
*
|
|
||||||
* Build up an IP config with a Link Local address
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
static NMIP4Config *
|
|
||||||
nm_device_new_ip4_autoip_config (NMDevice *self)
|
|
||||||
{
|
|
||||||
struct in_addr ip;
|
|
||||||
NMIP4Config *config = NULL;
|
|
||||||
NMSettingIP4Address *addr;
|
|
||||||
|
|
||||||
g_return_val_if_fail (self != NULL, NULL);
|
|
||||||
|
|
||||||
// FIXME: make our autoip implementation not suck; use avahi-autoip
|
|
||||||
if (!get_autoip (self, &ip))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
config = nm_ip4_config_new ();
|
|
||||||
addr = g_malloc0 (sizeof (NMSettingIP4Address));
|
|
||||||
addr->address = (guint32) ip.s_addr;
|
|
||||||
addr->prefix = 16;
|
|
||||||
nm_ip4_config_take_address (config, addr);
|
|
||||||
|
|
||||||
return config;
|
|
||||||
}
|
|
||||||
|
|
||||||
static GHashTable *shared_ips = NULL;
|
static GHashTable *shared_ips = NULL;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -735,7 +994,7 @@ real_act_stage4_get_ip4_config (NMDevice *self,
|
|||||||
g_assert (s_ip4);
|
g_assert (s_ip4);
|
||||||
|
|
||||||
if (!strcmp (s_ip4->method, NM_SETTING_IP4_CONFIG_METHOD_AUTOIP)) {
|
if (!strcmp (s_ip4->method, NM_SETTING_IP4_CONFIG_METHOD_AUTOIP)) {
|
||||||
*config = nm_device_new_ip4_autoip_config (self);
|
*config = aipd_get_ip4_config (self);
|
||||||
} else if (!strcmp (s_ip4->method, NM_SETTING_IP4_CONFIG_METHOD_MANUAL)) {
|
} else if (!strcmp (s_ip4->method, NM_SETTING_IP4_CONFIG_METHOD_MANUAL)) {
|
||||||
*config = nm_ip4_config_new ();
|
*config = nm_ip4_config_new ();
|
||||||
if (*config)
|
if (*config)
|
||||||
@@ -879,7 +1138,7 @@ out:
|
|||||||
/*
|
/*
|
||||||
* nm_device_activate_schedule_stage4_ip_config_timeout
|
* nm_device_activate_schedule_stage4_ip_config_timeout
|
||||||
*
|
*
|
||||||
* Deal with a timed out DHCP transaction
|
* Deal with a timeout of the IP configuration
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
@@ -1057,6 +1316,8 @@ nm_device_deactivate_quickly (NMDevice *self)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
aipd_cleanup (self);
|
||||||
|
|
||||||
/* Tear down an existing activation request */
|
/* Tear down an existing activation request */
|
||||||
clear_act_request (self);
|
clear_act_request (self);
|
||||||
|
|
||||||
@@ -1343,7 +1604,7 @@ dhcp_timeout (NMDHCPManager *dhcp_manager,
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (nm_device_get_state (device) == NM_DEVICE_STATE_IP_CONFIG)
|
if (nm_device_get_state (device) == NM_DEVICE_STATE_IP_CONFIG)
|
||||||
nm_device_activate_schedule_stage4_ip_config_timeout (device);
|
nm_device_activate_schedule_stage4_ip_config_timeout (device);
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
@@ -1494,7 +1755,7 @@ nm_device_is_up (NMDevice *self)
|
|||||||
}
|
}
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
nm_device_hw_bring_up (NMDevice *self, gboolean wait)
|
nm_device_hw_bring_up (NMDevice *self, gboolean do_wait)
|
||||||
{
|
{
|
||||||
gboolean success;
|
gboolean success;
|
||||||
guint32 tries = 0;
|
guint32 tries = 0;
|
||||||
@@ -1513,7 +1774,7 @@ nm_device_hw_bring_up (NMDevice *self, gboolean wait)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Wait for the device to come up if requested */
|
/* Wait for the device to come up if requested */
|
||||||
while (wait && !nm_device_hw_is_up (self) && (tries++ < 50))
|
while (do_wait && !nm_device_hw_is_up (self) && (tries++ < 50))
|
||||||
g_usleep (200);
|
g_usleep (200);
|
||||||
|
|
||||||
if (!nm_device_hw_is_up (self)) {
|
if (!nm_device_hw_is_up (self)) {
|
||||||
@@ -1531,7 +1792,7 @@ out:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
nm_device_hw_take_down (NMDevice *self, gboolean wait)
|
nm_device_hw_take_down (NMDevice *self, gboolean do_wait)
|
||||||
{
|
{
|
||||||
guint32 tries = 0;
|
guint32 tries = 0;
|
||||||
|
|
||||||
@@ -1546,18 +1807,18 @@ nm_device_hw_take_down (NMDevice *self, gboolean wait)
|
|||||||
NM_DEVICE_GET_CLASS (self)->hw_take_down (self);
|
NM_DEVICE_GET_CLASS (self)->hw_take_down (self);
|
||||||
|
|
||||||
/* Wait for the device to come up if requested */
|
/* Wait for the device to come up if requested */
|
||||||
while (wait && nm_device_hw_is_up (self) && (tries++ < 50))
|
while (do_wait && nm_device_hw_is_up (self) && (tries++ < 50))
|
||||||
g_usleep (200);
|
g_usleep (200);
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
nm_device_bring_up (NMDevice *self, gboolean wait)
|
nm_device_bring_up (NMDevice *self, gboolean do_wait)
|
||||||
{
|
{
|
||||||
gboolean success;
|
gboolean success;
|
||||||
|
|
||||||
g_return_val_if_fail (NM_IS_DEVICE (self), FALSE);
|
g_return_val_if_fail (NM_IS_DEVICE (self), FALSE);
|
||||||
|
|
||||||
if (!nm_device_hw_bring_up (self, wait))
|
if (!nm_device_hw_bring_up (self, do_wait))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
if (nm_device_is_up (self))
|
if (nm_device_is_up (self))
|
||||||
@@ -1575,7 +1836,7 @@ nm_device_bring_up (NMDevice *self, gboolean wait)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
nm_device_take_down (NMDevice *self, gboolean wait)
|
nm_device_take_down (NMDevice *self, gboolean do_wait)
|
||||||
{
|
{
|
||||||
g_return_if_fail (NM_IS_DEVICE (self));
|
g_return_if_fail (NM_IS_DEVICE (self));
|
||||||
|
|
||||||
@@ -1589,7 +1850,7 @@ nm_device_take_down (NMDevice *self, gboolean wait)
|
|||||||
NM_DEVICE_GET_CLASS (self)->take_down (self);
|
NM_DEVICE_GET_CLASS (self)->take_down (self);
|
||||||
}
|
}
|
||||||
|
|
||||||
nm_device_hw_take_down (self, wait);
|
nm_device_hw_take_down (self, do_wait);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@@ -19,6 +19,9 @@
|
|||||||
#include "nm-dbus-glib-types.h"
|
#include "nm-dbus-glib-types.h"
|
||||||
#include "nm-hal-manager.h"
|
#include "nm-hal-manager.h"
|
||||||
|
|
||||||
|
#define NM_AUTOIP_DBUS_SERVICE "org.freedesktop.nm_avahi_autoipd"
|
||||||
|
#define NM_AUTOIP_DBUS_IFACE "org.freedesktop.nm_avahi_autoipd"
|
||||||
|
|
||||||
static gboolean impl_manager_get_devices (NMManager *manager, GPtrArray **devices, GError **err);
|
static gboolean impl_manager_get_devices (NMManager *manager, GPtrArray **devices, GError **err);
|
||||||
static void impl_manager_activate_connection (NMManager *manager,
|
static void impl_manager_activate_connection (NMManager *manager,
|
||||||
const char *service_name,
|
const char *service_name,
|
||||||
@@ -108,6 +111,8 @@ typedef struct {
|
|||||||
NMVPNManager *vpn_manager;
|
NMVPNManager *vpn_manager;
|
||||||
guint vpn_manager_id;
|
guint vpn_manager_id;
|
||||||
|
|
||||||
|
DBusGProxy *aipd_proxy;
|
||||||
|
|
||||||
gboolean disposed;
|
gboolean disposed;
|
||||||
} NMManagerPrivate;
|
} NMManagerPrivate;
|
||||||
|
|
||||||
@@ -210,10 +215,50 @@ vpn_manager_connection_deactivated_cb (NMVPNManager *manager,
|
|||||||
g_object_notify (G_OBJECT (user_data), NM_MANAGER_ACTIVE_CONNECTIONS);
|
g_object_notify (G_OBJECT (user_data), NM_MANAGER_ACTIVE_CONNECTIONS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
aipd_handle_event (DBusGProxy *proxy,
|
||||||
|
const char *event,
|
||||||
|
const char *iface,
|
||||||
|
const char *address,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
NMManager *manager = NM_MANAGER (user_data);
|
||||||
|
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
|
||||||
|
GSList *iter;
|
||||||
|
gboolean handled;
|
||||||
|
|
||||||
|
if (!event || !iface) {
|
||||||
|
nm_warning ("Incomplete message received from avahi-autoipd");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( (strcmp (event, "BIND") != 0)
|
||||||
|
&& (strcmp (event, "CONFLICT") != 0)
|
||||||
|
&& (strcmp (event, "UNBIND") != 0)
|
||||||
|
&& (strcmp (event, "STOP") != 0)) {
|
||||||
|
nm_warning ("Unknown event '%s' received from avahi-autoipd", event);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (iter = priv->devices; iter; iter = g_slist_next (iter)) {
|
||||||
|
NMDevice *candidate = NM_DEVICE (iter->data);
|
||||||
|
|
||||||
|
if (!strcmp (nm_device_get_iface (candidate), iface)) {
|
||||||
|
nm_device_handle_autoip4_event (candidate, event, address);
|
||||||
|
handled = TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!handled)
|
||||||
|
nm_warning ("Unhandled avahi-autoipd event for '%s'", iface);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
nm_manager_init (NMManager *manager)
|
nm_manager_init (NMManager *manager)
|
||||||
{
|
{
|
||||||
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
|
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
|
||||||
|
DBusGConnection *g_connection;
|
||||||
guint id;
|
guint id;
|
||||||
|
|
||||||
priv->wireless_enabled = TRUE;
|
priv->wireless_enabled = TRUE;
|
||||||
@@ -237,6 +282,29 @@ nm_manager_init (NMManager *manager)
|
|||||||
id = g_signal_connect (G_OBJECT (priv->vpn_manager), "connection-deactivated",
|
id = g_signal_connect (G_OBJECT (priv->vpn_manager), "connection-deactivated",
|
||||||
G_CALLBACK (vpn_manager_connection_deactivated_cb), manager);
|
G_CALLBACK (vpn_manager_connection_deactivated_cb), manager);
|
||||||
priv->vpn_manager_id = id;
|
priv->vpn_manager_id = id;
|
||||||
|
|
||||||
|
g_connection = nm_dbus_manager_get_connection (priv->dbus_mgr);
|
||||||
|
priv->aipd_proxy = dbus_g_proxy_new_for_name (g_connection,
|
||||||
|
NM_AUTOIP_DBUS_SERVICE,
|
||||||
|
"/",
|
||||||
|
NM_AUTOIP_DBUS_IFACE);
|
||||||
|
if (priv->aipd_proxy) {
|
||||||
|
dbus_g_object_register_marshaller (nm_marshal_VOID__STRING_STRING_STRING,
|
||||||
|
G_TYPE_NONE,
|
||||||
|
G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
|
||||||
|
G_TYPE_INVALID);
|
||||||
|
|
||||||
|
dbus_g_proxy_add_signal (priv->aipd_proxy,
|
||||||
|
"Event",
|
||||||
|
G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
|
||||||
|
G_TYPE_INVALID);
|
||||||
|
|
||||||
|
dbus_g_proxy_connect_signal (priv->aipd_proxy, "Event",
|
||||||
|
G_CALLBACK (aipd_handle_event),
|
||||||
|
manager,
|
||||||
|
NULL);
|
||||||
|
} else
|
||||||
|
nm_warning ("Could not initialize avahi-autoipd D-Bus proxy");
|
||||||
}
|
}
|
||||||
|
|
||||||
NMState
|
NMState
|
||||||
|
Reference in New Issue
Block a user