#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include "tests_body.h"
/**********************************************************************/
/************************ TEST SCENARIOS ******************************/

struct smb_test wrst;
const char* TLIST[16] = {"2.1.1", "2.1.2", "2.2.1", "2.2.2", "2.2.5", "2.2.6",
                        "2.2.7", "3.1.1", "3.1.2", "3.1.3", "3.1.4", "3.1.5",
                        "3.2.1", "3.2.2", "3.3.1", "3.3.2"};

void init_wr_test(int test_no, int variant)
{
  unsigned int vtag, i;

  /*default values for functional tests*/
  for(i=0; i<SMB_PORTS; ++i) {
    wrst.ptx[i].fsize    = 64;
    wrst.ptx[i].fsize_start= 64;
    wrst.ptx[i].fsize_step = 64;
    wrst.ptx[i].fsize_stop = 64;
    wrst.ptx[i].fsize_n  = 0;
    wrst.ptx[i].fload_tab[0] = 10;
    wrst.ptx[i].fload_n  = 1;
    wrst.ptx[i].fnum     = T_2XX_FNUM;
  }
  wrst.test_type = TEST_FUNCTIONAL;
  wrst.permute = 0;
  wrst.force_prst = 0;

  /*loads and sizes for performance tests*/
  if (test_no >= TEST_3_1_1 && test_no != TEST_3_2_2 && variant == VAR1) {
    wrst.ftime = 0;
    wrst.test_type = TEST_PERFORMANCE;
    for (i=0; i<SMB_PORTS; ++i) {
      /* size:   64 - 1522 with step of 1
       * loads:  10, 30, 50, 70, 80, 85, 90, 92, 95, 97, 99, 100
       * number: 10^9 */
      wrst.ptx[i].fsize      = 60;
      wrst.ptx[i].fsize_start= 60;
      wrst.ptx[i].fsize_step = 32; //1;
      wrst.ptx[i].fsize_stop = 128; //1522;
      wrst.ptx[i].fsize_n    = 0;
      wrst.ptx[i].fload_tab[0]   = 10;
      wrst.ptx[i].fload_tab[1]   = 30;
      wrst.ptx[i].fload_tab[2]   = 50;
      wrst.ptx[i].fload_tab[3]   = 70;
      wrst.ptx[i].fload_tab[4]   = 80;
      wrst.ptx[i].fload_tab[5]   = 85;
      wrst.ptx[i].fload_tab[6]   = 90;
      wrst.ptx[i].fload_tab[7]   = 92;
      wrst.ptx[i].fload_tab[8]   = 95;
      wrst.ptx[i].fload_tab[9]   = 97;
      wrst.ptx[i].fload_tab[10]  = 99;
      wrst.ptx[i].fload_tab[11]  = 100;
      wrst.ptx[i].fload_n    = 12;
      wrst.ptx[i].fnum       = 1000000; //1000000000;  //10^9
    }
  }
  if ( (test_no >= TEST_3_1_1 && variant == VAR2) ||
       (test_no == TEST_3_2_2 && variant == VAR1) ||
       (test_no == TEST_3_3_1 && variant == VAR1) ||
       (test_no == TEST_3_3_2 && variant == VAR1) ) {
    wrst.ftime = 20; //5*60;  //5 min
    wrst.test_type = TEST_PERFORMANCE;
    for (i=0; i<SMB_PORTS; ++i) {
      /* size:          64, 65, 700, 701, 1521, 1522
       * loads:         50, 80, 95, 100
       * time of burst: 5 min */
      wrst.ptx[i].fsize      = 0;
      wrst.ptx[i].fsize_start= 0;
      wrst.ptx[i].fsize_step = 0;
      wrst.ptx[i].fsize_stop = 0;
      wrst.ptx[i].fsize_tab[0] = 60;
      wrst.ptx[i].fsize_tab[1] = 61;
      wrst.ptx[i].fsize_tab[2] = 696;
      wrst.ptx[i].fsize_tab[3] = 697;
      wrst.ptx[i].fsize_tab[4] = 1513;
      wrst.ptx[i].fsize_tab[5] = 1514;
      wrst.ptx[i].fsize_n  = 6;
      wrst.ptx[i].fload_tab[0] = 50;
      wrst.ptx[i].fload_tab[1] = 80; 
      wrst.ptx[i].fload_tab[2] = 95; 
      wrst.ptx[i].fload_tab[3] = 100; 
      wrst.ptx[i].fload_n  = 4; 
      wrst.ptx[i].fnum     = 0; 
    }
  }

  switch(test_no) {
    case TEST_2_1_1:
      /* 2.1.1  Unicast - one-to-one stream */
      /* TX:      p0->p2; p2 -> p0; 802.1d
       * RX_TRIG: p0; p2 -> smac 
       * RX:      p1; p3 */
      wrst.learning = 0;
      wrst.variants = 1;
      wrst.ptx[0].d_ports[0] = 2;
      wrst.ptx[2].d_ports[0] = 0;
      wrst.ptx[0].q_vid  = VID_NONE;
      wrst.ptx[2].q_vid  = VID_NONE;
      wrst.ptx[0].d_ports_n  = 1;
      wrst.ptx[1].d_ports_n  = 0;
      wrst.ptx[2].d_ports_n  = 1;
      wrst.ptx[3].d_ports_n  = 0;

      wrst.prx[0].s_port = 2;
      wrst.prx[2].s_port = 0;
      wrst.prx[1].s_port = RX_PALL;
      wrst.prx[3].s_port = RX_PALL;
      wrst.prx[0].trig2_len = 0;
      wrst.prx[1].trig2_len = 0;
      wrst.prx[2].trig2_len = 0;
      wrst.prx[3].trig2_len = 0;
      break;

    case TEST_2_1_2:
      /* 2.1.2 Unicast - many-to-many stream */
      /* TX:      p0->p1; p1->p0; p2->p3; p3->p2; 802.1d
       * RX_TRIG: p0; p1; p2; p3 */
      wrst.learning = 0;
      wrst.variants = 1;
      wrst.ptx[0].d_ports[0] = 1;
      wrst.ptx[0].d_ports[1] = 2;
      wrst.ptx[0].d_ports[2] = 3;

      wrst.ptx[1].d_ports[0] = 0;
      wrst.ptx[1].d_ports[1] = 2;
      wrst.ptx[1].d_ports[2] = 3;

      wrst.ptx[2].d_ports[0] = 0;
      wrst.ptx[2].d_ports[1] = 1;
      wrst.ptx[2].d_ports[2] = 3;

      wrst.ptx[3].d_ports[0] = 0;
      wrst.ptx[3].d_ports[1] = 1;
      wrst.ptx[3].d_ports[2] = 2;

      wrst.ptx[0].d_ports_n  = 3;
      wrst.ptx[1].d_ports_n  = 3;
      wrst.ptx[2].d_ports_n  = 3;
      wrst.ptx[3].d_ports_n  = 3;
      wrst.ptx[0].q_vid  = VID_NONE;
      wrst.ptx[1].q_vid  = VID_NONE;
      wrst.ptx[2].q_vid  = VID_NONE;
      wrst.ptx[3].q_vid  = VID_NONE;

      wrst.prx[0].s_port = RX_ALLUNI;
      wrst.prx[1].s_port = RX_ALLUNI;
      wrst.prx[2].s_port = RX_ALLUNI;
      wrst.prx[3].s_port = RX_ALLUNI;
      wrst.prx[0].trig2_len = 0;
      wrst.prx[1].trig2_len = 0;
      wrst.prx[2].trig2_len = 0;
      wrst.prx[3].trig2_len = 0;
      break;

    case TEST_2_2_1:
      /* 2.2.1 VLAN-limited forwarding */
      /* TX:      p0->p2; p2->p0; 802.1q
       * RX_TRIG: p0; p2 -> smac; vid; prio
       * RX:      p1; p3 */
      wrst.learning = 0;
      wrst.variants = 1;
      wrst.ptx[0].d_ports[0] = 2;
      wrst.ptx[2].d_ports[0] = 0;
      wrst.ptx[0].q_vid  = 1;
      wrst.ptx[0].q_pri  = 1;
      wrst.ptx[2].q_vid  = 1;
      wrst.ptx[2].q_pri  = 1;
      wrst.ptx[0].d_ports_n = 1;
      wrst.ptx[1].d_ports_n = 0;
      wrst.ptx[2].d_ports_n = 1;
      wrst.ptx[3].d_ports_n = 0;

      wrst.prx[0].s_port = 2;
      wrst.prx[2].s_port = 0;
      wrst.prx[1].s_port = RX_PALL;
      wrst.prx[3].s_port = RX_PALL;
      wrst.prx[0].trig2_len = 4;
      wrst.prx[2].trig2_len = 4;
      wrst.prx[1].trig2_len = 0;
      wrst.prx[3].trig2_len = 0;
      vtag = VLAN_TAG(1, 1);
      memcpy( wrst.prx[0].trig2_pat, &vtag, 4 );
      memcpy( wrst.prx[2].trig2_pat, &vtag, 4 );
      break;

    case TEST_2_2_2:
      /* 2.2.2 VLAN separation of traffic */
      /* TX:      p0; p2; 802.1q; broadcast
       * RX_TRIG: p0; p2 -> smac; vid; prio
       * RX:      p1; p3 */
      wrst.learning = 0;
      wrst.variants = 1;
      wrst.ptx[0].d_ports[0] = TX_PALL;
      wrst.ptx[2].d_ports[0] = TX_PALL;
      wrst.ptx[0].q_vid  = 1;
      wrst.ptx[0].q_pri  = 0;
      wrst.ptx[2].q_vid  = 1;
      wrst.ptx[2].q_pri  = 0;
      wrst.ptx[0].d_ports_n = 1;
      wrst.ptx[1].d_ports_n = 0;
      wrst.ptx[2].d_ports_n = 1;
      wrst.ptx[3].d_ports_n = 0;

      wrst.prx[0].s_port = 2;
      wrst.prx[2].s_port = 0;
      wrst.prx[1].s_port = RX_PALL;
      wrst.prx[3].s_port = RX_PALL;
      wrst.prx[0].trig2_len = 4;
      wrst.prx[2].trig2_len = 4;
      wrst.prx[1].trig2_len = 0;
      wrst.prx[3].trig2_len = 0;
      vtag = VLAN_TAG(1, 0);
      memcpy( wrst.prx[0].trig2_pat, &vtag, 4 );
      memcpy( wrst.prx[2].trig2_pat, &vtag, 4 );
      break;

    case TEST_2_2_5:
      /* 2.2.5 Tagging */
      /* TX:      p0->p2; p2->p0; 802.1d
       * RX_TRIG: p0; p2 -> smac; vid; prio
       * RX:      p1; p3 */
      wrst.learning = 0;
      wrst.variants = 1;
      wrst.ptx[0].d_ports[0] = 2;
      wrst.ptx[2].d_ports[0] = 0;
      wrst.ptx[0].q_vid  = VID_NONE;
      wrst.ptx[2].q_vid  = VID_NONE;
      wrst.ptx[0].d_ports_n = 1;
      wrst.ptx[1].d_ports_n = 0;
      wrst.ptx[2].d_ports_n = 1;
      wrst.ptx[3].d_ports_n = 0;

      wrst.prx[0].s_port = 2;
      wrst.prx[2].s_port = 0;
      wrst.prx[1].s_port = RX_PALL;
      wrst.prx[3].s_port = RX_PALL;
      wrst.prx[0].trig2_len = 4;
      wrst.prx[2].trig2_len = 4;
      wrst.prx[1].trig2_len = 0;
      wrst.prx[3].trig2_len = 0;
      vtag = VLAN_TAG(1, 3);
      memcpy( wrst.prx[0].trig2_pat, &vtag, 4 );
      memcpy( wrst.prx[2].trig2_pat, &vtag, 4 );
      break;

    case TEST_2_2_6:
      /* 2.2.6 Untagging */
      /* TX:      p0->p2; p2->p0; 802.1q
       * RX_TRIG: p0; p2 -> smac; ethtype
       * RX:      p1; p3 */
      wrst.learning = 0;
      wrst.variants = 1;
      wrst.ptx[0].d_ports[0] = 2;
      wrst.ptx[2].d_ports[0] = 0;
      wrst.ptx[0].q_vid  = 1;
      wrst.ptx[0].q_pri  = 0;
      wrst.ptx[2].q_vid  = 1;
      wrst.ptx[2].q_pri  = 0;
      wrst.ptx[0].d_ports_n = 1;
      wrst.ptx[1].d_ports_n = 0;
      wrst.ptx[2].d_ports_n = 1;
      wrst.ptx[3].d_ports_n = 0;

      wrst.prx[0].s_port = 2;
      wrst.prx[2].s_port = 0;
      wrst.prx[1].s_port = RX_PALL;
      wrst.prx[3].s_port = RX_PALL;
      wrst.prx[0].trig2_len = 2;
      wrst.prx[2].trig2_len = 2;
      wrst.prx[1].trig2_len = 0;
      wrst.prx[3].trig2_len = 0;
      vtag = NOVLAN_TAG;
      memcpy( wrst.prx[0].trig2_pat, &vtag, 2 );
      memcpy( wrst.prx[2].trig2_pat, &vtag, 2 );
      break;

    case TEST_2_2_7:
      /* 2.2.7 Snake test */
      /* TX:  p0->p1; p1->p0; p2->p3; p3->p2
       * RX_TRIG: p0; p1; p2; p3 -> smac; ethtype */
      wrst.learning = 0;
      wrst.variants = 1;
      wrst.ptx[0].d_ports[0] = 1;
      wrst.ptx[1].d_ports[0] = 0;
      wrst.ptx[2].d_ports[0] = 3;
      wrst.ptx[3].d_ports[0] = 2;
      wrst.ptx[0].q_vid  = VID_NONE;
      wrst.ptx[1].q_vid  = VID_NONE;
      wrst.ptx[2].q_vid  = VID_NONE;
      wrst.ptx[3].q_vid  = VID_NONE;
      wrst.ptx[0].d_ports_n = 1;
      wrst.ptx[1].d_ports_n = 1;
      wrst.ptx[2].d_ports_n = 1;
      wrst.ptx[3].d_ports_n = 1;

      wrst.prx[0].s_port = 1;
      wrst.prx[1].s_port = 0;
      wrst.prx[2].s_port = 3;
      wrst.prx[3].s_port = 2;
      wrst.prx[0].trig2_len = 2;
      wrst.prx[1].trig2_len = 2;
      wrst.prx[2].trig2_len = 2;
      wrst.prx[3].trig2_len = 2;
      vtag = NOVLAN_TAG;
      memcpy( wrst.prx[0].trig2_pat, &vtag, 2 );
      memcpy( wrst.prx[1].trig2_pat, &vtag, 2 );
      memcpy( wrst.prx[2].trig2_pat, &vtag, 2 );
      memcpy( wrst.prx[3].trig2_pat, &vtag, 2 );
      break;

    /***********************************************/ 
    /*             PERFORMANCE TESTS               */
    /***********************************************/ 
    case TEST_3_1_1:
      wrst.learning = 1;
      wrst.variants = 2;
      wrst.ptx[0].d_ports[0] = 2;
      wrst.ptx[2].d_ports[0] = 0;
      wrst.ptx[1].d_ports[0] = 3;
      wrst.ptx[3].d_ports[0] = 1;
      wrst.ptx[0].q_vid  = VID_NONE;
      wrst.ptx[1].q_vid  = VID_NONE;
      wrst.ptx[2].q_vid  = VID_NONE;
      wrst.ptx[3].q_vid  = VID_NONE;
      wrst.ptx[0].d_ports_n = 1;
      wrst.ptx[1].d_ports_n = 1;
      wrst.ptx[2].d_ports_n = 1;
      wrst.ptx[3].d_ports_n = 1;

      wrst.prx[0].s_port = 2;
      wrst.prx[2].s_port = 0;
      wrst.prx[1].s_port = 3;
      wrst.prx[3].s_port = 1;
      wrst.prx[0].trig2_len = 0;
      wrst.prx[1].trig2_len = 0;
      wrst.prx[2].trig2_len = 0;
      wrst.prx[3].trig2_len = 0;
      break;

    case TEST_3_1_2:
      /* 3.1.2 Unicast one-to-one streams */
      /* TX: p0->p1; p1->p0; p2->p3; p3->p2
       * RX_TRIG: p0; p1; p2; p3 -> smac */
      wrst.learning = 1;
      wrst.variants = 2;
      wrst.ptx[0].d_ports[0] = 1;
      wrst.ptx[1].d_ports[0] = 0;
      wrst.ptx[2].d_ports[0] = 3;
      wrst.ptx[3].d_ports[0] = 2;
      wrst.ptx[0].q_vid = VID_NONE;
      wrst.ptx[1].q_vid = VID_NONE;
      wrst.ptx[2].q_vid = VID_NONE;
      wrst.ptx[3].q_vid = VID_NONE;
      wrst.ptx[0].d_ports_n = 1;
      wrst.ptx[1].d_ports_n = 1;
      wrst.ptx[2].d_ports_n = 1;
      wrst.ptx[3].d_ports_n = 1;

      wrst.prx[0].s_port = 1;
      wrst.prx[1].s_port = 0;
      wrst.prx[2].s_port = 3;
      wrst.prx[3].s_port = 2;
      wrst.prx[0].trig2_len = 0;
      wrst.prx[1].trig2_len = 0;
      wrst.prx[2].trig2_len = 0;
      wrst.prx[3].trig2_len = 0;
      break;

    case TEST_3_1_3:
      /* 3.1.3 Unicast many-to-many streams */
      /* TX: p0->p1,p2,p3; p1->p0,p2,p3; p2->p0,p1,p3; p3->p0,p1,p2
       * RX_TRIG: p0; p1; p2; p3 */
      wrst.learning = 1;
      wrst.variants = 2;
      wrst.ptx[0].d_ports[0] = 1;
      wrst.ptx[0].d_ports[1] = 2;
      wrst.ptx[0].d_ports[2] = 3;

      wrst.ptx[1].d_ports[0] = 0;
      wrst.ptx[1].d_ports[1] = 2;
      wrst.ptx[1].d_ports[2] = 3;

      wrst.ptx[2].d_ports[0] = 0;
      wrst.ptx[2].d_ports[1] = 1;
      wrst.ptx[2].d_ports[2] = 3;

      wrst.ptx[3].d_ports[0] = 0;
      wrst.ptx[3].d_ports[1] = 1;
      wrst.ptx[3].d_ports[2] = 2;

      wrst.ptx[0].d_ports_n  = 3;
      wrst.ptx[1].d_ports_n  = 3;
      wrst.ptx[2].d_ports_n  = 3;
      wrst.ptx[3].d_ports_n  = 3;
      wrst.ptx[0].q_vid  = VID_NONE;
      wrst.ptx[1].q_vid  = VID_NONE;
      wrst.ptx[2].q_vid  = VID_NONE;
      wrst.ptx[3].q_vid  = VID_NONE;

      wrst.prx[0].s_port = RX_ALLUNI;
      wrst.prx[1].s_port = RX_ALLUNI;
      wrst.prx[2].s_port = RX_ALLUNI;
      wrst.prx[3].s_port = RX_ALLUNI;
      wrst.prx[0].trig2_len = 0;
      wrst.prx[1].trig2_len = 0;
      wrst.prx[2].trig2_len = 0;
      wrst.prx[3].trig2_len = 0;
      break;

    case TEST_3_1_4:
      /* 3.1.4 VLAN, broadcast */
      /* TX: p0; p1; p2; p3 -> broadcast, 802.1q
       * RX_TRIG: p0; p1; p2; p3 -> smac, vid, prio */
      wrst.learning = 1;
      wrst.variants = 2;
      wrst.ptx[0].d_ports[0] = TX_PALL;
      wrst.ptx[1].d_ports[0] = TX_PALL;
      wrst.ptx[2].d_ports[0] = TX_PALL;
      wrst.ptx[3].d_ports[0] = TX_PALL;
      wrst.ptx[0].q_vid = 1;
      wrst.ptx[1].q_vid = 2;
      wrst.ptx[2].q_vid = 1;
      wrst.ptx[3].q_vid = 2;
      wrst.ptx[0].q_pri = 0;
      wrst.ptx[1].q_pri = 0;
      wrst.ptx[2].q_pri = 0;
      wrst.ptx[3].q_pri = 0;
      wrst.ptx[0].d_ports_n = 1;
      wrst.ptx[1].d_ports_n = 1;
      wrst.ptx[2].d_ports_n = 1;
      wrst.ptx[3].d_ports_n = 1;

      wrst.prx[0].s_port = 2;
      wrst.prx[2].s_port = 0;
      wrst.prx[1].s_port = 3;
      wrst.prx[3].s_port = 1;
      wrst.prx[0].trig2_len = 4;
      wrst.prx[1].trig2_len = 4;
      wrst.prx[2].trig2_len = 4;
      wrst.prx[3].trig2_len = 4;
      vtag = VLAN_TAG(1, 0);
      memcpy( wrst.prx[0].trig2_pat, &vtag, 4 );
      memcpy( wrst.prx[2].trig2_pat, &vtag, 4 );
      vtag = VLAN_TAG(2, 0);
      memcpy( wrst.prx[1].trig2_pat, &vtag, 4 );
      memcpy( wrst.prx[3].trig2_pat, &vtag, 4 );
      break;

    case TEST_3_1_5:
      /* 3.1.5 VLAG, broadcast, tagging/untagging */
      /* TX: p0->p2; p2->p0; p1->p3; p3->p1
       * RX_TRIG: p0; p1; p2; p3 -> smac */
      wrst.learning = 1;
      wrst.variants = 2;
      wrst.ptx[0].d_ports[0] = TX_PALL;
      wrst.ptx[1].d_ports[0] = TX_PALL;
      wrst.ptx[2].d_ports[0] = TX_PALL;
      wrst.ptx[3].d_ports[0] = TX_PALL;
      wrst.ptx[0].q_vid = VID_NONE;
      wrst.ptx[1].q_vid = VID_NONE;
      wrst.ptx[2].q_vid = VID_NONE;
      wrst.ptx[3].q_vid = VID_NONE;
      wrst.ptx[0].d_ports_n = 1;
      wrst.ptx[1].d_ports_n = 1;
      wrst.ptx[2].d_ports_n = 1;
      wrst.ptx[3].d_ports_n = 1;

      wrst.prx[0].s_port = 2;
      wrst.prx[2].s_port = 0;
      wrst.prx[1].s_port = 3;
      wrst.prx[3].s_port = 1;
      wrst.prx[0].trig2_len = 0;
      wrst.prx[1].trig2_len = 0;
      wrst.prx[2].trig2_len = 0;
      wrst.prx[3].trig2_len = 0;
      break;

    case TEST_3_2_1:
      /* 3.2.1 Snake - Uniformly distributed load on all ports */
      /* TX: p0->p1; p1->p0; p2->p3; p3->p2
       * RX_TRIG: p0; p1; p2; p3 -> smac, ethtype */
      wrst.learning = 1;
      wrst.variants = 2;
      wrst.ptx[0].d_ports[0] = 1;
      wrst.ptx[1].d_ports[0] = 0;
      wrst.ptx[2].d_ports[0] = 3;
      wrst.ptx[3].d_ports[0] = 2;
      wrst.ptx[0].q_vid = VID_NONE;
      wrst.ptx[1].q_vid = VID_NONE;
      wrst.ptx[2].q_vid = VID_NONE;
      wrst.ptx[3].q_vid = VID_NONE;
      wrst.ptx[0].d_ports_n = 1;
      wrst.ptx[1].d_ports_n = 1;
      wrst.ptx[2].d_ports_n = 1;
      wrst.ptx[3].d_ports_n = 1;

      wrst.prx[0].s_port = 1;
      wrst.prx[1].s_port = 0;
      wrst.prx[2].s_port = 3;
      wrst.prx[3].s_port = 2;
      wrst.prx[0].trig2_len = 2;
      wrst.prx[1].trig2_len = 2;
      wrst.prx[2].trig2_len = 2;
      wrst.prx[3].trig2_len = 2;
      vtag = NOVLAN_TAG;
      memcpy( wrst.prx[0].trig2_pat, &vtag, 2 );
      memcpy( wrst.prx[1].trig2_pat, &vtag, 2 );
      memcpy( wrst.prx[2].trig2_pat, &vtag, 2 );
      memcpy( wrst.prx[3].trig2_pat, &vtag, 2 );
      break;

    case TEST_3_2_2:
      /* Non uniformly distributed load on ports */
      /* TX: p0->p1; p1->p0; p2->p3; p3->p2
       * RX_TRIG: p0; p1; p2; p3 -> smac, ethertype */
      wrst.learning = 1;
      wrst.variants = 1;
      wrst.permute  = 1;
      wrst.ptx[0].d_ports[0] = 1;
      wrst.ptx[1].d_ports[0] = 0;
      wrst.ptx[2].d_ports[0] = 3;
      wrst.ptx[3].d_ports[0] = 2;
      wrst.ptx[0].q_vid = VID_NONE;
      wrst.ptx[1].q_vid = VID_NONE;
      wrst.ptx[2].q_vid = VID_NONE;
      wrst.ptx[3].q_vid = VID_NONE;
      wrst.ptx[0].d_ports_n = 1;
      wrst.ptx[1].d_ports_n = 1;
      wrst.ptx[2].d_ports_n = 1;
      wrst.ptx[3].d_ports_n = 1;

      wrst.prx[0].s_port = 1;
      wrst.prx[1].s_port = 0;
      wrst.prx[2].s_port = 3;
      wrst.prx[3].s_port = 2;
      wrst.prx[0].trig2_len = 2;
      wrst.prx[1].trig2_len = 2;
      wrst.prx[2].trig2_len = 2;
      wrst.prx[3].trig2_len = 2;
      vtag = NOVLAN_TAG;
      memcpy( wrst.prx[0].trig2_pat, &vtag, 2 );
      memcpy( wrst.prx[1].trig2_pat, &vtag, 2 );
      memcpy( wrst.prx[2].trig2_pat, &vtag, 2 );
      memcpy( wrst.prx[3].trig2_pat, &vtag, 2 );
      break;

    case TEST_3_3_1:
      /* 3.3.1 Unicast frame storm */
      /* TX: p0->p1; p1->p0; p2->p3; p3->p2
       * RX_TRIG: p0; p1; p2; p3 -> smac */
      wrst.learning = 0;
      wrst.variants = 1;
      wrst.permute  = 0;
      wrst.force_prst = 1;
      wrst.ftime = 60;  //override default setting
      wrst.ptx[0].d_ports[0] = 1;
      wrst.ptx[1].d_ports[0] = 0;
      wrst.ptx[2].d_ports[0] = 3;
      wrst.ptx[3].d_ports[0] = 2;
      wrst.ptx[0].q_vid = VID_NONE;
      wrst.ptx[1].q_vid = VID_NONE;
      wrst.ptx[2].q_vid = VID_NONE;
      wrst.ptx[3].q_vid = VID_NONE;
      wrst.ptx[0].d_ports_n = 1;
      wrst.ptx[1].d_ports_n = 1;
      wrst.ptx[2].d_ports_n = 1;
      wrst.ptx[3].d_ports_n = 1;

      wrst.prx[0].s_port = 1;
      wrst.prx[1].s_port = 0;
      wrst.prx[2].s_port = 3;
      wrst.prx[3].s_port = 2;
      wrst.prx[0].trig2_len = 0;
      wrst.prx[1].trig2_len = 0;
      wrst.prx[2].trig2_len = 0;
      wrst.prx[3].trig2_len = 0;
      break;

    case TEST_3_3_2:
      /* 3.3.2 VLAN, broadcast, tagging/untagging */
      /* TX: p0->p1; p1->p0; p2->p3; p3->p2
       * RX_TRIG: p0; p1; p2; p3 -> smac */
      wrst.learning = 0;
      wrst.variants = 1;
      wrst.permute  = 0;
      wrst.force_prst = 1;
      wrst.ftime = 60;  //override default setting
      wrst.ptx[0].d_ports[0] = TX_PALL;
      wrst.ptx[1].d_ports[0] = TX_PALL;
      wrst.ptx[2].d_ports[0] = TX_PALL;
      wrst.ptx[3].d_ports[0] = TX_PALL;
      wrst.ptx[0].q_vid = VID_NONE;
      wrst.ptx[1].q_vid = VID_NONE;
      wrst.ptx[2].q_vid = VID_NONE;
      wrst.ptx[3].q_vid = VID_NONE;
      wrst.ptx[0].d_ports_n = 1;
      wrst.ptx[1].d_ports_n = 1;
      wrst.ptx[2].d_ports_n = 1;
      wrst.ptx[3].d_ports_n = 1;

      wrst.prx[0].s_port = 1;
      wrst.prx[1].s_port = 0;
      wrst.prx[2].s_port = 3;
      wrst.prx[3].s_port = 2;
      wrst.prx[0].trig2_len = 0;
      wrst.prx[1].trig2_len = 0;
      wrst.prx[2].trig2_len = 0;
      wrst.prx[3].trig2_len = 0;
      break;
  }
}

