diff options
author | Theo de Raadt <deraadt@cvs.openbsd.org> | 2006-08-29 03:55:10 +0000 |
---|---|---|
committer | Theo de Raadt <deraadt@cvs.openbsd.org> | 2006-08-29 03:55:10 +0000 |
commit | a652f988dfa9a2e2c1c9cfca94dff4dbb275a3cf (patch) | |
tree | bd1c12745606a8c47c34dbfcd3431253eea3e539 /sbin/dhclient | |
parent | 80010d966b61c52ba3916dc4df1db9977f0e3b27 (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.c | 10 | ||||
-rw-r--r-- | sbin/dhclient/dhcpd.h | 4 | ||||
-rw-r--r-- | sbin/dhclient/dispatch.c | 59 |
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; |