rmnetcfg: Initial commit

RmNet configuration library and command line utility for configuring
the RmNet Data kernel module.

CRs-Fixed: 525675
Acked-by: Subash Abhinov Kasiviswanathan <subashab@qti.qualcomm.com>
Change-Id: I4c15e2f0e32082077c189cf316f845699aef5f13
diff --git a/rmnetctl/cli/Android.mk b/rmnetctl/cli/Android.mk
new file mode 100644
index 0000000..27281ff
--- /dev/null
+++ b/rmnetctl/cli/Android.mk
@@ -0,0 +1,16 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := rmnetcli.c
+LOCAL_CFLAGS := -Wall -Werror
+
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/../inc
+LOCAL_C_INCLUDES += $(LOCAL_PATH)/../src
+LOCAL_C_INCLUDES += $(LOCAL_PATH)
+
+LOCAL_MODULE := rmnetcli
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SHARED_LIBRARIES := librmnetctl
+include $(BUILD_EXECUTABLE)
diff --git a/rmnetctl/cli/rmnetcli.c b/rmnetctl/cli/rmnetcli.c
new file mode 100644
index 0000000..2c4d099
--- /dev/null
+++ b/rmnetctl/cli/rmnetcli.c
@@ -0,0 +1,352 @@
+/******************************************************************************
+
+			R M N E T C L I . C
+
+Copyright (c) 2013, 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.
+
+******************************************************************************/
+
+/******************************************************************************
+
+  @file    rmnetcli.c
+  @brief   command line interface to expose rmnet control API's
+
+  DESCRIPTION
+  File containing implementation of the command line interface to expose the
+  rmnet control configuration .
+
+******************************************************************************/
+
+/*===========================================================================
+				INCLUDE FILES
+===========================================================================*/
+
+#include <sys/socket.h>
+#include <stdint.h>
+#include <linux/netlink.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include "rmnetcli.h"
+#include "librmnetctl.h"
+
+#define RMNET_MAX_STR_LEN  16
+
+#define _RMNETCLI_CHECKNULL(X)		do { if (!X) {                         \
+print_rmnet_api_status(RMNETCTL_INVALID_ARG, RMNETCTL_CFG_FAILURE_NO_COMMAND); \
+				rmnetctl_cleanup(handle);                      \
+				return RMNETCTL_INVALID_ARG;                   \
+		} } while (0);
+#define _STRTOUI32(X)           (uint32_t)strtoul(X, NULL, 0)
+#define _STRTOUI16(X)           (uint16_t)strtoul(X, NULL, 0)
+#define _STRTOUI8(X)           (uint8_t)strtoul(X, NULL, 0)
+#define _STRTOI32(X)           (int32_t)strtol(X, NULL, 0)
+
+#define _5TABS 		"\n\t\t\t\t\t"
+#define _2TABS 		"\n\t\t"
+
+/*!
+* @brief Contains a list of error message from CLI
+*/
+char rmnetcfg_error_code_text
+[RMNETCFG_TOTAL_ERR_MSGS][RMNETCTL_ERR_MSG_SIZE] = {
+	"Help option Specified",
+	"ERROR: No\\Invalid command was specified\n",
+	"ERROR: Could not allocate buffer for Egress device\n"
+};
+
+/*!
+* @brief Method to display the syntax for the commands
+* @details Displays the syntax and usage for the commands
+* @param void
+* @return void
+*/
+static void rmnet_api_usage()
+{
+	printf("RmNet API Usage:\n\n");
+	printf("rmnetcli help                            Displays this help\n");
+	printf("\n");
+	printf("rmnetcli assocnetdev <dev_name>          Registers the RmNet");
+	printf(_5TABS" data driver on a particular");
+	printf(_5TABS" device.dev_name cannot");
+	printf(_5TABS" be larger than 15");
+	printf(_5TABS" characters. Returns");
+	printf(_5TABS" the status code.\n\n");
+	printf("rmnetcli unassocnetdev <dev_name>        Unregisters the");
+	printf(_5TABS" RmNet data driver on a particular");
+	printf(_5TABS" device. dev_name cannot");
+	printf(_5TABS" be larger than 15");
+	printf(_5TABS" characters. Returns");
+	printf(_5TABS" the status code.\n\n");
+	printf("rmnetcli getnetdevassoc <dev_name>       Get if the RmNet");
+	printf(_5TABS" data driver is registered on");
+	printf(_5TABS" a particular device.");
+	printf(_5TABS" dev_name cannot be");
+	printf(_5TABS" larger than 15");
+	printf(_5TABS" characters. Returns 1");
+	printf(_5TABS" if is registered and");
+	printf(_5TABS" 0 if it is not");
+	printf(_5TABS" registered\n\n");
+	printf("rmnetcli setledf <egress_flags>          Sets the egress data");
+	printf(_2TABS" <agg_size>              format for a particular link.");
+	printf(_2TABS" <agg_count>             dev_name cannot be larger");
+	printf(_2TABS" <dev_name>              than 15 characters.");
+	printf(_5TABS" Returns the status code\n\n");
+	printf("rmnetcli getledf <dev_name>              Gets the egress data");
+	printf(_5TABS" format for a particular link.");
+	printf(_5TABS" dev_name cannot be larger");
+	printf(_5TABS" than 15. Returns the 4");
+	printf(_5TABS" byte unsigned integer");
+	printf(_5TABS" egress_flags\n\n");
+	printf("rmnetcli setlidf <ingress_flags>         Sets the ingress");
+	printf(_2TABS" <dev_name>              data format for a particular");
+	printf(_5TABS" link. egress_flags is 4");
+	printf(_5TABS" byte unsigned integer.");
+	printf(_5TABS" dev_name cannot be");
+	printf(_5TABS" larger than 15.");
+	printf(_5TABS" characters. Returns");
+	printf(_5TABS" the status code\n\n");
+	printf("rmnetcli getlidf <dev_name>              Gets the ingress");
+	printf(_5TABS" data format for a particular");
+	printf(_5TABS" link. dev_name cannot be");
+	printf(_5TABS" larger than 15. Returns");
+	printf(_5TABS" the 4 byte unsigned");
+	printf(_5TABS" integer ingress_flags\n\n");
+	printf("rmnetcli setlepc <logical_ep_id>         Sets the logical");
+	printf(_2TABS" <rmnet_mode>            endpoint configuration for");
+	printf(_2TABS" <dev_name>              a particular link.");
+	printf(_2TABS" <egress_dev_name>       logical_ep_id are 32bit");
+	printf(_5TABS" integers from -1 to 31.");
+	printf(_5TABS" rmnet_mode is a 1 byte");
+	printf(_5TABS" unsigned integer of");
+	printf(_5TABS" value none, vnd or");
+	printf(_5TABS" bridged. dev_name");
+	printf(_5TABS" and egress_dev_name");
+	printf(_5TABS" cannot be larger");
+	printf(_5TABS" than 15 tcharacters");
+	printf(_5TABS" Returns the status code\n\n");
+	printf("rmnetcli getlepc <logical_ep_id>         Sets the logical");
+	printf(_2TABS" <dev_name>              enpoint configuration for a");
+	printf(_5TABS" particular link.");
+	printf(_5TABS" logical_ep_id are 32bit");
+	printf(_5TABS" integers from -1 to 31.");
+	printf(_5TABS" Returns the rmnet_mode");
+	printf(_5TABS" and egress_dev_name.");
+	printf(_5TABS" rmnet_mode is a 1");
+	printf(_5TABS" byte unsigned integer");
+	printf(_5TABS" of value none, vnd or");
+	printf(_5TABS" bridged. dev_name and");
+	printf(_5TABS" egress_dev_name cannot be");
+	printf(_5TABS" larger than 15 ");
+	printf(_5TABS" characters. Returns the");
+	printf(_5TABS" status code\n\n");
+	printf("rmnetcli newvnd <dev_name>               Creates a new");
+	printf(_5TABS" virtual network device node.");
+	printf(_5TABS" dev_name cannot be");
+	printf(_5TABS" larger than 15. Returns");
+	printf(_5TABS" the status code\n\n");
+	printf("rmnetcli freevnd <dev_name>              Removes virtual");
+	printf(_5TABS" network device node. dev_name");
+	printf(_5TABS" cannot be larger than 15.");
+	printf(_5TABS" Returns the status code\n\n");
+}
+
+static void print_rmnetctl_lib_errors(uint16_t error_number)  {
+	if ((error_number > RMNETCTL_API_SUCCESS) &&
+		(error_number < RMNETCTL_API_ERR_ENUM_LENGTH)) {
+		printf("%s", rmnetctl_error_code_text[error_number]);
+	}
+	if ((error_number >= RMNETCFG_ERR_NUM_START) &&
+	(error_number < RMNETCFG_ERR_NUM_START + RMNETCFG_TOTAL_ERR_MSGS)) {
+		printf("%s", rmnetcfg_error_code_text
+			[error_number - RMNETCFG_ERR_NUM_START]);
+		if ((error_number == RMNETCTL_CFG_SUCCESS_HELP_COMMAND) ||
+			(error_number == RMNETCTL_CFG_FAILURE_NO_COMMAND))
+			rmnet_api_usage();
+	}
+}
+
+/*!
+* @brief Method to check the error numbers generated from API calls
+* @details Displays the error messages based on each error code
+* @param error_number Error number returned from the API and the CLI
+* @return void
+*/
+static void print_rmnet_api_status(int return_code, uint16_t error_number)
+{
+	if (return_code == RMNETCTL_SUCCESS)
+		printf("SUCCESS\n");
+	else if (return_code == RMNETCTL_LIB_ERR)
+		printf("LIBRARY ");
+	else if (return_code == RMNETCTL_KERNEL_ERR)
+		printf("KERNEL : Error code %u\n", error_number);
+	else if (return_code == RMNETCTL_INVALID_ARG)
+		printf("INVALID_ARG\n");
+
+	if (return_code == RMNETCTL_LIB_ERR) {
+		print_rmnetctl_lib_errors(error_number);
+	}
+}
+
+/*!
+* @brief Method to make the API calls
+* @details Checks for each type of parameter and calls the appropriate
+* function based on the number of parameters and paramter type
+* @param argc Number of arguments which vary based on the commands
+* @param argv Value of the arguments which vary based on the commands
+* @return RMNETCTL_SUCCESS if successful. Relevant data might be printed
+* based on the message type
+* @return RMNETCTL_LIB_ERR if there was a library error. Error code will be
+* printed
+* @return RMNETCTL_KERNEL_ERR if there was a error in the kernel. Error code will be
+* printed
+* @return RMNETCTL_INVALID_ARG if invalid arguments were passed to the API
+*/
+
+static int rmnet_api_call(int argc, char *argv[])
+{
+	struct rmnetctl_hndl_s *handle = NULL;
+	uint16_t error_number = RMNETCTL_CFG_FAILURE_NO_COMMAND;
+	int return_code = RMNETCTL_LIB_ERR;
+	if ((!argc) || (!*argv)) {
+		print_rmnet_api_status(RMNETCTL_LIB_ERR,
+		RMNETCTL_CFG_FAILURE_NO_COMMAND);
+		return RMNETCTL_LIB_ERR;
+	}
+	if (!strcmp(*argv, "help")) {
+		print_rmnet_api_status(RMNETCTL_LIB_ERR,
+		RMNETCTL_CFG_SUCCESS_HELP_COMMAND);
+		return RMNETCTL_LIB_ERR;
+	}
+	return_code = rmnetctl_init(&handle, &error_number);
+	if (return_code!= RMNETCTL_SUCCESS) {
+		print_rmnet_api_status(return_code, error_number);
+		return RMNETCTL_LIB_ERR;
+	}
+	error_number = RMNETCTL_CFG_FAILURE_NO_COMMAND;
+	return_code = RMNETCTL_LIB_ERR;
+	if (!strcmp(*argv, "assocnetdev")) {
+		return_code = rmnet_associate_network_device(handle,
+		argv[1], &error_number, RMNETCTL_DEVICE_ASSOCIATE);
+	} else if (!strcmp(*argv, "unassocnetdev")) {
+		return_code = rmnet_associate_network_device(handle,
+		argv[1], &error_number, RMNETCTL_DEVICE_UNASSOCIATE);
+	} else if (!strcmp(*argv, "getnetdevassoc")) {
+		int register_status;
+		return_code = rmnet_get_network_device_associated(handle,
+		argv[1], &register_status, &error_number);
+		if (return_code == RMNETCTL_SUCCESS)
+			printf("register_status is %d\n", register_status);
+	} else if (!strcmp(*argv, "getledf")) {
+		uint32_t egress_flags;
+		uint16_t agg_size, agg_count;
+		return_code = rmnet_get_link_egress_data_format(handle,
+		argv[1], &egress_flags, &agg_size, &agg_count, &error_number);
+		if (return_code == RMNETCTL_SUCCESS) {
+			printf("egress_flags is %u\n", egress_flags);
+			printf("agg_size is %u\n", agg_size);
+			printf("agg_count is %u\n", agg_count);
+		}
+	} else if (!strcmp(*argv, "getlidf")) {
+		uint32_t ingress_flags;
+		return_code = rmnet_get_link_ingress_data_format(handle,
+		argv[1], &ingress_flags, &error_number);
+		if (return_code == RMNETCTL_SUCCESS) {
+			printf("ingress_flags is %u\n", ingress_flags);
+		}
+	} else if (!strcmp(*argv, "newvnd")) {
+		_RMNETCLI_CHECKNULL(argv[1]);
+		return_code = rmnet_new_vnd(handle,
+		_STRTOUI32(argv[1]), &error_number, RMNETCTL_NEW_VND);
+	} else if (!strcmp(*argv, "freevnd")) {
+		_RMNETCLI_CHECKNULL(argv[1]);
+		return_code = rmnet_new_vnd(handle,
+		_STRTOUI32(argv[1]), &error_number, RMNETCTL_FREE_VND);
+	} else if (!strcmp(*argv, "setlidf")) {
+		_RMNETCLI_CHECKNULL(argv[1]);
+		return_code = rmnet_set_link_ingress_data_format(handle,
+		_STRTOUI32(argv[1]), argv[2], &error_number);
+	} else if (!strcmp(*argv, "getlepc")) {
+		_RMNETCLI_CHECKNULL(argv[1]);
+		uint8_t rmnet_mode;
+		char *egress_dev_name;
+		egress_dev_name = NULL;
+		egress_dev_name = (char *)malloc(RMNET_MAX_STR_LEN
+		* sizeof(char));
+		if (!egress_dev_name) {
+			print_rmnet_api_status(RMNETCTL_LIB_ERR,
+			RMNETCTL_CFG_FAILURE_EGRESS_DEV_NAME_NULL);
+			return RMNETCTL_LIB_ERR;
+		}
+		return_code = rmnet_get_logical_ep_config(handle,
+		_STRTOI32(argv[1]), argv[2], &rmnet_mode,
+		&egress_dev_name, &error_number);
+		if (return_code == RMNETCTL_SUCCESS) {
+			printf("rmnet_mode is %u\n", rmnet_mode);
+			printf("egress_dev_name is %s\n", egress_dev_name);
+		}
+	} else if (!strcmp(*argv, "setledf")) {
+		_RMNETCLI_CHECKNULL(argv[1]);
+		_RMNETCLI_CHECKNULL(argv[2]);
+		_RMNETCLI_CHECKNULL(argv[3]);
+		return_code = rmnet_set_link_egress_data_format(handle,
+		_STRTOUI32(argv[1]), _STRTOUI16(argv[2]), _STRTOUI16(argv[3]),
+		argv[4], &error_number);
+	} else if (!strcmp(*argv, "setlepc")) {
+		_RMNETCLI_CHECKNULL(argv[1]);
+		_RMNETCLI_CHECKNULL(argv[2]);
+		return_code = rmnet_set_logical_ep_config(handle,
+		_STRTOI32(argv[1]), _STRTOUI8(argv[2]), argv[3], argv[4],
+		&error_number);
+	}
+	print_rmnet_api_status(return_code, error_number);
+	rmnetctl_cleanup(handle);
+	return return_code;
+}
+
+/*!
+* @brief Method which serves as en entry point to the rmnetcli function
+* @details Entry point for the RmNet Netlink API. This is the command line
+* interface for the RmNet API
+* @param argc Number of arguments which vary based on the commands
+* @param argv Value of the arguments which vary based on the commands
+* @return RMNETCTL_SUCCESS if successful. Relevant data might be printed
+* based on the message type
+* @return RMNETCTL_LIB_ERR if there was a library error. Error code will be
+* printed
+* @return RMNETCTL_KERNEL_ERR if there was a error in the kernel. Error code will be
+* printed
+* @return RMNETCTL_INVALID_ARG if invalid arguments were passed to the API
+*/
+int main(int argc, char *argv[])
+{
+	argc--;
+	argv++;
+	return rmnet_api_call(argc, argv);
+}
diff --git a/rmnetctl/cli/rmnetcli.h b/rmnetctl/cli/rmnetcli.h
new file mode 100644
index 0000000..503a86e
--- /dev/null
+++ b/rmnetctl/cli/rmnetcli.h
@@ -0,0 +1,61 @@
+/******************************************************************************
+
+			  R M N E T C L I . H
+
+Copyright (c) 2013, 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.
+
+******************************************************************************/
+
+/******************************************************************************
+
+  @file	   rmnetcli.h
+  @brief   headers for the command line interface to expose rmnet control API's
+
+  DESCRIPTION
+  Header file containing definition for the command line interface to expose
+  rmnet control API's
+
+******************************************************************************/
+
+#ifndef RMNETCLI_H
+#define RMNETCLI_H
+
+/* Print the help for the commands since the help flag was used. */
+#define RMNETCTL_CFG_SUCCESS_HELP_COMMAND 100
+/* No/invalid API call was specified. So return an error. */
+#define RMNETCTL_CFG_FAILURE_NO_COMMAND 101
+/* The buffer for egress device name was NULL */
+#define RMNETCTL_CFG_FAILURE_EGRESS_DEV_NAME_NULL 102
+
+/* This should always be the value of the starting element */
+#define RMNETCFG_ERR_NUM_START 100
+
+/* This should always be the total number of error message from CLI */
+#define RMNETCFG_TOTAL_ERR_MSGS 3
+
+#endif /* not defined RMNETCLI_H */