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

📄 irnet_ppp.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
  else    mask |= irnet_ctrl_poll(ap, file, wait);  DEXIT(FS_TRACE, " - mask=0x%X\n", mask);  return(mask);}/*------------------------------------------------------------------*//* * IOCtl : Called when someone does some ioctls on /dev/irnet * This is the way pppd configure us and control us while the PPP * instance is active. */static intdev_irnet_ioctl(struct inode *	inode,		struct file *	file,		unsigned int	cmd,		unsigned long	arg){  irnet_socket *	ap = (struct irnet_socket *) file->private_data;  int			err;  int			val;  DENTER(FS_TRACE, "(file=0x%X, ap=0x%X, cmd=0x%X)\n",	 (unsigned int) file, (unsigned int) ap, cmd);  /* Basic checks... */  DASSERT(ap != NULL, -ENXIO, PPP_ERROR, "ap is NULL...\n");#ifdef SECURE_DEVIRNET  if(!capable(CAP_NET_ADMIN))    return -EPERM;#endif SECURE_DEVIRNET  err = -EFAULT;  switch(cmd)    {      /* Set discipline (should be N_SYNC_PPP or N_TTY) */    case TIOCSETD:      if(get_user(val, (int *) arg))	break;      if((val == N_SYNC_PPP) || (val == N_PPP))	{	  DEBUG(FS_INFO, "Entering PPP discipline.\n");	  /* PPP channel setup */	  ap->chan.private = ap;	  ap->chan.ops = &irnet_ppp_ops;	  ap->chan.mtu = PPP_MRU;	  err = ppp_register_channel(&ap->chan);	  if(err == 0)	    {	      /* Our ppp side is active */	      ap->ppp_open = 1;	      DEBUG(FS_INFO, "Trying to establish a connection.\n");	      /* Setup the IrDA link now - may fail... */	      irda_irnet_connect(ap);	    }	  else	    DERROR(FS_ERROR, "Can't setup PPP channel...\n");	}      else	{	  /* In theory, should be N_TTY */	  DEBUG(FS_INFO, "Exiting PPP discipline.\n");	  /* Disconnect from the generic PPP layer */	  if(ap->ppp_open)	    ppp_unregister_channel(&ap->chan);	  else	    DERROR(FS_ERROR, "Channel not registered !\n");	  ap->ppp_open = 0;	  err = 0;	}      break;      /* Attach this PPP instance to the PPP driver (set it active) */    case PPPIOCATTACH:    case PPPIOCDETACH:      if(ap->ppp_open)	err = ppp_channel_ioctl(&ap->chan, cmd, arg);      else	DERROR(FS_ERROR, "Channel not registered !\n");      break;      /* Query PPP channel and unit number */    case PPPIOCGCHAN:      if(!ap->ppp_open)	break;      if(put_user(ppp_channel_index(&ap->chan), (int *) arg))	break;      DEBUG(FS_INFO, "Query channel.\n");      err = 0;      break;    case PPPIOCGUNIT:      if(!ap->ppp_open)	break;      if(put_user(ppp_unit_number(&ap->chan), (int *) arg))	break;      DEBUG(FS_INFO, "Query unit number.\n");      err = 0;      break;      /* All these ioctls can be passed both directly and from ppp_generic,       * so we just deal with them in one place...       */    case PPPIOCGFLAGS:    case PPPIOCSFLAGS:    case PPPIOCGASYNCMAP:    case PPPIOCSASYNCMAP:    case PPPIOCGRASYNCMAP:    case PPPIOCSRASYNCMAP:    case PPPIOCGXASYNCMAP:    case PPPIOCSXASYNCMAP:    case PPPIOCGMRU:    case PPPIOCSMRU:      DEBUG(FS_INFO, "Standard PPP ioctl.\n");      if(!capable(CAP_NET_ADMIN))	err = -EPERM;      else	err = ppp_irnet_ioctl(&ap->chan, cmd, arg);      break;      /* TTY IOCTLs : Pretend that we are a tty, to keep pppd happy */      /* Get termios */    case TCGETS:      DEBUG(FS_INFO, "Get termios.\n");      if(kernel_termios_to_user_termios((struct termios *)arg, &ap->termios))	break;      err = 0;      break;      /* Set termios */    case TCSETSF:      DEBUG(FS_INFO, "Set termios.\n");      if(user_termios_to_kernel_termios(&ap->termios, (struct termios *) arg))	break;      err = 0;      break;      /* Set DTR/RTS */    case TIOCMBIS:     case TIOCMBIC:      /* Set exclusive/non-exclusive mode */    case TIOCEXCL:    case TIOCNXCL:      DEBUG(FS_INFO, "TTY compatibility.\n");      err = 0;      break;    case TCGETA:      DEBUG(FS_INFO, "TCGETA\n");      break;    case TCFLSH:      DEBUG(FS_INFO, "TCFLSH\n");      /* Note : this will flush buffers in PPP, so it *must* be done       * We should also worry that we don't accept junk here and that       * we get rid of our own buffers */#ifdef FLUSH_TO_PPP      ppp_output_wakeup(&ap->chan);#endif FLUSH_TO_PPP      err = 0;      break;    case FIONREAD:      DEBUG(FS_INFO, "FIONREAD\n");      val = 0;      if(put_user(val, (int *) arg))	break;      err = 0;      break;    default:      DERROR(FS_ERROR, "Unsupported ioctl (0x%X)\n", cmd);      err = -ENOIOCTLCMD;    }  DEXIT(FS_TRACE, " - err = 0x%X\n", err);  return err;}/************************** PPP CALLBACKS **************************//* * This are the functions that the generic PPP driver in the kernel * will call to communicate to us. *//*------------------------------------------------------------------*//* * Prepare the ppp frame for transmission over the IrDA socket. * We make sure that the header space is enough, and we change ppp header * according to flags passed by pppd. * This is not a callback, but just a helper function used in ppp_irnet_send() */static inline struct sk_buff *irnet_prepare_skb(irnet_socket *	ap,		  struct sk_buff *	skb){  unsigned char *	data;  int			proto;		/* PPP protocol */  int			islcp;		/* Protocol == LCP */  int			needaddr;	/* Need PPP address */  DENTER(PPP_TRACE, "(ap=0x%X, skb=0x%X)\n",	 (unsigned int) ap, (unsigned int) skb);  /* Extract PPP protocol from the frame */  data  = skb->data;  proto = (data[0] << 8) + data[1];  /* LCP packets with codes between 1 (configure-request)   * and 7 (code-reject) must be sent as though no options   * have been negotiated. */  islcp = (proto == PPP_LCP) && (1 <= data[2]) && (data[2] <= 7);  /* compress protocol field if option enabled */  if((data[0] == 0) && (ap->flags & SC_COMP_PROT) && (!islcp))    skb_pull(skb,1);  /* Check if we need address/control fields */  needaddr = 2*((ap->flags & SC_COMP_AC) == 0 || islcp);  /* Is the skb headroom large enough to contain all IrDA-headers? */  if((skb_headroom(skb) < (ap->max_header_size + needaddr)) ||      (skb_shared(skb)))    {      struct sk_buff *	new_skb;      DEBUG(PPP_INFO, "Reallocating skb\n");      /* Create a new skb */      new_skb = skb_realloc_headroom(skb, ap->max_header_size + needaddr);      /* We have to free the original skb anyway */      dev_kfree_skb(skb);      /* Did the realloc succeed ? */      DABORT(new_skb == NULL, NULL, PPP_ERROR, "Could not realloc skb\n");      /* Use the new skb instead */      skb = new_skb;    }  /* prepend address/control fields if necessary */  if(needaddr)    {      skb_push(skb,2);      skb->data[0] = PPP_ALLSTATIONS;      skb->data[1] = PPP_UI;    }  DEXIT(PPP_TRACE, "\n");  return skb;}/*------------------------------------------------------------------*//* * Send a packet to the peer over the IrTTP connection. * Returns 1 iff the packet was accepted. * Returns 0 iff packet was not consumed. * If the packet was not accepted, we will call ppp_output_wakeup * at some later time to reactivate flow control in ppp_generic. */static intppp_irnet_send(struct ppp_channel *	chan,	       struct sk_buff *		skb){  irnet_socket *	self = (struct irnet_socket *) chan->private;  int			ret;  DENTER(PPP_TRACE, "(channel=0x%X, ap/self=0x%X)\n",	 (unsigned int) chan, (unsigned int) self);  /* Check if things are somewhat valid... */  DASSERT(self != NULL, 0, PPP_ERROR, "Self is NULL !!!\n");  /* Check if we are connected */  if(self->ttp_open == 0)    {#ifdef CONNECT_IN_SEND      /* Let's try to connect one more time... */      /* Note : we won't connect fully yet, but we should be ready for       * next packet... */      /* Note : we can't do that, we need to have a process context to       * go through interruptible_sleep_on() in irnet_find_lsap_sel()       * We need to find another way... */      irda_irnet_connect(self);#endif CONNECT_IN_SEND      DEBUG(PPP_INFO, "IrTTP not ready ! (%d-0x%X)\n",	    self->ttp_open, (unsigned int) self->tsap);      /* Note : we can either drop the packet or block the packet.       *       * Blocking the packet allow us a better connection time,       * because by calling ppp_output_wakeup() we can have       * ppp_generic resending the LCP request immediately to us,       * rather than waiting for one of pppd periodic transmission of       * LCP request.       *       * On the other hand, if we block all packet, all those periodic       * transmissions of pppd accumulate in ppp_generic, creating a       * backlog of LCP request. When we eventually connect later on,       * we have to transmit all this backlog before we can connect       * proper (if we don't timeout before).       *       * The current strategy is as follow :       * While we are attempting to connect, we block packets to get       * a better connection time.       * If we fail to connect, we drain the queue and start dropping packets       */#ifdef BLOCK_WHEN_CONNECT      /* If we are attempting to connect */      if(self->tsap)	{	  /* Blocking packet, ppp_generic will retry later */	  return 0;	}#endif BLOCK_WHEN_CONNECT      /* Dropping packet, pppd will retry later */      dev_kfree_skb(skb);      return 1;    }  /* Check if the queue can accept any packet, otherwise block */  if(self->tx_flow != FLOW_START)    DRETURN(0, PPP_INFO, "IrTTP queue full (%d skbs)...\n",	    skb_queue_len(&self->tsap->tx_queue));  /* Prepare ppp frame for transmission */  skb = irnet_prepare_skb(self, skb);  DABORT(skb == NULL, 1, PPP_ERROR, "Prepare skb for Tx failed.\n");  /* Send the packet to IrTTP */  ret = irttp_data_request(self->tsap, skb);  if(ret < 0)    {      /*          * > IrTTPs tx queue is full, so we just have to       * > drop the frame! You might think that we should       * > just return -1 and don't deallocate the frame,       * > but that is dangerous since it's possible that       * > we have replaced the original skb with a new       * > one with larger headroom, and that would really       * > confuse do_dev_queue_xmit() in dev.c! I have       * > tried :-) DB        * Correction : we verify the flow control above (self->tx_flow),       * so we come here only if IrTTP doesn't like the packet (empty,       * too large, IrTTP not connected). In those rare cases, it's ok       * to drop it, we don't want to see it here again...       * Jean II       */      DERROR(PPP_ERROR, "IrTTP doesn't like this packet !!! (0x%X)\n", ret);      dev_kfree_skb(skb);    }  DEXIT(PPP_TRACE, "\n");  return 1;	/* Packet has been consumed */}/*------------------------------------------------------------------*//* * Take care of the ioctls that ppp_generic doesn't want to deal with... * Note : we are also called from dev_irnet_ioctl(). */static intppp_irnet_ioctl(struct ppp_channel *	chan,		unsigned int		cmd,		unsigned long		arg){  irnet_socket *	ap = (struct irnet_socket *) chan->private;  int			err;  int			val;  u32			accm[8];  DENTER(PPP_TRACE, "(channel=0x%X, ap=0x%X, cmd=0x%X)\n",	 (unsigned int) chan, (unsigned int) ap, cmd);  /* Basic checks... */  DASSERT(ap != NULL, -ENXIO, PPP_ERROR, "ap is NULL...\n");  err = -EFAULT;  switch(cmd)    {      /* PPP flags */    case PPPIOCGFLAGS:      val = ap->flags | ap->rbits;      if(put_user(val, (int *) arg))	break;      err = 0;      break;    case PPPIOCSFLAGS:      if(get_user(val, (int *) arg))	break;      ap->flags = val & ~SC_RCV_BITS;      ap->rbits = val & SC_RCV_BITS;      err = 0;      break;      /* Async map stuff - all dummy to please pppd */    case PPPIOCGASYNCMAP:      if(put_user(ap->xaccm[0], (u32 *) arg))	break;      err = 0;      break;    case PPPIOCSASYNCMAP:      if(get_user(ap->xaccm[0], (u32 *) arg))	break;      err = 0;      break;    case PPPIOCGRASYNCMAP:      if(put_user(ap->raccm, (u32 *) arg))	break;      err = 0;      break;    case PPPIOCSRASYNCMAP:      if(get_user(ap->raccm, (u32 *) arg))	break;      err = 0;      break;    case PPPIOCGXASYNCMAP:      if(copy_to_user((void *) arg, ap->xaccm, sizeof(ap->xaccm)))	break;      err = 0;      break;    case PPPIOCSXASYNCMAP:      if(copy_from_user(accm, (void *) arg, sizeof(accm)))	break;      accm[2] &= ~0x40000000U;		/* can't escape 0x5e */      accm[3] |= 0x60000000U;		/* must escape 0x7d, 0x7e */      memcpy(ap->xaccm, accm, sizeof(ap->xaccm));      err = 0;      break;      /* Max PPP frame size */    case PPPIOCGMRU:      if(put_user(ap->mru, (int *) arg))	break;      err = 0;      break;    case PPPIOCSMRU:      if(get_user(val, (int *) arg))	break;      if(val < PPP_MRU)	val = PPP_MRU;      ap->mru = val;      err = 0;      break;    default:      DEBUG(PPP_INFO, "Unsupported ioctl (0x%X)\n", cmd);      err = -ENOIOCTLCMD;    }  DEXIT(PPP_TRACE, " - err = 0x%X\n", err);  return err;}/************************** INITIALISATION **************************//* * Module initialisation and all that jazz... *//*------------------------------------------------------------------*//* * Hook our device callbacks in the filesystem, to connect our code * to /dev/irnet */intppp_irnet_init(void){  int err = 0;  DENTER(MODULE_TRACE, "()\n");  /* Allocate ourselves as a minor in the misc range */  err = misc_register(&irnet_misc_device);  DEXIT(MODULE_TRACE, "\n");  return err;}/*------------------------------------------------------------------*//* * Cleanup at exit... */voidppp_irnet_cleanup(void){  DENTER(MODULE_TRACE, "()\n");  /* De-allocate /dev/irnet minor in misc range */  misc_deregister(&irnet_misc_device);  DEXIT(MODULE_TRACE, "\n");}#ifdef MODULE/*------------------------------------------------------------------*//* * Module main entry point */intinit_module(void){  int err;  /* Initialise both parts... */  err = irda_irnet_init();  if(!err)    err = ppp_irnet_init();  return err;}/*------------------------------------------------------------------*//* * Module exit */voidcleanup_module(void){  irda_irnet_cleanup();  return ppp_irnet_cleanup();}#endif /* MODULE */

⌨️ 快捷键说明

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