llc_utility.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:5k
- /*
- * 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);
- }