aboutsummaryrefslogtreecommitdiffstats
path: root/src/libcharon/plugins/kernel_netlink
diff options
context:
space:
mode:
Diffstat (limited to 'src/libcharon/plugins/kernel_netlink')
-rw-r--r--src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c71
1 files changed, 53 insertions, 18 deletions
diff --git a/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c b/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c
index 95c0e3ce0..b21485e62 100644
--- a/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c
+++ b/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c
@@ -73,7 +73,7 @@
#endif
/** Base priority for installed policies */
-#define PRIO_BASE 384
+#define PRIO_BASE 100000
/** Default lifetime of an acquire XFRM state (in seconds) */
#define DEFAULT_ACQUIRE_LIFETIME 165
@@ -605,32 +605,66 @@ static bool policy_equals(policy_entry_t *key, policy_entry_t *other_key)
}
/**
+ * Determine number of set bits in 16 bit port mask
+ */
+static inline uint32_t port_mask_bits(uint16_t port_mask)
+{
+ uint32_t bits;
+ uint16_t bit_mask = 0x8000;
+
+ port_mask = ntohs(port_mask);
+
+ for (bits = 0; bits < 16; bits++)
+ {
+ if (!(port_mask & bit_mask))
+ {
+ break;
+ }
+ bit_mask >>= 1;
+ }
+ return bits;
+}
+
+/**
* Calculate the priority of a policy
+ *
+ * bits 0-0: restriction to network interface (0..1) 1 bit
+ * bits 1-6: src + dst port mask bits (2 * 0..16) 6 bits
+ * bits 7-7: restriction to protocol (0..1) 1 bit
+ * bits 8-16: src + dst network mask bits (2 * 0..128) 9 bits
+ * 17 bits
+ *
+ * smallest value: 000000000 0 000000 0: 0, lowest priority = 100'000
+ * largest value : 100000000 1 100000 1: 65'729, highst priority = 34'271
*/
-static inline uint32_t get_priority(policy_entry_t *policy,
- policy_priority_t prio)
+static uint32_t get_priority(policy_entry_t *policy, policy_priority_t prio,
+ char *interface)
{
- uint32_t priority = PRIO_BASE;
+ uint32_t priority = PRIO_BASE, sport_mask_bits, dport_mask_bits;
+
switch (prio)
{
case POLICY_PRIORITY_FALLBACK:
- priority <<= 1;
- /* fall-through */
+ priority += PRIO_BASE;
+ /* fall-through to next case */
case POLICY_PRIORITY_ROUTED:
- priority <<= 1;
- /* fall-through */
+ priority += PRIO_BASE;
+ /* fall-through to next case */
case POLICY_PRIORITY_DEFAULT:
- priority <<= 1;
- /* fall-through */
+ priority += PRIO_BASE;
+ /* fall-through to next case */
case POLICY_PRIORITY_PASS:
break;
}
- /* calculate priority based on selector size, small size = high prio */
- priority -= policy->sel.prefixlen_s;
- priority -= policy->sel.prefixlen_d;
- priority <<= 2; /* make some room for the two flags */
- priority += policy->sel.sport_mask || policy->sel.dport_mask ? 0 : 2;
- priority += policy->sel.proto ? 0 : 1;
+ sport_mask_bits = port_mask_bits(policy->sel.sport_mask);
+ dport_mask_bits = port_mask_bits(policy->sel.dport_mask);
+
+ /* calculate priority */
+ priority -= (policy->sel.prefixlen_s + policy->sel.prefixlen_d) * 256;
+ priority -= policy->sel.proto ? 128 : 0;
+ priority -= (sport_mask_bits + dport_mask_bits) * 2;
+ priority -= (interface != NULL);
+
return priority;
}
@@ -2401,7 +2435,7 @@ METHOD(kernel_ipsec_t, add_policy, status_t,
assigned_sa = policy_sa_create(this, id->dir, data->type, data->src,
data->dst, id->src_ts, id->dst_ts, id->mark, data->sa);
assigned_sa->priority = data->manual_prio ? data->manual_prio :
- get_priority(policy, data->prio);
+ get_priority(policy, data->prio, id->interface);
/* insert the SA according to its priority */
enumerator = policy->used_by->create_enumerator(policy->used_by);
@@ -2581,7 +2615,8 @@ METHOD(kernel_ipsec_t, del_policy, status_t,
/* remove mapping to SA by reqid and priority */
priority = data->manual_prio ? data->manual_prio :
- get_priority(current, data->prio);
+ get_priority(current, data->prio,id->interface);
+
enumerator = current->used_by->create_enumerator(current->used_by);
while (enumerator->enumerate(enumerator, (void**)&mapping))
{