/*
 * (llc_actn.c)-Implemetation of actions of station component of LLC
 * 
 * Description :
 *   Functions in this module are implemetation of station component actions.
 *   Details of actions can be found in IEEE-802.2 standard document.
 *   All functions have one station and one event as input argument. All of 
 *   them return 0 On success and 1 otherwise.
 *
 * Copyright (c) 1997 by Procom Technology,Inc.
 *
 * This program can be redistributed or modified under the terms of the 
 * GNU General Public License as published by the Free Software Foundation.
 * This program is distributed without any warranty or implied warranty
 * of merchantability or fitness for a particular purpose.
 *
 * See the GNU General Public License for more details.
 *
 */


#define LLC_ACTN_C


#include <net/cm_types.h>
#include <net/cm_mm.h>
#include <net/os_if.h>
#include <net/cm_dll.h>
#include <net/cm_frame.h>
#include <net/llc_if.h>
#include <net/llc_sap.h>
#include <net/llc_conn.h>
#include <net/llc_main.h>
#include <net/llc_evnt.h>
#include <net/llc_actn.h>
#include <net/llc_pdu.h>
#include <net/lan_hdrs.h>
#include <net/llc_lm.h>
#include <net/llc_glob.h>
#include <linux/kernel.h>
#include <net/llc_dbg.h>

#ifdef LLC_ACTN_DBG
  #define  DBG_MSG(body) { printk body; }
#else
  #define  DBG_MSG(body)  ;
#endif

static void station_ack_timer_callback (us32 timeout_data);

us16
station_ac_start_ack_timer(station_t * station, station_state_event_t * event)
{
	os_tmr_stop (station->ack_timer);
	os_tmr_set(station->ack_timer,(us32)SECS_TO_CT(ACK_TIME));
	os_tmr_start (station->ack_timer, station_ack_timer_callback, (void *) station);
	station->ack_timer_running = YES;
	return 0;
}



us16
station_ac_set_retry_count_0(station_t * station, station_state_event_t * event)
{
	station->retry_count = 0;
	return 0;
}

us16
station_ac_increment_retry_count_by_1(station_t * station, station_state_event_t * event)
{
	station->retry_count++;
	return 0;
}

us16
station_ac_set_xid_r_count_0(station_t * station, station_state_event_t * event)
{
	station->xid_r_count = 0;
	return 0;
}

us16
station_ac_increment_xid_r_count_by_1(station_t * station, station_state_event_t * event)
{
	station->xid_r_count++;
	return 0;
}

us16
station_ac_send_null_dsap_xid_c (station_t * station,
					station_state_event_t * event)
{
	us16		rc;
	frame_t *	pdu_frame;

	rc = frame_pdu_allocate (&pdu_frame);
	if (!rc) {
		pdu_header_init (pdu_frame, LLC_PDU_TYPE_U,
                                                 0, 0, LLC_PDU_CMD);
		pdu_init_as_xid_cmd (pdu_frame, XID_NULL_CLASS_2, 127);
		lan_hdrs_init (pdu_frame, station->mac_type,
					station->mac_sa, station->mac_sa);
		station_send_pdu (station, pdu_frame);
	}
	return rc;
}



us16
station_ac_send_xid_r(station_t * station, station_state_event_t * event)
{
	us8		mac_da [MAC_ADDR_LEN];
	us8		dsap;
	us16		rc = 1;	/* assume bad event or bad PDU */
	frame_t *	pdu_frame;
	frame_t *	ev_frame = event->data.pdu.frame;

	rc = frame_pdu_allocate (&pdu_frame);
	if (!rc) {
		pdu_frame->dev = ev_frame->dev;
		pdu_decode_sa (ev_frame, mac_da);
		pdu_decode_ssap (ev_frame, &dsap);
		pdu_header_init (pdu_frame, LLC_PDU_TYPE_U,
						0, dsap, LLC_PDU_RSP);
		pdu_init_as_xid_rsp (pdu_frame, XID_NULL_CLASS_2, 127);
		lan_hdrs_init (pdu_frame, station->mac_type,
							station->mac_sa, mac_da);
		station_send_pdu (station, pdu_frame);
	}
	return (rc);
}



us16
station_ac_send_test_r(station_t * station, station_state_event_t * event)
{
	us8		mac_da [MAC_ADDR_LEN];
	us8		dsap;
	us16		rc;
	frame_t *	pdu_frame;
	frame_t *	ev_frame = event->data.pdu.frame;

     	
	rc = frame_pdu_allocate (&pdu_frame);
	if (!rc) {
		pdu_frame->dev = ev_frame->dev;
		pdu_decode_sa (ev_frame, mac_da);
		pdu_decode_ssap (ev_frame, &dsap);
		pdu_header_init (pdu_frame, LLC_PDU_TYPE_U, 0, dsap,
								LLC_PDU_RSP);
       		pdu_init_as_test_rsp (pdu_frame, ev_frame);
		lan_hdrs_init (pdu_frame, station->mac_type, station->mac_sa, 
									mac_da);
		station_send_pdu (station, pdu_frame);
	}
	return (rc);
}



us16
station_ac_report_status(station_t * station, station_state_event_t * event)
{
	if (event->type == STATION_EV_TYPE_RPT_STATUS) {
		lm_report_status (LM_COMPONENT_TYPE_STATION, (us32) station,
						event->data.rsts.status);
	}
	return (0);
}



static void
station_ack_timer_callback (us32 timeout_data)
{
	us16			rc;
	station_t *		station = (station_t *) timeout_data;
	station_state_event_t *	event;

	station->ack_timer_running = NO;
	rc = station_get_event (station, (void **) &event);
	if (!rc) {
		event->type = STATION_EV_TYPE_ACK_TIMER;
		event->data.tmr.timer_specific = NULL;
		station_send_event (station, (void *) event);
	}
	return;
}

