diff --git a/target/linux/generic/hack-5.4/954-add-bcm-fullconenat-support.patch b/target/linux/generic/hack-5.4/954-add-bcm-fullconenat-support.patch new file mode 100644 index 0000000000..41b16c36d6 --- /dev/null +++ b/target/linux/generic/hack-5.4/954-add-bcm-fullconenat-support.patch @@ -0,0 +1,235 @@ +--- a/net/netfilter/nf_nat_masquerade.c ++++ b/net/netfilter/nf_nat_masquerade.c +@@ -8,6 +8,9 @@ + #include + + #include ++#include ++#include ++#include + + struct masq_dev_work { + struct work_struct work; +@@ -23,6 +26,129 @@ static DEFINE_MUTEX(masq_mutex); + static unsigned int masq_refcnt __read_mostly; + static atomic_t masq_worker_count __read_mostly; + ++static void bcm_nat_expect(struct nf_conn *ct, ++ struct nf_conntrack_expect *exp) ++{ ++ struct nf_nat_range2 range; ++ ++ /* This must be a fresh one. */ ++ BUG_ON(ct->status & IPS_NAT_DONE_MASK); ++ ++ /* Change src to where new ct comes from */ ++ range.flags = NF_NAT_RANGE_MAP_IPS; ++ range.min_addr = range.max_addr = ++ ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3; ++ nf_nat_setup_info(ct, &range, NF_NAT_MANIP_SRC); ++ ++ /* For DST manip, map port here to where it's expected. */ ++ range.flags = (NF_NAT_RANGE_MAP_IPS | NF_NAT_RANGE_PROTO_SPECIFIED); ++ range.min_proto = range.max_proto = exp->saved_proto; ++ range.min_addr = range.max_addr = exp->saved_addr; ++ nf_nat_setup_info(ct, &range, NF_NAT_MANIP_DST); ++} ++ ++/****************************************************************************/ ++static int bcm_nat_help(struct sk_buff *skb, unsigned int protoff, ++ struct nf_conn *ct, enum ip_conntrack_info ctinfo) ++{ ++ int dir = CTINFO2DIR(ctinfo); ++ struct nf_conn_help *help = nfct_help(ct); ++ struct nf_conntrack_expect *exp; ++ ++ if (dir != IP_CT_DIR_ORIGINAL || ++ help->expecting[NF_CT_EXPECT_CLASS_DEFAULT]) ++ return NF_ACCEPT; ++ ++ pr_debug("bcm_nat: packet[%d bytes] ", skb->len); ++ nf_ct_dump_tuple(&ct->tuplehash[dir].tuple); ++ pr_debug("reply: "); ++ nf_ct_dump_tuple(&ct->tuplehash[!dir].tuple); ++ ++ /* Create expect */ ++ if ((exp = nf_ct_expect_alloc(ct)) == NULL) ++ return NF_ACCEPT; ++ ++ nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, AF_INET, NULL, ++ &ct->tuplehash[!dir].tuple.dst.u3, IPPROTO_UDP, ++ NULL, &ct->tuplehash[!dir].tuple.dst.u.udp.port); ++ exp->flags = NF_CT_EXPECT_PERMANENT; ++ exp->saved_addr = ct->tuplehash[dir].tuple.src.u3; ++ exp->saved_proto.udp.port = ct->tuplehash[dir].tuple.src.u.udp.port; ++ exp->dir = !dir; ++ exp->expectfn = bcm_nat_expect; ++ ++ /* Setup expect */ ++ nf_ct_expect_related(exp, 0); ++ nf_ct_expect_put(exp); ++ pr_debug("bcm_nat: expect setup\n"); ++ ++ return NF_ACCEPT; ++} ++ ++/****************************************************************************/ ++static struct nf_conntrack_expect_policy bcm_nat_exp_policy __read_mostly = { ++ .max_expected = 1000, ++ .timeout = 240, ++}; ++ ++/****************************************************************************/ ++static struct nf_conntrack_helper nf_conntrack_helper_bcm_nat __read_mostly = { ++ .name = "BCM-NAT", ++ .me = THIS_MODULE, ++ .tuple.src.l3num = AF_INET, ++ .tuple.dst.protonum = IPPROTO_UDP, ++ .expect_policy = &bcm_nat_exp_policy, ++ .expect_class_max = 1, ++ .help = bcm_nat_help, ++}; ++ ++/****************************************************************************/ ++static inline int find_exp(__be32 ip, __be16 port, struct nf_conn *ct) ++{ ++ struct nf_conntrack_tuple tuple; ++ struct nf_conntrack_expect *i = NULL; ++ ++ ++ memset(&tuple, 0, sizeof(tuple)); ++ tuple.src.l3num = AF_INET; ++ tuple.dst.protonum = IPPROTO_UDP; ++ tuple.dst.u3.ip = ip; ++ tuple.dst.u.udp.port = port; ++ ++ rcu_read_lock(); ++ i = __nf_ct_expect_find(nf_ct_net(ct), nf_ct_zone(ct), &tuple); ++ rcu_read_unlock(); ++ ++ return i != NULL; ++} ++ ++/****************************************************************************/ ++static inline struct nf_conntrack_expect *find_fullcone_exp(struct nf_conn *ct) ++{ ++ struct nf_conntrack_tuple * tp = ++ &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple; ++ struct nf_conntrack_expect * exp = NULL; ++ struct nf_conntrack_expect * i; ++ unsigned int h; ++ ++ rcu_read_lock(); ++ for (h = 0; h < nf_ct_expect_hsize; h++) { ++ hlist_for_each_entry_rcu(i, &nf_ct_expect_hash[h], hnode) { ++ if (nf_inet_addr_cmp(&i->saved_addr, &tp->src.u3) && ++ i->saved_proto.all == tp->src.u.all && ++ i->tuple.dst.protonum == tp->dst.protonum && ++ i->tuple.src.u3.ip == 0 && ++ i->tuple.src.u.udp.port == 0) { ++ exp = i; ++ break; ++ } ++ } ++ } ++ rcu_read_unlock(); ++ ++ return exp; ++} ++ + unsigned int + nf_nat_masquerade_ipv4(struct sk_buff *skb, unsigned int hooknum, + const struct nf_nat_range2 *range, +@@ -60,6 +186,72 @@ nf_nat_masquerade_ipv4(struct sk_buff *s + if (nat) + nat->masq_index = out->ifindex; + ++/* RFC 4787 - 4.2.2. Port Parity ++ i.e., an even port will be mapped to an even port, and an odd port will be mapped to an odd port. ++*/ ++#define CHECK_PORT_PARITY(a, b) ((a%2)==(b%2)) ++ if (range->min_addr.ip != 0 /* nat_mode == full cone */ ++ && (nfct_help(ct) == NULL || nfct_help(ct)->helper == NULL) ++ && nf_ct_protonum(ct) == IPPROTO_UDP) { ++ unsigned int ret; ++ u_int16_t minport; ++ u_int16_t maxport; ++ struct nf_conntrack_expect *exp; ++ ++ pr_debug("bcm_nat: need full cone NAT\n"); ++ ++ /* Choose port */ ++ spin_lock_bh(&nf_conntrack_expect_lock); ++ /* Look for existing expectation */ ++ exp = find_fullcone_exp(ct); ++ if (exp) { ++ minport = maxport = exp->tuple.dst.u.udp.port; ++ pr_debug("bcm_nat: existing mapped port = %hu\n", ++ ntohs(minport)); ++ } else { /* no previous expect */ ++ u_int16_t newport, tmpport, orgport; ++ ++ minport = range->min_proto.all == 0? ++ ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src. ++ u.udp.port : range->min_proto.all; ++ maxport = range->max_proto.all == 0? ++ htons(65535) : range->max_proto.all; ++ orgport = ntohs(minport); ++ for (newport = ntohs(minport),tmpport = ntohs(maxport); ++ newport <= tmpport; newport++) { ++ if (CHECK_PORT_PARITY(orgport, newport) && !find_exp(newsrc, htons(newport), ct)) { ++ pr_debug("bcm_nat: new mapped port = " ++ "%hu\n", newport); ++ minport = maxport = htons(newport); ++ break; ++ } ++ } ++ } ++ spin_unlock_bh(&nf_conntrack_expect_lock); ++ ++ ++ memset(&newrange.min_addr, 0, sizeof(newrange.min_addr)); ++ memset(&newrange.max_addr, 0, sizeof(newrange.max_addr)); ++ ++ newrange.flags = range->flags | NF_NAT_RANGE_MAP_IPS | ++ NF_NAT_RANGE_PROTO_SPECIFIED; ++ newrange.max_addr.ip = newrange.min_addr.ip = newsrc; ++ newrange.min_proto.udp.port = newrange.max_proto.udp.port = minport; ++ ++ /* Set ct helper */ ++ ret = nf_nat_setup_info(ct, &newrange, NF_NAT_MANIP_SRC); ++ if (ret == NF_ACCEPT) { ++ struct nf_conn_help *help = nfct_help(ct); ++ if (help == NULL) ++ help = nf_ct_helper_ext_add(ct, GFP_ATOMIC); ++ if (help != NULL) { ++ help->helper = &nf_conntrack_helper_bcm_nat; ++ pr_debug("bcm_nat: helper set\n"); ++ } ++ } ++ return ret; ++ } ++ + /* Transfer from original range. */ + memset(&newrange.min_addr, 0, sizeof(newrange.min_addr)); + memset(&newrange.max_addr, 0, sizeof(newrange.max_addr)); +@@ -347,6 +539,7 @@ EXPORT_SYMBOL_GPL(nf_nat_masquerade_inet + + void nf_nat_masquerade_inet_unregister_notifiers(void) + { ++ nf_conntrack_helper_unregister(&nf_conntrack_helper_bcm_nat); + mutex_lock(&masq_mutex); + /* check if the notifiers still have clients */ + if (--masq_refcnt > 0) +--- a/net/netfilter/xt_MASQUERADE.c ++++ b/net/netfilter/xt_MASQUERADE.c +@@ -42,6 +42,9 @@ masquerade_tg(struct sk_buff *skb, const + range.min_proto = mr->range[0].min; + range.max_proto = mr->range[0].max; + ++ range.min_addr.ip = mr->range[0].min_ip; ++ range.max_addr.ip = mr->range[0].max_ip; ++ + return nf_nat_masquerade_ipv4(skb, xt_hooknum(par), &range, + xt_out(par)); + }