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

📄 af_irda.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
		IRDA_DEBUG( 0, __FUNCTION__ "(), Unable to allocate TSAP!\n");		return -ENOMEM;	}	/* Remember which TSAP selector we actually got */	self->stsap_sel = self->tsap->stsap_sel;	return 0;}/* * 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) {		WARNING(__FUNCTION__ "(), busy!\n");		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, __FUNCTION__ "(), Unable to allocate LSAP!\n");		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, __FUNCTION__ "(), name=%s\n", name);	ASSERT(self != NULL, return -1;);	if (self->iriap) {		WARNING(__FUNCTION__ "(), busy with a previous query\n");		return -EBUSY;	}	self->iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self,				 irda_getvalue_confirm);	/* Treat unexpected signals 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 already failed) */	if(self->iriap != NULL)		interruptible_sleep_on(&self->query_wait);	/* 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, __FUNCTION__ "() int=%d\n",			   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, __FUNCTION__ "(), bad type!\n");		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){	struct irda_device_info *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, __FUNCTION__ "(), name=%s\n", name);	ASSERT(self != NULL, return -1;);	/* 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);	/* 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, __FUNCTION__ "(), trying daddr = %08x\n",			   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, __FUNCTION__					   "(), discovered service ''%s'' in two different devices !!!\n",					   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, __FUNCTION__				   "(), unexpected IAS query failure\n");			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, __FUNCTION__			   "(), cannot discover service ''%s'' in any device !!!\n",			   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, __FUNCTION__ 		   "(), discovered requested service ''%s'' at address %08x\n",		   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 = sk->protinfo.irda;	if (peer) {		if (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, __FUNCTION__ "(), tsap_sel = %#x\n", saddr.sir_lsap_sel);	IRDA_DEBUG(1, __FUNCTION__ "(), addr = %08x\n", 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, __FUNCTION__ "()\n");	if ((sk->type != SOCK_STREAM) && (sk->type != SOCK_SEQPACKET) &&	    (sk->type != SOCK_DGRAM))		return -EOPNOTSUPP;	if (sk->state != TCP_LISTEN) {		sk->max_ack_backlog = backlog;		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;	__u16 hints = 0;	int err;	IRDA_DEBUG(2, __FUNCTION__ "()\n");	self = sk->protinfo.irda;	ASSERT(self != NULL, return -1;);	if (addr_len != sizeof(struct sockaddr_irda))		return -EINVAL;#ifdef CONFIG_IRDA_ULTRA	/* Special care for Ultra sockets */	if ((sk->type == SOCK_DGRAM) && (sk->protocol == IRDAPROTO_ULTRA)) {		self->pid = addr->sir_lsap_sel;		if (self->pid & 0x80) {			IRDA_DEBUG(0, __FUNCTION__ 				   "(), extension in PID not supp!\n");			return -EOPNOTSUPP;		}		err = irda_open_lsap(self, self->pid);		if (err < 0)			return err;				self->max_data_size = ULTRA_MAX_DATA - LMP_PID_HEADER;		self->max_header_size = IRDA_MAX_HEADER + LMP_PID_HEADER;		/* Pretend we are connected */		sock->state = SS_CONNECTED;		sk->state   = TCP_ESTABLISHED;		return 0;	}#endif /* CONFIG_IRDA_ULTRA */	err = irda_open_tsap(self, addr->sir_lsap_sel, addr->sir_name);	if (err < 0)		return err;		/*  Register with LM-IAS */	self->ias_obj = irias_new_object(addr->sir_name, jiffies);	irias_add_integer_attrib(self->ias_obj, "IrDA:TinyTP:LsapSel", 				 self->stsap_sel, IAS_KERNEL_ATTR);	irias_insert_object(self->ias_obj);	#if 1 /* Will be removed in near future */	/* Fill in some default hint bits values */	if (strncmp(addr->sir_name, "OBEX", 4) == 0)		hints = irlmp_service_to_hint(S_OBEX);		if (hints)		self->skey = irlmp_register_service(hints);#endif	return 0;}/* * Function irda_accept (sock, newsock, flags) * *    Wait for incomming connection * */static int irda_accept(struct socket *sock, struct socket *newsock, int flags){	struct irda_sock *self, *new;	struct sock *sk = sock->sk;	struct sock *newsk;	struct sk_buff *skb;	int err;	IRDA_DEBUG(2, __FUNCTION__ "()\n");	self = sk->protinfo.irda;	ASSERT(self != NULL, return -1;);	err = irda_create(newsock, sk->protocol);	if (err)		return err;	if (sock->state != SS_UNCONNECTED)		return -EINVAL;	if ((sk = sock->sk) == NULL)		return -EINVAL;	if ((sk->type != SOCK_STREAM) && (sk->type != SOCK_SEQPACKET) &&	    (sk->type != SOCK_DGRAM))		return -EOPNOTSUPP;	if (sk->state != TCP_LISTEN) 		return -EINVAL;	/*	 *	The read queue this time is holding sockets ready to use	 *	hooked into the SABM we saved	 */	do {		if ((skb = skb_dequeue(&sk->receive_queue)) == NULL) {			if (flags & O_NONBLOCK)				return -EWOULDBLOCK;			interruptible_sleep_on(sk->sleep);			if (signal_pending(current)) 				return -ERESTARTSYS;		}	} while (skb == NULL); 	newsk = newsock->sk;	newsk->state = TCP_ESTABLISHED;	new = newsk->protinfo.irda;	ASSERT(new != NULL, return -1;);	/* Now attach up the new socket */	new->tsap = irttp_dup(self->tsap, new);	if (!new->tsap) {		IRDA_DEBUG(0, __FUNCTION__ "(), dup failed!\n");		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 */	self->tsap->dtsap_sel = self->tsap->lsap->dlsap_sel = LSAP_ANY;	self->tsap->lsap->lsap_state = LSAP_DISCONNECTED;	skb->sk = NULL;	skb->destructor = NULL;	kfree_skb(skb);	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;	int err;	IRDA_DEBUG(2, __FUNCTION__ "()\n");	self = sk->protinfo.irda;		/* Don't allow connect for Ultra sockets */	if ((sk->type == SOCK_DGRAM) && (sk->protocol == IRDAPROTO_ULTRA))		return -ESOCKTNOSUPPORT;	if (sk->state == TCP_ESTABLISHED && sock->state == SS_CONNECTING) {		sock->state = SS_CONNECTED;		return 0;   /* Connect completed during a ERESTARTSYS event */	}		if (sk->state == TCP_CLOSE && sock->state == SS_CONNECTING) {		sock->state = SS_UNCONNECTED;		return -ECONNREFUSED;	}		if (sk->state == TCP_ESTABLISHED)		return -EISCONN;      /* No reconnect on a seqpacket socket */	

⌨️ 快捷键说明

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