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