librmnetctl: Add support for rmnet driver

Add support for newlink, dellink, chagelink and bridge netlink
operations for the netlink type "rmnet" to communicate with the
linux rmnet driver.

CRs-Fixed: 2184454
Change-Id: Ib088fd919a77c926c5e4c3a55062a59ab72fd5d0
This commit is contained in:
Subash Abhinov Kasiviswanathan
2017-12-20 19:11:40 -07:00
parent dba447c1ee
commit 5b903ddace
3 changed files with 601 additions and 9 deletions

View File

@@ -2,7 +2,7 @@
R M N E T C L I . C R M N E T C L I . C
Copyright (c) 2013-2015, 2017 The Linux Foundation. All rights reserved. Copyright (c) 2013-2015, 2017-2018 The Linux Foundation. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are modification, are permitted provided that the following conditions are
@@ -208,6 +208,21 @@ static void rmnet_api_usage(void)
printf(_2TABS" <mdm_flow_hndl> handle - tc flow handle"); printf(_2TABS" <mdm_flow_hndl> handle - tc flow handle");
printf(_2TABS" <tc_flow_hndl> mapping for a virtual network"); printf(_2TABS" <tc_flow_hndl> mapping for a virtual network");
printf(_2TABS" device node\n\n"); printf(_2TABS" device node\n\n");
printf("**************************\n");
printf("RmNet RTM_NETLINK API Usage:\n\n");
printf("rmnetcli -n newlink <dev_id> Add a vnd w/ newlink");
printf(_2TABS" <vnd> string - vnd device_name");
printf(_2TABS" <vnd id> int - new vnd id");
printf(_2TABS" [flags] int - starting flag config\n\n");
printf("rmnetcli -n changelink <dev_id> Change a vnd's flags");
printf(_2TABS" <vnd> string - vnd device_name");
printf(_2TABS" <vnd id> int - new vnd id");
printf(_2TABS" <flags> int - new flag config\n\n");
printf("rmnetcli -n dellink <dev_name> Delete a vnd");
printf(_2TABS" by inputting dev name\n\n");
printf("rmnetcli -n bridgelink <dev_name> Bridge a vnd and a dev");
printf(_2TABS" <vnd id> by specifying dev id and vnd id\n\n");
} }
static void print_rmnetctl_lib_errors(uint16_t error_number) static void print_rmnetctl_lib_errors(uint16_t error_number)
@@ -239,8 +254,11 @@ static void print_rmnet_api_status(int return_code, uint16_t error_number)
else if (return_code == RMNETCTL_LIB_ERR) { else if (return_code == RMNETCTL_LIB_ERR) {
printf("LIBRARY "); printf("LIBRARY ");
print_rmnetctl_lib_errors(error_number); print_rmnetctl_lib_errors(error_number);
} else if (return_code == RMNETCTL_KERNEL_ERR) } else if (return_code == RMNETCTL_KERNEL_ERR) {
printf("KERNEL %s", rmnetctl_error_code_text[error_number]); if (error_number < RMNETCTL_API_ERR_ENUM_LENGTH)
printf("KERNEL ERROR: System or rmnet error %d\n",
error_number);
}
else if (return_code == RMNETCTL_INVALID_ARG) else if (return_code == RMNETCTL_INVALID_ARG)
printf("INVALID_ARG\n"); printf("INVALID_ARG\n");
} }
@@ -275,13 +293,69 @@ static int rmnet_api_call(int argc, char *argv[])
RMNETCTL_CFG_SUCCESS_HELP_COMMAND); RMNETCTL_CFG_SUCCESS_HELP_COMMAND);
return RMNETCTL_LIB_ERR; return RMNETCTL_LIB_ERR;
} }
return_code = rmnetctl_init(&handle, &error_number);
if (return_code!= RMNETCTL_SUCCESS) { if (!strcmp(*argv, "-n")) {
return_code = rtrmnet_ctl_init(&handle, &error_number);
if (return_code != RMNETCTL_SUCCESS) {
print_rmnet_api_status(return_code, error_number); print_rmnet_api_status(return_code, error_number);
return RMNETCTL_LIB_ERR; return RMNETCTL_LIB_ERR;
} }
error_number = RMNETCTL_CFG_FAILURE_NO_COMMAND; error_number = RMNETCTL_CFG_FAILURE_NO_COMMAND;
return_code = RMNETCTL_LIB_ERR; return_code = RMNETCTL_LIB_ERR;
argv++;
argc--;
if ((!argc) || (!*argv)) {
print_rmnet_api_status(RMNETCTL_LIB_ERR,
RMNETCTL_CFG_FAILURE_NO_COMMAND);
return RMNETCTL_LIB_ERR;
}
if (!strcmp(*argv, "newlink")) {
_RMNETCLI_CHECKNULL(argv[1]);
_RMNETCLI_CHECKNULL(argv[2]);
_RMNETCLI_CHECKNULL(argv[3]);
uint32_t flags = 0;
/* If optional flag was used pass it on*/
if (argv[4])
flags = _STRTOI32(argv[4]);
return_code = rtrmnet_ctl_newvnd(handle, argv[1],
argv[2],
&error_number,
_STRTOI32(argv[3]),
flags);
} else if (!strcmp(*argv, "changelink")) {
_RMNETCLI_CHECKNULL(argv[1]);
_RMNETCLI_CHECKNULL(argv[2]);
_RMNETCLI_CHECKNULL(argv[3]);
_RMNETCLI_CHECKNULL(argv[4]);
return_code = rtrmnet_ctl_changevnd(handle, argv[1],
argv[2],
&error_number,
_STRTOI32(argv[3]),
_STRTOI32(argv[4]));
} else if (!strcmp(*argv, "dellink")) {
_RMNETCLI_CHECKNULL(argv[1]);
return_code = rtrmnet_ctl_delvnd(handle, argv[1],
&error_number);
} else if (!strcmp(*argv, "bridge")) {
_RMNETCLI_CHECKNULL(argv[1]);
_RMNETCLI_CHECKNULL(argv[2]);
return_code = rtrmnet_ctl_bridgevnd(handle, argv[1],
argv[2],
&error_number);
}
goto end;
} else {
return_code = rmnetctl_init(&handle, &error_number);
if (return_code != RMNETCTL_SUCCESS) {
print_rmnet_api_status(return_code, error_number);
return RMNETCTL_LIB_ERR;
}
}
error_number = RMNETCTL_CFG_FAILURE_NO_COMMAND;
return_code = RMNETCTL_LIB_ERR;
if (!strcmp(*argv, "assocnetdev")) { if (!strcmp(*argv, "assocnetdev")) {
return_code = rmnet_associate_network_device(handle, return_code = rmnet_associate_network_device(handle,
argv[1], &error_number, RMNETCTL_DEVICE_ASSOCIATE); argv[1], &error_number, RMNETCTL_DEVICE_ASSOCIATE);
@@ -400,8 +474,10 @@ static int rmnet_api_call(int argc, char *argv[])
return_code = rmnet_unset_logical_ep_config(handle, return_code = rmnet_unset_logical_ep_config(handle,
_STRTOI32(argv[1]), argv[2], &error_number); _STRTOI32(argv[1]), argv[2], &error_number);
} }
end:
print_rmnet_api_status(return_code, error_number); print_rmnet_api_status(return_code, error_number);
rmnetctl_cleanup(handle); rmnetctl_cleanup(handle);
rtrmnet_ctl_deinit(handle);
return return_code; return return_code;
} }

View File

@@ -2,7 +2,7 @@
L I B R M N E T C T L . H L I B R M N E T C T L . H
Copyright (c) 2013-2015, 2017 The Linux Foundation. All rights reserved. Copyright (c) 2013-2015, 2017-2018 The Linux Foundation. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are modification, are permitted provided that the following conditions are
@@ -517,5 +517,88 @@ int rmnet_add_del_vnd_tc_flow(rmnetctl_hndl_t *hndl,
uint8_t set_flow, uint8_t set_flow,
uint16_t *error_code); uint16_t *error_code);
/* @brief Public API to initialize the RTM_NETLINK RMNET control driver
* @details Allocates memory for the RmNet handle. Creates and binds to a
* netlink socket if successful
* @param **rmnetctl_hndl_t_val RmNet handle to be initialized
* @return RMNETCTL_SUCCESS if successful
* @return RMNETCTL_LIB_ERR if there was a library error. Check error_code
* @return RMNETCTL_KERNEL_ERR if there was an error in the kernel.
* Check error_code
* @return RMNETCTL_INVALID_ARG if invalid arguments were passed to the API
*/
int rtrmnet_ctl_init(rmnetctl_hndl_t **hndl, uint16_t *error_code);
/* @brief Public API to clean up the RTM_NETLINK RmNeT control handle
* @details Close the socket and free the RmNet handle
* @param *rmnetctl_hndl_t_val RmNet handle to be initialized
* @return void
*/
int rtrmnet_ctl_deinit(rmnetctl_hndl_t *hndl);
/* @brief Public API to create a new virtual device node
* @details Message type is RTM_NEWLINK
* @param hndl RmNet handle for the Netlink message
* @param dev_name Device name new node will be connected to
* @param vnd_name Name of virtual device to be created
* @param error_code Status code of this operation returned from the kernel
* @param index Index node will have
* @param flagconfig Flag configuration device will have
* @return RMNETCTL_SUCCESS if successful
* @return RMNETCTL_LIB_ERR if there was a library error. Check error_code
* @return RMNETCTL_KERNEL_ERR if there was an error in the kernel.
* Check error_code
* @return RMNETCTL_INVALID_ARG if invalid arguments were passed to the API
*/
int rtrmnet_ctl_newvnd(rmnetctl_hndl_t *hndl, char *devname, char *vndname,
uint16_t *error_code, uint8_t index,
uint32_t flagconfig);
/* @brief Public API to delete a virtual device node
* @details Message type is RTM_DELLINK
* @param hndl RmNet handle for the Netlink message
* @param vnd_name Name of virtual device to be deleted
* @param error_code Status code of this operation returned from the kernel
* @return RMNETCTL_SUCCESS if successful
* @return RMNETCTL_LIB_ERR if there was a library error. Check error_code
* @return RMNETCTL_KERNEL_ERR if there was an error in the kernel.
* Check error_code
* @return RMNETCTL_INVALID_ARG if invalid arguments were passed to the API
*/
int rtrmnet_ctl_delvnd(rmnetctl_hndl_t *hndl, char *vndname,
uint16_t *error_code);
/* @brief Public API to change flag's of a virtual device node
* @details Message type is RTM_NEWLINK
* @param hndl RmNet handle for the Netlink message
* @param dev_name Name of device node is connected to
* @param vnd_name Name of virtual device to be changed
* @param error_code Status code of this operation returned from the kernel
* @param flagconfig New flag config vnd should have
* @return RMNETCTL_SUCCESS if successful
* @return RMNETCTL_LIB_ERR if there was a library error. Check error_code
* @return RMNETCTL_KERNEL_ERR if there was an error in the kernel.
* Check error_code
* @return RMNETCTL_INVALID_ARG if invalid arguments were passed to the API
*/
int rtrmnet_ctl_changevnd(rmnetctl_hndl_t *hndl, char *devname, char *vndname,
uint16_t *error_code, uint8_t index,
uint32_t flagconfig);
/* @brief Public API to bridge a vnd and device
* @details Message type is RTM_NEWLINK
* @param hndl RmNet handle for the Netlink message
* @param dev_name device to bridge msg will be sent to
* @param vnd_name vnd name of device that will be dev_name's master
* @param error_code Status code of this operation returned from the kernel
* @return RMNETCTL_SUCCESS if successful
* @return RMNETCTL_LIB_ERR if there was a library error. Check error_code
* @return RMNETCTL_KERNEL_ERR if there was an error in the kernel.
* Check error_code
* @return RMNETCTL_INVALID_ARG if invalid arguments were passed to the API
*/
int rtrmnet_ctl_bridgevnd(rmnetctl_hndl_t *hndl, char *devname, char *vndname,
uint16_t *error_code);
#endif /* not defined LIBRMNETCTL_H */ #endif /* not defined LIBRMNETCTL_H */

