📄 irnet_ppp.c
字号:
/* * 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 + -