patch-2.4.15 linux/net/irda/irttp.c
Next file: linux/net/irda/parameters.c
Previous file: linux/net/irda/irsyms.c
Back to the patch index
Back to the overall index
- Lines: 246
- Date:
Fri Nov 9 14:22:17 2001
- Orig file:
v2.4.14/linux/net/irda/irttp.c
- Orig date:
Wed Jul 25 17:10:27 2001
diff -u --recursive --new-file v2.4.14/linux/net/irda/irttp.c linux/net/irda/irttp.c
@@ -11,6 +11,7 @@
*
* Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>,
* All Rights Reserved.
+ * Copyright (c) 2000-2001 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
@@ -223,6 +224,11 @@
del_timer(&self->todo_timer);
+ /* This one won't be cleaned up if we are diconnect_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;
@@ -235,6 +241,9 @@
* 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 responsability
+ * 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)
{
@@ -248,8 +257,8 @@
/* Make sure tsap has been disconnected */
if (self->connected) {
/* Check if disconnect is not pending */
- if (!self->disconnect_pend) {
- IRDA_DEBUG(0, __FUNCTION__ "(), TSAP still connected!\n");
+ if (!test_bit(0, &self->disconnect_pend)) {
+ WARNING(__FUNCTION__ "(), TSAP still connected!\n");
irttp_disconnect_request(self, NULL, P_NORMAL);
}
self->close_pend = TRUE;
@@ -407,6 +416,7 @@
unsigned long flags;
int n;
+ /* Get exclusive access to the tx queue, otherwise don't touch it */
if (irda_lock(&self->tx_queue_lock) == FALSE)
return;
@@ -473,27 +483,17 @@
* close the socket, we are dead !
* Jean II */
if (skb->sk != NULL) {
- struct sk_buff *tx_skb;
-
/* IrSOCK application, IrOBEX, ... */
IRDA_DEBUG(4, __FUNCTION__ "() : Detaching SKB from socket.\n");
- /* Note : still looking for a more efficient way
- * to do that - Jean II */
- /* Get another skb on the same buffer, but without
- * a reference to the socket (skb->sk = NULL) */
- tx_skb = skb_clone(skb, GFP_ATOMIC);
- if (tx_skb != NULL) {
- /* Release the skb associated with the
- * socket, and use the new skb insted */
- kfree_skb(skb);
- skb = tx_skb;
- }
+ /* That's the right way to do it - Jean II */
+ skb_orphan(skb);
} else {
/* IrCOMM over IrTTP, IrLAN, ... */
IRDA_DEBUG(4, __FUNCTION__ "() : Got SKB not attached to a socket.\n");
}
+ /* Pass the skb to IrLMP - done */
irlmp_data_request(self->lsap, skb);
self->stats.tx_packets++;
@@ -1105,18 +1105,23 @@
/* Already disconnected? */
if (!self->connected) {
IRDA_DEBUG(4, __FUNCTION__ "(), already disconnected!\n");
+ if (userdata)
+ dev_kfree_skb(userdata);
return -1;
}
- /* Disconnect already pending? */
- if (self->disconnect_pend) {
- IRDA_DEBUG(1, __FUNCTION__ "(), disconnect already pending\n");
- if (userdata) {
+ /* Disconnect already pending ?
+ * We need to use an atomic operation to prevent reentry. This
+ * function may be called from various context, like user, timer
+ * for following a disconnect_indication() (i.e. net_bh).
+ * Jean II */
+ if(test_and_set_bit(0, &self->disconnect_pend)) {
+ IRDA_DEBUG(0, __FUNCTION__ "(), disconnect already pending\n");
+ if (userdata)
dev_kfree_skb(userdata);
- }
/* Try to make some progress */
- irttp_run_rx_queue(self);
+ irttp_run_tx_queue(self);
return -1;
}
@@ -1125,25 +1130,20 @@
*/
if (skb_queue_len(&self->tx_queue) > 0) {
if (priority == P_HIGH) {
- IRDA_DEBUG(1, __FUNCTION__ "High priority!!()\n" );
-
/*
* No need to send the queued data, if we are
* disconnecting right now since the data will
* not have any usable connection to be sent on
*/
+ IRDA_DEBUG(1, __FUNCTION__ "High priority!!()\n" );
irttp_flush_queues(self);
} else if (priority == P_NORMAL) {
/*
- * Must delay disconnect til after all data segments
- * have been sent an the tx_queue is empty
+ * Must delay disconnect until after all data segments
+ * have been sent and the tx_queue is empty
*/
- if (userdata)
- self->disconnect_skb = userdata;
- else
- self->disconnect_skb = NULL;
-
- self->disconnect_pend = TRUE;
+ /* We'll reuse this one later for the disconnect */
+ self->disconnect_skb = userdata; /* May be NULL */
irttp_run_tx_queue(self);
@@ -1152,9 +1152,8 @@
}
}
IRDA_DEBUG(1, __FUNCTION__ "(), Disconnecting ...\n");
-
self->connected = FALSE;
-
+
if (!userdata) {
skb = dev_alloc_skb(64);
if (!skb)
@@ -1169,6 +1168,9 @@
}
ret = irlmp_disconnect_request(self->lsap, userdata);
+ /* The disconnect is no longer pending */
+ clear_bit(0, &self->disconnect_pend); /* FALSE */
+
return ret;
}
@@ -1190,19 +1192,27 @@
ASSERT(self != NULL, return;);
ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
+ /* Prevent higher layer to send more data */
self->connected = FALSE;
/* Check if client has already tried to close the TSAP */
if (self->close_pend) {
+ /* In this case, the higher layer is probably gone. Don't
+ * bother it and clean up the remains - Jean II */
+ if (skb)
+ dev_kfree_skb(skb);
irttp_close_tsap(self);
return;
}
+ /* If we are here, we assume that is the higher layer is still
+ * waiting for the disconnect notification and able to process it,
+ * even if he tried to disconnect. Otherwise, it would have already
+ * attempted to close the tsap and self->close_pend would be TRUE.
+ * Jean II */
+
/* No need to notify the client if has already tried to disconnect */
- if (self->disconnect_pend)
- return;
-
- if (self->notify.disconnect_indication)
+ if(self->notify.disconnect_indication)
self->notify.disconnect_indication(self->notify.instance, self,
reason, skb);
else
@@ -1222,7 +1232,7 @@
int err;
/* Check if client has already tried to close the TSAP */
- if (self->close_pend || self->disconnect_pend) {
+ if (self->close_pend) {
dev_kfree_skb(skb);
return;
}
@@ -1263,6 +1273,7 @@
IRDA_DEBUG(2, __FUNCTION__ "() send=%d,avail=%d,remote=%d\n",
self->send_credit, self->avail_credit, self->remote_credit);
+ /* Get exclusive access to the rx queue, otherwise don't touch it */
if (irda_lock(&self->rx_queue_lock) == FALSE)
return;
@@ -1500,7 +1511,7 @@
else
self->tx_max_sdu_size = param->pv.i;
- IRDA_DEBUG(0, __FUNCTION__ "(), MaxSduSize=%d\n", param->pv.i);
+ IRDA_DEBUG(1, __FUNCTION__ "(), MaxSduSize=%d\n", param->pv.i);
return 0;
}
@@ -1530,18 +1541,16 @@
}
/* Check if time for disconnect */
- if (self->disconnect_pend) {
+ 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 */
- self->disconnect_pend = FALSE;
- if (self->disconnect_skb) {
- irttp_disconnect_request(
- self, self->disconnect_skb, P_NORMAL);
- self->disconnect_skb = NULL;
- } else
- irttp_disconnect_request(self, NULL, P_NORMAL);
+ 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, 1*HZ);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)