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