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

📄 irnet_irda.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
  /* Unregister with LM-IAS */  if(self->iriap)     iriap_close(self->iriap);  /* Prevent higher layer from accessing IrTTP */  self->ttp_open = 0;  /* Close our IrTTP connection */  if(self->tsap)    {      DEBUG(IRDA_SOCK_INFO, "Closing our TTP connection.\n");      irttp_disconnect_request(self->tsap, NULL, P_NORMAL);      irttp_close_tsap(self->tsap);      self->tsap = NULL;      /* Note : as the disconnect comes from ppp_generic, the unit number       * doesn't exist anymore when we post the event, so we need to pass       * NULL as the first arg... */      irnet_post_event(NULL, IRNET_DISCONNECT_TO, self->daddr, self->rname);    }  self->stsap_sel = 0;  DEXIT(IRDA_SOCK_TRACE, "\n");  return;}/************************** SERVER SOCKET **************************//* * The IrNET service is composed of one server socket and a variable * number of regular IrNET sockets. The server socket is supposed to * handle incomming connections and redirect them to one IrNET sockets. * It's a superset of the regular IrNET socket, but has a very distinct * behaviour... *//*------------------------------------------------------------------*//* * Function irnet_daddr_to_dname (self) * *    Convert an IrDA address to a IrDA nickname * * It basically look into the discovery log until there is a match. */static inline intirnet_daddr_to_dname(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_SERV_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_SERV_INFO, "Cachelog empty...\n");  /* Now, check all discovered devices (if any) */  for(i = 0; i < number; i++)    {      /* Does the name match ? */      if(discoveries[i].daddr == self->daddr)	{	  /* Yes !!! Get it.. */	  strncpy(self->rname, discoveries[i].info, NICKNAME_MAX_LEN);	  self->rname[NICKNAME_MAX_LEN + 1] = '\0';	  DEBUG(IRDA_SERV_INFO, "Device 0x%08x is in fact ``%s''.\n",		self->daddr, self->rname);	  kfree(discoveries);	  DEXIT(IRDA_SERV_TRACE, "\n");	  return 0;	}    }  /* No luck ! */  DEXIT(IRDA_SERV_INFO, ": cannot discover device 0x%08x !!!\n", self->daddr);  kfree(discoveries);  return(-EADDRNOTAVAIL);}/*------------------------------------------------------------------*//* * Function irda_find_socket (self) * *    Find the correct IrNET socket * * Look into the list of IrNET sockets and finds one with the right * properties... */static inline irnet_socket *irnet_find_socket(irnet_socket *	self){  irnet_socket *	new = (irnet_socket *) NULL;  unsigned long		flags;  int			err;  DENTER(IRDA_SERV_TRACE, "(self=0x%X)\n", (unsigned int) self);  /* Get the address of the requester */  self->daddr = irttp_get_daddr(self->tsap);  /* Try to get the IrDA nickname of the requester */  err = irnet_daddr_to_dname(self);  /* Protect access to the instance list */  spin_lock_irqsave(&irnet_server.spinlock, flags);  /* So now, try to get an socket having specifically   * requested that nickname */  if(err == 0)    {      new = (irnet_socket *) hashbin_find(irnet_server.list,					  0, self->rname);      if(new)	DEBUG(IRDA_SERV_INFO, "Socket 0x%X matches rname ``%s''.\n",	      (unsigned int) new, new->rname);    }  /* If no name matches, try to find an socket by the destination address */  /* It can be either the requested destination address (set via the   * control channel), or the current destination address if the   * socket is in the middle of a connection request */  if(new == (irnet_socket *) NULL)    {      new = (irnet_socket *) hashbin_get_first(irnet_server.list);      while(new !=(irnet_socket *) NULL)	{	  /* Does it have the same address ? */	  if((new->raddr == self->daddr) || (new->daddr == self->daddr))	    {	      /* Yes !!! Get it.. */	      DEBUG(IRDA_SERV_INFO, "Socket 0x%X matches daddr %#08x.\n",		    (unsigned int) new, self->daddr);	      break;	    }	  new = (irnet_socket *) hashbin_get_next(irnet_server.list);	}    }  /* If we don't have any socket, get the first unconnected socket */  if(new == (irnet_socket *) NULL)    {      new = (irnet_socket *) hashbin_get_first(irnet_server.list);      while(new !=(irnet_socket *) NULL)	{	  /* Is it available ? */	  if(!(new->ttp_open) && (new->raddr == DEV_ADDR_ANY) &&	     (new->rname[0] == '\0') && (new->ppp_open))	    {	      /* Yes !!! Get it.. */	      DEBUG(IRDA_SERV_INFO, "Socket 0x%X is free.\n",		    (unsigned int) new);	      break;	    }	  new = (irnet_socket *) hashbin_get_next(irnet_server.list);	}    }  /* Spin lock end */  spin_unlock_irqrestore(&irnet_server.spinlock, flags);  DEXIT(IRDA_SERV_TRACE, " - new = 0x%X\n", (unsigned int) new);  return new;}/*------------------------------------------------------------------*//* * Function irda_connect_socket (self) * *    Connect an incomming connection to the socket * */static inline intirnet_connect_socket(irnet_socket *	self,		     irnet_socket *	new,		     struct qos_info *	qos,		     __u32		max_sdu_size,		     __u8		max_header_size){  DENTER(IRDA_SERV_TRACE, "(self=0x%X, new=0x%X)\n",	 (unsigned int) self, (unsigned int) new);  /* Now attach up the new socket */  new->tsap = irttp_dup(self->tsap, new);  DABORT(new->tsap == NULL, -1, IRDA_SERV_ERROR, "dup failed!\n");  /* Set up all the relevant parameters on the new socket */  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_header_size = max_header_size;  new->max_sdu_size_tx = max_sdu_size;  new->max_data_size   = max_sdu_size;#ifdef STREAM_COMPAT  /* If we want to receive "stream sockets" */  if(max_sdu_size == 0)    new->max_data_size = irttp_get_max_seg_size(new->tsap);#endif STREAM_COMPAT  /* 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;  /* Send a connection response on the new socket */  irttp_connect_response(new->tsap, new->max_sdu_size_rx, NULL);  /* Allow PPP to send its junk over the new socket... */  new->ttp_open = 1;#ifdef CONNECT_INDIC_KICK  /* As currently we don't packets in ppp_irnet_send(), this is not needed...   * Also, not doing it give IrDA a chance to finish the setup properly   * before beeing swamped with packets... */  ppp_output_wakeup(&new->chan);#endif CONNECT_INDIC_KICK  /* Notify the control channel */  irnet_post_event(new, IRNET_CONNECT_FROM, new->daddr, self->rname);  DEXIT(IRDA_SERV_TRACE, "\n");  return 0;}/*------------------------------------------------------------------*//* * Function irda_disconnect_server (self) * *    Cleanup the server socket when the incomming connection abort * */static inline voidirnet_disconnect_server(irnet_socket *	self,			struct sk_buff *skb){  DENTER(IRDA_SERV_TRACE, "(self=0x%X)\n", (unsigned int) self);  /* Put the received packet in the black hole */  kfree_skb(skb);#ifdef FAIL_SEND_DISCONNECT  /* Tell the other party we don't want to be connected */  /* Hum... Is it the right thing to do ? And do we need to send   * a connect response before ? It looks ok without this... */  irttp_disconnect_request(self->tsap, NULL, P_NORMAL);#endif FAIL_SEND_DISCONNECT  /* Clean up the server to keep it in listen state */  self->tsap->dtsap_sel = self->tsap->lsap->dlsap_sel = LSAP_ANY;  self->tsap->lsap->lsap_state = LSAP_DISCONNECTED;  /* Notify the control channel */  irnet_post_event(NULL, IRNET_REQUEST_FROM, self->daddr, self->rname);  DEXIT(IRDA_SERV_TRACE, "\n");  return;}/*------------------------------------------------------------------*//* * Function irda_setup_server (self) * *    Create a IrTTP server and set it up... * * Register the IrLAN hint bit, create a IrTTP instance for us, * set all the IrTTP callbacks and create an IrIAS entry... */static inline intirnet_setup_server(void){  __u16		hints;  DENTER(IRDA_SERV_TRACE, "()\n");  /* Initialise the regular socket part of the server */  irda_irnet_create(&irnet_server.s);  /* Open a local TSAP (an IrTTP instance) for the server */  irnet_open_tsap(&irnet_server.s);  /* PPP part setup */  irnet_server.s.ppp_open = 0;  irnet_server.s.chan.private = NULL;  irnet_server.s.file = NULL;  /* Get the hint bit corresponding to IrLAN */  /* Note : we overload the IrLAN hint bit. As it is only a "hint", and as   * we provide roughly the same functionality as IrLAN, this is ok.   * In fact, the situation is similar as JetSend overloading the Obex hint   */  hints = irlmp_service_to_hint(S_LAN);#ifdef ADVERTISE_HINT  /* Register with IrLMP as a service (advertise our hint bit) */  irnet_server.skey = irlmp_register_service(hints);#endif ADVERTISE_HINT  /* Register with LM-IAS (so that people can connect to us) */  irnet_server.ias_obj = irias_new_object(IRNET_SERVICE_NAME, jiffies);  irias_add_integer_attrib(irnet_server.ias_obj, IRNET_IAS_VALUE, 			   irnet_server.s.stsap_sel, IAS_KERNEL_ATTR);  irias_insert_object(irnet_server.ias_obj);#ifdef DISCOVERY_EVENTS  /* Tell IrLMP we want to be notified of newly discovered nodes */  irlmp_update_client(irnet_server.s.ckey, hints,		      irnet_discovery_indication, irnet_expiry_indication,		      (void *) &irnet_server.s);#endif  DEXIT(IRDA_SERV_TRACE, " - self=0x%X\n", (unsigned int) &irnet_server.s);  return 0;}/*------------------------------------------------------------------*//* * Function irda_destroy_server (self) * *    Destroy the IrTTP server... * * Reverse of the previous function... */static inline voidirnet_destroy_server(void){  DENTER(IRDA_SERV_TRACE, "()\n");#ifdef ADVERTISE_HINT  /* Unregister with IrLMP */  irlmp_unregister_service(irnet_server.skey);#endif ADVERTISE_HINT  /* Unregister with LM-IAS */  if(irnet_server.ias_obj)    irias_delete_object(irnet_server.ias_obj);  /* Cleanup the socket part */  irda_irnet_destroy(&irnet_server.s);  DEXIT(IRDA_SERV_TRACE, "\n");  return;}/************************ IRDA-TTP CALLBACKS ************************//* * When we create a IrTTP instance, we pass to it a set of callbacks * that IrTTP will call in case of various events. * We take care of those events here. *//*------------------------------------------------------------------*//* * Function irnet_data_indication (instance, sap, skb) * *    Received some data from TinyTP. Just queue it on the receive queue * */static intirnet_data_indication(void *	instance,		      void *	sap,		      struct sk_buff *skb){  irnet_socket *	ap = (irnet_socket *) instance;  unsigned char *	p;  int			code = 0;  DENTER(IRDA_TCB_TRACE, "(self/ap=0x%X, skb=0x%X)\n",	 (unsigned int) ap,(unsigned int) skb);  DASSERT(skb != NULL, 0, IRDA_CB_ERROR, "skb is NULL !!!\n");  /* Check is ppp is ready to receive our packet */  if(!ap->ppp_open)    {      DERROR(IRDA_CB_ERROR, "PPP not ready, dropping packet...\n");      /* When we return error, TTP will need to requeue the skb and       * will stop the sender. IrTTP will stall until we send it a       * flow control request... */      return -ENOMEM;    }  /* strip address/control field if present */  p = skb->data;  if((p[0] == PPP_ALLSTATIONS) && (p[1] == PPP_UI))    {      /* chop off address/control */      if(skb->len < 3)	goto err_exit;      p = skb_pull(skb, 2);    }  /* decompress protocol field if compressed */  if(p[0] & 1)    {      /* protocol is compressed */      skb_push(skb, 1)[0] = 0;    }  else    if(skb->len < 2)      goto err_exit;  /* pass to generic ppp layer */  /* Note : how do I know if ppp can accept or not the packet ? This is   * essential if I want to manage flow control smoothly... */  ppp_input(&ap->chan, skb);  DEXIT(IRDA_TCB_TRACE, "\n");  return 0; err_exit:  DERROR(IRDA_CB_ERROR, "Packet too small, dropping...\n");  kfree_skb(skb);  ppp_input_error(&ap->chan, code);  return 0;	/* Don't return an error code, only for flow control... */}/*------------------------------------------------------------------*//* * Function irnet_disconnect_indication (instance, sap, reason, skb) * *    Connection has been closed. Chech reason to find out why * * Note : there are many cases where we come here : *	o attempted to connect, timeout *	o connected, link is broken, LAP has timeout *	o connected, other side close the link *	o connection request on the server no handled */static voidirnet_disconnect_indication(void *	instance,			    void *	sap, 			    LM_REASON	reason,			    struct sk_buff *skb){  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");  /* If we were active, notify the control channel */  if(self->ttp_open)    irnet_post_event(self, IRNET_DISCONNECT_FROM, self->daddr, self->rname);  else    /* If we were trying to connect, notify the control channel */    if((self->tsap) && (self != &irnet_server.s))      irnet_post_event(self, IRNET_NOANSWER_FROM, self->daddr, self->rname);  /* Prevent higher layer from accessing IrTTP */  self->ttp_open = 0;  /* Close our IrTTP connection */  if((self->tsap) && (self != &irnet_server.s))    {      DEBUG(IRDA_CB_INFO, "Closing our TTP connection.\n");      irttp_disconnect_request(self->tsap, NULL, P_NORMAL);      irttp_close_tsap(self->tsap);      self->tsap = NULL;      /* Flush (drain) ppp_generic Tx queue (most often we have blocked it) */      if(self->ppp_open)	ppp_output_wakeup(&self->chan);    }  /* Cleanup the socket in case we want to reconnect */  self->stsap_sel = 0;  self->daddr = DEV_ADDR_ANY;  self->tx_flow = FLOW_START;  /* Note : what should we say to ppp ?   * It seem the ppp_generic and pppd are happy that way and will eventually   * timeout gracefully, so don't bother them... */  DEXIT(IRDA_TCB_TRACE, "\n");}/*------------------------------------------------------------------*//* * Function irnet_connect_confirm (instance, sap, qos, max_sdu_size, skb) * *    Connections has been confirmed by the remote device * */static voidirnet_connect_confirm(void *	instance,		      void *	sap, 		      struct qos_info *qos,		      __u32	max_sdu_size,		      __u8	max_header_size, 		      struct sk_buff *skb){  irnet_socket *	self = (irnet_socket *) instance;  DENTER(IRDA_TCB_TRACE, "(self=0x%X)\n", (unsigned int) self);

⌨️ 快捷键说明

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