diff options
author | Matthias Schiffer <mschiffer@universe-factory.net> | 2012-03-24 20:55:27 +0100 |
---|---|---|
committer | Matthias Schiffer <mschiffer@universe-factory.net> | 2012-03-24 20:55:27 +0100 |
commit | 4ffc28ecd6d914f9c1e5aaf5d5921ee4827bb289 (patch) | |
tree | ddd64c27220b75f45a6efdc162bbbe040a9ca001 | |
parent | 78fe2cda0572433e40889bcd7d64dd22707bfdd0 (diff) | |
download | fastd-4ffc28ecd6d914f9c1e5aaf5d5921ee4827bb289.tar fastd-4ffc28ecd6d914f9c1e5aaf5d5921ee4827bb289.zip |
Partial implementation of a config files parser
-rw-r--r-- | CMakeLists.txt | 3 | ||||
-rw-r--r-- | FindFLEX.cmake | 120 | ||||
-rw-r--r-- | src/CMakeLists.txt | 18 | ||||
-rw-r--r-- | src/config.c (renamed from src/configure.c) | 48 | ||||
-rw-r--r-- | src/config.l | 57 | ||||
-rw-r--r-- | src/config.y | 106 | ||||
-rw-r--r-- | src/fastd.c | 12 | ||||
-rw-r--r-- | src/fastd.h | 10 | ||||
-rw-r--r-- | src/handshake.c | 12 | ||||
-rw-r--r-- | src/packet.h | 2 | ||||
-rw-r--r-- | src/peer.c | 12 | ||||
-rw-r--r-- | src/types.h | 8 |
12 files changed, 365 insertions, 43 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index da8027e..ed04b15 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,6 +3,9 @@ project(FASTD C) set(CMAKE_MODULE_PATH ${FASTD_SOURCE_DIR}) +find_package(BISON REQUIRED) +find_package(FLEX REQUIRED) + find_package(UECC) find_package(NaCl) diff --git a/FindFLEX.cmake b/FindFLEX.cmake new file mode 100644 index 0000000..fe83369 --- /dev/null +++ b/FindFLEX.cmake @@ -0,0 +1,120 @@ +#============================================================================= +# Copyright 2009 Kitware, Inc. +# Copyright 2006 Tristan Carel +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# * Neither the names of Kitware, Inc., the Insight Software Consortium, +# nor the names of their contributors may be used to endorse or promote +# products derived from this software without specific prior written +# permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# ------------------------------------------------------------------------------ +# +# The above copyright and license notice applies to distributions of +# CMake in source and binary form. Some source files contain additional +# notices of original copyright by their contributors; see each source +# for details. Third-party software packages supplied with CMake under +# compatible licenses provide their own copyright notices documented in +# corresponding subdirectories. +#============================================================================= + +FIND_PROGRAM(FLEX_EXECUTABLE flex DOC "path to the flex executable") +MARK_AS_ADVANCED(FLEX_EXECUTABLE) + +FIND_LIBRARY(FL_LIBRARY NAMES fl + DOC "Path to the fl library") + +FIND_PATH(FLEX_INCLUDE_DIR FlexLexer.h + DOC "Path to the flex headers") + +MARK_AS_ADVANCED(FL_LIBRARY FLEX_INCLUDE_DIR) + +SET(FLEX_INCLUDE_DIRS ${FLEX_INCLUDE_DIR}) +SET(FLEX_LIBRARIES ${FL_LIBRARY}) + +IF(FLEX_EXECUTABLE) + + EXECUTE_PROCESS(COMMAND ${FLEX_EXECUTABLE} --version + OUTPUT_VARIABLE FLEX_version_output + ERROR_VARIABLE FLEX_version_error + RESULT_VARIABLE FLEX_version_result + OUTPUT_STRIP_TRAILING_WHITESPACE) + IF(NOT ${FLEX_version_result} EQUAL 0) + IF(FLEX_FIND_REQUIRED) + MESSAGE(SEND_ERROR "Command \"${FLEX_EXECUTABLE} --version\" failed with output:\n${FLEX_version_output}\n${FLEX_version_error}") + ELSE() + MESSAGE("Command \"${FLEX_EXECUTABLE} --version\" failed with output:\n${FLEX_version_output}\n${FLEX_version_error}\nFLEX_VERSION will not be available") + ENDIF() + ELSE() + STRING(REGEX REPLACE "^flex (.*)$" "\\1" + FLEX_VERSION "${FLEX_version_output}") + ENDIF() + + #============================================================ + # FLEX_TARGET (public macro) + #============================================================ + # + MACRO(FLEX_TARGET Name Input Output) + SET(FLEX_TARGET_usage "FLEX_TARGET(<Name> <Input> <Output> [COMPILE_FLAGS <string>]") + IF(${ARGC} GREATER 3) + IF(${ARGC} EQUAL 5) + IF("${ARGV3}" STREQUAL "COMPILE_FLAGS") + SET(FLEX_EXECUTABLE_opts "${ARGV4}") + SEPARATE_ARGUMENTS(FLEX_EXECUTABLE_opts) + ELSE() + MESSAGE(SEND_ERROR ${FLEX_TARGET_usage}) + ENDIF() + ELSE() + MESSAGE(SEND_ERROR ${FLEX_TARGET_usage}) + ENDIF() + ENDIF() + + STRING(REGEX REPLACE "^(.*)(\\.[^.]*)$" "\\2" _fileext "${Output}") + STRING(REPLACE "c" "h" _fileext ${_fileext}) + STRING(REGEX REPLACE "^(.*)(\\.[^.]*)$" "\\1${_fileext}" + OutputHeader "${Output}") + + ADD_CUSTOM_COMMAND(OUTPUT ${Output} ${OutputHeader} + COMMAND ${FLEX_EXECUTABLE} + ARGS ${FLEX_EXECUTABLE_opts} -o${Output} --header-file=${OutputHeader} ${Input} + DEPENDS ${Input} + COMMENT "[FLEX][${Name}] Building scanner with flex ${FLEX_VERSION}" + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) + + SET(FLEX_${Name}_DEFINED TRUE) + SET(FLEX_${Name}_OUTPUTS ${Output} ${OutputHeader}) + SET(FLEX_${Name}_OUTPUT_HEADER ${OutputHeader}) + SET(FLEX_${Name}_INPUT ${Input}) + SET(FLEX_${Name}_COMPILE_FLAGS ${FLEX_EXECUTABLE_opts}) + ENDMACRO(FLEX_TARGET) + #============================================================ + + +ENDIF(FLEX_EXECUTABLE) + +FIND_PACKAGE_HANDLE_STANDARD_ARGS(FLEX REQUIRED_VARS FLEX_EXECUTABLE + VERSION_VAR FLEX_VERSION) + +# FindFLEX.cmake ends here diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 223c62a..1da7d13 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,5 +1,5 @@ set(METHODS method_null.c) -set(FASTD_INCLUDES ${FASTD_BINARY_DIR}) +set(FASTD_INCLUDES ${CMAKE_CURRENT_SOURCE_DIR} ${FASTD_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}) set(FASTD_LIBS "") if(WITH_METHOD_ECFXP) @@ -10,5 +10,19 @@ endif(WITH_METHOD_ECFXP) include_directories(${FASTD_INCLUDES}) -add_executable(fastd fastd.c configure.c handshake.c peer.c printf.c queue.c task.c ${METHODS}) +FLEX_TARGET(fastd_config_lex config.l ${CMAKE_CURRENT_BINARY_DIR}/config.ll.c) +BISON_TARGET(fastd_config_parse config.y ${CMAKE_CURRENT_BINARY_DIR}/config.yy.c) + +add_executable(fastd + fastd.c + config.c + handshake.c + peer.c + printf.c + queue.c + task.c + ${FLEX_fastd_config_lex_OUTPUTS} + ${BISON_fastd_config_parse_OUTPUTS} + ${METHODS} +) target_link_libraries(fastd rt ${FASTD_LIBS}) diff --git a/src/configure.c b/src/config.c index 7473696..18fe120 100644 --- a/src/configure.c +++ b/src/config.c @@ -27,6 +27,8 @@ #include "fastd.h" #include "peer.h" +#include <config.ll.h> +#include <config.yy.h> #include <config.h> @@ -52,16 +54,16 @@ static void default_config(fastd_config *conf) { memset(&conf->bind_addr_in, 0, sizeof(struct sockaddr_in)); conf->bind_addr_in.sin_family = AF_UNSPEC; - conf->bind_addr_in.sin_port = htons(1337); + conf->bind_addr_in.sin_port = 0; conf->bind_addr_in.sin_addr.s_addr = htonl(INADDR_ANY); memset(&conf->bind_addr_in6, 0, sizeof(struct sockaddr_in6)); conf->bind_addr_in6.sin6_family = AF_UNSPEC; - conf->bind_addr_in6.sin6_port = htons(1337); + conf->bind_addr_in6.sin6_port = 0; conf->bind_addr_in6.sin6_addr = in6addr_any; conf->mtu = 1500; - conf->protocol = PROTOCOL_ETHERNET; + conf->mode = MODE_TAP; conf->method = &fastd_method_null; conf->peers = NULL; } @@ -85,6 +87,21 @@ static bool config_match(const char *opt, ...) { return match; } +static void fastd_read_config(fastd_context *ctx, fastd_config *conf, const char *filename) { + yyscan_t scanner; + FILE *file; + + file = fopen(filename, "r"); + fastd_config_lex_init(&scanner); + + fastd_config_set_in(file, scanner); + + fastd_config_parse(ctx, conf, scanner); + + fastd_config_lex_destroy(scanner); + fclose(file); +} + #define IF_OPTION(args...) if(config_match(argv[i], args, NULL) && (++i)) #define IF_OPTION_ARG(args...) if(config_match(argv[i], args, NULL) && ({ \ arg = argv[i+1]; \ @@ -114,6 +131,11 @@ void fastd_configure(fastd_context *ctx, fastd_config *conf, int argc, char *con while (i < argc) { + IF_OPTION_ARG("-c", "--config") { + fastd_read_config(ctx, conf, arg); + continue; + } + IF_OPTION_ARG("-i", "--interface") { conf->ifname = arg; continue; @@ -180,18 +202,18 @@ void fastd_configure(fastd_context *ctx, fastd_config *conf, int argc, char *con continue; } - IF_OPTION_ARG("-P", "--protocol") { - if (!strcmp(arg, "ethernet")) - conf->protocol = PROTOCOL_ETHERNET; - else if (!strcmp(arg, "ip")) - conf->protocol = PROTOCOL_IP; + IF_OPTION_ARG("-m", "--mode") { + if (!strcmp(arg, "tap")) + conf->mode = MODE_TAP; + else if (!strcmp(arg, "tun")) + conf->mode = MODE_TUN; else - exit_error(ctx, "invalid protocol `%s'", arg); + exit_error(ctx, "invalid mode `%s'", arg); continue; } - IF_OPTION_ARG("-m", "--method") { + IF_OPTION_ARG("-P", "--protocol") { if (!strcmp(arg, "null")) conf->method = &fastd_method_null; #ifdef WITH_METHOD_ECFXP @@ -199,7 +221,7 @@ void fastd_configure(fastd_context *ctx, fastd_config *conf, int argc, char *con conf->method = &fastd_method_ec25519_fhmqvc_xsalsa20_poly1305; #endif else - exit_error(ctx, "invalid method `%s'", arg); + exit_error(ctx, "invalid protocol `%s'", arg); continue; } @@ -281,8 +303,8 @@ void fastd_configure(fastd_context *ctx, fastd_config *conf, int argc, char *con } bool ok = true; - if (conf->protocol == PROTOCOL_IP && (!conf->peers || conf->peers->next)) { - pr_error(ctx, "for protocol `ip' exactly one peer must be configured"); + if (conf->mode == MODE_TUN && (!conf->peers || conf->peers->next)) { + pr_error(ctx, "for tun mode exactly one peer must be configured"); ok = false; } diff --git a/src/config.l b/src/config.l new file mode 100644 index 0000000..e9dd235 --- /dev/null +++ b/src/config.l @@ -0,0 +1,57 @@ +%option prefix="fastd_config_" +%option noyywrap +%option bison-bridge +%option reentrant + +%top { + #include <fastd.h> + #include <config.yy.h> + #define YY_DECL int fastd_config_lex(YYSTYPE *yylval_param, fastd_context *ctx, void *yyscanner) +} + +%x STRING +%x ADDR6 + +%% +[0-9]+ { yylval->num = atoi(yytext); return TOK_INTEGER; } + +interface { yylval->str = yytext; return TOK_INTERFACE; } +bind { yylval->str = yytext; return TOK_BIND; } +mtu { yylval->str = yytext; return TOK_MTU; } +mode { yylval->str = yytext; return TOK_MODE; } +protocol { yylval->str = yytext; return TOK_PROTOCOL; } +peer { yylval->str = yytext; return TOK_PEER; } + +[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3} { + if (!inet_pton(AF_INET, yytext, &yylval->addr)) + exit_error(ctx, "config error: invalid address"); + + return TOK_ADDR; + } + +any { yylval->str = yytext; return TOK_ANY; } +float { yylval->str = yytext; return TOK_FLOAT; } +tap { yylval->str = yytext; return TOK_TAP; } +tun { yylval->str = yytext; return TOK_TUN; } + +[A-Za-z_][A-Za-z0-9_]* { yylval->str = yytext; return TOK_IDENTIFIER; } + +[;:\{\}] { return *yytext; } + +[ \t\n] ; + +\" BEGIN(STRING); +<STRING>[^"]* { yylval->str = yytext; return TOK_STRING; } +<STRING>\" BEGIN(INITIAL); + +\[ BEGIN(ADDR6); +<ADDR6>[^\]]+ { + if (!inet_pton(AF_INET6, yytext, &yylval->addr6)) + exit_error(ctx, "config error: invalid address"); + + return TOK_ADDR6; + } +<ADDR6>\] BEGIN(INITIAL); + +<INITIAL,STRING,ADDR6>. exit_error(ctx, "config error: invalid character"); +%% diff --git a/src/config.y b/src/config.y new file mode 100644 index 0000000..08c5050 --- /dev/null +++ b/src/config.y @@ -0,0 +1,106 @@ +%define api.pure +%name-prefix "fastd_config_" +%lex-param {fastd_context *ctx} +%lex-param {yyscan_t scanner} +%parse-param {fastd_context *ctx} +%parse-param {fastd_config *config} +%parse-param {yyscan_t scanner} + +%code requires { + #include <arpa/inet.h> +} + +%union { + int num; + char* str; + struct in_addr addr; + struct in6_addr addr6; +} + +%token <num> TOK_INTEGER +%token <str> TOK_STRING +%token <str> TOK_IDENTIFIER + +%token <str> TOK_INTERFACE +%token <str> TOK_BIND +%token <str> TOK_MTU +%token <str> TOK_MODE +%token <str> TOK_PROTOCOL +%token <str> TOK_PEER + +%token <addr> TOK_ADDR +%token <addr6> TOK_ADDR6 + +%token <str> TOK_ANY +%token <str> TOK_FLOAT +%token <str> TOK_TAP +%token <str> TOK_TUN + +/* %code top { + #define YY_DECL int fastd_config_lex(YYSTYPE *yylval_param, fastd_context *ctx, yyscan_t yyscanner) +}*/ + + +%code { + #include <config.ll.h> + YY_DECL; + + void fastd_config_error(fastd_context *ctx, fastd_config *config, void *scanner, char *s); +} + +%code provides { + #include <fastd.h> + int fastd_config_parse (fastd_context *ctx, fastd_config *config, void *scanner); +} + +%% +config: config statement + | + ; + +statement: TOK_INTERFACE interface ';' + | TOK_BIND bind ';' + | TOK_MTU mtu ';' + | TOK_MODE mode ';' + | TOK_PROTOCOL protocol ';' + | TOK_PEER peer '{' peer_config '}' + ; + +interface: TOK_STRING { config->ifname = strdup($1); } + ; + +bind: TOK_ADDR + | TOK_ADDR ':' port + | TOK_ADDR6 + | TOK_ADDR6 ':' port + | TOK_ANY + | TOK_ANY ':' port + ; + +mtu: TOK_INTEGER { config->mtu = $1; } + ; + +mode: TOK_TAP { config->mode = MODE_TAP; } + | TOK_TUN { config->mode = MODE_TUN; } + ; + +protocol: TOK_STRING + ; + +peer: TOK_STRING + | + ; + +peer_config: peer_config peer_statement + | + ; + +peer_statement: ':' + ; + +port: TOK_INTEGER + ; +%% +void fastd_config_error(fastd_context *ctx, fastd_config *config, yyscan_t scanner, char *s) { + exit_error(ctx, "config error: %s", s); +} diff --git a/src/fastd.c b/src/fastd.c index cae7c64..3b27e98 100644 --- a/src/fastd.c +++ b/src/fastd.c @@ -53,17 +53,17 @@ static void init_tuntap(fastd_context *ctx) { if (ctx->conf->ifname) strncpy(ifr.ifr_name, ctx->conf->ifname, IF_NAMESIZE-1); - switch (ctx->conf->protocol) { - case PROTOCOL_ETHERNET: + switch (ctx->conf->mode) { + case MODE_TAP: ifr.ifr_flags = IFF_TAP; break; - case PROTOCOL_IP: + case MODE_TUN: ifr.ifr_flags = IFF_TUN; break; default: - exit_bug(ctx, "invalid protocol"); + exit_bug(ctx, "invalid mode"); } ifr.ifr_flags |= IFF_NO_PI; @@ -166,7 +166,7 @@ static void handle_tasks(fastd_context *ctx) { break; case TASK_HANDLE_RECV: - if (ctx->conf->protocol == PROTOCOL_ETHERNET) { + if (ctx->conf->mode == MODE_TAP) { const fastd_eth_addr *src_addr = fastd_get_source_address(ctx, task->handle_recv.buffer); if (fastd_eth_addr_is_unicast(src_addr)) @@ -208,7 +208,7 @@ static void handle_tun(fastd_context *ctx) { fastd_peer *peer = NULL; - if (ctx->conf->protocol == PROTOCOL_ETHERNET) { + if (ctx->conf->mode == MODE_TAP) { const fastd_eth_addr *dest_addr = fastd_get_dest_address(ctx, buffer); if (fastd_eth_addr_is_unicast(dest_addr)) { peer = fastd_peer_find_by_eth_addr(ctx, dest_addr); diff --git a/src/fastd.h b/src/fastd.h index c42baa3..4af9f20 100644 --- a/src/fastd.h +++ b/src/fastd.h @@ -87,7 +87,7 @@ struct _fastd_config { struct sockaddr_in6 bind_addr_in6; uint16_t mtu; - fastd_protocol protocol; + fastd_mode mode; fastd_method *method; @@ -153,13 +153,13 @@ static inline void fastd_buffer_free(fastd_buffer buffer) { } static inline size_t fastd_max_packet_size(const fastd_context *ctx) { - switch (ctx->conf->protocol) { - case PROTOCOL_ETHERNET: + switch (ctx->conf->mode) { + case MODE_TAP: return ctx->conf->mtu+ETH_HLEN; - case PROTOCOL_IP: + case MODE_TUN: return ctx->conf->mtu; default: - exit_bug(ctx, "invalid protocol"); + exit_bug(ctx, "invalid mode"); } } diff --git a/src/handshake.c b/src/handshake.c index e30ab9f..19f15a9 100644 --- a/src/handshake.c +++ b/src/handshake.c @@ -74,8 +74,8 @@ void fastd_handshake_send(fastd_context *ctx, fastd_peer *peer) { request->req_id = ++peer->last_req_id; request->rsv = 0; - uint8_t protocol = ctx->conf->protocol; - handshake_add(ctx, &buffer, RECORD_PROTOCOL, 1, &protocol); + uint8_t mode = ctx->conf->mode; + handshake_add(ctx, &buffer, RECORD_MODE, 1, &mode); handshake_add(ctx, &buffer, RECORD_METHOD_NAME, method_len, ctx->conf->method->name); @@ -119,15 +119,15 @@ void fastd_handshake_handle(fastd_context *ctx, fastd_peer *peer, fastd_buffer b uint8_t reply_code = REPLY_SUCCESS; uint8_t error_detail = 0; - if (!records[RECORD_PROTOCOL]) { + if (!records[RECORD_MODE]) { reply_code = REPLY_MANDATORY_MISSING; - error_detail = RECORD_PROTOCOL; + error_detail = RECORD_MODE; goto send_reply; } - if (lengths[RECORD_PROTOCOL] != 1 || *(uint8_t*)records[RECORD_PROTOCOL] != ctx->conf->protocol) { + if (lengths[RECORD_MODE] != 1 || *(uint8_t*)records[RECORD_MODE] != ctx->conf->mode) { reply_code = REPLY_UNACCEPTABLE_VALUE; - error_detail = RECORD_PROTOCOL; + error_detail = RECORD_MODE; goto send_reply; } diff --git a/src/packet.h b/src/packet.h index d442d18..b206663 100644 --- a/src/packet.h +++ b/src/packet.h @@ -42,7 +42,7 @@ typedef enum _fastd_handshake_record_type { RECORD_REPLY_CODE = 0, RECORD_ERROR_DETAIL, RECORD_FLAGS, - RECORD_PROTOCOL, + RECORD_MODE, RECORD_METHOD_NAME, RECORD_MAX, } fastd_handshake_record_type; @@ -32,20 +32,20 @@ const fastd_eth_addr* fastd_get_source_address(const fastd_context *ctx, fastd_buffer buffer) { - switch (ctx->conf->protocol) { - case PROTOCOL_ETHERNET: + switch (ctx->conf->mode) { + case MODE_TAP: return (fastd_eth_addr*)&((struct ethhdr*)buffer.data)->h_source; default: - exit_bug(ctx, "invalid protocol"); + exit_bug(ctx, "invalid mode"); } } const fastd_eth_addr* fastd_get_dest_address(const fastd_context *ctx, fastd_buffer buffer) { - switch (ctx->conf->protocol) { - case PROTOCOL_ETHERNET: + switch (ctx->conf->mode) { + case MODE_TAP: return (fastd_eth_addr*)&((struct ethhdr*)buffer.data)->h_dest; default: - exit_bug(ctx, "invalid protocol"); + exit_bug(ctx, "invalid mode"); } } diff --git a/src/types.h b/src/types.h index af577e3..61417fc 100644 --- a/src/types.h +++ b/src/types.h @@ -42,10 +42,10 @@ typedef enum _fastd_loglevel { LOG_DEBUG, } fastd_loglevel; -typedef enum _fastd_protocol { - PROTOCOL_ETHERNET, - PROTOCOL_IP, -} fastd_protocol; +typedef enum _fastd_mode { + MODE_TAP, + MODE_TUN, +} fastd_mode; typedef enum _fastd_peer_state { STATE_WAIT, |