[][openwrt][mt7988][tops][support v1.2.0]
[Description]
Add support to TOPS v1.2.0 with latest driver and firmware
1. Fix L2TPv2 offload bugs
2. Add L2TPv2/IPsec offload feature
3. Add PPTP offload feature
[Release-log]
N/A
Change-Id: Id27778b1d88417293f306b2ea281777936545b70
Reviewed-on: https://gerrit.mediatek.inc/c/openwrt/feeds/mtk_openwrt_feeds/+/8346642
diff --git a/package-21.02/kernel/tops/Makefile b/package-21.02/kernel/tops/Makefile
index b848646..2c7e0a9 100644
--- a/package-21.02/kernel/tops/Makefile
+++ b/package-21.02/kernel/tops/Makefile
@@ -54,6 +54,9 @@
kmod-tops \
+kmod-pce \
+@KERNEL_RELAY
+ifeq ($(CONFIG_MTK_TOPS_PPTP), y)
+ DEPENDS+= +kmod-pptp
+endif
endef
define KernelPackage/tops-release/description
diff --git a/package-21.02/kernel/tops/firmware/rebb/mt7988_mgmt/tops-mgmt.img b/package-21.02/kernel/tops/firmware/rebb/mt7988_mgmt/tops-mgmt.img
index 67f42dc..329dbb6 100644
--- a/package-21.02/kernel/tops/firmware/rebb/mt7988_mgmt/tops-mgmt.img
+++ b/package-21.02/kernel/tops/firmware/rebb/mt7988_mgmt/tops-mgmt.img
Binary files differ
diff --git a/package-21.02/kernel/tops/firmware/rebb/mt7988_offload/tops-offload.img b/package-21.02/kernel/tops/firmware/rebb/mt7988_offload/tops-offload.img
index 8738b5e..1a7bea5 100644
--- a/package-21.02/kernel/tops/firmware/rebb/mt7988_offload/tops-offload.img
+++ b/package-21.02/kernel/tops/firmware/rebb/mt7988_offload/tops-offload.img
Binary files differ
diff --git a/package-21.02/kernel/tops/src/Makefile b/package-21.02/kernel/tops/src/Makefile
index 86f860d..929d902 100644
--- a/package-21.02/kernel/tops/src/Makefile
+++ b/package-21.02/kernel/tops/src/Makefile
@@ -29,6 +29,7 @@
tops-y += trm-debugfs.o
tops-y += trm.o
tops-y += wdt.o
+tops-y += seq_gen.o
tops-y += protocol/mac/eth.o
tops-y += protocol/mac/ppp.o
@@ -36,5 +37,7 @@
tops-y += protocol/transport/udp.o
tops-$(CONFIG_MTK_TOPS_GRETAP) += protocol/tunnel/gre/gretap.o
tops-$(CONFIG_MTK_TOPS_L2TP_V2) += protocol/tunnel/l2tp/l2tpv2.o
+tops-$(CONFIG_MTK_TOPS_PPTP) += protocol/tunnel/pptp/pptp.o
+tops-$(CONFIG_MTK_TOPS_PPTP) += protocol/tunnel/pptp/pptp_seq.o
include $(wildcard $(src)/*.mk)
diff --git a/package-21.02/kernel/tops/src/inc/tops/hwspinlock.h b/package-21.02/kernel/tops/src/inc/tops/hwspinlock.h
index 1ce5004..407c01a 100644
--- a/package-21.02/kernel/tops/src/inc/tops/hwspinlock.h
+++ b/package-21.02/kernel/tops/src/inc/tops/hwspinlock.h
@@ -8,6 +8,7 @@
#ifndef _TOPS_HWSPIN_LOCK_H_
#define _TOPS_HWSPIN_LOCK_H_
+#include <linux/platform_device.h>
#include <linux/types.h>
#define HWSPINLOCK_SLOT_MAX 16
@@ -55,7 +56,7 @@
HWSPINLOCK_CLUST_SLOT_8,
HWSPINLOCK_CLUST_SLOT_9,
HWSPINLOCK_CLUST_SLOT_10,
- HWSPINLOCK_CLUST_SLOT_11,
+ HWSPINLOCK_CLUST_SLOT_PPTP_SEQ,
HWSPINLOCK_CLUST_SLOT_12,
HWSPINLOCK_CLUST_SLOT_13,
HWSPINLOCK_CLUST_SLOT_14,
diff --git a/package-21.02/kernel/tops/src/inc/tops/seq_gen.h b/package-21.02/kernel/tops/src/inc/tops/seq_gen.h
new file mode 100644
index 0000000..992cfb0
--- /dev/null
+++ b/package-21.02/kernel/tops/src/inc/tops/seq_gen.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (c) 2023 MediaTek Inc. All Rights Reserved.
+ *
+ * Author: Frank-zj Lin <frank-zj.lin@mediatek.com>
+ */
+
+#ifndef _TOPS_SEQ_GEN_H_
+#define _TOPS_SEQ_GEN_H_
+
+#include <linux/platform_device.h>
+
+#define TOPS_SEQ_GEN_BASE 0x880100 /* PKT_ID_GEN reg base */
+#define TOPS_SEQ_GEN_IDX_MAX 16 /* num of PKT_ID_GEN reg */
+
+void mtk_tops_seq_gen_set_16(int seq_gen_idx, u16 val);
+int mtk_tops_seq_gen_next_16(int seq_gen_idx, u16 *val);
+void mtk_tops_seq_gen_set_32(int seq_gen_idx, u32 val);
+int mtk_tops_seq_gen_next_32(int seq_gen_idx, u32 *val);
+int mtk_tops_seq_gen_alloc(int *seq_gen_idx);
+void mtk_tops_seq_gen_free(int seq_gen_idx);
+int mtk_tops_seq_gen_init(struct platform_device *pdev);
+#endif /* _TOPS_SEQ_GEN_H_ */
diff --git a/package-21.02/kernel/tops/src/inc/tops/tops_params.h b/package-21.02/kernel/tops/src/inc/tops/tops_params.h
index 0bdb9b5..057f20b 100644
--- a/package-21.02/kernel/tops/src/inc/tops/tops_params.h
+++ b/package-21.02/kernel/tops/src/inc/tops/tops_params.h
@@ -15,6 +15,7 @@
#include "tops/protocol/network/ip_params.h"
#include "tops/protocol/transport/udp_params.h"
#include "tops/protocol/tunnel/l2tp/l2tp_params.h"
+#include "tops/protocol/tunnel/pptp/pptp_params.h"
/* tunnel params flags */
#define TNL_DECAP_ENABLE (BIT(TNL_PARAMS_DECAP_ENABLE_BIT))
@@ -94,6 +95,7 @@
struct tops_tunnel_params {
union {
struct tops_l2tp_params l2tp;
+ struct tops_pptp_params pptp;
};
enum tops_tunnel_type type;
};
diff --git a/package-21.02/kernel/tops/src/init.c b/package-21.02/kernel/tops/src/init.c
index 478a45a..9944ea2 100644
--- a/package-21.02/kernel/tops/src/init.c
+++ b/package-21.02/kernel/tops/src/init.c
@@ -31,6 +31,7 @@
#include "tops/trm.h"
#include "tops/tunnel.h"
#include "tops/wdt.h"
+#include "tops/seq_gen.h"
#define EFUSE_TOPS_POWER_OFF (0xD08)
@@ -145,6 +146,12 @@
goto err_netsys_deinit;
}
+ ret = mtk_tops_seq_gen_init(pdev);
+ if (ret) {
+ TOPS_ERR("sequence generator init failed: %d\n", ret);
+ goto err_tdma_deinit;
+ }
+
ret = mtk_tops_tnl_offload_init(pdev);
if (ret) {
TOPS_ERR("tunnel table init failed: %d\n", ret);
diff --git a/package-21.02/kernel/tops/src/protocol/gre/gretap.c b/package-21.02/kernel/tops/src/protocol/gre/gretap.c
deleted file mode 100644
index 9e937af..0000000
--- a/package-21.02/kernel/tops/src/protocol/gre/gretap.c
+++ /dev/null
@@ -1,193 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Copyright (c) 2023 MediaTek Inc. All Rights Reserved.
- *
- * Author: Ren-Ting Wang <ren-ting.wang@mediatek.com>
- */
-
-#include <net/gre.h>
-
-#include <pce/cls.h>
-#include <pce/netsys.h>
-#include <pce/pce.h>
-
-#include "tunnel.h"
-
-static int gretap_cls_entry_setup(struct tops_tnl_info *tnl_info,
- struct cls_desc *cdesc)
-{
- CLS_DESC_DATA(cdesc, fport, PSE_PORT_PPE0);
- CLS_DESC_DATA(cdesc, tport_idx, 0x4);
- CLS_DESC_MASK_DATA(cdesc, tag, CLS_DESC_TAG_MASK, CLS_DESC_TAG_MATCH_L4_HDR);
- CLS_DESC_MASK_DATA(cdesc, dip_match, CLS_DESC_DIP_MATCH, CLS_DESC_DIP_MATCH);
- CLS_DESC_MASK_DATA(cdesc, l4_type, CLS_DESC_L4_TYPE_MASK, IPPROTO_GRE);
- CLS_DESC_MASK_DATA(cdesc, l4_udp_hdr_nez,
- CLS_DESC_UDPLITE_L4_HDR_NEZ_MASK,
- CLS_DESC_UDPLITE_L4_HDR_NEZ_MASK);
- CLS_DESC_MASK_DATA(cdesc, l4_valid,
- CLS_DESC_L4_VALID_MASK,
- CLS_DESC_VALID_UPPER_HALF_WORD_BIT |
- CLS_DESC_VALID_LOWER_HALF_WORD_BIT);
- CLS_DESC_MASK_DATA(cdesc, l4_hdr_usr_data, 0x0000FFFF, 0x00006558);
-
- return 0;
-}
-
-static int gretap_tnl_decap_param_setup(struct sk_buff *skb,
- struct tops_tnl_params *tnl_params)
-{
- struct gre_base_hdr *pgre;
- struct gre_base_hdr greh;
- struct ethhdr *eth;
- struct ethhdr ethh;
- struct iphdr *ip;
- struct iphdr iph;
- int ret = 0;
-
- if (!skb->dev->rtnl_link_ops
- || strcmp(skb->dev->rtnl_link_ops->kind, "gretap"))
- return -EAGAIN;
-
- skb_push(skb, sizeof(struct gre_base_hdr));
- pgre = skb_header_pointer(skb, 0, sizeof(struct gre_base_hdr), &greh);
- if (unlikely(!pgre)) {
- ret = -EINVAL;
- goto restore_gre;
- }
-
- if (unlikely(ntohs(pgre->protocol) != ETH_P_TEB)) {
- pr_notice("gre: %p protocol unmatched, proto: 0x%x\n",
- pgre, ntohs(pgre->protocol));
- ret = -EINVAL;
- goto restore_gre;
- }
-
- /* TODO: store gre parameters? */
-
- skb_push(skb, sizeof(struct iphdr));
- ip = skb_header_pointer(skb, 0, sizeof(struct iphdr), &iph);
- if (unlikely(!ip)) {
- ret = -EINVAL;
- goto restore_ip;
- }
-
- if (unlikely(ip->version != IPVERSION || ip->protocol != IPPROTO_GRE)) {
- pr_notice("ip: %p version or protocol unmatched, ver: 0x%x, proto: 0x%x\n",
- ip, ip->version, ip->protocol);
- ret = -EINVAL;
- goto restore_ip;
- }
-
- /* TODO: check ip options is support for us? */
- /* TODO: store ip parameters? */
- tnl_params->protocol = ip->protocol;
- tnl_params->sip = ip->daddr;
- tnl_params->dip = ip->saddr;
-
- skb_push(skb, sizeof(struct ethhdr));
- eth = skb_header_pointer(skb, 0, sizeof(struct ethhdr), ðh);
- if (unlikely(!eth)) {
- ret = -EINVAL;
- goto restore_eth;
- }
-
- if (unlikely(ntohs(eth->h_proto) != ETH_P_IP)) {
- pr_notice("eth proto not support, proto: 0x%x\n",
- ntohs(eth->h_proto));
- ret = -EINVAL;
- goto restore_eth;
- }
-
- memcpy(&tnl_params->saddr, eth->h_dest, sizeof(u8) * ETH_ALEN);
- memcpy(&tnl_params->daddr, eth->h_source, sizeof(u8) * ETH_ALEN);
-
-restore_eth:
- skb_pull(skb, sizeof(struct ethhdr));
-
-restore_ip:
- skb_pull(skb, sizeof(struct iphdr));
-
-restore_gre:
- skb_pull(skb, sizeof(struct gre_base_hdr));
-
- return ret;
-}
-
-static int gretap_tnl_encap_param_setup(struct sk_buff *skb,
- struct tops_tnl_params *tnl_params)
-{
- struct ethhdr *eth = eth_hdr(skb);
- struct iphdr *ip = ip_hdr(skb);
-
- /*
- * ether type no need to check since it is even not constructed yet
- * currently not support gre without ipv4
- */
- if (unlikely(ip->version != IPVERSION || ip->protocol != IPPROTO_GRE)) {
- pr_notice("eth proto: 0x%x, ip ver: 0x%x, proto: 0x%x is not support\n",
- ntohs(eth->h_proto),
- ip->version,
- ip->protocol);
- return -EINVAL;
- }
-
- memcpy(&tnl_params->saddr, eth->h_source, sizeof(u8) * ETH_ALEN);
- memcpy(&tnl_params->daddr, eth->h_dest, sizeof(u8) * ETH_ALEN);
- tnl_params->protocol = ip->protocol;
- tnl_params->sip = ip->saddr;
- tnl_params->dip = ip->daddr;
-
- return 0;
-}
-
-static int gretap_tnl_debug_param_setup(const char *buf, int *ofs,
- struct tops_tnl_params *tnl_params)
-{
- tnl_params->protocol = IPPROTO_GRE;
- return 0;
-}
-
-static bool gretap_tnl_info_match(struct tops_tnl_params *parms1,
- struct tops_tnl_params *parms2)
-{
- if (parms1->sip == parms2->sip
- && parms1->dip == parms2->dip
- && !memcmp(parms1->saddr, parms2->saddr, sizeof(u8) * ETH_ALEN)
- && !memcmp(parms1->daddr, parms2->daddr, sizeof(u8) * ETH_ALEN)) {
- return true;
- }
-
- return false;
-}
-
-static bool gretap_tnl_decap_offloadable(struct sk_buff *skb)
-{
- struct iphdr *ip = ip_hdr(skb);
-
- if (ip->protocol != IPPROTO_GRE)
- return false;
-
- return true;
-}
-
-static struct tops_tnl_type gretap_type = {
- .type_name = "gretap",
- .cls_entry_setup = gretap_cls_entry_setup,
- .tnl_decap_param_setup = gretap_tnl_decap_param_setup,
- .tnl_encap_param_setup = gretap_tnl_encap_param_setup,
- .tnl_debug_param_setup = gretap_tnl_debug_param_setup,
- .tnl_info_match = gretap_tnl_info_match,
- .tnl_decap_offloadable = gretap_tnl_decap_offloadable,
- .tops_entry = TOPS_ENTRY_GRETAP,
- .has_inner_eth = true,
-};
-
-int mtk_tops_gretap_init(void)
-{
- return mtk_tops_tnl_type_register(&gretap_type);
-}
-
-void mtk_tops_gretap_deinit(void)
-{
- mtk_tops_tnl_type_unregister(&gretap_type);
-}
diff --git a/package-21.02/kernel/tops/src/protocol/inc/tops/protocol/tunnel/l2tp/l2tp_params.h b/package-21.02/kernel/tops/src/protocol/inc/tops/protocol/tunnel/l2tp/l2tp_params.h
index dc266ef..62db153 100644
--- a/package-21.02/kernel/tops/src/protocol/inc/tops/protocol/tunnel/l2tp/l2tp_params.h
+++ b/package-21.02/kernel/tops/src/protocol/inc/tops/protocol/tunnel/l2tp/l2tp_params.h
@@ -19,8 +19,10 @@
#define UDP_L2TP_PORT 1701
struct tops_l2tp_params {
- u16 tid; /* l2tp tunnel id */
- u16 sid; /* l2tp session id */
+ u16 dl_tid; /* l2tp tunnel id for DL */
+ u16 dl_sid; /* l2tp session id for DL */
+ u16 ul_tid; /* l2tp tunnel id for UL */
+ u16 ul_sid; /* l2tp session id for UL */
};
/* Limited support: L2TPv2 only, no length field, no options */
diff --git a/package-21.02/kernel/tops/src/protocol/inc/tops/protocol/tunnel/pptp/pptp.h b/package-21.02/kernel/tops/src/protocol/inc/tops/protocol/tunnel/pptp/pptp.h
new file mode 100644
index 0000000..950c984
--- /dev/null
+++ b/package-21.02/kernel/tops/src/protocol/inc/tops/protocol/tunnel/pptp/pptp.h
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (c) 2023 MediaTek Inc. All Rights Reserved.
+ *
+ * Author: Frank-zj Lin <frank-zj.lin@mediatek.com>
+ */
+
+#ifndef _TOPS_PPTP_H_
+#define _TOPS_PPTP_H_
+
+int mtk_tops_pptp_seq_get_seq_gen_idx(u16 call_id, int *seq_gen_idx);
+int mtk_tops_pptp_seq_alloc(u16 call_id, u32 start, int *seq_gen_idx);
+void mtk_tops_pptp_seq_free(u16 call_id);
+int mtk_tops_pptp_seq_init(void);
+void mtk_tops_pptp_seq_deinit(void);
+
+#if defined(CONFIG_MTK_TOPS_PPTP)
+int mtk_tops_pptp_init(void);
+void mtk_tops_pptp_deinit(void);
+#else /* !defined(CONFIG_MTK_TOPS_PPTP) */
+static inline int mtk_tops_pptp_init(void)
+{
+ return 0;
+}
+
+static inline void mtk_tops_pptp_deinit(void)
+{
+}
+#endif /* defined(CONFIG_MTK_TOPS_PPTP) */
+#endif /* _TOPS_PPTP_H_ */
diff --git a/package-21.02/kernel/tops/src/protocol/inc/tops/protocol/tunnel/pptp/pptp_params.h b/package-21.02/kernel/tops/src/protocol/inc/tops/protocol/tunnel/pptp/pptp_params.h
new file mode 100644
index 0000000..0ac4b9b
--- /dev/null
+++ b/package-21.02/kernel/tops/src/protocol/inc/tops/protocol/tunnel/pptp/pptp_params.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (c) 2023 MediaTek Inc. All Rights Reserved.
+ *
+ * Author: Frank-zj Lin <frank-zj.lin@mediatek.com>
+ */
+
+#ifndef _TOPS_PPTP_PARAMS_H_
+#define _TOPS_PPTP_PARAMS_H_
+
+#define PPTP_GRE_HDR_ACK_LEN 4
+
+struct tops_pptp_params {
+ u16 dl_call_id; /* call id for download */
+ u16 ul_call_id; /* call id for upload */
+ u8 seq_gen_idx; /* seq generator idx */
+};
+#endif /* _TOPS_PPTP_PARAMS_H_ */
diff --git a/package-21.02/kernel/tops/src/protocol/l2tp/udp_l2tp_data.c b/package-21.02/kernel/tops/src/protocol/l2tp/udp_l2tp_data.c
deleted file mode 100644
index 592271d..0000000
--- a/package-21.02/kernel/tops/src/protocol/l2tp/udp_l2tp_data.c
+++ /dev/null
@@ -1,324 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Copyright (c) 2023 MediaTek Inc. All Rights Reserved.
- *
- * Author: Frank-zj Lin <rank-zj.lin@mediatek.com>
- * Ren-Ting Wang <ren-ting.wang@mediatek.com>
- */
-
-#include <linux/if_ether.h>
-#include <linux/netdevice.h>
-#include <linux/ppp_defs.h>
-#include <linux/udp.h>
-
-#include <pce/cls.h>
-#include <pce/netsys.h>
-#include <pce/pce.h>
-
-#include "protocol/l2tp/l2tp.h"
-#include "protocol/ppp/ppp.h"
-#include "tunnel.h"
-
-static int udp_l2tp_data_cls_entry_setup(struct tops_tnl_info *tnl_info,
- struct cls_desc *cdesc)
-{
- CLS_DESC_DATA(cdesc, fport, PSE_PORT_PPE0);
- CLS_DESC_DATA(cdesc, tport_idx, 0x4);
- CLS_DESC_MASK_DATA(cdesc, tag, CLS_DESC_TAG_MASK, CLS_DESC_TAG_MATCH_L4_USR);
- CLS_DESC_MASK_DATA(cdesc, dip_match, CLS_DESC_DIP_MATCH, CLS_DESC_DIP_MATCH);
- CLS_DESC_MASK_DATA(cdesc, l4_type, CLS_DESC_L4_TYPE_MASK, IPPROTO_UDP);
- CLS_DESC_MASK_DATA(cdesc, l4_valid,
- CLS_DESC_L4_VALID_MASK,
- CLS_DESC_VALID_UPPER_HALF_WORD_BIT |
- CLS_DESC_VALID_LOWER_HALF_WORD_BIT |
- CLS_DESC_VALID_DPORT_BIT);
- CLS_DESC_MASK_DATA(cdesc, l4_dport, CLS_DESC_L4_DPORT_MASK, 1701);
- CLS_DESC_MASK_DATA(cdesc, l4_hdr_usr_data, 0x80030000, 0x00020000);
-
- return 0;
-}
-
-static inline bool l2tpv2_offload_match(struct udp_l2tp_data_hdr *l2tp)
-{
- u16 hdrflags = ntohs(l2tp->flag_ver);
-
- return ((hdrflags & L2TP_HDR_VER_MASK) == L2TP_HDR_VER_2 &&
- !(hdrflags & L2TP_HDRFLAG_T));
-}
-
-static inline bool ppp_offload_match(struct ppp_hdr *ppp)
-{
- return (ppp->addr == PPP_ALLSTATIONS &&
- ppp->ctrl == PPP_UI && ntohs(ppp->proto) == PPP_IP);
-}
-
-static int udp_l2tp_data_tnl_decap_param_setup(struct sk_buff *skb,
- struct tops_tnl_params *tnl_params)
-{
- struct udp_l2tp_data_hdr *l2tp;
- struct udp_l2tp_data_hdr l2tph;
- struct ppp_hdr *ppp;
- struct ppp_hdr ppph;
- struct udphdr *udp;
- struct udphdr udph;
- struct ethhdr *eth;
- struct ethhdr ethh;
- struct iphdr *ip;
- struct iphdr iph;
- int ret = 0;
-
- /* ppp */
- skb_push(skb, sizeof(struct ppp_hdr));
- ppp = skb_header_pointer(skb, 0, sizeof(struct ppp_hdr), &ppph);
-
- if (unlikely(!ppp)) {
- ret = -EINVAL;
- goto restore_ppp;
- }
-
- if (unlikely(!ppp_offload_match(ppp))) {
- pr_notice("ppp offload unmatched\n");
- ret = -EINVAL;
- goto restore_ppp;
- }
-
- /* l2tp */
- skb_push(skb, sizeof(struct udp_l2tp_data_hdr));
- l2tp = skb_header_pointer(skb, 0, sizeof(struct udp_l2tp_data_hdr), &l2tph);
- if (unlikely(!l2tp)) {
- ret = -EINVAL;
- goto restore_l2tp;
- }
-
- if (unlikely(!l2tpv2_offload_match(l2tp))) {
- ret = -EINVAL;
- goto restore_l2tp;
- }
-
- tnl_params->priv.l2tp.tid = l2tp->tid;
- tnl_params->priv.l2tp.sid = l2tp->sid;
-
- /* udp */
- skb_push(skb, sizeof(struct udphdr));
- udp = skb_header_pointer(skb, 0, sizeof(struct udphdr), &udph);
- if (unlikely(!udp)) {
- ret = -EINVAL;
- goto restore_udp;
- }
-
- if (unlikely(ntohs(udp->dest) != UDP_L2TP_PORT)) {
- pr_notice("udp port 0x%x unmatched\n", ntohs(udp->dest));
- ret = -EINVAL;
- goto restore_udp;
- }
-
- tnl_params->sport = udp->dest;
- tnl_params->dport = udp->source;
-
- /* ip */
- skb_push(skb, sizeof(struct iphdr));
- ip = skb_header_pointer(skb, 0, sizeof(struct iphdr), &iph);
- if (unlikely(!ip)) {
- ret = -EINVAL;
- goto restore_ip;
- }
-
- if (unlikely(ip->version != IPVERSION || ip->protocol != IPPROTO_UDP)) {
- pr_notice("ip: %p version or protocol unmatched, ver: 0x%x, proto: 0x%x\n",
- ip, ip->version, ip->protocol);
- ret = -EINVAL;
- goto restore_ip;
- }
-
- tnl_params->protocol = ip->protocol;
- tnl_params->sip = ip->daddr;
- tnl_params->dip = ip->saddr;
-
- /* eth */
- skb_push(skb, sizeof(struct ethhdr));
- eth = skb_header_pointer(skb, 0, sizeof(struct ethhdr), ðh);
- if (unlikely(!eth)) {
- ret = -EINVAL;
- goto restore_eth;
- }
-
- if (unlikely(ntohs(eth->h_proto) != ETH_P_IP)) {
- pr_notice("eth proto not supported, proto: 0x%x\n",
- ntohs(eth->h_proto));
- ret = -EINVAL;
- goto restore_eth;
- }
-
- memcpy(&tnl_params->saddr, eth->h_dest, sizeof(u8) * ETH_ALEN);
- memcpy(&tnl_params->daddr, eth->h_source, sizeof(u8) * ETH_ALEN);
-
-restore_eth:
- skb_pull(skb, sizeof(struct ethhdr));
-restore_ip:
- skb_pull(skb, sizeof(struct iphdr));
-restore_udp:
- skb_pull(skb, sizeof(struct udphdr));
-restore_l2tp:
- skb_pull(skb, sizeof(struct udp_l2tp_data_hdr));
-restore_ppp:
- skb_pull(skb, sizeof(struct ppp_hdr));
-
- return ret;
-}
-
-static int udp_l2tp_data_tnl_encap_param_setup(struct sk_buff *skb,
- struct tops_tnl_params *tnl_params)
-{
- struct ethhdr *eth = eth_hdr(skb);
- struct iphdr *ip = ip_hdr(skb);
- struct udp_l2tp_data_hdr *l2tp;
- struct udp_l2tp_data_hdr l2tph;
- struct udphdr *udp;
- struct udphdr udph;
- int ret = 0;
-
- if (unlikely(ip->version != IPVERSION || ip->protocol != IPPROTO_UDP)) {
- pr_notice("eth proto: 0x%x, ip ver: 0x%x, proto: 0x%x is not support\n",
- ntohs(eth->h_proto),
- ip->version,
- ip->protocol);
- ret = -EINVAL;
- goto out;
- }
-
- skb_pull(skb, sizeof(struct iphdr));
- udp = skb_header_pointer(skb, 0, sizeof(struct udphdr), &udph);
- if (unlikely(!udp)) {
- ret = -EINVAL;
- goto restore_ip;
- }
-
- if (unlikely(ntohs(udp->dest) != UDP_L2TP_PORT)) {
- pr_notice("udp port 0x%x unmatched\n", ntohs(udp->dest));
- ret = -EINVAL;
- goto restore_ip;
- }
-
- skb_pull(skb, sizeof(struct udphdr));
- l2tp = skb_header_pointer(skb, 0, sizeof(struct udp_l2tp_data_hdr), &l2tph);
- if (unlikely(!l2tp)) {
- ret = -EINVAL;
- goto restore_udp;
- }
-
- if (unlikely(!l2tpv2_offload_match(l2tp))) {
- ret = -EINVAL;
- goto restore_udp;
- }
-
- memcpy(&tnl_params->saddr, eth->h_source, sizeof(u8) * ETH_ALEN);
- memcpy(&tnl_params->daddr, eth->h_dest, sizeof(u8) * ETH_ALEN);
- tnl_params->protocol = ip->protocol;
- tnl_params->sip = ip->saddr;
- tnl_params->dip = ip->daddr;
- tnl_params->sport = udp->source;
- tnl_params->dport = udp->dest;
- tnl_params->priv.l2tp.tid = l2tp->tid;
- tnl_params->priv.l2tp.sid = l2tp->sid;
-
-restore_udp:
- skb_push(skb, sizeof(struct udphdr));
-restore_ip:
- skb_push(skb, sizeof(struct iphdr));
-out:
- return ret;
-}
-
-static int udp_l2tp_data_tnl_debug_param_setup(const char *buf, int *ofs,
- struct tops_tnl_params *tnl_params)
-{
- return -EPERM; //TODO: not implemented
-}
-
-static int udp_l2tp_data_tnl_l2_param_update(struct sk_buff *skb,
- struct tops_tnl_params *tnl_params)
-{
- struct ethhdr *eth = eth_hdr(skb);
-
- memcpy(&tnl_params->saddr, eth->h_source, sizeof(u8) * ETH_ALEN);
- memcpy(&tnl_params->daddr, eth->h_dest, sizeof(u8) * ETH_ALEN);
-
- return 1;
-}
-
-static bool udp_l2tp_data_tnl_info_match(struct tops_tnl_params *params1,
- struct tops_tnl_params *params2)
-{
- if (params1->sip == params2->sip
- && params1->dip == params2->dip
- && params1->sport == params2->sport
- && params1->dport == params2->dport
- && params1->priv.l2tp.tid == params2->priv.l2tp.tid
- && params1->priv.l2tp.sid == params2->priv.l2tp.sid)
- return true;
-
- return false;
-}
-
-static bool udp_l2tp_data_tnl_decap_offloadable(struct sk_buff *skb)
-{
- struct udp_l2tp_data_hdr *l2tp;
- struct udp_l2tp_data_hdr l2tph;
- struct ppp_hdr *ppp;
- struct ppp_hdr ppph;
- struct udphdr *udp;
- struct iphdr *ip;
-
- ip = ip_hdr(skb);
- if (ip->protocol != IPPROTO_UDP)
- return false;
-
- udp = udp_hdr(skb);
- if (ntohs(udp->dest) != UDP_L2TP_PORT)
- return false;
-
- l2tp = skb_header_pointer(skb, ip_hdr(skb)->ihl * 4 + sizeof(struct udphdr),
- sizeof(struct udp_l2tp_data_hdr), &l2tph);
-
- if (unlikely(!l2tp))
- return false;
-
- if (unlikely(!l2tpv2_offload_match(l2tp)))
- return false;
-
- ppp = skb_header_pointer(skb, (ip_hdr(skb)->ihl * 4 +
- sizeof(struct udphdr) +
- sizeof(struct udp_l2tp_data_hdr)),
- sizeof(struct ppp_hdr), &ppph);
-
- if (unlikely(!ppp))
- return false;
-
- if (unlikely(!ppp_offload_match(ppp)))
- return false;
-
- return true;
-}
-
-static struct tops_tnl_type udp_l2tp_data_type = {
- .type_name = "udp-l2tp-data",
- .cls_entry_setup = udp_l2tp_data_cls_entry_setup,
- .tnl_decap_param_setup = udp_l2tp_data_tnl_decap_param_setup,
- .tnl_encap_param_setup = udp_l2tp_data_tnl_encap_param_setup,
- .tnl_debug_param_setup = udp_l2tp_data_tnl_debug_param_setup,
- .tnl_l2_param_update = udp_l2tp_data_tnl_l2_param_update,
- .tnl_info_match = udp_l2tp_data_tnl_info_match,
- .tnl_decap_offloadable = udp_l2tp_data_tnl_decap_offloadable,
- .tops_entry = TOPS_ENTRY_UDP_L2TP_DATA,
- .has_inner_eth = false,
-};
-
-int mtk_tops_udp_l2tp_data_init(void)
-{
- return mtk_tops_tnl_type_register(&udp_l2tp_data_type);
-}
-
-void mtk_tops_udp_l2tp_data_deinit(void)
-{
- mtk_tops_tnl_type_unregister(&udp_l2tp_data_type);
-}
diff --git a/package-21.02/kernel/tops/src/protocol/tunnel/gre/gretap.c b/package-21.02/kernel/tops/src/protocol/tunnel/gre/gretap.c
index 13618ce..584367f 100644
--- a/package-21.02/kernel/tops/src/protocol/tunnel/gre/gretap.c
+++ b/package-21.02/kernel/tops/src/protocol/tunnel/gre/gretap.c
@@ -87,10 +87,20 @@
static bool gretap_tnl_decap_offloadable(struct sk_buff *skb)
{
struct iphdr *ip = ip_hdr(skb);
+ struct gre_base_hdr *pgre;
+ struct gre_base_hdr greh;
if (ip->protocol != IPPROTO_GRE)
return false;
+ pgre = skb_header_pointer(skb, ip_hdr(skb)->ihl * 4,
+ sizeof(struct gre_base_hdr), &greh);
+ if (unlikely(!pgre))
+ return false;
+
+ if (ntohs(pgre->protocol) != ETH_P_TEB)
+ return false;
+
return true;
}
diff --git a/package-21.02/kernel/tops/src/protocol/tunnel/l2tp/l2tpv2.c b/package-21.02/kernel/tops/src/protocol/tunnel/l2tp/l2tpv2.c
index d00d3c0..ac5a929 100644
--- a/package-21.02/kernel/tops/src/protocol/tunnel/l2tp/l2tpv2.c
+++ b/package-21.02/kernel/tops/src/protocol/tunnel/l2tp/l2tpv2.c
@@ -6,7 +6,11 @@
* Ren-Ting Wang <ren-ting.wang@mediatek.com>
*/
+#include <linux/if_pppox.h>
#include <linux/netdevice.h>
+#include <linux/ppp_channel.h>
+
+#include <l2tp_core.h>
#include <pce/cls.h>
#include <pce/netsys.h>
@@ -37,6 +41,48 @@
return 0;
}
+/* Helpers to obtain tunnel params from ppp netdev */
+static int l2tpv2_param_obtain_from_netdev(struct net_device *dev,
+ struct tops_params *params)
+{
+ struct tops_l2tp_params *l2tpp;
+ struct l2tp_session *session;
+ struct l2tp_tunnel *tunnel;
+ struct sock *sk;
+ int ret = 0;
+
+ if (!dev || !params)
+ return -EINVAL;
+
+ sk = ppp_netdev_get_sock(dev);
+ if (IS_ERR(sk) || !sk)
+ return -EINVAL;
+
+ sock_hold(sk);
+ session = (struct l2tp_session *)(sk->sk_user_data);
+ if (!session) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (session->magic != L2TP_SESSION_MAGIC) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ tunnel = session->tunnel;
+
+ l2tpp = ¶ms->tunnel.l2tp;
+ l2tpp->dl_tid = htons(tunnel->tunnel_id);
+ l2tpp->dl_sid = htons(session->session_id);
+ l2tpp->ul_tid = htons(tunnel->peer_tunnel_id);
+ l2tpp->ul_sid = htons(session->peer_session_id);
+out:
+ sock_put(sk);
+
+ return ret;
+}
+
static inline bool l2tpv2_offload_valid(struct sk_buff *skb)
{
struct udp_l2tp_data_hdr *l2tp;
@@ -56,9 +102,6 @@
static int l2tpv2_tnl_decap_param_setup(struct sk_buff *skb,
struct tops_params *params)
{
- struct tops_l2tp_params *l2tpp;
- struct udp_l2tp_data_hdr *l2tp;
- struct udp_l2tp_data_hdr l2tph;
int ret = 0;
/* ppp */
@@ -75,17 +118,11 @@
goto restore_l2tp;
}
- l2tp = skb_header_pointer(skb, 0, sizeof(struct udp_l2tp_data_hdr), &l2tph);
- if (unlikely(!l2tp)) {
- ret = -EINVAL;
- goto restore_l2tp;
- }
-
params->tunnel.type = TOPS_TUNNEL_L2TP_V2;
- l2tpp = ¶ms->tunnel.l2tp;
- l2tpp->tid = l2tp->tid;
- l2tpp->sid = l2tp->sid;
+ ret = l2tpv2_param_obtain_from_netdev(skb->dev, params);
+ if (ret)
+ goto restore_l2tp;
ret = mtk_tops_transport_decap_param_setup(skb, params);
@@ -115,8 +152,8 @@
params->tunnel.type = TOPS_TUNNEL_L2TP_V2;
l2tpp = ¶ms->tunnel.l2tp;
- l2tpp->tid = l2tp->tid;
- l2tpp->sid = l2tp->sid;
+ l2tpp->ul_tid = l2tp->tid;
+ l2tpp->ul_sid = l2tp->sid;
return 0;
}
@@ -125,20 +162,25 @@
struct tops_params *params)
{
struct tops_l2tp_params *l2tpp;
+ u16 ul_tid = 0;
+ u16 ul_sid = 0;
+ u16 dl_tid = 0;
+ u16 dl_sid = 0;
int nchar = 0;
int ret;
- u16 tid = 0;
- u16 sid = 0;
params->tunnel.type = TOPS_TUNNEL_L2TP_V2;
l2tpp = ¶ms->tunnel.l2tp;
- ret = sscanf(buf + *ofs, "%hu %hu %n", &tid, &sid, &nchar);
+ ret = sscanf(buf + *ofs, "%hu %hu %hu %hu %n",
+ &ul_tid, &ul_sid, &dl_tid, &dl_sid, &nchar);
if (ret != 2)
return -EINVAL;
- l2tpp->tid = htons(tid);
- l2tpp->sid = htons(sid);
+ l2tpp->ul_tid = htons(ul_tid);
+ l2tpp->ul_sid = htons(ul_sid);
+ l2tpp->dl_tid = htons(dl_tid);
+ l2tpp->dl_sid = htons(dl_sid);
*ofs += nchar;
@@ -189,13 +231,39 @@
return ret;
}
+static void l2tpv2_tnl_param_restore(struct tops_params *old, struct tops_params *new)
+{
+ /* dl_tid and dl_sid are assigned at decap */
+ if (old->tunnel.l2tp.dl_tid)
+ new->tunnel.l2tp.dl_tid = old->tunnel.l2tp.dl_tid;
+ if (old->tunnel.l2tp.dl_sid)
+ new->tunnel.l2tp.dl_sid = old->tunnel.l2tp.dl_sid;
+
+ if (old->tunnel.l2tp.ul_tid)
+ new->tunnel.l2tp.ul_tid = old->tunnel.l2tp.ul_tid;
+ if (old->tunnel.l2tp.ul_sid)
+ new->tunnel.l2tp.ul_sid = old->tunnel.l2tp.ul_sid;
+}
+
+static bool l2tpv2_tnl_param_match(struct tops_params *p, struct tops_params *target)
+{
+ /*
+ * Only UL params are guaranteed to be valid for comparison, DL params
+ * may be left empty if no DL traffic had passed yet.
+ */
+ return (p->tunnel.l2tp.ul_tid == target->tunnel.l2tp.ul_tid)
+ && (p->tunnel.l2tp.ul_sid == target->tunnel.l2tp.ul_sid);
+}
+
static void l2tpv2_tnl_param_dump(struct seq_file *s, struct tops_params *params)
{
struct tops_l2tp_params *l2tpp = ¶ms->tunnel.l2tp;
seq_puts(s, "\tTunnel Type: L2TPv2 ");
- seq_printf(s, "tunnel ID: %05u session ID: %05u\n",
- ntohs(l2tpp->tid), ntohs(l2tpp->sid));
+ seq_printf(s, "DL tunnel ID: %05u DL session ID: %05u ",
+ ntohs(l2tpp->dl_tid), ntohs(l2tpp->dl_sid));
+ seq_printf(s, "UL tunnel ID: %05u UL session ID: %05u\n",
+ ntohs(l2tpp->ul_tid), ntohs(l2tpp->ul_sid));
}
static struct tops_tnl_type l2tpv2_type = {
@@ -206,6 +274,8 @@
.tnl_debug_param_setup = l2tpv2_tnl_debug_param_setup,
.tnl_decap_offloadable = l2tpv2_tnl_decap_offloadable,
.tnl_l2_param_update = l2tpv2_tnl_l2_param_update,
+ .tnl_param_restore = l2tpv2_tnl_param_restore,
+ .tnl_param_match = l2tpv2_tnl_param_match,
.tnl_param_dump = l2tpv2_tnl_param_dump,
.tnl_proto_type = TOPS_TUNNEL_L2TP_V2,
.has_inner_eth = false,
diff --git a/package-21.02/kernel/tops/src/protocol/tunnel/pptp/pptp.c b/package-21.02/kernel/tops/src/protocol/tunnel/pptp/pptp.c
new file mode 100644
index 0000000..8bc46fe
--- /dev/null
+++ b/package-21.02/kernel/tops/src/protocol/tunnel/pptp/pptp.c
@@ -0,0 +1,371 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2023 MediaTek Inc. All Rights Reserved.
+ *
+ * Author: Frank-zj Lin <frank-zj.lin@mediatek.com>
+ */
+
+#include <linux/if_pppox.h>
+#include <linux/ppp_channel.h>
+
+#include <net/gre.h>
+#include <net/pptp.h>
+#include <net/sock.h>
+
+#include <pce/cls.h>
+#include <pce/netsys.h>
+#include <pce/pce.h>
+
+#include "tops/protocol/mac/ppp.h"
+#include "tops/protocol/tunnel/pptp/pptp.h"
+#include "tops/seq_gen.h"
+#include "tops/tunnel.h"
+
+static int pptp_cls_entry_setup(struct tops_tnl_info *tnl_info,
+ struct cls_desc *cdesc)
+{
+ CLS_DESC_DATA(cdesc, fport, PSE_PORT_PPE0);
+ CLS_DESC_DATA(cdesc, tport_idx, 0x4);
+ CLS_DESC_MASK_DATA(cdesc, tag, CLS_DESC_TAG_MASK, CLS_DESC_TAG_MATCH_L4_HDR);
+ CLS_DESC_MASK_DATA(cdesc, dip_match, CLS_DESC_DIP_MATCH, CLS_DESC_DIP_MATCH);
+ CLS_DESC_MASK_DATA(cdesc, l4_type, CLS_DESC_L4_TYPE_MASK, IPPROTO_GRE);
+ CLS_DESC_MASK_DATA(cdesc, l4_udp_hdr_nez,
+ CLS_DESC_UDPLITE_L4_HDR_NEZ_MASK,
+ CLS_DESC_UDPLITE_L4_HDR_NEZ_MASK);
+ CLS_DESC_MASK_DATA(cdesc, l4_valid,
+ CLS_DESC_L4_VALID_MASK,
+ CLS_DESC_VALID_UPPER_HALF_WORD_BIT |
+ CLS_DESC_VALID_LOWER_HALF_WORD_BIT);
+ CLS_DESC_MASK_DATA(cdesc, l4_hdr_usr_data, 0x0000FFFF, 0x0000880B);
+
+ return 0;
+}
+
+/*
+ * If a sequence generator is already allocated for this tunnel (call_id),
+ * return with seq_gen_idx set. Otherwise, allocate a new sequence generator
+ * and set the starting sequence number.
+ */
+static int pptp_get_seq_gen_idx(uint16_t call_id, uint32_t seq_start,
+ int *seq_gen_idx)
+{
+ int ret;
+
+ ret = mtk_tops_pptp_seq_get_seq_gen_idx(call_id, seq_gen_idx);
+ if (ret)
+ ret = mtk_tops_pptp_seq_alloc(call_id, seq_start, seq_gen_idx);
+
+ return ret;
+}
+
+static inline bool pptp_gre_offload_valid(struct sk_buff *skb)
+{
+ struct pptp_gre_header *pptp_gre;
+ struct pptp_gre_header pptp_greh;
+
+ pptp_gre = skb_header_pointer(skb, 0, sizeof(struct pptp_gre_header), &pptp_greh);
+ if (unlikely(!pptp_gre))
+ return false;
+
+ if (pptp_gre->gre_hd.protocol != GRE_PROTO_PPP
+ || pptp_gre->payload_len < sizeof(struct ppp_hdr)
+ || GRE_IS_CSUM(pptp_gre->gre_hd.flags) /* flag CSUM should be clear */
+ || GRE_IS_ROUTING(pptp_gre->gre_hd.flags) /* flag ROUTING should be clear */
+ || !GRE_IS_KEY(pptp_gre->gre_hd.flags) /* flag KEY should be set */
+ || pptp_gre->gre_hd.flags & GRE_FLAGS) /* flag Recursion Ctrl should be clear */
+ return false;
+
+ return true;
+}
+
+static inline int pptp_gre_len_evaluate(struct sk_buff *skb)
+{
+ static const int possible_greh_len[] = {
+ sizeof(struct pptp_gre_header) - PPTP_GRE_HDR_ACK_LEN,
+ sizeof(struct pptp_gre_header),
+ };
+ struct pptp_gre_header *pptp_gre;
+ int pptp_gre_len;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(possible_greh_len); i++) {
+ pptp_gre_len = possible_greh_len[i];
+
+ skb_push(skb, pptp_gre_len);
+ pptp_gre = (struct pptp_gre_header *)skb->data;
+ skb_pull(skb, pptp_gre_len);
+
+ if (pptp_gre->gre_hd.protocol == GRE_PROTO_PPP)
+ return pptp_gre_len;
+ }
+
+ return -EINVAL;
+}
+
+static int pptp_tnl_decap_param_setup(struct sk_buff *skb,
+ struct tops_params *params)
+{
+ struct pptp_gre_header *pptp_gre;
+ struct pptp_gre_header pptp_greh;
+ struct tops_pptp_params *pptpp;
+ struct sock *sk;
+ int pptp_gre_len;
+ int ret = 0;
+
+ /* ppp */
+ skb_push(skb, sizeof(struct ppp_hdr));
+ if (unlikely(!mtk_tops_ppp_valid(skb))) {
+ ret = -EINVAL;
+ goto restore_ppp;
+ }
+
+ /* pptp_gre */
+ pptp_gre_len = pptp_gre_len_evaluate(skb);
+ if (pptp_gre_len < 0) {
+ ret = -EINVAL;
+ goto restore_ppp;
+ }
+
+ skb_push(skb, pptp_gre_len);
+ pptp_gre = skb_header_pointer(skb, 0, pptp_gre_len, &pptp_greh);
+ if (unlikely(!pptp_gre)) {
+ ret = -EINVAL;
+ goto restore_pptp_gre;
+ }
+
+ if (unlikely(!pptp_gre_offload_valid(skb))) {
+ ret = -EINVAL;
+ goto restore_pptp_gre;
+ }
+
+ /*
+ * In decap setup, dl_call_id is fetched from the skb and ul_call_id is
+ * fetched from socket struct of ppp device.
+ */
+ sk = ppp_netdev_get_sock(skb->dev);
+ if (IS_ERR(sk)) {
+ ret = PTR_ERR(sk);
+ goto restore_pptp_gre;
+ }
+
+ params->tunnel.type = TOPS_TUNNEL_PPTP;
+ pptpp = ¶ms->tunnel.pptp;
+ pptpp->dl_call_id = pptp_gre->call_id;
+ pptpp->ul_call_id = htons(pppox_sk(sk)->proto.pptp.dst_addr.call_id);
+
+ ret = mtk_tops_network_decap_param_setup(skb, params);
+
+restore_pptp_gre:
+ skb_pull(skb, pptp_gre_len);
+
+restore_ppp:
+ skb_pull(skb, sizeof(struct ppp_hdr));
+
+ return ret;
+}
+
+static int pptp_tnl_encap_param_setup(struct sk_buff *skb,
+ struct tops_params *params)
+{
+ struct pptp_gre_header *pptp_gre;
+ struct pptp_gre_header pptp_greh;
+ struct tops_pptp_params *pptpp;
+ uint32_t pptp_gre_len;
+ int seq_gen_idx;
+ int ret = 0;
+
+ if (unlikely(!pptp_gre_offload_valid(skb)))
+ return -EINVAL;
+
+ pptp_gre = skb_header_pointer(skb, 0, sizeof(struct pptp_gre_header), &pptp_greh);
+ if (unlikely(!pptp_gre))
+ return -EINVAL;
+
+ pptp_gre_len = sizeof(*pptp_gre);
+ if (!(GRE_IS_ACK(pptp_gre->gre_hd.flags)))
+ pptp_gre_len -= sizeof(pptp_gre->ack);
+
+ skb_pull(skb, pptp_gre_len);
+
+ /* check ppp */
+ if (unlikely(!mtk_tops_ppp_valid(skb))) {
+ ret = -EINVAL;
+ goto restore_pptp_gre;
+ }
+
+ ret = pptp_get_seq_gen_idx(ntohs(pptp_gre->call_id),
+ ntohl(pptp_gre->seq), &seq_gen_idx);
+ if (ret)
+ goto restore_pptp_gre;
+
+ params->tunnel.type = TOPS_TUNNEL_PPTP;
+ pptpp = ¶ms->tunnel.pptp;
+ pptpp->seq_gen_idx = (u8)seq_gen_idx;
+ pptpp->ul_call_id = pptp_gre->call_id;
+
+restore_pptp_gre:
+ skb_push(skb, pptp_gre_len);
+
+ return ret;
+}
+
+static int pptp_debug_param_fetch_call_id(const char *buf, int *ofs, u16 *call_id)
+{
+ int nchar = 0;
+ int ret;
+ u16 c = 0;
+
+ ret = sscanf(buf + *ofs, "%hu %n", &c, &nchar);
+ if (ret != 1)
+ return -EPERM;
+
+ *call_id = htons(c);
+
+ *ofs += nchar;
+
+ return 0;
+}
+
+static int pptp_tnl_debug_param_setup(const char *buf, int *ofs,
+ struct tops_params *params)
+{
+ struct tops_pptp_params *pptpp;
+ int seq_gen_idx;
+ int ret;
+
+ pptpp = ¶ms->tunnel.pptp;
+
+ ret = pptp_debug_param_fetch_call_id(buf, ofs, &pptpp->ul_call_id);
+ if (ret)
+ return ret;
+
+ ret = pptp_debug_param_fetch_call_id(buf, ofs, &pptpp->dl_call_id);
+ if (ret)
+ return ret;
+
+ ret = pptp_get_seq_gen_idx(ntohs(pptpp->ul_call_id), 0, &seq_gen_idx);
+ if (ret)
+ return ret;
+
+ pptpp->seq_gen_idx = (u8)seq_gen_idx;
+
+ return 0;
+}
+
+static bool pptp_tnl_decap_offloadable(struct sk_buff *skb)
+{
+ struct pptp_gre_header *pptp_gre;
+ struct pptp_gre_header pptp_greh;
+ struct iphdr *ip;
+ int pptp_gre_len;
+ int ip_len;
+ bool ret = true;
+
+ /* check ip */
+ ip = ip_hdr(skb);
+ if (ip->protocol != IPPROTO_GRE)
+ return false;
+
+ ip_len = ip_hdr(skb)->ihl * 4;
+
+ skb_pull(skb, ip_len);
+
+ /* check gre */
+ if (!pptp_gre_offload_valid(skb)) {
+ ret = false;
+ goto restore_ip;
+ }
+
+ pptp_gre = skb_header_pointer(skb, 0, sizeof(struct pptp_gre_header), &pptp_greh);
+ if (unlikely(!pptp_gre)) {
+ ret = false;
+ goto restore_ip;
+ }
+
+ pptp_gre_len = sizeof(*pptp_gre);
+ if (!(GRE_IS_ACK(pptp_gre->gre_hd.flags)))
+ pptp_gre_len -= sizeof(pptp_gre->ack);
+
+ skb_pull(skb, pptp_gre_len);
+
+ /* check ppp */
+ if (unlikely(!mtk_tops_ppp_valid(skb))) {
+ ret = false;
+ goto restore_pptp_gre;
+ }
+
+restore_pptp_gre:
+ skb_push(skb, pptp_gre_len);
+
+restore_ip:
+ skb_push(skb, ip_len);
+
+ return ret;
+}
+
+static void pptp_tnl_param_restore(struct tops_params *old, struct tops_params *new)
+{
+ /* dl_call_id is assigned at decap */
+ if (old->tunnel.pptp.dl_call_id)
+ new->tunnel.pptp.dl_call_id = old->tunnel.pptp.dl_call_id;
+
+ if (old->tunnel.pptp.ul_call_id)
+ new->tunnel.pptp.ul_call_id = old->tunnel.pptp.ul_call_id;
+
+ /* seq_gen_idx is assigned at encap */
+ if (old->tunnel.pptp.seq_gen_idx)
+ new->tunnel.pptp.seq_gen_idx = old->tunnel.pptp.seq_gen_idx;
+}
+
+static bool pptp_tnl_param_match(struct tops_params *p, struct tops_params *target)
+{
+ /*
+ * Only ul_call_id is guaranteed to be valid for comparison, dl_call_id
+ * may be left empty if no DL traffic had passed yet.
+ */
+ return p->tunnel.pptp.ul_call_id == target->tunnel.pptp.ul_call_id;
+}
+
+static void pptp_tnl_param_dump(struct seq_file *s, struct tops_params *params)
+{
+ struct tops_pptp_params *pptpp = ¶ms->tunnel.pptp;
+
+ seq_puts(s, "\tTunnel Type: PPTP ");
+ seq_printf(s, "DL Call ID: %05u UL Call ID: %05u SEQ_GEN_IDX: %05u\n",
+ ntohs(pptpp->dl_call_id), ntohs(pptpp->ul_call_id),
+ pptpp->seq_gen_idx);
+}
+
+static struct tops_tnl_type pptp_type = {
+ .type_name = "pptp",
+ .cls_entry_setup = pptp_cls_entry_setup,
+ .tnl_decap_param_setup = pptp_tnl_decap_param_setup,
+ .tnl_encap_param_setup = pptp_tnl_encap_param_setup,
+ .tnl_debug_param_setup = pptp_tnl_debug_param_setup,
+ .tnl_decap_offloadable = pptp_tnl_decap_offloadable,
+ .tnl_param_restore = pptp_tnl_param_restore,
+ .tnl_param_match = pptp_tnl_param_match,
+ .tnl_param_dump = pptp_tnl_param_dump,
+ .tnl_proto_type = TOPS_TUNNEL_PPTP,
+ .has_inner_eth = false,
+};
+
+int mtk_tops_pptp_init(void)
+{
+ int ret = 0;
+
+ ret = mtk_tops_tnl_type_register(&pptp_type);
+ if (ret)
+ return ret;
+
+ mtk_tops_pptp_seq_init();
+
+ return ret;
+}
+
+void mtk_tops_pptp_deinit(void)
+{
+ mtk_tops_pptp_seq_deinit();
+
+ mtk_tops_tnl_type_unregister(&pptp_type);
+}
diff --git a/package-21.02/kernel/tops/src/protocol/tunnel/pptp/pptp_seq.c b/package-21.02/kernel/tops/src/protocol/tunnel/pptp/pptp_seq.c
new file mode 100644
index 0000000..ff61cc8
--- /dev/null
+++ b/package-21.02/kernel/tops/src/protocol/tunnel/pptp/pptp_seq.c
@@ -0,0 +1,174 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2023 MediaTek Inc. All Rights Reserved.
+ *
+ * Author: Frank-zj Lin <frank-zj.lin@mediatek.com>
+ */
+
+#include <linux/hashtable.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+
+#include <net/pptp.h>
+
+#include "tops/hwspinlock.h"
+#include "tops/seq_gen.h"
+
+#define PPTP_SEQ_HT_BITS 4
+
+struct pptp_seq {
+ struct hlist_node hlist;
+ int seq_gen_idx;
+ uint16_t call_id;
+};
+
+static DEFINE_HASHTABLE(pptp_seq_ht, PPTP_SEQ_HT_BITS);
+static DEFINE_SPINLOCK(pptp_seq_ht_lock);
+
+static struct pptp_seq *mtk_tops_pptp_seq_find_no_lock(uint16_t call_id)
+{
+ struct pptp_seq *pptp_seq;
+
+ hash_for_each_possible(pptp_seq_ht, pptp_seq, hlist, call_id) {
+ if (pptp_seq->call_id == call_id)
+ return pptp_seq;
+ }
+
+ return ERR_PTR(-ENODEV);
+}
+
+static int mtk_tops_pptp_seq_alloc_no_lock(uint16_t call_id, uint32_t seq_start,
+ int *seq_gen_idx)
+{
+ struct pptp_seq *pptp_seq;
+ int ret;
+
+ if (!IS_ERR(mtk_tops_pptp_seq_find_no_lock(call_id)))
+ return -EBUSY;
+
+ ret = mtk_tops_seq_gen_alloc(seq_gen_idx);
+ if (ret)
+ return ret;
+
+ pptp_seq = kzalloc(sizeof(struct pptp_seq), GFP_KERNEL);
+ if (!pptp_seq) {
+ mtk_tops_seq_gen_free(*seq_gen_idx);
+ return -ENOMEM;
+ }
+
+ pptp_seq->seq_gen_idx = *seq_gen_idx;
+ pptp_seq->call_id = call_id;
+ hash_add(pptp_seq_ht, &pptp_seq->hlist, pptp_seq->call_id);
+
+ mtk_tops_seq_gen_set_32(*seq_gen_idx, seq_start);
+
+ return 0;
+}
+
+int mtk_tops_pptp_seq_alloc(uint16_t call_id, uint32_t seq_start,
+ int *seq_gen_idx)
+{
+ unsigned long flag;
+ int ret;
+
+ spin_lock_irqsave(&pptp_seq_ht_lock, flag);
+
+ ret = mtk_tops_pptp_seq_alloc_no_lock(call_id, seq_start, seq_gen_idx);
+
+ spin_unlock_irqrestore(&pptp_seq_ht_lock, flag);
+
+ return ret;
+}
+
+static void mtk_tops_pptp_seq_free_no_lock(uint16_t call_id)
+{
+ struct pptp_seq *pptp_seq;
+
+ pptp_seq = mtk_tops_pptp_seq_find_no_lock(call_id);
+ if (IS_ERR(pptp_seq))
+ return;
+
+ mtk_tops_seq_gen_free(pptp_seq->seq_gen_idx);
+ hash_del(&pptp_seq->hlist);
+ kfree(pptp_seq);
+}
+
+void mtk_tops_pptp_seq_free(uint16_t call_id)
+{
+ unsigned long flag;
+
+ spin_lock_irqsave(&pptp_seq_ht_lock, flag);
+
+ mtk_tops_pptp_seq_free_no_lock(call_id);
+
+ spin_unlock_irqrestore(&pptp_seq_ht_lock, flag);
+}
+
+static int mtk_tops_pptp_seq_next_no_lock(uint16_t call_id, uint32_t *val)
+{
+ struct pptp_seq *pptp_seq;
+
+ pptp_seq = mtk_tops_pptp_seq_find_no_lock(call_id);
+ if (IS_ERR(pptp_seq))
+ return -EINVAL;
+
+ return mtk_tops_seq_gen_next_32(pptp_seq->seq_gen_idx, val);
+}
+
+static int mtk_tops_pptp_seq_next(uint16_t call_id, uint32_t *val)
+{
+ unsigned long flag;
+ int ret;
+
+ spin_lock_irqsave(&pptp_seq_ht_lock, flag);
+
+ mtk_tops_hwspin_lock(HWSPINLOCK_GROUP_CLUST,
+ HWSPINLOCK_CLUST_SLOT_PPTP_SEQ);
+
+ ret = mtk_tops_pptp_seq_next_no_lock(call_id, val);
+
+ mtk_tops_hwspin_unlock(HWSPINLOCK_GROUP_CLUST,
+ HWSPINLOCK_CLUST_SLOT_PPTP_SEQ);
+
+ spin_unlock_irqrestore(&pptp_seq_ht_lock, flag);
+
+ return ret;
+}
+
+static int mtk_tops_pptp_seq_get_seq_gen_idx_no_lock(uint16_t call_id,
+ int *seq_gen_idx)
+{
+ struct pptp_seq *pptp_seq;
+
+ pptp_seq = mtk_tops_pptp_seq_find_no_lock(call_id);
+ if (IS_ERR(pptp_seq))
+ return -EINVAL;
+
+ *seq_gen_idx = pptp_seq->seq_gen_idx;
+
+ return 0;
+}
+
+int mtk_tops_pptp_seq_get_seq_gen_idx(uint16_t call_id, int *seq_gen_idx)
+{
+ unsigned long flag;
+ int ret;
+
+ spin_lock_irqsave(&pptp_seq_ht_lock, flag);
+
+ ret = mtk_tops_pptp_seq_get_seq_gen_idx_no_lock(call_id, seq_gen_idx);
+
+ spin_unlock_irqrestore(&pptp_seq_ht_lock, flag);
+
+ return ret;
+}
+
+void mtk_tops_pptp_seq_init(void)
+{
+ mtk_pptp_seq_next = mtk_tops_pptp_seq_next;
+}
+
+void mtk_tops_pptp_seq_deinit(void)
+{
+ mtk_pptp_seq_next = NULL;
+}
diff --git a/package-21.02/kernel/tops/src/seq_gen.c b/package-21.02/kernel/tops/src/seq_gen.c
new file mode 100644
index 0000000..b9ac9e5
--- /dev/null
+++ b/package-21.02/kernel/tops/src/seq_gen.c
@@ -0,0 +1,219 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2023 MediaTek Inc. All Rights Reserved.
+ *
+ * Author: Frank-zj Lin <frank-zj.lin@mediatek.com>
+ */
+
+#include <linux/io.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+
+#include "tops/internal.h"
+#include "tops/seq_gen.h"
+
+#define SEQ_GEN_L(idx) (TOPS_SEQ_GEN_BASE + (idx) * 0x20)
+#define SEQ_GEN_H(idx) (TOPS_SEQ_GEN_BASE + (idx) * 0x20 + 0x10)
+
+static void __iomem *base;
+
+static DECLARE_BITMAP(seq_gen_used, TOPS_SEQ_GEN_IDX_MAX);
+static DEFINE_SPINLOCK(seq_gen_used_lock);
+
+static inline u32 seq_gen_read(u32 reg)
+{
+ return readl(base + reg);
+}
+
+static inline void seq_gen_write(u32 reg, u32 val)
+{
+ writel(val, base + reg);
+}
+
+static inline int seq_gen_read_16(u32 seq_gen_idx, u16 *val)
+{
+ if (seq_gen_idx >= TOPS_SEQ_GEN_IDX_MAX)
+ return -EINVAL;
+
+ *val = (u16)seq_gen_read(SEQ_GEN_L(seq_gen_idx));
+
+ return 0;
+}
+
+static inline void seq_gen_write_16(u32 seq_gen_idx, u16 val)
+{
+ if (seq_gen_idx >= TOPS_SEQ_GEN_IDX_MAX)
+ return;
+
+ seq_gen_write(SEQ_GEN_L(seq_gen_idx), (u32)val);
+}
+
+static inline int seq_gen_read_32(u32 seq_gen_idx, u32 *val)
+{
+ u32 val_h, val_l;
+
+ if (seq_gen_idx >= TOPS_SEQ_GEN_IDX_MAX)
+ return -EINVAL;
+
+ val_l = seq_gen_read(SEQ_GEN_L(seq_gen_idx));
+ val_h = seq_gen_read(SEQ_GEN_H(seq_gen_idx));
+
+ if (val_l != 0xFFFF)
+ seq_gen_write(SEQ_GEN_H(seq_gen_idx), val_h);
+
+ *val = (val_h << 16) | val_l;
+
+ return 0;
+}
+
+static inline void seq_gen_write_32(u32 seq_gen_idx, u32 val)
+{
+ if (seq_gen_idx >= TOPS_SEQ_GEN_IDX_MAX)
+ return;
+
+ seq_gen_write(SEQ_GEN_L(seq_gen_idx), (val & 0xFFFF));
+ seq_gen_write(SEQ_GEN_H(seq_gen_idx), (val >> 16));
+}
+
+static void mtk_tops_seq_gen_set_16_no_lock(int seq_gen_idx, u16 val)
+{
+ if (unlikely(!test_bit(seq_gen_idx, seq_gen_used)))
+ return;
+
+ seq_gen_write_16(seq_gen_idx, val);
+}
+
+static void mtk_tops_seq_gen_set_32_no_lock(int seq_gen_idx, u32 val)
+{
+ if (unlikely(!test_bit(seq_gen_idx, seq_gen_used)))
+ return;
+
+ seq_gen_write_32(seq_gen_idx, val);
+}
+
+static int mtk_tops_seq_gen_next_16_no_lock(int seq_gen_idx, u16 *val)
+{
+ if (unlikely(!val || !test_bit(seq_gen_idx, seq_gen_used)))
+ return -EINVAL;
+
+ return seq_gen_read_16(seq_gen_idx, val);
+}
+
+static int mtk_tops_seq_gen_next_32_no_lock(int seq_gen_idx, u32 *val)
+{
+ if (unlikely(!val || !test_bit(seq_gen_idx, seq_gen_used)))
+ return -EINVAL;
+
+ return seq_gen_read_32(seq_gen_idx, val);
+}
+
+void mtk_tops_seq_gen_set_16(int seq_gen_idx, u16 val)
+{
+ unsigned long flag;
+
+ spin_lock_irqsave(&seq_gen_used_lock, flag);
+
+ mtk_tops_seq_gen_set_16_no_lock(seq_gen_idx, val);
+
+ spin_unlock_irqrestore(&seq_gen_used_lock, flag);
+}
+
+int mtk_tops_seq_gen_next_16(int seq_gen_idx, u16 *val)
+{
+ unsigned long flag;
+ int ret;
+
+ spin_lock_irqsave(&seq_gen_used_lock, flag);
+
+ ret = mtk_tops_seq_gen_next_16_no_lock(seq_gen_idx, val);
+
+ spin_unlock_irqrestore(&seq_gen_used_lock, flag);
+
+ return ret;
+}
+
+void mtk_tops_seq_gen_set_32(int seq_gen_idx, u32 val)
+{
+ unsigned long flag;
+
+ spin_lock_irqsave(&seq_gen_used_lock, flag);
+
+ mtk_tops_seq_gen_set_32_no_lock(seq_gen_idx, val);
+
+ spin_unlock_irqrestore(&seq_gen_used_lock, flag);
+}
+
+int mtk_tops_seq_gen_next_32(int seq_gen_idx, u32 *val)
+{
+ unsigned long flag;
+ int ret;
+
+ spin_lock_irqsave(&seq_gen_used_lock, flag);
+
+ ret = mtk_tops_seq_gen_next_32_no_lock(seq_gen_idx, val);
+
+ spin_unlock_irqrestore(&seq_gen_used_lock, flag);
+
+ return ret;
+}
+
+static int mtk_tops_seq_gen_alloc_no_lock(int *seq_gen_idx)
+{
+ if (!seq_gen_idx)
+ return -EINVAL;
+
+ *seq_gen_idx = find_first_zero_bit(seq_gen_used, TOPS_SEQ_GEN_IDX_MAX);
+ if (*seq_gen_idx == TOPS_SEQ_GEN_IDX_MAX) {
+ TOPS_NOTICE("Sequence generator exhausted\n");
+ return -ENOMEM;
+ }
+
+ set_bit(*seq_gen_idx, seq_gen_used);
+
+ return 0;
+}
+
+int mtk_tops_seq_gen_alloc(int *seq_gen_idx)
+{
+ unsigned long flag;
+ int ret;
+
+ spin_lock_irqsave(&seq_gen_used_lock, flag);
+
+ ret = mtk_tops_seq_gen_alloc_no_lock(seq_gen_idx);
+
+ spin_unlock_irqrestore(&seq_gen_used_lock, flag);
+
+ return ret;
+}
+
+static void mtk_tops_seq_gen_free_no_lock(int seq_gen_idx)
+{
+ clear_bit(seq_gen_idx, seq_gen_used);
+}
+
+void mtk_tops_seq_gen_free(int seq_gen_idx)
+{
+ unsigned long flag = 0;
+
+ spin_lock_irqsave(&seq_gen_used_lock, flag);
+
+ mtk_tops_seq_gen_free_no_lock(seq_gen_idx);
+
+ spin_unlock_irqrestore(&seq_gen_used_lock, flag);
+}
+
+int mtk_tops_seq_gen_init(struct platform_device *pdev)
+{
+ struct resource *res;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "tops-base");
+ if (!res)
+ return -ENXIO;
+
+ base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+ if (!base)
+ return -ENOMEM;
+
+ return 0;
+}
diff --git a/package-21.02/kernel/tops/src/tnl_offload.c b/package-21.02/kernel/tops/src/tnl_offload.c
index 714139b..bc3057d 100644
--- a/package-21.02/kernel/tops/src/tnl_offload.c
+++ b/package-21.02/kernel/tops/src/tnl_offload.c
@@ -34,6 +34,7 @@
#include "tops/netsys.h"
#include "tops/protocol/tunnel/gre/gretap.h"
#include "tops/protocol/tunnel/l2tp/l2tpv2.h"
+#include "tops/protocol/tunnel/pptp/pptp.h"
#include "tops/tunnel.h"
#define TOPS_PPE_ENTRY_BUCKETS (64)
@@ -1707,14 +1708,18 @@
mtk_tops_l2tpv2_init();
+ mtk_tops_pptp_init();
+
return 0;
}
void mtk_tops_tnl_offload_proto_teardown(struct platform_device *pdev)
{
- mtk_tops_gretap_deinit();
+ mtk_tops_pptp_deinit();
mtk_tops_l2tpv2_deinit();
+
+ mtk_tops_gretap_deinit();
}
struct tops_tnl_type *mtk_tops_tnl_type_get_by_name(const char *name)
diff --git a/package-21.02/kernel/tops/tops.mk b/package-21.02/kernel/tops/tops.mk
index 09d2a98..e8ccd39 100644
--- a/package-21.02/kernel/tops/tops.mk
+++ b/package-21.02/kernel/tops/tops.mk
@@ -10,6 +10,7 @@
CONFIG_MTK_TOPS_GRETAP=$(CONFIG_MTK_TOPS_GRETAP) \
CONFIG_MTK_TOPS_L2TP=$(CONFIG_MTK_TOPS_L2TP) \
CONFIG_MTK_TOPS_L2TP_V2=$(CONFIG_MTK_TOPS_L2TP_V2) \
+ CONFIG_MTK_TOPS_PPTP=$(CONFIG_MTK_TOPS_PPTP) \
CONFIG_MTK_TOPS_SECURE_FW=$(CONFIG_MTK_TOPS_SECURE_FW)
EXTRA_CFLAGS+= \
@@ -19,6 +20,7 @@
EXTRA_CFLAGS+= \
-I$(LINUX_DIR)/drivers/net/ethernet/mediatek/ \
-I$(LINUX_DIR)/drivers/dma/ \
+ -I$(LINUX_DIR)/net/l2tp/ \
-I$(KERNEL_BUILD_DIR)/pce/inc/ \
-DCONFIG_TOPS_TNL_NUM=$(CONFIG_TOPS_TNL_NUM) \
-DCONFIG_TOPS_TNL_MAP_BIT=$(CONFIG_TOPS_TNL_MAP_BIT) \
diff --git a/target/linux/mediatek/patches-5.4/999-4500-mtk-ppp-offload-support.patch b/target/linux/mediatek/patches-5.4/999-4500-mtk-ppp-offload-support.patch
new file mode 100644
index 0000000..1409f9f
--- /dev/null
+++ b/target/linux/mediatek/patches-5.4/999-4500-mtk-ppp-offload-support.patch
@@ -0,0 +1,65 @@
+--- a/drivers/net/ppp/ppp_generic.c
++++ b/drivers/net/ppp/ppp_generic.c
+@@ -296,6 +296,9 @@ static void unit_put(struct idr *p, int
+ static void *unit_find(struct idr *p, int n);
+ static void ppp_setup(struct net_device *dev);
+
++struct sock *ppp_netdev_get_sock(struct net_device *dev);
++EXPORT_SYMBOL(ppp_netdev_get_sock);
++
+ static const struct net_device_ops ppp_netdev_ops;
+
+ static struct class *ppp_class;
+@@ -1660,6 +1663,40 @@ ppp_send_frame(struct ppp *ppp, struct s
+ ++ppp->dev->stats.tx_errors;
+ }
+
++struct sock *ppp_netdev_get_sock(struct net_device *dev)
++{
++ struct list_head *list;
++ struct channel *pch;
++ struct ppp *ppp;
++ struct sock *sk;
++
++ if (!dev)
++ return ERR_PTR(-EINVAL);
++
++ ppp = netdev_priv(dev);
++
++ list = &ppp->channels;
++ if (list_empty(list))
++ /* nowhere to send the packet */
++ return ERR_PTR(-EINVAL);
++
++ if (ppp->flags & SC_MULTILINK)
++ /* not doing multilink: send it down the first channel */
++ return ERR_PTR(-EPERM);
++
++ list = list->next;
++ pch = list_entry(list, struct channel, clist);
++
++ spin_lock(&pch->downl);
++ if (pch->chan)
++ sk = (struct sock *)pch->chan->private;
++ else
++ sk = ERR_PTR(-EINVAL);
++ spin_unlock(&pch->downl);
++
++ return sk;
++}
++
+ /*
+ * Try to send the frame in xmit_pending.
+ * The caller should have the xmit path locked.
+--- a/include/linux/ppp_channel.h
++++ b/include/linux/ppp_channel.h
+@@ -75,6 +75,9 @@ extern int ppp_unit_number(struct ppp_ch
+ /* Get the device name associated with a channel, or NULL if none */
+ extern char *ppp_dev_name(struct ppp_channel *);
+
++/* Get the socket structure of a given ppp netdev */
++extern struct sock *ppp_netdev_get_sock(struct net_device *dev);
++
+ /*
+ * SMP locking notes:
+ * The channel code must ensure that when it calls ppp_unregister_channel,
diff --git a/target/linux/mediatek/patches-5.4/999-4500-mtk-l2tp-offload-support.patch b/target/linux/mediatek/patches-5.4/999-4501-mtk-l2tp-offload-support.patch
similarity index 100%
rename from target/linux/mediatek/patches-5.4/999-4500-mtk-l2tp-offload-support.patch
rename to target/linux/mediatek/patches-5.4/999-4501-mtk-l2tp-offload-support.patch
diff --git a/target/linux/mediatek/patches-5.4/999-4501-mtk-pptp-offload-support.patch b/target/linux/mediatek/patches-5.4/999-4501-mtk-pptp-offload-support.patch
new file mode 100644
index 0000000..ec218e1
--- /dev/null
+++ b/target/linux/mediatek/patches-5.4/999-4501-mtk-pptp-offload-support.patch
@@ -0,0 +1,100 @@
+--- a/drivers/net/ppp/pptp.c
++++ b/drivers/net/ppp/pptp.c
+@@ -33,6 +33,7 @@
+ #include <net/route.h>
+ #include <net/gre.h>
+ #include <net/pptp.h>
++#include <net/netfilter/nf_flow_table.h>
+
+ #include <linux/uaccess.h>
+
+@@ -40,6 +41,9 @@
+
+ #define MAX_CALLID 65535
+
++int (*mtk_pptp_seq_next)(u16 call_id, u32 *val) = NULL;
++EXPORT_SYMBOL(mtk_pptp_seq_next);
++
+ static DECLARE_BITMAP(callid_bitmap, MAX_CALLID + 1);
+ static struct pppox_sock __rcu **callid_sock;
+
+@@ -128,6 +132,26 @@ static void del_chan(struct pppox_sock *
+ spin_unlock(&chan_lock);
+ }
+
++#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
++static int pptp_flow_offload_check(struct ppp_channel *chan,
++ struct flow_offload_hw_path *path)
++{
++ struct sock *sk = (struct sock *)chan->private;
++ struct pppox_sock *po = pppox_sk(sk);
++
++ if (path->flags & FLOW_OFFLOAD_PATH_TNL)
++ return -EEXIST;
++
++ if (sk_pppox(po)->sk_state & PPPOX_DEAD)
++ return -EINVAL;
++
++ path->flags |= FLOW_OFFLOAD_PATH_TNL;
++ path->tnl_type = FLOW_OFFLOAD_TNL_PPTP;
++
++ return 0;
++}
++#endif /* IS_ENABLED(CONFIG_NF_FLOW_TABLE) */
++
+ static int pptp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
+ {
+ struct sock *sk = (struct sock *) chan->private;
+@@ -140,6 +164,7 @@ static int pptp_xmit(struct ppp_channel
+ int islcp;
+ int len;
+ unsigned char *data;
++ u32 seq_sent_hw;
+ __u32 seq_recv;
+
+
+@@ -204,7 +229,14 @@ static int pptp_xmit(struct ppp_channel
+ hdr->gre_hd.protocol = GRE_PROTO_PPP;
+ hdr->call_id = htons(opt->dst_addr.call_id);
+
+- hdr->seq = htonl(++opt->seq_sent);
++ if (mtk_pptp_seq_next && !mtk_pptp_seq_next(opt->dst_addr.call_id,
++ &seq_sent_hw)) {
++ opt->seq_sent = seq_sent_hw;
++ hdr->seq = htonl(opt->seq_sent);
++ } else {
++ hdr->seq = htonl(++opt->seq_sent);
++ }
++
+ if (opt->ack_sent != seq_recv) {
+ /* send ack with this message */
+ hdr->gre_hd.flags |= GRE_ACK;
+@@ -598,6 +630,9 @@ static int pptp_ppp_ioctl(struct ppp_cha
+ static const struct ppp_channel_ops pptp_chan_ops = {
+ .start_xmit = pptp_xmit,
+ .ioctl = pptp_ppp_ioctl,
++#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
++ .flow_offload_check = pptp_flow_offload_check,
++#endif /* IS_ENABLED(CONFIG_NF_FLOW_TABLE) */
+ };
+
+ static struct proto pptp_sk_proto __read_mostly = {
+--- a/include/net/pptp.h
++++ b/include/net/pptp.h
+@@ -2,6 +2,8 @@
+ #ifndef _NET_PPTP_H
+ #define _NET_PPTP_H
+
++#include <net/gre.h>
++
+ #define PPP_LCP_ECHOREQ 0x09
+ #define PPP_LCP_ECHOREP 0x0A
+ #define SC_RCV_BITS (SC_RCV_B7_1|SC_RCV_B7_0|SC_RCV_ODDP|SC_RCV_EVNP)
+@@ -20,5 +22,7 @@ struct pptp_gre_header {
+ __be32 ack;
+ } __packed;
+
++/* symbol exported from linux kernel driver/net/ppp/pptp.c */
++extern int (*mtk_pptp_seq_next)(uint16_t call_id, uint32_t *val);
+
+ #endif