1 /******************************************************************************
2 
3 			L I B R M N E T C T L . 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 * @file    librmnetctl.c
36 * @brief   rmnet control API's implentations file
37 */
38 
39 /*===========================================================================
40 			INCLUDE FILES
41 ===========================================================================*/
42 
43 #include <sys/socket.h>
44 #include <stdint.h>
45 #include <linux/netlink.h>
46 #include <string.h>
47 #include <stdio.h>
48 #include <unistd.h>
49 #include <stdlib.h>
50 #include <linux/rmnet_data.h>
51 #include "librmnetctl_hndl.h"
52 #include "librmnetctl.h"
53 
54 #ifdef USE_GLIB
55 #include <glib.h>
56 #define strlcpy g_strlcpy
57 #endif
58 
59 #define RMNETCTL_SOCK_FLAG 0
60 #define ROOT_USER_ID 0
61 #define MIN_VALID_PROCESS_ID 0
62 #define MIN_VALID_SOCKET_FD 0
63 #define KERNEL_PROCESS_ID 0
64 #define UNICAST 0
65 #define MAX_BUF_SIZE sizeof(struct nlmsghdr) + sizeof(struct rmnet_nl_msg_s)
66 
67 /*===========================================================================
68 			LOCAL FUNCTION DEFINITIONS
69 ===========================================================================*/
70 /*!
71 * @brief Synchronous method to send and receive messages to and from the kernel
72 * using  netlink sockets
73 * @details Increments the transaction id for each message sent to the kernel.
74 * Sends the netlink message to the kernel and receives the response from the
75 * kernel.
76 * @param *hndl RmNet handle for this transaction
77 * @param request Message to be sent to the kernel
78 * @param response Message received from the kernel
79 * @return RMNETCTL_API_SUCCESS if successfully able to send and receive message
80 * from the kernel
81 * @return RMNETCTL_API_ERR_HNDL_INVALID if RmNet handle for the transaction was
82 * NULL
83 * @return RMNETCTL_API_ERR_REQUEST_NULL not enough memory to create buffer for
84 * sending the message
85 * @return RMNETCTL_API_ERR_MESSAGE_SEND if could not send the message to kernel
86 * @return RMNETCTL_API_ERR_MESSAGE_RECEIVE if could not receive message from the
87 * kernel
88 * @return RMNETCTL_API_ERR_MESSAGE_TYPE if the request and response type do not
89 * match
90 */
rmnetctl_transact(rmnetctl_hndl_t * hndl,struct rmnet_nl_msg_s * request,struct rmnet_nl_msg_s * response)91 static int rmnetctl_transact(rmnetctl_hndl_t *hndl,
92 			struct rmnet_nl_msg_s *request,
93 			struct rmnet_nl_msg_s *response) {
94 	uint8_t *request_buf, *response_buf;
95 	struct nlmsghdr *nlmsghdr_val;
96 	struct rmnet_nl_msg_s *rmnet_nl_msg_s_val;
97 	int bytes_read = -1, return_code = RMNETCTL_API_ERR_HNDL_INVALID;
98 	request_buf = NULL;
99 	response_buf = NULL;
100 	nlmsghdr_val = NULL;
101 	rmnet_nl_msg_s_val = NULL;
102 	do {
103 	if (!hndl){
104 		break;
105 	}
106 	if (!request){
107 		return_code = RMNETCTL_API_ERR_REQUEST_NULL;
108 		break;
109 	}
110 	if (!response){
111 		return_code = RMNETCTL_API_ERR_RESPONSE_NULL;
112 		break;
113 	}
114 	request_buf = (uint8_t *)malloc(MAX_BUF_SIZE * sizeof(uint8_t));
115 	if (!request_buf){
116 		return_code = RMNETCTL_API_ERR_REQUEST_NULL;
117 		break;
118 	}
119 
120 	response_buf = (uint8_t *)malloc(MAX_BUF_SIZE * sizeof(uint8_t));
121 	if (!response_buf) {
122 		free(request_buf);
123 		return_code = RMNETCTL_API_ERR_RESPONSE_NULL;
124 		break;
125 	}
126 
127 	nlmsghdr_val = (struct nlmsghdr *)request_buf;
128 	rmnet_nl_msg_s_val = (struct rmnet_nl_msg_s *)NLMSG_DATA(request_buf);
129 
130 	memset(request_buf, 0, MAX_BUF_SIZE*sizeof(uint8_t));
131 	memset(response_buf, 0, MAX_BUF_SIZE*sizeof(uint8_t));
132 
133 	nlmsghdr_val->nlmsg_seq = hndl->transaction_id;
134 	nlmsghdr_val->nlmsg_pid = hndl->pid;
135 	nlmsghdr_val->nlmsg_len = MAX_BUF_SIZE;
136 
137 	memcpy((void *)NLMSG_DATA(request_buf), request,
138 	sizeof(struct rmnet_nl_msg_s));
139 
140 	rmnet_nl_msg_s_val->crd = RMNET_NETLINK_MSG_COMMAND;
141 	hndl->transaction_id++;
142 
143 	socklen_t addrlen = sizeof(struct sockaddr_nl);
144 	if (sendto(hndl->netlink_fd,
145 			request_buf,
146 			MAX_BUF_SIZE,
147 			RMNETCTL_SOCK_FLAG,
148 			(struct sockaddr *) &hndl->dest_addr,
149 			sizeof(struct sockaddr_nl)) < 0) {
150 		return_code = RMNETCTL_API_ERR_MESSAGE_SEND;
151 		free(request_buf);
152 		free(response_buf);
153 		break;
154 	}
155 
156 	bytes_read = recvfrom(hndl->netlink_fd,
157 			response_buf,
158 			MAX_BUF_SIZE,
159 			RMNETCTL_SOCK_FLAG,
160 			(struct sockaddr *) &hndl->src_addr,
161 			&addrlen);
162 	if (bytes_read < 0) {
163 		return_code = RMNETCTL_API_ERR_MESSAGE_RECEIVE;
164 		free(request_buf);
165 		free(response_buf);
166 		break;
167 	}
168 
169 	memcpy(response, (void *)NLMSG_DATA(response_buf),
170 	sizeof(struct rmnet_nl_msg_s));
171 	if (sizeof(*response) < sizeof(struct rmnet_nl_msg_s)) {
172 		return_code = RMNETCTL_API_ERR_RESPONSE_NULL;
173 		free(request_buf);
174 		free(response_buf);
175 		break;
176 	}
177 
178 	if (request->message_type != response->message_type) {
179 		return_code = RMNETCTL_API_ERR_MESSAGE_TYPE;
180 		free(request_buf);
181 		free(response_buf);
182 		break;
183 	}
184 	return_code = RMNETCTL_SUCCESS;
185 	} while(0);
186 	return return_code;
187 }
188 
189 /*!
190 * @brief Static function to check the dev name
191 * @details Checks if the name is not NULL and if the name is less than the
192 * RMNET_MAX_STR_LEN
193 * @param dev_name Name of the device
194 * @return RMNETCTL_SUCCESS if successful
195 * @return RMNETCTL_INVALID_ARG if invalid arguments were passed to the API
196 */
_rmnetctl_check_dev_name(const char * dev_name)197 static inline int _rmnetctl_check_dev_name(const char *dev_name) {
198 	int return_code = RMNETCTL_INVALID_ARG;
199 	do {
200 	if (!dev_name)
201 		break;
202 	if (strlen(dev_name) >= RMNET_MAX_STR_LEN)
203 		break;
204 	return_code = RMNETCTL_SUCCESS;
205 	} while(0);
206 	return return_code;
207 }
208 
209 /*!
210 * @brief Static function to check the string length after a copy
211 * @details Checks if the string length is not lesser than zero and lesser than
212 * RMNET_MAX_STR_LEN
213 * @param str_len length of the string after a copy
214 * @param error_code Status code of this operation
215 * @return RMNETCTL_SUCCESS if successful
216 * @return RMNETCTL_LIB_ERR if there was a library error. Check error_code
217 */
_rmnetctl_check_len(int str_len,uint16_t * error_code)218 static inline int _rmnetctl_check_len(int str_len, uint16_t *error_code) {
219 	int return_code = RMNETCTL_LIB_ERR;
220 	do {
221 	if ((str_len < 0) || (str_len > RMNET_MAX_STR_LEN)) {
222 		*error_code = RMNETCTL_API_ERR_STRING_TRUNCATION;
223 		break;
224 	}
225 	return_code = RMNETCTL_SUCCESS;
226 	} while(0);
227 	return return_code;
228 }
229 
230 /*!
231 * @brief Static function to check the response type
232 * @details Checks if the response type of this message was return code
233 * @param crd The crd field passed
234 * @param error_code Status code of this operation
235 * @return RMNETCTL_SUCCESS if successful
236 * @return RMNETCTL_LIB_ERR if there was a library error. Check error_code
237 */
_rmnetctl_check_code(int crd,uint16_t * error_code)238 static inline int _rmnetctl_check_code(int crd, uint16_t *error_code) {
239 	int return_code = RMNETCTL_LIB_ERR;
240 	do {
241 	if (crd != RMNET_NETLINK_MSG_RETURNCODE) {
242 		*error_code = RMNETCTL_API_ERR_RETURN_TYPE;
243 		break;
244 	}
245 	return_code = RMNETCTL_SUCCESS;
246 	} while(0);
247 	return return_code;
248 }
249 
250 /*!
251 * @brief Static function to check the response type
252 * @details Checks if the response type of this message was data
253 * @param crd The crd field passed
254 * @param error_code Status code of this operation
255 * @return RMNETCTL_SUCCESS if successful
256 * @return RMNETCTL_LIB_ERR if there was a library error. Check error_code
257 */
_rmnetctl_check_data(int crd,uint16_t * error_code)258 static inline int _rmnetctl_check_data(int crd, uint16_t *error_code) {
259 	int return_code = RMNETCTL_LIB_ERR;
260 	do {
261 	if (crd != RMNET_NETLINK_MSG_RETURNDATA) {
262 		*error_code = RMNETCTL_API_ERR_RETURN_TYPE;
263 		break;
264 	}
265 	return_code = RMNETCTL_SUCCESS;
266 	} while(0);
267 	return return_code;
268 }
269 
270 /*!
271 * @brief Static function to set the return value
272 * @details Checks if the error_code from the transaction is zero for a return
273 * code type message and sets the message type as RMNETCTL_SUCCESS
274 * @param crd The crd field passed
275 * @param error_code Status code of this operation
276 * @return RMNETCTL_SUCCESS if successful
277 * @return RMNETCTL_KERNEL_ERR if there was an error in the kernel.
278 * Check error_code
279 */
_rmnetctl_set_codes(int error_val,uint16_t * error_code)280 static inline int _rmnetctl_set_codes(int error_val, uint16_t *error_code) {
281 	int return_code = RMNETCTL_KERNEL_ERR;
282 	*error_code = error_val;
283 	if (*error_code == RMNETCTL_SUCCESS)
284 		return_code = RMNETCTL_SUCCESS;
285 	return return_code;
286 }
287 
288 /*===========================================================================
289 				EXPOSED API
290 ===========================================================================*/
291 
rmnetctl_init(rmnetctl_hndl_t ** hndl,uint16_t * error_code)292 int rmnetctl_init(rmnetctl_hndl_t **hndl, uint16_t *error_code)
293 {
294 	int pid = -1, netlink_fd = -1, return_code = RMNETCTL_LIB_ERR;
295 	do {
296 	if ((!hndl) || (!error_code)){
297 		return_code = RMNETCTL_INVALID_ARG;
298 		break;
299 	}
300 
301 	*hndl = (rmnetctl_hndl_t *)malloc(sizeof(rmnetctl_hndl_t));
302 	if (!*hndl) {
303 		*error_code = RMNETCTL_API_ERR_HNDL_INVALID;
304 		break;
305 	}
306 
307 	memset(*hndl, 0, sizeof(rmnetctl_hndl_t));
308 
309 	pid = getpid();
310 	if (pid  < MIN_VALID_PROCESS_ID) {
311 		free(*hndl);
312 		*error_code = RMNETCTL_INIT_ERR_PROCESS_ID;
313 		break;
314 	}
315 	(*hndl)->pid = pid;
316 	netlink_fd = socket(PF_NETLINK, SOCK_RAW, RMNET_NETLINK_PROTO);
317 	if (netlink_fd < MIN_VALID_SOCKET_FD) {
318 		free(*hndl);
319 		*error_code = RMNETCTL_INIT_ERR_NETLINK_FD;
320 		break;
321 	}
322 
323 	(*hndl)->netlink_fd = netlink_fd;
324 
325 	memset(&(*hndl)->src_addr, 0, sizeof(struct sockaddr_nl));
326 
327 	(*hndl)->src_addr.nl_family = AF_NETLINK;
328 	(*hndl)->src_addr.nl_pid = (*hndl)->pid;
329 
330 	if (bind((*hndl)->netlink_fd,
331 		(struct sockaddr *)&(*hndl)->src_addr,
332 		sizeof(struct sockaddr_nl)) < 0) {
333 		close((*hndl)->netlink_fd);
334 		free(*hndl);
335 		*error_code = RMNETCTL_INIT_ERR_BIND;
336 		break;
337 	}
338 
339 	memset(&(*hndl)->dest_addr, 0, sizeof(struct sockaddr_nl));
340 
341 	(*hndl)->dest_addr.nl_family = AF_NETLINK;
342 	(*hndl)->dest_addr.nl_pid = KERNEL_PROCESS_ID;
343 	(*hndl)->dest_addr.nl_groups = UNICAST;
344 
345 	return_code = RMNETCTL_SUCCESS;
346 	} while(0);
347 	return return_code;
348 }
349 
rmnetctl_cleanup(rmnetctl_hndl_t * hndl)350 void rmnetctl_cleanup(rmnetctl_hndl_t *hndl)
351 {
352 	if (!hndl)
353 		return;
354 	close(hndl->netlink_fd);
355 	free(hndl);
356 }
357 
rmnet_associate_network_device(rmnetctl_hndl_t * hndl,const char * dev_name,uint16_t * error_code,uint8_t assoc_dev)358 int rmnet_associate_network_device(rmnetctl_hndl_t *hndl,
359 				   const char *dev_name,
360 				   uint16_t *error_code,
361 				   uint8_t assoc_dev)
362 {
363 	struct rmnet_nl_msg_s request, response;
364 	int str_len = -1, return_code = RMNETCTL_LIB_ERR;
365 	do {
366 	if ((!hndl) || (!error_code) || _rmnetctl_check_dev_name(dev_name) ||
367 		((assoc_dev != RMNETCTL_DEVICE_ASSOCIATE) &&
368 		(assoc_dev != RMNETCTL_DEVICE_UNASSOCIATE))) {
369 		return_code = RMNETCTL_INVALID_ARG;
370 		break;
371 	}
372 
373 	if (assoc_dev == RMNETCTL_DEVICE_ASSOCIATE)
374 		request.message_type = RMNET_NETLINK_ASSOCIATE_NETWORK_DEVICE;
375 	else
376 		request.message_type = RMNET_NETLINK_UNASSOCIATE_NETWORK_DEVICE;
377 
378 	request.arg_length = RMNET_MAX_STR_LEN;
379 	str_len = strlcpy((char *)(request.data), dev_name, RMNET_MAX_STR_LEN);
380 	if (_rmnetctl_check_len(str_len, error_code) != RMNETCTL_SUCCESS)
381 		break;
382 
383 	if ((*error_code = rmnetctl_transact(hndl, &request, &response))
384 		!= RMNETCTL_SUCCESS)
385 		break;
386 	if (_rmnetctl_check_code(response.crd, error_code) != RMNETCTL_SUCCESS)
387 		break;
388 	return_code = _rmnetctl_set_codes(response.return_code, error_code);
389 	} while(0);
390 	return return_code;
391 }
392 
rmnet_get_network_device_associated(rmnetctl_hndl_t * hndl,const char * dev_name,int * register_status,uint16_t * error_code)393 int rmnet_get_network_device_associated(rmnetctl_hndl_t *hndl,
394 					const char *dev_name,
395 					int *register_status,
396 					uint16_t *error_code) {
397 	struct rmnet_nl_msg_s request, response;
398 	int str_len = -1, return_code = RMNETCTL_LIB_ERR;
399 	do {
400 	if ((!hndl) || (!register_status) || (!error_code) ||
401 	_rmnetctl_check_dev_name(dev_name)) {
402 		return_code = RMNETCTL_INVALID_ARG;
403 		break;
404 	}
405 
406 	request.message_type = RMNET_NETLINK_GET_NETWORK_DEVICE_ASSOCIATED;
407 
408 	request.arg_length = RMNET_MAX_STR_LEN;
409 	str_len = strlcpy((char *)(request.data), dev_name, RMNET_MAX_STR_LEN);
410 	if (_rmnetctl_check_len(str_len, error_code) != RMNETCTL_SUCCESS)
411 		break;
412 
413 	if ((*error_code = rmnetctl_transact(hndl, &request, &response))
414 		!= RMNETCTL_SUCCESS)
415 		break;
416 
417 	if (_rmnetctl_check_data(response.crd, error_code) != RMNETCTL_SUCCESS)
418 		break;
419 
420 	*register_status = response.return_code;
421 	return_code = RMNETCTL_SUCCESS;
422 	} while(0);
423 	return return_code;
424 }
425 
rmnet_set_link_egress_data_format(rmnetctl_hndl_t * hndl,uint32_t egress_flags,uint16_t agg_size,uint16_t agg_count,const char * dev_name,uint16_t * error_code)426 int rmnet_set_link_egress_data_format(rmnetctl_hndl_t *hndl,
427 				      uint32_t egress_flags,
428 				      uint16_t agg_size,
429 				      uint16_t agg_count,
430 				      const char *dev_name,
431 				      uint16_t *error_code) {
432 	struct rmnet_nl_msg_s request, response;
433 	int str_len = -1, return_code = RMNETCTL_LIB_ERR;
434 	do {
435 	if ((!hndl) || (!error_code) || _rmnetctl_check_dev_name(dev_name)) {
436 		return_code = RMNETCTL_INVALID_ARG;
437 		break;
438 	}
439 
440 	request.message_type = RMNET_NETLINK_SET_LINK_EGRESS_DATA_FORMAT;
441 
442 	request.arg_length = RMNET_MAX_STR_LEN +
443 			 sizeof(uint32_t) + sizeof(uint16_t) + sizeof(uint16_t);
444 	str_len = strlcpy((char *)(request.data_format.dev),
445 			  dev_name,
446 			  RMNET_MAX_STR_LEN);
447 	if (_rmnetctl_check_len(str_len, error_code) != RMNETCTL_SUCCESS)
448 		break;
449 
450 	request.data_format.flags = egress_flags;
451 	request.data_format.agg_size = agg_size;
452 	request.data_format.agg_count = agg_count;
453 
454 	if ((*error_code = rmnetctl_transact(hndl, &request, &response))
455 		!= RMNETCTL_SUCCESS)
456 		break;
457 
458 	if (_rmnetctl_check_code(response.crd, error_code) != RMNETCTL_SUCCESS)
459 		break;
460 
461 	return_code = _rmnetctl_set_codes(response.return_code, error_code);
462 	} while(0);
463 	return return_code;
464 }
465 
rmnet_get_link_egress_data_format(rmnetctl_hndl_t * hndl,const char * dev_name,uint32_t * egress_flags,uint16_t * agg_size,uint16_t * agg_count,uint16_t * error_code)466 int rmnet_get_link_egress_data_format(rmnetctl_hndl_t *hndl,
467 				      const char *dev_name,
468 				      uint32_t *egress_flags,
469 				      uint16_t *agg_size,
470 				      uint16_t *agg_count,
471 				      uint16_t *error_code) {
472 	struct rmnet_nl_msg_s request, response;
473 	int str_len = -1, return_code = RMNETCTL_LIB_ERR;
474 	do {
475 	if ((!hndl) || (!egress_flags) || (!agg_size) || (!agg_count) ||
476 	(!error_code) || _rmnetctl_check_dev_name(dev_name)) {
477 		return_code = RMNETCTL_INVALID_ARG;
478 		break;
479 	}
480 	request.message_type = RMNET_NETLINK_GET_LINK_EGRESS_DATA_FORMAT;
481 
482 	request.arg_length = RMNET_MAX_STR_LEN;
483 	str_len = strlcpy((char *)(request.data_format.dev),
484 			  dev_name,
485 			  RMNET_MAX_STR_LEN);
486 	if (_rmnetctl_check_len(str_len, error_code) != RMNETCTL_SUCCESS)
487 		break;
488 
489 	if ((*error_code = rmnetctl_transact(hndl, &request, &response))
490 		!= RMNETCTL_SUCCESS)
491 		break;
492 
493 	if (_rmnetctl_check_data(response.crd, error_code) != RMNETCTL_SUCCESS)
494 		break;
495 
496 	*egress_flags = response.data_format.flags;
497 	*agg_size = response.data_format.agg_size;
498 	*agg_count = response.data_format.agg_count;
499 	return_code = RMNETCTL_SUCCESS;
500 	} while(0);
501 	return return_code;
502 }
503 
rmnet_set_link_ingress_data_format_tailspace(rmnetctl_hndl_t * hndl,uint32_t ingress_flags,uint8_t tail_spacing,const char * dev_name,uint16_t * error_code)504 int rmnet_set_link_ingress_data_format_tailspace(rmnetctl_hndl_t *hndl,
505 						 uint32_t ingress_flags,
506 						 uint8_t  tail_spacing,
507 						 const char *dev_name,
508 						 uint16_t *error_code) {
509 	struct rmnet_nl_msg_s request, response;
510 	int str_len = -1, return_code = RMNETCTL_LIB_ERR;
511 	do {
512 	if ((!hndl) || (!error_code) || _rmnetctl_check_dev_name(dev_name)) {
513 		return_code = RMNETCTL_INVALID_ARG;
514 		break;
515 	}
516 
517 	request.message_type = RMNET_NETLINK_SET_LINK_INGRESS_DATA_FORMAT;
518 
519 	request.arg_length = RMNET_MAX_STR_LEN +
520 	sizeof(uint32_t) + sizeof(uint16_t) + sizeof(uint16_t);
521 	str_len = strlcpy((char *)(request.data_format.dev),
522 			  dev_name,
523 			  RMNET_MAX_STR_LEN);
524 	if (_rmnetctl_check_len(str_len, error_code) != RMNETCTL_SUCCESS)
525 		break;
526 	request.data_format.flags = ingress_flags;
527 	request.data_format.tail_spacing = tail_spacing;
528 
529 	if ((*error_code = rmnetctl_transact(hndl, &request, &response))
530 		!= RMNETCTL_SUCCESS)
531 		break;
532 
533 	if (_rmnetctl_check_code(response.crd, error_code) != RMNETCTL_SUCCESS)
534 		break;
535 
536 	return_code = _rmnetctl_set_codes(response.return_code, error_code);
537 	} while(0);
538 	return return_code;
539 }
540 
rmnet_get_link_ingress_data_format_tailspace(rmnetctl_hndl_t * hndl,const char * dev_name,uint32_t * ingress_flags,uint8_t * tail_spacing,uint16_t * error_code)541 int rmnet_get_link_ingress_data_format_tailspace(rmnetctl_hndl_t *hndl,
542 						 const char *dev_name,
543 						 uint32_t *ingress_flags,
544 						 uint8_t  *tail_spacing,
545 						 uint16_t *error_code) {
546 	struct rmnet_nl_msg_s request, response;
547 	int str_len = -1, return_code = RMNETCTL_LIB_ERR;
548 	do {
549 	if ((!hndl) || (!error_code) ||
550 		_rmnetctl_check_dev_name(dev_name)) {
551 		return_code = RMNETCTL_INVALID_ARG;
552 		break;
553 	}
554 
555 	request.message_type = RMNET_NETLINK_GET_LINK_INGRESS_DATA_FORMAT;
556 
557 	request.arg_length = RMNET_MAX_STR_LEN;
558 	str_len = strlcpy((char *)(request.data_format.dev),
559 			  dev_name,
560 			  RMNET_MAX_STR_LEN);
561 	if (_rmnetctl_check_len(str_len, error_code) != RMNETCTL_SUCCESS)
562 		break;
563 
564 	if ((*error_code = rmnetctl_transact(hndl, &request, &response))
565 		!= RMNETCTL_SUCCESS)
566 		break;
567 
568 	if (_rmnetctl_check_data(response.crd, error_code) != RMNETCTL_SUCCESS)
569 		break;
570 
571 	if (ingress_flags)
572 		*ingress_flags = response.data_format.flags;
573 
574 	if (tail_spacing)
575 		*tail_spacing = response.data_format.tail_spacing;
576 
577 	return_code = RMNETCTL_SUCCESS;
578 	} while(0);
579 	return return_code;
580 }
581 
rmnet_set_logical_ep_config(rmnetctl_hndl_t * hndl,int32_t ep_id,uint8_t operating_mode,const char * dev_name,const char * next_dev,uint16_t * error_code)582 int rmnet_set_logical_ep_config(rmnetctl_hndl_t *hndl,
583 				int32_t ep_id,
584 				uint8_t operating_mode,
585 				const char *dev_name,
586 				const char *next_dev,
587 				uint16_t *error_code) {
588 	struct rmnet_nl_msg_s request, response;
589 	int str_len = -1, return_code = RMNETCTL_LIB_ERR;
590 	do {
591 	if ((!hndl) || ((ep_id < -1) || (ep_id > 31)) || (!error_code) ||
592 		_rmnetctl_check_dev_name(dev_name) ||
593 		_rmnetctl_check_dev_name(next_dev)) {
594 		return_code = RMNETCTL_INVALID_ARG;
595 		break;
596 	}
597 
598 	request.message_type = RMNET_NETLINK_SET_LOGICAL_EP_CONFIG;
599 
600 	request.arg_length = RMNET_MAX_STR_LEN +
601 	RMNET_MAX_STR_LEN + sizeof(int32_t) + sizeof(uint8_t);
602 	str_len = strlcpy((char *)(request.local_ep_config.dev),
603 			  dev_name,
604 			  RMNET_MAX_STR_LEN);
605 	if (_rmnetctl_check_len(str_len, error_code) != RMNETCTL_SUCCESS)
606 		break;
607 
608 	str_len = strlcpy((char *)(request.local_ep_config.next_dev),
609 			  next_dev,
610 			  RMNET_MAX_STR_LEN);
611 	if (_rmnetctl_check_len(str_len, error_code) != RMNETCTL_SUCCESS)
612 		break;
613 	request.local_ep_config.ep_id = ep_id;
614 	request.local_ep_config.operating_mode = operating_mode;
615 
616 	if ((*error_code = rmnetctl_transact(hndl, &request, &response))
617 		!= RMNETCTL_SUCCESS)
618 		break;
619 	if (_rmnetctl_check_code(response.crd, error_code) != RMNETCTL_SUCCESS)
620 		break;
621 
622 	return_code = _rmnetctl_set_codes(response.return_code, error_code);
623 	} while(0);
624 	return return_code;
625 }
626 
rmnet_unset_logical_ep_config(rmnetctl_hndl_t * hndl,int32_t ep_id,const char * dev_name,uint16_t * error_code)627 int rmnet_unset_logical_ep_config(rmnetctl_hndl_t *hndl,
628 				  int32_t ep_id,
629 				  const char *dev_name,
630 				  uint16_t *error_code) {
631 	struct rmnet_nl_msg_s request, response;
632 	int str_len = -1, return_code = RMNETCTL_LIB_ERR;
633 	do {
634 
635 	if ((!hndl) || ((ep_id < -1) || (ep_id > 31)) || (!error_code) ||
636 		_rmnetctl_check_dev_name(dev_name)) {
637 		return_code = RMNETCTL_INVALID_ARG;
638 		break;
639 	}
640 
641 	request.message_type = RMNET_NETLINK_UNSET_LOGICAL_EP_CONFIG;
642 
643 	request.arg_length = RMNET_MAX_STR_LEN + sizeof(int32_t);
644 	str_len = strlcpy((char *)(request.local_ep_config.dev),
645 			  dev_name,
646 			  RMNET_MAX_STR_LEN);
647 
648 	if (_rmnetctl_check_len(str_len, error_code) != RMNETCTL_SUCCESS)
649 		break;
650 
651 	request.local_ep_config.ep_id = ep_id;
652 
653 	if ((*error_code = rmnetctl_transact(hndl, &request, &response))
654 		!= RMNETCTL_SUCCESS)
655 		break;
656 	if (_rmnetctl_check_code(response.crd, error_code) != RMNETCTL_SUCCESS)
657 		break;
658 
659 	return_code = _rmnetctl_set_codes(response.return_code, error_code);
660 	} while(0);
661 
662 	return return_code;
663 }
664 
rmnet_get_logical_ep_config(rmnetctl_hndl_t * hndl,int32_t ep_id,const char * dev_name,uint8_t * operating_mode,char ** next_dev,uint16_t * error_code)665 int rmnet_get_logical_ep_config(rmnetctl_hndl_t *hndl,
666 				int32_t ep_id,
667 				const char *dev_name,
668 				uint8_t *operating_mode,
669 				char **next_dev,
670 				uint16_t *error_code) {
671 	struct rmnet_nl_msg_s request, response;
672 	int str_len = -1, return_code = RMNETCTL_LIB_ERR;
673 	do {
674 	if ((!hndl) || (!operating_mode) || (!error_code) || ((ep_id < -1) ||
675 	(ep_id > 31)) || _rmnetctl_check_dev_name(dev_name) || (!next_dev)) {
676 		return_code = RMNETCTL_INVALID_ARG;
677 		break;
678 	}
679 
680 	request.message_type = RMNET_NETLINK_GET_LOGICAL_EP_CONFIG;
681 
682 	request.arg_length = RMNET_MAX_STR_LEN + sizeof(int32_t);
683 	str_len = strlcpy((char *)(request.local_ep_config.dev),
684 			  dev_name,
685 			  RMNET_MAX_STR_LEN);
686 	if (_rmnetctl_check_len(str_len, error_code) != RMNETCTL_SUCCESS)
687 		break;
688 
689 	request.local_ep_config.ep_id = ep_id;
690 
691 	if ((*error_code = rmnetctl_transact(hndl, &request, &response))
692 		!= RMNETCTL_SUCCESS)
693 		break;
694 	if (_rmnetctl_check_data(response.crd, error_code) != RMNETCTL_SUCCESS)
695 		break;
696 	printf("%s\n", (char *)(response.local_ep_config.next_dev));
697 	str_len = strlcpy(*next_dev,
698 			  (char *)(response.local_ep_config.next_dev),
699 			  RMNET_MAX_STR_LEN);
700 	if (_rmnetctl_check_len(str_len, error_code) != RMNETCTL_SUCCESS)
701 		break;
702 
703 	*operating_mode = response.local_ep_config.operating_mode;
704 	return_code = RMNETCTL_SUCCESS;
705 	} while(0);
706 	return return_code;
707 }
708 
rmnet_new_vnd_prefix(rmnetctl_hndl_t * hndl,uint32_t id,uint16_t * error_code,uint8_t new_vnd,const char * prefix)709 int rmnet_new_vnd_prefix(rmnetctl_hndl_t *hndl,
710 			 uint32_t id,
711 			 uint16_t *error_code,
712 			 uint8_t new_vnd,
713 			 const char *prefix)
714 {
715 	struct rmnet_nl_msg_s request, response;
716 	int return_code = RMNETCTL_LIB_ERR;
717 	int str_len = -1;
718 	do {
719 	if ((!hndl) || (!error_code) ||
720 	((new_vnd != RMNETCTL_NEW_VND) && (new_vnd != RMNETCTL_FREE_VND))) {
721 		return_code = RMNETCTL_INVALID_ARG;
722 		break;
723 	}
724 
725 	memset(request.vnd.vnd_name, 0, RMNET_MAX_STR_LEN);
726 	if (new_vnd ==  RMNETCTL_NEW_VND) {
727 		if (prefix) {
728 			request.message_type =RMNET_NETLINK_NEW_VND_WITH_PREFIX;
729 			str_len = strlcpy((char *)request.vnd.vnd_name,
730 					  prefix, RMNET_MAX_STR_LEN);
731 			if (_rmnetctl_check_len(str_len, error_code)
732 						!= RMNETCTL_SUCCESS)
733 				break;
734 		} else {
735 			request.message_type = RMNET_NETLINK_NEW_VND;
736 		}
737 	} else {
738 		request.message_type = RMNET_NETLINK_FREE_VND;
739 	}
740 
741 	request.arg_length = sizeof(uint32_t);
742 	request.vnd.id = id;
743 
744 	if ((*error_code = rmnetctl_transact(hndl, &request, &response))
745 		!= RMNETCTL_SUCCESS)
746 		break;
747 	if (_rmnetctl_check_code(response.crd, error_code) != RMNETCTL_SUCCESS)
748 		break;
749 
750 	return_code = _rmnetctl_set_codes(response.return_code, error_code);
751 	} while(0);
752 	return return_code;
753 }
754 
rmnet_new_vnd(rmnetctl_hndl_t * hndl,uint32_t id,uint16_t * error_code,uint8_t new_vnd)755 int rmnet_new_vnd(rmnetctl_hndl_t *hndl,
756 		  uint32_t id,
757 		  uint16_t *error_code,
758 		  uint8_t new_vnd)
759 {
760 	return rmnet_new_vnd_prefix(hndl, id, error_code, new_vnd, 0);
761 }
762 
rmnet_get_vnd_name(rmnetctl_hndl_t * hndl,uint32_t id,uint16_t * error_code,char * buf,uint32_t buflen)763 int rmnet_get_vnd_name(rmnetctl_hndl_t *hndl,
764 		       uint32_t id,
765 		       uint16_t *error_code,
766 		       char *buf,
767 		       uint32_t buflen)
768 {
769 	struct rmnet_nl_msg_s request, response;
770 	uint32_t str_len;
771 	int return_code = RMNETCTL_LIB_ERR;
772 	do {
773 	if ((!hndl) || (!error_code)) {
774 		return_code = RMNETCTL_INVALID_ARG;
775 		break;
776 	}
777 
778 	request.message_type = RMNET_NETLINK_GET_VND_NAME;
779 	request.arg_length = sizeof(uint32_t);
780 	request.vnd.id = id;
781 
782 
783 	if ((*error_code = rmnetctl_transact(hndl, &request, &response))
784 		!= RMNETCTL_SUCCESS)
785 		break;
786 	if (_rmnetctl_check_data(response.crd, error_code) != RMNETCTL_SUCCESS)
787 		break;
788 
789 	str_len = strlcpy(buf,
790 			  (char *)(response.vnd.vnd_name),
791 			  buflen);
792 	if (str_len >= buflen) {
793 		*error_code = RMNETCTL_API_ERR_STRING_TRUNCATION;
794 		break;
795 	}
796 
797 	return_code = RMNETCTL_SUCCESS;
798 	} while (0);
799 	return return_code;
800 }
801 
rmnet_add_del_vnd_tc_flow(rmnetctl_hndl_t * hndl,uint32_t id,uint32_t map_flow_id,uint32_t tc_flow_id,uint8_t set_flow,uint16_t * error_code)802 int rmnet_add_del_vnd_tc_flow(rmnetctl_hndl_t *hndl,
803 			      uint32_t id,
804 			      uint32_t map_flow_id,
805 			      uint32_t tc_flow_id,
806 			      uint8_t set_flow,
807 			      uint16_t *error_code) {
808 	struct rmnet_nl_msg_s request, response;
809 	int return_code = RMNETCTL_LIB_ERR;
810 	do {
811 	if ((!hndl) || ((set_flow != RMNETCTL_ADD_FLOW) &&
812 	(set_flow != RMNETCTL_DEL_FLOW))) {
813 		return_code = RMNETCTL_INVALID_ARG;
814 		break;
815 	}
816 	if (set_flow ==  RMNETCTL_ADD_FLOW)
817 		request.message_type = RMNET_NETLINK_ADD_VND_TC_FLOW;
818 	else
819 		request.message_type = RMNET_NETLINK_DEL_VND_TC_FLOW;
820 
821 	request.arg_length = (sizeof(uint32_t))*3;
822 	request.flow_control.id = id;
823 	request.flow_control.map_flow_id = map_flow_id;
824 	request.flow_control.tc_flow_id = tc_flow_id;
825 
826 	if ((*error_code = rmnetctl_transact(hndl, &request, &response))
827 	!= RMNETCTL_SUCCESS)
828 		break;
829 	if (_rmnetctl_check_code(response.crd, error_code) != RMNETCTL_SUCCESS)
830 		break;
831 	return_code = _rmnetctl_set_codes(response.return_code, error_code);
832 	} while(0);
833 	return return_code;
834 }
835 
836