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

#include <asm/byteorder.h>
#include <linux/netdevice.h>
#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_glob.h>
#include <net/llc_c_ev.h>
#include <net/llc_c_ac.h>
#include <net/llc_c_st.h>
#include <net/llc_pdu.h>
#include <net/llc_lm.h>
#include <net/lan_hdrs.h>
#include <net/llc_mac.h>
#include <net/llc_dbg.h>

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


static void conn_pf_cycle_timer_callback (us32 timeout_data);
static void conn_ack_timer_callback (us32 timeout_data);
static void conn_rej_timer_callback (us32 timeout_data);
static void conn_busy_timer_callback (us32 timeout_data);
static us16 conn_ac_increment_vs_by_1 (connection_t *conn, 
					conn_state_event_t *event);
static us16 process_timer_event(connection_t *conn, conn_state_event_t *event);
static us16 conn_ac_data_confirm (connection_t *conn,
					conn_state_event_t *event);

#define INCORRECT 0   


us16 
conn_ac_clear_remote_busy (connection_t *conn, conn_state_event_t *event)
{  
	us8 nr;
	pdu_sn_t *rx_pdu; 

	if (conn->remote_busy_flag == YES) {
		rx_pdu = (pdu_sn_t *) event->data.pdu.frame->llc_hdr;
		conn->remote_busy_flag = NO;
		os_tmr_stop (conn->busy_state_timer);
		conn->busy_state_running = NO;
		nr = LLC_I_GET_NR(rx_pdu);
		conn_resend_i_pdu_as_cmd (conn, nr, 0);
	}
	return (0);
}



us16 
conn_ac_connect_indication (connection_t *conn, conn_state_event_t *event)
{
	us16 rc = 1;             
	frame_t *ev_frame = event->data.pdu.frame;
	prim_data_u *prim_data = Ind_prim.data;
	prim_if_block_t *prim = &Ind_prim;
	sap_t *sap;

	pdu_decode_dsap (ev_frame, &prim_data->conn.dest_addr.lsap);
	rc = llc_sap_find (prim_data->conn.dest_addr.lsap, &sap);
	if (!rc) {
		pdu_decode_sa (ev_frame, conn->remote_dl_addr.mac);
		pdu_decode_da (ev_frame, conn->local_dl_addr.mac);
		conn->local_dev = ev_frame->dev; 
		prim_data->conn.priority = 0;
		prim_data->conn.connect_handle = (us32) conn;
		memcpy (&prim_data->conn.dest_addr, &conn->local_dl_addr,
							sizeof (address_t));
		memcpy (&prim_data->conn.source_addr, &conn->remote_dl_addr,
							sizeof (address_t));
		prim->data = prim_data;
		prim_data->conn.device = ev_frame->dev;
		prim->primitive = CONNECT_PRIM;
		prim->sap = (us32) conn->parent_sap;
		event->flag = YES;
		event->ind_prim = prim;
	}
	return (rc);
}



us16 
conn_ac_connect_confirm (connection_t *conn, conn_state_event_t *event)
{
	prim_data_u *prim_data = Cfm_prim.data;
	prim_if_block_t *prim = &Cfm_prim;
	sap_t *sap;

	sap = (sap_t *)conn->parent_sap;
	prim_data->conn.connect_handle = (us32) conn;
	prim_data->conn.priority = 0;
	prim_data->conn.status = event->status;
	prim_data->conn.link_no = conn->link_no;
	prim->data = prim_data;
	prim->primitive = CONNECT_PRIM;
	prim->sap = (us32) sap;
	event->flag = YES;
	event->cfm_prim = prim;
	return (0);
}



static us16 
conn_ac_data_confirm (connection_t *conn, conn_state_event_t *event)
{
	prim_if_block_t *prim = &Cfm_prim;
	prim_data_u *prim_data = Cfm_prim.data;

	prim_data->data.connect_handle = (us32) conn;
	prim_data->data.priority = 0;
	prim_data->data.link_no = conn->link_no;
	prim_data->data.status = RECEIVED;
	prim_data->data.unit = NULL;
	prim->data = prim_data;
	prim->primitive = DATA_PRIM;
	prim->sap = conn->parent_sap;
	event->flag = YES;
	event->cfm_prim = prim;
	return (0);
}


us16 
conn_ac_data_indication (connection_t *conn, conn_state_event_t *event)
{
	us16 rc = 1;             
	frame_t *ev_frame;
   
	ev_frame = event->data.pdu.frame;
	rc = conn_rtn_pdu (conn, ev_frame, (void *)event);
	if (rc) {
		FDBG_ERR_MSG((KERN_ERR "conn_ac_data_indication : 
							** failed ** \n"));
	}
	return (rc);
}


us16
conn_ac_disconnect_indication (connection_t *conn, conn_state_event_t *event)
{
	us8 reason=0;             
	us16 rc = 1;             
	pdu_un_t *rx_pdu;
	prim_data_u *prim_data = Ind_prim.data;
	prim_if_block_t *prim = &Ind_prim;

	if (event->type == CONN_EV_TYPE_PDU) {
		rx_pdu = (pdu_un_t *) event->data.pdu.frame->llc_hdr;
		if ((!LLC_PDU_IS_RSP(rx_pdu)) &&        
		   (!LLC_PDU_TYPE_IS_U(rx_pdu)) &&      
		   (LLC_U_PDU_RSP(rx_pdu) == LLC_2_PDU_RSP_DM)) {
			reason = DISC_REASON_RX_DM_RSP_PDU;
			rc = 0;
		} else if ((!LLC_PDU_IS_CMD(rx_pdu)) &&     
			   (!LLC_PDU_TYPE_IS_U(rx_pdu)) &&  
			   (LLC_U_PDU_CMD(rx_pdu) == LLC_2_PDU_CMD_DISC)) {
			reason = DISC_REASON_RX_DISC_CMD_PDU;
			rc = 0;
		}
	} else if (event->type == CONN_EV_TYPE_ACK_TIMER) {
		reason = DISC_REASON_ACK_TIMER_EXPIRED;
		rc = 0;
	} else {
		reason = 0;
		rc = 1;
	}

	if (!rc) {   
		prim_data->disc.connect_handle = (us32) conn;
		prim_data->disc.reason = reason;
		prim_data->disc.link_no = conn->link_no;
		prim->data = prim_data;
		prim->primitive = DISCONNECT_PRIM;
		prim->sap = (us32) conn->parent_sap;
		event->flag = YES;
		event->ind_prim = prim;
	}
	return (rc);
}

us16 
conn_ac_disconnect_confirm (connection_t *conn, conn_state_event_t *event)
{
	prim_data_u *prim_data = Cfm_prim.data;
	prim_if_block_t *prim = &Cfm_prim;

	prim_data->disc.connect_handle = (us32) conn;
	prim_data->disc.reason = event->status;
	prim_data->disc.link_no = conn->link_no;
	prim->data = prim_data;
	prim->primitive = DISCONNECT_PRIM;
	prim->sap = (us32) conn->parent_sap;
	event->flag = YES;
	event->cfm_prim = prim;
	return (0);
}



us16
conn_ac_reset_indication (connection_t *conn, conn_state_event_t *event)
{
	us8 reason = 0;             
	us16 rc = 1;            
	pdu_un_t *rx_pdu = (pdu_un_t *) event->data.pdu.frame->llc_hdr;
	prim_data_u *prim_data = Ind_prim.data;
	prim_if_block_t *prim = &Ind_prim;

	switch (event->type) {
		case CONN_EV_TYPE_PDU:
			if ((!LLC_PDU_IS_RSP(rx_pdu)) &&
			    (!LLC_PDU_TYPE_IS_U(rx_pdu)) &&          
			    (LLC_U_PDU_RSP(rx_pdu) == LLC_2_PDU_RSP_FRMR)) {
				reason = RESET_REASON_LOCAL;
				rc = 0;
			} else if ((!LLC_PDU_IS_CMD(rx_pdu)) && 
				   (!LLC_PDU_TYPE_IS_U(rx_pdu)) &&         
				   (LLC_U_PDU_CMD(rx_pdu) == LLC_2_PDU_CMD_SABME)) {
				reason = RESET_REASON_REMOTE;
				rc = 0;
			} else {
				reason = 0;
				rc  = 1;
			}

			break;

		case CONN_EV_TYPE_ACK_TIMER:
		case CONN_EV_TYPE_P_TIMER:
		case CONN_EV_TYPE_REJ_TIMER:
		case CONN_EV_TYPE_BUSY_TIMER:
			if (conn->retry_count > conn->n2) {
				reason = RESET_REASON_LOCAL;
				rc = 0;
			} else {
				rc = 1;
			}
			break;
	}

	if (!rc) {   
		prim_data->res.connect_handle = (us32) conn;
		prim_data->res.reason = reason;
		prim_data->res.link_no = conn->link_no;
		prim->data = prim_data;
		prim->primitive = RESET_PRIM;
		prim->sap = (us32) conn->parent_sap;
		event->flag = YES;
		event->ind_prim = prim;
	}
	return (rc);
}



us16 
conn_ac_reset_confirm (connection_t *conn, conn_state_event_t *event)
{
	prim_data_u *prim_data = Cfm_prim.data;
	prim_if_block_t *prim = &Cfm_prim;

	prim_data->res.connect_handle = (us32) conn;
	prim_data->res.link_no = conn->link_no;
	prim->data = prim_data;
	prim->primitive = RESET_PRIM;
	prim->sap = (us32) conn->parent_sap;
	event->flag = YES;
	event->cfm_prim = prim;
	return (0);
}



us16 
conn_ac_report_status (connection_t *conn, conn_state_event_t *event)
{
//	lm_report_status (LM_COMPONENT_TYPE_CONNECTION, (us32) conn, 0); 
	return (0);
}



us16 
conn_ac_clear_remote_busy_if_f_eq_1 (connection_t *conn,
						 conn_state_event_t *event)
{
	pdu_sn_t *rx_pdu;

	rx_pdu = (pdu_sn_t *) event->data.pdu.frame->llc_hdr;
	if ((!LLC_PDU_IS_RSP(rx_pdu)) &&                 
	    (!LLC_PDU_TYPE_IS_I(rx_pdu)) &&               
	    (!LLC_I_PF_IS_1(rx_pdu)) &&
	    (conn->ack_pf)) {
		conn_ac_clear_remote_busy (conn, event);
	}
	return (0);
}



us16 
conn_ac_stop_rej_timer_if_data_flag_eq_2 (connection_t *conn,
                                                conn_state_event_t *event)
{
	if (conn->data_flag == 2) {
		os_tmr_stop (conn->reject_sent_timer);
		conn->reject_sent_running = NO;
	}
	return (0);   
}



us16 
conn_ac_send_disc_cmd_p_set_x (connection_t *conn,
                                                conn_state_event_t *event)
{
	us8 p_bit = 1;
	us16 rc = 1;
	frame_t *pdu_frame;
	sap_t *sap;

	rc = frame_pdu_allocate (&pdu_frame);
	if (!rc) {
		pdu_frame->dev = conn->local_dev;
		sap = (sap_t *) conn->parent_sap;
		pdu_header_init (pdu_frame, LLC_PDU_TYPE_U,
					sap->local_dl_addr.lsap, 
					conn->remote_dl_addr.lsap, LLC_PDU_CMD);
		pdu_init_as_disc_cmd (pdu_frame, p_bit);
		lan_hdrs_init (pdu_frame,
				((station_t *) sap->parent_station)->mac_type,
				((struct device *)conn->local_dev)->dev_addr,
				conn->remote_dl_addr.mac);
		rc = conn_send_pdu (conn, pdu_frame);
	}
	conn_ac_set_p_flag_1(conn,event);
	return (rc);   
}



us16 
conn_ac_send_dm_rsp_f_set_p (connection_t *conn, conn_state_event_t *event)
{
	us8 f_bit;
	us16 rc = 1;
	frame_t *rx_pdu = event->data.pdu.frame;   
	frame_t *pdu_frame;
	sap_t *sap;

	rc = frame_pdu_allocate (&pdu_frame);
	if (!rc){
		pdu_frame->dev = conn->local_dev;
		sap = (sap_t *) conn->parent_sap;
		pdu_decode_pf_bit (rx_pdu, &f_bit);      
		pdu_header_init (pdu_frame, LLC_PDU_TYPE_U,
					sap->local_dl_addr.lsap, 
					conn->remote_dl_addr.lsap, LLC_PDU_RSP);
		pdu_init_as_dm_rsp (pdu_frame, f_bit);
		lan_hdrs_init (pdu_frame,
				((station_t *) sap->parent_station)->mac_type,
				((struct device *)conn->local_dev)->dev_addr,
				conn->remote_dl_addr.mac);
		rc = conn_send_pdu (conn, pdu_frame);
	}
	return (rc);
}



us16
conn_ac_send_dm_rsp_f_set_1 (connection_t *conn, conn_state_event_t *event)
{
	us8 f_bit;
	us16 rc = 1;
	frame_t *pdu_frame;
	sap_t *sap;

	rc = frame_pdu_allocate (&pdu_frame);
	if (!rc) {
		pdu_frame->dev = conn->local_dev;
		sap = (sap_t *) conn->parent_sap;
		f_bit = 1;
		pdu_header_init (pdu_frame, LLC_PDU_TYPE_U,
					sap->local_dl_addr.lsap, 
					conn->remote_dl_addr.lsap, LLC_PDU_RSP);
		pdu_init_as_dm_rsp (pdu_frame, f_bit);
		lan_hdrs_init (pdu_frame,
				((station_t *) sap->parent_station)->mac_type,
				((struct device *)conn->local_dev)->dev_addr,
				conn->remote_dl_addr.mac);
		rc = conn_send_pdu (conn, pdu_frame);
	} 
	return (rc);
}



us16 
conn_ac_send_dm_rsp_f_set_f_flag (connection_t *conn,
						 conn_state_event_t *event)
{
	us8 f_bit;               
	us16 rc = 1;
	frame_t *pdu_frame;
	sap_t *sap;

	f_bit = conn->f_flag;
	rc = frame_pdu_allocate (&pdu_frame);
	if (!rc){
		pdu_frame->dev = conn->local_dev;
		sap = (sap_t *) conn->parent_sap;
		pdu_header_init (pdu_frame, LLC_PDU_TYPE_U,
					sap->local_dl_addr.lsap, 
					conn->remote_dl_addr.lsap, LLC_PDU_RSP);
		pdu_init_as_dm_rsp (pdu_frame, f_bit);
		lan_hdrs_init (pdu_frame,
				((station_t *) sap->parent_station)->mac_type,
				((struct device *)conn->local_dev)->dev_addr,
				conn->remote_dl_addr.mac);
		rc = conn_send_pdu (conn, pdu_frame);
	}
	return (rc);
}

us16 
conn_ac_send_frmr_rsp_f_set_x (connection_t *conn, conn_state_event_t *event)
{
	us8 f_bit;
	us16 rc = 0;
	pdu_sn_t *rx_pdu;
	frame_t *pdu_frame;
	sap_t *sap;

	rx_pdu = (pdu_sn_t *) event->data.pdu.frame->llc_hdr;
	conn->rx_pdu_hdr = (us32) *((us32 *)rx_pdu);
	if (!LLC_PDU_IS_CMD(rx_pdu)) {                  
		pdu_decode_pf_bit (event->data.pdu.frame, &f_bit);
	} else {
		f_bit = 0;                
	}
	rc = frame_pdu_allocate (&pdu_frame);
	if (!rc) {
		pdu_frame->dev = conn->local_dev;
		sap = (sap_t *) conn->parent_sap;
		pdu_header_init (pdu_frame, LLC_PDU_TYPE_U,
					sap->local_dl_addr.lsap, 
					conn->remote_dl_addr.lsap, LLC_PDU_RSP);
		pdu_init_as_frmr_rsp (pdu_frame, 
					(void *) rx_pdu, f_bit, conn->vS, 
					conn->vR,INCORRECT); 
		lan_hdrs_init (pdu_frame,
				((station_t *) sap->parent_station)->mac_type,
				((struct device *)conn->local_dev)->dev_addr,
				conn->remote_dl_addr.mac);
		rc = conn_send_pdu (conn, pdu_frame);
	}
	return (rc);
}



us16 
conn_ac_resend_frmr_rsp_f_set_0 (connection_t *conn,
                                                conn_state_event_t *event)
{
	us8 f_bit;
	us16 rc = 1;
	frame_t *pdu_frame;
	sap_t *sap;
	pdu_sn_t *rx_pdu = (pdu_sn_t *)&conn->rx_pdu_hdr;

	f_bit = 0;
	rc = frame_pdu_allocate (&pdu_frame);
	if (!rc){   
		pdu_frame->dev = conn->local_dev;
		sap = (sap_t *) conn->parent_sap;
		pdu_header_init (pdu_frame, LLC_PDU_TYPE_U,
					sap->local_dl_addr.lsap, 
					conn->remote_dl_addr.lsap, LLC_PDU_RSP);
		pdu_init_as_frmr_rsp (pdu_frame, rx_pdu, f_bit, conn->vS, 
							conn->vR,INCORRECT);
		lan_hdrs_init (pdu_frame,
				((station_t *) sap->parent_station)->mac_type,
				((struct device *)conn->local_dev)->dev_addr,
				conn->remote_dl_addr.mac);
                 rc = conn_send_pdu (conn, pdu_frame);
	}
	return (rc);
}



us16 
conn_ac_resend_frmr_rsp_f_set_p (connection_t *conn,
                                                conn_state_event_t *event)
{
	us8 f_bit;
	us16 rc = 1;
	pdu_sn_t *rx_pdu = (pdu_sn_t *) event->data.pdu.frame->llc_hdr;
	frame_t *pdu_frame;
	sap_t *sap;

	pdu_decode_pf_bit ((frame_t *)event->data.pdu.frame, &f_bit);
	rc = frame_pdu_allocate (&pdu_frame);
	if (!rc){ 
		pdu_frame->dev = conn->local_dev;
		sap = (sap_t *) conn->parent_sap;
		pdu_header_init (pdu_frame, LLC_PDU_TYPE_U,
					sap->local_dl_addr.lsap, 
					conn->remote_dl_addr.lsap, LLC_PDU_RSP);
		pdu_init_as_frmr_rsp (pdu_frame,
					(void *) rx_pdu, f_bit, conn->vS, 
					conn->vR,INCORRECT);
		lan_hdrs_init (pdu_frame,
				((station_t *) sap->parent_station)->mac_type,
				((struct device *)conn->local_dev)->dev_addr,
				conn->remote_dl_addr.mac);
		rc = conn_send_pdu (conn, pdu_frame);
	}
	return (rc);
}



us16 
conn_ac_send_i_cmd_p_set_1 (connection_t *conn, conn_state_event_t *event)
{
	us8 p_bit;
	us16 rc = 1;
	frame_t *pdu_frame;
	sap_t *sap;

	pdu_frame = (frame_t *) (((prim_if_block_t *)
                               event->data.prim.data)->data->data.unit);
	p_bit = 1;
	sap = (sap_t *) conn->parent_sap;
	pdu_header_init (pdu_frame, LLC_PDU_TYPE_I,
                               sap->local_dl_addr.lsap, 
                               conn->remote_dl_addr.lsap, LLC_PDU_CMD);
	pdu_init_as_i_cmd (pdu_frame, p_bit, conn->vS, conn->vR);
	lan_hdrs_init (pdu_frame,
                           ((station_t *) sap->parent_station)->mac_type,
          	           ((struct device *)conn->local_dev)->dev_addr,
                                                conn->remote_dl_addr.mac);
        rc = conn_send_pdu (conn, pdu_frame);
        if (!rc){
   		conn_ac_increment_vs_by_1(conn,event);
	}
   	return (rc);
}

us16 
conn_ac_send_i_cmd_p_set_0 (connection_t *conn, conn_state_event_t *event)
{
	us8 p_bit;
	us16 rc = 1;
	frame_t *pdu_frame;
	sap_t *sap;

	pdu_frame = (frame_t *) (((prim_if_block_t *)
                               event->data.prim.data)->data->data.unit);
	p_bit = 0;
	sap = (sap_t *) conn->parent_sap;
	pdu_header_init (pdu_frame, LLC_PDU_TYPE_I,
                               sap->local_dl_addr.lsap, 
                               conn->remote_dl_addr.lsap, LLC_PDU_CMD);
	pdu_init_as_i_cmd (pdu_frame, p_bit, conn->vS, conn->vR);
	lan_hdrs_init (pdu_frame,
                           ((station_t *) sap->parent_station)->mac_type,
          	           ((struct device *)conn->local_dev)->dev_addr,
                                                conn->remote_dl_addr.mac);
	rc = conn_send_pdu (conn, pdu_frame);
        if (!rc){
		conn_ac_increment_vs_by_1(conn,event);
	}
	return (rc);
}


us16 
conn_ac_resend_i_cmd_p_set_1 (connection_t *conn, conn_state_event_t *event)
{
us8 nr;
us16 rc;
pdu_sn_t *rx_pdu;

	rx_pdu = (pdu_sn_t *) event->data.pdu.frame->llc_hdr;
	nr = LLC_I_GET_NR(rx_pdu);
	rc = conn_resend_i_pdu_as_cmd (conn, nr, 1);
	return (rc);   
}



us16 
conn_ac_resend_i_cmd_p_set_1_or_send_rr (connection_t *conn,
                                                conn_state_event_t *event)
{
	us8 nr;
	us16 rc = 1;
	pdu_sn_t *rx_pdu = (pdu_sn_t *) event->data.pdu.frame->llc_hdr;

	nr = LLC_I_GET_NR(rx_pdu);
	rc = conn_ac_send_rr_cmd_p_set_1 (conn, event);
	if (!rc) {
		rc = conn_resend_i_pdu_as_cmd (conn, nr, 0);
	}
	return (rc);
}



us16 
conn_ac_send_i_xxx_x_set_0 (connection_t *conn, conn_state_event_t *event)
{
	us8 p_bit;
	us16 rc = 1;
	frame_t *pdu_frame;
	sap_t *sap;
   
	pdu_frame = (frame_t *) (((prim_if_block_t *)
                                event->data.prim.data)->data->data.unit);
	p_bit = 0;
	sap = (sap_t *) conn->parent_sap;
	pdu_header_init (pdu_frame, LLC_PDU_TYPE_I,
                               sap->local_dl_addr.lsap, 
                               conn->remote_dl_addr.lsap, LLC_PDU_CMD);
	pdu_init_as_i_cmd (pdu_frame, p_bit, conn->vS, conn->vR);
	lan_hdrs_init (pdu_frame,
                      ((station_t *) sap->parent_station)->mac_type,
       	              ((struct device *)conn->local_dev)->dev_addr,
                                        conn->remote_dl_addr.mac);
	rc = conn_send_pdu (conn, pdu_frame);
	if (!rc){
		conn_ac_increment_vs_by_1(conn,event);
	}
	return (rc);
}



us16 
conn_ac_resend_i_xxx_x_set_0 (connection_t *conn, conn_state_event_t *event)
{
	us8 nr;
	us16 rc = 1;
	pdu_sn_t *rx_pdu = (pdu_sn_t *) event->data.pdu.frame->llc_hdr;

	nr = LLC_I_GET_NR(rx_pdu);
	rc = conn_resend_i_pdu_as_cmd (conn, nr, 0);
	return (rc);
}



us16 
conn_ac_resend_i_xxx_x_set_0_or_send_rr (connection_t *conn,
                                                conn_state_event_t *event)
{
	us8 nr;
	us8 f_bit = 0;
	us16 rc = 1;
	pdu_sn_t *rx_pdu = (pdu_sn_t *) event->data.pdu.frame->llc_hdr;
	frame_t *pdu_frame;
	sap_t *sap;

	rc = frame_pdu_allocate (&pdu_frame);
	if(!rc){
		pdu_frame->dev = conn->local_dev;
		sap = (sap_t *) conn->parent_sap;
		pdu_header_init (pdu_frame, LLC_PDU_TYPE_U,
                               sap->local_dl_addr.lsap, 
                               conn->remote_dl_addr.lsap, LLC_PDU_RSP);
		pdu_init_as_rr_rsp (pdu_frame, f_bit, conn->vR);
		lan_hdrs_init (pdu_frame,
                           ((station_t *) sap->parent_station)->mac_type,
          	           ((struct device *)conn->local_dev)->dev_addr,
                                               conn->remote_dl_addr.mac);
		rc = conn_send_pdu (conn, pdu_frame);
	}
	if (rc) {
		nr = LLC_I_GET_NR(rx_pdu);
		rc = conn_resend_i_pdu_as_cmd (conn, nr, f_bit);
	}
	return (rc);
}



us16 
conn_ac_resend_i_rsp_f_set_1 (connection_t *conn, conn_state_event_t *event)
{
	us8 nr;
	us16 rc = 1;
	pdu_sn_t *rx_pdu = (pdu_sn_t *) event->data.pdu.frame->llc_hdr;

	nr = LLC_I_GET_NR(rx_pdu);
	rc = conn_resend_i_pdu_as_rsp (conn, nr, 1);
	return (rc);   
}



us16 
conn_ac_send_rej_cmd_p_set_1 (connection_t *conn, conn_state_event_t *event)
{
	us8 p_bit;
	us16 rc = 1;
	frame_t *pdu_frame;
	sap_t *sap;

	p_bit = 1;
	rc = frame_pdu_allocate (&pdu_frame);
	if (!rc) {
		pdu_frame->dev = conn->local_dev;
		pdu_frame->data_size = LLC_PDU_LEN_S;
		sap = (sap_t *) conn->parent_sap;
		rc = pdu_header_init (pdu_frame, LLC_PDU_TYPE_S,
                               sap->local_dl_addr.lsap, 
                               conn->remote_dl_addr.lsap, LLC_PDU_CMD);
		pdu_init_as_rej_cmd (pdu_frame, p_bit, conn->vR);
		lan_hdrs_init (pdu_frame,
	                           ((station_t *) sap->parent_station)->mac_type,
	          	           ((struct device *)conn->local_dev)->dev_addr,
                                                conn->remote_dl_addr.mac);
		rc = conn_send_pdu (conn, pdu_frame);
	}
	return (rc);
}



us16 
conn_ac_send_rej_rsp_f_set_1 (connection_t *conn, conn_state_event_t *event)
{
	us8 f_bit;
	us16 rc = 1;
	frame_t *pdu_frame;
	sap_t *sap;
   
	f_bit = 1;
	rc = frame_pdu_allocate (&pdu_frame);
	if (!rc) {           
		pdu_frame->dev = conn->local_dev;
		sap = (sap_t *) conn->parent_sap;
		pdu_header_init (pdu_frame, LLC_PDU_TYPE_S,
                   	            sap->local_dl_addr.lsap, 
                   	            conn->remote_dl_addr.lsap, LLC_PDU_RSP);
		pdu_init_as_rej_rsp (pdu_frame, f_bit, conn->vR);
		lan_hdrs_init (pdu_frame,
                   	        ((station_t *) sap->parent_station)->mac_type,
          	   	        ((struct device *)conn->local_dev)->dev_addr,
                                               conn->remote_dl_addr.mac);
                rc = conn_send_pdu (conn, pdu_frame);
	}
	return (rc);
}



us16 
conn_ac_send_rej_xxx_x_set_0 (connection_t *conn, conn_state_event_t *event)
{
	us8 f_bit;
	us16 rc = 1;
	frame_t *pdu_frame;
	sap_t *sap;

	f_bit = 0;
	rc = frame_pdu_allocate (&pdu_frame);
	if (!rc) {           
		pdu_frame->dev = conn->local_dev;
		sap = (sap_t *) conn->parent_sap;
		pdu_header_init (pdu_frame, LLC_PDU_TYPE_S,
	                               sap->local_dl_addr.lsap, 
	                               conn->remote_dl_addr.lsap, LLC_PDU_RSP);
		pdu_init_as_rej_rsp (pdu_frame, f_bit, conn->vR);
		lan_hdrs_init (pdu_frame,
                           ((station_t *) sap->parent_station)->mac_type,
          	           ((struct device *)conn->local_dev)->dev_addr,
                                                conn->remote_dl_addr.mac);
		rc = conn_send_pdu (conn, pdu_frame);
	}
	return (rc);
}



us16 
conn_ac_send_rnr_cmd_p_set_1 (connection_t *conn, conn_state_event_t *event)
{
	us8 p_bit;
	us16 rc = 1;
	frame_t *pdu_frame;
	sap_t *sap;

	p_bit = 1;
	rc = frame_pdu_allocate (&pdu_frame);
	if (!rc) {           
		pdu_frame->dev = conn->local_dev;
		sap = (sap_t *) conn->parent_sap;
		pdu_header_init (pdu_frame, LLC_PDU_TYPE_S,
	                               sap->local_dl_addr.lsap, 
	                               conn->remote_dl_addr.lsap, LLC_PDU_CMD);
		pdu_init_as_rnr_cmd (pdu_frame, p_bit, conn->vR);
		lan_hdrs_init (pdu_frame,
                           ((station_t *) sap->parent_station)->mac_type,
          	           ((struct device *)conn->local_dev)->dev_addr,
                                                conn->remote_dl_addr.mac);
		rc = conn_send_pdu (conn, pdu_frame);
	}
	return (rc);
}



us16 
conn_ac_send_rnr_rsp_f_set_1 (connection_t * conn, conn_state_event_t * event)
{
	us8 f_bit;
	us16 rc = 1;
	frame_t *pdu_frame;
	sap_t *sap;

	f_bit = 1;
	rc = frame_pdu_allocate (&pdu_frame);
	if (!rc) {           
		pdu_frame->dev = conn->local_dev;
		sap = (sap_t *) conn->parent_sap;
		pdu_header_init (pdu_frame, LLC_PDU_TYPE_S,
                               sap->local_dl_addr.lsap, 
                               conn->remote_dl_addr.lsap, LLC_PDU_RSP);
		pdu_init_as_rnr_rsp (pdu_frame, f_bit, conn->vR);
		lan_hdrs_init (pdu_frame,
                           ((station_t *) sap->parent_station)->mac_type,
          	           ((struct device *)conn->local_dev)->dev_addr,
                                                conn->remote_dl_addr.mac);
		rc = conn_send_pdu (conn, pdu_frame);
	}
	return (rc);
}



us16
conn_ac_send_rnr_xxx_x_set_0 (connection_t * conn, conn_state_event_t * event)
{
	us8 f_bit;
	us16 rc = 1;
	frame_t *pdu_frame;
	sap_t *sap;

	f_bit = 0;
	rc = frame_pdu_allocate (&pdu_frame);
	if (!rc) {           
		pdu_frame->dev = conn->local_dev;
		sap = (sap_t *) conn->parent_sap;
		pdu_header_init (pdu_frame, LLC_PDU_TYPE_S,
                               sap->local_dl_addr.lsap, 
                               conn->remote_dl_addr.lsap, LLC_PDU_RSP);
		pdu_init_as_rnr_rsp (pdu_frame, f_bit, conn->vR);
		lan_hdrs_init (pdu_frame,
                           ((station_t *) sap->parent_station)->mac_type,
          	           ((struct device *)conn->local_dev)->dev_addr,
                                                conn->remote_dl_addr.mac);
		rc = conn_send_pdu (conn, pdu_frame);
	}
	return (rc);
}



us16 
conn_ac_set_remote_busy (connection_t * conn, conn_state_event_t * event)
{
	if (!conn->remote_busy_flag) {
		conn->remote_busy_flag = YES;
		os_tmr_set (conn->busy_state_timer,(us32)SECS_TO_CT(BUSY_TIME));
		os_tmr_start (conn->busy_state_timer, conn_busy_timer_callback, (void *) conn);
		conn->busy_state_running = YES;

		//lm_report_status (LM_COMPONENT_TYPE_CONNECTION, (us32) conn, 0);
	}
	return (0);
}



us16 
conn_ac_optional_send_rnr_xxx_x_set_0 (connection_t * conn,
                                                conn_state_event_t * event)
{
	us8 f_bit;
	us16 rc = 1;
	frame_t *pdu_frame;
	sap_t *sap;

	f_bit = 0;
	rc = frame_pdu_allocate (&pdu_frame);
	if (!rc) {           
		pdu_frame->dev = conn->local_dev;
		sap = (sap_t *) conn->parent_sap;
		pdu_header_init (pdu_frame, LLC_PDU_TYPE_S,
                               sap->local_dl_addr.lsap, 
                               conn->remote_dl_addr.lsap, LLC_PDU_RSP);
		pdu_init_as_rnr_rsp (pdu_frame, f_bit, conn->vR);
		lan_hdrs_init (pdu_frame,
                           ((station_t *) sap->parent_station)->mac_type,
          	           ((struct device *)conn->local_dev)->dev_addr,
                                                conn->remote_dl_addr.mac);
		rc = conn_send_pdu (conn, pdu_frame);
	}
	return (rc);
}



us16
conn_ac_send_rr_cmd_p_set_1 (connection_t * conn, conn_state_event_t * event)
{
	us8 p_bit;
	us16 rc = 1;
	frame_t *pdu_frame;
	sap_t *sap;

	p_bit = 1;
	rc = frame_pdu_allocate (&pdu_frame);
	if (!rc) {           
		pdu_frame->dev = conn->local_dev;
		sap = (sap_t *) conn->parent_sap;
		pdu_header_init (pdu_frame, LLC_PDU_TYPE_S,
                               sap->local_dl_addr.lsap, 
                               conn->remote_dl_addr.lsap, LLC_PDU_CMD);
		pdu_init_as_rr_cmd (pdu_frame, p_bit, conn->vR);
		lan_hdrs_init (pdu_frame,
                           ((station_t *) sap->parent_station)->mac_type,
          	           ((struct device *)conn->local_dev)->dev_addr,
                                                conn->remote_dl_addr.mac);
		rc = conn_send_pdu (conn, pdu_frame);
	}
	return (rc);
}



us16 
conn_ac_send_ack_cmd_p_set_1 (connection_t * conn, conn_state_event_t * event)
{
	us8 p_bit;
	us16 rc = 1;
	frame_t *pdu_frame;
	sap_t *sap;

	p_bit = 1;
	rc = frame_pdu_allocate (&pdu_frame);
	if (!rc) {   
		pdu_frame->dev = conn->local_dev;
		sap = (sap_t *) conn->parent_sap;
		pdu_header_init (pdu_frame, LLC_PDU_TYPE_S,
                               sap->local_dl_addr.lsap, 
                               conn->remote_dl_addr.lsap, LLC_PDU_CMD);
		pdu_init_as_rr_cmd (pdu_frame, p_bit, conn->vR);
		lan_hdrs_init (pdu_frame,
                       ((station_t *) sap->parent_station)->mac_type,
        	       ((struct device *)conn->local_dev)->dev_addr,
                                               conn->remote_dl_addr.mac);
		rc = conn_send_pdu (conn, pdu_frame);
	}
	return (rc);
}



us16 
conn_ac_send_rr_rsp_f_set_1 (connection_t * conn, conn_state_event_t * event)
{
	us8 f_bit;
	us16 rc = 1;
	frame_t *pdu_frame;
	sap_t *sap;

	f_bit = 1;
	rc = frame_pdu_allocate (&pdu_frame);
	if (!rc) {           
		pdu_frame->dev = conn->local_dev;
		sap = (sap_t *) conn->parent_sap;
		pdu_header_init (pdu_frame, LLC_PDU_TYPE_S,
                                   sap->local_dl_addr.lsap, 
                                   conn->remote_dl_addr.lsap, LLC_PDU_RSP);
		pdu_init_as_rr_rsp (pdu_frame, f_bit, conn->vR);
		lan_hdrs_init (pdu_frame,
                           ((station_t *) sap->parent_station)->mac_type,
          	           ((struct device *)conn->local_dev)->dev_addr,
                                                conn->remote_dl_addr.mac);
		rc = conn_send_pdu (conn, pdu_frame);
	}
	return (rc);
}



us16 
conn_ac_send_ack_rsp_f_set_1 (connection_t * conn, conn_state_event_t * event)
{
	us8 f_bit;
	us16 rc = 1;
	frame_t *pdu_frame;
	sap_t *sap;

	f_bit = 1;
	rc = frame_pdu_allocate (&pdu_frame);
	if (!rc) {   
		pdu_frame->dev = conn->local_dev;
		sap = (sap_t *) conn->parent_sap;
		pdu_header_init (pdu_frame, LLC_PDU_TYPE_S,
                               sap->local_dl_addr.lsap, 
                               conn->remote_dl_addr.lsap, LLC_PDU_RSP);
		pdu_init_as_rr_rsp (pdu_frame, f_bit, conn->vR);
		lan_hdrs_init (pdu_frame,
                       ((station_t *) sap->parent_station)->mac_type,
       	               ((struct device *)conn->local_dev)->dev_addr,
                                                conn->remote_dl_addr.mac);
		rc = conn_send_pdu (conn, pdu_frame);
	}
	return (rc);
}



us16 
conn_ac_send_rr_xxx_x_set_0 (connection_t * conn, conn_state_event_t * event)
{
	us8 f_bit;
	us16 rc = 1;
	frame_t *pdu_frame;
	sap_t *sap;

	f_bit = 0;
	rc = frame_pdu_allocate (&pdu_frame);
	if (!rc) {           
		pdu_frame->dev = conn->local_dev;
		sap = (sap_t *) conn->parent_sap;
		pdu_header_init (pdu_frame, LLC_PDU_TYPE_S,
                                   sap->local_dl_addr.lsap, 
                                   conn->remote_dl_addr.lsap, LLC_PDU_RSP);
		pdu_init_as_rr_rsp (pdu_frame, f_bit, conn->vR);
		lan_hdrs_init (pdu_frame,
                           ((station_t *) sap->parent_station)->mac_type,
          	           ((struct device *)conn->local_dev)->dev_addr,
                                                conn->remote_dl_addr.mac);
		rc = conn_send_pdu (conn, pdu_frame);
	}
	return (rc);
}



us16 
conn_ac_send_ack_xxx_x_set_0 (connection_t * conn, conn_state_event_t * event)
{
	us8 f_bit;
	us16 rc = 1;
	sap_t *sap = (sap_t *) conn->parent_sap;
	frame_t *pdu_frame;

	f_bit = 0;
	rc = frame_pdu_allocate (&pdu_frame);
	if (!rc) {
		pdu_frame->dev = conn->local_dev;
		pdu_header_init (pdu_frame, LLC_PDU_TYPE_S,
                               sap->local_dl_addr.lsap, 
                               conn->remote_dl_addr.lsap, LLC_PDU_RSP);
		pdu_init_as_rr_rsp (pdu_frame, f_bit, conn->vR);
		lan_hdrs_init (pdu_frame,
                           ((station_t *) sap->parent_station)->mac_type,
          	           ((struct device *)conn->local_dev)->dev_addr,
                                            conn->remote_dl_addr.mac);
		rc = conn_send_pdu (conn, pdu_frame);
	}
	return (rc);
}



us16 
conn_ac_send_sabme_cmd_p_set_x (connection_t * conn, conn_state_event_t * event)
{
	us8 p_bit;
	us16 rc = 1;
	frame_t *pdu_frame;
	sap_t *sap;

	p_bit = 1;
	rc = frame_pdu_allocate (&pdu_frame);
	if (!rc) {           
		pdu_frame->dev = conn->local_dev;
		sap = (sap_t *) conn->parent_sap;
		pdu_header_init (pdu_frame, LLC_PDU_TYPE_U,
                                   sap->local_dl_addr.lsap, 
                                   conn->remote_dl_addr.lsap, LLC_PDU_CMD);
		pdu_init_as_sabme_cmd (pdu_frame, p_bit);
		lan_hdrs_init (pdu_frame,
                           ((station_t *) sap->parent_station)->mac_type,
          	           ((struct device *)conn->local_dev)->dev_addr,
                                                conn->remote_dl_addr.mac);
		rc = conn_send_pdu (conn, pdu_frame);
	}
	conn->p_flag = p_bit;
	return (rc);
}



us16 
conn_ac_send_ua_rsp_f_set_f_flag (connection_t * conn, conn_state_event_t * event)
{
	us8 f_bit;
	us16 rc = 1;
	frame_t *pdu_frame;
	sap_t *sap;

	f_bit = conn->f_flag;
	rc = frame_pdu_allocate (&pdu_frame);
	if (!rc){           
		pdu_frame->dev = conn->local_dev;
		sap = (sap_t *) conn->parent_sap;
		pdu_header_init (pdu_frame, LLC_PDU_TYPE_U,
                            sap->local_dl_addr.lsap, 
	                    conn->remote_dl_addr.lsap, LLC_PDU_RSP);
		pdu_init_as_ua_rsp (pdu_frame, f_bit);
		lan_hdrs_init (pdu_frame,
                           ((station_t *) sap->parent_station)->mac_type,
          	           ((struct device *)conn->local_dev)->dev_addr,
                                                conn->remote_dl_addr.mac);
		rc = conn_send_pdu (conn, pdu_frame);
	}
	return (rc);
}



us16 
conn_ac_send_ua_rsp_f_set_p (connection_t * conn, conn_state_event_t * event)
{
	us8 f_bit;
	us16 rc = 1;
	frame_t *rx_pdu;
	frame_t *pdu_frame;
	sap_t *sap;

	rx_pdu = (frame_t *)event->data.pdu.frame;
	pdu_decode_pf_bit (rx_pdu, &f_bit);
	rc = frame_pdu_allocate (&pdu_frame);
	if (!rc) {           
		pdu_frame->dev = conn->local_dev;
		sap = (sap_t *) conn->parent_sap;
		pdu_header_init (pdu_frame, LLC_PDU_TYPE_U,
                               sap->local_dl_addr.lsap, 
                               conn->remote_dl_addr.lsap, LLC_PDU_RSP);
		pdu_init_as_ua_rsp (pdu_frame, f_bit);
		lan_hdrs_init (pdu_frame,
                           ((station_t *) sap->parent_station)->mac_type,
          	           ((struct device *)conn->local_dev)->dev_addr,
                                                conn->remote_dl_addr.mac);
		rc = conn_send_pdu (conn, pdu_frame);
	}
	return (rc);
}



us16 
conn_ac_set_s_flag_0 (connection_t * conn, conn_state_event_t * event)
{
	conn->s_flag = 0;
	return (0);
}



us16 
conn_ac_set_s_flag_1 (connection_t * conn, conn_state_event_t * event)
{
	conn->s_flag = 1;
	return (0);
}



us16 
conn_ac_start_p_timer (connection_t * conn, conn_state_event_t * event)
{
	conn->p_flag = 1;
	os_tmr_stop (conn->pf_cycle_timer);
	os_tmr_set (conn->pf_cycle_timer,(us32)SECS_TO_CT(P_TIME));
	os_tmr_start (conn->pf_cycle_timer, conn_pf_cycle_timer_callback,(void *)conn); 
	conn->pf_cycle_running = YES;
	return (0);
}


/*
 * Function: conn_ac_send_ack_if_needed
 *
 * Description:
 *  Checks number of received PDUs which have not been acknowledged, yet, If 
 *  number of them reaches to "npta"(Number of PDUs To Acknowlege) then sends
 *  an RR response as acknowledgement for them.
 * 
 * Parameters:
 *  connection_t *conn : This argument points to current connection structure.
 *  conn_state_event_t *event : This argument points to current event.
 * 
 * Returns:
 *  0 : success
 *  1 : failure
 */

us16 
conn_ac_send_ack_if_needed (connection_t *conn, conn_state_event_t *event)
{
	us8 pf_bit;
	frame_t *pdu_frame = event->data.pdu.frame;
   
	pdu_decode_pf_bit (pdu_frame, &pf_bit);
	conn->ack_pf|=pf_bit&1 ;
	if (conn->ack_must_be_send == NO) {
		conn->first_pdu_Ns = conn->vR;
		conn->ack_must_be_send = YES;
		conn->ack_pf = pf_bit&1;
	}
	if (((conn->vR - conn->first_pdu_Ns+129)%128) >= conn->npta ) {
		conn_ac_send_rr_rsp_f_set_ackpf(conn,event);
		conn->ack_must_be_send = NO ;
		conn->ack_pf= 0;
		conn_ac_increase_npta_value(conn,event); 
	}
	return (0);
}


/*
 * Function: conn_ac_reset_sendack_flag
 *
 * Description:
 *  This action resets ack_must_be_send flag of given connection, this flag
 *  indicates if there is any PDU which has not been acknowledged yet.
 * 
 * Parameters:
 *  connection_t *conn : This argument points to current connection structure.
 *  conn_state_event_t *event : This argument points to current event.
 * 
 * Returns:
 *  0 : success
 *  1 : failure
 */

us16 
conn_ac_reset_sendack_flag (connection_t * conn, conn_state_event_t * event)
{
	conn->ack_must_be_send = NO;
	conn->ack_pf=0;
	return (0);
}


/*
 * Function: conn_ac_send_i_rsp_f_set_ackpf
 *
 * Description:
 *  Sends an I response PDU with f-bit set to ack_pf flag as acknowledge to 
 *  all received PDUs which have not been acknowledged, yet. ack_pf flag
 *  is set to one if one PDU with p-bit set to one is received.
 * 
 * Parameters:
 *  connection_t *conn : This argument points to current connection structure.
 *  conn_state_event_t *event : This argument points to current event.
 * 
 * Returns:
 *  0 : success
 *  1 : failure
 */

us16 
conn_ac_send_i_rsp_f_set_ackpf (connection_t *conn, conn_state_event_t *event)
{
	us8 p_bit;
	us16 rc = 1;
	frame_t *pdu_frame;
	sap_t *sap;
   
	pdu_frame = (frame_t *) (((prim_if_block_t *)
                                event->data.prim.data)->data->data.unit);
	p_bit = conn->ack_pf;
	sap = (sap_t *) conn->parent_sap;
	pdu_header_init (pdu_frame, LLC_PDU_TYPE_I,
				sap->local_dl_addr.lsap, 
				conn->remote_dl_addr.lsap, LLC_PDU_RSP);
	pdu_init_as_i_cmd(pdu_frame, p_bit, conn->vS, conn->vR);
	lan_hdrs_init (pdu_frame,
			((station_t *) sap->parent_station)->mac_type,
			((struct device *)conn->local_dev)->dev_addr,
				conn->remote_dl_addr.mac);
	rc = conn_send_pdu (conn, pdu_frame);
        if (!rc) {
		conn_ac_increment_vs_by_1(conn, event);
	}
	return (rc);
}


/*
 * Function: conn_ac_send_i_as_ack
 *
 * Description:
 *  This action sends an I-format PDU as acknowledge to received PDUs which 
 *  have not been acknowledged, yet, if there is any. By using of this 
 *  action number of acknowledgements decreases, this technic is called 
 *  pigy backing.
 * 
 * Parameters:
 *  connection_t *conn : This argument points to current connection structure.
 *  conn_state_event_t *event : This argument points to current event.
 * 
 * Returns:
 *  0 : success
 *  1 : failure
 */
 
us16 
conn_ac_send_i_as_ack(connection_t *conn, conn_state_event_t *event)
{
	if (conn->ack_must_be_send == YES) {
		conn_ac_send_i_rsp_f_set_ackpf (conn,event);   
		conn->ack_must_be_send = NO ;
		conn->ack_pf = 0;
	} else
		conn_ac_send_i_cmd_p_set_0 (conn, event);
	return(0);
}


/*
 * Function: conn_ac_send_rr_rsp_f_set_ackpf
 *
 * Description:
 *  This action sends an RR response with f-bit set to ack_pf flag as 
 *  acknowledge to all received PDUs which have not been acknowledged, yet,
 *  if there is any. ack_pf flag indicates if a PDU has been received with 
 *  p-bit set to one. 
 * 
 * Parameters:
 *  connection_t *conn : This argument points to current connection structure.
 *  conn_state_event_t *event : This argument points to current event.
 * 
 * Returns:
 *  0 : success
 *  1 : failure
 */

us16 
conn_ac_send_rr_rsp_f_set_ackpf (connection_t *conn, conn_state_event_t *event)
{
	us8 f_bit;
	us16 rc = 1;
	frame_t *pdu_frame;
	sap_t *sap;

	f_bit = conn->ack_pf;
	rc = frame_pdu_allocate (&pdu_frame);
	if (!rc) {           
		pdu_frame->dev = conn->local_dev;
		sap = (sap_t *) conn->parent_sap;
		pdu_header_init (pdu_frame, LLC_PDU_TYPE_S,
                                   sap->local_dl_addr.lsap, 
                                   conn->remote_dl_addr.lsap, LLC_PDU_RSP);
		pdu_init_as_rr_rsp (pdu_frame, f_bit, conn->vR);
		lan_hdrs_init (pdu_frame,
                           ((station_t *) sap->parent_station)->mac_type,
          	           ((struct device *)conn->local_dev)->dev_addr,
                                                conn->remote_dl_addr.mac);
		rc = conn_send_pdu (conn, pdu_frame);
	}
	return (rc);
}


/*
 * Function: conn_ac_increase_npta_value
 *
 * Description:
 *  After "inc_cntr" times calling of this action, "npta" increase by one.
 *  this action tries to make vale of "npta" greater as possible; number of 
 *  acknowledgements decreases by increasing of "npta".
 * 
 * Parameters:
 *  connection_t *conn : This argument points to current connection structure.
 *  conn_state_event_t *event : This argument points to current event.
 * 
 * Returns:
 *  0 : success
 *  1 : failure
 */

us16 
conn_ac_increase_npta_value (connection_t *conn, conn_state_event_t *event)
{      

	if (conn->inc_cntr == 0) {
		conn->dec_step = NO ;
		conn->dec_cntr = 2;       
		conn->inc_cntr = 2;
		conn->npta = (us8)((conn->npta))+1;
		if (conn->npta > 127) 
			conn->npta = 127 ;
	} else
		conn->inc_cntr -=1;
	return (0) ;
}


/*
 * Function: conn_ac_adjust_npta_by_rr
 *
 * Description:
 *  After receiving "dec_cntr" times RR command, this action decreases "npta"
 *  by one.
 * 
 * Parameters:
 *  connection_t *conn : This argument points to current connection structure.
 *  conn_state_event_t *event : This argument points to current event.
 * 
 * Returns:
 *  0 : success
 *  1 : failure
 */

us16 
conn_ac_adjust_npta_by_rr (connection_t *conn, conn_state_event_t *event)
{
	if ((conn->connect_step == NO) && ( conn->remote_busy_flag == NO )) {
		if (conn->dec_step == NO) 
			if ( conn->dec_cntr == 0  ) { 
				conn->inc_cntr = 2 ; 
				if(conn->npta > 0)
					conn->npta = conn->npta - 1;
				conn->dec_cntr = 2;
			} else 
				conn->dec_cntr -=1; 
	} else 
		conn->connect_step = NO ;
	return(0);
}


/*
 * Function: conn_ac_adjust_npta_by_rnr
 *
 * Description:
 *  After receiving "dec_cntr" times RNR command, this action decreases "npta"
 *  by one.
 * 
 * Parameters:
 *  connection_t *conn : This argument points to current connection structure.
 *  conn_state_event_t *event : This argument points to current event.
 * 
 * Returns:
 *  0 : success
 *  1 : failure
 */

us16 
conn_ac_adjust_npta_by_rnr (connection_t * conn, conn_state_event_t * event)
{
	if ( conn->remote_busy_flag == YES ) {
		if (conn->dec_step == NO) 
			if ( conn->dec_cntr == 0  ) { 
				conn->inc_cntr = 2 ; 
				if(conn->npta > 0)
					conn->npta = conn->npta - 1;
				conn->dec_cntr = 2;
			} else 
				conn->dec_cntr -=1; 
	}
	return(0);
}


/*
 * Function: conn_ac_decrease_transmit_window_size
 *
 * Description:
 *  After receiving of a REJ command or response, transmit window size is
 *  decreased by number of PDUs which are outstanding yet.
 * 
 * Parameters:
 *  connection_t *conn : This argument points to current connection structure.
 *  conn_state_event_t *event : This argument points to current event.
 * 
 * Returns:
 *  0 : success
 *  1 : failure
 */

us16 
conn_ac_decrease_transmit_window_size (connection_t * conn,
                                                conn_state_event_t * event)
{
	us8 unacked_pdu;

	unacked_pdu = dll_query(&conn->pdu_unack_q);
	conn->k -= unacked_pdu ;
	if (conn->k < 2) 
		conn->k = 2 ;
	return(0);
}


/*
 * Function: conn_ac_increase_transmit_window_size
 *
 * Description:
 *  After receiving an RR response with f-bit set to one, transmit window size
 *  is increased by one.
 * 
 * Parameters:
 *  connection_t *conn : This argument points to current connection structure.
 *  conn_state_event_t *event : This argument points to current event.
 * 
 * Returns:
 *  0 : success
 *  1 : failure
 */

us16 
conn_ac_increase_transmit_window_size (connection_t *conn,
                                                conn_state_event_t *event)
{
	conn->k+=1;
	if (conn->k > 128) 
		conn->k = 128 ;
	return(0);
}


us16 
conn_ac_stop_all_timers (connection_t * conn, conn_state_event_t * event)
{
	os_tmr_stop (conn->pf_cycle_timer);
	conn->pf_cycle_running = NO;
	os_tmr_stop (conn->ack_timer);
	conn->ack_running = NO;
	os_tmr_stop (conn->reject_sent_timer);
	conn->reject_sent_running = NO;
	os_tmr_stop (conn->busy_state_timer);
	conn->busy_state_running = NO;
	conn->ack_must_be_send = NO;
	conn->ack_pf=0;
	return (0);
}


us16 
conn_ac_stop_other_timers (connection_t * conn, conn_state_event_t * event)
{
	os_tmr_stop (conn->reject_sent_timer);
	conn->reject_sent_running = NO;
	os_tmr_stop (conn->pf_cycle_timer);
	conn->pf_cycle_running = NO;
	os_tmr_stop (conn->busy_state_timer);
	conn->busy_state_running = NO;
	conn->ack_must_be_send = NO;
	conn->ack_pf=0;
	return (0);
}



us16 
conn_ac_start_ack_timer (connection_t *conn, conn_state_event_t *event)
{
	os_tmr_stop (conn->ack_timer);
	os_tmr_set(conn->ack_timer,(us32)SECS_TO_CT(ACK_TIME));
	os_tmr_start (conn->ack_timer, conn_ack_timer_callback, (void *) conn); 
	conn->ack_running = YES;
	return (0);
}



us16 
conn_ac_start_rej_timer (connection_t *conn, conn_state_event_t *event)
{
	os_tmr_stop (conn->reject_sent_timer);
	os_tmr_set(conn->reject_sent_timer,(us32)SECS_TO_CT(REJ_TIME));
	os_tmr_start (conn->reject_sent_timer, conn_rej_timer_callback, 
                                                            (void *) conn);
	conn->reject_sent_running = YES;
	return (0);
}


us16 
conn_ac_start_ack_timer_if_not_running (connection_t * conn,
                                                conn_state_event_t * event)
{
	if (conn->ack_running == NO) {
		os_tmr_set(conn->ack_timer,(us32)SECS_TO_CT(ACK_TIME));
		os_tmr_start (conn->ack_timer, conn_ack_timer_callback,(void *)conn);
		conn->ack_running = YES;
	}
	return (0);
}



us16 
conn_ac_stop_ack_timer (connection_t * conn, conn_state_event_t * event)
{
	os_tmr_stop (conn->ack_timer);
	conn->ack_running = NO;
	return (0);
}



us16 
conn_ac_stop_p_timer (connection_t * conn, conn_state_event_t * event)
{
	os_tmr_stop (conn->pf_cycle_timer);
	conn->pf_cycle_running = NO;
	conn->p_flag = 0;
	return (0);
}



us16 
conn_ac_stop_rej_timer (connection_t * conn, conn_state_event_t * event)
{
	os_tmr_stop (conn->reject_sent_timer);
	conn->reject_sent_running = NO;
	return (0);
}



us16 
conn_ac_update_nr_received (connection_t * conn, conn_state_event_t * event)
{
	us16 nbr_acked;
	us16 nbr_unack_pdus = 0;
	us8 fbit;
	pdu_sn_t *rx_pdu = (pdu_sn_t *) event->data.pdu.frame->llc_hdr;

	conn->last_nr = PDU_SUPV_GET_Nr(rx_pdu);
	nbr_acked = conn_remove_acked_pdus (conn, conn->last_nr, &nbr_unack_pdus);

        /*
          On loopback we don't queue I frames in unack_pdu_q queue.
        */

	if ( (nbr_acked > 0) || (is_loopback(conn->local_dev) == 0) ) {
		conn->retry_count = 0;
		os_tmr_stop (conn->ack_timer);
		conn->ack_running = NO;
		if (conn->failed_data_req == YES) {
                   /* 
                    * already, we did not accept data from upper layer(tx_window
                    * full or unacceptable state). now, we can send data and
                    * must inform to upper layer.
                    */
			conn->failed_data_req = NO;
			conn_ac_data_confirm(conn, event);
		}
		if (nbr_unack_pdus) {
			os_tmr_set(conn->ack_timer,(us32)SECS_TO_CT(ACK_TIME));
			os_tmr_start (conn->ack_timer, conn_ack_timer_callback, 
                                                            (void *) conn);
			conn->ack_running = YES;
	       }
	} else if (conn->failed_data_req == YES) {
		pdu_decode_pf_bit(event->data.pdu.frame,&fbit); 
		if (fbit == 1) {
			conn->failed_data_req = NO;
			conn_ac_data_confirm(conn, event);
		}
	}

	return (0);
}



us16 
conn_ac_update_p_flag (connection_t * conn, conn_state_event_t * event)
{
	pdu_sn_t *rx_pdu = (pdu_sn_t *) event->data.pdu.frame->llc_hdr;
	us8 f_bit;

	if ((!LLC_PDU_IS_RSP(rx_pdu)) &&           
	     !pdu_decode_pf_bit (event->data.pdu.frame, &f_bit) &&
	     f_bit) {
		conn->p_flag = 0;
		conn_ac_stop_p_timer (conn, event);
	}
	return (0);
}



us16 
conn_ac_set_data_flag_2 (connection_t * conn, conn_state_event_t * event)
{
	conn->data_flag = 2;
	return (0);
}



us16 
conn_ac_set_data_flag_0 (connection_t * conn, conn_state_event_t * event)
{
	conn->data_flag = 0;
	return (0);
}



us16 
conn_ac_set_data_flag_1 (connection_t * conn, conn_state_event_t * event)
{
	conn->data_flag = 1;
	return (0);
}



us16 
conn_ac_set_data_flag_1_if_data_flag_eq_0 (connection_t * conn,
                                                conn_state_event_t * event)
{
	if (conn->data_flag == 0) {
		conn->data_flag = 1;
	}
	return (0);
}



us16 
conn_ac_set_p_flag_0 (connection_t * conn, conn_state_event_t * event)
{
	conn->p_flag = 0;
	return (0);
}

us16 
conn_ac_set_p_flag_1 (connection_t * conn, conn_state_event_t * event)
{
	conn->p_flag = 1;
	return (0);
}

us16 
conn_ac_set_p_flag_p (connection_t * conn, conn_state_event_t * event)
{
	us8 p_bit;

	pdu_decode_pf_bit (event->data.prim.data, &p_bit); 
	conn->p_flag = p_bit;
	return (0);
}



us16
conn_ac_set_remote_busy_0 (connection_t * conn, conn_state_event_t * event)
{
	conn->remote_busy_flag = 0;
	return (0);
}

us16 
conn_ac_set_cause_flag_0 (connection_t * conn, conn_state_event_t * event)
{
	conn->cause_flag = 0;
	return (0);
}

us16 
conn_ac_set_cause_flag_1 (connection_t * conn, conn_state_event_t * event)
{
	conn->cause_flag = 1;
	return (0);
}


us16 
conn_ac_set_retry_count_0 (connection_t * conn, conn_state_event_t * event)
{
	conn->retry_count = 0;
	return (0);
}



us16 
conn_ac_increment_retry_count_by_1 (connection_t * conn,
                                                conn_state_event_t * event)
{
	conn->retry_count++;
	return (0);
}



us16 
conn_ac_set_vr_0 (connection_t * conn, conn_state_event_t * event)
{
	conn->vR = 0;
	return (0);
}



us16 
conn_ac_increment_vr_by_1 (connection_t * conn, conn_state_event_t * event)
{
	conn->vR = PDU_GET_NEXT_Vr(conn->vR);
	return (0);
}



us16 
conn_ac_set_vs_0 (connection_t * conn, conn_state_event_t * event)
{
	conn->vS = 0;
	return (0);
}



us16 
conn_ac_set_vs_nr (connection_t * conn, conn_state_event_t * event)
{
	conn->vS = conn->last_nr;
	return (0);
}

us16 
conn_ac_increment_vs_by_1 (connection_t * conn, conn_state_event_t * event)
{
	conn->vS = (conn->vS + 1) % 128;
	return (0);
}


us16
conn_ac_set_f_flag_p (connection_t * conn, conn_state_event_t * event)
{
	pdu_decode_pf_bit (event->data.pdu.frame, &conn->f_flag);
	return (0);
}


void 
conn_pf_cycle_timer_callback (us32 timeout_data)
{
	us16 rc;
	connection_t *conn = (connection_t *) timeout_data;
	conn_state_event_t *event;

	conn->pf_cycle_running = NO;
	rc = conn_get_event (conn, (void **) &event);
	if (!rc) {
		event->type = CONN_EV_TYPE_P_TIMER;
		event->data.tmr.timer_specific = NULL;
		process_timer_event(conn, event);
	}
}



static void 
conn_busy_timer_callback (us32 timeout_data)
{
	us16 rc;
	connection_t *conn = (connection_t *) timeout_data;
	conn_state_event_t *event;

	conn->busy_state_running = NO;
	rc = conn_get_event (conn, (void **) &event);
	if (!rc) {
		event->type = CONN_EV_TYPE_BUSY_TIMER;
		event->data.tmr.timer_specific = NULL;
		process_timer_event(conn, event);
	}
}



void 
conn_ack_timer_callback (us32 timeout_data)
{
	us16 rc;
	connection_t *conn = (connection_t *) timeout_data;
	conn_state_event_t *event;

	conn->ack_running = NO;
	rc = conn_get_event (conn, (void **) &event);
	if (!rc) {
		event->type = CONN_EV_TYPE_ACK_TIMER;
		event->data.tmr.timer_specific = NULL;
		process_timer_event(conn, event);
	}
}



static void 
conn_rej_timer_callback (us32 timeout_data)
{
	us16 rc;
	connection_t *conn = (connection_t *) timeout_data;
	conn_state_event_t *event;

	conn->reject_sent_running = NO;
	rc = conn_get_event (conn, (void **) &event);
	if (!rc) {
		event->type = CONN_EV_TYPE_REJ_TIMER;
		event->data.tmr.timer_specific = NULL;
		process_timer_event(conn, event);
	}
}

us16 
conn_ac_reset_vs(connection_t *conn, conn_state_event_t *event)
{
	conn->X = conn->vS;
	conn_ac_set_vs_nr(conn,event);
	return 0;
}

us16 conn_ac_update_vs(connection_t *conn, conn_state_event_t *event)
{
	us8 nr;
	pdu_sn_t *rx_pdu = (pdu_sn_t *) event->data.pdu.frame->llc_hdr;

	nr = PDU_SUPV_GET_Nr(rx_pdu);
	if ( circular_between(conn->vS, nr, conn->X) )
		conn_ac_set_vs_nr(conn,event);
	return 0;
}

/* 
 * non-standard actions; these not contained in IEEE specification; for
 * our own usage
 */


/*
 * Function : 
 *  conn_disconnect 
 * Description : 
 *  this function removes connection from list of it's SAP and
 *  returnes it to connection pool.
 * Parameters :
 *  connection_t *conn : closed connection.
 *  conn_stat_event_t *event : occured event. 
 * Returns : 
 *  always 0.
 */
us16
conn_disconnect (connection_t * conn, conn_state_event_t * event)
{
	sap_unassign_conn ((sap_t *) conn->parent_sap, (void *) conn);
	llc_connection_rtn (conn);
	return (0);
}

/*
 * Function : 
 *  conn_reset 
 * Description : 
 *  this function stop all timers, empty all queues and reset all flags. 
 * Parameters :
 *  connection_t *conn : reseting connection.
 *  conn_stat_event_t *event : occured event. 
 * Returns : 
 *  always 0.
 */

us16 
conn_reset (connection_t * conn, conn_state_event_t * event)
{
	llc_connection_reset (conn);
	return (0);
}

/*
 * Function : 
 *  circular_between 
 * Description : 
 *  This function designates that b is between a and c or not (for example,
 *  0 is between 127 and 1). 
 * Parameters :
 *  a,b,c : three number (unsigned char) between 0 and 255.
 * Returns : 
 *  1 : if b is between a and c.
 *  0 : otherwise
 */
us8
circular_between(us8 a, us8 b, us8 c)
{
	b = b-a;
	c = c-a;
	return ( b<=c);
}
/*
 * Function : 
 *  process_timer_event 
 * Description : 
 *  This function is called from timer callback functions. 
 *  When connection is busy (during sending a data frame) timer expiration event
 *  must queued. otherwise this event can be sent to connection state machine. 
 *  queued events will process by process_rxframes_events function after sending
 *  data frame.
 * Parameters :
 *  connection_t *conn : active connection.
 *  conn_stat_event_t *event : occured event.  
 * Returns : 
 *  1 : failure.
 *  0 : succes.
 */
static us16
process_timer_event(connection_t *conn, conn_state_event_t *event)
{ 
	rx_object_t *rx_obj;
	us16 rc=0;

	if ( conn->state  == CONN_OUT_OF_SVC ){
		printk("timer called on closed connection\n");
		conn_return_event (conn, (void *)event);  
		return 0;		
	}
	if ( conn->busy > 0 ) {
		rx_obj = (rx_object_t *) kmalloc (sizeof(rx_object_t),
								GFP_ATOMIC); 
		if (rx_obj) {
			rx_obj->desc = EVENT;
			rx_obj->obj.event = event;
			dll_add (&conn->log_q, (void *)event, DLL_WHERE_TAIL);
		} else {
			FDBG_ERR_MSG(("\np_timer_callback : can't allocate 
								memory\n"));
			conn_return_event (conn, (void *)event);  
			rc = 1;
		}
	} else {
		rc = conn_send_event (conn, (void *) event);
	}
	return (rc);
}






