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

📄 af_irda.c

📁 Linux内核源代码 为压缩文件 是<<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 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/config.h>#include <linux/module.h>#include <linux/types.h>#include <linux/socket.h>#include <linux/sockios.h>#include <linux/init.h>#include <linux/if_arp.h>#include <linux/net.h>#include <linux/irda.h>#include <linux/poll.h>#include <asm/uaccess.h>#include <net/sock.h>#include <net/irda/irda.h>#include <net/irda/iriap.h>#include <net/irda/irias_object.h>#include <net/irda/irlmp.h>#include <net/irda/irttp.h>#include <net/irda/discovery.h>extern int  irda_init(void);extern void irda_cleanup(void);extern int  irlap_driver_rcv(struct sk_buff *, struct net_device *, 			     struct packet_type *);static int irda_create(struct socket *sock, int protocol);static struct proto_ops irda_stream_ops;static struct proto_ops irda_seqpacket_ops;static struct proto_ops irda_dgram_ops;#ifdef CONFIG_IRDA_ULTRAstatic struct proto_ops irda_ultra_ops;#define ULTRA_MAX_DATA 382#endif /* CONFIG_IRDA_ULTRA */#define IRDA_MAX_HEADER (TTP_MAX_HEADER)#ifdef CONFIG_IRDA_DEBUG__u32 irda_debug = IRDA_DEBUG_LEVEL;#endif/* * 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;	self = (struct irda_sock *) instance;	ASSERT(self != NULL, return -1;);	sk = self->sk;	ASSERT(sk != NULL, return -1;);	err = sock_queue_rcv_skb(sk, skb);	if (err) {		IRDA_DEBUG(1, __FUNCTION__ "(), error: no more mem!\n");		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;	IRDA_DEBUG(2, __FUNCTION__ "()\n");	self = (struct irda_sock *) instance;	sk = self->sk;	if (sk == NULL)		return;	sk->state     = TCP_CLOSE;        sk->err       = ECONNRESET;        sk->shutdown |= SEND_SHUTDOWN;	if (!sk->dead) {		sk->state_change(sk);                sk->dead = 1;        }	/* Close our TSAP.	 * If we leave it open, IrLMP put it back into the list of	 * unconnected LSAPs. The problem is that any incomming 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->state, so we are safe...	 * Jean II	 */	irttp_close_tsap(self->tsap);	self->tsap = NULL;	/* 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->err,	 * sk->shutdown and sk->dead 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;	IRDA_DEBUG(2, __FUNCTION__ "()\n");	self = (struct irda_sock *) instance;	sk = self->sk;	if (sk == NULL)		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->type) {	case SOCK_STREAM:		if (max_sdu_size != 0) {			ERROR(__FUNCTION__ "(), max_sdu_size must be 0\n");			return;		}		self->max_data_size = irttp_get_max_seg_size(self->tsap);		break;	case SOCK_SEQPACKET:		if (max_sdu_size == 0) {			ERROR(__FUNCTION__ "(), max_sdu_size cannot be 0\n");			return;		}		self->max_data_size = max_sdu_size;		break;	default:		self->max_data_size = irttp_get_max_seg_size(self->tsap);	};	IRDA_DEBUG(2, __FUNCTION__ "(), max_data_size=%d\n", 		   self->max_data_size);	memcpy(&self->qos_tx, qos, sizeof(struct qos_info));	skb_queue_tail(&sk->receive_queue, skb);	/* We are now connected! */	sk->state = TCP_ESTABLISHED;	sk->state_change(sk);}/* * Function irda_connect_indication(instance, sap, qos, max_sdu_size, userdata) * *    Incomming 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;	IRDA_DEBUG(2, __FUNCTION__ "()\n"); 	self = (struct irda_sock *) instance;	sk = self->sk;	if (sk == NULL)		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->type) {	case SOCK_STREAM:		if (max_sdu_size != 0) {			ERROR(__FUNCTION__ "(), max_sdu_size must be 0\n");			return;		}		self->max_data_size = irttp_get_max_seg_size(self->tsap);		break;	case SOCK_SEQPACKET:		if (max_sdu_size == 0) {			ERROR(__FUNCTION__ "(), max_sdu_size cannot be 0\n");			return;		}		self->max_data_size = max_sdu_size;		break;	default:		self->max_data_size = irttp_get_max_seg_size(self->tsap);	};	IRDA_DEBUG(2, __FUNCTION__ "(), max_data_size=%d\n", 		   self->max_data_size);	memcpy(&self->qos_tx, qos, sizeof(struct qos_info));		skb_queue_tail(&sk->receive_queue, skb);	sk->state_change(sk);}/* * Function irda_connect_response (handle) * *    Accept incomming connection * */void irda_connect_response(struct irda_sock *self){	struct sk_buff *skb;	IRDA_DEBUG(2, __FUNCTION__ "()\n");	ASSERT(self != NULL, return;);	skb = dev_alloc_skb(64);	if (skb == NULL) {		IRDA_DEBUG(0, __FUNCTION__ "() Unable to allocate sk_buff!\n");		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, __FUNCTION__ "()\n");		self = (struct irda_sock *) instance;	ASSERT(self != NULL, return;);	sk = self->sk;	ASSERT(sk != NULL, return;);		switch (flow) {	case FLOW_STOP:		IRDA_DEBUG(1, __FUNCTION__ "(), IrTTP wants us to slow down\n");		self->tx_flow = flow;		break;	case FLOW_START:		self->tx_flow = flow;		IRDA_DEBUG(1, __FUNCTION__ 			   "(), IrTTP wants us to start again\n");		wake_up_interruptible(sk->sleep);		break;	default:		IRDA_DEBUG( 0, __FUNCTION__ "(), Unknown flow command!\n");		/* 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;		IRDA_DEBUG(2, __FUNCTION__ "()\n");	self = (struct irda_sock *) priv;	if (!self) {		WARNING(__FUNCTION__ "(), lost myself!\n");		return;	}	/* 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, __FUNCTION__ "(), IAS query failed! (%d)\n",			   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 matching our hint bit * filter. Check if it's a newly discovered node (or if node changed its * hint bits), and then wake up any process waiting for answer... */static void irda_selective_discovery_indication(discovery_t *discovery,						void *priv){	struct irda_sock *self;		IRDA_DEBUG(2, __FUNCTION__ "()\n");	self = (struct irda_sock *) priv;	if (!self) {		WARNING(__FUNCTION__ "(), lost myself!\n");		return;	}	/* Check if node is discovered is a new one or an old one.	 * We check when how long ago this node was discovered, with a	 * coarse timeout (we may miss some discovery events or be delayed).	 * Note : by doing this test here, we avoid waking up a process ;-)	 */	if((jiffies - discovery->first_timestamp) >	   (sysctl_discovery_timeout * HZ)) {		return;		/* Too old, not interesting -> goodbye */	}	/* Pass parameter to the caller */	self->cachediscovery = discovery;	/* 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, __FUNCTION__ "()\n");	self = (struct irda_sock *) priv;	ASSERT(self != NULL, return;);	/* Nothing for the caller */	self->cachelog = NULL;	self->cachediscovery = NULL;	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) {		WARNING(__FUNCTION__ "(), busy!\n");		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) {

⌨️ 快捷键说明

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