/*
 *	AX.25 release 029
 *
 *	This is ALPHA test software. This code may break your machine, randomly fail to work with new 
 *	releases, misbehave and/or generally screw up. It might even work. 
 *
 *	This code REQUIRES 1.2.1 or higher/ NET3.029
 *
 *	This module:
 *		This module is free software; you can redistribute it and/or
 *		modify it under the terms of the GNU General Public License
 *		as published by the Free Software Foundation; either version
 *		2 of the License, or (at your option) any later version.
 *
 *	Most of this code is based on the SDL diagrams published in the 7th
 *	ARRL Computer Networking Conference papers. The diagrams have mistakes
 *	in them, but are mostly correct. Before you modify the code could you
 *	read the SDL diagrams as the code is not obvious and probably very
 *	easy to break;
 *
 *	History
 *	AX.25 028a	Jonathan(G4KLX)	New state machine based on SDL diagrams.
 *	AX.25 029	Alan(GW4PTS) Switched to KA9Q constant names.
 *
 */

#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>

/*
 *	This is where all valid I frames are sent to, to be dispatched to
 *	whichever protocol requires them.
 */
 
static int ax25_rx_iframe(ax25_socket *sk, struct sk_buff *skb, unsigned char *iframe)
{
	int queued = 0;

	switch (iframe[1]) 	/* Address byte */
	{
#ifdef CONFIG_NETROM
		case AX25_P_NETROM:
			queued = nr_rx_iframe(skb);
			break;
#endif
#ifdef CONFIG_INET
		case AX25_P_IP:
			skb->h.raw = ((char *)(iframe)) + 2;
			skb->len  -= 2;
			ip_rcv(skb, skb->dev, NULL);	/* Wrong ptype */
			break;
#endif
		case AX25_P_TEXT:
			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 = 1;
			break;
					
		default:
			if (sk->debug)
				printk("S%d: unknown PID=%02X\n", sk->ax25_state, iframe[1]);
			break;
	}
			
	return(queued);
}

/*
 *	State machine for state 1, Awaiting Connection State.
 *	The handling of the timer(s) is in file ax25_timer.c.
 *	Handling of state 0 and connection release is in ax25.c.
 */
 
static int ax25_state1_machine(ax25_socket *sk, struct sk_buff *skb, unsigned char *frame, int frametype, int type)
{
	int pf = frame[0]&PF;

	switch (frametype)
	{
		case SABM:
			if (sk->debug)
				printk("S1: sending UA(?)\n");
			ax25_send_control(sk, UA|pf, C_RESPONSE);
			break;

		case DISC:
			if (sk->debug)
				printk("S1: sending DM(?)\n");
			ax25_send_control(sk, DM|pf, C_RESPONSE);
			break;

		case UA:
			if (pf) {
				sk->ax25_t1timer = 0;
				sk->ax25_t3timer = sk->ax25_t3;
				sk->ax25_vs      = 0;
				sk->ax25_va      = 0;
				sk->ax25_vr      = 0;
				sk->state        = TCP_ESTABLISHED;
				/* For WAIT_SABM connections we will produce an accept ready socket here */
				if (!sk->dead)
					sk->state_change(sk);
				if (sk->debug)
					printk("S1: going to state 3\n");
				sk->ax25_state   = AX25_STATE_3;
			}
			break;

		case DM:
			if (pf) {
				ax25_clear_tx_queue(sk);
				sk->state        = TCP_CLOSE;
				sk->err          = ECONNREFUSED;
				if (!sk->dead)
					sk->state_change(sk);
				if (sk->debug)
					printk("S1: going to state 0\n");
				sk->ax25_state   = AX25_STATE_0;
				sk->dead         = 1;
			}
			break;

		default:
			break;
	}

	return(0);
}

/*
 * State machine for state 2, Awaiting Release State.
 * The handling of the timer(s) is in file ax25_timer.c
 * Handling of state 0 and connection release is in ax25.c.
 */
 
