From ce6055583f7b8b4af7175b777b023bc115aed382 Mon Sep 17 00:00:00 2001
From: Julien BLACHE <julien-externe.blache@edf.fr>
Date: Tue, 10 Aug 2010 15:37:10 +0200
Subject: [PATCH] ipconfig: differentiate between error and non-DHCP/BOOTP traffic in packet_recv()

Commit 4efbcf90f60e27febe883ef052454d8cfded5c15 badly broke ipconfig by
turning packet_recv() into an all-or-nothing function. Before this commit,
packet_recv() did distinguish between a DHCP/BOOTP packet that's of interest,
random UDP packets we don't care about and errors.

After the patch, either a packet is a DHCP/BOOTP packet or packet_recv() exits
with an error.

This breaks ipconfig on big, noisy LANs where random UDP traffic can arrive
before the DHCP reply and throw the device into DEVST_ERROR state.
---
 usr/kinit/ipconfig/bootp_proto.c |    2 +-
 usr/kinit/ipconfig/dhcp_proto.c  |    4 ++--
 usr/kinit/ipconfig/packet.c      |    5 +++--
 3 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/usr/kinit/ipconfig/bootp_proto.c b/usr/kinit/ipconfig/bootp_proto.c
index 42dfad3..baf9d3e 100644
--- a/usr/kinit/ipconfig/bootp_proto.c
+++ b/usr/kinit/ipconfig/bootp_proto.c
@@ -171,7 +171,7 @@ int bootp_recv_reply(struct netdev *dev)
 
 	ret = packet_recv(iov, 3);
 	if (ret <= 0)
-		return -1;
+		return ret;
 
 	if (ret < sizeof(struct bootp_hdr) ||
 	    bootp.op != BOOTP_REPLY ||	/* RFC951 7.5 */
diff --git a/usr/kinit/ipconfig/dhcp_proto.c b/usr/kinit/ipconfig/dhcp_proto.c
index 2a2651a..fc0494d 100644
--- a/usr/kinit/ipconfig/dhcp_proto.c
+++ b/usr/kinit/ipconfig/dhcp_proto.c
@@ -148,8 +148,8 @@ static int dhcp_recv(struct netdev *dev)
 	int ret;
 
 	ret = packet_recv(iov, 3);
-	if (ret == 0)
-		return -1;
+	if (ret <= 0)
+		return ret;
 
 	dprintf("\n   dhcp xid %08x ", dev->bootp.xid);
 
diff --git a/usr/kinit/ipconfig/packet.c b/usr/kinit/ipconfig/packet.c
index 508c7ba..d0e143a 100644
--- a/usr/kinit/ipconfig/packet.c
+++ b/usr/kinit/ipconfig/packet.c
@@ -214,7 +214,8 @@ void packet_discard(void)
  * Receive a bootp packet.  The options are listed in iov[1...iov_len].
  * iov[0] must point to the bootp packet header.
  * Returns:
- *  0 = Error, try again later
+ * -1 = Error, try again later
+*   0 = Discarded packet (non-DHCP/BOOTP traffic)
  * >0 = Size of packet
  */
 int packet_recv(struct iovec *iov, int iov_len)
@@ -235,7 +236,7 @@ int packet_recv(struct iovec *iov, int iov_len)
 	ret = recvfrom(pkt_fd, &iph, sizeof(struct iphdr),
 		       MSG_PEEK, NULL, NULL);
 	if (ret == -1)
-		return 0;
+		return -1;
 
 	if (iph.ihl < 5 || iph.version != IPVERSION)
 		goto discard_pkt;
-- 
1.5.6.5

