import of dnsmasq-2.28.tar.gz
diff --git a/src/bpf.c b/src/bpf.c
new file mode 100644
index 0000000..562a438
--- /dev/null
+++ b/src/bpf.c
@@ -0,0 +1,238 @@
+/* dnsmasq is Copyright (c) 2000-2006 Simon Kelley
+
+   This program 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; version 2 dated June, 1991.
+
+   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.
+*/
+
+#include "dnsmasq.h"
+
+#ifndef HAVE_LINUX_NETWORK
+
+#include <net/bpf.h>
+
+static struct iovec ifconf = {
+  .iov_base = NULL,
+  .iov_len = 0
+};
+
+static struct iovec ifreq = {
+  .iov_base = NULL,
+  .iov_len = 0
+};
+
+struct header {
+  struct ether_header ether; 
+  struct ip ip;
+  struct udphdr {
+    u16 uh_sport;               /* source port */
+    u16 uh_dport;               /* destination port */
+    u16 uh_ulen;                /* udp length */
+    u16 uh_sum;                 /* udp checksum */
+  } udp;
+};
+
+void init_bpf(struct daemon *daemon)
+{
+  int i = 0;
+
+  while (1) 
+    {
+      /* useful size which happens to be sufficient */
+      if (expand_buf(&ifreq, sizeof(struct ifreq)))
+	{
+	  sprintf(ifreq.iov_base, "/dev/bpf%d", i++);
+	  if ((daemon->dhcp_raw_fd = open(ifreq.iov_base, O_RDWR, 0)) != -1)
+	    return;
+	}
+      if (errno != EBUSY)
+	die(_("cannot create DHCP BPF socket: %s"), NULL);
+    }	     
+}
+
+void send_via_bpf(struct daemon *daemon, struct dhcp_packet *mess, size_t len,
+		  struct in_addr iface_addr, struct ifreq *ifr)
+{
+   /* Hairy stuff, packet either has to go to the
+      net broadcast or the destination can't reply to ARP yet,
+      but we do know the physical address. 
+      Build the packet by steam, and send directly, bypassing
+      the kernel IP stack */
+  
+  struct header header;
+  u32 i, sum;
+  struct iovec iov[2];
+
+  /* Only know how to do ethernet on *BSD */
+  if (mess->htype != ARPHRD_ETHER || mess->hlen != ETHER_ADDR_LEN)
+    {
+      syslog(LOG_WARNING, _("DHCP request for unsupported hardware type (%d) received on %s"), 
+	     mess->htype, ifr->ifr_name);
+      return;
+    }
+   
+  ifr->ifr_addr.sa_family = AF_LINK;
+  if (ioctl(daemon->dhcpfd, SIOCGIFADDR, ifr) < 0)
+    return;
+  
+  memcpy(header.ether.ether_shost, LLADDR((struct sockaddr_dl *)&ifr->ifr_addr), ETHER_ADDR_LEN);
+  header.ether.ether_type = htons(ETHERTYPE_IP);
+  
+  if (ntohs(mess->flags) & 0x8000)
+    {
+      memset(header.ether.ether_dhost, 255,  ETHER_ADDR_LEN);
+      header.ip.ip_dst.s_addr = INADDR_BROADCAST;
+    }
+  else
+    {
+      memcpy(header.ether.ether_dhost, mess->chaddr, ETHER_ADDR_LEN); 
+      header.ip.ip_dst.s_addr = mess->yiaddr.s_addr;
+    }
+  
+  header.ip.ip_p = IPPROTO_UDP;
+  header.ip.ip_src.s_addr = iface_addr.s_addr;
+  header.ip.ip_len = htons(sizeof(struct ip) + 
+			   sizeof(struct udphdr) +
+			   len) ;
+  header.ip.ip_hl = sizeof(struct ip) / 4;
+  header.ip.ip_v = IPVERSION;
+  header.ip.ip_tos = 0;
+  header.ip.ip_id = htons(0);
+  header.ip.ip_off = htons(0x4000); /* don't fragment */
+  header.ip.ip_ttl = IPDEFTTL;
+  header.ip.ip_sum = 0;
+  for (sum = 0, i = 0; i < sizeof(struct ip) / 2; i++)
+    sum += ((u16 *)&header.ip)[i];
+  while (sum>>16)
+    sum = (sum & 0xffff) + (sum >> 16);  
+  header.ip.ip_sum = (sum == 0xffff) ? sum : ~sum;
+  
+  header.udp.uh_sport = htons(DHCP_SERVER_PORT);
+  header.udp.uh_dport = htons(DHCP_CLIENT_PORT);
+  if (len & 1)
+    ((char *)mess)[len] = 0; /* for checksum, in case length is odd. */
+  header.udp.uh_sum = 0;
+  header.udp.uh_ulen = sum = htons(sizeof(struct udphdr) + len);
+  sum += htons(IPPROTO_UDP);
+  for (i = 0; i < 4; i++)
+    sum += ((u16 *)&header.ip.ip_src)[i];
+  for (i = 0; i < sizeof(struct udphdr)/2; i++)
+    sum += ((u16 *)&header.udp)[i];
+  for (i = 0; i < (len + 1) / 2; i++)
+    sum += ((u16 *)mess)[i];
+  while (sum>>16)
+    sum = (sum & 0xffff) + (sum >> 16);
+  header.udp.uh_sum = (sum == 0xffff) ? sum : ~sum;
+  
+  ioctl(daemon->dhcp_raw_fd, BIOCSETIF, ifr);
+  
+  iov[0].iov_base = &header;
+  iov[0].iov_len = sizeof(struct header);
+  iov[1].iov_base = mess;
+  iov[1].iov_len = len;
+  while (writev(daemon->dhcp_raw_fd, iov, 2) == -1 && retry_send());
+}
+
+int iface_enumerate(struct daemon *daemon, void *parm, int (*ipv4_callback)(), int (*ipv6_callback)())
+{
+  char *ptr;
+  struct ifreq *ifr, ifaux;
+  struct ifconf ifc;
+  int fd, errsav, ret = 0;
+  int lastlen = 0;
+  size_t len;
+  
+  if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1)
+    return 0;
+        
+  for (len = 0; ; len += 10*sizeof(struct ifreq))
+    {
+       if (!expand_buf(&ifconf, len))
+	 goto err;
+
+       ifc.ifc_len = len;
+       ifc.ifc_buf = ifconf.iov_base;
+
+       if (ioctl(fd, SIOCGIFCONF, &ifc) == -1)
+	 {
+	   if (errno != EINVAL || lastlen != 0)
+	     goto err;
+	 }
+       else
+	 {
+	   if (ifc.ifc_len == lastlen)
+	     break; /* got a big enough buffer now */
+	   lastlen = ifc.ifc_len;
+	 }
+     }
+  
+  for (ptr = ifc.ifc_buf; ptr < ifc.ifc_buf + ifc.ifc_len; ptr += len )
+    {
+      /* subsequent entries may not be aligned, so copy into
+	 an aligned buffer to avoid nasty complaints about 
+	 unaligned accesses. */
+#ifdef HAVE_SOCKADDR_SA_LEN
+      len = ((struct ifreq *)ptr)->ifr_addr.sa_len + IF_NAMESIZE;
+#else
+      len = sizeof(struct ifreq);
+#endif
+      if (!expand_buf(&ifreq, len))
+	goto err;
+
+      ifr = ifreq.iov_base;
+      memcpy(ifr, ptr, len);
+      
+      strncpy(ifaux.ifr_name, ifr->ifr_name, IF_NAMESIZE);
+           
+      if (ifr->ifr_addr.sa_family == AF_INET && ipv4_callback)
+	{
+	  struct in_addr addr, netmask, broadcast;
+	  if (ioctl(fd, SIOCGIFINDEX, &ifaux) == -1)
+	    continue;
+	  broadcast.s_addr = 0;
+	  addr = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr;
+	  if (ioctl(fd, SIOCGIFNETMASK, ifr) == -1)
+	    continue;
+	  netmask = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr;
+	  if (ioctl(fd, SIOCGIFBRDADDR, ifr) != -1)
+	    broadcast = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr; 
+	  if (!((*ipv4_callback)(daemon, addr, (int)ifaux.ifr_index, netmask, broadcast, parm)))
+	    goto err;
+	}
+#ifdef HAVE_IPV6
+      else if (ifr->ifr_addr.sa_family == AF_INET6 && ipv6_callback)
+	{
+	  struct in6_addr *addr = &((struct sockaddr_in6 *)&ifr->ifr_addr)->sin6_addr;
+	  /* voodoo to clear interface field in address */
+	  if (!(daemon->options & OPT_NOWILD) && IN6_IS_ADDR_LINKLOCAL(addr))
+	    {
+	      addr->s6_addr[2] = 0;
+	      addr->s6_addr[3] = 0;
+	    }
+	  if (ioctl(fd, SIOCGIFINDEX, &ifaux) == -1)
+	    continue;
+	  if (!((*ipv6_callback)(daemon, addr,
+				 (int)((struct sockaddr_in6 *)&ifr->ifr_addr)->sin6_scope_id,
+				 (int)ifaux.ifr_index,
+				 parm)))
+	    goto err;
+	}
+#endif
+    }
+  
+  ret = 1;
+
+ err:
+  errsav = errno;
+  close(fd);  
+  errno = errsav;
+
+  return ret;
+}
+
+#endif