aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/skbuff.h2
-rw-r--r--net/bridge/br_netfilter.c70
2 files changed, 42 insertions, 30 deletions
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 36f3f43c0117..f66a089afc41 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -169,7 +169,7 @@ struct nf_bridge_info {
169 unsigned int mask; 169 unsigned int mask;
170 struct net_device *physindev; 170 struct net_device *physindev;
171 struct net_device *physoutdev; 171 struct net_device *physoutdev;
172 unsigned long data[32 / sizeof(unsigned long)]; 172 char neigh_header[8];
173}; 173};
174#endif 174#endif
175 175
diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c
index 282ed76c49e0..ca1cb6704a78 100644
--- a/net/bridge/br_netfilter.c
+++ b/net/bridge/br_netfilter.c
@@ -111,6 +111,19 @@ static inline __be16 pppoe_proto(const struct sk_buff *skb)
111 pppoe_proto(skb) == htons(PPP_IPV6) && \ 111 pppoe_proto(skb) == htons(PPP_IPV6) && \
112 brnf_filter_pppoe_tagged) 112 brnf_filter_pppoe_tagged)
113 113
114/* largest possible L2 header, see br_nf_dev_queue_xmit() */
115#define NF_BRIDGE_MAX_MAC_HEADER_LENGTH (PPPOE_SES_HLEN + ETH_HLEN)
116
117#if IS_ENABLED(CONFIG_NF_DEFRAG_IPV4)
118struct brnf_frag_data {
119 char mac[NF_BRIDGE_MAX_MAC_HEADER_LENGTH];
120 u8 encap_size;
121 u8 size;
122};
123
124static DEFINE_PER_CPU(struct brnf_frag_data, brnf_frag_data_storage);
125#endif
126
114static inline struct rtable *bridge_parent_rtable(const struct net_device *dev) 127static inline struct rtable *bridge_parent_rtable(const struct net_device *dev)
115{ 128{
116 struct net_bridge_port *port; 129 struct net_bridge_port *port;
@@ -189,14 +202,6 @@ static inline void nf_bridge_pull_encap_header_rcsum(struct sk_buff *skb)
189 skb->network_header += len; 202 skb->network_header += len;
190} 203}
191 204
192static inline void nf_bridge_save_header(struct sk_buff *skb)
193{
194 int header_size = ETH_HLEN + nf_bridge_encap_header_len(skb);
195
196 skb_copy_from_linear_data_offset(skb, -header_size,
197 skb->nf_bridge->data, header_size);
198}
199
200/* When handing a packet over to the IP layer 205/* When handing a packet over to the IP layer
201 * check whether we have a skb that is in the 206 * check whether we have a skb that is in the
202 * expected format 207 * expected format
@@ -318,7 +323,7 @@ static int br_nf_pre_routing_finish_bridge(struct sk_buff *skb)
318 */ 323 */
319 skb_copy_from_linear_data_offset(skb, 324 skb_copy_from_linear_data_offset(skb,
320 -(ETH_HLEN-ETH_ALEN), 325 -(ETH_HLEN-ETH_ALEN),
321 skb->nf_bridge->data, 326 nf_bridge->neigh_header,
322 ETH_HLEN-ETH_ALEN); 327 ETH_HLEN-ETH_ALEN);
323 /* tell br_dev_xmit to continue with forwarding */ 328 /* tell br_dev_xmit to continue with forwarding */
324 nf_bridge->mask |= BRNF_BRIDGED_DNAT; 329 nf_bridge->mask |= BRNF_BRIDGED_DNAT;
@@ -810,30 +815,22 @@ static unsigned int br_nf_forward_arp(const struct nf_hook_ops *ops,
810} 815}
811 816
812#if IS_ENABLED(CONFIG_NF_DEFRAG_IPV4) 817#if IS_ENABLED(CONFIG_NF_DEFRAG_IPV4)
813static bool nf_bridge_copy_header(struct sk_buff *skb) 818static int br_nf_push_frag_xmit(struct sk_buff *skb)
814{ 819{
820 struct brnf_frag_data *data;
815 int err; 821 int err;
816 unsigned int header_size;
817 822
818 nf_bridge_update_protocol(skb); 823 data = this_cpu_ptr(&brnf_frag_data_storage);
819 header_size = ETH_HLEN + nf_bridge_encap_header_len(skb); 824 err = skb_cow_head(skb, data->size);
820 err = skb_cow_head(skb, header_size);
821 if (err)
822 return false;
823 825
824 skb_copy_to_linear_data_offset(skb, -header_size, 826 if (err) {
825 skb->nf_bridge->data, header_size);
826 __skb_push(skb, nf_bridge_encap_header_len(skb));
827 return true;
828}
829
830static int br_nf_push_frag_xmit(struct sk_buff *skb)
831{
832 if (!nf_bridge_copy_header(skb)) {
833 kfree_skb(skb); 827 kfree_skb(skb);
834 return 0; 828 return 0;
835 } 829 }
836 830
831 skb_copy_to_linear_data_offset(skb, -data->size, data->mac, data->size);
832 __skb_push(skb, data->encap_size);
833
837 return br_dev_queue_push_xmit(skb); 834 return br_dev_queue_push_xmit(skb);
838} 835}
839 836
@@ -851,14 +848,27 @@ static int br_nf_dev_queue_xmit(struct sk_buff *skb)
851 * boundaries by preserving frag_list rather than refragmenting. 848 * boundaries by preserving frag_list rather than refragmenting.
852 */ 849 */
853 if (skb->len + mtu_reserved > skb->dev->mtu) { 850 if (skb->len + mtu_reserved > skb->dev->mtu) {
851 struct brnf_frag_data *data;
852
854 frag_max_size = BR_INPUT_SKB_CB(skb)->frag_max_size; 853 frag_max_size = BR_INPUT_SKB_CB(skb)->frag_max_size;
855 if (br_parse_ip_options(skb)) 854 if (br_parse_ip_options(skb))
856 /* Drop invalid packet */ 855 /* Drop invalid packet */
857 return NF_DROP; 856 return NF_DROP;
858 IPCB(skb)->frag_max_size = frag_max_size; 857 IPCB(skb)->frag_max_size = frag_max_size;
858
859 nf_bridge_update_protocol(skb);
860
861 data = this_cpu_ptr(&brnf_frag_data_storage);
862 data->encap_size = nf_bridge_encap_header_len(skb);
863 data->size = ETH_HLEN + data->encap_size;
864
865 skb_copy_from_linear_data_offset(skb, -data->size, data->mac,
866 data->size);
867
859 ret = ip_fragment(skb, br_nf_push_frag_xmit); 868 ret = ip_fragment(skb, br_nf_push_frag_xmit);
860 } else 869 } else {
861 ret = br_dev_queue_push_xmit(skb); 870 ret = br_dev_queue_push_xmit(skb);
871 }
862 872
863 return ret; 873 return ret;
864} 874}
@@ -906,7 +916,6 @@ static unsigned int br_nf_post_routing(const struct nf_hook_ops *ops,
906 } 916 }
907 917
908 nf_bridge_pull_encap_header(skb); 918 nf_bridge_pull_encap_header(skb);
909 nf_bridge_save_header(skb);
910 if (pf == NFPROTO_IPV4) 919 if (pf == NFPROTO_IPV4)
911 skb->protocol = htons(ETH_P_IP); 920 skb->protocol = htons(ETH_P_IP);
912 else 921 else
@@ -951,8 +960,11 @@ static void br_nf_pre_routing_finish_bridge_slow(struct sk_buff *skb)
951 skb_pull(skb, ETH_HLEN); 960 skb_pull(skb, ETH_HLEN);
952 nf_bridge->mask &= ~BRNF_BRIDGED_DNAT; 961 nf_bridge->mask &= ~BRNF_BRIDGED_DNAT;
953 962
954 skb_copy_to_linear_data_offset(skb, -(ETH_HLEN-ETH_ALEN), 963 BUILD_BUG_ON(sizeof(nf_bridge->neigh_header) != (ETH_HLEN - ETH_ALEN));
955 skb->nf_bridge->data, ETH_HLEN-ETH_ALEN); 964
965 skb_copy_to_linear_data_offset(skb, -(ETH_HLEN - ETH_ALEN),
966 nf_bridge->neigh_header,
967 ETH_HLEN - ETH_ALEN);
956 skb->dev = nf_bridge->physindev; 968 skb->dev = nf_bridge->physindev;
957 br_handle_frame_finish(skb); 969 br_handle_frame_finish(skb);
958} 970}