Skip to content

Commit b0109c3

Browse files
committed
Add support for prefix, link local and global in same net
1 parent a42271a commit b0109c3

File tree

5 files changed

+82
-40
lines changed

5 files changed

+82
-40
lines changed

mongoose.c

Lines changed: 39 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5214,27 +5214,44 @@ static void tx_ndp_rs(struct mg_tcpip_if *ifp, uint64_t *ip_dst, uint8_t *mac) {
52145214
MG_DEBUG(("NDP Router Solicitation sent"));
52155215
}
52165216

5217+
static void fill_prefix(uint8_t *dst, uint8_t *src, uint8_t len) {
5218+
uint8_t full = len / 8;
5219+
uint8_t rem = len % 8;
5220+
if (full > 0) memcpy(dst, src, full);
5221+
if (rem > 0) {
5222+
uint8_t mask = (uint8_t) (0xFF << (8 - rem));
5223+
dst[full] = src[full] & mask;
5224+
}
5225+
}
5226+
52175227
static bool fill_global(uint64_t *ip6, uint8_t *prefix, uint8_t prefix_len,
52185228
uint8_t *mac) {
52195229
uint8_t full = prefix_len / 8;
52205230
uint8_t rem = prefix_len % 8;
5221-
if (full >= 8 && rem != 0) {
5231+
if (full > 8 || (full == 8 && rem != 0)) {
52225232
MG_ERROR(("Prefix length > 64, UNSUPPORTED"));
52235233
return false;
52245234
} else if (full == 8 && rem == 0) {
52255235
ip6gen((uint8_t *) ip6, prefix, mac);
52265236
} else {
5227-
ip6[0] = ip6[1] = 0; // already zeroed before firing RS...
5228-
if (full) memcpy(ip6, prefix, full);
5229-
if (rem) {
5230-
uint8_t mask = (uint8_t) (0xFF << (8 - rem));
5231-
((uint8_t *) ip6)[full] = prefix[full] & mask;
5232-
}
5237+
ip6[0] = ip6[1] = 0;
5238+
fill_prefix((uint8_t *) ip6, prefix, prefix_len);
52335239
meui64(((uint8_t *) &ip6[1]), mac); // RFC-4291 2.5.4, 2.5.1
52345240
}
52355241
return true;
52365242
}
52375243

5244+
static bool match_prefix(uint8_t *new, uint8_t *cur, uint8_t len) {
5245+
uint8_t full = len / 8;
5246+
uint8_t rem = len % 8;
5247+
if (full > 0 && memcmp(cur, new, full) != 0) return false;
5248+
if (rem > 0) {
5249+
uint8_t mask = (uint8_t) (0xFF << (8 - rem));
5250+
if (cur[full] != (new[full] & mask)) return false;
5251+
}
5252+
return true;
5253+
}
5254+
52385255
// Router Advertisement, 4.2
52395256
static void rx_ndp_ra(struct mg_tcpip_if *ifp, struct pkt *pkt) {
52405257
if (pkt->pay.len < 12) return;
@@ -5270,15 +5287,14 @@ static void rx_ndp_ra(struct mg_tcpip_if *ifp, struct pkt *pkt) {
52705287
uint8_t *prefix = opts + 16;
52715288

52725289
// TODO (robertc2000): handle prefix options if necessary
5273-
(void) prefix_len;
52745290
(void) pfx_flags;
52755291
(void) valid;
52765292
(void) pref_lifetime;
5277-
(void) prefix;
52785293

5279-
// fill prefix length and global
5280-
ifp->prefix_len = prefix_len;
5294+
// fill prefix and global
52815295
if (!fill_global(ifp->ip6, prefix, prefix_len, ifp->mac)) return;
5296+
ifp->prefix_len = prefix_len;
5297+
fill_prefix(ifp->prefix, prefix, prefix_len);
52825298
}
52835299
opts += length;
52845300
opt_left -= length;
@@ -5345,9 +5361,11 @@ static uint8_t *get_return_mac(struct mg_tcpip_if *ifp, struct mg_addr *rem,
53455361
bool is_udp, struct pkt *pkt) {
53465362
#if MG_ENABLE_IPV6
53475363
if (rem->is_ip6) {
5348-
if (is_udp && MG_IP6MATCH(rem->addr.ip6, ip6_allnodes.u)) // local broadcast
5364+
if (is_udp &&
5365+
MG_IP6MATCH(rem->addr.ip6, ip6_allnodes.u)) // local broadcast
53495366
return (uint8_t *) ip6mac_allnodes;
5350-
if (rem->addr.ip6[0] == ifp->ip6[0]) // TODO(): HANDLE PREFIX ***
5367+
if (rem->addr.ip6[0] == ifp->ip6ll[0] ||
5368+
match_prefix((uint8_t *) rem->addr.ip6, ifp->prefix, ifp->prefix_len))
53515369
return pkt->eth->src; // we're on the same LAN, get MAC from frame
53525370
if (is_udp && *((uint8_t *) rem->addr.ip6) == 0xFF) // multicast
53535371
{
@@ -5531,7 +5549,7 @@ static struct mg_connection *accept_conn(struct mg_connection *lsn,
55315549
if ((mac = get_return_mac(lsn->mgr->ifp, &c->rem, false, pkt)) == NULL) {
55325550
free(c); // safety net for lousy networks, not actually needed
55335551
return NULL; // as path has already been checked at SYN (sending SYN+ACK)
5534-
}
5552+
}
55355553
memcpy(s->mac, mac, sizeof(s->mac));
55365554
settmout(c, MIP_TTYPE_KEEPALIVE);
55375555
MG_DEBUG(("%lu accepted %M", c->id, mg_print_ip_port, &c->rem));
@@ -6348,15 +6366,16 @@ void mg_connect_resolved(struct mg_connection *c) {
63486366
struct connstate *s = (struct connstate *) (c + 1);
63496367
memcpy(s->mac, ip6mac_allnodes, sizeof(s->mac));
63506368
mac_resolved(c);
6351-
} else if (c->rem.addr.ip6[0] == ifp->ip6[0] && // TODO(): HANDLE PREFIX ***
6352-
!MG_IP6MATCH(c->rem.addr.ip6,
6353-
ifp->gw6)) { // skip if gw (onstate6change -> NS)
6354-
// If we're in the same LAN, fire a Neighbor Solicitation
6355-
MG_DEBUG(("%lu NS lookup...", c->id));
6369+
} else if (match_prefix((uint8_t *) c->rem.addr.ip6, ifp->prefix,
6370+
ifp->prefix_len) // same global LAN
6371+
|| (c->rem.addr.ip6[0] == ifp->ip6ll[0] // same local LAN
6372+
&& !MG_IP6MATCH(c->rem.addr.ip6, ifp->gw6))) { // and not gw
6373+
MG_DEBUG(("%lu NS lookup...", c->id)); // fire a Neighbor Solicitation
63566374
tx_ndp_ns(ifp, c->rem.addr.ip6, ifp->mac);
63576375
settmout(c, MIP_TTYPE_ARP);
63586376
c->is_arplooking = 1;
6359-
} else if (c->is_udp && *((uint8_t *) c->rem.addr.ip6) == 0xFF) { // multicast
6377+
} else if (c->is_udp &&
6378+
*((uint8_t *) c->rem.addr.ip6) == 0xFF) { // multicast
63606379
struct connstate *s = (struct connstate *) (c + 1);
63616380
ip6_mcastmac(s->mac, c->rem.addr.ip6);
63626381
mac_resolved(c);

mongoose.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3202,6 +3202,7 @@ struct mg_tcpip_if {
32023202
#define MG_TCPIP_MTU_DEFAULT 1500
32033203
#if MG_ENABLE_IPV6
32043204
uint64_t ip6ll[2], ip6[2]; // IPv6 link-local and global addresses
3205+
uint8_t prefix[8]; // IPv6 global address prefix
32053206
uint8_t prefix_len; // Prefix length
32063207
uint64_t gw6[2]; // Default gateway
32073208
bool enable_slaac; // Enable IPv6 address autoconfiguration

src/net_builtin.c

Lines changed: 39 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -822,27 +822,44 @@ static void tx_ndp_rs(struct mg_tcpip_if *ifp, uint64_t *ip_dst, uint8_t *mac) {
822822
MG_DEBUG(("NDP Router Solicitation sent"));
823823
}
824824

825+
static void fill_prefix(uint8_t *dst, uint8_t *src, uint8_t len) {
826+
uint8_t full = len / 8;
827+
uint8_t rem = len % 8;
828+
if (full > 0) memcpy(dst, src, full);
829+
if (rem > 0) {
830+
uint8_t mask = (uint8_t) (0xFF << (8 - rem));
831+
dst[full] = src[full] & mask;
832+
}
833+
}
834+
825835
static bool fill_global(uint64_t *ip6, uint8_t *prefix, uint8_t prefix_len,
826836
uint8_t *mac) {
827837
uint8_t full = prefix_len / 8;
828838
uint8_t rem = prefix_len % 8;
829-
if (full >= 8 && rem != 0) {
839+
if (full > 8 || (full == 8 && rem != 0)) {
830840
MG_ERROR(("Prefix length > 64, UNSUPPORTED"));
831841
return false;
832842
} else if (full == 8 && rem == 0) {
833843
ip6gen((uint8_t *) ip6, prefix, mac);
834844
} else {
835-
ip6[0] = ip6[1] = 0; // already zeroed before firing RS...
836-
if (full) memcpy(ip6, prefix, full);
837-
if (rem) {
838-
uint8_t mask = (uint8_t) (0xFF << (8 - rem));
839-
((uint8_t *) ip6)[full] = prefix[full] & mask;
840-
}
845+
ip6[0] = ip6[1] = 0;
846+
fill_prefix((uint8_t *) ip6, prefix, prefix_len);
841847
meui64(((uint8_t *) &ip6[1]), mac); // RFC-4291 2.5.4, 2.5.1
842848
}
843849
return true;
844850
}
845851

852+
static bool match_prefix(uint8_t *new, uint8_t *cur, uint8_t len) {
853+
uint8_t full = len / 8;
854+
uint8_t rem = len % 8;
855+
if (full > 0 && memcmp(cur, new, full) != 0) return false;
856+
if (rem > 0) {
857+
uint8_t mask = (uint8_t) (0xFF << (8 - rem));
858+
if (cur[full] != (new[full] & mask)) return false;
859+
}
860+
return true;
861+
}
862+
846863
// Router Advertisement, 4.2
847864
static void rx_ndp_ra(struct mg_tcpip_if *ifp, struct pkt *pkt) {
848865
if (pkt->pay.len < 12) return;
@@ -878,15 +895,14 @@ static void rx_ndp_ra(struct mg_tcpip_if *ifp, struct pkt *pkt) {
878895
uint8_t *prefix = opts + 16;
879896

880897
// TODO (robertc2000): handle prefix options if necessary
881-
(void) prefix_len;
882898
(void) pfx_flags;
883899
(void) valid;
884900
(void) pref_lifetime;
885-
(void) prefix;
886901

887-
// fill prefix length and global
888-
ifp->prefix_len = prefix_len;
902+
// fill prefix and global
889903
if (!fill_global(ifp->ip6, prefix, prefix_len, ifp->mac)) return;
904+
ifp->prefix_len = prefix_len;
905+
fill_prefix(ifp->prefix, prefix, prefix_len);
890906
}
891907
opts += length;
892908
opt_left -= length;
@@ -953,9 +969,11 @@ static uint8_t *get_return_mac(struct mg_tcpip_if *ifp, struct mg_addr *rem,
953969
bool is_udp, struct pkt *pkt) {
954970
#if MG_ENABLE_IPV6
955971
if (rem->is_ip6) {
956-
if (is_udp && MG_IP6MATCH(rem->addr.ip6, ip6_allnodes.u)) // local broadcast
972+
if (is_udp &&
973+
MG_IP6MATCH(rem->addr.ip6, ip6_allnodes.u)) // local broadcast
957974
return (uint8_t *) ip6mac_allnodes;
958-
if (rem->addr.ip6[0] == ifp->ip6[0]) // TODO(): HANDLE PREFIX ***
975+
if (rem->addr.ip6[0] == ifp->ip6ll[0] ||
976+
match_prefix((uint8_t *) rem->addr.ip6, ifp->prefix, ifp->prefix_len))
959977
return pkt->eth->src; // we're on the same LAN, get MAC from frame
960978
if (is_udp && *((uint8_t *) rem->addr.ip6) == 0xFF) // multicast
961979
{
@@ -1139,7 +1157,7 @@ static struct mg_connection *accept_conn(struct mg_connection *lsn,
11391157
if ((mac = get_return_mac(lsn->mgr->ifp, &c->rem, false, pkt)) == NULL) {
11401158
free(c); // safety net for lousy networks, not actually needed
11411159
return NULL; // as path has already been checked at SYN (sending SYN+ACK)
1142-
}
1160+
}
11431161
memcpy(s->mac, mac, sizeof(s->mac));
11441162
settmout(c, MIP_TTYPE_KEEPALIVE);
11451163
MG_DEBUG(("%lu accepted %M", c->id, mg_print_ip_port, &c->rem));
@@ -1956,15 +1974,16 @@ void mg_connect_resolved(struct mg_connection *c) {
19561974
struct connstate *s = (struct connstate *) (c + 1);
19571975
memcpy(s->mac, ip6mac_allnodes, sizeof(s->mac));
19581976
mac_resolved(c);
1959-
} else if (c->rem.addr.ip6[0] == ifp->ip6[0] && // TODO(): HANDLE PREFIX ***
1960-
!MG_IP6MATCH(c->rem.addr.ip6,
1961-
ifp->gw6)) { // skip if gw (onstate6change -> NS)
1962-
// If we're in the same LAN, fire a Neighbor Solicitation
1963-
MG_DEBUG(("%lu NS lookup...", c->id));
1977+
} else if (match_prefix((uint8_t *) c->rem.addr.ip6, ifp->prefix,
1978+
ifp->prefix_len) // same global LAN
1979+
|| (c->rem.addr.ip6[0] == ifp->ip6ll[0] // same local LAN
1980+
&& !MG_IP6MATCH(c->rem.addr.ip6, ifp->gw6))) { // and not gw
1981+
MG_DEBUG(("%lu NS lookup...", c->id)); // fire a Neighbor Solicitation
19641982
tx_ndp_ns(ifp, c->rem.addr.ip6, ifp->mac);
19651983
settmout(c, MIP_TTYPE_ARP);
19661984
c->is_arplooking = 1;
1967-
} else if (c->is_udp && *((uint8_t *) c->rem.addr.ip6) == 0xFF) { // multicast
1985+
} else if (c->is_udp &&
1986+
*((uint8_t *) c->rem.addr.ip6) == 0xFF) { // multicast
19681987
struct connstate *s = (struct connstate *) (c + 1);
19691988
ip6_mcastmac(s->mac, c->rem.addr.ip6);
19701989
mac_resolved(c);

src/net_builtin.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ struct mg_tcpip_if {
5757
#define MG_TCPIP_MTU_DEFAULT 1500
5858
#if MG_ENABLE_IPV6
5959
uint64_t ip6ll[2], ip6[2]; // IPv6 link-local and global addresses
60+
uint8_t prefix[8]; // IPv6 global address prefix
6061
uint8_t prefix_len; // Prefix length
6162
uint64_t gw6[2]; // Default gateway
6263
bool enable_slaac; // Enable IPv6 address autoconfiguration

test/mip_test.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,8 @@ static void init_tests(struct mg_mgr *mgr, struct eth *e, struct ipp *ipp,
251251
#if MG_ENABLE_IPV6
252252
if (ipp->ip6 != NULL) {
253253
mif->ip6[0] = 1;
254+
mif->prefix[0] = 1;
255+
mif->prefix_len = 64;
254256
mif->gw6[0] = 1;
255257
mif->gw6_ready = true;
256258
mif->state = MG_TCPIP_STATE_READY; // so DHCP stops

0 commit comments

Comments
 (0)