static int ax25_state2_machine(ax25_socket *sk, struct sk_buff *skb, unsigned char *frame, int frametype, int type)
{
	int pf = frame[0]&PF;

	switch (frametype)
	{
		case SABM:
			if (sk->debug)
				printk("S2: sending DM(?)\n");
			ax25_send_control(sk, DM|pf, C_RESPONSE);
			break;

		case DISC:
			if (sk->debug)
				printk("S2: sending UA(?)\n");
			ax25_send_control(sk, UA|pf, C_RESPONSE);
			break;

		case UA:
			if (pf) {
				sk->state        = TCP_CLOSE;
				sk->err          = 0;
				if (!sk->dead)
					sk->state_change(sk);
				if (sk->debug)
					printk("S2: going to state 0\n");
				sk->ax25_state   = AX25_STATE_0;
				sk->dead         = 1;
			}
			break;

		case DM:
			if (pf) {
				sk->state      = TCP_CLOSE;
				sk->err        = 0;
				if (!sk->dead)
					sk->state_change(sk);
				if (sk->debug)
					printk("S2: going to state 0\n");
				sk->ax25_state = AX25_STATE_0;
				sk->dead       = 1;
			}
			break;

		case I:
		case REJ:
		case RNR:
		case RR:
			if (pf) {
				if (sk->debug)
					printk("S2: sending DM(F)\n");
				ax25_send_control(sk, DM|pf, C_RESPONSE);
			}
			break;
				
		default:
			break;
	}

	return(0);
}

/*
 * State machine for state 3, Connected State.
 * The handling of the timer(s) is in file ax25_timer.c
 * Handling of state 0 and connection release is in ax25.c.
 */
