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

📄 af_irda.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * Function irda_open_lsap (self) * *    Open local Link Service Access Point (LSAP). Used for opening Ultra *    sockets */#ifdef CONFIG_IRDA_ULTRAstatic int irda_open_lsap(struct irda_sock *self, int pid){	notify_t notify;	if (self->lsap) {		IRDA_WARNING("%s(), busy!\n", __FUNCTION__);		return -EBUSY;	}	/* Initialize callbacks to be used by the IrDA stack */	irda_notify_init(&notify);	notify.udata_indication	= irda_data_indication;	notify.instance = self;	strncpy(notify.name, "Ultra", NOTIFY_MAX_NAME);	self->lsap = irlmp_open_lsap(LSAP_CONNLESS, &notify, pid);	if (self->lsap == NULL) {		IRDA_DEBUG( 0, "%s(), Unable to allocate LSAP!\n", __FUNCTION__);		return -ENOMEM;	}	return 0;}#endif /* CONFIG_IRDA_ULTRA *//* * Function irda_find_lsap_sel (self, name) * *    Try to lookup LSAP selector in remote LM-IAS * * Basically, we start a IAP query, and then go to sleep. When the query * return, irda_getvalue_confirm will wake us up, and we can examine the * result of the query... * Note that in some case, the query fail even before we go to sleep, * creating some races... */static int irda_find_lsap_sel(struct irda_sock *self, char *name){	IRDA_DEBUG(2, "%s(%p, %s)\n", __FUNCTION__, self, name);	if (self->iriap) {		IRDA_WARNING("%s(): busy with a previous query\n",			     __FUNCTION__);		return -EBUSY;	}	self->iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self,				 irda_getvalue_confirm);	if(self->iriap == NULL)		return -ENOMEM;	/* Treat unexpected wakeup as disconnect */	self->errno = -EHOSTUNREACH;	/* Query remote LM-IAS */	iriap_getvaluebyclass_request(self->iriap, self->saddr, self->daddr,				      name, "IrDA:TinyTP:LsapSel");	/* Wait for answer, if not yet finished (or failed) */	if (wait_event_interruptible(self->query_wait, (self->iriap==NULL)))		/* Treat signals as disconnect */		return -EHOSTUNREACH;	/* Check what happened */	if (self->errno)	{		/* Requested object/attribute doesn't exist */		if((self->errno == IAS_CLASS_UNKNOWN) ||		   (self->errno == IAS_ATTRIB_UNKNOWN))			return (-EADDRNOTAVAIL);		else			return (-EHOSTUNREACH);	}	/* Get the remote TSAP selector */	switch (self->ias_result->type) {	case IAS_INTEGER:		IRDA_DEBUG(4, "%s() int=%d\n",			   __FUNCTION__, self->ias_result->t.integer);		if (self->ias_result->t.integer != -1)			self->dtsap_sel = self->ias_result->t.integer;		else			self->dtsap_sel = 0;		break;	default:		self->dtsap_sel = 0;		IRDA_DEBUG(0, "%s(), bad type!\n", __FUNCTION__);		break;	}	if (self->ias_result)		irias_delete_value(self->ias_result);	if (self->dtsap_sel)		return 0;	return -EADDRNOTAVAIL;}/* * Function irda_discover_daddr_and_lsap_sel (self, name) * *    This try to find a device with the requested service. * * It basically look into the discovery log. For each address in the list, * it queries the LM-IAS of the device to find if this device offer * the requested service. * If there is more than one node supporting the service, we complain * to the user (it should move devices around). * The, we set both the destination address and the lsap selector to point * on the service on the unique device we have found. * * Note : this function fails if there is more than one device in range, * because IrLMP doesn't disconnect the LAP when the last LSAP is closed. * Moreover, we would need to wait the LAP disconnection... */static int irda_discover_daddr_and_lsap_sel(struct irda_sock *self, char *name){	discinfo_t *discoveries;	/* Copy of the discovery log */	int	number;			/* Number of nodes in the log */	int	i;	int	err = -ENETUNREACH;	__u32	daddr = DEV_ADDR_ANY;	/* Address we found the service on */	__u8	dtsap_sel = 0x0;	/* TSAP associated with it */	IRDA_DEBUG(2, "%s(), name=%s\n", __FUNCTION__, name);	/* Ask lmp for the current discovery log	 * Note : we have to use irlmp_get_discoveries(), as opposed	 * to play with the cachelog directly, because while we are	 * making our ias query, le log might change... */	discoveries = irlmp_get_discoveries(&number, self->mask.word,					    self->nslots);	/* Check if the we got some results */	if (discoveries == NULL)		return -ENETUNREACH;	/* No nodes discovered */	/*	 * Now, check all discovered devices (if any), and connect	 * client only about the services that the client is	 * interested in...	 */	for(i = 0; i < number; i++) {		/* Try the address in the log */		self->daddr = discoveries[i].daddr;		self->saddr = 0x0;		IRDA_DEBUG(1, "%s(), trying daddr = %08x\n",			   __FUNCTION__, self->daddr);		/* Query remote LM-IAS for this service */		err = irda_find_lsap_sel(self, name);		switch (err) {		case 0:			/* We found the requested service */			if(daddr != DEV_ADDR_ANY) {				IRDA_DEBUG(1, "%s(), discovered service ''%s'' in two different devices !!!\n",					   __FUNCTION__, name);				self->daddr = DEV_ADDR_ANY;				kfree(discoveries);				return(-ENOTUNIQ);			}			/* First time we found that one, save it ! */			daddr = self->daddr;			dtsap_sel = self->dtsap_sel;			break;		case -EADDRNOTAVAIL:			/* Requested service simply doesn't exist on this node */			break;		default:			/* Something bad did happen :-( */			IRDA_DEBUG(0, "%s(), unexpected IAS query failure\n", __FUNCTION__);			self->daddr = DEV_ADDR_ANY;			kfree(discoveries);			return(-EHOSTUNREACH);			break;		}	}	/* Cleanup our copy of the discovery log */	kfree(discoveries);	/* Check out what we found */	if(daddr == DEV_ADDR_ANY) {		IRDA_DEBUG(1, "%s(), cannot discover service ''%s'' in any device !!!\n",			   __FUNCTION__, name);		self->daddr = DEV_ADDR_ANY;		return(-EADDRNOTAVAIL);	}	/* Revert back to discovered device & service */	self->daddr = daddr;	self->saddr = 0x0;	self->dtsap_sel = dtsap_sel;	IRDA_DEBUG(1, "%s(), discovered requested service ''%s'' at address %08x\n",		   __FUNCTION__, name, self->daddr);	return 0;}/* * Function irda_getname (sock, uaddr, uaddr_len, peer) * *    Return the our own, or peers socket address (sockaddr_irda) * */static int irda_getname(struct socket *sock, struct sockaddr *uaddr,			int *uaddr_len, int peer){	struct sockaddr_irda saddr;	struct sock *sk = sock->sk;	struct irda_sock *self = irda_sk(sk);	if (peer) {		if (sk->sk_state != TCP_ESTABLISHED)			return -ENOTCONN;		saddr.sir_family = AF_IRDA;		saddr.sir_lsap_sel = self->dtsap_sel;		saddr.sir_addr = self->daddr;	} else {		saddr.sir_family = AF_IRDA;		saddr.sir_lsap_sel = self->stsap_sel;		saddr.sir_addr = self->saddr;	}	IRDA_DEBUG(1, "%s(), tsap_sel = %#x\n", __FUNCTION__, saddr.sir_lsap_sel);	IRDA_DEBUG(1, "%s(), addr = %08x\n", __FUNCTION__, saddr.sir_addr);	/* uaddr_len come to us uninitialised */	*uaddr_len = sizeof (struct sockaddr_irda);	memcpy(uaddr, &saddr, *uaddr_len);	return 0;}/* * Function irda_listen (sock, backlog) * *    Just move to the listen state * */static int irda_listen(struct socket *sock, int backlog){	struct sock *sk = sock->sk;	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);	if ((sk->sk_type != SOCK_STREAM) && (sk->sk_type != SOCK_SEQPACKET) &&	    (sk->sk_type != SOCK_DGRAM))		return -EOPNOTSUPP;	if (sk->sk_state != TCP_LISTEN) {		sk->sk_max_ack_backlog = backlog;		sk->sk_state           = TCP_LISTEN;		return 0;	}	return -EOPNOTSUPP;}/* * Function irda_bind (sock, uaddr, addr_len) * *    Used by servers to register their well known TSAP * */static int irda_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len){	struct sock *sk = sock->sk;	struct sockaddr_irda *addr = (struct sockaddr_irda *) uaddr;	struct irda_sock *self = irda_sk(sk);	int err;	IRDA_DEBUG(2, "%s(%p)\n", __FUNCTION__, self);	if (addr_len != sizeof(struct sockaddr_irda))		return -EINVAL;#ifdef CONFIG_IRDA_ULTRA	/* Special care for Ultra sockets */	if ((sk->sk_type == SOCK_DGRAM) &&	    (sk->sk_protocol == IRDAPROTO_ULTRA)) {		self->pid = addr->sir_lsap_sel;		if (self->pid & 0x80) {			IRDA_DEBUG(0, "%s(), extension in PID not supp!\n", __FUNCTION__);			return -EOPNOTSUPP;		}		err = irda_open_lsap(self, self->pid);		if (err < 0)			return err;		/* Pretend we are connected */		sock->state = SS_CONNECTED;		sk->sk_state   = TCP_ESTABLISHED;		return 0;	}#endif /* CONFIG_IRDA_ULTRA */	self->ias_obj = irias_new_object(addr->sir_name, jiffies);	if (self->ias_obj == NULL)		return -ENOMEM;	err = irda_open_tsap(self, addr->sir_lsap_sel, addr->sir_name);	if (err < 0) {		kfree(self->ias_obj->name);		kfree(self->ias_obj);		return err;	}	/*  Register with LM-IAS */	irias_add_integer_attrib(self->ias_obj, "IrDA:TinyTP:LsapSel",				 self->stsap_sel, IAS_KERNEL_ATTR);	irias_insert_object(self->ias_obj);	return 0;}/* * Function irda_accept (sock, newsock, flags) * *    Wait for incoming connection * */static int irda_accept(struct socket *sock, struct socket *newsock, int flags){	struct sock *sk = sock->sk;	struct irda_sock *new, *self = irda_sk(sk);	struct sock *newsk;	struct sk_buff *skb;	int err;	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);	err = irda_create(sk->sk_net, newsock, sk->sk_protocol);	if (err)		return err;	if (sock->state != SS_UNCONNECTED)		return -EINVAL;	if ((sk = sock->sk) == NULL)		return -EINVAL;	if ((sk->sk_type != SOCK_STREAM) && (sk->sk_type != SOCK_SEQPACKET) &&	    (sk->sk_type != SOCK_DGRAM))		return -EOPNOTSUPP;	if (sk->sk_state != TCP_LISTEN)		return -EINVAL;	/*	 *	The read queue this time is holding sockets ready to use	 *	hooked into the SABM we saved	 */	/*	 * We can perform the accept only if there is incoming data	 * on the listening socket.	 * So, we will block the caller until we receive any data.	 * If the caller was waiting on select() or poll() before	 * calling us, the data is waiting for us ;-)	 * Jean II	 */	while (1) {		skb = skb_dequeue(&sk->sk_receive_queue);		if (skb)			break;		/* Non blocking operation */		if (flags & O_NONBLOCK)			return -EWOULDBLOCK;		err = wait_event_interruptible(*(sk->sk_sleep),					skb_peek(&sk->sk_receive_queue));		if (err)			return err;	}	newsk = newsock->sk;	if (newsk == NULL)		return -EIO;	newsk->sk_state = TCP_ESTABLISHED;	new = irda_sk(newsk);	/* Now attach up the new socket */	new->tsap = irttp_dup(self->tsap, new);	if (!new->tsap) {		IRDA_DEBUG(0, "%s(), dup failed!\n", __FUNCTION__);		kfree_skb(skb);		return -1;	}	new->stsap_sel = new->tsap->stsap_sel;	new->dtsap_sel = new->tsap->dtsap_sel;	new->saddr = irttp_get_saddr(new->tsap);	new->daddr = irttp_get_daddr(new->tsap);	new->max_sdu_size_tx = self->max_sdu_size_tx;	new->max_sdu_size_rx = self->max_sdu_size_rx;	new->max_data_size   = self->max_data_size;	new->max_header_size = self->max_header_size;	memcpy(&new->qos_tx, &self->qos_tx, sizeof(struct qos_info));	/* Clean up the original one to keep it in listen state */	irttp_listen(self->tsap);	/* Wow ! What is that ? Jean II */	skb->sk = NULL;	skb->destructor = NULL;	kfree_skb(skb);	sk->sk_ack_backlog--;	newsock->state = SS_CONNECTED;	irda_connect_response(new);	return 0;}/* * Function irda_connect (sock, uaddr, addr_len, flags) * *    Connect to a IrDA device * * The main difference with a "standard" connect is that with IrDA we need * to resolve the service name into a TSAP selector (in TCP, port number * doesn't have to be resolved). * Because of this service name resoltion, we can offer "auto-connect", * where we connect to a service without specifying a destination address. * * Note : by consulting "errno", the user space caller may learn the cause * of the failure. Most of them are visible in the function, others may come * from subroutines called and are listed here : *	o EBUSY : already processing a connect *	o EHOSTUNREACH : bad addr->sir_addr argument *	o EADDRNOTAVAIL : bad addr->sir_name argument *	o ENOTUNIQ : more than one node has addr->sir_name (auto-connect) *	o ENETUNREACH : no node found on the network (auto-connect) */static int irda_connect(struct socket *sock, struct sockaddr *uaddr,			int addr_len, int flags){	struct sock *sk = sock->sk;	struct sockaddr_irda *addr = (struct sockaddr_irda *) uaddr;	struct irda_sock *self = irda_sk(sk);	int err;	IRDA_DEBUG(2, "%s(%p)\n", __FUNCTION__, self);	/* Don't allow connect for Ultra sockets */	if ((sk->sk_type == SOCK_DGRAM) && (sk->sk_protocol == IRDAPROTO_ULTRA))		return -ESOCKTNOSUPPORT;	if (sk->sk_state == TCP_ESTABLISHED && sock->state == SS_CONNECTING) {		sock->state = SS_CONNECTED;		return 0;   /* Connect completed during a ERESTARTSYS event */	}	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);

⌨️ 快捷键说明

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