patch-2.2.15 linux/net/irda/irttp.c

Next file: linux/net/irda/parameters.c
Previous file: linux/net/irda/irsysctl.c
Back to the patch index
Back to the overall index

diff -u --new-file --recursive --exclude-from ../../exclude v2.2.14/net/irda/irttp.c linux/net/irda/irttp.c
@@ -3,13 +3,13 @@
  * Filename:      irttp.c
  * Version:       1.2
  * Description:   Tiny Transport Protocol (TTP) implementation
- * Status:        Experimental.
+ * Status:        Stable
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun Aug 31 20:14:31 1997
- * Modified at:   Mon May 31 10:29:56 1999
+ * Modified at:   Sun Jan 30 14:30:32 2000
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, 
+ *     Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>, 
  *     All Rights Reserved.
  *     
  *     This program is free software; you can redistribute it and/or 
@@ -32,7 +32,9 @@
 
 #include <net/irda/irda.h>
 #include <net/irda/irmod.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 = NULL;
@@ -58,6 +60,16 @@
 static void irttp_fragment_skb(struct tsap_cb *self, struct sk_buff *skb);
 static void irttp_start_todo_timer(struct tsap_cb *self, int timeout);
 static struct sk_buff *irttp_reassemble_skb(struct tsap_cb *self);
+static int irttp_param_max_sdu_size(void *instance, irda_param_t *param, 
+				    int get);
+
+/* 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 };
 
 /*
  * Function irttp_init (void)
@@ -65,7 +77,7 @@
  *    Initialize the IrTTP layer. Called by module initialization code
  *
  */
