1
1
Files
zyxel-vmg8825_b50b-cfw/target/linux/brcm963xx/bcmsdk-502L07P1-patches-4.1/020-ZyXEL_QoS.patch
T
2026-04-17 18:33:03 +02:00

2319 lines
72 KiB
Diff

Index: linux-4.1.52/include/uapi/linux/gen_stats.h
===================================================================
--- linux-4.1.52.orig/include/uapi/linux/gen_stats.h 2017-10-17 06:54:53.000000000 +0800
+++ linux-4.1.52/include/uapi/linux/gen_stats.h 2018-01-22 14:21:12.857630793 +0800
@@ -26,6 +26,9 @@
struct gnet_stats_basic_packed {
__u64 bytes;
__u32 packets;
+#if 1 /* ZyXEL QoS, porting from MSTC */
+ __u64 dropbytes;
+#endif
} __attribute__ ((packed));
/**
@@ -36,6 +39,9 @@
struct gnet_stats_rate_est {
__u32 bps;
__u32 pps;
+#if 1 /* ZyXEL QoS, porting from MSTC */
+ __u32 dropbps;
+#endif
};
/**
@@ -46,6 +52,9 @@
struct gnet_stats_rate_est64 {
__u64 bps;
__u64 pps;
+#if 1 /* ZyXEL QoS, porting from MSTC */
+ __u64 dropbps;
+#endif
};
/**
Index: linux-4.1.52/include/uapi/linux/netfilter/xt_AUTOMAP.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-4.1.52/include/uapi/linux/netfilter/xt_AUTOMAP.h 2018-01-22 14:21:12.857630793 +0800
@@ -0,0 +1,65 @@
+/* x_tables module for setting the IPv4/IPv6 DSCP field
+ *
+ * (C) 2002 Harald Welte <laforge@gnumonks.org>
+ * based on ipt_FTOS.c (C) 2000 by Matthew G. Marsh <mgm@paktronix.com>
+ * This software is distributed under GNU GPL v2, 1991
+ *
+ * See RFC2474 for a description of the DSCP field within the IP Header.
+ *
+ * xt_DSCP.h,v 1.7 2002/03/14 12:03:13 laforge Exp
+*/
+#ifndef _XT_AUTOMAP_TARGET_H
+#define _XT_AUTOMAP_TARGET_H
+
+#define XT_AUTO_TYPE 0x1
+//#define XT_AUTO_MARK 0x2
+//#define XT_AUTO_DSCP 0x4
+//#define XT_AUTO_ETHPRI 0x8
+
+/*Automapping Type*/
+#define AUTOMAP_TYPE_8021P 0x1
+#define AUTOMAP_TYPE_DSCP 0x2
+#define AUTOMAP_TYPE_PKTLEN 0x4
+
+#define DSCP_MASK_SHIFT 5
+#define ETHERPRI_MARK_SHIFT 12
+
+ /*
+ Auto Priority Mapping Table
+
+
+ DSCP | Packet Length | 802.1P | Queue |
+ ---------------------------------------------
+ | | 001 | 0 |
+ | | | |
+ | | 010 | 1 |
+ | | | |
+ 0x00 | >1100 | 000 | 2 |
+ | | | |
+ 0x08 | 250-1100 | 011 | 3 |
+ | | | |
+ 0x10 | | 100 | 4 |
+ | | | |
+ 0x18 | <250 | 101 | 5 |
+ | | | |
+ 0x20,0x28 | | 110 | 6 |
+ | | | |
+ 0x30,0x38 | | 111 | 7 |
+ */
+
+
+/* accoding to tr181 8021p to DSCP mapping table(upstream) higher value higher priority */
+unsigned short vlan8021pToDSCP[8]= {0x00,0x00,0x00,0x08,0x10,0x18,0x28,0x38};
+unsigned short dscpPrecedenceTo8021p[8] = {0,3,4,5,6,6,7,7};
+
+unsigned short vlan8021pToPriorityQueue[8] = {2,0,1,3,4,5,6,7};
+unsigned short dscpPrecedenceToPriorityQueue[8] = {2,3,4,5,6,6,7,7};
+
+/* target info */
+struct xt_automap_target_info {
+ int type;
+ int marktable[8];
+ int flags;
+};
+
+#endif /* _XT_AUTOMAP_TARGET_H */
Index: linux-4.1.52/include/uapi/linux/netfilter/xt_mark.h
===================================================================
--- linux-4.1.52.orig/include/uapi/linux/netfilter/xt_mark.h 2017-10-17 06:54:53.000000000 +0800
+++ linux-4.1.52/include/uapi/linux/netfilter/xt_mark.h 2018-01-22 14:21:12.861630793 +0800
@@ -3,8 +3,21 @@
#include <linux/types.h>
+/* Version 1 */
+#if 1 /* ZyXEL QoS, John (porting from MSTC) */
+enum {
+ XT_MARK_SET=0,
+ XT_MARK_AND,
+ XT_MARK_OR,
+ XT_MARK_VTAG_SET
+};
+#endif
+
struct xt_mark_tginfo2 {
__u32 mark, mask;
+#if 1 /* ZyXEL QoS, John */
+ __u8 mode;
+#endif
};
struct xt_mark_mtinfo1 {
Index: linux-4.1.52/include/uapi/linux/netfilter/xt_policer.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-4.1.52/include/uapi/linux/netfilter/xt_policer.h 2018-01-22 14:21:12.861630793 +0800
@@ -0,0 +1,38 @@
+#ifndef _XT_RATE_H
+#define _XT_RATE_H
+
+#define BITS_PER_BYTE 8
+#define KILO_SCALE 1000
+
+struct xt_policerinfo {
+#if 1//__MSTC__, Jones For compilation
+ int policerMode;
+
+ /* For srTCM and trTCM, rate means cRate and burst means cbsBurst.
+ For srTCM, pbsBurst means ebsBurst. */
+ u_int32_t rate, pRate;
+ u_int32_t burst, pbsBurst; /* Period multiplier for upper limit. */
+
+ /* Used internally by the kernel */
+ unsigned long prev;
+
+ /* For srTCM and trTCM, credit means cbsCredit and creditCap means cbsCreditCap.
+ For srTCM, pbsCreditCap means ebsCreditCap. */
+ u_int32_t credit, pbsCredit;
+ u_int32_t creditCap, pbsCreditCap;
+
+ struct xt_policerinfo *master;
+#else
+ u_int32_t avg; /* Average secs between packets * scale */
+ u_int32_t burst; /* Period multiplier for upper limit. */
+
+ /* Used internally by the kernel */
+ unsigned long prev;
+ u_int32_t credit;
+ u_int32_t credit_cap, cost;
+
+ struct xt_policerinfo *master;
+#endif
+};
+
+#endif /*_XT_RATE_H*/
Index: linux-4.1.52/include/uapi/linux/netfilter_bridge/ebt_AUTOMAP.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-4.1.52/include/uapi/linux/netfilter_bridge/ebt_AUTOMAP.h 2018-01-22 14:21:12.861630793 +0800
@@ -0,0 +1,50 @@
+/* Used by ebt_AUTOMAP.c, MitraStar Jeff, 20110114*/
+#ifndef __LINUX_BRIDGE_EBT_AUTOMAP_H
+#define __LINUX_BRIDGE_EBT_AUTOMAP_H
+
+#define EBT_AUTOMAP_TARGET "AUTOMAP"
+
+#define AUTOMAP_TYPE_8021P 0x1
+#define AUTOMAP_TYPE_DSCP 0x2
+#define AUTOMAP_TYPE_PKTLEN 0x4
+
+#define DSCP_MASK_SHIFT 5
+#define ETHERPRI_MARK_SHIFT 12
+
+
+ /*
+ Auto Priority Mapping Table
+
+
+ DSCP | Packet Length | 802.1P | Queue |
+ ---------------------------------------------
+ | | 001 | 0 |
+ | | | |
+ | | 010 | 1 |
+ | | | |
+ 0x00 | >1100 | 000 | 2 |
+ | | | |
+ 0x08 | 250-1100 | 011 | 3 |
+ | | | |
+ 0x10 | | 100 | 4 |
+ | | | |
+ 0x18 | <250 | 101 | 5 |
+ | | | |
+ 0x20,0x28 | | 110 | 6 |
+ | | | |
+ 0x30,0x38 | | 111 | 7 |
+ */
+
+
+/* accoding to tr181 8021p to DSCP mapping table(upstream), higher value higher priority*/
+unsigned short vlan8021pToPriorityQueue[8] = {2,0,1,3,4,5,6,7};
+unsigned short dscpPrecedenceToPriorityQueue[8] = {2,3,4,5,6,6,7,7};
+
+
+/* target info */
+struct ebt_automap_t_info {
+ int type;
+ int marktable[8];
+};
+
+#endif
Index: linux-4.1.52/include/uapi/linux/netfilter_bridge/ebt_ip.h
===================================================================
--- linux-4.1.52.orig/include/uapi/linux/netfilter_bridge/ebt_ip.h 2018-01-22 14:21:12.493630784 +0800
+++ linux-4.1.52/include/uapi/linux/netfilter_bridge/ebt_ip.h 2018-01-22 14:21:12.861630793 +0800
@@ -23,6 +23,55 @@
#define EBT_IP_PROTO 0x08
#define EBT_IP_SPORT 0x10
#define EBT_IP_DPORT 0x20
+
+#if 1 /* ZyXEL QoS, John (porting from MSTC) */
+#if defined(CONFIG_BCM_KF_NETFILTER) || !defined(CONFIG_BCM_IN_KERNEL)
+#define EBT_IP_DSCP 0x40
+#endif
+#define EBT_IP_LENGTH 0x80
+#define EBT_IP_TCP_FLAGS 0x100
+#define EBT_IP_DHCP_OPT60 0x200
+#define EBT_IP_DHCP_OPT61 0x400
+#define EBT_IP_DHCP_OPT77 0x800
+#define EBT_IP_DHCP_OPT125 0x1000
+#if defined(CONFIG_BCM_KF_NETFILTER) || !defined(CONFIG_BCM_IN_KERNEL)
+#define EBT_IP_MASK (EBT_IP_SOURCE | EBT_IP_DEST | EBT_IP_TOS | EBT_IP_PROTO |\
+ EBT_IP_SPORT | EBT_IP_DPORT | EBT_IP_DSCP | EBT_IP_LENGTH | EBT_IP_TCP_FLAGS |\
+ EBT_IP_DHCP_OPT60 | EBT_IP_DHCP_OPT61 | EBT_IP_DHCP_OPT77 | EBT_IP_DHCP_OPT125)
+#else
+#define EBT_IP_MASK (EBT_IP_SOURCE | EBT_IP_DEST | EBT_IP_TOS | EBT_IP_PROTO |\
+ EBT_IP_SPORT | EBT_IP_DPORT | EBT_IP_LENGTH | EBT_IP_TCP_FLAGS |\
+ EBT_IP_DHCP_OPT60 | EBT_IP_DHCP_OPT61 | EBT_IP_DHCP_OPT77 | EBT_IP_DHCP_OPT125)
+#endif
+#define DHCP_OPTION_MAX_LEN 556 /* IP header(20) + UDP header(8)+ DHCP header(528) */
+
+#define DHCP_PADDING 0x00
+#define DHCP_VENDOR 0x3c /*option 60 */
+#define DHCP_CLIENT_ID 0x3d /*option 61 */
+#define DHCP_USER_CLASS_ID 0x4d /*option 77 */
+#define DHCP_VENDOR_IDENTIFYING 0x7d /*option 125 */
+#define DHCP_OPTION_OVER 0x34
+#define DHCP_END 0xFF
+
+#define OPTION_FIELD 0
+#define FILE_FIELD 1
+#define SNAME_FIELD 2
+
+
+
+/* miscellaneous defines */
+#define OPT_CODE 0
+#define OPT_LEN 1
+#define OPT_DATA 2
+
+#define OPTION_MAC_ENTRY 32
+
+/* each option data shift length */
+#define DHCP_OPT_LEN_FIELD_LEN 1
+#define DHCP_OPT125_ENTERPRISE_NUM_LEN 4
+#define DHCP_OPT125_DATA_SHIFT DHCP_OPT125_ENTERPRISE_NUM_LEN + DHCP_OPT_LEN_FIELD_LEN
+
+#else
#if defined(CONFIG_BCM_KF_NETFILTER) || !defined(CONFIG_BCM_IN_KERNEL)
#define EBT_IP_DSCP 0x40
#define EBT_IP_MASK (EBT_IP_SOURCE | EBT_IP_DEST | EBT_IP_TOS | EBT_IP_PROTO |\
@@ -31,9 +80,61 @@
#define EBT_IP_MASK (EBT_IP_SOURCE | EBT_IP_DEST | EBT_IP_TOS | EBT_IP_PROTO |\
EBT_IP_SPORT | EBT_IP_DPORT )
#endif
+#endif
#define EBT_IP_MATCH "ip"
/* the same values are used for the invflags */
+#if 1 /* ZyXEL QoS, John (porting from MSTC) */
+struct cfgopt{
+ uint8_t len;
+ char cfgdata[254];
+};
+
+struct dhcpMessage {
+ uint8_t op;
+ uint8_t htype;
+ uint8_t hlen;
+ uint8_t hops;
+ uint32_t xid;
+ uint16_t secs;
+ uint16_t flags;
+ uint32_t ciaddr;
+ uint32_t yiaddr;
+ uint32_t siaddr;
+ uint32_t giaddr;
+ uint8_t chaddr[16];
+ uint8_t sname[64];
+ uint8_t file[128];
+ uint32_t cookie;
+ uint8_t options[308]; /* 312 - cookie */
+};
+
+struct ebt_ip_info
+{
+ __be32 saddr;
+ __be32 daddr;
+ __be32 smsk;
+ __be32 dmsk;
+ __u8 tos;
+#if defined(CONFIG_BCM_KF_NETFILTER) || !defined(CONFIG_BCM_IN_KERNEL)
+ __u8 dscp; /* brcm */
+#endif
+ __u8 protocol;
+ __u16 bitmask;
+ __u16 invflags;
+ __u8 tcp_flg_mask;
+ __u8 tcp_flg_cmp;
+ __u16 sport[2];
+ __u16 dport[2];
+ __u16 length[2];
+ struct cfgopt cfg60; //option 60
+ struct cfgopt cfg61; //option 61
+ struct cfgopt cfg77; //option 77
+ struct cfgopt cfg125; //option 125
+ char SrcMacArray[OPTION_MAC_ENTRY][ETH_ALEN];
+};
+#else
+/* the same values are used for the invflags */
struct ebt_ip_info {
__be32 saddr;
__be32 daddr;
@@ -49,5 +150,6 @@
__u16 sport[2];
__u16 dport[2];
};
+#endif
#endif
Index: linux-4.1.52/include/uapi/linux/netfilter_bridge/ebt_ip6.h
===================================================================
--- linux-4.1.52.orig/include/uapi/linux/netfilter_bridge/ebt_ip6.h 2017-10-17 06:54:53.000000000 +0800
+++ linux-4.1.52/include/uapi/linux/netfilter_bridge/ebt_ip6.h 2018-01-22 14:21:12.861630793 +0800
@@ -21,10 +21,19 @@
#define EBT_IP6_SPORT 0x10
#define EBT_IP6_DPORT 0x20
#define EBT_IP6_ICMP6 0x40
+#if 1 /* ZyXEL QoS, John (porting from MSTC) */
+#define EBT_IP6_LENGTH 0x80
+#endif
+#if 1 /* ZyXEL QoS, John (porting from MSTC) */
+#define EBT_IP6_MASK (EBT_IP6_SOURCE | EBT_IP6_DEST | EBT_IP6_TCLASS |\
+ EBT_IP6_PROTO | EBT_IP6_SPORT | EBT_IP6_DPORT | \
+ EBT_IP6_ICMP6 | EBT_IP6_LENGTH)
+#else
#define EBT_IP6_MASK (EBT_IP6_SOURCE | EBT_IP6_DEST | EBT_IP6_TCLASS |\
EBT_IP6_PROTO | EBT_IP6_SPORT | EBT_IP6_DPORT | \
EBT_IP6_ICMP6)
+#endif
#define EBT_IP6_MATCH "ip6"
/* the same values are used for the invflags */
@@ -45,6 +54,9 @@
__u16 dport[2];
__u8 icmpv6_code[2];
};
+#if 1 /* ZyXEL QoS, John (porting from MSTC) */
+ __u16 length[2];
+#endif
};
#endif
Index: linux-4.1.52/include/uapi/linux/netfilter_bridge/ebt_policer.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-4.1.52/include/uapi/linux/netfilter_bridge/ebt_policer.h 2018-01-22 14:21:12.861630793 +0800
@@ -0,0 +1,39 @@
+/* Used by ebt_policer.c, ZyXEL Stan, 20100107*/
+#ifndef __LINUX_BRIDGE_EBT_POLICER_H
+#define __LINUX_BRIDGE_EBT_POLICER_H
+
+#define EBT_POLICER_MATCH "policer"
+
+#define BITS_PER_BYTE 8
+#define KILO_SCALE 1000
+
+struct ebt_policer_info
+{
+#if 1//__MSTC__, Jones For compilation
+ int policerMode;
+
+ /* For srTCM and trTCM, rate means cRate and burst means cbsBurst.
+ For srTCM, pbsBurst means ebsBurst. */
+ u_int32_t rate, pRate;
+ u_int32_t burst, pbsBurst; /* Period multiplier for upper limit. */
+
+ /* Used internally by the kernel */
+ unsigned long prev;
+
+ /* For srTCM and trTCM, credit means cbsCredit and creditCap means cbsCreditCap.
+ For srTCM, pbsCreditCap means ebsCreditCap. */
+ u_int32_t credit, pbsCredit;
+ u_int32_t creditCap, pbsCreditCap;
+#else
+ u_int32_t avg; /* Average secs between packets * scale */
+ u_int32_t burst; /* Period multiplier for upper limit. */
+
+ /* Used internally by the kernel */
+ unsigned long prev;
+ u_int32_t credit;
+ u_int32_t credit_cap, cost;
+#endif
+};
+
+#endif
+
Index: linux-4.1.52/net/bridge/netfilter/Kconfig
===================================================================
--- linux-4.1.52.orig/net/bridge/netfilter/Kconfig 2018-01-22 14:21:12.597630786 +0800
+++ linux-4.1.52/net/bridge/netfilter/Kconfig 2018-01-22 14:21:12.861630793 +0800
@@ -65,6 +65,22 @@
See the man page for ebtables(8).
To compile it as a module, choose M here. If unsure, say N.
+config BRIDGE_EBT_AUTOMAP
+ tristate "ebt: auto priority mapping and DSCP marking support"
+ depends on BRIDGE_NF_EBTABLES
+ help
+ This option adds Auto Priority Mapping target on ebtables
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config BRIDGE_EBT_POLICER
+ tristate "ebt: policy rate limit support"
+ depends on BRIDGE_NF_EBTABLES
+ help
+ This option adds the policy rate limit support
+
+ To compile it as a module, choose M here. If unsure, say N.
+
#
# matches
#
Index: linux-4.1.52/net/bridge/netfilter/Makefile
===================================================================
--- linux-4.1.52.orig/net/bridge/netfilter/Makefile 2018-01-22 14:21:12.601630787 +0800
+++ linux-4.1.52/net/bridge/netfilter/Makefile 2018-01-22 14:21:12.861630793 +0800
@@ -49,6 +49,11 @@
obj-$(CONFIG_BRIDGE_EBT_WMM_MARK) += ebt_wmm_mark.o
obj-$(CONFIG_BRIDGE_EBT_QOS_MAP) += ebt_qos_map.o
obj-$(CONFIG_BRIDGE_EBT_REJECT) += ebt_reject.o
+# /* ZyXEL QoS, John (porting from MSTC) */
+obj-$(CONFIG_BRIDGE_EBT_AUTOMAP) += ebt_AUTOMAP.o
+
+# /* ZyXEL QoS, Mark (porting from MSTC) */
+obj-$(CONFIG_BRIDGE_EBT_POLICER) += ebt_policer.o
endif # BCM_KF # CONFIG_BCM_KF_NETFILTER
# watchers
Index: linux-4.1.52/net/bridge/netfilter/ebt_AUTOMAP.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-4.1.52/net/bridge/netfilter/ebt_AUTOMAP.c 2018-01-22 16:09:59.973788827 +0800
@@ -0,0 +1,149 @@
+/* Kernel module to control the rate in kbps. */
+/* This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation. */
+/* MitraStar Jeff, 20110114*/
+
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/ip.h>
+#include <linux/if_vlan.h>
+
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter_bridge/ebtables.h>
+#include <linux/netfilter_bridge/ebt_AUTOMAP.h>
+
+
+static int getVlanPrioAndIpHeader(struct sk_buff *skb, unsigned char *prio, struct iphdr **iph){
+ unsigned short TCI;
+ unsigned short id; /* VLAN ID, given from frame TCI */
+ /* Need to recalculate IP header checksum after altering TOS byte */
+ const struct vlan_hdr *fp;
+ struct vlan_hdr _frame;
+ struct iphdr *ih = NULL;
+
+ /* get ip header */
+ if (skb->protocol == __constant_htons(ETH_P_IP))
+ ih = (struct iphdr *)skb_network_header(skb);
+ else if (skb->protocol == __constant_htons(ETH_P_8021Q)) {
+ if (*(unsigned short *)(skb_network_header(skb) + VLAN_HLEN - 2) == __constant_htons(ETH_P_IP))
+ ih = (struct iphdr *)(skb_network_header(skb) + VLAN_HLEN);
+ }
+ *iph = ih;
+
+ if(ntohs(((struct vlan_hdr *)(skb->vlan_header))->h_vlan_encapsulated_proto) == 0){
+ if(skb->protocol == ETH_P_8021Q) {
+ fp = skb_header_pointer(skb, 0, sizeof(_frame), &_frame);
+ if (fp == NULL)
+ return EBT_CONTINUE;
+ /* Tag Control Information (TCI) consists of the following elements:
+ * - User_priority. The user_priority field is three bits in length,
+ * interpreted as a binary number.
+ * - Canonical Format Indicator (CFI). The Canonical Format Indicator
+ * (CFI) is a single bit flag value. Currently ignored.
+ * - VLAN Identifier (VID). The VID is encoded as
+ * an unsigned binary number. */
+ TCI = ntohs(fp->h_vlan_TCI);
+ id = TCI & VLAN_VID_MASK;
+ *prio = (TCI >> 13) & 0x7;
+ }
+ //Packet with no VLAN tag
+ else {
+ TCI = 0;
+ id = 0;
+ //Packet with no VLAN tag will be sent to default queue just like 1p value is 1
+ *prio = 1;
+ }
+ }
+ else {
+ // for new broadcom vlan device
+ TCI = ntohs(((struct vlan_hdr *)(skb->vlan_header))->h_vlan_TCI);
+ id = TCI & VLAN_VID_MASK;
+ *prio = (TCI >> 13) & 0x7;
+ }
+
+ return 0;
+}
+
+
+static unsigned int
+ebt_automap_tg(struct sk_buff *skb, const struct xt_action_param *par)
+{
+ const struct ebt_automap_t_info *aminfo = par->targinfo;
+ struct iphdr *iph = NULL;
+ unsigned char prio = 0;
+ unsigned char dscpPrecedence = 0;
+
+
+ getVlanPrioAndIpHeader(skb, &prio, &iph);
+
+ switch(aminfo->type){
+ case AUTOMAP_TYPE_8021P:
+ /* mark value for priority queue */
+ skb->mark |= vlan8021pToPriorityQueue[prio];
+
+ /* should mark DSCP here */
+ break;
+ case AUTOMAP_TYPE_DSCP:
+
+ if(iph==NULL)
+ skb->mark|=0x0;
+ else {
+ /* get dscp precedence */
+ dscpPrecedence = ((iph->tos)>>5)&0x7;
+
+ /* mark value for priority queue */
+ skb->mark |= dscpPrecedenceToPriorityQueue[dscpPrecedence];
+ }
+ break;
+ case AUTOMAP_TYPE_PKTLEN:
+ if(iph==NULL)
+ skb->mark|=0x0;
+ else {
+ if(iph->tot_len > 1100){
+ skb->mark|=vlan8021pToPriorityQueue[0]; /* queue prio 2 */
+ }else if(iph->tot_len < 250){
+ skb->mark|=vlan8021pToPriorityQueue[5]; /* queue prio 5 */
+ }else{ /*250~1100*/
+ skb->mark|=vlan8021pToPriorityQueue[3]; /* queue prio 3 */
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ return EBT_CONTINUE;
+}
+
+/* As a policer rule added, this function will be executed */
+static int ebt_automap_tg_check(const struct xt_tgchk_param *par)
+{
+ return 0;
+}
+
+static struct xt_target ebt_automap_tg_reg __read_mostly =
+{
+ .name = EBT_AUTOMAP_TARGET,
+ .revision = 0,
+ .family = NFPROTO_BRIDGE,
+ .target = ebt_automap_tg,
+ .checkentry = ebt_automap_tg_check,
+ .targetsize = XT_ALIGN(sizeof(struct ebt_automap_t_info)),
+ .me = THIS_MODULE,
+};
+
+static int __init ebt_automap_init(void)
+{
+ return xt_register_target(&ebt_automap_tg_reg);
+}
+
+static void __exit ebt_automap_fini(void)
+{
+ xt_unregister_target(&ebt_automap_tg_reg);
+}
+
+module_init(ebt_automap_init);
+module_exit(ebt_automap_fini);
+MODULE_LICENSE("GPL");
+
Index: linux-4.1.52/net/bridge/netfilter/ebt_ip.c
===================================================================
--- linux-4.1.52.orig/net/bridge/netfilter/ebt_ip.c 2018-01-22 14:21:12.593630786 +0800
+++ linux-4.1.52/net/bridge/netfilter/ebt_ip.c 2018-01-22 15:46:22.061754496 +0800
@@ -18,12 +18,205 @@
#include <linux/netfilter/x_tables.h>
#include <linux/netfilter_bridge/ebtables.h>
#include <linux/netfilter_bridge/ebt_ip.h>
-
+#if 1 /* ZyXEL QoS, John (porting from MSTC) */
+#include <linux/tcp.h>
+#include <linux/udp.h>
+#endif
struct tcpudphdr {
__be16 src;
__be16 dst;
};
+#if 1 /* ZyXEL QoS, John (porting from MSTC) */
+
+unsigned char *get_DhcpOption(struct dhcpMessage *packet, int code)
+{
+ int i, length;
+ unsigned char *optionptr;
+ int over = 0, done = 0, curr = OPTION_FIELD;
+
+ optionptr = packet->options;
+ i = 0;
+ length = 308;
+
+ while (!done) {
+ if (i >= length){
+ return NULL;
+ }
+ if (optionptr[i + OPT_CODE] == code) {
+ if (i + 1 + optionptr[i + OPT_LEN] >= length) {
+ return NULL;
+ }
+ return optionptr + i + 2;
+ }
+ switch (optionptr[i + OPT_CODE]) {
+ case DHCP_PADDING:
+ i++;
+ break;
+ case DHCP_OPTION_OVER:
+ if (i + 1 + optionptr[i + OPT_LEN] >= length) {
+ return NULL;
+ }
+ over = optionptr[i + 3];
+ i += optionptr[OPT_LEN] + 2;
+ break;
+ case DHCP_END:
+ if (curr == OPTION_FIELD && over & FILE_FIELD) {
+ optionptr = packet->file;
+ i = 0;
+ length = 128;
+ curr = FILE_FIELD;
+ } else if (curr == FILE_FIELD && over & SNAME_FIELD) {
+ optionptr = packet->sname;
+ i = 0;
+ length = 64;
+ curr = SNAME_FIELD;
+ } else done = 1;
+ break;
+ default:
+ i += optionptr[OPT_LEN + i] + 2;
+ }
+ }
+ return NULL;
+}
+
+/* If match, return value is 0 */
+static int cmp_option60(char *optval60, const struct ebt_ip_info *info)
+{
+ int len;
+ char optionData[254];
+ const struct cfgopt *cfgptr = NULL;
+ printk("%s %d\n", __FUNCTION__, __LINE__);
+
+ if (optval60 == NULL)
+ return false;
+
+ cfgptr = &(info->cfg60);
+
+ /* Compare option data length */
+ len = (int)(*((unsigned char *)optval60 - 1));
+ if(len != cfgptr->len)
+ return false;
+
+ /* Compare option data content */
+ memset(optionData, 0, 254);
+ strncpy(optionData, optval60, len);
+ printk("%s %d: cfgdata[%s] optionData[%s]\n", __FUNCTION__, __LINE__, cfgptr->cfgdata, optionData);
+ if(strcmp(cfgptr->cfgdata, optionData) == 0)
+ return true;
+
+ return 1;
+}
+
+/* If match, return value is 0 */
+static int cmp_option61(char *optval61, const struct ebt_ip_info *info)
+{
+ int len;
+ char optionData[254];
+ const struct cfgopt *cfgptr = NULL;
+
+
+
+ if (optval61 == NULL)
+ return false;
+
+ cfgptr = &(info->cfg61);
+
+ /* Compare option data length */
+ len = (int)(*((unsigned char *)optval61 - 1));
+
+ if(len != cfgptr->len)
+ return false;
+
+ /* Compare option data content */
+ memset(optionData, 0, 254);
+ memcpy(optionData, optval61, len);
+
+ if(!memcmp(cfgptr->cfgdata, optionData, len))
+ return true;
+
+ return 1;
+}
+
+/* If match, return value is 0 */
+static int cmp_option77(char *optval77, const struct ebt_ip_info *info)
+{
+ uint8_t len = 0, total_len = 0, current_len = 0;
+ char optionData[254];
+ const struct cfgopt *cfgptr = NULL;
+
+
+ if (optval77 == NULL)
+ return false;
+
+ cfgptr = &(info->cfg77);
+
+ /* Record option 77 total length */
+ total_len = (uint8_t)(*((unsigned char *)optval77 - 1));
+
+ while(total_len != current_len){
+ len = (uint8_t)*((unsigned char *)optval77); /* For option 77, one data length */
+
+ if(len != cfgptr->len)
+ return false;
+
+ /* Compare option data content */
+ memset(optionData, 0, 254);
+ memcpy(optionData, optval77 + DHCP_OPT_LEN_FIELD_LEN, len );
+ if(!memcmp(cfgptr->cfgdata, optionData, len))
+ return true;
+
+ /* shift to next vendor class data in option 125 */
+ current_len += (len + DHCP_OPT_LEN_FIELD_LEN);
+ optval77 += (len + DHCP_OPT_LEN_FIELD_LEN);
+ }
+ return false;
+}
+
+
+/* If match, return value is 0 */
+static int cmp_option125(char *optval125, const struct ebt_ip_info *info)
+{
+ int len = 0, total_len = 0, current_len = 0;
+ char optionData[254];
+ const struct cfgopt *cfgptr = NULL;
+
+ if (optval125 == NULL)
+ return false;
+
+ cfgptr = &(info->cfg125);
+
+ /* Record option 125 total length */
+ total_len = (int)(*((unsigned char *)optval125 - 1));
+
+ while(total_len != current_len){
+
+ len = (int)(*((unsigned char *)optval125 +DHCP_OPT125_ENTERPRISE_NUM_LEN)); /* For option 125, one data length */
+
+
+ if(len + DHCP_OPT125_DATA_SHIFT != cfgptr->len) /* Add 5 is for enterprise-number(4 bytes) and data length represent(1 byte) */
+ return false;
+
+ /* Compare option data content */
+ memset(optionData, 0, 254);
+ memcpy(optionData, optval125, len + DHCP_OPT125_DATA_SHIFT);
+
+ if(!memcmp(cfgptr->cfgdata, optionData, len + DHCP_OPT125_DATA_SHIFT))
+ return true;
+
+ /* shift to next vendor class data in option 125 */
+ current_len += (len + DHCP_OPT125_DATA_SHIFT);
+ optval125 += (len + DHCP_OPT125_DATA_SHIFT);
+ }
+ return false;
+
+}
+
+
+
+
+
+#endif
static bool
ebt_ip_mt(const struct sk_buff *skb, struct xt_action_param *par)
{
@@ -32,10 +225,112 @@
struct iphdr _iph;
const struct tcpudphdr *pptr;
struct tcpudphdr _ports;
+#if 1 /* ZyXEL QoS, John (porting from MSTC) */
+ struct tcphdr _tcph, *th;
+#endif
ih = skb_header_pointer(skb, 0, sizeof(_iph), &_iph);
if (ih == NULL)
return false;
+#if 1 /* ZyXEL QoS, John (porting from MSTC) */
+ if((info->bitmask & EBT_IP_DHCP_OPT60)||(info->bitmask & EBT_IP_DHCP_OPT61)||
+ (info->bitmask & EBT_IP_DHCP_OPT77)||(info->bitmask & EBT_IP_DHCP_OPT125)){
+ unsigned char payload[DHCP_OPTION_MAX_LEN];
+ struct dhcpMessage *dhcpPtr;
+ struct iphdr _iph, *ih;
+ struct tcpudphdr _ports, *pptr;
+ int skb_data_len=0, i, LastEntry = -1;
+ bool OptMatch = 0;
+ char TmpMac[ETH_ALEN];
+
+ memset(TmpMac , 0, sizeof(TmpMac));
+
+ ih = skb_header_pointer(skb, 0, sizeof(_iph), &_iph);
+ if (ih == NULL)
+ return false;
+
+ pptr = skb_header_pointer(skb, ih->ihl*4, sizeof(_ports), &_ports);
+
+ /* not DHCP packet, then try to compared with recoded mac */
+ if(pptr->src!=67 && pptr->src!=68 && pptr->dst!=67 && pptr->dst!=68){
+ for(i=0;i<OPTION_MAC_ENTRY;i++){
+ if(ether_addr_equal(eth_hdr(skb)->h_source, info->SrcMacArray[i])){
+ /* if match, continue to check other conditions */
+ goto CONTINUE;
+ }
+ if(!memcmp(TmpMac,info->SrcMacArray[i],ETH_ALEN)){
+ break;
+ }
+ }
+ return false;
+ }else{
+ /* If packet is dhcp packet */
+ memset(payload, 0, sizeof(payload));
+ skb_data_len = skb->len;
+
+ if (skb_copy_bits(skb, 0, payload, skb_data_len))
+ printk("Copy packet is failed by ebtables of filtering DHCP Option\n\r");
+
+ dhcpPtr = (struct dhcpMessage *)(payload + sizeof(struct iphdr) + sizeof(struct udphdr));
+
+ if(info->bitmask & EBT_IP_DHCP_OPT60){
+ char *opt60 = get_DhcpOption(dhcpPtr, DHCP_VENDOR);
+ if(cmp_option60(opt60, info)^ !!(info->invflags & EBT_IP_DHCP_OPT60))
+ OptMatch = 1;
+ }
+
+ if(info->bitmask & EBT_IP_DHCP_OPT61){
+ char *opt61 = get_DhcpOption(dhcpPtr, DHCP_CLIENT_ID);
+ if(cmp_option61(opt61, info)^ !!(info->invflags & EBT_IP_DHCP_OPT61))
+ OptMatch = 1;
+ }
+
+ if(info->bitmask & EBT_IP_DHCP_OPT77){
+ char *opt77 = get_DhcpOption(dhcpPtr, DHCP_USER_CLASS_ID);
+ if(cmp_option77(opt77, info)^ !!(info->invflags & EBT_IP_DHCP_OPT77))
+ OptMatch = 1;
+ }
+
+ if(info->bitmask & EBT_IP_DHCP_OPT125){
+ char *opt125 = get_DhcpOption(dhcpPtr, DHCP_VENDOR_IDENTIFYING);
+ if(cmp_option125(opt125, info)^ !!(info->invflags & EBT_IP_DHCP_OPT125))
+ OptMatch = 1;
+ }
+
+// printk("\nOptMatch is %d\n",OptMatch);
+
+ if(OptMatch){
+ /* match dhcp option, then record its MAC addr for future filter */
+ for(i=0;i<OPTION_MAC_ENTRY;i++){
+ if(!memcmp(TmpMac,info->SrcMacArray[i],ETH_ALEN)){
+ memcpy((void *)(info->SrcMacArray[i]), eth_hdr(skb)->h_source, ETH_ALEN);
+ break;
+ }else if(!memcmp(eth_hdr(skb)->h_source, info->SrcMacArray[i], ETH_ALEN)){
+ break;
+ }
+ }
+ }else{
+ /* not match, need to check current list whether this MAC hace once been matched, if so, clear this entry from this DHCP
+ option criteria (client might change another vendor information, ex different vendor ID string) */
+ for(i=0;i<OPTION_MAC_ENTRY;i++){
+ if(!memcmp(TmpMac,info->SrcMacArray[i],ETH_ALEN)){
+ if(LastEntry!=-1){
+ memcpy((void *)(info->SrcMacArray[LastEntry]), info->SrcMacArray[i-1], ETH_ALEN);
+ memset((void *)(info->SrcMacArray[i-1]), 0, ETH_ALEN);
+ }
+ break;
+ }else if(!memcmp(eth_hdr(skb)->h_source, info->SrcMacArray[i], ETH_ALEN)){
+ LastEntry = i;//Record clear entry
+ }
+ }
+
+ return false;
+ }
+ }
+
+ }
+CONTINUE:
+#endif
if (info->bitmask & EBT_IP_TOS &&
FWINV(info->tos != ih->tos, EBT_IP_TOS))
return false;
@@ -52,11 +347,26 @@
FWINV((ih->daddr & info->dmsk) !=
info->daddr, EBT_IP_DEST))
return false;
+#if 1 /* ZyXEL QoS, John (porting from MSTC) */
+ if(info->bitmask & EBT_IP_LENGTH) { /* IP Length */
+ u16 len = ntohs(ih->tot_len);
+ if (FWINV(len < info->length[0] ||
+ len > info->length[1],
+ EBT_IP_LENGTH))
+ return false;
+ }
+#endif
if (info->bitmask & EBT_IP_PROTO) {
if (FWINV(info->protocol != ih->protocol, EBT_IP_PROTO))
return false;
+#if 0 /* ZyXEL QoS, John (porting from MSTC) */
if (!(info->bitmask & EBT_IP_DPORT) &&
!(info->bitmask & EBT_IP_SPORT))
+#else
+ if (!(info->bitmask & EBT_IP_DPORT) &&
+ !(info->bitmask & EBT_IP_SPORT) &&
+ !(info->bitmask & EBT_IP_TCP_FLAGS))
+#endif
return true;
if (ntohs(ih->frag_off) & IP_OFFSET)
return false;
@@ -78,6 +388,19 @@
EBT_IP_SPORT))
return false;
}
+#if 1 /* ZyXEL QoS, John (porting from MSTC) */
+ if (info->bitmask & EBT_IP_TCP_FLAGS) {
+ th = skb_header_pointer(skb, ih->ihl*4, sizeof(_tcph), &_tcph);
+ if (th == NULL) {
+ /* We've been asked to examine this packet, and we
+ can't. Hence, no choice but to drop. */
+ printk("Dropping evil TCP offset=0 tinygram.\n");
+ return 0;
+ }
+ if (FWINV((((unsigned char *)th)[13] & info->tcp_flg_mask) != info->tcp_flg_cmp, EBT_IP_TCP_FLAGS))
+ return false;
+ }
+#endif
}
return true;
}
@@ -106,6 +429,10 @@
return -EINVAL;
if (info->bitmask & EBT_IP_SPORT && info->sport[0] > info->sport[1])
return -EINVAL;
+#if 1 /* ZyXEL QoS, John (porting from MSTC) */
+ if (info->bitmask & EBT_IP_LENGTH && info->length[0] > info->length[1])
+ return false;
+#endif
return 0;
}
Index: linux-4.1.52/net/bridge/netfilter/ebt_ip6.c
===================================================================
--- linux-4.1.52.orig/net/bridge/netfilter/ebt_ip6.c 2017-10-17 06:54:53.000000000 +0800
+++ linux-4.1.52/net/bridge/netfilter/ebt_ip6.c 2018-01-22 14:21:12.865630793 +0800
@@ -55,6 +55,15 @@
FWINV(ipv6_masked_addr_cmp(&ih6->daddr, &info->dmsk,
&info->daddr), EBT_IP6_DEST)))
return false;
+#if 1 /* ZyXEL QoS, John (porting from MSTC) */
+ if(info->bitmask & EBT_IP6_LENGTH) {
+ u16 len = ntohs(ih6->payload_len);
+ if (FWINV(len < info->length[0] ||
+ len > info->length[1],
+ EBT_IP6_LENGTH))
+ return false;
+ }
+#endif
if (info->bitmask & EBT_IP6_PROTO) {
uint8_t nexthdr = ih6->nexthdr;
__be16 frag_off;
@@ -128,6 +137,10 @@
info->icmpv6_code[0] > info->icmpv6_code[1])
return -EINVAL;
}
+#if 1 /* ZyXEL QoS, John (porting from MSTC) */
+ if (info->bitmask & EBT_IP6_LENGTH && info->length[0] > info->length[1])
+ return false;
+#endif
return 0;
}
Index: linux-4.1.52/net/bridge/netfilter/ebt_mark.c
===================================================================
--- linux-4.1.52.orig/net/bridge/netfilter/ebt_mark.c 2018-01-22 14:21:12.593630786 +0800
+++ linux-4.1.52/net/bridge/netfilter/ebt_mark.c 2018-01-22 14:21:12.865630793 +0800
@@ -65,6 +65,7 @@
frame->h_vlan_TCI = htons(TCI);
}
+#if 0 /* ZyXEL QoS, change VLAM header process to vlanCtl driver instead of ebtables module, John (porting from MSTC)*/
else
{
if ((skb_mac_header(skb) - skb->head) < VLAN_HLEN)
@@ -97,6 +98,7 @@
}
}
skb->vtag = 0;
+#endif
}
}
#endif // CONFIG_BCM_KF_NETFILTER
Index: linux-4.1.52/net/bridge/netfilter/ebt_policer.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-4.1.52/net/bridge/netfilter/ebt_policer.c 2018-01-22 16:22:34.841807103 +0800
@@ -0,0 +1,328 @@
+/* Kernel module to control the rate in kbps. */
+/* This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation. */
+/* ZyXEL Stan, 20100105*/
+
+#include <linux/module.h>
+#if 1 // __MSTC__, ZyXEL richard, QoS
+#include <linux/netfilter/x_tables.h>
+#endif // __MSTC__, ZyXEL richard, QoS
+#include <linux/netfilter_bridge/ebtables.h>
+#include <linux/netfilter_bridge/ebt_policer.h>
+
+#include <linux/netdevice.h>
+#include <linux/spinlock.h>
+#if 1 //__MSTC__, Eric, Qos policer.
+#include "skb_defines.h"
+#define RED 1
+#define YELLOW 2
+#define GREEN 3
+#endif
+#if 1//__MSTC__, Jones For compilation
+#define MODE_TBF 0
+#define MODE_SRTCM 1
+#define MODE_TRTCM 2
+#endif
+static DEFINE_SPINLOCK(policer_lock);
+#if 1//__MSTC__, Jones For compilation
+static bool
+ebt_policer_match(const struct sk_buff *skb, struct xt_action_param *par)
+
+{
+ struct ebt_policer_info *r = (struct ebt_policer_info *)par->matchinfo;
+ unsigned long now = jiffies;
+ unsigned long timePassed = 0;
+ struct sk_buff *tmp;
+ u_int32_t cost = 0;
+ u_int32_t extraCredit = 0;
+ spin_lock_bh(&policer_lock);
+
+#if 1 //__OBM__, Jones
+#if defined(CONFIG_MIPS_BRCM) && defined(CONFIG_BLOG)
+ blog_skip((struct sk_buff *)skb, blog_skip_reason_nf_ebt_skiplog);
+#endif
+#endif
+
+ //printk(KERN_EMERG "111__skb->mark=%x\n\r", skb->mark);
+ switch(r->policerMode) {
+ /* Token Bucket Filter (tbf) mode */
+ /* The algorithm used is the Simple Token Bucket Filter (TBF)
+ see net/sched/sch_tbf.c in the linux source tree. */
+ case MODE_TBF:
+ r->credit += (now - xchg(&r->prev, now)) * r->rate; /* Add TBF cerdit */
+ if (r->credit > r->creditCap) {
+ r->credit = r->creditCap;
+ }
+ cost = (skb->len + skb->mac_len) * BITS_PER_BYTE;
+ if (r->credit >= cost) {
+ /* We're not limited. (Match) */
+ r->credit -= cost; /* Take out credit */
+ spin_unlock_bh(&policer_lock);
+ //printk(KERN_EMERG "222__skb->mark=%x\n\r", skb->mark);
+ return true;
+ break;
+ }
+ /* We're limited. (Not Match) */
+ spin_unlock_bh(&policer_lock);
+ //printk(KERN_EMERG "333__skb->mark=%x\n\r", skb->mark);
+ return false;
+ break;
+
+ /* Single Rate Three Color Marker (srTCM) Mode */
+ case MODE_SRTCM:
+ /* Add CBS first */
+ r->credit += (now - xchg(&r->prev, now)) * r->rate; /* Add CBS cerdit */
+ if (r->credit > r->creditCap) {
+ extraCredit = r->credit - r->creditCap;
+ r->credit = r->creditCap;
+ }
+ if (r->pbsCredit < r->pbsCreditCap && extraCredit > 0) {
+ r->pbsCredit += extraCredit; /* Add EBS cerdit */
+ if (r->pbsCredit > r->pbsCreditCap) {
+ r->pbsCredit = r->pbsCreditCap;
+ }
+ }
+ cost = (skb->len + skb->mac_len) * BITS_PER_BYTE;
+ tmp = (struct sk_buff *)skb;
+ if (r->credit >= cost) {
+ tmp->mark &= ~(SKBMARK_POLICER_M); /* Reset 2 color bit */
+ tmp->mark |= SKBMARK_SET_POLICER(0 , GREEN); /* Green */
+ r->credit -= cost;
+ }
+ else if (r->pbsCredit >= cost) {
+ tmp->mark &= ~(SKBMARK_POLICER_M); /* Reset 2 color bit */
+ tmp->mark |= SKBMARK_SET_POLICER(0 , YELLOW); /* Yellow */
+ r->pbsCredit -= cost;
+ }
+ else {
+ tmp->mark &= ~(SKBMARK_POLICER_M); /* Reset 2 color bit */
+ tmp->mark |= SKBMARK_SET_POLICER(0 , RED); /* Red */
+ }
+ spin_unlock_bh(&policer_lock);
+ return true;
+ break;
+
+ /* Two Rate Three Color Marker (srTCM) Mode */
+ case MODE_TRTCM:
+ timePassed = (now - xchg(&r->prev, now));
+ r->credit += timePassed * r->rate; /* Add CBS cerdit */
+ r->pbsCredit += timePassed * r->pRate; /* Add PBS cerdit */
+ if (r->credit > r->creditCap) {
+ r->credit = r->creditCap;
+ }
+ if (r->pbsCredit > r->pbsCreditCap) {
+ r->pbsCredit = r->pbsCreditCap;
+ }
+ cost = (skb->len + skb->mac_len) * BITS_PER_BYTE;
+ tmp = (struct sk_buff *)skb;
+ if (r->pbsCredit < cost) {
+ tmp->mark &= ~(SKBMARK_POLICER_M); /* Reset 2 color bit */
+ tmp->mark |= SKBMARK_SET_POLICER(0 , RED); /* Red */
+ }
+ else if (r->credit < cost) {
+ tmp->mark &= ~(SKBMARK_POLICER_M); /* Reset 2 color bit */
+ tmp->mark |= SKBMARK_SET_POLICER(0 , YELLOW); /* Yellow */
+ r->pbsCredit -= cost;
+ }
+ else {
+ tmp->mark &= ~(SKBMARK_POLICER_M); /* Reset 2 color bit */
+ tmp->mark |= SKBMARK_SET_POLICER(0 , GREEN); /* Green */
+ r->pbsCredit -= cost;
+ r->credit -= cost;
+ }
+ spin_unlock_bh(&policer_lock);
+ return true;
+ break;
+
+ default:
+ return false;
+ }
+}
+/* end ipt_policer_match */
+#else
+#if 0 // __MSTC__, ZyXEL richard, QoS
+static int ebt_policer_match(const struct sk_buff *skb,
+ const struct net_device *in,
+ const struct net_device *out,
+ const void *data,
+ unsigned int datalen)
+{
+ struct ebt_policer_info *info = (struct ebt_policer_info *)data;
+ unsigned long now = jiffies;
+
+ spin_lock_bh(&policer_lock);
+ info->credit += (now - xchg(&info->prev, now)) * info->avg; /* Add credit. */
+ if (info->credit > info->credit_cap) {
+ info->credit = info->credit_cap;
+ }
+ u_int32_t temp_cost = 0;
+ temp_cost = (skb->len + skb->mac_len) * info->cost;
+ if (info->credit >= temp_cost) {
+ /* We're not limited. */
+ info->credit -= temp_cost; /* Take out credit */
+ spin_unlock_bh(&policer_lock);
+ return EBT_MATCH;
+ }
+
+ spin_unlock_bh(&policer_lock);
+ return EBT_NOMATCH;
+}
+#else
+static bool ebt_policer_match(const struct sk_buff *skb, const struct xt_match_param *par)
+{
+ struct ebt_policer_info *info = par->matchinfo;
+ unsigned long now = jiffies;
+
+ spin_lock_bh(&policer_lock);
+ info->credit += (now - xchg(&info->prev, now)) * info->avg; /* Add credit. */
+ if (info->credit > info->credit_cap) {
+ info->credit = info->credit_cap;
+ }
+
+ u_int32_t temp_cost;
+ temp_cost = (skb->len + skb->mac_len) * info->cost;
+ if (info->credit >= temp_cost) {
+ /* We're not limited. */
+ info->credit -= temp_cost; /* Take out credit */
+ spin_unlock_bh(&policer_lock);
+ return true;
+ ////return false;
+ }
+
+ spin_unlock_bh(&policer_lock);
+
+ return false;
+ ////return true;
+}
+#endif // __MSTC__, ZyXEL richard, QoS
+#endif
+
+#if 1//__MSTC__, Jones For compilation
+/* Precision saver. */
+/* As a policer rule added, this function will be executed */
+static int ebt_policer_check(const struct xt_mtchk_param *par)
+{
+ struct ebt_policer_info *r = par->matchinfo;
+
+ /* pRate must be equal or greater than crate. */
+ if (r->policerMode == 2) {
+ if (r->rate > r->pRate) {
+ return -EINVAL;
+ }
+ }
+
+ if (r->creditCap == 0) { /* Check if policer initiate or not. */
+ switch(r->policerMode) {
+ case MODE_TBF:
+ r->prev = jiffies;
+ r->creditCap = r->burst * BITS_PER_BYTE * KILO_SCALE; /* TBF Credits full */
+ r->credit = r->creditCap; /* TBF Credits full */
+ break;
+
+ case MODE_SRTCM:
+ r->prev = jiffies;
+ r->creditCap = r->burst * BITS_PER_BYTE * KILO_SCALE; /* CBS Credits full */
+ r->credit = r->creditCap; /* CBS Credits full */
+ r->pbsCreditCap = r->pbsBurst * BITS_PER_BYTE * KILO_SCALE; /* EBS Credits full */
+ r->pbsCredit = r->pbsCreditCap; /* EBS Credits full */
+ break;
+
+ case MODE_TRTCM:
+ r->prev = jiffies;
+ r->creditCap = r->burst * BITS_PER_BYTE * KILO_SCALE; /* CBS Credits full. */
+ r->credit = r->creditCap; /* CBS Credits full. */
+ r->pbsCreditCap = r->pbsBurst * BITS_PER_BYTE * KILO_SCALE; /* PBS Credits full. */
+ r->pbsCredit = r->pbsCreditCap; /* PBS Credits full. */
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+#else
+/* Precision saver. */
+/* As a policer rule added, this function will be executed */
+#if 0 // __MSTC__, ZyXEL richard, QoS
+static int ebt_policer_check(const char *tablename,
+ unsigned int hookmask,
+ const struct ebt_entry *e,
+ void *data,
+ unsigned int datalen)
+{
+ struct ebt_policer_info *info = (struct ebt_policer_info *)data;
+
+ if (datalen != EBT_ALIGN(sizeof(struct ebt_policer_info))) {
+ return -EINVAL;
+ }
+
+ info->prev = jiffies;
+ info->credit_cap = info->burst * BITS_PER_BYTE * KILO_SCALE; /*Credits full.*/
+ info->credit = info->burst * BITS_PER_BYTE * KILO_SCALE; /*Credits full.*/
+ info->cost = BITS_PER_BYTE;
+
+ return 0;
+}
+#else
+static bool ebt_policer_check(const struct xt_mtchk_param *par)
+{
+ struct ebt_policer_info *info = par->matchinfo;
+
+ /***if (par->datalen != EBT_ALIGN(sizeof(struct ebt_policer_info))) {
+ return -EINVAL;
+ }***/
+
+ info->prev = jiffies;
+ info->credit_cap = info->burst * BITS_PER_BYTE * KILO_SCALE; /*Credits full.*/
+ info->credit = info->burst * BITS_PER_BYTE * KILO_SCALE; /*Credits full.*/
+ info->cost = BITS_PER_BYTE;
+
+ return true;
+}
+#endif // __MSTC__, ZyXEL richard, QoS
+#endif
+
+#if 0 // __MSTC__, ZyXEL richard, QoS
+static struct ebt_match ebt_policer_reg =
+#else
+static struct xt_match ebt_policer_reg __read_mostly =
+#endif
+{
+ .name = EBT_POLICER_MATCH,
+#if 1 // __MSTC__, ZyXEL richard, QoS
+ .revision = 0,
+ .family = NFPROTO_BRIDGE,
+ .match = ebt_policer_match,
+ .checkentry = ebt_policer_check,
+ .matchsize = XT_ALIGN(sizeof(struct ebt_policer_info)),
+#else
+ .check = ebt_policer_check,
+ .match = ebt_policer_match,
+#endif // __MSTC__, ZyXEL richard, QoS
+ .me = THIS_MODULE,
+};
+
+static int __init ebt_policer_init(void)
+{
+#if 0 // __MSTC__, ZyXEL richard, QoS
+ return ebt_register_match(&ebt_policer_reg);
+#else
+ return xt_register_match(&ebt_policer_reg);
+#endif // __MSTC__, ZyXEL richard, QoS
+}
+
+static void __exit ebt_policer_fini(void)
+{
+#if 0 // __MSTC__, ZyXEL richard, QoS
+ ebt_unregister_match(&ebt_policer_reg);
+#else
+ xt_unregister_match(&ebt_policer_reg);
+#endif
+}
+
+module_init(ebt_policer_init);
+module_exit(ebt_policer_fini);
+MODULE_LICENSE("GPL");
+
Index: linux-4.1.52/net/bridge/netfilter/ebt_vlan.c
===================================================================
--- linux-4.1.52.orig/net/bridge/netfilter/ebt_vlan.c 2017-10-17 06:54:53.000000000 +0800
+++ linux-4.1.52/net/bridge/netfilter/ebt_vlan.c 2018-01-22 14:21:12.865630793 +0800
@@ -129,7 +129,9 @@
* Any value of user_priority are acceptable,
* but should be ignored according to 802.1Q Std.
* So we just drop the prio flag. */
+#if 0 /* ZyXEL QoS, John (porting from MSTC) */
info->bitmask &= ~EBT_VLAN_PRIO;
+#endif
}
/* Else, id=0 (null VLAN ID) => user_priority range (any?) */
}
Index: linux-4.1.52/net/bridge/netfilter/ebtables.c
===================================================================
--- linux-4.1.52.orig/net/bridge/netfilter/ebtables.c 2017-10-17 06:54:53.000000000 +0800
+++ linux-4.1.52/net/bridge/netfilter/ebtables.c 2018-01-22 14:21:12.869630793 +0800
@@ -31,6 +31,10 @@
/* needed for logical [in,out]-dev filtering */
#include "../br_private.h"
+#if 1 /* ZyXEL QoS, John */
+#include <linux/if_vlan.h>
+#endif
+
#define BUGPRINT(format, args...) printk("kernel msg: ebtables bug: please "\
"report to author: "format, ## args)
/* #define BUGPRINT(format, args...) */
@@ -124,10 +128,16 @@
#define FWINV2(bool, invflg) ((bool) ^ !!(e->invflags & invflg))
/* process standard matches */
-static inline int
-ebt_basic_match(const struct ebt_entry *e, const struct sk_buff *skb,
+
+#if 0 /* ZyXEL QoS, in order to filter VLAN, John (porting from MSTC) */
+static inline int ebt_basic_match(struct ebt_entry *e, struct ethhdr *h,
+ const struct net_device *in, const struct net_device *out)
+{
+#else
+static inline int ebt_basic_match(struct ebt_entry *e, struct sk_buff *skb,
const struct net_device *in, const struct net_device *out)
{
+#endif
const struct ethhdr *h = eth_hdr(skb);
const struct net_bridge_port *p;
__be16 ethproto;
@@ -138,13 +148,29 @@
else
ethproto = h->h_proto;
+#if 0 /* ZyXEL QoS, in order to filter VLAN, John (porting from MSTC) */
if (e->bitmask & EBT_802_3) {
if (FWINV2(ntohs(ethproto) >= ETH_P_802_3_MIN, EBT_IPROTO))
return 1;
} else if (!(e->bitmask & EBT_NOPROTO) &&
FWINV2(e->ethproto != ethproto, EBT_IPROTO))
return 1;
-
+#else
+ h = eth_hdr(skb);
+ if (e->bitmask & EBT_802_3) {
+ if (FWINV2(ntohs(h->h_proto) >= 1536, EBT_IPROTO))
+ return 1;
+ } else if (!(e->bitmask & EBT_NOPROTO) ){
+ if(e->ethproto == ETH_P_8021Q && ethproto!=ETH_P_8021Q) {/*If protocol type of rule is 802.1q and packet header is not 802.1q*/
+ /* for new broadcom vlan device */
+ if(FWINV2(!(ntohs(((struct vlan_hdr *)(skb->vlan_header))->h_vlan_encapsulated_proto)), EBT_IPROTO))
+ return 1;
+ }else{
+ if(FWINV2(e->ethproto != ethproto, EBT_IPROTO))
+ return 1;
+ }
+ }
+#endif
if (FWINV2(ebt_dev_check(e->in, in), EBT_IIN))
return 1;
if (FWINV2(ebt_dev_check(e->out, out), EBT_IOUT))
@@ -220,9 +246,13 @@
base = private->entries;
i = 0;
while (i < nentries) {
+#if 0 /* ZyXEL QoS, in order to filter VLAN, John(porting from MSTC) */
+ if (ebt_basic_match(point, eth_hdr(skb), in, out))
+ goto letscontinue;
+#else
if (ebt_basic_match(point, skb, in, out))
goto letscontinue;
-
+#endif
if (EBT_MATCH_ITERATE(point, ebt_do_match, skb, &acpar) != 0)
goto letscontinue;
if (acpar.hotdrop) {
Index: linux-4.1.52/net/core/gen_estimator.c
===================================================================
--- linux-4.1.52.orig/net/core/gen_estimator.c 2017-10-17 06:54:53.000000000 +0800
+++ linux-4.1.52/net/core/gen_estimator.c 2018-01-22 16:16:19.589798018 +0800
@@ -86,9 +86,15 @@
spinlock_t *stats_lock;
int ewma_log;
u64 last_bytes;
+#if 1 /* ZyXEL QoS, porting from MSTC */
+ u64 last_dropbytes;
+#endif
u64 avbps;
u32 last_packets;
u32 avpps;
+#if 1 /* ZyXEL QoS, porting from MSTC */
+ u32 avdropbps;
+#endif
struct rcu_head e_rcu;
struct rb_node node;
struct gnet_stats_basic_cpu __percpu *cpu_bstats;
@@ -119,6 +125,9 @@
list_for_each_entry_rcu(e, &elist[idx].list, list) {
struct gnet_stats_basic_packed b = {0};
u64 brate;
+#if 1 /* ZyXEL QoS, porting from MSTC */
+ u64 ndropbytes;
+#endif
u32 rate;
spin_lock(e->stats_lock);
@@ -127,12 +136,19 @@
goto skip;
__gnet_stats_copy_basic(&b, e->cpu_bstats, e->bstats);
-
+#if 1 /* ZyXEL QoS, porting from MSTC */
+ ndropbytes = e->bstats->dropbytes;
+#endif
brate = (b.bytes - e->last_bytes)<<(7 - idx);
e->last_bytes = b.bytes;
e->avbps += (brate >> e->ewma_log) - (e->avbps >> e->ewma_log);
e->rate_est->bps = (e->avbps+0xF)>>5;
-
+#if 1 /* ZyXEL QoS, porting from MSTC */
+ rate = (ndropbytes - e->last_dropbytes)<<(7 - idx);
+ e->last_dropbytes = ndropbytes;
+ e->avdropbps += ((long)rate - (long)e->avdropbps) >> e->ewma_log;
+ e->rate_est->dropbps = (e->avdropbps+0xF)>>5;
+#endif
rate = (b.packets - e->last_packets)<<(12 - idx);
e->last_packets = b.packets;
e->avpps += (rate >> e->ewma_log) - (e->avpps >> e->ewma_log);
Index: linux-4.1.52/net/netfilter/Kconfig
===================================================================
--- linux-4.1.52.orig/net/netfilter/Kconfig 2018-01-22 14:21:12.737630790 +0800
+++ linux-4.1.52/net/netfilter/Kconfig 2018-01-22 14:21:12.869630793 +0800
@@ -636,6 +636,21 @@
"Use netfilter MARK value as routing key") and can also be used by
other subsystems to change their behavior.
+config NETFILTER_XT_TARGET_AUTOMAP
+ tristate '"AUTOMAP" target support'
+ depends on NETFILTER_XTABLES
+ help
+
+ This option adds a `AUTOMAP' target, which allows packet auto mapping to Internal Priority Queue by 8021p value, and automaically mark DSCP value.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config NETFILTER_XT_POLICER
+ tristate '"policer" rate limit support'
+ depends on NETFILTER_XTABLES
+ help
+ To compile it as a module, choose M here. If unsure, say N.
+
config NETFILTER_XT_CONNMARK
tristate 'ctmark target and match support'
depends on NF_CONNTRACK
Index: linux-4.1.52/net/netfilter/Makefile
===================================================================
--- linux-4.1.52.orig/net/netfilter/Makefile 2018-01-22 14:21:12.737630790 +0800
+++ linux-4.1.52/net/netfilter/Makefile 2018-01-22 14:21:12.869630793 +0800
@@ -135,6 +135,10 @@
obj-$(CONFIG_NETFILTER_XT_TARGET_TEE) += xt_TEE.o
obj-$(CONFIG_NETFILTER_XT_TARGET_TRACE) += xt_TRACE.o
obj-$(CONFIG_NETFILTER_XT_TARGET_IDLETIMER) += xt_IDLETIMER.o
+# ZyXEL QoS, John (porting from MSTC)
+obj-$(CONFIG_NETFILTER_XT_TARGET_AUTOMAP) += xt_AUTOMAP.o
+# ZyXEL QoS, Mark (porting from MSTC)
+obj-$(CONFIG_NETFILTER_XT_POLICER) += xt_policer.o
ifdef BCM_KF # defined(CONFIG_BCM_KF_NETFILTER)
obj-$(CONFIG_NETFILTER_XT_TARGET_SKIPLOG) += xt_SKIPLOG.o
obj-$(CONFIG_NETFILTER_XT_TARGET_DC) += xt_DC.o
Index: linux-4.1.52/net/netfilter/xt_AUTOMAP.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-4.1.52/net/netfilter/xt_AUTOMAP.c 2018-01-22 14:21:12.873630793 +0800
@@ -0,0 +1,180 @@
+/* x_tables module for setting the IPv4/IPv6 DSCP field, Version 1.8
+ *
+ * (C) 2002 by Harald Welte <laforge@netfilter.org>
+ * based on ipt_FTOS.c (C) 2000 by Matthew G. Marsh <mgm@paktronix.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * See RFC2474 for a description of the DSCP field within the IP Header.
+ *
+ * xt_DSCP.c,v 1.8 2002/08/06 18:41:57 laforge Exp
+*/
+
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <net/dsfield.h>
+#include <linux/if_vlan.h>
+
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_AUTOMAP.h>
+#include <linux/netfilter/xt_DSCP.h>
+#include <net/dsfield.h>
+
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("ipt_AUTOMAP");
+MODULE_ALIAS("ip6t_AUTOMAP");
+
+static int getVlanPrioAndIpHeader(struct sk_buff *skb, unsigned char *prio, struct iphdr **iph){
+ unsigned short TCI;
+ unsigned short id; /* VLAN ID, given from frame TCI */
+ /* Need to recalculate IP header checksum after altering TOS byte */
+ const struct vlan_hdr *fp;
+ struct vlan_hdr _frame;
+ struct iphdr *ih = NULL;
+
+ /* get ip header */
+ ih = NULL;
+ ih = ip_hdr(skb);
+
+ *iph = ih;
+
+ /* check VLAN header is parsed or not ? */
+ if(ntohs(((struct vlan_hdr *)(skb->vlan_header))->h_vlan_encapsulated_proto) == 0){
+
+ /* tagged packet */
+ if(skb->protocol == ETH_P_8021Q) {
+
+ fp = skb_header_pointer(skb, 0, sizeof(_frame), &_frame);
+ if (fp == NULL)
+ return -1;
+
+ /* Tag Control Information (TCI) consists of the following elements:
+ * - User_priority. The user_priority field is three bits in length,
+ * interpreted as a binary number.
+ * - Canonical Format Indicator (CFI). The Canonical Format Indicator
+ * (CFI) is a single bit flag value. Currently ignored.
+ * - VLAN Identifier (VID). The VID is encoded as
+ * an unsigned binary number.
+ */
+ TCI = ntohs(fp->h_vlan_TCI);
+ id = TCI & VLAN_VID_MASK;
+ *prio = (TCI >> 13) & 0x7;
+
+ }
+ else { /* untagged packet */
+ TCI = 0;
+ id = 0;
+ /* Packet with no VLAN tag will be sent to default queue just like 1p value is 1 */
+ *prio = 1;
+ }
+
+ }
+ else{
+ /* for new broadcom vlan device */
+ TCI = ntohs(((struct vlan_hdr *)(skb->vlan_header))->h_vlan_TCI);
+ id = TCI & VLAN_VID_MASK;
+ *prio = (TCI >> 13) & 0x7;
+ }
+
+ return 0;
+}
+
+//static unsigned int target(struct sk_buff **pskb, const struct xt_tgchk_param *par)
+static unsigned int AUTOMAP_target_v4(struct sk_buff *skb, const struct xt_action_param *par)
+ //const struct net_device *in,
+ //const struct net_device *out,
+ //unsigned int hooknum,
+ //const struct xt_target *target,
+ //const void *targinfo)
+{
+ const struct xt_automap_target_info *aminfo = par->targinfo;
+ struct iphdr *iph = NULL;
+ unsigned char prio = 0;
+ unsigned char dscp = 0;
+ unsigned char dscpPrecedence = 0;
+
+ if(aminfo->flags & XT_AUTO_TYPE){
+ getVlanPrioAndIpHeader(skb, &prio, &iph);
+
+ switch(aminfo->type){
+ case AUTOMAP_TYPE_8021P:
+ /* mark priority queue */
+ skb->mark |= vlan8021pToPriorityQueue[prio];
+
+ /* lookup upstream 8021p to DSCP value table */
+ dscp = vlan8021pToDSCP[prio];
+
+ /* mark DSCP value */
+ if (!skb_make_writable(skb, sizeof(struct iphdr)))
+ return NF_DROP;
+
+ ipv4_change_dsfield(ip_hdr(skb), (__u8)(~XT_DSCP_MASK), dscp << XT_DSCP_SHIFT);
+
+ break;
+ case AUTOMAP_TYPE_DSCP:
+ /* get dscp precedence */
+ dscpPrecedence = ((iph->tos)>>5)&0x7;
+
+ /* mark priority queue */
+ skb->mark |= dscpPrecedenceToPriorityQueue[dscpPrecedence];
+
+ /* it should mark 8021p here, TBD */
+
+ break;
+ case AUTOMAP_TYPE_PKTLEN:
+
+ if(iph->tot_len > 1100){
+ skb->mark|=vlan8021pToPriorityQueue[0]; /* queue priority 2 */
+ }else if(iph->tot_len < 250){
+ skb->mark|=vlan8021pToPriorityQueue[5]; /* queue priority 5 */
+ }else{ /*250~1100*/
+ skb->mark|=vlan8021pToPriorityQueue[3]; /* queue priority 3 */
+ }
+ break;
+ default:
+ printk("unknown AUTOMAP type: \n");
+ break;
+ }
+ }
+
+ return XT_CONTINUE;
+}
+
+
+static int AUTOMAP_checkentry_v4(const struct xt_tgchk_param *par)
+{
+ return 0;
+}
+
+static struct xt_target xt_auto_target __read_mostly = {
+
+ .name = "AUTOMAP",
+ .revision = 0,
+ .family = NFPROTO_IPV4,
+ .checkentry = AUTOMAP_checkentry_v4,
+ .target = AUTOMAP_target_v4,
+ .targetsize = sizeof(struct xt_automap_target_info),
+ .table = "mangle",
+ .me = THIS_MODULE,
+
+};
+
+static int __init xt_automap_target_init(void)
+{
+ //return xt_register_targets(xt_auto_target, ARRAY_SIZE(xt_auto_target));
+ return xt_register_target(&xt_auto_target);
+}
+
+static void __exit xt_automap_target_fini(void)
+{
+ //xt_unregister_targets(xt_auto_target, ARRAY_SIZE(xt_auto_target));
+ xt_unregister_target(&xt_auto_target);
+}
+
+module_init(xt_automap_target_init);
+module_exit(xt_automap_target_fini);
Index: linux-4.1.52/net/netfilter/xt_mark.c
===================================================================
--- linux-4.1.52.orig/net/netfilter/xt_mark.c 2018-01-22 14:21:12.769630791 +0800
+++ linux-4.1.52/net/netfilter/xt_mark.c 2018-01-22 14:21:12.873630793 +0800
@@ -24,6 +24,49 @@
MODULE_ALIAS("ipt_MARK");
MODULE_ALIAS("ip6t_MARK");
+#if 1 /* ZyXEL QoS, John (porting from MSTC) */
+#include "skb_defines.h"
+#endif
+
+#if 1 /* ZyXEL QoS, John */
+static unsigned int
+mark_tg(struct sk_buff *skb, const struct xt_action_param *par)
+{
+ const struct xt_mark_tginfo2 *markinfo = par->targinfo;
+ int mark = 0;
+
+ switch (markinfo->mode) {
+ case XT_MARK_SET:
+ mark = markinfo->mark;
+ break;
+
+ case XT_MARK_AND:
+ mark = skb->mark & markinfo->mark;
+ break;
+
+ case XT_MARK_OR:
+ mark = skb->mark | markinfo->mark;
+ break;
+
+ case XT_MARK_VTAG_SET:
+ mark = skb->mark;
+ skb->vtag = (unsigned short)(markinfo->mark);
+ break;
+ }
+
+#if defined(CONFIG_BCM_KF_BLOG) && defined(CONFIG_BLOG_FEATURE)
+ skb->ipt_check |= IPT_TARGET_MARK;
+ skb->ipt_log.u32[BLOG_ORIGINAL_MARK_INDEX] = skb->mark;
+ skb->ipt_log.u32[BLOG_TARGET_MARK_INDEX] = mark;
+ if ( skb->ipt_check & IPT_TARGET_CHECK )
+ return XT_CONTINUE;
+#endif
+
+ skb->mark = mark;
+ return XT_CONTINUE;
+}
+
+#else
static unsigned int
mark_tg(struct sk_buff *skb, const struct xt_action_param *par)
{
@@ -41,6 +84,7 @@
skb->mark = (skb->mark & ~info->mask) ^ info->mark;
return XT_CONTINUE;
}
+#endif
static bool
mark_mt(const struct sk_buff *skb, struct xt_action_param *par)
Index: linux-4.1.52/net/netfilter/xt_policer.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-4.1.52/net/netfilter/xt_policer.c 2018-01-22 16:32:14.193821131 +0800
@@ -0,0 +1,382 @@
+/* Kernel module to control the rate in kbps. */
+/* This program is free software; you can redistribute it and/or modify
+ * * it under the terms of the GNU General Public License version 2 as
+ * * published by the Free Software Foundation. */
+/* ZyXEL Birken, 20100107. */
+
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_policer.h>
+#if 1 //__MSTC__, Eric, Qos policer.
+#include "skb_defines.h"
+#define RED 1
+#define YELLOW 2
+#define GREEN 3
+#endif
+#if 1//__MSTC__, Jones For compilation
+#define MODE_TBF 0
+#define MODE_SRTCM 1
+#define MODE_TRTCM 2
+#endif
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Herve Eychenne <rv@wallfire.org>");
+MODULE_DESCRIPTION("iptables rate policer match");
+MODULE_ALIAS("ipt_policer");
+MODULE_ALIAS("ip6t_policer");
+
+/* The algorithm used is the Simple Token Bucket Filter (TBF)
+ * * see net/sched/sch_tbf.c in the linux source tree. */
+
+static DEFINE_SPINLOCK(policer_lock);
+
+#if 0 //__MSTC__, richard, QoS
+static int
+ipt_policer_match(const struct sk_buff *skb,
+ const struct net_device *in,
+ const struct net_device *out,
+ const struct xt_match *match,
+ const void *matchinfo,
+ int offset,
+ unsigned int protoff,
+ int *hotdrop)
+#else
+static bool ipt_policer_match(const struct sk_buff *skb, struct xt_action_param *par)
+#endif //__MSTC__, richard, QoS
+{
+#if 1//__MSTC__, Jones For compilation
+ struct xt_policerinfo *r = (struct xt_policerinfo *)par->matchinfo;
+ unsigned long now = jiffies;
+ unsigned long timePassed = 0;
+ struct sk_buff *tmp;
+ u_int32_t cost = 0;
+ u_int32_t extraCredit = 0;
+ spin_lock_bh(&policer_lock);
+
+#if 1 //__OBM__, Jones
+#if defined(CONFIG_MIPS_BRCM) && defined(CONFIG_BLOG)
+ blog_skip((struct sk_buff *)skb, blog_skip_reason_nf_xt_skiplog);
+#endif
+#endif
+ switch(r->policerMode) {
+ /* Token Bucket Filter (tbf) mode */
+ /* The algorithm used is the Simple Token Bucket Filter (TBF)
+ see net/sched/sch_tbf.c in the linux source tree. */
+ case MODE_TBF:
+ r->credit += (now - xchg(&r->prev, now)) * r->rate; /* Add TBF cerdit */
+ if (r->credit > r->creditCap) {
+ r->credit = r->creditCap;
+ }
+ cost = (skb->len + skb->mac_len) * BITS_PER_BYTE;
+ if (r->credit >= cost) {
+ /* We're not limited. (Match) */
+ r->credit -= cost; /* Take out credit */
+ spin_unlock_bh(&policer_lock);
+ return true;
+ break;
+ }
+ /* We're limited. (Not Match) */
+ spin_unlock_bh(&policer_lock);
+ return false;
+ break;
+
+ /* Single Rate Three Color Marker (srTCM) Mode */
+ case MODE_SRTCM:
+ /* Add CBS first */
+ r->credit += (now - xchg(&r->prev, now)) * r->rate; /* Add CBS cerdit */
+ if (r->credit > r->creditCap) {
+ extraCredit = r->credit - r->creditCap;
+ r->credit = r->creditCap;
+ }
+ if (r->pbsCredit < r->pbsCreditCap && extraCredit > 0) {
+ r->pbsCredit += extraCredit; /* Add EBS cerdit */
+ if (r->pbsCredit > r->pbsCreditCap) {
+ r->pbsCredit = r->pbsCreditCap;
+ }
+ }
+ cost = (skb->len + skb->mac_len) * BITS_PER_BYTE;
+ tmp = (struct sk_buff *)skb;
+ if (r->credit >= cost) {
+ tmp->mark &= ~(SKBMARK_POLICER_M); /* Reset 2 color bit */
+ tmp->mark |= SKBMARK_SET_POLICER(0 , GREEN); /* Green */
+ r->credit -= cost;
+ }
+ else if (r->pbsCredit >= cost) {
+ tmp->mark &= ~(SKBMARK_POLICER_M); /* Reset 2 color bit */
+ tmp->mark |= SKBMARK_SET_POLICER(0 , YELLOW); /* Yellow */
+ r->pbsCredit -= cost;
+ }
+ else {
+ tmp->mark &= ~(SKBMARK_POLICER_M); /* Reset 2 color bit */
+ tmp->mark |= SKBMARK_SET_POLICER(0 , RED); /* Red */
+ }
+ spin_unlock_bh(&policer_lock);
+ return true;
+ break;
+
+ /* Two Rate Three Color Marker (srTCM) Mode */
+ case MODE_TRTCM:
+ timePassed = (now - xchg(&r->prev, now));
+ r->credit += timePassed * r->rate; /* Add CBS cerdit */
+ r->pbsCredit += timePassed * r->pRate; /* Add PBS cerdit */
+ if (r->credit > r->creditCap) {
+ r->credit = r->creditCap;
+ }
+ if (r->pbsCredit > r->pbsCreditCap) {
+ r->pbsCredit = r->pbsCreditCap;
+ }
+ cost = (skb->len + skb->mac_len) * BITS_PER_BYTE;
+ tmp = (struct sk_buff *)skb;
+ if (r->pbsCredit < cost) {
+ tmp->mark &= ~(SKBMARK_POLICER_M); /* Reset 2 color bit */
+ tmp->mark |= SKBMARK_SET_POLICER(0 , RED); /* Red */
+ }
+ else if (r->credit < cost) {
+ tmp->mark &= ~(SKBMARK_POLICER_M); /* Reset 2 color bit */
+ tmp->mark |= SKBMARK_SET_POLICER(0 , YELLOW); /* Yellow */
+ r->pbsCredit -= cost;
+ }
+ else {
+ tmp->mark &= ~(SKBMARK_POLICER_M); /* Reset 2 color bit */
+ tmp->mark |= SKBMARK_SET_POLICER(0 , GREEN); /* Green */
+ r->pbsCredit -= cost;
+ r->credit -= cost;
+ }
+ spin_unlock_bh(&policer_lock);
+ return true;
+ break;
+
+ default:
+ return false;
+ }
+#else
+#if 0 //__MSTC__, richard, QoS
+ struct xt_policerinfo *r = ((struct xt_policerinfo *)matchinfo)->master;
+#else
+ struct xt_policerinfo *r = (struct xt_policerinfo *)par->matchinfo;
+#endif //__MSTC__, richard, QoS
+
+ unsigned long now = jiffies;
+ spin_lock_bh(&policer_lock);
+ r->credit += (now - xchg(&r->prev, now)) * r->avg; /* Add cerdit */
+ if (r->credit > r->credit_cap) {
+ r->credit = r->credit_cap;
+ }
+ u_int32_t temp_cost = 0;
+ temp_cost = (skb->len + skb->mac_len) * r->cost;
+ if (r->credit >= temp_cost) {
+ /* We're not limited. */
+ r->credit -= temp_cost; /* Take out credit */
+ spin_unlock_bh(&policer_lock);
+#if 0 //__MSTC__, richard, QoS
+ return 1;
+#else
+ return true;
+ ////return false;
+#endif //__MSTC__, richard, QoS
+ }
+ spin_unlock_bh(&policer_lock);
+
+#if 0 //__MSTC__, richard, QoS
+ return 0;
+#else
+ return false;
+ ////return true;
+#endif //__MSTC__, richard, QoS
+#endif
+}
+
+
+#if 1//__MSTC__, Jones For compilation
+/* Precision saver. */
+/* As a policer rule added, this function will be executed */
+static int
+ipt_policer_checkentry(const struct xt_mtchk_param *par)
+{
+ struct xt_policerinfo *r = (struct xt_policerinfo *)par->matchinfo;
+ /* For SMP, we only want to use one set of counters. */
+ r->master = r;
+
+ /* pRate must be equal or greater than crate. */
+ if (r->policerMode == 2) {
+ if (r->rate > r->pRate) {
+ return -EINVAL;
+ }
+ }
+
+ if (r->creditCap == 0) { /* Check if policer initiate or not. */
+ switch(r->policerMode) {
+ case MODE_TBF:
+ r->prev = jiffies;
+ r->creditCap = r->burst * BITS_PER_BYTE * KILO_SCALE; /* TBF Credits full */
+ r->credit = r->creditCap; /* TBF Credits full */
+ break;
+
+ case MODE_SRTCM:
+ r->prev = jiffies;
+ r->creditCap = r->burst * BITS_PER_BYTE * KILO_SCALE; /* CBS Credits full */
+ r->credit = r->creditCap; /* CBS Credits full */
+ r->pbsCreditCap = r->pbsBurst * BITS_PER_BYTE * KILO_SCALE; /* EBS Credits full */
+ r->pbsCredit = r->pbsCreditCap; /* EBS Credits full */
+ break;
+
+ case MODE_TRTCM:
+ r->prev = jiffies;
+ r->creditCap = r->burst * BITS_PER_BYTE * KILO_SCALE; /* CBS Credits full. */
+ r->credit = r->creditCap; /* CBS Credits full. */
+ r->pbsCreditCap = r->pbsBurst * BITS_PER_BYTE * KILO_SCALE; /* PBS Credits full. */
+ r->pbsCredit = r->pbsCreditCap; /* PBS Credits full. */
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+/* end ipt_policer_checkentry */
+#else
+/* Precision saver. */
+/* As a policer rule added, this function will be executed */
+#if 0 //__MSTC__, richard, QoS
+static int
+ipt_policer_checkentry(const char *tablename,
+ const void *inf,
+ const struct xt_match *match,
+ void *matchinfo,
+ unsigned int hook_mask)
+#else
+static bool
+ipt_policer_checkentry(const struct xt_mtchk_param *par)
+#endif //__MSTC__, richard, QoS
+{
+#if 0 //__MSTC__, richard, QoS
+ struct xt_policerinfo *r = matchinfo;
+#else
+ struct xt_policerinfo *r = (struct xt_policerinfo *)par->matchinfo;
+#endif //__MSTC__, richard, QoS
+
+ /* For SMP, we only want to use one set of counters. */
+ r->master = r;
+ if (r->cost == 0) {
+ r->prev = jiffies;
+ r->credit_cap = r->burst * BITS_PER_BYTE * KILO_SCALE; /*Credits full.*/
+ r->credit = r->credit_cap; /*Credits full.*/
+ r->cost = BITS_PER_BYTE;
+ }
+#if 0 //__MSTC__, richard, QoS
+ return 1;
+#else
+ return true;
+#endif //__MSTC__, richard, QoS
+}
+#endif
+
+////#if 0 /* We do not know what this is for. Comment it temporarily. ZyXEL Birken, 20100107. */
+#ifdef CONFIG_COMPAT
+struct compat_xt_rateinfo {
+ u_int32_t avg;
+ u_int32_t burst;
+
+ compat_ulong_t prev;
+ u_int32_t credit;
+ u_int32_t credit_cap, cost;
+
+ u_int32_t master;
+};
+
+/* To keep the full "prev" timestamp, the upper 32 bits are stored in the
+ * * master pointer, which does not need to be preserved. */
+static void compat_from_user(void *dst, void *src)
+{
+ struct compat_xt_rateinfo *cm = src;
+ struct xt_policerinfo m = {
+ .avg = cm->avg,
+ .burst = cm->burst,
+ .prev = cm->prev | (unsigned long)cm->master << 32,
+ .credit = cm->credit,
+ .credit_cap = cm->credit_cap,
+ .cost = cm->cost,
+ };
+ memcpy(dst, &m, sizeof(m));
+}
+
+static int compat_to_user(void __user *dst, void *src)
+{
+ struct xt_policerinfo *m = src;
+ struct compat_xt_rateinfo cm = {
+ .avg = m->avg,
+ .burst = m->burst,
+ .prev = m->prev,
+ .credit = m->credit,
+#if 1//__MSTC__, Jones For compilation
+ .credit_cap = m->creditCap,
+#else
+ .credit_cap = m->credit_cap,
+#endif
+ .cost = m->cost,
+ .master = m->prev >> 32,
+ };
+ return copy_to_user(dst, &cm, sizeof(cm)) ? -EFAULT : 0;
+}
+#endif /* CONFIG_COMPAT */
+////#endif
+
+#if 0 //__MSTC__, richard, QoS
+static struct xt_match xt_policer_match[] __read_mostly = {
+ {
+#else
+static struct xt_match xt_policer_match __read_mostly = {
+#endif //__MSTC__, richard, QoS
+ .name = "policer",
+#if 0 //__MSTC__, richard, QoS
+ .family = AF_INET,
+#else
+ .family = NFPROTO_UNSPEC,
+#endif //__MSTC__, richard, QoS
+ .checkentry = ipt_policer_checkentry,
+ .match = ipt_policer_match,
+ .matchsize = sizeof(struct xt_policerinfo),
+#ifdef CONFIG_COMPAT
+ .compatsize = sizeof(struct compat_xt_rateinfo),
+ .compat_from_user = compat_from_user,
+ .compat_to_user = compat_to_user,
+#endif
+ .me = THIS_MODULE,
+#if 0 //__MSTC__, richard, QoS
+ },
+ {
+ .name = "policer",
+ .family = AF_INET6,
+ .checkentry = ipt_policer_checkentry,
+ .match = ipt_policer_match,
+ .matchsize = sizeof(struct xt_policerinfo),
+ .me = THIS_MODULE,
+ },
+#endif //__MSTC__, richard, QoS
+};
+
+static int __init xt_policer_init(void)
+{
+#if 0 //__MSTC__, richard, QoS
+ return xt_register_matches(xt_policer_match, ARRAY_SIZE(xt_policer_match));
+#else
+ return xt_register_match(&xt_policer_match);
+#endif //__MSTC__, richard, QoS
+}
+
+static void __exit xt_policer_fini(void)
+{
+#if 0 //__MSTC__, richard, QoS
+ xt_unregister_matches(xt_policer_match, ARRAY_SIZE(xt_policer_match));
+#else
+ xt_unregister_match(&xt_policer_match);
+#endif //__MSTC__, richard, QoS
+}
+
+module_init(xt_policer_init);
+module_exit(xt_policer_fini);
+
Index: linux-4.1.52/net/sched/sch_htb.c
===================================================================
--- linux-4.1.52.orig/net/sched/sch_htb.c 2018-01-22 14:21:12.785630791 +0800
+++ linux-4.1.52/net/sched/sch_htb.c 2018-01-22 14:21:12.877630793 +0800
@@ -584,6 +584,9 @@
__skb_queue_tail(&q->direct_queue, skb);
q->direct_pkts++;
} else {
+#if 1 /* ZyXEL QoS, porting from MSTC */
+ sch->bstats.dropbytes += skb->len;
+#endif
return qdisc_drop(skb, sch);
}
#ifdef CONFIG_NET_CLS_ACT
@@ -597,6 +600,9 @@
if (net_xmit_drop_count(ret)) {
qdisc_qstats_drop(sch);
cl->qstats.drops++;
+#if 1 /* ZyXEL QoS, porting from MSTC */
+ sch->bstats.dropbytes += skb->len;
+#endif
}
return ret;
} else {
Index: linux-4.1.52/net/sched/sch_sfq.c
===================================================================
--- linux-4.1.52.orig/net/sched/sch_sfq.c 2017-10-17 06:54:53.000000000 +0800
+++ linux-4.1.52/net/sched/sch_sfq.c 2018-01-22 14:21:12.877630793 +0800
@@ -329,6 +329,9 @@
len = qdisc_pkt_len(skb);
slot->backlog -= len;
sfq_dec(q, x);
+#if 1 /* ZyXEL QoS, porting from MSTC */
+ sch->bstats.dropbytes += skb->len;
+#endif
kfree_skb(skb);
sch->q.qlen--;
qdisc_qstats_drop(sch);
@@ -380,6 +383,9 @@
if (hash == 0) {
if (ret & __NET_XMIT_BYPASS)
qdisc_qstats_drop(sch);
+#if 1 /* ZyXEL QoS, porting from MSTC */
+ sch->bstats.dropbytes += skb->len;
+#endif
kfree_skb(skb);
return ret;
}
@@ -446,6 +452,9 @@
if (slot->qlen >= q->maxdepth) {
congestion_drop:
+#if 1 /* ZyXEL QoS, porting from MSTC */
+ sch->bstats.dropbytes += skb->len;
+#endif
if (!sfq_headdrop(q))
return qdisc_drop(skb, sch);
Index: linux-4.1.52/net/sched/sch_tbf.c
===================================================================
--- linux-4.1.52.orig/net/sched/sch_tbf.c 2017-10-17 06:54:53.000000000 +0800
+++ linux-4.1.52/net/sched/sch_tbf.c 2018-01-22 16:24:04.901809284 +0800
@@ -21,6 +21,9 @@
#include <net/netlink.h>
#include <net/sch_generic.h>
#include <net/pkt_sched.h>
+#if defined(CONFIG_BCM_KF_BLOG) && defined(CONFIG_BLOG) /* ZyXEL QoS, porting from MSTC */
+#include <linux/blog.h>
+#endif
/* Simple Token Bucket Filter.
@@ -202,8 +205,16 @@
}
ret = qdisc_enqueue(skb, q->qdisc);
if (ret != NET_XMIT_SUCCESS) {
+#if 1 /* ZyXEL QoS, porting from MSTC */
if (net_xmit_drop_count(ret))
+ {
qdisc_qstats_drop(sch);
+ sch->bstats.dropbytes += skb->len;
+ }
+#else
+ if (net_xmit_drop_count(ret))
+ qdisc_qstats_drop(sch);
+#endif
return ret;
}
@@ -266,6 +277,9 @@
sch->q.qlen--;
qdisc_unthrottled(sch);
qdisc_bstats_update(sch, skb);
+#if defined(CONFIG_BCM_KF_BLOG) && defined(CONFIG_BLOG) /* ZyXEL QoS, porting from MSTC */
+ blog_skip(skb, blog_skip_reason_sch_htb);
+#endif
return skb;
}