* 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 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;
*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 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));
+ if (preq_addr.s_addr != htonl(0L))
+ DPRINTF(" req_addr=%08" PRIx32 "\n", ntohl(preq_addr.s_addr));
else
DPRINTF("\n");
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");
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 += 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));
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;
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)