Hi all! I'm hacking on a target written by myself. I used dev_queue_xmit( ) to send a packet directly to another device( usb0 ), and returns NF_STOLEN. Is there any limit on using dev_queue_xmit( ) in a target function? I've got a low rate( 200 kbps on a usb data cable), but if I use a user space program transfer files between two hosts which the cable connected, the rate is 8Mbps. Why? ps,I've noticed that dev_queue_xmit( ) often returns NET_XMIT_DROP.
Regards Yangrunhua Here is the src: /* * This is a module which is used for logging packets. */ #include <linux/module.h> #include <linux/skbuff.h> #include <linux/ip.h> #include <linux/spinlock.h> #include <net/icmp.h> #include <net/udp.h> #include <net/tcp.h> #include <linux/netfilter_ipv4/ip_tables.h> struct in_device; #include <net/route.h> #include <linux/netfilter_ipv4/ipt_USBDEV.h> //#define DEBUG #if defined(DEBUG) #define DEBUGP printk #else #define DEBUGP(format, args...) #endif #define UNLINK_TIMEOUT_JIFFIES ((3 /*ms*/ * HZ)/1000) #define USBSENDQLEN 100 static struct sk_buff_head usb_sendq; static struct tasklet_struct usbsend_bh; static spinlock_t unload_mutex = SPIN_LOCK_UNLOCKED; static unsigned int ipt_USBDEV_target(struct sk_buff **pskb, unsigned int hooknum, const struct net_device *in, const struct net_device *out, const void *targinfo, void *userinfo) { struct iphdr *iph = (*pskb)->nh.iph; const struct ipt_usbdev_info *usbdevinfo = targinfo; unsigned long lockflags; static int i = 0; static char devname[14]; struct net_device *dev; #ifdef DEBUG if (in->name) printk(KERN_ALERT"card name:%s\n",in->name); #endif DEBUGP(KERN_ALERT "USBDEV:src=%u.%u.%u.%u dst=%u.%u.%u.%u len=%d\n", NIPQUAD(iph->saddr), NIPQUAD(iph->daddr), (*pskb)->len); devname[13] = 0; spin_lock(&unload_mutex); do{ i %= usbdevinfo->nr_usb; sprintf(devname,"usb%d",i); dev = dev_get_by_name(devname); i++; if (dev){ break; } }while(i < usbdevinfo->nr_usb); if (!dev) goto drop; DEBUGP(KERN_ALERT "USBDEV: select %s refcnt %d\n", dev->name, atomic_read(&dev->refcnt)); spin_lock_irqsave (&usb_sendq.lock,lockflags); (*pskb)->dev = dev; if (usb_sendq.qlen < USBSENDQLEN){ __skb_queue_tail (&usb_sendq, *pskb); if (usb_sendq.qlen == 1){ tasklet_schedule(&usbsend_bh); } }else { kfree_skb(*pskb); dev_put(dev); } spin_unlock_irqrestore (&usb_sendq.lock,lockflags); spin_unlock(&unload_mutex); return NF_STOLEN; drop: DEBUGP(KERN_ALERT "USBDEV: drop because of none dev\n"); spin_unlock(&unload_mutex); dev_kfree_skb_any(*pskb); return NF_STOLEN; } #define USBERR 33 static inline int usbsend_cont(struct sk_buff *skb) { struct net_device *dev = skb->dev; skb_push (skb, dev->hard_header_len); dev_queue_xmit(skb); dev_put(dev); return 0; } static void usbsend_bh_func (unsigned long param) { struct sk_buff *skb; struct net_device *dev; DEBUGP(KERN_ALERT "Enter usbsend_bh len = %d\n", skb_queue_len(&usb_sendq)); while ((skb = skb_dequeue (&usb_sendq))) { dev = skb->dev; usbsend_cont(skb); } } static int ipt_usbdev_checkentry(const char *tablename, const struct ipt_entry *e, void *targinfo, unsigned int targinfosize, unsigned int hook_mask) { const struct ipt_usbdev_info *usbdevinfo = targinfo; if (targinfosize != IPT_ALIGN(sizeof(struct ipt_usbdev_info))) { DEBUGP("USBDEV: targinfosize %u != %u\n", targinfosize, IPT_ALIGN(sizeof(struct ipt_usbdev_info))); return 0; } if (usbdevinfo->nr_usb <= 0) { DEBUGP("USBDEV: level <= 0\n"); return 0; } return 1; } static struct ipt_target ipt_USBDEV_reg = { { NULL, NULL }, "USBDEV", ipt_USBDEV_target, ipt_usbdev_checkentry, NULL, THIS_MODULE }; static int __init init(void) { skb_queue_head_init (&usb_sendq); usbsend_bh.func = usbsend_bh_func; usbsend_bh.data = (unsigned long)0; if (ipt_register_target(&ipt_USBDEV_reg)) return -EINVAL; return 0; } static void __exit fini(void) { ipt_unregister_target(&ipt_USBDEV_reg); spin_lock_bh(&unload_mutex); // maybe wait for deletions to finish. while ( skb_queue_len (&usb_sendq)) { current->state = TASK_UNINTERRUPTIBLE; schedule_timeout (UNLINK_TIMEOUT_JIFFIES); } spin_unlock_bh(&unload_mutex); } module_init(init); module_exit(fini);