1/******************************************************************************
2
3			L I B R M N E T C T L . C
4
5Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
6
7Redistribution and use in source and binary forms, with or without
8modification, are permitted provided that the following conditions are
9met:
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
20THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
21WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
22MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
23ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
24BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
27BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
29OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
30IF 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*/
105static 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*/
217static 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*/
238static 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*/
258static 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*/
278static 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*/
300static 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
313int 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
374void rmnetctl_cleanup(rmnetctl_hndl_t *hndl)
375{
376	if (!hndl)
377		return;
378	close(hndl->netlink_fd);
379	free(hndl);
380}
381
382int 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
418int 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
458int 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
500int 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
545int 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
584int 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
632int 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
679int 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
718int 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
772int 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
818int 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
826int 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
872int 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