Mercurial > hg > dhcpcd
view arp.c @ 0:49aca2b065f8 draft
Add dhcpcd-3 re-write
| author | Roy Marples <roy@marples.name> |
|---|---|
| date | Mon, 27 Nov 2006 20:23:22 +0000 |
| parents | |
| children | 89fd24932c4d |
line wrap: on
line source
/* * dhcpcd - DHCP client daemon - * Copyright (C) 2006 Roy Marples <uberlord@gentoo.org> * * dhcpcd is an RFC2131 compliant DHCP client daemon. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* OK, a lot of this was lifting from iputils as the existing code for dhcpcd was kinda klunky and had some issues */ #define _BSD_SOURCE #include <sys/ioctl.h> #include <sys/select.h> #include <sys/socket.h> #include <sys/types.h> #include <netinet/in_systm.h> #ifdef __linux #include <netinet/ether.h> #include <netpacket/packet.h> #endif #include <net/if.h> #include <net/if_arp.h> #include <arpa/inet.h> #include <string.h> #include <unistd.h> #include "common.h" #include "interface.h" #include "logger.h" #include "socket.h" /* Longer is safer and slower - 2 seconds seems a happy medium */ #define TIMEOUT 2 /* Linux does not seem to define these handy macros */ #ifndef ar_sha #define ar_sha(ap) (((unsigned char *) ((ap) + 1)) + 0) #define ar_spa(ap) (((unsigned char *) ((ap) + 1)) + (ap)->ar_hln) #define ar_tha(ap) (((unsigned char *) ((ap) + 1)) + (ap)->ar_hln + (ap)->ar_pln) #define ar_tpa(ap) (((unsigned char *) ((ap) + 1)) + 2 * (ap)->ar_hln + (ap)->ar_pln) #define arphdr_len2(ar_hln, ar_pln) (sizeof (struct arphdr) + 2 * (ar_hln) + 2 * (ar_pln)) #define arphdr_len(ap) (arphdr_len2 ((ap)->ar_hln, (ap)->ar_pln)) #endif int arp_check (interface_t *iface, struct in_addr address) { if (! iface->arpable) { logger (LOG_DEBUG, "arp_check: interface `%s' is not ARPable", iface->name); return 0; } unsigned char buf[256]; struct arphdr *ah = (struct arphdr *) buf; memset (&buf, 0, sizeof (buf)); ah->ar_hrd = htons (ARPHRD_ETHER); ah->ar_pro = htons (ETHERTYPE_IP); ah->ar_hln = ETHER_ADDR_LEN; ah->ar_pln = sizeof (struct in_addr); ah->ar_op = htons (ARPOP_REQUEST); memcpy (ar_sha (ah), &iface->ethernet_address, ah->ar_hln); memcpy (ar_tpa (ah), &address, ah->ar_pln); logger (LOG_INFO, "checking %s is available on attached networks", inet_ntoa (address)); open_socket (iface, true); send_packet (iface, ETHERTYPE_ARP, (unsigned char *) &buf, arphdr_len(ah)); unsigned char reply[4096]; int bytes; unsigned char buffer[iface->buffer_length]; struct timeval tv; long timeout = 0; fd_set rset; timeout = uptime() + TIMEOUT; while (1) { tv.tv_sec = timeout - uptime (); tv.tv_usec = 0; if (tv.tv_sec < 1) break; /* Time out */ FD_ZERO (&rset); FD_SET (iface->fd, &rset); if (select (iface->fd + 1, &rset, NULL, NULL, &tv) == 0) break; if (! FD_ISSET (iface->fd, &rset)) continue; memset (buffer, 0, sizeof (buffer)); int buflen = sizeof (buffer); int bufpos = -1; while (bufpos != 0) { memset (&reply, 0, sizeof (reply)); if ((bytes = get_packet (iface, (unsigned char *) &reply, buffer, &buflen, &bufpos)) < 0) break; ah = (struct arphdr *) reply; /* Only these types are recognised */ if (ah->ar_op != htons(ARPOP_REPLY) || ah->ar_hrd != htons (ARPHRD_ETHER)) continue; /* Protocol must be IP. */ if (ah->ar_pro != htons (ETHERTYPE_IP)) continue; if (ah->ar_pln != sizeof (struct in_addr)) continue; if (ah->ar_hln != ETHER_ADDR_LEN) continue; if (bytes < sizeof (*ah) + 2 * (4 + ah->ar_hln)) continue; logger (LOG_ERR, "ARPOP_REPLY received from %s (%s)", inet_ntoa (* (struct in_addr *) ar_spa (ah)), ether_ntoa ((struct ether_addr *) ar_sha (ah))); close (iface->fd); iface->fd = -1; return 1; } } close (iface->fd); iface->fd = -1; return 0; }
