diff options
Diffstat (limited to 'src/customdhcpcd/arp.c')
-rw-r--r-- | src/customdhcpcd/arp.c | 421 |
1 files changed, 221 insertions, 200 deletions
diff --git a/src/customdhcpcd/arp.c b/src/customdhcpcd/arp.c index 794850c..29a22f2 100644 --- a/src/customdhcpcd/arp.c +++ b/src/customdhcpcd/arp.c @@ -1,4 +1,4 @@ -/* +/* * dhcpcd - DHCP client daemon * Copyright 2006-2008 Roy Marples <roy@marples.name> * All rights reserved @@ -74,211 +74,232 @@ #ifdef ENABLE_ARP static int send_arp (const interface_t *iface, int op, struct in_addr sip, - const unsigned char *taddr, struct in_addr tip) + const unsigned char *taddr, struct in_addr tip) { - struct arphdr *arp; - size_t arpsize = arphdr_len2 (iface->hwlen, sizeof (sip)); - caddr_t tha; - int retval; - - arp = xzalloc (arpsize); - arp->ar_hrd = htons (iface->family); - arp->ar_pro = htons (ETHERTYPE_IP); - arp->ar_hln = iface->hwlen; - arp->ar_pln = sizeof (sip); - arp->ar_op = htons (op); - memcpy (ar_sha (arp), iface->hwaddr, (size_t) arp->ar_hln); - memcpy (ar_spa (arp), &sip, (size_t) arp->ar_pln); - if (taddr) { - /* NetBSD can return NULL from ar_tha, which is probably wrong - * but we still need to deal with it */ - if (! (tha = ar_tha (arp))) { - free (arp); - errno = EINVAL; - return (-1); - } - memcpy (tha, taddr, (size_t) arp->ar_hln); - } - memcpy (ar_tpa (arp), &tip, (size_t) arp->ar_pln); - - retval = send_packet (iface, ETHERTYPE_ARP, - (unsigned char *) arp, arphdr_len (arp)); - free (arp); - return (retval); + struct arphdr *arp; + size_t arpsize = arphdr_len2 (iface->hwlen, sizeof (sip)); + caddr_t tha; + int retval; + + arp = xzalloc (arpsize); + arp->ar_hrd = htons (iface->family); + arp->ar_pro = htons (ETHERTYPE_IP); + arp->ar_hln = iface->hwlen; + arp->ar_pln = sizeof (sip); + arp->ar_op = htons (op); + memcpy (ar_sha (arp), iface->hwaddr, (size_t) arp->ar_hln); + memcpy (ar_spa (arp), &sip, (size_t) arp->ar_pln); + if (taddr) + { + /* NetBSD can return NULL from ar_tha, which is probably wrong + * but we still need to deal with it */ + if (! (tha = ar_tha (arp))) + { + free (arp); + errno = EINVAL; + return (-1); + } + memcpy (tha, taddr, (size_t) arp->ar_hln); + } + memcpy (ar_tpa (arp), &tip, (size_t) arp->ar_pln); + + retval = send_packet (iface, ETHERTYPE_ARP, + (unsigned char *) arp, arphdr_len (arp)); + free (arp); + return (retval); } int arp_claim (interface_t *iface, struct in_addr address) { - struct arphdr *reply = NULL; - long timeout = 0; - unsigned char *buffer; - int retval = -1; - int nprobes = 0; - int nclaims = 0; - struct in_addr null_address; - struct pollfd fds[] = { - { -1, POLLIN, 0 }, - { -1, POLLIN, 0 } - }; - - if (! iface) - return (-1); - - if (! iface->arpable) { - logger (LOG_DEBUG, "interface `%s' is not ARPable", iface->name); - return (0); - } - - if (! IN_LINKLOCAL (ntohl (iface->previous_address.s_addr)) && - ! IN_LINKLOCAL (ntohl (address.s_addr))) - logger (LOG_INFO, - "checking %s is available on attached networks", - inet_ntoa (address)); - - if (! open_socket (iface, ETHERTYPE_ARP)) - return (-1); - - fds[0].fd = signal_fd (); - fds[1].fd = iface->fd; - - memset (&null_address, 0, sizeof (null_address)); - - buffer = xmalloc (iface->buffer_length); - reply = xmalloc (iface->buffer_length); - - for (;;) { - size_t bufpos = 0; - size_t buflen = iface->buffer_length; - int bytes; - int s = 0; - struct timeval stopat; - struct timeval now; - - /* Only poll if we have a timeout */ - if (timeout > 0) { - s = poll (fds, 2, timeout); - if (s == -1) { - if (errno == EINTR) { - if (signal_exists (NULL) == -1) { - errno = 0; - continue; - } else - break; - } - - logger (LOG_ERR, "poll: `%s'", - strerror (errno)); - break; - } - } - - /* Timed out */ - if (s == 0) { - if (nprobes < NPROBES) { - nprobes ++; - timeout = PROBE_INTERVAL; - logger (LOG_DEBUG, "sending ARP probe #%d", - nprobes); - if (send_arp (iface, ARPOP_REQUEST, - null_address, NULL, - address) == -1) - break; - - /* IEEE1394 cannot set ARP target address - * according to RFC2734 */ - if (nprobes >= NPROBES && - iface->family == ARPHRD_IEEE1394) - nclaims = NCLAIMS; - } else if (nclaims < NCLAIMS) { - nclaims ++; - timeout = CLAIM_INTERVAL; - 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; - - continue; - } - - /* We maybe ARP flooded, so check our time */ - if (get_time (&now) != 0) - break; - if (timercmp (&now, &stopat, >)) { - timeout = 0; - continue; - } - - if (! fds[1].revents & POLLIN) - continue; - - memset (buffer, 0, buflen); - do { - union { - unsigned char *c; - struct in_addr *a; - } rp; - union { - unsigned char *c; - struct ether_addr *a; - } rh; - - memset (reply, 0, iface->buffer_length); - if ((bytes = get_packet (iface, (unsigned char *) reply, - buffer, - &buflen, &bufpos)) == -1) - break; - - /* Only these types are recognised */ - if (reply->ar_op != htons (ARPOP_REPLY)) - continue; - - /* Protocol must be IP. */ - if (reply->ar_pro != htons (ETHERTYPE_IP)) - continue; - if (reply->ar_pln != sizeof (address)) - continue; - if ((unsigned) bytes < sizeof (reply) + - 2 * (4 + reply->ar_hln)) - continue; - - rp.c = (unsigned char *) ar_spa (reply); - rh.c = (unsigned char *) ar_sha (reply); - - /* Ensure the ARP reply is for the our address */ - if (rp.a->s_addr != address.s_addr) - continue; - - /* Some systems send a reply back from our hwaddress, - * which is wierd */ - if (reply->ar_hln == iface->hwlen && - memcmp (rh.c, iface->hwaddr, iface->hwlen) == 0) - continue; - - logger (LOG_ERR, "ARPOP_REPLY received from %s (%s)", - inet_ntoa (*rp.a), - hwaddr_ntoa (rh.c, (size_t) reply->ar_hln)); - retval = -1; - goto eexit; - } while (bufpos != 0); - } + struct arphdr *reply = NULL; + long timeout = 0; + unsigned char *buffer; + int retval = -1; + int nprobes = 0; + int nclaims = 0; + struct in_addr null_address; + struct pollfd fds[] = + { + { -1, POLLIN, 0 }, + { -1, POLLIN, 0 } + }; + + if (! iface) + return (-1); + + if (! iface->arpable) + { + logger (LOG_DEBUG, "interface `%s' is not ARPable", iface->name); + return (0); + } + + if (! IN_LINKLOCAL (ntohl (iface->previous_address.s_addr)) && + ! IN_LINKLOCAL (ntohl (address.s_addr))) + logger (LOG_INFO, + "checking %s is available on attached networks", + inet_ntoa (address)); + + if (! open_socket (iface, ETHERTYPE_ARP)) + return (-1); + + fds[0].fd = signal_fd (); + fds[1].fd = iface->fd; + + memset (&null_address, 0, sizeof (null_address)); + + buffer = xmalloc (iface->buffer_length); + reply = xmalloc (iface->buffer_length); + + for (;;) + { + size_t bufpos = 0; + size_t buflen = iface->buffer_length; + int bytes; + int s = 0; + struct timeval stopat; + struct timeval now; + + /* Only poll if we have a timeout */ + if (timeout > 0) + { + s = poll (fds, 2, timeout); + if (s == -1) + { + if (errno == EINTR) + { + if (signal_exists (NULL) == -1) + { + errno = 0; + continue; + } + else + break; + } + + logger (LOG_ERR, "poll: `%s'", + strerror (errno)); + break; + } + } + + /* Timed out */ + if (s == 0) + { + if (nprobes < NPROBES) + { + nprobes ++; + timeout = PROBE_INTERVAL; + logger (LOG_DEBUG, "sending ARP probe #%d", + nprobes); + if (send_arp (iface, ARPOP_REQUEST, + null_address, NULL, + address) == -1) + break; + + /* IEEE1394 cannot set ARP target address + * according to RFC2734 */ + if (nprobes >= NPROBES && + iface->family == ARPHRD_IEEE1394) + nclaims = NCLAIMS; + } + else if (nclaims < NCLAIMS) + { + nclaims ++; + timeout = CLAIM_INTERVAL; + 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; + + continue; + } + + /* We maybe ARP flooded, so check our time */ + if (get_time (&now) != 0) + break; + if (timercmp (&now, &stopat, > )) + { + timeout = 0; + continue; + } + + if (! fds[1].revents & POLLIN) + continue; + + memset (buffer, 0, buflen); + do + { + union + { + unsigned char *c; + struct in_addr *a; + } rp; + union + { + unsigned char *c; + struct ether_addr *a; + } rh; + + memset (reply, 0, iface->buffer_length); + if ((bytes = get_packet (iface, (unsigned char *) reply, + buffer, + &buflen, &bufpos)) == -1) + break; + + /* Only these types are recognised */ + if (reply->ar_op != htons (ARPOP_REPLY)) + continue; + + /* Protocol must be IP. */ + if (reply->ar_pro != htons (ETHERTYPE_IP)) + continue; + if (reply->ar_pln != sizeof (address)) + continue; + if ((unsigned) bytes < sizeof (reply) + + 2 * (4 + reply->ar_hln)) + continue; + + rp.c = (unsigned char *) ar_spa (reply); + rh.c = (unsigned char *) ar_sha (reply); + + /* Ensure the ARP reply is for the our address */ + if (rp.a->s_addr != address.s_addr) + continue; + + /* Some systems send a reply back from our hwaddress, + * which is wierd */ + if (reply->ar_hln == iface->hwlen && + memcmp (rh.c, iface->hwaddr, iface->hwlen) == 0) + continue; + + logger (LOG_ERR, "ARPOP_REPLY received from %s (%s)", + inet_ntoa (*rp.a), + hwaddr_ntoa (rh.c, (size_t) reply->ar_hln)); + retval = -1; + goto eexit; + } + while (bufpos != 0); + } eexit: - close (iface->fd); - iface->fd = -1; - free (buffer); - free (reply); - return (retval); + close (iface->fd); + iface->fd = -1; + free (buffer); + free (reply); + return (retval); } #endif |