Commit b413f850 authored by Tomek Mrugalski's avatar Tomek Mrugalski 🛰
Browse files

[3553] MAC extraction from DOCSIS options implemented.

parent 053c8392
......@@ -54,6 +54,10 @@ static const uint16_t BOOTP_BROADCAST = 32768L;
/* Possible values for hardware type (htype) field... */
enum HType {
HTYPE_ETHER = 1, /* Ethernet 10Mbps */
HTYPE_DOCSIS = 1, /* the traffic captures we have from cable modems as well
as this list by IANA: http://www.iana.org/assignments/
arp-parameters/arp-parameters.xhtml suggest that
Ethernet (1) should be used in DOCSIS environment. */
HTYPE_IEEE802 = 6, /* IEEE 802.2 Token Ring */
HTYPE_FDDI = 8 /* FDDI */
/// TODO Add infiniband here
......
......@@ -42,9 +42,14 @@ const int DOCSIS3_V4_DEFS_SIZE = sizeof(DOCSIS3_V4_DEFS) / sizeof(OptionDefPara
#define DOCSIS3_V6_TFTP_SERVERS 32
#define DOCSIS3_V6_CONFIG_FILE 33
#define DOCSIS3_V6_SYSLOG_SERVERS 34
#define DOCSIS3_V6_DEVICE_ID 36
#define DOCSIS3_V6_TIME_SERVERS 37
#define DOCSIS3_V6_TIME_OFFSET 38
// The following DOCSIS3 options are inserted by the CMTS (which acts as
// a relay agent)
#define DOCSIS3_V6_CMTS_CM_MAC 1026
/// @brief Definitions of standard DHCPv6 options.
const OptionDefParams DOCSIS3_V6_DEFS[] = {
{ "oro", DOCSIS3_V6_ORO, OPT_UINT16_TYPE, true, NO_RECORD_DEF, "" },
......@@ -54,7 +59,9 @@ const OptionDefParams DOCSIS3_V6_DEFS[] = {
{ "time-servers", DOCSIS3_V6_TIME_SERVERS, OPT_IPV6_ADDRESS_TYPE, true, NO_RECORD_DEF, "" },
{ "config-file", DOCSIS3_V6_CONFIG_FILE, OPT_STRING_TYPE, false, NO_RECORD_DEF, "" },
{ "syslog-servers", DOCSIS3_V6_SYSLOG_SERVERS, OPT_IPV6_ADDRESS_TYPE, true, NO_RECORD_DEF, "" },
{ "time-offset", DOCSIS3_V6_TIME_OFFSET, OPT_INT32_TYPE, false, NO_RECORD_DEF, "" }
{ "device-id", DOCSIS3_V6_DEVICE_ID, OPT_BINARY_TYPE, false, NO_RECORD_DEF, "" },
{ "time-offset", DOCSIS3_V6_TIME_OFFSET, OPT_INT32_TYPE, false, NO_RECORD_DEF, "" },
{ "cmts-cm-mac", DOCSIS3_V6_CMTS_CM_MAC, OPT_BINARY_TYPE, false, NO_RECORD_DEF, "" }
// @todo add definitions for all remaning options.
};
......
......@@ -35,7 +35,8 @@ const uint32_t HWAddr::HWADDR_SOURCE_IPV6_LINK_LOCAL = 0x00000004;
const uint32_t HWAddr::HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION = 0x00000008;
const uint32_t HWAddr::HWADDR_SOURCE_REMOTE_ID = 0x00000010;
const uint32_t HWAddr::HWADDR_SOURCE_SUBSCRIBER_ID = 0x00000020;
const uint32_t HWAddr::HWADDR_SOURCE_DOCSIS = 0x00000040;
const uint32_t HWAddr::HWADDR_SOURCE_DOCSIS_CMTS = 0x00000040;
const uint32_t HWAddr::HWADDR_SOURCE_DOCSIS_MODEM = 0x00000080;
HWAddr::HWAddr()
:htype_(HTYPE_ETHER), source_(0) {
......
......@@ -76,8 +76,15 @@ public:
/// A CMTS (acting as DHCP relay agent) that supports DOCSIS standard
/// can insert DOCSIS options that contain client's MAC address.
/// Client in this context would be a cable modem.
static const uint32_t HWADDR_SOURCE_DOCSIS;
/// This specific option is suboption 1026 in vendor-class option with
/// vendor-id=4491. Client in this context would be a cable modem.
static const uint32_t HWADDR_SOURCE_DOCSIS_CMTS;
/// A cable modem (acting as DHCP client) that supports DOCSIS standard
/// can insert DOCSIS options that contain client's MAC address.
/// This specific option is suboption 36 in vendor-class option with
/// vendor-id=4491.
static const uint32_t HWADDR_SOURCE_DOCSIS_MODEM;
/// @}
......
......@@ -182,8 +182,28 @@ Pkt::getMAC(uint32_t hw_addr_src) {
// Method 6: From subscriber-id option inserted by a relay
// Method 7: From docsis options
if (hw_addr_src & HWADDR_SOURCE_DOCSIS_CMTS) {
mac = getMACFromDocsisCMTS();
if (mac) {
return (mac);
} else if (hw_addr_src == HWADDR_SOURCE_DOCSIS_CMTS) {
// If we're interested only in CMTS options as a source of that
// info, there's no point in trying other options.
return (HWAddrPtr());
}
}
/// @todo: add other MAC acquisition methods here
// Method 8: From docsis options
if (hw_addr_src & HWADDR_SOURCE_DOCSIS_MODEM) {
mac = getMACFromDocsisModem();
if (mac) {
return (mac);
} else if (hw_addr_src == HWADDR_SOURCE_DOCSIS_MODEM) {
// If we're interested only in CMTS options as a source of that
// info, there's no point in trying other options.
return (HWAddrPtr());
}
}
// Ok, none of the methods were suitable. Return NULL.
return (HWAddrPtr());
......
......@@ -523,6 +523,32 @@ protected:
HWAddrPtr
getMACFromIPv6(const isc::asiolink::IOAddress& addr);
/// @brief Attempts to extract MAC/Hardware address from DOCSIS options
/// inserted by the modem itself.
///
/// This is a generic mechanism for extracting hardware address from the
/// DOCSIS options.
///
/// @note This is a pure virtual method and must be implemented in
/// the derived classes. The @c Pkt6 class have respective implementation.
/// This method is currently not implemented in DHCPv4.
///
/// @return hardware address (if necessary DOCSIS suboptions are present)
virtual HWAddrPtr getMACFromDocsisModem() = 0;
/// @brief Attempts to extract MAC/Hardware address from DOCSIS options
/// inserted by the CMTS (the relay agent)
///
/// This is a generic mechanism for extracting hardware address from the
/// DOCSIS options.
///
/// @note This is a pure virtual method and must be implemented in
/// the derived classes. The @c Pkt6 class have respective implementation.
/// This method is currently not implemented in DHCPv4.
///
/// @return hardware address (if necessary DOCSIS suboptions are present)
virtual HWAddrPtr getMACFromDocsisCMTS() = 0;
/// Transaction-id (32 bits for v4, 24 bits for v6)
uint32_t transid_;
......
......@@ -414,6 +414,17 @@ protected:
return (HWAddrPtr());
}
/// @brief No-op
///
/// This is a DHCPv4 version of the function that attempts to extract
/// MAC address from the options inserted by a cable modem. It is currently
/// not implemented for v4.
///
/// @return always NULL
virtual HWAddrPtr getMACFromDocsisModem() {
return (HWAddrPtr());
}
/// @brief No-op
///
/// This method returns hardware address extracted from DUID.
......@@ -425,6 +436,17 @@ protected:
return (HWAddrPtr());
}
/// @brief No-op
///
/// This is a DHCPv4 version of the function that attempts to extract
/// MAC address from the options inserted by a CMTS. It is currently
/// not implemented for v4.
///
/// @return always NULL
virtual HWAddrPtr getMACFromDocsisCMTS() {
return (HWAddrPtr());
}
/// local HW address (dst if receiving packet, src if sending packet)
HWAddrPtr local_hwaddr_;
......
......@@ -15,7 +15,10 @@
#include <dhcp/dhcp6.h>
#include <dhcp/libdhcp++.h>
#include <dhcp/option.h>
#include <dhcp/option_int.h>
#include <dhcp/option_vendor_class.h>
#include <dhcp/pkt6.h>
#include <dhcp/docsis3_option_defs.h>
#include <util/io_utilities.h>
#include <exceptions/exceptions.h>
#include <dhcp/duid.h>
......@@ -620,8 +623,62 @@ Pkt6::getMACFromIPv6RelayOpt() {
// +2, -2 means to skip the initial 2 bytes which are hwaddress type
return (HWAddrPtr(new HWAddr(&data[0] + 2, data.size() - 2,
opt->getUint16())));
} else {
return (HWAddrPtr());
}
}
HWAddrPtr
Pkt6::getMACFromDocsisModem() {
OptionUint32Ptr vendor = boost::dynamic_pointer_cast<
OptionUint32>(getOption(D6O_VENDOR_OPTS));
// Check if this is indeed DOCSIS3 environment
if (!vendor || vendor->getValue() != VENDOR_ID_CABLE_LABS) {
return (HWAddrPtr());
}
// If it is, try to get device-id option
OptionPtr device_id = vendor->getOption(DOCSIS3_V6_DEVICE_ID);
if (!device_id) {
return (HWAddrPtr());
}
OptionBuffer buf = device_id->getData();
if (buf.size() > 1) {
return (HWAddrPtr(new HWAddr(device_id->getData(), HTYPE_DOCSIS)));
} else {
return (HWAddrPtr());
}
else {
}
HWAddrPtr
Pkt6::getMACFromDocsisCMTS() {
if (relay_info_.empty()) {
// This message didn't pass through a CMTS, so there won't be any
// CMTS-specific options in it.
return (HWAddrPtr());
}
OptionUint32Ptr vendor = boost::dynamic_pointer_cast<
OptionUint32>(getAnyRelayOption(D6O_VENDOR_OPTS,
RELAY_SEARCH_FROM_CLIENT));
// Check if this is indeed DOCSIS3 environment
if (!vendor || vendor->getValue() != VENDOR_ID_CABLE_LABS) {
return (HWAddrPtr());
}
// If it is, try to get cable modem mac
OptionPtr cm_mac = vendor->getOption(DOCSIS3_V6_CMTS_CM_MAC);
if (!cm_mac) {
return (HWAddrPtr());
}
OptionBuffer buf = cm_mac->getData();
if (buf.size() > 1) {
return (HWAddrPtr(new HWAddr(cm_mac->getData(), HTYPE_DOCSIS)));
} else {
return (HWAddrPtr());
}
}
......
......@@ -305,9 +305,42 @@ protected:
/// @return Hardware address (or NULL)
virtual HWAddrPtr getMACFromIPv6RelayOpt();
/// @brief Extract MAC/Hardware address from client-id.
///
/// This method attempts to extract MAC/Hardware address from DUID sent
/// as client-id. This method may fail, as only DUID-LLT and DUID-LL are
/// based on link-layer addresses. Client may use other valid DUID types
/// and this method will fail.
///
/// @return Hardware address (or NULL)
virtual HWAddrPtr getMACFromDUID();
HWAddrPtr hwaddr_;
/// @brief Attempts to extract MAC/Hardware address from DOCSIS options
/// inserted by the modem itself.
///
/// The mechanism extracts that information from DOCSIS option
/// (vendor-specific info, vendor-id=4491, suboption 36). Note that
/// in a DOCSIS capable network, the MAC address information is provided
/// several times. The first is specified by the modem itself. The second
/// is added by the CMTS, which acts as a relay agent. This method
/// attempts to extract the former. See @ref getMACFromDocsisCMTS
/// for a similar method that extracts from the CMTS (relay) options.
///
/// @return hardware address (if DOCSIS suboption 36 is present)
virtual HWAddrPtr getMACFromDocsisModem();
/// @brief Attempts to extract MAC/Hardware address from DOCSIS options.
///
/// The DHCPv6 mechanism extracts that information from DOCSIS option
/// (vendor-specific info, vendor-id=4491, suboption 1026). Note that
/// in a DOCSIS capable network, the MAC address information is provided
/// several times. The first is specified by the modem itself. The second
/// is added by the CMTS, which acts as a relay agent. This method
/// attempts to extract the latter. See @ref getMACFromDocsisModem
/// for a similar method that extracts from the modem (client) options.
///
/// @return hardware address (if DOCSIS suboption 1026 is present)
virtual HWAddrPtr getMACFromDocsisCMTS();
/// @brief Builds on wire packet for TCP transmission.
///
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment