]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
Add more error checking if the link was taken down or ip addresses removed - if this...
authorRoy Marples <roy@marples.name>
Wed, 9 Jul 2008 06:50:31 +0000 (06:50 +0000)
committerRoy Marples <roy@marples.name>
Wed, 9 Jul 2008 06:50:31 +0000 (06:50 +0000)
client.c
net.c
net.h

index d552f3a91f8c7170c5eba9fb0f3b83f654860d87..7c74d80ebe64a0ed5e3bdf7d8bf07fe141ac41d0 100644 (file)
--- a/client.c
+++ b/client.c
@@ -585,17 +585,11 @@ do_socket(struct if_state *state, int mode)
                state->interface->udp_fd = -1;
        }
 
-       /* We need to bind to a port, otherwise we generate ICMP messages
-        * that cannot connect the port when we have an address.
-        * We don't actually use this fd at all, instead using our packet
-        * filter socket. */
        if (mode == SOCKET_OPEN &&
            state->interface->udp_fd == -1 &&
-           state->lease.addr.s_addr != 0)
-               if (open_udp_socket(state->interface) == -1) {
-                       logger(LOG_ERR, "open_udp_socket: %s", strerror(errno));
-                       return -1;
-               }
+           state->lease.addr.s_addr != 0 &&
+           open_udp_socket(state->interface) == -1)
+               logger(LOG_ERR, "open_udp_socket: %s", strerror(errno));
 
        if (mode == SOCKET_OPEN) 
                if (open_socket(state->interface, ETHERTYPE_IP) == -1) {
@@ -615,12 +609,22 @@ send_message(struct if_state *state, int type, const struct options *options)
        ssize_t r;
        struct in_addr from;
        struct in_addr to;
+       in_addr_t a = 0;
 
        logger(LOG_DEBUG, "sending %s with xid 0x%x",
               get_dhcp_op(type), state->xid);
        state->messages++;
+       /* If we couldn't open a UDP port for our IP address
+        * then we cannot renew.
+        * This could happen if our IP was pulled out from underneath us. */
+       if (state->interface->udp_fd == -1) {
+               a = state->interface->addr.s_addr;
+               state->interface->addr.s_addr = 0;
+       }
        len = make_message(&dhcp, state->interface, &state->lease, state->xid,
                           type, options);
+       if (state->interface->udp_fd == -1)
+               state->interface->addr.s_addr = a;
        from.s_addr = dhcp->ciaddr;
        if (from.s_addr)
                to.s_addr = state->lease.server.s_addr;
@@ -634,9 +638,17 @@ send_message(struct if_state *state, int type, const struct options *options)
                len = make_udp_packet(&udp, (uint8_t *)dhcp, len, from, to);
                free(dhcp);
                r = send_raw_packet(state->interface, ETHERTYPE_IP, udp, len);
+               free(udp);
                if (r == -1)
                        logger(LOG_ERR, "send_raw_packet: %s", strerror(errno));
-               free(udp);
+       }
+
+       /* Failed to send the packet? Return to the init state */
+       if (r == -1) {
+               state->state = STATE_INIT;
+               state->timeout = 0;
+               timerclear(&state->stop);
+               do_socket(state, SOCKET_CLOSED);
        }
        return r;
 }
@@ -710,6 +722,24 @@ wait_for_packet(struct if_state *state)
                if (errno == EINTR)
                        return 0;
                logger(LOG_ERR, "poll: %s", strerror(errno));
+       } else if (retval != 0) {
+               /* Check if any of the fd's have an error */
+               while (nfds-- > 0) {
+                       if (fds[nfds].revents & POLLERR) {
+                               logger(LOG_ERR, "error on fd %d", fds[nfds].fd);
+                               switch(state->state) {
+                               case STATE_INIT: /* FALLTHROUGH */
+                               case STATE_DISCOVERING: /* FALLTHROUGH */
+                               case STATE_REQUESTING: /* FALLTHROUGH */
+                                       state->state = STATE_INIT;
+                               default:
+                                       state->state = STATE_RENEW_REQUESTED;
+                               }
+                               state->timeout = 0;
+                               timerclear(&state->stop);
+                               return 0;
+                       }
+               }
        }
        return retval;
 }
