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 	if ((error_number > RMNETCTL_API_SUCCESS) &&
208 		(error_number < RMNETCTL_API_ERR_ENUM_LENGTH)) {
209 		printf("%s", rmnetctl_error_code_text[error_number]);
210 	}
211 	if ((error_number >= RMNETCFG_ERR_NUM_START) &&
212 	(error_number < RMNETCFG_ERR_NUM_START + RMNETCFG_TOTAL_ERR_MSGS)) {
213 		printf("%s", rmnetcfg_error_code_text
214 			[error_number - RMNETCFG_ERR_NUM_START]);
215 		if ((error_number == RMNETCTL_CFG_SUCCESS_HELP_COMMAND) ||
216 			(error_number == RMNETCTL_CFG_FAILURE_NO_COMMAND))
217 			rmnet_api_usage();
218 	}
219 }
220 
221 /*!
222 * @brief Method to check the error numbers generated from API calls
223 * @details Displays the error messages based on each error code
224 * @param error_number Error number returned from the API and the CLI
225 * @return void
226 */
print_rmnet_api_status(int return_code,uint16_t error_number)227 static void print_rmnet_api_status(int return_code, uint16_t error_number)
228 {
229 	if (return_code == RMNETCTL_SUCCESS)
230 		printf("SUCCESS\n");
231 	else if (return_code == RMNETCTL_LIB_ERR)
232 		printf("LIBRARY ");
233 	else if (return_code == RMNETCTL_KERNEL_ERR)
234 		printf("KERNEL : Error code %u\n", error_number);
235 	else if (return_code == RMNETCTL_INVALID_ARG)
236 		printf("INVALID_ARG\n");
237 
238 	if (return_code == RMNETCTL_LIB_ERR) {
239 		print_rmnetctl_lib_errors(error_number);
240 	}
241 }
242 
243 /*!
244 * @brief Method to make the API calls
245 * @details Checks for each type of parameter and calls the appropriate
246 * function based on the number of parameters and paramter type
247 * @param argc Number of arguments which vary based on the commands
248 * @param argv Value of the arguments which vary based on the commands
249 * @return RMNETCTL_SUCCESS if successful. Relevant data might be printed
250 * based on the message type
251 * @return RMNETCTL_LIB_ERR if there was a library error. Error code will be
252 * printed
253 * @return RMNETCTL_KERNEL_ERR if there was a error in the kernel. Error code will be
254 * printed
255 * @return RMNETCTL_INVALID_ARG if invalid arguments were passed to the API
256 */
257 
rmnet_api_call(int argc,char * argv[])258 static int rmnet_api_call(int argc, char *argv[])
259 {
260 	struct rmnetctl_hndl_s *handle = NULL;
261 	uint16_t error_number = RMNETCTL_CFG_FAILURE_NO_COMMAND;
262 	int return_code = RMNETCTL_LIB_ERR;
263 	if ((!argc) || (!*argv)) {
264 		print_rmnet_api_status(RMNETCTL_LIB_ERR,
265 		RMNETCTL_CFG_FAILURE_NO_COMMAND);
266 		return RMNETCTL_LIB_ERR;
267 	}
268 	if (!strcmp(*argv, "help")) {
269 		print_rmnet_api_status(RMNETCTL_LIB_ERR,
270 		RMNETCTL_CFG_SUCCESS_HELP_COMMAND);
271 		return RMNETCTL_LIB_ERR;
272 	}
273 	return_code = rmnetctl_init(&handle, &error_number);
274 	if (return_code!= RMNETCTL_SUCCESS) {
275 		print_rmnet_api_status(return_code, error_number);
276 		return RMNETCTL_LIB_ERR;
277 	}
278 	error_number = RMNETCTL_CFG_FAILURE_NO_COMMAND;
279 	return_code = RMNETCTL_LIB_ERR;
280 	if (!strcmp(*argv, "assocnetdev")) {
281 		return_code = rmnet_associate_network_device(handle,
282 		argv[1], &error_number, RMNETCTL_DEVICE_ASSOCIATE);
283 	} else if (!strcmp(*argv, "unassocnetdev")) {
284 		return_code = rmnet_associate_network_device(handle,
285 		argv[1], &error_number, RMNETCTL_DEVICE_UNASSOCIATE);
286 	} else if (!strcmp(*argv, "getnetdevassoc")) {
287 		int register_status;
288 		return_code = rmnet_get_network_device_associated(handle,
289 		argv[1], &register_status, &error_number);
290 		if (return_code == RMNETCTL_SUCCESS)
291 			printf("register_status is %d\n", register_status);
292 	} else if (!strcmp(*argv, "getledf")) {
293 		uint32_t egress_flags;
294 		uint16_t agg_size, agg_count;
295 		return_code = rmnet_get_link_egress_data_format(handle,
296 		argv[1], &egress_flags, &agg_size, &agg_count, &error_number);
297 		if (return_code == RMNETCTL_SUCCESS) {
298 			printf("egress_flags is %u\n", egress_flags);
299 			printf("agg_size is %u\n", agg_size);
300 			printf("agg_count is %u\n", agg_count);
301 		}
302 	} else if (!strcmp(*argv, "getlidf")) {
303 		uint32_t ingress_flags;
304 		uint8_t  tail_spacing;
305 		return_code = rmnet_get_link_ingress_data_format_tailspace(
306 		handle, argv[1], &ingress_flags, &tail_spacing, &error_number);
307 		if (return_code == RMNETCTL_SUCCESS) {
308 			printf("ingress_flags is %u\n", ingress_flags);
309 			printf("tail_spacing is %u\n", tail_spacing);
310 		}
311 	} else if (!strcmp(*argv, "newvndprefix")) {
312 		_RMNETCLI_CHECKNULL(argv[1]);
313 		_RMNETCLI_CHECKNULL(argv[2]);
314 		return_code = rmnet_new_vnd_prefix(handle,
315 		_STRTOUI32(argv[1]), &error_number, RMNETCTL_NEW_VND, argv[2]);
316 	} else if (!strcmp(*argv, "newvnd")) {
317 		_RMNETCLI_CHECKNULL(argv[1]);
318 		return_code = rmnet_new_vnd(handle,
319 		_STRTOUI32(argv[1]), &error_number, RMNETCTL_NEW_VND);
320 	} else if (!strcmp(*argv, "getvndname")) {
321 		char buffer[32];
322 		memset(buffer, 0, 32);
323 		_RMNETCLI_CHECKNULL(argv[1]);
324 		return_code = rmnet_get_vnd_name(handle, _STRTOUI32(argv[1]),
325 			           &error_number, buffer, 32);
326 		if (return_code == RMNETCTL_SUCCESS) {
327 			printf("VND name: %s\n", buffer);
328 		}
329 	} else if (!strcmp(*argv, "freevnd")) {
330 		_RMNETCLI_CHECKNULL(argv[1]);
331 		return_code = rmnet_new_vnd(handle,
332 		_STRTOUI32(argv[1]), &error_number, RMNETCTL_FREE_VND);
333 	} else if (!strcmp(*argv, "setlidf")) {
334 		_RMNETCLI_CHECKNULL(argv[1]);
335 		_RMNETCLI_CHECKNULL(argv[2]);
336 		_RMNETCLI_CHECKNULL(argv[3]);
337 		return_code = rmnet_set_link_ingress_data_format_tailspace(
338 		handle, _STRTOUI32(argv[1]), _STRTOUI8(argv[2]), argv[3],
339 		&error_number);
340 	} else if (!strcmp(*argv, "delvnctcflow")) {
341 		_RMNETCLI_CHECKNULL(argv[1]);
342 		_RMNETCLI_CHECKNULL(argv[2]);
343 		_RMNETCLI_CHECKNULL(argv[3]);
344 		return_code = rmnet_add_del_vnd_tc_flow(handle,
345 		_STRTOUI32(argv[1]), _STRTOUI32(argv[2]), _STRTOUI32(argv[3]),
346 		RMNETCTL_DEL_FLOW, &error_number);
347 	} else if (!strcmp(*argv, "getlepc")) {
348 		_RMNETCLI_CHECKNULL(argv[1]);
349 		uint8_t rmnet_mode;
350 		char *egress_dev_name;
351 		egress_dev_name = NULL;
352 		egress_dev_name = (char *)malloc(RMNET_MAX_STR_LEN
353 		* sizeof(char));
354 		if (!egress_dev_name) {
355 			print_rmnet_api_status(RMNETCTL_LIB_ERR,
356 			RMNETCTL_CFG_FAILURE_EGRESS_DEV_NAME_NULL);
357 			return RMNETCTL_LIB_ERR;
358 		}
359 		return_code = rmnet_get_logical_ep_config(handle,
360 		_STRTOI32(argv[1]), argv[2], &rmnet_mode,
361 		&egress_dev_name, &error_number);
362 		if (return_code == RMNETCTL_SUCCESS) {
363 			printf("rmnet_mode is %u\n", rmnet_mode);
364 			printf("egress_dev_name is %s\n", egress_dev_name);
365 		}
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