⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cl2llc.pre

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 PRE
字号:
/* * 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. * *		Class 2 llc algorithm. *		Pseudocode interpreter, transition table lookup, *			data_request & indicate primitives... * *		Code for initialization, termination, registration and  *		MAC layer glue. * *		Copyright 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 format *					Modified to use llc_ names *					Changed callbacks * *	This file must be processed by sed before it can be compiled. */#include <linux/types.h>#include <linux/kernel.h>#include <linux/malloc.h>#include <linux/netdevice.h>#include <linux/skbuff.h>#include <net/p8022.h>#include <linux/proc_fs.h>#include <linux/stat.h>#include <asm/byteorder.h>#include "pseudo/pseudocode.h"#include "transit/pdutr.h"#include "transit/timertr.h"#include <net/llc_frame.h>#include <net/llc.h>/* *	Data_request() is called by the client to present a data unit *	to the llc for transmission. *	In the future this function should also check if the transmit window *	allows the sending of another pdu, and if not put the skb on the atq *	for deferred sending. */int llc_data_request(llcptr lp, struct sk_buff *skb){	if (skb_headroom(skb) < (lp->dev->hard_header_len +4)){		printk("cl2llc: data_request() not enough headroom in skb\n");		return -1;	};	skb_push(skb, 4);	if ((lp->state != NORMAL) && (lp->state != BUSY) && (lp->state != REJECT))	{		printk("cl2llc: data_request() while no llc connection\n"); 		return -1;  	}	if (lp->remote_busy)	{     /* if the remote llc is BUSY, */		ADD_TO_ATQ(skb);      /* save skb in the await transmit queue */		return 0;	}                           	else	{		/*		 *	Else proceed with xmit 		 */		switch(lp->state)		{			case NORMAL:				if(lp->p_flag)					llc_interpret_pseudo_code(lp, NORMAL2, skb, NO_FRAME);				else					llc_interpret_pseudo_code(lp, NORMAL1, skb, NO_FRAME);				break;			case BUSY:				if (lp->p_flag)					llc_interpret_pseudo_code(lp, BUSY2, skb, NO_FRAME);				else					llc_interpret_pseudo_code(lp, BUSY1, skb, NO_FRAME);				break;			case REJECT:				if (lp->p_flag)					llc_interpret_pseudo_code(lp, REJECT2, skb, NO_FRAME);				else					llc_interpret_pseudo_code(lp, REJECT1, skb, NO_FRAME);				break;			default:		}		if(lp->llc_callbacks)		{			lp->llc_event(lp);			lp->llc_callbacks=0;		}		return 0;  	}              }/*  *	Disconnect_request() requests that the llc to terminate a connection */void disconnect_request(llcptr lp){	if ((lp->state == NORMAL) ||    		(lp->state == BUSY) ||		(lp->state == REJECT) ||		(lp->state == AWAIT) ||		(lp->state == AWAIT_BUSY) ||		(lp->state == AWAIT_REJECT))	{		lp->state = D_CONN;		llc_interpret_pseudo_code(lp, SH1, NULL, NO_FRAME);		if(lp->llc_callbacks)		{			lp->llc_event(lp);			lp->llc_callbacks=0;		}		/* 		 *	lp may be invalid after the callback		 */	}}/* *	Connect_request() requests that the llc to start a connection */void connect_request(llcptr lp){	if (lp->state == ADM)	{		lp->state = SETUP;		llc_interpret_pseudo_code(lp, ADM1, NULL, NO_FRAME);		if(lp->llc_callbacks)		{			lp->llc_event(lp);			lp->llc_callbacks=0;		}		/* 		 *	lp may be invalid after the callback		 */	}}/* *	Interpret_pseudo_code() executes the actions in the connection component *	state transition table. Table 4 in document on p88. * *	If this function is called to handle an incomming pdu, skb will point *	to the buffer with the pdu and type will contain the decoded pdu type. * *	If called by data_request skb points to an skb that was skb_alloc-ed by  *	the llc client to hold the information unit to be transmitted, there is *	no valid type in this case.   * *	If called because a timer expired no skb is passed, and there is no  *	type. */void llc_interpret_pseudo_code(llcptr lp, int pc_label, struct sk_buff *skb, 		char type){    	short int pc;	/* program counter in pseudo code array */ 	char p_flag_received;	frameptr fr;	int resend_count;   /* number of pdus resend by llc_resend_ipdu() */	int ack_count;      /* number of pdus acknowledged */	struct sk_buff *skb2;	if (skb != NULL) 	{		fr = (frameptr) skb->data;	}	else		fr = NULL;	pc = pseudo_code_idx[pc_label];	while(pseudo_code[pc])	{		switch(pseudo_code[pc])		{			case IF_F=1_CLEAR_REMOTE_BUSY:				if ((type != I_CMD) || (fr->i_hdr.i_pflag == 0))					break;			case CLEAR_REMOTE_BUSY:				lp->remote_busy = 0;				llc_stop_timer(lp, BUSY_TIMER);				if ((lp->state == NORMAL) ||					(lp->state == REJECT) ||					(lp->state == BUSY))				{					skb2 = llc_pull_from_atq(lp);					if (skb2 != NULL) 						llc_start_timer(lp, ACK_TIMER);					while (skb2 != NULL)					{						llc_sendipdu( lp, I_CMD, 0, skb2);						skb2 = llc_pull_from_atq(lp);					}				}	   				break;			case CONNECT_INDICATION:				lp->state = NORMAL;  /* needed to eliminate connect_response() */				lp->llc_mode = MODE_ABM;				lp->llc_callbacks|=LLC_CONN_INDICATION;				break;			case CONNECT_CONFIRM:				lp->llc_mode = MODE_ABM;				lp->llc_callbacks|=LLC_CONN_CONFIRM;				break;			case DATA_INDICATION:				skb_pull(skb, 4);				lp->inc_skb=skb;				lp->llc_callbacks|=LLC_DATA_INDIC;				break;			case DISCONNECT_INDICATION:				lp->llc_mode = MODE_ADM;				lp->llc_callbacks|=LLC_DISC_INDICATION;				break;			case RESET_INDICATION(LOCAL):				lp->llc_callbacks|=LLC_RESET_INDIC_LOC;				break;			case RESET_INDICATION(REMOTE):				lp->llc_callbacks|=LLC_RESET_INDIC_REM;				break;			case RESET_CONFIRM:				lp->llc_callbacks|=LLC_RST_CONFIRM;				break;			case REPORT_STATUS(FRMR_RECEIVED):				lp->llc_callbacks|=LLC_FRMR_RECV;				break;			case REPORT_STATUS(FRMR_SENT):				lp->llc_callbacks|=LLC_FRMR_SENT;				break;			case REPORT_STATUS(REMOTE_BUSY):				lp->llc_callbacks|=LLC_REMOTE_BUSY;				break;			case REPORT_STATUS(REMOTE_NOT_BUSY):				lp->llc_callbacks|=LLC_REMOTE_NOTBUSY;				break;			case SEND_DISC_CMD(P=X):				llc_sendpdu(lp, DISC_CMD, lp->f_flag, 0, NULL);				break;			case SEND_DM_RSP(F=X):				llc_sendpdu(lp, DM_RSP, 0, 0, NULL);				break;			case SEND_FRMR_RSP(F=X):                        				lp->frmr_info_fld.cntl1 = fr->pdu_cntl.byte1;				lp->frmr_info_fld.cntl2 = fr->pdu_cntl.byte2;				lp->frmr_info_fld.vs = lp->vs;				lp->frmr_info_fld.vr_cr = lp->vr;				llc_sendpdu(lp, FRMR_RSP, 0, 5, (char *) &lp->frmr_info_fld);				break;			case RE-SEND_FRMR_RSP(F=0):				llc_sendpdu(lp, FRMR_RSP, 0, 5, (char *) &lp->frmr_info_fld);				break;			case RE-SEND_FRMR_RSP(F=P):				llc_sendpdu(lp, FRMR_RSP, lp->p_flag,					5, (char *) &lp->frmr_info_fld);				break;			case SEND_I_CMD(P=1):				llc_sendipdu(lp, I_CMD, 1, skb);   				break;			case RE-SEND_I_CMD(P=1):				resend_count = llc_resend_ipdu(lp, fr->i_hdr.nr, I_CMD, 1);				break;			case RE-SEND_I_CMD(P=1)_OR_SEND_RR:				resend_count = llc_resend_ipdu(lp, fr->i_hdr.nr, I_CMD, 1);				if (resend_count == 0) 				{					llc_sendpdu(lp, RR_CMD, 1, 0, NULL);				}    				break;			case SEND_I_XXX(X=0):				llc_sendipdu(lp, I_CMD, 0, skb);   				break;			case RE-SEND_I_XXX(X=0):				resend_count = llc_resend_ipdu(lp, fr->i_hdr.nr, I_CMD, 0);				break;			case RE-SEND_I_XXX(X=0)_OR_SEND_RR:				resend_count = llc_resend_ipdu(lp, fr->i_hdr.nr, I_CMD, 0);				if (resend_count == 0) 				{					llc_sendpdu(lp, RR_CMD, 0, 0, NULL);				}    				break;			case RE-SEND_I_RSP(F=1):				resend_count = llc_resend_ipdu(lp, fr->i_hdr.nr, I_RSP, 1);				break;			case SEND_REJ_CMD(P=1):				llc_sendpdu(lp, REJ_CMD, 1, 0, NULL);				break;			case SEND_REJ_RSP(F=1):				llc_sendpdu(lp, REJ_RSP, 1, 0, NULL);				break;			case SEND_REJ_XXX(X=0):				if (IS_RSP(fr))					llc_sendpdu(lp, REJ_CMD, 0, 0, NULL);				else					llc_sendpdu(lp, REJ_RSP, 0, 0, NULL);				break;			case SEND_RNR_CMD(F=1):				llc_sendpdu(lp, RNR_CMD, 1, 0, NULL);				break;			case SEND_RNR_RSP(F=1):				llc_sendpdu(lp, RNR_RSP, 1, 0, NULL);				break;			case SEND_RNR_XXX(X=0):				if (IS_RSP(fr))					llc_sendpdu(lp, RNR_CMD, 0, 0, NULL);				else					llc_sendpdu(lp, RNR_RSP, 0, 0, NULL);				break;			case SET_REMOTE_BUSY:				if (lp->remote_busy == 0)				{					lp->remote_busy = 1;					llc_start_timer(lp, BUSY_TIMER);					lp->llc_callbacks|=LLC_REMOTE_BUSY;				}				else if (lp->timer_state[BUSY_TIMER] == TIMER_IDLE)				{					llc_start_timer(lp, BUSY_TIMER);				}				break;			case OPTIONAL_SEND_RNR_XXX(X=0):				if (IS_RSP(fr)) 					llc_sendpdu(lp, RNR_CMD, 0, 0, NULL);				else					llc_sendpdu(lp, RNR_RSP, 0, 0, NULL);				break;			case SEND_RR_CMD(P=1):				llc_sendpdu(lp, RR_CMD, 1, 0, NULL);				break;			case SEND_ACKNOWLEDGE_CMD(P=1):				llc_sendpdu(lp, RR_CMD, 1, 0, NULL);				break;			case SEND_RR_RSP(F=1):				llc_sendpdu(lp, RR_RSP, 1, 0, NULL);				break;			case SEND_ACKNOWLEDGE_RSP(F=1):				llc_sendpdu(lp, RR_RSP, 1, 0, NULL);				break;			case SEND_RR_XXX(X=0):				llc_sendpdu(lp, RR_RSP, 0, 0, NULL);				break;			case SEND_ACKNOWLEDGE_XXX(X=0):				if (IS_RSP(fr)) 					llc_sendpdu(lp, RR_CMD, 0, 0, NULL);				else					llc_sendpdu(lp, RR_RSP, 0, 0, NULL);				break;			case SEND_SABME_CMD(P=X):				llc_sendpdu(lp, SABME_CMD, 0, 0, NULL);				lp->f_flag = 0;				break;			case SEND_UA_RSP(F=X):				llc_sendpdu(lp, UA_RSP, lp->f_flag, 0, NULL);				break;			case S_FLAG:=0:				lp->s_flag = 0;				break;			case S_FLAG:=1:				lp->s_flag = 1;				break;			case START_P_TIMER:				if(lp->timer_state[P_TIMER] == TIMER_RUNNING)					llc_stop_timer(lp, P_TIMER);				llc_start_timer(lp, P_TIMER);				if (lp->p_flag == 0)				{					lp->retry_count = 0;					lp->p_flag = 1;				}				break;			case START_ACK_TIMER_IF_NOT_RUNNING:				if (lp->timer_state[ACK_TIMER] == TIMER_IDLE)					llc_start_timer(lp, ACK_TIMER);				break;			case START_ACK_TIMER:				llc_start_timer(lp, ACK_TIMER);				break;			case START_REJ_TIMER:				llc_start_timer(lp, REJ_TIMER);				break;			case STOP_ACK_TIMER:				llc_stop_timer(lp, ACK_TIMER);				break;			case STOP_P_TIMER:				llc_stop_timer(lp, ACK_TIMER);				lp->p_flag = 0;				break;			case IF_DATA_FLAG=2_STOP_REJ_TIMER:				if (lp->data_flag == 2)					llc_stop_timer(lp, REJ_TIMER);				break;			case STOP_REJ_TIMER:				llc_stop_timer(lp, REJ_TIMER);				break;			case STOP_ALL_TIMERS:				llc_stop_timer(lp, ACK_TIMER);				llc_stop_timer(lp, P_TIMER);				llc_stop_timer(lp, REJ_TIMER);				llc_stop_timer(lp, BUSY_TIMER);				break;			case STOP_OTHER_TIMERS:				llc_stop_timer(lp, P_TIMER);				llc_stop_timer(lp, REJ_TIMER);				llc_stop_timer(lp, BUSY_TIMER);				break;			case UPDATE_N(R)_RECEIVED:             				ack_count = llc_free_acknowledged_skbs(lp,					(unsigned char) fr->s_hdr.nr);				if (ack_count > 0)				{					lp->retry_count = 0;					llc_stop_timer(lp, ACK_TIMER);  					if (skb_peek(&lp->rtq) != NULL)					{						/* 						 *	Re-transmit queue not empty 						 */						llc_start_timer(lp, ACK_TIMER);  					}				}        				break;			case UPDATE_P_FLAG:				if (IS_UFRAME(fr)) 					p_flag_received = fr->u_hdr.u_pflag;				else					p_flag_received = fr->i_hdr.i_pflag;				if ((fr->pdu_hdr.ssap & 0x01) && (p_flag_received))				{					lp->p_flag = 0;					llc_stop_timer(lp, P_TIMER);  				}				break;			case DATA_FLAG:=2:				lp->data_flag = 2;				break;			case DATA_FLAG:=0:				lp->data_flag = 0;				break;			case DATA_FLAG:=1:				lp->data_flag = 1;				break;			case IF_DATA_FLAG_=0_THEN_DATA_FLAG:=1:				if (lp->data_flag == 0)					lp->data_flag = 1;				break;			case P_FLAG:=0:				lp->p_flag = 0;				break;			case P_FLAG:=P:				lp->p_flag = lp->f_flag;				break;			case REMOTE_BUSY:=0:				lp->remote_busy = 0;				break;			case RETRY_COUNT:=0:				lp->retry_count = 0;				break;			case RETRY_COUNT:=RETRY_COUNT+1:				lp->retry_count++;				break;			case V(R):=0:				lp->vr = 0;				break;			case V(R):=V(R)+1:				lp->vr++;				break;			case V(S):=0:				lp->vs = 0;				break;			case V(S):=N(R):				lp->vs = fr->i_hdr.nr;				break;			case F_FLAG:=P:				if (IS_UFRAME(fr)) 					lp->f_flag = fr->u_hdr.u_pflag;				else					lp->f_flag = fr->i_hdr.i_pflag;				break;			default:		}		pc++;		}}/* *	Process_otype2_frame will handle incoming frames *	for 802.2 Type 2 Procedure. */void llc_process_otype2_frame(llcptr lp, struct sk_buff *skb, char type){	int idx;		/*	index in transition table */	int pc_label;		/*	action to perform, from tr tbl */	int validation;		/*	result of validate_seq_nos */	int p_flag_received;	/*	p_flag in received frame */	frameptr fr;	fr = (frameptr) skb->data;	if (IS_UFRAME(fr))		p_flag_received = fr->u_hdr.u_pflag;	else		p_flag_received = fr->i_hdr.i_pflag;	switch(lp->state)	{		/*	Compute index in transition table: */		case ADM:			idx = type;			idx = (idx << 1) + p_flag_received;			break;		case CONN:		case RESET_WAIT:		case RESET_CHECK:		case ERROR:			idx = type;			break;		case SETUP:		case RESET:		case D_CONN:			idx = type;			idx = (idx << 1) + lp->p_flag;			break;		case NORMAL:		case BUSY:		case REJECT:		case AWAIT:		case AWAIT_BUSY:		case AWAIT_REJECT:			validation = llc_validate_seq_nos(lp, fr);			if (validation > 3) 				type = BAD_FRAME;			idx = type;			idx = (idx << 1);			if (validation & 1) 				idx = idx +1;			idx = (idx << 1) + p_flag_received;			idx = (idx << 1) + lp->p_flag;		default:			printk("llc_proc: bad state\n");			return;	}	idx = (idx << 1) + pdutr_offset[lp->state];	lp->state = pdutr_entry[idx +1]; 	pc_label = pdutr_entry[idx];	if (pc_label != NOP)	{ 		llc_interpret_pseudo_code(lp, pc_label, skb, type);		if(lp->llc_callbacks)		{			lp->llc_event(lp);			lp->llc_callbacks=0;		}		/* 		 *	lp may no longer be valid after this point. Be		 *	careful what is added!		 */	}}void llc_timer_expired(llcptr lp, int t){	int idx;		/* index in transition table	*/	int pc_label;       	/* action to perform, from tr tbl */	lp->timer_state[t] = TIMER_EXPIRED;	idx = lp->state;            /* Compute index in transition table: */	idx = (idx << 2) + t;	idx = idx << 1;	if (lp->retry_count >= lp->n2) 		idx = idx + 1;	idx = (idx << 1) + lp->s_flag;	idx = (idx << 1) + lp->p_flag;	idx = idx << 1;             /* 2 bytes per entry: action & newstate */	pc_label = timertr_entry[idx];	if (pc_label != NOP)	{		llc_interpret_pseudo_code(lp, pc_label, NULL, NO_FRAME);		lp->state = timertr_entry[idx +1];	}	lp->timer_state[t] = TIMER_IDLE;	if(lp->llc_callbacks)	{		lp->llc_event(lp);		lp->llc_callbacks=0;	}	/* 	 *	And lp may have vanished in the event callback 	 */}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -