transmit.c
上传用户:allwinjm
上传日期:2021-08-29
资源大小:99k
文件大小:10k
源码类别:

Internet/IE编程

开发平台:

Unix_Linux

  1. /************************************************************************ 
  2.  * RSTP library - Rapid Spanning Tree (802.1t, 802.1w) 
  3.  * Copyright (C) 2001-2003 Optical Access 
  4.  * Author: Alex Rozin 
  5.  * 
  6.  * This file is part of RSTP library. 
  7.  * 
  8.  * RSTP library is free software; you can redistribute it and/or modify it 
  9.  * under the terms of the GNU Lesser General Public License as published by the 
  10.  * Free Software Foundation; version 2.1 
  11.  * 
  12.  * RSTP library is distributed in the hope that it will be useful, but 
  13.  * WITHOUT ANY WARRANTY; without even the implied warranty of 
  14.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser 
  15.  * General Public License for more details. 
  16.  * 
  17.  * You should have received a copy of the GNU Lesser General Public License 
  18.  * along with RSTP library; see the file COPYING.  If not, write to the Free 
  19.  * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 
  20.  * 02111-1307, USA. 
  21.  **********************************************************************/
  22. /* Port Transmit state machine : 17.27 */
  23.   
  24. #include "base.h"
  25. #include "stpm.h"
  26. #include "stp_to.h" /* for STP_OUT_get_port_mac & STP_OUT_tx_bpdu */
  27. #define BPDU_LEN8023_OFF    12
  28. #define STATES {        
  29.   CHOOSE(TRANSMIT_INIT),    
  30.   CHOOSE(TRANSMIT_PERIODIC),    
  31.   CHOOSE(IDLE),         
  32.   CHOOSE(TRANSMIT_CONFIG),  
  33.   CHOOSE(TRANSMIT_TCN),     
  34.   CHOOSE(TRANSMIT_RSTP),    
  35. }
  36. #define GET_STATE_NAME STP_transmit_get_state_name
  37. #include "choose.h"
  38. #define MIN_FRAME_LENGTH    64
  39. typedef struct tx_tcn_bpdu_t {
  40.   MAC_HEADER_T  mac;
  41.   ETH_HEADER_T  eth;
  42.   BPDU_HEADER_T hdr;
  43. } TCN_BPDU_T;
  44. typedef struct tx_stp_bpdu_t {
  45.   MAC_HEADER_T  mac;
  46.   ETH_HEADER_T  eth;
  47.   BPDU_HEADER_T hdr;
  48.   BPDU_BODY_T   body;
  49. } CONFIG_BPDU_T;
  50. typedef struct tx_rstp_bpdu_t {
  51.   MAC_HEADER_T  mac;
  52.   ETH_HEADER_T  eth;
  53.   BPDU_HEADER_T hdr;
  54.   BPDU_BODY_T   body;
  55.   unsigned char ver_1_length[2];
  56. } RSTP_BPDU_T;
  57. static RSTP_BPDU_T bpdu_packet  = {
  58.   {/* MAC_HEADER_T */
  59.     {0x01, 0x80, 0xc2, 0x00, 0x00, 0x00},   /* dst_mac */
  60.     {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}    /* src_mac */
  61.   },
  62.   { /* ETH_HEADER_T */
  63.     {0x00, 0x00},               /* len8023 */
  64.     BPDU_L_SAP, BPDU_L_SAP, LLC_UI      /* dsap, ssap, llc */
  65.   },
  66.   {/* BPDU_HEADER_T */
  67.     {0x00, 0x00},               /* protocol */
  68.     BPDU_VERSION_ID, 0x00           /* version, bpdu_type */
  69.   },
  70.   {
  71.     0x00,                   /*  flags; */
  72.     {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},  /*  root_id[8]; */
  73.     {0x00,0x00,0x00,0x00},          /*  root_path_cost[4]; */
  74.     {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},  /*  bridge_id[8]; */
  75.     {0x00,0x00},                /*  port_id[2]; */
  76.     {0x00,0x00},                /*  message_age[2]; */
  77.     {0x00,0x00},                /*  max_age[2]; */
  78.     {0x00,0x00},                /*  hello_time[2]; */
  79.     {0x00,0x00},                /*  forward_delay[2]; */
  80.   },
  81.    {0x00,0x00},                 /*  ver_1_length[2]; */
  82. };
  83. static size_t
  84. build_bpdu_header (int port_index,
  85.                    unsigned char bpdu_type,
  86.                    unsigned short pkt_len)
  87. {
  88.   unsigned short len8023;
  89.   STP_OUT_get_port_mac (port_index, bpdu_packet.mac.src_mac);
  90.   bpdu_packet.hdr.bpdu_type = bpdu_type;
  91.   bpdu_packet.hdr.version = (BPDU_RSTP == bpdu_type) ?
  92.                             BPDU_VERSION_RAPID_ID    :
  93.                             BPDU_VERSION_ID;
  94.   /* NOTE: I suppose, that sizeof(unsigned short)=2 ! */
  95.   len8023 = htons ((unsigned short) (pkt_len + 3));
  96.   memcpy (&bpdu_packet.eth.len8023, &len8023, 2); 
  97.   if (pkt_len < MIN_FRAME_LENGTH) pkt_len = MIN_FRAME_LENGTH;
  98.   return pkt_len;
  99. }
  100. static int
  101. txTcn (STATE_MACH_T* this)
  102. { /* 17.19.17 (page 68) & 9.3.2 (page 25) */
  103.   register size_t       pkt_len;
  104.   register int          port_index, vlan_id;
  105. #ifdef STP_DBG
  106.   if (this->owner.port->skip_tx > 0) {
  107.     if (1 == this->owner.port->skip_tx)
  108.       stp_trace ("port %s stop tx skipping",
  109.                  this->owner.port->port_name);
  110.     this->owner.port->skip_tx--;
  111.     return STP_Nothing_To_Do;
  112.   }
  113. #endif
  114.   if (this->owner.port->admin_non_stp) return 1;
  115.   port_index = this->owner.port->port_index;
  116.   vlan_id = this->owner.port->owner->vlan_id;
  117.   pkt_len = build_bpdu_header (port_index,
  118.                                BPDU_TOPO_CHANGE_TYPE,
  119.                                sizeof (BPDU_HEADER_T));
  120. #ifdef STP_DBG
  121.   if (this->debug)
  122.     stp_trace ("port %s txTcn", this->owner.port->port_name);
  123. #endif
  124.   return STP_OUT_tx_bpdu (port_index, vlan_id,
  125.                           (unsigned char *) &bpdu_packet,
  126.                           pkt_len);
  127. }
  128. static void
  129. build_config_bpdu (PORT_T* port, Bool set_topo_ack_flag)
  130. {
  131.   bpdu_packet.body.flags = 0;
  132.   if (port->tcWhile) {
  133. #ifdef STP_DBG
  134.     if (port->topoch->debug)
  135.       stp_trace ("tcWhile=%d =>tx TOLPLOGY_CHANGE_BIT to port %s",
  136.                  (int) port->tcWhile, port->port_name);
  137. #endif
  138.     bpdu_packet.body.flags |= TOLPLOGY_CHANGE_BIT;
  139.   }
  140.   if (set_topo_ack_flag && port->tcAck) {
  141.     bpdu_packet.body.flags |= TOLPLOGY_CHANGE_ACK_BIT;
  142.   }
  143.   STP_VECT_set_vector (&port->portPrio, &bpdu_packet.body);
  144.   STP_set_times (&port->portTimes, &bpdu_packet.body);
  145. }
  146. static int
  147. txConfig (STATE_MACH_T* this)
  148. {/* 17.19.15 (page 67) & 9.3.1 (page 23) */
  149.   register size_t   pkt_len;
  150.   register PORT_T*  port = NULL;
  151.   register int      port_index, vlan_id;
  152. #ifdef STP_DBG
  153.   if (this->owner.port->skip_tx > 0) {
  154.     if (1 == this->owner.port->skip_tx)
  155.       stp_trace ("port %s stop tx skipping",
  156.                  this->owner.port->port_name);
  157.     this->owner.port->skip_tx--;
  158.     return STP_Nothing_To_Do;
  159.   }
  160. #endif
  161.   port = this->owner.port;
  162.   if (port->admin_non_stp) return 1;
  163.   port_index = port->port_index;
  164.   vlan_id = port->owner->vlan_id;
  165.   
  166.   pkt_len = build_bpdu_header (port->port_index,
  167.                                BPDU_CONFIG_TYPE,
  168.                                sizeof (BPDU_HEADER_T) + sizeof (BPDU_BODY_T));
  169.   build_config_bpdu (port, True);
  170.  
  171. #ifdef STP_DBG
  172.   if (this->debug)
  173.     stp_trace ("port %s txConfig flags=0X%lx",
  174.         port->port_name,
  175.         (unsigned long) bpdu_packet.body.flags);
  176. #endif
  177.   return STP_OUT_tx_bpdu (port_index, vlan_id,
  178.                           (unsigned char *) &bpdu_packet,
  179.                           pkt_len);
  180. }
  181. static int
  182. txRstp (STATE_MACH_T* this)
  183. {/* 17.19.16 (page 68) & 9.3.3 (page 25) */
  184.   register size_t       pkt_len;
  185.   register PORT_T*      port = NULL;
  186.   register int          port_index, vlan_id;
  187.   unsigned char         role;
  188. #ifdef STP_DBG
  189.   if (this->owner.port->skip_tx > 0) {
  190.     if (1 == this->owner.port->skip_tx)
  191.       stp_trace ("port %s stop tx skipping",
  192.                  this->owner.port->port_name);
  193.     else
  194.       stp_trace ("port %s skip tx %d",
  195.                  this->owner.port->port_name, this->owner.port->skip_tx);
  196.     this->owner.port->skip_tx--;
  197.     return STP_Nothing_To_Do;
  198.   }
  199. #endif
  200.   port = this->owner.port;
  201.   if (port->admin_non_stp) return 1;
  202.   port_index = port->port_index;
  203.   vlan_id = port->owner->vlan_id;
  204.   pkt_len = build_bpdu_header (port->port_index,
  205.                                BPDU_RSTP,
  206.                                sizeof (BPDU_HEADER_T) + sizeof (BPDU_BODY_T) + 2);
  207.   build_config_bpdu (port, False);
  208.   switch (port->selectedRole) {
  209.     default:
  210.     case DisabledPort:
  211.       role = RSTP_PORT_ROLE_UNKN;
  212.       break;
  213.     case AlternatePort:
  214.       role = RSTP_PORT_ROLE_ALTBACK;
  215.       break;
  216.     case BackupPort:
  217.       role = RSTP_PORT_ROLE_ALTBACK;
  218.       break;
  219.     case RootPort:
  220.       role = RSTP_PORT_ROLE_ROOT;
  221.       break;
  222.     case DesignatedPort:
  223.       role = RSTP_PORT_ROLE_DESGN;
  224.       break;
  225.   }
  226.   bpdu_packet.body.flags |= (role << PORT_ROLE_OFFS);
  227.   if (port->synced) {
  228. #if 0 /* def STP_DBG */
  229.     if (port->roletrns->debug)
  230.       stp_trace ("tx AGREEMENT_BIT to port %s", port->port_name);
  231. #endif
  232.     bpdu_packet.body.flags |= AGREEMENT_BIT;
  233.   }
  234.   if (port->proposing) {
  235. #if 0 /* def STP_DBG */
  236.     if (port->roletrns->debug)
  237.       stp_trace ("tx PROPOSAL_BIT to port %s", port->port_name);
  238. #endif
  239.     bpdu_packet.body.flags |= PROPOSAL_BIT;
  240.   }
  241. #ifdef STP_DBG
  242.   if (this->debug)
  243.     stp_trace ("port %s txRstp flags=0X%lx",
  244.         port->port_name,
  245.         (unsigned long) bpdu_packet.body.flags);
  246. #endif
  247.    
  248.   return STP_OUT_tx_bpdu (port_index, vlan_id,
  249.                           (unsigned char *) &bpdu_packet,
  250.                           pkt_len);
  251. }
  252. void
  253. STP_transmit_enter_state (STATE_MACH_T* this)
  254. {
  255.   register PORT_T*     port = this->owner.port;
  256.   switch (this->State) {
  257.     case BEGIN:
  258.     case TRANSMIT_INIT:
  259.       port->newInfo = False;
  260.       port->helloWhen = 0;
  261.       port->txCount = 0;
  262.       break;
  263.     case TRANSMIT_PERIODIC:
  264.       port->newInfo = port->newInfo ||
  265.                             ((port->role == DesignatedPort) ||
  266.                              ((port->role == RootPort) && port->tcWhile));
  267.       port->helloWhen = port->owner->rootTimes.HelloTime;
  268.       break;
  269.     case IDLE:
  270.       break;
  271.     case TRANSMIT_CONFIG:
  272.       port->newInfo = False;
  273.       txConfig (this);
  274.       port->txCount++;
  275.       port->tcAck = False;
  276.       break;
  277.     case TRANSMIT_TCN:
  278.       port->newInfo = False;
  279.       txTcn (this);
  280.       port->txCount++;
  281.       break;
  282.     case TRANSMIT_RSTP:
  283.       port->newInfo = False;
  284.       txRstp (this);
  285.       port->txCount++;
  286.       port->tcAck = False;
  287.       break;
  288.   };
  289. }
  290.   
  291. Bool
  292. STP_transmit_check_conditions (STATE_MACH_T* this)
  293. {
  294.   register PORT_T*     port = this->owner.port;
  295.   if (BEGIN == this->State) return STP_hop_2_state (this, TRANSMIT_INIT);
  296.   switch (this->State) {
  297.     case TRANSMIT_INIT:
  298.       return STP_hop_2_state (this, IDLE);
  299.     case TRANSMIT_PERIODIC:
  300.       return STP_hop_2_state (this, IDLE);
  301.     case IDLE:
  302.       if (!port->helloWhen) return STP_hop_2_state (this, TRANSMIT_PERIODIC);
  303.       if (!port->sendRSTP && port->newInfo &&
  304.           (port->txCount < TxHoldCount) &&
  305.           (port->role == DesignatedPort) &&
  306.           port->helloWhen)
  307.         return STP_hop_2_state (this, TRANSMIT_CONFIG);
  308.       if (!port->sendRSTP && port->newInfo &&
  309.           (port->txCount < TxHoldCount) &&
  310.           (port->role == RootPort) &&
  311.           port->helloWhen)
  312.         return STP_hop_2_state (this, TRANSMIT_TCN);
  313.       if (port->sendRSTP && port->newInfo &&
  314.           (port->txCount < TxHoldCount) &&
  315.           ((port->role == RootPort) ||
  316.            (port->role == DesignatedPort)))
  317.         return STP_hop_2_state (this, TRANSMIT_RSTP);
  318.       break;
  319.     case TRANSMIT_CONFIG:
  320.       return STP_hop_2_state (this, IDLE);
  321.     case TRANSMIT_TCN:
  322.       return STP_hop_2_state (this, IDLE);
  323.     case TRANSMIT_RSTP:
  324.       return STP_hop_2_state (this, IDLE);
  325.   };
  326.   return False;
  327. }