1/* 2 * Forwarding decision 3 * Linux ethernet bridge 4 * 5 * Authors: 6 * Lennert Buytenhek <buytenh@gnu.org> 7 * 8 * $Id: br_forward.c,v 1.1.1.1 2008/10/15 03:27:33 james26_jang Exp $ 9 * 10 * This program is free software; you can redistribute it and/or 11 * modify it under the terms of the GNU General Public License 12 * as published by the Free Software Foundation; either version 13 * 2 of the License, or (at your option) any later version. 14 */ 15 16#include <linux/kernel.h> 17#include <linux/netdevice.h> 18#include <linux/inetdevice.h> 19#include <linux/skbuff.h> 20#include <linux/if_bridge.h> 21#include <linux/netfilter_bridge.h> 22#include "br_private.h" 23 24static inline int should_deliver(struct net_bridge_port *p, struct sk_buff *skb) 25{ 26 if (skb->dev == p->dev || 27 p->state != BR_STATE_FORWARDING) 28 return 0; 29 30 return 1; 31} 32 33static int __dev_queue_push_xmit(struct sk_buff *skb) 34{ 35 skb_push(skb, ETH_HLEN); 36 dev_queue_xmit(skb); 37 38 return 0; 39} 40 41static int __br_forward_finish(struct sk_buff *skb) 42{ 43 NF_HOOK(PF_BRIDGE, NF_BR_POST_ROUTING, skb, NULL, skb->dev, 44 __dev_queue_push_xmit); 45 46 return 0; 47} 48 49static void __br_deliver(struct net_bridge_port *to, struct sk_buff *skb) 50{ 51 skb->dev = to->dev; 52 NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev, 53 __br_forward_finish); 54} 55 56static void __br_forward(struct net_bridge_port *to, struct sk_buff *skb) 57{ 58 struct net_device *indev; 59 60 indev = skb->dev; 61 skb->dev = to->dev; 62 63 NF_HOOK(PF_BRIDGE, NF_BR_FORWARD, skb, indev, skb->dev, 64 __br_forward_finish); 65} 66 67/* called under bridge lock */ 68void br_deliver(struct net_bridge_port *to, struct sk_buff *skb) 69{ 70 if (should_deliver(to, skb)) { 71 __br_deliver(to, skb); 72 return; 73 } 74 75 kfree_skb(skb); 76} 77 78/* called under bridge lock */ 79void br_forward(struct net_bridge_port *to, struct sk_buff *skb) 80{ 81 if (should_deliver(to, skb)) { 82 __br_forward(to, skb); 83 return; 84 } 85 86 kfree_skb(skb); 87} 88 89/* called under bridge lock */ 90static void br_flood(struct net_bridge *br, struct sk_buff *skb, int clone, 91 void (*__packet_hook)(struct net_bridge_port *p, struct sk_buff *skb)) 92{ 93 struct net_bridge_port *p; 94 struct net_bridge_port *prev; 95 96 if (clone) { 97 struct sk_buff *skb2; 98 99 if ((skb2 = skb_clone(skb, GFP_ATOMIC)) == NULL) { 100 br->statistics.tx_dropped++; 101 return; 102 } 103 104 skb = skb2; 105 } 106 107 prev = NULL; 108 109 p = br->port_list; 110 while (p != NULL) { 111 if (should_deliver(p, skb)) { 112 if (prev != NULL) { 113 struct sk_buff *skb2; 114 115 if ((skb2 = skb_clone(skb, GFP_ATOMIC)) == NULL) { 116 br->statistics.tx_dropped++; 117 kfree_skb(skb); 118 return; 119 } 120 121 __packet_hook(prev, skb2); 122 } 123 124 prev = p; 125 } 126 127 p = p->next; 128 } 129 130 if (prev != NULL) { 131 __packet_hook(prev, skb); 132 return; 133 } 134 135 kfree_skb(skb); 136} 137 138/* called under bridge lock */ 139void br_flood_deliver(struct net_bridge *br, struct sk_buff *skb, int clone) 140{ 141 br_flood(br, skb, clone, __br_deliver); 142} 143 144/* called under bridge lock */ 145void br_flood_forward(struct net_bridge *br, struct sk_buff *skb, int clone) 146{ 147 br_flood(br, skb, clone, __br_forward); 148} 149