Commit f289ef5a authored by Jean Tourrilhes's avatar Jean Tourrilhes Committed by Linus Torvalds

IrDA discovery fixes:

o [FEATURE] Propagate mode of discovery to higher protocols
o [CORRECT] Disable passive discovery in ircomm and irlan
  Prevent client and server to simultaneously connect to each other
o [CORRECT] Force expiry of discovery log on LAP disconnect
parent 0a082824
...@@ -39,6 +39,14 @@ ...@@ -39,6 +39,14 @@
#define DISCOVERY_EXPIRE_TIMEOUT 6*HZ #define DISCOVERY_EXPIRE_TIMEOUT 6*HZ
#define DISCOVERY_DEFAULT_SLOTS 0 #define DISCOVERY_DEFAULT_SLOTS 0
/* Types of discovery */
typedef enum {
DISCOVERY_LOG, /* What's in our discovery log */
DISCOVERY_ACTIVE, /* Doing our own discovery on the medium */
DISCOVERY_PASSIVE, /* Peer doing discovery on the medium */
EXPIRY_TIMEOUT, /* Entry expired due to timeout */
} DISCOVERY_MODE;
#define NICKNAME_MAX_LEN 21 #define NICKNAME_MAX_LEN 21
/* /*
......
...@@ -34,7 +34,7 @@ ...@@ -34,7 +34,7 @@
#include <net/irda/irlan_event.h> #include <net/irda/irlan_event.h>
void irlan_client_start_kick_timer(struct irlan_cb *self, int timeout); void irlan_client_start_kick_timer(struct irlan_cb *self, int timeout);
void irlan_client_discovery_indication(discovery_t *, void *); void irlan_client_discovery_indication(discovery_t *, DISCOVERY_MODE, void *);
void irlan_client_wakeup(struct irlan_cb *self, __u32 saddr, __u32 daddr); void irlan_client_wakeup(struct irlan_cb *self, __u32 saddr, __u32 daddr);
void irlan_client_open_ctrl_tsap( struct irlan_cb *self); void irlan_client_open_ctrl_tsap( struct irlan_cb *self);
......
...@@ -72,7 +72,7 @@ typedef enum { ...@@ -72,7 +72,7 @@ typedef enum {
S_END, S_END,
} SERVICE; } SERVICE;
typedef void (*DISCOVERY_CALLBACK1) (discovery_t *, void *); typedef void (*DISCOVERY_CALLBACK1) (discovery_t *, DISCOVERY_MODE, void *);
typedef void (*DISCOVERY_CALLBACK2) (hashbin_t *, void *); typedef void (*DISCOVERY_CALLBACK2) (hashbin_t *, void *);
typedef struct { typedef struct {
...@@ -214,7 +214,7 @@ void irlmp_disconnect_indication(struct lsap_cb *self, LM_REASON reason, ...@@ -214,7 +214,7 @@ void irlmp_disconnect_indication(struct lsap_cb *self, LM_REASON reason,
struct sk_buff *userdata); struct sk_buff *userdata);
int irlmp_disconnect_request(struct lsap_cb *, struct sk_buff *userdata); int irlmp_disconnect_request(struct lsap_cb *, struct sk_buff *userdata);
void irlmp_discovery_confirm(hashbin_t *discovery_log); void irlmp_discovery_confirm(hashbin_t *discovery_log, DISCOVERY_MODE);
void irlmp_discovery_request(int nslots); void irlmp_discovery_request(int nslots);
struct irda_device_info *irlmp_get_discoveries(int *pn, __u16 mask, int nslots); struct irda_device_info *irlmp_get_discoveries(int *pn, __u16 mask, int nslots);
void irlmp_do_expiry(void); void irlmp_do_expiry(void);
......
...@@ -415,6 +415,7 @@ static void irda_getvalue_confirm(int result, __u16 obj_id, ...@@ -415,6 +415,7 @@ static void irda_getvalue_confirm(int result, __u16 obj_id,
* hint bits), and then wake up any process waiting for answer... * hint bits), and then wake up any process waiting for answer...
*/ */
static void irda_selective_discovery_indication(discovery_t *discovery, static void irda_selective_discovery_indication(discovery_t *discovery,
DISCOVERY_MODE mode,
void *priv) void *priv)
{ {
struct irda_sock *self; struct irda_sock *self;
......
...@@ -47,6 +47,7 @@ ...@@ -47,6 +47,7 @@
static void ircomm_tty_ias_register(struct ircomm_tty_cb *self); static void ircomm_tty_ias_register(struct ircomm_tty_cb *self);
static void ircomm_tty_discovery_indication(discovery_t *discovery, static void ircomm_tty_discovery_indication(discovery_t *discovery,
DISCOVERY_MODE mode,
void *priv); void *priv);
static void ircomm_tty_getvalue_confirm(int result, __u16 obj_id, static void ircomm_tty_getvalue_confirm(int result, __u16 obj_id,
struct ias_value *value, void *priv); struct ias_value *value, void *priv);
...@@ -305,6 +306,7 @@ int ircomm_tty_send_initial_parameters(struct ircomm_tty_cb *self) ...@@ -305,6 +306,7 @@ int ircomm_tty_send_initial_parameters(struct ircomm_tty_cb *self)
* *
*/ */
static void ircomm_tty_discovery_indication(discovery_t *discovery, static void ircomm_tty_discovery_indication(discovery_t *discovery,
DISCOVERY_MODE mode,
void *priv) void *priv)
{ {
struct ircomm_tty_cb *self; struct ircomm_tty_cb *self;
...@@ -312,6 +314,20 @@ static void ircomm_tty_discovery_indication(discovery_t *discovery, ...@@ -312,6 +314,20 @@ static void ircomm_tty_discovery_indication(discovery_t *discovery,
IRDA_DEBUG(2, __FUNCTION__"()\n"); IRDA_DEBUG(2, __FUNCTION__"()\n");
/* Important note :
* We need to drop all passive discoveries.
* The LSAP management of IrComm is deficient and doesn't deal
* with the case of two instance connecting to each other
* simultaneously (it will deadlock in LMP).
* The proper fix would be to use the same technique as in IrNET,
* to have one server socket and separate instances for the
* connecting/connected socket.
* The workaround is to drop passive discovery, which drastically
* reduce the probability of this happening.
* Jean II */
if(mode == DISCOVERY_PASSIVE)
return;
info.daddr = discovery->daddr; info.daddr = discovery->daddr;
info.saddr = discovery->saddr; info.saddr = discovery->saddr;
......
...@@ -145,7 +145,9 @@ void irlan_client_wakeup(struct irlan_cb *self, __u32 saddr, __u32 daddr) ...@@ -145,7 +145,9 @@ void irlan_client_wakeup(struct irlan_cb *self, __u32 saddr, __u32 daddr)
* Remote device with IrLAN server support discovered * Remote device with IrLAN server support discovered
* *
*/ */
void irlan_client_discovery_indication(discovery_t *discovery, void *priv) void irlan_client_discovery_indication(discovery_t *discovery,
DISCOVERY_MODE mode,
void *priv)
{ {
struct irlan_cb *self; struct irlan_cb *self;
__u32 saddr, daddr; __u32 saddr, daddr;
...@@ -155,6 +157,15 @@ void irlan_client_discovery_indication(discovery_t *discovery, void *priv) ...@@ -155,6 +157,15 @@ void irlan_client_discovery_indication(discovery_t *discovery, void *priv)
ASSERT(irlan != NULL, return;); ASSERT(irlan != NULL, return;);
ASSERT(discovery != NULL, return;); ASSERT(discovery != NULL, return;);
/*
* I didn't check it, but I bet that IrLAN suffer from the same
* deficiency as IrComm and doesn't handle two instances
* simultaneously connecting to each other.
* Same workaround, drop passive discoveries.
* Jean II */
if(mode == DISCOVERY_PASSIVE)
return;
saddr = discovery->saddr; saddr = discovery->saddr;
daddr = discovery->daddr; daddr = discovery->daddr;
......
...@@ -732,7 +732,9 @@ void irlmp_do_expiry() ...@@ -732,7 +732,9 @@ void irlmp_do_expiry()
* On links which are connected, we can't do discovery * On links which are connected, we can't do discovery
* anymore and can't refresh the log, so we freeze the * anymore and can't refresh the log, so we freeze the
* discovery log to keep info about the device we are * discovery log to keep info about the device we are
* connected to. - Jean II * connected to.
* This info is mandatory if we want irlmp_connect_request()
* to work properly. - Jean II
*/ */
lap = (struct lap_cb *) hashbin_get_first(irlmp->links); lap = (struct lap_cb *) hashbin_get_first(irlmp->links);
while (lap != NULL) { while (lap != NULL) {
...@@ -804,7 +806,7 @@ void irlmp_do_discovery(int nslots) ...@@ -804,7 +806,7 @@ void irlmp_do_discovery(int nslots)
void irlmp_discovery_request(int nslots) void irlmp_discovery_request(int nslots)
{ {
/* Return current cached discovery log */ /* Return current cached discovery log */
irlmp_discovery_confirm(irlmp->cachelog); irlmp_discovery_confirm(irlmp->cachelog, DISCOVERY_LOG);
/* /*
* Start a single discovery operation if discovery is not already * Start a single discovery operation if discovery is not already
...@@ -907,7 +909,8 @@ void irlmp_check_services(discovery_t *discovery) ...@@ -907,7 +909,8 @@ void irlmp_check_services(discovery_t *discovery)
* partial/selective discovery based on the hints that it passed to IrLMP. * partial/selective discovery based on the hints that it passed to IrLMP.
*/ */
static inline void static inline void
irlmp_notify_client(irlmp_client_t *client, hashbin_t *log) irlmp_notify_client(irlmp_client_t *client,
hashbin_t *log, DISCOVERY_MODE mode)
{ {
discovery_t *discovery; discovery_t *discovery;
...@@ -930,7 +933,7 @@ irlmp_notify_client(irlmp_client_t *client, hashbin_t *log) ...@@ -930,7 +933,7 @@ irlmp_notify_client(irlmp_client_t *client, hashbin_t *log)
* bits ;-) * bits ;-)
*/ */
if (client->hint_mask & discovery->hints.word & 0x7f7f) if (client->hint_mask & discovery->hints.word & 0x7f7f)
client->disco_callback(discovery, client->priv); client->disco_callback(discovery, mode, client->priv);
discovery = (discovery_t *) hashbin_get_next(log); discovery = (discovery_t *) hashbin_get_next(log);
} }
...@@ -943,7 +946,7 @@ irlmp_notify_client(irlmp_client_t *client, hashbin_t *log) ...@@ -943,7 +946,7 @@ irlmp_notify_client(irlmp_client_t *client, hashbin_t *log)
* device it is, and give indication to the client(s) * device it is, and give indication to the client(s)
* *
*/ */
void irlmp_discovery_confirm(hashbin_t *log) void irlmp_discovery_confirm(hashbin_t *log, DISCOVERY_MODE mode)
{ {
irlmp_client_t *client; irlmp_client_t *client;
...@@ -957,7 +960,7 @@ void irlmp_discovery_confirm(hashbin_t *log) ...@@ -957,7 +960,7 @@ void irlmp_discovery_confirm(hashbin_t *log)
client = (irlmp_client_t *) hashbin_get_first(irlmp->clients); client = (irlmp_client_t *) hashbin_get_first(irlmp->clients);
while (client != NULL) { while (client != NULL) {
/* Check if we should notify client */ /* Check if we should notify client */
irlmp_notify_client(client, log); irlmp_notify_client(client, log, mode);
client = (irlmp_client_t *) hashbin_get_next(irlmp->clients); client = (irlmp_client_t *) hashbin_get_next(irlmp->clients);
} }
...@@ -987,7 +990,8 @@ void irlmp_discovery_expiry(discovery_t *expiry) ...@@ -987,7 +990,8 @@ void irlmp_discovery_expiry(discovery_t *expiry)
/* Check if we should notify client */ /* Check if we should notify client */
if ((client->expir_callback) && if ((client->expir_callback) &&
(client->hint_mask & expiry->hints.word & 0x7f7f)) (client->hint_mask & expiry->hints.word & 0x7f7f))
client->expir_callback(expiry, client->priv); client->expir_callback(expiry, EXPIRY_TIMEOUT,
client->priv);
/* Next client */ /* Next client */
client = (irlmp_client_t *) hashbin_get_next(irlmp->clients); client = (irlmp_client_t *) hashbin_get_next(irlmp->clients);
......
...@@ -459,6 +459,15 @@ static void irlmp_state_active(struct lap_cb *self, IRLMP_EVENT event, ...@@ -459,6 +459,15 @@ static void irlmp_state_active(struct lap_cb *self, IRLMP_EVENT event,
LM_LAP_DISCONNECT_INDICATION, LM_LAP_DISCONNECT_INDICATION,
NULL); NULL);
} }
/* Force an expiry of the discovery log.
* Now that the LAP is free, the system may attempt to
* connect to another device. Unfortunately, our entries
* are stale. There is a small window (<3s) before the
* normal discovery will run and where irlmp_connect_request()
* can get the wrong info, so make sure things get
* cleaned *NOW* ;-) - Jean II */
irlmp_do_expiry();
break; break;
default: default:
IRDA_DEBUG(0, __FUNCTION__ "(), Unknown event %s\n", IRDA_DEBUG(0, __FUNCTION__ "(), Unknown event %s\n",
......
...@@ -378,7 +378,7 @@ void irlmp_link_discovery_indication(struct lap_cb *self, ...@@ -378,7 +378,7 @@ void irlmp_link_discovery_indication(struct lap_cb *self,
/* Just handle it the same way as a discovery confirm, /* Just handle it the same way as a discovery confirm,
* bypass the LM_LAP state machine (see below) */ * bypass the LM_LAP state machine (see below) */
irlmp_discovery_confirm(irlmp->cachelog); irlmp_discovery_confirm(irlmp->cachelog, DISCOVERY_PASSIVE);
} }
/* /*
...@@ -404,7 +404,7 @@ void irlmp_link_discovery_confirm(struct lap_cb *self, hashbin_t *log) ...@@ -404,7 +404,7 @@ void irlmp_link_discovery_confirm(struct lap_cb *self, hashbin_t *log)
* 2) It doesn't affect the LM_LAP state * 2) It doesn't affect the LM_LAP state
* 3) Faster, slimer, simpler, ... * 3) Faster, slimer, simpler, ...
* Jean II */ * Jean II */
irlmp_discovery_confirm(irlmp->cachelog); irlmp_discovery_confirm(irlmp->cachelog, DISCOVERY_ACTIVE);
} }
#ifdef CONFIG_IRDA_CACHE_LAST_LSAP #ifdef CONFIG_IRDA_CACHE_LAST_LSAP
......
...@@ -1599,7 +1599,8 @@ irnet_discovervalue_confirm(int result, ...@@ -1599,7 +1599,8 @@ irnet_discovervalue_confirm(int result,
* is to messy, so we leave that to user space... * is to messy, so we leave that to user space...
*/ */
static void static void
irnet_discovery_indication(discovery_t *discovery, irnet_discovery_indication(discovery_t * discovery,
DISCOVERY_MODE mode,
void * priv) void * priv)
{ {
irnet_socket * self = &irnet_server.s; irnet_socket * self = &irnet_server.s;
...@@ -1638,6 +1639,7 @@ irnet_discovery_indication(discovery_t *discovery, ...@@ -1638,6 +1639,7 @@ irnet_discovery_indication(discovery_t *discovery,
*/ */
static void static void
irnet_expiry_indication(discovery_t * expiry, irnet_expiry_indication(discovery_t * expiry,
DISCOVERY_MODE mode,
void * priv) void * priv)
{ {
irnet_socket * self = &irnet_server.s; irnet_socket * self = &irnet_server.s;
......
...@@ -151,9 +151,11 @@ static void ...@@ -151,9 +151,11 @@ static void
#ifdef DISCOVERY_EVENTS #ifdef DISCOVERY_EVENTS
static void static void
irnet_discovery_indication(discovery_t *, irnet_discovery_indication(discovery_t *,
DISCOVERY_MODE,
void *); void *);
static void static void
irnet_expiry_indication(discovery_t *, irnet_expiry_indication(discovery_t *,
DISCOVERY_MODE,
void *); void *);
#endif #endif
/* -------------------------- PROC ENTRY -------------------------- */ /* -------------------------- PROC ENTRY -------------------------- */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment