openbcm

Git mirror of https://github.com/Broadcom-Network-Switching-Software/OpenBCM
git clone git://git.finwo.net/mirror/broadcom/openbcm
Log | Files | Refs | README

acl.c (52874B)


      1 /*
      2  * 
      3  * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file.
      4  * 
      5  * Copyright 2007-2019 Broadcom Inc. All rights reserved.
      6  *
      7  * File:        acl.c
      8  * Purpose:     
      9  *     Advanced ContentAware Enhanced Software (ACES) implementation.
     10  */
     11 
     12 #if defined(INCLUDE_ACL)
     13 
     14 #include <shared/bsl.h>
     15 
     16 #include <bcm/error.h>
     17 
     18 #include <sal/core/libc.h>
     19 
     20 #include <shared/util.h>
     21 
     22 #include <bcmx/lport.h>
     23 #include <bcmx/lplist.h>
     24 
     25 #include <appl/acl/acl.h>
     26 #include <appl/diag/system.h>
     27 
     28 #include "acl_field.h"
     29 #include "acl_util.h"
     30 
     31 /* Macros */
     32 
     33 /*
     34  * Macro: ACL_IS_INIT (internal)
     35  *
     36  * Purpose:
     37  *     Confirm that the ACL functions are initialized.
     38  *
     39  * Parameters:
     40  *
     41  * Notes:
     42  *     Results in return(BCM_E_UNAVAIL), or
     43  *     return(BCM_E_INIT) if fails.
     44  */
     45 #define ACL_IS_INIT() do {                                              \
     46         if (_acl_control == NULL) {                                     \
     47             LOG_ERROR(BSL_LS_APPL_ACCESSCTRLLIST,                       \
     48                       (BSL_META("ACL Error: ACL not initialized\n")));  \
     49             return BCM_E_INIT;                                          \
     50         }                                                               \
     51     } while (0)
     52 
     53 /*
     54  * Macro:
     55  *     ACL_LOCK/ACL_UNLOCK  (internal)
     56  * Purpose:
     57  *     Lock the ACL module.
     58  *
     59  * Parameters:
     60  */
     61 #define ACL_LOCK() \
     62     sal_mutex_take(_acl_control->acl_lock, sal_mutex_FOREVER)
     63 
     64 #define ACL_UNLOCK(_c_) \
     65     sal_mutex_give((_c_)->acl_lock)
     66 
     67 
     68 #define ACL_RETVAL_REPLACE(_retval_temp, _retval)                      \
     69         if ((_retval_temp) == BCM_E_INIT) {                            \
     70             (_retval_temp) = BCM_E_UNAVAIL;                            \
     71         }                                                              \
     72         if ((_retval_temp) < 0 && (_retval_temp) != BCM_E_UNAVAIL) {   \
     73             (_retval) = (_retval_temp);                                \
     74         } 
     75 
     76 
     77 
     78 /* Local Prototypes */
     79 STATIC int _acl_rule_validate (const bcma_acl_rule_t *rule);
     80 STATIC _acl_link_t* _acl_find(bcma_acl_list_id_t list_id);
     81 STATIC _acl_link_t* _acl_link_alloc(void);
     82 
     83 STATIC _acl_rule_link_t *_acl_rule_find(bcma_acl_rule_id_t rule_id);
     84 STATIC _acl_rule_link_t *_acl_rule_link_alloc(void);
     85 
     86 STATIC int _acl_sort(void);
     87 STATIC int _acl_cmp(void *a, void *b);
     88 STATIC int _acl_merge(void);
     89 STATIC int _acl_range_reduce(uint16 min, uint16 max, acl_node_t **list);
     90 
     91 /* Control Globals */
     92 static _acl_control_t *_acl_control;
     93 
     94 #ifdef BROADCOM_DEBUG
     95 static char *bcma_acl_ip_protocol_text[256] = {
     96   "HOPBYHOP",    "ICMP",         "IGMP",         "GGP",    
     97   "IP",          "ST",           "TCP",          "UCL",
     98   "EGP",         "IGP",          "BBN-RCC-MON",  "NVP_II",
     99   "PUP",         "ARGUS",        "EMCON",        "XNET",
    100   "CHAOS",       "UDP",          "MUX",          "DCN_MEAS",
    101   "HMP",         "PRM",          "XNS_IDP",      "TRUNK-1",
    102   "TRUNK-2",     "LEAF1",        "LEAF2",        "RDP",
    103   "IRTP",        "ISO_TP4",      "NETBLT",       "MFE-NSP",
    104   "MERIT_INP",   "SEP",          "3PC",          "IDRP",
    105   "XTP",         "DDP",          "IDPR_CMTP",    "TP++",
    106   "IL",          "SIP",          "SDRP",         "SIP-SR",
    107   "SIP-FRAG",    "IDRP",         "RSVP",         "GRE",
    108   "MHRP",        "BNA",          "SIPP_ESP",     "SIPP_AH",
    109   "I-NLSP",      "SWIPE",        "NHRP",         "",
    110   "",            "",             "",             "", 
    111   "",            "AHIP",         "CFTP",         "HI",
    112   "SAT_EXPAK",   "KRYPTOLAN",    "RVD",          "IPPC",
    113   "ADFS",        "SAT_MON",      "VISA",         "IPCV",
    114   "CPNX",        "CPHB",         "WSN",          "PVP",
    115   "BR_SAT_MON",  "SUN_ND",       "WB_MON",       "WB_EXPAK",
    116   "ISO_IP",      "VMTP",         "SECURE_VMTP",  "VINES",
    117   "TTP",         "NSFNET_IGP",   "DGP",          "TCF",
    118   "IGRP",        "OSPFIGP",      "SPRITE_RPC",   "LARP",
    119   "MTP",         "AX_25",        "IPIP",         "MICP",
    120   "SCC_SP",      "ETHERIP",      "ENCAP",        "APES",
    121   "GMTP",        "",       "",       "", 
    122   "",      "",       "",       "", 
    123   "",      "",       "",       "", 
    124   "",      "",       "",       "", 
    125   "",      "",       "",       "", 
    126   "",      "",       "",       "", 
    127   "",      "",       "",       "", 
    128   "",      "",       "",       "", 
    129   "",      "",       "",       "", 
    130   "",      "",       "",       "", 
    131   "",      "",       "",       "", 
    132   "",      "",       "",       "", 
    133   "",      "",       "",       "", 
    134   "",      "",       "",       "", 
    135   "",      "",       "",       "", 
    136   "",      "",       "",       "", 
    137   "",      "",       "",       "", 
    138   "",      "",       "",       "", 
    139   "",      "",       "",       "", 
    140   "",      "",       "",       "", 
    141   "",      "",       "",       "", 
    142   "",      "",       "",       "", 
    143   "",      "",       "",       "", 
    144   "",      "",       "",       "", 
    145   "",      "",       "",       "", 
    146   "",      "",       "",       "", 
    147   "",      "",       "",       "", 
    148   "",      "",       "",       "", 
    149   "",      "",       "",       "", 
    150   "",      "",       "",       "", 
    151   "",      "",       "",       "", 
    152   "",      "",       "",       "", 
    153   "",      "",       "",       "", 
    154   "",      "",       "",       "", 
    155   "",      "",       "",       "", 
    156   "",      "",       "",       "", 
    157   "",      "",       "",       "", 
    158   "",      "",       "",       "", 
    159   "",      "",       "",       "ANY"
    160 };
    161 #endif /* BROADCOM_DEBUG */
    162 
    163 /* Section: Constructor and destructor for ACL (ACES) module */
    164 
    165 /*
    166  * Function: bcma_acl_init
    167  *
    168  * Purpose:
    169  *     Initializes ACES.
    170  *
    171  * Parameters:
    172  *     none
    173  *
    174  * Returns:
    175  *     BCM_E_NONE   - Success
    176  *     BCM_E_MEMORY - Allocation failure
    177  */
    178 int
    179 bcma_acl_init(void) 
    180 {
    181     _acl_control_t      *control;
    182     int                 retval = BCM_E_NONE;
    183 
    184     LOG_DEBUG(BSL_LS_APPL_ACCESSCTRLLIST,
    185               (BSL_META("ACL bcma_acl_init()\n")));
    186 
    187     /* Detach first if it has been previously initialized. */
    188     if (_acl_control != NULL) {
    189         BCM_IF_ERROR_RETURN(bcma_acl_uninstall());
    190         BCM_IF_ERROR_RETURN(bcma_acl_detach());
    191     }
    192 
    193     control = sal_alloc(sizeof(_acl_control_t), "ACL Control");
    194     if (control == NULL) {
    195         LOG_ERROR(BSL_LS_APPL_ACCESSCTRLLIST,
    196                   (BSL_META("ACL Error: allocation failure for ACL control.\n")));
    197         return BCM_E_MEMORY;
    198     }
    199     sal_memset(control, 0, sizeof(_acl_control_t));
    200 
    201     control->acl_lock = sal_mutex_create("ACL_control.lock");
    202     if (control->acl_lock == NULL) {
    203         sal_free(control);
    204         LOG_ERROR(BSL_LS_APPL_ACCESSCTRLLIST,
    205                   (BSL_META("ACL Error: creation failure for ACL lock.\n")));
    206         return BCM_E_MEMORY;
    207     }
    208 
    209     /* Initialize control structure. */
    210     _acl_control = control;
    211     ACL_LOCK();
    212     control->head.next = NULL;
    213 
    214 #ifdef BCM_FIELD_SUPPORT
    215     {
    216     int retval_temp;
    217     retval_temp = _acl_field_init();
    218     ACL_RETVAL_REPLACE(retval_temp, retval);
    219     }
    220 #endif /* BCM_FIELD_SUPPORT */
    221 
    222     ACL_UNLOCK(_acl_control);
    223 
    224     return retval;
    225 }
    226 
    227 /*
    228  * Function: bcma_acl_detach
    229  *
    230  * Purpose:
    231  *     Remove any lists and free lock and control.
    232  *
    233  * Parameters:
    234  *     none
    235  *
    236  * Returns:
    237  *     BCM_E_NONE - Success
    238  *     BCM_E_INIT - ACL module not initialized
    239  *     BCM_E_XXX  - from bcma_acl_remove()
    240  */
    241 int
    242 bcma_acl_detach(void)
    243 {
    244     _acl_control_t      *control;
    245     int                 retval = BCM_E_NONE, retval_temp;
    246 
    247     LOG_DEBUG(BSL_LS_APPL_ACCESSCTRLLIST,
    248               (BSL_META("ACL bcma_acl_detach()\n")));
    249     ACL_IS_INIT();
    250 
    251     control = _acl_control;
    252 
    253     ACL_LOCK();
    254 
    255     /* Do hardware specific detach. */
    256 #ifdef BCM_FIELD_SUPPORT
    257     retval_temp = _acl_field_detach();
    258     ACL_RETVAL_REPLACE(retval_temp, retval);
    259 #endif /* BCM_FIELD_SUPPORT */
    260 
    261     /* Remove lists . */
    262     while (_acl_control->head.next != NULL && BCM_SUCCESS(retval)) {
    263         retval_temp = bcma_acl_remove(_acl_control->head.next->list->list_id);
    264         ACL_RETVAL_REPLACE(retval_temp, retval);
    265     }
    266 
    267     _acl_control = NULL;
    268 
    269     ACL_UNLOCK(control);
    270 
    271     sal_mutex_destroy(control->acl_lock);
    272     sal_free(control);
    273 
    274     return retval;
    275 }
    276 
    277 /* Section: List accessor functions. */
    278 
    279 /*
    280  * Function: bcma_acl_add
    281  *
    282  * Purpose:
    283  *     Adds a new ACL to ACES.
    284  *
    285  * Parameters:
    286  *     list - pointer to ACL data
    287  *
    288  * Returns:
    289  *     BCM_E_NONE   - Success
    290  *     BCM_E_INIT   - ACL module not initialized
    291  *     BCM_E_EXISTS - Duplicate list ID already exists
    292  *     BCM_E_MEMORY - Allocation failure for list link.
    293  */
    294 int
    295 bcma_acl_add(bcma_acl_t *list)
    296 {
    297     _acl_link_t         *list_link;
    298 
    299     LOG_DEBUG(BSL_LS_APPL_ACCESSCTRLLIST,
    300               (BSL_META("ACL bcma_acl_add()\n")));
    301     ACL_IS_INIT();
    302 
    303     if (list == NULL) {
    304         LOG_ERROR(BSL_LS_APPL_ACCESSCTRLLIST,
    305                   (BSL_META("ACL Error: null list pointer in bcma_acl_add()\n")));
    306         return BCM_E_PARAM;
    307     }
    308 
    309     /* Confirm that list ID does not already exist. */
    310     if (_acl_find(list->list_id) != NULL) {
    311         LOG_ERROR(BSL_LS_APPL_ACCESSCTRLLIST,
    312                   (BSL_META("ACL Error: List ID=%d already exists\n"),
    313                    list->list_id));
    314         return BCM_E_EXISTS;
    315     }
    316 
    317     /* Allocate a node for linked-list of ACLs and copy list. */
    318     list_link = _acl_link_alloc();
    319     if (list_link == NULL) {
    320         LOG_ERROR(BSL_LS_APPL_ACCESSCTRLLIST,
    321                   (BSL_META("ACL Error: allocation failure for new list node.\n")));
    322         return BCM_E_MEMORY;
    323     }
    324     list_link->list = list;
    325 
    326     /* Link the new list and add it to the linked-list. */
    327     ACL_LOCK();
    328 
    329     /* Test for no lists. */
    330     if (_acl_control->head.next == NULL) {
    331         _acl_control->head.next = list_link;
    332         list_link->prev = &_acl_control->head;
    333     } else {
    334         list_link->next = _acl_control->head.next;
    335         /* Insert at head. */
    336         if (_acl_control->head.next != NULL) {
    337             _acl_control->head.next->prev = list_link;
    338         }
    339 
    340         _acl_control->head.next = list_link;
    341         list_link->prev         = &_acl_control->head;
    342     }
    343 
    344     _acl_control->cur   = list_link;
    345     ACL_UNLOCK(_acl_control);
    346 
    347     return BCM_E_NONE;
    348 }
    349 
    350 /*
    351  * Function: bcma_acl_rule_add
    352  *
    353  * Purpose:
    354  *     Add a rule to a list of rules.
    355  *
    356  * Parameters:
    357  *     list_id  - List ID
    358  *     *rule - rule to be added to List
    359  *
    360  * Returns:
    361  *     BCM_E_NONE       - Success
    362  *     BCM_E_INIT       - ACL module not initialized
    363  *     BCM_E_PARAM      - NULL rule pointer.
    364  *     BCM_E_NOT_FOUND  - List ID not found 
    365  *     BCM_E_MEMORY     - Allocation failure for rule.
    366  *     BCM_E_EXISTS     - Rule ID already exists.
    367  */
    368 int
    369 bcma_acl_rule_add(bcma_acl_list_id_t list_id, bcma_acl_rule_t *rule)
    370 {
    371     _acl_link_t         *list_link;
    372     _acl_rule_link_t    *rule_link_iter = NULL,
    373                         *rule_link      = NULL;
    374     
    375     LOG_DEBUG(BSL_LS_APPL_ACCESSCTRLLIST,
    376               (BSL_META("ACL bcma_acl_rule_add(list_id=%d, rule=%p)\n"),
    377                list_id, (void *)rule));
    378     ACL_IS_INIT();
    379 
    380     BCM_IF_ERROR_RETURN(_acl_rule_validate(rule));
    381 
    382     ACL_LOCK();
    383     /* Find the list to add this rule to. */
    384     list_link = _acl_find(list_id);
    385     if (list_link == NULL) {
    386         ACL_UNLOCK(_acl_control);
    387         LOG_ERROR(BSL_LS_APPL_ACCESSCTRLLIST,
    388                   (BSL_META("ACL Error: List ID=%d not found\n"),
    389                    list_id));
    390         return BCM_E_NOT_FOUND;
    391     }
    392 
    393     if (_acl_rule_find(rule->rule_id) != NULL) {
    394         ACL_UNLOCK(_acl_control);
    395         LOG_ERROR(BSL_LS_APPL_ACCESSCTRLLIST,
    396                   (BSL_META("ACL Error: Rule ID=%d already exists\n"),
    397                    rule->rule_id));
    398         return BCM_E_EXISTS;
    399     }
    400 
    401     /* Make a copy of the input rule. */
    402     /* Create a rule link. */
    403     rule_link = _acl_rule_link_alloc();
    404     if (rule_link == NULL) {
    405         ACL_UNLOCK(_acl_control);
    406         LOG_ERROR(BSL_LS_APPL_ACCESSCTRLLIST,
    407                   (BSL_META("ACL Error: Allocation failure in _acl_rule_link_alloc()\n")));
    408         return BCM_E_MEMORY;
    409     }
    410     rule_link->rule = rule;
    411     rule_link->next = NULL;
    412 
    413     /* If list has no rules, add new rule link to the head. */
    414     if (list_link->rules == NULL) {
    415         list_link->rules = rule_link;
    416         ACL_UNLOCK(_acl_control);
    417         LOG_DEBUG(BSL_LS_APPL_ACCESSCTRLLIST,
    418                   (BSL_META("ACL bcma_acl_rule_add() END\n")));
    419         return BCM_E_NONE;
    420     }
    421     
    422     /* Find the tail. */
    423     rule_link_iter = list_link->rules;
    424     while (rule_link_iter->next != NULL) {
    425          rule_link_iter = rule_link_iter->next;
    426     }
    427 
    428     /* Put new rule link at tail of linked-list */
    429     rule_link_iter->next = rule_link;
    430 
    431     /* Make this the current rule (for iterator functions). */
    432     list_link->cur       = rule_link;
    433 
    434     ACL_UNLOCK(_acl_control);
    435 
    436     LOG_DEBUG(BSL_LS_APPL_ACCESSCTRLLIST,
    437               (BSL_META("ACL bcma_acl_rule_add() END\n")));
    438     return BCM_E_NONE;
    439 }
    440 
    441 #define _ACL_L4_MIN  (0)
    442 #define _ACL_L4_MAX  ((1 << 16) - 1)
    443 
    444 #define _ACL_L4_PORT_VALIDATE(_port_)                                   \
    445     do {                                                                \
    446         if ((_port_) < _ACL_L4_MIN || _ACL_L4_MAX < (_port_)) {         \
    447             LOG_ERROR(BSL_LS_APPL_ACCESSCTRLLIST,                       \
    448                       (BSL_META("ACL Error: L4 port=%d out of range\n"), \
    449                        (_port_)));                                      \
    450             return BCM_E_PARAM;                                         \
    451         }                                                               \
    452     } while (0)
    453 
    454 /*
    455  * Function:
    456  *    _acl_rule_validate
    457  *
    458  * Purpose:
    459  *     Confirms fields within the rule are in acceptible ranges.
    460  *
    461  * Parameters:
    462  *     rule - rule structure to be evaluated.
    463  *
    464  * Returns:
    465  *     BCM_E_NONE       - Success
    466  *     BCM_E_PARAM      - Out-of-range field(s) in rule
    467  */
    468 STATIC int
    469 _acl_rule_validate(const bcma_acl_rule_t *rule)
    470 {
    471     if (rule == NULL) {
    472         LOG_ERROR(BSL_LS_APPL_ACCESSCTRLLIST,
    473                   (BSL_META("ACL Error: rule=NULL\n")));
    474         return BCM_E_PARAM;
    475     }
    476 
    477     _ACL_L4_PORT_VALIDATE(rule->src_port_min);
    478     _ACL_L4_PORT_VALIDATE(rule->src_port_max);
    479     _ACL_L4_PORT_VALIDATE(rule->dst_port_min);
    480     _ACL_L4_PORT_VALIDATE(rule->dst_port_max);
    481 
    482     return BCM_E_NONE;
    483 }
    484 #undef _ACL_L4_MIN
    485 #undef _ACL_L4_MAX
    486 #undef _ACL_L4_PORT_VALIDATE
    487 
    488 /*
    489  * Function: bcma_acl_rule_remove
    490  *
    491  * Purpose:
    492  *     Remove an rule from a list.
    493  *
    494  * Parameters:
    495  *     list_id  - List ID where rule exists
    496  *     rule_id  - Rule ID to be removed
    497  *
    498  * Returns:
    499  *     BCM_E_NONE       - Success
    500  *     BCM_E_INIT       - ACL module not initialized
    501  *     BCM_E_NOT_FOUND  - List ID or Rule ID not found 
    502  */
    503 int
    504 bcma_acl_rule_remove(bcma_acl_list_id_t list_id, bcma_acl_rule_id_t rule_id)
    505 {
    506     _acl_link_t         *list_link;
    507     _acl_rule_link_t    *rule_link_cur, *rule_link_prev;
    508     int                 retval = BCM_E_NONE;
    509 
    510     LOG_DEBUG(BSL_LS_APPL_ACCESSCTRLLIST,
    511               (BSL_META("ACL bcma_acl_rule_remove(list_id=%d, rule_id=%d)\n"),
    512                list_id, rule_id));
    513     ACL_IS_INIT();
    514 
    515     ACL_LOCK();
    516     list_link = _acl_find(list_id);
    517 
    518     if (list_link == NULL) {
    519         ACL_UNLOCK(_acl_control);
    520         LOG_ERROR(BSL_LS_APPL_ACCESSCTRLLIST,
    521                   (BSL_META("ACL Error: List ID=%d not found\n"),
    522                    list_id));
    523         return BCM_E_NOT_FOUND;
    524     }
    525 
    526     /* Traverse the list of rule links, looking for matching RID to remove. */
    527     for (rule_link_prev = NULL, rule_link_cur = list_link->rules;
    528          rule_link_cur != NULL;
    529          rule_link_prev = rule_link_cur, rule_link_cur = rule_link_cur->next) {
    530         if (rule_link_cur->rule->rule_id == rule_id) {
    531             /* Point around old rule_link */
    532             if (rule_link_prev == NULL) {
    533                 /* At head of list. */
    534                 list_link->rules = rule_link_cur->next;
    535             } else {
    536                 /* Somewhere within list. */
    537                 rule_link_prev->next = rule_link_cur->next;
    538             }
    539             /* Remove the Rule ID from hardware. */
    540 #ifdef BCM_FIELD_SUPPORT
    541             {
    542             int retval_temp;
    543             retval_temp = _acl_field_rule_remove(rule_id);
    544             ACL_RETVAL_REPLACE(retval_temp, retval);
    545             }
    546 #endif /* BCM_FIELD_SUPPORT */
    547 
    548             /* Remove the rule_link from software. */
    549             sal_free(rule_link_cur);
    550             ACL_UNLOCK(_acl_control);
    551             return retval;
    552         }
    553     }
    554 
    555     ACL_UNLOCK(_acl_control);
    556     LOG_ERROR(BSL_LS_APPL_ACCESSCTRLLIST,
    557               (BSL_META("ACL Error: Rule ID=%d not found in List ID=%d\n"),
    558                rule_id, list_id));
    559     return BCM_E_NOT_FOUND;
    560 }
    561 
    562 /*
    563  * Function: bcma_acl_rule_get
    564  *
    565  * Purpose:
    566  *     Accessor function to get a Rule
    567  *
    568  * Parameters:
    569  *     rule_id - Rule ID
    570  *     rule    - (OUT) returned rule info
    571  *
    572  * Returns:
    573  *     BCM_E_NONE      - Success
    574  *     BCM_E_INIT      - ACL module not initialized
    575  *     BCM_E_PARAM     - rule pointer is NULL
    576  *     BCM_E_NOT_FOUND - Rule ID not found
    577  */
    578 int
    579 bcma_acl_rule_get(bcma_acl_rule_id_t rule_id, bcma_acl_rule_t **rule)
    580 {
    581     _acl_rule_link_t    *rule_link;
    582 
    583     LOG_DEBUG(BSL_LS_APPL_ACCESSCTRLLIST,
    584               (BSL_META("ACL bcma_acl_rule_get(rule_id=%d, rule=%p)\n"), 
    585                rule_id, (void *)rule));
    586     ACL_IS_INIT();
    587 
    588     if (*rule == NULL) {
    589         LOG_ERROR(BSL_LS_APPL_ACCESSCTRLLIST,
    590                   (BSL_META("ACL Error: *rule is NULL\n")));
    591         return BCM_E_PARAM;
    592     }
    593 
    594     rule_link = _acl_rule_find(rule_id);
    595 
    596     if (rule_link == NULL) {
    597         LOG_ERROR(BSL_LS_APPL_ACCESSCTRLLIST,
    598                   (BSL_META("ACL Error: Rule ID=%d not found\n"),
    599                    rule_id));
    600         return BCM_E_NOT_FOUND;
    601     }
    602 
    603     *rule = rule_link->rule;
    604 
    605     return BCM_E_NONE;
    606 }
    607 
    608 /*
    609  * Function: bcma_acl_remove
    610  *
    611  * Purpose:
    612  *     Remove ACL from list of ACLs. This removes the Filter and Field entries
    613  *     used to support any rules in this list. Then it frees internal link
    614  *     memory used by ACL, including the rule links in the list. 
    615  *
    616  * Parameters:
    617  *     list_id  - List ID to be removed
    618  *
    619  * Returns:
    620  *     BCM_E_NONE      - Success
    621  *     BCM_E_INIT      - ACL module not initialized
    622  *     BCM_E_NOT_FOUND - List ID not found
    623  */
    624 int
    625 bcma_acl_remove(bcma_acl_list_id_t list_id)
    626 {
    627     _acl_link_t         *link_cur;
    628     int                 retval;
    629 
    630     LOG_DEBUG(BSL_LS_APPL_ACCESSCTRLLIST,
    631               (BSL_META("ACL bcma_acl_remove(list_id=%d)\n"),
    632                list_id));
    633     ACL_IS_INIT();
    634 
    635     ACL_LOCK();
    636     link_cur = _acl_find(list_id);
    637     if (link_cur == NULL) {
    638         LOG_ERROR(BSL_LS_APPL_ACCESSCTRLLIST,
    639                   (BSL_META("ACL Error: List ID=%d not found\n"),
    640                    list_id));
    641         ACL_UNLOCK(_acl_control);
    642         return BCM_E_NOT_FOUND;
    643     }
    644 
    645     /* Remove rules in list. */
    646     while (link_cur->rules != NULL) {
    647         retval = bcma_acl_rule_remove(list_id, link_cur->rules->rule->rule_id);
    648         if (BCM_FAILURE(retval)) {
    649             ACL_UNLOCK(_acl_control);
    650             return retval;
    651         }
    652     }
    653 
    654     /* Remove the list link node itself. */
    655     if (link_cur->next != NULL) {
    656         link_cur->next->prev = link_cur->prev;
    657     }
    658     link_cur->prev->next = link_cur->next;
    659     sal_free(link_cur);
    660 
    661     ACL_UNLOCK(_acl_control);
    662     return BCM_E_NONE;
    663 }
    664 
    665 /*
    666  * Function: bcma_acl_get
    667  *
    668  * Purpose:
    669  *     Accessor function for a ACL
    670  *
    671  * Parameters:
    672  *     list_id   - List ID
    673  *     list  - (OUT) returned list info
    674  *
    675  * Returns:
    676  *     BCM_E_NONE      - Success
    677  *     BCM_E_INIT      - ACL module not initialized
    678  *     BCM_E_PARAM     - list pointer is NULL
    679  *     BCM_E_NOT_FOUND - List ID not found
    680  */
    681 int
    682 bcma_acl_get(bcma_acl_list_id_t list_id, bcma_acl_t *list)
    683 {
    684     _acl_link_t         *list_link;
    685 
    686     LOG_DEBUG(BSL_LS_APPL_ACCESSCTRLLIST,
    687               (BSL_META("ACL bcma_acl_get(list_id=%d, list=%p)\n"),
    688                list_id,
    689                (void *)list));
    690     ACL_IS_INIT();
    691 
    692     if (list == NULL) {
    693         LOG_ERROR(BSL_LS_APPL_ACCESSCTRLLIST,
    694                   (BSL_META("ACL Error: *list is NULL\n")));
    695         return BCM_E_PARAM;
    696     }
    697 
    698     list_link = _acl_find(list_id);
    699     if (list_link == NULL) {
    700         LOG_ERROR(BSL_LS_APPL_ACCESSCTRLLIST,
    701                   (BSL_META("ACL Error: List ID=%d not found\n"),
    702                    list_id));
    703         return BCM_E_NOT_FOUND;
    704     }
    705 
    706     sal_memcpy(list, &list_link->list, sizeof(bcma_acl_t));
    707     return BCM_E_NONE;
    708 }
    709 
    710 /*
    711  * Function:
    712  *     _acl_control_find
    713  *
    714  * Purpose:
    715  *     Find a ACL control
    716  *
    717  * Parameters:
    718  *
    719  * Returns:
    720  *     pointer to _acl_control_t on success
    721  *     NULL on failure
    722  */
    723 _acl_control_t *
    724 _acl_control_find(void) {
    725     return _acl_control;
    726 }
    727 
    728 /*
    729  * Function:
    730  *     _acl_first
    731  *
    732  * Purpose:
    733  *     Return the first link in list of ACLs. Along with _acl_next(),
    734  *     it is meant to be used in a for() loop as the initializer.
    735  *
    736  * Parameters:
    737  *     *control - ACES control
    738  *
    739  * Returns:
    740  *     pointer to the first _acl_link_t structure.
    741  *     NULL on failure
    742  */
    743 _acl_link_t *
    744 _acl_first(_acl_control_t *control) {
    745     assert(control != NULL);
    746     assert(control != (_acl_control_t*)0xffffffff);
    747 
    748     control->cur = control->head.next;
    749     return control->cur;
    750 }
    751 /*
    752  * Function:
    753  *     _acl_next
    754  *
    755  * Purpose:
    756  *     Return the next link in list of ACLs.
    757  *
    758  * Parameters:
    759  *     control - ACES control
    760  *
    761  * Returns:
    762  *     pointer to the first _acl_link_t structure.
    763  *     NULL at end of list
    764  */
    765 
    766 _acl_link_t *
    767 _acl_next(_acl_control_t *control) {
    768     assert(control != NULL);
    769     assert(control != (_acl_control_t*)0xffffffff);
    770     assert(control->cur != NULL);
    771 
    772     control->cur = control->cur->next;
    773     return control->cur;
    774 }
    775 
    776 
    777 /*
    778  * Function:
    779  *     _acl_find
    780  *
    781  * Purpose:
    782  *     Find an ACL given on its ID. 
    783  *
    784  * Parameters:
    785  *     list_id  - ACL identifier
    786  *
    787  * Returns:
    788  *     pointer to bcma_acl_struct on success
    789  *     NULL on failure
    790  */
    791 STATIC _acl_link_t*
    792 _acl_find(bcma_acl_list_id_t list_id) {
    793     _acl_link_t         *acl_iter;
    794 
    795     acl_iter = _acl_control->head.next;
    796 
    797     while (acl_iter != NULL) {
    798         if (acl_iter->list->list_id == list_id) {
    799             return acl_iter;
    800         }
    801         acl_iter = acl_iter->next;
    802     }
    803 
    804     return NULL;
    805 }
    806 
    807 /*
    808  * Function:
    809  *     _acl_link_alloc
    810  *
    811  * Purpose:
    812  *     Allocates the space for a list node and performs a deep copy of input
    813  *     list.
    814  *
    815  * Parameters:
    816  *     list - pointer to Access Control List to add to ACL.
    817  *
    818  * Returns:
    819  *     pointer to _acl_link_t struct on success
    820  *     NULL on failure
    821  */
    822 STATIC _acl_link_t*
    823 _acl_link_alloc(void) {
    824     _acl_link_t         *list_link;
    825 
    826     LOG_DEBUG(BSL_LS_APPL_ACCESSCTRLLIST,
    827               (BSL_META("ACL _acl_link_alloc()\n")));
    828     list_link = sal_alloc(sizeof(_acl_link_t), "ACL list node");
    829     if (list_link == NULL) {
    830         return list_link;
    831     }
    832 
    833     sal_memset(list_link, 0, sizeof(_acl_link_t));
    834     list_link->rules = NULL;
    835 
    836     return list_link;
    837 }
    838 
    839 /*
    840  * Function:
    841  *     _acl_rule_find
    842  *
    843  * Purpose:
    844  *     Find a rule link given an Rule ID. This searches all lists
    845  *     and returns the first rule link that has a matching rule ID.
    846  *
    847  * Parameters:
    848  *     rule_id  - Rule identifier
    849  *
    850  * Returns:
    851  *     pointer to _acl_rule_link_t on success
    852  *     NULL on failure
    853  */
    854 STATIC _acl_rule_link_t*
    855 _acl_rule_find(bcma_acl_rule_id_t rule_id) {
    856     _acl_link_t         *list_link = NULL;
    857     _acl_rule_link_t    *rule_link = NULL;
    858 
    859     /* Traverse the lists. */
    860     for (list_link = _acl_control->head.next;
    861          list_link != NULL;
    862          list_link = list_link->next) {
    863         for (rule_link = list_link->rules;
    864              rule_link != NULL;
    865              rule_link = rule_link->next) {
    866             if (rule_link->rule->rule_id == rule_id) {
    867                 break;
    868             }
    869         }
    870     }
    871 
    872     return rule_link;
    873 }
    874 
    875 /*
    876  * Function:
    877  *     _acl_rule_first
    878  *
    879  * Purpose:
    880  *     Get the first rule in the list. This also moves the current rule pointer
    881  *     to the first rule.
    882  *
    883  * Parameters:
    884  *     list_link - Wrapper to ACL where rule is.
    885  *
    886  * Returns:
    887  *     pointer to _acl_rule_link_t on success
    888  *     NULL on failure
    889  */
    890 bcma_acl_rule_t *
    891 _acl_rule_first(_acl_link_t *list_link)
    892 {
    893     assert(list_link != NULL);
    894 
    895     list_link->cur = list_link->rules;
    896 
    897     if (list_link->cur != NULL) {
    898         return list_link->rules->rule;
    899     }
    900 
    901     return NULL;
    902 }
    903 
    904 /*
    905  * Function:
    906  *     _acl_rule_next
    907  *
    908  * Purpose:
    909  *     Get the next rule in the list. This also increments the current rule
    910  *     pointer.
    911  *
    912  * Parameters:
    913  *     list_link - Wrapper to ACL where rule is.
    914  *
    915  * Returns:
    916  *     pointer to _acl_rule_link_t on success
    917  *     NULL on failure
    918  */
    919 bcma_acl_rule_t *
    920 _acl_rule_next(_acl_link_t *list_link)
    921 {
    922     assert(list_link != NULL);
    923     assert(list_link->cur != NULL);
    924 
    925     list_link->cur = list_link->cur->next;
    926 
    927     if (list_link->cur != NULL) {
    928         return list_link->cur->rule;
    929     } 
    930 
    931     return NULL;
    932 }
    933 
    934 _acl_rule_link_t *
    935 _acl_rule_link_find(bcma_acl_rule_id_t rule_id) 
    936 {
    937     _acl_link_t           *acl_link;
    938     _acl_rule_link_t      *rule_link;
    939 
    940     /* For each ACL */
    941     for (acl_link = _acl_first(_acl_control);
    942         acl_link != NULL;
    943         acl_link = _acl_next(_acl_control))
    944     {
    945         /* For each rule_link in list...*/
    946         for (rule_link = acl_link->rules;
    947             rule_link != NULL;
    948             rule_link = rule_link->next)
    949         {
    950             if (rule_link->rule->rule_id == rule_id) {
    951                 return rule_link;
    952             }
    953  
    954         }
    955     }
    956 
    957     return NULL;
    958 }
    959 
    960 /*
    961  * Function:
    962  *    _acl_rule_link_alloc
    963  *
    964  * Purpose:
    965  *    Allocate a rule link and copy the source rule data into it.
    966  *
    967  * Parameters:
    968  *     none
    969  *
    970  * Returns:
    971  *     pointer to newly allocated duplicate rule
    972  *     NULL on allocation failure 
    973  *
    974  * Note:
    975  *     next pointer of copy is NULL
    976  */
    977 STATIC _acl_rule_link_t *
    978 _acl_rule_link_alloc(void) {
    979     _acl_rule_link_t    *rule_link;
    980 
    981     LOG_DEBUG(BSL_LS_APPL_ACCESSCTRLLIST,
    982               (BSL_META("ACL _acl_rule_link_alloc()\n")));
    983     rule_link = sal_alloc(sizeof(_acl_rule_link_t), "ACL rule link");
    984     if (rule_link == NULL) {
    985         return NULL;
    986     }
    987     sal_memset(rule_link, 0, sizeof(_acl_rule_link_t));
    988 
    989     LOG_DEBUG(BSL_LS_APPL_ACCESSCTRLLIST,
    990               (BSL_META("ACL _acl_rule_link_alloc() returning=%p\n"),
    991                (void *)rule_link));
    992     return rule_link;
    993 }
    994 
    995 /* Section: Installation */
    996 /*
    997  * Function: _acl_sort
    998  *
    999  * Purpose:
   1000  *     Sorting of link list of ACLs into descending ordr of priorities. This
   1001  *     is necessary because priority values can be changed by the client code.
   1002  *     Even if they're inserted in order, the priorities are not guarranteed
   1003  *     to be correct at install time.
   1004  *
   1005  * Parameters:
   1006  *     none
   1007  *
   1008  * Returns:
   1009  *     BCM_E_NONE     - Success
   1010  *     BCM_E_MEMORY   - Allocation failure
   1011  */
   1012 STATIC int
   1013 _acl_sort(void)
   1014 {
   1015     _acl_link_t         *array;   /* Array of links to be sorted. */
   1016     int                 count = 0;  /* Number of ACLs. */
   1017     int                 idx;
   1018 
   1019     /* Count the number of ACLs. */
   1020     for (_acl_control->cur = _acl_control->head.next, count = 0;
   1021          _acl_control->cur != NULL;
   1022          _acl_control->cur = _acl_control->cur->next, count++) {
   1023     }
   1024 
   1025     /* Create an array of pointers to _acl_link_t structures. */
   1026     array = (_acl_link_t*)sal_alloc(sizeof(_acl_link_t) * count,
   1027                                      "ACL_sort_array"); 
   1028     if (array == NULL) {
   1029         return BCM_E_MEMORY;
   1030     }
   1031 
   1032     /* Copy to the array for sorting */
   1033     _acl_control->cur = &_acl_control->head;
   1034     for (idx = 0; idx < count; idx++) {
   1035         assert(_acl_control->cur != NULL);
   1036         sal_memcpy(&array[idx], _acl_control->cur->next, sizeof(_acl_link_t));
   1037 
   1038         /* We borrow the 'prev' pointer in the sorting array for
   1039          * identifying the element 
   1040          */
   1041         array[idx].prev = _acl_control->cur->next;
   1042 
   1043         _acl_control->cur = _acl_control->cur->next;
   1044     }
   1045 
   1046     /* Sort the array. */
   1047     _shr_sort(array, count, sizeof(_acl_link_t), _acl_cmp);
   1048 
   1049     /* Rewire the linked list in sorted order. */
   1050     _acl_control->cur = &_acl_control->head;
   1051     if (count) {
   1052         /* 
   1053          * head->next should be set to the element with highest 
   1054          * priority after sorted.
   1055          */
   1056         _acl_control->cur->next = array[0].prev;
   1057      }
   1058 
   1059     /* Re-construct the chain */
   1060     for (idx = 0; idx < count; idx++) {
   1061         sal_memcpy(_acl_control->cur->next, &array[idx], sizeof(_acl_link_t));
   1062         if (idx == 0) {
   1063             _acl_control->cur->next->prev = &_acl_control->head;
   1064         } else {
   1065             /* Remember we borrow the 'prev' to locate the actual element */
   1066             _acl_control->cur->next->prev = array[idx - 1].prev;
   1067         }
   1068         if (idx < count - 1) {
   1069             /* Remember we borrow the 'prev' to locate the actual element */
   1070             _acl_control->cur->next->next = array[idx + 1].prev;
   1071         } else {
   1072             _acl_control->cur->next->next = NULL;
   1073         }
   1074         _acl_control->cur = _acl_control->cur->next;
   1075     }
   1076 
   1077     /* Destroy the array. */
   1078     sal_free(array);
   1079 
   1080     LOG_DEBUG(BSL_LS_APPL_ACCESSCTRLLIST,
   1081               (BSL_META("ACL END _acl_sort()\n")));
   1082 
   1083     return BCM_E_NONE;
   1084 }
   1085 
   1086 /*
   1087  * Function: _acl_cmp
   1088  *
   1089  * Purpose:
   1090  *     Callback function for _shr_sort(). This compares two lists and returns
   1091  *     the usual Unix -1, 0, or +1 values. The only difference is that the -1
   1092  *     and +1 are reversed so the list will be arranged highest priority first.
   1093  *
   1094  * Parameters:
   1095  *     a - Pointer to first list link
   1096  *     b - Pointer to second list link
   1097  *
   1098  * Returns:
   1099  *     -1  - if A has higher priority than B 
   1100  *      0  - if A and B have equal priority
   1101  *     +1  - if B has higher priority than A
   1102  */
   1103 STATIC int
   1104 _acl_cmp(void *a, void *b)
   1105 {
   1106     _acl_link_t        *list_first, *list_second;
   1107 
   1108     list_first  = (_acl_link_t*)a;
   1109     list_second = (_acl_link_t*)b;
   1110     
   1111     if (list_first->list->prio > list_second->list->prio) {
   1112         return -1;
   1113     } else if (list_first->list->prio < list_second->list->prio) {
   1114         return 1;
   1115     }
   1116 
   1117     return 0;
   1118 }
   1119 
   1120 /*
   1121  * Function: _acl_merge
   1122  *
   1123  * Purpose:
   1124  *    Build a solution ready to install in the hardware. The main purpose of
   1125  *    this is to test if the current set of ACLs will fit in hardware.
   1126  *
   1127  * Parameters:
   1128  *
   1129  * Returns:
   1130  *     BCM_E_NONE     - Success
   1131  *     BCM_E_INIT     - ACL module not initialized
   1132  *     BCM_E_RESOURCE - Insufficient hardware resources for current Lists.
   1133  */
   1134 STATIC int
   1135 _acl_merge(void)
   1136 {
   1137     int                 retval = BCM_E_NONE;
   1138 
   1139     LOG_DEBUG(BSL_LS_APPL_ACCESSCTRLLIST,
   1140               (BSL_META("ACL _acl_merge()\n")));
   1141     ACL_IS_INIT();
   1142 
   1143     ACL_LOCK();
   1144 
   1145 #ifdef BCM_FIELD_SUPPORT
   1146     {
   1147     int retval_temp;
   1148     
   1149     retval_temp = _acl_field_merge(_acl_control);
   1150     ACL_RETVAL_REPLACE(retval_temp, retval);
   1151     }
   1152 #endif /* BCM_FIELD_SUPPORT */
   1153 
   1154     ACL_UNLOCK(_acl_control);
   1155     LOG_DEBUG(BSL_LS_APPL_ACCESSCTRLLIST,
   1156               (BSL_META("ACL END _acl_merge()\n")));
   1157 
   1158     return retval;
   1159 }
   1160 
   1161 /*
   1162  * Function: bcma_acl_install
   1163  *
   1164  * Purpose:
   1165  *     Write current ACL solution to hardware. Take working solution calculated
   1166  *     by _acl_merge() and commit it to hardware. This may be an expensive
   1167  *     operation if multiple rules must be shuffled to maintain atomicity.
   1168  *
   1169  * Parameters:
   1170  *     none
   1171  *
   1172  * Returns:
   1173  *     BCM_E_NONE     - Success
   1174  *     BCM_E_INIT     - ACL module not initialized
   1175  *     BCM_E_RESOURCE - Insufficient hardware resources to support current
   1176  *                      Lists.
   1177  *     BCM_E_MEMORY   - Allocation failure
   1178  */
   1179 int
   1180 bcma_acl_install(void)
   1181 {
   1182     int                 retval = BCM_E_NONE;
   1183 
   1184     LOG_DEBUG(BSL_LS_APPL_ACCESSCTRLLIST,
   1185               (BSL_META("ACL bcma_acl_install()\n")));
   1186     ACL_IS_INIT();
   1187 
   1188     ACL_LOCK();
   1189 
   1190     BCM_IF_ERROR_RETURN(bcma_acl_uninstall());
   1191     BCM_IF_ERROR_RETURN(_acl_sort());
   1192     BCM_IF_ERROR_RETURN(_acl_merge());
   1193 
   1194 #ifdef BCM_FIELD_SUPPORT
   1195     {
   1196     int retval_temp;
   1197     retval_temp = _acl_field_install();
   1198     ACL_RETVAL_REPLACE(retval_temp, retval);
   1199     }
   1200 #endif /* BCM_FIELD_SUPPORT */
   1201 
   1202     ACL_UNLOCK(_acl_control);
   1203 
   1204     return retval;
   1205 }
   1206 
   1207 /*
   1208  * Function: bcma_acl_uninstall
   1209  *
   1210  * Purpose:
   1211  *     Remove the current set of ACLs from the hardware.
   1212  *
   1213  * Parameters:
   1214  *
   1215  * Returns:
   1216  *     BCM_E_NONE     - Success
   1217  *     BCM_E_INIT     - ACL module not initialized
   1218  */
   1219 int
   1220 bcma_acl_uninstall(void)
   1221 {
   1222     int                 retval = BCM_E_NONE;
   1223 
   1224     LOG_DEBUG(BSL_LS_APPL_ACCESSCTRLLIST,
   1225               (BSL_META("ACL bcma_acl_uninstall()\n")));
   1226     ACL_IS_INIT();
   1227     ACL_LOCK();
   1228 
   1229 #ifdef BCM_FIELD_SUPPORT
   1230     {
   1231     int retval_temp;
   1232     retval_temp = _acl_field_uninstall();
   1233     ACL_RETVAL_REPLACE(retval_temp, retval);
   1234     }
   1235 #endif /* BCM_FIELD_SUPPORT */
   1236 
   1237     ACL_UNLOCK(_acl_control);
   1238     return retval;
   1239 }
   1240 
   1241 /*
   1242  * Function: acl_range_to_list
   1243  *
   1244  * Purpose:
   1245  *     Generate a mininal linked list of data/mask pairs that cover the
   1246  *     specified range.
   1247  *
   1248  * Parameters:
   1249  *     min   - lower limit of range
   1250  *     max   - upper limit of range
   1251  *     list  - (OUT) pointer to head of list
   1252  *     count - (OUT) number of nodes in list
   1253  *
   1254  * Returns:
   1255  *     BCM_E_NONE   - Success
   1256  *     BCM_E_MEMORY - Allocation failure.
   1257  */
   1258 int
   1259 acl_range_to_list(uint16 min, uint16 max, acl_node_t **list_p, int *count) {
   1260     acl_node_t          **list_temp;
   1261     int                 idx;
   1262     
   1263     if (list_p == NULL || count == NULL) {
   1264         LOG_ERROR(BSL_LS_APPL_ACCESSCTRLLIST,
   1265                   (BSL_META("ACL Error: list or count is NULL\n")));
   1266         return BCM_E_PARAM;
   1267     }
   1268     LOG_DEBUG(BSL_LS_APPL_ACCESSCTRLLIST,
   1269               (BSL_META("ACL acl_range_to_list(min=%d, max=%d)\n"),
   1270                min, max));
   1271     *list_p = NULL;
   1272 
   1273     *count = _acl_range_reduce(min, max, (acl_node_t **)NULL);
   1274 
   1275     /* Allocate a temporary array of pointers to nodes. */
   1276     list_temp = (acl_node_t **)sal_alloc(*count * sizeof(acl_node_t *),
   1277                                          "ACL temp_list");
   1278     if (list_temp == NULL) {
   1279         return BCM_E_MEMORY;
   1280     }
   1281     sal_memset(list_temp, 0, *count * sizeof(acl_node_t *));
   1282 
   1283     /* Allocate nodes. */
   1284     for (idx = 0; idx < *count; idx++) {
   1285         list_temp[idx] = (acl_node_t *)sal_alloc(sizeof(acl_node_t),
   1286                          "ACL range node");
   1287         sal_memset(list_temp[idx], 0, sizeof(acl_node_t));
   1288         if (list_temp[idx] == NULL) {
   1289             return BCM_E_MEMORY;
   1290         }
   1291 
   1292         /* Link nodes into list. */
   1293         if (idx > 0) {
   1294             list_temp[idx - 1]->next = list_temp[idx];
   1295         }
   1296     }
   1297 
   1298     *list_p = list_temp[0];
   1299     (void) _acl_range_reduce(min, max, list_temp);
   1300 
   1301     sal_free(list_temp);
   1302 
   1303     return BCM_E_NONE;
   1304 }
   1305 
   1306 /*
   1307  * Function:
   1308  *     _acl_range_reduce
   1309  *
   1310  * Purpose:
   1311  *     Create a minimum set of data/mask nodes given a min and max range.
   1312  *     This function needs to be called twice. First it should be called with
   1313  *     list==NULL to establish the count. Then it should be called to fill
   1314  *     in the list array with data/mask nodes.
   1315  *
   1316  * Parameters:
   1317  *     min   - lower limit of range
   1318  *     max   - upper limit of range
   1319  *     list  - (OUT) pointer to head of list of nodes
   1320  *
   1321  * Returns:
   1322  *     number of element data/mask nodes
   1323  */
   1324 STATIC int
   1325 _acl_range_reduce(uint16 min, uint16 max, acl_node_t **list)
   1326 {
   1327     int         nentry;
   1328     uint16      temp, mask;
   1329 
   1330     nentry = 0;
   1331 
   1332     while (min <= max) {
   1333         /* count low order 0 bits in min */
   1334         if (min == 0) {
   1335             mask = 0xffff;
   1336         } else {
   1337             for (temp = min, mask = 0; (temp & 1) == 0; temp >>= 1) {
   1338                 mask = (mask << 1) | 1;
   1339             }
   1340         }
   1341         temp = (min & ~mask) | mask;
   1342         if (temp <= max) {
   1343             ;
   1344         } else {
   1345             while (temp > max) {
   1346                 mask >>= 1;
   1347                 temp = (min & ~mask) | mask;
   1348             }
   1349         }
   1350         if (list) {
   1351             list[nentry]->data = min;
   1352             list[nentry]->mask = ~mask & 0xffff;
   1353         }
   1354         nentry += 1;
   1355         if (temp >= max) {
   1356             break;
   1357         }
   1358         min = temp + 1;
   1359     }
   1360 
   1361     return nentry;
   1362 }
   1363 
   1364 /*
   1365  * Function: acl_range_destroy
   1366  *
   1367  * Purpose:
   1368  *     Deallocate memory used by previously allocated range list of nodes.
   1369  *
   1370  * Parameters:
   1371  *     list  - pointer to head of list of nodes
   1372  *     count - number of nodes in list
   1373  *
   1374  * Returns:
   1375  *     BCM_E_NONE  - Success
   1376  *     BCM_E_PARAM - null list or count is wrong
   1377  */
   1378 int acl_range_destroy(acl_node_t *list, int count) {
   1379     acl_node_t          *node_cur  = NULL;
   1380     acl_node_t          *node_prev = NULL;
   1381 
   1382     if (list == NULL) {
   1383         LOG_ERROR(BSL_LS_APPL_ACCESSCTRLLIST,
   1384                   (BSL_META("ACL Error: list is NULL\n")));
   1385         return BCM_E_PARAM;
   1386     }
   1387 
   1388     node_cur = list;
   1389     while (count > 0) {
   1390         node_prev = node_cur;
   1391         if (node_prev == NULL) {
   1392             LOG_ERROR(BSL_LS_APPL_ACCESSCTRLLIST,
   1393                       (BSL_META("ACL Error: count is wrong\n")));
   1394             return BCM_E_PARAM;
   1395         }
   1396         node_cur = node_prev->next;
   1397         sal_free(node_prev);
   1398         count--;
   1399     }
   1400 
   1401     /* Confirm that list is empty. */
   1402     if (node_cur != NULL) {
   1403         LOG_ERROR(BSL_LS_APPL_ACCESSCTRLLIST,
   1404                   (BSL_META("ACL Error: count is wrong\n")));
   1405         return BCM_E_PARAM;
   1406     }
   1407 
   1408     return BCM_E_NONE;
   1409 }
   1410 
   1411 #ifdef BROADCOM_DEBUG
   1412 /*
   1413  * Function: bcma_acl_show
   1414  *
   1415  * Purpose:
   1416  *     Display access control lists currently in ACES.
   1417  *
   1418  * Parameters:
   1419  *
   1420  * Returns:
   1421  *     BCM_E_NONE - Success
   1422  *     BCM_E_XXX  - return value from bcma_acl_list_show()
   1423  */
   1424 int
   1425 bcma_acl_show(void)
   1426 {
   1427     int                 retval = BCM_E_NONE;
   1428     _acl_link_t         *list_link;
   1429     
   1430     LOG_DEBUG(BSL_LS_APPL_ACCESSCTRLLIST,
   1431               (BSL_META("ACL bcma_acl_show()\n")));
   1432     ACL_IS_INIT();
   1433 
   1434     for (list_link = _acl_control->head.next;
   1435          list_link != NULL;
   1436          list_link = list_link->next) {
   1437         BCM_IF_ERROR_RETURN(bcma_acl_list_show(list_link->list->list_id));
   1438     }
   1439 
   1440 #ifdef BCM_FIELD_SUPPORT
   1441     {
   1442     int retval_temp;
   1443     retval_temp = _acl_field_show();
   1444     ACL_RETVAL_REPLACE(retval_temp, retval);
   1445     }
   1446 #endif /* BCM_FIELD_SUPPORT */
   1447 
   1448     if (BCM_FAILURE(retval)) {
   1449         LOG_ERROR(BSL_LS_APPL_ACCESSCTRLLIST,
   1450                   (BSL_META("ACL Error: Device specific acl_show() failed\n")));
   1451         return retval;
   1452     }
   1453 
   1454     return BCM_E_NONE;
   1455 }
   1456 
   1457 #define ACL_SHOW_RANGE(rule, name, flag) do {                           \
   1458         if ((rule)->flags & (flag)) {                                   \
   1459             switch (flag) {                                             \
   1460             case BCMA_ACL_RULE_L4_SRC_PORT:                             \
   1461                 LOG_INFO(BSL_LS_APPL_ACCESSCTRLLIST,                    \
   1462                          (BSL_META("%s=%d-%d, "),                       \
   1463                           (name), (rule)->src_port_min,                 \
   1464                           (rule)->src_port_max));                       \
   1465                 break;                                                  \
   1466             case BCMA_ACL_RULE_L4_DST_PORT:                             \
   1467                 LOG_INFO(BSL_LS_APPL_ACCESSCTRLLIST,                    \
   1468                          (BSL_META("%s=%d-%d, "),                       \
   1469                           (name), (rule)->dst_port_min,                 \
   1470                           (rule)->dst_port_max));                       \
   1471                 break;                                                  \
   1472             case BCMA_ACL_RULE_VLAN:                                    \
   1473                 LOG_INFO(BSL_LS_APPL_ACCESSCTRLLIST,                    \
   1474                          (BSL_META("%s=%d-%d, "),                       \
   1475                           (name), (rule)->vlan_min,                     \
   1476                           (rule)->vlan_max));                           \
   1477                 break;                                                  \
   1478             }                                                           \
   1479         }                                                               \
   1480     } while (0)
   1481 
   1482 #define ACL_SHOW_MAC(rule, name, mac_str, flag) do {            \
   1483         if ((rule)->flags & (flag)) {                           \
   1484             if ((flag) == BCMA_ACL_RULE_SRC_MAC) {              \
   1485                 format_macaddr((mac_str), (rule)->src_mac);     \
   1486             } else if (flag == BCMA_ACL_RULE_DST_MAC) {         \
   1487                 format_macaddr((mac_str), (rule->dst_mac));     \
   1488             }                                                   \
   1489             LOG_INFO(BSL_LS_APPL_ACCESSCTRLLIST,                \
   1490                      (BSL_META("%s=%s, "),                      \
   1491                       (name), (mac_str)));                      \
   1492         }                                                       \
   1493     } while (0)
   1494 
   1495 #define ACL_SHOW_IP(rule, name, str_p, flag) do {               \
   1496         if ((rule)->flags & flag) {                             \
   1497             if (flag == BCMA_ACL_RULE_SRC_IP4) {                \
   1498                 format_ipaddr((str_p), (rule->src_ip));         \
   1499                 LOG_INFO(BSL_LS_APPL_ACCESSCTRLLIST,            \
   1500                          (BSL_META("%s=%s, "),                  \
   1501                           (name), (str_p)));                    \
   1502                 format_ipaddr((str_p), (rule->src_ip_mask));    \
   1503                 LOG_INFO(BSL_LS_APPL_ACCESSCTRLLIST,            \
   1504                          (BSL_META("%sMask=%s, "),              \
   1505                           (name), (str_p)));                    \
   1506             }                                                   \
   1507             if (flag == BCMA_ACL_RULE_DST_IP4) {                \
   1508                 format_ipaddr((str_p), (rule->dst_ip));         \
   1509                 LOG_INFO(BSL_LS_APPL_ACCESSCTRLLIST,            \
   1510                          (BSL_META("%s=%s, "),                  \
   1511                           (name), (str_p)));                    \
   1512                 format_ipaddr((str_p), (rule->dst_ip_mask));    \
   1513                 LOG_INFO(BSL_LS_APPL_ACCESSCTRLLIST,            \
   1514                          (BSL_META("%sMask=%s, "),              \
   1515                           (name), (str_p)));                    \
   1516             }                                                   \
   1517             if (flag == BCMA_ACL_RULE_SRC_IP6) {                \
   1518                 format_ip6addr((str_p), (rule->src_ip6));       \
   1519                 LOG_INFO(BSL_LS_APPL_ACCESSCTRLLIST,            \
   1520                          (BSL_META("%s=%s,\n"),                 \
   1521                           (name), (str_p)));                    \
   1522                 format_ip6addr((str_p), (rule->src_ip6_mask));  \
   1523                 LOG_INFO(BSL_LS_APPL_ACCESSCTRLLIST,            \
   1524                          (BSL_META("\t\t%sMask=%s, "),          \
   1525                           (name), (str_p)));                    \
   1526             }                                                   \
   1527             if (flag == BCMA_ACL_RULE_DST_IP6) {                \
   1528                 format_ip6addr((str_p), (rule->dst_ip6));       \
   1529                 LOG_INFO(BSL_LS_APPL_ACCESSCTRLLIST,            \
   1530                          (BSL_META("%s=%s,\n"),                 \
   1531                           (name), (str_p)));                    \
   1532                 format_ip6addr((str_p), (rule->dst_ip6_mask));  \
   1533                 LOG_INFO(BSL_LS_APPL_ACCESSCTRLLIST,            \
   1534                          (BSL_META("\t\t%sMask=%s, "),          \
   1535                           (name), (str_p)));                    \
   1536             }                                                   \
   1537         }                                                       \
   1538     } while (0)
   1539 
   1540 #define ACL_SHOW_ETHERTYPE(rule, name) do {                             \
   1541         if ((rule)->flags & (BCMA_ACL_RULE_ETHERTYPE)) {                \
   1542             LOG_INFO(BSL_LS_APPL_ACCESSCTRLLIST,                        \
   1543                      (BSL_META("%s=0x%04x, "),                          \
   1544                       (name), rule->ether_type));                       \
   1545         }                                                               \
   1546     } while (0)
   1547 
   1548 #define ACL_SEPARATOR(first_print) do {                                 \
   1549         if ((first_print) == 1) {                                       \
   1550             (first_print) = 0;                                          \
   1551         } else {                                                        \
   1552             LOG_INFO(BSL_LS_APPL_ACCESSCTRLLIST,                        \
   1553                      (BSL_META(", ")));                                 \
   1554         }                                                               \
   1555     } while (0)
   1556 
   1557 /*
   1558  * Function: bcma_acl_list_show
   1559  *
   1560  * Purpose:
   1561  *     Display a single access control list.
   1562  *
   1563  * Parameters:
   1564  *     list_id  - List ID
   1565  *
   1566  * Returns:
   1567  *     BCM_E_NONE      - Success
   1568  *     BCM_E_NOT_FOUND - List ID not found
   1569  *     BCM_E_XXX       - return value from bcma_acl_rule_show()
   1570  */
   1571 int
   1572 bcma_acl_list_show(bcma_acl_list_id_t list_id)
   1573 {
   1574     int                 count;
   1575     bcmx_lport_t        lport;
   1576     _acl_link_t         *list_link;
   1577     _acl_rule_link_t    *rule_link;
   1578     int                 first_print = TRUE;
   1579 
   1580     LOG_DEBUG(BSL_LS_APPL_ACCESSCTRLLIST,
   1581               (BSL_META("ACL bcma_acl_list_show(list_id=%d)\n"),
   1582                list_id));
   1583     ACL_IS_INIT();
   1584 
   1585     list_link = _acl_find(list_id);
   1586     if (list_link == NULL) {
   1587         LOG_ERROR(BSL_LS_APPL_ACCESSCTRLLIST,
   1588                   (BSL_META("ACL Error: list ID=%d not found\n"),
   1589                    list_id));
   1590         return BCM_E_NOT_FOUND;
   1591     }
   1592     LOG_INFO(BSL_LS_APPL_ACCESSCTRLLIST,
   1593              (BSL_META("acl={id=%d, lplist={"),
   1594               list_link->list->list_id));
   1595 
   1596     if ((BCMX_LPLIST_IS_EMPTY(&list_link->list->lplist))) {  
   1597         LOG_INFO(BSL_LS_APPL_ACCESSCTRLLIST,
   1598                  (BSL_META("None")));
   1599     } else {
   1600         count = BCMX_LPLIST_COUNT(&list_link->list->lplist);
   1601         BCMX_LPLIST_ITER(list_link->list->lplist, lport, count) {
   1602             if (first_print == TRUE) {
   1603                 LOG_INFO(BSL_LS_APPL_ACCESSCTRLLIST,
   1604                          (BSL_META("%d"),
   1605                           lport));
   1606                 first_print = FALSE;
   1607             } else {
   1608                 LOG_INFO(BSL_LS_APPL_ACCESSCTRLLIST,
   1609                         (BSL_META(", %d"),
   1610                          lport));
   1611             }
   1612         }
   1613     }
   1614 
   1615     LOG_INFO(BSL_LS_APPL_ACCESSCTRLLIST,
   1616              (BSL_META("}")));
   1617 
   1618     for (rule_link = list_link->rules;
   1619          rule_link != NULL;
   1620          rule_link = rule_link->next) {
   1621         LOG_INFO(BSL_LS_APPL_ACCESSCTRLLIST,
   1622                  (BSL_META("\n\t")));
   1623         BCM_IF_ERROR_RETURN(bcma_acl_rule_show(rule_link->rule));
   1624         LOG_INFO(BSL_LS_APPL_ACCESSCTRLLIST,
   1625                  (BSL_META(",")));
   1626     }
   1627     LOG_INFO(BSL_LS_APPL_ACCESSCTRLLIST,
   1628              (BSL_META("\n}\n")));
   1629 
   1630     return BCM_E_NONE;
   1631 }
   1632 
   1633 char *
   1634 _acl_ip_protocol_name(bcma_acl_ip_protocol_t ip_protocol)
   1635 {
   1636     return ip_protocol >= BCMA_ACL_IPPROTO_ANY ?
   1637                           "??" : bcma_acl_ip_protocol_text[ip_protocol];
   1638 }
   1639 
   1640 /*
   1641  * Function: bcma_acl_rule_show_id
   1642  *
   1643  * Purpose:
   1644  *     Display a single rule.
   1645  *
   1646  * Parameters:
   1647  *     rule_id  - Rule ID
   1648  *
   1649  * Returns:
   1650  *     BCM_E_NONE      - Success
   1651  *     BCM_E_NOT_FOUND - Rule ID not found
   1652  */
   1653 int
   1654 bcma_acl_rule_show_id(bcma_acl_rule_id_t rule_id)
   1655 {
   1656     _acl_rule_link_t    *rule_link;
   1657     
   1658     LOG_DEBUG(BSL_LS_APPL_ACCESSCTRLLIST,
   1659               (BSL_META("ACL bcma_acl_rule_show_id(rule_id=%d)\n"),
   1660                rule_id));
   1661     ACL_IS_INIT();
   1662 
   1663     rule_link = _acl_rule_find(rule_id);
   1664     if (rule_link == NULL) {
   1665         LOG_ERROR(BSL_LS_APPL_ACCESSCTRLLIST,
   1666                   (BSL_META("ACL Error: Rule ID=%d not found\n"),
   1667                    rule_id));
   1668         return BCM_E_NOT_FOUND;
   1669     }
   1670 
   1671     return bcma_acl_rule_show(rule_link->rule);
   1672 }
   1673 
   1674 /*
   1675  * Function: bcma_acl_rule_show
   1676  *
   1677  * Purpose:
   1678  *     Display a single rule given a pointer to the rule struct.
   1679  *
   1680  * Parameters:
   1681  *     rule - pointer to rule structure to be displayed
   1682  *
   1683  * Returns:
   1684  *     BCM_E_NONE      - Success
   1685  *     BCM_E_PARAM     - rule pointer is NULL
   1686  */
   1687 int
   1688 bcma_acl_rule_show(bcma_acl_rule_t *rule)
   1689 {
   1690     char            mac_str[MACADDR_STR_LEN + 3];
   1691     char            ip4_str[IPADDR_STR_LEN + 3];
   1692     char            ip6_str[IP6ADDR_STR_LEN + 3];
   1693 
   1694     LOG_DEBUG(BSL_LS_APPL_ACCESSCTRLLIST,
   1695               (BSL_META("ACL bcma_acl_rule_show(rule=%p)\n"),
   1696                (void *)rule));
   1697     ACL_IS_INIT();
   1698 
   1699     if (rule == NULL) {
   1700         LOG_ERROR(BSL_LS_APPL_ACCESSCTRLLIST,
   1701                   (BSL_META("ACL Error: null rule passed to bcma_acl_rule_show()\n")));
   1702         return BCM_E_PARAM;
   1703     }
   1704 
   1705     LOG_DEBUG(BSL_LS_APPL_ACCESSCTRLLIST,
   1706               (BSL_META("ACL bcma_acl_rule_show(rule_id=%d)\n"),
   1707                rule->rule_id));
   1708 
   1709     LOG_INFO(BSL_LS_APPL_ACCESSCTRLLIST,
   1710              (BSL_META("rule={id=%d, "),
   1711               rule->rule_id));
   1712 
   1713     LOG_VERBOSE(BSL_LS_APPL_ACCESSCTRLLIST,
   1714                 (BSL_META("flags=0x%03x, "),
   1715                  rule->flags));
   1716 
   1717     /* Show L4 source and destination port ranges. */
   1718     ACL_SHOW_RANGE(rule, "SrcPort", BCMA_ACL_RULE_L4_SRC_PORT);
   1719     ACL_SHOW_RANGE(rule, "DstPort", BCMA_ACL_RULE_L4_DST_PORT);
   1720 
   1721     /* Show Source and Destination MAC addresses. */
   1722     ACL_SHOW_MAC(rule, "SrcMac", mac_str, BCMA_ACL_RULE_SRC_MAC);
   1723     ACL_SHOW_MAC(rule, "DstMac", mac_str, BCMA_ACL_RULE_DST_MAC);
   1724 
   1725     /* Show Source IPv4 address */
   1726     ACL_SHOW_IP(rule, "SrcIp4", ip4_str, BCMA_ACL_RULE_SRC_IP4);
   1727 
   1728     /* Show Destination IPv4 address */
   1729     ACL_SHOW_IP(rule, "DstIp4", ip4_str, BCMA_ACL_RULE_DST_IP4);
   1730 
   1731     /* Show Source and Destination IPv6 addresses & masks. */
   1732     ACL_SHOW_IP(rule, "SrcIp6", ip6_str, BCMA_ACL_RULE_SRC_IP6);
   1733     ACL_SHOW_IP(rule, "DstIp6", ip6_str, BCMA_ACL_RULE_DST_IP6);
   1734 
   1735     /* Show Vlan range. */
   1736     ACL_SHOW_RANGE(rule, "Vlan", BCMA_ACL_RULE_VLAN);
   1737 
   1738     if (rule->ip_protocol != BCMA_ACL_IPPROTO_ANY) {
   1739         LOG_INFO(BSL_LS_APPL_ACCESSCTRLLIST,
   1740                  (BSL_META("IpProtocol=%s (%d), "),
   1741                   _acl_ip_protocol_name(rule->ip_protocol), rule->ip_protocol));
   1742     }
   1743     
   1744     /* Show EtherType. */
   1745     ACL_SHOW_ETHERTYPE(rule, "EtherType");
   1746 
   1747     bcma_acl_action_show(&rule->actions);
   1748     LOG_INFO(BSL_LS_APPL_ACCESSCTRLLIST,
   1749              (BSL_META("}")));
   1750 
   1751     return BCM_E_NONE;
   1752 }
   1753 
   1754 /*
   1755  * Function: bcma_acl_action_show
   1756  *
   1757  * Purpose:
   1758  *     Display a set of actions for a rule.
   1759  *
   1760  * Parameters:
   1761  *     action - pointer to action structure to be displayed
   1762  *
   1763  * Returns:
   1764  *     BCM_E_NONE      - Success
   1765  *     BCM_E_PARAM     - action pointer is NULL
   1766  */
   1767 int
   1768 bcma_acl_action_show(bcma_acl_action_t *action)
   1769 {
   1770     uint8               first_print = 1;
   1771 
   1772     LOG_DEBUG(BSL_LS_APPL_ACCESSCTRLLIST,
   1773               (BSL_META("ACL bcma_acl_action_show(action=%p)\n"),
   1774                (void *)action));
   1775     ACL_IS_INIT();
   1776 
   1777     if (action == NULL) {
   1778         LOG_ERROR(BSL_LS_APPL_ACCESSCTRLLIST,
   1779                   (BSL_META("ACL Error: null action passed to bcma_acl_action_show()\n")));
   1780         return BCM_E_PARAM;
   1781     }
   1782 
   1783     LOG_DEBUG(BSL_LS_APPL_ACCESSCTRLLIST,
   1784               (BSL_META("ACL bcma_acl_action_show(action=%p)\n"),
   1785                (void *)action));
   1786 
   1787     LOG_INFO(BSL_LS_APPL_ACCESSCTRLLIST,
   1788              (BSL_META("action={")));
   1789     LOG_VERBOSE(BSL_LS_APPL_ACCESSCTRLLIST,
   1790                 (BSL_META("flags=0x%x, "),
   1791                  action->flags));
   1792     if (action->flags & BCMA_ACL_ACTION_PERMIT) {
   1793         LOG_INFO(BSL_LS_APPL_ACCESSCTRLLIST,
   1794                  (BSL_META("Permit")));
   1795         first_print = 0;
   1796     }
   1797         
   1798     if (action->flags & BCMA_ACL_ACTION_DENY) {
   1799         ACL_SEPARATOR(first_print);
   1800         LOG_INFO(BSL_LS_APPL_ACCESSCTRLLIST,
   1801                  (BSL_META("Deny")));
   1802     }
   1803 
   1804     if (action->flags & BCMA_ACL_ACTION_LOG) {
   1805         ACL_SEPARATOR(first_print);
   1806         LOG_INFO(BSL_LS_APPL_ACCESSCTRLLIST,
   1807                  (BSL_META("Log")));
   1808     }
   1809 
   1810     if (action->flags & BCMA_ACL_ACTION_REDIR) {
   1811         ACL_SEPARATOR(first_print);
   1812         LOG_INFO(BSL_LS_APPL_ACCESSCTRLLIST,
   1813                  (BSL_META("Redirect={lport=%d}"),
   1814                   action->redir_port));
   1815     }
   1816 
   1817     if (action->flags & BCMA_ACL_ACTION_MIRROR) {
   1818         ACL_SEPARATOR(first_print);
   1819         LOG_INFO(BSL_LS_APPL_ACCESSCTRLLIST,
   1820                  (BSL_META("Mirror={lport=%d}"),
   1821                   action->mirror_port));
   1822     }
   1823 
   1824     LOG_INFO(BSL_LS_APPL_ACCESSCTRLLIST,
   1825              (BSL_META("}")));
   1826     return BCM_E_NONE;
   1827 }
   1828 #undef ACL_SEPARATOR
   1829 
   1830 #endif /* BROADCOM_DEBUG */
   1831 #endif /* INCLUDE_ACL */
   1832