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

📄 af_irda.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
}/* * Function irda_sendmsg_dgram (iocb, sock, msg, len) * *    Send message down to TinyTP for the unreliable sequenced *    packet service... * */static int irda_sendmsg_dgram(struct kiocb *iocb, struct socket *sock,			      struct msghdr *msg, size_t len){	struct sock *sk = sock->sk;	struct irda_sock *self;	struct sk_buff *skb;	int err;	IRDA_DEBUG(4, "%s(), len=%zd\n", __FUNCTION__, len);	if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_CMSG_COMPAT))		return -EINVAL;	if (sk->sk_shutdown & SEND_SHUTDOWN) {		send_sig(SIGPIPE, current, 0);		return -EPIPE;	}	if (sk->sk_state != TCP_ESTABLISHED)		return -ENOTCONN;	self = irda_sk(sk);	/*	 * Check that we don't send out too big frames. This is an unreliable	 * service, so we have no fragmentation and no coalescence	 */	if (len > self->max_data_size) {		IRDA_DEBUG(0, "%s(), Warning to much data! "			   "Chopping frame from %zd to %d bytes!\n",			   __FUNCTION__, len, self->max_data_size);		len = self->max_data_size;	}	skb = sock_alloc_send_skb(sk, len + self->max_header_size,				  msg->msg_flags & MSG_DONTWAIT, &err);	if (!skb)		return -ENOBUFS;	skb_reserve(skb, self->max_header_size);	skb_reset_transport_header(skb);	IRDA_DEBUG(4, "%s(), appending user data\n", __FUNCTION__);	skb_put(skb, len);	err = memcpy_fromiovec(skb_transport_header(skb), msg->msg_iov, len);	if (err) {		kfree_skb(skb);		return err;	}	/*	 * Just send the message to TinyTP, and let it deal with possible	 * errors. No need to duplicate all that here	 */	err = irttp_udata_request(self->tsap, skb);	if (err) {		IRDA_DEBUG(0, "%s(), err=%d\n", __FUNCTION__, err);		return err;	}	return len;}/* * Function irda_sendmsg_ultra (iocb, sock, msg, len) * *    Send message down to IrLMP for the unreliable Ultra *    packet service... */#ifdef CONFIG_IRDA_ULTRAstatic int irda_sendmsg_ultra(struct kiocb *iocb, struct socket *sock,			      struct msghdr *msg, size_t len){	struct sock *sk = sock->sk;	struct irda_sock *self;	__u8 pid = 0;	int bound = 0;	struct sk_buff *skb;	int err;	IRDA_DEBUG(4, "%s(), len=%zd\n", __FUNCTION__, len);	if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_CMSG_COMPAT))		return -EINVAL;	if (sk->sk_shutdown & SEND_SHUTDOWN) {		send_sig(SIGPIPE, current, 0);		return -EPIPE;	}	self = irda_sk(sk);	/* Check if an address was specified with sendto. Jean II */	if (msg->msg_name) {		struct sockaddr_irda *addr = (struct sockaddr_irda *) msg->msg_name;		/* Check address, extract pid. Jean II */		if (msg->msg_namelen < sizeof(*addr))			return -EINVAL;		if (addr->sir_family != AF_IRDA)			return -EINVAL;		pid = addr->sir_lsap_sel;		if (pid & 0x80) {			IRDA_DEBUG(0, "%s(), extension in PID not supp!\n", __FUNCTION__);			return -EOPNOTSUPP;		}	} else {		/* Check that the socket is properly bound to an Ultra		 * port. Jean II */		if ((self->lsap == NULL) ||		    (sk->sk_state != TCP_ESTABLISHED)) {			IRDA_DEBUG(0, "%s(), socket not bound to Ultra PID.\n",				   __FUNCTION__);			return -ENOTCONN;		}		/* Use PID from socket */		bound = 1;	}	/*	 * Check that we don't send out too big frames. This is an unreliable	 * service, so we have no fragmentation and no coalescence	 */	if (len > self->max_data_size) {		IRDA_DEBUG(0, "%s(), Warning to much data! "			   "Chopping frame from %zd to %d bytes!\n",			   __FUNCTION__, len, self->max_data_size);		len = self->max_data_size;	}	skb = sock_alloc_send_skb(sk, len + self->max_header_size,				  msg->msg_flags & MSG_DONTWAIT, &err);	if (!skb)		return -ENOBUFS;	skb_reserve(skb, self->max_header_size);	skb_reset_transport_header(skb);	IRDA_DEBUG(4, "%s(), appending user data\n", __FUNCTION__);	skb_put(skb, len);	err = memcpy_fromiovec(skb_transport_header(skb), msg->msg_iov, len);	if (err) {		kfree_skb(skb);		return err;	}	err = irlmp_connless_data_request((bound ? self->lsap : NULL),					  skb, pid);	if (err) {		IRDA_DEBUG(0, "%s(), err=%d\n", __FUNCTION__, err);		return err;	}	return len;}#endif /* CONFIG_IRDA_ULTRA *//* * Function irda_shutdown (sk, how) */static int irda_shutdown(struct socket *sock, int how){	struct sock *sk = sock->sk;	struct irda_sock *self = irda_sk(sk);	IRDA_DEBUG(1, "%s(%p)\n", __FUNCTION__, self);	sk->sk_state       = TCP_CLOSE;	sk->sk_shutdown   |= SEND_SHUTDOWN;	sk->sk_state_change(sk);	if (self->iriap) {		iriap_close(self->iriap);		self->iriap = NULL;	}	if (self->tsap) {		irttp_disconnect_request(self->tsap, NULL, P_NORMAL);		irttp_close_tsap(self->tsap);		self->tsap = NULL;	}	/* A few cleanup so the socket look as good as new... */	self->rx_flow = self->tx_flow = FLOW_START;	/* needed ??? */	self->daddr = DEV_ADDR_ANY;	/* Until we get re-connected */	self->saddr = 0x0;		/* so IrLMP assign us any link */	return 0;}/* * Function irda_poll (file, sock, wait) */static unsigned int irda_poll(struct file * file, struct socket *sock,			      poll_table *wait){	struct sock *sk = sock->sk;	struct irda_sock *self = irda_sk(sk);	unsigned int mask;	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);	poll_wait(file, sk->sk_sleep, wait);	mask = 0;	/* Exceptional events? */	if (sk->sk_err)		mask |= POLLERR;	if (sk->sk_shutdown & RCV_SHUTDOWN) {		IRDA_DEBUG(0, "%s(), POLLHUP\n", __FUNCTION__);		mask |= POLLHUP;	}	/* Readable? */	if (!skb_queue_empty(&sk->sk_receive_queue)) {		IRDA_DEBUG(4, "Socket is readable\n");		mask |= POLLIN | POLLRDNORM;	}	/* Connection-based need to check for termination and startup */	switch (sk->sk_type) {	case SOCK_STREAM:		if (sk->sk_state == TCP_CLOSE) {			IRDA_DEBUG(0, "%s(), POLLHUP\n", __FUNCTION__);			mask |= POLLHUP;		}		if (sk->sk_state == TCP_ESTABLISHED) {			if ((self->tx_flow == FLOW_START) &&			    sock_writeable(sk))			{				mask |= POLLOUT | POLLWRNORM | POLLWRBAND;			}		}		break;	case SOCK_SEQPACKET:		if ((self->tx_flow == FLOW_START) &&		    sock_writeable(sk))		{			mask |= POLLOUT | POLLWRNORM | POLLWRBAND;		}		break;	case SOCK_DGRAM:		if (sock_writeable(sk))			mask |= POLLOUT | POLLWRNORM | POLLWRBAND;		break;	default:		break;	}	return mask;}/* * Function irda_ioctl (sock, cmd, arg) */static int irda_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg){	struct sock *sk = sock->sk;	IRDA_DEBUG(4, "%s(), cmd=%#x\n", __FUNCTION__, cmd);	switch (cmd) {	case TIOCOUTQ: {		long amount;		amount = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc);		if (amount < 0)			amount = 0;		if (put_user(amount, (unsigned int __user *)arg))			return -EFAULT;		return 0;	}	case TIOCINQ: {		struct sk_buff *skb;		long amount = 0L;		/* These two are safe on a single CPU system as only user tasks fiddle here */		if ((skb = skb_peek(&sk->sk_receive_queue)) != NULL)			amount = skb->len;		if (put_user(amount, (unsigned int __user *)arg))			return -EFAULT;		return 0;	}	case SIOCGSTAMP:		if (sk != NULL)			return sock_get_timestamp(sk, (struct timeval __user *)arg);		return -EINVAL;	case SIOCGIFADDR:	case SIOCSIFADDR:	case SIOCGIFDSTADDR:	case SIOCSIFDSTADDR:	case SIOCGIFBRDADDR:	case SIOCSIFBRDADDR:	case SIOCGIFNETMASK:	case SIOCSIFNETMASK:	case SIOCGIFMETRIC:	case SIOCSIFMETRIC:		return -EINVAL;	default:		IRDA_DEBUG(1, "%s(), doing device ioctl!\n", __FUNCTION__);		return -ENOIOCTLCMD;	}	/*NOTREACHED*/	return 0;}#ifdef CONFIG_COMPAT/* * Function irda_ioctl (sock, cmd, arg) */static int irda_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg){	/*	 * All IRDA's ioctl are standard ones.	 */	return -ENOIOCTLCMD;}#endif/* * Function irda_setsockopt (sock, level, optname, optval, optlen) * *    Set some options for the socket * */static int irda_setsockopt(struct socket *sock, int level, int optname,			   char __user *optval, int optlen){	struct sock *sk = sock->sk;	struct irda_sock *self = irda_sk(sk);	struct irda_ias_set    *ias_opt;	struct ias_object      *ias_obj;	struct ias_attrib *	ias_attr;	/* Attribute in IAS object */	int opt, free_ias = 0;	IRDA_DEBUG(2, "%s(%p)\n", __FUNCTION__, self);	if (level != SOL_IRLMP)		return -ENOPROTOOPT;	switch (optname) {	case IRLMP_IAS_SET:		/* The user want to add an attribute to an existing IAS object		 * (in the IAS database) or to create a new object with this		 * attribute.		 * We first query IAS to know if the object exist, and then		 * create the right attribute...		 */		if (optlen != 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, optlen)) {			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') {			if(self->ias_obj == NULL) {				kfree(ias_opt);				return -EINVAL;			}			ias_obj = self->ias_obj;		} else			ias_obj = irias_find_object(ias_opt->irda_class_name);		/* Only ROOT can mess with the global IAS database.		 * Users can only add attributes to 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;		}		/* If the object doesn't exist, create it */		if(ias_obj == (struct ias_object *) NULL) {			/* Create a new object */			ias_obj = irias_new_object(ias_opt->irda_class_name,						   jiffies);			if (ias_obj == NULL) {				kfree(ias_opt);				return -ENOMEM;			}			free_ias = 1;		}		/* Do we have the attribute already ? */		if(irias_find_attrib(ias_obj, ias_opt->irda_attrib_name)) {			kfree(ias_opt);			if (free_ias) {				kfree(ias_obj->name);				kfree(ias_obj);			}			return -EINVAL;		}		/* Look at the type */		switch(ias_opt->irda_attrib_type) {		case IAS_INTEGER:			/* Add an integer attribute */			irias_add_integer_attrib(				ias_obj,				ias_opt->irda_attrib_name,				ias_opt->attribute.irda_attrib_int,				IAS_USER_ATTR);			break;		case IAS_OCT_SEQ:			/* Check length */			if(ias_opt->attribute.irda_attrib_octet_seq.len >			   IAS_MAX_OCTET_STRING) {				kfree(ias_opt);				if (free_ias) {					kfree(ias_obj->name);					kfree(ias_obj);				}				return -EINVAL;			}			/* Add an octet sequence attribute */			irias_add_octseq_attrib(			      ias_obj,			      ias_opt->irda_attrib_name,			      ias_opt->attribute.irda_attrib_octet_seq.octet_seq,			      ias_opt->attribute.irda_attrib_octet_seq.len,			      IAS_USER_ATTR);			break;		case IAS_STRING:			/* Should check charset & co */			/* Check length */			/* The length is encoded in a __u8, and			 * IAS_MAX_STRING == 256, so there is no way			 * userspace can pass us a string too large.			 * Jean II */			/* NULL terminate the string (avoid troubles) */			ias_opt->attribute.irda_attrib_string.string[ias_opt->attribute.irda_attrib_string.len] = '\0';			/* Add a string attribute */			irias_add_string_attrib(				ias_obj,				ias_opt->irda_attrib_name,				ias_opt->attribute.irda_attrib_string.string,				IAS_USER_ATTR);			break;		default :			kfree(ias_opt);			if (free_ias) {				kfree(ias_obj->name);				kfree(ias_obj);			}			return -EINVAL;		}		irias_insert_object(ias_obj);		kfree(ias_opt);		break;	case IRLMP_IAS_DEL:		/* The user want to delete an object from our local IAS		 * database. We just need to query the IAS, check is the		 * object is not owned by the kernel and delete it.		 */		if (optlen != 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, optlen)) {			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;

⌨️ 快捷键说明

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