Home | History | Annotate | Download | only in dhcpcd
      1 /*
      2  * dhcpcd - DHCP client daemon
      3  * Copyright (c) 2006-2011 Roy Marples <roy (at) marples.name>
      4  * All rights reserved
      5 
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  * 1. Redistributions of source code must retain the above copyright
     10  *    notice, this list of conditions and the following disclaimer.
     11  * 2. Redistributions in binary form must reproduce the above copyright
     12  *    notice, this list of conditions and the following disclaimer in the
     13  *    documentation and/or other materials provided with the distribution.
     14  *
     15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     25  * SUCH DAMAGE.
     26  */
     27 
     28 #include <errno.h>
     29 #include <signal.h>
     30 #include <stdlib.h>
     31 #include <string.h>
     32 #include <syslog.h>
     33 #include <unistd.h>
     34 
     35 #include "arp.h"
     36 #include "common.h"
     37 #include "dhcpcd.h"
     38 #include "eloop.h"
     39 #include "if-options.h"
     40 #include "ipv4ll.h"
     41 #include "net.h"
     42 
     43 static struct dhcp_message *
     44 make_ipv4ll_lease(uint32_t addr)
     45 {
     46 	uint32_t u32;
     47 	struct dhcp_message *dhcp;
     48 	uint8_t *p;
     49 
     50 	dhcp = xzalloc(sizeof(*dhcp));
     51 	/* Put some LL options in */
     52 	dhcp->yiaddr = addr;
     53 	p = dhcp->options;
     54 	*p++ = DHO_SUBNETMASK;
     55 	*p++ = sizeof(u32);
     56 	u32 = htonl(LINKLOCAL_MASK);
     57 	memcpy(p, &u32, sizeof(u32));
     58 	p += sizeof(u32);
     59 	*p++ = DHO_BROADCAST;
     60 	*p++ = sizeof(u32);
     61 	u32 = htonl(LINKLOCAL_BRDC);
     62 	memcpy(p, &u32, sizeof(u32));
     63 	p += sizeof(u32);
     64 	*p++ = DHO_END;
     65 
     66 	return dhcp;
     67 }
     68 
     69 static struct dhcp_message *
     70 find_ipv4ll_lease(uint32_t old_addr)
     71 {
     72 	uint32_t addr;
     73 
     74 	for (;;) {
     75 		addr = htonl(LINKLOCAL_ADDR |
     76 		    (((uint32_t)abs((int)arc4random())
     77 			% 0xFD00) + 0x0100));
     78 		if (addr != old_addr &&
     79 		    IN_LINKLOCAL(ntohl(addr)))
     80 			break;
     81 	}
     82 	return make_ipv4ll_lease(addr);
     83 }
     84 
     85 void
     86 start_ipv4ll(void *arg)
     87 {
     88 	struct interface *iface = arg;
     89 	uint32_t addr;
     90 
     91 	delete_timeout(NULL, iface);
     92 	iface->state->probes = 0;
     93 	iface->state->claims = 0;
     94 	if (iface->addr.s_addr) {
     95 		iface->state->conflicts = 0;
     96 		if (IN_LINKLOCAL(htonl(iface->addr.s_addr))) {
     97 			send_arp_announce(iface);
     98 			return;
     99 		}
    100 	}
    101 
    102 	if (iface->state->offer == NULL)
    103 		addr = 0;
    104 	else {
    105 		addr = iface->state->offer->yiaddr;
    106 		free(iface->state->offer);
    107 	}
    108 	/* We maybe rebooting an IPv4LL address. */
    109 	if (!IN_LINKLOCAL(htonl(addr))) {
    110 		syslog(LOG_INFO, "%s: probing for an IPv4LL address",
    111 		    iface->name);
    112 		addr = 0;
    113 	}
    114 	if (addr == 0)
    115 		iface->state->offer = find_ipv4ll_lease(addr);
    116 	else
    117 		iface->state->offer = make_ipv4ll_lease(addr);
    118 	iface->state->lease.frominfo = 0;
    119 	send_arp_probe(iface);
    120 }
    121 
    122 void
    123 handle_ipv4ll_failure(void *arg)
    124 {
    125 	struct interface *iface = arg;
    126 	time_t up;
    127 
    128 	if (iface->state->fail.s_addr == iface->addr.s_addr) {
    129 		up = uptime();
    130 		if (iface->state->defend + DEFEND_INTERVAL > up) {
    131 			syslog(LOG_DEBUG,
    132 			    "%s: IPv4LL %d second defence failed",
    133 			    iface->name, DEFEND_INTERVAL);
    134 			drop_dhcp(iface, "EXPIRE");
    135 			iface->state->conflicts = -1;
    136 		} else {
    137 			syslog(LOG_DEBUG, "%s: defended IPv4LL address",
    138 			    iface->name);
    139 			iface->state->defend = up;
    140 			return;
    141 		}
    142 	}
    143 
    144 	close_sockets(iface);
    145 	free(iface->state->offer);
    146 	iface->state->offer = NULL;
    147 	delete_timeout(NULL, iface);
    148 	if (++iface->state->conflicts > MAX_CONFLICTS) {
    149 		syslog(LOG_ERR, "%s: failed to acquire an IPv4LL address",
    150 		    iface->name);
    151 		iface->state->interval = RATE_LIMIT_INTERVAL / 2;
    152 		start_discover(iface);
    153 	} else {
    154 		add_timeout_sec(PROBE_WAIT, start_ipv4ll, iface);
    155 	}
    156 }
    157