diff options
author | Chris Friesen <cfriesen@nortel.com> | 2009-05-19 18:31:50 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-05-19 18:36:17 -0400 |
commit | 9643f4551255ce8b3ef7470aaaf7f435a20f9182 (patch) | |
tree | 4c2fe5194a697c2e9c0e61d7a74850760315ba76 /net | |
parent | fd2120ca0da9108e53f8db2fe57ab74fca76fd56 (diff) |
ipv4: teach ipconfig about the MTU option in DHCP
The DHCP spec allows the server to specify the MTU. This can be useful
for netbooting with UDP-based NFS-root on a network using jumbo frames.
This patch allows the kernel IP autoconfiguration to handle this option
correctly.
It would be possible to use initramfs and add a script to set the MTU,
but that seems like a complicated solution if no initramfs is otherwise
necessary, and would bloat the kernel image more than this code would.
This patch was originally submitted to LKML in 2003 by Hans-Peter Jansen.
Signed-off-by: Chris Friesen <cfriesen@nortel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/ipv4/ipconfig.c | 41 |
1 files changed, 37 insertions, 4 deletions
diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c index 88bf051d0cbb..f8d04c256454 100644 --- a/net/ipv4/ipconfig.c +++ b/net/ipv4/ipconfig.c | |||
@@ -160,6 +160,9 @@ static char user_dev_name[IFNAMSIZ] __initdata = { 0, }; | |||
160 | /* Protocols supported by available interfaces */ | 160 | /* Protocols supported by available interfaces */ |
161 | static int ic_proto_have_if __initdata = 0; | 161 | static int ic_proto_have_if __initdata = 0; |
162 | 162 | ||
163 | /* MTU for boot device */ | ||
164 | static int ic_dev_mtu __initdata = 0; | ||
165 | |||
163 | #ifdef IPCONFIG_DYNAMIC | 166 | #ifdef IPCONFIG_DYNAMIC |
164 | static DEFINE_SPINLOCK(ic_recv_lock); | 167 | static DEFINE_SPINLOCK(ic_recv_lock); |
165 | static volatile int ic_got_reply __initdata = 0; /* Proto(s) that replied */ | 168 | static volatile int ic_got_reply __initdata = 0; /* Proto(s) that replied */ |
@@ -286,7 +289,7 @@ set_sockaddr(struct sockaddr_in *sin, __be32 addr, __be16 port) | |||
286 | sin->sin_port = port; | 289 | sin->sin_port = port; |
287 | } | 290 | } |
288 | 291 | ||
289 | static int __init ic_dev_ioctl(unsigned int cmd, struct ifreq *arg) | 292 | static int __init ic_devinet_ioctl(unsigned int cmd, struct ifreq *arg) |
290 | { | 293 | { |
291 | int res; | 294 | int res; |
292 | 295 | ||
@@ -297,6 +300,17 @@ static int __init ic_dev_ioctl(unsigned int cmd, struct ifreq *arg) | |||
297 | return res; | 300 | return res; |
298 | } | 301 | } |
299 | 302 | ||
303 | static int __init ic_dev_ioctl(unsigned int cmd, struct ifreq *arg) | ||
304 | { | ||
305 | int res; | ||
306 | |||
307 | mm_segment_t oldfs = get_fs(); | ||
308 | set_fs(get_ds()); | ||
309 | res = dev_ioctl(&init_net, cmd, (struct ifreq __user *) arg); | ||
310 | set_fs(oldfs); | ||
311 | return res; | ||
312 | } | ||
313 | |||
300 | static int __init ic_route_ioctl(unsigned int cmd, struct rtentry *arg) | 314 | static int __init ic_route_ioctl(unsigned int cmd, struct rtentry *arg) |
301 | { | 315 | { |
302 | int res; | 316 | int res; |
@@ -321,20 +335,31 @@ static int __init ic_setup_if(void) | |||
321 | memset(&ir, 0, sizeof(ir)); | 335 | memset(&ir, 0, sizeof(ir)); |
322 | strcpy(ir.ifr_ifrn.ifrn_name, ic_dev->name); | 336 | strcpy(ir.ifr_ifrn.ifrn_name, ic_dev->name); |
323 | set_sockaddr(sin, ic_myaddr, 0); | 337 | set_sockaddr(sin, ic_myaddr, 0); |
324 | if ((err = ic_dev_ioctl(SIOCSIFADDR, &ir)) < 0) { | 338 | if ((err = ic_devinet_ioctl(SIOCSIFADDR, &ir)) < 0) { |
325 | printk(KERN_ERR "IP-Config: Unable to set interface address (%d).\n", err); | 339 | printk(KERN_ERR "IP-Config: Unable to set interface address (%d).\n", err); |
326 | return -1; | 340 | return -1; |
327 | } | 341 | } |
328 | set_sockaddr(sin, ic_netmask, 0); | 342 | set_sockaddr(sin, ic_netmask, 0); |
329 | if ((err = ic_dev_ioctl(SIOCSIFNETMASK, &ir)) < 0) { | 343 | if ((err = ic_devinet_ioctl(SIOCSIFNETMASK, &ir)) < 0) { |
330 | printk(KERN_ERR "IP-Config: Unable to set interface netmask (%d).\n", err); | 344 | printk(KERN_ERR "IP-Config: Unable to set interface netmask (%d).\n", err); |
331 | return -1; | 345 | return -1; |
332 | } | 346 | } |
333 | set_sockaddr(sin, ic_myaddr | ~ic_netmask, 0); | 347 | set_sockaddr(sin, ic_myaddr | ~ic_netmask, 0); |
334 | if ((err = ic_dev_ioctl(SIOCSIFBRDADDR, &ir)) < 0) { | 348 | if ((err = ic_devinet_ioctl(SIOCSIFBRDADDR, &ir)) < 0) { |
335 | printk(KERN_ERR "IP-Config: Unable to set interface broadcast address (%d).\n", err); | 349 | printk(KERN_ERR "IP-Config: Unable to set interface broadcast address (%d).\n", err); |
336 | return -1; | 350 | return -1; |
337 | } | 351 | } |
352 | /* Handle the case where we need non-standard MTU on the boot link (a network | ||
353 | * using jumbo frames, for instance). If we can't set the mtu, don't error | ||
354 | * out, we'll try to muddle along. | ||
355 | */ | ||
356 | if (ic_dev_mtu != 0) { | ||
357 | strcpy(ir.ifr_name, ic_dev->name); | ||
358 | ir.ifr_mtu = ic_dev_mtu; | ||
359 | if ((err = ic_dev_ioctl(SIOCSIFMTU, &ir)) < 0) | ||
360 | printk(KERN_ERR "IP-Config: Unable to set interface mtu to %d (%d).\n", | ||
361 | ic_dev_mtu, err); | ||
362 | } | ||
338 | return 0; | 363 | return 0; |
339 | } | 364 | } |
340 | 365 | ||
@@ -623,6 +648,7 @@ ic_dhcp_init_options(u8 *options) | |||
623 | 12, /* Host name */ | 648 | 12, /* Host name */ |
624 | 15, /* Domain name */ | 649 | 15, /* Domain name */ |
625 | 17, /* Boot path */ | 650 | 17, /* Boot path */ |
651 | 26, /* MTU */ | ||
626 | 40, /* NIS domain name */ | 652 | 40, /* NIS domain name */ |
627 | }; | 653 | }; |
628 | 654 | ||
@@ -798,6 +824,7 @@ static void __init ic_do_bootp_ext(u8 *ext) | |||
798 | { | 824 | { |
799 | u8 servers; | 825 | u8 servers; |
800 | int i; | 826 | int i; |
827 | u16 mtu; | ||
801 | 828 | ||
802 | #ifdef IPCONFIG_DEBUG | 829 | #ifdef IPCONFIG_DEBUG |
803 | u8 *c; | 830 | u8 *c; |
@@ -837,6 +864,10 @@ static void __init ic_do_bootp_ext(u8 *ext) | |||
837 | if (!root_server_path[0]) | 864 | if (!root_server_path[0]) |
838 | ic_bootp_string(root_server_path, ext+1, *ext, sizeof(root_server_path)); | 865 | ic_bootp_string(root_server_path, ext+1, *ext, sizeof(root_server_path)); |
839 | break; | 866 | break; |
867 | case 26: /* Interface MTU */ | ||
868 | memcpy(&mtu, ext+1, sizeof(mtu)); | ||
869 | ic_dev_mtu = ntohs(mtu); | ||
870 | break; | ||
840 | case 40: /* NIS Domain name (_not_ DNS) */ | 871 | case 40: /* NIS Domain name (_not_ DNS) */ |
841 | ic_bootp_string(utsname()->domainname, ext+1, *ext, __NEW_UTS_LEN); | 872 | ic_bootp_string(utsname()->domainname, ext+1, *ext, __NEW_UTS_LEN); |
842 | break; | 873 | break; |
@@ -1403,6 +1434,8 @@ static int __init ip_auto_config(void) | |||
1403 | printk(",\n bootserver=%pI4", &ic_servaddr); | 1434 | printk(",\n bootserver=%pI4", &ic_servaddr); |
1404 | printk(", rootserver=%pI4", &root_server_addr); | 1435 | printk(", rootserver=%pI4", &root_server_addr); |
1405 | printk(", rootpath=%s", root_server_path); | 1436 | printk(", rootpath=%s", root_server_path); |
1437 | if (ic_dev_mtu) | ||
1438 | printk(", mtu=%d", ic_dev_mtu); | ||
1406 | printk("\n"); | 1439 | printk("\n"); |
1407 | #endif /* !SILENT */ | 1440 | #endif /* !SILENT */ |
1408 | 1441 | ||