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

📄 af_irda.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	sk->state   = TCP_CLOSE;		sock->state = SS_UNCONNECTED;	if (addr_len != sizeof(struct sockaddr_irda))		return -EINVAL;	/* Check if user supplied any destination device address */	if ((!addr->sir_addr) || (addr->sir_addr == DEV_ADDR_ANY)) {		/* Try to find one suitable */		err = irda_discover_daddr_and_lsap_sel(self, addr->sir_name);		if (err) {			IRDA_DEBUG(0, __FUNCTION__ 				   "(), auto-connect failed!\n");			return err;		}	} else {		/* Use the one provided by the user */		self->daddr = addr->sir_addr;		IRDA_DEBUG(1, __FUNCTION__ "(), daddr = %08x\n", self->daddr);				/* Query remote LM-IAS */		err = irda_find_lsap_sel(self, addr->sir_name);		if (err) {			IRDA_DEBUG(0, __FUNCTION__ "(), connect failed!\n");			return err;		}	}	/* Check if we have opened a local TSAP */	if (!self->tsap)		irda_open_tsap(self, LSAP_ANY, addr->sir_name);		/* Move to connecting socket, start sending Connect Requests */	sock->state = SS_CONNECTING;	sk->state   = TCP_SYN_SENT;	/* Connect to remote device */	err = irttp_connect_request(self->tsap, self->dtsap_sel, 				    self->saddr, self->daddr, NULL, 				    self->max_sdu_size_rx, NULL);	if (err) {		IRDA_DEBUG(0, __FUNCTION__ "(), connect failed!\n");		return err;	}	/* Now the loop */	if (sk->state != TCP_ESTABLISHED && (flags & O_NONBLOCK))		return -EINPROGRESS;			cli();	/* To avoid races on the sleep */		/* A Connect Ack with Choke or timeout or failed routing will go to	 * closed.  */	while (sk->state == TCP_SYN_SENT) {		interruptible_sleep_on(sk->sleep);		if (signal_pending(current)) {			sti();			return -ERESTARTSYS;		}	}		if (sk->state != TCP_ESTABLISHED) {		sti();		sock->state = SS_UNCONNECTED;		return sock_error(sk);	/* Always set at this point */	}		sock->state = SS_CONNECTED;		sti();		/* At this point, IrLMP has assigned our source address */	self->saddr = irttp_get_saddr(self->tsap);	return 0;}/* * Function irda_create (sock, protocol) * *    Create IrDA socket * */static int irda_create(struct socket *sock, int protocol){	struct sock *sk;	struct irda_sock *self;	IRDA_DEBUG(2, __FUNCTION__ "()\n");		/* Check for valid socket type */	switch (sock->type) {	case SOCK_STREAM:     /* For TTP connections with SAR disabled */	case SOCK_SEQPACKET:  /* For TTP connections with SAR enabled */	case SOCK_DGRAM:      /* For TTP Unitdata or LMP Ultra transfers */		break;	default:		return -ESOCKTNOSUPPORT;	}	/* Allocate socket */	if ((sk = sk_alloc(PF_IRDA, GFP_ATOMIC, 1)) == NULL)		return -ENOMEM;		self = kmalloc(sizeof(struct irda_sock), GFP_ATOMIC);	if (self == NULL)		return -ENOMEM;	memset(self, 0, sizeof(struct irda_sock));	init_waitqueue_head(&self->query_wait);	self->sk = sk;	sk->protinfo.irda = self;	sock_init_data(sock, sk);	switch (sock->type) {	case SOCK_STREAM:		sock->ops = &irda_stream_ops;		self->max_sdu_size_rx = TTP_SAR_DISABLE;		break;	case SOCK_SEQPACKET:		sock->ops = &irda_seqpacket_ops;		self->max_sdu_size_rx = TTP_SAR_UNBOUND;		break;	case SOCK_DGRAM:		switch (protocol) {#ifdef CONFIG_IRDA_ULTRA		case IRDAPROTO_ULTRA:			sock->ops = &irda_ultra_ops;			break;#endif /* CONFIG_IRDA_ULTRA */		case IRDAPROTO_UNITDATA:			sock->ops = &irda_dgram_ops;			/* We let Unitdata conn. be like seqpack conn. */			self->max_sdu_size_rx = TTP_SAR_UNBOUND;			break;		default:			ERROR(__FUNCTION__ "(), protocol not supported!\n");			return -ESOCKTNOSUPPORT;		}		break;	default:		return -ESOCKTNOSUPPORT;	}			sk->protocol = protocol;	/* Register as a client with IrLMP */	self->ckey = irlmp_register_client(0, NULL, NULL, NULL);	self->mask = 0xffff;	self->rx_flow = self->tx_flow = FLOW_START;	self->nslots = DISCOVERY_DEFAULT_SLOTS;	self->daddr = DEV_ADDR_ANY;	/* Until we get connected */	self->saddr = 0x0;		/* so IrLMP assign us any link */	MOD_INC_USE_COUNT;	return 0;}/* * Function irda_destroy_socket (self) * *    Destroy socket * */void irda_destroy_socket(struct irda_sock *self){	IRDA_DEBUG(2, __FUNCTION__ "()\n");	ASSERT(self != NULL, return;);	/* Unregister with IrLMP */	irlmp_unregister_client(self->ckey);	irlmp_unregister_service(self->skey);	/* Unregister with LM-IAS */	if (self->ias_obj) {		irias_delete_object(self->ias_obj);		self->ias_obj = NULL;	}	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;	}#ifdef CONFIG_IRDA_ULTRA	if (self->lsap) {		irlmp_close_lsap(self->lsap);		self->lsap = NULL;	}#endif /* CONFIG_IRDA_ULTRA */	kfree(self);	MOD_DEC_USE_COUNT;		return;}/* * Function irda_release (sock) * *     * */static int irda_release(struct socket *sock){	struct sock *sk = sock->sk;		IRDA_DEBUG(2, __FUNCTION__ "()\n");        if (sk == NULL) 		return 0;		sk->state       = TCP_CLOSE;	sk->shutdown   |= SEND_SHUTDOWN;	sk->state_change(sk);	sk->dead        = 1;	irda_destroy_socket(sk->protinfo.irda);        sock->sk   = NULL;              sk->socket = NULL;      /* Not used, but we should do this. */        return 0;}/* * Function irda_sendmsg (sock, msg, len, scm) * *    Send message down to TinyTP. This function is used for both STREAM and *    SEQPACK services. This is possible since it forces the client to  *    fragment the message if necessary */static int irda_sendmsg(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);	/* Note : socket.c set MSG_EOR on SEQPACKET sockets */	if (msg->msg_flags & ~(MSG_DONTWAIT | MSG_EOR))		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 if IrTTP is wants us to slow down */	while (self->tx_flow == FLOW_STOP) {		IRDA_DEBUG(2, __FUNCTION__ "(), IrTTP is busy, going to sleep!\n");		interruptible_sleep_on(sk->sleep);				/* Check if we are still connected */		if (sk->state != TCP_ESTABLISHED)			return -ENOTCONN;	}	/* Check that we don't send out to big frames */	if (len > self->max_data_size) {		IRDA_DEBUG(2, __FUNCTION__ 			   "(), 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);		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_data_request(self->tsap, skb);	if (err) {		IRDA_DEBUG(0, __FUNCTION__ "(), err=%d\n", err);		return err;	}	/* Tell client how much data we actually sent */	return len;}/* * Function irda_recvmsg_dgram (sock, msg, size, flags, scm) * *    Try to receive message and copy it to user. The frame is discarded *    after being read, regardless of how much the user actually read */static int irda_recvmsg_dgram(struct socket *sock, struct msghdr *msg, 			      int size, int flags, struct scm_cookie *scm){	struct irda_sock *self;	struct sock *sk = sock->sk;	struct sk_buff *skb;	int copied, err;	IRDA_DEBUG(4, __FUNCTION__ "()\n");	self = sk->protinfo.irda;	ASSERT(self != NULL, return -1;);	skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT, 				flags & MSG_DONTWAIT, &err);	if (!skb)		return err;	skb->h.raw = skb->data;	copied     = skb->len;		if (copied > size) {		IRDA_DEBUG(2, __FUNCTION__ 			   "(), Received truncated frame (%d < %d)!\n",			   copied, size);		copied = size;		msg->msg_flags |= MSG_TRUNC;	}	skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);	skb_free_datagram(sk, skb);	/*	 *  Check if we have previously stopped IrTTP and we know	 *  have more free space in our rx_queue. If so tell IrTTP	 *  to start delivering frames again before our rx_queue gets	 *  empty	 */	if (self->rx_flow == FLOW_STOP) {		if ((atomic_read(&sk->rmem_alloc) << 2) <= sk->rcvbuf) {			IRDA_DEBUG(2, __FUNCTION__ "(), Starting IrTTP\n");			self->rx_flow = FLOW_START;			irttp_flow_request(self->tsap, FLOW_START);		}	}	return copied;}/* * Function irda_data_wait (sk) * *    Sleep until data has arrive. But check for races.. * */static void irda_data_wait(struct sock *sk){	if (!skb_peek(&sk->receive_queue)) {		set_bit(SOCK_ASYNC_WAITDATA, &sk->socket->flags);		interruptible_sleep_on(sk->sleep);		clear_bit(SOCK_ASYNC_WAITDATA, &sk->socket->flags);	}}/* * Function irda_recvmsg_stream (sock, msg, size, flags, scm) * *     * */static int irda_recvmsg_stream(struct socket *sock, struct msghdr *msg, 			       int size, int flags, struct scm_cookie *scm){	struct irda_sock *self;	struct sock *sk = sock->sk;	int noblock = flags & MSG_DONTWAIT;	int copied = 0;	int target = 1;	IRDA_DEBUG(3, __FUNCTION__ "()\n");	self = sk->protinfo.irda;	ASSERT(self != NULL, return -1;);	if (sock->flags & __SO_ACCEPTCON) 		return(-EINVAL);	if (flags & MSG_OOB)		return -EOPNOTSUPP;	if (flags & MSG_WAITALL)		target = size;			msg->msg_namelen = 0;	do {		int chunk;		struct sk_buff *skb;		skb=skb_dequeue(&sk->receive_queue);		if (skb==NULL) {			if (copied >= target)				break;						/*			 *	POSIX 1003.1g mandates this order.			 */						if (sk->err) {				return sock_error(sk);			}			if (sk->shutdown & RCV_SHUTDOWN)				break;			if (noblock)				return -EAGAIN;			irda_data_wait(sk);			if (signal_pending(current))				return -ERESTARTSYS;			continue;		}		chunk = min(skb->len, size);		if (memcpy_toiovec(msg->msg_iov, skb->data, chunk)) {			skb_queue_head(&sk->receive_queue, skb);			if (copied == 0)				copied = -EFAULT;			break;		}		copied += chunk;		size -= chunk;		/* Mark read part of skb as used */		if (!(flags & MSG_PEEK)) {			skb_pull(skb, chunk);			/* put the skb back if we didn't use it up.. */			if (skb->len) {				IRDA_DEBUG(1, __FUNCTION__ "(), back on q!\n");				skb_queue_head(&sk->receive_queue, skb);				break;			}			kfree_skb(skb);					} else {			IRDA_DEBUG(0, __FUNCTION__ "() questionable!?\n");			/* put message back and return */			skb_queue_head(&sk->receive_queue, skb);			break;		}	} while (size);	/*	 *  Check if we have previously stopped IrTTP and we know	 *  have more free space in our rx_queue. If so tell IrTTP	 *  to start delivering frames again before our rx_queue gets	 *  empty	 */	if (self->rx_flow == FLOW_STOP) {		if ((atomic_read(&sk->rmem_alloc) << 2) <= sk->rcvbuf) {			IRDA_DEBUG(2, __FUNCTION__ "(), Starting IrTTP\n");			self->rx_flow = FLOW_START;			irttp_flow_request(self->tsap, FLOW_START);		}	}	return copied;}/* * Function irda_sendmsg_dgram (sock, msg, len, scm) * *    Send message down to TinyTP for the unreliable sequenced *    packet service...

⌨️ 快捷键说明

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