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

📄 irnet_irda.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* *	IrNET protocol module : Synchronous PPP over an IrDA socket. * *		Jean II - HPL `00 - <jt@hpl.hp.com> * * This file implement the IRDA interface of IrNET. * Basically, we sit on top of IrTTP. We set up IrTTP, IrIAS properly, * and exchange frames with IrTTP. */#include <linux/config.h>#include "irnet_irda.h"		/* Private header *//************************* CONTROL CHANNEL *************************//* * When ppp is not active, /dev/irnet act as a control channel. * Writting allow to set up the IrDA destination of the IrNET channel, * and any application may be read events happening on IrNET... *//*------------------------------------------------------------------*//* * Post an event to the control channel... * Put the event in the log, and then wait all process blocked on read * so they can read the log... */static voidirnet_post_event(irnet_socket *	ap,		 irnet_event	event,		 __u32		addr,		 char *		name){  unsigned long		flags;		/* For spinlock */  int			index;		/* In the log */  DENTER(CTRL_TRACE, "(ap=0x%X, event=%d, addr=%08x, name=``%s'')\n",	 (unsigned int) ap, event, addr, name);  /* Protect this section via spinlock.   * Note : as we are the only event producer, we only need to exclude   * ourself when touching the log, which is nice and easy.   */  spin_lock_irqsave(&irnet_events.spinlock, flags);  /* Copy the event in the log */  index = irnet_events.index;  irnet_events.log[index].event = event;  irnet_events.log[index].addr = addr;  /* Try to copy IrDA nickname */  if(name)    strcpy(irnet_events.log[index].name, name);  else    irnet_events.log[index].name[0] = '\0';  /* Try to get ppp unit number */  if((ap != (irnet_socket *) NULL) && (ap->ppp_open))    irnet_events.log[index].unit = ppp_unit_number(&ap->chan);  else    irnet_events.log[index].unit = -1;  /* Increment the index   * Note that we increment the index only after the event is written,   * to make sure that the readers don't get garbage... */  irnet_events.index = (index + 1) % IRNET_MAX_EVENTS;  DEBUG(CTRL_INFO, "New event index is %d\n", irnet_events.index);  /* Spin lock end */  spin_unlock_irqrestore(&irnet_events.spinlock, flags);  /* Now : wake up everybody waiting for events... */  wake_up_interruptible_all(&irnet_events.rwait);  DEXIT(CTRL_TRACE, "\n");}/************************* IRDA SUBROUTINES *************************//* * These are a bunch of subroutines called from other functions * down there, mostly common code or to improve readability... * * Note : we duplicate quite heavily some routines of af_irda.c, * because our input structure (self) is quite different * (struct irnet instead of struct irda_sock), which make sharing * the same code impossible (at least, without templates). *//*------------------------------------------------------------------*//* * Function irda_open_tsap (self) * *    Open local Transport Service Access Point (TSAP) * * Create a IrTTP instance for us and set all the IrTTP callbacks. */static inline intirnet_open_tsap(irnet_socket *	self){  notify_t	notify;		/* Callback structure */  DENTER(IRDA_SR_TRACE, "(self=0x%X)\n", (unsigned int) self);  DABORT(self->tsap != NULL, -EBUSY, IRDA_SR_ERROR, "Already busy !\n");  /* Initialize IrTTP callbacks to be used by the IrDA stack */  irda_notify_init(&notify);  notify.connect_confirm	= irnet_connect_confirm;  notify.connect_indication	= irnet_connect_indication;  notify.disconnect_indication	= irnet_disconnect_indication;  notify.data_indication	= irnet_data_indication;  /*notify.udata_indication	= NULL;*/  notify.flow_indication	= irnet_flow_indication;  notify.status_indication	= irnet_status_indication;  notify.instance		= self;  strncpy(notify.name, IRNET_NOTIFY_NAME, NOTIFY_MAX_NAME);  /* Open an IrTTP instance */  self->tsap = irttp_open_tsap(LSAP_ANY, DEFAULT_INITIAL_CREDIT,			       &notify);	  DABORT(self->tsap == NULL, -ENOMEM,	 IRDA_SR_ERROR, "Unable to allocate TSAP !\n");  /* Remember which TSAP selector we actually got */  self->stsap_sel = self->tsap->stsap_sel;  DEXIT(IRDA_SR_TRACE, " - tsap=0x%X, sel=0x%X\n",	(unsigned int) self->tsap, self->stsap_sel);  return 0;}/*------------------------------------------------------------------*//* * Function irnet_find_lsap_sel (self) * *    Try to lookup LSAP selector in remote LM-IAS * * Basically, we start a IAP query, and then go to sleep. When the query * return, irnet_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 intirnet_find_lsap_sel(irnet_socket *	self){  DENTER(IRDA_SR_TRACE, "(self=0x%X)\n", (unsigned int) self);  /* This should not happen */  DABORT(self->iriap, -EBUSY, IRDA_SR_ERROR, "busy with a previous query.\n");  /* Create an IAP instance, will be closed in irnet_getvalue_confirm() */  self->iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self,			   irnet_getvalue_confirm);  /* Treat unexpected signals as disconnect */  self->errno = -EHOSTUNREACH;  /* Query remote LM-IAS */  iriap_getvaluebyclass_request(self->iriap, self->saddr, self->daddr,				IRNET_SERVICE_NAME, IRNET_IAS_VALUE);  /* Wait for answer (if not already failed) */  if(self->iriap != NULL)    interruptible_sleep_on(&self->query_wait);  /* Check what happened */  if(self->errno)    {      DEBUG(IRDA_SR_INFO, "IAS query failed! (%d)\n", 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:      DEBUG(IRDA_SR_INFO, "result=%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;      DERROR(IRDA_SR_ERROR, "bad type ! (0x%X)\n", self->ias_result->type);      break;    }  /* Cleanup */  if(self->ias_result)    irias_delete_value(self->ias_result);  DEXIT(IRDA_SR_TRACE, "\n");  if(self->dtsap_sel)    return 0;  return -EADDRNOTAVAIL;}/*------------------------------------------------------------------*//* * Function irnet_discover_daddr_and_lsap_sel (self) * *    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 inline intirnet_discover_daddr_and_lsap_sel(irnet_socket *	self){  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 */  DENTER(IRDA_SR_TRACE, "(self=0x%X)\n", (unsigned int) self);  /* 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)    DRETURN(-ENETUNREACH, IRDA_SR_INFO, "Cachelog empty...\n");  /*    * 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;      DEBUG(IRDA_SR_INFO, "trying daddr = %08x\n", self->daddr);      /* Query remote LM-IAS for this service */      err = irnet_find_lsap_sel(self);      switch(err)	{	case 0:	  /* We found the requested service */	  if(daddr != DEV_ADDR_ANY)	    {	      DEBUG(IRDA_SR_INFO, "More than one device in range supports IrNET...\n");	    }	  else	    {	      /* 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 :-( */	  DERROR(IRDA_SR_ERROR, "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)    {      self->daddr = DEV_ADDR_ANY;      DEXIT(IRDA_SR_INFO, "cannot discover IrNET in any device !!!\n");      return(-EADDRNOTAVAIL);    }  /* Revert back to discovered device & service */  self->daddr = daddr;  self->saddr = 0x0;  self->dtsap_sel = dtsap_sel;  DEBUG(IRDA_SR_INFO, "discovered IrNET at address %08x\n", self->daddr);  DEXIT(IRDA_SR_TRACE, "\n");  return 0;}/*------------------------------------------------------------------*//* * Function irnet_dname_to_daddr (self) * *    Convert an IrDA nickname to a valid IrDA address * * It basically look into the discovery log until there is a match. */static inline intirnet_dname_to_daddr(irnet_socket *	self){  struct irda_device_info *discoveries;	/* Copy of the discovery log */  int	number;			/* Number of nodes in the log */  int	i;  DENTER(IRDA_SR_TRACE, "(self=0x%X)\n", (unsigned int) self);  /* Ask lmp for the current discovery log */  discoveries = irlmp_get_discoveries(&number, 0xffff);  /* Check if the we got some results */  if(discoveries == NULL)    DRETURN(-ENETUNREACH, IRDA_SR_INFO, "Cachelog empty...\n");  /*    * 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++)    {      /* Does the name match ? */      if(!strncmp(discoveries[i].info, self->rname, NICKNAME_MAX_LEN))	{	  /* Yes !!! Get it.. */	  self->daddr = discoveries[i].daddr;	  DEBUG(IRDA_SR_INFO, "discovered device ``%s'' at address 0x%08x.\n",		self->rname, self->daddr);	  kfree(discoveries);	  DEXIT(IRDA_SR_TRACE, "\n");	  return 0;	}    }  /* No luck ! */  DEBUG(IRDA_SR_INFO, "cannot discover device ``%s'' !!!\n", self->rname);  kfree(discoveries);  return(-EADDRNOTAVAIL);}/************************* SOCKET ROUTINES *************************//* * This are the main operations on IrNET sockets, basically to create * and destroy IrNET sockets. These are called from the PPP part... *//*------------------------------------------------------------------*//* * Create a IrNET instance : just initialise some parameters... */intirda_irnet_create(irnet_socket *	self){  DENTER(IRDA_SOCK_TRACE, "(self=0x%X)\n", (unsigned int) self);  self->magic = IRNET_MAGIC;	/* Paranoia */  init_waitqueue_head(&self->query_wait);  self->ttp_open = 0;		/* Prevent higher layer from accessing IrTTP */  self->rname[0] = '\0';	/* May be set via control channel */  self->raddr = DEV_ADDR_ANY;	/* May be set via control channel */  self->daddr = DEV_ADDR_ANY;	/* Until we get connected */  self->saddr = 0x0;		/* so IrLMP assign us any link */  self->max_sdu_size_rx = TTP_SAR_UNBOUND;  /* Register as a client with IrLMP */  self->ckey = irlmp_register_client(0, NULL, NULL, NULL);#ifdef DISCOVERY_NOMASK  self->mask = 0xffff;		/* For W2k compatibility */#else DISCOVERY_NOMASK  self->mask = irlmp_service_to_hint(S_LAN);#endif DISCOVERY_NOMASK  self->tx_flow = FLOW_START;	/* Flow control from IrTTP */  DEXIT(IRDA_SOCK_TRACE, "\n");  return(0);}/*------------------------------------------------------------------*//* * Connect to the other side : *	o convert device name to an address *	o find the socket number (dlsap) *	o Establish the connection */intirda_irnet_connect(irnet_socket *	self){  int		err;  DENTER(IRDA_SOCK_TRACE, "(self=0x%X)\n", (unsigned int) self);  /* Check if we have opened a local TSAP :   * If we have already opened a TSAP, it means that either we are already   * connected or in the process of doing so... */  if(self->tsap != NULL)    DRETURN(-EBUSY, IRDA_SOCK_INFO, "Already connecting...\n");  /* Insert ourselves in the hashbin so that the IrNET server can find us.   * Notes : 4th arg is string of 32 char max and must be null terminated   *	     When 4th arg is used (string), 3rd arg isn't (int)   *	     Can't re-insert (MUST remove first) so check for that... */  if((irnet_server.running) && (self->q.q_next == NULL))    {      unsigned long		flags;      spin_lock_irqsave(&irnet_server.spinlock, flags);      hashbin_insert(irnet_server.list, (irda_queue_t *) self, 0, self->rname);      spin_unlock_irqrestore(&irnet_server.spinlock, flags);      DEBUG(IRDA_SOCK_INFO, "Inserted ``%s'' in hashbin...\n", self->rname);    }  /* If we don't have anything (no address, no name) */  if((self->raddr == DEV_ADDR_ANY) && (self->rname[0] == '\0'))    {      /* Try to find a suitable address */      if((err = irnet_discover_daddr_and_lsap_sel(self)) != 0) 	DRETURN(err, IRDA_SOCK_INFO, "auto-connect failed!\n");    }  else    {      /* If we have only the name (no address), try to get an address */      if(self->raddr == DEV_ADDR_ANY)	{	  if((err = irnet_dname_to_daddr(self)) != 0)	    DRETURN(err, IRDA_SOCK_INFO, "name-connect failed!\n");	}      else	/* Use the requested destination address */	self->daddr = self->raddr;      /* Query remote LM-IAS to find LSAP selector */      if((err = irnet_find_lsap_sel(self)) != 0)	DRETURN(err, IRDA_SOCK_INFO, "connect failed!\n");    }  DEBUG(IRDA_SOCK_INFO, "daddr = %08x, lsap = %d, starting IrTTP connection\n",	self->daddr, self->dtsap_sel);  /* Open a local TSAP (an IrTTP instance) */  err = irnet_open_tsap(self);  DABORT(err != 0, err, IRDA_SOCK_ERROR, "connect aborted!\n");  /* Connect to remote device */  err = irttp_connect_request(self->tsap, self->dtsap_sel, 			      self->saddr, self->daddr, NULL, 			      self->max_sdu_size_rx, NULL);  DABORT(err != 0, err, IRDA_SOCK_ERROR, "connect aborted!\n");  DEXIT(IRDA_SOCK_TRACE, "\n");  return(0);}/*------------------------------------------------------------------*//* * Function irda_irnet_destroy(self) * *    Destroy irnet instance * */voidirda_irnet_destroy(irnet_socket *	self){  DENTER(IRDA_SOCK_TRACE, "(self=0x%X)\n", (unsigned int) self);  if(self == NULL)    return;  /* Remove ourselves from hashbin (if we are queued in hashbin)   * Note : `irnet_server.running' protect us from calls in hashbin_delete() */  if((irnet_server.running) && (self->q.q_next != NULL))    {      struct irnet_socket *	entry;      unsigned long		flags;      DEBUG(IRDA_SOCK_INFO, "Removing from hash..\n");      spin_lock_irqsave(&irnet_server.spinlock, flags);      entry = hashbin_remove_this(irnet_server.list, (irda_queue_t *) self);      self->q.q_next = NULL;      spin_unlock_irqrestore(&irnet_server.spinlock, flags);      DASSERT(entry == self, , IRDA_SOCK_ERROR, "Can't remove from hash.\n");    }  /* Unregister with IrLMP */  irlmp_unregister_client(self->ckey);

⌨️ 快捷键说明

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