#include <dhcp/option_vendor.h>
#include <dhcp/option_string.h>
#include <dhcp/pkt4.h>
+#include <dhcp/pkt4o6.h>
+#include <dhcp/pkt6.h>
#include <dhcp/docsis3_option_defs.h>
+#include <dhcp4/dhcp4_dhcp4o6_ipc.h>
#include <dhcp4/dhcp4_log.h>
#include <dhcp4/dhcp4_srv.h>
#include <dhcpsrv/addr_utilities.h>
resp_.reset(new Pkt4(resp_type, getQuery()->getTransid()));
copyDefaultFields();
copyDefaultOptions();
+
+ if (getQuery()->isDhcp4o6()) {
+ initResponse4o6();
+ }
}
}
+void
+Dhcpv4Exchange::initResponse4o6() {
+ Pkt4o6Ptr query = boost::dynamic_pointer_cast<Pkt4o6>(getQuery());
+ if (!query) {
+ return;
+ }
+ const Pkt6Ptr& query6 = query->getPkt6();
+ Pkt6Ptr resp6(new Pkt6(DHCPV6_DHCPV4_RESPONSE, query6->getTransid()));
+ // Don't add client-id or server-id
+ // But copy relay info
+ if (!query6->relay_info_.empty()) {
+ resp6->copyRelayInfo(query6);
+ }
+ // Copy interface and remote address
+ resp6->setIface(query6->getIface());
+ resp6->setIndex(query6->getIndex());
+ resp6->setRemoteAddr(query6->getRemoteAddr());
+ resp_.reset(new Pkt4o6(resp_, resp6));
+}
+
void
Dhcpv4Exchange::copyDefaultFields() {
resp_->setIface(query_->getIface());
LOG_ERROR(dhcp4_logger, DHCP4_SRV_D2STOP_ERROR).arg(ex.what());
}
+ try {
+ Dhcp4o6Ipc::instance().close();
+ } catch(const std::exception& ex) {
+ // Highly unlikely, but lets Report it but go on
+ // LOG_ERROR(dhcp4_logger, DHCP4_SRV_DHCP4O6_ERROR).arg(ex.what());
+ }
+
IfaceMgr::instance().closeSockets();
// The lease manager was instantiated during DHCPv4Srv configuration,
isc::dhcp::Subnet4Ptr
Dhcpv4Srv::selectSubnet(const Pkt4Ptr& query) const {
+ // DHCPv4-over-DHCPv6 is a special (and complex) case
+ if (query->isDhcp4o6()) {
+ return (selectSubnet4o6(query));
+ }
+
Subnet4Ptr subnet;
SubnetSelector selector;
return (subnet);
}
+isc::dhcp::Subnet4Ptr
+Dhcpv4Srv::selectSubnet4o6(const Pkt4Ptr& query) const {
+#ifdef notyet
+ CfgMgr& cfgmgr = CfgMgr::instance();
+ Subnet4Ptr subnet;
+ Subnet6Ptr subnet6;
+ SubnetSelector selector;
+ selector.client_classes_ = query->classes_;
+
+ // DHCPv4 relay or option
+ selector.giaddr_ = query->getGiaddr();
+ if (!selector.giaddr_.isV4Zero()) {
+ subnet = cfgmgr.getCurrentCfg()->getCfgSubnets4()->selectSubnet(selector);
+ }
+
+ // DHCPv6 relay
+ if (!subnet) {
+ Pkt4o6Ptr query4o6 = boost::dynamic_pointer_cast<Pkt4o6>(query);
+ if (!query4o6) {
+ isc_throw(Unexpected, "Can't get DHCP4o6 message");
+ }
+ const Pkt6Ptr& query6 = query4o6->getPkt6();
+ if (query6 && !query6->relay_info_.empty()) {
+ selector.first_relay_linkaddr_ = query6->relay_info_.back().linkaddr_;
+ selector.interface_id_ =
+ query6->getAnyRelayOption(D6O_INTERFACE_ID, Pkt6::RELAY_GET_FIRST);
+ subnet6 =
+ cfgmgr.getCurrentCfg()->getCfgSubnets6()->selectSubnet(selector);
+ }
+ if (subnet6) {
+ // Rely on matching IDs
+ const Subnet4Collection* subnets =
+ cfgmgr.getCurrentCfg()->getCfgSubnets4()->getAll();
+ for (Subnet4Collection::const_iterator it = subnets->begin();
+ it != subnets->end(); ++it) {
+ if ((*it)->getID() == subnet6->getID()) {
+ subnet = *it;
+ }
+ }
+ }
+ }
+
+ // Applying default DHCPv4 rules (but not the IPv6 remote address)
+ if (!subnet) {
+ selector.ciaddr_ = query->getCiaddr();
+ // selector.remote_address_ = query->getRemoteAddr();
+ selector.iface_name_ = query->getIface();
+
+ subnet =
+ cfgmgr.getCurrentCfg()->getCfgSubnets4()->selectSubnet(selector);
+ }
+
+ // Let's execute all callouts registered for subnet4_select
+ // TODO
+
+ if (subnet) {
+ // Log at higher debug level that subnet has been found.
+ LOG_DEBUG(packet4_logger, DBG_DHCP4_BASIC_DATA, DHCP4_SUBNET_SELECTED)
+ .arg(query->getLabel())
+ .arg(subnet->getID());
+ // Log detailed information about the selected subnet at the
+ // lower debug level.
+ LOG_DEBUG(packet4_logger, DBG_DHCP4_DETAIL_DATA, DHCP4_SUBNET_DATA)
+ .arg(query->getLabel())
+ .arg(subnet->toText());
+
+ } else {
+ LOG_DEBUG(packet4_logger, DBG_DHCP4_DETAIL,
+ DHCP4_SUBNET_SELECTION_FAILED)
+ .arg(query->getLabel());
+ }
+
+ return (subnet);
+#else
+ return (Subnet4Ptr());
+#endif
+}
+
Pkt4Ptr
Dhcpv4Srv::receivePacket(int timeout) {
- return (IfaceMgr::instance().receive4(timeout));
+ Pkt4Ptr pkt = IfaceMgr::instance().receive4(timeout);
+ if (!pkt) {
+ Pkt4o6Ptr& pkt4o6 = Dhcp4o6Ipc::instance().getReceived();
+ if (pkt4o6) {
+ pkt = pkt4o6;
+ pkt4o6.reset();
+ }
+ }
+ return (pkt);
}
void
Dhcpv4Srv::sendPacket(const Pkt4Ptr& packet) {
- IfaceMgr::instance().send(packet);
+ if (!packet->isDhcp4o6()) {
+ IfaceMgr::instance().send(packet);
+ } else {
+ Pkt4o6Ptr pkt4o6 = boost::dynamic_pointer_cast<Pkt4o6>(packet);
+ // Should not happen
+ if (!pkt4o6) {
+ isc_throw(Unexpected, "Dhcp4o6 packet cast fail");
+ }
+ Dhcp4o6Ipc::instance().send(pkt4o6->getPkt6());
+ }
}
bool
// Instead we will need to use the address assigned to the interface
// on which the query has been received. In other cases, we will just
// use this address as a source address for the response.
- if (local_addr.isV4Bcast()) {
+ // Do the same for DHCPv4-over-DHCPv6 exchanges.
+ if (local_addr.isV4Bcast() || query->isDhcp4o6()) {
SocketInfo sock_info = IfaceMgr::instance().getSocket(*query);
local_addr = sock_info.addr_;
}
Pkt4Ptr query = ex.getQuery();
Pkt4Ptr response = ex.getResponse();
+ // DHCPv4-over-DHCPv6 is simple
+ if (query->isDhcp4o6()) {
+ response->setRemoteAddr(query->getRemoteAddr());
+ return;
+ }
+
// The DHCPINFORM is slightly different than other messages in a sense
// that the server should always unicast the response to the ciaddr.
// It appears however that some clients don't set the ciaddr. We still
if (pkt->isRelayed()) {
return (true);
}
+
+ // Accept all DHCPv4-over-DHCPv6 messages.
+ if (pkt->isDhcp4o6()) {
+ return (true);
+ }
+
// The source address must not be zero for the DHCPINFORM message from
// the directly connected client because the server will not know where
// to respond if the ciaddr was not present.