• 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-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