1 /******************************************************************************
2 
3 			R M N E T C L I . C
4 
5 Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
6 
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are
9 met:
10 	* Redistributions of source code must retain the above copyright
11 	  notice, this list of conditions and the following disclaimer.
12 	* Redistributions in binary form must reproduce the above
13 	  copyright notice, this list of conditions and the following
14 	  disclaimer in the documentation and/or other materials provided
15 	  with the distribution.
16 	* Neither the name of The Linux Foundation nor the names of its
17 	  contributors may be used to endorse or promote products derived
18 	  from this software without specific prior written permission.
19 
20 THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
21 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
22 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
23 ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
24 BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
27 BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
29 OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
30 IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 
32 ******************************************************************************/
33 
34 /******************************************************************************
35 
36   @file    rmnetcli.c
37   @brief   command line interface to expose rmnet control API's
38 
39   DESCRIPTION
40   File containing implementation of the command line interface to expose the
41   rmnet control configuration .
42 
43 ******************************************************************************/
44 
45 /*===========================================================================
46 				INCLUDE FILES
47 ===========================================================================*/
48 
49 #include <sys/socket.h>
50 #include <stdint.h>
51 #include <linux/netlink.h>
52 #include <string.h>
53 #include <stdio.h>
54 #include <unistd.h>
55 #include <stdlib.h>
56 #include "rmnetcli.h"
57 #include "librmnetctl.h"
58 
59 #define RMNET_MAX_STR_LEN  16
60 
61 #define _RMNETCLI_CHECKNULL(X)		do { if (!X) {                         \
62 print_rmnet_api_status(RMNETCTL_INVALID_ARG, RMNETCTL_CFG_FAILURE_NO_COMMAND); \
63 				rmnetctl_cleanup(handle);                      \
64 				return RMNETCTL_INVALID_ARG;                   \
65 		} } while (0);
66 #define _STRTOUI32(X)           (uint32_t)strtoul(X, NULL, 0)
67 #define _STRTOUI16(X)           (uint16_t)strtoul(X, NULL, 0)
68 #define _STRTOUI8(X)           (uint8_t)strtoul(X, NULL, 0)
69 #define _STRTOI32(X)           (int32_t)strtol(X, NULL, 0)
70 
71 #define _5TABS 		"\n\t\t\t\t\t"
72 #define _2TABS 		"\n\t\t"
73 
74 /*!
75 * @brief Contains a list of error message from CLI
76 */
77 char rmnetcfg_error_code_text
78 [RMNETCFG_TOTAL_ERR_MSGS][RMNETCTL_ERR_MSG_SIZE] = {
79 	"Help option Specified",
80 	"ERROR: No\\Invalid command was specified\n",
81 	"ERROR: Could not allocate buffer for Egress device\n"
82 };
83 
84 /*!
85 * @brief Method to display the syntax for the commands
86 * @details Displays the syntax and usage for the commands
87 * @param void
88 * @return void
89 */
rmnet_api_usage(void)90 static void rmnet_api_usage(void)
91 {
92 	printf("RmNet API Usage:\n\n");
93 	printf("rmnetcli help                            Displays this help\n");
94 	printf("\n");
95 	printf("rmnetcli assocnetdev <dev_name>          Registers the RmNet");
96 	printf(_5TABS" data driver on a particular");
97 	printf(_5TABS" device.dev_name cannot");
98 	printf(_5TABS" be larger than 15");
99 	printf(_5TABS" characters. Returns");
100 	printf(_5TABS" the status code.\n\n");
101 	printf("rmnetcli unassocnetdev <dev_name>        Unregisters the");
102 	printf(_5TABS" RmNet data driver on a particular");
103 	printf(_5TABS" device. dev_name cannot");
104 	printf(_5TABS" be larger than 15");
105 	printf(_5TABS" characters. Returns");
106 	printf(_5TABS" the status code.\n\n");
107 	printf("rmnetcli getnetdevassoc <dev_name>       Get if the RmNet");
108 	printf(_5TABS" data driver is registered on");
109 	printf(_5TABS" a particular device.");
110 	printf(_5TABS" dev_name cannot be");
111 	printf(_5TABS" larger than 15");
112 	printf(_5TABS" characters. Returns 1");
113 	printf(_5TABS" if is registered and");
114 	printf(_5TABS" 0 if it is not");
115 	printf(_5TABS" registered\n\n");
116 	printf("rmnetcli setledf <egress_flags>          Sets the egress data");
117 	printf(_2TABS" <agg_size>              format for a particular link.");
118 	printf(_2TABS" <agg_count>             dev_name cannot be larger");
119 	printf(_2TABS" <dev_name>              than 15 characters.");
120 	printf(_5TABS" Returns the status code\n\n");
121 	printf("rmnetcli getledf <dev_name>              Gets the egress data");
122 	printf(_5TABS" format for a particular link.");
123 	printf(_5TABS" dev_name cannot be larger");
124 	printf(_5TABS" than 15. Returns the 4");
125 	printf(_5TABS" byte unsigned integer");
126 	printf(_5TABS" egress_flags\n\n");
127 	printf("rmnetcli setlidf <ingress_flags>         Sets the ingress");
128 	printf(_2TABS" <tail_spacing>          data format for a particular");
129 	printf(_2TABS" <dev_name>              link. ingress_flags is 4");
130 	printf(_5TABS" byte unsigned integer.");
131 	printf(_5TABS" tail_spacing is a one.");
132 	printf(_5TABS" byte unsigned integer.");
133 	printf(_5TABS" dev_name cannot be");
134 	printf(_5TABS" larger than 15.");
135 	printf(_5TABS" characters. Returns");
136 	printf(_5TABS" the status code\n\n");
137 	printf("rmnetcli getlidf <dev_name>              Gets the ingress");
138 	printf(_5TABS" data format for a particular");
139 	printf(_5TABS" link. dev_name cannot be");
140 	printf(_5TABS" larger than 15. Returns");
141 	printf(_5TABS" the 4 byte unsigned");
142 	printf(_5TABS" integer ingress_flags\n\n");
143 	printf("rmnetcli setlepc <logical_ep_id>         Sets the logical");
144 	printf(_2TABS" <rmnet_mode>            endpoint configuration for");
145 	printf(_2TABS" <dev_name>              a particular link.");
146 	printf(_2TABS" <egress_dev_name>       logical_ep_id are 32bit");
147 	printf(_5TABS" integers from -1 to 31.");
148 	printf(_5TABS" rmnet_mode is a 1 byte");
149 	printf(_5TABS" unsigned integer of");
150 	printf(_5TABS" value none, vnd or");
151 	printf(_5TABS" bridged. dev_name");
152 	printf(_5TABS" and egress_dev_name");
153 	printf(_5TABS" cannot be larger");
154 	printf(_5TABS" than 15 tcharacters");
155 	printf(_5TABS" Returns the status code\n\n");
156 	printf("rmnetcli unsetlepc <logical_ep_id>       Un-sets the logical");
157 	printf(_2TABS"  <dev_name>              endpoint configuration for");
158 	printf(_5TABS" a particular link.");
159 	printf(_5TABS" integers from -1 to 31.");
160 	printf(_5TABS" dev_name cannot be larger");
161 	printf(_5TABS" than 15 tcharacters");
162 	printf(_5TABS" Returns the status code\n\n");
163 	printf("rmnetcli getlepc <logical_ep_id>         Sets the logical");
164 	printf(_2TABS" <dev_name>              enpoint configuration for a");
165 	printf(_5TABS" particular link.");
166 	printf(_5TABS" logical_ep_id are 32bit");
167 	printf(_5TABS" integers from -1 to 31.");
168 	printf(_5TABS" Returns the rmnet_mode");
169 	printf(_5TABS" and egress_dev_name.");
170 	printf(_5TABS" rmnet_mode is a 1");
171 	printf(_5TABS" byte unsigned integer");
172 	printf(_5TABS" of value none, vnd or");
173 	printf(_5TABS" bridged. dev_name and");
174 	printf(_5TABS" egress_dev_name cannot be");
175 	printf(_5TABS" larger than 15 ");
176 	printf(_5TABS" characters. Returns the");
177 	printf(_5TABS" status code\n\n");
178 	printf("rmnetcli newvnd <dev_id>                 Creates a new");
179 	printf(_5TABS" virtual network device node.");
180 	printf(_5TABS" dev_id is an int");
181 	printf(_5TABS" less than 32. Returns");
182 	printf(_5TABS" the status code\n\n");
183 	printf("rmnetcli newvndprefix <dev_id> <name_prefix>   Creates");
184 	printf(_5TABS" virtual network device node.");
185 	printf(_5TABS" dev_id is an int");
186 	printf(_5TABS" less than 32. Prefix");
187 	printf(_5TABS" must be less than");
188 	printf(_5TABS" 15 chars. Returns");
189 	printf(_5TABS" the status code\n\n");
190 	printf("rmnetcli getvndname <dev_id>              Get name of");
191 	printf(_5TABS" network device node from id\n\n");
192 	printf("rmnetcli freevnd <dev_id>              Removes virtual");
193 	printf(_5TABS" network device node. dev_name");
194 	printf(_5TABS" cannot be larger than 15.");
195 	printf(_5TABS" Returns the status code\n\n");
196 	printf("rmnetcli addvnctcflow <dev_id>            Add a modem flow");
197 	printf(_2TABS" <mdm_flow_hndl>         handle - tc flow handle");
198 	printf(_2TABS" <tc_flow_hndl>          mapping for a virtual network");
199 	printf(_2TABS" device node\n\n");
200 	printf("rmnetcli delvnctcflow <dev_id>            Delete a modem flow");
201 	printf(_2TABS" <mdm_flow_hndl>         handle - tc flow handle");
202 	printf(_2TABS" <tc_flow_hndl>          mapping for a virtual network");
203 	printf(_2TABS" device node\n\n");
204 }
205 
print_rmnetctl_lib_errors(uint16_t error_number)206 static void print_rmnetctl_lib_errors(uint16_t error_number)
207 {
208 	if ((error_number > RMNETCTL_API_SUCCESS) &&
209 		(error_number < RMNETCTL_API_ERR_ENUM_LENGTH)) {
210 		printf("%s", rmnetctl_error_code_text[error_number]);
211 	}
212 	if ((error_number >= RMNETCFG_ERR_NUM_START) &&
213 	(error_number < RMNETCFG_ERR_NUM_START + RMNETCFG_TOTAL_ERR_MSGS)) {
214 		printf("%s", rmnetcfg_error_code_text
215 			[error_number - RMNETCFG_ERR_NUM_START]);
216 		if ((error_number == RMNETCTL_CFG_SUCCESS_HELP_COMMAND) ||
217 			(error_number == RMNETCTL_CFG_FAILURE_NO_COMMAND))
218 			rmnet_api_usage();
219 	}
220 }
221 
222 /*!
223 * @brief Method to check the error numbers generated from API calls
224 * @details Displays the error messages based on each error code
225 * @param error_number Error number returned from the API and the CLI
226 * @return void
227 */
print_rmnet_api_status(int return_code,uint16_t error_number)228 static void print_rmnet_api_status(int return_code, uint16_t error_number)
229 {
230 	if (return_code == RMNETCTL_SUCCESS)
231 		printf("SUCCESS\n");
232 	else if (return_code == RMNETCTL_LIB_ERR) {
233 		printf("LIBRARY ");
234 		print_rmnetctl_lib_errors(error_number);
235 	} else if (return_code == RMNETCTL_KERNEL_ERR)
236 		printf("KERNEL %s", rmnetctl_error_code_text[error_number]);
237 	else if (return_code == RMNETCTL_INVALID_ARG)
238 		printf("INVALID_ARG\n");
239 }
240 
241 /*!
242 * @brief Method to make the API calls
243 * @details Checks for each type of parameter and calls the appropriate
244 * function based on the number of parameters and paramter type
245 * @param argc Number of arguments which vary based on the commands
246 * @param argv Value of the arguments which vary based on the commands
247 * @return RMNETCTL_SUCCESS if successful. Relevant data might be printed
248 * based on the message type
249 * @return RMNETCTL_LIB_ERR if there was a library error. Error code will be
250 * printed
251 * @return RMNETCTL_KERNEL_ERR if there was a error in the kernel. Error code will be
252 * printed
253 * @return RMNETCTL_INVALID_ARG if invalid arguments were passed to the API
254 */
255 
rmnet_api_call(int argc,char * argv[])256 static int rmnet_api_call(int argc, char *argv[])
257 {
258 	struct rmnetctl_hndl_s *handle = NULL;
259 	uint16_t error_number = RMNETCTL_CFG_FAILURE_NO_COMMAND;
260 	int return_code = RMNETCTL_LIB_ERR;
261 	if ((!argc) || (!*argv)) {
262 		print_rmnet_api_status(RMNETCTL_LIB_ERR,
263 		RMNETCTL_CFG_FAILURE_NO_COMMAND);
264 		return RMNETCTL_LIB_ERR;
265 	}
266 	if (!strcmp(*argv, "help")) {
267 		print_rmnet_api_status(RMNETCTL_LIB_ERR,
268 		RMNETCTL_CFG_SUCCESS_HELP_COMMAND);
269 		return RMNETCTL_LIB_ERR;
270 	}
271 	return_code = rmnetctl_init(&handle, &error_number);
272 	if (return_code!= RMNETCTL_SUCCESS) {
273 		print_rmnet_api_status(return_code, error_number);
274 		return RMNETCTL_LIB_ERR;
275 	}
276 	error_number = RMNETCTL_CFG_FAILURE_NO_COMMAND;
277 	return_code = RMNETCTL_LIB_ERR;
278 	if (!strcmp(*argv, "assocnetdev")) {
279 		return_code = rmnet_associate_network_device(handle,
280 		argv[1], &error_number, RMNETCTL_DEVICE_ASSOCIATE);
281 	} else if (!strcmp(*argv, "unassocnetdev")) {
282 		return_code = rmnet_associate_network_device(handle,
283 		argv[1], &error_number, RMNETCTL_DEVICE_UNASSOCIATE);
284 	} else if (!strcmp(*argv, "getnetdevassoc")) {
285 		int register_status;
286 		return_code = rmnet_get_network_device_associated(handle,
287 		argv[1], &register_status, &error_number);
288 		if (return_code == RMNETCTL_SUCCESS)
289 			printf("register_status is %d\n", register_status);
290 	} else if (!strcmp(*argv, "getledf")) {
291 		uint32_t egress_flags;
292 		uint16_t agg_size, agg_count;
293 		return_code = rmnet_get_link_egress_data_format(handle,
294 		argv[1], &egress_flags, &agg_size, &agg_count, &error_number);
295 		if (return_code == RMNETCTL_SUCCESS) {
296 			printf("egress_flags is %u\n", egress_flags);
297 			printf("agg_size is %u\n", agg_size);
298 			printf("agg_count is %u\n", agg_count);
299 		}
300 	} else if (!strcmp(*argv, "getlidf")) {
301 		uint32_t ingress_flags;
302 		uint8_t  tail_spacing;
303 		return_code = rmnet_get_link_ingress_data_format_tailspace(
304 		handle, argv[1], &ingress_flags, &tail_spacing, &error_number);
305 		if (return_code == RMNETCTL_SUCCESS) {
306 			printf("ingress_flags is %u\n", ingress_flags);
307 			printf("tail_spacing is %u\n", tail_spacing);
308 		}
309 	} else if (!strcmp(*argv, "newvndprefix")) {
310 		_RMNETCLI_CHECKNULL(argv[1]);
311 		_RMNETCLI_CHECKNULL(argv[2]);
312 		return_code = rmnet_new_vnd_prefix(handle,
313 		_STRTOUI32(argv[1]), &error_number, RMNETCTL_NEW_VND, argv[2]);
314 	} else if (!strcmp(*argv, "newvnd")) {
315 		_RMNETCLI_CHECKNULL(argv[1]);
316 		return_code = rmnet_new_vnd(handle,
317 		_STRTOUI32(argv[1]), &error_number, RMNETCTL_NEW_VND);
318 	} else if (!strcmp(*argv, "getvndname")) {
319 		char buffer[32];
320 		memset(buffer, 0, 32);
321 		_RMNETCLI_CHECKNULL(argv[1]);
322 		return_code = rmnet_get_vnd_name(handle, _STRTOUI32(argv[1]),
323 			           &error_number, buffer, 32);
324 		if (return_code == RMNETCTL_SUCCESS) {
325 			printf("VND name: %s\n", buffer);
326 		}
327 	} else if (!strcmp(*argv, "freevnd")) {
328 		_RMNETCLI_CHECKNULL(argv[1]);
329 		return_code = rmnet_new_vnd(handle,
330 		_STRTOUI32(argv[1]), &error_number, RMNETCTL_FREE_VND);
331 	} else if (!strcmp(*argv, "setlidf")) {
332 		_RMNETCLI_CHECKNULL(argv[1]);
333 		_RMNETCLI_CHECKNULL(argv[2]);
334 		_RMNETCLI_CHECKNULL(argv[3]);
335 		return_code = rmnet_set_link_ingress_data_format_tailspace(
336 		handle, _STRTOUI32(argv[1]), _STRTOUI8(argv[2]), argv[3],
337 		&error_number);
338 	} else if (!strcmp(*argv, "delvnctcflow")) {
339 		_RMNETCLI_CHECKNULL(argv[1]);
340 		_RMNETCLI_CHECKNULL(argv[2]);
341 		_RMNETCLI_CHECKNULL(argv[3]);
342 		return_code = rmnet_add_del_vnd_tc_flow(handle,
343 		_STRTOUI32(argv[1]), _STRTOUI32(argv[2]), _STRTOUI32(argv[3]),
344 		RMNETCTL_DEL_FLOW, &error_number);
345 	} else if (!strcmp(*argv, "getlepc")) {
346 		_RMNETCLI_CHECKNULL(argv[1]);
347 		uint8_t rmnet_mode;
348 		char *egress_dev_name;
349 		egress_dev_name = NULL;
350 		egress_dev_name = (char *)malloc(RMNET_MAX_STR_LEN
351 		* sizeof(char));
352 		if (!egress_dev_name) {
353 			print_rmnet_api_status(RMNETCTL_LIB_ERR,
354 			RMNETCTL_CFG_FAILURE_EGRESS_DEV_NAME_NULL);
355 			rmnetctl_cleanup(handle);
356 			return RMNETCTL_LIB_ERR;
357 		}
358 		return_code = rmnet_get_logical_ep_config(handle,
359 		_STRTOI32(argv[1]), argv[2], &rmnet_mode,
360 		&egress_dev_name, RMNET_MAX_STR_LEN, &error_number);
361 		if (return_code == RMNETCTL_SUCCESS) {
362 			printf("rmnet_mode is %u\n", rmnet_mode);
363 			printf("egress_dev_name is %s\n", egress_dev_name);
364 		}
365 		free(egress_dev_name);
366 	} else if (!strcmp(*argv, "addvnctcflow")) {
367 		_RMNETCLI_CHECKNULL(argv[1]);
368 		_RMNETCLI_CHECKNULL(argv[2]);
369 		_RMNETCLI_CHECKNULL(argv[3]);
370 		return_code = rmnet_add_del_vnd_tc_flow(handle,
371 		_STRTOUI32(argv[1]), _STRTOUI32(argv[2]), _STRTOUI32(argv[3]),
372 		RMNETCTL_ADD_FLOW, &error_number);
373 	} else if (!strcmp(*argv, "setledf")) {
374 		_RMNETCLI_CHECKNULL(argv[1]);
375 		_RMNETCLI_CHECKNULL(argv[2]);
376 		_RMNETCLI_CHECKNULL(argv[3]);
377 		return_code = rmnet_set_link_egress_data_format(handle,
378 		_STRTOUI32(argv[1]), _STRTOUI16(argv[2]), _STRTOUI16(argv[3]),
379 		argv[4], &error_number);
380 	} else if (!strcmp(*argv, "setlepc")) {
381 		_RMNETCLI_CHECKNULL(argv[1]);
382 		_RMNETCLI_CHECKNULL(argv[2]);
383 		return_code = rmnet_set_logical_ep_config(handle,
384 		_STRTOI32(argv[1]), _STRTOUI8(argv[2]), argv[3], argv[4],
385 		&error_number);
386 	} else if (!strcmp(*argv, "unsetlepc")) {
387 		_RMNETCLI_CHECKNULL(argv[1]);
388 		return_code = rmnet_unset_logical_ep_config(handle,
389 		_STRTOI32(argv[1]), argv[2], &error_number);
390 	}
391 	print_rmnet_api_status(return_code, error_number);
392 	rmnetctl_cleanup(handle);
393 	return return_code;
394 }
395 
396 /*!
397 * @brief Method which serves as en entry point to the rmnetcli function
398 * @details Entry point for the RmNet Netlink API. This is the command line
399 * interface for the RmNet API
400 * @param argc Number of arguments which vary based on the commands
401 * @param argv Value of the arguments which vary based on the commands
402 * @return RMNETCTL_SUCCESS if successful. Relevant data might be printed
403 * based on the message type
404 * @return RMNETCTL_LIB_ERR if there was a library error. Error code will be
405 * printed
406 * @return RMNETCTL_KERNEL_ERR if there was a error in the kernel. Error code will be
407 * printed
408 * @return RMNETCTL_INVALID_ARG if invalid arguments were passed to the API
409 */
main(int argc,char * argv[])410 int main(int argc, char *argv[])
411 {
412 	argc--;
413 	argv++;
414 	return rmnet_api_call(argc, argv);
415 }
416