igmp.c

来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 627 行 · 第 1/2 页

C
627
字号
		/*		 * an old report		 */		++igmpstat.igps_rcv_reports;		if (ifp->if_flags & IFF_LOOPBACK)			break;		if (!IN_MULTICAST(ntohl(igmp->igmp_group.s_addr)) ||		    igmp->igmp_group.s_addr != ip->ip_dst.s_addr) {			++igmpstat.igps_rcv_badreports;			m_freem(m);			return;		}		/*		 * KLUDGE: if the IP source address of the report has an		 * unspecified (i.e., zero) subnet number, as is allowed for		 * a booting host, replace it with the correct subnet number		 * so that a process-level multicast routing demon can		 * determine which subnet it arrived from.  This is necessary		 * to compensate for the lack of any way for a process to		 * determine the arrival interface of an incoming packet.		 */		if ((ntohl(ip->ip_src.s_addr) & IN_CLASSA_NET) == 0) {			IFP_TO_IA(ifp, ia);			if (ia) ip->ip_src.s_addr = htonl(ia->ia_subnet);		}		/*		 * If we belong to the group being reported, stop		 * our timer for that group.		 */		IN_LOOKUP_MULTI(igmp->igmp_group, ifp, inm);		if (inm != NULL) {		  inm->inm_timer = 0;		  ++igmpstat.igps_rcv_ourreports;		  		  switch(inm->inm_state){		  case IGMP_IDLE_MEMBER:		  case IGMP_LAZY_MEMBER:		  case IGMP_AWAKENING_MEMBER:		  case IGMP_SLEEPING_MEMBER:		    inm->inm_state = IGMP_SLEEPING_MEMBER;		    break;		  case IGMP_DELAYING_MEMBER:		    if (inm->inm_rti->type == IGMP_OLD_ROUTER)			inm->inm_state = IGMP_LAZY_MEMBER;		    else			inm->inm_state = IGMP_SLEEPING_MEMBER;		    break;		  }		}	      		break;	      case IGMP_HOST_NEW_MEMBERSHIP_REPORT:		/*		 * a new report		 */		/*		 * We can get confused and think there's someone		 * else out there if we are a multicast router.		 * For fast leave to work, we have to know that		 * we are the only member.		 */		IFP_TO_IA(ifp, ia);		if (ia && ip->ip_src.s_addr == IA_SIN(ia)->sin_addr.s_addr)			break;		++igmpstat.igps_rcv_reports;    		if (ifp->if_flags & IFF_LOOPBACK)		  break;				if (!IN_MULTICAST(ntohl(igmp->igmp_group.s_addr)) ||		    igmp->igmp_group.s_addr != ip->ip_dst.s_addr) {		  ++igmpstat.igps_rcv_badreports;		  m_freem(m);		  return;		}				/*		 * KLUDGE: if the IP source address of the report has an		 * unspecified (i.e., zero) subnet number, as is allowed for		 * a booting host, replace it with the correct subnet number		 * so that a process-level multicast routing demon can		 * determine which subnet it arrived from.  This is necessary		 * to compensate for the lack of any way for a process to		 * determine the arrival interface of an incoming packet.		 */		if ((ntohl(ip->ip_src.s_addr) & IN_CLASSA_NET) == 0) {/* #ifndef MROUTING XXX - I don't think the ifdef is necessary */		  IFP_TO_IA(ifp, ia);/* #endif */		  if (ia) ip->ip_src.s_addr = htonl(ia->ia_subnet);		}				/*		 * If we belong to the group being reported, stop		 * our timer for that group.		 */		IN_LOOKUP_MULTI(igmp->igmp_group, ifp, inm);		if (inm != NULL) {		  inm->inm_timer = 0;		  ++igmpstat.igps_rcv_ourreports;		  		  switch(inm->inm_state){		  case IGMP_DELAYING_MEMBER:		  case IGMP_IDLE_MEMBER:		    inm->inm_state = IGMP_LAZY_MEMBER;		    break;		  case IGMP_AWAKENING_MEMBER:		    inm->inm_state = IGMP_LAZY_MEMBER;		    break;		  case IGMP_LAZY_MEMBER:		  case IGMP_SLEEPING_MEMBER:		    break;		  }		}	}	/*	 * Pass all valid IGMP packets up to any process(es) listening	 * on a raw IGMP socket.	 */	rip_input(m);}voidigmp_joingroup(inm)	struct in_multi *inm;{	int s = splnet();	inm->inm_state = IGMP_IDLE_MEMBER;	if ((inm->inm_addr.s_addr & igmp_local_group_mask) == igmp_local_group	    || inm->inm_ifp->if_flags & IFF_LOOPBACK)		inm->inm_timer = 0;	else {		igmp_sendpkt(inm,fill_rti(inm));		inm->inm_timer = IGMP_RANDOM_DELAY(					IGMP_MAX_HOST_REPORT_DELAY*PR_FASTHZ);		inm->inm_state = IGMP_DELAYING_MEMBER;		igmp_timers_are_running = 1;	}	splx(s);}voidigmp_leavegroup(inm)	struct in_multi *inm;{         switch(inm->inm_state) {	 case IGMP_DELAYING_MEMBER:	 case IGMP_IDLE_MEMBER:	   if (((inm->inm_addr.s_addr & igmp_local_group_mask) 		!= igmp_local_group)	       && !(inm->inm_ifp->if_flags & IFF_LOOPBACK))	       if (inm->inm_rti->type != IGMP_OLD_ROUTER)		   igmp_sendleave(inm);	   break;	 case IGMP_LAZY_MEMBER:	 case IGMP_AWAKENING_MEMBER:	 case IGMP_SLEEPING_MEMBER:	   break;	 }}voidigmp_fasttimo(){	register struct in_multi *inm;	struct in_multistep step;	int s;	/*	 * Quick check to see if any work needs to be done, in order	 * to minimize the overhead of fasttimo processing.	 */	if (!igmp_timers_are_running)		return;	s = splnet();	igmp_timers_are_running = 0;	IN_FIRST_MULTI(step, inm);	while (inm != NULL) {		if (inm->inm_timer == 0) {			/* do nothing */		} else if (--inm->inm_timer == 0) {		  if (inm->inm_state == IGMP_DELAYING_MEMBER) {		    if (inm->inm_rti->type == IGMP_OLD_ROUTER)			igmp_sendpkt(inm, IGMP_HOST_MEMBERSHIP_REPORT);		    else			igmp_sendpkt(inm, IGMP_HOST_NEW_MEMBERSHIP_REPORT);		    inm->inm_state = IGMP_IDLE_MEMBER;		  }		} else {			igmp_timers_are_running = 1;		}		IN_NEXT_MULTI(step, inm);	}	splx(s);}voidigmp_slowtimo(){	int s = splnet();	register struct router_info *rti =  Head;#ifdef IGMP_DEBUG	printf("[igmp.c,_slowtimo] -- > entering \n");#endif	while (rti) {		rti->time ++;		if (rti->time >= IGMP_AGE_THRESHOLD){			rti->type = IGMP_NEW_ROUTER;			rti->time = IGMP_AGE_THRESHOLD;		}		rti = rti->next;	}#ifdef IGMP_DEBUG		printf("[igmp.c,_slowtimo] -- > exiting \n");#endif	splx(s);}static voidigmp_sendpkt(inm, type)	struct in_multi *inm;	int type;{        struct mbuf *m;        struct igmp *igmp;        struct ip *ip;        struct ip_moptions *imo;        MGETHDR(m, M_DONTWAIT, MT_HEADER);        if (m == NULL)                return;	MALLOC(imo, struct ip_moptions *, sizeof *imo, M_IPMOPTS, M_DONTWAIT);	if (!imo) {		m_free(m);		return;	}	m->m_pkthdr.rcvif = loif;	m->m_pkthdr.len = sizeof(struct ip) + IGMP_MINLEN;	MH_ALIGN(m, IGMP_MINLEN + sizeof(struct ip));	m->m_data += sizeof(struct ip);        m->m_len = IGMP_MINLEN;        igmp = mtod(m, struct igmp *);        igmp->igmp_type   = type;        igmp->igmp_code   = 0;        igmp->igmp_group  = inm->inm_addr;        igmp->igmp_cksum  = 0;        igmp->igmp_cksum  = in_cksum(m, IGMP_MINLEN);        m->m_data -= sizeof(struct ip);        m->m_len += sizeof(struct ip);        ip = mtod(m, struct ip *);        ip->ip_tos        = 0;        ip->ip_len        = sizeof(struct ip) + IGMP_MINLEN;        ip->ip_off        = 0;        ip->ip_p          = IPPROTO_IGMP;        ip->ip_src.s_addr = INADDR_ANY;        ip->ip_dst        = igmp->igmp_group;        imo->imo_multicast_ifp  = inm->inm_ifp;        imo->imo_multicast_ttl  = 1;	imo->imo_multicast_vif  = -1;        /*         * Request loopback of the report if we are acting as a multicast         * router, so that the process-level routing demon can hear it.         */        imo->imo_multicast_loop = (ip_mrouter != NULL);        ip_output(m, (struct mbuf *)0, (struct route *)0, 0, imo);	FREE(imo, M_IPMOPTS);        ++igmpstat.igps_snd_reports;}static voidigmp_sendleave(inm)	struct in_multi *inm;{	igmp_sendpkt(inm, IGMP_HOST_LEAVE_MESSAGE);}intigmp_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,	    void *newp, size_t newlen){	/* All sysctl names at this level are terminal. */	if (namelen != 1)		return ENOTDIR;	/* XXX overloaded */	switch(name[0]) {	case IGMPCTL_STATS:		return sysctl_rdstruct(oldp, oldlenp, newp, &igmpstat, 				       sizeof igmpstat);	default:		return ENOPROTOOPT;	}}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?