-__initfunc(int irttp_init(void))
+int __init irttp_init(void)
 {
 	/* Initialize the irttp structure. */
 	if (irttp == NULL) {
@@ -79,7 +91,7 @@
 
 	irttp->tsaps = hashbin_new(HB_LOCAL);
 	if (!irttp->tsaps) {
-		printk(KERN_WARNING "IrDA: Can't allocate IrTTP hashbin!\n");
+		ERROR(__FUNCTION__ "(), can't allocate IrTTP hashbin!\n");
 		return -ENOMEM;
 	}
 	
@@ -118,22 +130,22 @@
  *
  *    Create TSAP connection endpoint,
  */
-struct tsap_cb *irttp_open_tsap(__u8 stsap_sel, int credit, 
-				struct notify_t *notify) 
+struct tsap_cb *irttp_open_tsap(__u8 stsap_sel, int credit, notify_t *notify) 
 {
-	struct notify_t ttp_notify;
 	struct tsap_cb *self;
 	struct lsap_cb *lsap;
+	notify_t ttp_notify;
 
 	ASSERT(irttp != NULL, return NULL;);
 	ASSERT(irttp->magic == TTP_MAGIC, return NULL;);
 
 	self = kmalloc(sizeof(struct tsap_cb), GFP_ATOMIC);
 	if (self == NULL) {
-		DEBUG(0, __FUNCTION__ "(), unable to kmalloc!\n");
+		IRDA_DEBUG(0, __FUNCTION__ "(), unable to kmalloc!\n");
 		return NULL;
 	}
 	memset(self, 0, sizeof(struct tsap_cb));
+	spin_lock_init(&self->lock);
 
 	init_timer(&self->todo_timer);
 
@@ -156,9 +168,9 @@
 	/*
 	 *  Create LSAP at IrLMP layer
 	 */
-	lsap = irlmp_open_lsap(stsap_sel, &ttp_notify);
+	lsap = irlmp_open_lsap(stsap_sel, &ttp_notify, 0);
 	if (lsap == NULL) {
-		printk(KERN_ERR "IrTTP, Unable to get LSAP!!\n");
+		WARNING(__FUNCTION__ "(), unable to allocate LSAP!!\n");
 		return NULL;
 	}
 	
@@ -168,12 +180,12 @@
 	 *  the stsap_sel we have might not be valid anymore
 	 */
 	self->stsap_sel = lsap->slsap_sel;
-	DEBUG(4, __FUNCTION__ "(), stsap_sel=%02x\n", self->stsap_sel);
+	IRDA_DEBUG(4, __FUNCTION__ "(), stsap_sel=%02x\n", self->stsap_sel);
 
 	self->notify = *notify;
 	self->lsap = lsap;
 
-	hashbin_insert(irttp->tsaps, (QUEUE *) self, (int) self, NULL);
+	hashbin_insert(irttp->tsaps, (queue_t *) self, (int) self, NULL);
 
 	if (credit > TTP_MAX_QUEUE)
 		self->initial_credit = TTP_MAX_QUEUE;
@@ -217,7 +229,7 @@
 {
 	struct tsap_cb *tsap;
 
-	DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 
 	ASSERT(self != NULL, return -1;);
 	ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);
@@ -226,11 +238,11 @@
 	if (self->connected) {
 		/* Check if disconnect is not pending */
 		if (!self->disconnect_pend) {
-			DEBUG(0, __FUNCTION__ "(), TSAP still connected!\n");
+			IRDA_DEBUG(0, __FUNCTION__ "(), TSAP still connected!\n");
 			irttp_disconnect_request(self, NULL, P_NORMAL);
 		}
 		self->close_pend = TRUE;
-		irttp_start_todo_timer(self, 100);
+		irttp_start_todo_timer(self, 1*HZ);
 
 		return 0; /* Will be back! */
 	}
@@ -262,16 +274,16 @@
 	ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);
 	ASSERT(skb != NULL, return -1;);
 
-	DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 
 	/* Check that nothing bad happens */
 	if ((skb->len == 0) || (!self->connected)) {
-		DEBUG(1, __FUNCTION__ "(), No data, or not connected\n");
+		IRDA_DEBUG(1, __FUNCTION__ "(), No data, or not connected\n");
 		return -1;
 	}
 	
 	if (skb->len > self->max_seg_size) {
-		DEBUG(1, __FUNCTION__ "(), UData is to large for IrLAP!\n");
+		IRDA_DEBUG(1, __FUNCTION__ "(), UData is to large for IrLAP!\n");
 		return -1;
 	}
 		    
@@ -291,13 +303,9 @@
 {
 	__u8 *frame;
 
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);
-	ASSERT(skb != NULL, return -1;);
-
 	/* Check that nothing bad happens */
 	if ((skb->len == 0) || (!self->connected)) {
-		ERROR(__FUNCTION__ "(), No data, or not connected\n");
+		WARNING(__FUNCTION__ "(), No data, or not connected\n");
 		return -ENOTCONN;
 	}
 
@@ -316,7 +324,7 @@
 	 *  TxMaxSduSize 
 	 */
 	if ((self->tx_max_sdu_size != 0) && 
-	    (self->tx_max_sdu_size != SAR_UNBOUND) && 
+	    (self->tx_max_sdu_size != TTP_SAR_UNBOUND) && 
 	    (skb->len > self->tx_max_sdu_size))
 	{
 		ERROR(__FUNCTION__ "(), SAR enabled, "
@@ -355,7 +363,7 @@
 
 	/* Check if we can accept more data from client */
 	if ((!self->tx_sdu_busy) && 
-	    (skb_queue_len(&self->tx_queue) > HIGH_THRESHOLD)) {
+	    (skb_queue_len(&self->tx_queue) > TTP_HIGH_THRESHOLD)) {
 		
 		/* Tx queue filling up, so stop client */
 		self->tx_sdu_busy = TRUE;
@@ -375,25 +383,36 @@
 /*
  * Function irttp_run_tx_queue (self)
  *
- *    If possible, transmit a frame queued for transmission.
+ *    Transmit packets queued for transmission (if possible)
  *
  */
 static void irttp_run_tx_queue(struct tsap_cb *self) 
 {
-	struct sk_buff *skb = NULL;
+	struct sk_buff *skb;
 	unsigned long flags;
 	int n;
 
 	if (irda_lock(&self->tx_queue_lock) == FALSE)
 		return;
 
-	while ((self->send_credit > 0) && !skb_queue_empty(&self->tx_queue)) {
-		skb = skb_dequeue(&self->tx_queue);
-		ASSERT(skb != NULL, return;);
-		
-		/* Make room for TTP header */
-		ASSERT(skb_headroom(skb) >= TTP_HEADER, return;);
-				
+	/* Try to send out frames as long as we have credits */
+	while ((self->send_credit > 0) &&
+	       (skb = skb_dequeue(&self->tx_queue)))
+	{
+		/* 
+		 * Make sure we don't flood IrLAP with frames just because
+		 * the remote device has given us a lot of credits
+		 */
+		if (irlmp_get_lap_tx_queue_len(self->lsap) > LAP_MAX_QUEUE) {
+			/* Re-queue packet */
+			skb_queue_head(&self->tx_queue, skb);
+
+			/* Try later. Maybe IrLAP could notify us? */
+			irttp_start_todo_timer(self, MSECS_TO_JIFFIES(10));
+			
+			break;
+		}
+
 		/*
 		 *  Since we can transmit and receive frames concurrently, 
 		 *  the code below is a critical region and we must assure that
@@ -425,7 +444,7 @@
 
 		/* Check if we can accept more frames from client */
 		if ((self->tx_sdu_busy) && 
-		    (skb_queue_len(&self->tx_queue) < LOW_THRESHOLD)) 
+		    (skb_queue_len(&self->tx_queue) < TTP_LOW_THRESHOLD)) 
 		{
 			self->tx_sdu_busy = FALSE;
 			
@@ -435,9 +454,7 @@
 					FLOW_START);
 		}
 	}
-	
-	/* Reset lock */
-	self->tx_queue_lock = 0;
+	self->tx_queue_lock = 0; /* Reset lock */
 }
 
 /*
@@ -455,8 +472,8 @@
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == TTP_TSAP_MAGIC, return;);	
 
-	DEBUG(4, __FUNCTION__ "() send=%d,avail=%d,remote=%d\n", 
-	       self->send_credit, self->avail_credit, self->remote_credit);
+	IRDA_DEBUG(4, __FUNCTION__ "() send=%d,avail=%d,remote=%d\n", 
+		   self->send_credit, self->avail_credit, self->remote_credit);
 	
 	/* Give credit to peer */
 	tx_skb = dev_alloc_skb(64);
@@ -503,7 +520,7 @@
 {
 	struct tsap_cb *self;
 
-	DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 
 	self = (struct tsap_cb *) instance;
 
@@ -512,16 +529,18 @@
 	ASSERT(skb != NULL, return -1;);
 
 	/* Just pass data to layer above */
-	if (self->notify.udata_indication) {
-		self->notify.udata_indication(self->notify.instance, self, skb);
-	}
+	if (self->notify.udata_indication)
+		self->notify.udata_indication(self->notify.instance, self,skb);
+	else
+		dev_kfree_skb(skb);
+
 	self->stats.rx_packets++;
 
 	return 0;
 }
 
 /*
- * Function irttp_data_indication (handle, skb)
+ * Function irttp_data_indication (instance, sap, skb)
  *
  *    Receive segment from IrLMP. 
  *
@@ -534,20 +553,15 @@
 
 	self = (struct tsap_cb *) instance;
 
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);
-
 	n = skb->data[0] & 0x7f;     /* Extract the credits */
 
 	self->stats.rx_packets++;
 
 	/* 
-	 *  Data or dataless frame? Dataless frames only contain the 
-	 *  TTP_HEADER
+	 *  Data or dataless packet? Dataless frames contains only the 
+	 *  TTP_HEADER. 
 	 */
-	if (skb->len == 1)
-		self->send_credit += n;	/* Dataless flowdata TTP-PDU */
-	else {
+	if (skb->len > 1) {
 		/* Deal with inbound credit */
 		self->send_credit += n;
 		self->remote_credit--;
@@ -557,7 +571,10 @@
 		 *  more bit, so the defragment routing knows what to do
 		 */
 		skb_queue_tail(&self->rx_queue, skb);
-	} 
+	} else {
+		self->send_credit += n;	/* Dataless flowdata TTP-PDU */
+		dev_kfree_skb(skb);
+	}
 
 	irttp_run_rx_queue(self);
 
@@ -565,18 +582,22 @@
 	 *  Give avay some credits to peer? 
 	 */
 	if ((skb_queue_empty(&self->tx_queue)) && 
-	    (self->remote_credit < LOW_THRESHOLD) && 
+	    (self->remote_credit < TTP_LOW_THRESHOLD) && 
 	    (self->avail_credit > 0)) 
 	{
 		/* Schedule to start immediately after this thread */
 		irttp_start_todo_timer(self, 0);
+		/*irttp_give_credit(self);*/
 	}
-
-	/* If peer has given us some credites and we didn't have anyone
-         * from before, the we need to shedule the tx queue? 
+	
+	/* 
+	 * If the peer device has given us some credits and we didn't have
+         * anyone from before, the we need to shedule the tx queue?  
 	 */
-	if (self->send_credit == n)
+	if (self->send_credit == n) {
+		/*irttp_run_tx_queue(self);*/
 		irttp_start_todo_timer(self, 0);
+	}
 	return 0;
 }
 
@@ -589,24 +610,24 @@
  */
 void irttp_flow_request(struct tsap_cb *self, LOCAL_FLOW flow)
 {
-	DEBUG(1, __FUNCTION__ "()\n");
+	IRDA_DEBUG(1, __FUNCTION__ "()\n");
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
 
 	switch (flow) {
 	case FLOW_STOP:
-		DEBUG(1, __FUNCTION__ "(), flow stop\n");
+		IRDA_DEBUG(1, __FUNCTION__ "(), flow stop\n");
 		self->rx_sdu_busy = TRUE;
 		break;
 	case FLOW_START:
-		DEBUG(1, __FUNCTION__ "(), flow start\n");
+		IRDA_DEBUG(1, __FUNCTION__ "(), flow start\n");
 		self->rx_sdu_busy = FALSE;
 		
 		irttp_run_rx_queue(self);
 		break;
 	default:
-		DEBUG(1, __FUNCTION__ "(), Unknown flow command!\n");
+		IRDA_DEBUG(1, __FUNCTION__ "(), Unknown flow command!\n");
 	}
 }
 	
@@ -625,11 +646,14 @@
 	__u8 *frame;
 	__u8 n;
 	
-	DEBUG(4, __FUNCTION__ "(), max_sdu_size=%d\n", max_sdu_size); 
+	IRDA_DEBUG(4, __FUNCTION__ "(), max_sdu_size=%d\n", max_sdu_size); 
 	
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);
+	ASSERT(self != NULL, return -EBADR;);
+	ASSERT(self->magic == TTP_TSAP_MAGIC, return -EBADR;);
 
+	if (self->connected)
+		return -EISCONN;
+	
 	/* Any userdata supplied? */
 	if (userdata == NULL) {
 		skb = dev_alloc_skb(64);
@@ -705,17 +729,16 @@
  *
  */
 static void irttp_connect_confirm(void *instance, void *sap, 
-				  struct qos_info *qos,
-				  __u32 max_seg_size, __u8 max_header_size,
-				  struct sk_buff *skb) 
+				  struct qos_info *qos, __u32 max_seg_size,
+				  __u8 max_header_size, struct sk_buff *skb) 
 {
 	struct tsap_cb *self;
 	int parameters;
-	__u8 *frame;
-	__u8 plen, pi, pl;
+	int ret;
+	__u8 plen;
 	__u8 n;
 
-	DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 	
 	self = (struct tsap_cb *) instance;
 
@@ -723,7 +746,7 @@
 	ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
 	ASSERT(skb != NULL, return;);
 
-	self->max_seg_size = max_seg_size;
+	self->max_seg_size = max_seg_size - TTP_HEADER;
 	self->max_header_size = max_header_size + TTP_HEADER;
 
 	/*
@@ -731,63 +754,53 @@
 	 *  negotiated QoS for the link.
 	 */
 	if (qos) {
-		DEBUG(4, "IrTTP, Negotiated BAUD_RATE: %02x\n", 
+		IRDA_DEBUG(4, "IrTTP, Negotiated BAUD_RATE: %02x\n", 
 		       qos->baud_rate.bits);			
-		DEBUG(4, "IrTTP, Negotiated BAUD_RATE: %d bps.\n", 
+		IRDA_DEBUG(4, "IrTTP, Negotiated BAUD_RATE: %d bps.\n", 
 		       qos->baud_rate.value);
 	}
 
-	frame = skb->data;
-	n = frame[0] & 0x7f;
+	n = skb->data[0] & 0x7f;
 	
-	DEBUG(4, __FUNCTION__ "(), Initial send_credit=%d\n", n);
+	IRDA_DEBUG(4, __FUNCTION__ "(), Initial send_credit=%d\n", n);
 	
 	self->send_credit = n;
 	self->tx_max_sdu_size = 0;
 	self->connected = TRUE;
 
-	parameters = frame[0] & 0x80;	
+	parameters = skb->data[0] & 0x80;	
 
 	ASSERT(skb->len >= TTP_HEADER, return;);
 	skb_pull(skb, TTP_HEADER);
-		
+
 	if (parameters) {
-		plen = frame[1];
-		pi   = frame[2];
-		pl   = frame[3];
-
-		switch (pl) {
-		case 1:
-			self->tx_max_sdu_size = *(frame+4);
-			break;
-		case 2:
-			self->tx_max_sdu_size = 
-				be16_to_cpu(get_unaligned((__u16 *)(frame+4)));
-			break;
-		case 4:
-			self->tx_max_sdu_size = 
-				be32_to_cpu(get_unaligned((__u32 *)(frame+4)));
-			break;
-		default:
-			printk(KERN_ERR __FUNCTION__ 
-			       "() illegal value length for max_sdu_size!\n");
-			self->tx_max_sdu_size = 0;
-		};
+		plen = skb->data[0];
 
-		DEBUG(4, __FUNCTION__ "(), RxMaxSduSize=%d\n", 
-		      self->tx_max_sdu_size);
-		
+		ret = irda_param_extract_all(self, skb->data+1,
+					     IRDA_MIN(skb->len-1, plen), 
+					     &param_info);
+
+		/* Any errors in the parameter list? */
+		if (ret < 0) {
+			WARNING(__FUNCTION__ 
+				"(), error extracting parameters\n");
+			dev_kfree_skb(skb);
+
+			/* Do not accept this connection attempt */
+			return;
+		}
 		/* Remove parameters */
-		ASSERT(skb->len >= (plen+1), return;);
-		skb_pull(skb, plen+1);
+		skb_pull(skb, IRDA_MIN(skb->len, plen+1));
 	}
 	
-	DEBUG(4, __FUNCTION__ "() send=%d,avail=%d,remote=%d\n", 
+	IRDA_DEBUG(4, __FUNCTION__ "() send=%d,avail=%d,remote=%d\n", 
 	      self->send_credit, self->avail_credit, self->remote_credit);
 
+	IRDA_DEBUG(2, __FUNCTION__ "(), MaxSduSize=%d\n", self->tx_max_sdu_size);
+
 	if (self->notify.connect_confirm) {
 		self->notify.connect_confirm(self->notify.instance, self, qos,
-					     self->tx_max_sdu_size, 
+					     self->tx_max_sdu_size,
 					     self->max_header_size, skb);
 	}
 }
@@ -805,8 +818,8 @@
 	struct tsap_cb *self;
 	struct lsap_cb *lsap;
 	int parameters;
-	__u8 *frame;
-	__u8 plen, pi, pl;
+	int ret;
+	__u8 plen;
 	__u8 n;
 
 	self = (struct tsap_cb *) instance;
@@ -817,65 +830,51 @@
 
 	lsap = (struct lsap_cb *) sap;
 
-	self->max_seg_size = max_seg_size;
-
+	self->max_seg_size = max_seg_size - TTP_HEADER;;
 	self->max_header_size = max_header_size+TTP_HEADER;
 
-	DEBUG(4, __FUNCTION__ "(), TSAP sel=%02x\n", self->stsap_sel);
+	IRDA_DEBUG(4, __FUNCTION__ "(), TSAP sel=%02x\n", self->stsap_sel);
 
 	/* Need to update dtsap_sel if its equal to LSAP_ANY */
 	self->dtsap_sel = lsap->dlsap_sel;
 
-	frame = skb->data;
-	n = frame[0] & 0x7f;
+	n = skb->data[0] & 0x7f;
 
 	self->send_credit = n;
 	self->tx_max_sdu_size = 0;
 	
-	parameters = frame[0] & 0x80;
+	parameters = skb->data[0] & 0x80;
 
 	ASSERT(skb->len >= TTP_HEADER, return;);
 	skb_pull(skb, TTP_HEADER);
-		
+
 	if (parameters) {
-		DEBUG(3, __FUNCTION__ "(), Contains parameters!\n");
-		plen = frame[1];
-		pi   = frame[2];
-		pl   = frame[3];
-
-		switch (pl) {
-		case 1:
-			self->tx_max_sdu_size = frame[4];
-			break;
-		case 2:
-			self->tx_max_sdu_size = 
-				be16_to_cpu(get_unaligned((__u16 *)(frame+4)));
-			break;
-		case 4:
-			self->tx_max_sdu_size = 
-				be32_to_cpu(get_unaligned((__u32 *)(frame+4)));
-			break;
-		default:
-			printk(KERN_ERR __FUNCTION__ 
-			       "() illegal value length for max_sdu_size!\n");
-			self->tx_max_sdu_size = 0;
-		};
+		plen = skb->data[0];
 		
-		/* Remove parameters */
-		ASSERT(skb->len >= (plen+1), return;);
-		skb_pull(skb, plen+1);
+		ret = irda_param_extract_all(self, skb->data+1,
+					     IRDA_MIN(skb->len-1, plen), 
+					     &param_info);
+
+		/* Any errors in the parameter list? */
+		if (ret < 0) {
+			WARNING(__FUNCTION__ 
+				"(), error extracting parameters\n");
+			dev_kfree_skb(skb);
+			
+			/* Do not accept this connection attempt */
+			return;
+		}
 
-		DEBUG(3, __FUNCTION__ "(), MaxSduSize=%d\n", 
-		      self->tx_max_sdu_size);
+		/* Remove parameters */
+		skb_pull(skb, IRDA_MIN(skb->len, plen+1));
 	}
 
-	DEBUG(4, __FUNCTION__ "(), initial send_credit=%d\n", n);
-
 	if (self->notify.connect_indication) {
 		self->notify.connect_indication(self->notify.instance, self, 
-						qos, self->rx_max_sdu_size, 
+						qos, self->tx_max_sdu_size, 
 						self->max_header_size, skb);
-	}
+	} else
+		dev_kfree_skb(skb);
 }
 
 /*
@@ -885,24 +884,25 @@
  *    IrLMP!
  * 
  */
-void irttp_connect_response(struct tsap_cb *self, __u32 max_sdu_size, 
-			    struct sk_buff *userdata)
+int irttp_connect_response(struct tsap_cb *self, __u32 max_sdu_size, 
+			   struct sk_buff *userdata)
 {
 	struct sk_buff *skb;
 	__u8 *frame;
+	int ret;
 	__u8 n;
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
+	ASSERT(self != NULL, return -1;);
+	ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);
 
-	DEBUG(4, __FUNCTION__ "(), Source TSAP selector=%02x\n", 
-	      self->stsap_sel);
+	IRDA_DEBUG(4, __FUNCTION__ "(), Source TSAP selector=%02x\n", 
+		   self->stsap_sel);
 	
 	/* Any userdata supplied? */
 	if (userdata == NULL) {
 		skb = dev_alloc_skb(64);
 		if (!skb)
-			return;
+			return -ENOMEM;
 
 		/* Reserve space for MUX_CONTROL and LAP header */
 		skb_reserve(skb, TTP_MAX_HEADER);
@@ -912,7 +912,7 @@
 		 *  Check that the client has reserved enough space for 
 		 *  headers
 		 */
-		ASSERT(skb_headroom(skb) >= TTP_MAX_HEADER, return;);
+		ASSERT(skb_headroom(skb) >= TTP_MAX_HEADER, return -1;);
 	}
 	
 	self->avail_credit = 0;
@@ -935,13 +935,17 @@
 	/* SAR enabled? */
 	if (max_sdu_size > 0) {
 		ASSERT(skb_headroom(skb) >= (TTP_MAX_HEADER+TTP_SAR_HEADER), 
-		       return;);
+		       return -1;);
 		
 		/* Insert TTP header with SAR parameters */
 		frame = skb_push(skb, TTP_HEADER+TTP_SAR_HEADER);
 		
 		frame[0] = TTP_PARAMETERS | n;
 		frame[1] = 0x04; /* Length */
+
+		/* irda_param_insert(self, IRTTP_MAX_SDU_SIZE, frame+1,  */
+/* 				  TTP_SAR_HEADER, &param_info) */
+		
 		frame[2] = 0x01; /* MaxSduSize */
 		frame[3] = 0x02; /* Value length */
 
@@ -954,7 +958,9 @@
 		frame[0] = n & 0x7f;
 	}
 	 
-	irlmp_connect_response(self->lsap, skb);
+	ret = irlmp_connect_response(self->lsap, skb);
+
+	return ret;
 }
 
 /*
@@ -967,15 +973,15 @@
 {
 	struct tsap_cb *new;
 
-	DEBUG(1, __FUNCTION__ "()\n");
+	IRDA_DEBUG(1, __FUNCTION__ "()\n");
 
 	if (!hashbin_find(irttp->tsaps, (int) orig, NULL)) {
-		DEBUG(0, __FUNCTION__ "(), unable to find TSAP\n");
+		IRDA_DEBUG(0, __FUNCTION__ "(), unable to find TSAP\n");
 		return NULL;
 	}
 	new = kmalloc(sizeof(struct tsap_cb), GFP_ATOMIC);
 	if (!new) {
-		DEBUG(0, __FUNCTION__ "(), unable to kmalloc\n");
+		IRDA_DEBUG(0, __FUNCTION__ "(), unable to kmalloc\n");
 		return NULL;
 	}
 	/* Dup */
@@ -990,7 +996,7 @@
 	skb_queue_head_init(&new->tx_queue);
 	skb_queue_head_init(&new->rx_fragments);
 
-	hashbin_insert(irttp->tsaps, (QUEUE *) new, (int) new, NULL);
+	hashbin_insert(irttp->tsaps, (queue_t *) new, (int) new, NULL);
 
 	return new;
 }
