/*
 *	LAPB processing machine derived from code that is
 *
 *
 * Copyright (c) University of British Columbia, 1984
 * Copyright (c) 1990 The Regents of the University of California.
 * All rights reserved.
 *
 * This code is derived from software contributed to Berkeley by
 * the Laboratory for Computation Vision and the Computer Science Department
 * of the University of British Columbia.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed by the University of
 *	California, Berkeley and its contributors.
 * 4. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 *	@(#)hd_input.c	7.7 (Berkeley) 5/29/91
 */

#include <linux/config.h>
#ifdef CONFIG_AX25
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
#include <linux/in.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/string.h>
#include <linux/sockios.h>
#include <linux/net.h>
#include "ax25.h"
#include <linux/inet.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include "sock.h"
#include "ip.h"			/* For ip_rcv */
#include <asm/segment.h>
#include <asm/system.h>
#include <linux/fcntl.h>
#include <linux/mm.h>
#include <linux/interrupt.h>

/*
 *      HDLC INPUT INTERFACE
 *
 *      This routine is called when the HDLC physical device has
 *      completed reading a frame.
 */


/* Higher level upcall for a LAPB frame */

int ax25_process_rx_frame(ax25_socket *sk, sk_buff *skb, int type)
{
	int queued = FALSE, frametype, pf;
	struct Hdlc_frame *frame;

	frame = (struct Hdlc_frame *)(skb->h.raw);
	pf = ((struct Hdlc_iframe *) frame) -> pf;

	if(sk->debug)
		printk("Sock: %p(st %d) Received: pf=%d, type=%d, class=%d.\n",
			sk,sk->opt.ax25.state,pf,type, ax25_decode(sk,frame));
	switch ((frametype = ax25_decode (sk, frame)) + sk->opt.ax25.state) 
	{
	case DM + DISC_SENT:
	case UA + DISC_SENT:
		/*
		 * Link now closed.
		 */
		sk->opt.ax25.state = DISCONNECTED;
		sk->state = TCP_CLOSE;
		if(!sk->dead)
			sk->state_change(sk);
		break;

	case DM + INIT:
	case UA + INIT:
		/*
		 *	Spurious junk while initialising a connection. 
		 */
		/* Unexpected gunk while setting up: Just ignore it */
		SET_TIMER (sk);
		break;

	case SABM + DM_SENT: 
	case SABM + WAIT_SABM: 
		ax25_write_internal (sk, UA, pf, C_RESPONSE);
	case UA + SABM_SENT: 
	case UA + WAIT_UA: 
		KILL_TIMER (sk);
		ax25_init_vars (sk);
		sk->opt.ax25.state = ABM;
		/* Connected... */
		sk->state=TCP_ESTABLISHED;
		/* For WAIT_SABM connections we will produce an accept ready socket here */
		if(!sk->dead)
			sk->state_change(sk);
		break;

	case SABM + SABM_SENT: 
		/* Got a SABM collision. Acknowledge the remote's SABM
		   via UA but still wait for UA. */
		ax25_write_internal (sk, UA, pf, C_RESPONSE);
		break;

	case SABM + ABM: 
		/* Request to reset the link from the remote. */
		KILL_TIMER (sk);
#ifdef HDLCDEBUG
		hd_dumptrace (sk);
#endif
/*		hd_flush (sk->hd_ifp);*/
		ax25_write_internal (sk, UA, pf, C_RESPONSE);
		ax25_init_vars (sk);
		/* Link down and up again */
		sk->state=TCP_CLOSE;
		sk->err=ECONNRESET;
		if(!sk->dead)
			sk->state_change(sk);
		/* This bit is hard. Look for a new socket to connect to - ie find the socket */
		/* FIXME.. */
		break;

	case SABM + WAIT_UA: 
		ax25_write_internal (sk, UA, pf, C_RESPONSE);
		break;

	case DM + ABM: 
#ifdef HDLCDEBUG
		hd_dumptrace (hdp);
#endif
/*		hd_flush (sk->hd_ifp);*/
	case DM + DM_SENT: 
	case DM + WAIT_SABM: 
	case DM + WAIT_UA: 
		sk->opt.ax25.state=DISCONNECTED;
		sk->state = TCP_CLOSE;
		sk->err = ECONNRESET;
		if(!sk->dead)
			sk->state_change(sk);
		SET_TIMER (sk);
		break;

	case DISC + INIT:
	case DISC + DM_SENT: 
	case DISC + SABM_SENT: 
		/* Note: This is a non-standard state change. */
		ax25_write_internal (sk, UA, pf,C_RESPONSE);
		sk->opt.ax25.state = DISCONNECTED;
		SET_TIMER (sk);
		break;

	case DISC + WAIT_UA: 
		ax25_write_internal(sk, DM, pf, C_RESPONSE);
		SET_TIMER (sk);
		sk->opt.ax25.state = DM_SENT;
		sk->state = TCP_CLOSE;
		break;

	case DISC + ABM: 
		sk->state=TCP_CLOSE;
		sk->shutdown|=RCV_SHUTDOWN;
		sk->err=0;
		if(!sk->dead)
			sk->state_change(sk);
		ax25_write_internal(sk,UA,pf,C_RESPONSE);
		sk->opt.ax25.state = DISCONNECTED;
		SET_TIMER(sk);
		break;
		
	case DISC + WAIT_SABM: 
		/* Waiting for a connect got a DISC.. shrug harmless */
		ax25_write_internal (sk, DM, pf, C_RESPONSE);
		SET_TIMER (sk);
		break;

	case UA + ABM: 
		if(sk->opt.ax25.condition&HAS_ACKED_DATA)
		{
			sk->state=TCP_CLOSE;
			sk->err=ECONNRESET;
			if(!sk->dead)
				sk->state_change(sk);		/* So they see the bad news */
		}
		else
			break;		/* Just a repeated UA at connect time. Hide the details and let our timers
					   sort it out. This fits the connect() semantics better than the more 
					   obvious definition. */
						
	case UA + WAIT_SABM: 
		ax25_write_internal (sk, DM, pf, C_RESPONSE);
		sk->opt.ax25.state = DM_SENT;
		SET_TIMER (sk);
		break;

	case FRMR + DM_SENT: 
		sk->opt.ax25.state = DISCONNECTED;
		SET_TIMER (sk);
		break;

	case FRMR + WAIT_SABM: 
		ax25_write_internal (sk, DM, pf, C_RESPONSE);
		SET_TIMER (sk);
		break;

	case FRMR + ABM: 
		if(sk->debug)
			printk("FRMR received: Linked killed.\n");
		ax25_write_internal(sk, DISC, pf, C_COMMAND);
		sk->opt.ax25.state = DISCONNECTED;
		sk->state=TCP_CLOSE;
		sk->err=EPROTO;	/* Protocol error - boom!! */
		SET_TIMER (sk);
		break;

	case RR + ABM: 
	case RNR + ABM: 
	case REJ + ABM: 
		ax25_rx_sframe(sk, (struct Hdlc_sframe *)frame, frametype, type);
		break;

	case IFRAME + ABM: 
		queued = ax25_rx_iframe(sk, skb, (struct Hdlc_iframe *)frame);
		break;

	case IFRAME + SABM_SENT: 
	case RR + SABM_SENT: 
	case RNR + SABM_SENT: 
	case REJ + SABM_SENT: 
		ax25_write_internal (sk, DM, POLLON, C_RESPONSE);
		SET_TIMER (sk);
		break;

	case IFRAME + WAIT_SABM: 
	case RR + WAIT_SABM: 
	case RNR + WAIT_SABM: 
	case REJ + WAIT_SABM: 
		ax25_write_internal (sk, DM, POLLOFF, C_RESPONSE);
		SET_TIMER (sk);
		break;

	case ILLEGAL + SABM_SENT: 
		ax25_write_internal (sk, DM, POLLOFF, C_RESPONSE);
		sk->opt.ax25.state = DM_SENT;
		SET_TIMER (sk);
		break;

	case ILLEGAL + ABM: 
	case ILLEGAL + WAIT_SABM:
		ax25_write_internal (sk, FRMR, POLLOFF, C_RESPONSE);
		sk->opt.ax25.state = DISCONNECTED;
		sk->state = TCP_CLOSE;
		sk->err = EPROTO;
		if(!sk->dead)
		{
			sk->error_report(sk);
			sk->state_change(sk);
		}
		SET_TIMER (sk);
		break;
	}

	return (queued);
}

int ax25_rx_iframe(ax25_socket *sk, sk_buff *skb, struct Hdlc_iframe *frame)
{
	int    nr = frame -> nr,
	       ns = frame -> ns,
	       pf = frame -> pf;
	int    queued = FALSE;

	/* 
	 *  Validate the iframe's N(R) value. It's N(R) value must be in
	 *   sync with our V(S) value and our "last received nr".
	 */
	if(sk->debug)
		printk("I Frame received: NR=%d NS=%d\n",nr,ns);

	if (valid_nr (sk, nr, FALSE) == FALSE) {
		ax25_send_frmr(sk, Z, frame);
		return (queued);
	}


	/* 
	 *  This section tests the IFRAME for proper sequence. That is, it's
	 *  sequence number N(S) MUST be equal to V(S).
	 */

	if (ns != sk->opt.ax25.vr) {
		if (pf || (sk->opt.ax25.condition & REJ_CONDITION) == 0) {
			sk->opt.ax25.condition |= REJ_CONDITION;
			/*
			 * Flush the transmit queue. This is ugly but we
			 * have no choice.  A reject response must be
			 * immediately sent to the DCE.  Failure to do so
			 * may result in another out of sequence iframe
			 * arriving (and thus sending another reject)
			 * before the first reject is transmitted. This
			 * will cause the DCE to receive two or more
			 * rejects back to back, which must never happen.
			 */
/*			hd_flush (sk->hd_ifp);*/
			ax25_write_internal (sk, REJ, pf, C_RESPONSE);
		}
		return (queued);
	}
	sk->opt.ax25.condition &= ~REJ_CONDITION;

	/* 
	 *  This section finally tests the IFRAME's sequence number against
	 *  the window size (K)  and the sequence number of the  last frame
	 *  we have acknowledged.  If the IFRAME is completely correct then 
	 *  it is queued for the packet level.
	 */

	if (ns != (sk -> opt.ax25.lasttxnr + /*8*/7/*hdp -> hd_xcp -> xc_lwsize*/) % MODULUS) {
		sk -> opt.ax25.vr = (sk -> opt.ax25.vr + 1) % MODULUS;
		if (pf == 1) 
		{
			/* Must generate a RR or RNR with final bit on. */
			ax25_write_internal (sk, RR, POLLON, C_RESPONSE);
		} 
		else
		{
			unsigned long flags;
			save_flags(flags);
			cli();
			/*    
			 *  Hopefully we can piggyback the RR, if not we will generate
			 *  a RR when T1 timer expires.
			 */
			if (sk -> opt.ax25.rrtimer == 0)
				sk->opt.ax25.rrtimer = sk->opt.ax25.t1;
			
			restore_flags(flags);
		}
			/*ax25_write_internal(sk,RR,POLLOFF,C_RESPONSE);*/
		/* Forward iframe to layer above */
		/* Alloc a handle mark it for restore build a new rxbufdescr
		   from the supplied one removing the LAPB header, kick it
		   upstairs */
		   
#ifdef CONFIG_NETROM
		if(frame->address==AX25_P_NETROM)
			queued=nr_rx_iframe(skb);
#endif
#ifdef CONFIG_INET
#ifdef CONFIG_NETROM
		else
#endif
   	        if(frame->address==AX25_P_IP)
		{
			skb->h.raw=((char *)(frame))+2;
			skb->len-=2;
#ifdef FIXME			
			ip_rcv(skb,skb->dev,NULL);	/* Wrong ptype */
#endif			
			queued=FALSE;
		}
#endif		
#if defined(CONFIG_INET) || defined(CONFIG_NETROM)
		else
#endif		
		{		
			sk->rmem_alloc+=skb->mem_len;
			skb->sk=sk;
			skb_queue_tail(&sk->receive_queue,skb);
			if(!sk->dead)
				sk->data_ready(sk,skb->len-2);
			queued=TRUE;
		}

		/* Ought to check the memory and switch to RNR's when we
		   add to the state machine */

		ax25_kick(sk);	/* Send more back */
	} 
	else 
	{
		/* 
		 *  Here if the remote station has transmitted more iframes then
		 *  the number which have been acknowledged plus K. 
		 */
		ax25_send_frmr(sk, W, frame);
	}
	return (queued);
}

/* 
 *  This routine is used to determine if a value (the middle parameter)
 *  is between two other values. The low value is  the first  parameter
 *  the high value is the last parameter. The routine checks the middle
 *  value to see if it is within the range of the first and last values.
 *  The reason we need this routine is the values are modulo some  base
 *  hence a simple test for greater or less than is not sufficient.
 */

bool
range_check (int rear, int value, int front)
{
	bool result = FALSE;

	if (front > rear)
		result = (rear <= value) && (value <= front);
	else
		result = (rear <= value) || (value <= front);

	return (result);
}

/* 
 *  This routine handles all the frame reject conditions which can
 *  arise as a result  of secondary  processing.  The frame reject
 *  condition Y (frame length error) are handled elsewhere.
 */


void ax25_send_frmr(ax25_socket *sk, int rejectcode, struct Hdlc_iframe *frame)
{
	struct Frmr_frame *frmr = &ax25_frmr;

	frmr -> frmr_control = ((struct Hdlc_frame *) frame) -> control;

	frmr -> frmr_ns = frame -> ns;
	frmr -> frmr_f1_0 = 0;
	frmr -> frmr_nr = frame -> nr;
	frmr -> frmr_f2_0 = 0;

	frmr -> frmr_0000 = 0;
	frmr -> frmr_w = frmr -> frmr_x = frmr -> frmr_y =
		frmr -> frmr_z = 0;
	switch (rejectcode) {
	case Z: 
		frmr -> frmr_z = 1;/* invalid N(R). */
		break;

	case Y: 
		frmr -> frmr_y = 1;/* iframe length error. */
		break;

	case X: 
		frmr -> frmr_x = 1;/* invalid information field. */
		frmr -> frmr_w = 1;
		break;

	case W: 
		frmr -> frmr_w = 1;/* invalid N(S). */
	}

	if(sk->debug)
		printk("FRMR!\n");
	ax25_write_internal (sk, FRMR, POLLOFF, C_RESPONSE);
	sk->opt.ax25.state = DISCONNECTED;
	sk->err = EPROTO;
	sk->state = TCP_CLOSE;
	if(!sk->dead)
		sk->state_change(sk);
	SET_TIMER (sk);
}

/* 
 *  This procedure is invoked when ever we receive a supervisor
 *  frame such as RR, RNR and REJ. All processing for these
 *  frames is done here.
 */

void ax25_rx_sframe (ax25_socket *sk, struct Hdlc_sframe *frame, int frametype, int type)
{
	int nr = frame -> nr, pf = frame -> pf, pollbit = 0;

	if (valid_nr (sk, nr, pf) == TRUE) {
		switch (frametype) {
		case RR: 
			sk->opt.ax25.condition &= ~REMOTE_RNR_CONDITION;
		/*	sk->opt.ax25.retxcnt = 0; ADDED AC */
			break;

		case RNR: 
			sk->opt.ax25.condition |= REMOTE_RNR_CONDITION;
			sk->opt.ax25.retxcnt = 0;
			break;

		case REJ: 
			sk->opt.ax25.condition &= ~REMOTE_RNR_CONDITION;
		/*	sk->ax25_retxcnt = 0;	ADDED AC */
			ax25_reject(sk, nr);
		}

		if (pf == 1) {	/* Wants a reply */
			sk->opt.ax25.retxcnt = 0;
			sk->opt.ax25.condition &= ~TIMER_RECOVERY_CONDITION;
#if 0
			if (frametype == RR  && sk->opt.ax25.lastrxnr == sk->opt.ax25.vs
				&& sk->opt.ax25.timer == 0 && skb_peek(&sk->wfront) == NULL)
				ax25_write_internal(sk, RR, pf, C_RESPONSE);
			else
#endif			
			ax25_write_internal(sk,RR,pf,C_RESPONSE);

			/* If any iframes have been queued because of the
			   timer condition, transmit then now. */
			if (sk->opt.ax25.condition & REMOTE_RNR_CONDITION) {
				/* Remote is busy or timer condition, so only
				   send one. */
				if (sk->opt.ax25.vs != sk->opt.ax25.retxqi)
					ax25_send_iframe(sk,sk->opt.ax25.retxq[(int)sk->opt.ax25.vs], pollbit);
			}
			else	/* Flush the retransmit list first. */
				while (sk->opt.ax25.vs != sk->opt.ax25.retxqi)
					ax25_send_iframe(sk, sk->opt.ax25.retxq[(int)sk->opt.ax25.vs], POLLOFF);
		}

		ax25_kick(sk);
	} else
		ax25_send_frmr(sk, Z, (struct Hdlc_iframe *)frame);	/* Invalid N(R). */
}

/* 
 *  This routine tests the validity of the N(R) which we have received.
 *  If it is ok,  then all the  iframes which it acknowledges  (if any)
 *  will be freed.
 */

