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

📄 irnet_ppp.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 3 页
字号:
/* *	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 *//* Please put other headers in irnet.h - Thanks *//* Generic PPP callbacks (to call us) */static struct ppp_channel_ops irnet_ppp_ops = {	.start_xmit = ppp_irnet_send,	.ioctl = ppp_irnet_ioctl};/************************* CONTROL CHANNEL *************************//* * When a pppd instance is not active on /dev/irnet, it acts as a control * channel. * Writing 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 __user *buf,		 size_t		count){  char		command[IRNET_MAX_COMMAND];  char *	start;		/* Current command being processed */  char *	next;		/* Next command to process */  int		length;		/* Length of current command */  DENTER(CTRL_TRACE, "(ap=0x%p, count=%Zd)\n", ap, count);  /* Check for overflow... */  DABORT(count >= IRNET_MAX_COMMAND, -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;    }  /* Safe terminate the string */  command[count] = '\0';  DEBUG(CTRL_INFO, "Command line received is ``%s'' (%Zd).\n",	command, count);  /* Check every commands in the command line */  next = command;  while(next != NULL)    {      /* Look at the next command */      start = next;      /* Scrap whitespaces before the command */      while(isspace(*start))	start++;      /* ',' is our command separator */      next = strchr(start, ',');      if(next)	{	  *next = '\0';			/* Terminate command */	  length = next - start;	/* Length */	  next++;			/* Skip the '\0' */	}      else	length = strlen(start);      DEBUG(CTRL_INFO, "Found command ``%s'' (%d).\n", start, length);      /* Check if we recognised one of the known command       * We can't use "switch" with strings, so hack with "continue" */            /* First command : name -> Requested IrDA nickname */      if(!strncmp(start, "name", 4))	{	  /* Copy the name only if is included and not "any" */	  if((length > 5) && (strcmp(start + 5, "any")))	    {	      /* Strip out trailing whitespaces */	      while(isspace(start[length - 1]))		length--;	      /* Copy the name for later reuse */	      memcpy(ap->rname, start + 5, length - 5);	      ap->rname[length - 5] = '\0';	    }	  else	    ap->rname[0] = '\0';	  DEBUG(CTRL_INFO, "Got rname = ``%s''\n", ap->rname);	  /* Restart the loop */	  continue;	}      /* Second command : addr, daddr -> Requested IrDA destination address       * Also process : saddr -> Requested IrDA source address */      if((!strncmp(start, "addr", 4)) ||	 (!strncmp(start, "daddr", 5)) ||	 (!strncmp(start, "saddr", 5)))	{	  __u32		addr = DEV_ADDR_ANY;	  /* Copy the address only if is included and not "any" */	  if((length > 5) && (strcmp(start + 5, "any")))	    {	      char *	begp = start + 5;	      char *	endp;	      /* Scrap whitespaces before the command */	      while(isspace(*begp))		begp++;	      /* Convert argument to a number (last arg is the base) */	      addr = simple_strtoul(begp, &endp, 16);	      /* Has it worked  ? (endp should be start + length) */	      DABORT(endp <= (start + 5), -EINVAL,		     CTRL_ERROR, "Invalid address.\n");	    }	  /* Which type of address ? */	  if(start[0] == 's')	    {	      /* Save it */	      ap->rsaddr = addr;	      DEBUG(CTRL_INFO, "Got rsaddr = %08x\n", ap->rsaddr);	    }	  else	    {	      /* Save it */	      ap->rdaddr = addr;	      DEBUG(CTRL_INFO, "Got rdaddr = %08x\n", ap->rdaddr);	    }	  /* Restart the loop */	  continue;	}      /* Other possible command : connect N (number of retries) */      /* No command matched -> Failed... */      DABORT(1, -EINVAL, CTRL_ERROR, "Not a recognised IrNET command.\n");    }  /* Success : we have parsed all commands successfully */  return(count);}#ifdef INITIAL_DISCOVERY/*------------------------------------------------------------------*//* * Function irnet_get_discovery_log (self) * *    Query the content on the discovery log if not done * * This function query the current content of the discovery log * at the startup of the event channel and save it in the internal struct. */static voidirnet_get_discovery_log(irnet_socket *	ap){  __u16		mask = irlmp_service_to_hint(S_LAN);  /* Ask IrLMP for the current discovery log */  ap->discoveries = irlmp_get_discoveries(&ap->disco_number, mask,					  DISCOVERY_DEFAULT_SLOTS);  /* Check if the we got some results */  if(ap->discoveries == NULL)    ap->disco_number = -1;  DEBUG(CTRL_INFO, "Got the log (0x%p), size is %d\n",	ap->discoveries, ap->disco_number);}/*------------------------------------------------------------------*//* * Function irnet_read_discovery_log (self, event) * *    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 wrote an event on the control channel... * * State of the ap->disco_XXX variables : * Socket creation :  discoveries = NULL ; disco_index = 0 ; disco_number = 0 * While reading :    discoveries = ptr  ; disco_index = X ; disco_number = Y * After reading :    discoveries = NULL ; 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%p, event=0x%p)\n",	 ap, 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->discoveries == NULL)    irnet_get_discovery_log(ap);  /* Check if we have more item to dump */  if(ap->disco_index < ap->disco_number)    {      /* Write an event */      sprintf(event, "Found %08x (%s) behind %08x {hints %02X-%02X}\n",	      ap->discoveries[ap->disco_index].daddr,	      ap->discoveries[ap->disco_index].info,	      ap->discoveries[ap->disco_index].saddr,	      ap->discoveries[ap->disco_index].hints[0],	      ap->discoveries[ap->disco_index].hints[1]);      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%p)\n",	    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 __user *	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%p, count=%Zd)\n", 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 %Zd\n", ret);      return ret;    }  /* Which event is it ? */  switch(irnet_events.log[ap->event_index].event)    {    case IRNET_DISCOVER:      sprintf(event, "Discovered %08x (%s) behind %08x {hints %02X-%02X}\n",	      irnet_events.log[ap->event_index].daddr,	      irnet_events.log[ap->event_index].name,	      irnet_events.log[ap->event_index].saddr,	      irnet_events.log[ap->event_index].hints.byte[0],	      irnet_events.log[ap->event_index].hints.byte[1]);      break;    case IRNET_EXPIRE:      sprintf(event, "Expired %08x (%s) behind %08x {hints %02X-%02X}\n",	      irnet_events.log[ap->event_index].daddr,	      irnet_events.log[ap->event_index].name,	      irnet_events.log[ap->event_index].saddr,	      irnet_events.log[ap->event_index].hints.byte[0],	      irnet_events.log[ap->event_index].hints.byte[1]);      break;    case IRNET_CONNECT_TO:      sprintf(event, "Connected to %08x (%s) on ppp%d\n",	      irnet_events.log[ap->event_index].daddr,	      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].daddr,	      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) behind %08x\n",	      irnet_events.log[ap->event_index].daddr,	      irnet_events.log[ap->event_index].name,	      irnet_events.log[ap->event_index].saddr);      break;    case IRNET_NOANSWER_FROM:      sprintf(event, "No-answer from %08x (%s) on ppp%d\n",	      irnet_events.log[ap->event_index].daddr,	      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].daddr,	      irnet_events.log[ap->event_index].name,

⌨️ 快捷键说明

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