From: "Kazu" <kazoo@r3.dion.ne.jp>
To: qemu-devel@nongnu.org
Subject: [Qemu-devel][PATCH] Built-in DHCP server
Date: Tue, 20 Feb 2007 13:09:39 +0900 [thread overview]
Message-ID: <001301c754a4$f10d5120$0464a8c0@athlon> (raw)
[-- 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
next reply other threads:[~2007-02-20 4:09 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-02-20 4:09 Kazu [this message]
2007-02-20 14:22 ` [Qemu-devel][PATCH] Built-in DHCP server Lonnie Mendez
2007-02-21 8:01 ` Kazu
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to='001301c754a4$f10d5120$0464a8c0@athlon' \
--to=kazoo@r3.dion.ne.jp \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).