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
808c8a58
Commit
808c8a58
authored
Apr 10, 2003
by
James Simmons
Browse files
Options
Browse Files
Download
Plain Diff
Merge kozmo.(none):/usr/src/linus-2.5
into kozmo.(none):/usr/src/fbdev-2.5
parents
470d3cc3
8f44c5c2
Changes
43
Hide whitespace changes
Inline
Side-by-side
Showing
43 changed files
with
2136 additions
and
179 deletions
+2136
-179
arch/sparc/kernel/sparc_ksyms.c
arch/sparc/kernel/sparc_ksyms.c
+1
-0
fs/nfs/dir.c
fs/nfs/dir.c
+3
-2
fs/select.c
fs/select.c
+2
-2
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/linux/poll.h
include/linux/poll.h
+2
-2
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
kernel/timer.c
kernel/timer.c
+1
-1
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
sound/core/ioctl32/pcm32.c
sound/core/ioctl32/pcm32.c
+5
-9
sound/core/ioctl32/rawmidi32.c
sound/core/ioctl32/rawmidi32.c
+3
-7
sound/core/ioctl32/timer32.c
sound/core/ioctl32/timer32.c
+4
-9
sound/core/memalloc.c
sound/core/memalloc.c
+2
-2
No files found.
arch/sparc/kernel/sparc_ksyms.c
View file @
808c8a58
...
...
@@ -127,6 +127,7 @@ EXPORT_SYMBOL(__down_trylock);
EXPORT_SYMBOL
(
__down_interruptible
);
EXPORT_SYMBOL
(
sparc_valid_addr_bitmap
);
EXPORT_SYMBOL
(
phys_base
);
/* Atomic operations. */
EXPORT_SYMBOL_PRIVATE
(
_atomic_add
);
...
...
fs/nfs/dir.c
View file @
808c8a58
...
...
@@ -736,9 +736,10 @@ int nfs_cached_lookup(struct inode *dir, struct dentry *dentry,
res
=
-
EIO
;
if
(
PageUptodate
(
page
))
{
desc
.
ptr
=
kmap_atomic
(
page
,
KM_USER0
);
void
*
kaddr
=
kmap_atomic
(
page
,
KM_USER0
);
desc
.
ptr
=
kaddr
;
res
=
find_dirent_name
(
&
desc
,
page
,
dentry
);
kunmap_atomic
(
desc
.
pt
r
,
KM_USER0
);
kunmap_atomic
(
kadd
r
,
KM_USER0
);
}
page_cache_release
(
page
);
...
...
fs/select.c
View file @
808c8a58
...
...
@@ -268,7 +268,7 @@ static void select_bits_free(void *bits, int size)
((unsigned long) (MAX_SCHEDULE_TIMEOUT / HZ)-1)
asmlinkage
long
sys_select
(
int
n
,
fd_set
*
inp
,
fd_set
*
outp
,
fd_set
*
exp
,
struct
timeval
*
tvp
)
sys_select
(
int
n
,
fd_set
__user
*
inp
,
fd_set
__user
*
outp
,
fd_set
__user
*
exp
,
struct
timeval
__user
*
tvp
)
{
fd_set_bits
fds
;
char
*
bits
;
...
...
@@ -429,7 +429,7 @@ static int do_poll(unsigned int nfds, struct poll_list *list,
return
count
;
}
asmlinkage
long
sys_poll
(
struct
pollfd
*
ufds
,
unsigned
int
nfds
,
long
timeout
)
asmlinkage
long
sys_poll
(
struct
pollfd
__user
*
ufds
,
unsigned
int
nfds
,
long
timeout
)
{
struct
poll_wqueues
table
;
int
fdcount
,
err
;
...
...
include/linux/if_bridge.h
View file @
808c8a58
...
...
@@ -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 @
808c8a58
...
...
@@ -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 @
808c8a58
...
...
@@ -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 @
808c8a58
...
...
@@ -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/linux/poll.h
View file @
808c8a58
...
...
@@ -67,7 +67,7 @@ typedef struct {
* Use "unsigned long" accesses to let user-mode fd_set's be long-aligned.
*/
static
inline
int
get_fd_set
(
unsigned
long
nr
,
void
*
ufdset
,
unsigned
long
*
fdset
)
int
get_fd_set
(
unsigned
long
nr
,
void
__user
*
ufdset
,
unsigned
long
*
fdset
)
{
nr
=
FDS_BYTES
(
nr
);
if
(
ufdset
)
{
...
...
@@ -82,7 +82,7 @@ int get_fd_set(unsigned long nr, void *ufdset, unsigned long *fdset)
}
static
inline
void
set_fd_set
(
unsigned
long
nr
,
void
*
ufdset
,
unsigned
long
*
fdset
)
void
set_fd_set
(
unsigned
long
nr
,
void
__user
*
ufdset
,
unsigned
long
*
fdset
)
{
if
(
ufdset
)
__copy_to_user
(
ufdset
,
fdset
,
FDS_BYTES
(
nr
));
...
...
include/net/ip.h
View file @
808c8a58
...
...
@@ -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 @
808c8a58
...
...
@@ -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 @
808c8a58
...
...
@@ -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
);
...
...
kernel/timer.c
View file @
808c8a58
...
...
@@ -1091,7 +1091,7 @@ asmlinkage long sys_nanosleep(struct timespec *rqtp, struct timespec *rmtp)
/*
* sys_sysinfo - fill in sysinfo struct
*/
asmlinkage
long
sys_sysinfo
(
struct
sysinfo
*
info
)
asmlinkage
long
sys_sysinfo
(
struct
sysinfo
__user
*
info
)
{
struct
sysinfo
val
;
u64
uptime
;
...
...
net/bridge/br.c
View file @
808c8a58
...
...
@@ -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 @
808c8a58
...
...
@@ -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 @
808c8a58
...
...
@@ -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 @
808c8a58
...
...
@@ -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
;
switch
(
event
)
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 @
808c8a58
...
...
@@ -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
)
if
(
br_handle_frame_hook
(
skb
)
==
0
)
return
ret
;
pt_prev
=
NULL
;
}
#endif
...
...
net/ipv4/Kconfig
View file @
808c8a58
...
...
@@ -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 @
808c8a58
...
...
@@ -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 @
808c8a58
...
...
@@ -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
)
{
/* Alas, old v1 router presents here. */
max_delay
=
IGMP_Query_Response_Interval
;
in_dev
->
mr_v1_seen
=
jiffies
+
IGMP_V1_Router_Present_Timeout
;
group
=
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
;
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
;
spin_lock_bh
(
&
im
->
lock
);
igmp_start_timer
(
im
,
IGMP_Initial_Report_Delay
);
spin_unlock_bh
(
&
im
->
lock
);
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 @
808c8a58
...
...
@@ -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 @
808c8a58
...
...
@@ -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 @
808c8a58
/*
* 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 @
808c8a58
...
...
@@ -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 @
808c8a58
...
...
@@ -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 @
808c8a58
...
...
@@ -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 @
808c8a58
...
...
@@ -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 @
808c8a58
...
...
@@ -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 @
808c8a58
...
...
@@ -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 @
808c8a58
...
...
@@ -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 @
808c8a58
...
...
@@ -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 @
808c8a58
...
...
@@ -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 @
808c8a58
...
...
@@ -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 @
808c8a58
...
...
@@ -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 @
808c8a58
...
...
@@ -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 @
808c8a58
...
...
@@ -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 @
808c8a58
...
...
@@ -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 @
808c8a58
...
...
@@ -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 @
808c8a58
...
...
@@ -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
if
(
br_ioctl_hook
)
down
(
&
br_ioctl_mutex
);
if
(
br_ioctl_hook
)
err
=
br_ioctl_hook
(
arg
);
up
(
&
br_ioctl_mutex
);
break
;
case
SIOCGIFVLAN
:
case
SIOCSIFVLAN
:
...
...
sound/core/ioctl32/pcm32.c
View file @
808c8a58
...
...
@@ -21,6 +21,7 @@
#include <sound/driver.h>
#include <linux/time.h>
#include <linux/slab.h>
#include <linux/compat.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include "ioctl32.h"
...
...
@@ -136,15 +137,10 @@ struct sndrv_pcm_channel_info32 {
COPY(step);\
}
struct
timeval32
{
s32
tv_sec
;
s32
tv_usec
;
}
__attribute__
((
packed
));
struct
sndrv_pcm_status32
{
s32
state
;
struct
timeval32
trigger_tstamp
;
struct
timeval32
tstamp
;
struct
compat_timespec
trigger_tstamp
;
struct
compat_timespec
tstamp
;
u32
appl_ptr
;
u32
hw_ptr
;
s32
delay
;
...
...
@@ -159,9 +155,9 @@ struct sndrv_pcm_status32 {
{\
COPY(state);\
COPY(trigger_tstamp.tv_sec);\
COPY(trigger_tstamp.tv_
u
sec);\
COPY(trigger_tstamp.tv_
n
sec);\
COPY(tstamp.tv_sec);\
COPY(tstamp.tv_
u
sec);\
COPY(tstamp.tv_
n
sec);\
COPY(appl_ptr);\
COPY(hw_ptr);\
COPY(delay);\
...
...
sound/core/ioctl32/rawmidi32.c
View file @
808c8a58
...
...
@@ -21,6 +21,7 @@
#include <sound/driver.h>
#include <linux/time.h>
#include <linux/fs.h>
#include <linux/compat.h>
#include <sound/core.h>
#include <sound/rawmidi.h>
#include <asm/uaccess.h>
...
...
@@ -42,14 +43,9 @@ struct sndrv_rawmidi_params32 {
COPY(no_active_sensing);\
}
struct
timeval32
{
s32
tv_sec
;
s32
tv_usec
;
}
__attribute__
((
packed
));
struct
sndrv_rawmidi_status32
{
s32
stream
;
struct
timeval32
tstamp
;
struct
compat_timespec
tstamp
;
u32
avail
;
u32
xruns
;
unsigned
char
reserved
[
16
];
...
...
@@ -59,7 +55,7 @@ struct sndrv_rawmidi_status32 {
{\
COPY(stream);\
COPY(tstamp.tv_sec);\
COPY(tstamp.tv_
u
sec);\
COPY(tstamp.tv_
n
sec);\
COPY(avail);\
COPY(xruns);\
}
...
...
sound/core/ioctl32/timer32.c
View file @
808c8a58
...
...
@@ -21,6 +21,7 @@
#include <sound/driver.h>
#include <linux/time.h>
#include <linux/fs.h>
#include <linux/compat.h>
#include <sound/core.h>
#include <sound/timer.h>
#include <asm/uaccess.h>
...
...
@@ -31,7 +32,7 @@ struct sndrv_timer_info32 {
s32
card
;
unsigned
char
id
[
64
];
unsigned
char
name
[
80
];
u32
ticks
;
u32
reserved0
;
u32
resolution
;
unsigned
char
reserved
[
64
];
};
...
...
@@ -42,17 +43,11 @@ struct sndrv_timer_info32 {
COPY(card);\
memcpy(dst->id, src->id, sizeof(src->id));\
memcpy(dst->name, src->name, sizeof(src->name));\
COPY(ticks);\
COPY(resolution);\
}
struct
timeval32
{
s32
tv_sec
;
s32
tv_usec
;
};
struct
sndrv_timer_status32
{
struct
timeval32
tstamp
;
struct
compat_timespec
tstamp
;
u32
resolution
;
u32
lost
;
u32
overrun
;
...
...
@@ -63,7 +58,7 @@ struct sndrv_timer_status32 {
#define CVT_sndrv_timer_status()\
{\
COPY(tstamp.tv_sec);\
COPY(tstamp.tv_
u
sec);\
COPY(tstamp.tv_
n
sec);\
COPY(resolution);\
COPY(lost);\
COPY(overrun);\
...
...
sound/core/memalloc.c
View file @
808c8a58
...
...
@@ -205,7 +205,7 @@ int snd_dma_alloc_pages(const struct snd_dma_device *dev, size_t size,
#endif
#ifdef CONFIG_SBUS
case
SNDRV_DMA_TYPE_SBUS
:
dmab
->
area
=
snd_malloc_
pci
_pages
(
dev
->
dev
.
sbus
,
size
,
&
dmab
->
addr
);
dmab
->
area
=
snd_malloc_
sbus
_pages
(
dev
->
dev
.
sbus
,
size
,
&
dmab
->
addr
);
break
;
#endif
default:
...
...
@@ -248,7 +248,7 @@ void snd_dma_free_pages(const struct snd_dma_device *dev, struct snd_dma_buffer
#endif
#ifdef CONFIG_SBUS
case
SNDRV_DMA_TYPE_SBUS
:
snd_free_sbus_pages
(
dev
->
dev
.
sbus
,
dmab
->
size
,
dmab
->
are
,
dmab
->
addr
);
snd_free_sbus_pages
(
dev
->
dev
.
sbus
,
dmab
->
bytes
,
dmab
->
area
,
dmab
->
addr
);
break
;
#endif
default:
...
...
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