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:
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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 */
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user