Browse Source

[3549] Changes after review:
- It's called getMACFromIPv6() now
- Tests for u,g bits added.
- u bit is now flipped properly.
- Unit tests updated to reflect above changes.

Tomek Mrugalski 10 years ago
parent
commit
d4a2bd9fba
4 changed files with 24 additions and 13 deletions
  1. 9 1
      src/lib/dhcp/pkt.cc
  2. 1 1
      src/lib/dhcp/pkt.h
  3. 2 2
      src/lib/dhcp/pkt6.cc
  4. 12 9
      src/lib/dhcp/tests/pkt6_unittest.cc

+ 9 - 1
src/lib/dhcp/pkt.cc

@@ -169,7 +169,7 @@ Pkt::getMAC(uint32_t hw_addr_src) {
 }
 }
 
 
 HWAddrPtr
 HWAddrPtr
-Pkt::getMACfromIPv6(const isc::asiolink::IOAddress& addr) {
+Pkt::getMACFromIPv6(const isc::asiolink::IOAddress& addr) {
 
 
     if (!addr.isV6LinkLocal()) {
     if (!addr.isV6LinkLocal()) {
         return (HWAddrPtr());
         return (HWAddrPtr());
@@ -183,6 +183,10 @@ Pkt::getMACfromIPv6(const isc::asiolink::IOAddress& addr) {
         // Check that it's link-local (starts with fe80).
         // Check that it's link-local (starts with fe80).
         (bin[0] != 0xfe) || (bin[1] != 0x80) ||
         (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.
         // And that the IID is of EUI-64 type.
         (bin[11] != 0xff) || (bin[12] != 0xfe)) {
         (bin[11] != 0xff) || (bin[12] != 0xfe)) {
         return (HWAddrPtr());
         return (HWAddrPtr());
@@ -194,6 +198,10 @@ Pkt::getMACfromIPv6(const isc::asiolink::IOAddress& addr) {
     // Ok, we're down to EUI-64 only now: XX:XX:XX:ff:fe:XX:XX:XX
     // 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);
     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
     // Let's get the interface this packet was received on. We need it to get
     // hardware type
     // hardware type
     Iface* iface = IfaceMgr::instance().getIface(iface_);
     Iface* iface = IfaceMgr::instance().getIface(iface_);

+ 1 - 1
src/lib/dhcp/pkt.h

@@ -536,7 +536,7 @@ protected:
     /// @param addr IPv6 address to be converted
     /// @param addr IPv6 address to be converted
     /// @return hardware address (or NULL)
     /// @return hardware address (or NULL)
     HWAddrPtr
     HWAddrPtr
-    getMACfromIPv6(const isc::asiolink::IOAddress& addr);
+    getMACFromIPv6(const isc::asiolink::IOAddress& addr);
 
 
     /// Transaction-id (32 bits for v4, 24 bits for v6)
     /// Transaction-id (32 bits for v4, 24 bits for v6)
     uint32_t transid_;
     uint32_t transid_;

+ 2 - 2
src/lib/dhcp/pkt6.cc

@@ -546,11 +546,11 @@ HWAddrPtr
 Pkt6::getMACFromSrcLinkLocalAddr() {
 Pkt6::getMACFromSrcLinkLocalAddr() {
     if (relay_info_.empty()) {
     if (relay_info_.empty()) {
         // This is a direct message, use source address
         // 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
     // 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_));
 }
 }
 
 
 
 

+ 12 - 9
src/lib/dhcp/tests/pkt6_unittest.cc

@@ -923,9 +923,12 @@ TEST_F(Pkt6Test, getMACFromIPv6LinkLocal_direct) {
     pkt.setIface(iface->getName());
     pkt.setIface(iface->getName());
     pkt.setIndex(iface->getIndex());
     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 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
     // If received from a global address, this method should fail
     pkt.setRemoteAddr(global);
     pkt.setRemoteAddr(global);
@@ -937,7 +940,7 @@ TEST_F(Pkt6Test, getMACFromIPv6LinkLocal_direct) {
     ASSERT_TRUE(found);
     ASSERT_TRUE(found);
 
 
     stringstream tmp;
     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));
     EXPECT_EQ(tmp.str(), found->toText(true));
 }
 }
 
 
@@ -963,8 +966,8 @@ TEST_F(Pkt6Test, getMACFromIPv6LinkLocal_singleRelay) {
     pkt.setIndex(iface->getIndex());
     pkt.setIndex(iface->getIndex());
 
 
     IOAddress global("2001:db8::204:06ff:fe08:0a:0c"); // global address
     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
     // If received from a global address, this method should fail
     pkt.relay_info_[0].peeraddr_ = global;
     pkt.relay_info_[0].peeraddr_ = global;
@@ -980,7 +983,7 @@ TEST_F(Pkt6Test, getMACFromIPv6LinkLocal_singleRelay) {
     ASSERT_TRUE(found);
     ASSERT_TRUE(found);
 
 
     stringstream tmp;
     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));
     EXPECT_EQ(tmp.str(), found->toText(true));
 }
 }
 
 
@@ -995,9 +998,9 @@ TEST_F(Pkt6Test, getMACFromIPv6LinkLocal_multiRelay) {
     // are stored in relay_info_ in the encapsulation order rather than in
     // are stored in relay_info_ in the encapsulation order rather than in
     // traverse order. The following simulates:
     // traverse order. The following simulates:
     // client --- relay1 --- relay2 --- relay3 --- server
     // 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
     // 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.
     // outermost encapsulation layer, so it was parsed first during reception.