Skip to content
Commits on Source (28)
......@@ -5,6 +5,34 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
### Added
### Changed
### Deprecated
### Fixed
## [4.6.0] - 2021-06-14
### Added
- mbuf: Add debugging helpers for allocation. !90
### Changed
- Revert "Set macOS deployment target to macOS 10.4". !93
### Fixed
- mtod()-related buffer overflows (CVE-2021-3592 #44, CVE-2021-3593 #45,
CVE-2021-3594 #47, CVE-2021-3595 #46).
- poll_fd: add missing fd registration for UDP and ICMP
- ncsi: make ncsi_calculate_checksum work with unaligned data. !89
- Various typos and doc fixes. !88
## [4.5.0] - 2021-05-18
### Added
......@@ -148,7 +176,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Standalone project, removing any QEMU dependency.
- License clarifications.
[unreleased]: https://gitlab.freedesktop.org/slirp/libslirp/compare/v4.5.0...master
[Unreleased]: https://gitlab.freedesktop.org/slirp/libslirp/compare/v4.6.0...master
[4.6.0]: https://gitlab.freedesktop.org/slirp/libslirp/compare/v4.5.0...v4.6.0
[4.5.0]: https://gitlab.freedesktop.org/slirp/libslirp/compare/v4.4.0...v4.5.0
[4.4.0]: https://gitlab.freedesktop.org/slirp/libslirp/compare/v4.3.1...v4.4.0
[4.3.1]: https://gitlab.freedesktop.org/slirp/libslirp/compare/v4.3.0...v4.3.1
......
project('libslirp', 'c',
version : '4.5.0',
version : '4.6.0',
license : 'BSD-3-Clause',
default_options : ['warning_level=1', 'c_std=gnu99'],
meson_version : '>= 0.50',
......@@ -72,6 +72,10 @@ cargs = [
'-DG_LOG_DOMAIN="Slirp"',
]
if cc.check_header('valgrind/valgrind.h')
cargs += [ '-DHAVE_VALGRIND=1' ]
endif
sources = [
'src/arp_table.c',
'src/bootp.c',
......@@ -113,11 +117,6 @@ if cc.has_link_argument(vflag_test)
vflag += vflag_test
endif
if host_system == 'darwin'
cargs += '-mmacosx-version-min=10.4'
vflag += '-mmacosx-version-min=10.4'
endif
install_devel = not meson.is_subproject()
configure_file(
......
......@@ -92,21 +92,22 @@ found:
return bc;
}
static void dhcp_decode(const struct bootp_t *bp, int *pmsg_type,
static void dhcp_decode(const struct bootp_t *bp,
const uint8_t *bp_end,
int *pmsg_type,
struct in_addr *preq_addr)
{
const uint8_t *p, *p_end;
const uint8_t *p;
int len, tag;
*pmsg_type = 0;
preq_addr->s_addr = htonl(0L);
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++;
......@@ -114,10 +115,10 @@ static void dhcp_decode(const struct bootp_t *bp, int *pmsg_type,
break;
} else {
p++;
if (p >= p_end)
if (p >= bp_end)
break;
len = *p++;
if (p + len > p_end) {
if (p + len > bp_end) {
break;
}
DPRINTF("dhcp: tag=%d len=%d\n", tag, len);
......@@ -144,7 +145,9 @@ static void dhcp_decode(const struct bootp_t *bp, int *pmsg_type,
}
}
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;
......@@ -157,7 +160,7 @@ static void bootp_reply(Slirp *slirp, const struct bootp_t *bp)
uint8_t client_ethaddr[ETH_ALEN];
/* extract exact DHCP msg type */
dhcp_decode(bp, &dhcp_msg_type, &preq_addr);
dhcp_decode(bp, bp_end, &dhcp_msg_type, &preq_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));
......@@ -179,9 +182,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_msg_type == DHCPDISCOVER) {
if (preq_addr.s_addr != htonl(0L)) {
......@@ -235,7 +239,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 = (uint8_t *)&rbp[1];
end = rbp->bp_vend + DHCP_OPT_LEN;
memcpy(q, rfc1533_cookie, 4);
q += 4;
......@@ -361,9 +365,9 @@ static void bootp_reply(Slirp *slirp, const struct bootp_t *bp)
void bootp_input(struct mbuf *m)
{
struct bootp_t *bp = mtod(m, struct bootp_t *);
struct bootp_t *bp = mtod_check(m, sizeof(struct bootp_t));
if (bp->bp_op == BOOTP_REQUEST) {
bootp_reply(m->slirp, bp);
if (bp && bp->bp_op == BOOTP_REQUEST) {
bootp_reply(m->slirp, bp, m_end(m));
}
}
......@@ -114,7 +114,7 @@ struct bootp_t {
uint8_t bp_hwaddr[16];
uint8_t bp_sname[64];
char bp_file[128];
uint8_t bp_vend[DHCP_OPT_LEN];
uint8_t bp_vend[];
};
typedef struct {
......
......@@ -41,6 +41,8 @@ void if_init(Slirp *slirp)
void if_output(struct socket *so, struct mbuf *ifm)
{
Slirp *slirp = ifm->slirp;
M_DUP_DEBUG(slirp, ifm, 0, 0);
struct mbuf *ifq;
int on_fastq = 1;
......
......@@ -321,6 +321,8 @@ static void ndp_send_na(Slirp *slirp, struct ip6 *ip, struct icmp6 *icmp)
static void ndp_input(struct mbuf *m, Slirp *slirp, struct ip6 *ip,
struct icmp6 *icmp)
{
g_assert(M_ROOMBEFORE(m) >= ETH_HLEN);
m->m_len += ETH_HLEN;
m->m_data -= ETH_HLEN;
struct ethhdr *eth = mtod(m, struct ethhdr *);
......@@ -383,9 +385,12 @@ static void ndp_input(struct mbuf *m, Slirp *slirp, struct ip6 *ip,
*/
void icmp6_input(struct mbuf *m)
{
Slirp *slirp = m->slirp;
/* NDP reads the ethernet header for gratuitous NDP */
M_DUP_DEBUG(slirp, m, 1, ETH_HLEN);
struct icmp6 *icmp;
struct ip6 *ip = mtod(m, struct ip6 *);
Slirp *slirp = m->slirp;
int hlen = sizeof(struct ip6);
DEBUG_CALL("icmp6_input");
......
......@@ -23,8 +23,11 @@ void ip6_cleanup(Slirp *slirp)
void ip6_input(struct mbuf *m)
{
struct ip6 *ip6;
Slirp *slirp = m->slirp;
/* NDP reads the ethernet header for gratuitous NDP */
M_DUP_DEBUG(slirp, m, 1, TCPIPHDR_DELTA + 2 + ETH_HLEN);
struct ip6 *ip6;
if (!slirp->in6_enabled) {
goto bad;
......
......@@ -15,6 +15,9 @@
*/
int ip6_output(struct socket *so, struct mbuf *m, int fast)
{
Slirp *slirp = m->slirp;
M_DUP_DEBUG(slirp, m, 0, 0);
struct ip6 *ip = mtod(m, struct ip6 *);
DEBUG_CALL("ip6_output");
......
......@@ -85,6 +85,9 @@ void icmp_cleanup(Slirp *slirp)
static int icmp_send(struct socket *so, struct mbuf *m, int hlen)
{
Slirp *slirp = m->slirp;
M_DUP_DEBUG(slirp, m, 0, 0);
struct ip *ip = mtod(m, struct ip *);
struct sockaddr_in addr;
......@@ -92,6 +95,7 @@ static int icmp_send(struct socket *so, struct mbuf *m, int hlen)
if (so->s == -1) {
return -1;
}
so->slirp->cb->register_poll_fd(so->s, so->slirp->opaque);
if (slirp_bind_outbound(so, AF_INET) != 0) {
// bind failed - close socket
......@@ -136,10 +140,12 @@ void icmp_detach(struct socket *so)
*/
void icmp_input(struct mbuf *m, int hlen)
{
Slirp *slirp = m->slirp;
M_DUP_DEBUG(slirp, m, 0, 0);
register struct icmp *icp;
register struct ip *ip = mtod(m, struct ip *);
int icmplen = ip->ip_len;
Slirp *slirp = m->slirp;
DEBUG_CALL("icmp_input");
DEBUG_ARG("m = %p", m);
......@@ -180,8 +186,13 @@ void icmp_input(struct mbuf *m, int hlen)
so = socreate(slirp);
if (icmp_send(so, m, hlen) == 0) {
/* We could send this as ICMP, good! */
return;
}
/* We could not send this as ICMP, try to send it on UDP echo
* service (7), wishfully hoping that it is open there. */
if (udp_attach(so, AF_INET) == -1) {
DEBUG_MISC("icmp_input udp_attach errno = %d-%s", errno,
strerror(errno));
......@@ -245,7 +256,7 @@ void icmp_input(struct mbuf *m, int hlen)
default:
m_free(m);
} /* swith */
} /* switch */
end_error:
/* m is m_free()'d xor put in a socket xor or given to ip_send */
......
......@@ -70,6 +70,8 @@ void ip_cleanup(Slirp *slirp)
void ip_input(struct mbuf *m)
{
Slirp *slirp = m->slirp;
M_DUP_DEBUG(slirp, m, 0, TCPIPHDR_DELTA);
register struct ip *ip;
int hlen;
......@@ -347,7 +349,7 @@ insert:
/*
* If the fragments concatenated to an mbuf that's bigger than the total
* size of the fragment and the mbuf was not already using an m_ext buffer,
* then an m_ext buffer was alloced. But fp->ipq_next points to the old
* then an m_ext buffer was allocated. But fp->ipq_next points to the old
* buffer (in the mbuf), so we must point ip into the new buffer.
*/
if (m->m_flags & M_EXT) {
......
......@@ -51,6 +51,8 @@
int ip_output(struct socket *so, struct mbuf *m0)
{
Slirp *slirp = m0->slirp;
M_DUP_DEBUG(slirp, m0, 0, 0);
register struct ip *ip;
register struct mbuf *m = m0;
register int hlen = sizeof(struct ip);
......
......@@ -62,7 +62,7 @@ typedef struct SlirpCb {
void *(*timer_new)(SlirpTimerCb cb, void *cb_opaque, void *opaque);
/* Remove and free a timer */
void (*timer_free)(void *timer, void *opaque);
/* Modify a timer to expire at @expire_time */
/* Modify a timer to expire at @expire_time (ms) */
void (*timer_mod)(void *timer, int64_t expire_time, void *opaque);
/* Register a fd for future polling */
void (*register_poll_fd)(int fd, void *opaque);
......
......@@ -69,10 +69,10 @@ struct mbuf *m_get(Slirp *slirp)
DEBUG_CALL("m_get");
if (slirp->m_freelist.qh_link == &slirp->m_freelist) {
if (MBUF_DEBUG || slirp->m_freelist.qh_link == &slirp->m_freelist) {
m = g_malloc(SLIRP_MSIZE(slirp->if_mtu));
slirp->mbuf_alloced++;
if (slirp->mbuf_alloced > MBUF_THRESH)
if (MBUF_DEBUG || slirp->mbuf_alloced > MBUF_THRESH)
flags = M_DOFREE;
m->slirp = slirp;
} else {
......@@ -227,3 +227,55 @@ struct mbuf *dtom(Slirp *slirp, void *dat)
return (struct mbuf *)0;
}
/*
* Duplicate the mbuf
*
* copy_header specifies whether the bytes before m_data should also be copied.
* header_size specifies how many bytes are to be reserved before m_data.
*/
struct mbuf *m_dup(Slirp *slirp, struct mbuf *m,
bool copy_header,
size_t header_size)
{
struct mbuf *n;
int mcopy_result;
/* The previous mbuf was supposed to have it already, we can check it along
* the way */
assert(M_ROOMBEFORE(m) >= header_size);
n = m_get(slirp);
m_inc(n, m->m_len + header_size);
if (copy_header) {
m->m_len += header_size;
m->m_data -= header_size;
mcopy_result = m_copy(n, m, 0, m->m_len + header_size);
n->m_data += header_size;
m->m_len -= header_size;
m->m_data += header_size;
} else {
n->m_data += header_size;
mcopy_result = m_copy(n, m, 0, m->m_len);
}
g_assert(mcopy_result == 0);
return n;
}
void *mtod_check(struct mbuf *m, size_t len)
{
if (m->m_len >= len) {
return m->m_data;
}
DEBUG_ERROR("mtod failed");
return NULL;
}
void *m_end(struct mbuf *m)
{
return m->m_data + m->m_len;
}
......@@ -73,6 +73,13 @@
*/
#define M_FREEROOM(m) (M_ROOM(m) - (m)->m_len)
/*
* How much free room there is before m_data
*/
#define M_ROOMBEFORE(m) \
(((m)->m_flags & M_EXT) ? (m)->m_data - (m)->m_ext \
: (m)->m_data - (m)->m_dat)
struct mbuf {
/* XXX should union some of these! */
/* header at beginning of each mbuf: */
......@@ -117,11 +124,69 @@ void m_cat(register struct mbuf *, register struct mbuf *);
void m_inc(struct mbuf *, int);
void m_adj(struct mbuf *, int);
int m_copy(struct mbuf *, struct mbuf *, int, int);
struct mbuf *m_dup(Slirp *slirp, struct mbuf *m, bool copy_header, size_t header_size);
struct mbuf *dtom(Slirp *, void *);
void *mtod_check(struct mbuf *, size_t len);
void *m_end(struct mbuf *);
static inline void ifs_init(struct mbuf *ifm)
{
ifm->ifs_next = ifm->ifs_prev = ifm;
}
#ifdef DEBUG
# define MBUF_DEBUG 1
#else
# ifdef HAVE_VALGRIND
# include <valgrind/valgrind.h>
# define MBUF_DEBUG RUNNING_ON_VALGRIND
# else
# define MBUF_DEBUG 0
# endif
#endif
/*
* When a function is given an mbuf as well as the responsibility to free it, we
* want valgrind etc. to properly identify the new responsible for the
* free. Achieve this by making a new copy. For instance:
*
* f0(void) {
* struct mbuf *m = m_get(slirp);
* [...]
* switch (something) {
* case 1:
* f1(m);
* break;
* case 2:
* f2(m);
* break;
* [...]
* }
* }
*
* f1(struct mbuf *m) {
* M_DUP_DEBUG(m->slirp, m);
* [...]
* m_free(m); // but author of f1 might be forgetting this
* }
*
* f0 transfers the freeing responsibility to f1, f2, etc. Without the
* M_DUP_DEBUG call in f1, valgrind would tell us that it is f0 where the buffer
* was allocated, but it's difficult to know whether a leak is actually in f0,
* or in f1, or in f2, etc. Duplicating the mbuf in M_DUP_DEBUG each time the
* responsibility is transferred allows to immediately know where the leak
* actually is.
*/
#define M_DUP_DEBUG(slirp, m, copy_header, header_size) do { \
if (MBUF_DEBUG) { \
struct mbuf *__n; \
__n = m_dup((slirp), (m), (copy_header), (header_size)); \
m_free(m); \
(m) = __n; \
} else { \
(void) (slirp); (void) (copy_header); \
g_assert(M_ROOMBEFORE(m) >= (header_size)); \
} \
} while(0)
#endif
......@@ -49,36 +49,36 @@ struct ncsi_pkt_hdr {
unsigned char channel; /* Network controller ID */
__be16 length; /* Payload length */
__be32 reserved1[2]; /* Reserved */
};
} SLIRP_PACKED;
struct ncsi_cmd_pkt_hdr {
struct ncsi_pkt_hdr common; /* Common NCSI packet header */
};
} SLIRP_PACKED;
struct ncsi_rsp_pkt_hdr {
struct ncsi_pkt_hdr common; /* Common NCSI packet header */
__be16 code; /* Response code */
__be16 reason; /* Response reason */
};
} SLIRP_PACKED;
struct ncsi_aen_pkt_hdr {
struct ncsi_pkt_hdr common; /* Common NCSI packet header */
unsigned char reserved2[3]; /* Reserved */
unsigned char type; /* AEN packet type */
};
} SLIRP_PACKED;
/* NCSI common command packet */
struct ncsi_cmd_pkt {
struct ncsi_cmd_pkt_hdr cmd; /* Command header */
__be32 checksum; /* Checksum */
unsigned char pad[26];
};
} SLIRP_PACKED;
struct ncsi_rsp_pkt {
struct ncsi_rsp_pkt_hdr rsp; /* Response header */
__be32 checksum; /* Checksum */
unsigned char pad[22];
};
} SLIRP_PACKED;
/* Select Package */
struct ncsi_cmd_sp_pkt {
......@@ -87,7 +87,7 @@ struct ncsi_cmd_sp_pkt {
unsigned char hw_arbitration; /* HW arbitration */
__be32 checksum; /* Checksum */
unsigned char pad[22];
};
} SLIRP_PACKED;
/* Disable Channel */
struct ncsi_cmd_dc_pkt {
......@@ -96,7 +96,7 @@ struct ncsi_cmd_dc_pkt {
unsigned char ald; /* Allow link down */
__be32 checksum; /* Checksum */
unsigned char pad[22];
};
} SLIRP_PACKED;
/* Reset Channel */
struct ncsi_cmd_rc_pkt {
......@@ -104,7 +104,7 @@ struct ncsi_cmd_rc_pkt {
__be32 reserved; /* Reserved */
__be32 checksum; /* Checksum */
unsigned char pad[22];
};
} SLIRP_PACKED;
/* AEN Enable */
struct ncsi_cmd_ae_pkt {
......@@ -114,7 +114,7 @@ struct ncsi_cmd_ae_pkt {
__be32 mode; /* AEN working mode */
__be32 checksum; /* Checksum */
unsigned char pad[18];
};
} SLIRP_PACKED;
/* Set Link */
struct ncsi_cmd_sl_pkt {
......@@ -123,7 +123,7 @@ struct ncsi_cmd_sl_pkt {
__be32 oem_mode; /* OEM link mode */
__be32 checksum; /* Checksum */
unsigned char pad[18];
};
} SLIRP_PACKED;
/* Set VLAN Filter */
struct ncsi_cmd_svf_pkt {
......@@ -135,7 +135,7 @@ struct ncsi_cmd_svf_pkt {
unsigned char enable; /* Enable or disable */
__be32 checksum; /* Checksum */
unsigned char pad[14];
};
} SLIRP_PACKED;
/* Enable VLAN */
struct ncsi_cmd_ev_pkt {
......@@ -144,7 +144,7 @@ struct ncsi_cmd_ev_pkt {
unsigned char mode; /* VLAN filter mode */
__be32 checksum; /* Checksum */
unsigned char pad[22];
};
} SLIRP_PACKED;
/* Set MAC Address */
struct ncsi_cmd_sma_pkt {
......@@ -154,7 +154,7 @@ struct ncsi_cmd_sma_pkt {
unsigned char at_e; /* Addr type and operation */
__be32 checksum; /* Checksum */
unsigned char pad[18];
};
} SLIRP_PACKED;
/* Enable Broadcast Filter */
struct ncsi_cmd_ebf_pkt {
......@@ -162,7 +162,7 @@ struct ncsi_cmd_ebf_pkt {
__be32 mode; /* Filter mode */
__be32 checksum; /* Checksum */
unsigned char pad[22];
};
} SLIRP_PACKED;
/* Enable Global Multicast Filter */
struct ncsi_cmd_egmf_pkt {
......@@ -170,7 +170,7 @@ struct ncsi_cmd_egmf_pkt {
__be32 mode; /* Global MC mode */
__be32 checksum; /* Checksum */
unsigned char pad[22];
};
} SLIRP_PACKED;
/* Set NCSI Flow Control */
struct ncsi_cmd_snfc_pkt {
......@@ -179,7 +179,7 @@ struct ncsi_cmd_snfc_pkt {
unsigned char mode; /* Flow control mode */
__be32 checksum; /* Checksum */
unsigned char pad[22];
};
} SLIRP_PACKED;
/* Get Link Status */
struct ncsi_rsp_gls_pkt {
......@@ -189,7 +189,7 @@ struct ncsi_rsp_gls_pkt {
__be32 oem_status; /* OEM link status */
__be32 checksum;
unsigned char pad[10];
};
} SLIRP_PACKED;
/* Get Version ID */
struct ncsi_rsp_gvi_pkt {
......@@ -202,7 +202,7 @@ struct ncsi_rsp_gvi_pkt {
__be16 pci_ids[4]; /* PCI IDs */
__be32 mf_id; /* Manufacture ID */
__be32 checksum;
};
} SLIRP_PACKED;
/* Get Capabilities */
struct ncsi_rsp_gc_pkt {
......@@ -220,7 +220,7 @@ struct ncsi_rsp_gc_pkt {
unsigned char vlan_mode; /* VLAN mode */
unsigned char channel_cnt; /* Channel count */
__be32 checksum; /* Checksum */
};
} SLIRP_PACKED;
/* Get Parameters */
struct ncsi_rsp_gp_pkt {
......@@ -241,7 +241,7 @@ struct ncsi_rsp_gp_pkt {
unsigned char mac[6]; /* Supported MAC addr */
__be16 vlan; /* Supported VLAN tags */
__be32 checksum; /* Checksum */
};
} SLIRP_PACKED;
/* Get Controller Packet Statistics */
struct ncsi_rsp_gcps_pkt {
......@@ -288,7 +288,7 @@ struct ncsi_rsp_gcps_pkt {
__be32 rx_runt_pkts; /* Rx error runt packets */
__be32 rx_jabber_pkts; /* Rx error jabber packets */
__be32 checksum; /* Checksum */
};
} SLIRP_PACKED;
/* Get NCSI Statistics */
struct ncsi_rsp_gns_pkt {
......@@ -301,7 +301,7 @@ struct ncsi_rsp_gns_pkt {
__be32 tx_pkts; /* Tx NCSI packets */
__be32 tx_aen_pkts; /* Tx AEN packets */
__be32 checksum; /* Checksum */
};
} SLIRP_PACKED;
/* Get NCSI Pass-through Statistics */
struct ncsi_rsp_gnpts_pkt {
......@@ -316,21 +316,21 @@ struct ncsi_rsp_gnpts_pkt {
__be32 rx_us_err; /* Rx undersize errors */
__be32 rx_os_err; /* Rx oversize errors */
__be32 checksum; /* Checksum */
};
} SLIRP_PACKED;
/* Get package status */
struct ncsi_rsp_gps_pkt {
struct ncsi_rsp_pkt_hdr rsp; /* Response header */
__be32 status; /* Hardware arbitration status */
__be32 checksum;
};
} SLIRP_PACKED;
/* Get package UUID */
struct ncsi_rsp_gpuuid_pkt {
struct ncsi_rsp_pkt_hdr rsp; /* Response header */
unsigned char uuid[16]; /* UUID */
__be32 checksum;
};
} SLIRP_PACKED;
/* AEN: Link State Change */
struct ncsi_aen_lsc_pkt {
......@@ -339,14 +339,14 @@ struct ncsi_aen_lsc_pkt {
__be32 oem_status; /* OEM link status */
__be32 checksum; /* Checksum */
unsigned char pad[14];
};
} SLIRP_PACKED;
/* AEN: Configuration Required */
struct ncsi_aen_cr_pkt {
struct ncsi_aen_pkt_hdr aen; /* AEN header */
__be32 checksum; /* Checksum */
unsigned char pad[22];
};
} SLIRP_PACKED;
/* AEN: Host Network Controller Driver Status Change */
struct ncsi_aen_hncdsc_pkt {
......@@ -354,7 +354,7 @@ struct ncsi_aen_hncdsc_pkt {
__be32 status; /* Status */
__be32 checksum; /* Checksum */
unsigned char pad[18];
};
} SLIRP_PACKED;
/* NCSI packet revision */
#define NCSI_PKT_REVISION 0x01
......
......@@ -38,7 +38,7 @@
#include "ncsi-pkt.h"
static uint32_t ncsi_calculate_checksum(uint16_t *data, int len)
static uint32_t ncsi_calculate_checksum(uint8_t *data, int len)
{
uint32_t checksum = 0;
int i;
......@@ -47,8 +47,8 @@ static uint32_t ncsi_calculate_checksum(uint16_t *data, int len)
* 32-bit unsigned sum of the NC-SI packet header and NC-SI packet
* payload interpreted as a series of 16-bit unsigned integer values.
*/
for (i = 0; i < len / 2; i++) {
checksum += htons(data[i]);
for (i = 0; i < len; i += 2) {
checksum += (((uint16_t) data[i]) << 8) + data[i+1];
}
checksum = (~checksum + 1);
......@@ -188,7 +188,7 @@ void ncsi_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
}
/* Add the optional checksum at the end of the frame. */
checksum = ncsi_calculate_checksum((uint16_t *)rnh, ncsi_rsp_len);
checksum = ncsi_calculate_checksum((uint8_t *)rnh, ncsi_rsp_len);
pchecksum = (uint32_t *)((void *)rnh + ncsi_rsp_len);
*pchecksum = htonl(checksum);
ncsi_rsp_len += 4;
......
......@@ -82,6 +82,9 @@ static void tcp_xmit_timer(register struct tcpcb *tp, int rtt);
static int tcp_reass(register struct tcpcb *tp, register struct tcpiphdr *ti,
struct mbuf *m)
{
if (m)
M_DUP_DEBUG(m->slirp, m, 0, 0);
register struct tcpiphdr *q;
struct socket *so = tp->t_socket;
int flags;
......@@ -233,6 +236,16 @@ void tcp_input(struct mbuf *m, int iphlen, struct socket *inso,
goto cont_conn;
}
slirp = m->slirp;
switch (af) {
case AF_INET:
M_DUP_DEBUG(slirp, m, 0,
sizeof(struct tcpiphdr) - sizeof(struct ip) - sizeof(struct tcphdr));
break;
case AF_INET6:
M_DUP_DEBUG(slirp, m, 0,
sizeof(struct tcpiphdr) - sizeof(struct ip6) - sizeof(struct tcphdr));
break;
}
ip = mtod(m, struct ip *);
ip6 = mtod(m, struct ip6 *);
......
......@@ -50,7 +50,7 @@ static void tftp_session_terminate(struct tftp_session *spt)
}
static int tftp_session_allocate(Slirp *slirp, struct sockaddr_storage *srcsas,
struct tftp_t *tp)
struct tftphdr *hdr)
{
struct tftp_session *spt;
int k;
......@@ -75,7 +75,7 @@ found:
memcpy(&spt->client_addr, srcsas, sockaddr_size(srcsas));
spt->fd = -1;
spt->block_size = 512;
spt->client_port = tp->udp.uh_sport;
spt->client_port = hdr->udp.uh_sport;
spt->slirp = slirp;
tftp_session_update(spt);
......@@ -84,7 +84,7 @@ found:
}
static int tftp_session_find(Slirp *slirp, struct sockaddr_storage *srcsas,
struct tftp_t *tp)
struct tftphdr *hdr)
{
struct tftp_session *spt;
int k;
......@@ -94,7 +94,7 @@ static int tftp_session_find(Slirp *slirp, struct sockaddr_storage *srcsas,
if (tftp_session_in_use(spt)) {
if (sockaddr_equal(&spt->client_addr, srcsas)) {
if (spt->client_port == tp->udp.uh_sport) {
if (spt->client_port == hdr->udp.uh_sport) {
return k;
}
}
......@@ -148,13 +148,13 @@ static struct tftp_t *tftp_prep_mbuf_data(struct tftp_session *spt,
}
static void tftp_udp_output(struct tftp_session *spt, struct mbuf *m,
struct tftp_t *recv_tp)
struct tftphdr *hdr)
{
if (spt->client_addr.ss_family == AF_INET6) {
struct sockaddr_in6 sa6, da6;
sa6.sin6_addr = spt->slirp->vhost_addr6;
sa6.sin6_port = recv_tp->udp.uh_dport;
sa6.sin6_port = hdr->udp.uh_dport;
da6.sin6_addr = ((struct sockaddr_in6 *)&spt->client_addr)->sin6_addr;
da6.sin6_port = spt->client_port;
......@@ -163,7 +163,7 @@ static void tftp_udp_output(struct tftp_session *spt, struct mbuf *m,
struct sockaddr_in sa4, da4;
sa4.sin_addr = spt->slirp->vhost_addr;
sa4.sin_port = recv_tp->udp.uh_dport;
sa4.sin_port = hdr->udp.uh_dport;
da4.sin_addr = ((struct sockaddr_in *)&spt->client_addr)->sin_addr;
da4.sin_port = spt->client_port;
......@@ -185,14 +185,14 @@ static int tftp_send_oack(struct tftp_session *spt, const char *keys[],
tp = tftp_prep_mbuf_data(spt, m);
tp->tp_op = htons(TFTP_OACK);
tp->hdr.tp_op = htons(TFTP_OACK);
for (i = 0; i < nb; i++) {
n += slirp_fmt0(tp->x.tp_buf + n, sizeof(tp->x.tp_buf) - n, "%s", keys[i]);
n += slirp_fmt0(tp->x.tp_buf + n, sizeof(tp->x.tp_buf) - n, "%u", values[i]);
}
m->m_len = G_SIZEOF_MEMBER(struct tftp_t, tp_op) + n;
tftp_udp_output(spt, m, recv_tp);
m->m_len = G_SIZEOF_MEMBER(struct tftp_t, hdr.tp_op) + n;
tftp_udp_output(spt, m, &recv_tp->hdr);
return 0;
}
......@@ -213,21 +213,21 @@ static void tftp_send_error(struct tftp_session *spt, uint16_t errorcode,
tp = tftp_prep_mbuf_data(spt, m);
tp->tp_op = htons(TFTP_ERROR);
tp->hdr.tp_op = htons(TFTP_ERROR);
tp->x.tp_error.tp_error_code = htons(errorcode);
slirp_pstrcpy((char *)tp->x.tp_error.tp_msg, sizeof(tp->x.tp_error.tp_msg),
msg);
m->m_len = sizeof(struct tftp_t) - (TFTP_BLOCKSIZE_MAX + 2) + 3 +
strlen(msg) - sizeof(struct udphdr);
tftp_udp_output(spt, m, recv_tp);
tftp_udp_output(spt, m, &recv_tp->hdr);
out:
tftp_session_terminate(spt);
}
static void tftp_send_next_block(struct tftp_session *spt,
struct tftp_t *recv_tp)
struct tftphdr *hdr)
{
struct mbuf *m;
struct tftp_t *tp;
......@@ -241,7 +241,7 @@ static void tftp_send_next_block(struct tftp_session *spt,
tp = tftp_prep_mbuf_data(spt, m);
tp->tp_op = htons(TFTP_DATA);
tp->hdr.tp_op = htons(TFTP_DATA);
tp->x.tp_data.tp_block_nr = htons((spt->block_nr + 1) & 0xffff);
nobytes = tftp_read_data(spt, spt->block_nr, tp->x.tp_data.tp_buf,
......@@ -259,7 +259,7 @@ static void tftp_send_next_block(struct tftp_session *spt,
m->m_len = sizeof(struct tftp_t) - (TFTP_BLOCKSIZE_MAX - nobytes) -
sizeof(struct udphdr);
tftp_udp_output(spt, m, recv_tp);
tftp_udp_output(spt, m, hdr);
if (nobytes == spt->block_size) {
tftp_session_update(spt);
......@@ -282,12 +282,12 @@ static void tftp_handle_rrq(Slirp *slirp, struct sockaddr_storage *srcsas,
int nb_options = 0;
/* check if a session already exists and if so terminate it */
s = tftp_session_find(slirp, srcsas, tp);
s = tftp_session_find(slirp, srcsas, &tp->hdr);
if (s >= 0) {
tftp_session_terminate(&slirp->tftp_sessions[s]);
}
s = tftp_session_allocate(slirp, srcsas, tp);
s = tftp_session_allocate(slirp, srcsas, &tp->hdr);
if (s < 0) {
return;
......@@ -413,29 +413,29 @@ static void tftp_handle_rrq(Slirp *slirp, struct sockaddr_storage *srcsas,
}
spt->block_nr = 0;
tftp_send_next_block(spt, tp);
tftp_send_next_block(spt, &tp->hdr);
}
static void tftp_handle_ack(Slirp *slirp, struct sockaddr_storage *srcsas,
struct tftp_t *tp, int pktlen)
struct tftphdr *hdr)
{
int s;
s = tftp_session_find(slirp, srcsas, tp);
s = tftp_session_find(slirp, srcsas, hdr);
if (s < 0) {
return;
}
tftp_send_next_block(&slirp->tftp_sessions[s], tp);
tftp_send_next_block(&slirp->tftp_sessions[s], hdr);
}
static void tftp_handle_error(Slirp *slirp, struct sockaddr_storage *srcsas,
struct tftp_t *tp, int pktlen)
struct tftphdr *hdr)
{
int s;
s = tftp_session_find(slirp, srcsas, tp);
s = tftp_session_find(slirp, srcsas, hdr);
if (s < 0) {
return;
......@@ -446,19 +446,25 @@ static void tftp_handle_error(Slirp *slirp, struct sockaddr_storage *srcsas,
void tftp_input(struct sockaddr_storage *srcsas, struct mbuf *m)
{
struct tftp_t *tp = (struct tftp_t *)m->m_data;
struct tftphdr *hdr = mtod_check(m, sizeof(struct tftphdr));
if (hdr == NULL) {
return;
}
switch (ntohs(tp->tp_op)) {
switch (ntohs(hdr->tp_op)) {
case TFTP_RRQ:
tftp_handle_rrq(m->slirp, srcsas, tp, m->m_len);
tftp_handle_rrq(m->slirp, srcsas,
mtod(m, struct tftp_t *),
m->m_len);
break;
case TFTP_ACK:
tftp_handle_ack(m->slirp, srcsas, tp, m->m_len);
tftp_handle_ack(m->slirp, srcsas, hdr);
break;
case TFTP_ERROR:
tftp_handle_error(m->slirp, srcsas, tp, m->m_len);
tftp_handle_error(m->slirp, srcsas, hdr);
break;
}
}
......@@ -20,9 +20,13 @@
#define TFTP_FILENAME_MAX 512
#define TFTP_BLOCKSIZE_MAX 1428
struct tftp_t {
struct tftphdr {
struct udphdr udp;
uint16_t tp_op;
} SLIRP_PACKED;
struct tftp_t {
struct tftphdr hdr;
union {
struct {
uint16_t tp_block_nr;
......
......@@ -67,6 +67,8 @@ void udp_cleanup(Slirp *slirp)
void udp_input(register struct mbuf *m, int iphlen)
{
Slirp *slirp = m->slirp;
M_DUP_DEBUG(slirp, m, 0, 0);
register struct ip *ip;
register struct udphdr *uh;
int len;
......@@ -94,7 +96,10 @@ void udp_input(register struct mbuf *m, int iphlen)
/*
* Get IP and UDP header together in first mbuf.
*/
ip = mtod(m, struct ip *);
ip = mtod_check(m, iphlen + sizeof(struct udphdr));
if (ip == NULL) {
goto bad;
}
uh = (struct udphdr *)((char *)ip + iphlen);
/*
......@@ -245,6 +250,9 @@ bad:
int udp_output(struct socket *so, struct mbuf *m, struct sockaddr_in *saddr,
struct sockaddr_in *daddr, int iptos)
{
Slirp *slirp = m->slirp;
M_DUP_DEBUG(slirp, m, 0, sizeof(struct udpiphdr));
register struct udpiphdr *ui;
int error = 0;
......@@ -323,6 +331,7 @@ int udp_attach(struct socket *so, unsigned short af)
so->so_expire = curtime + SO_EXPIRE;
insque(so, &so->slirp->udb);
}
so->slirp->cb->register_poll_fd(so->s, so->slirp->opaque);
return (so->s);
}
......