📄 irnet_ppp.c
字号:
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; ap->chan.ops = &irnet_ppp_ops; ap->chan.mtu = (2048 - TTP_MAX_HEADER - 2 - PPP_HDRLEN); ap->chan.hdrlen = 2 + TTP_MAX_HEADER; /* for A/C + Max IrDA hdr */ /* PPP parameters */ ap->mru = (2048 - TTP_MAX_HEADER - 2 - PPP_HDRLEN); 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 -EAGAIN; 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 -EAGAIN; 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 |= 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 in configued in dev_irnet_open())*/ 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; /* 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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -