public inbox for netdev@vger.kernel.org 
 help / color / mirror / Atom feed
* Program to test/use the 'low level Ethernet debugging features'
@ 2012-02-17 18:12 Ben Greear
  0 siblings, 0 replies; only message in thread
From: Ben Greear @ 2012-02-17 18:12 UTC (permalink / raw)
  To: netdev; +Cc: Jeff Kirsher, Brown, Aaron F

[-- Attachment #1: Type: text/plain, Size: 491 bytes --]

I'm attaching a small program I wrote to test the 'send custom fcs'
patches.  You can also test the rx-fcs and rx-all logic by making
sure that the NIC properly handles the packets with bad FCS.

For those that might have seen a previous version of this, I added
the ability to specify the dest mac address which means you don't
have to put the receiving NIC into PROMISC mode now.

Thanks,
Ben

-- 
Ben Greear <greearb@candelatech•com>
Candela Technologies Inc  http://www.candelatech.com


[-- Attachment #2: nofcs.c --]
[-- Type: text/plain, Size: 5748 bytes --]

/**  This tool can be used to send packets with custom (ie, bad) Ethernet
 * Frame Checksum.
 *
 * This requires the 'Low-level Ethernet debugging features.' patch series,
 * which supports e100, e1000, and e1000e drivers.  Support for igb and
 * hopefully ixgbe will be added soon.
 *
 * To compile:  gcc -Wall nofcs.c -o nofcs
 *
 * Usage:
 *  Send 10 packets out eth0 with bad FCS:
 *    ./nofcs -i eth0 -dm 00:11:22:33:44:55
 *
 * To receive the packets, you could use a version of ethtool that supports
 * the feature strings logic posted by Michal Miroslaw and enable 'rx-all'
 * and optionally: 'rx-fcs'.
 *
 * The patch for ethtool is posted here:
 *    http://patchwork.ozlabs.org/patch/96374/
 *
 * This code was written by Ben Greear <greearb@candelatech•com>
 * and is hereby released into the public domain with no restrictions.
 * February 17, 2012.
 *
 */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <linux/if_packet.h>
#include <ctype.h>
#include <arpa/inet.h>
#include <net/if.h>


static char* dev = NULL;
static int count = 10;
static int bytes = 128; // not counting fcs
static unsigned int fcs = 0xdeadbeef;
static char* dst_mac = NULL;

static void print_usage() {
   printf("usage: -i [dev-name] -b [byte-count] -c [packet-count] -f [fcs] -dm [dest-mac]\n"
          "Example: nofcs -i eth0 -b 128 -c 10 -dm 00:11:22:33:44:55 -f 0xdeadbeef\n\n");
}


int createPacketSocket(const char* dev_name, int ether_type) {
   int s = socket(PF_PACKET, SOCK_RAW, htons(ether_type));
   int r; //retval
   struct sockaddr_ll myaddr;

   if (s < 0) {
      perror("socket(PF_PACKET)");
      exit(1);
   }

   memset(&myaddr, '\0', sizeof(myaddr));
   myaddr.sll_family = AF_PACKET;
   myaddr.sll_protocol = htons(ether_type);
   myaddr.sll_ifindex = if_nametoindex(dev_name);
   if (myaddr.sll_ifindex == 0) {
      perror("if_nametoindex");
      exit(1);
   }
      
   r = bind(s, (struct sockaddr*)(&myaddr), sizeof(myaddr));
   if (r < 0) {
      perror("bind");
      exit(1);
   }
   return s;
}

static int toMacString(unsigned char* rslt_mac, const char* raw_mac) {
   /* Turn HEX into bytes.  First, gather all the useful HEX */
   char tmp[12]; /* More than 12 is useless, at least right now */
   char c;
   int j = 0; /* tmp's index. */
   int i;
   char tmp_bt[3];

   for (i = 0; i<strlen(raw_mac); i++) {
      c = toupper(raw_mac[i]);
      if (((c >= '0') && (c <= '9')) || ((c >= 'A') && (c <= 'F'))) {
         tmp[j] = c;
         if (j == 11) {
            break; /* done */
         }
         j++;
      }
      else {
         if ((c == ':') || (c == ' ') || (c == '.')) {
            /* Ok, valid divider */
         }
         else {
            printf("ERROR:  Invalid characters found in the MAC input string: %s index: %i  character: %c\n",
                   raw_mac, i, c);
            exit(1);
         }
      }
   }

   if (j != 11) {
      printf("ERROR:  Not enough HEX values in the input string.\n");
      exit(1);
   }

   for (i = 0; i<6; i++) {
      tmp_bt[0] = tmp[i*2];
      tmp_bt[1] = tmp[i*2 +1];
      tmp_bt[2] = 0;
      rslt_mac[i] = (char)(strtol(tmp_bt, NULL, 16) & 0xFF); /* base 16 (HEX) */
   }
   return 0;
}//toMacString

int main(int argc, char **argv) {
   int i;
   int s;
   unsigned char* buf;
   unsigned int opt = 1;

   dev = strdup("eth0");
   dst_mac = strdup("00:11:22:33:44:55");

   for (i = 1; i<argc; i++) {

      /* Each argument requires a value */
      if (argc < i+1) {
         printf("ERROR:  Not enough arguments, argc: %i  i: %i\n",
                argc, i);
         print_usage();
         exit(1);
      }
      
      if (strcasecmp(argv[i], "-i") == 0) {
         free(dev);
         dev = strdup(argv[i + 1]);
      }
      else if (strcasecmp(argv[i], "-c") == 0) {
         count = strtoll(argv[i + 1], NULL, 0);
      }
      else if (strcasecmp(argv[i], "-b") == 0) {
         bytes = strtoll(argv[i + 1], NULL, 0);
      }
      else if (strcasecmp(argv[i], "-f") == 0) {
         fcs = strtoll(argv[i + 1], NULL, 0);
      }
      else if (strcasecmp(argv[i], "-dm") == 0) {
         free(dst_mac);
         dst_mac = strdup(argv[i + 1]);
      }
      else {
         printf("Unknown argument: %s\n", argv[i]);
         print_usage();
         exit(1);
      }
      i++;
   }

   if (bytes < 14) {
      printf("ERROR: Need at least 14 bytes of payload for ether header.\n");
      exit(1);
   }

   if (bytes < 60) {
      printf("WARNING: Most drivers require Ethernet frame of at least 60 bytes.\n");
   }

   /* Just use some made-up eth type */
   s = createPacketSocket(dev, 0x1111);

   if (setsockopt(s, SOL_SOCKET, 42 /* SO_NOFCS, see asm-x86/socket.h in linux kernel*/,
                  (char*)&opt, sizeof(opt)) < 0) {
      perror("setsockopt SO_NOFCS");
      printf("Kernel doesn't support the NO_FCS feature it seems.\n");
      exit(2);
   }

   buf = malloc(bytes + 4);

   /* mostly hard-code an ether header */
   toMacString(buf, dst_mac);

   /* src 00:22:22:22:22:22 */
   buf[6] = 0;
   for (i = 7; i<11; i++)
      buf[i] = 0x22;

   /* ether type */
   buf[12] = 0x11;
   buf[13] = 0x11;

   for (i = 14; i<bytes; i++) {
      buf[i] = i;
   }

   /* append our FCS */
   buf[bytes] = (fcs >> 24) & 0xff;
   buf[bytes + 1] = (fcs >> 16) & 0xff;
   buf[bytes + 2] = (fcs >> 8) & 0xff;
   buf[bytes + 3] = fcs & 0xff;

   for (i = 0; i<count; i++) {
      if (sendto(s, buf, bytes + 4, 0, NULL, 0) < 0) {
         perror("sendto");
         exit(1);
      }
   }
   
   printf("Sent %i packets.\n", count);

   /* Clean up, just to be nice */
   free(dst_mac);
   free(dev);
   free(buf);
   close(s);
   
   exit(0);
}

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2012-02-17 18:12 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-02-17 18:12 Program to test/use the 'low level Ethernet debugging features' Ben Greear

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox