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

📄 af_irda.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 5 页
字号:
	if (sk->sk_state == TCP_CLOSE && sock->state == SS_CONNECTING) {		sock->state = SS_UNCONNECTED;		return -ECONNREFUSED;	}	if (sk->sk_state == TCP_ESTABLISHED)		return -EISCONN;      /* No reconnect on a seqpacket socket */	sk->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, "%s(), auto-connect failed!\n", __FUNCTION__);			return err;		}	} else {		/* Use the one provided by the user */		self->daddr = addr->sir_addr;		IRDA_DEBUG(1, "%s(), daddr = %08x\n", __FUNCTION__, self->daddr);		/* Query remote LM-IAS */		err = irda_find_lsap_sel(self, addr->sir_name);		if (err) {			IRDA_DEBUG(0, "%s(), connect failed!\n", __FUNCTION__);			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->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, "%s(), connect failed!\n", __FUNCTION__);		return err;	}	/* Now the loop */	if (sk->sk_state != TCP_ESTABLISHED && (flags & O_NONBLOCK))		return -EINPROGRESS;	if (wait_event_interruptible(*(sk->sk_sleep),				     (sk->sk_state != TCP_SYN_SENT)))		return -ERESTARTSYS;	if (sk->sk_state != TCP_ESTABLISHED) {		sock->state = SS_UNCONNECTED;		return sock_error(sk);	/* Always set at this point */	}	sock->state = SS_CONNECTED;	/* 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, "%s()\n", __FUNCTION__);	/* 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)) == NULL)		return -ENOMEM;	/* Allocate IrDA socket */	self = sk->sk_protinfo = 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, "%s() : self is %p\n", __FUNCTION__, self);	init_waitqueue_head(&self->query_wait);	/* Initialise networking socket struct */	sock_init_data(sock, sk);	/* Note : set sk->sk_refcnt to 1 */	sk_set_owner(sk, THIS_MODULE);	sk->sk_family = PF_IRDA;	sk->sk_protocol = protocol;	/* Link networking socket and IrDA socket structs together */	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;			/* Initialise now, because we may send on unbound			 * sockets. Jean II */			self->max_data_size = ULTRA_MAX_DATA - LMP_PID_HEADER;			self->max_header_size = IRDA_MAX_HEADER + LMP_PID_HEADER;			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("%s: protocol not supported!\n", __FUNCTION__);			return -ESOCKTNOSUPPORT;		}		break;	default:		return -ESOCKTNOSUPPORT;	}	/* Register as a client with IrLMP */	self->ckey = irlmp_register_client(0, NULL, NULL, NULL);	self->mask.word = 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 */	return 0;}/* * Function irda_destroy_socket (self) * *    Destroy socket * */void irda_destroy_socket(struct irda_sock *self){	IRDA_DEBUG(2, "%s(%p)\n", __FUNCTION__, 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);}/* * Function irda_release (sock) */static int irda_release(struct socket *sock){	struct sock *sk = sock->sk;	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);        if (sk == NULL)		return 0;	sk->sk_state       = TCP_CLOSE;	sk->sk_shutdown   |= SEND_SHUTDOWN;	sk->sk_state_change(sk);	/* Destroy IrDA socket */	irda_destroy_socket(irda_sk(sk));	/* Prevent sock_def_destruct() to create havoc */	sk->sk_protinfo = NULL;	sock_orphan(sk);	sock->sk   = NULL;	/* Purge queues (see sock_init_data()) */	skb_queue_purge(&sk->sk_receive_queue);	/* Destroy networking socket if we are the last reference on it,	 * i.e. if(sk->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 incoming 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 (iocb, sock, msg, len) * *    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 kiocb *iocb, struct socket *sock,			struct msghdr *msg, size_t len){	struct sock *sk = sock->sk;	struct irda_sock *self;	struct sk_buff *skb;	unsigned char *asmptr;	int err;	IRDA_DEBUG(4, "%s(), len=%zd\n", __FUNCTION__, len);	/* Note : socket.c set MSG_EOR on SEQPACKET sockets */	if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_EOR|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);	ASSERT(self != NULL, return -1;);	/* Check if IrTTP is wants us to slow down */	if (wait_event_interruptible(*(sk->sk_sleep),	    (self->tx_flow != FLOW_STOP  ||  sk->sk_state != TCP_ESTABLISHED)))		return -ERESTARTSYS;	/* Check if we are still connected */	if (sk->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, "%s(), 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 + 16, 				  msg->msg_flags & MSG_DONTWAIT, &err);	if (!skb)		return -ENOBUFS;	skb_reserve(skb, self->max_header_size + 16);	asmptr = skb->h.raw = skb_put(skb, len);	err = memcpy_fromiovec(asmptr, 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_data_request(self->tsap, skb);	if (err) {		IRDA_DEBUG(0, "%s(), err=%d\n", __FUNCTION__, err);		return err;	}	/* Tell client how much data we actually sent */	return len;}/* * Function irda_recvmsg_dgram (iocb, sock, msg, size, flags) * *    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 kiocb *iocb, struct socket *sock,			      struct msghdr *msg, size_t size, int flags){	struct sock *sk = sock->sk;	struct irda_sock *self = irda_sk(sk);	struct sk_buff *skb;	size_t copied;	int err;	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);	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, "%s(), Received truncated frame (%zd < %zd)!\n",			   __FUNCTION__, 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->sk_rmem_alloc) << 2) <= sk->sk_rcvbuf) {			IRDA_DEBUG(2, "%s(), Starting IrTTP\n", __FUNCTION__);			self->rx_flow = FLOW_START;			irttp_flow_request(self->tsap, FLOW_START);		}	}	return copied;}/* * Function irda_recvmsg_stream (iocb, sock, msg, size, flags) */static int irda_recvmsg_stream(struct kiocb *iocb, struct socket *sock,			       struct msghdr *msg, size_t size, int flags){	struct sock *sk = sock->sk;	struct irda_sock *self = irda_sk(sk);	int noblock = flags & MSG_DONTWAIT;	size_t copied = 0;	int target = 1;	DECLARE_WAITQUEUE(waitq, current);	IRDA_DEBUG(3, "%s()\n", __FUNCTION__);	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_dequeue(&sk->sk_receive_queue);		if (skb==NULL) {			int ret = 0;			if (copied >= target)				break;			/* The following code is a cut'n'paste of the			 * wait_event_interruptible() macro.			 * We don't us the macro because the test condition			 * is messy. - Jean II */			set_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);			add_wait_queue(sk->sk_sleep, &waitq);			set_current_state(TASK_INTERRUPTIBLE);			/*			 *	POSIX 1003.1g mandates this order.			 */			if (sk->sk_err)				ret = sock_error(sk);			else if (sk->sk_shutdown & RCV_SHUTDOWN)				;			else if (noblock)				ret = -EAGAIN;			else if (signal_pending(current))				ret = -ERESTARTSYS;			else if (skb_peek(&sk->sk_receive_queue) == NULL)				/* Wait process until data arrives */				schedule();			current->state = TASK_RUNNING;			remove_wait_queue(sk->sk_sleep, &waitq);			clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);			if(ret)				return(ret);			if (sk->sk_shutdown & RCV_SHUTDOWN)				break;			continue;		}		chunk = min_t(unsigned int, skb->len, size);		if (memcpy_toiovec(msg->msg_iov, skb->data, chunk)) {			skb_queue_head(&sk->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, "%s(), back on q!\n",					   __FUNCTION__);				skb_queue_head(&sk->sk_receive_queue, skb);				break;			}			kfree_skb(skb);

⌨️ 快捷键说明

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