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