11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * Forwarding decision 31da177e4SLinus Torvalds * Linux ethernet bridge 41da177e4SLinus Torvalds * 51da177e4SLinus Torvalds * Authors: 61da177e4SLinus Torvalds * Lennert Buytenhek <buytenh@gnu.org> 71da177e4SLinus Torvalds * 81da177e4SLinus Torvalds * $Id: br_forward.c,v 1.4 2001/08/14 22:05:57 davem Exp $ 91da177e4SLinus Torvalds * 101da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or 111da177e4SLinus Torvalds * modify it under the terms of the GNU General Public License 121da177e4SLinus Torvalds * as published by the Free Software Foundation; either version 131da177e4SLinus Torvalds * 2 of the License, or (at your option) any later version. 141da177e4SLinus Torvalds */ 151da177e4SLinus Torvalds 161da177e4SLinus Torvalds #include <linux/kernel.h> 171da177e4SLinus Torvalds #include <linux/netdevice.h> 181da177e4SLinus Torvalds #include <linux/skbuff.h> 191da177e4SLinus Torvalds #include <linux/netfilter_bridge.h> 201da177e4SLinus Torvalds #include "br_private.h" 211da177e4SLinus Torvalds 221da177e4SLinus Torvalds static inline int should_deliver(const struct net_bridge_port *p, 231da177e4SLinus Torvalds const struct sk_buff *skb) 241da177e4SLinus Torvalds { 251da177e4SLinus Torvalds if (skb->dev == p->dev || 261da177e4SLinus Torvalds p->state != BR_STATE_FORWARDING) 271da177e4SLinus Torvalds return 0; 281da177e4SLinus Torvalds 291da177e4SLinus Torvalds return 1; 301da177e4SLinus Torvalds } 311da177e4SLinus Torvalds 321da177e4SLinus Torvalds int br_dev_queue_push_xmit(struct sk_buff *skb) 331da177e4SLinus Torvalds { 341da177e4SLinus Torvalds if (skb->len > skb->dev->mtu) 351da177e4SLinus Torvalds kfree_skb(skb); 361da177e4SLinus Torvalds else { 371da177e4SLinus Torvalds #ifdef CONFIG_BRIDGE_NETFILTER 381da177e4SLinus Torvalds /* ip_refrag calls ip_fragment, doesn't copy the MAC header. */ 391da177e4SLinus Torvalds nf_bridge_maybe_copy_header(skb); 401da177e4SLinus Torvalds #endif 411da177e4SLinus Torvalds skb_push(skb, ETH_HLEN); 421da177e4SLinus Torvalds 431da177e4SLinus Torvalds dev_queue_xmit(skb); 441da177e4SLinus Torvalds } 451da177e4SLinus Torvalds 461da177e4SLinus Torvalds return 0; 471da177e4SLinus Torvalds } 481da177e4SLinus Torvalds 491da177e4SLinus Torvalds int br_forward_finish(struct sk_buff *skb) 501da177e4SLinus Torvalds { 511da177e4SLinus Torvalds NF_HOOK(PF_BRIDGE, NF_BR_POST_ROUTING, skb, NULL, skb->dev, 521da177e4SLinus Torvalds br_dev_queue_push_xmit); 531da177e4SLinus Torvalds 541da177e4SLinus Torvalds return 0; 551da177e4SLinus Torvalds } 561da177e4SLinus Torvalds 571da177e4SLinus Torvalds static void __br_deliver(const struct net_bridge_port *to, struct sk_buff *skb) 581da177e4SLinus Torvalds { 591da177e4SLinus Torvalds skb->dev = to->dev; 601da177e4SLinus Torvalds #ifdef CONFIG_NETFILTER_DEBUG 611da177e4SLinus Torvalds skb->nf_debug = 0; 621da177e4SLinus Torvalds #endif 631da177e4SLinus Torvalds NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev, 641da177e4SLinus Torvalds br_forward_finish); 651da177e4SLinus Torvalds } 661da177e4SLinus Torvalds 671da177e4SLinus Torvalds static void __br_forward(const struct net_bridge_port *to, struct sk_buff *skb) 681da177e4SLinus Torvalds { 691da177e4SLinus Torvalds struct net_device *indev; 701da177e4SLinus Torvalds 711da177e4SLinus Torvalds indev = skb->dev; 721da177e4SLinus Torvalds skb->dev = to->dev; 731da177e4SLinus Torvalds skb->ip_summed = CHECKSUM_NONE; 741da177e4SLinus Torvalds 751da177e4SLinus Torvalds NF_HOOK(PF_BRIDGE, NF_BR_FORWARD, skb, indev, skb->dev, 761da177e4SLinus Torvalds br_forward_finish); 771da177e4SLinus Torvalds } 781da177e4SLinus Torvalds 791da177e4SLinus Torvalds /* called with rcu_read_lock */ 801da177e4SLinus Torvalds void br_deliver(const struct net_bridge_port *to, struct sk_buff *skb) 811da177e4SLinus Torvalds { 821da177e4SLinus Torvalds if (should_deliver(to, skb)) { 831da177e4SLinus Torvalds __br_deliver(to, skb); 841da177e4SLinus Torvalds return; 851da177e4SLinus Torvalds } 861da177e4SLinus Torvalds 871da177e4SLinus Torvalds kfree_skb(skb); 881da177e4SLinus Torvalds } 891da177e4SLinus Torvalds 901da177e4SLinus Torvalds /* called with rcu_read_lock */ 911da177e4SLinus Torvalds void br_forward(const struct net_bridge_port *to, struct sk_buff *skb) 921da177e4SLinus Torvalds { 931da177e4SLinus Torvalds if (should_deliver(to, skb)) { 941da177e4SLinus Torvalds __br_forward(to, skb); 951da177e4SLinus Torvalds return; 961da177e4SLinus Torvalds } 971da177e4SLinus Torvalds 981da177e4SLinus Torvalds kfree_skb(skb); 991da177e4SLinus Torvalds } 1001da177e4SLinus Torvalds 1011da177e4SLinus Torvalds /* called under bridge lock */ 1021da177e4SLinus Torvalds static void br_flood(struct net_bridge *br, struct sk_buff *skb, int clone, 1031da177e4SLinus Torvalds void (*__packet_hook)(const struct net_bridge_port *p, 1041da177e4SLinus Torvalds struct sk_buff *skb)) 1051da177e4SLinus Torvalds { 1061da177e4SLinus Torvalds struct net_bridge_port *p; 1071da177e4SLinus Torvalds struct net_bridge_port *prev; 1081da177e4SLinus Torvalds 1091da177e4SLinus Torvalds if (clone) { 1101da177e4SLinus Torvalds struct sk_buff *skb2; 1111da177e4SLinus Torvalds 1121da177e4SLinus Torvalds if ((skb2 = skb_clone(skb, GFP_ATOMIC)) == NULL) { 1131da177e4SLinus Torvalds br->statistics.tx_dropped++; 1141da177e4SLinus Torvalds return; 1151da177e4SLinus Torvalds } 1161da177e4SLinus Torvalds 1171da177e4SLinus Torvalds skb = skb2; 1181da177e4SLinus Torvalds } 1191da177e4SLinus Torvalds 1201da177e4SLinus Torvalds prev = NULL; 1211da177e4SLinus Torvalds 1221da177e4SLinus Torvalds list_for_each_entry_rcu(p, &br->port_list, list) { 1231da177e4SLinus Torvalds if (should_deliver(p, skb)) { 1241da177e4SLinus Torvalds if (prev != NULL) { 1251da177e4SLinus Torvalds struct sk_buff *skb2; 1261da177e4SLinus Torvalds 1271da177e4SLinus Torvalds if ((skb2 = skb_clone(skb, GFP_ATOMIC)) == NULL) { 1281da177e4SLinus Torvalds br->statistics.tx_dropped++; 1291da177e4SLinus Torvalds kfree_skb(skb); 1301da177e4SLinus Torvalds return; 1311da177e4SLinus Torvalds } 1321da177e4SLinus Torvalds 1331da177e4SLinus Torvalds __packet_hook(prev, skb2); 1341da177e4SLinus Torvalds } 1351da177e4SLinus Torvalds 1361da177e4SLinus Torvalds prev = p; 1371da177e4SLinus Torvalds } 1381da177e4SLinus Torvalds } 1391da177e4SLinus Torvalds 1401da177e4SLinus Torvalds if (prev != NULL) { 1411da177e4SLinus Torvalds __packet_hook(prev, skb); 1421da177e4SLinus Torvalds return; 1431da177e4SLinus Torvalds } 1441da177e4SLinus Torvalds 1451da177e4SLinus Torvalds kfree_skb(skb); 1461da177e4SLinus Torvalds } 1471da177e4SLinus Torvalds 1481da177e4SLinus Torvalds 1491da177e4SLinus Torvalds /* called with rcu_read_lock */ 1501da177e4SLinus Torvalds void br_flood_deliver(struct net_bridge *br, struct sk_buff *skb, int clone) 1511da177e4SLinus Torvalds { 1521da177e4SLinus Torvalds br_flood(br, skb, clone, __br_deliver); 1531da177e4SLinus Torvalds } 1541da177e4SLinus Torvalds 1551da177e4SLinus Torvalds /* called under bridge lock */ 1561da177e4SLinus Torvalds void br_flood_forward(struct net_bridge *br, struct sk_buff *skb, int clone) 1571da177e4SLinus Torvalds { 1581da177e4SLinus Torvalds br_flood(br, skb, clone, __br_forward); 1591da177e4SLinus Torvalds } 160