patch-2.1.27 linux/net/ax25/ax25_in.c

Next file: linux/net/ax25/ax25_ip.c
Previous file: linux/net/ax25/ax25_iface.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.26/linux/net/ax25/ax25_in.c linux/net/ax25/ax25_in.c
@@ -1,5 +1,5 @@
 /*
- *	AX.25 release 035
+ *	AX.25 release 036
  *
  *	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. 
@@ -36,6 +36,7 @@
  *	AX.25 033	Jonathan(G4KLX)	Remove auto-router.
  *					Modularisation changes.
  *	AX.25 035	Hans(PE1AYX)	Fixed interface to IP layer.
+ *	AX.25 036	Jonathan(G4KLX)	Move DAMA code into own file.
  */
 
 #include <linux/config.h>
@@ -54,16 +55,16 @@
 #include <linux/inet.h>
 #include <linux/netdevice.h>
 #include <linux/skbuff.h>
+#include <linux/firewall.h>
 #include <net/sock.h>
 #include <net/ip.h>			/* For ip_rcv */
+#include <net/arp.h>			/* For arp_rcv */
 #include <asm/uaccess.h>
 #include <asm/system.h>
 #include <linux/fcntl.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
 
-static int ax25_rx_iframe(ax25_cb *, struct sk_buff *);
-
 /*
  *	Given a fragment, queue it on the fragment queue and if the fragment
  *	is complete, send it back to ax25_rx_iframe.
@@ -90,7 +91,7 @@
 						return 1;
 					}
 
-					skbn->dev = ax25->device;
+					skbn->dev = ax25->ax25_dev->dev;
 
 					skb_reserve(skbn, AX25_MAX_HEADER_LEN);
 
@@ -143,7 +144,7 @@
  *	This is where all valid I frames are sent to, to be dispatched to
  *	whichever protocol requires them.
  */
-static int ax25_rx_iframe(ax25_cb *ax25, struct sk_buff *skb)
+int ax25_rx_iframe(ax25_cb *ax25, struct sk_buff *skb)
 {
 	int (*func)(struct sk_buff *, ax25_cb *);
 	volatile int queued = 0;
@@ -160,9 +161,9 @@
 		skb_pull(skb, 1);	/* Remove PID */
 		skb->h.raw    = skb->data;
 		skb->nh.raw   = skb->data;
-		skb->dev      = ax25->device;
+		skb->dev      = ax25->ax25_dev->dev;
 		skb->pkt_type = PACKET_HOST;
-		ip_rcv(skb, ax25->device, NULL);	/* Wrong ptype */
+		ip_rcv(skb, skb->dev, NULL);	/* Wrong ptype */
 		return 1;
 	}
 #endif
@@ -176,7 +177,7 @@
 		return (*func)(skb, ax25);
 	}
 
