1/******************************************************************************
2 * Fichier Module : proxy.c - An IGMPv3 Proxy implementation
3 ******************************************************************************
4 * Fichier    : proxy.c
5 * Description: Implementation des divers routines
6 *              Mars 2002
7 * Date       : Mars 15, 2000
8 * Auteur     : Anis.Ben-Hellel@loria.fr
9 * Last Modif : May 13, 2002
10 *
11 *****************************************************************************/
12
13#include "igmprt.h"
14
15/* Foxconn add start by aspen Bai, 12/07/2007 */
16#define IP_MSFILTER_SIZE(numsrc)  (sizeof(struct ip_msfilter) - sizeof(struct in_addr) \
17 + (numsrc) * sizeof(struct in_addr))
18/* Foxconn add start by aspen Bai, 12/07/2007 */
19
20vifi_t numvifs;
21char buffer[IP_MSFILTER_SIZE(MAX_ADDRS)];
22unsigned long upstream;
23extern int lan_index;
24extern int wan_index;
25
26
27/*
28 * set the source list and the source filter
29 * on upstream interface
30 */
31
32void set_source_filter(
33                        igmp_router_t* router,
34                        igmp_group_t* gp,
35                        unsigned long interface_adress,
36                        int fmode,
37                        int nsources,
38                        struct in_addr *sources)
39
40{
41       struct ip_msfilter *imsfp;
42       int i;
43
44       imsfp = (struct ip_msfilter *) &buffer;
45
46       if (VALID_ADDR(gp->igmpg_addr)) {
47
48         imsfp->imsf_fmode = fmode;
49         imsfp->imsf_numsrc = nsources;
50#ifdef Linux
51	 imsfp->imsf_multiaddr = gp->igmpg_addr.s_addr;
52	 imsfp->imsf_interface = interface_adress;
53#else
54         imsfp->imsf_multiaddr.s_addr =gp->igmpg_addr.s_addr;
55         imsfp->imsf_interface.s_addr = interface_adress;
56#endif
57         for (i=0; i<nsources; i++) {
58           imsfp->imsf_slist[i] = sources[i].s_addr;
59         }
60	 /*use setsockopt*/
61	 i = sizeof(*imsfp);
62
63	 /*if (setsockopt(router->igmprt_up_socket, IPPROTO_IP, IP_MSFILTER, imsfp,i) < 0 ){
64		perror("setsockopt IP_MSFILTER");
65	 }
66         if (ioctl(router->igmprt_up_socket, SIOCSIPMSFILTER, imsfp) != 0){
67           perror("ioctl - SIOCSIPMSFILTER");*/
68           //printf("ioctl error, group: %s, source: %s\n",inet_ntoa(gp->igmpg_addr.s_addr),inet_ntoa(sources[0].s_addr));
69         //}
70       }
71       return;
72}
73
74
75/*
76 * Open and init the multicast routing in the kernel.
77 */
78
79void k_init_proxy(int socket)
80{
81    int v = 1;
82
83    if (setsockopt(socket, IPPROTO_IP, MRT_INIT, (char *)&v, sizeof(int)) < 0)
84      perror("setsockopt - MRT_INIT");
85}
86
87
88
89/*
90 * Stops the multicast routing in the kernel.
91 */
92
93void k_stop_proxy(int socket)
94{
95    int v = 0;
96
97    if (setsockopt(socket, IPPROTO_IP, MRT_DONE, (char *)NULL, 0) < 0)
98      perror("setsockopt - MRT_DONE");
99}
100
101
102
103/*
104 * Add a virtual interface to the kernel
105 * using the pimd API:MRT_ADD_VIF
106 *
107 */
108
109int k_proxy_add_vif (int socket,unsigned long vifaddr,vifi_t vifi)
110{
111	struct vifctl vc;
112	int error;
113
114	vc.vifc_vifi = vifi;
115	vc.vifc_flags = 0;
116	vc.vifc_threshold = 1;
117	vc.vifc_rate_limit = 0;
118	vc.vifc_lcl_addr.s_addr = vifaddr;
119	vc.vifc_rmt_addr.s_addr = INADDR_ANY;
120
121	if (error=setsockopt(socket, IPPROTO_IP, MRT_ADD_VIF,(char *)&vc, sizeof(vc)) <0){
122	  perror("setsockopt - MRT_ADD_VIF");
123	  return FALSE;
124	}
125	return TRUE;
126}
127
128
129/*
130 * Del an MFC entry from the kernel
131 * using pimd API:MRT_DEL_MFC
132 */
133
134int k_proxy_del_mfc (int socket, u_long source, u_long group)
135{
136	struct mfcctl mc;
137	mc.mfcc_origin.s_addr   = source;
138	mc.mfcc_mcastgrp.s_addr = group;
139	mc.mfcc_parent = wan_index;   /* Foxconn add by aspen Bai, 01/07/2008 */
140
141	/* Foxconn add start by aspen Bai, 12/07/2007 */
142	/* clear the TTL vector
143     */
144    memset( mc.mfcc_ttls, 0, sizeof( mc.mfcc_ttls ) );
145    /* Foxconn add end by aspen Bai, 12/07/2007 */
146	if (setsockopt(socket, IPPROTO_IP, MRT_DEL_MFC, (char *)&mc, sizeof(mc)) <0){
147	  //perror("setsockopt - MRT_DEL_MFC");
148	  //printf("k_del_mfc:error on setsockopt\n");
149	  return FALSE;
150	}
151	return TRUE;
152}
153
154
155
156/*
157 * Install and modify a MFC entry in the kernel (S,G,interface address)
158 * using pimd API: MRT_AD_MFC
159 */
160
161int k_proxy_chg_mfc(int socket,u_long source,u_long group,vifi_t outvif,int fstate)
162{
163    struct mfcctl mc;
164    vifi_t vifi;
165
166    mc.mfcc_origin.s_addr = source;
167    mc.mfcc_mcastgrp.s_addr = group;
168    /* change me to the index of the upstream interface */
169    mc.mfcc_parent = outvif; /* Foxconn add by aspen Bai, 12/07/2007 */
170#ifndef Linux
171    mc.mfcc_oif = outvif;
172#endif
173
174    /* Foxconn add start by aspen Bai, 12/07/2007 */
175     mc.mfcc_ttls[lan_index] = fstate;
176    /* Foxconn add end by aspen Bai, 12/07/2007 */
177
178    if (setsockopt(socket, IPPROTO_IP, MRT_ADD_MFC, (char *)&mc, sizeof(mc)) < 0) {
179      perror("setsockopt - MRT_ADD_MFC");
180      return(FALSE);
181    }
182    return(TRUE);
183}
184
185/*
186 * create entry in the membership database
187 */
188
189membership_db*
190create_membership(struct in_addr group,int fmode,int numsources,struct in_addr sources[MAX_ADDRS])
191{
192        membership_db* member;
193        int i;
194        if (member = (membership_db*) malloc(sizeof(*member))) {
195                member->membership.group = group;
196                member->membership.fmode = fmode;
197                member->membership.numsources = numsources;
198                for(i=0;i<numsources;i++)
199                  member->membership.sources[i].s_addr = sources[i].s_addr;
200                member->next = NULL;
201                return member;
202        }else
203                return NULL;
204}
205
206
207/*
208 * lookup for a group entry in the membership database
209 */
210
211membership_db*
212find_membership(membership_db *membership,struct in_addr group)
213{
214  membership_db* memb;
215
216        for(memb=membership;memb;memb=memb->next)
217          if (memb->membership.group.s_addr == group.s_addr)
218            return memb;
219        return NULL;
220}
221
222/*
223 * deleate group entry from membership database
224 */
225
226membership_db*
227deleate_membership(igmp_router_t* igmprt,struct in_addr group)
228{
229       membership_db *member;
230       membership_db *memb;
231
232        member = find_membership(igmprt->igmprt_membership_db,group);
233        assert(igmprt != NULL);
234        assert(member != NULL);
235        if (igmprt->igmprt_membership_db->membership.group.s_addr != group.s_addr){
236          memb = igmprt->igmprt_membership_db;
237          while(memb->next->membership.group.s_addr != group.s_addr)
238            memb = memb->next;
239          memb->next = member->next;
240          free(member);
241        }
242        else { /*deleate the head*/
243          memb = igmprt->igmprt_membership_db;
244          igmprt->igmprt_membership_db = memb->next;
245          free(memb);
246        }
247        LOG((LOG_DEBUG, "membership database, group_cleanup: %s\n", inet_ntoa(member->membership.group.s_addr)));
248}
249
250
251
252/*
253 * find a source in a in a source list
254 */
255
256int find_source(struct in_addr sr,int nsources,struct in_addr *sources)
257{
258       int i;
259
260       for(i=0;i<nsources;i++)
261         if (sources[i].s_addr == sr.s_addr)
262           return TRUE;
263       return FALSE;
264}
265/*
266 * add multicast group to the membership database
267 */
268
269membership_db*
270update_multi(igmp_router_t *igmprt,struct in_addr group,int fmode,int nsources,struct in_addr sources[MAX_ADDRS])
271{
272
273       int i,k;
274       struct ip_msfilter *imsfp;
275       membership_db* member;
276       struct in_addr sr[MAX_ADDRS];
277
278       /*find corresponding group*/
279       if (member = find_membership(igmprt->igmprt_membership_db,group)) {
280           /*update group status using merging rules*/
281           member->membership.fmode = (int)member->membership.fmode && (int)fmode;
282           if (member->membership.fmode == IGMP_FMODE_INCLUDE) {
283                if (fmode == IGMP_FMODE_INCLUDE) {
284                     for(i=0;i<nsources;i++)
285                       if (find_source(sources[i],member->membership.numsources,member->membership.sources) == FALSE){
286                         member->membership.numsources = member->membership.numsources + 1;
287                         member->membership.sources[member->membership.numsources].s_addr = sources[i].s_addr;
288                       }
289                }
290                else{
291                     k = 0;
292                     for(i=0;i<nsources;i++)
293                         if (find_source(sources[i],member->membership.numsources,member->membership.sources) == FALSE){
294                             sr[k].s_addr = sources[i].s_addr;
295                             k = k+1;
296                         }
297                     member->membership.numsources = k;
298                     for(i=0;i<k;i++)
299                         member->membership.sources[i].s_addr = sr[i].s_addr;
300                }
301           }
302           else {
303                if (fmode == IGMP_FMODE_INCLUDE) {
304                     k = 0;
305                     for(i=0;i<member->membership.numsources;i++)
306                         if (find_source(member->membership.sources[i],nsources,sources) == FALSE){
307                             sr[k].s_addr = member->membership.sources[i].s_addr;
308                             k = k+1;
309                         }
310                     member->membership.numsources = k;
311                     for(i=0;i<k;i++)
312                       member->membership.sources[i].s_addr = sr[i].s_addr;
313                }
314                else{
315                     k = 0;
316                     for(i=0;i<member->membership.numsources;i++)
317                         if (find_source(member->membership.sources[i],nsources,sources) == TRUE){
318                             sr[k].s_addr = member->membership.sources[i].s_addr;
319                             k = k+1;
320                         }
321                     member->membership.numsources = k;
322                     for(i=0;i<k;i++)
323                       member->membership.sources[i].s_addr = sr[i].s_addr;
324                }
325           }
326           //printf("update membership database group: %s, source: %s\n",inet_ntoa(group.s_addr),inet_ntoa(member->membership.sources[0]
327       }
328       else {
329            /*create new entry in the membership database*/
330            member = create_membership(group,fmode,nsources,sources);
331            member->next = igmprt->igmprt_membership_db;
332            igmprt->igmprt_membership_db = member;
333       }
334       return member;
335}
336
337