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

📄 af_irda.c

📁 《嵌入式系统设计与实例开发实验教材二源码》Linux内核移植与编译实验
💻 C
📖 第 1 页 / 共 5 页
字号:
 * */static int irda_sendmsg_dgram(struct socket *sock, struct msghdr *msg,			      int len, struct scm_cookie *scm){	struct sock *sk = sock->sk;	struct irda_sock *self;	struct sk_buff *skb;	unsigned char *asmptr;	int err;		IRDA_DEBUG(4, __FUNCTION__ "(), len=%d\n", len);		if (msg->msg_flags & ~MSG_DONTWAIT)		return -EINVAL;	if (sk->shutdown & SEND_SHUTDOWN) {		send_sig(SIGPIPE, current, 0);		return -EPIPE;	}	if (sk->state != TCP_ESTABLISHED)		return -ENOTCONN;	self = sk->protinfo.irda;	ASSERT(self != NULL, return -1;);	/*  	 * Check that we don't send out to big frames. This is an unreliable 	 * service, so we have no fragmentation and no coalescence 	 */	if (len > self->max_data_size) {		IRDA_DEBUG(0, __FUNCTION__ "(), Warning to much data! "			   "Chopping frame from %d to %d bytes!\n", 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);		IRDA_DEBUG(4, __FUNCTION__ "(), appending user data\n");	asmptr = skb->h.raw = skb_put(skb, len);	memcpy_fromiovec(asmptr, msg->msg_iov, len);	/* 	 * 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, __FUNCTION__ "(), err=%d\n", err);		return err;	}	return len;}/* * Function irda_sendmsg_ultra (sock, msg, len, scm) * *    Send message down to IrLMP for the unreliable Ultra *    packet service... */#ifdef CONFIG_IRDA_ULTRAstatic int irda_sendmsg_ultra(struct socket *sock, struct msghdr *msg,			      int len, struct scm_cookie *scm){	struct sock *sk = sock->sk;	struct irda_sock *self;	struct sk_buff *skb;	unsigned char *asmptr;	int err;		IRDA_DEBUG(4, __FUNCTION__ "(), len=%d\n", len);		if (msg->msg_flags & ~MSG_DONTWAIT)		return -EINVAL;	if (sk->shutdown & SEND_SHUTDOWN) {		send_sig(SIGPIPE, current, 0);		return -EPIPE;	}	self = sk->protinfo.irda;	ASSERT(self != NULL, return -1;);	/*  	 * Check that we don't send out to big frames. This is an unreliable 	 * service, so we have no fragmentation and no coalescence 	 */	if (len > self->max_data_size) {		IRDA_DEBUG(0, __FUNCTION__ "(), Warning to much data! "			   "Chopping frame from %d to %d bytes!\n", 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);		IRDA_DEBUG(4, __FUNCTION__ "(), appending user data\n");	asmptr = skb->h.raw = skb_put(skb, len);	memcpy_fromiovec(asmptr, msg->msg_iov, len);	err = irlmp_connless_data_request(self->lsap, skb);	if (err) {		IRDA_DEBUG(0, __FUNCTION__ "(), err=%d\n", err);		return err;	}	return len;}#endif /* CONFIG_IRDA_ULTRA *//* * Function irda_shutdown (sk, how) * *     * */static int irda_shutdown(struct socket *sock, int how){	struct irda_sock *self;	struct sock *sk = sock->sk;	self = sk->protinfo.irda;	ASSERT(self != NULL, return -1;);	IRDA_DEBUG(1, __FUNCTION__ "(%p)\n", self);	sk->state       = TCP_CLOSE;	sk->shutdown   |= SEND_SHUTDOWN;	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;	unsigned int mask;	struct irda_sock *self;	IRDA_DEBUG(4, __FUNCTION__ "()\n");	self = sk->protinfo.irda;	poll_wait(file, sk->sleep, wait);	mask = 0;	/* Exceptional events? */	if (sk->err)		mask |= POLLERR;	if (sk->shutdown & RCV_SHUTDOWN) {		IRDA_DEBUG(0, __FUNCTION__ "(), POLLHUP\n");		mask |= POLLHUP;	}	/* Readable? */	if (!skb_queue_empty(&sk->receive_queue)) {		IRDA_DEBUG(4, "Socket is readable\n");		mask |= POLLIN | POLLRDNORM;	}	/* Connection-based need to check for termination and startup */	switch (sk->type) {	case SOCK_STREAM:		if (sk->state == TCP_CLOSE) {			IRDA_DEBUG(0, __FUNCTION__ "(), POLLHUP\n");			mask |= POLLHUP;		}		if (sk->state == TCP_ESTABLISHED) {			if ((self->tx_flow == FLOW_START) && 			    (sk->sndbuf - (int)atomic_read(&sk->wmem_alloc) >= SOCK_MIN_WRITE_SPACE))			{				mask |= POLLOUT | POLLWRNORM | POLLWRBAND;			}		}		break;	case SOCK_SEQPACKET:		if ((self->tx_flow == FLOW_START) && 		    (sk->sndbuf - (int)atomic_read(&sk->wmem_alloc) >= SOCK_MIN_WRITE_SPACE))		{				mask |= POLLOUT | POLLWRNORM | POLLWRBAND;		}		break;	case SOCK_DGRAM:		if (sk->sndbuf - (int)atomic_read(&sk->wmem_alloc) >= SOCK_MIN_WRITE_SPACE)			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, __FUNCTION__ "(), cmd=%#x\n", cmd);		switch (cmd) {	case TIOCOUTQ: {		long amount;		amount = sk->sndbuf - atomic_read(&sk->wmem_alloc);		if (amount < 0)			amount = 0;		if (put_user(amount, (unsigned int *)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->receive_queue)) != NULL)			amount = skb->len;		if (put_user(amount, (unsigned int *)arg))			return -EFAULT;		return 0;	}		case SIOCGSTAMP:		if (sk != NULL) {			if (sk->stamp.tv_sec == 0)				return -ENOENT;			if (copy_to_user((void *)arg, &sk->stamp, 					 sizeof(struct timeval)))				return -EFAULT;			return 0;		}		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, __FUNCTION__ "(), doing device ioctl!\n");		return dev_ioctl(cmd, (void *) arg);	}	/*NOTREACHED*/	return 0;}/* * 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 *optval, int optlen){ 	struct sock *sk = sock->sk;	struct irda_sock *self;	struct irda_ias_set    *ias_opt;	struct ias_object      *ias_obj;	struct ias_attrib *	ias_attr;	/* Attribute in IAS object */	int opt;		self = sk->protinfo.irda;	ASSERT(self != NULL, return -1;);	IRDA_DEBUG(2, __FUNCTION__ "(%p)\n", 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, (char *)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);		}		/* Do we have the attribute already ? */		if(irias_find_attrib(ias_obj, ias_opt->irda_attrib_name)) {			kfree(ias_opt);			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);				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 */			if(ias_opt->attribute.irda_attrib_string.len >			   IAS_MAX_STRING) {				kfree(ias_opt);				return -EINVAL;			}			/* 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);			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, (char *)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;		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, __FUNCTION__ 				   "(), attempting to delete a kernel attribute\n");			kfree(ias_opt);			return -EPERM;		}		/* Remove the attribute (and maybe the object) */		irias_delete_attrib(ias_obj, ias_attr);		kfree(ias_opt);		break;	case IRLMP_MAX_SDU_SIZE:		if (optlen < sizeof(int))			return -EINVAL;			if (get_user(opt, (int *)optval))			return -EFAULT;				/* Only possible for a seqpacket service (TTP with SAR) */		if (sk->type != SOCK_SEQPACKET) {			IRDA_DEBUG(2, __FUNCTION__ 				   "(), setting max_sdu_size = %d\n", opt);			self->max_sdu_size_rx = opt;		} else {			WARNING(__FUNCTION__ 				"(), not allowed to set MAXSDUSIZE for this "				"socket type!\n");			return -ENOPROTOOPT;		}		break;	case IRLMP_HINTS_SET:		if (optlen < sizeof(int))

⌨️ 快捷键说明

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