summaryrefslogtreecommitdiff
path: root/sbin/dhclient
diff options
context:
space:
mode:
authorTheo de Raadt <deraadt@cvs.openbsd.org>2006-08-29 03:55:10 +0000
committerTheo de Raadt <deraadt@cvs.openbsd.org>2006-08-29 03:55:10 +0000
commita652f988dfa9a2e2c1c9cfca94dff4dbb275a3cf (patch)
treebd1c12745606a8c47c34dbfcd3431253eea3e539 /sbin/dhclient
parent80010d966b61c52ba3916dc4df1db9977f0e3b27 (diff)
some net if devices do not media negotiate (for link) until brought up.
(for some drivers, this is a bug. for others, it is part of how they work) therefore before doing the 10-second link test, we must bring the if up. ok krw, tested marco ckuethe
Diffstat (limited to 'sbin/dhclient')
-rw-r--r--sbin/dhclient/dhclient.c10
-rw-r--r--sbin/dhclient/dhcpd.h4
-rw-r--r--sbin/dhclient/dispatch.c59
3 files changed, 68 insertions, 5 deletions
diff --git a/sbin/dhclient/dhclient.c b/sbin/dhclient/dhclient.c
index fcd364d5794..e640643c415 100644
--- a/sbin/dhclient/dhclient.c
+++ b/sbin/dhclient/dhclient.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: dhclient.c,v 1.86 2006/06/16 16:17:16 reyk Exp $ */
+/* $OpenBSD: dhclient.c,v 1.87 2006/08/29 03:55:08 deraadt Exp $ */
/*
* Copyright 2004 Henning Brauer <henning@openbsd.org>
@@ -243,7 +243,7 @@ die:
int
main(int argc, char *argv[])
{
- int ch, fd, quiet = 0, i = 0, pipe_fd[2];
+ int ch, fd, quiet = 0, i = 0, pipe_fd[2], linkstat;
extern char *__progname;
struct passwd *pw;
@@ -309,10 +309,14 @@ main(int argc, char *argv[])
read_client_conf();
+ linkstat = interface_link_forceup(ifi->name);
+
if (!interface_link_status(ifi->name)) {
fprintf(stderr, "%s: no link ...", ifi->name);
if (ifi->client->config->link_timeout == 0) {
fprintf(stderr, " giving up\n");
+ if (linkstat == 0)
+ interface_link_forcedown(ifi->name);
exit(1);
}
fflush(stderr);
@@ -322,6 +326,8 @@ main(int argc, char *argv[])
fflush(stderr);
if (++i > ifi->client->config->link_timeout) {
fprintf(stderr, " giving up\n");
+ if (linkstat == 0)
+ interface_link_forcedown(ifi->name);
exit(1);
}
sleep(1);
diff --git a/sbin/dhclient/dhcpd.h b/sbin/dhclient/dhcpd.h
index b0e07aa4f93..a5e18f1250c 100644
--- a/sbin/dhclient/dhcpd.h
+++ b/sbin/dhclient/dhcpd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: dhcpd.h,v 1.48 2006/05/08 17:25:59 deraadt Exp $ */
+/* $OpenBSD: dhcpd.h,v 1.49 2006/08/29 03:55:09 deraadt Exp $ */
/*
* Copyright (c) 2004 Henning Brauer <henning@openbsd.org>
@@ -286,6 +286,8 @@ void cancel_timeout(void (*)(void *), void *);
void add_protocol(char *, int, void (*)(struct protocol *), void *);
void remove_protocol(struct protocol *);
int interface_link_status(char *);
+int interface_link_forceup(char *);
+void interface_link_forcedown(char *);
/* tables.c */
extern const struct option dhcp_options[256];
diff --git a/sbin/dhclient/dispatch.c b/sbin/dhclient/dispatch.c
index 5b4f350eb45..5ce380f61cb 100644
--- a/sbin/dhclient/dispatch.c
+++ b/sbin/dhclient/dispatch.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: dispatch.c,v 1.32 2005/05/24 03:11:12 todd Exp $ */
+/* $OpenBSD: dispatch.c,v 1.33 2006/08/29 03:55:09 deraadt Exp $ */
/*
* Copyright 2004 Henning Brauer <henning@openbsd.org>
@@ -220,7 +220,6 @@ another:
} while (1);
}
-
void
got_one(struct protocol *l)
{
@@ -269,6 +268,62 @@ got_one(struct protocol *l)
}
int
+interface_link_forceup(char *ifname)
+{
+ struct ifreq ifr;
+ int sock, ret = 0;
+
+ if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
+ error("Can't create socket");
+
+ memset(&ifr, 0, sizeof(ifr));
+ strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+ if (ioctl(sock, SIOCGIFFLAGS, (caddr_t)&ifr) == -1) {
+ close(sock);
+ return (-1);
+ }
+
+ if ((ifr.ifr_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
+ ifr.ifr_flags |= IFF_UP;
+ if (ioctl(sock, SIOCSIFFLAGS, (caddr_t)&ifr) == -1) {
+ close(sock);
+ return (-1);
+ }
+ close(sock);
+ return (0);
+ }
+ close(sock);
+ return (1);
+}
+
+void
+interface_link_forcedown(char *ifname)
+{
+ struct ifreq ifr;
+ int sock;
+
+ if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
+ error("Can't create socket");
+
+ memset(&ifr, 0, sizeof(ifr));
+ strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+ if (ioctl(sock, SIOCGIFFLAGS, (caddr_t)&ifr) == -1) {
+ close(sock);
+ return;
+ }
+
+ if ((ifr.ifr_flags & IFF_UP) == IFF_UP) {
+ ifr.ifr_flags &= ~IFF_UP;
+ if (ioctl(sock, SIOCSIFFLAGS, (caddr_t)&ifr) == -1) {
+ close(sock);
+ return;
+ }
+ }
+
+ close(sock);
+}
+
+int
interface_status(struct interface_info *ifinfo)
{
char *ifname = ifinfo->name;