/* 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
#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, "" },
{ "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.
};
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) {
/// 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;
/// @}
// 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());
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_;
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.
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_;
#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>
// +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());
}
}
/// @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.
///