/*
* Automatic Configuration of IP -- use DHCP, BOOTP, RARP, or
* user-supplied information to configure own IP address and routes.
*
* Copyright (C) 1996-1998 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
*
* Derived from network configuration code in fs/nfs/nfsroot.c,
* originally Copyright (C) 1995, 1996 Gero Kuhlmann and me.
*
* BOOTP rewritten to construct and analyse packets itself instead
* of misusing the IP layer. num_bugs_causing_wrong_arp_replies--;
* -- MJ, December 1998
*
* Fixed ip_auto_config_setup calling at startup in the new "Linker Magic"
* initialization scheme.
* - Arnaldo Carvalho de Melo <acme@conectiva.com.br>, 08/11/1999
*
* DHCP support added. To users this looks like a whole separate
* protocol, but we know it's just a bag on the side of BOOTP.
* -- Chip Salzenberg <chip@valinux.com>, May 2000
*
* Ported DHCP support from 2.2.16 to 2.4.0-test4
* -- Eric Biederman <ebiederman@lnxi.com>, 30 Aug 2000
*
* Merged changes from 2.2.19 into 2.4.3
* -- Eric Biederman <ebiederman@lnxi.com>, 22 April Aug 2001
*
* Multiple Nameservers in /proc/net/pnp
* -- Josef Siemes <jsiemes@web.de>, Aug 2002
*/
#include <linux/types.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/jiffies.h>
#include <linux/random.h>
#include <linux/init.h>
#include <linux/utsname.h>
#include <linux/in.h>
#include <linux/if.h>
#include <linux/inet.h>
#include <linux/inetdevice.h>
#include <linux/netdevice.h>
#include <linux/if_arp.h>
#include <linux/skbuff.h>
#include <linux/ip.h>
#include <linux/socket.h>
#include <linux/route.h>
#include <linux/udp.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/major.h>
#include <linux/root_dev.h>
#include <linux/delay.h>
#include <linux/nfs_fs.h>
#include <net/net_namespace.h>
#include <net/arp.h>
#include <net/ip.h>
#include <net/ipconfig.h>
#include <net/route.h>
#include <asm/uaccess.h>
#include <net/checksum.h>
#include <asm/processor.h>
/* Define this to allow debugging output */
#undef IPCONFIG_DEBUG
#ifdef IPCONFIG_DEBUG
#define DBG(x) printk x
#else
#define DBG(x) do { } while(0)
#endif
#if defined(CONFIG_IP_PNP_DHCP)
#define IPCONFIG_DHCP
#endif
#if defined(CONFIG_IP_PNP_BOOTP) || defined(CONFIG_IP_PNP_DHCP)
#define IPCONFIG_BOOTP
#endif
#if defined(CONFIG_IP_PNP_RARP)
#define IPCONFIG_RARP
#endif
#if defined(IPCONFIG_BOOTP) || defined(IPCONFIG_RARP)
#define IPCONFIG_DYNAMIC
#endif
/* Define the friendly delay before and after opening net devices */
#define CONF_PRE_OPEN 500 /* Before opening: 1/2 second */
#define CONF_POST_OPEN 1 /* After opening: 1 second */
/* Define the timeout for waiting for a DHCP/BOOTP/RARP reply */
#define CONF_OPEN_RETRIES 2 /* (Re)open devices twice */
#define CONF_SEND_RETRIES 6 /* Send six requests per open */
#define CONF_INTER_TIMEOUT (HZ/2) /* Inter-device timeout: 1/2 second */
#define CONF_BASE_TIMEOUT (HZ*2) /* Initial timeout: 2 seconds */
#define CONF_TIMEOUT_RANDOM (HZ) /* Maximum amount of randomization */
#define CONF_TIMEOUT_MULT *7/4 /* Rate of timeout growth */
#define CONF_TIMEOUT_MAX (HZ*30) /* Maximum allowed timeout */
#define CONF_NAMESERVERS_MAX 3 /* Maximum number of nameservers
- '3' from resolv.h */
#define NONE __constant_htonl(INADDR_NONE)
#define ANY __constant_htonl(INADDR_ANY)
/*
* Public IP configuration
*/
/* This is used by platforms which might be able to set the ipconfig
* variables using firmware environment vars. If this is set, it will
* ignore such firmware variables.
*/
int ic_set_manually __initdata = 0; /* IPconfig parameters set manually */
static int ic_enable __initdata = 0; /* IP config enabled? */
/* Protocol choice */
int ic_proto_enabled __initdata = 0
#ifdef IPCONFIG_BOOTP
| IC_BOOTP
#endif
#ifdef CONFIG_IP_PNP_DHCP
| IC_USE_DHCP
#endif
#ifdef IPCONFIG_RARP
| IC_RARP
#endif
;
static int ic_host_name_set __initdata = 0; /* Host name set by us? */
__be32 ic_myaddr = NONE; /* My IP address */
static __be32 ic_netmask = NONE; /* Netmask for local subnet */
__be32 ic_gateway = NONE; /* Gateway IP address */
__be32 ic_servaddr = NONE; /* Boot server IP address */
__be32 root_server_addr = NONE; /* Address of NFS server */
u8 root_server_path[256] = { 0, }; /* Path to mount as root */
/* vendor class identifier */
static char vendor_class_identifier[253] __initdata;
/* Persistent data: */
static int ic_proto_used; /* Protocol used, if any */
static __be32 ic_nameservers[CONF_NAMESERVERS_MAX]; /* DNS Server IP addresses */
static u8 ic_domain[64]; /* DNS (not NIS) domain name */
/*
* Private state.
*/
/* Name of user-selected boot device */
static char user_dev_name[IFNAMSIZ] __initdata = { 0, };
/* Protocols supported by available interfaces */
static int ic_proto_have_if __initdata = 0;
#ifdef IPCONFIG_DYNAMIC
static DEFINE_SPINLOCK(ic_recv_lock);
static volatile int ic_got_reply __initdata = 0; /* Proto(s) that replied */
#endif
#ifdef IPCONFIG_DHCP
static int ic_dhcp_msgtype __initdata = 0; /* DHCP msg type received */
#endif
/*
* Network devices
*/
struct ic_device {
struct ic_device *next;
struct net_device *dev;
unsigned short flags;
short able;
__be32 xid;
};
static struct ic_device *ic_first_dev __initdata = NULL;/* List of open device */
static struct net_device *ic_dev __initdata = NULL; /* Selected device */
static int __init ic_open_devs(void)
{
struct ic_device *d, **last;
struct net_device *dev;
unsigned short oflags;
last = &ic_first_dev;
rtnl_lock();
/* bring loopback device up first */
for_each_netdev(&init_net, dev) {
if (!(dev->flags & IFF_LOOPBACK))
continue;
if (dev_change_flags(dev, dev->flags | IFF_UP) < 0)
printk(KERN_ERR "IP-Config: Failed to open %s\n", dev->name);
}
for_each_netdev(&init_net, dev) {
if (dev->flags & IFF_LOOPBACK)
continue;
if (user_dev_name[0] ? !strcmp(dev->name, user_dev_name) :
(!(dev->flags & IFF_LOOPBACK) &&
(dev->flags & (IFF_POINTOPOINT|IFF_BROADCAST)) &&
strncmp(dev->name, "dummy", 5))) {
int able = 0;
if (dev->mtu >= 364)
able |= IC_BOOTP;
else
printk(KERN_WARNING "DHCP/BOOTP: Ignoring device %s, MTU %d too small", dev->name, dev->mtu);
if (!(dev->flags & IFF_NOARP))
able |= IC_RARP;
able &= ic_proto_enabled;
if (ic_proto_enabled && !able)
continue;
oflags = dev->flags;
if (dev_change_flags(dev, oflags | IFF_UP) < 0) {
printk(KERN_ERR "IP-Config: Failed to open %s\n", dev->name);
continue;
}
if (!(d = kmalloc(sizeof(struct ic_device), GFP_KERNEL))) {
rtnl_unlock();
return -1;
}
d->dev = dev;
*last = d;
last = &d->next;
d->flags = oflags;
d->able = able;
if (able & IC_BOOTP)
get_random_bytes(&d->xid, sizeof(__be32));
else
d->xid = 0;
ic_proto_have_if |= able;
DBG(("IP-Config: %s UP (able=%d, xid=%08x)\n",
dev->name, able, d->xid));
}
}
rtnl_unlock();
*last = NULL;
if (!ic_first_dev) {
if (user_dev_name[0])
printk(KERN_ERR "IP-Config: Device `%s' not found.\n", user_dev_name);
else
|