patch-2.2.6 linux/net/irda/irttp.c
Next file: linux/net/irda/wrapper.c
Previous file: linux/net/irda/irqueue.c
Back to the patch index
Back to the overall index
- Lines: 757
- Date:
Thu Apr 15 05:42:42 1999
- Orig file:
v2.2.5/linux/net/irda/irttp.c
- Orig date:
Wed Mar 10 15:29:53 1999
diff -u --recursive --new-file v2.2.5/linux/net/irda/irttp.c linux/net/irda/irttp.c
@@ -1,12 +1,12 @@
/*********************************************************************
*
* Filename: irttp.c
- * Version: 1.0
+ * Version: 1.2
* Description: Tiny Transport Protocol (TTP) implementation
* Status: Experimental.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Sun Aug 31 20:14:31 1997
- * Modified at: Sat Feb 20 01:30:39 1999
+ * Modified at: Thu Mar 25 10:27:08 1999
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
* Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>,
@@ -30,6 +30,7 @@
#include <asm/byteorder.h>
#include <net/irda/irda.h>
+#include <net/irda/irmod.h>
#include <net/irda/irlmp.h>
#include <net/irda/irttp.h>
@@ -37,15 +38,15 @@
static void __irttp_close_tsap(struct tsap_cb *self);
-static void irttp_data_indication(void *instance, void *sap,
+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_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, int max_sdu_size,
+ struct qos_info *qos, __u32 max_sdu_size,
struct sk_buff *skb);
static void irttp_run_tx_queue(struct tsap_cb *self);
@@ -127,8 +128,7 @@
self = kmalloc(sizeof(struct tsap_cb), GFP_ATOMIC);
if (self == NULL) {
- printk(KERN_ERR "IrTTP: Can't allocate memory for "
- "TSAP control block!\n");
+ DEBUG(0, __FUNCTION__ "(), unable to kmalloc!\n");
return NULL;
}
memset(self, 0, sizeof(struct tsap_cb));
@@ -136,7 +136,6 @@
init_timer(&self->todo_timer);
/* 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;
@@ -146,6 +145,12 @@
ttp_notify.instance = self;
strncpy(ttp_notify.name, notify->name, NOTIFY_MAX_NAME);
+ self->magic = TTP_TSAP_MAGIC;
+ self->connected = FALSE;
+
+ skb_queue_head_init(&self->rx_queue);
+ skb_queue_head_init(&self->tx_queue);
+ skb_queue_head_init(&self->rx_fragments);
/*
* Create LSAP at IrLMP layer
*/
@@ -165,24 +170,15 @@
self->notify = *notify;
self->lsap = lsap;
- self->magic = TTP_TSAP_MAGIC;
- self->connected = FALSE;
-
- skb_queue_head_init(&self->rx_queue);
- skb_queue_head_init(&self->tx_queue);
- skb_queue_head_init(&self->rx_fragments);
- /*
- * Insert ourself into the hashbin
- */
- hashbin_insert(irttp->tsaps, (QUEUE *) self, self->stsap_sel, NULL);
+ hashbin_insert(irttp->tsaps, (QUEUE *) self, (int) self, NULL);
if (credit > TTP_MAX_QUEUE)
self->initial_credit = TTP_MAX_QUEUE;
else
self->initial_credit = credit;
-
- return self;
+
+ return self;
}
/*
@@ -194,8 +190,6 @@
*/
static void __irttp_close_tsap(struct tsap_cb *self)
{
- DEBUG(4, __FUNCTION__ "()\n");
-
/* First make sure we're connected. */
ASSERT(self != NULL, return;);
ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
@@ -239,7 +233,7 @@
return 0; /* Will be back! */
}
- tsap = hashbin_remove(irttp->tsaps, self->stsap_sel, NULL);
+ tsap = hashbin_remove(irttp->tsaps, (int) self, NULL);
ASSERT(tsap == self, return -1;);
@@ -295,8 +289,6 @@
{
__u8 *frame;
- DEBUG(4, __FUNCTION__ "()\n");
-
ASSERT(self != NULL, return -1;);
ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);
ASSERT(skb != NULL, return -1;);
@@ -304,7 +296,7 @@
/* Check that nothing bad happens */
if ((skb->len == 0) || (!self->connected)) {
DEBUG(4, __FUNCTION__ "(), No data, or not connected\n");
- return -1;
+ return -ENOTCONN;
}
/*
@@ -314,7 +306,7 @@
if ((self->tx_max_sdu_size == 0) && (skb->len > self->max_seg_size)) {
DEBUG(1, __FUNCTION__
"(), SAR disabled, and data is to large for IrLAP!\n");
- return -1;
+ return -EMSGSIZE;
}
/*
@@ -322,11 +314,12 @@
* TxMaxSduSize
*/
if ((self->tx_max_sdu_size != 0) &&
+ (self->tx_max_sdu_size != SAR_UNBOUND) &&
(skb->len > self->tx_max_sdu_size))
{
DEBUG(1, __FUNCTION__ "(), SAR enabled, "
"but data is larger than TxMaxSduSize!\n");
- return -1;
+ return -EMSGSIZE;
}
/*
* Check if transmit queue is full
@@ -337,7 +330,7 @@
*/
irttp_run_tx_queue(self);
- return -1;
+ return -ENOBUFS;
}
/* Queue frame, or queue frame segments */
@@ -378,7 +371,7 @@
}
/*
- * Function irttp_xmit (self)
+ * Function irttp_run_tx_queue (self)
*
* If possible, transmit a frame queued for transmission.
*
@@ -396,8 +389,7 @@
if (irda_lock(&self->tx_queue_lock) == FALSE)
return;
- while ((self->send_credit > 0) && !skb_queue_empty(&self->tx_queue)){
-
+ while ((self->send_credit > 0) && !skb_queue_empty(&self->tx_queue)) {
skb = skb_dequeue(&self->tx_queue);
ASSERT(skb != NULL, return;);
@@ -409,13 +401,12 @@
* the code below is a critical region and we must assure that
* nobody messes with the credits while we update them.
*/
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&self->lock, flags);
n = self->avail_credit;
self->avail_credit = 0;
- /* Only space for 127 credits in frame */
+ /* Only room for 127 credits in frame */
if (n > 127) {
self->avail_credit = n-127;
n = 127;
@@ -423,10 +414,8 @@
self->remote_credit += n;
self->send_credit--;
- restore_flags(flags);
+ spin_unlock_irqrestore(&self->lock, flags);
- DEBUG(4, "irttp_xmit: Giving away %d credits\n", n);
-
/*
* More bit must be set by the data_request() or fragment()
* functions
@@ -443,12 +432,14 @@
/* 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) < LOW_THRESHOLD))
+ {
self->tx_sdu_busy = FALSE;
if (self->notify.flow_indication)
self->notify.flow_indication(
- self->notify.instance, self, FLOW_START);
+ self->notify.instance, self,
+ FLOW_START);
}
}
@@ -487,8 +478,7 @@
* the code below is a critical region and we must assure that
* nobody messes with the credits while we update them.
*/
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&self->lock, flags);
n = self->avail_credit;
self->avail_credit = 0;
@@ -500,7 +490,7 @@
}
self->remote_credit += n;
- restore_flags(flags);
+ spin_unlock_irqrestore(&self->lock, flags);
skb_put(tx_skb, 1);
tx_skb->data[0] = (__u8) (n & 0x7f);
@@ -512,10 +502,11 @@
/*
* Function irttp_udata_indication (instance, sap, skb)
*
- *
+ * Received some unit-data (unreliable)
*
*/
-void irttp_udata_indication(void *instance, void *sap, struct sk_buff *skb)
+static int irttp_udata_indication(void *instance, void *sap,
+ struct sk_buff *skb)
{
struct tsap_cb *self;
@@ -523,15 +514,17 @@
self = (struct tsap_cb *) instance;
- ASSERT(self != NULL, return;);
- ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
- ASSERT(skb != NULL, return;);
+ ASSERT(self != NULL, return -1;);
+ ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);
+ 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);
}
self->stats.rx_packets++;
+
+ return 0;
}
/*
@@ -540,7 +533,8 @@
* Receive segment from IrLMP.
*
*/
-void irttp_data_indication(void *instance, void *sap, struct sk_buff *skb)
+static int irttp_data_indication(void *instance, void *sap,
+ struct sk_buff *skb)
{
struct tsap_cb *self;
int more;
@@ -549,17 +543,17 @@
self = (struct tsap_cb *) instance;
- ASSERT(self != NULL, return;);
- ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
- ASSERT(skb != NULL, return;);
+ ASSERT(self != NULL, return -1;);
+ ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);
+ ASSERT(skb != NULL, return -1;);
frame = skb->data;
n = frame[0] & 0x7f; /* Extract the credits */
more = frame[0] & 0x80;
- DEBUG(4, __FUNCTION__"(), got %d credits, TSAP sel=%02x\n",
- n, self->stsap_sel);
+ DEBUG(3, __FUNCTION__"(), got %d credits, TSAP sel=%02x\n",
+ n, self->stsap_sel);
self->stats.rx_packets++;
@@ -600,6 +594,7 @@
*/
if (self->send_credit == n)
irttp_start_todo_timer(self, 0);
+ return 0;
}
/*
@@ -638,25 +633,26 @@
* Try to connect to remote destination TSAP selector
*
*/
-void irttp_connect_request(struct tsap_cb *self, __u8 dtsap_sel,
- __u32 saddr, __u32 daddr,
- struct qos_info *qos, int max_sdu_size,
- struct sk_buff *userdata)
+int irttp_connect_request(struct tsap_cb *self, __u8 dtsap_sel,
+ __u32 saddr, __u32 daddr,
+ struct qos_info *qos, __u32 max_sdu_size,
+ struct sk_buff *userdata)
{
struct sk_buff *skb;
+ __u16 tmp_be;
__u8 *frame;
__u8 n;
DEBUG(4, __FUNCTION__ "(), max_sdu_size=%d\n", max_sdu_size);
- ASSERT(self != NULL, return;);
- ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
+ ASSERT(self != NULL, return -1;);
+ ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);
/* 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_HEADER+LMP_CONTROL_HEADER+LAP_HEADER));
@@ -667,7 +663,7 @@
* headers
*/
ASSERT(skb_headroom(userdata) >=
- (TTP_HEADER+LMP_CONTROL_HEADER+LAP_HEADER), return;);
+ (TTP_HEADER+LMP_CONTROL_HEADER+LAP_HEADER), return -1;);
}
/* Initialize connection parameters */
@@ -697,7 +693,7 @@
if (max_sdu_size > 0) {
ASSERT(skb_headroom(skb) >=
(TTP_HEADER_WITH_SAR+LMP_CONTROL_HEADER+LAP_HEADER),
- return;);
+ return -1;);
/* Insert SAR parameters */
frame = skb_push(skb, TTP_HEADER_WITH_SAR);
@@ -706,7 +702,9 @@
frame[1] = 0x04; /* Length */
frame[2] = 0x01; /* MaxSduSize */
frame[3] = 0x02; /* Value length */
- *((__u16 *) (frame+4))= htons(max_sdu_size); /* Big endian! */
+
+ tmp_be = cpu_to_be16((__u16) max_sdu_size);
+ memcpy(frame+4, &tmp_be, 2);
} else {
/* Insert plain TTP header */
frame = skb_push(skb, TTP_HEADER);
@@ -716,7 +714,8 @@
}
/* Connect with IrLMP. No QoS parameters for now */
- irlmp_connect_request(self->lsap, dtsap_sel, saddr, daddr, qos, skb);
+ return irlmp_connect_request(self->lsap, dtsap_sel, saddr, daddr, qos,
+ skb);
}
/*
@@ -726,12 +725,14 @@
*
*/
void irttp_connect_confirm(void *instance, void *sap, struct qos_info *qos,
- int max_seg_size, struct sk_buff *skb)
+ __u32 max_seg_size, struct sk_buff *skb)
{
struct tsap_cb *self;
+ __u16 tmp_cpu;
__u8 *frame;
__u8 n;
int parameters;
+ __u8 plen, pi, pl;
DEBUG(4, __FUNCTION__ "()\n");
@@ -765,9 +766,16 @@
parameters = frame[0] & 0x80;
if (parameters) {
- DEBUG(4, __FUNCTION__ "(), Contains parameters!\n");
-
- self->tx_max_sdu_size = ntohs(*(__u16 *)(frame+4));
+ plen = frame[1];
+ pi = frame[2];
+ pl = frame[3];
+
+ ASSERT(pl == 2, return;);
+
+ memcpy(&tmp_cpu, frame+4, 2); /* Align value */
+ be16_to_cpus(&tmp_cpu); /* Convert to host order */
+ self->tx_max_sdu_size = tmp_cpu;
+
DEBUG(4, __FUNCTION__ "(), RxMaxSduSize=%d\n",
self->tx_max_sdu_size);
}
@@ -791,14 +799,16 @@
*
*/
void irttp_connect_indication(void *instance, void *sap,
- struct qos_info *qos, int max_seg_size,
+ struct qos_info *qos, __u32 max_seg_size,
struct sk_buff *skb)
{
struct tsap_cb *self;
struct lsap_cb *lsap;
+ __u16 tmp_cpu;
__u8 *frame;
int parameters;
int n;
+ __u8 plen, pi, pl;
self = (struct tsap_cb *) instance;
@@ -827,15 +837,23 @@
parameters = frame[0] & 0x80;
if (parameters) {
DEBUG(4, __FUNCTION__ "(), Contains parameters!\n");
-
- self->tx_max_sdu_size = ntohs(*(__u16 *)(frame+4));
+ plen = frame[1];
+ pi = frame[2];
+ pl = frame[3];
+
+ ASSERT(pl == 2, return;);
+
+ memcpy(&tmp_cpu, frame+4, 2); /* Align value */
+ be16_to_cpus(&tmp_cpu); /* Convert to host order */
+
+ self->tx_max_sdu_size = tmp_cpu;
DEBUG(4, __FUNCTION__ "(), MaxSduSize=%d\n",
self->tx_max_sdu_size);
}
DEBUG(4, __FUNCTION__ "(), initial send_credit=%d\n", n);
- skb_pull(skb, 1);
+ skb_pull(skb, 1); /* Remove TTP header */
if (self->notify.connect_indication) {
self->notify.connect_indication(self->notify.instance, self,
@@ -851,10 +869,11 @@
* IrLMP!
*
*/
-void irttp_connect_response(struct tsap_cb *self, int max_sdu_size,
+void irttp_connect_response(struct tsap_cb *self, __u32 max_sdu_size,
struct sk_buff *userdata)
{
struct sk_buff *skb;
+ __u32 tmp_be;
__u8 *frame;
__u8 n;
@@ -912,7 +931,9 @@
frame[1] = 0x04; /* Length */
frame[2] = 0x01; /* MaxSduSize */
frame[3] = 0x02; /* Value length */
- *((__u16 *) (frame+4))= htons(max_sdu_size);
+
+ tmp_be = cpu_to_be16((__u16)max_sdu_size);
+ memcpy(frame+4, &tmp_be, 2);
} else {
/* Insert TTP header */
frame = skb_push(skb, TTP_HEADER);
@@ -924,6 +945,44 @@
}
/*
+ * Function irttp_dup (self, instance)
+ *
+ * Duplicate TSAP, can be used by servers to confirm a connection on a
+ * new TSAP so it can keep listening on the old one.
+ */
+struct tsap_cb *irttp_dup(struct tsap_cb *orig, void *instance)
+{
+ struct tsap_cb *new;
+
+ DEBUG(1, __FUNCTION__ "()\n");
+
+ if (!hashbin_find(irttp->tsaps, (int) orig, NULL)) {
+ 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");
+ return NULL;
+ }
+ /* Dup */
+ memcpy(new, orig, sizeof(struct tsap_cb));
+ new->notify.instance = instance;
+ new->lsap = irlmp_dup(orig->lsap, new);
+
+ /* Not everything should be copied */
+ init_timer(&new->todo_timer);
+
+ skb_queue_head_init(&new->rx_queue);
+ skb_queue_head_init(&new->tx_queue);
+ skb_queue_head_init(&new->rx_fragments);
+
+ hashbin_insert(irttp->tsaps, (QUEUE *) new, (int) new, NULL);
+
+ return new;
+}
+
+/*
* Function irttp_disconnect_request (self)
*
* Close this connection please! If priority is high, the queued data
@@ -1028,12 +1087,44 @@
self->connected = FALSE;
- /*
- * Use callback to notify layer above
+ if (!self->notify.disconnect_indication)
+ return;
+
+ self->notify.disconnect_indication(self->notify.instance, self, reason,
+ userdata);
+}
+
+/*
+ * Function irttp_do_data_indication (self, skb)
+ *
+ * Try to deliver reassebled skb to layer above, and requeue it if that
+ * for some reason should fail. We mark rx sdu as busy to apply back
+ * pressure is necessary.
+ */
+void irttp_do_data_indication(struct tsap_cb *self, struct sk_buff *skb)
+{
+ int err;
+
+ err = self->notify.data_indication(self->notify.instance, self, skb);
+
+ /* Usually the layer above will notify that it's input queue is
+ * starting to get filled by using the flow request, but this may
+ * be difficult, so it can instead just refuse to eat it and just
+ * give an error back
*/
- if (self->notify.disconnect_indication)
- self->notify.disconnect_indication(self->notify.instance,
- self, reason, userdata);
+ if (err == -ENOMEM) {
+ DEBUG(0, __FUNCTION__ "() requeueing skb!\n");
+
+ /* Make sure we take a break */
+ self->rx_sdu_busy = TRUE;
+
+ /* Need to push the header in again */
+ skb_push(skb, TTP_HEADER);
+ skb->data[0] = 0x00; /* Make sure MORE bit is cleared */
+
+ /* Put skb back on queue */
+ skb_queue_head(&self->rx_queue, skb);
+ }
}
/*
@@ -1045,15 +1136,7 @@
void irttp_run_rx_queue(struct tsap_cb *self)
{
struct sk_buff *skb;
- __u8 *frame;
int more = 0;
- void *instance;
-
- ASSERT(self != NULL, return;);
- ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
-
- instance = self->notify.instance;
- ASSERT(instance != NULL, return;);
DEBUG(4, __FUNCTION__ "() send=%d,avail=%d,remote=%d\n",
self->send_credit, self->avail_credit, self->remote_credit);
@@ -1062,20 +1145,12 @@
return;
/*
- * Process receive queue
+ * Reassemble all frames in receive queue and deliver them
*/
- while ((!skb_queue_empty(&self->rx_queue)) && !self->rx_sdu_busy) {
-
- skb = skb_dequeue(&self->rx_queue);
- if (!skb)
- break; /* Should not happend, but ... */
-
+ while (!self->rx_sdu_busy && (skb = skb_dequeue(&self->rx_queue))) {
self->avail_credit++;
- frame = skb->data;
- more = frame[0] & 0x80;
- DEBUG(4, __FUNCTION__ "(), More=%s\n", more ? "TRUE" :
- "FALSE");
+ more = skb->data[0] & 0x80;
/* Remove TTP header */
skb_pull(skb, TTP_HEADER);
@@ -1089,10 +1164,10 @@
* immediately. This can be requested by clients that
* implements byte streams without any message boundaries
*/
- if ((self->no_defrag) || (self->rx_max_sdu_size == 0)) {
- self->notify.data_indication(instance, self, skb);
+ if (self->rx_max_sdu_size == SAR_DISABLE) {
+ irttp_do_data_indication(self, skb);
self->rx_sdu_size = 0;
-
+
continue;
}
@@ -1103,43 +1178,47 @@
* limits of the maximum size of the rx_sdu
*/
if (self->rx_sdu_size <= self->rx_max_sdu_size) {
- DEBUG(4, __FUNCTION__
- "(), queueing fragment\n");
-
+ DEBUG(4, __FUNCTION__ "(), queueing frag\n");
skb_queue_tail(&self->rx_fragments, skb);
} else {
- DEBUG(1, __FUNCTION__ "(), Error!\n");
+ /* Free the part of the SDU that is too big */
+ dev_kfree_skb(skb);
}
- } else {
- /*
- * This is the last fragment, so time to reassemble!
+ continue;
+ }
+ /*
+ * 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))
+ {
+ /*
+ * A little optimizing. Only queue the fragment if
+ * there are other fragments. Since if this is the
+ * last and only fragment, there is no need to
+ * reassemble :-)
*/
- if (self->rx_sdu_size <= self->rx_max_sdu_size) {
-
- /* A little optimizing. Only queue the
- * fragment if there is other fragments. Since
- * if this is the last and only fragment,
- * there is no need to reassemble
- */
- if (!skb_queue_empty(&self->rx_fragments)) {
-
- DEBUG(4, __FUNCTION__
- "(), queueing fragment\n");
- skb_queue_tail(&self->rx_fragments,
- skb);
-
- skb = irttp_reassemble_skb(self);
- }
- self->notify.data_indication(instance, self,
- skb);
- } else {
- DEBUG(1, __FUNCTION__
- "(), Truncated frame\n");
- self->notify.data_indication(
- self->notify.instance, self, skb);
+ if (!skb_queue_empty(&self->rx_fragments)) {
+ skb_queue_tail(&self->rx_fragments,
+ skb);
+
+ skb = irttp_reassemble_skb(self);
}
- self->rx_sdu_size = 0;
+
+ /* Now we can deliver the reassembled skb */
+ irttp_do_data_indication(self, skb);
+ } else {
+ DEBUG(1, __FUNCTION__ "(), Truncated frame\n");
+
+ /* Free the part of the SDU that is too big */
+ dev_kfree_skb(skb);
+
+ /* Deliver only the valid but truncated part of SDU */
+ skb = irttp_reassemble_skb(self);
+
+ irttp_do_data_indication(self, skb);
}
+ self->rx_sdu_size = 0;
}
/* Reset lock */
self->rx_queue_lock = 0;
@@ -1194,6 +1273,11 @@
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);
/*
@@ -1310,6 +1394,9 @@
if (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 */
+ self->disconnect_pend = FALSE;
if (self->disconnect_skb) {
irttp_disconnect_request(
self, self->disconnect_skb, P_NORMAL);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)