Harout Hedeshian | b2fc5b1 | 2013-09-03 13:49:00 -0600 | [diff] [blame] | 1 | /****************************************************************************** |
| 2 | |
| 3 | L I B R M N E T C T L . C |
| 4 | |
Sean Tranchetti | 51133f5 | 2019-02-12 12:54:34 -0700 | [diff] [blame] | 5 | Copyright (c) 2013-2015, 2017-2019 The Linux Foundation. All rights reserved. |
Harout Hedeshian | b2fc5b1 | 2013-09-03 13:49:00 -0600 | [diff] [blame] | 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 |
Subash Abhinov Kasiviswanathan | cf71508 | 2015-04-14 13:51:59 -0600 | [diff] [blame] | 36 | * @brief rmnet control API's implementation file |
Harout Hedeshian | b2fc5b1 | 2013-09-03 13:49:00 -0600 | [diff] [blame] | 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> |
Subash Abhinov Kasiviswanathan | 5b903dd | 2017-12-20 19:11:40 -0700 | [diff] [blame] | 50 | #include <errno.h> |
| 51 | #include <linux/rtnetlink.h> |
| 52 | #include <linux/gen_stats.h> |
| 53 | #include <net/if.h> |
| 54 | #include <asm/types.h> |
Harout Hedeshian | b2fc5b1 | 2013-09-03 13:49:00 -0600 | [diff] [blame] | 55 | #include <linux/rmnet_data.h> |
| 56 | #include "librmnetctl_hndl.h" |
| 57 | #include "librmnetctl.h" |
| 58 | |
Harout Hedeshian | 04d6973 | 2013-10-02 09:29:11 -0600 | [diff] [blame] | 59 | #ifdef USE_GLIB |
| 60 | #include <glib.h> |
| 61 | #define strlcpy g_strlcpy |
| 62 | #endif |
| 63 | |
Harout Hedeshian | b2fc5b1 | 2013-09-03 13:49:00 -0600 | [diff] [blame] | 64 | #define RMNETCTL_SOCK_FLAG 0 |
| 65 | #define ROOT_USER_ID 0 |
| 66 | #define MIN_VALID_PROCESS_ID 0 |
| 67 | #define MIN_VALID_SOCKET_FD 0 |
| 68 | #define KERNEL_PROCESS_ID 0 |
| 69 | #define UNICAST 0 |
| 70 | #define MAX_BUF_SIZE sizeof(struct nlmsghdr) + sizeof(struct rmnet_nl_msg_s) |
Harout Hedeshian | 7782557 | 2014-02-17 10:47:14 +0200 | [diff] [blame] | 71 | #define INGRESS_FLAGS_MASK (RMNET_INGRESS_FIX_ETHERNET | \ |
| 72 | RMNET_INGRESS_FORMAT_MAP | \ |
| 73 | RMNET_INGRESS_FORMAT_DEAGGREGATION | \ |
| 74 | RMNET_INGRESS_FORMAT_DEMUXING | \ |
Sivan Reinstein | c22a0d8 | 2014-07-13 16:58:21 +0300 | [diff] [blame] | 75 | RMNET_INGRESS_FORMAT_MAP_COMMANDS | \ |
Subash Abhinov Kasiviswanathan | 21e5e44 | 2015-09-03 20:07:53 -0600 | [diff] [blame] | 76 | RMNET_INGRESS_FORMAT_MAP_CKSUMV3 | \ |
| 77 | RMNET_INGRESS_FORMAT_MAP_CKSUMV4) |
Harout Hedeshian | 7782557 | 2014-02-17 10:47:14 +0200 | [diff] [blame] | 78 | #define EGRESS_FLAGS_MASK (RMNET_EGRESS_FORMAT__RESERVED__ | \ |
| 79 | RMNET_EGRESS_FORMAT_MAP | \ |
| 80 | RMNET_EGRESS_FORMAT_AGGREGATION | \ |
Sivan Reinstein | a3c5717 | 2014-09-10 14:11:58 +0300 | [diff] [blame] | 81 | RMNET_EGRESS_FORMAT_MUXING | \ |
Subash Abhinov Kasiviswanathan | 21e5e44 | 2015-09-03 20:07:53 -0600 | [diff] [blame] | 82 | RMNET_EGRESS_FORMAT_MAP_CKSUMV3 | \ |
| 83 | RMNET_EGRESS_FORMAT_MAP_CKSUMV4) |
Harout Hedeshian | b2fc5b1 | 2013-09-03 13:49:00 -0600 | [diff] [blame] | 84 | |
Harout Hedeshian | 7782557 | 2014-02-17 10:47:14 +0200 | [diff] [blame] | 85 | #define min(a, b) (((a) < (b)) ? (a) : (b)) |
Subash Abhinov Kasiviswanathan | 5b903dd | 2017-12-20 19:11:40 -0700 | [diff] [blame] | 86 | #define NLMSG_TAIL(nmsg) \ |
| 87 | ((struct rtattr *) (((char *)(nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len))) |
| 88 | |
Subash Abhinov Kasiviswanathan | c26ed59 | 2018-06-15 15:38:27 -0700 | [diff] [blame] | 89 | #define NLMSG_DATA_SIZE 500 |
| 90 | |
| 91 | #define CHECK_MEMSCPY(x) ({if (x < 0 ){return RMNETCTL_LIB_ERR;}}) |
| 92 | |
Subash Abhinov Kasiviswanathan | 5b903dd | 2017-12-20 19:11:40 -0700 | [diff] [blame] | 93 | struct nlmsg { |
| 94 | struct nlmsghdr nl_addr; |
| 95 | struct ifinfomsg ifmsg; |
Subash Abhinov Kasiviswanathan | c26ed59 | 2018-06-15 15:38:27 -0700 | [diff] [blame] | 96 | char data[NLMSG_DATA_SIZE]; |
Subash Abhinov Kasiviswanathan | 5b903dd | 2017-12-20 19:11:40 -0700 | [diff] [blame] | 97 | }; |
| 98 | |
Sean Tranchetti | 6cac289 | 2019-04-19 11:04:57 -0600 | [diff] [blame] | 99 | struct rmnetctl_uplink_params { |
| 100 | uint16_t byte_count; |
Subash Abhinov Kasiviswanathan | a0c4bfb | 2019-08-14 11:26:52 -0600 | [diff] [blame] | 101 | uint8_t packet_count; |
| 102 | uint8_t features; |
Sean Tranchetti | 6cac289 | 2019-04-19 11:04:57 -0600 | [diff] [blame] | 103 | uint32_t time_limit; |
| 104 | }; |
| 105 | |
Sean Tranchetti | 037065c | 2019-04-19 11:04:43 -0600 | [diff] [blame] | 106 | /* IFLA Attributes for the RT RmNet driver */ |
| 107 | enum { |
| 108 | RMNETCTL_IFLA_UNSPEC, |
| 109 | RMNETCTL_IFLA_MUX_ID, |
| 110 | RMNETCTL_IFLA_FLAGS, |
| 111 | RMNETCTL_IFLA_DFC_QOS, |
Sean Tranchetti | 6cac289 | 2019-04-19 11:04:57 -0600 | [diff] [blame] | 112 | RMNETCTL_IFLA_UPLINK_PARAMS, |
Sean Tranchetti | 037065c | 2019-04-19 11:04:43 -0600 | [diff] [blame] | 113 | __RMNETCTL_IFLA_MAX, |
| 114 | }; |
| 115 | |
Sean Tranchetti | 4fb7294 | 2019-02-12 15:36:30 -0700 | [diff] [blame] | 116 | /* Flow message types sent to DFC driver */ |
| 117 | enum { |
| 118 | /* Activate flow */ |
| 119 | RMNET_FLOW_MSG_ACTIVATE = 1, |
| 120 | /* Delete flow */ |
| 121 | RMNET_FLOW_MSG_DEACTIVATE = 2, |
| 122 | /* Legacy flow control */ |
| 123 | RMNET_FLOW_MSG_CONTROL = 3, |
| 124 | /* Flow up */ |
| 125 | RMNET_FLOW_MSG_UP = 4, |
| 126 | /* Flow down */ |
| 127 | RMNET_FLOW_MSG_DOWN = 5, |
Sean Tranchetti | f74a76a | 2018-12-18 15:28:08 -0700 | [diff] [blame] | 128 | /* Change ACK scaling */ |
| 129 | RMNET_FLOW_MSG_QMI_SCALE = 6, |
| 130 | /* Change powersave workqueue polling freq */ |
| 131 | RMNET_FLOW_MSG_WDA_FREQ = 7, |
Sean Tranchetti | 4fb7294 | 2019-02-12 15:36:30 -0700 | [diff] [blame] | 132 | }; |
| 133 | |
Subash Abhinov Kasiviswanathan | db2b6da | 2019-10-17 17:10:49 -0700 | [diff] [blame] | 134 | /* 0 reserved, 1-15 for data, 16-30 for acks */ |
| 135 | #define RMNETCTL_NUM_TX_QUEUES 31 |
Subash Abhinov Kasiviswanathan | cf3f890 | 2018-08-30 14:23:08 -0600 | [diff] [blame] | 136 | |
| 137 | /* This needs to be hardcoded here because some legacy linux systems |
| 138 | * do not have this definition |
| 139 | */ |
| 140 | #define RMNET_IFLA_NUM_TX_QUEUES 31 |
| 141 | |
Harout Hedeshian | b2fc5b1 | 2013-09-03 13:49:00 -0600 | [diff] [blame] | 142 | /*=========================================================================== |
| 143 | LOCAL FUNCTION DEFINITIONS |
| 144 | ===========================================================================*/ |
Subash Abhinov Kasiviswanathan | c26ed59 | 2018-06-15 15:38:27 -0700 | [diff] [blame] | 145 | /* Helper functions |
| 146 | * @brief helper function to implement a secure memcpy |
| 147 | * @details take source and destination buffer size into |
| 148 | * considerations before copying |
| 149 | * @param dst destination buffer |
| 150 | * @param dst_size size of destination buffer |
| 151 | * @param src source buffer |
| 152 | * @param src_size size of source buffer |
| 153 | * @return size of the smallest of two buffer |
| 154 | */ |
| 155 | |
| 156 | static inline size_t memscpy(void *dst, size_t dst_size, const void *src, |
| 157 | size_t src_size) { |
| 158 | size_t min_size = dst_size < src_size ? dst_size : src_size; |
| 159 | memcpy(dst, src, min_size); |
| 160 | return min_size; |
| 161 | } |
| 162 | |
| 163 | /* |
| 164 | * @brief helper function to implement a secure memcpy |
| 165 | * for a concatenating buffer where offset is kept |
| 166 | * track of |
| 167 | * @details take source and destination buffer size into |
| 168 | * considerations before copying |
| 169 | * @param dst destination buffer |
| 170 | * @param dst_size pointer used to decrement |
| 171 | * @param src source buffer |
| 172 | * @param src_size size of source buffer |
| 173 | * @return size of the remaining buffer |
| 174 | */ |
| 175 | |
| 176 | |
| 177 | static inline int memscpy_repeat(void* dst, size_t *dst_size, |
| 178 | const void* src, size_t src_size) |
| 179 | { |
| 180 | if( !dst_size || *dst_size <= src_size || !dst || !src) |
| 181 | return RMNETCTL_LIB_ERR; |
| 182 | else { |
| 183 | *dst_size -= memscpy(dst, *dst_size, src, src_size); |
| 184 | } |
| 185 | return *dst_size; |
| 186 | } |
| 187 | |
| 188 | |
Harout Hedeshian | b2fc5b1 | 2013-09-03 13:49:00 -0600 | [diff] [blame] | 189 | /*! |
| 190 | * @brief Synchronous method to send and receive messages to and from the kernel |
| 191 | * using netlink sockets |
| 192 | * @details Increments the transaction id for each message sent to the kernel. |
| 193 | * Sends the netlink message to the kernel and receives the response from the |
| 194 | * kernel. |
| 195 | * @param *hndl RmNet handle for this transaction |
| 196 | * @param request Message to be sent to the kernel |
| 197 | * @param response Message received from the kernel |
| 198 | * @return RMNETCTL_API_SUCCESS if successfully able to send and receive message |
| 199 | * from the kernel |
| 200 | * @return RMNETCTL_API_ERR_HNDL_INVALID if RmNet handle for the transaction was |
| 201 | * NULL |
| 202 | * @return RMNETCTL_API_ERR_REQUEST_NULL not enough memory to create buffer for |
| 203 | * sending the message |
| 204 | * @return RMNETCTL_API_ERR_MESSAGE_SEND if could not send the message to kernel |
| 205 | * @return RMNETCTL_API_ERR_MESSAGE_RECEIVE if could not receive message from the |
| 206 | * kernel |
| 207 | * @return RMNETCTL_API_ERR_MESSAGE_TYPE if the request and response type do not |
| 208 | * match |
| 209 | */ |
Harout Hedeshian | 0bf0a17 | 2014-02-19 23:52:05 -0700 | [diff] [blame] | 210 | static uint16_t rmnetctl_transact(rmnetctl_hndl_t *hndl, |
Harout Hedeshian | b2fc5b1 | 2013-09-03 13:49:00 -0600 | [diff] [blame] | 211 | struct rmnet_nl_msg_s *request, |
| 212 | struct rmnet_nl_msg_s *response) { |
| 213 | uint8_t *request_buf, *response_buf; |
| 214 | struct nlmsghdr *nlmsghdr_val; |
| 215 | struct rmnet_nl_msg_s *rmnet_nl_msg_s_val; |
Subash Abhinov Kasiviswanathan | c26ed59 | 2018-06-15 15:38:27 -0700 | [diff] [blame] | 216 | ssize_t bytes_read = -1, buffsize = MAX_BUF_SIZE - sizeof(struct nlmsghdr); |
Harout Hedeshian | 0bf0a17 | 2014-02-19 23:52:05 -0700 | [diff] [blame] | 217 | uint16_t return_code = RMNETCTL_API_ERR_HNDL_INVALID; |
| 218 | struct sockaddr_nl* __attribute__((__may_alias__)) saddr_ptr; |
Harout Hedeshian | b2fc5b1 | 2013-09-03 13:49:00 -0600 | [diff] [blame] | 219 | request_buf = NULL; |
| 220 | response_buf = NULL; |
| 221 | nlmsghdr_val = NULL; |
| 222 | rmnet_nl_msg_s_val = NULL; |
| 223 | do { |
| 224 | if (!hndl){ |
| 225 | break; |
| 226 | } |
| 227 | if (!request){ |
| 228 | return_code = RMNETCTL_API_ERR_REQUEST_NULL; |
| 229 | break; |
| 230 | } |
| 231 | if (!response){ |
| 232 | return_code = RMNETCTL_API_ERR_RESPONSE_NULL; |
| 233 | break; |
| 234 | } |
| 235 | request_buf = (uint8_t *)malloc(MAX_BUF_SIZE * sizeof(uint8_t)); |
| 236 | if (!request_buf){ |
| 237 | return_code = RMNETCTL_API_ERR_REQUEST_NULL; |
| 238 | break; |
| 239 | } |
| 240 | |
| 241 | response_buf = (uint8_t *)malloc(MAX_BUF_SIZE * sizeof(uint8_t)); |
| 242 | if (!response_buf) { |
Harout Hedeshian | b2fc5b1 | 2013-09-03 13:49:00 -0600 | [diff] [blame] | 243 | return_code = RMNETCTL_API_ERR_RESPONSE_NULL; |
| 244 | break; |
| 245 | } |
| 246 | |
| 247 | nlmsghdr_val = (struct nlmsghdr *)request_buf; |
| 248 | rmnet_nl_msg_s_val = (struct rmnet_nl_msg_s *)NLMSG_DATA(request_buf); |
| 249 | |
| 250 | memset(request_buf, 0, MAX_BUF_SIZE*sizeof(uint8_t)); |
| 251 | memset(response_buf, 0, MAX_BUF_SIZE*sizeof(uint8_t)); |
| 252 | |
| 253 | nlmsghdr_val->nlmsg_seq = hndl->transaction_id; |
| 254 | nlmsghdr_val->nlmsg_pid = hndl->pid; |
| 255 | nlmsghdr_val->nlmsg_len = MAX_BUF_SIZE; |
| 256 | |
Subash Abhinov Kasiviswanathan | c26ed59 | 2018-06-15 15:38:27 -0700 | [diff] [blame] | 257 | memscpy((void *)NLMSG_DATA(request_buf), buffsize, request, |
Harout Hedeshian | b2fc5b1 | 2013-09-03 13:49:00 -0600 | [diff] [blame] | 258 | sizeof(struct rmnet_nl_msg_s)); |
| 259 | |
| 260 | rmnet_nl_msg_s_val->crd = RMNET_NETLINK_MSG_COMMAND; |
| 261 | hndl->transaction_id++; |
| 262 | |
Harout Hedeshian | 0bf0a17 | 2014-02-19 23:52:05 -0700 | [diff] [blame] | 263 | saddr_ptr = &hndl->dest_addr; |
Harout Hedeshian | b2fc5b1 | 2013-09-03 13:49:00 -0600 | [diff] [blame] | 264 | socklen_t addrlen = sizeof(struct sockaddr_nl); |
| 265 | if (sendto(hndl->netlink_fd, |
| 266 | request_buf, |
| 267 | MAX_BUF_SIZE, |
| 268 | RMNETCTL_SOCK_FLAG, |
Harout Hedeshian | 0bf0a17 | 2014-02-19 23:52:05 -0700 | [diff] [blame] | 269 | (struct sockaddr*)saddr_ptr, |
Harout Hedeshian | b2fc5b1 | 2013-09-03 13:49:00 -0600 | [diff] [blame] | 270 | sizeof(struct sockaddr_nl)) < 0) { |
| 271 | return_code = RMNETCTL_API_ERR_MESSAGE_SEND; |
Harout Hedeshian | b2fc5b1 | 2013-09-03 13:49:00 -0600 | [diff] [blame] | 272 | break; |
| 273 | } |
| 274 | |
Harout Hedeshian | 0bf0a17 | 2014-02-19 23:52:05 -0700 | [diff] [blame] | 275 | saddr_ptr = &hndl->src_addr; |
Harout Hedeshian | b2fc5b1 | 2013-09-03 13:49:00 -0600 | [diff] [blame] | 276 | bytes_read = recvfrom(hndl->netlink_fd, |
| 277 | response_buf, |
| 278 | MAX_BUF_SIZE, |
| 279 | RMNETCTL_SOCK_FLAG, |
Harout Hedeshian | 0bf0a17 | 2014-02-19 23:52:05 -0700 | [diff] [blame] | 280 | (struct sockaddr*)saddr_ptr, |
Harout Hedeshian | b2fc5b1 | 2013-09-03 13:49:00 -0600 | [diff] [blame] | 281 | &addrlen); |
| 282 | if (bytes_read < 0) { |
| 283 | return_code = RMNETCTL_API_ERR_MESSAGE_RECEIVE; |
Harout Hedeshian | b2fc5b1 | 2013-09-03 13:49:00 -0600 | [diff] [blame] | 284 | break; |
| 285 | } |
Subash Abhinov Kasiviswanathan | c26ed59 | 2018-06-15 15:38:27 -0700 | [diff] [blame] | 286 | buffsize = MAX_BUF_SIZE - sizeof(struct nlmsghdr); |
| 287 | memscpy(response, buffsize, (void *)NLMSG_DATA(response_buf), |
Harout Hedeshian | b2fc5b1 | 2013-09-03 13:49:00 -0600 | [diff] [blame] | 288 | sizeof(struct rmnet_nl_msg_s)); |
| 289 | if (sizeof(*response) < sizeof(struct rmnet_nl_msg_s)) { |
| 290 | return_code = RMNETCTL_API_ERR_RESPONSE_NULL; |
Harout Hedeshian | b2fc5b1 | 2013-09-03 13:49:00 -0600 | [diff] [blame] | 291 | break; |
| 292 | } |
| 293 | |
| 294 | if (request->message_type != response->message_type) { |
| 295 | return_code = RMNETCTL_API_ERR_MESSAGE_TYPE; |
Harout Hedeshian | b2fc5b1 | 2013-09-03 13:49:00 -0600 | [diff] [blame] | 296 | break; |
| 297 | } |
| 298 | return_code = RMNETCTL_SUCCESS; |
| 299 | } while(0); |
Harout Hedeshian | 7782557 | 2014-02-17 10:47:14 +0200 | [diff] [blame] | 300 | free(request_buf); |
| 301 | free(response_buf); |
Harout Hedeshian | b2fc5b1 | 2013-09-03 13:49:00 -0600 | [diff] [blame] | 302 | return return_code; |
| 303 | } |
| 304 | |
| 305 | /*! |
| 306 | * @brief Static function to check the dev name |
| 307 | * @details Checks if the name is not NULL and if the name is less than the |
| 308 | * RMNET_MAX_STR_LEN |
| 309 | * @param dev_name Name of the device |
| 310 | * @return RMNETCTL_SUCCESS if successful |
| 311 | * @return RMNETCTL_INVALID_ARG if invalid arguments were passed to the API |
| 312 | */ |
| 313 | static inline int _rmnetctl_check_dev_name(const char *dev_name) { |
| 314 | int return_code = RMNETCTL_INVALID_ARG; |
| 315 | do { |
| 316 | if (!dev_name) |
| 317 | break; |
| 318 | if (strlen(dev_name) >= RMNET_MAX_STR_LEN) |
| 319 | break; |
| 320 | return_code = RMNETCTL_SUCCESS; |
| 321 | } while(0); |
| 322 | return return_code; |
| 323 | } |
| 324 | |
| 325 | /*! |
| 326 | * @brief Static function to check the string length after a copy |
| 327 | * @details Checks if the string length is not lesser than zero and lesser than |
| 328 | * RMNET_MAX_STR_LEN |
| 329 | * @param str_len length of the string after a copy |
| 330 | * @param error_code Status code of this operation |
| 331 | * @return RMNETCTL_SUCCESS if successful |
| 332 | * @return RMNETCTL_LIB_ERR if there was a library error. Check error_code |
| 333 | */ |
Harout Hedeshian | 0bf0a17 | 2014-02-19 23:52:05 -0700 | [diff] [blame] | 334 | static inline int _rmnetctl_check_len(size_t str_len, uint16_t *error_code) { |
Harout Hedeshian | b2fc5b1 | 2013-09-03 13:49:00 -0600 | [diff] [blame] | 335 | int return_code = RMNETCTL_LIB_ERR; |
| 336 | do { |
Harout Hedeshian | 0bf0a17 | 2014-02-19 23:52:05 -0700 | [diff] [blame] | 337 | if (str_len > RMNET_MAX_STR_LEN) { |
Harout Hedeshian | b2fc5b1 | 2013-09-03 13:49:00 -0600 | [diff] [blame] | 338 | *error_code = RMNETCTL_API_ERR_STRING_TRUNCATION; |
| 339 | break; |
| 340 | } |
| 341 | return_code = RMNETCTL_SUCCESS; |
| 342 | } while(0); |
| 343 | return return_code; |
| 344 | } |
| 345 | |
| 346 | /*! |
| 347 | * @brief Static function to check the response type |
| 348 | * @details Checks if the response type of this message was return code |
| 349 | * @param crd The crd field passed |
| 350 | * @param error_code Status code of this operation |
| 351 | * @return RMNETCTL_SUCCESS if successful |
| 352 | * @return RMNETCTL_LIB_ERR if there was a library error. Check error_code |
| 353 | */ |
| 354 | static inline int _rmnetctl_check_code(int crd, uint16_t *error_code) { |
| 355 | int return_code = RMNETCTL_LIB_ERR; |
| 356 | do { |
| 357 | if (crd != RMNET_NETLINK_MSG_RETURNCODE) { |
| 358 | *error_code = RMNETCTL_API_ERR_RETURN_TYPE; |
| 359 | break; |
| 360 | } |
| 361 | return_code = RMNETCTL_SUCCESS; |
| 362 | } while(0); |
| 363 | return return_code; |
| 364 | } |
| 365 | |
| 366 | /*! |
| 367 | * @brief Static function to check the response type |
| 368 | * @details Checks if the response type of this message was data |
| 369 | * @param crd The crd field passed |
| 370 | * @param error_code Status code of this operation |
| 371 | * @return RMNETCTL_SUCCESS if successful |
| 372 | * @return RMNETCTL_LIB_ERR if there was a library error. Check error_code |
| 373 | */ |
| 374 | static inline int _rmnetctl_check_data(int crd, uint16_t *error_code) { |
| 375 | int return_code = RMNETCTL_LIB_ERR; |
| 376 | do { |
| 377 | if (crd != RMNET_NETLINK_MSG_RETURNDATA) { |
| 378 | *error_code = RMNETCTL_API_ERR_RETURN_TYPE; |
| 379 | break; |
| 380 | } |
| 381 | return_code = RMNETCTL_SUCCESS; |
| 382 | } while(0); |
| 383 | return return_code; |
| 384 | } |
| 385 | |
| 386 | /*! |
| 387 | * @brief Static function to set the return value |
| 388 | * @details Checks if the error_code from the transaction is zero for a return |
| 389 | * code type message and sets the message type as RMNETCTL_SUCCESS |
| 390 | * @param crd The crd field passed |
| 391 | * @param error_code Status code of this operation |
| 392 | * @return RMNETCTL_SUCCESS if successful |
| 393 | * @return RMNETCTL_KERNEL_ERR if there was an error in the kernel. |
| 394 | * Check error_code |
| 395 | */ |
| 396 | static inline int _rmnetctl_set_codes(int error_val, uint16_t *error_code) { |
| 397 | int return_code = RMNETCTL_KERNEL_ERR; |
Harout Hedeshian | 7782557 | 2014-02-17 10:47:14 +0200 | [diff] [blame] | 398 | if (error_val == RMNET_CONFIG_OK) |
Harout Hedeshian | b2fc5b1 | 2013-09-03 13:49:00 -0600 | [diff] [blame] | 399 | return_code = RMNETCTL_SUCCESS; |
Harout Hedeshian | 7782557 | 2014-02-17 10:47:14 +0200 | [diff] [blame] | 400 | else |
Harout Hedeshian | 0bf0a17 | 2014-02-19 23:52:05 -0700 | [diff] [blame] | 401 | *error_code = (uint16_t)error_val + RMNETCTL_KERNEL_FIRST_ERR; |
Harout Hedeshian | b2fc5b1 | 2013-09-03 13:49:00 -0600 | [diff] [blame] | 402 | return return_code; |
| 403 | } |
| 404 | |
| 405 | /*=========================================================================== |
| 406 | EXPOSED API |
| 407 | ===========================================================================*/ |
| 408 | |
| 409 | int rmnetctl_init(rmnetctl_hndl_t **hndl, uint16_t *error_code) |
| 410 | { |
Harout Hedeshian | 0bf0a17 | 2014-02-19 23:52:05 -0700 | [diff] [blame] | 411 | pid_t pid = 0; |
| 412 | int netlink_fd = -1, return_code = RMNETCTL_LIB_ERR; |
| 413 | struct sockaddr_nl* __attribute__((__may_alias__)) saddr_ptr; |
Harout Hedeshian | b2fc5b1 | 2013-09-03 13:49:00 -0600 | [diff] [blame] | 414 | do { |
| 415 | if ((!hndl) || (!error_code)){ |
| 416 | return_code = RMNETCTL_INVALID_ARG; |
| 417 | break; |
| 418 | } |
| 419 | |
| 420 | *hndl = (rmnetctl_hndl_t *)malloc(sizeof(rmnetctl_hndl_t)); |
| 421 | if (!*hndl) { |
| 422 | *error_code = RMNETCTL_API_ERR_HNDL_INVALID; |
| 423 | break; |
| 424 | } |
| 425 | |
| 426 | memset(*hndl, 0, sizeof(rmnetctl_hndl_t)); |
| 427 | |
| 428 | pid = getpid(); |
| 429 | if (pid < MIN_VALID_PROCESS_ID) { |
| 430 | free(*hndl); |
| 431 | *error_code = RMNETCTL_INIT_ERR_PROCESS_ID; |
| 432 | break; |
| 433 | } |
Harout Hedeshian | 0bf0a17 | 2014-02-19 23:52:05 -0700 | [diff] [blame] | 434 | (*hndl)->pid = (uint32_t)pid; |
Conner Huff | 1ecd2d8 | 2018-04-20 11:12:35 -0700 | [diff] [blame] | 435 | netlink_fd = socket(PF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, RMNET_NETLINK_PROTO); |
Harout Hedeshian | b2fc5b1 | 2013-09-03 13:49:00 -0600 | [diff] [blame] | 436 | if (netlink_fd < MIN_VALID_SOCKET_FD) { |
| 437 | free(*hndl); |
| 438 | *error_code = RMNETCTL_INIT_ERR_NETLINK_FD; |
| 439 | break; |
| 440 | } |
| 441 | |
| 442 | (*hndl)->netlink_fd = netlink_fd; |
| 443 | |
| 444 | memset(&(*hndl)->src_addr, 0, sizeof(struct sockaddr_nl)); |
| 445 | |
| 446 | (*hndl)->src_addr.nl_family = AF_NETLINK; |
| 447 | (*hndl)->src_addr.nl_pid = (*hndl)->pid; |
| 448 | |
Harout Hedeshian | 0bf0a17 | 2014-02-19 23:52:05 -0700 | [diff] [blame] | 449 | saddr_ptr = &(*hndl)->src_addr; |
Harout Hedeshian | b2fc5b1 | 2013-09-03 13:49:00 -0600 | [diff] [blame] | 450 | if (bind((*hndl)->netlink_fd, |
Harout Hedeshian | 0bf0a17 | 2014-02-19 23:52:05 -0700 | [diff] [blame] | 451 | (struct sockaddr*)saddr_ptr, |
Harout Hedeshian | b2fc5b1 | 2013-09-03 13:49:00 -0600 | [diff] [blame] | 452 | sizeof(struct sockaddr_nl)) < 0) { |
| 453 | close((*hndl)->netlink_fd); |
| 454 | free(*hndl); |
| 455 | *error_code = RMNETCTL_INIT_ERR_BIND; |
| 456 | break; |
| 457 | } |
| 458 | |
| 459 | memset(&(*hndl)->dest_addr, 0, sizeof(struct sockaddr_nl)); |
| 460 | |
| 461 | (*hndl)->dest_addr.nl_family = AF_NETLINK; |
| 462 | (*hndl)->dest_addr.nl_pid = KERNEL_PROCESS_ID; |
| 463 | (*hndl)->dest_addr.nl_groups = UNICAST; |
| 464 | |
| 465 | return_code = RMNETCTL_SUCCESS; |
| 466 | } while(0); |
| 467 | return return_code; |
| 468 | } |
| 469 | |
| 470 | void rmnetctl_cleanup(rmnetctl_hndl_t *hndl) |
| 471 | { |
| 472 | if (!hndl) |
| 473 | return; |
| 474 | close(hndl->netlink_fd); |
| 475 | free(hndl); |
| 476 | } |
| 477 | |
| 478 | int rmnet_associate_network_device(rmnetctl_hndl_t *hndl, |
| 479 | const char *dev_name, |
| 480 | uint16_t *error_code, |
| 481 | uint8_t assoc_dev) |
| 482 | { |
| 483 | struct rmnet_nl_msg_s request, response; |
Harout Hedeshian | 0bf0a17 | 2014-02-19 23:52:05 -0700 | [diff] [blame] | 484 | size_t str_len = 0; |
| 485 | int return_code = RMNETCTL_LIB_ERR; |
Harout Hedeshian | b2fc5b1 | 2013-09-03 13:49:00 -0600 | [diff] [blame] | 486 | do { |
| 487 | if ((!hndl) || (!error_code) || _rmnetctl_check_dev_name(dev_name) || |
| 488 | ((assoc_dev != RMNETCTL_DEVICE_ASSOCIATE) && |
| 489 | (assoc_dev != RMNETCTL_DEVICE_UNASSOCIATE))) { |
| 490 | return_code = RMNETCTL_INVALID_ARG; |
| 491 | break; |
| 492 | } |
| 493 | |
| 494 | if (assoc_dev == RMNETCTL_DEVICE_ASSOCIATE) |
| 495 | request.message_type = RMNET_NETLINK_ASSOCIATE_NETWORK_DEVICE; |
| 496 | else |
| 497 | request.message_type = RMNET_NETLINK_UNASSOCIATE_NETWORK_DEVICE; |
| 498 | |
| 499 | request.arg_length = RMNET_MAX_STR_LEN; |
Harout Hedeshian | 0bf0a17 | 2014-02-19 23:52:05 -0700 | [diff] [blame] | 500 | str_len = strlcpy((char *)(request.data), dev_name, (size_t)RMNET_MAX_STR_LEN); |
Harout Hedeshian | b2fc5b1 | 2013-09-03 13:49:00 -0600 | [diff] [blame] | 501 | if (_rmnetctl_check_len(str_len, error_code) != RMNETCTL_SUCCESS) |
| 502 | break; |
| 503 | |
| 504 | if ((*error_code = rmnetctl_transact(hndl, &request, &response)) |
| 505 | != RMNETCTL_SUCCESS) |
| 506 | break; |
| 507 | if (_rmnetctl_check_code(response.crd, error_code) != RMNETCTL_SUCCESS) |
| 508 | break; |
| 509 | return_code = _rmnetctl_set_codes(response.return_code, error_code); |
| 510 | } while(0); |
| 511 | return return_code; |
| 512 | } |
| 513 | |
| 514 | int rmnet_get_network_device_associated(rmnetctl_hndl_t *hndl, |
| 515 | const char *dev_name, |
| 516 | int *register_status, |
| 517 | uint16_t *error_code) { |
| 518 | struct rmnet_nl_msg_s request, response; |
Harout Hedeshian | 0bf0a17 | 2014-02-19 23:52:05 -0700 | [diff] [blame] | 519 | size_t str_len = 0; |
| 520 | int return_code = RMNETCTL_LIB_ERR; |
Harout Hedeshian | b2fc5b1 | 2013-09-03 13:49:00 -0600 | [diff] [blame] | 521 | do { |
| 522 | if ((!hndl) || (!register_status) || (!error_code) || |
| 523 | _rmnetctl_check_dev_name(dev_name)) { |
| 524 | return_code = RMNETCTL_INVALID_ARG; |
| 525 | break; |
| 526 | } |
| 527 | |
| 528 | request.message_type = RMNET_NETLINK_GET_NETWORK_DEVICE_ASSOCIATED; |
| 529 | |
| 530 | request.arg_length = RMNET_MAX_STR_LEN; |
| 531 | str_len = strlcpy((char *)(request.data), dev_name, RMNET_MAX_STR_LEN); |
| 532 | if (_rmnetctl_check_len(str_len, error_code) != RMNETCTL_SUCCESS) |
| 533 | break; |
| 534 | |
| 535 | if ((*error_code = rmnetctl_transact(hndl, &request, &response)) |
| 536 | != RMNETCTL_SUCCESS) |
| 537 | break; |
| 538 | |
Subash Abhinov Kasiviswanathan | d42712d | 2015-04-14 13:44:02 -0600 | [diff] [blame] | 539 | if (_rmnetctl_check_data(response.crd, error_code) |
| 540 | != RMNETCTL_SUCCESS) { |
| 541 | if (_rmnetctl_check_code(response.crd, error_code) |
| 542 | == RMNETCTL_SUCCESS) |
| 543 | return_code = _rmnetctl_set_codes(response.return_code, |
| 544 | error_code); |
Harout Hedeshian | b2fc5b1 | 2013-09-03 13:49:00 -0600 | [diff] [blame] | 545 | break; |
Subash Abhinov Kasiviswanathan | d42712d | 2015-04-14 13:44:02 -0600 | [diff] [blame] | 546 | } |
Harout Hedeshian | b2fc5b1 | 2013-09-03 13:49:00 -0600 | [diff] [blame] | 547 | |
| 548 | *register_status = response.return_code; |
| 549 | return_code = RMNETCTL_SUCCESS; |
| 550 | } while(0); |
| 551 | return return_code; |
| 552 | } |
| 553 | |
| 554 | int rmnet_set_link_egress_data_format(rmnetctl_hndl_t *hndl, |
| 555 | uint32_t egress_flags, |
| 556 | uint16_t agg_size, |
| 557 | uint16_t agg_count, |
| 558 | const char *dev_name, |
| 559 | uint16_t *error_code) { |
| 560 | struct rmnet_nl_msg_s request, response; |
Harout Hedeshian | 0bf0a17 | 2014-02-19 23:52:05 -0700 | [diff] [blame] | 561 | size_t str_len = 0; |
| 562 | int return_code = RMNETCTL_LIB_ERR; |
Harout Hedeshian | b2fc5b1 | 2013-09-03 13:49:00 -0600 | [diff] [blame] | 563 | do { |
Harout Hedeshian | 7782557 | 2014-02-17 10:47:14 +0200 | [diff] [blame] | 564 | if ((!hndl) || (!error_code) || _rmnetctl_check_dev_name(dev_name) || |
| 565 | ((~EGRESS_FLAGS_MASK) & egress_flags)) { |
Harout Hedeshian | b2fc5b1 | 2013-09-03 13:49:00 -0600 | [diff] [blame] | 566 | return_code = RMNETCTL_INVALID_ARG; |
| 567 | break; |
| 568 | } |
| 569 | |
| 570 | request.message_type = RMNET_NETLINK_SET_LINK_EGRESS_DATA_FORMAT; |
| 571 | |
| 572 | request.arg_length = RMNET_MAX_STR_LEN + |
| 573 | sizeof(uint32_t) + sizeof(uint16_t) + sizeof(uint16_t); |
| 574 | str_len = strlcpy((char *)(request.data_format.dev), |
| 575 | dev_name, |
| 576 | RMNET_MAX_STR_LEN); |
| 577 | if (_rmnetctl_check_len(str_len, error_code) != RMNETCTL_SUCCESS) |
| 578 | break; |
| 579 | |
| 580 | request.data_format.flags = egress_flags; |
| 581 | request.data_format.agg_size = agg_size; |
| 582 | request.data_format.agg_count = agg_count; |
| 583 | |
| 584 | if ((*error_code = rmnetctl_transact(hndl, &request, &response)) |
| 585 | != RMNETCTL_SUCCESS) |
| 586 | break; |
| 587 | |
| 588 | if (_rmnetctl_check_code(response.crd, error_code) != RMNETCTL_SUCCESS) |
| 589 | break; |
| 590 | |
| 591 | return_code = _rmnetctl_set_codes(response.return_code, error_code); |
| 592 | } while(0); |
| 593 | return return_code; |
| 594 | } |
| 595 | |
| 596 | int rmnet_get_link_egress_data_format(rmnetctl_hndl_t *hndl, |
| 597 | const char *dev_name, |
| 598 | uint32_t *egress_flags, |
| 599 | uint16_t *agg_size, |
| 600 | uint16_t *agg_count, |
| 601 | uint16_t *error_code) { |
| 602 | struct rmnet_nl_msg_s request, response; |
Harout Hedeshian | 0bf0a17 | 2014-02-19 23:52:05 -0700 | [diff] [blame] | 603 | size_t str_len = 0; |
| 604 | int return_code = RMNETCTL_LIB_ERR; |
Harout Hedeshian | b2fc5b1 | 2013-09-03 13:49:00 -0600 | [diff] [blame] | 605 | do { |
| 606 | if ((!hndl) || (!egress_flags) || (!agg_size) || (!agg_count) || |
| 607 | (!error_code) || _rmnetctl_check_dev_name(dev_name)) { |
| 608 | return_code = RMNETCTL_INVALID_ARG; |
| 609 | break; |
| 610 | } |
| 611 | request.message_type = RMNET_NETLINK_GET_LINK_EGRESS_DATA_FORMAT; |
| 612 | |
| 613 | request.arg_length = RMNET_MAX_STR_LEN; |
| 614 | str_len = strlcpy((char *)(request.data_format.dev), |
| 615 | dev_name, |
| 616 | RMNET_MAX_STR_LEN); |
| 617 | if (_rmnetctl_check_len(str_len, error_code) != RMNETCTL_SUCCESS) |
| 618 | break; |
| 619 | |
| 620 | if ((*error_code = rmnetctl_transact(hndl, &request, &response)) |
| 621 | != RMNETCTL_SUCCESS) |
| 622 | break; |
| 623 | |
Subash Abhinov Kasiviswanathan | d42712d | 2015-04-14 13:44:02 -0600 | [diff] [blame] | 624 | if (_rmnetctl_check_data(response.crd, error_code) |
| 625 | != RMNETCTL_SUCCESS) { |
| 626 | if (_rmnetctl_check_code(response.crd, error_code) |
| 627 | == RMNETCTL_SUCCESS) |
| 628 | return_code = _rmnetctl_set_codes(response.return_code, |
| 629 | error_code); |
Harout Hedeshian | b2fc5b1 | 2013-09-03 13:49:00 -0600 | [diff] [blame] | 630 | break; |
Subash Abhinov Kasiviswanathan | d42712d | 2015-04-14 13:44:02 -0600 | [diff] [blame] | 631 | } |
Harout Hedeshian | b2fc5b1 | 2013-09-03 13:49:00 -0600 | [diff] [blame] | 632 | |
| 633 | *egress_flags = response.data_format.flags; |
| 634 | *agg_size = response.data_format.agg_size; |
| 635 | *agg_count = response.data_format.agg_count; |
| 636 | return_code = RMNETCTL_SUCCESS; |
| 637 | } while(0); |
| 638 | return return_code; |
| 639 | } |
| 640 | |
Subash Abhinov Kasiviswanathan | 22fa388 | 2014-01-16 12:55:45 -0700 | [diff] [blame] | 641 | int rmnet_set_link_ingress_data_format_tailspace(rmnetctl_hndl_t *hndl, |
| 642 | uint32_t ingress_flags, |
| 643 | uint8_t tail_spacing, |
| 644 | const char *dev_name, |
| 645 | uint16_t *error_code) { |
Harout Hedeshian | b2fc5b1 | 2013-09-03 13:49:00 -0600 | [diff] [blame] | 646 | struct rmnet_nl_msg_s request, response; |
Harout Hedeshian | 0bf0a17 | 2014-02-19 23:52:05 -0700 | [diff] [blame] | 647 | size_t str_len = 0; |
| 648 | int return_code = RMNETCTL_LIB_ERR; |
Harout Hedeshian | b2fc5b1 | 2013-09-03 13:49:00 -0600 | [diff] [blame] | 649 | do { |
Harout Hedeshian | 7782557 | 2014-02-17 10:47:14 +0200 | [diff] [blame] | 650 | if ((!hndl) || (!error_code) || _rmnetctl_check_dev_name(dev_name) || |
| 651 | ((~INGRESS_FLAGS_MASK) & ingress_flags)) { |
Harout Hedeshian | b2fc5b1 | 2013-09-03 13:49:00 -0600 | [diff] [blame] | 652 | return_code = RMNETCTL_INVALID_ARG; |
| 653 | break; |
| 654 | } |
| 655 | |
| 656 | request.message_type = RMNET_NETLINK_SET_LINK_INGRESS_DATA_FORMAT; |
| 657 | |
| 658 | request.arg_length = RMNET_MAX_STR_LEN + |
| 659 | sizeof(uint32_t) + sizeof(uint16_t) + sizeof(uint16_t); |
| 660 | str_len = strlcpy((char *)(request.data_format.dev), |
| 661 | dev_name, |
| 662 | RMNET_MAX_STR_LEN); |
| 663 | if (_rmnetctl_check_len(str_len, error_code) != RMNETCTL_SUCCESS) |
| 664 | break; |
| 665 | request.data_format.flags = ingress_flags; |
Subash Abhinov Kasiviswanathan | 22fa388 | 2014-01-16 12:55:45 -0700 | [diff] [blame] | 666 | request.data_format.tail_spacing = tail_spacing; |
Harout Hedeshian | b2fc5b1 | 2013-09-03 13:49:00 -0600 | [diff] [blame] | 667 | |
| 668 | if ((*error_code = rmnetctl_transact(hndl, &request, &response)) |
| 669 | != RMNETCTL_SUCCESS) |
| 670 | break; |
| 671 | |
| 672 | if (_rmnetctl_check_code(response.crd, error_code) != RMNETCTL_SUCCESS) |
| 673 | break; |
| 674 | |
| 675 | return_code = _rmnetctl_set_codes(response.return_code, error_code); |
| 676 | } while(0); |
| 677 | return return_code; |
| 678 | } |
| 679 | |
Subash Abhinov Kasiviswanathan | 22fa388 | 2014-01-16 12:55:45 -0700 | [diff] [blame] | 680 | int rmnet_get_link_ingress_data_format_tailspace(rmnetctl_hndl_t *hndl, |
| 681 | const char *dev_name, |
| 682 | uint32_t *ingress_flags, |
| 683 | uint8_t *tail_spacing, |
| 684 | uint16_t *error_code) { |
Harout Hedeshian | b2fc5b1 | 2013-09-03 13:49:00 -0600 | [diff] [blame] | 685 | struct rmnet_nl_msg_s request, response; |
Harout Hedeshian | 0bf0a17 | 2014-02-19 23:52:05 -0700 | [diff] [blame] | 686 | size_t str_len = 0; |
| 687 | int return_code = RMNETCTL_LIB_ERR; |
Harout Hedeshian | b2fc5b1 | 2013-09-03 13:49:00 -0600 | [diff] [blame] | 688 | do { |
Subash Abhinov Kasiviswanathan | 22fa388 | 2014-01-16 12:55:45 -0700 | [diff] [blame] | 689 | if ((!hndl) || (!error_code) || |
Harout Hedeshian | b2fc5b1 | 2013-09-03 13:49:00 -0600 | [diff] [blame] | 690 | _rmnetctl_check_dev_name(dev_name)) { |
| 691 | return_code = RMNETCTL_INVALID_ARG; |
| 692 | break; |
| 693 | } |
| 694 | |
| 695 | request.message_type = RMNET_NETLINK_GET_LINK_INGRESS_DATA_FORMAT; |
| 696 | |
| 697 | request.arg_length = RMNET_MAX_STR_LEN; |
| 698 | str_len = strlcpy((char *)(request.data_format.dev), |
| 699 | dev_name, |
| 700 | RMNET_MAX_STR_LEN); |
| 701 | if (_rmnetctl_check_len(str_len, error_code) != RMNETCTL_SUCCESS) |
| 702 | break; |
| 703 | |
| 704 | if ((*error_code = rmnetctl_transact(hndl, &request, &response)) |
| 705 | != RMNETCTL_SUCCESS) |
| 706 | break; |
| 707 | |
Subash Abhinov Kasiviswanathan | d42712d | 2015-04-14 13:44:02 -0600 | [diff] [blame] | 708 | if (_rmnetctl_check_data(response.crd, error_code) |
| 709 | != RMNETCTL_SUCCESS) { |
| 710 | if (_rmnetctl_check_code(response.crd, error_code) |
| 711 | == RMNETCTL_SUCCESS) |
| 712 | return_code = _rmnetctl_set_codes(response.return_code, |
| 713 | error_code); |
Harout Hedeshian | b2fc5b1 | 2013-09-03 13:49:00 -0600 | [diff] [blame] | 714 | break; |
Subash Abhinov Kasiviswanathan | d42712d | 2015-04-14 13:44:02 -0600 | [diff] [blame] | 715 | } |
Harout Hedeshian | b2fc5b1 | 2013-09-03 13:49:00 -0600 | [diff] [blame] | 716 | |
Subash Abhinov Kasiviswanathan | 22fa388 | 2014-01-16 12:55:45 -0700 | [diff] [blame] | 717 | if (ingress_flags) |
| 718 | *ingress_flags = response.data_format.flags; |
| 719 | |
| 720 | if (tail_spacing) |
| 721 | *tail_spacing = response.data_format.tail_spacing; |
| 722 | |
Harout Hedeshian | b2fc5b1 | 2013-09-03 13:49:00 -0600 | [diff] [blame] | 723 | return_code = RMNETCTL_SUCCESS; |
| 724 | } while(0); |
| 725 | return return_code; |
| 726 | } |
| 727 | |
| 728 | int rmnet_set_logical_ep_config(rmnetctl_hndl_t *hndl, |
| 729 | int32_t ep_id, |
| 730 | uint8_t operating_mode, |
| 731 | const char *dev_name, |
| 732 | const char *next_dev, |
| 733 | uint16_t *error_code) { |
| 734 | struct rmnet_nl_msg_s request, response; |
Harout Hedeshian | 0bf0a17 | 2014-02-19 23:52:05 -0700 | [diff] [blame] | 735 | size_t str_len = 0; |
| 736 | int return_code = RMNETCTL_LIB_ERR; |
Harout Hedeshian | b2fc5b1 | 2013-09-03 13:49:00 -0600 | [diff] [blame] | 737 | do { |
| 738 | if ((!hndl) || ((ep_id < -1) || (ep_id > 31)) || (!error_code) || |
| 739 | _rmnetctl_check_dev_name(dev_name) || |
Harout Hedeshian | 7782557 | 2014-02-17 10:47:14 +0200 | [diff] [blame] | 740 | _rmnetctl_check_dev_name(next_dev) || |
| 741 | operating_mode >= RMNET_EPMODE_LENGTH) { |
Harout Hedeshian | b2fc5b1 | 2013-09-03 13:49:00 -0600 | [diff] [blame] | 742 | return_code = RMNETCTL_INVALID_ARG; |
| 743 | break; |
| 744 | } |
| 745 | |
| 746 | request.message_type = RMNET_NETLINK_SET_LOGICAL_EP_CONFIG; |
| 747 | |
| 748 | request.arg_length = RMNET_MAX_STR_LEN + |
| 749 | RMNET_MAX_STR_LEN + sizeof(int32_t) + sizeof(uint8_t); |
| 750 | str_len = strlcpy((char *)(request.local_ep_config.dev), |
| 751 | dev_name, |
| 752 | RMNET_MAX_STR_LEN); |
| 753 | if (_rmnetctl_check_len(str_len, error_code) != RMNETCTL_SUCCESS) |
| 754 | break; |
| 755 | |
| 756 | str_len = strlcpy((char *)(request.local_ep_config.next_dev), |
| 757 | next_dev, |
| 758 | RMNET_MAX_STR_LEN); |
| 759 | if (_rmnetctl_check_len(str_len, error_code) != RMNETCTL_SUCCESS) |
| 760 | break; |
| 761 | request.local_ep_config.ep_id = ep_id; |
| 762 | request.local_ep_config.operating_mode = operating_mode; |
| 763 | |
| 764 | if ((*error_code = rmnetctl_transact(hndl, &request, &response)) |
| 765 | != RMNETCTL_SUCCESS) |
| 766 | break; |
| 767 | if (_rmnetctl_check_code(response.crd, error_code) != RMNETCTL_SUCCESS) |
| 768 | break; |
| 769 | |
| 770 | return_code = _rmnetctl_set_codes(response.return_code, error_code); |
| 771 | } while(0); |
| 772 | return return_code; |
| 773 | } |
| 774 | |
Harout Hedeshian | a973165 | 2014-01-06 18:00:23 +0200 | [diff] [blame] | 775 | int rmnet_unset_logical_ep_config(rmnetctl_hndl_t *hndl, |
| 776 | int32_t ep_id, |
| 777 | const char *dev_name, |
| 778 | uint16_t *error_code) { |
| 779 | struct rmnet_nl_msg_s request, response; |
Harout Hedeshian | 0bf0a17 | 2014-02-19 23:52:05 -0700 | [diff] [blame] | 780 | size_t str_len = 0; |
| 781 | int return_code = RMNETCTL_LIB_ERR; |
Harout Hedeshian | a973165 | 2014-01-06 18:00:23 +0200 | [diff] [blame] | 782 | do { |
| 783 | |
| 784 | if ((!hndl) || ((ep_id < -1) || (ep_id > 31)) || (!error_code) || |
| 785 | _rmnetctl_check_dev_name(dev_name)) { |
| 786 | return_code = RMNETCTL_INVALID_ARG; |
| 787 | break; |
| 788 | } |
| 789 | |
| 790 | request.message_type = RMNET_NETLINK_UNSET_LOGICAL_EP_CONFIG; |
| 791 | |
| 792 | request.arg_length = RMNET_MAX_STR_LEN + sizeof(int32_t); |
| 793 | str_len = strlcpy((char *)(request.local_ep_config.dev), |
| 794 | dev_name, |
| 795 | RMNET_MAX_STR_LEN); |
| 796 | |
| 797 | if (_rmnetctl_check_len(str_len, error_code) != RMNETCTL_SUCCESS) |
| 798 | break; |
| 799 | |
| 800 | request.local_ep_config.ep_id = ep_id; |
| 801 | |
| 802 | if ((*error_code = rmnetctl_transact(hndl, &request, &response)) |
| 803 | != RMNETCTL_SUCCESS) |
| 804 | break; |
| 805 | if (_rmnetctl_check_code(response.crd, error_code) != RMNETCTL_SUCCESS) |
| 806 | break; |
| 807 | |
| 808 | return_code = _rmnetctl_set_codes(response.return_code, error_code); |
| 809 | } while(0); |
| 810 | |
| 811 | return return_code; |
| 812 | } |
| 813 | |
Harout Hedeshian | b2fc5b1 | 2013-09-03 13:49:00 -0600 | [diff] [blame] | 814 | int rmnet_get_logical_ep_config(rmnetctl_hndl_t *hndl, |
| 815 | int32_t ep_id, |
| 816 | const char *dev_name, |
| 817 | uint8_t *operating_mode, |
| 818 | char **next_dev, |
Harout Hedeshian | 7782557 | 2014-02-17 10:47:14 +0200 | [diff] [blame] | 819 | uint32_t next_dev_len, |
Harout Hedeshian | b2fc5b1 | 2013-09-03 13:49:00 -0600 | [diff] [blame] | 820 | uint16_t *error_code) { |
| 821 | struct rmnet_nl_msg_s request, response; |
Harout Hedeshian | 0bf0a17 | 2014-02-19 23:52:05 -0700 | [diff] [blame] | 822 | size_t str_len = 0; |
| 823 | int return_code = RMNETCTL_LIB_ERR; |
Harout Hedeshian | b2fc5b1 | 2013-09-03 13:49:00 -0600 | [diff] [blame] | 824 | do { |
| 825 | if ((!hndl) || (!operating_mode) || (!error_code) || ((ep_id < -1) || |
Harout Hedeshian | 7782557 | 2014-02-17 10:47:14 +0200 | [diff] [blame] | 826 | (ep_id > 31)) || _rmnetctl_check_dev_name(dev_name) || (!next_dev) |
| 827 | || (0 == next_dev_len)) { |
Harout Hedeshian | b2fc5b1 | 2013-09-03 13:49:00 -0600 | [diff] [blame] | 828 | return_code = RMNETCTL_INVALID_ARG; |
| 829 | break; |
| 830 | } |
| 831 | |
| 832 | request.message_type = RMNET_NETLINK_GET_LOGICAL_EP_CONFIG; |
| 833 | |
| 834 | request.arg_length = RMNET_MAX_STR_LEN + sizeof(int32_t); |
| 835 | str_len = strlcpy((char *)(request.local_ep_config.dev), |
| 836 | dev_name, |
| 837 | RMNET_MAX_STR_LEN); |
| 838 | if (_rmnetctl_check_len(str_len, error_code) != RMNETCTL_SUCCESS) |
| 839 | break; |
| 840 | |
| 841 | request.local_ep_config.ep_id = ep_id; |
| 842 | |
| 843 | if ((*error_code = rmnetctl_transact(hndl, &request, &response)) |
| 844 | != RMNETCTL_SUCCESS) |
| 845 | break; |
Subash Abhinov Kasiviswanathan | d42712d | 2015-04-14 13:44:02 -0600 | [diff] [blame] | 846 | |
| 847 | if (_rmnetctl_check_data(response.crd, error_code) |
| 848 | != RMNETCTL_SUCCESS) { |
| 849 | if (_rmnetctl_check_code(response.crd, error_code) |
| 850 | == RMNETCTL_SUCCESS) |
| 851 | return_code = _rmnetctl_set_codes(response.return_code, |
| 852 | error_code); |
Harout Hedeshian | b2fc5b1 | 2013-09-03 13:49:00 -0600 | [diff] [blame] | 853 | break; |
Subash Abhinov Kasiviswanathan | d42712d | 2015-04-14 13:44:02 -0600 | [diff] [blame] | 854 | } |
Harout Hedeshian | 7782557 | 2014-02-17 10:47:14 +0200 | [diff] [blame] | 855 | |
Harout Hedeshian | b2fc5b1 | 2013-09-03 13:49:00 -0600 | [diff] [blame] | 856 | str_len = strlcpy(*next_dev, |
| 857 | (char *)(response.local_ep_config.next_dev), |
Harout Hedeshian | 7782557 | 2014-02-17 10:47:14 +0200 | [diff] [blame] | 858 | min(RMNET_MAX_STR_LEN, next_dev_len)); |
Harout Hedeshian | b2fc5b1 | 2013-09-03 13:49:00 -0600 | [diff] [blame] | 859 | if (_rmnetctl_check_len(str_len, error_code) != RMNETCTL_SUCCESS) |
| 860 | break; |
| 861 | |
| 862 | *operating_mode = response.local_ep_config.operating_mode; |
| 863 | return_code = RMNETCTL_SUCCESS; |
| 864 | } while(0); |
| 865 | return return_code; |
| 866 | } |
| 867 | |
Harout Hedeshian | 89a91e2 | 2013-10-09 08:59:47 -0600 | [diff] [blame] | 868 | int rmnet_new_vnd_prefix(rmnetctl_hndl_t *hndl, |
| 869 | uint32_t id, |
| 870 | uint16_t *error_code, |
| 871 | uint8_t new_vnd, |
| 872 | const char *prefix) |
| 873 | { |
Harout Hedeshian | b2fc5b1 | 2013-09-03 13:49:00 -0600 | [diff] [blame] | 874 | struct rmnet_nl_msg_s request, response; |
| 875 | int return_code = RMNETCTL_LIB_ERR; |
Harout Hedeshian | 0bf0a17 | 2014-02-19 23:52:05 -0700 | [diff] [blame] | 876 | size_t str_len = 0; |
Harout Hedeshian | b2fc5b1 | 2013-09-03 13:49:00 -0600 | [diff] [blame] | 877 | do { |
| 878 | if ((!hndl) || (!error_code) || |
| 879 | ((new_vnd != RMNETCTL_NEW_VND) && (new_vnd != RMNETCTL_FREE_VND))) { |
| 880 | return_code = RMNETCTL_INVALID_ARG; |
| 881 | break; |
| 882 | } |
Harout Hedeshian | 89a91e2 | 2013-10-09 08:59:47 -0600 | [diff] [blame] | 883 | |
| 884 | memset(request.vnd.vnd_name, 0, RMNET_MAX_STR_LEN); |
| 885 | if (new_vnd == RMNETCTL_NEW_VND) { |
| 886 | if (prefix) { |
| 887 | request.message_type =RMNET_NETLINK_NEW_VND_WITH_PREFIX; |
| 888 | str_len = strlcpy((char *)request.vnd.vnd_name, |
| 889 | prefix, RMNET_MAX_STR_LEN); |
| 890 | if (_rmnetctl_check_len(str_len, error_code) |
| 891 | != RMNETCTL_SUCCESS) |
| 892 | break; |
| 893 | } else { |
| 894 | request.message_type = RMNET_NETLINK_NEW_VND; |
| 895 | } |
| 896 | } else { |
Harout Hedeshian | b2fc5b1 | 2013-09-03 13:49:00 -0600 | [diff] [blame] | 897 | request.message_type = RMNET_NETLINK_FREE_VND; |
Harout Hedeshian | 89a91e2 | 2013-10-09 08:59:47 -0600 | [diff] [blame] | 898 | } |
Harout Hedeshian | b2fc5b1 | 2013-09-03 13:49:00 -0600 | [diff] [blame] | 899 | |
| 900 | request.arg_length = sizeof(uint32_t); |
| 901 | request.vnd.id = id; |
| 902 | |
| 903 | if ((*error_code = rmnetctl_transact(hndl, &request, &response)) |
| 904 | != RMNETCTL_SUCCESS) |
| 905 | break; |
| 906 | if (_rmnetctl_check_code(response.crd, error_code) != RMNETCTL_SUCCESS) |
| 907 | break; |
| 908 | |
| 909 | return_code = _rmnetctl_set_codes(response.return_code, error_code); |
| 910 | } while(0); |
| 911 | return return_code; |
| 912 | } |
Harout Hedeshian | 89a91e2 | 2013-10-09 08:59:47 -0600 | [diff] [blame] | 913 | |
Subash Abhinov Kasiviswanathan | dba447c | 2017-02-23 17:58:09 -0700 | [diff] [blame] | 914 | int rmnet_new_vnd_name(rmnetctl_hndl_t *hndl, |
| 915 | uint32_t id, |
| 916 | uint16_t *error_code, |
| 917 | const char *prefix) |
| 918 | { |
| 919 | struct rmnet_nl_msg_s request, response; |
| 920 | int return_code = RMNETCTL_LIB_ERR; |
| 921 | size_t str_len = 0; |
| 922 | do { |
| 923 | if ((!hndl) || (!error_code)) { |
| 924 | return_code = RMNETCTL_INVALID_ARG; |
| 925 | break; |
| 926 | } |
| 927 | |
| 928 | memset(request.vnd.vnd_name, 0, RMNET_MAX_STR_LEN); |
| 929 | if (prefix) { |
| 930 | request.message_type =RMNET_NETLINK_NEW_VND_WITH_NAME; |
| 931 | str_len = strlcpy((char *)request.vnd.vnd_name, |
| 932 | prefix, RMNET_MAX_STR_LEN); |
| 933 | if (_rmnetctl_check_len(str_len, error_code) |
| 934 | != RMNETCTL_SUCCESS) |
| 935 | break; |
| 936 | } else { |
| 937 | request.message_type = RMNET_NETLINK_NEW_VND; |
| 938 | } |
| 939 | |
| 940 | request.arg_length = sizeof(uint32_t); |
| 941 | request.vnd.id = id; |
| 942 | |
| 943 | if ((*error_code = rmnetctl_transact(hndl, &request, &response)) |
| 944 | != RMNETCTL_SUCCESS) |
| 945 | break; |
| 946 | if (_rmnetctl_check_code(response.crd, error_code) != RMNETCTL_SUCCESS) |
| 947 | break; |
| 948 | |
| 949 | return_code = _rmnetctl_set_codes(response.return_code, error_code); |
| 950 | } while(0); |
| 951 | return return_code; |
| 952 | } |
| 953 | |
Harout Hedeshian | 89a91e2 | 2013-10-09 08:59:47 -0600 | [diff] [blame] | 954 | int rmnet_new_vnd(rmnetctl_hndl_t *hndl, |
| 955 | uint32_t id, |
| 956 | uint16_t *error_code, |
| 957 | uint8_t new_vnd) |
| 958 | { |
| 959 | return rmnet_new_vnd_prefix(hndl, id, error_code, new_vnd, 0); |
| 960 | } |
| 961 | |
| 962 | int rmnet_get_vnd_name(rmnetctl_hndl_t *hndl, |
| 963 | uint32_t id, |
| 964 | uint16_t *error_code, |
| 965 | char *buf, |
| 966 | uint32_t buflen) |
| 967 | { |
| 968 | struct rmnet_nl_msg_s request, response; |
| 969 | uint32_t str_len; |
| 970 | int return_code = RMNETCTL_LIB_ERR; |
| 971 | do { |
Harout Hedeshian | 7782557 | 2014-02-17 10:47:14 +0200 | [diff] [blame] | 972 | if ((!hndl) || (!error_code) || (!buf) || (0 == buflen)) { |
Harout Hedeshian | 89a91e2 | 2013-10-09 08:59:47 -0600 | [diff] [blame] | 973 | return_code = RMNETCTL_INVALID_ARG; |
| 974 | break; |
| 975 | } |
| 976 | |
| 977 | request.message_type = RMNET_NETLINK_GET_VND_NAME; |
| 978 | request.arg_length = sizeof(uint32_t); |
| 979 | request.vnd.id = id; |
| 980 | |
| 981 | |
| 982 | if ((*error_code = rmnetctl_transact(hndl, &request, &response)) |
| 983 | != RMNETCTL_SUCCESS) |
| 984 | break; |
Subash Abhinov Kasiviswanathan | d42712d | 2015-04-14 13:44:02 -0600 | [diff] [blame] | 985 | |
| 986 | if (_rmnetctl_check_data(response.crd, error_code) |
| 987 | != RMNETCTL_SUCCESS) { |
| 988 | if (_rmnetctl_check_code(response.crd, error_code) |
| 989 | == RMNETCTL_SUCCESS) |
| 990 | return_code = _rmnetctl_set_codes(response.return_code, |
| 991 | error_code); |
Harout Hedeshian | 89a91e2 | 2013-10-09 08:59:47 -0600 | [diff] [blame] | 992 | break; |
Subash Abhinov Kasiviswanathan | d42712d | 2015-04-14 13:44:02 -0600 | [diff] [blame] | 993 | } |
Harout Hedeshian | 89a91e2 | 2013-10-09 08:59:47 -0600 | [diff] [blame] | 994 | |
Harout Hedeshian | 0bf0a17 | 2014-02-19 23:52:05 -0700 | [diff] [blame] | 995 | str_len = (uint32_t)strlcpy(buf, |
Harout Hedeshian | 89a91e2 | 2013-10-09 08:59:47 -0600 | [diff] [blame] | 996 | (char *)(response.vnd.vnd_name), |
| 997 | buflen); |
| 998 | if (str_len >= buflen) { |
| 999 | *error_code = RMNETCTL_API_ERR_STRING_TRUNCATION; |
| 1000 | break; |
| 1001 | } |
| 1002 | |
| 1003 | return_code = RMNETCTL_SUCCESS; |
| 1004 | } while (0); |
| 1005 | return return_code; |
| 1006 | } |
| 1007 | |
Harout Hedeshian | 97a1e98 | 2013-11-08 09:28:53 -0700 | [diff] [blame] | 1008 | int rmnet_add_del_vnd_tc_flow(rmnetctl_hndl_t *hndl, |
| 1009 | uint32_t id, |
| 1010 | uint32_t map_flow_id, |
| 1011 | uint32_t tc_flow_id, |
| 1012 | uint8_t set_flow, |
| 1013 | uint16_t *error_code) { |
| 1014 | struct rmnet_nl_msg_s request, response; |
| 1015 | int return_code = RMNETCTL_LIB_ERR; |
| 1016 | do { |
Harout Hedeshian | 7782557 | 2014-02-17 10:47:14 +0200 | [diff] [blame] | 1017 | if ((!hndl) || (!error_code) || ((set_flow != RMNETCTL_ADD_FLOW) && |
| 1018 | (set_flow != RMNETCTL_DEL_FLOW))) { |
Harout Hedeshian | 97a1e98 | 2013-11-08 09:28:53 -0700 | [diff] [blame] | 1019 | return_code = RMNETCTL_INVALID_ARG; |
| 1020 | break; |
| 1021 | } |
| 1022 | if (set_flow == RMNETCTL_ADD_FLOW) |
| 1023 | request.message_type = RMNET_NETLINK_ADD_VND_TC_FLOW; |
| 1024 | else |
| 1025 | request.message_type = RMNET_NETLINK_DEL_VND_TC_FLOW; |
| 1026 | |
| 1027 | request.arg_length = (sizeof(uint32_t))*3; |
| 1028 | request.flow_control.id = id; |
| 1029 | request.flow_control.map_flow_id = map_flow_id; |
| 1030 | request.flow_control.tc_flow_id = tc_flow_id; |
| 1031 | |
| 1032 | if ((*error_code = rmnetctl_transact(hndl, &request, &response)) |
| 1033 | != RMNETCTL_SUCCESS) |
| 1034 | break; |
| 1035 | if (_rmnetctl_check_code(response.crd, error_code) != RMNETCTL_SUCCESS) |
| 1036 | break; |
| 1037 | return_code = _rmnetctl_set_codes(response.return_code, error_code); |
| 1038 | } while(0); |
| 1039 | return return_code; |
| 1040 | } |
| 1041 | |
Subash Abhinov Kasiviswanathan | 5b903dd | 2017-12-20 19:11:40 -0700 | [diff] [blame] | 1042 | /* |
| 1043 | * NEW DRIVER API |
| 1044 | */ |
Sean Tranchetti | 51133f5 | 2019-02-12 12:54:34 -0700 | [diff] [blame] | 1045 | |
| 1046 | /* @brief Add a Routing Attribute to a Netlink message |
| 1047 | * @param *req The Netlink message we're adding to |
| 1048 | * @param *reqsize The remaining space within the Netlink message |
| 1049 | * @param type The type of the RTA to add |
| 1050 | * @param len The length of the RTA data to add |
| 1051 | * @param *data A pointer to the RTA data to add |
| 1052 | * @return RMNETCTL_LIB_ERR if there is not enough space to add the RTA |
| 1053 | * @return RMNETCTL_SUCCESS if we added the RTA successfully |
| 1054 | */ |
| 1055 | static int rta_put(struct nlmsg *req, size_t *reqsize, int type, int len, |
| 1056 | void *data) |
| 1057 | { |
| 1058 | struct rtattr *attr = NLMSG_TAIL(&req->nl_addr); |
| 1059 | |
| 1060 | attr->rta_type = type; |
| 1061 | attr->rta_len = RTA_LENGTH(len); |
| 1062 | CHECK_MEMSCPY(memscpy_repeat(RTA_DATA(attr), reqsize, data, len)); |
| 1063 | req->nl_addr.nlmsg_len = NLMSG_ALIGN(req->nl_addr.nlmsg_len) + |
| 1064 | RTA_ALIGN(attr->rta_len); |
| 1065 | |
| 1066 | return RMNETCTL_SUCCESS; |
| 1067 | } |
Sean Tranchetti | 6e3d523 | 2019-02-12 13:46:42 -0700 | [diff] [blame] | 1068 | |
| 1069 | /* @brief Add an RTA to the Netlink message with a u16 data |
| 1070 | * @param *req The Netlink message |
| 1071 | * @param *reqsize The remainins space within the Netlink message |
| 1072 | * @param type The type of the RTA to add |
| 1073 | * @param data The data of the RTA |
| 1074 | * @rteturn RMNETCTL_LIB_ERR if there is not enough space to add the RTA |
| 1075 | * @return RMNETCTL_SUCCESS if we added the RTA successfully |
| 1076 | */ |
| 1077 | static int rta_put_u16(struct nlmsg *req, size_t *reqsize, int type, |
| 1078 | uint16_t data) |
| 1079 | { |
| 1080 | return rta_put(req, reqsize, type, sizeof(data), &data); |
| 1081 | } |
| 1082 | |
| 1083 | /* @brief Add an RTA to the Netlink message with a u32 data |
| 1084 | * @param *req The Netlink message |
| 1085 | * @param *reqsize The remainins space within the Netlink message |
| 1086 | * @param type The type of the RTA to add |
| 1087 | * @param data The data of the RTA |
| 1088 | * @rteturn RMNETCTL_LIB_ERR if there is not enough space to add the RTA |
| 1089 | * @return RMNETCTL_SUCCESS if we added the RTA successfully |
| 1090 | */ |
| 1091 | static int rta_put_u32(struct nlmsg *req, size_t *reqsize, int type, |
| 1092 | uint32_t data) |
| 1093 | { |
| 1094 | return rta_put(req, reqsize, type, sizeof(data), &data); |
| 1095 | } |
| 1096 | |
| 1097 | /* @brief Add an RTA to the Netlink message with string data |
| 1098 | * @param *req The Netlink message |
| 1099 | * @param *reqsize The remainins space within the Netlink message |
| 1100 | * @param type The type of the RTA to add |
| 1101 | * @param *data The data of the RTA |
| 1102 | * @rteturn RMNETCTL_LIB_ERR if there is not enough space to add the RTA |
| 1103 | * @return RMNETCTL_SUCCESS if we added the RTA successfully |
| 1104 | */ |
| 1105 | static int rta_put_string(struct nlmsg *req, size_t *reqsize, int type, |
| 1106 | char *data) |
| 1107 | { |
| 1108 | return rta_put(req, reqsize, type, strlen(data) + 1, data); |
| 1109 | } |
| 1110 | |
| 1111 | /* @brief Start a nested RTA within the Netlink message |
| 1112 | * @param *req The Netlink message |
| 1113 | * @param *reqsize The remainins space within the Netlink message |
| 1114 | * @param type The type of the RTA to add |
| 1115 | * @param **start A pointer where we store the start of the ensted attribute |
| 1116 | * @rteturn RMNETCTL_LIB_ERR if there is not enough space to add the RTA |
| 1117 | * @return RMNETCTL_SUCCESS if we added the RTA successfully |
| 1118 | */ |
| 1119 | static int rta_nested_start(struct nlmsg *req, size_t *reqsize, int type, |
| 1120 | struct rtattr **start) |
| 1121 | { |
| 1122 | *start = NLMSG_TAIL(&req->nl_addr); |
| 1123 | return rta_put(req, reqsize, type, 0, NULL); |
| 1124 | } |
| 1125 | |
| 1126 | /* @brief End a nested RTA previously started with rta_nested_start |
| 1127 | * @param *req The Netlink message |
| 1128 | * @param *start The start of the nested RTA, as provided by rta_nested_start |
| 1129 | */ |
| 1130 | static void rta_nested_end(struct nlmsg *req, struct rtattr *start) |
| 1131 | { |
| 1132 | start->rta_len = (char *)NLMSG_TAIL(&req->nl_addr) - (char *)start; |
| 1133 | } |
| 1134 | |
Sean Tranchetti | 1a2abef | 2019-01-03 14:33:16 -0700 | [diff] [blame] | 1135 | static void rta_parse(struct rtattr **tb, int maxtype, struct rtattr *head, |
| 1136 | int len) |
| 1137 | { |
| 1138 | struct rtattr *rta; |
| 1139 | |
| 1140 | memset(tb, 0, sizeof(struct rtattr *) * maxtype); |
| 1141 | for (rta = head; RTA_OK(rta, len); |
| 1142 | rta = RTA_NEXT(rta, len)) { |
| 1143 | __u16 type = rta->rta_type & NLA_TYPE_MASK; |
| 1144 | |
Subash Abhinov Kasiviswanathan | 0fb7abe | 2020-06-03 15:05:44 -0700 | [diff] [blame] | 1145 | if (type > 0 && type < maxtype) |
Sean Tranchetti | 1a2abef | 2019-01-03 14:33:16 -0700 | [diff] [blame] | 1146 | tb[type] = rta; |
| 1147 | } |
| 1148 | } |
| 1149 | |
| 1150 | static struct rtattr *rta_find(struct rtattr *rta, int attrlen, uint16_t type) |
| 1151 | { |
| 1152 | for (; RTA_OK(rta, attrlen); rta = RTA_NEXT(rta, attrlen)) { |
| 1153 | if (rta->rta_type == (type & NLA_TYPE_MASK)) |
| 1154 | return rta; |
| 1155 | } |
| 1156 | |
| 1157 | return NULL; |
| 1158 | } |
| 1159 | |
Sean Tranchetti | 37a08ec | 2019-02-12 15:22:50 -0700 | [diff] [blame] | 1160 | /* @brief Fill a Netlink messages with the necessary common RTAs for creating a |
| 1161 | * RTM_NEWLINK message for creating or changing rmnet devices. |
| 1162 | * @param *req The netlink message |
| 1163 | * @param *reqsize The remaining space within the Netlink message |
| 1164 | * @param devindex The ifindex of the physical device |
| 1165 | * @param *vndname The name of the rmnet device |
| 1166 | * @param index The MUX ID of the rmnet device |
| 1167 | * @param flagconfig The dataformat flags for the rmnet device |
| 1168 | * @return RMNETCTL_LIB_ERR if there is not enough space to add all RTAs |
| 1169 | * @return RMNETCTL_SUCCESS if everything was added successfully |
| 1170 | */ |
| 1171 | static int rmnet_fill_newlink_msg(struct nlmsg *req, size_t *reqsize, |
| 1172 | unsigned int devindex, char *vndname, |
| 1173 | uint8_t index, uint32_t flagconfig) |
| 1174 | { |
| 1175 | struct rtattr *linkinfo, *datainfo; |
| 1176 | struct ifla_vlan_flags flags; |
| 1177 | int rc; |
| 1178 | |
| 1179 | /* Set up link attr with devindex as data */ |
| 1180 | rc = rta_put_u32(req, reqsize, IFLA_LINK, devindex); |
| 1181 | if (rc != RMNETCTL_SUCCESS) |
| 1182 | return rc; |
| 1183 | |
| 1184 | rc = rta_put_string(req, reqsize, IFLA_IFNAME, vndname); |
| 1185 | if (rc != RMNETCTL_SUCCESS) |
| 1186 | return rc; |
| 1187 | |
| 1188 | /* Set up info kind RMNET that has linkinfo and type */ |
| 1189 | rc = rta_nested_start(req, reqsize, IFLA_LINKINFO, &linkinfo); |
| 1190 | if (rc != RMNETCTL_SUCCESS) |
| 1191 | return rc; |
| 1192 | |
| 1193 | rc = rta_put_string(req, reqsize, IFLA_INFO_KIND, "rmnet"); |
| 1194 | if (rc != RMNETCTL_SUCCESS) |
| 1195 | return rc; |
| 1196 | |
| 1197 | rc = rta_nested_start(req, reqsize, IFLA_INFO_DATA, &datainfo); |
| 1198 | if (rc != RMNETCTL_SUCCESS) |
| 1199 | return rc; |
| 1200 | |
Sean Tranchetti | 037065c | 2019-04-19 11:04:43 -0600 | [diff] [blame] | 1201 | rc = rta_put_u16(req, reqsize, RMNETCTL_IFLA_MUX_ID, index); |
Sean Tranchetti | 37a08ec | 2019-02-12 15:22:50 -0700 | [diff] [blame] | 1202 | if (rc != RMNETCTL_SUCCESS) |
| 1203 | return rc; |
| 1204 | |
| 1205 | if (flagconfig != 0) { |
| 1206 | flags.mask = flagconfig; |
| 1207 | flags.flags = flagconfig; |
| 1208 | |
Sean Tranchetti | 037065c | 2019-04-19 11:04:43 -0600 | [diff] [blame] | 1209 | rc = rta_put(req, reqsize, RMNETCTL_IFLA_FLAGS, sizeof(flags), |
Sean Tranchetti | 37a08ec | 2019-02-12 15:22:50 -0700 | [diff] [blame] | 1210 | &flags); |
| 1211 | if (rc != RMNETCTL_SUCCESS) |
| 1212 | return rc; |
| 1213 | } |
| 1214 | |
| 1215 | rta_nested_end(req, datainfo); |
| 1216 | rta_nested_end(req, linkinfo); |
| 1217 | |
| 1218 | return RMNETCTL_SUCCESS; |
| 1219 | } |
| 1220 | |
Sean Tranchetti | d9d69eb | 2019-02-12 14:30:49 -0700 | [diff] [blame] | 1221 | /* @brief Add all necessary RTA elements to a Netlink message suitable for |
| 1222 | * sending to the DFC driver |
| 1223 | * @param *req The Netlink message |
| 1224 | * @param *reqsize The remaining space in the Netlink message |
| 1225 | * @param devindex The ifindex of the real physical device |
| 1226 | * @param *vndname The name of the VND we're modifying |
| 1227 | * @param *flowinfo The parameters sent to the DFC driver |
| 1228 | * @return RMENTCTL_LIB_ERR if there is not enough space to add the RTAs |
| 1229 | * @return RMNETCTL_SUCCESS if everything was added successfully |
| 1230 | */ |
| 1231 | static int rmnet_fill_flow_msg(struct nlmsg *req, size_t *reqsize, |
| 1232 | unsigned int devindex, char *vndname, |
| 1233 | struct tcmsg *flowinfo) |
| 1234 | { |
| 1235 | struct rtattr *linkinfo, *datainfo; |
| 1236 | int rc; |
| 1237 | |
| 1238 | /* Set up link attr with devindex as data */ |
| 1239 | rc = rta_put_u32(req, reqsize, IFLA_LINK, devindex); |
| 1240 | if (rc != RMNETCTL_SUCCESS) |
| 1241 | return rc; |
| 1242 | |
| 1243 | rc = rta_put_string(req, reqsize, IFLA_IFNAME, vndname); |
| 1244 | if (rc != RMNETCTL_SUCCESS) |
| 1245 | return rc; |
| 1246 | |
| 1247 | /* Set up IFLA info kind RMNET that has linkinfo and type */ |
| 1248 | rc = rta_nested_start(req, reqsize, IFLA_LINKINFO, &linkinfo); |
| 1249 | if (rc != RMNETCTL_SUCCESS) |
| 1250 | return rc; |
| 1251 | |
| 1252 | rc = rta_put_string(req, reqsize, IFLA_INFO_KIND, "rmnet"); |
| 1253 | if (rc != RMNETCTL_SUCCESS) |
| 1254 | return rc; |
| 1255 | |
| 1256 | rc = rta_nested_start(req, reqsize, IFLA_INFO_DATA, &datainfo); |
| 1257 | if (rc != RMNETCTL_SUCCESS) |
| 1258 | return rc; |
| 1259 | |
Sean Tranchetti | 037065c | 2019-04-19 11:04:43 -0600 | [diff] [blame] | 1260 | rc = rta_put(req, reqsize, RMNETCTL_IFLA_DFC_QOS, sizeof(*flowinfo), |
Sean Tranchetti | d9d69eb | 2019-02-12 14:30:49 -0700 | [diff] [blame] | 1261 | flowinfo); |
| 1262 | if (rc != RMNETCTL_SUCCESS) |
| 1263 | return rc; |
| 1264 | |
| 1265 | rta_nested_end(req, datainfo); |
| 1266 | rta_nested_end(req, linkinfo); |
| 1267 | |
| 1268 | return RMNETCTL_SUCCESS; |
| 1269 | } |
| 1270 | |
Subash Abhinov Kasiviswanathan | 5b903dd | 2017-12-20 19:11:40 -0700 | [diff] [blame] | 1271 | /* @brief Synchronous method to receive messages to and from the kernel |
| 1272 | * using netlink sockets |
| 1273 | * @details Receives the ack response from the kernel. |
| 1274 | * @param *hndl RmNet handle for this transaction |
| 1275 | * @param *error_code Error code if transaction fails |
| 1276 | * @return RMNETCTL_API_SUCCESS if successfully able to send and receive message |
| 1277 | * from the kernel |
| 1278 | * @return RMNETCTL_API_ERR_HNDL_INVALID if RmNet handle for the transaction was |
| 1279 | * NULL |
| 1280 | * @return RMNETCTL_API_ERR_MESSAGE_RECEIVE if could not receive message from |
| 1281 | * the kernel |
| 1282 | * @return RMNETCTL_API_ERR_MESSAGE_TYPE if the response type does not |
| 1283 | * match |
| 1284 | */ |
| 1285 | static int rmnet_get_ack(rmnetctl_hndl_t *hndl, uint16_t *error_code) |
| 1286 | { |
| 1287 | struct nlack { |
| 1288 | struct nlmsghdr ackheader; |
| 1289 | struct nlmsgerr ackdata; |
| 1290 | char data[256]; |
| 1291 | |
| 1292 | } ack; |
| 1293 | int i; |
| 1294 | |
| 1295 | if (!hndl || !error_code) |
| 1296 | return RMNETCTL_INVALID_ARG; |
| 1297 | |
| 1298 | if ((i = recv(hndl->netlink_fd, &ack, sizeof(ack), 0)) < 0) { |
| 1299 | *error_code = errno; |
| 1300 | return RMNETCTL_API_ERR_MESSAGE_RECEIVE; |
| 1301 | } |
| 1302 | |
| 1303 | /*Ack should always be NLMSG_ERROR type*/ |
| 1304 | if (ack.ackheader.nlmsg_type == NLMSG_ERROR) { |
| 1305 | if (ack.ackdata.error == 0) { |
| 1306 | *error_code = RMNETCTL_API_SUCCESS; |
| 1307 | return RMNETCTL_SUCCESS; |
| 1308 | } else { |
| 1309 | *error_code = -ack.ackdata.error; |
| 1310 | return RMNETCTL_KERNEL_ERR; |
| 1311 | } |
| 1312 | } |
| 1313 | |
| 1314 | *error_code = RMNETCTL_API_ERR_RETURN_TYPE; |
| 1315 | return RMNETCTL_API_FIRST_ERR; |
| 1316 | } |
| 1317 | |
| 1318 | /* |
| 1319 | * EXPOSED NEW DRIVER API |
| 1320 | */ |
| 1321 | int rtrmnet_ctl_init(rmnetctl_hndl_t **hndl, uint16_t *error_code) |
| 1322 | { |
| 1323 | struct sockaddr_nl __attribute__((__may_alias__)) *saddr_ptr; |
| 1324 | int netlink_fd = -1; |
| 1325 | pid_t pid = 0; |
| 1326 | |
| 1327 | if (!hndl || !error_code) |
| 1328 | return RMNETCTL_INVALID_ARG; |
| 1329 | |
| 1330 | *hndl = (rmnetctl_hndl_t *)malloc(sizeof(rmnetctl_hndl_t)); |
| 1331 | if (!*hndl) { |
| 1332 | *error_code = RMNETCTL_API_ERR_HNDL_INVALID; |
| 1333 | return RMNETCTL_LIB_ERR; |
| 1334 | } |
| 1335 | |
| 1336 | memset(*hndl, 0, sizeof(rmnetctl_hndl_t)); |
| 1337 | |
| 1338 | pid = getpid(); |
| 1339 | if (pid < MIN_VALID_PROCESS_ID) { |
| 1340 | free(*hndl); |
| 1341 | *error_code = RMNETCTL_INIT_ERR_PROCESS_ID; |
| 1342 | return RMNETCTL_LIB_ERR; |
| 1343 | } |
| 1344 | (*hndl)->pid = KERNEL_PROCESS_ID; |
Conner Huff | 1ecd2d8 | 2018-04-20 11:12:35 -0700 | [diff] [blame] | 1345 | netlink_fd = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE); |
Subash Abhinov Kasiviswanathan | 5b903dd | 2017-12-20 19:11:40 -0700 | [diff] [blame] | 1346 | if (netlink_fd < MIN_VALID_SOCKET_FD) { |
| 1347 | free(*hndl); |
| 1348 | *error_code = RMNETCTL_INIT_ERR_NETLINK_FD; |
| 1349 | return RMNETCTL_LIB_ERR; |
| 1350 | } |
| 1351 | |
| 1352 | (*hndl)->netlink_fd = netlink_fd; |
| 1353 | |
| 1354 | memset(&(*hndl)->src_addr, 0, sizeof(struct sockaddr_nl)); |
| 1355 | |
| 1356 | (*hndl)->src_addr.nl_family = AF_NETLINK; |
| 1357 | (*hndl)->src_addr.nl_pid = (*hndl)->pid; |
| 1358 | |
| 1359 | saddr_ptr = &(*hndl)->src_addr; |
| 1360 | if (bind((*hndl)->netlink_fd, |
| 1361 | (struct sockaddr *)saddr_ptr, |
| 1362 | sizeof(struct sockaddr_nl)) < 0) { |
| 1363 | close((*hndl)->netlink_fd); |
| 1364 | free(*hndl); |
| 1365 | *error_code = RMNETCTL_INIT_ERR_BIND; |
| 1366 | return RMNETCTL_LIB_ERR; |
| 1367 | } |
| 1368 | |
| 1369 | memset(&(*hndl)->dest_addr, 0, sizeof(struct sockaddr_nl)); |
| 1370 | |
| 1371 | (*hndl)->dest_addr.nl_family = AF_NETLINK; |
| 1372 | (*hndl)->dest_addr.nl_pid = KERNEL_PROCESS_ID; |
| 1373 | (*hndl)->dest_addr.nl_groups = UNICAST; |
| 1374 | |
| 1375 | return RMNETCTL_SUCCESS; |
| 1376 | } |
| 1377 | |
| 1378 | int rtrmnet_ctl_deinit(rmnetctl_hndl_t *hndl) |
| 1379 | { |
| 1380 | if (!hndl) |
| 1381 | return RMNETCTL_SUCCESS; |
| 1382 | |
| 1383 | close(hndl->netlink_fd); |
| 1384 | free(hndl); |
| 1385 | |
| 1386 | return RMNETCTL_SUCCESS; |
| 1387 | } |
| 1388 | |
| 1389 | int rtrmnet_ctl_newvnd(rmnetctl_hndl_t *hndl, char *devname, char *vndname, |
| 1390 | uint16_t *error_code, uint8_t index, |
| 1391 | uint32_t flagconfig) |
| 1392 | { |
Sean Tranchetti | 6e3d523 | 2019-02-12 13:46:42 -0700 | [diff] [blame] | 1393 | unsigned int devindex = 0; |
Subash Abhinov Kasiviswanathan | 5b903dd | 2017-12-20 19:11:40 -0700 | [diff] [blame] | 1394 | struct nlmsg req; |
Subash Abhinov Kasiviswanathan | c26ed59 | 2018-06-15 15:38:27 -0700 | [diff] [blame] | 1395 | size_t reqsize; |
Sean Tranchetti | 51133f5 | 2019-02-12 12:54:34 -0700 | [diff] [blame] | 1396 | int rc; |
Subash Abhinov Kasiviswanathan | 5b903dd | 2017-12-20 19:11:40 -0700 | [diff] [blame] | 1397 | |
Subash Abhinov Kasiviswanathan | c26ed59 | 2018-06-15 15:38:27 -0700 | [diff] [blame] | 1398 | if (!hndl || !devname || !vndname || !error_code || |
| 1399 | _rmnetctl_check_dev_name(vndname) || _rmnetctl_check_dev_name(devname)) |
Subash Abhinov Kasiviswanathan | 5b903dd | 2017-12-20 19:11:40 -0700 | [diff] [blame] | 1400 | return RMNETCTL_INVALID_ARG; |
| 1401 | |
| 1402 | memset(&req, 0, sizeof(req)); |
Sean Tranchetti | 51133f5 | 2019-02-12 12:54:34 -0700 | [diff] [blame] | 1403 | reqsize = NLMSG_DATA_SIZE - sizeof(struct rtattr); |
Subash Abhinov Kasiviswanathan | 5b903dd | 2017-12-20 19:11:40 -0700 | [diff] [blame] | 1404 | req.nl_addr.nlmsg_type = RTM_NEWLINK; |
| 1405 | req.nl_addr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); |
| 1406 | req.nl_addr.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL | |
| 1407 | NLM_F_ACK; |
| 1408 | req.nl_addr.nlmsg_seq = hndl->transaction_id; |
| 1409 | hndl->transaction_id++; |
| 1410 | |
| 1411 | /* Get index of devname*/ |
| 1412 | devindex = if_nametoindex(devname); |
Sean Tranchetti | 1065092 | 2018-08-16 11:42:59 -0600 | [diff] [blame] | 1413 | if (devindex == 0) { |
Subash Abhinov Kasiviswanathan | 5b903dd | 2017-12-20 19:11:40 -0700 | [diff] [blame] | 1414 | *error_code = errno; |
| 1415 | return RMNETCTL_KERNEL_ERR; |
| 1416 | } |
| 1417 | |
Sean Tranchetti | 51133f5 | 2019-02-12 12:54:34 -0700 | [diff] [blame] | 1418 | *error_code = RMNETCTL_API_ERR_RTA_FAILURE; |
Sean Tranchetti | 6e3d523 | 2019-02-12 13:46:42 -0700 | [diff] [blame] | 1419 | rc = rta_put_u32(&req, &reqsize, RMNET_IFLA_NUM_TX_QUEUES, |
| 1420 | RMNETCTL_NUM_TX_QUEUES); |
Sean Tranchetti | 51133f5 | 2019-02-12 12:54:34 -0700 | [diff] [blame] | 1421 | if (rc != RMNETCTL_SUCCESS) |
| 1422 | return rc; |
Subash Abhinov Kasiviswanathan | 5b903dd | 2017-12-20 19:11:40 -0700 | [diff] [blame] | 1423 | |
Sean Tranchetti | 37a08ec | 2019-02-12 15:22:50 -0700 | [diff] [blame] | 1424 | rc = rmnet_fill_newlink_msg(&req, &reqsize, devindex, vndname, index, |
| 1425 | flagconfig); |
Sean Tranchetti | 51133f5 | 2019-02-12 12:54:34 -0700 | [diff] [blame] | 1426 | if (rc != RMNETCTL_SUCCESS) |
| 1427 | return rc; |
Subash Abhinov Kasiviswanathan | cf3f890 | 2018-08-30 14:23:08 -0600 | [diff] [blame] | 1428 | |
Subash Abhinov Kasiviswanathan | 5b903dd | 2017-12-20 19:11:40 -0700 | [diff] [blame] | 1429 | if (send(hndl->netlink_fd, &req, req.nl_addr.nlmsg_len, 0) < 0) { |
| 1430 | *error_code = RMNETCTL_API_ERR_MESSAGE_SEND; |
| 1431 | return RMNETCTL_LIB_ERR; |
| 1432 | } |
| 1433 | |
| 1434 | return rmnet_get_ack(hndl, error_code); |
| 1435 | } |
| 1436 | |
| 1437 | int rtrmnet_ctl_delvnd(rmnetctl_hndl_t *hndl, char *vndname, |
| 1438 | uint16_t *error_code) |
| 1439 | { |
Sean Tranchetti | 1065092 | 2018-08-16 11:42:59 -0600 | [diff] [blame] | 1440 | unsigned int devindex = 0; |
Subash Abhinov Kasiviswanathan | 5b903dd | 2017-12-20 19:11:40 -0700 | [diff] [blame] | 1441 | struct nlmsg req; |
| 1442 | |
| 1443 | if (!hndl || !vndname || !error_code) |
| 1444 | return RMNETCTL_INVALID_ARG; |
| 1445 | |
| 1446 | memset(&req, 0, sizeof(req)); |
| 1447 | req.nl_addr.nlmsg_type = RTM_DELLINK; |
| 1448 | req.nl_addr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); |
| 1449 | req.nl_addr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; |
| 1450 | req.nl_addr.nlmsg_seq = hndl->transaction_id; |
| 1451 | hndl->transaction_id++; |
| 1452 | |
| 1453 | /* Get index of vndname*/ |
| 1454 | devindex = if_nametoindex(vndname); |
Sean Tranchetti | 1065092 | 2018-08-16 11:42:59 -0600 | [diff] [blame] | 1455 | if (devindex == 0) { |
Subash Abhinov Kasiviswanathan | 5b903dd | 2017-12-20 19:11:40 -0700 | [diff] [blame] | 1456 | *error_code = errno; |
| 1457 | return RMNETCTL_KERNEL_ERR; |
| 1458 | } |
| 1459 | |
| 1460 | /* Setup index attribute */ |
| 1461 | req.ifmsg.ifi_index = devindex; |
| 1462 | if (send(hndl->netlink_fd, &req, req.nl_addr.nlmsg_len, 0) < 0) { |
| 1463 | *error_code = RMNETCTL_API_ERR_MESSAGE_SEND; |
| 1464 | return RMNETCTL_LIB_ERR; |
| 1465 | } |
| 1466 | |
| 1467 | return rmnet_get_ack(hndl, error_code); |
| 1468 | } |
| 1469 | |
| 1470 | |
| 1471 | int rtrmnet_ctl_changevnd(rmnetctl_hndl_t *hndl, char *devname, char *vndname, |
| 1472 | uint16_t *error_code, uint8_t index, |
| 1473 | uint32_t flagconfig) |
| 1474 | { |
Subash Abhinov Kasiviswanathan | 5b903dd | 2017-12-20 19:11:40 -0700 | [diff] [blame] | 1475 | struct nlmsg req; |
Sean Tranchetti | 51133f5 | 2019-02-12 12:54:34 -0700 | [diff] [blame] | 1476 | unsigned int devindex = 0; |
Subash Abhinov Kasiviswanathan | c26ed59 | 2018-06-15 15:38:27 -0700 | [diff] [blame] | 1477 | size_t reqsize; |
Sean Tranchetti | 51133f5 | 2019-02-12 12:54:34 -0700 | [diff] [blame] | 1478 | int rc; |
Subash Abhinov Kasiviswanathan | 5b903dd | 2017-12-20 19:11:40 -0700 | [diff] [blame] | 1479 | |
| 1480 | memset(&req, 0, sizeof(req)); |
| 1481 | |
Subash Abhinov Kasiviswanathan | c26ed59 | 2018-06-15 15:38:27 -0700 | [diff] [blame] | 1482 | if (!hndl || !devname || !vndname || !error_code || |
| 1483 | _rmnetctl_check_dev_name(vndname) || _rmnetctl_check_dev_name(devname)) |
Subash Abhinov Kasiviswanathan | 5b903dd | 2017-12-20 19:11:40 -0700 | [diff] [blame] | 1484 | return RMNETCTL_INVALID_ARG; |
| 1485 | |
Sean Tranchetti | 51133f5 | 2019-02-12 12:54:34 -0700 | [diff] [blame] | 1486 | reqsize = NLMSG_DATA_SIZE - sizeof(struct rtattr); |
Subash Abhinov Kasiviswanathan | 5b903dd | 2017-12-20 19:11:40 -0700 | [diff] [blame] | 1487 | req.nl_addr.nlmsg_type = RTM_NEWLINK; |
| 1488 | req.nl_addr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); |
| 1489 | req.nl_addr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; |
| 1490 | req.nl_addr.nlmsg_seq = hndl->transaction_id; |
| 1491 | hndl->transaction_id++; |
| 1492 | |
| 1493 | /* Get index of devname*/ |
| 1494 | devindex = if_nametoindex(devname); |
Sean Tranchetti | 1065092 | 2018-08-16 11:42:59 -0600 | [diff] [blame] | 1495 | if (devindex == 0) { |
Subash Abhinov Kasiviswanathan | 5b903dd | 2017-12-20 19:11:40 -0700 | [diff] [blame] | 1496 | *error_code = errno; |
| 1497 | return RMNETCTL_KERNEL_ERR; |
| 1498 | } |
| 1499 | |
Sean Tranchetti | 37a08ec | 2019-02-12 15:22:50 -0700 | [diff] [blame] | 1500 | rc = rmnet_fill_newlink_msg(&req, &reqsize, devindex, vndname, index, |
| 1501 | flagconfig); |
| 1502 | if (rc != RMNETCTL_SUCCESS) { |
| 1503 | *error_code = RMNETCTL_API_ERR_RTA_FAILURE; |
Sean Tranchetti | 51133f5 | 2019-02-12 12:54:34 -0700 | [diff] [blame] | 1504 | return rc; |
Subash Abhinov Kasiviswanathan | 5b903dd | 2017-12-20 19:11:40 -0700 | [diff] [blame] | 1505 | } |
| 1506 | |
Subash Abhinov Kasiviswanathan | 5b903dd | 2017-12-20 19:11:40 -0700 | [diff] [blame] | 1507 | if (send(hndl->netlink_fd, &req, req.nl_addr.nlmsg_len, 0) < 0) { |
| 1508 | *error_code = RMNETCTL_API_ERR_MESSAGE_SEND; |
| 1509 | return RMNETCTL_LIB_ERR; |
| 1510 | } |
| 1511 | |
| 1512 | return rmnet_get_ack(hndl, error_code); |
| 1513 | } |
| 1514 | |
Sean Tranchetti | 1a2abef | 2019-01-03 14:33:16 -0700 | [diff] [blame] | 1515 | int rtrmnet_ctl_getvnd(rmnetctl_hndl_t *hndl, char *vndname, |
| 1516 | uint16_t *error_code, uint16_t *mux_id, |
Subash Abhinov Kasiviswanathan | a0c4bfb | 2019-08-14 11:26:52 -0600 | [diff] [blame] | 1517 | uint32_t *flagconfig, uint8_t *agg_count, |
| 1518 | uint16_t *agg_size, uint32_t *agg_time, |
| 1519 | uint8_t *features) |
Sean Tranchetti | 1a2abef | 2019-01-03 14:33:16 -0700 | [diff] [blame] | 1520 | { |
| 1521 | struct nlmsg req; |
| 1522 | struct nlmsghdr *resp; |
| 1523 | struct rtattr *attrs, *linkinfo, *datainfo; |
Sean Tranchetti | 037065c | 2019-04-19 11:04:43 -0600 | [diff] [blame] | 1524 | struct rtattr *tb[__RMNETCTL_IFLA_MAX]; |
Sean Tranchetti | 1a2abef | 2019-01-03 14:33:16 -0700 | [diff] [blame] | 1525 | unsigned int devindex = 0; |
| 1526 | int resp_len; |
| 1527 | |
| 1528 | memset(&req, 0, sizeof(req)); |
| 1529 | |
| 1530 | if (!hndl || !vndname || !error_code || !(mux_id || flagconfig) || |
| 1531 | _rmnetctl_check_dev_name(vndname)) |
| 1532 | return RMNETCTL_INVALID_ARG; |
| 1533 | |
| 1534 | req.nl_addr.nlmsg_type = RTM_GETLINK; |
| 1535 | req.nl_addr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); |
| 1536 | req.nl_addr.nlmsg_flags = NLM_F_REQUEST; |
| 1537 | req.nl_addr.nlmsg_seq = hndl->transaction_id; |
| 1538 | hndl->transaction_id++; |
| 1539 | |
| 1540 | /* Get index of vndname */ |
| 1541 | devindex = if_nametoindex(vndname); |
| 1542 | if (devindex == 0) { |
| 1543 | *error_code = errno; |
| 1544 | return RMNETCTL_KERNEL_ERR; |
| 1545 | } |
| 1546 | |
| 1547 | req.ifmsg.ifi_index = devindex; |
| 1548 | if (send(hndl->netlink_fd, &req, req.nl_addr.nlmsg_len, 0) < 0) { |
| 1549 | *error_code = RMNETCTL_API_ERR_MESSAGE_SEND; |
| 1550 | return RMNETCTL_LIB_ERR; |
| 1551 | } |
| 1552 | |
| 1553 | resp_len = recv(hndl->netlink_fd, NULL, 0, MSG_PEEK | MSG_TRUNC); |
| 1554 | if (resp_len < 0) { |
| 1555 | *error_code = errno; |
| 1556 | return RMNETCTL_API_ERR_MESSAGE_RECEIVE; |
| 1557 | } |
| 1558 | |
| 1559 | resp = malloc((size_t)resp_len); |
| 1560 | if (!resp) { |
| 1561 | *error_code = errno; |
| 1562 | return RMNETCTL_LIB_ERR; |
| 1563 | } |
| 1564 | |
| 1565 | resp_len = recv(hndl->netlink_fd, (char *)resp, (size_t)resp_len, 0); |
| 1566 | if (resp_len < 0) { |
| 1567 | *error_code = errno; |
| 1568 | free(resp); |
| 1569 | return RMNETCTL_API_ERR_MESSAGE_RECEIVE; |
| 1570 | } |
| 1571 | |
| 1572 | /* Parse out the RT attributes */ |
| 1573 | attrs = (struct rtattr *)((char *)NLMSG_DATA(resp) + |
| 1574 | NLMSG_ALIGN(sizeof(req.ifmsg))); |
| 1575 | linkinfo = rta_find(attrs, NLMSG_PAYLOAD(resp, sizeof(req.ifmsg)), |
| 1576 | IFLA_LINKINFO); |
| 1577 | if (!linkinfo) { |
| 1578 | free(resp); |
| 1579 | *error_code = RMNETCTL_API_ERR_RTA_FAILURE; |
| 1580 | return RMNETCTL_KERNEL_ERR; |
| 1581 | } |
| 1582 | |
| 1583 | datainfo = rta_find(RTA_DATA(linkinfo), RTA_PAYLOAD(linkinfo), |
| 1584 | IFLA_INFO_DATA); |
| 1585 | if (!datainfo) { |
| 1586 | free(resp); |
| 1587 | *error_code = RMNETCTL_API_ERR_RTA_FAILURE; |
| 1588 | return RMNETCTL_KERNEL_ERR; |
| 1589 | } |
| 1590 | |
| 1591 | /* Parse all the rmnet-specific information from the kernel */ |
Sean Tranchetti | 037065c | 2019-04-19 11:04:43 -0600 | [diff] [blame] | 1592 | rta_parse(tb, __RMNETCTL_IFLA_MAX, RTA_DATA(datainfo), |
Sean Tranchetti | 1a2abef | 2019-01-03 14:33:16 -0700 | [diff] [blame] | 1593 | RTA_PAYLOAD(datainfo)); |
Sean Tranchetti | 037065c | 2019-04-19 11:04:43 -0600 | [diff] [blame] | 1594 | if (tb[RMNETCTL_IFLA_MUX_ID] && mux_id) |
| 1595 | *mux_id = *((uint16_t *)RTA_DATA(tb[RMNETCTL_IFLA_MUX_ID])); |
| 1596 | if (tb[RMNETCTL_IFLA_FLAGS] && flagconfig) { |
Sean Tranchetti | 1a2abef | 2019-01-03 14:33:16 -0700 | [diff] [blame] | 1597 | struct ifla_vlan_flags *flags; |
| 1598 | |
| 1599 | flags = (struct ifla_vlan_flags *) |
Sean Tranchetti | 037065c | 2019-04-19 11:04:43 -0600 | [diff] [blame] | 1600 | RTA_DATA(tb[RMNETCTL_IFLA_FLAGS]); |
Sean Tranchetti | 1a2abef | 2019-01-03 14:33:16 -0700 | [diff] [blame] | 1601 | *flagconfig = flags->flags; |
| 1602 | } |
Sean Tranchetti | 406fd81 | 2019-04-22 16:45:19 -0600 | [diff] [blame] | 1603 | if (tb[RMNETCTL_IFLA_UPLINK_PARAMS]) { |
| 1604 | struct rmnetctl_uplink_params *ul_agg; |
| 1605 | |
| 1606 | ul_agg = (struct rmnetctl_uplink_params *) |
| 1607 | RTA_DATA(tb[RMNETCTL_IFLA_UPLINK_PARAMS]); |
Subash Abhinov Kasiviswanathan | a0c4bfb | 2019-08-14 11:26:52 -0600 | [diff] [blame] | 1608 | |
Sean Tranchetti | 406fd81 | 2019-04-22 16:45:19 -0600 | [diff] [blame] | 1609 | if (agg_size) |
| 1610 | *agg_size = ul_agg->byte_count; |
Subash Abhinov Kasiviswanathan | a0c4bfb | 2019-08-14 11:26:52 -0600 | [diff] [blame] | 1611 | |
| 1612 | if (agg_count) |
| 1613 | *agg_count = ul_agg->packet_count; |
| 1614 | |
| 1615 | if (features) |
| 1616 | *features = ul_agg->features; |
| 1617 | |
Sean Tranchetti | 406fd81 | 2019-04-22 16:45:19 -0600 | [diff] [blame] | 1618 | if (agg_time) |
| 1619 | *agg_time = ul_agg->time_limit; |
| 1620 | } |
Sean Tranchetti | 1a2abef | 2019-01-03 14:33:16 -0700 | [diff] [blame] | 1621 | |
| 1622 | free(resp); |
| 1623 | return RMNETCTL_API_SUCCESS; |
| 1624 | } |
| 1625 | |
Subash Abhinov Kasiviswanathan | 5b903dd | 2017-12-20 19:11:40 -0700 | [diff] [blame] | 1626 | int rtrmnet_ctl_bridgevnd(rmnetctl_hndl_t *hndl, char *devname, char *vndname, |
| 1627 | uint16_t *error_code) |
| 1628 | { |
Sean Tranchetti | 1065092 | 2018-08-16 11:42:59 -0600 | [diff] [blame] | 1629 | unsigned int devindex = 0, vndindex = 0; |
Subash Abhinov Kasiviswanathan | 5b903dd | 2017-12-20 19:11:40 -0700 | [diff] [blame] | 1630 | struct nlmsg req; |
Subash Abhinov Kasiviswanathan | c26ed59 | 2018-06-15 15:38:27 -0700 | [diff] [blame] | 1631 | size_t reqsize; |
Sean Tranchetti | 51133f5 | 2019-02-12 12:54:34 -0700 | [diff] [blame] | 1632 | int rc; |
Subash Abhinov Kasiviswanathan | 5b903dd | 2017-12-20 19:11:40 -0700 | [diff] [blame] | 1633 | |
Subash Abhinov Kasiviswanathan | c26ed59 | 2018-06-15 15:38:27 -0700 | [diff] [blame] | 1634 | if (!hndl || !vndname || !devname || !error_code || _rmnetctl_check_dev_name(vndname)) |
Subash Abhinov Kasiviswanathan | 5b903dd | 2017-12-20 19:11:40 -0700 | [diff] [blame] | 1635 | return RMNETCTL_INVALID_ARG; |
| 1636 | |
| 1637 | memset(&req, 0, sizeof(req)); |
Sean Tranchetti | 51133f5 | 2019-02-12 12:54:34 -0700 | [diff] [blame] | 1638 | reqsize = NLMSG_DATA_SIZE - sizeof(struct rtattr); |
Subash Abhinov Kasiviswanathan | 5b903dd | 2017-12-20 19:11:40 -0700 | [diff] [blame] | 1639 | req.nl_addr.nlmsg_type = RTM_NEWLINK; |
| 1640 | req.nl_addr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); |
| 1641 | req.nl_addr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; |
| 1642 | req.nl_addr.nlmsg_seq = hndl->transaction_id; |
| 1643 | hndl->transaction_id++; |
| 1644 | |
| 1645 | /* Get index of vndname*/ |
| 1646 | devindex = if_nametoindex(devname); |
Sean Tranchetti | 1065092 | 2018-08-16 11:42:59 -0600 | [diff] [blame] | 1647 | if (devindex == 0) { |
Subash Abhinov Kasiviswanathan | 5b903dd | 2017-12-20 19:11:40 -0700 | [diff] [blame] | 1648 | *error_code = errno; |
| 1649 | return RMNETCTL_KERNEL_ERR; |
| 1650 | } |
| 1651 | |
| 1652 | vndindex = if_nametoindex(vndname); |
Sean Tranchetti | 1065092 | 2018-08-16 11:42:59 -0600 | [diff] [blame] | 1653 | if (vndindex == 0) { |
Subash Abhinov Kasiviswanathan | 5b903dd | 2017-12-20 19:11:40 -0700 | [diff] [blame] | 1654 | *error_code = errno; |
| 1655 | return RMNETCTL_KERNEL_ERR; |
| 1656 | } |
| 1657 | |
| 1658 | /* Setup index attribute */ |
| 1659 | req.ifmsg.ifi_index = devindex; |
Sean Tranchetti | 6e3d523 | 2019-02-12 13:46:42 -0700 | [diff] [blame] | 1660 | rc = rta_put_u32(&req, &reqsize, IFLA_MASTER, vndindex); |
Sean Tranchetti | 51133f5 | 2019-02-12 12:54:34 -0700 | [diff] [blame] | 1661 | if (rc != RMNETCTL_SUCCESS) { |
| 1662 | *error_code = RMNETCTL_API_ERR_RTA_FAILURE; |
| 1663 | return rc; |
| 1664 | } |
Subash Abhinov Kasiviswanathan | 5b903dd | 2017-12-20 19:11:40 -0700 | [diff] [blame] | 1665 | |
| 1666 | if (send(hndl->netlink_fd, &req, req.nl_addr.nlmsg_len, 0) < 0) { |
| 1667 | *error_code = RMNETCTL_API_ERR_MESSAGE_SEND; |
| 1668 | return RMNETCTL_LIB_ERR; |
| 1669 | } |
| 1670 | |
| 1671 | return rmnet_get_ack(hndl, error_code); |
| 1672 | } |
Conner Huff | d0f3eca | 2018-05-18 11:37:46 -0700 | [diff] [blame] | 1673 | |
Sean Tranchetti | 6cac289 | 2019-04-19 11:04:57 -0600 | [diff] [blame] | 1674 | int rtrmnet_set_uplink_aggregation_params(rmnetctl_hndl_t *hndl, |
| 1675 | char *devname, |
| 1676 | char *vndname, |
| 1677 | uint8_t packet_count, |
| 1678 | uint16_t byte_count, |
| 1679 | uint32_t time_limit, |
Subash Abhinov Kasiviswanathan | a0c4bfb | 2019-08-14 11:26:52 -0600 | [diff] [blame] | 1680 | uint8_t features, |
Sean Tranchetti | 6cac289 | 2019-04-19 11:04:57 -0600 | [diff] [blame] | 1681 | uint16_t *error_code) |
| 1682 | { |
| 1683 | struct nlmsg req; |
| 1684 | struct rmnetctl_uplink_params uplink_params; |
| 1685 | struct rtattr *linkinfo, *datainfo; |
| 1686 | unsigned int devindex = 0; |
| 1687 | size_t reqsize; |
| 1688 | int rc; |
| 1689 | |
| 1690 | memset(&req, 0, sizeof(req)); |
| 1691 | memset(&uplink_params, 0, sizeof(uplink_params)); |
| 1692 | |
| 1693 | if (!hndl || !devname || !error_code ||_rmnetctl_check_dev_name(devname) || |
| 1694 | _rmnetctl_check_dev_name(vndname)) |
| 1695 | return RMNETCTL_INVALID_ARG; |
| 1696 | |
| 1697 | reqsize = NLMSG_DATA_SIZE - sizeof(struct rtattr); |
| 1698 | req.nl_addr.nlmsg_type = RTM_NEWLINK; |
| 1699 | req.nl_addr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); |
| 1700 | req.nl_addr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; |
| 1701 | req.nl_addr.nlmsg_seq = hndl->transaction_id; |
| 1702 | hndl->transaction_id++; |
| 1703 | |
| 1704 | /* Get index of devname*/ |
| 1705 | devindex = if_nametoindex(devname); |
| 1706 | if (devindex == 0) { |
| 1707 | *error_code = errno; |
| 1708 | return RMNETCTL_KERNEL_ERR; |
| 1709 | } |
| 1710 | |
| 1711 | /* Set up link attr with devindex as data */ |
| 1712 | rc = rta_put_u32(&req, &reqsize, IFLA_LINK, devindex); |
| 1713 | if (rc != RMNETCTL_SUCCESS) { |
| 1714 | *error_code = RMNETCTL_API_ERR_RTA_FAILURE; |
| 1715 | return rc; |
| 1716 | } |
| 1717 | |
| 1718 | rc = rta_put_string(&req, &reqsize, IFLA_IFNAME, vndname); |
| 1719 | if (rc != RMNETCTL_SUCCESS) { |
| 1720 | *error_code = RMNETCTL_API_ERR_RTA_FAILURE; |
| 1721 | return rc; |
| 1722 | } |
| 1723 | |
| 1724 | /* Set up IFLA info kind RMNET that has linkinfo and type */ |
| 1725 | rc = rta_nested_start(&req, &reqsize, IFLA_LINKINFO, &linkinfo); |
| 1726 | if (rc != RMNETCTL_SUCCESS) { |
| 1727 | *error_code = RMNETCTL_API_ERR_RTA_FAILURE; |
| 1728 | return rc; |
| 1729 | } |
| 1730 | |
| 1731 | rc = rta_put_string(&req, &reqsize, IFLA_INFO_KIND, "rmnet"); |
| 1732 | if (rc != RMNETCTL_SUCCESS) { |
| 1733 | *error_code = RMNETCTL_API_ERR_RTA_FAILURE; |
| 1734 | return rc; |
| 1735 | } |
| 1736 | |
| 1737 | rc = rta_nested_start(&req, &reqsize, IFLA_INFO_DATA, &datainfo); |
| 1738 | if (rc != RMNETCTL_SUCCESS) { |
| 1739 | *error_code = RMNETCTL_API_ERR_RTA_FAILURE; |
| 1740 | return rc; |
| 1741 | } |
| 1742 | |
| 1743 | uplink_params.byte_count = byte_count; |
| 1744 | uplink_params.packet_count = packet_count; |
Subash Abhinov Kasiviswanathan | a0c4bfb | 2019-08-14 11:26:52 -0600 | [diff] [blame] | 1745 | uplink_params.features = features; |
Sean Tranchetti | 6cac289 | 2019-04-19 11:04:57 -0600 | [diff] [blame] | 1746 | uplink_params.time_limit = time_limit; |
| 1747 | rc = rta_put(&req, &reqsize, RMNETCTL_IFLA_UPLINK_PARAMS, |
| 1748 | sizeof(uplink_params), &uplink_params); |
| 1749 | if (rc != RMNETCTL_SUCCESS) { |
| 1750 | *error_code = RMNETCTL_API_ERR_RTA_FAILURE; |
| 1751 | return rc; |
| 1752 | } |
| 1753 | |
| 1754 | rta_nested_end(&req, datainfo); |
| 1755 | rta_nested_end(&req, linkinfo); |
| 1756 | |
| 1757 | if (send(hndl->netlink_fd, &req, req.nl_addr.nlmsg_len, 0) < 0) { |
| 1758 | *error_code = RMNETCTL_API_ERR_MESSAGE_SEND; |
| 1759 | return RMNETCTL_LIB_ERR; |
| 1760 | } |
| 1761 | |
| 1762 | return rmnet_get_ack(hndl, error_code); |
| 1763 | |
| 1764 | } |
Conner Huff | d0f3eca | 2018-05-18 11:37:46 -0700 | [diff] [blame] | 1765 | |
| 1766 | int rtrmnet_activate_flow(rmnetctl_hndl_t *hndl, |
| 1767 | char *devname, |
| 1768 | char *vndname, |
| 1769 | uint8_t bearer_id, |
| 1770 | uint32_t flow_id, |
| 1771 | int ip_type, |
| 1772 | uint32_t tcm_handle, |
| 1773 | uint16_t *error_code) |
| 1774 | { |
Conner Huff | d0f3eca | 2018-05-18 11:37:46 -0700 | [diff] [blame] | 1775 | struct tcmsg flowinfo; |
Conner Huff | d0f3eca | 2018-05-18 11:37:46 -0700 | [diff] [blame] | 1776 | struct nlmsg req; |
Sean Tranchetti | 1065092 | 2018-08-16 11:42:59 -0600 | [diff] [blame] | 1777 | unsigned int devindex = 0; |
Subash Abhinov Kasiviswanathan | c26ed59 | 2018-06-15 15:38:27 -0700 | [diff] [blame] | 1778 | size_t reqsize =0; |
Sean Tranchetti | 51133f5 | 2019-02-12 12:54:34 -0700 | [diff] [blame] | 1779 | int rc; |
Conner Huff | d0f3eca | 2018-05-18 11:37:46 -0700 | [diff] [blame] | 1780 | |
| 1781 | memset(&req, 0, sizeof(req)); |
| 1782 | memset(&flowinfo, 0, sizeof(flowinfo)); |
| 1783 | |
| 1784 | |
Subash Abhinov Kasiviswanathan | c26ed59 | 2018-06-15 15:38:27 -0700 | [diff] [blame] | 1785 | if (!hndl || !devname || !error_code ||_rmnetctl_check_dev_name(devname) || |
| 1786 | _rmnetctl_check_dev_name(vndname)) |
Conner Huff | d0f3eca | 2018-05-18 11:37:46 -0700 | [diff] [blame] | 1787 | return RMNETCTL_INVALID_ARG; |
| 1788 | |
Sean Tranchetti | 51133f5 | 2019-02-12 12:54:34 -0700 | [diff] [blame] | 1789 | reqsize = NLMSG_DATA_SIZE - sizeof(struct rtattr); |
Conner Huff | d0f3eca | 2018-05-18 11:37:46 -0700 | [diff] [blame] | 1790 | req.nl_addr.nlmsg_type = RTM_NEWLINK; |
| 1791 | req.nl_addr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); |
| 1792 | req.nl_addr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; |
| 1793 | req.nl_addr.nlmsg_seq = hndl->transaction_id; |
| 1794 | hndl->transaction_id++; |
| 1795 | |
| 1796 | /* Get index of devname*/ |
| 1797 | devindex = if_nametoindex(devname); |
Sean Tranchetti | 1065092 | 2018-08-16 11:42:59 -0600 | [diff] [blame] | 1798 | if (devindex == 0) { |
Conner Huff | d0f3eca | 2018-05-18 11:37:46 -0700 | [diff] [blame] | 1799 | *error_code = errno; |
| 1800 | return RMNETCTL_KERNEL_ERR; |
| 1801 | } |
| 1802 | |
Conner Huff | d0f3eca | 2018-05-18 11:37:46 -0700 | [diff] [blame] | 1803 | flowinfo.tcm_handle = tcm_handle; |
Sean Tranchetti | 4fb7294 | 2019-02-12 15:36:30 -0700 | [diff] [blame] | 1804 | flowinfo.tcm_family = RMNET_FLOW_MSG_ACTIVATE; |
Conner Huff | d0f3eca | 2018-05-18 11:37:46 -0700 | [diff] [blame] | 1805 | flowinfo.tcm__pad1 = bearer_id; |
| 1806 | flowinfo.tcm_ifindex = ip_type; |
| 1807 | flowinfo.tcm_parent = flow_id; |
| 1808 | |
Sean Tranchetti | d9d69eb | 2019-02-12 14:30:49 -0700 | [diff] [blame] | 1809 | rc = rmnet_fill_flow_msg(&req, &reqsize, devindex, vndname, &flowinfo); |
| 1810 | if (rc != RMNETCTL_SUCCESS) { |
| 1811 | *error_code = RMNETCTL_API_ERR_RTA_FAILURE; |
Sean Tranchetti | 51133f5 | 2019-02-12 12:54:34 -0700 | [diff] [blame] | 1812 | return rc; |
Sean Tranchetti | d9d69eb | 2019-02-12 14:30:49 -0700 | [diff] [blame] | 1813 | } |
Conner Huff | d0f3eca | 2018-05-18 11:37:46 -0700 | [diff] [blame] | 1814 | |
| 1815 | if (send(hndl->netlink_fd, &req, req.nl_addr.nlmsg_len, 0) < 0) { |
| 1816 | *error_code = RMNETCTL_API_ERR_MESSAGE_SEND; |
| 1817 | return RMNETCTL_LIB_ERR; |
| 1818 | } |
| 1819 | |
| 1820 | return rmnet_get_ack(hndl, error_code); |
| 1821 | } |
| 1822 | |
| 1823 | |
| 1824 | int rtrmnet_delete_flow(rmnetctl_hndl_t *hndl, |
| 1825 | char *devname, |
| 1826 | char *vndname, |
| 1827 | uint8_t bearer_id, |
| 1828 | uint32_t flow_id, |
| 1829 | int ip_type, |
| 1830 | uint16_t *error_code) |
| 1831 | { |
Conner Huff | d0f3eca | 2018-05-18 11:37:46 -0700 | [diff] [blame] | 1832 | struct tcmsg flowinfo; |
Conner Huff | d0f3eca | 2018-05-18 11:37:46 -0700 | [diff] [blame] | 1833 | struct nlmsg req; |
Sean Tranchetti | 1065092 | 2018-08-16 11:42:59 -0600 | [diff] [blame] | 1834 | unsigned int devindex = 0; |
Subash Abhinov Kasiviswanathan | c26ed59 | 2018-06-15 15:38:27 -0700 | [diff] [blame] | 1835 | size_t reqsize; |
Sean Tranchetti | 51133f5 | 2019-02-12 12:54:34 -0700 | [diff] [blame] | 1836 | int rc; |
Conner Huff | d0f3eca | 2018-05-18 11:37:46 -0700 | [diff] [blame] | 1837 | |
| 1838 | memset(&req, 0, sizeof(req)); |
| 1839 | memset(&flowinfo, 0, sizeof(flowinfo)); |
| 1840 | |
Subash Abhinov Kasiviswanathan | c26ed59 | 2018-06-15 15:38:27 -0700 | [diff] [blame] | 1841 | if (!hndl || !devname || !error_code ||_rmnetctl_check_dev_name(devname) || |
| 1842 | _rmnetctl_check_dev_name(vndname)) |
Conner Huff | d0f3eca | 2018-05-18 11:37:46 -0700 | [diff] [blame] | 1843 | return RMNETCTL_INVALID_ARG; |
| 1844 | |
Subash Abhinov Kasiviswanathan | c26ed59 | 2018-06-15 15:38:27 -0700 | [diff] [blame] | 1845 | reqsize = NLMSG_DATA_SIZE - sizeof(struct rtattr); |
Conner Huff | d0f3eca | 2018-05-18 11:37:46 -0700 | [diff] [blame] | 1846 | req.nl_addr.nlmsg_type = RTM_NEWLINK; |
| 1847 | req.nl_addr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); |
| 1848 | req.nl_addr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; |
| 1849 | req.nl_addr.nlmsg_seq = hndl->transaction_id; |
| 1850 | hndl->transaction_id++; |
| 1851 | |
| 1852 | /* Get index of devname*/ |
| 1853 | devindex = if_nametoindex(devname); |
Sean Tranchetti | 1065092 | 2018-08-16 11:42:59 -0600 | [diff] [blame] | 1854 | if (devindex == 0) { |
Conner Huff | d0f3eca | 2018-05-18 11:37:46 -0700 | [diff] [blame] | 1855 | *error_code = errno; |
| 1856 | return RMNETCTL_KERNEL_ERR; |
| 1857 | } |
| 1858 | |
Sean Tranchetti | 4fb7294 | 2019-02-12 15:36:30 -0700 | [diff] [blame] | 1859 | flowinfo.tcm_family = RMNET_FLOW_MSG_DEACTIVATE; |
Sean Tranchetti | 51133f5 | 2019-02-12 12:54:34 -0700 | [diff] [blame] | 1860 | flowinfo.tcm_ifindex = ip_type; |
| 1861 | flowinfo.tcm__pad1 = bearer_id; |
| 1862 | flowinfo.tcm_parent = flow_id; |
Conner Huff | d0f3eca | 2018-05-18 11:37:46 -0700 | [diff] [blame] | 1863 | |
Sean Tranchetti | d9d69eb | 2019-02-12 14:30:49 -0700 | [diff] [blame] | 1864 | rc = rmnet_fill_flow_msg(&req, &reqsize, devindex, vndname, &flowinfo); |
| 1865 | if (rc != RMNETCTL_SUCCESS) { |
| 1866 | *error_code = RMNETCTL_API_ERR_RTA_FAILURE; |
Sean Tranchetti | 51133f5 | 2019-02-12 12:54:34 -0700 | [diff] [blame] | 1867 | return rc; |
Sean Tranchetti | d9d69eb | 2019-02-12 14:30:49 -0700 | [diff] [blame] | 1868 | } |
Subash Abhinov Kasiviswanathan | c26ed59 | 2018-06-15 15:38:27 -0700 | [diff] [blame] | 1869 | |
Sean Tranchetti | 51133f5 | 2019-02-12 12:54:34 -0700 | [diff] [blame] | 1870 | if (send(hndl->netlink_fd, &req, req.nl_addr.nlmsg_len, 0) < 0) { |
| 1871 | *error_code = RMNETCTL_API_ERR_MESSAGE_SEND; |
| 1872 | return RMNETCTL_LIB_ERR; |
| 1873 | } |
Conner Huff | d0f3eca | 2018-05-18 11:37:46 -0700 | [diff] [blame] | 1874 | |
Sean Tranchetti | 51133f5 | 2019-02-12 12:54:34 -0700 | [diff] [blame] | 1875 | return rmnet_get_ack(hndl, error_code); |
| 1876 | } |
Conner Huff | d0f3eca | 2018-05-18 11:37:46 -0700 | [diff] [blame] | 1877 | |
Sean Tranchetti | 51133f5 | 2019-02-12 12:54:34 -0700 | [diff] [blame] | 1878 | int rtrmnet_control_flow(rmnetctl_hndl_t *hndl, |
| 1879 | char *devname, |
| 1880 | char *vndname, |
| 1881 | uint8_t bearer_id, |
| 1882 | uint16_t sequence, |
| 1883 | uint32_t grantsize, |
| 1884 | uint8_t ack, |
| 1885 | uint16_t *error_code) |
| 1886 | { |
Sean Tranchetti | 51133f5 | 2019-02-12 12:54:34 -0700 | [diff] [blame] | 1887 | struct tcmsg flowinfo; |
Sean Tranchetti | 51133f5 | 2019-02-12 12:54:34 -0700 | [diff] [blame] | 1888 | struct nlmsg req; |
| 1889 | unsigned int devindex = 0; |
| 1890 | size_t reqsize; |
| 1891 | int rc; |
| 1892 | |
| 1893 | memset(&req, 0, sizeof(req)); |
| 1894 | memset(&flowinfo, 0, sizeof(flowinfo)); |
| 1895 | |
| 1896 | if (!hndl || !devname || !error_code ||_rmnetctl_check_dev_name(devname) || |
| 1897 | _rmnetctl_check_dev_name(vndname)) |
| 1898 | return RMNETCTL_INVALID_ARG; |
| 1899 | |
| 1900 | reqsize = NLMSG_DATA_SIZE - sizeof(struct rtattr); |
| 1901 | req.nl_addr.nlmsg_type = RTM_NEWLINK; |
| 1902 | req.nl_addr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); |
| 1903 | req.nl_addr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; |
| 1904 | req.nl_addr.nlmsg_seq = hndl->transaction_id; |
| 1905 | hndl->transaction_id++; |
| 1906 | |
| 1907 | /* Get index of devname*/ |
| 1908 | devindex = if_nametoindex(devname); |
| 1909 | if (devindex == 0) { |
| 1910 | *error_code = errno; |
| 1911 | return RMNETCTL_KERNEL_ERR; |
| 1912 | } |
| 1913 | |
Sean Tranchetti | 4fb7294 | 2019-02-12 15:36:30 -0700 | [diff] [blame] | 1914 | flowinfo.tcm_family = RMNET_FLOW_MSG_CONTROL; |
Sean Tranchetti | 51133f5 | 2019-02-12 12:54:34 -0700 | [diff] [blame] | 1915 | flowinfo.tcm__pad1 = bearer_id; |
| 1916 | flowinfo.tcm__pad2 = sequence; |
| 1917 | flowinfo.tcm_parent = ack; |
| 1918 | flowinfo.tcm_info = grantsize; |
| 1919 | |
Sean Tranchetti | d9d69eb | 2019-02-12 14:30:49 -0700 | [diff] [blame] | 1920 | rc = rmnet_fill_flow_msg(&req, &reqsize, devindex, vndname, &flowinfo); |
| 1921 | if (rc != RMNETCTL_SUCCESS) { |
| 1922 | *error_code = RMNETCTL_API_ERR_RTA_FAILURE; |
Sean Tranchetti | 51133f5 | 2019-02-12 12:54:34 -0700 | [diff] [blame] | 1923 | return rc; |
Sean Tranchetti | d9d69eb | 2019-02-12 14:30:49 -0700 | [diff] [blame] | 1924 | } |
Sean Tranchetti | 51133f5 | 2019-02-12 12:54:34 -0700 | [diff] [blame] | 1925 | |
| 1926 | if (send(hndl->netlink_fd, &req, req.nl_addr.nlmsg_len, 0) < 0) { |
| 1927 | *error_code = RMNETCTL_API_ERR_MESSAGE_SEND; |
| 1928 | return RMNETCTL_LIB_ERR; |
| 1929 | } |
| 1930 | |
| 1931 | return rmnet_get_ack(hndl, error_code); |
| 1932 | } |
| 1933 | |
| 1934 | |
| 1935 | int rtrmnet_flow_state_up(rmnetctl_hndl_t *hndl, |
| 1936 | char *devname, |
| 1937 | char *vndname, |
| 1938 | uint32_t instance, |
| 1939 | uint32_t ep_type, |
| 1940 | uint32_t ifaceid, |
| 1941 | int flags, |
| 1942 | uint16_t *error_code) |
| 1943 | { |
Sean Tranchetti | 51133f5 | 2019-02-12 12:54:34 -0700 | [diff] [blame] | 1944 | struct tcmsg flowinfo; |
Sean Tranchetti | 51133f5 | 2019-02-12 12:54:34 -0700 | [diff] [blame] | 1945 | struct nlmsg req; |
| 1946 | unsigned int devindex = 0; |
| 1947 | size_t reqsize; |
| 1948 | int rc; |
| 1949 | |
| 1950 | memset(&req, 0, sizeof(req)); |
| 1951 | memset(&flowinfo, 0, sizeof(flowinfo)); |
| 1952 | |
| 1953 | if (!hndl || !devname || !error_code ||_rmnetctl_check_dev_name(devname) || |
| 1954 | _rmnetctl_check_dev_name(vndname)) |
| 1955 | return RMNETCTL_INVALID_ARG; |
| 1956 | |
| 1957 | reqsize = NLMSG_DATA_SIZE - sizeof(struct rtattr); |
| 1958 | req.nl_addr.nlmsg_type = RTM_NEWLINK; |
| 1959 | req.nl_addr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); |
| 1960 | req.nl_addr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; |
| 1961 | req.nl_addr.nlmsg_seq = hndl->transaction_id; |
| 1962 | hndl->transaction_id++; |
| 1963 | |
| 1964 | /* Get index of devname*/ |
| 1965 | devindex = if_nametoindex(devname); |
| 1966 | if (devindex == 0) { |
| 1967 | *error_code = errno; |
| 1968 | return RMNETCTL_KERNEL_ERR; |
| 1969 | } |
| 1970 | |
Sean Tranchetti | 51133f5 | 2019-02-12 12:54:34 -0700 | [diff] [blame] | 1971 | flowinfo.tcm_handle = instance; |
Sean Tranchetti | 4fb7294 | 2019-02-12 15:36:30 -0700 | [diff] [blame] | 1972 | flowinfo.tcm_family = RMNET_FLOW_MSG_UP; |
Sean Tranchetti | 51133f5 | 2019-02-12 12:54:34 -0700 | [diff] [blame] | 1973 | flowinfo.tcm_ifindex = flags; |
| 1974 | flowinfo.tcm_parent = ifaceid; |
| 1975 | flowinfo.tcm_info = ep_type; |
| 1976 | |
Sean Tranchetti | d9d69eb | 2019-02-12 14:30:49 -0700 | [diff] [blame] | 1977 | rc = rmnet_fill_flow_msg(&req, &reqsize, devindex, vndname, &flowinfo); |
| 1978 | if (rc != RMNETCTL_SUCCESS) { |
| 1979 | *error_code = RMNETCTL_API_ERR_RTA_FAILURE; |
Sean Tranchetti | 51133f5 | 2019-02-12 12:54:34 -0700 | [diff] [blame] | 1980 | return rc; |
Sean Tranchetti | d9d69eb | 2019-02-12 14:30:49 -0700 | [diff] [blame] | 1981 | } |
Sean Tranchetti | 51133f5 | 2019-02-12 12:54:34 -0700 | [diff] [blame] | 1982 | |
| 1983 | if (send(hndl->netlink_fd, &req, req.nl_addr.nlmsg_len, 0) < 0) { |
| 1984 | *error_code = RMNETCTL_API_ERR_MESSAGE_SEND; |
| 1985 | return RMNETCTL_LIB_ERR; |
| 1986 | } |
| 1987 | |
| 1988 | return rmnet_get_ack(hndl, error_code); |
| 1989 | } |
| 1990 | |
| 1991 | |
| 1992 | int rtrmnet_flow_state_down(rmnetctl_hndl_t *hndl, |
| 1993 | char *devname, |
| 1994 | char *vndname, |
| 1995 | uint32_t instance, |
| 1996 | uint16_t *error_code) |
| 1997 | { |
Sean Tranchetti | 51133f5 | 2019-02-12 12:54:34 -0700 | [diff] [blame] | 1998 | struct tcmsg flowinfo; |
Sean Tranchetti | 51133f5 | 2019-02-12 12:54:34 -0700 | [diff] [blame] | 1999 | struct nlmsg req; |
| 2000 | unsigned int devindex = 0; |
| 2001 | size_t reqsize; |
| 2002 | int rc; |
| 2003 | |
| 2004 | memset(&req, 0, sizeof(req)); |
| 2005 | memset(&flowinfo, 0, sizeof(flowinfo)); |
| 2006 | |
| 2007 | if (!hndl || !devname || !error_code ||_rmnetctl_check_dev_name(devname) || |
| 2008 | _rmnetctl_check_dev_name(vndname)) |
| 2009 | return RMNETCTL_INVALID_ARG; |
| 2010 | |
| 2011 | reqsize = NLMSG_DATA_SIZE - sizeof(struct rtattr); |
| 2012 | req.nl_addr.nlmsg_type = RTM_NEWLINK; |
| 2013 | req.nl_addr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); |
| 2014 | req.nl_addr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; |
| 2015 | req.nl_addr.nlmsg_seq = hndl->transaction_id; |
| 2016 | hndl->transaction_id++; |
| 2017 | |
| 2018 | /* Get index of devname*/ |
| 2019 | devindex = if_nametoindex(devname); |
| 2020 | if (devindex == 0) { |
| 2021 | *error_code = errno; |
| 2022 | return RMNETCTL_KERNEL_ERR; |
| 2023 | } |
| 2024 | |
Conner Huff | d0f3eca | 2018-05-18 11:37:46 -0700 | [diff] [blame] | 2025 | flowinfo.tcm_handle = instance; |
Sean Tranchetti | 4fb7294 | 2019-02-12 15:36:30 -0700 | [diff] [blame] | 2026 | flowinfo.tcm_family = RMNET_FLOW_MSG_DOWN; |
Conner Huff | d0f3eca | 2018-05-18 11:37:46 -0700 | [diff] [blame] | 2027 | |
Sean Tranchetti | d9d69eb | 2019-02-12 14:30:49 -0700 | [diff] [blame] | 2028 | rc = rmnet_fill_flow_msg(&req, &reqsize, devindex, vndname, &flowinfo); |
| 2029 | if (rc != RMNETCTL_SUCCESS) { |
| 2030 | *error_code = RMNETCTL_API_ERR_RTA_FAILURE; |
Sean Tranchetti | 51133f5 | 2019-02-12 12:54:34 -0700 | [diff] [blame] | 2031 | return rc; |
Sean Tranchetti | d9d69eb | 2019-02-12 14:30:49 -0700 | [diff] [blame] | 2032 | } |
Conner Huff | d0f3eca | 2018-05-18 11:37:46 -0700 | [diff] [blame] | 2033 | |
| 2034 | if (send(hndl->netlink_fd, &req, req.nl_addr.nlmsg_len, 0) < 0) { |
| 2035 | *error_code = RMNETCTL_API_ERR_MESSAGE_SEND; |
| 2036 | return RMNETCTL_LIB_ERR; |
| 2037 | } |
| 2038 | |
| 2039 | return rmnet_get_ack(hndl, error_code); |
| 2040 | } |
Sean Tranchetti | f74a76a | 2018-12-18 15:28:08 -0700 | [diff] [blame] | 2041 | |
| 2042 | int rtrmnet_set_qmi_scale(rmnetctl_hndl_t *hndl, |
| 2043 | char *devname, |
| 2044 | char *vndname, |
| 2045 | uint32_t scale, |
| 2046 | uint16_t *error_code) |
| 2047 | { |
| 2048 | struct tcmsg flowinfo; |
| 2049 | struct nlmsg req; |
| 2050 | unsigned int devindex = 0; |
| 2051 | size_t reqsize; |
| 2052 | int rc; |
| 2053 | |
| 2054 | memset(&req, 0, sizeof(req)); |
| 2055 | memset(&flowinfo, 0, sizeof(flowinfo)); |
| 2056 | |
| 2057 | if (!hndl || !devname || !error_code ||_rmnetctl_check_dev_name(devname) || |
| 2058 | _rmnetctl_check_dev_name(vndname) || !scale) |
| 2059 | return RMNETCTL_INVALID_ARG; |
| 2060 | |
| 2061 | reqsize = NLMSG_DATA_SIZE - sizeof(struct rtattr); |
| 2062 | req.nl_addr.nlmsg_type = RTM_NEWLINK; |
| 2063 | req.nl_addr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); |
| 2064 | req.nl_addr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; |
| 2065 | req.nl_addr.nlmsg_seq = hndl->transaction_id; |
| 2066 | hndl->transaction_id++; |
| 2067 | |
| 2068 | /* Get index of devname*/ |
| 2069 | devindex = if_nametoindex(devname); |
| 2070 | if (devindex == 0) { |
| 2071 | *error_code = errno; |
| 2072 | return RMNETCTL_KERNEL_ERR; |
| 2073 | } |
| 2074 | |
| 2075 | flowinfo.tcm_ifindex = scale; |
| 2076 | flowinfo.tcm_family = RMNET_FLOW_MSG_QMI_SCALE; |
| 2077 | |
| 2078 | rc = rmnet_fill_flow_msg(&req, &reqsize, devindex, vndname, &flowinfo); |
| 2079 | if (rc != RMNETCTL_SUCCESS) { |
| 2080 | *error_code = RMNETCTL_API_ERR_RTA_FAILURE; |
| 2081 | return rc; |
| 2082 | } |
| 2083 | |
| 2084 | if (send(hndl->netlink_fd, &req, req.nl_addr.nlmsg_len, 0) < 0) { |
| 2085 | *error_code = RMNETCTL_API_ERR_MESSAGE_SEND; |
| 2086 | return RMNETCTL_LIB_ERR; |
| 2087 | } |
| 2088 | |
| 2089 | return rmnet_get_ack(hndl, error_code); |
| 2090 | } |
| 2091 | |
| 2092 | int rtrmnet_set_wda_freq(rmnetctl_hndl_t *hndl, |
| 2093 | char *devname, |
| 2094 | char *vndname, |
| 2095 | uint32_t freq, |
| 2096 | uint16_t *error_code) |
| 2097 | { |
| 2098 | struct tcmsg flowinfo; |
| 2099 | struct nlmsg req; |
| 2100 | unsigned int devindex = 0; |
| 2101 | size_t reqsize; |
| 2102 | int rc; |
| 2103 | |
| 2104 | memset(&req, 0, sizeof(req)); |
| 2105 | memset(&flowinfo, 0, sizeof(flowinfo)); |
| 2106 | |
| 2107 | if (!hndl || !devname || !error_code ||_rmnetctl_check_dev_name(devname) || |
| 2108 | _rmnetctl_check_dev_name(vndname)) |
| 2109 | return RMNETCTL_INVALID_ARG; |
| 2110 | |
| 2111 | reqsize = NLMSG_DATA_SIZE - sizeof(struct rtattr); |
| 2112 | req.nl_addr.nlmsg_type = RTM_NEWLINK; |
| 2113 | req.nl_addr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); |
| 2114 | req.nl_addr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; |
| 2115 | req.nl_addr.nlmsg_seq = hndl->transaction_id; |
| 2116 | hndl->transaction_id++; |
| 2117 | |
| 2118 | /* Get index of devname*/ |
| 2119 | devindex = if_nametoindex(devname); |
| 2120 | if (devindex == 0) { |
| 2121 | *error_code = errno; |
| 2122 | return RMNETCTL_KERNEL_ERR; |
| 2123 | } |
| 2124 | |
| 2125 | flowinfo.tcm_ifindex = freq; |
| 2126 | flowinfo.tcm_family = RMNET_FLOW_MSG_WDA_FREQ; |
| 2127 | |
| 2128 | rc = rmnet_fill_flow_msg(&req, &reqsize, devindex, vndname, &flowinfo); |
| 2129 | if (rc != RMNETCTL_SUCCESS) { |
| 2130 | *error_code = RMNETCTL_API_ERR_RTA_FAILURE; |
| 2131 | return rc; |
| 2132 | } |
| 2133 | |
| 2134 | if (send(hndl->netlink_fd, &req, req.nl_addr.nlmsg_len, 0) < 0) { |
| 2135 | *error_code = RMNETCTL_API_ERR_MESSAGE_SEND; |
| 2136 | return RMNETCTL_LIB_ERR; |
| 2137 | } |
| 2138 | |
| 2139 | return rmnet_get_ack(hndl, error_code); |
| 2140 | } |