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

📄 irttp.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
	/* First make sure we're connected. */	IRDA_ASSERT(self != NULL, return;);	IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return;);	irttp_flush_queues(self);	del_timer(&self->todo_timer);	/* This one won't be cleaned up if we are disconnect_pend + close_pend	 * and we receive a disconnect_indication */	if (self->disconnect_skb)		dev_kfree_skb(self->disconnect_skb);	self->connected = FALSE;	self->magic = ~TTP_TSAP_MAGIC;	kfree(self);}/* * Function irttp_close (self) * *    Remove TSAP from list of all TSAPs and then deallocate all resources *    associated with this TSAP * * Note : because we *free* the tsap structure, it is the responsibility * of the caller to make sure we are called only once and to deal with * possible race conditions. - Jean II */int irttp_close_tsap(struct tsap_cb *self){	struct tsap_cb *tsap;	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);	IRDA_ASSERT(self != NULL, return -1;);	IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);	/* Make sure tsap has been disconnected */	if (self->connected) {		/* Check if disconnect is not pending */		if (!test_bit(0, &self->disconnect_pend)) {			IRDA_WARNING("%s: TSAP still connected!\n",				     __FUNCTION__);			irttp_disconnect_request(self, NULL, P_NORMAL);		}		self->close_pend = TRUE;		irttp_start_todo_timer(self, HZ/10);		return 0; /* Will be back! */	}	tsap = hashbin_remove(irttp->tsaps, (long) self, NULL);	IRDA_ASSERT(tsap == self, return -1;);	/* Close corresponding LSAP */	if (self->lsap) {		irlmp_close_lsap(self->lsap);		self->lsap = NULL;	}	__irttp_close_tsap(self);	return 0;}EXPORT_SYMBOL(irttp_close_tsap);/* * Function irttp_udata_request (self, skb) * *    Send unreliable data on this TSAP * */int irttp_udata_request(struct tsap_cb *self, struct sk_buff *skb){	IRDA_ASSERT(self != NULL, return -1;);	IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);	IRDA_ASSERT(skb != NULL, return -1;);	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);	/* Check that nothing bad happens */	if ((skb->len == 0) || (!self->connected)) {		IRDA_DEBUG(1, "%s(), No data, or not connected\n",			   __FUNCTION__);		goto err;	}	if (skb->len > self->max_seg_size) {		IRDA_DEBUG(1, "%s(), UData is too large for IrLAP!\n",			   __FUNCTION__);		goto err;	}	irlmp_udata_request(self->lsap, skb);	self->stats.tx_packets++;	return 0;err:	dev_kfree_skb(skb);	return -1;}EXPORT_SYMBOL(irttp_udata_request);/* * Function irttp_data_request (handle, skb) * *    Queue frame for transmission. If SAR is enabled, fragement the frame *    and queue the fragments for transmission */int irttp_data_request(struct tsap_cb *self, struct sk_buff *skb){	__u8 *frame;	int ret;	IRDA_ASSERT(self != NULL, return -1;);	IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);	IRDA_ASSERT(skb != NULL, return -1;);	IRDA_DEBUG(2, "%s() : queue len = %d\n", __FUNCTION__,		   skb_queue_len(&self->tx_queue));	/* Check that nothing bad happens */	if ((skb->len == 0) || (!self->connected)) {		IRDA_WARNING("%s: No data, or not connected\n", __FUNCTION__);		ret = -ENOTCONN;		goto err;	}	/*	 *  Check if SAR is disabled, and the frame is larger than what fits	 *  inside an IrLAP frame	 */	if ((self->tx_max_sdu_size == 0) && (skb->len > self->max_seg_size)) {		IRDA_ERROR("%s: SAR disabled, and data is too large for IrLAP!\n",			   __FUNCTION__);		ret = -EMSGSIZE;		goto err;	}	/*	 *  Check if SAR is enabled, and the frame is larger than the	 *  TxMaxSduSize	 */	if ((self->tx_max_sdu_size != 0) &&	    (self->tx_max_sdu_size != TTP_SAR_UNBOUND) &&	    (skb->len > self->tx_max_sdu_size))	{		IRDA_ERROR("%s: SAR enabled, but data is larger than TxMaxSduSize!\n",			   __FUNCTION__);		ret = -EMSGSIZE;		goto err;	}	/*	 *  Check if transmit queue is full	 */	if (skb_queue_len(&self->tx_queue) >= TTP_TX_MAX_QUEUE) {		/*		 *  Give it a chance to empty itself		 */		irttp_run_tx_queue(self);		/* Drop packet. This error code should trigger the caller		 * to resend the data in the client code - Jean II */		ret = -ENOBUFS;		goto err;	}	/* Queue frame, or queue frame segments */	if ((self->tx_max_sdu_size == 0) || (skb->len < self->max_seg_size)) {		/* Queue frame */		IRDA_ASSERT(skb_headroom(skb) >= TTP_HEADER, return -1;);		frame = skb_push(skb, TTP_HEADER);		frame[0] = 0x00; /* Clear more bit */		skb_queue_tail(&self->tx_queue, skb);	} else {		/*		 *  Fragment the frame, this function will also queue the		 *  fragments, we don't care about the fact the transmit		 *  queue may be overfilled by all the segments for a little		 *  while		 */		irttp_fragment_skb(self, skb);	}	/* Check if we can accept more data from client */	if ((!self->tx_sdu_busy) &&	    (skb_queue_len(&self->tx_queue) > TTP_TX_HIGH_THRESHOLD)) {		/* Tx queue filling up, so stop client. */		if (self->notify.flow_indication) {			self->notify.flow_indication(self->notify.instance,						     self, FLOW_STOP);		}		/* self->tx_sdu_busy is the state of the client.		 * Update state after notifying client to avoid		 * race condition with irttp_flow_indication().		 * If the queue empty itself after our test but before		 * we set the flag, we will fix ourselves below in		 * irttp_run_tx_queue().		 * Jean II */		self->tx_sdu_busy = TRUE;	}	/* Try to make some progress */	irttp_run_tx_queue(self);	return 0;err:	dev_kfree_skb(skb);	return ret;}EXPORT_SYMBOL(irttp_data_request);/* * Function irttp_run_tx_queue (self) * *    Transmit packets queued for transmission (if possible) * */static void irttp_run_tx_queue(struct tsap_cb *self){	struct sk_buff *skb;	unsigned long flags;	int n;	IRDA_DEBUG(2, "%s() : send_credit = %d, queue_len = %d\n",		   __FUNCTION__,		   self->send_credit, skb_queue_len(&self->tx_queue));	/* Get exclusive access to the tx queue, otherwise don't touch it */	if (irda_lock(&self->tx_queue_lock) == FALSE)		return;	/* Try to send out frames as long as we have credits	 * and as long as LAP is not full. If LAP is full, it will	 * poll us through irttp_flow_indication() - Jean II */	while ((self->send_credit > 0) &&	       (!irlmp_lap_tx_queue_full(self->lsap)) &&	       (skb = skb_dequeue(&self->tx_queue)))	{		/*		 *  Since we can transmit and receive frames concurrently,		 *  the code below is a critical region and we must assure that		 *  nobody messes with the credits while we update them.		 */		spin_lock_irqsave(&self->lock, flags);		n = self->avail_credit;		self->avail_credit = 0;		/* Only room for 127 credits in frame */		if (n > 127) {			self->avail_credit = n-127;			n = 127;		}		self->remote_credit += n;		self->send_credit--;		spin_unlock_irqrestore(&self->lock, flags);		/*		 *  More bit must be set by the data_request() or fragment()		 *  functions		 */		skb->data[0] |= (n & 0x7f);		/* Detach from socket.		 * The current skb has a reference to the socket that sent		 * it (skb->sk). When we pass it to IrLMP, the skb will be		 * stored in in IrLAP (self->wx_list). When we are within		 * IrLAP, we lose the notion of socket, so we should not		 * have a reference to a socket. So, we drop it here.		 *		 * Why does it matter ?		 * When the skb is freed (kfree_skb), if it is associated		 * with a socket, it release buffer space on the socket		 * (through sock_wfree() and sock_def_write_space()).		 * If the socket no longer exist, we may crash. Hard.		 * When we close a socket, we make sure that associated packets		 * in IrTTP are freed. However, we have no way to cancel		 * the packet that we have passed to IrLAP. So, if a packet		 * remains in IrLAP (retry on the link or else) after we		 * close the socket, we are dead !		 * Jean II */		if (skb->sk != NULL) {			/* IrSOCK application, IrOBEX, ... */			skb_orphan(skb);		}			/* IrCOMM over IrTTP, IrLAN, ... */		/* Pass the skb to IrLMP - done */		irlmp_data_request(self->lsap, skb);		self->stats.tx_packets++;	}	/* Check if we can accept more frames from client.	 * We don't want to wait until the todo timer to do that, and we	 * can't use tasklets (grr...), so we are obliged to give control	 * to client. That's ok, this test will be true not too often	 * (max once per LAP window) and we are called from places	 * where we can spend a bit of time doing stuff. - Jean II */	if ((self->tx_sdu_busy) &&	    (skb_queue_len(&self->tx_queue) < TTP_TX_LOW_THRESHOLD) &&	    (!self->close_pend))	{		if (self->notify.flow_indication)			self->notify.flow_indication(self->notify.instance,						     self, FLOW_START);		/* self->tx_sdu_busy is the state of the client.		 * We don't really have a race here, but it's always safer		 * to update our state after the client - Jean II */		self->tx_sdu_busy = FALSE;	}	/* Reset lock */	self->tx_queue_lock = 0;}/* * Function irttp_give_credit (self) * *    Send a dataless flowdata TTP-PDU and give available credit to peer *    TSAP */static inline void irttp_give_credit(struct tsap_cb *self){	struct sk_buff *tx_skb = NULL;	unsigned long flags;	int n;	IRDA_ASSERT(self != NULL, return;);	IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return;);	IRDA_DEBUG(4, "%s() send=%d,avail=%d,remote=%d\n",		   __FUNCTION__,		   self->send_credit, self->avail_credit, self->remote_credit);	/* Give credit to peer */	tx_skb = alloc_skb(TTP_MAX_HEADER, GFP_ATOMIC);	if (!tx_skb)		return;	/* Reserve space for LMP, and LAP header */	skb_reserve(tx_skb, LMP_MAX_HEADER);	/*	 *  Since we can transmit and receive frames concurrently,	 *  the code below is a critical region and we must assure that	 *  nobody messes with the credits while we update them.	 */	spin_lock_irqsave(&self->lock, flags);	n = self->avail_credit;	self->avail_credit = 0;	/* Only space for 127 credits in frame */	if (n > 127) {		self->avail_credit = n - 127;		n = 127;	}	self->remote_credit += n;	spin_unlock_irqrestore(&self->lock, flags);	skb_put(tx_skb, 1);	tx_skb->data[0] = (__u8) (n & 0x7f);	irlmp_data_request(self->lsap, tx_skb);	self->stats.tx_packets++;}/* * Function irttp_udata_indication (instance, sap, skb) * *    Received some unit-data (unreliable) * */static int irttp_udata_indication(void *instance, void *sap,				  struct sk_buff *skb){	struct tsap_cb *self;	int err;	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);	self = (struct tsap_cb *) instance;	IRDA_ASSERT(self != NULL, return -1;);	IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);	IRDA_ASSERT(skb != NULL, return -1;);	self->stats.rx_packets++;	/* Just pass data to layer above */	if (self->notify.udata_indication) {		err = self->notify.udata_indication(self->notify.instance,						    self,skb);		/* Same comment as in irttp_do_data_indication() */		if (!err)			return 0;	}	/* Either no handler, or handler returns an error */	dev_kfree_skb(skb);	return 0;}/* * Function irttp_data_indication (instance, sap, skb) * *    Receive segment from IrLMP. * */static int irttp_data_indication(void *instance, void *sap,				 struct sk_buff *skb){	struct tsap_cb *self;	unsigned long flags;	int n;	self = (struct tsap_cb *) instance;	n = skb->data[0] & 0x7f;     /* Extract the credits */	self->stats.rx_packets++;	/*  Deal with inbound credit	 *  Since we can transmit and receive frames concurrently,	 *  the code below is a critical region and we must assure that	 *  nobody messes with the credits while we update them.	 */	spin_lock_irqsave(&self->lock, flags);	self->send_credit += n;	if (skb->len > 1)		self->remote_credit--;	spin_unlock_irqrestore(&self->lock, flags);	/*	 *  Data or dataless packet? Dataless frames contains only the	 *  TTP_HEADER.	 */	if (skb->len > 1) {		/*		 *  We don't remove the TTP header, since we must preserve the		 *  more bit, so the defragment routing knows what to do		 */		skb_queue_tail(&self->rx_queue, skb);	} else {		/* Dataless flowdata TTP-PDU */		dev_kfree_skb(skb);	}	/* Push data to the higher layer.	 * We do it synchronously because running the todo timer for each	 * receive packet would be too much overhead and latency.	 * By passing control to the higher layer, we run the risk that	 * it may take time or grab a lock. Most often, the higher layer	 * will only put packet in a queue.	 * Anyway, packets are only dripping through the IrDA, so we can	 * have time before the next packet.	 * Further, we are run from NET_BH, so the worse that can happen is	 * us missing the optimal time to send back the PF bit in LAP.	 * Jean II */	irttp_run_rx_queue(self);	/* We now give credits to peer in irttp_run_rx_queue().	 * We need to send credit *NOW*, otherwise we are going	 * to miss the next Tx window. The todo timer may take

⌨️ 快捷键说明

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