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