nfs: new subdir Documentation/filesystems/nfs
[safe/jmp/linux-2.6] / net / ipv4 / ipconfig.c
index 420f56a..7dcbf47 100644 (file)
@@ -1,6 +1,4 @@
 /*
- *  $Id: ipconfig.c,v 1.46 2002/02/01 22:01:04 davem Exp $
- *
  *  Automatic Configuration of IP -- use DHCP, BOOTP, RARP, or
  *  user-supplied information to configure own IP address and routes.
  *
 #define CONF_NAMESERVERS_MAX   3       /* Maximum number of nameservers
                                           - '3' from resolv.h */
 
-#define NONE __constant_htonl(INADDR_NONE)
+#define NONE cpu_to_be32(INADDR_NONE)
+#define ANY cpu_to_be32(INADDR_ANY)
 
 /*
  * Public IP configuration
@@ -140,6 +139,11 @@ __be32 ic_servaddr = NONE; /* Boot server IP address */
 __be32 root_server_addr = NONE;        /* Address of NFS server */
 u8 root_server_path[256] = { 0, };     /* Path to mount as root */
 
+u32 ic_dev_xid;                /* Device under configuration */
+
+/* vendor class identifier */
+static char vendor_class_identifier[253] __initdata;
+
 /* Persistent data: */
 
 static int ic_proto_used;                      /* Protocol used, if any */
@@ -156,6 +160,9 @@ static char user_dev_name[IFNAMSIZ] __initdata = { 0, };
 /* Protocols supported by available interfaces */
 static int ic_proto_have_if __initdata = 0;
 
+/* MTU for boot device */
+static int ic_dev_mtu __initdata = 0;
+
 #ifdef IPCONFIG_DYNAMIC
 static DEFINE_SPINLOCK(ic_recv_lock);
 static volatile int ic_got_reply __initdata = 0;    /* Proto(s) that replied */
@@ -282,13 +289,24 @@ set_sockaddr(struct sockaddr_in *sin, __be32 addr, __be16 port)
        sin->sin_port = port;
 }
 
+static int __init ic_devinet_ioctl(unsigned int cmd, struct ifreq *arg)
+{
+       int res;
+
+       mm_segment_t oldfs = get_fs();
+       set_fs(get_ds());
+       res = devinet_ioctl(&init_net, cmd, (struct ifreq __user *) arg);
+       set_fs(oldfs);
+       return res;
+}
+
 static int __init ic_dev_ioctl(unsigned int cmd, struct ifreq *arg)
 {
        int res;
 
        mm_segment_t oldfs = get_fs();
        set_fs(get_ds());
-       res = devinet_ioctl(cmd, (struct ifreq __user *) arg);
+       res = dev_ioctl(&init_net, cmd, (struct ifreq __user *) arg);
        set_fs(oldfs);
        return res;
 }
@@ -299,7 +317,7 @@ static int __init ic_route_ioctl(unsigned int cmd, struct rtentry *arg)
 
        mm_segment_t oldfs = get_fs();
        set_fs(get_ds());
-       res = ip_rt_ioctl(cmd, (void __user *) arg);
+       res = ip_rt_ioctl(&init_net, cmd, (void __user *) arg);
        set_fs(oldfs);
        return res;
 }
