changeset 73:6e7ab19c2475 draft

RFC 2131 is full of confusion regarding MTU it seems as the effective minimum MTU is really 576 or DHCP requests stop working.
author Roy Marples <roy@marples.name>
date Fri, 02 Mar 2007 12:11:46 +0000
parents 9bf434f2313a
children 5d21af7476c7
files ChangeLog Makefile dhcp.c dhcp.h interface.c interface.h
diffstat 6 files changed, 66 insertions(+), 7 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Thu Mar 01 10:42:01 2007 +0000
+++ b/ChangeLog	Fri Mar 02 12:11:46 2007 +0000
@@ -1,3 +1,7 @@
+dhcpcd-3.0.16
+RFC 2131 is full of confusion regarding MTU it seems as the effective minimum
+MTU is really 576 or DHCP requests stop working.
+
 dhcpcd-3.0.15
 Fix MTU length checking.
 We now request MTU from the DHCP server, and if given we set it.
--- a/Makefile	Thu Mar 01 10:42:01 2007 +0000
+++ b/Makefile	Fri Mar 02 12:11:46 2007 +0000
@@ -1,6 +1,6 @@
 # Should work for both GNU make and BSD make
 
-VERSION = 3.0.15
+VERSION = 3.0.16
 
 CFLAGS ?= -O2 -pipe
 
--- a/dhcp.c	Thu Mar 01 10:42:01 2007 +0000
+++ b/dhcp.c	Fri Mar 02 12:11:46 2007 +0000
@@ -123,7 +123,13 @@
     {
       *p++ = DHCP_MAXMESSAGESIZE;
       *p++ = 2;
-      sz = htons (sizeof (dhcpmessage_t));
+      sz = get_mtu (iface->name);
+      if (sz < MTU_MIN)
+	{
+	  if (set_mtu (iface->name, MTU_MIN) == 0)
+	    sz = MTU_MIN;
+	}
+      sz = htons (sz);
       memcpy (p, &sz, 2);
       p += 2;
     }
@@ -601,11 +607,12 @@
 	  break;
 	case DHCP_MTU:
 	  GET_UINT16_H (dhcp->mtu);
-	  /* Minimum legal mtu is 68 */
-	  if (dhcp->mtu < 68)
+	  /* Minimum legal mtu is 68 accoridng to RFC 2132.
+	     In practise it's 576 (minimum maximum message size) */
+	  if (dhcp->mtu < MTU_MIN)
 	    {
-	      logger (LOG_ERR, "minimum legal MTU is 68");
-	      dhcp->mtu = 68;
+	      logger (LOG_ERR, "given MTU %d is too low, minium is %d", dhcp->mtu, MTU_MIN);
+	      dhcp->mtu = MTU_MIN;
 	    }
 	  break;
 
--- a/dhcp.h	Thu Mar 01 10:42:01 2007 +0000
+++ b/dhcp.h	Fri Mar 02 12:11:46 2007 +0000
@@ -33,6 +33,7 @@
 
 /* Max MTU - defines dhcp option length */
 #define MTU_MAX			1500
+#define MTU_MIN			576
 
 /* UDP port numbers for DHCP */
 #define DHCP_SERVER_PORT 67
@@ -163,7 +164,6 @@
 #define DHCP_OPTION_LEN		(MTU_MAX - DHCP_FIXED_LEN - DHCP_UDP_LEN \
 				 - DHCP_RESERVE_LEN)
 
-
 typedef struct dhcpmessage_t
 {
   unsigned char op;				/* message type */
--- a/interface.c	Thu Mar 01 10:42:01 2007 +0000
+++ b/interface.c	Fri Mar 02 12:11:46 2007 +0000
@@ -55,6 +55,7 @@
 #include <unistd.h>
 
 #include "common.h"
+#include "dhcp.h"
 #include "interface.h"
 #include "logger.h"
 #include "pathnames.h"
@@ -231,6 +232,26 @@
 #endif
 
   strncpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+  if (ioctl(s, SIOCGIFMTU, &ifr) < 0)
+    {
+      logger (LOG_ERR, "ioctl SIOCGIFMTU: %s", strerror (errno));
+      close (s);
+      return NULL;
+    }
+  if (ifr.ifr_mtu < MTU_MIN)
+    {
+      logger (LOG_DEBUG, "MTU of %d is too low, setting to %d", ifr.ifr_mtu, MTU_MIN);
+      ifr.ifr_mtu = MTU_MIN;
+      strncpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+      if (ioctl(s, SIOCSIFMTU, &ifr) < 0)
+	{
+	  logger (LOG_ERR, "ioctl SIOCSIFMTU,: %s", strerror (errno));
+	  close (s);
+	  return NULL;
+	}
+    }
+
+  strncpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
   if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0)
     {
       logger (LOG_ERR, "ioctl SIOCGIFFLAGS: %s", strerror (errno));
@@ -268,6 +289,32 @@
   return iface;
 }
 
+int get_mtu (const char *ifname)
+{
+  struct ifreq ifr;
+  int r;
+  int s;
+
+  if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) 
+    {
+      logger (LOG_ERR, "socket: %s", strerror (errno));
+      return (-1);
+    }
+
+  memset (&ifr, 0, sizeof (struct ifreq));
+  strcpy (ifr.ifr_name, ifname);
+  r = ioctl (s, SIOCGIFMTU, &ifr);
+  close (s);
+
+  if (r < 0)
+    {
+      logger (LOG_ERR, "ioctl SIOCGIFMTU: %s", strerror (errno));
+      return (-1);
+    }
+
+  return (ifr.ifr_mtu);
+}
+
 int set_mtu (const char *ifname, short int mtu)
 {
   struct ifreq ifr;
--- a/interface.h	Thu Mar 01 10:42:01 2007 +0000
+++ b/interface.h	Fri Mar 02 12:11:46 2007 +0000
@@ -85,6 +85,7 @@
 void free_address (address_t *addresses);
 void free_route (route_t *routes);
 interface_t *read_interface (const char *ifname, int metric);
+int get_mtu (const char *ifname);
 int set_mtu (const char *ifname, short int mtu);
 
 int add_address (const char *ifname, struct in_addr address,