@@ -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+
52175227static 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
52395256static 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);
0 commit comments