import of dnsmasq-2.41.tar.gz
diff --git a/src/tftp.c b/src/tftp.c
index 5a80ceb..071806e 100644
--- a/src/tftp.c
+++ b/src/tftp.c
@@ -2,12 +2,16 @@
 
    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.
-
+   the Free Software Foundation; version 2 dated June, 1991, or
+   (at your option) version 3 dated 29 June, 2007.
+ 
    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, see <http://www.gnu.org/licenses/>.
 */
 
 #include "dnsmasq.h"
@@ -47,11 +51,17 @@
   int is_err = 1, if_index = 0;
   struct iname *tmp;
   struct tftp_transfer *transfer;
-
+  int port = daemon->start_tftp_port; /* may be zero to use ephemeral port */
+#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
+  int mtu = IP_PMTUDISC_DONT;
+#endif
+  
   union {
     struct cmsghdr align; /* this ensures alignment */
-#ifdef HAVE_LINUX_NETWORK
+#if defined(HAVE_LINUX_NETWORK)
     char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
+#elif defined(HAVE_SOLARIS_NETWORK)
+    char control[CMSG_SPACE(sizeof(unsigned int))];
 #else
     char control[CMSG_SPACE(sizeof(struct sockaddr_dl))];
 #endif
@@ -96,7 +106,11 @@
 	if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVDSTADDR)
 	  addr.sin_addr = *((struct in_addr *)CMSG_DATA(cmptr));
 	else if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
-	  if_index = ((struct sockaddr_dl *)CMSG_DATA(cmptr))->sdl_index;
+#ifdef HAVE_SOLARIS_NETWORK
+	  if_index = *((unsigned int *)CMSG_DATA(cmptr));
+#else
+          if_index = ((struct sockaddr_dl *)CMSG_DATA(cmptr))->sdl_index;
+#endif
       
       if (if_index == 0 || !if_indextoname(if_index, ifr.ifr_name))
 	return;
@@ -117,8 +131,7 @@
       
     }
   
-  /* tell kernel to use ephemeral port */
-  addr.sin_port = 0;
+  addr.sin_port = htons(port);
   addr.sin_family = AF_INET;
 #ifdef HAVE_SOCKADDR_SA_LEN
   addr.sin_len = sizeof(addr);
@@ -141,13 +154,30 @@
   transfer->file = NULL;
   transfer->opt_blocksize = transfer->opt_transize = 0;
 
-  if (bind(transfer->sockfd, (struct sockaddr *)&addr, sizeof(addr)) == -1 ||
-      !fix_fd(transfer->sockfd))
+  /* if we have a nailed-down range, iterate until we find a free one. */
+  while (1)
     {
-      free_transfer(transfer);
-      return;
+      if (bind(transfer->sockfd, (struct sockaddr *)&addr, sizeof(addr)) == -1 ||
+#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
+	  setsockopt(transfer->sockfd, SOL_IP, IP_MTU_DISCOVER, &mtu, sizeof(mtu)) == -1 ||
+#endif
+	  !fix_fd(transfer->sockfd))
+	{
+	  if (errno == EADDRINUSE && daemon->start_tftp_port != 0)
+	    {
+	      if (++port <= daemon->end_tftp_port)
+		{ 
+		  addr.sin_port = htons(port);
+		  continue;
+		}
+	      my_syslog(LOG_ERR, _("unable to get free port for TFTP"));
+	    }
+	  free_transfer(transfer);
+	  return;
+	}
+      break;
     }
-
+  
   p = packet + 2;
   end = packet + len;
 
@@ -362,7 +392,7 @@
 		    {
 		      char *q, *r;
 		      for (q = r = err; *r; r++)
-			if (isprint(*r))
+			if (isprint((int)*r))
 			  *(q++) = *r;
 		      *q = 0;
 		    }