patch-2.1.15 linux/net/802/llc_utility.c

Next file: linux/net/802/pseudo/Makefile
Previous file: linux/net/802/llc_sendpdu.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.14/linux/net/802/llc_utility.c linux/net/802/llc_utility.c
@@ -0,0 +1,253 @@
+/*
+ * NET		An implementation of the IEEE 802.2 LLC protocol for the
+ *		LINUX operating system.  LLC is implemented as a set of 
+ *		state machines and callbacks for higher networking layers.
+ *
+ *		Small utilities, Linux timer handling.
+ *
+ *		Written by Tim Alpaerts, Tim_Alpaerts@toyota-motor-europe.com
+ *
+ *		This program 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.
+ *
+ *	Changes
+ *		Alan Cox	:	Chainsawed into Linux form.
+ *					Added llc_ function name prefixes.
+ *					Fixed bug in stop/start timer.
+ *					Added llc_cancel_timers for closing
+ *						down an llc
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+#include <net/llc_frame.h>
+#include <net/llc.h>
+
+int llc_decode_frametype(frameptr fr)
+{
+	if (IS_UFRAME(fr)) 
+	{      /* unnumbered cmd/rsp */
+		switch(fr->u_mm.mm & 0x3B)
+		{
+			case 0x1B:
+			    return(SABME_CMD);
+			    break;
+			case 0x10:
+			    return(DISC_CMD);
+			    break;
+			case 0x18:
+			    return(UA_RSP);
+			    break;
+			case 0x03:
+			    return(DM_RSP);
+			    break;
+			case 0x21:
+			    return(FRMR_RSP);
+			    break;
+			case 0x00:
+			    return(UI_CMD);
+			    break;
+			case 0x2B:
+		 	    if (IS_RSP(fr)) 
+		 	    	return(XID_RSP);
+			    else
+			    	return(XID_CMD);
+			    break;
+			case 0x38:
+		    	    if (IS_RSP(fr))
+		    	    	return(TEST_RSP);
+			    else
+				return(TEST_CMD);
+			    break;
+			default:
+			    return(BAD_FRAME);
+		}
+	}
+	else if (IS_SFRAME(fr))
+	{  /* supervisory cmd/rsp */
+		switch(fr->s_hdr.ss)
+		{
+			case 0x00:
+			    if (IS_RSP(fr)) 
+			    	return(RR_RSP);
+			    else
+			    	return(RR_CMD);
+			    break;
+			case 0x02:
+			    if (IS_RSP(fr))
+			    	return(REJ_RSP);
+			    else
+			    	return(REJ_CMD);
+			    break;
+			case 0x01:
+			    if (IS_RSP(fr))
+			    	return(RNR_RSP);
+			    else
+			    	return(RNR_CMD);
+			    break;
+			default:
+			    return(BAD_FRAME);
+		}
+	}
+	else
+	{			  /* information xfer */
+		if (IS_RSP(fr)) 
+			return(I_RSP);
+		else	
+			return(I_CMD);
+	}
+}
+
+
+/*
+ *	Validate_seq_nos will check N(S) and N(R) to see if they are
+ *	invalid or unexpected.
+ *	"unexpected" is explained on p44 Send State Variable.
+ *	The return value is:
+ *		4 * invalid N(R) +
+ *		2 * invalid N(S) +
+ *		1 * unexpected N(S)
+ */
+
+int llc_validate_seq_nos(llcptr lp, frameptr fr)
+{
+	int res;
+     
+	/*
+	 *	A U-frame is always good 
+	 */
+
+	if (IS_UFRAME(fr)) 
+		return(0);	
+
+	/*
+	 *	For S- and I-frames check N(R): 
+	 */
+
+	if (fr->i_hdr.nr == lp->vs) 
+	{    	/* if N(R) = V(S)  */
+        	res = 0;                        /* N(R) is good */
+	}
+	else
+	{				/* lp->k = transmit window size */
+    		if (lp->vs >= lp->k) 
+    		{	/* if window not wrapped around 127 */
+			if ((fr->i_hdr.nr < lp->vs) &&
+				(fr->i_hdr.nr > (lp->vs - lp->k)))
+				res = 0;
+			else 
+				res = 4;		/* N(R) invalid */
+		}
+		else
+		{	/* window wraps around 127 */
+			if ((fr->i_hdr.nr < lp->vs) ||
+				(fr->i_hdr.nr > (128 + lp->vs - lp->k))) 
+				res = 0;
+			else
+				res = 4;		/* N(R) invalid */
+		}
+	}
+
+	/*
+	 *	For an I-frame, must check N(S) also:  
+	 */
+
+	if (IS_IFRAME(fr)) 
+	{
+    		if (fr->i_hdr.ns == lp->vr) 
+    			return res;   /* N(S) good */
+		if (lp->vr >= lp->rw) 
+		{
+			/* if receive window not wrapped */
+
+			if ((fr->i_hdr.ns < lp->vr) &&
+				(fr->i_hdr.ns > (lp->vr - lp->k)))
+				res = res +1;   	/* N(S) unexpected */
+			else  
+				res = res +2;         /* N(S) invalid */            
+		}
+		else
+		{
+			/* Window wraps around 127 */
+
+			if ((fr->i_hdr.ns < lp->vr) ||
+				(fr->i_hdr.ns > (128 + lp->vr - lp->k)))
+				res = res +1;   	/* N(S) unexpected */
+			else
+				res = res +2;         /* N(S) invalid */            
+		}
+	}					
+	return(res);
+}
+
+/* **************** timer management routines ********************* */
+
+static void llc_p_timer_expired(unsigned long ulp)
+{
+	llc_timer_expired((llcptr) ulp, P_TIMER);
+}
+
+static void llc_rej_timer_expired(unsigned long ulp)
+{
+	llc_timer_expired((llcptr) ulp, REJ_TIMER);
+}
+
+static void llc_ack_timer_expired(unsigned long ulp)
+{
+	llc_timer_expired((llcptr) ulp, ACK_TIMER);
+} 
+
+static void llc_busy_timer_expired(unsigned long ulp)
+{
+	llc_timer_expired((llcptr) ulp, BUSY_TIMER);
+}
+
+/* exp_fcn is an array holding the 4 entry points of the
+   timer expiry routines above.
+   It is required to keep start_timer() generic.
+   Thank you cdecl.
+ */
+
+static void (* exp_fcn[])(unsigned long) = 
+{
+	llc_p_timer_expired,
+	llc_rej_timer_expired,
+	llc_ack_timer_expired,
+	llc_busy_timer_expired
+};   
+
+void llc_start_timer(llcptr lp, int t)
+{
+	if (lp->timer_state[t] == TIMER_IDLE)
+	{
+    		lp->tl[t].expires = jiffies + lp->timer_interval[t];
+    		lp->tl[t].data = (unsigned long) lp;
+    		lp->tl[t].function = exp_fcn[t];
+    		add_timer(&lp->tl[t]);
+    		lp->timer_state[t] = TIMER_RUNNING;
+	}
+}
+
+void llc_stop_timer(llcptr lp, int t)
+{
+	if (lp->timer_state[t] == TIMER_RUNNING)
+	{
+        	del_timer(&lp->tl[t]);
+        	lp->timer_state[t] = TIMER_IDLE;
+	}
+}
+
+void llc_cancel_timers(llcptr lp)
+{
+	llc_stop_timer(lp, P_TIMER);
+	llc_stop_timer(lp, REJ_TIMER);
+	llc_stop_timer(lp, ACK_TIMER);
+	llc_stop_timer(lp, BUSY_TIMER);
+}
+

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