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

📄 af_irda.c

📁 《嵌入式系统设计与实例开发实验教材二源码》Linux内核移植与编译实验
💻 C
📖 第 1 页 / 共 5 页
字号:
			return -EINVAL;			if (get_user(opt, (int *)optval))			return -EFAULT;		/* Unregister any old registration */		if (self->skey)			irlmp_unregister_service(self->skey);		self->skey = irlmp_register_service((__u16) opt);		break;	case IRLMP_HINT_MASK_SET:		/* As opposed to the previous case which set the hint bits		 * that we advertise, this one set the filter we use when		 * making a discovery (nodes which don't match any hint		 * bit in the mask are not reported).		 */		if (optlen < sizeof(int))			return -EINVAL;			if (get_user(opt, (int *)optval))			return -EFAULT;		/* Set the new hint mask */		self->mask = (__u16) opt;		/* Mask out extension bits */		self->mask &= 0x7f7f;		/* Check if no bits */		if(!self->mask)			self->mask = 0xFFFF;		break;	default:		return -ENOPROTOOPT;	}	return 0;}/* * Function irda_extract_ias_value(ias_opt, ias_value) * *    Translate internal IAS value structure to the user space representation * * The external representation of IAS values, as we exchange them with * user space program is quite different from the internal representation, * as stored in the IAS database (because we need a flat structure for * crossing kernel boundary). * This function transform the former in the latter. We also check * that the value type is valid. */static int irda_extract_ias_value(struct irda_ias_set *ias_opt,				  struct ias_value *ias_value){	/* Look at the type */	switch (ias_value->type) {	case IAS_INTEGER:		/* Copy the integer */		ias_opt->attribute.irda_attrib_int = ias_value->t.integer;		break;	case IAS_OCT_SEQ:		/* Set length */		ias_opt->attribute.irda_attrib_octet_seq.len = ias_value->len;		/* Copy over */		memcpy(ias_opt->attribute.irda_attrib_octet_seq.octet_seq,		       ias_value->t.oct_seq, ias_value->len);		break;	case IAS_STRING:		/* Set length */		ias_opt->attribute.irda_attrib_string.len = ias_value->len;		ias_opt->attribute.irda_attrib_string.charset = ias_value->charset;		/* Copy over */		memcpy(ias_opt->attribute.irda_attrib_string.string,		       ias_value->t.string, ias_value->len);		/* NULL terminate the string (avoid troubles) */		ias_opt->attribute.irda_attrib_string.string[ias_value->len] = '\0';		break;	case IAS_MISSING:	default :		return -EINVAL;	}		/* Copy type over */	ias_opt->irda_attrib_type = ias_value->type;		return 0;}/* * Function irda_getsockopt (sock, level, optname, optval, optlen) * *     * */static int irda_getsockopt(struct socket *sock, int level, int optname, 			   char *optval, int *optlen){	struct sock *sk = sock->sk;	struct irda_sock *self;	struct irda_device_list list;	struct irda_device_info *discoveries;	struct irda_ias_set *	ias_opt;	/* IAS get/query params */	struct ias_object *	ias_obj;	/* Object in IAS */	struct ias_attrib *	ias_attr;	/* Attribute in IAS object */	int daddr = DEV_ADDR_ANY;	/* Dest address for IAS queries */	int val = 0;	int len = 0;	int err;	int offset, total;	self = sk->protinfo.irda;	IRDA_DEBUG(2, __FUNCTION__ "(%p)\n", self);	if (level != SOL_IRLMP)		return -ENOPROTOOPT;	if (get_user(len, optlen))		return -EFAULT;	if(len < 0)		return -EINVAL;			switch (optname) {	case IRLMP_ENUMDEVICES:		/* Ask lmp for the current discovery log */		discoveries = irlmp_get_discoveries(&list.len, self->mask,						    self->nslots);		/* Check if the we got some results */		if (discoveries == NULL)			return -EAGAIN;		/* Didn't find any devices */		err = 0;		/* Write total list length back to client */		if (copy_to_user(optval, &list, 				 sizeof(struct irda_device_list) -				 sizeof(struct irda_device_info)))			err = -EFAULT;		/* Offset to first device entry */		offset = sizeof(struct irda_device_list) - 			sizeof(struct irda_device_info);		/* Copy the list itself - watch for overflow */		if(list.len > 2048)		{			err = -EINVAL;			goto bed;		}		total = offset + (list.len * sizeof(struct irda_device_info));		if (total > len)			total = len;		if (copy_to_user(optval+offset, discoveries, total - offset))			err = -EFAULT;		/* Write total number of bytes used back to client */		if (put_user(total, optlen))			err = -EFAULT;bed:		/* Free up our buffer */		kfree(discoveries);		if (err)			return err;		break;	case IRLMP_MAX_SDU_SIZE:		val = self->max_data_size;		len = sizeof(int);		if (put_user(len, optlen))			return -EFAULT;				if (copy_to_user(optval, &val, len))			return -EFAULT;		break;	case IRLMP_IAS_GET:		/* The user want an object from our local IAS database.		 * We just need to query the IAS and return the value		 * that we found */		/* Check that the user has allocated the right space for us */		if (len != sizeof(struct irda_ias_set))			return -EINVAL;		ias_opt = kmalloc(sizeof(struct irda_ias_set), GFP_ATOMIC);		if (ias_opt == NULL)			return -ENOMEM;		/* Copy query to the driver. */		if (copy_from_user((char *) ias_opt, (char *)optval, len)) {			kfree(ias_opt);		  	return -EFAULT;		}		/* Find the object we target.		 * If the user gives us an empty string, we use the object		 * associated with this socket. This will workaround		 * duplicated class name - Jean II */		if(ias_opt->irda_class_name[0] == '\0')			ias_obj = self->ias_obj;		else			ias_obj = irias_find_object(ias_opt->irda_class_name);		if(ias_obj == (struct ias_object *) NULL) {			kfree(ias_opt);			return -EINVAL;		}		/* Find the attribute (in the object) we target */		ias_attr = irias_find_attrib(ias_obj,					     ias_opt->irda_attrib_name); 		if(ias_attr == (struct ias_attrib *) NULL) {			kfree(ias_opt);			return -EINVAL;		}		/* Translate from internal to user structure */		err = irda_extract_ias_value(ias_opt, ias_attr->value);		if(err) {			kfree(ias_opt);			return err;		}		/* Copy reply to the user */		if (copy_to_user((char *)optval, (char *) ias_opt,				 sizeof(struct irda_ias_set))) {			kfree(ias_opt);		  	return -EFAULT;		}		/* Note : don't need to put optlen, we checked it */		kfree(ias_opt);		break;	case IRLMP_IAS_QUERY:		/* The user want an object from a remote IAS database.		 * We need to use IAP to query the remote database and		 * then wait for the answer to come back. */		/* Check that the user has allocated the right space for us */		if (len != sizeof(struct irda_ias_set))			return -EINVAL;		ias_opt = kmalloc(sizeof(struct irda_ias_set), GFP_ATOMIC);		if (ias_opt == NULL)			return -ENOMEM;		/* Copy query to the driver. */		if (copy_from_user((char *) ias_opt, (char *)optval, len)) {			kfree(ias_opt);		  	return -EFAULT;		}		/* At this point, there are two cases...		 * 1) the socket is connected - that's the easy case, we		 *	just query the device we are connected to...		 * 2) the socket is not connected - the user doesn't want		 *	to connect and/or may not have a valid service name		 *	(so can't create a fake connection). In this case,		 *	we assume that the user pass us a valid destination		 *	address in the requesting structure...		 */		if(self->daddr != DEV_ADDR_ANY) {			/* We are connected - reuse known daddr */			daddr = self->daddr;		} else {			/* We are not connected, we must specify a valid			 * destination address */			daddr = ias_opt->daddr;			if((!daddr) || (daddr == DEV_ADDR_ANY)) {				kfree(ias_opt);				return -EINVAL;			}		}		/* Check that we can proceed with IAP */		if (self->iriap) {			WARNING(__FUNCTION__				"(), busy with a previous query\n");			kfree(ias_opt);			return -EBUSY;		}		self->iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self,					 irda_getvalue_confirm);		/* Treat unexpected signals as disconnect */		self->errno = -EHOSTUNREACH;		/* Query remote LM-IAS */		iriap_getvaluebyclass_request(self->iriap,					      self->saddr, daddr,					      ias_opt->irda_class_name,					      ias_opt->irda_attrib_name);		/* Wait for answer (if not already failed) */		if(self->iriap != NULL)			interruptible_sleep_on(&self->query_wait);		/* Check what happened */		if (self->errno)		{			kfree(ias_opt);			/* Requested object/attribute doesn't exist */			if((self->errno == IAS_CLASS_UNKNOWN) ||			   (self->errno == IAS_ATTRIB_UNKNOWN))				return (-EADDRNOTAVAIL);			else				return (-EHOSTUNREACH);		}		/* Translate from internal to user structure */		err = irda_extract_ias_value(ias_opt, self->ias_result);		if (self->ias_result)			irias_delete_value(self->ias_result);		if (err) {			kfree(ias_opt);			return err;		}		/* Copy reply to the user */		if (copy_to_user((char *)optval, (char *) ias_opt,				 sizeof(struct irda_ias_set))) {			kfree(ias_opt);		  	return -EFAULT;		}		/* Note : don't need to put optlen, we checked it */		kfree(ias_opt);		break;	case IRLMP_WAITDEVICE:		/* This function is just another way of seeing life ;-)		 * IRLMP_ENUMDEVICES assumes that you have a static network,		 * and that you just want to pick one of the devices present.		 * On the other hand, in here we assume that no device is		 * present and that at some point in the future a device will		 * come into range. When this device arrive, we just wake		 * up the caller, so that he has time to connect to it before		 * the device goes away...		 * Note : once the node has been discovered for more than a		 * few second, it won't trigger this function, unless it		 * goes away and come back changes its hint bits (so we		 * might call it IRLMP_WAITNEWDEVICE).		 */		/* Check that the user is passing us an int */		if (len != sizeof(int))			return -EINVAL;		/* Get timeout in ms (max time we block the caller) */		if (get_user(val, (int *)optval))			return -EFAULT;		/* Tell IrLMP we want to be notified */		irlmp_update_client(self->ckey, self->mask,				    irda_selective_discovery_indication,				    NULL, (void *) self);				/* Do some discovery (and also return cached results) */		irlmp_discovery_request(self->nslots);				/* Wait until a node is discovered */		if (!self->cachediscovery) {			IRDA_DEBUG(1, __FUNCTION__ 				   "(), nothing discovered yet, going to sleep...\n");			/* Set watchdog timer to expire in <val> ms. */			self->watchdog.function = irda_discovery_timeout;			self->watchdog.data = (unsigned long) self;			self->watchdog.expires = jiffies + (val * HZ/1000);			add_timer(&(self->watchdog));			/* Wait for IR-LMP to call us back */			interruptible_sleep_on(&self->query_wait);			/* If watchdog is still activated, kill it! */			if(timer_pending(&(self->watchdog)))				del_timer(&(self->watchdog));			IRDA_DEBUG(1, __FUNCTION__ 				   "(), ...waking up !\n");		}		else			IRDA_DEBUG(1, __FUNCTION__ 				   "(), found immediately !\n");		/* Tell IrLMP that we have been notified */		irlmp_update_client(self->ckey, self->mask, NULL, NULL, NULL);		/* Check if the we got some results */		if (!self->cachediscovery)			return -EAGAIN;		/* Didn't find any devices */		/* Cleanup */		self->cachediscovery = NULL;		/* Note : We don't return anything to the user.		 * We could return the device that triggered the wake up,		 * but it's probably better to force the user to query		 * the whole discovery log and let him pick one device...		 */		break;	default:		return -ENOPROTOOPT;	}		return 0;}static struct net_proto_family irda_family_ops ={	PF_IRDA,	irda_create};static struct proto_ops SOCKOPS_WRAPPED(irda_stream_ops) = {	family:		PF_IRDA,		release:	irda_release,	bind:		irda_bind,	connect:	irda_connect,	socketpair:	sock_no_socketpair,	accept:		irda_accept,	getname:	irda_getname,	poll:		irda_poll,	ioctl:		irda_ioctl,	listen:		irda_listen,	shutdown:	irda_shutdown,	setsockopt:	irda_setsockopt,	getsockopt:	irda_getsockopt,	sendmsg:	irda_sendmsg,	recvmsg:	irda_recvmsg_stream,	mmap:		sock_no_mmap,	sendpage:	sock_no_sendpage,};static struct proto_ops SOCKOPS_WRAPPED(irda_seqpacket_ops) = {	family:		PF_IRDA,		release:	irda_release,	bind:		irda_bind,	connect:	irda_connect,	socketpair:	sock_no_socketpair,	accept:		irda_accept,	getname:	irda_getname,	poll:		datagram_poll,	ioctl:		irda_ioctl,	listen:		irda_listen,	shutdown:	irda_shutdown,	setsockopt:	irda_setsockopt,	getsockopt:	irda_getsockopt,	sendmsg:	irda_sendmsg,	recvmsg:	irda_recvmsg_dgram,	mmap:		sock_no_mmap,	sendpage:	sock_no_sendpage,};static struct proto_ops SOCKOPS_WRAPPED(irda_dgram_ops) = {	family:		PF_IRDA,       	release:	irda_release,	bind:		irda_bind,	connect:	irda_connect,	socketpair:	sock_no_socketpair,	accept:		irda_accept,	getname:	irda_getname,	poll:		datagram_poll,	ioctl:		irda_ioctl,	listen:		irda_listen,	shutdown:	irda_shutdown,	setsockopt:	irda_setsockopt,	getsockopt:	irda_getsockopt,	sendmsg:	irda_sendmsg_dgram,	recvmsg:	irda_recvmsg_dgram,	mmap:		sock_no_mmap,	sendpage:	sock_no_sendpage,};#ifdef CONFIG_IRDA_ULTRAstatic struct proto_ops SOCKOPS_WRAPPED(irda_ultra_ops) = {	family:		PF_IRDA,       	release:	irda_release,	bind:		irda_bind,	connect:	sock_no_connect,	socketpair:	sock_no_socketpair,	accept:		sock_no_accept,	getname:	irda_getname,	poll:		datagram_poll,	ioctl:		irda_ioctl,	listen:		sock_no_listen,	shutdown:	irda_shutdown,	setsockopt:	irda_setsockopt,	getsockopt:	irda_getsockopt,	sendmsg:	irda_sendmsg_ultra,	recvmsg:	irda_recvmsg_dgram,	mmap:		sock_no_mmap,	sendpage:	sock_no_sendpage,};#endif /* CONFIG_IRDA_ULTRA */#include <linux/smp_lock.h>SOCKOPS_WRAP(irda_stream, PF_IRDA);SOCKOPS_WRAP(irda_seqpacket, PF_IRDA);SOCKOPS_WRAP(irda_dgram, PF_IRDA);#ifdef CONFIG_IRDA_ULTRASOCKOPS_WRAP(irda_ultra, PF_IRDA);#endif /* CONFIG_IRDA_ULTRA *//* * Function irda_device_event (this

⌨️ 快捷键说明

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