]> git.pld-linux.org Git - packages/kernel.git/blob - ir243_ttp_sock_races-2.diff
- added description of djurban's branch
[packages/kernel.git] / ir243_ttp_sock_races-2.diff
1 diff -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  
130 diff -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  /*
171 diff -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);
420 diff -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);
514 diff -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  
534 diff -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() */
617 diff -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  
1048 diff -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.157274 seconds and 3 git commands to generate.