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

📄 irnet_ppp.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *	IrNET protocol module : Synchronous PPP over an IrDA socket. * *		Jean II - HPL `00 - <jt@hpl.hp.com> * * This file implement the PPP interface and /dev/irnet character device. * The PPP interface hook to the ppp_generic module, handle all our *	relationship to the PPP code in the kernel (and by extension to pppd), *	and exchange PPP frames with this module (send/receive). * The /dev/irnet device is used primarily for 2 functions : *	1) as a stub for pppd (the ppp daemon), so that we can appropriately *	generate PPP sessions (we pretend we are a tty). *	2) as a control channel (write commands, read events) */#include "irnet_ppp.h"		/* Private header *//************************* CONTROL CHANNEL *************************//* * When a pppd instance is not active on /dev/irnet, it acts as a control * channel. * Writting allow to set up the IrDA destination of the IrNET channel, * and any application may be read events happening in IrNET... *//*------------------------------------------------------------------*//* * Write is used to send a command to configure a IrNET channel * before it is open by pppd. The syntax is : "command argument" * Currently there is only two defined commands : *	o name : set the requested IrDA nickname of the IrNET peer. *	o addr : set the requested IrDA address of the IrNET peer. * Note : the code is crude, but effective... */static inline ssize_tirnet_ctrl_write(irnet_socket *	ap,		 const char *	buf,		 size_t		count){  char		command[5 + NICKNAME_MAX_LEN + 2];  int		length = count;  DENTER(CTRL_TRACE, "(ap=0x%X, count=%d)\n", (unsigned int) ap, count);  /* Check for overflow... */  DABORT(count > (5 + NICKNAME_MAX_LEN + 1), -ENOMEM,	 CTRL_ERROR, "Too much data !!!\n");  /* Get the data in the driver */  if(copy_from_user(command, buf, count))    {      DERROR(CTRL_ERROR, "Invalid user space pointer.\n");      return -EFAULT;    }  /* Strip out '\n' if needed, and safe terminate the string */  if(command[length - 1] == '\0')    length--;  if(command[length - 1] == '\n')    length--;  command[length] = '\0';  DEBUG(CTRL_INFO, "Command received is ``%s'' (%d-%d).\n",	command, length, count);  /* Check if we recognised the command */  /* First command : name */  if(!strncmp(command, "name", 4))    {      /* Copy the name only if is included and not "any" */      if((length > 5) && (strcmp(command + 5, "any")))	{	  /* Copy the name for later reuse (including the '/0') */	  memcpy(ap->rname, command + 5, length - 5 + 1);	}      else	ap->rname[0] = '\0';      DEXIT(CTRL_TRACE, " - rname = ``%s''\n", ap->rname);      return(count);    }  /* Second command : addr */  if(!strncmp(command, "addr", 4))    {      /* Copy the address only if is included and not "any" */      if((length > 5) && (strcmp(command + 5, "any")))	{	  char *	endp;	  __u32		daddr;	  /* Convert argument to a number (last arg is the base) */	  daddr = simple_strtoul(command + 5, &endp, 16);	  /* Has it worked  ? (endp should be command + count) */	  DABORT(endp <= (command + 5), -EINVAL,		 CTRL_ERROR, "Invalid address.\n");	  /* Save it */	  ap->raddr = daddr;	}      else	ap->raddr = DEV_ADDR_ANY;      DEXIT(CTRL_TRACE, " - raddr = %08x\n", ap->raddr);      return(count);    }  /* Other possible command : connect N (number of retries) */  /* Failed... */  DABORT(1, -EINVAL, CTRL_ERROR, "Not a recognised IrNET command.\n");}#ifdef INITIAL_DISCOVERY/*------------------------------------------------------------------*//* * Function irnet_read_discovery_log (self) * *    Read the content on the discovery log * * This function dump the current content of the discovery log * at the startup of the event channel. * Return 1 if written on the control channel... * * State of the ap->disco_XXX variables : *	at socket creation :	disco_index = 0 ; disco_number = 0 *	while reading :		disco_index = X ; disco_number = Y *	After reading :		disco_index = Y ; disco_number = -1 */static inline intirnet_read_discovery_log(irnet_socket *	ap,			 char *		event){  int		done_event = 0;  DENTER(CTRL_TRACE, "(ap=0x%X, event=0x%X)\n",	 (unsigned int) ap, (unsigned int) event);  /* Test if we have some work to do or we have already finished */  if(ap->disco_number == -1)    {      DEBUG(CTRL_INFO, "Already done\n");      return 0;    }  /* Test if it's the first time and therefore we need to get the log */  if(ap->disco_index == 0)    {      __u16		mask = irlmp_service_to_hint(S_LAN);      /* Ask IrLMP for the current discovery log */      ap->discoveries = irlmp_get_discoveries(&ap->disco_number, mask);      /* Check if the we got some results */      if(ap->discoveries == NULL)	ap->disco_number = -1;      DEBUG(CTRL_INFO, "Got the log (0x%X), size is %d\n",	    (unsigned int) ap->discoveries, ap->disco_number);    }  /* Check if we have more item to dump */  if(ap->disco_index < ap->disco_number)    {      /* Write an event */      sprintf(event, "Found %08x (%s)\n",	      ap->discoveries[ap->disco_index].daddr,	      ap->discoveries[ap->disco_index].info);      DEBUG(CTRL_INFO, "Writing discovery %d : %s\n",	    ap->disco_index, ap->discoveries[ap->disco_index].info);      /* We have an event */      done_event = 1;      /* Next discovery */      ap->disco_index++;    }  /* Check if we have done the last item */  if(ap->disco_index >= ap->disco_number)    {      /* No more items : remove the log and signal termination */      DEBUG(CTRL_INFO, "Cleaning up log (0x%X)\n",	    (unsigned int) ap->discoveries);      if(ap->discoveries != NULL)	{	  /* Cleanup our copy of the discovery log */	  kfree(ap->discoveries);	  ap->discoveries = NULL;	}      ap->disco_number = -1;    }  return done_event;}#endif INITIAL_DISCOVERY/*------------------------------------------------------------------*//* * Read is used to get IrNET events */static inline ssize_tirnet_ctrl_read(irnet_socket *	ap,		struct file *	file,		char *		buf,		size_t		count){  DECLARE_WAITQUEUE(wait, current);  char		event[64];	/* Max event is 61 char */  ssize_t	ret = 0;  DENTER(CTRL_TRACE, "(ap=0x%X, count=%d)\n", (unsigned int) ap, count);  /* Check if we can write an event out in one go */  DABORT(count < sizeof(event), -EOVERFLOW, CTRL_ERROR, "Buffer to small.\n");#ifdef INITIAL_DISCOVERY  /* Check if we have read the log */  if(irnet_read_discovery_log(ap, event))    {      /* We have an event !!! Copy it to the user */      if(copy_to_user(buf, event, strlen(event)))	{	  DERROR(CTRL_ERROR, "Invalid user space pointer.\n");	  return -EFAULT;	}      DEXIT(CTRL_TRACE, "\n");      return(strlen(event));    }#endif INITIAL_DISCOVERY  /* Put ourselves on the wait queue to be woken up */  add_wait_queue(&irnet_events.rwait, &wait);  current->state = TASK_INTERRUPTIBLE;  for(;;)    {      /* If there is unread events */      ret = 0;      if(ap->event_index != irnet_events.index)	break;      ret = -EAGAIN;      if(file->f_flags & O_NONBLOCK)	break;      ret = -ERESTARTSYS;      if(signal_pending(current))	break;      /* Yield and wait to be woken up */      schedule();    }  current->state = TASK_RUNNING;  remove_wait_queue(&irnet_events.rwait, &wait);  /* Did we got it ? */  if(ret != 0)    {      /* No, return the error code */      DEXIT(CTRL_TRACE, " - ret %d\n", ret);      return ret;    }  /* Which event is it ? */  switch(irnet_events.log[ap->event_index].event)    {    case IRNET_DISCOVER:      sprintf(event, "Discovered %08x (%s)\n",	      irnet_events.log[ap->event_index].addr,	      irnet_events.log[ap->event_index].name);      break;    case IRNET_EXPIRE:      sprintf(event, "Expired %08x (%s)\n",	      irnet_events.log[ap->event_index].addr,	      irnet_events.log[ap->event_index].name);      break;    case IRNET_CONNECT_TO:      sprintf(event, "Connected to %08x (%s) on ppp%d\n",	      irnet_events.log[ap->event_index].addr,	      irnet_events.log[ap->event_index].name,	      irnet_events.log[ap->event_index].unit);      break;    case IRNET_CONNECT_FROM:      sprintf(event, "Connection from %08x (%s) on ppp%d\n",	      irnet_events.log[ap->event_index].addr,	      irnet_events.log[ap->event_index].name,	      irnet_events.log[ap->event_index].unit);      break;    case IRNET_REQUEST_FROM:      sprintf(event, "Request from %08x (%s)\n",	      irnet_events.log[ap->event_index].addr,	      irnet_events.log[ap->event_index].name);      break;    case IRNET_NOANSWER_FROM:      sprintf(event, "No-answer from %08x (%s) on ppp%d\n",	      irnet_events.log[ap->event_index].addr,	      irnet_events.log[ap->event_index].name,	      irnet_events.log[ap->event_index].unit);      break;    case IRNET_BLOCKED_LINK:      sprintf(event, "Blocked link with %08x (%s) on ppp%d\n",	      irnet_events.log[ap->event_index].addr,	      irnet_events.log[ap->event_index].name,	      irnet_events.log[ap->event_index].unit);      break;    case IRNET_DISCONNECT_FROM:      sprintf(event, "Disconnection from %08x (%s) on ppp%d\n",	      irnet_events.log[ap->event_index].addr,	      irnet_events.log[ap->event_index].name,	      irnet_events.log[ap->event_index].unit);      break;    case IRNET_DISCONNECT_TO:      sprintf(event, "Disconnected to %08x (%s)\n",	      irnet_events.log[ap->event_index].addr,	      irnet_events.log[ap->event_index].name);      break;    default:      sprintf(event, "Bug\n");    }  /* Increment our event index */  ap->event_index = (ap->event_index + 1) % IRNET_MAX_EVENTS;  DEBUG(CTRL_INFO, "Event is :%s", event);  /* Copy it to the user */  if(copy_to_user(buf, event, strlen(event)))    {      DERROR(CTRL_ERROR, "Invalid user space pointer.\n");      return -EFAULT;    }  DEXIT(CTRL_TRACE, "\n");  return(strlen(event));}/*------------------------------------------------------------------*//* * Poll : called when someone do a select on /dev/irnet. * Just check if there are new events... */static inline unsigned intirnet_ctrl_poll(irnet_socket *	ap,		struct file *	file,		poll_table *	wait){  unsigned int mask;  DENTER(CTRL_TRACE, "(ap=0x%X)\n", (unsigned int) ap);  poll_wait(file, &irnet_events.rwait, wait);  mask = POLLOUT | POLLWRNORM;  /* If there is unread events */  if(ap->event_index != irnet_events.index)    mask |= POLLIN | POLLRDNORM;#ifdef INITIAL_DISCOVERY  if(ap->disco_number != -1)    mask |= POLLIN | POLLRDNORM;#endif INITIAL_DISCOVERY  DEXIT(CTRL_TRACE, " - mask=0x%X\n", mask);  return mask;}/*********************** FILESYSTEM CALLBACKS ***********************//* * Implement the usual open, read, write functions that will be called * by the file system when some action is performed on /dev/irnet. * Most of those actions will in fact be performed by "pppd" or * the control channel, we just act as a redirector... *//*------------------------------------------------------------------*//* * Open : when somebody open /dev/irnet * We basically create a new instance of irnet and initialise it. */static intdev_irnet_open(struct inode *	inode,	       struct file *	file){  struct irnet_socket *	ap;  int			err;  DENTER(FS_TRACE, "(file=0x%X)\n", (unsigned int) file);#ifdef SECURE_DEVIRNET  /* This could (should?) be enforced by the permissions on /dev/irnet. */  if(!capable(CAP_NET_ADMIN))    return -EPERM;#endif SECURE_DEVIRNET  /* Allocate a private structure for this IrNET instance */  ap = kmalloc(sizeof(*ap), GFP_KERNEL);  DABORT(ap == NULL, -ENOMEM, FS_ERROR, "Can't allocate struct irnet...\n");  MOD_INC_USE_COUNT;  /* initialize the irnet structure */  memset(ap, 0, sizeof(*ap));  ap->file = file;  /* PPP channel setup */  ap->ppp_open = 0;  ap->chan.private = ap;  /* PPP parameters */  ap->mru = PPP_MRU;  ap->xaccm[0] = ~0U;  ap->xaccm[3] = 0x60000000U;  ap->raccm = ~0U;  /* Setup the IrDA part... */  err = irda_irnet_create(ap);  if(err)    {      DERROR(FS_ERROR, "Can't setup IrDA link...\n");      kfree(ap);      MOD_DEC_USE_COUNT;      return err;    }  /* For the control channel */  ap->event_index = irnet_events.index;	/* Cancel all past events */  /* Put our stuff where we will be able to find it later */  file->private_data = ap;  DEXIT(FS_TRACE, " - ap=0x%X\n", (unsigned int) ap);  return 0;}/*------------------------------------------------------------------*//* * Close : when somebody close /dev/irnet * Destroy the instance of /dev/irnet */static intdev_irnet_close(struct inode *	inode,		struct file *	file){  irnet_socket *	ap = (struct irnet_socket *) file->private_data;  DENTER(FS_TRACE, "(file=0x%X, ap=0x%X)\n",	 (unsigned int) file, (unsigned int) ap);  DABORT(ap == NULL, 0, FS_ERROR, "ap is NULL !!!\n");  /* Detach ourselves */  file->private_data = NULL;  /* Close IrDA stuff */  irda_irnet_destroy(ap);  /* Disconnect from the generic PPP layer if not already done */  if(ap->ppp_open)    {      DERROR(FS_ERROR, "Channel still registered - deregistering !\n");      ppp_unregister_channel(&ap->chan);      ap->ppp_open = 0;    }  kfree(ap);  MOD_DEC_USE_COUNT;  DEXIT(FS_TRACE, "\n");  return 0;}/*------------------------------------------------------------------*//* * Write does nothing. * (we receive packet from ppp_generic through ppp_irnet_send()) */static ssize_tdev_irnet_write(struct file *	file,		const char *	buf,		size_t		count,		loff_t *	ppos){  irnet_socket *	ap = (struct irnet_socket *) file->private_data;  DPASS(FS_TRACE, "(file=0x%X, ap=0x%X, count=%d)\n",	(unsigned int) file, (unsigned int) ap, count);  DABORT(ap == NULL, -ENXIO, FS_ERROR, "ap is NULL !!!\n");  /* If we are connected to ppp_generic, let it handle the job */  if(ap->ppp_open)    return ppp_channel_write(&ap->chan, buf, count);  else    return irnet_ctrl_write(ap, buf, count);}/*------------------------------------------------------------------*//* * Read doesn't do much either. * (pppd poll us, but ultimately reads through /dev/ppp) */static ssize_tdev_irnet_read(struct file *	file,	       char *		buf,	       size_t		count,	       loff_t *		ppos){  irnet_socket *	ap = (struct irnet_socket *) file->private_data;  DPASS(FS_TRACE, "(file=0x%X, ap=0x%X, count=%d)\n",	(unsigned int) file, (unsigned int) ap, count);  DABORT(ap == NULL, -ENXIO, FS_ERROR, "ap is NULL !!!\n");  /* If we are connected to ppp_generic, let it handle the job */  if(ap->ppp_open)    return ppp_channel_read(&ap->chan, file, buf, count);  else    return irnet_ctrl_read(ap, file, buf, count);}/*------------------------------------------------------------------*//* * Poll : called when someone do a select on /dev/irnet */static unsigned intdev_irnet_poll(struct file *	file,	       poll_table *	wait){  irnet_socket *	ap = (struct irnet_socket *) file->private_data;  unsigned int		mask;  DENTER(FS_TRACE, "(file=0x%X, ap=0x%X)\n",	 (unsigned int) file, (unsigned int) ap);  mask = POLLOUT | POLLWRNORM;  DABORT(ap == NULL, mask, FS_ERROR, "ap is NULL !!!\n");  /* If we are connected to ppp_generic, let it handle the job */  if(ap->ppp_open)    mask |= ppp_channel_poll(&ap->chan, file, wait);

⌨️ 快捷键说明

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