/* * Copyright (c) 2004-2005 Endace Technology Ltd, Hamilton, New Zealand. * All rights reserved. * * This source code is proprietary to Endace Technology Limited and no part * of it may be redistributed, published or disclosed except as outlined in * the written contract supplied with this product. * * $Id: dagtuntap.c 13924 2011-02-10 01:51:27Z sfd $ */ /*****************************************************************************/ /* Includes */ /*****************************************************************************/ /* Endace headers. */ #include "dag_config_api.h" #include "dagapi.h" #include "dagutil.h" #include "dagclarg.h" /* CVS Header. */ static const char* const kCvsHeader __attribute__ ((unused)) = "$Id: dagtuntap.c 13924 2011-02-10 01:51:27Z sfd $"; static const char* const kRevisionString = "$Revision: 13924 $"; /*****************************************************************************/ /* Macros and constants */ /*****************************************************************************/ #define DEFAULT_DEVICE "/dev/dag0" #define MAC_BUFSIZE 30 #define MAC_PACKSIZE 7 #define NUM_PORTS 4 #define PORTS_BUFSIZE NUM_PORTS+1 /*****************************************************************************/ /* Data structures */ /*****************************************************************************/ typedef struct { int tun_fd; int configured; char mac[MAC_PACKSIZE]; } port_t; typedef struct { int stream; int txstream; unsigned int tnum; unsigned int mtu; int mac_override:1; int fast:1; int daemon:1; int allports:1; int append_crc:1; int card_ports; port_t ports[NUM_PORTS]; char device[DAGNAME_BUFSIZE]; /* Which DAG device to use */ } conf_t; typedef struct { int dag_fd; int exit_now; } globals_t; /* Commandline argument codes. */ enum { CLA_DEVICE, CLA_HELP, CLA_VERBOSE, CLA_VERSION, CLA_PORT, CLA_TNUM, CLA_MAC, CLA_TXSTREAM, CLA_MTU, CLA_FAST, CLA_DAEMON, CLA_ALLPORTS }; /*****************************************************************************/ /* File-scope variables */ /*****************************************************************************/ static conf_t uConfiguration; /* Configuration options */ static pthread_t uRxThread; static pthread_t uTxThread; static char dagname[DAGNAME_BUFSIZE] = DEFAULT_DEVICE; static globals_t uGlobals; /*****************************************************************************/ /*** Functions ***/ /*****************************************************************************/ static char *packtomac(const char *buf); static void print_version(void) { printf("dagflood (DAG %s) %s\n", kDagReleaseVersion, kRevisionString); } /*****************************************************************************/ static void print_usage(ClArgPtr clarg) { print_version(); printf("dagtuntap - Endace DAG tun/tap network interface daemon.\n"); printf("Usage: dagtuntap [options]\n"); dagclarg_display_usage(clarg, stdout); } /*****************************************************************************/ static void init_options(void) { memset (&uConfiguration, 0, sizeof(uConfiguration)); strncpy(uConfiguration.device,dagname,DAGNAME_BUFSIZE); uConfiguration.txstream = 1; uConfiguration.mtu = 1500; uConfiguration.ports[0].configured = 1; /* default to Port A */ } static void print_configuration(void) { int count; char tempstr[80]; int len = 0; int tnum; dagutil_verbose("Configuration:\n"); dagutil_verbose("Device: %s\n", uConfiguration.device); dagutil_verbose("Receive stream: %d\n", uConfiguration.stream); dagutil_verbose("Transmit stream: %d\n", uConfiguration.txstream); dagutil_verbose("MTU: %d\n", uConfiguration.mtu); dagutil_verbose("Fast Polling: %s\n", uConfiguration.fast?"On":"Off"); dagutil_verbose("Daemon mode: %s\n", uConfiguration.daemon?"On":"Off"); dagutil_verbose("Append CRC: %s\n", uConfiguration.append_crc?"On":"Off"); tnum = uConfiguration.tnum; for (count = 0; count < uConfiguration.card_ports; count++) { len = 0; len += snprintf(tempstr + len, 80 - len, "Port %c: ", count + 'A'); if (uConfiguration.ports[count].configured) { len += snprintf(tempstr + len, 80 - len, "tap%d MAC %s", tnum, packtomac(uConfiguration.ports[count].mac)); tnum++; } else { len += snprintf(tempstr + len, 80 - len, "Not enabled"); } len += snprintf(tempstr + len, 80 - len, "\n"); dagutil_verbose("%s", tempstr); } } /*****************************************************************************/ static char * mactopack(const char *buf) { static char macstr[MAC_PACKSIZE]; unsigned int a,b,c,d,e,f; if(!buf) return NULL; sscanf(buf, "%x:%x:%x:%x:%x:%x", &a, &b, &c, &d, &e, &f); macstr[0] = (unsigned char)(a&0xff); macstr[1] = (unsigned char)(b&0xff); macstr[2] = (unsigned char)(c&0xff); macstr[3] = (unsigned char)(d&0xff); macstr[4] = (unsigned char)(e&0xff); macstr[5] = (unsigned char)(f&0xff); macstr[6] = '\0'; return macstr; } /*****************************************************************************/ static char * packtomac(const char *buf) { static char mac_buf[MAC_BUFSIZE]; if(!buf) return NULL; snprintf(mac_buf, MAC_BUFSIZE, "%02x:%02x:%02x:%02x:%02x:%02x", buf[0]&0xff, buf[1]&0xff, buf[2]&0xff, buf[3]&0xff, buf[4]&0xff, buf[5]&0xff); return mac_buf; } /*****************************************************************************/ int macpackincrement(char *buf) { int count, carry=1; if(!buf) return -1; for(count=5; count>-1; count--) { if (carry) { buf[count]++; if (buf[count] == 0) carry = 1; else carry = 0; } } return 0; } /*****************************************************************************/ int parse_commandline(int argc, char *argv[]) { FILE* errorfile = NULL; ClArgPtr clarg = NULL; int result; int argindex; int code; char port; char ports[PORTS_BUFSIZE]; unsigned int tnum; unsigned int txstream; unsigned int mtu; char mac_buf[MAC_BUFSIZE]; int count; init_options(); /* Set up the command line options. */ clarg = dagclarg_init(argc, (const char* const *) argv); dagclarg_add(clarg, "display help (this page)", "--help", 'h', CLA_HELP); dagclarg_add_long_option(clarg, CLA_HELP, "--usage"); dagclarg_add_short_option(clarg, CLA_HELP, '?'); dagclarg_add(clarg, "display version information", "--version", 'V', CLA_VERSION); dagclarg_add(clarg, "increase verbosity", "--verbose", 'v', CLA_VERBOSE); dagclarg_add_string(clarg, "DAG device to use. Default: dag0.", "--device", 'd', "device", dagname, DAGNAME_BUFSIZE, CLA_DEVICE); dagclarg_add_string(clarg, "Physical ports on Card to use. Default: A. Specify multiple ports as ABCD", "--ports", 'p', "ports", ports, PORTS_BUFSIZE, CLA_PORT); dagclarg_add(clarg, "Use all available physical ports (equivalent to -p ABCD on 4 port card)\n", "--allports", 'c', CLA_ALLPORTS); dagclarg_add_uint(clarg, "Tx stream buffer. Default: 1.", "--txstream", 's', "stream", &txstream, CLA_TXSTREAM); dagclarg_add_uint(clarg, "TUN/TAP device number. Default: 0.", "--tnum", 't', "num", &tnum, CLA_TNUM); dagclarg_add_string(clarg, "Override MAC Addresses, incrementing from Port A", "--mac", 'a', "address", mac_buf, MAC_BUFSIZE, CLA_MAC); dagclarg_add_uint(clarg, "Interface MTU. Default: 1500.", "--mtu", 'm', "MTU", &mtu, CLA_MTU); dagclarg_add(clarg, "Use fast polling. Low latency but high CPU utilisation", "--fastpoll", 'f', CLA_FAST); dagclarg_add(clarg, "Fork into background, run as daemon.", "--daemon", 'b', CLA_DAEMON); /* Parse the command line options. */ result = dagclarg_parse(clarg, errorfile, &argindex, &code); while (1 == result) { switch (code) { case CLA_DEVICE: if (-1 == dag_parse_name(dagname, uConfiguration.device, DAGNAME_BUFSIZE, &uConfiguration.stream)) { dagutil_error("dag_parse_name(%s): %s\n", dagname, strerror(errno)); return EXIT_FAILURE; } dagutil_verbose_level(2, "device=%s:%d\n", uConfiguration.device, uConfiguration.stream); break; case CLA_PORT: uConfiguration.ports[0].configured = 0; /* clear default config */ /* parse option string one char at a time */ for (count = 0; count < strlen(ports); count++) { if (count > NUM_PORTS) break; port = tolower(ports[count]); if( (port < 0) || (port - 'a' > NUM_PORTS) ) { dagutil_panic("invalid port: %c\n", port); } uConfiguration.ports[(port - 'a')].configured = 1; dagutil_verbose_level(2, "enabling port=%c\n", port -'a' + 'A'); } break; case CLA_ALLPORTS: uConfiguration.allports = 1; break; case CLA_TNUM: uConfiguration.tnum = tnum; dagutil_verbose_level(2, "tun/tap number=%d\n", uConfiguration.tnum); break; case CLA_MAC: memcpy(uConfiguration.ports[0].mac, mactopack(mac_buf), MAC_PACKSIZE); uConfiguration.mac_override = 1; dagutil_verbose_level(2, "MAC address=%s\n", packtomac(uConfiguration.ports[0].mac)); break; case CLA_TXSTREAM: if (!(txstream%2)) { dagutil_error("Invalid txstream %d. tx streams are always odd numbers\n", txstream); return EXIT_FAILURE; } uConfiguration.txstream = txstream; dagutil_verbose_level(2, "tx stream=%d\n", uConfiguration.txstream); break; case CLA_MTU: uConfiguration.mtu = mtu; break; case CLA_FAST: uConfiguration.fast = 1; break; case CLA_DAEMON: uConfiguration.daemon = 1; break; case CLA_HELP: print_usage(clarg); exit(EXIT_SUCCESS); break; case CLA_VERBOSE: dagutil_inc_verbosity(); errorfile = stderr; break; case CLA_VERSION: print_version(); exit(EXIT_SUCCESS); break; default: /* Unknown option. */ dagutil_error("unknown option %s\n", argv[argindex]); print_usage(clarg); return EXIT_FAILURE; } result = dagclarg_parse(clarg, errorfile, &argindex, &code); } if (-1 == result) { if (argindex < argc) { dagutil_error("while processing option %s\n", argv[argindex]); } dagclarg_display_usage(clarg, stderr); return EXIT_FAILURE; } return EXIT_SUCCESS; } /*****************************************************************************/ int get_port_count(dag_card_ref_t card_ref, int *count) { dag_component_t root; root = dag_config_get_root_component(card_ref); *count = dag_component_get_subcomponent_count_of_type(root, kComponentPort); return 0; } /*****************************************************************************/ const char *get_mac_address(dag_card_ref_t card_ref, int portnum) { attr_uuid_t attr; int temp; const char *result = NULL; temp = dagutil_get_verbosity(); dagutil_set_verbosity(0); attr = dag_config_get_indexed_named_attribute_uuid(card_ref, "mac_address", 0); if(attr == kNullAttributeUuid) goto exit; result = dag_config_get_string_attribute(card_ref, attr); if (strncmp("00:00:00:00:00:00", result, 17) == 0) result = NULL; exit: dagutil_set_verbosity(temp); return result; } /*****************************************************************************/ int set_crc_strip(dag_card_ref_t card_ref, int strip) { dag_component_t root; dag_component_t terf; attr_uuid_t attr; uint32_t value; if (strip) { value = 3; dagutil_verbose_level(2, "Setting terf_strip32 on %s\n", uConfiguration.device); } else { value = 1; dagutil_verbose_level(2, "Setting noterf_strip on %s\n", uConfiguration.device); } root = dag_config_get_root_component(card_ref); if (dag_component_get_subcomponent_count_of_type(root, kComponentTerf)) terf = dag_component_get_subcomponent(root, kComponentTerf, 0); /* Use the same component kComponentTerf as kComponentTrTerf is not used anymore*/ /* else if (dag_component_get_subcomponent_count_of_type(root, kComponentTrTerf)) terf = dag_component_get_subcomponent(root, kComponentTrTerf, 0); */ else { dagutil_warning("terf/trterf not supported by this firmware\n"); return EXIT_FAILURE; } attr = dag_component_get_attribute_uuid(terf, kUint32AttributeTerfStripCrc); if ( attr ) dag_config_set_uint32_attribute(card_ref, attr, value); return EXIT_SUCCESS; } /*****************************************************************************/ void set_align64(dag_card_ref_t card_ref) { dag_component_t root; dag_component_t gpp; attr_uuid_t attr; root = dag_config_get_root_component(card_ref); if (dag_component_get_subcomponent_count_of_type(root, kComponentGpp)) gpp = dag_component_get_subcomponent(root, kComponentGpp, 0); else return; attr = dag_component_get_attribute_uuid(gpp, kBooleanAttributeAlign64); if(attr != kNullAttributeUuid) dag_config_set_uint32_attribute(card_ref, attr, 1); } /*****************************************************************************/ int set_snaplen(dag_card_ref_t card_ref) { dag_component_t root; dag_component_t gpp; attr_uuid_t attr; uint32_t value; value = uConfiguration.mtu + 18 + 2 + 2; /* MAC + optional vlan tag + offset/pad bytes */ if(value%8) value += 8-(value%8); root = dag_config_get_root_component(card_ref); if (dag_component_get_subcomponent_count_of_type(root, kComponentGpp)) gpp = dag_component_get_subcomponent(root, kComponentGpp, 0); else if (dag_component_get_subcomponent_count_of_type(root, kComponentSRGPP)) gpp = dag_component_get_subcomponent(root, kComponentSRGPP, 0); else return EXIT_FAILURE; attr = dag_component_get_attribute_uuid(gpp, kUint32AttributeSnaplength); dag_config_set_uint32_attribute(card_ref, attr, value); return EXIT_SUCCESS; } /*****************************************************************************/ static void* transmit_thread(void *context) { dag_record_t hdr; unsigned char *erf_p = NULL; unsigned char *payload_p = NULL; int l = 1; unsigned short rlen, wlen; int count; fd_set fds; int max_fd; struct timeval tv; int dag_fd; dag_fd = uGlobals.dag_fd; memset(&hdr, 0, sizeof(hdr)); hdr.type = ERF_TYPE_ETH; hdr.flags.vlen = 1; /* Reserve tx buffer memory for first packet and initialize pointers */ if ( (erf_p = dag_tx_get_stream_space(dag_fd, uConfiguration.txstream, 64*1024)) == NULL ) { uGlobals.exit_now = 1; dagutil_error("dag_tx_get_stream_space %d: %s\n", dag_record_size, strerror(errno)); pthread_exit(NULL); } payload_p = erf_p + dag_record_size + 2 - 4; while(!uGlobals.exit_now){ FD_ZERO(&fds); max_fd = 0; for (count = 0; count < uConfiguration.card_ports; count++) { if (uConfiguration.ports[count].configured) { FD_SET(uConfiguration.ports[count].tun_fd, &fds); if (uConfiguration.ports[count].tun_fd > max_fd) max_fd = uConfiguration.ports[count].tun_fd; } } tv.tv_sec=0; tv.tv_usec=10000; select(max_fd+1, &fds, NULL, NULL, &tv); for (count = 0; count < uConfiguration.card_ports; count++) { if ( (uConfiguration.ports[count].configured) && (FD_ISSET(uConfiguration.ports[count].tun_fd, &fds)) ) { /* see if packet is there, read tun flags+proto to bitbucket */ if ((l = read(uConfiguration.ports[count].tun_fd, payload_p, 64*1024-dag_record_size+2)) > 0) { //printf("got pkt %d\n", l); /* copy template ERF header into temp buffer */ memcpy(erf_p, &hdr, dag_record_size); /* Set tx interface */ ((dag_record_t*)erf_p)->flags.iface = count; /* Some DAG cards (4.3GE) will drop short packets on tx. * The ERF record on these cards needs to have a minimum * wlen of 60 with noterf_strip. * l is the TUN packet size, and includes a 4 byte header, * so l must be increased to a minimum of 64 to produce a * wlen of at least 60. */ if(l < 64) l = 64; /* subtract 4 byte TUN header */ wlen = l - 4; /* set wlen and rlen in packet ERF header */ rlen = l + dag_record_size + 2 - 4; if(uConfiguration.append_crc) { /* setting nocrc_strip failed, so pad record with incorrect crc! */ rlen += 4; wlen += 4; } if(rlen%8) rlen += 8-(rlen%8); ((dag_record_t*)erf_p)->rlen = htons(rlen); ((dag_record_t*)erf_p)->wlen = htons(wlen); /* debug */ dagutil_verbose_level(2, "tx packet rlen %d wlen %d port %d\n", rlen, wlen, count); /* tell card to send packet */ dag_tx_stream_commit_bytes(dag_fd, uConfiguration.txstream, rlen); } else if( l < 0 && (errno != EAGAIN && errno != EINTR) ) { uGlobals.exit_now = 1; dagutil_error("read: %s\n", strerror(errno)); pthread_exit(NULL); } /* Reserve tx buffer memory for next packet */ if ( (erf_p = dag_tx_get_stream_space(dag_fd, uConfiguration.txstream, 64*1024)) == NULL ) { uGlobals.exit_now = 1; dagutil_error("dag_tx_get_stream_space %d: %s\n", dag_record_size, strerror(errno)); pthread_exit(NULL); } payload_p = erf_p + dag_record_size + 2 - 4; } } } return NULL; } /*****************************************************************************/ static void* receive_thread(void* context) { dag_record_t *erf; uint8_t *record; int written; int dag_fd; unsigned short wlen; dag_fd = uGlobals.dag_fd; while(!uGlobals.exit_now) { if ( (record = dag_rx_stream_next_record(dag_fd, uConfiguration.stream)) == NULL ) { if ( errno == EAGAIN ) { if (uConfiguration.fast) dagutil_microsleep(10); continue; } else { uGlobals.exit_now = 1; dagutil_error("dag_rx_stream_next_record: %s", strerror(errno)); pthread_exit(NULL); } } erf = (dag_record_t*)record; dagutil_verbose_level(2, "rx record rlen %d wlen %d port %d\n", ntohs(erf->rlen), ntohs(erf->wlen), erf->flags.iface); if (erf->flags.rxerror) continue; if (!uConfiguration.ports[erf->flags.iface].configured) continue; if ( (erf->type != ERF_TYPE_ETH) && (erf->type != ERF_TYPE_COLOR_ETH) && (erf->type != ERF_TYPE_DSM_COLOR_ETH) ) continue; wlen = ntohs(erf->wlen); memset(record+14, 0, 2); memcpy(record+16, record+31, 2); if ( (written = write(uConfiguration.ports[erf->flags.iface].tun_fd, record+14, wlen+4)) != wlen+4 ) { uGlobals.exit_now = 1; dagutil_error("write %d got %d: %s", wlen+4, written, strerror(errno)); pthread_exit(NULL); } } return NULL; } static void anysig(int sig) { /* Restore the default signal handlers, so the next interrupt will have the default effect (e.g. exit) */ dagutil_set_signal_handler(SIG_DFL); /* Tell the main loop to exit */ uGlobals.exit_now = 1; return; } /*****************************************************************************/ int main(int argc, char *argv[]) { dag_card_ref_t card_ref = NULL; int ports; int s = -1; struct ifreq ifr; char buf[6]; const char *mac; int result; uint32_t mindata; struct timeval maxwait, poll; int retval = EXIT_SUCCESS; int temp; int count; dagutil_set_progname("dagtuntap"); if ( (retval = parse_commandline(argc, argv)) != EXIT_SUCCESS) goto fail; if(uConfiguration.daemon) { dagutil_verbose("Forking into background\n"); if (dagutil_get_verbosity() > 1) dagutil_set_verbosity(1); temp = daemon(0,0); dagutil_daemon(LOG_PID | LOG_CONS, LOG_DAEMON); dagutil_verbose_level(0, "Started\n"); } temp = dagutil_get_verbosity(); dagutil_set_verbosity(0); if ((card_ref = dag_config_init(uConfiguration.device)) == NULL) { dagutil_error("%s not available: %s\n", uConfiguration.device, strerror(errno)); goto fail_dag; } dagutil_set_verbosity(temp); uGlobals.dag_fd = dag_config_get_card_fd(card_ref); get_port_count(card_ref, &ports); uConfiguration.card_ports = ports; /* For allports option enable all available ports. */ if (uConfiguration.allports) { for (count = 0; count < ports; count++) uConfiguration.ports[count].configured = 1; } /* Check if user requested an interface that is not present */ for (count = ports; count < NUM_PORTS; count++) { if (uConfiguration.ports[count].configured) { dagutil_error("Port %c not in range A-%c\n", count + 'A', ports + 'A' - 1); goto fail_dag; } } if (!uConfiguration.mac_override) { dagutil_verbose_level(2, "MAC not supplied, reading card MAC\n"); for (count = 0; count < ports; count++) { mac = get_mac_address(card_ref, count); if (mac) { memcpy(uConfiguration.ports[count].mac, mactopack(mac), MAC_PACKSIZE); uConfiguration.mac_override = 1; } else dagutil_verbose("DAG card has no MAC Address assigned to port %c and user did not supply MAC (with -m). Using randomly generated MAC\n", count + 'A'); } } else { /* user specified MAC for Port A, increment across to all ports */ for (count = 1; count < ports; count++) { memcpy(uConfiguration.ports[count].mac, uConfiguration.ports[count-1].mac, MAC_PACKSIZE); macpackincrement(uConfiguration.ports[count].mac); } } /* Tell the Terf/TrTerf NOT to strip off 32-bit of CRC on transmit, * because we are not supplying a CRC */ if (set_crc_strip(card_ref, 0)) uConfiguration.append_crc = 1; /* Print configuration details */ print_configuration(); /* Set align64. Not strictly necessary since ERF frames not forwarded? */ //set_align64(card_ref); /* Set snap length */ if ( (retval = set_snaplen(card_ref)) != EXIT_SUCCESS ) { dagutil_warning("set_snaplen: gpp not supported by this firmware, snaplen unchanged\n"); } /* Open tun device(s) */ for (count = 0; count < ports; count++) { if (uConfiguration.ports[count].configured) { snprintf(buf, 6, "tap%d", uConfiguration.tnum + count); if ((uConfiguration.ports[count].tun_fd = open("/dev/net/tun", O_RDWR)) <0) { dagutil_error("open /dev/net/tun: %s\n", strerror(errno)); retval = EXIT_FAILURE; goto fail_dag; } memset(&ifr, 0, sizeof(ifr)); /* Flags: IFF_TUN - TUN device (no Ethernet headers) * IFF_TAP - TAP device * * IFF_NO_PI - Do not provide packet information */ ifr.ifr_flags = IFF_TAP; strncpy(ifr.ifr_name, buf, dagutil_min(6,IFNAMSIZ)); if( ioctl(uConfiguration.ports[count].tun_fd, TUNSETIFF, (void *) &ifr) < 0 ){ retval = EXIT_FAILURE; dagutil_error("TUNSETIFF: %s\n", strerror(errno)); goto fail_tun; } /* OS does not need to compute Ethernet checksum on received frames */ if( ioctl(uConfiguration.ports[count].tun_fd, TUNSETNOCSUM, 1) < 0 ){ retval = EXIT_FAILURE; dagutil_error("TUNSETNOCSUM: %s\n", strerror(errno)); goto fail_tun; } if (uConfiguration.mac_override) { dagutil_verbose_level(2, "Setting MAC Address for Port %c : %s\n", ('A' + count), packtomac(uConfiguration.ports[count].mac)); memcpy(ifr.ifr_hwaddr.sa_data, uConfiguration.ports[count].mac, MAC_PACKSIZE); ifr.ifr_hwaddr.sa_family = AF_LOCAL; /* open socket */ if( (s = socket(AF_INET, SOCK_DGRAM, 0)) == -1 ) { retval = EXIT_FAILURE; dagutil_error("Open socket: %s\n", strerror(errno)); goto fail_tun; } /* set mac */ memcpy(ifr.ifr_hwaddr.sa_data, uConfiguration.ports[count].mac, MAC_PACKSIZE); if( ioctl(s, SIOCSIFHWADDR, &ifr) < 0 ){ retval = EXIT_FAILURE; dagutil_error("SIOCSIFHWADDR: %s\n", strerror(errno)); close(s); goto fail_tun; } close(s); s = -1; } } } /* attach receive stream */ if (dag_attach_stream(uGlobals.dag_fd, uConfiguration.stream, 0, 0)) { retval = EXIT_FAILURE; dagutil_error("dag_attach_stream %d: %s\n", uConfiguration.stream, strerror(errno)); goto fail_tun; } /* attach transmit stream */ if (dag_attach_stream(uGlobals.dag_fd, uConfiguration.txstream, 0, 0)) { retval = EXIT_FAILURE; dagutil_error("dag_attach_stream %d: %s\n", uConfiguration.txstream, strerror(errno)); goto fail_rxstream; } /* Configure stream polling */ maxwait.tv_sec = 0; maxwait.tv_usec = 10000; poll.tv_sec = 0; poll.tv_usec = 1000; mindata = dag_record_size; if (uConfiguration.fast) { maxwait.tv_sec = 0; maxwait.tv_usec = 0; mindata = 0; } dag_set_stream_poll(uGlobals.dag_fd, uConfiguration.stream, mindata, &maxwait, &poll); dag_set_stream_poll(uGlobals.dag_fd, uConfiguration.txstream, mindata, &maxwait, &poll); dagutil_set_signal_handler(anysig); /* Start rx stream */ if (dag_start_stream(uGlobals.dag_fd, uConfiguration.stream)) { retval = EXIT_FAILURE; dagutil_error("dag_start_stream %d: %s\n", uConfiguration.stream, strerror(errno)); goto fail_txstream; } /* Start tx stream */ if (dag_start_stream(uGlobals.dag_fd, uConfiguration.txstream)) { retval = EXIT_FAILURE; dagutil_error("dag_start_stream %d: %s\n", uConfiguration.txstream, strerror(errno)); goto fail_rxstop; } /* start RxThread */ result = pthread_create(&uRxThread, NULL, receive_thread, NULL); if (0 != result) { retval = EXIT_FAILURE; dagutil_error("could not create receive thread: %s\n", strerror(result)); goto fail_txstart; } /* start TxThread */ result = pthread_create(&uTxThread, NULL, transmit_thread, NULL); if (0 != result) { retval = EXIT_FAILURE; dagutil_error("could not create transmit thread: %s\n", strerror(result)); uGlobals.exit_now = 1; goto fail_rxthread; } /* Wait for exit conditions */ pthread_join(uTxThread, NULL); fail_rxthread: pthread_join(uRxThread, NULL); /* shut down */ fail_txstart: dag_stop_stream(uGlobals.dag_fd, uConfiguration.txstream); fail_rxstop: dag_stop_stream(uGlobals.dag_fd, uConfiguration.stream); fail_txstream: dag_detach_stream(uGlobals.dag_fd, uConfiguration.txstream); fail_rxstream: dag_detach_stream(uGlobals.dag_fd, uConfiguration.stream); fail_tun: for(count=0; count < ports; count++) { if(uConfiguration.ports[count].configured) { close(uConfiguration.ports[count].tun_fd); uConfiguration.ports[count].configured = 0; } } fail_dag: dag_config_dispose(card_ref); fail: dagutil_verbose_level(0, "Exiting\n"); return retval; } .