import of dnsmasq-2.52.tar.gz
diff --git a/src/dhcp.c b/src/dhcp.c
index 335fc04..dcc57b1 100644
--- a/src/dhcp.c
+++ b/src/dhcp.c
@@ -1,4 +1,4 @@
-/* dnsmasq is Copyright (c) 2000-2009 Simon Kelley
+/* dnsmasq is Copyright (c) 2000-2010 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
@@ -27,7 +27,7 @@
 static int complete_context(struct in_addr local, int if_index, 
 			    struct in_addr netmask, struct in_addr broadcast, void *vparam);
 
-void dhcp_init(void)
+static int make_fd(int port)
 {
   int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
   struct sockaddr_in saddr;
@@ -67,7 +67,7 @@
   
   memset(&saddr, 0, sizeof(saddr));
   saddr.sin_family = AF_INET;
-  saddr.sin_port = htons(daemon->dhcp_server_port);
+  saddr.sin_port = htons(port);
   saddr.sin_addr.s_addr = INADDR_ANY;
 #ifdef HAVE_SOCKADDR_SA_LEN
   saddr.sin_len = sizeof(struct sockaddr_in);
@@ -76,7 +76,20 @@
   if (bind(fd, (struct sockaddr *)&saddr, sizeof(struct sockaddr_in)))
     die(_("failed to bind DHCP server socket: %s"), NULL, EC_BADNET);
 
-  daemon->dhcpfd = fd;
+  return fd;
+}
+
+void dhcp_init(void)
+{
+#if defined(HAVE_BSD_NETWORK)
+  int oneopt = 1;
+#endif
+
+  daemon->dhcpfd = make_fd(daemon->dhcp_server_port);
+  if (daemon->enable_pxe)
+    daemon->pxefd = make_fd(PXE_PORT);
+  else
+    daemon->pxefd = -1;
 
 #if defined(HAVE_BSD_NETWORK)
   /* When we're not using capabilities, we need to do this here before
@@ -99,8 +112,9 @@
   daemon->dhcp_packet.iov_base = safe_malloc(daemon->dhcp_packet.iov_len);
 }
   
-void dhcp_packet(time_t now)
+void dhcp_packet(time_t now, int pxe_fd)
 {
+  int fd = pxe_fd ? daemon->pxefd : daemon->dhcpfd;
   struct dhcp_packet *mess;
   struct dhcp_context *context;
   struct iname *tmp;
@@ -135,7 +149,7 @@
   while (1)
     {
       msg.msg_flags = 0;
-      while ((sz = recvmsg(daemon->dhcpfd, &msg, MSG_PEEK | MSG_TRUNC)) == -1 && errno == EINTR);
+      while ((sz = recvmsg(fd, &msg, MSG_PEEK | MSG_TRUNC)) == -1 && errno == EINTR);
       
       if (sz == -1)
 	return;
@@ -165,7 +179,7 @@
   msg.msg_name = &dest;
   msg.msg_namelen = sizeof(dest);
 
-  while ((sz = recvmsg(daemon->dhcpfd, &msg, 0)) == -1 && errno == EINTR);
+  while ((sz = recvmsg(fd, &msg, 0)) == -1 && errno == EINTR);
  
   if ((msg.msg_flags & MSG_TRUNC) || sz < (ssize_t)(sizeof(*mess) - sizeof(mess->options)))
     return;
@@ -243,7 +257,7 @@
     return;
   lease_prune(NULL, now); /* lose any expired leases */
   iov.iov_len = dhcp_reply(parm.current, ifr.ifr_name, iface_index, (size_t)sz, 
-			   now, unicast_dest, &is_inform);
+			   now, unicast_dest, &is_inform, pxe_fd);
   lease_update_file(now);
   lease_update_dns();
     
@@ -264,7 +278,12 @@
   dest.sin_len = sizeof(struct sockaddr_in);
 #endif
      
-  if (mess->giaddr.s_addr)
+  if (pxe_fd)
+    { 
+      if (mess->ciaddr.s_addr != 0)
+	dest.sin_addr = mess->ciaddr;
+    }
+  else if (mess->giaddr.s_addr)
     {
       /* Send to BOOTP relay  */
       dest.sin_port = htons(daemon->dhcp_server_port);
@@ -348,10 +367,10 @@
 #endif
    
 #ifdef HAVE_SOLARIS_NETWORK
-  setsockopt(daemon->dhcpfd, IPPROTO_IP, IP_BOUND_IF, &iface_index, sizeof(iface_index));
+  setsockopt(fd, IPPROTO_IP, IP_BOUND_IF, &iface_index, sizeof(iface_index));
 #endif
   
-  while(sendmsg(daemon->dhcpfd, &msg, 0) == -1 && retry_send());
+  while(sendmsg(fd, &msg, 0) == -1 && retry_send());
 }
  
 /* This is a complex routine: it gets called with each (address,netmask,broadcast) triple