int run_test( HTCountStructure *cntrs, char mac[][6] )
{
  int i, j, rx_pmask = 0, tx_pmask = 0;
  struct smb_port_tx *p_tx = NULL;
  struct smb_port_rx *p_rx = NULL;
  
  //reset_ports(SMB_P0 | SMB_P1 | SMB_P2 | SMB_P3);

  ///* optional learning */
  //if (wrst.learning)
  //  smb_learning(SMB_PALL, mac, 3);

  /* setup required streams */
  for (i=0; i<SMB_PORTS; ++i) {
    p_tx = &(wrst.ptx[i]);

    //if (p_tx->d_ports_n > 0) {
    //  tx_pmask |= PORT_TO_PMASK(i);
    //  setup_stream(i, mac[p_tx->d_ports[0]], mac[i], p_tx->fsize, p_tx->fnum,
    //      p_tx->fload[0]/100.0, p_tx->q_pri, p_tx->q_vid);
    //}
    for (j=0; j< p_tx->d_ports_n; ++j) {
      setup_stream(i, mac[p_tx->d_ports[j]], mac[i], p_tx->fsize, p_tx->fnum,
          p_tx->fload/100.0/p_tx->d_ports_n, p_tx->q_pri, p_tx->q_vid, j);
    }
    if(p_tx->d_ports_n>0) {
      tx_pmask |= PORT_TO_PMASK(i);
      setup_stream(i, mac[p_tx->d_ports[j]], mac[i], p_tx->fsize, p_tx->fnum,
          p_tx->fload/100.0/p_tx->d_ports_n, p_tx->q_pri, p_tx->q_vid, -1);
    }
  }

  /* setup required triggers */
  for (i=0; i<SMB_PORTS; ++i) {
    p_rx = &(wrst.prx[i]);

    /* TRIG1 - SMAC or DMAC */
    if (p_rx->s_port == RX_ALLUNI)
      smb_set_trigger( mac[i], i, 0, 6, HTTRIGGER_1 );
    else if (p_rx->s_port != RX_PALL)
      smb_set_trigger( mac[p_rx->s_port], i, 6, 6, HTTRIGGER_1 );
    /* TRIG2 - Ethtype */
    if (p_rx->trig2_len > 0)
      smb_set_trigger( p_rx->trig2_pat, i, 12, p_rx->trig2_len, HTTRIGGER_2);
  }

  clear_allcntrs(SMB_PALL);

  ////wait for link up
  rx_pmask = 0;
  for (i=0; i<SMB_PORTS; ++i) {
    p_rx = &(wrst.prx[i]);
    if ((p_rx->s_port >= 0 && p_rx->s_port <=3) || p_rx->s_port == RX_PALL)
      rx_pmask |= PORT_TO_PMASK(i);
  }
  wait_linkup(rx_pmask);

  //generate traffic
  run_traffic(tx_pmask, TRAFFIC_START);
  //NSDelay(1);

  wait_test_done(tx_pmask, wrst.ftime);

  if(wrst.ftime > 0) {
    run_traffic(tx_pmask, TRAFFIC_STOP);
    wait_test_done(tx_pmask, 0);
  }

  get_allcntrs(SMB_PALL, cntrs);

  return 0;
}

