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

auth.c (41814B)


      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  * 802.1X
      8  */
      9 
     10 #include <sal/core/libc.h>
     11 
     12 #include <soc/drv.h>
     13 
     14 #include <bcm/error.h>
     15 #include <bcm/auth.h>
     16 
     17 #include <bcm_int/esw/field.h> /* _bcm_field_setup_post_ethertype_udf() */
     18 #include <bcm_int/esw/port.h>
     19 
     20 #include <bcm_int/esw_dispatch.h>
     21 #if defined(BCM_KATANA2_SUPPORT)
     22 #include <bcm_int/esw/katana2.h>
     23 #endif
     24 
     25 #define AUTH_INIT(unit) \
     26         if (!SOC_UNIT_VALID(unit)) { return (BCM_E_UNIT); } \
     27         else if (!(soc_feature(unit, soc_feature_field))) { \
     28             return (BCM_E_UNAVAIL); \
     29         } \
     30         else if (NUM_E_PORT(unit) <= 0) { return (BCM_E_BADID); } \
     31         else if (auth_cntl[unit] == NULL) { return (BCM_E_INIT); }
     32 #define AUTH_INIT_NO_PORT(unit) \
     33         if (!SOC_UNIT_VALID(unit)) { return (BCM_E_UNIT); } \
     34         else if (!(soc_feature(unit, soc_feature_field))) { \
     35             return (BCM_E_UNAVAIL); \
     36         } \
     37         else if (auth_cntl[unit] == NULL) { return (BCM_E_INIT); }
     38 #define AUTH_PORT(unit, port) \
     39         if (!SOC_PORT_VALID(unit, port) || !IS_E_PORT(unit, port)) \
     40         { return (BCM_E_PORT); }
     41 
     42 #define AUTH_MODE_MASK \
     43         (BCM_AUTH_MODE_UNCONTROLLED | BCM_AUTH_MODE_AUTH | BCM_AUTH_MODE_UNAUTH)
     44 
     45 #define _AUTH_ETHERTYPE_EAPOL 0x888e
     46 #define _AUTH_ETHERTYPE_MASK  0xffff
     47 
     48 typedef struct auth_mac_s *auth_mac_p;
     49 
     50 typedef struct auth_mac_s {
     51     bcm_mac_t         mac;  
     52     bcm_field_entry_t entry;
     53     pbmp_t            pbmp;
     54     auth_mac_p        next;
     55 } auth_mac_t;
     56 
     57 typedef struct bcm_auth_cntl_s {
     58     int              mode;
     59     int              etmp;
     60     int              mac_set;
     61     auth_mac_t       *macList;
     62 } bcm_auth_cntl_t;
     63 
     64 typedef struct auth_cb_cntl_s {
     65     int             registered;
     66     bcm_auth_cb_t   auth_cbs;
     67     void            *auth_cb_data;
     68 } auth_cb_cntl_t;
     69 
     70 typedef struct auth_field_s {
     71     int               inited;
     72     int               count;
     73     bcm_field_group_t group0;
     74     auth_mac_t        *macList;
     75     bcm_field_group_t group1;
     76     bcm_field_entry_t entry1;
     77     bcm_field_group_t group2;
     78     bcm_field_entry_t entry2;
     79     pbmp_t            group2_pbmp;
     80 } auth_field_cntl_t;
     81 
     82 static bcm_auth_cntl_t *auth_cntl[BCM_MAX_NUM_UNITS];
     83 static auth_cb_cntl_t cb_cntl[BCM_MAX_NUM_UNITS];
     84 static auth_field_cntl_t fp_cntl[BCM_MAX_NUM_UNITS];
     85 
     86 /* Forward declarations */
     87 STATIC void _auth_linkscan_cb(int unit, bcm_port_t port, bcm_port_info_t *info);
     88 STATIC int _auth_field_install(int unit, int port, bcm_mac_t mac); 
     89 STATIC int _auth_field_remove(int unit, int port, bcm_mac_t mac); 
     90 STATIC int _auth_field_install_all(int unit, int port);
     91 STATIC int _auth_field_remove_all(int unit, int port);
     92 #if defined(BCM_FIELD_SUPPORT)
     93 STATIC int _auth_maclist_insert(auth_mac_t **list, bcm_mac_t mac, auth_mac_p *ins);
     94 STATIC int _auth_maclist_lookup(auth_mac_t **list, bcm_mac_t mac, auth_mac_p *entry);
     95 #endif /* !BCM_FIELD_SUPPORT */
     96 STATIC int _auth_maclist_remove(auth_mac_t **list, bcm_mac_t mac, auth_mac_p *del);
     97 STATIC int _auth_maclist_destroy(auth_mac_t **list);
     98 #ifdef AUTH_DEBUG
     99 STATIC int _auth_maclist_dump(auth_mac_t **list);
    100 #endif
    101 
    102 /*
    103  * Function:
    104  *	bcm_auth_init
    105  * Purpose:
    106  *	Initialize auth module.
    107  * Parameters:
    108  *	unit - Device number
    109  * Returns:
    110  *     BCM_E_NONE     - Success
    111  *     BCM_E_UNIT     - Invalid unit number
    112  *     BCM_E_UNAVAIL  - Insufficient hardware support
    113  *     BCM_E_MEMORY   - Allocation failure
    114  *
    115  * Notes:
    116  *	All ports are marked as being in the uncontrolled state.
    117  */
    118 
    119 int
    120 bcm_esw_auth_init(int unit)
    121 {
    122     bcm_port_t   port;
    123     int          rv = BCM_E_NONE, max_num_port = 0;
    124 
    125     if (!SOC_UNIT_VALID(unit)) {
    126         return BCM_E_UNIT;
    127     }
    128 
    129     if (!(soc_feature(unit, soc_feature_field))) {
    130         return (BCM_E_UNAVAIL);
    131     }
    132 
    133     if (auth_cntl[unit] != NULL) {
    134         rv = bcm_esw_auth_detach(unit);
    135         BCM_IF_ERROR_RETURN(rv);
    136     }
    137 
    138     max_num_port = SOC_MAX_NUM_PORTS;
    139 
    140 #ifdef BCM_KATANA2_SUPPORT
    141     if (soc_feature(unit, soc_feature_linkphy_coe) ||
    142         soc_feature(unit, soc_feature_subtag_coe)) {
    143         max_num_port = SOC_MAX_NUM_PP_PORTS;
    144     }
    145 #endif
    146 
    147     auth_cntl[unit] = sal_alloc(max_num_port * 
    148                                 sizeof(bcm_auth_cntl_t), "auth_cntl");
    149     if (auth_cntl[unit] == NULL) {
    150         return BCM_E_MEMORY;
    151     }
    152     sal_memset(auth_cntl[unit], 0, max_num_port * 
    153                sizeof(bcm_auth_cntl_t));
    154 
    155     for (port = 0; port < max_num_port; port++) {
    156         auth_cntl[unit][port].mode = BCM_AUTH_MODE_UNCONTROLLED;
    157         if (soc_feature(unit, soc_feature_field)) {
    158             BCM_IF_ERROR_RETURN(_auth_field_remove_all(unit, port));
    159         }
    160     }
    161     rv = bcm_esw_linkscan_register(unit, _auth_linkscan_cb);
    162     BCM_IF_ERROR_RETURN(rv);
    163     cb_cntl[unit].registered = TRUE;
    164 
    165     return BCM_E_NONE;
    166 }
    167 
    168 /*
    169  * Function:
    170  *	bcm_auth_detach
    171  * Purpose:
    172  *	Stop all auth module processing and deallocate resources.
    173  * Parameters:
    174  *	unit - Device number
    175  * Returns:
    176  *     BCM_E_NONE     - Success
    177  *     BCM_E_UNIT     - Invalid unit number
    178  *     BCM_E_UNAVAIL  - Insufficient hardware support
    179  * Notes:
    180  *	All ports are moved to the uncontrolled state.  All internal
    181  *	callbacks and filters are removed.
    182  */
    183 
    184 int
    185 bcm_esw_auth_detach(int unit)
    186 {
    187     bcm_port_t        port;
    188     int rv = BCM_E_NONE, max_num_port = 0;
    189     bcm_pbmp_t temp_pbmp;
    190     SOC_PBMP_CLEAR(temp_pbmp);
    191 
    192     if (soc_feature(unit, soc_feature_field) == 0 ||
    193         auth_cntl[unit] == NULL) { 
    194         return (BCM_E_NONE);
    195     } 
    196 
    197     AUTH_INIT_NO_PORT(unit);
    198 
    199     max_num_port = SOC_MAX_NUM_PORTS;
    200     BCM_PBMP_ASSIGN(temp_pbmp, PBMP_E_ALL(unit));
    201 
    202 #ifdef BCM_KATANA2_SUPPORT
    203     if (soc_feature(unit, soc_feature_linkphy_coe) ||
    204         soc_feature(unit, soc_feature_subtag_coe)) {
    205         _bcm_kt2_subport_pbmp_update(unit, &temp_pbmp);
    206 	max_num_port = SOC_MAX_NUM_PP_PORTS;
    207     }
    208 #endif
    209 
    210     if (0 == SOC_HW_ACCESS_DISABLE(unit)) {
    211         for (port = 0; port < max_num_port ; port++) {
    212             if (BCM_PBMP_MEMBER(temp_pbmp, port)) {
    213                 if (soc_feature(unit, soc_feature_field)) {
    214                     BCM_IF_ERROR_RETURN(_auth_field_remove_all(unit, port));
    215                 }
    216                 _auth_maclist_destroy(&auth_cntl[unit][port].macList);
    217                 bcm_esw_port_learn_set(unit, port, 
    218                                        BCM_PORT_LEARN_ARL | BCM_PORT_LEARN_FWD);
    219                 bcm_esw_port_stp_set(unit, port, BCM_STG_STP_FORWARD);
    220                 auth_cntl[unit][port].mode = BCM_AUTH_MODE_UNCONTROLLED;
    221                 auth_cntl[unit][port].etmp = FALSE;
    222             }
    223         }
    224     }
    225 
    226     for (port = 0; port < max_num_port; port++) {
    227         _auth_maclist_destroy(&auth_cntl[unit][port].macList);
    228     }
    229 
    230     fp_cntl[unit].inited = FALSE;
    231     fp_cntl[unit].count = 0;
    232 
    233     if (cb_cntl[unit].registered) {
    234         rv = bcm_esw_linkscan_unregister(unit, _auth_linkscan_cb); 
    235         /* If linkscan thread was restarted callback might be gone. */
    236         if ((BCM_FAILURE(rv)) && (BCM_E_NOT_FOUND != rv)) {
    237             return (rv);
    238         }
    239         cb_cntl[unit].registered = FALSE;
    240     }
    241     sal_free(auth_cntl[unit]);
    242     auth_cntl[unit] = NULL;
    243     return BCM_E_NONE;
    244 }
    245 
    246 /*
    247  * Function:
    248  *	bcm_auth_mode_set
    249  * Purpose:
    250  *	Set the 802.1X operating mode
    251  * Parameters:
    252  *	unit - Device number
    253  *	port - Port number, -1 to set all non-stack-ports
    254  *	mode - One of BCM_AUTH_MODE_XXX and other flags (see below)
    255  * Returns:
    256  *     BCM_E_NONE     - Success
    257  *     BCM_E_UNIT     - Invalid unit number
    258  *     BCM_E_UNAVAIL  - Insufficient hardware support
    259  *     BCM_E_PORT     - Invalid port
    260  * Notes:
    261  *	While in the uncontrolled state, any packets may flow in or out
    262  *	of the port and normal L2 learning takes place.
    263  *
    264  *	If mode is BCM_AUTH_UNAUTH, a set of flags may be ORed into
    265  *	the mode word:
    266  *		BCM_AUTH_BLOCK_IN	allow outgoing packets
    267  *		BCM_AUTH_BLOCK_INOUT	do not allow in or out packets
    268  *					(default)
    269  *	While in the unauthorized state, all L2 MAC addresses
    270  *	associated with the port are removed, L2 learning is disabled,
    271  *	and packet transfer is blocked as specified by the
    272  *	BCM_AUTH_BLOCK_* flags.  Incoming EAPOL frames are allowed
    273  *	either addressed as BPDUs or to the switch CPU's MAC address.
    274  *	Some hardware may forward all EAPOL frames regardless of the
    275  *	destination MAC address.  These will be delivered to the CPU
    276  *	for processing.
    277  *
    278  *	Outgoing EAPOL frames to be sent must be sent with a pair of
    279  *	bcm_auth_egress_set calls, enabling the egress before the
    280  *	EAPOL packet and disabling the egress after the packet is
    281  *	sent.  If the BCM_AUTH_BLOCK_IN flag has been given, then the
    282  *	bcm_auth_egress_set calls will not do anything.
    283  *
    284  *	If mode is BCM_AUTH_MODE_AUTH, a set of flags may be ORed into 
    285  *      the mode word:
    286  *		BCM_AUTH_LEARN		allow L2 learning while authorized
    287  *		BCM_AUTH_IGNORE_LINK	do not unauthorize upon link down
    288  *		BCM_AUTH_IGNORE_VIOLATION do not unauth upon security
    289  *					 violation
    290  *	After moving the port to the authorized state, one or more
    291  *	static L2 entries may be added using bcm_l2_addr_add with the
    292  *	auth field set.  These L2 addresses would typically be for
    293  *	the source MAC address of the requesting EAPOL frame that was
    294  *	authorized, in as many VLANs as are configured for the
    295  *	authorized user.
    296  *
    297  *	While in the authorized state, any packets incoming from source
    298  *	MAC addresses set by bcm_l2_addr_add will be accepted for
    299  *	transfer.  Any other source MAC addresses will be accepted if
    300  *	BCM_AUTH_LEARN was set.  If BCM_AUTH_LEARN was not set and the
    301  *	hardware supports it and BCM_AUTH_IGNORE_VIOLATION is not set,
    302  *	then unknown source MAC addresses will cause a security
    303  *	violation and move the port to the unauthorized state.
    304  *
    305  *	If the link goes down on the port while in the authorized
    306  *	state and BCM_AUTH_IGNORE_LINK is not set, then the port will
    307  *	be moved to the unauthorized state.
    308  */
    309 
    310 int
    311 bcm_esw_auth_mode_set(int unit, int port, uint32 mode)
    312 {
    313     pbmp_t   pbmp;
    314     bcm_port_t p;
    315 
    316     AUTH_INIT(unit);
    317 
    318     if (port < 0) { 
    319         BCM_PBMP_ASSIGN(pbmp, PBMP_E_ALL(unit));
    320 #ifdef BCM_KATANA2_SUPPORT
    321         if (soc_feature(unit, soc_feature_linkphy_coe) ||
    322             soc_feature(unit, soc_feature_subtag_coe)) {
    323             _bcm_kt2_subport_pbmp_update(unit, &pbmp);
    324         }
    325 #endif
    326     } else { /* port >= 0 */
    327         BCM_IF_ERROR_RETURN(_bcm_esw_port_gport_validate(unit, port, &port));
    328         AUTH_PORT(unit, port);
    329         BCM_PBMP_PORT_SET(pbmp, port);
    330     }
    331 
    332     /* Remove stack ports from bitmap */
    333     BCM_PBMP_REMOVE(pbmp, SOC_PBMP_STACK_CURRENT(unit));
    334 
    335     BCM_PBMP_ITER(pbmp, p) {
    336         switch (mode & AUTH_MODE_MASK) {
    337         case BCM_AUTH_MODE_UNCONTROLLED:
    338             if (soc_feature(unit, soc_feature_field)) {
    339                 BCM_IF_ERROR_RETURN(_auth_field_remove_all(unit, p));
    340             }
    341             bcm_esw_port_learn_set(unit, p, BCM_PORT_LEARN_ARL |
    342                                    BCM_PORT_LEARN_FWD);
    343             bcm_esw_port_stp_set(unit, p, BCM_STG_STP_FORWARD);
    344             auth_cntl[unit][p].etmp = FALSE;
    345             break;
    346         case BCM_AUTH_MODE_UNAUTH:
    347             /* Disable learning on that port */
    348             bcm_esw_port_learn_set(unit, p, BCM_PORT_LEARN_FWD);
    349 
    350             /* remove all L2 (MAC) addresses associated with the port */
    351             bcm_esw_l2_addr_delete_by_port(unit, -1, p, BCM_L2_DELETE_STATIC);
    352 
    353             if (mode & BCM_AUTH_BLOCK_IN) {
    354                 if (soc_feature(unit, soc_feature_field)) {
    355                     BCM_IF_ERROR_RETURN(_auth_field_install_all(unit, p)); 
    356                 }
    357                 /* Set STP state as forward for BLOCK_IN */
    358                 BCM_IF_ERROR_RETURN(bcm_esw_port_stp_set(unit, p,
    359                                                          BCM_STG_STP_FORWARD));
    360             }
    361             else {
    362                 /* unauthorized for both directions */
    363                 if (soc_feature(unit, soc_feature_field)) {
    364                     BCM_IF_ERROR_RETURN(_auth_field_remove_all(unit, p));
    365                 }
    366                 mode |= BCM_AUTH_BLOCK_INOUT;
    367                 BCM_IF_ERROR_RETURN(bcm_esw_port_stp_set(unit, p,
    368                                                          BCM_STG_STP_BLOCK));
    369             }
    370             break;
    371         case BCM_AUTH_MODE_AUTH:
    372             /* Invalid for both hardware learning and SLF dropping */
    373             if ((mode & (BCM_AUTH_LEARN | BCM_AUTH_DROP_UNKNOWN)) ==
    374                (BCM_AUTH_LEARN | BCM_AUTH_DROP_UNKNOWN)) {
    375                 return BCM_E_PARAM;    
    376             }
    377             if (mode & BCM_AUTH_DROP_UNKNOWN) {
    378                 /* Drop the packet */
    379                 bcm_esw_port_learn_set(unit, p, 0);
    380             } else {
    381                 /* No learn, Send to CPU, Drop the packet */
    382                 bcm_esw_port_learn_set(unit, p, BCM_PORT_LEARN_CPU);
    383             }
    384             if (soc_feature(unit, soc_feature_field)) {
    385                 BCM_IF_ERROR_RETURN(_auth_field_remove_all(unit, p));
    386             }
    387             bcm_esw_port_stp_set(unit, p, BCM_STG_STP_FORWARD);
    388             if (mode & BCM_AUTH_LEARN) {
    389                 bcm_esw_port_learn_set(unit, p, BCM_PORT_LEARN_ARL
    390                                        | BCM_PORT_LEARN_FWD);
    391             }
    392             auth_cntl[unit][p].etmp = FALSE;
    393             break;
    394         default:
    395             return BCM_E_PARAM;
    396         }
    397         auth_cntl[unit][p].mode = mode;
    398     }
    399 
    400     return BCM_E_NONE;
    401 }
    402 
    403 /*
    404  * Function:
    405  *	bcm_auth_mode_get
    406  * Purpose:
    407  *	Get the 802.1X operating mode
    408  * Parameters:
    409  *	unit - Device number
    410  *	port - Port number
    411  *	mode - (OUT) One of BCM_AUTH_MODE_XXX and other flags
    412  * Returns:
    413  *     BCM_E_NONE     - Success
    414  *     BCM_E_UNIT     - Invalid unit number
    415  *     BCM_E_UNAVAIL  - Insufficient hardware support
    416  *     BCM_E_PORT     - Invalid port
    417  * Notes:
    418  */
    419 
    420 int
    421 bcm_esw_auth_mode_get(int unit, int port, uint32 *modep)
    422 {
    423 
    424     AUTH_INIT(unit);
    425     BCM_IF_ERROR_RETURN(_bcm_esw_port_gport_validate(unit, port, &port));
    426     AUTH_PORT(unit, port);
    427 
    428     *modep = auth_cntl[unit][port].mode;
    429 
    430     return BCM_E_NONE;
    431 }
    432 
    433 /*
    434  * Function:
    435  *	bcm_auth_unauth_callback
    436  * Purpose:
    437  *	Set the callback function for 802.1X notifications
    438  * Parameters:
    439  *	unit - Device number
    440  *	func - Callback function
    441  *	cookie - Arbitrary value passed along to callback function
    442  * Returns:
    443  *     BCM_E_NONE     - Success
    444  *     BCM_E_UNIT     - Invalid unit number
    445  *     BCM_E_UNAVAIL  - Insufficient hardware support
    446  * Notes:
    447  *	Calls func when a port on the unit has been moved from
    448  *	authorized to unauthorized state.  Reason can be one of:
    449  *		BCM_AUTH_REASON_UNKNOWN
    450  *		BCM_AUTH_REASON_LINK
    451  *		BCM_AUTH_REASON_VIOLATION
    452  */
    453 
    454 int
    455 bcm_esw_auth_unauth_callback(int unit, bcm_auth_cb_t func, void *cookie)
    456 {
    457     AUTH_INIT_NO_PORT(unit);
    458 
    459     cb_cntl[unit].auth_cbs = func;
    460     cb_cntl[unit].auth_cb_data = cookie;
    461 
    462     return BCM_E_NONE;
    463 }
    464 
    465 /*
    466  * Function:
    467  *	bcm_auth_egress_set
    468  * Purpose:
    469  *	Enable/disable the ability of packets to be sent out a port.
    470  * Parameters:
    471  *	unit - Device number
    472  *	port - Port number
    473  *	enable - TRUE to enable, FALSE to disable
    474  * Returns:
    475  *     BCM_E_NONE     - Success
    476  *     BCM_E_UNIT     - Invalid unit number
    477  *     BCM_E_UNAVAIL  - Insufficient hardware support
    478  *     BCM_E_PORT     - Invalid port
    479  * Notes:
    480  *	This call should only be used around calls that a CPU uses to
    481  *	transmit an EAPOL frame out the port.  If the port is in an
    482  *	unauthorized state with BCM_AUTH_BLOCK_IN set or is not in an
    483  *	unauthorized state, then this call does nothing.
    484  */
    485 
    486 int
    487 bcm_esw_auth_egress_set(int unit, int port, int enable)
    488 {
    489     AUTH_INIT(unit);
    490 
    491     BCM_IF_ERROR_RETURN(_bcm_esw_port_gport_validate(unit, port, &port));
    492     AUTH_PORT(unit, port);
    493 
    494     if (enable) {
    495        if ((auth_cntl[unit][port].mode & BCM_AUTH_MODE_UNAUTH) &&
    496            !(auth_cntl[unit][port].mode & BCM_AUTH_BLOCK_IN)) {
    497            bcm_esw_port_stp_set(unit, port, BCM_STG_STP_FORWARD);
    498            if (soc_feature(unit, soc_feature_field)) {
    499                _auth_field_install_all(unit, port); 
    500            }
    501            auth_cntl[unit][port].mode &= ~BCM_AUTH_BLOCK_INOUT;
    502            auth_cntl[unit][port].mode |= BCM_AUTH_BLOCK_IN;
    503            auth_cntl[unit][port].etmp= TRUE;
    504        }
    505     }
    506     else {
    507        if ((auth_cntl[unit][port].mode & BCM_AUTH_MODE_UNAUTH) &&
    508            (auth_cntl[unit][port].mode & BCM_AUTH_BLOCK_IN)) {
    509            if (soc_feature(unit, soc_feature_field)) {
    510                BCM_IF_ERROR_RETURN(_auth_field_remove_all(unit, port)); 
    511            }
    512            bcm_esw_port_stp_set(unit, port, BCM_STG_STP_BLOCK);
    513            auth_cntl[unit][port].mode &= ~BCM_AUTH_BLOCK_IN;
    514            auth_cntl[unit][port].mode |= BCM_AUTH_BLOCK_INOUT;
    515            auth_cntl[unit][port].etmp= FALSE;
    516        
    517        }
    518     }
    519 
    520     return BCM_E_NONE;
    521 }
    522 
    523 /*
    524  * Function:
    525  *	bcm_auth_egress_get
    526  * Purpose:
    527  *	Return enable/disable state of packets being sent out a port.
    528  * Parameters:
    529  *	unit - Device number
    530  *	port - Port number
    531  *	enable - (OUT) TRUE if enabled, FALSE if disabled
    532  * Returns:
    533  *     BCM_E_NONE     - Success
    534  *     BCM_E_UNIT     - Invalid unit number
    535  *     BCM_E_UNAVAIL  - Insufficient hardware support
    536  *     BCM_E_PORT     - Invalid port
    537  * Notes:
    538  */
    539 
    540 int
    541 bcm_esw_auth_egress_get(int unit, int port, int *enable)
    542 {
    543     AUTH_INIT(unit);
    544 
    545     BCM_IF_ERROR_RETURN(_bcm_esw_port_gport_validate(unit, port, &port));
    546     AUTH_PORT(unit, port);
    547 
    548     *enable = auth_cntl[unit][port].etmp;
    549 
    550     return BCM_E_NONE;
    551 }
    552 
    553 /*
    554  * Function:
    555  *      bcm_auth_mac_add
    556  * Purpose:
    557  *      Add switch's MAC addresses 
    558  * Parameters:
    559  *      unit - Device number
    560  *	port - Port number, -1 to all ports
    561  *      mac -  Switch's MAC address
    562  * Returns:
    563  *     BCM_E_NONE     - Success
    564  *     BCM_E_UNIT     - Invalid unit number
    565  *     BCM_E_UNAVAIL  - Insufficient hardware support
    566  *     BCM_E_PORT     - Invalid port
    567  *     BCM_E_PARAM    - bad mac
    568  * Notes:
    569  */
    570 
    571 int
    572 bcm_esw_auth_mac_add(int unit, int port, bcm_mac_t mac)
    573 {
    574     bcm_mac_t mac_zero = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 
    575     bcm_mac_t mac_resv = {0x01, 0x80, 0xc2, 0x00, 0x00, 0x03}; 
    576     pbmp_t   pbm;
    577 #if defined(BCM_FIELD_SUPPORT)
    578     auth_mac_p entry = NULL;
    579     int rv;
    580     bcm_port_t p;
    581 #endif /* BCM_FIELD_SUPPORT */
    582 
    583     AUTH_INIT(unit);
    584 
    585     if ((!sal_memcmp(mac, mac_zero, sizeof(bcm_mac_t))) ||
    586         (!sal_memcmp(mac, mac_resv, sizeof(bcm_mac_t)))) { 
    587         return BCM_E_PARAM;
    588     }
    589 
    590     if (port < 0) { 
    591         BCM_PBMP_ASSIGN(pbm, PBMP_E_ALL(unit));
    592 #ifdef BCM_KATANA2_SUPPORT
    593         if (soc_feature(unit, soc_feature_linkphy_coe) ||
    594             soc_feature(unit, soc_feature_subtag_coe)) {
    595             _bcm_kt2_subport_pbmp_update(unit, &pbm);
    596         }
    597 #endif
    598     } else { /* port >= 0 */
    599         BCM_IF_ERROR_RETURN(_bcm_esw_port_gport_validate(unit, port, &port));
    600         AUTH_PORT(unit, port);
    601 
    602         BCM_PBMP_PORT_SET(pbm, port);
    603     }
    604 
    605 #if defined(BCM_FIELD_SUPPORT)
    606     BCM_PBMP_ITER(pbm, p) {
    607         if ((rv = _auth_maclist_insert(&auth_cntl[unit][p].macList, 
    608                                        mac, &entry)) < 0) {
    609             return rv;
    610         }
    611 
    612         if (auth_cntl[unit][p].mac_set) {
    613             if (soc_feature(unit, soc_feature_field)) {
    614 #ifdef BCM_FIELD_SUPPORT
    615                 if ((rv = _auth_field_install(unit, p, mac)) < 0) {
    616                     _auth_maclist_remove(&auth_cntl[unit][p].macList, 
    617                                          mac, &entry);    
    618                     sal_free(entry);
    619                     return rv;
    620                 }
    621 #endif /* BCM_FIELD_SUPPORT */
    622             }
    623         }
    624     }
    625    
    626     return BCM_E_NONE;
    627 #else /* !BCM_FIELD_SUPPORT */
    628     return BCM_E_UNAVAIL;
    629 #endif /* !BCM_FIELD_SUPPORT */
    630 }
    631 
    632 /*
    633  * Function:
    634  *      bcm_auth_mac_delete
    635  * Purpose:
    636  *      Delete switch's MAC address.
    637  * Parameters:
    638  *      unit - Device number
    639  *      port - Port number
    640  *      mac  - Switch's MAC address 
    641  * Returns:
    642  *     BCM_E_NONE       - Success
    643  *     BCM_E_UNIT       - Invalid unit number
    644  *     BCM_E_UNAVAIL    - Insufficient hardware support
    645  *     BCM_E_PORT       - Invalid port
    646  *     BCM_E_PARAM      - bad mac
    647  *     BCM_E_NOT_FOUND  - MAC address not found
    648  * Notes:
    649  */
    650 
    651 int
    652 bcm_esw_auth_mac_delete(int unit, int port, bcm_mac_t mac)
    653 {
    654     auth_mac_p entry = NULL;
    655     int rv;
    656 
    657     AUTH_INIT(unit);
    658 
    659     BCM_IF_ERROR_RETURN(_bcm_esw_port_gport_validate(unit, port, &port));
    660     AUTH_PORT(unit, port);
    661 
    662     rv = _auth_maclist_remove(&auth_cntl[unit][port].macList, mac, &entry);
    663 
    664     if (rv < 0) {
    665         return rv;
    666     }
    667 
    668     if (auth_cntl[unit][port].mac_set) {
    669         if (soc_feature(unit, soc_feature_field)) {
    670             BCM_IF_ERROR_RETURN(_auth_field_remove(unit, port, mac)); 
    671         }
    672     }
    673 
    674     sal_free(entry);
    675     
    676     return BCM_E_NONE;
    677 }
    678 
    679 /*
    680  * Function:
    681  *      bcm_auth_mac_delete_all
    682  * Purpose:
    683  *      Delete all switch's MAC addresses.
    684  * Parameters:
    685  *      unit - Device number
    686  *	port - Port number 
    687  * Returns:
    688  *      BCM_E_XXX
    689  * Notes:
    690  */
    691 
    692 int
    693 bcm_esw_auth_mac_delete_all(int unit, int port)
    694 {
    695     int tmp, rv;
    696 
    697     AUTH_INIT(unit);
    698 
    699     BCM_IF_ERROR_RETURN(_bcm_esw_port_gport_validate(unit, port, &port));
    700     AUTH_PORT(unit, port);
    701 
    702     tmp = auth_cntl[unit][port].mac_set;
    703     if (soc_feature(unit, soc_feature_field)) {
    704         BCM_IF_ERROR_RETURN(_auth_field_remove_all(unit, port));
    705     }
    706     rv = _auth_maclist_destroy(&auth_cntl[unit][port].macList);
    707     auth_cntl[unit][port].mac_set = tmp;
    708 
    709     return rv;
    710 }
    711 
    712 /*
    713  * Function:
    714  *      _auth_linkscan_cb
    715  * Description:
    716  *      Put authorized state to unauthorized state if link down,
    717  *      given BCM_AUTH_IGNORE_LINK not set
    718  * Parameters:
    719  *      unit - Device number
    720  *      port - Port number
    721  *      info - pointer to structure giving status
    722  * Returns:
    723  *      None
    724  * Notes:
    725  */
    726 
    727 STATIC void
    728 _auth_linkscan_cb(int unit, bcm_port_t port, bcm_port_info_t *info)
    729 {
    730     if ((auth_cntl[unit] != NULL) && (IS_E_PORT(unit, port))
    731         && !(auth_cntl[unit][port].mode & BCM_AUTH_MODE_UNCONTROLLED)) {
    732         if (info->linkstatus != BCM_PORT_LINK_STATUS_UP) {
    733             if ((auth_cntl[unit][port].mode & BCM_AUTH_MODE_AUTH) &&
    734                 !(auth_cntl[unit][port].mode & BCM_AUTH_IGNORE_LINK)) {
    735                 bcm_esw_auth_mode_set(unit, port, BCM_AUTH_MODE_UNAUTH);
    736                 if (cb_cntl[unit].auth_cbs) {
    737                     cb_cntl[unit].auth_cbs(cb_cntl[unit].auth_cb_data,
    738                                   unit, port, BCM_AUTH_REASON_LINK);
    739                 }
    740             }
    741         }
    742     }
    743 }
    744 
    745 /*
    746  * Function:
    747  *      _auth_field_install
    748  * Description:
    749  *      Install FP for accepting EAPOL frames
    750  *      destinated for switch CPU's MAC address
    751  * Parameters:
    752  *      unit - Device number
    753  *      port - Port number
    754  *      mac -  MAC address
    755  * Returns:
    756  *      BCM_E_XXX
    757  * Notes:
    758  */
    759 
    760 STATIC int
    761 _auth_field_install(int unit, int port, bcm_mac_t mac) 
    762 {
    763 #ifdef BCM_FIELD_SUPPORT
    764     _field_stage_t         *stage_fc=NULL;  /* Stage Field control structure.   */
    765     bcm_port_config_t      pc;              /* Port Configuration structure.    */
    766     bcm_field_group_config_t fg0;           /* Group configuration structure.   */
    767     bcm_field_group_config_t fg2;           /* Group configuration structure.   */
    768     int                    instance=0;      /* Pipe instance.                   */
    769     bcm_pbmp_t             mask_pbmp;       /* IPBM mask.                       */
    770     int rv = BCM_E_NONE;
    771     int rv2 = BCM_E_NONE;
    772     pbmp_t   pbm;
    773     bcm_field_group_t group0;
    774     bcm_field_entry_t entry0;
    775     bcm_mac_t mac_all_ones;
    776     auth_mac_p entry = NULL;
    777 
    778     /* In Tomahawk, In global mode, Group is created with port bitmaps of all pipes. 
    779      * In PerPipe mode, Group is created with port bitmaps of only the 
    780      * pipe to which the input port belongs to.
    781      */
    782     BCM_IF_ERROR_RETURN(_field_stage_control_get(unit, _BCM_FIELD_STAGE_INGRESS, &stage_fc));
    783     
    784     bcm_port_config_t_init(&pc);
    785     BCM_IF_ERROR_RETURN(bcm_esw_port_config_get(unit, &pc));
    786 
    787     bcm_field_group_config_t_init(&fg0);
    788     bcm_field_group_config_t_init(&fg2);
    789     instance = SOC_INFO(unit).port_pipe[port];   
    790     mask_pbmp = PBMP_E_ALL(unit); 
    791 
    792     if (SOC_IS_TOMAHAWKX(unit)) {
    793         switch (stage_fc->oper_mode) {
    794             case bcmFieldGroupOperModeGlobal:
    795                 break;
    796             case bcmFieldGroupOperModePipeLocal:
    797                 fg0.ports = pc.per_pipe[instance];
    798                 fg0.flags |= BCM_FIELD_GROUP_CREATE_WITH_PORT; 
    799                 fg2.ports = pc.per_pipe[instance];
    800                 fg2.flags |= BCM_FIELD_GROUP_CREATE_WITH_PORT;
    801                 mask_pbmp = PBMP_PIPE(unit,instance);
    802                 break;
    803             default: 
    804                 return (BCM_E_INTERNAL);
    805         }
    806     }
    807            
    808     sal_memset(mac_all_ones, 0xff, sizeof(bcm_mac_t));
    809 
    810     if (!fp_cntl[unit].inited) {
    811         bcm_field_group_t group2;
    812         bcm_field_entry_t entry2;
    813 
    814         BCM_FIELD_QSET_INIT(fg0.qset);
    815         if (soc_feature(unit, soc_feature_ifp_no_inports_support)) {
    816             BCM_FIELD_QSET_ADD(fg0.qset, bcmFieldQualifyInPort);
    817         } else {
    818             BCM_FIELD_QSET_ADD(fg0.qset, bcmFieldQualifyInPorts);
    819         }
    820         BCM_FIELD_QSET_ADD(fg0.qset, bcmFieldQualifyDstMac);
    821         BCM_FIELD_QSET_ADD(fg0.qset, bcmFieldQualifyEtherType);
    822 
    823         fg0.priority = 14;
    824         BCM_IF_ERROR_RETURN(bcm_esw_field_group_config_create(unit, &fg0));
    825         group0 = fg0.group;
    826 
    827         BCM_IF_ERROR_RETURN(
    828             bcm_esw_field_entry_create(unit, group0, &entry0));
    829         BCM_PBMP_PORT_SET(pbm, port);
    830         if (soc_feature(unit, soc_feature_ifp_no_inports_support)) {
    831             BCM_IF_ERROR_RETURN(
    832                 bcm_esw_field_qualify_InPort(unit, entry0, port, -1));
    833         } else {
    834             BCM_IF_ERROR_RETURN(
    835                 bcm_esw_field_qualify_InPorts(unit, entry0, pbm, mask_pbmp));
    836         }
    837         BCM_IF_ERROR_RETURN(
    838             bcm_esw_field_qualify_DstMac(unit, entry0, mac, 
    839                                      (uint8 *)mac_all_ones));
    840         BCM_IF_ERROR_RETURN(
    841             bcm_esw_field_qualify_EtherType(unit, entry0, _AUTH_ETHERTYPE_EAPOL,
    842                                         _AUTH_ETHERTYPE_MASK));
    843         BCM_IF_ERROR_RETURN(
    844             bcm_esw_field_action_add(unit, entry0, bcmFieldActionCopyToCpu, 0, 0));
    845 
    846         BCM_FIELD_QSET_INIT(fg2.qset);
    847         if (soc_feature(unit, soc_feature_ifp_no_inports_support)) {
    848             BCM_FIELD_QSET_ADD(fg2.qset, bcmFieldQualifyInPort);
    849         } else {
    850             BCM_FIELD_QSET_ADD(fg2.qset, bcmFieldQualifyInPorts);
    851         }
    852 
    853         fg2.priority = 13;
    854         BCM_IF_ERROR_RETURN(bcm_esw_field_group_config_create(unit, &fg2));
    855         group2 = fg2.group;
    856 
    857         BCM_IF_ERROR_RETURN(
    858             bcm_esw_field_entry_create(unit, group2, &entry2));
    859         if (soc_feature(unit, soc_feature_ifp_no_inports_support)) {
    860             BCM_IF_ERROR_RETURN(
    861                 bcm_esw_field_qualify_InPort(unit, entry2, port, -1));
    862         } else {
    863             BCM_IF_ERROR_RETURN(
    864                 bcm_esw_field_qualify_InPorts(unit, entry2, pbm, mask_pbmp));
    865         }
    866 
    867         BCM_IF_ERROR_RETURN(
    868             bcm_esw_field_action_add(unit, entry2, bcmFieldActionDrop, 0, 0));
    869 
    870         rv = bcm_esw_field_entry_install(unit, entry0);
    871         rv2 = bcm_esw_field_entry_install(unit, entry2);
    872         if (BCM_FAILURE(rv) || BCM_FAILURE(rv2)) {
    873             BCM_IF_ERROR_RETURN(bcm_esw_field_entry_remove(unit, entry0));
    874             BCM_IF_ERROR_RETURN(bcm_esw_field_entry_destroy(unit, entry0));
    875             BCM_IF_ERROR_RETURN(bcm_esw_field_group_destroy(unit, group0));
    876             BCM_IF_ERROR_RETURN(bcm_esw_field_entry_remove(unit, entry2));
    877             BCM_IF_ERROR_RETURN(bcm_esw_field_entry_destroy(unit, entry2));
    878             BCM_IF_ERROR_RETURN(bcm_esw_field_group_destroy(unit, group2));
    879             return (rv != BCM_E_NONE ? rv : rv2);
    880         }
    881 
    882         fp_cntl[unit].group0 = group0;
    883         rv2 = _auth_maclist_insert(&fp_cntl[unit].macList, mac, &entry);
    884         if (rv2 == BCM_E_NONE) {
    885             entry->entry = entry0;
    886             BCM_PBMP_PORT_SET(entry->pbmp, port);
    887         }
    888         fp_cntl[unit].group2 = group2;
    889         fp_cntl[unit].entry2 = entry2;
    890         BCM_PBMP_PORT_SET(fp_cntl[unit].group2_pbmp, port);
    891         fp_cntl[unit].inited = TRUE; 
    892         fp_cntl[unit].count++; 
    893     } else {
    894         if ((rv = _auth_maclist_lookup(&fp_cntl[unit].macList, mac, &entry)) > 0) {
    895             BCM_FIELD_QSET_INIT(fg0.qset);
    896             if (soc_feature(unit, soc_feature_ifp_no_inports_support)) {
    897                 BCM_FIELD_QSET_ADD(fg0.qset, bcmFieldQualifyInPort);
    898             } else {
    899                 BCM_FIELD_QSET_ADD(fg0.qset, bcmFieldQualifyInPorts);
    900             }
    901             pbm = entry->pbmp; 
    902             BCM_PBMP_PORT_ADD(pbm, port);
    903             if (soc_feature(unit, soc_feature_ifp_no_inports_support)) {
    904                 BCM_IF_ERROR_RETURN(
    905                     bcm_esw_field_qualify_InPort(unit, entry->entry, port, -1)); 
    906             } else {
    907                 BCM_IF_ERROR_RETURN(
    908                     bcm_esw_field_qualify_InPorts(unit, entry->entry, pbm, 
    909                                             mask_pbmp));
    910             }
    911             BCM_IF_ERROR_RETURN(
    912                 bcm_esw_field_entry_reinstall(unit, entry->entry));
    913             entry->pbmp = pbm;
    914         } else {
    915             BCM_FIELD_QSET_INIT(fg0.qset);
    916             if (soc_feature(unit, soc_feature_ifp_no_inports_support)) {
    917                 BCM_FIELD_QSET_ADD(fg0.qset, bcmFieldQualifyInPort);
    918             } else {
    919                 BCM_FIELD_QSET_ADD(fg0.qset, bcmFieldQualifyInPorts);
    920             }
    921             BCM_FIELD_QSET_ADD(fg0.qset, bcmFieldQualifyDstMac);
    922             BCM_FIELD_QSET_ADD(fg0.qset, bcmFieldQualifyEtherType);
    923             BCM_IF_ERROR_RETURN(
    924                 bcm_esw_field_entry_create(unit, fp_cntl[unit].group0, &entry0));
    925             BCM_PBMP_PORT_SET(pbm, port);
    926             if (soc_feature(unit, soc_feature_ifp_no_inports_support)) {
    927                 BCM_IF_ERROR_RETURN(
    928                     bcm_esw_field_qualify_InPort(unit, entry0, port, -1));
    929             } else {
    930                 BCM_IF_ERROR_RETURN(
    931                     bcm_esw_field_qualify_InPorts(unit, entry0, pbm, mask_pbmp));
    932             }
    933             BCM_IF_ERROR_RETURN(
    934                 bcm_esw_field_qualify_DstMac(unit, entry0, mac,
    935                                              (uint8 *) mac_all_ones));
    936             BCM_IF_ERROR_RETURN(
    937                 bcm_esw_field_qualify_EtherType(unit, entry0, _AUTH_ETHERTYPE_EAPOL,
    938                                                 _AUTH_ETHERTYPE_MASK));
    939             BCM_IF_ERROR_RETURN(
    940                 bcm_esw_field_action_add(unit, entry0, bcmFieldActionCopyToCpu, 
    941                                         0, 0));
    942             rv = bcm_esw_field_entry_install(unit, entry0);
    943             if (BCM_SUCCESS(rv)) {
    944                 auth_mac_p entry = NULL;
    945                 rv2 = _auth_maclist_insert(&fp_cntl[unit].macList, mac, &entry);
    946                 if (rv2 == BCM_E_NONE) {
    947                     entry->entry = entry0;
    948                     entry->pbmp = pbm;
    949                 }
    950                 fp_cntl[unit].count++; 
    951             } else {
    952                 BCM_IF_ERROR_RETURN(bcm_esw_field_entry_destroy(unit, entry0));
    953             }
    954         }
    955 
    956         /* Add port to Drop all group */
    957         pbm = fp_cntl[unit].group2_pbmp; 
    958         BCM_PBMP_PORT_ADD(pbm, port);
    959         if (soc_feature(unit, soc_feature_ifp_no_inports_support)) {
    960             BCM_IF_ERROR_RETURN(
    961                 bcm_esw_field_qualify_InPort(unit, fp_cntl[unit].entry2, port, -1));
    962         } else {
    963             BCM_IF_ERROR_RETURN(
    964                 bcm_esw_field_qualify_InPorts(unit, fp_cntl[unit].entry2, pbm, 
    965                                             mask_pbmp));
    966         }
    967         BCM_IF_ERROR_RETURN(
    968             bcm_esw_field_entry_reinstall(unit, fp_cntl[unit].entry2));
    969         fp_cntl[unit].group2_pbmp = pbm;
    970         
    971     }
    972 
    973     return rv;
    974 #else /* !BCM_FIELD_SUPPORT */
    975     return BCM_E_UNAVAIL;
    976 #endif /* !BCM_FIELD_SUPPORT */
    977 }
    978 
    979 /*
    980  * Function:
    981  *      _auth_field_install_all
    982  * Description:
    983  *      Install FP for accepting EAPOL frames
    984  *      destinated for switch CPU's MAC addresses
    985  * Parameters:
    986  *      unit - Device number
    987  *      port - Port number
    988  * Returns:
    989  *      BCM_E_XXX
    990  * Notes:
    991  */
    992 
    993 STATIC int
    994 _auth_field_install_all(int unit, int port)
    995 {
    996     auth_mac_t **list=&auth_cntl[unit][port].macList;
    997     auth_mac_p entry = NULL;
    998     int rv = BCM_E_NONE;
    999     bcm_mac_t mac_zero = {0};
   1000 
   1001     if (auth_cntl[unit][port].mac_set) {
   1002         return BCM_E_EXISTS;
   1003     }
   1004 
   1005     /* No accepted MAC addresses, drop all for default */
   1006     if (*list == NULL) {
   1007         rv = _auth_field_install(unit, port, mac_zero);
   1008         if (rv < 0) {
   1009             return rv;
   1010         }
   1011     }
   1012 
   1013     while (*list != NULL) {
   1014         rv = _auth_field_install(unit, port, (*list)->mac);
   1015         if (rv < 0) {
   1016             _auth_maclist_remove(list, (*list)->mac, &entry);
   1017             sal_free(entry);
   1018         } else {
   1019             list = &(*list)->next;
   1020         }
   1021     }
   1022     auth_cntl[unit][port].mac_set = TRUE;
   1023 
   1024     return rv;
   1025 }
   1026 
   1027 /*
   1028  * Function:
   1029  *      _auth_field_remove_all
   1030  * Description:
   1031  *      Removed all installed FP in controlled state
   1032  * Parameters:
   1033  *      unit - Device number
   1034  *      port - Port number
   1035  * Returns:
   1036  *      BCM_E_XXX
   1037  * Notes:
   1038  */
   1039 
   1040 STATIC int
   1041 _auth_field_remove_all(int unit, int port)
   1042 {
   1043     bcm_pbmp_t pbmp_mask;
   1044     auth_mac_t **list=&fp_cntl[unit].macList;
   1045 
   1046     if (!auth_cntl[unit][port].mac_set) {
   1047         return BCM_E_NONE;
   1048     }
   1049 
   1050     BCM_PBMP_CLEAR(pbmp_mask);
   1051     BCM_PBMP_ASSIGN (pbmp_mask, PBMP_E_ALL(unit));
   1052 #ifdef BCM_KATANA2_SUPPORT
   1053     if (soc_feature(unit, soc_feature_linkphy_coe) ||
   1054         soc_feature(unit, soc_feature_subtag_coe)) {
   1055         _bcm_kt2_subport_pbmp_update(unit, &pbmp_mask);
   1056     }
   1057 #endif
   1058 
   1059     while (*list != NULL) {
   1060         pbmp_t   pbm;
   1061         pbm = (*list)->pbmp;
   1062         BCM_PBMP_PORT_REMOVE(pbm, port); 
   1063         if (BCM_PBMP_IS_NULL(pbm)) {
   1064             BCM_IF_ERROR_RETURN
   1065                 (bcm_esw_field_entry_remove(unit, (*list)->entry)); 
   1066             BCM_IF_ERROR_RETURN
   1067                 (bcm_esw_field_entry_destroy(unit, (*list)->entry));
   1068             fp_cntl[unit].count--;
   1069             (*list)->entry = -1;
   1070         } else {
   1071             if (!soc_feature(unit, soc_feature_ifp_no_inports_support)) {
   1072                 BCM_IF_ERROR_RETURN
   1073                     (bcm_esw_field_qualify_InPorts(unit, (*list)->entry, pbm, pbmp_mask));
   1074             }
   1075             BCM_IF_ERROR_RETURN
   1076                 (bcm_esw_field_entry_reinstall(unit, (*list)->entry));
   1077             (*list)->pbmp = pbm;
   1078         }
   1079         list = &(*list)->next;
   1080     }
   1081 
   1082     if ((fp_cntl[unit].count==0) && (fp_cntl[unit].inited)) {
   1083         BCM_IF_ERROR_RETURN
   1084             (bcm_esw_field_entry_remove(unit, fp_cntl[unit].entry2)); 
   1085         BCM_IF_ERROR_RETURN
   1086             (bcm_esw_field_entry_destroy(unit, fp_cntl[unit].entry2));
   1087         BCM_IF_ERROR_RETURN
   1088             (bcm_esw_field_group_destroy(unit, fp_cntl[unit].group0));
   1089         BCM_IF_ERROR_RETURN
   1090             (bcm_esw_field_group_destroy(unit, fp_cntl[unit].group2));
   1091         _auth_maclist_destroy(&fp_cntl[unit].macList);
   1092         fp_cntl[unit].inited = FALSE;
   1093     } else {
   1094         auth_mac_p    entry;
   1095         list = &fp_cntl[unit].macList;
   1096         while (*list != NULL) {
   1097             if ((*list)->entry == -1) {   
   1098                entry = *list;
   1099                *list = entry->next;
   1100                sal_free(entry);
   1101             } 
   1102             list = &(*list)->next;
   1103         }
   1104     }
   1105 
   1106     auth_cntl[unit][port].mac_set = FALSE;
   1107 
   1108     return BCM_E_NONE;
   1109 }
   1110 
   1111 /*
   1112  * Function:
   1113  *      _auth_field_remove
   1114  * Description:
   1115  *      Removed installed FP
   1116  * Parameters:
   1117  *      unit - Device number
   1118  *      port - Port number
   1119  *      mac -  Switch's MAC address 
   1120  * Returns:
   1121  *      BCM_E_XXX
   1122  * Notes:
   1123  */
   1124 
   1125 STATIC int
   1126 _auth_field_remove(int unit, int port, bcm_mac_t mac)
   1127 {
   1128 #ifdef BCM_FIELD_SUPPORT
   1129     pbmp_t   pbm;
   1130     bcm_field_qset_t qset0;
   1131     auth_mac_p entry = NULL;
   1132     bcm_pbmp_t pbmp_mask;
   1133 
   1134     BCM_PBMP_CLEAR(pbmp_mask);
   1135     BCM_PBMP_ASSIGN (pbmp_mask, PBMP_E_ALL(unit));
   1136 #ifdef BCM_KATANA2_SUPPORT
   1137     if (soc_feature(unit, soc_feature_linkphy_coe) ||
   1138         soc_feature(unit, soc_feature_subtag_coe)) {
   1139         _bcm_kt2_subport_pbmp_update(unit, &pbmp_mask);
   1140     }
   1141 #endif
   1142 
   1143     if (_auth_maclist_lookup(&fp_cntl[unit].macList, mac, &entry) > 0) {
   1144         BCM_FIELD_QSET_INIT(qset0);
   1145         if (soc_feature(unit, soc_feature_ifp_no_inports_support)) {
   1146             BCM_FIELD_QSET_ADD(qset0, bcmFieldQualifyInPort);
   1147         } else {
   1148             BCM_FIELD_QSET_ADD(qset0, bcmFieldQualifyInPorts);
   1149         }
   1150         pbm = entry->pbmp;
   1151         BCM_PBMP_PORT_REMOVE(pbm, port);
   1152         if (BCM_PBMP_IS_NULL(pbm)) {
   1153             BCM_IF_ERROR_RETURN
   1154                 (bcm_esw_field_entry_remove(unit, entry->entry)); 
   1155             BCM_IF_ERROR_RETURN
   1156                 (bcm_esw_field_entry_destroy(unit, entry->entry));
   1157             fp_cntl[unit].count--;
   1158             _auth_maclist_remove(&fp_cntl[unit].macList, mac, &entry);    
   1159             sal_free(entry);
   1160         } else {
   1161             if (soc_feature(unit, soc_feature_ifp_no_inports_support)) {
   1162                 BCM_IF_ERROR_RETURN
   1163                     (bcm_esw_field_qualify_InPort(unit, entry->entry, port, -1));
   1164             } else {
   1165                 BCM_IF_ERROR_RETURN
   1166                     (bcm_esw_field_qualify_InPorts(unit, entry->entry, pbm, pbmp_mask));
   1167             }
   1168             BCM_IF_ERROR_RETURN(
   1169                 bcm_esw_field_entry_reinstall(unit, entry->entry));
   1170             entry->pbmp = pbm;
   1171         }
   1172     }
   1173 
   1174     if ((fp_cntl[unit].count==0) && (fp_cntl[unit].inited)) {
   1175         BCM_IF_ERROR_RETURN
   1176             (bcm_esw_field_entry_remove(unit, fp_cntl[unit].entry2)); 
   1177         BCM_IF_ERROR_RETURN
   1178             (bcm_esw_field_entry_destroy(unit, fp_cntl[unit].entry2));
   1179         BCM_IF_ERROR_RETURN
   1180             (bcm_esw_field_group_destroy(unit, fp_cntl[unit].group0));
   1181         BCM_IF_ERROR_RETURN
   1182             (bcm_esw_field_group_destroy(unit, fp_cntl[unit].group2));
   1183         _auth_maclist_destroy(&fp_cntl[unit].macList);
   1184         fp_cntl[unit].inited = FALSE;
   1185     }
   1186 
   1187     return BCM_E_NONE;
   1188 #else /* !BCM_FIELD_SUPPORT */
   1189     return BCM_E_UNAVAIL;
   1190 #endif /* !BCM_FIELD_SUPPORT */
   1191 }
   1192 
   1193 #if defined(BCM_FIELD_SUPPORT)
   1194 /*
   1195  * Function:
   1196  *      _auth_maclist_insert 
   1197  * Description:
   1198  *      Add a MAC address to the list 
   1199  * Parameters:
   1200  *      list - list to be inserted 
   1201  *      mac -  MAC address 
   1202  *      ins -  (OUT) entry inserted  
   1203  * Returns:
   1204  *      BCM_E_XXX
   1205  * Notes:
   1206  */
   1207 
   1208 STATIC int
   1209 _auth_maclist_insert(auth_mac_t **list, bcm_mac_t mac, auth_mac_p *ins)
   1210 {
   1211     auth_mac_p    entry = NULL;
   1212 
   1213     if (_auth_maclist_lookup(list, mac, &entry) > 0) {
   1214         return BCM_E_EXISTS;
   1215     } 
   1216 
   1217     if ((entry = sal_alloc(sizeof(auth_mac_t), "maclist")) == NULL) {
   1218         return BCM_E_MEMORY;
   1219     }
   1220 
   1221     sal_memset(entry, 0, sizeof(auth_mac_t));
   1222     sal_memcpy(entry->mac, mac, sizeof(bcm_mac_t)); 
   1223     entry->next = *list;
   1224     *list = entry;
   1225     *ins = entry;
   1226 
   1227     return BCM_E_NONE;
   1228 }
   1229 #endif /* !BCM_FIELD_SUPPORT */
   1230 
   1231 /*
   1232  * Function:
   1233  *      _auth_maclist_remove
   1234  * Description:
   1235  *      Remove a MAC address from the list
   1236  * Parameters:
   1237  *      list - list to be removed 
   1238  *      mac -  MAC address
   1239  *      ins -  (OUT) entry deleted 
   1240  * Returns:
   1241  *      BCM_E_NONE       - Success
   1242  *      BCM_E_NOT_FOUND  - MAC not found in list
   1243  * Notes:
   1244  */
   1245 
   1246 STATIC int
   1247 _auth_maclist_remove(auth_mac_t **list, bcm_mac_t mac, auth_mac_p *del)
   1248 {
   1249     auth_mac_p    entry;
   1250 
   1251     while (*list != NULL) {
   1252         if (!sal_memcmp((*list)->mac, mac, sizeof(bcm_mac_t))) { 
   1253             entry = *list;
   1254             *list = entry->next;
   1255             *del = entry;
   1256             return BCM_E_NONE;
   1257         }
   1258         list = &(*list)->next;
   1259     }
   1260 
   1261     return BCM_E_NOT_FOUND;
   1262 }
   1263 
   1264 #if defined(BCM_FIELD_SUPPORT)
   1265 /*
   1266  * Function:
   1267  *      _auth_maclist_lookup
   1268  * Description:
   1269  *      Lookup a MAC address in the list
   1270  * Parameters:
   1271  *      list - list to be lookuped 
   1272  *      mac -  MAC address
   1273  * Returns:
   1274  *      BCM_E_XXX
   1275  * Notes:
   1276  */
   1277 
   1278 STATIC int
   1279 _auth_maclist_lookup(auth_mac_t **list, bcm_mac_t mac, auth_mac_p *entry)
   1280 {
   1281     while (*list != NULL) {
   1282         if (!sal_memcmp((*list)->mac, mac, sizeof(bcm_mac_t))) { 
   1283             *entry = *list;  
   1284             return TRUE;
   1285         }
   1286         list = &(*list)->next;
   1287     }
   1288 
   1289     return FALSE;
   1290 }
   1291 #endif /* !BCM_FIELD_SUPPORT */
   1292 
   1293 /*
   1294  * Function:
   1295  *      _auth_maclist_destroy
   1296  * Description:
   1297  *      Destroy all MAC addresses in the list
   1298  * Parameters:
   1299  *      list - list to be destroyed 
   1300  * Returns:
   1301  *      BCM_E_XXX
   1302  * Notes:
   1303  */
   1304 
   1305 STATIC int
   1306 _auth_maclist_destroy(auth_mac_t **list)
   1307 {
   1308     auth_mac_p entry = NULL;
   1309 
   1310     if (*list == NULL) {
   1311         return BCM_E_EMPTY;
   1312     }
   1313 
   1314     while (*list != NULL) {
   1315         _auth_maclist_remove(list, (*list)->mac, &entry);
   1316         sal_free(entry);
   1317     }
   1318     return BCM_E_NONE;
   1319 }
   1320 
   1321 #ifdef AUTH_DEBUG
   1322 /*
   1323  * Function:
   1324  *      _auth_maclist_dump
   1325  * Description:
   1326  *      Dump all MAC addresses in the list
   1327  * Parameters:
   1328  *      list - list to be dumped 
   1329  * Returns:
   1330  *      BCM_E_XXX
   1331  * Notes:
   1332  */
   1333 
   1334 STATIC int
   1335 _auth_maclist_dump(auth_mac_t **list)
   1336 {
   1337     while (*list != NULL) {
   1338         LOG_CLI((BSL_META_U(unit,
   1339                             "%02x:%02x:%02x:%02x:%02x:%02x\n"),
   1340                  (*list)->mac[0], (*list)->mac[1],
   1341                  (*list)->mac[2], (*list)->mac[3],
   1342                  (*list)->mac[4], (*list)->mac[5]));
   1343         list = &(*list)->next;
   1344     }
   1345 
   1346     return BCM_E_NONE;
   1347 }
   1348 #endif /* AUTH_DEBUG */