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

📄 irlap_event.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/********************************************************************* * * Filename:      irlap_event.c * Version:       0.9 * Description:   IrLAP state machine implementation * Status:        Experimental. * Author:        Dag Brattli <dag@brattli.net> * Created at:    Sat Aug 16 00:59:29 1997 * Modified at:   Sat Dec 25 21:07:57 1999 * Modified by:   Dag Brattli <dag@brattli.net> * *     Copyright (c) 1998-2000 Dag Brattli <dag@brattli.net>, *     Copyright (c) 1998      Thomas Davis <ratbert@radiks.net> *     All Rights Reserved. *     Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.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. * *     Neither Dag Brattli nor University of Tromsø admit liability nor *     provide warranty for any of this software. This material is *     provided "AS-IS" and at no charge. * ********************************************************************/#include <linux/string.h>#include <linux/kernel.h>#include <linux/delay.h>#include <linux/skbuff.h>#include <net/irda/irda.h>#include <net/irda/irlap_event.h>#include <net/irda/timer.h>#include <net/irda/irlap.h>#include <net/irda/irlap_frame.h>#include <net/irda/qos.h>#include <net/irda/parameters.h>#include <net/irda/irlmp.h>		/* irlmp_flow_indication(), ... */#include <net/irda/irda_device.h>#ifdef CONFIG_IRDA_FAST_RRint sysctl_fast_poll_increase = 50;#endifstatic int irlap_state_ndm    (struct irlap_cb *self, IRLAP_EVENT event,			       struct sk_buff *skb, struct irlap_info *info);static int irlap_state_query  (struct irlap_cb *self, IRLAP_EVENT event,			       struct sk_buff *skb, struct irlap_info *info);static int irlap_state_reply  (struct irlap_cb *self, IRLAP_EVENT event,			       struct sk_buff *skb, struct irlap_info *info);static int irlap_state_conn   (struct irlap_cb *self, IRLAP_EVENT event,			       struct sk_buff *skb, struct irlap_info *info);static int irlap_state_setup  (struct irlap_cb *self, IRLAP_EVENT event,			       struct sk_buff *skb, struct irlap_info *info);static int irlap_state_offline(struct irlap_cb *self, IRLAP_EVENT event,			       struct sk_buff *skb, struct irlap_info *info);static int irlap_state_xmit_p (struct irlap_cb *self, IRLAP_EVENT event,			       struct sk_buff *skb, struct irlap_info *info);static int irlap_state_pclose (struct irlap_cb *self, IRLAP_EVENT event,			       struct sk_buff *skb, struct irlap_info *info);static int irlap_state_nrm_p  (struct irlap_cb *self, IRLAP_EVENT event,			       struct sk_buff *skb, struct irlap_info *info);static int irlap_state_reset_wait(struct irlap_cb *self, IRLAP_EVENT event,				  struct sk_buff *skb, struct irlap_info *info);static int irlap_state_reset  (struct irlap_cb *self, IRLAP_EVENT event,			       struct sk_buff *skb, struct irlap_info *info);static int irlap_state_nrm_s  (struct irlap_cb *self, IRLAP_EVENT event,			       struct sk_buff *skb, struct irlap_info *info);static int irlap_state_xmit_s (struct irlap_cb *self, IRLAP_EVENT event,			       struct sk_buff *skb, struct irlap_info *info);static int irlap_state_sclose (struct irlap_cb *self, IRLAP_EVENT event,			       struct sk_buff *skb, struct irlap_info *info);static int irlap_state_reset_check(struct irlap_cb *, IRLAP_EVENT event,				   struct sk_buff *, struct irlap_info *);#ifdef CONFIG_IRDA_DEBUGstatic const char *irlap_event[] = {	"DISCOVERY_REQUEST",	"CONNECT_REQUEST",	"CONNECT_RESPONSE",	"DISCONNECT_REQUEST",	"DATA_REQUEST",	"RESET_REQUEST",	"RESET_RESPONSE",	"SEND_I_CMD",	"SEND_UI_FRAME",	"RECV_DISCOVERY_XID_CMD",	"RECV_DISCOVERY_XID_RSP",	"RECV_SNRM_CMD",	"RECV_TEST_CMD",	"RECV_TEST_RSP",	"RECV_UA_RSP",	"RECV_DM_RSP",	"RECV_RD_RSP",	"RECV_I_CMD",	"RECV_I_RSP",	"RECV_UI_FRAME",	"RECV_FRMR_RSP",	"RECV_RR_CMD",	"RECV_RR_RSP",	"RECV_RNR_CMD",	"RECV_RNR_RSP",	"RECV_REJ_CMD",	"RECV_REJ_RSP",	"RECV_SREJ_CMD",	"RECV_SREJ_RSP",	"RECV_DISC_CMD",	"SLOT_TIMER_EXPIRED",	"QUERY_TIMER_EXPIRED",	"FINAL_TIMER_EXPIRED",	"POLL_TIMER_EXPIRED",	"DISCOVERY_TIMER_EXPIRED",	"WD_TIMER_EXPIRED",	"BACKOFF_TIMER_EXPIRED",	"MEDIA_BUSY_TIMER_EXPIRED",};#endif	/* CONFIG_IRDA_DEBUG */const char *irlap_state[] = {	"LAP_NDM",	"LAP_QUERY",	"LAP_REPLY",	"LAP_CONN",	"LAP_SETUP",	"LAP_OFFLINE",	"LAP_XMIT_P",	"LAP_PCLOSE",	"LAP_NRM_P",	"LAP_RESET_WAIT",	"LAP_RESET",	"LAP_NRM_S",	"LAP_XMIT_S",	"LAP_SCLOSE",	"LAP_RESET_CHECK",};static int (*state[])(struct irlap_cb *self, IRLAP_EVENT event,		      struct sk_buff *skb, struct irlap_info *info) ={	irlap_state_ndm,	irlap_state_query,	irlap_state_reply,	irlap_state_conn,	irlap_state_setup,	irlap_state_offline,	irlap_state_xmit_p,	irlap_state_pclose,	irlap_state_nrm_p,	irlap_state_reset_wait,	irlap_state_reset,	irlap_state_nrm_s,	irlap_state_xmit_s,	irlap_state_sclose,	irlap_state_reset_check,};/* * Function irda_poll_timer_expired (data) * *    Poll timer has expired. Normally we must now send a RR frame to the *    remote device */static void irlap_poll_timer_expired(void *data){	struct irlap_cb *self = (struct irlap_cb *) data;	IRDA_ASSERT(self != NULL, return;);	IRDA_ASSERT(self->magic == LAP_MAGIC, return;);	irlap_do_event(self, POLL_TIMER_EXPIRED, NULL, NULL);}/* * Calculate and set time before we will have to send back the pf bit * to the peer. Use in primary. * Make sure that state is XMIT_P/XMIT_S when calling this function * (and that nobody messed up with the state). - Jean II */static void irlap_start_poll_timer(struct irlap_cb *self, int timeout){	IRDA_ASSERT(self != NULL, return;);	IRDA_ASSERT(self->magic == LAP_MAGIC, return;);#ifdef CONFIG_IRDA_FAST_RR	/*	 * Send out the RR frames faster if our own transmit queue is empty, or	 * if the peer is busy. The effect is a much faster conversation	 */	if (skb_queue_empty(&self->txq) || self->remote_busy) {		if (self->fast_RR == TRUE) {			/*			 *  Assert that the fast poll timer has not reached the			 *  normal poll timer yet			 */			if (self->fast_RR_timeout < timeout) {				/*				 *  FIXME: this should be a more configurable				 *         function				 */				self->fast_RR_timeout +=					(sysctl_fast_poll_increase * HZ/1000);				/* Use this fast(er) timeout instead */				timeout = self->fast_RR_timeout;			}		} else {			self->fast_RR = TRUE;			/* Start with just 0 ms */			self->fast_RR_timeout = 0;			timeout = 0;		}	} else		self->fast_RR = FALSE;	IRDA_DEBUG(3, "%s(), timeout=%d (%ld)\n", __FUNCTION__, timeout, jiffies);#endif /* CONFIG_IRDA_FAST_RR */	if (timeout == 0)		irlap_do_event(self, POLL_TIMER_EXPIRED, NULL, NULL);	else		irda_start_timer(&self->poll_timer, timeout, self,				 irlap_poll_timer_expired);}/* * Function irlap_do_event (event, skb, info) * *    Rushes through the state machine without any delay. If state == XMIT *    then send queued data frames. */void irlap_do_event(struct irlap_cb *self, IRLAP_EVENT event,		    struct sk_buff *skb, struct irlap_info *info){	int ret;	if (!self || self->magic != LAP_MAGIC)		return;	IRDA_DEBUG(3, "%s(), event = %s, state = %s\n", __FUNCTION__,		   irlap_event[event], irlap_state[self->state]);	ret = (*state[self->state])(self, event, skb, info);	/*	 *  Check if there are any pending events that needs to be executed	 */	switch (self->state) {	case LAP_XMIT_P: /* FALLTHROUGH */	case LAP_XMIT_S:		/*		 * We just received the pf bit and are at the beginning		 * of a new LAP transmit window.		 * Check if there are any queued data frames, and do not		 * try to disconnect link if we send any data frames, since		 * that will change the state away form XMIT		 */		IRDA_DEBUG(2, "%s() : queue len = %d\n", __FUNCTION__,			   skb_queue_len(&self->txq));		if (!skb_queue_empty(&self->txq)) {			/* Prevent race conditions with irlap_data_request() */			self->local_busy = TRUE;			/* Theory of operation.			 * We send frames up to when we fill the window or			 * reach line capacity. Those frames will queue up			 * in the device queue, and the driver will slowly			 * send them.			 * After each frame that we send, we poll the higher			 * layer for more data. It's the right time to do			 * that because the link layer need to perform the mtt			 * and then send the first frame, so we can afford			 * to send a bit of time in kernel space.			 * The explicit flow indication allow to minimise			 * buffers (== lower latency), to avoid higher layer			 * polling via timers (== less context switches) and			 * to implement a crude scheduler - Jean II */			/* Try to send away all queued data frames */			while ((skb = skb_dequeue(&self->txq)) != NULL) {				/* Send one frame */				ret = (*state[self->state])(self, SEND_I_CMD,							    skb, NULL);				/* Drop reference count.				 * It will be increase as needed in				 * irlap_send_data_xxx() */				kfree_skb(skb);				/* Poll the higher layers for one more frame */				irlmp_flow_indication(self->notify.instance,						      FLOW_START);				if (ret == -EPROTO)					break; /* Try again later! */			}			/* Finished transmitting */			self->local_busy = FALSE;		} else if (self->disconnect_pending) {			self->disconnect_pending = FALSE;			ret = (*state[self->state])(self, DISCONNECT_REQUEST,						    NULL, NULL);		}		break;/*	case LAP_NDM: *//*	case LAP_CONN: *//*	case LAP_RESET_WAIT: *//*	case LAP_RESET_CHECK: */	default:		break;	}}/* * Function irlap_state_ndm (event, skb, frame) * *    NDM (Normal Disconnected Mode) state * */static int irlap_state_ndm(struct irlap_cb *self, IRLAP_EVENT event,			   struct sk_buff *skb, struct irlap_info *info){	discovery_t *discovery_rsp;	int ret = 0;	IRDA_ASSERT(self != NULL, return -1;);	IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;);	switch (event) {	case CONNECT_REQUEST:		IRDA_ASSERT(self->netdev != NULL, return -1;);		if (self->media_busy) {			/* Note : this will never happen, because we test			 * media busy in irlap_connect_request() and			 * postpone the event... - Jean II */			IRDA_DEBUG(0, "%s(), CONNECT_REQUEST: media busy!\n",				   __FUNCTION__);			/* Always switch state before calling upper layers */			irlap_next_state(self, LAP_NDM);			irlap_disconnect_indication(self, LAP_MEDIA_BUSY);		} else {			irlap_send_snrm_frame(self, &self->qos_rx);			/* Start Final-bit timer */			irlap_start_final_timer(self, self->final_timeout);			self->retry_count = 0;			irlap_next_state(self, LAP_SETUP);		}		break;	case RECV_SNRM_CMD:		/* Check if the frame contains and I field */		if (info) {			self->daddr = info->daddr;			self->caddr = info->caddr;			irlap_next_state(self, LAP_CONN);			irlap_connect_indication(self, skb);		} else {			IRDA_DEBUG(0, "%s(), SNRM frame does not "				   "contain an I field!\n", __FUNCTION__);		}		break;	case DISCOVERY_REQUEST:		IRDA_ASSERT(info != NULL, return -1;);		if (self->media_busy) {			IRDA_DEBUG(1, "%s(), DISCOVERY_REQUEST: media busy!\n",				   __FUNCTION__);			/* irlap->log.condition = MEDIA_BUSY; */			/* This will make IrLMP try again */			irlap_discovery_confirm(self, NULL);			/* Note : the discovery log is not cleaned up here,			 * it will be done in irlap_discovery_request()			 * Jean II */			return 0;		}		self->S = info->S;		self->s = info->s;		irlap_send_discovery_xid_frame(self, info->S, info->s, TRUE,					       info->discovery);		self->frame_sent = FALSE;		self->s++;		irlap_start_slot_timer(self, self->slot_timeout);		irlap_next_state(self, LAP_QUERY);		break;	case RECV_DISCOVERY_XID_CMD:		IRDA_ASSERT(info != NULL, return -1;);		/* Assert that this is not the final slot */		if (info->s <= info->S) {			self->slot = irlap_generate_rand_time_slot(info->S,								   info->s);			if (self->slot == info->s) {				discovery_rsp = irlmp_get_discovery_response();				discovery_rsp->data.daddr = info->daddr;				irlap_send_discovery_xid_frame(self, info->S,							       self->slot,							       FALSE,							       discovery_rsp);				self->frame_sent = TRUE;			} else				self->frame_sent = FALSE;			/*			 * Go to reply state until end of discovery to			 * inhibit our own transmissions. Set the timer			 * to not stay forever there... Jean II			 */			irlap_start_query_timer(self, info->S, info->s);			irlap_next_state(self, LAP_REPLY);		} else {		/* This is the final slot. How is it possible ?		 * This would happen is both discoveries are just slightly		 * offset (if they are in sync, all packets are lost).		 * Most often, all the discovery requests will be received		 * in QUERY state (see my comment there), except for the		 * last frame that will come here.		 * The big trouble when it happen is that active discovery		 * doesn't happen, because nobody answer the discoveries		 * frame of the other guy, so the log shows up empty.		 * What should we do ?		 * Not much. It's too late to answer those discovery frames,		 * so we just pass the info to IrLMP who will put it in the		 * log (and post an event).		 * Another cause would be devices that do discovery much		 * slower than us, however the latest fixes should minimise		 * those cases...		 * Jean II		 */			IRDA_DEBUG(1, "%s(), Receiving final discovery request, missed the discovery slots :-(\n", __FUNCTION__);			/* Last discovery request -> in the log */			irlap_discovery_indication(self, info->discovery);		}		break;	case MEDIA_BUSY_TIMER_EXPIRED:		/* A bunch of events may be postponed because the media is		 * busy (usually immediately after we close a connection),		 * or while we are doing discovery (state query/reply).		 * In all those cases, the media busy flag will be cleared		 * when it's OK for us to process those postponed events.		 * This event is not mentioned in the state machines in the		 * IrLAP spec. It's because they didn't consider Ultra and		 * postponing connection request is optional.		 * Jean II */

⌨️ 快捷键说明

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