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);


Reply via email to