⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 irlmp.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
	if (!service) {		IRDA_DEBUG(1, "%s(), Unknown service!\n", __FUNCTION__);		return -1;	}	hashbin_remove_this(irlmp->services, (irda_queue_t *) service);	kfree(service);	/* Remove old hint bits */	irlmp->hints.word = 0;	/* Refresh current hint bits */	spin_lock_irqsave(&irlmp->services->hb_spinlock, flags);	service = (irlmp_service_t *) hashbin_get_first(irlmp->services);	while (service) {		irlmp->hints.word |= service->hints.word;		service = (irlmp_service_t *)hashbin_get_next(irlmp->services);	}	spin_unlock_irqrestore(&irlmp->services->hb_spinlock, flags);	return 0;}EXPORT_SYMBOL(irlmp_unregister_service);/* * Function irlmp_register_client (hint_mask, callback1, callback2) * *    Register a local client with IrLMP *	First callback is selective discovery (based on hints) *	Second callback is for selective discovery expiries * *    Returns: handle > 0 on success, 0 on error */void *irlmp_register_client(__u16 hint_mask, DISCOVERY_CALLBACK1 disco_clb,			    DISCOVERY_CALLBACK2 expir_clb, void *priv){	irlmp_client_t *client;	IRDA_DEBUG(1, "%s()\n", __FUNCTION__);	IRDA_ASSERT(irlmp != NULL, return NULL;);	/* Make a new registration */	client = kmalloc(sizeof(irlmp_client_t), GFP_ATOMIC);	if (!client) {		IRDA_DEBUG( 1, "%s(), Unable to kmalloc!\n", __FUNCTION__);		return NULL;	}	/* Register the details */	client->hint_mask.word = hint_mask;	client->disco_callback = disco_clb;	client->expir_callback = expir_clb;	client->priv = priv;	hashbin_insert(irlmp->clients, (irda_queue_t *) client,		       (long) client, NULL);	return (void *) client;}EXPORT_SYMBOL(irlmp_register_client);/* * Function irlmp_update_client (handle, hint_mask, callback1, callback2) * *    Updates specified client (handle) with possibly new hint_mask and *    callback * *    Returns: 0 on success, -1 on error */int irlmp_update_client(void *handle, __u16 hint_mask,			DISCOVERY_CALLBACK1 disco_clb,			DISCOVERY_CALLBACK2 expir_clb, void *priv){	irlmp_client_t *client;	if (!handle)		return -1;	client = hashbin_lock_find(irlmp->clients, (long) handle, NULL);	if (!client) {		IRDA_DEBUG(1, "%s(), Unknown client!\n", __FUNCTION__);		return -1;	}	client->hint_mask.word = hint_mask;	client->disco_callback = disco_clb;	client->expir_callback = expir_clb;	client->priv = priv;	return 0;}EXPORT_SYMBOL(irlmp_update_client);/* * Function irlmp_unregister_client (handle) * *    Returns: 0 on success, -1 on error * */int irlmp_unregister_client(void *handle){	struct irlmp_client *client;	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);	if (!handle)		return -1;	/* Caller may call with invalid handle (it's legal) - Jean II */	client = hashbin_lock_find(irlmp->clients, (long) handle, NULL);	if (!client) {		IRDA_DEBUG(1, "%s(), Unknown client!\n", __FUNCTION__);		return -1;	}	IRDA_DEBUG(4, "%s(), removing client!\n", __FUNCTION__);	hashbin_remove_this(irlmp->clients, (irda_queue_t *) client);	kfree(client);	return 0;}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 */static int irlmp_slsap_inuse(__u8 slsap_sel){	struct lsap_cb *self;	struct lap_cb *lap;	unsigned long flags;	IRDA_ASSERT(irlmp != NULL, return TRUE;);	IRDA_ASSERT(irlmp->magic == LMP_MAGIC, return TRUE;);	IRDA_ASSERT(slsap_sel != LSAP_ANY, return TRUE;);	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);#ifdef CONFIG_IRDA_ULTRA	/* Accept all bindings to the connectionless LSAP */	if (slsap_sel == LSAP_CONNLESS)		return FALSE;#endif /* CONFIG_IRDA_ULTRA */	/* Valid values are between 0 and 127 (0x0-0x6F) */	if (slsap_sel > LSAP_MAX)		return TRUE;	/*	 *  Check if slsap is already in use. To do this we have to loop over	 *  every IrLAP connection and check every LSAP associated with each	 *  the connection.	 */	spin_lock_irqsave_nested(&irlmp->links->hb_spinlock, flags,			SINGLE_DEPTH_NESTING);	lap = (struct lap_cb *) hashbin_get_first(irlmp->links);	while (lap != NULL) {		IRDA_ASSERT(lap->magic == LMP_LAP_MAGIC, goto errlap;);		/* Careful for priority inversions here !		 * 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) {			IRDA_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);				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) {		IRDA_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);IRDA_ASSERT_LABEL(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;}/* * Function irlmp_find_free_slsap () * *    Find a free source LSAP to use. This function is called if the service *    user has requested a source LSAP equal to LM_ANY */static __u8 irlmp_find_free_slsap(void){	__u8 lsap_sel;	int wrapped = 0;	IRDA_ASSERT(irlmp != NULL, return -1;);	IRDA_ASSERT(irlmp->magic == LMP_MAGIC, return -1;);	/* 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->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++) {				IRDA_ERROR("%s: no more free LSAPs !\n",					   __FUNCTION__);				return 0;			}		}		/* 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;}/* * Function irlmp_convert_lap_reason (lap_reason) * *    Converts IrLAP disconnect reason codes to IrLMP disconnect reason *    codes * */LM_REASON irlmp_convert_lap_reason( LAP_REASON lap_reason){	int reason = LM_LAP_DISCONNECT;	switch (lap_reason) {	case LAP_DISC_INDICATION: /* Received a disconnect request from peer */		IRDA_DEBUG( 1, "%s(), LAP_DISC_INDICATION\n", __FUNCTION__);		reason = LM_USER_REQUEST;		break;	case LAP_NO_RESPONSE:    /* To many retransmits without response */		IRDA_DEBUG( 1, "%s(), LAP_NO_RESPONSE\n", __FUNCTION__);		reason = LM_LAP_DISCONNECT;		break;	case LAP_RESET_INDICATION:		IRDA_DEBUG( 1, "%s(), LAP_RESET_INDICATION\n", __FUNCTION__);		reason = LM_LAP_RESET;		break;	case LAP_FOUND_NONE:	case LAP_MEDIA_BUSY:	case LAP_PRIMARY_CONFLICT:		IRDA_DEBUG(1, "%s(), LAP_FOUND_NONE, LAP_MEDIA_BUSY or LAP_PRIMARY_CONFLICT\n", __FUNCTION__);		reason = LM_CONNECT_FAILURE;		break;	default:		IRDA_DEBUG(1, "%s(), Unknow IrLAP disconnect reason %d!\n",			   __FUNCTION__, lap_reason);		reason = LM_LAP_DISCONNECT;		break;	}	return reason;}#ifdef CONFIG_PROC_FSstruct irlmp_iter_state {	hashbin_t *hashbin;};#define LSAP_START_TOKEN	((void *)1)#define LINK_START_TOKEN	((void *)2)static void *irlmp_seq_hb_idx(struct irlmp_iter_state *iter, loff_t *off){	void *element;	spin_lock_irq(&iter->hashbin->hb_spinlock);	for (element = hashbin_get_first(iter->hashbin);	     element != NULL;	     element = hashbin_get_next(iter->hashbin)) {		if (!off || *off-- == 0) {			/* NB: hashbin left locked */			return element;		}	}	spin_unlock_irq(&iter->hashbin->hb_spinlock);	iter->hashbin = NULL;	return NULL;}static void *irlmp_seq_start(struct seq_file *seq, loff_t *pos){	struct irlmp_iter_state *iter = seq->private;	void *v;	loff_t off = *pos;	iter->hashbin = NULL;	if (off-- == 0)		return LSAP_START_TOKEN;	iter->hashbin = irlmp->unconnected_lsaps;	v = irlmp_seq_hb_idx(iter, &off);	if (v)		return v;	if (off-- == 0)		return LINK_START_TOKEN;	iter->hashbin = irlmp->links;	return irlmp_seq_hb_idx(iter, &off);}static void *irlmp_seq_next(struct seq_file *seq, void *v, loff_t *pos){	struct irlmp_iter_state *iter = seq->private;	++*pos;	if (v == LSAP_START_TOKEN) {		/* start of list of lsaps */		iter->hashbin = irlmp->unconnected_lsaps;		v = irlmp_seq_hb_idx(iter, NULL);		return v ? v : LINK_START_TOKEN;	}	if (v == LINK_START_TOKEN) {		/* start of list of links */		iter->hashbin = irlmp->links;		return irlmp_seq_hb_idx(iter, NULL);	}	v = hashbin_get_next(iter->hashbin);	if (v == NULL) {			/* no more in this hash bin */		spin_unlock_irq(&iter->hashbin->hb_spinlock);		if (iter->hashbin == irlmp->unconnected_lsaps)			v =  LINK_START_TOKEN;		iter->hashbin = NULL;	}	return v;}static void irlmp_seq_stop(struct seq_file *seq, void *v){	struct irlmp_iter_state *iter = seq->private;	if (iter->hashbin)		spin_unlock_irq(&iter->hashbin->hb_spinlock);}static int irlmp_seq_show(struct seq_file *seq, void *v){	const struct irlmp_iter_state *iter = seq->private;	struct lsap_cb *self = v;	if (v == LSAP_START_TOKEN)		seq_puts(seq, "Unconnected LSAPs:\n");	else if (v == LINK_START_TOKEN)		seq_puts(seq, "\nRegistered Link Layers:\n");	else if (iter->hashbin == irlmp->unconnected_lsaps) {		self = v;		IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -EINVAL; );		seq_printf(seq, "lsap state: %s, ",			   irlsap_state[ self->lsap_state]);		seq_printf(seq,			   "slsap_sel: %#02x, dlsap_sel: %#02x, ",			   self->slsap_sel, self->dlsap_sel);		seq_printf(seq, "(%s)", self->notify.name);		seq_printf(seq, "\n");	} else if (iter->hashbin == irlmp->links) {		struct lap_cb *lap = v;		seq_printf(seq, "lap state: %s, ",			   irlmp_state[lap->lap_state]);		seq_printf(seq, "saddr: %#08x, daddr: %#08x, ",			   lap->saddr, lap->daddr);		seq_printf(seq, "num lsaps: %d",			   HASHBIN_GET_SIZE(lap->lsaps));		seq_printf(seq, "\n");		/* Careful for priority inversions here !		 * All other uses of attrib spinlock are independent of		 * the object spinlock, so we are safe. Jean II */		spin_lock(&lap->lsaps->hb_spinlock);		seq_printf(seq, "\n  Connected LSAPs:\n");		for (self = (struct lsap_cb *) hashbin_get_first(lap->lsaps);		     self != NULL;		     self = (struct lsap_cb *)hashbin_get_next(lap->lsaps)) {			IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC,				    goto outloop;);			seq_printf(seq, "  lsap state: %s, ",				   irlsap_state[ self->lsap_state]);			seq_printf(seq,				   "slsap_sel: %#02x, dlsap_sel: %#02x, ",				   self->slsap_sel, self->dlsap_sel);			seq_printf(seq, "(%s)", self->notify.name);			seq_putc(seq, '\n');		}	IRDA_ASSERT_LABEL(outloop:)		spin_unlock(&lap->lsaps->hb_spinlock);		seq_putc(seq, '\n');	} else		return -EINVAL;	return 0;}static const struct seq_operations irlmp_seq_ops = {	.start  = irlmp_seq_start,	.next   = irlmp_seq_next,	.stop   = irlmp_seq_stop,	.show   = irlmp_seq_show,};static int irlmp_seq_open(struct inode *inode, struct file *file){	IRDA_ASSERT(irlmp != NULL, return -EINVAL;);	return seq_open_private(file, &irlmp_seq_ops,			sizeof(struct irlmp_iter_state));}const struct file_operations irlmp_seq_fops = {	.owner		= THIS_MODULE,	.open           = irlmp_seq_open,	.read           = seq_read,	.llseek         = seq_lseek,	.release	= seq_release_private,};#endif /* PROC_FS */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -