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

📄 irlap.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/********************************************************************* * * Filename:      irlap.c * Version:       1.0 * Description:   IrLAP implementation for Linux * Status:        Stable * Author:        Dag Brattli <dagb@cs.uit.no> * Created at:    Mon Aug  4 20:40:53 1997 * Modified at:   Tue Dec 14 09:26:44 1999 * Modified by:   Dag Brattli <dagb@cs.uit.no> * *     Copyright (c) 1998-1999 Dag Brattli, 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. * *     This program is distributed in the hope that it will be useful, *     but WITHOUT ANY WARRANTY; without even the implied warranty of *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *     GNU General Public License for more details. * *     You should have received a copy of the GNU General Public License *     along with this program; if not, write to the Free Software *     Foundation, Inc., 59 Temple Place, Suite 330, Boston, *     MA 02111-1307 USA * ********************************************************************/#include <linux/slab.h>#include <linux/string.h>#include <linux/skbuff.h>#include <linux/delay.h>#include <linux/proc_fs.h>#include <linux/init.h>#include <linux/random.h>#include <linux/module.h>#include <linux/seq_file.h>#include <net/irda/irda.h>#include <net/irda/irda_device.h>#include <net/irda/irqueue.h>#include <net/irda/irlmp.h>#include <net/irda/irlmp_frame.h>#include <net/irda/irlap_frame.h>#include <net/irda/irlap.h>#include <net/irda/timer.h>#include <net/irda/qos.h>static hashbin_t *irlap = NULL;int sysctl_slot_timeout = SLOT_TIMEOUT * 1000 / HZ;/* This is the delay of missed pf period before generating an event * to the application. The spec mandate 3 seconds, but in some cases * it's way too long. - Jean II */int sysctl_warn_noreply_time = 3;extern void irlap_queue_xmit(struct irlap_cb *self, struct sk_buff *skb);static void __irlap_close(struct irlap_cb *self);static void irlap_init_qos_capabilities(struct irlap_cb *self,					struct qos_info *qos_user);#ifdef CONFIG_IRDA_DEBUGstatic char *lap_reasons[] = {	"ERROR, NOT USED",	"LAP_DISC_INDICATION",	"LAP_NO_RESPONSE",	"LAP_RESET_INDICATION",	"LAP_FOUND_NONE",	"LAP_MEDIA_BUSY",	"LAP_PRIMARY_CONFLICT",	"ERROR, NOT USED",};#endif	/* CONFIG_IRDA_DEBUG */int __init irlap_init(void){	/* Check if the compiler did its job properly.	 * May happen on some ARM configuration, check with Russell King. */	IRDA_ASSERT(sizeof(struct xid_frame) == 14, ;);	IRDA_ASSERT(sizeof(struct test_frame) == 10, ;);	IRDA_ASSERT(sizeof(struct ua_frame) == 10, ;);	IRDA_ASSERT(sizeof(struct snrm_frame) == 11, ;);	/* Allocate master array */	irlap = hashbin_new(HB_LOCK);	if (irlap == NULL) {		IRDA_ERROR("%s: can't allocate irlap hashbin!\n",			   __FUNCTION__);		return -ENOMEM;	}	return 0;}void irlap_cleanup(void){	IRDA_ASSERT(irlap != NULL, return;);	hashbin_delete(irlap, (FREE_FUNC) __irlap_close);}/* * Function irlap_open (driver) * *    Initialize IrLAP layer * */struct irlap_cb *irlap_open(struct net_device *dev, struct qos_info *qos,			    const char *hw_name){	struct irlap_cb *self;	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);	/* Initialize the irlap structure. */	self = kzalloc(sizeof(struct irlap_cb), GFP_KERNEL);	if (self == NULL)		return NULL;	self->magic = LAP_MAGIC;	/* Make a binding between the layers */	self->netdev = dev;	self->qos_dev = qos;	/* Copy hardware name */	if(hw_name != NULL) {		strlcpy(self->hw_name, hw_name, sizeof(self->hw_name));	} else {		self->hw_name[0] = '\0';	}	/* FIXME: should we get our own field? */	dev->atalk_ptr = self;	self->state = LAP_OFFLINE;	/* Initialize transmit queue */	skb_queue_head_init(&self->txq);	skb_queue_head_init(&self->txq_ultra);	skb_queue_head_init(&self->wx_list);	/* My unique IrLAP device address! */	/* We don't want the broadcast address, neither the NULL address	 * (most often used to signify "invalid"), and we don't want an	 * address already in use (otherwise connect won't be able	 * to select the proper link). - Jean II */	do {		get_random_bytes(&self->saddr, sizeof(self->saddr));	} while ((self->saddr == 0x0) || (self->saddr == BROADCAST) ||		 (hashbin_lock_find(irlap, self->saddr, NULL)) );	/* Copy to the driver */	memcpy(dev->dev_addr, &self->saddr, 4);	init_timer(&self->slot_timer);	init_timer(&self->query_timer);	init_timer(&self->discovery_timer);	init_timer(&self->final_timer);	init_timer(&self->poll_timer);	init_timer(&self->wd_timer);	init_timer(&self->backoff_timer);	init_timer(&self->media_busy_timer);	irlap_apply_default_connection_parameters(self);	self->N3 = 3; /* # connections attemts to try before giving up */	self->state = LAP_NDM;	hashbin_insert(irlap, (irda_queue_t *) self, self->saddr, NULL);	irlmp_register_link(self, self->saddr, &self->notify);	return self;}EXPORT_SYMBOL(irlap_open);/* * Function __irlap_close (self) * *    Remove IrLAP and all allocated memory. Stop any pending timers. * */static void __irlap_close(struct irlap_cb *self){	IRDA_ASSERT(self != NULL, return;);	IRDA_ASSERT(self->magic == LAP_MAGIC, return;);	/* Stop timers */	del_timer(&self->slot_timer);	del_timer(&self->query_timer);	del_timer(&self->discovery_timer);	del_timer(&self->final_timer);	del_timer(&self->poll_timer);	del_timer(&self->wd_timer);	del_timer(&self->backoff_timer);	del_timer(&self->media_busy_timer);	irlap_flush_all_queues(self);	self->magic = 0;	kfree(self);}/* * Function irlap_close (self) * *    Remove IrLAP instance * */void irlap_close(struct irlap_cb *self){	struct irlap_cb *lap;	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);	IRDA_ASSERT(self != NULL, return;);	IRDA_ASSERT(self->magic == LAP_MAGIC, return;);	/* We used to send a LAP_DISC_INDICATION here, but this was	 * racy. This has been move within irlmp_unregister_link()	 * itself. Jean II */	/* Kill the LAP and all LSAPs on top of it */	irlmp_unregister_link(self->saddr);	self->notify.instance = NULL;	/* Be sure that we manage to remove ourself from the hash */	lap = hashbin_remove(irlap, self->saddr, NULL);	if (!lap) {		IRDA_DEBUG(1, "%s(), Didn't find myself!\n", __FUNCTION__);		return;	}	__irlap_close(lap);}EXPORT_SYMBOL(irlap_close);/* * Function irlap_connect_indication (self, skb) * *    Another device is attempting to make a connection * */void irlap_connect_indication(struct irlap_cb *self, struct sk_buff *skb){	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);	IRDA_ASSERT(self != NULL, return;);	IRDA_ASSERT(self->magic == LAP_MAGIC, return;);	irlap_init_qos_capabilities(self, NULL); /* No user QoS! */	irlmp_link_connect_indication(self->notify.instance, self->saddr,				      self->daddr, &self->qos_tx, skb);}/* * Function irlap_connect_response (self, skb) * *    Service user has accepted incoming connection * */void irlap_connect_response(struct irlap_cb *self, struct sk_buff *userdata){	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);	irlap_do_event(self, CONNECT_RESPONSE, userdata, NULL);}/* * Function irlap_connect_request (self, daddr, qos_user, sniff) * *    Request connection with another device, sniffing is not implemented *    yet. * */void irlap_connect_request(struct irlap_cb *self, __u32 daddr,			   struct qos_info *qos_user, int sniff){	IRDA_DEBUG(3, "%s(), daddr=0x%08x\n", __FUNCTION__, daddr);	IRDA_ASSERT(self != NULL, return;);	IRDA_ASSERT(self->magic == LAP_MAGIC, return;);	self->daddr = daddr;	/*	 *  If the service user specifies QoS values for this connection,	 *  then use them	 */	irlap_init_qos_capabilities(self, qos_user);	if ((self->state == LAP_NDM) && !self->media_busy)		irlap_do_event(self, CONNECT_REQUEST, NULL, NULL);	else		self->connect_pending = TRUE;}/* * Function irlap_connect_confirm (self, skb) * *    Connection request has been accepted * */void irlap_connect_confirm(struct irlap_cb *self, struct sk_buff *skb){	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);	IRDA_ASSERT(self != NULL, return;);	IRDA_ASSERT(self->magic == LAP_MAGIC, return;);	irlmp_link_connect_confirm(self->notify.instance, &self->qos_tx, skb);}/* * Function irlap_data_indication (self, skb) * *    Received data frames from IR-port, so we just pass them up to *    IrLMP for further processing * */void irlap_data_indication(struct irlap_cb *self, struct sk_buff *skb,			   int unreliable){	/* Hide LAP header from IrLMP layer */	skb_pull(skb, LAP_ADDR_HEADER+LAP_CTRL_HEADER);	irlmp_link_data_indication(self->notify.instance, skb, unreliable);}/* * Function irlap_data_request (self, skb) * *    Queue data for transmission, must wait until XMIT state * */void irlap_data_request(struct irlap_cb *self, struct sk_buff *skb,			int unreliable){	IRDA_ASSERT(self != NULL, return;);	IRDA_ASSERT(self->magic == LAP_MAGIC, return;);	IRDA_DEBUG(3, "%s()\n", __FUNCTION__);	IRDA_ASSERT(skb_headroom(skb) >= (LAP_ADDR_HEADER+LAP_CTRL_HEADER),		    return;);	skb_push(skb, LAP_ADDR_HEADER+LAP_CTRL_HEADER);	/*	 *  Must set frame format now so that the rest of the code knows	 *  if its dealing with an I or an UI frame	 */	if (unreliable)		skb->data[1] = UI_FRAME;	else		skb->data[1] = I_FRAME;	/* Don't forget to refcount it - see irlmp_connect_request(). */	skb_get(skb);	/* Add at the end of the queue (keep ordering) - Jean II */	skb_queue_tail(&self->txq, skb);	/*	 *  Send event if this frame only if we are in the right state	 *  FIXME: udata should be sent first! (skb_queue_head?)	 */	if ((self->state == LAP_XMIT_P) || (self->state == LAP_XMIT_S)) {		/* If we are not already processing the Tx queue, trigger		 * transmission immediately - Jean II */		if((skb_queue_len(&self->txq) <= 1) && (!self->local_busy))			irlap_do_event(self, DATA_REQUEST, skb, NULL);		/* Otherwise, the packets will be sent normally at the		 * next pf-poll - Jean II */	}}/* * Function irlap_unitdata_request (self, skb) * *    Send Ultra data. This is data that must be sent outside any connection * */#ifdef CONFIG_IRDA_ULTRAvoid irlap_unitdata_request(struct irlap_cb *self, struct sk_buff *skb){	IRDA_ASSERT(self != NULL, return;);	IRDA_ASSERT(self->magic == LAP_MAGIC, return;);	IRDA_DEBUG(3, "%s()\n", __FUNCTION__);	IRDA_ASSERT(skb_headroom(skb) >= (LAP_ADDR_HEADER+LAP_CTRL_HEADER),	       return;);	skb_push(skb, LAP_ADDR_HEADER+LAP_CTRL_HEADER);	skb->data[0] = CBROADCAST;	skb->data[1] = UI_FRAME;	/* Don't need to refcount, see irlmp_connless_data_request() */	skb_queue_tail(&self->txq_ultra, skb);	irlap_do_event(self, SEND_UI_FRAME, NULL, NULL);}#endif /*CONFIG_IRDA_ULTRA *//* * Function irlap_udata_indication (self, skb) *

⌨️ 快捷键说明

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