📄 slip.c
字号:
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 intslip_ioctl(struct tty_struct *tty, void *file, int cmd, void *arg){ struct slip *sl = (struct slip *) tty->disc_data; unsigned int tmp; /* First make sure we're connected. */ if (!sl || sl->magic != SLIP_MAGIC) { return -EINVAL; } switch(cmd) { case SIOCGIFNAME: /* Please, do not put this line under copy_to_user, it breaks my old poor gcc on alpha --ANK */ tmp = strlen(sl->dev->name) + 1; if (copy_to_user(arg, sl->dev->name, tmp)) return -EFAULT; return 0; case SIOCGIFENCAP: if (put_user(sl->mode, (int *)arg)) return -EFAULT; return 0; case SIOCSIFENCAP: if (get_user(tmp,(int *)arg)) 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,(int *)arg)) 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, (int *)arg)) return -EFAULT; return 0; case SIOCSOUTFILL: if (get_user(tmp,(int *)arg)) 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, (int *)arg)) 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, (struct file *) file, cmd, (unsigned long) 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); 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 int)((unsigned long)rq->ifr_data)) > 255) { spin_unlock_bh(&sl->lock); return -EINVAL; } sl->keepalive = (unchar) ((unsigned long)rq->ifr_data); 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: rq->ifr_data=(caddr_t)((unsigned long)sl->keepalive); break; case SIOCSOUTFILL: if (((unsigned)((unsigned long)rq->ifr_data)) > 255) { /* max for unchar */ spin_unlock_bh(&sl->lock); return -EINVAL; } if ((sl->outfill = (unchar)((unsigned long) rq->ifr_data)) != 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: rq->ifr_data=(caddr_t)((unsigned long)sl->outfill); break; case SIOCSLEASE: /* Resolve race condition, when ioctl'ing hanged up and opened by another process device. */ if (sl->tty != current->tty && sl->pid != current->pid) { spin_unlock_bh(&sl->lock); return -EPERM; } sl->leased = 0; if ((unsigned long)rq->ifr_data) sl->leased = 1; break; case SIOCGLEASE: rq->ifr_data=(caddr_t)((unsigned long)sl->leased); }; spin_unlock_bh(&sl->lock); return 0;}#endif/* VSV changes end *//* Initialize SLIP control device -- register SLIP line discipline */int __init slip_init_ctrl_dev(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) && !defined(MODULE) printk("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_ctrls = (slip_ctrl_t **) kmalloc(sizeof(void*)*slip_maxdev, GFP_KERNEL); if (slip_ctrls == NULL) { printk("SLIP: Can't allocate slip_ctrls[] array! Uaargh! (-> No SLIP available)\n"); return -ENOMEM; } /* Clear the pointer array, we allocate devices when we need them */ memset(slip_ctrls, 0, sizeof(void*)*slip_maxdev); /* Pointers */ /* Fill in our line protocol discipline, and register it */ memset(&sl_ldisc, 0, sizeof(sl_ldisc)); sl_ldisc.magic = TTY_LDISC_MAGIC; sl_ldisc.name = "slip"; sl_ldisc.flags = 0; sl_ldisc.open = slip_open; sl_ldisc.close = slip_close; sl_ldisc.read = NULL; sl_ldisc.write = NULL; sl_ldisc.ioctl = (int (*)(struct tty_struct *, struct file *, unsigned int, unsigned long)) slip_ioctl; sl_ldisc.poll = NULL; sl_ldisc.receive_buf = slip_receive_buf; sl_ldisc.receive_room = slip_receive_room; sl_ldisc.write_wakeup = slip_write_wakeup; if ((status = tty_register_ldisc(N_SLIP, &sl_ldisc)) != 0) { printk("SLIP: can't register line discipline (err = %d)\n", status); } return status;}#ifdef MODULEintinit_module(void){ return slip_init_ctrl_dev();}voidcleanup_module(void){ int i; if (slip_ctrls != NULL) { unsigned long start = jiffies; int busy = 0; /* First of all: check for active disciplines and hangup them. */ do { if (busy) { current->counter = 0; schedule(); } busy = 0; local_bh_disable(); for (i = 0; i < slip_maxdev; i++) { struct slip_ctrl *slc = slip_ctrls[i]; if (!slc) continue; spin_lock(&slc->ctrl.lock); if (slc->ctrl.tty) { busy++; tty_hangup(slc->ctrl.tty); } spin_unlock(&slc->ctrl.lock); } local_bh_enable(); } while (busy && jiffies - start < 1*HZ); busy = 0; for (i = 0; i < slip_maxdev; i++) { struct slip_ctrl *slc = slip_ctrls[i]; if (slc) { unregister_netdev(&slc->dev); if (slc->ctrl.tty) { printk("%s: tty discipline is still running\n", slc->dev.name); /* Pin module forever */ MOD_INC_USE_COUNT; busy++; continue; } sl_free_bufs(&slc->ctrl); kfree(slc); slip_ctrls[i] = NULL; } } if (!busy) { kfree(slip_ctrls); slip_ctrls = NULL; } } if ((i = tty_register_ldisc(N_SLIP, NULL))) { printk("SLIP: can't unregister line discipline (err = %d)\n", i); }}#endif /* MODULE */#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("%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);}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -