Commit | Line | Data |
---|---|---|
09c434b8 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
1da177e4 LT |
2 | /* |
3 | * ebtable_broute | |
4 | * | |
5 | * Authors: | |
6 | * Bart De Schuymer <bdschuym@pandora.be> | |
7 | * | |
8 | * April, 2002 | |
9 | * | |
10 | * This table lets you choose between routing and bridging for frames | |
11 | * entering on a bridge enslaved nic. This table is traversed before any | |
12 | * other ebtables table. See net/bridge/br_input.c. | |
13 | */ | |
14 | ||
15 | #include <linux/netfilter_bridge/ebtables.h> | |
16 | #include <linux/module.h> | |
17 | #include <linux/if_bridge.h> | |
18 | ||
223fd0ad FW |
19 | #include "../br_private.h" |
20 | ||
1da177e4 LT |
21 | /* EBT_ACCEPT means the frame will be bridged |
22 | * EBT_DROP means the frame will be routed | |
23 | */ | |
24 | static struct ebt_entries initial_chain = { | |
25 | .name = "BROUTING", | |
26 | .policy = EBT_ACCEPT, | |
27 | }; | |
28 | ||
97ad8b53 | 29 | static struct ebt_replace_kernel initial_table = { |
1da177e4 LT |
30 | .name = "broute", |
31 | .valid_hooks = 1 << NF_BR_BROUTING, | |
32 | .entries_size = sizeof(struct ebt_entries), | |
33 | .hook_entry = { | |
34 | [NF_BR_BROUTING] = &initial_chain, | |
35 | }, | |
36 | .entries = (char *)&initial_chain, | |
37 | }; | |
38 | ||
39 | static int check(const struct ebt_table_info *info, unsigned int valid_hooks) | |
40 | { | |
41 | if (valid_hooks & ~(1 << NF_BR_BROUTING)) | |
42 | return -EINVAL; | |
43 | return 0; | |
44 | } | |
45 | ||
97ad8b53 | 46 | static const struct ebt_table broute_table = { |
1da177e4 LT |
47 | .name = "broute", |
48 | .table = &initial_table, | |
49 | .valid_hooks = 1 << NF_BR_BROUTING, | |
1da177e4 LT |
50 | .check = check, |
51 | .me = THIS_MODULE, | |
52 | }; | |
53 | ||
223fd0ad FW |
54 | static unsigned int ebt_broute(void *priv, struct sk_buff *skb, |
55 | const struct nf_hook_state *s) | |
1da177e4 | 56 | { |
223fd0ad | 57 | struct net_bridge_port *p = br_port_get_rcu(skb->dev); |
97b59c3a | 58 | struct nf_hook_state state; |
223fd0ad | 59 | unsigned char *dest; |
1da177e4 LT |
60 | int ret; |
61 | ||
223fd0ad FW |
62 | if (!p || p->state != BR_STATE_FORWARDING) |
63 | return NF_ACCEPT; | |
64 | ||
01886bd9 | 65 | nf_hook_state_init(&state, NF_BR_BROUTING, |
223fd0ad FW |
66 | NFPROTO_BRIDGE, s->in, NULL, NULL, |
67 | s->net, NULL); | |
97b59c3a EB |
68 | |
69 | ret = ebt_do_table(skb, &state, state.net->xt.broute_table); | |
223fd0ad FW |
70 | |
71 | if (ret != NF_DROP) | |
72 | return ret; | |
73 | ||
74 | /* DROP in ebtables -t broute means that the | |
75 | * skb should be routed, not bridged. | |
76 | * This is awkward, but can't be changed for compatibility | |
77 | * reasons. | |
78 | * | |
79 | * We map DROP to ACCEPT and set the ->br_netfilter_broute flag. | |
80 | */ | |
81 | BR_INPUT_SKB_CB(skb)->br_netfilter_broute = 1; | |
82 | ||
83 | /* undo PACKET_HOST mangling done in br_input in case the dst | |
84 | * address matches the logical bridge but not the port. | |
85 | */ | |
86 | dest = eth_hdr(skb)->h_dest; | |
87 | if (skb->pkt_type == PACKET_HOST && | |
88 | !ether_addr_equal(skb->dev->dev_addr, dest) && | |
89 | ether_addr_equal(p->br->dev->dev_addr, dest)) | |
90 | skb->pkt_type = PACKET_OTHERHOST; | |
91 | ||
92 | return NF_ACCEPT; | |
1da177e4 LT |
93 | } |
94 | ||
223fd0ad FW |
95 | static const struct nf_hook_ops ebt_ops_broute = { |
96 | .hook = ebt_broute, | |
97 | .pf = NFPROTO_BRIDGE, | |
98 | .hooknum = NF_BR_PRE_ROUTING, | |
99 | .priority = NF_BR_PRI_FIRST, | |
100 | }; | |
101 | ||
8157e6d1 AD |
102 | static int __net_init broute_net_init(struct net *net) |
103 | { | |
223fd0ad | 104 | return ebt_register_table(net, &broute_table, &ebt_ops_broute, |
e6b72ee8 | 105 | &net->xt.broute_table); |
8157e6d1 AD |
106 | } |
107 | ||
108 | static void __net_exit broute_net_exit(struct net *net) | |
109 | { | |
223fd0ad | 110 | ebt_unregister_table(net, net->xt.broute_table, &ebt_ops_broute); |
8157e6d1 AD |
111 | } |
112 | ||
113 | static struct pernet_operations broute_net_ops = { | |
114 | .init = broute_net_init, | |
115 | .exit = broute_net_exit, | |
116 | }; | |
117 | ||
65b4b4e8 | 118 | static int __init ebtable_broute_init(void) |
1da177e4 | 119 | { |
223fd0ad | 120 | return register_pernet_subsys(&broute_net_ops); |
1da177e4 LT |
121 | } |
122 | ||
65b4b4e8 | 123 | static void __exit ebtable_broute_fini(void) |
1da177e4 | 124 | { |
8157e6d1 | 125 | unregister_pernet_subsys(&broute_net_ops); |
1da177e4 LT |
126 | } |
127 | ||
65b4b4e8 AM |
128 | module_init(ebtable_broute_init); |
129 | module_exit(ebtable_broute_fini); | |
1da177e4 | 130 | MODULE_LICENSE("GPL"); |