Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 39 additions & 20 deletions mongoose.c
Original file line number Diff line number Diff line change
Expand Up @@ -5214,27 +5214,44 @@ static void tx_ndp_rs(struct mg_tcpip_if *ifp, uint64_t *ip_dst, uint8_t *mac) {
MG_DEBUG(("NDP Router Solicitation sent"));
}

static void fill_prefix(uint8_t *dst, uint8_t *src, uint8_t len) {
uint8_t full = len / 8;
uint8_t rem = len % 8;
if (full > 0) memcpy(dst, src, full);
if (rem > 0) {
uint8_t mask = (uint8_t) (0xFF << (8 - rem));
dst[full] = src[full] & mask;
}
}

static bool fill_global(uint64_t *ip6, uint8_t *prefix, uint8_t prefix_len,
uint8_t *mac) {
uint8_t full = prefix_len / 8;
uint8_t rem = prefix_len % 8;
if (full >= 8 && rem != 0) {
if (full > 8 || (full == 8 && rem != 0)) {
MG_ERROR(("Prefix length > 64, UNSUPPORTED"));
return false;
} else if (full == 8 && rem == 0) {
ip6gen((uint8_t *) ip6, prefix, mac);
} else {
ip6[0] = ip6[1] = 0; // already zeroed before firing RS...
if (full) memcpy(ip6, prefix, full);
if (rem) {
uint8_t mask = (uint8_t) (0xFF << (8 - rem));
((uint8_t *) ip6)[full] = prefix[full] & mask;
}
ip6[0] = ip6[1] = 0;
fill_prefix((uint8_t *) ip6, prefix, prefix_len);
meui64(((uint8_t *) &ip6[1]), mac); // RFC-4291 2.5.4, 2.5.1
}
return true;
}

static bool match_prefix(uint8_t *new, uint8_t *cur, uint8_t len) {
uint8_t full = len / 8;
uint8_t rem = len % 8;
if (full > 0 && memcmp(cur, new, full) != 0) return false;
if (rem > 0) {
uint8_t mask = (uint8_t) (0xFF << (8 - rem));
if (cur[full] != (new[full] & mask)) return false;
}
return true;
}

// Router Advertisement, 4.2
static void rx_ndp_ra(struct mg_tcpip_if *ifp, struct pkt *pkt) {
if (pkt->pay.len < 12) return;
Expand Down Expand Up @@ -5270,15 +5287,14 @@ static void rx_ndp_ra(struct mg_tcpip_if *ifp, struct pkt *pkt) {
uint8_t *prefix = opts + 16;

// TODO (robertc2000): handle prefix options if necessary
(void) prefix_len;
(void) pfx_flags;
(void) valid;
(void) pref_lifetime;
(void) prefix;

// fill prefix length and global
ifp->prefix_len = prefix_len;
// fill prefix and global
if (!fill_global(ifp->ip6, prefix, prefix_len, ifp->mac)) return;
ifp->prefix_len = prefix_len;
fill_prefix(ifp->prefix, prefix, prefix_len);
}
opts += length;
opt_left -= length;
Expand Down Expand Up @@ -5345,9 +5361,11 @@ static uint8_t *get_return_mac(struct mg_tcpip_if *ifp, struct mg_addr *rem,
bool is_udp, struct pkt *pkt) {
#if MG_ENABLE_IPV6
if (rem->is_ip6) {
if (is_udp && MG_IP6MATCH(rem->addr.ip6, ip6_allnodes.u)) // local broadcast
if (is_udp &&
MG_IP6MATCH(rem->addr.ip6, ip6_allnodes.u)) // local broadcast
return (uint8_t *) ip6mac_allnodes;
if (rem->addr.ip6[0] == ifp->ip6[0]) // TODO(): HANDLE PREFIX ***
if (rem->addr.ip6[0] == ifp->ip6ll[0] ||
match_prefix((uint8_t *) rem->addr.ip6, ifp->prefix, ifp->prefix_len))
return pkt->eth->src; // we're on the same LAN, get MAC from frame
if (is_udp && *((uint8_t *) rem->addr.ip6) == 0xFF) // multicast
{
Expand Down Expand Up @@ -5531,7 +5549,7 @@ static struct mg_connection *accept_conn(struct mg_connection *lsn,
if ((mac = get_return_mac(lsn->mgr->ifp, &c->rem, false, pkt)) == NULL) {
free(c); // safety net for lousy networks, not actually needed
return NULL; // as path has already been checked at SYN (sending SYN+ACK)
}
}
memcpy(s->mac, mac, sizeof(s->mac));
settmout(c, MIP_TTYPE_KEEPALIVE);
MG_DEBUG(("%lu accepted %M", c->id, mg_print_ip_port, &c->rem));
Expand Down Expand Up @@ -6348,15 +6366,16 @@ void mg_connect_resolved(struct mg_connection *c) {
struct connstate *s = (struct connstate *) (c + 1);
memcpy(s->mac, ip6mac_allnodes, sizeof(s->mac));
mac_resolved(c);
} else if (c->rem.addr.ip6[0] == ifp->ip6[0] && // TODO(): HANDLE PREFIX ***
!MG_IP6MATCH(c->rem.addr.ip6,
ifp->gw6)) { // skip if gw (onstate6change -> NS)
// If we're in the same LAN, fire a Neighbor Solicitation
MG_DEBUG(("%lu NS lookup...", c->id));
} else if (match_prefix((uint8_t *) c->rem.addr.ip6, ifp->prefix,
ifp->prefix_len) // same global LAN
|| (c->rem.addr.ip6[0] == ifp->ip6ll[0] // same local LAN
&& !MG_IP6MATCH(c->rem.addr.ip6, ifp->gw6))) { // and not gw
MG_DEBUG(("%lu NS lookup...", c->id)); // fire a Neighbor Solicitation
tx_ndp_ns(ifp, c->rem.addr.ip6, ifp->mac);
settmout(c, MIP_TTYPE_ARP);
c->is_arplooking = 1;
} else if (c->is_udp && *((uint8_t *) c->rem.addr.ip6) == 0xFF) { // multicast
} else if (c->is_udp &&
*((uint8_t *) c->rem.addr.ip6) == 0xFF) { // multicast
struct connstate *s = (struct connstate *) (c + 1);
ip6_mcastmac(s->mac, c->rem.addr.ip6);
mac_resolved(c);
Expand Down
1 change: 1 addition & 0 deletions mongoose.h
Original file line number Diff line number Diff line change
Expand Up @@ -3202,6 +3202,7 @@ struct mg_tcpip_if {
#define MG_TCPIP_MTU_DEFAULT 1500
#if MG_ENABLE_IPV6
uint64_t ip6ll[2], ip6[2]; // IPv6 link-local and global addresses
uint8_t prefix[8]; // IPv6 global address prefix
uint8_t prefix_len; // Prefix length
uint64_t gw6[2]; // Default gateway
bool enable_slaac; // Enable IPv6 address autoconfiguration
Expand Down
59 changes: 39 additions & 20 deletions src/net_builtin.c
Original file line number Diff line number Diff line change
Expand Up @@ -822,27 +822,44 @@ static void tx_ndp_rs(struct mg_tcpip_if *ifp, uint64_t *ip_dst, uint8_t *mac) {
MG_DEBUG(("NDP Router Solicitation sent"));
}

static void fill_prefix(uint8_t *dst, uint8_t *src, uint8_t len) {
uint8_t full = len / 8;
uint8_t rem = len % 8;
if (full > 0) memcpy(dst, src, full);
if (rem > 0) {
uint8_t mask = (uint8_t) (0xFF << (8 - rem));
dst[full] = src[full] & mask;
}
}

static bool fill_global(uint64_t *ip6, uint8_t *prefix, uint8_t prefix_len,
uint8_t *mac) {
uint8_t full = prefix_len / 8;
uint8_t rem = prefix_len % 8;
if (full >= 8 && rem != 0) {
if (full > 8 || (full == 8 && rem != 0)) {
MG_ERROR(("Prefix length > 64, UNSUPPORTED"));
return false;
} else if (full == 8 && rem == 0) {
ip6gen((uint8_t *) ip6, prefix, mac);
} else {
ip6[0] = ip6[1] = 0; // already zeroed before firing RS...
if (full) memcpy(ip6, prefix, full);
if (rem) {
uint8_t mask = (uint8_t) (0xFF << (8 - rem));
((uint8_t *) ip6)[full] = prefix[full] & mask;
}
ip6[0] = ip6[1] = 0;
fill_prefix((uint8_t *) ip6, prefix, prefix_len);
meui64(((uint8_t *) &ip6[1]), mac); // RFC-4291 2.5.4, 2.5.1
}
return true;
}

static bool match_prefix(uint8_t *new, uint8_t *cur, uint8_t len) {
uint8_t full = len / 8;
uint8_t rem = len % 8;
if (full > 0 && memcmp(cur, new, full) != 0) return false;
if (rem > 0) {
uint8_t mask = (uint8_t) (0xFF << (8 - rem));
if (cur[full] != (new[full] & mask)) return false;
}
return true;
}

// Router Advertisement, 4.2
static void rx_ndp_ra(struct mg_tcpip_if *ifp, struct pkt *pkt) {
if (pkt->pay.len < 12) return;
Expand Down Expand Up @@ -878,15 +895,14 @@ static void rx_ndp_ra(struct mg_tcpip_if *ifp, struct pkt *pkt) {
uint8_t *prefix = opts + 16;

// TODO (robertc2000): handle prefix options if necessary
(void) prefix_len;
(void) pfx_flags;
(void) valid;
(void) pref_lifetime;
(void) prefix;

// fill prefix length and global
ifp->prefix_len = prefix_len;
// fill prefix and global
if (!fill_global(ifp->ip6, prefix, prefix_len, ifp->mac)) return;
ifp->prefix_len = prefix_len;
fill_prefix(ifp->prefix, prefix, prefix_len);
}
opts += length;
opt_left -= length;
Expand Down Expand Up @@ -953,9 +969,11 @@ static uint8_t *get_return_mac(struct mg_tcpip_if *ifp, struct mg_addr *rem,
bool is_udp, struct pkt *pkt) {
#if MG_ENABLE_IPV6
if (rem->is_ip6) {
if (is_udp && MG_IP6MATCH(rem->addr.ip6, ip6_allnodes.u)) // local broadcast
if (is_udp &&
MG_IP6MATCH(rem->addr.ip6, ip6_allnodes.u)) // local broadcast
return (uint8_t *) ip6mac_allnodes;
if (rem->addr.ip6[0] == ifp->ip6[0]) // TODO(): HANDLE PREFIX ***
if (rem->addr.ip6[0] == ifp->ip6ll[0] ||
match_prefix((uint8_t *) rem->addr.ip6, ifp->prefix, ifp->prefix_len))
return pkt->eth->src; // we're on the same LAN, get MAC from frame
if (is_udp && *((uint8_t *) rem->addr.ip6) == 0xFF) // multicast
{
Expand Down Expand Up @@ -1139,7 +1157,7 @@ static struct mg_connection *accept_conn(struct mg_connection *lsn,
if ((mac = get_return_mac(lsn->mgr->ifp, &c->rem, false, pkt)) == NULL) {
free(c); // safety net for lousy networks, not actually needed
return NULL; // as path has already been checked at SYN (sending SYN+ACK)
}
}
memcpy(s->mac, mac, sizeof(s->mac));
settmout(c, MIP_TTYPE_KEEPALIVE);
MG_DEBUG(("%lu accepted %M", c->id, mg_print_ip_port, &c->rem));
Expand Down Expand Up @@ -1956,15 +1974,16 @@ void mg_connect_resolved(struct mg_connection *c) {
struct connstate *s = (struct connstate *) (c + 1);
memcpy(s->mac, ip6mac_allnodes, sizeof(s->mac));
mac_resolved(c);
} else if (c->rem.addr.ip6[0] == ifp->ip6[0] && // TODO(): HANDLE PREFIX ***
!MG_IP6MATCH(c->rem.addr.ip6,
ifp->gw6)) { // skip if gw (onstate6change -> NS)
// If we're in the same LAN, fire a Neighbor Solicitation
MG_DEBUG(("%lu NS lookup...", c->id));
} else if (match_prefix((uint8_t *) c->rem.addr.ip6, ifp->prefix,
ifp->prefix_len) // same global LAN
|| (c->rem.addr.ip6[0] == ifp->ip6ll[0] // same local LAN
&& !MG_IP6MATCH(c->rem.addr.ip6, ifp->gw6))) { // and not gw
MG_DEBUG(("%lu NS lookup...", c->id)); // fire a Neighbor Solicitation
tx_ndp_ns(ifp, c->rem.addr.ip6, ifp->mac);
settmout(c, MIP_TTYPE_ARP);
c->is_arplooking = 1;
} else if (c->is_udp && *((uint8_t *) c->rem.addr.ip6) == 0xFF) { // multicast
} else if (c->is_udp &&
*((uint8_t *) c->rem.addr.ip6) == 0xFF) { // multicast
struct connstate *s = (struct connstate *) (c + 1);
ip6_mcastmac(s->mac, c->rem.addr.ip6);
mac_resolved(c);
Expand Down
1 change: 1 addition & 0 deletions src/net_builtin.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ struct mg_tcpip_if {
#define MG_TCPIP_MTU_DEFAULT 1500
#if MG_ENABLE_IPV6
uint64_t ip6ll[2], ip6[2]; // IPv6 link-local and global addresses
uint8_t prefix[8]; // IPv6 global address prefix
uint8_t prefix_len; // Prefix length
uint64_t gw6[2]; // Default gateway
bool enable_slaac; // Enable IPv6 address autoconfiguration
Expand Down
2 changes: 2 additions & 0 deletions test/mip_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,8 @@ static void init_tests(struct mg_mgr *mgr, struct eth *e, struct ipp *ipp,
#if MG_ENABLE_IPV6
if (ipp->ip6 != NULL) {
mif->ip6[0] = 1;
mif->prefix[0] = 1;
mif->prefix_len = 64;
mif->gw6[0] = 1;
mif->gw6_ready = true;
mif->state = MG_TCPIP_STATE_READY; // so DHCP stops
Expand Down