Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
b12d2ca2
Commit
b12d2ca2
authored
Sep 17, 2002
by
Linus Torvalds
Browse files
Options
Browse Files
Download
Plain Diff
Merge master.kernel.org:/home/davem/BK/net-2.5
into home.transmeta.com:/home/torvalds/v2.5/linux
parents
18cddbe6
78a10cc5
Changes
30
Hide whitespace changes
Inline
Side-by-side
Showing
30 changed files
with
2984 additions
and
54 deletions
+2984
-54
MAINTAINERS
MAINTAINERS
+8
-0
arch/i386/lib/checksum.S
arch/i386/lib/checksum.S
+37
-3
drivers/net/tg3.c
drivers/net/tg3.c
+71
-23
drivers/net/tg3.h
drivers/net/tg3.h
+3
-2
include/linux/if_bridge.h
include/linux/if_bridge.h
+2
-1
include/linux/netfilter_bridge.h
include/linux/netfilter_bridge.h
+12
-1
net/Config.in
net/Config.in
+3
-0
net/bridge/Makefile
net/bridge/Makefile
+3
-0
net/bridge/br.c
net/bridge/br.c
+4
-0
net/bridge/br_forward.c
net/bridge/br_forward.c
+3
-0
net/bridge/br_input.c
net/bridge/br_input.c
+11
-4
net/bridge/br_private.h
net/bridge/br_private.h
+1
-1
net/bridge/netfilter/Config.help
net/bridge/netfilter/Config.help
+105
-0
net/bridge/netfilter/Config.in
net/bridge/netfilter/Config.in
+17
-0
net/bridge/netfilter/Makefile
net/bridge/netfilter/Makefile
+20
-0
net/bridge/netfilter/ebt_arp.c
net/bridge/netfilter/ebt_arp.c
+101
-0
net/bridge/netfilter/ebt_dnat.c
net/bridge/netfilter/ebt_dnat.c
+64
-0
net/bridge/netfilter/ebt_ip.c
net/bridge/netfilter/ebt_ip.c
+72
-0
net/bridge/netfilter/ebt_log.c
net/bridge/netfilter/ebt_log.c
+99
-0
net/bridge/netfilter/ebt_mark.c
net/bridge/netfilter/ebt_mark.c
+65
-0
net/bridge/netfilter/ebt_mark_m.c
net/bridge/netfilter/ebt_mark_m.c
+60
-0
net/bridge/netfilter/ebt_redirect.c
net/bridge/netfilter/ebt_redirect.c
+70
-0
net/bridge/netfilter/ebt_snat.c
net/bridge/netfilter/ebt_snat.c
+63
-0
net/bridge/netfilter/ebt_vlan.c
net/bridge/netfilter/ebt_vlan.c
+316
-0
net/bridge/netfilter/ebtable_broute.c
net/bridge/netfilter/ebtable_broute.c
+78
-0
net/bridge/netfilter/ebtable_filter.c
net/bridge/netfilter/ebtable_filter.c
+89
-0
net/bridge/netfilter/ebtable_nat.c
net/bridge/netfilter/ebtable_nat.c
+95
-0
net/bridge/netfilter/ebtables.c
net/bridge/netfilter/ebtables.c
+1484
-0
net/core/dev.c
net/core/dev.c
+7
-3
net/llc/llc_sock.c
net/llc/llc_sock.c
+21
-16
No files found.
MAINTAINERS
View file @
b12d2ca2
...
...
@@ -531,6 +531,14 @@ M: mike@i-Connect.Net
L: linux-eata@i-connect.net, linux-scsi@vger.kernel.org
S: Maintained
EBTABLES
P: Bart De Schuymer
M: bart.de.schuymer@pandora.be
L: ebtables-user@lists.sourceforge.net
L: ebtables-devel@lists.sourceforge.net
W: http://ebtables.sourceforge.net/
S: Maintained
EEPRO100 NETWORK DRIVER
P: Andrey V. Savochkin
M: saw@saw.sw.com.sg
...
...
arch/i386/lib/checksum.S
View file @
b12d2ca2
...
...
@@ -55,8 +55,21 @@ csum_partial:
movl
20
(%
esp
),%
eax
#
Function
arg
:
unsigned
int
sum
movl
16
(%
esp
),%
ecx
#
Function
arg
:
int
len
movl
12
(%
esp
),%
esi
#
Function
arg
:
unsigned
char
*
buff
testl
$
2
,
%
esi
#
Check
alignment
.
testl
$
3
,
%
esi
#
Check
alignment
.
jz
2
f
#
Jump
if
alignment
is
ok
.
testl
$
1
,
%
esi
#
Check
alignment
.
jz
10
f
#
Jump
if
alignment
is
boundary
of
2
bytes
.
#
buf
is
odd
dec
%
ecx
jl
8
f
movzbl
(%
esi
),
%
ebx
adcl
%
ebx
,
%
eax
roll
$
8
,
%
eax
inc
%
esi
testl
$
2
,
%
esi
jz
2
f
10
:
subl
$
2
,
%
ecx
#
Alignment
uses
up
two
bytes
.
jae
1
f
#
Jump
if
we
had
at
least
two
bytes
.
addl
$
2
,
%
ecx
#
ecx
was
<
2
.
Deal
with
it
.
...
...
@@ -111,6 +124,10 @@ csum_partial:
6
:
addl
%
ecx
,%
eax
adcl
$
0
,
%
eax
7
:
testl
$
1
,
12
(%
esp
)
jz
8
f
roll
$
8
,
%
eax
8
:
popl
%
ebx
popl
%
esi
ret
...
...
@@ -126,8 +143,8 @@ csum_partial:
movl
16
(%
esp
),%
ecx
#
Function
arg
:
int
len
movl
12
(%
esp
),%
esi
#
Function
arg
:
const
unsigned
char
*
buf
testl
$
2
,
%
esi
jnz
30
f
testl
$
3
,
%
esi
jnz
25
f
10
:
movl
%
ecx
,
%
edx
movl
%
ecx
,
%
ebx
...
...
@@ -145,6 +162,19 @@ csum_partial:
lea
2
(%
esi
),
%
esi
adcl
$
0
,
%
eax
jmp
10
b
25
:
testl
$
1
,
%
esi
jz
30
f
#
buf
is
odd
dec
%
ecx
jl
90
f
movzbl
(%
esi
),
%
ebx
addl
%
ebx
,
%
eax
adcl
$
0
,
%
eax
roll
$
8
,
%
eax
inc
%
esi
testl
$
2
,
%
esi
jz
10
b
30
:
subl
$
2
,
%
ecx
ja
20
b
...
...
@@ -211,6 +241,10 @@ csum_partial:
addl
%
ebx
,%
eax
adcl
$
0
,%
eax
80
:
testl
$
1
,
12
(%
esp
)
jz
90
f
roll
$
8
,
%
eax
90
:
popl
%
ebx
popl
%
esi
ret
...
...
drivers/net/tg3.c
View file @
b12d2ca2
...
...
@@ -237,6 +237,39 @@ static void tg3_enable_ints(struct tg3 *tp)
tr32
(
MAILBOX_INTERRUPT_0
+
TG3_64BIT_REG_LOW
);
}
static
inline
void
tg3_mask_ints
(
struct
tg3
*
tp
)
{
tw32
(
TG3PCI_MISC_HOST_CTRL
,
(
tp
->
misc_host_ctrl
|
MISC_HOST_CTRL_MASK_PCI_INT
));
}
static
inline
void
tg3_unmask_ints
(
struct
tg3
*
tp
)
{
tw32
(
TG3PCI_MISC_HOST_CTRL
,
(
tp
->
misc_host_ctrl
&
~
MISC_HOST_CTRL_MASK_PCI_INT
));
if
(
tp
->
hw_status
->
status
&
SD_STATUS_UPDATED
)
{
tw32
(
GRC_LOCAL_CTRL
,
tp
->
grc_local_ctrl
|
GRC_LCLCTRL_SETINT
);
}
}
static
void
tg3_switch_clocks
(
struct
tg3
*
tp
)
{
if
(
tr32
(
TG3PCI_CLOCK_CTRL
)
&
CLOCK_CTRL_44MHZ_CORE
)
{
tw32
(
TG3PCI_CLOCK_CTRL
,
(
CLOCK_CTRL_44MHZ_CORE
|
CLOCK_CTRL_ALTCLK
));
tr32
(
TG3PCI_CLOCK_CTRL
);
udelay
(
40
);
tw32
(
TG3PCI_CLOCK_CTRL
,
(
CLOCK_CTRL_ALTCLK
));
tr32
(
TG3PCI_CLOCK_CTRL
);
udelay
(
40
);
}
tw32
(
TG3PCI_CLOCK_CTRL
,
0
);
tr32
(
TG3PCI_CLOCK_CTRL
);
udelay
(
40
);
}
#define PHY_BUSY_LOOPS 5000
static
int
tg3_readphy
(
struct
tg3
*
tp
,
int
reg
,
u32
*
val
)
...
...
@@ -443,10 +476,12 @@ static int tg3_set_power_state(struct tg3 *tp, int state)
tp
->
link_config
.
orig_autoneg
=
tp
->
link_config
.
autoneg
;
}
tp
->
link_config
.
speed
=
SPEED_10
;
tp
->
link_config
.
duplex
=
DUPLEX_HALF
;
tp
->
link_config
.
autoneg
=
AUTONEG_ENABLE
;
tg3_setup_phy
(
tp
);
if
(
tp
->
phy_id
!=
PHY_ID_SERDES
)
{
tp
->
link_config
.
speed
=
SPEED_10
;
tp
->
link_config
.
duplex
=
DUPLEX_HALF
;
tp
->
link_config
.
autoneg
=
AUTONEG_ENABLE
;
tg3_setup_phy
(
tp
);
}
tg3_halt
(
tp
);
...
...
@@ -455,14 +490,19 @@ static int tg3_set_power_state(struct tg3 *tp, int state)
if
(
tp
->
tg3_flags
&
TG3_FLAG_WOL_ENABLE
)
{
u32
mac_mode
;
tg3_writephy
(
tp
,
MII_TG3_AUX_CTRL
,
0x5a
);
udelay
(
40
);
if
(
tp
->
phy_id
!=
PHY_ID_SERDES
)
{
tg3_writephy
(
tp
,
MII_TG3_AUX_CTRL
,
0x5a
);
udelay
(
40
);
mac_mode
=
MAC_MODE_PORT_MODE_MII
;
mac_mode
=
MAC_MODE_PORT_MODE_MII
;
if
(
GET_ASIC_REV
(
tp
->
pci_chip_rev_id
)
!=
ASIC_REV_5700
||
!
(
tp
->
tg3_flags
&
TG3_FLAG_WOL_SPEED_100MB
))
mac_mode
|=
MAC_MODE_LINK_POLARITY
;
}
else
{
mac_mode
=
MAC_MODE_PORT_MODE_TBI
;
}
if
(
GET_ASIC_REV
(
tp
->
pci_chip_rev_id
)
!=
ASIC_REV_5700
||
!
(
tp
->
tg3_flags
&
TG3_FLAG_WOL_SPEED_100MB
))
mac_mode
|=
MAC_MODE_LINK_POLARITY
;
if
(((
power_caps
&
PCI_PM_CAP_PME_D3cold
)
&&
(
tp
->
tg3_flags
&
TG3_FLAG_WOL_ENABLE
)))
...
...
@@ -470,7 +510,7 @@ static int tg3_set_power_state(struct tg3 *tp, int state)
tw32
(
MAC_MODE
,
mac_mode
);
tr32
(
MAC_MODE
);
udelay
(
4
0
);
udelay
(
10
0
);
tw32
(
MAC_RX_MODE
,
RX_MODE_ENABLE
);
tr32
(
MAC_RX_MODE
);
...
...
@@ -1033,16 +1073,15 @@ static int tg3_setup_copper_phy(struct tg3 *tp)
tp
->
mac_mode
|=
MAC_MODE_HALF_DUPLEX
;
tp
->
mac_mode
&=
~
MAC_MODE_LINK_POLARITY
;
if
(
GET_ASIC_REV
(
tp
->
pci_chip_rev_id
)
==
ASIC_REV_5701
||
GET_ASIC_REV
(
tp
->
pci_chip_rev_id
)
==
ASIC_REV_5703
)
{
if
(
current_link_up
==
1
)
tp
->
mac_mode
|=
MAC_MODE_LINK_POLARITY
;
tw32
(
MAC_LED_CTRL
,
LED_CTRL_PHY_MODE_1
);
}
else
{
if
(
GET_ASIC_REV
(
tp
->
pci_chip_rev_id
)
==
ASIC_REV_5700
)
{
if
((
tp
->
led_mode
==
led_mode_link10
)
||
(
current_link_up
==
1
&&
tp
->
link_config
.
active_speed
==
SPEED_10
))
tp
->
mac_mode
|=
MAC_MODE_LINK_POLARITY
;
}
else
{
if
(
current_link_up
==
1
)
tp
->
mac_mode
|=
MAC_MODE_LINK_POLARITY
;
tw32
(
MAC_LED_CTRL
,
LED_CTRL_PHY_MODE_1
);
}
/* ??? Without this setting Netgear GA302T PHY does not
...
...
@@ -2068,7 +2107,7 @@ static int tg3_poll(struct net_device *netdev, int *budget)
if
(
done
)
{
netif_rx_complete
(
netdev
);
tg3_
enable
_ints
(
tp
);
tg3_
unmask
_ints
(
tp
);
}
spin_unlock_irq
(
&
tp
->
lock
);
...
...
@@ -2095,11 +2134,10 @@ static __inline__ void tg3_interrupt_main_work(struct net_device *dev, struct tg
return
;
if
(
netif_rx_schedule_prep
(
dev
))
{
/* NOTE: Th
is write is
posted by the readback of
/* NOTE: Th
ese writes are
posted by the readback of
* the mailbox register done by our caller.
*/
tw32
(
TG3PCI_MISC_HOST_CTRL
,
(
tp
->
misc_host_ctrl
|
MISC_HOST_CTRL_MASK_PCI_INT
));
tg3_mask_ints
(
tp
);
__netif_rx_schedule
(
dev
);
}
else
{
printk
(
KERN_ERR
PFX
"%s: Error, poll already scheduled
\n
"
,
...
...
@@ -4385,6 +4423,8 @@ static int tg3_init_hw(struct tg3 *tp)
if
(
err
)
goto
out
;
tg3_switch_clocks
(
tp
);
tw32
(
TG3PCI_MEM_WIN_BASE_ADDR
,
0
);
err
=
tg3_reset_hw
(
tp
);
...
...
@@ -5259,6 +5299,11 @@ static int tg3_ethtool_ioctl (struct net_device *dev, void *useraddr)
return
-
EFAULT
;
if
(
wol
.
wolopts
&
~
WAKE_MAGIC
)
return
-
EINVAL
;
if
((
wol
.
wolopts
&
WAKE_MAGIC
)
&&
tp
->
phy_id
==
PHY_ID_SERDES
&&
!
(
tp
->
tg3_flags
&
TG3_FLAG_SERDES_WOL_CAP
))
return
-
EINVAL
;
spin_lock_irq
(
&
tp
->
lock
);
if
(
wol
.
wolopts
&
WAKE_MAGIC
)
tp
->
tg3_flags
|=
TG3_FLAG_WOL_ENABLE
;
...
...
@@ -5793,6 +5838,8 @@ static int __devinit tg3_phy_probe(struct tg3 *tp)
if
(
nic_cfg
&
NIC_SRAM_DATA_CFG_ASF_ENABLE
)
tp
->
tg3_flags
|=
TG3_FLAG_ENABLE_ASF
;
if
(
nic_cfg
&
NIC_SRAM_DATA_CFG_FIBER_WOL
)
tp
->
tg3_flags
|=
TG3_FLAG_SERDES_WOL_CAP
;
}
/* Now read the physical PHY_ID from the chip and verify
...
...
@@ -6131,8 +6178,9 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
/* Initialize data/descriptor byte/word swapping. */
tw32
(
GRC_MODE
,
tp
->
grc_mode
);
/* Clear these out for sanity. */
tw32
(
TG3PCI_CLOCK_CTRL
,
0
);
tg3_switch_clocks
(
tp
);
/* Clear this out for sanity. */
tw32
(
TG3PCI_MEM_WIN_BASE_ADDR
,
0
);
pci_read_config_dword
(
tp
->
pdev
,
TG3PCI_PCISTATE
,
...
...
drivers/net/tg3.h
View file @
b12d2ca2
...
...
@@ -1274,6 +1274,7 @@
#define NIC_SRAM_DATA_CFG_WOL_ENABLE 0x00000040
#define NIC_SRAM_DATA_CFG_ASF_ENABLE 0x00000080
#define NIC_SRAM_DATA_CFG_EEPROM_WP 0x00000100
#define NIC_SRAM_DATA_CFG_FIBER_WOL 0x00004000
#define NIC_SRAM_DATA_PHY_ID 0x00000b74
#define NIC_SRAM_DATA_PHY_ID1_MASK 0xffff0000
...
...
@@ -1311,7 +1312,7 @@
#define NIC_SRAM_RX_JUMBO_BUFFER_DESC 0x00007000
/* 256 entries */
#define NIC_SRAM_MBUF_POOL_BASE 0x00008000
#define NIC_SRAM_MBUF_POOL_SIZE96 0x00018000
#define NIC_SRAM_MBUF_POOL_SIZE64 0x0001
8
000
#define NIC_SRAM_MBUF_POOL_SIZE64 0x0001
0
000
/* Currently this is fixed. */
#define PHY_ADDR 0x01
...
...
@@ -1779,7 +1780,7 @@ struct tg3 {
#define TG3_FLAG_PCI_32BIT 0x00080000
#define TG3_FLAG_NO_TX_PSEUDO_CSUM 0x00100000
#define TG3_FLAG_NO_RX_PSEUDO_CSUM 0x00200000
#define TG3_FLAG_
AUTONEG_DISABLE
0x00400000
#define TG3_FLAG_
SERDES_WOL_CAP
0x00400000
#define TG3_FLAG_JUMBO_ENABLE 0x00800000
#define TG3_FLAG_10_100_ONLY 0x01000000
#define TG3_FLAG_PAUSE_AUTONEG 0x02000000
...
...
include/linux/if_bridge.h
View file @
b12d2ca2
...
...
@@ -102,7 +102,8 @@ struct net_bridge;
struct
net_bridge_port
;
extern
int
(
*
br_ioctl_hook
)(
unsigned
long
arg
);
extern
void
(
*
br_handle_frame_hook
)(
struct
sk_buff
*
skb
);
extern
int
(
*
br_handle_frame_hook
)(
struct
sk_buff
*
skb
);
extern
int
(
*
br_should_route_hook
)(
struct
sk_buff
**
pskb
);
#endif
...
...
include/linux/netfilter_bridge.h
View file @
b12d2ca2
...
...
@@ -18,7 +18,18 @@
#define NF_BR_LOCAL_OUT 3
/* Packets about to hit the wire. */
#define NF_BR_POST_ROUTING 4
#define NF_BR_NUMHOOKS 5
/* Not really a hook, but used for the ebtables broute table */
#define NF_BR_BROUTING 5
#define NF_BR_NUMHOOKS 6
enum
nf_br_hook_priorities
{
NF_BR_PRI_FIRST
=
INT_MIN
,
NF_BR_PRI_FILTER_BRIDGED
=
-
200
,
NF_BR_PRI_FILTER_OTHER
=
200
,
NF_BR_PRI_NAT_DST_BRIDGED
=
-
300
,
NF_BR_PRI_NAT_DST_OTHER
=
100
,
NF_BR_PRI_NAT_SRC
=
300
,
NF_BR_PRI_LAST
=
INT_MAX
,
};
#endif
net/Config.in
View file @
b12d2ca2
...
...
@@ -65,6 +65,9 @@ if [ "$CONFIG_DECNET" != "n" ]; then
source net/decnet/Config.in
fi
dep_tristate '802.1d Ethernet Bridging' CONFIG_BRIDGE $CONFIG_INET
if [ "$CONFIG_BRIDGE" != "n" -a "$CONFIG_NETFILTER" != "n" ]; then
source net/bridge/netfilter/Config.in
fi
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
tristate 'CCITT X.25 Packet Layer (EXPERIMENTAL)' CONFIG_X25
tristate 'LAPB Data Link Driver (EXPERIMENTAL)' CONFIG_LAPB
...
...
net/bridge/Makefile
View file @
b12d2ca2
...
...
@@ -2,10 +2,13 @@
# Makefile for the IEEE 802.1d ethernet bridging layer.
#
export-objs
:=
br.o
obj-$(CONFIG_BRIDGE)
+=
bridge.o
bridge-objs
:=
br.o br_device.o br_fdb.o br_forward.o br_if.o br_input.o
\
br_ioctl.o br_notify.o br_stp.o br_stp_bpdu.o
\
br_stp_if.o br_stp_timer.o
obj-$(CONFIG_BRIDGE_NF_EBTABLES)
+=
netfilter/
include
$(TOPDIR)/Rules.make
net/bridge/br.c
View file @
b12d2ca2
...
...
@@ -28,6 +28,8 @@
#include "../atm/lec.h"
#endif
int
(
*
br_should_route_hook
)
(
struct
sk_buff
**
pskb
)
=
NULL
;
void
br_dec_use_count
()
{
MOD_DEC_USE_COUNT
;
...
...
@@ -74,6 +76,8 @@ static void __exit br_deinit(void)
#endif
}
EXPORT_SYMBOL
(
br_should_route_hook
);
module_init
(
br_init
)
module_exit
(
br_deinit
)
MODULE_LICENSE
(
"GPL"
);
net/bridge/br_forward.c
View file @
b12d2ca2
...
...
@@ -49,6 +49,9 @@ static int __br_forward_finish(struct sk_buff *skb)
static
void
__br_deliver
(
struct
net_bridge_port
*
to
,
struct
sk_buff
*
skb
)
{
skb
->
dev
=
to
->
dev
;
#ifdef CONFIG_NETFILTER_DEBUG
skb
->
nf_debug
=
0
;
#endif
NF_HOOK
(
PF_BRIDGE
,
NF_BR_LOCAL_OUT
,
skb
,
NULL
,
skb
->
dev
,
__br_forward_finish
);
}
...
...
net/bridge/br_input.c
View file @
b12d2ca2
...
...
@@ -24,6 +24,9 @@ unsigned char bridge_ula[6] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 };
static
int
br_pass_frame_up_finish
(
struct
sk_buff
*
skb
)
{
#ifdef CONFIG_NETFILTER_DEBUG
skb
->
nf_debug
=
0
;
#endif
netif_rx
(
skb
);
return
0
;
...
...
@@ -112,7 +115,7 @@ static int br_handle_frame_finish(struct sk_buff *skb)
return
0
;
}
void
br_handle_frame
(
struct
sk_buff
*
skb
)
int
br_handle_frame
(
struct
sk_buff
*
skb
)
{
struct
net_bridge
*
br
;
unsigned
char
*
dest
;
...
...
@@ -146,25 +149,29 @@ void br_handle_frame(struct sk_buff *skb)
goto
handle_special_frame
;
if
(
p
->
state
==
BR_STATE_FORWARDING
)
{
if
(
br_should_route_hook
&&
br_should_route_hook
(
&
skb
))
return
-
1
;
NF_HOOK
(
PF_BRIDGE
,
NF_BR_PRE_ROUTING
,
skb
,
skb
->
dev
,
NULL
,
br_handle_frame_finish
);
read_unlock
(
&
br
->
lock
);
return
;
return
0
;
}
err:
read_unlock
(
&
br
->
lock
);
err_nolock:
kfree_skb
(
skb
);
return
;
return
0
;
handle_special_frame:
if
(
!
dest
[
5
])
{
br_stp_handle_bpdu
(
skb
);
read_unlock
(
&
br
->
lock
);
return
;
return
0
;
}
kfree_skb
(
skb
);
read_unlock
(
&
br
->
lock
);
return
0
;
}
net/bridge/br_private.h
View file @
b12d2ca2
...
...
@@ -166,7 +166,7 @@ extern void br_get_port_ifindices(struct net_bridge *br,
int
*
ifindices
);
/* br_input.c */
extern
void
br_handle_frame
(
struct
sk_buff
*
skb
);
extern
int
br_handle_frame
(
struct
sk_buff
*
skb
);
/* br_ioctl.c */
extern
void
br_call_ioctl_atomic
(
void
(
*
fn
)(
void
));
...
...
net/bridge/netfilter/Config.help
0 → 100644
View file @
b12d2ca2
CONFIG_BRIDGE_EBT
ebtables is an extendable frame filtering system for the Linux
Ethernet bridge. Its usage and implementation is very similar to that
of iptables.
The difference is that ebtables works on the Link Layer, while iptables
works on the Network Layer. ebtables can filter all frames that come
into contact with a logical bridge device.
Apart from filtering, ebtables also allows MAC source and destination
alterations (we call it MAC SNAT and MAC DNAT) and also provides
functionality for making Linux a brouter.
If you want to compile it as a module, say M here and read
<file:Documentation/modules.txt>. If unsure, say `N'.
CONFIG_BRIDGE_EBT_T_FILTER
The ebtables filter table is used to define frame filtering rules at
local input, forwarding and local output. See the man page for
ebtables(8).
If you want to compile it as a module, say M here and read
<file:Documentation/modules.txt>. If unsure, say `N'.
CONFIG_BRIDGE_EBT_T_NAT
The ebtables nat table is used to define rules that alter the MAC
source address (MAC SNAT) or the MAC destination address (MAC DNAT).
See the man page for ebtables(8).
If you want to compile it as a module, say M here and read
<file:Documentation/modules.txt>. If unsure, say `N'.
CONFIG_BRIDGE_EBT_BROUTE
The ebtables broute table is used to define rules that decide between
bridging and routing frames, giving Linux the functionality of a
brouter. See the man page for ebtables(8) and examples on the ebtables
website.
If you want to compile it as a module, say M here and read
<file:Documentation/modules.txt>. If unsure, say `N'.
CONFIG_BRIDGE_EBT_LOG
This option adds the log target, that you can use in any rule in
any ebtables table. It records the frame header to the syslog.
If you want to compile it as a module, say M here and read
<file:Documentation/modules.txt>. If unsure, say `N'.
CONFIG_BRIDGE_EBT_IPF
This option adds the IP match, which allows basic IP header field
filtering.
If you want to compile it as a module, say M here and read
<file:Documentation/modules.txt>. If unsure, say `N'.
CONFIG_BRIDGE_EBT_ARPF
This option adds the ARP match, which allows ARP and RARP header field
filtering.
If you want to compile it as a module, say M here and read
<file:Documentation/modules.txt>. If unsure, say `N'.
CONFIG_BRIDGE_EBT_VLANF
This option adds the 802.1Q vlan match, which allows the filtering of
802.1Q vlan fields.
If you want to compile it as a module, say M here and read
<file:Documentation/modules.txt>. If unsure, say `N'.
CONFIG_BRIDGE_EBT_MARKF
This option adds the mark match, which allows matching frames based on
the 'nfmark' value in the frame. This can be set by the mark target.
This value is the same as the one used in the iptables mark match and
target.
If you want to compile it as a module, say M here and read
<file:Documentation/modules.txt>. If unsure, say `N'.
CONFIG_BRIDGE_EBT_SNAT
This option adds the MAC SNAT target, which allows altering the MAC
source address of frames.
If you want to compile it as a module, say M here and read
<file:Documentation/modules.txt>. If unsure, say `N'.
CONFIG_BRIDGE_EBT_DNAT
This option adds the MAC DNAT target, which allows altering the MAC
destination address of frames.
If you want to compile it as a module, say M here and read
<file:Documentation/modules.txt>. If unsure, say `N'.
CONFIG_BRIDGE_EBT_REDIRECT
This option adds the MAC redirect target, which allows altering the MAC
destination address of a frame to that of the device it arrived on.
If you want to compile it as a module, say M here and read
<file:Documentation/modules.txt>. If unsure, say `N'.
CONFIG_BRIDGE_EBT_MARK_T
This option adds the mark target, which allows marking frames by
setting the 'nfmark' value in the frame.
This value is the same as the one used in the iptables mark match and
target.
If you want to compile it as a module, say M here and read
<file:Documentation/modules.txt>. If unsure, say `N'.
net/bridge/netfilter/Config.in
0 → 100644
View file @
b12d2ca2
#
# Bridge netfilter configuration
#
dep_tristate ' Bridge: ebtables' CONFIG_BRIDGE_NF_EBTABLES $CONFIG_BRIDGE
dep_tristate ' ebt: filter table support' CONFIG_BRIDGE_EBT_T_FILTER $CONFIG_BRIDGE_NF_EBTABLES
dep_tristate ' ebt: nat table support' CONFIG_BRIDGE_EBT_T_NAT $CONFIG_BRIDGE_NF_EBTABLES
dep_tristate ' ebt: broute table support' CONFIG_BRIDGE_EBT_BROUTE $CONFIG_BRIDGE_NF_EBTABLES
dep_tristate ' ebt: log support' CONFIG_BRIDGE_EBT_LOG $CONFIG_BRIDGE_NF_EBTABLES
dep_tristate ' ebt: IP filter support' CONFIG_BRIDGE_EBT_IPF $CONFIG_BRIDGE_NF_EBTABLES
dep_tristate ' ebt: ARP filter support' CONFIG_BRIDGE_EBT_ARPF $CONFIG_BRIDGE_NF_EBTABLES
dep_tristate ' ebt: 802.1Q VLAN filter support (EXPERIMENTAL)' CONFIG_BRIDGE_EBT_VLANF $CONFIG_BRIDGE_NF_EBTABLES
dep_tristate ' ebt: mark filter support' CONFIG_BRIDGE_EBT_MARKF $CONFIG_BRIDGE_NF_EBTABLES
dep_tristate ' ebt: snat target support' CONFIG_BRIDGE_EBT_SNAT $CONFIG_BRIDGE_NF_EBTABLES
dep_tristate ' ebt: dnat target support' CONFIG_BRIDGE_EBT_DNAT $CONFIG_BRIDGE_NF_EBTABLES
dep_tristate ' ebt: redirect target support' CONFIG_BRIDGE_EBT_REDIRECT $CONFIG_BRIDGE_NF_EBTABLES
dep_tristate ' ebt: mark target support' CONFIG_BRIDGE_EBT_MARK_T $CONFIG_BRIDGE_NF_EBTABLES
net/bridge/netfilter/Makefile
0 → 100644
View file @
b12d2ca2
#
# Makefile for the netfilter modules for Link Layer filtering on a bridge.
#
export-objs
:=
ebtables.o
obj-$(CONFIG_BRIDGE_NF_EBTABLES)
+=
ebtables.o
obj-$(CONFIG_BRIDGE_EBT_T_FILTER)
+=
ebtable_filter.o
obj-$(CONFIG_BRIDGE_EBT_T_NAT)
+=
ebtable_nat.o
obj-$(CONFIG_BRIDGE_EBT_BROUTE)
+=
ebtable_broute.o
obj-$(CONFIG_BRIDGE_EBT_IPF)
+=
ebt_ip.o
obj-$(CONFIG_BRIDGE_EBT_ARPF)
+=
ebt_arp.o
obj-$(CONFIG_BRIDGE_EBT_VLANF)
+=
ebt_vlan.o
obj-$(CONFIG_BRIDGE_EBT_MARKF)
+=
ebt_mark_m.o
obj-$(CONFIG_BRIDGE_EBT_LOG)
+=
ebt_log.o
obj-$(CONFIG_BRIDGE_EBT_SNAT)
+=
ebt_snat.o
obj-$(CONFIG_BRIDGE_EBT_DNAT)
+=
ebt_dnat.o
obj-$(CONFIG_BRIDGE_EBT_REDIRECT)
+=
ebt_redirect.o
obj-$(CONFIG_BRIDGE_EBT_MARK_T)
+=
ebt_mark.o
include
$(TOPDIR)/Rules.make
net/bridge/netfilter/ebt_arp.c
0 → 100644
View file @
b12d2ca2
/*
* ebt_arp
*
* Authors:
* Bart De Schuymer <bart.de.schuymer@pandora.be>
* Tim Gardner <timg@tpi.com>
*
* April, 2002
*
*/
#include <linux/netfilter_bridge/ebtables.h>
#include <linux/netfilter_bridge/ebt_arp.h>
#include <linux/if_arp.h>
#include <linux/module.h>
static
int
ebt_filter_arp
(
const
struct
sk_buff
*
skb
,
const
struct
net_device
*
in
,
const
struct
net_device
*
out
,
const
void
*
data
,
unsigned
int
datalen
)
{
struct
ebt_arp_info
*
info
=
(
struct
ebt_arp_info
*
)
data
;
if
(
info
->
bitmask
&
EBT_ARP_OPCODE
&&
FWINV
(
info
->
opcode
!=
((
*
skb
).
nh
.
arph
)
->
ar_op
,
EBT_ARP_OPCODE
))
return
EBT_NOMATCH
;
if
(
info
->
bitmask
&
EBT_ARP_HTYPE
&&
FWINV
(
info
->
htype
!=
((
*
skb
).
nh
.
arph
)
->
ar_hrd
,
EBT_ARP_HTYPE
))
return
EBT_NOMATCH
;
if
(
info
->
bitmask
&
EBT_ARP_PTYPE
&&
FWINV
(
info
->
ptype
!=
((
*
skb
).
nh
.
arph
)
->
ar_pro
,
EBT_ARP_PTYPE
))
return
EBT_NOMATCH
;
if
(
info
->
bitmask
&
(
EBT_ARP_SRC_IP
|
EBT_ARP_DST_IP
))
{
uint32_t
arp_len
=
sizeof
(
struct
arphdr
)
+
(
2
*
(((
*
skb
).
nh
.
arph
)
->
ar_hln
))
+
(
2
*
(((
*
skb
).
nh
.
arph
)
->
ar_pln
));
uint32_t
dst
;
uint32_t
src
;
// Make sure the packet is long enough.
if
((((
*
skb
).
nh
.
raw
)
+
arp_len
)
>
(
*
skb
).
tail
)
return
EBT_NOMATCH
;
// IPv4 addresses are always 4 bytes.
if
(((
*
skb
).
nh
.
arph
)
->
ar_pln
!=
sizeof
(
uint32_t
))
return
EBT_NOMATCH
;
if
(
info
->
bitmask
&
EBT_ARP_SRC_IP
)
{
memcpy
(
&
src
,
((
*
skb
).
nh
.
raw
)
+
sizeof
(
struct
arphdr
)
+
((
*
skb
).
nh
.
arph
)
->
ar_hln
,
sizeof
(
uint32_t
));
if
(
FWINV
(
info
->
saddr
!=
(
src
&
info
->
smsk
),
EBT_ARP_SRC_IP
))
return
EBT_NOMATCH
;
}
if
(
info
->
bitmask
&
EBT_ARP_DST_IP
)
{
memcpy
(
&
dst
,
((
*
skb
).
nh
.
raw
)
+
sizeof
(
struct
arphdr
)
+
(
2
*
(((
*
skb
).
nh
.
arph
)
->
ar_hln
))
+
(((
*
skb
).
nh
.
arph
)
->
ar_pln
),
sizeof
(
uint32_t
));
if
(
FWINV
(
info
->
daddr
!=
(
dst
&
info
->
dmsk
),
EBT_ARP_DST_IP
))
return
EBT_NOMATCH
;
}
}
return
EBT_MATCH
;
}
static
int
ebt_arp_check
(
const
char
*
tablename
,
unsigned
int
hookmask
,
const
struct
ebt_entry
*
e
,
void
*
data
,
unsigned
int
datalen
)
{
struct
ebt_arp_info
*
info
=
(
struct
ebt_arp_info
*
)
data
;
if
(
datalen
!=
sizeof
(
struct
ebt_arp_info
))
return
-
EINVAL
;
if
((
e
->
ethproto
!=
__constant_htons
(
ETH_P_ARP
)
&&
e
->
ethproto
!=
__constant_htons
(
ETH_P_RARP
))
||
e
->
invflags
&
EBT_IPROTO
)
return
-
EINVAL
;
if
(
info
->
bitmask
&
~
EBT_ARP_MASK
||
info
->
invflags
&
~
EBT_ARP_MASK
)
return
-
EINVAL
;
return
0
;
}
static
struct
ebt_match
filter_arp
=
{
{
NULL
,
NULL
},
EBT_ARP_MATCH
,
ebt_filter_arp
,
ebt_arp_check
,
NULL
,
THIS_MODULE
};
static
int
__init
init
(
void
)
{
return
ebt_register_match
(
&
filter_arp
);
}
static
void
__exit
fini
(
void
)
{
ebt_unregister_match
(
&
filter_arp
);
}
module_init
(
init
);
module_exit
(
fini
);
MODULE_LICENSE
(
"GPL"
);
net/bridge/netfilter/ebt_dnat.c
0 → 100644
View file @
b12d2ca2
/*
* ebt_dnat
*
* Authors:
* Bart De Schuymer <bart.de.schuymer@pandora.be>
*
* June, 2002
*
*/
#include <linux/netfilter_bridge/ebtables.h>
#include <linux/netfilter_bridge/ebt_nat.h>
#include <linux/module.h>
#include <net/sock.h>
static
int
ebt_target_dnat
(
struct
sk_buff
**
pskb
,
unsigned
int
hooknr
,
const
struct
net_device
*
in
,
const
struct
net_device
*
out
,
const
void
*
data
,
unsigned
int
datalen
)
{
struct
ebt_nat_info
*
info
=
(
struct
ebt_nat_info
*
)
data
;
memcpy
(((
**
pskb
).
mac
.
ethernet
)
->
h_dest
,
info
->
mac
,
ETH_ALEN
*
sizeof
(
unsigned
char
));
return
info
->
target
;
}
static
int
ebt_target_dnat_check
(
const
char
*
tablename
,
unsigned
int
hookmask
,
const
struct
ebt_entry
*
e
,
void
*
data
,
unsigned
int
datalen
)
{
struct
ebt_nat_info
*
info
=
(
struct
ebt_nat_info
*
)
data
;
if
(
BASE_CHAIN
&&
info
->
target
==
EBT_RETURN
)
return
-
EINVAL
;
CLEAR_BASE_CHAIN_BIT
;
if
(
(
strcmp
(
tablename
,
"nat"
)
||
(
hookmask
&
~
((
1
<<
NF_BR_PRE_ROUTING
)
|
(
1
<<
NF_BR_LOCAL_OUT
))))
&&
(
strcmp
(
tablename
,
"broute"
)
||
hookmask
&
~
(
1
<<
NF_BR_BROUTING
))
)
return
-
EINVAL
;
if
(
datalen
!=
sizeof
(
struct
ebt_nat_info
))
return
-
EINVAL
;
if
(
INVALID_TARGET
)
return
-
EINVAL
;
return
0
;
}
static
struct
ebt_target
dnat
=
{
{
NULL
,
NULL
},
EBT_DNAT_TARGET
,
ebt_target_dnat
,
ebt_target_dnat_check
,
NULL
,
THIS_MODULE
};
static
int
__init
init
(
void
)
{
return
ebt_register_target
(
&
dnat
);
}
static
void
__exit
fini
(
void
)
{
ebt_unregister_target
(
&
dnat
);
}
module_init
(
init
);
module_exit
(
fini
);
MODULE_LICENSE
(
"GPL"
);
net/bridge/netfilter/ebt_ip.c
0 → 100644
View file @
b12d2ca2
/*
* ebt_ip
*
* Authors:
* Bart De Schuymer <bart.de.schuymer@pandora.be>
*
* April, 2002
*
*/
#include <linux/netfilter_bridge/ebtables.h>
#include <linux/netfilter_bridge/ebt_ip.h>
#include <linux/ip.h>
#include <linux/module.h>
static
int
ebt_filter_ip
(
const
struct
sk_buff
*
skb
,
const
struct
net_device
*
in
,
const
struct
net_device
*
out
,
const
void
*
data
,
unsigned
int
datalen
)
{
struct
ebt_ip_info
*
info
=
(
struct
ebt_ip_info
*
)
data
;
if
(
info
->
bitmask
&
EBT_IP_TOS
&&
FWINV
(
info
->
tos
!=
((
*
skb
).
nh
.
iph
)
->
tos
,
EBT_IP_TOS
))
return
EBT_NOMATCH
;
if
(
info
->
bitmask
&
EBT_IP_PROTO
&&
FWINV
(
info
->
protocol
!=
((
*
skb
).
nh
.
iph
)
->
protocol
,
EBT_IP_PROTO
))
return
EBT_NOMATCH
;
if
(
info
->
bitmask
&
EBT_IP_SOURCE
&&
FWINV
((((
*
skb
).
nh
.
iph
)
->
saddr
&
info
->
smsk
)
!=
info
->
saddr
,
EBT_IP_SOURCE
))
return
EBT_NOMATCH
;
if
((
info
->
bitmask
&
EBT_IP_DEST
)
&&
FWINV
((((
*
skb
).
nh
.
iph
)
->
daddr
&
info
->
dmsk
)
!=
info
->
daddr
,
EBT_IP_DEST
))
return
EBT_NOMATCH
;
return
EBT_MATCH
;
}
static
int
ebt_ip_check
(
const
char
*
tablename
,
unsigned
int
hookmask
,
const
struct
ebt_entry
*
e
,
void
*
data
,
unsigned
int
datalen
)
{
struct
ebt_ip_info
*
info
=
(
struct
ebt_ip_info
*
)
data
;
if
(
datalen
!=
sizeof
(
struct
ebt_ip_info
))
return
-
EINVAL
;
if
(
e
->
ethproto
!=
__constant_htons
(
ETH_P_IP
)
||
e
->
invflags
&
EBT_IPROTO
)
return
-
EINVAL
;
if
(
info
->
bitmask
&
~
EBT_IP_MASK
||
info
->
invflags
&
~
EBT_IP_MASK
)
return
-
EINVAL
;
return
0
;
}
static
struct
ebt_match
filter_ip
=
{
{
NULL
,
NULL
},
EBT_IP_MATCH
,
ebt_filter_ip
,
ebt_ip_check
,
NULL
,
THIS_MODULE
};
static
int
__init
init
(
void
)
{
return
ebt_register_match
(
&
filter_ip
);
}
static
void
__exit
fini
(
void
)
{
ebt_unregister_match
(
&
filter_ip
);
}
module_init
(
init
);
module_exit
(
fini
);
MODULE_LICENSE
(
"GPL"
);
net/bridge/netfilter/ebt_log.c
0 → 100644
View file @
b12d2ca2
/*
* ebt_log
*
* Authors:
* Bart De Schuymer <bart.de.schuymer@pandora.be>
*
* April, 2002
*
*/
#include <linux/netfilter_bridge/ebtables.h>
#include <linux/netfilter_bridge/ebt_log.h>
#include <linux/module.h>
#include <linux/ip.h>
#include <linux/if_arp.h>
#include <linux/spinlock.h>
static
spinlock_t
ebt_log_lock
=
SPIN_LOCK_UNLOCKED
;
static
int
ebt_log_check
(
const
char
*
tablename
,
unsigned
int
hookmask
,
const
struct
ebt_entry
*
e
,
void
*
data
,
unsigned
int
datalen
)
{
struct
ebt_log_info
*
info
=
(
struct
ebt_log_info
*
)
data
;
if
(
datalen
!=
sizeof
(
struct
ebt_log_info
))
return
-
EINVAL
;
if
(
info
->
bitmask
&
~
EBT_LOG_MASK
)
return
-
EINVAL
;
if
(
info
->
loglevel
>=
8
)
return
-
EINVAL
;
info
->
prefix
[
EBT_LOG_PREFIX_SIZE
-
1
]
=
'\0'
;
return
0
;
}
static
void
ebt_log
(
const
struct
sk_buff
*
skb
,
const
struct
net_device
*
in
,
const
struct
net_device
*
out
,
const
void
*
data
,
unsigned
int
datalen
)
{
struct
ebt_log_info
*
info
=
(
struct
ebt_log_info
*
)
data
;
char
level_string
[
4
]
=
"< >"
;
level_string
[
1
]
=
'0'
+
info
->
loglevel
;
spin_lock_bh
(
&
ebt_log_lock
);
printk
(
level_string
);
printk
(
"%s IN=%s OUT=%s "
,
info
->
prefix
,
in
?
in
->
name
:
""
,
out
?
out
->
name
:
""
);
if
(
skb
->
dev
->
hard_header_len
)
{
int
i
;
unsigned
char
*
p
=
(
skb
->
mac
.
ethernet
)
->
h_source
;
printk
(
"MAC source = "
);
for
(
i
=
0
;
i
<
ETH_ALEN
;
i
++
,
p
++
)
printk
(
"%02x%c"
,
*
p
,
i
==
ETH_ALEN
-
1
?
' '
:
':'
);
printk
(
"MAC dest = "
);
p
=
(
skb
->
mac
.
ethernet
)
->
h_dest
;
for
(
i
=
0
;
i
<
ETH_ALEN
;
i
++
,
p
++
)
printk
(
"%02x%c"
,
*
p
,
i
==
ETH_ALEN
-
1
?
' '
:
':'
);
}
printk
(
"proto = 0x%04x"
,
ntohs
(((
*
skb
).
mac
.
ethernet
)
->
h_proto
));
if
((
info
->
bitmask
&
EBT_LOG_IP
)
&&
skb
->
mac
.
ethernet
->
h_proto
==
htons
(
ETH_P_IP
)){
struct
iphdr
*
iph
=
skb
->
nh
.
iph
;
printk
(
" IP SRC=%u.%u.%u.%u IP DST=%u.%u.%u.%u,"
,
NIPQUAD
(
iph
->
saddr
),
NIPQUAD
(
iph
->
daddr
));
printk
(
" IP tos=0x%02X, IP proto=%d"
,
iph
->
tos
,
iph
->
protocol
);
}
if
((
info
->
bitmask
&
EBT_LOG_ARP
)
&&
((
skb
->
mac
.
ethernet
->
h_proto
==
__constant_htons
(
ETH_P_ARP
))
||
(
skb
->
mac
.
ethernet
->
h_proto
==
__constant_htons
(
ETH_P_RARP
))))
{
struct
arphdr
*
arph
=
skb
->
nh
.
arph
;
printk
(
" ARP HTYPE=%d, PTYPE=0x%04x, OPCODE=%d"
,
ntohs
(
arph
->
ar_hrd
),
ntohs
(
arph
->
ar_pro
),
ntohs
(
arph
->
ar_op
));
}
printk
(
"
\n
"
);
spin_unlock_bh
(
&
ebt_log_lock
);
}
struct
ebt_watcher
log
=
{
{
NULL
,
NULL
},
EBT_LOG_WATCHER
,
ebt_log
,
ebt_log_check
,
NULL
,
THIS_MODULE
};
static
int
__init
init
(
void
)
{
return
ebt_register_watcher
(
&
log
);
}
static
void
__exit
fini
(
void
)
{
ebt_unregister_watcher
(
&
log
);
}
module_init
(
init
);
module_exit
(
fini
);
MODULE_LICENSE
(
"GPL"
);
net/bridge/netfilter/ebt_mark.c
0 → 100644
View file @
b12d2ca2
/*
* ebt_mark
*
* Authors:
* Bart De Schuymer <bart.de.schuymer@pandora.be>
*
* July, 2002
*
*/
// The mark target can be used in any chain
// I believe adding a mangle table just for marking is total overkill
// Marking a frame doesn't really change anything in the frame anyway
#include <linux/netfilter_bridge/ebtables.h>
#include <linux/netfilter_bridge/ebt_mark_t.h>
#include <linux/module.h>
static
int
ebt_target_mark
(
struct
sk_buff
**
pskb
,
unsigned
int
hooknr
,
const
struct
net_device
*
in
,
const
struct
net_device
*
out
,
const
void
*
data
,
unsigned
int
datalen
)
{
struct
ebt_mark_t_info
*
info
=
(
struct
ebt_mark_t_info
*
)
data
;
if
((
*
pskb
)
->
nfmark
!=
info
->
mark
)
{
(
*
pskb
)
->
nfmark
=
info
->
mark
;
(
*
pskb
)
->
nfcache
|=
NFC_ALTERED
;
}
return
info
->
target
;
}
static
int
ebt_target_mark_check
(
const
char
*
tablename
,
unsigned
int
hookmask
,
const
struct
ebt_entry
*
e
,
void
*
data
,
unsigned
int
datalen
)
{
struct
ebt_mark_t_info
*
info
=
(
struct
ebt_mark_t_info
*
)
data
;
if
(
datalen
!=
sizeof
(
struct
ebt_mark_t_info
))
return
-
EINVAL
;
if
(
BASE_CHAIN
&&
info
->
target
==
EBT_RETURN
)
return
-
EINVAL
;
CLEAR_BASE_CHAIN_BIT
;
if
(
INVALID_TARGET
)
return
-
EINVAL
;
return
0
;
}
static
struct
ebt_target
mark_target
=
{
{
NULL
,
NULL
},
EBT_MARK_TARGET
,
ebt_target_mark
,
ebt_target_mark_check
,
NULL
,
THIS_MODULE
};
static
int
__init
init
(
void
)
{
return
ebt_register_target
(
&
mark_target
);
}
static
void
__exit
fini
(
void
)
{
ebt_unregister_target
(
&
mark_target
);
}
module_init
(
init
);
module_exit
(
fini
);
MODULE_LICENSE
(
"GPL"
);
net/bridge/netfilter/ebt_mark_m.c
0 → 100644
View file @
b12d2ca2
/*
* ebt_mark_m
*
* Authors:
* Bart De Schuymer <bart.de.schuymer@pandora.be>
*
* July, 2002
*
*/
#include <linux/netfilter_bridge/ebtables.h>
#include <linux/netfilter_bridge/ebt_mark_m.h>
#include <linux/module.h>
static
int
ebt_filter_mark
(
const
struct
sk_buff
*
skb
,
const
struct
net_device
*
in
,
const
struct
net_device
*
out
,
const
void
*
data
,
unsigned
int
datalen
)
{
struct
ebt_mark_m_info
*
info
=
(
struct
ebt_mark_m_info
*
)
data
;
if
(
info
->
bitmask
&
EBT_MARK_OR
)
return
!
(
!!
(
skb
->
nfmark
&
info
->
mask
)
^
info
->
invert
);
return
!
(((
skb
->
nfmark
&
info
->
mask
)
==
info
->
mark
)
^
info
->
invert
);
}
static
int
ebt_mark_check
(
const
char
*
tablename
,
unsigned
int
hookmask
,
const
struct
ebt_entry
*
e
,
void
*
data
,
unsigned
int
datalen
)
{
struct
ebt_mark_m_info
*
info
=
(
struct
ebt_mark_m_info
*
)
data
;
if
(
datalen
!=
sizeof
(
struct
ebt_mark_m_info
))
return
-
EINVAL
;
if
(
info
->
bitmask
&
~
EBT_MARK_MASK
)
return
-
EINVAL
;
if
((
info
->
bitmask
&
EBT_MARK_OR
)
&&
(
info
->
bitmask
&
EBT_MARK_AND
))
return
-
EINVAL
;
if
(
!
info
->
bitmask
)
return
-
EINVAL
;
return
0
;
}
static
struct
ebt_match
filter_mark
=
{
{
NULL
,
NULL
},
EBT_MARK_MATCH
,
ebt_filter_mark
,
ebt_mark_check
,
NULL
,
THIS_MODULE
};
static
int
__init
init
(
void
)
{
return
ebt_register_match
(
&
filter_mark
);
}
static
void
__exit
fini
(
void
)
{
ebt_unregister_match
(
&
filter_mark
);
}
module_init
(
init
);
module_exit
(
fini
);
MODULE_LICENSE
(
"GPL"
);
net/bridge/netfilter/ebt_redirect.c
0 → 100644
View file @
b12d2ca2
/*
* ebt_redirect
*
* Authors:
* Bart De Schuymer <bart.de.schuymer@pandora.be>
*
* April, 2002
*
*/
#include <linux/netfilter_bridge/ebtables.h>
#include <linux/netfilter_bridge/ebt_redirect.h>
#include <linux/module.h>
#include <net/sock.h>
#include "../br_private.h"
static
int
ebt_target_redirect
(
struct
sk_buff
**
pskb
,
unsigned
int
hooknr
,
const
struct
net_device
*
in
,
const
struct
net_device
*
out
,
const
void
*
data
,
unsigned
int
datalen
)
{
struct
ebt_redirect_info
*
info
=
(
struct
ebt_redirect_info
*
)
data
;
if
(
hooknr
!=
NF_BR_BROUTING
)
memcpy
((
**
pskb
).
mac
.
ethernet
->
h_dest
,
in
->
br_port
->
br
->
dev
.
dev_addr
,
ETH_ALEN
);
else
{
memcpy
((
**
pskb
).
mac
.
ethernet
->
h_dest
,
in
->
dev_addr
,
ETH_ALEN
);
(
*
pskb
)
->
pkt_type
=
PACKET_HOST
;
}
return
info
->
target
;
}
static
int
ebt_target_redirect_check
(
const
char
*
tablename
,
unsigned
int
hookmask
,
const
struct
ebt_entry
*
e
,
void
*
data
,
unsigned
int
datalen
)
{
struct
ebt_redirect_info
*
info
=
(
struct
ebt_redirect_info
*
)
data
;
if
(
datalen
!=
sizeof
(
struct
ebt_redirect_info
))
return
-
EINVAL
;
if
(
BASE_CHAIN
&&
info
->
target
==
EBT_RETURN
)
return
-
EINVAL
;
CLEAR_BASE_CHAIN_BIT
;
if
(
(
strcmp
(
tablename
,
"nat"
)
||
hookmask
&
~
(
1
<<
NF_BR_PRE_ROUTING
))
&&
(
strcmp
(
tablename
,
"broute"
)
||
hookmask
&
~
(
1
<<
NF_BR_BROUTING
))
)
return
-
EINVAL
;
if
(
INVALID_TARGET
)
return
-
EINVAL
;
return
0
;
}
static
struct
ebt_target
redirect_target
=
{
{
NULL
,
NULL
},
EBT_REDIRECT_TARGET
,
ebt_target_redirect
,
ebt_target_redirect_check
,
NULL
,
THIS_MODULE
};
static
int
__init
init
(
void
)
{
return
ebt_register_target
(
&
redirect_target
);
}
static
void
__exit
fini
(
void
)
{
ebt_unregister_target
(
&
redirect_target
);
}
module_init
(
init
);
module_exit
(
fini
);
MODULE_LICENSE
(
"GPL"
);
net/bridge/netfilter/ebt_snat.c
0 → 100644
View file @
b12d2ca2
/*
* ebt_snat
*
* Authors:
* Bart De Schuymer <bart.de.schuymer@pandora.be>
*
* June, 2002
*
*/
#include <linux/netfilter_bridge/ebtables.h>
#include <linux/netfilter_bridge/ebt_nat.h>
#include <linux/module.h>
static
int
ebt_target_snat
(
struct
sk_buff
**
pskb
,
unsigned
int
hooknr
,
const
struct
net_device
*
in
,
const
struct
net_device
*
out
,
const
void
*
data
,
unsigned
int
datalen
)
{
struct
ebt_nat_info
*
info
=
(
struct
ebt_nat_info
*
)
data
;
memcpy
(((
**
pskb
).
mac
.
ethernet
)
->
h_source
,
info
->
mac
,
ETH_ALEN
*
sizeof
(
unsigned
char
));
return
info
->
target
;
}
static
int
ebt_target_snat_check
(
const
char
*
tablename
,
unsigned
int
hookmask
,
const
struct
ebt_entry
*
e
,
void
*
data
,
unsigned
int
datalen
)
{
struct
ebt_nat_info
*
info
=
(
struct
ebt_nat_info
*
)
data
;
if
(
datalen
!=
sizeof
(
struct
ebt_nat_info
))
return
-
EINVAL
;
if
(
BASE_CHAIN
&&
info
->
target
==
EBT_RETURN
)
return
-
EINVAL
;
CLEAR_BASE_CHAIN_BIT
;
if
(
strcmp
(
tablename
,
"nat"
))
return
-
EINVAL
;
if
(
hookmask
&
~
(
1
<<
NF_BR_POST_ROUTING
))
return
-
EINVAL
;
if
(
INVALID_TARGET
)
return
-
EINVAL
;
return
0
;
}
static
struct
ebt_target
snat
=
{
{
NULL
,
NULL
},
EBT_SNAT_TARGET
,
ebt_target_snat
,
ebt_target_snat_check
,
NULL
,
THIS_MODULE
};
static
int
__init
init
(
void
)
{
return
ebt_register_target
(
&
snat
);
}
static
void
__exit
fini
(
void
)
{
ebt_unregister_target
(
&
snat
);
}
module_init
(
init
);
module_exit
(
fini
);
MODULE_LICENSE
(
"GPL"
);
net/bridge/netfilter/ebt_vlan.c
0 → 100644
View file @
b12d2ca2
/*
* Description: EBTables 802.1Q match extension kernelspace module.
* Authors: Nick Fedchik <nick@fedchik.org.ua>
* Bart De Schuymer <bart.de.schuymer@pandora.be>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/if_ether.h>
#include <linux/if_vlan.h>
#include <linux/module.h>
#include <linux/netfilter_bridge/ebtables.h>
#include <linux/netfilter_bridge/ebt_vlan.h>
static
unsigned
char
debug
;
#define MODULE_VERSION "0.4 (" __DATE__ " " __TIME__ ")"
MODULE_PARM
(
debug
,
"0-1b"
);
MODULE_PARM_DESC
(
debug
,
"debug=1 is turn on debug messages"
);
MODULE_AUTHOR
(
"Nick Fedchik <nick@fedchik.org.ua>"
);
MODULE_DESCRIPTION
(
"802.1Q match module (ebtables extension), v"
MODULE_VERSION
);
MODULE_LICENSE
(
"GPL"
);
#define DEBUG_MSG(...) if (debug) printk (KERN_DEBUG __FILE__ ":" __VA_ARGS__)
#define INV_FLAG(_inv_flag_) (info->invflags & _inv_flag_) ? "!" : ""
#define GET_BITMASK(_BIT_MASK_) info->bitmask & _BIT_MASK_
#define SET_BITMASK(_BIT_MASK_) info->bitmask |= _BIT_MASK_
#define EXIT_ON_MISMATCH(_MATCH_,_MASK_) if (!((info->_MATCH_ == _MATCH_)^!!(info->invflags & _MASK_))) return 1;
/*
* Function description: ebt_filter_vlan() is main engine for
* checking passed 802.1Q frame according to
* the passed extension parameters (in the *data buffer)
* ebt_filter_vlan() is called after successfull check the rule params
* by ebt_check_vlan() function.
* Parameters:
* const struct sk_buff *skb - pointer to passed ethernet frame buffer
* const void *data - pointer to passed extension parameters
* unsigned int datalen - length of passed *data buffer
* const struct net_device *in -
* const struct net_device *out -
* const struct ebt_counter *c -
* Returned values:
* 0 - ok (all rule params matched)
* 1 - miss (rule params not acceptable to the parsed frame)
*/
static
int
ebt_filter_vlan
(
const
struct
sk_buff
*
skb
,
const
struct
net_device
*
in
,
const
struct
net_device
*
out
,
const
void
*
data
,
unsigned
int
datalen
)
{
struct
ebt_vlan_info
*
info
=
(
struct
ebt_vlan_info
*
)
data
;
/* userspace data */
struct
vlan_ethhdr
*
frame
=
(
struct
vlan_ethhdr
*
)
skb
->
mac
.
raw
;
/* Passed tagged frame */
unsigned
short
TCI
;
/* Whole TCI, given from parsed frame */
unsigned
short
id
;
/* VLAN ID, given from frame TCI */
unsigned
char
prio
;
/* user_priority, given from frame TCI */
unsigned
short
encap
;
/* VLAN encapsulated Type/Length field, given from orig frame */
/*
* Tag Control Information (TCI) consists of the following elements:
* - User_priority. This field allows the tagged frame to carry user_priority
* information across Bridged LANs in which individual LAN segments may be unable to signal
* priority information (e.g., 802.3/Ethernet segments).
* The user_priority field is three bits in length,
* interpreted as a binary number. The user_priority is therefore
* capable of representing eight priority levels, 0 through 7.
* The use and interpretation of this field is defined in ISO/IEC 15802-3.
* - Canonical Format Indicator (CFI). This field is used,
* in 802.3/Ethernet, to signal the presence or absence
* of a RIF field, and, in combination with the Non-canonical Format Indicator (NCFI) carried
* in the RIF, to signal the bit order of address information carried in the encapsulated
* frame. The Canonical Format Indicator (CFI) is a single bit flag value.
* - VLAN Identifier (VID). This field uniquely identifies the VLAN to
* which the frame belongs. The twelve-bit VLAN Identifier (VID) field
* uniquely identify the VLAN to which the frame belongs.
* The VID is encoded as an unsigned binary number.
*/
TCI
=
ntohs
(
frame
->
h_vlan_TCI
);
id
=
TCI
&
0xFFF
;
prio
=
TCI
>>
13
;
encap
=
frame
->
h_vlan_encapsulated_proto
;
/*
* First step is to check is null VLAN ID present
* in the parsed frame
*/
if
(
!
(
id
))
{
/*
* Checking VLAN Identifier (VID)
*/
if
(
GET_BITMASK
(
EBT_VLAN_ID
))
{
/* Is VLAN ID parsed? */
EXIT_ON_MISMATCH
(
id
,
EBT_VLAN_ID
);
DEBUG_MSG
(
"matched rule id=%s%d for frame id=%d
\n
"
,
INV_FLAG
(
EBT_VLAN_ID
),
info
->
id
,
id
);
}
}
else
{
/*
* Checking user_priority
*/
if
(
GET_BITMASK
(
EBT_VLAN_PRIO
))
{
/* Is VLAN user_priority parsed? */
EXIT_ON_MISMATCH
(
prio
,
EBT_VLAN_PRIO
);
DEBUG_MSG
(
"matched rule prio=%s%d for frame prio=%d
\n
"
,
INV_FLAG
(
EBT_VLAN_PRIO
),
info
->
prio
,
prio
);
}
}
/*
* Checking Encapsulated Proto (Length/Type) field
*/
if
(
GET_BITMASK
(
EBT_VLAN_ENCAP
))
{
/* Is VLAN Encap parsed? */
EXIT_ON_MISMATCH
(
encap
,
EBT_VLAN_ENCAP
);
DEBUG_MSG
(
"matched encap=%s%2.4X for frame encap=%2.4X
\n
"
,
INV_FLAG
(
EBT_VLAN_ENCAP
),
ntohs
(
info
->
encap
),
ntohs
(
encap
));
}
/*
* All possible extension parameters was parsed.
* If rule never returned by missmatch, then all ok.
*/
return
0
;
}
/*
* Function description: ebt_vlan_check() is called when userspace
* delivers the table to the kernel,
* and to check that userspace doesn't give a bad table.
* Parameters:
* const char *tablename - table name string
* unsigned int hooknr - hook number
* const struct ebt_entry *e - ebtables entry basic set
* const void *data - pointer to passed extension parameters
* unsigned int datalen - length of passed *data buffer
* Returned values:
* 0 - ok (all delivered rule params are correct)
* 1 - miss (rule params is out of range, invalid, incompatible, etc.)
*/
static
int
ebt_check_vlan
(
const
char
*
tablename
,
unsigned
int
hooknr
,
const
struct
ebt_entry
*
e
,
void
*
data
,
unsigned
int
datalen
)
{
struct
ebt_vlan_info
*
info
=
(
struct
ebt_vlan_info
*
)
data
;
/*
* Parameters buffer overflow check
*/
if
(
datalen
!=
sizeof
(
struct
ebt_vlan_info
))
{
DEBUG_MSG
(
"params size %d is not eq to ebt_vlan_info (%d)
\n
"
,
datalen
,
sizeof
(
struct
ebt_vlan_info
));
return
-
EINVAL
;
}
/*
* Is it 802.1Q frame checked?
*/
if
(
e
->
ethproto
!=
__constant_htons
(
ETH_P_8021Q
))
{
DEBUG_MSG
(
"passed entry proto %2.4X is not 802.1Q (8100)
\n
"
,
(
unsigned
short
)
ntohs
(
e
->
ethproto
));
return
-
EINVAL
;
}
/*
* Check for bitmask range
* True if even one bit is out of mask
*/
if
(
info
->
bitmask
&
~
EBT_VLAN_MASK
)
{
DEBUG_MSG
(
"bitmask %2X is out of mask (%2X)
\n
"
,
info
->
bitmask
,
EBT_VLAN_MASK
);
return
-
EINVAL
;
}
/*
* Check for inversion flags range
*/
if
(
info
->
invflags
&
~
EBT_VLAN_MASK
)
{
DEBUG_MSG
(
"inversion flags %2X is out of mask (%2X)
\n
"
,
info
->
invflags
,
EBT_VLAN_MASK
);
return
-
EINVAL
;
}
/*
* Reserved VLAN ID (VID) values
* -----------------------------
* 0 - The null VLAN ID. Indicates that the tag header contains only user_priority information;
* no VLAN identifier is present in the frame. This VID value shall not be
* configured as a PVID, configured in any Filtering Database entry, or used in any
* Management operation.
*
* 1 - The default Port VID (PVID) value used for classifying frames on ingress through a Bridge
* Port. The PVID value can be changed by management on a per-Port basis.
*
* 0x0FFF - Reserved for implementation use. This VID value shall not be configured as a
* PVID or transmitted in a tag header.
*
* The remaining values of VID are available for general use as VLAN identifiers.
* A Bridge may implement the ability to support less than the full range of VID values;
* i.e., for a given implementation,
* an upper limit, N, is defined for the VID values supported, where N is less than or equal to 4094.
* All implementations shall support the use of all VID values in the range 0 through their defined maximum
* VID, N.
*
* For Linux, N = 4094.
*/
if
(
GET_BITMASK
(
EBT_VLAN_ID
))
{
/* when vlan-id param was spec-ed */
if
(
!!
info
->
id
)
{
/* if id!=0 => check vid range */
if
(
info
->
id
>
4094
)
{
/* check if id > than (0x0FFE) */
DEBUG_MSG
(
"vlan id %d is out of range (1-4094)
\n
"
,
info
->
id
);
return
-
EINVAL
;
}
/*
* Note: This is valid VLAN-tagged frame point.
* Any value of user_priority are acceptable, but could be ignored
* according to 802.1Q Std.
*/
}
else
{
/*
* if id=0 (null VLAN ID) => Check for user_priority range
*/
if
(
GET_BITMASK
(
EBT_VLAN_PRIO
))
{
if
((
unsigned
char
)
info
->
prio
>
7
)
{
DEBUG_MSG
(
"prio %d is out of range (0-7)
\n
"
,
info
->
prio
);
return
-
EINVAL
;
}
}
/*
* Note2: This is valid priority-tagged frame point
* with null VID field.
*/
}
}
else
{
/* VLAN Id not set */
if
(
GET_BITMASK
(
EBT_VLAN_PRIO
))
{
/* But user_priority is set - abnormal! */
info
->
id
=
0
;
/* Set null VID (case for Priority-tagged frames) */
SET_BITMASK
(
EBT_VLAN_ID
);
/* and set id flag */
}
}
/*
* Check for encapsulated proto range - it is possible to be any value for u_short range.
* When relaying a tagged frame between 802.3/Ethernet MACs,
* a Bridge may adjust the padding field such that
* the minimum size of a transmitted tagged frame is 68 octets (7.2).
* if_ether.h: ETH_ZLEN 60 - Min. octets in frame sans FCS
*/
if
(
GET_BITMASK
(
EBT_VLAN_ENCAP
))
{
if
((
unsigned
short
)
ntohs
(
info
->
encap
)
<
ETH_ZLEN
)
{
DEBUG_MSG
(
"encap packet length %d is less than minimal %d
\n
"
,
ntohs
(
info
->
encap
),
ETH_ZLEN
);
return
-
EINVAL
;
}
}
/*
* Otherwise is all correct
*/
DEBUG_MSG
(
"802.1Q tagged frame checked (%s table, %d hook)
\n
"
,
tablename
,
hooknr
);
return
0
;
}
static
struct
ebt_match
filter_vlan
=
{
{
NULL
,
NULL
},
EBT_VLAN_MATCH
,
ebt_filter_vlan
,
ebt_check_vlan
,
NULL
,
THIS_MODULE
};
/*
* Module initialization function.
* Called when module is loaded to kernelspace
*/
static
int
__init
init
(
void
)
{
DEBUG_MSG
(
"ebtables 802.1Q extension module v"
MODULE_VERSION
"
\n
"
);
DEBUG_MSG
(
"module debug=%d
\n
"
,
!!
debug
);
return
ebt_register_match
(
&
filter_vlan
);
}
/*
* Module "finalization" function
* Called when download module from kernelspace
*/
static
void
__exit
fini
(
void
)
{
ebt_unregister_match
(
&
filter_vlan
);
}
module_init
(
init
);
module_exit
(
fini
);
net/bridge/netfilter/ebtable_broute.c
0 → 100644
View file @
b12d2ca2
/*
* ebtable_broute
*
* Authors:
* Bart De Schuymer <bart.de.schuymer@pandora.be>
*
* April, 2002
*
* This table lets you choose between routing and bridging for frames
* entering on a bridge enslaved nic. This table is traversed before any
* other ebtables table. See net/bridge/br_input.c.
*/
#include <linux/netfilter_bridge/ebtables.h>
#include <linux/module.h>
#include <linux/if_bridge.h>
#include <linux/brlock.h>
// EBT_ACCEPT means the frame will be bridged
// EBT_DROP means the frame will be routed
static
struct
ebt_entries
initial_chain
=
{
0
,
"BROUTING"
,
0
,
EBT_ACCEPT
,
0
};
static
struct
ebt_replace
initial_table
=
{
"broute"
,
1
<<
NF_BR_BROUTING
,
0
,
sizeof
(
struct
ebt_entries
),
{
[
NF_BR_BROUTING
]
&
initial_chain
},
0
,
NULL
,
(
char
*
)
&
initial_chain
};
static
int
check
(
const
struct
ebt_table_info
*
info
,
unsigned
int
valid_hooks
)
{
if
(
valid_hooks
&
~
(
1
<<
NF_BR_BROUTING
))
return
-
EINVAL
;
return
0
;
}
static
struct
ebt_table
broute_table
=
{
{
NULL
,
NULL
},
"broute"
,
&
initial_table
,
1
<<
NF_BR_BROUTING
,
RW_LOCK_UNLOCKED
,
check
,
NULL
};
static
int
ebt_broute
(
struct
sk_buff
**
pskb
)
{
int
ret
;
ret
=
ebt_do_table
(
NF_BR_BROUTING
,
pskb
,
(
*
pskb
)
->
dev
,
NULL
,
&
broute_table
);
if
(
ret
==
NF_DROP
)
return
1
;
// route it
return
0
;
// bridge it
}
static
int
__init
init
(
void
)
{
int
ret
;
ret
=
ebt_register_table
(
&
broute_table
);
if
(
ret
<
0
)
return
ret
;
br_write_lock_bh
(
BR_NETPROTO_LOCK
);
// see br_input.c
br_should_route_hook
=
ebt_broute
;
br_write_unlock_bh
(
BR_NETPROTO_LOCK
);
return
ret
;
}
static
void
__exit
fini
(
void
)
{
br_write_lock_bh
(
BR_NETPROTO_LOCK
);
br_should_route_hook
=
NULL
;
br_write_unlock_bh
(
BR_NETPROTO_LOCK
);
ebt_unregister_table
(
&
broute_table
);
}
module_init
(
init
);
module_exit
(
fini
);
MODULE_LICENSE
(
"GPL"
);
net/bridge/netfilter/ebtable_filter.c
0 → 100644
View file @
b12d2ca2
/*
* ebtable_filter
*
* Authors:
* Bart De Schuymer <bart.de.schuymer@pandora.be>
*
* April, 2002
*
*/
#include <linux/netfilter_bridge/ebtables.h>
#include <linux/module.h>
#define FILTER_VALID_HOOKS ((1 << NF_BR_LOCAL_IN) | (1 << NF_BR_FORWARD) | \
(1 << NF_BR_LOCAL_OUT))
static
struct
ebt_entries
initial_chains
[]
=
{
{
0
,
"INPUT"
,
0
,
EBT_ACCEPT
,
0
},
{
0
,
"FORWARD"
,
0
,
EBT_ACCEPT
,
0
},
{
0
,
"OUTPUT"
,
0
,
EBT_ACCEPT
,
0
}
};
static
struct
ebt_replace
initial_table
=
{
"filter"
,
FILTER_VALID_HOOKS
,
0
,
3
*
sizeof
(
struct
ebt_entries
),
{
[
NF_BR_LOCAL_IN
]
&
initial_chains
[
0
],
[
NF_BR_FORWARD
]
&
initial_chains
[
1
],
[
NF_BR_LOCAL_OUT
]
&
initial_chains
[
2
]
},
0
,
NULL
,
(
char
*
)
initial_chains
};
static
int
check
(
const
struct
ebt_table_info
*
info
,
unsigned
int
valid_hooks
)
{
if
(
valid_hooks
&
~
FILTER_VALID_HOOKS
)
return
-
EINVAL
;
return
0
;
}
static
struct
ebt_table
frame_filter
=
{
{
NULL
,
NULL
},
"filter"
,
&
initial_table
,
FILTER_VALID_HOOKS
,
RW_LOCK_UNLOCKED
,
check
,
NULL
};
static
unsigned
int
ebt_hook
(
unsigned
int
hook
,
struct
sk_buff
**
pskb
,
const
struct
net_device
*
in
,
const
struct
net_device
*
out
,
int
(
*
okfn
)(
struct
sk_buff
*
))
{
return
ebt_do_table
(
hook
,
pskb
,
in
,
out
,
&
frame_filter
);
}
static
struct
nf_hook_ops
ebt_ops_filter
[]
=
{
{
{
NULL
,
NULL
},
ebt_hook
,
PF_BRIDGE
,
NF_BR_LOCAL_IN
,
NF_BR_PRI_FILTER_BRIDGED
},
{
{
NULL
,
NULL
},
ebt_hook
,
PF_BRIDGE
,
NF_BR_FORWARD
,
NF_BR_PRI_FILTER_BRIDGED
},
{
{
NULL
,
NULL
},
ebt_hook
,
PF_BRIDGE
,
NF_BR_LOCAL_OUT
,
NF_BR_PRI_FILTER_OTHER
}
};
static
int
__init
init
(
void
)
{
int
i
,
j
,
ret
;
ret
=
ebt_register_table
(
&
frame_filter
);
if
(
ret
<
0
)
return
ret
;
for
(
i
=
0
;
i
<
sizeof
(
ebt_ops_filter
)
/
sizeof
(
ebt_ops_filter
[
0
]);
i
++
)
if
((
ret
=
nf_register_hook
(
&
ebt_ops_filter
[
i
]))
<
0
)
goto
cleanup
;
return
ret
;
cleanup:
for
(
j
=
0
;
j
<
i
;
j
++
)
nf_unregister_hook
(
&
ebt_ops_filter
[
j
]);
ebt_unregister_table
(
&
frame_filter
);
return
ret
;
}
static
void
__exit
fini
(
void
)
{
int
i
;
for
(
i
=
0
;
i
<
sizeof
(
ebt_ops_filter
)
/
sizeof
(
ebt_ops_filter
[
0
]);
i
++
)
nf_unregister_hook
(
&
ebt_ops_filter
[
i
]);
ebt_unregister_table
(
&
frame_filter
);
}
module_init
(
init
);
module_exit
(
fini
);
MODULE_LICENSE
(
"GPL"
);
net/bridge/netfilter/ebtable_nat.c
0 → 100644
View file @
b12d2ca2
/*
* ebtable_nat
*
* Authors:
* Bart De Schuymer <bart.de.schuymer@pandora.be>
*
* April, 2002
*
*/
#include <linux/netfilter_bridge/ebtables.h>
#include <linux/module.h>
#define NAT_VALID_HOOKS ((1 << NF_BR_PRE_ROUTING) | (1 << NF_BR_LOCAL_OUT) | \
(1 << NF_BR_POST_ROUTING))
static
struct
ebt_entries
initial_chains
[]
=
{
{
0
,
"PREROUTING"
,
0
,
EBT_ACCEPT
,
0
},
{
0
,
"OUTPUT"
,
0
,
EBT_ACCEPT
,
0
},
{
0
,
"POSTROUTING"
,
0
,
EBT_ACCEPT
,
0
}
};
static
struct
ebt_replace
initial_table
=
{
"nat"
,
NAT_VALID_HOOKS
,
0
,
3
*
sizeof
(
struct
ebt_entries
),
{
[
NF_BR_PRE_ROUTING
]
&
initial_chains
[
0
],
[
NF_BR_LOCAL_OUT
]
&
initial_chains
[
1
],
[
NF_BR_POST_ROUTING
]
&
initial_chains
[
2
]
},
0
,
NULL
,
(
char
*
)
initial_chains
};
static
int
check
(
const
struct
ebt_table_info
*
info
,
unsigned
int
valid_hooks
)
{
if
(
valid_hooks
&
~
NAT_VALID_HOOKS
)
return
-
EINVAL
;
return
0
;
}
static
struct
ebt_table
frame_nat
=
{
{
NULL
,
NULL
},
"nat"
,
&
initial_table
,
NAT_VALID_HOOKS
,
RW_LOCK_UNLOCKED
,
check
,
NULL
};
static
unsigned
int
ebt_nat_dst
(
unsigned
int
hook
,
struct
sk_buff
**
pskb
,
const
struct
net_device
*
in
,
const
struct
net_device
*
out
,
int
(
*
okfn
)(
struct
sk_buff
*
))
{
return
ebt_do_table
(
hook
,
pskb
,
in
,
out
,
&
frame_nat
);
}
static
unsigned
int
ebt_nat_src
(
unsigned
int
hook
,
struct
sk_buff
**
pskb
,
const
struct
net_device
*
in
,
const
struct
net_device
*
out
,
int
(
*
okfn
)(
struct
sk_buff
*
))
{
return
ebt_do_table
(
hook
,
pskb
,
in
,
out
,
&
frame_nat
);
}
static
struct
nf_hook_ops
ebt_ops_nat
[]
=
{
{
{
NULL
,
NULL
},
ebt_nat_dst
,
PF_BRIDGE
,
NF_BR_LOCAL_OUT
,
NF_BR_PRI_NAT_DST_OTHER
},
{
{
NULL
,
NULL
},
ebt_nat_src
,
PF_BRIDGE
,
NF_BR_POST_ROUTING
,
NF_BR_PRI_NAT_SRC
},
{
{
NULL
,
NULL
},
ebt_nat_dst
,
PF_BRIDGE
,
NF_BR_PRE_ROUTING
,
NF_BR_PRI_NAT_DST_BRIDGED
},
};
static
int
__init
init
(
void
)
{
int
i
,
ret
,
j
;
ret
=
ebt_register_table
(
&
frame_nat
);
if
(
ret
<
0
)
return
ret
;
for
(
i
=
0
;
i
<
sizeof
(
ebt_ops_nat
)
/
sizeof
(
ebt_ops_nat
[
0
]);
i
++
)
if
((
ret
=
nf_register_hook
(
&
ebt_ops_nat
[
i
]))
<
0
)
goto
cleanup
;
return
ret
;
cleanup:
for
(
j
=
0
;
j
<
i
;
j
++
)
nf_unregister_hook
(
&
ebt_ops_nat
[
j
]);
ebt_unregister_table
(
&
frame_nat
);
return
ret
;
}
static
void
__exit
fini
(
void
)
{
int
i
;
for
(
i
=
0
;
i
<
sizeof
(
ebt_ops_nat
)
/
sizeof
(
ebt_ops_nat
[
0
]);
i
++
)
nf_unregister_hook
(
&
ebt_ops_nat
[
i
]);
ebt_unregister_table
(
&
frame_nat
);
}
module_init
(
init
);
module_exit
(
fini
);
MODULE_LICENSE
(
"GPL"
);
net/bridge/netfilter/ebtables.c
0 → 100644
View file @
b12d2ca2
/*
* ebtables
*
* Author:
* Bart De Schuymer <bart.de.schuymer@pandora.be>
*
* ebtables.c,v 2.0, July, 2002
*
* This code is stongly inspired on the iptables code which is
* Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
// used for print_string
#include <linux/sched.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/module.h>
#include <linux/vmalloc.h>
#include <linux/netfilter_bridge/ebtables.h>
#include <linux/spinlock.h>
#include <asm/uaccess.h>
#include <linux/smp.h>
#include <net/sock.h>
// needed for logical [in,out]-dev filtering
#include "../br_private.h"
// list_named_find
#define ASSERT_READ_LOCK(x)
#define ASSERT_WRITE_LOCK(x)
#include <linux/netfilter_ipv4/listhelp.h>
#if 0 // use this for remote debugging
// Copyright (C) 1998 by Ori Pomerantz
// Print the string to the appropriate tty, the one
// the current task uses
static void print_string(char *str)
{
struct tty_struct *my_tty;
/* The tty for the current task */
my_tty = current->tty;
if (my_tty != NULL) {
(*(my_tty->driver).write)(my_tty, 0, str, strlen(str));
(*(my_tty->driver).write)(my_tty, 0, "\015\012", 2);
}
}
#define BUGPRINT(args) print_string(args);
#else
#define BUGPRINT(format, args...) printk("kernel msg: ebtables bug: please "\
"report to author: "format, ## args)
// #define BUGPRINT(format, args...)
#endif
#define MEMPRINT(format, args...) printk("kernel msg: ebtables "\
": out of memory: "format, ## args)
// #define MEMPRINT(format, args...)
// Each cpu has its own set of counters, so there is no need for write_lock in
// the softirq
// For reading or updating the counters, the user context needs to
// get a write_lock
// The size of each set of counters is altered to get cache alignment
#define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1))
#define COUNTER_OFFSET(n) (SMP_ALIGN(n * sizeof(struct ebt_counter)))
#define COUNTER_BASE(c, n, cpu) ((struct ebt_counter *)(((char *)c) + \
COUNTER_OFFSET(n) * cpu))
static
DECLARE_MUTEX
(
ebt_mutex
);
static
LIST_HEAD
(
ebt_tables
);
static
LIST_HEAD
(
ebt_targets
);
static
LIST_HEAD
(
ebt_matches
);
static
LIST_HEAD
(
ebt_watchers
);
static
struct
ebt_target
ebt_standard_target
=
{
{
NULL
,
NULL
},
EBT_STANDARD_TARGET
,
NULL
,
NULL
,
NULL
,
NULL
};
static
inline
int
ebt_do_watcher
(
struct
ebt_entry_watcher
*
w
,
const
struct
sk_buff
*
skb
,
const
struct
net_device
*
in
,
const
struct
net_device
*
out
)
{
w
->
u
.
watcher
->
watcher
(
skb
,
in
,
out
,
w
->
data
,
w
->
watcher_size
);
// watchers don't give a verdict
return
0
;
}
static
inline
int
ebt_do_match
(
struct
ebt_entry_match
*
m
,
const
struct
sk_buff
*
skb
,
const
struct
net_device
*
in
,
const
struct
net_device
*
out
)
{
return
m
->
u
.
match
->
match
(
skb
,
in
,
out
,
m
->
data
,
m
->
match_size
);
}
static
inline
int
ebt_dev_check
(
char
*
entry
,
const
struct
net_device
*
device
)
{
if
(
*
entry
==
'\0'
)
return
0
;
if
(
!
device
)
return
1
;
return
!!
strcmp
(
entry
,
device
->
name
);
}
#define FWINV2(bool,invflg) ((bool) ^ !!(e->invflags & invflg))
// process standard matches
static
inline
int
ebt_basic_match
(
struct
ebt_entry
*
e
,
struct
ethhdr
*
h
,
const
struct
net_device
*
in
,
const
struct
net_device
*
out
)
{
int
verdict
,
i
;
if
(
e
->
bitmask
&
EBT_802_3
)
{
if
(
FWINV2
(
ntohs
(
h
->
h_proto
)
>=
1536
,
EBT_IPROTO
))
return
1
;
}
else
if
(
!
(
e
->
bitmask
&
EBT_NOPROTO
)
&&
FWINV2
(
e
->
ethproto
!=
h
->
h_proto
,
EBT_IPROTO
))
return
1
;
if
(
FWINV2
(
ebt_dev_check
(
e
->
in
,
in
),
EBT_IIN
))
return
1
;
if
(
FWINV2
(
ebt_dev_check
(
e
->
out
,
out
),
EBT_IOUT
))
return
1
;
if
((
!
in
||
!
in
->
br_port
)
?
0
:
FWINV2
(
ebt_dev_check
(
e
->
logical_in
,
&
in
->
br_port
->
br
->
dev
),
EBT_ILOGICALIN
))
return
1
;
if
((
!
out
||
!
out
->
br_port
)
?
0
:
FWINV2
(
ebt_dev_check
(
e
->
logical_out
,
&
out
->
br_port
->
br
->
dev
),
EBT_ILOGICALOUT
))
return
1
;
if
(
e
->
bitmask
&
EBT_SOURCEMAC
)
{
verdict
=
0
;
for
(
i
=
0
;
i
<
6
;
i
++
)
verdict
|=
(
h
->
h_source
[
i
]
^
e
->
sourcemac
[
i
])
&
e
->
sourcemsk
[
i
];
if
(
FWINV2
(
verdict
!=
0
,
EBT_ISOURCE
)
)
return
1
;
}
if
(
e
->
bitmask
&
EBT_DESTMAC
)
{
verdict
=
0
;
for
(
i
=
0
;
i
<
6
;
i
++
)
verdict
|=
(
h
->
h_dest
[
i
]
^
e
->
destmac
[
i
])
&
e
->
destmsk
[
i
];
if
(
FWINV2
(
verdict
!=
0
,
EBT_IDEST
)
)
return
1
;
}
return
0
;
}
// Do some firewalling
unsigned
int
ebt_do_table
(
unsigned
int
hook
,
struct
sk_buff
**
pskb
,
const
struct
net_device
*
in
,
const
struct
net_device
*
out
,
struct
ebt_table
*
table
)
{
int
i
,
nentries
;
struct
ebt_entry
*
point
;
struct
ebt_counter
*
counter_base
,
*
cb_base
;
struct
ebt_entry_target
*
t
;
int
verdict
,
sp
=
0
;
struct
ebt_chainstack
*
cs
;
struct
ebt_entries
*
chaininfo
;
char
*
base
;
struct
ebt_table_info
*
private
=
table
->
private
;
read_lock_bh
(
&
table
->
lock
);
cb_base
=
COUNTER_BASE
(
private
->
counters
,
private
->
nentries
,
smp_processor_id
());
if
(
private
->
chainstack
)
cs
=
private
->
chainstack
[
smp_processor_id
()];
else
cs
=
NULL
;
chaininfo
=
private
->
hook_entry
[
hook
];
nentries
=
private
->
hook_entry
[
hook
]
->
nentries
;
point
=
(
struct
ebt_entry
*
)(
private
->
hook_entry
[
hook
]
->
data
);
counter_base
=
cb_base
+
private
->
hook_entry
[
hook
]
->
counter_offset
;
// base for chain jumps
base
=
(
char
*
)
chaininfo
;
i
=
0
;
while
(
i
<
nentries
)
{
if
(
ebt_basic_match
(
point
,
(
**
pskb
).
mac
.
ethernet
,
in
,
out
))
goto
letscontinue
;
if
(
EBT_MATCH_ITERATE
(
point
,
ebt_do_match
,
*
pskb
,
in
,
out
)
!=
0
)
goto
letscontinue
;
// increase counter
(
*
(
counter_base
+
i
)).
pcnt
++
;
// these should only watch: not modify, nor tell us
// what to do with the packet
EBT_WATCHER_ITERATE
(
point
,
ebt_do_watcher
,
*
pskb
,
in
,
out
);
t
=
(
struct
ebt_entry_target
*
)
(((
char
*
)
point
)
+
point
->
target_offset
);
// standard target
if
(
!
t
->
u
.
target
->
target
)
verdict
=
((
struct
ebt_standard_target
*
)
t
)
->
verdict
;
else
verdict
=
t
->
u
.
target
->
target
(
pskb
,
hook
,
in
,
out
,
t
->
data
,
t
->
target_size
);
if
(
verdict
==
EBT_ACCEPT
)
{
read_unlock_bh
(
&
table
->
lock
);
return
NF_ACCEPT
;
}
if
(
verdict
==
EBT_DROP
)
{
read_unlock_bh
(
&
table
->
lock
);
return
NF_DROP
;
}
if
(
verdict
==
EBT_RETURN
)
{
letsreturn:
#ifdef CONFIG_NETFILTER_DEBUG
if
(
sp
==
0
)
{
BUGPRINT
(
"RETURN on base chain"
);
// act like this is EBT_CONTINUE
goto
letscontinue
;
}
#endif
sp
--
;
// put all the local variables right
i
=
cs
[
sp
].
n
;
chaininfo
=
cs
[
sp
].
chaininfo
;
nentries
=
chaininfo
->
nentries
;
point
=
cs
[
sp
].
e
;
counter_base
=
cb_base
+
chaininfo
->
counter_offset
;
continue
;
}
if
(
verdict
==
EBT_CONTINUE
)
goto
letscontinue
;
#ifdef CONFIG_NETFILTER_DEBUG
if
(
verdict
<
0
)
{
BUGPRINT
(
"bogus standard verdict
\n
"
);
read_unlock_bh
(
&
table
->
lock
);
return
NF_DROP
;
}
#endif
// jump to a udc
cs
[
sp
].
n
=
i
+
1
;
cs
[
sp
].
chaininfo
=
chaininfo
;
cs
[
sp
].
e
=
(
struct
ebt_entry
*
)
(((
char
*
)
point
)
+
point
->
next_offset
);
i
=
0
;
chaininfo
=
(
struct
ebt_entries
*
)
(
base
+
verdict
);
#ifdef CONFIG_NETFILTER_DEBUG
if
(
chaininfo
->
distinguisher
)
{
BUGPRINT
(
"jump to non-chain
\n
"
);
read_unlock_bh
(
&
table
->
lock
);
return
NF_DROP
;
}
#endif
nentries
=
chaininfo
->
nentries
;
point
=
(
struct
ebt_entry
*
)
chaininfo
->
data
;
counter_base
=
cb_base
+
chaininfo
->
counter_offset
;
sp
++
;
continue
;
letscontinue:
point
=
(
struct
ebt_entry
*
)
(((
char
*
)
point
)
+
point
->
next_offset
);
i
++
;
}
// I actually like this :)
if
(
chaininfo
->
policy
==
EBT_RETURN
)
goto
letsreturn
;
if
(
chaininfo
->
policy
==
EBT_ACCEPT
)
{
read_unlock_bh
(
&
table
->
lock
);
return
NF_ACCEPT
;
}
read_unlock_bh
(
&
table
->
lock
);
return
NF_DROP
;
}
// If it succeeds, returns element and locks mutex
static
inline
void
*
find_inlist_lock_noload
(
struct
list_head
*
head
,
const
char
*
name
,
int
*
error
,
struct
semaphore
*
mutex
)
{
void
*
ret
;
*
error
=
down_interruptible
(
mutex
);
if
(
*
error
!=
0
)
return
NULL
;
ret
=
list_named_find
(
head
,
name
);
if
(
!
ret
)
{
*
error
=
-
ENOENT
;
up
(
mutex
);
}
return
ret
;
}
#ifndef CONFIG_KMOD
#define find_inlist_lock(h,n,p,e,m) find_inlist_lock_noload((h),(n),(e),(m))
#else
static
void
*
find_inlist_lock
(
struct
list_head
*
head
,
const
char
*
name
,
const
char
*
prefix
,
int
*
error
,
struct
semaphore
*
mutex
)
{
void
*
ret
;
ret
=
find_inlist_lock_noload
(
head
,
name
,
error
,
mutex
);
if
(
!
ret
)
{
char
modulename
[
EBT_FUNCTION_MAXNAMELEN
+
strlen
(
prefix
)
+
1
];
strcpy
(
modulename
,
prefix
);
strcat
(
modulename
,
name
);
request_module
(
modulename
);
ret
=
find_inlist_lock_noload
(
head
,
name
,
error
,
mutex
);
}
return
ret
;
}
#endif
static
inline
struct
ebt_table
*
find_table_lock
(
const
char
*
name
,
int
*
error
,
struct
semaphore
*
mutex
)
{
return
find_inlist_lock
(
&
ebt_tables
,
name
,
"ebtable_"
,
error
,
mutex
);
}
static
inline
struct
ebt_match
*
find_match_lock
(
const
char
*
name
,
int
*
error
,
struct
semaphore
*
mutex
)
{
return
find_inlist_lock
(
&
ebt_matches
,
name
,
"ebt_"
,
error
,
mutex
);
}
static
inline
struct
ebt_watcher
*
find_watcher_lock
(
const
char
*
name
,
int
*
error
,
struct
semaphore
*
mutex
)
{
return
find_inlist_lock
(
&
ebt_watchers
,
name
,
"ebt_"
,
error
,
mutex
);
}
static
inline
struct
ebt_target
*
find_target_lock
(
const
char
*
name
,
int
*
error
,
struct
semaphore
*
mutex
)
{
return
find_inlist_lock
(
&
ebt_targets
,
name
,
"ebt_"
,
error
,
mutex
);
}
static
inline
int
ebt_check_match
(
struct
ebt_entry_match
*
m
,
struct
ebt_entry
*
e
,
const
char
*
name
,
unsigned
int
hookmask
,
unsigned
int
*
cnt
)
{
struct
ebt_match
*
match
;
int
ret
;
if
(((
char
*
)
m
)
+
m
->
match_size
+
sizeof
(
struct
ebt_entry_match
)
>
((
char
*
)
e
)
+
e
->
watchers_offset
)
return
-
EINVAL
;
match
=
find_match_lock
(
m
->
u
.
name
,
&
ret
,
&
ebt_mutex
);
if
(
!
match
)
return
ret
;
m
->
u
.
match
=
match
;
if
(
match
->
me
)
__MOD_INC_USE_COUNT
(
match
->
me
);
up
(
&
ebt_mutex
);
if
(
match
->
check
&&
match
->
check
(
name
,
hookmask
,
e
,
m
->
data
,
m
->
match_size
)
!=
0
)
{
BUGPRINT
(
"match->check failed
\n
"
);
if
(
match
->
me
)
__MOD_DEC_USE_COUNT
(
match
->
me
);
return
-
EINVAL
;
}
(
*
cnt
)
++
;
return
0
;
}
static
inline
int
ebt_check_watcher
(
struct
ebt_entry_watcher
*
w
,
struct
ebt_entry
*
e
,
const
char
*
name
,
unsigned
int
hookmask
,
unsigned
int
*
cnt
)
{
struct
ebt_watcher
*
watcher
;
int
ret
;
if
(((
char
*
)
w
)
+
w
->
watcher_size
+
sizeof
(
struct
ebt_entry_watcher
)
>
((
char
*
)
e
)
+
e
->
target_offset
)
return
-
EINVAL
;
watcher
=
find_watcher_lock
(
w
->
u
.
name
,
&
ret
,
&
ebt_mutex
);
if
(
!
watcher
)
return
ret
;
w
->
u
.
watcher
=
watcher
;
if
(
watcher
->
me
)
__MOD_INC_USE_COUNT
(
watcher
->
me
);
up
(
&
ebt_mutex
);
if
(
watcher
->
check
&&
watcher
->
check
(
name
,
hookmask
,
e
,
w
->
data
,
w
->
watcher_size
)
!=
0
)
{
BUGPRINT
(
"watcher->check failed
\n
"
);
if
(
watcher
->
me
)
__MOD_DEC_USE_COUNT
(
watcher
->
me
);
return
-
EINVAL
;
}
(
*
cnt
)
++
;
return
0
;
}
// this one is very careful, as it is the first function
// to parse the userspace data
static
inline
int
ebt_check_entry_size_and_hooks
(
struct
ebt_entry
*
e
,
struct
ebt_table_info
*
newinfo
,
char
*
base
,
char
*
limit
,
struct
ebt_entries
**
hook_entries
,
unsigned
int
*
n
,
unsigned
int
*
cnt
,
unsigned
int
*
totalcnt
,
unsigned
int
*
udc_cnt
,
unsigned
int
valid_hooks
)
{
int
i
;
for
(
i
=
0
;
i
<
NF_BR_NUMHOOKS
;
i
++
)
{
if
((
valid_hooks
&
(
1
<<
i
))
==
0
)
continue
;
if
(
(
char
*
)
hook_entries
[
i
]
-
base
==
(
char
*
)
e
-
newinfo
->
entries
)
break
;
}
// beginning of a new chain
// if i == NF_BR_NUMHOOKS it must be a user defined chain
if
(
i
!=
NF_BR_NUMHOOKS
||
!
(
e
->
bitmask
&
EBT_ENTRY_OR_ENTRIES
))
{
if
((
e
->
bitmask
&
EBT_ENTRY_OR_ENTRIES
)
!=
0
)
{
// we make userspace set this right,
// so there is no misunderstanding
BUGPRINT
(
"EBT_ENTRY_OR_ENTRIES shouldn't be set "
"in distinguisher
\n
"
);
return
-
EINVAL
;
}
// this checks if the previous chain has as many entries
// as it said it has
if
(
*
n
!=
*
cnt
)
{
BUGPRINT
(
"nentries does not equal the nr of entries "
"in the chain
\n
"
);
return
-
EINVAL
;
}
// before we look at the struct, be sure it is not too big
if
((
char
*
)
hook_entries
[
i
]
+
sizeof
(
struct
ebt_entries
)
>
limit
)
{
BUGPRINT
(
"entries_size too small
\n
"
);
return
-
EINVAL
;
}
if
(((
struct
ebt_entries
*
)
e
)
->
policy
!=
EBT_DROP
&&
((
struct
ebt_entries
*
)
e
)
->
policy
!=
EBT_ACCEPT
)
{
// only RETURN from udc
if
(
i
!=
NF_BR_NUMHOOKS
||
((
struct
ebt_entries
*
)
e
)
->
policy
!=
EBT_RETURN
)
{
BUGPRINT
(
"bad policy
\n
"
);
return
-
EINVAL
;
}
}
if
(
i
==
NF_BR_NUMHOOKS
)
// it's a user defined chain
(
*
udc_cnt
)
++
;
else
newinfo
->
hook_entry
[
i
]
=
(
struct
ebt_entries
*
)
e
;
if
(((
struct
ebt_entries
*
)
e
)
->
counter_offset
!=
*
totalcnt
)
{
BUGPRINT
(
"counter_offset != totalcnt"
);
return
-
EINVAL
;
}
*
n
=
((
struct
ebt_entries
*
)
e
)
->
nentries
;
*
cnt
=
0
;
return
0
;
}
// a plain old entry, heh
if
(
sizeof
(
struct
ebt_entry
)
>
e
->
watchers_offset
||
e
->
watchers_offset
>
e
->
target_offset
||
e
->
target_offset
>=
e
->
next_offset
)
{
BUGPRINT
(
"entry offsets not in right order
\n
"
);
return
-
EINVAL
;
}
// this is not checked anywhere else
if
(
e
->
next_offset
-
e
->
target_offset
<
sizeof
(
struct
ebt_entry_target
))
{
BUGPRINT
(
"target size too small
\n
"
);
return
-
EINVAL
;
}
(
*
cnt
)
++
;
(
*
totalcnt
)
++
;
return
0
;
}
struct
ebt_cl_stack
{
struct
ebt_chainstack
cs
;
int
from
;
unsigned
int
hookmask
;
};
// we need these positions to check that the jumps to a different part of the
// entries is a jump to the beginning of a new chain.
static
inline
int
ebt_get_udc_positions
(
struct
ebt_entry
*
e
,
struct
ebt_table_info
*
newinfo
,
struct
ebt_entries
**
hook_entries
,
unsigned
int
*
n
,
unsigned
int
valid_hooks
,
struct
ebt_cl_stack
*
udc
)
{
int
i
;
// we're only interested in chain starts
if
(
e
->
bitmask
&
EBT_ENTRY_OR_ENTRIES
)
return
0
;
for
(
i
=
0
;
i
<
NF_BR_NUMHOOKS
;
i
++
)
{
if
((
valid_hooks
&
(
1
<<
i
))
==
0
)
continue
;
if
(
newinfo
->
hook_entry
[
i
]
==
(
struct
ebt_entries
*
)
e
)
break
;
}
// only care about udc
if
(
i
!=
NF_BR_NUMHOOKS
)
return
0
;
udc
[
*
n
].
cs
.
chaininfo
=
(
struct
ebt_entries
*
)
e
;
// these initialisations are depended on later in check_chainloops()
udc
[
*
n
].
cs
.
n
=
0
;
udc
[
*
n
].
hookmask
=
0
;
(
*
n
)
++
;
return
0
;
}
static
inline
int
ebt_cleanup_match
(
struct
ebt_entry_match
*
m
,
unsigned
int
*
i
)
{
if
(
i
&&
(
*
i
)
--
==
0
)
return
1
;
if
(
m
->
u
.
match
->
destroy
)
m
->
u
.
match
->
destroy
(
m
->
data
,
m
->
match_size
);
if
(
m
->
u
.
match
->
me
)
__MOD_DEC_USE_COUNT
(
m
->
u
.
match
->
me
);
return
0
;
}
static
inline
int
ebt_cleanup_watcher
(
struct
ebt_entry_watcher
*
w
,
unsigned
int
*
i
)
{
if
(
i
&&
(
*
i
)
--
==
0
)
return
1
;
if
(
w
->
u
.
watcher
->
destroy
)
w
->
u
.
watcher
->
destroy
(
w
->
data
,
w
->
watcher_size
);
if
(
w
->
u
.
watcher
->
me
)
__MOD_DEC_USE_COUNT
(
w
->
u
.
watcher
->
me
);
return
0
;
}
static
inline
int
ebt_cleanup_entry
(
struct
ebt_entry
*
e
,
unsigned
int
*
cnt
)
{
struct
ebt_entry_target
*
t
;
if
((
e
->
bitmask
&
EBT_ENTRY_OR_ENTRIES
)
==
0
)
return
0
;
// we're done
if
(
cnt
&&
(
*
cnt
)
--
==
0
)
return
1
;
EBT_WATCHER_ITERATE
(
e
,
ebt_cleanup_watcher
,
NULL
);
EBT_MATCH_ITERATE
(
e
,
ebt_cleanup_match
,
NULL
);
t
=
(
struct
ebt_entry_target
*
)(((
char
*
)
e
)
+
e
->
target_offset
);
if
(
t
->
u
.
target
->
destroy
)
t
->
u
.
target
->
destroy
(
t
->
data
,
t
->
target_size
);
if
(
t
->
u
.
target
->
me
)
__MOD_DEC_USE_COUNT
(
t
->
u
.
target
->
me
);
return
0
;
}
static
inline
int
ebt_check_entry
(
struct
ebt_entry
*
e
,
struct
ebt_table_info
*
newinfo
,
const
char
*
name
,
unsigned
int
*
cnt
,
unsigned
int
valid_hooks
,
struct
ebt_cl_stack
*
cl_s
,
unsigned
int
udc_cnt
)
{
struct
ebt_entry_target
*
t
;
struct
ebt_target
*
target
;
unsigned
int
i
,
j
,
hook
=
0
,
hookmask
=
0
;
int
ret
;
// Don't mess with the struct ebt_entries
if
((
e
->
bitmask
&
EBT_ENTRY_OR_ENTRIES
)
==
0
)
return
0
;
if
(
e
->
bitmask
&
~
EBT_F_MASK
)
{
BUGPRINT
(
"Unknown flag for bitmask
\n
"
);
return
-
EINVAL
;
}
if
(
e
->
invflags
&
~
EBT_INV_MASK
)
{
BUGPRINT
(
"Unknown flag for inv bitmask
\n
"
);
return
-
EINVAL
;
}
if
(
(
e
->
bitmask
&
EBT_NOPROTO
)
&&
(
e
->
bitmask
&
EBT_802_3
)
)
{
BUGPRINT
(
"NOPROTO & 802_3 not allowed
\n
"
);
return
-
EINVAL
;
}
// what hook do we belong to?
for
(
i
=
0
;
i
<
NF_BR_NUMHOOKS
;
i
++
)
{
if
((
valid_hooks
&
(
1
<<
i
))
==
0
)
continue
;
if
((
char
*
)
newinfo
->
hook_entry
[
i
]
<
(
char
*
)
e
)
hook
=
i
;
else
break
;
}
// (1 << NF_BR_NUMHOOKS) tells the check functions the rule is on
// a base chain
if
(
i
<
NF_BR_NUMHOOKS
)
hookmask
=
(
1
<<
hook
)
|
(
1
<<
NF_BR_NUMHOOKS
);
else
{
for
(
i
=
0
;
i
<
udc_cnt
;
i
++
)
if
((
char
*
)(
cl_s
[
i
].
cs
.
chaininfo
)
>
(
char
*
)
e
)
break
;
if
(
i
==
0
)
hookmask
=
(
1
<<
hook
)
|
(
1
<<
NF_BR_NUMHOOKS
);
else
hookmask
=
cl_s
[
i
-
1
].
hookmask
;
}
i
=
0
;
ret
=
EBT_MATCH_ITERATE
(
e
,
ebt_check_match
,
e
,
name
,
hookmask
,
&
i
);
if
(
ret
!=
0
)
goto
cleanup_matches
;
j
=
0
;
ret
=
EBT_WATCHER_ITERATE
(
e
,
ebt_check_watcher
,
e
,
name
,
hookmask
,
&
j
);
if
(
ret
!=
0
)
goto
cleanup_watchers
;
t
=
(
struct
ebt_entry_target
*
)(((
char
*
)
e
)
+
e
->
target_offset
);
target
=
find_target_lock
(
t
->
u
.
name
,
&
ret
,
&
ebt_mutex
);
if
(
!
target
)
goto
cleanup_watchers
;
if
(
target
->
me
)
__MOD_INC_USE_COUNT
(
target
->
me
);
up
(
&
ebt_mutex
);
t
->
u
.
target
=
target
;
if
(
t
->
u
.
target
==
&
ebt_standard_target
)
{
if
(
e
->
target_offset
+
sizeof
(
struct
ebt_standard_target
)
>
e
->
next_offset
)
{
BUGPRINT
(
"Standard target size too big
\n
"
);
ret
=
-
EFAULT
;
goto
cleanup_watchers
;
}
if
(((
struct
ebt_standard_target
*
)
t
)
->
verdict
<
-
NUM_STANDARD_TARGETS
)
{
BUGPRINT
(
"Invalid standard target
\n
"
);
ret
=
-
EFAULT
;
goto
cleanup_watchers
;
}
}
else
if
((
e
->
target_offset
+
t
->
target_size
+
sizeof
(
struct
ebt_entry_target
)
>
e
->
next_offset
)
||
(
t
->
u
.
target
->
check
&&
t
->
u
.
target
->
check
(
name
,
hookmask
,
e
,
t
->
data
,
t
->
target_size
)
!=
0
)){
if
(
t
->
u
.
target
->
me
)
__MOD_DEC_USE_COUNT
(
t
->
u
.
target
->
me
);
ret
=
-
EFAULT
;
goto
cleanup_watchers
;
}
(
*
cnt
)
++
;
return
0
;
cleanup_watchers:
EBT_WATCHER_ITERATE
(
e
,
ebt_cleanup_watcher
,
&
j
);
cleanup_matches:
EBT_MATCH_ITERATE
(
e
,
ebt_cleanup_match
,
&
i
);
return
ret
;
}
// checks for loops and sets the hook mask for udc
// the hook mask for udc tells us from which base chains the udc can be
// accessed. This mask is a parameter to the check() functions of the extensions
int
check_chainloops
(
struct
ebt_entries
*
chain
,
struct
ebt_cl_stack
*
cl_s
,
unsigned
int
udc_cnt
,
unsigned
int
hooknr
,
char
*
base
)
{
int
i
,
chain_nr
=
-
1
,
pos
=
0
,
nentries
=
chain
->
nentries
,
verdict
;
struct
ebt_entry
*
e
=
(
struct
ebt_entry
*
)
chain
->
data
;
struct
ebt_entry_target
*
t
;
while
(
pos
<
nentries
||
chain_nr
!=
-
1
)
{
// end of udc, go back one 'recursion' step
if
(
pos
==
nentries
)
{
// put back values of the time when this chain was called
e
=
cl_s
[
chain_nr
].
cs
.
e
;
if
(
cl_s
[
chain_nr
].
from
!=
-
1
)
nentries
=
cl_s
[
cl_s
[
chain_nr
].
from
].
cs
.
chaininfo
->
nentries
;
else
nentries
=
chain
->
nentries
;
pos
=
cl_s
[
chain_nr
].
cs
.
n
;
// make sure we won't see a loop that isn't one
cl_s
[
chain_nr
].
cs
.
n
=
0
;
chain_nr
=
cl_s
[
chain_nr
].
from
;
if
(
pos
==
nentries
)
continue
;
}
t
=
(
struct
ebt_entry_target
*
)
(((
char
*
)
e
)
+
e
->
target_offset
);
if
(
strcmp
(
t
->
u
.
name
,
EBT_STANDARD_TARGET
))
goto
letscontinue
;
if
(
e
->
target_offset
+
sizeof
(
struct
ebt_standard_target
)
>
e
->
next_offset
)
{
BUGPRINT
(
"Standard target size too big
\n
"
);
return
-
1
;
}
verdict
=
((
struct
ebt_standard_target
*
)
t
)
->
verdict
;
if
(
verdict
>=
0
)
{
// jump to another chain
struct
ebt_entries
*
hlp2
=
(
struct
ebt_entries
*
)(
base
+
verdict
);
for
(
i
=
0
;
i
<
udc_cnt
;
i
++
)
if
(
hlp2
==
cl_s
[
i
].
cs
.
chaininfo
)
break
;
// bad destination or loop
if
(
i
==
udc_cnt
)
{
BUGPRINT
(
"bad destination
\n
"
);
return
-
1
;
}
if
(
cl_s
[
i
].
cs
.
n
)
{
BUGPRINT
(
"loop
\n
"
);
return
-
1
;
}
// this can't be 0, so the above test is correct
cl_s
[
i
].
cs
.
n
=
pos
+
1
;
pos
=
0
;
cl_s
[
i
].
cs
.
e
=
((
void
*
)
e
+
e
->
next_offset
);
e
=
(
struct
ebt_entry
*
)(
hlp2
->
data
);
nentries
=
hlp2
->
nentries
;
cl_s
[
i
].
from
=
chain_nr
;
chain_nr
=
i
;
// this udc is accessible from the base chain for hooknr
cl_s
[
i
].
hookmask
|=
(
1
<<
hooknr
);
continue
;
}
letscontinue:
e
=
(
void
*
)
e
+
e
->
next_offset
;
pos
++
;
}
return
0
;
}
// do the parsing of the table/chains/entries/matches/watchers/targets, heh
static
int
translate_table
(
struct
ebt_replace
*
repl
,
struct
ebt_table_info
*
newinfo
)
{
unsigned
int
i
,
j
,
k
,
udc_cnt
;
int
ret
;
struct
ebt_cl_stack
*
cl_s
=
NULL
;
// used in the checking for chain loops
i
=
0
;
while
(
i
<
NF_BR_NUMHOOKS
&&
!
(
repl
->
valid_hooks
&
(
1
<<
i
)))
i
++
;
if
(
i
==
NF_BR_NUMHOOKS
)
{
BUGPRINT
(
"No valid hooks specified
\n
"
);
return
-
EINVAL
;
}
if
(
repl
->
hook_entry
[
i
]
!=
(
struct
ebt_entries
*
)
repl
->
entries
)
{
BUGPRINT
(
"Chains don't start at beginning
\n
"
);
return
-
EINVAL
;
}
// make sure chains are ordered after each other in same order
// as their corresponding hooks
for
(
j
=
i
+
1
;
j
<
NF_BR_NUMHOOKS
;
j
++
)
{
if
(
!
(
repl
->
valid_hooks
&
(
1
<<
j
)))
continue
;
if
(
repl
->
hook_entry
[
j
]
<=
repl
->
hook_entry
[
i
]
)
{
BUGPRINT
(
"Hook order must be followed
\n
"
);
return
-
EINVAL
;
}
i
=
j
;
}
for
(
i
=
0
;
i
<
NF_BR_NUMHOOKS
;
i
++
)
newinfo
->
hook_entry
[
i
]
=
NULL
;
newinfo
->
entries_size
=
repl
->
entries_size
;
newinfo
->
nentries
=
repl
->
nentries
;
// do some early checkings and initialize some things
i
=
0
;
// holds the expected nr. of entries for the chain
j
=
0
;
// holds the up to now counted entries for the chain
k
=
0
;
// holds the total nr. of entries, should equal
// newinfo->nentries afterwards
udc_cnt
=
0
;
// will hold the nr. of user defined chains (udc)
ret
=
EBT_ENTRY_ITERATE
(
newinfo
->
entries
,
newinfo
->
entries_size
,
ebt_check_entry_size_and_hooks
,
newinfo
,
repl
->
entries
,
repl
->
entries
+
repl
->
entries_size
,
repl
->
hook_entry
,
&
i
,
&
j
,
&
k
,
&
udc_cnt
,
repl
->
valid_hooks
);
if
(
ret
!=
0
)
return
ret
;
if
(
i
!=
j
)
{
BUGPRINT
(
"nentries does not equal the nr of entries in the "
"(last) chain
\n
"
);
return
-
EINVAL
;
}
if
(
k
!=
newinfo
->
nentries
)
{
BUGPRINT
(
"Total nentries is wrong
\n
"
);
return
-
EINVAL
;
}
// check if all valid hooks have a chain
for
(
i
=
0
;
i
<
NF_BR_NUMHOOKS
;
i
++
)
{
if
(
newinfo
->
hook_entry
[
i
]
==
NULL
&&
(
repl
->
valid_hooks
&
(
1
<<
i
)))
{
BUGPRINT
(
"Valid hook without chain
\n
"
);
return
-
EINVAL
;
}
}
// Get the location of the udc, put them in an array
// While we're at it, allocate the chainstack
if
(
udc_cnt
)
{
// this will get free'd in do_replace()/ebt_register_table()
// if an error occurs
newinfo
->
chainstack
=
(
struct
ebt_chainstack
**
)
vmalloc
(
NR_CPUS
*
sizeof
(
struct
ebt_chainstack
));
if
(
!
newinfo
->
chainstack
)
return
-
ENOMEM
;
for
(
i
=
0
;
i
<
NR_CPUS
;
i
++
)
{
newinfo
->
chainstack
[
i
]
=
vmalloc
(
udc_cnt
*
sizeof
(
struct
ebt_chainstack
));
if
(
!
newinfo
->
chainstack
[
i
])
{
while
(
i
)
vfree
(
newinfo
->
chainstack
[
--
i
]);
vfree
(
newinfo
->
chainstack
);
newinfo
->
chainstack
=
NULL
;
return
-
ENOMEM
;
}
}
cl_s
=
(
struct
ebt_cl_stack
*
)
vmalloc
(
udc_cnt
*
sizeof
(
struct
ebt_cl_stack
));
if
(
!
cl_s
)
return
-
ENOMEM
;
i
=
0
;
// the i'th udc
EBT_ENTRY_ITERATE
(
newinfo
->
entries
,
newinfo
->
entries_size
,
ebt_get_udc_positions
,
newinfo
,
repl
->
hook_entry
,
&
i
,
repl
->
valid_hooks
,
cl_s
);
// sanity check
if
(
i
!=
udc_cnt
)
{
BUGPRINT
(
"i != udc_cnt
\n
"
);
vfree
(
cl_s
);
return
-
EFAULT
;
}
}
// Check for loops
for
(
i
=
0
;
i
<
NF_BR_NUMHOOKS
;
i
++
)
if
(
repl
->
valid_hooks
&
(
1
<<
i
))
if
(
check_chainloops
(
newinfo
->
hook_entry
[
i
],
cl_s
,
udc_cnt
,
i
,
newinfo
->
entries
))
{
if
(
cl_s
)
vfree
(
cl_s
);
return
-
EINVAL
;
}
// we now know the following (along with E=mc):
// - the nr of entries in each chain is right
// - the size of the allocated space is right
// - all valid hooks have a corresponding chain
// - there are no loops
// - wrong data can still be on the level of a single entry
// - could be there are jumps to places that are not the
// beginning of a chain. This can only occur in chains that
// are not accessible from any base chains, so we don't care.
// used to know what we need to clean up if something goes wrong
i
=
0
;
ret
=
EBT_ENTRY_ITERATE
(
newinfo
->
entries
,
newinfo
->
entries_size
,
ebt_check_entry
,
newinfo
,
repl
->
name
,
&
i
,
repl
->
valid_hooks
,
cl_s
,
udc_cnt
);
if
(
ret
!=
0
)
{
EBT_ENTRY_ITERATE
(
newinfo
->
entries
,
newinfo
->
entries_size
,
ebt_cleanup_entry
,
&
i
);
}
if
(
cl_s
)
vfree
(
cl_s
);
return
ret
;
}
// called under write_lock
static
void
get_counters
(
struct
ebt_counter
*
oldcounters
,
struct
ebt_counter
*
counters
,
unsigned
int
nentries
)
{
int
i
,
cpu
;
struct
ebt_counter
*
counter_base
;
// counters of cpu 0
memcpy
(
counters
,
oldcounters
,
sizeof
(
struct
ebt_counter
)
*
nentries
);
// add other counters to those of cpu 0
for
(
cpu
=
1
;
cpu
<
NR_CPUS
;
cpu
++
)
{
counter_base
=
COUNTER_BASE
(
oldcounters
,
nentries
,
cpu
);
for
(
i
=
0
;
i
<
nentries
;
i
++
)
counters
[
i
].
pcnt
+=
counter_base
[
i
].
pcnt
;
}
}
// replace the table
static
int
do_replace
(
void
*
user
,
unsigned
int
len
)
{
int
ret
,
i
,
countersize
;
struct
ebt_table_info
*
newinfo
;
struct
ebt_replace
tmp
;
struct
ebt_table
*
t
;
struct
ebt_counter
*
counterstmp
=
NULL
;
// used to be able to unlock earlier
struct
ebt_table_info
*
table
;
if
(
copy_from_user
(
&
tmp
,
user
,
sizeof
(
tmp
))
!=
0
)
return
-
EFAULT
;
if
(
len
!=
sizeof
(
tmp
)
+
tmp
.
entries_size
)
{
BUGPRINT
(
"Wrong len argument
\n
"
);
return
-
EINVAL
;
}
if
(
tmp
.
entries_size
==
0
)
{
BUGPRINT
(
"Entries_size never zero
\n
"
);
return
-
EINVAL
;
}
countersize
=
COUNTER_OFFSET
(
tmp
.
nentries
)
*
NR_CPUS
;
newinfo
=
(
struct
ebt_table_info
*
)
vmalloc
(
sizeof
(
struct
ebt_table_info
)
+
countersize
);
if
(
!
newinfo
)
return
-
ENOMEM
;
if
(
countersize
)
memset
(
newinfo
->
counters
,
0
,
countersize
);
newinfo
->
entries
=
(
char
*
)
vmalloc
(
tmp
.
entries_size
);
if
(
!
newinfo
->
entries
)
{
ret
=
-
ENOMEM
;
goto
free_newinfo
;
}
if
(
copy_from_user
(
newinfo
->
entries
,
tmp
.
entries
,
tmp
.
entries_size
)
!=
0
)
{
BUGPRINT
(
"Couldn't copy entries from userspace
\n
"
);
ret
=
-
EFAULT
;
goto
free_entries
;
}
// the user wants counters back
// the check on the size is done later, when we have the lock
if
(
tmp
.
num_counters
)
{
counterstmp
=
(
struct
ebt_counter
*
)
vmalloc
(
tmp
.
num_counters
*
sizeof
(
struct
ebt_counter
));
if
(
!
counterstmp
)
{
ret
=
-
ENOMEM
;
goto
free_entries
;
}
}
else
counterstmp
=
NULL
;
// this can get initialized by translate_table()
newinfo
->
chainstack
=
NULL
;
ret
=
translate_table
(
&
tmp
,
newinfo
);
if
(
ret
!=
0
)
goto
free_counterstmp
;
t
=
find_table_lock
(
tmp
.
name
,
&
ret
,
&
ebt_mutex
);
if
(
!
t
)
goto
free_iterate
;
// the table doesn't like it
if
(
t
->
check
&&
(
ret
=
t
->
check
(
newinfo
,
tmp
.
valid_hooks
)))
goto
free_unlock
;
if
(
tmp
.
num_counters
&&
tmp
.
num_counters
!=
t
->
private
->
nentries
)
{
BUGPRINT
(
"Wrong nr. of counters requested
\n
"
);
ret
=
-
EINVAL
;
goto
free_unlock
;
}
// we have the mutex lock, so no danger in reading this pointer
table
=
t
->
private
;
// we need an atomic snapshot of the counters
write_lock_bh
(
&
t
->
lock
);
if
(
tmp
.
num_counters
)
get_counters
(
t
->
private
->
counters
,
counterstmp
,
t
->
private
->
nentries
);
t
->
private
=
newinfo
;
write_unlock_bh
(
&
t
->
lock
);
up
(
&
ebt_mutex
);
// So, a user can change the chains while having messed up her counter
// allocation. Only reason why this is done is because this way the lock
// is held only once, while this doesn't bring the kernel into a
// dangerous state.
if
(
tmp
.
num_counters
&&
copy_to_user
(
tmp
.
counters
,
counterstmp
,
tmp
.
num_counters
*
sizeof
(
struct
ebt_counter
)))
{
BUGPRINT
(
"Couldn't copy counters to userspace
\n
"
);
ret
=
-
EFAULT
;
}
else
ret
=
0
;
// decrease module count and free resources
EBT_ENTRY_ITERATE
(
table
->
entries
,
table
->
entries_size
,
ebt_cleanup_entry
,
NULL
);
vfree
(
table
->
entries
);
if
(
table
->
chainstack
)
{
for
(
i
=
0
;
i
<
NR_CPUS
;
i
++
)
vfree
(
table
->
chainstack
[
i
]);
vfree
(
table
->
chainstack
);
}
vfree
(
table
);
if
(
counterstmp
)
vfree
(
counterstmp
);
return
ret
;
free_unlock:
up
(
&
ebt_mutex
);
free_iterate:
EBT_ENTRY_ITERATE
(
newinfo
->
entries
,
newinfo
->
entries_size
,
ebt_cleanup_entry
,
NULL
);
free_counterstmp:
if
(
counterstmp
)
vfree
(
counterstmp
);
// can be initialized in translate_table()
if
(
newinfo
->
chainstack
)
{
for
(
i
=
0
;
i
<
NR_CPUS
;
i
++
)
vfree
(
newinfo
->
chainstack
[
i
]);
vfree
(
newinfo
->
chainstack
);
}
free_entries:
if
(
newinfo
->
entries
)
vfree
(
newinfo
->
entries
);
free_newinfo:
if
(
newinfo
)
vfree
(
newinfo
);
return
ret
;
}
int
ebt_register_target
(
struct
ebt_target
*
target
)
{
int
ret
;
ret
=
down_interruptible
(
&
ebt_mutex
);
if
(
ret
!=
0
)
return
ret
;
if
(
!
list_named_insert
(
&
ebt_targets
,
target
))
{
up
(
&
ebt_mutex
);
return
-
EEXIST
;
}
up
(
&
ebt_mutex
);
MOD_INC_USE_COUNT
;
return
0
;
}
void
ebt_unregister_target
(
struct
ebt_target
*
target
)
{
down
(
&
ebt_mutex
);
LIST_DELETE
(
&
ebt_targets
,
target
);
up
(
&
ebt_mutex
);
MOD_DEC_USE_COUNT
;
}
int
ebt_register_match
(
struct
ebt_match
*
match
)
{
int
ret
;
ret
=
down_interruptible
(
&
ebt_mutex
);
if
(
ret
!=
0
)
return
ret
;
if
(
!
list_named_insert
(
&
ebt_matches
,
match
))
{
up
(
&
ebt_mutex
);
return
-
EEXIST
;
}
up
(
&
ebt_mutex
);
MOD_INC_USE_COUNT
;
return
0
;
}
void
ebt_unregister_match
(
struct
ebt_match
*
match
)
{
down
(
&
ebt_mutex
);
LIST_DELETE
(
&
ebt_matches
,
match
);
up
(
&
ebt_mutex
);
MOD_DEC_USE_COUNT
;
}
int
ebt_register_watcher
(
struct
ebt_watcher
*
watcher
)
{
int
ret
;
ret
=
down_interruptible
(
&
ebt_mutex
);
if
(
ret
!=
0
)
return
ret
;
if
(
!
list_named_insert
(
&
ebt_watchers
,
watcher
))
{
up
(
&
ebt_mutex
);
return
-
EEXIST
;
}
up
(
&
ebt_mutex
);
MOD_INC_USE_COUNT
;
return
0
;
}
void
ebt_unregister_watcher
(
struct
ebt_watcher
*
watcher
)
{
down
(
&
ebt_mutex
);
LIST_DELETE
(
&
ebt_watchers
,
watcher
);
up
(
&
ebt_mutex
);
MOD_DEC_USE_COUNT
;
}
int
ebt_register_table
(
struct
ebt_table
*
table
)
{
struct
ebt_table_info
*
newinfo
;
int
ret
,
i
,
countersize
;
if
(
!
table
||
!
table
->
table
||!
table
->
table
->
entries
||
table
->
table
->
entries_size
==
0
||
table
->
table
->
counters
||
table
->
private
)
{
BUGPRINT
(
"Bad table data for ebt_register_table!!!
\n
"
);
return
-
EINVAL
;
}
countersize
=
COUNTER_OFFSET
(
table
->
table
->
nentries
)
*
NR_CPUS
;
newinfo
=
(
struct
ebt_table_info
*
)
vmalloc
(
sizeof
(
struct
ebt_table_info
)
+
countersize
);
ret
=
-
ENOMEM
;
if
(
!
newinfo
)
return
-
ENOMEM
;
newinfo
->
entries
=
(
char
*
)
vmalloc
(
table
->
table
->
entries_size
);
if
(
!
(
newinfo
->
entries
))
goto
free_newinfo
;
memcpy
(
newinfo
->
entries
,
table
->
table
->
entries
,
table
->
table
->
entries_size
);
if
(
countersize
)
memset
(
newinfo
->
counters
,
0
,
countersize
);
// fill in newinfo and parse the entries
newinfo
->
chainstack
=
NULL
;
ret
=
translate_table
(
table
->
table
,
newinfo
);
if
(
ret
!=
0
)
{
BUGPRINT
(
"Translate_table failed
\n
"
);
goto
free_chainstack
;
}
if
(
table
->
check
&&
table
->
check
(
newinfo
,
table
->
valid_hooks
))
{
BUGPRINT
(
"The table doesn't like its own initial data, lol
\n
"
);
return
-
EINVAL
;
}
table
->
private
=
newinfo
;
table
->
lock
=
RW_LOCK_UNLOCKED
;
ret
=
down_interruptible
(
&
ebt_mutex
);
if
(
ret
!=
0
)
goto
free_chainstack
;
if
(
list_named_find
(
&
ebt_tables
,
table
->
name
))
{
ret
=
-
EEXIST
;
BUGPRINT
(
"Table name already exists
\n
"
);
goto
free_unlock
;
}
list_prepend
(
&
ebt_tables
,
table
);
up
(
&
ebt_mutex
);
MOD_INC_USE_COUNT
;
return
0
;
free_unlock:
up
(
&
ebt_mutex
);
free_chainstack:
if
(
newinfo
->
chainstack
)
{
for
(
i
=
0
;
i
<
NR_CPUS
;
i
++
)
vfree
(
newinfo
->
chainstack
[
i
]);
vfree
(
newinfo
->
chainstack
);
}
vfree
(
newinfo
->
entries
);
free_newinfo:
vfree
(
newinfo
);
return
ret
;
}
void
ebt_unregister_table
(
struct
ebt_table
*
table
)
{
int
i
;
if
(
!
table
)
{
BUGPRINT
(
"Request to unregister NULL table!!!
\n
"
);
return
;
}
down
(
&
ebt_mutex
);
LIST_DELETE
(
&
ebt_tables
,
table
);
up
(
&
ebt_mutex
);
EBT_ENTRY_ITERATE
(
table
->
private
->
entries
,
table
->
private
->
entries_size
,
ebt_cleanup_entry
,
NULL
);
if
(
table
->
private
->
entries
)
vfree
(
table
->
private
->
entries
);
if
(
table
->
private
->
chainstack
)
{
for
(
i
=
0
;
i
<
NR_CPUS
;
i
++
)
vfree
(
table
->
private
->
chainstack
[
i
]);
vfree
(
table
->
private
->
chainstack
);
}
vfree
(
table
->
private
);
MOD_DEC_USE_COUNT
;
}
// userspace just supplied us with counters
static
int
update_counters
(
void
*
user
,
unsigned
int
len
)
{
int
i
,
ret
;
struct
ebt_counter
*
tmp
;
struct
ebt_replace
hlp
;
struct
ebt_table
*
t
;
if
(
copy_from_user
(
&
hlp
,
user
,
sizeof
(
hlp
)))
return
-
EFAULT
;
if
(
len
!=
sizeof
(
hlp
)
+
hlp
.
num_counters
*
sizeof
(
struct
ebt_counter
))
return
-
EINVAL
;
if
(
hlp
.
num_counters
==
0
)
return
-
EINVAL
;
if
(
!
(
tmp
=
(
struct
ebt_counter
*
)
vmalloc
(
hlp
.
num_counters
*
sizeof
(
struct
ebt_counter
)))
){
MEMPRINT
(
"Update_counters && nomemory
\n
"
);
return
-
ENOMEM
;
}
t
=
find_table_lock
(
hlp
.
name
,
&
ret
,
&
ebt_mutex
);
if
(
!
t
)
goto
free_tmp
;
if
(
hlp
.
num_counters
!=
t
->
private
->
nentries
)
{
BUGPRINT
(
"Wrong nr of counters
\n
"
);
ret
=
-
EINVAL
;
goto
unlock_mutex
;
}
if
(
copy_from_user
(
tmp
,
hlp
.
counters
,
hlp
.
num_counters
*
sizeof
(
struct
ebt_counter
))
)
{
BUGPRINT
(
"Updata_counters && !cfu
\n
"
);
ret
=
-
EFAULT
;
goto
unlock_mutex
;
}
// we want an atomic add of the counters
write_lock_bh
(
&
t
->
lock
);
// we add to the counters of the first cpu
for
(
i
=
0
;
i
<
hlp
.
num_counters
;
i
++
)
t
->
private
->
counters
[
i
].
pcnt
+=
tmp
[
i
].
pcnt
;
write_unlock_bh
(
&
t
->
lock
);
ret
=
0
;
unlock_mutex:
up
(
&
ebt_mutex
);
free_tmp:
vfree
(
tmp
);
return
ret
;
}
static
inline
int
ebt_make_matchname
(
struct
ebt_entry_match
*
m
,
char
*
base
,
char
*
ubase
)
{
char
*
hlp
=
ubase
-
base
+
(
char
*
)
m
;
if
(
copy_to_user
(
hlp
,
m
->
u
.
match
->
name
,
EBT_FUNCTION_MAXNAMELEN
))
return
-
EFAULT
;
return
0
;
}
static
inline
int
ebt_make_watchername
(
struct
ebt_entry_watcher
*
w
,
char
*
base
,
char
*
ubase
)
{
char
*
hlp
=
ubase
-
base
+
(
char
*
)
w
;
if
(
copy_to_user
(
hlp
,
w
->
u
.
watcher
->
name
,
EBT_FUNCTION_MAXNAMELEN
))
return
-
EFAULT
;
return
0
;
}
static
inline
int
ebt_make_names
(
struct
ebt_entry
*
e
,
char
*
base
,
char
*
ubase
)
{
int
ret
;
char
*
hlp
;
struct
ebt_entry_target
*
t
;
if
((
e
->
bitmask
&
EBT_ENTRY_OR_ENTRIES
)
==
0
)
return
0
;
hlp
=
ubase
-
base
+
(
char
*
)
e
+
e
->
target_offset
;
t
=
(
struct
ebt_entry_target
*
)(((
char
*
)
e
)
+
e
->
target_offset
);
ret
=
EBT_MATCH_ITERATE
(
e
,
ebt_make_matchname
,
base
,
ubase
);
if
(
ret
!=
0
)
return
ret
;
ret
=
EBT_WATCHER_ITERATE
(
e
,
ebt_make_watchername
,
base
,
ubase
);
if
(
ret
!=
0
)
return
ret
;
if
(
copy_to_user
(
hlp
,
t
->
u
.
target
->
name
,
EBT_FUNCTION_MAXNAMELEN
))
return
-
EFAULT
;
return
0
;
}
// called with ebt_mutex down
static
int
copy_everything_to_user
(
struct
ebt_table
*
t
,
void
*
user
,
int
*
len
,
int
cmd
)
{
struct
ebt_replace
tmp
;
struct
ebt_counter
*
counterstmp
,
*
oldcounters
;
unsigned
int
entries_size
,
nentries
;
char
*
entries
;
if
(
cmd
==
EBT_SO_GET_ENTRIES
)
{
entries_size
=
t
->
private
->
entries_size
;
nentries
=
t
->
private
->
nentries
;
entries
=
t
->
private
->
entries
;
oldcounters
=
t
->
private
->
counters
;
}
else
{
entries_size
=
t
->
table
->
entries_size
;
nentries
=
t
->
table
->
nentries
;
entries
=
t
->
table
->
entries
;
oldcounters
=
t
->
table
->
counters
;
}
if
(
copy_from_user
(
&
tmp
,
user
,
sizeof
(
tmp
)))
{
BUGPRINT
(
"Cfu didn't work
\n
"
);
return
-
EFAULT
;
}
if
(
*
len
!=
sizeof
(
struct
ebt_replace
)
+
entries_size
+
(
tmp
.
num_counters
?
nentries
*
sizeof
(
struct
ebt_counter
)
:
0
))
{
BUGPRINT
(
"Wrong size
\n
"
);
return
-
EINVAL
;
}
if
(
tmp
.
nentries
!=
nentries
)
{
BUGPRINT
(
"Nentries wrong
\n
"
);
return
-
EINVAL
;
}
if
(
tmp
.
entries_size
!=
entries_size
)
{
BUGPRINT
(
"Wrong size
\n
"
);
return
-
EINVAL
;
}
// userspace might not need the counters
if
(
tmp
.
num_counters
)
{
if
(
tmp
.
num_counters
!=
nentries
)
{
BUGPRINT
(
"Num_counters wrong
\n
"
);
return
-
EINVAL
;
}
counterstmp
=
(
struct
ebt_counter
*
)
vmalloc
(
nentries
*
sizeof
(
struct
ebt_counter
));
if
(
!
counterstmp
)
{
MEMPRINT
(
"Couldn't copy counters, out of memory
\n
"
);
return
-
ENOMEM
;
}
write_lock_bh
(
&
t
->
lock
);
get_counters
(
oldcounters
,
counterstmp
,
nentries
);
write_unlock_bh
(
&
t
->
lock
);
if
(
copy_to_user
(
tmp
.
counters
,
counterstmp
,
nentries
*
sizeof
(
struct
ebt_counter
)))
{
BUGPRINT
(
"Couldn't copy counters to userspace
\n
"
);
vfree
(
counterstmp
);
return
-
EFAULT
;
}
vfree
(
counterstmp
);
}
if
(
copy_to_user
(
tmp
.
entries
,
entries
,
entries_size
))
{
BUGPRINT
(
"Couldn't copy entries to userspace
\n
"
);
return
-
EFAULT
;
}
// set the match/watcher/target names right
return
EBT_ENTRY_ITERATE
(
entries
,
entries_size
,
ebt_make_names
,
entries
,
tmp
.
entries
);
}
static
int
do_ebt_set_ctl
(
struct
sock
*
sk
,
int
cmd
,
void
*
user
,
unsigned
int
len
)
{
int
ret
;
switch
(
cmd
)
{
case
EBT_SO_SET_ENTRIES
:
ret
=
do_replace
(
user
,
len
);
break
;
case
EBT_SO_SET_COUNTERS
:
ret
=
update_counters
(
user
,
len
);
break
;
default:
ret
=
-
EINVAL
;
}
return
ret
;
}
static
int
do_ebt_get_ctl
(
struct
sock
*
sk
,
int
cmd
,
void
*
user
,
int
*
len
)
{
int
ret
;
struct
ebt_replace
tmp
;
struct
ebt_table
*
t
;
if
(
copy_from_user
(
&
tmp
,
user
,
sizeof
(
tmp
)))
return
-
EFAULT
;
t
=
find_table_lock
(
tmp
.
name
,
&
ret
,
&
ebt_mutex
);
if
(
!
t
)
return
ret
;
switch
(
cmd
)
{
case
EBT_SO_GET_INFO
:
case
EBT_SO_GET_INIT_INFO
:
if
(
*
len
!=
sizeof
(
struct
ebt_replace
)){
ret
=
-
EINVAL
;
up
(
&
ebt_mutex
);
break
;
}
if
(
cmd
==
EBT_SO_GET_INFO
)
{
tmp
.
nentries
=
t
->
private
->
nentries
;
tmp
.
entries_size
=
t
->
private
->
entries_size
;
tmp
.
valid_hooks
=
t
->
valid_hooks
;
}
else
{
tmp
.
nentries
=
t
->
table
->
nentries
;
tmp
.
entries_size
=
t
->
table
->
entries_size
;
tmp
.
valid_hooks
=
t
->
table
->
valid_hooks
;
}
up
(
&
ebt_mutex
);
if
(
copy_to_user
(
user
,
&
tmp
,
*
len
)
!=
0
){
BUGPRINT
(
"c2u Didn't work
\n
"
);
ret
=
-
EFAULT
;
break
;
}
ret
=
0
;
break
;
case
EBT_SO_GET_ENTRIES
:
case
EBT_SO_GET_INIT_ENTRIES
:
ret
=
copy_everything_to_user
(
t
,
user
,
len
,
cmd
);
up
(
&
ebt_mutex
);
break
;
default:
up
(
&
ebt_mutex
);
ret
=
-
EINVAL
;
}
return
ret
;
}
static
struct
nf_sockopt_ops
ebt_sockopts
=
{
{
NULL
,
NULL
},
PF_INET
,
EBT_BASE_CTL
,
EBT_SO_SET_MAX
+
1
,
do_ebt_set_ctl
,
EBT_BASE_CTL
,
EBT_SO_GET_MAX
+
1
,
do_ebt_get_ctl
,
0
,
NULL
};
static
int
__init
init
(
void
)
{
int
ret
;
down
(
&
ebt_mutex
);
list_named_insert
(
&
ebt_targets
,
&
ebt_standard_target
);
up
(
&
ebt_mutex
);
if
((
ret
=
nf_register_sockopt
(
&
ebt_sockopts
))
<
0
)
return
ret
;
printk
(
"Ebtables v2.0 registered"
);
return
0
;
}
static
void
__exit
fini
(
void
)
{
nf_unregister_sockopt
(
&
ebt_sockopts
);
printk
(
"Ebtables v2.0 unregistered"
);
}
EXPORT_SYMBOL
(
ebt_register_table
);
EXPORT_SYMBOL
(
ebt_unregister_table
);
EXPORT_SYMBOL
(
ebt_register_match
);
EXPORT_SYMBOL
(
ebt_unregister_match
);
EXPORT_SYMBOL
(
ebt_register_watcher
);
EXPORT_SYMBOL
(
ebt_unregister_watcher
);
EXPORT_SYMBOL
(
ebt_register_target
);
EXPORT_SYMBOL
(
ebt_unregister_target
);
EXPORT_SYMBOL
(
ebt_do_table
);
module_init
(
init
);
module_exit
(
fini
);
MODULE_LICENSE
(
"GPL"
);
net/core/dev.c
View file @
b12d2ca2
...
...
@@ -1397,7 +1397,7 @@ void net_call_rx_atomic(void (*fn)(void))
}
#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
void
(
*
br_handle_frame_hook
)(
struct
sk_buff
*
skb
)
=
NULL
;
int
(
*
br_handle_frame_hook
)(
struct
sk_buff
*
skb
)
=
NULL
;
#endif
static
__inline__
int
handle_bridge
(
struct
sk_buff
*
skb
,
...
...
@@ -1414,7 +1414,6 @@ static __inline__ int handle_bridge(struct sk_buff *skb,
}
}
br_handle_frame_hook
(
skb
);
return
ret
;
}
...
...
@@ -1475,7 +1474,12 @@ int netif_receive_skb(struct sk_buff *skb)
#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
if
(
skb
->
dev
->
br_port
&&
br_handle_frame_hook
)
{
return
handle_bridge
(
skb
,
pt_prev
);
int
ret
;
ret
=
handle_bridge
(
skb
,
pt_prev
);
if
(
br_handle_frame_hook
(
skb
)
==
0
)
return
ret
;
pt_prev
=
NULL
;
}
#endif
...
...
net/llc/llc_sock.c
View file @
b12d2ca2
...
...
@@ -878,18 +878,22 @@ static int llc_ui_recvmsg(struct socket *sock, struct msghdr *msg, int size,
if
(
!
skb
)
/* shutdown */
goto
out
;
copied
=
skb
->
len
;
if
(
copied
>
size
)
{
if
(
copied
>
size
)
copied
=
size
;
msg
->
msg_flags
|=
MSG_TRUNC
;
}
rc
=
skb_copy_datagram_iovec
(
skb
,
0
,
msg
->
msg_iov
,
copied
);
if
(
rc
)
goto
dgram_free
;
if
(
skb
->
len
>
copied
)
{
skb_pull
(
skb
,
copied
);
skb_queue_head
(
&
sk
->
receive_queue
,
skb
);
}
if
(
uaddr
)
memcpy
(
uaddr
,
llc_ui_skb_cb
(
skb
),
sizeof
(
*
uaddr
));
msg
->
msg_namelen
=
sizeof
(
*
uaddr
);
if
(
!
skb
->
list
)
{
dgram_free:
kfree_skb
(
skb
);
kfree_skb
(
skb
);
}
out:
release_sock
(
sk
);
return
rc
?
:
copied
;
...
...
@@ -915,7 +919,7 @@ static int llc_ui_sendmsg(struct socket *sock, struct msghdr *msg, int len,
int
noblock
=
flags
&
MSG_DONTWAIT
;
struct
net_device
*
dev
;
struct
sk_buff
*
skb
;
int
rc
=
-
EINVAL
,
size
=
0
;
int
rc
=
-
EINVAL
,
size
=
0
,
copied
=
0
,
hdrlen
;
dprintk
(
"%s: sending from %02X to %02X
\n
"
,
__FUNCTION__
,
llc
->
laddr
.
lsap
,
llc
->
daddr
.
lsap
);
lock_sock
(
sk
);
...
...
@@ -943,20 +947,26 @@ static int llc_ui_sendmsg(struct socket *sock, struct msghdr *msg, int len,
goto
release
;
}
else
dev
=
llc
->
dev
;
size
=
dev
->
hard_header_len
+
len
+
llc_ui_header_len
(
sk
,
addr
);
rc
=
-
EMSGSIZE
;
hdrlen
=
dev
->
hard_header_
len
+
llc_ui_header_len
(
sk
,
addr
);
size
=
hdrlen
+
len
;
if
(
size
>
dev
->
mtu
)
goto
release
;
size
=
dev
->
mtu
;
copied
=
size
-
hdrlen
;
skb
=
sock_alloc_send_skb
(
sk
,
size
,
noblock
,
&
rc
);
if
(
!
skb
)
goto
release
;
skb
->
sk
=
sk
;
skb
->
dev
=
dev
;
skb
->
protocol
=
llc_proto_type
(
addr
->
sllc_arphrd
);
skb_reserve
(
skb
,
dev
->
hard_header_len
+
llc_ui_header_len
(
sk
,
addr
));
rc
=
memcpy_fromiovec
(
skb_put
(
skb
,
len
),
msg
->
msg_iov
,
len
);
skb_reserve
(
skb
,
hdrlen
);
rc
=
memcpy_fromiovec
(
skb_put
(
skb
,
copied
),
msg
->
msg_iov
,
copied
);
if
(
rc
)
goto
out
;
if
(
sk
->
type
==
SOCK_DGRAM
||
addr
->
sllc_ua
)
{
llc_build_and_send_ui_pkt
(
llc
->
sap
,
skb
,
addr
->
sllc_dmac
,
addr
->
sllc_dsap
);
goto
out
;
}
if
(
addr
->
sllc_test
)
{
llc_build_and_send_test_pkt
(
llc
->
sap
,
skb
,
addr
->
sllc_dmac
,
addr
->
sllc_dsap
);
...
...
@@ -967,11 +977,6 @@ static int llc_ui_sendmsg(struct socket *sock, struct msghdr *msg, int len,
addr
->
sllc_dsap
);
goto
out
;
}
if
(
sk
->
type
==
SOCK_DGRAM
||
addr
->
sllc_ua
)
{
llc_build_and_send_ui_pkt
(
llc
->
sap
,
skb
,
addr
->
sllc_dmac
,
addr
->
sllc_dsap
);
goto
out
;
}
rc
=
-
ENOPROTOOPT
;
if
(
!
(
sk
->
type
==
SOCK_STREAM
&&
!
addr
->
sllc_ua
))
goto
out
;
...
...
@@ -986,7 +991,7 @@ static int llc_ui_sendmsg(struct socket *sock, struct msghdr *msg, int len,
dprintk
(
"%s: failed sending from %02X to %02X: %d
\n
"
,
__FUNCTION__
,
llc
->
laddr
.
lsap
,
llc
->
daddr
.
lsap
,
rc
);
release_sock
(
sk
);
return
rc
?
:
len
;
return
rc
?
:
copied
;
}
/**
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment