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

📄 irnet_irda.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
  /* 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;  self->max_data_size = max_sdu_size;#ifdef STREAM_COMPAT  if(max_sdu_size == 0)    self->max_data_size = irttp_get_max_seg_size(self->tsap);#endif STREAM_COMPAT  /* At this point, IrLMP has assigned our source address */  self->saddr = irttp_get_saddr(self->tsap);  /* Allow higher layer to access IrTTP */  self->ttp_open = 1;  /* Give a kick in the ass of ppp_generic so that he sends us some data */  ppp_output_wakeup(&self->chan);  /* Check size of received packet */  if(skb->len > 0)    {#ifdef PASS_CONNECT_PACKETS      DEBUG(IRDA_CB_INFO, "Passing connect packet to PPP.\n");      /* Try to pass it to PPP */      irnet_data_indication(instance, sap, skb);#else PASS_CONNECT_PACKETS      DERROR(IRDA_CB_ERROR, "Dropping non empty packet.\n");      kfree_skb(skb);	/* Note : will be optimised with other kfree... */#endif PASS_CONNECT_PACKETS    }  else    kfree_skb(skb);  /* Notify the control channel */  irnet_post_event(self, IRNET_CONNECT_TO, self->daddr, self->rname);  DEXIT(IRDA_TCB_TRACE, "\n");}/*------------------------------------------------------------------*//* * Function irnet_flow_indication (instance, sap, flow) * *    Used by TinyTP to tell us if it can accept more data or not * */static voidirnet_flow_indication(void *	instance,		      void *	sap,		      LOCAL_FLOW flow) {  irnet_socket *	self = (irnet_socket *) instance;  DENTER(IRDA_TCB_TRACE, "(self=0x%X, flow=%d)\n", (unsigned int) self, flow);  /* Update our state */  self->tx_flow = flow;  /* Check what IrTTP want us to do... */  switch(flow)    {    case FLOW_START:      DEBUG(IRDA_CB_INFO, "IrTTP wants us to start again\n");      ppp_output_wakeup(&self->chan);      break;    case FLOW_STOP:      DEBUG(IRDA_CB_INFO, "IrTTP wants us to slow down\n");      break;    default:      DEBUG(IRDA_CB_INFO, "Unknown flow command!\n");      break;    }  DEXIT(IRDA_TCB_TRACE, "\n");}/*------------------------------------------------------------------*//* * Function irnet_status_indication (instance, sap, reason, skb) * *    Link (IrLAP) status report. * */static voidirnet_status_indication(void *	instance,			LINK_STATUS link,			LOCK_STATUS lock){  irnet_socket *	self = (irnet_socket *) instance;  DENTER(IRDA_TCB_TRACE, "(self=0x%X)\n", (unsigned int) self);  DASSERT(self != NULL, , IRDA_CB_ERROR, "Self is NULL !!!\n");  /* We can only get this event if we are connected */  switch(link)    {    case STATUS_NO_ACTIVITY:      irnet_post_event(self, IRNET_BLOCKED_LINK, self->daddr, self->rname);      break;    default:      DEBUG(IRDA_CB_INFO, "Unknown status...\n");    }  DEXIT(IRDA_TCB_TRACE, "\n");}/*------------------------------------------------------------------*//* * Function irnet_connect_indication(instance, sap, qos, max_sdu_size, userdata) * *    Incomming connection * * In theory, this function is called only on the server socket. * Some other node is attempting to connect to the IrNET service, and has * sent a connection request on our server socket. * We just redirect the connection to the relevant IrNET socket. *  * Note : we also make sure that between 2 irnet nodes, there can * exist only one irnet connection. */static voidirnet_connect_indication(void *		instance,			 void *		sap, 			 struct qos_info *qos,			 __u32		max_sdu_size,			 __u8		max_header_size,			 struct sk_buff *skb){  irnet_socket *	self = &irnet_server.s;  irnet_socket *	new = (irnet_socket *) NULL;  DENTER(IRDA_TCB_TRACE, "(self=0x%X)\n", (unsigned int) self);  DASSERT(instance == &irnet_server, , IRDA_CB_ERROR,	  "Invalid instance (0x%X) !!!\n", (unsigned int) instance);  DASSERT(sap == irnet_server.s.tsap, , IRDA_CB_ERROR, "Invalid sap !!!\n");  /* Try to find the most appropriate IrNET socket */  new = irnet_find_socket(self);  /* After all this hard work, do we have an socket ? */  if(new == (irnet_socket *) NULL)    {      DEXIT(IRDA_CB_INFO, ": No socket waiting for this connection.\n");      irnet_disconnect_server(self, skb);      return;    }  /* Is the socket already busy ? */  if(new->ttp_open)    {      DEXIT(IRDA_CB_INFO, ": Socket already connected.\n");      irnet_disconnect_server(self, skb);      return;    }  /* Socket connecting */  if(new->tsap != NULL)    {      /* The socket has sent a IrTTP connection request and is waiting for       * a connection response (that may never come).       * Now, the pain is that the socket has open a tsap and is waiting on it,       * while the other end is trying to connect to it on another tsap.       * Argh ! We will deal with that later...       */      DERROR(IRDA_CB_ERROR, "Socket already connecting. Ouch !\n");#ifdef ALLOW_SIMULT_CONNECT      /* Close the connection the new socket was attempting.       * WARNING : This need more testing ! */      irttp_close_tsap(new->tsap);      /* Note : no return, fall through... */#else ALLOW_SIMULT_CONNECT      irnet_disconnect_server(self, skb);      return;#endif ALLOW_SIMULT_CONNECT    }  /* So : at this point, we have a socket, and it is idle. Good ! */  irnet_connect_socket(self, new, qos, max_sdu_size, max_header_size);  /* Check size of received packet */  if(skb->len > 0)    {#ifdef PASS_CONNECT_PACKETS      DEBUG(IRDA_CB_INFO, "Passing connect packet to PPP.\n");      /* Try to pass it to PPP */      irnet_data_indication(new, new->tsap, skb);#else PASS_CONNECT_PACKETS      DERROR(IRDA_CB_ERROR, "Dropping non empty packet.\n");      kfree_skb(skb);	/* Note : will be optimised with other kfree... */#endif PASS_CONNECT_PACKETS    }  else    kfree_skb(skb);  DEXIT(IRDA_TCB_TRACE, "\n");}/********************** IRDA-IAS/LMP CALLBACKS **********************//* * These are the callbacks called by other layers of the IrDA stack, * mainly LMP for discovery and IAS for name queries. *//*------------------------------------------------------------------*//* * Function irnet_getvalue_confirm (obj_id, value, priv) * *    Got answer from remote LM-IAS, just pass object to requester... * */static voidirnet_getvalue_confirm(int	result,		       __u16	obj_id, 		       struct ias_value *value,		       void *	priv){  irnet_socket *	self = (irnet_socket *) priv;  DENTER(IRDA_OCB_TRACE, "(self=0x%X)\n", (unsigned int) self);  DASSERT(self != NULL, , IRDA_CB_ERROR, "Self is NULL !!!\n");  /* 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)    {      DEBUG(IRDA_CB_INFO, "IAS query failed! (%d)\n", result);      self->errno = result;	/* We really need it later */    }  else    {      /* 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);  DEXIT(IRDA_OCB_TRACE, "\n");}#ifdef DISCOVERY_EVENTS/*------------------------------------------------------------------*//* * Function irnet_discovery_indication (discovery) * *    Got a discovery indication from IrLMP, post an event * * Note : IrLMP take care of matching the hint mask for us, we only * check if it is a "new" node... * * As IrLMP filter on the IrLAN hint bit, we get both IrLAN and IrNET * nodes, so it's only at connection time that we will know if the * node support IrNET, IrLAN or both. The other solution is to check * in IAS the PNP ids and service name. * Note : even if a node support IrNET (or IrLAN), it's no guarantee * that we will be able to connect to it, the node might already be * busy... * * One last thing : in some case, this function will trigger duplicate * discovery events. On the other hand, we should catch all * discoveries properly (i.e. not miss one). Filtering duplicate here * is to messy, so we leave that to user space... */static voidirnet_discovery_indication(discovery_t *discovery,			   void *	priv){  irnet_socket *	self = &irnet_server.s;	  DENTER(IRDA_OCB_TRACE, "(self=0x%X)\n", (unsigned int) self);  DASSERT(priv == &irnet_server, , IRDA_CB_ERROR,	  "Invalid instance (0x%X) !!!\n", (unsigned int) priv);  /* 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).   */  if((jiffies - discovery->first_timestamp) >= (sysctl_discovery_timeout * HZ))    {      return;		/* Too old, not interesting -> goodbye */    }  DEBUG(IRDA_CB_INFO, "Discovered new IrNET/IrLAN node %s...\n",	discovery->nickname);  /* Notify the control channel */  irnet_post_event(NULL, IRNET_DISCOVER, discovery->daddr,		   discovery->nickname);  DEXIT(IRDA_OCB_TRACE, "\n");}/*------------------------------------------------------------------*//* * Function irnet_expiry_indication (expiry) * *    Got a expiry indication from IrLMP, post an event * * Note : IrLMP take care of matching the hint mask for us, we only * check if it is a "new" node... */static voidirnet_expiry_indication(discovery_t *	expiry,			void *		priv){  irnet_socket *	self = &irnet_server.s;	  DENTER(IRDA_OCB_TRACE, "(self=0x%X)\n", (unsigned int) self);  DASSERT(priv == &irnet_server, , IRDA_CB_ERROR,	  "Invalid instance (0x%X) !!!\n", (unsigned int) priv);  DEBUG(IRDA_CB_INFO, "IrNET/IrLAN node %s expired...\n",	expiry->nickname);  /* Notify the control channel */  irnet_post_event(NULL, IRNET_EXPIRE, expiry->daddr,		   expiry->nickname);  DEXIT(IRDA_OCB_TRACE, "\n");}#endif DISCOVERY_EVENTS/*********************** PROC ENTRY CALLBACKS ***********************//* * We create a instance in the /proc filesystem, and here we take care * of that... */#ifdef CONFIG_PROC_FS/*------------------------------------------------------------------*//* * Function irnet_proc_read (buf, start, offset, len, unused) * *    Give some info to the /proc file system */static intirnet_proc_read(char *	buf,		char **	start,		off_t	offset,		int	len){  irnet_socket *	self;  char *		state;  unsigned long		flags;  int			i = 0;  len = 0;	  /* Get the IrNET server information... */  len += sprintf(buf+len, "IrNET server - ");  len += sprintf(buf+len, "IrDA state: %s, ",		 (irnet_server.running ? "running" : "dead"));  len += sprintf(buf+len, "stsap_sel: %02x, ", irnet_server.s.stsap_sel);  len += sprintf(buf+len, "dtsap_sel: %02x\n", irnet_server.s.dtsap_sel);  /* Do we need to continue ? */  if(!irnet_server.running)    return len;  /* Protect access to the instance list */  spin_lock_irqsave(&irnet_server.spinlock, flags);  /* Get the sockets one by one... */  self = (irnet_socket *) hashbin_get_first(irnet_server.list);  while(self != NULL)    {      /* Start printing info about the socket. */      len += sprintf(buf+len, "\nIrNET socket %d - ", i++);      /* First, get the requested configuration */      len += sprintf(buf+len, "Requested IrDA name: \"%s\", ", self->rname);      len += sprintf(buf+len, "addr: %08x\n", self->raddr);      /* Second, get all the PPP info */      len += sprintf(buf+len, "	PPP state: %s",		 (self->ppp_open ? "registered" : "unregistered"));      if(self->ppp_open)	{	  len += sprintf(buf+len, ", unit: ppp%d",			 ppp_unit_number(&self->chan));	  len += sprintf(buf+len, ", channel: %d",			 ppp_channel_index(&self->chan));	  len += sprintf(buf+len, ", mru: %d",			 self->mru);	  /* Maybe add self->flags ? Later... */	}      /* Then, get all the IrDA specific info... */      if(self->ttp_open)	state = "connected";      else	if(self->tsap != NULL)	  state = "connecting";	else	  state = "idle";      len += sprintf(buf+len, "\n	IrDA state: %s, ", state);      len += sprintf(buf+len, "daddr: %08x, ", self->daddr);      len += sprintf(buf+len, "stsap_sel: %02x, ", self->stsap_sel);      len += sprintf(buf+len, "dtsap_sel: %02x\n", self->dtsap_sel);      /* Next socket, please... */      self = (irnet_socket *) hashbin_get_next(irnet_server.list);    }  /* Spin lock end */  spin_unlock_irqrestore(&irnet_server.spinlock, flags);  return len;}#endif /* PROC_FS *//********************** CONFIGURATION/CLEANUP **********************//* * Initialisation and teardown of the IrDA part, called at module * insertion and removal... *//*------------------------------------------------------------------*//* * Prepare the IrNET layer for operation... */intirda_irnet_init(void){  int		err = 0;  DENTER(MODULE_TRACE, "()\n");  /* Pure paranoia - should be redundant */  memset(&irnet_server, 0, sizeof(struct irnet_root));  /* Setup start of irnet instance list */  irnet_server.list = hashbin_new(HB_LOCAL);   DABORT(irnet_server.list == NULL, -ENOMEM,	 MODULE_ERROR, "Can't allocate hashbin!\n");  /* Init spinlock for instance list */  spin_lock_init(&irnet_server.spinlock);  /* Initialise control channel */  init_waitqueue_head(&irnet_events.rwait);  irnet_events.index = 0;  /* Init spinlock for event logging */  spin_lock_init(&irnet_events.spinlock);#ifdef CONFIG_PROC_FS  /* Add a /proc file for irnet infos */  create_proc_info_entry("irnet", 0, proc_irda, irnet_proc_read);#endif /* CONFIG_PROC_FS */  /* Setup the IrNET server */  err = irnet_setup_server();  if(!err)    /* We are no longer functional... */    irnet_server.running = 1;  DEXIT(MODULE_TRACE, "\n");  return err;}/*------------------------------------------------------------------*//* * Cleanup at exit... */voidirda_irnet_cleanup(void){  DENTER(MODULE_TRACE, "()\n");  /* We are no longer there... */  irnet_server.running = 0;#ifdef CONFIG_PROC_FS  /* Remove our /proc file */  remove_proc_entry("irnet", proc_irda);#endif CONFIG_PROC_FS  /* Remove our IrNET server from existence */  irnet_destroy_server();  /* Remove all instances of IrNET socket still present */  hashbin_delete(irnet_server.list, (FREE_FUNC) irda_irnet_destroy);  DEXIT(MODULE_TRACE, "\n");}

⌨️ 快捷键说明

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