Esempio n. 1
0
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;

    }

}
Esempio n. 2
0
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;
}
Esempio n. 3
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;

    }

}
Esempio n. 4
0
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);

}