qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: renzo@cs.unibo.it (Renzo Davoli)
To: qemu-devel@nongnu.org
Subject: Re: [Qemu-devel] [patch] slirp bootp, Request&Discover
Date: Thu, 13 May 2004 17:02:21 +0200	[thread overview]
Message-ID: <20040513150221.GD18157@cs.unibo.it> (raw)
In-Reply-To: <40A28488.5060201@bellard.org>

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

On Wed, May 12, 2004 at 10:09:44PM +0200, Fabrice Bellard wrote:
> Strange. If a real DHCP server accepts that, then I agree to merge it. 
> Otherwise, it may be bug in the NE2000 emulation.

AFAIK it is not strange.

DHCP request is sent also for renewing a lease.
you use a very long lease time (1 day) but it seems that win 98 despite
of a boot remembers that it already had a lease and asks just for a renewal.

I have written a new patch that not only solves this problem but it
gives also a better approximation of the DHCP protocol by managing 
a simplified version of the lease protocol.

It is useful for using qemu with user-net for a period of time longer than the 
lease expire time (or to connect several interfaces-machines to the dhcp
server).

This patch:
- tries to reaasign the previous address to each MAC address.
- if there are no more available addresses re-assigns IP with expired
  leases.
- If somebody tries to DISCOVER multiple times sends back the same
  address (Win 98 ask several times when the address has changed)
- When REQUEST asks for an already assigned address returns DHCPNAK
  (unfortunately Win 98 does not manage this correctly).
  When 98 has a valid lease from a previous session it asks twice for
  the previous address and regardless of the NAK coming from the server it tests
  with a ping whether the address is available or not and *keeps it*!
  IMHO this is plain against the RFC 2131.

Fabrice,
I am including this into slirpvde, maybe my previous fix is enough for
dhcp inside qemu (as it has a single guest machine) but if you like we
can keep the source code aligned.

ciao
	renzo


[-- Attachment #2: bootp.diff --]
[-- Type: text/plain, Size: 4849 bytes --]

--- oldbootp.c	2004-05-03 14:11:44.000000000 +0200
+++ bootp.c	2004-05-13 16:57:08.000000000 +0200
@@ -29,10 +29,12 @@
 
 #define START_ADDR 15
 
-#define LEASE_TIME (24 * 3600)
+#define LEASE_TIME (120)
 
 typedef struct {
     uint8_t allocated;
+    uint8_t macaddr[6];
+    int time;
 } BOOTPClient;
 
 BOOTPClient bootp_clients[NB_ADDR];
@@ -50,26 +52,69 @@
 {
     BOOTPClient *bc;
     int i;
+    int now=time(NULL);
 
     for(i = 0; i < NB_ADDR; i++) {
         if (!bootp_clients[i].allocated)
             goto found;
     }
+    for(i = 0; i < NB_ADDR; i++) {
+        if (now-bootp_clients[i].time > 3*LEASE_TIME)
+            goto found;
+    }
     return NULL;
  found:
     bc = &bootp_clients[i];
-    bc->allocated = 1;
     paddr->s_addr = htonl(ntohl(special_addr.s_addr) | (i + START_ADDR));
     return bc;
 }
 
+static BOOTPClient *find_addr(struct in_addr *paddr, const uint8_t *macaddr)
+{
+    BOOTPClient *bc;
+    int i;
+
+    for(i = 0; i < NB_ADDR; i++) {
+        if (!memcmp(macaddr, bootp_clients[i].macaddr, 6))
+            goto found;
+    }
+    return NULL;
+ found:
+    bc = &bootp_clients[i];
+    paddr->s_addr = htonl(ntohl(special_addr.s_addr) | (i + START_ADDR));
+    return bc;
+}
+
+static BOOTPClient *find_reqaddr(struct in_addr *paddr, struct in_addr *reqaddr, const uint8_t *macaddr)
+{
+    BOOTPClient *bc=NULL;
+    int i;
+    /*check the net prefix*/
+    if ((ntohl(reqaddr->s_addr) & 0xffffff00) ==
+		    (ntohl(special_addr.s_addr) & 0xffffff00)) {
+	    i=(ntohl(reqaddr->s_addr) & 0xff) - START_ADDR;
+	    if (i>=0 && i< NB_ADDR) {
+		    bc = &bootp_clients[i];
+		    if (bc->allocated &&
+				    (memcmp(macaddr, bootp_clients[i].macaddr, 6)==0)) {
+			    paddr->s_addr = reqaddr->s_addr;
+			    return bc;
+		    }
+		    else
+			    bc=NULL;
+	    }
+    }
+    return bc;
+}
+
 static void dhcp_decode(const uint8_t *buf, int size,
-                        int *pmsg_type)
+                        int *pmsg_type, struct sockaddr_in *preqaddr)
 {
     const uint8_t *p, *p_end;
     int len, tag;
 
     *pmsg_type = 0;    
+    preqaddr->sin_addr.s_addr=htonl(0L);
 
     p = buf;
     p_end = buf + size;
@@ -96,6 +141,10 @@
                 if (len >= 1)
                     *pmsg_type = p[0];
                 break;
+            case RFC2132_REQ_ADDR:
+		if (len == 4) {
+			memcpy(&(preqaddr->sin_addr),p,4);
+		}
             default:
                 break;
             }