int anl_result( HTCountStructure *cntrs, int testno)
{
  int req_num;
  unsigned long exp_rx[SMB_PORTS];

  switch (testno) {
    case TEST_2_1_1:
      /* All frames sent from p0 received on p2
       * All frames sent from p2 received on p0
       * Limited number of frames may be received on p1; p3 due to learning */
      if ( (cntrs[0].TmtPkt == T_2XX_FNUM && cntrs[2].RcvPkt == T_2XX_FNUM && cntrs[2].RcvTrig == T_2XX_FNUM) &&
           (cntrs[2].TmtPkt == T_2XX_FNUM && cntrs[0].RcvPkt == T_2XX_FNUM && cntrs[0].RcvTrig == T_2XX_FNUM) &&
           (cntrs[1].RcvPkt < T_2XX_UNRECOG_THR) && (cntrs[3].RcvPkt < T_2XX_UNRECOG_THR))
        return TEST_PASSED;

      if ( (cntrs[0].TmtPkt == T_2XX_FNUM && cntrs[2].RcvPkt == T_2XX_FNUM && cntrs[2].RcvTrig == T_2XX_FNUM) &&
           (cntrs[2].TmtPkt == T_2XX_FNUM && cntrs[0].RcvPkt == T_2XX_FNUM && cntrs[0].RcvTrig == T_2XX_FNUM) )
        return TEST_WARNING;

      break;
      
    case TEST_2_1_2:
      req_num = (SMB_PORTS-1)*T_2XX_FNUM;
      /* Each of the ports got frames addressed to it from all other ports
       * Limited number of frames addressed to other ports may be received due to learning */
      if ( (cntrs[0].TmtPkt == req_num && cntrs[0].RcvTrig == req_num && cntrs[0].RcvPkt <= req_num + T_2XX_UNRECOG_THR) &&
           (cntrs[1].TmtPkt == req_num && cntrs[1].RcvTrig == req_num && cntrs[1].RcvPkt <= req_num + T_2XX_UNRECOG_THR) &&
           (cntrs[2].TmtPkt == req_num && cntrs[2].RcvTrig == req_num && cntrs[2].RcvPkt <= req_num + T_2XX_UNRECOG_THR) &&
           (cntrs[3].TmtPkt == req_num && cntrs[3].RcvTrig == req_num && cntrs[3].RcvPkt <= req_num + T_2XX_UNRECOG_THR) )
        return TEST_PASSED;

      if ( (cntrs[0].TmtPkt == req_num && cntrs[0].RcvTrig == req_num) &&
           (cntrs[1].TmtPkt == req_num && cntrs[1].RcvTrig == req_num) &&
           (cntrs[2].TmtPkt == req_num && cntrs[2].RcvTrig == req_num) &&
           (cntrs[3].TmtPkt == req_num && cntrs[3].RcvTrig == req_num) )
        return TEST_WARNING;
      break;

    case TEST_2_2_7:
      /* All frames sent from p0 received on p1
       * All frames sent from p1 received on p0
       * All frames sent from p2 received on p3
       * All frames sent from p3 received on p2 */
      if ( (cntrs[0].TmtPkt == T_2XX_FNUM && cntrs[1].RcvPkt == T_2XX_FNUM && cntrs[1].RcvTrig == T_2XX_FNUM) &&
           (cntrs[1].TmtPkt == T_2XX_FNUM && cntrs[0].RcvPkt == T_2XX_FNUM && cntrs[0].RcvTrig == T_2XX_FNUM) &&
           (cntrs[2].TmtPkt == T_2XX_FNUM && cntrs[3].RcvPkt == T_2XX_FNUM && cntrs[3].RcvTrig == T_2XX_FNUM) &&
           (cntrs[3].TmtPkt == T_2XX_FNUM && cntrs[2].RcvPkt == T_2XX_FNUM && cntrs[2].RcvTrig == T_2XX_FNUM) )
        return TEST_PASSED;

      if ( (cntrs[0].TmtPkt == T_2XX_FNUM && cntrs[1].RcvPkt >= T_2XX_FNUM && cntrs[1].RcvTrig == T_2XX_FNUM) &&
           (cntrs[1].TmtPkt == T_2XX_FNUM && cntrs[0].RcvPkt >= T_2XX_FNUM && cntrs[0].RcvTrig == T_2XX_FNUM) &&
           (cntrs[2].TmtPkt == T_2XX_FNUM && cntrs[3].RcvPkt >= T_2XX_FNUM && cntrs[3].RcvTrig == T_2XX_FNUM) &&
           (cntrs[3].TmtPkt == T_2XX_FNUM && cntrs[2].RcvPkt >= T_2XX_FNUM && cntrs[2].RcvTrig == T_2XX_FNUM) )
        return TEST_WARNING;

      break;

    case TEST_2_2_1:
    case TEST_2_2_5:
    case TEST_2_2_6:
      /* All frames sent from p0 received on p2
       * All frames sent from p2 received on p0
       * No frames received on ports other than p0; p2 */
      if ( (cntrs[0].TmtPkt == T_2XX_FNUM && cntrs[2].RcvPkt == T_2XX_FNUM && cntrs[2].RcvTrig == T_2XX_FNUM) &&
           (cntrs[2].TmtPkt == T_2XX_FNUM && cntrs[0].RcvPkt == T_2XX_FNUM && cntrs[0].RcvTrig == T_2XX_FNUM) &&
           (cntrs[1].RcvPkt == 0 && cntrs[3].RcvPkt == 0) )
        return TEST_PASSED;
      break;

    case TEST_2_2_2:
      /* All frames sent from p0 dropped
       * All frames sent from p2 received only on p0
       * No frames received on ports other than p0 */
      if ( (cntrs[0].TmtPkt == T_2XX_FNUM && cntrs[2].RcvPkt == 0 && cntrs[2].RcvTrig == 0) &&
           (cntrs[2].TmtPkt == T_2XX_FNUM && cntrs[0].RcvPkt == T_2XX_FNUM && cntrs[0].RcvTrig == T_2XX_FNUM) &&
           (cntrs[1].RcvPkt == 0 && cntrs[2].RcvPkt == 0 && cntrs[3].RcvPkt == 0) )
        return TEST_PASSED;
      break;

    case TEST_3_1_1:
    case TEST_3_1_4:
    case TEST_3_1_5:
      /* All frames sent from p0 received on p2
       * All frames sent from p2 received on p0
       * All frames sent from p1 received on p3
       * All frames sent from p3 received on p1 */
      if ( (cntrs[0].TmtPkt == cntrs[2].RcvPkt && cntrs[0].TmtPkt == cntrs[2].RcvTrig) &&
           (cntrs[2].TmtPkt == cntrs[0].RcvPkt && cntrs[2].TmtPkt == cntrs[0].RcvTrig) &&
           (cntrs[1].TmtPkt == cntrs[3].RcvPkt && cntrs[1].TmtPkt == cntrs[3].RcvTrig) &&
           (cntrs[3].TmtPkt == cntrs[1].RcvPkt && cntrs[3].TmtPkt == cntrs[1].RcvTrig) )
        return TEST_PASSED;
      break;

    case TEST_3_1_2:
    case TEST_3_2_1:
    case TEST_3_2_2:
      /* All frames sent from p0 received on p1
       * All frames sent from p1 received on p0
       * All frames sent from p2 received on p3
       * All frames sent from p3 received on p2 */
      if ( (cntrs[0].TmtPkt == cntrs[1].RcvPkt && cntrs[0].TmtPkt == cntrs[1].RcvTrig) &&
           (cntrs[1].TmtPkt == cntrs[0].RcvPkt && cntrs[1].TmtPkt == cntrs[0].RcvTrig) &&
           (cntrs[2].TmtPkt == cntrs[3].RcvPkt && cntrs[2].TmtPkt == cntrs[3].RcvTrig) &&
           (cntrs[3].TmtPkt == cntrs[2].RcvPkt && cntrs[3].TmtPkt == cntrs[2].RcvTrig) )
        return TEST_PASSED;
      break;

    case TEST_3_1_3:
      /* Each of the ports got frames addressed to it from all other ports */
      exp_rx_frames(&wrst, cntrs, exp_rx);
      if ( (cntrs[0].RcvTrig == cntrs[0].RcvPkt && cntrs[0].RcvTrig == exp_rx[0]) &&
           (cntrs[1].RcvTrig == cntrs[1].RcvPkt && cntrs[1].RcvTrig == exp_rx[1]) &&
           (cntrs[2].RcvTrig == cntrs[2].RcvPkt && cntrs[2].RcvTrig == exp_rx[2]) &&
           (cntrs[3].RcvTrig == cntrs[3].RcvPkt && cntrs[3].RcvTrig == exp_rx[3]) )
        return TEST_PASSED;
      break;

    case TEST_3_3_1:
    case TEST_3_3_2:
      /* All frames sent from p0 received on p1
       * All frames sent from p1 received on p0
       * All frames sent from p2 received on p3
       * All frames sent from p3 received on p2
       * Limited number of additional frames may be received on p0; p1; p2; p3 due to learning */
      if ( (cntrs[0].RcvTrig == cntrs[1].TmtPkt && cntrs[0].RcvPkt >= cntrs[1].TmtPkt &&
                              cntrs[0].RcvPkt <= cntrs[1].TmtPkt + T_2XX_UNRECOG_THR) &&
           (cntrs[1].RcvTrig == cntrs[0].TmtPkt && cntrs[1].RcvPkt >= cntrs[0].TmtPkt &&
                              cntrs[1].RcvPkt <= cntrs[0].TmtPkt + T_2XX_UNRECOG_THR) &&
           (cntrs[2].RcvTrig == cntrs[3].TmtPkt && cntrs[2].RcvPkt >= cntrs[3].TmtPkt &&
                              cntrs[2].RcvPkt <= cntrs[3].TmtPkt + T_2XX_UNRECOG_THR) &&
           (cntrs[3].RcvTrig == cntrs[2].TmtPkt && cntrs[3].RcvPkt >= cntrs[2].TmtPkt &&
                              cntrs[3].RcvPkt <= cntrs[2].TmtPkt + T_2XX_UNRECOG_THR) )
        return TEST_PASSED;

      if ( (cntrs[0].RcvTrig == cntrs[1].TmtPkt && cntrs[0].RcvPkt >= cntrs[1].TmtPkt) &&
           (cntrs[1].RcvTrig == cntrs[0].TmtPkt && cntrs[1].RcvPkt >= cntrs[0].TmtPkt) &&
           (cntrs[2].RcvTrig == cntrs[3].TmtPkt && cntrs[2].RcvPkt >= cntrs[3].TmtPkt) &&
           (cntrs[3].RcvTrig == cntrs[2].TmtPkt && cntrs[3].RcvPkt >= cntrs[2].TmtPkt) )
        return TEST_WARNING;

      break;

  }

  return TEST_FAILED;
}

