diff -u -p linux/include/net/irda/irlmp.d2.h linux/include/net/irda/irlmp.h --- linux/include/net/irda/irlmp.d2.h Fri Nov 2 14:11:19 2001 +++ linux/include/net/irda/irlmp.h Fri Nov 2 18:37:29 2001 @@ -131,7 +131,6 @@ struct lap_cb { struct irlap_cb *irlap; /* Instance of IrLAP layer */ hashbin_t *lsaps; /* LSAP associated with this link */ - int refcount; __u8 caddr; /* Connection address */ __u32 saddr; /* Source device address */ diff -u -p linux/include/net/irda/irlmp_event.d2.h linux/include/net/irda/irlmp_event.h --- linux/include/net/irda/irlmp_event.d2.h Fri Nov 2 18:47:47 2001 +++ linux/include/net/irda/irlmp_event.h Fri Nov 2 15:46:29 2001 @@ -103,10 +103,6 @@ void irlmp_watchdog_timer_expired(void * void irlmp_discovery_timer_expired(void *data); void irlmp_idle_timer_expired(void *data); -void irlmp_next_station_state(IRLMP_STATE state); -void irlmp_next_lsap_state(struct lsap_cb *self, LSAP_STATE state); -void irlmp_next_lap_state(struct lap_cb *self, IRLMP_STATE state); - void irlmp_do_lap_event(struct lap_cb *self, IRLMP_EVENT event, struct sk_buff *skb); int irlmp_do_lsap_event(struct lsap_cb *self, IRLMP_EVENT event, diff -u -p linux/include/net/irda/irlap_event.d2.h linux/include/net/irda/irlap_event.h --- linux/include/net/irda/irlap_event.d2.h Fri Nov 2 18:47:12 2001 +++ linux/include/net/irda/irlap_event.h Fri Nov 2 18:11:20 2001 @@ -103,6 +103,7 @@ typedef enum { DISCOVERY_TIMER_EXPIRED, WD_TIMER_EXPIRED, BACKOFF_TIMER_EXPIRED, + MEDIA_BUSY_TIMER_EXPIRED, } IRLAP_EVENT; /* diff -u -p linux/net/irda/irlmp.d2.c linux/net/irda/irlmp.c --- linux/net/irda/irlmp.d2.c Wed Oct 31 15:44:59 2001 +++ linux/net/irda/irlmp.c Fri Nov 2 16:53:17 2001 @@ -75,7 +75,7 @@ int irlmp_proc_read(char *buf, char **st */ int __init irlmp_init(void) { - IRDA_DEBUG(0, __FUNCTION__ "()\n"); + IRDA_DEBUG(1, __FUNCTION__ "()\n"); /* Initialize the irlmp structure. */ irlmp = kmalloc( sizeof(struct irlmp_cb), GFP_KERNEL); if (irlmp == NULL) @@ -170,14 +170,14 @@ struct lsap_cb *irlmp_open_lsap(__u8 sls #endif /* CONFIG_IRDA_ULTRA */ } else self->dlsap_sel = LSAP_ANY; - self->connected = FALSE; + /* self->connected = FALSE; -> already NULL via memset() */ init_timer(&self->watchdog_timer); ASSERT(notify->instance != NULL, return NULL;); self->notify = *notify; - irlmp_next_lsap_state(self, LSAP_DISCONNECTED); + self->lsap_state = LSAP_DISCONNECTED; /* Insert into queue of unconnected LSAPs */ hashbin_insert(irlmp->unconnected_lsaps, (irda_queue_t *) self, (int) self, @@ -237,6 +237,7 @@ void irlmp_close_lsap(struct lsap_cb *se ASSERT(lap->magic == LMP_LAP_MAGIC, return;); lsap = hashbin_remove(lap->lsaps, (int) self, NULL); } + self->lap = NULL; /* Check if we found the LSAP! If not then try the unconnected lsaps */ if (!lsap) { lsap = hashbin_remove(irlmp->unconnected_lsaps, (int) self, @@ -281,7 +282,7 @@ void irlmp_register_link(struct irlap_cb lap->daddr = DEV_ADDR_ANY; lap->lsaps = hashbin_new(HB_GLOBAL); - irlmp_next_lap_state(lap, LAP_STANDBY); + lap->lap_state = LAP_STANDBY; init_timer(&lap->idle_timer); @@ -346,7 +347,7 @@ int irlmp_connect_request(struct lsap_cb "(), slsap_sel=%02x, dlsap_sel=%02x, saddr=%08x, daddr=%08x\n", self->slsap_sel, dlsap_sel, saddr, daddr); - if (self->connected) + if (test_bit(0, &self->connected)) return -EISCONN; /* Client must supply destination device address */ @@ -435,7 +436,7 @@ int irlmp_connect_request(struct lsap_cb hashbin_insert(self->lap->lsaps, (irda_queue_t *) self, (int) self, NULL); - self->connected = TRUE; + set_bit(0, &self->connected); /* TRUE */ /* * User supplied qos specifications? @@ -481,6 +482,8 @@ void irlmp_connect_indication(struct lsa self->notify.connect_indication(self->notify.instance, self, &self->qos, max_seg_size, max_header_size, skb); + else + dev_kfree_skb(skb); } /* @@ -495,7 +498,7 @@ int irlmp_connect_response(struct lsap_c ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;); ASSERT(userdata != NULL, return -1;); - self->connected = TRUE; + set_bit(0, &self->connected); /* TRUE */ IRDA_DEBUG(2, __FUNCTION__ "(), slsap_sel=%02x, dlsap_sel=%02x\n", self->slsap_sel, self->dlsap_sel); @@ -543,7 +546,8 @@ void irlmp_connect_confirm(struct lsap_c self->notify.connect_confirm(self->notify.instance, self, &self->qos, max_seg_size, max_header_size, skb); - } + } else + dev_kfree_skb(skb); } /* @@ -598,16 +602,18 @@ int irlmp_disconnect_request(struct lsap ASSERT(self != NULL, return -1;); ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;); + ASSERT(userdata != NULL, return -1;); - /* Already disconnected? */ - if (!self->connected) { - WARNING(__FUNCTION__ "(), already disconnected!\n"); + /* Already disconnected ? + * There is a race condition between irlmp_disconnect_indication() + * and us that might mess up the hashbins below. This fixes it. + * Jean II */ + if (! test_and_clear_bit(0, &self->connected)) { + IRDA_DEBUG(0, __FUNCTION__ "(), already disconnected!\n"); + dev_kfree_skb(userdata); return -1; } - ASSERT(userdata != NULL, return -1;); - ASSERT(self->connected == TRUE, return -1;); - skb_push(userdata, LMP_CONTROL_HEADER); /* @@ -634,7 +640,6 @@ int irlmp_disconnect_request(struct lsap NULL); /* Reset some values */ - self->connected = FALSE; self->dlsap_sel = LSAP_ANY; self->lap = NULL; @@ -651,16 +656,23 @@ void irlmp_disconnect_indication(struct { struct lsap_cb *lsap; - IRDA_DEBUG(1, __FUNCTION__ "(), reason=%s\n", lmp_reasons[reason]); + IRDA_DEBUG(1, __FUNCTION__ "(), reason=%s\n", lmp_reasons[reason]); ASSERT(self != NULL, return;); ASSERT(self->magic == LMP_LSAP_MAGIC, return;); - ASSERT(self->connected == TRUE, return;); IRDA_DEBUG(3, __FUNCTION__ "(), slsap_sel=%02x, dlsap_sel=%02x\n", self->slsap_sel, self->dlsap_sel); - self->connected = FALSE; - self->dlsap_sel = LSAP_ANY; + /* Already disconnected ? + * There is a race condition between irlmp_disconnect_request() + * and us that might mess up the hashbins below. This fixes it. + * Jean II */ + if (! test_and_clear_bit(0, &self->connected)) { + IRDA_DEBUG(0, __FUNCTION__ "(), already disconnected!\n"); + if (userdata) + dev_kfree_skb(userdata); + return; + } #ifdef CONFIG_IRDA_CACHE_LAST_LSAP irlmp->cache.valid = FALSE; @@ -679,6 +691,7 @@ void irlmp_disconnect_indication(struct hashbin_insert(irlmp->unconnected_lsaps, (irda_queue_t *) lsap, (int) lsap, NULL); + self->dlsap_sel = LSAP_ANY; self->lap = NULL; /* @@ -689,7 +702,8 @@ void irlmp_disconnect_indication(struct self, reason, userdata); else { IRDA_DEBUG(0, __FUNCTION__ "(), no handler\n"); - dev_kfree_skb(userdata); + if (userdata) + dev_kfree_skb(userdata); } } @@ -1401,7 +1415,7 @@ __u32 irlmp_register_client(__u16 hint_m irlmp_client_t *client; __u32 handle; - IRDA_DEBUG(0, __FUNCTION__ "()\n"); + IRDA_DEBUG(1, __FUNCTION__ "()\n"); ASSERT(irlmp != NULL, return 0;); /* Get a unique handle for this client */ @@ -1673,14 +1687,15 @@ int irlmp_proc_read(char *buf, char **st len += sprintf(buf+len, "saddr: %#08x, daddr: %#08x, ", lap->saddr, lap->daddr); - len += sprintf(buf+len, "refcount: %d", lap->refcount); + len += sprintf(buf+len, "num lsaps: %d", + HASHBIN_GET_SIZE(lap->lsaps)); len += sprintf(buf+len, "\n"); - len += sprintf(buf+len, "\nConnected LSAPs:\n"); + len += sprintf(buf+len, "\n Connected LSAPs:\n"); self = (struct lsap_cb *) hashbin_get_first(lap->lsaps); while (self != NULL) { ASSERT(self->magic == LMP_LSAP_MAGIC, return 0;); - len += sprintf(buf+len, "lsap state: %s, ", + len += sprintf(buf+len, " lsap state: %s, ", irlsap_state[ self->lsap_state]); len += sprintf(buf+len, "slsap_sel: %#02x, dlsap_sel: %#02x, ", diff -u -p linux/net/irda/irlmp_event.d2.c linux/net/irda/irlmp_event.c --- linux/net/irda/irlmp_event.d2.c Fri Nov 2 13:55:19 2001 +++ linux/net/irda/irlmp_event.c Fri Nov 2 19:06:59 2001 @@ -114,6 +114,25 @@ static int (*lsap_state[])( struct lsap_ irlmp_state_setup_pend }; +static inline void irlmp_next_lap_state(struct lap_cb *self, + IRLMP_STATE state) +{ + /* + IRDA_DEBUG(4, __FUNCTION__ "(), LMP LAP = %s\n", irlmp_state[state]); + */ + self->lap_state = state; +} + +static inline void irlmp_next_lsap_state(struct lsap_cb *self, + LSAP_STATE state) +{ + /* + ASSERT(self != NULL, return;); + IRDA_DEBUG(4, __FUNCTION__ "(), LMP LSAP = %s\n", irlsap_state[state]); + */ + self->lsap_state = state; +} + /* Do connection control events */ int irlmp_do_lsap_event(struct lsap_cb *self, IRLMP_EVENT event, struct sk_buff *skb) @@ -223,7 +242,6 @@ static void irlmp_state_standby(struct l IRDA_DEBUG(4, __FUNCTION__ "() LS_CONNECT_REQUEST\n"); irlmp_next_lap_state(self, LAP_U_CONNECT); - self->refcount++; /* FIXME: need to set users requested QoS */ irlap_connect_request(self->irlap, self->daddr, NULL, 0); @@ -278,12 +296,12 @@ static void irlmp_state_u_connect(struct * the lsaps may already have gone. This avoid getting stuck * forever in LAP_ACTIVE state - Jean II */ if (HASHBIN_GET_SIZE(self->lsaps) == 0) { + IRDA_DEBUG(0, __FUNCTION__ "() NO LSAPs !\n"); irlmp_start_idle_timer(self, LM_IDLE_TIMEOUT); } break; case LM_LAP_CONNECT_REQUEST: /* Already trying to connect */ - self->refcount++; break; case LM_LAP_CONNECT_CONFIRM: /* For all lsap_ce E Associated do LS_Connect_confirm */ @@ -298,12 +316,13 @@ static void irlmp_state_u_connect(struct * the lsaps may already have gone. This avoid getting stuck * forever in LAP_ACTIVE state - Jean II */ if (HASHBIN_GET_SIZE(self->lsaps) == 0) { + IRDA_DEBUG(0, __FUNCTION__ "() NO LSAPs !\n"); irlmp_start_idle_timer(self, LM_IDLE_TIMEOUT); } break; case LM_LAP_DISCONNECT_INDICATION: + IRDA_DEBUG(1, __FUNCTION__ "(), LM_LAP_DISCONNECT_REQUEST\n"); irlmp_next_lap_state(self, LAP_STANDBY); - self->refcount = 0; /* Send disconnect event to all LSAPs using this link */ lsap = (struct lsap_cb *) hashbin_get_first( self->lsaps); @@ -320,11 +339,13 @@ static void irlmp_state_u_connect(struct } break; case LM_LAP_DISCONNECT_REQUEST: - IRDA_DEBUG(4, __FUNCTION__ "(), LM_LAP_DISCONNECT_REQUEST\n"); + IRDA_DEBUG(1, __FUNCTION__ "(), LM_LAP_DISCONNECT_REQUEST\n"); - self->refcount--; - if (self->refcount == 0) - irlmp_next_lap_state(self, LAP_STANDBY); + /* One of the LSAP did timeout or was closed, if it was + * the last one, try to get out of here - Jean II */ + if (HASHBIN_GET_SIZE(self->lsaps) <= 1) { + irlap_disconnect_request(self->irlap); + } break; default: IRDA_DEBUG(0, __FUNCTION__ "(), Unknown event %s\n", @@ -352,7 +373,6 @@ static void irlmp_state_active(struct la switch (event) { case LM_LAP_CONNECT_REQUEST: IRDA_DEBUG(4, __FUNCTION__ "(), LS_CONNECT_REQUEST\n"); - self->refcount++; /* * LAP connection allready active, just bounce back! Since we @@ -379,8 +399,6 @@ static void irlmp_state_active(struct la /* Keep state */ break; case LM_LAP_DISCONNECT_REQUEST: - self->refcount--; - /* * Need to find out if we should close IrLAP or not. If there * is only one LSAP connection left on this link, that LSAP @@ -419,7 +437,6 @@ static void irlmp_state_active(struct la break; case LM_LAP_DISCONNECT_INDICATION: irlmp_next_lap_state(self, LAP_STANDBY); - self->refcount = 0; /* In some case, at this point our side has already closed * all lsaps, and we are waiting for the idle_timer to @@ -517,6 +534,8 @@ static int irlmp_state_disconnected(stru * If we receive this event while our LAP is closing down, * the LM_LAP_CONNECT_REQUEST get lost and we get stuck in * CONNECT_PEND state forever. + * The other cause of getting stuck down there is if the + * higher layer never reply to the CONNECT_INDICATION. * Anyway, it make sense to make sure that we always have * a backup plan. 1 second is plenty (should be immediate). * Jean II */ @@ -577,9 +596,8 @@ static int irlmp_state_connect(struct ls * Jean II */ IRDA_DEBUG(0, __FUNCTION__ "() WATCHDOG_TIMEOUT!\n"); - /* Here, we should probably disconnect proper */ + /* Disconnect, get out... - Jean II */ self->dlsap_sel = LSAP_ANY; - self->conn_skb = NULL; irlmp_next_lsap_state(self, LSAP_DISCONNECTED); break; default: @@ -612,15 +630,6 @@ static int irlmp_state_connect_pend(stru case LM_CONNECT_REQUEST: /* Keep state */ break; - case LM_CONNECT_INDICATION: - /* Will happen in some rare cases when the socket get stuck, - * the other side retries the connect request. - * We just unstuck the socket - Jean II */ - IRDA_DEBUG(0, __FUNCTION__ "(), LM_CONNECT_INDICATION, " - "LSAP stuck in CONNECT_PEND state...\n"); - /* Keep state */ - irlmp_do_lap_event(self->lap, LM_LAP_CONNECT_REQUEST, NULL); - break; case LM_CONNECT_RESPONSE: IRDA_DEBUG(0, __FUNCTION__ "(), LM_CONNECT_RESPONSE, " "no indication issued yet\n"); @@ -648,6 +657,8 @@ static int irlmp_state_connect_pend(stru /* Go back to disconnected mode, keep the socket waiting */ self->dlsap_sel = LSAP_ANY; + if(self->conn_skb) + dev_kfree_skb(self->conn_skb); self->conn_skb = NULL; irlmp_next_lsap_state(self, LSAP_DISCONNECTED); break; @@ -856,7 +867,7 @@ static int irlmp_state_setup_pend(struct irlmp_next_lsap_state(self, LSAP_SETUP); break; case LM_WATCHDOG_TIMEOUT: - IRDA_DEBUG(0, __FUNCTION__ "() WATCHDOG_TIMEOUT!\n"); + IRDA_DEBUG(0, __FUNCTION__ "() : WATCHDOG_TIMEOUT !\n"); ASSERT(self->lap != NULL, return -1;); irlmp_do_lap_event(self->lap, LM_LAP_DISCONNECT_REQUEST, NULL); @@ -881,18 +892,4 @@ static int irlmp_state_setup_pend(struct break; } return ret; -} - -void irlmp_next_lap_state(struct lap_cb *self, IRLMP_STATE state) -{ - IRDA_DEBUG(4, __FUNCTION__ "(), LMP LAP = %s\n", irlmp_state[state]); - self->lap_state = state; -} - -void irlmp_next_lsap_state(struct lsap_cb *self, LSAP_STATE state) -{ - ASSERT(self != NULL, return;); - - IRDA_DEBUG(4, __FUNCTION__ "(), LMP LSAP = %s\n", irlsap_state[state]); - self->lsap_state = state; } diff -u -p linux/net/irda/timer.d2.c linux/net/irda/timer.c --- linux/net/irda/timer.d2.c Fri Nov 2 18:04:22 2001 +++ linux/net/irda/timer.c Fri Nov 2 19:03:02 2001 @@ -106,17 +106,13 @@ void irlap_stop_mbusy_timer(struct irlap if(timer_pending(&self->media_busy_timer)) del_timer(&self->media_busy_timer); -#ifdef CONFIG_IRDA_ULTRA - /* Send any pending Ultra frames if any */ - if (!skb_queue_empty(&self->txq_ultra)) - /* Note : we don't send the frame, just post an event. - * Frames will be sent only if we are in NDM mode (see - * irlap_event.c). - * Also, moved this code from irlap_media_busy_expired() - * to here to catch properly all cases... - * Jean II */ - irlap_do_event(self, SEND_UI_FRAME, NULL, NULL); -#endif /* CONFIG_IRDA_ULTRA */ + /* If we are in NDM, there is a bunch of events in LAP that + * that be pending due to the media_busy condition, such as + * CONNECT_REQUEST and SEND_UI_FRAME. If we don't generate + * an event, they will wait forever... + * Jean II */ + if (self->state == LAP_NDM) + irlap_do_event(self, MEDIA_BUSY_TIMER_EXPIRED, NULL, NULL); } void irlmp_start_watchdog_timer(struct lsap_cb *self, int timeout) @@ -237,5 +233,6 @@ void irlap_media_busy_expired(void* data ASSERT(self != NULL, return;); irda_device_set_media_busy(self->netdev, FALSE); - /* Note : will deal with Ultra frames */ + /* Note : the LAP event will be send in irlap_stop_mbusy_timer(), + * to catch other cases and do it after clearing the mbusy flag */ } diff -u -p linux/net/irda/irlap_event.d2.c linux/net/irda/irlap_event.c --- linux/net/irda/irlap_event.d2.c Fri Nov 2 16:28:13 2001 +++ linux/net/irda/irlap_event.c Fri Nov 2 19:15:59 2001 @@ -114,6 +114,7 @@ static const char *irlap_event[] = { "DISCOVERY_TIMER_EXPIRED", "WD_TIMER_EXPIRED", "BACKOFF_TIMER_EXPIRED", + "MEDIA_BUSY_TIMER_EXPIRED", }; const char *irlap_state[] = { @@ -264,6 +265,15 @@ void irlap_do_event(struct irlap_cb *sel } break; case LAP_NDM: + /* This one *should* not pend in this state, except if a + * socket try to connect and immediately disconnected. + * clear - Jean II */ + if (self->disconnect_pending) { + IRDA_DEBUG(0, __FUNCTION__ "(), Clear pending disconnect!\n"); + self->disconnect_pending = FALSE; + self->connect_pending = FALSE; + irlap_disconnect_indication(self, LAP_DISC_INDICATION); + } /* Check if we should try to connect */ if ((self->connect_pending) && !self->media_busy) { self->connect_pending = FALSE; @@ -440,6 +450,20 @@ static int irlap_state_ndm(struct irlap_ irlap_discovery_indication(self, info->discovery); } break; + case MEDIA_BUSY_TIMER_EXPIRED: + /* A bunch of events may be postponed because the media is busy + * This event indicate the the media is free, therefore + * we can process those events... - Jean II */ +#ifdef CONFIG_IRDA_ULTRA + /* Send any pending Ultra frames if any */ + if (!skb_queue_empty(&self->txq_ultra)) + /* We don't send the frame, just post an event. + * Also, previously this code was in timer.c... + * Jean II */ + ret = (*state[self->state])(self, SEND_UI_FRAME, + NULL, NULL); +#endif /* CONFIG_IRDA_ULTRA */ + break; #ifdef CONFIG_IRDA_ULTRA case SEND_UI_FRAME: /* Only allowed to repeat an operation twice */ @@ -735,8 +759,10 @@ static int irlap_state_conn(struct irlap break; case DISCONNECT_REQUEST: + IRDA_DEBUG(0, __FUNCTION__ "(), Disconnect request!\n"); irlap_send_dm_frame(self); - irlap_next_state( self, LAP_CONN); + irlap_next_state( self, LAP_NDM); + irlap_disconnect_indication(self, LAP_DISC_INDICATION); break; default: IRDA_DEBUG(1, __FUNCTION__ "(), Unknown event %d, %s\n", event, @@ -1417,13 +1443,12 @@ static int irlap_state_nrm_p(struct irla irlap_start_final_timer(self, self->final_timeout); break; case RECV_RD_RSP: - IRDA_DEBUG(0, __FUNCTION__ "(), RECV_RD_RSP\n"); + IRDA_DEBUG(1, __FUNCTION__ "(), RECV_RD_RSP\n"); - irlap_next_state(self, LAP_PCLOSE); - irlap_send_disc_frame(self); irlap_flush_all_queues(self); - irlap_start_final_timer(self, self->final_timeout); - self->retry_count = 0; + irlap_next_state(self, LAP_XMIT_P); + /* Call back the LAP state machine to do a proper disconnect */ + irlap_disconnect_request(self); break; default: IRDA_DEBUG(1, __FUNCTION__ "(), Unknown event %s\n",