* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-#include <slirp.h>
+#include "qemu/osdep.h"
+#include "slirp.h"
-/* XXX: only DHCP is supported */
+#if defined(_WIN32)
+/* Windows ntohl() returns an u_long value.
+ * Add a type cast to match the format strings. */
+# define ntohl(n) ((uint32_t)ntohl(n))
+#endif
-#define NB_ADDR 16
+/* XXX: only DHCP is supported */
#define LEASE_TIME (24 * 3600)
-typedef struct {
- uint8_t allocated;
- uint8_t macaddr[6];
-} BOOTPClient;
-
-static BOOTPClient bootp_clients[NB_ADDR];
-
-char *bootp_filename;
-
static const uint8_t rfc1533_cookie[] = { RFC1533_COOKIE };
#ifdef DEBUG
-#define dprintf(fmt, ...) \
-if (slirp_debug & DBG_CALL) { fprintf(dfd, fmt, ## __VA_ARGS__); fflush(dfd); }
+#define DPRINTF(fmt, ...) \
+do if (slirp_debug & DBG_CALL) { fprintf(dfd, fmt, ## __VA_ARGS__); fflush(dfd); } while (0)
#else
-#define dprintf(fmt, ...)
+#define DPRINTF(fmt, ...) do{}while(0)
#endif
-static BOOTPClient *get_new_addr(struct in_addr *paddr,
+static BOOTPClient *get_new_addr(Slirp *slirp, struct in_addr *paddr,
const uint8_t *macaddr)
{
BOOTPClient *bc;
int i;
- for(i = 0; i < NB_ADDR; i++) {
- bc = &bootp_clients[i];
+ for(i = 0; i < NB_BOOTP_CLIENTS; i++) {
+ bc = &slirp->bootp_clients[i];
if (!bc->allocated || !memcmp(macaddr, bc->macaddr, 6))
goto found;
}
return NULL;
found:
- bc = &bootp_clients[i];
+ bc = &slirp->bootp_clients[i];
bc->allocated = 1;
- paddr->s_addr = vdhcp_startaddr.s_addr + htonl(i);
+ paddr->s_addr = slirp->vdhcp_startaddr.s_addr + htonl(i);
return bc;
}
-static BOOTPClient *request_addr(const struct in_addr *paddr,
+static BOOTPClient *request_addr(Slirp *slirp, const struct in_addr *paddr,
const uint8_t *macaddr)
{
uint32_t req_addr = ntohl(paddr->s_addr);
- uint32_t dhcp_addr = ntohl(vdhcp_startaddr.s_addr);
+ uint32_t dhcp_addr = ntohl(slirp->vdhcp_startaddr.s_addr);
BOOTPClient *bc;
if (req_addr >= dhcp_addr &&
- req_addr < (dhcp_addr + NB_ADDR)) {
- bc = &bootp_clients[req_addr - dhcp_addr];
+ req_addr < (dhcp_addr + NB_BOOTP_CLIENTS)) {
+ bc = &slirp->bootp_clients[req_addr - dhcp_addr];
if (!bc->allocated || !memcmp(macaddr, bc->macaddr, 6)) {
bc->allocated = 1;
return bc;
return NULL;
}
-static BOOTPClient *find_addr(struct in_addr *paddr, const uint8_t *macaddr)
+static BOOTPClient *find_addr(Slirp *slirp, 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))
+ for(i = 0; i < NB_BOOTP_CLIENTS; i++) {
+ if (!memcmp(macaddr, slirp->bootp_clients[i].macaddr, 6))
goto found;
}
return NULL;
found:
- bc = &bootp_clients[i];
+ bc = &slirp->bootp_clients[i];
bc->allocated = 1;
- paddr->s_addr = vdhcp_startaddr.s_addr + htonl(i);
+ paddr->s_addr = slirp->vdhcp_startaddr.s_addr + htonl(i);
return bc;
}
static void dhcp_decode(const struct bootp_t *bp, int *pmsg_type,
- const struct in_addr **preq_addr)
+ struct in_addr *preq_addr)
{
const uint8_t *p, *p_end;
int len, tag;
*pmsg_type = 0;
- *preq_addr = NULL;
+ preq_addr->s_addr = htonl(0L);
p = bp->bp_vend;
p_end = p + DHCP_OPT_LEN;
if (p >= p_end)
break;
len = *p++;
- dprintf("dhcp: tag=%d len=%d\n", tag, len);
+ DPRINTF("dhcp: tag=%d len=%d\n", tag, len);
switch(tag) {
case RFC2132_MSG_TYPE:
*pmsg_type = p[0];
break;
case RFC2132_REQ_ADDR:
- if (len >= 4)
- *preq_addr = (struct in_addr *)p;
+ if (len >= 4) {
+ memcpy(&(preq_addr->s_addr), p, 4);
+ }
break;
default:
break;
p += len;
}
}
- if (*pmsg_type == DHCPREQUEST && !*preq_addr && bp->bp_ciaddr.s_addr) {
- *preq_addr = &bp->bp_ciaddr;
+ if (*pmsg_type == DHCPREQUEST && preq_addr->s_addr == htonl(0L) &&
+ bp->bp_ciaddr.s_addr) {
+ memcpy(&(preq_addr->s_addr), &bp->bp_ciaddr, 4);
}
}
-static void bootp_reply(const struct bootp_t *bp)
+static void bootp_reply(Slirp *slirp, const struct bootp_t *bp)
{
BOOTPClient *bc = NULL;
struct mbuf *m;
struct bootp_t *rbp;
struct sockaddr_in saddr, daddr;
- const struct in_addr *preq_addr;
+ struct in_addr preq_addr;
int dhcp_msg_type, val;
uint8_t *q;
+ uint8_t client_ethaddr[ETH_ALEN];
/* extract exact DHCP msg type */
dhcp_decode(bp, &dhcp_msg_type, &preq_addr);
- dprintf("bootp packet op=%d msgtype=%d", bp->bp_op, dhcp_msg_type);
- if (preq_addr)
- dprintf(" req_addr=%08x\n", ntohl(preq_addr->s_addr));
+ DPRINTF("bootp packet op=%d msgtype=%d", bp->bp_op, dhcp_msg_type);
+ if (preq_addr.s_addr != htonl(0L))
+ DPRINTF(" req_addr=%08" PRIx32 "\n", ntohl(preq_addr.s_addr));
else
- dprintf("\n");
+ DPRINTF("\n");
if (dhcp_msg_type == 0)
dhcp_msg_type = DHCPREQUEST; /* Force reply for old BOOTP clients */
if (dhcp_msg_type != DHCPDISCOVER &&
dhcp_msg_type != DHCPREQUEST)
return;
- /* XXX: this is a hack to get the client mac address */
- memcpy(client_ethaddr, bp->bp_hwaddr, 6);
- if ((m = m_get()) == NULL)
+ /* Get client's hardware address from bootp request */
+ memcpy(client_ethaddr, bp->bp_hwaddr, ETH_ALEN);
+
+ m = m_get(slirp);
+ if (!m) {
return;
+ }
m->m_data += IF_MAXLINKHDR;
rbp = (struct bootp_t *)m->m_data;
m->m_data += sizeof(struct udpiphdr);
memset(rbp, 0, sizeof(struct bootp_t));
if (dhcp_msg_type == DHCPDISCOVER) {
- if (preq_addr) {
- bc = request_addr(preq_addr, client_ethaddr);
+ if (preq_addr.s_addr != htonl(0L)) {
+ bc = request_addr(slirp, &preq_addr, client_ethaddr);
if (bc) {
- daddr.sin_addr = *preq_addr;
+ daddr.sin_addr = preq_addr;
}
}
if (!bc) {
new_addr:
- bc = get_new_addr(&daddr.sin_addr, client_ethaddr);
+ bc = get_new_addr(slirp, &daddr.sin_addr, client_ethaddr);
if (!bc) {
- dprintf("no address left\n");
+ DPRINTF("no address left\n");
return;
}
}
- memcpy(bc->macaddr, client_ethaddr, 6);
- } else if (preq_addr) {
- bc = request_addr(preq_addr, client_ethaddr);
+ memcpy(bc->macaddr, client_ethaddr, ETH_ALEN);
+ } else if (preq_addr.s_addr != htonl(0L)) {
+ bc = request_addr(slirp, &preq_addr, client_ethaddr);
if (bc) {
- daddr.sin_addr = *preq_addr;
- memcpy(bc->macaddr, client_ethaddr, 6);
+ daddr.sin_addr = preq_addr;
+ memcpy(bc->macaddr, client_ethaddr, ETH_ALEN);
} else {
- daddr.sin_addr.s_addr = 0;
+ /* DHCPNAKs should be sent to broadcast */
+ daddr.sin_addr.s_addr = 0xffffffff;
}
} else {
- bc = find_addr(&daddr.sin_addr, bp->bp_hwaddr);
+ bc = find_addr(slirp, &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) */
}
}
- saddr.sin_addr = vhost_addr;
+ /* Update ARP table for this IP address */
+ arp_table_add(slirp, daddr.sin_addr.s_addr, client_ethaddr);
+
+ saddr.sin_addr = slirp->vhost_addr;
saddr.sin_port = htons(BOOTP_SERVER);
daddr.sin_port = htons(BOOTP_CLIENT);
rbp->bp_xid = bp->bp_xid;
rbp->bp_htype = 1;
rbp->bp_hlen = 6;
- memcpy(rbp->bp_hwaddr, bp->bp_hwaddr, 6);
+ memcpy(rbp->bp_hwaddr, bp->bp_hwaddr, ETH_ALEN);
rbp->bp_yiaddr = daddr.sin_addr; /* Client IP address */
rbp->bp_siaddr = saddr.sin_addr; /* Server IP address */
q += 4;
if (bc) {
- dprintf("%s addr=%08x\n",
+ DPRINTF("%s addr=%08" PRIx32 "\n",
(dhcp_msg_type == DHCPDISCOVER) ? "offered" : "ack'ed",
ntohl(daddr.sin_addr.s_addr));
*q++ = DHCPACK;
}
- if (bootp_filename)
+ if (slirp->bootp_filename)
snprintf((char *)rbp->bp_file, sizeof(rbp->bp_file), "%s",
- bootp_filename);
+ slirp->bootp_filename);
*q++ = RFC2132_SRV_ID;
*q++ = 4;
*q++ = RFC1533_NETMASK;
*q++ = 4;
- memcpy(q, &vnetwork_mask, 4);
+ memcpy(q, &slirp->vnetwork_mask, 4);
q += 4;
- if (!slirp_restrict) {
+ if (!slirp->restricted) {
*q++ = RFC1533_GATEWAY;
*q++ = 4;
memcpy(q, &saddr.sin_addr, 4);
*q++ = RFC1533_DNS;
*q++ = 4;
- memcpy(q, &vnameserver_addr, 4);
+ memcpy(q, &slirp->vnameserver_addr, 4);
q += 4;
}
memcpy(q, &val, 4);
q += 4;
- if (*slirp_hostname) {
- val = strlen(slirp_hostname);
+ if (*slirp->client_hostname) {
+ val = strlen(slirp->client_hostname);
*q++ = RFC1533_HOSTNAME;
*q++ = val;
- memcpy(q, slirp_hostname, val);
+ memcpy(q, slirp->client_hostname, val);
q += val;
}
+
+ if (slirp->vdnssearch) {
+ size_t spaceleft = sizeof(rbp->bp_vend) - (q - rbp->bp_vend);
+ val = slirp->vdnssearch_len;
+ if (val + 1 > spaceleft) {
+ g_warning("DHCP packet size exceeded, "
+ "omitting domain-search option.");
+ } else {
+ memcpy(q, slirp->vdnssearch, val);
+ q += val;
+ }
+ }
} else {
static const char nak_msg[] = "requested address not available";
- dprintf("nak'ed addr=%08x\n", ntohl(preq_addr->s_addr));
+ DPRINTF("nak'ed addr=%08" PRIx32 "\n", ntohl(preq_addr.s_addr));
*q++ = RFC2132_MSG_TYPE;
*q++ = 1;
memcpy(q, nak_msg, sizeof(nak_msg) - 1);
q += sizeof(nak_msg) - 1;
}
- *q++ = RFC1533_END;
+ *q = RFC1533_END;
daddr.sin_addr.s_addr = 0xffffffffu;
m->m_len = sizeof(struct bootp_t) -
sizeof(struct ip) - sizeof(struct udphdr);
- udp_output2(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
+ udp_output(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
}
void bootp_input(struct mbuf *m)
struct bootp_t *bp = mtod(m, struct bootp_t *);
if (bp->bp_op == BOOTP_REQUEST) {
- bootp_reply(bp);
+ bootp_reply(m->slirp, bp);
}
}