162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  Automatic Configuration of IP -- use DHCP, BOOTP, RARP, or
462306a36Sopenharmony_ci *  user-supplied information to configure own IP address and routes.
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci *  Copyright (C) 1996-1998 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci *  Derived from network configuration code in fs/nfs/nfsroot.c,
962306a36Sopenharmony_ci *  originally Copyright (C) 1995, 1996 Gero Kuhlmann and me.
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci *  BOOTP rewritten to construct and analyse packets itself instead
1262306a36Sopenharmony_ci *  of misusing the IP layer. num_bugs_causing_wrong_arp_replies--;
1362306a36Sopenharmony_ci *					     -- MJ, December 1998
1462306a36Sopenharmony_ci *
1562306a36Sopenharmony_ci *  Fixed ip_auto_config_setup calling at startup in the new "Linker Magic"
1662306a36Sopenharmony_ci *  initialization scheme.
1762306a36Sopenharmony_ci *	- Arnaldo Carvalho de Melo <acme@conectiva.com.br>, 08/11/1999
1862306a36Sopenharmony_ci *
1962306a36Sopenharmony_ci *  DHCP support added.  To users this looks like a whole separate
2062306a36Sopenharmony_ci *  protocol, but we know it's just a bag on the side of BOOTP.
2162306a36Sopenharmony_ci *		-- Chip Salzenberg <chip@valinux.com>, May 2000
2262306a36Sopenharmony_ci *
2362306a36Sopenharmony_ci *  Ported DHCP support from 2.2.16 to 2.4.0-test4
2462306a36Sopenharmony_ci *              -- Eric Biederman <ebiederman@lnxi.com>, 30 Aug 2000
2562306a36Sopenharmony_ci *
2662306a36Sopenharmony_ci *  Merged changes from 2.2.19 into 2.4.3
2762306a36Sopenharmony_ci *              -- Eric Biederman <ebiederman@lnxi.com>, 22 April Aug 2001
2862306a36Sopenharmony_ci *
2962306a36Sopenharmony_ci *  Multiple Nameservers in /proc/net/pnp
3062306a36Sopenharmony_ci *              --  Josef Siemes <jsiemes@web.de>, Aug 2002
3162306a36Sopenharmony_ci *
3262306a36Sopenharmony_ci *  NTP servers in /proc/net/ipconfig/ntp_servers
3362306a36Sopenharmony_ci *              --  Chris Novakovic <chris@chrisn.me.uk>, April 2018
3462306a36Sopenharmony_ci */
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci#include <linux/types.h>
3762306a36Sopenharmony_ci#include <linux/string.h>
3862306a36Sopenharmony_ci#include <linux/kernel.h>
3962306a36Sopenharmony_ci#include <linux/jiffies.h>
4062306a36Sopenharmony_ci#include <linux/random.h>
4162306a36Sopenharmony_ci#include <linux/init.h>
4262306a36Sopenharmony_ci#include <linux/utsname.h>
4362306a36Sopenharmony_ci#include <linux/in.h>
4462306a36Sopenharmony_ci#include <linux/if.h>
4562306a36Sopenharmony_ci#include <linux/inet.h>
4662306a36Sopenharmony_ci#include <linux/inetdevice.h>
4762306a36Sopenharmony_ci#include <linux/netdevice.h>
4862306a36Sopenharmony_ci#include <linux/if_arp.h>
4962306a36Sopenharmony_ci#include <linux/skbuff.h>
5062306a36Sopenharmony_ci#include <linux/ip.h>
5162306a36Sopenharmony_ci#include <linux/socket.h>
5262306a36Sopenharmony_ci#include <linux/route.h>
5362306a36Sopenharmony_ci#include <linux/udp.h>
5462306a36Sopenharmony_ci#include <linux/proc_fs.h>
5562306a36Sopenharmony_ci#include <linux/seq_file.h>
5662306a36Sopenharmony_ci#include <linux/major.h>
5762306a36Sopenharmony_ci#include <linux/root_dev.h>
5862306a36Sopenharmony_ci#include <linux/delay.h>
5962306a36Sopenharmony_ci#include <linux/nfs_fs.h>
6062306a36Sopenharmony_ci#include <linux/slab.h>
6162306a36Sopenharmony_ci#include <linux/export.h>
6262306a36Sopenharmony_ci#include <net/net_namespace.h>
6362306a36Sopenharmony_ci#include <net/arp.h>
6462306a36Sopenharmony_ci#include <net/ip.h>
6562306a36Sopenharmony_ci#include <net/ipconfig.h>
6662306a36Sopenharmony_ci#include <net/route.h>
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci#include <linux/uaccess.h>
6962306a36Sopenharmony_ci#include <net/checksum.h>
7062306a36Sopenharmony_ci#include <asm/processor.h>
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci#if defined(CONFIG_IP_PNP_DHCP)
7362306a36Sopenharmony_ci#define IPCONFIG_DHCP
7462306a36Sopenharmony_ci#endif
7562306a36Sopenharmony_ci#if defined(CONFIG_IP_PNP_BOOTP) || defined(CONFIG_IP_PNP_DHCP)
7662306a36Sopenharmony_ci#define IPCONFIG_BOOTP
7762306a36Sopenharmony_ci#endif
7862306a36Sopenharmony_ci#if defined(CONFIG_IP_PNP_RARP)
7962306a36Sopenharmony_ci#define IPCONFIG_RARP
8062306a36Sopenharmony_ci#endif
8162306a36Sopenharmony_ci#if defined(IPCONFIG_BOOTP) || defined(IPCONFIG_RARP)
8262306a36Sopenharmony_ci#define IPCONFIG_DYNAMIC
8362306a36Sopenharmony_ci#endif
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci/* Define the friendly delay before and after opening net devices */
8662306a36Sopenharmony_ci#define CONF_POST_OPEN		10	/* After opening: 10 msecs */
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci/* Define the timeout for waiting for a DHCP/BOOTP/RARP reply */
8962306a36Sopenharmony_ci#define CONF_OPEN_RETRIES 	2	/* (Re)open devices twice */
9062306a36Sopenharmony_ci#define CONF_SEND_RETRIES 	6	/* Send six requests per open */
9162306a36Sopenharmony_ci#define CONF_BASE_TIMEOUT	(HZ*2)	/* Initial timeout: 2 seconds */
9262306a36Sopenharmony_ci#define CONF_TIMEOUT_RANDOM	(HZ)	/* Maximum amount of randomization */
9362306a36Sopenharmony_ci#define CONF_TIMEOUT_MULT	*7/4	/* Rate of timeout growth */
9462306a36Sopenharmony_ci#define CONF_TIMEOUT_MAX	(HZ*30)	/* Maximum allowed timeout */
9562306a36Sopenharmony_ci#define CONF_NAMESERVERS_MAX   3       /* Maximum number of nameservers
9662306a36Sopenharmony_ci					   - '3' from resolv.h */
9762306a36Sopenharmony_ci#define CONF_NTP_SERVERS_MAX   3	/* Maximum number of NTP servers */
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci#define NONE cpu_to_be32(INADDR_NONE)
10062306a36Sopenharmony_ci#define ANY cpu_to_be32(INADDR_ANY)
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci/* Wait for carrier timeout default in seconds */
10362306a36Sopenharmony_cistatic unsigned int carrier_timeout = 120;
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci/*
10662306a36Sopenharmony_ci * Public IP configuration
10762306a36Sopenharmony_ci */
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci/* This is used by platforms which might be able to set the ipconfig
11062306a36Sopenharmony_ci * variables using firmware environment vars.  If this is set, it will
11162306a36Sopenharmony_ci * ignore such firmware variables.
11262306a36Sopenharmony_ci */
11362306a36Sopenharmony_ciint ic_set_manually __initdata = 0;		/* IPconfig parameters set manually */
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_cistatic int ic_enable __initdata;		/* IP config enabled? */
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci/* Protocol choice */
11862306a36Sopenharmony_ciint ic_proto_enabled __initdata = 0
11962306a36Sopenharmony_ci#ifdef IPCONFIG_BOOTP
12062306a36Sopenharmony_ci			| IC_BOOTP
12162306a36Sopenharmony_ci#endif
12262306a36Sopenharmony_ci#ifdef CONFIG_IP_PNP_DHCP
12362306a36Sopenharmony_ci			| IC_USE_DHCP
12462306a36Sopenharmony_ci#endif
12562306a36Sopenharmony_ci#ifdef IPCONFIG_RARP
12662306a36Sopenharmony_ci			| IC_RARP
12762306a36Sopenharmony_ci#endif
12862306a36Sopenharmony_ci			;
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_cistatic int ic_host_name_set __initdata;	/* Host name set by us? */
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci__be32 ic_myaddr = NONE;		/* My IP address */
13362306a36Sopenharmony_cistatic __be32 ic_netmask = NONE;	/* Netmask for local subnet */
13462306a36Sopenharmony_ci__be32 ic_gateway = NONE;	/* Gateway IP address */
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci#ifdef IPCONFIG_DYNAMIC
13762306a36Sopenharmony_cistatic __be32 ic_addrservaddr = NONE;	/* IP Address of the IP addresses'server */
13862306a36Sopenharmony_ci#endif
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci__be32 ic_servaddr = NONE;	/* Boot server IP address */
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci__be32 root_server_addr = NONE;	/* Address of NFS server */
14362306a36Sopenharmony_ciu8 root_server_path[256] = { 0, };	/* Path to mount as root */
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci/* vendor class identifier */
14662306a36Sopenharmony_cistatic char vendor_class_identifier[253] __initdata;
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci#if defined(CONFIG_IP_PNP_DHCP)
14962306a36Sopenharmony_cistatic char dhcp_client_identifier[253] __initdata;
15062306a36Sopenharmony_ci#endif
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci/* Persistent data: */
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci#ifdef IPCONFIG_DYNAMIC
15562306a36Sopenharmony_cistatic int ic_proto_used;			/* Protocol used, if any */
15662306a36Sopenharmony_ci#else
15762306a36Sopenharmony_ci#define ic_proto_used 0
15862306a36Sopenharmony_ci#endif
15962306a36Sopenharmony_cistatic __be32 ic_nameservers[CONF_NAMESERVERS_MAX]; /* DNS Server IP addresses */
16062306a36Sopenharmony_cistatic __be32 ic_ntp_servers[CONF_NTP_SERVERS_MAX]; /* NTP server IP addresses */
16162306a36Sopenharmony_cistatic u8 ic_domain[64];		/* DNS (not NIS) domain name */
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci/*
16462306a36Sopenharmony_ci * Private state.
16562306a36Sopenharmony_ci */
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci/* Name of user-selected boot device */
16862306a36Sopenharmony_cistatic char user_dev_name[IFNAMSIZ] __initdata = { 0, };
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci/* Protocols supported by available interfaces */
17162306a36Sopenharmony_cistatic int ic_proto_have_if __initdata;
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci/* MTU for boot device */
17462306a36Sopenharmony_cistatic int ic_dev_mtu __initdata;
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci#ifdef IPCONFIG_DYNAMIC
17762306a36Sopenharmony_cistatic DEFINE_SPINLOCK(ic_recv_lock);
17862306a36Sopenharmony_cistatic volatile int ic_got_reply __initdata;    /* Proto(s) that replied */
17962306a36Sopenharmony_ci#endif
18062306a36Sopenharmony_ci#ifdef IPCONFIG_DHCP
18162306a36Sopenharmony_cistatic int ic_dhcp_msgtype __initdata;	/* DHCP msg type received */
18262306a36Sopenharmony_ci#endif
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci/*
18662306a36Sopenharmony_ci *	Network devices
18762306a36Sopenharmony_ci */
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_cistruct ic_device {
19062306a36Sopenharmony_ci	struct ic_device *next;
19162306a36Sopenharmony_ci	struct net_device *dev;
19262306a36Sopenharmony_ci	unsigned short flags;
19362306a36Sopenharmony_ci	short able;
19462306a36Sopenharmony_ci	__be32 xid;
19562306a36Sopenharmony_ci};
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_cistatic struct ic_device *ic_first_dev __initdata;	/* List of open device */
19862306a36Sopenharmony_cistatic struct ic_device *ic_dev __initdata;		/* Selected device */
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_cistatic bool __init ic_is_init_dev(struct net_device *dev)
20162306a36Sopenharmony_ci{
20262306a36Sopenharmony_ci	if (dev->flags & IFF_LOOPBACK)
20362306a36Sopenharmony_ci		return false;
20462306a36Sopenharmony_ci	return user_dev_name[0] ? !strcmp(dev->name, user_dev_name) :
20562306a36Sopenharmony_ci	    (!(dev->flags & IFF_LOOPBACK) &&
20662306a36Sopenharmony_ci	     (dev->flags & (IFF_POINTOPOINT|IFF_BROADCAST)) &&
20762306a36Sopenharmony_ci	     strncmp(dev->name, "dummy", 5));
20862306a36Sopenharmony_ci}
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_cistatic int __init ic_open_devs(void)
21162306a36Sopenharmony_ci{
21262306a36Sopenharmony_ci	struct ic_device *d, **last;
21362306a36Sopenharmony_ci	struct net_device *dev;
21462306a36Sopenharmony_ci	unsigned short oflags;
21562306a36Sopenharmony_ci	unsigned long start, next_msg;
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	last = &ic_first_dev;
21862306a36Sopenharmony_ci	rtnl_lock();
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	/* bring loopback device up first */
22162306a36Sopenharmony_ci	for_each_netdev(&init_net, dev) {
22262306a36Sopenharmony_ci		if (!(dev->flags & IFF_LOOPBACK))
22362306a36Sopenharmony_ci			continue;
22462306a36Sopenharmony_ci		if (dev_change_flags(dev, dev->flags | IFF_UP, NULL) < 0)
22562306a36Sopenharmony_ci			pr_err("IP-Config: Failed to open %s\n", dev->name);
22662306a36Sopenharmony_ci	}
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	for_each_netdev(&init_net, dev) {
22962306a36Sopenharmony_ci		if (ic_is_init_dev(dev)) {
23062306a36Sopenharmony_ci			int able = 0;
23162306a36Sopenharmony_ci			if (dev->mtu >= 364)
23262306a36Sopenharmony_ci				able |= IC_BOOTP;
23362306a36Sopenharmony_ci			else
23462306a36Sopenharmony_ci				pr_warn("DHCP/BOOTP: Ignoring device %s, MTU %d too small\n",
23562306a36Sopenharmony_ci					dev->name, dev->mtu);
23662306a36Sopenharmony_ci			if (!(dev->flags & IFF_NOARP))
23762306a36Sopenharmony_ci				able |= IC_RARP;
23862306a36Sopenharmony_ci			able &= ic_proto_enabled;
23962306a36Sopenharmony_ci			if (ic_proto_enabled && !able)
24062306a36Sopenharmony_ci				continue;
24162306a36Sopenharmony_ci			oflags = dev->flags;
24262306a36Sopenharmony_ci			if (dev_change_flags(dev, oflags | IFF_UP, NULL) < 0) {
24362306a36Sopenharmony_ci				pr_err("IP-Config: Failed to open %s\n",
24462306a36Sopenharmony_ci				       dev->name);
24562306a36Sopenharmony_ci				continue;
24662306a36Sopenharmony_ci			}
24762306a36Sopenharmony_ci			if (!(d = kmalloc(sizeof(struct ic_device), GFP_KERNEL))) {
24862306a36Sopenharmony_ci				rtnl_unlock();
24962306a36Sopenharmony_ci				return -ENOMEM;
25062306a36Sopenharmony_ci			}
25162306a36Sopenharmony_ci			d->dev = dev;
25262306a36Sopenharmony_ci			*last = d;
25362306a36Sopenharmony_ci			last = &d->next;
25462306a36Sopenharmony_ci			d->flags = oflags;
25562306a36Sopenharmony_ci			d->able = able;
25662306a36Sopenharmony_ci			if (able & IC_BOOTP)
25762306a36Sopenharmony_ci				get_random_bytes(&d->xid, sizeof(__be32));
25862306a36Sopenharmony_ci			else
25962306a36Sopenharmony_ci				d->xid = 0;
26062306a36Sopenharmony_ci			ic_proto_have_if |= able;
26162306a36Sopenharmony_ci			pr_debug("IP-Config: %s UP (able=%d, xid=%08x)\n",
26262306a36Sopenharmony_ci				 dev->name, able, d->xid);
26362306a36Sopenharmony_ci		}
26462306a36Sopenharmony_ci	}
26562306a36Sopenharmony_ci	/* Devices with a complex topology like SFP ethernet interfaces needs
26662306a36Sopenharmony_ci	 * the rtnl_lock at init. The carrier wait-loop must therefore run
26762306a36Sopenharmony_ci	 * without holding it.
26862306a36Sopenharmony_ci	 */
26962306a36Sopenharmony_ci	rtnl_unlock();
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	/* no point in waiting if we could not bring up at least one device */
27262306a36Sopenharmony_ci	if (!ic_first_dev)
27362306a36Sopenharmony_ci		goto have_carrier;
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	/* wait for a carrier on at least one device */
27662306a36Sopenharmony_ci	start = jiffies;
27762306a36Sopenharmony_ci	next_msg = start + msecs_to_jiffies(20000);
27862306a36Sopenharmony_ci	while (time_before(jiffies, start +
27962306a36Sopenharmony_ci			   msecs_to_jiffies(carrier_timeout * 1000))) {
28062306a36Sopenharmony_ci		int wait, elapsed;
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci		rtnl_lock();
28362306a36Sopenharmony_ci		for_each_netdev(&init_net, dev)
28462306a36Sopenharmony_ci			if (ic_is_init_dev(dev) && netif_carrier_ok(dev)) {
28562306a36Sopenharmony_ci				rtnl_unlock();
28662306a36Sopenharmony_ci				goto have_carrier;
28762306a36Sopenharmony_ci			}
28862306a36Sopenharmony_ci		rtnl_unlock();
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci		msleep(1);
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci		if (time_before(jiffies, next_msg))
29362306a36Sopenharmony_ci			continue;
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci		elapsed = jiffies_to_msecs(jiffies - start);
29662306a36Sopenharmony_ci		wait = (carrier_timeout * 1000 - elapsed + 500) / 1000;
29762306a36Sopenharmony_ci		pr_info("Waiting up to %d more seconds for network.\n", wait);
29862306a36Sopenharmony_ci		next_msg = jiffies + msecs_to_jiffies(20000);
29962306a36Sopenharmony_ci	}
30062306a36Sopenharmony_cihave_carrier:
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci	*last = NULL;
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	if (!ic_first_dev) {
30562306a36Sopenharmony_ci		if (user_dev_name[0])
30662306a36Sopenharmony_ci			pr_err("IP-Config: Device `%s' not found\n",
30762306a36Sopenharmony_ci			       user_dev_name);
30862306a36Sopenharmony_ci		else
30962306a36Sopenharmony_ci			pr_err("IP-Config: No network devices available\n");
31062306a36Sopenharmony_ci		return -ENODEV;
31162306a36Sopenharmony_ci	}
31262306a36Sopenharmony_ci	return 0;
31362306a36Sopenharmony_ci}
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci/* Close all network interfaces except the one we've autoconfigured, and its
31662306a36Sopenharmony_ci * lowers, in case it's a stacked virtual interface.
31762306a36Sopenharmony_ci */
31862306a36Sopenharmony_cistatic void __init ic_close_devs(void)
31962306a36Sopenharmony_ci{
32062306a36Sopenharmony_ci	struct net_device *selected_dev = ic_dev ? ic_dev->dev : NULL;
32162306a36Sopenharmony_ci	struct ic_device *d, *next;
32262306a36Sopenharmony_ci	struct net_device *dev;
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	rtnl_lock();
32562306a36Sopenharmony_ci	next = ic_first_dev;
32662306a36Sopenharmony_ci	while ((d = next)) {
32762306a36Sopenharmony_ci		bool bring_down = (d != ic_dev);
32862306a36Sopenharmony_ci		struct net_device *lower;
32962306a36Sopenharmony_ci		struct list_head *iter;
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci		next = d->next;
33262306a36Sopenharmony_ci		dev = d->dev;
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci		if (selected_dev) {
33562306a36Sopenharmony_ci			netdev_for_each_lower_dev(selected_dev, lower, iter) {
33662306a36Sopenharmony_ci				if (dev == lower) {
33762306a36Sopenharmony_ci					bring_down = false;
33862306a36Sopenharmony_ci					break;
33962306a36Sopenharmony_ci				}
34062306a36Sopenharmony_ci			}
34162306a36Sopenharmony_ci		}
34262306a36Sopenharmony_ci		if (bring_down) {
34362306a36Sopenharmony_ci			pr_debug("IP-Config: Downing %s\n", dev->name);
34462306a36Sopenharmony_ci			dev_change_flags(dev, d->flags, NULL);
34562306a36Sopenharmony_ci		}
34662306a36Sopenharmony_ci		kfree(d);
34762306a36Sopenharmony_ci	}
34862306a36Sopenharmony_ci	rtnl_unlock();
34962306a36Sopenharmony_ci}
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci/*
35262306a36Sopenharmony_ci *	Interface to various network functions.
35362306a36Sopenharmony_ci */
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_cistatic inline void
35662306a36Sopenharmony_ciset_sockaddr(struct sockaddr_in *sin, __be32 addr, __be16 port)
35762306a36Sopenharmony_ci{
35862306a36Sopenharmony_ci	sin->sin_family = AF_INET;
35962306a36Sopenharmony_ci	sin->sin_addr.s_addr = addr;
36062306a36Sopenharmony_ci	sin->sin_port = port;
36162306a36Sopenharmony_ci}
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci/*
36462306a36Sopenharmony_ci *	Set up interface addresses and routes.
36562306a36Sopenharmony_ci */
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_cistatic int __init ic_setup_if(void)
36862306a36Sopenharmony_ci{
36962306a36Sopenharmony_ci	struct ifreq ir;
37062306a36Sopenharmony_ci	struct sockaddr_in *sin = (void *) &ir.ifr_ifru.ifru_addr;
37162306a36Sopenharmony_ci	int err;
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	memset(&ir, 0, sizeof(ir));
37462306a36Sopenharmony_ci	strcpy(ir.ifr_ifrn.ifrn_name, ic_dev->dev->name);
37562306a36Sopenharmony_ci	set_sockaddr(sin, ic_myaddr, 0);
37662306a36Sopenharmony_ci	if ((err = devinet_ioctl(&init_net, SIOCSIFADDR, &ir)) < 0) {
37762306a36Sopenharmony_ci		pr_err("IP-Config: Unable to set interface address (%d)\n",
37862306a36Sopenharmony_ci		       err);
37962306a36Sopenharmony_ci		return -1;
38062306a36Sopenharmony_ci	}
38162306a36Sopenharmony_ci	set_sockaddr(sin, ic_netmask, 0);
38262306a36Sopenharmony_ci	if ((err = devinet_ioctl(&init_net, SIOCSIFNETMASK, &ir)) < 0) {
38362306a36Sopenharmony_ci		pr_err("IP-Config: Unable to set interface netmask (%d)\n",
38462306a36Sopenharmony_ci		       err);
38562306a36Sopenharmony_ci		return -1;
38662306a36Sopenharmony_ci	}
38762306a36Sopenharmony_ci	set_sockaddr(sin, ic_myaddr | ~ic_netmask, 0);
38862306a36Sopenharmony_ci	if ((err = devinet_ioctl(&init_net, SIOCSIFBRDADDR, &ir)) < 0) {
38962306a36Sopenharmony_ci		pr_err("IP-Config: Unable to set interface broadcast address (%d)\n",
39062306a36Sopenharmony_ci		       err);
39162306a36Sopenharmony_ci		return -1;
39262306a36Sopenharmony_ci	}
39362306a36Sopenharmony_ci	/* Handle the case where we need non-standard MTU on the boot link (a network
39462306a36Sopenharmony_ci	 * using jumbo frames, for instance).  If we can't set the mtu, don't error
39562306a36Sopenharmony_ci	 * out, we'll try to muddle along.
39662306a36Sopenharmony_ci	 */
39762306a36Sopenharmony_ci	if (ic_dev_mtu != 0) {
39862306a36Sopenharmony_ci		rtnl_lock();
39962306a36Sopenharmony_ci		if ((err = dev_set_mtu(ic_dev->dev, ic_dev_mtu)) < 0)
40062306a36Sopenharmony_ci			pr_err("IP-Config: Unable to set interface mtu to %d (%d)\n",
40162306a36Sopenharmony_ci			       ic_dev_mtu, err);
40262306a36Sopenharmony_ci		rtnl_unlock();
40362306a36Sopenharmony_ci	}
40462306a36Sopenharmony_ci	return 0;
40562306a36Sopenharmony_ci}
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_cistatic int __init ic_setup_routes(void)
40862306a36Sopenharmony_ci{
40962306a36Sopenharmony_ci	/* No need to setup device routes, only the default route... */
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	if (ic_gateway != NONE) {
41262306a36Sopenharmony_ci		struct rtentry rm;
41362306a36Sopenharmony_ci		int err;
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci		memset(&rm, 0, sizeof(rm));
41662306a36Sopenharmony_ci		if ((ic_gateway ^ ic_myaddr) & ic_netmask) {
41762306a36Sopenharmony_ci			pr_err("IP-Config: Gateway not on directly connected network\n");
41862306a36Sopenharmony_ci			return -1;
41962306a36Sopenharmony_ci		}
42062306a36Sopenharmony_ci		set_sockaddr((struct sockaddr_in *) &rm.rt_dst, 0, 0);
42162306a36Sopenharmony_ci		set_sockaddr((struct sockaddr_in *) &rm.rt_genmask, 0, 0);
42262306a36Sopenharmony_ci		set_sockaddr((struct sockaddr_in *) &rm.rt_gateway, ic_gateway, 0);
42362306a36Sopenharmony_ci		rm.rt_flags = RTF_UP | RTF_GATEWAY;
42462306a36Sopenharmony_ci		if ((err = ip_rt_ioctl(&init_net, SIOCADDRT, &rm)) < 0) {
42562306a36Sopenharmony_ci			pr_err("IP-Config: Cannot add default route (%d)\n",
42662306a36Sopenharmony_ci			       err);
42762306a36Sopenharmony_ci			return -1;
42862306a36Sopenharmony_ci		}
42962306a36Sopenharmony_ci	}
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	return 0;
43262306a36Sopenharmony_ci}
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci/*
43562306a36Sopenharmony_ci *	Fill in default values for all missing parameters.
43662306a36Sopenharmony_ci */
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_cistatic int __init ic_defaults(void)
43962306a36Sopenharmony_ci{
44062306a36Sopenharmony_ci	/*
44162306a36Sopenharmony_ci	 *	At this point we have no userspace running so need not
44262306a36Sopenharmony_ci	 *	claim locks on system_utsname
44362306a36Sopenharmony_ci	 */
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	if (!ic_host_name_set)
44662306a36Sopenharmony_ci		sprintf(init_utsname()->nodename, "%pI4", &ic_myaddr);
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci	if (root_server_addr == NONE)
44962306a36Sopenharmony_ci		root_server_addr = ic_servaddr;
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci	if (ic_netmask == NONE) {
45262306a36Sopenharmony_ci		if (IN_CLASSA(ntohl(ic_myaddr)))
45362306a36Sopenharmony_ci			ic_netmask = htonl(IN_CLASSA_NET);
45462306a36Sopenharmony_ci		else if (IN_CLASSB(ntohl(ic_myaddr)))
45562306a36Sopenharmony_ci			ic_netmask = htonl(IN_CLASSB_NET);
45662306a36Sopenharmony_ci		else if (IN_CLASSC(ntohl(ic_myaddr)))
45762306a36Sopenharmony_ci			ic_netmask = htonl(IN_CLASSC_NET);
45862306a36Sopenharmony_ci		else if (IN_CLASSE(ntohl(ic_myaddr)))
45962306a36Sopenharmony_ci			ic_netmask = htonl(IN_CLASSE_NET);
46062306a36Sopenharmony_ci		else {
46162306a36Sopenharmony_ci			pr_err("IP-Config: Unable to guess netmask for address %pI4\n",
46262306a36Sopenharmony_ci			       &ic_myaddr);
46362306a36Sopenharmony_ci			return -1;
46462306a36Sopenharmony_ci		}
46562306a36Sopenharmony_ci		pr_notice("IP-Config: Guessing netmask %pI4\n",
46662306a36Sopenharmony_ci			  &ic_netmask);
46762306a36Sopenharmony_ci	}
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci	return 0;
47062306a36Sopenharmony_ci}
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci/*
47362306a36Sopenharmony_ci *	RARP support.
47462306a36Sopenharmony_ci */
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci#ifdef IPCONFIG_RARP
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_cistatic int ic_rarp_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev);
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_cistatic struct packet_type rarp_packet_type __initdata = {
48162306a36Sopenharmony_ci	.type =	cpu_to_be16(ETH_P_RARP),
48262306a36Sopenharmony_ci	.func =	ic_rarp_recv,
48362306a36Sopenharmony_ci};
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_cistatic inline void __init ic_rarp_init(void)
48662306a36Sopenharmony_ci{
48762306a36Sopenharmony_ci	dev_add_pack(&rarp_packet_type);
48862306a36Sopenharmony_ci}
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_cistatic inline void __init ic_rarp_cleanup(void)
49162306a36Sopenharmony_ci{
49262306a36Sopenharmony_ci	dev_remove_pack(&rarp_packet_type);
49362306a36Sopenharmony_ci}
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci/*
49662306a36Sopenharmony_ci *  Process received RARP packet.
49762306a36Sopenharmony_ci */
49862306a36Sopenharmony_cistatic int __init
49962306a36Sopenharmony_ciic_rarp_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
50062306a36Sopenharmony_ci{
50162306a36Sopenharmony_ci	struct arphdr *rarp;
50262306a36Sopenharmony_ci	unsigned char *rarp_ptr;
50362306a36Sopenharmony_ci	__be32 sip, tip;
50462306a36Sopenharmony_ci	unsigned char *tha;		/* t for "target" */
50562306a36Sopenharmony_ci	struct ic_device *d;
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci	if (!net_eq(dev_net(dev), &init_net))
50862306a36Sopenharmony_ci		goto drop;
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci	skb = skb_share_check(skb, GFP_ATOMIC);
51162306a36Sopenharmony_ci	if (!skb)
51262306a36Sopenharmony_ci		return NET_RX_DROP;
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci	if (!pskb_may_pull(skb, sizeof(struct arphdr)))
51562306a36Sopenharmony_ci		goto drop;
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci	/* Basic sanity checks can be done without the lock.  */
51862306a36Sopenharmony_ci	rarp = (struct arphdr *)skb_transport_header(skb);
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci	/* If this test doesn't pass, it's not IP, or we should
52162306a36Sopenharmony_ci	 * ignore it anyway.
52262306a36Sopenharmony_ci	 */
52362306a36Sopenharmony_ci	if (rarp->ar_hln != dev->addr_len || dev->type != ntohs(rarp->ar_hrd))
52462306a36Sopenharmony_ci		goto drop;
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci	/* If it's not a RARP reply, delete it. */
52762306a36Sopenharmony_ci	if (rarp->ar_op != htons(ARPOP_RREPLY))
52862306a36Sopenharmony_ci		goto drop;
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci	/* If it's not Ethernet, delete it. */
53162306a36Sopenharmony_ci	if (rarp->ar_pro != htons(ETH_P_IP))
53262306a36Sopenharmony_ci		goto drop;
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci	if (!pskb_may_pull(skb, arp_hdr_len(dev)))
53562306a36Sopenharmony_ci		goto drop;
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci	/* OK, it is all there and looks valid, process... */
53862306a36Sopenharmony_ci	rarp = (struct arphdr *)skb_transport_header(skb);
53962306a36Sopenharmony_ci	rarp_ptr = (unsigned char *) (rarp + 1);
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ci	/* One reply at a time, please. */
54262306a36Sopenharmony_ci	spin_lock(&ic_recv_lock);
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci	/* If we already have a reply, just drop the packet */
54562306a36Sopenharmony_ci	if (ic_got_reply)
54662306a36Sopenharmony_ci		goto drop_unlock;
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci	/* Find the ic_device that the packet arrived on */
54962306a36Sopenharmony_ci	d = ic_first_dev;
55062306a36Sopenharmony_ci	while (d && d->dev != dev)
55162306a36Sopenharmony_ci		d = d->next;
55262306a36Sopenharmony_ci	if (!d)
55362306a36Sopenharmony_ci		goto drop_unlock;	/* should never happen */
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci	/* Extract variable-width fields */
55662306a36Sopenharmony_ci	rarp_ptr += dev->addr_len;
55762306a36Sopenharmony_ci	memcpy(&sip, rarp_ptr, 4);
55862306a36Sopenharmony_ci	rarp_ptr += 4;
55962306a36Sopenharmony_ci	tha = rarp_ptr;
56062306a36Sopenharmony_ci	rarp_ptr += dev->addr_len;
56162306a36Sopenharmony_ci	memcpy(&tip, rarp_ptr, 4);
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci	/* Discard packets which are not meant for us. */
56462306a36Sopenharmony_ci	if (memcmp(tha, dev->dev_addr, dev->addr_len))
56562306a36Sopenharmony_ci		goto drop_unlock;
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci	/* Discard packets which are not from specified server. */
56862306a36Sopenharmony_ci	if (ic_servaddr != NONE && ic_servaddr != sip)
56962306a36Sopenharmony_ci		goto drop_unlock;
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci	/* We have a winner! */
57262306a36Sopenharmony_ci	ic_dev = d;
57362306a36Sopenharmony_ci	if (ic_myaddr == NONE)
57462306a36Sopenharmony_ci		ic_myaddr = tip;
57562306a36Sopenharmony_ci	ic_servaddr = sip;
57662306a36Sopenharmony_ci	ic_addrservaddr = sip;
57762306a36Sopenharmony_ci	ic_got_reply = IC_RARP;
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_cidrop_unlock:
58062306a36Sopenharmony_ci	/* Show's over.  Nothing to see here.  */
58162306a36Sopenharmony_ci	spin_unlock(&ic_recv_lock);
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_cidrop:
58462306a36Sopenharmony_ci	/* Throw the packet out. */
58562306a36Sopenharmony_ci	kfree_skb(skb);
58662306a36Sopenharmony_ci	return 0;
58762306a36Sopenharmony_ci}
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci/*
59162306a36Sopenharmony_ci *  Send RARP request packet over a single interface.
59262306a36Sopenharmony_ci */
59362306a36Sopenharmony_cistatic void __init ic_rarp_send_if(struct ic_device *d)
59462306a36Sopenharmony_ci{
59562306a36Sopenharmony_ci	struct net_device *dev = d->dev;
59662306a36Sopenharmony_ci	arp_send(ARPOP_RREQUEST, ETH_P_RARP, 0, dev, 0, NULL,
59762306a36Sopenharmony_ci		 dev->dev_addr, dev->dev_addr);
59862306a36Sopenharmony_ci}
59962306a36Sopenharmony_ci#endif
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci/*
60262306a36Sopenharmony_ci *  Predefine Nameservers
60362306a36Sopenharmony_ci */
60462306a36Sopenharmony_cistatic inline void __init ic_nameservers_predef(void)
60562306a36Sopenharmony_ci{
60662306a36Sopenharmony_ci	int i;
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ci	for (i = 0; i < CONF_NAMESERVERS_MAX; i++)
60962306a36Sopenharmony_ci		ic_nameservers[i] = NONE;
61062306a36Sopenharmony_ci}
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci/* Predefine NTP servers */
61362306a36Sopenharmony_cistatic inline void __init ic_ntp_servers_predef(void)
61462306a36Sopenharmony_ci{
61562306a36Sopenharmony_ci	int i;
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ci	for (i = 0; i < CONF_NTP_SERVERS_MAX; i++)
61862306a36Sopenharmony_ci		ic_ntp_servers[i] = NONE;
61962306a36Sopenharmony_ci}
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci/*
62262306a36Sopenharmony_ci *	DHCP/BOOTP support.
62362306a36Sopenharmony_ci */
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci#ifdef IPCONFIG_BOOTP
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_cistruct bootp_pkt {		/* BOOTP packet format */
62862306a36Sopenharmony_ci	struct iphdr iph;	/* IP header */
62962306a36Sopenharmony_ci	struct udphdr udph;	/* UDP header */
63062306a36Sopenharmony_ci	u8 op;			/* 1=request, 2=reply */
63162306a36Sopenharmony_ci	u8 htype;		/* HW address type */
63262306a36Sopenharmony_ci	u8 hlen;		/* HW address length */
63362306a36Sopenharmony_ci	u8 hops;		/* Used only by gateways */
63462306a36Sopenharmony_ci	__be32 xid;		/* Transaction ID */
63562306a36Sopenharmony_ci	__be16 secs;		/* Seconds since we started */
63662306a36Sopenharmony_ci	__be16 flags;		/* Just what it says */
63762306a36Sopenharmony_ci	__be32 client_ip;		/* Client's IP address if known */
63862306a36Sopenharmony_ci	__be32 your_ip;		/* Assigned IP address */
63962306a36Sopenharmony_ci	__be32 server_ip;		/* (Next, e.g. NFS) Server's IP address */
64062306a36Sopenharmony_ci	__be32 relay_ip;		/* IP address of BOOTP relay */
64162306a36Sopenharmony_ci	u8 hw_addr[16];		/* Client's HW address */
64262306a36Sopenharmony_ci	u8 serv_name[64];	/* Server host name */
64362306a36Sopenharmony_ci	u8 boot_file[128];	/* Name of boot file */
64462306a36Sopenharmony_ci	u8 exten[312];		/* DHCP options / BOOTP vendor extensions */
64562306a36Sopenharmony_ci};
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci/* packet ops */
64862306a36Sopenharmony_ci#define BOOTP_REQUEST	1
64962306a36Sopenharmony_ci#define BOOTP_REPLY	2
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_ci/* DHCP message types */
65262306a36Sopenharmony_ci#define DHCPDISCOVER	1
65362306a36Sopenharmony_ci#define DHCPOFFER	2
65462306a36Sopenharmony_ci#define DHCPREQUEST	3
65562306a36Sopenharmony_ci#define DHCPDECLINE	4
65662306a36Sopenharmony_ci#define DHCPACK		5
65762306a36Sopenharmony_ci#define DHCPNAK		6
65862306a36Sopenharmony_ci#define DHCPRELEASE	7
65962306a36Sopenharmony_ci#define DHCPINFORM	8
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_cistatic int ic_bootp_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev);
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_cistatic struct packet_type bootp_packet_type __initdata = {
66462306a36Sopenharmony_ci	.type =	cpu_to_be16(ETH_P_IP),
66562306a36Sopenharmony_ci	.func =	ic_bootp_recv,
66662306a36Sopenharmony_ci};
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_ci/* DHCPACK can overwrite DNS if fallback was set upon first BOOTP reply */
66962306a36Sopenharmony_cistatic int ic_nameservers_fallback __initdata;
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_ci/*
67262306a36Sopenharmony_ci *  Initialize DHCP/BOOTP extension fields in the request.
67362306a36Sopenharmony_ci */
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_cistatic const u8 ic_bootp_cookie[4] = { 99, 130, 83, 99 };
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_ci#ifdef IPCONFIG_DHCP
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_cistatic void __init
68062306a36Sopenharmony_ciic_dhcp_init_options(u8 *options, struct ic_device *d)
68162306a36Sopenharmony_ci{
68262306a36Sopenharmony_ci	u8 mt = ((ic_servaddr == NONE)
68362306a36Sopenharmony_ci		 ? DHCPDISCOVER : DHCPREQUEST);
68462306a36Sopenharmony_ci	u8 *e = options;
68562306a36Sopenharmony_ci	int len;
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ci	pr_debug("DHCP: Sending message type %d (%s)\n", mt, d->dev->name);
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci	memcpy(e, ic_bootp_cookie, 4);	/* RFC1048 Magic Cookie */
69062306a36Sopenharmony_ci	e += 4;
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci	*e++ = 53;		/* DHCP message type */
69362306a36Sopenharmony_ci	*e++ = 1;
69462306a36Sopenharmony_ci	*e++ = mt;
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci	if (mt == DHCPREQUEST) {
69762306a36Sopenharmony_ci		*e++ = 54;	/* Server ID (IP address) */
69862306a36Sopenharmony_ci		*e++ = 4;
69962306a36Sopenharmony_ci		memcpy(e, &ic_servaddr, 4);
70062306a36Sopenharmony_ci		e += 4;
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_ci		*e++ = 50;	/* Requested IP address */
70362306a36Sopenharmony_ci		*e++ = 4;
70462306a36Sopenharmony_ci		memcpy(e, &ic_myaddr, 4);
70562306a36Sopenharmony_ci		e += 4;
70662306a36Sopenharmony_ci	}
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_ci	/* always? */
70962306a36Sopenharmony_ci	{
71062306a36Sopenharmony_ci		static const u8 ic_req_params[] = {
71162306a36Sopenharmony_ci			1,	/* Subnet mask */
71262306a36Sopenharmony_ci			3,	/* Default gateway */
71362306a36Sopenharmony_ci			6,	/* DNS server */
71462306a36Sopenharmony_ci			12,	/* Host name */
71562306a36Sopenharmony_ci			15,	/* Domain name */
71662306a36Sopenharmony_ci			17,	/* Boot path */
71762306a36Sopenharmony_ci			26,	/* MTU */
71862306a36Sopenharmony_ci			40,	/* NIS domain name */
71962306a36Sopenharmony_ci			42,	/* NTP servers */
72062306a36Sopenharmony_ci		};
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_ci		*e++ = 55;	/* Parameter request list */
72362306a36Sopenharmony_ci		*e++ = sizeof(ic_req_params);
72462306a36Sopenharmony_ci		memcpy(e, ic_req_params, sizeof(ic_req_params));
72562306a36Sopenharmony_ci		e += sizeof(ic_req_params);
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_ci		if (ic_host_name_set) {
72862306a36Sopenharmony_ci			*e++ = 12;	/* host-name */
72962306a36Sopenharmony_ci			len = strlen(utsname()->nodename);
73062306a36Sopenharmony_ci			*e++ = len;
73162306a36Sopenharmony_ci			memcpy(e, utsname()->nodename, len);
73262306a36Sopenharmony_ci			e += len;
73362306a36Sopenharmony_ci		}
73462306a36Sopenharmony_ci		if (*vendor_class_identifier) {
73562306a36Sopenharmony_ci			pr_info("DHCP: sending class identifier \"%s\"\n",
73662306a36Sopenharmony_ci				vendor_class_identifier);
73762306a36Sopenharmony_ci			*e++ = 60;	/* Class-identifier */
73862306a36Sopenharmony_ci			len = strlen(vendor_class_identifier);
73962306a36Sopenharmony_ci			*e++ = len;
74062306a36Sopenharmony_ci			memcpy(e, vendor_class_identifier, len);
74162306a36Sopenharmony_ci			e += len;
74262306a36Sopenharmony_ci		}
74362306a36Sopenharmony_ci		len = strlen(dhcp_client_identifier + 1);
74462306a36Sopenharmony_ci		/* the minimum length of identifier is 2, include 1 byte type,
74562306a36Sopenharmony_ci		 * and can not be larger than the length of options
74662306a36Sopenharmony_ci		 */
74762306a36Sopenharmony_ci		if (len >= 1 && len < 312 - (e - options) - 1) {
74862306a36Sopenharmony_ci			*e++ = 61;
74962306a36Sopenharmony_ci			*e++ = len + 1;
75062306a36Sopenharmony_ci			memcpy(e, dhcp_client_identifier, len + 1);
75162306a36Sopenharmony_ci			e += len + 1;
75262306a36Sopenharmony_ci		}
75362306a36Sopenharmony_ci	}
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_ci	*e++ = 255;	/* End of the list */
75662306a36Sopenharmony_ci}
75762306a36Sopenharmony_ci
75862306a36Sopenharmony_ci#endif /* IPCONFIG_DHCP */
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_cistatic void __init ic_bootp_init_ext(u8 *e)
76162306a36Sopenharmony_ci{
76262306a36Sopenharmony_ci	memcpy(e, ic_bootp_cookie, 4);	/* RFC1048 Magic Cookie */
76362306a36Sopenharmony_ci	e += 4;
76462306a36Sopenharmony_ci	*e++ = 1;		/* Subnet mask request */
76562306a36Sopenharmony_ci	*e++ = 4;
76662306a36Sopenharmony_ci	e += 4;
76762306a36Sopenharmony_ci	*e++ = 3;		/* Default gateway request */
76862306a36Sopenharmony_ci	*e++ = 4;
76962306a36Sopenharmony_ci	e += 4;
77062306a36Sopenharmony_ci#if CONF_NAMESERVERS_MAX > 0
77162306a36Sopenharmony_ci	*e++ = 6;		/* (DNS) name server request */
77262306a36Sopenharmony_ci	*e++ = 4 * CONF_NAMESERVERS_MAX;
77362306a36Sopenharmony_ci	e += 4 * CONF_NAMESERVERS_MAX;
77462306a36Sopenharmony_ci#endif
77562306a36Sopenharmony_ci	*e++ = 12;		/* Host name request */
77662306a36Sopenharmony_ci	*e++ = 32;
77762306a36Sopenharmony_ci	e += 32;
77862306a36Sopenharmony_ci	*e++ = 40;		/* NIS Domain name request */
77962306a36Sopenharmony_ci	*e++ = 32;
78062306a36Sopenharmony_ci	e += 32;
78162306a36Sopenharmony_ci	*e++ = 17;		/* Boot path */
78262306a36Sopenharmony_ci	*e++ = 40;
78362306a36Sopenharmony_ci	e += 40;
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_ci	*e++ = 57;		/* set extension buffer size for reply */
78662306a36Sopenharmony_ci	*e++ = 2;
78762306a36Sopenharmony_ci	*e++ = 1;		/* 128+236+8+20+14, see dhcpd sources */
78862306a36Sopenharmony_ci	*e++ = 150;
78962306a36Sopenharmony_ci
79062306a36Sopenharmony_ci	*e++ = 255;		/* End of the list */
79162306a36Sopenharmony_ci}
79262306a36Sopenharmony_ci
79362306a36Sopenharmony_ci
79462306a36Sopenharmony_ci/*
79562306a36Sopenharmony_ci *  Initialize the DHCP/BOOTP mechanism.
79662306a36Sopenharmony_ci */
79762306a36Sopenharmony_cistatic inline void __init ic_bootp_init(void)
79862306a36Sopenharmony_ci{
79962306a36Sopenharmony_ci	/* Re-initialise all name servers and NTP servers to NONE, in case any
80062306a36Sopenharmony_ci	 * were set via the "ip=" or "nfsaddrs=" kernel command line parameters:
80162306a36Sopenharmony_ci	 * any IP addresses specified there will already have been decoded but
80262306a36Sopenharmony_ci	 * are no longer needed
80362306a36Sopenharmony_ci	 */
80462306a36Sopenharmony_ci	ic_nameservers_predef();
80562306a36Sopenharmony_ci	ic_ntp_servers_predef();
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci	dev_add_pack(&bootp_packet_type);
80862306a36Sopenharmony_ci}
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_ci/*
81262306a36Sopenharmony_ci *  DHCP/BOOTP cleanup.
81362306a36Sopenharmony_ci */
81462306a36Sopenharmony_cistatic inline void __init ic_bootp_cleanup(void)
81562306a36Sopenharmony_ci{
81662306a36Sopenharmony_ci	dev_remove_pack(&bootp_packet_type);
81762306a36Sopenharmony_ci}
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_ci
82062306a36Sopenharmony_ci/*
82162306a36Sopenharmony_ci *  Send DHCP/BOOTP request to single interface.
82262306a36Sopenharmony_ci */
82362306a36Sopenharmony_cistatic void __init ic_bootp_send_if(struct ic_device *d, unsigned long jiffies_diff)
82462306a36Sopenharmony_ci{
82562306a36Sopenharmony_ci	struct net_device *dev = d->dev;
82662306a36Sopenharmony_ci	struct sk_buff *skb;
82762306a36Sopenharmony_ci	struct bootp_pkt *b;
82862306a36Sopenharmony_ci	struct iphdr *h;
82962306a36Sopenharmony_ci	int hlen = LL_RESERVED_SPACE(dev);
83062306a36Sopenharmony_ci	int tlen = dev->needed_tailroom;
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_ci	/* Allocate packet */
83362306a36Sopenharmony_ci	skb = alloc_skb(sizeof(struct bootp_pkt) + hlen + tlen + 15,
83462306a36Sopenharmony_ci			GFP_KERNEL);
83562306a36Sopenharmony_ci	if (!skb)
83662306a36Sopenharmony_ci		return;
83762306a36Sopenharmony_ci	skb_reserve(skb, hlen);
83862306a36Sopenharmony_ci	b = skb_put_zero(skb, sizeof(struct bootp_pkt));
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_ci	/* Construct IP header */
84162306a36Sopenharmony_ci	skb_reset_network_header(skb);
84262306a36Sopenharmony_ci	h = ip_hdr(skb);
84362306a36Sopenharmony_ci	h->version = 4;
84462306a36Sopenharmony_ci	h->ihl = 5;
84562306a36Sopenharmony_ci	h->tot_len = htons(sizeof(struct bootp_pkt));
84662306a36Sopenharmony_ci	h->frag_off = htons(IP_DF);
84762306a36Sopenharmony_ci	h->ttl = 64;
84862306a36Sopenharmony_ci	h->protocol = IPPROTO_UDP;
84962306a36Sopenharmony_ci	h->daddr = htonl(INADDR_BROADCAST);
85062306a36Sopenharmony_ci	h->check = ip_fast_csum((unsigned char *) h, h->ihl);
85162306a36Sopenharmony_ci
85262306a36Sopenharmony_ci	/* Construct UDP header */
85362306a36Sopenharmony_ci	b->udph.source = htons(68);
85462306a36Sopenharmony_ci	b->udph.dest = htons(67);
85562306a36Sopenharmony_ci	b->udph.len = htons(sizeof(struct bootp_pkt) - sizeof(struct iphdr));
85662306a36Sopenharmony_ci	/* UDP checksum not calculated -- explicitly allowed in BOOTP RFC */
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_ci	/* Construct DHCP/BOOTP header */
85962306a36Sopenharmony_ci	b->op = BOOTP_REQUEST;
86062306a36Sopenharmony_ci	if (dev->type < 256) /* check for false types */
86162306a36Sopenharmony_ci		b->htype = dev->type;
86262306a36Sopenharmony_ci	else if (dev->type == ARPHRD_FDDI)
86362306a36Sopenharmony_ci		b->htype = ARPHRD_ETHER;
86462306a36Sopenharmony_ci	else {
86562306a36Sopenharmony_ci		pr_warn("Unknown ARP type 0x%04x for device %s\n", dev->type,
86662306a36Sopenharmony_ci			dev->name);
86762306a36Sopenharmony_ci		b->htype = dev->type; /* can cause undefined behavior */
86862306a36Sopenharmony_ci	}
86962306a36Sopenharmony_ci
87062306a36Sopenharmony_ci	/* server_ip and your_ip address are both already zero per RFC2131 */
87162306a36Sopenharmony_ci	b->hlen = dev->addr_len;
87262306a36Sopenharmony_ci	memcpy(b->hw_addr, dev->dev_addr, dev->addr_len);
87362306a36Sopenharmony_ci	b->secs = htons(jiffies_diff / HZ);
87462306a36Sopenharmony_ci	b->xid = d->xid;
87562306a36Sopenharmony_ci
87662306a36Sopenharmony_ci	/* add DHCP options or BOOTP extensions */
87762306a36Sopenharmony_ci#ifdef IPCONFIG_DHCP
87862306a36Sopenharmony_ci	if (ic_proto_enabled & IC_USE_DHCP)
87962306a36Sopenharmony_ci		ic_dhcp_init_options(b->exten, d);
88062306a36Sopenharmony_ci	else
88162306a36Sopenharmony_ci#endif
88262306a36Sopenharmony_ci		ic_bootp_init_ext(b->exten);
88362306a36Sopenharmony_ci
88462306a36Sopenharmony_ci	/* Chain packet down the line... */
88562306a36Sopenharmony_ci	skb->dev = dev;
88662306a36Sopenharmony_ci	skb->protocol = htons(ETH_P_IP);
88762306a36Sopenharmony_ci	if (dev_hard_header(skb, dev, ntohs(skb->protocol),
88862306a36Sopenharmony_ci			    dev->broadcast, dev->dev_addr, skb->len) < 0) {
88962306a36Sopenharmony_ci		kfree_skb(skb);
89062306a36Sopenharmony_ci		printk("E");
89162306a36Sopenharmony_ci		return;
89262306a36Sopenharmony_ci	}
89362306a36Sopenharmony_ci
89462306a36Sopenharmony_ci	if (dev_queue_xmit(skb) < 0)
89562306a36Sopenharmony_ci		printk("E");
89662306a36Sopenharmony_ci}
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_ci
89962306a36Sopenharmony_ci/*
90062306a36Sopenharmony_ci *  Copy BOOTP-supplied string
90162306a36Sopenharmony_ci */
90262306a36Sopenharmony_cistatic int __init ic_bootp_string(char *dest, char *src, int len, int max)
90362306a36Sopenharmony_ci{
90462306a36Sopenharmony_ci	if (!len)
90562306a36Sopenharmony_ci		return 0;
90662306a36Sopenharmony_ci	if (len > max-1)
90762306a36Sopenharmony_ci		len = max-1;
90862306a36Sopenharmony_ci	memcpy(dest, src, len);
90962306a36Sopenharmony_ci	dest[len] = '\0';
91062306a36Sopenharmony_ci	return 1;
91162306a36Sopenharmony_ci}
91262306a36Sopenharmony_ci
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_ci/*
91562306a36Sopenharmony_ci *  Process BOOTP extensions.
91662306a36Sopenharmony_ci */
91762306a36Sopenharmony_cistatic void __init ic_do_bootp_ext(u8 *ext)
91862306a36Sopenharmony_ci{
91962306a36Sopenharmony_ci	u8 servers;
92062306a36Sopenharmony_ci	int i;
92162306a36Sopenharmony_ci	__be16 mtu;
92262306a36Sopenharmony_ci
92362306a36Sopenharmony_ci	u8 *c;
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_ci	pr_debug("DHCP/BOOTP: Got extension %d:", *ext);
92662306a36Sopenharmony_ci	for (c=ext+2; c<ext+2+ext[1]; c++)
92762306a36Sopenharmony_ci		pr_debug(" %02x", *c);
92862306a36Sopenharmony_ci	pr_debug("\n");
92962306a36Sopenharmony_ci
93062306a36Sopenharmony_ci	switch (*ext++) {
93162306a36Sopenharmony_ci	case 1:		/* Subnet mask */
93262306a36Sopenharmony_ci		if (ic_netmask == NONE)
93362306a36Sopenharmony_ci			memcpy(&ic_netmask, ext+1, 4);
93462306a36Sopenharmony_ci		break;
93562306a36Sopenharmony_ci	case 3:		/* Default gateway */
93662306a36Sopenharmony_ci		if (ic_gateway == NONE)
93762306a36Sopenharmony_ci			memcpy(&ic_gateway, ext+1, 4);
93862306a36Sopenharmony_ci		break;
93962306a36Sopenharmony_ci	case 6:		/* DNS server */
94062306a36Sopenharmony_ci		servers= *ext/4;
94162306a36Sopenharmony_ci		if (servers > CONF_NAMESERVERS_MAX)
94262306a36Sopenharmony_ci			servers = CONF_NAMESERVERS_MAX;
94362306a36Sopenharmony_ci		for (i = 0; i < servers; i++) {
94462306a36Sopenharmony_ci			if (ic_nameservers[i] == NONE ||
94562306a36Sopenharmony_ci			    ic_nameservers_fallback)
94662306a36Sopenharmony_ci				memcpy(&ic_nameservers[i], ext+1+4*i, 4);
94762306a36Sopenharmony_ci		}
94862306a36Sopenharmony_ci		break;
94962306a36Sopenharmony_ci	case 12:	/* Host name */
95062306a36Sopenharmony_ci		if (!ic_host_name_set) {
95162306a36Sopenharmony_ci			ic_bootp_string(utsname()->nodename, ext+1, *ext,
95262306a36Sopenharmony_ci					__NEW_UTS_LEN);
95362306a36Sopenharmony_ci			ic_host_name_set = 1;
95462306a36Sopenharmony_ci		}
95562306a36Sopenharmony_ci		break;
95662306a36Sopenharmony_ci	case 15:	/* Domain name (DNS) */
95762306a36Sopenharmony_ci		if (!ic_domain[0])
95862306a36Sopenharmony_ci			ic_bootp_string(ic_domain, ext+1, *ext, sizeof(ic_domain));
95962306a36Sopenharmony_ci		break;
96062306a36Sopenharmony_ci	case 17:	/* Root path */
96162306a36Sopenharmony_ci		if (!root_server_path[0])
96262306a36Sopenharmony_ci			ic_bootp_string(root_server_path, ext+1, *ext,
96362306a36Sopenharmony_ci					sizeof(root_server_path));
96462306a36Sopenharmony_ci		break;
96562306a36Sopenharmony_ci	case 26:	/* Interface MTU */
96662306a36Sopenharmony_ci		memcpy(&mtu, ext+1, sizeof(mtu));
96762306a36Sopenharmony_ci		ic_dev_mtu = ntohs(mtu);
96862306a36Sopenharmony_ci		break;
96962306a36Sopenharmony_ci	case 40:	/* NIS Domain name (_not_ DNS) */
97062306a36Sopenharmony_ci		ic_bootp_string(utsname()->domainname, ext+1, *ext,
97162306a36Sopenharmony_ci				__NEW_UTS_LEN);
97262306a36Sopenharmony_ci		break;
97362306a36Sopenharmony_ci	case 42:	/* NTP servers */
97462306a36Sopenharmony_ci		servers = *ext / 4;
97562306a36Sopenharmony_ci		if (servers > CONF_NTP_SERVERS_MAX)
97662306a36Sopenharmony_ci			servers = CONF_NTP_SERVERS_MAX;
97762306a36Sopenharmony_ci		for (i = 0; i < servers; i++) {
97862306a36Sopenharmony_ci			if (ic_ntp_servers[i] == NONE)
97962306a36Sopenharmony_ci				memcpy(&ic_ntp_servers[i], ext+1+4*i, 4);
98062306a36Sopenharmony_ci		}
98162306a36Sopenharmony_ci		break;
98262306a36Sopenharmony_ci	}
98362306a36Sopenharmony_ci}
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_ci
98662306a36Sopenharmony_ci/*
98762306a36Sopenharmony_ci *  Receive BOOTP reply.
98862306a36Sopenharmony_ci */
98962306a36Sopenharmony_cistatic int __init ic_bootp_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
99062306a36Sopenharmony_ci{
99162306a36Sopenharmony_ci	struct bootp_pkt *b;
99262306a36Sopenharmony_ci	struct iphdr *h;
99362306a36Sopenharmony_ci	struct ic_device *d;
99462306a36Sopenharmony_ci	int len, ext_len;
99562306a36Sopenharmony_ci
99662306a36Sopenharmony_ci	if (!net_eq(dev_net(dev), &init_net))
99762306a36Sopenharmony_ci		goto drop;
99862306a36Sopenharmony_ci
99962306a36Sopenharmony_ci	/* Perform verifications before taking the lock.  */
100062306a36Sopenharmony_ci	if (skb->pkt_type == PACKET_OTHERHOST)
100162306a36Sopenharmony_ci		goto drop;
100262306a36Sopenharmony_ci
100362306a36Sopenharmony_ci	skb = skb_share_check(skb, GFP_ATOMIC);
100462306a36Sopenharmony_ci	if (!skb)
100562306a36Sopenharmony_ci		return NET_RX_DROP;
100662306a36Sopenharmony_ci
100762306a36Sopenharmony_ci	if (!pskb_may_pull(skb,
100862306a36Sopenharmony_ci			   sizeof(struct iphdr) +
100962306a36Sopenharmony_ci			   sizeof(struct udphdr)))
101062306a36Sopenharmony_ci		goto drop;
101162306a36Sopenharmony_ci
101262306a36Sopenharmony_ci	b = (struct bootp_pkt *)skb_network_header(skb);
101362306a36Sopenharmony_ci	h = &b->iph;
101462306a36Sopenharmony_ci
101562306a36Sopenharmony_ci	if (h->ihl != 5 || h->version != 4 || h->protocol != IPPROTO_UDP)
101662306a36Sopenharmony_ci		goto drop;
101762306a36Sopenharmony_ci
101862306a36Sopenharmony_ci	/* Fragments are not supported */
101962306a36Sopenharmony_ci	if (ip_is_fragment(h)) {
102062306a36Sopenharmony_ci		net_err_ratelimited("DHCP/BOOTP: Ignoring fragmented reply\n");
102162306a36Sopenharmony_ci		goto drop;
102262306a36Sopenharmony_ci	}
102362306a36Sopenharmony_ci
102462306a36Sopenharmony_ci	if (skb->len < ntohs(h->tot_len))
102562306a36Sopenharmony_ci		goto drop;
102662306a36Sopenharmony_ci
102762306a36Sopenharmony_ci	if (ip_fast_csum((char *) h, h->ihl))
102862306a36Sopenharmony_ci		goto drop;
102962306a36Sopenharmony_ci
103062306a36Sopenharmony_ci	if (b->udph.source != htons(67) || b->udph.dest != htons(68))
103162306a36Sopenharmony_ci		goto drop;
103262306a36Sopenharmony_ci
103362306a36Sopenharmony_ci	if (ntohs(h->tot_len) < ntohs(b->udph.len) + sizeof(struct iphdr))
103462306a36Sopenharmony_ci		goto drop;
103562306a36Sopenharmony_ci
103662306a36Sopenharmony_ci	len = ntohs(b->udph.len) - sizeof(struct udphdr);
103762306a36Sopenharmony_ci	ext_len = len - (sizeof(*b) -
103862306a36Sopenharmony_ci			 sizeof(struct iphdr) -
103962306a36Sopenharmony_ci			 sizeof(struct udphdr) -
104062306a36Sopenharmony_ci			 sizeof(b->exten));
104162306a36Sopenharmony_ci	if (ext_len < 0)
104262306a36Sopenharmony_ci		goto drop;
104362306a36Sopenharmony_ci
104462306a36Sopenharmony_ci	/* Ok the front looks good, make sure we can get at the rest.  */
104562306a36Sopenharmony_ci	if (!pskb_may_pull(skb, skb->len))
104662306a36Sopenharmony_ci		goto drop;
104762306a36Sopenharmony_ci
104862306a36Sopenharmony_ci	b = (struct bootp_pkt *)skb_network_header(skb);
104962306a36Sopenharmony_ci	h = &b->iph;
105062306a36Sopenharmony_ci
105162306a36Sopenharmony_ci	/* One reply at a time, please. */
105262306a36Sopenharmony_ci	spin_lock(&ic_recv_lock);
105362306a36Sopenharmony_ci
105462306a36Sopenharmony_ci	/* If we already have a reply, just drop the packet */
105562306a36Sopenharmony_ci	if (ic_got_reply)
105662306a36Sopenharmony_ci		goto drop_unlock;
105762306a36Sopenharmony_ci
105862306a36Sopenharmony_ci	/* Find the ic_device that the packet arrived on */
105962306a36Sopenharmony_ci	d = ic_first_dev;
106062306a36Sopenharmony_ci	while (d && d->dev != dev)
106162306a36Sopenharmony_ci		d = d->next;
106262306a36Sopenharmony_ci	if (!d)
106362306a36Sopenharmony_ci		goto drop_unlock;  /* should never happen */
106462306a36Sopenharmony_ci
106562306a36Sopenharmony_ci	/* Is it a reply to our BOOTP request? */
106662306a36Sopenharmony_ci	if (b->op != BOOTP_REPLY ||
106762306a36Sopenharmony_ci	    b->xid != d->xid) {
106862306a36Sopenharmony_ci		net_err_ratelimited("DHCP/BOOTP: Reply not for us on %s, op[%x] xid[%x]\n",
106962306a36Sopenharmony_ci				    d->dev->name, b->op, b->xid);
107062306a36Sopenharmony_ci		goto drop_unlock;
107162306a36Sopenharmony_ci	}
107262306a36Sopenharmony_ci
107362306a36Sopenharmony_ci	/* Parse extensions */
107462306a36Sopenharmony_ci	if (ext_len >= 4 &&
107562306a36Sopenharmony_ci	    !memcmp(b->exten, ic_bootp_cookie, 4)) { /* Check magic cookie */
107662306a36Sopenharmony_ci		u8 *end = (u8 *) b + ntohs(b->iph.tot_len);
107762306a36Sopenharmony_ci		u8 *ext;
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_ci#ifdef IPCONFIG_DHCP
108062306a36Sopenharmony_ci		if (ic_proto_enabled & IC_USE_DHCP) {
108162306a36Sopenharmony_ci			__be32 server_id = NONE;
108262306a36Sopenharmony_ci			int mt = 0;
108362306a36Sopenharmony_ci
108462306a36Sopenharmony_ci			ext = &b->exten[4];
108562306a36Sopenharmony_ci			while (ext < end && *ext != 0xff) {
108662306a36Sopenharmony_ci				u8 *opt = ext++;
108762306a36Sopenharmony_ci				if (*opt == 0)	/* Padding */
108862306a36Sopenharmony_ci					continue;
108962306a36Sopenharmony_ci				ext += *ext + 1;
109062306a36Sopenharmony_ci				if (ext >= end)
109162306a36Sopenharmony_ci					break;
109262306a36Sopenharmony_ci				switch (*opt) {
109362306a36Sopenharmony_ci				case 53:	/* Message type */
109462306a36Sopenharmony_ci					if (opt[1])
109562306a36Sopenharmony_ci						mt = opt[2];
109662306a36Sopenharmony_ci					break;
109762306a36Sopenharmony_ci				case 54:	/* Server ID (IP address) */
109862306a36Sopenharmony_ci					if (opt[1] >= 4)
109962306a36Sopenharmony_ci						memcpy(&server_id, opt + 2, 4);
110062306a36Sopenharmony_ci					break;
110162306a36Sopenharmony_ci				}
110262306a36Sopenharmony_ci			}
110362306a36Sopenharmony_ci
110462306a36Sopenharmony_ci			pr_debug("DHCP: Got message type %d (%s)\n", mt, d->dev->name);
110562306a36Sopenharmony_ci
110662306a36Sopenharmony_ci			switch (mt) {
110762306a36Sopenharmony_ci			case DHCPOFFER:
110862306a36Sopenharmony_ci				/* While in the process of accepting one offer,
110962306a36Sopenharmony_ci				 * ignore all others.
111062306a36Sopenharmony_ci				 */
111162306a36Sopenharmony_ci				if (ic_myaddr != NONE)
111262306a36Sopenharmony_ci					goto drop_unlock;
111362306a36Sopenharmony_ci
111462306a36Sopenharmony_ci				/* Let's accept that offer. */
111562306a36Sopenharmony_ci				ic_myaddr = b->your_ip;
111662306a36Sopenharmony_ci				ic_servaddr = server_id;
111762306a36Sopenharmony_ci				pr_debug("DHCP: Offered address %pI4 by server %pI4\n",
111862306a36Sopenharmony_ci					 &ic_myaddr, &b->iph.saddr);
111962306a36Sopenharmony_ci				/* The DHCP indicated server address takes
112062306a36Sopenharmony_ci				 * precedence over the bootp header one if
112162306a36Sopenharmony_ci				 * they are different.
112262306a36Sopenharmony_ci				 */
112362306a36Sopenharmony_ci				if ((server_id != NONE) &&
112462306a36Sopenharmony_ci				    (b->server_ip != server_id))
112562306a36Sopenharmony_ci					b->server_ip = ic_servaddr;
112662306a36Sopenharmony_ci				break;
112762306a36Sopenharmony_ci
112862306a36Sopenharmony_ci			case DHCPACK:
112962306a36Sopenharmony_ci				if (memcmp(dev->dev_addr, b->hw_addr, dev->addr_len) != 0)
113062306a36Sopenharmony_ci					goto drop_unlock;
113162306a36Sopenharmony_ci
113262306a36Sopenharmony_ci				/* Yeah! */
113362306a36Sopenharmony_ci				break;
113462306a36Sopenharmony_ci
113562306a36Sopenharmony_ci			default:
113662306a36Sopenharmony_ci				/* Urque.  Forget it*/
113762306a36Sopenharmony_ci				ic_myaddr = NONE;
113862306a36Sopenharmony_ci				ic_servaddr = NONE;
113962306a36Sopenharmony_ci				goto drop_unlock;
114062306a36Sopenharmony_ci			}
114162306a36Sopenharmony_ci
114262306a36Sopenharmony_ci			ic_dhcp_msgtype = mt;
114362306a36Sopenharmony_ci
114462306a36Sopenharmony_ci		}
114562306a36Sopenharmony_ci#endif /* IPCONFIG_DHCP */
114662306a36Sopenharmony_ci
114762306a36Sopenharmony_ci		ext = &b->exten[4];
114862306a36Sopenharmony_ci		while (ext < end && *ext != 0xff) {
114962306a36Sopenharmony_ci			u8 *opt = ext++;
115062306a36Sopenharmony_ci			if (*opt == 0)	/* Padding */
115162306a36Sopenharmony_ci				continue;
115262306a36Sopenharmony_ci			ext += *ext + 1;
115362306a36Sopenharmony_ci			if (ext < end)
115462306a36Sopenharmony_ci				ic_do_bootp_ext(opt);
115562306a36Sopenharmony_ci		}
115662306a36Sopenharmony_ci	}
115762306a36Sopenharmony_ci
115862306a36Sopenharmony_ci	/* We have a winner! */
115962306a36Sopenharmony_ci	ic_dev = d;
116062306a36Sopenharmony_ci	ic_myaddr = b->your_ip;
116162306a36Sopenharmony_ci	ic_servaddr = b->server_ip;
116262306a36Sopenharmony_ci	ic_addrservaddr = b->iph.saddr;
116362306a36Sopenharmony_ci	if (ic_gateway == NONE && b->relay_ip)
116462306a36Sopenharmony_ci		ic_gateway = b->relay_ip;
116562306a36Sopenharmony_ci	if (ic_nameservers[0] == NONE) {
116662306a36Sopenharmony_ci		ic_nameservers[0] = ic_servaddr;
116762306a36Sopenharmony_ci		ic_nameservers_fallback = 1;
116862306a36Sopenharmony_ci	}
116962306a36Sopenharmony_ci	ic_got_reply = IC_BOOTP;
117062306a36Sopenharmony_ci
117162306a36Sopenharmony_cidrop_unlock:
117262306a36Sopenharmony_ci	/* Show's over.  Nothing to see here.  */
117362306a36Sopenharmony_ci	spin_unlock(&ic_recv_lock);
117462306a36Sopenharmony_ci
117562306a36Sopenharmony_cidrop:
117662306a36Sopenharmony_ci	/* Throw the packet out. */
117762306a36Sopenharmony_ci	kfree_skb(skb);
117862306a36Sopenharmony_ci
117962306a36Sopenharmony_ci	return 0;
118062306a36Sopenharmony_ci}
118162306a36Sopenharmony_ci
118262306a36Sopenharmony_ci
118362306a36Sopenharmony_ci#endif
118462306a36Sopenharmony_ci
118562306a36Sopenharmony_ci
118662306a36Sopenharmony_ci/*
118762306a36Sopenharmony_ci *	Dynamic IP configuration -- DHCP, BOOTP, RARP.
118862306a36Sopenharmony_ci */
118962306a36Sopenharmony_ci
119062306a36Sopenharmony_ci#ifdef IPCONFIG_DYNAMIC
119162306a36Sopenharmony_ci
119262306a36Sopenharmony_cistatic int __init ic_dynamic(void)
119362306a36Sopenharmony_ci{
119462306a36Sopenharmony_ci	int retries;
119562306a36Sopenharmony_ci	struct ic_device *d;
119662306a36Sopenharmony_ci	unsigned long start_jiffies, timeout, jiff;
119762306a36Sopenharmony_ci	int do_bootp = ic_proto_have_if & IC_BOOTP;
119862306a36Sopenharmony_ci	int do_rarp = ic_proto_have_if & IC_RARP;
119962306a36Sopenharmony_ci
120062306a36Sopenharmony_ci	/*
120162306a36Sopenharmony_ci	 * If none of DHCP/BOOTP/RARP was selected, return with an error.
120262306a36Sopenharmony_ci	 * This routine gets only called when some pieces of information
120362306a36Sopenharmony_ci	 * are missing, and without DHCP/BOOTP/RARP we are unable to get it.
120462306a36Sopenharmony_ci	 */
120562306a36Sopenharmony_ci	if (!ic_proto_enabled) {
120662306a36Sopenharmony_ci		pr_err("IP-Config: Incomplete network configuration information\n");
120762306a36Sopenharmony_ci		return -1;
120862306a36Sopenharmony_ci	}
120962306a36Sopenharmony_ci
121062306a36Sopenharmony_ci#ifdef IPCONFIG_BOOTP
121162306a36Sopenharmony_ci	if ((ic_proto_enabled ^ ic_proto_have_if) & IC_BOOTP)
121262306a36Sopenharmony_ci		pr_err("DHCP/BOOTP: No suitable device found\n");
121362306a36Sopenharmony_ci#endif
121462306a36Sopenharmony_ci#ifdef IPCONFIG_RARP
121562306a36Sopenharmony_ci	if ((ic_proto_enabled ^ ic_proto_have_if) & IC_RARP)
121662306a36Sopenharmony_ci		pr_err("RARP: No suitable device found\n");
121762306a36Sopenharmony_ci#endif
121862306a36Sopenharmony_ci
121962306a36Sopenharmony_ci	if (!ic_proto_have_if)
122062306a36Sopenharmony_ci		/* Error message already printed */
122162306a36Sopenharmony_ci		return -1;
122262306a36Sopenharmony_ci
122362306a36Sopenharmony_ci	/*
122462306a36Sopenharmony_ci	 * Setup protocols
122562306a36Sopenharmony_ci	 */
122662306a36Sopenharmony_ci#ifdef IPCONFIG_BOOTP
122762306a36Sopenharmony_ci	if (do_bootp)
122862306a36Sopenharmony_ci		ic_bootp_init();
122962306a36Sopenharmony_ci#endif
123062306a36Sopenharmony_ci#ifdef IPCONFIG_RARP
123162306a36Sopenharmony_ci	if (do_rarp)
123262306a36Sopenharmony_ci		ic_rarp_init();
123362306a36Sopenharmony_ci#endif
123462306a36Sopenharmony_ci
123562306a36Sopenharmony_ci	/*
123662306a36Sopenharmony_ci	 * Send requests and wait, until we get an answer. This loop
123762306a36Sopenharmony_ci	 * seems to be a terrible waste of CPU time, but actually there is
123862306a36Sopenharmony_ci	 * only one process running at all, so we don't need to use any
123962306a36Sopenharmony_ci	 * scheduler functions.
124062306a36Sopenharmony_ci	 * [Actually we could now, but the nothing else running note still
124162306a36Sopenharmony_ci	 *  applies.. - AC]
124262306a36Sopenharmony_ci	 */
124362306a36Sopenharmony_ci	pr_notice("Sending %s%s%s requests .",
124462306a36Sopenharmony_ci		  do_bootp
124562306a36Sopenharmony_ci		  ? ((ic_proto_enabled & IC_USE_DHCP) ? "DHCP" : "BOOTP") : "",
124662306a36Sopenharmony_ci		  (do_bootp && do_rarp) ? " and " : "",
124762306a36Sopenharmony_ci		  do_rarp ? "RARP" : "");
124862306a36Sopenharmony_ci
124962306a36Sopenharmony_ci	start_jiffies = jiffies;
125062306a36Sopenharmony_ci	d = ic_first_dev;
125162306a36Sopenharmony_ci	retries = CONF_SEND_RETRIES;
125262306a36Sopenharmony_ci	get_random_bytes(&timeout, sizeof(timeout));
125362306a36Sopenharmony_ci	timeout = CONF_BASE_TIMEOUT + (timeout % (unsigned int) CONF_TIMEOUT_RANDOM);
125462306a36Sopenharmony_ci	for (;;) {
125562306a36Sopenharmony_ci#ifdef IPCONFIG_BOOTP
125662306a36Sopenharmony_ci		if (do_bootp && (d->able & IC_BOOTP))
125762306a36Sopenharmony_ci			ic_bootp_send_if(d, jiffies - start_jiffies);
125862306a36Sopenharmony_ci#endif
125962306a36Sopenharmony_ci#ifdef IPCONFIG_RARP
126062306a36Sopenharmony_ci		if (do_rarp && (d->able & IC_RARP))
126162306a36Sopenharmony_ci			ic_rarp_send_if(d);
126262306a36Sopenharmony_ci#endif
126362306a36Sopenharmony_ci
126462306a36Sopenharmony_ci		if (!d->next) {
126562306a36Sopenharmony_ci			jiff = jiffies + timeout;
126662306a36Sopenharmony_ci			while (time_before(jiffies, jiff) && !ic_got_reply)
126762306a36Sopenharmony_ci				schedule_timeout_uninterruptible(1);
126862306a36Sopenharmony_ci		}
126962306a36Sopenharmony_ci#ifdef IPCONFIG_DHCP
127062306a36Sopenharmony_ci		/* DHCP isn't done until we get a DHCPACK. */
127162306a36Sopenharmony_ci		if ((ic_got_reply & IC_BOOTP) &&
127262306a36Sopenharmony_ci		    (ic_proto_enabled & IC_USE_DHCP) &&
127362306a36Sopenharmony_ci		    ic_dhcp_msgtype != DHCPACK) {
127462306a36Sopenharmony_ci			ic_got_reply = 0;
127562306a36Sopenharmony_ci			/* continue on device that got the reply */
127662306a36Sopenharmony_ci			d = ic_dev;
127762306a36Sopenharmony_ci			pr_cont(",");
127862306a36Sopenharmony_ci			continue;
127962306a36Sopenharmony_ci		}
128062306a36Sopenharmony_ci#endif /* IPCONFIG_DHCP */
128162306a36Sopenharmony_ci
128262306a36Sopenharmony_ci		if (ic_got_reply) {
128362306a36Sopenharmony_ci			pr_cont(" OK\n");
128462306a36Sopenharmony_ci			break;
128562306a36Sopenharmony_ci		}
128662306a36Sopenharmony_ci
128762306a36Sopenharmony_ci		if ((d = d->next))
128862306a36Sopenharmony_ci			continue;
128962306a36Sopenharmony_ci
129062306a36Sopenharmony_ci		if (! --retries) {
129162306a36Sopenharmony_ci			pr_cont(" timed out!\n");
129262306a36Sopenharmony_ci			break;
129362306a36Sopenharmony_ci		}
129462306a36Sopenharmony_ci
129562306a36Sopenharmony_ci		d = ic_first_dev;
129662306a36Sopenharmony_ci
129762306a36Sopenharmony_ci		timeout = timeout CONF_TIMEOUT_MULT;
129862306a36Sopenharmony_ci		if (timeout > CONF_TIMEOUT_MAX)
129962306a36Sopenharmony_ci			timeout = CONF_TIMEOUT_MAX;
130062306a36Sopenharmony_ci
130162306a36Sopenharmony_ci		pr_cont(".");
130262306a36Sopenharmony_ci	}
130362306a36Sopenharmony_ci
130462306a36Sopenharmony_ci#ifdef IPCONFIG_BOOTP
130562306a36Sopenharmony_ci	if (do_bootp)
130662306a36Sopenharmony_ci		ic_bootp_cleanup();
130762306a36Sopenharmony_ci#endif
130862306a36Sopenharmony_ci#ifdef IPCONFIG_RARP
130962306a36Sopenharmony_ci	if (do_rarp)
131062306a36Sopenharmony_ci		ic_rarp_cleanup();
131162306a36Sopenharmony_ci#endif
131262306a36Sopenharmony_ci
131362306a36Sopenharmony_ci	if (!ic_got_reply) {
131462306a36Sopenharmony_ci		ic_myaddr = NONE;
131562306a36Sopenharmony_ci		return -1;
131662306a36Sopenharmony_ci	}
131762306a36Sopenharmony_ci
131862306a36Sopenharmony_ci	pr_info("IP-Config: Got %s answer from %pI4, my address is %pI4\n",
131962306a36Sopenharmony_ci		((ic_got_reply & IC_RARP) ? "RARP"
132062306a36Sopenharmony_ci		: (ic_proto_enabled & IC_USE_DHCP) ? "DHCP" : "BOOTP"),
132162306a36Sopenharmony_ci		&ic_addrservaddr, &ic_myaddr);
132262306a36Sopenharmony_ci
132362306a36Sopenharmony_ci	return 0;
132462306a36Sopenharmony_ci}
132562306a36Sopenharmony_ci
132662306a36Sopenharmony_ci#endif /* IPCONFIG_DYNAMIC */
132762306a36Sopenharmony_ci
132862306a36Sopenharmony_ci#ifdef CONFIG_PROC_FS
132962306a36Sopenharmony_ci/* proc_dir_entry for /proc/net/ipconfig */
133062306a36Sopenharmony_cistatic struct proc_dir_entry *ipconfig_dir;
133162306a36Sopenharmony_ci
133262306a36Sopenharmony_ci/* Name servers: */
133362306a36Sopenharmony_cistatic int pnp_seq_show(struct seq_file *seq, void *v)
133462306a36Sopenharmony_ci{
133562306a36Sopenharmony_ci	int i;
133662306a36Sopenharmony_ci
133762306a36Sopenharmony_ci	if (ic_proto_used & IC_PROTO)
133862306a36Sopenharmony_ci		seq_printf(seq, "#PROTO: %s\n",
133962306a36Sopenharmony_ci			   (ic_proto_used & IC_RARP) ? "RARP"
134062306a36Sopenharmony_ci			   : (ic_proto_used & IC_USE_DHCP) ? "DHCP" : "BOOTP");
134162306a36Sopenharmony_ci	else
134262306a36Sopenharmony_ci		seq_puts(seq, "#MANUAL\n");
134362306a36Sopenharmony_ci
134462306a36Sopenharmony_ci	if (ic_domain[0])
134562306a36Sopenharmony_ci		seq_printf(seq,
134662306a36Sopenharmony_ci			   "domain %s\n", ic_domain);
134762306a36Sopenharmony_ci	for (i = 0; i < CONF_NAMESERVERS_MAX; i++) {
134862306a36Sopenharmony_ci		if (ic_nameservers[i] != NONE)
134962306a36Sopenharmony_ci			seq_printf(seq, "nameserver %pI4\n",
135062306a36Sopenharmony_ci				   &ic_nameservers[i]);
135162306a36Sopenharmony_ci	}
135262306a36Sopenharmony_ci	if (ic_servaddr != NONE)
135362306a36Sopenharmony_ci		seq_printf(seq, "bootserver %pI4\n",
135462306a36Sopenharmony_ci			   &ic_servaddr);
135562306a36Sopenharmony_ci	return 0;
135662306a36Sopenharmony_ci}
135762306a36Sopenharmony_ci
135862306a36Sopenharmony_ci/* Create the /proc/net/ipconfig directory */
135962306a36Sopenharmony_cistatic int __init ipconfig_proc_net_init(void)
136062306a36Sopenharmony_ci{
136162306a36Sopenharmony_ci	ipconfig_dir = proc_net_mkdir(&init_net, "ipconfig", init_net.proc_net);
136262306a36Sopenharmony_ci	if (!ipconfig_dir)
136362306a36Sopenharmony_ci		return -ENOMEM;
136462306a36Sopenharmony_ci
136562306a36Sopenharmony_ci	return 0;
136662306a36Sopenharmony_ci}
136762306a36Sopenharmony_ci
136862306a36Sopenharmony_ci/* Create a new file under /proc/net/ipconfig */
136962306a36Sopenharmony_cistatic int ipconfig_proc_net_create(const char *name,
137062306a36Sopenharmony_ci				    const struct proc_ops *proc_ops)
137162306a36Sopenharmony_ci{
137262306a36Sopenharmony_ci	char *pname;
137362306a36Sopenharmony_ci	struct proc_dir_entry *p;
137462306a36Sopenharmony_ci
137562306a36Sopenharmony_ci	if (!ipconfig_dir)
137662306a36Sopenharmony_ci		return -ENOMEM;
137762306a36Sopenharmony_ci
137862306a36Sopenharmony_ci	pname = kasprintf(GFP_KERNEL, "%s%s", "ipconfig/", name);
137962306a36Sopenharmony_ci	if (!pname)
138062306a36Sopenharmony_ci		return -ENOMEM;
138162306a36Sopenharmony_ci
138262306a36Sopenharmony_ci	p = proc_create(pname, 0444, init_net.proc_net, proc_ops);
138362306a36Sopenharmony_ci	kfree(pname);
138462306a36Sopenharmony_ci	if (!p)
138562306a36Sopenharmony_ci		return -ENOMEM;
138662306a36Sopenharmony_ci
138762306a36Sopenharmony_ci	return 0;
138862306a36Sopenharmony_ci}
138962306a36Sopenharmony_ci
139062306a36Sopenharmony_ci/* Write NTP server IP addresses to /proc/net/ipconfig/ntp_servers */
139162306a36Sopenharmony_cistatic int ntp_servers_show(struct seq_file *seq, void *v)
139262306a36Sopenharmony_ci{
139362306a36Sopenharmony_ci	int i;
139462306a36Sopenharmony_ci
139562306a36Sopenharmony_ci	for (i = 0; i < CONF_NTP_SERVERS_MAX; i++) {
139662306a36Sopenharmony_ci		if (ic_ntp_servers[i] != NONE)
139762306a36Sopenharmony_ci			seq_printf(seq, "%pI4\n", &ic_ntp_servers[i]);
139862306a36Sopenharmony_ci	}
139962306a36Sopenharmony_ci	return 0;
140062306a36Sopenharmony_ci}
140162306a36Sopenharmony_ciDEFINE_PROC_SHOW_ATTRIBUTE(ntp_servers);
140262306a36Sopenharmony_ci#endif /* CONFIG_PROC_FS */
140362306a36Sopenharmony_ci
140462306a36Sopenharmony_ci/*
140562306a36Sopenharmony_ci *  Extract IP address from the parameter string if needed. Note that we
140662306a36Sopenharmony_ci *  need to have root_server_addr set _before_ IPConfig gets called as it
140762306a36Sopenharmony_ci *  can override it.
140862306a36Sopenharmony_ci */
140962306a36Sopenharmony_ci__be32 __init root_nfs_parse_addr(char *name)
141062306a36Sopenharmony_ci{
141162306a36Sopenharmony_ci	__be32 addr;
141262306a36Sopenharmony_ci	int octets = 0;
141362306a36Sopenharmony_ci	char *cp, *cq;
141462306a36Sopenharmony_ci
141562306a36Sopenharmony_ci	cp = cq = name;
141662306a36Sopenharmony_ci	while (octets < 4) {
141762306a36Sopenharmony_ci		while (*cp >= '0' && *cp <= '9')
141862306a36Sopenharmony_ci			cp++;
141962306a36Sopenharmony_ci		if (cp == cq || cp - cq > 3)
142062306a36Sopenharmony_ci			break;
142162306a36Sopenharmony_ci		if (*cp == '.' || octets == 3)
142262306a36Sopenharmony_ci			octets++;
142362306a36Sopenharmony_ci		if (octets < 4)
142462306a36Sopenharmony_ci			cp++;
142562306a36Sopenharmony_ci		cq = cp;
142662306a36Sopenharmony_ci	}
142762306a36Sopenharmony_ci	if (octets == 4 && (*cp == ':' || *cp == '\0')) {
142862306a36Sopenharmony_ci		if (*cp == ':')
142962306a36Sopenharmony_ci			*cp++ = '\0';
143062306a36Sopenharmony_ci		addr = in_aton(name);
143162306a36Sopenharmony_ci		memmove(name, cp, strlen(cp) + 1);
143262306a36Sopenharmony_ci	} else
143362306a36Sopenharmony_ci		addr = NONE;
143462306a36Sopenharmony_ci
143562306a36Sopenharmony_ci	return addr;
143662306a36Sopenharmony_ci}
143762306a36Sopenharmony_ci
143862306a36Sopenharmony_ci#define DEVICE_WAIT_MAX		12 /* 12 seconds */
143962306a36Sopenharmony_ci
144062306a36Sopenharmony_cistatic int __init wait_for_devices(void)
144162306a36Sopenharmony_ci{
144262306a36Sopenharmony_ci	int i;
144362306a36Sopenharmony_ci	bool try_init_devs = true;
144462306a36Sopenharmony_ci
144562306a36Sopenharmony_ci	for (i = 0; i < DEVICE_WAIT_MAX; i++) {
144662306a36Sopenharmony_ci		struct net_device *dev;
144762306a36Sopenharmony_ci		int found = 0;
144862306a36Sopenharmony_ci
144962306a36Sopenharmony_ci		/* make sure deferred device probes are finished */
145062306a36Sopenharmony_ci		wait_for_device_probe();
145162306a36Sopenharmony_ci
145262306a36Sopenharmony_ci		rtnl_lock();
145362306a36Sopenharmony_ci		for_each_netdev(&init_net, dev) {
145462306a36Sopenharmony_ci			if (ic_is_init_dev(dev)) {
145562306a36Sopenharmony_ci				found = 1;
145662306a36Sopenharmony_ci				break;
145762306a36Sopenharmony_ci			}
145862306a36Sopenharmony_ci		}
145962306a36Sopenharmony_ci		rtnl_unlock();
146062306a36Sopenharmony_ci		if (found)
146162306a36Sopenharmony_ci			return 0;
146262306a36Sopenharmony_ci		if (try_init_devs &&
146362306a36Sopenharmony_ci		    (ROOT_DEV == Root_NFS || ROOT_DEV == Root_CIFS)) {
146462306a36Sopenharmony_ci			try_init_devs = false;
146562306a36Sopenharmony_ci			wait_for_init_devices_probe();
146662306a36Sopenharmony_ci		}
146762306a36Sopenharmony_ci		ssleep(1);
146862306a36Sopenharmony_ci	}
146962306a36Sopenharmony_ci	return -ENODEV;
147062306a36Sopenharmony_ci}
147162306a36Sopenharmony_ci
147262306a36Sopenharmony_ci/*
147362306a36Sopenharmony_ci *	IP Autoconfig dispatcher.
147462306a36Sopenharmony_ci */
147562306a36Sopenharmony_ci
147662306a36Sopenharmony_cistatic int __init ip_auto_config(void)
147762306a36Sopenharmony_ci{
147862306a36Sopenharmony_ci	__be32 addr;
147962306a36Sopenharmony_ci#ifdef IPCONFIG_DYNAMIC
148062306a36Sopenharmony_ci	int retries = CONF_OPEN_RETRIES;
148162306a36Sopenharmony_ci#endif
148262306a36Sopenharmony_ci	int err;
148362306a36Sopenharmony_ci	unsigned int i, count;
148462306a36Sopenharmony_ci
148562306a36Sopenharmony_ci	/* Initialise all name servers and NTP servers to NONE (but only if the
148662306a36Sopenharmony_ci	 * "ip=" or "nfsaddrs=" kernel command line parameters weren't decoded,
148762306a36Sopenharmony_ci	 * otherwise we'll overwrite the IP addresses specified there)
148862306a36Sopenharmony_ci	 */
148962306a36Sopenharmony_ci	if (ic_set_manually == 0) {
149062306a36Sopenharmony_ci		ic_nameservers_predef();
149162306a36Sopenharmony_ci		ic_ntp_servers_predef();
149262306a36Sopenharmony_ci	}
149362306a36Sopenharmony_ci
149462306a36Sopenharmony_ci#ifdef CONFIG_PROC_FS
149562306a36Sopenharmony_ci	proc_create_single("pnp", 0444, init_net.proc_net, pnp_seq_show);
149662306a36Sopenharmony_ci
149762306a36Sopenharmony_ci	if (ipconfig_proc_net_init() == 0)
149862306a36Sopenharmony_ci		ipconfig_proc_net_create("ntp_servers", &ntp_servers_proc_ops);
149962306a36Sopenharmony_ci#endif /* CONFIG_PROC_FS */
150062306a36Sopenharmony_ci
150162306a36Sopenharmony_ci	if (!ic_enable)
150262306a36Sopenharmony_ci		return 0;
150362306a36Sopenharmony_ci
150462306a36Sopenharmony_ci	pr_debug("IP-Config: Entered.\n");
150562306a36Sopenharmony_ci#ifdef IPCONFIG_DYNAMIC
150662306a36Sopenharmony_ci try_try_again:
150762306a36Sopenharmony_ci#endif
150862306a36Sopenharmony_ci	/* Wait for devices to appear */
150962306a36Sopenharmony_ci	err = wait_for_devices();
151062306a36Sopenharmony_ci	if (err)
151162306a36Sopenharmony_ci		return err;
151262306a36Sopenharmony_ci
151362306a36Sopenharmony_ci	/* Setup all network devices */
151462306a36Sopenharmony_ci	err = ic_open_devs();
151562306a36Sopenharmony_ci	if (err)
151662306a36Sopenharmony_ci		return err;
151762306a36Sopenharmony_ci
151862306a36Sopenharmony_ci	/* Give drivers a chance to settle */
151962306a36Sopenharmony_ci	msleep(CONF_POST_OPEN);
152062306a36Sopenharmony_ci
152162306a36Sopenharmony_ci	/*
152262306a36Sopenharmony_ci	 * If the config information is insufficient (e.g., our IP address or
152362306a36Sopenharmony_ci	 * IP address of the boot server is missing or we have multiple network
152462306a36Sopenharmony_ci	 * interfaces and no default was set), use BOOTP or RARP to get the
152562306a36Sopenharmony_ci	 * missing values.
152662306a36Sopenharmony_ci	 */
152762306a36Sopenharmony_ci	if (ic_myaddr == NONE ||
152862306a36Sopenharmony_ci#if defined(CONFIG_ROOT_NFS) || defined(CONFIG_CIFS_ROOT)
152962306a36Sopenharmony_ci	    (root_server_addr == NONE &&
153062306a36Sopenharmony_ci	     ic_servaddr == NONE &&
153162306a36Sopenharmony_ci	     (ROOT_DEV == Root_NFS || ROOT_DEV == Root_CIFS)) ||
153262306a36Sopenharmony_ci#endif
153362306a36Sopenharmony_ci	    ic_first_dev->next) {
153462306a36Sopenharmony_ci#ifdef IPCONFIG_DYNAMIC
153562306a36Sopenharmony_ci		if (ic_dynamic() < 0) {
153662306a36Sopenharmony_ci			ic_close_devs();
153762306a36Sopenharmony_ci
153862306a36Sopenharmony_ci			/*
153962306a36Sopenharmony_ci			 * I don't know why, but sometimes the
154062306a36Sopenharmony_ci			 * eepro100 driver (at least) gets upset and
154162306a36Sopenharmony_ci			 * doesn't work the first time it's opened.
154262306a36Sopenharmony_ci			 * But then if you close it and reopen it, it
154362306a36Sopenharmony_ci			 * works just fine.  So we need to try that at
154462306a36Sopenharmony_ci			 * least once before giving up.
154562306a36Sopenharmony_ci			 *
154662306a36Sopenharmony_ci			 * Also, if the root will be NFS-mounted, we
154762306a36Sopenharmony_ci			 * have nowhere to go if DHCP fails.  So we
154862306a36Sopenharmony_ci			 * just have to keep trying forever.
154962306a36Sopenharmony_ci			 *
155062306a36Sopenharmony_ci			 * 				-- Chip
155162306a36Sopenharmony_ci			 */
155262306a36Sopenharmony_ci#ifdef CONFIG_ROOT_NFS
155362306a36Sopenharmony_ci			if (ROOT_DEV ==  Root_NFS) {
155462306a36Sopenharmony_ci				pr_err("IP-Config: Retrying forever (NFS root)...\n");
155562306a36Sopenharmony_ci				goto try_try_again;
155662306a36Sopenharmony_ci			}
155762306a36Sopenharmony_ci#endif
155862306a36Sopenharmony_ci#ifdef CONFIG_CIFS_ROOT
155962306a36Sopenharmony_ci			if (ROOT_DEV == Root_CIFS) {
156062306a36Sopenharmony_ci				pr_err("IP-Config: Retrying forever (CIFS root)...\n");
156162306a36Sopenharmony_ci				goto try_try_again;
156262306a36Sopenharmony_ci			}
156362306a36Sopenharmony_ci#endif
156462306a36Sopenharmony_ci
156562306a36Sopenharmony_ci			if (--retries) {
156662306a36Sopenharmony_ci				pr_err("IP-Config: Reopening network devices...\n");
156762306a36Sopenharmony_ci				goto try_try_again;
156862306a36Sopenharmony_ci			}
156962306a36Sopenharmony_ci
157062306a36Sopenharmony_ci			/* Oh, well.  At least we tried. */
157162306a36Sopenharmony_ci			pr_err("IP-Config: Auto-configuration of network failed\n");
157262306a36Sopenharmony_ci			return -1;
157362306a36Sopenharmony_ci		}
157462306a36Sopenharmony_ci#else /* !DYNAMIC */
157562306a36Sopenharmony_ci		pr_err("IP-Config: Incomplete network configuration information\n");
157662306a36Sopenharmony_ci		ic_close_devs();
157762306a36Sopenharmony_ci		return -1;
157862306a36Sopenharmony_ci#endif /* IPCONFIG_DYNAMIC */
157962306a36Sopenharmony_ci	} else {
158062306a36Sopenharmony_ci		/* Device selected manually or only one device -> use it */
158162306a36Sopenharmony_ci		ic_dev = ic_first_dev;
158262306a36Sopenharmony_ci	}
158362306a36Sopenharmony_ci
158462306a36Sopenharmony_ci	addr = root_nfs_parse_addr(root_server_path);
158562306a36Sopenharmony_ci	if (root_server_addr == NONE)
158662306a36Sopenharmony_ci		root_server_addr = addr;
158762306a36Sopenharmony_ci
158862306a36Sopenharmony_ci	/*
158962306a36Sopenharmony_ci	 * Use defaults wherever applicable.
159062306a36Sopenharmony_ci	 */
159162306a36Sopenharmony_ci	if (ic_defaults() < 0)
159262306a36Sopenharmony_ci		return -1;
159362306a36Sopenharmony_ci
159462306a36Sopenharmony_ci	/*
159562306a36Sopenharmony_ci	 * Record which protocol was actually used.
159662306a36Sopenharmony_ci	 */
159762306a36Sopenharmony_ci#ifdef IPCONFIG_DYNAMIC
159862306a36Sopenharmony_ci	ic_proto_used = ic_got_reply | (ic_proto_enabled & IC_USE_DHCP);
159962306a36Sopenharmony_ci#endif
160062306a36Sopenharmony_ci
160162306a36Sopenharmony_ci#ifndef IPCONFIG_SILENT
160262306a36Sopenharmony_ci	/*
160362306a36Sopenharmony_ci	 * Clue in the operator.
160462306a36Sopenharmony_ci	 */
160562306a36Sopenharmony_ci	pr_info("IP-Config: Complete:\n");
160662306a36Sopenharmony_ci
160762306a36Sopenharmony_ci	pr_info("     device=%s, hwaddr=%*phC, ipaddr=%pI4, mask=%pI4, gw=%pI4\n",
160862306a36Sopenharmony_ci		ic_dev->dev->name, ic_dev->dev->addr_len, ic_dev->dev->dev_addr,
160962306a36Sopenharmony_ci		&ic_myaddr, &ic_netmask, &ic_gateway);
161062306a36Sopenharmony_ci	pr_info("     host=%s, domain=%s, nis-domain=%s\n",
161162306a36Sopenharmony_ci		utsname()->nodename, ic_domain, utsname()->domainname);
161262306a36Sopenharmony_ci	pr_info("     bootserver=%pI4, rootserver=%pI4, rootpath=%s",
161362306a36Sopenharmony_ci		&ic_servaddr, &root_server_addr, root_server_path);
161462306a36Sopenharmony_ci	if (ic_dev_mtu)
161562306a36Sopenharmony_ci		pr_cont(", mtu=%d", ic_dev_mtu);
161662306a36Sopenharmony_ci	/* Name servers (if any): */
161762306a36Sopenharmony_ci	for (i = 0, count = 0; i < CONF_NAMESERVERS_MAX; i++) {
161862306a36Sopenharmony_ci		if (ic_nameservers[i] != NONE) {
161962306a36Sopenharmony_ci			if (i == 0)
162062306a36Sopenharmony_ci				pr_info("     nameserver%u=%pI4",
162162306a36Sopenharmony_ci					i, &ic_nameservers[i]);
162262306a36Sopenharmony_ci			else
162362306a36Sopenharmony_ci				pr_cont(", nameserver%u=%pI4",
162462306a36Sopenharmony_ci					i, &ic_nameservers[i]);
162562306a36Sopenharmony_ci
162662306a36Sopenharmony_ci			count++;
162762306a36Sopenharmony_ci		}
162862306a36Sopenharmony_ci		if ((i + 1 == CONF_NAMESERVERS_MAX) && count > 0)
162962306a36Sopenharmony_ci			pr_cont("\n");
163062306a36Sopenharmony_ci	}
163162306a36Sopenharmony_ci	/* NTP servers (if any): */
163262306a36Sopenharmony_ci	for (i = 0, count = 0; i < CONF_NTP_SERVERS_MAX; i++) {
163362306a36Sopenharmony_ci		if (ic_ntp_servers[i] != NONE) {
163462306a36Sopenharmony_ci			if (i == 0)
163562306a36Sopenharmony_ci				pr_info("     ntpserver%u=%pI4",
163662306a36Sopenharmony_ci					i, &ic_ntp_servers[i]);
163762306a36Sopenharmony_ci			else
163862306a36Sopenharmony_ci				pr_cont(", ntpserver%u=%pI4",
163962306a36Sopenharmony_ci					i, &ic_ntp_servers[i]);
164062306a36Sopenharmony_ci
164162306a36Sopenharmony_ci			count++;
164262306a36Sopenharmony_ci		}
164362306a36Sopenharmony_ci		if ((i + 1 == CONF_NTP_SERVERS_MAX) && count > 0)
164462306a36Sopenharmony_ci			pr_cont("\n");
164562306a36Sopenharmony_ci	}
164662306a36Sopenharmony_ci#endif /* !SILENT */
164762306a36Sopenharmony_ci
164862306a36Sopenharmony_ci	/*
164962306a36Sopenharmony_ci	 * Close all network devices except the device we've
165062306a36Sopenharmony_ci	 * autoconfigured and set up routes.
165162306a36Sopenharmony_ci	 */
165262306a36Sopenharmony_ci	if (ic_setup_if() < 0 || ic_setup_routes() < 0)
165362306a36Sopenharmony_ci		err = -1;
165462306a36Sopenharmony_ci	else
165562306a36Sopenharmony_ci		err = 0;
165662306a36Sopenharmony_ci
165762306a36Sopenharmony_ci	ic_close_devs();
165862306a36Sopenharmony_ci
165962306a36Sopenharmony_ci	return err;
166062306a36Sopenharmony_ci}
166162306a36Sopenharmony_ci
166262306a36Sopenharmony_cilate_initcall(ip_auto_config);
166362306a36Sopenharmony_ci
166462306a36Sopenharmony_ci
166562306a36Sopenharmony_ci/*
166662306a36Sopenharmony_ci *  Decode any IP configuration options in the "ip=" or "nfsaddrs=" kernel
166762306a36Sopenharmony_ci *  command line parameter.  See Documentation/admin-guide/nfs/nfsroot.rst.
166862306a36Sopenharmony_ci */
166962306a36Sopenharmony_cistatic int __init ic_proto_name(char *name)
167062306a36Sopenharmony_ci{
167162306a36Sopenharmony_ci	if (!strcmp(name, "on") || !strcmp(name, "any")) {
167262306a36Sopenharmony_ci		return 1;
167362306a36Sopenharmony_ci	}
167462306a36Sopenharmony_ci	if (!strcmp(name, "off") || !strcmp(name, "none")) {
167562306a36Sopenharmony_ci		return 0;
167662306a36Sopenharmony_ci	}
167762306a36Sopenharmony_ci#ifdef CONFIG_IP_PNP_DHCP
167862306a36Sopenharmony_ci	else if (!strncmp(name, "dhcp", 4)) {
167962306a36Sopenharmony_ci		char *client_id;
168062306a36Sopenharmony_ci
168162306a36Sopenharmony_ci		ic_proto_enabled &= ~IC_RARP;
168262306a36Sopenharmony_ci		client_id = strstr(name, "dhcp,");
168362306a36Sopenharmony_ci		if (client_id) {
168462306a36Sopenharmony_ci			char *v;
168562306a36Sopenharmony_ci
168662306a36Sopenharmony_ci			client_id = client_id + 5;
168762306a36Sopenharmony_ci			v = strchr(client_id, ',');
168862306a36Sopenharmony_ci			if (!v)
168962306a36Sopenharmony_ci				return 1;
169062306a36Sopenharmony_ci			*v = 0;
169162306a36Sopenharmony_ci			if (kstrtou8(client_id, 0, dhcp_client_identifier))
169262306a36Sopenharmony_ci				pr_debug("DHCP: Invalid client identifier type\n");
169362306a36Sopenharmony_ci			strncpy(dhcp_client_identifier + 1, v + 1, 251);
169462306a36Sopenharmony_ci			*v = ',';
169562306a36Sopenharmony_ci		}
169662306a36Sopenharmony_ci		return 1;
169762306a36Sopenharmony_ci	}
169862306a36Sopenharmony_ci#endif
169962306a36Sopenharmony_ci#ifdef CONFIG_IP_PNP_BOOTP
170062306a36Sopenharmony_ci	else if (!strcmp(name, "bootp")) {
170162306a36Sopenharmony_ci		ic_proto_enabled &= ~(IC_RARP | IC_USE_DHCP);
170262306a36Sopenharmony_ci		return 1;
170362306a36Sopenharmony_ci	}
170462306a36Sopenharmony_ci#endif
170562306a36Sopenharmony_ci#ifdef CONFIG_IP_PNP_RARP
170662306a36Sopenharmony_ci	else if (!strcmp(name, "rarp")) {
170762306a36Sopenharmony_ci		ic_proto_enabled &= ~(IC_BOOTP | IC_USE_DHCP);
170862306a36Sopenharmony_ci		return 1;
170962306a36Sopenharmony_ci	}
171062306a36Sopenharmony_ci#endif
171162306a36Sopenharmony_ci#ifdef IPCONFIG_DYNAMIC
171262306a36Sopenharmony_ci	else if (!strcmp(name, "both")) {
171362306a36Sopenharmony_ci		ic_proto_enabled &= ~IC_USE_DHCP; /* backward compat :-( */
171462306a36Sopenharmony_ci		return 1;
171562306a36Sopenharmony_ci	}
171662306a36Sopenharmony_ci#endif
171762306a36Sopenharmony_ci	return 0;
171862306a36Sopenharmony_ci}
171962306a36Sopenharmony_ci
172062306a36Sopenharmony_cistatic int __init ip_auto_config_setup(char *addrs)
172162306a36Sopenharmony_ci{
172262306a36Sopenharmony_ci	char *cp, *ip, *dp;
172362306a36Sopenharmony_ci	int num = 0;
172462306a36Sopenharmony_ci
172562306a36Sopenharmony_ci	ic_set_manually = 1;
172662306a36Sopenharmony_ci	ic_enable = 1;
172762306a36Sopenharmony_ci
172862306a36Sopenharmony_ci	/*
172962306a36Sopenharmony_ci	 * If any dhcp, bootp etc options are set, leave autoconfig on
173062306a36Sopenharmony_ci	 * and skip the below static IP processing.
173162306a36Sopenharmony_ci	 */
173262306a36Sopenharmony_ci	if (ic_proto_name(addrs))
173362306a36Sopenharmony_ci		return 1;
173462306a36Sopenharmony_ci
173562306a36Sopenharmony_ci	/* If no static IP is given, turn off autoconfig and bail.  */
173662306a36Sopenharmony_ci	if (*addrs == 0 ||
173762306a36Sopenharmony_ci	    strcmp(addrs, "off") == 0 ||
173862306a36Sopenharmony_ci	    strcmp(addrs, "none") == 0) {
173962306a36Sopenharmony_ci		ic_enable = 0;
174062306a36Sopenharmony_ci		return 1;
174162306a36Sopenharmony_ci	}
174262306a36Sopenharmony_ci
174362306a36Sopenharmony_ci	/* Initialise all name servers and NTP servers to NONE */
174462306a36Sopenharmony_ci	ic_nameservers_predef();
174562306a36Sopenharmony_ci	ic_ntp_servers_predef();
174662306a36Sopenharmony_ci
174762306a36Sopenharmony_ci	/* Parse string for static IP assignment.  */
174862306a36Sopenharmony_ci	ip = addrs;
174962306a36Sopenharmony_ci	while (ip && *ip) {
175062306a36Sopenharmony_ci		if ((cp = strchr(ip, ':')))
175162306a36Sopenharmony_ci			*cp++ = '\0';
175262306a36Sopenharmony_ci		if (strlen(ip) > 0) {
175362306a36Sopenharmony_ci			pr_debug("IP-Config: Parameter #%d: `%s'\n", num, ip);
175462306a36Sopenharmony_ci			switch (num) {
175562306a36Sopenharmony_ci			case 0:
175662306a36Sopenharmony_ci				if ((ic_myaddr = in_aton(ip)) == ANY)
175762306a36Sopenharmony_ci					ic_myaddr = NONE;
175862306a36Sopenharmony_ci				break;
175962306a36Sopenharmony_ci			case 1:
176062306a36Sopenharmony_ci				if ((ic_servaddr = in_aton(ip)) == ANY)
176162306a36Sopenharmony_ci					ic_servaddr = NONE;
176262306a36Sopenharmony_ci				break;
176362306a36Sopenharmony_ci			case 2:
176462306a36Sopenharmony_ci				if ((ic_gateway = in_aton(ip)) == ANY)
176562306a36Sopenharmony_ci					ic_gateway = NONE;
176662306a36Sopenharmony_ci				break;
176762306a36Sopenharmony_ci			case 3:
176862306a36Sopenharmony_ci				if ((ic_netmask = in_aton(ip)) == ANY)
176962306a36Sopenharmony_ci					ic_netmask = NONE;
177062306a36Sopenharmony_ci				break;
177162306a36Sopenharmony_ci			case 4:
177262306a36Sopenharmony_ci				if ((dp = strchr(ip, '.'))) {
177362306a36Sopenharmony_ci					*dp++ = '\0';
177462306a36Sopenharmony_ci					strscpy(utsname()->domainname, dp,
177562306a36Sopenharmony_ci						sizeof(utsname()->domainname));
177662306a36Sopenharmony_ci				}
177762306a36Sopenharmony_ci				strscpy(utsname()->nodename, ip,
177862306a36Sopenharmony_ci					sizeof(utsname()->nodename));
177962306a36Sopenharmony_ci				ic_host_name_set = 1;
178062306a36Sopenharmony_ci				break;
178162306a36Sopenharmony_ci			case 5:
178262306a36Sopenharmony_ci				strscpy(user_dev_name, ip, sizeof(user_dev_name));
178362306a36Sopenharmony_ci				break;
178462306a36Sopenharmony_ci			case 6:
178562306a36Sopenharmony_ci				if (ic_proto_name(ip) == 0 &&
178662306a36Sopenharmony_ci				    ic_myaddr == NONE) {
178762306a36Sopenharmony_ci					ic_enable = 0;
178862306a36Sopenharmony_ci				}
178962306a36Sopenharmony_ci				break;
179062306a36Sopenharmony_ci			case 7:
179162306a36Sopenharmony_ci				if (CONF_NAMESERVERS_MAX >= 1) {
179262306a36Sopenharmony_ci					ic_nameservers[0] = in_aton(ip);
179362306a36Sopenharmony_ci					if (ic_nameservers[0] == ANY)
179462306a36Sopenharmony_ci						ic_nameservers[0] = NONE;
179562306a36Sopenharmony_ci				}
179662306a36Sopenharmony_ci				break;
179762306a36Sopenharmony_ci			case 8:
179862306a36Sopenharmony_ci				if (CONF_NAMESERVERS_MAX >= 2) {
179962306a36Sopenharmony_ci					ic_nameservers[1] = in_aton(ip);
180062306a36Sopenharmony_ci					if (ic_nameservers[1] == ANY)
180162306a36Sopenharmony_ci						ic_nameservers[1] = NONE;
180262306a36Sopenharmony_ci				}
180362306a36Sopenharmony_ci				break;
180462306a36Sopenharmony_ci			case 9:
180562306a36Sopenharmony_ci				if (CONF_NTP_SERVERS_MAX >= 1) {
180662306a36Sopenharmony_ci					ic_ntp_servers[0] = in_aton(ip);
180762306a36Sopenharmony_ci					if (ic_ntp_servers[0] == ANY)
180862306a36Sopenharmony_ci						ic_ntp_servers[0] = NONE;
180962306a36Sopenharmony_ci				}
181062306a36Sopenharmony_ci				break;
181162306a36Sopenharmony_ci			}
181262306a36Sopenharmony_ci		}
181362306a36Sopenharmony_ci		ip = cp;
181462306a36Sopenharmony_ci		num++;
181562306a36Sopenharmony_ci	}
181662306a36Sopenharmony_ci
181762306a36Sopenharmony_ci	return 1;
181862306a36Sopenharmony_ci}
181962306a36Sopenharmony_ci__setup("ip=", ip_auto_config_setup);
182062306a36Sopenharmony_ci
182162306a36Sopenharmony_cistatic int __init nfsaddrs_config_setup(char *addrs)
182262306a36Sopenharmony_ci{
182362306a36Sopenharmony_ci	return ip_auto_config_setup(addrs);
182462306a36Sopenharmony_ci}
182562306a36Sopenharmony_ci__setup("nfsaddrs=", nfsaddrs_config_setup);
182662306a36Sopenharmony_ci
182762306a36Sopenharmony_cistatic int __init vendor_class_identifier_setup(char *addrs)
182862306a36Sopenharmony_ci{
182962306a36Sopenharmony_ci	if (strscpy(vendor_class_identifier, addrs,
183062306a36Sopenharmony_ci		    sizeof(vendor_class_identifier))
183162306a36Sopenharmony_ci	    >= sizeof(vendor_class_identifier))
183262306a36Sopenharmony_ci		pr_warn("DHCP: vendorclass too long, truncated to \"%s\"\n",
183362306a36Sopenharmony_ci			vendor_class_identifier);
183462306a36Sopenharmony_ci	return 1;
183562306a36Sopenharmony_ci}
183662306a36Sopenharmony_ci__setup("dhcpclass=", vendor_class_identifier_setup);
183762306a36Sopenharmony_ci
183862306a36Sopenharmony_cistatic int __init set_carrier_timeout(char *str)
183962306a36Sopenharmony_ci{
184062306a36Sopenharmony_ci	ssize_t ret;
184162306a36Sopenharmony_ci
184262306a36Sopenharmony_ci	if (!str)
184362306a36Sopenharmony_ci		return 0;
184462306a36Sopenharmony_ci
184562306a36Sopenharmony_ci	ret = kstrtouint(str, 0, &carrier_timeout);
184662306a36Sopenharmony_ci	if (ret)
184762306a36Sopenharmony_ci		return 0;
184862306a36Sopenharmony_ci
184962306a36Sopenharmony_ci	return 1;
185062306a36Sopenharmony_ci}
185162306a36Sopenharmony_ci__setup("carrier_timeout=", set_carrier_timeout);
1852