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