#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define NETLINK_TAPBASE 24 void HexChar(const void* vBytes,int aLen) { int i,start=0; char tmp[128]; char* tmp_ptr=tmp; const u8* aBytes = (const u8*)vBytes; printk(KERN_INFO "0x%p +\n",vBytes); while(start=0x20)tmp_ptr+=sprintf(tmp_ptr,"%c",aBytes[i]); else tmp_ptr+=sprintf(tmp_ptr,"."); } else tmp_ptr+=sprintf(tmp_ptr," "); } start+=16; printk(KERN_INFO "%s\n",tmp); tmp_ptr=tmp; } } void skb_dump(const struct sk_buff *skb) { if(skb) do { unsigned int size = skb_end_offset(skb) + skb->data_len; printk(KERN_INFO "--------------------------------------------\n"); printk(KERN_INFO "x25tap skb = %p\n",skb); printk(KERN_INFO "x25tap skb->next = %p\n",skb->next); printk(KERN_INFO "x25tap skb->prev = %p\n",skb->prev); printk(KERN_INFO "x25tap skb->sk = %p\n",skb->sk); printk(KERN_INFO "x25tap skb->len = %d\n",skb->len); printk(KERN_INFO "x25tap skb->truesize = %d\n",skb->truesize); printk(KERN_INFO "x25tap skb->users = %d\n",skb->users.counter); printk(KERN_INFO "x25tap skb_headlen(skb) = %d\n", skb_headlen(skb)); printk(KERN_INFO "x25tap skb_headroom(skb) = %d\n", skb_headroom(skb)); printk(KERN_INFO "x25tap skb_end_offset(skb) = %d\n", skb_end_offset(skb)); printk(KERN_INFO "x25tap skb->data_len = %d\n", skb->data_len); printk(KERN_INFO "x25tap size = %d\n", size); printk(KERN_INFO "x25tap skb->head = %p\n",skb->head); printk(KERN_INFO "x25tap skb->data = %p\n",skb->data); printk(KERN_INFO "x25tap skb->tail = %d\n",skb->tail); printk(KERN_INFO "x25tap skb->end = %d\n",skb->end); printk(KERN_INFO "x25tap skb->mac_header = %d\n",skb->mac_header); printk(KERN_INFO "x25tap skb->mac_len = %d\n",skb->mac_len); printk(KERN_INFO "-HEAD-------------------------------------------\n"); HexChar(skb->head,skb_headroom(skb)); printk(KERN_INFO "-DATA-------------------------------------------\n"); HexChar(skb->data,skb->len); printk(KERN_INFO "-CB-------------------------------------------\n"); HexChar(skb->cb,sizeof(skb->cb)); printk(KERN_INFO "--------------------------------------------\n"); }while(0); else printk(KERN_INFO "x25tap skb NULL\n"); } struct x25tap_dev { int unit; struct sock *nls; //link to netlink struct net_device_stats stats; }; static struct net_device **tap_map; static int max_taps = 1; module_param(max_taps, int, 0); MODULE_PARM_DESC(max_taps, "Max number of x25 tap devices"); //static int x25tap_debug = 5; static void x25tap_rx_skb(struct sk_buff *skb) { unsigned unit = skb->sk->sk_protocol - NETLINK_TAPBASE; struct net_device *dev; struct x25tap_dev *x25tap; struct sk_buff* __skb; unsigned char* dptr; int len; if (unit >= max_taps || (dev = tap_map[unit]) == NULL) { printk(KERN_CRIT "x25tap: bad unit %u!\n", unit); skb_queue_purge(&skb->sk->sk_receive_queue); // kfree_skb(skb); return;// -ENODEV } x25tap = netdev_priv(dev); len = skb->len; if(len < 19){ printk(KERN_INFO "%s : rx len = %d\n", dev->name, len); // kfree_skb(skb); x25tap->stats.rx_errors++; return;// -EINVAL; } if (NETLINK_CREDS(skb)->uid.val) { printk(KERN_INFO "%s : user %d\n", dev->name, NETLINK_CREDS(skb)->uid.val); // kfree_skb(skb); return;// -EPERM; } skb_pull(skb,16); len = skb->data[0] + skb->data[1] * 256; skb_pull(skb, 2); skb_trim(skb, len); if((__skb = dev_alloc_skb(skb->len)) == NULL) { printk(KERN_INFO "%s : dev_alloc_skb(%d) == NULL\n", dev->name,skb->len); return; } // skb_dump(skb); if (skb->data[0] == 0) { x25tap->stats.rx_packets++; x25tap->stats.rx_bytes += len; } dptr = skb_put(__skb,skb->len); memcpy(dptr,skb->data,skb->len); printk(KERN_INFO "x25tap rx_skb device %s rx %d bytes\n",dev->name,len); __skb->protocol=x25_type_trans(__skb,dev); // skb_dump(__skb); // kfree_skb(skb);!!!!! do nt open: fatal damage !!!!! netif_rx(__skb); } static int x25tap_open(struct net_device *dev) { struct x25tap_dev *x25tap = netdev_priv(dev); struct netlink_kernel_cfg cfg = { .groups = 1, .input = x25tap_rx_skb, }; x25tap->nls = NULL; x25tap->nls = netlink_kernel_create(&init_net,x25tap->unit,&cfg); if(!x25tap->nls) return -EIO; netif_start_queue(dev); printk(KERN_INFO "x25tap open device %s (%p)\n",dev->name,x25tap->nls); return 0; } static int x25tap_close(struct net_device *dev) { struct x25tap_dev *x25tap = netdev_priv(dev); struct sock *sk = x25tap->nls; netif_stop_queue(dev); if(sk){ x25tap->nls = NULL; netlink_kernel_release(sk); } printk(KERN_INFO "x25tap close device %s (%p)\n",dev->name,sk); return 0; } /* * We transmit by throwing the packet at netlink. We have to clone * it for 2.0 so that we dev_kfree_skb() the locked original. */ static int x25tap_xmit(struct sk_buff *skb, struct net_device *dev) { unsigned char *dptr; struct x25tap_dev *lp = netdev_priv(dev); struct nlmsghdr *nlh; struct sk_buff *__skb = nlmsg_new(skb->len + 2, GFP_ATOMIC); if (__skb == NULL) { lp->stats.tx_dropped++; kfree_skb(skb); return 0; } nlh = nlmsg_put(__skb, 0, 0, NLMSG_DONE, skb->len + 2, 0); NETLINK_CB(__skb).dst_group = 1; NETLINK_CREDS(__skb)->pid = 0; dptr = nlmsg_data(nlh); *dptr++ = skb->len % 256; *dptr++ = skb->len / 256; memcpy(dptr, skb->data, skb->len); // skb_dump(__skb); switch (skb->data[0]) { case 0x00: /* Data request */ lp->stats.tx_bytes+=skb->len -1; lp->stats.tx_packets++; break; case 0x01: /* Connection request, do nothing */ printk(KERN_INFO "x25tap_start_xmit: Connection request\n"); break; case 0x02: /* Disconnect request */ printk(KERN_INFO "x25tap_start_xmit: Disconnect request\n"); break; default: printk(KERN_INFO "x25tap_start_xmit: unknown firstbyte\n"); lp->stats.tx_dropped++; kfree_skb(skb); return -1; break; } kfree_skb(skb); if(lp->nls)netlink_broadcast(lp->nls, __skb, 0, 1, GFP_ATOMIC); else kfree_skb(__skb); return 0; } static struct net_device_stats *x25tap_get_stats(struct net_device *dev) { struct x25tap_dev *x25tap = netdev_priv(dev); struct net_device_stats *stats = &x25tap->stats; return stats; } static const struct net_device_ops x25tap_netdevice_ops = { .ndo_open = x25tap_open, .ndo_stop = x25tap_close, .ndo_start_xmit = x25tap_xmit, .ndo_get_stats = x25tap_get_stats, }; static void x25tap_setup(struct net_device *dev) { dev->netdev_ops = &x25tap_netdevice_ops; dev->flags |= IFF_NOARP; dev->mtu = 1031;//1024; dev->hard_header_len = 1; dev->addr_len = 0; dev->type = ARPHRD_X25; dev->tx_queue_len = 10; } static int __init x25tap_probe(int unit) { struct net_device *ndev; int rc = -ENOMEM; struct x25tap_dev *lp; printk(KERN_INFO "x25tap create unit %d\n",unit); ndev = alloc_netdev(sizeof(struct x25tap_dev), "x25tap%d", x25tap_setup); if (!ndev) goto out; // dev_net_set(ndev,&init_net); rc = -EIO; if (register_netdev(ndev)) goto fail; printk(KERN_INFO "x25tap register unit %d\n",unit); tap_map[unit] = ndev; lp = netdev_priv(ndev); lp->unit = unit + NETLINK_TAPBASE; rc = 0; out: return rc; fail: free_netdev(ndev); goto out; } static int __init x25tap_init(void) { int i, err = 0; printk(KERN_INFO "x25tap --- init driver version 0.03 ---\n"); /* netlink can only hande 8 entries unless modified */ if (max_taps > MAX_LINKS - NETLINK_TAPBASE) return -E2BIG; tap_map = kmalloc(sizeof(struct net_device *)*max_taps, GFP_KERNEL); if (!tap_map) return -ENOMEM; for (i = 0; i < max_taps; i++) { err = x25tap_probe(i); if (err) { while (--i > 0) { unregister_netdev(tap_map[i]); free_netdev(tap_map[i]); } break; } } if (err) kfree(tap_map); return err; } module_init(x25tap_init); void __exit x25tap_cleanup(void) { int i; for (i = 0; i < max_taps; i++) { struct net_device *dev = tap_map[i]; if (dev) { tap_map[i] = NULL; unregister_netdev(dev); printk(KERN_INFO "x25tap unregister unit %d\n",i); free_netdev(dev); printk(KERN_INFO "x25tap delete unit %d\n",i); } } kfree(tap_map); printk(KERN_INFO "x25tap --- done driver version 0.03 ---\n"); } module_exit(x25tap_cleanup); MODULE_AUTHOR("Pavel Nagornyi