bool
valid_nr (ax25_socket *sk, int nr, int finalbit)
{
	/* Make sure it really does acknowledge something. */
	
	if (sk->debug)
		printk("valid_nr entered: nr=%d ax25_vs=%d\n",nr,(int)sk->opt.ax25.vs);
	if (sk->opt.ax25.lastrxnr == nr)
		return (TRUE);

	/* 
	 *  This section validates the frame's  N(R) value.  It's N(R) value
	 *  must be  in syncronization  with  our V(S)  value and  our "last
	 *  received nr" variable. If it is correct then we are able to send
	 *  more IFRAME's, else frame reject condition is entered.
	 */

	if (range_check (sk->opt.ax25.lastrxnr, nr, sk->opt.ax25.vs) == FALSE) {
		if ((sk->opt.ax25.condition & TIMER_RECOVERY_CONDITION) &&
				range_check (sk->opt.ax25.vs, nr, sk->opt.ax25.xx) == TRUE)
			sk->opt.ax25.vs = nr;

		else {
			return (FALSE);
		}
	}

	/* 
	 *  If we get to here, we do have a valid frame  but it might be out
	 *  of sequence.  However, we should  still accept the receive state
	 *  number N(R) since it has already passed our previous test and it
	 *  does acknowledge frames which we are sending.
	 */

	KILL_TIMER (sk);
	ax25_free_iframes(sk, &nr, finalbit);/* Free all acknowledged iframes */
	if (nr != sk->opt.ax25.vs)
		SET_TIMER (sk);

	if(sk->debug)
		printk("valid_nr done: nr=%d ax25_vs=%d\n",nr,(int)sk->opt.ax25.vs);
	return (TRUE);
}

/* 
 *  This routine determines how many iframes need to be retransmitted.
 *  It then resets the Send State Variable V(S) to accomplish this.
 */


void ax25_reject(ax25_socket *sk, int rejnr)
{
	int anchor;

	/*
	 * Flush the output queue.  Any iframes queued for
	 * transmission will be out of sequence.
	 */

/*	hd_flush (hdp->hd_ifp);*/

	/* 
	 *  Determine how many frames should be re-transmitted. In the case 
	 *  of a normal REJ this  should be 1 to K.  In the case of a timer
	 *  recovery REJ (ie. a REJ with the Final Bit on) this could be 0. 
	 */

	anchor = sk->opt.ax25.vs;
	if (sk->opt.ax25.condition & TIMER_RECOVERY_CONDITION)
		anchor = sk->opt.ax25.xx;

	anchor = (anchor - rejnr + 8) % MODULUS;

	if (anchor > 0) 
	{

		/* There is at least one iframe to retransmit. */
		KILL_TIMER (sk);
		sk->opt.ax25.vs = rejnr;

		while (sk->opt.ax25.vs != sk->opt.ax25.retxqi)
			ax25_send_iframe(sk, sk->opt.ax25.retxq[(int)sk->opt.ax25.vs], POLLOFF);

	}
	ax25_kick(sk);
}

/* 
 *  This routine frees iframes from the retransmit queue. It is called
 *  when a previously written iframe is acknowledged.
 */

void ax25_free_iframes(ax25_socket *sk, int *nr, int finalbit)
{
	int    i, k;

	/* 
	 *  We  need to do the  following  because  of a  funny quirk  in  the 
	 *  protocol.  This case  occurs  when  in Timer  recovery  condition 
	 *  we get  a  N(R)  which  acknowledges all  the outstanding  iframes
	 *  but with  the Final Bit off. In this case we need to save the last
	 *  iframe for possible retransmission even though it has already been 
	 *  acknowledged!
	 */

	if ((sk->opt.ax25.condition & TIMER_RECOVERY_CONDITION) && *nr == sk->opt.ax25.xx && finalbit == 0) {
		*nr = (*nr - 1 + 8) % MODULUS;
/*		printf ("QUIRK\n"); */
	}

	k = (*nr - sk->opt.ax25.lastrxnr + 8) % MODULUS;

	sk->opt.ax25.condition |= HAS_ACKED_DATA;
	
	/* Loop here freeing all acknowledged iframes. */
	for (i = 0; i < k; ++i) 
	{
		sk_buff *tb=sk->opt.ax25.retxq[(int)sk->opt.ax25.lastrxnr];
		if(tb==NULL)
			printk("OOPS: Double free iframe!.\n");
		else
		{
			tb->free=1;
			tb->sk=sk;
			if(tb->next && tb->prev)
				skb_unlink(tb);		/* Pull it off any device queues */
			kfree_skb(tb,FREE_WRITE);
			sk->opt.ax25.retxq[(int)sk->opt.ax25.lastrxnr] = 0;
		}
		sk->opt.ax25.lastrxnr = (sk->opt.ax25.lastrxnr + 1) % MODULUS;
	}

}


#endif
