2005-04-17 02:20:36 +04:00
/*
* Automatic Configuration of IP - - use DHCP , BOOTP , RARP , or
* user - supplied information to configure own IP address and routes .
*
* Copyright ( C ) 1996 - 1998 Martin Mares < mj @ atrey . karlin . mff . cuni . cz >
*
* Derived from network configuration code in fs / nfs / nfsroot . c ,
* originally Copyright ( C ) 1995 , 1996 Gero Kuhlmann and me .
*
* BOOTP rewritten to construct and analyse packets itself instead
* of misusing the IP layer . num_bugs_causing_wrong_arp_replies - - ;
* - - MJ , December 1998
2007-02-09 17:24:47 +03:00
*
2005-04-17 02:20:36 +04:00
* Fixed ip_auto_config_setup calling at startup in the new " Linker Magic "
* initialization scheme .
* - Arnaldo Carvalho de Melo < acme @ conectiva . com . br > , 08 / 11 / 1999
*
* DHCP support added . To users this looks like a whole separate
* protocol , but we know it ' s just a bag on the side of BOOTP .
* - - Chip Salzenberg < chip @ valinux . com > , May 2000
*
* Ported DHCP support from 2.2 .16 to 2.4 .0 - test4
* - - Eric Biederman < ebiederman @ lnxi . com > , 30 Aug 2000
*
* Merged changes from 2.2 .19 into 2.4 .3
* - - Eric Biederman < ebiederman @ lnxi . com > , 22 April Aug 2001
*
* Multiple Nameservers in / proc / net / pnp
* - - Josef Siemes < jsiemes @ web . de > , Aug 2002
*/
# include <linux/types.h>
# include <linux/string.h>
# include <linux/kernel.h>
# include <linux/jiffies.h>
# include <linux/random.h>
# include <linux/init.h>
# include <linux/utsname.h>
# include <linux/in.h>
# include <linux/if.h>
# include <linux/inet.h>
2005-12-27 07:43:12 +03:00
# include <linux/inetdevice.h>
2005-04-17 02:20:36 +04:00
# include <linux/netdevice.h>
# include <linux/if_arp.h>
# include <linux/skbuff.h>
# include <linux/ip.h>
# include <linux/socket.h>
# include <linux/route.h>
# include <linux/udp.h>
# include <linux/proc_fs.h>
# include <linux/seq_file.h>
# include <linux/major.h>
# include <linux/root_dev.h>
# include <linux/delay.h>
2005-09-06 05:05:52 +04:00
# include <linux/nfs_fs.h>
2007-09-12 14:01:34 +04:00
# include <net/net_namespace.h>
2005-04-17 02:20:36 +04:00
# include <net/arp.h>
# include <net/ip.h>
# include <net/ipconfig.h>
2005-12-27 07:43:12 +03:00
# include <net/route.h>
2005-04-17 02:20:36 +04:00
# include <asm/uaccess.h>
# include <net/checksum.h>
# include <asm/processor.h>
/* Define this to allow debugging output */
# undef IPCONFIG_DEBUG
# ifdef IPCONFIG_DEBUG
# define DBG(x) printk x
# else
# define DBG(x) do { } while(0)
# endif
# if defined(CONFIG_IP_PNP_DHCP)
# define IPCONFIG_DHCP
# endif
# if defined(CONFIG_IP_PNP_BOOTP) || defined(CONFIG_IP_PNP_DHCP)
# define IPCONFIG_BOOTP
# endif
# if defined(CONFIG_IP_PNP_RARP)
# define IPCONFIG_RARP
# endif
# if defined(IPCONFIG_BOOTP) || defined(IPCONFIG_RARP)
# define IPCONFIG_DYNAMIC
# endif
/* Define the friendly delay before and after opening net devices */
# define CONF_PRE_OPEN 500 /* Before opening: 1/2 second */
# define CONF_POST_OPEN 1 /* After opening: 1 second */
/* Define the timeout for waiting for a DHCP/BOOTP/RARP reply */
# define CONF_OPEN_RETRIES 2 /* (Re)open devices twice */
# define CONF_SEND_RETRIES 6 /* Send six requests per open */
# define CONF_INTER_TIMEOUT (HZ / 2) /* Inter-device timeout: 1/2 second */
# define CONF_BASE_TIMEOUT (HZ*2) /* Initial timeout: 2 seconds */
# define CONF_TIMEOUT_RANDOM (HZ) /* Maximum amount of randomization */
# define CONF_TIMEOUT_MULT *7 / 4 /* Rate of timeout growth */
# define CONF_TIMEOUT_MAX (HZ*30) /* Maximum allowed timeout */
2007-02-09 17:24:47 +03:00
# define CONF_NAMESERVERS_MAX 3 / * Maximum number of nameservers
- ' 3 ' from resolv . h */
2005-04-17 02:20:36 +04:00
2006-11-08 11:19:38 +03:00
# define NONE __constant_htonl(INADDR_NONE)
2008-03-18 08:44:53 +03:00
# define ANY __constant_htonl(INADDR_ANY)
2005-04-17 02:20:36 +04:00
/*
* Public IP configuration
*/
/* This is used by platforms which might be able to set the ipconfig
* variables using firmware environment vars . If this is set , it will
* ignore such firmware variables .
*/
int ic_set_manually __initdata = 0 ; /* IPconfig parameters set manually */
static int ic_enable __initdata = 0 ; /* IP config enabled? */
/* Protocol choice */
int ic_proto_enabled __initdata = 0
# ifdef IPCONFIG_BOOTP
| IC_BOOTP
# endif
# ifdef CONFIG_IP_PNP_DHCP
| IC_USE_DHCP
# endif
# ifdef IPCONFIG_RARP
| IC_RARP
# endif
;
static int ic_host_name_set __initdata = 0 ; /* Host name set by us? */
2006-11-08 11:19:38 +03:00
__be32 ic_myaddr = NONE ; /* My IP address */
static __be32 ic_netmask = NONE ; /* Netmask for local subnet */
__be32 ic_gateway = NONE ; /* Gateway IP address */
2005-04-17 02:20:36 +04:00
2006-11-08 11:19:38 +03:00
__be32 ic_servaddr = NONE ; /* Boot server IP address */
2005-04-17 02:20:36 +04:00
2006-11-08 11:19:38 +03:00
__be32 root_server_addr = NONE ; /* Address of NFS server */
2005-04-17 02:20:36 +04:00
u8 root_server_path [ 256 ] = { 0 , } ; /* Path to mount as root */
2007-11-20 08:56:16 +03:00
/* vendor class identifier */
static char vendor_class_identifier [ 253 ] __initdata ;
2007-11-14 13:18:39 +03:00
2005-04-17 02:20:36 +04:00
/* Persistent data: */
static int ic_proto_used ; /* Protocol used, if any */
2006-11-08 11:19:38 +03:00
static __be32 ic_nameservers [ CONF_NAMESERVERS_MAX ] ; /* DNS Server IP addresses */
2005-04-17 02:20:36 +04:00
static u8 ic_domain [ 64 ] ; /* DNS (not NIS) domain name */
/*
* Private state .
*/
/* Name of user-selected boot device */
static char user_dev_name [ IFNAMSIZ ] __initdata = { 0 , } ;
/* Protocols supported by available interfaces */
static int ic_proto_have_if __initdata = 0 ;
# ifdef IPCONFIG_DYNAMIC
static DEFINE_SPINLOCK ( ic_recv_lock ) ;
static volatile int ic_got_reply __initdata = 0 ; /* Proto(s) that replied */
# endif
# ifdef IPCONFIG_DHCP
static int ic_dhcp_msgtype __initdata = 0 ; /* DHCP msg type received */
# endif
/*
* Network devices
*/
struct ic_device {
struct ic_device * next ;
struct net_device * dev ;
unsigned short flags ;
short able ;
2006-11-08 11:19:38 +03:00
__be32 xid ;
2005-04-17 02:20:36 +04:00
} ;
static struct ic_device * ic_first_dev __initdata = NULL ; /* List of open device */
static struct net_device * ic_dev __initdata = NULL ; /* Selected device */
static int __init ic_open_devs ( void )
{
struct ic_device * d , * * last ;
struct net_device * dev ;
unsigned short oflags ;
last = & ic_first_dev ;
2006-03-21 09:23:58 +03:00
rtnl_lock ( ) ;
2005-04-17 02:20:36 +04:00
/* bring loopback device up first */
2007-09-27 09:10:06 +04:00
for_each_netdev ( & init_net , dev ) {
if ( ! ( dev - > flags & IFF_LOOPBACK ) )
continue ;
if ( dev_change_flags ( dev , dev - > flags | IFF_UP ) < 0 )
printk ( KERN_ERR " IP-Config: Failed to open %s \n " , dev - > name ) ;
}
2005-04-17 02:20:36 +04:00
2007-09-17 22:56:21 +04:00
for_each_netdev ( & init_net , dev ) {
2007-09-27 09:10:06 +04:00
if ( dev - > flags & IFF_LOOPBACK )
2005-04-17 02:20:36 +04:00
continue ;
if ( user_dev_name [ 0 ] ? ! strcmp ( dev - > name , user_dev_name ) :
( ! ( dev - > flags & IFF_LOOPBACK ) & &
( dev - > flags & ( IFF_POINTOPOINT | IFF_BROADCAST ) ) & &
strncmp ( dev - > name , " dummy " , 5 ) ) ) {
int able = 0 ;
if ( dev - > mtu > = 364 )
able | = IC_BOOTP ;
else
printk ( KERN_WARNING " DHCP/BOOTP: Ignoring device %s, MTU %d too small " , dev - > name , dev - > mtu ) ;
if ( ! ( dev - > flags & IFF_NOARP ) )
able | = IC_RARP ;
able & = ic_proto_enabled ;
if ( ic_proto_enabled & & ! able )
continue ;
oflags = dev - > flags ;
if ( dev_change_flags ( dev , oflags | IFF_UP ) < 0 ) {
printk ( KERN_ERR " IP-Config: Failed to open %s \n " , dev - > name ) ;
continue ;
}
if ( ! ( d = kmalloc ( sizeof ( struct ic_device ) , GFP_KERNEL ) ) ) {
2006-03-21 09:23:58 +03:00
rtnl_unlock ( ) ;
2005-04-17 02:20:36 +04:00
return - 1 ;
}
d - > dev = dev ;
* last = d ;
last = & d - > next ;
d - > flags = oflags ;
d - > able = able ;
if ( able & IC_BOOTP )
2006-11-08 11:19:38 +03:00
get_random_bytes ( & d - > xid , sizeof ( __be32 ) ) ;
2005-04-17 02:20:36 +04:00
else
d - > xid = 0 ;
ic_proto_have_if | = able ;
DBG ( ( " IP-Config: %s UP (able=%d, xid=%08x) \n " ,
dev - > name , able , d - > xid ) ) ;
}
}
2006-03-21 09:23:58 +03:00
rtnl_unlock ( ) ;
2005-04-17 02:20:36 +04:00
* last = NULL ;
if ( ! ic_first_dev ) {
if ( user_dev_name [ 0 ] )
printk ( KERN_ERR " IP-Config: Device `%s' not found. \n " , user_dev_name ) ;
else
printk ( KERN_ERR " IP-Config: No network devices available. \n " ) ;
return - 1 ;
}
return 0 ;
}
static void __init ic_close_devs ( void )
{
struct ic_device * d , * next ;
struct net_device * dev ;
2006-03-21 09:23:58 +03:00
rtnl_lock ( ) ;
2005-04-17 02:20:36 +04:00
next = ic_first_dev ;
while ( ( d = next ) ) {
next = d - > next ;
dev = d - > dev ;
if ( dev ! = ic_dev ) {
DBG ( ( " IP-Config: Downing %s \n " , dev - > name ) ) ;
dev_change_flags ( dev , d - > flags ) ;
}
kfree ( d ) ;
}
2006-03-21 09:23:58 +03:00
rtnl_unlock ( ) ;
2005-04-17 02:20:36 +04:00
}
/*
* Interface to various network functions .
*/
static inline void
2006-11-08 11:19:38 +03:00
set_sockaddr ( struct sockaddr_in * sin , __be32 addr , __be16 port )
2005-04-17 02:20:36 +04:00
{
sin - > sin_family = AF_INET ;
sin - > sin_addr . s_addr = addr ;
sin - > sin_port = port ;
}
static int __init ic_dev_ioctl ( unsigned int cmd , struct ifreq * arg )
{
int res ;
mm_segment_t oldfs = get_fs ( ) ;
set_fs ( get_ds ( ) ) ;
2008-02-29 07:51:43 +03:00
res = devinet_ioctl ( & init_net , cmd , ( struct ifreq __user * ) arg ) ;
2005-04-17 02:20:36 +04:00
set_fs ( oldfs ) ;
return res ;
}
static int __init ic_route_ioctl ( unsigned int cmd , struct rtentry * arg )
{
int res ;
mm_segment_t oldfs = get_fs ( ) ;
set_fs ( get_ds ( ) ) ;
2008-01-10 14:29:53 +03:00
res = ip_rt_ioctl ( & init_net , cmd , ( void __user * ) arg ) ;
2005-04-17 02:20:36 +04:00
set_fs ( oldfs ) ;
return res ;
}
/*
* Set up interface addresses and routes .
*/
static int __init ic_setup_if ( void )
{
struct ifreq ir ;
struct sockaddr_in * sin = ( void * ) & ir . ifr_ifru . ifru_addr ;
int err ;
memset ( & ir , 0 , sizeof ( ir ) ) ;
strcpy ( ir . ifr_ifrn . ifrn_name , ic_dev - > name ) ;
set_sockaddr ( sin , ic_myaddr , 0 ) ;
if ( ( err = ic_dev_ioctl ( SIOCSIFADDR , & ir ) ) < 0 ) {
printk ( KERN_ERR " IP-Config: Unable to set interface address (%d). \n " , err ) ;
return - 1 ;
}
set_sockaddr ( sin , ic_netmask , 0 ) ;
if ( ( err = ic_dev_ioctl ( SIOCSIFNETMASK , & ir ) ) < 0 ) {
printk ( KERN_ERR " IP-Config: Unable to set interface netmask (%d). \n " , err ) ;
return - 1 ;
}
set_sockaddr ( sin , ic_myaddr | ~ ic_netmask , 0 ) ;
if ( ( err = ic_dev_ioctl ( SIOCSIFBRDADDR , & ir ) ) < 0 ) {
printk ( KERN_ERR " IP-Config: Unable to set interface broadcast address (%d). \n " , err ) ;
return - 1 ;
}
return 0 ;
}
static int __init ic_setup_routes ( void )
{
/* No need to setup device routes, only the default route... */
2006-11-08 11:19:38 +03:00
if ( ic_gateway ! = NONE ) {
2005-04-17 02:20:36 +04:00
struct rtentry rm ;
int err ;
memset ( & rm , 0 , sizeof ( rm ) ) ;
if ( ( ic_gateway ^ ic_myaddr ) & ic_netmask ) {
printk ( KERN_ERR " IP-Config: Gateway not on directly connected network. \n " ) ;
return - 1 ;
}
set_sockaddr ( ( struct sockaddr_in * ) & rm . rt_dst , 0 , 0 ) ;
set_sockaddr ( ( struct sockaddr_in * ) & rm . rt_genmask , 0 , 0 ) ;
set_sockaddr ( ( struct sockaddr_in * ) & rm . rt_gateway , ic_gateway , 0 ) ;
rm . rt_flags = RTF_UP | RTF_GATEWAY ;
if ( ( err = ic_route_ioctl ( SIOCADDRT , & rm ) ) < 0 ) {
printk ( KERN_ERR " IP-Config: Cannot add default route (%d). \n " , err ) ;
return - 1 ;
}
}
return 0 ;
}
/*
* Fill in default values for all missing parameters .
*/
static int __init ic_defaults ( void )
{
/*
* At this point we have no userspace running so need not
* claim locks on system_utsname
*/
2007-02-09 17:24:47 +03:00
2005-04-17 02:20:36 +04:00
if ( ! ic_host_name_set )
2008-10-31 10:53:57 +03:00
sprintf ( init_utsname ( ) - > nodename , " %pI4 " , & ic_myaddr ) ;
2005-04-17 02:20:36 +04:00
2006-11-08 11:19:38 +03:00
if ( root_server_addr = = NONE )
2005-04-17 02:20:36 +04:00
root_server_addr = ic_servaddr ;
2006-11-08 11:19:38 +03:00
if ( ic_netmask = = NONE ) {
2005-04-17 02:20:36 +04:00
if ( IN_CLASSA ( ntohl ( ic_myaddr ) ) )
ic_netmask = htonl ( IN_CLASSA_NET ) ;
else if ( IN_CLASSB ( ntohl ( ic_myaddr ) ) )
ic_netmask = htonl ( IN_CLASSB_NET ) ;
else if ( IN_CLASSC ( ntohl ( ic_myaddr ) ) )
ic_netmask = htonl ( IN_CLASSC_NET ) ;
else {
2008-10-31 10:53:57 +03:00
printk ( KERN_ERR " IP-Config: Unable to guess netmask for address %pI4 \n " ,
& ic_myaddr ) ;
2005-04-17 02:20:36 +04:00
return - 1 ;
}
2008-10-31 10:53:57 +03:00
printk ( " IP-Config: Guessing netmask %pI4 \n " , & ic_netmask ) ;
2005-04-17 02:20:36 +04:00
}
return 0 ;
}
/*
* RARP support .
*/
# ifdef IPCONFIG_RARP
2005-08-10 06:34:12 +04:00
static int ic_rarp_recv ( struct sk_buff * skb , struct net_device * dev , struct packet_type * pt , struct net_device * orig_dev ) ;
2005-04-17 02:20:36 +04:00
static struct packet_type rarp_packet_type __initdata = {
. type = __constant_htons ( ETH_P_RARP ) ,
. func = ic_rarp_recv ,
} ;
2008-04-30 07:58:15 +04:00
static inline void __init ic_rarp_init ( void )
2005-04-17 02:20:36 +04:00
{
dev_add_pack ( & rarp_packet_type ) ;
}
2008-04-30 07:58:15 +04:00
static inline void __init ic_rarp_cleanup ( void )
2005-04-17 02:20:36 +04:00
{
dev_remove_pack ( & rarp_packet_type ) ;
}
/*
* Process received RARP packet .
*/
static int __init
2005-08-10 06:34:12 +04:00
ic_rarp_recv ( struct sk_buff * skb , struct net_device * dev , struct packet_type * pt , struct net_device * orig_dev )
2005-04-17 02:20:36 +04:00
{
struct arphdr * rarp ;
unsigned char * rarp_ptr ;
2006-11-08 11:19:38 +03:00
__be32 sip , tip ;
2005-04-17 02:20:36 +04:00
unsigned char * sha , * tha ; /* s for "source", t for "target" */
struct ic_device * d ;
2008-07-20 09:34:43 +04:00
if ( ! net_eq ( dev_net ( dev ) , & init_net ) )
2007-09-17 22:53:39 +04:00
goto drop ;
2005-04-17 02:20:36 +04:00
if ( ( skb = skb_share_check ( skb , GFP_ATOMIC ) ) = = NULL )
return NET_RX_DROP ;
if ( ! pskb_may_pull ( skb , sizeof ( struct arphdr ) ) )
goto drop ;
/* Basic sanity checks can be done without the lock. */
2007-04-26 05:04:18 +04:00
rarp = ( struct arphdr * ) skb_transport_header ( skb ) ;
2005-04-17 02:20:36 +04:00
/* If this test doesn't pass, it's not IP, or we should
* ignore it anyway .
*/
if ( rarp - > ar_hln ! = dev - > addr_len | | dev - > type ! = ntohs ( rarp - > ar_hrd ) )
goto drop ;
/* If it's not a RARP reply, delete it. */
if ( rarp - > ar_op ! = htons ( ARPOP_RREPLY ) )
goto drop ;
/* If it's not Ethernet, delete it. */
if ( rarp - > ar_pro ! = htons ( ETH_P_IP ) )
goto drop ;
2008-03-03 23:20:57 +03:00
if ( ! pskb_may_pull ( skb , arp_hdr_len ( dev ) ) )
2005-04-17 02:20:36 +04:00
goto drop ;
/* OK, it is all there and looks valid, process... */
2007-04-26 05:04:18 +04:00
rarp = ( struct arphdr * ) skb_transport_header ( skb ) ;
2005-04-17 02:20:36 +04:00
rarp_ptr = ( unsigned char * ) ( rarp + 1 ) ;
/* One reply at a time, please. */
spin_lock ( & ic_recv_lock ) ;
/* If we already have a reply, just drop the packet */
if ( ic_got_reply )
goto drop_unlock ;
/* Find the ic_device that the packet arrived on */
d = ic_first_dev ;
while ( d & & d - > dev ! = dev )
d = d - > next ;
if ( ! d )
goto drop_unlock ; /* should never happen */
/* Extract variable-width fields */
sha = rarp_ptr ;
rarp_ptr + = dev - > addr_len ;
memcpy ( & sip , rarp_ptr , 4 ) ;
rarp_ptr + = 4 ;
tha = rarp_ptr ;
rarp_ptr + = dev - > addr_len ;
memcpy ( & tip , rarp_ptr , 4 ) ;
/* Discard packets which are not meant for us. */
if ( memcmp ( tha , dev - > dev_addr , dev - > addr_len ) )
goto drop_unlock ;
/* Discard packets which are not from specified server. */
2006-11-08 11:19:38 +03:00
if ( ic_servaddr ! = NONE & & ic_servaddr ! = sip )
2005-04-17 02:20:36 +04:00
goto drop_unlock ;
/* We have a winner! */
ic_dev = dev ;
2006-11-08 11:19:38 +03:00
if ( ic_myaddr = = NONE )
2005-04-17 02:20:36 +04:00
ic_myaddr = tip ;
ic_servaddr = sip ;
ic_got_reply = IC_RARP ;
drop_unlock :
/* Show's over. Nothing to see here. */
spin_unlock ( & ic_recv_lock ) ;
drop :
/* Throw the packet out. */
kfree_skb ( skb ) ;
return 0 ;
}
/*
* Send RARP request packet over a single interface .
*/
static void __init ic_rarp_send_if ( struct ic_device * d )
{
struct net_device * dev = d - > dev ;
arp_send ( ARPOP_RREQUEST , ETH_P_RARP , 0 , dev , 0 , NULL ,
dev - > dev_addr , dev - > dev_addr ) ;
}
# endif
/*
* DHCP / BOOTP support .
*/
# ifdef IPCONFIG_BOOTP
struct bootp_pkt { /* BOOTP packet format */
struct iphdr iph ; /* IP header */
struct udphdr udph ; /* UDP header */
u8 op ; /* 1=request, 2=reply */
u8 htype ; /* HW address type */
u8 hlen ; /* HW address length */
u8 hops ; /* Used only by gateways */
2006-11-08 11:19:38 +03:00
__be32 xid ; /* Transaction ID */
__be16 secs ; /* Seconds since we started */
__be16 flags ; /* Just what it says */
__be32 client_ip ; /* Client's IP address if known */
__be32 your_ip ; /* Assigned IP address */
__be32 server_ip ; /* (Next, e.g. NFS) Server's IP address */
__be32 relay_ip ; /* IP address of BOOTP relay */
2005-04-17 02:20:36 +04:00
u8 hw_addr [ 16 ] ; /* Client's HW address */
u8 serv_name [ 64 ] ; /* Server host name */
u8 boot_file [ 128 ] ; /* Name of boot file */
u8 exten [ 312 ] ; /* DHCP options / BOOTP vendor extensions */
} ;
/* packet ops */
# define BOOTP_REQUEST 1
# define BOOTP_REPLY 2
/* DHCP message types */
# define DHCPDISCOVER 1
# define DHCPOFFER 2
# define DHCPREQUEST 3
# define DHCPDECLINE 4
# define DHCPACK 5
# define DHCPNAK 6
# define DHCPRELEASE 7
# define DHCPINFORM 8
2005-08-10 06:34:12 +04:00
static int ic_bootp_recv ( struct sk_buff * skb , struct net_device * dev , struct packet_type * pt , struct net_device * orig_dev ) ;
2005-04-17 02:20:36 +04:00
static struct packet_type bootp_packet_type __initdata = {
. type = __constant_htons ( ETH_P_IP ) ,
. func = ic_bootp_recv ,
} ;
/*
* Initialize DHCP / BOOTP extension fields in the request .
*/
static const u8 ic_bootp_cookie [ 4 ] = { 99 , 130 , 83 , 99 } ;
# ifdef IPCONFIG_DHCP
static void __init
ic_dhcp_init_options ( u8 * options )
{
2006-11-08 11:19:38 +03:00
u8 mt = ( ( ic_servaddr = = NONE )
2005-04-17 02:20:36 +04:00
? DHCPDISCOVER : DHCPREQUEST ) ;
u8 * e = options ;
2007-11-14 13:18:39 +03:00
int len ;
2005-04-17 02:20:36 +04:00
# ifdef IPCONFIG_DEBUG
printk ( " DHCP: Sending message type %d \n " , mt ) ;
# endif
memcpy ( e , ic_bootp_cookie , 4 ) ; /* RFC1048 Magic Cookie */
e + = 4 ;
* e + + = 53 ; /* DHCP message type */
* e + + = 1 ;
* e + + = mt ;
if ( mt = = DHCPREQUEST ) {
* e + + = 54 ; /* Server ID (IP address) */
* e + + = 4 ;
memcpy ( e , & ic_servaddr , 4 ) ;
e + = 4 ;
* e + + = 50 ; /* Requested IP address */
* e + + = 4 ;
memcpy ( e , & ic_myaddr , 4 ) ;
e + = 4 ;
}
/* always? */
{
static const u8 ic_req_params [ ] = {
1 , /* Subnet mask */
3 , /* Default gateway */
6 , /* DNS server */
12 , /* Host name */
15 , /* Domain name */
17 , /* Boot path */
40 , /* NIS domain name */
} ;
* e + + = 55 ; /* Parameter request list */
* e + + = sizeof ( ic_req_params ) ;
memcpy ( e , ic_req_params , sizeof ( ic_req_params ) ) ;
e + = sizeof ( ic_req_params ) ;
2007-11-14 13:18:39 +03:00
if ( * vendor_class_identifier ) {
printk ( KERN_INFO " DHCP: sending class identifier \" %s \" \n " ,
vendor_class_identifier ) ;
* e + + = 60 ; /* Class-identifier */
len = strlen ( vendor_class_identifier ) ;
* e + + = len ;
memcpy ( e , vendor_class_identifier , len ) ;
e + = len ;
}
2005-04-17 02:20:36 +04:00
}
* e + + = 255 ; /* End of the list */
}
# endif /* IPCONFIG_DHCP */
static void __init ic_bootp_init_ext ( u8 * e )
{
memcpy ( e , ic_bootp_cookie , 4 ) ; /* RFC1048 Magic Cookie */
e + = 4 ;
* e + + = 1 ; /* Subnet mask request */
* e + + = 4 ;
e + = 4 ;
* e + + = 3 ; /* Default gateway request */
* e + + = 4 ;
e + = 4 ;
* e + + = 5 ; /* Name server request */
* e + + = 8 ;
e + = 8 ;
* e + + = 12 ; /* Host name request */
* e + + = 32 ;
e + = 32 ;
* e + + = 40 ; /* NIS Domain name request */
* e + + = 32 ;
e + = 32 ;
* e + + = 17 ; /* Boot path */
* e + + = 40 ;
e + = 40 ;
2007-02-09 17:24:47 +03:00
* e + + = 57 ; /* set extension buffer size for reply */
2005-04-17 02:20:36 +04:00
* e + + = 2 ;
2007-02-09 17:24:47 +03:00
* e + + = 1 ; /* 128+236+8+20+14, see dhcpd sources */
2005-04-17 02:20:36 +04:00
* e + + = 150 ;
* e + + = 255 ; /* End of the list */
}
/*
* Initialize the DHCP / BOOTP mechanism .
*/
2008-04-30 07:58:15 +04:00
static inline void __init ic_bootp_init ( void )
2005-04-17 02:20:36 +04:00
{
int i ;
for ( i = 0 ; i < CONF_NAMESERVERS_MAX ; i + + )
2006-11-08 11:19:38 +03:00
ic_nameservers [ i ] = NONE ;
2005-04-17 02:20:36 +04:00
dev_add_pack ( & bootp_packet_type ) ;
}
/*
* DHCP / BOOTP cleanup .
*/
2008-04-30 07:58:15 +04:00
static inline void __init ic_bootp_cleanup ( void )
2005-04-17 02:20:36 +04:00
{
dev_remove_pack ( & bootp_packet_type ) ;
}
/*
* Send DHCP / BOOTP request to single interface .
*/
static void __init ic_bootp_send_if ( struct ic_device * d , unsigned long jiffies_diff )
{
struct net_device * dev = d - > dev ;
struct sk_buff * skb ;
struct bootp_pkt * b ;
struct iphdr * h ;
/* Allocate packet */
2008-05-13 07:48:31 +04:00
skb = alloc_skb ( sizeof ( struct bootp_pkt ) + LL_ALLOCATED_SPACE ( dev ) + 15 ,
GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( ! skb )
return ;
2008-05-13 07:48:31 +04:00
skb_reserve ( skb , LL_RESERVED_SPACE ( dev ) ) ;
2005-04-17 02:20:36 +04:00
b = ( struct bootp_pkt * ) skb_put ( skb , sizeof ( struct bootp_pkt ) ) ;
memset ( b , 0 , sizeof ( struct bootp_pkt ) ) ;
/* Construct IP header */
2007-03-11 01:27:27 +03:00
skb_reset_network_header ( skb ) ;
2007-04-21 09:47:35 +04:00
h = ip_hdr ( skb ) ;
2005-04-17 02:20:36 +04:00
h - > version = 4 ;
h - > ihl = 5 ;
h - > tot_len = htons ( sizeof ( struct bootp_pkt ) ) ;
h - > frag_off = htons ( IP_DF ) ;
h - > ttl = 64 ;
h - > protocol = IPPROTO_UDP ;
2006-11-08 11:19:38 +03:00
h - > daddr = htonl ( INADDR_BROADCAST ) ;
2005-04-17 02:20:36 +04:00
h - > check = ip_fast_csum ( ( unsigned char * ) h , h - > ihl ) ;
/* Construct UDP header */
b - > udph . source = htons ( 68 ) ;
b - > udph . dest = htons ( 67 ) ;
b - > udph . len = htons ( sizeof ( struct bootp_pkt ) - sizeof ( struct iphdr ) ) ;
/* UDP checksum not calculated -- explicitly allowed in BOOTP RFC */
/* Construct DHCP/BOOTP header */
b - > op = BOOTP_REQUEST ;
if ( dev - > type < 256 ) /* check for false types */
b - > htype = dev - > type ;
else if ( dev - > type = = ARPHRD_IEEE802_TR ) /* fix for token ring */
b - > htype = ARPHRD_IEEE802 ;
else if ( dev - > type = = ARPHRD_FDDI )
b - > htype = ARPHRD_ETHER ;
else {
printk ( " Unknown ARP type 0x%04x for device %s \n " , dev - > type , dev - > name ) ;
b - > htype = dev - > type ; /* can cause undefined behavior */
}
2008-03-05 04:03:49 +03:00
/* server_ip and your_ip address are both already zero per RFC2131 */
2005-04-17 02:20:36 +04:00
b - > hlen = dev - > addr_len ;
memcpy ( b - > hw_addr , dev - > dev_addr , dev - > addr_len ) ;
b - > secs = htons ( jiffies_diff / HZ ) ;
b - > xid = d - > xid ;
/* add DHCP options or BOOTP extensions */
# ifdef IPCONFIG_DHCP
if ( ic_proto_enabled & IC_USE_DHCP )
ic_dhcp_init_options ( b - > exten ) ;
else
# endif
ic_bootp_init_ext ( b - > exten ) ;
/* Chain packet down the line... */
skb - > dev = dev ;
skb - > protocol = htons ( ETH_P_IP ) ;
2007-10-09 12:36:32 +04:00
if ( dev_hard_header ( skb , dev , ntohs ( skb - > protocol ) ,
dev - > broadcast , dev - > dev_addr , skb - > len ) < 0 | |
2005-04-17 02:20:36 +04:00
dev_queue_xmit ( skb ) < 0 )
printk ( " E " ) ;
}
/*
* Copy BOOTP - supplied string if not already set .
*/
static int __init ic_bootp_string ( char * dest , char * src , int len , int max )
{
if ( ! len )
return 0 ;
if ( len > max - 1 )
len = max - 1 ;
memcpy ( dest , src , len ) ;
dest [ len ] = ' \0 ' ;
return 1 ;
}
/*
* Process BOOTP extensions .
*/
static void __init ic_do_bootp_ext ( u8 * ext )
{
u8 servers ;
int i ;
# ifdef IPCONFIG_DEBUG
u8 * c ;
printk ( " DHCP/BOOTP: Got extension %d: " , * ext ) ;
2007-03-09 07:44:43 +03:00
for ( c = ext + 2 ; c < ext + 2 + ext [ 1 ] ; c + + )
2005-04-17 02:20:36 +04:00
printk ( " %02x " , * c ) ;
printk ( " \n " ) ;
# endif
switch ( * ext + + ) {
case 1 : /* Subnet mask */
2006-11-08 11:19:38 +03:00
if ( ic_netmask = = NONE )
2005-04-17 02:20:36 +04:00
memcpy ( & ic_netmask , ext + 1 , 4 ) ;
break ;
case 3 : /* Default gateway */
2006-11-08 11:19:38 +03:00
if ( ic_gateway = = NONE )
2005-04-17 02:20:36 +04:00
memcpy ( & ic_gateway , ext + 1 , 4 ) ;
break ;
case 6 : /* DNS server */
servers = * ext / 4 ;
if ( servers > CONF_NAMESERVERS_MAX )
servers = CONF_NAMESERVERS_MAX ;
for ( i = 0 ; i < servers ; i + + ) {
2006-11-08 11:19:38 +03:00
if ( ic_nameservers [ i ] = = NONE )
2005-04-17 02:20:36 +04:00
memcpy ( & ic_nameservers [ i ] , ext + 1 + 4 * i , 4 ) ;
}
break ;
case 12 : /* Host name */
2006-10-02 13:18:11 +04:00
ic_bootp_string ( utsname ( ) - > nodename , ext + 1 , * ext , __NEW_UTS_LEN ) ;
2005-04-17 02:20:36 +04:00
ic_host_name_set = 1 ;
break ;
case 15 : /* Domain name (DNS) */
ic_bootp_string ( ic_domain , ext + 1 , * ext , sizeof ( ic_domain ) ) ;
break ;
case 17 : /* Root path */
if ( ! root_server_path [ 0 ] )
ic_bootp_string ( root_server_path , ext + 1 , * ext , sizeof ( root_server_path ) ) ;
break ;
case 40 : /* NIS Domain name (_not_ DNS) */
2006-10-02 13:18:11 +04:00
ic_bootp_string ( utsname ( ) - > domainname , ext + 1 , * ext , __NEW_UTS_LEN ) ;
2005-04-17 02:20:36 +04:00
break ;
}
}
/*
* Receive BOOTP reply .
*/
2005-08-10 06:34:12 +04:00
static int __init ic_bootp_recv ( struct sk_buff * skb , struct net_device * dev , struct packet_type * pt , struct net_device * orig_dev )
2005-04-17 02:20:36 +04:00
{
struct bootp_pkt * b ;
struct iphdr * h ;
struct ic_device * d ;
int len , ext_len ;
2008-07-20 09:34:43 +04:00
if ( ! net_eq ( dev_net ( dev ) , & init_net ) )
2007-09-17 22:53:39 +04:00
goto drop ;
2005-04-17 02:20:36 +04:00
/* Perform verifications before taking the lock. */
if ( skb - > pkt_type = = PACKET_OTHERHOST )
goto drop ;
if ( ( skb = skb_share_check ( skb , GFP_ATOMIC ) ) = = NULL )
return NET_RX_DROP ;
if ( ! pskb_may_pull ( skb ,
sizeof ( struct iphdr ) +
sizeof ( struct udphdr ) ) )
goto drop ;
2007-04-21 09:47:35 +04:00
b = ( struct bootp_pkt * ) skb_network_header ( skb ) ;
2005-04-17 02:20:36 +04:00
h = & b - > iph ;
if ( h - > ihl ! = 5 | | h - > version ! = 4 | | h - > protocol ! = IPPROTO_UDP )
goto drop ;
/* Fragments are not supported */
if ( h - > frag_off & htons ( IP_OFFSET | IP_MF ) ) {
if ( net_ratelimit ( ) )
printk ( KERN_ERR " DHCP/BOOTP: Ignoring fragmented "
" reply. \n " ) ;
goto drop ;
}
if ( skb - > len < ntohs ( h - > tot_len ) )
goto drop ;
if ( ip_fast_csum ( ( char * ) h , h - > ihl ) )
goto drop ;
if ( b - > udph . source ! = htons ( 67 ) | | b - > udph . dest ! = htons ( 68 ) )
goto drop ;
if ( ntohs ( h - > tot_len ) < ntohs ( b - > udph . len ) + sizeof ( struct iphdr ) )
goto drop ;
len = ntohs ( b - > udph . len ) - sizeof ( struct udphdr ) ;
ext_len = len - ( sizeof ( * b ) -
sizeof ( struct iphdr ) -
sizeof ( struct udphdr ) -
sizeof ( b - > exten ) ) ;
if ( ext_len < 0 )
goto drop ;
/* Ok the front looks good, make sure we can get at the rest. */
if ( ! pskb_may_pull ( skb , skb - > len ) )
goto drop ;
2007-04-21 09:47:35 +04:00
b = ( struct bootp_pkt * ) skb_network_header ( skb ) ;
2005-04-17 02:20:36 +04:00
h = & b - > iph ;
/* One reply at a time, please. */
spin_lock ( & ic_recv_lock ) ;
/* If we already have a reply, just drop the packet */
if ( ic_got_reply )
goto drop_unlock ;
/* Find the ic_device that the packet arrived on */
d = ic_first_dev ;
while ( d & & d - > dev ! = dev )
d = d - > next ;
if ( ! d )
goto drop_unlock ; /* should never happen */
/* Is it a reply to our BOOTP request? */
if ( b - > op ! = BOOTP_REPLY | |
b - > xid ! = d - > xid ) {
if ( net_ratelimit ( ) )
printk ( KERN_ERR " DHCP/BOOTP: Reply not for us, "
" op[%x] xid[%x] \n " ,
b - > op , b - > xid ) ;
goto drop_unlock ;
}
/* Parse extensions */
if ( ext_len > = 4 & &
! memcmp ( b - > exten , ic_bootp_cookie , 4 ) ) { /* Check magic cookie */
2007-02-09 17:24:47 +03:00
u8 * end = ( u8 * ) b + ntohs ( b - > iph . tot_len ) ;
2005-04-17 02:20:36 +04:00
u8 * ext ;
# ifdef IPCONFIG_DHCP
if ( ic_proto_enabled & IC_USE_DHCP ) {
2006-11-08 11:19:38 +03:00
__be32 server_id = NONE ;
2005-04-17 02:20:36 +04:00
int mt = 0 ;
ext = & b - > exten [ 4 ] ;
while ( ext < end & & * ext ! = 0xff ) {
u8 * opt = ext + + ;
if ( * opt = = 0 ) /* Padding */
continue ;
ext + = * ext + 1 ;
if ( ext > = end )
break ;
switch ( * opt ) {
case 53 : /* Message type */
if ( opt [ 1 ] )
mt = opt [ 2 ] ;
break ;
case 54 : /* Server ID (IP address) */
if ( opt [ 1 ] > = 4 )
memcpy ( & server_id , opt + 2 , 4 ) ;
break ;
2007-04-21 04:09:22 +04:00
}
2005-04-17 02:20:36 +04:00
}
# ifdef IPCONFIG_DEBUG
printk ( " DHCP: Got message type %d \n " , mt ) ;
# endif
switch ( mt ) {
case DHCPOFFER :
/* While in the process of accepting one offer,
* ignore all others .
*/
2006-11-08 11:19:38 +03:00
if ( ic_myaddr ! = NONE )
2005-04-17 02:20:36 +04:00
goto drop_unlock ;
/* Let's accept that offer. */
ic_myaddr = b - > your_ip ;
ic_servaddr = server_id ;
# ifdef IPCONFIG_DEBUG
2008-10-31 10:53:57 +03:00
printk ( " DHCP: Offered address %pI4 by server %pI4 \n " ,
& ic_myaddr , & ic_servaddr ) ;
2005-04-17 02:20:36 +04:00
# endif
/* The DHCP indicated server address takes
* precedence over the bootp header one if
* they are different .
*/
2006-11-08 11:19:38 +03:00
if ( ( server_id ! = NONE ) & &
2005-04-17 02:20:36 +04:00
( b - > server_ip ! = server_id ) )
b - > server_ip = ic_servaddr ;
break ;
case DHCPACK :
if ( memcmp ( dev - > dev_addr , b - > hw_addr , dev - > addr_len ) ! = 0 )
goto drop_unlock ;
/* Yeah! */
break ;
default :
/* Urque. Forget it*/
2006-11-08 11:19:38 +03:00
ic_myaddr = NONE ;
ic_servaddr = NONE ;
2005-04-17 02:20:36 +04:00
goto drop_unlock ;
2007-04-21 04:09:22 +04:00
}
2005-04-17 02:20:36 +04:00
ic_dhcp_msgtype = mt ;
}
# endif /* IPCONFIG_DHCP */
ext = & b - > exten [ 4 ] ;
while ( ext < end & & * ext ! = 0xff ) {
u8 * opt = ext + + ;
if ( * opt = = 0 ) /* Padding */
continue ;
ext + = * ext + 1 ;
if ( ext < end )
ic_do_bootp_ext ( opt ) ;
}
}
/* We have a winner! */
ic_dev = dev ;
ic_myaddr = b - > your_ip ;
ic_servaddr = b - > server_ip ;
2006-11-08 11:19:38 +03:00
if ( ic_gateway = = NONE & & b - > relay_ip )
2005-04-17 02:20:36 +04:00
ic_gateway = b - > relay_ip ;
2006-11-08 11:19:38 +03:00
if ( ic_nameservers [ 0 ] = = NONE )
2005-04-17 02:20:36 +04:00
ic_nameservers [ 0 ] = ic_servaddr ;
ic_got_reply = IC_BOOTP ;
drop_unlock :
/* Show's over. Nothing to see here. */
spin_unlock ( & ic_recv_lock ) ;
drop :
/* Throw the packet out. */
kfree_skb ( skb ) ;
return 0 ;
2007-02-09 17:24:47 +03:00
}
2005-04-17 02:20:36 +04:00
# endif
/*
* Dynamic IP configuration - - DHCP , BOOTP , RARP .
*/
# ifdef IPCONFIG_DYNAMIC
static int __init ic_dynamic ( void )
{
int retries ;
struct ic_device * d ;
unsigned long start_jiffies , timeout , jiff ;
int do_bootp = ic_proto_have_if & IC_BOOTP ;
int do_rarp = ic_proto_have_if & IC_RARP ;
/*
* If none of DHCP / BOOTP / RARP was selected , return with an error .
* This routine gets only called when some pieces of information
* are missing , and without DHCP / BOOTP / RARP we are unable to get it .
*/
if ( ! ic_proto_enabled ) {
printk ( KERN_ERR " IP-Config: Incomplete network configuration information. \n " ) ;
return - 1 ;
}
# ifdef IPCONFIG_BOOTP
if ( ( ic_proto_enabled ^ ic_proto_have_if ) & IC_BOOTP )
printk ( KERN_ERR " DHCP/BOOTP: No suitable device found. \n " ) ;
# endif
# ifdef IPCONFIG_RARP
if ( ( ic_proto_enabled ^ ic_proto_have_if ) & IC_RARP )
printk ( KERN_ERR " RARP: No suitable device found. \n " ) ;
# endif
if ( ! ic_proto_have_if )
/* Error message already printed */
return - 1 ;
/*
* Setup protocols
*/
# ifdef IPCONFIG_BOOTP
if ( do_bootp )
ic_bootp_init ( ) ;
# endif
# ifdef IPCONFIG_RARP
if ( do_rarp )
ic_rarp_init ( ) ;
# endif
/*
* Send requests and wait , until we get an answer . This loop
* seems to be a terrible waste of CPU time , but actually there is
* only one process running at all , so we don ' t need to use any
* scheduler functions .
2007-02-09 17:24:47 +03:00
* [ Actually we could now , but the nothing else running note still
2005-04-17 02:20:36 +04:00
* applies . . - AC ]
*/
printk ( KERN_NOTICE " Sending %s%s%s requests . " ,
do_bootp
? ( ( ic_proto_enabled & IC_USE_DHCP ) ? " DHCP " : " BOOTP " ) : " " ,
( do_bootp & & do_rarp ) ? " and " : " " ,
do_rarp ? " RARP " : " " ) ;
start_jiffies = jiffies ;
d = ic_first_dev ;
retries = CONF_SEND_RETRIES ;
get_random_bytes ( & timeout , sizeof ( timeout ) ) ;
timeout = CONF_BASE_TIMEOUT + ( timeout % ( unsigned ) CONF_TIMEOUT_RANDOM ) ;
2007-03-09 07:44:43 +03:00
for ( ; ; ) {
2005-04-17 02:20:36 +04:00
# ifdef IPCONFIG_BOOTP
if ( do_bootp & & ( d - > able & IC_BOOTP ) )
ic_bootp_send_if ( d , jiffies - start_jiffies ) ;
# endif
# ifdef IPCONFIG_RARP
if ( do_rarp & & ( d - > able & IC_RARP ) )
ic_rarp_send_if ( d ) ;
# endif
jiff = jiffies + ( d - > next ? CONF_INTER_TIMEOUT : timeout ) ;
2005-09-13 01:15:34 +04:00
while ( time_before ( jiffies , jiff ) & & ! ic_got_reply )
schedule_timeout_uninterruptible ( 1 ) ;
2005-04-17 02:20:36 +04:00
# ifdef IPCONFIG_DHCP
/* DHCP isn't done until we get a DHCPACK. */
if ( ( ic_got_reply & IC_BOOTP )
& & ( ic_proto_enabled & IC_USE_DHCP )
& & ic_dhcp_msgtype ! = DHCPACK )
{
ic_got_reply = 0 ;
printk ( " , " ) ;
continue ;
}
# endif /* IPCONFIG_DHCP */
if ( ic_got_reply ) {
printk ( " OK \n " ) ;
break ;
}
if ( ( d = d - > next ) )
continue ;
if ( ! - - retries ) {
printk ( " timed out! \n " ) ;
break ;
}
d = ic_first_dev ;
timeout = timeout CONF_TIMEOUT_MULT ;
if ( timeout > CONF_TIMEOUT_MAX )
timeout = CONF_TIMEOUT_MAX ;
printk ( " . " ) ;
}
# ifdef IPCONFIG_BOOTP
if ( do_bootp )
ic_bootp_cleanup ( ) ;
# endif
# ifdef IPCONFIG_RARP
if ( do_rarp )
ic_rarp_cleanup ( ) ;
# endif
2005-06-29 00:21:12 +04:00
if ( ! ic_got_reply ) {
2006-11-08 11:19:38 +03:00
ic_myaddr = NONE ;
2005-04-17 02:20:36 +04:00
return - 1 ;
2005-06-29 00:21:12 +04:00
}
2005-04-17 02:20:36 +04:00
2008-10-31 10:53:57 +03:00
printk ( " IP-Config: Got %s answer from %pI4, " ,
2007-02-09 17:24:47 +03:00
( ( ic_got_reply & IC_RARP ) ? " RARP "
2005-04-17 02:20:36 +04:00
: ( ic_proto_enabled & IC_USE_DHCP ) ? " DHCP " : " BOOTP " ) ,
2008-10-31 10:53:57 +03:00
& ic_servaddr ) ;
printk ( " my address is %pI4 \n " , & ic_myaddr ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
# endif /* IPCONFIG_DYNAMIC */
# ifdef CONFIG_PROC_FS
static int pnp_seq_show ( struct seq_file * seq , void * v )
{
int i ;
if ( ic_proto_used & IC_PROTO )
seq_printf ( seq , " #PROTO: %s \n " ,
( ic_proto_used & IC_RARP ) ? " RARP "
: ( ic_proto_used & IC_USE_DHCP ) ? " DHCP " : " BOOTP " ) ;
else
seq_puts ( seq , " #MANUAL \n " ) ;
if ( ic_domain [ 0 ] )
seq_printf ( seq ,
" domain %s \n " , ic_domain ) ;
for ( i = 0 ; i < CONF_NAMESERVERS_MAX ; i + + ) {
2006-11-08 11:19:38 +03:00
if ( ic_nameservers [ i ] ! = NONE )
2008-10-31 10:53:57 +03:00
seq_printf ( seq , " nameserver %pI4 \n " ,
& ic_nameservers [ i ] ) ;
2005-04-17 02:20:36 +04:00
}
2006-11-08 11:19:38 +03:00
if ( ic_servaddr ! = NONE )
2008-10-31 10:53:57 +03:00
seq_printf ( seq , " bootserver %pI4 \n " ,
& ic_servaddr ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
static int pnp_seq_open ( struct inode * indoe , struct file * file )
{
return single_open ( file , pnp_seq_show , NULL ) ;
}
2007-02-12 11:55:35 +03:00
static const struct file_operations pnp_seq_fops = {
2005-04-17 02:20:36 +04:00
. owner = THIS_MODULE ,
. open = pnp_seq_open ,
. read = seq_read ,
. llseek = seq_lseek ,
. release = single_release ,
} ;
# endif /* CONFIG_PROC_FS */
/*
* Extract IP address from the parameter string if needed . Note that we
* need to have root_server_addr set _before_ IPConfig gets called as it
* can override it .
*/
2006-11-08 11:19:38 +03:00
__be32 __init root_nfs_parse_addr ( char * name )
2005-04-17 02:20:36 +04:00
{
2006-11-08 11:19:38 +03:00
__be32 addr ;
2005-04-17 02:20:36 +04:00
int octets = 0 ;
char * cp , * cq ;
cp = cq = name ;
while ( octets < 4 ) {
while ( * cp > = ' 0 ' & & * cp < = ' 9 ' )
cp + + ;
if ( cp = = cq | | cp - cq > 3 )
break ;
if ( * cp = = ' . ' | | octets = = 3 )
octets + + ;
if ( octets < 4 )
cp + + ;
cq = cp ;
}
if ( octets = = 4 & & ( * cp = = ' : ' | | * cp = = ' \0 ' ) ) {
if ( * cp = = ' : ' )
* cp + + = ' \0 ' ;
addr = in_aton ( name ) ;
memmove ( name , cp , strlen ( cp ) + 1 ) ;
} else
2006-11-08 11:19:38 +03:00
addr = NONE ;
2005-04-17 02:20:36 +04:00
return addr ;
}
/*
* IP Autoconfig dispatcher .
*/
static int __init ip_auto_config ( void )
{
2006-11-08 11:19:38 +03:00
__be32 addr ;
2009-01-30 03:19:13 +03:00
# ifdef IPCONFIG_DYNAMIC
int retries = CONF_OPEN_RETRIES ;
# endif
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_PROC_FS
2007-09-12 14:01:34 +04:00
proc_net_fops_create ( & init_net , " pnp " , S_IRUGO , & pnp_seq_fops ) ;
2005-04-17 02:20:36 +04:00
# endif /* CONFIG_PROC_FS */
if ( ! ic_enable )
return 0 ;
DBG ( ( " IP-Config: Entered. \n " ) ) ;
# ifdef IPCONFIG_DYNAMIC
try_try_again :
# endif
/* Give hardware a chance to settle */
msleep ( CONF_PRE_OPEN ) ;
/* Setup all network devices */
if ( ic_open_devs ( ) < 0 )
return - 1 ;
/* Give drivers a chance to settle */
ssleep ( CONF_POST_OPEN ) ;
/*
* If the config information is insufficient ( e . g . , our IP address or
* IP address of the boot server is missing or we have multiple network
* interfaces and no default was set ) , use BOOTP or RARP to get the
* missing values .
*/
2006-11-08 11:19:38 +03:00
if ( ic_myaddr = = NONE | |
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_ROOT_NFS
2007-08-11 02:14:54 +04:00
( root_server_addr = = NONE
& & ic_servaddr = = NONE
& & ROOT_DEV = = Root_NFS ) | |
2005-04-17 02:20:36 +04:00
# endif
ic_first_dev - > next ) {
# ifdef IPCONFIG_DYNAMIC
if ( ic_dynamic ( ) < 0 ) {
ic_close_devs ( ) ;
/*
* I don ' t know why , but sometimes the
* eepro100 driver ( at least ) gets upset and
* doesn ' t work the first time it ' s opened .
* But then if you close it and reopen it , it
* works just fine . So we need to try that at
* least once before giving up .
*
* Also , if the root will be NFS - mounted , we
* have nowhere to go if DHCP fails . So we
* just have to keep trying forever .
*
* - - Chip
*/
# ifdef CONFIG_ROOT_NFS
if ( ROOT_DEV = = Root_NFS ) {
2007-02-09 17:24:47 +03:00
printk ( KERN_ERR
2005-04-17 02:20:36 +04:00
" IP-Config: Retrying forever (NFS root)... \n " ) ;
goto try_try_again ;
}
# endif
if ( - - retries ) {
2007-02-09 17:24:47 +03:00
printk ( KERN_ERR
2005-04-17 02:20:36 +04:00
" IP-Config: Reopening network devices... \n " ) ;
goto try_try_again ;
}
/* Oh, well. At least we tried. */
printk ( KERN_ERR " IP-Config: Auto-configuration of network failed. \n " ) ;
return - 1 ;
}
# else /* !DYNAMIC */
printk ( KERN_ERR " IP-Config: Incomplete network configuration information. \n " ) ;
ic_close_devs ( ) ;
return - 1 ;
# endif /* IPCONFIG_DYNAMIC */
} else {
/* Device selected manually or only one device -> use it */
ic_dev = ic_first_dev - > dev ;
}
addr = root_nfs_parse_addr ( root_server_path ) ;
2006-11-08 11:19:38 +03:00
if ( root_server_addr = = NONE )
2005-04-17 02:20:36 +04:00
root_server_addr = addr ;
/*
* Use defaults whereever applicable .
*/
if ( ic_defaults ( ) < 0 )
return - 1 ;
/*
* Close all network devices except the device we ' ve
* autoconfigured and set up routes .
*/
ic_close_devs ( ) ;
if ( ic_setup_if ( ) < 0 | | ic_setup_routes ( ) < 0 )
return - 1 ;
/*
* Record which protocol was actually used .
*/
# ifdef IPCONFIG_DYNAMIC
ic_proto_used = ic_got_reply | ( ic_proto_enabled & IC_USE_DHCP ) ;
# endif
# ifndef IPCONFIG_SILENT
/*
* Clue in the operator .
*/
printk ( " IP-Config: Complete: " ) ;
2008-02-18 09:28:32 +03:00
printk ( " \n device=%s " , ic_dev - > name ) ;
2008-10-31 10:53:57 +03:00
printk ( " , addr=%pI4 " , & ic_myaddr ) ;
printk ( " , mask=%pI4 " , & ic_netmask ) ;
printk ( " , gw=%pI4 " , & ic_gateway ) ;
2005-04-17 02:20:36 +04:00
printk ( " , \n host=%s, domain=%s, nis-domain=%s " ,
2006-10-02 13:18:11 +04:00
utsname ( ) - > nodename , ic_domain , utsname ( ) - > domainname ) ;
2008-10-31 10:53:57 +03:00
printk ( " , \n bootserver=%pI4 " , & ic_servaddr ) ;
printk ( " , rootserver=%pI4 " , & root_server_addr ) ;
2005-04-17 02:20:36 +04:00
printk ( " , rootpath=%s " , root_server_path ) ;
printk ( " \n " ) ;
# endif /* !SILENT */
return 0 ;
}
late_initcall ( ip_auto_config ) ;
/*
* Decode any IP configuration options in the " ip= " or " nfsaddrs= " kernel
2008-04-07 23:59:03 +04:00
* command line parameter . See Documentation / filesystems / nfsroot . txt .
2005-04-17 02:20:36 +04:00
*/
static int __init ic_proto_name ( char * name )
{
if ( ! strcmp ( name , " on " ) | | ! strcmp ( name , " any " ) ) {
return 1 ;
}
2007-12-26 07:54:42 +03:00
if ( ! strcmp ( name , " off " ) | | ! strcmp ( name , " none " ) ) {
2008-01-06 10:23:06 +03:00
return 0 ;
2007-12-26 07:54:42 +03:00
}
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_IP_PNP_DHCP
else if ( ! strcmp ( name , " dhcp " ) ) {
ic_proto_enabled & = ~ IC_RARP ;
return 1 ;
}
# endif
# ifdef CONFIG_IP_PNP_BOOTP
else if ( ! strcmp ( name , " bootp " ) ) {
ic_proto_enabled & = ~ ( IC_RARP | IC_USE_DHCP ) ;
return 1 ;
}
# endif
# ifdef CONFIG_IP_PNP_RARP
else if ( ! strcmp ( name , " rarp " ) ) {
ic_proto_enabled & = ~ ( IC_BOOTP | IC_USE_DHCP ) ;
return 1 ;
}
# endif
# ifdef IPCONFIG_DYNAMIC
else if ( ! strcmp ( name , " both " ) ) {
ic_proto_enabled & = ~ IC_USE_DHCP ; /* backward compat :-( */
return 1 ;
}
# endif
return 0 ;
}
static int __init ip_auto_config_setup ( char * addrs )
{
char * cp , * ip , * dp ;
int num = 0 ;
ic_set_manually = 1 ;
2007-12-28 08:19:10 +03:00
ic_enable = 1 ;
2005-04-17 02:20:36 +04:00
2008-01-06 10:23:06 +03:00
/*
* If any dhcp , bootp etc options are set , leave autoconfig on
* and skip the below static IP processing .
*/
2005-04-17 02:20:36 +04:00
if ( ic_proto_name ( addrs ) )
return 1 ;
2008-01-06 10:23:06 +03:00
/* If no static IP is given, turn off autoconfig and bail. */
if ( * addrs = = 0 | |
strcmp ( addrs , " off " ) = = 0 | |
strcmp ( addrs , " none " ) = = 0 ) {
ic_enable = 0 ;
return 1 ;
}
/* Parse string for static IP assignment. */
2005-04-17 02:20:36 +04:00
ip = addrs ;
while ( ip & & * ip ) {
if ( ( cp = strchr ( ip , ' : ' ) ) )
* cp + + = ' \0 ' ;
if ( strlen ( ip ) > 0 ) {
DBG ( ( " IP-Config: Parameter #%d: `%s' \n " , num , ip ) ) ;
switch ( num ) {
case 0 :
2008-03-18 08:44:53 +03:00
if ( ( ic_myaddr = in_aton ( ip ) ) = = ANY )
2006-11-08 11:19:38 +03:00
ic_myaddr = NONE ;
2005-04-17 02:20:36 +04:00
break ;
case 1 :
2008-03-18 08:44:53 +03:00
if ( ( ic_servaddr = in_aton ( ip ) ) = = ANY )
2006-11-08 11:19:38 +03:00
ic_servaddr = NONE ;
2005-04-17 02:20:36 +04:00
break ;
case 2 :
2008-03-18 08:44:53 +03:00
if ( ( ic_gateway = in_aton ( ip ) ) = = ANY )
2006-11-08 11:19:38 +03:00
ic_gateway = NONE ;
2005-04-17 02:20:36 +04:00
break ;
case 3 :
2008-03-18 08:44:53 +03:00
if ( ( ic_netmask = in_aton ( ip ) ) = = ANY )
2006-11-08 11:19:38 +03:00
ic_netmask = NONE ;
2005-04-17 02:20:36 +04:00
break ;
case 4 :
if ( ( dp = strchr ( ip , ' . ' ) ) ) {
* dp + + = ' \0 ' ;
2006-10-02 13:18:11 +04:00
strlcpy ( utsname ( ) - > domainname , dp ,
sizeof ( utsname ( ) - > domainname ) ) ;
2005-04-17 02:20:36 +04:00
}
2006-10-02 13:18:11 +04:00
strlcpy ( utsname ( ) - > nodename , ip ,
sizeof ( utsname ( ) - > nodename ) ) ;
2005-04-17 02:20:36 +04:00
ic_host_name_set = 1 ;
break ;
case 5 :
strlcpy ( user_dev_name , ip , sizeof ( user_dev_name ) ) ;
break ;
case 6 :
2008-01-06 10:23:06 +03:00
if ( ic_proto_name ( ip ) = = 0 & &
ic_myaddr = = NONE ) {
ic_enable = 0 ;
}
2005-04-17 02:20:36 +04:00
break ;
}
}
ip = cp ;
num + + ;
}
return 1 ;
}
static int __init nfsaddrs_config_setup ( char * addrs )
{
return ip_auto_config_setup ( addrs ) ;
}
2007-11-14 13:18:39 +03:00
static int __init vendor_class_identifier_setup ( char * addrs )
{
if ( strlcpy ( vendor_class_identifier , addrs ,
sizeof ( vendor_class_identifier ) )
> = sizeof ( vendor_class_identifier ) )
printk ( KERN_WARNING " DHCP: vendorclass too long, truncated to \" %s \" " ,
vendor_class_identifier ) ;
return 1 ;
}
2005-04-17 02:20:36 +04:00
__setup ( " ip= " , ip_auto_config_setup ) ;
__setup ( " nfsaddrs= " , nfsaddrs_config_setup ) ;
2007-11-14 13:18:39 +03:00
__setup ( " dhcpclass= " , vendor_class_identifier_setup ) ;