[qca-nss-ecm] Added support for PPTP packet acceleration
Change-Id: I834130ce635bb2e21363b9d1fc3912d022442fa2
Signed-off-by: Shyam Sunder <ssunde@codeaurora.org>
diff --git a/Makefile b/Makefile
index f017c40..8a499db 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
# #############################################################################
diff --git a/ecm_db.c b/ecm_db.c
index 047ee5f..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
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 c94bb6b..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);
@@ -2817,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;
@@ -2936,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
*/
@@ -3260,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
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 f34f2e6..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
/*
@@ -1349,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 192a052..745609a 100644
--- a/frontends/nss/ecm_nss_ipv6.c
+++ b/frontends/nss/ecm_nss_ipv6.c
@@ -1065,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_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 58571ca..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
*/