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