]> git.pld-linux.org Git - packages/kernel.git/blame - ir243_ttp_sock_races-2.diff
- ported from linux-2.4.25-atmdd.patch
[packages/kernel.git] / ir243_ttp_sock_races-2.diff
CommitLineData
f9435081 1diff -u -p linux/include/net/irda/irmod.d2.h linux/include/net/irda/irmod.h
2--- linux/include/net/irda/irmod.d2.h Wed Nov 7 13:21:31 2001
3+++ linux/include/net/irda/irmod.h Wed Nov 7 13:57:41 2001
4@@ -10,6 +10,7 @@
5 * Modified by: Dag Brattli <dagb@cs.uit.no>
6 *
7 * Copyright (c) 1998-2000 Dag Brattli, All Rights Reserved.
8+ * Copyright (c) 2000-2001 Jean Tourrilhes <jt@hpl.hp.com>
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License as
12@@ -25,108 +26,19 @@
13 #ifndef IRMOD_H
14 #define IRMOD_H
15
16-#include <linux/skbuff.h>
17-#include <linux/miscdevice.h>
18+#include <net/irda/irda.h> /* Notify stuff */
19
20-#include <net/irda/irqueue.h>
21+/* Nothing much here anymore - Maybe this header should be merged in
22+ * another header like net/irda/irda.h... - Jean II */
23
24-#define IRMGR_IOC_MAGIC 'm'
25-#define IRMGR_IOCTNPC _IO(IRMGR_IOC_MAGIC, 1)
26-#define IRMGR_IOC_MAXNR 1
27-
28-/*
29- * Events that we pass to the user space manager
30- */
31-typedef enum {
32- EVENT_DEVICE_DISCOVERED = 0,
33- EVENT_REQUEST_MODULE,
34- EVENT_IRLAN_START,
35- EVENT_IRLAN_STOP,
36- EVENT_IRLPT_START, /* Obsolete */
37- EVENT_IRLPT_STOP, /* Obsolete */
38- EVENT_IROBEX_START, /* Obsolete */
39- EVENT_IROBEX_STOP, /* Obsolete */
40- EVENT_IRDA_STOP,
41- EVENT_NEED_PROCESS_CONTEXT,
42-} IRMGR_EVENT;
43-
44-/*
45- * Event information passed to the IrManager daemon process
46- */
47-struct irmanager_event {
48- IRMGR_EVENT event;
49- char devname[10];
50- char info[32];
51- int service;
52- __u32 saddr;
53- __u32 daddr;
54-};
55-
56-typedef void (*TODO_CALLBACK)( void *self, __u32 param);
57-
58-/*
59- * Same as irmanager_event but this one can be queued and inclueds some
60- * addtional information
61- */
62-struct irda_event {
63- irda_queue_t q; /* Must be first */
64-
65- struct irmanager_event event;
66-};
67-
68-/*
69- * Funtions with needs to be called with a process context
70- */
71-struct irda_todo {
72- irda_queue_t q; /* Must be first */
73-
74- void *self;
75- TODO_CALLBACK callback;
76- __u32 param;
77-};
78-
79-/*
80- * Main structure for the IrDA device (not much here :-)
81- */
82-struct irda_cb {
83- struct miscdevice dev;
84- wait_queue_head_t wait_queue;
85-
86- int in_use;
87-
88- irda_queue_t *event_queue; /* Events queued for the irmanager */
89- irda_queue_t *todo_queue; /* Todo list */
90-};
91-
92-int irmod_init_module(void);
93-void irmod_cleanup_module(void);
94-
95-/*
96- * Function irda_lock (lock)
97- *
98- * Lock variable. Returns false if the lock is already set.
99- *
100- */
101-static inline int irda_lock(int *lock)
102-{
103- if (test_and_set_bit( 0, (void *) lock)) {
104- IRDA_DEBUG(3, __FUNCTION__
105- "(), Trying to lock, already locked variable!\n");
106- return FALSE;
107- }
108- return TRUE;
109-}
110-
111-inline int irda_unlock(int *lock);
112+/* Locking wrapper - Note the inverted logic on irda_lock().
113+ * Those function basically return false if the lock is already in the
114+ * position you want to set it. - Jean II */
115+#define irda_lock(lock) (! test_and_set_bit(0, (void *) (lock)))
116+#define irda_unlock(lock) (test_and_clear_bit(0, (void *) (lock)))
117
118+/* Zero the notify structure */
119 void irda_notify_init(notify_t *notify);
120-
121-void irda_execute_as_process(void *self, TODO_CALLBACK callback, __u32 param);
122-void irmanager_notify(struct irmanager_event *event);
123-
124-extern void irda_proc_modcount(struct inode *, int);
125-void irda_mod_inc_use_count(void);
126-void irda_mod_dec_use_count(void);
127
128 #endif /* IRMOD_H */
129
130diff -u -p linux/net/irda/irsyms.d2.c linux/net/irda/irsyms.c
131--- linux/net/irda/irsyms.d2.c Wed Nov 7 13:16:00 2001
132+++ linux/net/irda/irsyms.c Wed Nov 7 13:42:19 2001
133@@ -10,6 +10,7 @@
134 * Modified by: Dag Brattli <dagb@cs.uit.no>
135 *
136 * Copyright (c) 1997, 1999-2000 Dag Brattli, All Rights Reserved.
137+ * Copyright (c) 2000-2001 Jean Tourrilhes <jt@hpl.hp.com>
138 *
139 * This program is free software; you can redistribute it and/or
140 * modify it under the terms of the GNU General Public License as
141@@ -79,7 +80,6 @@ EXPORT_SYMBOL(irttp_dup);
142 EXPORT_SYMBOL(irda_debug);
143 #endif
144 EXPORT_SYMBOL(irda_notify_init);
145-EXPORT_SYMBOL(irda_lock);
146 #ifdef CONFIG_PROC_FS
147 EXPORT_SYMBOL(proc_irda);
148 #endif
149@@ -217,21 +217,6 @@ static void __exit irda_cleanup(void)
150
151 /* Remove middle layer */
152 irlmp_cleanup();
153-}
154-
155-/*
156- * Function irda_unlock (lock)
157- *
158- * Unlock variable. Returns false if lock is already unlocked
159- *
160- */
161-inline int irda_unlock(int *lock)
162-{
163- if (!test_and_clear_bit(0, (void *) lock)) {
164- printk("Trying to unlock already unlocked variable!\n");
165- return FALSE;
166- }
167- return TRUE;
168 }
169
170 /*
171diff -u -p linux/net/irda/irttp.d2.c linux/net/irda/irttp.c
172--- linux/net/irda/irttp.d2.c Tue Oct 30 18:14:58 2001
173+++ linux/net/irda/irttp.c Wed Nov 7 13:33:09 2001
174@@ -11,6 +11,7 @@
175 *
176 * Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>,
177 * All Rights Reserved.
178+ * Copyright (c) 2000-2001 Jean Tourrilhes <jt@hpl.hp.com>
179 *
180 * This program is free software; you can redistribute it and/or
181 * modify it under the terms of the GNU General Public License as
182@@ -223,6 +224,11 @@ static void __irttp_close_tsap(struct ts
183
184 del_timer(&self->todo_timer);
185
186+ /* This one won't be cleaned up if we are diconnect_pend + close_pend
187+ * and we receive a disconnect_indication */
188+ if (self->disconnect_skb)
189+ dev_kfree_skb(self->disconnect_skb);
190+
191 self->connected = FALSE;
192 self->magic = ~TTP_TSAP_MAGIC;
193
194@@ -235,6 +241,9 @@ static void __irttp_close_tsap(struct ts
195 * Remove TSAP from list of all TSAPs and then deallocate all resources
196 * associated with this TSAP
197 *
198+ * Note : because we *free* the tsap structure, it is the responsability
199+ * of the caller to make sure we are called only once and to deal with
200+ * possible race conditions. - Jean II
201 */
202 int irttp_close_tsap(struct tsap_cb *self)
203 {
204@@ -248,8 +257,8 @@ int irttp_close_tsap(struct tsap_cb *sel
205 /* Make sure tsap has been disconnected */
206 if (self->connected) {
207 /* Check if disconnect is not pending */
208- if (!self->disconnect_pend) {
209- IRDA_DEBUG(0, __FUNCTION__ "(), TSAP still connected!\n");
210+ if (!test_bit(0, &self->disconnect_pend)) {
211+ WARNING(__FUNCTION__ "(), TSAP still connected!\n");
212 irttp_disconnect_request(self, NULL, P_NORMAL);
213 }
214 self->close_pend = TRUE;
215@@ -407,6 +416,7 @@ static void irttp_run_tx_queue(struct ts
216 unsigned long flags;
217 int n;
218
219+ /* Get exclusive access to the tx queue, otherwise don't touch it */
220 if (irda_lock(&self->tx_queue_lock) == FALSE)
221 return;
222
223@@ -473,27 +483,17 @@ static void irttp_run_tx_queue(struct ts
224 * close the socket, we are dead !
225 * Jean II */
226 if (skb->sk != NULL) {
227- struct sk_buff *tx_skb;
228-
229 /* IrSOCK application, IrOBEX, ... */
230 IRDA_DEBUG(4, __FUNCTION__ "() : Detaching SKB from socket.\n");
231- /* Note : still looking for a more efficient way
232- * to do that - Jean II */
233
234- /* Get another skb on the same buffer, but without
235- * a reference to the socket (skb->sk = NULL) */
236- tx_skb = skb_clone(skb, GFP_ATOMIC);
237- if (tx_skb != NULL) {
238- /* Release the skb associated with the
239- * socket, and use the new skb insted */
240- kfree_skb(skb);
241- skb = tx_skb;
242- }
243+ /* That's the right way to do it - Jean II */
244+ skb_orphan(skb);
245 } else {
246 /* IrCOMM over IrTTP, IrLAN, ... */
247 IRDA_DEBUG(4, __FUNCTION__ "() : Got SKB not attached to a socket.\n");
248 }
249
250+ /* Pass the skb to IrLMP - done */
251 irlmp_data_request(self->lsap, skb);
252 self->stats.tx_packets++;
253
254@@ -1105,18 +1105,23 @@ int irttp_disconnect_request(struct tsap
255 /* Already disconnected? */
256 if (!self->connected) {
257 IRDA_DEBUG(4, __FUNCTION__ "(), already disconnected!\n");
258+ if (userdata)
259+ dev_kfree_skb(userdata);
260 return -1;
261 }
262
263- /* Disconnect already pending? */
264- if (self->disconnect_pend) {
265- IRDA_DEBUG(1, __FUNCTION__ "(), disconnect already pending\n");
266- if (userdata) {
267+ /* Disconnect already pending ?
268+ * We need to use an atomic operation to prevent reentry. This
269+ * function may be called from various context, like user, timer
270+ * for following a disconnect_indication() (i.e. net_bh).
271+ * Jean II */
272+ if(test_and_set_bit(0, &self->disconnect_pend)) {
273+ IRDA_DEBUG(0, __FUNCTION__ "(), disconnect already pending\n");
274+ if (userdata)
275 dev_kfree_skb(userdata);
276- }
277
278 /* Try to make some progress */
279- irttp_run_rx_queue(self);
280+ irttp_run_tx_queue(self);
281 return -1;
282 }
283
284@@ -1125,25 +1130,20 @@ int irttp_disconnect_request(struct tsap
285 */
286 if (skb_queue_len(&self->tx_queue) > 0) {
287 if (priority == P_HIGH) {
288- IRDA_DEBUG(1, __FUNCTION__ "High priority!!()\n" );
289-
290 /*
291 * No need to send the queued data, if we are
292 * disconnecting right now since the data will
293 * not have any usable connection to be sent on
294 */
295+ IRDA_DEBUG(1, __FUNCTION__ "High priority!!()\n" );
296 irttp_flush_queues(self);
297 } else if (priority == P_NORMAL) {
298 /*
299- * Must delay disconnect til after all data segments
300- * have been sent an the tx_queue is empty
301+ * Must delay disconnect until after all data segments
302+ * have been sent and the tx_queue is empty
303 */
304- if (userdata)
305- self->disconnect_skb = userdata;
306- else
307- self->disconnect_skb = NULL;
308-
309- self->disconnect_pend = TRUE;
310+ /* We'll reuse this one later for the disconnect */
311+ self->disconnect_skb = userdata; /* May be NULL */
312
313 irttp_run_tx_queue(self);
314
315@@ -1152,9 +1152,8 @@ int irttp_disconnect_request(struct tsap
316 }
317 }
318 IRDA_DEBUG(1, __FUNCTION__ "(), Disconnecting ...\n");
319-
320 self->connected = FALSE;
321-
322+
323 if (!userdata) {
324 skb = dev_alloc_skb(64);
325 if (!skb)
326@@ -1169,6 +1168,9 @@ int irttp_disconnect_request(struct tsap
327 }
328 ret = irlmp_disconnect_request(self->lsap, userdata);
329
330+ /* The disconnect is no longer pending */
331+ clear_bit(0, &self->disconnect_pend); /* FALSE */
332+
333 return ret;
334 }
335
336@@ -1190,19 +1192,27 @@ void irttp_disconnect_indication(void *i
337 ASSERT(self != NULL, return;);
338 ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
339
340+ /* Prevent higher layer to send more data */
341 self->connected = FALSE;
342
343 /* Check if client has already tried to close the TSAP */
344 if (self->close_pend) {
345+ /* In this case, the higher layer is probably gone. Don't
346+ * bother it and clean up the remains - Jean II */
347+ if (skb)
348+ dev_kfree_skb(skb);
349 irttp_close_tsap(self);
350 return;
351 }
352
353+ /* If we are here, we assume that is the higher layer is still
354+ * waiting for the disconnect notification and able to process it,
355+ * even if he tried to disconnect. Otherwise, it would have already
356+ * attempted to close the tsap and self->close_pend would be TRUE.
357+ * Jean II */
358+
359 /* No need to notify the client if has already tried to disconnect */
360- if (self->disconnect_pend)
361- return;
362-
363- if (self->notify.disconnect_indication)
364+ if(self->notify.disconnect_indication)
365 self->notify.disconnect_indication(self->notify.instance, self,
366 reason, skb);
367 else
368@@ -1222,7 +1232,7 @@ void irttp_do_data_indication(struct tsa
369 int err;
370
371 /* Check if client has already tried to close the TSAP */
372- if (self->close_pend || self->disconnect_pend) {
373+ if (self->close_pend) {
374 dev_kfree_skb(skb);
375 return;
376 }
377@@ -1263,6 +1273,7 @@ void irttp_run_rx_queue(struct tsap_cb *
378 IRDA_DEBUG(2, __FUNCTION__ "() send=%d,avail=%d,remote=%d\n",
379 self->send_credit, self->avail_credit, self->remote_credit);
380
381+ /* Get exclusive access to the rx queue, otherwise don't touch it */
382 if (irda_lock(&self->rx_queue_lock) == FALSE)
383 return;
384
385@@ -1500,7 +1511,7 @@ static int irttp_param_max_sdu_size(void
386 else
387 self->tx_max_sdu_size = param->pv.i;
388
389- IRDA_DEBUG(0, __FUNCTION__ "(), MaxSduSize=%d\n", param->pv.i);
390+ IRDA_DEBUG(1, __FUNCTION__ "(), MaxSduSize=%d\n", param->pv.i);
391
392 return 0;
393 }
394@@ -1530,18 +1541,16 @@ static void irttp_todo_expired(unsigned
395 }
396
397 /* Check if time for disconnect */
398- if (self->disconnect_pend) {
399+ if (test_bit(0, &self->disconnect_pend)) {
400 /* Check if it's possible to disconnect yet */
401 if (skb_queue_empty(&self->tx_queue)) {
402-
403 /* Make sure disconnect is not pending anymore */
404- self->disconnect_pend = FALSE;
405- if (self->disconnect_skb) {
406- irttp_disconnect_request(
407- self, self->disconnect_skb, P_NORMAL);
408- self->disconnect_skb = NULL;
409- } else
410- irttp_disconnect_request(self, NULL, P_NORMAL);
411+ clear_bit(0, &self->disconnect_pend); /* FALSE */
412+
413+ /* Note : self->disconnect_skb may be NULL */
414+ irttp_disconnect_request(self, self->disconnect_skb,
415+ P_NORMAL);
416+ self->disconnect_skb = NULL;
417 } else {
418 /* Try again later */
419 irttp_start_todo_timer(self, 1*HZ);
420diff -u -p linux/net/irda/af_irda.d2.c linux/net/irda/af_irda.c
421--- linux/net/irda/af_irda.d2.c Fri Nov 2 11:09:12 2001
422+++ linux/net/irda/af_irda.c Mon Nov 5 18:40:11 2001
423@@ -11,7 +11,7 @@
424 * Sources: af_netroom.c, af_ax25.c, af_rose.c, af_x25.c etc.
425 *
426 * Copyright (c) 1999 Dag Brattli <dagb@cs.uit.no>
427- * Copyright (c) 1999 Jean Tourrilhes <jt@hpl.hp.com>
428+ * Copyright (c) 1999-2001 Jean Tourrilhes <jt@hpl.hp.com>
429 * All Rights Reserved.
430 *
431 * This program is free software; you can redistribute it and/or
432@@ -134,33 +134,41 @@ static void irda_disconnect_indication(v
433
434 IRDA_DEBUG(2, __FUNCTION__ "(%p)\n", self);
435
436+ /* Don't care about it, but let's not leak it */
437+ if(skb)
438+ dev_kfree_skb(skb);
439+
440 sk = self->sk;
441 if (sk == NULL)
442 return;
443
444- sk->state = TCP_CLOSE;
445- sk->err = ECONNRESET;
446- sk->shutdown |= SEND_SHUTDOWN;
447- if (!sk->dead) {
448+ /* Prevent race conditions with irda_release() and irda_shutdown() */
449+ if ((!sk->dead) && (sk->state != TCP_CLOSE)) {
450+ sk->state = TCP_CLOSE;
451+ sk->err = ECONNRESET;
452+ sk->shutdown |= SEND_SHUTDOWN;
453+
454 sk->state_change(sk);
455- sk->dead = 1;
456- }
457+ sk->dead = 1; /* Uh-oh... Should use sock_orphan ? */
458
459- /* Close our TSAP.
460- * If we leave it open, IrLMP put it back into the list of
461- * unconnected LSAPs. The problem is that any incoming request
462- * can then be matched to this socket (and it will be, because
463- * it is at the head of the list). This would prevent any
464- * listening socket waiting on the same TSAP to get those requests.
465- * Some apps forget to close sockets, or hang to it a bit too long,
466- * so we may stay in this dead state long enough to be noticed...
467- * Note : all socket function do check sk->state, so we are safe...
468- * Jean II
469- */
470- if (self->tsap) {
471- irttp_close_tsap(self->tsap);
472- self->tsap = NULL;
473- }
474+ /* Close our TSAP.
475+ * If we leave it open, IrLMP put it back into the list of
476+ * unconnected LSAPs. The problem is that any incoming request
477+ * can then be matched to this socket (and it will be, because
478+ * it is at the head of the list). This would prevent any
479+ * listening socket waiting on the same TSAP to get those
480+ * requests. Some apps forget to close sockets, or hang to it
481+ * a bit too long, so we may stay in this dead state long
482+ * enough to be noticed...
483+ * Note : all socket function do check sk->state, so we are
484+ * safe...
485+ * Jean II
486+ */
487+ if (self->tsap) {
488+ irttp_close_tsap(self->tsap);
489+ self->tsap = NULL;
490+ }
491+ }
492
493 /* Note : once we are there, there is not much you want to do
494 * with the socket anymore, apart from closing it.
495@@ -222,7 +230,8 @@ static void irda_connect_confirm(void *i
496 self->max_data_size);
497
498 memcpy(&self->qos_tx, qos, sizeof(struct qos_info));
499- kfree_skb(skb);
500+ dev_kfree_skb(skb);
501+ // Should be ??? skb_queue_tail(&sk->receive_queue, skb);
502
503 /* We are now connected! */
504 sk->state = TCP_ESTABLISHED;
505@@ -1205,7 +1214,7 @@ static int irda_release(struct socket *s
506 sk->protinfo.irda = NULL;
507
508 sock_orphan(sk);
509- sock->sk = NULL;
510+ sock->sk = NULL;
511
512 /* Purge queues (see sock_init_data()) */
513 skb_queue_purge(&sk->receive_queue);
514diff -u -p linux/net/irda/iriap.d2.c linux/net/irda/iriap.c
515--- linux/net/irda/iriap.d2.c Fri Nov 2 11:14:13 2001
516+++ linux/net/irda/iriap.c Mon Nov 5 18:41:12 2001
517@@ -11,6 +11,7 @@
518 *
519 * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>,
520 * All Rights Reserved.
521+ * Copyright (c) 2000-2001 Jean Tourrilhes <jt@hpl.hp.com>
522 *
523 * This program is free software; you can redistribute it and/or
524 * modify it under the terms of the GNU General Public License as
525@@ -773,7 +774,7 @@ static void iriap_connect_indication(voi
526 {
527 struct iriap_cb *self, *new;
528
529- IRDA_DEBUG(0, __FUNCTION__ "()\n");
530+ IRDA_DEBUG(1, __FUNCTION__ "()\n");
531
532 self = (struct iriap_cb *) instance;
533
534diff -u -p linux/net/irda/irnet/irnet.d2.h linux/net/irda/irnet/irnet.h
535--- linux/net/irda/irnet/irnet.d2.h Wed Oct 31 16:09:19 2001
536+++ linux/net/irda/irnet/irnet.h Wed Nov 7 14:02:34 2001
537@@ -126,17 +126,17 @@
538 * History :
539 * -------
540 *
541- * v1 - 15/5/00 - Jean II
542+ * v1 - 15.5.00 - Jean II
543 * o Basic IrNET (hook to ppp_generic & IrTTP - incl. multipoint)
544 * o control channel on /dev/irnet (set name/address)
545 * o event channel on /dev/irnet (for user space daemon)
546 *
547- * v2 - 5/6/00 - Jean II
548+ * v2 - 5.6.00 - Jean II
549 * o Enable DROP_NOT_READY to avoid PPP timeouts & other weirdness...
550 * o Add DISCONNECT_TO event and rename DISCONNECT_FROM.
551 * o Set official device number alloaction on /dev/irnet
552 *
553- * v3 - 30/8/00 - Jean II
554+ * v3 - 30.8.00 - Jean II
555 * o Update to latest Linux-IrDA changes :
556 * - queue_t => irda_queue_t
557 * o Update to ppp-2.4.0 :
558@@ -148,17 +148,17 @@
559 * another multilink bug (darn !)
560 * o Remove LINKNAME_IOCTL cruft
561 *
562- * v3b - 31/8/00 - Jean II
563+ * v3b - 31.8.00 - Jean II
564 * o Dump discovery log at event channel startup
565 *
566- * v4 - 28/9/00 - Jean II
567+ * v4 - 28.9.00 - Jean II
568 * o Fix interaction between poll/select and dump discovery log
569 * o Add IRNET_BLOCKED_LINK event (depend on new IrDA-Linux patch)
570 * o Add IRNET_NOANSWER_FROM event (mostly to help support)
571 * o Release flow control in disconnect_indication
572 * o Block packets while connecting (speed up connections)
573 *
574- * v5 - 11/01/01 - Jean II
575+ * v5 - 11.01.01 - Jean II
576 * o Init self->max_header_size, just in case...
577 * o Set up ap->chan.hdrlen, to get zero copy on tx side working.
578 * o avoid tx->ttp->flow->ppp->tx->... loop, by checking flow state
579@@ -169,7 +169,7 @@
580 * o Declare hashbin HB_NOLOCK instead of HB_LOCAL to avoid
581 * disabling and enabling irq twice
582 *
583- * v6 - 31/05/01 - Jean II
584+ * v6 - 31.05.01 - Jean II
585 * o Print source address in Found, Discovery, Expiry & Request events
586 * o Print requested source address in /proc/net/irnet
587 * o Change control channel input. Allow multiple commands in one line.
588@@ -186,12 +186,19 @@
589 * o Add ttp_connect flag to prevent rentry on the connect procedure
590 * o Test and fixups to eliminate side effects of retries
591 *
592- * v7 - 22/08/01 - Jean II
593+ * v7 - 22.08.01 - Jean II
594 * o Cleanup : Change "saddr = 0x0" to "saddr = DEV_ADDR_ANY"
595 * o Fix bug in BLOCK_WHEN_CONNECT introduced in v6 : due to the
596 * asynchronous IAS query, self->tsap is NULL when PPP send the
597 * first packet. This was preventing "connect-delay 0" to work.
598 * Change the test in ppp_irnet_send() to self->ttp_connect.
599+ *
600+ * v8 - 1.11.01 - Jean II
601+ * o Tighten the use of self->ttp_connect and self->ttp_open to
602+ * prevent various race conditions.
603+ * o Avoid leaking discovery log and skb
604+ * o Replace "self" with "server" in irnet_connect_indication() to
605+ * better detect cut'n'paste error ;-)
606 */
607
608 /***************************** INCLUDES *****************************/
609@@ -204,6 +211,7 @@
610 #include <linux/proc_fs.h>
611 #include <linux/devfs_fs_kernel.h>
612 #include <linux/netdevice.h>
613+#include <linux/miscdevice.h>
614 #include <linux/poll.h>
615 #include <linux/config.h>
616 #include <linux/ctype.h> /* isspace() */
617diff -u -p linux/net/irda/irnet/irnet_irda.d2.c linux/net/irda/irnet/irnet_irda.c
618--- linux/net/irda/irnet/irnet_irda.d2.c Wed Oct 31 16:00:53 2001
619+++ linux/net/irda/irnet/irnet_irda.c Wed Nov 7 10:48:58 2001
620@@ -272,7 +272,7 @@ irnet_connect_tsap(irnet_socket * self)
621 err = irnet_open_tsap(self);
622 if(err != 0)
623 {
624- self->ttp_connect = 0;
625+ clear_bit(0, &self->ttp_connect);
626 DERROR(IRDA_SR_ERROR, "connect aborted!\n");
627 return(err);
628 }
629@@ -283,7 +283,7 @@ irnet_connect_tsap(irnet_socket * self)
630 self->max_sdu_size_rx, NULL);
631 if(err != 0)
632 {
633- self->ttp_connect = 0;
634+ clear_bit(0, &self->ttp_connect);
635 DERROR(IRDA_SR_ERROR, "connect aborted!\n");
636 return(err);
637 }
638@@ -377,7 +377,7 @@ irnet_discover_daddr_and_lsap_sel(irnet_
639 if(self->discoveries == NULL)
640 {
641 self->disco_number = -1;
642- self->ttp_connect = 0;
643+ clear_bit(0, &self->ttp_connect);
644 DRETURN(-ENETUNREACH, IRDA_SR_INFO, "No Cachelog...\n");
645 }
646 DEBUG(IRDA_SR_INFO, "Got the log (0x%X), size is %d\n",
647@@ -399,7 +399,7 @@ irnet_discover_daddr_and_lsap_sel(irnet_
648 kfree(self->discoveries);
649 self->discoveries = NULL;
650
651- self->ttp_connect = 0;
652+ clear_bit(0, &self->ttp_connect);
653 DRETURN(-ENETUNREACH, IRDA_SR_INFO, "Cachelog empty...\n");
654 }
655
656@@ -518,12 +518,12 @@ irda_irnet_connect(irnet_socket * self)
657
658 DENTER(IRDA_SOCK_TRACE, "(self=0x%X)\n", (unsigned int) self);
659
660- /* Check if we have opened a local TSAP :
661- * If we have already opened a TSAP, it means that either we are already
662- * connected or in the process of doing so... */
663- if(self->ttp_connect)
664+ /* Check if we are already trying to connect.
665+ * Because irda_irnet_connect() can be called directly by pppd plus
666+ * packet retries in ppp_generic and connect may take time, plus we may
667+ * race with irnet_connect_indication(), we need to be careful there... */
668+ if(test_and_set_bit(0, &self->ttp_connect))
669 DRETURN(-EBUSY, IRDA_SOCK_INFO, "Already connecting...\n");
670- self->ttp_connect = 1;
671 if((self->iriap != NULL) || (self->tsap != NULL))
672 DERROR(IRDA_SOCK_ERROR, "Socket not cleaned up...\n");
673
674@@ -579,6 +579,7 @@ irda_irnet_connect(irnet_socket * self)
675 *
676 * Destroy irnet instance
677 *
678+ * Note : this need to be called from a process context.
679 */
680 void
681 irda_irnet_destroy(irnet_socket * self)
682@@ -601,6 +602,23 @@ irda_irnet_destroy(irnet_socket * self)
683 DASSERT(entry == self, , IRDA_SOCK_ERROR, "Can't remove from hash.\n");
684 }
685
686+ /* If we were connected, post a message */
687+ if(test_bit(0, &self->ttp_open))
688+ {
689+ /* Note : as the disconnect comes from ppp_generic, the unit number
690+ * doesn't exist anymore when we post the event, so we need to pass
691+ * NULL as the first arg... */
692+ irnet_post_event(NULL, IRNET_DISCONNECT_TO,
693+ self->saddr, self->daddr, self->rname);
694+ }
695+
696+ /* Prevent various IrDA callbacks from messing up things
697+ * Need to be first */
698+ clear_bit(0, &self->ttp_connect);
699+
700+ /* Prevent higher layer from accessing IrTTP */
701+ clear_bit(0, &self->ttp_open);
702+
703 /* Unregister with IrLMP */
704 irlmp_unregister_client(self->ckey);
705
706@@ -611,19 +629,14 @@ irda_irnet_destroy(irnet_socket * self)
707 self->iriap = NULL;
708 }
709
710- /* If we were connected, post a message */
711- if(self->ttp_open)
712+ /* Cleanup eventual discoveries from connection attempt */
713+ if(self->discoveries != NULL)
714 {
715- /* Note : as the disconnect comes from ppp_generic, the unit number
716- * doesn't exist anymore when we post the event, so we need to pass
717- * NULL as the first arg... */
718- irnet_post_event(NULL, IRNET_DISCONNECT_TO,
719- self->saddr, self->daddr, self->rname);
720+ /* Cleanup our copy of the discovery log */
721+ kfree(self->discoveries);
722+ self->discoveries = NULL;
723 }
724
725- /* Prevent higher layer from accessing IrTTP */
726- self->ttp_open = 0;
727-
728 /* Close our IrTTP connection */
729 if(self->tsap)
730 {
731@@ -761,7 +774,7 @@ irnet_find_socket(irnet_socket * self)
732 while(new !=(irnet_socket *) NULL)
733 {
734 /* Is it available ? */
735- if(!(new->ttp_open) && (new->rdaddr == DEV_ADDR_ANY) &&
736+ if(!(test_bit(0, &new->ttp_open)) && (new->rdaddr == DEV_ADDR_ANY) &&
737 (new->rname[0] == '\0') && (new->ppp_open))
738 {
739 /* Yes !!! Get it.. */
740@@ -788,17 +801,17 @@ irnet_find_socket(irnet_socket * self)
741 *
742 */
743 static inline int
744-irnet_connect_socket(irnet_socket * self,
745+irnet_connect_socket(irnet_socket * server,
746 irnet_socket * new,
747 struct qos_info * qos,
748 __u32 max_sdu_size,
749 __u8 max_header_size)
750 {
751- DENTER(IRDA_SERV_TRACE, "(self=0x%X, new=0x%X)\n",
752- (unsigned int) self, (unsigned int) new);
753+ DENTER(IRDA_SERV_TRACE, "(server=0x%X, new=0x%X)\n",
754+ (unsigned int) server, (unsigned int) new);
755
756 /* Now attach up the new socket */
757- new->tsap = irttp_dup(self->tsap, new);
758+ new->tsap = irttp_dup(server->tsap, new);
759 DABORT(new->tsap == NULL, -1, IRDA_SERV_ERROR, "dup failed!\n");
760
761 /* Set up all the relevant parameters on the new socket */
762@@ -817,17 +830,32 @@ irnet_connect_socket(irnet_socket * self
763 #endif /* STREAM_COMPAT */
764
765 /* Clean up the original one to keep it in listen state */
766- self->tsap->dtsap_sel = self->tsap->lsap->dlsap_sel = LSAP_ANY;
767- self->tsap->lsap->lsap_state = LSAP_DISCONNECTED;
768+ server->tsap->dtsap_sel = server->tsap->lsap->dlsap_sel = LSAP_ANY;
769+ server->tsap->lsap->lsap_state = LSAP_DISCONNECTED;
770
771 /* Send a connection response on the new socket */
772 irttp_connect_response(new->tsap, new->max_sdu_size_rx, NULL);
773
774 /* Allow PPP to send its junk over the new socket... */
775- new->ttp_open = 1;
776- new->ttp_connect = 0;
777+ set_bit(0, &new->ttp_open);
778+
779+ /* Not connecting anymore, and clean up last possible remains
780+ * of connection attempts on the socket */
781+ clear_bit(0, &new->ttp_connect);
782+ if(new->iriap)
783+ {
784+ iriap_close(new->iriap);
785+ new->iriap = NULL;
786+ }
787+ if(new->discoveries != NULL)
788+ {
789+ kfree(new->discoveries);
790+ new->discoveries = NULL;
791+ }
792+
793 #ifdef CONNECT_INDIC_KICK
794- /* As currently we don't packets in ppp_irnet_send(), this is not needed...
795+ /* As currently we don't block packets in ppp_irnet_send() while passive,
796+ * this is not really needed...
797 * Also, not doing it give IrDA a chance to finish the setup properly
798 * before beeing swamped with packets... */
799 ppp_output_wakeup(&new->chan);
800@@ -835,7 +863,7 @@ irnet_connect_socket(irnet_socket * self
801
802 /* Notify the control channel */
803 irnet_post_event(new, IRNET_CONNECT_FROM,
804- new->saddr, new->daddr, self->rname);
805+ new->saddr, new->daddr, server->rname);
806
807 DEXIT(IRDA_SERV_TRACE, "\n");
808 return 0;
809@@ -1053,12 +1081,33 @@ irnet_disconnect_indication(void * insta
810 struct sk_buff *skb)
811 {
812 irnet_socket * self = (irnet_socket *) instance;
813+ int test = 0;
814
815 DENTER(IRDA_TCB_TRACE, "(self=0x%X)\n", (unsigned int) self);
816 DASSERT(self != NULL, , IRDA_CB_ERROR, "Self is NULL !!!\n");
817
818+ /* Don't care about it, but let's not leak it */
819+ if(skb)
820+ dev_kfree_skb(skb);
821+
822+ /* Prevent higher layer from accessing IrTTP */
823+ test = test_and_clear_bit(0, &self->ttp_open);
824+ /* Not connecting anymore...
825+ * (note : TSAP is open, so IAP callbacks are no longer pending...) */
826+ test |= test_and_clear_bit(0, &self->ttp_connect);
827+
828+ /* If both self->ttp_open and self->ttp_connect are NULL, it mean that we
829+ * have a race condition with irda_irnet_destroy() or
830+ * irnet_connect_indication(), so don't mess up tsap...
831+ */
832+ if(!test)
833+ {
834+ DERROR(IRDA_CB_ERROR, "Race condition detected...\n");
835+ return;
836+ }
837+
838 /* If we were active, notify the control channel */
839- if(self->ttp_open)
840+ if(test_bit(0, &self->ttp_open))
841 irnet_post_event(self, IRNET_DISCONNECT_FROM,
842 self->saddr, self->daddr, self->rname);
843 else
844@@ -1067,15 +1116,10 @@ irnet_disconnect_indication(void * insta
845 irnet_post_event(self, IRNET_NOANSWER_FROM,
846 self->saddr, self->daddr, self->rname);
847
848- /* Prevent higher layer from accessing IrTTP */
849- self->ttp_open = 0;
850- self->ttp_connect = 0;
851-
852- /* Close our IrTTP connection */
853+ /* Close our IrTTP connection, cleanup tsap */
854 if((self->tsap) && (self != &irnet_server.s))
855 {
856 DEBUG(IRDA_CB_INFO, "Closing our TTP connection.\n");
857- irttp_disconnect_request(self->tsap, NULL, P_NORMAL);
858 irttp_close_tsap(self->tsap);
859 self->tsap = NULL;
860
861@@ -1114,6 +1158,13 @@ irnet_connect_confirm(void * instance,
862
863 DENTER(IRDA_TCB_TRACE, "(self=0x%X)\n", (unsigned int) self);
864
865+ /* Check if socket is closing down (via irda_irnet_destroy()) */
866+ if(! test_bit(0, &self->ttp_connect))
867+ {
868+ DERROR(IRDA_CB_ERROR, "Socket no longer connecting. Ouch !\n");
869+ return;
870+ }
871+
872 /* How much header space do we need to reserve */
873 self->max_header_size = max_header_size;
874
875@@ -1129,8 +1180,8 @@ irnet_connect_confirm(void * instance,
876 self->saddr = irttp_get_saddr(self->tsap);
877
878 /* Allow higher layer to access IrTTP */
879- self->ttp_connect = 0;
880- self->ttp_open = 1;
881+ set_bit(0, &self->ttp_open);
882+ clear_bit(0, &self->ttp_connect); /* Not racy, IrDA traffic is serial */
883 /* Give a kick in the ass of ppp_generic so that he sends us some data */
884 ppp_output_wakeup(&self->chan);
885
886@@ -1251,56 +1302,76 @@ irnet_connect_indication(void * instanc
887 __u8 max_header_size,
888 struct sk_buff *skb)
889 {
890- irnet_socket * self = &irnet_server.s;
891+ irnet_socket * server = &irnet_server.s;
892 irnet_socket * new = (irnet_socket *) NULL;
893
894- DENTER(IRDA_TCB_TRACE, "(self=0x%X)\n", (unsigned int) self);
895+ DENTER(IRDA_TCB_TRACE, "(server=0x%X)\n", (unsigned int) server);
896 DASSERT(instance == &irnet_server, , IRDA_CB_ERROR,
897 "Invalid instance (0x%X) !!!\n", (unsigned int) instance);
898 DASSERT(sap == irnet_server.s.tsap, , IRDA_CB_ERROR, "Invalid sap !!!\n");
899
900 /* Try to find the most appropriate IrNET socket */
901- new = irnet_find_socket(self);
902+ new = irnet_find_socket(server);
903
904 /* After all this hard work, do we have an socket ? */
905 if(new == (irnet_socket *) NULL)
906 {
907 DEXIT(IRDA_CB_INFO, ": No socket waiting for this connection.\n");
908- irnet_disconnect_server(self, skb);
909+ irnet_disconnect_server(server, skb);
910 return;
911 }
912
913 /* Is the socket already busy ? */
914- if(new->ttp_open)
915+ if(test_bit(0, &new->ttp_open))
916 {
917 DEXIT(IRDA_CB_INFO, ": Socket already connected.\n");
918- irnet_disconnect_server(self, skb);
919+ irnet_disconnect_server(server, skb);
920 return;
921 }
922
923- /* Socket connecting */
924- if(new->tsap != NULL)
925- {
926- /* The socket has sent a IrTTP connection request and is waiting for
927- * a connection response (that may never come).
928- * Now, the pain is that the socket has open a tsap and is waiting on it,
929- * while the other end is trying to connect to it on another tsap.
930- * Argh ! We will deal with that later...
931+ /* Socket connecting ?
932+ * Clear up flag : prevent irnet_disconnect_indication() to mess up tsap */
933+ if(test_and_clear_bit(0, &new->ttp_connect))
934+ {
935+ /* The socket is trying to connect to the other end and may have sent
936+ * a IrTTP connection request and is waiting for a connection response
937+ * (that may never come).
938+ * Now, the pain is that the socket may have opened a tsap and is
939+ * waiting on it, while the other end is trying to connect to it on
940+ * another tsap.
941 */
942 DERROR(IRDA_CB_ERROR, "Socket already connecting. Ouch !\n");
943 #ifdef ALLOW_SIMULT_CONNECT
944- /* Close the connection the new socket was attempting.
945- * WARNING : This need more testing ! */
946- irttp_close_tsap(new->tsap);
947+ /* Cleanup the TSAP if necessary - IrIAP will be cleaned up later */
948+ if(new->tsap != NULL)
949+ {
950+ /* Close the connection the new socket was attempting.
951+ * This seems to be safe... */
952+ irttp_close_tsap(new->tsap);
953+ new->tsap = NULL;
954+ }
955 /* Note : no return, fall through... */
956 #else /* ALLOW_SIMULT_CONNECT */
957- irnet_disconnect_server(self, skb);
958+ irnet_disconnect_server(server, skb);
959 return;
960 #endif /* ALLOW_SIMULT_CONNECT */
961 }
962+ else
963+ /* If socket is not connecting or connected, tsap should be NULL */
964+ if(new->tsap != NULL)
965+ {
966+ /* If we are here, we are also in irnet_disconnect_indication(),
967+ * and it's a nice race condition... On the other hand, we can't be
968+ * in irda_irnet_destroy() otherwise we would not have found the
969+ * socket in the hashbin. */
970+ /* Better get out of here, otherwise we will mess up tsaps ! */
971+ DERROR(IRDA_CB_ERROR, "Race condition detected, abort connect...\n");
972+ irnet_disconnect_server(server, skb);
973+ return;
974+ }
975
976 /* So : at this point, we have a socket, and it is idle. Good ! */
977- irnet_connect_socket(self, new, qos, max_sdu_size, max_header_size);
978+ irnet_connect_socket(server, new, qos, max_sdu_size, max_header_size);
979
980 /* Check size of received packet */
981 if(skb->len > 0)
982@@ -1349,24 +1420,25 @@ irnet_getvalue_confirm(int result,
983 DENTER(IRDA_OCB_TRACE, "(self=0x%X)\n", (unsigned int) self);
984 DASSERT(self != NULL, , IRDA_OCB_ERROR, "Self is NULL !!!\n");
985
986- /* We probably don't need to make any more queries */
987- iriap_close(self->iriap);
988- self->iriap = NULL;
989-
990- /* Check if already connected (via irnet_connect_socket()) */
991- if(self->ttp_open)
992+ /* Check if already connected (via irnet_connect_socket())
993+ * or socket is closing down (via irda_irnet_destroy()) */
994+ if(! test_bit(0, &self->ttp_connect))
995 {
996- DERROR(IRDA_OCB_ERROR, "Socket already connected. Ouch !\n");
997+ DERROR(IRDA_OCB_ERROR, "Socket no longer connecting. Ouch !\n");
998 return;
999 }
1000
1001+ /* We probably don't need to make any more queries */
1002+ iriap_close(self->iriap);
1003+ self->iriap = NULL;
1004+
1005 /* Post process the IAS reply */
1006 self->dtsap_sel = irnet_ias_to_tsap(self, result, value);
1007
1008 /* If error, just go out */
1009 if(self->errno)
1010 {
1011- self->ttp_connect = 0;
1012+ clear_bit(0, &self->ttp_connect);
1013 DERROR(IRDA_OCB_ERROR, "IAS connect failed ! (0x%X)\n", self->errno);
1014 return;
1015 }
1016@@ -1412,6 +1484,14 @@ irnet_discovervalue_confirm(int result,
1017 DENTER(IRDA_OCB_TRACE, "(self=0x%X)\n", (unsigned int) self);
1018 DASSERT(self != NULL, , IRDA_OCB_ERROR, "Self is NULL !!!\n");
1019
1020+ /* Check if already connected (via irnet_connect_socket())
1021+ * or socket is closing down (via irda_irnet_destroy()) */
1022+ if(! test_bit(0, &self->ttp_connect))
1023+ {
1024+ DERROR(IRDA_OCB_ERROR, "Socket no longer connecting. Ouch !\n");
1025+ return;
1026+ }
1027+
1028 /* Post process the IAS reply */
1029 dtsap_sel = irnet_ias_to_tsap(self, result, value);
1030
1031@@ -1468,15 +1548,8 @@ irnet_discovervalue_confirm(int result,
1032 if(self->daddr == DEV_ADDR_ANY)
1033 {
1034 self->daddr = DEV_ADDR_ANY;
1035- self->ttp_connect = 0;
1036+ clear_bit(0, &self->ttp_connect);
1037 DEXIT(IRDA_OCB_TRACE, ": cannot discover IrNET in any device !!!\n");
1038- return;
1039- }
1040-
1041- /* Check if already connected (via irnet_connect_socket()) */
1042- if(self->ttp_open)
1043- {
1044- DERROR(IRDA_OCB_ERROR, "Socket already connected. Ouch !\n");
1045 return;
1046 }
1047
1048diff -u -p linux/net/irda/irnet/irnet_ppp.d2.c linux/net/irda/irnet/irnet_ppp.c
1049--- linux/net/irda/irnet/irnet_ppp.d2.c Thu Nov 1 12:14:43 2001
1050+++ linux/net/irda/irnet/irnet_ppp.c Thu Nov 1 14:11:53 2001
1051@@ -850,7 +850,7 @@ ppp_irnet_send(struct ppp_channel * chan
1052 DASSERT(self != NULL, 0, PPP_ERROR, "Self is NULL !!!\n");
1053
1054 /* Check if we are connected */
1055- if(self->ttp_open == 0)
1056+ if(!(test_bit(0, &self->ttp_open)))
1057 {
1058 #ifdef CONNECT_IN_SEND
1059 /* Let's try to connect one more time... */
1060@@ -884,7 +884,7 @@ ppp_irnet_send(struct ppp_channel * chan
1061 */
1062 #ifdef BLOCK_WHEN_CONNECT
1063 /* If we are attempting to connect */
1064- if(self->ttp_connect)
1065+ if(test_bit(0, &self->ttp_connect))
1066 {
1067 /* Blocking packet, ppp_generic will retry later */
1068 return 0;
1069
This page took 0.270664 seconds and 4 git commands to generate.