/*************************************************************/

int next_testcase(int reset)
{
  static int cur_load[2], cur_size[2];
  int i, j, quit = 1;
  int p_no;

  if(reset) {
    cur_load[0] = 0;
    cur_load[1] = 0;
    cur_size[0] = 0;
    cur_size[1] = 0;
    /* init load, needed for first run */
    for(j=0; j<SMB_PORTS; ++j) {
      if (wrst.ptx[j].fsize_n > 0)
        wrst.ptx[j].fsize = wrst.ptx[j].fsize_tab[0];
      else
        wrst.ptx[j].fsize = wrst.ptx[j].fsize_start;
      wrst.ptx[j].fload = wrst.ptx[j].fload_tab[0];
    }
    cur_load[0]++;
    cur_load[1]++;
    cur_size[0]++;
    cur_size[1]++;

    return NEXT_STEP;
  }

  if(wrst.permute) {
    /* that's the only fucking different case than all other... */

    for(i=0; i<2; ++i) {

      quit = 1;
      /* size */
      for(j=0; j<SMB_PORTS/2; ++j) {
        p_no = i*2+j;
        /* no more sizes */
        if( (wrst.ptx[p_no].fsize_n > 0 && cur_size[i] >= wrst.ptx[p_no].fsize_n) ||
            (wrst.ptx[p_no].fsize_n == 0 && wrst.ptx[p_no].fsize_start + cur_size[i]*wrst.ptx[p_no].fsize_step > wrst.ptx[p_no].fsize_stop) ) {
          //printf("greg port %d no more sizes\n", p_no);
          quit = 0;
          cur_size[i] = 0;
          //printf("%s: no more size for port %d\n", __FUNCTION__, p_no);
        }
        /*next*/
        //printf("greg incr size port %d\n", p_no);
        if (wrst.ptx[p_no].fsize_n > 0 && cur_size[i] < wrst.ptx[p_no].fsize_n)
          wrst.ptx[p_no].fsize = wrst.ptx[p_no].fsize_tab[cur_size[i]];
        else if (wrst.ptx[p_no].fsize_n == 0)
          wrst.ptx[p_no].fsize = wrst.ptx[p_no].fsize_start + cur_size[i]*wrst.ptx[p_no].fsize_step;
        //printf("%s: port %d fsize %d\n", __FUNCTION__, p_no, wrst.ptx[p_no].fsize);
        /*set also size and load for i=0*/
        if(i==1) {
          if(wrst.ptx[0].fsize_n > 0)
            wrst.ptx[0].fsize = wrst.ptx[0].fsize_tab[0];
          else
            wrst.ptx[0].fsize = wrst.ptx[0].fsize_start;
          if(wrst.ptx[1].fsize_n > 0)
            wrst.ptx[1].fsize = wrst.ptx[1].fsize_tab[0];
          else
            wrst.ptx[1].fsize = wrst.ptx[1].fsize_start;
          wrst.ptx[0].fload = wrst.ptx[0].fload_tab[0];
          wrst.ptx[1].fload = wrst.ptx[1].fload_tab[0];
        }
      }
      cur_size[i]++;
      if(quit) return NEXT_STEP;

      quit = 1;
      /* load */
      for(j=0; j<SMB_PORTS/2; ++j) {
        p_no = i*2+j;
        /* no more loads */
        if(cur_load[i] >= wrst.ptx[p_no].fload_n) {
          //printf("greg port %d no more loads\n", p_no);
          quit = 0;
          cur_load[i] = -1;
          break;
        }
        /*next*/
        //printf("greg incr load port %d\n", p_no);
        wrst.ptx[p_no].fload = wrst.ptx[p_no].fload_tab[cur_load[i]];
        if(wrst.ptx[p_no].fsize_n > 0)
          wrst.ptx[p_no].fsize = wrst.ptx[p_no].fsize_tab[0];
        else
          wrst.ptx[p_no].fsize = wrst.ptx[p_no].fsize_start;
        //printf("%s: port %d new fload %d fsize %d\n", __FUNCTION__, p_no, wrst.ptx[p_no].fload, wrst.ptx[p_no].fsize);
      }
      cur_load[i]++;

      if(quit) return NEXT_STEP;
    }

  }
  else {
    //printf("greg %s: no permute\n", __FUNCTION__);
    /* size */
    for(j=0; j<SMB_PORTS; ++j) {
      /* no more sizes */
      if( (wrst.ptx[j].fsize_n > 0 && cur_size[0] >= wrst.ptx[j].fsize_n) ||
          (wrst.ptx[j].fsize_n == 0 && wrst.ptx[j].fsize_start + cur_size[0]*wrst.ptx[j].fsize_step > wrst.ptx[j].fsize_stop) ) {
        quit = 0;
        cur_size[0] = 0;
        //printf("greg %s: no more size for port %d\n", __FUNCTION__, j);
      }
      /*next*/
      if (wrst.ptx[j].fsize_n > 0 && cur_size[0] < wrst.ptx[j].fsize_n)
        wrst.ptx[j].fsize = wrst.ptx[j].fsize_tab[cur_size[0]];
      else if (wrst.ptx[j].fsize_n == 0)
        wrst.ptx[j].fsize = wrst.ptx[j].fsize_start + cur_size[0]*wrst.ptx[j].fsize_step;
      //printf("greg %s: port %d fsize %d\n", __FUNCTION__, j, wrst.ptx[j].fsize);
    }
    cur_size[0]++;
    if(quit) return NEXT_STEP;

    quit = 1;
    /* load */
    for(j=0; j<SMB_PORTS; ++j) {
      /* no more loads */
      if(cur_load[i] >= wrst.ptx[j].fload_n) {
        quit = 0;
        cur_load[i] = 0;
        break;
      }
      /*next*/
      wrst.ptx[j].fload = wrst.ptx[j].fload_tab[cur_load[i]];
      if(wrst.ptx[j].fsize_n > 0)
        wrst.ptx[j].fsize = wrst.ptx[j].fsize_tab[0];
      else
        wrst.ptx[j].fsize = wrst.ptx[j].fsize_start;
      //printf("greg %s: port %d new fload %d fsize %d\n", __FUNCTION__, j, wrst.ptx[j].fload, wrst.ptx[j].fsize);
    }
    cur_load[i]++;
  }

  if (!quit) return NONEXT_STEP;
  else return NEXT_STEP;
}

