📄 igmp.c
字号:
entry = (igmp_entry *) knewa (igmp_entry, (int)IGMP_CNT); if (entry == (igmp_entry *)0) {#ifdef DEBUG os_printf("igmpinit: out of heap !!!!!\n");#endif return FNS_ENOMEM; } OS_MEMSET ((char *)entry, 0, (unsigned long)(sizeof(igmp_entry)*IGMP_CNT)); igmp_tbl = entry; igmp_entries = 0; return 0;}/********************************************************************** ** igmp_no_v1_router ( void *vndp ) * * PARAMETERS: vndp - A *netdev passed as a void * * DESCRIPTION: Timer callback for when the IGMPv2 No V1 Router Present * timer expires. When it does when can then start sending * v2 reports again. * * RETURNS: none * ***********************************************************************/int igmp_no_v1_router( void *vndp ){ netdev *ndp = (netdev *)vndp; if( !ndp ) { /* Its times like this that you just want to die */ os_printf( "igmp_no_v1_router: INTERNAL ERROR - NULL ndp\n"); return -1; } ndp->v1_router_present = false; return 0;}/********************************************************************** ** igmp_report () * * PARAMETERS: m *mp - pointer to the received structure * * DESCRIPTION: Processes a received IGMP V1 or V2 report. Note * that there isn't really any difference in processing. * There are two different report types soley for * the benefit of IGMPv2 Routers so they can tell when * there are IGMPv2 hosts present. * * * RETURNS: none * ***********************************************************************/voidigmp_report( m *mp ){ fast IGMP_T *igmphp; int i; igmphp = (IGMP_T *)mp->m_cp; switch( IGMP_TP(igmphp) ) { case IGMP_V1_REPORT:#ifdef IGMP_TEST os_printf("\n\tIGMP_V1_REPORT from %lX : ",mp->m_src.a_ipa.ip_nethost);#endif break; case IGMP_V2_REPORT:#ifdef IGMP_TEST os_printf("\n\tIGMP_V2_REPORT from %lX : ", mp->m_src.a_ipa.ip_nethost);#endif break; default:#ifdef IGMP_TEST os_printf("\n\n\t\tIGMP REPORT RECEIVED WITH UNKNOWN TYPE from %lX\n", mp->m_src.a_ipa.ip_nethost);#endif return; } if ((i = igmp_find (MemToHost32(&igmphp[IGMP_T_IP_ADDR]),mp->m_ndp)) >= 0 ) { if( igmp_tbl[i].state == IGMP_DELAY ) { if (igmp_tbl[i].timer != (tcb *)0) { t_stop(igmp_tbl[i].timer); igmp_tbl[i].state = IGMP_IDLE; igmp_tbl[i].last_2_report = false; } } }#ifdef DEBUG else { os_printf("IGMP report received but not one of our interfaces\n"); }#endif#ifdef IGMP_TEST /* Print the report */ os_printf("MRP %02x : ", igmphp[IGMP_T_MAX_RESP_TIME]); os_printf("Group addr %u.%u.%u.%u\n", igmphp[IGMP_T_IP_ADDR+0], igmphp[IGMP_T_IP_ADDR+1], igmphp[IGMP_T_IP_ADDR+2], igmphp[IGMP_T_IP_ADDR+3]);#endif}/********************************************************************** ** igmp_query () * * PARAMETERS: m *mp - pointer to the received structure * * DESCRIPTION: Processes a received IGMP V1 or V2 general, or group-specific * query. * * RETURNS: none * ***********************************************************************//* Note: a new requirement for IGMPv2 is that when a query is received and a group is already in the delaying state then the timer should be reset to the new Max Response Time if, and only if, the Max Response Time is < the time remaining before the timer expires.*/voidigmp_query( m *mp ){ fast IGMP_T *igmphp; use_critical; u8 max_resp_time; netdev *ndp = mp->m_ndp; igmphp = (IGMP_T *)mp->m_cp; /* First validate */ if( MemToHost32(&igmphp[IGMP_T_IP_ADDR]) == 0 ) { /* Should be a general query. Verify that it is being sent to the allhost address. */ if( ntohl(mp->m_dest.a_ipa.ip_nethost) != IGMP_ALLHOST ) {#ifdef DEBUG os_printf("IGMP general query not addressed to all hosts\n");#endif return; } }else { /* Must be a group-specific query. See if its legit */ if( MemToHost32(&igmphp[IGMP_T_IP_ADDR]) != mp->m_dest.a_ipa.ip_nethost) { return; } } /* For IGMPv2 if this is a v1 query we must not send any v2 reports on this interface (for any group) until IGMP_V1_ROUTER_PRESENT_TIMEOUT seconds have passed. By definition it is a v1 query if the max response time is zero. */ if( igmphp[IGMP_T_MAX_RESP_TIME] == 0 ) { ndp->v1_router_present = true; if( ndp->v1_router_tcb ) { /* Stop timer and restart with full timeout again */ critical; t_stop(ndp->v1_router_tcb); normal; } /* Note that t_new will work for an existing timer also */ if( !(ndp->v1_router_tcb = t_new ( ndp->v1_router_tcb, igmp_no_v1_router, (void *)ndp, (u32)IGMP_V1_ROUTER_PRESENT_TIMEOUT*(u32)1000, (u16)0 )) ) {#ifdef DEBUG os_printf("igmp_report: Out of heap!!\n");#endif return; } } /* Now start timers */ if( ndp->v1_router_present ) { max_resp_time = 0; }else { max_resp_time = igmphp[IGMP_T_MAX_RESP_TIME]; } if( MemToHost32(&igmphp[IGMP_T_IP_ADDR]) == 0 ) { /* General Query */ igmp_start_t (mp->m_ndp, (a32 *)0, max_resp_time); }else { /* Call igmp_start_t with the group address so it only starts the timer for that entry. */ igmp_start_t ( mp->m_ndp, (a32 *)&igmphp[IGMP_T_IP_ADDR], max_resp_time); }}/********************************************************************** ** igmp_leave () * * PARAMETERS: m *mp - pointer to the received structure * * DESCRIPTION: Processes a received IGMP V2 leave message (demo/test) * * RETURNS: none * ***********************************************************************/voidigmp_leave( m *mp ){#ifdef IGMP_TEST fast IGMP_T *igmphp; int i; igmphp = (IGMP_T *)mp->m_cp; /* Validate the leave meassage */ if( mp->m_dest.a_ipa.ip_nethost != IGMP_ALLROUTER ) { os_printf("IGMP V2 Leave not addressed to all routers\n"); } if( !is_D_class( &igmphp[IGMP_T_IP_ADDR] )) { os_printf("IGMP V2 Leave with group address not class D\n"); } /* Print the report */ os_printf("\n\n\t\tIGMP V2 Leave received from %lX\n", mp->m_src.a_ipa.ip_nethost); os_printf("\t\tMax Reponse Time (unused) = %02x\n", igmphp[IGMP_T_MAX_RESP_TIME] ); os_printf("\t\tGroup address = %u.%u.%u.%u\n", igmphp[IGMP_T_IP_ADDR + 0], igmphp[IGMP_T_IP_ADDR + 1], igmphp[IGMP_T_IP_ADDR + 2], igmphp[IGMP_T_IP_ADDR + 3] );#else return;#endif}/********************************************************************** ** igmp_dink () * * PARAMETERS: m *mp - pointer to the received structure * * DESCRIPTION: Allows IGMP to set the TTL to 1 as required by the RFC * * RETURNS: next function (always dispose since we're done). ************************************************************************/int igmp_dink( m *mp ){ IPH_T * iphp; iphp = m_ptr(mp, IPH_T); iphp[IPH_TTL] = 1; return 0;}/********************************************************************** ** igmp_up () * * PARAMETERS: m *mp - pointer to the received structure * * DESCRIPTION: Checks if the following: * - igmp packet length * - igmp version * - igmp checksum * - Dest ip address is the same as group ip * Based on igmp type processes the packet. * * RETURNS: next function (always dispose since we're done). ************************************************************************/export st igmp_up (struct m *mp){ fast IGMP_T *igmphp; igmphp = (IGMP_T *)mp->m_cp; if (mp->m_tp - mp->m_cp != SIZEOF_IGMP_T) {#ifdef DEBUG os_printf("igmp_up: wrong size\n");#endif return (st)mp->m_dispfn; } /* We save the checksum of each incoming packet for use in the "random" number generator. */ offset = NetToHost16(&igmphp[IGMP_T_IGMP_CHECKSUM]); if (oc_sum((a16 *)igmphp, mp->m_tp - mp->m_cp)) {#ifdef DEBUG os_printf("igmp_up: wrong checksum\n");#endif return (st)mp->m_dispfn; } switch (IGMP_TP(igmphp)) { case IGMP_QUERY: igmp_query(mp); break; case IGMP_V1_REPORT: case IGMP_V2_REPORT: igmp_report(mp); break; case IGMP_V2_LEAVE: igmp_leave(mp); break; default:#ifdef DEBUG os_printf("IGMP - UNKNOWN TYPE %x RECEIVED\n", IGMP_TP(igmphp));#endif break; } return (st)mp->m_dispfn;}/********************************************************************** ** igmp_start_t () * * PARAMETERS: netdev *ndp - device driver pointer * * DESCRIPTION: Starts the timer for all IDLE multicast entries in * the igmp_tbl. The interval timer is set by igmp_num(). * * RETURNS: 0 if OK * -1 if problem. ************************************************************************//* For IGMPv2 we must accept an (optionally NULL) group address for the case of a group-specific query, and a max response time for the case of IGMPv2 queries. Also, for IGMPv2 (max_resp_time > 0) we must restart the timer with a new random value <= max_resp_time if t_remaining is greater than max_resp_time.*/int igmp_start_t (netdev *ndp, a32 *groupaddr, u8 max_resp_time ){ int i; int bFound = 0; use_critical; critical; for (i=0; i < IGMP_CNT; i++) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -