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

📄 irlmp_event.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/********************************************************************* * * Filename:      irlmp_event.c * Version:       0.8 * Description:   An IrDA LMP event driver for Linux * Status:        Experimental. * Author:        Dag Brattli <dagb@cs.uit.no> * Created at:    Mon Aug  4 20:40:53 1997 * Modified at:   Tue Dec 14 23:04:16 1999 * Modified by:   Dag Brattli <dagb@cs.uit.no> * *     Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, *     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/kernel.h>#include <net/irda/irda.h>#include <net/irda/timer.h>#include <net/irda/irlap.h>#include <net/irda/irlmp.h>#include <net/irda/irlmp_frame.h>#include <net/irda/irlmp_event.h>const char *irlmp_state[] = {	"LAP_STANDBY",	"LAP_U_CONNECT",	"LAP_ACTIVE",};const char *irlsap_state[] = {	"LSAP_DISCONNECTED",	"LSAP_CONNECT",	"LSAP_CONNECT_PEND",	"LSAP_DATA_TRANSFER_READY",	"LSAP_SETUP",	"LSAP_SETUP_PEND",};#ifdef CONFIG_IRDA_DEBUGstatic const char *irlmp_event[] = {	"LM_CONNECT_REQUEST",	"LM_CONNECT_CONFIRM",	"LM_CONNECT_RESPONSE",	"LM_CONNECT_INDICATION",	"LM_DISCONNECT_INDICATION",	"LM_DISCONNECT_REQUEST",	"LM_DATA_REQUEST",	"LM_UDATA_REQUEST",	"LM_DATA_INDICATION",	"LM_UDATA_INDICATION",	"LM_WATCHDOG_TIMEOUT",	/* IrLAP events */	"LM_LAP_CONNECT_REQUEST",	"LM_LAP_CONNECT_INDICATION",	"LM_LAP_CONNECT_CONFIRM",	"LM_LAP_DISCONNECT_INDICATION",	"LM_LAP_DISCONNECT_REQUEST",	"LM_LAP_DISCOVERY_REQUEST",	"LM_LAP_DISCOVERY_CONFIRM",	"LM_LAP_IDLE_TIMEOUT",};#endif	/* CONFIG_IRDA_DEBUG *//* LAP Connection control proto declarations */static void irlmp_state_standby  (struct lap_cb *, IRLMP_EVENT,				  struct sk_buff *);static void irlmp_state_u_connect(struct lap_cb *, IRLMP_EVENT,				  struct sk_buff *);static void irlmp_state_active   (struct lap_cb *, IRLMP_EVENT,				  struct sk_buff *);/* LSAP Connection control proto declarations */static int irlmp_state_disconnected(struct lsap_cb *, IRLMP_EVENT,				    struct sk_buff *);static int irlmp_state_connect     (struct lsap_cb *, IRLMP_EVENT,				    struct sk_buff *);static int irlmp_state_connect_pend(struct lsap_cb *, IRLMP_EVENT,				    struct sk_buff *);static int irlmp_state_dtr         (struct lsap_cb *, IRLMP_EVENT,				    struct sk_buff *);static int irlmp_state_setup       (struct lsap_cb *, IRLMP_EVENT,				    struct sk_buff *);static int irlmp_state_setup_pend  (struct lsap_cb *, IRLMP_EVENT,				    struct sk_buff *);static void (*lap_state[]) (struct lap_cb *, IRLMP_EVENT, struct sk_buff *) ={	irlmp_state_standby,	irlmp_state_u_connect,	irlmp_state_active,};static int (*lsap_state[])( struct lsap_cb *, IRLMP_EVENT, struct sk_buff *) ={	irlmp_state_disconnected,	irlmp_state_connect,	irlmp_state_connect_pend,	irlmp_state_dtr,	irlmp_state_setup,	irlmp_state_setup_pend};static inline void irlmp_next_lap_state(struct lap_cb *self,					IRLMP_STATE state){	/*	IRDA_DEBUG(4, "%s(), LMP LAP = %s\n", __FUNCTION__, irlmp_state[state]);	*/	self->lap_state = state;}static inline void irlmp_next_lsap_state(struct lsap_cb *self,					 LSAP_STATE state){	/*	IRDA_ASSERT(self != NULL, return;);	IRDA_DEBUG(4, "%s(), LMP LSAP = %s\n", __FUNCTION__, irlsap_state[state]);	*/	self->lsap_state = state;}/* Do connection control events */int irlmp_do_lsap_event(struct lsap_cb *self, IRLMP_EVENT event,			struct sk_buff *skb){	IRDA_ASSERT(self != NULL, return -1;);	IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);	IRDA_DEBUG(4, "%s(), EVENT = %s, STATE = %s\n",		__FUNCTION__, irlmp_event[event], irlsap_state[ self->lsap_state]);	return (*lsap_state[self->lsap_state]) (self, event, skb);}/* * Function do_lap_event (event, skb, info) * *    Do IrLAP control events * */void irlmp_do_lap_event(struct lap_cb *self, IRLMP_EVENT event,			struct sk_buff *skb){	IRDA_ASSERT(self != NULL, return;);	IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;);	IRDA_DEBUG(4, "%s(), EVENT = %s, STATE = %s\n", __FUNCTION__,		   irlmp_event[event],		   irlmp_state[self->lap_state]);	(*lap_state[self->lap_state]) (self, event, skb);}void irlmp_discovery_timer_expired(void *data){	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);	/* We always cleanup the log (active & passive discovery) */	irlmp_do_expiry();	/* Active discovery is conditional */	if (sysctl_discovery)		irlmp_do_discovery(sysctl_discovery_slots);	/* Restart timer */	irlmp_start_discovery_timer(irlmp, sysctl_discovery_timeout * HZ);}void irlmp_watchdog_timer_expired(void *data){	struct lsap_cb *self = (struct lsap_cb *) data;	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);	IRDA_ASSERT(self != NULL, return;);	IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return;);	irlmp_do_lsap_event(self, LM_WATCHDOG_TIMEOUT, NULL);}void irlmp_idle_timer_expired(void *data){	struct lap_cb *self = (struct lap_cb *) data;	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);	IRDA_ASSERT(self != NULL, return;);	IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;);	irlmp_do_lap_event(self, LM_LAP_IDLE_TIMEOUT, NULL);}/* * Send an event on all LSAPs attached to this LAP. */static inline voidirlmp_do_all_lsap_event(hashbin_t *	lsap_hashbin,			IRLMP_EVENT	event){	struct lsap_cb *lsap;	struct lsap_cb *lsap_next;	/* Note : this function use the new hashbin_find_next()	 * function, instead of the old hashbin_get_next().	 * This make sure that we are always pointing one lsap	 * ahead, so that if the current lsap is removed as the	 * result of sending the event, we don't care.	 * Also, as we store the context ourselves, if an enumeration	 * of the same lsap hashbin happens as the result of sending the	 * event, we don't care.	 * The only problem is if the next lsap is removed. In that case,	 * hashbin_find_next() will return NULL and we will abort the	 * enumeration. - Jean II */	/* Also : we don't accept any skb in input. We can *NOT* pass	 * the same skb to multiple clients safely, we would need to	 * skb_clone() it. - Jean II */	lsap = (struct lsap_cb *) hashbin_get_first(lsap_hashbin);	while (NULL != hashbin_find_next(lsap_hashbin,					 (long) lsap,					 NULL,					 (void *) &lsap_next) ) {		irlmp_do_lsap_event(lsap, event, NULL);		lsap = lsap_next;	}}/********************************************************************* * *    LAP connection control states * ********************************************************************//* * Function irlmp_state_standby (event, skb, info) * *    STANDBY, The IrLAP connection does not exist. * */static void irlmp_state_standby(struct lap_cb *self, IRLMP_EVENT event,				struct sk_buff *skb){	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);	IRDA_ASSERT(self->irlap != NULL, return;);	switch (event) {	case LM_LAP_DISCOVERY_REQUEST:		/* irlmp_next_station_state( LMP_DISCOVER); */		irlap_discovery_request(self->irlap, &irlmp->discovery_cmd);		break;	case LM_LAP_CONNECT_INDICATION:		/*  It's important to switch state first, to avoid IrLMP to		 *  think that the link is free since IrLMP may then start		 *  discovery before the connection is properly set up. DB.		 */		irlmp_next_lap_state(self, LAP_ACTIVE);		/* Just accept connection TODO, this should be fixed */		irlap_connect_response(self->irlap, skb);		break;	case LM_LAP_CONNECT_REQUEST:		IRDA_DEBUG(4, "%s() LS_CONNECT_REQUEST\n", __FUNCTION__);		irlmp_next_lap_state(self, LAP_U_CONNECT);		/* FIXME: need to set users requested QoS */		irlap_connect_request(self->irlap, self->daddr, NULL, 0);		break;	case LM_LAP_DISCONNECT_INDICATION:		IRDA_DEBUG(4, "%s(), Error LM_LAP_DISCONNECT_INDICATION\n",			   __FUNCTION__);		irlmp_next_lap_state(self, LAP_STANDBY);		break;	default:		IRDA_DEBUG(0, "%s(), Unknown event %s\n",			   __FUNCTION__, irlmp_event[event]);		break;	}}/* * Function irlmp_state_u_connect (event, skb, info) * *    U_CONNECT, The layer above has tried to open an LSAP connection but *    since the IrLAP connection does not exist, we must first start an *    IrLAP connection. We are now waiting response from IrLAP. * */static void irlmp_state_u_connect(struct lap_cb *self, IRLMP_EVENT event,				  struct sk_buff *skb){	IRDA_DEBUG(2, "%s(), event=%s\n", __FUNCTION__, irlmp_event[event]);	switch (event) {	case LM_LAP_CONNECT_INDICATION:		/*  It's important to switch state first, to avoid IrLMP to		 *  think that the link is free since IrLMP may then start		 *  discovery before the connection is properly set up. DB.		 */		irlmp_next_lap_state(self, LAP_ACTIVE);		/* Just accept connection TODO, this should be fixed */		irlap_connect_response(self->irlap, skb);		/* Tell LSAPs that they can start sending data */		irlmp_do_all_lsap_event(self->lsaps, LM_LAP_CONNECT_CONFIRM);		/* Note : by the time we get there (LAP retries and co),		 * the lsaps may already have gone. This avoid getting stuck		 * forever in LAP_ACTIVE state - Jean II */		if (HASHBIN_GET_SIZE(self->lsaps) == 0) {			IRDA_DEBUG(0, "%s() NO LSAPs !\n",  __FUNCTION__);			irlmp_start_idle_timer(self, LM_IDLE_TIMEOUT);		}		break;	case LM_LAP_CONNECT_REQUEST:		/* Already trying to connect */		break;	case LM_LAP_CONNECT_CONFIRM:		/* For all lsap_ce E Associated do LS_Connect_confirm */		irlmp_next_lap_state(self, LAP_ACTIVE);		/* Tell LSAPs that they can start sending data */		irlmp_do_all_lsap_event(self->lsaps, LM_LAP_CONNECT_CONFIRM);		/* Note : by the time we get there (LAP retries and co),		 * the lsaps may already have gone. This avoid getting stuck		 * forever in LAP_ACTIVE state - Jean II */		if (HASHBIN_GET_SIZE(self->lsaps) == 0) {			IRDA_DEBUG(0, "%s() NO LSAPs !\n",  __FUNCTION__);			irlmp_start_idle_timer(self, LM_IDLE_TIMEOUT);		}		break;	case LM_LAP_DISCONNECT_INDICATION:		IRDA_DEBUG(4, "%s(), LM_LAP_DISCONNECT_INDICATION\n",  __FUNCTION__);		irlmp_next_lap_state(self, LAP_STANDBY);		/* Send disconnect event to all LSAPs using this link */		irlmp_do_all_lsap_event(self->lsaps,					LM_LAP_DISCONNECT_INDICATION);		break;	case LM_LAP_DISCONNECT_REQUEST:		IRDA_DEBUG(4, "%s(), LM_LAP_DISCONNECT_REQUEST\n",  __FUNCTION__);		/* One of the LSAP did timeout or was closed, if it was		 * the last one, try to get out of here - Jean II */		if (HASHBIN_GET_SIZE(self->lsaps) <= 1) {			irlap_disconnect_request(self->irlap);		}		break;	default:		IRDA_DEBUG(0, "%s(), Unknown event %s\n",			 __FUNCTION__, irlmp_event[event]);		break;	}}/* * Function irlmp_state_active (event, skb, info) * *    ACTIVE, IrLAP connection is active * */static void irlmp_state_active(struct lap_cb *self, IRLMP_EVENT event,			       struct sk_buff *skb){	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);	switch (event) {	case LM_LAP_CONNECT_REQUEST:		IRDA_DEBUG(4, "%s(), LS_CONNECT_REQUEST\n", __FUNCTION__);		/*		 * IrLAP may have a pending disconnect. We tried to close		 * IrLAP, but it was postponed because the link was		 * busy or we were still sending packets. As we now		 * need it, make sure it stays on. Jean II		 */		irlap_clear_disconnect(self->irlap);		/*		 *  LAP connection already active, just bounce back! Since we		 *  don't know which LSAP that tried to do this, we have to		 *  notify all LSAPs using this LAP, but that should be safe to		 *  do anyway.		 */		irlmp_do_all_lsap_event(self->lsaps, LM_LAP_CONNECT_CONFIRM);		/* Needed by connect indication */		irlmp_do_all_lsap_event(irlmp->unconnected_lsaps,					LM_LAP_CONNECT_CONFIRM);		/* Keep state */		break;	case LM_LAP_DISCONNECT_REQUEST:		/*		 *  Need to find out if we should close IrLAP or not. If there		 *  is only one LSAP connection left on this link, that LSAP		 *  must be the one that tries to close IrLAP. It will be		 *  removed later and moved to the list of unconnected LSAPs		 */		if (HASHBIN_GET_SIZE(self->lsaps) > 0) {			/* Timer value is checked in irsysctl - Jean II */			irlmp_start_idle_timer(self, sysctl_lap_keepalive_time * HZ / 1000);		} else {			/* No more connections, so close IrLAP */			/* We don't want to change state just yet, because			 * we want to reflect accurately the real state of			 * the LAP, not the state we wish it was in,			 * so that we don't lose LM_LAP_CONNECT_REQUEST.			 * In some cases, IrLAP won't close the LAP			 * immediately. For example, it might still be			 * retrying packets or waiting for the pf bit.			 * As the LAP always send a DISCONNECT_INDICATION			 * in PCLOSE or SCLOSE, just change state on that.			 * Jean II */			irlap_disconnect_request(self->irlap);		}		break;	case LM_LAP_IDLE_TIMEOUT:		if (HASHBIN_GET_SIZE(self->lsaps) == 0) {			/* Same reasoning as above - keep state */			irlap_disconnect_request(self->irlap);		}		break;	case LM_LAP_DISCONNECT_INDICATION:		irlmp_next_lap_state(self, LAP_STANDBY);		/* In some case, at this point our side has already closed		 * all lsaps, and we are waiting for the idle_timer to		 * expire. If another device reconnect immediately, the		 * idle timer will expire in the midle of the connection		 * initialisation, screwing up things a lot...		 * Therefore, we must stop the timer... */		irlmp_stop_idle_timer(self);		/*

⌨️ 快捷键说明

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