summaryrefslogtreecommitdiff
path: root/staging/send_eth.c
diff options
context:
space:
mode:
Diffstat (limited to 'staging/send_eth.c')
-rw-r--r--staging/send_eth.c491
1 files changed, 491 insertions, 0 deletions
diff --git a/staging/send_eth.c b/staging/send_eth.c
new file mode 100644
index 0000000..ae811e8
--- /dev/null
+++ b/staging/send_eth.c
@@ -0,0 +1,491 @@
+/*
+ * Mausezahn - A fast versatile traffic generator
+ * Copyright (C) 2008 Herbert Haas
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see http://www.gnu.org/licenses/gpl-2.0.html
+ *
+*/
+
+
+
+
+// ***************************************************************************
+// This sections contains (as alternative to 'send_frame' in send.c)
+// a layer-2 based flexible sending function.
+//
+// Layer-2 modifications such as 802.1Q and MPLS is considered here!
+//
+// ***************************************************************************
+
+
+
+#include "mz.h"
+
+libnet_ptag_t create_eth_frame (libnet_t *l, libnet_ptag_t t3, libnet_ptag_t t4)
+{
+ libnet_t *L=NULL;
+ char errbuf[LIBNET_ERRBUF_SIZE];
+ libnet_ptag_t t=0, tmpls;
+ char argval[128];
+ u_int8_t et[2];
+ int et_len;
+
+ int i=0, j, mlen, mkomma, len, count, offset=0, found_colon=0;
+ char *left, *right;
+ char *f, mtag[64];
+ char verbose_mpls_string[128];
+
+ u_int8_t *packet;
+ u_int32_t packet_s;
+
+ char *saveptr, *ptrsubstring, substring[16], tmp[4*MAX_8021Q_TAGS];
+ u_int8_t CoS; // 0..7
+ u_int16_t vlan; // 12 bit value (0..4095)
+ u_int8_t dot1Q[4*MAX_8021Q_TAGS], *ptr;
+ u_int16_t dot1Q_eth_type=0x8100;
+ int bytecnt=0;
+
+ int isdot1Q, tcp_seq_delta, dp_isrange, sp_isrange, ip_dst_isrange, ip_src_isrange, eth_src_rand, rtp_mode=0;
+ unsigned int delay;
+
+
+
+
+
+
+ ////////////////////////////////////////////////////
+ // Prepare MPLS header if required
+ if (tx.mpls)
+ {
+ // first check how many labels have been specified:
+ mlen = strlen (tx.mpls_txt);
+ mkomma=0;
+
+ for (i=0; i<mlen; i++)
+ {
+ if (tx.mpls_txt[i]==',') mkomma++;
+ }
+
+ f = strtok_r (tx.mpls_txt, ",", &saveptr);
+
+ tx.mpls_bos=1;
+
+ do
+ {
+ strncpy(mtag, f, 64);
+ /*
+ if (mkomma==0)
+ {
+ tx.mpls_bos=0;
+ }
+ else
+ {
+ printf("BOS=1\n");
+ tx.mpls_bos=1;
+ }
+ */
+
+
+ if ( get_mpls_params(mtag) ) // error?
+ {
+ fprintf(stderr," mz/get_mpls_params: MPLS Parameters problem.\n");
+ exit (0);
+ }
+
+ tmpls = libnet_build_mpls(tx.mpls_label,
+ tx.mpls_exp,
+ tx.mpls_bos,
+ tx.mpls_ttl,
+ NULL,
+ 0,
+ l,
+ 0);
+
+ if (tmpls == -1)
+ {
+ fprintf(stderr, " mz/create_ip_packet: Can't build MPLS header: %s\n", libnet_geterror(l));
+ exit (0);
+ }
+
+ if (verbose)
+ {
+ sprintf(verbose_mpls_string,"[%u:%u:%u:%u]",
+ tx.mpls_label,
+ tx.mpls_exp,
+ tx.mpls_bos,
+ tx.mpls_ttl);
+ strcat(tx.mpls_verbose_string, verbose_mpls_string);
+ strcat(tx.mpls_verbose_string, " ");
+ }
+
+ tx.mpls_bos=0;
+ mkomma--;
+ }
+ while ( (f=strtok_r(NULL, ",", &saveptr)) != NULL);
+
+ }
+
+
+
+
+
+
+
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ // Evaluate Ethernet CLI options (-a and -b)
+ if (check_eth_mac_txt(ETH_DST)) // if true then problem (invalid user input?)
+ {
+ str2hex("ff:ff:ff:ff:ff:ff",tx.eth_dst, 6); // the default
+ }
+
+ // if not specified then own MAC will be used automatically
+ (void) check_eth_mac_txt(ETH_SRC);
+
+
+ // Get CLI arguments:
+ // If NOT set, default: 0x800 or ETHERTYPE_MPLS if MPLS is used (see init.c)
+ if (getarg(tx.arg_string,"ether_type", argval)==1)
+ {
+ et_len = str2hex (argval, et, 2);
+
+ if (et_len==1)
+ tx.eth_type = et[0];
+ else // 2 bytes specified
+ tx.eth_type = 256 * et[0] + et[1];
+
+ //tx.eth_type = (u_int16_t) str2int(argval);
+ }
+
+
+
+
+
+
+
+
+ /////////////////////////////////////////////////////////////////////////////////
+ // Ethernet with 802.1Q
+ //
+ // If multiple 802.1Q tags are specified then we need to build the whole
+ // frame manually because libnet only supports adding a single VLAN header.
+ // The easiest solution is to create the hex-string of the 802.1Q-chain as
+ // u_int8_t QinQ[] then add the IP packet as payload...
+ //
+ if (tx.dot1Q) // actually contains the number of VLAN tags
+ {
+
+ // we want our own context!
+ L = libnet_init(LIBNET_LINK_ADV, tx.device, errbuf);
+ if (L == NULL)
+ {
+ fprintf(stderr, "%s", errbuf);
+ exit(EXIT_FAILURE);
+ }
+
+ strncpy(tmp,tx.dot1Q_txt,(4*MAX_8021Q_TAGS));
+ ptrsubstring = strtok_r(tmp, ",.", &saveptr);
+ bytecnt=0;
+ do
+ {
+ // make a local copy
+ strncpy(substring, ptrsubstring, 16);
+ CoS=0; vlan=0;
+ // Get CoS and VLAN ID from partial string
+ len = strlen(substring);
+ found_colon=0;
+ for (i=0; i<len; i++)
+ {
+ if (substring[i]==':') found_colon=1;
+ }
+ if (found_colon) // Both CoS and VLAN specified
+ {
+ left = strtok (substring, ":");
+ right = strtok (NULL, ":");
+ CoS = (u_int8_t) str2int (left);
+ vlan = (u_int16_t) str2int (right);
+ }
+ else // Only VLAN specified
+ {
+ vlan = (u_int16_t) str2int (substring);
+ }
+
+ if (CoS > 7)
+ {
+ fprintf(stderr, " mz/create_eth_frame: CoS too high, adjusted to 7\n");
+ CoS = 7;
+ }
+
+ if (vlan > 4095)
+ {
+ fprintf(stderr, " mz/create_eth_frame: VLAN number too high, adjusted to 4095\n");
+ vlan = 4095;
+ }
+
+ // create 4 byte 802.1Q header:
+
+ dot1Q[bytecnt+0]=0x81;
+ dot1Q[bytecnt+1]=0x00;
+ ptr = (u_int8_t*) &vlan;
+ dot1Q[bytecnt+3]=*ptr;
+ ptr++;
+ *ptr = *ptr ^ (CoS<<5); // add CoS
+ dot1Q[bytecnt+2]=*ptr;
+ //check:
+ //printf("%02x %02x %02x %02x\n",dot1Q[bytecnt+0],dot1Q[bytecnt+1],dot1Q[bytecnt+2],dot1Q[bytecnt+3]);
+ bytecnt+=4; // next tag (note that bytecnt will finally hold the number of used bytes!)
+
+ } while ( (ptrsubstring = strtok_r(NULL, ",.", &saveptr)) !=NULL); //get all VLAN tags
+
+ // now create the whole packet:
+
+ dot1Q_eth_type = 0x8100; //these are also the first two bytes of dot1Q[]
+ bytecnt = bytecnt-2;
+
+ for (i=0;i<bytecnt;i++)
+ {
+ tx.eth_payload[i]=dot1Q[i+2];
+ }
+
+ // now add official EtherType for the payload (this has been determined some lines above)
+ ptr = (u_int8_t*) & tx.eth_type;
+ tx.eth_payload[i+1]= *ptr;
+ ptr++;
+ tx.eth_payload[i]= *ptr;
+ offset = i+2;
+
+ // -
+ // --
+ // ---
+ // ---- now all 802.1Q headers are genereated ----
+ // ---- and are placed already in tx.eth_payload ----
+ // ---- (and 'i' points to the next free byte) ----
+ // ---
+ // --
+ // -
+
+ // Finally get all bytes of upper layers (IP packet and payload)
+ if (libnet_adv_cull_packet(l, &packet, &packet_s) == -1)
+ {
+ fprintf(stderr, "%s", libnet_geterror(l));
+ }
+
+ // Copy the upper layer data to the eth_payload
+ for (j=0; j<packet_s; j++)
+ {
+ tx.eth_payload[j+offset]=packet[j];
+ }
+
+ // 'libnet_adv_cull_packet' performs an implicit malloc() and a corresponding call
+ // to libnet_adv_free_packet() should be made to free the memory packet occupies:
+ libnet_adv_free_packet(l, packet);
+
+ tx.eth_payload_s = j+offset;
+ tx.eth_type = dot1Q_eth_type;
+
+ t = libnet_build_ethernet (tx.eth_dst,
+ tx.eth_src,
+ tx.eth_type,
+ tx.eth_payload,
+ tx.eth_payload_s,
+ L,
+ 0);
+
+ if (t == -1)
+ {
+ fprintf(stderr, " mz/create_eth_frame: Can't build Ethernet header: %s\n",
+ libnet_geterror(l));
+ exit(EXIT_FAILURE);
+ }
+
+ // NOW the whole frame is ready to send!
+
+ }
+
+ else // normal Ethernet header without any 802.1Q-tag or MPLS-label
+
+ {
+
+ t = libnet_build_ethernet (tx.eth_dst,
+ tx.eth_src,
+ tx.eth_type,
+ NULL, // the payload
+ 0,
+ l,
+ 0);
+
+ if (t == -1)
+ {
+ fprintf(stderr, " mz/create_eth_frame: Can't build Ethernet header: %s\n",
+ libnet_geterror(l));
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ /////////////////////////////////////////////////////////////////////////////
+ //
+ // Now send everything - maybe lots of times with modifications.
+ //
+ //
+
+ // local vars are faster :-)
+ count = tx.count;
+ delay = tx.delay;
+ eth_src_rand = tx.eth_src_rand;
+ tcp_seq_delta = tx.tcp_seq_delta;
+ dp_isrange = tx.dp_isrange;
+ sp_isrange = tx.sp_isrange;
+ ip_dst_isrange = tx.ip_dst_isrange;
+ ip_src_isrange = tx.ip_src_isrange | tx.ip_src_rand; // either case should call update_SA()
+ isdot1Q = tx.dot1Q;
+ if (mode == RTP) rtp_mode = 1;
+
+ if (count==0) goto AGAIN;
+
+ for (i=0; i<count; i++)
+ {
+
+ AGAIN:
+
+ if (isdot1Q)
+ {
+ // Get all bytes of upper layers (IP packet and payload)
+ if (libnet_adv_cull_packet(l, &packet, &packet_s) == -1)
+ {
+ fprintf(stderr, "%s", libnet_geterror(l));
+ }
+
+ // Copy the upper layer data to the eth_payload
+ for (j=0; j<packet_s; j++)
+ {
+ tx.eth_payload[j+offset]=packet[j];
+ }
+
+ // 'libnet_adv_cull_packet' performs an implicit malloc() and a corresponding call
+ // to libnet_adv_free_packet() should be made to free the memory packet occupies:
+ libnet_adv_free_packet(l, packet);
+
+ if (eth_src_rand) update_Eth_SA(L, t);
+
+ t = libnet_build_ethernet (tx.eth_dst,
+ tx.eth_src,
+ tx.eth_type,
+ tx.eth_payload,
+ tx.eth_payload_s,
+ L,
+ t);
+ if (t == -1)
+ {
+ fprintf(stderr, " mz/create_eth_frame: Can't build Ethernet header: %s\n",
+ libnet_geterror(l));
+ exit(EXIT_FAILURE);
+ }
+ if (verbose) (void) print_frame_details();
+ libnet_write(L);
+ }
+ else // No QinQ and/or MPLS modifications => use normal 'l' context:
+ {
+ if (eth_src_rand) update_Eth_SA(l, t);
+ if (verbose) (void) print_frame_details();
+ libnet_write(l);
+ }
+
+
+// if (verbose) (void) print_frame_details();
+ if (delay) SLEEP (delay);
+
+
+ if (tcp_seq_delta)
+ {
+ if (update_TCP_SQNR(l, t4)==0) // end of range not yet reached
+ {
+ goto AGAIN;
+ }
+ }
+
+ if (dp_isrange)
+ {
+ if (update_DPORT(l, t4)==0) // end of range not yet reached
+ {
+ goto AGAIN;
+ }
+ }
+
+ if (sp_isrange)
+ {
+ if (update_SPORT(l, t4)==0) // end of range not yet reached
+ {
+ goto AGAIN;
+ }
+ }
+
+ if (ip_dst_isrange)
+ {
+ if (update_IP_DA(l, t3)==0) // end of range not yet reached
+ {
+ goto AGAIN;
+ }
+ }
+
+ if (ip_src_isrange)
+ {
+ if (update_IP_SA(l, t3)==0) // end of range not yet reached
+ {
+ goto AGAIN;
+ }
+ }
+
+
+ if (rtp_mode) // update SQNR and Timestamps in RTP header and payload
+ {
+ update_RTP(l, t4);
+ }
+
+
+ if (!count) goto AGAIN;
+ }
+
+
+ libnet_destroy(l);
+ if (isdot1Q)
+ libnet_destroy(L);
+
+
+ return t;
+}
+
+
+
+void print_dot1Q_help(void)
+{
+
+ fprintf(stderr,"\n"
+ MAUSEZAHN_VERSION
+ "\n"
+ "| 802.1Q header Syntax: -Q tag[,tag[,tag[,...]]]\n"
+ "| where each tag may consist of a CoS value using the syntax:\n"
+ "|\n"
+ "| <CoS>:<tag value>\n"
+ "|\n"
+ "| Examples:\n"
+ "|\n"
+ "| # mz -Q 100\n"
+ "| # mz -Q 5:100\n"
+ "| # mz -Q 5:100,200\n"
+ "| # mz -Q 5:100,7:200\n"
+ "| # mz -Q 100,200,300,5:400\n"
+ "\n\n");
+
+ exit(0);
+}
+
+