Merge c26ed59ecede290aa16461248ceaeea814fa3d68 on remote branch
Change-Id: I02be6148ba32e2b2afa1e474606b23e597e669a0
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 @@
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 @@
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_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..d621f43 100644
--- a/rmnetctl/src/librmnetctl.c
+++ b/rmnetctl/src/librmnetctl.c
@@ -86,17 +86,63 @@
#define NLMSG_TAIL(nmsg) \
((struct rtattr *) (((char *)(nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)))
+#define NLMSG_DATA_SIZE 500
+
+#define CHECK_MEMSCPY(x) ({if (x < 0 ){return RMNETCTL_LIB_ERR;}})
+
struct nlmsg {
struct nlmsghdr nl_addr;
struct ifinfomsg ifmsg;
- char data[500];
+ char data[NLMSG_DATA_SIZE];
};
-
-
/*===========================================================================
LOCAL FUNCTION DEFINITIONS
===========================================================================*/
+/* Helper functions
+ * @brief helper function to implement a secure memcpy
+ * @details take source and destination buffer size into
+ * considerations before copying
+ * @param dst destination buffer
+ * @param dst_size size of destination buffer
+ * @param src source buffer
+ * @param src_size size of source buffer
+ * @return size of the smallest of two buffer
+ */
+
+static inline size_t memscpy(void *dst, size_t dst_size, const void *src,
+ size_t src_size) {
+ size_t min_size = dst_size < src_size ? dst_size : src_size;
+ memcpy(dst, src, min_size);
+ return min_size;
+}
+
+/*
+* @brief helper function to implement a secure memcpy
+ * for a concatenating buffer where offset is kept
+ * track of
+ * @details take source and destination buffer size into
+ * considerations before copying
+ * @param dst destination buffer
+ * @param dst_size pointer used to decrement
+ * @param src source buffer
+ * @param src_size size of source buffer
+ * @return size of the remaining buffer
+ */
+
+
+static inline int memscpy_repeat(void* dst, size_t *dst_size,
+ const void* src, size_t src_size)
+{
+ if( !dst_size || *dst_size <= src_size || !dst || !src)
+ return RMNETCTL_LIB_ERR;
+ else {
+ *dst_size -= memscpy(dst, *dst_size, src, src_size);
+ }
+ return *dst_size;
+}
+
+
/*!
* @brief Synchronous method to send and receive messages to and from the kernel
* using netlink sockets
@@ -124,7 +170,7 @@
uint8_t *request_buf, *response_buf;
struct nlmsghdr *nlmsghdr_val;
struct rmnet_nl_msg_s *rmnet_nl_msg_s_val;
- ssize_t bytes_read = -1;
+ ssize_t bytes_read = -1, buffsize = MAX_BUF_SIZE - sizeof(struct nlmsghdr);
uint16_t return_code = RMNETCTL_API_ERR_HNDL_INVALID;
struct sockaddr_nl* __attribute__((__may_alias__)) saddr_ptr;
request_buf = NULL;
@@ -165,7 +211,7 @@
nlmsghdr_val->nlmsg_pid = hndl->pid;
nlmsghdr_val->nlmsg_len = MAX_BUF_SIZE;
- memcpy((void *)NLMSG_DATA(request_buf), request,
+ memscpy((void *)NLMSG_DATA(request_buf), buffsize, request,
sizeof(struct rmnet_nl_msg_s));
rmnet_nl_msg_s_val->crd = RMNET_NETLINK_MSG_COMMAND;
@@ -194,8 +240,8 @@
return_code = RMNETCTL_API_ERR_MESSAGE_RECEIVE;
break;
}
-
- memcpy(response, (void *)NLMSG_DATA(response_buf),
+ buffsize = MAX_BUF_SIZE - sizeof(struct nlmsghdr);
+ memscpy(response, buffsize, (void *)NLMSG_DATA(response_buf),
sizeof(struct rmnet_nl_msg_s));
if (sizeof(*response) < sizeof(struct rmnet_nl_msg_s)) {
return_code = RMNETCTL_API_ERR_RESPONSE_NULL;
@@ -1081,11 +1127,14 @@
char *kind = "rmnet";
struct nlmsg req;
short id;
+ size_t reqsize;
- if (!hndl || !devname || !vndname || !error_code)
+ if (!hndl || !devname || !vndname || !error_code ||
+ _rmnetctl_check_dev_name(vndname) || _rmnetctl_check_dev_name(devname))
return RMNETCTL_INVALID_ARG;
memset(&req, 0, sizeof(req));
+ reqsize = NLMSG_DATA_SIZE - sizeof(*attrinfo);
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 |
@@ -1104,9 +1153,10 @@
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));
+ CHECK_MEMSCPY(memscpy_repeat(RTA_DATA(attrinfo), &reqsize, &val, sizeof(val)));
req.nl_addr.nlmsg_len = NLMSG_ALIGN(req.nl_addr.nlmsg_len) +
RTA_ALIGN(RTA_LENGTH(sizeof(val)));
@@ -1115,12 +1165,14 @@
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);
+ CHECK_MEMSCPY(memscpy_repeat(RTA_DATA(attrinfo), &reqsize, 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) +
@@ -1128,9 +1180,11 @@
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));
+ CHECK_MEMSCPY(memscpy_repeat(RTA_DATA(attrinfo), &reqsize, kind, strlen(kind)));
+
req.nl_addr.nlmsg_len = NLMSG_ALIGN(req.nl_addr.nlmsg_len) +
RTA_ALIGN(RTA_LENGTH(strlen(kind)));
@@ -1146,7 +1200,7 @@
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));
+ *(short *)RTA_DATA(attrinfo) = id;
req.nl_addr.nlmsg_len = NLMSG_ALIGN(req.nl_addr.nlmsg_len) +
RTA_ALIGN(RTA_LENGTH(sizeof(id)));
@@ -1158,7 +1212,8 @@
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));
+ CHECK_MEMSCPY(memscpy_repeat(RTA_DATA(attrinfo), &reqsize, &flags,
+ sizeof(flags)));
req.nl_addr.nlmsg_len = NLMSG_ALIGN(req.nl_addr.nlmsg_len) +
RTA_ALIGN(RTA_LENGTH(sizeof(flags)));
}
@@ -1217,15 +1272,17 @@
struct ifla_vlan_flags flags;
char *kind = "rmnet";
struct nlmsg req;
- int devindex = 0;
- int val = 0;
+ int devindex = 0, val = 0;
+ size_t reqsize;
short id;
memset(&req, 0, sizeof(req));
- if (!hndl || !devname || !vndname || !error_code)
+ if (!hndl || !devname || !vndname || !error_code ||
+ _rmnetctl_check_dev_name(vndname) || _rmnetctl_check_dev_name(devname))
return RMNETCTL_INVALID_ARG;
+ reqsize = NLMSG_DATA_SIZE - sizeof(*attrinfo);
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;
@@ -1246,16 +1303,17 @@
attrinfo->rta_type = IFLA_LINK;
attrinfo->rta_len = RTA_ALIGN(RTA_LENGTH(sizeof(val)));
- memcpy(RTA_DATA(attrinfo), &val, sizeof(val));
+ CHECK_MEMSCPY(memscpy_repeat(RTA_DATA(attrinfo), &reqsize, &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 */
+ /* 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);
+ CHECK_MEMSCPY(memscpy_repeat(RTA_DATA(attrinfo), &reqsize, vndname, strlen(vndname) + 1));
+
req.nl_addr.nlmsg_len = NLMSG_ALIGN(req.nl_addr.nlmsg_len) +
RTA_ALIGN(RTA_LENGTH(strlen(vndname) + 1));
@@ -1267,19 +1325,18 @@
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));
+ CHECK_MEMSCPY(memscpy_repeat(RTA_DATA(attrinfo), &reqsize, 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) +
@@ -1290,7 +1347,7 @@
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));
+ *(short *)RTA_DATA(attrinfo) = id;
req.nl_addr.nlmsg_len = NLMSG_ALIGN(req.nl_addr.nlmsg_len) +
RTA_ALIGN(RTA_LENGTH(sizeof(id)));
@@ -1302,7 +1359,8 @@
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));
+ CHECK_MEMSCPY(memscpy_repeat(RTA_DATA(attrinfo), &reqsize, &flags,
+ sizeof(flags)));
req.nl_addr.nlmsg_len = NLMSG_ALIGN(req.nl_addr.nlmsg_len) +
RTA_ALIGN(RTA_LENGTH(sizeof(flags)));
}
@@ -1325,11 +1383,13 @@
int devindex = 0, vndindex = 0;
struct rtattr *masterinfo;
struct nlmsg req;
+ size_t reqsize;
- if (!hndl || !vndname || !devname || !error_code)
+ if (!hndl || !vndname || !devname || !error_code || _rmnetctl_check_dev_name(vndname))
return RMNETCTL_INVALID_ARG;
memset(&req, 0, sizeof(req));
+ reqsize = NLMSG_DATA_SIZE - sizeof(*masterinfo);
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;
@@ -1356,7 +1416,7 @@
masterinfo->rta_type = IFLA_MASTER;
masterinfo->rta_len = RTA_LENGTH(sizeof(vndindex));
- memcpy(RTA_DATA(masterinfo), &vndindex, sizeof(vndindex));
+ CHECK_MEMSCPY(memscpy_repeat(RTA_DATA(masterinfo), &reqsize, &vndindex, sizeof(vndindex)));
req.nl_addr.nlmsg_len = NLMSG_ALIGN(req.nl_addr.nlmsg_len) +
RTA_ALIGN(RTA_LENGTH(sizeof(vndindex)));
@@ -1367,3 +1427,551 @@
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;
+ size_t reqsize =0;
+
+ memset(&req, 0, sizeof(req));
+ memset(&flowinfo, 0, sizeof(flowinfo));
+
+
+ if (!hndl || !devname || !error_code ||_rmnetctl_check_dev_name(devname) ||
+ _rmnetctl_check_dev_name(vndname))
+ return RMNETCTL_INVALID_ARG;
+
+ reqsize = NLMSG_DATA_SIZE - sizeof(*attrinfo);
+ 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)));
+ CHECK_MEMSCPY(memscpy_repeat(RTA_DATA(attrinfo), &reqsize, &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));
+ CHECK_MEMSCPY(memscpy_repeat(RTA_DATA(attrinfo), &reqsize, 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)));
+ CHECK_MEMSCPY(memscpy_repeat(RTA_DATA(attrinfo), &reqsize, 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));
+ CHECK_MEMSCPY(memscpy_repeat(RTA_DATA(attrinfo), &reqsize, &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;
+ size_t reqsize;
+
+ memset(&req, 0, sizeof(req));
+ memset(&flowinfo, 0, sizeof(flowinfo));
+
+ if (!hndl || !devname || !error_code ||_rmnetctl_check_dev_name(devname) ||
+ _rmnetctl_check_dev_name(vndname))
+ return RMNETCTL_INVALID_ARG;
+
+ reqsize = NLMSG_DATA_SIZE - sizeof(*attrinfo);
+ 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)));
+ CHECK_MEMSCPY(memscpy_repeat(RTA_DATA(attrinfo), &reqsize, &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));
+ CHECK_MEMSCPY(memscpy_repeat(RTA_DATA(attrinfo), &reqsize, 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)));
+ CHECK_MEMSCPY(memscpy_repeat(RTA_DATA(attrinfo), &reqsize, 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));
+ CHECK_MEMSCPY(memscpy_repeat(RTA_DATA(attrinfo), &reqsize, &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;
+ size_t reqsize;
+
+ memset(&req, 0, sizeof(req));
+ memset(&flowinfo, 0, sizeof(flowinfo));
+
+ if (!hndl || !devname || !error_code ||_rmnetctl_check_dev_name(devname) ||
+ _rmnetctl_check_dev_name(vndname))
+ return RMNETCTL_INVALID_ARG;
+
+ reqsize = NLMSG_DATA_SIZE - sizeof(*attrinfo);
+ 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)));
+ CHECK_MEMSCPY(memscpy_repeat(RTA_DATA(attrinfo), &reqsize, &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));
+ CHECK_MEMSCPY(memscpy_repeat(RTA_DATA(attrinfo), &reqsize, 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)));
+ CHECK_MEMSCPY(memscpy_repeat(RTA_DATA(attrinfo), &reqsize, 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));
+ CHECK_MEMSCPY(memscpy_repeat(RTA_DATA(attrinfo), &reqsize, &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;
+ size_t reqsize;
+
+ memset(&req, 0, sizeof(req));
+ memset(&flowinfo, 0, sizeof(flowinfo));
+
+ if (!hndl || !devname || !error_code ||_rmnetctl_check_dev_name(devname) ||
+ _rmnetctl_check_dev_name(vndname))
+ return RMNETCTL_INVALID_ARG;
+
+ reqsize = NLMSG_DATA_SIZE - sizeof(*attrinfo);
+ 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)));
+ CHECK_MEMSCPY(memscpy_repeat(RTA_DATA(attrinfo), &reqsize, &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));
+ CHECK_MEMSCPY(memscpy_repeat(RTA_DATA(attrinfo), &reqsize, 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)));
+ CHECK_MEMSCPY(memscpy_repeat(RTA_DATA(attrinfo), &reqsize, 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));
+ CHECK_MEMSCPY(memscpy_repeat(RTA_DATA(attrinfo), &reqsize, &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;
+ size_t reqsize;
+
+ memset(&req, 0, sizeof(req));
+ memset(&flowinfo, 0, sizeof(flowinfo));
+
+ if (!hndl || !devname || !error_code ||_rmnetctl_check_dev_name(devname) ||
+ _rmnetctl_check_dev_name(vndname))
+ return RMNETCTL_INVALID_ARG;
+
+ reqsize = NLMSG_DATA_SIZE - sizeof(struct rtattr);
+ 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)));
+ CHECK_MEMSCPY(memscpy_repeat(RTA_DATA(attrinfo), &reqsize, &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));
+ CHECK_MEMSCPY(memscpy_repeat(RTA_DATA(attrinfo), &reqsize, 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)));
+ CHECK_MEMSCPY(memscpy_repeat(RTA_DATA(attrinfo), &reqsize, 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));
+ CHECK_MEMSCPY(memscpy_repeat(RTA_DATA(attrinfo), &reqsize, &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);
+}