patch-2.4.0-test11 linux/net/irda/discovery.c
Next file: linux/net/irda/ircomm/ircomm_core.c
Previous file: linux/net/irda/compressors/irda_deflate.c
Back to the patch index
Back to the overall index
- Lines: 257
- Date:
Sat Nov 11 18:11:23 2000
- Orig file:
v2.4.0-test10/linux/net/irda/discovery.c
- Orig date:
Tue Dec 21 10:17:58 1999
diff -u --recursive --new-file v2.4.0-test10/linux/net/irda/discovery.c linux/net/irda/discovery.c
@@ -43,13 +43,25 @@
*
* Add a new discovery to the cachelog, and remove any old discoveries
* from the same device
+ *
+ * Note : we try to preserve the time this device was *first* discovered
+ * (as opposed to the time of last discovery used for cleanup). This is
+ * used by clients waiting for discovery events to tell if the device
+ * discovered is "new" or just the same old one. They can't rely there
+ * on a binary flag (new/old), because not all discovery events are
+ * propagated to them, and they might not always listen, so they would
+ * miss some new devices popping up...
+ * Jean II
*/
void irlmp_add_discovery(hashbin_t *cachelog, discovery_t *new)
{
discovery_t *discovery, *node;
unsigned long flags;
- spin_lock_irqsave(&irlmp->lock, flags);
+ /* Set time of first discovery if node is new (see below) */
+ new->first_timestamp = new->timestamp;
+
+ spin_lock_irqsave(&irlmp->log_lock, flags);
/*
* Remove all discoveries of devices that has previously been
@@ -59,27 +71,31 @@
*/
discovery = (discovery_t *) hashbin_get_first(cachelog);
while (discovery != NULL ) {
- node = discovery;
+ node = discovery;
- /* 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))
- {
- /* This discovery is a previous discovery
- * from the same device, so just remove it
- */
- hashbin_remove(cachelog, node->daddr, NULL);
- kfree(node);
- }
- }
+ /* Be sure to stay one item ahead */
+ discovery = (discovery_t *) hashbin_get_next(cachelog);
+ 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_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 */
+ new->first_timestamp = node->first_timestamp;
+ kfree(node);
+ }
+ }
/* Insert the new and updated version */
- hashbin_insert(cachelog, (queue_t *) new, new->daddr, NULL);
+ hashbin_insert(cachelog, (irda_queue_t *) new, new->daddr, NULL);
- spin_unlock_irqrestore(&irlmp->lock, flags);
+ spin_unlock_irqrestore(&irlmp->log_lock, flags);
}
/*
@@ -120,13 +136,18 @@
*
* 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)
{
discovery_t *discovery, *curr;
+ unsigned long flags;
IRDA_DEBUG(4, __FUNCTION__ "()\n");
+ spin_lock_irqsave(&irlmp->log_lock, flags);
+
discovery = (discovery_t *) hashbin_get_first(log);
while (discovery != NULL) {
curr = discovery;
@@ -135,14 +156,20 @@
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);
}
}
+
+ spin_unlock_irqrestore(&irlmp->log_lock, flags);
}
/*
@@ -169,6 +196,75 @@
}
/*
+ * Function irlmp_copy_discoveries (log, pn, mask)
+ *
+ * Copy all discoveries in a buffer
+ *
+ * This function implement a safe way for lmp clients to access the
+ * discovery log. The basic problem is that we don't want the log
+ * to change (add/remove) while the client is reading it. If the
+ * lmp client manipulate directly the hashbin, he is sure to get
+ * into troubles...
+ * The idea is that we copy all the current discovery log in a buffer
+ * which is specific to the client and pass this copy to him. As we
+ * do this operation with the spinlock grabbed, we are safe...
+ * Note : we don't want those clients to grab the spinlock, because
+ * we have no control on how long they will hold it...
+ * Note : we choose to copy the log in "struct irda_device_info" to
+ * save space...
+ * Note : the client must kfree himself() the log...
+ * Jean II
+ */
+struct irda_device_info *irlmp_copy_discoveries(hashbin_t *log, int *pn, __u16 mask)
+{
+ discovery_t * discovery;
+ unsigned long flags;
+ struct irda_device_info * buffer;
+ int i = 0;
+ int n;
+
+ ASSERT(pn != NULL, return NULL;);
+
+ /* Check if log is empty */
+ if(log == NULL)
+ return NULL;
+
+ /* Save spin lock - spinlock should be discovery specific */
+ spin_lock_irqsave(&irlmp->log_lock, flags);
+
+ /* Create the client specific buffer */
+ n = HASHBIN_GET_SIZE(log);
+ buffer = kmalloc(n * sizeof(struct irda_device_info), GFP_ATOMIC);
+ if (buffer == NULL) {
+ spin_unlock_irqrestore(&irlmp->log_lock, flags);
+ return NULL;
+ }
+
+ discovery = (discovery_t *) hashbin_get_first(log);
+ while ((discovery != NULL) && (i < n)) {
+ /* Mask out the ones we don't want */
+ if (discovery->hints.word & mask) {
+ /* Copy discovery information */
+ buffer[i].saddr = discovery->saddr;
+ buffer[i].daddr = discovery->daddr;
+ buffer[i].charset = discovery->charset;
+ buffer[i].hints[0] = discovery->hints.byte[0];
+ buffer[i].hints[1] = discovery->hints.byte[1];
+ strncpy(buffer[i].info, discovery->nickname,
+ NICKNAME_MAX_LEN);
+ i++;
+ }
+ discovery = (discovery_t *) hashbin_get_next(log);
+ }
+
+ spin_unlock_irqrestore(&irlmp->log_lock, flags);
+
+ /* Get the actual number of device in the buffer and return */
+ *pn = i;
+ return(buffer);
+}
+
+/*
* Function irlmp_find_device (name, saddr)
*
* Look through the discovery log at each of the links and try to find
@@ -180,7 +276,7 @@
unsigned long flags;
discovery_t *d;
- spin_lock_irqsave(&irlmp->lock, flags);
+ spin_lock_irqsave(&irlmp->log_lock, flags);
/* Look at all discoveries for that link */
d = (discovery_t *) hashbin_get_first(cachelog);
@@ -192,13 +288,13 @@
if (strcmp(name, d->nickname) == 0) {
*saddr = d->saddr;
- spin_unlock_irqrestore(&irlmp->lock, flags);
+ spin_unlock_irqrestore(&irlmp->log_lock, flags);
return d->daddr;
}
d = (discovery_t *) hashbin_get_next(cachelog);
}
- spin_unlock_irqrestore(&irlmp->lock, flags);
+ spin_unlock_irqrestore(&irlmp->log_lock, flags);
return 0;
}
@@ -209,23 +305,23 @@
* 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",
@@ -266,7 +362,7 @@
discovery = (discovery_t *) hashbin_get_next(cachelog);
}
- restore_flags(flags);
+ spin_unlock_irqrestore(&irlmp->log_lock, flags);
return len;
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)