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], ®ister_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