blob: 2970321f6c56124cfaf3060815a464c8a55b20b6 [file]
/* SPDX-License-Identifier: BSD-3-Clause */
#include "slirp.h"
#include "dhcpv6.h"
static uint8_t reply[65536];
static size_t reply_len;
static slirp_ssize_t send_packet(const void *buf, size_t len, void *opaque)
{
g_assert_cmpuint(len, <=, sizeof(reply));
memcpy(reply, buf, len);
reply_len = len;
return len;
}
static int64_t clock_ns(void *opaque) { return 0; }
static void timer_mod(void *timer, int64_t expire, void *opaque) { }
static SlirpCb callbacks = {
.send_packet = send_packet,
.clock_get_ns = clock_ns,
.timer_mod = timer_mod,
};
int main(void)
{
struct in6_addr addrs[200];
SlirpConfig cfg = {
.version = SLIRP_CONFIG_VERSION_MAX,
.if_mtu = 1280,
.advertised_nameservers6 = addrs,
.advertised_nameservers6_len = G_N_ELEMENTS(addrs),
};
struct sockaddr_in6 guest = { .sin6_family = AF_INET6, .sin6_port = htons(546) };
uint8_t mac[ETH_ALEN] = { 0x52, 0x54, 0, 0, 0, 1 };
const uint8_t request[] = { 11, 1, 2, 3, 0, 6, 0, 2, 0, 23 };
struct mbuf *m;
Slirp *s;
unsigned int size;
size_t off;
for (unsigned int i = 0; i < G_N_ELEMENTS(addrs); i++) {
memset(&addrs[i], 0, sizeof(addrs[i]));
addrs[i].s6_addr[0] = 0x20;
addrs[i].s6_addr[1] = 1;
addrs[i].s6_addr[15] = i;
}
guest.sin6_addr.s6_addr[0] = 0xfd;
guest.sin6_addr.s6_addr[15] = 15;
s = slirp_new(&cfg, &callbacks, NULL);
ndp_table_add(s, guest.sin6_addr, mac);
m = m_get(s);
memset(m->m_data, 0, sizeof(struct udphdr));
memcpy(m->m_data + sizeof(struct udphdr), request, sizeof(request));
m->m_len = sizeof(struct udphdr) + sizeof(request);
dhcpv6_input(&guest, m);
m_free(m);
g_assert_cmpuint(reply_len, <=, ETH_HLEN + cfg.if_mtu);
off = ETH_HLEN + sizeof(struct ip6) + sizeof(struct udphdr) + 4;
g_assert_cmpuint(reply_len, >, off + 4);
g_assert_cmpuint(reply[off + 1], ==, 23);
size = (reply[off + 2] << 8) | reply[off + 3];
g_assert_cmpuint(size, ==, ((1280 - 40 - 8 - 4 - 4) / 16) * 16);
g_assert_cmpmem(reply + off + 4, size, addrs, size);
ra_timer_handler(s, NULL);
g_assert_cmpuint(reply_len, <=, ETH_HLEN + cfg.if_mtu);
off = ETH_HLEN + sizeof(struct ip6) + ICMP6_NDP_RA_MINLEN +
NDPOPT_LINKLAYER_LEN + NDPOPT_PREFIXINFO_LEN;
g_assert_cmpuint(reply[off], ==, NDPOPT_RDNSS);
size = reply[off + 1] * 8 - NDPOPT_RDNSS_HEADER_LEN;
g_assert_cmpuint(size, >, 0);
g_assert_cmpuint(size, <, sizeof(addrs));
g_assert_cmpmem(reply + off + NDPOPT_RDNSS_HEADER_LEN, size, addrs, size);
slirp_cleanup(s);
return 0;
}