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

📄 af_irda.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/********************************************************************* * * Filename:      af_irda.c * Version:       0.9 * Description:   IrDA sockets implementation * Status:        Stable * Author:        Dag Brattli <dagb@cs.uit.no> * Created at:    Sun May 31 10:12:43 1998 * Modified at:   Sat Dec 25 21:10:23 1999 * Modified by:   Dag Brattli <dag@brattli.net> * Sources:       af_netroom.c, af_ax25.c, af_rose.c, af_x25.c etc. * *     Copyright (c) 1999 Dag Brattli <dagb@cs.uit.no> *     Copyright (c) 1999-2003 Jean Tourrilhes <jt@hpl.hp.com> *     All Rights Reserved. * *     This program is free software; you can redistribute it and/or *     modify it under the terms of the GNU General Public License as *     published by the Free Software Foundation; either version 2 of *     the License, or (at your option) any later version. * *     This program is distributed in the hope that it will be useful, *     but WITHOUT ANY WARRANTY; without even the implied warranty of *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *     GNU General Public License for more details. * *     You should have received a copy of the GNU General Public License *     along with this program; if not, write to the Free Software *     Foundation, Inc., 59 Temple Place, Suite 330, Boston, *     MA 02111-1307 USA * *     Linux-IrDA now supports four different types of IrDA sockets: * *     o SOCK_STREAM:    TinyTP connections with SAR disabled. The *                       max SDU size is 0 for conn. of this type *     o SOCK_SEQPACKET: TinyTP connections with SAR enabled. TTP may *                       fragment the messages, but will preserve *                       the message boundaries *     o SOCK_DGRAM:     IRDAPROTO_UNITDATA: TinyTP connections with Unitdata *                       (unreliable) transfers *                       IRDAPROTO_ULTRA: Connectionless and unreliable data * ********************************************************************/#include <linux/capability.h>#include <linux/module.h>#include <linux/types.h>#include <linux/socket.h>#include <linux/sockios.h>#include <linux/init.h>#include <linux/net.h>#include <linux/irda.h>#include <linux/poll.h>#include <asm/ioctls.h>		/* TIOCOUTQ, TIOCINQ */#include <asm/uaccess.h>#include <net/sock.h>#include <net/tcp_states.h>#include <net/irda/af_irda.h>static int irda_create(struct net *net, struct socket *sock, int protocol);static const struct proto_ops irda_stream_ops;static const struct proto_ops irda_seqpacket_ops;static const struct proto_ops irda_dgram_ops;#ifdef CONFIG_IRDA_ULTRAstatic const struct proto_ops irda_ultra_ops;#define ULTRA_MAX_DATA 382#endif /* CONFIG_IRDA_ULTRA */#define IRDA_MAX_HEADER (TTP_MAX_HEADER)/* * Function irda_data_indication (instance, sap, skb) * *    Received some data from TinyTP. Just queue it on the receive queue * */static int irda_data_indication(void *instance, void *sap, struct sk_buff *skb){	struct irda_sock *self;	struct sock *sk;	int err;	IRDA_DEBUG(3, "%s()\n", __FUNCTION__);	self = instance;	sk = instance;	err = sock_queue_rcv_skb(sk, skb);	if (err) {		IRDA_DEBUG(1, "%s(), error: no more mem!\n", __FUNCTION__);		self->rx_flow = FLOW_STOP;		/* When we return error, TTP will need to requeue the skb */		return err;	}	return 0;}/* * Function irda_disconnect_indication (instance, sap, reason, skb) * *    Connection has been closed. Check reason to find out why * */static void irda_disconnect_indication(void *instance, void *sap,				       LM_REASON reason, struct sk_buff *skb){	struct irda_sock *self;	struct sock *sk;	self = instance;	IRDA_DEBUG(2, "%s(%p)\n", __FUNCTION__, self);	/* Don't care about it, but let's not leak it */	if(skb)		dev_kfree_skb(skb);	sk = instance;	if (sk == NULL) {		IRDA_DEBUG(0, "%s(%p) : BUG : sk is NULL\n",			   __FUNCTION__, self);		return;	}	/* Prevent race conditions with irda_release() and irda_shutdown() */	bh_lock_sock(sk);	if (!sock_flag(sk, SOCK_DEAD) && sk->sk_state != TCP_CLOSE) {		sk->sk_state     = TCP_CLOSE;		sk->sk_shutdown |= SEND_SHUTDOWN;		sk->sk_state_change(sk);		/* Close our TSAP.		 * If we leave it open, IrLMP put it back into the list of		 * unconnected LSAPs. The problem is that any incoming request		 * can then be matched to this socket (and it will be, because		 * it is at the head of the list). This would prevent any		 * listening socket waiting on the same TSAP to get those		 * requests. Some apps forget to close sockets, or hang to it		 * a bit too long, so we may stay in this dead state long		 * enough to be noticed...		 * Note : all socket function do check sk->sk_state, so we are		 * safe...		 * Jean II		 */		if (self->tsap) {			irttp_close_tsap(self->tsap);			self->tsap = NULL;		}	}	bh_unlock_sock(sk);	/* Note : once we are there, there is not much you want to do	 * with the socket anymore, apart from closing it.	 * For example, bind() and connect() won't reset sk->sk_err,	 * sk->sk_shutdown and sk->sk_flags to valid values...	 * Jean II	 */}/* * Function irda_connect_confirm (instance, sap, qos, max_sdu_size, skb) * *    Connections has been confirmed by the remote device * */static void irda_connect_confirm(void *instance, void *sap,				 struct qos_info *qos,				 __u32 max_sdu_size, __u8 max_header_size,				 struct sk_buff *skb){	struct irda_sock *self;	struct sock *sk;	self = instance;	IRDA_DEBUG(2, "%s(%p)\n", __FUNCTION__, self);	sk = instance;	if (sk == NULL) {		dev_kfree_skb(skb);		return;	}	dev_kfree_skb(skb);	// Should be ??? skb_queue_tail(&sk->sk_receive_queue, skb);	/* How much header space do we need to reserve */	self->max_header_size = max_header_size;	/* IrTTP max SDU size in transmit direction */	self->max_sdu_size_tx = max_sdu_size;	/* Find out what the largest chunk of data that we can transmit is */	switch (sk->sk_type) {	case SOCK_STREAM:		if (max_sdu_size != 0) {			IRDA_ERROR("%s: max_sdu_size must be 0\n",				   __FUNCTION__);			return;		}		self->max_data_size = irttp_get_max_seg_size(self->tsap);		break;	case SOCK_SEQPACKET:		if (max_sdu_size == 0) {			IRDA_ERROR("%s: max_sdu_size cannot be 0\n",				   __FUNCTION__);			return;		}		self->max_data_size = max_sdu_size;		break;	default:		self->max_data_size = irttp_get_max_seg_size(self->tsap);	}	IRDA_DEBUG(2, "%s(), max_data_size=%d\n", __FUNCTION__,		   self->max_data_size);	memcpy(&self->qos_tx, qos, sizeof(struct qos_info));	/* We are now connected! */	sk->sk_state = TCP_ESTABLISHED;	sk->sk_state_change(sk);}/* * Function irda_connect_indication(instance, sap, qos, max_sdu_size, userdata) * *    Incoming connection * */static void irda_connect_indication(void *instance, void *sap,				    struct qos_info *qos, __u32 max_sdu_size,				    __u8 max_header_size, struct sk_buff *skb){	struct irda_sock *self;	struct sock *sk;	self = instance;	IRDA_DEBUG(2, "%s(%p)\n", __FUNCTION__, self);	sk = instance;	if (sk == NULL) {		dev_kfree_skb(skb);		return;	}	/* How much header space do we need to reserve */	self->max_header_size = max_header_size;	/* IrTTP max SDU size in transmit direction */	self->max_sdu_size_tx = max_sdu_size;	/* Find out what the largest chunk of data that we can transmit is */	switch (sk->sk_type) {	case SOCK_STREAM:		if (max_sdu_size != 0) {			IRDA_ERROR("%s: max_sdu_size must be 0\n",				   __FUNCTION__);			kfree_skb(skb);			return;		}		self->max_data_size = irttp_get_max_seg_size(self->tsap);		break;	case SOCK_SEQPACKET:		if (max_sdu_size == 0) {			IRDA_ERROR("%s: max_sdu_size cannot be 0\n",				   __FUNCTION__);			kfree_skb(skb);			return;		}		self->max_data_size = max_sdu_size;		break;	default:		self->max_data_size = irttp_get_max_seg_size(self->tsap);	}	IRDA_DEBUG(2, "%s(), max_data_size=%d\n", __FUNCTION__,		   self->max_data_size);	memcpy(&self->qos_tx, qos, sizeof(struct qos_info));	skb_queue_tail(&sk->sk_receive_queue, skb);	sk->sk_state_change(sk);}/* * Function irda_connect_response (handle) * *    Accept incoming connection * */static void irda_connect_response(struct irda_sock *self){	struct sk_buff *skb;	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);	skb = alloc_skb(TTP_MAX_HEADER + TTP_SAR_HEADER,			GFP_ATOMIC);	if (skb == NULL) {		IRDA_DEBUG(0, "%s() Unable to allocate sk_buff!\n",			   __FUNCTION__);		return;	}	/* Reserve space for MUX_CONTROL and LAP header */	skb_reserve(skb, IRDA_MAX_HEADER);	irttp_connect_response(self->tsap, self->max_sdu_size_rx, skb);}/* * Function irda_flow_indication (instance, sap, flow) * *    Used by TinyTP to tell us if it can accept more data or not * */static void irda_flow_indication(void *instance, void *sap, LOCAL_FLOW flow){	struct irda_sock *self;	struct sock *sk;	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);	self = instance;	sk = instance;	BUG_ON(sk == NULL);	switch (flow) {	case FLOW_STOP:		IRDA_DEBUG(1, "%s(), IrTTP wants us to slow down\n",			   __FUNCTION__);		self->tx_flow = flow;		break;	case FLOW_START:		self->tx_flow = flow;		IRDA_DEBUG(1, "%s(), IrTTP wants us to start again\n",			   __FUNCTION__);		wake_up_interruptible(sk->sk_sleep);		break;	default:		IRDA_DEBUG(0, "%s(), Unknown flow command!\n", __FUNCTION__);		/* Unknown flow command, better stop */		self->tx_flow = flow;		break;	}}/* * Function irda_getvalue_confirm (obj_id, value, priv) * *    Got answer from remote LM-IAS, just pass object to requester... * * Note : duplicate from above, but we need our own version that * doesn't touch the dtsap_sel and save the full value structure... */static void irda_getvalue_confirm(int result, __u16 obj_id,				  struct ias_value *value, void *priv){	struct irda_sock *self;	self = (struct irda_sock *) priv;	if (!self) {		IRDA_WARNING("%s: lost myself!\n", __FUNCTION__);		return;	}	IRDA_DEBUG(2, "%s(%p)\n", __FUNCTION__, self);	/* We probably don't need to make any more queries */	iriap_close(self->iriap);	self->iriap = NULL;	/* Check if request succeeded */	if (result != IAS_SUCCESS) {		IRDA_DEBUG(1, "%s(), IAS query failed! (%d)\n", __FUNCTION__,			   result);		self->errno = result;	/* We really need it later */		/* Wake up any processes waiting for result */		wake_up_interruptible(&self->query_wait);		return;	}	/* Pass the object to the caller (so the caller must delete it) */	self->ias_result = value;	self->errno = 0;	/* Wake up any processes waiting for result */	wake_up_interruptible(&self->query_wait);}/* * Function irda_selective_discovery_indication (discovery) * *    Got a selective discovery indication from IrLMP. * * IrLMP is telling us that this node is new and matching our hint bit * filter. Wake up any process waiting for answer... */static void irda_selective_discovery_indication(discinfo_t *discovery,						DISCOVERY_MODE mode,						void *priv){	struct irda_sock *self;	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);	self = (struct irda_sock *) priv;	if (!self) {		IRDA_WARNING("%s: lost myself!\n", __FUNCTION__);		return;	}	/* Pass parameter to the caller */	self->cachedaddr = discovery->daddr;	/* Wake up process if its waiting for device to be discovered */	wake_up_interruptible(&self->query_wait);}/* * Function irda_discovery_timeout (priv) * *    Timeout in the selective discovery process * * We were waiting for a node to be discovered, but nothing has come up * so far. Wake up the user and tell him that we failed... */static void irda_discovery_timeout(u_long priv){	struct irda_sock *self;	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);	self = (struct irda_sock *) priv;	BUG_ON(self == NULL);	/* Nothing for the caller */	self->cachelog = NULL;	self->cachedaddr = 0;	self->errno = -ETIME;	/* Wake up process if its still waiting... */	wake_up_interruptible(&self->query_wait);}/* * Function irda_open_tsap (self) * *    Open local Transport Service Access Point (TSAP) * */static int irda_open_tsap(struct irda_sock *self, __u8 tsap_sel, char *name){	notify_t notify;	if (self->tsap) {		IRDA_WARNING("%s: busy!\n", __FUNCTION__);		return -EBUSY;	}	/* Initialize callbacks to be used by the IrDA stack */	irda_notify_init(&notify);	notify.connect_confirm       = irda_connect_confirm;	notify.connect_indication    = irda_connect_indication;	notify.disconnect_indication = irda_disconnect_indication;	notify.data_indication       = irda_data_indication;	notify.udata_indication	     = irda_data_indication;	notify.flow_indication       = irda_flow_indication;	notify.instance = self;	strncpy(notify.name, name, NOTIFY_MAX_NAME);	self->tsap = irttp_open_tsap(tsap_sel, DEFAULT_INITIAL_CREDIT,				     &notify);	if (self->tsap == NULL) {		IRDA_DEBUG(0, "%s(), Unable to allocate TSAP!\n",			   __FUNCTION__);		return -ENOMEM;	}	/* Remember which TSAP selector we actually got */	self->stsap_sel = self->tsap->stsap_sel;	return 0;}

⌨️ 快捷键说明

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