diff --git a/rmnetctl/cli/rmnetcli.c b/rmnetctl/cli/rmnetcli.c index c02850b..a40be0a 100644 --- a/rmnetctl/cli/rmnetcli.c +++ b/rmnetctl/cli/rmnetcli.c @@ -222,6 +222,31 @@ static void rmnet_api_usage(void) printf(_2TABS" by inputting dev name\n\n"); printf("rmnetcli -n bridgelink Bridge a vnd and a dev"); printf(_2TABS" by specifying dev id and vnd id\n\n"); + printf("rmnetcli -n flowactivate activate a flow\n"); + printf(_2TABS" string - vnd device name\n\n"); + printf(_2TABS" int - bearer id\n\n"); + printf(_2TABS" int - flow id\n\n"); + printf(_2TABS" int - ip type\n\n"); + printf(_2TABS" int - flow handle\n\n"); + printf("rmnetcli -n flowdel delete a flow\n"); + printf(_2TABS" string - vnd device name\n\n"); + printf(_2TABS" int - bearer id\n\n"); + printf(_2TABS" int - flow id\n\n"); + printf(_2TABS" int - ip type\n\n"); + printf("rmnetcli -n flowcontrol "); + printf(_2TABS" string - vnd device name\n\n"); + printf(_2TABS" int - bearer id\n\n"); + printf(_2TABS" int - sequence\n\n"); + printf(_2TABS" int - grant size\n\n"); + printf(_2TABS" int - ack\n\n"); + printf("rmnetcli -n systemup \n"); + printf(_2TABS" string - vnd device name\n\n"); + printf(_2TABS" int - bearer id\n\n"); + printf(_2TABS" int - ep type\n\n"); + printf(_2TABS" int - iface id\n\n"); + printf(_2TABS" int - flags\n\n"); + printf("rmnetcli -n systemdown \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); diff --git a/rmnetctl/inc/librmnetctl.h b/rmnetctl/inc/librmnetctl.h index 3d622bf..7ecbcb9 100644 --- a/rmnetctl/inc/librmnetctl.h +++ b/rmnetctl/inc/librmnetctl.h @@ -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 */ diff --git a/rmnetctl/src/librmnetctl.c b/rmnetctl/src/librmnetctl.c index 731681a..b4dc543 100644 --- a/rmnetctl/src/librmnetctl.c +++ b/rmnetctl/src/librmnetctl.c @@ -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); +}