Commit 503861cd authored by Jean Tourrilhes's avatar Jean Tourrilhes Committed by David S. Miller

[IRDA]: IrCOMM IAS object fix

o [CORRECT] Restore properly the IAS object when IrCOMM disconnect.
Allow 'pppd passive persist' to work properly.
Signed-off-by: default avatarJean Tourrilhes <jt@hpl.hp.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 2863ffcb
......@@ -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);
......
......@@ -143,12 +143,6 @@ int ircomm_tty_attach_cable(struct ircomm_tty_cb *self)
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 ircomm_tty_cb *self)
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(struct ircomm_tty_cb *self)
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(struct ircomm_tty_cb *self)
/* 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_indication(discinfo_t *discovery,
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 ircomm_tty_cb *self)
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 ircomm_tty_cb *self)
}
/*
* 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(void *data)
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(struct ircomm_tty_cb *self,
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_parameters(struct ircomm_tty_cb *self,
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_sel(struct ircomm_tty_cb *self,
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 ircomm_tty_cb *self,
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_cb *self,
*/
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_cb *self,
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 ircomm_tty_cb *self,
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);
}
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