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:
Sean Tranchetti
2019-01-03 14:33:16 -07:00
parent 4fb7294ca2
commit 1a2abef95b
3 changed files with 148 additions and 1 deletions

View File

@@ -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],

View File

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

View File

@@ -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)
{