---
 src/connman.h |    2 ++
 src/inet.c    |   77 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 79 insertions(+)

diff --git a/src/connman.h b/src/connman.h
index 6726078..71ea1ba 100644
--- a/src/connman.h
+++ b/src/connman.h
@@ -193,6 +193,8 @@ int __connman_inet_rtnl_addattr_l(struct nlmsghdr *n, 
size_t max_length,
                        int type, const void *data, size_t data_length);
 int __connman_inet_rtnl_addattr32(struct nlmsghdr *n, size_t maxlen,
                        int type, __u32 data);
+int __connman_inet_add_fwmark_rule(int ifindex, int family, uint32_t fwmark);
+int __connman_inet_del_fwmark_rule(int ifindex, int family, uint32_t fwmark);
 
 #include <connman/resolver.h>
 
diff --git a/src/inet.c b/src/inet.c
index c28c3e4..0058faf 100644
--- a/src/inet.c
+++ b/src/inet.c
@@ -45,6 +45,7 @@
 #include <fcntl.h>
 #include <linux/if_tun.h>
 #include <ctype.h>
+#include <linux/fib_rules.h>
 
 #include "connman.h"
 
@@ -2316,3 +2317,79 @@ error:
        free(ifr);
        return NULL;
 }
+
+static int iprule_modify(int cmd, int family, uint32_t table_id,
+                       uint32_t fwmark)
+{
+       struct __connman_inet_rtnl_handle rth;
+       int ret;
+
+       memset(&rth, 0, sizeof(rth));
+
+       rth.req.n.nlmsg_type = cmd;
+       rth.req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
+       rth.req.n.nlmsg_flags = NLM_F_REQUEST;
+       rth.req.u.r.rt.rtm_family = family;
+       rth.req.u.r.rt.rtm_protocol = RTPROT_BOOT;
+       rth.req.u.r.rt.rtm_scope = RT_SCOPE_UNIVERSE;
+       rth.req.u.r.rt.rtm_table = table_id;
+       rth.req.u.r.rt.rtm_type = RTN_UNSPEC;
+       rth.req.u.r.rt.rtm_flags = 0;
+
+       if (cmd == RTM_NEWRULE) {
+               rth.req.n.nlmsg_flags |= NLM_F_CREATE|NLM_F_EXCL;
+               rth.req.u.r.rt.rtm_type = RTN_UNICAST;
+       }
+
+       __connman_inet_rtnl_addattr32(&rth.req.n, sizeof(rth.req),
+                                                       FRA_FWMARK, fwmark);
+
+       if (table_id < 256) {
+               rth.req.u.r.rt.rtm_table = table_id;
+       } else {
+               rth.req.u.r.rt.rtm_table = RT_TABLE_UNSPEC;
+               __connman_inet_rtnl_addattr32(&rth.req.n, sizeof(rth.req),
+                                               FRA_TABLE, table_id);
+       }
+
+       if (rth.req.u.r.rt.rtm_family == AF_UNSPEC)
+               rth.req.u.r.rt.rtm_family = AF_INET;
+
+       ret = __connman_inet_rtnl_open(&rth);
+       if (ret < 0)
+               goto done;
+
+       ret = __connman_inet_rtnl_send(&rth, &rth.req.n);
+
+done:
+       __connman_inet_rtnl_close(&rth);
+
+       return ret;
+}
+
+/*
+ * Tie the table number to interface index number, substract 1 because
+ * indexes are > 0
+ */
+static uint32_t get_table_id(int ifindex)
+{
+       const uint32_t value = ('c' << 24) | ('m' << 16) | ('a' << 8) | 'n';
+
+       return value + ifindex - 1;
+}
+
+int __connman_inet_add_fwmark_rule(int ifindex, int family, uint32_t fwmark)
+{
+       /* ip rule add fwmark 9876 table 1234 */
+
+       uint32_t table_id = get_table_id(ifindex);
+
+       return iprule_modify(RTM_NEWRULE, family, table_id, fwmark);
+}
+
+int __connman_inet_del_fwmark_rule(int ifindex, int family, uint32_t fwmark)
+{
+       uint32_t table_id = get_table_id(ifindex);
+
+       return iprule_modify(RTM_DELRULE, family, table_id, fwmark);
+}
-- 
1.7.9.5

_______________________________________________
connman mailing list
connman@connman.net
http://lists.connman.net/listinfo/connman

Reply via email to