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