rmnetctl: add getlink library API and CLI option
Add support for the RTM_GETLINK message in order to retrieve the configuration of an RmNet device after it has been created. Change-Id: I7de75c461ab1201a0856911348acef939d3ef172 Signed-off-by: Sean Tranchetti <stranche@codeaurora.org>
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
|
||||
R M N E T C L I . C
|
||||
|
||||
Copyright (c) 2013-2015, 2017-2018 The Linux Foundation. All rights reserved.
|
||||
Copyright (c) 2013-2015, 2017-2019 The Linux Foundation. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
@@ -218,6 +218,7 @@ static void rmnet_api_usage(void)
|
||||
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 getlink <dev_name> Get device 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");
|
||||
@@ -359,6 +360,19 @@ static int rmnet_api_call(int argc, char *argv[])
|
||||
&error_number,
|
||||
_STRTOI32(argv[3]),
|
||||
_STRTOI32(argv[4]));
|
||||
} else if (!strcmp(*argv, "getlink")) {
|
||||
_RMNETCLI_CHECKNULL(argv[1]);
|
||||
uint32_t flags = 0;
|
||||
uint16_t mux_id = 0;
|
||||
|
||||
return_code = rtrmnet_ctl_getvnd(handle, argv[1],
|
||||
&error_number,
|
||||
&mux_id, &flags);
|
||||
if (return_code == RMNETCTL_API_SUCCESS) {
|
||||
printf("Configuration for device %s:\n", argv[1]);
|
||||
printf("\tMux id: %d\n", mux_id);
|
||||
printf("\tData format: 0x%04x\n", flags);
|
||||
}
|
||||
} else if (!strcmp(*argv, "dellink")) {
|
||||
_RMNETCLI_CHECKNULL(argv[1]);
|
||||
return_code = rtrmnet_ctl_delvnd(handle, argv[1],
|
||||
|
||||
@@ -591,6 +591,23 @@ 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 retrieve configuration of a virtual device node
|
||||
* @details Message type is RTM_GETLINK
|
||||
* @param hndl RmNet handle for the Netlink message
|
||||
* @param vndname Name of virtual device to query
|
||||
* @param error_code Status code of this operation returned from the kernel
|
||||
* @param mux_id Where to store the value of the node's mux id
|
||||
* @param flagconfig Where to store the value of the node's data format flags
|
||||
* @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_ARF if invalid arguments were passed to the API
|
||||
*/
|
||||
int rtrmnet_ctl_getvnd(rmnetctl_hndl_t *hndl, char *vndname,
|
||||
uint16_t *error_code, uint16_t *mux_id,
|
||||
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
|
||||
|
||||
@@ -1110,6 +1110,31 @@ static void rta_nested_end(struct nlmsg *req, struct rtattr *start)
|
||||
start->rta_len = (char *)NLMSG_TAIL(&req->nl_addr) - (char *)start;
|
||||
}
|
||||
|
||||
static void rta_parse(struct rtattr **tb, int maxtype, struct rtattr *head,
|
||||
int len)
|
||||
{
|
||||
struct rtattr *rta;
|
||||
|
||||
memset(tb, 0, sizeof(struct rtattr *) * maxtype);
|
||||
for (rta = head; RTA_OK(rta, len);
|
||||
rta = RTA_NEXT(rta, len)) {
|
||||
__u16 type = rta->rta_type & NLA_TYPE_MASK;
|
||||
|
||||
if (type > 0 && type <= maxtype)
|
||||
tb[type] = rta;
|
||||
}
|
||||
}
|
||||
|
||||
static struct rtattr *rta_find(struct rtattr *rta, int attrlen, uint16_t type)
|
||||
{
|
||||
for (; RTA_OK(rta, attrlen); rta = RTA_NEXT(rta, attrlen)) {
|
||||
if (rta->rta_type == (type & NLA_TYPE_MASK))
|
||||
return rta;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* @brief Fill a Netlink messages with the necessary common RTAs for creating a
|
||||
* RTM_NEWLINK message for creating or changing rmnet devices.
|
||||
* @param *req The netlink message
|
||||
@@ -1465,6 +1490,97 @@ int rtrmnet_ctl_changevnd(rmnetctl_hndl_t *hndl, char *devname, char *vndname,
|
||||
return rmnet_get_ack(hndl, error_code);
|
||||
}
|
||||
|
||||
int rtrmnet_ctl_getvnd(rmnetctl_hndl_t *hndl, char *vndname,
|
||||
uint16_t *error_code, uint16_t *mux_id,
|
||||
uint32_t *flagconfig)
|
||||
{
|
||||
struct nlmsg req;
|
||||
struct nlmsghdr *resp;
|
||||
struct rtattr *attrs, *linkinfo, *datainfo;
|
||||
struct rtattr *tb[IFLA_VLAN_MAX + 1];
|
||||
unsigned int devindex = 0;
|
||||
int resp_len;
|
||||
|
||||
memset(&req, 0, sizeof(req));
|
||||
|
||||
if (!hndl || !vndname || !error_code || !(mux_id || flagconfig) ||
|
||||
_rmnetctl_check_dev_name(vndname))
|
||||
return RMNETCTL_INVALID_ARG;
|
||||
|
||||
req.nl_addr.nlmsg_type = RTM_GETLINK;
|
||||
req.nl_addr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
|
||||
req.nl_addr.nlmsg_flags = NLM_F_REQUEST;
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
resp_len = recv(hndl->netlink_fd, NULL, 0, MSG_PEEK | MSG_TRUNC);
|
||||
if (resp_len < 0) {
|
||||
*error_code = errno;
|
||||
return RMNETCTL_API_ERR_MESSAGE_RECEIVE;
|
||||
}
|
||||
|
||||
resp = malloc((size_t)resp_len);
|
||||
if (!resp) {
|
||||
*error_code = errno;
|
||||
return RMNETCTL_LIB_ERR;
|
||||
}
|
||||
|
||||
resp_len = recv(hndl->netlink_fd, (char *)resp, (size_t)resp_len, 0);
|
||||
if (resp_len < 0) {
|
||||
*error_code = errno;
|
||||
free(resp);
|
||||
return RMNETCTL_API_ERR_MESSAGE_RECEIVE;
|
||||
}
|
||||
|
||||
/* Parse out the RT attributes */
|
||||
attrs = (struct rtattr *)((char *)NLMSG_DATA(resp) +
|
||||
NLMSG_ALIGN(sizeof(req.ifmsg)));
|
||||
linkinfo = rta_find(attrs, NLMSG_PAYLOAD(resp, sizeof(req.ifmsg)),
|
||||
IFLA_LINKINFO);
|
||||
if (!linkinfo) {
|
||||
free(resp);
|
||||
*error_code = RMNETCTL_API_ERR_RTA_FAILURE;
|
||||
return RMNETCTL_KERNEL_ERR;
|
||||
}
|
||||
|
||||
datainfo = rta_find(RTA_DATA(linkinfo), RTA_PAYLOAD(linkinfo),
|
||||
IFLA_INFO_DATA);
|
||||
if (!datainfo) {
|
||||
free(resp);
|
||||
*error_code = RMNETCTL_API_ERR_RTA_FAILURE;
|
||||
return RMNETCTL_KERNEL_ERR;
|
||||
}
|
||||
|
||||
/* Parse all the rmnet-specific information from the kernel */
|
||||
rta_parse(tb, IFLA_VLAN_MAX + 1, RTA_DATA(datainfo),
|
||||
RTA_PAYLOAD(datainfo));
|
||||
if (tb[IFLA_VLAN_ID] && mux_id)
|
||||
*mux_id = *((uint16_t *)RTA_DATA(tb[IFLA_VLAN_ID]));
|
||||
if (tb[IFLA_VLAN_FLAGS] && flagconfig) {
|
||||
struct ifla_vlan_flags *flags;
|
||||
|
||||
flags = (struct ifla_vlan_flags *)
|
||||
RTA_DATA(tb[IFLA_VLAN_FLAGS]);
|
||||
*flagconfig = flags->flags;
|
||||
}
|
||||
|
||||
free(resp);
|
||||
return RMNETCTL_API_SUCCESS;
|
||||
}
|
||||
|
||||
int rtrmnet_ctl_bridgevnd(rmnetctl_hndl_t *hndl, char *devname, char *vndname,
|
||||
uint16_t *error_code)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user