[PATCH] Configure MTU via kernel DHCP

From: Shane Hathaway
Date: Wed Feb 02 2005 - 23:47:04 EST


The attached patch enhances the kernel's DHCP client support (in
net/ipv4/ipconfig.c) to set the interface MTU if provided by the DHCP server.
Without this patch, it's difficult to netboot on a network that uses jumbo
frames. The patch is based on 2.6.10, but I'll update it to the latest
testing kernel if that would expedite its inclusion in the kernel.

More background: it's currently difficult to netboot on a jumbo frame network
because when clients try to mount the root partition, they are still
configured with a small MTU and therefore reject packets sent by the
jumbo-frame-enabled NFS server. Linux needs to set the client MTU before
mounting any NFS shares. Fortunately, the DHCP protocol already supports
setting the MTU; this patch just integrates that feature into the kernel.

Incidentally, ipconfig.c doesn't appear to do enough bounds checking on byte 1
of DHCP/BOOTP extension fields (the length field). It looks like a malicious
DHCP server could mess with kernel memory that way. I could try to fix the
hole, but maybe someone more experienced with this code would like to verify
there's a problem first.

Shane
--- ipconfig.c.orig 2005-02-02 17:23:35.175853560 -0700
+++ ipconfig.c 2005-02-02 19:10:39.843155672 -0700
@@ -126,6 +126,7 @@

int ic_host_name_set __initdata = 0; /* Host name set by us? */

+u16 ic_mtu = 0; /* Interface MTU */
u32 ic_myaddr = INADDR_NONE; /* My IP address */
u32 ic_netmask = INADDR_NONE; /* Netmask for local subnet */
u32 ic_gateway = INADDR_NONE; /* Gateway IP address */
@@ -322,6 +323,13 @@
printk(KERN_ERR "IP-Config: Unable to set interface broadcast address (%d).\n", err);
return -1;
}
+ rtnl_shlock();
+ err = dev_set_mtu(ic_dev, ic_mtu);
+ rtnl_shunlock();
+ if (err < 0) {
+ printk(KERN_ERR "IP-Config: Unable to set interface MTU (%d).\n", err);
+ return -1;
+ }
return 0;
}

@@ -609,6 +617,7 @@
12, /* Host name */
15, /* Domain name */
17, /* Boot path */
+ 26, /* MTU */
40, /* NIS domain name */
};

@@ -812,6 +821,9 @@
if (!root_server_path[0])
ic_bootp_string(root_server_path, ext+1, *ext, sizeof(root_server_path));
break;
+ case 26: /* Interface MTU */
+ ic_mtu = (((u16) ext[1]) << 8) | ext[2];
+ break;
case 40: /* NIS Domain name (_not_ DNS) */
ic_bootp_string(system_utsname.domainname, ext+1, *ext, __NEW_UTS_LEN);
break;
@@ -1362,8 +1374,9 @@
* Clue in the operator.
*/
printk("IP-Config: Complete:");
- printk("\n device=%s", ic_dev->name);
- printk(", addr=%u.%u.%u.%u", NIPQUAD(ic_myaddr));
+ printk("\n device=%s", ic_dev->name);
+ printk(", mtu=%u", (unsigned int)ic_mtu);
+ printk(",\n addr=%u.%u.%u.%u", NIPQUAD(ic_myaddr));
printk(", mask=%u.%u.%u.%u", NIPQUAD(ic_netmask));
printk(", gw=%u.%u.%u.%u", NIPQUAD(ic_gateway));
printk(",\n host=%s, domain=%s, nis-domain=%s",