@@ -317,20 +335,31 @@ static int __init ic_setup_if(void)
        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) {
+       if ((err = ic_devinet_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) {
+       if ((err = ic_devinet_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) {
+       if ((err = ic_devinet_ioctl(SIOCSIFBRDADDR, &ir)) < 0) {
                printk(KERN_ERR "IP-Config: Unable to set interface broadcast address (%d).\n", err);
                return -1;
        }
+       /* Handle the case where we need non-standard MTU on the boot link (a network
+        * using jumbo frames, for instance).  If we can't set the mtu, don't error
+        * out, we'll try to muddle along.
+        */
+       if (ic_dev_mtu != 0) {
+               strcpy(ir.ifr_name, ic_dev->name);
+               ir.ifr_mtu = ic_dev_mtu;
+               if ((err = ic_dev_ioctl(SIOCSIFMTU, &ir)) < 0)
+                       printk(KERN_ERR "IP-Config: Unable to set interface mtu to %d (%d).\n",
+                                        ic_dev_mtu, err);
+       }
        return 0;
 }
 
@@ -372,7 +401,7 @@ static int __init ic_defaults(void)
         */
 
        if (!ic_host_name_set)
-               sprintf(init_utsname()->nodename, "%u.%u.%u.%u", NIPQUAD(ic_myaddr));
+               sprintf(init_utsname()->nodename, "%pI4", &ic_myaddr);
 
        if (root_server_addr == NONE)
                root_server_addr = ic_servaddr;
@@ -385,11 +414,11 @@ static int __init ic_defaults(void)
                else if (IN_CLASSC(ntohl(ic_myaddr)))
                        ic_netmask = htonl(IN_CLASSC_NET);
                else {
-                       printk(KERN_ERR "IP-Config: Unable to guess netmask for address %u.%u.%u.%u\n",
-                               NIPQUAD(ic_myaddr));
+                       printk(KERN_ERR "IP-Config: Unable to guess netmask for address %pI4\n",
+                               &ic_myaddr);
                        return -1;
                }
-               printk("IP-Config: Guessing netmask %u.%u.%u.%u\n", NIPQUAD(ic_netmask));
+               printk("IP-Config: Guessing netmask %pI4\n", &ic_netmask);
        }
 
        return 0;
@@ -404,16 +433,16 @@ static int __init ic_defaults(void)
 static int ic_rarp_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev);
 
 static struct packet_type rarp_packet_type __initdata = {
-       .type = __constant_htons(ETH_P_RARP),
+       .type = cpu_to_be16(ETH_P_RARP),
        .func = ic_rarp_recv,
 };
 
-static inline void ic_rarp_init(void)
+static inline void __init ic_rarp_init(void)
 {
        dev_add_pack(&rarp_packet_type);
 }
 
-static inline void ic_rarp_cleanup(void)
+static inline void __init ic_rarp_cleanup(void)
 {
        dev_remove_pack(&rarp_packet_type);
 }
@@ -430,7 +459,7 @@ ic_rarp_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt
        unsigned char *sha, *tha;               /* s for "source", t for "target" */
        struct ic_device *d;
 
-       if (dev->nd_net != &init_net)
+       if (!net_eq(dev_net(dev), &init_net))
                goto drop;
 
        if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL)
@@ -456,10 +485,7 @@ ic_rarp_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt
        if (rarp->ar_pro != htons(ETH_P_IP))
                goto drop;
 
-       if (!pskb_may_pull(skb,
-                          sizeof(struct arphdr) +
-                          (2 * dev->addr_len) +
-                          (2 * 4)))
+       if (!pskb_may_pull(skb, arp_hdr_len(dev)))
                goto drop;
 
        /* OK, it is all there and looks valid, process... */
@@ -569,7 +595,7 @@ struct bootp_pkt {          /* BOOTP packet format */
 static int ic_bootp_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev);
 
 static struct packet_type bootp_packet_type __initdata = {
-       .type = __constant_htons(ETH_P_IP),
+       .type = cpu_to_be16(ETH_P_IP),
        .func = ic_bootp_recv,
 };
 
@@ -588,6 +614,7 @@ ic_dhcp_init_options(u8 *options)
        u8 mt = ((ic_servaddr == NONE)
                 ? DHCPDISCOVER : DHCPREQUEST);
        u8 *e = options;
+       int len;
 
 #ifdef IPCONFIG_DEBUG
        printk("DHCP: Sending message type %d\n", mt);
@@ -621,6 +648,7 @@ ic_dhcp_init_options(u8 *options)
                        12,     /* Host name */
                        15,     /* Domain name */
                        17,     /* Boot path */
+                       26,     /* MTU */
                        40,     /* NIS domain name */
                };
 
@@ -628,6 +656,16 @@ ic_dhcp_init_options(u8 *options)
                *e++ = sizeof(ic_req_params);
                memcpy(e, ic_req_params, sizeof(ic_req_params));
                e += sizeof(ic_req_params);
+
+               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;
+               }
        }
 
        *e++ = 255;     /* End of the list */
@@ -670,7 +708,7 @@ static void __init ic_bootp_init_ext(u8 *e)
 /*
  *  Initialize the DHCP/BOOTP mechanism.
  */
-static inline void ic_bootp_init(void)
+static inline void __init ic_bootp_init(void)
 {
        int i;
 
@@ -684,7 +722,7 @@ static inline void ic_bootp_init(void)
 /*
  *  DHCP/BOOTP cleanup.
  */
-static inline void ic_bootp_cleanup(void)
+static inline void __init ic_bootp_cleanup(void)
 {
        dev_remove_pack(&bootp_packet_type);
 }
@@ -698,14 +736,14 @@ static void __init ic_bootp_send_if(struct ic_device *d, unsigned long jiffies_d
        struct net_device *dev = d->dev;
        struct sk_buff *skb;
        struct bootp_pkt *b;
-       int hh_len = LL_RESERVED_SPACE(dev);
        struct iphdr *h;
 
        /* Allocate packet */
-       skb = alloc_skb(sizeof(struct bootp_pkt) + hh_len + 15, GFP_KERNEL);
+       skb = alloc_skb(sizeof(struct bootp_pkt) + LL_ALLOCATED_SPACE(dev) + 15,
+                       GFP_KERNEL);
        if (!skb)
                return;
-       skb_reserve(skb, hh_len);
+       skb_reserve(skb, LL_RESERVED_SPACE(dev));
        b = (struct bootp_pkt *) skb_put(skb, sizeof(struct bootp_pkt));
        memset(b, 0, sizeof(struct bootp_pkt));
 
@@ -739,9 +777,9 @@ static void __init ic_bootp_send_if(struct ic_device *d, unsigned long jiffies_d
                printk("Unknown ARP type 0x%04x for device %s\n", dev->type, dev->name);
                b->htype = dev->type; /* can cause undefined behavior */
        }
+
+       /* server_ip and your_ip address are both already zero per RFC2131 */
        b->hlen = dev->addr_len;
-       b->your_ip = NONE;
-       b->server_ip = NONE;
        memcpy(b->hw_addr, dev->dev_addr, dev->addr_len);
        b->secs = htons(jiffies_diff / HZ);
        b->xid = d->xid;
@@ -786,6 +824,7 @@ static void __init ic_do_bootp_ext(u8 *ext)
 {
        u8 servers;
        int i;
+       u16 mtu;
 
 #ifdef IPCONFIG_DEBUG
        u8 *c;
@@ -825,6 +864,10 @@ static void __init ic_do_bootp_ext(u8 *ext)
                        if (!root_server_path[0])
                                ic_bootp_string(root_server_path, ext+1, *ext, sizeof(root_server_path));
                        break;
+               case 26:        /* Interface MTU */
+                       memcpy(&mtu, ext+1, sizeof(mtu));
+                       ic_dev_mtu = ntohs(mtu);
+                       break;
                case 40:        /* NIS Domain name (_not_ DNS) */
                        ic_bootp_string(utsname()->domainname, ext+1, *ext, __NEW_UTS_LEN);
                        break;
@@ -842,7 +885,7 @@ static int __init ic_bootp_recv(struct sk_buff *skb, struct net_device *dev, str
        struct ic_device *d;
        int len, ext_len;
 
-       if (dev->nd_net != &init_net)
+       if (!net_eq(dev_net(dev), &init_net))
                goto drop;
 
        /* Perform verifications before taking the lock.  */
@@ -922,6 +965,13 @@ static int __init ic_bootp_recv(struct sk_buff *skb, struct net_device *dev, str
                goto drop_unlock;
        }
 
+       /* Is it a reply for the device we are configuring? */
+       if (b->xid != ic_dev_xid) {
+               if (net_ratelimit())
+                       printk(KERN_ERR "DHCP/BOOTP: Ignoring delayed packet \n");
+               goto drop_unlock;
+       }
+
        /* Parse extensions */
        if (ext_len >= 4 &&
            !memcmp(b->exten, ic_bootp_cookie, 4)) { /* Check magic cookie */
@@ -969,10 +1019,8 @@ static int __init ic_bootp_recv(struct sk_buff *skb, struct net_device *dev, str
                                ic_myaddr = b->your_ip;
                                ic_servaddr = server_id;
 #ifdef IPCONFIG_DEBUG
-                               printk("DHCP: Offered address %u.%u.%u.%u",
-                                      NIPQUAD(ic_myaddr));
-                               printk(" by server %u.%u.%u.%u\n",
-                                      NIPQUAD(ic_servaddr));
+                               printk("DHCP: Offered address %pI4 by server %pI4\n",
+                                      &ic_myaddr, &ic_servaddr);
 #endif
                                /* The DHCP indicated server address takes
                                 * precedence over the bootp header one if
@@ -1107,6 +1155,9 @@ static int __init ic_dynamic(void)
        get_random_bytes(&timeout, sizeof(timeout));
        timeout = CONF_BASE_TIMEOUT + (timeout % (unsigned) CONF_TIMEOUT_RANDOM);
        for (;;) {
+               /* Track the device we are configuring */
+               ic_dev_xid = d->xid;
+
 #ifdef IPCONFIG_BOOTP
                if (do_bootp && (d->able & IC_BOOTP))
                        ic_bootp_send_if(d, jiffies - start_jiffies);
@@ -1167,11 +1218,11 @@ static int __init ic_dynamic(void)
                return -1;
        }
 
-       printk("IP-Config: Got %s answer from %u.%u.%u.%u, ",
+       printk("IP-Config: Got %s answer from %pI4, ",
                ((ic_got_reply & IC_RARP) ? "RARP"
                 : (ic_proto_enabled & IC_USE_DHCP) ? "DHCP" : "BOOTP"),
-               NIPQUAD(ic_servaddr));
-       printk("my address is %u.%u.%u.%u\n", NIPQUAD(ic_myaddr));
+               &ic_servaddr);
+       printk("my address is %pI4\n", &ic_myaddr);
 
        return 0;
 }
@@ -1196,14 +1247,12 @@ static int pnp_seq_show(struct seq_file *seq, void *v)
                           "domain %s\n", ic_domain);
        for (i = 0; i < CONF_NAMESERVERS_MAX; i++) {
                if (ic_nameservers[i] != NONE)
-                       seq_printf(seq,
-                                  "nameserver %u.%u.%u.%u\n",
-                                  NIPQUAD(ic_nameservers[i]));
+                       seq_printf(seq, "nameserver %pI4\n",
+                                  &ic_nameservers[i]);
        }
        if (ic_servaddr != NONE)
-               seq_printf(seq,
-                          "bootserver %u.%u.%u.%u\n",
-                          NIPQUAD(ic_servaddr));
+               seq_printf(seq, "bootserver %pI4\n",
+                          &ic_servaddr);
        return 0;
 }
 
@@ -1262,6 +1311,9 @@ __be32 __init root_nfs_parse_addr(char *name)
 static int __init ip_auto_config(void)
 {
        __be32 addr;
+#ifdef IPCONFIG_DYNAMIC
+       int retries = CONF_OPEN_RETRIES;
+#endif
 
 #ifdef CONFIG_PROC_FS
        proc_net_fops_create(&init_net, "pnp", S_IRUGO, &pnp_seq_fops);
@@ -1298,9 +1350,6 @@ static int __init ip_auto_config(void)
 #endif
            ic_first_dev->next) {
 #ifdef IPCONFIG_DYNAMIC
-
-               int retries = CONF_OPEN_RETRIES;
-
                if (ic_dynamic() < 0) {
                        ic_close_devs();
 
@@ -1376,15 +1425,17 @@ static int __init ip_auto_config(void)
         * Clue in the operator.
         */
        printk("IP-Config: Complete:");
-       printk("\n      device=%s", ic_dev->name);
-       printk(", addr=%u.%u.%u.%u", NIPQUAD(ic_myaddr));
-       printk(", mask=%u.%u.%u.%u", NIPQUAD(ic_netmask));
-       printk(", gw=%u.%u.%u.%u", NIPQUAD(ic_gateway));
+       printk("\n     device=%s", ic_dev->name);
+       printk(", addr=%pI4", &ic_myaddr);
+       printk(", mask=%pI4", &ic_netmask);
+       printk(", gw=%pI4", &ic_gateway);
        printk(",\n     host=%s, domain=%s, nis-domain=%s",
               utsname()->nodename, ic_domain, utsname()->domainname);
-       printk(",\n     bootserver=%u.%u.%u.%u", NIPQUAD(ic_servaddr));
-       printk(", rootserver=%u.%u.%u.%u", NIPQUAD(root_server_addr));
+       printk(",\n     bootserver=%pI4", &ic_servaddr);
+       printk(", rootserver=%pI4", &root_server_addr);
        printk(", rootpath=%s", root_server_path);
+       if (ic_dev_mtu)
+               printk(", mtu=%d", ic_dev_mtu);
        printk("\n");
 #endif /* !SILENT */
 
@@ -1396,7 +1447,7 @@ late_initcall(ip_auto_config);
 
 /*
  *  Decode any IP configuration options in the "ip=" or "nfsaddrs=" kernel
- *  command line parameter.  See Documentation/nfsroot.txt.
+ *  command line parameter.  See Documentation/filesystems/nfs/nfsroot.txt.
  */
 static int __init ic_proto_name(char *name)
 {
@@ -1404,8 +1455,7 @@ static int __init ic_proto_name(char *name)
                return 1;
        }
        if (!strcmp(name, "off") || !strcmp(name, "none")) {
-               ic_enable = 0;
-               return 1;
+               return 0;
        }
 #ifdef CONFIG_IP_PNP_DHCP
        else if (!strcmp(name, "dhcp")) {
@@ -1440,11 +1490,24 @@ static int __init ip_auto_config_setup(char *addrs)
        int num = 0;
 
        ic_set_manually = 1;
+       ic_enable = 1;
 
+       /*
+        * If any dhcp, bootp etc options are set, leave autoconfig on
+        * and skip the below static IP processing.
+        */
        if (ic_proto_name(addrs))
                return 1;
 
-       /* Parse the whole string */
+       /* 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.  */
        ip = addrs;
        while (ip && *ip) {
                if ((cp = strchr(ip, ':')))
@@ -1453,19 +1516,19 @@ static int __init ip_auto_config_setup(char *addrs)
                        DBG(("IP-Config: Parameter #%d: `%s'\n", num, ip));
                        switch (num) {
                        case 0:
-                               if ((ic_myaddr = in_aton(ip)) == INADDR_ANY)
+                               if ((ic_myaddr = in_aton(ip)) == ANY)
                                        ic_myaddr = NONE;
                                break;
                        case 1:
-                               if ((ic_servaddr = in_aton(ip)) == INADDR_ANY)
+                               if ((ic_servaddr = in_aton(ip)) == ANY)
                                        ic_servaddr = NONE;
                                break;
                        case 2:
-                               if ((ic_gateway = in_aton(ip)) == INADDR_ANY)
+                               if ((ic_gateway = in_aton(ip)) == ANY)
                                        ic_gateway = NONE;
                                break;
                        case 3:
-                               if ((ic_netmask = in_aton(ip)) == INADDR_ANY)
+                               if ((ic_netmask = in_aton(ip)) == ANY)
                                        ic_netmask = NONE;
                                break;
                        case 4:
@@ -1482,7 +1545,10 @@ static int __init ip_auto_config_setup(char *addrs)
                                strlcpy(user_dev_name, ip, sizeof(user_dev_name));
                                break;
                        case 6:
-                               ic_proto_name(ip);
+                               if (ic_proto_name(ip) == 0 &&
+                                   ic_myaddr == NONE) {
+                                       ic_enable = 0;
+                               }
                                break;
                        }
                }
@@ -1498,5 +1564,16 @@ static int __init nfsaddrs_config_setup(char *addrs)
        return ip_auto_config_setup(addrs);
 }
 
+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;
+}
+
 __setup("ip=", ip_auto_config_setup);
 __setup("nfsaddrs=", nfsaddrs_config_setup);
+__setup("dhcpclass=", vendor_class_identifier_setup);