📄 mkiss.c
字号:
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 net_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. */ 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 */ netif_start_queue(dev); return 0;noxbuff: kfree(ax->rbuff);norbuff: return -ENOMEM;}/* Close the low-level part of the AX25 channel. Easy! */static int ax_close(struct net_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); netif_stop_queue(dev); 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 || !netif_running(ax->dev)) 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); tty_ldisc_flush(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 (netif_running(&ax25_ctrls[cnt]->dev)) { 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; /* First make sure we're connected. */ if (ax == NULL || ax->magic != AX25_MAGIC) return; unregister_netdev(ax->dev); tty->disc_data = 0; ax->tty = NULL; ax_free(ax); MOD_DEC_USE_COUNT;}static struct net_device_stats *ax_get_stats(struct net_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_bytes = ax->rx_bytes; stats.tx_bytes = ax->tx_bytes; 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 * ************************************************************************/static 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=0; *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){ switch (s) { case END: /* drop keeptest bit = VSV */ if (test_bit(AXF_KEEPTEST, &ax->flags)) clear_bit(AXF_KEEPTEST, &ax->flags); if (!test_and_clear_bit(AXF_ERROR, &ax->flags) && (ax->rcount > 2)) ax_bump(ax); clear_bit(AXF_ESCAPE, &ax->flags); ax->rcount = 0; return; case ESC: set_bit(AXF_ESCAPE, &ax->flags); return; case ESC_ESC: if (test_and_clear_bit(AXF_ESCAPE, &ax->flags)) s = ESC; break; case ESC_END: if (test_and_clear_bit(AXF_ESCAPE, &ax->flags)) s = END; break; } if (!test_bit(AXF_ERROR, &ax->flags)) { if (ax->rcount < ax->buffsize) { ax->rbuff[ax->rcount++] = s; return; } ax->rx_over_errors++; set_bit(AXF_ERROR, &ax->flags); }}static int ax_set_mac_address(struct net_device *dev, void *addr){ if (copy_from_user(dev->dev_addr, addr, AX25_ADDR_LEN)) return -EFAULT; return 0;}static int ax_set_dev_mac_address(struct net_device *dev, void *addr){ struct sockaddr *sa = addr; memcpy(dev->dev_addr, sa->sa_data, AX25_ADDR_LEN); return 0;}/* Perform I/O control on an active ax25 channel. */static int ax25_disp_ioctl(struct tty_struct *tty, void *file, int cmd, void *arg){ struct ax_disp *ax = (struct ax_disp *) tty->disc_data; unsigned int tmp; /* First make sure we're connected. */ if (ax == NULL || ax->magic != AX25_MAGIC) return -EINVAL; switch (cmd) { case SIOCGIFNAME: if (copy_to_user(arg, ax->dev->name, strlen(ax->dev->name) + 1)) return -EFAULT; return 0; case SIOCGIFENCAP: return put_user(4, (int *)arg); case SIOCSIFENCAP: if (get_user(tmp, (int *)arg)) return -EFAULT; ax->mode = tmp; ax->dev->addr_len = AX25_ADDR_LEN; /* sizeof an AX.25 addr */ ax->dev->hard_header_len = AX25_KISS_HEADER_LEN + AX25_MAX_HEADER_LEN + 3; ax->dev->type = ARPHRD_AX25; return 0; case SIOCSIFHWADDR: return ax_set_mac_address(ax->dev, arg); default: return -ENOIOCTLCMD; }}static int ax_open_dev(struct net_device *dev){ struct ax_disp *ax = (struct ax_disp *) dev->priv; if (ax->tty == NULL) return -ENODEV; return 0;}/* Initialize the driver. Called by network startup. */static int ax25_init(struct net_device *dev){ struct ax_disp *ax = (struct ax_disp *) dev->priv; static char ax25_bcast[AX25_ADDR_LEN] = {'Q'<<1,'S'<<1,'T'<<1,' '<<1,' '<<1,' '<<1,'0'<<1}; static char ax25_test[AX25_ADDR_LEN] = {'L'<<1,'I'<<1,'N'<<1,'U'<<1,'X'<<1,' '<<1,'1'<<1}; if (ax == NULL) /* Allocation failed ?? */ return -ENODEV; /* Set up the "AX25 Control Block". (And clear statistics) */ memset(ax, 0, sizeof (struct ax_disp)); ax->magic = AX25_MAGIC; ax->dev = dev; /* Finish setting up the DEVICE info. */ dev->mtu = AX_MTU; dev->hard_start_xmit = ax_xmit; dev->open = ax_open_dev; dev->stop = ax_close; dev->get_stats = ax_get_stats; dev->set_mac_address = ax_set_dev_mac_address; dev->hard_header_len = 0; dev->addr_len = 0; dev->type = ARPHRD_AX25; dev->tx_queue_len = 10; dev->hard_header = ax_header; dev->rebuild_header = ax_rebuild_header; memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN); memcpy(dev->dev_addr, ax25_test, AX25_ADDR_LEN); /* New-style flags. */ dev->flags = IFF_BROADCAST | IFF_MULTICAST; return 0;}/* ******************************************************************** *//* * Init MKISS driver * *//* ******************************************************************** */static int __init mkiss_init_driver(void){ int status; printk(banner); if (ax25_maxdev < 4) ax25_maxdev = 4; /* Sanity */ if ((ax25_ctrls = kmalloc(sizeof(void *) * ax25_maxdev, GFP_KERNEL)) == NULL) { printk(KERN_ERR "mkiss: Can't allocate ax25_ctrls[] array!\n"); return -ENOMEM; } /* Clear the pointer array, we allocate devices when we need them */ memset(ax25_ctrls, 0, sizeof(void*) * ax25_maxdev); /* Pointers */ /* Fill in our line protocol discipline, and register it */ ax_ldisc.magic = TTY_LDISC_MAGIC; ax_ldisc.name = "mkiss"; ax_ldisc.open = ax25_open; ax_ldisc.close = ax25_close; ax_ldisc.ioctl = (int (*)(struct tty_struct *, struct file *, unsigned int, unsigned long))ax25_disp_ioctl; ax_ldisc.receive_buf = ax25_receive_buf; ax_ldisc.receive_room = ax25_receive_room; ax_ldisc.write_wakeup = ax25_write_wakeup; if ((status = tty_register_ldisc(N_AX25, &ax_ldisc)) != 0) { printk(KERN_ERR "mkiss: can't register line discipline (err = %d)\n", status); kfree(ax25_ctrls); } return status;}static void __exit mkiss_exit_driver(void){ int i; for (i = 0; i < ax25_maxdev; i++) { if (ax25_ctrls[i]) { /* * VSV = if dev->start==0, then device * unregistered while close proc. */ if (netif_running(&ax25_ctrls[i]->dev)) unregister_netdev(&ax25_ctrls[i]->dev); kfree(ax25_ctrls[i]); } } kfree(ax25_ctrls); ax25_ctrls = NULL; if ((i = tty_register_ldisc(N_AX25, NULL))) printk(KERN_ERR "mkiss: can't unregister line discipline (err = %d)\n", i);}MODULE_AUTHOR("Hans Albas PE1AYX <hans@esrac.ele.tue.nl>");MODULE_DESCRIPTION("KISS driver for AX.25 over TTYs");MODULE_PARM(ax25_maxdev, "i");MODULE_PARM_DESC(ax25_maxdev, "number of MKISS devices");MODULE_LICENSE("GPL");module_init(mkiss_init_driver);module_exit(mkiss_exit_driver);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -