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