2 * Mausezahn - A fast versatile traffic generator
3 * Copyright (C) 2008 Herbert Haas
5 * This program is free software; you can redistribute it and/or modify it under
6 * the terms of the GNU General Public License version 2 as published by the
7 * Free Software Foundation.
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
14 * You should have received a copy of the GNU General Public License along with
15 * this program; if not, see http://www.gnu.org/licenses/gpl-2.0.html
22 // ***************************************************************************
23 // This sections contains (as alternative to 'send_frame' in send.c)
24 // a layer-2 based flexible sending function.
26 // Layer-2 modifications such as 802.1Q and MPLS is considered here!
28 // ***************************************************************************
34 libnet_ptag_t
create_eth_frame (libnet_t
*l
, libnet_ptag_t t3
, libnet_ptag_t t4
)
37 char errbuf
[LIBNET_ERRBUF_SIZE
];
38 libnet_ptag_t t
=0, tmpls
;
43 int i
=0, j
, mlen
, mkomma
, len
, count
, offset
=0, found_colon
=0;
46 char verbose_mpls_string
[128];
51 char *saveptr
, *ptrsubstring
, substring
[16], tmp
[4*MAX_8021Q_TAGS
];
53 u_int16_t vlan
; // 12 bit value (0..4095)
54 u_int8_t dot1Q
[4*MAX_8021Q_TAGS
], *ptr
;
55 u_int16_t dot1Q_eth_type
=0x8100;
58 int isdot1Q
, tcp_seq_delta
, dp_isrange
, sp_isrange
, ip_dst_isrange
, ip_src_isrange
, eth_src_rand
, rtp_mode
=0;
66 ////////////////////////////////////////////////////
67 // Prepare MPLS header if required
70 // first check how many labels have been specified:
71 mlen
= strlen (tx
.mpls_txt
);
74 for (i
=0; i
<mlen
; i
++)
76 if (tx
.mpls_txt
[i
]==',') mkomma
++;
79 f
= strtok_r (tx
.mpls_txt
, ",", &saveptr
);
99 if ( get_mpls_params(mtag
) ) // error?
101 fprintf(stderr
," mz/get_mpls_params: MPLS Parameters problem.\n");
105 tmpls
= libnet_build_mpls(tx
.mpls_label
,
116 fprintf(stderr
, " mz/create_ip_packet: Can't build MPLS header: %s\n", libnet_geterror(l
));
122 sprintf(verbose_mpls_string
,"[%u:%u:%u:%u]",
127 strcat(tx
.mpls_verbose_string
, verbose_mpls_string
);
128 strcat(tx
.mpls_verbose_string
, " ");
134 while ( (f
=strtok_r(NULL
, ",", &saveptr
)) != NULL
);
144 ////////////////////////////////////////////////////////////////////////////////////////////
145 // Evaluate Ethernet CLI options (-a and -b)
146 if (check_eth_mac_txt(ETH_DST
)) // if true then problem (invalid user input?)
148 str2hex("ff:ff:ff:ff:ff:ff",tx
.eth_dst
, 6); // the default
151 // if not specified then own MAC will be used automatically
152 (void) check_eth_mac_txt(ETH_SRC
);
155 // Get CLI arguments:
156 // If NOT set, default: 0x800 or ETHERTYPE_MPLS if MPLS is used (see init.c)
157 if (getarg(tx
.arg_string
,"ether_type", argval
)==1)
159 et_len
= str2hex (argval
, et
, 2);
163 else // 2 bytes specified
164 tx
.eth_type
= 256 * et
[0] + et
[1];
166 //tx.eth_type = (u_int16_t) str2int(argval);
176 /////////////////////////////////////////////////////////////////////////////////
177 // Ethernet with 802.1Q
179 // If multiple 802.1Q tags are specified then we need to build the whole
180 // frame manually because libnet only supports adding a single VLAN header.
181 // The easiest solution is to create the hex-string of the 802.1Q-chain as
182 // u_int8_t QinQ[] then add the IP packet as payload...
184 if (tx
.dot1Q
) // actually contains the number of VLAN tags
187 // we want our own context!
188 L
= libnet_init(LIBNET_LINK_ADV
, tx
.device
, errbuf
);
191 fprintf(stderr
, "%s", errbuf
);
195 strncpy(tmp
,tx
.dot1Q_txt
,(4*MAX_8021Q_TAGS
));
196 ptrsubstring
= strtok_r(tmp
, ",.", &saveptr
);
201 strncpy(substring
, ptrsubstring
, 16);
203 // Get CoS and VLAN ID from partial string
204 len
= strlen(substring
);
206 for (i
=0; i
<len
; i
++)
208 if (substring
[i
]==':') found_colon
=1;
210 if (found_colon
) // Both CoS and VLAN specified
212 left
= strtok (substring
, ":");
213 right
= strtok (NULL
, ":");
214 CoS
= (u_int8_t
) str2int (left
);
215 vlan
= (u_int16_t
) str2int (right
);
217 else // Only VLAN specified
219 vlan
= (u_int16_t
) str2int (substring
);
224 fprintf(stderr
, " mz/create_eth_frame: CoS too high, adjusted to 7\n");
230 fprintf(stderr
, " mz/create_eth_frame: VLAN number too high, adjusted to 4095\n");
234 // create 4 byte 802.1Q header:
236 dot1Q
[bytecnt
+0]=0x81;
237 dot1Q
[bytecnt
+1]=0x00;
238 ptr
= (u_int8_t
*) &vlan
;
239 dot1Q
[bytecnt
+3]=*ptr
;
241 *ptr
= *ptr
^ (CoS
<<5); // add CoS
242 dot1Q
[bytecnt
+2]=*ptr
;
244 //printf("%02x %02x %02x %02x\n",dot1Q[bytecnt+0],dot1Q[bytecnt+1],dot1Q[bytecnt+2],dot1Q[bytecnt+3]);
245 bytecnt
+=4; // next tag (note that bytecnt will finally hold the number of used bytes!)
247 } while ( (ptrsubstring
= strtok_r(NULL
, ",.", &saveptr
)) !=NULL
); //get all VLAN tags
249 // now create the whole packet:
251 dot1Q_eth_type
= 0x8100; //these are also the first two bytes of dot1Q[]
254 for (i
=0;i
<bytecnt
;i
++)
256 tx
.eth_payload
[i
]=dot1Q
[i
+2];
259 // now add official EtherType for the payload (this has been determined some lines above)
260 ptr
= (u_int8_t
*) & tx
.eth_type
;
261 tx
.eth_payload
[i
+1]= *ptr
;
263 tx
.eth_payload
[i
]= *ptr
;
269 // ---- now all 802.1Q headers are genereated ----
270 // ---- and are placed already in tx.eth_payload ----
271 // ---- (and 'i' points to the next free byte) ----
276 // Finally get all bytes of upper layers (IP packet and payload)
277 if (libnet_adv_cull_packet(l
, &packet
, &packet_s
) == -1)
279 fprintf(stderr
, "%s", libnet_geterror(l
));
282 // Copy the upper layer data to the eth_payload
283 for (j
=0; j
<packet_s
; j
++)
285 tx
.eth_payload
[j
+offset
]=packet
[j
];
288 // 'libnet_adv_cull_packet' performs an implicit malloc() and a corresponding call
289 // to libnet_adv_free_packet() should be made to free the memory packet occupies:
290 libnet_adv_free_packet(l
, packet
);
292 tx
.eth_payload_s
= j
+offset
;
293 tx
.eth_type
= dot1Q_eth_type
;
295 t
= libnet_build_ethernet (tx
.eth_dst
,
305 fprintf(stderr
, " mz/create_eth_frame: Can't build Ethernet header: %s\n",
310 // NOW the whole frame is ready to send!
314 else // normal Ethernet header without any 802.1Q-tag or MPLS-label
318 t
= libnet_build_ethernet (tx
.eth_dst
,
328 fprintf(stderr
, " mz/create_eth_frame: Can't build Ethernet header: %s\n",
334 /////////////////////////////////////////////////////////////////////////////
336 // Now send everything - maybe lots of times with modifications.
340 // local vars are faster :-)
343 eth_src_rand
= tx
.eth_src_rand
;
344 tcp_seq_delta
= tx
.tcp_seq_delta
;
345 dp_isrange
= tx
.dp_isrange
;
346 sp_isrange
= tx
.sp_isrange
;
347 ip_dst_isrange
= tx
.ip_dst_isrange
;
348 ip_src_isrange
= tx
.ip_src_isrange
| tx
.ip_src_rand
; // either case should call update_SA()
350 if (mode
== RTP
) rtp_mode
= 1;
352 if (count
==0) goto AGAIN
;
354 for (i
=0; i
<count
; i
++)
361 // Get all bytes of upper layers (IP packet and payload)
362 if (libnet_adv_cull_packet(l
, &packet
, &packet_s
) == -1)
364 fprintf(stderr
, "%s", libnet_geterror(l
));
367 // Copy the upper layer data to the eth_payload
368 for (j
=0; j
<packet_s
; j
++)
370 tx
.eth_payload
[j
+offset
]=packet
[j
];
373 // 'libnet_adv_cull_packet' performs an implicit malloc() and a corresponding call
374 // to libnet_adv_free_packet() should be made to free the memory packet occupies:
375 libnet_adv_free_packet(l
, packet
);
377 if (eth_src_rand
) update_Eth_SA(L
, t
);
379 t
= libnet_build_ethernet (tx
.eth_dst
,
388 fprintf(stderr
, " mz/create_eth_frame: Can't build Ethernet header: %s\n",
392 if (verbose
) (void) print_frame_details();
395 else // No QinQ and/or MPLS modifications => use normal 'l' context:
397 if (eth_src_rand
) update_Eth_SA(l
, t
);
398 if (verbose
) (void) print_frame_details();
403 // if (verbose) (void) print_frame_details();
404 if (delay
) SLEEP (delay
);
409 if (update_TCP_SQNR(l
, t4
)==0) // end of range not yet reached
417 if (update_DPORT(l
, t4
)==0) // end of range not yet reached
425 if (update_SPORT(l
, t4
)==0) // end of range not yet reached
433 if (update_IP_DA(l
, t3
)==0) // end of range not yet reached
441 if (update_IP_SA(l
, t3
)==0) // end of range not yet reached
448 if (rtp_mode
) // update SQNR and Timestamps in RTP header and payload
454 if (!count
) goto AGAIN
;
468 void print_dot1Q_help(void)
474 "| 802.1Q header Syntax: -Q tag[,tag[,tag[,...]]]\n"
475 "| where each tag may consist of a CoS value using the syntax:\n"
477 "| <CoS>:<tag value>\n"
483 "| # mz -Q 5:100,200\n"
484 "| # mz -Q 5:100,7:200\n"
485 "| # mz -Q 100,200,300,5:400\n"