OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [net/] [core/] [pktgen.c] - Diff between revs 1278 and 1765

Only display areas with differences | Details | Blame | View Log

Rev 1278 Rev 1765
/* -*-linux-c-*-
/* -*-linux-c-*-
 * $Id: pktgen.c,v 1.1.1.1 2004-04-17 22:13:21 phoenix Exp $
 * $Id: pktgen.c,v 1.1.1.1 2004-04-17 22:13:21 phoenix Exp $
 * pktgen.c: Packet Generator for performance evaluation.
 * pktgen.c: Packet Generator for performance evaluation.
 *
 *
 * Copyright 2001, 2002 by Robert Olsson <robert.olsson@its.uu.se>
 * Copyright 2001, 2002 by Robert Olsson <robert.olsson@its.uu.se>
 *                                 Uppsala University, Sweden
 *                                 Uppsala University, Sweden
 *
 *
 * A tool for loading the network with preconfigurated packets.
 * A tool for loading the network with preconfigurated packets.
 * The tool is implemented as a linux module.  Parameters are output
 * The tool is implemented as a linux module.  Parameters are output
 * device, IPG (interpacket gap), number of packets, and whether
 * device, IPG (interpacket gap), number of packets, and whether
 * to use multiple SKBs or just the same one.
 * to use multiple SKBs or just the same one.
 * pktgen uses the installed interface's output routine.
 * pktgen uses the installed interface's output routine.
 *
 *
 * Additional hacking by:
 * Additional hacking by:
 *
 *
 * Jens.Laas@data.slu.se
 * Jens.Laas@data.slu.se
 * Improved by ANK. 010120.
 * Improved by ANK. 010120.
 * Improved by ANK even more. 010212.
 * Improved by ANK even more. 010212.
 * MAC address typo fixed. 010417 --ro
 * MAC address typo fixed. 010417 --ro
 * Integrated.  020301 --DaveM
 * Integrated.  020301 --DaveM
 * Added multiskb option 020301 --DaveM
 * Added multiskb option 020301 --DaveM
 * Scaling of results. 020417--sigurdur@linpro.no
 * Scaling of results. 020417--sigurdur@linpro.no
 * Significant re-work of the module:
 * Significant re-work of the module:
 *   *  Updated to support generation over multiple interfaces at once
 *   *  Updated to support generation over multiple interfaces at once
 *       by creating 32 /proc/net/pg* files.  Each file can be manipulated
 *       by creating 32 /proc/net/pg* files.  Each file can be manipulated
 *       individually.
 *       individually.
 *   *  Converted many counters to __u64 to allow longer runs.
 *   *  Converted many counters to __u64 to allow longer runs.
 *   *  Allow configuration of ranges, like min/max IP address, MACs,
 *   *  Allow configuration of ranges, like min/max IP address, MACs,
 *       and UDP-ports, for both source and destination, and can
 *       and UDP-ports, for both source and destination, and can
 *       set to use a random distribution or sequentially walk the range.
 *       set to use a random distribution or sequentially walk the range.
 *   *  Can now change some values after starting.
 *   *  Can now change some values after starting.
 *   *  Place 12-byte packet in UDP payload with magic number,
 *   *  Place 12-byte packet in UDP payload with magic number,
 *       sequence number, and timestamp.  Will write receiver next.
 *       sequence number, and timestamp.  Will write receiver next.
 *   *  The new changes seem to have a performance impact of around 1%,
 *   *  The new changes seem to have a performance impact of around 1%,
 *       as far as I can tell.
 *       as far as I can tell.
 *   --Ben Greear <greearb@candelatech.com>
 *   --Ben Greear <greearb@candelatech.com>
 *
 *
 * Renamed multiskb to clone_skb and cleaned up sending core for two distinct
 * Renamed multiskb to clone_skb and cleaned up sending core for two distinct
 * skb modes. A clone_skb=0 mode for Ben "ranges" work and a clone_skb != 0
 * skb modes. A clone_skb=0 mode for Ben "ranges" work and a clone_skb != 0
 * as a "fastpath" with a configurable number of clones after alloc's.
 * as a "fastpath" with a configurable number of clones after alloc's.
 *
 *
 * clone_skb=0 means all packets are allocated this also means ranges time
 * clone_skb=0 means all packets are allocated this also means ranges time
 * stamps etc can be used. clone_skb=100 means 1 malloc is followed by 100
 * stamps etc can be used. clone_skb=100 means 1 malloc is followed by 100
 * clones.
 * clones.
 *
 *
 * Also moved to /proc/net/pktgen/
 * Also moved to /proc/net/pktgen/
 * --ro
 * --ro
 *
 *
 * Fix refcount off by one if first packet fails, potential null deref,
 * Fix refcount off by one if first packet fails, potential null deref,
 * memleak 030710- KJP
 * memleak 030710- KJP
 *
 *
 * See Documentation/networking/pktgen.txt for how to use this.
 * See Documentation/networking/pktgen.txt for how to use this.
 */
 */
 
 
#include <linux/module.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/sched.h>
#include <linux/types.h>
#include <linux/types.h>
#include <linux/string.h>
#include <linux/string.h>
#include <linux/ptrace.h>
#include <linux/ptrace.h>
#include <linux/errno.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/ioport.h>
#include <linux/slab.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/init.h>
#include <linux/inet.h>
#include <linux/inet.h>
#include <asm/byteorder.h>
#include <asm/byteorder.h>
#include <asm/bitops.h>
#include <asm/bitops.h>
#include <asm/io.h>
#include <asm/io.h>
#include <asm/dma.h>
#include <asm/dma.h>
#include <asm/uaccess.h>
#include <asm/uaccess.h>
 
 
#include <linux/in.h>
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/ip.h>
#include <linux/udp.h>
#include <linux/udp.h>
#include <linux/skbuff.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
#include <linux/netdevice.h>
#include <linux/inetdevice.h>
#include <linux/inetdevice.h>
#include <linux/rtnetlink.h>
#include <linux/rtnetlink.h>
#include <linux/proc_fs.h>
#include <linux/proc_fs.h>
#include <linux/if_arp.h>
#include <linux/if_arp.h>
#include <net/checksum.h>
#include <net/checksum.h>
#include <asm/timex.h>
#include <asm/timex.h>
 
 
#define cycles()        ((u32)get_cycles())
#define cycles()        ((u32)get_cycles())
 
 
 
 
#define VERSION "pktgen version 1.3"
#define VERSION "pktgen version 1.3"
static char version[] __initdata =
static char version[] __initdata =
  "pktgen.c: v1.3: Packet Generator for packet performance testing.\n";
  "pktgen.c: v1.3: Packet Generator for packet performance testing.\n";
 
 
/* Used to help with determining the pkts on receive */
/* Used to help with determining the pkts on receive */
 
 
#define PKTGEN_MAGIC 0xbe9be955
#define PKTGEN_MAGIC 0xbe9be955
 
 
 
 
/* Keep information per interface */
/* Keep information per interface */
struct pktgen_info {
struct pktgen_info {
        /* Parameters */
        /* Parameters */
 
 
        /* If min != max, then we will either do a linear iteration, or
        /* If min != max, then we will either do a linear iteration, or
         * we will do a random selection from within the range.
         * we will do a random selection from within the range.
         */
         */
        __u32 flags;
        __u32 flags;
 
 
#define F_IPSRC_RND   (1<<0)  /* IP-Src Random  */
#define F_IPSRC_RND   (1<<0)  /* IP-Src Random  */
#define F_IPDST_RND   (1<<1)  /* IP-Dst Random  */
#define F_IPDST_RND   (1<<1)  /* IP-Dst Random  */
#define F_UDPSRC_RND  (1<<2)  /* UDP-Src Random */
#define F_UDPSRC_RND  (1<<2)  /* UDP-Src Random */
#define F_UDPDST_RND  (1<<3)  /* UDP-Dst Random */
#define F_UDPDST_RND  (1<<3)  /* UDP-Dst Random */
#define F_MACSRC_RND  (1<<4)  /* MAC-Src Random */
#define F_MACSRC_RND  (1<<4)  /* MAC-Src Random */
#define F_MACDST_RND  (1<<5)  /* MAC-Dst Random */
#define F_MACDST_RND  (1<<5)  /* MAC-Dst Random */
#define F_SET_SRCMAC  (1<<6)  /* Specify-Src-Mac 
#define F_SET_SRCMAC  (1<<6)  /* Specify-Src-Mac 
                                 (default is to use Interface's MAC Addr) */
                                 (default is to use Interface's MAC Addr) */
#define F_SET_SRCIP   (1<<7)  /*  Specify-Src-IP
#define F_SET_SRCIP   (1<<7)  /*  Specify-Src-IP
                                  (default is to use Interface's IP Addr) */
                                  (default is to use Interface's IP Addr) */
 
 
 
 
        int pkt_size;    /* = ETH_ZLEN; */
        int pkt_size;    /* = ETH_ZLEN; */
        int nfrags;
        int nfrags;
        __u32 ipg;       /* Default Interpacket gap in nsec */
        __u32 ipg;       /* Default Interpacket gap in nsec */
        __u64 count;     /* Default No packets to send */
        __u64 count;     /* Default No packets to send */
        __u64 sofar;     /* How many pkts we've sent so far */
        __u64 sofar;     /* How many pkts we've sent so far */
        __u64 errors;    /* Errors when trying to transmit, pkts will be re-sent */
        __u64 errors;    /* Errors when trying to transmit, pkts will be re-sent */
        struct timeval started_at;
        struct timeval started_at;
        struct timeval stopped_at;
        struct timeval stopped_at;
        __u64 idle_acc;
        __u64 idle_acc;
        __u32 seq_num;
        __u32 seq_num;
 
 
        int clone_skb;   /* Use multiple SKBs during packet gen.  If this number
        int clone_skb;   /* Use multiple SKBs during packet gen.  If this number
                          * is greater than 1, then that many coppies of the same
                          * is greater than 1, then that many coppies of the same
                          * packet will be sent before a new packet is allocated.
                          * packet will be sent before a new packet is allocated.
                          * For instance, if you want to send 1024 identical packets
                          * For instance, if you want to send 1024 identical packets
                          * before creating a new packet, set clone_skb to 1024.
                          * before creating a new packet, set clone_skb to 1024.
                          */
                          */
        int busy;
        int busy;
        int do_run_run;   /* if this changes to false, the test will stop */
        int do_run_run;   /* if this changes to false, the test will stop */
 
 
        char outdev[32];
        char outdev[32];
        char dst_min[32];
        char dst_min[32];
        char dst_max[32];
        char dst_max[32];
        char src_min[32];
        char src_min[32];
        char src_max[32];
        char src_max[32];
 
 
        /* If we're doing ranges, random or incremental, then this
        /* If we're doing ranges, random or incremental, then this
         * defines the min/max for those ranges.
         * defines the min/max for those ranges.
         */
         */
        __u32 saddr_min; /* inclusive, source IP address */
        __u32 saddr_min; /* inclusive, source IP address */
        __u32 saddr_max; /* exclusive, source IP address */
        __u32 saddr_max; /* exclusive, source IP address */
        __u32 daddr_min; /* inclusive, dest IP address */
        __u32 daddr_min; /* inclusive, dest IP address */
        __u32 daddr_max; /* exclusive, dest IP address */
        __u32 daddr_max; /* exclusive, dest IP address */
 
 
        __u16 udp_src_min; /* inclusive, source UDP port */
        __u16 udp_src_min; /* inclusive, source UDP port */
        __u16 udp_src_max; /* exclusive, source UDP port */
        __u16 udp_src_max; /* exclusive, source UDP port */
        __u16 udp_dst_min; /* inclusive, dest UDP port */
        __u16 udp_dst_min; /* inclusive, dest UDP port */
        __u16 udp_dst_max; /* exclusive, dest UDP port */
        __u16 udp_dst_max; /* exclusive, dest UDP port */
 
 
        __u32 src_mac_count; /* How many MACs to iterate through */
        __u32 src_mac_count; /* How many MACs to iterate through */
        __u32 dst_mac_count; /* How many MACs to iterate through */
        __u32 dst_mac_count; /* How many MACs to iterate through */
 
 
        unsigned char dst_mac[6];
        unsigned char dst_mac[6];
        unsigned char src_mac[6];
        unsigned char src_mac[6];
 
 
        __u32 cur_dst_mac_offset;
        __u32 cur_dst_mac_offset;
        __u32 cur_src_mac_offset;
        __u32 cur_src_mac_offset;
        __u32 cur_saddr;
        __u32 cur_saddr;
        __u32 cur_daddr;
        __u32 cur_daddr;
        __u16 cur_udp_dst;
        __u16 cur_udp_dst;
        __u16 cur_udp_src;
        __u16 cur_udp_src;
 
 
        __u8 hh[14];
        __u8 hh[14];
        /* = {
        /* = {
           0x00, 0x80, 0xC8, 0x79, 0xB3, 0xCB,
           0x00, 0x80, 0xC8, 0x79, 0xB3, 0xCB,
 
 
           We fill in SRC address later
           We fill in SRC address later
           0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
           0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
           0x08, 0x00
           0x08, 0x00
           };
           };
        */
        */
        __u16 pad; /* pad out the hh struct to an even 16 bytes */
        __u16 pad; /* pad out the hh struct to an even 16 bytes */
        char result[512];
        char result[512];
 
 
        /* proc file names */
        /* proc file names */
        char fname[80];
        char fname[80];
        char busy_fname[80];
        char busy_fname[80];
 
 
        struct proc_dir_entry *proc_ent;
        struct proc_dir_entry *proc_ent;
        struct proc_dir_entry *busy_proc_ent;
        struct proc_dir_entry *busy_proc_ent;
};
};
 
 
struct pktgen_hdr {
struct pktgen_hdr {
        __u32 pgh_magic;
        __u32 pgh_magic;
        __u32 seq_num;
        __u32 seq_num;
        struct timeval timestamp;
        struct timeval timestamp;
};
};
 
 
static int cpu_speed;
static int cpu_speed;
static int debug;
static int debug;
 
 
/* Module parameters, defaults. */
/* Module parameters, defaults. */
static int count_d = 100000;
static int count_d = 100000;
static int ipg_d = 0;
static int ipg_d = 0;
static int clone_skb_d = 0;
static int clone_skb_d = 0;
 
 
 
 
#define MAX_PKTGEN 8
#define MAX_PKTGEN 8
static struct pktgen_info pginfos[MAX_PKTGEN];
static struct pktgen_info pginfos[MAX_PKTGEN];
 
 
 
 
/** Convert to miliseconds */
/** Convert to miliseconds */
inline __u64 tv_to_ms(const struct timeval* tv) {
inline __u64 tv_to_ms(const struct timeval* tv) {
        __u64 ms = tv->tv_usec / 1000;
        __u64 ms = tv->tv_usec / 1000;
        ms += (__u64)tv->tv_sec * (__u64)1000;
        ms += (__u64)tv->tv_sec * (__u64)1000;
        return ms;
        return ms;
}
}
 
 
inline __u64 getCurMs(void) {
inline __u64 getCurMs(void) {
        struct timeval tv;
        struct timeval tv;
        do_gettimeofday(&tv);
        do_gettimeofday(&tv);
        return tv_to_ms(&tv);
        return tv_to_ms(&tv);
}
}
 
 
#define PG_PROC_DIR "pktgen"
#define PG_PROC_DIR "pktgen"
static struct proc_dir_entry *proc_dir = 0;
static struct proc_dir_entry *proc_dir = 0;
 
 
static struct net_device *setup_inject(struct pktgen_info* info)
static struct net_device *setup_inject(struct pktgen_info* info)
{
{
        struct net_device *odev;
        struct net_device *odev;
 
 
        rtnl_lock();
        rtnl_lock();
        odev = __dev_get_by_name(info->outdev);
        odev = __dev_get_by_name(info->outdev);
        if (!odev) {
        if (!odev) {
                sprintf(info->result, "No such netdevice: \"%s\"", info->outdev);
                sprintf(info->result, "No such netdevice: \"%s\"", info->outdev);
                goto out_unlock;
                goto out_unlock;
        }
        }
 
 
        if (odev->type != ARPHRD_ETHER) {
        if (odev->type != ARPHRD_ETHER) {
                sprintf(info->result, "Not ethernet device: \"%s\"", info->outdev);
                sprintf(info->result, "Not ethernet device: \"%s\"", info->outdev);
                goto out_unlock;
                goto out_unlock;
        }
        }
 
 
        if (!netif_running(odev)) {
        if (!netif_running(odev)) {
                sprintf(info->result, "Device is down: \"%s\"", info->outdev);
                sprintf(info->result, "Device is down: \"%s\"", info->outdev);
                goto out_unlock;
                goto out_unlock;
        }
        }
 
 
        /* Default to the interface's mac if not explicitly set. */
        /* Default to the interface's mac if not explicitly set. */
        if (!(info->flags & F_SET_SRCMAC)) {
        if (!(info->flags & F_SET_SRCMAC)) {
                memcpy(&(info->hh[6]), odev->dev_addr, 6);
                memcpy(&(info->hh[6]), odev->dev_addr, 6);
        }
        }
        else {
        else {
                memcpy(&(info->hh[6]), info->src_mac, 6);
                memcpy(&(info->hh[6]), info->src_mac, 6);
        }
        }
 
 
        /* Set up Dest MAC */
        /* Set up Dest MAC */
        memcpy(&(info->hh[0]), info->dst_mac, 6);
        memcpy(&(info->hh[0]), info->dst_mac, 6);
 
 
        info->saddr_min = 0;
        info->saddr_min = 0;
        info->saddr_max = 0;
        info->saddr_max = 0;
        if (strlen(info->src_min) == 0) {
        if (strlen(info->src_min) == 0) {
                if (odev->ip_ptr) {
                if (odev->ip_ptr) {
                        struct in_device *in_dev = odev->ip_ptr;
                        struct in_device *in_dev = odev->ip_ptr;
 
 
                        if (in_dev->ifa_list) {
                        if (in_dev->ifa_list) {
                                info->saddr_min = in_dev->ifa_list->ifa_address;
                                info->saddr_min = in_dev->ifa_list->ifa_address;
                                info->saddr_max = info->saddr_min;
                                info->saddr_max = info->saddr_min;
                        }
                        }
                }
                }
        }
        }
        else {
        else {
                info->saddr_min = in_aton(info->src_min);
                info->saddr_min = in_aton(info->src_min);
                info->saddr_max = in_aton(info->src_max);
                info->saddr_max = in_aton(info->src_max);
        }
        }
 
 
        info->daddr_min = in_aton(info->dst_min);
        info->daddr_min = in_aton(info->dst_min);
        info->daddr_max = in_aton(info->dst_max);
        info->daddr_max = in_aton(info->dst_max);
 
 
        /* Initialize current values. */
        /* Initialize current values. */
        info->cur_dst_mac_offset = 0;
        info->cur_dst_mac_offset = 0;
        info->cur_src_mac_offset = 0;
        info->cur_src_mac_offset = 0;
        info->cur_saddr = info->saddr_min;
        info->cur_saddr = info->saddr_min;
        info->cur_daddr = info->daddr_min;
        info->cur_daddr = info->daddr_min;
        info->cur_udp_dst = info->udp_dst_min;
        info->cur_udp_dst = info->udp_dst_min;
        info->cur_udp_src = info->udp_src_min;
        info->cur_udp_src = info->udp_src_min;
 
 
        atomic_inc(&odev->refcnt);
        atomic_inc(&odev->refcnt);
        rtnl_unlock();
        rtnl_unlock();
 
 
        return odev;
        return odev;
 
 
out_unlock:
out_unlock:
        rtnl_unlock();
        rtnl_unlock();
        return NULL;
        return NULL;
}
}
 
 
static void nanospin(int ipg, struct pktgen_info* info)
static void nanospin(int ipg, struct pktgen_info* info)
{
{
        u32 idle_start, idle;
        u32 idle_start, idle;
 
 
        idle_start = cycles();
        idle_start = cycles();
 
 
        for (;;) {
        for (;;) {
                barrier();
                barrier();
                idle = cycles() - idle_start;
                idle = cycles() - idle_start;
                if (idle * 1000 >= ipg * cpu_speed)
                if (idle * 1000 >= ipg * cpu_speed)
                        break;
                        break;
        }
        }
        info->idle_acc += idle;
        info->idle_acc += idle;
}
}
 
 
static int calc_mhz(void)
static int calc_mhz(void)
{
{
        struct timeval start, stop;
        struct timeval start, stop;
        u32 start_s, elapsed;
        u32 start_s, elapsed;
 
 
        do_gettimeofday(&start);
        do_gettimeofday(&start);
        start_s = cycles();
        start_s = cycles();
        do {
        do {
                barrier();
                barrier();
                elapsed = cycles() - start_s;
                elapsed = cycles() - start_s;
                if (elapsed == 0)
                if (elapsed == 0)
                        return 0;
                        return 0;
        } while (elapsed < 1000 * 50000);
        } while (elapsed < 1000 * 50000);
        do_gettimeofday(&stop);
        do_gettimeofday(&stop);
        return elapsed/(stop.tv_usec-start.tv_usec+1000000*(stop.tv_sec-start.tv_sec));
        return elapsed/(stop.tv_usec-start.tv_usec+1000000*(stop.tv_sec-start.tv_sec));
}
}
 
 
static void cycles_calibrate(void)
static void cycles_calibrate(void)
{
{
        int i;
        int i;
 
 
        for (i = 0; i < 3; i++) {
        for (i = 0; i < 3; i++) {
                int res = calc_mhz();
                int res = calc_mhz();
                if (res > cpu_speed)
                if (res > cpu_speed)
                        cpu_speed = res;
                        cpu_speed = res;
        }
        }
}
}
 
 
 
 
/* Increment/randomize headers according to flags and current values
/* Increment/randomize headers according to flags and current values
 * for IP src/dest, UDP src/dst port, MAC-Addr src/dst
 * for IP src/dest, UDP src/dst port, MAC-Addr src/dst
 */
 */
static void mod_cur_headers(struct pktgen_info* info) {
static void mod_cur_headers(struct pktgen_info* info) {
        __u32 imn;
        __u32 imn;
        __u32 imx;
        __u32 imx;
 
 
        /*  Deal with source MAC */
        /*  Deal with source MAC */
        if (info->src_mac_count > 1) {
        if (info->src_mac_count > 1) {
                __u32 mc;
                __u32 mc;
                __u32 tmp;
                __u32 tmp;
                if (info->flags & F_MACSRC_RND) {
                if (info->flags & F_MACSRC_RND) {
                        mc = net_random() % (info->src_mac_count);
                        mc = net_random() % (info->src_mac_count);
                }
                }
                else {
                else {
                        mc = info->cur_src_mac_offset++;
                        mc = info->cur_src_mac_offset++;
                        if (info->cur_src_mac_offset > info->src_mac_count) {
                        if (info->cur_src_mac_offset > info->src_mac_count) {
                                info->cur_src_mac_offset = 0;
                                info->cur_src_mac_offset = 0;
                        }
                        }
                }
                }
 
 
                tmp = info->src_mac[5] + (mc & 0xFF);
                tmp = info->src_mac[5] + (mc & 0xFF);
                info->hh[11] = tmp;
                info->hh[11] = tmp;
                tmp = (info->src_mac[4] + ((mc >> 8) & 0xFF) + (tmp >> 8));
                tmp = (info->src_mac[4] + ((mc >> 8) & 0xFF) + (tmp >> 8));
                info->hh[10] = tmp;
                info->hh[10] = tmp;
                tmp = (info->src_mac[3] + ((mc >> 16) & 0xFF) + (tmp >> 8));
                tmp = (info->src_mac[3] + ((mc >> 16) & 0xFF) + (tmp >> 8));
                info->hh[9] = tmp;
                info->hh[9] = tmp;
                tmp = (info->src_mac[2] + ((mc >> 24) & 0xFF) + (tmp >> 8));
                tmp = (info->src_mac[2] + ((mc >> 24) & 0xFF) + (tmp >> 8));
                info->hh[8] = tmp;
                info->hh[8] = tmp;
                tmp = (info->src_mac[1] + (tmp >> 8));
                tmp = (info->src_mac[1] + (tmp >> 8));
                info->hh[7] = tmp;
                info->hh[7] = tmp;
        }
        }
 
 
        /*  Deal with Destination MAC */
        /*  Deal with Destination MAC */
        if (info->dst_mac_count > 1) {
        if (info->dst_mac_count > 1) {
                __u32 mc;
                __u32 mc;
                __u32 tmp;
                __u32 tmp;
                if (info->flags & F_MACDST_RND) {
                if (info->flags & F_MACDST_RND) {
                        mc = net_random() % (info->dst_mac_count);
                        mc = net_random() % (info->dst_mac_count);
                }
                }
                else {
                else {
                        mc = info->cur_dst_mac_offset++;
                        mc = info->cur_dst_mac_offset++;
                        if (info->cur_dst_mac_offset > info->dst_mac_count) {
                        if (info->cur_dst_mac_offset > info->dst_mac_count) {
                                info->cur_dst_mac_offset = 0;
                                info->cur_dst_mac_offset = 0;
                        }
                        }
                }
                }
 
 
                tmp = info->dst_mac[5] + (mc & 0xFF);
                tmp = info->dst_mac[5] + (mc & 0xFF);
                info->hh[5] = tmp;
                info->hh[5] = tmp;
                tmp = (info->dst_mac[4] + ((mc >> 8) & 0xFF) + (tmp >> 8));
                tmp = (info->dst_mac[4] + ((mc >> 8) & 0xFF) + (tmp >> 8));
                info->hh[4] = tmp;
                info->hh[4] = tmp;
                tmp = (info->dst_mac[3] + ((mc >> 16) & 0xFF) + (tmp >> 8));
                tmp = (info->dst_mac[3] + ((mc >> 16) & 0xFF) + (tmp >> 8));
                info->hh[3] = tmp;
                info->hh[3] = tmp;
                tmp = (info->dst_mac[2] + ((mc >> 24) & 0xFF) + (tmp >> 8));
                tmp = (info->dst_mac[2] + ((mc >> 24) & 0xFF) + (tmp >> 8));
                info->hh[2] = tmp;
                info->hh[2] = tmp;
                tmp = (info->dst_mac[1] + (tmp >> 8));
                tmp = (info->dst_mac[1] + (tmp >> 8));
                info->hh[1] = tmp;
                info->hh[1] = tmp;
        }
        }
 
 
        if (info->udp_src_min < info->udp_src_max) {
        if (info->udp_src_min < info->udp_src_max) {
                if (info->flags & F_UDPSRC_RND) {
                if (info->flags & F_UDPSRC_RND) {
                        info->cur_udp_src = ((net_random() % (info->udp_src_max - info->udp_src_min))
                        info->cur_udp_src = ((net_random() % (info->udp_src_max - info->udp_src_min))
                                             + info->udp_src_min);
                                             + info->udp_src_min);
                }
                }
                else {
                else {
                     info->cur_udp_src++;
                     info->cur_udp_src++;
                     if (info->cur_udp_src >= info->udp_src_max) {
                     if (info->cur_udp_src >= info->udp_src_max) {
                             info->cur_udp_src = info->udp_src_min;
                             info->cur_udp_src = info->udp_src_min;
                     }
                     }
                }
                }
        }
        }
 
 
        if (info->udp_dst_min < info->udp_dst_max) {
        if (info->udp_dst_min < info->udp_dst_max) {
                if (info->flags & F_UDPDST_RND) {
                if (info->flags & F_UDPDST_RND) {
                        info->cur_udp_dst = ((net_random() % (info->udp_dst_max - info->udp_dst_min))
                        info->cur_udp_dst = ((net_random() % (info->udp_dst_max - info->udp_dst_min))
                                             + info->udp_dst_min);
                                             + info->udp_dst_min);
                }
                }
                else {
                else {
                     info->cur_udp_dst++;
                     info->cur_udp_dst++;
                     if (info->cur_udp_dst >= info->udp_dst_max) {
                     if (info->cur_udp_dst >= info->udp_dst_max) {
                             info->cur_udp_dst = info->udp_dst_min;
                             info->cur_udp_dst = info->udp_dst_min;
                     }
                     }
                }
                }
        }
        }
 
 
        if ((imn = ntohl(info->saddr_min)) < (imx = ntohl(info->saddr_max))) {
        if ((imn = ntohl(info->saddr_min)) < (imx = ntohl(info->saddr_max))) {
                __u32 t;
                __u32 t;
                if (info->flags & F_IPSRC_RND) {
                if (info->flags & F_IPSRC_RND) {
                        t = ((net_random() % (imx - imn)) + imn);
                        t = ((net_random() % (imx - imn)) + imn);
                }
                }
                else {
                else {
                     t = ntohl(info->cur_saddr);
                     t = ntohl(info->cur_saddr);
                     t++;
                     t++;
                     if (t >= imx) {
                     if (t >= imx) {
                             t = imn;
                             t = imn;
                     }
                     }
                }
                }
                info->cur_saddr = htonl(t);
                info->cur_saddr = htonl(t);
        }
        }
 
 
        if ((imn = ntohl(info->daddr_min)) < (imx = ntohl(info->daddr_max))) {
        if ((imn = ntohl(info->daddr_min)) < (imx = ntohl(info->daddr_max))) {
                __u32 t;
                __u32 t;
                if (info->flags & F_IPDST_RND) {
                if (info->flags & F_IPDST_RND) {
                        t = ((net_random() % (imx - imn)) + imn);
                        t = ((net_random() % (imx - imn)) + imn);
                }
                }
                else {
                else {
                     t = ntohl(info->cur_daddr);
                     t = ntohl(info->cur_daddr);
                     t++;
                     t++;
                     if (t >= imx) {
                     if (t >= imx) {
                             t = imn;
                             t = imn;
                     }
                     }
                }
                }
                info->cur_daddr = htonl(t);
                info->cur_daddr = htonl(t);
        }
        }
}/* mod_cur_headers */
}/* mod_cur_headers */
 
 
 
 
static struct sk_buff *fill_packet(struct net_device *odev, struct pktgen_info* info)
static struct sk_buff *fill_packet(struct net_device *odev, struct pktgen_info* info)
{
{
        struct sk_buff *skb = NULL;
        struct sk_buff *skb = NULL;
        __u8 *eth;
        __u8 *eth;
        struct udphdr *udph;
        struct udphdr *udph;
        int datalen, iplen;
        int datalen, iplen;
        struct iphdr *iph;
        struct iphdr *iph;
        struct pktgen_hdr *pgh = NULL;
        struct pktgen_hdr *pgh = NULL;
 
 
        skb = alloc_skb(info->pkt_size + 64 + 16, GFP_ATOMIC);
        skb = alloc_skb(info->pkt_size + 64 + 16, GFP_ATOMIC);
        if (!skb) {
        if (!skb) {
                sprintf(info->result, "No memory");
                sprintf(info->result, "No memory");
                return NULL;
                return NULL;
        }
        }
 
 
        skb_reserve(skb, 16);
        skb_reserve(skb, 16);
 
 
        /*  Reserve for ethernet and IP header  */
        /*  Reserve for ethernet and IP header  */
        eth = (__u8 *) skb_push(skb, 14);
        eth = (__u8 *) skb_push(skb, 14);
        iph = (struct iphdr *)skb_put(skb, sizeof(struct iphdr));
        iph = (struct iphdr *)skb_put(skb, sizeof(struct iphdr));
        udph = (struct udphdr *)skb_put(skb, sizeof(struct udphdr));
        udph = (struct udphdr *)skb_put(skb, sizeof(struct udphdr));
 
 
        /* Update any of the values, used when we're incrementing various
        /* Update any of the values, used when we're incrementing various
         * fields.
         * fields.
         */
         */
        mod_cur_headers(info);
        mod_cur_headers(info);
 
 
        memcpy(eth, info->hh, 14);
        memcpy(eth, info->hh, 14);
 
 
        datalen = info->pkt_size - 14 - 20 - 8; /* Eth + IPh + UDPh */
        datalen = info->pkt_size - 14 - 20 - 8; /* Eth + IPh + UDPh */
        if (datalen < sizeof(struct pktgen_hdr)) {
        if (datalen < sizeof(struct pktgen_hdr)) {
                datalen = sizeof(struct pktgen_hdr);
                datalen = sizeof(struct pktgen_hdr);
        }
        }
 
 
        udph->source = htons(info->cur_udp_src);
        udph->source = htons(info->cur_udp_src);
        udph->dest = htons(info->cur_udp_dst);
        udph->dest = htons(info->cur_udp_dst);
        udph->len = htons(datalen + 8); /* DATA + udphdr */
        udph->len = htons(datalen + 8); /* DATA + udphdr */
        udph->check = 0;  /* No checksum */
        udph->check = 0;  /* No checksum */
 
 
        iph->ihl = 5;
        iph->ihl = 5;
        iph->version = 4;
        iph->version = 4;
        iph->ttl = 3;
        iph->ttl = 3;
        iph->tos = 0;
        iph->tos = 0;
        iph->protocol = IPPROTO_UDP; /* UDP */
        iph->protocol = IPPROTO_UDP; /* UDP */
        iph->saddr = info->cur_saddr;
        iph->saddr = info->cur_saddr;
        iph->daddr = info->cur_daddr;
        iph->daddr = info->cur_daddr;
        iph->frag_off = 0;
        iph->frag_off = 0;
        iplen = 20 + 8 + datalen;
        iplen = 20 + 8 + datalen;
        iph->tot_len = htons(iplen);
        iph->tot_len = htons(iplen);
        iph->check = 0;
        iph->check = 0;
        iph->check = ip_fast_csum((void *) iph, iph->ihl);
        iph->check = ip_fast_csum((void *) iph, iph->ihl);
        skb->protocol = __constant_htons(ETH_P_IP);
        skb->protocol = __constant_htons(ETH_P_IP);
        skb->mac.raw = ((u8 *)iph) - 14;
        skb->mac.raw = ((u8 *)iph) - 14;
        skb->dev = odev;
        skb->dev = odev;
        skb->pkt_type = PACKET_HOST;
        skb->pkt_type = PACKET_HOST;
 
 
        if (info->nfrags <= 0) {
        if (info->nfrags <= 0) {
                pgh = (struct pktgen_hdr *)skb_put(skb, datalen);
                pgh = (struct pktgen_hdr *)skb_put(skb, datalen);
        } else {
        } else {
                int frags = info->nfrags;
                int frags = info->nfrags;
                int i;
                int i;
 
 
                /* TODO: Verify this is OK...it sure is ugly. --Ben */
                /* TODO: Verify this is OK...it sure is ugly. --Ben */
                pgh = (struct pktgen_hdr*)(((char*)(udph)) + 8);
                pgh = (struct pktgen_hdr*)(((char*)(udph)) + 8);
 
 
                if (frags > MAX_SKB_FRAGS)
                if (frags > MAX_SKB_FRAGS)
                        frags = MAX_SKB_FRAGS;
                        frags = MAX_SKB_FRAGS;
                if (datalen > frags*PAGE_SIZE) {
                if (datalen > frags*PAGE_SIZE) {
                        skb_put(skb, datalen-frags*PAGE_SIZE);
                        skb_put(skb, datalen-frags*PAGE_SIZE);
                        datalen = frags*PAGE_SIZE;
                        datalen = frags*PAGE_SIZE;
                }
                }
 
 
                i = 0;
                i = 0;
                while (datalen > 0) {
                while (datalen > 0) {
                        struct page *page = alloc_pages(GFP_KERNEL, 0);
                        struct page *page = alloc_pages(GFP_KERNEL, 0);
                        skb_shinfo(skb)->frags[i].page = page;
                        skb_shinfo(skb)->frags[i].page = page;
                        skb_shinfo(skb)->frags[i].page_offset = 0;
                        skb_shinfo(skb)->frags[i].page_offset = 0;
                        skb_shinfo(skb)->frags[i].size =
                        skb_shinfo(skb)->frags[i].size =
                                (datalen < PAGE_SIZE ? datalen : PAGE_SIZE);
                                (datalen < PAGE_SIZE ? datalen : PAGE_SIZE);
                        datalen -= skb_shinfo(skb)->frags[i].size;
                        datalen -= skb_shinfo(skb)->frags[i].size;
                        skb->len += skb_shinfo(skb)->frags[i].size;
                        skb->len += skb_shinfo(skb)->frags[i].size;
                        skb->data_len += skb_shinfo(skb)->frags[i].size;
                        skb->data_len += skb_shinfo(skb)->frags[i].size;
                        i++;
                        i++;
                        skb_shinfo(skb)->nr_frags = i;
                        skb_shinfo(skb)->nr_frags = i;
                }
                }
 
 
                while (i < frags) {
                while (i < frags) {
                        int rem;
                        int rem;
 
 
                        if (i == 0)
                        if (i == 0)
                                break;
                                break;
 
 
                        rem = skb_shinfo(skb)->frags[i - 1].size / 2;
                        rem = skb_shinfo(skb)->frags[i - 1].size / 2;
                        if (rem == 0)
                        if (rem == 0)
                                break;
                                break;
 
 
                        skb_shinfo(skb)->frags[i - 1].size -= rem;
                        skb_shinfo(skb)->frags[i - 1].size -= rem;
 
 
                        skb_shinfo(skb)->frags[i] = skb_shinfo(skb)->frags[i - 1];
                        skb_shinfo(skb)->frags[i] = skb_shinfo(skb)->frags[i - 1];
                        get_page(skb_shinfo(skb)->frags[i].page);
                        get_page(skb_shinfo(skb)->frags[i].page);
                        skb_shinfo(skb)->frags[i].page = skb_shinfo(skb)->frags[i - 1].page;
                        skb_shinfo(skb)->frags[i].page = skb_shinfo(skb)->frags[i - 1].page;
                        skb_shinfo(skb)->frags[i].page_offset += skb_shinfo(skb)->frags[i - 1].size;
                        skb_shinfo(skb)->frags[i].page_offset += skb_shinfo(skb)->frags[i - 1].size;
                        skb_shinfo(skb)->frags[i].size = rem;
                        skb_shinfo(skb)->frags[i].size = rem;
                        i++;
                        i++;
                        skb_shinfo(skb)->nr_frags = i;
                        skb_shinfo(skb)->nr_frags = i;
                }
                }
        }
        }
 
 
        /* Stamp the time, and sequence number, convert them to network byte order */
        /* Stamp the time, and sequence number, convert them to network byte order */
        if (pgh) {
        if (pgh) {
                pgh->pgh_magic = htonl(PKTGEN_MAGIC);
                pgh->pgh_magic = htonl(PKTGEN_MAGIC);
                do_gettimeofday(&(pgh->timestamp));
                do_gettimeofday(&(pgh->timestamp));
                pgh->timestamp.tv_usec = htonl(pgh->timestamp.tv_usec);
                pgh->timestamp.tv_usec = htonl(pgh->timestamp.tv_usec);
                pgh->timestamp.tv_sec = htonl(pgh->timestamp.tv_sec);
                pgh->timestamp.tv_sec = htonl(pgh->timestamp.tv_sec);
                pgh->seq_num = htonl(info->seq_num);
                pgh->seq_num = htonl(info->seq_num);
        }
        }
 
 
        return skb;
        return skb;
}
}
 
 
 
 
static void inject(struct pktgen_info* info)
static void inject(struct pktgen_info* info)
{
{
        struct net_device *odev = NULL;
        struct net_device *odev = NULL;
        struct sk_buff *skb = NULL;
        struct sk_buff *skb = NULL;
        __u64 total = 0;
        __u64 total = 0;
        __u64 idle = 0;
        __u64 idle = 0;
        __u64 lcount = 0;
        __u64 lcount = 0;
        int nr_frags = 0;
        int nr_frags = 0;
        int last_ok = 1;           /* Was last skb sent?
        int last_ok = 1;           /* Was last skb sent?
                                    * Or a failed transmit of some sort?  This will keep
                                    * Or a failed transmit of some sort?  This will keep
                                    * sequence numbers in order, for example.
                                    * sequence numbers in order, for example.
                                    */
                                    */
        __u64 fp = 0;
        __u64 fp = 0;
        __u32 fp_tmp = 0;
        __u32 fp_tmp = 0;
 
 
        odev = setup_inject(info);
        odev = setup_inject(info);
        if (!odev)
        if (!odev)
                return;
                return;
 
 
        info->do_run_run = 1; /* Cranke yeself! */
        info->do_run_run = 1; /* Cranke yeself! */
        info->idle_acc = 0;
        info->idle_acc = 0;
        info->sofar = 0;
        info->sofar = 0;
        lcount = info->count;
        lcount = info->count;
 
 
 
 
        /* Build our initial pkt and place it as a re-try pkt. */
        /* Build our initial pkt and place it as a re-try pkt. */
        skb = fill_packet(odev, info);
        skb = fill_packet(odev, info);
        if (skb == NULL) goto out_reldev;
        if (skb == NULL) goto out_reldev;
 
 
        do_gettimeofday(&(info->started_at));
        do_gettimeofday(&(info->started_at));
 
 
        while(info->do_run_run) {
        while(info->do_run_run) {
 
 
                /* Set a time-stamp, so build a new pkt each time */
                /* Set a time-stamp, so build a new pkt each time */
 
 
                if (last_ok) {
                if (last_ok) {
                        if (++fp_tmp >= info->clone_skb ) {
                        if (++fp_tmp >= info->clone_skb ) {
                                kfree_skb(skb);
                                kfree_skb(skb);
                                skb = fill_packet(odev, info);
                                skb = fill_packet(odev, info);
                                if (skb == NULL) {
                                if (skb == NULL) {
                                        goto out_reldev;
                                        goto out_reldev;
                                }
                                }
                                fp++;
                                fp++;
                                fp_tmp = 0; /* reset counter */
                                fp_tmp = 0; /* reset counter */
                        }
                        }
                }
                }
 
 
                nr_frags = skb_shinfo(skb)->nr_frags;
                nr_frags = skb_shinfo(skb)->nr_frags;
 
 
                spin_lock_bh(&odev->xmit_lock);
                spin_lock_bh(&odev->xmit_lock);
                if (!netif_queue_stopped(odev)) {
                if (!netif_queue_stopped(odev)) {
 
 
                        atomic_inc(&skb->users);
                        atomic_inc(&skb->users);
 
 
                        if (odev->hard_start_xmit(skb, odev)) {
                        if (odev->hard_start_xmit(skb, odev)) {
 
 
                                atomic_dec(&skb->users);
                                atomic_dec(&skb->users);
                                if (net_ratelimit()) {
                                if (net_ratelimit()) {
                                   printk(KERN_INFO "Hard xmit error\n");
                                   printk(KERN_INFO "Hard xmit error\n");
                                }
                                }
                                info->errors++;
                                info->errors++;
                                last_ok = 0;
                                last_ok = 0;
                        }
                        }
                        else {
                        else {
                           last_ok = 1;
                           last_ok = 1;
                           info->sofar++;
                           info->sofar++;
                           info->seq_num++;
                           info->seq_num++;
                        }
                        }
                }
                }
                else {
                else {
                        /* Re-try it next time */
                        /* Re-try it next time */
                        last_ok = 0;
                        last_ok = 0;
                }
                }
 
 
 
 
                spin_unlock_bh(&odev->xmit_lock);
                spin_unlock_bh(&odev->xmit_lock);
 
 
                if (info->ipg) {
                if (info->ipg) {
                        /* Try not to busy-spin if we have larger sleep times.
                        /* Try not to busy-spin if we have larger sleep times.
                         * TODO:  Investigate better ways to do this.
                         * TODO:  Investigate better ways to do this.
                         */
                         */
                        if (info->ipg < 10000) { /* 10 usecs or less */
                        if (info->ipg < 10000) { /* 10 usecs or less */
                                nanospin(info->ipg, info);
                                nanospin(info->ipg, info);
                        }
                        }
                        else if (info->ipg < 10000000) { /* 10ms or less */
                        else if (info->ipg < 10000000) { /* 10ms or less */
                                udelay(info->ipg / 1000);
                                udelay(info->ipg / 1000);
                        }
                        }
                        else {
                        else {
                                mdelay(info->ipg / 1000000);
                                mdelay(info->ipg / 1000000);
                        }
                        }
                }
                }
 
 
                if (signal_pending(current)) {
                if (signal_pending(current)) {
                        break;
                        break;
                }
                }
 
 
                /* If lcount is zero, then run forever */
                /* If lcount is zero, then run forever */
                if ((lcount != 0) && (--lcount == 0)) {
                if ((lcount != 0) && (--lcount == 0)) {
                        if (atomic_read(&skb->users) != 1) {
                        if (atomic_read(&skb->users) != 1) {
                                u32 idle_start, idle;
                                u32 idle_start, idle;
 
 
                                idle_start = cycles();
                                idle_start = cycles();
                                while (atomic_read(&skb->users) != 1) {
                                while (atomic_read(&skb->users) != 1) {
                                        if (signal_pending(current)) {
                                        if (signal_pending(current)) {
                                                break;
                                                break;
                                        }
                                        }
                                        schedule();
                                        schedule();
                                }
                                }
                                idle = cycles() - idle_start;
                                idle = cycles() - idle_start;
                                info->idle_acc += idle;
                                info->idle_acc += idle;
                        }
                        }
                        break;
                        break;
                }
                }
 
 
                if (netif_queue_stopped(odev) || current->need_resched) {
                if (netif_queue_stopped(odev) || current->need_resched) {
                        u32 idle_start, idle;
                        u32 idle_start, idle;
 
 
                        idle_start = cycles();
                        idle_start = cycles();
                        do {
                        do {
                                if (signal_pending(current)) {
                                if (signal_pending(current)) {
                                        info->do_run_run = 0;
                                        info->do_run_run = 0;
                                        break;
                                        break;
                                }
                                }
                                if (!netif_running(odev)) {
                                if (!netif_running(odev)) {
                                        info->do_run_run = 0;
                                        info->do_run_run = 0;
                                        break;
                                        break;
                                }
                                }
                                if (current->need_resched)
                                if (current->need_resched)
                                        schedule();
                                        schedule();
                                else
                                else
                                        do_softirq();
                                        do_softirq();
                        } while (netif_queue_stopped(odev));
                        } while (netif_queue_stopped(odev));
                        idle = cycles() - idle_start;
                        idle = cycles() - idle_start;
                        info->idle_acc += idle;
                        info->idle_acc += idle;
                }
                }
        }/* while we should be running */
        }/* while we should be running */
 
 
        do_gettimeofday(&(info->stopped_at));
        do_gettimeofday(&(info->stopped_at));
 
 
        total = (info->stopped_at.tv_sec - info->started_at.tv_sec) * 1000000 +
        total = (info->stopped_at.tv_sec - info->started_at.tv_sec) * 1000000 +
                info->stopped_at.tv_usec - info->started_at.tv_usec;
                info->stopped_at.tv_usec - info->started_at.tv_usec;
 
 
        idle = (__u32)(info->idle_acc)/(__u32)(cpu_speed);
        idle = (__u32)(info->idle_acc)/(__u32)(cpu_speed);
 
 
        {
        {
                char *p = info->result;
                char *p = info->result;
                __u64 pps = (__u32)(info->sofar * 1000) / ((__u32)(total) / 1000);
                __u64 pps = (__u32)(info->sofar * 1000) / ((__u32)(total) / 1000);
                __u64 bps = pps * 8 * (info->pkt_size + 4); /* take 32bit ethernet CRC into account */
                __u64 bps = pps * 8 * (info->pkt_size + 4); /* take 32bit ethernet CRC into account */
                p += sprintf(p, "OK: %llu(c%llu+d%llu) usec, %llu (%dbyte,%dfrags) %llupps %lluMb/sec (%llubps)  errors: %llu",
                p += sprintf(p, "OK: %llu(c%llu+d%llu) usec, %llu (%dbyte,%dfrags) %llupps %lluMb/sec (%llubps)  errors: %llu",
                             (unsigned long long) total,
                             (unsigned long long) total,
                             (unsigned long long) (total - idle),
                             (unsigned long long) (total - idle),
                             (unsigned long long) idle,
                             (unsigned long long) idle,
                             (unsigned long long) info->sofar,
                             (unsigned long long) info->sofar,
                             skb->len + 4, /* Add 4 to account for the ethernet checksum */
                             skb->len + 4, /* Add 4 to account for the ethernet checksum */
                             nr_frags,
                             nr_frags,
                             (unsigned long long) pps,
                             (unsigned long long) pps,
                             (unsigned long long) (bps / (u64) 1024 / (u64) 1024),
                             (unsigned long long) (bps / (u64) 1024 / (u64) 1024),
                             (unsigned long long) bps,
                             (unsigned long long) bps,
                             (unsigned long long) info->errors
                             (unsigned long long) info->errors
                             );
                             );
        }
        }
 
 
        kfree_skb(skb);
        kfree_skb(skb);
 
 
out_reldev:
out_reldev:
        if (odev) {
        if (odev) {
                dev_put(odev);
                dev_put(odev);
                odev = NULL;
                odev = NULL;
        }
        }
 
 
        return;
        return;
 
 
}
}
 
 
/* proc/net/pktgen/pg */
/* proc/net/pktgen/pg */
 
 
static int proc_busy_read(char *buf , char **start, off_t offset,
static int proc_busy_read(char *buf , char **start, off_t offset,
                             int len, int *eof, void *data)
                             int len, int *eof, void *data)
{
{
        char *p;
        char *p;
        int idx = (int)(long)(data);
        int idx = (int)(long)(data);
        struct pktgen_info* info = NULL;
        struct pktgen_info* info = NULL;
 
 
        if ((idx < 0) || (idx >= MAX_PKTGEN)) {
        if ((idx < 0) || (idx >= MAX_PKTGEN)) {
                printk("ERROR: idx: %i is out of range in proc_write\n", idx);
                printk("ERROR: idx: %i is out of range in proc_write\n", idx);
                return -EINVAL;
                return -EINVAL;
        }
        }
        info = &(pginfos[idx]);
        info = &(pginfos[idx]);
 
 
        p = buf;
        p = buf;
        p += sprintf(p, "%d\n", info->busy);
        p += sprintf(p, "%d\n", info->busy);
        *eof = 1;
        *eof = 1;
 
 
        return p-buf;
        return p-buf;
}
}
 
 
static int proc_read(char *buf , char **start, off_t offset,
static int proc_read(char *buf , char **start, off_t offset,
                        int len, int *eof, void *data)
                        int len, int *eof, void *data)
{
{
        char *p;
        char *p;
        int i;
        int i;
        int idx = (int)(long)(data);
        int idx = (int)(long)(data);
        struct pktgen_info* info = NULL;
        struct pktgen_info* info = NULL;
        __u64 sa;
        __u64 sa;
        __u64 stopped;
        __u64 stopped;
        __u64 now = getCurMs();
        __u64 now = getCurMs();
 
 
        if ((idx < 0) || (idx >= MAX_PKTGEN)) {
        if ((idx < 0) || (idx >= MAX_PKTGEN)) {
                printk("ERROR: idx: %i is out of range in proc_write\n", idx);
                printk("ERROR: idx: %i is out of range in proc_write\n", idx);
                return -EINVAL;
                return -EINVAL;
        }
        }
        info = &(pginfos[idx]);
        info = &(pginfos[idx]);
 
 
        p = buf;
        p = buf;
        p += sprintf(p, "%s\n", VERSION); /* Help with parsing compatibility */
        p += sprintf(p, "%s\n", VERSION); /* Help with parsing compatibility */
        p += sprintf(p, "Params: count %llu  pkt_size: %u  frags: %d  ipg: %u  clone_skb: %d odev \"%s\"\n",
        p += sprintf(p, "Params: count %llu  pkt_size: %u  frags: %d  ipg: %u  clone_skb: %d odev \"%s\"\n",
                     (unsigned long long) info->count,
                     (unsigned long long) info->count,
                     info->pkt_size, info->nfrags, info->ipg,
                     info->pkt_size, info->nfrags, info->ipg,
                     info->clone_skb, info->outdev);
                     info->clone_skb, info->outdev);
        p += sprintf(p, "     dst_min: %s  dst_max: %s  src_min: %s  src_max: %s\n",
        p += sprintf(p, "     dst_min: %s  dst_max: %s  src_min: %s  src_max: %s\n",
                     info->dst_min, info->dst_max, info->src_min, info->src_max);
                     info->dst_min, info->dst_max, info->src_min, info->src_max);
        p += sprintf(p, "     src_mac: ");
        p += sprintf(p, "     src_mac: ");
        for (i = 0; i < 6; i++) {
        for (i = 0; i < 6; i++) {
                p += sprintf(p, "%02X%s", info->src_mac[i], i == 5 ? "  " : ":");
                p += sprintf(p, "%02X%s", info->src_mac[i], i == 5 ? "  " : ":");
        }
        }
        p += sprintf(p, "dst_mac: ");
        p += sprintf(p, "dst_mac: ");
        for (i = 0; i < 6; i++) {
        for (i = 0; i < 6; i++) {
                p += sprintf(p, "%02X%s", info->dst_mac[i], i == 5 ? "\n" : ":");
                p += sprintf(p, "%02X%s", info->dst_mac[i], i == 5 ? "\n" : ":");
        }
        }
        p += sprintf(p, "     udp_src_min: %d  udp_src_max: %d  udp_dst_min: %d  udp_dst_max: %d\n",
        p += sprintf(p, "     udp_src_min: %d  udp_src_max: %d  udp_dst_min: %d  udp_dst_max: %d\n",
                     info->udp_src_min, info->udp_src_max, info->udp_dst_min,
                     info->udp_src_min, info->udp_src_max, info->udp_dst_min,
                     info->udp_dst_max);
                     info->udp_dst_max);
        p += sprintf(p, "     src_mac_count: %d  dst_mac_count: %d\n     Flags: ",
        p += sprintf(p, "     src_mac_count: %d  dst_mac_count: %d\n     Flags: ",
                     info->src_mac_count, info->dst_mac_count);
                     info->src_mac_count, info->dst_mac_count);
        if (info->flags &  F_IPSRC_RND) {
        if (info->flags &  F_IPSRC_RND) {
                p += sprintf(p, "IPSRC_RND  ");
                p += sprintf(p, "IPSRC_RND  ");
        }
        }
        if (info->flags & F_IPDST_RND) {
        if (info->flags & F_IPDST_RND) {
                p += sprintf(p, "IPDST_RND  ");
                p += sprintf(p, "IPDST_RND  ");
        }
        }
        if (info->flags & F_UDPSRC_RND) {
        if (info->flags & F_UDPSRC_RND) {
                p += sprintf(p, "UDPSRC_RND  ");
                p += sprintf(p, "UDPSRC_RND  ");
        }
        }
        if (info->flags & F_UDPDST_RND) {
        if (info->flags & F_UDPDST_RND) {
                p += sprintf(p, "UDPDST_RND  ");
                p += sprintf(p, "UDPDST_RND  ");
        }
        }
        if (info->flags & F_MACSRC_RND) {
        if (info->flags & F_MACSRC_RND) {
                p += sprintf(p, "MACSRC_RND  ");
                p += sprintf(p, "MACSRC_RND  ");
        }
        }
        if (info->flags & F_MACDST_RND) {
        if (info->flags & F_MACDST_RND) {
                p += sprintf(p, "MACDST_RND  ");
                p += sprintf(p, "MACDST_RND  ");
        }
        }
        p += sprintf(p, "\n");
        p += sprintf(p, "\n");
 
 
        sa = tv_to_ms(&(info->started_at));
        sa = tv_to_ms(&(info->started_at));
        stopped = tv_to_ms(&(info->stopped_at));
        stopped = tv_to_ms(&(info->stopped_at));
        if (info->do_run_run) {
        if (info->do_run_run) {
                stopped = now; /* not really stopped, more like last-running-at */
                stopped = now; /* not really stopped, more like last-running-at */
        }
        }
        p += sprintf(p, "Current:\n     pkts-sofar: %llu  errors: %llu\n     started: %llums  stopped: %llums  now: %llums  idle: %lluns\n",
        p += sprintf(p, "Current:\n     pkts-sofar: %llu  errors: %llu\n     started: %llums  stopped: %llums  now: %llums  idle: %lluns\n",
                     (unsigned long long) info->sofar,
                     (unsigned long long) info->sofar,
                     (unsigned long long) info->errors,
                     (unsigned long long) info->errors,
                     (unsigned long long) sa,
                     (unsigned long long) sa,
                     (unsigned long long) stopped,
                     (unsigned long long) stopped,
                     (unsigned long long) now,
                     (unsigned long long) now,
                     (unsigned long long) info->idle_acc);
                     (unsigned long long) info->idle_acc);
        p += sprintf(p, "     seq_num: %d  cur_dst_mac_offset: %d  cur_src_mac_offset: %d\n",
        p += sprintf(p, "     seq_num: %d  cur_dst_mac_offset: %d  cur_src_mac_offset: %d\n",
                     info->seq_num, info->cur_dst_mac_offset, info->cur_src_mac_offset);
                     info->seq_num, info->cur_dst_mac_offset, info->cur_src_mac_offset);
        p += sprintf(p, "     cur_saddr: 0x%x  cur_daddr: 0x%x  cur_udp_dst: %d  cur_udp_src: %d\n",
        p += sprintf(p, "     cur_saddr: 0x%x  cur_daddr: 0x%x  cur_udp_dst: %d  cur_udp_src: %d\n",
                     info->cur_saddr, info->cur_daddr, info->cur_udp_dst, info->cur_udp_src);
                     info->cur_saddr, info->cur_daddr, info->cur_udp_dst, info->cur_udp_src);
 
 
        if (info->result[0])
        if (info->result[0])
                p += sprintf(p, "Result: %s\n", info->result);
                p += sprintf(p, "Result: %s\n", info->result);
        else
        else
                p += sprintf(p, "Result: Idle\n");
                p += sprintf(p, "Result: Idle\n");
        *eof = 1;
        *eof = 1;
 
 
        return p - buf;
        return p - buf;
}
}
 
 
static int count_trail_chars(const char *user_buffer, unsigned int maxlen)
static int count_trail_chars(const char *user_buffer, unsigned int maxlen)
{
{
        int i;
        int i;
 
 
        for (i = 0; i < maxlen; i++) {
        for (i = 0; i < maxlen; i++) {
                char c;
                char c;
 
 
                if (get_user(c, &user_buffer[i]))
                if (get_user(c, &user_buffer[i]))
                        return -EFAULT;
                        return -EFAULT;
                switch (c) {
                switch (c) {
                case '\"':
                case '\"':
                case '\n':
                case '\n':
                case '\r':
                case '\r':
                case '\t':
                case '\t':
                case ' ':
                case ' ':
                case '=':
                case '=':
                        break;
                        break;
                default:
                default:
                        goto done;
                        goto done;
                };
                };
        }
        }
done:
done:
        return i;
        return i;
}
}
 
 
static unsigned long num_arg(const char *user_buffer, unsigned long maxlen,
static unsigned long num_arg(const char *user_buffer, unsigned long maxlen,
                             unsigned long *num)
                             unsigned long *num)
{
{
        int i = 0;
        int i = 0;
 
 
        *num = 0;
        *num = 0;
 
 
        for(; i < maxlen; i++) {
        for(; i < maxlen; i++) {
                char c;
                char c;
 
 
                if (get_user(c, &user_buffer[i]))
                if (get_user(c, &user_buffer[i]))
                        return -EFAULT;
                        return -EFAULT;
                if ((c >= '0') && (c <= '9')) {
                if ((c >= '0') && (c <= '9')) {
                        *num *= 10;
                        *num *= 10;
                        *num += c -'0';
                        *num += c -'0';
                } else
                } else
                        break;
                        break;
        }
        }
        return i;
        return i;
}
}
 
 
static int strn_len(const char *user_buffer, unsigned int maxlen)
static int strn_len(const char *user_buffer, unsigned int maxlen)
{
{
        int i = 0;
        int i = 0;
 
 
        for(; i < maxlen; i++) {
        for(; i < maxlen; i++) {
                char c;
                char c;
 
 
                if (get_user(c, &user_buffer[i]))
                if (get_user(c, &user_buffer[i]))
                        return -EFAULT;
                        return -EFAULT;
                switch (c) {
                switch (c) {
                case '\"':
                case '\"':
                case '\n':
                case '\n':
                case '\r':
                case '\r':
                case '\t':
                case '\t':
                case ' ':
                case ' ':
                        goto done_str;
                        goto done_str;
                default:
                default:
                        break;
                        break;
                };
                };
        }
        }
done_str:
done_str:
        return i;
        return i;
}
}
 
 
static int proc_write(struct file *file, const char *user_buffer,
static int proc_write(struct file *file, const char *user_buffer,
                         unsigned long count, void *data)
                         unsigned long count, void *data)
{
{
        int i = 0, max, len;
        int i = 0, max, len;
        char name[16], valstr[32];
        char name[16], valstr[32];
        unsigned long value = 0;
        unsigned long value = 0;
        int idx = (int)(long)(data);
        int idx = (int)(long)(data);
        struct pktgen_info* info = NULL;
        struct pktgen_info* info = NULL;
        char* result = NULL;
        char* result = NULL;
        int tmp;
        int tmp;
 
 
        if ((idx < 0) || (idx >= MAX_PKTGEN)) {
        if ((idx < 0) || (idx >= MAX_PKTGEN)) {
                printk("ERROR: idx: %i is out of range in proc_write\n", idx);
                printk("ERROR: idx: %i is out of range in proc_write\n", idx);
                return -EINVAL;
                return -EINVAL;
        }
        }
        info = &(pginfos[idx]);
        info = &(pginfos[idx]);
        result = &(info->result[0]);
        result = &(info->result[0]);
 
 
        if (count < 1) {
        if (count < 1) {
                sprintf(result, "Wrong command format");
                sprintf(result, "Wrong command format");
                return -EINVAL;
                return -EINVAL;
        }
        }
 
 
        max = count - i;
        max = count - i;
        tmp = count_trail_chars(&user_buffer[i], max);
        tmp = count_trail_chars(&user_buffer[i], max);
        if (tmp < 0)
        if (tmp < 0)
                return tmp;
                return tmp;
        i += tmp;
        i += tmp;
 
 
        /* Read variable name */
        /* Read variable name */
 
 
        len = strn_len(&user_buffer[i], sizeof(name) - 1);
        len = strn_len(&user_buffer[i], sizeof(name) - 1);
        if (len < 0)
        if (len < 0)
                return len;
                return len;
        memset(name, 0, sizeof(name));
        memset(name, 0, sizeof(name));
        if (copy_from_user(name, &user_buffer[i], len))
        if (copy_from_user(name, &user_buffer[i], len))
                return -EFAULT;
                return -EFAULT;
        i += len;
        i += len;
 
 
        max = count -i;
        max = count -i;
        len = count_trail_chars(&user_buffer[i], max);
        len = count_trail_chars(&user_buffer[i], max);
        if (len < 0)
        if (len < 0)
                return len;
                return len;
        i += len;
        i += len;
 
 
        if (debug)
        if (debug)
                printk("pg: %s,%lu\n", name, count);
                printk("pg: %s,%lu\n", name, count);
 
 
        if (!strcmp(name, "stop")) {
        if (!strcmp(name, "stop")) {
                if (info->do_run_run) {
                if (info->do_run_run) {
                        strcpy(result, "Stopping");
                        strcpy(result, "Stopping");
                }
                }
                else {
                else {
                        strcpy(result, "Already stopped...\n");
                        strcpy(result, "Already stopped...\n");
                }
                }
                info->do_run_run = 0;
                info->do_run_run = 0;
                return count;
                return count;
        }
        }
 
 
        if (!strcmp(name, "pkt_size")) {
        if (!strcmp(name, "pkt_size")) {
                len = num_arg(&user_buffer[i], 10, &value);
                len = num_arg(&user_buffer[i], 10, &value);
                if (len < 0)
                if (len < 0)
                        return len;
                        return len;
                i += len;
                i += len;
                if (value < 14+20+8)
                if (value < 14+20+8)
                        value = 14+20+8;
                        value = 14+20+8;
                info->pkt_size = value;
                info->pkt_size = value;
                sprintf(result, "OK: pkt_size=%u", info->pkt_size);
                sprintf(result, "OK: pkt_size=%u", info->pkt_size);
                return count;
                return count;
        }
        }
        if (!strcmp(name, "frags")) {
        if (!strcmp(name, "frags")) {
                len = num_arg(&user_buffer[i], 10, &value);
                len = num_arg(&user_buffer[i], 10, &value);
                if (len < 0)
                if (len < 0)
                        return len;
                        return len;
                i += len;
                i += len;
                info->nfrags = value;
                info->nfrags = value;
                sprintf(result, "OK: frags=%u", info->nfrags);
                sprintf(result, "OK: frags=%u", info->nfrags);
                return count;
                return count;
        }
        }
        if (!strcmp(name, "ipg")) {
        if (!strcmp(name, "ipg")) {
                len = num_arg(&user_buffer[i], 10, &value);
                len = num_arg(&user_buffer[i], 10, &value);
                if (len < 0)
                if (len < 0)
                        return len;
                        return len;
                i += len;
                i += len;
                info->ipg = value;
                info->ipg = value;
                sprintf(result, "OK: ipg=%u", info->ipg);
                sprintf(result, "OK: ipg=%u", info->ipg);
                return count;
                return count;
        }
        }
        if (!strcmp(name, "udp_src_min")) {
        if (!strcmp(name, "udp_src_min")) {
                len = num_arg(&user_buffer[i], 10, &value);
                len = num_arg(&user_buffer[i], 10, &value);
                if (len < 0)
                if (len < 0)
                        return len;
                        return len;
                i += len;
                i += len;
                info->udp_src_min = value;
                info->udp_src_min = value;
                sprintf(result, "OK: udp_src_min=%u", info->udp_src_min);
                sprintf(result, "OK: udp_src_min=%u", info->udp_src_min);
                return count;
                return count;
        }
        }
        if (!strcmp(name, "udp_dst_min")) {
        if (!strcmp(name, "udp_dst_min")) {
                len = num_arg(&user_buffer[i], 10, &value);
                len = num_arg(&user_buffer[i], 10, &value);
                if (len < 0)
                if (len < 0)
                        return len;
                        return len;
                i += len;
                i += len;
                info->udp_dst_min = value;
                info->udp_dst_min = value;
                sprintf(result, "OK: udp_dst_min=%u", info->udp_dst_min);
                sprintf(result, "OK: udp_dst_min=%u", info->udp_dst_min);
                return count;
                return count;
        }
        }
        if (!strcmp(name, "udp_src_max")) {
        if (!strcmp(name, "udp_src_max")) {
                len = num_arg(&user_buffer[i], 10, &value);
                len = num_arg(&user_buffer[i], 10, &value);
                if (len < 0)
                if (len < 0)
                        return len;
                        return len;
                i += len;
                i += len;
                info->udp_src_max = value;
                info->udp_src_max = value;
                sprintf(result, "OK: udp_src_max=%u", info->udp_src_max);
                sprintf(result, "OK: udp_src_max=%u", info->udp_src_max);
                return count;
                return count;
        }
        }
        if (!strcmp(name, "udp_dst_max")) {
        if (!strcmp(name, "udp_dst_max")) {
                len = num_arg(&user_buffer[i], 10, &value);
                len = num_arg(&user_buffer[i], 10, &value);
                if (len < 0)
                if (len < 0)
                        return len;
                        return len;
                i += len;
                i += len;
                info->udp_dst_max = value;
                info->udp_dst_max = value;
                sprintf(result, "OK: udp_dst_max=%u", info->udp_dst_max);
                sprintf(result, "OK: udp_dst_max=%u", info->udp_dst_max);
                return count;
                return count;
        }
        }
        if (!strcmp(name, "clone_skb")) {
        if (!strcmp(name, "clone_skb")) {
                len = num_arg(&user_buffer[i], 10, &value);
                len = num_arg(&user_buffer[i], 10, &value);
                if (len < 0)
                if (len < 0)
                        return len;
                        return len;
                i += len;
                i += len;
                info->clone_skb = value;
                info->clone_skb = value;
 
 
                sprintf(result, "OK: clone_skb=%d", info->clone_skb);
                sprintf(result, "OK: clone_skb=%d", info->clone_skb);
                return count;
                return count;
        }
        }
        if (!strcmp(name, "count")) {
        if (!strcmp(name, "count")) {
                len = num_arg(&user_buffer[i], 10, &value);
                len = num_arg(&user_buffer[i], 10, &value);
                if (len < 0)
                if (len < 0)
                        return len;
                        return len;
                i += len;
                i += len;
                info->count = value;
                info->count = value;
                sprintf(result, "OK: count=%llu", (unsigned long long) info->count);
                sprintf(result, "OK: count=%llu", (unsigned long long) info->count);
                return count;
                return count;
        }
        }
        if (!strcmp(name, "src_mac_count")) {
        if (!strcmp(name, "src_mac_count")) {
                len = num_arg(&user_buffer[i], 10, &value);
                len = num_arg(&user_buffer[i], 10, &value);
                if (len < 0)
                if (len < 0)
                        return len;
                        return len;
                i += len;
                i += len;
                info->src_mac_count = value;
                info->src_mac_count = value;
                sprintf(result, "OK: src_mac_count=%d", info->src_mac_count);
                sprintf(result, "OK: src_mac_count=%d", info->src_mac_count);
                return count;
                return count;
        }
        }
        if (!strcmp(name, "dst_mac_count")) {
        if (!strcmp(name, "dst_mac_count")) {
                len = num_arg(&user_buffer[i], 10, &value);
                len = num_arg(&user_buffer[i], 10, &value);
                if (len < 0)
                if (len < 0)
                        return len;
                        return len;
                i += len;
                i += len;
                info->dst_mac_count = value;
                info->dst_mac_count = value;
                sprintf(result, "OK: dst_mac_count=%d", info->dst_mac_count);
                sprintf(result, "OK: dst_mac_count=%d", info->dst_mac_count);
                return count;
                return count;
        }
        }
        if (!strcmp(name, "odev")) {
        if (!strcmp(name, "odev")) {
                len = strn_len(&user_buffer[i], sizeof(info->outdev) - 1);
                len = strn_len(&user_buffer[i], sizeof(info->outdev) - 1);
                if (len < 0)
                if (len < 0)
                        return len;
                        return len;
                memset(info->outdev, 0, sizeof(info->outdev));
                memset(info->outdev, 0, sizeof(info->outdev));
                if (copy_from_user(info->outdev, &user_buffer[i], len))
                if (copy_from_user(info->outdev, &user_buffer[i], len))
                        return -EFAULT;
                        return -EFAULT;
                i += len;
                i += len;
                sprintf(result, "OK: odev=%s", info->outdev);
                sprintf(result, "OK: odev=%s", info->outdev);
                return count;
                return count;
        }
        }
        if (!strcmp(name, "flag")) {
        if (!strcmp(name, "flag")) {
                char f[32];
                char f[32];
                len = strn_len(&user_buffer[i], sizeof(f) - 1);
                len = strn_len(&user_buffer[i], sizeof(f) - 1);
                if (len < 0)
                if (len < 0)
                        return len;
                        return len;
                memset(f, 0, 32);
                memset(f, 0, 32);
                if (copy_from_user(f, &user_buffer[i], len))
                if (copy_from_user(f, &user_buffer[i], len))
                        return -EFAULT;
                        return -EFAULT;
                i += len;
                i += len;
                if (strcmp(f, "IPSRC_RND") == 0) {
                if (strcmp(f, "IPSRC_RND") == 0) {
                        info->flags |= F_IPSRC_RND;
                        info->flags |= F_IPSRC_RND;
                }
                }
                else if (strcmp(f, "!IPSRC_RND") == 0) {
                else if (strcmp(f, "!IPSRC_RND") == 0) {
                        info->flags &= ~F_IPSRC_RND;
                        info->flags &= ~F_IPSRC_RND;
                }
                }
                else if (strcmp(f, "IPDST_RND") == 0) {
                else if (strcmp(f, "IPDST_RND") == 0) {
                        info->flags |= F_IPDST_RND;
                        info->flags |= F_IPDST_RND;
                }
                }
                else if (strcmp(f, "!IPDST_RND") == 0) {
                else if (strcmp(f, "!IPDST_RND") == 0) {
                        info->flags &= ~F_IPDST_RND;
                        info->flags &= ~F_IPDST_RND;
                }
                }
                else if (strcmp(f, "UDPSRC_RND") == 0) {
                else if (strcmp(f, "UDPSRC_RND") == 0) {
                        info->flags |= F_UDPSRC_RND;
                        info->flags |= F_UDPSRC_RND;
                }
                }
                else if (strcmp(f, "!UDPSRC_RND") == 0) {
                else if (strcmp(f, "!UDPSRC_RND") == 0) {
                        info->flags &= ~F_UDPSRC_RND;
                        info->flags &= ~F_UDPSRC_RND;
                }
                }
                else if (strcmp(f, "UDPDST_RND") == 0) {
                else if (strcmp(f, "UDPDST_RND") == 0) {
                        info->flags |= F_UDPDST_RND;
                        info->flags |= F_UDPDST_RND;
                }
                }
                else if (strcmp(f, "!UDPDST_RND") == 0) {
                else if (strcmp(f, "!UDPDST_RND") == 0) {
                        info->flags &= ~F_UDPDST_RND;
                        info->flags &= ~F_UDPDST_RND;
                }
                }
                else if (strcmp(f, "MACSRC_RND") == 0) {
                else if (strcmp(f, "MACSRC_RND") == 0) {
                        info->flags |= F_MACSRC_RND;
                        info->flags |= F_MACSRC_RND;
                }
                }
                else if (strcmp(f, "!MACSRC_RND") == 0) {
                else if (strcmp(f, "!MACSRC_RND") == 0) {
                        info->flags &= ~F_MACSRC_RND;
                        info->flags &= ~F_MACSRC_RND;
                }
                }
                else if (strcmp(f, "MACDST_RND") == 0) {
                else if (strcmp(f, "MACDST_RND") == 0) {
                        info->flags |= F_MACDST_RND;
                        info->flags |= F_MACDST_RND;
                }
                }
                else if (strcmp(f, "!MACDST_RND") == 0) {
                else if (strcmp(f, "!MACDST_RND") == 0) {
                        info->flags &= ~F_MACDST_RND;
                        info->flags &= ~F_MACDST_RND;
                }
                }
                else {
                else {
                        sprintf(result, "Flag -:%s:- unknown\nAvailable flags, (prepend ! to un-set flag):\n%s",
                        sprintf(result, "Flag -:%s:- unknown\nAvailable flags, (prepend ! to un-set flag):\n%s",
                                f,
                                f,
                                "IPSRC_RND, IPDST_RND, UDPSRC_RND, UDPDST_RND, MACSRC_RND, MACDST_RND\n");
                                "IPSRC_RND, IPDST_RND, UDPSRC_RND, UDPDST_RND, MACSRC_RND, MACDST_RND\n");
                        return count;
                        return count;
                }
                }
                sprintf(result, "OK: flags=0x%x", info->flags);
                sprintf(result, "OK: flags=0x%x", info->flags);
                return count;
                return count;
        }
        }
        if (!strcmp(name, "dst_min") || !strcmp(name, "dst")) {
        if (!strcmp(name, "dst_min") || !strcmp(name, "dst")) {
                len = strn_len(&user_buffer[i], sizeof(info->dst_min) - 1);
                len = strn_len(&user_buffer[i], sizeof(info->dst_min) - 1);
                if (len < 0)
                if (len < 0)
                        return len;
                        return len;
                memset(info->dst_min, 0, sizeof(info->dst_min));
                memset(info->dst_min, 0, sizeof(info->dst_min));
                if (copy_from_user(info->dst_min, &user_buffer[i], len))
                if (copy_from_user(info->dst_min, &user_buffer[i], len))
                        return -EFAULT;
                        return -EFAULT;
                if(debug)
                if(debug)
                        printk("pg: dst_min set to: %s\n", info->dst_min);
                        printk("pg: dst_min set to: %s\n", info->dst_min);
                i += len;
                i += len;
                sprintf(result, "OK: dst_min=%s", info->dst_min);
                sprintf(result, "OK: dst_min=%s", info->dst_min);
                return count;
                return count;
        }
        }
        if (!strcmp(name, "dst_max")) {
        if (!strcmp(name, "dst_max")) {
                len = strn_len(&user_buffer[i], sizeof(info->dst_max) - 1);
                len = strn_len(&user_buffer[i], sizeof(info->dst_max) - 1);
                if (len < 0)
                if (len < 0)
                        return len;
                        return len;
                memset(info->dst_max, 0, sizeof(info->dst_max));
                memset(info->dst_max, 0, sizeof(info->dst_max));
                if (copy_from_user(info->dst_max, &user_buffer[i], len))
                if (copy_from_user(info->dst_max, &user_buffer[i], len))
                        return -EFAULT;
                        return -EFAULT;
                if(debug)
                if(debug)
                        printk("pg: dst_max set to: %s\n", info->dst_max);
                        printk("pg: dst_max set to: %s\n", info->dst_max);
                i += len;
                i += len;
                sprintf(result, "OK: dst_max=%s", info->dst_max);
                sprintf(result, "OK: dst_max=%s", info->dst_max);
                return count;
                return count;
        }
        }
        if (!strcmp(name, "src_min")) {
        if (!strcmp(name, "src_min")) {
                len = strn_len(&user_buffer[i], sizeof(info->src_min) - 1);
                len = strn_len(&user_buffer[i], sizeof(info->src_min) - 1);
                if (len < 0)
                if (len < 0)
                        return len;
                        return len;
                memset(info->src_min, 0, sizeof(info->src_min));
                memset(info->src_min, 0, sizeof(info->src_min));
                if (copy_from_user(info->src_min, &user_buffer[i], len))
                if (copy_from_user(info->src_min, &user_buffer[i], len))
                        return -EFAULT;
                        return -EFAULT;
                if(debug)
                if(debug)
                        printk("pg: src_min set to: %s\n", info->src_min);
                        printk("pg: src_min set to: %s\n", info->src_min);
                i += len;
                i += len;
                sprintf(result, "OK: src_min=%s", info->src_min);
                sprintf(result, "OK: src_min=%s", info->src_min);
                return count;
                return count;
        }
        }
        if (!strcmp(name, "src_max")) {
        if (!strcmp(name, "src_max")) {
                len = strn_len(&user_buffer[i], sizeof(info->src_max) - 1);
                len = strn_len(&user_buffer[i], sizeof(info->src_max) - 1);
                if (len < 0)
                if (len < 0)
                        return len;
                        return len;
                memset(info->src_max, 0, sizeof(info->src_max));
                memset(info->src_max, 0, sizeof(info->src_max));
                if (copy_from_user(info->src_max, &user_buffer[i], len))
                if (copy_from_user(info->src_max, &user_buffer[i], len))
                        return -EFAULT;
                        return -EFAULT;
                if(debug)
                if(debug)
                        printk("pg: src_max set to: %s\n", info->src_max);
                        printk("pg: src_max set to: %s\n", info->src_max);
                i += len;
                i += len;
                sprintf(result, "OK: src_max=%s", info->src_max);
                sprintf(result, "OK: src_max=%s", info->src_max);
                return count;
                return count;
        }
        }
        if (!strcmp(name, "dstmac")) {
        if (!strcmp(name, "dstmac")) {
                char *v = valstr;
                char *v = valstr;
                unsigned char *m = info->dst_mac;
                unsigned char *m = info->dst_mac;
 
 
                len = strn_len(&user_buffer[i], sizeof(valstr) - 1);
                len = strn_len(&user_buffer[i], sizeof(valstr) - 1);
                if (len < 0)
                if (len < 0)
                        return len;
                        return len;
                memset(valstr, 0, sizeof(valstr));
                memset(valstr, 0, sizeof(valstr));
                if (copy_from_user(valstr, &user_buffer[i], len))
                if (copy_from_user(valstr, &user_buffer[i], len))
                        return -EFAULT;
                        return -EFAULT;
                i += len;
                i += len;
 
 
                for(*m = 0;*v && m < info->dst_mac + 6; v++) {
                for(*m = 0;*v && m < info->dst_mac + 6; v++) {
                        if (*v >= '0' && *v <= '9') {
                        if (*v >= '0' && *v <= '9') {
                                *m *= 16;
                                *m *= 16;
                                *m += *v - '0';
                                *m += *v - '0';
                        }
                        }
                        if (*v >= 'A' && *v <= 'F') {
                        if (*v >= 'A' && *v <= 'F') {
                                *m *= 16;
                                *m *= 16;
                                *m += *v - 'A' + 10;
                                *m += *v - 'A' + 10;
                        }
                        }
                        if (*v >= 'a' && *v <= 'f') {
                        if (*v >= 'a' && *v <= 'f') {
                                *m *= 16;
                                *m *= 16;
                                *m += *v - 'a' + 10;
                                *m += *v - 'a' + 10;
                        }
                        }
                        if (*v == ':') {
                        if (*v == ':') {
                                m++;
                                m++;
                                *m = 0;
                                *m = 0;
                        }
                        }
                }
                }
                sprintf(result, "OK: dstmac");
                sprintf(result, "OK: dstmac");
                return count;
                return count;
        }
        }
        if (!strcmp(name, "srcmac")) {
        if (!strcmp(name, "srcmac")) {
                char *v = valstr;
                char *v = valstr;
                unsigned char *m = info->src_mac;
                unsigned char *m = info->src_mac;
 
 
                len = strn_len(&user_buffer[i], sizeof(valstr) - 1);
                len = strn_len(&user_buffer[i], sizeof(valstr) - 1);
                if (len < 0)
                if (len < 0)
                        return len;
                        return len;
                memset(valstr, 0, sizeof(valstr));
                memset(valstr, 0, sizeof(valstr));
                if (copy_from_user(valstr, &user_buffer[i], len))
                if (copy_from_user(valstr, &user_buffer[i], len))
                        return -EFAULT;
                        return -EFAULT;
                i += len;
                i += len;
 
 
                for(*m = 0;*v && m < info->src_mac + 6; v++) {
                for(*m = 0;*v && m < info->src_mac + 6; v++) {
                        if (*v >= '0' && *v <= '9') {
                        if (*v >= '0' && *v <= '9') {
                                *m *= 16;
                                *m *= 16;
                                *m += *v - '0';
                                *m += *v - '0';
                        }
                        }
                        if (*v >= 'A' && *v <= 'F') {
                        if (*v >= 'A' && *v <= 'F') {
                                *m *= 16;
                                *m *= 16;
                                *m += *v - 'A' + 10;
                                *m += *v - 'A' + 10;
                        }
                        }
                        if (*v >= 'a' && *v <= 'f') {
                        if (*v >= 'a' && *v <= 'f') {
                                *m *= 16;
                                *m *= 16;
                                *m += *v - 'a' + 10;
                                *m += *v - 'a' + 10;
                        }
                        }
                        if (*v == ':') {
                        if (*v == ':') {
                                m++;
                                m++;
                                *m = 0;
                                *m = 0;
                        }
                        }
                }
                }
                sprintf(result, "OK: srcmac");
                sprintf(result, "OK: srcmac");
                return count;
                return count;
        }
        }
 
 
        if (!strcmp(name, "inject") || !strcmp(name, "start")) {
        if (!strcmp(name, "inject") || !strcmp(name, "start")) {
                MOD_INC_USE_COUNT;
                MOD_INC_USE_COUNT;
                if (info->busy) {
                if (info->busy) {
                        strcpy(info->result, "Already running...\n");
                        strcpy(info->result, "Already running...\n");
                }
                }
                else {
                else {
                        info->busy = 1;
                        info->busy = 1;
                        strcpy(info->result, "Starting");
                        strcpy(info->result, "Starting");
                        inject(info);
                        inject(info);
                        info->busy = 0;
                        info->busy = 0;
                }
                }
                MOD_DEC_USE_COUNT;
                MOD_DEC_USE_COUNT;
                return count;
                return count;
        }
        }
 
 
        sprintf(info->result, "No such parameter \"%s\"", name);
        sprintf(info->result, "No such parameter \"%s\"", name);
        return -EINVAL;
        return -EINVAL;
}
}
 
 
 
 
int create_proc_dir(void)
int create_proc_dir(void)
{
{
        int     len;
        int     len;
        /*  does proc_dir already exists */
        /*  does proc_dir already exists */
        len = strlen(PG_PROC_DIR);
        len = strlen(PG_PROC_DIR);
 
 
        for (proc_dir = proc_net->subdir; proc_dir;
        for (proc_dir = proc_net->subdir; proc_dir;
             proc_dir=proc_dir->next) {
             proc_dir=proc_dir->next) {
                if ((proc_dir->namelen == len) &&
                if ((proc_dir->namelen == len) &&
                    (! memcmp(proc_dir->name, PG_PROC_DIR, len)))
                    (! memcmp(proc_dir->name, PG_PROC_DIR, len)))
                        break;
                        break;
        }
        }
        if (!proc_dir)
        if (!proc_dir)
                proc_dir = create_proc_entry(PG_PROC_DIR, S_IFDIR, proc_net);
                proc_dir = create_proc_entry(PG_PROC_DIR, S_IFDIR, proc_net);
        if (!proc_dir) return -ENODEV;
        if (!proc_dir) return -ENODEV;
        return 1;
        return 1;
}
}
 
 
int remove_proc_dir(void)
int remove_proc_dir(void)
{
{
        remove_proc_entry(PG_PROC_DIR, proc_net);
        remove_proc_entry(PG_PROC_DIR, proc_net);
        return 1;
        return 1;
}
}
 
 
static int __init init(void)
static int __init init(void)
{
{
        int i;
        int i;
        printk(version);
        printk(version);
        cycles_calibrate();
        cycles_calibrate();
        if (cpu_speed == 0) {
        if (cpu_speed == 0) {
                printk("pktgen: Error: your machine does not have working cycle counter.\n");
                printk("pktgen: Error: your machine does not have working cycle counter.\n");
                return -EINVAL;
                return -EINVAL;
        }
        }
 
 
        create_proc_dir();
        create_proc_dir();
 
 
        for (i = 0; i<MAX_PKTGEN; i++) {
        for (i = 0; i<MAX_PKTGEN; i++) {
                memset(&(pginfos[i]), 0, sizeof(pginfos[i]));
                memset(&(pginfos[i]), 0, sizeof(pginfos[i]));
                pginfos[i].pkt_size = ETH_ZLEN;
                pginfos[i].pkt_size = ETH_ZLEN;
                pginfos[i].nfrags = 0;
                pginfos[i].nfrags = 0;
                pginfos[i].clone_skb = clone_skb_d;
                pginfos[i].clone_skb = clone_skb_d;
                pginfos[i].ipg = ipg_d;
                pginfos[i].ipg = ipg_d;
                pginfos[i].count = count_d;
                pginfos[i].count = count_d;
                pginfos[i].sofar = 0;
                pginfos[i].sofar = 0;
                pginfos[i].hh[12] = 0x08; /* fill in protocol.  Rest is filled in later. */
                pginfos[i].hh[12] = 0x08; /* fill in protocol.  Rest is filled in later. */
                pginfos[i].hh[13] = 0x00;
                pginfos[i].hh[13] = 0x00;
                pginfos[i].udp_src_min = 9; /* sink NULL */
                pginfos[i].udp_src_min = 9; /* sink NULL */
                pginfos[i].udp_src_max = 9;
                pginfos[i].udp_src_max = 9;
                pginfos[i].udp_dst_min = 9;
                pginfos[i].udp_dst_min = 9;
                pginfos[i].udp_dst_max = 9;
                pginfos[i].udp_dst_max = 9;
 
 
                sprintf(pginfos[i].fname, "net/%s/pg%i", PG_PROC_DIR, i);
                sprintf(pginfos[i].fname, "net/%s/pg%i", PG_PROC_DIR, i);
                pginfos[i].proc_ent = create_proc_entry(pginfos[i].fname, 0600, 0);
                pginfos[i].proc_ent = create_proc_entry(pginfos[i].fname, 0600, 0);
                if (!pginfos[i].proc_ent) {
                if (!pginfos[i].proc_ent) {
                        printk("pktgen: Error: cannot create net/%s/pg procfs entry.\n", PG_PROC_DIR);
                        printk("pktgen: Error: cannot create net/%s/pg procfs entry.\n", PG_PROC_DIR);
                        goto cleanup_mem;
                        goto cleanup_mem;
                }
                }
                pginfos[i].proc_ent->read_proc = proc_read;
                pginfos[i].proc_ent->read_proc = proc_read;
                pginfos[i].proc_ent->write_proc = proc_write;
                pginfos[i].proc_ent->write_proc = proc_write;
                pginfos[i].proc_ent->data = (void*)(long)(i);
                pginfos[i].proc_ent->data = (void*)(long)(i);
 
 
                sprintf(pginfos[i].busy_fname, "net/%s/pg_busy%i",  PG_PROC_DIR, i);
                sprintf(pginfos[i].busy_fname, "net/%s/pg_busy%i",  PG_PROC_DIR, i);
                pginfos[i].busy_proc_ent = create_proc_entry(pginfos[i].busy_fname, 0, 0);
                pginfos[i].busy_proc_ent = create_proc_entry(pginfos[i].busy_fname, 0, 0);
                if (!pginfos[i].busy_proc_ent) {
                if (!pginfos[i].busy_proc_ent) {
                        printk("pktgen: Error: cannot create net/%s/pg_busy procfs entry.\n", PG_PROC_DIR);
                        printk("pktgen: Error: cannot create net/%s/pg_busy procfs entry.\n", PG_PROC_DIR);
                        goto cleanup_mem;
                        goto cleanup_mem;
                }
                }
                pginfos[i].busy_proc_ent->read_proc = proc_busy_read;
                pginfos[i].busy_proc_ent->read_proc = proc_busy_read;
                pginfos[i].busy_proc_ent->data = (void*)(long)(i);
                pginfos[i].busy_proc_ent->data = (void*)(long)(i);
        }
        }
        return 0;
        return 0;
 
 
cleanup_mem:
cleanup_mem:
        for (i = 0; i<MAX_PKTGEN; i++) {
        for (i = 0; i<MAX_PKTGEN; i++) {
                if (strlen(pginfos[i].fname)) {
                if (strlen(pginfos[i].fname)) {
                        remove_proc_entry(pginfos[i].fname, NULL);
                        remove_proc_entry(pginfos[i].fname, NULL);
                }
                }
                if (strlen(pginfos[i].busy_fname)) {
                if (strlen(pginfos[i].busy_fname)) {
                        remove_proc_entry(pginfos[i].busy_fname, NULL);
                        remove_proc_entry(pginfos[i].busy_fname, NULL);
                }
                }
        }
        }
        return -ENOMEM;
        return -ENOMEM;
}
}
 
 
 
 
static void __exit cleanup(void)
static void __exit cleanup(void)
{
{
        int i;
        int i;
        for (i = 0; i<MAX_PKTGEN; i++) {
        for (i = 0; i<MAX_PKTGEN; i++) {
                if (strlen(pginfos[i].fname)) {
                if (strlen(pginfos[i].fname)) {
                        remove_proc_entry(pginfos[i].fname, NULL);
                        remove_proc_entry(pginfos[i].fname, NULL);
                }
                }
                if (strlen(pginfos[i].busy_fname)) {
                if (strlen(pginfos[i].busy_fname)) {
                        remove_proc_entry(pginfos[i].busy_fname, NULL);
                        remove_proc_entry(pginfos[i].busy_fname, NULL);
                }
                }
        }
        }
        remove_proc_dir();
        remove_proc_dir();
}
}
 
 
module_init(init);
module_init(init);
module_exit(cleanup);
module_exit(cleanup);
 
 
MODULE_AUTHOR("Robert Olsson <robert.olsson@its.uu.se");
MODULE_AUTHOR("Robert Olsson <robert.olsson@its.uu.se");
MODULE_DESCRIPTION("Packet Generator tool");
MODULE_DESCRIPTION("Packet Generator tool");
MODULE_LICENSE("GPL");
MODULE_LICENSE("GPL");
MODULE_PARM(count_d, "i");
MODULE_PARM(count_d, "i");
MODULE_PARM(ipg_d, "i");
MODULE_PARM(ipg_d, "i");
MODULE_PARM(cpu_speed, "i");
MODULE_PARM(cpu_speed, "i");
MODULE_PARM(clone_skb_d, "i");
MODULE_PARM(clone_skb_d, "i");
 
 
 
 
 
 
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.