}
HWAddrPtr
-Pkt::getMACfromIPv6(const isc::asiolink::IOAddress& addr) {
+Pkt::getMACFromIPv6(const isc::asiolink::IOAddress& addr) {
if (!addr.isV6LinkLocal()) {
return (HWAddrPtr());
// Check that it's link-local (starts with fe80).
(bin[0] != 0xfe) || (bin[1] != 0x80) ||
+ // Check that u bit is set and g is clear. See Section 2.5.1 of RFC2373
+ // for details.
+ ( (bin[0] & 3) != 2) ||
+
// And that the IID is of EUI-64 type.
(bin[11] != 0xff) || (bin[12] != 0xfe)) {
return (HWAddrPtr());
// Ok, we're down to EUI-64 only now: XX:XX:XX:ff:fe:XX:XX:XX
bin.erase(bin.begin() + 3, bin.begin() + 5);
+ // MAC-48 to EUI-64 involves inverting u bit (see explanation in Section
+ // 2.5.1 of RFC2373). We need to revert that.
+ bin[0] = bin[0] ^ 2;
+
// Let's get the interface this packet was received on. We need it to get
// hardware type
Iface* iface = IfaceMgr::instance().getIface(iface_);
Pkt6::getMACFromSrcLinkLocalAddr() {
if (relay_info_.empty()) {
// This is a direct message, use source address
- return (getMACfromIPv6(remote_addr_));
+ return (getMACFromIPv6(remote_addr_));
}
// This is a relayed message, get the peer-addr from the first relay-forw
- return (getMACfromIPv6(relay_info_[relay_info_.size() - 1].peeraddr_));
+ return (getMACFromIPv6(relay_info_[relay_info_.size() - 1].peeraddr_));
}
pkt.setIface(iface->getName());
pkt.setIndex(iface->getIndex());
+ // Note that u and g bits (the least significant ones of the most significant
+ // byte) have special meaning and must not be set in MAC. u bit is always set
+ // in EUI-64. g is always cleared.
IOAddress global("2001:db8::204:06ff:fe08:0a:0c");
- IOAddress linklocal_eui64("fe80::204:06ff:fe08:0a0c");
- IOAddress linklocal_noneui64("fe80::0204:0608:0a0c:0e10");
+ IOAddress linklocal_eui64("fe80::f204:06ff:fe08:0a0c");
+ IOAddress linklocal_noneui64("fe80::f204:0608:0a0c:0e10");
// If received from a global address, this method should fail
pkt.setRemoteAddr(global);
ASSERT_TRUE(found);
stringstream tmp;
- tmp << "hwtype=" << (int)iface->getHWType() << " 02:04:06:08:0a:0c";
+ tmp << "hwtype=" << (int)iface->getHWType() << " f0:04:06:08:0a:0c";
EXPECT_EQ(tmp.str(), found->toText(true));
}
pkt.setIndex(iface->getIndex());
IOAddress global("2001:db8::204:06ff:fe08:0a:0c"); // global address
- IOAddress linklocal_noneui64("fe80::0204:0608:0a0c:0e10"); // no fffe
- IOAddress linklocal_eui64("fe80::204:06ff:fe08:0a0c"); // valid EUI-64
+ IOAddress linklocal_noneui64("fe80::f204:0608:0a0c:0e10"); // no fffe
+ IOAddress linklocal_eui64("fe80::f204:06ff:fe08:0a0c"); // valid EUI-64
// If received from a global address, this method should fail
pkt.relay_info_[0].peeraddr_ = global;
ASSERT_TRUE(found);
stringstream tmp;
- tmp << "hwtype=" << (int)iface->getHWType() << " 02:04:06:08:0a:0c";
+ tmp << "hwtype=" << (int)iface->getHWType() << " f0:04:06:08:0a:0c";
EXPECT_EQ(tmp.str(), found->toText(true));
}
// are stored in relay_info_ in the encapsulation order rather than in
// traverse order. The following simulates:
// client --- relay1 --- relay2 --- relay3 --- server
- IOAddress linklocal1("fe80::ff:fe00:1"); // valid EUI-64
- IOAddress linklocal2("fe80::ff:fe00:2"); // valid EUI-64
- IOAddress linklocal3("fe80::ff:fe00:3"); // valid EUI-64
+ IOAddress linklocal1("fe80::200:ff:fe00:1"); // valid EUI-64
+ IOAddress linklocal2("fe80::200:ff:fe00:2"); // valid EUI-64
+ IOAddress linklocal3("fe80::200:ff:fe00:3"); // valid EUI-64
// Let's add info about relay3. This was the last relay, so it added the
// outermost encapsulation layer, so it was parsed first during reception.