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
nexedi
linux
Commits
78d4faf7
Commit
78d4faf7
authored
Apr 10, 2003
by
David S. Miller
Browse files
Options
Browse Files
Download
Plain Diff
Merge davem@nuts.ninka.net:/home/davem/src/BK/net-2.5
into kernel.bkbits.net:/home/davem/net-2.5
parents
d55d7cdf
7cfe7c7e
Changes
34
Show whitespace changes
Inline
Side-by-side
Showing
34 changed files
with
2113 additions
and
145 deletions
+2113
-145
include/linux/if_bridge.h
include/linux/if_bridge.h
+1
-1
include/linux/igmp.h
include/linux/igmp.h
+96
-2
include/linux/in.h
include/linux/in.h
+26
-0
include/linux/inetdevice.h
include/linux/inetdevice.h
+10
-0
include/net/ip.h
include/net/ip.h
+1
-0
include/net/ip6_fib.h
include/net/ip6_fib.h
+8
-3
include/net/ip6_route.h
include/net/ip6_route.h
+4
-2
net/bridge/br.c
net/bridge/br.c
+4
-9
net/bridge/br_if.c
net/bridge/br_if.c
+18
-5
net/bridge/br_ioctl.c
net/bridge/br_ioctl.c
+18
-16
net/bridge/br_notify.c
net/bridge/br_notify.c
+17
-16
net/core/dev.c
net/core/dev.c
+5
-4
net/ipv4/Kconfig
net/ipv4/Kconfig
+8
-0
net/ipv4/Makefile
net/ipv4/Makefile
+1
-0
net/ipv4/igmp.c
net/ipv4/igmp.c
+1338
-37
net/ipv4/ip_output.c
net/ipv4/ip_output.c
+1
-0
net/ipv4/ip_sockglue.c
net/ipv4/ip_sockglue.c
+74
-2
net/ipv4/ipcomp.c
net/ipv4/ipcomp.c
+366
-0
net/ipv4/netfilter/ip_conntrack_core.c
net/ipv4/netfilter/ip_conntrack_core.c
+5
-0
net/ipv4/route.c
net/ipv4/route.c
+3
-2
net/ipv4/udp.c
net/ipv4/udp.c
+2
-0
net/ipv4/xfrm4_input.c
net/ipv4/xfrm4_input.c
+3
-0
net/ipv4/xfrm4_policy.c
net/ipv4/xfrm4_policy.c
+7
-0
net/ipv6/addrconf.c
net/ipv6/addrconf.c
+5
-5
net/ipv6/ip6_fib.c
net/ipv6/ip6_fib.c
+11
-9
net/ipv6/ndisc.c
net/ipv6/ndisc.c
+2
-2
net/ipv6/route.c
net/ipv6/route.c
+40
-27
net/ipv6/xfrm6_input.c
net/ipv6/xfrm6_input.c
+3
-0
net/ipv6/xfrm6_policy.c
net/ipv6/xfrm6_policy.c
+1
-0
net/netsyms.c
net/netsyms.c
+1
-1
net/sched/sch_csz.c
net/sched/sch_csz.c
+8
-0
net/sched/sch_htb.c
net/sched/sch_htb.c
+2
-0
net/sched/sch_prio.c
net/sched/sch_prio.c
+6
-0
net/socket.c
net/socket.c
+18
-2
No files found.
include/linux/if_bridge.h
View file @
78d4faf7
...
...
@@ -101,7 +101,7 @@ struct __fdb_entry
struct
net_bridge
;
struct
net_bridge_port
;
extern
int
(
*
br_ioctl_hook
)(
unsigned
long
arg
);
extern
void
brioctl_set
(
int
(
*
ioctl_hook
)(
unsigned
long
)
);
extern
int
(
*
br_handle_frame_hook
)(
struct
sk_buff
*
skb
);
extern
int
(
*
br_should_route_hook
)(
struct
sk_buff
**
pskb
);
...
...
include/linux/igmp.h
View file @
78d4faf7
...
...
@@ -32,13 +32,60 @@ struct igmphdr
__u32
group
;
};
/* V3 group record types [grec_type] */
#define IGMPV3_MODE_IS_INCLUDE 1
#define IGMPV3_MODE_IS_EXCLUDE 2
#define IGMPV3_CHANGE_TO_INCLUDE 3
#define IGMPV3_CHANGE_TO_EXCLUDE 4
#define IGMPV3_ALLOW_NEW_SOURCES 5
#define IGMPV3_BLOCK_OLD_SOURCES 6
struct
igmpv3_grec
{
__u8
grec_type
;
__u8
grec_auxwords
;
__u16
grec_nsrcs
;
__u32
grec_mca
;
__u32
grec_src
[
0
];
};
struct
igmpv3_report
{
__u8
type
;
__u8
resv1
;
__u16
csum
;
__u16
resv2
;
__u16
ngrec
;
struct
igmpv3_grec
grec
[
0
];
};
struct
igmpv3_query
{
__u8
type
;
__u8
code
;
__u16
csum
;
__u32
group
;
#if defined(__LITTLE_ENDIAN_BITFIELD)
__u8
qrv
:
3
,
suppress:
1
,
resv:
4
;
#elif defined(__BIG_ENDIAN_BITFIELD)
__u8
resv
:
4
,
suppress:
1
,
qrv:
3
;
#else
#error "Please fix <asm/byteorder.h>"
#endif
__u8
qqic
;
__u16
nsrcs
;
__u32
srcs
[
0
];
};
#define IGMP_HOST_MEMBERSHIP_QUERY 0x11
/* From RFC1112 */
#define IGMP_HOST_MEMBERSHIP_REPORT 0x12
/* Ditto */
#define IGMP_DVMRP 0x13
/* DVMRP routing */
#define IGMP_PIM 0x14
/* PIM routing */
#define IGMP_TRACE 0x15
#define IGMP
_HOST_NEW_MEMBERSHIP_REPORT 0x16
/* New
version of 0x11 */
#define IGMP
V2_HOST_MEMBERSHIP_REPORT 0x16
/* V2
version of 0x11 */
#define IGMP_HOST_LEAVE_MESSAGE 0x17
#define IGMPV3_HOST_MEMBERSHIP_REPORT 0x22
/* V3 version of 0x11 */
#define IGMP_MTRACE_RESP 0x1e
#define IGMP_MTRACE 0x1f
...
...
@@ -68,6 +115,7 @@ struct igmphdr
#define IGMP_ALL_HOSTS htonl(0xE0000001L)
#define IGMP_ALL_ROUTER htonl(0xE0000002L)
#define IGMPV3_ALL_MCR htonl(0xE0000016L)
#define IGMP_LOCAL_GROUP htonl(0xE0000000L)
#define IGMP_LOCAL_GROUP_MASK htonl(0xFFFFFF00L)
...
...
@@ -79,6 +127,18 @@ struct igmphdr
#include <linux/skbuff.h>
#include <linux/in.h>
struct
ip_sf_socklist
{
unsigned
int
sl_max
;
unsigned
int
sl_count
;
__u32
sl_addr
[
0
];
};
#define IP_SFLSIZE(count) (sizeof(struct ip_sf_socklist) + \
(count) * sizeof(__u32))
#define IP_SFBLOCK 10
/* allocate this many at once */
/* ip_mc_socklist is real list now. Speed is not argument;
this list never used in fast path code
*/
...
...
@@ -88,12 +148,28 @@ struct ip_mc_socklist
struct
ip_mc_socklist
*
next
;
int
count
;
struct
ip_mreqn
multi
;
unsigned
int
sfmode
;
/* MCAST_{INCLUDE,EXCLUDE} */
struct
ip_sf_socklist
*
sflist
;
};
struct
ip_sf_list
{
struct
ip_sf_list
*
sf_next
;
__u32
sf_inaddr
;
unsigned
long
sf_count
[
2
];
/* include/exclude counts */
unsigned
char
sf_gsresp
;
/* include in g & s response? */
unsigned
char
sf_oldin
;
/* change state */
unsigned
char
sf_crcount
;
/* retrans. left to send */
};
struct
ip_mc_list
{
struct
in_device
*
interface
;
unsigned
long
multiaddr
;
struct
ip_sf_list
*
sources
;
struct
ip_sf_list
*
tomb
;
unsigned
int
sfmode
;
unsigned
long
sfcount
[
2
];
struct
ip_mc_list
*
next
;
struct
timer_list
timer
;
int
users
;
...
...
@@ -103,13 +179,31 @@ struct ip_mc_list
char
reporter
;
char
unsolicit_count
;
char
loaded
;
unsigned
char
gsquery
;
/* check source marks? */
unsigned
char
crcount
;
};
extern
int
ip_check_mc
(
struct
in_device
*
dev
,
u32
mc_addr
);
/* V3 exponential field decoding */
#define IGMPV3_MASK(value, nb) ((nb)>=32 ? (value) : ((1<<(nb))-1) & (value))
#define IGMPV3_EXP(thresh, nbmant, nbexp, value) \
((value) < (thresh) ? (value) : \
((IGMPV3_MASK(value, nbmant) | (1<<(nbmant+nbexp))) << \
(IGMPV3_MASK((value) >> (nbmant), nbexp) + (nbexp))))
#define IGMPV3_QQIC(value) IGMPV3_EXP(0x80, 4, 3, value)
#define IGMPV3_MRC(value) IGMPV3_EXP(0x8000, 12, 3, value)
extern
int
ip_check_mc
(
struct
in_device
*
dev
,
u32
mc_addr
,
u32
src_addr
,
u16
proto
);
extern
int
igmp_rcv
(
struct
sk_buff
*
);
extern
int
ip_mc_join_group
(
struct
sock
*
sk
,
struct
ip_mreqn
*
imr
);
extern
int
ip_mc_leave_group
(
struct
sock
*
sk
,
struct
ip_mreqn
*
imr
);
extern
void
ip_mc_drop_socket
(
struct
sock
*
sk
);
extern
int
ip_mc_source
(
int
add
,
int
omode
,
struct
sock
*
sk
,
struct
ip_mreq_source
*
mreqs
);
extern
int
ip_mc_msfilter
(
struct
sock
*
sk
,
struct
ip_msfilter
*
msf
);
extern
int
ip_mc_msfget
(
struct
sock
*
sk
,
struct
ip_msfilter
*
msf
,
struct
ip_msfilter
*
optval
,
int
*
optlen
);
extern
int
ip_mc_sf_allow
(
struct
sock
*
sk
,
u32
local
,
u32
rmt
,
int
dif
);
extern
void
ip_mr_init
(
void
);
extern
void
ip_mc_init_dev
(
struct
in_device
*
);
extern
void
ip_mc_destroy_dev
(
struct
in_device
*
);
...
...
include/linux/in.h
View file @
78d4faf7
...
...
@@ -85,6 +85,14 @@ struct in_addr {
#define IP_MULTICAST_LOOP 34
#define IP_ADD_MEMBERSHIP 35
#define IP_DROP_MEMBERSHIP 36
#define IP_UNBLOCK_SOURCE 37
#define IP_BLOCK_SOURCE 38
#define IP_ADD_SOURCE_MEMBERSHIP 39
#define IP_DROP_SOURCE_MEMBERSHIP 40
#define IP_MSFILTER 41
#define MCAST_EXCLUDE 0
#define MCAST_INCLUDE 1
/* These need to appear somewhere around here */
#define IP_DEFAULT_MULTICAST_TTL 1
...
...
@@ -105,6 +113,24 @@ struct ip_mreqn
int
imr_ifindex
;
/* Interface index */
};
struct
ip_mreq_source
{
__u32
imr_multiaddr
;
__u32
imr_interface
;
__u32
imr_sourceaddr
;
};
struct
ip_msfilter
{
__u32
imsf_multiaddr
;
__u32
imsf_interface
;
__u32
imsf_fmode
;
__u32
imsf_numsrc
;
__u32
imsf_slist
[
1
];
};
#define IP_MSFILTER_SIZE(numsrc) \
(sizeof(struct ip_msfilter) - sizeof(__u32) \
+ (numsrc) * sizeof(__u32))
struct
in_pktinfo
{
int
ipi_ifindex
;
...
...
include/linux/inetdevice.h
View file @
78d4faf7
...
...
@@ -34,7 +34,17 @@ struct in_device
int
dead
;
struct
in_ifaddr
*
ifa_list
;
/* IP ifaddr chain */
struct
ip_mc_list
*
mc_list
;
/* IP multicast filter chain */
rwlock_t
mc_lock
;
/* for mc_tomb */
struct
ip_mc_list
*
mc_tomb
;
unsigned
long
mr_v1_seen
;
unsigned
long
mr_v2_seen
;
unsigned
long
mr_maxdelay
;
unsigned
char
mr_qrv
;
unsigned
char
mr_gq_running
;
unsigned
char
mr_ifc_count
;
struct
timer_list
mr_gq_timer
;
/* general query timer */
struct
timer_list
mr_ifc_timer
;
/* interface change timer */
struct
neigh_parms
*
arp_parms
;
struct
ipv4_devconf
cnf
;
};
...
...
include/net/ip.h
View file @
78d4faf7
...
...
@@ -79,6 +79,7 @@ extern rwlock_t ip_ra_lock;
extern
void
ip_mc_dropsocket
(
struct
sock
*
);
extern
void
ip_mc_dropdevice
(
struct
net_device
*
dev
);
extern
int
ip_mc_procinfo
(
char
*
,
char
**
,
off_t
,
int
);
extern
int
ip_mcf_procinfo
(
char
*
,
char
**
,
off_t
,
int
);
/*
* Functions provided by ip.c
...
...
include/net/ip6_fib.h
View file @
78d4faf7
...
...
@@ -72,6 +72,8 @@ struct rt6_info
struct
rt6key
rt6i_dst
;
struct
rt6key
rt6i_src
;
u8
rt6i_protocol
;
};
struct
fib6_walker_t
...
...
@@ -160,11 +162,14 @@ extern int fib6_walk(struct fib6_walker_t *w);
extern
int
fib6_walk_continue
(
struct
fib6_walker_t
*
w
);
extern
int
fib6_add
(
struct
fib6_node
*
root
,
struct
rt6_info
*
rt
);
struct
rt6_info
*
rt
,
struct
nlmsghdr
*
nlh
);
extern
int
fib6_del
(
struct
rt6_info
*
rt
);
extern
int
fib6_del
(
struct
rt6_info
*
rt
,
struct
nlmsghdr
*
nlh
);
extern
void
inet6_rt_notify
(
int
event
,
struct
rt6_info
*
rt
);
extern
void
inet6_rt_notify
(
int
event
,
struct
rt6_info
*
rt
,
struct
nlmsghdr
*
nlh
);
extern
void
fib6_run_gc
(
unsigned
long
dummy
);
...
...
include/net/ip6_route.h
View file @
78d4faf7
...
...
@@ -37,8 +37,10 @@ extern void ip6_route_cleanup(void);
extern
int
ipv6_route_ioctl
(
unsigned
int
cmd
,
void
*
arg
);
extern
int
ip6_route_add
(
struct
in6_rtmsg
*
rtmsg
);
extern
int
ip6_del_rt
(
struct
rt6_info
*
);
extern
int
ip6_route_add
(
struct
in6_rtmsg
*
rtmsg
,
struct
nlmsghdr
*
);
extern
int
ip6_del_rt
(
struct
rt6_info
*
,
struct
nlmsghdr
*
);
extern
int
ip6_rt_addr_add
(
struct
in6_addr
*
addr
,
struct
net_device
*
dev
);
...
...
net/bridge/br.c
View file @
78d4faf7
...
...
@@ -49,8 +49,9 @@ static int __init br_init(void)
if
(
br_netfilter_init
())
return
1
;
#endif
brioctl_set
(
br_ioctl_deviceless_stub
);
br_handle_frame_hook
=
br_handle_frame
;
br_ioctl_hook
=
br_ioctl_deviceless_stub
;
#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
br_fdb_get_hook
=
br_fdb_get
;
br_fdb_put_hook
=
br_fdb_put
;
...
...
@@ -60,24 +61,18 @@ static int __init br_init(void)
return
0
;
}
static
void
__br_clear_ioctl_hook
(
void
)
{
br_ioctl_hook
=
NULL
;
}
static
void
__exit
br_deinit
(
void
)
{
#ifdef CONFIG_NETFILTER
br_netfilter_fini
();
#endif
unregister_netdevice_notifier
(
&
br_device_notifier
);
br_call_ioctl_atomic
(
__br_clear_ioctl_hook
);
br
_write_lock_bh
(
BR_NETPROTO_LOCK
);
br
ioctl_set
(
NULL
);
br_handle_frame_hook
=
NULL
;
br_write_unlock_bh
(
BR_NETPROTO_LOCK
);
#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
/* FIX ME. move into hook structure with ref count */
br_fdb_get_hook
=
NULL
;
br_fdb_put_hook
=
NULL
;
#endif
...
...
net/bridge/br_if.c
View file @
78d4faf7
...
...
@@ -23,6 +23,7 @@
#include "br_private.h"
static
struct
net_bridge
*
bridge_list
;
static
spinlock_t
bridge_lock
=
SPIN_LOCK_UNLOCKED
;
static
int
br_initial_port_cost
(
struct
net_device
*
dev
)
{
...
...
@@ -69,6 +70,7 @@ static int __br_del_if(struct net_bridge *br, struct net_device *dev)
return
0
;
}
/* called with bridge_lock */
static
struct
net_bridge
**
__find_br
(
char
*
name
)
{
struct
net_bridge
**
b
;
...
...
@@ -188,8 +190,10 @@ int br_add_bridge(char *name)
return
-
EEXIST
;
}
spin_lock
(
&
bridge_lock
);
br
->
next
=
bridge_list
;
bridge_list
=
br
;
spin_unlock
(
&
bridge_lock
);
br_inc_use_count
();
register_netdev
(
&
br
->
dev
);
...
...
@@ -202,17 +206,22 @@ int br_del_bridge(char *name)
struct
net_bridge
**
b
;
struct
net_bridge
*
br
;
if
((
b
=
__find_br
(
name
))
==
NULL
)
spin_lock
(
&
bridge_lock
);
if
((
b
=
__find_br
(
name
))
==
NULL
)
{
spin_unlock
(
&
bridge_lock
);
return
-
ENXIO
;
}
br
=
*
b
;
if
(
br
->
dev
.
flags
&
IFF_UP
)
if
(
br
->
dev
.
flags
&
IFF_UP
)
{
spin_unlock
(
&
bridge_lock
);
return
-
EBUSY
;
del_ifs
(
br
);
}
*
b
=
br
->
next
;
spin_unlock
(
&
bridge_lock
);
del_ifs
(
br
);
unregister_netdev
(
&
br
->
dev
);
kfree
(
br
);
...
...
@@ -272,6 +281,7 @@ int br_get_bridge_ifindices(int *indices, int num)
struct
net_bridge
*
br
;
int
i
;
spin_lock
(
&
bridge_lock
);
br
=
bridge_list
;
for
(
i
=
0
;
i
<
num
;
i
++
)
{
if
(
br
==
NULL
)
...
...
@@ -280,6 +290,7 @@ int br_get_bridge_ifindices(int *indices, int num)
indices
[
i
]
=
br
->
dev
.
ifindex
;
br
=
br
->
next
;
}
spin_unlock
(
&
bridge_lock
);
return
i
;
}
...
...
@@ -289,9 +300,11 @@ void br_get_port_ifindices(struct net_bridge *br, int *ifindices)
{
struct
net_bridge_port
*
p
;
read_lock
(
&
br
->
lock
);
p
=
br
->
port_list
;
while
(
p
!=
NULL
)
{
ifindices
[
p
->
port_no
]
=
p
->
dev
->
ifindex
;
p
=
p
->
next
;
}
read_unlock
(
&
br
->
lock
);
}
net/bridge/br_ioctl.c
View file @
78d4faf7
...
...
@@ -53,6 +53,7 @@ static int br_ioctl_device(struct net_bridge *br,
{
struct
__bridge_info
b
;
read_lock
(
&
br
->
lock
);
memset
(
&
b
,
0
,
sizeof
(
struct
__bridge_info
));
memcpy
(
&
b
.
designated_root
,
&
br
->
designated_root
,
8
);
memcpy
(
&
b
.
bridge_id
,
&
br
->
bridge_id
,
8
);
...
...
@@ -73,6 +74,7 @@ static int br_ioctl_device(struct net_bridge *br,
b
.
tcn_timer_value
=
br_timer_get_residue
(
&
br
->
tcn_timer
);
b
.
topology_change_timer_value
=
br_timer_get_residue
(
&
br
->
topology_change_timer
);
b
.
gc_timer_value
=
br_timer_get_residue
(
&
br
->
gc_timer
);
read_unlock
(
&
br
->
lock
);
if
(
copy_to_user
((
void
*
)
arg0
,
&
b
,
sizeof
(
b
)))
return
-
EFAULT
;
...
...
@@ -96,21 +98,27 @@ static int br_ioctl_device(struct net_bridge *br,
}
case
BRCTL_SET_BRIDGE_FORWARD_DELAY
:
write_lock
(
&
br
->
lock
);
br
->
bridge_forward_delay
=
arg0
;
if
(
br_is_root_bridge
(
br
))
br
->
forward_delay
=
arg0
;
write_unlock
(
&
br
->
lock
);
return
0
;
case
BRCTL_SET_BRIDGE_HELLO_TIME
:
write_lock
(
&
br
->
lock
);
br
->
bridge_hello_time
=
arg0
;
if
(
br_is_root_bridge
(
br
))
br
->
hello_time
=
arg0
;
write_unlock
(
&
br
->
lock
);
return
0
;
case
BRCTL_SET_BRIDGE_MAX_AGE
:
write_lock
(
&
br
->
lock
);
br
->
bridge_max_age
=
arg0
;
if
(
br_is_root_bridge
(
br
))
br
->
max_age
=
arg0
;
write_unlock
(
&
br
->
lock
);
return
0
;
case
BRCTL_SET_AGEING_TIME
:
...
...
@@ -126,6 +134,7 @@ static int br_ioctl_device(struct net_bridge *br,
struct
__port_info
p
;
struct
net_bridge_port
*
pt
;
read_lock
(
&
br
->
lock
);
if
((
pt
=
br_get_port
(
br
,
arg1
))
==
NULL
)
return
-
EINVAL
;
...
...
@@ -143,6 +152,8 @@ static int br_ioctl_device(struct net_bridge *br,
p
.
forward_delay_timer_value
=
br_timer_get_residue
(
&
pt
->
forward_delay_timer
);
p
.
hold_timer_value
=
br_timer_get_residue
(
&
pt
->
hold_timer
);
read_unlock
(
&
br
->
lock
);
if
(
copy_to_user
((
void
*
)
arg0
,
&
p
,
sizeof
(
p
)))
return
-
EFAULT
;
...
...
@@ -154,16 +165,20 @@ static int br_ioctl_device(struct net_bridge *br,
return
0
;
case
BRCTL_SET_BRIDGE_PRIORITY
:
write_lock
(
&
br
->
lock
);
br_stp_set_bridge_priority
(
br
,
arg0
);
write_unlock
(
&
br
->
lock
);
return
0
;
case
BRCTL_SET_PORT_PRIORITY
:
{
struct
net_bridge_port
*
p
;
write_lock
(
&
br
->
lock
);
if
((
p
=
br_get_port
(
br
,
arg0
))
==
NULL
)
return
-
EINVAL
;
br_stp_set_port_priority
(
p
,
arg1
);
write_unlock
(
&
br
->
lock
);
return
0
;
}
...
...
@@ -171,9 +186,11 @@ static int br_ioctl_device(struct net_bridge *br,
{
struct
net_bridge_port
*
p
;
write_lock
(
&
br
->
lock
);
if
((
p
=
br_get_port
(
br
,
arg0
))
==
NULL
)
return
-
EINVAL
;
br_stp_set_path_cost
(
p
,
arg1
);
write_unlock
(
&
br
->
lock
);
return
0
;
}
...
...
@@ -230,11 +247,9 @@ static int br_ioctl_deviceless(unsigned int cmd,
return
-
EOPNOTSUPP
;
}
static
DECLARE_MUTEX
(
ioctl_mutex
);
int
br_ioctl_deviceless_stub
(
unsigned
long
arg
)
{
int
err
;
unsigned
long
i
[
3
];
if
(
!
capable
(
CAP_NET_ADMIN
))
...
...
@@ -243,11 +258,7 @@ int br_ioctl_deviceless_stub(unsigned long arg)
if
(
copy_from_user
(
i
,
(
void
*
)
arg
,
3
*
sizeof
(
unsigned
long
)))
return
-
EFAULT
;
down
(
&
ioctl_mutex
);
err
=
br_ioctl_deviceless
(
i
[
0
],
i
[
1
],
i
[
2
]);
up
(
&
ioctl_mutex
);
return
err
;
return
br_ioctl_deviceless
(
i
[
0
],
i
[
1
],
i
[
2
]);
}
int
br_ioctl
(
struct
net_bridge
*
br
,
unsigned
int
cmd
,
unsigned
long
arg0
,
unsigned
long
arg1
,
unsigned
long
arg2
)
...
...
@@ -257,18 +268,9 @@ int br_ioctl(struct net_bridge *br, unsigned int cmd, unsigned long arg0, unsign
if
(
!
capable
(
CAP_NET_ADMIN
))
return
-
EPERM
;
down
(
&
ioctl_mutex
);
err
=
br_ioctl_deviceless
(
cmd
,
arg0
,
arg1
);
if
(
err
==
-
EOPNOTSUPP
)
err
=
br_ioctl_device
(
br
,
cmd
,
arg0
,
arg1
,
arg2
);
up
(
&
ioctl_mutex
);
return
err
;
}
void
br_call_ioctl_atomic
(
void
(
*
fn
)(
void
))
{
down
(
&
ioctl_mutex
);
fn
();
up
(
&
ioctl_mutex
);
}
net/bridge/br_notify.c
View file @
78d4faf7
...
...
@@ -21,15 +21,14 @@ static int br_device_event(struct notifier_block *unused, unsigned long event, v
struct
notifier_block
br_device_notifier
=
{
br_device_event
,
NULL
,
0
.
notifier_call
=
br_device_event
};
static
int
br_device_event
(
struct
notifier_block
*
unused
,
unsigned
long
event
,
void
*
ptr
)
{
struct
net_device
*
dev
;
struct
net_bridge_port
*
p
;
struct
net_bridge
*
br
;
dev
=
ptr
;
p
=
dev
->
br_port
;
...
...
@@ -37,13 +36,15 @@ static int br_device_event(struct notifier_block *unused, unsigned long event, v
if
(
p
==
NULL
)
return
NOTIFY_DONE
;
br
=
p
->
br
;
switch
(
event
)
{
case
NETDEV_CHANGEADDR
:
read_lock
(
&
p
->
br
->
lock
);
write_lock_bh
(
&
br
->
lock
);
br_fdb_changeaddr
(
p
,
dev
->
dev_addr
);
br_stp_recalculate_bridge_id
(
p
->
br
);
read_unlock
(
&
p
->
br
->
lock
);
br_stp_recalculate_bridge_id
(
br
);
write_unlock_bh
(
&
br
->
lock
);
break
;
case
NETDEV_GOING_DOWN
:
...
...
@@ -51,23 +52,23 @@ static int br_device_event(struct notifier_block *unused, unsigned long event, v
break
;
case
NETDEV_DOWN
:
if
(
p
->
br
->
dev
.
flags
&
IFF_UP
)
{
read_lock
(
&
p
->
br
->
lock
);
br_stp_disable_port
(
dev
->
br_port
);
read_unlock
(
&
p
->
br
->
lock
);
if
(
br
->
dev
.
flags
&
IFF_UP
)
{
write_lock_bh
(
&
br
->
lock
);
br_stp_disable_port
(
p
);
write_unlock_bh
(
&
br
->
lock
);
}
break
;
case
NETDEV_UP
:
if
(
p
->
br
->
dev
.
flags
&
IFF_UP
)
{
read_lock
(
&
p
->
br
->
lock
);
br_stp_enable_port
(
dev
->
br_port
);
read_unlock
(
&
p
->
br
->
lock
);
if
(
!
(
br
->
dev
.
flags
&
IFF_UP
)
)
{
write_lock_bh
(
&
br
->
lock
);
br_stp_enable_port
(
p
);
write_unlock_bh
(
&
br
->
lock
);
}
break
;
case
NETDEV_UNREGISTER
:
br_del_if
(
dev
->
br_port
->
br
,
dev
);
br_del_if
(
br
,
dev
);
break
;
}
...
...
net/core/dev.c
View file @
78d4faf7
...
...
@@ -1433,9 +1433,8 @@ static void net_tx_action(struct softirq_action *h)
}
}
#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
#if defined(CONFIG_BRIDGE) || defined
(CONFIG_BRIDGE_MODULE)
int
(
*
br_handle_frame_hook
)(
struct
sk_buff
*
skb
)
=
NULL
;
#endif
static
__inline__
int
handle_bridge
(
struct
sk_buff
*
skb
,
struct
packet_type
*
pt_prev
)
...
...
@@ -1454,6 +1453,7 @@ static __inline__ int handle_bridge(struct sk_buff *skb,
return
ret
;
}
#endif
#ifdef CONFIG_NET_DIVERT
static
inline
int
handle_diverter
(
struct
sk_buff
*
skb
)
...
...
@@ -1510,12 +1510,13 @@ int netif_receive_skb(struct sk_buff *skb)
#endif
/* CONFIG_NET_DIVERT */
#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
if
(
skb
->
dev
->
br_port
&&
br_handle_frame_hook
)
{
if
(
skb
->
dev
->
br_port
)
{
int
ret
;
ret
=
handle_bridge
(
skb
,
pt_prev
);
if
(
br_handle_frame_hook
(
skb
)
==
0
)
return
ret
;
pt_prev
=
NULL
;
}
#endif
...
...
net/ipv4/Kconfig
View file @
78d4faf7
...
...
@@ -362,5 +362,13 @@ config INET_ESP
If unsure, say Y.
config INET_IPCOMP
tristate "IP: IPComp transformation"
---help---
Support for IP Paylod Compression (RFC3173), typically needed
for IPsec.
If unsure, say Y.
source "net/ipv4/netfilter/Kconfig"
net/ipv4/Makefile
View file @
78d4faf7
...
...
@@ -18,6 +18,7 @@ obj-$(CONFIG_NET_IPGRE) += ip_gre.o
obj-$(CONFIG_SYN_COOKIES)
+=
syncookies.o
obj-$(CONFIG_INET_AH)
+=
ah.o
obj-$(CONFIG_INET_ESP)
+=
esp.o
obj-$(CONFIG_INET_IPCOMP)
+=
ipcomp.o
obj-$(CONFIG_IP_PNP)
+=
ipconfig.o
obj-$(CONFIG_NETFILTER)
+=
netfilter/
...
...
net/ipv4/igmp.c
View file @
78d4faf7
...
...
@@ -68,6 +68,8 @@
* Alan Cox: Forget to enable FDDI support earlier.
* Alexey Kuznetsov: Fixed leaving groups on device down.
* Alexey Kuznetsov: Accordance to igmp-v2-06 draft.
* David L Stevens: IGMPv3 support, with help from
* Vinay Kulkarni
*/
...
...
@@ -101,12 +103,10 @@
#define IP_MAX_MEMBERSHIPS 20
#ifdef CONFIG_IP_MULTICAST
/* Parameter names and values are taken from igmp-v2-06 draft */
#define IGMP_V1_Router_Present_Timeout (400*HZ)
#define IGMP_V2_Router_Present_Timeout (400*HZ)
#define IGMP_Unsolicited_Report_Interval (10*HZ)
#define IGMP_Query_Response_Interval (10*HZ)
#define IGMP_Unsolicited_Report_Count 2
...
...
@@ -121,9 +121,21 @@
* contradict to specs provided this delay is small enough.
*/
#define IGMP_V1_SEEN(in_dev) ((in_dev)->mr_v1_seen && (long)(jiffies - (in_dev)->mr_v1_seen) < 0)
#define IGMP_V1_SEEN(in_dev) ((in_dev)->mr_v1_seen && \
time_before(jiffies, (in_dev)->mr_v1_seen))
#define IGMP_V2_SEEN(in_dev) ((in_dev)->mr_v2_seen && \
time_before(jiffies, (in_dev)->mr_v2_seen))
#ifdef CONFIG_MULTICAST
static
void
igmpv3_add_delrec
(
struct
in_device
*
in_dev
,
struct
ip_mc_list
*
im
);
#endif
static
void
igmpv3_del_delrec
(
struct
in_device
*
in_dev
,
__u32
multiaddr
);
static
void
igmpv3_clear_delrec
(
struct
in_device
*
in_dev
);
static
int
sf_setstate
(
struct
ip_mc_list
*
pmc
);
static
void
sf_markstate
(
struct
ip_mc_list
*
pmc
);
static
void
ip_mc_clear_src
(
struct
ip_mc_list
*
pmc
);
int
ip_mc_add_src
(
struct
in_device
*
in_dev
,
__u32
*
pmca
,
int
sfmode
,
int
sfcount
,
__u32
*
psfsrc
,
int
delta
);
static
void
ip_ma_put
(
struct
ip_mc_list
*
im
)
{
...
...
@@ -160,6 +172,23 @@ static void igmp_start_timer(struct ip_mc_list *im, int max_delay)
atomic_inc
(
&
im
->
refcnt
);
}
static
void
igmp_gq_start_timer
(
struct
in_device
*
in_dev
)
{
int
tv
=
net_random
()
%
in_dev
->
mr_maxdelay
;
in_dev
->
mr_gq_running
=
1
;
if
(
!
mod_timer
(
&
in_dev
->
mr_gq_timer
,
jiffies
+
tv
+
2
))
atomic_inc
(
&
in_dev
->
refcnt
);
}
static
void
igmp_ifc_start_timer
(
struct
in_device
*
in_dev
,
int
delay
)
{
int
tv
=
net_random
()
%
delay
;
if
(
!
mod_timer
(
&
in_dev
->
mr_ifc_timer
,
jiffies
+
tv
+
2
))
atomic_inc
(
&
in_dev
->
refcnt
);
}
static
void
igmp_mod_timer
(
struct
ip_mc_list
*
im
,
int
max_delay
)
{
spin_lock_bh
(
&
im
->
lock
);
...
...
@@ -184,20 +213,396 @@ static void igmp_mod_timer(struct ip_mc_list *im, int max_delay)
#define IGMP_SIZE (sizeof(struct igmphdr)+sizeof(struct iphdr)+4)
static
int
igmp_send_report
(
struct
net_device
*
dev
,
u32
group
,
int
type
)
static
int
is_in
(
struct
ip_mc_list
*
pmc
,
struct
ip_sf_list
*
psf
,
int
type
,
int
gdeleted
,
int
sdeleted
)
{
switch
(
type
)
{
case
IGMPV3_MODE_IS_INCLUDE
:
case
IGMPV3_MODE_IS_EXCLUDE
:
if
(
gdeleted
||
sdeleted
)
return
0
;
return
!
(
pmc
->
gsquery
&&
!
psf
->
sf_gsresp
);
case
IGMPV3_CHANGE_TO_INCLUDE
:
if
(
gdeleted
||
sdeleted
)
return
0
;
return
psf
->
sf_count
[
MCAST_INCLUDE
]
!=
0
;
case
IGMPV3_CHANGE_TO_EXCLUDE
:
if
(
gdeleted
||
sdeleted
)
return
0
;
if
(
pmc
->
sfcount
[
MCAST_EXCLUDE
]
==
0
||
psf
->
sf_count
[
MCAST_INCLUDE
])
return
0
;
return
pmc
->
sfcount
[
MCAST_EXCLUDE
]
==
psf
->
sf_count
[
MCAST_EXCLUDE
];
case
IGMPV3_ALLOW_NEW_SOURCES
:
if
(
gdeleted
||
!
psf
->
sf_crcount
)
return
0
;
return
(
pmc
->
sfmode
==
MCAST_INCLUDE
)
^
sdeleted
;
case
IGMPV3_BLOCK_OLD_SOURCES
:
if
(
pmc
->
sfmode
==
MCAST_INCLUDE
)
return
gdeleted
||
(
psf
->
sf_crcount
&&
sdeleted
);
return
psf
->
sf_crcount
&&
!
gdeleted
&&
!
sdeleted
;
}
return
0
;
}
static
int
igmp_scount
(
struct
ip_mc_list
*
pmc
,
int
type
,
int
gdeleted
,
int
sdeleted
)
{
struct
ip_sf_list
*
psf
;
int
scount
=
0
;
for
(
psf
=
pmc
->
sources
;
psf
;
psf
=
psf
->
sf_next
)
{
if
(
!
is_in
(
pmc
,
psf
,
type
,
gdeleted
,
sdeleted
))
continue
;
scount
++
;
}
return
scount
;
}
static
struct
sk_buff
*
igmpv3_newpack
(
struct
net_device
*
dev
,
int
size
)
{
struct
sk_buff
*
skb
;
struct
rtable
*
rt
;
struct
iphdr
*
pip
;
struct
igmpv3_report
*
pig
;
skb
=
alloc_skb
(
size
+
dev
->
hard_header_len
+
15
,
GFP_ATOMIC
);
if
(
skb
==
NULL
)
return
0
;
{
struct
flowi
fl
=
{
.
oif
=
dev
->
ifindex
,
.
nl_u
=
{
.
ip4_u
=
{
.
daddr
=
IGMPV3_ALL_MCR
}
},
.
proto
=
IPPROTO_IGMP
};
if
(
ip_route_output_key
(
&
rt
,
&
fl
))
return
0
;
}
if
(
rt
->
rt_src
==
0
)
{
ip_rt_put
(
rt
);
return
0
;
}
skb
->
dst
=
&
rt
->
u
.
dst
;
skb
->
dev
=
dev
;
skb_reserve
(
skb
,
(
dev
->
hard_header_len
+
15
)
&~
15
);
skb
->
nh
.
iph
=
pip
=
(
struct
iphdr
*
)
skb_put
(
skb
,
sizeof
(
struct
iphdr
)
+
4
);
pip
->
version
=
4
;
pip
->
ihl
=
(
sizeof
(
struct
iphdr
)
+
4
)
>>
2
;
pip
->
tos
=
0xc0
;
pip
->
frag_off
=
htons
(
IP_DF
);
pip
->
ttl
=
1
;
pip
->
daddr
=
rt
->
rt_dst
;
pip
->
saddr
=
rt
->
rt_src
;
pip
->
protocol
=
IPPROTO_IGMP
;
pip
->
tot_len
=
0
;
/* filled in later */
ip_select_ident
(
pip
,
&
rt
->
u
.
dst
,
NULL
);
((
u8
*
)
&
pip
[
1
])[
0
]
=
IPOPT_RA
;
((
u8
*
)
&
pip
[
1
])[
1
]
=
4
;
((
u8
*
)
&
pip
[
1
])[
2
]
=
0
;
((
u8
*
)
&
pip
[
1
])[
3
]
=
0
;
pig
=
(
struct
igmpv3_report
*
)
skb_put
(
skb
,
sizeof
(
*
pig
));
skb
->
h
.
igmph
=
(
struct
igmphdr
*
)
pig
;
pig
->
type
=
IGMPV3_HOST_MEMBERSHIP_REPORT
;
pig
->
resv1
=
0
;
pig
->
csum
=
0
;
pig
->
resv2
=
0
;
pig
->
ngrec
=
0
;
return
skb
;
}
static
int
igmpv3_sendpack
(
struct
sk_buff
*
skb
)
{
struct
iphdr
*
pip
=
skb
->
nh
.
iph
;
struct
igmphdr
*
pig
=
skb
->
h
.
igmph
;
int
iplen
,
igmplen
;
iplen
=
skb
->
tail
-
(
unsigned
char
*
)
skb
->
nh
.
iph
;
pip
->
tot_len
=
htons
(
iplen
);
ip_send_check
(
pip
);
igmplen
=
skb
->
tail
-
(
unsigned
char
*
)
skb
->
h
.
igmph
;
pig
->
csum
=
ip_compute_csum
((
void
*
)
skb
->
h
.
igmph
,
igmplen
);
return
NF_HOOK
(
PF_INET
,
NF_IP_LOCAL_OUT
,
skb
,
NULL
,
skb
->
dev
,
dst_output
);
}
static
int
grec_size
(
struct
ip_mc_list
*
pmc
,
int
type
,
int
gdel
,
int
sdel
)
{
return
sizeof
(
struct
igmpv3_grec
)
+
4
*
igmp_scount
(
pmc
,
type
,
gdel
,
sdel
);
}
static
struct
sk_buff
*
add_grhead
(
struct
sk_buff
*
skb
,
struct
ip_mc_list
*
pmc
,
int
type
,
struct
igmpv3_grec
**
ppgr
)
{
struct
net_device
*
dev
=
pmc
->
interface
->
dev
;
struct
igmpv3_report
*
pih
;
struct
igmpv3_grec
*
pgr
;
if
(
!
skb
)
skb
=
igmpv3_newpack
(
dev
,
dev
->
mtu
);
if
(
!
skb
)
return
0
;
pgr
=
(
struct
igmpv3_grec
*
)
skb_put
(
skb
,
sizeof
(
struct
igmpv3_grec
));
pgr
->
grec_type
=
type
;
pgr
->
grec_auxwords
=
0
;
pgr
->
grec_nsrcs
=
0
;
pgr
->
grec_mca
=
pmc
->
multiaddr
;
pih
=
(
struct
igmpv3_report
*
)
skb
->
h
.
igmph
;
pih
->
ngrec
=
htons
(
ntohs
(
pih
->
ngrec
)
+
1
);
*
ppgr
=
pgr
;
return
skb
;
}
#define AVAILABLE(skb) ((skb) ? ((skb)->dev ? (skb)->dev->mtu - (skb)->len : \
skb_tailroom(skb)) : 0)
static
struct
sk_buff
*
add_grec
(
struct
sk_buff
*
skb
,
struct
ip_mc_list
*
pmc
,
int
type
,
int
gdeleted
,
int
sdeleted
)
{
struct
net_device
*
dev
=
pmc
->
interface
->
dev
;
struct
igmpv3_report
*
pih
;
struct
igmpv3_grec
*
pgr
=
0
;
struct
ip_sf_list
*
psf
,
*
psf_next
,
*
psf_prev
,
*
psf_list
;
int
scount
,
first
,
isquery
,
truncate
;
if
(
pmc
->
multiaddr
==
IGMP_ALL_HOSTS
)
return
skb
;
isquery
=
type
==
IGMPV3_MODE_IS_INCLUDE
||
type
==
IGMPV3_MODE_IS_EXCLUDE
;
truncate
=
type
==
IGMPV3_MODE_IS_EXCLUDE
||
type
==
IGMPV3_CHANGE_TO_EXCLUDE
;
psf_list
=
sdeleted
?
pmc
->
tomb
:
pmc
->
sources
;
if
(
!
psf_list
)
{
if
(
type
==
IGMPV3_ALLOW_NEW_SOURCES
||
type
==
IGMPV3_BLOCK_OLD_SOURCES
)
return
skb
;
if
(
pmc
->
crcount
||
isquery
)
skb
=
add_grhead
(
skb
,
pmc
,
type
,
&
pgr
);
return
skb
;
}
pih
=
skb
?
(
struct
igmpv3_report
*
)
skb
->
h
.
igmph
:
0
;
/* EX and TO_EX get a fresh packet, if needed */
if
(
truncate
)
{
if
(
pih
&&
pih
->
ngrec
&&
AVAILABLE
(
skb
)
<
grec_size
(
pmc
,
type
,
gdeleted
,
sdeleted
))
{
if
(
skb
)
igmpv3_sendpack
(
skb
);
skb
=
igmpv3_newpack
(
dev
,
dev
->
mtu
);
}
}
first
=
1
;
scount
=
0
;
psf_prev
=
0
;
for
(
psf
=
psf_list
;
psf
;
psf
=
psf_next
)
{
u32
*
psrc
;
psf_next
=
psf
->
sf_next
;
if
(
!
is_in
(
pmc
,
psf
,
type
,
gdeleted
,
sdeleted
))
{
psf_prev
=
psf
;
continue
;
}
/* clear marks on query responses */
if
(
isquery
)
psf
->
sf_gsresp
=
0
;
if
(
AVAILABLE
(
skb
)
<
sizeof
(
u32
)
+
first
*
sizeof
(
struct
igmpv3_grec
))
{
if
(
truncate
&&
!
first
)
break
;
/* truncate these */
if
(
pgr
)
pgr
->
grec_nsrcs
=
htons
(
scount
);
if
(
skb
)
igmpv3_sendpack
(
skb
);
skb
=
igmpv3_newpack
(
dev
,
dev
->
mtu
);
first
=
1
;
scount
=
0
;
}
if
(
first
)
{
skb
=
add_grhead
(
skb
,
pmc
,
type
,
&
pgr
);
first
=
0
;
}
psrc
=
(
u32
*
)
skb_put
(
skb
,
sizeof
(
u32
));
*
psrc
=
psf
->
sf_inaddr
;
scount
++
;
if
((
type
==
IGMPV3_ALLOW_NEW_SOURCES
||
type
==
IGMPV3_BLOCK_OLD_SOURCES
)
&&
psf
->
sf_crcount
)
{
psf
->
sf_crcount
--
;
if
((
sdeleted
||
gdeleted
)
&&
psf
->
sf_crcount
==
0
)
{
if
(
psf_prev
)
psf_prev
->
sf_next
=
psf
->
sf_next
;
else
pmc
->
tomb
=
psf
->
sf_next
;
kfree
(
psf
);
continue
;
}
}
psf_prev
=
psf
;
}
if
(
pgr
)
pgr
->
grec_nsrcs
=
htons
(
scount
);
if
(
isquery
)
pmc
->
gsquery
=
0
;
/* clear query state on report */
return
skb
;
}
static
int
igmpv3_send_report
(
struct
in_device
*
in_dev
,
struct
ip_mc_list
*
pmc
)
{
struct
sk_buff
*
skb
=
0
;
int
type
;
if
(
!
pmc
)
{
read_lock
(
&
in_dev
->
lock
);
for
(
pmc
=
in_dev
->
mc_list
;
pmc
;
pmc
=
pmc
->
next
)
{
if
(
pmc
->
multiaddr
==
IGMP_ALL_HOSTS
)
continue
;
spin_lock_bh
(
&
pmc
->
lock
);
if
(
pmc
->
sfcount
[
MCAST_EXCLUDE
])
type
=
IGMPV3_MODE_IS_EXCLUDE
;
else
type
=
IGMPV3_MODE_IS_INCLUDE
;
skb
=
add_grec
(
skb
,
pmc
,
type
,
0
,
0
);
spin_unlock_bh
(
&
pmc
->
lock
);
}
read_unlock
(
&
in_dev
->
lock
);
}
else
{
spin_lock_bh
(
&
pmc
->
lock
);
if
(
pmc
->
sfcount
[
MCAST_EXCLUDE
])
type
=
IGMPV3_MODE_IS_EXCLUDE
;
else
type
=
IGMPV3_MODE_IS_INCLUDE
;
skb
=
add_grec
(
skb
,
pmc
,
type
,
0
,
0
);
spin_unlock_bh
(
&
pmc
->
lock
);
}
if
(
!
skb
)
return
0
;
return
igmpv3_sendpack
(
skb
);
}
/*
* remove zero-count source records from a source filter list
*/
static
void
igmpv3_clear_zeros
(
struct
ip_sf_list
**
ppsf
)
{
struct
ip_sf_list
*
psf_prev
,
*
psf_next
,
*
psf
;
psf_prev
=
0
;
for
(
psf
=*
ppsf
;
psf
;
psf
=
psf_next
)
{
psf_next
=
psf
->
sf_next
;
if
(
psf
->
sf_crcount
==
0
)
{
if
(
psf_prev
)
psf_prev
->
sf_next
=
psf
->
sf_next
;
else
*
ppsf
=
psf
->
sf_next
;
kfree
(
psf
);
}
else
psf_prev
=
psf
;
}
}
static
void
igmpv3_send_cr
(
struct
in_device
*
in_dev
)
{
struct
ip_mc_list
*
pmc
,
*
pmc_prev
,
*
pmc_next
;
struct
sk_buff
*
skb
=
0
;
int
type
,
dtype
;
read_lock
(
&
in_dev
->
lock
);
write_lock_bh
(
&
in_dev
->
mc_lock
);
/* deleted MCA's */
pmc_prev
=
0
;
for
(
pmc
=
in_dev
->
mc_tomb
;
pmc
;
pmc
=
pmc_next
)
{
pmc_next
=
pmc
->
next
;
if
(
pmc
->
sfmode
==
MCAST_INCLUDE
)
{
type
=
IGMPV3_BLOCK_OLD_SOURCES
;
dtype
=
IGMPV3_BLOCK_OLD_SOURCES
;
skb
=
add_grec
(
skb
,
pmc
,
type
,
1
,
0
);
skb
=
add_grec
(
skb
,
pmc
,
dtype
,
1
,
1
);
}
if
(
pmc
->
crcount
)
{
pmc
->
crcount
--
;
if
(
pmc
->
sfmode
==
MCAST_EXCLUDE
)
{
type
=
IGMPV3_CHANGE_TO_INCLUDE
;
skb
=
add_grec
(
skb
,
pmc
,
type
,
1
,
0
);
}
if
(
pmc
->
crcount
==
0
)
{
igmpv3_clear_zeros
(
&
pmc
->
tomb
);
igmpv3_clear_zeros
(
&
pmc
->
sources
);
}
}
if
(
pmc
->
crcount
==
0
&&
!
pmc
->
tomb
&&
!
pmc
->
sources
)
{
if
(
pmc_prev
)
pmc_prev
->
next
=
pmc_next
;
else
in_dev
->
mc_tomb
=
pmc_next
;
in_dev_put
(
pmc
->
interface
);
kfree
(
pmc
);
}
else
pmc_prev
=
pmc
;
}
write_unlock_bh
(
&
in_dev
->
mc_lock
);
/* change recs */
for
(
pmc
=
in_dev
->
mc_list
;
pmc
;
pmc
=
pmc
->
next
)
{
spin_lock_bh
(
&
pmc
->
lock
);
if
(
pmc
->
sfcount
[
MCAST_EXCLUDE
])
{
type
=
IGMPV3_BLOCK_OLD_SOURCES
;
dtype
=
IGMPV3_ALLOW_NEW_SOURCES
;
}
else
{
type
=
IGMPV3_ALLOW_NEW_SOURCES
;
dtype
=
IGMPV3_BLOCK_OLD_SOURCES
;
}
skb
=
add_grec
(
skb
,
pmc
,
type
,
0
,
0
);
skb
=
add_grec
(
skb
,
pmc
,
dtype
,
0
,
1
);
/* deleted sources */
/* filter mode changes */
if
(
pmc
->
crcount
)
{
pmc
->
crcount
--
;
if
(
pmc
->
sfmode
==
MCAST_EXCLUDE
)
type
=
IGMPV3_CHANGE_TO_EXCLUDE
;
else
type
=
IGMPV3_CHANGE_TO_INCLUDE
;
skb
=
add_grec
(
skb
,
pmc
,
type
,
0
,
0
);
}
spin_unlock_bh
(
&
pmc
->
lock
);
}
read_unlock
(
&
in_dev
->
lock
);
if
(
!
skb
)
return
;
(
void
)
igmpv3_sendpack
(
skb
);
}
static
int
igmp_send_report
(
struct
in_device
*
in_dev
,
struct
ip_mc_list
*
pmc
,
int
type
)
{
struct
sk_buff
*
skb
;
struct
iphdr
*
iph
;
struct
igmphdr
*
ih
;
struct
rtable
*
rt
;
struct
net_device
*
dev
=
in_dev
->
dev
;
u32
group
=
pmc
?
pmc
->
multiaddr
:
0
;
u32
dst
;
/* According to IGMPv2 specs, LEAVE messages are
* sent to all-routers group.
*/
dst
=
group
;
if
(
type
==
IGMP_HOST_LEAVE_MESSAGE
)
if
(
type
==
IGMPV3_HOST_MEMBERSHIP_REPORT
)
return
igmpv3_send_report
(
in_dev
,
pmc
);
else
if
(
type
==
IGMP_HOST_LEAVE_MESSAGE
)
dst
=
IGMP_ALL_ROUTER
;
else
dst
=
group
;
{
struct
flowi
fl
=
{
.
oif
=
dev
->
ifindex
,
...
...
@@ -225,7 +630,7 @@ static int igmp_send_report(struct net_device *dev, u32 group, int type)
iph
->
version
=
4
;
iph
->
ihl
=
(
sizeof
(
struct
iphdr
)
+
4
)
>>
2
;
iph
->
tos
=
0
;
iph
->
tos
=
0
xc0
;
iph
->
frag_off
=
htons
(
IP_DF
);
iph
->
ttl
=
1
;
iph
->
daddr
=
dst
;
...
...
@@ -250,6 +655,34 @@ static int igmp_send_report(struct net_device *dev, u32 group, int type)
dst_output
);
}
static
void
igmp_gq_timer_expire
(
unsigned
long
data
)
{
struct
in_device
*
in_dev
=
(
struct
in_device
*
)
data
;
in_dev
->
mr_gq_running
=
0
;
igmpv3_send_report
(
in_dev
,
0
);
}
static
void
igmp_ifc_timer_expire
(
unsigned
long
data
)
{
struct
in_device
*
in_dev
=
(
struct
in_device
*
)
data
;
igmpv3_send_cr
(
in_dev
);
if
(
in_dev
->
mr_ifc_count
)
{
in_dev
->
mr_ifc_count
--
;
igmp_ifc_start_timer
(
in_dev
,
IGMP_Unsolicited_Report_Interval
);
}
}
static
void
igmp_ifc_event
(
struct
in_device
*
in_dev
)
{
if
(
IGMP_V1_SEEN
(
in_dev
)
||
IGMP_V2_SEEN
(
in_dev
))
return
;
in_dev
->
mr_ifc_count
=
in_dev
->
mr_qrv
?
in_dev
->
mr_qrv
:
IGMP_Unsolicited_Report_Count
;
igmp_ifc_start_timer
(
in_dev
,
1
);
}
static
void
igmp_timer_expire
(
unsigned
long
data
)
{
...
...
@@ -267,13 +700,33 @@ static void igmp_timer_expire(unsigned long data)
spin_unlock
(
&
im
->
lock
);
if
(
IGMP_V1_SEEN
(
in_dev
))
igmp_send_report
(
in_dev
->
dev
,
im
->
multiaddr
,
IGMP_HOST_MEMBERSHIP_REPORT
);
igmp_send_report
(
in_dev
,
im
,
IGMP_HOST_MEMBERSHIP_REPORT
);
else
if
(
IGMP_V2_SEEN
(
in_dev
))
igmp_send_report
(
in_dev
,
im
,
IGMPV2_HOST_MEMBERSHIP_REPORT
);
else
igmp_send_report
(
in_dev
->
dev
,
im
->
multiaddr
,
IGMP_HOST_NEW
_MEMBERSHIP_REPORT
);
igmp_send_report
(
in_dev
,
im
,
IGMPV3_HOST
_MEMBERSHIP_REPORT
);
ip_ma_put
(
im
);
}
static
void
igmp_marksources
(
struct
ip_mc_list
*
pmc
,
int
nsrcs
,
__u32
*
srcs
)
{
struct
ip_sf_list
*
psf
;
int
i
,
scount
;
scount
=
0
;
for
(
psf
=
pmc
->
sources
;
psf
;
psf
=
psf
->
sf_next
)
{
if
(
scount
==
nsrcs
)
break
;
for
(
i
=
0
;
i
<
nsrcs
;
i
++
)
if
(
srcs
[
i
]
==
psf
->
sf_inaddr
)
{
psf
->
sf_gsresp
=
1
;
scount
++
;
break
;
}
}
}
static
void
igmp_heard_report
(
struct
in_device
*
in_dev
,
u32
group
)
{
struct
ip_mc_list
*
im
;
...
...
@@ -293,20 +746,46 @@ static void igmp_heard_report(struct in_device *in_dev, u32 group)
read_unlock
(
&
in_dev
->
lock
);
}
static
void
igmp_heard_query
(
struct
in_device
*
in_dev
,
unsigned
char
max_resp_time
,
u32
group
)
static
void
igmp_heard_query
(
struct
in_device
*
in_dev
,
struct
igmphdr
*
ih
,
int
len
)
{
struct
igmpv3_query
*
ih3
=
(
struct
igmpv3_query
*
)
ih
;
struct
ip_mc_list
*
im
;
u32
group
=
ih
->
group
;
int
max_delay
;
int
mark
=
0
;
max_delay
=
max_resp_time
*
(
HZ
/
IGMP_TIMER_SCALE
);
if
(
max_resp_time
==
0
)
{
if
(
len
==
8
)
{
if
(
ih
->
code
==
0
)
{
/* Alas, old v1 router presents here. */
max_delay
=
IGMP_Query_Response_Interval
;
in_dev
->
mr_v1_seen
=
jiffies
+
IGMP_V1_Router_Present_Timeout
;
in_dev
->
mr_v1_seen
=
jiffies
+
IGMP_V1_Router_Present_Timeout
;
group
=
0
;
}
else
{
/* v2 router present */
max_delay
=
ih
->
code
*
(
HZ
/
IGMP_TIMER_SCALE
);
in_dev
->
mr_v2_seen
=
jiffies
+
IGMP_V2_Router_Present_Timeout
;
}
igmpv3_clear_delrec
(
in_dev
);
}
else
if
(
len
<
12
)
{
return
;
/* ignore bogus packet; freed by caller */
}
else
{
/* v3 */
max_delay
=
IGMPV3_MRC
(
ih3
->
code
)
*
(
HZ
/
IGMP_TIMER_SCALE
);
in_dev
->
mr_maxdelay
=
max_delay
;
if
(
ih3
->
qrv
)
in_dev
->
mr_qrv
=
ih3
->
qrv
;
if
(
!
group
)
{
/* general query */
if
(
ih3
->
nsrcs
)
return
;
/* no sources allowed */
igmp_gq_start_timer
(
in_dev
);
return
;
}
/* mark sources to include, if group & source-specific */
mark
=
ih3
->
nsrcs
!=
0
;
}
/*
...
...
@@ -325,6 +804,14 @@ static void igmp_heard_query(struct in_device *in_dev, unsigned char max_resp_ti
continue
;
if
(
im
->
multiaddr
==
IGMP_ALL_HOSTS
)
continue
;
spin_lock_bh
(
&
im
->
lock
);
if
(
im
->
tm_running
)
im
->
gsquery
=
im
->
gsquery
&&
mark
;
else
im
->
gsquery
=
mark
;
if
(
im
->
gsquery
)
igmp_marksources
(
im
,
ntohs
(
ih3
->
nsrcs
),
ih3
->
srcs
);
spin_unlock_bh
(
&
im
->
lock
);
igmp_mod_timer
(
im
,
max_delay
);
}
read_unlock
(
&
in_dev
->
lock
);
...
...
@@ -358,10 +845,11 @@ int igmp_rcv(struct sk_buff *skb)
switch
(
ih
->
type
)
{
case
IGMP_HOST_MEMBERSHIP_QUERY
:
igmp_heard_query
(
in_dev
,
ih
->
code
,
ih
->
group
);
igmp_heard_query
(
in_dev
,
ih
,
len
);
break
;
case
IGMP_HOST_MEMBERSHIP_REPORT
:
case
IGMP_HOST_NEW_MEMBERSHIP_REPORT
:
case
IGMPV2_HOST_MEMBERSHIP_REPORT
:
case
IGMPV3_HOST_MEMBERSHIP_REPORT
:
/* Is it our report looped back? */
if
(((
struct
rtable
*
)
skb
->
dst
)
->
fl
.
iif
==
0
)
break
;
...
...
@@ -422,15 +910,105 @@ static void ip_mc_filter_del(struct in_device *in_dev, u32 addr)
dev_mc_delete
(
dev
,
buf
,
dev
->
addr_len
,
0
);
}
#ifdef CONFIG_IP_MULTICAST
/*
* deleted ip_mc_list manipulation
*/
static
void
igmpv3_add_delrec
(
struct
in_device
*
in_dev
,
struct
ip_mc_list
*
im
)
{
struct
ip_mc_list
*
pmc
;
/* this is an "ip_mc_list" for convenience; only the fields below
* are actually used. In particular, the refcnt and users are not
* used for management of the delete list. Using the same structure
* for deleted items allows change reports to use common code with
* non-deleted or query-response MCA's.
*/
pmc
=
(
struct
ip_mc_list
*
)
kmalloc
(
sizeof
(
*
pmc
),
GFP_KERNEL
);
if
(
!
pmc
)
return
;
memset
(
pmc
,
0
,
sizeof
(
*
pmc
));
spin_lock_bh
(
&
im
->
lock
);
pmc
->
interface
=
im
->
interface
;
in_dev_hold
(
in_dev
);
pmc
->
multiaddr
=
im
->
multiaddr
;
pmc
->
crcount
=
in_dev
->
mr_qrv
?
in_dev
->
mr_qrv
:
IGMP_Unsolicited_Report_Count
;
pmc
->
sfmode
=
im
->
sfmode
;
if
(
pmc
->
sfmode
==
MCAST_INCLUDE
)
{
struct
ip_sf_list
*
psf
;
pmc
->
tomb
=
im
->
tomb
;
pmc
->
sources
=
im
->
sources
;
im
->
tomb
=
im
->
sources
=
0
;
for
(
psf
=
pmc
->
sources
;
psf
;
psf
=
psf
->
sf_next
)
psf
->
sf_crcount
=
pmc
->
crcount
;
}
spin_unlock_bh
(
&
im
->
lock
);
write_lock_bh
(
&
in_dev
->
mc_lock
);
pmc
->
next
=
in_dev
->
mc_tomb
;
in_dev
->
mc_tomb
=
pmc
;
write_unlock_bh
(
&
in_dev
->
mc_lock
);
}
#endif
static
void
igmpv3_del_delrec
(
struct
in_device
*
in_dev
,
__u32
multiaddr
)
{
struct
ip_mc_list
*
pmc
,
*
pmc_prev
;
struct
ip_sf_list
*
psf
,
*
psf_next
;
write_lock_bh
(
&
in_dev
->
mc_lock
);
pmc_prev
=
0
;
for
(
pmc
=
in_dev
->
mc_tomb
;
pmc
;
pmc
=
pmc
->
next
)
{
if
(
pmc
->
multiaddr
==
multiaddr
)
break
;
pmc_prev
=
pmc
;
}
if
(
pmc
)
{
if
(
pmc_prev
)
pmc_prev
->
next
=
pmc
->
next
;
else
in_dev
->
mc_tomb
=
pmc
->
next
;
}
write_unlock_bh
(
&
in_dev
->
mc_lock
);
if
(
pmc
)
{
for
(
psf
=
pmc
->
tomb
;
psf
;
psf
=
psf_next
)
{
psf_next
=
psf
->
sf_next
;
kfree
(
psf
);
}
in_dev_put
(
pmc
->
interface
);
kfree
(
pmc
);
}
}
static
void
igmpv3_clear_delrec
(
struct
in_device
*
in_dev
)
{
struct
ip_mc_list
*
pmc
,
*
nextpmc
;
write_lock_bh
(
&
in_dev
->
mc_lock
);
pmc
=
in_dev
->
mc_tomb
;
in_dev
->
mc_tomb
=
0
;
write_unlock_bh
(
&
in_dev
->
mc_lock
);
for
(;
pmc
;
pmc
=
nextpmc
)
{
nextpmc
=
pmc
->
next
;
ip_mc_clear_src
(
pmc
);
in_dev_put
(
pmc
->
interface
);
kfree
(
pmc
);
}
}
static
void
igmp_group_dropped
(
struct
ip_mc_list
*
im
)
{
struct
in_device
*
in_dev
=
im
->
interface
;
#ifdef CONFIG_IP_MULTICAST
int
reporter
;
#endif
if
(
im
->
loaded
)
{
im
->
loaded
=
0
;
ip_mc_filter_del
(
i
m
->
interface
,
im
->
multiaddr
);
ip_mc_filter_del
(
i
n_dev
,
im
->
multiaddr
);
}
#ifdef CONFIG_IP_MULTICAST
...
...
@@ -440,25 +1018,46 @@ static void igmp_group_dropped(struct ip_mc_list *im)
reporter
=
im
->
reporter
;
igmp_stop_timer
(
im
);
if
(
reporter
&&
!
IGMP_V1_SEEN
(
im
->
interface
))
igmp_send_report
(
im
->
interface
->
dev
,
im
->
multiaddr
,
IGMP_HOST_LEAVE_MESSAGE
);
if
(
IGMP_V1_SEEN
(
in_dev
))
goto
done
;
if
(
IGMP_V2_SEEN
(
in_dev
))
{
if
(
reporter
)
igmp_send_report
(
in_dev
,
im
,
IGMP_HOST_LEAVE_MESSAGE
);
goto
done
;
}
/* IGMPv3 */
igmpv3_add_delrec
(
in_dev
,
im
);
igmp_ifc_event
(
in_dev
);
done:
ip_mc_clear_src
(
im
);
#endif
}
static
void
igmp_group_added
(
struct
ip_mc_list
*
im
)
{
struct
in_device
*
in_dev
=
im
->
interface
;
if
(
im
->
loaded
==
0
)
{
im
->
loaded
=
1
;
ip_mc_filter_add
(
i
m
->
interface
,
im
->
multiaddr
);
ip_mc_filter_add
(
i
n_dev
,
im
->
multiaddr
);
}
#ifdef CONFIG_IP_MULTICAST
if
(
im
->
multiaddr
==
IGMP_ALL_HOSTS
)
return
;
if
(
IGMP_V1_SEEN
(
in_dev
)
||
IGMP_V2_SEEN
(
in_dev
))
{
spin_lock_bh
(
&
im
->
lock
);
igmp_start_timer
(
im
,
IGMP_Initial_Report_Delay
);
spin_unlock_bh
(
&
im
->
lock
);
return
;
}
/* else, v3 */
im
->
crcount
=
in_dev
->
mr_qrv
?
in_dev
->
mr_qrv
:
IGMP_Unsolicited_Report_Count
;
igmp_ifc_event
(
in_dev
);
#endif
}
...
...
@@ -481,6 +1080,7 @@ void ip_mc_inc_group(struct in_device *in_dev, u32 addr)
for
(
im
=
in_dev
->
mc_list
;
im
;
im
=
im
->
next
)
{
if
(
im
->
multiaddr
==
addr
)
{
im
->
users
++
;
ip_mc_add_src
(
in_dev
,
&
addr
,
MCAST_EXCLUDE
,
0
,
0
,
0
);
goto
out
;
}
}
...
...
@@ -493,6 +1093,13 @@ void ip_mc_inc_group(struct in_device *in_dev, u32 addr)
im
->
interface
=
in_dev
;
in_dev_hold
(
in_dev
);
im
->
multiaddr
=
addr
;
/* initial mode is (EX, empty) */
im
->
sfmode
=
MCAST_EXCLUDE
;
im
->
sfcount
[
MCAST_INCLUDE
]
=
0
;
im
->
sfcount
[
MCAST_EXCLUDE
]
=
1
;
im
->
sources
=
0
;
im
->
tomb
=
0
;
im
->
crcount
=
0
;
atomic_set
(
&
im
->
refcnt
,
1
);
spin_lock_init
(
&
im
->
lock
);
#ifdef CONFIG_IP_MULTICAST
...
...
@@ -502,12 +1109,14 @@ void ip_mc_inc_group(struct in_device *in_dev, u32 addr)
im
->
timer
.
function
=&
igmp_timer_expire
;
im
->
unsolicit_count
=
IGMP_Unsolicited_Report_Count
;
im
->
reporter
=
0
;
im
->
gsquery
=
0
;
#endif
im
->
loaded
=
0
;
write_lock_bh
(
&
in_dev
->
lock
);
im
->
next
=
in_dev
->
mc_list
;
in_dev
->
mc_list
=
im
;
write_unlock_bh
(
&
in_dev
->
lock
);
igmpv3_del_delrec
(
in_dev
,
im
->
multiaddr
);
igmp_group_added
(
im
);
if
(
in_dev
->
dev
->
flags
&
IFF_UP
)
ip_rt_multicast_event
(
in_dev
);
...
...
@@ -552,9 +1161,18 @@ void ip_mc_down(struct in_device *in_dev)
ASSERT_RTNL
();
in_dev
->
mr_ifc_count
=
0
;
if
(
del_timer
(
&
in_dev
->
mr_ifc_timer
))
atomic_dec
(
&
in_dev
->
refcnt
);
in_dev
->
mr_gq_running
=
0
;
if
(
del_timer
(
&
in_dev
->
mr_gq_timer
))
atomic_dec
(
&
in_dev
->
refcnt
);
for
(
i
=
in_dev
->
mc_list
;
i
;
i
=
i
->
next
)
igmp_group_dropped
(
i
);
igmpv3_clear_delrec
(
in_dev
);
ip_mc_dec_group
(
in_dev
,
IGMP_ALL_HOSTS
);
}
...
...
@@ -566,6 +1184,20 @@ void ip_mc_up(struct in_device *in_dev)
ASSERT_RTNL
();
#ifdef CONFIG_IP_MULTICAST
in_dev
->
mc_lock
=
RW_LOCK_UNLOCKED
;
in_dev
->
mr_gq_running
=
0
;
init_timer
(
&
in_dev
->
mr_gq_timer
);
in_dev
->
mr_gq_timer
.
data
=
(
unsigned
long
)
in_dev
;
in_dev
->
mr_gq_timer
.
function
=&
igmp_gq_timer_expire
;
in_dev
->
mc_tomb
=
0
;
in_dev
->
mr_ifc_count
=
0
;
init_timer
(
&
in_dev
->
mr_ifc_timer
);
in_dev
->
mr_ifc_timer
.
data
=
(
unsigned
long
)
in_dev
;
in_dev
->
mr_ifc_timer
.
function
=&
igmp_ifc_timer_expire
;
in_dev
->
mr_qrv
=
IGMP_Unsolicited_Report_Count
;
#endif
ip_mc_inc_group
(
in_dev
,
IGMP_ALL_HOSTS
);
for
(
i
=
in_dev
->
mc_list
;
i
;
i
=
i
->
next
)
...
...
@@ -626,6 +1258,262 @@ static struct in_device * ip_mc_find_dev(struct ip_mreqn *imr)
*/
int
sysctl_igmp_max_memberships
=
IP_MAX_MEMBERSHIPS
;
static
int
ip_mc_del1_src
(
struct
ip_mc_list
*
pmc
,
int
sfmode
,
__u32
*
psfsrc
)
{
struct
ip_sf_list
*
psf
,
*
psf_prev
;
int
rv
=
0
;
psf_prev
=
0
;
for
(
psf
=
pmc
->
sources
;
psf
;
psf
=
psf
->
sf_next
)
{
if
(
psf
->
sf_inaddr
==
*
psfsrc
)
break
;
psf_prev
=
psf
;
}
if
(
!
psf
||
psf
->
sf_count
[
sfmode
]
==
0
)
{
/* source filter not found, or count wrong => bug */
return
-
ESRCH
;
}
psf
->
sf_count
[
sfmode
]
--
;
if
(
psf
->
sf_count
[
sfmode
]
==
0
)
{
ip_rt_multicast_event
(
pmc
->
interface
);
}
if
(
!
psf
->
sf_count
[
MCAST_INCLUDE
]
&&
!
psf
->
sf_count
[
MCAST_EXCLUDE
])
{
struct
in_device
*
in_dev
=
pmc
->
interface
;
/* no more filters for this source */
if
(
psf_prev
)
psf_prev
->
sf_next
=
psf
->
sf_next
;
else
pmc
->
sources
=
psf
->
sf_next
;
if
(
psf
->
sf_oldin
&&
!
IGMP_V1_SEEN
(
in_dev
)
&&
!
IGMP_V2_SEEN
(
in_dev
))
{
psf
->
sf_crcount
=
in_dev
->
mr_qrv
?
in_dev
->
mr_qrv
:
IGMP_Unsolicited_Report_Count
;
psf
->
sf_next
=
pmc
->
tomb
;
pmc
->
tomb
=
psf
;
rv
=
1
;
}
else
kfree
(
psf
);
}
return
rv
;
}
#ifndef CONFIG_IP_MULTICAST
#define igmp_ifc_event(x) do { } while (0)
#endif
int
ip_mc_del_src
(
struct
in_device
*
in_dev
,
__u32
*
pmca
,
int
sfmode
,
int
sfcount
,
__u32
*
psfsrc
,
int
delta
)
{
struct
ip_mc_list
*
pmc
;
int
changerec
=
0
;
int
i
,
err
;
if
(
!
in_dev
)
return
-
ENODEV
;
read_lock
(
&
in_dev
->
lock
);
for
(
pmc
=
in_dev
->
mc_list
;
pmc
;
pmc
=
pmc
->
next
)
{
if
(
*
pmca
==
pmc
->
multiaddr
)
break
;
}
if
(
!
pmc
)
{
/* MCA not found?? bug */
read_unlock
(
&
in_dev
->
lock
);
return
-
ESRCH
;
}
spin_lock_bh
(
&
pmc
->
lock
);
read_unlock
(
&
in_dev
->
lock
);
sf_markstate
(
pmc
);
if
(
!
delta
)
{
if
(
!
pmc
->
sfcount
[
sfmode
])
return
-
EINVAL
;
pmc
->
sfcount
[
sfmode
]
--
;
}
err
=
0
;
for
(
i
=
0
;
i
<
sfcount
;
i
++
)
{
int
rv
=
ip_mc_del1_src
(
pmc
,
sfmode
,
&
psfsrc
[
i
]);
changerec
|=
rv
>
0
;
if
(
!
err
&&
rv
<
0
)
err
=
rv
;
}
if
(
pmc
->
sfmode
==
MCAST_EXCLUDE
&&
pmc
->
sfcount
[
MCAST_EXCLUDE
]
==
0
&&
pmc
->
sfcount
[
MCAST_INCLUDE
])
{
struct
ip_sf_list
*
psf
;
/* filter mode change */
pmc
->
sfmode
=
MCAST_INCLUDE
;
pmc
->
crcount
=
in_dev
->
mr_qrv
?
in_dev
->
mr_qrv
:
IGMP_Unsolicited_Report_Count
;
in_dev
->
mr_ifc_count
=
pmc
->
crcount
;
for
(
psf
=
pmc
->
sources
;
psf
;
psf
=
psf
->
sf_next
)
psf
->
sf_crcount
=
0
;
igmp_ifc_event
(
pmc
->
interface
);
}
else
if
(
sf_setstate
(
pmc
)
||
changerec
)
{
igmp_ifc_event
(
pmc
->
interface
);
}
spin_unlock_bh
(
&
pmc
->
lock
);
return
err
;
}
/*
* Add multicast single-source filter to the interface list
*/
static
int
ip_mc_add1_src
(
struct
ip_mc_list
*
pmc
,
int
sfmode
,
__u32
*
psfsrc
,
int
delta
)
{
struct
ip_sf_list
*
psf
,
*
psf_prev
;
psf_prev
=
0
;
for
(
psf
=
pmc
->
sources
;
psf
;
psf
=
psf
->
sf_next
)
{
if
(
psf
->
sf_inaddr
==
*
psfsrc
)
break
;
psf_prev
=
psf
;
}
if
(
!
psf
)
{
psf
=
(
struct
ip_sf_list
*
)
kmalloc
(
sizeof
(
*
psf
),
GFP_ATOMIC
);
if
(
!
psf
)
return
-
ENOBUFS
;
memset
(
psf
,
0
,
sizeof
(
*
psf
));
psf
->
sf_inaddr
=
*
psfsrc
;
if
(
psf_prev
)
{
psf_prev
->
sf_next
=
psf
;
}
else
pmc
->
sources
=
psf
;
}
psf
->
sf_count
[
sfmode
]
++
;
if
(
psf
->
sf_count
[
sfmode
]
==
1
)
{
ip_rt_multicast_event
(
pmc
->
interface
);
}
return
0
;
}
static
void
sf_markstate
(
struct
ip_mc_list
*
pmc
)
{
struct
ip_sf_list
*
psf
;
int
mca_xcount
=
pmc
->
sfcount
[
MCAST_EXCLUDE
];
for
(
psf
=
pmc
->
sources
;
psf
;
psf
=
psf
->
sf_next
)
if
(
pmc
->
sfcount
[
MCAST_EXCLUDE
])
{
psf
->
sf_oldin
=
mca_xcount
==
psf
->
sf_count
[
MCAST_EXCLUDE
]
&&
!
psf
->
sf_count
[
MCAST_INCLUDE
];
}
else
psf
->
sf_oldin
=
psf
->
sf_count
[
MCAST_INCLUDE
]
!=
0
;
}
static
int
sf_setstate
(
struct
ip_mc_list
*
pmc
)
{
struct
ip_sf_list
*
psf
;
int
mca_xcount
=
pmc
->
sfcount
[
MCAST_EXCLUDE
];
int
qrv
=
pmc
->
interface
->
mr_qrv
;
int
new_in
,
rv
;
rv
=
0
;
for
(
psf
=
pmc
->
sources
;
psf
;
psf
=
psf
->
sf_next
)
{
if
(
pmc
->
sfcount
[
MCAST_EXCLUDE
])
{
new_in
=
mca_xcount
==
psf
->
sf_count
[
MCAST_EXCLUDE
]
&&
!
psf
->
sf_count
[
MCAST_INCLUDE
];
}
else
new_in
=
psf
->
sf_count
[
MCAST_INCLUDE
]
!=
0
;
if
(
new_in
!=
psf
->
sf_oldin
)
{
psf
->
sf_crcount
=
qrv
;
rv
++
;
}
}
return
rv
;
}
/*
* Add multicast source filter list to the interface list
*/
int
ip_mc_add_src
(
struct
in_device
*
in_dev
,
__u32
*
pmca
,
int
sfmode
,
int
sfcount
,
__u32
*
psfsrc
,
int
delta
)
{
struct
ip_mc_list
*
pmc
;
int
isexclude
;
int
i
,
err
;
if
(
!
in_dev
)
return
-
ENODEV
;
read_lock
(
&
in_dev
->
lock
);
for
(
pmc
=
in_dev
->
mc_list
;
pmc
;
pmc
=
pmc
->
next
)
{
if
(
*
pmca
==
pmc
->
multiaddr
)
break
;
}
if
(
!
pmc
)
{
/* MCA not found?? bug */
read_unlock
(
&
in_dev
->
lock
);
return
-
ESRCH
;
}
spin_lock_bh
(
&
pmc
->
lock
);
read_unlock
(
&
in_dev
->
lock
);
sf_markstate
(
pmc
);
isexclude
=
pmc
->
sfmode
==
MCAST_EXCLUDE
;
if
(
!
delta
)
pmc
->
sfcount
[
sfmode
]
++
;
err
=
0
;
for
(
i
=
0
;
i
<
sfcount
;
i
++
)
{
err
=
ip_mc_add1_src
(
pmc
,
sfmode
,
&
psfsrc
[
i
],
delta
);
if
(
err
)
break
;
}
if
(
err
)
{
int
j
;
pmc
->
sfcount
[
sfmode
]
--
;
for
(
j
=
0
;
j
<
i
;
j
++
)
(
void
)
ip_mc_del1_src
(
pmc
,
sfmode
,
&
psfsrc
[
i
]);
}
else
if
(
isexclude
!=
(
pmc
->
sfcount
[
MCAST_EXCLUDE
]
!=
0
))
{
struct
in_device
*
in_dev
=
pmc
->
interface
;
struct
ip_sf_list
*
psf
;
/* filter mode change */
if
(
pmc
->
sfcount
[
MCAST_EXCLUDE
])
pmc
->
sfmode
=
MCAST_EXCLUDE
;
else
if
(
pmc
->
sfcount
[
MCAST_INCLUDE
])
pmc
->
sfmode
=
MCAST_INCLUDE
;
/* else no filters; keep old mode for reports */
pmc
->
crcount
=
in_dev
->
mr_qrv
?
in_dev
->
mr_qrv
:
IGMP_Unsolicited_Report_Count
;
in_dev
->
mr_ifc_count
=
pmc
->
crcount
;
for
(
psf
=
pmc
->
sources
;
psf
;
psf
=
psf
->
sf_next
)
psf
->
sf_crcount
=
0
;
igmp_ifc_event
(
in_dev
);
}
else
if
(
sf_setstate
(
pmc
))
igmp_ifc_event
(
in_dev
);
spin_unlock_bh
(
&
pmc
->
lock
);
return
err
;
}
static
void
ip_mc_clear_src
(
struct
ip_mc_list
*
pmc
)
{
struct
ip_sf_list
*
psf
,
*
nextpsf
;
for
(
psf
=
pmc
->
tomb
;
psf
;
psf
=
nextpsf
)
{
nextpsf
=
psf
->
sf_next
;
kfree
(
psf
);
}
pmc
->
tomb
=
0
;
for
(
psf
=
pmc
->
sources
;
psf
;
psf
=
nextpsf
)
{
nextpsf
=
psf
->
sf_next
;
kfree
(
psf
);
}
pmc
->
sources
=
0
;
pmc
->
sfmode
=
MCAST_EXCLUDE
;
pmc
->
sfcount
[
MCAST_EXCLUDE
]
=
0
;
pmc
->
sfcount
[
MCAST_EXCLUDE
]
=
1
;
}
/*
* Join a multicast group
*/
int
ip_mc_join_group
(
struct
sock
*
sk
,
struct
ip_mreqn
*
imr
)
{
int
err
;
...
...
@@ -674,6 +1562,8 @@ int ip_mc_join_group(struct sock *sk , struct ip_mreqn *imr)
memcpy
(
&
iml
->
multi
,
imr
,
sizeof
(
*
imr
));
iml
->
next
=
inet
->
mc_list
;
iml
->
count
=
1
;
iml
->
sflist
=
NULL
;
iml
->
sfmode
=
MCAST_EXCLUDE
;
inet
->
mc_list
=
iml
;
ip_mc_inc_group
(
in_dev
,
addr
);
iml
=
NULL
;
...
...
@@ -686,6 +1576,24 @@ int ip_mc_join_group(struct sock *sk , struct ip_mreqn *imr)
return
err
;
}
int
ip_mc_leave_src
(
struct
sock
*
sk
,
struct
ip_mc_socklist
*
iml
,
struct
in_device
*
in_dev
)
{
int
err
;
if
(
iml
->
sflist
==
0
)
{
/* any-source empty exclude case */
return
ip_mc_del_src
(
in_dev
,
&
iml
->
multi
.
imr_multiaddr
.
s_addr
,
iml
->
sfmode
,
0
,
0
,
0
);
}
err
=
ip_mc_del_src
(
in_dev
,
&
iml
->
multi
.
imr_multiaddr
.
s_addr
,
iml
->
sfmode
,
iml
->
sflist
->
sl_count
,
iml
->
sflist
->
sl_addr
,
0
);
sock_kfree_s
(
sk
,
iml
->
sflist
,
IP_SFLSIZE
(
iml
->
sflist
->
sl_max
));
iml
->
sflist
=
0
;
return
err
;
}
/*
* Ask a socket to leave a group.
*/
...
...
@@ -701,14 +1609,19 @@ int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr)
iml
->
multi
.
imr_address
.
s_addr
==
imr
->
imr_address
.
s_addr
&&
(
!
imr
->
imr_ifindex
||
iml
->
multi
.
imr_ifindex
==
imr
->
imr_ifindex
))
{
struct
in_device
*
in_dev
;
in_dev
=
inetdev_by_index
(
iml
->
multi
.
imr_ifindex
);
if
(
in_dev
)
(
void
)
ip_mc_leave_src
(
sk
,
iml
,
in_dev
);
if
(
--
iml
->
count
)
{
rtnl_unlock
();
if
(
in_dev
)
in_dev_put
(
in_dev
);
return
0
;
}
*
imlp
=
iml
->
next
;
in_dev
=
inetdev_by_index
(
iml
->
multi
.
imr_ifindex
);
if
(
in_dev
)
{
ip_mc_dec_group
(
in_dev
,
imr
->
imr_multiaddr
.
s_addr
);
in_dev_put
(
in_dev
);
...
...
@@ -722,6 +1635,283 @@ int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr)
return
-
EADDRNOTAVAIL
;
}
int
ip_mc_source
(
int
add
,
int
omode
,
struct
sock
*
sk
,
struct
ip_mreq_source
*
mreqs
)
{
int
err
;
struct
ip_mreqn
imr
;
u32
addr
=
mreqs
->
imr_multiaddr
;
struct
ip_mc_socklist
*
pmc
;
struct
in_device
*
in_dev
;
struct
inet_opt
*
inet
=
inet_sk
(
sk
);
struct
ip_sf_socklist
*
psl
;
int
i
,
j
,
rv
;
if
(
!
MULTICAST
(
addr
))
return
-
EINVAL
;
rtnl_shlock
();
imr
.
imr_multiaddr
.
s_addr
=
mreqs
->
imr_multiaddr
;
imr
.
imr_address
.
s_addr
=
mreqs
->
imr_interface
;
imr
.
imr_ifindex
=
0
;
in_dev
=
ip_mc_find_dev
(
&
imr
);
if
(
!
in_dev
)
{
err
=
-
ENODEV
;
goto
done
;
}
err
=
-
EADDRNOTAVAIL
;
for
(
pmc
=
inet
->
mc_list
;
pmc
;
pmc
=
pmc
->
next
)
{
if
(
memcmp
(
&
pmc
->
multi
,
mreqs
,
2
*
sizeof
(
__u32
))
==
0
)
break
;
}
if
(
!
pmc
)
/* must have a prior join */
goto
done
;
/* if a source filter was set, must be the same mode as before */
if
(
pmc
->
sflist
)
{
if
(
pmc
->
sfmode
!=
omode
)
goto
done
;
}
else
if
(
pmc
->
sfmode
!=
omode
)
{
/* allow mode switches for empty-set filters */
ip_mc_del_src
(
in_dev
,
&
mreqs
->
imr_multiaddr
,
pmc
->
sfmode
,
0
,
0
,
0
);
pmc
->
sfmode
=
omode
;
ip_mc_add_src
(
in_dev
,
&
mreqs
->
imr_multiaddr
,
pmc
->
sfmode
,
0
,
0
,
0
);
}
psl
=
pmc
->
sflist
;
if
(
!
add
)
{
if
(
!
psl
)
goto
done
;
rv
=
!
0
;
for
(
i
=
0
;
i
<
psl
->
sl_count
;
i
++
)
{
rv
=
memcmp
(
&
psl
->
sl_addr
,
&
mreqs
->
imr_multiaddr
,
sizeof
(
__u32
));
if
(
rv
>=
0
)
break
;
}
if
(
!
rv
)
/* source not found */
goto
done
;
/* update the interface filter */
ip_mc_del_src
(
in_dev
,
&
mreqs
->
imr_multiaddr
,
omode
,
1
,
&
mreqs
->
imr_sourceaddr
,
1
);
for
(
j
=
i
+
1
;
j
<
psl
->
sl_count
;
j
++
)
psl
->
sl_addr
[
j
-
1
]
=
psl
->
sl_addr
[
j
];
psl
->
sl_count
--
;
err
=
0
;
goto
done
;
}
/* else, add a new source to the filter */
if
(
!
psl
||
psl
->
sl_count
==
psl
->
sl_max
)
{
struct
ip_sf_socklist
*
newpsl
;
int
count
=
IP_SFBLOCK
;
if
(
psl
)
count
+=
psl
->
sl_max
;
newpsl
=
(
struct
ip_sf_socklist
*
)
sock_kmalloc
(
sk
,
IP_SFLSIZE
(
count
),
GFP_KERNEL
);
if
(
!
newpsl
)
{
err
=
-
ENOBUFS
;
goto
done
;
}
newpsl
->
sl_max
=
count
;
newpsl
->
sl_count
=
count
-
IP_SFBLOCK
;
if
(
psl
)
{
for
(
i
=
0
;
i
<
psl
->
sl_count
;
i
++
)
newpsl
->
sl_addr
[
i
]
=
psl
->
sl_addr
[
i
];
sock_kfree_s
(
sk
,
psl
,
IP_SFLSIZE
(
psl
->
sl_max
));
}
pmc
->
sflist
=
psl
=
newpsl
;
}
rv
=
1
;
/* > 0 for insert logic below if sl_count is 0 */
for
(
i
=
0
;
i
<
psl
->
sl_count
;
i
++
)
{
rv
=
memcmp
(
&
psl
->
sl_addr
,
&
mreqs
->
imr_multiaddr
,
sizeof
(
__u32
));
if
(
rv
>=
0
)
break
;
}
if
(
rv
==
0
)
/* address already there is an error */
goto
done
;
for
(
j
=
psl
->
sl_count
-
1
;
j
>=
i
;
j
--
)
psl
->
sl_addr
[
j
+
1
]
=
psl
->
sl_addr
[
j
];
psl
->
sl_addr
[
i
]
=
mreqs
->
imr_sourceaddr
;
psl
->
sl_count
++
;
err
=
0
;
/* update the interface list */
ip_mc_add_src
(
in_dev
,
&
mreqs
->
imr_multiaddr
,
omode
,
1
,
&
mreqs
->
imr_sourceaddr
,
1
);
done:
rtnl_shunlock
();
return
err
;
}
int
ip_mc_msfilter
(
struct
sock
*
sk
,
struct
ip_msfilter
*
msf
)
{
int
err
;
struct
ip_mreqn
imr
;
u32
addr
=
msf
->
imsf_multiaddr
;
struct
ip_mc_socklist
*
pmc
;
struct
in_device
*
in_dev
;
struct
inet_opt
*
inet
=
inet_sk
(
sk
);
struct
ip_sf_socklist
*
newpsl
,
*
psl
;
if
(
!
MULTICAST
(
addr
))
return
-
EINVAL
;
if
(
msf
->
imsf_fmode
!=
MCAST_INCLUDE
&&
msf
->
imsf_fmode
!=
MCAST_EXCLUDE
)
return
-
EINVAL
;
rtnl_shlock
();
imr
.
imr_multiaddr
.
s_addr
=
msf
->
imsf_multiaddr
;
imr
.
imr_address
.
s_addr
=
msf
->
imsf_interface
;
imr
.
imr_ifindex
=
0
;
in_dev
=
ip_mc_find_dev
(
&
imr
);
if
(
!
in_dev
)
{
err
=
-
ENODEV
;
goto
done
;
}
err
=
-
EADDRNOTAVAIL
;
for
(
pmc
=
inet
->
mc_list
;
pmc
;
pmc
=
pmc
->
next
)
{
if
(
memcmp
(
&
pmc
->
multi
,
&
imr
,
sizeof
(
imr
))
==
0
)
break
;
}
if
(
!
pmc
)
/* must have a prior join */
goto
done
;
if
(
msf
->
imsf_numsrc
)
{
newpsl
=
(
struct
ip_sf_socklist
*
)
sock_kmalloc
(
sk
,
IP_SFLSIZE
(
msf
->
imsf_numsrc
),
GFP_KERNEL
);
if
(
!
newpsl
)
{
err
=
-
ENOBUFS
;
goto
done
;
}
newpsl
->
sl_max
=
newpsl
->
sl_count
=
msf
->
imsf_numsrc
;
memcpy
(
newpsl
->
sl_addr
,
msf
->
imsf_slist
,
msf
->
imsf_numsrc
*
sizeof
(
msf
->
imsf_slist
[
0
]));
err
=
ip_mc_add_src
(
in_dev
,
&
msf
->
imsf_multiaddr
,
msf
->
imsf_fmode
,
newpsl
->
sl_count
,
newpsl
->
sl_addr
,
0
);
if
(
err
)
{
sock_kfree_s
(
sk
,
newpsl
,
IP_SFLSIZE
(
newpsl
->
sl_max
));
goto
done
;
}
}
else
newpsl
=
0
;
psl
=
pmc
->
sflist
;
if
(
psl
)
{
(
void
)
ip_mc_del_src
(
in_dev
,
&
msf
->
imsf_multiaddr
,
pmc
->
sfmode
,
psl
->
sl_count
,
psl
->
sl_addr
,
0
);
sock_kfree_s
(
sk
,
psl
,
IP_SFLSIZE
(
psl
->
sl_max
));
}
else
(
void
)
ip_mc_del_src
(
in_dev
,
&
msf
->
imsf_multiaddr
,
pmc
->
sfmode
,
0
,
0
,
0
);
pmc
->
sflist
=
newpsl
;
pmc
->
sfmode
=
msf
->
imsf_fmode
;
done:
rtnl_shunlock
();
return
err
;
}
int
ip_mc_msfget
(
struct
sock
*
sk
,
struct
ip_msfilter
*
msf
,
struct
ip_msfilter
*
optval
,
int
*
optlen
)
{
int
err
,
len
,
count
,
copycount
;
struct
ip_mreqn
imr
;
u32
addr
=
msf
->
imsf_multiaddr
;
struct
ip_mc_socklist
*
pmc
;
struct
in_device
*
in_dev
;
struct
inet_opt
*
inet
=
inet_sk
(
sk
);
struct
ip_sf_socklist
*
psl
;
if
(
!
MULTICAST
(
addr
))
return
-
EINVAL
;
if
(
msf
->
imsf_fmode
!=
MCAST_INCLUDE
&&
msf
->
imsf_fmode
!=
MCAST_EXCLUDE
)
return
-
EINVAL
;
rtnl_shlock
();
imr
.
imr_multiaddr
.
s_addr
=
msf
->
imsf_multiaddr
;
imr
.
imr_address
.
s_addr
=
msf
->
imsf_interface
;
imr
.
imr_ifindex
=
0
;
in_dev
=
ip_mc_find_dev
(
&
imr
);
if
(
!
in_dev
)
{
err
=
-
ENODEV
;
goto
done
;
}
err
=
-
EADDRNOTAVAIL
;
for
(
pmc
=
inet
->
mc_list
;
pmc
;
pmc
=
pmc
->
next
)
{
if
(
memcmp
(
&
pmc
->
multi
,
&
imr
,
sizeof
(
imr
))
==
0
)
break
;
}
if
(
!
pmc
)
/* must have a prior join */
goto
done
;
msf
->
imsf_fmode
=
pmc
->
sfmode
;
psl
=
pmc
->
sflist
;
rtnl_shunlock
();
if
(
!
psl
)
{
len
=
0
;
count
=
0
;
}
else
{
count
=
psl
->
sl_count
;
}
copycount
=
count
<
msf
->
imsf_numsrc
?
count
:
msf
->
imsf_numsrc
;
len
=
copycount
*
sizeof
(
psl
->
sl_addr
[
0
]);
msf
->
imsf_numsrc
=
count
;
if
(
put_user
(
IP_MSFILTER_SIZE
(
copycount
),
optlen
)
||
copy_to_user
((
void
*
)
optval
,
msf
,
IP_MSFILTER_SIZE
(
0
)))
{
return
-
EFAULT
;
}
if
(
len
&&
copy_to_user
((
void
*
)
&
optval
->
imsf_slist
[
0
],
psl
->
sl_addr
,
len
))
return
-
EFAULT
;
return
0
;
done:
rtnl_shunlock
();
return
err
;
}
/*
* check if a multicast source filter allows delivery for a given <src,dst,intf>
*/
int
ip_mc_sf_allow
(
struct
sock
*
sk
,
u32
loc_addr
,
u32
rmt_addr
,
int
dif
)
{
struct
inet_opt
*
inet
=
inet_sk
(
sk
);
struct
ip_mc_socklist
*
pmc
;
struct
ip_sf_socklist
*
psl
;
int
i
;
for
(
pmc
=
inet
->
mc_list
;
pmc
;
pmc
=
pmc
->
next
)
{
if
(
pmc
->
multi
.
imr_multiaddr
.
s_addr
==
loc_addr
&&
pmc
->
multi
.
imr_ifindex
==
dif
)
break
;
}
if
(
!
pmc
)
return
0
;
psl
=
pmc
->
sflist
;
if
(
!
psl
)
return
pmc
->
sfmode
==
MCAST_EXCLUDE
;
for
(
i
=
0
;
i
<
psl
->
sl_count
;
i
++
)
{
if
(
psl
->
sl_addr
[
i
]
==
rmt_addr
)
break
;
}
if
(
pmc
->
sfmode
==
MCAST_INCLUDE
&&
i
<
psl
->
sl_count
)
return
1
;
if
(
pmc
->
sfmode
==
MCAST_EXCLUDE
&&
i
>=
psl
->
sl_count
)
return
1
;
return
0
;
}
/*
* A socket is closing.
*/
...
...
@@ -740,6 +1930,7 @@ void ip_mc_drop_socket(struct sock *sk)
inet
->
mc_list
=
iml
->
next
;
if
((
in_dev
=
inetdev_by_index
(
iml
->
multi
.
imr_ifindex
))
!=
NULL
)
{
(
void
)
ip_mc_leave_src
(
sk
,
iml
,
in_dev
);
ip_mc_dec_group
(
in_dev
,
iml
->
multi
.
imr_multiaddr
.
s_addr
);
in_dev_put
(
in_dev
);
}
...
...
@@ -749,19 +1940,33 @@ void ip_mc_drop_socket(struct sock *sk)
rtnl_unlock
();
}
int
ip_check_mc
(
struct
in_device
*
in_dev
,
u32
mc_addr
)
int
ip_check_mc
(
struct
in_device
*
in_dev
,
u32
mc_addr
,
u32
src_addr
,
u16
proto
)
{
struct
ip_mc_list
*
im
;
struct
ip_sf_list
*
psf
;
int
rv
=
0
;
read_lock
(
&
in_dev
->
lock
);
for
(
im
=
in_dev
->
mc_list
;
im
;
im
=
im
->
next
)
{
if
(
im
->
multiaddr
==
mc_addr
)
{
read_unlock
(
&
in_dev
->
lock
);
return
1
;
if
(
im
->
multiaddr
==
mc_addr
)
break
;
}
if
(
im
&&
proto
==
IPPROTO_IGMP
)
{
rv
=
1
;
}
else
if
(
im
)
{
for
(
psf
=
im
->
sources
;
psf
;
psf
=
psf
->
sf_next
)
{
if
(
psf
->
sf_inaddr
==
src_addr
)
break
;
}
if
(
psf
)
rv
=
psf
->
sf_count
[
MCAST_INCLUDE
]
||
psf
->
sf_count
[
MCAST_EXCLUDE
]
!=
im
->
sfcount
[
MCAST_EXCLUDE
];
else
rv
=
im
->
sfcount
[
MCAST_EXCLUDE
]
!=
0
;
}
read_unlock
(
&
in_dev
->
lock
);
return
0
;
return
rv
;
}
...
...
@@ -822,5 +2027,101 @@ int ip_mc_procinfo(char *buffer, char **start, off_t offset, int length)
len
=
0
;
return
len
;
}
int
ip_mcf_procinfo
(
char
*
buffer
,
char
**
start
,
off_t
offset
,
int
length
)
{
off_t
pos
=
0
,
begin
=
0
;
int
len
=
0
;
int
first
=
1
;
struct
net_device
*
dev
;
read_lock
(
&
dev_base_lock
);
for
(
dev
=
dev_base
;
dev
;
dev
=
dev
->
next
)
{
struct
in_device
*
in_dev
=
in_dev_get
(
dev
);
struct
ip_mc_list
*
imc
;
if
(
in_dev
==
NULL
)
continue
;
read_lock
(
&
in_dev
->
lock
);
for
(
imc
=
in_dev
->
mc_list
;
imc
;
imc
=
imc
->
next
)
{
struct
ip_sf_list
*
psf
;
unsigned
long
icount
,
xcount
;
spin_lock_bh
(
&
imc
->
lock
);
icount
=
imc
->
sfcount
[
MCAST_INCLUDE
];
xcount
=
imc
->
sfcount
[
MCAST_EXCLUDE
];
for
(
psf
=
imc
->
sources
;
psf
;
psf
=
psf
->
sf_next
)
{
if
(
first
)
{
len
+=
sprintf
(
buffer
+
len
,
"%3s %6s "
"%10s %10s %6s %6s
\n
"
,
"Idx"
,
"Device"
,
"MCA"
,
"SRC"
,
"INC"
,
"EXC"
);
first
=
0
;
}
len
+=
sprintf
(
buffer
+
len
,
"%3d %6.6s 0x%08x "
"0x%08x %6lu %6lu
\n
"
,
dev
->
ifindex
,
dev
->
name
,
ntohl
(
imc
->
multiaddr
),
ntohl
(
psf
->
sf_inaddr
),
psf
->
sf_count
[
MCAST_INCLUDE
],
psf
->
sf_count
[
MCAST_EXCLUDE
]);
pos
=
begin
+
len
;
if
(
pos
<
offset
)
{
len
=
0
;
begin
=
pos
;
}
if
(
pos
>
offset
+
length
)
{
spin_unlock_bh
(
&
imc
->
lock
);
read_unlock
(
&
in_dev
->
lock
);
in_dev_put
(
in_dev
);
goto
done
;
}
icount
-=
psf
->
sf_count
[
MCAST_INCLUDE
];
xcount
-=
psf
->
sf_count
[
MCAST_EXCLUDE
];
}
if
(
icount
>
0
||
xcount
>
0
)
{
if
(
first
)
{
len
+=
sprintf
(
buffer
+
len
,
"%3s %6s "
"%10s %10s %6s %6s
\n
"
,
"Idx"
,
"Device"
,
"MCA"
,
"SRC"
,
"INC"
,
"EXC"
);
first
=
0
;
}
len
+=
sprintf
(
buffer
+
len
,
"%3d %6.6s 0x%08x "
"%10s %6lu %6lu
\n
"
,
dev
->
ifindex
,
dev
->
name
,
ntohl
(
imc
->
multiaddr
),
"NONE"
,
icount
,
xcount
);
pos
=
begin
+
len
;
if
(
pos
<
offset
)
{
len
=
0
;
begin
=
pos
;
}
if
(
pos
>
offset
+
length
)
{
spin_unlock_bh
(
&
imc
->
lock
);
read_unlock
(
&
in_dev
->
lock
);
in_dev_put
(
in_dev
);
goto
done
;
}
}
spin_unlock_bh
(
&
imc
->
lock
);
}
read_unlock
(
&
in_dev
->
lock
);
in_dev_put
(
in_dev
);
}
done:
read_unlock
(
&
dev_base_lock
);
*
start
=
buffer
+
(
offset
-
begin
);
len
-=
(
offset
-
begin
);
if
(
len
>
length
)
len
=
length
;
if
(
len
<
0
)
len
=
0
;
return
len
;
}
#endif
net/ipv4/ip_output.c
View file @
78d4faf7
...
...
@@ -1312,5 +1312,6 @@ void __init ip_init(void)
#ifdef CONFIG_IP_MULTICAST
proc_net_create
(
"igmp"
,
0
,
ip_mc_procinfo
);
proc_net_create
(
"mcfilter"
,
0
,
ip_mcf_procinfo
);
#endif
}
net/ipv4/ip_sockglue.c
View file @
78d4faf7
...
...
@@ -610,9 +610,67 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int opt
}
if
(
optname
==
IP_ADD_MEMBERSHIP
)
err
=
ip_mc_join_group
(
sk
,
&
mreq
);
err
=
ip_mc_join_group
(
sk
,
&
mreq
);
else
err
=
ip_mc_leave_group
(
sk
,
&
mreq
);
err
=
ip_mc_leave_group
(
sk
,
&
mreq
);
break
;
}
case
IP_MSFILTER
:
{
struct
ip_msfilter
*
msf
;
if
(
optlen
<
IP_MSFILTER_SIZE
(
0
))
goto
e_inval
;
msf
=
(
struct
ip_msfilter
*
)
kmalloc
(
optlen
,
GFP_KERNEL
);
if
(
msf
==
0
)
{
err
=
-
ENOBUFS
;
break
;
}
err
=
-
EFAULT
;
if
(
copy_from_user
(
msf
,
optval
,
optlen
))
{
kfree
(
msf
);
break
;
}
err
=
ip_mc_msfilter
(
sk
,
msf
);
kfree
(
msf
);
break
;
}
case
IP_BLOCK_SOURCE
:
case
IP_UNBLOCK_SOURCE
:
case
IP_ADD_SOURCE_MEMBERSHIP
:
case
IP_DROP_SOURCE_MEMBERSHIP
:
{
struct
ip_mreq_source
mreqs
;
int
omode
,
add
;
if
(
optlen
!=
sizeof
(
struct
ip_mreq_source
))
goto
e_inval
;
if
(
copy_from_user
(
&
mreqs
,
optval
,
sizeof
(
mreqs
)))
{
err
=
-
EFAULT
;
break
;
}
if
(
optname
==
IP_BLOCK_SOURCE
)
{
omode
=
MCAST_EXCLUDE
;
add
=
1
;
}
else
if
(
optname
==
IP_UNBLOCK_SOURCE
)
{
omode
=
MCAST_EXCLUDE
;
add
=
0
;
}
else
if
(
optname
==
IP_ADD_SOURCE_MEMBERSHIP
)
{
struct
ip_mreqn
mreq
;
mreq
.
imr_multiaddr
.
s_addr
=
mreqs
.
imr_multiaddr
;
mreq
.
imr_address
.
s_addr
=
mreqs
.
imr_interface
;
mreq
.
imr_ifindex
=
0
;
err
=
ip_mc_join_group
(
sk
,
&
mreq
);
if
(
err
)
break
;
omode
=
MCAST_INCLUDE
;
add
=
1
;
}
else
/*IP_DROP_SOURCE_MEMBERSHIP */
{
omode
=
MCAST_INCLUDE
;
add
=
0
;
}
err
=
ip_mc_source
(
add
,
omode
,
sk
,
&
mreqs
);
break
;
}
case
IP_ROUTER_ALERT
:
...
...
@@ -763,6 +821,20 @@ int ip_getsockopt(struct sock *sk, int level, int optname, char *optval, int *op
return
-
EFAULT
;
return
0
;
}
case
IP_MSFILTER
:
{
struct
ip_msfilter
msf
;
int
err
;
if
(
len
<
IP_MSFILTER_SIZE
(
0
))
return
-
EINVAL
;
if
(
copy_from_user
(
&
msf
,
optval
,
IP_MSFILTER_SIZE
(
0
)))
return
-
EFAULT
;
err
=
ip_mc_msfget
(
sk
,
&
msf
,
(
struct
ip_msfilter
*
)
optval
,
optlen
);
release_sock
(
sk
);
return
err
;
}
case
IP_PKTOPTIONS
:
{
struct
msghdr
msg
;
...
...
net/ipv4/ipcomp.c
0 → 100644
View file @
78d4faf7
/*
* IP Payload Compression Protocol (IPComp) - RFC3713.
*
* Copyright (c) 2003 James Morris <jmorris@intercode.com.au>
*
* 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.
*
* Todo:
* - Tunable compression parameters.
* - Compression stats.
* - Adaptive compression.
*/
#include <linux/config.h>
#include <linux/module.h>
#include <asm/scatterlist.h>
#include <linux/crypto.h>
#include <linux/pfkeyv2.h>
#include <net/ip.h>
#include <net/xfrm.h>
#include <net/icmp.h>
#include <net/esp.h>
#define IPCOMP_SCRATCH_SIZE 65400
struct
ipcomp_hdr
{
u8
nexthdr
;
u8
flags
;
u16
cpi
;
};
struct
ipcomp_data
{
u16
threshold
;
u8
*
scratch
;
struct
crypto_tfm
*
tfm
;
};
static
int
ipcomp_decompress
(
struct
xfrm_state
*
x
,
struct
sk_buff
*
skb
)
{
int
err
,
plen
,
dlen
;
struct
iphdr
*
iph
;
struct
ipcomp_data
*
ipcd
=
x
->
data
;
u8
*
start
,
*
scratch
=
ipcd
->
scratch
;
plen
=
skb
->
len
;
dlen
=
IPCOMP_SCRATCH_SIZE
;
start
=
skb
->
data
;
err
=
crypto_comp_decompress
(
ipcd
->
tfm
,
start
,
plen
,
scratch
,
&
dlen
);
if
(
err
)
goto
out
;
if
(
dlen
<
(
plen
+
sizeof
(
struct
ipcomp_hdr
)))
{
err
=
-
EINVAL
;
goto
out
;
}
err
=
pskb_expand_head
(
skb
,
0
,
dlen
-
plen
,
GFP_ATOMIC
);
if
(
err
)
goto
out
;
skb_put
(
skb
,
dlen
-
plen
);
memcpy
(
skb
->
data
,
scratch
,
dlen
);
iph
=
skb
->
nh
.
iph
;
iph
->
tot_len
=
htons
(
dlen
+
iph
->
ihl
*
4
);
out:
return
err
;
}
static
int
ipcomp_input
(
struct
xfrm_state
*
x
,
struct
xfrm_decap_state
*
decap
,
struct
sk_buff
*
skb
)
{
u8
nexthdr
;
int
err
=
0
;
struct
iphdr
*
iph
;
union
{
struct
iphdr
iph
;
char
buf
[
60
];
}
tmp_iph
;
if
((
skb_is_nonlinear
(
skb
)
||
skb_cloned
(
skb
))
&&
skb_linearize
(
skb
,
GFP_ATOMIC
)
!=
0
)
{
err
=
-
ENOMEM
;
goto
out
;
}
skb
->
ip_summed
=
CHECKSUM_NONE
;
/* Remove ipcomp header and decompress original payload */
iph
=
skb
->
nh
.
iph
;
memcpy
(
&
tmp_iph
,
iph
,
iph
->
ihl
*
4
);
nexthdr
=
*
(
u8
*
)
skb
->
data
;
skb_pull
(
skb
,
sizeof
(
struct
ipcomp_hdr
));
memcpy
(
skb
->
nh
.
raw
,
&
tmp_iph
,
tmp_iph
.
iph
.
ihl
*
4
);
iph
->
tot_len
=
htons
(
ntohs
(
iph
->
tot_len
)
-
sizeof
(
struct
ipcomp_hdr
));
iph
->
protocol
=
nexthdr
;
skb
->
h
.
raw
=
skb
->
data
;
err
=
ipcomp_decompress
(
x
,
skb
);
out:
return
err
;
}
static
int
ipcomp_compress
(
struct
xfrm_state
*
x
,
struct
sk_buff
*
skb
)
{
int
err
,
plen
,
dlen
,
ihlen
;
struct
iphdr
*
iph
=
skb
->
nh
.
iph
;
struct
ipcomp_data
*
ipcd
=
x
->
data
;
u8
*
start
,
*
scratch
=
ipcd
->
scratch
;
ihlen
=
iph
->
ihl
*
4
;
plen
=
skb
->
len
-
ihlen
;
dlen
=
IPCOMP_SCRATCH_SIZE
;
start
=
skb
->
data
+
ihlen
;
err
=
crypto_comp_compress
(
ipcd
->
tfm
,
start
,
plen
,
scratch
,
&
dlen
);
if
(
err
)
goto
out
;
if
((
dlen
+
sizeof
(
struct
ipcomp_hdr
))
>=
plen
)
{
err
=
-
EMSGSIZE
;
goto
out
;
}
memcpy
(
start
,
scratch
,
dlen
);
pskb_trim
(
skb
,
ihlen
+
dlen
);
out:
return
err
;
}
static
void
ipcomp_tunnel_encap
(
struct
xfrm_state
*
x
,
struct
sk_buff
*
skb
,
int
compress
)
{
struct
dst_entry
*
dst
=
skb
->
dst
;
struct
iphdr
*
iph
,
*
top_iph
;
iph
=
skb
->
nh
.
iph
;
top_iph
=
(
struct
iphdr
*
)
skb_push
(
skb
,
sizeof
(
struct
iphdr
));
top_iph
->
ihl
=
5
;
top_iph
->
version
=
4
;
top_iph
->
tos
=
iph
->
tos
;
top_iph
->
tot_len
=
htons
(
skb
->
len
);
if
(
!
(
iph
->
frag_off
&
htons
(
IP_DF
)))
__ip_select_ident
(
top_iph
,
dst
,
0
);
top_iph
->
ttl
=
iph
->
ttl
;
top_iph
->
protocol
=
compress
?
IPPROTO_COMP
:
IPPROTO_IPIP
;
top_iph
->
check
=
0
;
top_iph
->
saddr
=
x
->
props
.
saddr
.
a4
;
top_iph
->
daddr
=
x
->
id
.
daddr
.
a4
;
top_iph
->
frag_off
=
iph
->
frag_off
&~
htons
(
IP_MF
|
IP_OFFSET
);
memset
(
&
(
IPCB
(
skb
)
->
opt
),
0
,
sizeof
(
struct
ip_options
));
skb
->
nh
.
raw
=
skb
->
data
;
}
static
int
ipcomp_output
(
struct
sk_buff
*
skb
)
{
int
err
;
struct
dst_entry
*
dst
=
skb
->
dst
;
struct
xfrm_state
*
x
=
dst
->
xfrm
;
struct
iphdr
*
iph
,
*
top_iph
;
struct
ipcomp_hdr
*
ipch
;
struct
ipcomp_data
*
ipcd
=
x
->
data
;
union
{
struct
iphdr
iph
;
char
buf
[
60
];
}
tmp_iph
;
if
(
skb
->
ip_summed
==
CHECKSUM_HW
&&
skb_checksum_help
(
skb
)
==
NULL
)
{
err
=
-
EINVAL
;
goto
error_nolock
;
}
spin_lock_bh
(
&
x
->
lock
);
if
((
err
=
xfrm_state_check_expire
(
x
))
!=
0
)
goto
error
;
if
((
err
=
xfrm_state_check_space
(
x
,
skb
))
!=
0
)
goto
error
;
/* Don't bother compressing */
if
(
skb
->
len
<
ipcd
->
threshold
)
{
if
(
x
->
props
.
mode
)
{
ipcomp_tunnel_encap
(
x
,
skb
,
0
);
iph
=
skb
->
nh
.
iph
;
ip_send_check
(
iph
);
}
goto
out_ok
;
}
if
(
x
->
props
.
mode
)
ipcomp_tunnel_encap
(
x
,
skb
,
1
);
if
((
skb_is_nonlinear
(
skb
)
||
skb_cloned
(
skb
))
&&
skb_linearize
(
skb
,
GFP_ATOMIC
)
!=
0
)
{
err
=
-
ENOMEM
;
goto
error
;
}
err
=
ipcomp_compress
(
x
,
skb
);
if
(
err
)
{
if
(
err
==
-
EMSGSIZE
)
goto
out_ok
;
goto
error
;
}
/* Install ipcomp header, convert into ipcomp datagram. */
iph
=
skb
->
nh
.
iph
;
memcpy
(
&
tmp_iph
,
iph
,
iph
->
ihl
*
4
);
top_iph
=
(
struct
iphdr
*
)
skb_push
(
skb
,
sizeof
(
struct
ipcomp_hdr
));
memcpy
(
top_iph
,
&
tmp_iph
,
iph
->
ihl
*
4
);
iph
=
top_iph
;
iph
->
tot_len
=
htons
(
skb
->
len
);
iph
->
protocol
=
IPPROTO_COMP
;
iph
->
check
=
0
;
ipch
=
(
struct
ipcomp_hdr
*
)((
char
*
)
iph
+
iph
->
ihl
*
4
);
ipch
->
nexthdr
=
x
->
props
.
mode
?
IPPROTO_IPIP
:
tmp_iph
.
iph
.
protocol
;
ipch
->
flags
=
0
;
ipch
->
cpi
=
htons
((
u16
)
ntohl
(
x
->
id
.
spi
));
ip_send_check
(
iph
);
skb
->
nh
.
raw
=
skb
->
data
;
out_ok:
x
->
curlft
.
bytes
+=
skb
->
len
;
x
->
curlft
.
packets
++
;
spin_unlock_bh
(
&
x
->
lock
);
if
((
skb
->
dst
=
dst_pop
(
dst
))
==
NULL
)
{
err
=
-
EHOSTUNREACH
;
goto
error_nolock
;
}
err
=
NET_XMIT_BYPASS
;
out_exit:
return
err
;
error:
spin_unlock_bh
(
&
x
->
lock
);
error_nolock:
kfree_skb
(
skb
);
goto
out_exit
;
}
static
void
ipcomp4_err
(
struct
sk_buff
*
skb
,
u32
info
)
{
u32
spi
;
struct
iphdr
*
iph
=
(
struct
iphdr
*
)
skb
->
data
;
struct
ipcomp_hdr
*
ipch
=
(
struct
ipcomp_hdr
*
)(
skb
->
data
+
(
iph
->
ihl
<<
2
));
struct
xfrm_state
*
x
;
if
(
skb
->
h
.
icmph
->
type
!=
ICMP_DEST_UNREACH
||
skb
->
h
.
icmph
->
code
!=
ICMP_FRAG_NEEDED
)
return
;
spi
=
ntohl
(
ntohs
(
ipch
->
cpi
));
x
=
xfrm_state_lookup
((
xfrm_address_t
*
)
&
iph
->
daddr
,
spi
,
IPPROTO_COMP
,
AF_INET
);
if
(
!
x
)
return
;
printk
(
KERN_DEBUG
"pmtu discvovery on SA IPCOMP/%08x/%u.%u.%u.%u
\n
"
,
spi
,
NIPQUAD
(
iph
->
daddr
));
xfrm_state_put
(
x
);
}
static
void
ipcomp_free_data
(
struct
ipcomp_data
*
ipcd
)
{
if
(
ipcd
->
tfm
)
crypto_free_tfm
(
ipcd
->
tfm
);
if
(
ipcd
->
scratch
)
kfree
(
ipcd
->
scratch
);
}
static
void
ipcomp_destroy
(
struct
xfrm_state
*
x
)
{
struct
ipcomp_data
*
ipcd
=
x
->
data
;
ipcomp_free_data
(
ipcd
);
kfree
(
ipcd
);
}
static
int
ipcomp_init_state
(
struct
xfrm_state
*
x
,
void
*
args
)
{
int
err
=
-
ENOMEM
;
struct
ipcomp_data
*
ipcd
;
struct
xfrm_algo_desc
*
calg_desc
;
ipcd
=
kmalloc
(
sizeof
(
*
ipcd
),
GFP_KERNEL
);
if
(
!
ipcd
)
goto
error
;
memset
(
ipcd
,
0
,
sizeof
(
*
ipcd
));
x
->
props
.
header_len
=
sizeof
(
struct
ipcomp_hdr
);
if
(
x
->
props
.
mode
)
x
->
props
.
header_len
+=
sizeof
(
struct
iphdr
);
x
->
data
=
ipcd
;
ipcd
->
scratch
=
kmalloc
(
IPCOMP_SCRATCH_SIZE
,
GFP_KERNEL
);
if
(
!
ipcd
->
scratch
)
goto
error
;
ipcd
->
tfm
=
crypto_alloc_tfm
(
x
->
calg
->
alg_name
,
0
);
if
(
!
ipcd
->
tfm
)
goto
error
;
calg_desc
=
xfrm_calg_get_byname
(
x
->
calg
->
alg_name
);
BUG_ON
(
!
calg_desc
);
ipcd
->
threshold
=
calg_desc
->
uinfo
.
comp
.
threshold
;
err
=
0
;
out:
return
err
;
error:
if
(
ipcd
)
{
ipcomp_free_data
(
ipcd
);
kfree
(
ipcd
);
}
goto
out
;
}
static
struct
xfrm_type
ipcomp_type
=
{
.
description
=
"IPCOMP4"
,
.
proto
=
IPPROTO_COMP
,
.
init_state
=
ipcomp_init_state
,
.
destructor
=
ipcomp_destroy
,
.
input
=
ipcomp_input
,
.
output
=
ipcomp_output
};
static
struct
inet_protocol
ipcomp4_protocol
=
{
.
handler
=
xfrm4_rcv
,
.
err_handler
=
ipcomp4_err
,
.
no_policy
=
1
,
};
static
int
__init
ipcomp4_init
(
void
)
{
SET_MODULE_OWNER
(
&
ipcomp_type
);
if
(
xfrm_register_type
(
&
ipcomp_type
,
AF_INET
)
<
0
)
{
printk
(
KERN_INFO
"ipcomp init: can't add xfrm type
\n
"
);
return
-
EAGAIN
;
}
if
(
inet_add_protocol
(
&
ipcomp4_protocol
,
IPPROTO_COMP
)
<
0
)
{
printk
(
KERN_INFO
"ipcomp init: can't add protocol
\n
"
);
xfrm_unregister_type
(
&
ipcomp_type
,
AF_INET
);
return
-
EAGAIN
;
}
return
0
;
}
static
void
__exit
ipcomp4_fini
(
void
)
{
if
(
inet_del_protocol
(
&
ipcomp4_protocol
,
IPPROTO_COMP
)
<
0
)
printk
(
KERN_INFO
"ip ipcomp close: can't remove protocol
\n
"
);
if
(
xfrm_unregister_type
(
&
ipcomp_type
,
AF_INET
)
<
0
)
printk
(
KERN_INFO
"ip ipcomp close: can't remove xfrm type
\n
"
);
}
module_init
(
ipcomp4_init
);
module_exit
(
ipcomp4_fini
);
MODULE_LICENSE
(
"GPL"
);
MODULE_DESCRIPTION
(
"IP Payload Compression Protocol (IPComp) - RFC3713"
);
MODULE_AUTHOR
(
"James Morris <jmorris@intercode.com.au>"
);
net/ipv4/netfilter/ip_conntrack_core.c
View file @
78d4faf7
...
...
@@ -273,6 +273,8 @@ static void remove_expectations(struct ip_conntrack *ct)
* the un-established ones only */
if
(
exp
->
sibling
)
{
DEBUGP
(
"remove_expectations: skipping established %p of %p
\n
"
,
exp
->
sibling
,
ct
);
/* Indicate that this expectations parent is dead */
exp
->
expectant
=
NULL
;
continue
;
}
...
...
@@ -324,6 +326,9 @@ destroy_conntrack(struct nf_conntrack *nfct)
ip_conntrack_destroyed
(
ct
);
WRITE_LOCK
(
&
ip_conntrack_lock
);
/* Delete us from our own list to prevent corruption later */
list_del
(
&
ct
->
sibling_list
);
/* Delete our master expectation */
if
(
ct
->
master
)
{
/* can't call __unexpect_related here,
...
...
net/ipv4/route.c
View file @
78d4faf7
...
...
@@ -1790,7 +1790,8 @@ int ip_route_input(struct sk_buff *skb, u32 daddr, u32 saddr,
read_lock
(
&
inetdev_lock
);
if
((
in_dev
=
__in_dev_get
(
dev
))
!=
NULL
)
{
int
our
=
ip_check_mc
(
in_dev
,
daddr
);
int
our
=
ip_check_mc
(
in_dev
,
daddr
,
saddr
,
skb
->
nh
.
iph
->
protocol
);
if
(
our
#ifdef CONFIG_IP_MROUTE
||
(
!
LOCAL_MCAST
(
daddr
)
&&
IN_DEV_MFORWARD
(
in_dev
))
...
...
@@ -2020,7 +2021,7 @@ int ip_route_output_slow(struct rtable **rp, const struct flowi *oldflp)
}
}
else
if
(
res
.
type
==
RTN_MULTICAST
)
{
flags
|=
RTCF_MULTICAST
|
RTCF_LOCAL
;
if
(
!
ip_check_mc
(
in_dev
,
oldflp
->
fl4_dst
))
if
(
!
ip_check_mc
(
in_dev
,
oldflp
->
fl4_dst
,
oldflp
->
fl4_src
,
oldflp
->
proto
))
flags
&=
~
RTCF_LOCAL
;
/* If multicast route do not exist use
default one, but do not gateway in this case.
...
...
net/ipv4/udp.c
View file @
78d4faf7
...
...
@@ -298,6 +298,8 @@ static inline struct sock *udp_v4_mcast_next(struct sock *sk,
ipv6_only_sock
(
s
)
||
(
s
->
bound_dev_if
&&
s
->
bound_dev_if
!=
dif
))
continue
;
if
(
!
ip_mc_sf_allow
(
sk
,
loc_addr
,
rmt_addr
,
dif
))
continue
;
break
;
}
return
s
;
...
...
net/ipv4/xfrm4_input.c
View file @
78d4faf7
...
...
@@ -48,6 +48,9 @@ int xfrm4_rcv_encap(struct sk_buff *skb, __u16 encap_type)
if
(
x
->
props
.
replay_window
&&
xfrm_replay_check
(
x
,
seq
))
goto
drop_unlock
;
if
(
xfrm_state_check_expire
(
x
))
goto
drop_unlock
;
xfrm_vec
[
xfrm_nr
].
decap
.
decap_type
=
encap_type
;
if
(
x
->
type
->
input
(
x
,
&
(
xfrm_vec
[
xfrm_nr
].
decap
),
skb
))
goto
drop_unlock
;
...
...
net/ipv4/xfrm4_policy.c
View file @
78d4faf7
...
...
@@ -201,6 +201,13 @@ _decode_session4(struct sk_buff *skb, struct flowi *fl)
}
break
;
case
IPPROTO_COMP
:
if
(
pskb_may_pull
(
skb
,
xprth
+
4
-
skb
->
data
))
{
u16
*
ipcomp_hdr
=
(
u16
*
)
xprth
;
fl
->
uli_u
.
spi
=
ntohl
(
ntohs
(
ipcomp_hdr
[
1
]));
}
break
;
default:
fl
->
uli_u
.
spi
=
0
;
break
;
...
...
net/ipv6/addrconf.c
View file @
78d4faf7
...
...
@@ -1202,7 +1202,7 @@ addrconf_prefix_route(struct in6_addr *pfx, int plen, struct net_device *dev,
if
(
dev
->
type
==
ARPHRD_SIT
&&
(
dev
->
flags
&
IFF_POINTOPOINT
))
rtmsg
.
rtmsg_flags
|=
RTF_NONEXTHOP
;
ip6_route_add
(
&
rtmsg
);
ip6_route_add
(
&
rtmsg
,
NULL
);
}
/* Create "default" multicast route to the interface */
...
...
@@ -1219,7 +1219,7 @@ static void addrconf_add_mroute(struct net_device *dev)
rtmsg
.
rtmsg_ifindex
=
dev
->
ifindex
;
rtmsg
.
rtmsg_flags
=
RTF_UP
|
RTF_ADDRCONF
;
rtmsg
.
rtmsg_type
=
RTMSG_NEWROUTE
;
ip6_route_add
(
&
rtmsg
);
ip6_route_add
(
&
rtmsg
,
NULL
);
}
static
void
sit_route_add
(
struct
net_device
*
dev
)
...
...
@@ -1236,7 +1236,7 @@ static void sit_route_add(struct net_device *dev)
rtmsg
.
rtmsg_flags
=
RTF_UP
|
RTF_NONEXTHOP
;
rtmsg
.
rtmsg_ifindex
=
dev
->
ifindex
;
ip6_route_add
(
&
rtmsg
);
ip6_route_add
(
&
rtmsg
,
NULL
);
}
static
void
addrconf_add_lroute
(
struct
net_device
*
dev
)
...
...
@@ -1328,7 +1328,7 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len)
if
(
rt
&&
((
rt
->
rt6i_flags
&
(
RTF_GATEWAY
|
RTF_DEFAULT
))
==
0
))
{
if
(
rt
->
rt6i_flags
&
RTF_EXPIRES
)
{
if
(
pinfo
->
onlink
==
0
||
valid_lft
==
0
)
{
ip6_del_rt
(
rt
);
ip6_del_rt
(
rt
,
NULL
);
rt
=
NULL
;
}
else
{
rt
->
rt6i_expires
=
rt_expires
;
...
...
@@ -1952,7 +1952,7 @@ static void addrconf_rs_timer(unsigned long data)
rtmsg
.
rtmsg_ifindex
=
ifp
->
idev
->
dev
->
ifindex
;
ip6_route_add
(
&
rtmsg
);
ip6_route_add
(
&
rtmsg
,
NULL
);
}
out:
...
...
net/ipv6/ip6_fib.c
View file @
78d4faf7
...
...
@@ -423,7 +423,8 @@ static struct fib6_node * fib6_add_1(struct fib6_node *root, void *addr,
* Insert routing information in a node.
*/
static
int
fib6_add_rt2node
(
struct
fib6_node
*
fn
,
struct
rt6_info
*
rt
)
static
int
fib6_add_rt2node
(
struct
fib6_node
*
fn
,
struct
rt6_info
*
rt
,
struct
nlmsghdr
*
nlh
)
{
struct
rt6_info
*
iter
=
NULL
;
struct
rt6_info
**
ins
;
...
...
@@ -480,7 +481,7 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt)
*
ins
=
rt
;
rt
->
rt6i_node
=
fn
;
atomic_inc
(
&
rt
->
rt6i_ref
);
inet6_rt_notify
(
RTM_NEWROUTE
,
rt
);
inet6_rt_notify
(
RTM_NEWROUTE
,
rt
,
nlh
);
rt6_stats
.
fib_rt_entries
++
;
if
((
fn
->
fn_flags
&
RTN_RTINFO
)
==
0
)
{
...
...
@@ -504,7 +505,7 @@ static __inline__ void fib6_start_gc(struct rt6_info *rt)
* with source addr info in sub-trees
*/
int
fib6_add
(
struct
fib6_node
*
root
,
struct
rt6_info
*
rt
)
int
fib6_add
(
struct
fib6_node
*
root
,
struct
rt6_info
*
rt
,
struct
nlmsghdr
*
nlh
)
{
struct
fib6_node
*
fn
;
int
err
=
-
ENOMEM
;
...
...
@@ -577,7 +578,7 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt)
}
#endif
err
=
fib6_add_rt2node
(
fn
,
rt
);
err
=
fib6_add_rt2node
(
fn
,
rt
,
nlh
);
if
(
err
==
0
)
{
fib6_start_gc
(
rt
);
...
...
@@ -885,7 +886,8 @@ static struct fib6_node * fib6_repair_tree(struct fib6_node *fn)
}
}
static
void
fib6_del_route
(
struct
fib6_node
*
fn
,
struct
rt6_info
**
rtp
)
static
void
fib6_del_route
(
struct
fib6_node
*
fn
,
struct
rt6_info
**
rtp
,
struct
nlmsghdr
*
nlh
)
{
struct
fib6_walker_t
*
w
;
struct
rt6_info
*
rt
=
*
rtp
;
...
...
@@ -940,11 +942,11 @@ static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp)
if
(
atomic_read
(
&
rt
->
rt6i_ref
)
!=
1
)
BUG
();
}
inet6_rt_notify
(
RTM_DELROUTE
,
rt
);
inet6_rt_notify
(
RTM_DELROUTE
,
rt
,
nlh
);
rt6_release
(
rt
);
}
int
fib6_del
(
struct
rt6_info
*
rt
)
int
fib6_del
(
struct
rt6_info
*
rt
,
struct
nlmsghdr
*
nlh
)
{
struct
fib6_node
*
fn
=
rt
->
rt6i_node
;
struct
rt6_info
**
rtp
;
...
...
@@ -969,7 +971,7 @@ int fib6_del(struct rt6_info *rt)
for
(
rtp
=
&
fn
->
leaf
;
*
rtp
;
rtp
=
&
(
*
rtp
)
->
u
.
next
)
{
if
(
*
rtp
==
rt
)
{
fib6_del_route
(
fn
,
rtp
);
fib6_del_route
(
fn
,
rtp
,
nlh
);
return
0
;
}
}
...
...
@@ -1098,7 +1100,7 @@ static int fib6_clean_node(struct fib6_walker_t *w)
res
=
c
->
func
(
rt
,
c
->
arg
);
if
(
res
<
0
)
{
w
->
leaf
=
rt
;
res
=
fib6_del
(
rt
);
res
=
fib6_del
(
rt
,
NULL
);
if
(
res
)
{
#if RT6_DEBUG >= 2
printk
(
KERN_DEBUG
"fib6_clean_node: del failed: rt=%p@%p err=%d
\n
"
,
rt
,
rt
->
rt6i_node
,
res
);
...
...
net/ipv6/ndisc.c
View file @
78d4faf7
...
...
@@ -961,7 +961,7 @@ void ndisc_recv_na(struct sk_buff *skb)
struct
rt6_info
*
rt
;
rt
=
rt6_get_dflt_router
(
saddr
,
dev
);
if
(
rt
)
ip6_del_rt
(
rt
);
ip6_del_rt
(
rt
,
NULL
);
}
}
else
{
if
(
msg
->
icmph
.
icmp6_router
)
...
...
@@ -1035,7 +1035,7 @@ static void ndisc_router_discovery(struct sk_buff *skb)
rt
=
rt6_get_dflt_router
(
&
skb
->
nh
.
ipv6h
->
saddr
,
skb
->
dev
);
if
(
rt
&&
lifetime
==
0
)
{
ip6_del_rt
(
rt
);
ip6_del_rt
(
rt
,
NULL
);
rt
=
NULL
;
}
...
...
net/ipv6/route.c
View file @
78d4faf7
...
...
@@ -318,12 +318,12 @@ struct rt6_info *rt6_lookup(struct in6_addr *daddr, struct in6_addr *saddr,
be destroyed.
*/
static
int
rt6_ins
(
struct
rt6_info
*
rt
)
static
int
rt6_ins
(
struct
rt6_info
*
rt
,
struct
nlmsghdr
*
nlh
)
{
int
err
;
write_lock_bh
(
&
rt6_lock
);
err
=
fib6_add
(
&
ip6_routing_table
,
rt
);
err
=
fib6_add
(
&
ip6_routing_table
,
rt
,
nlh
);
write_unlock_bh
(
&
rt6_lock
);
return
err
;
...
...
@@ -366,7 +366,7 @@ static struct rt6_info *rt6_cow(struct rt6_info *ort, struct in6_addr *daddr,
dst_hold
(
&
rt
->
u
.
dst
);
err
=
rt6_ins
(
rt
);
err
=
rt6_ins
(
rt
,
NULL
);
if
(
err
==
0
)
return
rt
;
...
...
@@ -522,7 +522,7 @@ static struct dst_entry *ip6_negative_advice(struct dst_entry *dst)
if
(
rt
)
{
if
(
rt
->
rt6i_flags
&
RTF_CACHE
)
ip6_del_rt
(
rt
);
ip6_del_rt
(
rt
,
NULL
);
else
dst_release
(
dst
);
}
...
...
@@ -625,9 +625,10 @@ static int ipv6_get_hoplimit(struct net_device *dev)
*
*/
int
ip6_route_add
(
struct
in6_rtmsg
*
rtmsg
)
int
ip6_route_add
(
struct
in6_rtmsg
*
rtmsg
,
struct
nlmsghdr
*
nlh
)
{
int
err
;
struct
rtmsg
*
r
;
struct
rt6_info
*
rt
;
struct
net_device
*
dev
=
NULL
;
int
addr_type
;
...
...
@@ -648,6 +649,11 @@ int ip6_route_add(struct in6_rtmsg *rtmsg)
rt
->
u
.
dst
.
obsolete
=
-
1
;
rt
->
rt6i_expires
=
rtmsg
->
rtmsg_info
;
if
(
nlh
&&
(
r
=
NLMSG_DATA
(
nlh
)))
{
rt
->
rt6i_protocol
=
r
->
rtm_protocol
;
}
else
{
rt
->
rt6i_protocol
=
RTPROT_BOOT
;
}
addr_type
=
ipv6_addr_type
(
&
rtmsg
->
rtmsg_dst
);
...
...
@@ -772,7 +778,7 @@ int ip6_route_add(struct in6_rtmsg *rtmsg)
if
(
dst_metric
(
&
rt
->
u
.
dst
,
RTAX_ADVMSS
)
>
65535
-
20
)
rt
->
u
.
dst
.
metrics
[
RTAX_ADVMSS
-
1
]
=
65535
;
rt
->
u
.
dst
.
dev
=
dev
;
return
rt6_ins
(
rt
);
return
rt6_ins
(
rt
,
nlh
);
out:
if
(
dev
)
...
...
@@ -781,7 +787,7 @@ int ip6_route_add(struct in6_rtmsg *rtmsg)
return
err
;
}
int
ip6_del_rt
(
struct
rt6_info
*
rt
)
int
ip6_del_rt
(
struct
rt6_info
*
rt
,
struct
nlmsghdr
*
nlh
)
{
int
err
;
...
...
@@ -793,13 +799,13 @@ int ip6_del_rt(struct rt6_info *rt)
dst_release
(
&
rt
->
u
.
dst
);
err
=
fib6_del
(
rt
);
err
=
fib6_del
(
rt
,
nlh
);
write_unlock_bh
(
&
rt6_lock
);
return
err
;
}
static
int
ip6_route_del
(
struct
in6_rtmsg
*
rtmsg
)
static
int
ip6_route_del
(
struct
in6_rtmsg
*
rtmsg
,
struct
nlmsghdr
*
nlh
)
{
struct
fib6_node
*
fn
;
struct
rt6_info
*
rt
;
...
...
@@ -826,7 +832,7 @@ static int ip6_route_del(struct in6_rtmsg *rtmsg)
dst_hold
(
&
rt
->
u
.
dst
);
read_unlock_bh
(
&
rt6_lock
);
return
ip6_del_rt
(
rt
);
return
ip6_del_rt
(
rt
,
nlh
);
}
}
read_unlock_bh
(
&
rt6_lock
);
...
...
@@ -928,11 +934,11 @@ void rt6_redirect(struct in6_addr *dest, struct in6_addr *saddr,
nrt
->
u
.
dst
.
metrics
[
RTAX_ADVMSS
-
1
]
=
65535
;
nrt
->
rt6i_hoplimit
=
ipv6_get_hoplimit
(
neigh
->
dev
);
if
(
rt6_ins
(
nrt
))
if
(
rt6_ins
(
nrt
,
NULL
))
goto
out
;
if
(
rt
->
rt6i_flags
&
RTF_CACHE
)
{
ip6_del_rt
(
rt
);
ip6_del_rt
(
rt
,
NULL
);
return
;
}
...
...
@@ -1018,7 +1024,7 @@ void rt6_pmtu_discovery(struct in6_addr *daddr, struct in6_addr *saddr,
dst_set_expires
(
&
nrt
->
u
.
dst
,
ip6_rt_mtu_expires
);
nrt
->
rt6i_flags
|=
RTF_DYNAMIC
|
RTF_CACHE
|
RTF_EXPIRES
;
nrt
->
u
.
dst
.
metrics
[
RTAX_MTU
-
1
]
=
pmtu
;
rt6_ins
(
nrt
);
rt6_ins
(
nrt
,
NULL
);
}
out:
...
...
@@ -1091,7 +1097,7 @@ struct rt6_info *rt6_add_dflt_router(struct in6_addr *gwaddr,
rtmsg
.
rtmsg_ifindex
=
dev
->
ifindex
;
ip6_route_add
(
&
rtmsg
);
ip6_route_add
(
&
rtmsg
,
NULL
);
return
rt6_get_dflt_router
(
gwaddr
,
dev
);
}
...
...
@@ -1117,7 +1123,7 @@ void rt6_purge_dflt_routers(int last_resort)
read_unlock_bh
(
&
rt6_lock
);
ip6_del_rt
(
rt
);
ip6_del_rt
(
rt
,
NULL
);
goto
restart
;
}
...
...
@@ -1143,10 +1149,10 @@ int ipv6_route_ioctl(unsigned int cmd, void *arg)
rtnl_lock
();
switch
(
cmd
)
{
case
SIOCADDRT
:
err
=
ip6_route_add
(
&
rtmsg
);
err
=
ip6_route_add
(
&
rtmsg
,
NULL
);
break
;
case
SIOCDELRT
:
err
=
ip6_route_del
(
&
rtmsg
);
err
=
ip6_route_del
(
&
rtmsg
,
NULL
);
break
;
default:
err
=
-
EINVAL
;
...
...
@@ -1203,7 +1209,7 @@ int ip6_rt_addr_add(struct in6_addr *addr, struct net_device *dev)
ipv6_addr_copy
(
&
rt
->
rt6i_dst
.
addr
,
addr
);
rt
->
rt6i_dst
.
plen
=
128
;
rt6_ins
(
rt
);
rt6_ins
(
rt
,
NULL
);
return
0
;
}
...
...
@@ -1220,7 +1226,7 @@ int ip6_rt_addr_del(struct in6_addr *addr, struct net_device *dev)
rt
=
rt6_lookup
(
addr
,
NULL
,
loopback_dev
.
ifindex
,
1
);
if
(
rt
)
{
if
(
rt
->
rt6i_dst
.
plen
==
128
)
err
=
ip6_del_rt
(
rt
);
err
=
ip6_del_rt
(
rt
,
NULL
);
else
dst_release
(
&
rt
->
u
.
dst
);
}
...
...
@@ -1350,7 +1356,7 @@ int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
if
(
inet6_rtm_to_rtmsg
(
r
,
arg
,
&
rtmsg
))
return
-
EINVAL
;
return
ip6_route_del
(
&
rtmsg
);
return
ip6_route_del
(
&
rtmsg
,
nlh
);
}
int
inet6_rtm_newroute
(
struct
sk_buff
*
skb
,
struct
nlmsghdr
*
nlh
,
void
*
arg
)
...
...
@@ -1360,7 +1366,7 @@ int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
if
(
inet6_rtm_to_rtmsg
(
r
,
arg
,
&
rtmsg
))
return
-
EINVAL
;
return
ip6_route_add
(
&
rtmsg
);
return
ip6_route_add
(
&
rtmsg
,
nlh
);
}
struct
rt6_rtnl_dump_arg
...
...
@@ -1373,13 +1379,18 @@ static int rt6_fill_node(struct sk_buff *skb, struct rt6_info *rt,
struct
in6_addr
*
dst
,
struct
in6_addr
*
src
,
int
iif
,
int
type
,
u32
pid
,
u32
seq
)
int
type
,
u32
pid
,
u32
seq
,
struct
nlmsghdr
*
in_nlh
)
{
struct
rtmsg
*
rtm
;
struct
nlmsghdr
*
nlh
;
unsigned
char
*
b
=
skb
->
tail
;
struct
rta_cacheinfo
ci
;
if
(
!
pid
&&
in_nlh
)
{
pid
=
in_nlh
->
nlmsg_pid
;
}
nlh
=
NLMSG_PUT
(
skb
,
pid
,
seq
,
type
,
sizeof
(
*
rtm
));
rtm
=
NLMSG_DATA
(
nlh
);
rtm
->
rtm_family
=
AF_INET6
;
...
...
@@ -1395,7 +1406,7 @@ static int rt6_fill_node(struct sk_buff *skb, struct rt6_info *rt,
rtm
->
rtm_type
=
RTN_UNICAST
;
rtm
->
rtm_flags
=
0
;
rtm
->
rtm_scope
=
RT_SCOPE_UNIVERSE
;
rtm
->
rtm_protocol
=
RTPROT_BOOT
;
rtm
->
rtm_protocol
=
rt
->
rt6i_protocol
;
if
(
rt
->
rt6i_flags
&
RTF_DYNAMIC
)
rtm
->
rtm_protocol
=
RTPROT_REDIRECT
;
else
if
(
rt
->
rt6i_flags
&
(
RTF_ADDRCONF
|
RTF_ALLONLINK
))
...
...
@@ -1458,7 +1469,8 @@ static int rt6_dump_route(struct rt6_info *rt, void *p_arg)
struct
rt6_rtnl_dump_arg
*
arg
=
(
struct
rt6_rtnl_dump_arg
*
)
p_arg
;
return
rt6_fill_node
(
arg
->
skb
,
rt
,
NULL
,
NULL
,
0
,
RTM_NEWROUTE
,
NETLINK_CB
(
arg
->
cb
->
skb
).
pid
,
arg
->
cb
->
nlh
->
nlmsg_seq
);
NETLINK_CB
(
arg
->
cb
->
skb
).
pid
,
arg
->
cb
->
nlh
->
nlmsg_seq
,
NULL
);
}
static
int
fib6_dump_node
(
struct
fib6_walker_t
*
w
)
...
...
@@ -1608,7 +1620,8 @@ int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg)
fl
.
nl_u
.
ip6_u
.
daddr
,
fl
.
nl_u
.
ip6_u
.
saddr
,
iif
,
RTM_NEWROUTE
,
NETLINK_CB
(
in_skb
).
pid
,
nlh
->
nlmsg_seq
);
RTM_NEWROUTE
,
NETLINK_CB
(
in_skb
).
pid
,
nlh
->
nlmsg_seq
,
nlh
);
if
(
err
<
0
)
{
err
=
-
EMSGSIZE
;
goto
out_free
;
...
...
@@ -1624,7 +1637,7 @@ int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg)
goto
out
;
}
void
inet6_rt_notify
(
int
event
,
struct
rt6_info
*
rt
)
void
inet6_rt_notify
(
int
event
,
struct
rt6_info
*
rt
,
struct
nlmsghdr
*
nlh
)
{
struct
sk_buff
*
skb
;
int
size
=
NLMSG_SPACE
(
sizeof
(
struct
rtmsg
)
+
256
);
...
...
@@ -1634,7 +1647,7 @@ void inet6_rt_notify(int event, struct rt6_info *rt)
netlink_set_err
(
rtnl
,
0
,
RTMGRP_IPV6_ROUTE
,
ENOBUFS
);
return
;
}
if
(
rt6_fill_node
(
skb
,
rt
,
NULL
,
NULL
,
0
,
event
,
0
,
0
)
<
0
)
{
if
(
rt6_fill_node
(
skb
,
rt
,
NULL
,
NULL
,
0
,
event
,
0
,
0
,
nlh
)
<
0
)
{
kfree_skb
(
skb
);
netlink_set_err
(
rtnl
,
0
,
RTMGRP_IPV6_ROUTE
,
EINVAL
);
return
;
...
...
net/ipv6/xfrm6_input.c
View file @
78d4faf7
...
...
@@ -172,6 +172,9 @@ int xfrm6_rcv(struct sk_buff **pskb)
if
(
x
->
props
.
replay_window
&&
xfrm_replay_check
(
x
,
seq
))
goto
drop_unlock
;
if
(
xfrm_state_check_expire
(
x
))
goto
drop_unlock
;
nexthdr
=
x
->
type
->
input
(
x
,
&
(
xfrm_vec
[
xfrm_nr
].
decap
),
skb
);
if
(
nexthdr
<=
0
)
goto
drop_unlock
;
...
...
net/ipv6/xfrm6_policy.c
View file @
78d4faf7
...
...
@@ -203,6 +203,7 @@ _decode_session6(struct sk_buff *skb, struct flowi *fl)
/* XXX Why are there these headers? */
case
IPPROTO_AH
:
case
IPPROTO_ESP
:
case
IPPROTO_COMP
:
default:
fl
->
uli_u
.
spi
=
0
;
return
;
...
...
net/netsyms.c
View file @
78d4faf7
...
...
@@ -234,8 +234,8 @@ EXPORT_SYMBOL(scm_detach_fds);
#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
EXPORT_SYMBOL
(
br_handle_frame_hook
);
EXPORT_SYMBOL
(
brioctl_set
);
#endif
EXPORT_SYMBOL
(
br_ioctl_hook
);
#ifdef CONFIG_NET_DIVERT
EXPORT_SYMBOL
(
alloc_divert_blk
);
...
...
net/sched/sch_csz.c
View file @
78d4faf7
...
...
@@ -749,6 +749,14 @@ csz_reset(struct Qdisc* sch)
static
void
csz_destroy
(
struct
Qdisc
*
sch
)
{
struct
csz_sched_data
*
q
=
(
struct
csz_sched_data
*
)
sch
->
data
;
struct
tcf_proto
*
tp
;
while
((
tp
=
q
->
filter_list
)
!=
NULL
)
{
q
->
filter_list
=
tp
->
next
;
tp
->
ops
->
destroy
(
tp
);
}
MOD_DEC_USE_COUNT
;
}
...
...
net/sched/sch_htb.c
View file @
78d4faf7
...
...
@@ -102,7 +102,9 @@
#define HTB_PASSQ q,
#define HTB_ARGQ struct htb_sched *q,
#define static
#undef __inline__
#define __inline__
#undef inline
#define inline
#define HTB_CMAGIC 0xFEFAFEF1
#define htb_safe_rb_erase(N,R) do { BUG_TRAP((N)->rb_color != -1); \
...
...
net/sched/sch_prio.c
View file @
78d4faf7
...
...
@@ -158,6 +158,12 @@ prio_destroy(struct Qdisc* sch)
{
int
prio
;
struct
prio_sched_data
*
q
=
(
struct
prio_sched_data
*
)
sch
->
data
;
struct
tcf_proto
*
tp
;
while
((
tp
=
q
->
filter_list
)
!=
NULL
)
{
q
->
filter_list
=
tp
->
next
;
tp
->
ops
->
destroy
(
tp
);
}
for
(
prio
=
0
;
prio
<
q
->
bands
;
prio
++
)
{
qdisc_destroy
(
q
->
queues
[
prio
]);
...
...
net/socket.c
View file @
78d4faf7
...
...
@@ -71,6 +71,7 @@
#include <linux/wanrouter.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <linux/if_bridge.h>
#include <linux/init.h>
#include <linux/poll.h>
#include <linux/cache.h>
...
...
@@ -712,7 +713,18 @@ static ssize_t sock_writev(struct file *file, const struct iovec *vector,
file
,
vector
,
count
,
tot_len
);
}
int
(
*
br_ioctl_hook
)(
unsigned
long
arg
);
static
DECLARE_MUTEX
(
br_ioctl_mutex
);
static
int
(
*
br_ioctl_hook
)(
unsigned
long
arg
)
=
NULL
;
void
brioctl_set
(
int
(
*
hook
)(
unsigned
long
))
{
down
(
&
br_ioctl_mutex
);
br_ioctl_hook
=
hook
;
up
(
&
br_ioctl_mutex
);
}
int
(
*
vlan_ioctl_hook
)(
unsigned
long
arg
);
#ifdef CONFIG_DLCI
...
...
@@ -759,12 +771,16 @@ static int sock_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
case
SIOCGIFBR
:
case
SIOCSIFBR
:
err
=
-
ENOPKG
;
#ifdef CONFIG_KMOD
if
(
!
br_ioctl_hook
)
request_module
(
"bridge"
);
#endif
down
(
&
br_ioctl_mutex
);
if
(
br_ioctl_hook
)
err
=
br_ioctl_hook
(
arg
);
up
(
&
br_ioctl_mutex
);
break
;
case
SIOCGIFVLAN
:
case
SIOCSIFVLAN
:
...
...
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