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

📄 af_irda.c

📁 《嵌入式系统设计与实例开发实验教材二源码》Linux内核移植与编译实验
💻 C
📖 第 1 页 / 共 5 页
字号:
	/* 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 networking socket */	if ((sk = sk_alloc(PF_IRDA, GFP_ATOMIC, 1)) == NULL)		return -ENOMEM;	/* Allocate IrDA socket */	self = kmalloc(sizeof(struct irda_sock), GFP_ATOMIC);	if (self == NULL) {		sk_free(sk);		return -ENOMEM;	}	memset(self, 0, sizeof(struct irda_sock));	IRDA_DEBUG(2, __FUNCTION__ "() : self is %p\n", self);	init_waitqueue_head(&self->query_wait);	/* Initialise networking socket struct */ 	sock_init_data(sock, sk);	/* Note : set sk->refcnt to 1 */	sk->family = PF_IRDA;	sk->protocol = protocol;	/* Link networking socket and IrDA socket structs together */	sk->protinfo.irda = self;	self->sk = 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;	}			/* 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__ "(%p)\n", self);	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);	/* Destroy IrDA socket */	irda_destroy_socket(sk->protinfo.irda);	/* Prevent sock_def_destruct() to create havoc */	sk->protinfo.irda = NULL;	sock_orphan(sk);	sock->sk   = NULL;      	/* Purge queues (see sock_init_data()) */	skb_queue_purge(&sk->receive_queue);	/* Destroy networking socket if we are the last reference on it,	 * i.e. if(sk->refcnt == 0) -> sk_free(sk) */	sock_put(sk);	/* Notes on socket locking and deallocation... - Jean II	 * In theory we should put pairs of sock_hold() / sock_put() to	 * prevent the socket to be destroyed whenever there is an	 * outstanding request or outstanding incomming packet or event.	 *	 * 1) This may include IAS request, both in connect and getsockopt.	 * Unfortunately, the situation is a bit more messy than it looks,	 * because we close iriap and kfree(self) above.	 * 	 * 2) This may include selective discovery in getsockopt.	 * Same stuff as above, irlmp registration and self are gone.	 *	 * Probably 1 and 2 may not matter, because it's all triggered	 * by a process and the socket layer already prevent the	 * socket to go away while a process is holding it, through	 * sockfd_put() and fput()...	 *	 * 3) This may include deferred TSAP closure. In particular,	 * we may receive a late irda_disconnect_indication()	 * Fortunately, (tsap_cb *)->close_pend should protect us	 * from that.	 *	 * I did some testing on SMP, and it looks solid. And the socket	 * memory leak is now gone... - Jean II	 */        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, 				  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_t(unsigned int, 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 + -