static int ax25_state3_machine(ax25_socket *sk, struct sk_buff *skb, unsigned char *frame, int frametype, int type)
{
	/*
	 *	Unpack the control bits
	 */
	unsigned char nr = (frame[0]>>5)&7;
	unsigned char ns = (frame[0]>>1)&7;
	int pf = frame[0]&PF;
	int queued = 0;

	switch (frametype)
	{
		case SABM:
			if (sk->debug)
				printk("S3: sending UA(?)\n");
			ax25_send_control(sk, UA|pf, C_RESPONSE);
			sk->ax25_condition = 0x00;
			if (sk->ax25_vs != sk->ax25_va)
				ax25_clear_tx_queue(sk);
			sk->ax25_t1timer   = 0;
			sk->ax25_t3timer   = sk->ax25_t3;
			sk->ax25_vs        = 0;
			sk->ax25_va        = 0;
			sk->ax25_vr        = 0;
			break;

		case DISC:
			ax25_clear_tx_queue(sk);
			if (sk->debug)
				printk("S3: sending UA(?)\n");
			ax25_send_control(sk, UA|pf, C_RESPONSE);
			sk->ax25_t3timer = 0;
			sk->state        = TCP_CLOSE;
			sk->err          = 0;
			if (!sk->dead)
				sk->state_change(sk);
			if (sk->debug)
				printk("S3: going to state 0\n");
			sk->ax25_state   = AX25_STATE_0;
			sk->dead         = 1;
			break;

		case UA:
			ax25_establish_data_link(sk);
			if (sk->debug)
				printk("S3: going to state 1\n");
			sk->ax25_state = AX25_STATE_1;
			break;

		case DM:
			ax25_clear_tx_queue(sk);
			sk->ax25_t3timer = 0;
			sk->state        = TCP_CLOSE;
			sk->err          = ECONNRESET;
			if (!sk->dead)
				sk->state_change(sk);
			if (sk->debug)
				printk("S3: going to state 0\n");
			sk->ax25_state   = AX25_STATE_0;
			sk->dead         = 1;
			break;

		case RNR:
			sk->ax25_condition |= PEER_RX_BUSY_CONDITION;
			ax25_check_need_response(sk, type, pf);
			if (ax25_validate_nr(sk, nr)) {
				ax25_check_iframes_acked(sk, nr);
			} else {
				ax25_nr_error_recovery(sk);
				if (sk->debug)
					printk("S3: going to state 1\n");
				sk->ax25_state = AX25_STATE_1;
			}
			break;
			
		case RR:
			sk->ax25_condition &= ~PEER_RX_BUSY_CONDITION;
			ax25_check_need_response(sk, type, pf);
			if (ax25_validate_nr(sk, nr)) {
				ax25_check_iframes_acked(sk, nr);
			} else {
				ax25_nr_error_recovery(sk);
				if (sk->debug)
					printk("S3: going to state 1\n");
				sk->ax25_state = AX25_STATE_1;
			}
			break;
				
		case REJ:
			sk->ax25_condition &= ~PEER_RX_BUSY_CONDITION;
			ax25_check_need_response(sk, type, pf);
			if (ax25_validate_nr(sk, nr)) {
				ax25_frames_acked(sk, nr);
				sk->ax25_t1timer = 0;
				sk->ax25_t3timer = sk->ax25_t3;
				ax25_invoke_retransmission(sk, nr);
			} else {
				ax25_nr_error_recovery(sk);
				if (sk->debug)
					printk("S3: going to state 1\n");
				sk->ax25_state = AX25_STATE_1;
			}
			break;
			
		case I:
			if (type != C_COMMAND)
				break;
			if (!ax25_validate_nr(sk, nr)) {
				ax25_nr_error_recovery(sk);
				if (sk->debug)
					printk("S3: going to state 1\n");
				sk->ax25_state = AX25_STATE_1;
				break;
			}
			if (sk->ax25_condition & PEER_RX_BUSY_CONDITION) {
				ax25_frames_acked(sk, nr);
			} else {
				ax25_check_iframes_acked(sk, nr);
			}
			if (sk->ax25_condition & OWN_RX_BUSY_CONDITION) {
				ax25_clear_tx_queue(sk);
				if (pf) {
					if (sk->debug)
						printk("S3: sending RNR(F) vr=%d\n", sk->ax25_vr);
					ax25_send_control(sk, RNR|PF, C_RESPONSE);
					sk->ax25_condition &= ~ACK_PENDING_CONDITION;
				}
				break;
			}
			if (ns == sk->ax25_vr) {
				sk->ax25_vr = (sk->ax25_vr + 1) % MODULUS;
				sk->ax25_condition &= ~REJECT_CONDITION;
				queued = ax25_rx_iframe(sk, skb, frame);
				if (pf) {
					if (sk->debug)
						printk("S3: sending RR(F) vr=%d\n", sk->ax25_vr);
					ax25_send_control(sk, RR|PF, C_RESPONSE);
					sk->ax25_condition &= ~ACK_PENDING_CONDITION;
				} else {
					if (!(sk->ax25_condition & ACK_PENDING_CONDITION)) {
						sk->ax25_t2timer = sk->ax25_t2;
						sk->ax25_condition |= ACK_PENDING_CONDITION;
					}
				}
			} else {
				ax25_clear_tx_queue(sk);
				if (sk->ax25_condition & REJECT_CONDITION) {
					if (pf) {
						if (sk->debug)
							printk("S3: sending RR(F) vr=%d\n", sk->ax25_vr);
						ax25_send_control(sk, RR|PF, C_RESPONSE);
						sk->ax25_condition &= ~ACK_PENDING_CONDITION;
					}
				} else {
					sk->ax25_condition |= REJECT_CONDITION;
					if (sk->debug)
						printk("S3: sending REJ(?) vr=%d\n", sk->ax25_vr);
					ax25_send_control(sk, REJ|pf, C_RESPONSE);
					sk->ax25_condition &= ~ACK_PENDING_CONDITION;
				}
			}
			break;

		case ILLEGAL:
			ax25_clear_tx_queue(sk);
			ax25_establish_data_link(sk);
			if (sk->debug)
				printk("S3: going to state 1\n");
			sk->ax25_state = AX25_STATE_1;
			break;

		case FRMR:
			ax25_establish_data_link(sk);
			if (sk->debug)
				printk("S3: going to state 1\n");
			sk->ax25_state = AX25_STATE_1;
			break;
		
		default:
			break;
	}

	return(queued);
}

