All of lore.kernel.org
 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 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.