1/* 2 * Copyright (c) 2012, The Linux Foundation. All rights reserved. 3 * Permission to use, copy, modify, and/or distribute this software for 4 * any purpose with or without fee is hereby granted, provided that the 5 * above copyright notice and this permission notice appear in all copies. 6 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 7 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 8 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 9 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 10 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 11 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 12 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 13 */ 14 15 16 17#include "fal_nat.h" 18#include "fal_ip.h" 19#include "hsl_api.h" 20#include "sw.h" 21#include "hsl.h" 22#include "hsl_dev.h" 23#include "hsl_port_prop.h" 24#include "isisc_igmp.h" 25#include "isisc_reg.h" 26#include "isisc_acl.h" 27#include "fal_multi.h" 28#include "hsl_shared_api.h" 29#include "sal/os/aos_lock.h" 30 31#if 0 32/** 33 * I/F prototype for complete igmpv3 & mldv2 support 34 */ 35 36/*supports 32 entries*/ 37#define FAL_IGMP_SG_ENTRY_MAX 32 38 39typedef enum 40{ 41 FAL_ADDR_IPV4 = 0, 42 FAL_ADDR_IPV6 43} fal_addr_type_t; 44 45typedef struct 46{ 47 fal_addr_type_t type; 48 union 49 { 50 fal_ip4_addr_t ip4_addr; 51 fal_ip6_addr_t ip6_addr; 52 } u; 53} fal_igmp_sg_addr_t; 54 55typedef struct 56{ 57 fal_igmp_sg_addr_t source; 58 fal_igmp_sg_addr_t group; 59 fal_pbmp_t port_map; 60} fal_igmp_sg_entry_t; 61 62/** 63 * @brief set PortMap of IGMP sg entry. 64 * search entry according to source/group address, 65 * update PortMap if SG entry is found, otherwise create a new sg entry. 66 * @param[in] dev_id device id 67 * @param[in-out] entry SG entry 68 * @return SW_OK or error code 69 */ 70HSL_LOCAL sw_error_t 71isisc_igmp_sg_entry_set(a_uint32_t dev_id, fal_igmp_sg_entry_t * entry); 72 73/** 74 * @brief clear PortMap of IGMP sg entry. 75 * search entry according to source/group address, 76 * update PortMap if SG entry is found, delete the entry in case PortMap was 0. 77 * SW_NOT_FOUND will be returned in case search failed. 78 * @param[in] dev_id device id 79 * @param[in-out] entry SG entry 80 * @return SW_OK or error code 81 */ 82HSL_LOCAL sw_error_t 83isisc_igmp_sg_entry_clear(a_uint32_t dev_id, fal_igmp_sg_entry_t * entry); 84 85#define MULTI_DEBUG_ 86#ifdef MULTI_DEBUG_ 87#define MULTI_DEBUG(x...) aos_printk(x) 88#else 89#define MULTI_DEBUG(x...) 90#endif 91 92#define FAL_ACL_LIST_MULTICAST 55 93#define FAL_MULTICAST_PRI 5 94 95#define MULT_ACTION_SET 1 96#define MULT_ACTION_CLEAR 1 97 98static a_uint32_t rule_nr=1; 99 100typedef struct 101{ 102 a_uint8_t index; //MAX is 32 103 fal_igmp_sg_entry_t entry; //Stores the specific ACL rule info 104} multi_acl_info_t; 105#endif 106 107static a_uint32_t mul_rule_nr=1; 108 109void 110isisc_multicast_init(a_uint32_t dev_id); 111 112HSL_LOCAL sw_error_t multi_portmap_aclreg_set(a_uint32_t pos, fal_igmp_sg_entry_t * entry); 113 114static multi_acl_info_t multi_acl_info[FAL_IGMP_SG_ENTRY_MAX]; 115static multi_acl_info_t multi_acl_group[FAL_IGMP_SG_ENTRY_MAX]; 116 117static int ip6_addr_is_null(fal_ip6_addr_t *ip6) 118{ 119 if (NULL == ip6) 120 { 121 aos_printk("Invalid ip6 address\n"); 122 return -1; 123 } 124 if(0 == ip6->ul[0] && 0 == ip6->ul[1] && 0 == ip6->ul[2] && 0 == ip6->ul[3]) 125 return 1; 126 else 127 return 0; 128} 129static int multi_source_is_null(fal_igmp_sg_addr_t *s) 130{ 131 if (NULL == s) 132 { 133 aos_printk("Invalid source address\n"); 134 return -1; 135 } 136 if(0 == s->type && 0==s->u.ip4_addr) 137 return 1; 138 if(1 == s->type && 1 == ip6_addr_is_null(&(s->u.ip6_addr))) 139 return 1; 140 141 return 0; 142} 143 144HSL_LOCAL int iterate_multicast_acl_rule(int list_id, int start_n) 145{ 146 a_uint32_t dev_id=0; 147 a_uint32_t rule_id; 148 sw_error_t ret; 149 fal_acl_rule_t rule= {0}; 150 151 if(start_n>=FAL_IGMP_SG_ENTRY_MAX) 152 { 153 return -1; 154 } 155 156 for(rule_id=0; rule_id<FAL_IGMP_SG_ENTRY_MAX; rule_id++) 157 { 158 ret = ACL_RULE_QUERY(dev_id, list_id, rule_id, &rule); 159 160 if (ret==SW_NOT_FOUND ) 161 break;//NOT found in ACL rule 162 if((rule_id+start_n)>=FAL_IGMP_SG_ENTRY_MAX) 163 { 164 return -1; 165 } 166 167 multi_acl_info[rule_id+start_n].index = rule_id; // consider here... index is NOT related start_n 168 //MULTI_DEBUG("normal query1: rule dest_ip4_val=%x, src ip4=%x, dst_ip6=%x, ports=%x\n", 169 //rule.dest_ip4_val, rule.src_ip4_val, rule.dest_ip6_val.ul[0], rule.ports); 170 171 if(rule.dest_ip4_val !=0 && ip6_addr_is_null(&rule.dest_ip6_val)) //only ip4 172 { 173 multi_acl_info[rule_id+start_n].entry.group.type = FAL_ADDR_IPV4; 174 multi_acl_info[rule_id+start_n].entry.source.type = FAL_ADDR_IPV4; 175 multi_acl_info[rule_id+start_n].entry.group.u.ip4_addr = rule.dest_ip4_val; 176 multi_acl_info[rule_id+start_n].entry.source.u.ip4_addr = rule.src_ip4_val; 177 multi_acl_info[rule_id+start_n].entry.port_map= rule.ports; 178 } 179 else if(rule.dest_ip4_val ==0 && !ip6_addr_is_null(&rule.dest_ip6_val)) //only ip6 180 { 181 multi_acl_info[rule_id+start_n].entry.group.type = FAL_ADDR_IPV6; 182 multi_acl_info[rule_id+start_n].entry.source.type = FAL_ADDR_IPV6; 183 memcpy(&(multi_acl_info[rule_id+start_n].entry.group.u.ip6_addr), &(rule.dest_ip6_val), sizeof(rule.dest_ip6_val)); 184 memcpy(&(multi_acl_info[rule_id+start_n].entry.source.u.ip6_addr), &(rule.src_ip6_val), sizeof(rule.src_ip6_val)); 185 multi_acl_info[rule_id+start_n].entry.port_map= rule.ports; 186 } 187 if (FAL_FIELD_FLG_TST(rule.field_flg, FAL_ACL_FIELD_MAC_VID)) 188 { 189 multi_acl_info[rule_id+start_n].entry.vlan_id = rule.vid_val; 190 } 191 else 192 { 193 multi_acl_info[rule_id+start_n].entry.vlan_id = 0xffff; 194 } 195 } 196 197 return rule_id+start_n; 198} 199/* 200** Iterate the total 32 multicast ACL entries. 201 After the function completes: 202 1. Stores all multicast related ACL rules in multi_acl_info[32] 203 2. return the number of multicast related ACL rules 204*/ 205HSL_LOCAL a_uint32_t isisc_multicast_acl_query(void) 206{ 207 int start_n; 208 int total_n; 209 //a_uint32_t i; 210 211 start_n = iterate_multicast_acl_rule(FAL_ACL_LIST_MULTICAST, 0); 212 if(-1 == start_n) 213 aos_printk("ACL rule1 is FULL\n"); 214 total_n = iterate_multicast_acl_rule(FAL_ACL_LIST_MULTICAST+1, start_n); 215 if(-1 == total_n) 216 aos_printk("ACL rule2 is FULL\n"); 217 218 MULTI_DEBUG("KKK, the total ACL rule number is %d, (G,S) number=%d\n", total_n, start_n); 219 /* 220 for(i=0;i<total_n;i++) 221 MULTI_DEBUG("KKK, indx=%d, multi_acl_info[%d].entry=[%d][%x]\n", multi_acl_info[i].index,i, 222 multi_acl_info[i].entry.group.type, multi_acl_info[i].entry.group.u.ip4_addr ); 223 */ 224 225 return total_n; 226} 227 228HSL_LOCAL a_uint32_t isisc_multicast_acl_total_n(a_uint32_t list_id) 229{ 230 a_uint32_t dev_id=0; 231 a_uint32_t ret; 232 a_uint32_t rule_id; 233 fal_acl_rule_t rule= {0}; 234 235 for(rule_id=0; rule_id<FAL_IGMP_SG_ENTRY_MAX; rule_id++) 236 { 237 ret = ACL_RULE_QUERY(dev_id, list_id, 238 rule_id, &rule); 239 if(ret==SW_NOT_FOUND) 240 return rule_id; 241 242 } 243 return 0; 244} 245 246HSL_LOCAL a_uint32_t isisc_acl_multigroup_cmp(fal_igmp_sg_addr_t *group, fal_acl_rule_t* rule) 247{ 248 if(group->type == FAL_ADDR_IPV4) 249 return memcmp(&group->u.ip4_addr, &rule->dest_ip4_val, sizeof(rule->dest_ip4_val)); 250 else if(group->type == FAL_ADDR_IPV6) 251 return memcmp(group->u.ip6_addr.ul, rule->dest_ip6_val.ul, sizeof(rule->dest_ip6_val)); 252 253 return -1; 254} 255 256 257#define ISISC_FILTER_ACT_ADDR 0x5a000 258#define ISISC_FILTER_MSK_ADDR 0x59000 259HSL_LOCAL sw_error_t multi_portmap_aclreg_set_all(a_uint32_t pos, fal_igmp_sg_entry_t * entry) 260{ 261 a_uint32_t i, base, addr; 262 a_uint32_t dev_id=0; 263 a_uint32_t msk_valid=0; 264 sw_error_t rv; 265 266 /* 2'b00:start; 2'b01:continue; 2'b10:end; 2'b11:start&end*/ 267 for(i=pos; i<pos+4; i++) 268 { 269 base = ISISC_FILTER_MSK_ADDR +(i<<5); 270 addr = base+(4<<2); //fifth byte 271 HSL_REG_ENTRY_GEN_GET(rv, dev_id, addr, sizeof (a_uint32_t), 272 (a_uint8_t *) (&msk_valid), 273 sizeof (a_uint32_t)); 274 275 SW_RTN_ON_ERROR(rv); 276 if ((((msk_valid>>6)&0x3) == 0x3) || (((msk_valid>>6)&0x3) == 0x2)) 277 { 278 rv = multi_portmap_aclreg_set(i, entry); 279 break; 280 } 281 else if ((((msk_valid>>6)&0x3)) == 0x0 || (((msk_valid>>6)&0x3) == 0x1)) 282 { 283 rv = multi_portmap_aclreg_set(i, entry); 284 continue; 285 } 286 else 287 { 288 aos_printk("The rule valid bit:6 7 is wrong!!!"); 289 break; 290 } 291 } 292 return rv; 293} 294HSL_LOCAL sw_error_t multi_portmap_aclreg_set(a_uint32_t pos, fal_igmp_sg_entry_t * entry) 295{ 296 a_uint32_t i, base, addr; 297 a_uint32_t dev_id=0; 298 sw_error_t rv; 299 a_uint32_t act[3]= {0}; 300 fal_pbmp_t pm; 301 302 pm = entry->port_map; 303 304 base = ISISC_FILTER_ACT_ADDR + (pos << 4); 305 for (i = 0; i < 3; i++) 306 { 307 addr = base + (i << 2); 308 HSL_REG_ENTRY_GEN_GET(rv, dev_id, addr, sizeof (a_uint32_t), 309 (a_uint8_t *) (&act[i]), 310 sizeof (a_uint32_t)); 311 //MULTI_DEBUG("2:Get register value 0x%x =%x\n", addr, act[i]); 312 SW_RTN_ON_ERROR(rv); 313 } 314 315 act[1] &= ~(0x7<<29); // clear the high 3 bits 316 act[1] |= (pm&0x7)<<29; //the low 3 bits of pm means redirect port 0,1,2 317 318 /* New modification: update acl ACTION register from DENY to redirect */ 319 if((act[2]>>6)&0x7 == 0x7 ) //DENY mode 320 { 321 if(pm) 322 { 323 act[2] &= ~(0x7<<6);//clear DENY bits 324 act[2] |= (0x1<<4); //DES_PORT_EN set 1, enable 325 } 326 } 327 else if((act[2]>>4)&0x1 == 0x1) //redirect mode 328 { 329 if(pm==0) 330 { 331 act[2] &= ~(0x1<<4);//clear redirect bits 332 act[2] |= (0x7<<6); //set to DENY 333 } 334 } 335 336 act[2] &= ~0xf; //clear the low 4 bits of port 3,4,5,6 337 act[2] |= (pm>>3)&0xf; 338 339 addr = base + (1<<2); 340 HSL_REG_ENTRY_GEN_SET(rv, dev_id, addr, sizeof (a_uint32_t), 341 (a_uint8_t *) (&act[1]), sizeof (a_uint32_t)); 342 addr = base + (2<<2); 343 HSL_REG_ENTRY_GEN_SET(rv, dev_id, addr, sizeof (a_uint32_t), 344 (a_uint8_t *) (&act[2]), sizeof (a_uint32_t)); 345 MULTI_DEBUG("pos=%d, before sync portmap, the new act=%x %x\n", pos, act[1],act[2]); 346 if((rv = ACL_RULE_SYNC_MULTI_PORTMAP(dev_id, pos, act)) < 0) 347 aos_printk("Sync multicast portmap error\n"); 348 return rv; 349} 350 351HSL_LOCAL int multi_get_dp() 352{ 353 a_uint32_t addr; 354 a_uint32_t dev_id=0; 355 sw_error_t rv; 356 int val=0; 357 358 addr = 0x624;//GLOBAL_FW_CTRL1 359 HSL_REG_ENTRY_GEN_GET(rv, dev_id, addr, sizeof (a_uint32_t), 360 (a_uint8_t *) (&val), 361 sizeof (a_uint32_t)); 362 val = (val>>24)&0x7f; //30:24, IGMP_JOIN_LEAVE_DP 363 364 return val; 365} 366static int old_bind_p=-1; 367HSL_LOCAL int multi_acl_bind() 368{ 369 int bind_p; 370 int i; 371 372 bind_p = multi_get_dp(); 373 if(bind_p == old_bind_p) 374 return 0; 375 old_bind_p = bind_p; 376 377 for(i=0; i<7; i++) 378 { 379 ACL_LIST_UNBIND(0, FAL_ACL_LIST_MULTICAST, FAL_ACL_DIREC_IN, FAL_ACL_BIND_PORT, i); 380 ACL_LIST_UNBIND(0, FAL_ACL_LIST_MULTICAST+1, FAL_ACL_DIREC_IN, FAL_ACL_BIND_PORT, i); 381 } 382 383 if(bind_p==0) 384 { 385 for(i=0; i<7; i++) 386 { 387 ACL_LIST_BIND(0, FAL_ACL_LIST_MULTICAST, FAL_ACL_DIREC_IN, FAL_ACL_BIND_PORT, i); 388 ACL_LIST_BIND(0, FAL_ACL_LIST_MULTICAST+1, FAL_ACL_DIREC_IN, FAL_ACL_BIND_PORT, i); 389 } 390 } 391 else 392 { 393 for(i=0; i<7; i++) 394 if((bind_p>>i) &0x1) 395 { 396 ACL_LIST_BIND(0, FAL_ACL_LIST_MULTICAST, FAL_ACL_DIREC_IN, FAL_ACL_BIND_PORT, i); 397 ACL_LIST_BIND(0, FAL_ACL_LIST_MULTICAST+1, FAL_ACL_DIREC_IN, FAL_ACL_BIND_PORT, i); 398 } 399 else 400 continue; 401 } 402} 403/* 404** Only update the related portmap from the privious input. 405*/ 406HSL_LOCAL sw_error_t isisc_multicast_acl_update( int list_id, int acl_index, fal_igmp_sg_entry_t * entry, int action) 407{ 408 a_uint32_t dev_id=0; 409 //a_uint32_t list_pos; 410 a_uint32_t rule_pos; 411 a_uint32_t list_pri; 412 sw_error_t rv; 413 414 //if(entry->port_map < 1 || acl_index<0) 415 if(acl_index<0) 416 aos_printk("Something is wrong...\n"); 417 418 if(list_id == FAL_ACL_LIST_MULTICAST) //Update all matched group based acl_rule->source 419 list_pri=FAL_MULTICAST_PRI; 420 else if(list_id == FAL_ACL_LIST_MULTICAST+1) //only update the specific (G,*)entry 421 list_pri=FAL_MULTICAST_PRI+1; 422 423 424 //list_pos = isisc_acl_rule_get_pos(dev_id, list_id, list_pri); 425 rule_pos = ACL_RULE_GET_OFFSET(dev_id, list_id, multi_acl_group[acl_index].index); 426 if(MULT_ACTION_SET == action) 427 { 428 multi_acl_group[acl_index].entry.port_map |= entry->port_map; 429 if(entry->port_map == 0) 430 { 431 multi_acl_group[acl_index].entry.port_map = 0; 432 } 433 } 434 else if(MULT_ACTION_CLEAR == action) 435 multi_acl_group[acl_index].entry.port_map &= ~(entry->port_map); 436 437 rv = multi_portmap_aclreg_set_all(rule_pos, &multi_acl_group[acl_index].entry); 438 439 multi_acl_bind(); //Here need extra bind since IGMP join/leave would happen 440 return rv; 441} 442 443HSL_LOCAL sw_error_t sw_multicast_acl_update( int list_id, int acl_index, fal_igmp_sg_entry_t * entry, int action) 444{ 445 a_uint32_t dev_id=0; 446 a_uint32_t rule_pos; 447 a_uint32_t list_pri; 448 449 if(list_id == FAL_ACL_LIST_MULTICAST) //Update all matched group based acl_rule->source 450 list_pri=FAL_MULTICAST_PRI; 451 else if(list_id == FAL_ACL_LIST_MULTICAST+1) //only update the specific (G,*)entry 452 list_pri=FAL_MULTICAST_PRI+1; 453 454 rule_pos = ACL_RULE_GET_OFFSET(dev_id, list_id, multi_acl_group[acl_index].index); 455 456 MULTI_DEBUG("SW update: rule_pos=%d, index=%d, old portmap=%x\n", 457 rule_pos, acl_index, multi_acl_group[acl_index].entry.port_map); 458 if(MULT_ACTION_SET == action) 459 entry->port_map |= multi_acl_group[acl_index].entry.port_map; 460 else if(MULT_ACTION_CLEAR == action) 461 entry->port_map &= ~multi_acl_group[acl_index].entry.port_map; 462 463 return SW_OK; 464} 465 466 467HSL_LOCAL sw_error_t isisc_multicast_acl_del(int list_id, int index) 468{ 469 sw_error_t rv; 470 int rule_id; 471 472 rule_id = multi_acl_group[index].index; 473 474 rv = ACL_RULE_DEL(0, list_id, rule_id, 1); 475 multi_acl_bind(); //Here need extra bind since IGMP join/leave would happen 476} 477 478/* 479** Add new acl rule with parameters: DIP, SIP, redirect port. 480*/ 481HSL_LOCAL sw_error_t isisc_multicast_acl_add(int list_id, fal_igmp_sg_entry_t * entry) 482{ 483 sw_error_t val; 484 a_uint32_t pos; 485 fal_acl_rule_t acl= {0}; 486 487 /* IPv4 multicast */ 488 if( entry->group.type == FAL_ADDR_IPV4 ) 489 { 490 MULTI_DEBUG("KKK1, group[%d][%x], source[%d][%x]\n",entry->group.type, 491 entry->group.u.ip4_addr, entry->source.type, entry->source.u.ip4_addr); 492 493 acl.rule_type = FAL_ACL_RULE_IP4; 494 495 if(entry->group.u.ip4_addr!= 0) 496 { 497 acl.dest_ip4_val = entry->group.u.ip4_addr; 498 acl.dest_ip4_mask = 0xffffffff;//e->ip.dmsk.s_addr; 499 FAL_FIELD_FLG_SET(acl.field_flg, FAL_ACL_FIELD_IP4_DIP); 500 } 501 if(entry->source.u.ip4_addr!= 0) 502 { 503 acl.src_ip4_val = entry->source.u.ip4_addr; 504 acl.src_ip4_mask = 0xffffffff;//e->ip.smsk.s_addr; 505 FAL_FIELD_FLG_SET(acl.field_flg, FAL_ACL_FIELD_IP4_SIP); 506 } 507 if( entry->port_map==0 ) 508 FAL_ACTION_FLG_SET ( acl.action_flg, FAL_ACL_ACTION_DENY); 509 else 510 //FAL_FIELD_FLG_SET(acl.field_flg, FAL_ACL_FIELD_INVERSE_ALL); 511 FAL_ACTION_FLG_SET ( acl.action_flg, FAL_ACL_ACTION_PERMIT ); 512 513 /* Be careful, _isisc_acl_action_parse() will block FAL_ACL_ACTION_DENY action, So we change it. */ 514 if( entry->port_map ) 515 { 516 FAL_ACTION_FLG_SET(acl.action_flg, FAL_ACL_ACTION_REDPT); 517 acl.ports = entry->port_map; 518 } 519 } 520 else if( entry->group.type == FAL_ADDR_IPV6 ) 521 { 522 MULTI_DEBUG("KKK2, group[%d][%x], source[%d][%x], pm=%x\n",entry->group.type, 523 entry->group.u.ip6_addr.ul[0], entry->source.type, entry->source.u.ip6_addr.ul[0], entry->port_map); 524 525 acl.rule_type = FAL_ACL_RULE_IP6; 526 527 if(!ip6_addr_is_null(&(entry->group.u.ip6_addr))) 528 { 529 memcpy(&acl.dest_ip6_val, &(entry->group.u.ip6_addr), sizeof(entry->group.u.ip6_addr)); 530 acl.dest_ip6_mask.ul[0] = 0xffffffff; 531 acl.dest_ip6_mask.ul[1] = 0xffffffff; 532 acl.dest_ip6_mask.ul[2] = 0xffffffff; 533 acl.dest_ip6_mask.ul[3] = 0xffffffff; 534 FAL_FIELD_FLG_SET(acl.field_flg, FAL_ACL_FIELD_IP6_DIP); 535 } 536 if(!ip6_addr_is_null(&(entry->source.u.ip6_addr))) 537 { 538 memcpy(&acl.src_ip6_val, &(entry->source.u.ip6_addr), sizeof(entry->source.u.ip6_addr)); 539 acl.src_ip6_mask.ul[0] = 0xffffffff; 540 acl.src_ip6_mask.ul[1] = 0xffffffff; 541 acl.src_ip6_mask.ul[2] = 0xffffffff; 542 acl.src_ip6_mask.ul[3] = 0xffffffff; 543 FAL_FIELD_FLG_SET(acl.field_flg, FAL_ACL_FIELD_IP6_SIP); 544 } 545 546 if( entry->port_map==0 ) 547 FAL_ACTION_FLG_SET ( acl.action_flg, FAL_ACL_ACTION_DENY); 548 else 549 //FAL_FIELD_FLG_SET(acl.field_flg, FAL_ACL_FIELD_INVERSE_ALL); 550 FAL_ACTION_FLG_SET ( acl.action_flg, FAL_ACL_ACTION_PERMIT ); 551 552 /* Be careful, _isisc_acl_action_parse() will block FAL_ACL_ACTION_DENY action, So we change it. */ 553 if( entry->port_map ) 554 { 555 FAL_ACTION_FLG_SET(acl.action_flg, FAL_ACL_ACTION_REDPT); 556 acl.ports = entry->port_map; 557 } 558 } 559 560 if (entry->vlan_id < 4096) 561 { 562 FAL_FIELD_FLG_SET(acl.field_flg, FAL_ACL_FIELD_MAC_VID); 563 acl.vid_val = entry->vlan_id; 564 acl.vid_op = FAL_ACL_FIELD_MASK; 565 acl.vid_mask = 0xfff; 566 } 567 568 pos = isisc_multicast_acl_total_n(list_id); 569 570 MULTI_DEBUG("In isisc_multicast_acl_add, list_id=%d, rule_id=%d\n", list_id, pos); 571 val = ACL_RULE_ADD(0, list_id, pos, mul_rule_nr, &acl); 572 573 multi_acl_bind(); 574 575 return val; 576} 577 578 579HSL_LOCAL int iterate_multicast_acl_group(a_uint32_t number, fal_igmp_sg_entry_t * entry) 580{ 581 int count=0; 582 int i; 583 584 if (number == 0) 585 return 0; //no any ACL rules based the query 586 587 for(i=0; i<number; i++) 588 { 589 590 /*MULTI_DEBUG("2:iterate_multicast_acl_group, index=%d, multi_acl_info[%d].entry=type[%d]-addr[%x], pm=%x, new entry=type[%d]-addr[%x], pm=%x\n", 591 multi_acl_info[i].index,i, multi_acl_info[i].entry.group.type, multi_acl_info[i].entry.group.u.ip6_addr.ul[0], multi_acl_info[i].entry.port_map, 592 entry->group.type, entry->group.u.ip6_addr.ul[0], entry->port_map);*/ 593 594 if(0 == memcmp(&(multi_acl_info[i].entry.group), &(entry->group), sizeof(entry->group))) 595 { 596 memcpy(&multi_acl_group[count], &multi_acl_info[i], sizeof(multi_acl_info[i])); 597 count++;//return the real number of multi_acl_group[] 598 MULTI_DEBUG("in iterate_multicast_acl_group, count=%d, i=%d\n", count, i); 599 } 600 } 601 602 return count; 603} 604 605HSL_LOCAL int mult_acl_has_entry(fal_igmp_sg_addr_t * group, fal_igmp_sg_addr_t *source) 606{ 607 int rule_id; 608 int ret = 0; 609#if 0 610 if(source != NULL) 611 { 612 MULTI_DEBUG("new group[%d]= %x %x %x %x, new source[%d]=%x %x %x %x\n", 613 group->type, group->u.ip6_addr.ul[0], group->u.ip6_addr.ul[1], group->u.ip6_addr.ul[2], group->u.ip6_addr.ul[3], 614 source->type, source->u.ip6_addr.ul[0], source->u.ip6_addr.ul[1], source->u.ip6_addr.ul[2], source->u.ip6_addr.ul[3]); 615 616 MULTI_DEBUG("old group[%d]= %x %x %x %x, old source[%d]=%x %x %x %x\n", 617 multi_acl_group[0].entry.group.type, multi_acl_group[0].entry.group.u.ip6_addr.ul[0], 618 multi_acl_group[0].entry.group.u.ip6_addr.ul[1], multi_acl_group[0].entry.group.u.ip6_addr.ul[2], multi_acl_group[0].entry.group.u.ip6_addr.ul[3], 619 multi_acl_group[0].entry.source.type, multi_acl_group[0].entry.source.u.ip6_addr.ul[0], 620 multi_acl_group[0].entry.source.u.ip6_addr.ul[1], multi_acl_group[0].entry.source.u.ip6_addr.ul[2], multi_acl_group[0].entry.source.u.ip6_addr.ul[3]); 621 } 622#endif 623 if(source == NULL) 624 { 625 for(rule_id=0; rule_id<FAL_IGMP_SG_ENTRY_MAX; rule_id++) 626 { 627 if( (0==memcmp(&multi_acl_group[rule_id].entry.group, group, sizeof(fal_igmp_sg_addr_t))) && 628 (multi_source_is_null(&multi_acl_group[rule_id].entry.source))) 629 { 630 MULTI_DEBUG("Source=0:Orignal ACL rule have this entry! rule id= %d\n", rule_id); 631 ret = rule_id+1; // ensure the return value is the actually number of entry 632 break; 633 } 634 } 635 } 636 else 637 { 638 for(rule_id=0; rule_id<FAL_IGMP_SG_ENTRY_MAX; rule_id++) 639 { 640 if( (0==memcmp(&multi_acl_group[rule_id].entry.group, group, sizeof(fal_igmp_sg_addr_t))) && 641 (0==memcmp(&multi_acl_group[rule_id].entry.source, source, sizeof(fal_igmp_sg_addr_t)))) 642 { 643 MULTI_DEBUG("Orignal ACL rule have this entry! rule id= %d\n", rule_id); 644 ret = rule_id+1; // ensure the return value is the actually number of entry 645 break; 646 } 647 } 648 } 649 650 return ret; 651} 652HSL_LOCAL int portmap_null(int index, fal_pbmp_t portmap) 653{ 654 int val; 655 if (index<0) 656 aos_printk("portmap_null, index error\n"); 657 658 val = multi_acl_group[index].entry.port_map&(~portmap); 659 660 if( 0 == (val&0xff) ) 661 return 1; 662 else 663 return 0; 664} 665 666HSL_LOCAL int portmap_valid(fal_igmp_sg_entry_t *g_source, fal_igmp_sg_entry_t *g_star) 667{ 668 /* return 0 means the portmap is Not valid 669 return 1 means the protmap is valid 670 */ 671 /* MULTI_DEBUG("portmap_valid:g_source portmap=%x, source=%x,group=%x, g_star portmap=%x, source=%x, group=%x\n", 672 g_source->port_map, g_source->source.u.ip4_addr, g_source->group.u.ip4_addr, 673 g_star->port_map, g_star->source.u.ip4_addr,g_star->group.u.ip4_addr);*/ 674 675 if(multi_source_is_null(&(g_star->source))) 676 { 677 if((g_source->port_map|g_star->port_map) == g_star->port_map) 678 { 679 return 0; 680 } 681 } 682 683 return 1; 684} 685 686 687HSL_LOCAL int portmap_clear_type(int count, int index, fal_pbmp_t portmap) 688{ 689 if(count>=0 && index<count) //new_index must >0; this means there're (G,*) and (G,S) 690 { 691 //if the new clear portmap will cause (G,S)=(G,*), Delete the (G,S) 692 if((multi_acl_group[index].entry.port_map & (~portmap)) == multi_acl_group[count].entry.port_map) 693 return 1; //delete 694 695 696 //The following means there must be at least one bit clear wrong. Clear the (G,*) portmap. 697 if( ((multi_acl_group[index].entry.port_map & (~portmap)) & (multi_acl_group[count].entry.port_map)) 698 != (multi_acl_group[count].entry.port_map)) 699 return 0; 700 701 return 2; //Normal update 702 } 703 ; 704} 705sw_error_t isisc_igmp_sg_entry_set(a_uint32_t dev_id, fal_igmp_sg_entry_t * entry) 706{ 707 HSL_API_LOCK; 708 int number, count; 709 int new_index=0; 710 int tmp_index=0; 711 sw_error_t rv; 712 int action = MULT_ACTION_SET; 713 fal_igmp_sg_entry_t tmp_entry[1]= {}; 714 int i=0; 715 716 (void)isisc_multicast_init(0); 717 aos_mem_zero(multi_acl_info, FAL_IGMP_SG_ENTRY_MAX * sizeof (multi_acl_info_t)); 718 aos_mem_zero(multi_acl_group, FAL_IGMP_SG_ENTRY_MAX * sizeof (multi_acl_info_t)); 719 MULTI_DEBUG("Before query: group=%x, source=%x, portmap=%x\n", entry->group.u.ip4_addr, entry->source.u.ip4_addr, entry->port_map); 720 //number is the total multicast ACL rules amount, stores in multi_acl_info[]; 721 number = isisc_multicast_acl_query(); 722 //count the total specific multicast group ACL rules, stores in multi_acl_group[]; count <=number 723 count = iterate_multicast_acl_group(number, entry); 724 //new_index-1 is the found entry index in multi_acl_group[], the real index is [new_index-1], 0 means no entry 725 new_index = mult_acl_has_entry(&entry->group, &entry->source); 726 727 MULTI_DEBUG("Start entry set: number=%d, count=%d, new_index=%d, pm=%x\n", number, count, new_index, entry->port_map); 728 if( 0==multi_source_is_null(&entry->source) ) // new entry is (G, S) 729 { 730 MULTI_DEBUG("the new entry is (G,S)\n"); 731 if(count>0 && 0 == portmap_valid(entry, &(multi_acl_group[count-1].entry))) //specfic group entry exist,(G,S) or (G,*) 732 { 733 //return SW_NO_CHANGE; // The new portmap is Not valid 734 MULTI_DEBUG("KKK, modified 1 !!!\n"); 735 } 736 737 if(0 == new_index) //new entry, need add 738 { 739#if 0 740 /*The method: 741 1. predict if the portmap should be modified. 742 2. add new acl rule with new portmap value. 743 */ 744 if((tmp_index = mult_acl_has_entry(&entry->group, NULL))>0) // (G, *) entry exist 745 { 746 /*Here the update should new (G, S) OR orignal (G,*) portmap, 747 be careful, entry's portmap value will be modified, so I use tmp_entry. 748 */ 749 memcpy(tmp_entry, entry, sizeof(fal_igmp_sg_entry_t)); 750 MULTI_DEBUG("Here, (G,*) exist! tmp_index=%d\n", tmp_index); 751 sw_multicast_acl_update(FAL_ACL_LIST_MULTICAST+1, tmp_index-1, tmp_entry, action); 752 753 isisc_multicast_acl_add(FAL_ACL_LIST_MULTICAST, tmp_entry); 754 return SW_OK; 755 } 756#endif 757 isisc_multicast_acl_add(FAL_ACL_LIST_MULTICAST, entry); 758 MULTI_DEBUG("Here, need add (G, S), portmap=%x\n", entry->port_map); 759 return SW_OK; 760 } 761 else 762 { 763 //Here update Just: the old exist entry portmap OR the new entry portmap 764 isisc_multicast_acl_update(FAL_ACL_LIST_MULTICAST, new_index-1, entry, action); 765 return SW_OK; 766 } 767 } //end of memcmp 768 else // new entry is (G, *) 769 { 770 if(0 == new_index) //new entry, need add 771 { 772 isisc_multicast_acl_add(FAL_ACL_LIST_MULTICAST+1, entry); 773 rv = SW_OK; 774 } 775 else if(new_index > 0) // (G, *) entry exist? 776 { 777 //Update exist (G, *) portmap with new portmap 778 MULTI_DEBUG("(G,*) exist, before update, new_index=%d\n", new_index ); 779 isisc_multicast_acl_update(FAL_ACL_LIST_MULTICAST+1, new_index-1, entry, action); 780 rv = SW_OK; 781 } 782 783 if(new_index>0&&count>1) //(G,S*) and (G,*) exist, new entry is (G,*) 784 { 785 for(i=count-2; i>=0; i--) 786 { 787 if(multi_acl_group[i].entry.port_map==0) //This ACL rule should be done nothing, DENY rule 788 continue; 789 790 if(0 == portmap_valid(&(multi_acl_group[i].entry), &(multi_acl_group[count-1].entry))) 791 { 792 MULTI_DEBUG("1:portmap is not valid, should delete, i=%d, source portmap=%x, gstar pm=%x\n", 793 i, multi_acl_group[i].entry.port_map, multi_acl_group[count-1].entry.port_map); 794 isisc_multicast_acl_del(FAL_ACL_LIST_MULTICAST, i); 795 rv = SW_NO_MORE; 796 } 797 else 798 { 799 MULTI_DEBUG("1:Start update all (G,S),i=%d, gstar portmap=%x\n", i, multi_acl_group[count-1].entry.port_map); 800 //Update all (G,S) entry portmap with new(G, *) portmap 801 isisc_multicast_acl_update(FAL_ACL_LIST_MULTICAST, i, entry, action); 802 rv = SW_OK; 803 } 804 } 805 } 806 else if(new_index==0&&count>0) //only exist (G,S*) orignally 807 { 808 for(i=count-1; i>=0; i--) 809 { 810 if(multi_acl_group[i].entry.port_map==0) //This ACL rule should be done nothing, DENY rule 811 continue; 812 813 if(0 == portmap_valid(&(multi_acl_group[i].entry), entry)) 814 { 815 MULTI_DEBUG("2:portmap is not valid, should delete, i=%d, source portmap=%x, gstar pm=%x\n", 816 i, multi_acl_group[i].entry.port_map, entry->port_map); 817 isisc_multicast_acl_del(FAL_ACL_LIST_MULTICAST, i); 818 rv = SW_NO_MORE; 819 } 820 else 821 { 822 MULTI_DEBUG("2:Start update all (G,S),i=%d, portmap=%x\n", i, entry->port_map); 823 //Update all (G,S) entry portmap with new(G, *) portmap 824 isisc_multicast_acl_update(FAL_ACL_LIST_MULTICAST, i, entry, action); 825 rv = SW_OK; 826 } 827 } 828 } 829 } 830 HSL_API_UNLOCK; 831 return rv; 832} 833 834sw_error_t isisc_igmp_sg_entry_clear(a_uint32_t dev_id, fal_igmp_sg_entry_t * entry) 835{ 836 HSL_API_LOCK; 837 a_uint32_t number, count; 838 int new_index=0; 839 sw_error_t rv; 840 int action= MULT_ACTION_CLEAR; 841 int i=0; 842 int pm_type; 843 844 (void)isisc_multicast_init(0); 845 aos_mem_zero(multi_acl_info, FAL_IGMP_SG_ENTRY_MAX * sizeof (multi_acl_info_t)); 846 aos_mem_zero(multi_acl_group, FAL_IGMP_SG_ENTRY_MAX * sizeof (multi_acl_info_t)); 847 //number is the total multicast ACL rules amount, stores in multi_acl_info[]; 848 number = isisc_multicast_acl_query(); 849 //count the total specific multicast group ACL rules, stores in multi_acl_group[]; count <=number 850 count = iterate_multicast_acl_group(number, entry); 851 //new_index-1 is the found entry index in multi_acl_group[] 852 new_index = mult_acl_has_entry(&entry->group, &entry->source); 853 854 MULTI_DEBUG("Start entry clear: number=%d, count=%d, new_index=%d\n", number, count, new_index); 855 if(0 == new_index) //new entry, the user command is wrong 856 { 857 return SW_NO_SUCH; 858 } 859 860 if( 0==multi_source_is_null(&entry->source) ) // new entry is (G, S) 861 { 862 if (portmap_null(new_index-1, entry->port_map)) 863 { 864 MULTI_DEBUG("KKK entry clear, new(G,S), with null portmap. \n"); 865 isisc_multicast_acl_del(FAL_ACL_LIST_MULTICAST, new_index-1); 866 return SW_NO_MORE; 867 } 868 else 869 { 870 MULTI_DEBUG("KKK entry clear, new(G,S), with NOT null portmap. \n"); 871 /* If (G,*) doesn't exist, [count-1] is the last specfic group, maybe(G,*) */ 872 if(0 == multi_source_is_null(&(multi_acl_group[count-1].entry.source))) 873 { 874 isisc_multicast_acl_update(FAL_ACL_LIST_MULTICAST, new_index-1, entry, action); 875 } 876 else //(G,*) exist 877 { 878 pm_type = portmap_clear_type(count-1, new_index-1, entry->port_map); 879 if(pm_type == 0) 880 return SW_NO_CHANGE; 881 else if(pm_type == 1) 882 { 883 isisc_multicast_acl_del(FAL_ACL_LIST_MULTICAST, new_index-1); 884 return SW_NO_MORE; 885 } 886 else 887 { 888 //normal update; consider here...wangson 889 isisc_multicast_acl_update(FAL_ACL_LIST_MULTICAST, new_index-1, entry, action); 890 } 891 } 892 } 893 return SW_OK; 894 } 895 else //clear entry is (G,*) 896 { 897 MULTI_DEBUG("Here, new_index[%d]>=0, new portmap to clear is %x\n", new_index, entry->port_map); 898 if (portmap_null(new_index-1, entry->port_map)) 899 { 900 isisc_multicast_acl_del(FAL_ACL_LIST_MULTICAST+1, new_index-1); 901 rv = SW_NO_MORE; 902 } 903 else 904 { 905 MULTI_DEBUG("Update (G,*)!, new_index=%d, pm=%x\n", new_index, entry->port_map); 906 isisc_multicast_acl_update(FAL_ACL_LIST_MULTICAST+1, new_index-1, entry, action); 907 } 908 MULTI_DEBUG("KKK, ready clear (G, S*), count=%d\n", count); 909#if 0 910 if(count>1) // (G, S*) entry exist, if count=1 here, only exist(G,*)entry 911 { 912 //count must >=2 913 for(i=count-2; i>=0; i--) 914 { 915 if(portmap_null(i, entry->port_map)) 916 { 917 MULTI_DEBUG("portmap_null, i=%d\n", i); 918 isisc_multicast_acl_del(FAL_ACL_LIST_MULTICAST, i); 919 rv = SW_NO_MORE; 920 } 921 else 922 { 923 //Update all (G,S) entry portmap with new(G, *) portmap 924 isisc_multicast_acl_update(FAL_ACL_LIST_MULTICAST, i, entry, action); 925 rv = SW_OK; 926 } 927 } 928 } 929#else 930 if(count>1) // (G, S*) entry exist, if count=1 here, only exist(G,*)entry 931 { 932 //count must >=2 933 for(i=count-2; i>=0; i--) 934 { 935 //PortMap of entry (S,G) == (*,G) portmap after clear? 936 if((multi_acl_group[new_index-1].entry.port_map&(~(entry->port_map))) == 937 multi_acl_group[i].entry.port_map) 938 isisc_multicast_acl_del(FAL_ACL_LIST_MULTICAST, i); 939 else 940 //Update all (G,S) entry portmap with new(G, *) portmap 941 isisc_multicast_acl_update(FAL_ACL_LIST_MULTICAST, i, entry, action); 942 rv = SW_OK; 943 } 944 } 945#endif 946 } 947 HSL_API_UNLOCK; 948 return rv; 949} 950 951static void 952print_ip4addr(char * param_name, a_uint32_t * buf, 953 a_uint32_t size) 954{ 955 a_uint32_t i; 956 fal_ip4_addr_t ip4; 957 958 ip4 = *((fal_ip4_addr_t *) buf); 959 aos_printk("%s", param_name); 960 for (i = 0; i < 3; i++) 961 { 962 aos_printk("%d.", (ip4 >> (24 - i * 8)) & 0xff); 963 } 964 aos_printk("%d", (ip4 & 0xff)); 965} 966static void 967print_ip6addr(char * param_name, a_uint32_t * buf, 968 a_uint32_t size) 969{ 970 a_uint32_t i; 971 fal_ip6_addr_t ip6; 972 973 ip6 = *(fal_ip6_addr_t *) buf; 974 aos_printk("%s", param_name); 975 for (i = 0; i < 3; i++) 976 { 977 aos_printk("%x:%x:", (ip6.ul[i] >> 16) & 0xffff, ip6.ul[i] & 0xffff); 978 } 979 aos_printk("%x:%x", (ip6.ul[3] >> 16) & 0xffff, ip6.ul[3] & 0xffff); 980} 981sw_error_t isisc_igmp_sg_entry_show(a_uint32_t dev_id) 982{ 983 HSL_API_LOCK; 984 a_uint32_t number; 985 int i; 986 987 (void)isisc_multicast_init(0); 988 aos_mem_zero(multi_acl_info, FAL_IGMP_SG_ENTRY_MAX * sizeof (multi_acl_info_t)); 989 aos_mem_zero(multi_acl_group, FAL_IGMP_SG_ENTRY_MAX * sizeof (multi_acl_info_t)); 990 //number is the total multicast ACL rules amount, stores in multi_acl_info[]; 991 number = isisc_multicast_acl_query(); 992 993 for(i=0; i<number; i++) 994 { 995 if(0 == multi_acl_info[i].entry.group.type) //ipv4 996 { 997 aos_printk("\n[%d]:", i); 998 print_ip4addr(" [Group IPv4 addr]:", (a_uint32_t *)&(multi_acl_info[i].entry.group.u.ip4_addr), sizeof (fal_ip4_addr_t)); 999 print_ip4addr(" [Source IPv4 addr]:", (a_uint32_t *)&(multi_acl_info[i].entry.source.u.ip4_addr), sizeof (fal_ip4_addr_t)); 1000 aos_printk("\n [Portmap]: 0x%x ", multi_acl_info[i].entry.port_map); 1001 aos_printk(" [Vlanid]: %d ", multi_acl_info[i].entry.vlan_id); 1002 } 1003 else if(1 == multi_acl_info[i].entry.group.type) //ipv6 1004 { 1005 aos_printk("\n[%d]:", i); 1006 print_ip6addr(" [Group IPv6 addr]: ", (a_uint32_t *)&(multi_acl_info[i].entry.group.u.ip6_addr), sizeof (fal_ip6_addr_t)); 1007 print_ip6addr(" [Source IPv6 addr]: ", (a_uint32_t *)&(multi_acl_info[i].entry.source.u.ip6_addr), sizeof (fal_ip6_addr_t)); 1008 aos_printk("\n [Portmap]: 0x%x ", multi_acl_info[i].entry.port_map); 1009 aos_printk(" [Vlanid]: %d ", multi_acl_info[i].entry.vlan_id); 1010 } 1011 1012 } 1013 aos_printk("\n\nTotal %d multicast ACL rules.\n", number); 1014 HSL_API_UNLOCK; 1015 1016 return SW_OK; 1017} 1018 1019void 1020isisc_multicast_init(a_uint32_t dev_id) 1021{ 1022 sw_error_t val; 1023 1024 ACL_STATUS_SET(0, 1); 1025 1026 val = ACL_LIST_CREATE(0, FAL_ACL_LIST_MULTICAST, FAL_MULTICAST_PRI); 1027 if(val !=SW_OK && val != SW_ALREADY_EXIST) 1028 aos_printk("Multicast 1 acl list create error, val=%d\n", val); 1029 1030 val = ACL_LIST_CREATE(0, FAL_ACL_LIST_MULTICAST+1, FAL_MULTICAST_PRI+1); 1031 if(val !=SW_OK && val != SW_ALREADY_EXIST) 1032 aos_printk("Multicast 2 acl list create error, val=%d\n", val); 1033 1034} 1035 1036sw_error_t isisc_igmp_sg_entry_query(a_uint32_t dev_id, fal_igmp_sg_info_t *info) 1037{ 1038 HSL_API_LOCK; 1039 a_uint32_t number; 1040 int i; 1041 1042 isisc_multicast_init(0); 1043 aos_mem_zero(multi_acl_info, FAL_IGMP_SG_ENTRY_MAX * sizeof (multi_acl_info_t)); 1044 /*number is the total multicast ACL rules amount, stores in multi_acl_info[];*/ 1045 number = isisc_multicast_acl_query(); 1046 info->cnt = number; 1047 1048 for(i=0; i<number; i++) 1049 { 1050 aos_mem_copy(&(info->acl_info[i]), &(multi_acl_info[i]), sizeof(multi_acl_info_t)); 1051 } 1052 HSL_API_UNLOCK; 1053 1054 return SW_OK; 1055} 1056 1057