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

📄 af_irda.c

📁 Linux内核源代码 为压缩文件 是<<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, 0, 				  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, 0, 				  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;	IRDA_DEBUG(0, __FUNCTION__ "()\n");	self = sk->protinfo.irda;	ASSERT(self != NULL, return -1;);	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;	IRDA_DEBUG(4, __FUNCTION__ "()\n");	poll_wait(file, sk->sleep, wait);	mask = 0;	/* exceptional events? */	if (sk->err)		mask |= POLLERR;	if (sk->shutdown & RCV_SHUTDOWN)		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 */	if (sk->type == SOCK_STREAM && sk->state==TCP_CLOSE)		mask |= POLLHUP;	/*	 * we set writable also when the other side has shut down the	 * connection. This prevents stuck sockets.	 */	if (sk->sndbuf - (int)atomic_read(&sk->wmem_alloc) >= SOCK_MIN_WRITE_SPACE)			mask |= POLLOUT | POLLWRNORM | POLLWRBAND;	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;);	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;			/* Copy query to the driver. */		if (copy_from_user(&ias_opt, (char *)optval, optlen))		  	return -EFAULT;		/* Find the object we target */		ias_obj = irias_find_object(ias_opt.irda_class_name);		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 it already ? */		if(irias_find_attrib(ias_obj, ias_opt.irda_attrib_name))			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)				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)				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 :			return -EINVAL;		}		irias_insert_object(ias_obj);		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;			/* Copy query to the driver. */		if (copy_from_user(&ias_opt, (char *)optval, optlen))		  	return -EFAULT;		/* Find the object we target */		ias_obj = irias_find_object(ias_opt.irda_class_name);		if(ias_obj == (struct ias_object *) NULL)			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)			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");			return -EPERM;		}		/* Remove the attribute (and maybe the object) */		irias_delete_attrib(ias_obj, ias_attr);		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))			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,

⌨️ 快捷键说明

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