📄 mkiss.c
字号:
actual = ax->mkiss->tty->driver.write(ax->mkiss->tty, 0, ax->mkiss->xbuff, count); ax->tx_packets++; ax->mkiss->dev->trans_start = jiffies; ax->mkiss->xleft = count - actual; ax->mkiss->xhead = ax->mkiss->xbuff + actual; }}/* * Called by the driver when there's room for more data. If we have * more packets to send, we send them here. */static void ax25_write_wakeup(struct tty_struct *tty){ int actual; struct ax_disp *ax = (struct ax_disp *)tty->disc_data; struct mkiss_channel *mkiss; /* First make sure we're connected. */ if (ax == NULL || ax->magic != AX25_MAGIC || !ax->dev->start) return; if (ax->xleft <= 0) { /* Now serial buffer is almost free & we can start * transmission of another packet */ tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); if (ax->mkiss != NULL) { mkiss= ax->mkiss->tty->driver_data; if (mkiss->magic == MKISS_DRIVER_MAGIC) ax_unlock(ax->mkiss); } ax_unlock(ax); mark_bh(NET_BH); return; } actual = tty->driver.write(tty, 0, ax->xhead, ax->xleft); ax->xleft -= actual; ax->xhead += actual;}/* Encapsulate an AX.25 packet and kick it into a TTY queue. */static int ax_xmit(struct sk_buff *skb, struct device *dev){ struct ax_disp *ax = (struct ax_disp*)dev->priv; struct mkiss_channel *mkiss = ax->tty->driver_data; struct ax_disp *tmp_ax; tmp_ax = NULL; if (mkiss->magic == MKISS_DRIVER_MAGIC) { if (skb->data[0] < 0x10) skb->data[0] = skb->data[0] + 0x10; tmp_ax = ax->mkiss; } if (!dev->start) { printk(KERN_ERR "mkiss: %s: xmit call when iface is down\n", dev->name); return 1; } if (tmp_ax != NULL) if (tmp_ax->dev->tbusy) return 1; if (tmp_ax != NULL) if (dev->tbusy) { printk(KERN_ERR "mkiss: dev busy while serial dev is free\n"); ax_unlock(ax); } if (dev->tbusy) { /* * May be we must check transmitter timeout here ? * 14 Oct 1994 Dmitry Gorodchanin. */ if (jiffies - dev->trans_start < 20 * HZ) { /* 20 sec timeout not reached */ return 1; } printk(KERN_ERR "mkiss: %s: transmit timed out, %s?\n", dev->name, (ax->tty->driver.chars_in_buffer(ax->tty) || ax->xleft) ? "bad line quality" : "driver error"); ax->xleft = 0; ax->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); ax_unlock(ax); } /* We were not busy, so we are now... :-) */ if (skb != NULL) { ax_lock(ax); if (tmp_ax != NULL) ax_lock(tmp_ax); ax_encaps(ax, skb->data, skb->len); kfree_skb(skb); } return 0;}#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)/* Return the frame type ID */static int ax_header(struct sk_buff *skb, struct device *dev, unsigned short type, void *daddr, void *saddr, unsigned len){#ifdef CONFIG_INET if (type != htons(ETH_P_AX25)) return ax25_encapsulate(skb, dev, type, daddr, saddr, len);#endif return 0;}static int ax_rebuild_header(struct sk_buff *skb){#ifdef CONFIG_INET return ax25_rebuild_header(skb);#else return 0;#endif}#endif /* CONFIG_{AX25,AX25_MODULE} *//* Open the low-level part of the AX25 channel. Easy! */static int ax_open(struct device *dev){ struct ax_disp *ax = (struct ax_disp*)dev->priv; unsigned long len; if (ax->tty == NULL) return -ENODEV; /* * Allocate the frame buffers: * * rbuff Receive buffer. * xbuff Transmit buffer. * cbuff Temporary compression buffer. */ len = dev->mtu * 2; /* * allow for arrival of larger UDP packets, even if we say not to * also fixes a bug in which SunOS sends 512-byte packets even with * an MSS of 128 */ if (len < 576 * 2) len = 576 * 2; if ((ax->rbuff = kmalloc(len + 4, GFP_KERNEL)) == NULL) goto norbuff; if ((ax->xbuff = kmalloc(len + 4, GFP_KERNEL)) == NULL) goto noxbuff; ax->mtu = dev->mtu + 73; ax->buffsize = len; ax->rcount = 0; ax->xleft = 0; ax->flags &= (1 << AXF_INUSE); /* Clear ESCAPE & ERROR flags */ dev->tbusy = 0; dev->start = 1; return 0; /* Cleanup */ kfree(ax->xbuff);noxbuff: kfree(ax->rbuff);norbuff: return -ENOMEM;}/* Close the low-level part of the AX25 channel. Easy! */static int ax_close(struct device *dev){ struct ax_disp *ax = (struct ax_disp*)dev->priv; if (ax->tty == NULL) return -EBUSY; ax->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); dev->tbusy = 1; dev->start = 0; return 0;}static int ax25_receive_room(struct tty_struct *tty){ return 65536; /* We can handle an infinite amount of data. :-) */}/* * Handle the 'receiver data ready' interrupt. * This function is called by the 'tty_io' module in the kernel when * a block of data has been received, which can now be decapsulated * and sent on to the AX.25 layer for further processing. */static void ax25_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, int count){ struct ax_disp *ax = (struct ax_disp *)tty->disc_data; if (ax == NULL || ax->magic != AX25_MAGIC || !ax->dev->start) return; /* * Argh! mtu change time! - costs us the packet part received * at the change */ if (ax->mtu != ax->dev->mtu + 73) ax_changedmtu(ax); /* Read the characters out of the buffer */ while (count--) { if (fp != NULL && *fp++) { if (!test_and_set_bit(AXF_ERROR, &ax->flags)) ax->rx_errors++; cp++; continue; } kiss_unesc(ax, *cp++); }}static int ax25_open(struct tty_struct *tty){ struct ax_disp *ax = (struct ax_disp *)tty->disc_data; struct ax_disp *tmp_ax; struct mkiss_channel *mkiss; int err, cnt; /* First make sure we're not already connected. */ if (ax && ax->magic == AX25_MAGIC) return -EEXIST; /* OK. Find a free AX25 channel to use. */ if ((ax = ax_alloc()) == NULL) return -ENFILE; ax->tty = tty; tty->disc_data = ax; ax->mkiss = NULL; tmp_ax = NULL; if (tty->driver.flush_buffer) tty->driver.flush_buffer(tty); if (tty->ldisc.flush_buffer) tty->ldisc.flush_buffer(tty); /* Restore default settings */ ax->dev->type = ARPHRD_AX25; /* Perform the low-level AX25 initialization. */ if ((err = ax_open(ax->dev))) return err; mkiss= ax->tty->driver_data; if (mkiss->magic == MKISS_DRIVER_MAGIC) { for (cnt = 1; cnt < ax25_maxdev; cnt++) { if (ax25_ctrls[cnt]) { if (ax25_ctrls[cnt]->dev.start) { if (ax == &ax25_ctrls[cnt]->ctrl) { cnt--; tmp_ax = &ax25_ctrls[cnt]->ctrl; break; } } } } } if (tmp_ax != NULL) { ax->mkiss = tmp_ax; tmp_ax->mkiss = ax; } MOD_INC_USE_COUNT; /* Done. We have linked the TTY line to a channel. */ return ax->dev->base_addr;}static void ax25_close(struct tty_struct *tty){ struct ax_disp *ax = (struct ax_disp *)tty->disc_data; int mkiss ; /* First make sure we're connected. */ if (ax == NULL || ax->magic != AX25_MAGIC) return; mkiss = ax->mode; dev_close(ax->dev); tty->disc_data = 0; ax->tty = NULL; /* VSV = very important to remove timers */ ax_free(ax); unregister_netdev(ax->dev); MOD_DEC_USE_COUNT;}static struct net_device_stats *ax_get_stats(struct device *dev){ static struct net_device_stats stats; struct ax_disp *ax = (struct ax_disp*)dev->priv; memset(&stats, 0, sizeof(struct net_device_stats)); stats.rx_packets = ax->rx_packets; stats.tx_packets = ax->tx_packets; stats.rx_dropped = ax->rx_dropped; stats.tx_dropped = ax->tx_dropped; stats.tx_errors = ax->tx_errors; stats.rx_errors = ax->rx_errors; stats.rx_over_errors = ax->rx_over_errors; return &stats;}/************************************************************************ * STANDARD ENCAPSULATION * ************************************************************************/int kiss_esc(unsigned char *s, unsigned char *d, int len){ unsigned char *ptr = d; unsigned char c; /* * Send an initial END character to flush out any * data that may have accumulated in the receiver * due to line noise. */ *ptr++ = END; while (len-- > 0) { switch (c = *s++) { case END: *ptr++ = ESC; *ptr++ = ESC_END; break; case ESC: *ptr++ = ESC; *ptr++ = ESC_ESC; break; default: *ptr++ = c; break; } } *ptr++ = END; return ptr - d;}/* * MW: * OK its ugly, but tell me a better solution without copying the * packet to a temporary buffer :-) */static int kiss_esc_crc(unsigned char *s, unsigned char *d, unsigned short crc, int len){ unsigned char *ptr = d; unsigned char c; *ptr++ = END; while (len > 0) { if (len > 2) c = *s++; else if (len > 1) c = crc >> 8; else if (len > 0) c = crc & 0xff; len--; switch (c) { case END: *ptr++ = ESC; *ptr++ = ESC_END; break; case ESC: *ptr++ = ESC; *ptr++ = ESC_ESC; break; default: *ptr++ = c; break; } } *ptr++ = END; return ptr - d; }static void kiss_unesc(struct ax_disp *ax, unsigned char s)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -