* 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"
+
+#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
/* XXX: only DHCP is supported */
static const uint8_t rfc1533_cookie[] = { RFC1533_COOKIE };
#ifdef DEBUG
-#define dprintf(fmt, ...) \
+#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(Slirp *slirp, struct in_addr *paddr,
}
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);
+ if (p + len > p_end) {
+ break;
+ }
+ 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);
}
}
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 *end;
+ 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(slirp->client_ethaddr, bp->bp_hwaddr, 6);
+
+ /* Get client's hardware address from bootp request */
+ memcpy(client_ethaddr, bp->bp_hwaddr, ETH_ALEN);
m = m_get(slirp);
if (!m) {
memset(rbp, 0, sizeof(struct bootp_t));
if (dhcp_msg_type == DHCPDISCOVER) {
- if (preq_addr) {
- bc = request_addr(slirp, preq_addr, slirp->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(slirp, &daddr.sin_addr, slirp->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, slirp->client_ethaddr, 6);
- } else if (preq_addr) {
- bc = request_addr(slirp, preq_addr, slirp->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, slirp->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(slirp, &daddr.sin_addr, bp->bp_hwaddr);
}
}
+ /* 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);
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 = rbp->bp_vend;
+ end = (uint8_t *)&rbp[1];
memcpy(q, rfc1533_cookie, 4);
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));
if (*slirp->client_hostname) {
val = strlen(slirp->client_hostname);
- *q++ = RFC1533_HOSTNAME;
- *q++ = val;
- memcpy(q, slirp->client_hostname, val);
- q += val;
+ if (q + val + 2 >= end) {
+ g_warning("DHCP packet size exceeded, "
+ "omitting host name option.");
+ } else {
+ *q++ = RFC1533_HOSTNAME;
+ *q++ = val;
+ memcpy(q, slirp->client_hostname, val);
+ q += val;
+ }
+ }
+
+ if (slirp->vdomainname) {
+ val = strlen(slirp->vdomainname);
+ if (q + val + 2 >= end) {
+ g_warning("DHCP packet size exceeded, "
+ "omitting domain name option.");
+ } else {
+ *q++ = RFC1533_DOMAINNAME;
+ *q++ = val;
+ memcpy(q, slirp->vdomainname, val);
+ q += val;
+ }
+ }
+
+ if (slirp->tftp_server_name) {
+ val = strlen(slirp->tftp_server_name);
+ if (q + val + 2 >= end) {
+ g_warning("DHCP packet size exceeded, "
+ "omitting tftp-server-name option.");
+ } else {
+ *q++ = RFC2132_TFTP_SERVER_NAME;
+ *q++ = val;
+ memcpy(q, slirp->tftp_server_name, val);
+ q += val;
+ }
+ }
+
+ if (slirp->vdnssearch) {
+ val = slirp->vdnssearch_len;
+ if (q + val >= end) {
+ 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;
+ assert(q < 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)