📄 slip.c
字号:
}static void slip_unesc(struct slip *sl, unsigned char s){ switch(s) { case END:#ifdef CONFIG_SLIP_SMART /* drop keeptest bit = VSV */ if (test_bit(SLF_KEEPTEST, &sl->flags)) clear_bit(SLF_KEEPTEST, &sl->flags);#endif if (!test_and_clear_bit(SLF_ERROR, &sl->flags) && (sl->rcount > 2)) { sl_bump(sl); } clear_bit(SLF_ESCAPE, &sl->flags); sl->rcount = 0; return; case ESC: set_bit(SLF_ESCAPE, &sl->flags); return; case ESC_ESC: if (test_and_clear_bit(SLF_ESCAPE, &sl->flags)) { s = ESC; } break; case ESC_END: if (test_and_clear_bit(SLF_ESCAPE, &sl->flags)) { s = END; } break; } if (!test_bit(SLF_ERROR, &sl->flags)) { if (sl->rcount < sl->buffsize) { sl->rbuff[sl->rcount++] = s; return; } sl->rx_over_errors++; set_bit(SLF_ERROR, &sl->flags); }}#ifdef CONFIG_SLIP_MODE_SLIP6/************************************************************************ * 6 BIT SLIP ENCAPSULATION * ************************************************************************/intslip_esc6(unsigned char *s, unsigned char *d, int len){ unsigned char *ptr = d; unsigned char c; int i; unsigned short v = 0; short bits = 0; /* * Send an initial END character to flush out any * data that may have accumulated in the receiver * due to line noise. */ *ptr++ = 0x70; /* * Encode the packet into printable ascii characters */ for (i = 0; i < len; ++i) { v = (v << 8) | s[i]; bits += 8; while (bits >= 6) { bits -= 6; c = 0x30 + ((v >> bits) & 0x3F); *ptr++ = c; } } if (bits) { c = 0x30 + ((v << (6 - bits)) & 0x3F); *ptr++ = c; } *ptr++ = 0x70; return ptr - d;}voidslip_unesc6(struct slip *sl, unsigned char s){ unsigned char c; if (s == 0x70) {#ifdef CONFIG_SLIP_SMART /* drop keeptest bit = VSV */ if (test_bit(SLF_KEEPTEST, &sl->flags)) clear_bit(SLF_KEEPTEST, &sl->flags);#endif if (!test_and_clear_bit(SLF_ERROR, &sl->flags) && (sl->rcount > 2)) { sl_bump(sl); } sl->rcount = 0; sl->xbits = 0; sl->xdata = 0; } else if (s >= 0x30 && s < 0x70) { sl->xdata = (sl->xdata << 6) | ((s - 0x30) & 0x3F); sl->xbits += 6; if (sl->xbits >= 8) { sl->xbits -= 8; c = (unsigned char)(sl->xdata >> sl->xbits); if (!test_bit(SLF_ERROR, &sl->flags)) { if (sl->rcount < sl->buffsize) { sl->rbuff[sl->rcount++] = c; return; } sl->rx_over_errors++; set_bit(SLF_ERROR, &sl->flags); } } }}#endif /* CONFIG_SLIP_MODE_SLIP6 *//* Perform I/O control on an active SLIP channel. */static int slip_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg){ struct slip *sl = (struct slip *) tty->disc_data; unsigned int tmp; int __user *p = (int __user *)arg; /* First make sure we're connected. */ if (!sl || sl->magic != SLIP_MAGIC) { return -EINVAL; } switch(cmd) { case SIOCGIFNAME: tmp = strlen(sl->dev->name) + 1; if (copy_to_user((void __user *)arg, sl->dev->name, tmp)) return -EFAULT; return 0; case SIOCGIFENCAP: if (put_user(sl->mode, p)) return -EFAULT; return 0; case SIOCSIFENCAP: if (get_user(tmp, p)) return -EFAULT;#ifndef SL_INCLUDE_CSLIP if (tmp & (SL_MODE_CSLIP|SL_MODE_ADAPTIVE)) { return -EINVAL; }#else if ((tmp & (SL_MODE_ADAPTIVE | SL_MODE_CSLIP)) == (SL_MODE_ADAPTIVE | SL_MODE_CSLIP)) { /* return -EINVAL; */ tmp &= ~SL_MODE_ADAPTIVE; }#endif#ifndef CONFIG_SLIP_MODE_SLIP6 if (tmp & SL_MODE_SLIP6) { return -EINVAL; }#endif sl->mode = tmp; sl->dev->type = ARPHRD_SLIP+sl->mode; return 0; case SIOCSIFHWADDR: return -EINVAL;#ifdef CONFIG_SLIP_SMART /* VSV changes start here */ case SIOCSKEEPALIVE: if (get_user(tmp, p)) return -EFAULT; if (tmp > 255) /* max for unchar */ return -EINVAL; spin_lock_bh(&sl->lock); if (!sl->tty) { spin_unlock_bh(&sl->lock); return -ENODEV; } if ((sl->keepalive = (unchar) tmp) != 0) { mod_timer(&sl->keepalive_timer, jiffies+sl->keepalive*HZ); set_bit(SLF_KEEPTEST, &sl->flags); } else { del_timer (&sl->keepalive_timer); } spin_unlock_bh(&sl->lock); return 0; case SIOCGKEEPALIVE: if (put_user(sl->keepalive, p)) return -EFAULT; return 0; case SIOCSOUTFILL: if (get_user(tmp, p)) return -EFAULT; if (tmp > 255) /* max for unchar */ return -EINVAL; spin_lock_bh(&sl->lock); if (!sl->tty) { spin_unlock_bh(&sl->lock); return -ENODEV; } if ((sl->outfill = (unchar) tmp) != 0){ mod_timer(&sl->outfill_timer, jiffies+sl->outfill*HZ); set_bit(SLF_OUTWAIT, &sl->flags); } else { del_timer (&sl->outfill_timer); } spin_unlock_bh(&sl->lock); return 0; case SIOCGOUTFILL: if (put_user(sl->outfill, p)) return -EFAULT; return 0; /* VSV changes end */#endif /* Allow stty to read, but not set, the serial port */ case TCGETS: case TCGETA: return n_tty_ioctl(tty, file, cmd, arg); default: return -ENOIOCTLCMD; }}/* VSV changes start here */#ifdef CONFIG_SLIP_SMART/* function do_ioctl called from net/core/dev.c to allow get/set outfill/keepalive parameter by ifconfig */static int sl_ioctl(struct net_device *dev,struct ifreq *rq,int cmd){ struct slip *sl = (struct slip*)(dev->priv); unsigned long *p = (unsigned long *)&rq->ifr_ifru; if (sl == NULL) /* Allocation failed ?? */ return -ENODEV; spin_lock_bh(&sl->lock); if (!sl->tty) { spin_unlock_bh(&sl->lock); return -ENODEV; } switch(cmd){ case SIOCSKEEPALIVE: /* max for unchar */ if ((unsigned)*p > 255) { spin_unlock_bh(&sl->lock); return -EINVAL; } sl->keepalive = (unchar) *p; if (sl->keepalive != 0) { sl->keepalive_timer.expires=jiffies+sl->keepalive*HZ; mod_timer(&sl->keepalive_timer, jiffies+sl->keepalive*HZ); set_bit(SLF_KEEPTEST, &sl->flags); } else { del_timer(&sl->keepalive_timer); } break; case SIOCGKEEPALIVE: *p = sl->keepalive; break; case SIOCSOUTFILL: if ((unsigned)*p > 255) { /* max for unchar */ spin_unlock_bh(&sl->lock); return -EINVAL; } if ((sl->outfill = (unchar)*p) != 0){ mod_timer(&sl->outfill_timer, jiffies+sl->outfill*HZ); set_bit(SLF_OUTWAIT, &sl->flags); } else { del_timer (&sl->outfill_timer); } break; case SIOCGOUTFILL: *p = sl->outfill; break; case SIOCSLEASE: /* Resolve race condition, when ioctl'ing hanged up and opened by another process device. */ if (sl->tty != current->signal->tty && sl->pid != current->pid) { spin_unlock_bh(&sl->lock); return -EPERM; } sl->leased = 0; if (*p) sl->leased = 1; break; case SIOCGLEASE: *p = sl->leased; }; spin_unlock_bh(&sl->lock); return 0;}#endif/* VSV changes end */static struct tty_ldisc sl_ldisc = { .owner = THIS_MODULE, .magic = TTY_LDISC_MAGIC, .name = "slip", .open = slip_open, .close = slip_close, .ioctl = slip_ioctl, .receive_buf = slip_receive_buf, .receive_room = slip_receive_room, .write_wakeup = slip_write_wakeup,};static int __init slip_init(void){ int status; if (slip_maxdev < 4) slip_maxdev = 4; /* Sanity */ printk(KERN_INFO "SLIP: version %s (dynamic channels, max=%d)"#ifdef CONFIG_SLIP_MODE_SLIP6 " (6 bit encapsulation enabled)"#endif ".\n", SLIP_VERSION, slip_maxdev );#if defined(SL_INCLUDE_CSLIP) printk(KERN_INFO "CSLIP: code copyright 1989 Regents of the University of California.\n");#endif#ifdef CONFIG_SLIP_SMART printk(KERN_INFO "SLIP linefill/keepalive option.\n");#endif slip_devs = kmalloc(sizeof(struct net_device *)*slip_maxdev, GFP_KERNEL); if (!slip_devs) { printk(KERN_ERR "SLIP: Can't allocate slip devices array! Uaargh! (-> No SLIP available)\n"); return -ENOMEM; } /* Clear the pointer array, we allocate devices when we need them */ memset(slip_devs, 0, sizeof(struct net_device *)*slip_maxdev); /* Fill in our line protocol discipline, and register it */ if ((status = tty_register_ldisc(N_SLIP, &sl_ldisc)) != 0) { printk(KERN_ERR "SLIP: can't register line discipline (err = %d)\n", status); kfree(slip_devs); } return status;}static void __exit slip_exit(void){ int i; struct net_device *dev; struct slip *sl; unsigned long timeout = jiffies + HZ; int busy = 0; if (slip_devs == NULL) return; /* First of all: check for active disciplines and hangup them. */ do { if (busy) { set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(HZ / 10); } busy = 0; for (i = 0; i < slip_maxdev; i++) { dev = slip_devs[i]; if (!dev) continue; sl = dev->priv; spin_lock_bh(&sl->lock); if (sl->tty) { busy++; tty_hangup(sl->tty); } spin_unlock_bh(&sl->lock); } } while (busy && time_before(jiffies, timeout)); for (i = 0; i < slip_maxdev; i++) { dev = slip_devs[i]; if (!dev) continue; slip_devs[i] = NULL; sl = dev->priv; if (sl->tty) { printk(KERN_ERR "%s: tty discipline still running\n", dev->name); /* Intentionally leak the control block. */ dev->destructor = NULL; } unregister_netdev(dev); } kfree(slip_devs); slip_devs = NULL; if ((i = tty_register_ldisc(N_SLIP, NULL))) { printk(KERN_ERR "SLIP: can't unregister line discipline (err = %d)\n", i); }}module_init(slip_init);module_exit(slip_exit);#ifdef CONFIG_SLIP_SMART/* * This is start of the code for multislip style line checking * added by Stanislav Voronyi. All changes before marked VSV */static void sl_outfill(unsigned long sls){ struct slip *sl=(struct slip *)sls; spin_lock(&sl->lock); if (sl->tty == NULL) goto out; if(sl->outfill) { if( test_bit(SLF_OUTWAIT, &sl->flags) ) { /* no packets were transmitted, do outfill */#ifdef CONFIG_SLIP_MODE_SLIP6 unsigned char s = (sl->mode & SL_MODE_SLIP6)?0x70:END;#else unsigned char s = END;#endif /* put END into tty queue. Is it right ??? */ if (!netif_queue_stopped(sl->dev)) { /* if device busy no outfill */ sl->tty->driver->write(sl->tty, 0, &s, 1); } } else set_bit(SLF_OUTWAIT, &sl->flags); mod_timer(&sl->outfill_timer, jiffies+sl->outfill*HZ); }out: spin_unlock(&sl->lock);}static void sl_keepalive(unsigned long sls){ struct slip *sl=(struct slip *)sls; spin_lock(&sl->lock); if (sl->tty == NULL) goto out; if( sl->keepalive) { if(test_bit(SLF_KEEPTEST, &sl->flags)) { /* keepalive still high :(, we must hangup */ if( sl->outfill ) /* outfill timer must be deleted too */ (void)del_timer(&sl->outfill_timer); printk(KERN_DEBUG "%s: no packets received during keepalive timeout, hangup.\n", sl->dev->name); tty_hangup(sl->tty); /* this must hangup tty & close slip */ /* I think we need not something else */ goto out; } else set_bit(SLF_KEEPTEST, &sl->flags); mod_timer(&sl->keepalive_timer, jiffies+sl->keepalive*HZ); }out: spin_unlock(&sl->lock);}#endifMODULE_LICENSE("GPL");MODULE_ALIAS_LDISC(N_SLIP);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -