librmnetctl: Egress qos for rmnet driver

Additional flow control support added for rmnet driver.
Supported by the addition of IFLA_VLAN_EGRESS_QOS netlink
attributes in rmnet driver and this RTM_NEWLINK message
configuration api.

•   flow_activate (uint16 bearer_id, uint32 flow_id, uint8 ip_type, uint32 tcm_handle)
•   flow_delete (uint16 bearer_id)
•   flow_control (uint16 bearer_id, uint32 grant_size, uint16 seq, uint8 ack)
•   flow_state_up (uint16 instance, uint32 ep_type, uint32 iface_id)
•   flow_state_down (uint16 instance)

CRs-Fixed: 2224576
Change-Id: Ib8b337c840631ef8a3d36884e42a4faea153ba18
This commit is contained in:
Conner Huff
2018-05-18 11:37:46 -07:00
committed by Gerrit - the friendly Code Review server
parent 2b07e91d73
commit d0f3eca57d
3 changed files with 674 additions and 0 deletions

View File

@@ -222,6 +222,31 @@ static void rmnet_api_usage(void)
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");
printf("rmnetcli -n flowactivate <real dev> activate a flow\n");
printf(_2TABS" <vnd_name> string - vnd device name\n\n");
printf(_2TABS" <bearer_id> int - bearer id\n\n");
printf(_2TABS" <flow id> int - flow id\n\n");
printf(_2TABS" <ip type> int - ip type\n\n");
printf(_2TABS" <handle> int - flow handle\n\n");
printf("rmnetcli -n flowdel <real dev> delete a flow\n");
printf(_2TABS" <vnd_name> string - vnd device name\n\n");
printf(_2TABS" <bearer_id> int - bearer id\n\n");
printf(_2TABS" <flow id> int - flow id\n\n");
printf(_2TABS" <ip type> int - ip type\n\n");
printf("rmnetcli -n flowcontrol <real dev>");
printf(_2TABS" <vnd_name> string - vnd device name\n\n");
printf(_2TABS" <bearer_id> int - bearer id\n\n");
printf(_2TABS" <seq> int - sequence\n\n");
printf(_2TABS" <grant size> int - grant size\n\n");
printf(_2TABS" <ack> int - ack\n\n");
printf("rmnetcli -n systemup <real dev>\n");
printf(_2TABS" <vnd_name> string - vnd device name\n\n");
printf(_2TABS" <instance> int - bearer id\n\n");
printf(_2TABS" <eptype> int - ep type\n\n");
printf(_2TABS" <iface_id> int - iface id\n\n");
printf(_2TABS" <flags> int - flags\n\n");
printf("rmnetcli -n systemdown <real dev> <vnd name> <instance>\n\n ");
}
@@ -345,6 +370,72 @@ static int rmnet_api_call(int argc, char *argv[])
argv[2],
&error_number);
}
else if (!strcmp(*argv, "flowactivate")) {
_RMNETCLI_CHECKNULL(argv[1]);
_RMNETCLI_CHECKNULL(argv[2]);
_RMNETCLI_CHECKNULL(argv[3]);
_RMNETCLI_CHECKNULL(argv[4]);
_RMNETCLI_CHECKNULL(argv[5]);
return_code = rtrmnet_activate_flow(handle, argv[1], argv[2],
_STRTOUI8(argv[3]),
_STRTOI32(argv[4]),
_STRTOUI32(argv[5]),
_STRTOUI32(argv[6]),
&error_number);
} else if (!strcmp(*argv, "flowdel")) {
_RMNETCLI_CHECKNULL(argv[1]);
_RMNETCLI_CHECKNULL(argv[2]);
_RMNETCLI_CHECKNULL(argv[3]);
_RMNETCLI_CHECKNULL(argv[4]);
_RMNETCLI_CHECKNULL(argv[5]);
return_code = rtrmnet_delete_flow(handle, argv[1], argv[2],
_STRTOUI8(argv[3]),
_STRTOUI32(argv[4]),
_STRTOI32(argv[5]),
&error_number);
} else if (!strcmp(*argv, "flowcontrol")) {
_RMNETCLI_CHECKNULL(argv[1]);
_RMNETCLI_CHECKNULL(argv[2]);
_RMNETCLI_CHECKNULL(argv[3]);
_RMNETCLI_CHECKNULL(argv[4]);
_RMNETCLI_CHECKNULL(argv[5]);
_RMNETCLI_CHECKNULL(argv[6]);
return_code = rtrmnet_control_flow(handle, argv[1], argv[2],
_STRTOUI8(argv[3]),
_STRTOUI32(argv[4]),
_STRTOUI16(argv[5]),
_STRTOUI8(argv[6]),
&error_number);
} else if (!strcmp(*argv, "systemup")) {
_RMNETCLI_CHECKNULL(argv[1]);
_RMNETCLI_CHECKNULL(argv[2]);
_RMNETCLI_CHECKNULL(argv[3]);
_RMNETCLI_CHECKNULL(argv[4]);
_RMNETCLI_CHECKNULL(argv[5]);
_RMNETCLI_CHECKNULL(argv[6]);
return_code = rtrmnet_flow_state_up(handle, argv[1], argv[2],
_STRTOUI32(argv[3]),
_STRTOUI32(argv[4]),
_STRTOUI32(argv[5]),
_STRTOUI32(argv[6]),
&error_number);
} else if (!strcmp(*argv, "systemdown")) {
_RMNETCLI_CHECKNULL(argv[1]);
_RMNETCLI_CHECKNULL(argv[2]);
_RMNETCLI_CHECKNULL(argv[3]);
return_code = rtrmnet_flow_state_down(handle, argv[1], argv[2],
_STRTOUI32(argv[3]),
&error_number);
}
goto end;
} else {
return_code = rmnetctl_init(&handle, &error_number);

View File

@@ -600,5 +600,50 @@ int rtrmnet_ctl_changevnd(rmnetctl_hndl_t *hndl, char *devname, char *vndname,
int rtrmnet_ctl_bridgevnd(rmnetctl_hndl_t *hndl, char *devname, char *vndname,
uint16_t *error_code);
int rtrmnet_activate_flow(rmnetctl_hndl_t *hndl,
char *devname,
char *vndname,
uint8_t bearer_id,
uint32_t flow_id,
int ip_type,
uint32_t tcm_handle,
uint16_t *error_code);
int rtrmnet_delete_flow(rmnetctl_hndl_t *hndl,
char *devname,
char *vndname,
uint8_t bearer_id,
uint32_t flow_id,
int ip_type,
uint16_t *error_code);
int rtrmnet_control_flow(rmnetctl_hndl_t *hndl,
char *devname,
char *vndname,
uint8_t bearer_id,
uint16_t sequence,
uint32_t grantsize,
uint8_t ack,
uint16_t *error_code);
int rtrmnet_flow_state_down(rmnetctl_hndl_t *hndl,
char *devname,
char *vndname,
uint32_t instance,
uint16_t *error_code);
int rtrmnet_flow_state_up(rmnetctl_hndl_t *hndl,
char *devname,
char *vndname,
uint32_t instance,
uint32_t ep_type,
uint32_t ifaceid,
int flags,
uint16_t *error_code);
#endif /* not defined LIBRMNETCTL_H */

View File

@@ -1367,3 +1367,541 @@ int rtrmnet_ctl_bridgevnd(rmnetctl_hndl_t *hndl, char *devname, char *vndname,
return rmnet_get_ack(hndl, error_code);
}
int rtrmnet_activate_flow(rmnetctl_hndl_t *hndl,
char *devname,
char *vndname,
uint8_t bearer_id,
uint32_t flow_id,
int ip_type,
uint32_t tcm_handle,
uint16_t *error_code)
{
struct rtattr *attrinfo, *datainfo, *linkinfo;
struct tcmsg flowinfo;
char *kind = "rmnet";
struct nlmsg req;
int devindex = 0;
int val = 0;
memset(&req, 0, sizeof(req));
memset(&flowinfo, 0, sizeof(flowinfo));
if (!hndl || !devname || !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));
flowinfo.tcm_handle = tcm_handle;
flowinfo.tcm_family = 0x1;
flowinfo.tcm__pad1 = bearer_id;
flowinfo.tcm_ifindex = ip_type;
flowinfo.tcm_parent = flow_id;
attrinfo = (struct rtattr *)(((char *)&req) +
NLMSG_ALIGN(req.nl_addr.nlmsg_len));
attrinfo->rta_type = IFLA_VLAN_EGRESS_QOS;
attrinfo->rta_len = RTA_LENGTH(sizeof(flowinfo));
memcpy(RTA_DATA(attrinfo), &flowinfo, sizeof(flowinfo));
req.nl_addr.nlmsg_len = NLMSG_ALIGN(req.nl_addr.nlmsg_len) +
RTA_ALIGN(RTA_LENGTH(sizeof(flowinfo)));
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_delete_flow(rmnetctl_hndl_t *hndl,
char *devname,
char *vndname,
uint8_t bearer_id,
uint32_t flow_id,
int ip_type,
uint16_t *error_code)
{
struct rtattr *attrinfo, *datainfo, *linkinfo;
struct tcmsg flowinfo;
char *kind = "rmnet";
struct nlmsg req;
int devindex = 0;
int val = 0;
memset(&req, 0, sizeof(req));
memset(&flowinfo, 0, sizeof(flowinfo));
if (!hndl || !devname || !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));
flowinfo.tcm_family = 0x2;
flowinfo.tcm_ifindex = ip_type;
flowinfo.tcm__pad1 = bearer_id;
flowinfo.tcm_parent = flow_id;
attrinfo = (struct rtattr *)(((char *)&req) +
NLMSG_ALIGN(req.nl_addr.nlmsg_len));
attrinfo->rta_type = IFLA_VLAN_EGRESS_QOS;
attrinfo->rta_len = RTA_LENGTH(sizeof(flowinfo));
memcpy(RTA_DATA(attrinfo), &flowinfo, sizeof(flowinfo));
req.nl_addr.nlmsg_len = NLMSG_ALIGN(req.nl_addr.nlmsg_len) +
RTA_ALIGN(RTA_LENGTH(sizeof(flowinfo)));
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_control_flow(rmnetctl_hndl_t *hndl,
char *devname,
char *vndname,
uint8_t bearer_id,
uint16_t sequence,
uint32_t grantsize,
uint8_t ack,
uint16_t *error_code)
{
struct rtattr *attrinfo, *datainfo, *linkinfo;
struct tcmsg flowinfo;
char *kind = "rmnet";
struct nlmsg req;
int devindex = 0;
int val = 0;
memset(&req, 0, sizeof(req));
memset(&flowinfo, 0, sizeof(flowinfo));
if (!hndl || !devname || !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));
flowinfo.tcm_family = 0x3;
flowinfo.tcm__pad1 = bearer_id;
flowinfo.tcm__pad2 = sequence;
flowinfo.tcm_parent = ack;
flowinfo.tcm_info = grantsize;
attrinfo = (struct rtattr *)(((char *)&req) +
NLMSG_ALIGN(req.nl_addr.nlmsg_len));
attrinfo->rta_type = IFLA_VLAN_EGRESS_QOS;
attrinfo->rta_len = RTA_LENGTH(sizeof(flowinfo));
memcpy(RTA_DATA(attrinfo), &flowinfo, sizeof(flowinfo));
req.nl_addr.nlmsg_len = NLMSG_ALIGN(req.nl_addr.nlmsg_len) +
RTA_ALIGN(RTA_LENGTH(sizeof(flowinfo)));
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_flow_state_up(rmnetctl_hndl_t *hndl,
char *devname,
char *vndname,
uint32_t instance,
uint32_t ep_type,
uint32_t ifaceid,
int flags,
uint16_t *error_code)
{
struct rtattr *attrinfo, *datainfo, *linkinfo;
struct tcmsg flowinfo;
char *kind = "rmnet";
struct nlmsg req;
int devindex = 0;
int val = 0;
memset(&req, 0, sizeof(req));
memset(&flowinfo, 0, sizeof(flowinfo));
if (!hndl || !devname || !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));
flowinfo.tcm_handle = instance;
flowinfo.tcm_family = 0x4;
flowinfo.tcm_ifindex = flags;
flowinfo.tcm_parent = ifaceid;
flowinfo.tcm_info = ep_type;
attrinfo = (struct rtattr *)(((char *)&req) +
NLMSG_ALIGN(req.nl_addr.nlmsg_len));
attrinfo->rta_type = IFLA_VLAN_EGRESS_QOS;
attrinfo->rta_len = RTA_LENGTH(sizeof(flowinfo));
memcpy(RTA_DATA(attrinfo), &flowinfo, sizeof(flowinfo));
req.nl_addr.nlmsg_len = NLMSG_ALIGN(req.nl_addr.nlmsg_len) +
RTA_ALIGN(RTA_LENGTH(sizeof(flowinfo)));
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_flow_state_down(rmnetctl_hndl_t *hndl,
char *devname,
char *vndname,
uint32_t instance,
uint16_t *error_code)
{
struct rtattr *attrinfo, *datainfo, *linkinfo;
struct tcmsg flowinfo;
char *kind = "rmnet";
struct nlmsg req;
int devindex = 0;
int val = 0;
memset(&req, 0, sizeof(req));
memset(&flowinfo, 0, sizeof(flowinfo));
if (!hndl || !devname || !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));
flowinfo.tcm_handle = instance;
flowinfo.tcm_family = 0x5;
attrinfo = (struct rtattr *)(((char *)&req) +
NLMSG_ALIGN(req.nl_addr.nlmsg_len));
attrinfo->rta_type = IFLA_VLAN_EGRESS_QOS;
attrinfo->rta_len = RTA_LENGTH(sizeof(flowinfo));
memcpy(RTA_DATA(attrinfo), &flowinfo, sizeof(flowinfo));
req.nl_addr.nlmsg_len = NLMSG_ALIGN(req.nl_addr.nlmsg_len) +
RTA_ALIGN(RTA_LENGTH(sizeof(flowinfo)));
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);
}