/*
 * State machine for state 4, Timer Recovery State.
 * The handling of the timer(s) is in file ax25_timer.c
 * Handling of state 0 and connection release is in ax25.c.
 */
static int ax25_state4_machine(ax25_socket *sk, struct sk_buff *skb, unsigned char *frame, int frametype, int type)
{
	/*
	 *	Unpack the control bits
	 */
	unsigned char nr = (frame[0]>>5)&7;
	unsigned char ns = (frame[0]>>1)&7;
	int pf = frame[0]&PF;
	int queued = 0;

	switch (frametype)
	{
		case SABM:
			if (sk->debug)
				printk("S4: sending UA(?)\n");
			ax25_send_control(sk, UA|pf, C_RESPONSE);
			sk->ax25_condition = 0x00;
			if (sk->ax25_vs != sk->ax25_va)
				ax25_clear_tx_queue(sk);
			sk->ax25_t1timer   = 0;
			sk->ax25_t3timer   = sk->ax25_t3;
			sk->ax25_vs        = 0;
			sk->ax25_va        = 0;
			sk->ax25_vr        = 0;
			sk->ax25_state     = AX25_STATE_3;
			if (sk->debug)
				printk("S4: going to state 3\n");
			break;

		case DISC:
			ax25_clear_tx_queue(sk);
			if (sk->debug)
				printk("S4: sending UA(?)\n");
			ax25_send_control(sk, UA|pf, C_RESPONSE);
			sk->ax25_t3timer = 0;
			sk->state        = TCP_CLOSE;
			sk->err          = 0;
			if (!sk->dead)
				sk->state_change(sk);
			if (sk->debug)
				printk("S4: going to state 0\n");
			sk->ax25_state   = AX25_STATE_0;
			sk->dead         = 1;
			break;

		case UA:
			ax25_establish_data_link(sk);
			if (sk->debug)
				printk("S4: going to state 1\n");
			sk->ax25_state = AX25_STATE_1;
			break;

		case DM:
			ax25_clear_tx_queue(sk);
			sk->ax25_t3timer = 0;
			sk->state        = TCP_CLOSE;
			sk->err          = ECONNRESET;
			if (!sk->dead)
				sk->state_change(sk);
			if (sk->debug)
				printk("S4: going to state 0\n");
			sk->ax25_state   = AX25_STATE_0;
			sk->dead         = 1;
			break;

		case RNR:
			sk->ax25_condition |= PEER_RX_BUSY_CONDITION;
			if (type == C_RESPONSE && pf) {
				sk->ax25_t1timer = 0;
				if (ax25_validate_nr(sk, nr)) {
					ax25_frames_acked(sk, nr);
					if (sk->ax25_vs == sk->ax25_va) {
						sk->ax25_t3timer = sk->ax25_t3;
						if (sk->debug)
							printk("S4: going to state 3\n");
						sk->ax25_state = AX25_STATE_3;
					} else {
						ax25_invoke_retransmission(sk, nr);
					}
				} else {
					ax25_nr_error_recovery(sk);
					if (sk->debug)
						printk("S4: going to state 1\n");
					sk->ax25_state = AX25_STATE_1;
				}
				break;
			}
			if (type == C_COMMAND && pf)
				ax25_enquiry_response(sk);
			if (ax25_validate_nr(sk, nr)) {
				ax25_frames_acked(sk, nr);
			} else {
				ax25_nr_error_recovery(sk);
				if (sk->debug)
					printk("S4: going to state 1\n");
				sk->ax25_state = AX25_STATE_1;
			}
			break;
			
		case RR:
			sk->ax25_condition &= ~PEER_RX_BUSY_CONDITION;
			if (type == C_RESPONSE && pf) {
				sk->ax25_t1timer = 0;
				if (ax25_validate_nr(sk, nr)) {
					ax25_frames_acked(sk, nr);
					if (sk->ax25_vs == sk->ax25_va) {
						sk->ax25_t3timer = sk->ax25_t3;
						if (sk->debug)
							printk("S4: going to state 3\n");
						sk->ax25_state = AX25_STATE_3;
					} else {
						ax25_invoke_retransmission(sk, nr);
					}
				} else {
					ax25_nr_error_recovery(sk);
					if (sk->debug)
						printk("S4: going to state 1\n");
					sk->ax25_state = AX25_STATE_1;
				}
				break;
			}
			if (type == C_COMMAND && pf)
				ax25_enquiry_response(sk);
			if (ax25_validate_nr(sk, nr)) {
				ax25_frames_acked(sk, nr);
			} else {
				ax25_nr_error_recovery(sk);
				if (sk->debug)
					printk("S4: going to state 1\n");
				sk->ax25_state = AX25_STATE_1;
			}
			break;

		case REJ:
			sk->ax25_condition &= ~PEER_RX_BUSY_CONDITION;
			if (type == C_RESPONSE && pf) {
				sk->ax25_t1timer = 0;
				if (ax25_validate_nr(sk, nr)) {
					ax25_frames_acked(sk, nr);
					if (sk->ax25_vs == sk->ax25_va) {
						sk->ax25_t3timer = sk->ax25_t3;
						if (sk->debug)
							printk("S4: going to state 3\n");
						sk->ax25_state = AX25_STATE_3;
					} else {
						ax25_invoke_retransmission(sk, nr);
					}
				} else {
					ax25_nr_error_recovery(sk);
					if (sk->debug)
						printk("S4: going to state 1\n");
					sk->ax25_state = AX25_STATE_1;
				}
				break;
			}
			if (type == C_COMMAND && pf)
				ax25_enquiry_response(sk);
			if (ax25_validate_nr(sk, nr)) {
				ax25_frames_acked(sk, nr);
				if (sk->ax25_vs != sk->ax25_va)
					ax25_invoke_retransmission(sk, nr);
			} else {
				ax25_nr_error_recovery(sk);
				if (sk->debug)
					printk("S4: going to state 1\n");
				sk->ax25_state = AX25_STATE_1;
			}
			break;

		case I:
			if (type != C_COMMAND)
				break;
			if (!ax25_validate_nr(sk, nr)) {
				ax25_nr_error_recovery(sk);
				if (sk->debug)
					printk("S4: going to state 1\n");
				sk->ax25_state = AX25_STATE_1;
				break;
			}
			ax25_frames_acked(sk, nr);
			if (sk->ax25_condition & OWN_RX_BUSY_CONDITION) {
				ax25_clear_tx_queue(sk);
				if (pf) {
					if (sk->debug)
						printk("S4: sending RNR(F) vr=%d\n", sk->ax25_vr);
					ax25_send_control(sk, RNR|PF, C_RESPONSE);
					sk->ax25_condition &= ~ACK_PENDING_CONDITION;
				}
				break;
			}
			if (ns == sk->ax25_vr) {
				sk->ax25_vr = (sk->ax25_vr + 1) % MODULUS;
				sk->ax25_condition &= ~REJECT_CONDITION;
				queued = ax25_rx_iframe(sk, skb, frame);
				if (pf) {
					if (sk->debug)
						printk("S4: sending RR(F) vr=%d\n", sk->ax25_vr);
					ax25_send_control(sk, RR|PF, C_RESPONSE);
					sk->ax25_condition &= ~ACK_PENDING_CONDITION;
				} else {
					if (!(sk->ax25_condition & ACK_PENDING_CONDITION)) {
						sk->ax25_t2timer = sk->ax25_t2;
						sk->ax25_condition |= ACK_PENDING_CONDITION;
					}
				}
			} else {
				ax25_clear_tx_queue(sk);
				if (sk->ax25_condition & REJECT_CONDITION) {
					if (pf) {
						if (sk->debug)
							printk("S4: sending RR(F) vr=%d\n", sk->ax25_vr);
						ax25_send_control(sk, RR|PF, C_RESPONSE);
						sk->ax25_condition &= ~ACK_PENDING_CONDITION;
					}
				} else {
					sk->ax25_condition |= REJECT_CONDITION;
					if (sk->debug)
						printk("S4: sending REJ(?) vr=%d\n", sk->ax25_vr);
					ax25_send_control(sk, REJ|pf, C_RESPONSE);
					sk->ax25_condition &= ~ACK_PENDING_CONDITION;
				}
			}
			break;
		
		case ILLEGAL:
			ax25_clear_tx_queue(sk);
			ax25_establish_data_link(sk);
			if (sk->debug)
				printk("S4: going to state 1\n");
			sk->ax25_state = AX25_STATE_1;
			break;

		case FRMR:
			ax25_establish_data_link(sk);
			if (sk->debug)
				printk("S4: going to state 1\n");
			sk->ax25_state =  AX25_STATE_1;
			break;
		
		default:
			break;
	}

	return(queued);
}

