From d0009856814c13d13770db5aadd7b2fabf947776 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Mon, 13 May 2013 13:53:27 +0200 Subject: staging: add mausezahn staging directory After some back and forth, we decided that it is easier to maintain mausezahn in a staging directory until it is fully reworked and cleaned up to be ready to be fully integrated. This way, it is better than having it in a separate branch, and we can also accept patches from outside more easily. Also, while at it, fix up some function mismatches with libcli. Signed-off-by: Daniel Borkmann Signed-off-by: Tobias Klauser --- staging/layer2.c | 902 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 902 insertions(+) create mode 100644 staging/layer2.c (limited to 'staging/layer2.c') diff --git a/staging/layer2.c b/staging/layer2.c new file mode 100644 index 0000000..ebbc7d8 --- /dev/null +++ b/staging/layer2.c @@ -0,0 +1,902 @@ +/* + * Mausezahn - A fast versatile traffic generator + * Copyright (C) 2008-2010 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 functions to send various L2-based PDUs such as +// * ARP +// * BPDU +// *************************************************************************** + +#include "mz.h" +#include "cli.h" + + + +#define MZ_ARP_HELP \ + "| ARP type: Send arbitrary ARP packets.\n" \ + "| Note:\n" \ + "| - The Ethernet dst and src MAC addresses can be specified but can be also 'rand'.\n" \ + "| - If dst and src are NOT specified then practical defaults are used (src=own MAC, dst=bc).\n" \ + "|\n" \ + "| ARGUMENT SYNTAX: []\n" \ + "| | |\n" \ + "| help, request, reply --+ |\n" \ + "| +-- sendermac, senderip, targetmac, targetip\n" \ + "| smac sip tmac tip\n" \ + "|\n" \ + "| EXAMPLES:\n" \ + "| 1. Legitimate ARP response to broadcast:\n" \ + "| # mz eth0 -t arp \"reply\"\n" \ + "| 2. ARP cache poisoning, claiming to be 192.168.0.1, telling a target PC:\n" \ + "| # mz eth0 -t arp \"reply, senderip=192.168.0.1, targetmac=00:00:0c:01:02:03, targetip=172.16.1.50\"\n" \ + "\n" + + +#define MZ_BPDU_HELP \ + "| BPDU type: Send arbitrary BPDU packets (spanning tree).\n" \ + "|\n" \ + "| ARGUMENT SYNTAX: []\n" \ + "| | \n" \ + "| conf, tcn --+ \n" \ + "| \n" \ + "| Parameters:\n" \ + "|\n" \ + "| id = 0-65535 ..... default: 0, identifies 'Spanning Tree Protocol'\n" \ + "| version = 0-255 ..... default: 0\n" \ + "| type = 0-255 ..... BPDU Type: 0=CONF, 1=TCN (default: CONF)\n" \ + "| flags = 0-255 ..... 1=TC, 128=ACK (default: 0 = No TC, No ACK)\n" \ + "| rootid = : ..... 8 byte Root-ID (default: 00:00:)\n" \ + "| rootpc = 0-4294967295 ..... root path cost (default: 0)\n" \ + "| bid = ..... 6 byte MAC address (default: own-mac)\n" \ + "| pid = 0-65535 ..... port identifier (default: 0)\n" \ + "| age = 0-65535 ..... message age (default: 0)\n" \ + "| maxage = 0-65535 ..... max age (default: 20)\n" \ + "| hello = 0-65535 ..... hello time (default: 2)\n" \ + "| fwd = 0-65535 ..... forward delay (default: 15)\n" \ + "| tag - ..... Keyword to enforce 802.1Q VLAN tag; use this\n" \ + "| together with the 'vlan' parameter below.\n" \ + "|\n" \ + "| PVST+ extensions:\n" \ + "|\n" \ + "| vlan ..... VLAN number (default: 0)\n" \ + "| pri ..... 802.1P-Priority (0-7, default: 0)\n" \ + "| notag ..... Omit 802.1Q VLAN tag\n" \ + "| \n" \ + "|\n" \ + "| DEFAULTS: mz sends standard IEEE 802.1d (CST) BPDUs and assumes that your computer\n" \ + "| wants to become the root bridge (rid=bid). Configuration BPDUs are the default but\n" \ + "| can be changed using the 'tcn' keyword. Optionally the 802.3 source and destination\n" \ + "| MAC addresses can be specified using the -a and -b options. Per default, the correct\n" \ + "| STP or PVST+ destination addresses are used (same as '-b stp' or '-b pvst', \n" \ + "| respectively).\n" \ + "| \n" \ + "| Note that the parameter 'vlan' only selects the PVST+ mode if the parameter 'tag' is\n" \ + "| NOT used.\n" \ + "\n" + + + +// Send arbitrary ARP packets. +// Note: +// - The Ethernet dst and src MAC addresses can be specified, +// the eth_src_txt can be 'rand' +// - If eth_dst and eth_src are NOT specified then practical defaults are used +// +// arg_string syntax: , , ... , +// - commands: 'request' OR 'reply' +// - params: 'sendermac', 'senderip', 'targetmac', 'targetip' +// +// Example arg_string for ARP cache poisoning: +// "reply, senderip=192.168.0.1, targetmac=00:00:0c:01:02:03, targetip=172.16.1.50" +// where sendermac will be automatically replaced by own mac, +// senderip is the spoofed IP, +// targetmac and targetip identifies the receiver. +// +int send_arp () +{ + libnet_t *l; + libnet_ptag_t t; + + char + argval[64], + t1[64], + t2[64], + src, + dst, + errbuf[LIBNET_ERRBUF_SIZE]; + + int + i, + arpmode=0, + arpop=0, + loop, + tm=0; + + u_int8_t + *packet, + sendermac[6], + targetmac[6]; + + + + u_int32_t + packet_s, + senderip=0, + targetip=0; + + + if (tx.dot1Q) + { + fprintf(stderr," Note: ARP mode does not support 802.1Q builder.\n"); + exit(1); + } + + if (tx.mpls) + { + fprintf(stderr," Note: ARP mode does not support MPLS builder.\n"); + exit(1); + } + + if (getarg(tx.arg_string,"help", NULL)==1) + { + if (mz_port) + { + cli_print(gcli, "%s", MZ_ARP_HELP); + return -1; + } + else + { + fprintf(stderr,"\n" + MAUSEZAHN_VERSION + "\n%s", MZ_ARP_HELP); + exit(0); + } + } + + + // Set the flags to shorten subsequent decisions: + src = strlen(tx.eth_src_txt); + dst = strlen(tx.eth_dst_txt); + + l = libnet_init(LIBNET_LINK_ADV, tx.device, errbuf); + + if (l == NULL) + { + fprintf(stderr, "%s", errbuf); + exit(EXIT_FAILURE); + } + + + + if (getarg(tx.arg_string,"request", NULL)==1) + { + arpmode=1; + arpop = ARPOP_REQUEST; + } + else + if (getarg(tx.arg_string, "reply", NULL)==1) + { + arpmode=2; + arpop = ARPOP_REPLY; + } + else + { // Default: + arpmode=2; + arpop = ARPOP_REPLY; + } + + + + if ( (getarg(tx.arg_string,"sendermac", argval)==1) || (getarg(tx.arg_string,"smac", argval)==1) ) + { + //TODO: Allow 'rand' as sendermac + str2hex(argval,sendermac,6); + } + else + { + // sendermac is usually ALWAYS own MAC: + getbytes(tx.eth_src, sendermac,1,6); + } + + + if ( (getarg(tx.arg_string,"targetmac", argval)==1) || (getarg(tx.arg_string,"tmac", argval)==1) ) + { + str2hex(argval,targetmac,6); + tm=1; + } + else + { + // targetmac is either zero (request) or bcast (reply=>gratitious ARP) + if (arpmode==1) //request + str2hex("00:00:00:00:00:00",targetmac, 6); + else //reply + str2hex("ff:ff:ff:ff:ff:ff",targetmac, 6); + } + + + if ( (getarg(tx.arg_string,"senderip", argval)==1) || (getarg(tx.arg_string,"sip", argval)==1) ) + { + senderip = str2ip32_rev(argval); + } + else + { + // senderip is usually ALWAYS the own IP + senderip = libnet_get_ipaddr4(l); // TODO - use tx.ip_src + } + + + + if ( (getarg(tx.arg_string,"targetip", argval)==1) || (getarg(tx.arg_string,"tip", argval)==1) ) + { + targetip = str2ip32_rev(argval); + } + else + { + // if targetip is missing also use own IP because it may be used for duplicate IP detection + targetip = libnet_get_ipaddr4(l); + } + + + + // NOTE: Now all ARP parameters are set (possibly defaults used!) + + bs2str(sendermac,t1,6); + bs2str(targetmac,t2,6); + //Check: + //printf("-- sendermac=%s targetmac=%s senderip=%u targetip=%u\n",t1,t2,senderip,targetip); + + + + // Build the ARP header + + t = libnet_autobuild_arp(arpop, /* operation type */ + sendermac, /* sender hardware addr */ + (u_int8_t *)&senderip, /* sender protocol addr */ + targetmac, /* target hardware addr */ + (u_int8_t *)&targetip, /* target protocol addr */ + l); /* libnet context */ + + if (t == -1) + { + fprintf(stderr, " mz/send_arp: Can't build ARP header: %s\n", libnet_geterror(l)); + exit(EXIT_FAILURE); + } + + + // Finally build the Ethernet header + + if ((!dst) && (!src)) // ... user does not care about addresses (both eth_dst and eth_src NOT specified) + { + if (arpmode==1) + str2hex("ff:ff:ff:ff:ff:ff", tx.eth_dst, 6); + else + getbytes(targetmac, tx.eth_dst, 1, 6); // either also bcast or specific MAC + + t = libnet_autobuild_ethernet(tx.eth_dst, /* ethernet destination */ + ETHERTYPE_ARP, /* protocol type */ + l); /* libnet handle */ + + if (t == -1) + { + fprintf(stderr, " mz/send_arp: Can't build ethernet header: %s\n", + libnet_geterror(l)); + exit(EXIT_FAILURE); + } + } + else // EITHER eth_dst OR eth_src OR BOTH specified: + { + if (!dst) + { + if (arpmode==1) + str2hex("ff:ff:ff:ff:ff:ff", tx.eth_dst, 6); + else + getbytes(targetmac, tx.eth_dst, 1, 6); // either also bcast when reply or specific MAC + } + else // eth_dst specified + { + if (check_eth_mac_txt(ETH_DST)) // if true then problem! + { + str2hex("ff:ff:ff:ff:ff:ff",tx.eth_dst, 6); // the default + } + } + + + if (!src) + { + // tx.eth_src contains own MAC by default! + } + else // use specified source MAC address + { + if (check_eth_mac_txt(ETH_SRC)) // if true then problem! + { + str2hex("ff:ff:ff:ff:ff:ff",tx.eth_src, 6); // the default + } + } + + t = libnet_build_ethernet (tx.eth_dst, tx.eth_src, ETHERTYPE_ARP, NULL, 0, l, 0); // Note: payload=NULL, payload_s=0 + } + + if (libnet_adv_cull_packet(l, &packet, &packet_s) == -1) + { + fprintf(stderr, "%s", libnet_geterror(l)); + } + else + { + libnet_adv_free_packet(l, packet); + } + + // this is for the statistics: + mz_start = clock(); + total_d = tx.count; + + + again: + + if (tx.count==0) + loop=1000000; + else + loop=tx.count; + + for (i=1; i<=loop; i++) + { + + if (!simulate) libnet_write(l); + + if (verbose) + { + fprintf(stderr," sent ARP: %s smac=%s sip=%s tmac=%s tip=%s\n", + (arpmode==1) ? "request" : "reply", + t1, + libnet_addr2name4(senderip,LIBNET_DONT_RESOLVE), + t2, + libnet_addr2name4(targetip,LIBNET_DONT_RESOLVE)); + } + + + if (tx.delay) SLEEP (tx.delay); + } + + if (tx.count==0) + { + goto again; + } + + + libnet_destroy(l); + + return 0; +} + + + + + + + + + + + + + + + +/////////////////////////////////////////////////////////////////////////////////////// +// Send arbitrary BPDU frames. +// +// commands: +// conf|tcn ...when specifying everything yourself +// +// params: +// id, version, type, flags, rootid, rootpc, bid, pid, age, maxage, hello, fwd, +// vlan +// +// defaults: +// mz assumes you want to become root bridge! (rid=bid) +// +int send_bpdu () +{ + + // BPDU parameters: + u_int16_t + id=0; + u_int8_t + version=0, + bpdu_type=0, // 0=conf, 1=topology change (actually in big endian!) + flags=0, // 1=TC, 128=TCAck + root_id[8], // Root BID + bridge_id[8]; // Own BID + u_int32_t + root_pc=0; // Root Path Cost + u_int16_t + port_id=0, // Port Identifier + message_age=0, // All timers are multiples of 1/256 sec. Thus times range from 0 to 256 seconds. + max_age=20, + hello_time=2, // + f_delay=15; + + // LLC Parameters: + u_int8_t + dsap=0x42, + ssap=0x42, + control=0x3; + + // Optional payload (needed for PVST+) + u_int8_t + bpdu_payload[64], + snap_oui[3]; + u_int32_t + bpdu_payload_s=0; + u_int16_t + vlan=0; + u_int8_t + priority=0x00, + *x; + int + tag=0; + + + // Standard libnet variables: + libnet_t *l; + libnet_ptag_t t; + char errbuf[LIBNET_ERRBUF_SIZE]; + + // Other variables: + unsigned int i, loop; + int bpdumode=0; + char argval[64]; + char dum1[32], dum2[32]; + + + if (tx.dot1Q) + { + fprintf(stderr," Note: BPDU mode does not support 802.1Q builder.\n"); + exit(1); + } + + if (tx.mpls) + { + fprintf(stderr," Note: BPDU mode does not support MPLS builder.\n"); + exit(1); + } + + + // HELP TEXT + if (getarg(tx.arg_string,"help", NULL)==1) + { + if (mz_port) + { + cli_print(gcli, "%s", MZ_BPDU_HELP); + return -1; + } + else + { + fprintf(stderr,"\n" + MAUSEZAHN_VERSION + "\n%s", MZ_BPDU_HELP); + exit(0); + } + } + + ///////////////////////////////////////////////////////// + // Default Destination Address + if (check_eth_mac_txt(ETH_DST)) // if true then problem! + { + str2hex("01:80:C2:00:00:00",tx.eth_dst, 6); // if '1' then user did not set MAC address (or problem occurred) + } + + // Default Bridge-ID + bridge_id[0]=0x00; + bridge_id[1]=0x00; + for (i=0; i<6; i++) bridge_id[2+i]=tx.eth_src[i]; + for (i=0; i<8; i++) root_id[i]=bridge_id[i]; + ///////////////////////////////////////////////////////// + + + + + // determine BPDU type: + if (getarg(tx.arg_string,"conf", NULL)==1) + { + bpdumode=1; + tx.eth_len = LIBNET_802_2_H + LIBNET_STP_CONF_H; + } + else + if (getarg(tx.arg_string, "tcn", NULL)==1) + { + bpdumode=2; + tx.eth_len = LIBNET_802_2_H + LIBNET_STP_TCN_H; + bpdu_type=0x80; + } + else // default + { + bpdumode=1; + tx.eth_len = LIBNET_802_2_H + LIBNET_STP_CONF_H; + } + + +// Commands summary: +// id, version, type, flags, rid, rootpc, bid, pid, age, maxage, hello, fwd + + if (getarg(tx.arg_string,"id", argval)==1) + { + id = (u_int16_t) str2int(argval); + } + + if (getarg(tx.arg_string,"version", argval)==1) + { + version = (u_int8_t) str2int(argval); + } + + if (getarg(tx.arg_string,"bpdu_type", argval)==1) + { + bpdu_type = (u_int8_t) str2int(argval); + } + + if (getarg(tx.arg_string,"flags", argval)==1) + { + flags = (u_int8_t) str2int(argval); + } + + if (getarg(tx.arg_string,"rid", argval)==1) + { + if (str2hex(argval,root_id, 8)!=8) + { + fprintf(stderr," mz/send_bpdu: [ERROR] The root-id must be exactly 8 bytes!\n"); + exit (-1); + } + } + + if (getarg(tx.arg_string,"rootpc", argval)==1) + { + root_pc = (u_int32_t) str2int(argval); + } + + if (getarg(tx.arg_string,"bid", argval)==1) + { + if (str2hex(argval,bridge_id, 6)!=6) + { + fprintf(stderr," mz/send_bpdu: [ERROR] The bridge-id must be exactly 6 bytes!\n"); + exit (-1); + } + } + + if (getarg(tx.arg_string,"pid", argval)==1) + { + port_id = (u_int16_t) str2int(argval); + } + + if (getarg(tx.arg_string,"age", argval)==1) + { + message_age = (u_int16_t) str2int(argval); + } + + if (getarg(tx.arg_string,"maxage", argval)==1) + { + max_age = (u_int16_t) str2int(argval); + } + + if (getarg(tx.arg_string,"hello", argval)==1) + { + hello_time = (u_int16_t) str2int(argval); + } + + if (getarg(tx.arg_string,"fwd", argval)==1) + { + f_delay = (u_int16_t) str2int(argval); + } + + + + if (getarg(tx.arg_string,"vlan", argval)==1) + { + // PVST+ uses TLVs of type=0x00, len=0x02, and Value=0xVV which is the VLAN ID + // The DA must be 0100.0ccc.cccd instead of the standard 0180.c200.0000 + // + if (check_eth_mac_txt(ETH_DST)) // if '1' then user did not set MAC address (or problem occurred) + { + str2hex("01:00:0C:CC:CC:CD",tx.eth_dst, 6); // Cisco PVST+ address + } + +/* // OLD TLV, maybe wrong, maybe obsolete, I don't know. + + bpdu_payload[0] = 0x34; + bpdu_payload[1] = 0x00; + bpdu_payload[2] = 0x02; + vlan = (u_int16_t) str2int(argval); + + x = (u_int8_t*) &vlan; + bpdu_payload[3] = *(x+1); + bpdu_payload[4] = *(x); + bpdu_payload[5] = 0x00; + bpdu_payload[6] = 0x00; + bpdu_payload_s = 7; +*/ + // Updated PVST+ TLV: + bpdu_payload[0] = 0x00; + bpdu_payload[1] = 0x00; + bpdu_payload[2] = 0x00; + bpdu_payload[3] = 0x00; + bpdu_payload[4] = 0x02; + vlan = (u_int16_t) str2int(argval); + x = (u_int8_t*) &vlan; + bpdu_payload[5] = *(x+1); + bpdu_payload[6] = *(x); + bpdu_payload_s = 7; + + tag=1; // set the default: Use 802.1Q tag !!! + } + else // even a normal BPDU must be padded to 60 bytes (total) + { + bpdu_payload[0] = 0x00; + bpdu_payload[1] = 0x00; + bpdu_payload[2] = 0x00; + bpdu_payload[3] = 0x00; + bpdu_payload[4] = 0x00; + bpdu_payload[5] = 0x00; + bpdu_payload[6] = 0x00; + bpdu_payload[7] = 0x00; + bpdu_payload_s = 8; + + tag=0; // set the default: send untagged !!! + } + + + // Note: The order is important because above the defaults for 'tag' has been set. + // + if (getarg(tx.arg_string,"notag", NULL)==1) + { + tag=0; + } + + + // Send normal BPDU with VLAN tag + if (getarg(tx.arg_string,"tag", NULL)==1) + { + tag=2; + bpdu_payload[0] = 0x00; + bpdu_payload[1] = 0x00; + bpdu_payload[2] = 0x00; + bpdu_payload[3] = 0x00; + bpdu_payload[4] = 0x00; + bpdu_payload[5] = 0x00; + bpdu_payload[6] = 0x00; + bpdu_payload[7] = 0x00; + bpdu_payload_s = 8; + + // Rewrite to standard 0180.c200.0000 + // + if (check_eth_mac_txt(ETH_DST)) // if '1' then user did not set MAC address (or problem occurred) + { + str2hex("01:80:C2:00:00:00",tx.eth_dst, 6); + } + vlan = (u_int16_t) str2int(argval); + } + + + if (getarg(tx.arg_string,"pri", argval)==1) + { + priority = (u_int8_t) str2int(argval); + if (priority>7) + { + fprintf(stderr, " mz/send_bpdu: Priority must be between 0 and 7.\n"); + exit(1); + } + + if (tag==0) + { + fprintf(stderr, " mz/send_bpdu: Priority cannot be used together with the 'notag' keyword.\n"); + exit(1); + } + } + + + // Open the link - get libnet handle + l = libnet_init(LIBNET_LINK_ADV, tx.device, errbuf); + + if (l == NULL) + { + fprintf(stderr, "%s", errbuf); + exit(EXIT_FAILURE); + } + + + if (bpdumode==1) // Prepare CONFIGURATION BPDU: + { + + t = libnet_build_stp_conf (id, + version, + bpdu_type, + flags, + root_id, + root_pc, + bridge_id, + port_id, + message_age, + max_age, + hello_time, + f_delay, + (bpdu_payload_s) ? bpdu_payload : NULL, + bpdu_payload_s, + l, + 0); + + if (t == -1) + { + fprintf(stderr, " mz/send_bpdu: Can't build BPDU header: %s\n", + libnet_geterror(l)); + exit(EXIT_FAILURE); + } + } + else // Topology Change BPDU + { + t = libnet_build_stp_tcn(id, + version, + bpdu_type, + (bpdu_payload_s) ? bpdu_payload : NULL, + bpdu_payload_s, + l, + 0); + if (t == -1) + { + + fprintf(stderr, " mz/send_bpdu: Can't build BPDU header: %s\n", + libnet_geterror(l)); + exit(EXIT_FAILURE); + } + } + + + + if ( (vlan==0) || (tag==2) ) // normal BPDU + { + // normal LLC without SNAP + t = libnet_build_802_2 (dsap, + ssap, + control, + NULL, + 0, + l, + 0); + + if (t == -1) + { + fprintf(stderr, " mz/send_bpdu: Can't build LLC header: %s\n", + libnet_geterror(l)); + exit(EXIT_FAILURE); + } + } + else // PVST+ => LLC with SNAP + { + snap_oui[0]=0x00; + snap_oui[1]=0x00; + snap_oui[2]=0x0c; + + // requires a SNAP header with oui=0x00000c and type=0x010b + t = libnet_build_802_2snap(0xAA, + 0xAA, + 0x03, + snap_oui, + 0x010b, + NULL, + 0, + l, + 0); + + if (t == -1) + { + fprintf(stderr, " mz/send_bpdu: Can't build SNAP header: %s\n", + libnet_geterror(l)); + exit(EXIT_FAILURE); + } + } + + + if (tag==0) + { + // Normal 802.3 header without VLAN tag + t = libnet_build_802_3 (tx.eth_dst, + tx.eth_src, + (vlan) ? 0x36 : tx.eth_len, // NOTE the LENGTH field => 802.3 header! + NULL, + 0, + l, + 0); + + } + else // PVST+ => 802.3 with 802.1Q + { + t = libnet_build_802_1q(tx.eth_dst, + tx.eth_src, + 0x8100, + priority, + 0x00, // CFI + vlan, + 0x32, //tx.eth_len, + NULL, + 0, + l, + 0); + } + + + if (t == -1) + { + fprintf(stderr, " mz/send_bpdu: Can't build 802.3 header: %s\n", + libnet_geterror(l)); + exit(EXIT_FAILURE); + } + + + // This is ugly but it works good ;-) + if (tx.count==0) + loop=1000000; + else + loop=tx.count; + + // this is for the statistics: + mz_start = clock(); + total_d = tx.count; + + + again: + + for (i=1; i<=loop; i++) + { + if (!simulate) libnet_write(l); + + if (verbose) + { + bs2str(root_id,dum1,8); + bs2str(bridge_id,dum2,8); + fprintf(stderr," sent BPDU: "); + fprintf(stderr,"%s ", (bpdumode==1) ? "conf" : "tcn "); + fprintf(stderr," id=%u ver=%u flags=%x rid=%s bid=%s\n" + " rpc=%u pid=%u age=%u maxage=%u hello=%u fwd_delay=%u\n", + id, + version, + flags, + dum1, + dum2, + root_pc, + port_id, + message_age, + max_age, + hello_time, + f_delay); + + fprintf(stderr,"\n"); + } + + + if (tx.delay) SLEEP (tx.delay); + } + + if (tx.count==0) + { + goto again; + } + + + libnet_destroy(l); + + return 0; +} + -- cgit v1.2.3-54-g00ecf