/*************************************************************/

int run_and_analyze(int test_no, FILE *logfile)
{
  char mac[SMB_PORTS+1][6] = {{0x3c, 0x47, 0x0e, 0x04, 0x05, 0x06},
                              {0x3c, 0x47, 0x0e, 0x14, 0x15, 0x16},
                              {0x3c, 0x47, 0x0e, 0x24, 0x25, 0x26},
                              {0x3c, 0x47, 0x0e, 0x34, 0x35, 0x36},
                              {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}};
  HTCountStructure cntrs[SMB_PORTS];
  unsigned long exp_rxf[SMB_PORTS];
  int result, result_final, i, j,  i_var;
  time_t t_start, t_stop;

  printf("------ TEST %s ------\n", TLIST[test_no]);
  fprintf(logfile, "\n\n------ TEST %s ------\n", TLIST[test_no]);

  printf("Configuring WR Switch...\n");
  wrs_config("127.0.0.1", test_no);
  reset_ports(SMB_PALL);

  init_wr_test(test_no, 0);
  for(i_var=0; i_var<wrst.variants; ++i_var) {

    if(i_var > 0) {
      printf("------ TEST %s.%d ------\n", TLIST[test_no], i_var);
      fprintf(logfile, "\n\n------ TEST %s.%d ------\n", TLIST[test_no], i_var);
    }
    init_wr_test(test_no, i_var);
    //printf("Running test...");
    //fflush(stdout);


    /* optional learning */
    if (wrst.learning)
      smb_learning(SMB_PALL, mac, 3);

    result_final = TEST_PASSED;

    next_testcase(1);
    do {
      t_start = time(NULL);
      if( wrst.permute ) {
        printf("load %3d %3d frame size %4d %4d B...", wrst.ptx[0].fload,
            wrst.ptx[2].fload, wrst.ptx[0].fsize, wrst.ptx[2].fsize);
        fflush(stdout);
        fprintf(logfile, "\nload %3d %3d frame size %4d %4d B...\n", wrst.ptx[0].fload,
            wrst.ptx[2].fload, wrst.ptx[0].fsize, wrst.ptx[2].fsize);
      } else {
        printf("load %3d frame size %4d B...", wrst.ptx[0].fload, wrst.ptx[0].fsize);
        fflush(stdout);
        fprintf(logfile, "\nload %3d frame size %4d B...\n", wrst.ptx[0].fload, wrst.ptx[0].fsize);
      }

      if(wrst.force_prst)
        reset_ports(SMB_PALL);
      run_test(cntrs, mac);
      exp_rx_frames(&wrst, cntrs, exp_rxf);
      fprintf(logfile, "expected RX frames: p0 = %lu, p1 = %lu, p2 = %lu, p3 = %lu\n",
          exp_rxf[0], exp_rxf[1], exp_rxf[2], exp_rxf[3]);
      result = anl_result(cntrs, test_no);
      if(wrst.test_type == TEST_PERFORMANCE)
        show_floss(logfile, cntrs, exp_rxf);

      t_stop = time(NULL);
      /* update final result of the test */
      if ( (result_final == TEST_PASSED) ||
           (result_final == TEST_WARNING && result != TEST_PASSED) ) {
        result_final = result;
        //printf("updating final result to %d\n", result_final);
      }

      switch (result) {
        case TEST_PASSED:
          printf("OK (time %u)\n", (unsigned)(t_stop - t_start));
          fprintf(logfile, "OK (time %u)\n", (unsigned)(t_stop - t_start));
          break;
        case TEST_WARNING:
          printf("WARNING (time %u)\n", (unsigned)(t_stop - t_start));
          fprintf(logfile, "WARNING (time %u)\n", (unsigned)(t_stop - t_start));
          break;
        case TEST_FAILED:
          printf("Failed (time %u)\n", (unsigned)(t_stop - t_start));
          fprintf(logfile, "Failed (time %u)\n", (unsigned)(t_stop - t_start));
          break;
      }

      show_allcntrs(logfile, SMB_PALL, cntrs);
      fflush(logfile);
      //show_allcntrs(stdout, SMB_PALL, cntrs);
      //fflush(stdout);
     
      if(detect_stop() > 0) break;
    } while( next_testcase(0) );
  }

  return result_final;
}
