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

📄 af_irda.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
		else			ias_obj = irias_find_object(ias_opt->irda_class_name);		if(ias_obj == (struct ias_object *) NULL) {			kfree(ias_opt);			return -EINVAL;		}		/* Only ROOT can mess with the global IAS database.		 * Users can only del attributes from the object associated		 * with the socket they own - Jean II */		if((!capable(CAP_NET_ADMIN)) &&		   ((ias_obj == NULL) || (ias_obj != self->ias_obj))) {			kfree(ias_opt);			return -EPERM;		}		/* 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;		}		/* Check is the user space own the object */		if(ias_attr->value->owner != IAS_USER_ATTR) {			IRDA_DEBUG(1, "%s(), attempting to delete a kernel attribute\n", __FUNCTION__);			kfree(ias_opt);			return -EPERM;		}		/* Remove the attribute (and maybe the object) */		irias_delete_attrib(ias_obj, ias_attr, 1);		kfree(ias_opt);		break;	case IRLMP_MAX_SDU_SIZE:		if (optlen < sizeof(int))			return -EINVAL;		if (get_user(opt, (int __user *)optval))			return -EFAULT;		/* Only possible for a seqpacket service (TTP with SAR) */		if (sk->sk_type != SOCK_SEQPACKET) {			IRDA_DEBUG(2, "%s(), setting max_sdu_size = %d\n",				   __FUNCTION__, opt);			self->max_sdu_size_rx = opt;		} else {			IRDA_WARNING("%s: not allowed to set MAXSDUSIZE for this socket type!\n",				     __FUNCTION__);			return -ENOPROTOOPT;		}		break;	case IRLMP_HINTS_SET:		if (optlen < sizeof(int))			return -EINVAL;		/* The input is really a (__u8 hints[2]), easier as an int */		if (get_user(opt, (int __user *)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;		/* The input is really a (__u8 hints[2]), easier as an int */		if (get_user(opt, (int __user *)optval))			return -EFAULT;		/* Set the new hint mask */		self->mask.word = (__u16) opt;		/* Mask out extension bits */		self->mask.word &= 0x7f7f;		/* Check if no bits */		if(!self->mask.word)			self->mask.word = 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 __user *optval, int __user *optlen){	struct sock *sk = sock->sk;	struct irda_sock *self = irda_sk(sk);	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;	IRDA_DEBUG(2, "%s(%p)\n", __FUNCTION__, 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.word,						    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(ias_opt, 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(optval, 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(ias_opt, 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) {			IRDA_WARNING("%s: busy with a previous query\n",				     __FUNCTION__);			kfree(ias_opt);			return -EBUSY;		}		self->iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self,					 irda_getvalue_confirm);		if (self->iriap == NULL) {			kfree(ias_opt);			return -ENOMEM;		}		/* Treat unexpected wakeup 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 yet finished (or failed) */		if (wait_event_interruptible(self->query_wait,					     (self->iriap == NULL))) {			/* pending request uses copy of ias_opt-content			 * we can free it regardless! */			kfree(ias_opt);			/* Treat signals as disconnect */			return -EHOSTUNREACH;		}		/* 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(optval, 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 __user *)optval))			return -EFAULT;		/* Tell IrLMP we want to be notified */		irlmp_update_client(self->ckey, self->mask.word,				    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->cachedaddr) {			int ret = 0;			IRDA_DEBUG(1, "%s(), nothing discovered yet, going to sleep...\n", __FUNCTION__);			/* Set watchdog timer to expire in <val> ms. */			self->errno = 0;			init_timer(&self->watchdog);			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 */			__wait_event_interruptible(self->query_wait,			      (self->cachedaddr != 0 || self->errno == -ETIME),						   ret);			/* If watchdog is still activated, kill it! */			if(timer_pending(&(self->watchdog)))				del_timer(&(self->watchdog));			IRDA_DEBUG(1, "%s(), ...waking up !\n", __FUNCTION__);			if (ret != 0)				return ret;		}		else			IRDA_DEBUG(1, "%s(), found immediately !\n",				   __FUNCTION__);		/* Tell IrLMP that we have been notified */		irlmp_update_client(self->ckey, self->mask.word,				    NULL, NULL, NULL);		/* Check if the we got some results */		if (!self->cachedaddr)			return -EAGAIN;		/* Didn't find any devices */		daddr = self->cachedaddr;		/* Cleanup */		self->cachedaddr = 0;		/* We return the daddr of the device that trigger the		 * wakeup. As irlmp pass us only the new devices, we		 * are sure that it's not an old device.		 * If the user want more details, he should query		 * the whole discovery log and pick one device...		 */		if (put_user(daddr, (int __user *)optval))			return -EFAULT;		break;	default:		return -ENOPROTOOPT;	}	return 0;}static struct net_proto_family irda_family_ops = {	.family = PF_IRDA,	.create = irda_create,	.owner	= THIS_MODULE,};static const struct proto_ops SOCKOPS_WRAPPED(irda_stream_ops) = {	.family =	PF_IRDA,	.owner =	THIS_MODULE,	.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,#ifdef CONFIG_COMPAT	.compat_ioctl =	irda_c

⌨️ 快捷键说明

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