X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=net%2Firda%2Firlmp.c;h=26b22f49076bc98edd7521c94dedf971123c5928;hb=6a77f38946aaee1cd85eeec6cf4229b204c15071;hp=320940a5c68746186ea03bc045bff9cd4899a33d;hpb=87fc8d1bb10cd459024a742c6a10961fefcef18f;p=linux-2.6.git diff --git a/net/irda/irlmp.c b/net/irda/irlmp.c index 320940a5c..26b22f490 100644 --- a/net/irda/irlmp.c +++ b/net/irda/irlmp.c @@ -44,6 +44,9 @@ #include #include +static __u8 irlmp_find_free_slsap(void); +static int irlmp_slsap_inuse(__u8 slsap_sel); + /* Master structure */ struct irlmp_cb *irlmp = NULL; @@ -99,7 +102,7 @@ int __init irlmp_init(void) spin_lock_init(&irlmp->cachelog->hb_spinlock); - irlmp->free_lsap_sel = 0x10; /* Reserved 0x00-0x0f */ + irlmp->last_lsap_sel = 0x0f; /* Reserved 0x00-0x0f */ strcpy(sysctl_devname, "Linux"); /* Do discovery every 3 seconds */ @@ -160,7 +163,7 @@ struct lsap_cb *irlmp_open_lsap(__u8 slsap_sel, notify_t *notify, __u8 pid) /* Allocate new instance of a LSAP connection */ self = kmalloc(sizeof(struct lsap_cb), GFP_ATOMIC); if (self == NULL) { - ERROR("%s: can't allocate memory", __FUNCTION__); + ERROR("%s: can't allocate memory\n", __FUNCTION__); return NULL; } memset(self, 0, sizeof(struct lsap_cb)); @@ -1278,11 +1281,6 @@ void irlmp_connless_data_indication(struct lsap_cb *self, struct sk_buff *skb) } #endif /* CONFIG_IRDA_ULTRA */ -void irlmp_status_request(void) -{ - IRDA_DEBUG(0, "%s(), Not implemented\n", __FUNCTION__); -} - /* * Propagate status indication from LAP to LSAPs (via LMP) * This don't trigger any change of state in lap_cb, lmp_cb or lsap_cb, @@ -1649,8 +1647,14 @@ EXPORT_SYMBOL(irlmp_unregister_client); * Function irlmp_slsap_inuse (slsap) * * Check if the given source LSAP selector is in use + * + * This function is clearly not very efficient. On the mitigating side, the + * stack make sure that in 99% of the cases, we are called only once + * for each socket allocation. We could probably keep a bitmap + * of the allocated LSAP, but I'm not sure the complexity is worth it. + * Jean II */ -int irlmp_slsap_inuse(__u8 slsap_sel) +static int irlmp_slsap_inuse(__u8 slsap_sel) { struct lsap_cb *self; struct lap_cb *lap; @@ -1668,7 +1672,7 @@ int irlmp_slsap_inuse(__u8 slsap_sel) return FALSE; #endif /* CONFIG_IRDA_ULTRA */ - /* Valid values are between 0 and 127 */ + /* Valid values are between 0 and 127 (0x0-0x6F) */ if (slsap_sel > LSAP_MAX) return TRUE; @@ -1680,30 +1684,68 @@ int irlmp_slsap_inuse(__u8 slsap_sel) spin_lock_irqsave(&irlmp->links->hb_spinlock, flags); lap = (struct lap_cb *) hashbin_get_first(irlmp->links); while (lap != NULL) { - ASSERT(lap->magic == LMP_LAP_MAGIC, return TRUE;); + ASSERT(lap->magic == LMP_LAP_MAGIC, goto errlap;); /* Careful for priority inversions here ! - * All other uses of attrib spinlock are independent of - * the object spinlock, so we are safe. Jean II */ + * irlmp->links is never taken while another IrDA + * spinlock is held, so we are safe. Jean II */ spin_lock(&lap->lsaps->hb_spinlock); + /* For this IrLAP, check all the LSAPs */ self = (struct lsap_cb *) hashbin_get_first(lap->lsaps); while (self != NULL) { - ASSERT(self->magic == LMP_LSAP_MAGIC, return TRUE;); + ASSERT(self->magic == LMP_LSAP_MAGIC, goto errlsap;); if ((self->slsap_sel == slsap_sel)) { IRDA_DEBUG(4, "Source LSAP selector=%02x in use\n", - self->slsap_sel); - return TRUE; + self->slsap_sel); + goto errlsap; } self = (struct lsap_cb*) hashbin_get_next(lap->lsaps); } spin_unlock(&lap->lsaps->hb_spinlock); + /* Next LAP */ lap = (struct lap_cb *) hashbin_get_next(irlmp->links); } spin_unlock_irqrestore(&irlmp->links->hb_spinlock, flags); + + /* + * Server sockets are typically waiting for connections and + * therefore reside in the unconnected list. We don't want + * to give out their LSAPs for obvious reasons... + * Jean II + */ + spin_lock_irqsave(&irlmp->unconnected_lsaps->hb_spinlock, flags); + + self = (struct lsap_cb *) hashbin_get_first(irlmp->unconnected_lsaps); + while (self != NULL) { + ASSERT(self->magic == LMP_LSAP_MAGIC, goto erruncon;); + if ((self->slsap_sel == slsap_sel)) { + IRDA_DEBUG(4, "Source LSAP selector=%02x in use (unconnected)\n", + self->slsap_sel); + goto erruncon; + } + self = (struct lsap_cb*) hashbin_get_next(irlmp->unconnected_lsaps); + } + spin_unlock_irqrestore(&irlmp->unconnected_lsaps->hb_spinlock, flags); + return FALSE; + + /* Error exit from within one of the two nested loops. + * Make sure we release the right spinlock in the righ order. + * Jean II */ +errlsap: + spin_unlock(&lap->lsaps->hb_spinlock); +errlap: + spin_unlock_irqrestore(&irlmp->links->hb_spinlock, flags); + return TRUE; + + /* Error exit from within the unconnected loop. + * Just one spinlock to release... Jean II */ +erruncon: + spin_unlock_irqrestore(&irlmp->unconnected_lsaps->hb_spinlock, flags); + return TRUE; } /* @@ -1712,7 +1754,7 @@ int irlmp_slsap_inuse(__u8 slsap_sel) * Find a free source LSAP to use. This function is called if the service * user has requested a source LSAP equal to LM_ANY */ -__u8 irlmp_find_free_slsap(void) +static __u8 irlmp_find_free_slsap(void) { __u8 lsap_sel; int wrapped = 0; @@ -1720,22 +1762,48 @@ __u8 irlmp_find_free_slsap(void) ASSERT(irlmp != NULL, return -1;); ASSERT(irlmp->magic == LMP_MAGIC, return -1;); - lsap_sel = irlmp->free_lsap_sel++; - - /* Check if the new free lsap is really free */ - while (irlmp_slsap_inuse(irlmp->free_lsap_sel)) { - irlmp->free_lsap_sel++; + /* Most users don't really care which LSAPs they are given, + * and therefore we automatically give them a free LSAP. + * This function try to find a suitable LSAP, i.e. which is + * not in use and is within the acceptable range. Jean II */ + + do { + /* Always increment to LSAP number before using it. + * In theory, we could reuse the last LSAP number, as long + * as it is no longer in use. Some IrDA stack do that. + * However, the previous socket may be half closed, i.e. + * we closed it, we think it's no longer in use, but the + * other side did not receive our close and think it's + * active and still send data on it. + * This is similar to what is done with PIDs and TCP ports. + * Also, this reduce the number of calls to irlmp_slsap_inuse() + * which is an expensive function to call. + * Jean II */ + irlmp->last_lsap_sel++; /* Check if we need to wraparound (0x70-0x7f are reserved) */ - if (irlmp->free_lsap_sel > LSAP_MAX) { - irlmp->free_lsap_sel = 10; + if (irlmp->last_lsap_sel > LSAP_MAX) { + /* 0x00-0x10 are also reserved for well know ports */ + irlmp->last_lsap_sel = 0x10; /* Make sure we terminate the loop */ - if (wrapped++) + if (wrapped++) { + ERROR("%s: no more free LSAPs !\n", + __FUNCTION__); return 0; + } } - } - IRDA_DEBUG(4, "%s(), next free lsap_sel=%02x\n", + + /* If the LSAP is in use, try the next one. + * Despite the autoincrement, we need to check if the lsap + * is really in use or not, first because LSAP may be + * directly allocated in irlmp_open_lsap(), and also because + * we may wraparound on old sockets. Jean II */ + } while (irlmp_slsap_inuse(irlmp->last_lsap_sel)); + + /* Got it ! */ + lsap_sel = irlmp->last_lsap_sel; + IRDA_DEBUG(4, "%s(), found free lsap_sel=%02x\n", __FUNCTION__, lsap_sel); return lsap_sel;