1
2/******************************************************************************
3 * Fichier Module :igmpv3.c - An IGMPv3-router implementation
4 ******************************************************************************
5 * Fichier    : igmpv3.c
6 * Description: Implementation de differentes routines du protocole IGMPv3-router
7 *               en se basant sur le "draft-ietf-idmr-igmp-v3-07.txt", Mars 2001
8 * Date       : May 18, 2000
9 * Auteurs    : lahmadi@loria.fr
10 *              Anis.Ben-Hellel@loria.fr
11 * Last Modif : juin 10,  2002
12 *
13 *****************************************************************************/
14
15#include "igmprt.h"
16
17unsigned long upstream;
18int forward_upstream;
19
20/* Foxconn add start by aspen Bai, 01/08/2008 */
21igmp_mulsrc_t mulsrc;
22extern int wan_index;
23extern int lan_index;
24extern int wan_igmp_socket;
25extern igmp_router_t router;
26extern int wan_igmp_version;
27extern unsigned long lan_ipaddr, lan_netmask;
28int wan_version_timer = IGMP_WAN_VERSION_TIMER;
29unsigned int general_query_count = 0;
30int emf_cfg_mfdb_find(struct in_addr group);//aspen
31/* Foxconn add end by aspen Bai, 01/08/2008 */
32
33/* Foxconn add start by aspen Bai, 02/29/2008 */
34/* For multicast throughput test */
35#if 1
36#include <linux/netlink.h>
37#define MAX_DATA_SIZE sizeof(emf_cfg_request_t)
38#define EMFCFG_OPER_TYPE_GET        1
39#define EMFCFG_OPER_TYPE_SET        2
40
41#define EMFCFG_STATUS_SUCCESS       1
42#define EMFCFG_STATUS_FAILURE       2
43#define EMFCFG_STATUS_CMD_UNKNOWN   3
44#define EMFCFG_STATUS_OPER_UNKNOWN  4
45#define EMFCFG_STATUS_INVALID_IF    5
46
47#define EMFCFG_CMD_MFDB_LIST        5
48#define NETLINK_EMFC   17
49#define EMFCFG_MAX_ARG_SIZE         1024
50typedef struct emf_cfg_request
51{
52	unsigned char   inst_id[16];          /* Bridge name as instance identifier */
53	unsigned int  command_id;             /* Command identifier */
54	unsigned int  oper_type;              /* Operation type: GET, SET */
55	unsigned int  status;                 /* Command status */
56	unsigned int  size;                   /* Size of the argument */
57										  /* Command arguments */
58	char   arg[EMFCFG_MAX_ARG_SIZE];
59} emf_cfg_request_t;
60
61typedef struct emf_cfg_mfdb_list
62{
63	unsigned int  num_entries;            /* Number of entries in MFDB */
64	struct mfdb_entry
65	{
66		unsigned int  mgrp_ip;        /* Multicast Group address */
67		unsigned char   if_name[16];    /* Interface name */
68		unsigned int  pkts_fwd;       /* Number of packets forwarded */
69	} mfdb_entry[0];
70} emf_cfg_mfdb_list_t;
71#endif
72/* Foxconn add end by aspen Bai, 02/29/2008 */
73
74/*
75 * int check_src_set(src,set)
76 * check if a source is in a set
77 *
78 */
79int check_src_set (
80        struct in_addr src,
81        igmp_src_t *set)
82{
83    igmp_src_t *sr;
84    for (sr=set;sr;sr=(igmp_src_t *)sr->igmps_next){
85        if (sr->igmps_source.s_addr == src.s_addr)
86            return TRUE;
87    }
88    return FALSE;
89}
90/*
91 * int check_src (
92 *  struct in_addr src,
93 *      struct in_addr *sources,
94 *  int numsrc)
95 */
96int check_src (
97        struct in_addr src,
98        struct in_addr *sources, int numsrc)
99{
100    int i;
101    for (i=0;i< numsrc; i++){
102        if (src.s_addr == sources[i].s_addr)
103            return TRUE;
104    }
105    return FALSE;
106}
107
108/*
109 * void igmp_group_handle_allow
110 * handle an allow report for a group
111 *
112 */
113void igmp_group_handle_allow(
114            igmp_router_t *router,
115            igmp_interface_t *ifp,
116            igmp_group_t *gp,
117            int numsrc,
118            struct in_addr *sources)
119{
120    igmp_src_t *src;
121    int i,num;
122    struct in_addr set_src[MAX_ADDRS];
123    igmp_group_t *gp1;
124    membership_db* member;
125
126    /* state INCLUDE(A+B)*/
127    for (i=0;i<numsrc;i++) {
128      src=igmp_group_src_add(gp,sources[i]);
129          if (ifp->igmpi_addr.s_addr == upstream)
130             k_proxy_chg_mfc(router->igmprt_socket,sources[i].s_addr,gp->igmpg_addr.s_addr,ifp->igmpi_index,forward_upstream);
131          else
132			 k_proxy_chg_mfc(router->igmprt_socket,sources[i].s_addr,gp->igmpg_addr.s_addr,ifp->igmpi_index,1);
133    }
134
135    /* (B) = GMI */
136    num =0;
137    gp1 = gp;
138    for (src=gp->igmpg_sources;src;src=(igmp_src_t *)src->igmps_next){
139      if (check_src(src->igmps_source,sources,numsrc) == TRUE){
140        src->igmps_timer = IGMP_GMI;
141        src->igmps_fstate= FALSE;
142      }
143      set_src[num].s_addr = src->igmps_source.s_addr;
144      num = num+1;
145    }
146    gp = gp1;
147    if (ifp->igmpi_addr.s_addr != upstream){
148      member = (membership_db*)update_multi(router,gp->igmpg_addr,gp->igmpg_fmode,num,set_src);
149      set_source_filter(router,gp,upstream,member->membership.fmode,member->membership.numsources,member->membership.sources);
150    }
151}
152
153/*
154 * void igmp_group_handle_block
155 * handle a block report for a group
156 *
157 */
158void igmp_group_handle_block(
159            igmp_router_t *router,
160            igmp_interface_t *ifp,
161            igmp_group_t *gp,
162            int numsrc,
163            struct in_addr *sources)
164{
165    igmp_src_t *sr,*old_src_set;
166    struct in_addr set_src[MAX_ADDRS];
167    int i,num;
168    igmp_group_t *gp1;
169    membership_db* member;
170
171    old_src_set = gp->igmpg_sources;
172    if (gp->igmpg_fmode ==IGMP_FMODE_INCLUDE){
173        /* send Q(G,A*B) */
174        num=0;
175        gp1=gp;
176        for (sr=gp->igmpg_sources;sr;sr=(igmp_src_t *)sr->igmps_next){
177            if ((check_src_set(sr->igmps_source,old_src_set) == TRUE)&& (check_src(sr->igmps_source,sources,numsrc) == TRUE)){
178                set_src[num].s_addr = sr->igmps_source.s_addr;
179                    num = num+1;
180            }
181        }
182        send_group_src_specific_q(router,ifp,gp,set_src,num);
183        gp=gp1;
184
185        num=0;
186        gp1=gp;
187        for (sr=gp->igmpg_sources;sr;sr=(igmp_src_t *)sr->igmps_next){
188           if (check_src_set(sr->igmps_source,old_src_set) == TRUE) {
189               set_src[num].s_addr=sr->igmps_source.s_addr;
190               num = num+1;
191				}
192            }
193        gp=gp1;
194           if (ifp->igmpi_addr.s_addr != upstream){
195          member = (membership_db*)update_multi(router,gp->igmpg_addr,gp->igmpg_fmode,num,set_src);
196          set_source_filter(router,gp,upstream,member->membership.fmode,member->membership.numsources,member->membership.sources);
197        }
198
199    }else{
200      /* EXCLUDE MODE*/
201      /* add source to group source table*/
202      for (i=0;i<numsrc;i++){
203            sr=igmp_group_src_add(gp,sources[i]);
204        /*(A-X-Y)=group_timer*/
205            if ((check_src_set(sr->igmps_source,old_src_set) == FALSE) && (check_src(sr->igmps_source,sources,numsrc) == TRUE)){
206            sr->igmps_timer= gp->igmpg_timer;
207        sr->igmps_fstate = FALSE;
208        }
209    }
210    /* send Q(G,A-Y) */
211    num=0;
212    gp1=gp;
213    for (sr=gp->igmpg_sources;sr;sr=(igmp_src_t *)sr->igmps_next){
214        if ((check_src(sr->igmps_source,sources,numsrc) == TRUE) && (sr->igmps_timer == 0)){
215             set_src[num].s_addr=sr->igmps_source.s_addr;
216             num = num+1;
217        }
218    }
219    gp=gp1;
220    send_group_src_specific_q(router,ifp,gp,set_src,num);
221
222    num=0;
223    gp1=gp;
224    for (sr=gp->igmpg_sources;sr;sr=(igmp_src_t *)sr->igmps_next){
225      if (check_src_set(sr->igmps_source,old_src_set) == TRUE) {
226        set_src[num].s_addr=sr->igmps_source.s_addr;
227        num = num+1;
228      }
229    }
230    gp=gp1;
231    if (ifp->igmpi_addr.s_addr != upstream){
232      member = (membership_db*)update_multi(router,gp->igmpg_addr,gp->igmpg_fmode,num,set_src);
233      set_source_filter(router,gp,upstream,member->membership.fmode,member->membership.numsources,member->membership.sources);
234    }
235    }
236}
237
238/*
239 * void igmp_group_toex()
240 * Handle a to_ex{} report for a group
241 */
242
243void igmp_group_handle_toex(
244                igmp_router_t *router,
245                igmp_interface_t *ifp,
246                igmp_group_t *gp,
247                int numsrc,
248                struct in_addr *sources)
249{
250    igmp_src_t *src,*sr,*old_src_set;
251    struct in_addr set_src[MAX_ADDRS];
252    igmp_group_t *gp1;
253    int i,num,count=0;
254    membership_db* member;
255	igmp_rep_t *rep;
256
257	//printf("%s, %d\n",__FUNCTION__,__LINE__);
258	for(rep=gp->igmpg_members;rep;rep=(igmp_rep_t *)rep->igmpr_next)
259	{
260		//printf("%s, %d\n",__FUNCTION__,__LINE__);
261		if((rep->igmpr_addr.s_addr != lan_ipaddr) && ((rep->igmpr_addr.s_addr & lan_netmask)
262			    == (lan_ipaddr & lan_netmask)))
263		{
264			//printf("%s, %d\n",__FUNCTION__,__LINE__);
265			count++;
266		}
267	}
268	if(count == 1)
269		if(gp->igmpg_flags!=FIRST_JOIN_GROUP_HAD_SEND)
270			gp->igmpg_flags = FIRST_JOIN_GROUP; /* First join a group */
271		/* Foxconn removed start, zacker, 06/16/2009 */
272		//else
273		//	gp->igmpg_flags = GROUP_INIT;
274		/* Foxconn removed end, zacker, 06/16/2009 */
275
276    old_src_set=(igmp_src_t *)gp->igmpg_sources;
277    if (gp->igmpg_fmode == IGMP_FMODE_INCLUDE){
278		//printf("%s, %d\n",__FUNCTION__,__LINE__);
279      for(i=0;i<numsrc;i++){
280		  //printf("%s, %d\n",__FUNCTION__,__LINE__);
281        src=igmp_group_src_add(gp,sources[i]);
282        if ((check_src_set(src->igmps_source,old_src_set) == FALSE) && check_src(src->igmps_source,sources,numsrc) == TRUE) {
283			//printf("%s, %d\n",__FUNCTION__,__LINE__);
284          src->igmps_timer=0;
285            }
286        if ((check_src_set(src->igmps_source,old_src_set) == TRUE) && check_src(src->igmps_source,sources,numsrc) == FALSE){
287			//printf("%s, %d\n",__FUNCTION__,__LINE__);
288          igmp_src_cleanup(gp,src);
289          k_proxy_del_mfc (router->igmprt_socket, src->igmps_source.s_addr, gp->igmpg_addr.s_addr);
290        }
291      }
292    }else{ /*EXCLUDE filter mode*/
293      for (i=0;i<numsrc;i++){
294		  //printf("%s, %d\n",__FUNCTION__,__LINE__);
295        src=igmp_group_src_add(gp,sources[i]);
296        /*(A-X-Y)=group timer*/
297        if ((check_src_set(src->igmps_source,old_src_set) == FALSE) && (check_src(src->igmps_source,sources,numsrc) == TRUE)){
298			//printf("%s, %d\n",__FUNCTION__,__LINE__);
299          src->igmps_timer= gp->igmpg_timer;
300          src->igmps_fstate = FALSE;
301        }
302        /*delete( X-A) delete (Y-A)*/
303        if ((check_src(src->igmps_source,sources,numsrc) == FALSE) && (check_src_set(src->igmps_source,old_src_set) == TRUE)){
304			//printf("%s, %d\n",__FUNCTION__,__LINE__);
305            igmp_src_cleanup(gp,src);
306        k_proxy_del_mfc (router->igmprt_socket, src->igmps_source.s_addr, gp->igmpg_addr.s_addr);
307         }
308      }
309    }
310    /*group timer = GMI*/
311    gp->igmpg_timer=IGMP_GMI;
312    /* send querry Q(G,A-Y) or A*B */
313    num=0;
314    gp1=gp;
315    for (sr=gp->igmpg_sources;sr!=NULL;sr=(igmp_src_t *)sr->igmps_next){
316		//printf("%s, %d\n",__FUNCTION__,__LINE__);
317      if (sr->igmps_timer > 0) {
318		  //printf("%s, %d\n",__FUNCTION__,__LINE__);
319        set_src[num].s_addr=sr->igmps_source.s_addr;
320        num = num+1;
321      }
322    }
323    gp=gp1;
324    send_group_src_specific_q(router,ifp,gp,set_src,num);
325    /* group filter mode : EXCLUDE*/
326    gp->igmpg_fmode = IGMP_FMODE_EXCLUDE;
327
328    if (ifp->igmpi_addr.s_addr != upstream){
329		//printf("%s, %d\n",__FUNCTION__,__LINE__);
330      member = (membership_db*)update_multi(router,gp->igmpg_addr,gp->igmpg_fmode,num,set_src);
331      set_source_filter(router,gp,upstream,member->membership.fmode,member->membership.numsources,member->membership.sources);
332    }
333
334	/* Foxconn add start by aspen Bai, 12/07/2007 */
335    if(numsrc == 0)
336    {
337		//printf("%s, %d\n",__FUNCTION__,__LINE__);
338        k_proxy_chg_mfc(router->igmprt_socket,mulsrc.igmps_addr.s_addr,gp->igmpg_addr.s_addr,wan_index,1);
339    }
340    /* Foxconn add end by aspen Bai, 12/07/2007 */
341	igmp_info_print(router);
342}
343
344
345/*
346 * void igmp_group_toin()
347 * handle to_in{} report for a group
348 */
349void igmp_group_handle_toin(
350                igmp_router_t *router,
351                igmp_interface_t *ifp,
352                igmp_group_t *gp,
353                int numsrc,
354				igmp_rep_t *srcrep,
355                struct in_addr *sources)
356{
357  igmp_src_t *src,*old_src_set,*sr;
358  struct in_addr set_src[MAX_ADDRS];
359  int i,n,num,count=0,igmplen;
360  igmp_group_t *gp1,*gp2;
361  membership_db* member;
362  igmp_rep_t *rep;
363
364  	/* Foxconn add start by aspen Bai, 12/07/2007 */
365	if(!igmp_interface_group_lookup(ifp,gp->igmpg_addr))
366	{
367		//printf("%s, %d\n",__FUNCTION__,__LINE__);
368		return;
369	}
370
371	if (!igmp_group_rep_lookup(gp, srcrep->igmpr_addr))
372	{
373		//printf("%s, %d\n",__FUNCTION__,__LINE__);
374	    return;
375	}
376
377	igmp_group_rep_del(gp,srcrep->igmpr_addr);
378	igmp_info_print(router);
379
380	//printf("%s, %d\n",__FUNCTION__,__LINE__);
381	for(rep=gp->igmpg_members;rep;rep=(igmp_rep_t *)rep->igmpr_next)
382	{
383		//printf("%s, %d\n",__FUNCTION__,__LINE__);
384		if((rep->igmpr_addr.s_addr != lan_ipaddr) && ((rep->igmpr_addr.s_addr & lan_netmask)
385			    == (lan_ipaddr & lan_netmask)))
386		{
387			//printf("%s, %d\n",__FUNCTION__,__LINE__);
388			count++;
389		}
390	}
391
392	if(count == 0)
393	{
394		//printf("%s, %d\n",__FUNCTION__,__LINE__);
395		if(gp->igmpg_flags!=LAST_LEAVE_GROUP_HAD_SEND)
396			gp->igmpg_flags = LAST_LEAVE_GROUP; /* Last leave a group */
397
398		if(wan_igmp_version != IGMP_VERSION_1)
399			k_proxy_del_mfc(router->igmprt_socket,mulsrc.igmps_addr.s_addr,gp->igmpg_addr.s_addr);
400	}
401	/* Foxconn removed start, zacker, 06/16/2009 */
402	//else
403	//	gp->igmpg_flags = GROUP_INIT;
404	/* Foxconn removed end, zacker, 06/16/2009 */
405	/* Foxconn add end by aspen Bai, 12/07/2007 */
406
407
408  old_src_set=(igmp_src_t *)gp->igmpg_sources;
409  for (i=0;i<numsrc;i++){
410	  //printf("%s, %d\n",__FUNCTION__,__LINE__);
411      src=igmp_group_src_add(gp,sources[i]);
412      /*(B) = GMI*/
413      if ((check_src(src->igmps_source,sources,numsrc) == TRUE) && (check_src_set(src->igmps_source,old_src_set) == FALSE)){
414		  //printf("%s, %d\n",__FUNCTION__,__LINE__);
415    src->igmps_timer= IGMP_GMI;
416    src->igmps_fstate = FALSE;
417        if (ifp->igmpi_addr.s_addr == upstream)
418		{
419			//printf("%s, %d\n",__FUNCTION__,__LINE__);
420           k_proxy_chg_mfc(router->igmprt_socket,sources[i].s_addr,gp->igmpg_addr.s_addr,ifp->igmpi_index,forward_upstream);
421		}
422        else
423		{
424			//printf("%s, %d\n",__FUNCTION__,__LINE__);
425           k_proxy_chg_mfc(router->igmprt_socket,sources[i].s_addr,gp->igmpg_addr.s_addr,ifp->igmpi_index,1);
426		}
427    }
428  }
429  if (gp->igmpg_fmode == IGMP_FMODE_INCLUDE){
430	  //printf("%s, %d\n",__FUNCTION__,__LINE__);
431      /*send querry Q(G,A-B)*/
432      gp1=gp;
433      num=0;
434      for (sr=gp->igmpg_sources;sr;sr=(igmp_src_t *)sr->igmps_next){
435		  //printf("%s, %d\n",__FUNCTION__,__LINE__);
436        if ((check_src(sr->igmps_source,sources,numsrc) == FALSE) && (check_src_set(sr->igmps_source,old_src_set) == TRUE )){
437			//printf("%s, %d\n",__FUNCTION__,__LINE__);
438        set_src[num].s_addr=sr->igmps_source.s_addr;
439        num = num+1;
440        }
441      }
442      gp =gp1;
443      send_group_src_specific_q(router,ifp,gp,set_src,num);
444      gp->igmpg_fmode=IGMP_FMODE_INCLUDE;
445
446      gp1=gp;
447      num = 0;
448	  //printf("%s, %d\n",__FUNCTION__,__LINE__);
449      for (sr=gp->igmpg_sources;sr;sr=(igmp_src_t *)sr->igmps_next){
450		  //printf("%s, %d\n",__FUNCTION__,__LINE__);
451     set_src[num].s_addr=sr->igmps_source.s_addr;
452     num = num+1;
453      }
454      gp = gp1;
455
456      if (ifp->igmpi_addr.s_addr != upstream){
457		  //printf("%s, %d\n",__FUNCTION__,__LINE__);
458    member = (membership_db*)update_multi(router,gp->igmpg_addr,gp->igmpg_fmode,num,set_src);
459	//printf("%s, %d\n",__FUNCTION__,__LINE__);
460    set_source_filter(router,gp,upstream,member->membership.fmode,member->membership.numsources,member->membership.sources);
461      }
462
463  }else{
464	  //printf("%s, %d\n",__FUNCTION__,__LINE__);
465	/*send Q(G,X-A)*/
466    gp1=gp;
467    num = 0;
468    for (sr=gp->igmpg_sources;sr;sr=(igmp_src_t *)sr->igmps_next){
469		//printf("%s, %d\n",__FUNCTION__,__LINE__);
470      if ((check_src(sr->igmps_source,sources,numsrc) == FALSE) && (check_src_set(sr->igmps_source,old_src_set) == TRUE ) && (sr->igmps_timer > 0)){
471		  //printf("%s, %d\n",__FUNCTION__,__LINE__);
472    set_src[num].s_addr=sr->igmps_source.s_addr;
473    num = num+1;
474      }
475    }
476	//printf("%s, %d\n",__FUNCTION__,__LINE__);
477    gp=gp1;
478    send_group_src_specific_q(router,ifp,gp,set_src,num);
479    /*send Q(G)*/
480    send_group_specific_query(router,ifp,gp);
481    gp->igmpg_fmode=IGMP_FMODE_EXCLUDE;
482
483    gp1 = gp;
484    num = 0;
485    for (sr=gp->igmpg_sources;sr; sr=(igmp_src_t *)sr->igmps_next){
486		//printf("%s, %d\n",__FUNCTION__,__LINE__);
487    set_src[num].s_addr=sr->igmps_source.s_addr;
488        num = num+1;
489    }
490    gp = gp1;
491	if (ifp->igmpi_addr.s_addr != upstream){
492		//printf("%s, %d\n",__FUNCTION__,__LINE__);
493      member = (membership_db*)update_multi(router,gp->igmpg_addr,gp->igmpg_fmode,num,set_src);
494	  //printf("%s, %d\n",__FUNCTION__,__LINE__);
495      //set_source_filter(router,gp,upstream,member->membership.fmode,member->membership.numsources,member->membership.sources);
496
497    }
498
499	}
500
501 }
502
503/*
504 * void igmp_group_handle_isex()
505 *
506 * Handle a is_ex{A} report for a group
507 * the report have only one source
508 */
509void
510igmp_group_handle_isex(
511    igmp_router_t* router,
512    igmp_interface_t* ifp,
513    igmp_group_t* gp,
514    int numsrc,
515    struct in_addr *sources)
516{
517    igmp_src_t *src,*sr,*old_src_set;
518    int i;
519    membership_db* member;
520
521	/* Foxconn add start by aspen Bai, 01/31/2008 */
522	/* In order to forward multicast packets automatically when gproxy run later than client joining a group */
523	//printf("%s, %d, general_query_count %d gp->igmpg_fmode %d,numsrc %d\n",__FUNCTION__,__LINE__,general_query_count,gp->igmpg_fmode,numsrc);
524	if(numsrc == 0)
525	{
526		if( general_query_count < 5)
527		{
528			//printf("%s, %d\n",__FUNCTION__,__LINE__);
529			//printf("%d, 0x%x,0x%x,0x%x,\n",router->igmprt_socket,mulsrc.igmps_addr.s_addr,gp->igmpg_addr.s_addr,wan_index);
530			k_proxy_chg_mfc(router->igmprt_socket,mulsrc.igmps_addr.s_addr,gp->igmpg_addr.s_addr,wan_index,1);
531			//printf("%s, %d\n",__FUNCTION__,__LINE__);
532		}
533	}
534	/* Foxconn add end by aspen Bai, 01/31/2008 */
535
536    /* Reset timer */
537    gp->igmpg_timer = IGMP_GMI; /* ifp->igmpi_qi = GMI : GMI = (RBV * QI) + QRI */
538    /* Do the v3 logic */
539    old_src_set=gp->igmpg_sources;
540    if (gp->igmpg_fmode == IGMP_FMODE_EXCLUDE) {
541      /* $6.4.1: State = Excl(X,Y), Report = IS_EX(A) */
542      for (i=0;i < numsrc;i++){
543        src=igmp_group_src_add(gp,sources[i]);
544        /* (A-X-Y) = GMI */
545        if ((check_src_set(src->igmps_source,old_src_set) == FALSE) && (check_src(src->igmps_source,sources,numsrc) == TRUE)){
546          src->igmps_timer = IGMP_GMI;
547          src->igmps_fstate = FALSE;
548        }
549        else
550          /* delete ( X-A)  delete (Y-A) */
551          if ((check_src(src->igmps_source,sources,numsrc) == FALSE) && (check_src_set(src->igmps_source,old_src_set) == TRUE)){
552        /* Foxconn modified start, zacker, 06/20/2009 */
553        igmp_src_cleanup(gp,src);
554        k_proxy_del_mfc (router->igmprt_socket, src->igmps_source.s_addr, gp->igmpg_addr.s_addr);
555        /* Foxconn modified end, zacker, 06/20/2009 */
556          }
557      }
558    }
559    else {
560      /* $6.4.1: State = Incl(X,Y), Report = IS_EX(A) */
561      for (i=0;i< numsrc; i++){
562        src=igmp_group_src_add(gp,sources[i]);
563        if ((check_src_set(src->igmps_source,old_src_set) == FALSE) && (check_src(src->igmps_source,sources,numsrc) == TRUE)){
564          /*(B-A) = 0*/
565          src->igmps_timer = 0;
566        }else{
567          if ((check_src(src->igmps_source,sources,numsrc) == FALSE) && (check_src_set(src->igmps_source,old_src_set) == TRUE)){
568        /* delete (A-B)*/
569        igmp_src_cleanup(gp,src);
570        k_proxy_del_mfc (router->igmprt_socket, src->igmps_source.s_addr, gp->igmpg_addr.s_addr);
571          }
572        }
573      }
574    }
575    gp->igmpg_fmode = IGMP_FMODE_EXCLUDE;
576
577    if (ifp->igmpi_addr.s_addr != upstream){
578      member = (membership_db*)update_multi(router,gp->igmpg_addr,gp->igmpg_fmode,numsrc,sources);
579      set_source_filter(router,gp,upstream,member->membership.fmode,member->membership.numsources,member->membership.sources);
580    }
581
582	igmp_info_print(router); //aspen
583}
584
585/*
586 * void igmp_group_handle_isin()
587 *
588 * Handle a is_in{A} report for a group
589 * the report have only one source
590 */
591void
592igmp_group_handle_isin(
593    igmp_router_t* router,
594    igmp_interface_t* ifp,
595    igmp_group_t* gp,
596    int numsrc,
597    struct in_addr *sources)
598{
599    igmp_src_t *src,*sr;
600    struct in_addr *source;
601    struct in_addr set_src[MAX_ADDRS];
602    int i,num;
603    igmp_group_t *gp1;
604    membership_db* member;
605
606    /* Do the v3 logic */
607    for (i=0;i < numsrc;i++){
608      /*(A) = GMI*/
609      src=igmp_group_src_add(gp,sources[i]);
610      if (check_src(src->igmps_source,sources,numsrc) == TRUE){
611        src->igmps_timer = IGMP_GMI;
612        src->igmps_fstate = FALSE;
613            if (ifp->igmpi_addr.s_addr == upstream)
614                k_proxy_chg_mfc(router->igmprt_socket,sources[i].s_addr,gp->igmpg_addr.s_addr,ifp->igmpi_index,forward_upstream);
615            else
616                k_proxy_chg_mfc(router->igmprt_socket,sources[i].s_addr,gp->igmpg_addr.s_addr,ifp->igmpi_index,1);
617      }
618    }
619    num=0;
620    gp1=gp;
621    for (sr=gp->igmpg_sources;sr;sr=(igmp_src_t *)sr->igmps_next){
622      set_src[num].s_addr=sr->igmps_source.s_addr;
623      num = num+1;
624    }
625    gp=gp1;
626    if (gp->igmpg_fmode == IGMP_FMODE_EXCLUDE) {
627      /* $6.4.1: State = Excl(X,Y), Report = IS_IN(A) */
628      gp->igmpg_fmode = IGMP_FMODE_EXCLUDE;
629
630      if (ifp->igmpi_addr.s_addr != upstream){
631        member = (membership_db*)update_multi(router,gp->igmpg_addr,gp->igmpg_fmode,num,set_src);
632        set_source_filter(router,gp,upstream,member->membership.fmode,member->membership.numsources,member->membership.sources);
633      }
634    }
635    else {
636      /* $6.4.1: State = Incl(A), Report = IS_IN(B) */
637      gp->igmpg_fmode = IGMP_FMODE_INCLUDE;
638
639      if (ifp->igmpi_addr.s_addr != upstream){
640        member = (membership_db*)update_multi(router,gp->igmpg_addr,gp->igmpg_fmode,num,set_src);
641        set_source_filter(router,gp,upstream,member->membership.fmode,member->membership.numsources,member->membership.sources);
642      }
643    }
644}
645
646/***************************************************************************/
647/*                                     */
648/*              Timer management routines                          */
649/************************************************************************* */
650
651/*
652 * void igmprt_timer_querier(igmp_interface_t *ifp)
653 * handle the other querier timer
654 *
655 */
656void igmprt_timer_querier(igmp_interface_t *ifp)
657{
658
659    if (ifp->igmpi_oqp > 0)
660        --ifp->igmpi_oqp;
661    if (ifp->igmpi_oqp <= 0)
662        ifp->igmpi_isquerier = TRUE;
663}
664
665
666/*
667 * void igmprt_timer_group(igmp_router_t* router, igmp_interface_t *ifp)
668 *
669 * handle the  groups timers for this router
670 *
671 */
672
673void igmprt_timer_group(igmp_router_t* router,igmp_interface_t *ifp)
674{
675  igmp_group_t *gp;
676  igmp_src_t   *src;
677  int delete_gr;
678  int flag,count=0;
679  struct ip_mreq mreq;
680  igmp_interface_t* upstream_interface, *ifp1;
681  struct in_addr up,srctmp;;
682  igmp_router_t* igmprt;
683
684  for(gp=ifp->igmpi_groups;gp;gp=gp->igmpg_next){
685    /*decrement group timer*/
686    if (gp->igmpg_timer > 0)
687      --gp->igmpg_timer;
688    /*handle group timer*/
689    if (gp->igmpg_fmode == IGMP_FMODE_EXCLUDE){
690      if ((gp->igmpg_timer == 0) && (ifp->igmpi_addr.s_addr == lan_ipaddr)){
691		  /* Foxconn add start by aspen Bai, 02/29/2008, for multicast throughput test */
692		  if(!emf_cfg_mfdb_group_find(gp->igmpg_addr))
693			k_proxy_del_mfc(router->igmprt_socket,mulsrc.igmps_addr.s_addr,gp->igmpg_addr.s_addr);
694		  /* Foxconn add end by aspen Bai, 02/29/2008 */
695
696    /* no more listeners to group */
697    delete_gr = TRUE;
698    for (src=gp->igmpg_sources;src;src=(igmp_src_t *)src->igmps_next){
699      if (src->igmps_timer > 0){
700        delete_gr = FALSE;
701      }else{
702        igmp_src_cleanup(gp,src);
703        k_proxy_del_mfc (router->igmprt_socket, src->igmps_source.s_addr, gp->igmpg_addr.s_addr);
704      }
705
706	}
707    if (delete_gr == TRUE){
708      /*all source timers expired*/
709      LOG((LOG_DEBUG,"all source timer expired delete group\n"));
710
711      /*igmp_group_cleanup(gp);*/  /* Del by lewis min, 12/15/2007 */
712
713      igmprt = router;
714      /*delete group from the set of groups of upstream interface if all downstream memberships are down*/
715      flag = TRUE;
716	  for (ifp1 = router->igmprt_interfaces; ifp1; ifp1 = ifp1->igmpi_next)
717	  {
718        if ((igmp_interface_group_lookup(ifp1,gp->igmpg_addr) != NULL) && (ifp1->igmpi_addr.s_addr != upstream))
719		{
720			flag = FALSE;
721		}
722	  }
723      if (flag == TRUE) {
724        mreq.imr_multiaddr.s_addr=gp->igmpg_addr.s_addr;
725        mreq.imr_interface.s_addr=upstream;
726        if (VALID_ADDR(mreq.imr_multiaddr)) {
727          up.s_addr = upstream;
728          upstream_interface = igmprt_interface_lookup(router,up);
729          if (igmp_interface_group_lookup(upstream_interface,mreq.imr_multiaddr) != NULL) {
730        if (setsockopt(router->igmprt_up_socket, IPPROTO_IP, IP_DROP_MEMBERSHIP, (void *) &mreq, sizeof(mreq)) < 0) {
731          perror("setsockopt - IP_DROP_MEMBERSHIP");
732          //exit(1);
733        }
734
735          }
736        }
737      }
738      router = igmprt;
739    }
740    else{
741
742      /*switch to INCLUDE filter-mode with source list = sources with timer running*/
743      gp->igmpg_fmode = IGMP_FMODE_INCLUDE;
744    }
745      }
746    }
747  }
748  igmprt_clear_timer_group(ifp);
749}
750
751
752
753/*
754 * void igmprt_timer_source(igmp_router_t* router, igmp_interface_t *ifp)
755 *
756 * handle source timers
757 */
758void igmprt_timer_source (igmp_router_t* router,igmp_interface_t *ifp)
759{
760  igmp_group_t *gp;
761  igmp_src_t   *src;
762  int flag;
763  struct ip_mreq mreq;
764  igmp_interface_t* upstream_interface;
765  struct in_addr up;
766  igmp_router_t* igmprt;
767  igmp_interface_t *ifp1;
768
769  for (gp=ifp->igmpi_groups;gp;gp=gp->igmpg_next)
770    for (src=gp->igmpg_sources;src;src=(igmp_src_t *)src->igmps_next){
771      /*decrement source timer*/
772      if (src->igmps_timer > 0)
773    --src->igmps_timer;
774      /*handle source timer*/
775      switch(gp->igmpg_fmode){
776      case IGMP_FMODE_INCLUDE:
777    if (src->igmps_timer > 0 ){
778      /* suggest to forward traffic from source */
779      /* TO DO: add a flag to the source record*/
780      if (src->igmps_fstate == FALSE){
781        src->igmps_fstate= TRUE;
782        //printf("forward traffic from source: %s\n",inet_ntoa(src->igmps_source));
783        /*tell the kernel to forward traffic from this source*/
784        k_proxy_chg_mfc(router->igmprt_socket,src->igmps_source.s_addr,gp->igmpg_addr.s_addr,ifp->igmpi_index,1);
785      }
786    }else {
787      if (src->igmps_timer == 0){
788        /*suggest to stop forwarding traffic from source*/
789        if (src->igmps_fstate == TRUE){
790          src->igmps_fstate = FALSE;
791          //printf("stop forwarding traffic from source, timer = 0: %s\n",inet_ntoa(src->igmps_source));
792          /*tell the kernel to stop forwarding traffic from this source*/
793          k_proxy_chg_mfc(router->igmprt_socket,src->igmps_source.s_addr,gp->igmpg_addr.s_addr,ifp->igmpi_index,0);
794        }
795        igmp_src_cleanup(gp,src);
796        k_proxy_del_mfc (router->igmprt_socket, src->igmps_source.s_addr, gp->igmpg_addr.s_addr);
797        if (gp->igmpg_sources == NULL) {
798          /*delete group*/
799          igmp_group_cleanup(gp);
800
801          igmprt = router;
802          /*deleate group from the set of groups of upstream interface if all downstream memberships are down*/
803          flag = TRUE;
804          for (ifp1 = igmprt->igmprt_interfaces; ifp1; ifp1 = ifp1->igmpi_next)
805        if ((igmp_interface_group_lookup(ifp1,gp->igmpg_addr) != NULL) && (ifp1->igmpi_addr.s_addr != upstream))
806          flag = FALSE;
807          if (flag == TRUE) {
808        mreq.imr_multiaddr.s_addr=gp->igmpg_addr.s_addr;
809        mreq.imr_interface.s_addr=upstream;
810        if (VALID_ADDR(mreq.imr_multiaddr)) {
811          up.s_addr = upstream;
812          upstream_interface = igmprt_interface_lookup(router,up);
813          if (igmp_interface_group_lookup(upstream_interface,mreq.imr_multiaddr) != NULL) {
814            if (setsockopt(router->igmprt_up_socket, IPPROTO_IP, IP_DROP_MEMBERSHIP, (void *) &mreq, sizeof(mreq)) < 0) {
815              perror("setsockopt - IP_DROP_MEMBERSHIP");
816              //exit(1);
817            }
818          }
819        }
820          }
821          router = igmprt;
822        }
823      }
824    }
825    if (gp->igmpg_sources == NULL)/*TODO: (*,G) state source addr = ADRESSE_NONE*/
826      printf("not forward source\n");
827    break;
828      case IGMP_FMODE_EXCLUDE:
829    if (src->igmps_timer > 0 ){
830      if (src->igmps_fstate == FALSE){
831        src->igmps_fstate = TRUE;
832        printf("suggest to forward traffic from src: %s\n",inet_ntoa(src->igmps_source));
833        /*tell the kernel to forward traffic from this source */
834        k_proxy_chg_mfc(router->igmprt_socket,src->igmps_source.s_addr,gp->igmpg_addr.s_addr,ifp->igmpi_index,1);
835      }
836    }
837    else{
838      if (src->igmps_timer == 0){
839        if (src->igmps_fstate == TRUE){
840          src->igmps_fstate = FALSE;
841          printf("not forward traffic from src: %s\n",inet_ntoa(src->igmps_source));
842          /*tell the kernel to stop forwarding traffic from this source*/
843          k_proxy_chg_mfc(router->igmprt_socket,src->igmps_source.s_addr,gp->igmpg_addr.s_addr,ifp->igmpi_index,0);
844        }
845      }
846      if (gp->igmpg_sources == NULL)/*TODO: (*,G) state source addr = ADRESSE_NONE*/
847        printf("forward traffic from all sources\n");
848      break;
849    }
850      }
851    }
852}
853
854/*****************************************************************************
855 *
856 *                  Query Routines
857 *
858 *****************************************************************************/
859/*
860 * sch_query_t * igmp_sch_create ( struct in_addr gp)
861 * create a new scheduled entry
862 */
863sch_query_t *igmp_sch_create( struct in_addr gp)
864{
865    sch_query_t *sh;
866    if (sh=(sch_query_t *)malloc(sizeof(*sh))){
867        sh->gp_addr.s_addr = gp.s_addr;
868        sh->sch_next = NULL;
869    }
870    return sh;
871}
872/*
873 * void sch_group_specq_add(router,ifp,gp,sources,numsrc)
874 * add a scheduled query entry
875 */
876void sch_group_specq_add(
877        igmp_interface_t *ifp,
878        struct in_addr gp,
879        struct in_addr *sources,
880        int numsrc)
881{
882    sch_query_t* sch;
883    int i;
884    if (numsrc != 0){
885    /*create the schedule entry*/
886    sch=igmp_sch_create(gp);
887    /*set the retransmissions number*/
888    sch->igmp_retnum = IGMP_DEF_RV - 1;
889    sch->numsrc = numsrc;
890    for (i=0;i<numsrc;i++)
891        sch->sources[i].s_addr = sources[i].s_addr;
892    sch->sch_next = (sch_query_t *)ifp->sch_group_query;
893    ifp->sch_group_query = sch;
894    }else
895        return;
896}
897
898
899/*
900 * void igmprt_membership_query()
901 *
902 * Send a membership query on the specified interface, to the specified group.
903 * Include sources if they are specified and the router version of the
904 * interface is igmp version 3.
905 */
906void
907igmprt_membership_query(igmp_router_t* igmprt, igmp_interface_t* ifp,
908    struct in_addr *group, struct in_addr *sources, int numsrc, int SRSP)
909{
910    char buf[12], *pbuf = NULL;
911    igmpv3q_t *query;
912    //int size;
913    struct sockaddr_in sin;
914    int i, igmplen, version = ifp->igmpi_version;
915
916    assert(igmprt != NULL);
917    assert(ifp != NULL);
918
919	general_query_count++;
920    /* Allocate a buffer to build the query */
921    if (numsrc != 0 && version == IGMP_VERSION_3) {
922        pbuf = (char*) malloc(sizeof(*query) + numsrc * sizeof(struct in_addr));
923        if (pbuf == NULL)
924            return;
925        query = (igmpv3q_t *) pbuf;
926    }
927    else
928        query = (igmpv3q_t *) buf;
929
930    /* Set the common fields */
931    query->igmpq_type = IGMP_MEMBERSHIP_QUERY;
932    query->igmpq_group.s_addr = group->s_addr;
933    query->igmpq_cksum = 0;
934
935    /* Foxconn modified start, zacker, 06/20/2009 */
936    /* Set the version specific fields */
937    switch (ifp->igmpi_version) {
938        case IGMP_VERSION_1:
939            igmplen = 8;
940            query->igmpq_code = 0;
941            break;
942        case IGMP_VERSION_2:
943            igmplen = 8;
944            if (group->s_addr == 0)
945                query->igmpq_code = ifp->igmpi_qri;
946            else
947                query->igmpq_code = (IGMP_DEF_QRI_LAST * IGMP_DEF_QRI_UNIT);
948            break;
949        case IGMP_VERSION_3:
950            igmplen = sizeof(*query)+(numsrc-1)*sizeof(struct in_addr);
951            if (group->s_addr == 0)
952                query->igmpq_code = ifp->igmpi_qri;
953            else
954                query->igmpq_code = (IGMP_DEF_QRI_LAST * IGMP_DEF_QRI_UNIT);
955
956            if (SRSP == TRUE) /*set supress router-side Processing*/
957                query->igmpq_misc=(ifp->igmpi_rv | 0x08);
958            else
959                query->igmpq_misc = ifp->igmpi_rv;
960
961            query->igmpq_qqi = ifp->igmpi_qi;
962            query->igmpq_numsrc = htons(numsrc);
963            for (i=0; i<numsrc; i++){
964                query->igmpq_sources[i].s_addr = sources[i].s_addr;
965            }
966            break;
967        default:
968            if (pbuf)
969                free(pbuf);
970            return;
971    }
972
973    /* Checksum */
974    query->igmpq_cksum = in_cksum((unsigned short*) query, igmplen);
975    /* Send out the query */
976    //size=sizeof(*query)+(numsrc-1)*sizeof(struct in_addr);
977    sin.sin_family = AF_INET;
978    if (group->s_addr == 0)
979        sin.sin_addr.s_addr = htonl(INADDR_ALLHOSTS_GROUP);
980    else
981        sin.sin_addr.s_addr = group->s_addr;
982    sendto(ifp->igmpi_socket, (void*) query, igmplen, 0,
983        (struct sockaddr*)&sin, sizeof(sin));
984    /* Foxconn modified end, zacker, 06/20/2009 */
985
986    if (pbuf)
987        free(pbuf);
988}
989/*
990 * void send_group_specific_query()
991 * send a query to a specific group
992 *
993 */
994void send_group_specific_query(
995        igmp_router_t *router,
996        igmp_interface_t *ifp,
997        igmp_group_t *gp)
998{
999    int SRSP=FALSE;
1000    if (gp->igmpg_timer > IGMP_TIMER_SCALE)
1001        SRSP = TRUE;
1002    else
1003        gp->igmpg_timer = IGMP_TIMER_SCALE;
1004    /*send a group specific query immediately*/
1005    igmprt_membership_query(router,ifp,&gp->igmpg_addr,NULL,0,SRSP);
1006    /*schedule retransmission*/
1007    sch_group_specq_add(ifp,gp->igmpg_addr,NULL,0);
1008}
1009
1010/*
1011 * void send_group_src_specific_q()
1012 * send a group and source specific query
1013 */
1014void send_group_src_specific_q(
1015            igmp_router_t *router,
1016            igmp_interface_t *ifp,
1017            igmp_group_t *gp,
1018            struct in_addr *sources,
1019            int numsrc)
1020{
1021    int i;
1022    igmp_src_t *src;
1023
1024    if (gp != NULL){
1025    for (i=0;i < numsrc; i++){
1026        src=igmp_group_src_lookup(gp,sources[i]);
1027        if (src != NULL)
1028            src->igmps_timer = IGMP_TIMER_SCALE;
1029        else
1030           return;
1031    }
1032    /*schedule retransmission*/
1033    sch_group_specq_add(ifp,gp->igmpg_addr,sources,numsrc);
1034    }
1035
1036
1037}
1038/*
1039 * void sch_query_cleanup(ifp,sch)
1040 * cleanup a scheduled record query from an inteeface
1041 *
1042 */
1043void sch_query_cleanup(igmp_interface_t *ifp,
1044               sch_query_t *sch)
1045{
1046    sch_query_t *sh;
1047    if (sch != ifp->sch_group_query){
1048      for (sh=ifp->sch_group_query;sh->sch_next != sch;sh=sh->sch_next);
1049      sh->sch_next = sch->sch_next;
1050      free(sch);
1051    }else{ /*delete the head*/
1052      sh=ifp->sch_group_query;
1053      ifp->sch_group_query = sh->sch_next;
1054      free(sh);
1055    }
1056}
1057/*
1058 * void construct_set()
1059 * construct two sets of sources with source timer lower than LMQI
1060 * et another with source timer greater than LMQI
1061 */
1062void construct_set( igmp_interface_t *ifp,
1063            sch_query_t *sch,
1064            struct in_addr *src_inf_lmqi,
1065            struct in_addr *src_sup_lmqi,
1066            int *numsrc1,
1067            int *numsrc2)
1068{
1069    igmp_src_t *src;
1070    igmp_group_t *gp;
1071    int i,numsr1,numsr2;
1072    /*src_sup_lmqi=NULL;
1073    src_inf_lmqi=NULL;*/
1074
1075    numsr1 = numsr2 = 0;
1076
1077    for (i=0;i < sch->numsrc; i++){
1078        /*lookup the group of the source*/
1079        if ((gp=igmp_interface_group_lookup(ifp,sch->gp_addr))== NULL){
1080            *numsrc1 = numsr1;
1081            *numsrc1 = numsr2;
1082            return;
1083        }
1084        /*lookup the record source in the group*/
1085        if ((src=igmp_group_src_lookup(gp,sch->sources[i]))==NULL){
1086            *numsrc1 = numsr1;
1087            *numsrc1 = numsr2;
1088            return;
1089        }
1090        if (src->igmps_timer > IGMP_TIMER_SCALE){
1091            src_sup_lmqi[numsr1].s_addr=src->igmps_source.s_addr;
1092            numsr1++;
1093        }else{
1094            src_inf_lmqi[numsr2].s_addr=src->igmps_source.s_addr;
1095            numsr2++;
1096        }
1097    }
1098
1099    *numsrc1 =numsr1;
1100    *numsrc2 =numsr2;
1101}
1102/*
1103 * send_sh_query(router,ifp)
1104 * send scheduled query on an interface
1105 *
1106 */
1107void send_sh_query(igmp_router_t *router,
1108           igmp_interface_t *ifp)
1109{
1110    sch_query_t *sch;
1111    struct in_addr src_inf_lmqi;
1112    struct in_addr src_sup_lmqi;
1113    int numsrc1;
1114    int numsrc2;
1115    igmp_group_t *gp;
1116
1117    if (ifp->sch_group_query != NULL){
1118        for (sch=ifp->sch_group_query;sch;sch=sch->sch_next){
1119            /*trait query per query*/
1120            if (sch->numsrc == 0){
1121                /*group specifq query*/
1122                if (sch->igmp_retnum >0){
1123					/*another query yet*/
1124                    if ((gp=igmp_interface_group_lookup(ifp,sch->gp_addr))==NULL){
1125                        return;
1126                    }
1127                    if (gp->igmpg_timer > IGMP_TIMER_SCALE)
1128					{
1129						/* group timer > LMQI*/
1130                        igmprt_membership_query(router,ifp,&sch->gp_addr,NULL,0,1);
1131					}
1132                    else
1133					{
1134                        igmprt_membership_query(router,ifp,&sch->gp_addr,NULL,0,0);
1135					}
1136                    --sch->igmp_retnum;
1137                }else{ /*number retransmission = 0*/
1138                    /*delete the query record*/
1139                    sch_query_cleanup(ifp,sch);
1140                }
1141            }else{
1142                /*group and source specifiq query*/
1143                if (sch->igmp_retnum > 0 ){
1144                    construct_set(ifp,sch,&src_inf_lmqi,&src_sup_lmqi,&numsrc1,&numsrc2);
1145                    /*send query of source with timer > LMQI*/
1146                    if (numsrc2 != 0){
1147                        igmprt_membership_query(router,ifp,&sch->gp_addr,&src_inf_lmqi,numsrc2,0);}
1148                    if (numsrc1  != 0){
1149                        igmprt_membership_query(router,ifp,&sch->gp_addr,&src_sup_lmqi,numsrc1,1);}
1150
1151                    --sch->igmp_retnum;
1152                }else /*retransmission =0*/
1153                    sch_query_cleanup(ifp,sch);
1154
1155            }
1156        }
1157    }
1158
1159}
1160
1161/* Send report when we are queried or first join a group, Weal@ 01/07/2008 */
1162/*
1163 * send out a membership report, version 1 and 2
1164 */
1165int send_membership_report_v12(igmp_router_t* igmprt, struct in_addr group, int version)
1166{
1167    igmpr_t *v2_report;
1168    char *pbuf = NULL;
1169    igmp_interface_t *ifp_1;
1170    igmp_group_t *gp_1;
1171    int igmplen=0,size=0;
1172	struct sockaddr_in sin;
1173
1174    pbuf = (char*) malloc(sizeof(igmpr_t));
1175    if (pbuf == NULL){
1176        printf(" Can not allocate memoey for report packet\n");
1177        return -1;
1178        }
1179
1180    v2_report = (igmpr_t *) pbuf;
1181
1182    if (wan_igmp_version == IGMP_VERSION_1)
1183        v2_report->igmpr_type = IGMP_V1_MEMBERSHIP_REPORT;
1184    else
1185		if (wan_igmp_version == IGMP_VERSION_2)
1186            v2_report->igmpr_type = IGMP_V2_MEMBERSHIP_REPORT;
1187
1188    v2_report->igmpr_code = 0;
1189    igmplen += sizeof(igmpr_t);
1190
1191	/* send igmpv2 membership report including all group report if we are queried */
1192	if(group.s_addr == 0)
1193	{
1194	/* Foxconn added start, zacker, 05/11/2009, workaround sulution
1195	 * for v2 report can't send to wan while in snooping enabled @no_v2_report_in_snoop */
1196#ifdef __CONFIG_IGMP_SNOOPING__
1197#if (defined U12H072) || (defined U12H139) || (defined BCM5325E)
1198		if (acosNvramConfig_match("emf_enable", "1"))
1199		{
1200			system("/usr/sbin/et robowr 0x4 0x0 0x00");
1201		}
1202#endif
1203#if (defined WNR3500L) || (defined WNDR4500) || (defined WNR3500Lv2)
1204		if (acosNvramConfig_match("emf_enable", "1"))
1205		{
1206			system("/usr/sbin/et robowr 0x4 0xE 0x0000");
1207		}
1208#endif
1209#endif
1210	/* Foxconn added end, zacker, 05/11/2009, @no_v2_report_in_snoop */
1211		for (ifp_1=igmprt->igmprt_interfaces; ifp_1;ifp_1=ifp_1->igmpi_next)
1212		{
1213			if(ifp_1->igmpi_addr.s_addr == lan_ipaddr)
1214				for (gp_1=ifp_1->igmpi_groups; gp_1 ; gp_1=gp_1->igmpg_next)
1215				{
1216					 if (gp_1->igmpg_addr.s_addr == 0){
1217						 continue;
1218						}
1219					/* We cannot send igmpv2 packet whose dst ip is "224.0.0.22"  or "224.0.0.2" to wan port when queried */
1220					 if ((gp_1->igmpg_addr.s_addr == inet_addr(IGMP_ALL_ROUTERS_V3)) ||
1221						 (gp_1->igmpg_addr.s_addr == inet_addr(IGMP_ALL_ROUTERS)))
1222					 {
1223						 continue;
1224					 }
1225					 if( gp_1->igmpg_members == NULL)
1226						 continue;
1227					/*Fill in group address*/
1228					memcpy(&(v2_report->igmpr_group),&(gp_1->igmpg_addr),4);
1229
1230					/* Checksum */
1231					v2_report->igmpr_cksum = 0;
1232					v2_report->igmpr_cksum = in_cksum((unsigned short*) v2_report, igmplen);
1233					/* Send out the report message */
1234					size = sizeof(*v2_report);
1235					sin.sin_family = AF_INET;
1236					memcpy(&sin.sin_addr,&(gp_1->igmpg_addr),4);
1237
1238					sendto(wan_igmp_socket, (void*) v2_report, size, 0, (struct sockaddr*)&sin, sizeof(sin));
1239				}
1240		}
1241		/* Foxconn added start, zacker, 05/11/2009, @no_v2_report_in_snoop */
1242#ifdef __CONFIG_IGMP_SNOOPING__
1243#if (defined U12H072) || (defined U12H139) || (defined BCM5325E)
1244		usleep(100000);
1245		if (acosNvramConfig_match("emf_enable", "1"))
1246		{
1247			system("/usr/sbin/et robowr 0x4 0x0 0x10");
1248		}
1249#endif
1250#if (defined WNR3500L) || (defined WNDR4500) || (defined WNR3500Lv2)
1251		if (acosNvramConfig_match("emf_enable", "1"))
1252		{
1253			system("/usr/sbin/et robowr 0x4 0xE 0x0AAA");
1254		}
1255#endif
1256#endif
1257		/* Foxconn added end, zacker, 05/11/2009, @no_v2_report_in_snoop */
1258	}
1259	/* send igmp membership report to wan according to wan igmp version */
1260	else
1261	{
1262		if(wan_igmp_version == IGMP_VERSION_3)
1263			/*if(igmp_aggregation_timer == 0)*/
1264				send_membership_report_v12_to_v3(group,CHANGE_TO_EXCLUDE); /* v2 join group is equivalent to v3 type CHANGE_TO_EXCLUDE */
1265		else
1266			if((wan_igmp_version == IGMP_VERSION_1) || (wan_igmp_version == IGMP_VERSION_2))
1267		{
1268			v2_report->igmpr_type = wan_igmp_version;
1269			/*Fill in group address*/
1270			if (group.s_addr == inet_addr(IGMP_ALL_ROUTERS_V3) ||
1271				 group.s_addr == inet_addr(IGMP_ALL_ROUTERS))
1272			{
1273				if (pbuf)
1274					free(pbuf);
1275				 return 0;
1276			}
1277			/* Foxconn added start, zacker, 05/11/2009, @no_v2_report_in_snoop */
1278#ifdef __CONFIG_IGMP_SNOOPING__
1279#if (defined U12H072) || (defined U12H139) || (defined BCM5325E)
1280			if (acosNvramConfig_match("emf_enable", "1"))
1281			{
1282				system("/usr/sbin/et robowr 0x4 0x0 0x00");
1283			}
1284#endif
1285#if (defined WNR3500L) || (defined WNDR4500) || (defined WNR3500Lv2)
1286    		if (acosNvramConfig_match("emf_enable", "1"))
1287    		{
1288    			system("/usr/sbin/et robowr 0x4 0xE 0x0000");
1289    		}
1290#endif
1291#endif
1292			/* Foxconn added end, zacker, 05/11/2009, @no_v2_report_in_snoop */
1293			memcpy(&(v2_report->igmpr_group),&group,4);
1294
1295			//igmplen += 4; /* Foxconn removed, zacker, 05/11/2009, no need */
1296			/* Checksum */
1297			v2_report->igmpr_cksum = 0;
1298			v2_report->igmpr_cksum = in_cksum((unsigned short*) v2_report, igmplen);
1299			/* Send out the leave group message */
1300			size = sizeof(*v2_report);
1301			sin.sin_family = AF_INET;
1302			sin.sin_addr.s_addr = group.s_addr;
1303
1304			sendto(wan_igmp_socket, (void*) v2_report, size, 0, (struct sockaddr*)&sin, sizeof(sin));
1305			/* Foxconn added start, zacker, 05/11/2009, @no_v2_report_in_snoop */
1306#ifdef __CONFIG_IGMP_SNOOPING__
1307#if (defined U12H072) || (defined U12H139) || (defined BCM5325E)
1308			usleep(100000);
1309			if (acosNvramConfig_match("emf_enable", "1"))
1310			{
1311				system("/usr/sbin/et robowr 0x4 0x0 0x10");
1312			}
1313#endif
1314#if (defined WNR3500L) || (defined WNDR4500) || (defined WNR3500Lv2)
1315    		if (acosNvramConfig_match("emf_enable", "1"))
1316    		{
1317    			system("/usr/sbin/et robowr 0x4 0xE 0x0AAA");
1318    		}
1319#endif
1320#endif
1321			/* Foxconn added end, zacker, 05/11/2009, @no_v2_report_in_snoop */
1322		}
1323	}
1324
1325    if (pbuf)
1326        free(pbuf);
1327    return 0;
1328}
1329
1330
1331/* Send report when we are queried or first join a group, Weal@ 01/07/2008 */
1332/*
1333 * send out a membership report, version 3
1334 */
1335int send_membership_report_v3(int is_be_queried)
1336{
1337    igmp_report_t *v3_report;
1338    char *pbuf = NULL;
1339    igmp_interface_t *ifp1;
1340    igmp_group_t *gp1;
1341    igmp_group_t *next_gp = NULL;
1342    int igmplen=0, recordnum=0;
1343    /* I suppose, the number of records is less than 64 */
1344    igmp_group_t records[64];
1345	struct sockaddr_in sin;
1346	igmp_grouprec_t  arecord;
1347    //printf("%s, %d\n",__FUNCTION__,__LINE__);/* an TO_IN report */
1348    for (ifp1=router.igmprt_interfaces; ifp1;ifp1=ifp1->igmpi_next)
1349    {
1350		//printf("%s, %d\n",__FUNCTION__,__LINE__);/* an TO_IN report */
1351		if(ifp1->igmpi_addr.s_addr == lan_ipaddr)
1352			for (gp1=ifp1->igmpi_groups; gp1; gp1=gp1->igmpg_next)
1353			{
1354				/* We should not send igmpv3 packet whose dst ip is "224.0.0.2" to wan port */
1355				//printf("%s, %d\n",__FUNCTION__,__LINE__);/* an TO_IN report */
1356				//if ((gp1->igmpg_addr.s_addr != 0) && (recordnum < 64) && (gp1->igmpg_members != NULL))
1357				//{
1358					//records[recordnum].igmpg_addr.s_addr = gp->igmpg_addr.s_addr;
1359					//records[recordnum++].igmpg_fmode = gp->igmpg_fmode;
1360					recordnum++;
1361					//printf("%s, %d\n",__FUNCTION__,__LINE__);/* an TO_IN report */
1362					/* TODO: may be copy all src and member to the array */
1363				//}
1364			}
1365    }
1366    //printf("%s, %d, recordnum %d\n",__FUNCTION__,__LINE__,recordnum);/* an TO_IN report */
1367    if (recordnum > 0)
1368    {
1369
1370        int i = 0,j = 0;
1371		//printf("%s, %d malloc length %d\n",__FUNCTION__,__LINE__,(sizeof(igmp_report_t) + (recordnum-1)*8));
1372        pbuf = (char*) malloc(sizeof(igmp_report_t) + (recordnum-1)*8);
1373		//printf("%s, %d\n",__FUNCTION__,__LINE__);/* an TO_IN report */
1374        if (pbuf == NULL){
1375            printf(" Can not allocate memoey for report packet\n");
1376            return -1;
1377        }
1378
1379        v3_report = (igmp_report_t *) pbuf;
1380        v3_report->igmpr_type = IGMP_V3_MEMBERSHIP_REPORT;
1381        v3_report->igmpr_code = 0;
1382        v3_report->igmpr_rsv = 0;
1383
1384        igmplen += sizeof(igmp_report_t);
1385		//printf("%s, %d\n",__FUNCTION__,__LINE__);/* an TO_IN report */
1386		/* send igmpv3 membership report including all group report if we are queried */
1387		if(is_be_queried)
1388		{
1389			for (ifp1=router.igmprt_interfaces; ifp1;ifp1=ifp1->igmpi_next)
1390			{
1391				//printf("%s, %d\n",__FUNCTION__,__LINE__);/* an TO_IN report */
1392				if(ifp1->igmpi_addr.s_addr == lan_ipaddr)
1393				{
1394					//printf("%s, %d\n",__FUNCTION__,__LINE__);/* an TO_IN report */
1395					for (i=0,gp1=ifp1->igmpi_groups; gp1; gp1=gp1->igmpg_next,i++)
1396					{
1397						if(gp1->igmpg_addr.s_addr == inet_addr(IGMP_ALL_ROUTERS) || gp1->igmpg_addr.s_addr == inet_addr(IGMP_ALL_ROUTERS_V3))
1398							continue;
1399						if( gp1->igmpg_members == NULL)
1400							continue;
1401						//printf("%s, %d\n",__FUNCTION__,__LINE__);/* an TO_IN report */
1402						arecord.igmpg_type = gp1->igmpg_type;
1403						arecord.igmpg_datalen = 0;
1404						arecord.igmpg_numsrc = 0;
1405						arecord.igmpg_group.s_addr = gp1->igmpg_addr.s_addr;
1406
1407						memcpy(((char *)&(v3_report->igmpr_group[i])), &arecord, sizeof(igmp_grouprec_t));
1408						if(0!=i)
1409							igmplen += sizeof(igmp_grouprec_t);
1410					}
1411					//printf("%s, %d\n",__FUNCTION__,__LINE__);/* an TO_IN report */
1412				}
1413			}
1414			v3_report->igmpr_numgrps = htons(i);
1415			/* Checksum */
1416			v3_report->igmpr_cksum = 0;
1417			v3_report->igmpr_cksum = in_cksum((unsigned short*) v3_report, igmplen);
1418			/* Send out the report message */
1419			sin.sin_family = AF_INET;
1420			sin.sin_addr.s_addr = inet_addr(IGMP_ALL_ROUTERS_V3);
1421	        //printf("%s, %d i=%d\n",__FUNCTION__,__LINE__,i);/* an TO_IN report */
1422			sendto(wan_igmp_socket, (void*) v3_report, igmplen, 0, (struct sockaddr*)&sin, sizeof(sin));
1423		}
1424		/* send igmp membership report including group report only changed according to wan igmp version */
1425		else
1426		{
1427			if(wan_igmp_version == IGMP_VERSION_3)
1428			{
1429				//printf("%s, %d\n",__FUNCTION__,__LINE__);/* an TO_IN report */
1430				for (ifp1=router.igmprt_interfaces; ifp1;ifp1=ifp1->igmpi_next)
1431				{
1432					//printf("%s, %d\n",__FUNCTION__,__LINE__);/* an TO_IN report */
1433					if(ifp1->igmpi_addr.s_addr == lan_ipaddr)
1434					{
1435						//printf("%s, %d\n",__FUNCTION__,__LINE__);/* an TO_IN report */
1436						/* Foxconn modified start, zacker, 06/20/2009 */
1437						for (j=0,gp1=ifp1->igmpi_groups; gp1; gp1 = next_gp)
1438						{
1439							/* Foxconn added, zacker, 05/07/2009, @cleanup_after_leave */
1440							next_gp=gp1->igmpg_next;
1441							//printf("%s, %d\n",__FUNCTION__,__LINE__);/* an TO_IN report */
1442							/* send report to wan when we first join or leave a group */
1443							if(gp1->igmpg_flags == FIRST_JOIN_GROUP || gp1->igmpg_flags == LAST_LEAVE_GROUP)
1444							{
1445								//printf("%s, %d\n",__FUNCTION__,__LINE__);/* an TO_IN report */
1446								arecord.igmpg_type = gp1->igmpg_type;
1447								arecord.igmpg_datalen = 0;
1448								arecord.igmpg_numsrc = 0;
1449								arecord.igmpg_group.s_addr = gp1->igmpg_addr.s_addr;
1450								if(gp1->igmpg_flags== LAST_LEAVE_GROUP)
1451									gp1->igmpg_flags = LAST_LEAVE_GROUP_HAD_SEND;
1452								if(gp1->igmpg_flags== FIRST_JOIN_GROUP)
1453									gp1->igmpg_flags = FIRST_JOIN_GROUP_HAD_SEND;
1454
1455								memcpy(((char *)&(v3_report->igmpr_group[j])), &arecord, sizeof(igmp_grouprec_t));
1456								//printf("%s, %d\n",__FUNCTION__,__LINE__);/* an TO_IN report */
1457								if(0!=j)
1458									igmplen += sizeof(igmp_grouprec_t);
1459								j++;
1460							}
1461							/* Foxconn added, zacker, 06/20/2009, @cleanup_after_leave */
1462							if (gp1->igmpg_flags == LAST_LEAVE_GROUP_HAD_SEND)
1463								igmp_group_cleanup(gp1);
1464						}
1465						/* Foxconn modified end, zacker, 06/20/2009 */
1466
1467						if(0==j)
1468						{
1469							if (pbuf)
1470								free(pbuf);
1471							//printf("%s, %d not send any\n",__FUNCTION__,__LINE__);/* an TO_IN report */
1472							return -1;
1473						}
1474
1475						v3_report->igmpr_numgrps = htons(j);
1476						//printf("%s, %d igmpr_numgrps %d\n",__FUNCTION__,__LINE__,v3_report->igmpr_numgrps);/* an TO_IN report */
1477						/* Checksum */
1478						v3_report->igmpr_cksum = 0;
1479						v3_report->igmpr_cksum = in_cksum((unsigned short*) v3_report, igmplen);
1480						//printf("%s, %d\n",__FUNCTION__,__LINE__);/* an TO_IN report */
1481
1482					}
1483				}
1484
1485				/* Send out the report message */
1486				sin.sin_family = AF_INET;
1487				sin.sin_addr.s_addr = inet_addr(IGMP_ALL_ROUTERS_V3);
1488		        //printf("%s, %d\n",__FUNCTION__,__LINE__);/* an TO_IN report */
1489				sendto(wan_igmp_socket, (void*) v3_report, igmplen, 0, (struct sockaddr*)&sin, sizeof(sin));
1490
1491				//printf("%s, %d\n",__FUNCTION__,__LINE__);/* an TO_IN report */
1492			}
1493			else
1494			{
1495				//printf("%s, %d\n",__FUNCTION__,__LINE__);/* an TO_IN report */
1496				send_membership_report_v3_to_v12();
1497				//printf("%s, %d\n",__FUNCTION__,__LINE__);/* an TO_IN report */
1498			}
1499
1500		}
1501		//printf("%s, %d\n",__FUNCTION__,__LINE__);/* an TO_IN report */
1502
1503        if (pbuf)
1504            free(pbuf);
1505
1506		//printf("%s, %d\n",__FUNCTION__,__LINE__);/* an TO_IN report */
1507    }
1508    //printf("%s, %d\n",__FUNCTION__,__LINE__);/* an TO_IN report */
1509
1510    return 0;
1511}
1512
1513
1514/* Foxconn add start by aspen Bai, 01/07/2008 */
1515/*
1516 *	Change v12 membership report to v3 and send to wan port
1517 */
1518int send_membership_report_v12_to_v3(struct in_addr group, int type)
1519{
1520	igmp_report_t *igmpv3_report;
1521	char *p1buf = NULL;
1522    igmp_interface_t *ifp_2;
1523	int igmplen_12=0;
1524	igmp_grouprec_t  arecord;
1525	struct sockaddr_in sin;
1526
1527	p1buf = (char*) malloc(sizeof(igmp_report_t));
1528        if (p1buf == NULL){
1529            printf(" Can not allocate memoey for report packet\n");
1530            return -1;
1531        }
1532
1533	if (group.s_addr == inet_addr(IGMP_ALL_ROUTERS_V3) ||
1534		group.s_addr == inet_addr(IGMP_ALL_ROUTERS))
1535	{
1536			if (p1buf)
1537				free(p1buf);
1538			return 0;
1539	}
1540
1541	igmpv3_report = (igmp_report_t *) p1buf;
1542    igmpv3_report->igmpr_type = IGMP_V3_MEMBERSHIP_REPORT;
1543    igmpv3_report->igmpr_code = 0;
1544    igmpv3_report->igmpr_rsv = 0;
1545    igmpv3_report->igmpr_cksum = 0;
1546	igmpv3_report->igmpr_numgrps = htons(1);
1547
1548    igmplen_12 += 8;
1549
1550	arecord.igmpg_type = type;
1551	arecord.igmpg_datalen = 0;
1552	arecord.igmpg_numsrc = 0;
1553	arecord.igmpg_group.s_addr = group.s_addr;
1554
1555	memcpy(((char *)&(igmpv3_report->igmpr_group[0])), &arecord, 8);
1556	igmplen_12 += 8;
1557
1558	igmpv3_report->igmpr_cksum = in_cksum((unsigned short*) igmpv3_report, igmplen_12);
1559
1560    /* Send out the report message */
1561    sin.sin_family = AF_INET;
1562	sin.sin_addr.s_addr = inet_addr(IGMP_ALL_ROUTERS_V3);
1563
1564	sendto(wan_igmp_socket, (void*) igmpv3_report, igmplen_12, 0, (struct sockaddr*)&sin, sizeof(sin));
1565
1566	if (p1buf)
1567		 free(p1buf);
1568
1569	return 0;
1570}
1571/* Foxconn add end by aspen Bai, 01/07/2008 */
1572
1573
1574/* Foxconn add start by aspen Bai, 01/07/2008 */
1575/*
1576 * Change v3 membership report to v12 and send to wan port
1577 */
1578int send_membership_report_v3_to_v12()
1579{
1580	igmpr_t *v12_report;
1581    char *p2buf = NULL;
1582    igmp_interface_t *ifp2;
1583    igmp_group_t *gp2;
1584    igmp_group_t *next_gp = NULL;
1585	int igmplen2=0, recordnum2=0;
1586	struct sockaddr_in sin;
1587
1588	for (ifp2=router.igmprt_interfaces; ifp2;ifp2=ifp2->igmpi_next)
1589    {
1590		if(ifp2->igmpi_addr.s_addr == lan_ipaddr)
1591			for (gp2=ifp2->igmpi_groups; gp2; gp2=gp2->igmpg_next)
1592			{
1593				if ((gp2->igmpg_addr.s_addr != 0) && (recordnum2 < 64) && (gp2->igmpg_members != NULL)){
1594					recordnum2++;
1595					/* TODO: may be copy all src and member to the array */
1596				}
1597			}
1598    }
1599
1600	if (recordnum2 > 0)
1601    {
1602        p2buf = (char*) malloc(sizeof(igmpr_t));
1603        if (p2buf == NULL){
1604            printf(" Can not allocate memoey for report packet\n");
1605            return -1;
1606        }
1607        /* Foxconn added start, zacker, 05/11/2009, @no_v2_report_in_snoop */
1608#ifdef __CONFIG_IGMP_SNOOPING__
1609#if (defined U12H072) || (defined U12H139) || (defined BCM5325E)
1610        if (acosNvramConfig_match("emf_enable", "1"))
1611        {
1612            system("/usr/sbin/et robowr 0x4 0x0 0x00");
1613        }
1614#endif
1615#if (defined WNR3500L) || (defined WNDR4500) || (defined WNR3500Lv2)
1616		if (acosNvramConfig_match("emf_enable", "1"))
1617		{
1618			system("/usr/sbin/et robowr 0x4 0xE 0x0000");
1619		}
1620#endif
1621#endif
1622        /* Foxconn added end, zacker, 05/11/2009, @no_v2_report_in_snoop */
1623        v12_report = (igmpr_t *) p2buf;
1624        v12_report->igmpr_type = wan_igmp_version;
1625        v12_report->igmpr_code = 0;
1626        igmplen2 += 8;
1627		/* Foxconn modified start, zacker, 06/20/2009 */
1628		for (ifp2=router.igmprt_interfaces; ifp2;ifp2=ifp2->igmpi_next)
1629		{
1630			if(ifp2->igmpi_addr.s_addr == lan_ipaddr)
1631				for (gp2=ifp2->igmpi_groups; gp2; gp2 = next_gp)
1632				{
1633					/* Foxconn added, zacker, 05/07/2009, @cleanup_after_leave */
1634					next_gp = gp2->igmpg_next;
1635					if (gp2->igmpg_addr.s_addr == 0){
1636						continue;
1637						}
1638					/* We cannot send igmpv12 packet whose dst ip is "224.0.0.22" and "224.0.0.2" to wan port */
1639					if (gp2->igmpg_addr.s_addr == inet_addr(IGMP_ALL_ROUTERS_V3) ||
1640						gp2->igmpg_addr.s_addr == inet_addr(IGMP_ALL_ROUTERS))
1641					{
1642						 continue;
1643					}
1644					/*Fill in group address*/
1645					/* First join a group */
1646					if(gp2->igmpg_flags == FIRST_JOIN_GROUP)
1647					{
1648						gp2->igmpg_flags = FIRST_JOIN_GROUP_HAD_SEND;
1649						memcpy(&(v12_report->igmpr_group),&(gp2->igmpg_addr),4);
1650						memcpy(&sin.sin_addr,&(gp2->igmpg_addr),4);
1651					}
1652					else if(gp2->igmpg_flags == LAST_LEAVE_GROUP)/* Last leave a group */
1653					{
1654						gp2->igmpg_flags = LAST_LEAVE_GROUP_HAD_SEND;
1655						if(wan_igmp_version == IGMP_VERSION_2)
1656						{
1657							v12_report->igmpr_type = IGMP_V2_LEAVE_GROUP;
1658							memcpy(&(v12_report->igmpr_group),&(gp2->igmpg_addr),4);
1659							sin.sin_addr.s_addr = inet_addr(IGMP_ALL_ROUTERS);
1660						}
1661					}
1662					else
1663						continue;
1664
1665					/* Foxconn added, zacker, 06/20/2009, @cleanup_after_leave */
1666					if (gp2->igmpg_flags == LAST_LEAVE_GROUP_HAD_SEND)
1667						igmp_group_cleanup(gp2);
1668
1669					/* Checksum */
1670					v12_report->igmpr_cksum = 0;
1671					v12_report->igmpr_cksum = in_cksum((unsigned short*) v12_report, igmplen2);
1672					/* Send out the report message */
1673					sin.sin_family = AF_INET;
1674
1675					sendto(wan_igmp_socket, (void*) v12_report, igmplen2, 0, (struct sockaddr*)&sin, sizeof(sin));
1676				}
1677		}
1678		if(p2buf)
1679			free(p2buf);
1680		/* Foxconn modified end, zacker, 06/20/2009 */
1681		/* Foxconn added start, zacker, 05/11/2009, @no_v2_report_in_snoop */
1682#ifdef __CONFIG_IGMP_SNOOPING__
1683#if (defined U12H072) || (defined U12H139) || (defined BCM5325E)
1684		usleep(100000);
1685		if (acosNvramConfig_match("emf_enable", "1"))
1686		{
1687			system("/usr/sbin/et robowr 0x4 0x0 0x10");
1688		}
1689#endif
1690#if (defined WNR3500L) || (defined WNDR4500) || (defined WNR3500Lv2)
1691		if (acosNvramConfig_match("emf_enable", "1"))
1692		{
1693			system("/usr/sbin/et robowr 0x4 0xE 0x0AAA");
1694		}
1695#endif
1696#endif
1697		/* Foxconn added end, zacker, 05/11/2009, @no_v2_report_in_snoop */
1698	}
1699
1700	//if(p2buf)
1701		//free(p2buf);
1702
1703	return 0;
1704}
1705/* Foxconn add end by aspen Bai, 01/07/2008 */
1706
1707
1708/* Foxconn add start by aspen Bai, 01/07/2008 */
1709/*
1710 * send out a v2 leave group message
1711 */
1712int send_leave_group_v2(struct in_addr group)
1713{
1714	igmpr_t *v2_report;
1715	igmp_interface_t* ifp;
1716    char *pbuf = NULL;
1717    int igmplen=0,size;
1718	struct sockaddr_in sin;
1719
1720    pbuf = (char*) malloc(sizeof(igmpr_t));
1721    if (pbuf == NULL){
1722        printf(" Can not allocate memoey for report packet\n");
1723        return -1;
1724        }
1725    v2_report = (igmpr_t *) pbuf;
1726	if (wan_igmp_version == IGMP_VERSION_2)
1727		v2_report->igmpr_type = IGMP_V2_LEAVE_GROUP;
1728	else
1729	{
1730		if (pbuf)
1731			free(pbuf);
1732		return 0;
1733	}
1734    v2_report->igmpr_code = 0;
1735    v2_report->igmpr_cksum = 0;
1736    igmplen += 4;
1737
1738	/*Fill in group address*/
1739    memcpy(&(v2_report->igmpr_group),&group,4);
1740
1741    igmplen += 4;
1742	/* Checksum */
1743	v2_report->igmpr_cksum = in_cksum((unsigned short*) v2_report, igmplen);
1744    /* Send out the leave group message */
1745    size = sizeof(*v2_report);
1746    sin.sin_family = AF_INET;
1747    sin.sin_addr.s_addr = inet_addr(IGMP_ALL_ROUTERS);
1748    //sendto(router.igmprt_socket, (void*) v2_report, size, 0, (struct sockaddr*)&sin, sizeof(sin));
1749
1750	sendto(wan_igmp_socket, (void*) v2_report, size, 0, (struct sockaddr*)&sin, sizeof(sin));
1751
1752    if (pbuf)
1753        free(pbuf);
1754
1755    return 0;
1756}
1757/* Foxconn add end by aspen Bai, 01/07/2008 */
1758
1759
1760/*
1761 * void receive_membership_query()
1762 * handle a reception of membership query
1763 */
1764void receive_membership_query(igmp_router_t* igmprt,
1765				  igmp_interface_t *ifp,
1766                  struct in_addr gp,
1767                  struct in_addr *sources,
1768                  u_long src_query,
1769                  int numsrc,
1770			      int srsp,
1771                  int version)
1772{
1773    igmp_group_t *gr;
1774    igmp_src_t *src;
1775    int i;
1776	struct in_addr group={0};
1777
1778    if (src_query < ifp->igmpi_addr.s_addr){ /* another querier is present with lower IP adress*/
1779        ifp->igmpi_oqp=IGMP_OQPI;/*set the Other-Querier-Present timer to OQPI*/
1780        ifp->igmpi_isquerier = FALSE;
1781    }
1782    if ( srsp == FALSE){ /* Supress Router-Side Processing flag not set */
1783        gr=igmp_interface_group_lookup(ifp,gp);
1784        if (gr != NULL){
1785            if (numsrc == 0){
1786                /*group specific query*/
1787                /* group timer is lowered to LMQI*/
1788                gr->igmpg_timer = IGMP_TIMER_SCALE;
1789            }else{
1790                /*group and source specific query*/
1791                for (i=0;i < numsrc; i++){
1792                    src=igmp_group_src_lookup(gr,sources[i]);
1793                    if (src != NULL)
1794                        src->igmps_timer= IGMP_TIMER_SCALE;
1795                }
1796
1797            }
1798		}
1799      }
1800
1801	 wan_version_timer = IGMP_WAN_VERSION_TIMER;
1802
1803     switch(version)
1804		{
1805		case IGMP_VERSION_1:
1806			wan_igmp_version = IGMP_VERSION_1;
1807			send_membership_report_v12(igmprt,group,version);
1808			break;
1809		case IGMP_VERSION_2:
1810			wan_igmp_version = IGMP_VERSION_2;
1811			send_membership_report_v12(igmprt,group,version);
1812			break;
1813		case IGMP_VERSION_3:
1814			wan_igmp_version = IGMP_VERSION_3;
1815			send_membership_report_v3(TRUE);
1816			break;
1817		default:
1818			break;
1819		}
1820}
1821
1822/* Foxconn add start by aspen Bai, 03/01/2008 */
1823#if 1
1824int emf_cfg_request_send_down(emf_cfg_request_t *buffer, int length)
1825{
1826	struct sockaddr_nl src_addr, dest_addr;
1827	struct nlmsghdr *nlh = NULL;
1828	struct msghdr msg;
1829	struct iovec iov;
1830	int    sock_fd, ret;
1831
1832	if ((buffer == NULL) || (length > MAX_DATA_SIZE))
1833	{
1834		fprintf(stderr, "Invalid parameters %p %d\n", buffer, length);
1835		return (-1);
1836	}
1837
1838	/* Create a netlink socket */
1839	sock_fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_EMFC);
1840
1841	if (sock_fd < 0)
1842	{
1843		fprintf(stderr, "Netlink socket create failed\n");
1844		return (-1);
1845	}
1846
1847	/* Associate a local address with the opened socket */
1848	memset(&src_addr, 0, sizeof(struct sockaddr_nl));
1849	src_addr.nl_family = AF_NETLINK;
1850	src_addr.nl_pid = getpid();
1851	src_addr.nl_groups = 0;
1852	bind(sock_fd, (struct sockaddr *)&src_addr, sizeof(src_addr));
1853
1854	/* Fill the destination address, pid of 0 indicates kernel */
1855	memset(&dest_addr, 0, sizeof(struct sockaddr_nl));
1856	dest_addr.nl_family = AF_NETLINK;
1857	dest_addr.nl_pid = 0;
1858	dest_addr.nl_groups = 0;
1859
1860	/* Allocate memory for sending configuration request */
1861	nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_DATA_SIZE));
1862
1863	if (nlh == NULL)
1864	{
1865		fprintf(stderr, "Out of memory allocating cfg buffer\n");
1866		close(sock_fd); /* Foxconn added, zacker, 06/20/2009 */
1867		return (-1);
1868	}
1869
1870	/* Fill the netlink message header. The configuration request
1871	 * contains netlink header followed by data.
1872	 */
1873	nlh->nlmsg_len = NLMSG_SPACE(MAX_DATA_SIZE);
1874	nlh->nlmsg_pid = getpid();
1875	nlh->nlmsg_flags = 0;
1876
1877	/* Fill the data part */
1878	memcpy(NLMSG_DATA(nlh), buffer, length);
1879	iov.iov_base = (void *)nlh;
1880	iov.iov_len = nlh->nlmsg_len;
1881	memset(&msg, 0, sizeof(struct msghdr));
1882	msg.msg_name = (void *)&dest_addr;
1883	msg.msg_namelen = sizeof(dest_addr);
1884	msg.msg_iov = &iov;
1885	msg.msg_iovlen = 1;
1886
1887	/* Send request to kernel module */
1888	ret = sendmsg(sock_fd, &msg, 0);
1889	if (ret < 0)
1890	{
1891		perror("sendmsg:");
1892		close(sock_fd); /* Foxconn added, zacker, 06/20/2009 */
1893		if (nlh)
1894			free(nlh);
1895		return (ret);
1896	}
1897
1898	/* Wait for the response */
1899	memset(nlh, 0, NLMSG_SPACE(MAX_DATA_SIZE));
1900	ret = recvmsg(sock_fd, &msg, 0);
1901	if (ret < 0)
1902	{
1903		perror("recvmsg:");
1904		close(sock_fd); /* Foxconn added, zacker, 06/20/2009 */
1905		if (nlh)
1906			free(nlh);
1907		return (ret);
1908	}
1909
1910	/* Copy data to user buffer */
1911	memcpy(buffer, NLMSG_DATA(nlh), length);
1912
1913	if (nlh)
1914		free(nlh);
1915
1916	close(sock_fd);
1917
1918	return (ret);
1919}
1920
1921/* Return 1 if group found, otherwise 0 */
1922int
1923emf_cfg_mfdb_group_find(struct in_addr group)
1924{
1925	emf_cfg_request_t req;
1926	emf_cfg_mfdb_list_t *list;
1927	int i;
1928
1929	strcpy(req.inst_id, "br0");
1930	req.command_id = EMFCFG_CMD_MFDB_LIST;
1931	req.oper_type = EMFCFG_OPER_TYPE_GET;
1932	req.size = sizeof(req.arg);
1933	list = (emf_cfg_mfdb_list_t *)req.arg;
1934
1935	if (emf_cfg_request_send_down(&req, sizeof(emf_cfg_request_t)) < 0)
1936	{
1937		fprintf(stderr, "Unable to send request to EMF\n");
1938		return (0);
1939	}
1940
1941	if (req.status != EMFCFG_STATUS_SUCCESS)
1942	{
1943		fprintf(stderr, "Unable to get the MFBD list\n");
1944		return (0);
1945	}
1946
1947	for (i = 0; i < list->num_entries; i++)
1948	{
1949		if(htonl(group.s_addr) == list->mfdb_entry[i].mgrp_ip)
1950		{
1951			return EMFCFG_STATUS_SUCCESS;
1952		}
1953	}
1954	return (0);
1955}
1956#endif
1957/* Foxconn add end by aspen Bai, 03/01/2008 */
1958
1959