@@ -109,14 +158,14 @@
     BOOTPClient *bc;
     struct mbuf *m;
     struct bootp_t *rbp;
-    struct sockaddr_in saddr, daddr;
+    struct sockaddr_in saddr, daddr, reqaddr;
     struct in_addr dns_addr;
     int dhcp_msg_type, val;
-    uint8_t *q;
+    uint8_t *q,replytype;
 
     /* extract exact DHCP msg type */
-    dhcp_decode(bp->bp_vend, DHCP_OPT_LEN, &dhcp_msg_type);
-    dprintf("bootp packet op=%d msgtype=%d\n", bp->bp_op, dhcp_msg_type);
+    dhcp_decode(bp->bp_vend, DHCP_OPT_LEN, &dhcp_msg_type,&reqaddr);
+    dprintf("bootp packet op=%d msgtype=%d reqaddr=%x\n", bp->bp_op, dhcp_msg_type,ntohl(reqaddr.sin_addr.s_addr));
     
     if (dhcp_msg_type != DHCPDISCOVER && 
         dhcp_msg_type != DHCPREQUEST)
@@ -131,11 +180,20 @@
     m->m_data += sizeof(struct udpiphdr);
     memset(rbp, 0, sizeof(struct bootp_t));
 
+    bc=NULL;
+    daddr.sin_addr.s_addr=htonl(0L);
+    if (dhcp_msg_type == DHCPREQUEST) {
+	    if (reqaddr.sin_addr.s_addr != htonl(0L))
+		    bc = find_reqaddr(&daddr.sin_addr, &reqaddr.sin_addr, bp->bp_hwaddr);
+	    else 
+		    bc = find_addr(&daddr.sin_addr, bp->bp_hwaddr);
+    }
+    else if (dhcp_msg_type == DHCPDISCOVER) {
+	    bc = find_addr(&daddr.sin_addr, bp->bp_hwaddr);
+	    if (!bc)
     bc = get_new_addr(&daddr.sin_addr);
-    if (!bc) {
-        dprintf("no address left\n");
-        return;
     }
+
     dprintf("offered addr=%08x\n", ntohl(daddr.sin_addr.s_addr));
 
     saddr.sin_addr.s_addr = htonl(ntohl(special_addr.s_addr) | CTL_ALIAS);
@@ -155,18 +213,21 @@
     memcpy(q, rfc1533_cookie, 4);
     q += 4;
 
-    if (dhcp_msg_type == DHCPDISCOVER) {
-        *q++ = RFC2132_MSG_TYPE;
-        *q++ = 1;
-        *q++ = DHCPOFFER;
-    } else if (dhcp_msg_type == DHCPREQUEST) {
+    if (bc != NULL) {
+        memcpy(bc->macaddr, client_ethaddr, 6);
+    	bc->allocated = 1;
+	bc->time = time(NULL);
+    	replytype=(dhcp_msg_type == DHCPDISCOVER)?DHCPOFFER:DHCPACK;
+    }
+    else
+	replytype=DHCPNACK;
+
         *q++ = RFC2132_MSG_TYPE;
         *q++ = 1;
-        *q++ = DHCPACK;
-    }
+    *q++ = replytype;
         
-    if (dhcp_msg_type == DHCPDISCOVER ||
-        dhcp_msg_type == DHCPREQUEST) {
+    if ((dhcp_msg_type == DHCPDISCOVER ||
+        dhcp_msg_type == DHCPREQUEST) && replytype!=DHCPNACK) {
         *q++ = RFC2132_SRV_ID;
         *q++ = 4;
         memcpy(q, &saddr.sin_addr, 4);

      reply	other threads:[~2004-05-13 15:11 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2004-05-12 15:30 [Qemu-devel] [patch] slirp bootp, Request&Discover Renzo Davoli
2004-05-12 20:09 ` Fabrice Bellard
2004-05-13 15:02   ` Renzo Davoli [this message]

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=20040513150221.GD18157@cs.unibo.it \
    --to=renzo@cs.unibo.it \
    --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).