1/******************************************************************************
2 * Fichier main :igmprt - An IGMP Proxy implementation
3 ******************************************************************************
4 * Fichier    : igmprt.c
5 * Description: Implementation d'un proxy IGMP en se basant sur
6 *              l'internet draft "draft-ietf-idmr-igmp-v3-07.txt", Mars 2001
7 *              et "draft-ietf-idmr-igmp-proxy-01.txt", Janvier 2002
8 * Date       : May 18, 2000
9 * Auteurs    : wilbertdg@hetnet.nl
10 *              lahmadi@loria.fr
11 *              Anis.Ben-Hellel@loria.fr
12 * Last Modif : Juin 10, 2002
13 *
14 *****************************************************************************/
15
16#include "conf.h"
17#include "igmprt.h"
18#include <acosNvramConfig.h> /* Foxconn add by aspen Bai, 12/07/2007 */
19
20/*version and isquerier variable from the config file*/
21
22int version,querier;
23/* Foxconn add start by aspen Bai, 12/07/2007 */
24extern igmp_mulsrc_t mulsrc;
25int wan_index;
26int lan_index;
27unsigned long lan_ipaddr,lan_netmask;
28int wan_igmp_version = IGMP_VERSION_3;
29extern int wan_version_timer;
30int wan_igmp_socket;
31/* Foxconn add end by aspen Bai, 12/07/2007 */
32//unsigned long upstream;
33
34#ifdef STATIC_PPPOE
35int sec_wan_status = 0;
36#endif
37
38void igmp_info_print(igmp_router_t *router)
39{
40#ifdef IGMP_DEBUG
41	igmp_interface_t *ifp;
42	igmp_group_t *gp;
43	igmp_src_t *src;
44	igmp_rep_t *rep;
45	printf("\nIGMP Table\n");
46	printf("-----------------\n");
47	printf("\n%-14s %-9s %-14s %-5s %-14s %-14s\n","interface","version","groups","mode","source","Members");
48	for (ifp=router->igmprt_interfaces;ifp;ifp=(igmp_interface_t *)ifp->igmpi_next){
49		printf("%-14s 0x%x\n",inet_ntoa(ifp->igmpi_addr),ifp->igmpi_version);
50		if (ifp->igmpi_groups != NULL){
51			for(gp=ifp->igmpi_groups;gp;gp=(igmp_group_t*)gp->igmpg_next){
52				printf("%32s %11s\n",inet_ntoa(gp->igmpg_addr),(gp->igmpg_fmode == IGMP_FMODE_INCLUDE)? "INCLUDE":"EXCLUDE");
53				if (gp->igmpg_sources != NULL)
54				     for (src=gp->igmpg_sources;src;src=(igmp_src_t *)src->igmps_next)
55					printf("%50s\n",inet_ntoa(src->igmps_source));
56				if (gp->igmpg_members != NULL)
57					for (rep=gp->igmpg_members;rep;rep=(igmp_rep_t *)rep->igmpr_next)
58						/*if (gp->igmpg_sources != NULL)
59							printf("%17s\n",inet_ntoa(rep->igmpr_addr));
60						else*/
61							printf("%70s\n",inet_ntoa(rep->igmpr_addr));
62				else printf("\n");
63			}
64		}else
65			printf("\n");
66
67	}
68#endif
69
70}
71
72/****************************************************************************
73 *
74 * LDAP communication
75 *
76 ***************************************************************************/
77int validate(){
78
79/* validation du report provenant d'un membre d'un groupe*/
80    return 0; /* Foxconn added, zacker, 06/20/2009 */
81}
82
83/****************************************************************************
84 *
85 * Routines pour les enregistrements des membres: Ceci n'a pas ete specifie
86 * dans le draft, mais pour se rendre compte vite q'un membre viend de quitter
87 * un groupe, ou pour garder trace du membres on peut utiliser ces routines
88 *
89 ***************************************************************************/
90
91/*
92 * igmp_rep_t* igmp_rep_create()
93 *
94 * Cree un enregistrement d'un membre d'un groupe
95 */
96igmp_rep_t*
97igmp_rep_create(
98	struct in_addr srcaddr)
99{
100	igmp_rep_t* rep;
101
102	if (rep = (igmp_rep_t*) malloc(sizeof(*rep))) {
103	  rep->igmpr_addr.s_addr = srcaddr.s_addr;
104	  rep->igmpr_next  = NULL;
105	}
106	return rep;
107}
108
109/*
110 * void igmp_rep_cleanup()
111 *
112 * Effacer un enregistrement d'un membre
113 */
114void
115igmp_rep_cleanup(
116	igmp_group_t *gp,
117	igmp_rep_t * rep)
118{
119	igmp_rep_t *re;
120
121	assert(rep != NULL);
122	assert (gp != NULL);
123	if (rep != gp->igmpg_members){
124	  for (re=gp->igmpg_members;(igmp_rep_t *)re->igmpr_next != rep;re=(igmp_rep_t *)re->igmpr_next);
125	  re->igmpr_next = rep->igmpr_next;
126	  free(rep);
127	}else{
128	  /*delete the head*/
129	  re=gp->igmpg_members;
130	  gp->igmpg_members = (igmp_rep_t *)re->igmpr_next;
131	  free(re);
132	}
133	LOG((LOG_DEBUG, "igmp_rep_cleanup: %s\n", inet_ntoa(rep->igmpr_addr)));
134}
135
136/*
137 * void igmp_rep_print()
138 *
139 * Imprimer un enregistrement d'un membre
140 */
141void
142igmp_rep_print(
143	igmp_rep_t* rep)
144{
145  printf("\t\tmembre:%-16s\n",
146	 inet_ntoa(rep->igmpr_addr));
147}
148/*
149 * igmp_rep_t* igmp_group_rep_lookup()
150 *
151 * Lookup a membre in the sourcetable of a group
152 */
153igmp_rep_t*
154igmp_group_rep_lookup(
155	igmp_group_t *gp,
156	struct in_addr srcaddr)
157{
158  igmp_rep_t *rep;
159
160  assert(gp != NULL);
161  for (rep = (igmp_rep_t *) gp->igmpg_members; rep; rep = (igmp_rep_t *)rep->igmpr_next)
162    if (rep->igmpr_addr.s_addr == srcaddr.s_addr)
163      return rep;
164  return NULL;
165}
166
167/*
168 * igmp_rep_t* igmp_group_rep_add()
169 *
170 * Add a member to the set of sources of a group
171 */
172igmp_rep_t*
173igmp_group_rep_add(
174	igmp_group_t *gp,
175	struct in_addr srcaddr)
176{
177	igmp_rep_t* rep;
178
179	assert(gp != NULL);
180	/* Return the source if it's already present */
181	if (rep = igmp_group_rep_lookup(gp, srcaddr))
182	  return rep;
183	/* Create the source and add to the set */
184	if (rep = igmp_rep_create(srcaddr)) {
185	  rep->igmpr_next = (igmp_rep_t *)gp->igmpg_members;
186	  gp->igmpg_members = rep;
187	}
188	return rep;
189}
190
191
192igmp_rep_t*
193igmp_group_rep_del(
194	igmp_group_t *gp,
195	struct in_addr srcaddr)
196{
197	igmp_rep_t* rep;
198
199	assert(gp != NULL);
200	/* Return the source if it's not already present */
201	if (!(rep = igmp_group_rep_lookup(gp, srcaddr)))
202	  return NULL;
203	/* Delete the source and del to the set */
204	igmp_rep_cleanup(gp,rep);
205	return NULL; /* Foxconn added, zacker, 06/20/2009 */
206}
207/******************************************************************************
208 *
209 * igmp source routines
210 *
211 *****************************************************************************/
212/*
213 * igm_src_t* igmp_src_create()
214 *
215 * Cree un enregistrement d'une source
216 */
217igmp_src_t*
218igmp_src_create(
219	struct in_addr srcaddr)
220{
221	igmp_src_t* src;
222
223	if (src = (igmp_src_t*) malloc(sizeof(*src))) {
224	  src->igmps_source.s_addr = srcaddr.s_addr;
225	  src->igmps_timer = 0;
226	  src->igmps_fstate = TRUE;
227	  src->igmps_next  = NULL;
228	}
229	return src;
230}
231
232/*
233 * void igmp_src_cleanup()
234 *
235 * Effacer un enregistrement d'une source
236 */
237void
238igmp_src_cleanup(
239	igmp_group_t *gp,
240	igmp_src_t * src)
241{
242	igmp_src_t *sr;
243
244	assert(src != NULL);
245	assert (gp != NULL);
246	if (src != gp->igmpg_sources){
247	  for (sr=gp->igmpg_sources;(igmp_src_t *)sr->igmps_next != src;sr=(igmp_src_t *)sr->igmps_next);
248	  sr->igmps_next = src->igmps_next;
249	  free(src);
250	}else{
251	  /*delete the head*/
252	  sr=gp->igmpg_sources;
253	  gp->igmpg_sources = (igmp_src_t *)sr->igmps_next;
254	  free(sr);
255	}
256	LOG((LOG_DEBUG, "igmp_src_cleanup: %s\n", inet_ntoa(src->igmps_source)));
257}
258
259/*
260 * void igmp_src_print()
261 *
262 * Imprimer un enregistrement d'une source
263 */
264void
265igmp_src_print(
266	igmp_src_t* src)
267{
268  printf("\t\tsource:%-16s  %d\n",
269	 inet_ntoa(src->igmps_source),src->igmps_timer);
270}
271/*
272 * igmp_src_t* igmp_group_src_lookup()
273 *
274 * Lookup a source in the sourcetable of a group
275 */
276igmp_src_t*
277igmp_group_src_lookup(
278	igmp_group_t *gp,
279	struct in_addr srcaddr)
280{
281  igmp_src_t *src;
282
283 if (gp != NULL){
284  for (src = gp->igmpg_sources; src != NULL; src = (igmp_src_t *)src->igmps_next){
285    if (src->igmps_source.s_addr == srcaddr.s_addr)
286      return src;
287  }
288  }
289  return NULL;
290}
291
292/*
293 * igmp_src_t* igmp_group_src_add()
294 *
295 * Add a source to the set of sources of a group
296 */
297igmp_src_t*
298igmp_group_src_add(
299	igmp_group_t *gp,
300	struct in_addr srcaddr)
301{
302	igmp_src_t* src;
303
304	assert(gp != NULL);
305	/* Return the source if it's already present */
306	if (src = igmp_group_src_lookup(gp, srcaddr))
307	  return src;
308	/* Create the source and add to the set */
309	if (src = igmp_src_create(srcaddr)) {
310	  src->igmps_next = (igmp_src_t *)gp->igmpg_sources;
311	  gp->igmpg_sources = src;
312	}
313	return src;
314}
315
316
317
318/******************************************************************************
319 *
320 * igmp group routines
321 *
322 *****************************************************************************/
323
324/*
325 * igmp_group_t* igmp_group_create()
326 *
327 * Create a group record
328 */
329igmp_group_t*
330igmp_group_create(
331	struct in_addr groupaddr)
332{
333	igmp_group_t* gp;
334
335	if (gp = (igmp_group_t*) malloc(sizeof(*gp))) {
336		gp->igmpg_addr.s_addr = groupaddr.s_addr;
337		gp->igmpg_fmode = IGMP_FMODE_INCLUDE;
338		gp->igmpg_version = IGMP_VERSION_3;/*default version is V3*/
339		gp->igmpg_timer = 0;
340		gp->igmpg_sources = NULL;
341		gp->igmpg_members = NULL;
342		/* Foxconn added start, zacker, 06/20/2009 */
343		gp->igmpg_flags = GROUP_INIT;
344		gp->igmpg_type= MODE_IS_INCLUDE;
345		/* Foxconn added end, zacker, 06/20/2009 */
346		gp->igmpg_next = NULL;
347		return gp;
348	}else
349		return NULL;
350
351}
352
353/*
354 * void igmp_group_print()
355 *
356 * Print a group record
357 */
358void
359igmp_group_print(
360	igmp_group_t* gp)
361{
362  igmp_src_t *src;
363  igmp_rep_t *rep;
364  printf("  %-16s %s %d\n",
365	 inet_ntoa(gp->igmpg_addr),
366	 (gp->igmpg_fmode == IGMP_FMODE_EXCLUDE) ? "exclude" : "include",
367	 gp->igmpg_timer);
368  if (gp->igmpg_sources != NULL)
369    for (src=gp->igmpg_sources;src;src=(igmp_src_t *)src->igmps_next)
370      printf("source : %s timer : %d\n",inet_ntoa(src->igmps_source),src->igmps_timer);
371   if (gp->igmpg_members != NULL)
372    for (rep=gp->igmpg_members;rep;rep=(igmp_rep_t *)rep->igmpr_next)
373      printf("member : %s \n",inet_ntoa(rep->igmpr_addr));
374}
375
376/******************************************************************************
377 *
378 * igmp interface routines
379 *
380 *****************************************************************************/
381
382/*
383 * igmp_interface_t* igmp_interface_create()
384 *
385 * Create and initialize interface record
386 */
387igmp_interface_t*
388igmp_interface_create(
389	struct in_addr ifaddr,
390	char *ifname,
391	vifi_t index)
392{
393  igmp_interface_t* ifp = NULL; /* Foxconn modified, zacker, 06/20/2009 */
394  struct ip_mreq mreq;
395  char ra[4];
396  int i, prom;
397  short flags;
398
399	if (((ifp = (igmp_interface_t*) malloc(sizeof(*ifp)))) == NULL)
400		return NULL;
401
402	/* Allocate a buffer to receive igmp messages */
403	ifp->igmpi_bufsize = get_interface_mtu(ifname);
404	if (ifp->igmpi_bufsize == -1)
405		ifp->igmpi_bufsize = MAX_MSGBUFSIZE;
406	/* XXX Should make buffer slightly bigger for ip header */
407	if ((ifp->igmpi_buf = (char*) malloc(ifp->igmpi_bufsize)) == NULL) {
408		free(ifp);
409		return NULL;
410	}
411
412	/* Create a raw igmp socket */
413	ifp->igmpi_socket = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP);
414
415	if (ifp->igmpi_socket == -1) {
416		printf("can't create socket \n");
417		free(ifp->igmpi_buf);
418		free(ifp);
419		return NULL;
420	}
421	/* Initialize all fields */
422	ifp->igmpi_addr.s_addr = ifaddr.s_addr;
423	strncpy(ifp->igmpi_name, ifname, IFNAMSIZ);
424	ifp->igmpi_groups = NULL;
425	ifp->sch_group_query = NULL;
426
427	/* Foxconn add start by aspen Bai, 12/07/2007 */
428	if (((ifp->igmpi_addr.s_addr & lan_netmask)
429			    == (lan_ipaddr & lan_netmask)))
430	{
431		ifp->igmpi_type = DOWNSTREAM;
432		lan_index = index;
433	}else
434	{
435		if(ifp->igmpi_addr.s_addr)
436		{
437		   ifp->igmpi_type = UPSTREAM;
438		   upstream = ifp->igmpi_addr.s_addr;
439		   wan_index = index;
440		   wan_igmp_socket = ifp->igmpi_socket;
441		}
442		else
443		{
444			printf("can't get correct wan ip 0x%x \n",ifp->igmpi_addr.s_addr);
445			free(ifp->igmpi_buf);
446			free(ifp);
447			return NULL;
448		}
449	}
450	/* Foxconn add end by aspen Bai, 12/07/2007 */
451
452	ifp->igmpi_isquerier = TRUE;
453	ifp->igmpi_version = version; /* IGMP_VERSION_3 */
454	ifp->igmpi_qi = IGMP_DEF_QI;
455	/* Foxconn modified start, zacker, 06/20/2009 */
456	ifp->igmpi_qri = (IGMP_DEF_QRI * IGMP_DEF_QRI_UNIT);
457	ifp->igmpi_oqp = IGMP_OQPI;
458	ifp->ifp_udp_socket = -1;
459	/* Foxconn modified end, zacker, 06/20/2009 */
460	ifp->igmpi_rv = IGMP_DEF_RV;
461	ifp->igmpi_gmi = ifp->igmpi_rv * ifp->igmpi_qi + ifp->igmpi_qri;
462	ifp->igmpi_ti_qi = 0;
463	ifp->igmpi_next = NULL;
464
465	/* Set router alert */
466	ra[0] = 148;
467	ra[1] = 4;
468	ra[2] = 0;
469	ra[3] = 0;
470
471#if 1
472	setsockopt(ifp->igmpi_socket, IPPROTO_IP, IP_OPTIONS, ra, 4);
473	/* Set reuseaddr, ttl, loopback and set outgoing interface */
474	i = 1;
475	setsockopt(ifp->igmpi_socket, SOL_SOCKET, SO_REUSEADDR,
476		(void*)&i, sizeof(i));
477	i = 1;
478	setsockopt(ifp->igmpi_socket, IPPROTO_IP, IP_MULTICAST_TTL,
479		(void*)&i, sizeof(i));
480	/* Foxconn add start by aspen Bai, 01/08/2008 */
481	i = 0;
482	setsockopt(ifp->igmpi_socket, IPPROTO_IP, IP_MULTICAST_LOOP,
483		(void*)&i, sizeof(i));
484	/* Foxconn add end by aspen Bai, 01/08/2008 */
485	setsockopt(ifp->igmpi_socket, IPPROTO_IP, IP_MULTICAST_IF,
486		(void*)&ifaddr, sizeof(ifaddr));
487
488
489	//setsockopt(ifp->igmpi_socket, IPPROTO_IP, IP_RECVIF, &i, sizeof(i));
490	/* Add membership to ALL_ROUTERS and ALL_ROUTERS_V3 on this interface */
491	mreq.imr_multiaddr.s_addr = inet_addr(IGMP_ALL_ROUTERS);
492	mreq.imr_interface.s_addr = ifaddr.s_addr;/*htonl(0);*/
493	setsockopt(ifp->igmpi_socket, IPPROTO_IP, IP_ADD_MEMBERSHIP,
494		(void*)&mreq, sizeof(mreq));
495	mreq.imr_multiaddr.s_addr = inet_addr(IGMP_ALL_ROUTERS_V3);
496	mreq.imr_interface.s_addr = ifaddr.s_addr;/*htonl(0);*/
497	setsockopt(ifp->igmpi_socket, IPPROTO_IP, IP_ADD_MEMBERSHIP,
498		(void*)&mreq, sizeof(mreq));
499#endif
500
501#if 1
502	/* Tell the kernel this interface belongs to a multicast router */
503	mrouter_onoff(ifp->igmpi_socket,1);
504	//k_proxy_add_vif(ifp->igmpi_socket, ifp->igmpi_addr.s_addr, index);
505	ifp->igmpi_index = index;
506	/* Set the interface flags to receive all multicast packets */
507	ifp->igmpi_save_flags = get_interface_flags(ifname);
508	if (ifp->igmpi_save_flags != -1) {
509		set_interface_flags(ifname, ifp->igmpi_save_flags | IFF_ALLMULTI);
510		/* If IFF_ALLMULTI didn't work, try IFF_PROMISC */
511		flags = get_interface_flags(ifname);
512		if ((flags & IFF_ALLMULTI) != IFF_ALLMULTI)
513			set_interface_flags(ifname, ifp->igmpi_save_flags | IFF_PROMISC);
514	}
515#endif
516
517	return ifp;
518}
519
520/*
521 * void igmp_interface_cleanup()
522 *
523 * Cleanup an interface
524 */
525void
526igmp_interface_cleanup(igmp_interface_t* ifp)
527{
528	igmp_group_t* gp,*gp2;
529
530	assert(ifp != NULL);
531	LOG((LOG_DEBUG, "igmp_interface_cleanup: %s\n", inet_ntoa(ifp->igmpi_addr)));
532
533	/* Cleanup all groups */
534	gp=ifp->igmpi_groups;
535	ifp->igmpi_groups = NULL;
536	while(gp != NULL){
537		gp2=gp;
538		gp=gp->igmpg_next;
539		free(gp2);
540	}
541	/* Tell the kernel the multicast router is no more */
542	mrouter_onoff(ifp->igmpi_socket, 0);
543	close(ifp->igmpi_socket);
544
545 	free(ifp->igmpi_buf);
546
547	/* If we managed to get/set the interface flags, revert */
548	if (ifp->igmpi_save_flags != -1)
549		set_interface_flags(ifp->igmpi_name, ifp->igmpi_save_flags);
550	free(ifp);
551}
552
553/*
554 * igmp_group_t* igmp_interface_group_add()
555 *
556 * Add a group to the set of groups of an interface
557 */
558igmp_group_t*
559igmp_interface_group_add(
560	igmp_router_t* router,
561	igmp_interface_t *ifp,
562	struct in_addr groupaddr)
563{
564	igmp_group_t* gp;
565	struct ip_mreq mreq;
566	igmp_interface_t* upstream_interface;
567	struct in_addr up;
568
569	assert(ifp != NULL);
570	/* Return the group if it's already present */
571	if (gp = igmp_interface_group_lookup(ifp, groupaddr))
572		return gp;
573	/* Create the group and add to the set */
574	if (gp = igmp_group_create(groupaddr)) {
575		gp->igmpg_next = ifp->igmpi_groups;
576		ifp->igmpi_groups = gp;
577
578		/*add group to the set of groups of upstream interface*/
579		mreq.imr_multiaddr.s_addr=groupaddr.s_addr;
580		mreq.imr_interface.s_addr=upstream;
581		if ((VALID_ADDR(mreq.imr_multiaddr)) && (ifp->igmpi_addr.s_addr != upstream)) {
582		  up.s_addr = upstream;
583		  upstream_interface = igmprt_interface_lookup(router,up);
584		  if (igmp_interface_group_lookup(upstream_interface,mreq.imr_multiaddr) == NULL) {
585		    if (setsockopt(router->igmprt_up_socket, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void *) &mreq, sizeof(mreq)) < 0) {
586		      //perror("setsockopt - IP_ADD_MEMBERSHIP");
587		      //exit(1);
588		    }
589		  }
590		}
591	}
592	return gp;
593}
594
595/*
596 * igmp_group_t* igmp_interface_group_lookup()
597 *
598 * Lookup a group in the grouptable of an interface
599 */
600igmp_group_t*
601igmp_interface_group_lookup(
602	igmp_interface_t *ifp,
603	struct in_addr groupaddr)
604{
605	igmp_group_t* gp;
606	assert(ifp != NULL);
607	for (gp = ifp->igmpi_groups; gp; gp = gp->igmpg_next)
608		if (gp->igmpg_addr.s_addr == groupaddr.s_addr)
609			return gp;
610	return NULL;
611}
612
613/*
614 * void igmp_interface_membership_report_v12()
615 *
616 * Process a v1/v2 membership report
617 */
618void
619igmp_interface_membership_report_v12(
620	igmp_router_t* router,
621	igmp_interface_t* ifp,
622	struct in_addr src,
623	igmpr_t* report,
624	int len,
625	int version)
626{
627	igmp_group_t* gp;
628	igmp_rep_t *rep;
629
630	/* Ignore a report for a non-multicast address */
631	if (! IN_MULTICAST(ntohl(report->igmpr_group.s_addr)))
632		return;
633
634	if(!igmp_interface_group_lookup(ifp,report->igmpr_group))
635	{
636		send_membership_report_v12(router,report->igmpr_group,version);
637	}
638
639	/* Find the group, and if not present, add it */
640	if ((gp = igmp_interface_group_add(router,ifp, report->igmpr_group)) == NULL)
641		return;
642
643    /* find the member and add it if not present*/
644	rep=igmp_group_rep_add(gp,src);
645
646	/* Consider this to be a v3 is_ex{} report */
647	igmp_group_handle_isex(router,ifp, gp, 0, NULL);
648
649    /* Foxconn add start by aspen Bai, 12/07/2007 */
650    if(((src.s_addr & lan_netmask)
651			    == (lan_ipaddr & lan_netmask))
652				&& (src.s_addr != lan_ipaddr))
653    {
654        k_proxy_chg_mfc(router->igmprt_socket,mulsrc.igmps_addr.s_addr,gp->igmpg_addr.s_addr,wan_index,1);
655    }
656	igmp_info_print(router);
657    /* Foxconn add end by aspen Bai, 12/07/2007 */
658}
659
660#ifdef IGMP_DEBUG
661void printContent(char * pBuf, int len)
662{
663	int i;
664	for(i=0;i<len;i++,pBuf++)
665	{
666		if(i%0x10==0)
667		{
668			printf("0x%x  ", *pBuf);
669			printf("\n\r");
670		}
671		else
672		 printf("0x%x  ", *pBuf);
673	}
674	printf("\n");
675}
676#endif
677/*
678 * void igmp_interface_membership_report_v3()
679 *
680 * Process a v3 membership report :only a group record in the report
681 * len :will be used in the Baal implementation
682 */
683void
684igmp_interface_membership_report_v3(
685				    igmp_router_t* router,
686				    igmp_interface_t* ifp,
687				    struct in_addr src,/* addresse member */
688				    igmp_report_t* report,
689				    int len)
690{
691	igmp_group_t* gp;
692    igmp_rep_t *rep;
693	u_short numsrc;
694	u_short numgrps;
695	u_char type = MODE_IS_INCLUDE;
696	int i;
697
698	/* test l'interface: si report prevenant de l'upstream,
699           et @addresse membre != mon addresse 	alors forward_upstream  = 1
700         */
701	//printf("%s, %d, src %s\n",__FUNCTION__,__LINE__,inet_ntoa(src.s_addr));
702    if ((ifp->igmpi_addr.s_addr == upstream) && (src.s_addr != upstream) && (VALID_ADDR(report->igmpr_group[0].igmpg_group)))
703	{
704		//printf("%s, %d\n",__FUNCTION__,__LINE__);
705       forward_upstream = 1;
706	}
707	numgrps = ntohs(report->igmpr_numgrps);
708
709	for (i=0; i < numgrps;i++){
710		//printf("%s, %d\n",__FUNCTION__,__LINE__);
711		/* Ignore a report for a non-multicast address */
712		/* Foxconn modified start, zacker, 06/20/2009 */
713		if (! IN_MULTICAST(ntohl(report->igmpr_group[i].igmpg_group.s_addr)))
714			continue;
715
716		if(report->igmpr_group[i].igmpg_group.s_addr == inet_addr(IGMP_ALL_ROUTERS))
717			continue;
718
719		if (igmp_interface_group_lookup(ifp, report->igmpr_group[i].igmpg_group) == NULL
720			&& report->igmpr_group[i].igmpg_type == CHANGE_TO_INCLUDE)
721			continue;
722
723		/* Find the group, and if not present, add it */
724		if ((gp = igmp_interface_group_add(router,ifp, report->igmpr_group[i].igmpg_group)) == NULL)
725			continue;
726		/* Foxconn modified end, zacker, 06/20/2009 */
727	    /* find the source of the report and add it if not present*/
728		rep=igmp_group_rep_add(gp,src);
729
730		/* Find the group record type */
731		type   = (u_char)report->igmpr_group[i].igmpg_type;
732		numsrc = ntohs(report->igmpr_group[i].igmpg_numsrc);
733		gp->igmpg_type = type;
734		//printf("%s, %d type %d, group %s\n",__FUNCTION__,__LINE__,type,inet_ntoa(gp->igmpg_addr.s_addr));
735		switch(type) {
736		case MODE_IS_INCLUDE:	/* an IS_IN report */
737		  igmp_group_handle_isin(router,ifp,gp,numsrc,(struct in_addr *) (&report->igmpr_group[i].igmpg_group+4));
738		  break;
739		case MODE_IS_EXCLUDE:	/* an IS_EX report */
740		  igmp_group_handle_isex(router,ifp,gp,numsrc,(struct in_addr *) (&report->igmpr_group[i].igmpg_group+4));
741		  break;
742		case CHANGE_TO_INCLUDE:
743			//printf("%s, %d\n",__FUNCTION__,__LINE__);/* an TO_IN report */
744		  igmp_group_handle_toin(router,ifp,gp,numsrc,rep,(struct in_addr *) (&report->igmpr_group[i].igmpg_group+4));
745		  break;
746		case CHANGE_TO_EXCLUDE:
747			//printf("%s, %d\n",__FUNCTION__,__LINE__);/* an TO_EX report */
748		  igmp_group_handle_toex(router,ifp,gp,numsrc,(struct in_addr *) (&report->igmpr_group[i].igmpg_group+4));
749		  break;
750		case ALLOW_NEW_SOURCES: /* an ALLOW report */
751		  igmp_group_handle_allow(router,ifp,gp,numsrc,(struct in_addr *) (&report->igmpr_group[i].igmpg_group+4));
752		  break;
753		case BLOCK_OLD_SOURCES: /* an BLOCK report */
754		  igmp_group_handle_block(router,ifp,gp,numsrc,(struct in_addr *) (&report->igmpr_group[i].igmpg_group+4));
755		  break;
756		default:
757		  LOG((LOG_INFO, "igmp_interface_membership_report_v3: group record type undefined"));
758		  break;
759		}
760	}
761
762	if(i && (type != MODE_IS_EXCLUDE))
763	{
764		send_membership_report_v3(FALSE);
765	}
766}
767
768
769/*
770 * void igmp_interface_print()
771 *
772 * Print status of an interface
773 */
774void
775igmp_interface_print(
776	igmp_interface_t* ifp)
777{
778	igmp_group_t* gp;
779
780	printf(" interface %s, %s ver=0x%x\n",
781		inet_ntoa(ifp->igmpi_addr),(ifp->igmpi_type == UPSTREAM)?"UPSTREAM":"DOWNSTREAM", ifp->igmpi_version);
782	for (gp = ifp->igmpi_groups; gp; gp = gp->igmpg_next)
783		igmp_group_print(gp);
784}
785
786/******************************************************************************
787 *
788 * igmp router routines
789 *
790 *****************************************************************************/
791
792/*
793 * int igmprt_init()
794 *
795 * Initialize igmp router
796 */
797int
798igmprt_init(
799	igmp_router_t* igmprt)
800{
801	igmprt->igmprt_interfaces = NULL;
802	igmprt->igmprt_thr_timer = igmprt->igmprt_thr_input = NULL;
803	igmprt->igmprt_flag_timer = 0;
804	igmprt->igmprt_flag_input = 0;
805	/*create datagram socket to tell igmpv3 host about reports to send on upstream interface*/
806	igmprt->igmprt_up_socket = socket( AF_INET, SOCK_DGRAM, 0 );
807        if( igmprt->igmprt_up_socket < 0) {
808	  perror("can't open upstream socket");
809	  exit (1);
810	}
811	/*create raw socket to update mfc and vif table*/
812	igmprt->igmprt_socket = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP);
813	if (igmprt->igmprt_socket < 0)
814	  perror("can't open igmp socket");
815        forward_upstream = 0;
816	return 1;
817}
818
819/*
820 * void igmprt_destroy()
821 *
822 * Cleanup the router
823 */
824void
825igmprt_destroy(igmp_router_t* igmprt)
826{
827	igmp_interface_t *ifp, *ifp2;
828	igmp_group_t *gp;
829	igmp_src_t *sp;
830
831	for (ifp = igmprt->igmprt_interfaces; ifp;) {
832		ifp2 = ifp;
833		ifp = ifp->igmpi_next;
834		igmp_interface_cleanup(ifp2);
835	}
836	LOG((LOG_DETAIL, "destroy igmp router ...\n"));
837	igmprt_stop(igmprt);
838
839}
840
841/*
842 * interface_t* igmprt_interface_lookup()
843 *
844 * Lookup a group, identified by the interface address
845 */
846igmp_interface_t*
847igmprt_interface_lookup(
848	igmp_router_t* igmprt,
849	struct in_addr ifaddr)
850{
851	igmp_interface_t *ifp;
852
853	for (ifp = igmprt->igmprt_interfaces; ifp; ifp = ifp->igmpi_next)
854		if (ifp->igmpi_addr.s_addr == ifaddr.s_addr)
855			return ifp;
856	return NULL;
857}
858
859/*
860 * interface_t* igmprt_interface_lookup_index()
861 *
862 * Lookup a interface, identified by the interface index
863 */
864igmp_interface_t*
865igmprt_interface_lookup_index(
866	igmp_router_t* igmprt,
867	int ifp_index)
868{
869	igmp_interface_t *ifp;
870
871	for (ifp = igmprt->igmprt_interfaces; ifp; ifp = ifp->igmpi_next)
872		if (ifp->igmpi_index == ifp_index)
873			return ifp;
874	return NULL;
875}
876
877/*
878 * igmp_entry_t* igmprt_group_lookup()
879 *
880 * Lookup a group, identified by the interface and group address
881 */
882igmp_group_t*
883igmprt_group_lookup(
884	igmp_router_t* igmprt,
885	struct in_addr ifaddr,
886	struct in_addr groupaddr)
887{
888	igmp_interface_t *ifp;
889
890	if (ifp = igmprt_interface_lookup(igmprt, ifaddr))
891		return igmp_interface_group_lookup(ifp, groupaddr);
892	return NULL;
893}
894
895/*
896 * struct igmp_interface_t* igmprt_interface_add()
897 *
898 * Add an interface to the interfacetable
899 */
900igmp_interface_t*
901igmprt_interface_add(
902	igmp_router_t* igmprt,
903	struct in_addr ifaddr,
904	char *ifname,
905	vifi_t index)
906{
907	igmp_interface_t *ifp;
908
909	/* Return the interface if it's already in the set */
910	if (ifp = igmprt_interface_lookup(igmprt, ifaddr))
911		return ifp;
912	/* Create the interface and add to the set */
913	if (ifp = igmp_interface_create(ifaddr, ifname,index)) {
914		ifp->igmpi_next = igmprt->igmprt_interfaces;
915		igmprt->igmprt_interfaces = ifp;
916	}
917	return ifp;
918}
919
920/*
921 * igmp_group_t* igmprt_group_add()
922 *
923 * Add a group to the grouptable of some interface
924 */
925igmp_group_t*
926igmprt_group_add(
927	igmp_router_t* igmprt,
928	struct in_addr ifaddr,
929	struct in_addr groupaddr)
930{
931	igmp_interface_t *ifp;
932	igmp_group_t *gp;
933
934	if (ifp = igmprt_interface_lookup(igmprt, ifaddr))
935		return NULL;
936	return igmp_interface_group_add(igmprt,ifp, groupaddr);
937}
938
939/*
940 * void igmprt_timergroup(igmp_router_t* igmprt)
941 *
942 * Decrement timers and handle whatever has to be done when one expires
943 */
944void
945igmprt_timer(igmp_router_t* igmprt)
946{
947  igmp_interface_t* ifp;
948  igmp_group_t* gp;
949  struct in_addr zero;
950
951  zero.s_addr = 0;
952
953  /* Foxconn add start by aspen Bai, 01/10/2008 */
954  if(--wan_version_timer == 0)
955  {
956	  wan_version_timer = IGMP_WAN_VERSION_TIMER;
957	  wan_igmp_version = IGMP_VERSION_3;
958  }
959
960  /*
961  if(--igmp_aggregation_timer == 0)
962  {
963	  igmp_aggregation_timer = IGMP_V3_AGGREGATION_INTERVAL;
964  }*/
965  /* Foxconn add end by aspen Bai, 01/10/2008 */
966
967  /* Handle every interface */
968  for (ifp = igmprt->igmprt_interfaces; ifp; ifp = ifp->igmpi_next) {
969    /* If we're the querier for this network, handle all querier
970     * duties */
971    if (ifp->igmpi_isquerier == TRUE) {
972      /* Deal with the general query */
973      if (--ifp->igmpi_ti_qi <= 0) {
974	ifp->igmpi_ti_qi = ifp->igmpi_qi;
975	igmprt_membership_query(igmprt, ifp, &zero, NULL, 0, 0);
976      }
977    }
978
979	else{
980     /* If not the querier, deal with other-querier-present timer*/
981     igmprt_timer_querier(ifp);
982    }
983    /*handle group timer*/
984    /*LOG((LOG_DEBUG, "handle timer group\n"));*/
985    igmprt_timer_group(igmprt,ifp);
986    /*handle source timer*/
987    /*LOG((LOG_DEBUG, "handle timer source\n"));*/
988    igmprt_timer_source(igmprt,ifp);
989    /*handle scheduled query*/
990    send_sh_query(igmprt,ifp);
991  }
992
993
994}
995
996/*
997 * void* igmprt_timer_thread(void* arg)
998 *
999 * The thread that deals with the timer
1000 */
1001void*
1002igmprt_timer_thread(void* arg)
1003{
1004  igmp_router_t* igmprt = (igmp_router_t*) arg;
1005
1006  while (igmprt->igmprt_flag_timer) {
1007    igmprt_timer(igmprt);
1008    /* Should be changed to take care of drifting */
1009    usleep(1000000);
1010  }
1011  pthread_exit(NULL);
1012  return NULL;
1013}
1014
1015/*
1016 * void igmprt_input()
1017 *
1018 * Process an incoming igmp message
1019 */
1020void
1021igmprt_input(igmp_router_t* igmprt, igmp_interface_t* ifp)
1022{
1023
1024	/*struct msghdr msg;
1025	struct iovec iov;
1026	struct cmsghdr *cmsg;
1027	char *ctrl = (char *)malloc(MAXCTRLSIZE);*/
1028
1029	int if_index;
1030	struct sockaddr_in sin;
1031	struct ip *iph;
1032	unsigned char *ptype;
1033	int n, len, igmplen;
1034	igmp_report_t *report;
1035	igmpv3q_t *query;
1036    struct in_addr src,rt_lan,rt_wan;
1037	int srsp;
1038	igmp_interface_t *ifpi;
1039
1040	/* Read the igmp message */
1041	/*iov.iov_base = (char *)ifp->igmpi_buf;
1042	iov.iov_len = ifp->igmpi_bufsize;
1043	msg.msg_iov = &iov;
1044	msg.msg_iovlen= 1;
1045	msg.msg_control = ctrl;
1046	msg.msg_controllen = MAXCTRLSIZE;*/
1047
1048	/*n=recvmsg(ifp->igmpi_socket,&msg,0);*/
1049
1050	//for(cmsg=CMSG_FIRSTHDR(&msg); cmsg != NULL;cmsg =CMSG_NXTHDR(&msg,cmsg)) {
1051		/*if (cmsg->cmsg_type == IP_RECVIF){
1052			if_index = CMSG_IFINDEX(cmsg);*//* returns 1 or 2*/
1053			//if_index --; /* for us interfaces are 0 or 1*/
1054
1055		//}
1056	//}
1057	len = sizeof(sin);
1058	rt_lan.s_addr = lan_ipaddr;
1059	rt_wan.s_addr = upstream;
1060
1061	/* Fonconn add start by aspen Bai, 01/03/2008 */
1062	n = recvfrom(igmprt->igmprt_socket, ifp->igmpi_buf, ifp->igmpi_bufsize, 0,
1063		(struct sockaddr*)&sin, &len);
1064
1065	if (n <= sizeof(*iph))
1066		return;
1067#ifdef IGMP_DEBUG
1068	printContent(ifp->igmpi_buf, n);
1069#endif
1070
1071	/* Set pointer to start of report */
1072	iph = (struct ip*) ifp->igmpi_buf;
1073	if ((igmplen = n - (iph->ip_hl << 2)) < IGMP_MINLEN)
1074		return;
1075
1076	if (iph->ip_p != IPPROTO_IGMP)
1077		return;
1078
1079    src=iph->ip_src;
1080	/* Foxconn add start by aspen Bai, 12/7/2007 */
1081	if((src.s_addr != upstream)
1082		&& ((src.s_addr & lan_netmask)
1083		    != (lan_ipaddr & lan_netmask)))
1084	{
1085/* Foxconn modify start by aspen Bai, 01/28/2008 */
1086#if 1
1087		memset(&mulsrc,0,sizeof(igmp_mulsrc_t));
1088		//mulsrc.igmps_addr.s_addr = 0;
1089		mulsrc.igmps_addr.s_addr = src.s_addr;
1090		mulsrc.igmps_next = NULL;
1091#endif
1092
1093/* Foxconn modify end by aspen Bai, 01/28/2008 */
1094	}
1095	/* Foxconn add end by aspen Bai, 12/7/2007 */
1096 	ptype =ifp->igmpi_buf + (iph->ip_hl << 2);
1097	if ((src.s_addr & lan_netmask)
1098			    == (lan_ipaddr & lan_netmask))
1099		ifpi = igmprt_interface_lookup(igmprt, rt_lan);
1100	else
1101		ifpi = igmprt_interface_lookup(igmprt, rt_wan);
1102	/* Fonconn add end by aspen Bai, 01/03/2008 */
1103
1104	//printf("%s, %d, type %d, src %s\n",__FUNCTION__,__LINE__,*ptype,inet_ntoa(src.s_addr));
1105	/* Handle the message */
1106	switch (*ptype) {
1107	case IGMP_MEMBERSHIP_QUERY:
1108		//printf("%s, %d\n",__FUNCTION__,__LINE__);
1109		query = (igmpv3q_t *)(ifp->igmpi_buf + (iph->ip_hl << 2));
1110		srsp=IGMP_SRSP(query);
1111		if (query->igmpq_code == 0){
1112			/*version 1 query*/
1113			LOG((LOG_DEBUG, "igmpv1 query \n"));
1114			receive_membership_query(igmprt,ifpi,query->igmpq_group,NULL,src.s_addr,0,srsp,IGMP_VERSION_1);
1115		}else if (igmplen == 8){
1116			/*version 2 query*/
1117			LOG((LOG_DEBUG, "igmpv2 query \n"));
1118			receive_membership_query(igmprt,ifpi,query->igmpq_group,NULL,src.s_addr,0,srsp,IGMP_VERSION_2);
1119		}else if (igmplen >= 12){
1120			/*version 3 query*/
1121			receive_membership_query(igmprt,ifpi,query->igmpq_group,query->igmpq_sources,src.s_addr,query->igmpq_numsrc,srsp,IGMP_VERSION_3);
1122		}
1123		break;
1124	case IGMP_V1_MEMBERSHIP_REPORT:
1125		//printf("%s, %d\n",__FUNCTION__,__LINE__);
1126		igmp_interface_membership_report_v12(igmprt,ifpi,src, (igmpr_t*) ptype, igmplen, IGMP_VERSION_1);
1127		break;
1128	case IGMP_V2_MEMBERSHIP_REPORT:
1129		//printf("%s, %d\n",__FUNCTION__,__LINE__);
1130		igmp_interface_membership_report_v12(igmprt,ifpi,src, (igmpr_t*) ptype, igmplen, IGMP_VERSION_2);
1131		break;
1132	case IGMP_V3_MEMBERSHIP_REPORT:
1133		//printf("%s, %d\n",__FUNCTION__,__LINE__);
1134		/* use ifp->igmpi_buf to construct report content, not ifpi->igmpi_buf */
1135		report = (igmp_report_t *)(ifp->igmpi_buf + (iph->ip_hl << 2));
1136	    igmp_interface_membership_report_v3(igmprt,ifpi,src,report,sizeof(report));
1137	        break;
1138	case IGMP_V2_LEAVE_GROUP:
1139		igmp_interface_leave_group_v2(igmprt,ifpi,src, (igmpr_t*) ptype, igmplen);
1140		break;
1141	default:
1142		break;
1143	}
1144}
1145
1146/*
1147 * void* igmprt_input_thread(void* arg)
1148 *
1149 * Wait on all interfaces for packets to arrive
1150 */
1151void*
1152igmprt_input_thread(void* arg)
1153{
1154	igmp_router_t* igmprt = (igmp_router_t*) arg;
1155	igmp_interface_t* ifp;
1156	fd_set allset, rset;
1157	int n, maxfd;
1158	/*struct timeval timeout={0};
1159	timeout.tv_sec = 300;
1160	timeout.tv_usec = 0 ;*/
1161
1162	/* Add the sockets from all interfaces to the set */
1163
1164	FD_ZERO(&allset);
1165	maxfd = 0;
1166	/*for (ifp = igmprt->igmprt_interfaces; ifp; ifp = ifp->igmpi_next) {
1167		FD_SET(ifp->igmpi_socket, &allset);
1168		if (maxfd < ifp->igmpi_socket)
1169			maxfd = ifp->igmpi_socket;
1170
1171	}*/
1172	FD_SET(igmprt->igmprt_socket, &allset);
1173	for (ifp = igmprt->igmprt_interfaces; ifp; ifp = ifp->igmpi_next)
1174	{
1175		FD_SET(ifp->igmpi_socket, &allset);
1176		if (maxfd < ifp->igmpi_socket)
1177			maxfd = ifp->igmpi_socket;
1178	}
1179	maxfd = (igmprt->igmprt_socket>maxfd)?igmprt->igmprt_socket:maxfd;
1180	if (maxfd == 0) {
1181		LOG((LOG_INFO, "error: no interfaces available to wait for input\n"));
1182		return NULL;
1183	}
1184	/* Wait for data on all sockets */
1185	while (1) {
1186		FD_COPY(&allset, &rset);
1187		n = select(maxfd+1, &rset, NULL, NULL, NULL);
1188		if (n == 0)
1189			sleep(1);
1190		for (ifp = igmprt->igmprt_interfaces; ifp; ifp = ifp->igmpi_next) {
1191			if (FD_ISSET(ifp->igmpi_socket, &rset) || FD_ISSET(igmprt->igmprt_socket,&rset))
1192				; /* Foxconn modify by aspen Bai, 01/29/2008 */
1193				/* Let igmprt_input to block , not select */
1194			igmprt_input(igmprt, ifp);
1195			if (--n == 0)
1196				break;
1197		}
1198	}
1199	return NULL;
1200}
1201
1202/*
1203 * void igmprt_start(igmp_router_t* igmprt)
1204 *
1205 * Start the threads of this router
1206 */
1207void
1208igmprt_start(igmp_router_t* igmprt)
1209{
1210	int err;
1211
1212	/* Return if already running */
1213	if (igmprt->igmprt_running)
1214		return;
1215
1216	/* Create and start the timer handling (thread) */
1217	igmprt->igmprt_flag_timer = 1;
1218	igmprt->igmprt_thr_timer = NULL;
1219	if ((err = pthread_create(&igmprt->igmprt_thr_timer, NULL,
1220		igmprt_timer_thread, (void*) igmprt)) != 0)
1221		printf("couldn't start timer thread\n");
1222
1223	/* Create and start input handling (thread) */
1224
1225	igmprt->igmprt_flag_input = 1;
1226	igmprt->igmprt_thr_input = NULL;
1227	if ((err = pthread_create(&igmprt->igmprt_thr_input, NULL,
1228		igmprt_input_thread, (void*) igmprt)) != 0)
1229		printf("couldn't start input thread\n");
1230	igmprt->igmprt_running = 1;
1231}
1232
1233/*
1234 * void igmprt_stop(igmp_router_t* igmprt)
1235 *
1236 * Stop the threads of this router
1237 */
1238void
1239igmprt_stop(igmp_router_t* igmprt)
1240{
1241	igmp_interface_t* ifp;
1242	int i=0;
1243
1244	/* Return if not running */
1245	if (! igmprt->igmprt_running)
1246		return;
1247
1248	k_stop_proxy(igmprt->igmprt_socket);
1249
1250	/* Signal threads to stop */
1251	igmprt->igmprt_flag_timer = 0;
1252	igmprt->igmprt_flag_input = 0;
1253
1254	/* Wait for the threads to finish */
1255	/* XXX Should use attach */
1256	igmprt->igmprt_running = 0;
1257	/* Make sure select of  input-thread wakes up */
1258	/*if ((ifp = igmprt->igmprt_interfaces))
1259		write(ifp->igmpi_socket, &i, sizeof(i));*/
1260	sleep(3);
1261}
1262
1263/*
1264 * void igmprt_print()
1265 *
1266 * Print the status of the igmpv3 proxy/router
1267 */
1268void
1269igmprt_print(igmp_router_t* igmprt)
1270{
1271	igmp_interface_t* ifp;
1272
1273	assert(igmprt != NULL);
1274	printf("igmp router:\n");
1275	for (ifp = igmprt->igmprt_interfaces; ifp; ifp = ifp->igmpi_next)
1276		igmp_interface_print(ifp);
1277}
1278
1279/******************************************************************************
1280 *
1281 * The application
1282 *
1283 *****************************************************************************/
1284
1285#define BUF_CMD	100
1286
1287igmp_router_t router;
1288int go_on = 1;
1289char* pidfile = DEFAULT_PID_FILE_NAME;
1290
1291void
1292write_pid()
1293{
1294	FILE *fp = fopen(pidfile, "w");
1295	if (fp) {
1296		fprintf(fp, "%d\n", getpid());
1297		fclose(fp);
1298	}
1299}
1300
1301void
1302done(int sig)
1303{
1304	igmprt_destroy(&router);
1305	unlink(pidfile);
1306	exit(0);
1307}
1308
1309void parse_option(void)
1310{
1311
1312  FILE *f;
1313  char linebuf[100];
1314  char *w, *s;
1315  int option;
1316
1317  if ((f=fopen(DEFAULT_CONF_FILE_PATH,"r")) == NULL)
1318    printf("can't open config file DEFAULT_CONF_FILE_PATH\n");
1319
1320  while(fgets(linebuf,sizeof(linebuf),f) != NULL){
1321    s=linebuf;
1322    w=(char *)next_word(&s);
1323    option=wordToOption(w);
1324    switch(option){
1325    case EMPTY:
1326      continue;
1327      break;
1328    case IGMPVERSION:
1329      printf("version :");
1330      if (EQUAL((w=(char *)next_word(&s))," ")){
1331	version= DEFAULT_VERSION;
1332	printf("version set to default :%d\n",DEFAULT_VERSION);
1333      }
1334      else if(sscanf(w,"%d",&version) == 1){
1335	printf("%d\n",version);
1336      }
1337      break;
1338    case IS_QUERIER:
1339      printf("isquerier : ");
1340      if (EQUAL((w=(char *)next_word(&s))," ")){
1341	querier=DEFAULT_ISQUERIER;
1342	printf("is_querier set to default :%d\n",DEFAULT_ISQUERIER);
1343      }
1344      else if(sscanf(w,"%d",&querier) == 1)
1345	printf("%d\n",querier);
1346	break;
1347
1348	/* We must get upstream dynamically */
1349	/* Foxconn mark start by aspen Bai, 12/07/2007 */
1350    /* case UPSTREAM:
1351        w=(char *)next_word(&s);
1352        upstream = inet_addr(w);
1353	break;*/
1354	/* Foxconn mark end by aspen Bai, 12/07/2007 */
1355
1356    default:
1357      printf("unknown option\n");
1358
1359    }
1360  }
1361}
1362
1363int
1364main(int argc, char *argv[])
1365{
1366	struct in_addr addr;
1367	struct sockaddr_in *psin;
1368	interface_list_t *ifl, *ifp;
1369	char cmd[BUF_CMD];
1370	char *i,*group,*str1;
1371	igmp_group_t *gp;
1372	struct in_addr gr,interface;
1373	vifi_t vifi;
1374
1375	/* log_level = LOG_INFO; */
1376	log_level = LOG_DEBUG;
1377
1378	//daemon(0,0); //aspen
1379
1380	/* Initialize */
1381	signal(SIGUSR1, done);
1382	signal(SIGKILL, done);
1383	signal(SIGABRT, done);
1384	signal(SIGTERM, done);
1385	signal(SIGHUP, done);
1386	write_pid();
1387	/* parse option on config file */
1388	parse_option();
1389
1390	lan_ipaddr = inet_addr(acosNvramConfig_get("lan_ipaddr"));
1391	lan_netmask = inet_addr(acosNvramConfig_get("lan_netmask"));
1392#ifdef STATIC_PPPOE
1393	if(acosNvramConfig_match("second_wan_status", "1"))
1394		sec_wan_status = 1;
1395	else
1396		sec_wan_status = 0;
1397#endif
1398
1399	/* Create and initialize the router */
1400	igmprt_init(&router);
1401	k_init_proxy(((igmp_router_t *) &router)->igmprt_socket);
1402
1403	int numvifs = 0;
1404	/* Add all the multicast enabled ipv4 interfaces */
1405
1406	ifl = get_interface_list(AF_INET, IFF_MULTICAST, IFF_LOOPBACK);
1407	for (vifi=0,ifp=ifl;ifp;ifp=ifp->ifl_next,vifi++) {
1408		psin = (struct sockaddr_in*) &ifp->ifl_addr;
1409#ifdef STATIC_PPPOE
1410		/* foxconn modified, zacker, 07/08/2011 */
1411		if (sec_wan_status && (strcmp(ifp->ifl_name, "ppp0") == 0)
1412		       && (acosNvramConfig_match ("gui_region", "Russian")
1413		       || acosNvramConfig_match("sku_name", "RU"))
1414	           )
1415	           /* foxconn modified, zacker, 07/08/2011 */
1416	        {
1417	             printf("igmp: Skip interface %s(ppp0)\n", inet_ntoa(psin->sin_addr));
1418	             continue;
1419	        }
1420                else
1421#endif
1422		{
1423			igmprt_interface_add(&router, psin->sin_addr, ifp->ifl_name,vifi);
1424			k_proxy_add_vif(((igmp_router_t *) &router)->igmprt_socket,psin->sin_addr.s_addr,vifi);
1425			numvifs++;
1426		}
1427	}
1428
1429	free_interface_list(ifl);
1430	/* Print the status of the router */
1431	igmprt_print(&router);
1432
1433	/* Start the router */
1434	igmprt_start(&router);
1435
1436		while (go_on)
1437		{
1438		/* Read and process commands */
1439		/* Foxconn mark by aspen Bai, 01/29/2008 */
1440		/* we don't need to deal with process_cmd because gproxy runs in background */
1441		sleep(180);
1442		/*fflush(stdout);
1443		if (fgets(cmd, BUF_CMD, stdin) != NULL)
1444			go_on=process_cmd(cmd);*/
1445		} // while
1446
1447	/* Done */
1448	done(0);
1449	return 0;
1450}
1451void print_usage()
1452{
1453	printf("g adress multicast:show a group state\n");
1454	printf("s adress unicast  :show a source state\n");
1455	printf("a		  :show the IGMP table\n");
1456	printf("q		  :quit\n");
1457}
1458/* Process a command */
1459int process_cmd (cmd)
1460	char *cmd;
1461{
1462	char *line;
1463	char group[20],i[20],source[20];
1464	igmp_group_t *gp;
1465	igmp_src_t *src;
1466	struct in_addr interface,gr,srcaddr;
1467	igmp_interface_t *ifp;
1468	/* skip white spaces */
1469	line = cmd + 1;
1470	while (isblank(*line)) line ++;
1471	switch (*cmd) {
1472		case '?':
1473			print_usage();
1474			return 1;
1475		case 'q':
1476			return 0;
1477		case 'g':
1478		   /* print a group details*/
1479		   if (sscanf(line,"%s",group) != 1){
1480			printf("-1\n");
1481			return 1;
1482		   }
1483		  /* interface.s_addr=inet_addr(i);*/
1484		   gr.s_addr=inet_addr(group);
1485		   for (ifp=(&router)->igmprt_interfaces;ifp;ifp=ifp->igmpi_next){
1486	 	   	gp=igmprt_group_lookup(&router,ifp->igmpi_addr,gr);
1487			if (gp != NULL){
1488				printf("interface: %s\n",inet_ntoa(ifp->igmpi_addr));
1489	           		igmp_group_print(gp);
1490			} else
1491			   printf("unknown group\n");
1492		   }
1493	           return 1;
1494		case 's':
1495		    /* print a source of a group details*/
1496		    if (sscanf(line,"%s",source) !=1){
1497			printf("-1\n");
1498			return 1;
1499		    }
1500		    gr.s_addr=inet_addr(group);
1501		    srcaddr.s_addr=inet_addr(source);
1502		    for (ifp=(&router)->igmprt_interfaces;ifp;ifp=ifp->igmpi_next)
1503			for (gp=ifp->igmpi_groups;gp;gp=gp->igmpg_next)
1504				if ((src=igmp_group_src_lookup(gp,srcaddr)) != NULL){
1505					printf("interface : %s\n",inet_ntoa(ifp->igmpi_addr));
1506					printf("\tgroup : %s\n",inet_ntoa(gp->igmpg_addr));
1507					igmp_src_print(src);
1508				}
1509		    return 1;
1510
1511	       case 'a' :
1512		 /*print all details of the router*/
1513#ifdef IGMP_DEBUG
1514		 igmprt_print(&router);   //with this more details*/
1515#endif
1516		 igmp_info_print(&router);  /* but this more beautiful*/
1517		return 1;
1518	       default	:
1519		  printf("-1\n");
1520		  return 1;
1521               }
1522  return 1;
1523}
1524
1525
1526
1527/*
1528 * void igmp_group_cleanup()
1529 *
1530 * Cleanup a group record
1531 */
1532void
1533igmp_group_cleanup(
1534	igmp_group_t* gp)
1535{
1536	igmp_group_t *g;
1537	igmp_interface_t *ifp;
1538    igmp_router_t *pRrouter;
1539	int found=0;
1540	assert(gp != NULL);
1541	pRrouter=&router;
1542	ifp=pRrouter->igmprt_interfaces;
1543
1544	for (ifp=pRrouter->igmprt_interfaces;ifp;ifp=(igmp_interface_t *)ifp->igmpi_next){
1545    	if((NULL==ifp) || (ifp->igmpi_groups==NULL))
1546			continue;
1547
1548	  if (ifp->igmpi_groups != gp){
1549			for(g=ifp->igmpi_groups;g->igmpg_next;g=(igmp_group_t*)g->igmpg_next){
1550				if(NULL==g)
1551					return;
1552			    if((igmp_group_t *)g->igmpg_next == gp)
1553				{
1554					found=1;
1555     				break;
1556				}
1557			}
1558
1559			if(1==found)
1560			{
1561				g->igmpg_next=gp->igmpg_next;
1562				found=0;
1563			}
1564	  }else{/*delete the head*/
1565	  g=ifp->igmpi_groups;
1566	  ifp->igmpi_groups = (igmp_group_t *)g->igmpg_next;
1567
1568	  }
1569	}
1570	free(gp);
1571}
1572
1573
1574/* Foxconn add start by aspen Bai, 01/07/2008 */
1575void igmprt_clear_timer_group(igmp_interface_t *ifp)
1576{
1577    igmp_group_t *gp,*g;
1578	gp=ifp->igmpi_groups;
1579	while(gp){
1580		g=gp->igmpg_next;
1581		if( (gp->igmpg_fmode == IGMP_FMODE_EXCLUDE)&&(gp->igmpg_timer == 0))
1582		{
1583			igmp_group_cleanup(gp);
1584		}
1585		gp=g;
1586	}
1587}
1588/* Foxconn add end by aspen Bai, 01/07/2008 */
1589
1590
1591/* Foxconn add start by aspen Bai, 01/07/2008 */
1592/*
1593 * void igmp_interface_leave_group_v2()
1594 * handle a reception of leave group message
1595 *
1596 */
1597
1598void igmp_interface_leave_group_v2(
1599	igmp_router_t* router,
1600	igmp_interface_t* ifp,
1601	struct in_addr src,
1602	igmpr_t* report,
1603	int len)
1604{
1605	igmp_group_t* gp,gp1;
1606	igmp_rep_t *rep;
1607	int count=0;
1608
1609	/* Ignore a report for a non-multicast address */
1610	if (! IN_MULTICAST(ntohl(report->igmpr_group.s_addr)))
1611		return;
1612	/* Find the group, and if not present, return */
1613	if((gp = igmp_interface_group_lookup(ifp, report->igmpr_group)) == NULL)
1614		return;
1615
1616	if (!igmp_group_rep_lookup(gp, src))
1617	    return;
1618	igmp_group_rep_del(gp,src);
1619
1620	for(rep=gp->igmpg_members;rep;rep=(igmp_rep_t *)rep->igmpr_next)
1621	{
1622		if((rep->igmpr_addr.s_addr != lan_ipaddr) && ((rep->igmpr_addr.s_addr & lan_netmask)
1623			    == (lan_ipaddr & lan_netmask)))
1624			count++;
1625	}
1626	if(count == 0)
1627	{
1628		if(wan_igmp_version == IGMP_VERSION_1)
1629			return;
1630		k_proxy_del_mfc(router->igmprt_socket,mulsrc.igmps_addr.s_addr,gp->igmpg_addr.s_addr);
1631		if(wan_igmp_version == IGMP_VERSION_2)
1632			send_leave_group_v2(gp->igmpg_addr);
1633		else
1634			if(wan_igmp_version == IGMP_VERSION_3)
1635				send_membership_report_v12_to_v3(gp->igmpg_addr,CHANGE_TO_INCLUDE); /* v2 leave group is equivalent to v3 type CHANGE_TO_INCLUDE */
1636		/* send a specific query because we last leave a group */
1637		send_group_specific_query(router,ifp,gp);
1638		/* Foxconn added, zacker, 05/07/2009, @cleanup_after_leave */
1639		igmp_group_cleanup(gp);
1640	}
1641	igmp_info_print(router);
1642}
1643/* Foxconn add end by aspen Bai, 01/07/2008 */
1644
1645