Continued updating builtin slirp from libslirp code.

- Updated arp_table.cc (except debug code).
- Updated bootp.cc (Bochs extensions still present).
- Related changes in other files.
This commit is contained in:
Volker Ruppert 2024-04-21 20:35:27 +02:00
parent aa529a42f6
commit 7e3edfe7d9
7 changed files with 124 additions and 75 deletions

View File

@ -27,7 +27,8 @@
#if BX_NETWORKING && BX_NETMOD_SLIRP
void arp_table_add(Slirp *slirp, uint32_t ip_addr, uint8_t ethaddr[ETH_ALEN])
void arp_table_add(Slirp *slirp, uint32_t ip_addr,
const uint8_t ethaddr[ETH_ALEN])
{
const uint32_t broadcast_addr =
~slirp->vnetwork_mask.s_addr | slirp->vnetwork_addr.s_addr;
@ -40,12 +41,7 @@ void arp_table_add(Slirp *slirp, uint32_t ip_addr, uint8_t ethaddr[ETH_ALEN])
ethaddr[0], ethaddr[1], ethaddr[2],
ethaddr[3], ethaddr[4], ethaddr[5]));
/* Check 0.0.0.0/8 invalid source-only addresses */
if ((ip_addr & htonl(~(0xfU << 28))) == 0) {
return;
}
if (ip_addr == 0xffffffff || ip_addr == broadcast_addr) {
if (ip_addr == 0 || ip_addr == 0xffffffff || ip_addr == broadcast_addr) {
/* Do not register broadcast addresses */
return;
}
@ -61,7 +57,7 @@ void arp_table_add(Slirp *slirp, uint32_t ip_addr, uint8_t ethaddr[ETH_ALEN])
/* No entry found, create a new one */
arptbl->table[arptbl->next_victim].ar_sip = ip_addr;
memcpy(arptbl->table[arptbl->next_victim].ar_sha, ethaddr, ETH_ALEN);
memcpy(arptbl->table[arptbl->next_victim].ar_sha, ethaddr, ETH_ALEN);
arptbl->next_victim = (arptbl->next_victim + 1) % ARP_TABLE_SIZE;
}
@ -76,11 +72,8 @@ bool arp_table_search(Slirp *slirp, uint32_t ip_addr,
DEBUG_CALL("arp_table_search");
DEBUG_ARG("ip = 0x%x", ip_addr);
/* Check 0.0.0.0/8 invalid source-only addresses */
assert((ip_addr & htonl(~(0xfU << 28))) != 0);
/* If broadcast address */
if (ip_addr == 0xffffffff || ip_addr == broadcast_addr) {
if (ip_addr == 0 || ip_addr == 0xffffffff || ip_addr == broadcast_addr) {
/* return Ethernet broadcast address */
memset(out_ethaddr, 0xff, ETH_ALEN);
return 1;
@ -88,7 +81,7 @@ bool arp_table_search(Slirp *slirp, uint32_t ip_addr,
for (i = 0; i < ARP_TABLE_SIZE; i++) {
if (arptbl->table[i].ar_sip == ip_addr) {
memcpy(out_ethaddr, arptbl->table[i].ar_sha, ETH_ALEN);
memcpy(out_ethaddr, arptbl->table[i].ar_sha, ETH_ALEN);
DEBUG_ARGS((dfd, " found hw addr = %02x:%02x:%02x:%02x:%02x:%02x\n",
out_ethaddr[0], out_ethaddr[1], out_ethaddr[2],
out_ethaddr[3], out_ethaddr[4], out_ethaddr[5]));

View File

@ -23,11 +23,16 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "slirp.h"
#if BX_NETWORKING && BX_NETMOD_SLIRP
#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 */
#define LEASE_TIME (24 * 3600)
@ -42,6 +47,8 @@ typedef struct {
uint32_t lease_time;
} dhcp_options_t;
#define UEFI_HTTP_VENDOR_CLASS_ID "HTTPClient"
static const uint8_t rfc1533_cookie[] = { RFC1533_COOKIE };
#ifdef DEBUG
@ -77,8 +84,7 @@ static BOOTPClient *request_addr(Slirp *slirp, const struct in_addr *paddr,
uint32_t dhcp_addr = ntohl(slirp->vdhcp_startaddr.s_addr);
BOOTPClient *bc;
if (req_addr >= dhcp_addr &&
req_addr < (dhcp_addr + NB_BOOTP_CLIENTS)) {
if (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;
@ -106,9 +112,11 @@ static BOOTPClient *find_addr(Slirp *slirp, struct in_addr *paddr,
return bc;
}
static void dhcp_decode(Slirp *slirp, const struct bootp_t *bp, dhcp_options_t *opts)
static void dhcp_decode(Slirp *slirp, const struct bootp_t *bp,
const uint8_t *bp_end,
dhcp_options_t *opts)
{
const uint8_t *p, *p_end;
const uint8_t *p;
uint16_t defsize, maxsize;
int len, tag;
char msg[80];
@ -116,11 +124,10 @@ static void dhcp_decode(Slirp *slirp, const struct bootp_t *bp, dhcp_options_t *
memset(opts, 0, sizeof(dhcp_options_t));
p = bp->bp_vend;
p_end = p + DHCP_OPT_LEN;
if (memcmp(p, rfc1533_cookie, 4) != 0)
return;
p += 4;
while (p < p_end) {
while (p < bp_end) {
tag = p[0];
if (tag == RFC1533_PAD) {
p++;
@ -128,9 +135,12 @@ static void dhcp_decode(Slirp *slirp, const struct bootp_t *bp, dhcp_options_t *
break;
} else {
p++;
if (p >= p_end)
if (p >= bp_end)
break;
len = *p++;
if (p + len > bp_end) {
break;
}
DPRINTF("dhcp: tag=%d len=%d\n", tag, len);
switch(tag) {
@ -172,7 +182,7 @@ static void dhcp_decode(Slirp *slirp, const struct bootp_t *bp, dhcp_options_t *
case RFC2132_MAX_SIZE:
if (len == 2) {
memcpy(&maxsize, p, len);
defsize = sizeof(struct bootp_t) - sizeof(struct ip) - sizeof(struct udphdr);
defsize = sizeof(struct bootp_t) + DHCP_OPT_LEN - sizeof(struct ip) - sizeof(struct udphdr);
if (ntohs(maxsize) < defsize) {
sprintf(msg, "DHCP server: RFB2132_MAX_SIZE=%u not supported yet", ntohs(maxsize));
slirp_warning(msg, slirp->opaque);
@ -193,7 +203,9 @@ static void dhcp_decode(Slirp *slirp, const struct bootp_t *bp, dhcp_options_t *
}
}
static void bootp_reply(Slirp *slirp, const struct bootp_t *bp)
static void bootp_reply(Slirp *slirp,
const struct bootp_t *bp,
const uint8_t *bp_end)
{
BOOTPClient *bc = NULL;
struct mbuf *m;
@ -201,14 +213,13 @@ static void bootp_reply(Slirp *slirp, const struct bootp_t *bp)
struct sockaddr_in saddr, daddr;
struct in_addr bcast_addr;
int val;
uint8_t *q, *pp, plen;
uint8_t *q, *end, *pp, plen;
uint8_t client_ethaddr[ETH_ALEN];
dhcp_options_t dhcp_opts;
size_t spaceleft;
char msg[80];
/* extract exact DHCP msg type */
dhcp_decode(slirp, bp, &dhcp_opts);
dhcp_decode(slirp, bp, bp_end, &dhcp_opts);
DPRINTF("bootp packet op=%d msgtype=%d", bp->bp_op, dhcp_opts.msg_type);
if (dhcp_opts.req_addr.s_addr != htonl(0L))
DPRINTF(" req_addr=%08x\n", ntohl(dhcp_opts.req_addr.s_addr));
@ -230,9 +241,10 @@ static void bootp_reply(Slirp *slirp, const struct bootp_t *bp)
return;
}
m->m_data += IF_MAXLINKHDR;
m_inc(m, sizeof(struct bootp_t) + DHCP_OPT_LEN);
rbp = (struct bootp_t *)m->m_data;
m->m_data += sizeof(struct udpiphdr);
memset(rbp, 0, sizeof(struct bootp_t));
memset(rbp, 0, sizeof(struct bootp_t) + DHCP_OPT_LEN);
if (dhcp_opts.msg_type == DHCPDISCOVER) {
if (dhcp_opts.req_addr.s_addr != htonl(0L)) {
@ -286,6 +298,7 @@ static void bootp_reply(Slirp *slirp, const struct bootp_t *bp)
rbp->bp_siaddr = saddr.sin_addr; /* Server IP address */
q = rbp->bp_vend;
end = rbp->bp_vend + DHCP_OPT_LEN;
memcpy(q, rfc1533_cookie, 4);
q += 4;
@ -325,7 +338,6 @@ static void bootp_reply(Slirp *slirp, const struct bootp_t *bp)
memcpy(q, &val, 4);
}
q += 4;
dhcp_opts.lease_time = 0;
if (*slirp->client_hostname || (dhcp_opts.hostname != NULL)) {
val = 0;
if (*slirp->client_hostname) {
@ -351,8 +363,7 @@ static void bootp_reply(Slirp *slirp, const struct bootp_t *bp)
pp = dhcp_opts.params;
plen = dhcp_opts.params_len;
while (plen-- > 0) {
spaceleft = sizeof(rbp->bp_vend) - (q - rbp->bp_vend);
if (spaceleft < 6) break;
if (q + 6 >= end) break;
switch (*pp++) {
case RFC1533_NETMASK:
*q++ = RFC1533_NETMASK;
@ -378,9 +389,8 @@ static void bootp_reply(Slirp *slirp, const struct bootp_t *bp)
break;
case RFC1533_DOMAINNAME:
if (slirp->vdomainname) {
spaceleft = sizeof(rbp->bp_vend) - (q - rbp->bp_vend);
val = strlen(slirp->vdomainname);
if (val + 1 > (int)spaceleft) {
if (q + val + 2 >= end) {
slirp_warning("DHCP packet size exceeded, omitting domain name option.", slirp->opaque);
} else {
*q++ = RFC1533_DOMAINNAME;
@ -413,9 +423,8 @@ static void bootp_reply(Slirp *slirp, const struct bootp_t *bp)
break;
case RFC2132_TFTP_SERVER_NAME:
if (slirp->tftp_server_name) {
spaceleft = sizeof(rbp->bp_vend) - (q - rbp->bp_vend);
val = strlen(slirp->tftp_server_name);
if (val + 1 > (int)spaceleft) {
if (q + val + 2 >= end) {
slirp_warning("DHCP packet size exceeded, omitting tftp-server-name option.", slirp->opaque);
} else {
*q++ = RFC2132_TFTP_SERVER_NAME;
@ -437,15 +446,35 @@ static void bootp_reply(Slirp *slirp, const struct bootp_t *bp)
}
if (slirp->vdnssearch) {
spaceleft = sizeof(rbp->bp_vend) - (q - rbp->bp_vend);
val = slirp->vdnssearch_len;
if (val + 1 > (int)spaceleft) {
if (q + val >= end) {
slirp_warning("DHCP packet size exceeded, omitting domain-search option.", slirp->opaque);
} else {
memcpy(q, slirp->vdnssearch, val);
q += val;
}
}
/* this allows to support UEFI HTTP boot: according to the UEFI
specification, DHCP server must send vendor class identifier option
set to "HTTPClient" string, when responding to DHCP requests as part
of the UEFI HTTP boot
we assume that, if the bootfile parameter was configured as an http
URL, the user intends to perform UEFI HTTP boot, so send this option
automatically */
if (slirp->bootp_filename && !strncmp(slirp->bootp_filename, "http://", 7)) {
val = strlen(UEFI_HTTP_VENDOR_CLASS_ID);
if (q + val + 2 >= end) {
slirp_warning("DHCP packet size exceeded, omitting vendor class id option.",
slirp->opaque);
} else {
*q++ = RFC2132_VENDOR_CLASS_ID;
*q++ = val;
memcpy(q, UEFI_HTTP_VENDOR_CLASS_ID, val);
q += val;
}
}
} else {
static const char nak_msg[] = "requested address not available";
@ -466,17 +495,17 @@ static void bootp_reply(Slirp *slirp, const struct bootp_t *bp)
if (dhcp_opts.params != NULL) free(dhcp_opts.params);
m->m_len = sizeof(struct bootp_t) -
m->m_len = sizeof(struct bootp_t) + (end - rbp->bp_vend) -
sizeof(struct ip) - sizeof(struct udphdr);
udp_output2(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
}
void bootp_input(struct mbuf *m)
{
struct bootp_t *bp = mtod(m, struct bootp_t *);
struct bootp_t *bp = (struct bootp_t *)mtod_check(m, sizeof(struct bootp_t));
if (bp->bp_op == BOOTP_REQUEST) {
bootp_reply(m->slirp, bp);
if (!m->slirp->disable_dhcp && bp && bp->bp_op == BOOTP_REQUEST) {
bootp_reply(m->slirp, bp, (uint8_t*)m_end(m));
}
}

View File

@ -1,13 +1,14 @@
/* SPDX-License-Identifier: BSD-3-Clause */
/* bootp/dhcp defines */
#ifndef SLIRP_BOOTP_H
#define SLIRP_BOOTP_H 1
#define SLIRP_BOOTP_H
#define BOOTP_SERVER 67
#define BOOTP_CLIENT 68
#define BOOTP_SERVER 67
#define BOOTP_CLIENT 68
#define BOOTP_REQUEST 1
#define BOOTP_REPLY 2
#define BOOTP_REQUEST 1
#define BOOTP_REPLY 2
#define RFC1533_COOKIE 99, 130, 83, 99
#define RFC1533_PAD 0
@ -61,40 +62,41 @@
#define RFC1533_XFS 48
#define RFC1533_XDM 49
#define RFC2132_REQ_ADDR 50
#define RFC2132_REQ_ADDR 50
#define RFC2132_LEASE_TIME 51
#define RFC2132_MSG_TYPE 53
#define RFC2132_SRV_ID 54
#define RFC2132_PARAM_LIST 55
#define RFC2132_MESSAGE 56
#define RFC2132_MAX_SIZE 57
#define RFC2132_MSG_TYPE 53
#define RFC2132_SRV_ID 54
#define RFC2132_PARAM_LIST 55
#define RFC2132_MESSAGE 56
#define RFC2132_MAX_SIZE 57
#define RFC2132_RENEWAL_TIME 58
#define RFC2132_REBIND_TIME 59
#define RFC2132_VENDOR_CLASS_ID 60
#define RFC2132_TFTP_SERVER_NAME 66
#define DHCPDISCOVER 1
#define DHCPOFFER 2
#define DHCPREQUEST 3
#define DHCPACK 5
#define DHCPNAK 6
#define DHCPDISCOVER 1
#define DHCPOFFER 2
#define DHCPREQUEST 3
#define DHCPACK 5
#define DHCPNAK 6
#define RFC1533_VENDOR_MAJOR 0
#define RFC1533_VENDOR_MINOR 0
#define RFC1533_VENDOR_MAJOR 0
#define RFC1533_VENDOR_MINOR 0
#define RFC1533_VENDOR_MAGIC 128
#define RFC1533_VENDOR_ADDPARM 129
#define RFC1533_VENDOR_ETHDEV 130
#define RFC1533_VENDOR_HOWTO 132
#define RFC1533_VENDOR_MNUOPTS 160
#define RFC1533_VENDOR_MAGIC 128
#define RFC1533_VENDOR_ADDPARM 129
#define RFC1533_VENDOR_ETHDEV 130
#define RFC1533_VENDOR_HOWTO 132
#define RFC1533_VENDOR_MNUOPTS 160
#define RFC1533_VENDOR_SELECTION 176
#define RFC1533_VENDOR_MOTD 184
#define RFC1533_VENDOR_NUMOFMOTD 8
#define RFC1533_VENDOR_IMG 192
#define RFC1533_VENDOR_NUMOFIMG 16
#define RFC1533_VENDOR_MOTD 184
#define RFC1533_VENDOR_NUMOFMOTD 8
#define RFC1533_VENDOR_IMG 192
#define RFC1533_VENDOR_NUMOFIMG 16
#define RFC1533_END 255
#define BOOTP_VENDOR_LEN 64
#define DHCP_OPT_LEN 312
#define RFC1533_END 255
#define BOOTP_VENDOR_LEN 64
#define DHCP_OPT_LEN 312
struct bootp_t {
struct ip ip;
@ -112,8 +114,8 @@ struct bootp_t {
struct in_addr bp_giaddr;
uint8_t bp_hwaddr[16];
uint8_t bp_sname[64];
uint8_t bp_file[128];
uint8_t bp_vend[DHCP_OPT_LEN];
char bp_file[128];
uint8_t bp_vend[];
};
typedef struct {
@ -123,6 +125,7 @@ typedef struct {
#define NB_BOOTP_CLIENTS 16
/* Process a bootp packet from the guest */
void bootp_input(struct mbuf *m);
#endif

View File

@ -15,7 +15,7 @@
#define IF_MRU 1500
#define IF_COMP IF_AUTOCOMP /* Flags for compression */
/* 2 for alignment, 14 for ethernet, 40 for TCP/IP */
#define IF_MAXLINKHDR (2 + 14 + 40)
/* 2 for alignment, 14 for ethernet */
#define IF_MAXLINKHDR (2 + ETH_HLEN)
#endif

View File

@ -240,4 +240,20 @@ dtom(Slirp *slirp, void *dat)
return (struct mbuf *)0;
}
void *mtod_check(struct mbuf *m, size_t len)
{
if (m->m_len >= (int)len) {
return m->m_data;
}
DEBUG_ERROR("mtod failed");
return NULL;
}
void *m_end(struct mbuf *m)
{
return m->m_data + m->m_len;
}
#endif

View File

@ -111,6 +111,13 @@ void m_adj(struct mbuf *, int);
int m_copy(struct mbuf *, struct mbuf *, int, int);
struct mbuf * dtom(Slirp *, void *);
/* Check that the mbuf contains at least len bytes, and return the data */
void *mtod_check(struct mbuf *, size_t len);
/* Return the end of the data of the mbuf */
void *m_end(struct mbuf *);
/* Initialize the ifs queue of the mbuf */
static inline void ifs_init(struct mbuf *ifm)
{
ifm->ifs_next = ifm->ifs_prev = ifm;

View File

@ -224,7 +224,7 @@ typedef struct ArpTable {
int next_victim;
} ArpTable;
void arp_table_add(Slirp *slirp, uint32_t ip_addr, uint8_t ethaddr[ETH_ALEN]);
void arp_table_add(Slirp *slirp, uint32_t ip_addr, const uint8_t ethaddr[ETH_ALEN]);
bool arp_table_search(Slirp *slirp, uint32_t ip_addr,
uint8_t out_ethaddr[ETH_ALEN]);
@ -239,6 +239,7 @@ struct Slirp {
struct in_addr vnetwork_addr;
struct in_addr vnetwork_mask;
struct in_addr vhost_addr;
bool disable_dhcp; /* slirp will not reply to any DHCP requests */
struct in_addr vdhcp_startaddr;
struct in_addr vnameserver_addr;