All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel][PATCH] Built-in DHCP server
@ 2007-02-20  4:09 Kazu
  2007-02-20 14:22 ` Lonnie Mendez
  0 siblings, 1 reply; 3+ messages in thread
From: Kazu @ 2007-02-20  4:09 UTC (permalink / raw)
  To: qemu-devel

[-- Attachment #1: Type: text/plain, Size: 856 bytes --]

Hi,

After I used TAP device by -net nic -net tap,ifname=mytap and I tried to use
user mode network by -net nic -net user, a Windows XP guest doesn't get
IP address from a built-in DHCP server.

It is fixed by an attached patch.

DHCPRELEASE and DHCPNACK are introduced.

DHCPRELEASE code is borrowed from VirtualBox. Windows 2000/XP tries to call
DHCPREQUEST and get old IP address when it boots. I made a code to reply
DHCPNACK to the request. Then the Win2k/XP called DHCPDISCOVER and try to
get a new IP address.

I tested Windows 98SE/2000/XP, Knoppix 3.8, Morphix, Fedora Core 3 and
RedHat 7.2 guest.
There is not problem except RH7.2. It can get IP address but it is
10.0.2.16. dhcpcd in RH7.2 tries to call DHCPDISCOVER two times. So it
consumes two entries in the built-in DHCP server. It seems that it is a bug
of dhcpcd in RH7.2.

Regards,
Kazu

[-- Attachment #2: qemu-20070220-dhcp.patch --]
[-- Type: application/octet-stream, Size: 4066 bytes --]

Index: slirp/bootp.c
===================================================================
RCS file: /sources/qemu/qemu/slirp/bootp.c,v
retrieving revision 1.9
diff -u -r1.9 bootp.c
--- slirp/bootp.c	20 Feb 2007 00:05:08 -0000	1.9
+++ slirp/bootp.c	20 Feb 2007 03:36:39 -0000
@@ -66,6 +66,18 @@
     return bc;
 }
 
+/* From VirtualBox */
+static void release_addr(struct in_addr *paddr)
+{
+    int i;
+
+    i = ntohl(paddr->s_addr) - START_ADDR - ntohl(special_addr.s_addr);
+    if (i >= NB_ADDR)
+        return;
+    memset(bootp_clients[i].macaddr, '\0', 6);
+    bootp_clients[i].allocated = 0;
+}
+
 static BOOTPClient *find_addr(struct in_addr *paddr, const uint8_t *macaddr)
 {
     BOOTPClient *bc;
@@ -133,6 +145,7 @@
     struct in_addr dns_addr;
     int dhcp_msg_type, val;
     uint8_t *q;
+    int freply_nack = 0;
 
     /* extract exact DHCP msg type */
     dhcp_decode(bp->bp_vend, DHCP_OPT_LEN, &dhcp_msg_type);
@@ -141,6 +154,13 @@
     if (dhcp_msg_type == 0)
         dhcp_msg_type = DHCPREQUEST; /* Force reply for old BOOTP clients */
         
+    if (dhcp_msg_type == DHCPRELEASE) {
+        release_addr(&bp->bp_ciaddr);
+        dprintf("released addr=%08lx\n", ntohl(bp->bp_ciaddr.s_addr));
+        /* This message is not to be answered in any way. */
+        return;
+    }
+
     if (dhcp_msg_type != DHCPDISCOVER && 
         dhcp_msg_type != DHCPREQUEST)
         return;
@@ -155,7 +175,6 @@
     memset(rbp, 0, sizeof(struct bootp_t));
 
     if (dhcp_msg_type == DHCPDISCOVER) {
-    new_addr:
         bc = get_new_addr(&daddr.sin_addr);
         if (!bc) {
             dprintf("no address left\n");
@@ -165,16 +184,18 @@
     } else {
         bc = find_addr(&daddr.sin_addr, bp->bp_hwaddr);
         if (!bc) {
-            /* if never assigned, behaves as if it was already
-               assigned (windows fix because it remembers its address) */
-            goto new_addr;
+            /* if never assigned, reply DHCPNACK to BROADCAST.
+               (windows fix because it remembers its address). */
+            daddr.sin_addr.s_addr = htonl(0xffffffff);
+            freply_nack = 1;
+            dprintf("reply NACK\n");
         }
     }
 
     if (bootp_filename)
         snprintf(rbp->bp_file, sizeof(rbp->bp_file), "%s", bootp_filename);
 
-    dprintf("offered addr=%08x\n", ntohl(daddr.sin_addr.s_addr));
+    dprintf("offered addr=%08lx\n", ntohl(daddr.sin_addr.s_addr));
 
     saddr.sin_addr.s_addr = htonl(ntohl(special_addr.s_addr) | CTL_ALIAS);
     saddr.sin_port = htons(BOOTP_SERVER);
@@ -187,7 +208,10 @@
     rbp->bp_hlen = 6;
     memcpy(rbp->bp_hwaddr, bp->bp_hwaddr, 6);
 
-    rbp->bp_yiaddr = daddr.sin_addr; /* Client IP address */
+    if (freply_nack)
+        rbp->bp_yiaddr.s_addr = htonl(0); /* When NACK, IP address is 0. */
+    else
+        rbp->bp_yiaddr = daddr.sin_addr; /* Client IP address */
     rbp->bp_siaddr = saddr.sin_addr; /* Server IP address */
 
     q = rbp->bp_vend;
@@ -201,11 +225,14 @@
     } else if (dhcp_msg_type == DHCPREQUEST) {
         *q++ = RFC2132_MSG_TYPE;
         *q++ = 1;
-        *q++ = DHCPACK;
+        if (freply_nack)
+            *q++ = DHCPNACK;
+        else
+            *q++ = DHCPACK;
     }
         
     if (dhcp_msg_type == DHCPDISCOVER ||
-        dhcp_msg_type == DHCPREQUEST) {
+        ((dhcp_msg_type == DHCPREQUEST) && !freply_nack)) {
         *q++ = RFC2132_SRV_ID;
         *q++ = 4;
         memcpy(q, &saddr.sin_addr, 4);
Index: slirp/bootp.h
===================================================================
RCS file: /sources/qemu/qemu/slirp/bootp.h,v
retrieving revision 1.2
diff -u -r1.2 bootp.h
--- slirp/bootp.h	5 Jun 2005 17:11:42 -0000	1.2
+++ slirp/bootp.h	20 Feb 2007 03:36:39 -0000
@@ -71,6 +71,8 @@
 #define DHCPOFFER		2
 #define DHCPREQUEST		3
 #define DHCPACK			5
+#define DHCPNACK		6
+#define DHCPRELEASE		7
 
 #define RFC1533_VENDOR_MAJOR	0
 #define RFC1533_VENDOR_MINOR	0

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2007-02-21  8:01 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-02-20  4:09 [Qemu-devel][PATCH] Built-in DHCP server Kazu
2007-02-20 14:22 ` Lonnie Mendez
2007-02-21  8:01   ` Kazu

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.