View File

@@ -2,7 +2,7 @@
L I B R M N E T C T L . C L I B R M N E T C T L . C
Copyright (c) 2013-2015, 2017 The Linux Foundation. All rights reserved. Copyright (c) 2013-2015, 2017-2018 The Linux Foundation. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are modification, are permitted provided that the following conditions are
@@ -47,6 +47,11 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <stdio.h> #include <stdio.h>
#include <unistd.h> #include <unistd.h>
#include <stdlib.h> #include <stdlib.h>
#include <errno.h>
#include <linux/rtnetlink.h>
#include <linux/gen_stats.h>
#include <net/if.h>
#include <asm/types.h>
#include <linux/rmnet_data.h> #include <linux/rmnet_data.h>
#include "librmnetctl_hndl.h" #include "librmnetctl_hndl.h"
#include "librmnetctl.h" #include "librmnetctl.h"
@@ -78,6 +83,17 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
RMNET_EGRESS_FORMAT_MAP_CKSUMV4) RMNET_EGRESS_FORMAT_MAP_CKSUMV4)
#define min(a, b) (((a) < (b)) ? (a) : (b)) #define min(a, b) (((a) < (b)) ? (a) : (b))
#define NLMSG_TAIL(nmsg) \
((struct rtattr *) (((char *)(nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)))
struct nlmsg {
struct nlmsghdr nl_addr;
struct ifinfomsg ifmsg;
char data[500];
};
/*=========================================================================== /*===========================================================================
LOCAL FUNCTION DEFINITIONS LOCAL FUNCTION DEFINITIONS
===========================================================================*/ ===========================================================================*/
@@ -934,3 +950,420 @@ int rmnet_add_del_vnd_tc_flow(rmnetctl_hndl_t *hndl,
return return_code; return return_code;
} }
/*
* NEW DRIVER API
*/
/* @brief Synchronous method to receive messages to and from the kernel
* using netlink sockets
* @details Receives the ack response from the kernel.
* @param *hndl RmNet handle for this transaction
* @param *error_code Error code if transaction fails
* @return RMNETCTL_API_SUCCESS if successfully able to send and receive message
* from the kernel
* @return RMNETCTL_API_ERR_HNDL_INVALID if RmNet handle for the transaction was
* NULL
* @return RMNETCTL_API_ERR_MESSAGE_RECEIVE if could not receive message from
* the kernel
* @return RMNETCTL_API_ERR_MESSAGE_TYPE if the response type does not
* match
*/
static int rmnet_get_ack(rmnetctl_hndl_t *hndl, uint16_t *error_code)
{
struct nlack {
struct nlmsghdr ackheader;
struct nlmsgerr ackdata;
char data[256];
} ack;
int i;
if (!hndl || !error_code)
return RMNETCTL_INVALID_ARG;
if ((i = recv(hndl->netlink_fd, &ack, sizeof(ack), 0)) < 0) {
*error_code = errno;
return RMNETCTL_API_ERR_MESSAGE_RECEIVE;
}
/*Ack should always be NLMSG_ERROR type*/
if (ack.ackheader.nlmsg_type == NLMSG_ERROR) {
if (ack.ackdata.error == 0) {
*error_code = RMNETCTL_API_SUCCESS;
return RMNETCTL_SUCCESS;
} else {
*error_code = -ack.ackdata.error;
return RMNETCTL_KERNEL_ERR;
}
}
*error_code = RMNETCTL_API_ERR_RETURN_TYPE;
return RMNETCTL_API_FIRST_ERR;
}
/*
* EXPOSED NEW DRIVER API
*/
int rtrmnet_ctl_init(rmnetctl_hndl_t **hndl, uint16_t *error_code)
{
struct sockaddr_nl __attribute__((__may_alias__)) *saddr_ptr;
int netlink_fd = -1;
pid_t pid = 0;
if (!hndl || !error_code)
return RMNETCTL_INVALID_ARG;
*hndl = (rmnetctl_hndl_t *)malloc(sizeof(rmnetctl_hndl_t));
if (!*hndl) {
*error_code = RMNETCTL_API_ERR_HNDL_INVALID;
return RMNETCTL_LIB_ERR;
}
memset(*hndl, 0, sizeof(rmnetctl_hndl_t));
pid = getpid();
if (pid < MIN_VALID_PROCESS_ID) {
free(*hndl);
*error_code = RMNETCTL_INIT_ERR_PROCESS_ID;
return RMNETCTL_LIB_ERR;
}
(*hndl)->pid = KERNEL_PROCESS_ID;
netlink_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
if (netlink_fd < MIN_VALID_SOCKET_FD) {
free(*hndl);
*error_code = RMNETCTL_INIT_ERR_NETLINK_FD;
return RMNETCTL_LIB_ERR;
}
(*hndl)->netlink_fd = netlink_fd;
memset(&(*hndl)->src_addr, 0, sizeof(struct sockaddr_nl));
(*hndl)->src_addr.nl_family = AF_NETLINK;
(*hndl)->src_addr.nl_pid = (*hndl)->pid;
saddr_ptr = &(*hndl)->src_addr;
if (bind((*hndl)->netlink_fd,
(struct sockaddr *)saddr_ptr,
sizeof(struct sockaddr_nl)) < 0) {
close((*hndl)->netlink_fd);
free(*hndl);
*error_code = RMNETCTL_INIT_ERR_BIND;
return RMNETCTL_LIB_ERR;
}
memset(&(*hndl)->dest_addr, 0, sizeof(struct sockaddr_nl));
(*hndl)->dest_addr.nl_family = AF_NETLINK;
(*hndl)->dest_addr.nl_pid = KERNEL_PROCESS_ID;
(*hndl)->dest_addr.nl_groups = UNICAST;
return RMNETCTL_SUCCESS;
}
int rtrmnet_ctl_deinit(rmnetctl_hndl_t *hndl)
{
if (!hndl)
return RMNETCTL_SUCCESS;
close(hndl->netlink_fd);
free(hndl);
return RMNETCTL_SUCCESS;
}
int rtrmnet_ctl_newvnd(rmnetctl_hndl_t *hndl, char *devname, char *vndname,
uint16_t *error_code, uint8_t index,
uint32_t flagconfig)
{
struct rtattr *attrinfo, *datainfo, *linkinfo;
struct ifla_vlan_flags flags;
int devindex = 0, val = 0;
char *kind = "rmnet";
struct nlmsg req;
short id;
if (!hndl || !devname || !vndname || !error_code)
return RMNETCTL_INVALID_ARG;
memset(&req, 0, sizeof(req));
req.nl_addr.nlmsg_type = RTM_NEWLINK;
req.nl_addr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
req.nl_addr.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL |
NLM_F_ACK;
req.nl_addr.nlmsg_seq = hndl->transaction_id;
hndl->transaction_id++;
/* Get index of devname*/
devindex = if_nametoindex(devname);
if (devindex < 0) {
*error_code = errno;
return RMNETCTL_KERNEL_ERR;
}
/* Setup link attr with devindex as data */
val = devindex;
attrinfo = (struct rtattr *)(((char *)&req) +
NLMSG_ALIGN(req.nl_addr.nlmsg_len));
attrinfo->rta_type = IFLA_LINK;
attrinfo->rta_len = RTA_ALIGN(RTA_LENGTH(sizeof(val)));
memcpy(RTA_DATA(attrinfo), &val, sizeof(val));
req.nl_addr.nlmsg_len = NLMSG_ALIGN(req.nl_addr.nlmsg_len) +
RTA_ALIGN(RTA_LENGTH(sizeof(val)));
/* Set up IFLA info kind RMNET that has linkinfo and type */
attrinfo = (struct rtattr *)(((char *)&req) +
NLMSG_ALIGN(req.nl_addr.nlmsg_len));
attrinfo->rta_type = IFLA_IFNAME;
attrinfo->rta_len = RTA_ALIGN(RTA_LENGTH(strlen(vndname) + 1));
memcpy(RTA_DATA(attrinfo), vndname, strlen(vndname) + 1);
req.nl_addr.nlmsg_len = NLMSG_ALIGN(req.nl_addr.nlmsg_len) +
RTA_ALIGN(RTA_LENGTH(strlen(vndname) + 1));
linkinfo = (struct rtattr *)(((char *)&req) +
NLMSG_ALIGN(req.nl_addr.nlmsg_len));
linkinfo->rta_type = IFLA_LINKINFO;
linkinfo->rta_len = RTA_ALIGN(RTA_LENGTH(0));
req.nl_addr.nlmsg_len = NLMSG_ALIGN(req.nl_addr.nlmsg_len) +
RTA_ALIGN(RTA_LENGTH(0));
attrinfo = (struct rtattr *)(((char *)&req) +
NLMSG_ALIGN(req.nl_addr.nlmsg_len));
attrinfo->rta_type = IFLA_INFO_KIND;
attrinfo->rta_len = RTA_ALIGN(RTA_LENGTH(strlen(kind)));
memcpy(RTA_DATA(attrinfo), kind, strlen(kind));
req.nl_addr.nlmsg_len = NLMSG_ALIGN(req.nl_addr.nlmsg_len) +
RTA_ALIGN(RTA_LENGTH(strlen(kind)));
datainfo = (struct rtattr *)(((char *)&req) +
NLMSG_ALIGN(req.nl_addr.nlmsg_len));
datainfo->rta_type = IFLA_INFO_DATA;
datainfo->rta_len = RTA_ALIGN(RTA_LENGTH(0));
req.nl_addr.nlmsg_len = NLMSG_ALIGN(req.nl_addr.nlmsg_len) +
RTA_ALIGN(RTA_LENGTH(0));
id = index;
attrinfo = (struct rtattr *)(((char *)&req) +
NLMSG_ALIGN(req.nl_addr.nlmsg_len));
attrinfo->rta_type = IFLA_VLAN_ID;
attrinfo->rta_len = RTA_LENGTH(sizeof(id));
memcpy(RTA_DATA(attrinfo), &id, sizeof(id));
req.nl_addr.nlmsg_len = NLMSG_ALIGN(req.nl_addr.nlmsg_len) +
RTA_ALIGN(RTA_LENGTH(sizeof(id)));
if (flagconfig != 0) {
flags.mask = flagconfig;
flags.flags = flagconfig;
attrinfo = (struct rtattr *)(((char *)&req) +
NLMSG_ALIGN(req.nl_addr.nlmsg_len));
attrinfo->rta_type = IFLA_VLAN_FLAGS;
attrinfo->rta_len = RTA_LENGTH(sizeof(flags));
memcpy(RTA_DATA(attrinfo), &flags, sizeof(flags));
req.nl_addr.nlmsg_len = NLMSG_ALIGN(req.nl_addr.nlmsg_len) +
RTA_ALIGN(RTA_LENGTH(sizeof(flags)));
}
datainfo->rta_len = (char *)NLMSG_TAIL(&req.nl_addr) - (char *)datainfo;
linkinfo->rta_len = (char *)NLMSG_TAIL(&req.nl_addr) - (char *)linkinfo;
if (send(hndl->netlink_fd, &req, req.nl_addr.nlmsg_len, 0) < 0) {
*error_code = RMNETCTL_API_ERR_MESSAGE_SEND;
return RMNETCTL_LIB_ERR;
}
return rmnet_get_ack(hndl, error_code);
}
int rtrmnet_ctl_delvnd(rmnetctl_hndl_t *hndl, char *vndname,
uint16_t *error_code)
{
int devindex = 0;
struct nlmsg req;
if (!hndl || !vndname || !error_code)
return RMNETCTL_INVALID_ARG;
memset(&req, 0, sizeof(req));
req.nl_addr.nlmsg_type = RTM_DELLINK;
req.nl_addr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
req.nl_addr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
req.nl_addr.nlmsg_seq = hndl->transaction_id;
hndl->transaction_id++;
/* Get index of vndname*/
devindex = if_nametoindex(vndname);
if (devindex < 0) {
*error_code = errno;
return RMNETCTL_KERNEL_ERR;
}
/* Setup index attribute */
req.ifmsg.ifi_index = devindex;
if (send(hndl->netlink_fd, &req, req.nl_addr.nlmsg_len, 0) < 0) {
*error_code = RMNETCTL_API_ERR_MESSAGE_SEND;
return RMNETCTL_LIB_ERR;
}
return rmnet_get_ack(hndl, error_code);
}
int rtrmnet_ctl_changevnd(rmnetctl_hndl_t *hndl, char *devname, char *vndname,
uint16_t *error_code, uint8_t index,
uint32_t flagconfig)
{
struct rtattr *attrinfo, *datainfo, *linkinfo;
struct ifla_vlan_flags flags;
char *kind = "rmnet";
struct nlmsg req;
int devindex = 0;
int val = 0;
short id;
memset(&req, 0, sizeof(req));
if (!hndl || !devname || !vndname || !error_code)
return RMNETCTL_INVALID_ARG;
req.nl_addr.nlmsg_type = RTM_NEWLINK;
req.nl_addr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
req.nl_addr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
req.nl_addr.nlmsg_seq = hndl->transaction_id;
hndl->transaction_id++;
/* Get index of devname*/
devindex = if_nametoindex(devname);
if (devindex < 0) {
*error_code = errno;
return RMNETCTL_KERNEL_ERR;
}
/* Setup link attr with devindex as data */
val = devindex;
attrinfo = (struct rtattr *)(((char *)&req) +
NLMSG_ALIGN(req.nl_addr.nlmsg_len));
attrinfo->rta_type = IFLA_LINK;
attrinfo->rta_len = RTA_ALIGN(RTA_LENGTH(sizeof(val)));
memcpy(RTA_DATA(attrinfo), &val, sizeof(val));
req.nl_addr.nlmsg_len = NLMSG_ALIGN(req.nl_addr.nlmsg_len) +
RTA_ALIGN(RTA_LENGTH(sizeof(val)));
/* Set up IFLA info kind RMNET that has linkinfo and type */
attrinfo = (struct rtattr *)(((char *)&req) +
NLMSG_ALIGN(req.nl_addr.nlmsg_len));
attrinfo->rta_type = IFLA_IFNAME;
attrinfo->rta_len = RTA_ALIGN(RTA_LENGTH(strlen(vndname) + 1));
memcpy(RTA_DATA(attrinfo), vndname, strlen(vndname) + 1);
req.nl_addr.nlmsg_len = NLMSG_ALIGN(req.nl_addr.nlmsg_len) +
RTA_ALIGN(RTA_LENGTH(strlen(vndname) + 1));
linkinfo = (struct rtattr *)(((char *)&req) +
NLMSG_ALIGN(req.nl_addr.nlmsg_len));
linkinfo->rta_type = IFLA_LINKINFO;
linkinfo->rta_len = RTA_ALIGN(RTA_LENGTH(0));
req.nl_addr.nlmsg_len = NLMSG_ALIGN(req.nl_addr.nlmsg_len) +
RTA_ALIGN(RTA_LENGTH(0));
attrinfo = (struct rtattr *)(((char *)&req) +
NLMSG_ALIGN(req.nl_addr.nlmsg_len));
attrinfo->rta_type = IFLA_INFO_KIND;
attrinfo->rta_len = RTA_ALIGN(RTA_LENGTH(strlen(kind)));
memcpy(RTA_DATA(attrinfo), kind, strlen(kind));
req.nl_addr.nlmsg_len = NLMSG_ALIGN(req.nl_addr.nlmsg_len) +
RTA_ALIGN(RTA_LENGTH(strlen(kind)));
datainfo = (struct rtattr *)(((char *)&req) +
NLMSG_ALIGN(req.nl_addr.nlmsg_len));
datainfo->rta_type = IFLA_INFO_DATA;
datainfo->rta_len = RTA_ALIGN(RTA_LENGTH(0));
req.nl_addr.nlmsg_len = NLMSG_ALIGN(req.nl_addr.nlmsg_len) +
RTA_ALIGN(RTA_LENGTH(0));
id = index;
attrinfo = (struct rtattr *)(((char *)&req) +
NLMSG_ALIGN(req.nl_addr.nlmsg_len));
attrinfo->rta_type = IFLA_VLAN_ID;
attrinfo->rta_len = RTA_LENGTH(sizeof(id));
memcpy(RTA_DATA(attrinfo), &id, sizeof(id));
req.nl_addr.nlmsg_len = NLMSG_ALIGN(req.nl_addr.nlmsg_len) +
RTA_ALIGN(RTA_LENGTH(sizeof(id)));
if (flagconfig != 0) {
flags.mask = flagconfig;
flags.flags = flagconfig;
attrinfo = (struct rtattr *)(((char *)&req) +
NLMSG_ALIGN(req.nl_addr.nlmsg_len));
attrinfo->rta_type = IFLA_VLAN_FLAGS;
attrinfo->rta_len = RTA_LENGTH(sizeof(flags));
memcpy(RTA_DATA(attrinfo), &flags, sizeof(flags));
req.nl_addr.nlmsg_len = NLMSG_ALIGN(req.nl_addr.nlmsg_len) +
RTA_ALIGN(RTA_LENGTH(sizeof(flags)));
}
datainfo->rta_len = (char *)NLMSG_TAIL(&req.nl_addr) - (char *)datainfo;
linkinfo->rta_len = (char *)NLMSG_TAIL(&req.nl_addr) - (char *)linkinfo;
if (send(hndl->netlink_fd, &req, req.nl_addr.nlmsg_len, 0) < 0) {
*error_code = RMNETCTL_API_ERR_MESSAGE_SEND;
return RMNETCTL_LIB_ERR;
}
return rmnet_get_ack(hndl, error_code);
}
int rtrmnet_ctl_bridgevnd(rmnetctl_hndl_t *hndl, char *devname, char *vndname,
uint16_t *error_code)
{
int devindex = 0, vndindex = 0;
struct rtattr *masterinfo;
struct nlmsg req;
if (!hndl || !vndname || !devname || !error_code)
return RMNETCTL_INVALID_ARG;
memset(&req, 0, sizeof(req));
req.nl_addr.nlmsg_type = RTM_NEWLINK;
req.nl_addr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
req.nl_addr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
req.nl_addr.nlmsg_seq = hndl->transaction_id;
hndl->transaction_id++;
/* Get index of vndname*/
devindex = if_nametoindex(devname);
if (devindex < 0) {
*error_code = errno;
return RMNETCTL_KERNEL_ERR;
}
vndindex = if_nametoindex(vndname);
if (vndindex < 0) {
*error_code = errno;
return RMNETCTL_KERNEL_ERR;
}
/* Setup index attribute */
req.ifmsg.ifi_index = devindex;
masterinfo = (struct rtattr *)(((char *)&req) +
NLMSG_ALIGN(req.nl_addr.nlmsg_len));
masterinfo->rta_type = IFLA_MASTER;
masterinfo->rta_len = RTA_LENGTH(sizeof(vndindex));
memcpy(RTA_DATA(masterinfo), &vndindex, sizeof(vndindex));
req.nl_addr.nlmsg_len = NLMSG_ALIGN(req.nl_addr.nlmsg_len) +
RTA_ALIGN(RTA_LENGTH(sizeof(vndindex)));
if (send(hndl->netlink_fd, &req, req.nl_addr.nlmsg_len, 0) < 0) {
*error_code = RMNETCTL_API_ERR_MESSAGE_SEND;
return RMNETCTL_LIB_ERR;
}
return rmnet_get_ack(hndl, error_code);
}