-	if (ax25->sk != NULL && ax25_dev_get_value(ax25->device, AX25_VALUES_TEXT) && ax25->sk->protocol == pid) {
+	if (ax25->sk != NULL && ax25->ax25_dev->values[AX25_VALUES_CONMODE] == 2 && ax25->sk->protocol == pid) {
 		if (sock_queue_rcv_skb(ax25->sk, skb) == 0)
 			queued = 1;
 		else
@@ -187,552 +188,304 @@
 }
 
 /*
- *	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.
+ *	Higher level upcall for a LAPB frame
  */
-static int ax25_state1_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int pf, int type, int dama)
+static int ax25_process_rx_frame(ax25_cb *ax25, struct sk_buff *skb, int type)
 {
-	switch (frametype) {
-		case AX25_SABM:
-			ax25->modulus = AX25_MODULUS;
-			ax25->window  = ax25_dev_get_value(ax25->device, AX25_VALUES_WINDOW);
-			ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
-			break;
+	int queued = 0;
 
-		case AX25_SABME:
-			ax25->modulus = AX25_EMODULUS;
-			ax25->window  = ax25_dev_get_value(ax25->device, AX25_VALUES_EWINDOW);
-			ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
-			break;
+	if (ax25->state == AX25_STATE_0)
+		return 0;
 
-		case AX25_DISC:
-			ax25_send_control(ax25, AX25_DM, pf, AX25_RESPONSE);
-			break;
+	del_timer(&ax25->timer);
 
-		case AX25_UA:
-			if (pf || dama) {
-				if (dama) ax25_dama_on(ax25); /* bke */
-				ax25_calculate_rtt(ax25);
-				ax25->t1timer = 0;
-				ax25->t3timer = ax25->t3;
-				ax25->idletimer = ax25->idle;
-				ax25->vs      = 0;
-				ax25->va      = 0;
-				ax25->vr      = 0;
-				ax25->state   = AX25_STATE_3;
-				ax25->n2count = 0;
-				ax25->dama_slave = dama;	/* bke */
-				if (ax25->sk != NULL) {
-					ax25->sk->state = TCP_ESTABLISHED;
-					/* For WAIT_SABM connections we will produce an accept ready socket here */
-					if (!ax25->sk->dead)
-						ax25->sk->state_change(ax25->sk);
-				}
-			}
+	switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
+		case AX25_PROTO_STD:
+			queued = ax25_std_frame_in(ax25, skb, type);
+			break;
+#ifdef CONFIG_AX25_DAMA_SLAVE
+		case AX25_PROTO_DAMA_SLAVE:
+			queued = ax25_ds_frame_in(ax25, skb, type);
 			break;
+#endif
+	}
+
+	ax25_set_timer(ax25);
+
+	return queued;
+}
 
