/* * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. * * 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 name of The Linux Foundation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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. */ /* * This file was originally distributed by Qualcomm Atheros, Inc. * under proprietary terms before Copyright ownership was assigned * to the Linux Foundation. */ /** * @file dsrc_config.c * @brief Configuration commands for DSRC. * * Configuration commands are part of the 802.11p spec. This reads all the * user parameters for a control command, process those into a format exposed * by the dsrc_nl APIs and call nl80211 APIs that will do the actual * communication with the host driver. */ #include #include #include #include #include #include "dsrc_nl.h" #define DCC_BITMAP_DEFAULT 0xff #define TIME_ERROR_DEFAULT 0xff #ifdef _ANDROID_ int getsubopt(char **optionp, char * const *tokens, char **valuep); #endif /** * @brief UTC time conversion constant. * * Number of seconds from Jan 1st 1958 to Jan 2nd 1970 * This is needed to convert from the Linux UTC to 802.11 * definition of UTC time */ #define SEC_1958_1970 378691200 #define DEFAULT_CONTROL_CHANNEL 5860 #define DEFAULT_SERVICE_CHANNEL 5900 #define DEFAULT_CCH_GUARD_MS 4 #define DEFAULT_SCH_GUARD_MS 4 #define DEFAULT_CCH_DURATION_MS 50 #define DEFAULT_SCH_DURATION_MS 50 #define DEFAULT_CCH_TX_POWER 17 #define DEFAULT_SCH_TX_POWER 17 #define DEFAULR_QOS_BE_AIFSN 6 #define DEFAULT_QOS_BE_CWMIN 4 #define DEFAULT_QOS_BE_CWMAX 10 #define DEFAULT_QOS_BK_AIFSN 9 #define DEFAULT_QOS_BK_CWMAX 10 #define DEFAULT_QOS_BK_CWMIN 4 #define DEFAULT_QOS_VI_AIFSN 3 #define DEFAULT_QOS_VI_CWMAX 4 #define DEFAULT_QOS_VI_CWMIN 3 #define DEFAULT_QOS_VO_AIFSN 2 #define DEFAULT_QOS_VO_CWMAX 4 #define DEFAULT_QOS_VO_CWMIN 2 struct dsrc_channel { uint32_t frequency; uint32_t bandwidth; uint32_t tx_power; uint32_t sched_duration; uint32_t sched_guard; uint16_t flags; struct dsrc_ocb_qos_params qos_params[DSRC_OCB_NUM_AC]; }; struct dsrc_config_params { char *cmd; char *interface; char *chan_opts; uint32_t num_channels; uint32_t enable_dcc; struct dsrc_channel channels[2]; uint32_t repeat_rate; uint32_t flags; }; /** * Prints the command line usage message. */ void dsrc_config_usage() { printf("Usage: dsrc_config [-i ] [-c ]\n"); printf(" [-o ] [-d] [-r repeat rate>]\n"); printf("Defaults: interface wlanocb0, channel 5860\n"); printf("-c : \n"); printf(" set_config, ndl_update, get_stats, stats_event, \n"); printf(" clear_stats, set_utc, start_ta, stop_ta, get_tsf, rx_vsa\n"); printf("-o : \n"); printf(" Used for set_config, get_stats, start_ta and stop_ta. \n"); printf(" num_channels={1|2} : \n"); printf(" when 1 channel_freq0 and channel_bandwidth0 are needed.\n"); printf(" when 2 same as 1, additionally freq1 and bandwidth1 are needed.\n"); printf(" channel_freq0=
\n"); printf(" channel_bandwidth0=\n"); printf(" tx_power0=\n"); printf(" duration0=\n"); printf(" guard0=\n"); printf(" disable_rx_stats0={0|1} : \n"); printf(" when 0 (default) RX stats headers are added.\n"); printf(" when 1 RX stats headers are not added.\n"); printf(" channel_freq1=
\n"); printf(" channel_bandwidth1=\n"); printf(" tx_power1=\n"); printf(" duration1=\n"); printf(" guard1=\n"); printf(" disable_rx_stats1={0|1} : \n"); printf(" when 0 (default) RX stats headers are added.\n"); printf(" when 1 RX stats headers are not added.\n"); printf(" expiry_tsf={0|1} : \n"); printf(" when 0 (default) expiry time in TX options is relative.\n"); printf(" when 1 expiry time in TX options is interpreted as a TSF time.\n"); printf(" eth_mode={0|1} :\n"); printf(" when 0 (default) the app must send 802.11 frames and firmware will not convert.\n"); printf(" when 1 the firmware will convert 802.3 frames to 802.11.\n"); printf("-d : \n"); printf(" Enable DCC parameters if this option is present.\n"); printf(" Used for the set_config command.\n"); printf("-r : \n"); printf(" Number of times the TA frame will be sent in a 5 seconds interval.\n"); printf(" Used for the start_ta command.\n"); } int dsrc_config_get_options(int argc, char *argv[], struct dsrc_config_params *params) { int c; int rc = 0; /* defaults */ params->interface = "wlanocb0"; params->cmd = "set_config"; while ((c = getopt(argc, argv, "c:i:o:df:r:h?")) != -1) { switch (c) { case 'c': params->cmd = optarg; break; case 'i': params->interface = optarg; break; case 'o': params->chan_opts = optarg; break; case 'd': params->enable_dcc = 1; break; case 'r': params->repeat_rate = strtoul(optarg, NULL, 10); break; case 'h': case '?': default: rc = -1; dsrc_config_usage(); goto bail; } } bail: return rc; } static void dsrc_channel_init(struct dsrc_config_params *params) { params->num_channels = 1; params->flags = OCB_CONFIG_FLAG_80211_FRAME_MODE; params->channels[0].frequency = DEFAULT_CONTROL_CHANNEL; params->channels[0].bandwidth = 10; params->channels[0].sched_duration = DEFAULT_CCH_DURATION_MS; params->channels[0].sched_guard = DEFAULT_CCH_GUARD_MS; params->channels[0].tx_power = DEFAULT_CCH_TX_POWER; params->channels[0].flags = 0; params->channels[0].qos_params[DSRC_OCB_AC_BE].aifsn = DEFAULR_QOS_BE_AIFSN; params->channels[0].qos_params[DSRC_OCB_AC_BE].cwmax = DEFAULT_QOS_BE_CWMAX; params->channels[0].qos_params[DSRC_OCB_AC_BE].cwmin = DEFAULT_QOS_BE_CWMIN; params->channels[0].qos_params[DSRC_OCB_AC_BK].aifsn = DEFAULT_QOS_BK_AIFSN; params->channels[0].qos_params[DSRC_OCB_AC_BK].cwmax = DEFAULT_QOS_BK_CWMAX; params->channels[0].qos_params[DSRC_OCB_AC_BK].cwmin = DEFAULT_QOS_BK_CWMIN; params->channels[0].qos_params[DSRC_OCB_AC_VI].aifsn = DEFAULT_QOS_VI_AIFSN; params->channels[0].qos_params[DSRC_OCB_AC_VI].cwmax = DEFAULT_QOS_VI_CWMAX; params->channels[0].qos_params[DSRC_OCB_AC_VI].cwmin = DEFAULT_QOS_VI_CWMIN; params->channels[0].qos_params[DSRC_OCB_AC_VO].aifsn = DEFAULT_QOS_VO_AIFSN; params->channels[0].qos_params[DSRC_OCB_AC_VO].cwmax = DEFAULT_QOS_VO_CWMAX; params->channels[0].qos_params[DSRC_OCB_AC_VO].cwmin = DEFAULT_QOS_VO_CWMIN; params->channels[1].frequency = DEFAULT_SERVICE_CHANNEL; params->channels[1].bandwidth = 10; params->channels[1].sched_duration = DEFAULT_SCH_DURATION_MS; params->channels[1].sched_guard = DEFAULT_SCH_GUARD_MS; params->channels[1].tx_power = DEFAULT_SCH_TX_POWER; params->channels[1].flags = 0; params->channels[1].qos_params[DSRC_OCB_AC_BE].aifsn = DEFAULR_QOS_BE_AIFSN; params->channels[1].qos_params[DSRC_OCB_AC_BE].cwmax = DEFAULT_QOS_BE_CWMAX; params->channels[1].qos_params[DSRC_OCB_AC_BE].cwmin = DEFAULT_QOS_BE_CWMIN; params->channels[1].qos_params[DSRC_OCB_AC_BK].aifsn = DEFAULT_QOS_BK_AIFSN; params->channels[1].qos_params[DSRC_OCB_AC_BK].cwmax = DEFAULT_QOS_BK_CWMAX; params->channels[1].qos_params[DSRC_OCB_AC_BK].cwmin = DEFAULT_QOS_BK_CWMIN; params->channels[1].qos_params[DSRC_OCB_AC_VI].aifsn = DEFAULT_QOS_VI_AIFSN; params->channels[1].qos_params[DSRC_OCB_AC_VI].cwmax = DEFAULT_QOS_VI_CWMAX; params->channels[1].qos_params[DSRC_OCB_AC_VI].cwmin = DEFAULT_QOS_VI_CWMIN; params->channels[1].qos_params[DSRC_OCB_AC_VO].aifsn = DEFAULT_QOS_VO_AIFSN; params->channels[1].qos_params[DSRC_OCB_AC_VO].cwmax = DEFAULT_QOS_VO_CWMAX; params->channels[1].qos_params[DSRC_OCB_AC_VO].cwmin = DEFAULT_QOS_VO_CWMIN; } static int dsrc_parse_channel_options(struct dsrc_config_params *params) { int rc = 0; enum { NUM_CHAN = 0, CHAN0, BW0, PWR0, DUR0, GUARD0, DISABLE_RX_STATS0, CHAN1, BW1, PWR1, DUR1, GUARD1, DISABLE_RX_STATS1, EXPIRY_TSF, ETH_MODE, THE_END }; char *set_chan_opts[] = { [NUM_CHAN] = "num_channels", [CHAN0] = "channel_freq0", [BW0] = "channel_bandwidth0", [PWR0] = "tx_power0", [DUR0] = "duration0", [GUARD0] = "guard0", [DISABLE_RX_STATS0] = "disable_rx_stats0", [CHAN1] = "channel_freq1", [BW1] = "channel_bandwidth1", [PWR1] = "tx_power1", [DUR1] = "duration1", [GUARD1] = "guard1", [DISABLE_RX_STATS1] = "disable_rx_stats1", [EXPIRY_TSF] = "expiry_tsf", [ETH_MODE] = "eth_mode", [THE_END] = NULL }; char *value; dsrc_channel_init(params); while (params->chan_opts && *(params->chan_opts) != '\0') { switch (getsubopt(¶ms->chan_opts, set_chan_opts, &value)) { case NUM_CHAN: if (value == NULL) { printf("Missing value for suboption '%s'\n", set_chan_opts[NUM_CHAN]); break; } params->num_channels = strtol(value, NULL, 10); break; case CHAN0: if (value == NULL) { printf("Missing value for suboption '%s'\n", set_chan_opts[CHAN0]); break; } params->channels[0].frequency = strtol(value, NULL, 10); break; case CHAN1: if (value == NULL) { printf("Missing value for suboption '%s'\n", set_chan_opts[CHAN1]); break; } params->channels[1].frequency = strtol(value, NULL, 10); break; case BW0: if (value == NULL) { printf("Missing value for suboption '%s'\n", set_chan_opts[BW0]); break; } params->channels[0].bandwidth = strtol(value, NULL, 10); break; case BW1: if (value == NULL) { printf("Missing value for suboption '%s'\n", set_chan_opts[BW1]); break; } params->channels[1].bandwidth = strtol(value, NULL, 10); break; case PWR0: if (value == NULL) { printf("Missing value for suboption '%s'\n", set_chan_opts[PWR0]); break; } params->channels[0].tx_power = strtol(value, NULL, 10); break; case PWR1: if (value == NULL) { printf("Missing value for suboption '%s'\n", set_chan_opts[PWR1]); break; } params->channels[1].tx_power = strtol(value, NULL, 10); break; case DUR0: if (value == NULL) { printf("Missing value for suboption '%s'\n", set_chan_opts[DUR0]); break; } params->channels[0].sched_duration = strtol(value, NULL, 10); break; case DUR1: if (value == NULL) { printf("Missing value for suboption '%s'\n", set_chan_opts[DUR1]); break; } params->channels[1].sched_duration = strtol(value, NULL, 10); break; case GUARD0: if (value == NULL) { printf("Missing value for suboption '%s'\n", set_chan_opts[GUARD0]); break; } params->channels[0].sched_guard = strtol(value, NULL, 10); break; case GUARD1: if (value == NULL) { printf("Missing value for suboption '%s'\n", set_chan_opts[GUARD1]); break; } params->channels[1].sched_guard = strtol(value, NULL, 10); break; case DISABLE_RX_STATS0: if (value == NULL) { printf("Missing value for suboption '%s'\n", set_chan_opts[DISABLE_RX_STATS0]); break; } if (strtol(value, NULL, 10)) params->channels[0].flags |= OCB_CHANNEL_FLAG_DISABLE_RX_STATS_HDR; else params->channels[0].flags &= ~OCB_CHANNEL_FLAG_DISABLE_RX_STATS_HDR; break; case DISABLE_RX_STATS1: if (value == NULL) { printf("Missing value for suboption '%s'\n", set_chan_opts[DISABLE_RX_STATS1]); break; } if (strtol(value, NULL, 10)) params->channels[1].flags |= OCB_CHANNEL_FLAG_DISABLE_RX_STATS_HDR; else params->channels[1].flags &= ~OCB_CHANNEL_FLAG_DISABLE_RX_STATS_HDR; break; case EXPIRY_TSF: if (value == NULL) { printf("Missing value for suboption '%s'\n", set_chan_opts[EXPIRY_TSF]); break; } if (strtol(value, NULL, 10)) params->flags |= OCB_CONFIG_FLAG_EXPIRY_TIME_IN_TSF; else params->flags &= ~OCB_CONFIG_FLAG_EXPIRY_TIME_IN_TSF; break; case ETH_MODE: if (value == NULL) { printf("Missing value for suboption '%s'\n", set_chan_opts[ETH_MODE]); break; } if (strtol(value, NULL, 10)) params->flags &= ~OCB_CONFIG_FLAG_80211_FRAME_MODE; else params->flags |= OCB_CONFIG_FLAG_80211_FRAME_MODE; break; default: rc = -1; dsrc_config_usage(); goto bail; } } bail: return rc; } int dsrc_set_config(char *interface, unsigned char num_channels, struct dsrc_channel channels[2], int enable_dcc, unsigned int flags) { dsrc_ocb_config_channel_t chan[2] = { {0} }; dsrc_ocb_config_sched_t sched[2] = { {0} }; dcc_ndl_chan *dcc_chan = NULL; dcc_ndl_active_state_config *state_cfg = NULL; unsigned char num_active_states = 0; unsigned char num_dcc_channels = 0; /* Convert to host driver structs */ chan[0].chan_freq = channels[0].frequency; chan[0].bandwidth = channels[0].bandwidth; chan[0].max_pwr = channels[0].tx_power; chan[0].min_pwr = 6; chan[0].flags = channels[0].flags; sched[0].chan_freq = channels[0].frequency; sched[0].total_duration = channels[0].sched_duration; sched[0].guard_interval = channels[0].sched_guard; chan[0].qos_params[DSRC_OCB_AC_BE].aifsn = channels[0].qos_params[DSRC_OCB_AC_BE].aifsn; chan[0].qos_params[DSRC_OCB_AC_BE].cwmax = channels[0].qos_params[DSRC_OCB_AC_BE].cwmax; chan[0].qos_params[DSRC_OCB_AC_BE].cwmin = channels[0].qos_params[DSRC_OCB_AC_BE].cwmin; chan[0].qos_params[DSRC_OCB_AC_BK].aifsn = channels[0].qos_params[DSRC_OCB_AC_BK].aifsn; chan[0].qos_params[DSRC_OCB_AC_BK].cwmax = channels[0].qos_params[DSRC_OCB_AC_BK].cwmax; chan[0].qos_params[DSRC_OCB_AC_BK].cwmin = channels[0].qos_params[DSRC_OCB_AC_BK].cwmin; chan[0].qos_params[DSRC_OCB_AC_VI].aifsn = channels[0].qos_params[DSRC_OCB_AC_VI].aifsn; chan[0].qos_params[DSRC_OCB_AC_VI].cwmax = channels[0].qos_params[DSRC_OCB_AC_VI].cwmax; chan[0].qos_params[DSRC_OCB_AC_VI].cwmin = channels[0].qos_params[DSRC_OCB_AC_VI].cwmin; chan[0].qos_params[DSRC_OCB_AC_VO].aifsn = channels[0].qos_params[DSRC_OCB_AC_VO].aifsn; chan[0].qos_params[DSRC_OCB_AC_VO].cwmax = channels[0].qos_params[DSRC_OCB_AC_VO].cwmax; chan[0].qos_params[DSRC_OCB_AC_VO].cwmin = channels[0].qos_params[DSRC_OCB_AC_VO].cwmin; chan[1].qos_params[DSRC_OCB_AC_BE].aifsn = channels[1].qos_params[DSRC_OCB_AC_BE].aifsn; chan[1].qos_params[DSRC_OCB_AC_BE].cwmax = channels[1].qos_params[DSRC_OCB_AC_BE].cwmax; chan[1].qos_params[DSRC_OCB_AC_BE].cwmin = channels[1].qos_params[DSRC_OCB_AC_BE].cwmin; chan[1].qos_params[DSRC_OCB_AC_BK].aifsn = channels[1].qos_params[DSRC_OCB_AC_BK].aifsn; chan[1].qos_params[DSRC_OCB_AC_BK].cwmax = channels[1].qos_params[DSRC_OCB_AC_BK].cwmax; chan[1].qos_params[DSRC_OCB_AC_BK].cwmin = channels[1].qos_params[DSRC_OCB_AC_BK].cwmin; chan[1].qos_params[DSRC_OCB_AC_VI].aifsn = channels[1].qos_params[DSRC_OCB_AC_VI].aifsn; chan[1].qos_params[DSRC_OCB_AC_VI].cwmax = channels[1].qos_params[DSRC_OCB_AC_VI].cwmax; chan[1].qos_params[DSRC_OCB_AC_VI].cwmin = channels[1].qos_params[DSRC_OCB_AC_VI].cwmin; chan[1].qos_params[DSRC_OCB_AC_VO].aifsn = channels[1].qos_params[DSRC_OCB_AC_VO].aifsn; chan[1].qos_params[DSRC_OCB_AC_VO].cwmax = channels[1].qos_params[DSRC_OCB_AC_VO].cwmax; chan[1].qos_params[DSRC_OCB_AC_VO].cwmin = channels[1].qos_params[DSRC_OCB_AC_VO].cwmin; chan[1].chan_freq = channels[1].frequency; chan[1].bandwidth = channels[1].bandwidth; chan[1].max_pwr = channels[1].tx_power; chan[1].min_pwr = 6; chan[1].flags = channels[1].flags; sched[1].chan_freq = channels[1].frequency; sched[1].total_duration = channels[1].sched_duration; sched[1].guard_interval = channels[1].sched_guard; /* Get NDL */ if (enable_dcc) { dcc_get_config(&num_dcc_channels, &dcc_chan, &num_active_states, &state_cfg); if (num_dcc_channels < num_channels) { printf("DCC enabled but NDL not provided\n"); return -1; } } /* Pass NDL chan and active states down. */ return dsrc_ocb_set_config(interface, num_channels, chan, dcc_chan, num_channels, sched, num_active_states, state_cfg, flags); } int dsrc_update_ndl(char *interface) { dcc_ndl_chan *dcc_chan; dcc_ndl_active_state_config *state_cfg; unsigned char num_channels, num_active_states; /* Get NDL */ dcc_get_config(&num_channels, &dcc_chan, &num_active_states, &state_cfg); /* Pass NDL chan and active states down. */ return dsrc_ocb_dcc_ndl_update(interface, num_channels, dcc_chan, num_active_states, state_cfg); } int dsrc_get_stats(char *interface, uint32_t chan_freq1, uint32_t chan_freq2) { unsigned int num_channels = 1; dcc_channel_stats_request stats_request[2]; stats_request[0].chan_freq = chan_freq1; stats_request[0].dcc_stats_bitmap = DCC_BITMAP_DEFAULT; if (chan_freq2 != 0) { num_channels = 2; stats_request[1].chan_freq = chan_freq2; stats_request[1].dcc_stats_bitmap = DCC_BITMAP_DEFAULT; } return dsrc_ocb_dcc_get_stats(interface, num_channels, &stats_request[0]); } void dsrc_dcc_stats_event(char *interface) { dsrc_ocb_dcc_stats_event(interface); } int dsrc_clear_stats(char *interface) { return dsrc_ocb_dcc_clear_stats(interface, DCC_BITMAP_DEFAULT); } int dsrc_get_tsf_timer(char *interface) { return dsrc_ocb_get_tsf_timer(interface); } int dsrc_set_utc_time(char *interface) { uint8_t time_value[DSRC_OCB_UTC_TIME_LEN]; uint8_t time_error[DSRC_OCB_UTC_TIME_ERROR_LEN]; /* This is the UTC time in seconds from Jan 1st, 1958 */ uint64_t seconds; uint64_t *time_ptr; /* Time error as sequence of 1s means it is undetermined */ memset(time_error, TIME_ERROR_DEFAULT, DSRC_OCB_UTC_TIME_ERROR_LEN); /* Initialize time value */ memset(time_value, 0, DSRC_OCB_UTC_TIME_LEN); /* UTC time is the number of nanoseconds since Jan 1st 1958 */ seconds = (uint64_t)time(NULL); seconds += SEC_1958_1970; time_ptr = (uint64_t*)time_value; /* UTC time in IEEE spec is set in nanoseconds */ *time_ptr = seconds*1000000; return dsrc_ocb_set_utc_time(interface, time_value, time_error); } int dsrc_start_timing_advert(char *interface, uint32_t chan_freq, uint32_t repeat_rate) { return dsrc_ocb_start_timing_advert(interface, chan_freq, repeat_rate); } int dsrc_stop_timing_advert(char *interface, uint32_t chan_freq) { return dsrc_ocb_stop_timing_advert(interface, chan_freq); } void dsrc_rx_vsa_frames(char *interface) { dsrc_ocb_rx_vsa_frames(interface); } int main(int argc, char **argv) { struct dsrc_config_params params = {0}; int rc = -1; /* Process command line options */ rc = dsrc_config_get_options(argc, argv, ¶ms); if (rc) { goto exit; } /* Parse the channel options */ rc = dsrc_parse_channel_options(¶ms); if (rc) { goto exit; } if (!strcmp(params.cmd, "set_config")) rc = dsrc_set_config(params.interface, params.num_channels, params.channels, params.enable_dcc, params.flags); else if (!strcmp(params.cmd, "set_utc")) rc = dsrc_set_utc_time(params.interface); else if (!strcmp(params.cmd, "start_ta")) rc = dsrc_start_timing_advert(params.interface, params.channels[0].frequency, params.repeat_rate); else if (!strcmp(params.cmd, "stop_ta")) rc = dsrc_stop_timing_advert(params.interface, params.channels[0].frequency); else if (!strcmp(params.cmd, "ndl_update")) rc = dsrc_update_ndl(params.interface); else if (!strcmp(params.cmd, "get_stats")) rc = dsrc_get_stats(params.interface, params.channels[0].frequency, params.channels[1].frequency); else if (!strcmp(params.cmd, "stats_event")) dsrc_dcc_stats_event(params.interface); else if (!strcmp(params.cmd, "clear_stats")) rc = dsrc_clear_stats(params.interface); else if (!strcmp(params.cmd, "get_tsf")) rc = dsrc_get_tsf_timer(params.interface); else if (!strcmp(params.cmd, "rx_vsa")) dsrc_rx_vsa_frames(params.interface); else dsrc_config_usage(); if (rc) { printf("Error executing command, ret=%d\n", rc); } else { printf("Success executing command\n"); } exit: return rc; }