@@ -1002,32 +1008,31 @@
  *    segments, if any, will be deallocated first
  *
  */
-void irttp_disconnect_request(struct tsap_cb *self, struct sk_buff *userdata, 
-			      int priority)
+int irttp_disconnect_request(struct tsap_cb *self, struct sk_buff *userdata, 
+			     int priority)
 {
 	struct sk_buff *skb;
+	int ret;
 
-	DEBUG(2, __FUNCTION__ "()\n");
-
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
+	ASSERT(self != NULL, return -1;);
+	ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);
 
 	/* Already disconnected? */
 	if (!self->connected) {
-		DEBUG(4, __FUNCTION__ "(), already disconnected!\n");
-		return;
+		IRDA_DEBUG(4, __FUNCTION__ "(), already disconnected!\n");
+		return -1;
 	}
 
 	/* Disconnect already pending? */
 	if (self->disconnect_pend) {
-		DEBUG(1, __FUNCTION__ "(), disconnect already pending\n");
+		IRDA_DEBUG(1, __FUNCTION__ "(), disconnect already pending\n");
 		if (userdata) {
 			dev_kfree_skb(userdata);
 		}
 
 		/* Try to make some progress */
 		irttp_run_rx_queue(self);
-		return;
+		return -1;
 	}
 
 	/*
@@ -1035,7 +1040,7 @@
 	 */
 	if (skb_queue_len(&self->tx_queue) > 0) {
 		if (priority == P_HIGH) {
-			DEBUG(1, __FUNCTION__  "High priority!!()\n" );
+			IRDA_DEBUG(1, __FUNCTION__  "High priority!!()\n" );
 			
 			/* 
 			 *  No need to send the queued data, if we are 
@@ -1057,18 +1062,18 @@
 
 			irttp_run_tx_queue(self);
 
-			irttp_start_todo_timer(self, 100);
-			return;
+			irttp_start_todo_timer(self, MSECS_TO_JIFFIES(1000));
+			return -1;
 		}
 	}
-	DEBUG(1, __FUNCTION__ "(), Disconnecting ...\n");
+	IRDA_DEBUG(1, __FUNCTION__ "(), Disconnecting ...\n");
 
 	self->connected = FALSE;
 	
 	if (!userdata) {
 		skb = dev_alloc_skb(64);
 		if (!skb)
-			return;
+			return -ENOMEM;
 		
 		/* 
 		 *  Reserve space for MUX and LAP header 
@@ -1077,7 +1082,9 @@
 		
 		userdata = skb;
 	}
-	irlmp_disconnect_request(self->lsap, userdata);
+	ret = irlmp_disconnect_request(self->lsap, userdata);
+
+	return ret;
 }
 
 /*
@@ -1087,11 +1094,11 @@
  *
  */
 void irttp_disconnect_indication(void *instance, void *sap, LM_REASON reason, 
-				 struct sk_buff *userdata) 
+				 struct sk_buff *skb) 
 {
 	struct tsap_cb *self;
 
-	DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 
 	self = (struct tsap_cb *) instance;
 	
@@ -1100,11 +1107,22 @@
 	
 	self->connected = FALSE;
 	
-	if (!self->notify.disconnect_indication)
+	/* Check if client has already tried to close the TSAP */
+	if (self->close_pend) {
+		irttp_close_tsap(self);
 		return;
+	}
 
-	self->notify.disconnect_indication(self->notify.instance, self, reason,
-					   userdata);
+	/* No need to notify the client if has already tried to disconnect */
+	if (self->disconnect_pend)
+		return;
+	
+	if (self->notify.disconnect_indication)
+		self->notify.disconnect_indication(self->notify.instance, self,
+						   reason, skb);
+	else
+		if (skb)
+			dev_kfree_skb(skb);
 }
 
 /*
@@ -1118,6 +1136,12 @@
 {
 	int err;
 
+	/* Check if client has already tried to close the TSAP */
+	if (self->close_pend || self->disconnect_pend) {
+		dev_kfree_skb(skb);
+		return;
+	}
+
 	err = self->notify.data_indication(self->notify.instance, self, skb);
 
 	/* Usually the layer above will notify that it's input queue is
@@ -1126,7 +1150,7 @@
 	 * give an error back 
 	 */
 	if (err == -ENOMEM) {
-		DEBUG(0, __FUNCTION__ "() requeueing skb!\n");
+		IRDA_DEBUG(0, __FUNCTION__ "() requeueing skb!\n");
 
 		/* Make sure we take a break */
 		self->rx_sdu_busy = TRUE;
@@ -1151,8 +1175,8 @@
 	struct sk_buff *skb;
 	int more = 0;
 
-	DEBUG(4, __FUNCTION__ "() send=%d,avail=%d,remote=%d\n", 
-	       self->send_credit, self->avail_credit, self->remote_credit);
+	IRDA_DEBUG(2, __FUNCTION__ "() send=%d,avail=%d,remote=%d\n", 
+		   self->send_credit, self->avail_credit, self->remote_credit);
 
 	if (irda_lock(&self->rx_queue_lock) == FALSE)
 		return;
@@ -1177,7 +1201,7 @@
 		 * immediately. This can be requested by clients that
 		 * implements byte streams without any message boundaries
 		 */
-		if (self->rx_max_sdu_size == SAR_DISABLE) {
+		if (self->rx_max_sdu_size == TTP_SAR_DISABLE) {
 			irttp_do_data_indication(self, skb);
 			self->rx_sdu_size = 0;
 
@@ -1191,7 +1215,7 @@
 			 *  limits of the maximum size of the rx_sdu
 			 */
 			if (self->rx_sdu_size <= self->rx_max_sdu_size) {
-				DEBUG(4, __FUNCTION__ "(), queueing frag\n");
+				IRDA_DEBUG(4, __FUNCTION__ "(), queueing frag\n");
 				skb_queue_tail(&self->rx_fragments, skb);
 			} else {
 				/* Free the part of the SDU that is too big */
@@ -1203,7 +1227,7 @@
 		 *  This is the last fragment, so time to reassemble!
 		 */
 		if ((self->rx_sdu_size <= self->rx_max_sdu_size) ||
-		    (self->rx_max_sdu_size == SAR_UNBOUND)) 
+		    (self->rx_max_sdu_size == TTP_SAR_UNBOUND)) 
 		{
 			/* 
 			 * A little optimizing. Only queue the fragment if
@@ -1221,7 +1245,7 @@
 			/* Now we can deliver the reassembled skb */
 			irttp_do_data_indication(self, skb);
 		} else {
-			DEBUG(1, __FUNCTION__ "(), Truncated frame\n");
+			IRDA_DEBUG(1, __FUNCTION__ "(), Truncated frame\n");
 			
 			/* Free the part of the SDU that is too big */
 			dev_kfree_skb(skb);
@@ -1246,7 +1270,7 @@
 {
 	struct sk_buff* skb;
 	
-	DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
@@ -1279,10 +1303,10 @@
       	ASSERT(self != NULL, return NULL;);
 	ASSERT(self->magic == TTP_TSAP_MAGIC, return NULL;);
 
-	DEBUG(4, __FUNCTION__ "(), self->rx_sdu_size=%d\n", 
-	      self->rx_sdu_size);
+	IRDA_DEBUG(2, __FUNCTION__ "(), self->rx_sdu_size=%d\n", 
+		   self->rx_sdu_size);
 
-	skb = dev_alloc_skb(self->rx_sdu_size);
+	skb = dev_alloc_skb(TTP_HEADER + self->rx_sdu_size);
 	if (!skb)
 		return NULL;
 
@@ -1302,11 +1326,12 @@
 		
 		dev_kfree_skb(frag);
 	}
-	DEBUG(4, __FUNCTION__ "(), frame len=%d\n", n);
-	/* Set the new length */
+	IRDA_DEBUG(2, __FUNCTION__ "(), frame len=%d\n", n);
 
-	DEBUG(4, __FUNCTION__ "(), rx_sdu_size=%d\n", self->rx_sdu_size);
+	IRDA_DEBUG(2, __FUNCTION__ "(), rx_sdu_size=%d\n", self->rx_sdu_size);
 	ASSERT(n <= self->rx_sdu_size, return NULL;);
+
+	/* Set the new length */
 	skb_trim(skb, n);
 
 	self->rx_sdu_size = 0;
@@ -1325,7 +1350,7 @@
 	struct sk_buff *frag;
 	__u8 *frame;
 
-	DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
@@ -1334,22 +1359,9 @@
 	/*
 	 *  Split frame into a number of segments
 	 */
-	while (skb->len > 0) {
-		/*
-		 *  Instead of making the last segment, we just
-		 *  queue what is left of the original skb
-		 */
-		if (skb->len < self->max_seg_size) {
-			DEBUG(4, __FUNCTION__ 
-			       "(), queuing last segment\n");
-
-			frame = skb_push(skb, TTP_HEADER);
-			frame[0] = 0x00; /* Clear more bit */
-			skb_queue_tail(&self->tx_queue, skb);
-			
-			return;
-		}
-		
+	while (skb->len > self->max_seg_size) {
+		IRDA_DEBUG(2, __FUNCTION__  "(), fragmenting ...\n");
+
 		/* Make new segment */
 		frag = dev_alloc_skb(self->max_seg_size+self->max_header_size);
 		if (!frag)
@@ -1357,19 +1369,55 @@
 
 		skb_reserve(frag, self->max_header_size);
 
-		/*
-		 *  Copy data from the original skb into this fragment. We
-		 *  first insert the TTP header with the more bit set
-		 */
-		frame = skb_put(frag, self->max_seg_size+TTP_HEADER);
+		/* Copy data from the original skb into this fragment. */
+		memcpy(skb_put(frag, self->max_seg_size), skb->data, 
+		       self->max_seg_size);
+
+		/* Insert TTP header, with the more bit set */
+		frame = skb_push(frag, TTP_HEADER);
 		frame[0] = TTP_MORE;
-		memcpy(frag->data+1, skb->data, self->max_seg_size);
 		
 		/* 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, __FUNCTION__  "(), queuing last segment\n");
+	
+	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;
+
+	ASSERT(self != NULL, return -1;);
+	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(0, __FUNCTION__ "(), MaxSduSize=%d\n", param->pv.i);
+	
+	return 0;
 }
 
 /*
@@ -1382,18 +1430,15 @@
 {
 	struct tsap_cb *self = (struct tsap_cb *) data;
 
-	DEBUG(4, __FUNCTION__ "()\n");
-	
 	/* Check that we still exist */
-	if (!self || self->magic != TTP_TSAP_MAGIC) {
+	if (!self || self->magic != TTP_TSAP_MAGIC)
 		return;
-	}
-
+	
 	irttp_run_rx_queue(self);
 	irttp_run_tx_queue(self);
-
+		
 	/*  Give avay some credits to peer?  */
-	if ((self->remote_credit < LOW_THRESHOLD) && 
+	if ((self->remote_credit < TTP_LOW_THRESHOLD) && 
 	    (self->avail_credit > 0) && (skb_queue_empty(&self->tx_queue)))
 	{
 		irttp_give_credit(self);
@@ -1414,13 +1459,13 @@
 				irttp_disconnect_request(self, NULL, P_NORMAL);
 		} else {
 			/* Try again later */
-			irttp_start_todo_timer(self, 100);
+			irttp_start_todo_timer(self, 1*HZ);
 			
 			/* No reason to try and close now */
 			return;
 		}
 	}
-
+	
 	/* Check if it's closing time */
 	if (self->close_pend)
 		irttp_close_tsap(self);
@@ -1442,7 +1487,7 @@
 	self->todo_timer.data     = (unsigned long) self;
 	self->todo_timer.function = &irttp_todo_expired;
 	self->todo_timer.expires  = jiffies + timeout;
-	
+
 	add_timer(&self->todo_timer);
 }
 
@@ -1467,42 +1512,40 @@
 
 	self = (struct tsap_cb *) hashbin_get_first(irttp->tsaps);
 	while (self != NULL) {
-		if (!self || self->magic != TTP_TSAP_MAGIC) {
-			DEBUG(1, "irttp_proc_read: bad ptr self\n");
+		if (!self || self->magic != TTP_TSAP_MAGIC)
 			return len;
-		}
 
 		len += sprintf(buf+len, "TSAP %d, ", i++);
 		len += sprintf(buf+len, "stsap_sel: %02x, ", 
-				self->stsap_sel);
+			       self->stsap_sel);
 		len += sprintf(buf+len, "dtsap_sel: %02x\n", 
-				self->dtsap_sel);
+			       self->dtsap_sel);
 		len += sprintf(buf+len, "  connected: %s, ",
-				self->connected? "TRUE":"FALSE");
+			       self->connected? "TRUE":"FALSE");
 		len += sprintf(buf+len, "avail credit: %d, ",
-				self->avail_credit);
+			       self->avail_credit);
 		len += sprintf(buf+len, "remote credit: %d, ",
-				self->remote_credit);
+			       self->remote_credit);
 		len += sprintf(buf+len, "send credit: %d\n",
-				self->send_credit);
+			       self->send_credit);
 		len += sprintf(buf+len, "  tx packets: %d, ",
-				self->stats.tx_packets);
+			       self->stats.tx_packets);
 		len += sprintf(buf+len, "rx packets: %d, ",
-				self->stats.rx_packets);
+			       self->stats.rx_packets);
 		len += sprintf(buf+len, "tx_queue len: %d ", 
-				skb_queue_len(&self->tx_queue));
+			       skb_queue_len(&self->tx_queue));
 		len += sprintf(buf+len, "rx_queue len: %d\n", 
-				skb_queue_len(&self->rx_queue));
+			       skb_queue_len(&self->rx_queue));
 		len += sprintf(buf+len, "  tx_sdu_busy: %s, ",
-				self->tx_sdu_busy? "TRUE":"FALSE");
+			       self->tx_sdu_busy? "TRUE":"FALSE");
 		len += sprintf(buf+len, "rx_sdu_busy: %s\n",
-				self->rx_sdu_busy? "TRUE":"FALSE");
+			       self->rx_sdu_busy? "TRUE":"FALSE");
 		len += sprintf(buf+len, "  max_seg_size: %d, ",
-				self->max_seg_size);
+			       self->max_seg_size);
 		len += sprintf(buf+len, "tx_max_sdu_size: %d, ",
-				self->tx_max_sdu_size);
+			       self->tx_max_sdu_size);
 		len += sprintf(buf+len, "rx_max_sdu_size: %d\n",
-				self->rx_max_sdu_size);
+			       self->rx_max_sdu_size);
 
 		len += sprintf(buf+len, "  Used by (%s)\n", 
 				self->notify.name);

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)