-		case AX25_DM:
-			if (pf) {
-				if (ax25->modulus == AX25_MODULUS) {
-					ax25_clear_queues(ax25);
-					ax25->state = AX25_STATE_0;
-					if (ax25->sk != NULL) {
-						ax25->sk->state     = TCP_CLOSE;
-						ax25->sk->err       = ECONNREFUSED;
-						ax25->sk->shutdown |= SEND_SHUTDOWN;
-						if (!ax25->sk->dead)
-							ax25->sk->state_change(ax25->sk);
-						ax25->sk->dead      = 1;
+static int ax25_rcv(struct sk_buff *skb, struct device *dev, ax25_address *dev_addr, struct packet_type *ptype)
+{
+	struct sock *make;
+	struct sock *sk;
+	int type = 0;
+	ax25_digi dp, reverse_dp;
+	ax25_cb *ax25;
+	ax25_address src, dest;
+	ax25_address *next_digi = NULL;
+	ax25_dev *ax25_dev;
+	struct sock *raw;
+	int mine = 0;
+	int dama;
+
+	/*
+	 *	Process the AX.25/LAPB frame.
+	 */
+
+	skb->h.raw = skb->data;
+
+	if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL) {
+		kfree_skb(skb, FREE_READ);
+		return 0;
+	}
+
+#ifdef CONFIG_FIREWALL
+	if (call_in_firewall(PF_AX25, skb->dev, skb->h.raw, NULL) != FW_ACCEPT) {
+		kfree_skb(skb, FREE_READ);
+		return 0;
+	}
+#endif
+
+	/*
+	 *	Parse the address header.
+	 */
+
+	if (ax25_addr_parse(skb->data, skb->len, &src, &dest, &dp, &type, &dama) == NULL) {
+		kfree_skb(skb, FREE_READ);
+		return 0;
+	}
+
+	/*
+	 *	Ours perhaps ?
+	 */
+	if (dp.lastrepeat + 1 < dp.ndigi)		/* Not yet digipeated completely */
+		next_digi = &dp.calls[dp.lastrepeat + 1];
+
+	/*
+	 *	Pull of the AX.25 headers leaving the CTRL/PID bytes
+	 */
+	skb_pull(skb, ax25_addr_size(&dp));
+
+	/* For our port addresses ? */
+	if (ax25cmp(&dest, dev_addr) == 0 && dp.lastrepeat + 1 == dp.ndigi)
+		mine = 1;
+
+	/* Also match on any registered callsign from L3/4 */
+	if (!mine && ax25_listen_mine(&dest, dev) && dp.lastrepeat + 1 == dp.ndigi)
+		mine = 1;
+
+	/* UI frame - bypass LAPB processing */
+	if ((*skb->data & ~0x10) == AX25_UI && dp.lastrepeat + 1 == dp.ndigi) {
+		skb->h.raw = skb->data + 2;		/* skip control and pid */
+
+		if ((raw = ax25_addr_match(&dest)) != NULL)
+			ax25_send_to_raw(raw, skb, skb->data[1]);
+
+		if (!mine && ax25cmp(&dest, (ax25_address *)dev->broadcast) != 0) {
+			kfree_skb(skb, FREE_READ);
+			return 0;
+		}
+
+		/* Now we are pointing at the pid byte */
+		switch (skb->data[1]) {
+#ifdef CONFIG_INET
+			case AX25_P_IP:
+				skb_pull(skb,2);		/* drop PID/CTRL */
+				skb->h.raw    = skb->data;
+				skb->nh.raw   = skb->data;
+				skb->dev      = dev;
+				skb->pkt_type = PACKET_HOST;
+				ip_rcv(skb, dev, ptype);	/* Note ptype here is the wrong one, fix me later */
+				break;
+
+			case AX25_P_ARP:
+				skb_pull(skb,2);
+				skb->h.raw    = skb->data;
+				skb->nh.raw   = skb->data;
+				skb->dev      = dev;
+				skb->pkt_type = PACKET_HOST;
+				arp_rcv(skb, dev, ptype);	/* Note ptype here is wrong... */
+				break;
+#endif
+			case AX25_P_TEXT:
+				/* Now find a suitable dgram socket */
+				if ((sk = ax25_find_socket(&dest, &src, SOCK_DGRAM)) != NULL) {
+					if (sk->rmem_alloc >= sk->rcvbuf) {
+						kfree_skb(skb, FREE_READ);
+					} else {
+						/*
+						 *	Remove the control and PID.
+						 */
+						skb_pull(skb, 2);
+						if (sock_queue_rcv_skb(sk, skb) != 0)
+							kfree_skb(skb, FREE_READ);
 					}
 				} else {
-					ax25->modulus = AX25_MODULUS;
-					ax25->window  = ax25_dev_get_value(ax25->device, AX25_VALUES_WINDOW);
+					kfree_skb(skb, FREE_READ);
 				}
-			}
-			break;
+				break;
 
-		default:
-			if (dama && pf)
-				ax25_send_control(ax25, AX25_SABM, AX25_POLLON, AX25_COMMAND);
-			break;
+			default:
+				kfree_skb(skb, FREE_READ);	/* Will scan SOCK_AX25 RAW sockets */
+				break;
+		}
+
+		return 0;
 	}
 
-	return 0;
-}
+	/*
+	 *	Is connected mode supported on this device ?
+	 *	If not, should we DM the incoming frame (except DMs) or
+	 *	silently ignore them. For now we stay quiet.
+	 */
+	if (ax25_dev->values[AX25_VALUES_CONMODE] == 0) {
+		kfree_skb(skb, FREE_READ);
+		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_cb *ax25, struct sk_buff *skb, int frametype, int pf, int type)
-{
-	switch (frametype) {
-		case AX25_SABM:
-		case AX25_SABME:
-			ax25_send_control(ax25, AX25_DM, pf, AX25_RESPONSE);
-			if (ax25->dama_slave)
-				ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
-			break;
+	/* LAPB */
 
-		case AX25_DISC:
-			ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
-			if (ax25->dama_slave) {
-				ax25->state = AX25_STATE_0;
-				ax25_dama_off(ax25);
-				if (ax25->sk != NULL) {
-					ax25->sk->state     = TCP_CLOSE;
-					ax25->sk->err       = 0;
-					ax25->sk->shutdown |= SEND_SHUTDOWN;
-					if (!ax25->sk->dead)
-						ax25->sk->state_change(ax25->sk);
-					ax25->sk->dead      = 1;
-				}
-			}
-			break;
+	/* AX.25 state 1-4 */
 
-		case AX25_DM:
-		case AX25_UA:
-			if (pf) {
-				ax25->state = AX25_STATE_0;
-				ax25_dama_off(ax25);
-				if (ax25->sk != NULL) {
-					ax25->sk->state     = TCP_CLOSE;
-					ax25->sk->err       = 0;
-					ax25->sk->shutdown |= SEND_SHUTDOWN;
-					if (!ax25->sk->dead)
-						ax25->sk->state_change(ax25->sk);
-					ax25->sk->dead      = 1;
-				}
-			}
-			break;
+	ax25_digi_invert(&dp, &reverse_dp);
 
-		case AX25_I:
-		case AX25_REJ:
-		case AX25_RNR:
-		case AX25_RR:
-			if (pf) {
-				if (ax25->dama_slave)
-					ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
-				else
-					ax25_send_control(ax25, AX25_DM, AX25_POLLON, AX25_RESPONSE);
-			}
-			break;
+	if ((ax25 = ax25_find_cb(&dest, &src, &reverse_dp, dev)) != NULL) {
+		/*
+		 *	Process the frame. If it is queued up internally it returns one otherwise we
+		 *	free it immediately. This routine itself wakes the user context layers so we
+		 *	do no further work
+		 */
+		if (ax25_process_rx_frame(ax25, skb, type) == 0)
+			kfree_skb(skb, FREE_READ);
 
-		default:
-			break;
+		return 0;
 	}
 
-	return 0;
-}
+	/* AX.25 state 0 (disconnected) */
 
-/*
- *	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_cb *ax25, struct sk_buff *skb, int frametype, int ns, int nr, int pf, int type, int dama)
-{
-	int queued = 0;
+	/* a) received not a SABM(E) */
 
-	switch (frametype) {
-		case AX25_SABM:
-		case AX25_SABME:
-			if (dama) ax25_dama_on(ax25);
-			if (frametype == AX25_SABM) {
-				ax25->modulus = AX25_MODULUS;
-				ax25->window  = ax25_dev_get_value(ax25->device, AX25_VALUES_WINDOW);
-			} else {
-				ax25->modulus = AX25_EMODULUS;
-				ax25->window  = ax25_dev_get_value(ax25->device, AX25_VALUES_EWINDOW);
-			}
-			ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
-			ax25->condition = 0x00;
-			ax25->t1timer   = 0;
-			ax25->t3timer   = ax25->t3;
-			ax25->idletimer = ax25->idle;
-			ax25->vs        = 0;
-			ax25->va        = 0;
-			ax25->vr        = 0;
-			ax25->dama_slave = dama;
-			ax25_requeue_frames(ax25);
-			break;
+	if ((*skb->data & ~AX25_PF) != AX25_SABM && (*skb->data & ~AX25_PF) != AX25_SABME) {
+		/*
+		 *	Never reply to a DM. Also ignore any connects for
+		 *	addresses that are not our interfaces and not a socket.
+		 */
+		if ((*skb->data & ~AX25_PF) != AX25_DM && mine)
+			ax25_return_dm(dev, &src, &dest, &dp);
 
-		case AX25_DISC:
-			ax25_clear_queues(ax25);
-			ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
-			ax25->t3timer = 0;
-			ax25->state   = AX25_STATE_0;
-			ax25_dama_off(ax25);
-			if (ax25->sk != NULL) {
-				ax25->sk->state     = TCP_CLOSE;
-				ax25->sk->err       = 0;
-				ax25->sk->shutdown |= SEND_SHUTDOWN;
-				if (!ax25->sk->dead)
-					ax25->sk->state_change(ax25->sk);
-				ax25->sk->dead      = 1;
-			}
-			break;
+		kfree_skb(skb, FREE_READ);
+		return 0;
+	}
 
-		case AX25_DM:
-			ax25_clear_queues(ax25);
-			ax25->t3timer = 0;
-			ax25->state   = AX25_STATE_0;
-			ax25_dama_off(ax25);
-			if (ax25->sk != NULL) {
-				ax25->sk->state     = TCP_CLOSE;
-				ax25->sk->err       = ECONNRESET;
-				ax25->sk->shutdown |= SEND_SHUTDOWN;
-				if (!ax25->sk->dead)
-					ax25->sk->state_change(ax25->sk);
-				ax25->sk->dead      = 1;
-			}
-			break;
+	/* b) received SABM(E) */
 
-		case AX25_RR:
-		case AX25_RNR:
-			if (frametype == AX25_RR)
-				ax25->condition &= ~AX25_COND_PEER_RX_BUSY;
-			else
-				ax25->condition |= AX25_COND_PEER_RX_BUSY;
-			ax25_check_need_response(ax25, type, pf);
-			if (ax25_validate_nr(ax25, nr)) {
-				ax25_check_iframes_acked(ax25, nr);
-				dama_check_need_response(ax25, type, pf);
-			} else {
-				ax25_nr_error_recovery(ax25);
-				ax25->state = AX25_STATE_1;
-			}
-			break;
+	if (dp.lastrepeat + 1 == dp.ndigi)
+		sk = ax25_find_listener(&dest, 0, dev, SOCK_SEQPACKET);
+	else
+		sk = ax25_find_listener(next_digi, 1, dev, SOCK_SEQPACKET);
+
+	if (sk != NULL) {
+		if (sk->ack_backlog == sk->max_ack_backlog || (make = ax25_make_new(sk, dev)) == NULL) {
+			if (mine) ax25_return_dm(dev, &src, &dest, &dp);
+			kfree_skb(skb, FREE_READ);
+			return 0;
+		}
 
-		case AX25_REJ:
-			ax25->condition &= ~AX25_COND_PEER_RX_BUSY;
-			ax25_check_need_response(ax25, type, pf);
-			if (ax25_validate_nr(ax25, nr)) {
-				ax25_frames_acked(ax25, nr);
-				ax25_calculate_rtt(ax25);
-				ax25->t1timer = 0;
-				ax25->t3timer = ax25->t3;
-				ax25_requeue_frames(ax25);
-				dama_check_need_response(ax25, type, pf);
-			} else {
-				ax25_nr_error_recovery(ax25);
-				ax25->state = AX25_STATE_1;
-			}
-			break;
+		ax25 = make->protinfo.ax25;
 
-		case AX25_I:
-			if (!ax25_validate_nr(ax25, nr)) {
-				ax25_nr_error_recovery(ax25);
-				ax25->state = AX25_STATE_1;
-				break;
-			}
-			if (ax25->condition & AX25_COND_PEER_RX_BUSY) {
-				ax25_frames_acked(ax25, nr);
-			} else {
-				ax25_check_iframes_acked(ax25, nr);
-			}
-			if (ax25->condition & AX25_COND_OWN_RX_BUSY) {
-				if (pf)	{
-					if (ax25->dama_slave)
-						dama_enquiry_response(ax25);
-					else
-						ax25_enquiry_response(ax25);
-				}
-				break;
-			}
-			if (ns == ax25->vr) {
-				ax25->vr = (ax25->vr + 1) % ax25->modulus;
-				queued = ax25_rx_iframe(ax25, skb);
-				if (ax25->condition & AX25_COND_OWN_RX_BUSY) {
-					ax25->vr = ns;	/* ax25->vr - 1 */
-					if (pf) {
-						if (ax25->dama_slave)
-							dama_enquiry_response(ax25);
-						else
-							ax25_enquiry_response(ax25);
-					}
-					break;
-				}
-				ax25->condition &= ~AX25_COND_REJECT;
-				if (pf) {
-					if (ax25->dama_slave)
-						dama_enquiry_response(ax25);
-					else
-						ax25_enquiry_response(ax25);
-				} else {
-					if (!(ax25->condition & AX25_COND_ACK_PENDING)) {
-						ax25->t2timer = ax25->t2;
-						ax25->condition |= AX25_COND_ACK_PENDING;
-					}
-				}
-			} else {
-				if (ax25->condition & AX25_COND_REJECT) {
-					if (pf) {
-						if (ax25->dama_slave)
-							dama_enquiry_response(ax25);
-						else
-							ax25_enquiry_response(ax25);
-					}
-				} else {
-					ax25->condition |= AX25_COND_REJECT;
-					if (ax25->dama_slave)
-						dama_enquiry_response(ax25);
-					else
-						ax25_send_control(ax25, AX25_REJ, pf, AX25_RESPONSE);
-					ax25->condition &= ~AX25_COND_ACK_PENDING;
-				}
-			}
-			break;
+		skb_queue_head(&sk->receive_queue, skb);
 
-		case AX25_FRMR:
-		case AX25_ILLEGAL:
-			ax25_establish_data_link(ax25);
-			ax25->state = AX25_STATE_1;
-			break;
+		skb->sk     = make;
+		make->state = TCP_ESTABLISHED;
+		make->pair  = sk;
 
-		default:
-			break;
+		sk->ack_backlog++;
+	} else {
+		if (!mine) {
+			kfree_skb(skb, FREE_READ);
+			return 0;
+		}
+
+		if ((ax25 = ax25_create_cb()) == NULL) {
+			ax25_return_dm(dev, &src, &dest, &dp);
+			kfree_skb(skb, FREE_READ);
+			return 0;
+		}
+
+		ax25_fillin_cb(ax25, ax25_dev);
+		ax25->idletimer = ax25->idle;
 	}
 
-	return queued;
-}
+	ax25->source_addr = dest;
+	ax25->dest_addr   = src;
 
-/*
- *	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_cb *ax25, struct sk_buff *skb, int frametype, int ns, int nr, int pf, int type, int dama)
-{
-	int queued = 0;
+	/*
+	 *	Sort out any digipeated paths.
+	 */
+	if (dp.ndigi != 0 && ax25->digipeat == NULL && (ax25->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) {
+		kfree_skb(skb, FREE_READ);
+		ax25_destroy_socket(ax25);
+		return 0;
+	}
 
-	switch (frametype) {
-		case AX25_SABM:
-		case AX25_SABME:
-			if (dama) ax25_dama_on(ax25);
-			if (frametype == AX25_SABM) {
-				ax25->modulus = AX25_MODULUS;
-				ax25->window  = ax25_dev_get_value(ax25->device, AX25_VALUES_WINDOW);
-			} else {
-				ax25->modulus = AX25_EMODULUS;
-				ax25->window  = ax25_dev_get_value(ax25->device, AX25_VALUES_EWINDOW);
-			}
-			ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
-			ax25->condition = 0x00;
-			ax25->t1timer   = 0;
-			ax25->t3timer   = ax25->t3;
-			ax25->idletimer = ax25->idle;
-			ax25->vs        = 0;
-			ax25->va        = 0;
-			ax25->vr        = 0;
-			ax25->state     = AX25_STATE_3;
-			ax25->n2count   = 0;
-			ax25->dama_slave = dama;
-			ax25_requeue_frames(ax25);
-			break;
+	if (dp.ndigi == 0) {
+		if (ax25->digipeat != NULL) {
+			kfree_s(ax25->digipeat, sizeof(ax25_digi));
+			ax25->digipeat = NULL;
+		}
+	} else {
+		/* Reverse the source SABM's path */
+		*ax25->digipeat = reverse_dp;
+	}
 
-		case AX25_DISC:
-			ax25_clear_queues(ax25);
-			ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
-			ax25->t3timer = 0;
-			ax25->state   = AX25_STATE_0;
-			ax25_dama_off(ax25);
-			if (ax25->sk != NULL) {
-				ax25->sk->state     = TCP_CLOSE;
-				ax25->sk->err       = 0;
-				ax25->sk->shutdown |= SEND_SHUTDOWN;
-				if (!ax25->sk->dead)
-					ax25->sk->state_change(ax25->sk);
-				ax25->sk->dead      = 1;
-			}
-			break;
+	if ((*skb->data & ~AX25_PF) == AX25_SABME) {
+		ax25->modulus = AX25_EMODULUS;
+		ax25->window  = ax25_dev->values[AX25_VALUES_EWINDOW];
+	} else {
+		ax25->modulus = AX25_MODULUS;
+		ax25->window  = ax25_dev->values[AX25_VALUES_WINDOW];
+	}
 
-		case AX25_DM:
-			ax25_clear_queues(ax25);
-			ax25->t3timer = 0;
-			ax25->state   = AX25_STATE_0;
-			ax25_dama_off(ax25);
-			if (ax25->sk != NULL) {
-				ax25->sk->state     = TCP_CLOSE;
-				ax25->sk->err       = ECONNRESET;
-				ax25->sk->shutdown |= SEND_SHUTDOWN;
-				if (!ax25->sk->dead)
-					ax25->sk->state_change(ax25->sk);
-				ax25->sk->dead      = 1;
-			}
-			break;
+	ax25_send_control(ax25, AX25_UA, AX25_POLLON, AX25_RESPONSE);
 
-		case AX25_RR:
-		case AX25_RNR:
-			if (frametype == AX25_RR)
-				ax25->condition &= ~AX25_COND_PEER_RX_BUSY;
-			else
-				ax25->condition |= AX25_COND_PEER_RX_BUSY;
-			if (type == AX25_RESPONSE && pf) {
-				ax25->t1timer = 0;
-				if (ax25_validate_nr(ax25, nr)) {
-					ax25_frames_acked(ax25, nr);
-					if (ax25->vs == ax25->va) {
-						ax25->t3timer = ax25->t3;
-						ax25->n2count = 0;
-						ax25->state   = AX25_STATE_3;
-					}
-				} else {
-					ax25_nr_error_recovery(ax25);
-					ax25->state = AX25_STATE_1;
-				}
-				break;
-			}
-			ax25_check_need_response(ax25, type, pf);
-			if (ax25_validate_nr(ax25, nr)) {
-				ax25_frames_acked(ax25, nr);
-				dama_check_need_response(ax25, type, pf);
-			} else {
-				ax25_nr_error_recovery(ax25);
-				ax25->state = AX25_STATE_1;
-			}
-			break;
+#ifdef CONFIG_AX25_DAMA_SLAVE
+	if (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL] == AX25_PROTO_DAMA_SLAVE)
+		ax25_dama_on(ax25);
+#endif
 
-		case AX25_REJ:
-			ax25->condition &= ~AX25_COND_PEER_RX_BUSY;
-			if (pf && (type == AX25_RESPONSE || (ax25->dama_slave && type == AX25_COMMAND))) {
-				ax25->t1timer = 0;
-				if (ax25_validate_nr(ax25, nr)) {
-					ax25_frames_acked(ax25, nr);
-					if (ax25->vs == ax25->va) {
-						ax25->t3timer = ax25->t3;
-						ax25->n2count = 0;
-						ax25->state   = AX25_STATE_3;
-					} else {
-						ax25_requeue_frames(ax25);
-					}
-					dama_check_need_response(ax25, type, pf);
-				} else {
-					ax25_nr_error_recovery(ax25);
-					ax25->state = AX25_STATE_1;
-				}
-				break;
-			}
-			ax25_check_need_response(ax25, type, pf);
-			if (ax25_validate_nr(ax25, nr)) {
-				ax25_frames_acked(ax25, nr);
-				if(ax25->vs != ax25->va) {
-					ax25_requeue_frames(ax25);
-				}
-				dama_check_need_response(ax25, type, pf);
-			} else {
-				ax25_nr_error_recovery(ax25);
-				ax25->state = AX25_STATE_1;
-			}
-			break;
+	ax25->t3timer = ax25->t3;
+	ax25->state   = AX25_STATE_3;
 
-		case AX25_I:
-			if (!ax25_validate_nr(ax25, nr)) {
-				ax25_nr_error_recovery(ax25);
-				ax25->state = AX25_STATE_1;
-				break;
-			}
-			ax25_frames_acked(ax25, nr);
-			if (ax25->condition & AX25_COND_OWN_RX_BUSY) {
-				if (pf) {
-					if (ax25->dama_slave)
-						ax25_enquiry_response(ax25);
-					else
-						dama_enquiry_response(ax25);
-				}
-				break;
-			}
-			if (ns == ax25->vr) {
-				ax25->vr = (ax25->vr + 1) % ax25->modulus;
-				queued = ax25_rx_iframe(ax25, skb);
-				if (ax25->condition & AX25_COND_OWN_RX_BUSY) {
-					ax25->vr = ns;	/* ax25->vr - 1 */
-					if (pf) {
-						if (ax25->dama_slave)
-							dama_enquiry_response(ax25);
-						else
-							ax25_enquiry_response(ax25);
-					}
-					break;
-				}
-				ax25->condition &= ~AX25_COND_REJECT;
-				if (pf) {
-					if (ax25->dama_slave)
-						dama_enquiry_response(ax25);
-					else
-						ax25_enquiry_response(ax25);
-				} else {
-					if (!(ax25->condition & AX25_COND_ACK_PENDING)) {
-						ax25->t2timer = ax25->t2;
-						ax25->condition |= AX25_COND_ACK_PENDING;
-					}
-				}
-			} else {
-				if (ax25->condition & AX25_COND_REJECT) {
-					if (pf) {
-						if (ax25->dama_slave)
-							dama_enquiry_response(ax25);
-						else
-							ax25_enquiry_response(ax25);
-					}
-				} else {
-					ax25->condition |= AX25_COND_REJECT;
-					if (ax25->dama_slave)
-						dama_enquiry_response(ax25);
-					else
-						ax25_send_control(ax25, AX25_REJ, pf, AX25_RESPONSE);
-					ax25->condition &= ~AX25_COND_ACK_PENDING;
-				}
-			}
-			break;
+	ax25_insert_socket(ax25);
 
-		case AX25_FRMR:
-		case AX25_ILLEGAL:
-			ax25_establish_data_link(ax25);
-			ax25->state = AX25_STATE_1;
-			break;
+	ax25_set_timer(ax25);
 
-		default:
-			break;
+	if (sk != NULL) {
+		if (!sk->dead)
+			sk->data_ready(sk, skb->len);
+	} else {
+		kfree_skb(skb, FREE_READ);
 	}
 
-	return queued;
+	return 0;
 }
 
 /*
- *	Higher level upcall for a LAPB frame
+ *	Receive an AX.25 frame via a SLIP interface.
  */
-int ax25_process_rx_frame(ax25_cb *ax25, struct sk_buff *skb, int type, int dama)
+int ax25_kiss_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *ptype)
 {
-	int queued = 0, frametype, ns, nr, pf;
+	skb->sk = NULL;		/* Initially we don't know who it's for */
 
-	if (ax25->state == AX25_STATE_0)
+	if ((*skb->data & 0x0F) != 0) {
+		kfree_skb(skb, FREE_READ);	/* Not a KISS data frame */
 		return 0;
-
-	del_timer(&ax25->timer);
-
-	frametype = ax25_decode(ax25, skb, &ns, &nr, &pf);
-
-	switch (ax25->state) {
-		case AX25_STATE_1:
-			queued = ax25_state1_machine(ax25, skb, frametype, pf, type, dama);
-			break;
-		case AX25_STATE_2:
-			queued = ax25_state2_machine(ax25, skb, frametype, pf, type);
-			break;
-		case AX25_STATE_3:
-			queued = ax25_state3_machine(ax25, skb, frametype, ns, nr, pf, type, dama);
-			break;
-		case AX25_STATE_4:
-			queued = ax25_state4_machine(ax25, skb, frametype, ns, nr, pf, type, dama);
-			break;
 	}
 
-	ax25_set_timer(ax25);
+	skb_pull(skb, AX25_KISS_HEADER_LEN);	/* Remove the KISS byte */
 
-	return queued;
+	return ax25_rcv(skb, dev, (ax25_address *)dev->dev_addr, ptype);
 }
 
 #endif

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov