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

📄 irttp.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
/********************************************************************* * * Filename:      irttp.c * Version:       1.2 * Description:   Tiny Transport Protocol (TTP) implementation * Status:        Stable * Author:        Dag Brattli <dagb@cs.uit.no> * Created at:    Sun Aug 31 20:14:31 1997 * Modified at:   Wed Jan  5 11:31:27 2000 * Modified by:   Dag Brattli <dagb@cs.uit.no> * *     Copyright (c) 1998-2000 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/skbuff.h>#include <linux/init.h>#include <linux/fs.h>#include <linux/seq_file.h>#include <asm/byteorder.h>#include <asm/unaligned.h>#include <net/irda/irda.h>#include <net/irda/irlap.h>#include <net/irda/irlmp.h>#include <net/irda/parameters.h>#include <net/irda/irttp.h>static struct irttp_cb *irttp;static void __irttp_close_tsap(struct tsap_cb *self);static int irttp_data_indication(void *instance, void *sap,				 struct sk_buff *skb);static int irttp_udata_indication(void *instance, void *sap,				  struct sk_buff *skb);static void irttp_disconnect_indication(void *instance, void *sap,					LM_REASON reason, struct sk_buff *);static void irttp_connect_indication(void *instance, void *sap,				     struct qos_info *qos, __u32 max_sdu_size,				     __u8 header_size, struct sk_buff *skb);static void irttp_connect_confirm(void *instance, void *sap,				  struct qos_info *qos, __u32 max_sdu_size,				  __u8 header_size, struct sk_buff *skb);static void irttp_run_tx_queue(struct tsap_cb *self);static void irttp_run_rx_queue(struct tsap_cb *self);static void irttp_flush_queues(struct tsap_cb *self);static void irttp_fragment_skb(struct tsap_cb *self, struct sk_buff *skb);static struct sk_buff *irttp_reassemble_skb(struct tsap_cb *self);static void irttp_todo_expired(unsigned long data);static int irttp_param_max_sdu_size(void *instance, irda_param_t *param,				    int get);static void irttp_flow_indication(void *instance, void *sap, LOCAL_FLOW flow);static void irttp_status_indication(void *instance,				    LINK_STATUS link, LOCK_STATUS lock);/* Information for parsing parameters in IrTTP */static pi_minor_info_t pi_minor_call_table[] = {	{ NULL, 0 },                                             /* 0x00 */	{ irttp_param_max_sdu_size, PV_INTEGER | PV_BIG_ENDIAN } /* 0x01 */};static pi_major_info_t pi_major_call_table[] = {{ pi_minor_call_table, 2 }};static pi_param_info_t param_info = { pi_major_call_table, 1, 0x0f, 4 };/************************ GLOBAL PROCEDURES ************************//* * Function irttp_init (void) * *    Initialize the IrTTP layer. Called by module initialization code * */int __init irttp_init(void){	irttp = kzalloc(sizeof(struct irttp_cb), GFP_KERNEL);	if (irttp == NULL)		return -ENOMEM;	irttp->magic = TTP_MAGIC;	irttp->tsaps = hashbin_new(HB_LOCK);	if (!irttp->tsaps) {		IRDA_ERROR("%s: can't allocate IrTTP hashbin!\n",			   __FUNCTION__);		kfree(irttp);		return -ENOMEM;	}	return 0;}/* * Function irttp_cleanup (void) * *    Called by module destruction/cleanup code * */void irttp_cleanup(void){	/* Check for main structure */	IRDA_ASSERT(irttp->magic == TTP_MAGIC, return;);	/*	 *  Delete hashbin and close all TSAP instances in it	 */	hashbin_delete(irttp->tsaps, (FREE_FUNC) __irttp_close_tsap);	irttp->magic = 0;	/* De-allocate main structure */	kfree(irttp);	irttp = NULL;}/*************************** SUBROUTINES ***************************//* * Function irttp_start_todo_timer (self, timeout) * *    Start todo timer. * * Made it more effient and unsensitive to race conditions - Jean II */static inline void irttp_start_todo_timer(struct tsap_cb *self, int timeout){	/* Set new value for timer */	mod_timer(&self->todo_timer, jiffies + timeout);}/* * Function irttp_todo_expired (data) * *    Todo timer has expired! * * One of the restriction of the timer is that it is run only on the timer * interrupt which run every 10ms. This mean that even if you set the timer * with a delay of 0, it may take up to 10ms before it's run. * So, to minimise latency and keep cache fresh, we try to avoid using * it as much as possible. * Note : we can't use tasklets, because they can't be asynchronously * killed (need user context), and we can't guarantee that here... * Jean II */static void irttp_todo_expired(unsigned long data){	struct tsap_cb *self = (struct tsap_cb *) data;	/* Check that we still exist */	if (!self || self->magic != TTP_TSAP_MAGIC)		return;	IRDA_DEBUG(4, "%s(instance=%p)\n", __FUNCTION__, self);	/* Try to make some progress, especially on Tx side - Jean II */	irttp_run_rx_queue(self);	irttp_run_tx_queue(self);	/* Check if time for disconnect */	if (test_bit(0, &self->disconnect_pend)) {		/* Check if it's possible to disconnect yet */		if (skb_queue_empty(&self->tx_queue)) {			/* Make sure disconnect is not pending anymore */			clear_bit(0, &self->disconnect_pend);	/* FALSE */			/* Note : self->disconnect_skb may be NULL */			irttp_disconnect_request(self, self->disconnect_skb,						 P_NORMAL);			self->disconnect_skb = NULL;		} else {			/* Try again later */			irttp_start_todo_timer(self, HZ/10);			/* No reason to try and close now */			return;		}	}	/* Check if it's closing time */	if (self->close_pend)		/* Finish cleanup */		irttp_close_tsap(self);}/* * Function irttp_flush_queues (self) * *     Flushes (removes all frames) in transitt-buffer (tx_list) */void irttp_flush_queues(struct tsap_cb *self){	struct sk_buff* skb;	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);	IRDA_ASSERT(self != NULL, return;);	IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return;);	/* Deallocate frames waiting to be sent */	while ((skb = skb_dequeue(&self->tx_queue)) != NULL)		dev_kfree_skb(skb);	/* Deallocate received frames */	while ((skb = skb_dequeue(&self->rx_queue)) != NULL)		dev_kfree_skb(skb);	/* Deallocate received fragments */	while ((skb = skb_dequeue(&self->rx_fragments)) != NULL)		dev_kfree_skb(skb);}/* * Function irttp_reassemble (self) * *    Makes a new (continuous) skb of all the fragments in the fragment *    queue * */static struct sk_buff *irttp_reassemble_skb(struct tsap_cb *self){	struct sk_buff *skb, *frag;	int n = 0;  /* Fragment index */	IRDA_ASSERT(self != NULL, return NULL;);	IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return NULL;);	IRDA_DEBUG(2, "%s(), self->rx_sdu_size=%d\n", __FUNCTION__,		   self->rx_sdu_size);	skb = dev_alloc_skb(TTP_HEADER + self->rx_sdu_size);	if (!skb)		return NULL;	/*	 * Need to reserve space for TTP header in case this skb needs to	 * be requeued in case delivery failes	 */	skb_reserve(skb, TTP_HEADER);	skb_put(skb, self->rx_sdu_size);	/*	 *  Copy all fragments to a new buffer	 */	while ((frag = skb_dequeue(&self->rx_fragments)) != NULL) {		skb_copy_to_linear_data_offset(skb, n, frag->data, frag->len);		n += frag->len;		dev_kfree_skb(frag);	}	IRDA_DEBUG(2,		   "%s(), frame len=%d, rx_sdu_size=%d, rx_max_sdu_size=%d\n",		   __FUNCTION__, n, self->rx_sdu_size, self->rx_max_sdu_size);	/* Note : irttp_run_rx_queue() calculate self->rx_sdu_size	 * by summing the size of all fragments, so we should always	 * have n == self->rx_sdu_size, except in cases where we	 * droped the last fragment (when self->rx_sdu_size exceed	 * self->rx_max_sdu_size), where n < self->rx_sdu_size.	 * Jean II */	IRDA_ASSERT(n <= self->rx_sdu_size, n = self->rx_sdu_size;);	/* Set the new length */	skb_trim(skb, n);	self->rx_sdu_size = 0;	return skb;}/* * Function irttp_fragment_skb (skb) * *    Fragments a frame and queues all the fragments for transmission * */static inline void irttp_fragment_skb(struct tsap_cb *self,				      struct sk_buff *skb){	struct sk_buff *frag;	__u8 *frame;	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);	IRDA_ASSERT(self != NULL, return;);	IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return;);	IRDA_ASSERT(skb != NULL, return;);	/*	 *  Split frame into a number of segments	 */	while (skb->len > self->max_seg_size) {		IRDA_DEBUG(2, "%s(), fragmenting ...\n", __FUNCTION__);		/* Make new segment */		frag = alloc_skb(self->max_seg_size+self->max_header_size,				 GFP_ATOMIC);		if (!frag)			return;		skb_reserve(frag, self->max_header_size);		/* Copy data from the original skb into this fragment. */		skb_copy_from_linear_data(skb, skb_put(frag, self->max_seg_size),			      self->max_seg_size);		/* Insert TTP header, with the more bit set */		frame = skb_push(frag, TTP_HEADER);		frame[0] = TTP_MORE;		/* Hide the copied data from the original skb */		skb_pull(skb, self->max_seg_size);		/* Queue fragment */		skb_queue_tail(&self->tx_queue, frag);	}	/* Queue what is left of the original skb */	IRDA_DEBUG(2, "%s(), queuing last segment\n", __FUNCTION__);	frame = skb_push(skb, TTP_HEADER);	frame[0] = 0x00; /* Clear more bit */	/* Queue fragment */	skb_queue_tail(&self->tx_queue, skb);}/* * Function irttp_param_max_sdu_size (self, param) * *    Handle the MaxSduSize parameter in the connect frames, this function *    will be called both when this parameter needs to be inserted into, and *    extracted from the connect frames */static int irttp_param_max_sdu_size(void *instance, irda_param_t *param,				    int get){	struct tsap_cb *self;	self = (struct tsap_cb *) instance;	IRDA_ASSERT(self != NULL, return -1;);	IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);	if (get)		param->pv.i = self->tx_max_sdu_size;	else		self->tx_max_sdu_size = param->pv.i;	IRDA_DEBUG(1, "%s(), MaxSduSize=%d\n", __FUNCTION__, param->pv.i);	return 0;}/*************************** CLIENT CALLS ***************************//************************** LMP CALLBACKS **************************//* Everything is happily mixed up. Waiting for next clean up - Jean II *//* * Initialization, that has to be done on new tsap * instance allocation and on duplication */static void irttp_init_tsap(struct tsap_cb *tsap){	spin_lock_init(&tsap->lock);	init_timer(&tsap->todo_timer);	skb_queue_head_init(&tsap->rx_queue);	skb_queue_head_init(&tsap->tx_queue);	skb_queue_head_init(&tsap->rx_fragments);}/* * Function irttp_open_tsap (stsap, notify) * *    Create TSAP connection endpoint, */struct tsap_cb *irttp_open_tsap(__u8 stsap_sel, int credit, notify_t *notify){	struct tsap_cb *self;	struct lsap_cb *lsap;	notify_t ttp_notify;	IRDA_ASSERT(irttp->magic == TTP_MAGIC, return NULL;);	/* The IrLMP spec (IrLMP 1.1 p10) says that we have the right to	 * use only 0x01-0x6F. Of course, we can use LSAP_ANY as well.	 * JeanII */	if((stsap_sel != LSAP_ANY) &&	   ((stsap_sel < 0x01) || (stsap_sel >= 0x70))) {		IRDA_DEBUG(0, "%s(), invalid tsap!\n", __FUNCTION__);		return NULL;	}	self = kzalloc(sizeof(struct tsap_cb), GFP_ATOMIC);	if (self == NULL) {		IRDA_DEBUG(0, "%s(), unable to kmalloc!\n", __FUNCTION__);		return NULL;	}	/* Initialize internal objects */	irttp_init_tsap(self);	/* Initialise todo timer */	self->todo_timer.data     = (unsigned long) self;	self->todo_timer.function = &irttp_todo_expired;	/* Initialize callbacks for IrLMP to use */	irda_notify_init(&ttp_notify);	ttp_notify.connect_confirm = irttp_connect_confirm;	ttp_notify.connect_indication = irttp_connect_indication;	ttp_notify.disconnect_indication = irttp_disconnect_indication;	ttp_notify.data_indication = irttp_data_indication;	ttp_notify.udata_indication = irttp_udata_indication;	ttp_notify.flow_indication = irttp_flow_indication;	if(notify->status_indication != NULL)		ttp_notify.status_indication = irttp_status_indication;	ttp_notify.instance = self;	strncpy(ttp_notify.name, notify->name, NOTIFY_MAX_NAME);	self->magic = TTP_TSAP_MAGIC;	self->connected = FALSE;	/*	 *  Create LSAP at IrLMP layer	 */	lsap = irlmp_open_lsap(stsap_sel, &ttp_notify, 0);	if (lsap == NULL) {		IRDA_WARNING("%s: unable to allocate LSAP!!\n", __FUNCTION__);		return NULL;	}	/*	 *  If user specified LSAP_ANY as source TSAP selector, then IrLMP	 *  will replace it with whatever source selector which is free, so	 *  the stsap_sel we have might not be valid anymore	 */	self->stsap_sel = lsap->slsap_sel;	IRDA_DEBUG(4, "%s(), stsap_sel=%02x\n", __FUNCTION__, self->stsap_sel);	self->notify = *notify;	self->lsap = lsap;	hashbin_insert(irttp->tsaps, (irda_queue_t *) self, (long) self, NULL);	if (credit > TTP_RX_MAX_CREDIT)		self->initial_credit = TTP_RX_MAX_CREDIT;	else		self->initial_credit = credit;	return self;}EXPORT_SYMBOL(irttp_open_tsap);/* * Function irttp_close (handle) * *    Remove an instance of a TSAP. This function should only deal with the *    deallocation of the TSAP, and resetting of the TSAPs values; * */static void __irttp_close_tsap(struct tsap_cb *self){

⌨️ 快捷键说明

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