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

📄 irlmp.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
 *    Incoming connection * */void irlmp_connect_indication(struct lsap_cb *self, struct sk_buff *skb){	int max_seg_size;	int lap_header_size;	int max_header_size;	IRDA_ASSERT(self != NULL, return;);	IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return;);	IRDA_ASSERT(skb != NULL, return;);	IRDA_ASSERT(self->lap != NULL, return;);	IRDA_DEBUG(2, "%s(), slsap_sel=%02x, dlsap_sel=%02x\n",		   __FUNCTION__, self->slsap_sel, self->dlsap_sel);	/* Note : self->lap is set in irlmp_link_data_indication(),	 * (case CONNECT_CMD:) because we have no way to set it here.	 * Similarly, self->dlsap_sel is usually set in irlmp_find_lsap().	 * Jean II */	self->qos = *self->lap->qos;	max_seg_size = self->lap->qos->data_size.value-LMP_HEADER;	lap_header_size = IRLAP_GET_HEADER_SIZE(self->lap->irlap);	max_header_size = LMP_HEADER + lap_header_size;	/* Hide LMP_CONTROL_HEADER header from layer above */	skb_pull(skb, LMP_CONTROL_HEADER);	if (self->notify.connect_indication) {		/* Don't forget to refcount it - see irlap_driver_rcv(). */		skb_get(skb);		self->notify.connect_indication(self->notify.instance, self,						&self->qos, max_seg_size,						max_header_size, skb);	}}/* * Function irlmp_connect_response (handle, userdata) * *    Service user is accepting connection * */int irlmp_connect_response(struct lsap_cb *self, struct sk_buff *userdata){	IRDA_ASSERT(self != NULL, return -1;);	IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);	IRDA_ASSERT(userdata != NULL, return -1;);	/* We set the connected bit and move the lsap to the connected list	 * in the state machine itself. Jean II */	IRDA_DEBUG(2, "%s(), slsap_sel=%02x, dlsap_sel=%02x\n",		   __FUNCTION__, self->slsap_sel, self->dlsap_sel);	/* Make room for MUX control header (3 bytes) */	IRDA_ASSERT(skb_headroom(userdata) >= LMP_CONTROL_HEADER, return -1;);	skb_push(userdata, LMP_CONTROL_HEADER);	irlmp_do_lsap_event(self, LM_CONNECT_RESPONSE, userdata);	/* Drop reference count - see irlap_data_request(). */	dev_kfree_skb(userdata);	return 0;}EXPORT_SYMBOL(irlmp_connect_response);/* * Function irlmp_connect_confirm (handle, skb) * *    LSAP connection confirmed peer device! */void irlmp_connect_confirm(struct lsap_cb *self, struct sk_buff *skb){	int max_header_size;	int lap_header_size;	int max_seg_size;	IRDA_DEBUG(3, "%s()\n", __FUNCTION__);	IRDA_ASSERT(skb != NULL, return;);	IRDA_ASSERT(self != NULL, return;);	IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return;);	IRDA_ASSERT(self->lap != NULL, return;);	self->qos = *self->lap->qos;	max_seg_size    = self->lap->qos->data_size.value-LMP_HEADER;	lap_header_size = IRLAP_GET_HEADER_SIZE(self->lap->irlap);	max_header_size = LMP_HEADER + lap_header_size;	IRDA_DEBUG(2, "%s(), max_header_size=%d\n",		   __FUNCTION__, max_header_size);	/* Hide LMP_CONTROL_HEADER header from layer above */	skb_pull(skb, LMP_CONTROL_HEADER);	if (self->notify.connect_confirm) {		/* Don't forget to refcount it - see irlap_driver_rcv() */		skb_get(skb);		self->notify.connect_confirm(self->notify.instance, self,					     &self->qos, max_seg_size,					     max_header_size, skb);	}}/* * Function irlmp_dup (orig, instance) * *    Duplicate LSAP, can be used by servers to confirm a connection on a *    new LSAP so it can keep listening on the old one. * */struct lsap_cb *irlmp_dup(struct lsap_cb *orig, void *instance){	struct lsap_cb *new;	unsigned long flags;	IRDA_DEBUG(1, "%s()\n", __FUNCTION__);	spin_lock_irqsave(&irlmp->unconnected_lsaps->hb_spinlock, flags);	/* Only allowed to duplicate unconnected LSAP's, and only LSAPs	 * that have received a connect indication. Jean II */	if ((!hashbin_find(irlmp->unconnected_lsaps, (long) orig, NULL)) ||	    (orig->lap == NULL)) {		IRDA_DEBUG(0, "%s(), invalid LSAP (wrong state)\n",			   __FUNCTION__);		spin_unlock_irqrestore(&irlmp->unconnected_lsaps->hb_spinlock,				       flags);		return NULL;	}	/* Allocate a new instance */	new = kmemdup(orig, sizeof(*new), GFP_ATOMIC);	if (!new)  {		IRDA_DEBUG(0, "%s(), unable to kmalloc\n", __FUNCTION__);		spin_unlock_irqrestore(&irlmp->unconnected_lsaps->hb_spinlock,				       flags);		return NULL;	}	/* new->lap = orig->lap; => done in the memcpy() */	/* new->slsap_sel = orig->slsap_sel; => done in the memcpy() */	new->conn_skb = NULL;	spin_unlock_irqrestore(&irlmp->unconnected_lsaps->hb_spinlock, flags);	/* Not everything is the same */	new->notify.instance = instance;	init_timer(&new->watchdog_timer);	hashbin_insert(irlmp->unconnected_lsaps, (irda_queue_t *) new,		       (long) new, NULL);#ifdef CONFIG_IRDA_CACHE_LAST_LSAP	/* Make sure that we invalidate the LSAP cache */	new->lap->cache.valid = FALSE;#endif /* CONFIG_IRDA_CACHE_LAST_LSAP */	return new;}/* * Function irlmp_disconnect_request (handle, userdata) * *    The service user is requesting disconnection, this will not remove the *    LSAP, but only mark it as disconnected */int irlmp_disconnect_request(struct lsap_cb *self, struct sk_buff *userdata){	struct lsap_cb *lsap;	IRDA_ASSERT(self != NULL, return -1;);	IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);	IRDA_ASSERT(userdata != NULL, return -1;);	/* 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, "%s(), already disconnected!\n", __FUNCTION__);		dev_kfree_skb(userdata);		return -1;	}	skb_push(userdata, LMP_CONTROL_HEADER);	/*	 *  Do the event before the other stuff since we must know	 *  which lap layer that the frame should be transmitted on	 */	irlmp_do_lsap_event(self, LM_DISCONNECT_REQUEST, userdata);	/* Drop reference count - see irlap_data_request(). */	dev_kfree_skb(userdata);	/*	 *  Remove LSAP from list of connected LSAPs for the particular link	 *  and insert it into the list of unconnected LSAPs	 */	IRDA_ASSERT(self->lap != NULL, return -1;);	IRDA_ASSERT(self->lap->magic == LMP_LAP_MAGIC, return -1;);	IRDA_ASSERT(self->lap->lsaps != NULL, return -1;);	lsap = hashbin_remove(self->lap->lsaps, (long) self, NULL);#ifdef CONFIG_IRDA_CACHE_LAST_LSAP	self->lap->cache.valid = FALSE;#endif	IRDA_ASSERT(lsap != NULL, return -1;);	IRDA_ASSERT(lsap->magic == LMP_LSAP_MAGIC, return -1;);	IRDA_ASSERT(lsap == self, return -1;);	hashbin_insert(irlmp->unconnected_lsaps, (irda_queue_t *) self,		       (long) self, NULL);	/* Reset some values */	self->dlsap_sel = LSAP_ANY;	self->lap = NULL;	return 0;}EXPORT_SYMBOL(irlmp_disconnect_request);/* * Function irlmp_disconnect_indication (reason, userdata) * *    LSAP is being closed! */void irlmp_disconnect_indication(struct lsap_cb *self, LM_REASON reason,				 struct sk_buff *skb){	struct lsap_cb *lsap;	IRDA_DEBUG(1, "%s(), reason=%s\n", __FUNCTION__, irlmp_reasons[reason]);	IRDA_ASSERT(self != NULL, return;);	IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return;);	IRDA_DEBUG(3, "%s(), slsap_sel=%02x, dlsap_sel=%02x\n",		   __FUNCTION__, self->slsap_sel, self->dlsap_sel);	/* 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, "%s(), already disconnected!\n", __FUNCTION__);		return;	}	/*	 *  Remove association between this LSAP and the link it used	 */	IRDA_ASSERT(self->lap != NULL, return;);	IRDA_ASSERT(self->lap->lsaps != NULL, return;);	lsap = hashbin_remove(self->lap->lsaps, (long) self, NULL);#ifdef CONFIG_IRDA_CACHE_LAST_LSAP	self->lap->cache.valid = FALSE;#endif	IRDA_ASSERT(lsap != NULL, return;);	IRDA_ASSERT(lsap == self, return;);	hashbin_insert(irlmp->unconnected_lsaps, (irda_queue_t *) lsap,		       (long) lsap, NULL);	self->dlsap_sel = LSAP_ANY;	self->lap = NULL;	/*	 *  Inform service user	 */	if (self->notify.disconnect_indication) {		/* Don't forget to refcount it - see irlap_driver_rcv(). */		if(skb)			skb_get(skb);		self->notify.disconnect_indication(self->notify.instance,						   self, reason, skb);	} else {		IRDA_DEBUG(0, "%s(), no handler\n", __FUNCTION__);	}}/* * Function irlmp_do_expiry (void) * *    Do a cleanup of the discovery log (remove old entries) * * Note : separate from irlmp_do_discovery() so that we can handle * passive discovery properly. */void irlmp_do_expiry(void){	struct lap_cb *lap;	/*	 * Expire discovery on all links which are *not* connected.	 * On links which are connected, we can't do discovery	 * anymore and can't refresh the log, so we freeze the	 * discovery log to keep info about the device we are	 * connected to.	 * This info is mandatory if we want irlmp_connect_request()	 * to work properly. - Jean II	 */	lap = (struct lap_cb *) hashbin_get_first(irlmp->links);	while (lap != NULL) {		IRDA_ASSERT(lap->magic == LMP_LAP_MAGIC, return;);		if (lap->lap_state == LAP_STANDBY) {			/* Expire discoveries discovered on this link */			irlmp_expire_discoveries(irlmp->cachelog, lap->saddr,						 FALSE);		}		lap = (struct lap_cb *) hashbin_get_next(irlmp->links);	}}/* * Function irlmp_do_discovery (nslots) * *    Do some discovery on all links * * Note : log expiry is done above. */void irlmp_do_discovery(int nslots){	struct lap_cb *lap;	__u16 *data_hintsp;	/* Make sure the value is sane */	if ((nslots != 1) && (nslots != 6) && (nslots != 8) && (nslots != 16)){		IRDA_WARNING("%s: invalid value for number of slots!\n",			     __FUNCTION__);		nslots = sysctl_discovery_slots = 8;	}	/* Construct new discovery info to be used by IrLAP, */	data_hintsp = (__u16 *) irlmp->discovery_cmd.data.hints;	put_unaligned(irlmp->hints.word, data_hintsp);	/*	 *  Set character set for device name (we use ASCII), and	 *  copy device name. Remember to make room for a \0 at the	 *  end	 */	irlmp->discovery_cmd.data.charset = CS_ASCII;	strncpy(irlmp->discovery_cmd.data.info, sysctl_devname,		NICKNAME_MAX_LEN);	irlmp->discovery_cmd.name_len = strlen(irlmp->discovery_cmd.data.info);	irlmp->discovery_cmd.nslots = nslots;	/*	 * Try to send discovery packets on all links	 */	lap = (struct lap_cb *) hashbin_get_first(irlmp->links);	while (lap != NULL) {		IRDA_ASSERT(lap->magic == LMP_LAP_MAGIC, return;);		if (lap->lap_state == LAP_STANDBY) {			/* Try to discover */			irlmp_do_lap_event(lap, LM_LAP_DISCOVERY_REQUEST,					   NULL);		}		lap = (struct lap_cb *) hashbin_get_next(irlmp->links);	}}/* * Function irlmp_discovery_request (nslots) * *    Do a discovery of devices in front of the computer * * If the caller has registered a client discovery callback, this * allow him to receive the full content of the discovery log through * this callback (as normally he will receive only new discoveries). */void irlmp_discovery_request(int nslots){	/* Return current cached discovery log (in full) */	irlmp_discovery_confirm(irlmp->cachelog, DISCOVERY_LOG);	/*	 * Start a single discovery operation if discovery is not already	 * running	 */	if (!sysctl_discovery) {		/* Check if user wants to override the default */		if (nslots == DISCOVERY_DEFAULT_SLOTS)			nslots = sysctl_discovery_slots;		irlmp_do_discovery(nslots);		/* Note : we never do expiry here. Expiry will run on the		 * discovery timer regardless of the state of sysctl_discovery		 * Jean II */	}}EXPORT_SYMBOL(irlmp_discovery_request);/* * Function irlmp_get_discoveries (pn, mask, slots) * *    Return the current discovery log * * If discovery is not enabled, you should call this function again * after 1 or 2 seconds (i.e. after discovery has been done). */struct irda_device_info *irlmp_get_discoveries(int *pn, __u16 mask, int nslots){	/* If discovery is not enabled, it's likely that the discovery log	 * will be empty. So, we trigger a single discovery, so that next	 * time the user call us there might be some results in the log.	 * Jean II	 */	if (!sysctl_discovery) {		/* Check if user wants to override the default */		if (nslots == DISCOVERY_DEFAULT_SLOTS)			nslots = sysctl_discovery_slots;		/* Start discovery - will complete sometime later */		irlmp_do_discovery(nslots);		/* Note : we never do expiry here. Expiry will run on the		 * discovery timer regardless of the state of sysctl_discovery		 * Jean II */	}	/* Return current cached discovery log */	return(irlmp_copy_discoveries(irlmp->cachelog, pn, mask, TRUE));}EXPORT_SYMBOL(irlmp_get_discoveries);/* * Function irlmp_notify_client (log) * *    Notify all about discovered devices * * Clients registered with IrLMP are : *	o IrComm *	o IrLAN *	o Any socket (in any state - ouch, that may be a lot !) * The client may have defined a callback to be notified in case of * partial/selective discovery based on the hints that it passed to IrLMP. */static inline voidirlmp_notify_client(irlmp_client_t *client,		    hashbin_t *log, DISCOVERY_MODE mode){	discinfo_t *discoveries;	/* Copy of the discovery log */	int	number;			/* Number of nodes in the log */	int	i;	IRDA_DEBUG(3, "%s()\n", __FUNCTION__);	/* Check if client wants or not partial/selective log (optimisation) */	if (!client->disco_callback)		return;	/*	 * Locking notes :	 * the old code was manipulating the log directly, which was	 * very racy. Now, we use copy_discoveries, that protects	 * itself while dumping the log for us.	 * The overhead of the copy is compensated by the fact that	 * we only pass new discoveries in normal mode and don't	 * pass the same old entry every 3s to the caller as we used	 * to do (virtual function calling is expensive).	 * Jean II	 */	/*	 * Now, check all discovered devices (if any), and notify client	 * only about the services that the client is interested in	 * We also notify only about the new devices unless the caller	 * explicitly request a dump of the log. Jean II	 */	discoveries = irlmp_copy_discoveries(log, &number,					     client->hint_mask.word,					     (mode == DISCOVERY_LOG));	/* Check if the we got some results */	if (discoveries == NULL)		return;	/* No nodes discovered */	/* Pass all entries to the listener */	for(i = 0; i < number; i++)		client->disco_callback(&(discoveries[i]), mode, client->priv);	/* Free up our buffer */	kfree(discoveries);}/* * Function irlmp_discovery_confirm ( self, log) * *    Some device(s) answered to our discovery request! Check to see which *    device it is, and give indication to the client(s) * */void irlmp_discovery_confirm(hashbin_t *log, DISCOVERY_MODE mode){	irlmp_client_t *client;	irlmp_client_t *client_next;

⌨️ 快捷键说明

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