summaryrefslogtreecommitdiff
path: root/mcast/common/.svn/text-base/mld_client.c.svn-base
diff options
context:
space:
mode:
Diffstat (limited to 'mcast/common/.svn/text-base/mld_client.c.svn-base')
-rw-r--r--mcast/common/.svn/text-base/mld_client.c.svn-base244
1 files changed, 244 insertions, 0 deletions
diff --git a/mcast/common/.svn/text-base/mld_client.c.svn-base b/mcast/common/.svn/text-base/mld_client.c.svn-base
new file mode 100644
index 0000000..d291466
--- /dev/null
+++ b/mcast/common/.svn/text-base/mld_client.c.svn-base
@@ -0,0 +1,244 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+#undef DEBUG
+#include "headers.h"
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+int send_mldv2_report (struct intnode *intn, int grec_number, struct in6_addr *mcas, int srcn, struct in6_addr *sources, int mode)
+{
+ unsigned int length;
+ struct mld_report_packet
+ {
+ struct ip6_hdr ip6;
+ struct ip6_hbh hbh;
+ struct
+ {
+ uint8_t type;
+ uint8_t length;
+ uint16_t value;
+ uint8_t optpad[2];
+ } routeralert;
+ struct mld2_report mld2r;
+ } *packet;
+ struct mld2_grec *grec = NULL;
+ struct in6_addr *src = NULL;
+ int mca_index, src_index;
+ int count = 0;
+
+ bool any = false;
+
+
+ //printf("creating multicast listener report packet....\n");
+ //printf("size src = %d size grec = %d \n",sizeof(*src),sizeof(*grec));
+ if (intn->mtu < sizeof (*packet)) {
+ /*
+ * MTU is too small to support this type of packet
+ * Should not happen though
+ */
+ dbg ("MTU too small for packet while sending MLDv2 report on interface %s/%u mtu=%u!?\n", intn->name, intn->ifindex, intn->mtu);
+ return -1;
+ }
+
+ /* Allocate a buffer matching the MTU size of this interface */
+ packet = (struct mld_report_packet *) malloc (intn->mtu);
+
+ if (!packet) {
+ err ("Cannot get memory for MLD2 report packet, aborting\n");
+ }
+// printf("addr packet = %u \n",packet);
+ memset (packet, 0, intn->mtu);
+
+
+ /* Create the IPv6 packet */
+ packet->ip6.ip6_vfc = 0x60;
+ packet->ip6.ip6_plen = ntohs (sizeof (*packet) - sizeof (packet->ip6));
+ packet->ip6.ip6_nxt = IPPROTO_HOPOPTS;
+ packet->ip6.ip6_hlim = 1;
+
+ /*
+ * The source address must be the link-local address
+ * of the interface we are sending on
+ */
+ memcpy (&packet->ip6.ip6_src, &intn->linklocal, sizeof (packet->ip6.ip6_src));
+
+ /* MLDv2 Report -> All IPv6 Multicast Routers (ff02::16) */
+ packet->ip6.ip6_dst.s6_addr[0] = 0xff;
+ packet->ip6.ip6_dst.s6_addr[1] = 0x02;
+ packet->ip6.ip6_dst.s6_addr[15] = 0x16;
+
+ /* HopByHop Header Extension */
+ packet->hbh.ip6h_nxt = IPPROTO_ICMPV6;
+ packet->hbh.ip6h_len = 0;
+
+ /* Router Alert Option */
+ packet->routeralert.type = 5;
+ packet->routeralert.length = sizeof (packet->routeralert.value);
+ packet->routeralert.value = 0; /* MLD ;) */
+
+ /* Option Padding */
+ packet->routeralert.optpad[0] = IP6OPT_PADN;
+ packet->routeralert.optpad[1] = 0;
+
+ /* ICMPv6 MLD Report */
+ packet->mld2r.type = ICMP6_V2_MEMBERSHIP_REPORT;
+ //number of multi cast address reocrds
+ packet->mld2r.ngrec = 0; //grec_number;//htons(1);
+ length = 0;
+ count = 0;
+ for (mca_index = 0; mca_index < grec_number; mca_index++) {
+ src = NULL;
+ if (!grec) {
+ length = sizeof (*packet) + sizeof (*grec) - sizeof (packet->ip6);
+ //fprintf(stdout,"(grec = %02d) %02d. current report length = %04d MTU: %04d)\n",packet->mld2r.ngrec,mca_index,length+sizeof(packet->ip6),intn->mtu);
+
+ if (length + sizeof (packet->ip6) > intn->mtu) {
+ /* Should not happen! Would mean the MTU is smaller than a standard mld report */
+ dbg ("No grec and MTU too small for packet while sending MLDv2 report on interface %s/%u mtu=%u!?\n", intn->name, intn->ifindex, intn->mtu);
+ free (packet);
+ return (-1);
+ } else
+ grec = (struct mld2_grec *) (((char *) packet) + sizeof (*packet));
+
+ packet->mld2r.ngrec++;
+ } else {
+ if (!src)
+ length = ((((char *) grec) - ((char *) packet)) + sizeof (*grec) + (sizeof (*src) * (grec->grec_nsrcs))) - sizeof (packet->ip6);
+
+ //fprintf(stdout,"\nloop1:(grec = %02d) %02d.length = %04d (Total : %04d MTU: %04d)\n\n", packet->mld2r.ngrec , mca_index,length,(length + sizeof(packet->ip6)), intn->mtu);
+
+ if (((length + sizeof (packet->ip6) + sizeof (*grec)) > intn->mtu)) {
+
+ /* Take care of endianess */
+ //fprintf(stdout,"next grec record does not fit... sending... \n");
+
+ packet->mld2r.ngrec = htons (packet->mld2r.ngrec);
+ grec->grec_nsrcs = htons (grec->grec_nsrcs);
+
+ /* Calculate and fill in the checksum */
+ packet->ip6.ip6_plen = htons (length);
+ packet->mld2r.csum = htons (0);
+ packet->mld2r.csum = ipv6_checksum (&packet->ip6, IPPROTO_ICMPV6, (uint8_t *) & packet->mld2r, length - sizeof (struct ip6_hbh) - sizeof (packet->routeralert));
+ count++;
+#ifdef DEBUG
+ dbg ("%04d.Sending2 MLDv2 Report on %s/%u, ngrec=%u, length=%u sources=%u (in last grec)\n", count, intn->name, intn->ifindex, ntohs (packet->mld2r.ngrec), length, ntohs (grec->grec_nsrcs));
+ sendpacket6 (intn, (const struct ip6_hdr *) packet, length + sizeof (packet->ip6));
+#endif
+ /* Increase ICMP sent statistics */
+ g_conf->stat_icmp_sent++;
+ intn->stat_icmp_sent++;
+
+ /* Reset the MLDv2 struct */
+ packet->mld2r.ngrec = 0;
+ grec = (struct mld2_grec *) (((char *) packet) + sizeof (*packet));
+ } else {
+ //next grec
+ grec->grec_nsrcs = htons (grec->grec_nsrcs);
+ grec = (struct mld2_grec *) (((char *) grec) + sizeof (*grec) + (sizeof (*src) * ntohs (grec->grec_nsrcs)));
+
+ }
+ packet->mld2r.ngrec++;
+ }
+ //Copy MCA to record
+ memcpy (&grec->grec_mca, mcas + mca_index, sizeof (grec->grec_mca));
+
+ /* Zero sources upto now */
+ grec->grec_nsrcs = 0;
+ /* 0 Sources -> Exclude those */
+ grec->grec_type = MLD2_MODE_IS_EXCLUDE;
+ if (mode) {
+ grec->grec_type = mode;
+ }
+
+ /* Nothing added yet */
+ any = false;
+
+ for (src_index = 0; src_index < srcn || (!srcn && src_index == 0); src_index++) {
+
+ //check for duplicate source reocrds and any address
+
+ /* Packet with at least one grec and one or more src's, excluding ip6 header */
+
+ length = (((char *) grec) - ((char *) packet)) + sizeof (*grec) + (sizeof (*src) * (grec->grec_nsrcs)) - sizeof (packet->ip6);
+
+ //fprintf(stdout,"loop2:(grec = %02d) %02d.length = %04d (Total : %04d MTU: %04d)\n", packet->mld2r.ngrec,mca_index,length,(length + sizeof(packet->ip6)),intn->mtu);
+ /* Would adding it not fit? -> Send it out */
+ if (((length + sizeof (packet->ip6) + sizeof (*src)) > (intn->mtu)) && srcn) {
+ //fprintf(stdout,"next source addr. does not fit... sending... \n");
+ //fprintf(stdout,"src_index = %d grec->grec_nsrcs = %d \n",src_index,grec->grec_nsrcs);
+
+ /* Take care of endianess */
+ packet->mld2r.ngrec = htons (packet->mld2r.ngrec);
+ grec->grec_nsrcs = htons (grec->grec_nsrcs);
+ /* Calculate and fill in the checksum */
+
+ packet->ip6.ip6_plen = htons (length);
+ packet->mld2r.csum = htons (0);
+ packet->mld2r.csum = ipv6_checksum (&packet->ip6, IPPROTO_ICMPV6, (uint8_t *) & packet->mld2r, length - sizeof (struct ip6_hbh) - sizeof (packet->routeralert));
+
+ count++;
+ dbg ("%04d.Sending2 MLDv2 Report on %s/%u, ngrec=%u, length=%u sources=%u (in last grec)\n", count, intn->name, intn->ifindex, ntohs (packet->mld2r.ngrec), length, ntohs (grec->grec_nsrcs));
+ sendpacket6 (intn, (const struct ip6_hdr *) packet, length + sizeof (packet->ip6));
+
+ /* Increase ICMP sent statistics */
+ g_conf->stat_icmp_sent++;
+ intn->stat_icmp_sent++;
+
+ /* Reset the MLDv2 struct */
+ packet->mld2r.ngrec = 0;
+ src = NULL;
+ grec = NULL;
+ //if not IS_EX or TO EXCLUDE_MODE splitting must be done
+ break;
+ }
+
+ /* Only add non-:: addresses */
+ if (!srcn)
+ break;
+ if (!IN6_IS_ADDR_UNSPECIFIED (sources + src_index) && srcn) {
+ /* First/Next address */
+ src = (struct in6_addr *) (((char *) grec) + sizeof (*grec) + (sizeof (*src) * grec->grec_nsrcs));
+ /* An additional source */
+ grec->grec_nsrcs++;
+ if (mode) {
+ grec->grec_type = mode; //MLD2_MODE_IS_EXCLUDE;
+ }
+ /* Append the source address */
+ memcpy (src, sources + src_index, sizeof (*src));
+ }
+ }
+ }
+
+ //fprintf(stdout,"done\n");
+ if (packet->mld2r.ngrec == 0) {
+ //fprintf(stdout,"All data sent !!!!!!\n");
+ free (packet);
+ packet = NULL;
+ return (1);
+ }
+ /* Take care of endianess */
+ length = (((char *) grec) - ((char *) packet) + sizeof (*grec) + (sizeof (*src) * (grec->grec_nsrcs)) - sizeof (packet->ip6));
+ packet->mld2r.ngrec = htons (packet->mld2r.ngrec);
+ grec->grec_nsrcs = htons (grec->grec_nsrcs);
+
+ /* Calculate and fill in the checksum */
+ packet->ip6.ip6_plen = htons (length);
+ packet->mld2r.csum = htons (0);
+ packet->mld2r.csum = ipv6_checksum (&packet->ip6, IPPROTO_ICMPV6, (uint8_t *) & packet->mld2r, length - sizeof (struct ip6_hbh) - sizeof (packet->routeralert));
+ count++;
+ dbg ("%04d.Sending2 MLDv2 Report on %s/%u, ngrec=%u, length=%u sources=%u (in last grec)\n", count, intn->name, intn->ifindex, ntohs (packet->mld2r.ngrec), length, ntohs (grec->grec_nsrcs));
+ sendpacket6 (intn, (const struct ip6_hdr *) packet, length + sizeof (packet->ip6));
+
+ /* Increase ICMP sent statistics */
+ g_conf->stat_icmp_sent++;
+ intn->stat_icmp_sent++;
+
+ free (packet);
+ //fprintf(stdout,"Total ICMP packets sent = %llu\n", intn->stat_icmp_sent );
+ return 0;
+}