/*
 * (llc_s_ac.c) - actions performed during sap state transition. 
 *
 * Description :
 *   Functions in this module are implemetation of sap component actions.
 *   Details of actions can be found in IEEE-802.2 standard document.
 *   All functions have one sap 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_S_AC_C


#include <net/cm_types.h>
#include <net/cm_mm.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_s_ev.h>
#include <net/llc_s_ac.h>
#include <net/llc_glob.h>
#include <net/llc_pdu.h>
#include <net/llc_lm.h>
#include <net/lan_hdrs.h>
#include <net/llc_dbg.h>

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


/*
 * Function: sap_action_unit_data_indication
 * 
 * Description:
 *  Received a UI PDU from MAC layer; forward to network layer as a
 *  UNITDATA INDICATION; verify our event is the kind we expect
 */

us16
sap_action_unitdata_indication (sap_t * sap, sap_state_event_t * event)
{
	us16		rc = 1;
	frame_t *	ev_frame = event->data.pdu.frame;

	rc = sap_rtn_pdu (sap, ev_frame,event);
	return (rc);
}


/*
 * Function: sap_action_send_ui
 * 
 * Description:
 *  Sends a UI PDU to the MAC layer in response to a UNITDATA REQUEST
 *  primitive from the network layer. Verifes event is a primitive
 *  type of event. Verify the primitive is a UNITDATA REQUEST.
 */

us16
sap_action_send_ui (sap_t * sap, sap_state_event_t * event)
{
	us16			rc = 1;
	frame_t *		data_frame;
	prim_if_block_t *	prim = (prim_if_block_t *) event->data.prim.data;
	prim_unit_data_t *	prim_data;

	prim_data = (prim_unit_data_t *) &prim->data->udata;
	data_frame = (frame_t *) prim->data->udata.unit;
	rc = pdu_header_init (data_frame, LLC_PDU_TYPE_U,
				prim_data->source_addr.lsap,
				prim_data->dest_addr.lsap, LLC_PDU_CMD);
	if (!rc) {
		rc = pdu_init_as_ui_cmd (data_frame);
		if (!rc) {
			rc = lan_hdrs_init (data_frame, data_frame->mac_type,
					prim_data->source_addr.mac,
					prim_data->dest_addr.mac);
			if (!rc) {
				rc = sap_send_pdu (sap, data_frame);
			}
		}
	}
	return (rc);
}

/*
 * Function: sap_action_send_xid_c
 * 
 * Description:
 *  send a XID command PDU to MAC layer in response to a XID REQUEST
 *  primitive from the network layer. Verify event is a primitive
 *  type event. Verify the primitive is a XID REQUEST.
 */

us16
sap_action_send_xid_c (sap_t * sap, sap_state_event_t * event)
{
	us16			rc = 1;
	frame_t *		pdu_frame;
	prim_if_block_t *	prim = (prim_if_block_t *)
						event->data.prim.data;
	prim_xid_t *		prim_data;

	FDBG_ERR_MSG((KERN_ERR "sap_action_send_xid_c :  called\n"));
	prim_data = (prim_xid_t *) &prim->data->xid;
	rc = frame_pdu_allocate (&pdu_frame);
	if (!rc) {
		pdu_frame->free_frame_flag = YES;
		pdu_frame->data_size = LLC_PDU_LEN_U;
		rc = pdu_header_init (pdu_frame, LLC_PDU_TYPE_U,
				prim_data->source_addr.lsap,
				prim_data->dest_addr.lsap, LLC_PDU_CMD);
		if (!rc) {
			rc = pdu_init_as_xid_cmd (pdu_frame, XID_NULL_CLASS_2, 0);
			if (!rc) {
			rc = lan_hdrs_init (pdu_frame,
				((station_t *) sap->parent_station)->mac_type,
				prim_data->source_addr.mac,
				prim_data->dest_addr.mac);
				if (!rc) {
					rc = sap_send_pdu (sap, pdu_frame);
				}
			}
		}
	}
	return (rc);
}


/*
 * Function: sap_action_send_xid_r
 * 
 * Description:
 *  send XID response PDU to MAC in response to an earlier received
 *  XID command PDU. Verify event is a PDU type event
 */

us16
sap_action_send_xid_r (sap_t * sap, sap_state_event_t * event)
{
	us8		mac_da [MAC_ADDR_LEN],mac_sa[MAC_ADDR_LEN];
	us8		dsap;
	us16		rc = 1;
	frame_t *	ev_frame = event->data.pdu.frame;
	pdu_un_t *	rx_cmd_pdu = (pdu_un_t *) ev_frame->llc_hdr;
	frame_t *	frame; 

	FDBG_ERR_MSG((KERN_ERR "sap_action_send_xid_r :  called\n"));
	rx_cmd_pdu = (pdu_un_t *) ev_frame->llc_hdr;
	pdu_decode_sa (ev_frame, mac_da);
	pdu_decode_da (ev_frame, mac_sa);
	pdu_decode_ssap (ev_frame, &dsap);
	rc = frame_pdu_allocate(&frame);
	if (!rc) {
		frame->dev = ev_frame->dev;
		frame->free_frame_flag = YES;
		rc = pdu_header_init (frame, LLC_PDU_TYPE_U,
				sap->local_dl_addr.lsap, dsap, LLC_PDU_RSP);
		if (!rc) {
			rc = pdu_init_as_xid_rsp (frame, XID_NULL_CLASS_2, 0);
			if (!rc) {
				rc = lan_hdrs_init (frame,
					((station_t *) sap->parent_station)->mac_type,
					mac_sa, mac_da);
				if (!rc) {
					rc = sap_send_pdu (sap, frame);
				}
			}
		}
	} 
	return (rc);
}


/*
 * Function: sap_action_send_test_c
 * 
 * Description:
 *  Send a TEST command PDU to the MAC layer in response to a TEST
 *  REQUEST primitive from the network layer. Verify event is a
 *  primitive type event; verify the primitive is a TEST REQUEST.
 */

us16
sap_action_send_test_c (sap_t * sap, sap_state_event_t * event)
{
	us16			rc = 1;
	frame_t *		pdu_frame;
	prim_if_block_t *	prim = (prim_if_block_t *) event->data.prim.data;
	prim_test_t *		prim_data;

	FDBG_ERR_MSG((KERN_ERR "sap_action_send_test_c :  called\n"));
	prim_data = (prim_test_t *) &prim->data->test;
	pdu_frame = (frame_t *) prim_data->unit;
	pdu_frame->data_size += LLC_PDU_LEN_U;
	rc = pdu_header_init (pdu_frame, LLC_PDU_TYPE_U,
			prim_data->source_addr.lsap,
			prim_data->dest_addr.lsap, LLC_PDU_CMD);
	if (!rc) {
		rc = pdu_init_as_test_cmd (pdu_frame);
		if (!rc) {
			rc = lan_hdrs_init (pdu_frame,
					((station_t *) sap->parent_station)->mac_type,
					prim_data->source_addr.mac,
					prim_data->dest_addr.mac);
			if (!rc) {
				rc = sap_send_pdu (sap, pdu_frame);
			}
		}
	}
	return (rc);
}


us16
sap_action_send_test_r (sap_t * sap, sap_state_event_t * event)
{
	us8			mac_da [MAC_ADDR_LEN],mac_sa [MAC_ADDR_LEN];
	us8			dsap;
	us16			rc = 1;
	frame_t *		ev_frame = event->data.pdu.frame;
	pdu_un_t *		rx_cmd_pdu = (pdu_un_t *) ev_frame->llc_hdr;
	struct sk_buff *	skb;
	frame_t *		frame;

	FDBG_ERR_MSG((KERN_ERR "sap_action_send_test_r :  called\n"));
	rx_cmd_pdu = (pdu_un_t *) ev_frame->llc_hdr;
	pdu_decode_sa (ev_frame, mac_da);
	pdu_decode_da (ev_frame, mac_sa);
	pdu_decode_ssap (ev_frame, &dsap);
	rc = frame_allocate(&frame);
	if (!rc) {
		skb = skb_clone(ev_frame->skb,GFP_ATOMIC);
		frame->skb = skb;
		frame->dev = ev_frame->dev;
		rc = pdu_header_init (frame, LLC_PDU_TYPE_U,
				sap->local_dl_addr.lsap, dsap, LLC_PDU_RSP);
		if (!rc) {
			rc = pdu_init_as_test_rsp (frame, ev_frame);
			if (!rc) {
				rc = lan_hdrs_init (frame,
					((station_t *) sap->parent_station)->mac_type,
					mac_sa, mac_da);
				if (!rc) {
					rc = sap_send_pdu (sap, frame);
				}
			}
		}
	}
	return (rc);
}


/*
 * Functionn: sap_action_report_status
 * 
 * Description:
 *  Report data link status to layer management. Verify our event
 *  is the kind we expect.
 */

us16
sap_action_report_status (sap_t * sap, sap_state_event_t * event)
{
	if (event->type == SAP_EV_TYPE_RPT_STATUS) {
		lm_report_status (LM_COMPONENT_TYPE_SAP, (us32) sap, 
					event->data.rsts.status);
	}
	return (0);
}


/*
 * Function: sap_action_xid_indication
 * 
 * Description:
 *  Send a XID response PDU to the network layer via a XID INDICATION
 *  primitive.
 */

us16
sap_action_xid_indication (sap_t * sap, sap_state_event_t * event)
{
	us16		rc = 1;
	frame_t *	ev_frame = event->data.pdu.frame;

	rc = sap_rtn_pdu (sap, ev_frame, event);
	return (rc);
}


/*
 * Function: sap_action_test_indication
 * 
 * Description:
 *  Send a TEST response PDU to the network layer via a TEST INDICATION
 *  primitive. Verify our event is a PDU type event.
 */

us16
sap_action_test_indication (sap_t * sap, sap_state_event_t * event)
{
	us16		rc = 1;
	frame_t *	ev_frame = event->data.pdu.frame;

	rc = sap_rtn_pdu (sap, ev_frame, event);
	return (rc);
}
