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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 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 350 void rmnetctl_cleanup(rmnetctl_hndl_t *hndl) 351 { 352 if (!hndl) 353 return; 354 close(hndl->netlink_fd); 355 free(hndl); 356 } 357 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 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 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 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 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 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 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 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 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 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 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 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 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