/*
 *	Higher level upcall for a LAPB frame 
 */
 
int ax25_lapb_rcv(ax25_socket *sk, struct sk_buff *skb, int type)
{
	int queued = 0, frametype, pf, ns, nr;
	unsigned char *frame;

	del_timer(&sk->timer);

	frame = (unsigned char *)skb->h.raw;
	pf    = frame[0]&PF;
	nr = (frame[0]>>5)&7;
	ns = (frame[0]>>1)&7;

	frametype = ax25_decode(sk, frame);

	if (sk->debug) {
		switch (frametype) {
			case DM:
				printk("S%d: received DM pf=%d ", sk->ax25_state, pf);
				break;
			case UA:
				printk("S%d: received UA pf=%d ", sk->ax25_state, pf);
				break;
			case RR:
				printk("S%d: received RR pf=%d nr=%d ", sk->ax25_state, pf, nr);
				break;
			case RNR:
				printk("S%d: received RNR pf=%d nr=%d ", sk->ax25_state, pf, nr);
				break;
			case REJ:
				printk("S%d: received REJ pf=%d nr=%d ", sk->ax25_state, pf, nr);
				break;
			case DISC:
				printk("S%d: received DISC pf=%d ", sk->ax25_state, pf);
				break;
			case SABM:
				printk("S%d: received SABM pf=%d ", sk->ax25_state, pf);
				break;
			case FRMR:
				printk("S%d: received FRMR pf=%d ", sk->ax25_state, pf);
				break;
			case I:
				printk("S%d: received I pf=%d nr=%d ns=%d ", sk->ax25_state, pf, nr, ns);
				break;
                        default:
				printk("S%d: received ??? pf=%d ", sk->ax25_state, pf);
				break;
		}

		printk("vs=%d va=%d vr=%d\n", sk->ax25_vs, sk->ax25_va, sk->ax25_vr);
	}

	switch (sk->ax25_state)
	{
		case AX25_STATE_1:
			queued = ax25_state1_machine(sk, skb, frame, frametype, type);
			break;
		case AX25_STATE_2:
			queued = ax25_state2_machine(sk, skb, frame, frametype, type);
			break;
		case AX25_STATE_3:
			queued = ax25_state3_machine(sk, skb, frame, frametype, type);
			break;
		case AX25_STATE_4:
			queued = ax25_state4_machine(sk, skb, frame, frametype, type);
			break;
		default:
			printk("S0: Frame received - weird\n");
			break;
	}

	ax25_set_timer(sk);

	return(queued);
}

#endif
