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