
From: Jean Tourrilhes <jt@bougret.hpl.hp.com>

o [CORRECT] Restore properly the IAS object when IrCOMM disconnect.
Allow "pppd passive persist" to work properly.

Signed-off-by: Jean Tourrilhes <jt@hpl.hp.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 /dev/null                                    |    0 
 25-akpm/include/net/irda/ircomm_tty_attach.h |    1 
 25-akpm/net/irda/ircomm/ircomm_tty_attach.c  |  186 ++++++++++++++++-----------
 3 files changed, 112 insertions(+), 75 deletions(-)

diff -L include/net/irda/ircomm_tty_attach.d0.h -puN /dev/null /dev/null
diff -puN include/net/irda/ircomm_tty_attach.h~irda-ircomm-ias-object-fix include/net/irda/ircomm_tty_attach.h
--- 25/include/net/irda/ircomm_tty_attach.h~irda-ircomm-ias-object-fix	Wed Oct 20 15:50:29 2004
+++ 25-akpm/include/net/irda/ircomm_tty_attach.h	Wed Oct 20 15:50:29 2004
@@ -72,7 +72,6 @@ extern char *ircomm_tty_state[];
 
 int ircomm_tty_do_event(struct ircomm_tty_cb *self, IRCOMM_TTY_EVENT event,
 			struct sk_buff *skb, struct ircomm_tty_info *info);
-void ircomm_tty_next_state(struct ircomm_tty_cb *self, IRCOMM_TTY_STATE state);
 
 
 int  ircomm_tty_attach_cable(struct ircomm_tty_cb *self);
diff -puN net/irda/ircomm/ircomm_tty_attach.c~irda-ircomm-ias-object-fix net/irda/ircomm/ircomm_tty_attach.c
--- 25/net/irda/ircomm/ircomm_tty_attach.c~irda-ircomm-ias-object-fix	Wed Oct 20 15:50:29 2004
+++ 25-akpm/net/irda/ircomm/ircomm_tty_attach.c	Wed Oct 20 15:50:29 2004
@@ -143,12 +143,6 @@ int ircomm_tty_attach_cable(struct ircom
 
 	ircomm_tty_ias_register(self);
 
-	/* Check if somebody has already connected to us */
-	if (ircomm_is_connected(self->ircomm)) {
-		IRDA_DEBUG(0, "%s(), already connected!\n", __FUNCTION__ );
-		return 0;
-	}
-
 	ircomm_tty_do_event(self, IRCOMM_TTY_ATTACH_CABLE, NULL, NULL);
 
 	return 0;
@@ -169,9 +163,16 @@ void ircomm_tty_detach_cable(struct irco
 
 	del_timer(&self->watchdog_timer);
 
+	/* Remove discovery handler */
+	if (self->ckey) {
+		irlmp_unregister_client(self->ckey);
+		self->ckey = NULL;
+	}
 	/* Remove IrCOMM hint bits */
-	irlmp_unregister_client(self->ckey);
-	irlmp_unregister_service(self->skey);
+	if (self->skey) {
+		irlmp_unregister_service(self->skey);
+		self->skey = NULL;
+	}
 
 	if (self->iriap) { 
 		iriap_close(self->iriap);
@@ -209,18 +210,30 @@ static void ircomm_tty_ias_register(stru
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
 	
+	/* Compute hint bits based on service */
+	hints = irlmp_service_to_hint(S_COMM);
+	if (self->service_type & IRCOMM_3_WIRE_RAW)
+		hints |= irlmp_service_to_hint(S_PRINTER);
+
+	/* Advertise IrCOMM hint bit in discovery */
+	if (!self->skey)
+		self->skey = irlmp_register_service(hints);
+	/* Set up a discovery handler */
+	if (!self->ckey)
+		self->ckey = irlmp_register_client(hints,
+						   ircomm_tty_discovery_indication,
+						   NULL, (void *) self);
+
+	/* If already done, no need to do it again */
+	if (self->obj)
+		return;
+
 	if (self->service_type & IRCOMM_3_WIRE_RAW) {
-		hints = irlmp_service_to_hint(S_PRINTER);
-		hints |= irlmp_service_to_hint(S_COMM);
-		
 		/* Register IrLPT with LM-IAS */
 		self->obj = irias_new_object("IrLPT", IAS_IRLPT_ID);
 		irias_add_integer_attrib(self->obj, "IrDA:IrLMP:LsapSel", 
 					 self->slsap_sel, IAS_KERNEL_ATTR);
-		irias_insert_object(self->obj);
 	} else {
-		hints = irlmp_service_to_hint(S_COMM);
-
 		/* Register IrCOMM with LM-IAS */
 		self->obj = irias_new_object("IrDA:IrCOMM", IAS_IRCOMM_ID);
 		irias_add_integer_attrib(self->obj, "IrDA:TinyTP:LsapSel", 
@@ -234,12 +247,45 @@ static void ircomm_tty_ias_register(stru
 		/* Register parameters with LM-IAS */
 		irias_add_octseq_attrib(self->obj, "Parameters", oct_seq, 6,
 					IAS_KERNEL_ATTR);
-		irias_insert_object(self->obj);
 	}
-	self->skey = irlmp_register_service(hints);
-	self->ckey = irlmp_register_client(hints,
-					   ircomm_tty_discovery_indication,
-					   NULL, (void *) self);
+	irias_insert_object(self->obj);
+}
+
+/*
+ * Function ircomm_tty_ias_unregister (self)
+ *
+ *    Remove our IAS object and client hook while connected.
+ *
+ */
+static void ircomm_tty_ias_unregister(struct ircomm_tty_cb *self)
+{
+	/* Remove LM-IAS object now so it is not reused.
+	 * IrCOMM deals very poorly with multiple incoming connections.
+	 * It should looks a lot more like IrNET, and "dup" a server TSAP
+	 * to the application TSAP (based on various rules).
+	 * This is a cheap workaround allowing multiple clients to
+	 * connect to us. It will not always work.
+	 * Each IrCOMM socket has an IAS entry. Incoming connection will
+	 * pick the first one found. So, when we are fully connected,
+	 * we remove our IAS entries so that the next IAS entry is used.
+	 * We do that for *both* client and server, because a server
+	 * can also create client instances.
+	 * Jean II */
+	if (self->obj) {
+		irias_delete_object(self->obj);
+		self->obj = NULL;
+	}
+
+#if 0
+	/* Remove discovery handler.
+	 * While we are connected, we no longer need to receive
+	 * discovery events. This would be the case if there is
+	 * multiple IrLAP interfaces. Jean II */
+	if (self->ckey) {
+		irlmp_unregister_client(self->ckey);
+		self->ckey = NULL;
+	}
+#endif
 }
 
 /*
@@ -333,7 +379,8 @@ static void ircomm_tty_discovery_indicat
 	info.daddr = discovery->daddr;
 	info.saddr = discovery->saddr;
 
-	/* FIXME. We probably need to use hashbin_find_next(), but we first
+	/* FIXME. We have a locking problem on the hashbin here.
+	 * We probably need to use hashbin_find_next(), but we first
 	 * need to ensure that "line" is unique. - Jean II */
 	self = (struct ircomm_tty_cb *) hashbin_get_first(ircomm_tty);
 	while (self != NULL) {
@@ -519,23 +566,6 @@ void ircomm_tty_link_established(struct 
 	
 	del_timer(&self->watchdog_timer);
 
-	/* Remove LM-IAS object now so it is not reused.
-	 * IrCOMM deals very poorly with multiple incoming connections.
-	 * It should looks a lot more like IrNET, and "dup" a server TSAP
-	 * to the application TSAP (based on various rules).
-	 * This is a cheap workaround allowing multiple clients to
-	 * connect to us. It will not always work.
-	 * Each IrCOMM socket has an IAS entry. Incoming connection will
-	 * pick the first one found. So, when we are fully connected,
-	 * we remove our IAS entries so that the next IAS entry is used.
-	 * We do that for *both* client and server, because a server
-	 * can also create client instances.
-	 * Jean II */
-	if (self->obj) {
-		irias_delete_object(self->obj);
-		self->obj = NULL;
-	}
-
 	/* 
 	 * IrCOMM link is now up, and if we are not using hardware
 	 * flow-control, then declare the hardware as running. Otherwise we
@@ -558,7 +588,7 @@ void ircomm_tty_link_established(struct 
 }
 
 /*
- * Function irlan_start_watchdog_timer (self, timeout)
+ * Function ircomm_tty_start_watchdog_timer (self, timeout)
  *
  *    Start the watchdog timer. This timer is used to make sure that any 
  *    connection attempt is successful, and if not, we will retry after 
@@ -591,6 +621,43 @@ void ircomm_tty_watchdog_timer_expired(v
 	ircomm_tty_do_event(self, IRCOMM_TTY_WD_TIMER_EXPIRED, NULL, NULL);
 }
 
+
+/*
+ * Function ircomm_tty_do_event (self, event, skb)
+ *
+ *    Process event
+ *
+ */
+int ircomm_tty_do_event(struct ircomm_tty_cb *self, IRCOMM_TTY_EVENT event,
+			struct sk_buff *skb, struct ircomm_tty_info *info)
+{
+	ASSERT(self != NULL, return -1;);
+	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
+
+	IRDA_DEBUG(2, "%s: state=%s, event=%s\n", __FUNCTION__ ,
+		   ircomm_tty_state[self->state], ircomm_tty_event[event]);
+
+	return (*state[self->state])(self, event, skb, info);
+}
+
+/*
+ * Function ircomm_tty_next_state (self, state)
+ *
+ *    Switch state
+ *
+ */
+static inline void ircomm_tty_next_state(struct ircomm_tty_cb *self, IRCOMM_TTY_STATE state)
+{
+	/*
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
+
+	IRDA_DEBUG(2, "%s: next state=%s, service type=%d\n", __FUNCTION__ ,
+		   ircomm_tty_state[self->state], self->service_type);
+	*/
+	self->state = state;
+}
+
 /*
  * Function ircomm_tty_state_idle (self, event, skb, info)
  *
@@ -700,6 +767,7 @@ static int ircomm_tty_state_search(struc
 		break;
 	case IRCOMM_TTY_CONNECT_INDICATION:
 		del_timer(&self->watchdog_timer);
+		ircomm_tty_ias_unregister(self);
 
 		/* Accept connection */
 		ircomm_connect_response(self->ircomm, NULL);
@@ -765,6 +833,7 @@ static int ircomm_tty_state_query_parame
 		break;
 	case IRCOMM_TTY_CONNECT_INDICATION:
 		del_timer(&self->watchdog_timer);
+		ircomm_tty_ias_unregister(self);
 
 		/* Accept connection */
 		ircomm_connect_response(self->ircomm, NULL);
@@ -813,6 +882,7 @@ static int ircomm_tty_state_query_lsap_s
 		break;
 	case IRCOMM_TTY_CONNECT_INDICATION:
 		del_timer(&self->watchdog_timer);
+		ircomm_tty_ias_unregister(self);
 
 		/* Accept connection */
 		ircomm_connect_response(self->ircomm, NULL);
@@ -848,7 +918,7 @@ static int ircomm_tty_state_setup(struct
 	switch (event) {
 	case IRCOMM_TTY_CONNECT_CONFIRM:
 		del_timer(&self->watchdog_timer);
-		ircomm_tty_next_state(self, IRCOMM_TTY_READY);
+		ircomm_tty_ias_unregister(self);
 		
 		/* 
 		 * Send initial parameters. This will also send out queued
@@ -856,9 +926,11 @@ static int ircomm_tty_state_setup(struct
 		 */
 		ircomm_tty_send_initial_parameters(self);
 		ircomm_tty_link_established(self);
+		ircomm_tty_next_state(self, IRCOMM_TTY_READY);
 		break;
 	case IRCOMM_TTY_CONNECT_INDICATION:
 		del_timer(&self->watchdog_timer);
+		ircomm_tty_ias_unregister(self);
 		
 		/* Accept connection */
 		ircomm_connect_response(self->ircomm, NULL);
@@ -903,6 +975,7 @@ static int ircomm_tty_state_ready(struct
 		ircomm_tty_next_state(self, IRCOMM_TTY_IDLE);
 		break;
 	case IRCOMM_TTY_DISCONNECT_INDICATION:
+		ircomm_tty_ias_register(self);
 		ircomm_tty_next_state(self, IRCOMM_TTY_SEARCH);
 		ircomm_tty_start_watchdog_timer(self, 3*HZ);
 
@@ -924,38 +997,3 @@ static int ircomm_tty_state_ready(struct
 	return ret;
 }
 
-/*
- * Function ircomm_tty_do_event (self, event, skb)
- *
- *    Process event
- *
- */
-int ircomm_tty_do_event(struct ircomm_tty_cb *self, IRCOMM_TTY_EVENT event,
-			struct sk_buff *skb, struct ircomm_tty_info *info) 
-{
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
-
-	IRDA_DEBUG(2, "%s: state=%s, event=%s\n", __FUNCTION__ ,
-		   ircomm_tty_state[self->state], ircomm_tty_event[event]);
-	
-	return (*state[self->state])(self, event, skb, info);
-}
-
-/*
- * Function ircomm_tty_next_state (self, state)
- *
- *    Switch state
- *
- */
-void ircomm_tty_next_state(struct ircomm_tty_cb *self, IRCOMM_TTY_STATE state)
-{
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
-
-	self->state = state;
-	
-	IRDA_DEBUG(2, "%s: next state=%s, service type=%d\n", __FUNCTION__ , 
-		   ircomm_tty_state[self->state], self->service_type);
-}
-
diff -L net/irda/ircomm/ircomm_tty_attach.d0.c -puN /dev/null /dev/null
_
