/*	lac_tx.c   2.02.000 20JUN99 12:19  */

#include "sys.h"
#include "lac_options.h"
#include "lac_types.h"
#include "lac_defaults.h"
#include "lac_machines.h"
/******************************************************************************
 * LAC : LINK AGGREGATION CONTROL PROTOCOL : LACPDU TRANSMISSION
 ******************************************************************************
 */
static void copy_info(Lac_info *from, Lac_info *to)
{/*
  */
   to->port_priority         = from->port_priority;
   to->port_no               = from->port_no;
   to->system_priority       = from->system_priority;
   to->system_id             = from->system_id;
   to->key                   = from->key;
   to->state.lacp_activity   = from->state.lacp_activity;
   to->state.lacp_timeout    = from->state.lacp_timeout;
   to->state.aggregation     = from->state.aggregation;
   to->state.synchronization = from->state.synchronization;
   to->state.collecting      = from->state.collecting;
   to->state.distributing    = from->state.distributing;
   to->state.defaulted       = from->state.defaulted;
   to->state.expired         = from->state.expired;
}
/*---------------------------------------------------------------------------*/
static Boolean tx_lacpdu(Lac_port *port)
{
	Lac_pdu *pdu;
  
   if (sysmalloc(sizeof(Lac_pdu), &pdu))
   {
      copy_info(&port->actor,   &pdu->actor);
      copy_info(&port->partner, &pdu->partner);
 
      sys_tx(&port->mac, pdu);
      sysfree(pdu);
      return(True);
}  }
/*---------------------------------------------------------------------------*/
extern void tx_machine(Lac_port *port, Lac_event event)
{
   switch (event)
   {
   case Lac_init:
   case Lac_port_disabled:
      sys_cstop_timer(&port->tx_scheduler);
      port->ntt        = False;
      port->hold_while = Expired;
      port->hold_count = Zero;
      break;

   case Lac_ntt:
      if ((!port->ntt) && (port->hold_count < Max_tx_per_interval))
         sys_start_timer(&port->tx_scheduler, Lac_tx_scheduling_ticks);

      port->ntt = True;
      break;

   case Lac_tick:
      if (sys_check_expiry(&port->hold_while))
      {
         if (port->ntt && (port->hold_count == Max_tx_per_interval))
            sys_start_timer(&port->tx_scheduler, Lac_tx_scheduling_ticks);

         port->hold_count = Zero;
      }
      break;

   case Lac_txd:
      if (port->ntt && port->lacp_enabled && port->port_enabled &&
         (port->actor.state.lacp_activity || port->partner.state.lacp_activity))
      {
         if (tx_lacpdu(port))
         {
            port->hold_while = Tx_interval_ticks;
            port->hold_count ++;
            port->ntt = False;
         }
         else sys_start_timer(&port->tx_scheduler, Lac_tx_scheduling_ticks);            
      }
      break;
   default:
      break;
}   }
/*---------------------------------------------------------------------------*/
extern void tx_opportunity(Lac_port *port)
{
   tx_machine(port, Lac_txd);
}
/*---------------------------------------------------------------------------*/
extern void periodic_machine(Lac_port *port, Lac_event event)
{
   switch (event)
   {
   case Lac_init:
   case Lac_port_disabled:
      port->periodic_after = Stopped; /* NO_PERIODIC */
      break;

   case Lac_tick:
      if (  (port->port_enabled) && (port->lacp_enabled)
         && (port->actor.state.lacp_activity ||
             port->partner.state.lacp_activity)
         ) /* PERIODIC */
      {
         port->periodic_after +=1;

         if ( (  (port->partner.state.lacp_timeout == Short_timeout)
              && (port->periodic_after             >= Fast_periodic_ticks)
              )
              || (port->periodic_after             >= Slow_periodic_ticks)
            )
         {
            tx_machine(port, Lac_ntt);
            port->periodic_after = Stopped;
         }
         
      }
      else port->periodic_after = Stopped; /* NO_PERIODIC */
      break;

   default:
      break;
}   }
/*---------------------------------------------------------------------------*/
