Hi Dag,

        I was fixing the last multilink bugs of IrNET, and I've had to
make a few changes to the IrDA stack to get everything proper. I took
advantage to nail a few suttle bugs, as usual.
        Patch attached...

        Enjoy...

        Jean
diff -u -p linux/include/net/irda/irlmp.d4.h linux/include/net/irda/irlmp.h
--- linux/include/net/irda/irlmp.d4.h   Tue Aug 29 11:46:24 2000
+++ linux/include/net/irda/irlmp.h      Wed Aug 30 12:13:27 2000
@@ -85,8 +85,8 @@ typedef struct {
 
        __u16 hint_mask;
 
-       DISCOVERY_CALLBACK1 callback1;
-       DISCOVERY_CALLBACK2 callback2;
+       DISCOVERY_CALLBACK1 disco_callback;     /* Selective discovery */
+       DISCOVERY_CALLBACK1 expir_callback;     /* Selective expiration */
        void *priv;                /* Used to identify client */
 } irlmp_client_t;
 
@@ -192,11 +192,12 @@ void irlmp_close_lsap( struct lsap_cb *s
 __u16 irlmp_service_to_hint(int service);
 __u32 irlmp_register_service(__u16 hints);
 int irlmp_unregister_service(__u32 handle);
-__u32 irlmp_register_client(__u16 hint_mask, DISCOVERY_CALLBACK1 callback1,
-                           DISCOVERY_CALLBACK2 callback2, void *priv);
+__u32 irlmp_register_client(__u16 hint_mask, DISCOVERY_CALLBACK1 disco_clb,
+                           DISCOVERY_CALLBACK1 expir_clb, void *priv);
 int irlmp_unregister_client(__u32 handle);
 int irlmp_update_client(__u32 handle, __u16 hint_mask, 
-                       DISCOVERY_CALLBACK1, DISCOVERY_CALLBACK2, void *priv);
+                       DISCOVERY_CALLBACK1 disco_clb,
+                       DISCOVERY_CALLBACK1 expir_clb, void *priv);
 
 void irlmp_register_link(struct irlap_cb *, __u32 saddr, notify_t *);
 void irlmp_unregister_link(__u32 saddr);
@@ -218,6 +219,7 @@ void irlmp_discovery_request(int nslots)
 struct irda_device_info *irlmp_get_discoveries(int *pn, __u16 mask);
 void irlmp_do_discovery(int nslots);
 discovery_t *irlmp_get_discovery_response(void);
+void irlmp_discovery_expiry(discovery_t *expiry);
 
 int  irlmp_data_request(struct lsap_cb *, struct sk_buff *);
 void irlmp_data_indication(struct lsap_cb *, struct sk_buff *);
diff -u -p linux/include/net/irda/irqueue.d4.h linux/include/net/irda/irqueue.h
--- linux/include/net/irda/irqueue.d4.h Tue Aug 29 17:54:53 2000
+++ linux/include/net/irda/irqueue.h    Wed Aug 30 12:10:01 2000
@@ -89,6 +89,7 @@ void     hashbin_insert(hashbin_t* hashb
 void*    hashbin_find(hashbin_t* hashbin, __u32 hashv, char* name);
 void*    hashbin_remove(hashbin_t* hashbin, __u32 hashv, char* name);
 void*    hashbin_remove_first(hashbin_t *hashbin);
+void*   hashbin_remove_this( hashbin_t* hashbin, irda_queue_t* entry);
 irda_queue_t *hashbin_get_first(hashbin_t *hashbin);
 irda_queue_t *hashbin_get_next(hashbin_t *hashbin);
 
diff -u -p linux/net/irda/af_irda.d4.c linux/net/irda/af_irda.c
--- linux/net/irda/af_irda.d4.c Tue Aug 29 10:13:55 2000
+++ linux/net/irda/af_irda.c    Wed Aug 30 09:42:33 2000
@@ -366,33 +366,6 @@ static void irda_getvalue_confirm(int re
        wake_up_interruptible(&self->query_wait);
 }
 
-#if 0
-/* Obsolete */
-/*
- * Function irda_discovery_indication (log)
- *
- *    Got a discovery log from IrLMP, wake up any process waiting for answer
- *
- */
-static void irda_discovery_indication(hashbin_t *log, void *priv)
-{
-       struct irda_sock *self;
-       
-       IRDA_DEBUG(2, __FUNCTION__ "()\n");
-
-       self = (struct irda_sock *) priv;
-       if (!self) {
-               WARNING(__FUNCTION__ "(), lost myself!\n");
-               return;
-       }
-
-       self->cachelog = log;
-
-       /* Wake up process if its waiting for device to be discovered */
-       wake_up_interruptible(&self->query_wait);
-}
-#endif
-
 /*
  * Function irda_selective_discovery_indication (discovery)
  *
@@ -2174,8 +2147,8 @@ static int irda_getsockopt(struct socket
 
                /* Tell IrLMP we want to be notified */
                irlmp_update_client(self->ckey, self->mask,
-                                   irda_selective_discovery_indication, NULL,
-                                   (void *) self);
+                                   irda_selective_discovery_indication,
+                                   NULL, (void *) self);
                
                /* Do some discovery (and also return cached results) */
                irlmp_discovery_request(self->nslots);
diff -u -p linux/net/irda/discovery.d4.c linux/net/irda/discovery.c
--- linux/net/irda/discovery.d4.c       Tue Aug 29 15:22:05 2000
+++ linux/net/irda/discovery.c  Tue Aug 29 18:17:12 2000
@@ -75,14 +75,15 @@ void irlmp_add_discovery(hashbin_t *cach
 
                /* Be sure to stay one item ahead */
                discovery = (discovery_t *) hashbin_get_next(cachelog);
-                       
-               if ((node->daddr == new->daddr) || 
-                   (strcmp(node->nickname, new->nickname) == 0))
+
+               if ((node->saddr == new->saddr) &&
+                   ((node->daddr == new->daddr) || 
+                    (strcmp(node->nickname, new->nickname) == 0)))
                {
                        /* This discovery is a previous discovery 
                         * from the same device, so just remove it
                         */
-                       hashbin_remove(cachelog, node->daddr, NULL);
+                       hashbin_remove_this(cachelog, (irda_queue_t *) node);
                        /* Check if hints bits have changed */
                        if(node->hints.word == new->hints.word)
                                /* Set time of first discovery for this node */
@@ -135,6 +136,8 @@ void irlmp_add_discovery_log(hashbin_t *
  *
  *    Go through all discoveries and expire all that has stayed to long
  *
+ * Note : this assume that IrLAP won't change its saddr, which
+ * currently is a valid assumption...
  */
 void irlmp_expire_discoveries(hashbin_t *log, __u32 saddr, int force)
 {
@@ -153,10 +156,14 @@ void irlmp_expire_discoveries(hashbin_t 
                discovery = (discovery_t *) hashbin_get_next(log);
 
                /* Test if it's time to expire this discovery */
-               if ((curr->saddr == saddr) && (force ||
-                   ((jiffies - curr->timestamp) > DISCOVERY_EXPIRE_TIMEOUT)))
+               if ((curr->saddr == saddr) &&
+                   (force ||
+                    ((jiffies - curr->timestamp) > DISCOVERY_EXPIRE_TIMEOUT)))
                {
-                       curr = hashbin_remove(log, curr->daddr, NULL);
+                       /* Tell IrLMP and registered clients about it */
+                       irlmp_discovery_expiry(curr);
+                       /* Remove it from the log */
+                       curr = hashbin_remove_this(log, (irda_queue_t *) curr);
                        if (curr)
                                kfree(curr);
                }
@@ -298,23 +305,23 @@ __u32 irlmp_find_device(hashbin_t *cache
  *    Print discovery information in /proc file system
  *
  */
-int discovery_proc_read(char *buf, char **start, off_t offset, int len, 
+int discovery_proc_read(char *buf, char **start, off_t offset, int length, 
                        int unused)
 {
        discovery_t *discovery;
        unsigned long flags;
        hashbin_t *cachelog = irlmp_get_cachelog();
+       int             len = 0;
 
        if (!irlmp)
                return len;
 
        len = sprintf(buf, "IrLMP: Discovery log:\n\n");        
        
-       save_flags(flags);
-       cli();
-       
+       spin_lock_irqsave(&irlmp->log_lock, flags);
+
        discovery = (discovery_t *) hashbin_get_first(cachelog);
-       while ( discovery != NULL) {
+       while (( discovery != NULL) && (len < length)) {
                len += sprintf(buf+len, "nickname: %s,", discovery->nickname);
                
                len += sprintf(buf+len, " hint: 0x%02x%02x", 
@@ -355,7 +362,7 @@ int discovery_proc_read(char *buf, char 
                
                discovery = (discovery_t *) hashbin_get_next(cachelog);
        }
-       restore_flags(flags);
+       spin_unlock_irqrestore(&irlmp->log_lock, flags);
 
        return len;
 }
diff -u -p linux/net/irda/irlmp.d4.c linux/net/irda/irlmp.c
--- linux/net/irda/irlmp.d4.c   Tue Aug 29 11:52:49 2000
+++ linux/net/irda/irlmp.c      Wed Aug 30 10:03:09 2000
@@ -837,22 +837,18 @@ void irlmp_check_services(discovery_t *d
  *     o IrComm
  *     o IrLAN
  *     o Any socket (in any state - ouch, that may be a lot !)
- * The client may have defined one of two callback to be notified in case
- * of discovery, one callback for any discovery and one for partial/selective
- * discovery based on the hints that it passed to IrLMP.
+ * The client may have defined a callback to be notified in case of
+ * partial/selective discovery based on the hints that it passed to IrLMP.
  */
-void irlmp_notify_client(irlmp_client_t *client, hashbin_t *log)
+static inline void
+irlmp_notify_client(irlmp_client_t *client, hashbin_t *log)
 {
        discovery_t *discovery;
 
        IRDA_DEBUG(3, __FUNCTION__ "()\n");
        
-       /* Check if client wants the whole log */
-       if (client->callback2)
-               client->callback2(log, client->priv);
-       
        /* Check if client wants or not partial/selective log (optimisation) */
-       if (!client->callback1)
+       if (!client->disco_callback)
                return;
 
        /* 
@@ -867,10 +863,9 @@ void irlmp_notify_client(irlmp_client_t 
                 * Any common hint bits? Remember to mask away the extension
                 * bits ;-)
                 */
-               if (client->hint_mask & discovery->hints.word & 0x7f7f) {
-                       if (client->callback1)
-                               client->callback1(discovery, client->priv);
-               }
+               if (client->hint_mask & discovery->hints.word & 0x7f7f)
+                       client->disco_callback(discovery, client->priv);
+
                discovery = (discovery_t *) hashbin_get_next(log);
        }
 }
@@ -903,9 +898,40 @@ void irlmp_discovery_confirm(hashbin_t *
 }
 
 /*
+ * Function irlmp_discovery_expiry (expiry)
+ *
+ *     This device is no longer been discovered, and therefore it is beeing
+ *     purged from the discovery log. Inform all clients who have
+ *     registered for this event...
+ * 
+ *     Note : called exclusively from discovery.c
+ *     Note : as we are currently processing the log, the clients callback
+ *     should *NOT* attempt to touch the log now.
+ */
+void irlmp_discovery_expiry(discovery_t *expiry) 
+{
+       irlmp_client_t *client;
+       
+       IRDA_DEBUG(3, __FUNCTION__ "()\n");
+
+       ASSERT(expiry != NULL, return;);
+       
+       client = (irlmp_client_t *) hashbin_get_first(irlmp->clients);
+       while (client != NULL) {
+               /* Check if we should notify client */
+               if ((client->expir_callback) &&
+                   (client->hint_mask & expiry->hints.word & 0x7f7f))
+                       client->expir_callback(expiry, client->priv);
+
+               /* Next client */
+               client = (irlmp_client_t *) hashbin_get_next(irlmp->clients);
+       }
+}
+
+/*
  * Function irlmp_get_discovery_response ()
  *
- *    Used by IrLAP to get the disocvery info it needs when answering
+ *    Used by IrLAP to get the discovery info it needs when answering
  *    discovery requests by other devices.
  */
 discovery_t *irlmp_get_discovery_response()
@@ -1294,11 +1320,13 @@ int irlmp_unregister_service(__u32 handl
  * Function irlmp_register_client (hint_mask, callback1, callback2)
  *
  *    Register a local client with IrLMP
+ *     First callback is selective discovery (based on hints)
+ *     Second callback is for selective discovery expiries
  *
  *    Returns: handle > 0 on success, 0 on error
  */
-__u32 irlmp_register_client(__u16 hint_mask, DISCOVERY_CALLBACK1 callback1,
-                           DISCOVERY_CALLBACK2 callback2, void *priv)
+__u32 irlmp_register_client(__u16 hint_mask, DISCOVERY_CALLBACK1 disco_clb,
+                           DISCOVERY_CALLBACK1 expir_clb, void *priv)
 {
        irlmp_client_t *client;
        __u32 handle;
@@ -1318,8 +1346,8 @@ __u32 irlmp_register_client(__u16 hint_m
 
        /* Register the details */
        client->hint_mask = hint_mask;
-       client->callback1 = callback1;
-       client->callback2 = callback2;
+       client->disco_callback = disco_clb;
+       client->expir_callback = expir_clb;
        client->priv = priv;
 
        hashbin_insert(irlmp->clients, (irda_queue_t *) client, handle, NULL);
@@ -1336,8 +1364,8 @@ __u32 irlmp_register_client(__u16 hint_m
  *    Returns: 0 on success, -1 on error
  */
 int irlmp_update_client(__u32 handle, __u16 hint_mask, 
-                       DISCOVERY_CALLBACK1 callback1, 
-                       DISCOVERY_CALLBACK2 callback2, void *priv)
+                       DISCOVERY_CALLBACK1 disco_clb, 
+                       DISCOVERY_CALLBACK1 expir_clb, void *priv)
 {
        irlmp_client_t *client;
 
@@ -1351,8 +1379,8 @@ int irlmp_update_client(__u32 handle, __
        }
 
        client->hint_mask = hint_mask;
-       client->callback1 = callback1;
-       client->callback2 = callback2;
+       client->disco_callback = disco_clb;
+       client->expir_callback = expir_clb;
        client->priv = priv;
        
        return 0;
diff -u -p linux/net/irda/irlap_event.d4.c linux/net/irda/irlap_event.c
--- linux/net/irda/irlap_event.d4.c     Tue Aug 29 15:48:02 2000
+++ linux/net/irda/irlap_event.c        Tue Aug 29 16:05:03 2000
@@ -492,6 +492,30 @@ static int irlap_state_query(struct irla
                /* irlap_next_state(self, LAP_QUERY);  */
 
                break;
+       case RECV_DISCOVERY_XID_CMD:
+               /* Yes, it is possible to receive those frames in this mode.
+                * This would happen is both discoveries are just slightly
+                * offset (if they are in sync, all packets are lost).
+                * The big trouble when it happen is that passive discovery
+                * doesn't happen, because nobody answer the discoveries
+                * frame of the other guy, so the log shows up empty.
+                * What should we do ?
+                * Not much. We are currently performing our own discovery,
+                * therefore we can't answer those frames. We don't want
+                * to change state either. We just pass the info to
+                * IrLMP who will put it in the log (and post an event).
+                * Jean II
+                */
+
+               ASSERT(info != NULL, return -1;);
+
+               IRDA_DEBUG(1, __FUNCTION__ "(), Receiving event %d, %s\n",
+                          event, irlap_event[event]);
+
+               /* Last discovery frame? */
+               if (info->s == 0xff)
+                       irlap_discovery_indication(self, info->discovery); 
+               break;
        case SLOT_TIMER_EXPIRED:
                /*
                 * Wait a little longer if we detect an incomming frame. This
diff -u -p linux/net/irda/irlmp_frame.d4.c linux/net/irda/irlmp_frame.c
--- linux/net/irda/irlmp_frame.d4.c     Tue Aug 29 16:12:07 2000
+++ linux/net/irda/irlmp_frame.c        Tue Aug 29 16:16:27 2000
@@ -397,7 +397,7 @@ void irlmp_link_discovery_indication(str
        /* If delay was activated, kill it! */
        if(timer_pending(&disco_delay))
                del_timer(&disco_delay);
-       /* Set delay timer to expire in 0.5s. */
+       /* Set delay timer to expire in 0.25s. */
        disco_delay.expires = jiffies + (DISCO_SMALL_DELAY * HZ/1000);
        disco_delay.function = irlmp_discovery_timeout;
        disco_delay.data = (unsigned long) self;
@@ -420,8 +420,8 @@ void irlmp_link_discovery_confirm(struct
        ASSERT(self->magic == LMP_LAP_MAGIC, return;);
        
        irlmp_add_discovery_log(irlmp->cachelog, log);
-      
-       /* If delay was activated, kill it! */
+
+       /* If discovery delay was activated, kill it! */
        if(timer_pending(&disco_delay))
                del_timer(&disco_delay);
 
diff -u -p linux/net/irda/irqueue.d4.c linux/net/irda/irqueue.c
--- linux/net/irda/irqueue.d4.c Tue Aug 29 17:28:07 2000
+++ linux/net/irda/irqueue.c    Tue Aug 29 18:37:05 2000
@@ -381,6 +381,7 @@ void* hashbin_remove( hashbin_t* hashbin
                hashv = hash( name );
        bin = GET_HASHBIN( hashv );
 
+       /* Synchronize */
        if ( hashbin->hb_type & HB_GLOBAL ) {
                spin_lock_irqsave( &hashbin->hb_mutex[ bin ], flags);
 
@@ -448,6 +449,75 @@ void* hashbin_remove( hashbin_t* hashbin
        else
                return NULL;
        
+}
+
+/* 
+ *  Function hashbin_remove (hashbin, hashv, name)
+ *
+ *    Remove entry with the given name
+ *
+ * In some cases, the user of hashbin can't guarantee the unicity
+ * of either the hashv or name.
+ * In those cases, using the above function is guaranteed to cause troubles,
+ * so we use this one instead...
+ * And by the way, it's also faster, because we skip the search phase ;-)
+ */
+void* hashbin_remove_this( hashbin_t* hashbin, irda_queue_t* entry)
+{
+       unsigned long flags = 0;
+       int     bin;
+       __u32   hashv;
+
+       IRDA_DEBUG( 4, __FUNCTION__ "()\n");
+
+       ASSERT( hashbin != NULL, return NULL;);
+       ASSERT( hashbin->magic == HB_MAGIC, return NULL;);
+       ASSERT( entry != NULL, return NULL;);
+       
+       /* Check if valid and not already removed... */
+       if((entry->q_next == NULL) || (entry->q_prev == NULL))
+               return NULL;
+
+       /*
+        * Locate hashbin
+        */
+       hashv = entry->q_hash;
+       bin = GET_HASHBIN( hashv );
+
+       /* Synchronize */
+       if ( hashbin->hb_type & HB_GLOBAL ) {
+               spin_lock_irqsave( &hashbin->hb_mutex[ bin ], flags);
+
+       } else if ( hashbin->hb_type & HB_LOCAL ) {
+               save_flags(flags);
+               cli();
+       } /* Default is no-lock  */
+
+       /*
+        * Dequeue the entry...
+        */
+       dequeue_general( (irda_queue_t**) &hashbin->hb_queue[ bin ],
+                        (irda_queue_t*) entry );
+       hashbin->hb_size--;
+       entry->q_next = NULL;
+       entry->q_prev = NULL;
+
+       /*
+        *  Check if this item is the currently selected item, and in
+        *  that case we must reset hb_current
+        */
+       if ( entry == hashbin->hb_current)
+               hashbin->hb_current = NULL;
+
+       /* Release lock */
+       if ( hashbin->hb_type & HB_GLOBAL) {
+               spin_unlock_irq( &hashbin->hb_mutex[ bin]);
+
+       } else if ( hashbin->hb_type & HB_LOCAL) {
+               restore_flags( flags);
+       }
+
+       return entry;
 }
 
 /*
diff -u -p linux/net/irda/irmod.d4.c linux/net/irda/irmod.c
--- linux/net/irda/irmod.d4.c   Tue Aug 29 17:53:41 2000
+++ linux/net/irda/irmod.c      Tue Aug 29 17:54:11 2000
@@ -170,6 +170,7 @@ EXPORT_SYMBOL(hashbin_new);
 EXPORT_SYMBOL(hashbin_insert);
 EXPORT_SYMBOL(hashbin_delete);
 EXPORT_SYMBOL(hashbin_remove);
+EXPORT_SYMBOL(hashbin_remove_this);
 EXPORT_SYMBOL(hashbin_get_next);
 EXPORT_SYMBOL(hashbin_get_first);
 

Reply via email to