void mcast_recv_igmp(int sockfd, int version) { unsigned char buf[MAX_RECV_BUF_LEN] = {0}; int num = 0; struct iphdr* ip = NULL; int iph_len = 0, igh_len = 0; struct igmphdr *p_igh; pi_addr pig, pia; struct msghdr msg; struct sockaddr sa; struct iovec iov; struct cmsghdr *cmsg; char *ctrl = (char *) malloc(MAXCTRLSIZE); struct in_pktinfo *info; unsigned int if_index = 0; imp_interface* p_if = NULL; /*To get the unique index of the interfacethe packet was received on*/ bzero(&msg, sizeof(msg)); iov.iov_base = buf; iov.iov_len = 2048; msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = ctrl; msg.msg_controllen = MAXCTRLSIZE; msg.msg_name = &sa; msg.msg_namelen = sizeof(struct sockaddr); num = recvmsg(get_igmp_mld_socket(AF_INET), &msg, MSG_WAITALL); if (num <= sizeof(*ip)) { IMP_LOG_ERROR("BAD packet received n=%d \n", num); free(ctrl); return; } for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg)) { if (cmsg->cmsg_type == IP_PKTINFO) { info = (struct in_pktinfo *) CMSG_DATA(cmsg); if_index = info->ipi_ifindex; } } free(ctrl); /*return if the interface don't enable igmp*/ for(p_if = imp_interface_first();p_if;p_if = LIST_NEXT(p_if, link)) { if(p_if->if_index == if_index && p_if->if_addr.ss.ss_family == AF_INET) break; } if(p_if == NULL){ IMP_LOG_WARNING("Don't exist this VIF\n", if_index); return; } IMP_LOG_DEBUG("src addr = %s\nreceived interface %d\n", imp_inet_ntoa(((struct sockaddr_in*)&sa)->sin_addr.s_addr), if_index); ip = (struct iphdr*)buf; if (ip->protocol != IPPROTO_IGMP && ip->protocol != 0) { IMP_LOG_ERROR("error protocol number %d\n", ip->protocol); return; } imp_build_piaddr(AF_INET, &ip->daddr, &pig); imp_build_piaddr(AF_INET, &ip->saddr, &pia); if (mcast_if_get_by_addr(&pia) != NULL) { IMP_LOG_DEBUG("Ignore igmp from myself\n"); return; } /*when protocol is zero, we need add MFC base one this kind of packet*/ if (ip->protocol == 0 && p_if->type == INTERFACE_UPSTREAM) { if_set ttls; bzero(&ttls, sizeof(ttls)); /*get ttls*/ if(imp_get_mfcc_ttls(&ttls, MAXVIFS, &pia, &pig) != 0){ IMP_LOG_DEBUG("add MFC:src -- %s group -- %s\n\n", imp_pi_ntoa(&pia), imp_pi_ntoa(&pig)); imp_membership_db_mfc_add(&pig, &pia, &ttls); } return; } else if (ip->protocol == 0) { return; } if (p_if->type != INTERFACE_DOWNSTREAM) { IMP_LOG_WARNING("Don't exist this Downstream VIF\n"); return; } #if 0 /*print hex*/ for(;i<num;i++) { if(i%10 == 0) printf("\n"); printf("0x%02x ", buf[i]); } printf("\n"); #endif iph_len = ip->ihl * sizeof(int); if(iph_len < 24) { /*to do:need to judge option if is RAO or not */ IMP_LOG_WARNING("Don't contain Router alter option\n"); return; } igh_len = num - iph_len; p_igh = (struct igmphdr*)((char*)ip + iph_len); if(in_cusm((unsigned short*)p_igh, igh_len) != 0) { IMP_LOG_ERROR("check sum is error\n"); return; } switch (p_igh->type) { case IGMP_HOST_MEMBERSHIP_REPORT: imp_input_report_v1v2(p_if, p_igh); break; case IGMP_HOST_LEAVE_MESSAGE: case IGMPV2_HOST_MEMBERSHIP_REPORT: if (version < IM_IGMPv2_MLDv1) { IMP_LOG_WARNING("Don't support IGMPv2, " \ "current version is igmpv%d\n", version); return; } imp_input_report_v1v2(p_if, p_igh); break; case IGMPV3_HOST_MEMBERSHIP_REPORT: if (version < IM_IGMPv3_MLDv2) { IMP_LOG_WARNING("Don't support IGMPv3, " \ "current version is igmpv%d\n", version); return; } imp_input_report_v3(p_if, (struct igmpv3_report*)p_igh, igh_len); break; default: IMP_LOG_WARNING("unknown igmp type 0x%x\n", p_igh->type); break; } }
static int imp_verify_multicast_addr(pi_addr *p_pia) { if(p_pia->ss.ss_family == AF_INET6) { if (!IN6_IS_ADDR_MULTICAST(p_pia->v6.sin6_addr.s6_addr)) { IMP_LOG_ERROR("Address %s isn't multicast address\n", imp_pi_ntoa(p_pia)); return -1; } /* Interface-Local scope spans only a single interface on a node * and is useful only for loopback transmission of multicast. * * Link-Local multicast scope spans the same topological region as * the corresponding unicast scope. * [RFC 4291 section 2.7] */ if (IN6_IS_ADDR_MC_LINKLOCAL(p_pia->v6.sin6_addr.s6_addr) || IN6_IS_ADDR_MC_NODELOCAL(p_pia->v6.sin6_addr.s6_addr)) { IMP_LOG_WARNING("Group address %s is link-local multicast address\n", imp_pi_ntoa(p_pia)); return -1; } /* * Nodes must not originate a packet to a multicast address whose scop * field contains the reserved value 0; if such a packet is received, it * must be silently dropped. Nodes should not originate a packet to a * multicast address whose scop field contains the reserved value F; if * such a packet is sent or received, it must be treated the same as * packets destined to a global (scop E) multicast address. * [RFC 4291 section 2.7] */ if ((p_pia->v6.sin6_addr.s6_addr[1] & 0x0f) == 0) { IMP_LOG_WARNING("group address %s's scope is 0, Ignore it.\n", imp_pi_ntoa(p_pia)); return -1; } } else if(p_pia->ss.ss_family == AF_INET) { if (!IN_MULTICAST(p_pia->v4.sin_addr.s_addr)) { IMP_LOG_ERROR("group address %s isn't multicast adddress\n", imp_pi_ntoa(p_pia)); return -1; } /* * Address Range Size Designation * ------------- ---- ----------- * 224.0.0.0 - 224.0.0.255 (/24) Local Network Control Block * * Addresses in the Local Network Control Block are used for protocol * control traffic that is not forwarded off link. * [RFC 5771 section 4] */ if (IN_LOCAL_CONTROL_BLOCK(p_pia->v4.sin_addr.s_addr)) { IMP_LOG_INFO("Group address %s is Local Network Control Block\n", imp_pi_ntoa(p_pia)); return -1; } /* 239.255.0.0/16 is defined to be the IPv4 Local Scope. * [RFC 2365 section 6.1] */ if (IN_LOCAL_SCOPE_BLOCK(p_pia->v4.sin_addr.s_addr)) { IMP_LOG_INFO("Group address %s belongs to IPv4 Local Scope.\n", imp_pi_ntoa(p_pia)); return -1; } }else return -1; return 0; }
void mcast_recv_mld(int sockfd, int version) { unsigned char buf[MAX_RECV_BUF_LEN] = {0}; int num = 0; pi_addr pig, pia; struct msghdr msg; struct sockaddr_in6 sa; struct iovec iov; struct cmsghdr *cmsg; char *ctrl = (char *) malloc(MAXCTRLSIZE); struct in6_pktinfo *info; unsigned int if_index = 0; struct mld_hdr *p_mldh; imp_interface *p_if = NULL; /*To get the unique index of the interfacethe packet was received on*/ bzero(&msg, sizeof(msg)); iov.iov_base = buf; iov.iov_len = 2048; msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = ctrl; msg.msg_controllen = MAXCTRLSIZE; msg.msg_name = &sa; msg.msg_namelen = sizeof(struct sockaddr_in6); num = recvmsg(get_igmp_mld_socket(AF_INET6), &msg, MSG_WAITALL); if (num <= 20) { IMP_LOG_ERROR("BAD packet received n=%d \n", num); free(ctrl); return; } for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg)) { if (cmsg->cmsg_type == IPV6_PKTINFO) { info = (struct in6_pktinfo *) CMSG_DATA(cmsg); if_index = info->ipi6_ifindex; imp_build_piaddr(AF_INET6, &info->ipi6_addr, &pig); imp_build_piaddr(AF_INET6, &sa.sin6_addr, &pia); IMP_LOG_DEBUG("from %s %s %d\n", imp_pi_ntoa(&pig), imp_pi_ntoa(&pia), if_index); } } free(ctrl); if (if_index == 0) { /* * Structure used to communicate from kernel to multicast router. * We'll overlay the structure onto an MLD header (not an IPv6 heder like igmpmsg{} * used for IPv4 implementation). This is because this structure will be passed via an * IPv6 raw socket, on wich an application will only receiver the payload i.e the data after * the IPv6 header and all the extension headers. (See section 3 of RFC 3542) */ struct mrt6msg *p_mrmsg; int mif = 0; p_mrmsg = msg.msg_iov->iov_base; IMP_LOG_DEBUG("DUMP mrmsg:\n\tmif %d\n\tmsgtype %d\n\tsrc %s\n\tgroup %s\n", p_mrmsg->im6_mif, p_mrmsg->im6_msgtype, imp_inet6_ntoa(p_mrmsg->im6_src.s6_addr), imp_inet6_ntoa(p_mrmsg->im6_dst.s6_addr)); imp_build_piaddr(AF_INET6, &p_mrmsg->im6_dst, &pig); imp_build_piaddr(AF_INET6, &p_mrmsg->im6_src, &pia); mif = k_get_vmif(get_up_if_index(), AF_INET6); IMP_LOG_DEBUG("k_get_vmif = %d im6_mif %d\n", mif, p_mrmsg->im6_mif); if (mif == p_mrmsg->im6_mif) { if_set ttls; bzero(&ttls, sizeof(ttls)); /*get ttls*/ if (imp_get_mfcc_ttls(&ttls, MAXVIFS, &pia, &pig) != 0) { IMP_LOG_DEBUG("add MFC:src -- %s group -- %s\n\n", imp_pi_ntoa(&pia), imp_pi_ntoa(&pig)); imp_membership_db_mfc_add(&pig, &pia, &ttls); } } return; } /* An MLDv2 Report MUST be sent with a valid IPv6 link-local source * address, or the unspecified address (::), if the sending interface * has not acquired a valid link-local address yet. * [rfc 3810 5.2.13] */ if (!(IN6_IS_ADDR_LINKLOCAL(&sa.sin6_addr) || IN6_IS_ADDR_UNSPECIFIED(&sa.sin6_addr))) { IMP_LOG_ERROR("MLDv2 Report MUST be sent with a valid IPv6 link-local " "source address, or the unspecified address (::).\n"); return; } /*return if the interface don't enable igmp*/ for(p_if = imp_interface_first();p_if;p_if = LIST_NEXT(p_if, link)) { if(p_if->if_index == if_index && p_if->if_addr.ss.ss_family == AF_INET6) break; } if (p_if == NULL) { IMP_LOG_WARNING("Don't exist this VIF\n"); return; } p_mldh = msg.msg_iov->iov_base; switch (p_mldh->mld_type) { case MLD_LISTENER_REPORT: case MLD_LISTENER_REDUCTION: imp_input_report_mld(p_if, p_mldh); break; case MLD_V2_LISTENER_REPORT: if (version < IM_IGMPv3_MLDv2) { IMP_LOG_WARNING("current version is mldv%d\n", version - 1); return; } imp_input_report_mldv2(p_if, p_mldh, num); break; default: IMP_LOG_WARNING("unknown type %d\n", p_mldh->mld_type); break; } }
void mcast_to_in_handler(imp_interface *p_if, pi_addr *p_ga, pa_list* p_src_list, im_version version) { imp_group *p_gp; pa_list *p_node = NULL; struct timeval lmqt; imp_time_val(TIMER_LMQT, &lmqt); p_gp = imp_group_find(p_if, p_ga); if (p_gp != NULL) { IMP_LOG_DEBUG("Leave Group %s\n", imp_pi_ntoa(p_ga)); if (p_gp->version < version) { IMP_LOG_WARNING("%s's Group Compatibility Mode is IGMPv1.\n", imp_pi_ntoa(p_ga)); return; } if (p_gp->type == GROUP_INCLUDE) { /*INCLUDE (A) TO_IN (B) INCLUDE (A+B) (B)=GMI Send Q(G, A-B) */ imp_source *p_is = NULL; for (p_is = LIST_FIRST(&p_gp->src_list); p_is; p_is = LIST_NEXT(p_is, link)) { if (pa_list_find(p_src_list, &p_is->src_addr) == NULL) { /* Send Q(G, A-B)*/ if(TIMEVAL_LT(lmqt, p_is->timer->tm)) { p_is->times = DEFAULT_RV; imp_set_timer(TIMER_LMQT, p_is->timer); } } else { imp_set_timer(TIMER_GMI, p_is->timer); } } for(p_node = p_src_list; p_node; p_node = p_node->next) { if (imp_source_find(p_gp, &p_node->addr, FORWARDING) == NULL){ imp_source_create(p_gp, &p_node->addr, FORWARDING);/*forward*/ } } } else { /*EXCLUDE (X, Y) TO_IN (A) EXCLUDE (X+A, Y-A) (A)=GMI * Send Q(G, X-A) * Send Q(G) */ imp_source *p_is = NULL, *p_is_next = NULL; /*Y-A*/ for (p_is = LIST_FIRST(&p_gp->src_list); p_is; p_is = p_is_next) { p_is_next = LIST_NEXT(p_is, link); if(!TIMEVAL_ISZERO(p_is->timer->tm)) continue; if (pa_list_find(p_src_list, &p_is->src_addr) != NULL) { imp_source_cleanup(p_is); } } for (p_is = LIST_FIRST(&p_gp->src_list); p_is; p_is = LIST_NEXT(p_is, link)) { if(TIMEVAL_ISZERO(p_is->timer->tm)) continue; if (pa_list_find(p_src_list, &p_is->src_addr) == NULL) { /*Send Q(G, X-A)*/ if(TIMEVAL_LT(lmqt, p_is->timer->tm)) { p_is->times = DEFAULT_RV; imp_set_timer(TIMER_LMQT, p_is->timer); } } else { imp_set_timer(TIMER_GMI, p_is->timer); } } for(p_node = p_src_list; p_node; p_node = p_node->next) { if (imp_source_find(p_gp, &p_node->addr, FORWARDING) == NULL){ imp_source_create(p_gp, &p_node->addr, FORWARDING);/*forward*/ } } /*Send Q(G)*/ if(p_gp->gs_sch_times == 0) { IMP_LOG_DEBUG("Send Q(G)\n"); p_gp->gs_sch_times = DEFAULT_RV; imp_set_timer(TIMER_LMQT, p_gp->timer); } } if(p_gp->sch_timer == NULL) { p_gp->sch_timer = imp_add_timer( group_source_specific_timer_handler, p_gp); imp_set_timer(0, p_gp->sch_timer); } return; } if(p_src_list == NULL) return; IMP_LOG_DEBUG("Can't find group %s, will create it\n", imp_pi_ntoa(p_ga)); p_gp = imp_group_create(p_if, p_ga, p_src_list, GROUP_INCLUDE, version); if (p_gp == NULL) { IMP_LOG_ERROR("imp_group_create failed"); return; } imp_group_print(p_if); }