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