Index: qemu/slirp/bootp.c @@ -29,11 +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]; @@ -68,26 +69,54 @@ { BOOTPClient *bc; int i; + int now=time(NULL); for(i = 0; i < NB_ADDR; i++) { if (!memcmp(macaddr, bootp_clients[i].macaddr, 6)) 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_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; @@ -114,6 +143,10 @@ if (len >= 1) *pmsg_type = p[0]; break; + case RFC2132_REQ_ADDR: + if (len == 4) { + memcpy(&(preqaddr->sin_addr),p,4); + } default: break; } @@ -127,14 +160,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 == 0) dhcp_msg_type = DHCPREQUEST; /* Force reply for old BOOTP clients */ @@ -152,21 +185,18 @@ m->m_data += sizeof(struct udpiphdr); 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"); - return; - } - memcpy(bc->macaddr, client_ethaddr, 6); - } 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; - } + 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); } dprintf("offered addr=%08x\n", ntohl(daddr.sin_addr.s_addr)); @@ -181,25 +211,27 @@ rbp->bp_hlen = 6; memcpy(rbp->bp_hwaddr, bp->bp_hwaddr, 6); - rbp->bp_yiaddr = daddr.sin_addr; /* Client IP address */ - rbp->bp_siaddr = saddr.sin_addr; /* Server IP address */ + rbp->bp_yiaddr = daddr.sin_addr; /* IP address */ q = rbp->bp_vend; 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); Index: qemu/slirp/bootp.h =================================================================== RCS file: /cvsroot/qemu/qemu/slirp/bootp.h,v retrieving revision 1.1 diff -u -r1.1 bootp.h --- slirp/bootp.h 22 Apr 2004 00:10:47 -0000 1.1 +++ slirp/bootp.h 5 Jun 2004 19:34:22 -0000 @@ -71,6 +71,7 @@ #define DHCPOFFER 2 #define DHCPREQUEST 3 #define DHCPACK 5 +#define DHCPNACK 6 #define RFC1533_VENDOR_MAJOR 0 #define RFC1533_VENDOR_MINOR 0