linux/drivers/net/skfp/rmt.c
<<
>>
Prefs
   1/******************************************************************************
   2 *
   3 *      (C)Copyright 1998,1999 SysKonnect,
   4 *      a business unit of Schneider & Koch & Co. Datensysteme GmbH.
   5 *
   6 *      See the file "skfddi.c" for further information.
   7 *
   8 *      This program is free software; you can redistribute it and/or modify
   9 *      it under the terms of the GNU General Public License as published by
  10 *      the Free Software Foundation; either version 2 of the License, or
  11 *      (at your option) any later version.
  12 *
  13 *      The information in this file is provided "AS IS" without warranty.
  14 *
  15 ******************************************************************************/
  16
  17/*
  18        SMT RMT
  19        Ring Management
  20*/
  21
  22/*
  23 * Hardware independent state machine implemantation
  24 * The following external SMT functions are referenced :
  25 *
  26 *              queue_event()
  27 *              smt_timer_start()
  28 *              smt_timer_stop()
  29 *
  30 *      The following external HW dependent functions are referenced :
  31 *              sm_ma_control()
  32 *              sm_mac_check_beacon_claim()
  33 *
  34 *      The following HW dependent events are required :
  35 *              RM_RING_OP
  36 *              RM_RING_NON_OP
  37 *              RM_MY_BEACON
  38 *              RM_OTHER_BEACON
  39 *              RM_MY_CLAIM
  40 *              RM_TRT_EXP
  41 *              RM_VALID_CLAIM
  42 *
  43 */
  44
  45#include "h/types.h"
  46#include "h/fddi.h"
  47#include "h/smc.h"
  48
  49#define KERNEL
  50#include "h/smtstate.h"
  51
  52#ifndef lint
  53static const char ID_sccs[] = "@(#)rmt.c        2.13 99/07/02 (C) SK " ;
  54#endif
  55
  56/*
  57 * FSM Macros
  58 */
  59#define AFLAG   0x10
  60#define GO_STATE(x)     (smc->mib.m[MAC0].fddiMACRMTState = (x)|AFLAG)
  61#define ACTIONS_DONE()  (smc->mib.m[MAC0].fddiMACRMTState &= ~AFLAG)
  62#define ACTIONS(x)      (x|AFLAG)
  63
  64#define RM0_ISOLATED    0
  65#define RM1_NON_OP      1               /* not operational */
  66#define RM2_RING_OP     2               /* ring operational */
  67#define RM3_DETECT      3               /* detect dupl addresses */
  68#define RM4_NON_OP_DUP  4               /* dupl. addr detected */
  69#define RM5_RING_OP_DUP 5               /* ring oper. with dupl. addr */
  70#define RM6_DIRECTED    6               /* sending directed beacons */
  71#define RM7_TRACE       7               /* trace initiated */
  72
  73#ifdef  DEBUG
  74/*
  75 * symbolic state names
  76 */
  77static const char * const rmt_states[] = {
  78        "RM0_ISOLATED","RM1_NON_OP","RM2_RING_OP","RM3_DETECT",
  79        "RM4_NON_OP_DUP","RM5_RING_OP_DUP","RM6_DIRECTED",
  80        "RM7_TRACE"
  81} ;
  82
  83/*
  84 * symbolic event names
  85 */
  86static const char * const rmt_events[] = {
  87        "NONE","RM_RING_OP","RM_RING_NON_OP","RM_MY_BEACON",
  88        "RM_OTHER_BEACON","RM_MY_CLAIM","RM_TRT_EXP","RM_VALID_CLAIM",
  89        "RM_JOIN","RM_LOOP","RM_DUP_ADDR","RM_ENABLE_FLAG",
  90        "RM_TIMEOUT_NON_OP","RM_TIMEOUT_T_STUCK",
  91        "RM_TIMEOUT_ANNOUNCE","RM_TIMEOUT_T_DIRECT",
  92        "RM_TIMEOUT_D_MAX","RM_TIMEOUT_POLL","RM_TX_STATE_CHANGE"
  93} ;
  94#endif
  95
  96/*
  97 * Globals
  98 * in struct s_rmt
  99 */
 100
 101
 102/*
 103 * function declarations
 104 */
 105static void rmt_fsm(struct s_smc *smc, int cmd);
 106static void start_rmt_timer0(struct s_smc *smc, u_long value, int event);
 107static void start_rmt_timer1(struct s_smc *smc, u_long value, int event);
 108static void start_rmt_timer2(struct s_smc *smc, u_long value, int event);
 109static void stop_rmt_timer0(struct s_smc *smc);
 110static void stop_rmt_timer1(struct s_smc *smc);
 111static void stop_rmt_timer2(struct s_smc *smc);
 112static void rmt_dup_actions(struct s_smc *smc);
 113static void rmt_reinsert_actions(struct s_smc *smc);
 114static void rmt_leave_actions(struct s_smc *smc);
 115static void rmt_new_dup_actions(struct s_smc *smc);
 116
 117#ifndef SUPERNET_3
 118extern void restart_trt_for_dbcn() ;
 119#endif /*SUPERNET_3*/
 120
 121/*
 122        init RMT state machine
 123        clear all RMT vars and flags
 124*/
 125void rmt_init(struct s_smc *smc)
 126{
 127        smc->mib.m[MAC0].fddiMACRMTState = ACTIONS(RM0_ISOLATED) ;
 128        smc->r.dup_addr_test = DA_NONE ;
 129        smc->r.da_flag = 0 ;
 130        smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ;
 131        smc->r.sm_ma_avail = FALSE ;
 132        smc->r.loop_avail = 0 ;
 133        smc->r.bn_flag = 0 ;
 134        smc->r.jm_flag = 0 ;
 135        smc->r.no_flag = TRUE ;
 136}
 137
 138/*
 139        RMT state machine
 140        called by dispatcher
 141
 142        do
 143                display state change
 144                process event
 145        until SM is stable
 146*/
 147void rmt(struct s_smc *smc, int event)
 148{
 149        int     state ;
 150
 151        do {
 152                DB_RMT("RMT : state %s%s",
 153                        (smc->mib.m[MAC0].fddiMACRMTState & AFLAG) ? "ACTIONS " : "",
 154                        rmt_states[smc->mib.m[MAC0].fddiMACRMTState & ~AFLAG]) ;
 155                DB_RMT(" event %s\n",rmt_events[event],0) ;
 156                state = smc->mib.m[MAC0].fddiMACRMTState ;
 157                rmt_fsm(smc,event) ;
 158                event = 0 ;
 159        } while (state != smc->mib.m[MAC0].fddiMACRMTState) ;
 160        rmt_state_change(smc,(int)smc->mib.m[MAC0].fddiMACRMTState) ;
 161}
 162
 163/*
 164        process RMT event
 165*/
 166static void rmt_fsm(struct s_smc *smc, int cmd)
 167{
 168        /*
 169         * RM00-RM70 : from all states
 170         */
 171        if (!smc->r.rm_join && !smc->r.rm_loop &&
 172                smc->mib.m[MAC0].fddiMACRMTState != ACTIONS(RM0_ISOLATED) &&
 173                smc->mib.m[MAC0].fddiMACRMTState != RM0_ISOLATED) {
 174                RS_SET(smc,RS_NORINGOP) ;
 175                rmt_indication(smc,0) ;
 176                GO_STATE(RM0_ISOLATED) ;
 177                return ;
 178        }
 179
 180        switch(smc->mib.m[MAC0].fddiMACRMTState) {
 181        case ACTIONS(RM0_ISOLATED) :
 182                stop_rmt_timer0(smc) ;
 183                stop_rmt_timer1(smc) ;
 184                stop_rmt_timer2(smc) ;
 185
 186                /*
 187                 * Disable MAC.
 188                 */
 189                sm_ma_control(smc,MA_OFFLINE) ;
 190                smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ;
 191                smc->r.loop_avail = FALSE ;
 192                smc->r.sm_ma_avail = FALSE ;
 193                smc->r.no_flag = TRUE ;
 194                DB_RMTN(1,"RMT : ISOLATED\n",0,0) ;
 195                ACTIONS_DONE() ;
 196                break ;
 197        case RM0_ISOLATED :
 198                /*RM01*/
 199                if (smc->r.rm_join || smc->r.rm_loop) {
 200                        /*
 201                         * According to the standard the MAC must be reset
 202                         * here. The FORMAC will be initialized and Claim
 203                         * and Beacon Frames will be uploaded to the MAC.
 204                         * So any change of Treq will take effect NOW.
 205                         */
 206                        sm_ma_control(smc,MA_RESET) ;
 207                        GO_STATE(RM1_NON_OP) ;
 208                        break ;
 209                }
 210                break ;
 211        case ACTIONS(RM1_NON_OP) :
 212                start_rmt_timer0(smc,smc->s.rmt_t_non_op,RM_TIMEOUT_NON_OP) ;
 213                stop_rmt_timer1(smc) ;
 214                stop_rmt_timer2(smc) ;
 215                sm_ma_control(smc,MA_BEACON) ;
 216                DB_RMTN(1,"RMT : RING DOWN\n",0,0) ;
 217                RS_SET(smc,RS_NORINGOP) ;
 218                smc->r.sm_ma_avail = FALSE ;
 219                rmt_indication(smc,0) ;
 220                ACTIONS_DONE() ;
 221                break ;
 222        case RM1_NON_OP :
 223                /*RM12*/
 224                if (cmd == RM_RING_OP) {
 225                        RS_SET(smc,RS_RINGOPCHANGE) ;
 226                        GO_STATE(RM2_RING_OP) ;
 227                        break ;
 228                }
 229                /*RM13*/
 230                else if (cmd == RM_TIMEOUT_NON_OP) {
 231                        smc->r.bn_flag = FALSE ;
 232                        smc->r.no_flag = TRUE ;
 233                        GO_STATE(RM3_DETECT) ;
 234                        break ;
 235                }
 236                break ;
 237        case ACTIONS(RM2_RING_OP) :
 238                stop_rmt_timer0(smc) ;
 239                stop_rmt_timer1(smc) ;
 240                stop_rmt_timer2(smc) ;
 241                smc->r.no_flag = FALSE ;
 242                if (smc->r.rm_loop)
 243                        smc->r.loop_avail = TRUE ;
 244                if (smc->r.rm_join) {
 245                        smc->r.sm_ma_avail = TRUE ;
 246                        if (smc->mib.m[MAC0].fddiMACMA_UnitdataEnable)
 247                        smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = TRUE ;
 248                                else
 249                        smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ;
 250                }
 251                DB_RMTN(1,"RMT : RING UP\n",0,0) ;
 252                RS_CLEAR(smc,RS_NORINGOP) ;
 253                RS_SET(smc,RS_RINGOPCHANGE) ;
 254                rmt_indication(smc,1) ;
 255                smt_stat_counter(smc,0) ;
 256                ACTIONS_DONE() ;
 257                break ;
 258        case RM2_RING_OP :
 259                /*RM21*/
 260                if (cmd == RM_RING_NON_OP) {
 261                        smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ;
 262                        smc->r.loop_avail = FALSE ;
 263                        RS_SET(smc,RS_RINGOPCHANGE) ;
 264                        GO_STATE(RM1_NON_OP) ;
 265                        break ;
 266                }
 267                /*RM22a*/
 268                else if (cmd == RM_ENABLE_FLAG) {
 269                        if (smc->mib.m[MAC0].fddiMACMA_UnitdataEnable)
 270                        smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = TRUE ;
 271                                else
 272                        smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ;
 273                }
 274                /*RM25*/
 275                else if (smc->r.dup_addr_test == DA_FAILED) {
 276                        smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ;
 277                        smc->r.loop_avail = FALSE ;
 278                        smc->r.da_flag = TRUE ;
 279                        GO_STATE(RM5_RING_OP_DUP) ;
 280                        break ;
 281                }
 282                break ;
 283        case ACTIONS(RM3_DETECT) :
 284                start_rmt_timer0(smc,smc->s.mac_d_max*2,RM_TIMEOUT_D_MAX) ;
 285                start_rmt_timer1(smc,smc->s.rmt_t_stuck,RM_TIMEOUT_T_STUCK) ;
 286                start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL) ;
 287                sm_mac_check_beacon_claim(smc) ;
 288                DB_RMTN(1,"RMT : RM3_DETECT\n",0,0) ;
 289                ACTIONS_DONE() ;
 290                break ;
 291        case RM3_DETECT :
 292                if (cmd == RM_TIMEOUT_POLL) {
 293                        start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL);
 294                        sm_mac_check_beacon_claim(smc) ;
 295                        break ;
 296                }
 297                if (cmd == RM_TIMEOUT_D_MAX) {
 298                        smc->r.timer0_exp = TRUE ;
 299                }
 300                /*
 301                 *jd(22-Feb-1999)
 302                 * We need a time ">= 2*mac_d_max" since we had finished
 303                 * Claim or Beacon state. So we will restart timer0 at
 304                 * every state change.
 305                 */
 306                if (cmd == RM_TX_STATE_CHANGE) {
 307                        start_rmt_timer0(smc,
 308                                         smc->s.mac_d_max*2,
 309                                         RM_TIMEOUT_D_MAX) ;
 310                }
 311                /*RM32*/
 312                if (cmd == RM_RING_OP) {
 313                        GO_STATE(RM2_RING_OP) ;
 314                        break ;
 315                }
 316                /*RM33a*/
 317                else if ((cmd == RM_MY_BEACON || cmd == RM_OTHER_BEACON)
 318                        && smc->r.bn_flag) {
 319                        smc->r.bn_flag = FALSE ;
 320                }
 321                /*RM33b*/
 322                else if (cmd == RM_TRT_EXP && !smc->r.bn_flag) {
 323                        int     tx ;
 324                        /*
 325                         * set bn_flag only if in state T4 or T5:
 326                         * only if we're the beaconer should we start the
 327                         * trace !
 328                         */
 329                        if ((tx =  sm_mac_get_tx_state(smc)) == 4 || tx == 5) {
 330                        DB_RMTN(2,"RMT : DETECT && TRT_EXPIRED && T4/T5\n",0,0);
 331                                smc->r.bn_flag = TRUE ;
 332                                /*
 333                                 * If one of the upstream stations beaconed
 334                                 * and the link to the upstream neighbor is
 335                                 * lost we need to restart the stuck timer to
 336                                 * check the "stuck beacon" condition.
 337                                 */
 338                                start_rmt_timer1(smc,smc->s.rmt_t_stuck,
 339                                        RM_TIMEOUT_T_STUCK) ;
 340                        }
 341                        /*
 342                         * We do NOT need to clear smc->r.bn_flag in case of
 343                         * not being in state T4 or T5, because the flag
 344                         * must be cleared in order to get in this condition.
 345                         */
 346
 347                        DB_RMTN(2,
 348                        "RMT : sm_mac_get_tx_state() = %d (bn_flag = %d)\n",
 349                        tx,smc->r.bn_flag) ;
 350                }
 351                /*RM34a*/
 352                else if (cmd == RM_MY_CLAIM && smc->r.timer0_exp) {
 353                        rmt_new_dup_actions(smc) ;
 354                        GO_STATE(RM4_NON_OP_DUP) ;
 355                        break ;
 356                }
 357                /*RM34b*/
 358                else if (cmd == RM_MY_BEACON && smc->r.timer0_exp) {
 359                        rmt_new_dup_actions(smc) ;
 360                        GO_STATE(RM4_NON_OP_DUP) ;
 361                        break ;
 362                }
 363                /*RM34c*/
 364                else if (cmd == RM_VALID_CLAIM) {
 365                        rmt_new_dup_actions(smc) ;
 366                        GO_STATE(RM4_NON_OP_DUP) ;
 367                        break ;
 368                }
 369                /*RM36*/
 370                else if (cmd == RM_TIMEOUT_T_STUCK &&
 371                        smc->r.rm_join && smc->r.bn_flag) {
 372                        GO_STATE(RM6_DIRECTED) ;
 373                        break ;
 374                }
 375                break ;
 376        case ACTIONS(RM4_NON_OP_DUP) :
 377                start_rmt_timer0(smc,smc->s.rmt_t_announce,RM_TIMEOUT_ANNOUNCE);
 378                start_rmt_timer1(smc,smc->s.rmt_t_stuck,RM_TIMEOUT_T_STUCK) ;
 379                start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL) ;
 380                sm_mac_check_beacon_claim(smc) ;
 381                DB_RMTN(1,"RMT : RM4_NON_OP_DUP\n",0,0) ;
 382                ACTIONS_DONE() ;
 383                break ;
 384        case RM4_NON_OP_DUP :
 385                if (cmd == RM_TIMEOUT_POLL) {
 386                        start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL);
 387                        sm_mac_check_beacon_claim(smc) ;
 388                        break ;
 389                }
 390                /*RM41*/
 391                if (!smc->r.da_flag) {
 392                        GO_STATE(RM1_NON_OP) ;
 393                        break ;
 394                }
 395                /*RM44a*/
 396                else if ((cmd == RM_MY_BEACON || cmd == RM_OTHER_BEACON) &&
 397                        smc->r.bn_flag) {
 398                        smc->r.bn_flag = FALSE ;
 399                }
 400                /*RM44b*/
 401                else if (cmd == RM_TRT_EXP && !smc->r.bn_flag) {
 402                        int     tx ;
 403                        /*
 404                         * set bn_flag only if in state T4 or T5:
 405                         * only if we're the beaconer should we start the
 406                         * trace !
 407                         */
 408                        if ((tx =  sm_mac_get_tx_state(smc)) == 4 || tx == 5) {
 409                        DB_RMTN(2,"RMT : NOPDUP && TRT_EXPIRED && T4/T5\n",0,0);
 410                                smc->r.bn_flag = TRUE ;
 411                                /*
 412                                 * If one of the upstream stations beaconed
 413                                 * and the link to the upstream neighbor is
 414                                 * lost we need to restart the stuck timer to
 415                                 * check the "stuck beacon" condition.
 416                                 */
 417                                start_rmt_timer1(smc,smc->s.rmt_t_stuck,
 418                                        RM_TIMEOUT_T_STUCK) ;
 419                        }
 420                        /*
 421                         * We do NOT need to clear smc->r.bn_flag in case of
 422                         * not being in state T4 or T5, because the flag
 423                         * must be cleared in order to get in this condition.
 424                         */
 425
 426                        DB_RMTN(2,
 427                        "RMT : sm_mac_get_tx_state() = %d (bn_flag = %d)\n",
 428                        tx,smc->r.bn_flag) ;
 429                }
 430                /*RM44c*/
 431                else if (cmd == RM_TIMEOUT_ANNOUNCE && !smc->r.bn_flag) {
 432                        rmt_dup_actions(smc) ;
 433                }
 434                /*RM45*/
 435                else if (cmd == RM_RING_OP) {
 436                        smc->r.no_flag = FALSE ;
 437                        GO_STATE(RM5_RING_OP_DUP) ;
 438                        break ;
 439                }
 440                /*RM46*/
 441                else if (cmd == RM_TIMEOUT_T_STUCK &&
 442                        smc->r.rm_join && smc->r.bn_flag) {
 443                        GO_STATE(RM6_DIRECTED) ;
 444                        break ;
 445                }
 446                break ;
 447        case ACTIONS(RM5_RING_OP_DUP) :
 448                stop_rmt_timer0(smc) ;
 449                stop_rmt_timer1(smc) ;
 450                stop_rmt_timer2(smc) ;
 451                DB_RMTN(1,"RMT : RM5_RING_OP_DUP\n",0,0) ;
 452                ACTIONS_DONE() ;
 453                break;
 454        case RM5_RING_OP_DUP :
 455                /*RM52*/
 456                if (smc->r.dup_addr_test == DA_PASSED) {
 457                        smc->r.da_flag = FALSE ;
 458                        GO_STATE(RM2_RING_OP) ;
 459                        break ;
 460                }
 461                /*RM54*/
 462                else if (cmd == RM_RING_NON_OP) {
 463                        smc->r.jm_flag = FALSE ;
 464                        smc->r.bn_flag = FALSE ;
 465                        GO_STATE(RM4_NON_OP_DUP) ;
 466                        break ;
 467                }
 468                break ;
 469        case ACTIONS(RM6_DIRECTED) :
 470                start_rmt_timer0(smc,smc->s.rmt_t_direct,RM_TIMEOUT_T_DIRECT) ;
 471                stop_rmt_timer1(smc) ;
 472                start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL) ;
 473                sm_ma_control(smc,MA_DIRECTED) ;
 474                RS_SET(smc,RS_BEACON) ;
 475                DB_RMTN(1,"RMT : RM6_DIRECTED\n",0,0) ;
 476                ACTIONS_DONE() ;
 477                break ;
 478        case RM6_DIRECTED :
 479                /*RM63*/
 480                if (cmd == RM_TIMEOUT_POLL) {
 481                        start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL);
 482                        sm_mac_check_beacon_claim(smc) ;
 483#ifndef SUPERNET_3
 484                        /* Because of problems with the Supernet II chip set
 485                         * sending of Directed Beacon will stop after 165ms
 486                         * therefore restart_trt_for_dbcn(smc) will be called
 487                         * to prevent this.
 488                         */
 489                        restart_trt_for_dbcn(smc) ;
 490#endif /*SUPERNET_3*/
 491                        break ;
 492                }
 493                if ((cmd == RM_MY_BEACON || cmd == RM_OTHER_BEACON) &&
 494                        !smc->r.da_flag) {
 495                        smc->r.bn_flag = FALSE ;
 496                        GO_STATE(RM3_DETECT) ;
 497                        break ;
 498                }
 499                /*RM64*/
 500                else if ((cmd == RM_MY_BEACON || cmd == RM_OTHER_BEACON) &&
 501                        smc->r.da_flag) {
 502                        smc->r.bn_flag = FALSE ;
 503                        GO_STATE(RM4_NON_OP_DUP) ;
 504                        break ;
 505                }
 506                /*RM67*/
 507                else if (cmd == RM_TIMEOUT_T_DIRECT) {
 508                        GO_STATE(RM7_TRACE) ;
 509                        break ;
 510                }
 511                break ;
 512        case ACTIONS(RM7_TRACE) :
 513                stop_rmt_timer0(smc) ;
 514                stop_rmt_timer1(smc) ;
 515                stop_rmt_timer2(smc) ;
 516                smc->e.trace_prop |= ENTITY_BIT(ENTITY_MAC) ;
 517                queue_event(smc,EVENT_ECM,EC_TRACE_PROP) ;
 518                DB_RMTN(1,"RMT : RM7_TRACE\n",0,0) ;
 519                ACTIONS_DONE() ;
 520                break ;
 521        case RM7_TRACE :
 522                break ;
 523        default:
 524                SMT_PANIC(smc,SMT_E0122, SMT_E0122_MSG) ;
 525                break;
 526        }
 527}
 528
 529/*
 530 * (jd) RMT duplicate address actions
 531 * leave the ring or reinsert just as configured
 532 */
 533static void rmt_dup_actions(struct s_smc *smc)
 534{
 535        if (smc->r.jm_flag) {
 536        }
 537        else {
 538                if (smc->s.rmt_dup_mac_behavior) {
 539                        SMT_ERR_LOG(smc,SMT_E0138, SMT_E0138_MSG) ;
 540                        rmt_reinsert_actions(smc) ;
 541                }
 542                else {
 543                        SMT_ERR_LOG(smc,SMT_E0135, SMT_E0135_MSG) ;
 544                        rmt_leave_actions(smc) ;
 545                }
 546        }
 547}
 548
 549/*
 550 * Reconnect to the Ring
 551 */
 552static void rmt_reinsert_actions(struct s_smc *smc)
 553{
 554        queue_event(smc,EVENT_ECM,EC_DISCONNECT) ;
 555        queue_event(smc,EVENT_ECM,EC_CONNECT) ;
 556}
 557
 558/*
 559 * duplicate address detected
 560 */
 561static void rmt_new_dup_actions(struct s_smc *smc)
 562{
 563        smc->r.da_flag = TRUE ;
 564        smc->r.bn_flag = FALSE ;
 565        smc->r.jm_flag = FALSE ;
 566        /*
 567         * we have three options : change address, jam or leave
 568         * we leave the ring as default 
 569         * Optionally it's possible to reinsert after leaving the Ring
 570         * but this will not conform with SMT Spec.
 571         */
 572        if (smc->s.rmt_dup_mac_behavior) {
 573                SMT_ERR_LOG(smc,SMT_E0138, SMT_E0138_MSG) ;
 574                rmt_reinsert_actions(smc) ;
 575        }
 576        else {
 577                SMT_ERR_LOG(smc,SMT_E0135, SMT_E0135_MSG) ;
 578                rmt_leave_actions(smc) ;
 579        }
 580}
 581
 582
 583/*
 584 * leave the ring
 585 */
 586static void rmt_leave_actions(struct s_smc *smc)
 587{
 588        queue_event(smc,EVENT_ECM,EC_DISCONNECT) ;
 589        /*
 590         * Note: Do NOT try again later. (with please reconnect)
 591         * The station must be left from the ring!
 592         */
 593}
 594
 595/*
 596 * SMT timer interface
 597 *      start RMT timer 0
 598 */
 599static void start_rmt_timer0(struct s_smc *smc, u_long value, int event)
 600{
 601        smc->r.timer0_exp = FALSE ;             /* clear timer event flag */
 602        smt_timer_start(smc,&smc->r.rmt_timer0,value,EV_TOKEN(EVENT_RMT,event));
 603}
 604
 605/*
 606 * SMT timer interface
 607 *      start RMT timer 1
 608 */
 609static void start_rmt_timer1(struct s_smc *smc, u_long value, int event)
 610{
 611        smc->r.timer1_exp = FALSE ;     /* clear timer event flag */
 612        smt_timer_start(smc,&smc->r.rmt_timer1,value,EV_TOKEN(EVENT_RMT,event));
 613}
 614
 615/*
 616 * SMT timer interface
 617 *      start RMT timer 2
 618 */
 619static void start_rmt_timer2(struct s_smc *smc, u_long value, int event)
 620{
 621        smc->r.timer2_exp = FALSE ;             /* clear timer event flag */
 622        smt_timer_start(smc,&smc->r.rmt_timer2,value,EV_TOKEN(EVENT_RMT,event));
 623}
 624
 625/*
 626 * SMT timer interface
 627 *      stop RMT timer 0
 628 */
 629static void stop_rmt_timer0(struct s_smc *smc)
 630{
 631        if (smc->r.rmt_timer0.tm_active)
 632                smt_timer_stop(smc,&smc->r.rmt_timer0) ;
 633}
 634
 635/*
 636 * SMT timer interface
 637 *      stop RMT timer 1
 638 */
 639static void stop_rmt_timer1(struct s_smc *smc)
 640{
 641        if (smc->r.rmt_timer1.tm_active)
 642                smt_timer_stop(smc,&smc->r.rmt_timer1) ;
 643}
 644
 645/*
 646 * SMT timer interface
 647 *      stop RMT timer 2
 648 */
 649static void stop_rmt_timer2(struct s_smc *smc)
 650{
 651        if (smc->r.rmt_timer2.tm_active)
 652                smt_timer_stop(smc,&smc->r.rmt_timer2) ;
 653}
 654
 655