mcproxy has no way to send an IGMPv2 query today. If you force IGMPv2 (by setting the protocol in the mcproxy config and setting the force_igmp_version flag on all interfaces) the bridge will send v2 queries but if mcproxy takes over as the querier it will send v3 queries. The patch below adds support for sending v2 queries so everyone stays in sync: Signed-off-by: Sukru Senli <sukru.senli@iopsys.eu> Signed-off-by: Chad Monroe <chad.monroe@smartrg.com> Signed-off-by: John Crispin <john@phrozen.org>
116 lines
4.4 KiB
Diff
116 lines
4.4 KiB
Diff
--- a/mcproxy/include/proxy/igmp_sender.hpp
|
|
+++ b/mcproxy/include/proxy/igmp_sender.hpp
|
|
@@ -37,9 +37,10 @@ class igmp_sender : public sender
|
|
{
|
|
private:
|
|
bool send_igmpv3_query(unsigned int if_index, const timers_values& tv, const addr_storage& gaddr, bool s_flag, const source_list<source>& slist) const;
|
|
+ bool send_igmpv2_query(unsigned int if_index, const timers_values& tv, const addr_storage& gaddr ) const;
|
|
|
|
public:
|
|
- igmp_sender(const std::shared_ptr<const interfaces>& interfaces);
|
|
+ igmp_sender(const std::shared_ptr<const interfaces>& interfaces, const group_mem_protocol gmp);
|
|
|
|
bool send_record(unsigned int if_index, mc_filter filter_mode, const addr_storage& gaddr, const source_list<source>& slist) const override;
|
|
|
|
--- a/mcproxy/src/proxy/igmp_sender.cpp
|
|
+++ b/mcproxy/src/proxy/igmp_sender.cpp
|
|
@@ -32,7 +32,7 @@
|
|
|
|
#include <memory>
|
|
|
|
-igmp_sender::igmp_sender(const std::shared_ptr<const interfaces>& interfaces): sender(interfaces, IGMPv3)
|
|
+igmp_sender::igmp_sender(const std::shared_ptr<const interfaces>& interfaces, const group_mem_protocol gmp): sender(interfaces, gmp)
|
|
{
|
|
HC_LOG_TRACE("");
|
|
|
|
@@ -119,10 +119,79 @@ bool igmp_sender::send_mc_addr_and_src_s
|
|
return rc;
|
|
}
|
|
|
|
+bool igmp_sender::send_igmpv2_query(unsigned int if_index, const timers_values& tv, const addr_storage& gaddr ) const
|
|
+{
|
|
+ HC_LOG_TRACE("");
|
|
+
|
|
+ std::unique_ptr<unsigned char[]> packet;
|
|
+ unsigned int size;
|
|
+
|
|
+ size = sizeof(ip) + sizeof(router_alert_option) + sizeof(igmp);
|
|
+ packet.reset(new unsigned char[size]);
|
|
+
|
|
+ addr_storage dst_addr;
|
|
+
|
|
+ if (gaddr == addr_storage(AF_INET)) { //is general query
|
|
+ dst_addr = IPV4_ALL_HOST_ADDR;
|
|
+ } else {
|
|
+ dst_addr = gaddr;
|
|
+ }
|
|
+
|
|
+ //-------------------------------------------------------------------
|
|
+ //fill ip header
|
|
+ ip* ip_hdr = reinterpret_cast<ip*>(packet.get());
|
|
+
|
|
+ ip_hdr->ip_v = 4;
|
|
+ ip_hdr->ip_hl = (sizeof(ip) + sizeof(router_alert_option)) / 4;
|
|
+ ip_hdr->ip_tos = 0;
|
|
+ ip_hdr->ip_len = htons(size);
|
|
+ ip_hdr->ip_id = 0;
|
|
+ ip_hdr->ip_off = htons(0 | IP_DF); //dont fragment flag
|
|
+ ip_hdr->ip_ttl = 1;
|
|
+ ip_hdr->ip_p = IPPROTO_IGMP;
|
|
+ ip_hdr->ip_sum = 0;
|
|
+ ip_hdr->ip_src = m_interfaces->get_saddr(interfaces::get_if_name(if_index)).get_in_addr();
|
|
+ ip_hdr->ip_dst = dst_addr.get_in_addr();
|
|
+
|
|
+ //-------------------------------------------------------------------
|
|
+ //fill router_alert_option header
|
|
+ router_alert_option* ra_hdr = reinterpret_cast<router_alert_option*>(reinterpret_cast<unsigned char*>(ip_hdr) + sizeof(ip));
|
|
+ *ra_hdr = router_alert_option();
|
|
+
|
|
+ ip_hdr->ip_sum = m_sock.calc_checksum(reinterpret_cast<unsigned char*>(ip_hdr), sizeof(ip) + sizeof(router_alert_option));
|
|
+
|
|
+ //-------------------------------------------------------------------
|
|
+ //fill igmpv3 query
|
|
+ igmp* query = reinterpret_cast<igmp*>(reinterpret_cast<unsigned char*>(ra_hdr) + sizeof(router_alert_option));
|
|
+
|
|
+ query->igmp_type = IGMP_MEMBERSHIP_QUERY;
|
|
+
|
|
+ if (gaddr == addr_storage(AF_INET)) { //general query
|
|
+ query->igmp_code = tv.maxrespi_to_maxrespc_igmpv3(tv.get_query_response_interval());
|
|
+ } else {
|
|
+ query->igmp_code = tv.maxrespi_to_maxrespc_igmpv3(tv.get_last_listener_query_time());
|
|
+ }
|
|
+
|
|
+ query->igmp_cksum = 0;
|
|
+ query->igmp_group = gaddr.get_in_addr();
|
|
+
|
|
+ query->igmp_cksum = m_sock.calc_checksum(reinterpret_cast<unsigned char*>(query), (sizeof(igmp) ));
|
|
+
|
|
+ if (!m_sock.choose_if(if_index)) {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ return m_sock.send_packet(dst_addr, reinterpret_cast<unsigned char*>(ip_hdr), size);
|
|
+}
|
|
+
|
|
bool igmp_sender::send_igmpv3_query(unsigned int if_index, const timers_values& tv, const addr_storage& gaddr, bool s_flag, const source_list<source>& slist) const
|
|
{
|
|
HC_LOG_TRACE("");
|
|
|
|
+ if ( (m_group_mem_protocol & IGMPv3) == 0 ) {
|
|
+ return send_igmpv2_query( if_index, tv, gaddr );
|
|
+ }
|
|
+
|
|
std::unique_ptr<unsigned char[]> packet;
|
|
unsigned int size;
|
|
|
|
--- a/mcproxy/src/proxy/proxy_instance.cpp
|
|
+++ b/mcproxy/src/proxy/proxy_instance.cpp
|
|
@@ -119,7 +119,7 @@ bool proxy_instance::init_sender()
|
|
{
|
|
HC_LOG_TRACE("");
|
|
if (is_IPv4(m_group_mem_protocol)) {
|
|
- m_sender = std::make_shared<igmp_sender>(m_interfaces);
|
|
+ m_sender = std::make_shared<igmp_sender>(m_interfaces, m_group_mem_protocol );
|
|
} else if (is_IPv6(m_group_mem_protocol)) {
|
|
m_sender = std::make_shared<mld_sender>(m_interfaces);
|
|
} else {
|