diff --git a/src/address.cc b/src/address.cc
index f0298d7..993a237 100644
--- a/src/address.cc
+++ b/src/address.cc
@@ -57,6 +57,19 @@ address::address(const address& addr)
_mask.s6_addr32[3] = addr._mask.s6_addr32[3];
}
+address::address(const ptr
& addr)
+{
+ _addr.s6_addr32[0] = addr->_addr.s6_addr32[0];
+ _addr.s6_addr32[1] = addr->_addr.s6_addr32[1];
+ _addr.s6_addr32[2] = addr->_addr.s6_addr32[2];
+ _addr.s6_addr32[3] = addr->_addr.s6_addr32[3];
+
+ _mask.s6_addr32[0] = addr->_mask.s6_addr32[0];
+ _mask.s6_addr32[1] = addr->_mask.s6_addr32[1];
+ _mask.s6_addr32[2] = addr->_mask.s6_addr32[2];
+ _mask.s6_addr32[3] = addr->_mask.s6_addr32[3];
+}
+
address::address(const std::string& str)
{
parse_string(str);
diff --git a/src/address.h b/src/address.h
index 90b1a03..f320d49 100644
--- a/src/address.h
+++ b/src/address.h
@@ -31,6 +31,7 @@ class address {
public:
address();
address(const address& addr);
+ address(const ptr& addr);
address(const std::string& str);
address(const char* str);
address(const in6_addr& addr);
diff --git a/src/iface.cc b/src/iface.cc
index 6c09f60..56357e3 100644
--- a/src/iface.cc
+++ b/src/iface.cc
@@ -385,7 +385,7 @@ ssize_t iface::read_solicit(address& saddr, address& daddr, address& taddr)
saddr = ip6h->ip6_src;
logger::debug() << "iface::read_solicit() saddr=" << saddr.to_string()
- << ", daddr=" << daddr.to_string() << ", len=" << len;
+ << ", daddr=" << daddr.to_string() << ", taddr=" << taddr.to_string() << ", len=" << len;
return len;
}
@@ -589,10 +589,22 @@ int iface::poll_all()
if (!saddr.is_unicast()/* || !daddr.is_multicast()*/) {
continue;
}
+
+ if (ifa->_pr)
+ {
+ // Setup the reverse path
+ if (saddr.is_unicast()) {
+ ptr se = ifa->_pr->find_or_create_session(saddr);
+ if (se) {
+ se->add_iface(ifa);
+ se->handle_advert(ifa);
+ }
+ }
- if (ifa->_pr) {
- ifa->_pr->handle_solicit(saddr, daddr, taddr);
+ // Now process the solicit
+ ifa->_pr->handle_solicit(saddr, taddr);
}
+
} else {
if (ifa->read_advert(saddr, taddr) < 0) {
logger::error() << "Failed to read from interface '%s'", ifa->_name.c_str();
@@ -606,7 +618,7 @@ int iface::poll_all()
const ptr sess = *s_it;
- if ((sess->taddr() == taddr) && (sess->status() == session::WAITING || sess->status() == session::RENEWING)) {
+ if ((sess->taddr() == taddr)) {
sess->handle_advert(ifa);
found = true;
break;
@@ -615,7 +627,7 @@ int iface::poll_all()
if (found == false) {
if (ifa->owner()) {
- ifa->owner()->handle_advert(saddr, taddr, ifa);
+ ifa->owner()->handle_advert(taddr, ifa);
} else {
logger::debug() << "iface::poll_all - ignoring advert on proxy iface=" << ifa->name();
}
diff --git a/src/proxy.cc b/src/proxy.cc
index 4197232..5cbc81f 100644
--- a/src/proxy.cc
+++ b/src/proxy.cc
@@ -63,7 +63,7 @@ ptr proxy::open(const std::string& ifname, bool promiscuous)
return create(ifa, promiscuous);
}
-ptr proxy::find_or_create_session(const address& saddr, const address& daddr, const address& taddr, const ptr& receiver)
+ptr proxy::find_or_create_session(const address& taddr)
{
// Let's check this proxy's list of sessions to see if we can
// find one with the same target address.
@@ -75,31 +75,8 @@ ptr proxy::find_or_create_session(const address& saddr, const address&
return (*sit);
}
- // Check if there is an address for this specific interface it was received
- // on (if so then immediately return a notice)
-
ptr se;
- if (receiver) {
- for (std::list >::iterator ad = address::addresses_begin();
- ad != address::addresses_end(); ad++)
- {
- if ((*ad)->addr() == taddr && (*ad)->ifname() == receiver->name())
- {
- se = session::create(_ptr, saddr, daddr, taddr, _autowire, _keepalive, _retries);
- if (se) {
- se->add_iface(receiver);
- _sessions.push_back(se);
-
- logger::debug() << "proxy::handle_advert() found local taddr=" << taddr;
- se->handle_advert(receiver);
-
- return se;
- }
- }
- }
- }
-
// Since we couldn't find a session that matched, we'll try to find
// a matching rule instead, and then set up a new session.
@@ -109,16 +86,9 @@ ptr proxy::find_or_create_session(const address& saddr, const address&
logger::debug() << "checking " << ru->addr() << " against " << taddr;
- if (!daddr.is_multicast() && ru->addr() != daddr && daddr != taddr) {
- continue;
- }
-
- if (receiver && ru->ifa() && receiver->name() != ru->ifa()->name())
- continue;
-
if (ru->addr() == taddr) {
if (!se) {
- se = session::create(_ptr, saddr, daddr, taddr, _autowire, _keepalive, _retries);
+ se = session::create(_ptr, taddr, _autowire, _keepalive, _retries);
}
if (ru->is_auto()) {
@@ -138,6 +108,7 @@ ptr proxy::find_or_create_session(const address& saddr, const address&
// it "static" and immediately send the response.
se->handle_advert();
return se;
+
} else {
ptr ifa = (*it)->ifa();
@@ -150,18 +121,6 @@ ptr proxy::find_or_create_session(const address& saddr, const address&
se->handle_advert();
}
#endif
-
- // If a local address exists and it is for the requested interface
- // then we already have a valid session
- for (std::list >::iterator ad = address::addresses_begin();
- ad != address::addresses_end(); ad++)
- {
- if ((*ad)->addr() == taddr && (*ad)->ifname() == ifa->name()) {
- logger::debug() << "proxy::handle_advert() found local taddr=" << taddr;
- se->handle_advert(ifa);
- break;
- }
- }
}
}
}
@@ -173,27 +132,46 @@ ptr proxy::find_or_create_session(const address& saddr, const address&
return se;
}
-void proxy::handle_advert(const address& saddr, const address& taddr, const ptr& receiver)
+void proxy::handle_advert(const address& taddr, const ptr& receiver)
{
logger::debug()
- << "proxy::handle_advert() proxy=" << (ifa() ? ifa()->name() : "null") << ", receiver=" << (receiver ? receiver->name() : "null")
- << ", saddr=" << saddr.to_string()
- << ", taddr=" << taddr.to_string();
+ << "proxy::handle_advert() proxy=" << (ifa() ? ifa()->name() : "null") << ", receiver=" << (receiver ? receiver->name() : "null");
- ptr se = find_or_create_session(all_nodes, all_nodes, taddr, receiver);
+ ptr se = find_or_create_session(taddr);
if (!se) return;
se->handle_advert(receiver);
}
-void proxy::handle_solicit(const address& saddr, const address& daddr, const address& taddr)
+void proxy::handle_solicit(const address& saddr, const address& taddr)
{
logger::debug()
- << "proxy::handle_solicit() ifa=" << ((_ifa) ? _ifa->name() : "null")
- << ", saddr=" << saddr.to_string()
- << ", taddr=" << taddr.to_string();
+ << "proxy::handle_solicit() ifa=" << ((_ifa) ? _ifa->name() : "null");
- ptr se = find_or_create_session(saddr, daddr, taddr, ptr());
+ // Check if the address is for an interface we own that is attached to
+ // one of the slave interfaces
+ for (std::list >::iterator ad = address::addresses_begin(); ad != address::addresses_end(); ad++)
+ {
+ if ((*ad)->addr() == taddr)
+ {
+ for (std::list >::iterator it = _rules.begin(); it != _rules.end(); it++) {
+ ptr ru = *it;
+
+ if (ru->ifa() && ru->ifa()->name() == (*ad)->ifname())
+ {
+ logger::debug() << "proxy::handle_solicit() found local taddr=" << taddr;
+
+ if (_ifa)
+ _ifa->write_advert(saddr, taddr, router());
+ }
+ }
+
+ return;
+ }
+ }
+
+ // Otherwise find or create a session to scan for this address
+ ptr se = find_or_create_session(taddr);
if (!se) return;
se->touch();
@@ -201,11 +179,11 @@ void proxy::handle_solicit(const address& saddr, const address& daddr, const add
switch (se->status()) {
case session::WAITING:
case session::INVALID:
- return;
+ se->add_pending(saddr);
case session::VALID:
case session::RENEWING:
- se->send_advert();
+ se->send_advert(saddr);
}
}
diff --git a/src/proxy.h b/src/proxy.h
index e7faffc..d045e52 100644
--- a/src/proxy.h
+++ b/src/proxy.h
@@ -34,11 +34,11 @@ public:
static ptr open(const std::string& ifn, bool promiscuous);
- ptr find_or_create_session(const address& saddr, const address& daddr, const address& taddr, const ptr& receiver);
+ ptr find_or_create_session(const address& taddr);
- void handle_advert(const address& saddr, const address& taddr, const ptr& receiver);
+ void handle_advert(const address& taddr, const ptr& receiver);
- void handle_solicit(const address& saddr, const address& daddr, const address& taddr);
+ void handle_solicit(const address& saddr, const address& taddr);
void remove_session(const ptr& se);
diff --git a/src/session.cc b/src/session.cc
index 317a31f..1159a60 100644
--- a/src/session.cc
+++ b/src/session.cc
@@ -114,16 +114,13 @@ session::~session()
}
}
-ptr session::create(const ptr& pr, const address& saddr,
- const address& daddr, const address& taddr, bool auto_wire, bool keepalive, int retries)
+ptr session::create(const ptr& pr, const address& taddr, bool auto_wire, bool keepalive, int retries)
{
ptr se(new session());
se->_ptr = se;
se->_pr = pr;
- se->_saddr = address("::") == saddr ? all_nodes : saddr;
se->_taddr = taddr;
- se->_daddr = daddr;
se->_autowire = auto_wire;
se->_keepalive = keepalive;
se->_retries = retries;
@@ -134,8 +131,8 @@ ptr session::create(const ptr& pr, const address& saddr,
_sessions.push_back(se);
logger::debug()
- << "session::create() pr=" << logger::format("%x", (proxy* )pr) << ", proxy=" << ((pr->ifa()) ? pr->ifa()->name() : "null") << ", saddr=" << saddr
- << ", daddr=" << daddr << ", taddr=" << taddr << " =" << logger::format("%x", (session* )se);
+ << "session::create() pr=" << logger::format("%x", (proxy* )pr) << ", proxy=" << ((pr->ifa()) ? pr->ifa()->name() : "null")
+ << ", taddr=" << taddr << " =" << logger::format("%x", (session* )se);
return se;
}
@@ -149,6 +146,16 @@ void session::add_iface(const ptr& ifa)
_ifaces.push_back(ifa);
}
+void session::add_pending(const address& addr)
+{
+ for (std::list >::iterator ad = _pending.begin(); ad != _pending.end(); ad++) {
+ if (addr == (*ad))
+ return;
+ }
+
+ _pending.push_back(new address(addr));
+}
+
void session::send_solicit()
{
logger::debug() << "session::send_solicit() (_ifaces.size() = " << _ifaces.size() << ")";
@@ -171,13 +178,16 @@ void session::touch()
}
}
-void session::send_advert()
+void session::send_advert(const address& daddr)
{
- _pr->ifa()->write_advert(_saddr, _taddr, _pr->router());
+ _pr->ifa()->write_advert(daddr, _taddr, _pr->router());
}
void session::handle_auto_wire(const ptr& ifa)
{
+ if (_wired == true)
+ return;
+
logger::debug()
<< "session::handle_auto_wire() taddr=" << _taddr << ", ifa=" << ifa->name();
@@ -238,8 +248,18 @@ void session::handle_advert()
_status = VALID;
_ttl = _pr->ttl();
_fails = 0;
+
+ if (!_pending.empty()) {
+ for (std::list >::iterator ad = _pending.begin();
+ ad != _pending.end(); ad++) {
+ ptr addr = (*ad);
+ logger::debug() << " - forward to " << addr;
- send_advert();
+ send_advert(addr);
+ }
+
+ _pending.clear();
+ }
}
const address& session::taddr() const
@@ -247,16 +267,6 @@ const address& session::taddr() const
return _taddr;
}
-const address& session::saddr() const
-{
- return _saddr;
-}
-
-const address& session::daddr() const
-{
- return _daddr;
-}
-
bool session::autowire() const
{
return _autowire;
diff --git a/src/session.h b/src/session.h
index fd2b82a..08eb73d 100644
--- a/src/session.h
+++ b/src/session.h
@@ -43,6 +43,8 @@ private:
// An array of interfaces this session is monitoring for
// ND_NEIGHBOR_ADVERT on.
std::list > _ifaces;
+
+ std::list > _pending;
// The remaining time in miliseconds the object will stay in the
// interface's session array or cache.
@@ -70,10 +72,11 @@ public:
// Destructor.
~session();
- static ptr create(const ptr& pr, const address& saddr,
- const address& daddr, const address& taddr, bool autowire, bool keepalive, int retries);
+ static ptr create(const ptr& pr, const address& taddr, bool autowire, bool keepalive, int retries);
void add_iface(const ptr& ifa);
+
+ void add_pending(const address& addr);
const address& taddr() const;
@@ -107,7 +110,7 @@ public:
void touch();
- void send_advert();
+ void send_advert(const address& daddr);
void send_solicit();