Merge "[netlink] Updating netlink interface"
diff --git a/Makefile b/Makefile
index 676e283..49de9fe 100755
--- a/Makefile
+++ b/Makefile
@@ -80,15 +80,26 @@
ccflags-$(ECM_INTERFACE_L2TPV2_ENABLE) += -DECM_INTERFACE_L2TPV2_ENABLE
# #############################################################################
-# if pppoe, l2tpv2 acceleration is enabled, ppp should
+# Define ECM_INTERFACE_PPTP_ENABLE=y in order
+# to enable support for pptp acceleration.
+# #############################################################################
+ifneq ($(findstring 3.4, $(KERNELVERSION)),)
+ECM_INTERFACE_PPTP_ENABLE=y
+endif
+ccflags-$(ECM_INTERFACE_PPTP_ENABLE) += -DECM_INTERFACE_PPTP_ENABLE
+
+# #############################################################################
+# if pppoe, l2tpv2, pptp acceleration is enabled, ppp should
# be enabled automatically
# #############################################################################
ECM_INTERFACE_PPP_ENABLE=y
ifeq "$(ECM_INTERFACE_PPPOE_ENABLE)" "n"
ifeq "$(ECM_INTERFACE_L2TPV2_ENABLE)" "n"
+ifeq "$(ECM_INTERFACE_PPTP_ENABLE)" "n"
ECM_INTERFACE_PPP_ENABLE=n
endif
endif
+endif
ccflags-$(ECM_INTERFACE_PPP_ENABLE) += -DECM_INTERFACE_PPP_ENABLE
# #############################################################################
@@ -109,13 +120,10 @@
# Define ECM_MULTICAST_ENABLE=y in order to enable support for ECM Multicast
# #############################################################################
ifeq ($(ECM_FRONT_END_NSS_ENABLE), y)
-ifneq ($(findstring 3.4, $(KERNELVERSION)),)
-ECM_MULTICAST_ENABLE=y
-endif
-endif
ecm-$(ECM_MULTICAST_ENABLE) += frontends/nss/ecm_nss_multicast_ipv4.o
ecm-$(ECM_MULTICAST_ENABLE) += frontends/nss/ecm_nss_multicast_ipv6.o
ccflags-$(ECM_MULTICAST_ENABLE) += -DECM_MULTICAST_ENABLE
+endif
# #############################################################################
# Define ECM_INTERFACE_VLAN_ENABLE=y in order to enable support for VLAN
diff --git a/ecm_classifier.h b/ecm_classifier.h
index d3068dd..19a386f 100644
--- a/ecm_classifier.h
+++ b/ecm_classifier.h
@@ -152,6 +152,12 @@
#endif
/*
+ * Determines if a connection should be kept.
+ */
+typedef bool (*ecm_classifier_should_keep_connection_t)
+ (struct ecm_classifier_instance *ci, uint8_t *mac);
+
+/*
* Base class for all types of classifiers
*/
struct ecm_classifier_instance {
@@ -172,6 +178,8 @@
/* Reclassify */
ecm_classifier_last_process_response_get_callback_t last_process_response_get;
/* Return last process response */
+ ecm_classifier_should_keep_connection_t should_keep_connection;
+ /* Check if connection should be kept when FDB updates */
#ifdef ECM_STATE_OUTPUT_ENABLE
ecm_classifier_state_get_callback_t state_get;
/* Return its state */
diff --git a/ecm_classifier_hyfi.c b/ecm_classifier_hyfi.c
index 23fe114..656cc36 100644
--- a/ecm_classifier_hyfi.c
+++ b/ecm_classifier_hyfi.c
@@ -69,7 +69,7 @@
#include "ecm_tracker_tcp.h"
#include "ecm_db.h"
#include "ecm_classifier_hyfi.h"
-
+#include "ecm_front_end_ipv4.h"
/*
* Magic numbers
*/
@@ -220,6 +220,7 @@
struct ecm_front_end_connection_instance *feci;
ecm_front_end_acceleration_mode_t accel_mode;
uint32_t became_relevant = 0;
+ uint32_t flag = 0;
chfi = (struct ecm_classifier_hyfi_instance *)aci;
DEBUG_CHECK_MAGIC(chfi, ECM_CLASSIFIER_HYFI_INSTANCE_MAGIC, "%p: magic failed\n", chfi);
@@ -285,13 +286,21 @@
}
/*
- * Compute the hash
+ * Compute the hashes in both forward and reverse directions
*/
- if (unlikely(hyfi_hash_skbuf(skb, &chfi->flow.hash, &chfi->flow.flag, &chfi->flow.priority, &chfi->flow.seq))) {
+ if (unlikely(hyfi_hash_skbuf(skb, &chfi->flow.hash, &flag,
+ &chfi->flow.priority, &chfi->flow.seq)))
goto hyfi_classifier_done;
- }
+
+ if (unlikely(hyfi_hash_skbuf_reverse(skb, &chfi->flow.reverse_hash)))
+ goto hyfi_classifier_done;
chfi->flow.ecm_serial = chfi->ci_serial;
+ if (flag & ECM_HYFI_IS_IPPROTO_UDP)
+ hyfi_ecm_set_flag(&chfi->flow, ECM_HYFI_IS_IPPROTO_UDP);
+ else
+ hyfi_ecm_clear_flag(&chfi->flow, ECM_HYFI_IS_IPPROTO_UDP);
+
memcpy(&chfi->flow.sa, eth_hdr(skb)->h_source, ETH_ALEN);
memcpy(&chfi->flow.da, eth_hdr(skb)->h_dest, ETH_ALEN);
@@ -315,9 +324,25 @@
{
struct ecm_classifier_hyfi_instance *chfi;
struct ecm_db_connection_instance *ci;
- uint64_t num_packets = 0;
- uint64_t num_bytes = 0;
- int32_t ret;
+ uint64_t from_packets = 0;
+ uint64_t from_bytes = 0;
+ uint64_t to_packets = 0;
+ uint64_t to_bytes = 0;
+ uint64_t from_packets_dropped = 0;
+ uint64_t from_bytes_dropped = 0;
+ uint64_t to_packets_dropped = 0;
+ uint64_t to_bytes_dropped = 0;
+ int32_t ret_fwd, ret_rev;
+ u_int32_t time_now, time_elapsed_fwd, time_elapsed_rev;
+ uint8_t flow_dest_addr[ETH_ALEN];
+ uint64_t fwd_bytes, rev_bytes, fwd_packets, rev_packets;
+ bool should_keep_on_fdb_update_fwd, should_keep_on_fdb_update_rev;
+
+ if (sync->reason != ECM_FRONT_END_IPV4_RULE_SYNC_REASON_STATS) {
+ DEBUG_TRACE("%p: Update not due to stats: %d\n",
+ aci, sync->reason);
+ return;
+ }
chfi = (struct ecm_classifier_hyfi_instance *)aci;
DEBUG_CHECK_MAGIC(chfi, ECM_CLASSIFIER_HYFI_INSTANCE_MAGIC, "%p: magic failed", chfi);
@@ -336,39 +361,106 @@
/*
* Update the stats on Hy-Fi side
*/
- ecm_db_connection_data_stats_get(ci, NULL, &num_bytes,
- NULL, &num_packets,
- NULL, NULL,
- NULL, NULL );
+ ecm_db_connection_to_node_address_get(ci, &flow_dest_addr[0]);
+ ecm_db_connection_data_stats_get(ci, &from_bytes, &to_bytes,
+ &from_packets, &to_packets,
+ &from_bytes_dropped, &to_bytes_dropped,
+ &from_packets_dropped, &to_packets_dropped);
ecm_db_connection_deref(ci);
- DEBUG_INFO("UPDATE STATS: Flow serial: %d\nFlow hash: 0x%02x, priority 0x%08x, flag: %d\nSA: %pM\nDA: %pM\n\n",
- chfi->flow.ecm_serial, chfi->flow.hash, chfi->flow.priority, chfi->flow.flag,
+ DEBUG_INFO("UPDATE STATS: Flow serial: %d\npriority 0x%08x, flag: %d\nSA: %pM\nDA: %pM\n\n",
+ chfi->flow.ecm_serial, chfi->flow.priority, chfi->flow.flag,
chfi->flow.sa, chfi->flow.da);
- DEBUG_INFO("num_bytes = %lld, num_packets = %lld\n", num_bytes, num_packets);
+ time_now = jiffies;
+ /*
+ * Make sure destination address still matches
+ */
+ if (memcmp(&flow_dest_addr[0], &chfi->flow.da[0], ETH_ALEN)) {
+ DEBUG_INFO("UPDATE STATS: Direction of flow is "
+ "reverse of expectation\n");
+ fwd_bytes = (to_bytes - to_bytes_dropped);
+ fwd_packets = (to_packets - to_packets_dropped);
+ rev_bytes = (from_bytes - from_bytes_dropped);
+ rev_packets = (from_packets - from_packets_dropped);
+ } else {
+ fwd_bytes = (from_bytes - from_bytes_dropped);
+ fwd_packets = (from_packets - from_packets_dropped);
+ rev_bytes = (to_bytes - to_bytes_dropped);
+ rev_packets = (to_packets - to_packets_dropped);
+ }
- ret = hyfi_ecm_update_stats(&chfi->flow, num_bytes, num_packets);
+ /*
+ * Update forward direction 'from' bytes
+ */
+ ret_fwd = hyfi_ecm_update_stats(&chfi->flow, chfi->flow.hash,
+ &chfi->flow.da[0], &chfi->flow.sa[0],
+ fwd_bytes, fwd_packets, time_now,
+ &should_keep_on_fdb_update_fwd,
+ &time_elapsed_fwd);
+ DEBUG_INFO("ret_fwd %d Forward hash: 0x%02x, from_bytes = %lld, from_packets = %lld, "
+ "num_bytes_dropped = %lld, num_packets_dropped = %lld\n",
+ ret_fwd, chfi->flow.hash, from_bytes, from_packets,
+ from_bytes_dropped, from_packets_dropped);
- if (ret < 0) {
- printk("%s: Fatal error\n", __func__);
+ /*
+ * Update reverse direction 'to' bytes
+ */
+ ret_rev = hyfi_ecm_update_stats(&chfi->flow, chfi->flow.reverse_hash,
+ &chfi->flow.sa[0], &chfi->flow.da[0],
+ rev_bytes, rev_packets, time_now,
+ &should_keep_on_fdb_update_rev,
+ &time_elapsed_rev);
+
+ DEBUG_INFO("ret_rev %d Reverse hash: 0x%02x, to_bytes = %lld, to_packets = %lld, "
+ "num_bytes_dropped = %lld, num_packets_dropped = %lld\n",
+ ret_rev, chfi->flow.reverse_hash, to_bytes, to_packets,
+ to_bytes_dropped, to_packets_dropped);
+
+ chfi->flow.last_update = time_now;
+ chfi->flow.last_elapsed_time = time_elapsed_fwd >= time_elapsed_rev ?
+ time_elapsed_fwd : time_elapsed_rev;
+
+ if (!time_elapsed_fwd) {
+ if (should_keep_on_fdb_update_fwd) {
+ hyfi_ecm_set_flag(&chfi->flow,
+ ECM_HYFI_SHOULD_KEEP_ON_FDB_UPDATE_FWD);
+ } else {
+ hyfi_ecm_clear_flag(&chfi->flow,
+ ECM_HYFI_SHOULD_KEEP_ON_FDB_UPDATE_FWD);
+ }
+ }
+
+ if (!time_elapsed_rev) {
+ if (should_keep_on_fdb_update_rev) {
+ hyfi_ecm_set_flag(&chfi->flow,
+ ECM_HYFI_SHOULD_KEEP_ON_FDB_UPDATE_REV);
+ } else {
+ hyfi_ecm_clear_flag(&chfi->flow,
+ ECM_HYFI_SHOULD_KEEP_ON_FDB_UPDATE_REV);
+ }
+ }
+
+ if (ret_fwd < 0 || ret_rev < 0) {
+ DEBUG_ERROR("%p: Error updating stats", aci);
return;
}
- switch(ret)
- {
- case 0: /* OK */
+ /*
+ * Only need to be interested in forward or reverse direction
+ */
+ if (ret_fwd == 0 || ret_rev == 0) {
chfi->hyfi_state = ECM_CLASSIFIER_HYFI_STATE_REGISTERED;
- break;
-
- case 1: /* Not interested */
- chfi->hyfi_state = ECM_CLASSIFIER_HYFI_STATE_IGNORE;
- break;
-
- case 2: /* Not attached, may be interested in the future */
- default:
+ } else if (ret_fwd == 2 || ret_rev == 2) {
+ /*
+ * Not attached, may be interested in the future
+ */
chfi->hyfi_state = ECM_CLASSIFIER_HYFI_STATE_INIT;
- break;
+ } else {
+ /*
+ * Not interested
+ */
+ chfi->hyfi_state = ECM_CLASSIFIER_HYFI_STATE_IGNORE;
}
}
@@ -390,57 +482,8 @@
*/
static void ecm_classifier_hyfi_sync_to_v6(struct ecm_classifier_instance *aci, struct ecm_classifier_rule_sync *sync)
{
- struct ecm_classifier_hyfi_instance *chfi;
- struct ecm_db_connection_instance *ci;
- uint64_t num_packets = 0;
- uint64_t num_bytes = 0;
- int32_t ret;
-
- chfi = (struct ecm_classifier_hyfi_instance *)aci;
- DEBUG_CHECK_MAGIC(chfi, ECM_CLASSIFIER_HYFI_INSTANCE_MAGIC, "%p: magic failed", chfi);
-
- if (chfi->hyfi_state &
- (ECM_CLASSIFIER_HYFI_STATE_IGNORE)) {
- return;
- }
-
- ci = ecm_db_connection_serial_find_and_ref(chfi->ci_serial);
- if (!ci) {
- DEBUG_TRACE("%p: No ci found for %u\n", chfi, chfi->ci_serial);
- return;
- }
-
- /*
- * Update the stats on Hy-Fi side
- */
- ecm_db_connection_data_stats_get(ci, NULL, &num_bytes,
- NULL, &num_packets,
- NULL, NULL,
- NULL, NULL );
- ecm_db_connection_deref(ci);
-
- ret = hyfi_ecm_update_stats(&chfi->flow, num_bytes, num_packets);
-
- if (ret < 0) {
- DEBUG_ERROR("%s: Fatal error\n", __func__);
- return;
- }
-
- switch(ret)
- {
- case 0: /* OK */
- chfi->hyfi_state = ECM_CLASSIFIER_HYFI_STATE_REGISTERED;
- break;
-
- case 1: /* Not interested */
- chfi->hyfi_state = ECM_CLASSIFIER_HYFI_STATE_IGNORE;
- break;
-
- case 2: /* Not attached, may be interested in the future */
- default:
- chfi->hyfi_state = ECM_CLASSIFIER_HYFI_STATE_INIT;
- break;
- }
+ /* Same processing as v4 */
+ ecm_classifier_hyfi_sync_to_v4(aci, sync);
}
/*
@@ -543,6 +586,24 @@
}
#endif
+static bool ecm_classifier_hyfi_should_keep_connection(
+ struct ecm_classifier_instance *aci, uint8_t *mac)
+{
+ struct ecm_classifier_hyfi_instance *chfi;
+
+ chfi = (struct ecm_classifier_hyfi_instance *)aci;
+ DEBUG_CHECK_MAGIC(chfi, ECM_CLASSIFIER_HYFI_INSTANCE_MAGIC,
+ "%p: magic failed", chfi);
+
+ if (chfi->hyfi_state &
+ (ECM_CLASSIFIER_HYFI_STATE_IGNORE)) {
+ /* HyFi doesn't care if connection deleted */
+ return false;
+ }
+
+ return hyfi_ecm_should_keep(&chfi->flow, mac);
+}
+
/*
* ecm_classifier_hyfi_instance_alloc()
* Allocate an instance of the HyFi classifier
@@ -571,6 +632,8 @@
chfi->base.last_process_response_get = ecm_classifier_hyfi_last_process_response_get;
chfi->base.reclassify_allowed = ecm_classifier_hyfi_reclassify_allowed;
chfi->base.reclassify = ecm_classifier_hyfi_reclassify;
+ chfi->base.should_keep_connection =
+ ecm_classifier_hyfi_should_keep_connection;
#ifdef ECM_STATE_OUTPUT_ENABLE
chfi->base.state_get = ecm_classifier_hyfi_state_get;
#endif
@@ -628,7 +691,6 @@
uint32_t serial = ecm_db_connection_serial_get(ci);
DEBUG_INFO("%p: HYFI LISTENER: added conn with serial: %u\n", ci, serial);
#endif
-// Add your own code here
}
/*
@@ -637,11 +699,34 @@
*/
static void ecm_classifier_hyfi_connection_removed(void *arg, struct ecm_db_connection_instance *ci)
{
-#if (DEBUG_LEVEL > 2)
+ struct ecm_classifier_instance *aci;
+ struct ecm_classifier_hyfi_instance *chfi;
uint32_t serial = ecm_db_connection_serial_get(ci);
+
DEBUG_INFO("%p: HYFI LISTENER: removed conn with serial: %u\n", ci, serial);
-#endif
-// Add your own code here
+
+ /*
+ * Only handle events if there is an HyFi classifier attached
+ */
+ aci = ecm_db_connection_assigned_classifier_find_and_ref(ci, ECM_CLASSIFIER_TYPE_HYFI);
+ if (!aci) {
+ DEBUG_TRACE("%p: Connection removed ignored"
+ " - no HyFi classifier\n", ci);
+ return;
+ }
+
+ chfi = (struct ecm_classifier_hyfi_instance *)aci;
+ DEBUG_INFO("%p: removed conn with serial: %u, "
+ "hash 0x%x, rev hash 0x%x\n",
+ aci, serial, chfi->flow.hash, chfi->flow.reverse_hash);
+
+ /*
+ * Mark as decelerated
+ */
+ hyfi_ecm_decelerate(chfi->flow.hash, serial);
+ hyfi_ecm_decelerate(chfi->flow.reverse_hash, serial);
+
+ aci->deref(aci);
}
/*
diff --git a/ecm_db.c b/ecm_db.c
index 5d825c8..b2d3550 100644
--- a/ecm_db.c
+++ b/ecm_db.c
@@ -256,6 +256,9 @@
#ifdef ECM_INTERFACE_L2TPV2_ENABLE
struct ecm_db_interface_info_pppol2tpv2 pppol2tpv2; /* type == ECM_DB_IFACE_TYPE_PPPOL2TPV2 */
#endif
+#ifdef ECM_INTERFACE_PPTP_ENABLE
+ struct ecm_db_interface_info_pptp pptp; /* type == ECM_DB_IFACE_TYPE_PPTP */
+#endif
struct ecm_db_interface_info_unknown unknown; /* type == ECM_DB_IFACE_TYPE_UNKNOWN */
struct ecm_db_interface_info_loopback loopback; /* type == ECM_DB_IFACE_TYPE_LOOPBACK */
#ifdef ECM_INTERFACE_IPSEC_ENABLE
@@ -882,7 +885,8 @@
"UNKNOWN",
"SIT",
"TUNIPIP6",
- "PPPoL2TPV2"
+ "PPPoL2TPV2",
+ "PPTP"
};
/*
@@ -3958,6 +3962,18 @@
#endif
+#ifdef ECM_INTERFACE_PPTP_ENABLE
+/*
+ * ecm_db_iface_generate_hash_index_pptp()
+ * Calculate the hash index.
+ */
+static inline ecm_db_iface_hash_t ecm_db_iface_generate_hash_index_pptp(uint16_t pptp_src_call_id, uint16_t pptp_dst_call_id)
+{
+ uint32_t hash_val;
+ hash_val = (uint32_t)jhash_2words(pptp_src_call_id, pptp_dst_call_id, ecm_db_jhash_rnd);
+ return (ecm_db_iface_hash_t)(hash_val & (ECM_DB_IFACE_HASH_SLOTS - 1));
+}
+#endif
/*
* ecm_db_iface_generate_hash_index_unknown()
* Calculate the hash index.
@@ -4538,6 +4554,65 @@
#endif
+#ifdef ECM_INTERFACE_PPTP_ENABLE
+/*
+ * ecm_db_iface_pptp_session_info_get
+ * get pptp specific info
+ */
+void ecm_db_iface_pptp_session_info_get(struct ecm_db_iface_instance *ii, struct ecm_db_interface_info_pptp *pptp_info)
+{
+ DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
+ DEBUG_ASSERT(ii->type == ECM_DB_IFACE_TYPE_PPTP, "%p: Bad type, expected pptp, actual: %d\n", ii, ii->type);
+ spin_lock_bh(&ecm_db_lock);
+ memcpy(pptp_info, &ii->type_info.pptp, sizeof(struct ecm_db_interface_info_pptp));
+ spin_unlock_bh(&ecm_db_lock);
+}
+EXPORT_SYMBOL(ecm_db_iface_pptp_session_info_get);
+
+/*
+ * ecm_db_iface_find_and_ref_pptp()
+ * Lookup and return a iface reference if any
+ */
+struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_pptp(uint32_t pptp_src_call_id, uint32_t pptp_dst_call_id)
+{
+ ecm_db_iface_hash_t hash_index;
+ struct ecm_db_iface_instance *ii;
+
+ /*
+ * Compute the hash chain index and prepare to walk the chain
+ */
+ hash_index = ecm_db_iface_generate_hash_index_pptp(pptp_src_call_id, pptp_dst_call_id);
+
+ DEBUG_TRACE("Lookup pptp iface with local_call_id = %d, remote_call_id = %d, hash = 0x%x\n", pptp_src_call_id,
+ pptp_dst_call_id, hash_index);
+
+ /*
+ * Iterate the chain looking for a host with matching details
+ */
+ spin_lock_bh(&ecm_db_lock);
+ ii = ecm_db_iface_table[hash_index];
+
+ while (ii) {
+ if ((ii->type != ECM_DB_IFACE_TYPE_PPTP)
+ || (ii->type_info.pptp.src_call_id != pptp_src_call_id)
+ || (ii->type_info.pptp.dst_call_id != pptp_dst_call_id)) {
+ ii = ii->hash_next;
+ continue;
+ }
+
+ _ecm_db_iface_ref(ii);
+ spin_unlock_bh(&ecm_db_lock);
+ DEBUG_TRACE("iface found %p\n", ii);
+ return ii;
+ }
+ spin_unlock_bh(&ecm_db_lock);
+
+ DEBUG_TRACE("Iface not found\n");
+ return NULL;
+}
+EXPORT_SYMBOL(ecm_db_iface_find_and_ref_pptp);
+#endif
+
/*
* ecm_db_iface_find_and_ref_unknown()
* Lookup and return a iface reference if any
@@ -7710,6 +7785,45 @@
#endif
+#ifdef ECM_INTERFACE_PPTP_ENABLE
+/*
+ * ecm_db_iface_pptp_state_get()
+ * Return interface type specific state
+ */
+static int ecm_db_iface_pptp_state_get(struct ecm_db_iface_instance *ii, struct ecm_state_file_instance *sfi)
+{
+ int result;
+ struct ecm_db_interface_info_pptp type_info;
+
+ DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
+ spin_lock_bh(&ecm_db_lock);
+ memcpy(&type_info, &ii->type_info, sizeof(struct ecm_db_interface_info_pptp));
+ spin_unlock_bh(&ecm_db_lock);
+
+ result = ecm_state_prefix_add(sfi, "pptp");
+ if (result) {
+ return result;
+ }
+
+ result = ecm_db_iface_state_get_base(ii, sfi);
+ if (result) {
+ return result;
+ }
+
+ result = ecm_state_write(sfi, "local_call_id", "%u", type_info.src_call_id);
+ if (result) {
+ return result;
+ }
+
+ result = ecm_state_write(sfi, "peer_call_id", "%u", type_info.dst_call_id);
+ if (result) {
+ return result;
+ }
+
+ return ecm_state_prefix_remove(sfi);
+}
+#endif
+
/*
* ecm_db_iface_unknown_state_get()
* Return interface type specific state
@@ -9547,6 +9661,123 @@
#endif
+#ifdef ECM_INTERFACE_PPTP_ENABLE
+/*
+ * ecm_db_iface_add_pptp()
+ * Add a iface instance into the database
+ */
+void ecm_db_iface_add_pptp(struct ecm_db_iface_instance *ii, struct ecm_db_interface_info_pptp *pptp_info,
+ char *name, int32_t mtu, int32_t interface_identifier,
+ int32_t ae_interface_identifier, ecm_db_iface_final_callback_t final,
+ void *arg)
+{
+ ecm_db_iface_hash_t hash_index;
+ ecm_db_iface_id_hash_t iface_id_hash_index;
+ struct ecm_db_listener_instance *li;
+ struct ecm_db_interface_info_pptp *type_info;
+
+ DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
+ spin_lock_bh(&ecm_db_lock);
+#ifdef ECM_DB_XREF_ENABLE
+ DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%p: nodes not null\n", ii);
+#endif
+ DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%p: inserted\n", ii);
+ DEBUG_ASSERT(name, "%p: no name given\n", ii);
+ spin_unlock_bh(&ecm_db_lock);
+
+ /*
+ * Record general info
+ */
+ ii->type = ECM_DB_IFACE_TYPE_PPTP;
+#ifdef ECM_STATE_OUTPUT_ENABLE
+ ii->state_get = ecm_db_iface_pptp_state_get;
+#endif
+ ii->arg = arg;
+ ii->final = final;
+ strlcpy(ii->name, name, IFNAMSIZ);
+ ii->mtu = mtu;
+ ii->interface_identifier = interface_identifier;
+ ii->ae_interface_identifier = ae_interface_identifier;
+
+ /*
+ * Type specific info
+ */
+ type_info = &ii->type_info.pptp;
+ memcpy(type_info, pptp_info, sizeof(struct ecm_db_interface_info_pptp));
+
+ /*
+ * Compute hash chain for insertion
+ */
+ hash_index = ecm_db_iface_generate_hash_index_pptp(type_info->src_call_id,
+ type_info->dst_call_id);
+ ii->hash_index = hash_index;
+
+ iface_id_hash_index = ecm_db_iface_id_generate_hash_index(interface_identifier);
+ ii->iface_id_hash_index = iface_id_hash_index;
+ /*
+ * Add into the global list
+ */
+ spin_lock_bh(&ecm_db_lock);
+ ii->flags |= ECM_DB_IFACE_FLAGS_INSERTED;
+ ii->prev = NULL;
+ ii->next = ecm_db_interfaces;
+ if (ecm_db_interfaces) {
+ ecm_db_interfaces->prev = ii;
+ }
+ ecm_db_interfaces = ii;
+
+ /*
+ * Insert into chain
+ */
+ ii->hash_next = ecm_db_iface_table[hash_index];
+ if (ecm_db_iface_table[hash_index]) {
+ ecm_db_iface_table[hash_index]->hash_prev = ii;
+ }
+ ecm_db_iface_table[hash_index] = ii;
+ ecm_db_iface_table_lengths[hash_index]++;
+ DEBUG_ASSERT(ecm_db_iface_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ii, ecm_db_iface_table_lengths[hash_index]);
+
+ DEBUG_INFO("%p: interface inserted at hash index %u, hash prev is %p, type: %d\n", ii, ii->hash_index, ii->hash_prev, ii->type);
+
+ /*
+ * Insert into interface identifier chain
+ */
+ ii->iface_id_hash_next = ecm_db_iface_id_table[iface_id_hash_index];
+ if (ecm_db_iface_id_table[iface_id_hash_index]) {
+ ecm_db_iface_id_table[iface_id_hash_index]->iface_id_hash_prev = ii;
+ }
+ ecm_db_iface_id_table[iface_id_hash_index] = ii;
+ ecm_db_iface_id_table_lengths[iface_id_hash_index]++;
+ DEBUG_ASSERT(ecm_db_iface_id_table_lengths[iface_id_hash_index] > 0, "%p: invalid iface id table len %d\n", ii, ecm_db_iface_id_table_lengths[iface_id_hash_index]);
+
+ /*
+ * Set time of addition
+ */
+ ii->time_added = ecm_db_time;
+ spin_unlock_bh(&ecm_db_lock);
+
+ /*
+ * Throw add event to the listeners
+ */
+ DEBUG_TRACE("%p: Throw iface added event\n", ii);
+ li = ecm_db_listeners_get_and_ref_first();
+ while (li) {
+ struct ecm_db_listener_instance *lin;
+ if (li->iface_added) {
+ li->iface_added(li->arg, ii);
+ }
+
+ /*
+ * Get next listener
+ */
+ lin = ecm_db_listener_get_and_ref_next(li);
+ ecm_db_listener_deref(li);
+ li = lin;
+ }
+}
+EXPORT_SYMBOL(ecm_db_iface_add_pptp);
+#endif
+
/*
* ecm_db_iface_add_unknown()
* Add a iface instance into the database
@@ -11297,11 +11528,41 @@
}
/*
+ * ecm_db_should_keep_connection()
+ * check if any classifier believes this connection should
+ * be kept
+ */
+static bool ecm_db_should_keep_connection(
+ struct ecm_db_connection_instance *ci, uint8_t *mac)
+{
+ bool should_keep_connection = false;
+ int assignment_count;
+ int aci_index;
+ struct ecm_classifier_instance *assignments[ECM_CLASSIFIER_TYPES];
+
+ assignment_count =
+ ecm_db_connection_classifier_assignments_get_and_ref(ci, assignments);
+ for (aci_index = 0; aci_index < assignment_count; ++aci_index) {
+ struct ecm_classifier_instance *aci;
+ aci = assignments[aci_index];
+ if (aci->should_keep_connection &&
+ aci->should_keep_connection(aci, mac)) {
+ should_keep_connection = true;
+ break;
+ }
+ }
+ ecm_db_connection_assignments_release(assignment_count, assignments);
+
+ return should_keep_connection;
+}
+
+/*
* ecm_db_traverse_node_from_connection_list_and_decelerate()
* traverse from_list of a node and calls ecm_db_connection_decelerate_and_defunct()
* for each entry
*/
-void ecm_db_traverse_node_from_connection_list_and_decelerate(struct ecm_db_node_instance *node)
+void ecm_db_traverse_node_from_connection_list_and_decelerate(
+ struct ecm_db_node_instance *node)
{
struct ecm_db_connection_instance *ci = NULL;
@@ -11312,8 +11573,12 @@
while (ci) {
struct ecm_db_connection_instance *cin;
- DEBUG_TRACE("%p: defunct\n", ci);
- ecm_db_connection_decelerate_and_defunct(ci);
+ if (!ecm_db_should_keep_connection(ci, node->address)) {
+ DEBUG_TRACE("%p: defunct\n", ci);
+ ecm_db_connection_decelerate_and_defunct(ci);
+ } else {
+ DEBUG_TRACE("%p: keeping connection\n", ci);
+ }
cin = ecm_db_node_from_connection_get_and_ref_next(ci);
ecm_db_connection_deref(ci);
@@ -11327,7 +11592,8 @@
* traverse to_list of a node and calls ecm_db_connection_decelerate_and_defunct()
* for each entry
*/
-void ecm_db_traverse_node_to_connection_list_and_decelerate(struct ecm_db_node_instance *node)
+void ecm_db_traverse_node_to_connection_list_and_decelerate(
+ struct ecm_db_node_instance *node)
{
struct ecm_db_connection_instance *ci = NULL;
@@ -11338,8 +11604,12 @@
while (ci) {
struct ecm_db_connection_instance *cin;
- DEBUG_TRACE("%p: defunct\n", ci);
- ecm_db_connection_decelerate_and_defunct(ci);
+ if (!ecm_db_should_keep_connection(ci, node->address)) {
+ DEBUG_TRACE("%p: defunct\n", ci);
+ ecm_db_connection_decelerate_and_defunct(ci);
+ } else {
+ DEBUG_TRACE("%p: keeping connection\n", ci);
+ }
cin = ecm_db_node_to_connection_get_and_ref_next(ci);
ecm_db_connection_deref(ci);
@@ -11353,7 +11623,8 @@
* traverse from_nat_list of a node and calls ecm_db_connection_decelerate_and_defunct()
* for each entry
*/
-void ecm_db_traverse_node_from_nat_connection_list_and_decelerate(struct ecm_db_node_instance *node)
+void ecm_db_traverse_node_from_nat_connection_list_and_decelerate(
+ struct ecm_db_node_instance *node)
{
struct ecm_db_connection_instance *ci = NULL;
@@ -11364,8 +11635,12 @@
while (ci) {
struct ecm_db_connection_instance *cin;
- DEBUG_TRACE("%p: defunct\n", ci);
- ecm_db_connection_decelerate_and_defunct(ci);
+ if (!ecm_db_should_keep_connection(ci, node->address)) {
+ DEBUG_TRACE("%p: defunct\n", ci);
+ ecm_db_connection_decelerate_and_defunct(ci);
+ } else {
+ DEBUG_TRACE("%p: keeping connection\n", ci);
+ }
cin = ecm_db_node_from_nat_connection_get_and_ref_next(ci);
ecm_db_connection_deref(ci);
@@ -11379,7 +11654,8 @@
* traverse to_nat_list of a node and calls ecm_db_connection_decelerate_and_defunct()
* for each entry
*/
-void ecm_db_traverse_node_to_nat_connection_list_and_decelerate(struct ecm_db_node_instance *node)
+void ecm_db_traverse_node_to_nat_connection_list_and_decelerate(
+ struct ecm_db_node_instance *node)
{
struct ecm_db_connection_instance *ci = NULL;
@@ -11390,8 +11666,12 @@
while (ci) {
struct ecm_db_connection_instance *cin;
- DEBUG_TRACE("%p: defunct\n", ci);
- ecm_db_connection_decelerate_and_defunct(ci);
+ if (!ecm_db_should_keep_connection(ci, node->address)) {
+ DEBUG_TRACE("%p: defunct\n", ci);
+ ecm_db_connection_decelerate_and_defunct(ci);
+ } else {
+ DEBUG_TRACE("%p: keeping connection\n", ci);
+ }
cin = ecm_db_node_to_nat_connection_get_and_ref_next(ci);
ecm_db_connection_deref(ci);
diff --git a/ecm_db.h b/ecm_db.h
index 68871dc..c4f5e84 100644
--- a/ecm_db.h
+++ b/ecm_db.h
@@ -154,6 +154,10 @@
void ecm_db_iface_pppol2tpv2_session_info_get(struct ecm_db_iface_instance *ii, struct ecm_db_interface_info_pppol2tpv2 *pppol2tpv2_info);
struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_pppol2tpv2(uint32_t pppol2tpv2_tunnel_id, uint32_t pppol2tpv2_session_id);
#endif
+#ifdef ECM_INTERFACE_PPTP_ENABLE
+struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_pptp(uint32_t pptp_src_call_id, uint32_t pptp_dst_call_id);
+void ecm_db_iface_pptp_session_info_get(struct ecm_db_iface_instance *ii, struct ecm_db_interface_info_pptp *pptp_info);
+#endif
struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_loopback(uint32_t os_specific_ident);
#ifdef ECM_INTERFACE_IPSEC_ENABLE
struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_ipsec_tunnel(uint32_t os_specific_ident);
@@ -278,6 +282,11 @@
#ifdef ECM_INTERFACE_L2TPV2_ENABLE
void ecm_db_iface_add_pppol2tpv2(struct ecm_db_iface_instance *ii, struct ecm_db_interface_info_pppol2tpv2 *pppol2tpv2_info, char *name, int32_t mtu, int32_t interface_identifier, int32_t ae_interface_identifier, ecm_db_iface_final_callback_t final, void *arg);
#endif
+
+#ifdef ECM_INTERFACE_PPTP_ENABLE
+void ecm_db_iface_add_pptp(struct ecm_db_iface_instance *ii, struct ecm_db_interface_info_pptp *pptp_info, char *name, int32_t mtu, int32_t interface_identifier, int32_t ae_interface_identifier, ecm_db_iface_final_callback_t final, void *arg);
+#endif
+
void ecm_db_iface_add_unknown(struct ecm_db_iface_instance *ii, uint32_t os_specific_ident, char *name, int32_t mtu, int32_t interface_identifier, int32_t ae_interface_identifier, ecm_db_iface_final_callback_t final, void *arg);
void ecm_db_iface_add_loopback(struct ecm_db_iface_instance *ii, uint32_t os_specific_ident, char *name, int32_t mtu, int32_t interface_identifier, int32_t ae_interface_identifier, ecm_db_iface_final_callback_t final, void *arg);
#ifdef ECM_INTERFACE_IPSEC_ENABLE
diff --git a/ecm_db_types.h b/ecm_db_types.h
index 69e526d..cc8cd05 100644
--- a/ecm_db_types.h
+++ b/ecm_db_types.h
@@ -242,6 +242,7 @@
ECM_DB_IFACE_TYPE_SIT, /* IPv6 in IPv4 tunnel (SIT) interface */
ECM_DB_IFACE_TYPE_TUNIPIP6, /* IPIP6 Tunnel (TUNNEL6) interface */
ECM_DB_IFACE_TYPE_PPPOL2TPV2, /* Interface is a PPPoL2TPV2 interface (a specific form of PPP that we recognise in the ECM) */
+ ECM_DB_IFACE_TYPE_PPTP, /* Interface is a PPTP interface */
ECM_DB_IFACE_TYPE_COUNT, /* Number of interface types */
};
typedef enum ecm_db_iface_types ecm_db_iface_type_t;
@@ -301,6 +302,15 @@
#endif
+#ifdef ECM_INTERFACE_PPTP_ENABLE
+struct ecm_db_interface_info_pptp {
+ uint32_t src_ip;
+ uint32_t dst_ip;
+ uint16_t src_call_id;
+ uint16_t dst_call_id;
+};
+#endif
+
struct ecm_db_interface_info_unknown { /* type == ECM_DB_IFACE_TYPE_UNKNOWN */
uint32_t os_specific_ident; /* Operating system specific identifier (known only by front end) */
};
diff --git a/ecm_interface.c b/ecm_interface.c
index bb4bd2e..ca84ebf 100644
--- a/ecm_interface.c
+++ b/ecm_interface.c
@@ -74,6 +74,9 @@
#ifdef ECM_INTERFACE_L2TPV2_ENABLE
#include <linux/if_pppol2tp.h>
#endif
+#ifdef ECM_INTERFACE_PPTP_ENABLE
+#include <linux/netfilter/nf_conntrack_proto_gre.h>
+#endif
#endif
/*
@@ -785,15 +788,14 @@
#endif
#ifdef ECM_INTERFACE_PPP_ENABLE
-#ifdef ECM_INTERFACE_L2TPV2_ENABLE
/*
- * ecm_interface_skip_l2tpv3_pptp()
+ * ecm_interface_skip_pptp()
* skip pptp tunnel encapsulated traffic
*
- * ECM does not handle PPTP and l2tpv3,
+ * ECM does not handle PPTP,
* this function detects packets of that type so they can be skipped over to improve their throughput.
*/
-bool ecm_interface_skip_l2tpv3_pptp(struct sk_buff *skb, const struct net_device *out)
+bool ecm_interface_skip_pptp(struct sk_buff *skb, const struct net_device *out)
{
struct ppp_channel *ppp_chan[1];
int px_proto;
@@ -814,25 +816,6 @@
return true;
}
- /*
- * Check for L2TPv3 packets
- */
- if (px_proto == PX_PROTO_OL2TP) {
- struct pppol2tp_common_addr info;
- if (pppol2tp_channel_addressing_get(ppp_chan[0], &info)) {
- ppp_release_channels(ppp_chan, 1);
- return true;
- }
-
- if (info.tunnel_version == 2) {
- ppp_release_channels(ppp_chan, 1);
- return false;
- }
- if (info.tunnel_version == 3) {
- ppp_release_channels(ppp_chan, 1);
- return true;
- }
- }
ppp_release_channels(ppp_chan, 1);
}
@@ -858,6 +841,64 @@
return true;
}
+ ppp_release_channels(ppp_chan, 1);
+ }
+
+ dev_put(in);
+ return false;
+}
+
+/*
+ * ecm_interface_skip_l2tp_packet_by_version()
+ * Check version of l2tp tunnel encapsulated traffic
+ *
+ * ECM does not handle l2tp,
+ * this function detects packets of that type so they can be skipped over to improve their throughput.
+ */
+bool ecm_interface_skip_l2tp_packet_by_version(struct sk_buff *skb, const struct net_device *out, int ver)
+{
+ struct ppp_channel *ppp_chan[1];
+ int px_proto;
+ struct net_device *in;
+
+ if (out->type == ARPHRD_PPP) {
+ if (ppp_hold_channels((struct net_device *)out, ppp_chan, 1) != 1) {
+ return true;
+ }
+
+ px_proto = ppp_channel_get_protocol(ppp_chan[0]);
+
+ /*
+ * Check for L2TPv3 packets
+ */
+ if (px_proto == PX_PROTO_OL2TP) {
+ struct pppol2tp_common_addr info;
+ if (pppol2tp_channel_addressing_get(ppp_chan[0], &info)) {
+ ppp_release_channels(ppp_chan, 1);
+ return true;
+ }
+
+ if (info.tunnel_version == ver) {
+ ppp_release_channels(ppp_chan, 1);
+ return true;
+ }
+ }
+ ppp_release_channels(ppp_chan, 1);
+ }
+
+ in = dev_get_by_index(&init_net, skb->skb_iif);
+ if (!in) {
+ return true;
+ }
+
+ if (in->type == ARPHRD_PPP) {
+ if (__ppp_hold_channels((struct net_device *)in, ppp_chan, 1) != 1) {
+ dev_put(in);
+ return true;
+ }
+
+ px_proto = ppp_channel_get_protocol(ppp_chan[0]);
+
/*
* Check for L2TPv3 pkts
*/
@@ -868,12 +909,8 @@
dev_put(in);
return true;
}
- if (info.tunnel_version == 2) {
- ppp_release_channels(ppp_chan, 1);
- dev_put(in);
- return false;
- }
- if (info.tunnel_version == 3) {
+
+ if (info.tunnel_version == ver) {
ppp_release_channels(ppp_chan, 1);
dev_put(in);
return true;
@@ -885,7 +922,6 @@
dev_put(in);
return false;
}
-#endif
/*
* ecm_interface_skip_l2tp_pptp()
@@ -1240,6 +1276,59 @@
#endif
+#ifdef ECM_INTERFACE_PPTP_ENABLE
+/*
+ * ecm_interface_pptp_interface_establish()
+ * Returns a reference to a iface of the PPTP type, possibly creating one if necessary.
+ * Returns NULL on failure or a reference to interface.
+ */
+static struct ecm_db_iface_instance *ecm_interface_pptp_interface_establish(struct ecm_db_interface_info_pptp *type_info,
+ char *dev_name, int32_t dev_interface_num, int32_t ae_interface_num, int32_t mtu)
+{
+ struct ecm_db_iface_instance *nii;
+ struct ecm_db_iface_instance *ii;
+
+ DEBUG_INFO("Establish PPTP iface: %s with local call id %u peer call id %u\n", dev_name, type_info->src_call_id,
+ type_info->dst_call_id);
+ /*
+ * Locate the iface
+ */
+ ii = ecm_db_iface_find_and_ref_pptp(type_info->src_call_id, type_info->dst_call_id);
+ if (ii) {
+ DEBUG_TRACE("%p: iface established\n", ii);
+ ecm_db_iface_update_ae_interface_identifier(ii, ae_interface_num);
+ return ii;
+ }
+
+ /*
+ * No iface - create one
+ */
+ nii = ecm_db_iface_alloc();
+ if (!nii) {
+ DEBUG_WARN("Failed to establish iface\n");
+ return NULL;
+ }
+
+ /*
+ * Add iface into the database, atomically to avoid races creating the same thing
+ */
+ spin_lock_bh(&ecm_interface_lock);
+ ii = ecm_db_iface_find_and_ref_pptp(type_info->src_call_id, type_info->dst_call_id);
+ if (ii) {
+ spin_unlock_bh(&ecm_interface_lock);
+ ecm_db_iface_deref(nii);
+ ecm_db_iface_update_ae_interface_identifier(ii, ae_interface_num);
+ return ii;
+ }
+
+ ecm_db_iface_add_pptp(nii, type_info, dev_name, mtu, dev_interface_num, ae_interface_num, NULL, nii);
+ spin_unlock_bh(&ecm_interface_lock);
+
+ DEBUG_TRACE("%p: pptp iface established\n", nii);
+ return nii;
+}
+#endif
+
/*
* ecm_interface_unknown_interface_establish()
* Returns a reference to a iface of the UNKNOWN type, possibly creating one if necessary.
@@ -1530,6 +1619,9 @@
#ifdef ECM_INTERFACE_L2TPV2_ENABLE
struct ecm_db_interface_info_pppol2tpv2 pppol2tpv2; /* type == ECM_DB_IFACE_TYPE_PPPOL2TPV2 */
#endif
+#ifdef ECM_INTERFACE_PPTP_ENABLE
+ struct ecm_db_interface_info_pptp pptp; /* type == ECM_DB_IFACE_TYPE_PPTP */
+#endif
struct ecm_db_interface_info_unknown unknown; /* type == ECM_DB_IFACE_TYPE_UNKNOWN */
struct ecm_db_interface_info_loopback loopback; /* type == ECM_DB_IFACE_TYPE_LOOPBACK */
#ifdef ECM_INTERFACE_IPSEC_ENABLE
@@ -1552,8 +1644,16 @@
#ifdef ECM_INTERFACE_PPPOE_ENABLE
struct pppoe_opt addressing;
#endif
+#ifdef ECM_INTERFACE_PPTP_ENABLE
+ int protocol = IPPROTO_IP;
+ struct pptp_opt opt;
+ struct iphdr *v4_hdr = NULL;
+ if (skb) {
+ v4_hdr = ip_hdr(skb);
+ protocol = v4_hdr->protocol;
+ }
#endif
-
+#endif
/*
* Get basic information about the given device
*/
@@ -1852,6 +1952,53 @@
}
#endif
+#ifdef ECM_INTERFACE_PPTP_ENABLE
+ if ((protocol == IPPROTO_GRE) && skb && v4_hdr) {
+ struct gre_hdr_pptp *gre_hdr;
+ uint16_t proto;
+ int ret;
+
+ skb_pull(skb, sizeof(struct iphdr));
+ gre_hdr = (struct gre_hdr_pptp *)(skb->data);
+ proto = ntohs(gre_hdr->protocol);
+ if ((gre_hdr->version == GRE_VERSION_PPTP) && (proto == GRE_PROTOCOL_PPTP)) {
+ ret = pptp_session_find(&opt, gre_hdr->call_id, v4_hdr->daddr);
+ if (ret < 0) {
+ skb_push(skb, sizeof(struct iphdr));
+ DEBUG_WARN("PPTP session info not found\n");
+ return NULL;
+ }
+
+ /*
+ * Get PPTP session info
+ */
+ type_info.pptp.src_call_id = ntohs(opt.src_addr.call_id);
+ type_info.pptp.dst_call_id = ntohs(opt.dst_addr.call_id);
+ type_info.pptp.src_ip = ntohl(opt.src_addr.sin_addr.s_addr);
+ type_info.pptp.dst_ip = ntohl(opt.dst_addr.sin_addr.s_addr);
+
+ skb_push(skb, sizeof(struct iphdr));
+
+ /*
+ * Establish this type of interface
+ */
+ ii = ecm_interface_pptp_interface_establish(&type_info.pptp, dev_name, dev_interface_num, ae_interface_num, dev_mtu);
+ return ii;
+ }
+
+ skb_push(skb, sizeof(struct iphdr));
+
+ DEBUG_TRACE("Unknown GRE protocol \n");
+ type_info.unknown.os_specific_ident = dev_interface_num;
+
+ /*
+ * Establish this type of interface
+ */
+ ii = ecm_interface_unknown_interface_establish(&type_info.unknown, dev_name, dev_interface_num, ae_interface_num, dev_mtu);
+ return ii;
+ }
+#endif
+
/*
* PPP - but what is the channel type?
* First: If this is multi-link then we do not support it
@@ -1955,6 +2102,29 @@
return ii;
}
#endif
+
+#ifdef ECM_INTERFACE_PPTP_ENABLE
+ if (channel_protocol == PX_PROTO_PPTP) {
+ pptp_channel_addressing_get(&opt, ppp_chan[0]);
+
+ /*
+ * Get PPTP session info
+ */
+ type_info.pptp.src_call_id = ntohs(opt.src_addr.call_id);
+ type_info.pptp.dst_call_id = ntohs(opt.dst_addr.call_id);
+ type_info.pptp.src_ip = ntohl(opt.src_addr.sin_addr.s_addr);
+ type_info.pptp.dst_ip = ntohl(opt.dst_addr.sin_addr.s_addr);
+
+ DEBUG_TRACE("Net device: %p PPTP source call id: %d,n", dev, type_info.pptp.src_call_id);
+ ppp_release_channels(ppp_chan, 1);
+
+ /*
+ * Establish this type of interface
+ */
+ ii = ecm_interface_pptp_interface_establish(&type_info.pptp, dev_name, dev_interface_num, ae_interface_num, dev_mtu);
+ return ii;
+ }
+#endif
DEBUG_TRACE("Net device: %p PPP channel protocol: %d - Unknown to the ECM\n", dev, channel_protocol);
type_info.unknown.os_specific_ident = dev_interface_num;
@@ -1968,7 +2138,6 @@
*/
ii = ecm_interface_unknown_interface_establish(&type_info.unknown, dev_name, dev_interface_num, ae_interface_num, dev_mtu);
return ii;
-
#endif
}
EXPORT_SYMBOL(ecm_interface_establish_and_ref);
@@ -2381,7 +2550,8 @@
if (in_dev && !mfc_update) {
if (ecm_front_end_is_bridge_port(in_dev)) {
src_dev_is_bridge = true;
- br_dev_src = in_dev->master;
+ br_dev_src = ecm_interface_get_and_hold_dev_master(in_dev);
+ DEBUG_ASSERT(br_dev_src, "Expected a master\n");
/*
* The source net_dev found as bridge slave. In case of routed interface
@@ -2431,8 +2601,9 @@
*/
return 0;
}
+
dest_dev = br_dev_src;
- dev_hold(dest_dev);
+
}
dest_dev_type = dest_dev->type;
@@ -2815,6 +2986,20 @@
}
#endif
+#ifdef ECM_INTERFACE_PPTP_ENABLE
+ /*
+ * if the address is a local address and indev=PPTP.
+ */
+ if (protocol == IPPROTO_GRE && given_dest_dev && given_dest_dev->type == ARPHRD_PPP) {
+ dev_put(dest_dev);
+ dest_dev = given_dest_dev;
+ if (dest_dev) {
+ dev_hold(dest_dev);
+ DEBUG_TRACE("PPTP packet tunnel packet with dest_addr: " ECM_IP_ADDR_OCTAL_FMT " uses dev: %p(%s)\n", ECM_IP_ADDR_TO_OCTAL(dest_addr), dest_dev, dest_dev->name);
+ }
+ }
+#endif
+
if (!dest_dev) {
DEBUG_WARN("dest_addr: " ECM_IP_ADDR_OCTAL_FMT " - cannot locate device\n", ECM_IP_ADDR_TO_OCTAL(dest_addr));
return ECM_DB_IFACE_HEIRARCHY_MAX;
@@ -2934,7 +3119,6 @@
while (current_interface_index > 0) {
struct ecm_db_iface_instance *ii;
struct net_device *next_dev;
-
/*
* Get the ecm db interface instance for the device at hand
*/
@@ -3258,6 +3442,13 @@
}
}
#endif
+
+#ifdef ECM_INTERFACE_PPTP_ENABLE
+ if (protocol == IPPROTO_GRE && dest_dev && dest_dev->type == ARPHRD_PPP) {
+ DEBUG_TRACE("Net device: %p PPP channel is PPTP\n", dest_dev);
+ break;
+ }
+#endif
/*
* PPP - but what is the channel type?
* First: If this is multi-link then we do not support it
@@ -3834,10 +4025,10 @@
node = ecm_db_node_find_and_ref(mac);
if(unlikely(!node)) {
- DEBUG_WARN("node address is null \n");
+ DEBUG_WARN("node address is null\n");
return NOTIFY_DONE;
}
-
+ DEBUG_INFO("FDB updated for node %pM\n", mac);
ecm_db_traverse_node_from_connection_list_and_decelerate(node);
ecm_db_traverse_node_to_connection_list_and_decelerate(node);
ecm_db_traverse_node_from_nat_connection_list_and_decelerate(node);
diff --git a/ecm_interface.h b/ecm_interface.h
index 78b05ed..adc903d 100644
--- a/ecm_interface.h
+++ b/ecm_interface.h
@@ -51,7 +51,8 @@
#ifdef ECM_IPV6_ENABLE
struct neighbour *ecm_interface_ipv6_neigh_get(ip_addr_t addr);
#endif
-bool ecm_interface_skip_l2tpv3_pptp(struct sk_buff *skb, const struct net_device *out);
+bool ecm_interface_skip_pptp(struct sk_buff *skb, const struct net_device *out);
+bool ecm_interface_skip_l2tp_packet_by_version(struct sk_buff *skb, const struct net_device *out, int ver);
bool ecm_interface_skip_l2tp_pptp(struct sk_buff *skb, const struct net_device *out);
struct ecm_db_iface_instance *ecm_interface_establish_and_ref(struct ecm_front_end_connection_instance *feci, struct net_device *dev, struct sk_buff *skb);
diff --git a/frontends/nss/ecm_nss_ipv4.c b/frontends/nss/ecm_nss_ipv4.c
index 815e1ca..9f9037f 100644
--- a/frontends/nss/ecm_nss_ipv4.c
+++ b/frontends/nss/ecm_nss_ipv4.c
@@ -188,7 +188,7 @@
int i;
bool done;
uint8_t node_addr[ETH_ALEN];
-#ifdef ECM_INTERFACE_L2TPV2_ENABLE
+#if defined(ECM_INTERFACE_L2TPV2_ENABLE) || defined(ECM_INTERFACE_PPTP_ENABLE)
ip_addr_t local_ip, remote_ip;
#endif
@@ -222,6 +222,9 @@
#ifdef ECM_INTERFACE_L2TPV2_ENABLE
struct ecm_db_interface_info_pppol2tpv2 pppol2tpv2_info;
#endif
+#ifdef ECM_INTERFACE_PPTP_ENABLE
+ struct ecm_db_interface_info_pptp pptp_info;
+#endif
type = ecm_db_connection_iface_type_get(interface_list[i]);
DEBUG_INFO("Lookup node address, interface @ %d is type: %d\n", i, type);
@@ -271,6 +274,30 @@
return NULL;
#endif
+ case ECM_DB_IFACE_TYPE_PPTP:
+#ifdef ECM_INTERFACE_PPTP_ENABLE
+ ecm_db_iface_pptp_session_info_get(interface_list[i], &pptp_info);
+ ECM_HIN4_ADDR_TO_IP_ADDR(local_ip, pptp_info.src_ip);
+ ECM_HIN4_ADDR_TO_IP_ADDR(remote_ip, pptp_info.dst_ip);
+ if (ECM_IP_ADDR_MATCH(local_ip, addr)) {
+ if (unlikely(!ecm_interface_mac_addr_get(local_ip, node_addr, &on_link, gw_addr))) {
+ DEBUG_TRACE("failed to obtain node address for " ECM_IP_ADDR_DOT_FMT "\n", ECM_IP_ADDR_TO_DOT(local_ip));
+ return NULL;
+ }
+
+ } else {
+ if (unlikely(!ecm_interface_mac_addr_get(remote_ip, node_addr, &on_link, gw_addr))) {
+ DEBUG_TRACE("failed to obtain node address for host " ECM_IP_ADDR_DOT_FMT "\n", ECM_IP_ADDR_TO_DOT(remote_ip));
+ return NULL;
+ }
+ }
+
+ done = true;
+ break;
+#else
+ DEBUG_TRACE("PPTP interface unsupported\n");
+ return NULL;
+#endif
case ECM_DB_IFACE_TYPE_VLAN:
#ifdef ECM_INTERFACE_VLAN_ENABLE
/*
@@ -848,7 +875,6 @@
}
DEBUG_INFO("%p: reclassify success\n", ci);
-
ecm_ipv4_regen_done:
/*
@@ -1318,6 +1344,11 @@
DEBUG_TRACE("%p: Routing: %s\n", out, out->name);
+ if (ecm_front_end_acceleration_rejected(skb)) {
+ DEBUG_TRACE("Acceleration rejected\n");
+ return NF_ACCEPT;
+ }
+
/*
* If operations have stopped then do not process packets
*/
@@ -1345,18 +1376,27 @@
#endif
#ifdef ECM_INTERFACE_PPP_ENABLE
-#ifdef ECM_INTERFACE_L2TPV2_ENABLE
+#ifndef ECM_INTERFACE_PPTP_ENABLE
/*
- * skip l2tpv3/pptp because we don't accelerate them
+ * skip pptp because we don't accelerate them
*/
- if (ecm_interface_skip_l2tpv3_pptp(skb, out)) {
+ if (ecm_interface_skip_pptp(skb, out)) {
+ return NF_ACCEPT;
+ }
+#endif
+#ifndef ECM_INTERFACE_L2TPV2_ENABLE
+ /*
+ * skip l2tp v2 and v3, because we don't accelerate them
+ */
+ if (ecm_interface_skip_l2tp_packet_by_version(skb, out, 2) ||
+ ecm_interface_l2tp_version_check(skb, out, 3)) {
return NF_ACCEPT;
}
#else
/*
- * skip l2tp/pptp because we don't accelerate them
+ * skip l2tpv3 because we don't accelerate them
*/
- if (ecm_interface_skip_l2tp_pptp(skb, out)) {
+ if (ecm_interface_skip_l2tp_packet_by_version(skb, out, 3)) {
return NF_ACCEPT;
}
#endif
diff --git a/frontends/nss/ecm_nss_ipv6.c b/frontends/nss/ecm_nss_ipv6.c
index f544dd3..745609a 100644
--- a/frontends/nss/ecm_nss_ipv6.c
+++ b/frontends/nss/ecm_nss_ipv6.c
@@ -1031,6 +1031,11 @@
DEBUG_TRACE("%p: Routing: %s\n", out, out->name);
+ if (ecm_front_end_acceleration_rejected(skb)) {
+ DEBUG_TRACE("Acceleration rejected.\n");
+ return NF_ACCEPT;
+ }
+
/*
* If operations have stopped then do not process packets
*/
@@ -1060,9 +1065,17 @@
#ifdef ECM_INTERFACE_PPP_ENABLE
#ifdef ECM_INTERFACE_L2TPV2_ENABLE
/*
- * skip l2tpv3/pptp because we don't accelerate them
+ * skip l2tpv3 because we don't accelerate them
*/
- if (ecm_interface_skip_l2tpv3_pptp(skb, out)) {
+ if (ecm_interface_skip_l2tp_packet_by_version(skb, out, 3)) {
+ return NF_ACCEPT;
+ }
+
+ /*
+ * Skip PPTP beacuse we don't support acceleration for
+ * IPv6 inner header over PPTP
+ */
+ if (ecm_interface_skip_pptp(skb, out)) {
return NF_ACCEPT;
}
#else
diff --git a/frontends/nss/ecm_nss_multicast_ipv4.c b/frontends/nss/ecm_nss_multicast_ipv4.c
index 1b87bb1..20ab413 100644
--- a/frontends/nss/ecm_nss_multicast_ipv4.c
+++ b/frontends/nss/ecm_nss_multicast_ipv4.c
@@ -2166,6 +2166,7 @@
int dest_port;
int src_port_nat = 0;
struct net_device *in_dev_nat = NULL;
+ struct net_device *out_dev_master = NULL;
struct ecm_db_multicast_tuple_instance *tuple_instance;
struct ecm_db_connection_instance *ci;
ip_addr_t match_addr;
@@ -2268,14 +2269,18 @@
is_routed = true;
br_dev_found_in_mfc = ecm_interface_multicast_check_for_br_dev(dst_dev, if_cnt);
} else {
+ out_dev_master = ecm_interface_get_and_hold_dev_master(out_dev);
+ DEBUG_ASSERT(out_dev_master, "Expected a master\n");
+
+
/*
* Packet flow is pure bridge. Try to query the snooper for the destination
* interface list
*/
- if_cnt = mc_bridge_ipv4_get_if(out_dev->master, ip_src, ip_grp, ECM_DB_MULTICAST_IF_MAX, dst_dev);
+ if_cnt = mc_bridge_ipv4_get_if(out_dev_master, ip_src, ip_grp, ECM_DB_MULTICAST_IF_MAX, dst_dev);
if (if_cnt <= 0) {
DEBUG_WARN("Not found a valid MCS if count %d\n", if_cnt);
- return NF_ACCEPT;
+ goto done;
}
/*
@@ -2287,7 +2292,7 @@
if_cnt = ecm_interface_multicast_check_for_src_ifindex(dst_dev, if_cnt, in_dev->ifindex);
if (if_cnt <= 0) {
DEBUG_WARN("Not found a valid MCS if count %d\n", if_cnt);
- return NF_ACCEPT;
+ goto done;
}
}
}
@@ -2298,7 +2303,7 @@
if (!is_routed) {
if (iph->ttl < 2) {
DEBUG_TRACE("%p: Ignoring, Multicast IPv4 Header has TTL one\n", skb);
- return NF_ACCEPT;
+ goto done;
}
}
@@ -2315,7 +2320,7 @@
*/
in_dev_nat = ecm_interface_dev_find_by_addr(ip_src_addr_nat, &from_local_addr);
if (!in_dev_nat) {
- return NF_ACCEPT;
+ goto done;
}
/*
@@ -2335,7 +2340,7 @@
* list for a NAT flow, which should not happen.
*/
if (!nat_if_found) {
- return NF_ACCEPT;
+ goto done;
}
}
@@ -2385,7 +2390,7 @@
/*
* As we are terminating we just allow the packet to pass - it's no longer our concern
*/
- return NF_ACCEPT;
+ goto done;
}
spin_unlock_bh(&ecm_nss_ipv4_lock);
@@ -2395,7 +2400,7 @@
nci = ecm_db_connection_alloc();
if (!nci) {
DEBUG_WARN("Failed to allocate connection\n");
- return NF_ACCEPT;
+ goto done;
}
/*
@@ -2405,7 +2410,7 @@
if (!feci) {
ecm_db_connection_deref(nci);
DEBUG_WARN("Failed to allocate front end\n");
- return NF_ACCEPT;
+ goto done;
}
/*
@@ -2415,7 +2420,7 @@
if (!tuple_instance) {
ecm_db_connection_deref(nci);
DEBUG_WARN("Failed to allocate tuple instance\n");
- return NF_ACCEPT;
+ goto done;
}
/*
@@ -2434,7 +2439,7 @@
ecm_db_connection_deref(nci);
ecm_db_multicast_tuple_instance_deref(tuple_instance);
DEBUG_WARN("Failed to obtain 'from' heirarchy list\n");
- return NF_ACCEPT;
+ goto done;
}
ecm_db_connection_from_interfaces_reset(nci, from_list, from_list_first);
@@ -2446,7 +2451,7 @@
feci->deref(feci);
ecm_db_connection_deref(nci);
ecm_db_multicast_tuple_instance_deref(tuple_instance);
- return NF_ACCEPT;
+ goto done;
}
DEBUG_TRACE("%p: Create source mapping\n", nci);
@@ -2457,7 +2462,7 @@
feci->deref(feci);
ecm_db_connection_deref(nci);
ecm_db_multicast_tuple_instance_deref(tuple_instance);
- return NF_ACCEPT;
+ goto done;
}
to_list = (struct ecm_db_iface_instance *)kzalloc(ECM_DB_TO_MCAST_INTERFACES_SIZE, GFP_ATOMIC | __GFP_NOWARN);
@@ -2468,7 +2473,7 @@
feci->deref(feci);
ecm_db_connection_deref(nci);
ecm_db_multicast_tuple_instance_deref(tuple_instance);
- return NF_ACCEPT;
+ goto done;
}
to_list_first = (int32_t *)kzalloc(sizeof(int32_t *) * ECM_DB_MULTICAST_IF_MAX, GFP_ATOMIC | __GFP_NOWARN);
@@ -2481,7 +2486,7 @@
ecm_db_connection_deref(nci);
ecm_db_multicast_tuple_instance_deref(tuple_instance);
kfree(to_list);
- return NF_ACCEPT;
+ goto done;
}
/*
@@ -2494,7 +2499,7 @@
}
interface_idx_cnt = ecm_nss_multicast_connection_to_interface_heirarchy_construct(feci, to_list, ip_src_addr, ip_dest_addr, in_dev,
- out_dev->master, if_cnt, dst_dev, to_list_first,
+ out_dev_master, if_cnt, dst_dev, to_list_first,
src_node_addr, is_routed, layer4hdr, skb);
if (interface_idx_cnt == 0) {
ecm_db_node_deref(src_ni);
@@ -2505,7 +2510,7 @@
kfree(to_list);
kfree(to_list_first);
DEBUG_WARN("%p: Failed to obtain mutlicast 'to' heirarchy list\n", nci);
- return NF_ACCEPT;
+ goto done;
}
ret = ecm_db_multicast_connection_to_interfaces_reset(nci, to_list, to_list_first);
if (ret < 0) {
@@ -2524,7 +2529,7 @@
kfree(to_list);
kfree(to_list_first);
DEBUG_WARN("%p: Failed to obtain mutlicast 'to' heirarchy list\n", nci);
- return NF_ACCEPT;
+ goto done;
}
DEBUG_TRACE("%p: Create destination node\n", nci);
@@ -2550,7 +2555,7 @@
kfree(to_list);
kfree(to_list_first);
DEBUG_WARN("Failed to establish destination node\n");
- return NF_ACCEPT;
+ goto done;
}
DEBUG_TRACE("%p: Create source mapping\n", nci);
@@ -2572,7 +2577,7 @@
kfree(to_list);
kfree(to_list_first);
DEBUG_WARN("Failed to establish dst mapping\n");
- return NF_ACCEPT;
+ goto done;
}
DEBUG_TRACE("%p: Create the 'from NAT' interface heirarchy list\n", nci);
@@ -2595,7 +2600,7 @@
kfree(to_list);
kfree(to_list_first);
DEBUG_WARN("Failed to obtain 'from NAT' heirarchy list\n");
- return NF_ACCEPT;
+ goto done;
}
ecm_db_connection_from_nat_interfaces_reset(nci, from_nat_list, from_nat_list_first);
@@ -2619,7 +2624,7 @@
kfree(to_list);
kfree(to_list_first);
DEBUG_WARN("Failed to obtain 'from NAT' node\n");
- return NF_ACCEPT;
+ goto done;
}
DEBUG_TRACE("%p: Create from NAT mapping\n", nci);
@@ -2644,7 +2649,7 @@
kfree(to_list);
kfree(to_list_first);
DEBUG_WARN("Failed to establish from nat mapping\n");
- return NF_ACCEPT;
+ goto done;
}
/*
@@ -2671,7 +2676,7 @@
kfree(to_list);
kfree(to_list_first);
DEBUG_WARN("Failed to allocate default classifier\n");
- return NF_ACCEPT;
+ goto done;
}
ecm_db_connection_classifier_assign(nci, (struct ecm_classifier_instance *)dci);
@@ -2704,7 +2709,7 @@
kfree(to_list);
kfree(to_list_first);
DEBUG_WARN("Failed to allocate classifiers assignments\n");
- return NF_ACCEPT;
+ goto done;
}
}
@@ -2799,14 +2804,14 @@
to_list = (struct ecm_db_iface_instance *)kzalloc(ECM_DB_TO_MCAST_INTERFACES_SIZE, GFP_ATOMIC | __GFP_NOWARN);
if (!to_list) {
ecm_db_connection_deref(ci);
- return NF_ACCEPT;
+ goto done;
}
to_list_first = (int32_t *)kzalloc(sizeof(int32_t *) * ECM_DB_MULTICAST_IF_MAX, GFP_ATOMIC | __GFP_NOWARN);
if (!to_list_first) {
ecm_db_connection_deref(ci);
kfree(to_list);
- return NF_ACCEPT;
+ goto done;
}
/*
@@ -2819,7 +2824,7 @@
feci = ecm_db_connection_front_end_get_and_ref(ci);
interface_idx_cnt = ecm_nss_multicast_connection_to_interface_heirarchy_construct(feci, to_list, ip_src_addr, ip_dest_addr, in_dev,
- out_dev->master, if_cnt, dst_dev, to_list_first,
+ out_dev_master, if_cnt, dst_dev, to_list_first,
src_node_addr, is_routed, (__be16 *)&udp_hdr, skb);
feci->deref(feci);
if (interface_idx_cnt == 0) {
@@ -2827,7 +2832,7 @@
ecm_db_connection_deref(ci);
kfree(to_list);
kfree(to_list_first);
- return NF_ACCEPT;
+ goto done;
}
ret = ecm_db_multicast_connection_to_interfaces_reset(ci, to_list, to_list_first);
@@ -2850,7 +2855,7 @@
*/
if (ret < 0) {
ecm_db_connection_deref(ci);
- return NF_ACCEPT;
+ goto done;
}
}
}
@@ -2860,7 +2865,7 @@
*/
if (!ecm_db_connection_defunct_timer_touch(ci)) {
ecm_db_connection_deref(ci);
- return NF_ACCEPT;
+ goto done;
}
/*
@@ -3013,7 +3018,7 @@
DEBUG_TRACE("%p: drop: %p\n", ci, skb);
ecm_db_connection_data_totals_update_dropped(ci, (sender == ECM_TRACKER_SENDER_TYPE_SRC)? true : false, skb->len, 1);
ecm_db_connection_deref(ci);
- return NF_ACCEPT;
+ goto done;
}
ecm_db_multicast_connection_data_totals_update(ci, false, skb->len, 1);
@@ -3025,11 +3030,13 @@
feci = ecm_db_connection_front_end_get_and_ref(ci);
ecm_nss_multicast_ipv4_connection_accelerate(feci, &prevalent_pr);
feci->deref(feci);
- } else {
- goto done;
}
-done:
ecm_db_connection_deref(ci);
+
+done:
+ if (out_dev_master) {
+ dev_put(out_dev_master);
+ }
return NF_ACCEPT;
}
diff --git a/frontends/nss/ecm_nss_multicast_ipv6.c b/frontends/nss/ecm_nss_multicast_ipv6.c
index a40d0a1..42ddefd 100644
--- a/frontends/nss/ecm_nss_multicast_ipv6.c
+++ b/frontends/nss/ecm_nss_multicast_ipv6.c
@@ -2125,6 +2125,7 @@
bool br_dev_found_in_mfc = false;
int protocol = (int)orig_tuple->dst.protonum;
__be16 *layer4hdr = NULL;
+ struct net_device *out_dev_master = NULL;
if (protocol != IPPROTO_UDP) {
DEBUG_WARN("Invalid Protocol %d in skb %p\n", protocol, skb);
@@ -2207,15 +2208,17 @@
is_routed = true;
br_dev_found_in_mfc = ecm_interface_multicast_check_for_br_dev(mc_dest_if, mc_if_cnt);
} else {
+ out_dev_master = ecm_interface_get_and_hold_dev_master(out_dev);
+ DEBUG_ASSERT(out_dev_master, "Expected a master\n");
/*
* Packet flow is pure bridge. Try to query the snooper for the destination
* interface list
*/
- mc_if_cnt = mc_bridge_ipv6_get_if(out_dev->master, &origin6, &group6, ECM_DB_MULTICAST_IF_MAX, mc_dest_if);
+ mc_if_cnt = mc_bridge_ipv6_get_if(out_dev_master, &origin6, &group6, ECM_DB_MULTICAST_IF_MAX, mc_dest_if);
if (mc_if_cnt <= 0) {
DEBUG_WARN("Not found a valid MCS if count %d\n", mc_if_cnt);
- return NF_ACCEPT;
+ goto done;
}
/*
@@ -2227,7 +2230,7 @@
mc_if_cnt = ecm_interface_multicast_check_for_src_ifindex(mc_dest_if, mc_if_cnt, in_dev->ifindex);
if (mc_if_cnt <= 0) {
DEBUG_WARN("Not found a valid MCS if count %d\n", mc_if_cnt);
- return NF_ACCEPT;
+ goto done;
}
}
}
@@ -2238,7 +2241,7 @@
if (!is_routed) {
if (iph->ttl < 2) {
DEBUG_TRACE("%p: Ignoring, Multicast IPv6 Header has Hop Limit one\n", skb);
- return NF_ACCEPT;
+ goto done;
}
}
@@ -2288,7 +2291,7 @@
/*
* As we are terminating we just allow the packet to pass - it's no longer our concern
*/
- return NF_ACCEPT;
+ goto done;
}
spin_unlock_bh(&ecm_nss_ipv6_lock);
@@ -2298,7 +2301,7 @@
nci = ecm_db_connection_alloc();
if (!nci) {
DEBUG_WARN("Failed to allocate connection\n");
- return NF_ACCEPT;
+ goto done;
}
/*
@@ -2308,7 +2311,7 @@
if (!feci) {
ecm_db_connection_deref(nci);
DEBUG_WARN("Failed to allocate front end\n");
- return NF_ACCEPT;
+ goto done;
}
/*
@@ -2318,7 +2321,7 @@
if (!tuple_instance) {
ecm_db_connection_deref(nci);
DEBUG_WARN("Failed to allocate tuple instance\n");
- return NF_ACCEPT;
+ goto done;
}
/*
* Create Destination MAC address using IP multicast destination address
@@ -2338,7 +2341,7 @@
ecm_db_connection_deref(nci);
ecm_db_multicast_tuple_instance_deref(tuple_instance);
DEBUG_WARN("Failed to obtain 'from' heirarchy list\n");
- return NF_ACCEPT;
+ goto done;
}
ecm_db_connection_from_interfaces_reset(nci, from_list, from_list_first);
@@ -2350,7 +2353,7 @@
ecm_db_connection_deref(nci);
ecm_db_multicast_tuple_instance_deref(tuple_instance);
DEBUG_WARN("Failed to establish source node\n");
- return NF_ACCEPT;
+ goto done;
}
DEBUG_TRACE("%p: Create source mapping\n", nci);
@@ -2361,7 +2364,7 @@
ecm_db_connection_deref(nci);
ecm_db_multicast_tuple_instance_deref(tuple_instance);
DEBUG_WARN("Failed to establish src mapping\n");
- return NF_ACCEPT;
+ goto done;
}
DEBUG_TRACE("%p: Create the 'to' interface heirarchy list\n", nci);
@@ -2373,7 +2376,7 @@
feci->deref(feci);
ecm_db_connection_deref(nci);
ecm_db_multicast_tuple_instance_deref(tuple_instance);
- return NF_ACCEPT;
+ goto done;
}
to_list_first = (int32_t *)kzalloc(sizeof(int32_t *) * ECM_DB_MULTICAST_IF_MAX, GFP_ATOMIC | __GFP_NOWARN);
@@ -2385,7 +2388,7 @@
ecm_db_connection_deref(nci);
ecm_db_multicast_tuple_instance_deref(tuple_instance);
kfree(to_list);
- return NF_ACCEPT;
+ goto done;
}
/*
@@ -2397,7 +2400,7 @@
*to_first = ECM_DB_IFACE_HEIRARCHY_MAX;
}
- interface_idx_cnt = ecm_nss_multicast_ipv6_interface_heirarchy_construct(feci, to_list, in_dev, out_dev->master, ip_src_addr,
+ interface_idx_cnt = ecm_nss_multicast_ipv6_interface_heirarchy_construct(feci, to_list, in_dev, out_dev_master, ip_src_addr,
ip_dest_addr, mc_if_cnt, mc_dest_if, to_list_first, src_node_addr, is_routed, skb);
if (interface_idx_cnt == 0) {
DEBUG_WARN("Failed to obtain 'to' heirarchy list\n");
@@ -2407,7 +2410,7 @@
ecm_db_connection_deref(nci);
kfree(to_list);
kfree(to_list_first);
- return NF_ACCEPT;
+ goto done;
}
ret = ecm_db_multicast_connection_to_interfaces_reset(nci, to_list, to_list_first);
@@ -2427,7 +2430,7 @@
kfree(to_list);
kfree(to_list_first);
DEBUG_WARN("Failed to obtain 'to' heirarchy list\n");
- return NF_ACCEPT;
+ goto done;
}
/*
@@ -2458,7 +2461,7 @@
kfree(to_list);
kfree(to_list_first);
DEBUG_WARN("Failed to establish dest node\n");
- return NF_ACCEPT;
+ goto done;
}
DEBUG_TRACE("%p: Create dest mapping\n", nci);
@@ -2479,7 +2482,7 @@
kfree(to_list);
kfree(to_list_first);
DEBUG_WARN("Failed to establish dest mapping\n");
- return NF_ACCEPT;
+ goto done;
}
/*
@@ -2503,7 +2506,7 @@
kfree(to_list);
kfree(to_list_first);
DEBUG_WARN("Failed to allocate default classifier\n");
- return NF_ACCEPT;
+ goto done;
}
ecm_db_connection_classifier_assign(nci, (struct ecm_classifier_instance *)dci);
@@ -2533,7 +2536,7 @@
kfree(to_list);
kfree(to_list_first);
DEBUG_WARN("Failed to allocate classifiers assignments\n");
- return NF_ACCEPT;
+ goto done;
}
}
@@ -2634,14 +2637,14 @@
to_list = (struct ecm_db_iface_instance *)kzalloc(ECM_DB_TO_MCAST_INTERFACES_SIZE, GFP_ATOMIC | __GFP_NOWARN);
if (!to_list) {
ecm_db_connection_deref(ci);
- return NF_ACCEPT;
+ goto done;
}
to_list_first = (int32_t *)kzalloc(sizeof(int32_t *) * ECM_DB_MULTICAST_IF_MAX, GFP_ATOMIC | __GFP_NOWARN);
if (!to_list_first) {
ecm_db_connection_deref(ci);
kfree(to_list);
- return NF_ACCEPT;
+ goto done;
}
for (i = 0; i < ECM_DB_MULTICAST_IF_MAX; i++) {
@@ -2650,7 +2653,7 @@
}
feci = ecm_db_connection_front_end_get_and_ref(ci);
- interface_idx_cnt = ecm_nss_multicast_ipv6_interface_heirarchy_construct(feci, to_list, in_dev, out_dev->master,\
+ interface_idx_cnt = ecm_nss_multicast_ipv6_interface_heirarchy_construct(feci, to_list, in_dev, out_dev_master,\
ip_src_addr, ip_dest_addr, mc_if_cnt,\
mc_dest_if, to_list_first, src_node_addr,
is_routed, skb);
@@ -2660,7 +2663,7 @@
ecm_db_connection_deref(ci);
kfree(to_list);
kfree(to_list_first);
- return NF_ACCEPT;
+ goto done;
}
ret = ecm_db_multicast_connection_to_interfaces_reset(ci, to_list, to_list_first);
@@ -2684,7 +2687,7 @@
*/
if (ret < 0) {
ecm_db_connection_deref(ci);
- return NF_ACCEPT;
+ goto done;
}
}
}
@@ -2694,7 +2697,7 @@
*/
if (!ecm_db_connection_defunct_timer_touch(ci)) {
ecm_db_connection_deref(ci);
- return NF_ACCEPT;
+ goto done;
}
/*
@@ -2847,7 +2850,7 @@
DEBUG_TRACE("%p: drop: %p\n", ci, skb);
ecm_db_connection_data_totals_update_dropped(ci, (sender == ECM_TRACKER_SENDER_TYPE_SRC)? true : false, skb->len, 1);
ecm_db_connection_deref(ci);
- return NF_ACCEPT;
+ goto done;
}
ecm_db_connection_data_totals_update(ci, (sender == ECM_TRACKER_SENDER_TYPE_SRC)? true : false, skb->len, 1);
@@ -2867,11 +2870,13 @@
feci = ecm_db_connection_front_end_get_and_ref(ci);
ecm_nss_multicast_ipv6_connection_accelerate(feci, &prevalent_pr);
feci->deref(feci);
- } else {
- goto done;
}
-done:
ecm_db_connection_deref(ci);
+
+done:
+ if (out_dev_master) {
+ dev_put(out_dev_master);
+ }
return NF_ACCEPT;
}
diff --git a/frontends/nss/ecm_nss_non_ported_ipv4.c b/frontends/nss/ecm_nss_non_ported_ipv4.c
index cdeb75d..59ce422 100644
--- a/frontends/nss/ecm_nss_non_ported_ipv4.c
+++ b/frontends/nss/ecm_nss_non_ported_ipv4.c
@@ -387,7 +387,10 @@
uint8_t from_nss_iface_address[ETH_ALEN];
uint8_t to_nss_iface_address[ETH_ALEN];
ip_addr_t addr;
- struct nss_ipv4_msg nim;
+#if defined(ECM_INTERFACE_L2TPV2_ENABLE) || defined(ECM_INTERFACE_PPTP_ENABLE)
+ struct net_device *dev __attribute__((unused));
+#endif
+ struct nss_ipv4_msg *nim;
struct nss_ipv4_rule_create_msg *nircm;
struct ecm_classifier_instance *assignments[ECM_CLASSIFIER_TYPES];
int aci_index;
@@ -413,7 +416,7 @@
* For non-ported protocols we only support IPv6 in 4 or ESP
*/
protocol = ecm_db_connection_protocol_get(feci->ci);
- if ((protocol != IPPROTO_IPV6) && (protocol != IPPROTO_ESP)) {
+ if ((protocol != IPPROTO_IPV6) && (protocol != IPPROTO_ESP) && (protocol != IPPROTO_GRE)) {
spin_lock_bh(&feci->lock);
feci->accel_mode = ECM_FRONT_END_ACCELERATION_MODE_FAIL_RULE;
spin_unlock_bh(&feci->lock);
@@ -429,19 +432,24 @@
return;
}
+ nim = (struct nss_ipv4_msg *)kzalloc(sizeof(struct nss_ipv4_msg), GFP_ATOMIC | __GFP_NOWARN);
+ if (!nim) {
+ DEBUG_WARN("%p: no memory for nss ipv4 message structure instance: %p\n", feci, feci->ci);
+ return;
+ }
+
/*
* Okay construct an accel command.
* Initialise creation structure.
* NOTE: We leverage the app_data void pointer to be our 32 bit connection serial number.
* When we get it back we re-cast it to a uint32 and do a faster connection lookup.
*/
- memset(&nim, 0, sizeof(struct nss_ipv4_msg));
- nss_ipv4_msg_init(&nim, NSS_IPV4_RX_INTERFACE, NSS_IPV4_TX_CREATE_RULE_MSG,
+ nss_ipv4_msg_init(nim, NSS_IPV4_RX_INTERFACE, NSS_IPV4_TX_CREATE_RULE_MSG,
sizeof(struct nss_ipv4_rule_create_msg),
ecm_nss_non_ported_ipv4_connection_callback,
(void *)ecm_db_connection_serial_get(feci->ci));
- nircm = &nim.msg.rule_create;
+ nircm = &nim->msg.rule_create;
nircm->valid_flags = 0;
nircm->rule_flags = 0;
@@ -654,6 +662,31 @@
DEBUG_TRACE("%p: IPSEC - unsupported\n", nnpci);
#endif
break;
+ case ECM_DB_IFACE_TYPE_PPTP:
+#ifdef ECM_INTERFACE_PPTP_ENABLE
+ /*
+ * pptp packets from lan to wan gets routed twice.
+ * 1. eth1-->br-lan to pptp
+ * 2. pptp ---> eth0.
+ * we need to push nss rule for both. Requirement
+ * mandidates multiple session per tunnel and all tunnel
+ * packets has same 5 tuple info. So need to create a
+ * special static pptp interface with nss to identify
+ * packets from wan side. So pptp--->eth0 rule to be
+ * pushed with this static interface.
+ */
+ ecm_db_connection_from_address_get(feci->ci, addr);
+ dev = ecm_interface_dev_find_by_local_addr(addr);
+ if (likely(dev)) {
+ dev_put(dev);
+ from_nss_iface_id = NSS_PPTP_INTERFACE;
+ nircm->conn_rule.flow_interface_num = from_nss_iface_id;
+ }
+#else
+ rule_invalid = true;
+ DEBUG_TRACE("%p: PPTP - unsupported\n", nnpci);
+#endif
+ break;
default:
DEBUG_TRACE("%p: Ignoring: %d (%s)\n", nnpci, ii_type, ii_name);
}
@@ -875,6 +908,20 @@
* The flow_ip is where the connection established from
*/
ecm_db_connection_from_address_get(feci->ci, addr);
+
+ /*
+ * Get MTU information
+ */
+ nircm->conn_rule.flow_mtu = (uint32_t)ecm_db_connection_from_iface_mtu_get(feci->ci);
+#ifdef ECM_INTERFACE_PPTP_ENABLE
+ if (unlikely(from_nss_iface_id == NSS_PPTP_INTERFACE)) {
+ dev = ecm_interface_dev_find_by_local_addr(addr);
+ if (likely(dev)) {
+ nircm->conn_rule.flow_mtu = dev->mtu;
+ dev_put(dev);
+ }
+ }
+#endif
ECM_IP_ADDR_TO_HIN4_ADDR(nircm->tuple.flow_ip, addr);
/*
@@ -951,7 +998,6 @@
/*
* Get MTU information
*/
- nircm->conn_rule.flow_mtu = (uint32_t)ecm_db_connection_from_iface_mtu_get(feci->ci);
nircm->conn_rule.return_mtu = (uint32_t)ecm_db_connection_to_iface_mtu_get(feci->ci);
/*
@@ -1048,6 +1094,7 @@
if (regen_occurrances != ecm_db_connection_regeneration_occurrances_get(feci->ci)) {
DEBUG_INFO("%p: connection:%p regen occurred - aborting accel rule.\n", feci, feci->ci);
ecm_nss_ipv4_accel_pending_clear(feci, ECM_FRONT_END_ACCELERATION_MODE_DECEL);
+ kfree(nim);
return;
}
@@ -1069,7 +1116,7 @@
/*
* Call the rule create function
*/
- nss_tx_status = nss_ipv4_tx(ecm_nss_ipv4_nss_ipv4_mgr, &nim);
+ nss_tx_status = nss_ipv4_tx(ecm_nss_ipv4_nss_ipv4_mgr, nim);
if (nss_tx_status == NSS_TX_SUCCESS) {
/*
* Reset the driver_fail count - transmission was okay here.
@@ -1077,9 +1124,12 @@
spin_lock_bh(&feci->lock);
feci->stats.driver_fail = 0;
spin_unlock_bh(&feci->lock);
+ kfree(nim);
return;
}
+ kfree(nim);
+
/*
* Release that ref!
*/
@@ -1109,6 +1159,7 @@
non_ported_accel_bad_rule:
;
+ kfree(nim);
/*
* Jump to here when rule data is bad and an offload command cannot be constructed
*/
@@ -1739,7 +1790,7 @@
* Look up a connection.
*/
protocol = (int)orig_tuple->dst.protonum;
- if ((protocol == IPPROTO_IPV6) || (protocol == IPPROTO_ESP)) {
+ if ((protocol == IPPROTO_IPV6) || (protocol == IPPROTO_ESP || (protocol == IPPROTO_GRE))) {
src_port = 0;
src_port_nat = 0;
dest_port = 0;
diff --git a/frontends/nss/ecm_nss_ported_ipv4.c b/frontends/nss/ecm_nss_ported_ipv4.c
index db9833a..f2fb9a2 100644
--- a/frontends/nss/ecm_nss_ported_ipv4.c
+++ b/frontends/nss/ecm_nss_ported_ipv4.c
@@ -330,10 +330,10 @@
uint8_t from_nss_iface_address[ETH_ALEN];
uint8_t to_nss_iface_address[ETH_ALEN];
ip_addr_t addr;
-#ifdef ECM_INTERFACE_L2TPV2_ENABLE
+#if defined(ECM_INTERFACE_L2TPV2_ENABLE) || defined(ECM_INTERFACE_PPTP_ENABLE)
struct net_device *dev;
#endif
- struct nss_ipv4_msg nim;
+ struct nss_ipv4_msg *nim;
struct nss_ipv4_rule_create_msg *nircm;
struct ecm_classifier_instance *assignments[ECM_CLASSIFIER_TYPES];
int aci_index;
@@ -363,19 +363,24 @@
return;
}
+ nim = (struct nss_ipv4_msg *)kzalloc(sizeof(struct nss_ipv4_msg), GFP_ATOMIC | __GFP_NOWARN);
+ if (!nim) {
+ DEBUG_WARN("%p: no memory for nss ipv4 message structure instance: %p\n", feci, feci->ci);
+ return;
+ }
+
/*
* Okay construct an accel command.
* Initialise creation structure.
* NOTE: We leverage the app_data void pointer to be our 32 bit connection serial number.
* When we get it back we re-cast it to a uint32 and do a faster connection lookup.
*/
- memset(&nim, 0, sizeof(struct nss_ipv4_msg));
- nss_ipv4_msg_init(&nim, NSS_IPV4_RX_INTERFACE, NSS_IPV4_TX_CREATE_RULE_MSG,
+ nss_ipv4_msg_init(nim, NSS_IPV4_RX_INTERFACE, NSS_IPV4_TX_CREATE_RULE_MSG,
sizeof(struct nss_ipv4_rule_create_msg),
ecm_nss_ported_ipv4_connection_callback,
(void *)ecm_db_connection_serial_get(feci->ci));
- nircm = &nim.msg.rule_create;
+ nircm = &nim->msg.rule_create;
nircm->valid_flags = 0;
nircm->rule_flags = 0;
@@ -793,6 +798,31 @@
DEBUG_TRACE("%p: IPSEC - unsupported\n", npci);
#endif
break;
+ case ECM_DB_IFACE_TYPE_PPTP:
+#ifdef ECM_INTERFACE_PPTP_ENABLE
+ /*
+ * pptp packets from lan to wan gets routed twice.
+ * 1. eth1-->br-lan to pptp
+ * 2. pptp ---> eth0.
+ * we need to push nss rule for both. Requirement
+ * mandidates multiple session per tunnel and all tunnel
+ * packets has same 5 tuple info. So need to create a
+ * special static pptp interface with nss to identify
+ * packets from wan side. So pptp--->eth0 rule to be
+ * pushed with this static interface.
+ */
+ ecm_db_connection_to_address_get(feci->ci, addr);
+ dev = ecm_interface_dev_find_by_local_addr(addr);
+ if (likely(dev)) {
+ dev_put(dev);
+ from_nss_iface_id = NSS_PPTP_INTERFACE;
+ nircm->conn_rule.flow_interface_num = from_nss_iface_id;
+ }
+#else
+ rule_invalid = true;
+ DEBUG_TRACE("%p: PPTP - unsupported\n", npci);
+#endif
+ break;
default:
DEBUG_TRACE("%p: Ignoring: %d (%s)\n", npci, ii_type, ii_name);
}
@@ -1110,6 +1140,7 @@
if (regen_occurrances != ecm_db_connection_regeneration_occurrances_get(feci->ci)) {
DEBUG_INFO("%p: connection:%p regen occurred - aborting accel rule.\n", feci, feci->ci);
ecm_nss_ipv4_accel_pending_clear(feci, ECM_FRONT_END_ACCELERATION_MODE_DECEL);
+ kfree(nim);
return;
}
@@ -1131,7 +1162,7 @@
/*
* Call the rule create function
*/
- nss_tx_status = nss_ipv4_tx(ecm_nss_ipv4_nss_ipv4_mgr, &nim);
+ nss_tx_status = nss_ipv4_tx(ecm_nss_ipv4_nss_ipv4_mgr, nim);
if (nss_tx_status == NSS_TX_SUCCESS) {
/*
* Reset the driver_fail count - transmission was okay here.
@@ -1139,9 +1170,12 @@
spin_lock_bh(&feci->lock);
feci->stats.driver_fail = 0;
spin_unlock_bh(&feci->lock);
+ kfree(nim);
return;
}
+ kfree(nim);
+
/*
* Release that ref!
*/
@@ -1171,6 +1205,8 @@
ported_accel_bad_rule:
;
+ kfree(nim);
+
/*
* Jump to here when rule data is bad and an offload command cannot be constructed
*/
@@ -1305,7 +1341,6 @@
nss_tx_status_t nss_tx_status;
DEBUG_CHECK_MAGIC(npci, ECM_NSS_PORTED_IPV4_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", npci);
-
/*
* If decelerate is in error or already pending then ignore
*/
@@ -2318,6 +2353,36 @@
}
/*
+ * In DMZ scenarios SNAT rule is getting applied on the packet after packet
+ * passed through bridge post routing hook
+ *
+ * Example
+ * Consider following scenario where both WLAN PC and eth1 are part of same bridge
+ * 192.168.1.3(WLAN PC)<-->192.168.1.1(DUT br-lan)---> 192.168.1.4(Eth1 PC)
+ * When a DNAT is applied it is observed that following NAT rules are appended in iptables
+ *
+ * -A nat_reflection_out -s 192.168.1.0/24 -d 192.168.1.4/32 -p tcp -m tcp --dport 3389 -m comment --comment "wan" -j SNAT
+ * --to-source 192.168.1.1
+ * -A nat_reflection_out -s 192.168.1.0/24 -d 192.168.1.4/32 -p udp -m udp --dport 3389 -m comment --comment "wan" -j SNAT
+ * --to-source 192.168.1.1
+ *
+ * This Shows that SNAT is getting applied on bridged packet also. However it is observed that
+ * the SNAT is updated in ct after the packet has crossed this function through bridge hook.
+ *
+ * Hence Flushing the connection that was already created earlier if the ip_src_addr_nat value changes for same tuple in
+ * subsequent packets
+ */
+ ecm_db_connection_from_address_nat_get(ci, match_addr);
+ if (!ECM_IP_ADDR_MATCH(ip_src_addr_nat, match_addr) && ct) {
+ /*
+ * Force destruction of the connection my making it defunct
+ */
+ ecm_db_connection_make_defunct(ci);
+ ecm_db_connection_deref(ci);
+ return NF_ACCEPT;
+ }
+
+ /*
* Keep connection alive as we have seen activity
*/
if (!ecm_db_connection_defunct_timer_touch(ci)) {
@@ -2337,6 +2402,7 @@
sender = ECM_TRACKER_SENDER_TYPE_DEST;
}
+
/*
* Do we need to action generation change?
*/