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

rlink.c (72188B)


      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  * Remote asynchronous operations including linkscan, L2 address
      8  * change notification and RX tunnelling.  Only provides connection
      9  * service for tunnelling.  The tunnelled packet handler is registered
     10  * directly with RX and doesn't go through RLink notify.
     11  *
     12  * The client side:
     13  *	- remembers the application callbacks
     14  *	- sends an RPC to the server side indicating that registration has
     15  *	  happended
     16  *	- registers with ATP to receive remote link notifications
     17  *	- For linkscanning, when an ATP packet is received, does a
     18  *        bcm_port_info_get to the remote side and then calls the
     19  *        application callback
     20  *
     21  * The server side:
     22  *	- receives the registration RPC from the client
     23  *	- remembers which units have been registered
     24  *	- Registers with the proper local function
     25  *        (eg, bcm_linkscan_register) on the local unit
     26  *	- when a local callback happens, sends an ATP back to any
     27  *	  registered clients
     28  *
     29  * There is a thread that's started on both client and server sides to
     30  * handle the RPCs and packet handling without deadlock.  A single thread
     31  * handles both client and server side.
     32  *
     33  * rlink was originally designed for a master-slave architecture.
     34  * There are two master change situations that may occur:  The stack
     35  * changes so that the master is still present but is no longer the
     36  * master.  For this case, there are two sub cases:  The slave remains
     37  * a slave to the new master, or it becomes the master itself.
     38  *
     39  * The second scenario is that the master disappears from the stack.
     40  * This has the same two subcases as above.
     41  *
     42  * In the second case, we might get a "de-registration" call from the
     43  * old master when it detaches.  But if communication is already torn
     44  * down, we may not; and in the second case, we definitely won't get
     45  * a teardown message.
     46  *
     47  * Because of these situations, rlink now will overwrite information if
     48  * a new registration appears from a different requesting CPU.  This
     49  * has two implications.
     50  *
     51  * First, rlink will not support peer-to-peer connections.  Some L2
     52  * synchronization code may be peer-to-peer; either it won't use rlink,
     53  * or rlink will change.
     54  *
     55  * Second, this may open a security hole since a rogue might be able
     56  * to overwrite the current info.  rlink expects a layer of security
     57  * above its calls.
     58  */
     59 
     60 #include <shared/bsl.h>
     61 
     62 #include <shared/alloc.h>
     63 #include <sal/core/libc.h>
     64 #include <sal/core/sync.h>
     65 #include <sal/core/thread.h>
     66 
     67 #include <bcm/types.h>
     68 #include <bcm/error.h>
     69 #include <bcm/l2.h>
     70 #include <bcm/link.h>
     71 #include <bcm/port.h>
     72 #include <bcm/rx.h>
     73 #include <bcm/auth.h>
     74 
     75 #include <soc/property.h>
     76 #include <soc/drv.h>
     77 
     78 #include <bcm_int/control.h>
     79 #include <bcm_int/rpc/pack.h>
     80 #include <bcm_int/rpc/rlink.h>
     81 #include <bcm_int/esw/rx.h>
     82 
     83 #include <appl/cpudb/cpudb.h>
     84 #include <appl/cputrans/atp.h>
     85 #include <appl/cputrans/ct_tun.h>
     86 #include "rlink.h"
     87 #include "traverse.h"
     88 
     89 #ifdef	BCM_RPC_SUPPORT
     90 
     91 #ifndef RLINK_THREAD_STACK
     92 #define	RLINK_THREAD_STACK	SAL_THREAD_STKSZ
     93 #endif
     94 
     95 #ifndef RLINK_THREAD_PRIO
     96 #define	RLINK_THREAD_PRIO	50
     97 #endif
     98 
     99 #define	RLINK_INIT	(_rlink_lock != NULL)
    100 #define	RLINK_SLEEP	sal_sem_take(_rlink_sem, sal_sem_FOREVER)
    101 #define	RLINK_WAKE	sal_sem_give(_rlink_sem)
    102 #define	RLINK_LOCK	sal_mutex_take(_rlink_lock, sal_mutex_FOREVER)
    103 #define	RLINK_UNLOCK	sal_mutex_give(_rlink_lock)
    104 #define	RLINK_NOTIFY_LOCK	\
    105 			sal_mutex_take(_rlink_notify_lock, sal_mutex_FOREVER)
    106 #define	RLINK_NOTIFY_UNLOCK	\
    107 			sal_mutex_give(_rlink_notify_lock)
    108 
    109 #define RLINK_ENQUEUE_NOTIFY(_rnot) do {                        \
    110         _rnot->next = NULL;                                     \
    111         RLINK_NOTIFY_LOCK;                                      \
    112         if (_rlink_notify_tail == NULL) {                       \
    113             _rlink_notify_head = _rlink_notify_tail = _rnot;    \
    114         } else {                                                \
    115             _rlink_notify_tail->next = _rnot;                   \
    116             _rlink_notify_tail = _rnot;                         \
    117         }                                                       \
    118         ++_rlink_queue_size;                                    \
    119         RLINK_NOTIFY_UNLOCK;                                    \
    120         RLINK_WAKE;                                             \
    121     } while (0)
    122 
    123 #define MSG_STR(_m) \
    124     (((_m) == RLINK_MSG_ADD) ? "add" : \
    125      ((_m) == RLINK_MSG_DELETE) ? "delete" : \
    126      ((_m) == RLINK_MSG_NOTIFY) ? "notify" : \
    127      ((_m) == RLINK_MSG_TRAVERSE) ? "traverse" : \
    128      "?")
    129 
    130 #define TYPE_STR(_t) \
    131     (((_t) == RLINK_TYPE_LINK) ? "link" : \
    132      ((_t) == RLINK_TYPE_AUTH) ? "auth" : \
    133      ((_t) == RLINK_TYPE_L2) ? "l2" : \
    134      ((_t) == RLINK_TYPE_RX) ? "rx" : \
    135      ((_t) == RLINK_TYPE_OAM) ? "oam" : \
    136      ((_t) == RLINK_TYPE_BFD) ? "bfd" : \
    137      ((_t) == RLINK_TYPE_ADD) ? "add" : \
    138      ((_t) == RLINK_TYPE_DELETE) ? "delete" : \
    139      ((_t) == RLINK_TYPE_START) ? "start" : \
    140      ((_t) == RLINK_TYPE_NEXT) ? "next" : \
    141      ((_t) == RLINK_TYPE_QUIT) ? "quit" : \
    142      ((_t) == RLINK_TYPE_ERROR) ? "error" : \
    143      ((_t) == RLINK_TYPE_MORE) ? "more" : \
    144      ((_t) == RLINK_TYPE_DONE) ? "done" : \
    145 	"?")
    146 
    147 /* Arguments for registration routines */
    148 typedef struct _rlink_register_args_s {
    149     union {
    150         struct {
    151             bcm_oam_event_types_t events;
    152         } oam;
    153 #if defined(INCLUDE_BFD)
    154         struct {
    155             bcm_bfd_event_types_t events;
    156         } bfd;
    157 #endif
    158     } u;
    159 } _rlink_register_args_t;
    160 
    161 /* client side link handlers */
    162 typedef struct _rlink_handle_s {
    163     struct _rlink_handle_s	*next;
    164     int				unit;
    165     rlink_type_t		type;
    166     union {
    167         void                    *generic_func_ptr;
    168         bcm_linkscan_handler_t  link;
    169         bcm_auth_cb_t           auth;
    170         bcm_l2_addr_callback_t  l2;
    171         /* No function registration is needed for RX tunnelling since
    172          * applications use bcm_rx_register directly. */
    173         bcm_oam_event_cb        oam;
    174 #if defined(INCLUDE_BFD)
    175         bcm_bfd_event_cb        bfd;
    176 #endif
    177     } func;
    178     void			*cookie;
    179     cpudb_key_t			cpu;
    180     int				cunit;
    181 } _rlink_handle_t;
    182 
    183 /* server side link handlers */
    184 typedef struct _rlink_scan_s {
    185     struct _rlink_scan_s	*next;
    186     int				unit;
    187     rlink_type_t		type;
    188     cpudb_key_t			cpu;
    189 } _rlink_scan_t;
    190 
    191 /* client side notifications (also used for server side add/delete/send) */
    192 typedef struct _rlink_notify_s {
    193     struct _rlink_notify_s	*next;
    194     cpudb_key_t			cpu;
    195     int				unit;
    196     rlink_type_t		type;
    197     int				pkt_send;  /* Boolean: Send notify pkt? */
    198     union {
    199         struct {   /* For client notification ops */
    200             uint8               *buf;
    201             int                 len;
    202             int                 check_cpu;
    203             uint32              ct_flags;
    204         } cli;
    205         struct {
    206             bcm_port_t          port;
    207             bcm_port_info_t     info;
    208         } link;
    209         struct {
    210             bcm_port_t          port;
    211             int                 reason;
    212         } auth;
    213         struct {
    214             int                 insert;
    215             bcm_l2_addr_t       addr;
    216         } l2;
    217         struct {
    218             uint32               flags;
    219             bcm_oam_event_type_t event_type;
    220             bcm_oam_group_t      group;
    221             bcm_oam_endpoint_t   endpoint;
    222         } oam;
    223 #if defined(INCLUDE_BFD)
    224         struct {
    225             uint32               flags;
    226             bcm_bfd_event_types_t event_types;
    227             bcm_bfd_endpoint_t   endpoint;
    228         } bfd;
    229 #endif
    230         struct {
    231             rlink_type_t	type;
    232         } msg;
    233         struct {
    234             bcm_pkt_t           *pkt;
    235             uint8               *buf;
    236             int                 len;
    237         } traverse;
    238     } u;
    239     _rlink_register_args_t    register_args;
    240 } _rlink_notify_t;
    241 
    242 static sal_mutex_t		_rlink_lock;
    243 static sal_mutex_t		_rlink_notify_lock;
    244 static sal_sem_t		_rlink_sem;
    245 static sal_thread_t		_rlink_thread = SAL_THREAD_ERROR;
    246 static int			_rlink_thread_exit;
    247 
    248 /*
    249  * Example RLINK call sequence:
    250  *
    251  * CLIENT CPU:
    252  * App -> linkscan_register -> client_linkscan_register
    253  *      RLINK adds entry to _handle_ list.
    254  *      Makes remote MSG_ADD call to remote CPU controlling unit
    255  *      ===> to remote CPU
    256  *           -> _rlink_pkt_handler ->_rlink_scan_add
    257  *           RLINK adds entry to _scan_ list.
    258  * Later, a link event comes in on the remote system
    259  *      -> _bcm_rlink_linkscan_handler on REMOTE system
    260  *      Enqueues entry on _notify_ list
    261  *      -> rlink_thread runs through _scan_ list and
    262  *      sends MSG_NOTIFY to CLIENT CPUs.
    263  *          CLIENT CPU enqueues request on its _notify_ list.
    264  *          CLIENT RLINK thread dequeues notify event,
    265  *          runs through _handle_ list and makes callbacks.
    266  *
    267  * The length of the _notify_ list may be limited to avoid
    268  * overload due to RX or L2 notifies.
    269  */
    270 
    271 static _rlink_handle_t		*_rlink_handle_head;
    272 static _rlink_handle_t		*_rlink_handle_tail;
    273 static _rlink_scan_t		*_rlink_scan_head;
    274 static _rlink_scan_t		*_rlink_scan_tail;
    275 static _rlink_notify_t		*_rlink_notify_head;
    276 static _rlink_notify_t		*_rlink_notify_tail;
    277 
    278 /* Some counters */
    279 #if defined(BROADCOM_DEBUG)
    280 #define INCR_COUNTER(counter) ++(counter)
    281 volatile int rlink_link_out;
    282 volatile int rlink_link_out_disc;
    283 volatile int rlink_link_in;
    284 volatile int rlink_link_in_disc;
    285 volatile int rlink_auth_out;
    286 volatile int rlink_auth_out_disc;
    287 volatile int rlink_auth_in;
    288 volatile int rlink_auth_in_disc;
    289 volatile int rlink_l2_out;
    290 volatile int rlink_l2_out_disc;
    291 volatile int rlink_l2_in;
    292 volatile int rlink_l2_in_disc;
    293 volatile int rlink_rx_out;
    294 volatile int rlink_rx_out_disc;
    295 volatile int rlink_rx_in;
    296 volatile int rlink_rx_in_disc;
    297 volatile int rlink_oam_out;
    298 volatile int rlink_oam_out_disc;
    299 volatile int rlink_oam_in;
    300 volatile int rlink_oam_in_disc;
    301 volatile int rlink_bfd_out;
    302 volatile int rlink_bfd_out_disc;
    303 volatile int rlink_bfd_in;
    304 volatile int rlink_bfd_in_disc;
    305 
    306 volatile int rlink_add_req_in;
    307 volatile int rlink_del_req_in;
    308 volatile int rlink_notify_in;
    309 volatile int rlink_trav_req_in;
    310 volatile int rlink_buff_alloc_fail;
    311 volatile int rlink_pkt_send_fail;
    312 #else
    313 #define INCR_COUNTER(counter)
    314 #endif /* BROADCOM_DEBUG */
    315 
    316 /* The rlink queue length may be limited */
    317 static int                      _rlink_queue_size;
    318 
    319 /*
    320  * Since notify requests are now queued, rather than sent in
    321  * the calling thread context, a queue size limiting mechanism
    322  * is implemented.
    323  *
    324  * If foo_max > 0 and queue_size > foo_max, then foo requests are
    325  * not enqueued (but without notice).  This applies to L2 notification,
    326  * link notification and RX tunnels.  For RX, the max is checked on a
    327  * per-COS basis.
    328  *
    329  * In addition, the local and remote operations are checked independently,
    330  * although local RX requests go directly to RX which does its own
    331  * rate limiting.
    332  *
    333  * It is recommended that link notifications not be limited.
    334  *
    335  * Currently, these are exported to allow applications to set them
    336  * directly.  In the future, accessors or "bcm_rlink_control" may be
    337  * implemented depending on scalability requirements.
    338  */
    339 
    340 int bcm_rlink_link_remote_max;
    341 int bcm_rlink_auth_remote_max;
    342 int bcm_rlink_l2_remote_max = BCM_RLINK_L2_REMOTE_MAX_DEFAULT;
    343 int bcm_rlink_rx_remote_max[BCM_COS_COUNT] = BCM_RLINK_RX_REMOTE_MAX_DEFAULT;
    344 int bcm_rlink_oam_remote_max;
    345 int bcm_rlink_bfd_remote_max;
    346 
    347 int bcm_rlink_link_local_max;  /* 0 -> no limit; recommended setting */
    348 int bcm_rlink_auth_local_max;  /* 0 -> no limit; recommended setting */
    349 int bcm_rlink_l2_local_max;
    350 int bcm_rlink_oam_local_max;   /* 0 -> no limit; recommended setting */
    351 int bcm_rlink_bfd_local_max;   /* 0 -> no limit; recommended setting */
    352 
    353 int	_rlink_nexthop = 0;
    354 
    355 
    356 /* Array size for bcm_oam_event_types_t bit declare type */
    357 #define _BCM_OAM_EVENT_TYPES_ARRAY_SIZE    _SHR_BITDCLSIZE(bcmOAMEventCount)
    358 #if defined(INCLUDE_BFD)
    359 /* Array size for bcm_bfd_event_types_t bit declare type */
    360 #define _BCM_BFD_EVENT_TYPES_ARRAY_SIZE    _SHR_BITDCLSIZE(bcmBFDEventCount)
    361 #endif
    362 
    363 STATIC void
    364 _bcm_rlink_send_enqueue(int unit,
    365 			rlink_type_t type,
    366 			uint8 *buf,
    367 			int len,
    368 			int check_cpu,
    369 			cpudb_key_t cpu,
    370 			uint32 ct_flags)
    371 {
    372     _rlink_notify_t     *rnot;
    373 
    374     rnot = sal_alloc(sizeof(*rnot), "bcm_rlink_notify");
    375     if (rnot == NULL) {
    376         return; /* Failure */
    377     }
    378 
    379     CPUDB_KEY_COPY(rnot->cpu, cpu);
    380     rnot->unit = unit;
    381     rnot->type = type;
    382     rnot->pkt_send = TRUE;
    383     rnot->u.cli.buf = buf;
    384     rnot->u.cli.len = len;
    385     rnot->u.cli.check_cpu = check_cpu;
    386     rnot->u.cli.ct_flags = ct_flags;
    387 
    388     RLINK_ENQUEUE_NOTIFY(rnot);
    389 }
    390 
    391 
    392 /*
    393  * Server side handlers.
    394  * Registered for any units of interest to requesting clients.
    395  * Send off a notify packet to any clients interested in this unit.
    396  */
    397 #define cpudb_key_ignore cpudb_bcast_key
    398 
    399 /*
    400  * Tail end of linkscan and l2 handlers.
    401  * Send notify to appropriate clients.
    402  */
    403 STATIC void
    404 _bcm_rlink_send_notify(int unit,
    405                        rlink_type_t type,
    406                        uint8 *buf,
    407                        int len,
    408                        int check_cpu,
    409                        cpudb_key_t cpu,
    410                        uint32 ct_flags)
    411 {
    412     int rv = BCM_E_NONE;
    413     _rlink_scan_t	*rscan;
    414 
    415     LOG_VERBOSE(BSL_LS_BCM_RX,
    416                 (BSL_META_U(unit,
    417                             "Sending RLINK %s notify for unit %d\n"),
    418                  TYPE_STR(type), unit));
    419     RLINK_LOCK;
    420     for (rscan = _rlink_scan_head; rscan != NULL; rscan = rscan->next) {
    421         if (rscan->unit == unit && rscan->type == type) {
    422             if (check_cpu) {
    423                 if (!CPUDB_KEY_EQUAL(cpu, rscan->cpu)) {
    424                     continue;
    425                 }
    426             }
    427             LOG_VERBOSE(BSL_LS_BCM_RX,
    428                         (BSL_META_U(unit,
    429                                     "RLINK to " CPUDB_KEY_FMT_EOLN),
    430                          CPUDB_KEY_DISP(rscan->cpu)));
    431             rv = atp_tx(rscan->cpu, RLINK_CLIENT_ID,
    432                             buf, len, ct_flags, NULL, NULL);
    433             if (BCM_FAILURE(rv)) {
    434                 INCR_COUNTER(rlink_pkt_send_fail);
    435             }
    436         }
    437     }
    438     RLINK_UNLOCK;
    439 
    440     /* coverity[identical_branches] */
    441     if (type != RLINK_TYPE_RX) {
    442         atp_tx_data_free(buf);
    443     } else {   
    444         atp_tx_data_free(buf);
    445     }
    446 }
    447 
    448 /****************************************************************
    449  *
    450  * Callbacks registered at the BCM layer on local units on the
    451  * (rlink) server side.  These handle the async events on the
    452  * CPUs where they first occur.  They forward notification via
    453  * "send_notify" (above) when configuration is right for the
    454  * given event.
    455  */
    456 
    457 /*
    458  * Registered with RX at server to check if pkts should be
    459  * tunnelled.
    460  */
    461 
    462 STATIC bcm_rx_t
    463 _bcm_rlink_rx_handler(int unit, bcm_pkt_t *pkt, void *cookie)
    464 {
    465     uint32 ct_flags = 0;
    466     bcm_cpu_tunnel_mode_t tunnel_pkt;
    467     int no_ack;
    468     uint8 *buf, *bp;
    469     int len;
    470     cpudb_key_t cpu;
    471     int check_cpu;
    472 
    473     if (_rlink_thread_exit) { /* Not running */
    474         return BCM_RX_NOT_HANDLED;
    475     }
    476 
    477     /*
    478      * Find out if the packet should be tunnelled; if so, should
    479      * it be directed to one CPU?
    480      */
    481     tunnel_pkt = ct_rx_tunnel_check(unit, pkt, &no_ack, &check_cpu, &cpu);
    482 
    483     if (tunnel_pkt == BCM_CPU_TUNNEL_NONE) {  /* Don't tunnel */
    484         return BCM_RX_NOT_HANDLED;
    485     }
    486 
    487     INCR_COUNTER(rlink_rx_out);
    488 
    489     if (bcm_rlink_rx_remote_max[pkt->cos] > 0 &&
    490             _rlink_queue_size > bcm_rlink_rx_remote_max[pkt->cos]) {
    491         INCR_COUNTER(rlink_rx_out_disc);
    492         /* No space in queue */
    493         return BCM_RX_NOT_HANDLED;
    494     }
    495 
    496     CPUTRANS_COS_SET(ct_flags, pkt->cos);
    497     if (no_ack) {   /* Mark packet as tunnelled via best effort */
    498         ct_flags |= CPUTRANS_NO_ACK;
    499     }
    500 
    501     /* msg, type, unit, port, info */
    502     len = 1 + 1 + 4 + ct_rx_tunnel_header_bytes_get() + pkt->pkt_len;
    503 
    504     
    505     buf = atp_tx_data_alloc(len);
    506     if (buf == NULL) {
    507         INCR_COUNTER(rlink_buff_alloc_fail);
    508         LOG_WARN(BSL_LS_SOC_COMMON,
    509                  (BSL_META_U(unit,
    510                              "RLINK Tunnel Src: alloc failed\n")));
    511         return BCM_RX_NOT_HANDLED;
    512     }
    513 
    514     bp = bcm_rlink_encode(buf, RLINK_MSG_NOTIFY, RLINK_TYPE_RX, unit);
    515     (void)ct_rx_tunnel_pkt_pack(pkt, bp);
    516 
    517     _bcm_rlink_send_enqueue(unit, RLINK_TYPE_RX, buf, len, check_cpu,
    518                             cpu, ct_flags);
    519 
    520     return BCM_RX_HANDLED;
    521 }
    522 
    523 
    524 /*
    525  * Server side linkscan handler
    526  */
    527 STATIC void
    528 _bcm_rlink_linkscan_handler(int unit,
    529 			    bcm_port_t port,
    530 			    bcm_port_info_t *info)
    531 {
    532     uint8	*buf, *bp;
    533     int		len;
    534 
    535     if (_rlink_thread_exit) { /* Not running */
    536         return;
    537     }
    538 
    539     INCR_COUNTER(rlink_link_out);
    540 
    541     if (bcm_rlink_link_remote_max > 0 &&
    542             _rlink_queue_size > bcm_rlink_link_remote_max) {
    543         INCR_COUNTER(rlink_link_out_disc);
    544         /* No space in queue */
    545         return;
    546     }
    547 
    548     /* msg, type, unit, port, info */
    549     len = 1 + 1 + 4 + 4 + BCM_PACKLEN_PORT_INFO;
    550     buf = atp_tx_data_alloc(len);
    551     if (buf == NULL) {
    552         INCR_COUNTER(rlink_buff_alloc_fail);
    553         return;
    554     }
    555     bp = bcm_rlink_encode(buf, RLINK_MSG_NOTIFY, RLINK_TYPE_LINK, unit);
    556     BCM_PACK_U32(bp, port);
    557     (void) _bcm_pack_port_info(bp, info);
    558 
    559     _bcm_rlink_send_enqueue(unit, RLINK_TYPE_LINK, buf, len, FALSE,
    560                             cpudb_key_ignore, 0);
    561 }
    562 
    563 /*
    564  * Server side linkscan handler
    565  */
    566 STATIC void
    567 _bcm_rlink_auth_handler(void *cookie,
    568                         int unit,
    569                         int port,
    570                         int reason)
    571 {
    572     uint8	*buf, *bp;
    573     int		len;
    574 
    575     if (_rlink_thread_exit) { /* Not running */
    576         return;
    577     }
    578 
    579     INCR_COUNTER(rlink_auth_out);
    580 
    581     if (bcm_rlink_auth_remote_max > 0 &&
    582             _rlink_queue_size > bcm_rlink_auth_remote_max) {
    583         INCR_COUNTER(rlink_auth_out_disc);
    584         /* No space in queue */
    585         return;
    586     }
    587 
    588     /* msg, type, unit, port, reason */
    589     len = 1 + 1 + 4 + 4 + 4;
    590     buf = atp_tx_data_alloc(len);
    591     if (buf == NULL) {
    592         INCR_COUNTER(rlink_buff_alloc_fail);
    593         return;
    594     }
    595     bp = bcm_rlink_encode(buf, RLINK_MSG_NOTIFY, RLINK_TYPE_AUTH, unit);
    596     BCM_PACK_U32(bp, port);
    597     BCM_PACK_U32(bp, reason);
    598 
    599     _bcm_rlink_send_enqueue(unit, RLINK_TYPE_AUTH, buf, len, FALSE,
    600                             cpudb_key_ignore, 0);
    601 }
    602 
    603 
    604 /*
    605  * Server side l2 handler.  Not all L2 events should be sent to
    606  * clients.  This is determined by a callback that can be
    607  * registered here.
    608  *
    609  * In addition, the most important criteria is whether the L2
    610  * address is "native" to the unit (learned on a front panel
    611  * port).  This can be set up directly using the calls below.
    612  */
    613 
    614 static bcm_rlink_l2_cb_f _l2_cb = NULL;
    615 static uint32 _l2_native_only = FALSE;
    616 
    617 void
    618 bcm_rlink_l2_cb_set(bcm_rlink_l2_cb_f l2_cb)
    619 {
    620     _l2_cb = l2_cb;
    621 }
    622 
    623 void
    624 bcm_rlink_l2_cb_get(bcm_rlink_l2_cb_f *l2_cb)
    625 {
    626     *l2_cb = _l2_cb;
    627 }
    628 
    629 void
    630 bcm_rlink_l2_native_only_set(int native_only)
    631 {
    632     _l2_native_only = native_only;
    633 }
    634 
    635 void
    636 bcm_rlink_l2_native_only_get(int *native_only)
    637 {
    638     *native_only = _l2_native_only;
    639 }
    640 
    641 STATIC void
    642 _bcm_rlink_l2_handler(int unit,
    643 		      bcm_l2_addr_t *l2addr,
    644 		      int insert,
    645 		      void *cookie)
    646 {
    647     uint8		*buf, *bp;
    648     int			len;
    649 
    650     if (_rlink_thread_exit) { /* Not running */
    651         return;
    652     }
    653 
    654     /* See if callback present; if it is and returns FALSE, return */
    655     if (_l2_cb != NULL) {
    656         if (_l2_cb(unit, l2addr, insert) == FALSE) {
    657             return;
    658         }
    659     }
    660 
    661     /* Check for native only setting */
    662     if (_l2_native_only == TRUE) {
    663         if (!(l2addr->flags & BCM_L2_NATIVE)) {
    664             return;
    665         }
    666     }
    667 
    668     INCR_COUNTER(rlink_l2_out);
    669 
    670     if (bcm_rlink_l2_remote_max > 0 &&
    671             _rlink_queue_size > bcm_rlink_l2_remote_max) {
    672         INCR_COUNTER(rlink_l2_out_disc);
    673         /* No space in queue */
    674         return;
    675     }
    676 
    677     /* msg, type, unit, insert, l2addr */
    678     len = 1 + 1 + 4 + 1 + BCM_PACKLEN_L2_ADDR;
    679     buf = atp_tx_data_alloc(len);
    680     if (buf == NULL) {
    681         INCR_COUNTER(rlink_buff_alloc_fail);
    682         return;
    683     }
    684     bp = bcm_rlink_encode(buf, RLINK_MSG_NOTIFY, RLINK_TYPE_L2, unit);
    685     BCM_PACK_U8(bp, insert ? 1 : 0);
    686     (void) _bcm_pack_l2_addr(bp, l2addr);
    687 
    688     _bcm_rlink_send_enqueue(unit, RLINK_TYPE_L2, buf, len, FALSE,
    689                             cpudb_key_ignore, 0);
    690 }
    691 
    692 /*
    693  * Server side oam event handler
    694  */
    695 STATIC int
    696 _bcm_rlink_oam_handler(int unit, 
    697                        uint32 flags, 
    698                        bcm_oam_event_type_t event_type, 
    699                        bcm_oam_group_t group, 
    700                        bcm_oam_endpoint_t endpoint, 
    701                        void *cookie)
    702 {
    703     uint8	*buf, *bp;
    704     int		len;
    705 
    706     if (_rlink_thread_exit) { /* Not running */
    707         return BCM_E_FAIL;
    708     }
    709 
    710     INCR_COUNTER(rlink_oam_out);
    711 
    712     if (bcm_rlink_oam_remote_max > 0 &&
    713         _rlink_queue_size > bcm_rlink_oam_remote_max) {
    714         INCR_COUNTER(rlink_oam_out_disc);
    715         /* No space in queue */
    716         return BCM_E_FULL;
    717     }
    718 
    719     /* msg, type, unit, flags, event_type, group, endpoint */
    720     len = 1 + 1 + 4 + 4 + 4 + 4 + 4;
    721     buf = atp_tx_data_alloc(len);
    722     if (buf == NULL) {
    723         INCR_COUNTER(rlink_buff_alloc_fail);
    724         return BCM_E_MEMORY;
    725     }
    726     bp = bcm_rlink_encode(buf, RLINK_MSG_NOTIFY, RLINK_TYPE_OAM, unit);
    727     BCM_PACK_U32(bp, flags);
    728     BCM_PACK_U32(bp, event_type);
    729     BCM_PACK_U32(bp, group);
    730     BCM_PACK_U32(bp, endpoint);
    731 
    732     _bcm_rlink_send_enqueue(unit, RLINK_TYPE_OAM, buf, len, FALSE,
    733                             cpudb_key_ignore, 0);
    734     return BCM_E_NONE;
    735 }
    736 
    737 #if defined(INCLUDE_BFD)
    738 /*
    739  * Server side bfd event handler
    740  */
    741 STATIC int
    742 _bcm_rlink_bfd_handler(int unit, 
    743                        uint32 flags, 
    744                        bcm_bfd_event_types_t event_types, 
    745                        bcm_bfd_endpoint_t endpoint, 
    746                        void *cookie)
    747 {
    748     uint8	*buf, *bp;
    749     int		len, i;
    750 
    751     if (_rlink_thread_exit) { /* Not running */
    752         return BCM_E_FAIL;
    753     }
    754 
    755     INCR_COUNTER(rlink_bfd_out);
    756 
    757     if (bcm_rlink_bfd_remote_max > 0 &&
    758         _rlink_queue_size > bcm_rlink_bfd_remote_max) {
    759         INCR_COUNTER(rlink_bfd_out_disc);
    760         /* No space in queue */
    761         return BCM_E_FULL;
    762     }
    763 
    764     /* msg, type, unit, flags, group */
    765     len = 1 + 1 + 4 + 4 + 4;
    766     /* events */
    767     for (i = 0; i < _BCM_BFD_EVENT_TYPES_ARRAY_SIZE; i++) {
    768         len += 4;
    769     }
    770     buf = atp_tx_data_alloc(len);
    771     if (buf == NULL) {
    772         INCR_COUNTER(rlink_buff_alloc_fail);
    773         return BCM_E_MEMORY;
    774     }
    775     bp = bcm_rlink_encode(buf, RLINK_MSG_NOTIFY, RLINK_TYPE_BFD, unit);
    776     BCM_PACK_U32(bp, flags);
    777     for (i = 0; i < _BCM_BFD_EVENT_TYPES_ARRAY_SIZE; i++) {
    778         BCM_PACK_U32(bp, event_types.w[i]);
    779     }
    780     BCM_PACK_U32(bp, endpoint);
    781 
    782     _bcm_rlink_send_enqueue(unit, RLINK_TYPE_BFD, buf, len, FALSE,
    783                             cpudb_key_ignore, 0);
    784     return BCM_E_NONE;
    785 }
    786 #endif
    787 
    788 /****************************************************************
    789  *
    790  * Server side registration control.
    791  * Invoked when a client CPU sends an "add" or "delete" request.
    792  */
    793 
    794 STATIC void
    795 _bcm_rlink_scan_add(cpudb_key_t cpu, int unit, rlink_type_t type,
    796                     _rlink_register_args_t *args)
    797 {
    798     _rlink_scan_t	*rscan;
    799     int                 present;
    800 
    801     if(!BCM_CONTROL_UNIT_LEGAL(unit)) {
    802         LOG_WARN(BSL_LS_SOC_COMMON,
    803                  (BSL_META_U(unit,
    804                              "RLINK unit is out of range\n")));
    805         return;
    806     }
    807 
    808     /* For RX in particular, unit must be local */
    809     if (!BCM_IS_LOCAL(unit)) {
    810         LOG_WARN(BSL_LS_SOC_COMMON,
    811                  (BSL_META_U(unit,
    812                              "RLINK scan add on non-local unit %d, "
    813                              "type %s\n"), unit, TYPE_STR(type)));
    814     }
    815     LOG_VERBOSE(BSL_LS_SOC_COMMON,
    816                 (BSL_META_U(unit,
    817                             "RLINK add on unit %d, type %s for CPU "
    818                             CPUDB_KEY_FMT_EOLN), unit, TYPE_STR(type),
    819                  CPUDB_KEY_DISP(cpu)));
    820 
    821     /* If (cpu, unit, type) is in scan chain, don't add again */
    822 
    823     RLINK_LOCK;
    824     present = FALSE;
    825     for (rscan = _rlink_scan_head; rscan != NULL; rscan = rscan->next) {
    826 	if (type == rscan->type && unit == rscan->unit &&
    827                CPUDB_KEY_EQUAL(cpu, rscan->cpu)) {
    828             present = TRUE;
    829 	    break;
    830 	}
    831     }
    832 
    833     if (!present) { /* Okay, add entry */
    834         rscan = sal_alloc(sizeof(*rscan), "bcm_rlink_scan");
    835         if (rscan == NULL) {
    836             RLINK_UNLOCK;
    837             return;		/* failure */
    838         }
    839         CPUDB_KEY_COPY(rscan->cpu, cpu);
    840         rscan->unit = unit;
    841         rscan->type = type;
    842         rscan->next = NULL;
    843 
    844         if (_rlink_scan_tail == NULL) {
    845             _rlink_scan_head = _rlink_scan_tail = rscan;
    846         } else {
    847             _rlink_scan_tail->next = rscan;
    848             _rlink_scan_tail = rscan;
    849         }
    850     }
    851     RLINK_UNLOCK;
    852 
    853     /* always attempt to re-register to lower level */
    854     switch (type) {
    855     case RLINK_TYPE_LINK:
    856         (void)bcm_linkscan_register(unit,
    857                                     _bcm_rlink_linkscan_handler);
    858         break;
    859     case RLINK_TYPE_AUTH:
    860         (void)bcm_auth_unauth_callback(unit,
    861                                        _bcm_rlink_auth_handler, NULL);
    862         break;
    863     case RLINK_TYPE_L2:
    864         (void)bcm_l2_addr_register(unit,
    865                                    _bcm_rlink_l2_handler, NULL);
    866         break;
    867     case RLINK_TYPE_RX:
    868         (void)bcm_rx_queue_register(unit, "rlink",
    869                                     BCM_RX_COS_ALL,
    870                                     _bcm_rlink_rx_handler,
    871                                     ct_rx_tunnel_priority_get(), NULL,
    872                                     BCM_RCO_F_ALL_COS);
    873 
    874         break;
    875     case RLINK_TYPE_OAM:
    876         (void)bcm_oam_event_register(unit, 
    877                                      args->u.oam.events,
    878                                      _bcm_rlink_oam_handler,
    879                                      NULL);
    880         break;
    881     case RLINK_TYPE_BFD:
    882 #if defined(INCLUDE_BFD)
    883         (void)bcm_bfd_event_register(unit, 
    884                                      args->u.bfd.events,
    885                                      _bcm_rlink_bfd_handler,
    886                                      NULL);
    887 #endif
    888         break;
    889     default:
    890 	break;
    891     }
    892 }
    893 
    894 
    895 STATIC void
    896 _bcm_rlink_scan_delete(cpudb_key_t cpu, int unit, rlink_type_t type,
    897                        _rlink_register_args_t *args)
    898 {
    899     _rlink_scan_t	*rscan, *pscan;
    900     int			last;
    901 
    902     if(!BCM_CONTROL_UNIT_LEGAL(unit)) {
    903         LOG_WARN(BSL_LS_SOC_COMMON,
    904                  (BSL_META_U(unit,
    905                              "RLINK unit is out of range\n")));
    906         return;
    907     }
    908 
    909     if (!BCM_IS_LOCAL(unit)) {
    910         LOG_WARN(BSL_LS_SOC_COMMON,
    911                  (BSL_META_U(unit,
    912                              "RLINK scan delete on non-local unit %d, "
    913                              "type %s\n"), unit, TYPE_STR(type)));
    914     }
    915     LOG_VERBOSE(BSL_LS_SOC_COMMON,
    916                 (BSL_META_U(unit,
    917                             "RLINK scan delete on unit %d, type %s for CPU "
    918                             CPUDB_KEY_FMT_EOLN), unit, TYPE_STR(type),
    919                  CPUDB_KEY_DISP(cpu)));
    920 
    921     RLINK_LOCK;
    922     pscan = NULL;
    923     for (rscan = _rlink_scan_head; rscan != NULL;
    924 	 pscan = rscan, rscan = rscan->next) {
    925 	if (rscan->type == type && rscan->unit == unit &&
    926 	    CPUDB_KEY_EQUAL(rscan->cpu, cpu)) {
    927 	    if (pscan == NULL) {
    928 		_rlink_scan_head = rscan->next;
    929 	    } else {
    930 		pscan->next = rscan->next;
    931 	    }
    932 	    if (rscan == _rlink_scan_tail) {
    933 		_rlink_scan_tail = pscan;
    934 	    }
    935 	    break;
    936 	}
    937     }
    938 
    939     if (rscan == NULL) {
    940 	RLINK_UNLOCK;
    941 	return;			/* not found */
    942     }
    943 
    944     /* Check if no more entries of this type, on this unit */
    945     last = TRUE;
    946     for (pscan = _rlink_scan_head; pscan != NULL; pscan = pscan->next) {
    947 	if (type == pscan->type && unit == pscan->unit) {
    948 	    last = FALSE;
    949 	    break;
    950 	}
    951     }
    952 
    953     RLINK_UNLOCK;
    954 
    955     sal_free(rscan);
    956 
    957     if (last) {
    958 	switch (type) {
    959 	case RLINK_TYPE_LINK:
    960 	    (void)bcm_linkscan_unregister(unit,
    961 					  _bcm_rlink_linkscan_handler);
    962 	    break;
    963 	case RLINK_TYPE_AUTH: /* Clear callback with NULL as function */
    964 	    (void)bcm_auth_unauth_callback(unit, NULL, NULL);
    965 	    break;
    966 	case RLINK_TYPE_L2:
    967 	    (void)bcm_l2_addr_unregister(unit,
    968 					 _bcm_rlink_l2_handler, NULL);
    969 	    break;
    970 	case RLINK_TYPE_RX:
    971 	    (void)bcm_rx_unregister(unit, _bcm_rlink_rx_handler,
    972 				    ct_rx_tunnel_priority_get());
    973 	    break;
    974 	case RLINK_TYPE_OAM:
    975 	    (void)bcm_oam_event_unregister(unit, 
    976                                        args->u.oam.events,
    977                                        _bcm_rlink_oam_handler);
    978 	    break;
    979 	case RLINK_TYPE_BFD:
    980 #if defined(INCLUDE_BFD)
    981 	    (void)bcm_bfd_event_unregister(unit, 
    982                                        args->u.bfd.events,
    983                                        _bcm_rlink_bfd_handler);
    984 #endif
    985 	    break;
    986 	default:
    987 	    break;
    988 	}
    989     }
    990 }
    991 
    992 /*
    993  * Function:
    994  *      bcm_rlink_device_clear
    995  * Purpose:
    996  *      Clear the RLINK state for the given LOCAL unit (server clear).
    997  * Parameters:
    998  *      unit     - LOCAL unit number
    999  * Notes:
   1000  *      Removes all RLINK refs for the given unit.  It might be
   1001  *      better to do this on a per-CPU basis as well, but currently,
   1002  *      only the master CPU ever gets referenced here.  In addition,
   1003  *      this could probably be done once for all local units
   1004  *      controlled, but this is more consistent with the rest of the API.
   1005  *
   1006  *      See rlink_device_detach for sending a cleanup call to a remote
   1007  *      device.
   1008  */
   1009 
   1010 void
   1011 bcm_rlink_device_clear(int unit)
   1012 {
   1013     _rlink_scan_t       *cur_entry, *next_entry, *prev_entry;
   1014     bcm_oam_event_types_t oam_events;
   1015 #if defined(INCLUDE_BFD)
   1016     bcm_bfd_event_types_t bfd_events;
   1017 #endif
   1018     if (!RLINK_INIT) {
   1019         return;
   1020     }
   1021 
   1022     prev_entry = NULL;
   1023 
   1024     RLINK_LOCK;
   1025     for (cur_entry = _rlink_scan_head; cur_entry != NULL;
   1026          cur_entry = next_entry) {
   1027         next_entry = cur_entry->next;
   1028 
   1029         if (cur_entry->unit == unit) {  /* Remove entry */
   1030             if (prev_entry != NULL) {
   1031                 prev_entry->next = cur_entry->next;
   1032             } else {
   1033                 _rlink_scan_head = cur_entry->next;
   1034             }
   1035             sal_free(cur_entry);
   1036 
   1037         } else {
   1038             prev_entry = cur_entry;
   1039         }
   1040     }
   1041     RLINK_UNLOCK;
   1042 
   1043     /* Set all bits to clear all oam events */
   1044     sal_memset(&(oam_events), 1, sizeof(bcm_oam_event_types_t));
   1045 #if defined(INCLUDE_BFD)
   1046     sal_memset(&(bfd_events), 1, sizeof(bcm_bfd_event_types_t));
   1047 #endif
   1048     (void)bcm_linkscan_unregister(unit, _bcm_rlink_linkscan_handler);
   1049     (void)bcm_auth_unauth_callback(unit, NULL, NULL);
   1050     (void)bcm_l2_addr_unregister(unit, _bcm_rlink_l2_handler, NULL);
   1051     (void)bcm_rx_unregister(unit, _bcm_rlink_rx_handler,
   1052                             ct_rx_tunnel_priority_get());
   1053     (void)bcm_oam_event_unregister(unit, oam_events,
   1054                                    _bcm_rlink_oam_handler);
   1055 #if defined(INCLUDE_BFD)
   1056     (void)bcm_bfd_event_unregister(unit, bfd_events,
   1057                                    _bcm_rlink_bfd_handler);
   1058 #endif
   1059 }
   1060 
   1061 /*
   1062  * Function:
   1063  *      bcm_rlink_server_clear
   1064  * Purpose:
   1065  *      Clear all RLINK server (local) information.
   1066  * Notes:
   1067  *      Forces de-registration of rlink callbacks on local units
   1068  */
   1069 
   1070 void
   1071 bcm_rlink_server_clear(void)
   1072 {
   1073     _rlink_scan_t       *cur_entry, *next_entry;
   1074     int			unit;
   1075     bcm_oam_event_types_t oam_events;
   1076 #if defined(INCLUDE_BFD)
   1077     bcm_bfd_event_types_t bfd_events;
   1078 #endif
   1079 
   1080     /* Set all bits to clear all oam events */
   1081     sal_memset(&(oam_events), 1, sizeof(bcm_oam_event_types_t));
   1082 #if defined(INCLUDE_BFD)
   1083     sal_memset(&(bfd_events), 1, sizeof(bcm_bfd_event_types_t));
   1084 #endif
   1085     RLINK_LOCK;
   1086 
   1087     /* Clear server information */
   1088     for (cur_entry = _rlink_scan_head; cur_entry != NULL;
   1089              cur_entry = next_entry) {
   1090         next_entry = cur_entry->next;
   1091         sal_free(cur_entry);
   1092     }
   1093 
   1094     _rlink_scan_head = _rlink_scan_tail = NULL;
   1095 
   1096     for (unit = 0; unit < BCM_MAX_NUM_UNITS; unit++) {
   1097         (void)bcm_linkscan_unregister(unit, _bcm_rlink_linkscan_handler);
   1098         (void)bcm_auth_unauth_callback(unit, NULL, NULL);
   1099         (void)bcm_l2_addr_unregister(unit, _bcm_rlink_l2_handler, NULL);
   1100         (void)bcm_rx_unregister(unit, _bcm_rlink_rx_handler,
   1101                                 ct_rx_tunnel_priority_get());
   1102         (void)bcm_oam_event_unregister(unit, oam_events,
   1103                                        _bcm_rlink_oam_handler);
   1104 #if defined(INCLUDE_BFD)
   1105         (void)bcm_bfd_event_unregister(unit, bfd_events,
   1106                                        _bcm_rlink_bfd_handler);
   1107 #endif
   1108     }
   1109 
   1110     bcm_rlink_traverse_server_clear();    
   1111     RLINK_UNLOCK;
   1112 }
   1113 
   1114 /*
   1115  * Function:
   1116  *      bcm_rlink_client_clear
   1117  * Purpose:
   1118  *      Clear all client (remote related) information
   1119  */
   1120 
   1121 void
   1122 bcm_rlink_client_clear(void)
   1123 {
   1124     _rlink_handle_t	*cur_hand, *next_hand;
   1125 
   1126     RLINK_LOCK;
   1127 
   1128     /* Clear client information */
   1129     for (cur_hand = _rlink_handle_head; cur_hand != NULL;
   1130              cur_hand = next_hand) {
   1131         next_hand = cur_hand->next;
   1132         sal_free(cur_hand);
   1133     }
   1134 
   1135     _rlink_handle_head = _rlink_handle_tail = NULL;
   1136 
   1137     bcm_rlink_traverse_client_clear();    
   1138     RLINK_UNLOCK;
   1139 }
   1140 
   1141 /*
   1142  * Function:
   1143  *      bcm_rlink_clear
   1144  * Purpose:
   1145  *      Clear both client and server state
   1146  */
   1147 
   1148 void
   1149 bcm_rlink_clear(void)
   1150 {
   1151     bcm_rlink_server_clear();
   1152     bcm_rlink_client_clear();
   1153 }
   1154 
   1155 /*
   1156  * Client side packet send
   1157  */
   1158 STATIC int
   1159 _bcm_rlink_send_control(cpudb_key_t cpu, int unit,
   1160                         rlink_msg_t msg, rlink_type_t type,
   1161                         _rlink_register_args_t *args)
   1162 {
   1163     uint8	*buf, *bp;
   1164     int		len;
   1165     int     i;
   1166     int     rv = BCM_E_NONE;
   1167 
   1168     LOG_VERBOSE(BSL_LS_SOC_COMMON,
   1169                 (BSL_META_U(unit,
   1170                             "RLINK ctl msg %s, cpu-unit %d, type %s to "
   1171                             CPUDB_KEY_FMT_EOLN), MSG_STR(msg), unit, TYPE_STR(type),
   1172                  CPUDB_KEY_DISP(cpu)));
   1173     len = 1 + 1 + 4;	/* msg, type, unit */
   1174     /* Other arguments for register function */
   1175     if (args) {
   1176         switch (type) {
   1177         case RLINK_TYPE_OAM:    /* event_types */
   1178             for (i = 0; i < _BCM_OAM_EVENT_TYPES_ARRAY_SIZE; i++) {
   1179                 len += 4;
   1180             }
   1181             break;
   1182         case RLINK_TYPE_BFD:    /* event_types */
   1183 #if defined(INCLUDE_BFD)
   1184             for (i = 0; i < _BCM_BFD_EVENT_TYPES_ARRAY_SIZE; i++) {
   1185                 len += 4;
   1186             }
   1187 #endif
   1188             break;
   1189         default:
   1190             break;
   1191         }
   1192     }
   1193 
   1194     buf = atp_tx_data_alloc(len);
   1195     if (buf == NULL) {
   1196         INCR_COUNTER(rlink_buff_alloc_fail);
   1197         return BCM_E_MEMORY;
   1198     }
   1199     bp = bcm_rlink_encode(buf, msg, type, unit);
   1200 
   1201     /* Other arguments for register function */
   1202     if (args) {
   1203         switch (type) {
   1204         case RLINK_TYPE_OAM:
   1205             for (i = 0; i < _BCM_OAM_EVENT_TYPES_ARRAY_SIZE; i++) {
   1206                 BCM_PACK_U32(bp, args->u.oam.events.w[i]);
   1207             }
   1208             break;
   1209         case RLINK_TYPE_BFD:
   1210 #if defined(INCLUDE_BFD)
   1211             for (i = 0; i < _BCM_BFD_EVENT_TYPES_ARRAY_SIZE; i++) {
   1212                 BCM_PACK_U32(bp, args->u.bfd.events.w[i]);
   1213             }
   1214 #endif
   1215             break;
   1216         default:
   1217             break;
   1218         }
   1219     }
   1220 
   1221     rv = atp_tx(cpu, RLINK_CLIENT_ID, buf, len, 0, NULL, NULL);
   1222     if (BCM_FAILURE(rv)) {
   1223         INCR_COUNTER(rlink_pkt_send_fail);
   1224     }
   1225     atp_tx_data_free(buf);
   1226     return rv;
   1227 }
   1228 
   1229 /*
   1230  * Function:
   1231  *  _bcm_rlink_handle_list_add
   1232  *
   1233  * Purpose:
   1234  *     Internal function to add data to list _rlink_handle_head/tail.
   1235  *     Data would only be added if it is already not exising in the
   1236  *     list. Fields 'unit', 'type' and 'function' from the parameter
   1237  *     'data_node' would be used as keys to search the list.
   1238  *
   1239  * Parameters:
   1240  *     data_node - (IN) Node with data to be added.
   1241  *
   1242  * Returns:
   1243  *     BCM_E_NONE - Successfully added the data to the list
   1244  *     BCM_E_EXISTS - Data not added as it already exists in the list
   1245  *     BCM_E_MEMORY - Data not added as memory Allocation failed
   1246  *
   1247  * Note:
   1248  */
   1249 STATIC int
   1250 _bcm_rlink_handle_list_add(_rlink_handle_t *data_node) {
   1251 
   1252     int rv = BCM_E_NONE;
   1253     _rlink_handle_t *rhand = NULL;
   1254 
   1255     /* Lock the list */
   1256     RLINK_LOCK;
   1257 
   1258     /* See if already registered */
   1259     for (rhand = _rlink_handle_head; rhand != NULL; rhand = rhand->next) {
   1260         if (rhand->type == data_node->type &&
   1261             rhand->unit == data_node->unit &&
   1262             rhand->func.generic_func_ptr == data_node->func.generic_func_ptr) {
   1263                 RLINK_UNLOCK;
   1264                 return BCM_E_EXISTS;
   1265         }
   1266     }
   1267 
   1268     /* Allocate memory for the node */
   1269     rhand = sal_alloc(sizeof(*rhand), "bcm_rlink_handle");
   1270     if (rhand == NULL) {
   1271         RLINK_UNLOCK;
   1272         return BCM_E_MEMORY;
   1273     }
   1274 
   1275     /* Fill in the data */
   1276     rhand->unit = data_node->unit;
   1277     rhand->type = data_node->type;
   1278     rhand->func.generic_func_ptr = data_node->func.generic_func_ptr;
   1279     rhand->cookie = data_node->cookie;
   1280     CPUDB_KEY_COPY(rhand->cpu, data_node->cpu);
   1281     rhand->cunit = data_node->cunit;
   1282     rhand->next = NULL;
   1283 
   1284     /* Call routine to add it to the list */
   1285     if (_rlink_handle_tail == NULL) {
   1286         _rlink_handle_head = _rlink_handle_tail = rhand;
   1287     } else {
   1288         _rlink_handle_tail->next = rhand;
   1289         _rlink_handle_tail = rhand;
   1290     }
   1291 
   1292     /* Unlock the list */
   1293     RLINK_UNLOCK;
   1294 
   1295     return rv;
   1296 }
   1297 
   1298 /*
   1299  * Function:
   1300  *  _bcm_rlink_handle_list_delete
   1301  *
   1302  * Purpose:
   1303  *     Internal function to delete data from list _rlink_handle_head/tail.
   1304  *     Data would only be deleted if it  exists in the list. Fields 'unit'
   1305  *     , 'type' and 'function' in parameter data_node would be used as keys
   1306  *     to search the list for pre-existence check.
   1307  *
   1308  * Parameters:
   1309  *     data_node - (IN/OUT) Node with data to be deleted. It acts in INPUT for
   1310  *                  fields unit, type, and OUTPUT for fields cookie, cpukey,
   1311  *                  cunit
   1312  *     last - (OUT) Indicates if the deleted node was the last of its kind
   1313  *
   1314  * Returns:
   1315  *     BCM_E_NONE - Successfully deleted the data from the list
   1316  *     BCM_E_NOT_FOUND - Data did not delete as it does not exist
   1317  *
   1318  * Note:
   1319  *     1) Matching Node will be removed from the list and its memory deallocated
   1320  *     2) Fields cookie, cpu and cunit in the given node are populated before
   1321  *         the node is de-allocated.
   1322  */
   1323 STATIC int
   1324 _bcm_rlink_handle_list_delete(_rlink_handle_t *data_node, int *last) {
   1325 
   1326     int rv = BCM_E_NONE;
   1327     _rlink_handle_t *rhand = NULL, *phand = NULL;
   1328 
   1329     /* Lock the list */
   1330     RLINK_LOCK;
   1331 
   1332     for (rhand = _rlink_handle_head;
   1333          rhand != NULL;
   1334          phand = rhand, rhand = rhand->next) {
   1335             if (rhand->type == data_node->type &&
   1336               rhand->unit == data_node->unit &&
   1337               rhand->func.generic_func_ptr == data_node->func.generic_func_ptr)
   1338             {
   1339                 if (phand == NULL) {
   1340                     _rlink_handle_head = rhand->next;
   1341                 } else {
   1342                     phand->next = rhand->next;
   1343                 }
   1344                 if (rhand == _rlink_handle_tail) {
   1345                     _rlink_handle_tail = phand;
   1346                 }
   1347                 rhand->next = NULL;
   1348                 break;
   1349             }
   1350     }
   1351 
   1352     if (NULL == rhand) {
   1353         /* Since entry not found, mark it so */
   1354         rv = BCM_E_NOT_FOUND;
   1355     } else {
   1356         /* Save cookie, cpu_key and cunit infortmation */
   1357         CPUDB_KEY_COPY(data_node->cpu, rhand->cpu);
   1358         data_node->cunit = rhand->cunit;
   1359         data_node->cookie = rhand->cookie;
   1360 
   1361         /* De-allocate the node memory */
   1362         sal_free(rhand);
   1363 
   1364         /* See if this was the last entry for this unit */
   1365         if (NULL != last) {
   1366             *last = 1; /* Mark it to be the last at first */
   1367 
   1368             for (phand = _rlink_handle_head; phand != NULL; phand = phand->next)
   1369             {
   1370                 if (phand->type == data_node->type &&
   1371                     phand->unit == data_node->unit) {
   1372                     *last = 0;
   1373                     break;
   1374                 }
   1375             }
   1376         }
   1377     }
   1378 
   1379     /* Unlock the list */
   1380     RLINK_UNLOCK;
   1381 
   1382     return rv;
   1383 }
   1384 
   1385 /*
   1386  * Function:
   1387  *      _bcm_rlink_register
   1388  *
   1389  * Purpose:
   1390  *      Generic function to register a rlink callback.
   1391  *      Initially the callback data is added to a client rlink list pointed
   1392  *      by '_rlink_handle_head'. Next the remote device is sent a RLINK_MSG
   1393  *      with type ADD. If the MSG returns back with an error or the send
   1394  *      itself failed then the previous step of adding the data to the list
   1395  *      is reverted by deleting it back from the list.
   1396  *
   1397  * Parameters:
   1398  *      node - (IN/OUT) List node.
   1399  *      args - (IN) register event, if any
   1400  *
   1401  * Returns:
   1402  *      BCM_E_NONE - Successful registration
   1403  *      BCM_E_XXX - Other failures
   1404  */
   1405 STATIC int
   1406 _bcm_rlink_register(_rlink_handle_t *node, _rlink_register_args_t *args)
   1407 {
   1408     int is_new_data = 1;
   1409     int rv = BCM_E_NONE;
   1410 
   1411     if (!RLINK_INIT) {
   1412         return BCM_E_UNAVAIL;
   1413     }
   1414 
   1415     /* Deduce and store CPUDB_KEY and CUNIT */
   1416     CPUDB_KEY_COPY(node->cpu,
   1417                    *((cpudb_key_t *)BCM_CONTROL(node->unit)->drv_control));
   1418     node->cunit = BCM_CONTROL(node->unit)->unit;
   1419 
   1420     /* Call internal routine to add the data to the list */
   1421     rv = _bcm_rlink_handle_list_add(node);
   1422     if (BCM_E_EXISTS == rv) {
   1423         is_new_data = 0;
   1424     } else if(BCM_FAILURE(rv)) {
   1425         return rv;
   1426     }
   1427 
   1428     /* always send an ADD, just in case */
   1429     rv = _bcm_rlink_send_control(
   1430             node->cpu, node->cunit, RLINK_MSG_ADD, node->type, args);
   1431 
   1432     /* Perform graceful error handling */
   1433     if (BCM_FAILURE(rv) && (1 == is_new_data)) {
   1434         /* Delete the just added entry from the list */
   1435         (void)_bcm_rlink_handle_list_delete(node, NULL);
   1436     }
   1437 
   1438     return rv;
   1439 }
   1440 
   1441 /*
   1442  * Function:
   1443  *      _bcm_rlink_unregister
   1444  *
   1445  * Purpose:
   1446  *      Generic function to deregister a rlink callback.
   1447  *      Initially the callback data is deleted from the client rlink list
   1448  *      pointed by '_rlink_handle_head'. Next the remote device is sent a
   1449  *      RLINK_MSG with type DELETE. If the MSG returns back with an error
   1450  *      or the send itself failed then the previous step of removing the
   1451  *      data from the list is reverted by adding it back to the list.
   1452  *
   1453  * Parameters:
   1454  *      node - (IN/OUT) Node with data which has to be deleted.
   1455  *      args - (IN) register event, if any
   1456  *
   1457  * Returns:
   1458  *      BCM_E_NONE - Successful de-registration
   1459  *      BCM_E_XXX - Other failures
   1460  */
   1461 STATIC int
   1462 _bcm_rlink_unregister(_rlink_handle_t *node, _rlink_register_args_t *args)
   1463 {
   1464     int         last = 1;
   1465     int         rv = BCM_E_NONE;
   1466 
   1467     if (!RLINK_INIT) {
   1468         return BCM_E_UNAVAIL;
   1469     }
   1470 
   1471     /* Delete the details from the internal list */
   1472     rv = _bcm_rlink_handle_list_delete(node, &last);
   1473 
   1474     if (BCM_E_NOT_FOUND == rv) { /* Entry not found- NOOP and return success */
   1475         rv = BCM_E_NONE;
   1476     } else if (BCM_E_NONE == rv) {  /* Found an entry which was removed */
   1477         if (last) {
   1478             rv = _bcm_rlink_send_control(node->cpu, node->cunit,
   1479                                          RLINK_MSG_DELETE, node->type, args);
   1480         }
   1481 
   1482         if (BCM_FAILURE(rv)) {
   1483             /* If send Msg failed then revert the list changes */
   1484             (void) _bcm_rlink_handle_list_add(node);
   1485         }
   1486     }
   1487 
   1488     return rv;
   1489 }
   1490 
   1491 uint8 *bcm_rlink_decode(uint8 *buf,
   1492                         rlink_msg_t *msgp, rlink_type_t *typep, int *unitp)
   1493 {
   1494     
   1495     uint8 *bp = buf;
   1496     rlink_msg_t msg;
   1497     rlink_type_t type;
   1498     int unit;
   1499     
   1500     BCM_UNPACK_U8(bp, msg);
   1501     BCM_UNPACK_U8(bp, type);
   1502     BCM_UNPACK_U32(bp, unit);
   1503 
   1504     *msgp = msg;
   1505     *typep = type;
   1506     *unitp = unit;
   1507     return bp;
   1508 }
   1509 
   1510 uint8 *bcm_rlink_encode(uint8 *buf,
   1511                         rlink_msg_t msg, rlink_type_t type, int unit)
   1512 {
   1513     
   1514     uint8 *bp = buf;
   1515     
   1516     BCM_PACK_U8(bp, msg);
   1517     BCM_PACK_U8(bp, type);
   1518     BCM_PACK_U32(bp, unit);
   1519 
   1520     return bp;
   1521 }
   1522 
   1523 /*
   1524  * Packet handler.
   1525  * On client side receives notify packets from server.
   1526  * On server side receives add/delete packets from client.
   1527  */
   1528 STATIC bcm_rx_t
   1529 _bcm_rlink_pkt_handler(cpudb_key_t cpu,
   1530                        int client_id,
   1531                        bcm_pkt_t *pkt,
   1532                        uint8 *buf,
   1533                        int buf_len,
   1534                        void *cookie)
   1535 {
   1536     uint8               *bp;
   1537     int                 unit;
   1538     rlink_msg_t		msg;
   1539     rlink_type_t	type;
   1540     _rlink_notify_t     *rnot;
   1541     int                 i;
   1542     bcm_rx_t            rv;
   1543 
   1544     COMPILER_REFERENCE(client_id);
   1545     COMPILER_REFERENCE(cookie);
   1546 
   1547     LOG_VERBOSE(BSL_LS_SOC_COMMON,
   1548                 (BSL_META("RLINK msg IN from "
   1549                           CPUDB_KEY_FMT_EOLN),
   1550                  CPUDB_KEY_DISP(cpu)));
   1551 
   1552     if (!RLINK_INIT || _rlink_thread_exit) {
   1553 	return BCM_RX_NOT_HANDLED;
   1554     }
   1555 
   1556     bp = bcm_rlink_decode(buf, &msg, &type, &unit);
   1557 
   1558     LOG_VERBOSE(BSL_LS_SOC_COMMON,
   1559                 (BSL_META_U(unit,
   1560                             "RLINK IN msg %s, local-unit %d, type %s\n"),
   1561                  MSG_STR(msg), unit, TYPE_STR(type)));
   1562 
   1563     rnot = NULL;
   1564     rv = BCM_RX_HANDLED;
   1565 
   1566     switch (msg) {
   1567     case RLINK_MSG_TRAVERSE:
   1568         INCR_COUNTER(rlink_trav_req_in);
   1569         rnot = sal_alloc(sizeof(*rnot), "bcm_rlink_notify");
   1570         if (rnot == NULL) {
   1571             return BCM_RX_HANDLED;              /* failure */
   1572         }
   1573         CPUDB_KEY_COPY(rnot->cpu, cpu);
   1574         rnot->unit = unit;
   1575         rnot->type = type;
   1576         rnot->pkt_send = FALSE;
   1577         rnot->next = NULL;
   1578         rnot->u.traverse.pkt = pkt;
   1579         rnot->u.traverse.buf = buf;
   1580         rnot->u.traverse.len = buf_len;
   1581         rv = BCM_RX_HANDLED_OWNED;
   1582         break;
   1583     case RLINK_MSG_ADD:
   1584         INCR_COUNTER(rlink_add_req_in);
   1585         rnot = sal_alloc(sizeof(*rnot), "bcm_rlink_notify");
   1586         if (rnot == NULL) {
   1587             return BCM_RX_HANDLED;              /* failure */
   1588         }
   1589         CPUDB_KEY_COPY(rnot->cpu, cpu);
   1590         rnot->unit = unit;
   1591         rnot->type = RLINK_TYPE_ADD;
   1592         rnot->u.msg.type = type;
   1593         rnot->pkt_send = FALSE;
   1594         rnot->next = NULL;
   1595         /* Other parameters in the registration routine */
   1596         switch (type) {
   1597         case RLINK_TYPE_OAM:
   1598             for (i = 0; i < _BCM_OAM_EVENT_TYPES_ARRAY_SIZE; i++) {
   1599                 BCM_UNPACK_U32(bp, rnot->register_args.u.oam.events.w[i]);
   1600             }
   1601             break;
   1602         case RLINK_TYPE_BFD:
   1603 #if defined(INCLUDE_BFD)
   1604             for (i = 0; i < _BCM_BFD_EVENT_TYPES_ARRAY_SIZE; i++) {
   1605                 BCM_UNPACK_U32(bp, rnot->register_args.u.bfd.events.w[i]);
   1606             }
   1607 #endif
   1608             break;
   1609         default:
   1610             break;
   1611         }
   1612         break;
   1613     case RLINK_MSG_DELETE:
   1614         INCR_COUNTER(rlink_del_req_in);
   1615         rnot = sal_alloc(sizeof(*rnot), "bcm_rlink_notify");
   1616         if (rnot == NULL) {
   1617             return BCM_RX_HANDLED;              /* failure */
   1618         }
   1619         CPUDB_KEY_COPY(rnot->cpu, cpu);
   1620         rnot->unit = unit;
   1621         rnot->type = RLINK_TYPE_DELETE;
   1622 	rnot->u.msg.type = type;
   1623         rnot->pkt_send = FALSE;
   1624         rnot->next = NULL;
   1625 	break;
   1626     case RLINK_MSG_NOTIFY:
   1627         INCR_COUNTER(rlink_notify_in);
   1628         /* See if currently space in the queue */
   1629         switch (type) {
   1630         case RLINK_TYPE_LINK:
   1631             INCR_COUNTER(rlink_link_in);
   1632             if (bcm_rlink_link_local_max > 0 &&
   1633 		_rlink_queue_size > bcm_rlink_link_local_max) {
   1634                 INCR_COUNTER(rlink_link_in_disc);
   1635                 return BCM_RX_HANDLED;
   1636             }
   1637             break;
   1638         case RLINK_TYPE_AUTH:
   1639             INCR_COUNTER(rlink_auth_in);
   1640             if (bcm_rlink_auth_local_max > 0 &&
   1641 		_rlink_queue_size > bcm_rlink_auth_local_max) {
   1642                 INCR_COUNTER(rlink_auth_in_disc);
   1643                 return BCM_RX_HANDLED;
   1644             }
   1645             break;
   1646         case RLINK_TYPE_L2:
   1647             INCR_COUNTER(rlink_l2_in);
   1648             if (bcm_rlink_l2_local_max > 0 &&
   1649 		_rlink_queue_size > bcm_rlink_l2_local_max) {
   1650                 INCR_COUNTER(rlink_l2_in_disc);
   1651                 return BCM_RX_HANDLED;
   1652             }
   1653             break;
   1654         case RLINK_TYPE_RX:
   1655             INCR_COUNTER(rlink_rx_in);
   1656             ct_rx_tunnelled_pkt_handler(cpu, bp, buf_len - 1 - 1 - 4);
   1657 	    return BCM_RX_HANDLED;
   1658 	    break;
   1659         case RLINK_TYPE_OAM:
   1660             INCR_COUNTER(rlink_oam_in);
   1661             if (bcm_rlink_oam_local_max > 0 &&
   1662                 _rlink_queue_size > bcm_rlink_oam_local_max) {
   1663                 INCR_COUNTER(rlink_oam_in_disc);
   1664                 return BCM_RX_HANDLED;
   1665             }
   1666             break;
   1667 	default:
   1668 	    break;
   1669         }
   1670         rnot = sal_alloc(sizeof(*rnot), "bcm_rlink_notify");
   1671         if (rnot == NULL) {
   1672             return BCM_RX_HANDLED;              /* failure */
   1673         }
   1674         CPUDB_KEY_COPY(rnot->cpu, cpu);
   1675         rnot->unit = unit;
   1676         rnot->type = type;
   1677         rnot->pkt_send = FALSE;
   1678         rnot->next = NULL;
   1679         switch (type) {
   1680         case RLINK_TYPE_LINK:
   1681             BCM_UNPACK_U32(bp, rnot->u.link.port);
   1682             (void) _bcm_unpack_port_info(bp, &rnot->u.link.info);
   1683             break;
   1684         case RLINK_TYPE_AUTH:
   1685             BCM_UNPACK_U32(bp, rnot->u.auth.port);
   1686             BCM_UNPACK_U32(bp, rnot->u.auth.reason);
   1687             break;
   1688         case RLINK_TYPE_L2:
   1689             BCM_UNPACK_U8(bp, rnot->u.l2.insert);
   1690             (void) _bcm_unpack_l2_addr(bp, &rnot->u.l2.addr);
   1691             break;
   1692         case RLINK_TYPE_OAM:
   1693             BCM_UNPACK_U32(bp, rnot->u.oam.flags);
   1694             BCM_UNPACK_U32(bp, rnot->u.oam.event_type);
   1695             BCM_UNPACK_U32(bp, rnot->u.oam.group);
   1696             BCM_UNPACK_U32(bp, rnot->u.oam.endpoint);
   1697             break;
   1698 	default:
   1699 	    break;
   1700         }
   1701         break;
   1702     }
   1703 
   1704     if (rnot != NULL) {
   1705 	RLINK_ENQUEUE_NOTIFY(rnot);
   1706     }
   1707     return rv;
   1708 }
   1709 
   1710 /*
   1711  * Process a notify record.
   1712  */
   1713 STATIC void
   1714 _bcm_rlink_notify(_rlink_notify_t *rnot)
   1715 {
   1716     _rlink_handle_t	*rhand, *nhand;
   1717 
   1718     if (rnot->pkt_send) { /* Send out prepared packet */
   1719 	_bcm_rlink_send_notify(rnot->unit,
   1720 			       rnot->type,
   1721 			       rnot->u.cli.buf,
   1722 			       rnot->u.cli.len,
   1723 			       rnot->u.cli.check_cpu,
   1724 			       rnot->cpu,
   1725 			       rnot->u.cli.ct_flags);
   1726 	return;
   1727     }
   1728 
   1729     /* server side scan add/delete requests */
   1730     switch (rnot->type) {
   1731     case RLINK_TYPE_ADD:
   1732 	_bcm_rlink_scan_add(rnot->cpu, rnot->unit, rnot->u.msg.type,
   1733                         &rnot->register_args);
   1734 	return;
   1735     case RLINK_TYPE_DELETE:
   1736 	_bcm_rlink_scan_delete(rnot->cpu, rnot->unit, rnot->u.msg.type,
   1737                            &rnot->register_args);
   1738 	return;
   1739 
   1740         /* traverse server and client messages are handles identically */
   1741     case RLINK_TYPE_START:
   1742     case RLINK_TYPE_NEXT:
   1743     case RLINK_TYPE_QUIT:
   1744     case RLINK_TYPE_ERROR:
   1745     case RLINK_TYPE_MORE:
   1746     case RLINK_TYPE_DONE:
   1747         (void)bcm_rlink_traverse_request(rnot->type,
   1748                                          rnot->cpu,
   1749                                          rnot->u.traverse.pkt,
   1750                                          rnot->u.traverse.buf,
   1751                                          rnot->u.traverse.len);
   1752         return;
   1753     default:
   1754 	break;
   1755     }
   1756 
   1757     /* client side handler callbacks */
   1758     RLINK_LOCK;
   1759     for (rhand = _rlink_handle_head; rhand != NULL; rhand = nhand) {
   1760 	nhand = rhand->next;
   1761 	if (rhand->cunit != rnot->unit) {
   1762 	    continue;
   1763 	}
   1764 	if (rhand->type != rnot->type) {
   1765 	    continue;
   1766 	}
   1767 	if (CPUDB_KEY_COMPARE(rhand->cpu, rnot->cpu) != 0) {
   1768 	    continue;
   1769 	}
   1770 	switch (rnot->type) {
   1771 	case RLINK_TYPE_LINK:
   1772 	    (*rhand->func.link)(rhand->unit,
   1773 				rnot->u.link.port,
   1774 				&rnot->u.link.info);
   1775 	    break;
   1776 	case RLINK_TYPE_AUTH:
   1777 	    (*rhand->func.auth)(rhand->cookie,
   1778                                 rhand->unit,
   1779                                 rnot->u.auth.port,
   1780                                 rnot->u.auth.reason);
   1781 	    break;
   1782 	case RLINK_TYPE_L2:
   1783 	    (*rhand->func.l2)(rhand->unit,
   1784 			      &rnot->u.l2.addr,
   1785 			      rnot->u.l2.insert,
   1786 			      rhand->cookie);
   1787 	    break;
   1788 	case RLINK_TYPE_OAM:
   1789 	    (*rhand->func.oam)(rhand->unit,
   1790                            rnot->u.oam.flags,
   1791                            rnot->u.oam.event_type,
   1792                            rnot->u.oam.group,
   1793                            rnot->u.oam.endpoint,
   1794                            rhand->cookie);
   1795 	    break;
   1796         default:
   1797             break;
   1798 	}
   1799     }
   1800     RLINK_UNLOCK;
   1801 }
   1802 
   1803 /*
   1804  * Client (and now server) side callback thread.
   1805  * Notify packets are sent to this thread to be executed.
   1806  */
   1807 STATIC void
   1808 _bcm_rlink_thread(void *cookie)
   1809 {
   1810     _rlink_notify_t	*rnot, *fnot;
   1811 
   1812     COMPILER_REFERENCE(cookie);
   1813 
   1814     _rlink_thread_exit = 0;
   1815     for (;;) {
   1816 	RLINK_SLEEP;
   1817 
   1818 	/* grab a set of notifications off the queue */
   1819 	RLINK_NOTIFY_LOCK;
   1820 	rnot = _rlink_notify_head;
   1821 	_rlink_notify_head = _rlink_notify_tail = NULL;
   1822         _rlink_queue_size = 0;
   1823 	RLINK_NOTIFY_UNLOCK;
   1824 
   1825 	/* run the notifications */
   1826 	while (rnot != NULL) {
   1827 	    _bcm_rlink_notify(rnot);
   1828             fnot = rnot;
   1829             rnot = rnot->next;
   1830             sal_free(fnot);
   1831         }
   1832 	if (_rlink_thread_exit) {
   1833 	    _rlink_thread = SAL_THREAD_ERROR;
   1834 	    sal_thread_exit(0);
   1835 	    return;
   1836 	}
   1837     }
   1838 }
   1839 
   1840 /*
   1841  * Externally visible api routines.
   1842  * Thread start/stop controls.
   1843  * Client registration functions.
   1844  */
   1845 
   1846 /*
   1847  * Start the remote registration system
   1848  */
   1849 int
   1850 bcm_rlink_start(void)
   1851 {
   1852     int		rv, flags, i;
   1853     int     rlink_auth_remote_max, rlink_auth_local_max;
   1854     int     rlink_l2_remote_max, rlink_l2_local_max;
   1855     int     rlink_link_remote_max, rlink_link_local_max;
   1856     int     rlink_oam_remote_max, rlink_oam_local_max;
   1857     int     rlink_rx_remote_max[BCM_COS_COUNT] = BCM_RLINK_RX_REMOTE_MAX_DEFAULT;
   1858     char    *rlink_rx_remote_properties[BCM_COS_COUNT] = {spn_RLINK_RX0_REMOTE_MAX,
   1859                                                           spn_RLINK_RX1_REMOTE_MAX,
   1860                                                           spn_RLINK_RX2_REMOTE_MAX,  
   1861                                                           spn_RLINK_RX3_REMOTE_MAX,  
   1862                                                           spn_RLINK_RX4_REMOTE_MAX,  
   1863                                                           spn_RLINK_RX5_REMOTE_MAX,  
   1864                                                           spn_RLINK_RX6_REMOTE_MAX,  
   1865                                                           spn_RLINK_RX7_REMOTE_MAX};  
   1866 
   1867     if (RLINK_INIT) {
   1868 	return BCM_E_BUSY;
   1869     }
   1870 
   1871     _rlink_lock = sal_mutex_create("bcm_rlink");
   1872     _rlink_notify_lock = sal_mutex_create("bcm_rlink_notify");
   1873     _rlink_sem = sal_sem_create("bcm_rlink", sal_sem_BINARY, 0);
   1874 
   1875     /* Get max values if different then default */
   1876     /* Givving 0 hard coded as unit to  soc_property_get is fine 
   1877        since these are unitless settings anyway */
   1878     if (SOC_UNIT_VALID(0)) {
   1879         rlink_auth_remote_max = soc_property_get(0, spn_RLINK_AUTH_REMOTE_MAX, -1);
   1880         rlink_auth_local_max = soc_property_get(0, spn_RLINK_AUTH_LOCAL_MAX, -1);
   1881         rlink_l2_remote_max = soc_property_get(0, spn_RLINK_L2_REMOTE_MAX, -1);
   1882         rlink_l2_local_max = soc_property_get(0, spn_RLINK_L2_LOCAL_MAX, -1);
   1883         rlink_link_remote_max = soc_property_get(0, spn_RLINK_LINK_REMOTE_MAX, -1);
   1884         rlink_link_local_max = soc_property_get(0, spn_RLINK_LINK_LOCAL_MAX, -1);
   1885         rlink_oam_remote_max = soc_property_get(0, spn_RLINK_OAM_REMOTE_MAX, -1);
   1886         rlink_oam_local_max = soc_property_get(0, spn_RLINK_OAM_LOCAL_MAX, -1);
   1887     } else {
   1888         rlink_auth_remote_max = -1;
   1889         rlink_auth_local_max = -1;
   1890         rlink_l2_remote_max = -1;
   1891         rlink_l2_local_max = -1;
   1892         rlink_link_remote_max = -1;
   1893         rlink_link_local_max = -1;
   1894         rlink_oam_remote_max = -1;
   1895         rlink_oam_local_max = -1;
   1896     }
   1897 
   1898     if (-1 != rlink_auth_remote_max) {
   1899         bcm_rlink_auth_remote_max = rlink_auth_remote_max;
   1900     }
   1901     if (-1 != rlink_auth_local_max) {
   1902         bcm_rlink_auth_local_max = rlink_auth_local_max;
   1903     }
   1904     if (-1 != rlink_l2_remote_max) {
   1905         bcm_rlink_l2_remote_max = rlink_l2_remote_max;
   1906     }
   1907     if (-1 != rlink_l2_local_max) {
   1908         bcm_rlink_l2_local_max = rlink_l2_local_max;
   1909     }
   1910     if (-1 != rlink_link_remote_max) {
   1911         bcm_rlink_link_remote_max = rlink_link_remote_max;
   1912     }
   1913     if (-1 != rlink_link_local_max) {
   1914         bcm_rlink_link_local_max = rlink_link_local_max;
   1915     }
   1916     if (-1 != rlink_oam_remote_max) {
   1917         bcm_rlink_oam_remote_max = rlink_oam_remote_max;
   1918     }
   1919     if (-1 != rlink_oam_local_max) {
   1920         bcm_rlink_oam_local_max = rlink_oam_local_max;
   1921     }
   1922 
   1923     for (i = 0 ; i < BCM_COS_COUNT; i++) {
   1924         if (SOC_UNIT_VALID(0)) {
   1925             rlink_rx_remote_max[i] = soc_property_get(0, rlink_rx_remote_properties[i], -1);
   1926         } else {
   1927             rlink_rx_remote_max[i] = -1;
   1928         }
   1929         if (-1 != rlink_rx_remote_max[i]) {
   1930             bcm_rlink_rx_remote_max[i] = rlink_rx_remote_max[i];
   1931         }
   1932     }
   1933 
   1934     _rlink_thread = sal_thread_create("bcmRLINK",
   1935 				      RLINK_THREAD_STACK,
   1936 				      RLINK_THREAD_PRIO,
   1937 				      _bcm_rlink_thread,
   1938 				      NULL);
   1939     if (_rlink_thread == SAL_THREAD_ERROR) {
   1940     	sal_sem_destroy(_rlink_sem);
   1941     	sal_mutex_destroy(_rlink_notify_lock);
   1942     	_rlink_notify_lock = NULL;
   1943     	sal_mutex_destroy(_rlink_lock);
   1944     	_rlink_lock = NULL;
   1945     
   1946         return BCM_E_RESOURCE;
   1947     }
   1948 
   1949     /* can be configured to use nexthop or cpu2cpu */
   1950     if (_rlink_nexthop) {
   1951         flags = ATP_F_REASSEM_BUF | ATP_F_NEXT_HOP;
   1952     } else {
   1953         flags = ATP_F_REASSEM_BUF;
   1954     }
   1955     rv = atp_register(RLINK_CLIENT_ID, flags,
   1956                       _bcm_rlink_pkt_handler, NULL, -1, -1);
   1957 
   1958     if (BCM_SUCCESS(rv)) {
   1959         rv = bcm_rlink_traverse_init();
   1960     }
   1961     return rv;
   1962 }
   1963 
   1964 /*
   1965  * Stop the remote registration system
   1966  */
   1967 int
   1968 bcm_rlink_stop(void)
   1969 {
   1970     _rlink_notify_t	*rnot, *nnot;
   1971 
   1972     if (!RLINK_INIT) {
   1973 	return BCM_E_NONE;
   1974     }
   1975     atp_unregister(RLINK_CLIENT_ID);
   1976 
   1977     /* destroy thread */
   1978     _rlink_thread_exit = 1;
   1979     RLINK_WAKE;
   1980     sal_thread_yield();
   1981     while (_rlink_thread != SAL_THREAD_ERROR) {
   1982 	RLINK_WAKE;
   1983 	sal_usleep(10000);
   1984     }
   1985 
   1986     /* free any queued notification */
   1987     RLINK_NOTIFY_LOCK;
   1988     rnot = _rlink_notify_head;
   1989     _rlink_notify_head = _rlink_notify_tail = NULL;
   1990     _rlink_queue_size = 0;
   1991     RLINK_NOTIFY_UNLOCK;
   1992     while (rnot != NULL) {
   1993 	nnot = rnot->next;
   1994 	sal_free(rnot);
   1995 	rnot = nnot;
   1996     }
   1997 
   1998     sal_sem_destroy(_rlink_sem);
   1999     sal_mutex_destroy(_rlink_notify_lock);
   2000     _rlink_notify_lock = NULL;
   2001     sal_mutex_destroy(_rlink_lock);
   2002     _rlink_lock = NULL;
   2003     (void) bcm_rlink_traverse_deinit();
   2004     return BCM_E_NONE;
   2005 }
   2006 
   2007 /*
   2008  * When a unit is detached from the system, this should be called.
   2009  * It will flush all rlink handlers asssociated with the unit.
   2010  * It should only be called for remote units.  Since it assumes the
   2011  * unit is gone, it does not do commands back to the controlling CPU.
   2012  */
   2013 
   2014 int
   2015 bcm_rlink_device_detach(int unit)
   2016 {
   2017     _rlink_handle_t	*rhand, *phand, *nhand;
   2018 
   2019     if (!RLINK_INIT) {
   2020 	return BCM_E_UNAVAIL;
   2021     }
   2022 
   2023     RLINK_LOCK;
   2024     phand = NULL;
   2025     for (rhand = _rlink_handle_head; rhand != NULL; /* see below */) {
   2026         nhand = rhand->next;   /* rhand my be deallocated */
   2027         if (unit == rhand->unit) {  /* Remove from list */
   2028             if (phand == NULL) {
   2029                 _rlink_handle_head = rhand->next;
   2030             } else {
   2031                 phand->next = rhand->next;
   2032             }
   2033             if (rhand == _rlink_handle_tail) {
   2034                 _rlink_handle_tail = phand;
   2035             }
   2036             sal_free(rhand);
   2037         } else {
   2038             phand = rhand;
   2039         }
   2040         rhand = nhand;
   2041     }
   2042     RLINK_UNLOCK;
   2043 
   2044     return BCM_E_NONE;
   2045 }
   2046 
   2047 /*
   2048  * Auth registration for de-authorization callback.
   2049  *
   2050  * Due to the implementation of the auth_unauth callback
   2051  * structure (there is only one call; it's not a register/unregister
   2052  * protocol) we make the following convention:  Multiple callbacks
   2053  * may be registered per device (unit).
   2054  *
   2055  * To de-register, func is passed as NULL.  This causes all
   2056  * registered entries that match unit and cookie to be deleted.
   2057  */
   2058 
   2059 int
   2060 bcm_client_auth_unauth_callback(int unit,
   2061                                 bcm_auth_cb_t func,
   2062                                 void *cookie)
   2063 {
   2064     int rv = BCM_E_NONE;
   2065 
   2066     if (!RLINK_INIT) {
   2067         return BCM_E_UNAVAIL;
   2068     }
   2069 
   2070     if (func == NULL) { /* Unregister entries matching unit and cookie */
   2071         int last = 1;
   2072         int cunit = 0;
   2073         int deleted = 0;
   2074         cpudb_key_t cpukey;
   2075         _rlink_handle_t *rhand = NULL; /* Iterator thru handler list */
   2076         _rlink_handle_t *phand = NULL; /* Track previous node in the list */
   2077         _rlink_handle_t *to_delete = NULL;
   2078         _rlink_handle_t *tmp_list_head = NULL;
   2079         _rlink_handle_t *tmp_list_tail = NULL;
   2080 
   2081         RLINK_LOCK;
   2082         for (rhand = _rlink_handle_head; rhand != NULL; ) {
   2083             if (rhand->type == RLINK_TYPE_AUTH && rhand->unit == unit) {
   2084                 if (rhand->cookie == cookie) {
   2085                     /* Record info in case disconnection done later */
   2086                     deleted = 1;
   2087                     CPUDB_KEY_COPY(cpukey, rhand->cpu);
   2088                     cunit = rhand->cunit;
   2089                     /* Remove this entry */
   2090                     if (phand == NULL) { /* First item on list being removed */
   2091                         _rlink_handle_head = rhand->next;
   2092                     } else {
   2093                         phand->next = rhand->next;
   2094                     }
   2095                     if (rhand == _rlink_handle_tail) { /* Last in list */
   2096                         _rlink_handle_tail = phand;
   2097                     }
   2098                     /* Safe deletion of pointer; don't update phand */
   2099                     to_delete = rhand;
   2100                     rhand = rhand->next;
   2101 
   2102                     /* Insert node to be deleted in the tmp list */
   2103                     to_delete->next = NULL;
   2104                     if (NULL == tmp_list_tail) {
   2105                         tmp_list_head = tmp_list_tail = to_delete;
   2106                     } else {
   2107                         tmp_list_tail->next = to_delete;
   2108                         tmp_list_tail = to_delete;
   2109                     }
   2110                 } else { /* Entry matches type and device, but not cookie */
   2111                     last = 0; /* Won't disconnect from CPU */
   2112                     phand = rhand;           /* Update pointers */
   2113                     rhand = rhand->next;
   2114                 }
   2115             } else {  /* Move to next entry in list */
   2116                 phand = rhand;
   2117                 rhand = rhand->next;
   2118             }
   2119         }
   2120         RLINK_UNLOCK;
   2121 
   2122         if (deleted) {
   2123             if (last) {
   2124                 rv = _bcm_rlink_send_control(cpukey, cunit,
   2125                                              RLINK_MSG_DELETE, RLINK_TYPE_AUTH,
   2126                                              NULL);
   2127             }
   2128 
   2129             if (BCM_SUCCESS(rv)) {
   2130                 /* Now de-allocate the deleted nodes */
   2131                 for (rhand = tmp_list_head; rhand != NULL;) {
   2132                     to_delete = rhand;
   2133                     rhand = rhand->next;
   2134                     sal_free(to_delete);
   2135                 }
   2136             } else {
   2137                 /* DEL Msg send failed, add back removed nodes to the list */
   2138                 RLINK_LOCK;
   2139                 if (NULL == _rlink_handle_tail) {
   2140                     _rlink_handle_head = tmp_list_head;
   2141                 } else {
   2142                     _rlink_handle_tail->next = tmp_list_head;
   2143                 }
   2144                 _rlink_handle_tail = tmp_list_tail;
   2145                 RLINK_UNLOCK;
   2146             }
   2147         }
   2148     } else {  /* Non-null function, register */
   2149         _rlink_handle_t node = {0};
   2150 
   2151         /* Fill in required details */
   2152         node.unit = unit;
   2153         node.type = RLINK_TYPE_AUTH;
   2154         node.func.auth = func;
   2155         node.cookie = cookie;
   2156 
   2157         rv = _bcm_rlink_register(&node, NULL);
   2158     }
   2159 
   2160     return rv;
   2161 }
   2162 
   2163 /*
   2164  * Register a linkscan callback function on the rpc client
   2165  * Referenced from the client dispatch table
   2166  */
   2167 int
   2168 bcm_client_linkscan_register(int unit, bcm_linkscan_handler_t f)
   2169 {
   2170     _rlink_handle_t node = {0};
   2171 
   2172     /* Fill in required details */
   2173     node.unit = unit;
   2174     node.type = RLINK_TYPE_LINK;
   2175     node.func.link = f;
   2176     node.cookie = NULL;
   2177 
   2178     return _bcm_rlink_register(&node, NULL);
   2179 }
   2180 
   2181 /*
   2182  * Remove a linkscan callback function on the rpc client
   2183  * Referenced from the client dispatch table
   2184  */
   2185 
   2186 int
   2187 bcm_client_linkscan_unregister(int unit, bcm_linkscan_handler_t f)
   2188 {
   2189     _rlink_handle_t node = {0};
   2190 
   2191     /* Fill in required details */
   2192     node.unit = unit;
   2193     node.type = RLINK_TYPE_LINK;
   2194     node.func.link = f;
   2195     node.cookie = NULL;
   2196 
   2197     return _bcm_rlink_unregister(&node, NULL);
   2198 }
   2199 
   2200 /*
   2201  * Register an l2 callback function on the rpc client
   2202  * Referenced from the client dispatch table
   2203  */
   2204 int
   2205 bcm_client_l2_addr_register(int unit,
   2206 			    bcm_l2_addr_callback_t f,
   2207 			    void *cookie)
   2208 {
   2209     _rlink_handle_t node = {0};
   2210 
   2211     /* Fill in required details */
   2212     node.unit = unit;
   2213     node.type = RLINK_TYPE_L2;
   2214     node.func.l2 = f;
   2215     node.cookie = cookie;
   2216 
   2217     return _bcm_rlink_register(&node, NULL);
   2218 }
   2219 
   2220 /*
   2221  * Remove an l2 callback function on the rpc client
   2222  * Referenced from the client dispatch table
   2223  */
   2224 int
   2225 bcm_client_l2_addr_unregister(int unit,
   2226 			      bcm_l2_addr_callback_t f,
   2227 			      void *cookie)
   2228 {
   2229     _rlink_handle_t node = {0};
   2230 
   2231     /* Fill in required details */
   2232     node.unit = unit;
   2233     node.type = RLINK_TYPE_L2;
   2234     node.func.l2 = f;
   2235     node.cookie = cookie;
   2236 ;
   2237     return _bcm_rlink_unregister(&node, NULL);
   2238 }
   2239 
   2240 
   2241 /*
   2242  * Register an oam event callback function on the rpc client
   2243  * Referenced from the client dispatch table
   2244  */
   2245 int
   2246 bcm_client_oam_event_register(int unit,
   2247                               bcm_oam_event_types_t event_types,
   2248                               bcm_oam_event_cb f,
   2249                               void *cookie)
   2250 {
   2251     _rlink_handle_t node = {0};
   2252     _rlink_register_args_t register_args;
   2253 
   2254     /* Fill in required details */
   2255     node.unit = unit;
   2256     node.type = RLINK_TYPE_OAM;
   2257     node.func.oam = f;
   2258     node.cookie = cookie;
   2259     register_args.u.oam.events = event_types;
   2260 
   2261     return _bcm_rlink_register(&node, &register_args);
   2262 }
   2263 
   2264 /*
   2265  * Remove an oam event callback function on the rpc client
   2266  * Referenced from the client dispatch table
   2267  */
   2268 int
   2269 bcm_client_oam_event_unregister(int unit,
   2270                                 bcm_oam_event_types_t event_types, 
   2271                                 bcm_oam_event_cb f)
   2272 {
   2273     _rlink_handle_t node = {0};
   2274     _rlink_register_args_t register_args;
   2275 
   2276     /* Fill in required details */
   2277     node.unit = unit;
   2278     node.type = RLINK_TYPE_OAM;
   2279     node.func.oam = f;
   2280     node.cookie = NULL;
   2281     register_args.u.oam.events = event_types;
   2282 
   2283     return _bcm_rlink_unregister(&node, &register_args);
   2284 }
   2285 
   2286 #if defined(INCLUDE_BFD)
   2287 /*
   2288  * Register an bfd event callback function on the rpc client
   2289  * Referenced from the client dispatch table
   2290  */
   2291 int
   2292 bcm_client_bfd_event_register(int unit,
   2293                               uint32 event_types,
   2294                               bcm_bfd_event_cb f,
   2295                               void *cookie)
   2296 {
   2297     /* to be done for BFD, including this function to compile */
   2298     return BCM_E_NONE;
   2299 }
   2300 
   2301 /*
   2302  * Remove an bfd event callback function on the rpc client
   2303  * Referenced from the client dispatch table
   2304  */
   2305 int
   2306 bcm_client_bfd_event_unregister(int unit,
   2307                                 uint32 event_types, 
   2308                                 bcm_bfd_event_cb f)
   2309 {
   2310     /* to be done for BFD, including this function to compile */
   2311     return BCM_E_NONE;
   2312 }
   2313 #endif
   2314 
   2315 /*
   2316  * Special connect and disconnect code for RX.
   2317  *
   2318  * These correspond to register and unregister above, but are slightly
   2319  * different because the function callbacks for RX are handled by
   2320  * the RX subsystem (so that the packets can go through the normal
   2321  * RX stack).
   2322  *
   2323  * The functions below make the proper setup happen for the RLink portion
   2324  * of the process.
   2325  *
   2326  * This assumes that the upper layer is keeping track of redundant
   2327  * calls for connecting, so no checking of that is done here.
   2328  *
   2329  * Unit must be a remote unit number; it is translated here to
   2330  * a physical unit number on the remote CPU.
   2331  */
   2332 
   2333 int
   2334 bcm_rlink_rx_connect(int unit)
   2335 {
   2336     cpudb_key_t *cpu;
   2337     int cpu_unit;
   2338 
   2339     if (!RLINK_INIT) {
   2340         return BCM_E_UNAVAIL;
   2341     }
   2342 
   2343     if (BCM_IS_LOCAL(unit)) {
   2344         return BCM_E_PARAM;
   2345     }
   2346 
   2347     cpu = (cpudb_key_t *)BCM_CONTROL(unit)->drv_control;
   2348     cpu_unit = BCM_CONTROL(unit)->unit;
   2349 
   2350     return (_bcm_rlink_send_control(
   2351                 *cpu, cpu_unit, RLINK_MSG_ADD, RLINK_TYPE_RX, NULL));
   2352 }
   2353 
   2354 int
   2355 bcm_rlink_rx_disconnect(int unit)
   2356 {
   2357     cpudb_key_t *cpu;
   2358     int cpu_unit;
   2359 
   2360     if (!RLINK_INIT) {
   2361         return BCM_E_UNAVAIL;
   2362     }
   2363 
   2364     if (BCM_IS_LOCAL(unit)) {
   2365         return BCM_E_PARAM;
   2366     }
   2367 
   2368     cpu = (cpudb_key_t *)BCM_CONTROL(unit)->drv_control;
   2369     cpu_unit = BCM_CONTROL(unit)->unit;
   2370 
   2371     return (_bcm_rlink_send_control(
   2372                 *cpu, cpu_unit, RLINK_MSG_DELETE, RLINK_TYPE_RX, NULL));
   2373 }
   2374 
   2375 #if defined(BROADCOM_DEBUG)
   2376 void
   2377 bcm_rlink_dump(void)
   2378 {
   2379     _rlink_handle_t *h_ent;
   2380     _rlink_scan_t *s_ent;
   2381 
   2382     if (_rlink_lock == NULL) {
   2383         LOG_CLI((BSL_META("RLink not initialized\n")));
   2384         return;
   2385     }
   2386 
   2387     LOG_CLI((BSL_META("RLink thread %x; thread exit %d\n"),
   2388              PTR_TO_INT(_rlink_thread), _rlink_thread_exit));
   2389 
   2390     LOG_CLI((BSL_META("Server side scan list\n")));
   2391     for (s_ent = _rlink_scan_head; s_ent != NULL; s_ent = s_ent->next) {
   2392         LOG_CLI((BSL_META("    Unit %d. Type %s. CPU " CPUDB_KEY_FMT_EOLN),
   2393                  s_ent->unit, TYPE_STR(s_ent->type),
   2394                  CPUDB_KEY_DISP(s_ent->cpu)));
   2395     }
   2396 
   2397     LOG_CLI((BSL_META("Client side handler registrants\n")));
   2398     for (h_ent = _rlink_handle_head; h_ent != NULL; h_ent = h_ent->next) {
   2399         LOG_CLI((BSL_META("    Fn %p. Unit %d. Type %s. CPU " CPUDB_KEY_FMT_EOLN),
   2400                           h_ent->func.link,
   2401                           h_ent->unit,
   2402                           TYPE_STR(h_ent->type),
   2403                  CPUDB_KEY_DISP(h_ent->cpu)));
   2404     }
   2405 
   2406     LOG_CLI((BSL_META("Counters:\n")));
   2407     LOG_CLI((BSL_META("  l2 in %d. l2 in disc %d. l2 out %d. l2 out disc %d\n"),
   2408              rlink_l2_in, rlink_l2_in_disc,
   2409              rlink_l2_out, rlink_l2_out_disc));
   2410     LOG_CLI((BSL_META("  link in %d. link in disc %d. link out %d. link out "
   2411                       "disc %d\n"), rlink_link_in, rlink_link_in_disc,
   2412              rlink_link_out, rlink_link_out_disc));
   2413     LOG_CLI((BSL_META("  auth in %d. auth in disc %d. auth out %d. auth out disc %d\n"),
   2414              rlink_auth_in, rlink_auth_in_disc,
   2415              rlink_auth_out, rlink_auth_out_disc));
   2416     LOG_CLI((BSL_META("  rx in %d. rx in disc %d. rx out %d. rx out disc %d\n"),
   2417              rlink_rx_in, rlink_rx_in_disc,
   2418              rlink_rx_out, rlink_rx_out_disc));
   2419     LOG_CLI((BSL_META("  oam event in %d. oam event in disc %d. oam event out %d. "
   2420                       "oam event out disc %d\n"),
   2421              rlink_oam_in, rlink_oam_in_disc,
   2422              rlink_oam_out, rlink_oam_out_disc));
   2423     LOG_CLI((BSL_META("  bfd event in %d. bfd event in disc %d. bfd event out %d. "
   2424                       "bfd event out disc %d\n"),
   2425              rlink_bfd_in, rlink_bfd_in_disc,
   2426              rlink_bfd_out, rlink_bfd_out_disc));
   2427     LOG_CLI((BSL_META("  add req %d. del req %d. notify %d\n"),
   2428              rlink_add_req_in, rlink_del_req_in, rlink_notify_in));
   2429     LOG_CLI((BSL_META("  trav req %d.\n"),
   2430              rlink_trav_req_in));
   2431     LOG_CLI((BSL_META("  pkt buffer alloc failure %d. pkt send failure %d\n"),
   2432              rlink_buff_alloc_fail, rlink_pkt_send_fail));
   2433 
   2434     bcm_linkscan_dump(0);
   2435 }
   2436 #endif	/* BROADCOM_DEBUG */
   2437 
   2438 #endif  /* BCM_RPC_SUPPORT */