/* * netsniff-ng - the packet sniffing beast * Mausezahn, a fast versatile traffic generator * Copyright 2008, 2009, 2010 Herbert Haas. * Subject to the GPL, version 2. */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "mz.h" #include "cli.h" #include "mops.h" #include "config.h" #include "llist.h" #include "die.h" #include "dev.h" int verbose_level = 0; static const char *short_options = "46hqvVSxra:A:b:B:c:d:E:f:F:l:p:P:t:T:M:Q:X:"; static void signal_handler(int number) { clean_up(number); } void clean_up(int sig) { int i; struct arp_table_struct *cur, *next; if (!quiet) fprintf(stderr, "\nMausezahn cleans up...\n"); if (fp != NULL) { verbose_l1(" close files (1) ...\n"); fflush(fp); fclose(fp); } if (fp2!=NULL) { if (verbose) fprintf(stderr, " close files (2) ...\n"); (void) fflush(fp2); (void) fclose(fp2); } // interactive mode? if (mz_port) { if (verbose) fprintf(stderr, " clear mops list...\n"); mops_cleanup(mp_head); if (verbose) fprintf(stderr, " clear automops list...\n"); automops_cleanup(amp_head); if (verbose) fprintf(stderr, " clear packet sequences...\n"); mz_ll_delete_list(packet_sequences); } for (i=0; inext; if (cur!=NULL) free(cur); cur=next; } } // close packet sockets if (device_list[i].ps>=0) { close(device_list[i].ps); } } if (verbose) fprintf(stderr, "finished.\n"); exit(sig); } static void help(void) { printf("\nmausezahn %s, a fast versatile traffic generator\n", VERSION_STRING); puts("http://www.netsniff-ng.org\n\n" "Usage: mausezahn [options] [interface] ||\n" "Options:\n" " -x Interactive mode with telnet CLI, default port: 25542\n" " -l Listen address to bind to when in interactive mode, default: 0.0.0.0\n" " -4 IPv4 mode (default)\n" " -6 IPv6 mode\n" " -c Send packet count times, default:1, infinite:0\n" " -d Apply delay between transmissions. The delay value can be\n" " specified in usec (default, no additional unit needed), or in\n" " msec (e.g. 100m or 100msec), or in seconds (e.g. 100s or 100sec)\n" " -r Multiplies the specified delay with a random value\n" " -p Pad the raw frame to specified length (using random bytes)\n" " -a Use specified source mac address, no matter what has\n" " been specified with other arguments; keywords see below,\n" " Default is own interface\n" " -b Same with destination mac address; keywords:\n" " rand Use a random MAC address\n" " bc Use a broadcast MAC address\n" " own Use own interface MAC address (default for source MAC)\n" " stp Use IEEE 802.1d STP multicast address\n" " cisco Use Cisco multicast address as used for CDP, VTP, or PVST+\n" " -A Use specified source IP address (default is own interface IP)\n" " -B Send packet to specified destination IP or domain name\n" " -P Use the specified ASCII payload\n" " -f Read the ASCII payload from a file\n" " -F Read the hexadecimal payload from a file\n" " -Q <[CoS:]vlan> Specify 802.1Q VLAN tag and optional Class of Service, you can\n" " specify multiple 802.1Q VLAN tags (QinQ...) by separating them\n" " via a comma or a period (e.g. '5:10,20,2:30')\n" " -t Specify packet type for autobuild (you don't need to care for\n" " encapsulations in lower layers, most packet types allow/require\n" " additional packet-specific arguments in an ;\n" " Currently supported types: arp, bpdu, cdp, ip, icmp, udp, tcp,\n" " dns, rtp, syslog, lldp and more;\n" " For context-help use 'help' as !\n" " -T Specify packet type for server mode, currently only rtp is supported;\n" " Enter -T help or -T rtp help for further information\n" " -M Insert a MPLS label, enter '-M help' for a syntax description\n" " -V|VV|... Verbose and more verbose mode\n" " -q Quiet mode, even omit 'important' standard short messages\n" " -S Simulation mode: DOES NOT put anything on the wire, this is\n" " typically combined with one of the verbose modes (v or V)\n" " -v Show version\n" " -h Print this help\n\n" "Examples:\n" " mausezahn -x 99\n" " mausezahn -c 0 -d 2s -t bpdu conf\n" " mausezahn -t cdp change -c 0\n" " mausezahn -t syslog sev=3 -P \"You have been mausezahned.\" -A 10.1.1.109 -B 192.168.7.7\n" " mausezahn eth0 -A rand -B 1.1.1.1 -c 0 -t tcp \"dp=1-1023, flags=syn\"\n\n" "Note:\n" " This tool is targeted for network developers! You should\n" " be aware of what you are doing and what these options above\n" " mean! Only use this tool in an isolated LAN that you own!\n\n" "Please report bugs to \n" "Copyright (C) 2008-2010 Herbert Haas ,\n" "Copyright (C) 2011 Daniel Borkmann ,\n" "Swiss federal institute of technology (ETH Zurich)\n" "License: GNU GPL version 2.0\n" "This is free software: you are free to change and redistribute it.\n" "There is NO WARRANTY, to the extent permitted by law.\n"); die(); } static void version(void) { printf("\nmausezahn %s, Git id: %s\n", VERSION_LONG, GITVERSION); puts("a fast versatile traffic generator\n" "http://www.netsniff-ng.org\n\n" "Please report bugs to \n" "Copyright (C) 2008-2010 Herbert Haas ,\n" "Copyright (C) 2011 Daniel Borkmann ,\n" "Swiss federal institute of technology (ETH Zurich)\n" "License: GNU GPL version 2.0\n" "This is free software: you are free to change and redistribute it.\n" "There is NO WARRANTY, to the extent permitted by law.\n"); die(); } int reset(void) { int i; time_t t; // Determine platform type sizes: MZ_SIZE_LONG_INT = sizeof(long int); mz_default_config_path[0] = 0x00; mz_default_log_path[0] = 0x00; // Reset globals: quiet = 0; ipv6_mode = 0; verbose = 0; simulate = 0; filename[0] = '\0'; path[0] = '\0'; gind=0; gind_max = TIME_COUNT; fp = NULL; fp2 = NULL; mz_port = 0; mz_rand = 0; char mz_listen_addr[16] = "0.0.0.0"; mp_head = NULL; for (i=0;i)\n" "\n"); die(); } // Purpose: Properly handle arguments and configure global structs (tx) int getopts (int argc, char *argv[]) { int i, c, rargs, RX=0, count_set=0, delay_set=0; unsigned int time_factor; char *packet_type=NULL, *mops_type=NULL; char *dum; unsigned char *dum1, *dum2; bool do_help = false; libnet_t *l; char err_buf[LIBNET_ERRBUF_SIZE]; struct libnet_ether_addr *mymac; FILE *afp; char hexpld[MAX_PAYLOAD_SIZE*2]; int hexpld_specified=0; long delay; char unit; opterr = 1; // let getopt print error message if necessary while ((c = getopt(argc, argv, short_options)) != -1) switch (c) { case '4': tx.eth_type = 0x0800; ipv6_mode=0; break; case '6': tx.eth_type = 0x86dd; ipv6_mode=1; break; case 'h': help(); break; case 'q': quiet=1; break; case 'v': version(); break; case 'V': verbose++; break; case 'S': simulate=1; break; case 'x': mz_port = MZ_DEFAULT_PORT; break; case 'l': strncpy (mz_listen_addr, optarg, sizeof(mz_listen_addr)); break; case 'a': strncpy (tx.eth_src_txt, optarg, 32); tx.packet_mode = 0; break; case 'A': strncpy (tx.ip_src_txt, optarg, sizeof(tx.ip_src_txt)); break; case 'b': strncpy (tx.eth_dst_txt, optarg, 32); tx.packet_mode = 0; break; case 'B': strncpy (tx.ip_dst_txt, optarg, sizeof(tx.ip_dst_txt)); break; case 'c': errno=0; tx.count = strtol(optarg, (char **)NULL, 10); if ((errno == ERANGE && (tx.count == LONG_MAX || tx.count == LONG_MIN)) || (errno != 0 && tx.count == 0)) { perror("strtol"); return (-1); } if (tx.count<0) tx.count=1; //TODO: Allow count=0 which means infinity (need to update all send_functions) count_set=1; break; case 'd': errno=0; time_factor=0; delay=0; unit='u'; // default is usecs if (sscanf(optarg, "%ld%c", &delay, &unit) == EOF) { perror("sscanf"); return (-1); } if (delay < 0) { fprintf(stderr, " Incorrect delay format\n"); return(-1); } if (unit == 's') time_factor=1000000; // seconds else if (unit == 'm') time_factor=1000; // msecs else if (unit == 'u') time_factor=1; // usecs else { fprintf(stderr, " Incorrect delay format\n"); return(-1); } tx.delay = delay * time_factor; if ((errno == ERANGE && (tx.delay == LONG_MAX || tx.delay == LONG_MIN)) || (errno != 0 && tx.delay == 0)) { perror("strtol"); return (-1); } if (tx.delay<0) tx.delay=0; // no delay delay_set=1; break; case 'p': errno=0; tx.padding = strtol(optarg, (char **)NULL, 10); if ((errno == ERANGE && (tx.padding == LONG_MAX || tx.padding == LONG_MIN)) || (errno != 0 && tx.padding == 0)) { perror("strtol"); return (-1); } if (tx.padding>10000) { fprintf(stderr, " Warning: Padding must not exceed 10000!\n"); return -1; } break; case 't': packet_type = optarg; // analyzed below if (strcmp(packet_type,"help") == 0) print_packet_types(); break; case 'X': mops_type = optarg; // MOPS TRANSITION STRATEGY -- analyzed below break; case 'T': packet_type = optarg; RX = 1; break; case 'r': mz_rand = 1; break; case 'M': if (strncmp(optarg,"help",4)==0) { (void) get_mpls_params("help "); } else { strncpy (tx.mpls_txt, optarg, 128); tx.eth_type = ETHERTYPE_MPLS; tx.packet_mode = 0; tx.mpls=1; } break; case 'P': // ASCII payload strncpy((char*)tx.ascii_payload, optarg, MAX_PAYLOAD_SIZE); tx.ascii = 1; break; case 'f': // ASCII payload in FILE afp = fopen(optarg, "r"); if (!afp) { fprintf(stderr, " mz/getopts: Can not open file %s. %s!\n", optarg, strerror(errno)); return -1; } if (fgets((char*)tx.ascii_payload, MAX_PAYLOAD_SIZE, afp) == NULL) fprintf(stderr, " mz/getopts: File empty?\n"); fclose(afp); tx.ascii = 1; break; case 'F': // HEX payload in FILE afp = fopen(optarg, "r"); if (!afp) { fprintf(stderr, " mz/getopts: Can not open file %s. %s!\n", optarg, strerror(errno)); return -1; } i=0; while ( (hexpld[i]=fgetc(afp))!=EOF ) { if (isspace(hexpld[i])) { hexpld[i]=':'; } i++; } hexpld[i]='\0'; fclose(afp); hexpld_specified=1; break; case 'Q': // VLAN TAG if (strncmp(optarg,"help",4)==0) { print_dot1Q_help(); // ugly but most simple and safe solution } else { strncpy (tx.dot1Q_txt, optarg, 32); tx.dot1Q=1; // determine number of VLAN tags for (i=0; i2) { // number of remaining arguments fprintf(stderr," mz/getopts: Too many arguments!\n"); return -1; } // There can be 0-2 additional arguments switch (rargs) { case 0: if (lookupdev()) { // no device found if (verbose) fprintf(stderr, " mz: no active interfaces found!\n"); strcpy(tx.device, "lo"); } break; case 1: // arg_string OR device given => find out! if (__device_ifindex(argv[optind]) > 0) { strncpy(tx.device, argv[optind], 16); } else { /// arg_string given => no device has been specified -- let's find one! strncpy (tx.arg_string, argv[optind], MAX_PAYLOAD_SIZE); do_help = !!getarg(tx.arg_string,"help", NULL); if (!do_help) { if (lookupdev()) { /* no device found */ if (verbose) fprintf(stderr, " mz: no active interfaces found!\n"); strcpy(tx.device, "lo"); } if (verbose) fprintf(stderr," mz: device not given, will use %s\n",tx.device); } } break; case 2: // both device and arg_string given strncpy (tx.device, argv[optind], 16); strncpy (tx.arg_string, argv[optind+1], MAX_PAYLOAD_SIZE); break; default: fprintf(stderr," mz/getopts: Unknown argument problem!\n"); return 1; } if (hexpld_specified) { strcat(tx.arg_string, ",p="); strcat(tx.arg_string, hexpld); } ////////////////////////////////////////////////////////////////////////// // // Initialize MAC and IP Addresses. // // - tx.eth_src = own interface MAC // - tx.ip_src = own interface IP or user specified // - tx.ip_dst = 255.255.255.255 or user specified (can be a range) // - tx.ip_src_rand ... is set if needed. // // Get own device MAC address: // Don't open context if only a help text is requested if (!do_help && getarg(tx.arg_string,"help", NULL) !=1) { l = libnet_init (LIBNET_LINK_ADV, tx.device, err_buf ); if (l == NULL) { fprintf(stderr, " mz/getopts: libnet_init() failed (%s)", err_buf); return -1; } mymac = libnet_get_hwaddr(l); for (i=0; i<6; i++) { tx.eth_src[i] = mymac->ether_addr_octet[i]; tx.eth_mac_own[i] = mymac->ether_addr_octet[i]; } // Set source IP address: if (strlen(tx.ip_src_txt)) { // option -A has been specified if (mz_strcmp(tx.ip_src_txt, "bcast", 2)==0) { if (ipv6_mode) { fprintf(stderr, "Option -A does not support 'bcast' when in IPv6 mode.\n"); return 1; } tx.ip_src = libnet_name2addr4 (l, "255.255.255.255", LIBNET_DONT_RESOLVE); } else if (strcmp(tx.ip_src_txt, "rand") == 0) { if (ipv6_mode) { fprintf(stderr, "Option -A does not support 'rand' when in IPv6 mode.\n"); return 1; } tx.ip_src_rand = 1; tx.ip_src_h = (u_int32_t) ( ((float) rand()/RAND_MAX)*0xE0000000); //this is 224.0.0.0 } else if ( (ipv6_mode && get_ip6_range_src(tx.ip_src_txt, l)) || // returns 1 when no range has been specified (!ipv6_mode && get_ip_range_src(tx.ip_src_txt)) ) { // name2addr4 accepts a DOTTED DECIMAL ADDRESS or a FQDN: if (ipv6_mode) tx.ip6_src = libnet_name2addr6 (l, tx.ip_src_txt, LIBNET_RESOLVE); else tx.ip_src = libnet_name2addr4 (l, tx.ip_src_txt, LIBNET_RESOLVE); } } else { // no source IP specified: by default use own IP address if (ipv6_mode) { tx.ip6_src = libnet_get_ipaddr6(l); if (strncmp((char*)&tx.ip6_src,(char*)&in6addr_error,sizeof(in6addr_error))==0) printf("Failed to set source IPv6 address: %s", l->err_buf); } else tx.ip_src = libnet_get_ipaddr4(l); } // Set destination IP address: if (strlen(tx.ip_dst_txt)) { // option -B has been specified if (mz_strcmp(tx.ip_dst_txt, "rand", 2)==0) { fprintf(stderr, "Option -B does not support random destination IP addresses currently.\n"); return 1; } if (mz_strcmp(tx.ip_dst_txt, "bcast", 2)==0) { if (ipv6_mode) { fprintf(stderr, "Option -B does not support 'bcast' when in IPv6 mode.\n"); return 1; } tx.ip_dst = libnet_name2addr4 (l, "255.255.255.255", LIBNET_DONT_RESOLVE); } else if ( (ipv6_mode && get_ip6_range_dst(tx.ip_dst_txt, l)) || // returns 1 when no range has been specified (!ipv6_mode && get_ip_range_dst(tx.ip_dst_txt))) { // name2addr4 accepts a DOTTED DECIMAL ADDRESS or a FQDN: if (ipv6_mode) tx.ip6_dst = libnet_name2addr6 (l, tx.ip_dst_txt, LIBNET_RESOLVE); else tx.ip_dst = libnet_name2addr4 (l, tx.ip_dst_txt, LIBNET_RESOLVE); } } else { // no destination IP specified: by default use broadcast if (ipv6_mode) { tx.ip6_dst = libnet_name2addr6 (l, "ff02::1", LIBNET_DONT_RESOLVE); } else { tx.ip_dst = libnet_name2addr4 (l, "255.255.255.255", LIBNET_DONT_RESOLVE); } } // Initialize tx.ip_src_h and tx.ip_dst_h which are used by 'print_frame_details()' // in verbose mode. See 'modifications.c'. if (tx.ip_src_rand) { // ip_src_h already given, convert to ip_src dum1 = (unsigned char*) &tx.ip_src_h; dum2 = (unsigned char*) &tx.ip_src; } else { // ip_src already given, convert to ip_src_h if (ipv6_mode) { if (tx.ip_src_isrange) { tx.ip6_src = tx.ip6_src_start; } } else { dum1 = (unsigned char*) &tx.ip_src; dum2 = (unsigned char*) &tx.ip_src_h; } } if (ipv6_mode) { if (tx.ip_dst_isrange) { tx.ip6_dst = tx.ip6_dst_start; } } else { *dum2 = *(dum1+3); dum2++; *dum2 = *(dum1+2); dum2++; *dum2 = *(dum1+1); dum2++; *dum2 = *dum1; dum1 = (unsigned char*) &tx.ip_dst; dum2 = (unsigned char*) &tx.ip_dst_h; *dum2 = *(dum1+3); dum2++; *dum2 = *(dum1+2); dum2++; *dum2 = *(dum1+1); dum2++; *dum2 = *dum1; } libnet_destroy(l); } // // END OF ADDRESS INITIALIZATION // ////////////////////////////////////////////////////////////////////////// ////// retrieve interface parameters /////// for (i=0; i special packet types, stateless // // If -t not present then evaluate arg_string which must // contain a byte-string in hexadecimal notation. // // // ***** NEW: MOPS TRANSITION STRATEGY ***** if (mops_type != NULL) { if (mz_strcmp(mops_type,"lldp",4)==0) { mops_direct(tx.device, MOPS_LLDP, tx.arg_string); } } if (packet_type == NULL) { // raw hex string given mode = BYTE_STREAM; } else if (strcmp(packet_type,"arp")==0) { mode = ARP; } else if (strcmp(packet_type,"bpdu")==0) { mode = BPDU; } else if (strcmp(packet_type,"ip")==0) { mode = IP; } else if (strcmp(packet_type,"udp")==0) { mode = UDP; } else if (strcmp(packet_type,"icmp")==0) { mode = ICMP; } else if (strcmp(packet_type,"icmp6")==0) { mode = ICMP6; } else if (strcmp(packet_type,"tcp")==0) { mode = TCP; } else if (strcmp(packet_type,"dns")==0) { mode = DNS; } else if (strcmp(packet_type,"cdp")==0) { mode = CDP; } else if (strcmp(packet_type,"syslog")==0) { mode = SYSLOG; } else if (strcmp(packet_type, "igmp") == 0) { mode = IGMP; } else if (strcmp(packet_type,"lldp")==0) { mode = LLDP; tx.packet_mode=0; // create whole frame by ourself } else if (strcmp(packet_type,"rtp")==0) { if (RX) { mode = RX_RTP; } else { mode = RTP; if (!count_set) tx.count = 0; if (!delay_set) tx.delay = 20000; // 20 msec inter-packet delay for RTP } } else { fprintf(stderr, " mz: you must specify a valid packet type!\n"); } ////////////////////////////////////////////////////////////////////////// // TODO: Implement macro support // Check macro types here return 0; } int main(int argc, char **argv) { // These handles are only used when creating L3 and above packets. libnet_t *l; // the context libnet_ptag_t t2=0, t3=0, t4=0; // handles to layers double cpu_time_used; reset(); if ( getopts(argc, argv) ) { (void) fprintf(stderr, " Invalid command line parameters!\n"); help(); } // Check whether hires timers are supported or not: (void) check_timer(); signal(SIGINT, signal_handler); // to close all file pointers etc upon SIGINT switch (mode) { case BYTE_STREAM: send_eth(); break; case ARP: (void) send_arp(); break; case BPDU: (void) send_bpdu(); break; case CDP: (void) send_cdp(); break; case IP: // From now on a new much more modular method is used: l = get_link_context(); t3 = create_ip_packet(l); // t3 can be used for later header changes if (!quiet) complexity(); if (tx.packet_mode==0) // Ethernet manipulation features does NOT use ARP to determine eth_dst t2 = create_eth_frame(l, t3, t4); // t2 can be used for later header changes else send_frame (l, t3, t4); // NOTE: send_frame also destroys context finaly break; case ICMP: tx.ip_proto = 1; l = get_link_context(); t4 = create_icmp_packet(l); // t4 can be used for later header changes t3 = create_ip_packet(l); // t3 can be used for later header changes if (!quiet) complexity(); if (tx.packet_mode==0) // Ethernet manipulation features does NOT use ARP to determine eth_dst t2 = create_eth_frame(l, t3, t4); // t2 can be used for later header changes else send_frame (l, t3, t4); // NOTE: send_frame also destroys context finaly break; case ICMP6: tx.ip_proto = 58; l = get_link_context(); t4 = create_icmp6_packet(l); // t4 can be used for later header changes t3 = create_ip_packet(l); // t3 can be used for later header changes if (!quiet) complexity(); if (tx.packet_mode==0) // Ethernet manipulation features does NOT use ARP to determine eth_dst t2 = create_eth_frame(l, t3, t4); // t2 can be used for later header changes else send_frame (l, t3, t4); // NOTE: send_frame also destroys context finaly break; case UDP: tx.ip_proto = 17; l = get_link_context(); t4 = create_udp_packet(l); // t4 can be used for later header changes t3 = create_ip_packet(l); // t3 can be used for later header changes if (!quiet) complexity(); if (tx.packet_mode==0) // Ethernet manipulation features does NOT use ARP to determine eth_dst t2 = create_eth_frame(l, t3, t4); // t2 can be used for later header changes else send_frame (l, t3, t4); // NOTE: send_frame also destroys context finaly break; case TCP: tx.ip_proto = 6; l = get_link_context(); t4 = create_tcp_packet(l); // t4 can be used for later header changes t3 = create_ip_packet(l); // t3 can be used for later header changes if (!quiet) complexity(); if (tx.packet_mode==0) // Ethernet manipulation features does NOT use ARP to determine eth_dst t2 = create_eth_frame(l, t3, t4); // t2 can be used for later header changes else send_frame (l, t3, t4); // NOTE: send_frame also destroys context finaly break; case IGMP: tx.ip_proto = 2; l = get_link_context(); t4 = create_igmp_packet(l); /* t3 can be used for later header changes */ t3 = create_ip_packet(l); if (!quiet) complexity(); /* Ethernet manipulation features does NOT use ARP to determine eth_dst * */ if (tx.packet_mode == 0) t2 = create_eth_frame(l, t3, t4); // t2 can be used for later header changes else send_frame(l, t3, t4); // NOTE: send_frame also destroys context finaly break; case DNS: tx.ip_proto = 17; l = get_link_context(); (void) create_dns_packet(); t4 = create_udp_packet(l); // t4 can be used for later header changes t3 = create_ip_packet(l); // t3 can be used for later header changes if (!quiet) complexity(); if (tx.packet_mode==0) // Ethernet manipulation features does NOT use ARP to determine eth_dst t2 = create_eth_frame(l, t3, t4); // t2 can be used for later header changes else send_frame (l, t3, t4); // NOTE: send_frame also destroys context finaly break; case RTP: tx.ip_proto = 17; l = get_link_context(); if (!quiet) fprintf(stderr, " mz: RTP mode! (count=%u, delay=%u usec)\n\n", tx.count, tx.delay); (void) create_rtp_packet(); t4 = create_udp_packet(l); // t4 can be used for later header changes t3 = create_ip_packet(l); // t3 can be used for later header changes if (!quiet) complexity(); if (tx.packet_mode==0) // Ethernet manipulation features does NOT use ARP to determine eth_dst t2 = create_eth_frame(l, t3, t4); // t2 can be used for later header changes else send_frame (l, t3, t4); // NOTE: send_frame also destroys context finaly break; case RX_RTP: // Receive RTP packets rcv_rtp_init(); rcv_rtp(); break; case SYSLOG: tx.ip_proto = 17; l = get_link_context(); (void) create_syslog_packet(); t4 = create_udp_packet(l); // t4 can be used for later header changes t3 = create_ip_packet(l); // t3 can be used for later header changes if (!quiet) complexity(); if (tx.packet_mode==0) // Ethernet manipulation features does NOT use ARP to determine eth_dst t2 = create_eth_frame(l, t3, t4); // t2 can be used for later header changes else send_frame (l, t3, t4); // NOTE: send_frame also destroys context finaly break; case LLDP: // start with a new concept here //l = get_link_context(); //(void) create_lldp_packet(); // // // printf("SIZE=%lu\n",sizeof(struct tx_struct)); fprintf(stderr, "LLDP is currently only supported via the interactive mode\n"); exit(1); break; default: (void) fprintf(stderr," mz/main: unknown mode! Stop.\n"); return (1); } if (!quiet) { mz_stop = clock(); cpu_time_used = ((double) (mz_stop - mz_start)) / CLOCKS_PER_SEC; if (cpu_time_used > 0) { total_d /= cpu_time_used; fprintf(stderr, "%.2f seconds (%.Lf packets per second)\n",cpu_time_used,total_d); } else { fprintf(stderr, "\n"); } } return(0); }