patch-2.2.0-pre5 linux/net/ipv4/ipconfig.c

Next file: linux/net/ipv4/route.c
Previous file: linux/net/ipv4/ip_output.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.2.0-pre4/linux/net/ipv4/ipconfig.c linux/net/ipv4/ipconfig.c
@@ -1,13 +1,17 @@
 /*
- *  $Id: ipconfig.c,v 1.16 1998/10/21 22:27:26 davem Exp $
+ *  $Id: ipconfig.c,v 1.18 1999/01/04 20:14:10 davem Exp $
  *
  *  Automatic Configuration of IP -- use BOOTP or RARP or user-supplied
  *  information to configure own IP address and routes.
  *
- *  Copyright (C) 1996, 1997 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
+ *  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
  */
 
 #include <linux/config.h>
@@ -21,22 +25,20 @@
 #include <linux/in.h>
 #include <linux/if.h>
 #include <linux/inet.h>
-#include <linux/net.h>
 #include <linux/netdevice.h>
 #include <linux/if_arp.h>
 #include <linux/skbuff.h>
 #include <linux/ip.h>
 #include <linux/socket.h>
-#include <linux/inetdevice.h>
 #include <linux/route.h>
-#include <net/route.h>
-#include <net/sock.h>
+#include <linux/udp.h>
 #include <net/arp.h>
-#include <net/ip_fib.h>
+#include <net/ip.h>
 #include <net/ipconfig.h>
 
 #include <asm/segment.h>
 #include <asm/uaccess.h>
+#include <asm/checksum.h>
 
 /* Define this to allow debugging output */
 #undef IPCONFIG_DEBUG
@@ -60,8 +62,6 @@
 u32 ic_servaddr __initdata = INADDR_NONE;	/* Server IP address */
 u32 ic_gateway __initdata = INADDR_NONE;	/* Gateway IP address */
 u32 ic_netmask __initdata = INADDR_NONE;	/* Netmask for local subnet */
-int ic_bootp_flag __initdata = 1;		/* Use BOOTP */
-int ic_rarp_flag __initdata = 1;		/* Use RARP */
 int ic_enable __initdata = 1;			/* Automatic IP configuration enabled */
 int ic_host_name_set __initdata = 0;		/* Host name configured manually */
 int ic_set_manually __initdata = 0;		/* IPconfig parameters set manually */
@@ -73,13 +73,17 @@
 
 #define CONFIG_IP_PNP_DYNAMIC
 
-static int ic_got_reply __initdata = 0;
+static int ic_proto_enabled __initdata = IC_BOOTP | IC_RARP;	/* Protocols enabled */
+static int ic_got_reply __initdata = 0;				/* Protocol(s) we got reply from */
+
+#else
 
-#define IC_GOT_BOOTP 1
-#define IC_GOT_RARP 2
+static int ic_proto_enabled __initdata = 0;
 
 #endif
 
+static int ic_proto_have_if __initdata = 0;
+
 /*
  *	Network devices
  */
@@ -88,14 +92,13 @@
 	struct ic_device *next;
 	struct device *dev;
 	unsigned short flags;
+	int able;
 };
 
 static struct ic_device *ic_first_dev __initdata = NULL;/* List of open device */
 static struct device *ic_dev __initdata = NULL;		/* Selected device */
-static int bootp_dev_count __initdata = 0;		/* BOOTP capable devices */
-static int rarp_dev_count __initdata = 0;		/* RARP capable devices */
 
-__initfunc(int ic_open_devs(void))
+static int __init ic_open_devs(void)
 {
 	struct ic_device *d, **last;
 	struct device *dev;
@@ -103,10 +106,20 @@
 
 	last = &ic_first_dev;
 	for (dev = dev_base; dev; dev = dev->next)
-		if (dev->type < ARPHRD_SLIP &&
-		    !(dev->flags & (IFF_LOOPBACK | IFF_POINTOPOINT)) &&
-		    strncmp(dev->name, "dummy", 5) &&
-		    (!user_dev_name[0] || !strcmp(dev->name, user_dev_name))) {
+		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 "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);
@@ -118,14 +131,13 @@
 			*last = d;
 			last = &d->next;
 			d->flags = oflags;
-			bootp_dev_count++;
-			if (!(dev->flags & IFF_NOARP))
-				rarp_dev_count++;
-			DBG(("IP-Config: Opened %s\n", dev->name));
+			d->able = able;
+			ic_proto_have_if |= able;
+			DBG(("IP-Config: Opened %s (able=%d)\n", dev->name, able));
 		}
 	*last = NULL;
 
-	if (!bootp_dev_count) {
+	if (!ic_first_dev) {
 		if (user_dev_name[0])
 			printk(KERN_ERR "IP-Config: Device `%s' not found.\n", user_dev_name);
 		else
@@ -135,7 +147,7 @@
 	return 0;
 }
 
-__initfunc(void ic_close_devs(void))
+static void __init ic_close_devs(void)
 {
 	struct ic_device *d, *next;
 	struct device *dev;
@@ -164,7 +176,7 @@
 	sin->sin_port = port;
 }
 
-__initfunc(static int ic_dev_ioctl(unsigned int cmd, struct ifreq *arg))
+static int __init ic_dev_ioctl(unsigned int cmd, struct ifreq *arg)
 {
 	int res;
 
@@ -175,7 +187,7 @@
 	return res;
 }
 
-__initfunc(static int ic_route_ioctl(unsigned int cmd, struct rtentry *arg))
+static int __init ic_route_ioctl(unsigned int cmd, struct rtentry *arg)
 {
 	int res;
 
@@ -190,7 +202,7 @@
  *	Set up interface addresses and routes.
  */
 
-__initfunc(static int ic_setup_if(void))
+static int __init ic_setup_if(void)
 {
 	struct ifreq ir;
 	struct sockaddr_in *sin = (void *) &ir.ifr_ifru.ifru_addr;
@@ -216,7 +228,7 @@
 	return 0;
 }
 
-__initfunc(int ic_setup_routes(void))
+static int __init ic_setup_routes(void)
 {
 	/* No need to setup device routes, only the default route... */
 
@@ -246,7 +258,7 @@
  *	Fill in default values for all missing parameters.
  */
 
-__initfunc(int ic_defaults(void))
+static int __init ic_defaults(void)
 {
 	/*
 	 *	At this point we have no userspace running so need not
@@ -270,6 +282,7 @@
 			printk(KERN_ERR "IP-Config: Unable to guess netmask for address %08x\n", ic_myaddr);
 			return -1;
 		}
+		printk("IP-Config: Guessing netmask %s\n", in_ntoa(ic_netmask));
 	}
 
 	return 0;
@@ -281,25 +294,22 @@
 
 #ifdef CONFIG_IP_PNP_RARP
 
-static int ic_rarp_recv(struct sk_buff *skb, struct device *dev,
-			struct packet_type *pt);
+static int ic_rarp_recv(struct sk_buff *skb, struct device *dev, struct packet_type *pt);
 
 static struct packet_type rarp_packet_type __initdata = {
-	0,			/* Should be: __constant_htons(ETH_P_RARP)
-				 * - but this _doesn't_ come out constant! */
+	__constant_htons(ETH_P_RARP),
 	NULL,			/* Listen to all devices */
 	ic_rarp_recv,
 	NULL,
 	NULL
 };
 
-__initfunc(static void ic_rarp_init(void))
+static inline void ic_rarp_init(void)
 {
-	rarp_packet_type.type = htons(ETH_P_RARP);
 	dev_add_pack(&rarp_packet_type);
 }
 
-__initfunc(static void ic_rarp_cleanup(void))
+static inline void ic_rarp_cleanup(void)
 {
 	dev_remove_pack(&rarp_packet_type);
 }
@@ -307,14 +317,18 @@
 /*
  *  Process received RARP packet.
  */
-__initfunc(static int
-ic_rarp_recv(struct sk_buff *skb, struct device *dev, struct packet_type *pt))
+static int __init
+ic_rarp_recv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
 {
 	struct arphdr *rarp = (struct arphdr *)skb->h.raw;
 	unsigned char *rarp_ptr = (unsigned char *) (rarp + 1);
 	unsigned long sip, tip;
 	unsigned char *sha, *tha;		/* s for "source", t for "target" */
 
+	/* If we already have a reply, just drop the packet */
+	if (ic_got_reply)
+		goto drop;
+
 	/* 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;
@@ -346,7 +360,7 @@
 
 	/* Victory! The packet is what we were looking for! */
 	if (!ic_got_reply) {
-		ic_got_reply = IC_GOT_RARP;
+		ic_got_reply = IC_RARP;
 		ic_dev = dev;
 		if (ic_myaddr == INADDR_NONE)
 			ic_myaddr = tip;
@@ -363,16 +377,16 @@
 /*
  *  Send RARP request packet over all devices which allow RARP.
  */
-__initfunc(static void ic_rarp_send(void))
+static void __init ic_rarp_send(void)
 {
 	struct ic_device *d;
 
-	for (d=ic_first_dev; d; d=d->next) {
-		struct device *dev = d->dev;
-		if (!(dev->flags & IFF_NOARP))
+	for (d=ic_first_dev; d; d=d->next)
+		if (d->able & IC_RARP) {
+			struct device *dev = d->dev;
 			arp_send(ARPOP_RREQUEST, ETH_P_RARP, 0, dev, 0, NULL,
 				 dev->dev_addr, dev->dev_addr);
-	}
+		}
 }
 
 #endif
@@ -383,10 +397,9 @@
 
 #ifdef CONFIG_IP_PNP_BOOTP
 
-static struct socket *ic_bootp_xmit_sock __initdata = NULL; /* BOOTP send socket */
-static struct socket *ic_bootp_recv_sock __initdata = NULL; /* BOOTP receive socket */
-
 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 */
@@ -407,150 +420,23 @@
 #define BOOTP_REQUEST 1
 #define BOOTP_REPLY 2
 
-static struct bootp_pkt *ic_xmit_bootp __initdata = NULL; /* Packet being transmitted */
-static struct bootp_pkt *ic_recv_bootp __initdata = NULL; /* Packet being received */
-
-/*
- *  Allocation and freeing of BOOTP packet buffers.
- */
-__initfunc(static int ic_bootp_alloc(void))
-{
-	if (!(ic_xmit_bootp = kmalloc(sizeof(struct bootp_pkt), GFP_KERNEL)) ||
-	    !(ic_recv_bootp = kmalloc(sizeof(struct bootp_pkt), GFP_KERNEL))) {
-		printk(KERN_ERR "BOOTP: Out of memory!\n");
-		return -1;
-	}
-	return 0;
-}
-
-__initfunc(static void ic_bootp_free(void))
-{
-	if (ic_xmit_bootp) {
-		kfree_s(ic_xmit_bootp, sizeof(struct bootp_pkt));
-		ic_xmit_bootp = NULL;
-	}
-	if (ic_recv_bootp) {
-		kfree_s(ic_recv_bootp, sizeof(struct bootp_pkt));
-		ic_recv_bootp = NULL;
-	}
-}
-
-
-/*
- *  Add / Remove fake interface addresses for BOOTP packet sending.
- */
-__initfunc(static int ic_bootp_addrs_add(void))
-{
-	struct ic_device *d;
-	int err;
-
-	for(d=ic_first_dev; d; d=d->next)
-		if ((err = inet_add_bootp_addr(d->dev)) < 0) {
-			printk(KERN_ERR "BOOTP: Unable to set interface address\n");
-			return -1;
-		}
-	return 0;
-}
-
-__initfunc(static void ic_bootp_addrs_del(void))
-{
-	struct ic_device *d;
-
-	for(d=ic_first_dev; d; d=d->next)
-		inet_del_bootp_addr(d->dev);
-}
-
-/*
- *  UDP socket operations.
- */
-__initfunc(static int ic_udp_open(struct socket **sock))
-{
-	int err;
-
-	if ((err = sock_create(PF_INET, SOCK_DGRAM, IPPROTO_UDP, sock)) < 0)
-		printk(KERN_ERR "BOOTP: Cannot open UDP socket!\n");
-	return err;
-}
-
-static inline void ic_udp_close(struct socket *sock)
-{
-	if (sock)
-		sock_release(sock);
-}
-
-__initfunc(static int ic_udp_connect(struct socket *sock, u32 addr, u16 port))
-{
-	struct sockaddr_in sa;
-	int err;
-
-	set_sockaddr(&sa, htonl(addr), htons(port));
-	err = sock->ops->connect(sock, (struct sockaddr *) &sa, sizeof(sa), 0);
-	if (err < 0) {
-		printk(KERN_ERR "BOOTP: connect() failed (%d)\n", err);
-		return -1;
-	}
-	return 0;
-}
-
-__initfunc(static int ic_udp_bind(struct socket *sock, u32 addr, u16 port))
-{
-	struct sockaddr_in sa;
-	int err;
-
-	set_sockaddr(&sa, htonl(addr), htons(port));
-	err = sock->ops->bind(sock, (struct sockaddr *) &sa, sizeof(sa));
-	if (err < 0) {
-		printk(KERN_ERR "BOOTP: bind() failed (%d)\n", err);
-		return -1;
-	}
-	return 0;
-}
-
-__initfunc(static int ic_udp_send(struct socket *sock, void *buf, int size))
-{
-	mm_segment_t oldfs;
-	int result;
-	struct msghdr msg;
-	struct iovec iov;
-
-	oldfs = get_fs();
-	set_fs(get_ds());
-	iov.iov_base = buf;
-	iov.iov_len = size;
-	memset(&msg, 0, sizeof(msg));
-	msg.msg_iov = &iov;
-	msg.msg_iovlen = 1;
-	result = sock_sendmsg(sock, &msg, size);
-	set_fs(oldfs);
-
-	return (result != size);
-}
+static u32 ic_bootp_xid;
 
-__initfunc(static int ic_udp_recv(struct socket *sock, void *buf, int size))
-{
-	mm_segment_t oldfs;
-	int result;
-	struct msghdr msg;
-	struct iovec iov;
+static int ic_bootp_recv(struct sk_buff *skb, struct device *dev, struct packet_type *pt);
 
-	oldfs = get_fs();
-	set_fs(get_ds());
-	iov.iov_base = buf;
-	iov.iov_len = size;
-	memset(&msg, 0, sizeof(msg));
-	msg.msg_flags = MSG_DONTWAIT;
-	msg.msg_iov = &iov;
-	msg.msg_iovlen = 1;
-	result = sock_recvmsg(sock, &msg, size, MSG_DONTWAIT);
-	set_fs(oldfs);
-	return result;
-}
+static struct packet_type bootp_packet_type __initdata = {
+	__constant_htons(ETH_P_IP),
+	NULL,			/* Listen to all devices */
+	ic_bootp_recv,
+	NULL,
+	NULL
+};
 
 
 /*
  *  Initialize BOOTP extension fields in the request.
  */
-__initfunc(static void ic_bootp_init_ext(u8 *e))
+static void __init ic_bootp_init_ext(u8 *e)
 {
 	*e++ = 99;		/* RFC1048 Magic Cookie */
 	*e++ = 130;
@@ -578,92 +464,96 @@
 /*
  *  Initialize the BOOTP mechanism.
  */
-__initfunc(static int ic_bootp_init(void))
+static inline void ic_bootp_init(void)
 {
-	/* Allocate memory for BOOTP packets */
-	if (ic_bootp_alloc() < 0)
-		return -1;
-
-	/* Add fake zero addresses to all interfaces */
-	if (ic_bootp_addrs_add() < 0)
-		return -1;
-	
-	/* Setting the addresses automatically creates appropriate
-	   routes. */	
-
-	/* Initialize common portion of BOOTP request */
-	memset(ic_xmit_bootp, 0, sizeof(struct bootp_pkt));
-	ic_xmit_bootp->op = BOOTP_REQUEST;
-	get_random_bytes(&ic_xmit_bootp->xid, sizeof(ic_xmit_bootp->xid));
-	ic_bootp_init_ext(ic_xmit_bootp->vendor_area);
-
-	DBG(("BOOTP: XID=%08x\n", ic_xmit_bootp->xid));
-
-	/* Open the sockets */
-	if (ic_udp_open(&ic_bootp_xmit_sock) ||
-	    ic_udp_open(&ic_bootp_recv_sock))
-		return -1;
-
-	/* Bind/connect the sockets */
-	ic_bootp_xmit_sock->sk->broadcast = 1;
-	ic_bootp_xmit_sock->sk->reuse = 1;
-	ic_bootp_recv_sock->sk->reuse = 1;
-	if (ic_udp_bind(ic_bootp_recv_sock, INADDR_ANY, 68) ||
-	    ic_udp_bind(ic_bootp_xmit_sock, INADDR_ANY, 68) ||
-	    ic_udp_connect(ic_bootp_xmit_sock, INADDR_BROADCAST, 67))
-		return -1;
-
-	return 0;
+	get_random_bytes(&ic_bootp_xid, sizeof(u32));
+	DBG(("BOOTP: XID=%08x\n", ic_bootp_xid));
+	dev_add_pack(&bootp_packet_type);
 }
 
 
 /*
  *  BOOTP cleanup.
  */
-__initfunc(static void ic_bootp_cleanup(void))
+static inline void ic_bootp_cleanup(void)
 {
-	ic_udp_close(ic_bootp_xmit_sock);
-	ic_udp_close(ic_bootp_recv_sock);
-	ic_bootp_addrs_del();
-	ic_bootp_free();
+	dev_remove_pack(&bootp_packet_type);
 }
 
 
 /*
  *  Send BOOTP request to single interface.
  */
-__initfunc(static int ic_bootp_send_if(struct ic_device *d, u32 jiffies))
+static void __init ic_bootp_send_if(struct ic_device *d, u32 jiffies)
 {
 	struct device *dev = d->dev;
-	struct bootp_pkt *b = ic_xmit_bootp;
+	struct sk_buff *skb;
+	struct bootp_pkt *b;
+	int hh_len = (dev->hard_header_len + 15) & ~15;
+	struct iphdr *h;
+
+	/* Allocate packet */
+	skb = alloc_skb(sizeof(struct bootp_pkt) + hh_len + 15, GFP_KERNEL);
+	if (!skb)
+		return;
+	skb_reserve(skb, hh_len);
+	b = (struct bootp_pkt *) skb_put(skb, sizeof(struct bootp_pkt));
+	memset(b, 0, sizeof(struct bootp_pkt));
+
+	/* Construct IP header */
+	skb->nh.iph = h = &b->iph;
+	h->version = 4;
+	h->ihl = 5;
+	h->tot_len = htons(sizeof(struct bootp_pkt));
+	h->frag_off = htons(IP_DF);
+	h->ttl = 1;
+	h->protocol = IPPROTO_UDP;
+	h->daddr = INADDR_BROADCAST;
+	h->check = 0;
+	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 BOOTP header */
+	b->op = BOOTP_REQUEST;
 	b->htype = dev->type;
 	b->hlen = dev->addr_len;
-	memset(b->hw_addr, 0, sizeof(b->hw_addr));
 	memcpy(b->hw_addr, dev->dev_addr, dev->addr_len);
 	b->secs = htons(jiffies / HZ);
-	return ic_udp_send(ic_bootp_xmit_sock, b, sizeof(struct bootp_pkt));
+	b->xid = ic_bootp_xid;
+	ic_bootp_init_ext(b->vendor_area);
+
+	/* Chain packet down the line... */
+	skb->dev = dev;
+	skb->protocol = __constant_htons(ETH_P_IP);
+	if ((dev->hard_header &&
+	     dev->hard_header(skb, dev, ntohs(skb->protocol), dev->broadcast, dev->dev_addr, skb->len) < 0) ||
+	    dev_queue_xmit(skb) < 0)
+		printk("E");
 }
 
 
 /*
  *  Send BOOTP requests to all interfaces.
  */
-__initfunc(static int ic_bootp_send(u32 jiffies))
+static void __init ic_bootp_send(u32 jiffies)
 {
 	struct ic_device *d;
 
 	for(d=ic_first_dev; d; d=d->next)
-		if (ic_bootp_send_if(d, jiffies) < 0)
-			return -1;
-	return 0;
+		if (d->able & IC_BOOTP)
+			ic_bootp_send_if(d, jiffies);
 }
 
 
 /*
  *  Copy BOOTP-supplied string if not already set.
  */
-__initfunc(static int ic_bootp_string(char *dest, char *src, int len, int max))
+static int __init ic_bootp_string(char *dest, char *src, int len, int max)
 {
 	if (!len)
 		return 0;
@@ -678,7 +568,7 @@
 /*
  *  Process BOOTP extension.
  */
-__initfunc(static void ic_do_bootp_ext(u8 *ext))
+static void __init ic_do_bootp_ext(u8 *ext)
 {
 #ifdef IPCONFIG_DEBUG
 	u8 *c;
@@ -714,65 +604,64 @@
 
 
 /*
- *  Receive BOOTP request.
+ *  Receive BOOTP reply.
  */
-__initfunc(static void ic_bootp_recv(void))
+static int __init ic_bootp_recv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
 {
+	struct bootp_pkt *b = (struct bootp_pkt *) skb->nh.iph;
+	struct iphdr *h = &b->iph;
 	int len;
-	u8 *ext, *end, *opt;
-	struct ic_device *d;
-	struct bootp_pkt *b = ic_recv_bootp;
 
-	if ((len = ic_udp_recv(ic_bootp_recv_sock, b, sizeof(struct bootp_pkt))) < 0)
-		return;
+	/* If we already have a reply, just drop the packet */
+	if (ic_got_reply)
+		goto drop;
 
-	/* Check consistency of incoming packet */
-	if (len < 300 ||			/* See RFC 1542:2.1 */
-	    b->op != BOOTP_REPLY ||
-	    b->xid != ic_xmit_bootp->xid) {
-		printk("?");
-		return;
-		}
+	/* Check whether it's a BOOTP packet */
+	if (skb->pkt_type == PACKET_OTHERHOST ||
+	    skb->len < sizeof(struct udphdr) + sizeof(struct iphdr) ||
+	    h->ihl != 5 ||
+	    h->version != 4 ||
+	    ip_fast_csum((char *) h, h->ihl) != 0 ||
+	    skb->len < ntohs(h->tot_len) ||
+	    h->protocol != IPPROTO_UDP ||
+	    b->udph.source != htons(67) ||
+	    b->udph.dest != htons(68) ||
+	    ntohs(h->tot_len) < ntohs(b->udph.len) + sizeof(struct iphdr))
+		goto drop;
 
-	/* Find interface this arrived from */
-	for(d=ic_first_dev; d; d=d->next) {
-		struct device *dev = d->dev;
-		if (b->htype == dev->type ||
-		    b->hlen == dev->addr_len ||
-		    !memcmp(b->hw_addr, dev->dev_addr, dev->addr_len))
-			break;
-	}
-	if (!d) {	/* Unknown device */
-		printk("!");
-		return;
+	/* Fragments are not supported */
+	if (h->frag_off & htons(IP_OFFSET|IP_MF)) {
+		printk(KERN_ERR "BOOTP: Ignoring fragmented reply.\n");
+		goto drop;
 	}
 
-	/* Record BOOTP packet arrival */
-	cli();
-	if (ic_got_reply) {
-		sti();
-		return;
+	/* Is it a reply to our BOOTP request? */
+	len = ntohs(b->udph.len) - sizeof(struct udphdr);
+	if (len < 300 ||				    /* See RFC 951:2.1 */
+	    b->op != BOOTP_REPLY ||
+	    b->xid != ic_bootp_xid) {
+		printk("?");
+		goto drop;
 	}
-	ic_got_reply = IC_GOT_BOOTP;
-	sti();
-	ic_dev = d->dev;
 
 	/* Extract basic fields */
 	ic_myaddr = b->your_ip;
 	ic_servaddr = b->server_ip;
+	ic_got_reply = IC_BOOTP;
+	ic_dev = dev;
 
 	/* Parse extensions */
 	if (b->vendor_area[0] == 99 &&	/* Check magic cookie */
 	    b->vendor_area[1] == 130 &&
 	    b->vendor_area[2] == 83 &&
 	    b->vendor_area[3] == 99) {
-		ext = &b->vendor_area[4];
-		end = (u8 *) b + len;
+		u8 *ext = &b->vendor_area[4];
+		u8 *end = (u8 *) b + len;
 		while (ext < end && *ext != 0xff) {
 			if (*ext == 0)		/* Padding */
 				ext++;
 			else {
-				opt = ext;
+				u8 *opt = ext;
 				ext += ext[1] + 2;
 				if (ext <= end)
 					ic_do_bootp_ext(opt);
@@ -782,7 +671,12 @@
 
 	if (ic_gateway == INADDR_NONE && b->relay_ip)
 		ic_gateway = b->relay_ip;
-}
+
+drop:
+	kfree_skb(skb);
+	return 0;
+}	
+
 
 #endif
 
@@ -793,11 +687,13 @@
 
 #ifdef CONFIG_IP_PNP_DYNAMIC
 
-__initfunc(int ic_dynamic(void))
+static int __init ic_dynamic(void)
 {
 	int retries;
 	unsigned long timeout, jiff;
 	unsigned long start_jiffies;
+	int do_rarp = ic_proto_have_if & IC_RARP;
+	int do_bootp = ic_proto_have_if & IC_BOOTP;
 
 	/*
 	 * If neither BOOTP nor RARP was selected, return with an error. This
@@ -805,30 +701,22 @@
 	 * sing, and without BOOTP and RARP we are not able to get that in-
 	 * formation.
 	 */
-	if (!ic_bootp_flag && !ic_rarp_flag) {
+	if (!ic_proto_enabled) {
 		printk(KERN_ERR "IP-Config: Incomplete network configuration information.\n");
 		return -1;
 	}
 
 #ifdef CONFIG_IP_PNP_BOOTP
-	if (ic_bootp_flag && !bootp_dev_count) {
+	if ((ic_proto_enabled ^ ic_proto_have_if) & IC_BOOTP)
 		printk(KERN_ERR "BOOTP: No suitable device found.\n");
-		ic_bootp_flag = 0;
-	}
-#else
-	ic_bootp_flag = 0;
 #endif
 
 #ifdef CONFIG_IP_PNP_RARP
-	if (ic_rarp_flag && !rarp_dev_count) {
+	if ((ic_proto_enabled ^ ic_proto_have_if) & IC_RARP)
 		printk(KERN_ERR "RARP: No suitable device found.\n");
-		ic_rarp_flag = 0;
-	}
-#else
-	ic_rarp_flag = 0;
 #endif
 
-	if (!ic_bootp_flag && !ic_rarp_flag)
+	if (!ic_proto_have_if)
 		/* Error message already printed */
 		return -1;
 
@@ -836,14 +724,12 @@
 	 * Setup RARP and BOOTP protocols
 	 */
 #ifdef CONFIG_IP_PNP_RARP
-	if (ic_rarp_flag)
+	if (do_rarp)
 		ic_rarp_init();
 #endif
 #ifdef CONFIG_IP_PNP_BOOTP
-	if (ic_bootp_flag && ic_bootp_init() < 0) {
-		ic_bootp_cleanup();
-		return -1;
-	}
+	if (do_bootp)
+		ic_bootp_init();
 #endif
 
 	/*
@@ -855,36 +741,26 @@
 	 *  applies.. - AC]
 	 */
 	printk(KERN_NOTICE "Sending %s%s%s requests...",
-		ic_bootp_flag ? "BOOTP" : "",
-		ic_bootp_flag && ic_rarp_flag ? " and " : "",
-		ic_rarp_flag ? "RARP" : "");
+	        do_bootp ? "BOOTP" : "",
+		do_bootp && do_rarp ? " and " : "",
+		do_rarp ? "RARP" : "");
 	start_jiffies = jiffies;
 	retries = CONF_RETRIES;
 	get_random_bytes(&timeout, sizeof(timeout));
 	timeout = CONF_BASE_TIMEOUT + (timeout % (unsigned) CONF_TIMEOUT_RANDOM);
 	for(;;) {
 #ifdef CONFIG_IP_PNP_BOOTP
-		if (ic_bootp_flag && ic_bootp_send(jiffies - start_jiffies) < 0) {
-			printk(" BOOTP failed!\n");
-			ic_bootp_cleanup();
-			ic_bootp_flag = 0;
-			if (!ic_rarp_flag)
-				break;
-		}
+		if (do_bootp)
+			ic_bootp_send(jiffies - start_jiffies);
 #endif
 #ifdef CONFIG_IP_PNP_RARP
-		if (ic_rarp_flag)
+		if (do_rarp)
 			ic_rarp_send();
 #endif
 		printk(".");
 		jiff = jiffies + timeout;
 		while (jiffies < jiff && !ic_got_reply)
-#ifdef CONFIG_IP_PNP_BOOTP
-			if (ic_bootp_flag)
-				ic_bootp_recv();
-#else
 			;
-#endif
 		if (ic_got_reply) {
 			printk(" OK\n");
 			break;
@@ -899,11 +775,11 @@
 	}
 
 #ifdef CONFIG_IP_PNP_RARP
-	if (ic_rarp_flag)
+	if (do_rarp)
 		ic_rarp_cleanup();
 #endif
 #ifdef CONFIG_IP_PNP_BOOTP
-	if (ic_bootp_flag)
+	if (do_bootp)
 		ic_bootp_cleanup();
 #endif
 
@@ -911,7 +787,7 @@
 		return -1;
 
 	printk("IP-Config: Got %s answer from %s, ",
-		(ic_got_reply == IC_GOT_BOOTP) ? "BOOTP" : "RARP",
+		(ic_got_reply & IC_BOOTP) ? "BOOTP" : "RARP",
 		in_ntoa(ic_servaddr));
 	printk("my address is %s\n", in_ntoa(ic_myaddr));
 
@@ -924,7 +800,7 @@
  *	IP Autoconfig dispatcher.
  */
 
-__initfunc(int ip_auto_config(void))
+int __init ip_auto_config(void)
 {
 	if (!ic_enable)
 		return 0;
@@ -1000,25 +876,44 @@
  *	<device>	- use all available devices
  *	<bootp|rarp|both|off> - use both protocols to determine my own address
  */
-__initfunc(void ip_auto_config_setup(char *addrs, int *ints))
+static int __init ic_proto_name(char *name)
+{
+	if (!strcmp(name, "off")) {
+		ic_proto_enabled = 0;
+		return 1;
+	}
+#ifdef CONFIG_IP_PNP_BOOTP
+	else if (!strcmp(name, "bootp")) {
+		ic_proto_enabled &= ~IC_RARP;
+		return 1;
+	}
+#endif
+#ifdef CONFIG_IP_PNP_RARP
+	else if (!strcmp(name, "rarp")) {
+		ic_proto_enabled &= ~IC_BOOTP;
+		return 1;
+	}
+#endif
+#ifdef CONFIG_IP_PNP_DYNAMIC
+	else if (!strcmp(name, "both")) {
+		return 1;
+	}
+#endif
+	return 0;
+}
+
+void __init ip_auto_config_setup(char *addrs, int *ints)
 {
 	char *cp, *ip, *dp;
 	int num = 0;
 
 	ic_set_manually = 1;
-
-	if (!strcmp(addrs, "bootp")) {
-		ic_rarp_flag = 0;
-		return;
-	} else if (!strcmp(addrs, "rarp")) {
-		ic_bootp_flag = 0;
-		return;
-	} else if (!strcmp(addrs, "both")) {
-		return;
-	} else if (!strcmp(addrs, "off")) {
+	if (!strcmp(addrs, "off")) {
 		ic_enable = 0;
 		return;
 	}
+	if (ic_proto_name(addrs))
+		return;
 
 	/* Parse the whole string */
 	ip = addrs;
@@ -1059,12 +954,7 @@
 				user_dev_name[IFNAMSIZ-1] = '\0';
 				break;
 			case 6:
-				if (!strcmp(ip, "rarp"))
-					ic_bootp_flag = 0;
-				else if (!strcmp(ip, "bootp"))
-					ic_rarp_flag = 0;
-				else if (strcmp(ip, "both"))
-					ic_bootp_flag = ic_rarp_flag = 0;
+				ic_proto_name(ip);
 				break;
 			}
 		}

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov