1*4eaa4710SRishi Srivatsavai /************************************************************************ 2*4eaa4710SRishi Srivatsavai * RSTP library - Rapid Spanning Tree (802.1t, 802.1w) 3*4eaa4710SRishi Srivatsavai * Copyright (C) 2001-2003 Optical Access 4*4eaa4710SRishi Srivatsavai * Author: Alex Rozin 5*4eaa4710SRishi Srivatsavai * 6*4eaa4710SRishi Srivatsavai * This file is part of RSTP library. 7*4eaa4710SRishi Srivatsavai * 8*4eaa4710SRishi Srivatsavai * RSTP library is free software; you can redistribute it and/or modify it 9*4eaa4710SRishi Srivatsavai * under the terms of the GNU Lesser General Public License as published by the 10*4eaa4710SRishi Srivatsavai * Free Software Foundation; version 2.1 11*4eaa4710SRishi Srivatsavai * 12*4eaa4710SRishi Srivatsavai * RSTP library is distributed in the hope that it will be useful, but 13*4eaa4710SRishi Srivatsavai * WITHOUT ANY WARRANTY; without even the implied warranty of 14*4eaa4710SRishi Srivatsavai * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 15*4eaa4710SRishi Srivatsavai * General Public License for more details. 16*4eaa4710SRishi Srivatsavai * 17*4eaa4710SRishi Srivatsavai * You should have received a copy of the GNU Lesser General Public License 18*4eaa4710SRishi Srivatsavai * along with RSTP library; see the file COPYING. If not, write to the Free 19*4eaa4710SRishi Srivatsavai * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 20*4eaa4710SRishi Srivatsavai * 02111-1307, USA. 21*4eaa4710SRishi Srivatsavai **********************************************************************/ 22*4eaa4710SRishi Srivatsavai 23*4eaa4710SRishi Srivatsavai /* STP machine instance : bridge per VLAN: 17.17 */ 24*4eaa4710SRishi Srivatsavai 25*4eaa4710SRishi Srivatsavai #include "base.h" 26*4eaa4710SRishi Srivatsavai #include "stpm.h" 27*4eaa4710SRishi Srivatsavai #include "stp_to.h" /* for STP_OUT_flush_lt */ 28*4eaa4710SRishi Srivatsavai 29*4eaa4710SRishi Srivatsavai static STPM_T *bridges = NULL; 30*4eaa4710SRishi Srivatsavai 31*4eaa4710SRishi Srivatsavai static int 32*4eaa4710SRishi Srivatsavai _stp_stpm_init_machine (STATE_MACH_T* this) 33*4eaa4710SRishi Srivatsavai { 34*4eaa4710SRishi Srivatsavai this->State = BEGIN; 35*4eaa4710SRishi Srivatsavai (*(this->concreteEnterState)) (this); 36*4eaa4710SRishi Srivatsavai return 0; 37*4eaa4710SRishi Srivatsavai } 38*4eaa4710SRishi Srivatsavai 39*4eaa4710SRishi Srivatsavai static int 40*4eaa4710SRishi Srivatsavai _stp_stpm_iterate_machines (STPM_T* this, 41*4eaa4710SRishi Srivatsavai int (*iter_callb) (STATE_MACH_T*), 42*4eaa4710SRishi Srivatsavai Bool exit_on_non_zero_ret) 43*4eaa4710SRishi Srivatsavai { 44*4eaa4710SRishi Srivatsavai register STATE_MACH_T* stater; 45*4eaa4710SRishi Srivatsavai register PORT_T* port; 46*4eaa4710SRishi Srivatsavai int iret, mret = 0; 47*4eaa4710SRishi Srivatsavai 48*4eaa4710SRishi Srivatsavai /* state machines per bridge */ 49*4eaa4710SRishi Srivatsavai for (stater = this->machines; stater; stater = stater->next) { 50*4eaa4710SRishi Srivatsavai iret = (*iter_callb) (stater); 51*4eaa4710SRishi Srivatsavai if (exit_on_non_zero_ret && iret) 52*4eaa4710SRishi Srivatsavai return iret; 53*4eaa4710SRishi Srivatsavai else 54*4eaa4710SRishi Srivatsavai mret += iret; 55*4eaa4710SRishi Srivatsavai } 56*4eaa4710SRishi Srivatsavai 57*4eaa4710SRishi Srivatsavai /* state machines per port */ 58*4eaa4710SRishi Srivatsavai for (port = this->ports; port; port = port->next) { 59*4eaa4710SRishi Srivatsavai for (stater = port->machines; stater; stater = stater->next) { 60*4eaa4710SRishi Srivatsavai iret = (*iter_callb) (stater); 61*4eaa4710SRishi Srivatsavai if (exit_on_non_zero_ret && iret) 62*4eaa4710SRishi Srivatsavai return iret; 63*4eaa4710SRishi Srivatsavai else 64*4eaa4710SRishi Srivatsavai mret += iret; 65*4eaa4710SRishi Srivatsavai } 66*4eaa4710SRishi Srivatsavai } 67*4eaa4710SRishi Srivatsavai 68*4eaa4710SRishi Srivatsavai return mret; 69*4eaa4710SRishi Srivatsavai } 70*4eaa4710SRishi Srivatsavai 71*4eaa4710SRishi Srivatsavai void 72*4eaa4710SRishi Srivatsavai _stp_stpm_init_data (STPM_T* this) 73*4eaa4710SRishi Srivatsavai { 74*4eaa4710SRishi Srivatsavai STP_VECT_create (&this->rootPrio, 75*4eaa4710SRishi Srivatsavai &this->BrId, 76*4eaa4710SRishi Srivatsavai 0, 77*4eaa4710SRishi Srivatsavai &this->BrId, 78*4eaa4710SRishi Srivatsavai 0, 0); 79*4eaa4710SRishi Srivatsavai 80*4eaa4710SRishi Srivatsavai this->BrTimes.MessageAge = 0; 81*4eaa4710SRishi Srivatsavai 82*4eaa4710SRishi Srivatsavai STP_copy_times (&this->rootTimes, &this->BrTimes); 83*4eaa4710SRishi Srivatsavai } 84*4eaa4710SRishi Srivatsavai 85*4eaa4710SRishi Srivatsavai static unsigned char 86*4eaa4710SRishi Srivatsavai _check_topoch (STPM_T* this) 87*4eaa4710SRishi Srivatsavai { 88*4eaa4710SRishi Srivatsavai register PORT_T* port; 89*4eaa4710SRishi Srivatsavai 90*4eaa4710SRishi Srivatsavai for (port = this->ports; port; port = port->next) { 91*4eaa4710SRishi Srivatsavai if (port->tcWhile) { 92*4eaa4710SRishi Srivatsavai return 1; 93*4eaa4710SRishi Srivatsavai } 94*4eaa4710SRishi Srivatsavai } 95*4eaa4710SRishi Srivatsavai return 0; 96*4eaa4710SRishi Srivatsavai } 97*4eaa4710SRishi Srivatsavai 98*4eaa4710SRishi Srivatsavai void 99*4eaa4710SRishi Srivatsavai STP_stpm_one_second (STPM_T* param) 100*4eaa4710SRishi Srivatsavai { 101*4eaa4710SRishi Srivatsavai STPM_T* this = (STPM_T*) param; 102*4eaa4710SRishi Srivatsavai register PORT_T* port; 103*4eaa4710SRishi Srivatsavai register int iii; 104*4eaa4710SRishi Srivatsavai 105*4eaa4710SRishi Srivatsavai if (STP_ENABLED != this->admin_state) return; 106*4eaa4710SRishi Srivatsavai 107*4eaa4710SRishi Srivatsavai for (port = this->ports; port; port = port->next) { 108*4eaa4710SRishi Srivatsavai for (iii = 0; iii < TIMERS_NUMBER; iii++) { 109*4eaa4710SRishi Srivatsavai if (*(port->timers[iii]) > 0) { 110*4eaa4710SRishi Srivatsavai (*port->timers[iii])--; 111*4eaa4710SRishi Srivatsavai } 112*4eaa4710SRishi Srivatsavai } 113*4eaa4710SRishi Srivatsavai port->uptime++; 114*4eaa4710SRishi Srivatsavai } 115*4eaa4710SRishi Srivatsavai 116*4eaa4710SRishi Srivatsavai (void) STP_stpm_update (this); 117*4eaa4710SRishi Srivatsavai this->Topo_Change = _check_topoch (this); 118*4eaa4710SRishi Srivatsavai if (this->Topo_Change) { 119*4eaa4710SRishi Srivatsavai this->Topo_Change_Count++; 120*4eaa4710SRishi Srivatsavai this->timeSince_Topo_Change = 0; 121*4eaa4710SRishi Srivatsavai } else { 122*4eaa4710SRishi Srivatsavai this->Topo_Change_Count = 0; 123*4eaa4710SRishi Srivatsavai this->timeSince_Topo_Change++; 124*4eaa4710SRishi Srivatsavai } 125*4eaa4710SRishi Srivatsavai } 126*4eaa4710SRishi Srivatsavai 127*4eaa4710SRishi Srivatsavai STPM_T* 128*4eaa4710SRishi Srivatsavai STP_stpm_create (int vlan_id, char* name) 129*4eaa4710SRishi Srivatsavai { 130*4eaa4710SRishi Srivatsavai STPM_T* this; 131*4eaa4710SRishi Srivatsavai 132*4eaa4710SRishi Srivatsavai STP_NEW_IN_LIST(this, STPM_T, bridges, "stp instance"); 133*4eaa4710SRishi Srivatsavai 134*4eaa4710SRishi Srivatsavai this->admin_state = STP_DISABLED; 135*4eaa4710SRishi Srivatsavai 136*4eaa4710SRishi Srivatsavai this->vlan_id = vlan_id; 137*4eaa4710SRishi Srivatsavai if (name) { 138*4eaa4710SRishi Srivatsavai STP_STRDUP(this->name, name, "stp bridge name"); 139*4eaa4710SRishi Srivatsavai } 140*4eaa4710SRishi Srivatsavai 141*4eaa4710SRishi Srivatsavai this->machines = NULL; 142*4eaa4710SRishi Srivatsavai this->ports = NULL; 143*4eaa4710SRishi Srivatsavai 144*4eaa4710SRishi Srivatsavai STP_STATE_MACH_IN_LIST(rolesel); 145*4eaa4710SRishi Srivatsavai 146*4eaa4710SRishi Srivatsavai #ifdef STP_DBG 147*4eaa4710SRishi Srivatsavai /* this->rolesel->debug = 2; */ 148*4eaa4710SRishi Srivatsavai #endif 149*4eaa4710SRishi Srivatsavai 150*4eaa4710SRishi Srivatsavai return this; 151*4eaa4710SRishi Srivatsavai } 152*4eaa4710SRishi Srivatsavai 153*4eaa4710SRishi Srivatsavai int 154*4eaa4710SRishi Srivatsavai STP_stpm_enable (STPM_T* this, UID_STP_MODE_T admin_state) 155*4eaa4710SRishi Srivatsavai { 156*4eaa4710SRishi Srivatsavai int rc = 0; 157*4eaa4710SRishi Srivatsavai 158*4eaa4710SRishi Srivatsavai if (admin_state == this->admin_state) { 159*4eaa4710SRishi Srivatsavai /* nothing to do :) */ 160*4eaa4710SRishi Srivatsavai return 0; 161*4eaa4710SRishi Srivatsavai } 162*4eaa4710SRishi Srivatsavai 163*4eaa4710SRishi Srivatsavai if (STP_ENABLED == admin_state) { 164*4eaa4710SRishi Srivatsavai if (this->ports) 165*4eaa4710SRishi Srivatsavai rc = STP_stpm_start (this); 166*4eaa4710SRishi Srivatsavai this->admin_state = admin_state; 167*4eaa4710SRishi Srivatsavai } else { 168*4eaa4710SRishi Srivatsavai this->admin_state = admin_state; 169*4eaa4710SRishi Srivatsavai STP_stpm_stop (this); 170*4eaa4710SRishi Srivatsavai } 171*4eaa4710SRishi Srivatsavai 172*4eaa4710SRishi Srivatsavai return rc; 173*4eaa4710SRishi Srivatsavai } 174*4eaa4710SRishi Srivatsavai 175*4eaa4710SRishi Srivatsavai void 176*4eaa4710SRishi Srivatsavai STP_stpm_delete (STPM_T* this) 177*4eaa4710SRishi Srivatsavai { 178*4eaa4710SRishi Srivatsavai register STPM_T* tmp; 179*4eaa4710SRishi Srivatsavai register STPM_T* prev; 180*4eaa4710SRishi Srivatsavai register STATE_MACH_T* stater; 181*4eaa4710SRishi Srivatsavai register PORT_T* port; 182*4eaa4710SRishi Srivatsavai register void* pv; 183*4eaa4710SRishi Srivatsavai 184*4eaa4710SRishi Srivatsavai (void) STP_stpm_enable (this, STP_DISABLED); 185*4eaa4710SRishi Srivatsavai 186*4eaa4710SRishi Srivatsavai for (stater = this->machines; stater; ) { 187*4eaa4710SRishi Srivatsavai pv = (void*) stater->next; 188*4eaa4710SRishi Srivatsavai STP_state_mach_delete (stater); 189*4eaa4710SRishi Srivatsavai this->machines = stater = (STATE_MACH_T*) pv; 190*4eaa4710SRishi Srivatsavai } 191*4eaa4710SRishi Srivatsavai 192*4eaa4710SRishi Srivatsavai for (port = this->ports; port; ) { 193*4eaa4710SRishi Srivatsavai pv = (void*) port->next; 194*4eaa4710SRishi Srivatsavai STP_port_delete (port); 195*4eaa4710SRishi Srivatsavai this->ports = port = (PORT_T*) pv; 196*4eaa4710SRishi Srivatsavai } 197*4eaa4710SRishi Srivatsavai 198*4eaa4710SRishi Srivatsavai prev = NULL; 199*4eaa4710SRishi Srivatsavai for (tmp = bridges; tmp; tmp = tmp->next) { 200*4eaa4710SRishi Srivatsavai if (tmp->vlan_id == this->vlan_id) { 201*4eaa4710SRishi Srivatsavai if (prev) { 202*4eaa4710SRishi Srivatsavai prev->next = this->next; 203*4eaa4710SRishi Srivatsavai } else { 204*4eaa4710SRishi Srivatsavai bridges = this->next; 205*4eaa4710SRishi Srivatsavai } 206*4eaa4710SRishi Srivatsavai 207*4eaa4710SRishi Srivatsavai if (this->name) 208*4eaa4710SRishi Srivatsavai STP_FREE(this->name, "stp bridge name"); 209*4eaa4710SRishi Srivatsavai STP_FREE(this, "stp instance"); 210*4eaa4710SRishi Srivatsavai break; 211*4eaa4710SRishi Srivatsavai } 212*4eaa4710SRishi Srivatsavai prev = tmp; 213*4eaa4710SRishi Srivatsavai } 214*4eaa4710SRishi Srivatsavai } 215*4eaa4710SRishi Srivatsavai 216*4eaa4710SRishi Srivatsavai int 217*4eaa4710SRishi Srivatsavai STP_stpm_start (STPM_T* this) 218*4eaa4710SRishi Srivatsavai { 219*4eaa4710SRishi Srivatsavai register PORT_T* port; 220*4eaa4710SRishi Srivatsavai 221*4eaa4710SRishi Srivatsavai if (! this->ports) { /* there are not any ports :( */ 222*4eaa4710SRishi Srivatsavai return STP_There_Are_No_Ports; 223*4eaa4710SRishi Srivatsavai } 224*4eaa4710SRishi Srivatsavai 225*4eaa4710SRishi Srivatsavai if (! STP_compute_bridge_id (this)) {/* can't compute bridge id ? :( */ 226*4eaa4710SRishi Srivatsavai return STP_Cannot_Compute_Bridge_Prio; 227*4eaa4710SRishi Srivatsavai } 228*4eaa4710SRishi Srivatsavai 229*4eaa4710SRishi Srivatsavai /* check, that the stpm has unique bridge Id */ 230*4eaa4710SRishi Srivatsavai if (0 != STP_stpm_check_bridge_priority (this)) { 231*4eaa4710SRishi Srivatsavai /* there is an enabled bridge with same ID :( */ 232*4eaa4710SRishi Srivatsavai return STP_Invalid_Bridge_Priority; 233*4eaa4710SRishi Srivatsavai } 234*4eaa4710SRishi Srivatsavai 235*4eaa4710SRishi Srivatsavai _stp_stpm_init_data (this); 236*4eaa4710SRishi Srivatsavai 237*4eaa4710SRishi Srivatsavai for (port = this->ports; port; port = port->next) { 238*4eaa4710SRishi Srivatsavai STP_port_init (port, this, True); 239*4eaa4710SRishi Srivatsavai } 240*4eaa4710SRishi Srivatsavai 241*4eaa4710SRishi Srivatsavai #ifndef STRONGLY_SPEC_802_1W 242*4eaa4710SRishi Srivatsavai /* A. see comment near STRONGLY_SPEC_802_1W in topoch.c */ 243*4eaa4710SRishi Srivatsavai /* B. port=0 here means: delete for all ports */ 244*4eaa4710SRishi Srivatsavai #ifdef STP_DBG 245*4eaa4710SRishi Srivatsavai stp_trace("%s (all, start stpm)", 246*4eaa4710SRishi Srivatsavai "clearFDB"); 247*4eaa4710SRishi Srivatsavai #endif 248*4eaa4710SRishi Srivatsavai 249*4eaa4710SRishi Srivatsavai STP_OUT_flush_lt (0, this->vlan_id, LT_FLASH_ONLY_THE_PORT, "start stpm"); 250*4eaa4710SRishi Srivatsavai #endif 251*4eaa4710SRishi Srivatsavai 252*4eaa4710SRishi Srivatsavai (void) _stp_stpm_iterate_machines (this, _stp_stpm_init_machine, False); 253*4eaa4710SRishi Srivatsavai (void) STP_stpm_update (this); 254*4eaa4710SRishi Srivatsavai 255*4eaa4710SRishi Srivatsavai return 0; 256*4eaa4710SRishi Srivatsavai } 257*4eaa4710SRishi Srivatsavai 258*4eaa4710SRishi Srivatsavai /* ARGSUSED */ 259*4eaa4710SRishi Srivatsavai void 260*4eaa4710SRishi Srivatsavai STP_stpm_stop (STPM_T* this) 261*4eaa4710SRishi Srivatsavai { 262*4eaa4710SRishi Srivatsavai } 263*4eaa4710SRishi Srivatsavai 264*4eaa4710SRishi Srivatsavai int 265*4eaa4710SRishi Srivatsavai STP_stpm_update (STPM_T* this) /* returns number of loops */ 266*4eaa4710SRishi Srivatsavai { 267*4eaa4710SRishi Srivatsavai register Bool need_state_change; 268*4eaa4710SRishi Srivatsavai register int number_of_loops = 0; 269*4eaa4710SRishi Srivatsavai 270*4eaa4710SRishi Srivatsavai need_state_change = False; 271*4eaa4710SRishi Srivatsavai 272*4eaa4710SRishi Srivatsavai for (;;) {/* loop until not need changes */ 273*4eaa4710SRishi Srivatsavai need_state_change = _stp_stpm_iterate_machines (this, 274*4eaa4710SRishi Srivatsavai STP_check_condition, 275*4eaa4710SRishi Srivatsavai True); 276*4eaa4710SRishi Srivatsavai if (! need_state_change) break; 277*4eaa4710SRishi Srivatsavai 278*4eaa4710SRishi Srivatsavai number_of_loops++; 279*4eaa4710SRishi Srivatsavai /* here we know, that at least one stater must be 280*4eaa4710SRishi Srivatsavai updated (it has changed state) */ 281*4eaa4710SRishi Srivatsavai number_of_loops += _stp_stpm_iterate_machines (this, 282*4eaa4710SRishi Srivatsavai STP_change_state, 283*4eaa4710SRishi Srivatsavai False); 284*4eaa4710SRishi Srivatsavai 285*4eaa4710SRishi Srivatsavai } 286*4eaa4710SRishi Srivatsavai 287*4eaa4710SRishi Srivatsavai return number_of_loops; 288*4eaa4710SRishi Srivatsavai } 289*4eaa4710SRishi Srivatsavai 290*4eaa4710SRishi Srivatsavai BRIDGE_ID * 291*4eaa4710SRishi Srivatsavai STP_compute_bridge_id (STPM_T* this) 292*4eaa4710SRishi Srivatsavai { 293*4eaa4710SRishi Srivatsavai register PORT_T* port; 294*4eaa4710SRishi Srivatsavai register PORT_T* min_num_port = NULL; 295*4eaa4710SRishi Srivatsavai int port_index = 0; 296*4eaa4710SRishi Srivatsavai 297*4eaa4710SRishi Srivatsavai for (port = this->ports; port; port = port->next) { 298*4eaa4710SRishi Srivatsavai if (! port_index || port->port_index < port_index) { 299*4eaa4710SRishi Srivatsavai min_num_port = port; 300*4eaa4710SRishi Srivatsavai port_index = port->port_index; 301*4eaa4710SRishi Srivatsavai } 302*4eaa4710SRishi Srivatsavai } 303*4eaa4710SRishi Srivatsavai 304*4eaa4710SRishi Srivatsavai if (! min_num_port) return NULL; /* IMHO, it may not be */ 305*4eaa4710SRishi Srivatsavai 306*4eaa4710SRishi Srivatsavai STP_OUT_get_port_mac (min_num_port->port_index, this->BrId.addr); 307*4eaa4710SRishi Srivatsavai 308*4eaa4710SRishi Srivatsavai return &this->BrId; 309*4eaa4710SRishi Srivatsavai } 310*4eaa4710SRishi Srivatsavai 311*4eaa4710SRishi Srivatsavai STPM_T* 312*4eaa4710SRishi Srivatsavai STP_stpm_get_the_list (void) 313*4eaa4710SRishi Srivatsavai { 314*4eaa4710SRishi Srivatsavai return bridges; 315*4eaa4710SRishi Srivatsavai } 316*4eaa4710SRishi Srivatsavai 317*4eaa4710SRishi Srivatsavai void 318*4eaa4710SRishi Srivatsavai STP_stpm_update_after_bridge_management (STPM_T* this) 319*4eaa4710SRishi Srivatsavai { 320*4eaa4710SRishi Srivatsavai register PORT_T* port; 321*4eaa4710SRishi Srivatsavai 322*4eaa4710SRishi Srivatsavai for (port = this->ports; port; port = port->next) { 323*4eaa4710SRishi Srivatsavai port->reselect = True; 324*4eaa4710SRishi Srivatsavai port->selected = False; 325*4eaa4710SRishi Srivatsavai } 326*4eaa4710SRishi Srivatsavai } 327*4eaa4710SRishi Srivatsavai 328*4eaa4710SRishi Srivatsavai int 329*4eaa4710SRishi Srivatsavai STP_stpm_check_bridge_priority (STPM_T* this) 330*4eaa4710SRishi Srivatsavai { 331*4eaa4710SRishi Srivatsavai register STPM_T* oth; 332*4eaa4710SRishi Srivatsavai 333*4eaa4710SRishi Srivatsavai for (oth = bridges; oth; oth = oth->next) { 334*4eaa4710SRishi Srivatsavai if (STP_ENABLED == oth->admin_state && oth != this && 335*4eaa4710SRishi Srivatsavai ! STP_VECT_compare_bridge_id (&this->BrId, &oth->BrId)) { 336*4eaa4710SRishi Srivatsavai return STP_Invalid_Bridge_Priority; 337*4eaa4710SRishi Srivatsavai } 338*4eaa4710SRishi Srivatsavai } 339*4eaa4710SRishi Srivatsavai 340*4eaa4710SRishi Srivatsavai return 0; 341*4eaa4710SRishi Srivatsavai } 342*4eaa4710SRishi Srivatsavai 343*4eaa4710SRishi Srivatsavai const char* 344*4eaa4710SRishi Srivatsavai STP_stpm_get_port_name_by_id (STPM_T* this, PORT_ID port_id) 345*4eaa4710SRishi Srivatsavai { 346*4eaa4710SRishi Srivatsavai register PORT_T* port; 347*4eaa4710SRishi Srivatsavai 348*4eaa4710SRishi Srivatsavai for (port = this->ports; port; port = port->next) { 349*4eaa4710SRishi Srivatsavai if (port_id == port->port_id) { 350*4eaa4710SRishi Srivatsavai return port->port_name; 351*4eaa4710SRishi Srivatsavai } 352*4eaa4710SRishi Srivatsavai } 353*4eaa4710SRishi Srivatsavai 354*4eaa4710SRishi Srivatsavai return "Undef?"; 355*4eaa4710SRishi Srivatsavai } 356*4eaa4710SRishi Srivatsavai 357*4eaa4710SRishi Srivatsavai 358*4eaa4710SRishi Srivatsavai 359*4eaa4710SRishi Srivatsavai 360*4eaa4710SRishi Srivatsavai 361