1ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat/* dnsmasq is Copyright (c) 2000-2009 Simon Kelley
2ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
3ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat   This program is free software; you can redistribute it and/or modify
4ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat   it under the terms of the GNU General Public License as published by
5ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat   the Free Software Foundation; version 2 dated June, 1991, or
6ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat   (at your option) version 3 dated 29 June, 2007.
7ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
8ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat   This program is distributed in the hope that it will be useful,
9ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat   but WITHOUT ANY WARRANTY; without even the implied warranty of
10ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat   GNU General Public License for more details.
12ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
13ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat   You should have received a copy of the GNU General Public License
14ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat   along with this program.  If not, see <http://www.gnu.org/licenses/>.
15ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat*/
16ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
17ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#include "dnsmasq.h"
18ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
19ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#if defined(HAVE_BSD_NETWORK) || defined(HAVE_SOLARIS_NETWORK)
20ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
21ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatstatic struct iovec ifconf = {
22ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  .iov_base = NULL,
23ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  .iov_len = 0
24ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat};
25ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
26ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatstatic struct iovec ifreq = {
27ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  .iov_base = NULL,
28ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  .iov_len = 0
29ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat};
30ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
31ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatint iface_enumerate(void *parm, int (*ipv4_callback)(), int (*ipv6_callback)())
32ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{
33ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  char *ptr;
34ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  struct ifreq *ifr;
35ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  struct ifconf ifc;
36ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  int fd, errsav, ret = 0;
37ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  int lastlen = 0;
38ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  size_t len = 0;
39ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
40ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1)
41ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    return 0;
42ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
43ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  while(1)
44ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    {
45ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      len += 10*sizeof(struct ifreq);
46ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
47ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      if (!expand_buf(&ifconf, len))
48ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	goto err;
49ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
50ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      ifc.ifc_len = len;
51ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      ifc.ifc_buf = ifconf.iov_base;
52ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
53ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      if (ioctl(fd, SIOCGIFCONF, &ifc) == -1)
54ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	{
55ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  if (errno != EINVAL || lastlen != 0)
56ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    goto err;
57ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	}
58ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      else
59ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	{
60ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  if (ifc.ifc_len == lastlen)
61ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    break; /* got a big enough buffer now */
62ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  lastlen = ifc.ifc_len;
63ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	}
64ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    }
65ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
66ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  for (ptr = ifc.ifc_buf; ptr < (char *)(ifc.ifc_buf + ifc.ifc_len); ptr += len)
67ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    {
68ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      /* subsequent entries may not be aligned, so copy into
69ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	 an aligned buffer to avoid nasty complaints about
70ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	 unaligned accesses. */
71ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
72ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      len = sizeof(struct ifreq);
73ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
74ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#ifdef HAVE_SOCKADDR_SA_LEN
75ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      ifr = (struct ifreq *)ptr;
76ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      if (ifr->ifr_addr.sa_len > sizeof(ifr->ifr_ifru))
77ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	len = ifr->ifr_addr.sa_len + offsetof(struct ifreq, ifr_ifru);
78ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif
79ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
80ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      if (!expand_buf(&ifreq, len))
81ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	goto err;
82ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
83ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      ifr = (struct ifreq *)ifreq.iov_base;
84ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      memcpy(ifr, ptr, len);
85ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
86ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      if (ifr->ifr_addr.sa_family == AF_INET && ipv4_callback)
87ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	{
88ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  struct in_addr addr, netmask, broadcast;
89ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  broadcast.s_addr = 0;
90ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  addr = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr;
91ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  if (ioctl(fd, SIOCGIFNETMASK, ifr) == -1)
92ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    continue;
93ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  netmask = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr;
94ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  if (ioctl(fd, SIOCGIFBRDADDR, ifr) != -1)
95ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    broadcast = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr;
96ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  if (!((*ipv4_callback)(addr,
97ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat				 (int)if_nametoindex(ifr->ifr_name),
98ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat				 netmask, broadcast,
99ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat				 parm)))
100ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    goto err;
101ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	}
102ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#ifdef HAVE_IPV6
103ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      else if (ifr->ifr_addr.sa_family == AF_INET6 && ipv6_callback)
104ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	{
105ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  struct in6_addr *addr = &((struct sockaddr_in6 *)&ifr->ifr_addr)->sin6_addr;
106ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  /* voodoo to clear interface field in address */
107ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  if (!(daemon->options & OPT_NOWILD) && IN6_IS_ADDR_LINKLOCAL(addr))
108ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    {
109ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      addr->s6_addr[2] = 0;
110ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      addr->s6_addr[3] = 0;
111ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    }
112ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  if (!((*ipv6_callback)(addr,
113ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat				 (int)((struct sockaddr_in6 *)&ifr->ifr_addr)->sin6_scope_id,
114ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat				 (int)if_nametoindex(ifr->ifr_name),
115ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat				 parm)))
116ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    goto err;
117ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	}
118ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif
119ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    }
120ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
121ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  ret = 1;
122ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
123ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat err:
124ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  errsav = errno;
125ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  close(fd);
126ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  errno = errsav;
127ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
128ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  return ret;
129ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat}
130ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif
131ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
132ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
133ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#if defined(HAVE_BSD_NETWORK) && defined(HAVE_DHCP)
134ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#include <net/bpf.h>
135ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
136ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatvoid init_bpf(void)
137ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{
138ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  int i = 0;
139ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
140ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  while (1)
141ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    {
142ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      /* useful size which happens to be sufficient */
143ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      if (expand_buf(&ifreq, sizeof(struct ifreq)))
144ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	{
145ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  sprintf(ifreq.iov_base, "/dev/bpf%d", i++);
146ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  if ((daemon->dhcp_raw_fd = open(ifreq.iov_base, O_RDWR, 0)) != -1)
147ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    return;
148ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	}
149ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      if (errno != EBUSY)
150ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	die(_("cannot create DHCP BPF socket: %s"), NULL, EC_BADNET);
151ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    }
152ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat}
153ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
154ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatvoid send_via_bpf(struct dhcp_packet *mess, size_t len,
155ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		  struct in_addr iface_addr, struct ifreq *ifr)
156ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{
157ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat   /* Hairy stuff, packet either has to go to the
158ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      net broadcast or the destination can't reply to ARP yet,
159ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      but we do know the physical address.
160ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      Build the packet by steam, and send directly, bypassing
161ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      the kernel IP stack */
162ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
163ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  struct ether_header ether;
164ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  struct ip ip;
165ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  struct udphdr {
166ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    u16 uh_sport;               /* source port */
167ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    u16 uh_dport;               /* destination port */
168ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    u16 uh_ulen;                /* udp length */
169ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    u16 uh_sum;                 /* udp checksum */
170ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  } udp;
171ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
172ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  u32 i, sum;
173ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  struct iovec iov[4];
174ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
175ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  /* Only know how to do ethernet on *BSD */
176ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if (mess->htype != ARPHRD_ETHER || mess->hlen != ETHER_ADDR_LEN)
177ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    {
178ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      my_syslog(MS_DHCP | LOG_WARNING, _("DHCP request for unsupported hardware type (%d) received on %s"),
179ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		mess->htype, ifr->ifr_name);
180ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      return;
181ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    }
182ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
183ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  ifr->ifr_addr.sa_family = AF_LINK;
184ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if (ioctl(daemon->dhcpfd, SIOCGIFADDR, ifr) < 0)
185ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    return;
186ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
187ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  memcpy(ether.ether_shost, LLADDR((struct sockaddr_dl *)&ifr->ifr_addr), ETHER_ADDR_LEN);
188ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  ether.ether_type = htons(ETHERTYPE_IP);
189ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
190ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if (ntohs(mess->flags) & 0x8000)
191ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    {
192ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      memset(ether.ether_dhost, 255,  ETHER_ADDR_LEN);
193ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      ip.ip_dst.s_addr = INADDR_BROADCAST;
194ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    }
195ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  else
196ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    {
197ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      memcpy(ether.ether_dhost, mess->chaddr, ETHER_ADDR_LEN);
198ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      ip.ip_dst.s_addr = mess->yiaddr.s_addr;
199ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    }
200ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
201ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  ip.ip_p = IPPROTO_UDP;
202ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  ip.ip_src.s_addr = iface_addr.s_addr;
203ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  ip.ip_len = htons(sizeof(struct ip) +
204ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		    sizeof(struct udphdr) +
205ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		    len) ;
206ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  ip.ip_hl = sizeof(struct ip) / 4;
207ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  ip.ip_v = IPVERSION;
208ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  ip.ip_tos = 0;
209ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  ip.ip_id = htons(0);
210ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  ip.ip_off = htons(0x4000); /* don't fragment */
211ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  ip.ip_ttl = IPDEFTTL;
212ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  ip.ip_sum = 0;
213ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  for (sum = 0, i = 0; i < sizeof(struct ip) / 2; i++)
214ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    sum += ((u16 *)&ip)[i];
215ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  while (sum>>16)
216ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    sum = (sum & 0xffff) + (sum >> 16);
217ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  ip.ip_sum = (sum == 0xffff) ? sum : ~sum;
218ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
219ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  udp.uh_sport = htons(daemon->dhcp_server_port);
220ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  udp.uh_dport = htons(daemon->dhcp_client_port);
221ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if (len & 1)
222ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    ((char *)mess)[len] = 0; /* for checksum, in case length is odd. */
223ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  udp.uh_sum = 0;
224ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  udp.uh_ulen = sum = htons(sizeof(struct udphdr) + len);
225ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  sum += htons(IPPROTO_UDP);
226ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  sum += ip.ip_src.s_addr & 0xffff;
227ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  sum += (ip.ip_src.s_addr >> 16) & 0xffff;
228ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  sum += ip.ip_dst.s_addr & 0xffff;
229ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  sum += (ip.ip_dst.s_addr >> 16) & 0xffff;
230ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  for (i = 0; i < sizeof(struct udphdr)/2; i++)
231ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    sum += ((u16 *)&udp)[i];
232ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  for (i = 0; i < (len + 1) / 2; i++)
233ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    sum += ((u16 *)mess)[i];
234ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  while (sum>>16)
235ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    sum = (sum & 0xffff) + (sum >> 16);
236ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  udp.uh_sum = (sum == 0xffff) ? sum : ~sum;
237ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
238ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  ioctl(daemon->dhcp_raw_fd, BIOCSETIF, ifr);
239ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
240ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  iov[0].iov_base = &ether;
241ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  iov[0].iov_len = sizeof(ether);
242ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  iov[1].iov_base = &ip;
243ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  iov[1].iov_len = sizeof(ip);
244ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  iov[2].iov_base = &udp;
245ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  iov[2].iov_len = sizeof(udp);
246ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  iov[3].iov_base = mess;
247ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  iov[3].iov_len = len;
248ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
249ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  while (writev(daemon->dhcp_raw_fd, iov, 4) == -1 && retry_send());
250ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat}
251ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
252ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif
253ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
254ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
255