summaryrefslogtreecommitdiffstats
path: root/net.c
diff options
context:
space:
mode:
authorRoy Marples <roy@marples.name>2008-06-08 20:07:54 +0000
committerRoy Marples <roy@marples.name>2008-06-08 20:07:54 +0000
commit5fb580a7713ca5bca9b7238a57977f1d739cdd46 (patch)
tree1f10e990c22847a6f203107b2b90365ad9a91122 /net.c
parent27e5226dc33c91862912b03c1f3d9162579dbcac (diff)
downloaddhcpcd-5fb580a7713ca5bca9b7238a57977f1d739cdd46.tar.xz
Re-write the client state engine around a simple timer instead of complex loops. Use the re-transmission times as per RFC 2131. Integrate the ARP handling code in the new engine so we are able to defend our IPV4LL address whilst negotiating a DHCP lease. This also means we're able to bind the address and fork BEFORE waiting to send announcements which makes us appear faster on the commandline.
Diffstat (limited to 'net.c')
-rw-r--r--net.c203
1 files changed, 11 insertions, 192 deletions
diff --git a/net.c b/net.c
index 1a05f91e..aa530ba2 100644
--- a/net.c
+++ b/net.c
@@ -367,6 +367,9 @@ read_interface(const char *ifname, _unused int metric)
/* 0 is a valid fd, so init to -1 */
iface->fd = -1;
iface->udp_fd = -1;
+#ifdef ENABLE_ARP
+ iface->arp_fd = -1;
+#endif
eexit:
close(s);
@@ -464,6 +467,7 @@ struct udp_dhcp_packet
struct udphdr udp;
struct dhcp_message dhcp;
};
+const size_t udp_dhcp_len = sizeof(struct udp_dhcp_packet);
static uint16_t
checksum(const void *data, uint16_t len)
@@ -591,9 +595,8 @@ valid_udp_packet(const uint8_t *data)
}
#ifdef ENABLE_ARP
-static int
-send_arp(const struct interface *iface, int op, struct in_addr sip,
- const unsigned char *taddr, struct in_addr tip)
+int
+send_arp(const struct interface *iface, int op, in_addr_t sip, in_addr_t tip)
{
struct arphdr *arp;
size_t arpsize;
@@ -602,7 +605,7 @@ send_arp(const struct interface *iface, int op, struct in_addr sip,
arpsize = sizeof(*arp) + 2 * iface->hwlen + 2 *sizeof(sip);
- arp = xzalloc(arpsize);
+ arp = xmalloc(arpsize);
arp->ar_hrd = htons(iface->family);
arp->ar_pro = htons(ETHERTYPE_IP);
arp->ar_hln = iface->hwlen;
@@ -614,199 +617,15 @@ send_arp(const struct interface *iface, int op, struct in_addr sip,
p += iface->hwlen;
memcpy(p, &sip, sizeof(sip));
p += sizeof(sip);
-
- if (taddr != NULL)
- memcpy(p, taddr, iface->hwlen);
- else
- memset(p, 0, iface->hwlen);
+ /* ARP requests should ignore this, but we fill with 0xff
+ * for broadcast. */
+ memset(p, 0xff, iface->hwlen);
p += iface->hwlen;
memcpy(p, &tip, sizeof(tip));
retval = send_raw_packet(iface, ETHERTYPE_ARP, arp, arpsize);
- if (retval == -1)
- logger(LOG_ERR,"send_packet: %s", strerror(errno));
free(arp);
return retval;
}
-
-int
-arp_claim(struct interface *iface, struct in_addr address)
-{
- struct arphdr reply;
- struct in_addr reply_s;
- struct in_addr reply_t;
- uint8_t arp_reply[sizeof(reply) + 2 * sizeof(reply_s) + 2 * HWADDR_LEN];
- uint8_t *hw_s, *hw_t;
- long timeout;
- int retval = -1;
- int nprobes = 0;
- int nclaims = 0;
- struct in_addr null_addr;
- struct pollfd fds[] = {
- { -1, POLLIN, 0 },
- { -1, POLLIN, 0 }
- };
- int bytes;
- int s;
- struct timeval stopat;
- struct timeval now;
-
- if (!iface->arpable) {
- logger(LOG_DEBUG, "interface `%s' is not ARPable", iface->name);
- return 0;
- }
-
- if (!IN_LINKLOCAL(ntohl(iface->addr.s_addr)) ||
- !IN_LINKLOCAL(ntohl(address.s_addr)))
- logger(LOG_INFO,
- "checking %s is available on attached networks",
- inet_ntoa(address));
-
- timeout = arc4random() % PROBE_WAIT;
- if (get_time(&stopat) != 0)
- return -1;
- stopat.tv_usec += timeout * 1000;
-
- if (open_socket(iface, ETHERTYPE_ARP) == -1) {
- logger (LOG_ERR, "open_socket: %s", strerror(errno));
- return -1;
- }
-
- fds[0].fd = signal_fd();
- fds[1].fd = iface->fd;
- memset(&null_addr, 0, sizeof(null_addr));
-
- for (;;) {
- /* Only poll if we have a timeout */
- if (timeout > 0) {
- /* Obey IPV4LL timings, but make us faster for
- * routeable addresses */
- if (!IN_LINKLOCAL(htonl(address.s_addr)))
- timeout /= 6;
- s = poll(fds, 2, timeout);
- if (s == -1) {
- if (errno != EINTR)
- logger(LOG_ERR, "poll: `%s'",
- strerror(errno));
- break;
- }
- } else
- s = 0;
-
- /* Timed out */
- if (s == 0) {
- if (nprobes < PROBE_NUM) {
- nprobes++;
- timeout = (arc4random() %
- (PROBE_MAX - PROBE_MIN)) +
- PROBE_MIN;
- logger(LOG_DEBUG, "sending ARP probe #%d",
- nprobes);
- if (send_arp(iface, ARPOP_REQUEST,
- null_addr, NULL,
- address) == -1)
- break;
-
- /* IEEE1394 cannot set ARP target address
- * according to RFC2734 */
- if (nprobes >= PROBE_NUM &&
- iface->family == ARPHRD_IEEE1394)
- nclaims = ANNOUNCE_NUM;
- } else if (nclaims < ANNOUNCE_NUM) {
- nclaims++;
- timeout = ANNOUNCE_INTERVAL;
- /* Kernel will send the last ARP when we add
- * the address. */
- if (nclaims < ANNOUNCE_NUM) {
- logger(LOG_DEBUG,
- "sending ARP claim #%d",
- nclaims);
- if (send_arp(iface, ARPOP_REQUEST,
- address, iface->hwaddr,
- address) == -1)
- break;
- }
- } else {
- /* No replies, so done */
- retval = 0;
- break;
- }
-
- /* Setup our stop time */
- if (get_time(&stopat) != 0)
- break;
- stopat.tv_usec += timeout * 1000;
- continue;
- }
-
- /* We maybe ARP flooded, so check our time */
- if (get_time(&now) != 0)
- break;
- if (timercmp(&now, &stopat, >)) {
- timeout = 0;
- continue;
- }
-
- /* Check if signalled */
- if ((fds[0].revents & POLLIN)) {
- errno = EINTR;
- return -1;
- }
-
- if (!(fds[1].revents & POLLIN))
- continue;
- for(;;) {
- memset(arp_reply, 0, sizeof(arp_reply));
- bytes = get_packet(iface,
- arp_reply, sizeof(arp_reply));
- if (bytes == -1 || bytes == 0)
- break;
-
- /* We must have a full ARP header */
- if ((size_t)bytes < sizeof(reply))
- continue;
- memcpy(&reply, arp_reply, sizeof(reply));
- /* Protocol must be IP. */
- if (reply.ar_pro != htons(ETHERTYPE_IP))
- continue;
- if (reply.ar_pln != sizeof(reply_s))
- continue;
- /* Only these types are recognised */
- if (reply.ar_op != htons(ARPOP_REPLY) &&
- reply.ar_op != htons(ARPOP_REQUEST))
- continue;
-
- /* Get pointers to the hardware addreses */
- hw_s = arp_reply + sizeof(reply);
- hw_t = hw_s + reply.ar_hln + reply.ar_pln;
- /* Ensure we got all the data */
- if ((hw_t + reply.ar_hln + reply.ar_pln) - arp_reply > bytes)
- continue;
- /* Copy out the IP addresses */
- memcpy(&reply_s, hw_s + reply.ar_hln, reply.ar_pln);
- memcpy(&reply_t, hw_t + reply.ar_hln, reply.ar_pln);
-
- /* Check for conflict */
- if (reply_s.s_addr == address.s_addr ||
- (reply_t.s_addr == address.s_addr &&
- reply.ar_op == htons(ARPOP_REQUEST) &&
- (iface->hwlen != reply.ar_hln ||
- memcmp(hw_s, iface->hwaddr, iface->hwlen) != 0)))
- {
- logger(LOG_ERR, "hardware address %s claims %s",
- hwaddr_ntoa((unsigned char *)hw_s,
- (size_t)reply.ar_hln),
- inet_ntoa(address));
- errno = EEXIST;
- retval = -1;
- goto eexit;
- }
- }
- }
-
-eexit:
- close(iface->fd);
- iface->fd = -1;
- return retval;
-}
#endif
+