@@ -1059,6 +1089,7 @@ handle_timeout(struct if_state *state, const struct options *options)
        case STATE_INIT:  /* FALLTHROUGH */
        case STATE_BOUND: /* FALLTHROUGH */
        case STATE_RENEW_REQUESTED:
+               up_interface(iface->name);
                do_socket(state, SOCKET_OPEN);
                state->xid = arc4random();
                state->messages = 0;
diff --git a/net.c b/net.c
index 74dace15d189c6437d6a1ef44cb17b6bd7923487..fa1b7c9284f2da869058be14b8c29424abba6801 100644 (file)
--- a/net.c
+++ b/net.c
@@ -278,6 +278,38 @@ do_interface(const char *ifname,
        return retval;
 }
 
+int
+up_interface(const char *ifname)
+{
+       int s;
+       struct ifreq ifr;
+       int retval = -1;
+#ifdef __linux__
+       char *p;
+#endif
+
+       if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
+               return -1;
+       memset(&ifr, 0, sizeof(ifr));
+       strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+#ifdef __linux__
+       /* We can only bring the real interface up */
+       if ((p = strchr(ifr.ifr_name, ':')))
+               *p = '\0';
+#endif
+       if (ioctl(s, SIOCGIFFLAGS, &ifr) == 0) {
+               if ((ifr.ifr_flags & IFF_UP))
+                       retval = 0;
+               else {
+                       ifr.ifr_flags |= IFF_UP;
+                       if (ioctl(s, SIOCSIFFLAGS, &ifr) == 0)
+                               retval = 0;
+               }
+       }
+       close(s);
+       return retval;
+}
+
 struct interface *
 read_interface(const char *ifname, _unused int metric)
 {
@@ -287,9 +319,6 @@ read_interface(const char *ifname, _unused int metric)
        unsigned char *hwaddr = NULL;
        size_t hwlen = 0;
        sa_family_t family = 0;
-#ifdef __linux__
-       char *p;
-#endif
 
        memset(&ifr, 0, sizeof(ifr));
        strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
@@ -342,20 +371,8 @@ read_interface(const char *ifname, _unused int metric)
                        goto eexit;
        }
 
-       /* Bring the interface up if it's down */
-       strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
-#ifdef __linux__
-       /* We can only bring the real interface up */
-       if ((p = strchr(ifr.ifr_name, ':')))
-               *p = '\0';
-#endif
-       if (ioctl(s, SIOCGIFFLAGS, &ifr) == -1)
+       if (up_interface(ifname) != 0)
                goto eexit;
-       if (!(ifr.ifr_flags & IFF_UP)) {
-               ifr.ifr_flags |= IFF_UP;
-               if (ioctl(s, SIOCSIFFLAGS, &ifr) != 0)
-                       goto eexit;
-       }
 
        iface = xzalloc(sizeof(*iface));
        strlcpy(iface->name, ifname, IF_NAMESIZE);
diff --git a/net.h b/net.h
index 0be56cf542b9517aef985f5844df9e12d30f36e0..3b030eb242b2f0c1e54cc78d071f58985c09d08b 100644 (file)
--- a/net.h
+++ b/net.h
@@ -131,6 +131,7 @@ int do_mtu(const char *, short int);
 int inet_ntocidr(struct in_addr);
 int inet_cidrtoaddr(int, struct in_addr *);
 
+int up_interface(const char *);
 int do_interface(const char *, unsigned char *, size_t *,
                 struct in_addr *, struct in_addr *, int);
 int if_address(const char *, const struct in_addr *, const struct in_addr *,