Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
4f78b8d1
Commit
4f78b8d1
authored
Jun 14, 2003
by
David S. Miller
Browse files
Options
Browse Files
Download
Plain Diff
Merge nuts.ninka.net:/home/davem/src/BK/network-2.5
into nuts.ninka.net:/home/davem/src/BK/net-2.5
parents
0f7923d7
36f29ee0
Changes
19
Show whitespace changes
Inline
Side-by-side
Showing
19 changed files
with
442 additions
and
421 deletions
+442
-421
drivers/net/ppp_generic.c
drivers/net/ppp_generic.c
+3
-8
drivers/net/slip.c
drivers/net/slip.c
+124
-94
include/linux/netdevice.h
include/linux/netdevice.h
+10
-2
include/net/route.h
include/net/route.h
+2
-0
include/net/tcp.h
include/net/tcp.h
+8
-1
include/net/xfrm.h
include/net/xfrm.h
+0
-1
net/bluetooth/rfcomm/tty.c
net/bluetooth/rfcomm/tty.c
+0
-2
net/core/dev.c
net/core/dev.c
+77
-142
net/core/net-sysfs.c
net/core/net-sysfs.c
+44
-14
net/decnet/dn_nsp_in.c
net/decnet/dn_nsp_in.c
+1
-1
net/ipv4/af_inet.c
net/ipv4/af_inet.c
+1
-1
net/ipv4/route.c
net/ipv4/route.c
+6
-2
net/ipv4/tcp_ipv4.c
net/ipv4/tcp_ipv4.c
+1
-1
net/ipv4/tcp_minisocks.c
net/ipv4/tcp_minisocks.c
+2
-2
net/ipv4/tcp_timer.c
net/ipv4/tcp_timer.c
+3
-3
net/ipv6/ah6.c
net/ipv6/ah6.c
+155
-11
net/ipv6/ipv6_syms.c
net/ipv6/ipv6_syms.c
+0
-1
net/ipv6/xfrm6_input.c
net/ipv6/xfrm6_input.c
+4
-134
net/xfrm/xfrm_state.c
net/xfrm/xfrm_state.c
+1
-1
No files found.
drivers/net/ppp_generic.c
View file @
4f78b8d1
...
...
@@ -2343,14 +2343,9 @@ static void ppp_shutdown_interface(struct ppp *ppp)
dev
=
ppp
->
dev
;
ppp
->
dev
=
0
;
ppp_unlock
(
ppp
);
if
(
dev
)
{
rtnl_lock
();
/* This will call dev_close() for us. */
unregister_netdevice
(
dev
);
rtnl_unlock
();
}
if
(
dev
)
unregister_netdev
(
dev
);
cardmap_set
(
&
all_ppp_units
,
ppp
->
file
.
index
,
NULL
);
ppp
->
file
.
dead
=
1
;
ppp
->
owner
=
NULL
;
...
...
drivers/net/slip.c
View file @
4f78b8d1
...
...
@@ -83,12 +83,7 @@
#define SLIP_VERSION "0.8.4-NET3.019-NEWTTY"
typedef
struct
slip_ctrl
{
struct
slip
ctrl
;
/* SLIP things */
struct
net_device
dev
;
/* the device */
}
slip_ctrl_t
;
static
slip_ctrl_t
**
slip_ctrls
;
static
struct
net_device
**
slip_devs
;
int
slip_maxdev
=
SL_NRUNIT
;
/* Can be overridden with insmod! */
MODULE_PARM
(
slip_maxdev
,
"i"
);
...
...
@@ -624,32 +619,45 @@ static int sl_init(struct net_device *dev)
*/
dev
->
mtu
=
sl
->
mtu
;
dev
->
hard_start_xmit
=
sl_xmit
;
dev
->
type
=
ARPHRD_SLIP
+
sl
->
mode
;
#ifdef SL_CHECK_TRANSMIT
dev
->
tx_timeout
=
sl_tx_timeout
;
dev
->
watchdog_timeo
=
20
*
HZ
;
#endif
return
0
;
}
static
void
sl_uninit
(
struct
net_device
*
dev
)
{
struct
slip
*
sl
=
(
struct
slip
*
)(
dev
->
priv
);
sl_free_bufs
(
sl
);
}
static
void
sl_setup
(
struct
net_device
*
dev
)
{
dev
->
init
=
sl_init
;
dev
->
uninit
=
sl_uninit
;
dev
->
open
=
sl_open
;
dev
->
destructor
=
(
void
(
*
)(
struct
net_device
*
))
kfree
;
dev
->
stop
=
sl_close
;
dev
->
get_stats
=
sl_get_stats
;
dev
->
change_mtu
=
sl_change_mtu
;
dev
->
hard_start_xmit
=
sl_xmit
;
#ifdef CONFIG_SLIP_SMART
dev
->
do_ioctl
=
sl_ioctl
;
#endif
dev
->
hard_header_len
=
0
;
dev
->
addr_len
=
0
;
dev
->
type
=
ARPHRD_SLIP
+
sl
->
mode
;
dev
->
tx_queue_len
=
10
;
SET_MODULE_OWNER
(
dev
);
/* New-style flags. */
dev
->
flags
=
IFF_NOARP
|
IFF_POINTOPOINT
|
IFF_MULTICAST
;
return
0
;
}
/******************************************
Routines looking at TTY side.
******************************************/
...
...
@@ -702,52 +710,57 @@ static void slip_receive_buf(struct tty_struct *tty, const unsigned char *cp, ch
static
void
sl_sync
(
void
)
{
int
i
;
struct
net_device
*
dev
;
struct
slip
*
sl
;
for
(
i
=
0
;
i
<
slip_maxdev
;
i
++
)
{
slip_ctrl_t
*
slp
=
slip_ctrls
[
i
];
if
(
slp
==
NULL
)
if
((
dev
=
slip_devs
[
i
])
==
NULL
)
break
;
if
(
slp
->
ctrl
.
tty
||
slp
->
ctrl
.
leased
)
sl
=
dev
->
priv
;
if
(
sl
->
tty
||
sl
->
leased
)
continue
;
if
(
slp
->
dev
.
flags
&
IFF_UP
)
dev_close
(
&
slp
->
dev
);
if
(
dev
->
flags
&
IFF_UP
)
dev_close
(
dev
);
}
}
/* Find a free SLIP channel, and link in this `tty' line. */
static
struct
slip
*
sl_alloc
(
dev_t
line
)
{
struct
slip
*
sl
;
slip_ctrl_t
*
slp
=
NULL
;
int
i
;
int
sel
=
-
1
;
int
score
=
-
1
;
struct
net_device
*
dev
=
NULL
;
struct
slip
*
sl
;
if
(
slip_
ctrls
==
NULL
)
if
(
slip_
devs
==
NULL
)
return
NULL
;
/* Master array missing ! */
for
(
i
=
0
;
i
<
slip_maxdev
;
i
++
)
{
slp
=
slip_ctrl
s
[
i
];
if
(
slp
==
NULL
)
dev
=
slip_dev
s
[
i
];
if
(
dev
==
NULL
)
break
;
if
(
slp
->
ctrl
.
leased
)
{
if
(
slp
->
ctrl
.
line
!=
line
)
sl
=
dev
->
priv
;
if
(
sl
->
leased
)
{
if
(
sl
->
line
!=
line
)
continue
;
if
(
sl
p
->
ctrl
.
tty
)
if
(
sl
->
tty
)
return
NULL
;
/* Clear ESCAPE & ERROR flags */
sl
p
->
ctrl
.
flags
&=
(
1
<<
SLF_INUSE
);
return
&
slp
->
ctr
l
;
sl
->
flags
&=
(
1
<<
SLF_INUSE
);
return
s
l
;
}
if
(
sl
p
->
ctrl
.
tty
)
if
(
sl
->
tty
)
continue
;
if
(
current
->
pid
==
sl
p
->
ctrl
.
pid
)
{
if
(
sl
p
->
ctrl
.
line
==
line
&&
score
<
3
)
{
if
(
current
->
pid
==
sl
->
pid
)
{
if
(
sl
->
line
==
line
&&
score
<
3
)
{
sel
=
i
;
score
=
3
;
continue
;
...
...
@@ -758,7 +771,7 @@ sl_alloc(dev_t line)
}
continue
;
}
if
(
sl
p
->
ctrl
.
line
==
line
&&
score
<
1
)
{
if
(
sl
->
line
==
line
&&
score
<
1
)
{
sel
=
i
;
score
=
1
;
continue
;
...
...
@@ -771,10 +784,11 @@ sl_alloc(dev_t line)
if
(
sel
>=
0
)
{
i
=
sel
;
slp
=
slip_ctrl
s
[
i
];
dev
=
slip_dev
s
[
i
];
if
(
score
>
1
)
{
slp
->
ctrl
.
flags
&=
(
1
<<
SLF_INUSE
);
return
&
slp
->
ctrl
;
sl
=
dev
->
priv
;
sl
->
flags
&=
(
1
<<
SLF_INUSE
);
return
sl
;
}
}
...
...
@@ -782,26 +796,32 @@ sl_alloc(dev_t line)
if
(
i
>=
slip_maxdev
)
return
NULL
;
if
(
slp
)
{
if
(
test_bit
(
SLF_INUSE
,
&
slp
->
ctrl
.
flags
))
{
unregister_netdevice
(
&
slp
->
dev
);
sl_free_bufs
(
&
slp
->
ctrl
);
if
(
dev
)
{
sl
=
dev
->
priv
;
if
(
test_bit
(
SLF_INUSE
,
&
sl
->
flags
))
{
unregister_netdevice
(
dev
);
dev
=
NULL
;
slip_devs
[
i
]
=
NULL
;
}
}
}
else
if
((
slp
=
(
slip_ctrl_t
*
)
kmalloc
(
sizeof
(
slip_ctrl_t
),
GFP_KERNEL
))
==
NULL
)
if
(
!
dev
)
{
char
name
[
IFNAMSIZ
];
sprintf
(
name
,
"sl%d"
,
i
);
dev
=
alloc_netdev
(
sizeof
(
*
sl
),
name
,
sl_setup
);
if
(
!
dev
)
return
NULL
;
dev
->
base_addr
=
i
;
}
memset
(
slp
,
0
,
sizeof
(
slip_ctrl_t
))
;
sl
=
dev
->
priv
;
sl
=
&
slp
->
ctrl
;
/* Initialize channel control data */
sl
->
magic
=
SLIP_MAGIC
;
sl
->
dev
=
&
slp
->
dev
;
sl
->
dev
=
dev
;
spin_lock_init
(
&
sl
->
lock
);
sl
->
mode
=
SL_MODE_DEFAULT
;
sprintf
(
slp
->
dev
.
name
,
"sl%d"
,
i
);
slp
->
dev
.
base_addr
=
i
;
slp
->
dev
.
priv
=
(
void
*
)
sl
;
slp
->
dev
.
init
=
sl_init
;
#ifdef CONFIG_SLIP_SMART
init_timer
(
&
sl
->
keepalive_timer
);
/* initialize timer_list struct */
sl
->
keepalive_timer
.
data
=
(
unsigned
long
)
sl
;
...
...
@@ -810,8 +830,9 @@ sl_alloc(dev_t line)
sl
->
outfill_timer
.
data
=
(
unsigned
long
)
sl
;
sl
->
outfill_timer
.
function
=
sl_outfill
;
#endif
slip_ctrls
[
i
]
=
slp
;
return
&
slp
->
ctrl
;
slip_devs
[
i
]
=
dev
;
return
sl
;
}
/*
...
...
@@ -865,12 +886,10 @@ slip_open(struct tty_struct *tty)
if
((
err
=
sl_alloc_bufs
(
sl
,
SL_MTU
))
!=
0
)
goto
err_free_chan
;
if
(
register_netdevice
(
sl
->
dev
))
{
sl_free_bufs
(
sl
);
goto
err_free_chan
;
}
set_bit
(
SLF_INUSE
,
&
sl
->
flags
);
if
((
err
=
register_netdevice
(
sl
->
dev
)))
goto
err_free_bufs
;
}
#ifdef CONFIG_SLIP_SMART
...
...
@@ -888,6 +907,9 @@ slip_open(struct tty_struct *tty)
rtnl_unlock
();
return
sl
->
dev
->
base_addr
;
err_free_bufs:
sl_free_bufs
(
sl
);
err_free_chan:
sl
->
tty
=
NULL
;
tty
->
disc_data
=
NULL
;
...
...
@@ -1335,14 +1357,14 @@ static int __init slip_init(void)
printk
(
KERN_INFO
"SLIP linefill/keepalive option.
\n
"
);
#endif
slip_
ctrls
=
kmalloc
(
sizeof
(
void
*
)
*
slip_maxdev
,
GFP_KERNEL
);
if
(
!
slip_
ctrl
s
)
{
printk
(
KERN_ERR
"SLIP: Can't allocate slip
_ctrls[]
array! Uaargh! (-> No SLIP available)
\n
"
);
slip_
devs
=
kmalloc
(
sizeof
(
struct
net_device
*
)
*
slip_maxdev
,
GFP_KERNEL
);
if
(
!
slip_
dev
s
)
{
printk
(
KERN_ERR
"SLIP: Can't allocate slip
devices
array! Uaargh! (-> No SLIP available)
\n
"
);
return
-
ENOMEM
;
}
/* Clear the pointer array, we allocate devices when we need them */
memset
(
slip_
ctrls
,
0
,
sizeof
(
void
*
)
*
slip_maxdev
);
/* Pointers */
memset
(
slip_
devs
,
0
,
sizeof
(
struct
net_device
*
)
*
slip_maxdev
);
/* Fill in our line protocol discipline, and register it */
if
((
status
=
tty_register_ldisc
(
N_SLIP
,
&
sl_ldisc
))
!=
0
)
{
...
...
@@ -1354,51 +1376,59 @@ static int __init slip_init(void)
static
void
__exit
slip_exit
(
void
)
{
int
i
;
if
(
slip_ctrls
!=
NULL
)
{
struct
net_device
*
dev
;
struct
slip
*
sl
;
unsigned
long
timeout
=
jiffies
+
HZ
;
int
busy
=
0
;
if
(
slip_devs
==
NULL
)
return
;
/* First of all: check for active disciplines and hangup them.
*/
do
{
if
(
busy
)
yield
();
if
(
busy
)
{
current
->
state
=
TASK_INTERRUPTIBLE
;
schedule_timeout
(
HZ
/
10
);
current
->
state
=
TASK_RUNNING
;
}
busy
=
0
;
local_bh_disable
();
for
(
i
=
0
;
i
<
slip_maxdev
;
i
++
)
{
struct
slip_ctrl
*
slc
=
slip_ctrl
s
[
i
];
if
(
!
slc
)
dev
=
slip_dev
s
[
i
];
if
(
!
dev
)
continue
;
spin_lock
(
&
slc
->
ctrl
.
lock
);
if
(
slc
->
ctrl
.
tty
)
{
sl
=
dev
->
priv
;
spin_lock_bh
(
&
sl
->
lock
);
if
(
sl
->
tty
)
{
busy
++
;
tty_hangup
(
slc
->
ctrl
.
tty
);
tty_hangup
(
sl
->
tty
);
}
spin_unlock
(
&
slc
->
ctrl
.
lock
);
spin_unlock_bh
(
&
sl
->
lock
);
}
local_bh_enable
();
}
while
(
busy
&&
time_before
(
jiffies
,
timeout
));
for
(
i
=
0
;
i
<
slip_maxdev
;
i
++
)
{
struct
slip_ctrl
*
slc
=
slip_ctrls
[
i
];
if
(
slc
)
{
unregister_netdev
(
&
slc
->
dev
);
if
(
slc
->
ctrl
.
tty
)
{
printk
(
KERN_ERR
"%s: tty discipline is still running
\n
"
,
slc
->
dev
.
name
);
dev
=
slip_devs
[
i
];
if
(
!
dev
)
continue
;
slip_devs
[
i
]
=
NULL
;
sl
=
dev
->
priv
;
if
(
sl
->
tty
)
{
printk
(
KERN_ERR
"%s: tty discipline still running
\n
"
,
dev
->
name
);
/* Intentionally leak the control block. */
}
else
{
sl_free_bufs
(
&
slc
->
ctrl
);
kfree
(
slc
);
}
slip_ctrls
[
i
]
=
NULL
;
}
dev
->
destructor
=
NULL
;
}
kfree
(
slip_ctrls
);
slip_ctrls
=
NULL
;
unregister_netdev
(
dev
);
}
kfree
(
slip_devs
);
slip_devs
=
NULL
;
if
((
i
=
tty_register_ldisc
(
N_SLIP
,
NULL
)))
{
printk
(
KERN_ERR
"SLIP: can't unregister line discipline (err = %d)
\n
"
,
i
);
...
...
include/linux/netdevice.h
View file @
4f78b8d1
...
...
@@ -355,8 +355,16 @@ struct net_device
spinlock_t
queue_lock
;
/* Number of references to this device */
atomic_t
refcnt
;
/* The flag marking that device is unregistered, but held by an user */
int
deadbeaf
;
/* delayed register/unregister */
struct
list_head
todo_list
;
/* register/unregister state machine */
enum
{
NETREG_UNINITIALIZED
=
0
,
NETREG_REGISTERING
,
/* called register_netdevice */
NETREG_REGISTERED
,
/* completed register todo */
NETREG_UNREGISTERING
,
/* called unregister_netdevice */
NETREG_UNREGISTERED
,
/* completed unregister todo */
}
reg_state
;
/* Net device features */
int
features
;
...
...
include/net/route.h
View file @
4f78b8d1
...
...
@@ -102,6 +102,8 @@ struct rt_cache_stat
unsigned
int
gc_ignored
;
unsigned
int
gc_goal_miss
;
unsigned
int
gc_dst_overflow
;
unsigned
int
in_hlist_search
;
unsigned
int
out_hlist_search
;
};
extern
struct
rt_cache_stat
*
rt_cache_stat
;
...
...
include/net/tcp.h
View file @
4f78b8d1
...
...
@@ -160,6 +160,12 @@ static __inline__ int tcp_bhashfn(__u16 lport)
extern
void
tcp_bind_hash
(
struct
sock
*
sk
,
struct
tcp_bind_bucket
*
tb
,
unsigned
short
snum
);
#if (BITS_PER_LONG == 64)
#define TCP_ADDRCMP_ALIGN_BYTES 8
#else
#define TCP_ADDRCMP_ALIGN_BYTES 4
#endif
/* This is a TIME_WAIT bucket. It works around the memory consumption
* problems of sockets in such a state on heavily loaded servers, but
* without violating the protocol specification.
...
...
@@ -184,7 +190,8 @@ struct tcp_tw_bucket {
__u16
tw_sport
;
/* Socket demultiplex comparisons on incoming packets. */
/* these five are in inet_opt */
__u32
tw_daddr
;
__u32
tw_daddr
__attribute__
((
aligned
(
TCP_ADDRCMP_ALIGN_BYTES
)));
__u32
tw_rcv_saddr
;
__u16
tw_dport
;
__u16
tw_num
;
...
...
include/net/xfrm.h
View file @
4f78b8d1
...
...
@@ -782,7 +782,6 @@ extern int xfrm4_tunnel_register(struct xfrm_tunnel *handler);
extern
int
xfrm4_tunnel_deregister
(
struct
xfrm_tunnel
*
handler
);
extern
int
xfrm4_tunnel_check_size
(
struct
sk_buff
*
skb
);
extern
int
xfrm6_rcv
(
struct
sk_buff
**
pskb
,
unsigned
int
*
nhoffp
);
extern
int
xfrm6_clear_mutable_options
(
struct
sk_buff
*
skb
,
u16
*
nh_offset
,
int
dir
);
extern
int
xfrm_user_policy
(
struct
sock
*
sk
,
int
optname
,
u8
*
optval
,
int
optlen
);
void
xfrm_policy_init
(
void
);
...
...
net/bluetooth/rfcomm/tty.c
View file @
4f78b8d1
...
...
@@ -874,8 +874,6 @@ static struct tty_operations rfcomm_ops = {
int
rfcomm_init_ttys
(
void
)
{
int
i
;
rfcomm_tty_driver
=
alloc_tty_driver
(
RFCOMM_TTY_PORTS
);
if
(
!
rfcomm_tty_driver
)
return
-
1
;
...
...
net/core/dev.c
View file @
4f78b8d1
...
...
@@ -168,14 +168,6 @@ static void sample_queue(unsigned long dummy);
static
struct
timer_list
samp_timer
=
TIMER_INITIALIZER
(
sample_queue
,
0
,
0
);
#endif
#ifdef CONFIG_HOTPLUG
static
void
net_run_sbin_hotplug
(
struct
net_device
*
dev
,
int
is_register
);
static
void
net_run_hotplug_todo
(
void
);
#else
#define net_run_sbin_hotplug(dev, is_register) do { } while (0)
#define net_run_hotplug_todo() do { } while (0)
#endif
/*
* Our notifier list
*/
...
...
@@ -2537,6 +2529,17 @@ int dev_new_index(void)
static
int
dev_boot_phase
=
1
;
/* Delayed registration/unregisteration */
static
spinlock_t
net_todo_list_lock
=
SPIN_LOCK_UNLOCKED
;
static
struct
list_head
net_todo_list
=
LIST_HEAD_INIT
(
net_todo_list
);
static
inline
void
net_set_todo
(
struct
net_device
*
dev
)
{
spin_lock
(
&
net_todo_list_lock
);
list_add_tail
(
&
dev
->
todo_list
,
&
net_todo_list
);
spin_unlock
(
&
net_todo_list_lock
);
}
/**
* register_netdevice - register a network device
* @dev: device to register
...
...
@@ -2563,6 +2566,9 @@ int register_netdevice(struct net_device *dev)
BUG_ON
(
dev_boot_phase
);
ASSERT_RTNL
();
/* When net_device's are persistent, this will be fatal. */
WARN_ON
(
dev
->
reg_state
!=
NETREG_UNINITIALIZED
);
spin_lock_init
(
&
dev
->
queue_lock
);
spin_lock_init
(
&
dev
->
xmit_lock
);
dev
->
xmit_lock_owner
=
-
1
;
...
...
@@ -2592,9 +2598,6 @@ int register_netdevice(struct net_device *dev)
goto
out_err
;
}
if
((
ret
=
netdev_register_sysfs
(
dev
)))
goto
out_err
;
/* Fix illegal SG+CSUM combinations. */
if
((
dev
->
features
&
NETIF_F_SG
)
&&
!
(
dev
->
features
&
(
NETIF_F_IP_CSUM
|
...
...
@@ -2625,13 +2628,14 @@ int register_netdevice(struct net_device *dev)
write_lock_bh
(
&
dev_base_lock
);
*
dp
=
dev
;
dev_hold
(
dev
);
dev
->
deadbeaf
=
0
;
dev
->
reg_state
=
NETREG_REGISTERING
;
write_unlock_bh
(
&
dev_base_lock
);
/* Notify protocols, that a new device appeared. */
notifier_call_chain
(
&
netdev_chain
,
NETDEV_REGISTER
,
dev
);
net_run_sbin_hotplug
(
dev
,
1
);
/* Finish registration after unlock */
net_set_todo
(
dev
);
ret
=
0
;
out:
...
...
@@ -2654,7 +2658,7 @@ static int netdev_finish_unregister(struct net_device *dev)
BUG_TRAP
(
!
dev
->
ip6_ptr
);
BUG_TRAP
(
!
dev
->
dn_ptr
);
if
(
!
dev
->
deadbeaf
)
{
if
(
dev
->
reg_state
!=
NETREG_UNREGISTERED
)
{
printk
(
KERN_ERR
"Freeing alive device %p, %s
\n
"
,
dev
,
dev
->
name
);
return
0
;
...
...
@@ -2731,41 +2735,60 @@ static void netdev_wait_allrefs(struct net_device *dev)
* rtnl_unlock();
*
* We are invoked by rtnl_unlock() after it drops the semaphore.
* This allows us to deal with
two
problems:
* 1) We can
invoke hotplug without deadlocking with linkwatch via
* keventd.
* This allows us to deal with problems:
* 1) We can
create/delete sysfs objects which invoke hotplug
*
without deadlocking with linkwatch via
keventd.
* 2) Since we run with the RTNL semaphore not held, we can sleep
* safely in order to wait for the netdev refcnt to drop to zero.
*/
static
spinlock_t
unregister_todo_lock
=
SPIN_LOCK_UNLOCKED
;
static
struct
net_device
*
unregister_todo
;
static
DECLARE_MUTEX
(
net_todo_run_mutex
);
void
netdev_run_todo
(
void
)
{
struct
net_device
*
dev
;
struct
list_head
list
=
LIST_HEAD_INIT
(
list
)
;
net_run_hotplug_todo
();
/* Safe outside mutex since we only care about entries that
* this cpu put into queue while under RTNL.
*/
if
(
list_empty
(
&
net_todo_list
))
return
;
spin_lock
(
&
unregister_todo_lock
);
dev
=
unregister_todo
;
unregister_todo
=
NULL
;
spin_unlock
(
&
unregister_todo_lock
);
/* Need to guard against multiple cpu's getting out of order. */
down
(
&
net_todo_run_mutex
);
while
(
dev
)
{
struct
net_device
*
next
=
dev
->
next
;
/* Snapshot list, allow later requests */
spin_lock
(
&
net_todo_list_lock
);
list_splice_init
(
&
net_todo_list
,
&
list
);
spin_unlock
(
&
net_todo_list_lock
);
dev
->
next
=
NULL
;
while
(
!
list_empty
(
&
list
))
{
struct
net_device
*
dev
=
list_entry
(
list
.
next
,
struct
net_device
,
todo_list
);
list_del
(
&
dev
->
todo_list
);
switch
(
dev
->
reg_state
)
{
case
NETREG_REGISTERING
:
netdev_register_sysfs
(
dev
);
dev
->
reg_state
=
NETREG_REGISTERED
;
break
;
case
NETREG_UNREGISTERING
:
netdev_unregister_sysfs
(
dev
);
dev
->
reg_state
=
NETREG_UNREGISTERED
;
netdev_wait_allrefs
(
dev
);
BUG_ON
(
atomic_read
(
&
dev
->
refcnt
));
netdev_finish_unregister
(
dev
);
break
;
dev
=
next
;
default:
printk
(
KERN_ERR
"network todo '%s' but state %d
\n
"
,
dev
->
name
,
dev
->
reg_state
);
break
;
}
}
up
(
&
net_todo_run_mutex
);
}
/* Synchronize with packet receive processing. */
...
...
@@ -2795,13 +2818,19 @@ int unregister_netdevice(struct net_device *dev)
BUG_ON
(
dev_boot_phase
);
ASSERT_RTNL
();
/* Some devices call without registering for initialization unwind. */
if
(
dev
->
reg_state
==
NETREG_UNINITIALIZED
)
{
printk
(
KERN_DEBUG
"unregister_netdevice: device %s/%p never "
"was registered
\n
"
,
dev
->
name
,
dev
);
return
-
ENODEV
;
}
BUG_ON
(
dev
->
reg_state
!=
NETREG_REGISTERED
);
/* If device is running, close it first. */
if
(
dev
->
flags
&
IFF_UP
)
dev_close
(
dev
);
BUG_TRAP
(
!
dev
->
deadbeaf
);
dev
->
deadbeaf
=
1
;
/* And unlink it from device chain. */
for
(
dp
=
&
dev_base
;
(
d
=
*
dp
)
!=
NULL
;
dp
=
&
d
->
next
)
{
if
(
d
==
dev
)
{
...
...
@@ -2812,11 +2841,13 @@ int unregister_netdevice(struct net_device *dev)
}
}
if
(
!
d
)
{
printk
(
KERN_
DEBUG
"unregister_netdevice: device %s/%p never "
"was registered
\n
"
,
dev
->
name
,
dev
);
printk
(
KERN_
ERR
"unregister net_device: '%s' not found
\n
"
,
dev
->
name
);
return
-
ENODEV
;
}
dev
->
reg_state
=
NETREG_UNREGISTERING
;
synchronize_net
();
#ifdef CONFIG_NET_FASTROUTE
...
...
@@ -2826,7 +2857,6 @@ int unregister_netdevice(struct net_device *dev)
/* Shutdown queueing discipline. */
dev_shutdown
(
dev
);
net_run_sbin_hotplug
(
dev
,
0
);
/* Notify protocols, that we are about to destroy
this device. They should clean all the things.
...
...
@@ -2846,10 +2876,8 @@ int unregister_netdevice(struct net_device *dev)
free_divert_blk
(
dev
);
spin_lock
(
&
unregister_todo_lock
);
dev
->
next
=
unregister_todo
;
unregister_todo
=
dev
;
spin_unlock
(
&
unregister_todo_lock
);
/* Finish processing unregister after unlock */
net_set_todo
(
dev
);
dev_put
(
dev
);
return
0
;
...
...
@@ -2955,11 +2983,11 @@ static int __init net_dev_init(void)
* dev_alloc_name can now advance to next suitable
* name that is checked next.
*/
dev
->
deadbeaf
=
1
;
dp
=
&
dev
->
next
;
}
else
{
dp
=
&
dev
->
next
;
dev
->
ifindex
=
dev_new_index
();
dev
->
reg_state
=
NETREG_REGISTERED
;
if
(
dev
->
iflink
==
-
1
)
dev
->
iflink
=
dev
->
ifindex
;
if
(
!
dev
->
rebuild_header
)
...
...
@@ -2974,7 +3002,7 @@ static int __init net_dev_init(void)
*/
dp
=
&
dev_base
;
while
((
dev
=
*
dp
)
!=
NULL
)
{
if
(
dev
->
deadbeaf
)
{
if
(
dev
->
reg_state
!=
NETREG_REGISTERED
)
{
write_lock_bh
(
&
dev_base_lock
);
*
dp
=
dev
->
next
;
write_unlock_bh
(
&
dev_base_lock
);
...
...
@@ -3001,96 +3029,3 @@ static int __init net_dev_init(void)
}
subsys_initcall
(
net_dev_init
);
#ifdef CONFIG_HOTPLUG
struct
net_hotplug_todo
{
struct
list_head
list
;
char
ifname
[
IFNAMSIZ
];
int
is_register
;
};
static
spinlock_t
net_hotplug_list_lock
=
SPIN_LOCK_UNLOCKED
;
static
DECLARE_MUTEX
(
net_hotplug_run
);
static
struct
list_head
net_hotplug_list
=
LIST_HEAD_INIT
(
net_hotplug_list
);
static
inline
void
net_run_hotplug_one
(
struct
net_hotplug_todo
*
ent
)
{
char
*
argv
[
3
],
*
envp
[
5
],
ifname
[
12
+
IFNAMSIZ
],
action_str
[
32
];
int
i
;
sprintf
(
ifname
,
"INTERFACE=%s"
,
ent
->
ifname
);
sprintf
(
action_str
,
"ACTION=%s"
,
(
ent
->
is_register
?
"register"
:
"unregister"
));
i
=
0
;
argv
[
i
++
]
=
hotplug_path
;
argv
[
i
++
]
=
"net"
;
argv
[
i
]
=
0
;
i
=
0
;
/* minimal command environment */
envp
[
i
++
]
=
"HOME=/"
;
envp
[
i
++
]
=
"PATH=/sbin:/bin:/usr/sbin:/usr/bin"
;
envp
[
i
++
]
=
ifname
;
envp
[
i
++
]
=
action_str
;
envp
[
i
]
=
0
;
call_usermodehelper
(
argv
[
0
],
argv
,
envp
,
0
);
}
/* Run all queued hotplug requests.
* Requests are run in FIFO order.
*/
static
void
net_run_hotplug_todo
(
void
)
{
struct
list_head
list
=
LIST_HEAD_INIT
(
list
);
/* This is racy but okay since any other requests will get
* processed when the other guy does rtnl_unlock.
*/
if
(
list_empty
(
&
net_hotplug_list
))
return
;
/* Need to guard against multiple cpu's getting out of order. */
down
(
&
net_hotplug_run
);
/* Snapshot list, allow later requests */
spin_lock
(
&
net_hotplug_list_lock
);
list_splice_init
(
&
net_hotplug_list
,
&
list
);
spin_unlock
(
&
net_hotplug_list_lock
);
while
(
!
list_empty
(
&
list
))
{
struct
net_hotplug_todo
*
ent
;
ent
=
list_entry
(
list
.
next
,
struct
net_hotplug_todo
,
list
);
list_del
(
&
ent
->
list
);
net_run_hotplug_one
(
ent
);
kfree
(
ent
);
}
up
(
&
net_hotplug_run
);
}
/* Notify userspace when a netdevice event occurs,
* by running '/sbin/hotplug net' with certain
* environment variables set.
*/
static
void
net_run_sbin_hotplug
(
struct
net_device
*
dev
,
int
is_register
)
{
struct
net_hotplug_todo
*
ent
=
kmalloc
(
sizeof
(
*
ent
),
GFP_KERNEL
);
ASSERT_RTNL
();
if
(
!
ent
)
return
;
INIT_LIST_HEAD
(
&
ent
->
list
);
memcpy
(
ent
->
ifname
,
dev
->
name
,
IFNAMSIZ
);
ent
->
is_register
=
is_register
;
spin_lock
(
&
net_hotplug_list_lock
);
list_add
(
&
ent
->
list
,
&
net_hotplug_list
);
spin_unlock
(
&
net_hotplug_list_lock
);
}
#endif
net/core/net-sysfs.c
View file @
4f78b8d1
...
...
@@ -15,6 +15,11 @@
#define to_class_dev(obj) container_of(obj,struct class_device,kobj)
#define to_net_dev(class) container_of(class, struct net_device, class_dev)
static
inline
int
dev_isalive
(
const
struct
net_device
*
dev
)
{
return
dev
->
reg_state
==
NETREG_REGISTERED
;
}
/* use same locking rules as GIF* ioctl's */
static
ssize_t
netdev_show
(
const
struct
class_device
*
cd
,
char
*
buf
,
ssize_t
(
*
format
)(
const
struct
net_device
*
,
char
*
))
...
...
@@ -23,7 +28,7 @@ static ssize_t netdev_show(const struct class_device *cd, char *buf,
ssize_t
ret
=
-
EINVAL
;
read_lock
(
&
dev_base_lock
);
if
(
!
net
->
deadbeaf
)
if
(
dev_isalive
(
net
)
)
ret
=
(
*
format
)(
net
,
buf
);
read_unlock
(
&
dev_base_lock
);
...
...
@@ -60,7 +65,7 @@ static ssize_t netdev_store(struct class_device *dev,
goto
err
;
rtnl_lock
();
if
(
!
net
->
deadbeaf
)
{
if
(
dev_isalive
(
net
)
)
{
if
((
ret
=
(
*
set
)(
net
,
new
))
==
0
)
ret
=
len
;
}
...
...
@@ -97,17 +102,17 @@ static ssize_t format_addr(char *buf, const unsigned char *addr, int len)
static
ssize_t
show_address
(
struct
class_device
*
dev
,
char
*
buf
)
{
struct
net_device
*
net
=
to_net_dev
(
dev
);
if
(
net
->
deadbeaf
)
return
-
EINVAL
;
if
(
dev_isalive
(
net
))
return
format_addr
(
buf
,
net
->
dev_addr
,
net
->
addr_len
);
return
-
EINVAL
;
}
static
ssize_t
show_broadcast
(
struct
class_device
*
dev
,
char
*
buf
)
{
struct
net_device
*
net
=
to_net_dev
(
dev
);
if
(
net
->
deadbeaf
)
return
-
EINVAL
;
if
(
dev_isalive
(
net
))
return
format_addr
(
buf
,
net
->
broadcast
,
net
->
addr_len
);
return
-
EINVAL
;
}
static
CLASS_DEVICE_ATTR
(
address
,
S_IRUGO
,
show_address
,
NULL
);
...
...
@@ -152,16 +157,12 @@ static int change_tx_queue_len(struct net_device *net, unsigned long new_len)
static
ssize_t
store_tx_queue_len
(
struct
class_device
*
dev
,
const
char
*
buf
,
size_t
len
)
{
return
netdev_store
(
dev
,
buf
,
len
,
change_tx_queue_len
);
return
netdev_store
(
dev
,
buf
,
len
,
change_tx_queue_len
);
}
static
CLASS_DEVICE_ATTR
(
tx_queue_len
,
S_IRUGO
|
S_IWUSR
,
show_tx_queue_len
,
store_tx_queue_len
);
static
struct
class
net_class
=
{
.
name
=
"net"
,
};
static
struct
class_device_attribute
*
net_class_attributes
[]
=
{
&
class_device_attr_ifindex
,
...
...
@@ -263,7 +264,7 @@ netstat_attr_show(struct kobject *kobj, struct attribute *attr, char *buf)
ssize_t
ret
=
-
EINVAL
;
read_lock
(
&
dev_base_lock
);
if
(
!
dev
->
deadbeaf
&&
entry
->
show
&&
dev
->
get_stats
&&
if
(
dev_isalive
(
dev
)
&&
entry
->
show
&&
dev
->
get_stats
&&
(
stats
=
(
*
dev
->
get_stats
)(
dev
)))
ret
=
entry
->
show
(
stats
,
buf
);
read_unlock
(
&
dev_base_lock
);
...
...
@@ -279,6 +280,35 @@ static struct kobj_type netstat_ktype = {
.
default_attrs
=
default_attrs
,
};
#ifdef CONFIG_HOTPLUG
static
int
netdev_hotplug
(
struct
class_device
*
cd
,
char
**
envp
,
int
num_envp
,
char
*
buf
,
int
size
)
{
struct
net_device
*
dev
=
to_net_dev
(
cd
);
int
i
=
0
;
int
n
;
/* pass interface in env to hotplug. */
envp
[
i
++
]
=
buf
;
n
=
snprintf
(
buf
,
size
,
"INTERFACE=%s"
,
dev
->
name
)
+
1
;
buf
+=
n
;
size
-=
n
;
if
((
size
<=
0
)
||
(
i
>=
num_envp
))
return
-
ENOMEM
;
envp
[
i
]
=
0
;
return
0
;
}
#endif
static
struct
class
net_class
=
{
.
name
=
"net"
,
#ifdef CONFIG_HOTPLUG
.
hotplug
=
netdev_hotplug
,
#endif
};
/* Create sysfs entries for network device. */
int
netdev_register_sysfs
(
struct
net_device
*
net
)
{
...
...
net/decnet/dn_nsp_in.c
View file @
4f78b8d1
...
...
@@ -812,7 +812,7 @@ static int dn_nsp_rx_packet(struct sk_buff *skb)
printk
(
KERN_DEBUG
"NSP: 0x%02x 0x%02x 0x%04x 0x%04x %d
\n
"
,
(
int
)
cb
->
rt_flags
,
(
int
)
cb
->
nsp_flags
,
(
int
)
cb
->
src_port
,
(
int
)
cb
->
dst_port
,
(
int
)
sock_owned_by_user
(
sk
));
!!
sock_owned_by_user
(
sk
));
if
(
!
sock_owned_by_user
(
sk
))
ret
=
dn_nsp_backlog_rcv
(
sk
,
skb
);
else
...
...
net/ipv4/af_inet.c
View file @
4f78b8d1
...
...
@@ -1134,7 +1134,7 @@ static int __init inet_init(void)
printk
(
KERN_CRIT
"inet_init: Cannot add TCP protocol
\n
"
);
#ifdef CONFIG_IP_MULTICAST
if
(
inet_add_protocol
(
&
igmp_protocol
,
IPPROTO_IGMP
)
<
0
)
printk
(
KERN_CRIT
"inet_init: Cannot add
TC
P protocol
\n
"
);
printk
(
KERN_CRIT
"inet_init: Cannot add
IGM
P protocol
\n
"
);
#endif
/* Register the socket-side information for inet_create. */
...
...
net/ipv4/route.c
View file @
4f78b8d1
...
...
@@ -321,7 +321,7 @@ static int rt_cache_stat_get_info(char *buffer, char **start, off_t offset, int
for
(
i
=
0
;
i
<
NR_CPUS
;
i
++
)
{
if
(
!
cpu_possible
(
i
))
continue
;
len
+=
sprintf
(
buffer
+
len
,
"%08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x
\n
"
,
len
+=
sprintf
(
buffer
+
len
,
"%08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x
%08x %08x
\n
"
,
dst_entries
,
per_cpu_ptr
(
rt_cache_stat
,
i
)
->
in_hit
,
per_cpu_ptr
(
rt_cache_stat
,
i
)
->
in_slow_tot
,
...
...
@@ -338,7 +338,9 @@ static int rt_cache_stat_get_info(char *buffer, char **start, off_t offset, int
per_cpu_ptr
(
rt_cache_stat
,
i
)
->
gc_total
,
per_cpu_ptr
(
rt_cache_stat
,
i
)
->
gc_ignored
,
per_cpu_ptr
(
rt_cache_stat
,
i
)
->
gc_goal_miss
,
per_cpu_ptr
(
rt_cache_stat
,
i
)
->
gc_dst_overflow
per_cpu_ptr
(
rt_cache_stat
,
i
)
->
gc_dst_overflow
,
per_cpu_ptr
(
rt_cache_stat
,
i
)
->
in_hlist_search
,
per_cpu_ptr
(
rt_cache_stat
,
i
)
->
out_hlist_search
);
}
...
...
@@ -1786,6 +1788,7 @@ int ip_route_input(struct sk_buff *skb, u32 daddr, u32 saddr,
skb
->
dst
=
(
struct
dst_entry
*
)
rth
;
return
0
;
}
RT_CACHE_STAT_INC
(
in_hlist_search
);
}
rcu_read_unlock
();
...
...
@@ -2153,6 +2156,7 @@ int __ip_route_output_key(struct rtable **rp, const struct flowi *flp)
*
rp
=
rth
;
return
0
;
}
RT_CACHE_STAT_INC
(
out_hlist_search
);
}
rcu_read_unlock
();
...
...
net/ipv4/tcp_ipv4.c
View file @
4f78b8d1
...
...
@@ -1363,7 +1363,7 @@ static inline void syn_flood_warning(struct sk_buff *skb)
{
static
unsigned
long
warntime
;
if
(
jiffies
-
warntime
>
HZ
*
60
)
{
if
(
time_after
(
jiffies
,
(
warntime
+
HZ
*
60
))
)
{
warntime
=
jiffies
;
printk
(
KERN_INFO
"possible SYN flooding on port %d. Sending cookies.
\n
"
,
...
...
net/ipv4/tcp_minisocks.c
View file @
4f78b8d1
...
...
@@ -563,7 +563,7 @@ void tcp_tw_schedule(struct tcp_tw_bucket *tw, int timeo)
tcp_twcal_timer
.
expires
=
tcp_twcal_jiffie
+
(
slot
<<
TCP_TW_RECYCLE_TICK
);
add_timer
(
&
tcp_twcal_timer
);
}
else
{
if
(
(
long
)(
tcp_twcal_timer
.
expires
-
jiffies
)
>
(
slot
<<
TCP_TW_RECYCLE_TICK
))
if
(
time_after
(
tcp_twcal_timer
.
expires
,
jiffies
+
(
slot
<<
TCP_TW_RECYCLE_TICK
)
))
mod_timer
(
&
tcp_twcal_timer
,
jiffies
+
(
slot
<<
TCP_TW_RECYCLE_TICK
));
slot
=
(
tcp_twcal_hand
+
slot
)
&
(
TCP_TW_RECYCLE_SLOTS
-
1
);
}
...
...
@@ -596,7 +596,7 @@ void tcp_twcal_tick(unsigned long dummy)
j
=
tcp_twcal_jiffie
;
for
(
n
=
0
;
n
<
TCP_TW_RECYCLE_SLOTS
;
n
++
)
{
if
(
(
long
)(
j
-
now
)
<=
0
)
{
if
(
time_before_eq
(
j
,
now
)
)
{
struct
tcp_tw_bucket
*
tw
;
while
((
tw
=
tcp_twcal_row
[
slot
])
!=
NULL
)
{
...
...
net/ipv4/tcp_timer.c
View file @
4f78b8d1
...
...
@@ -227,7 +227,7 @@ static void tcp_delack_timer(unsigned long data)
if
(
sk
->
sk_state
==
TCP_CLOSE
||
!
(
tp
->
ack
.
pending
&
TCP_ACK_TIMER
))
goto
out
;
if
(
(
long
)(
tp
->
ack
.
timeout
-
jiffies
)
>
0
)
{
if
(
time_after
(
tp
->
ack
.
timeout
,
jiffies
)
)
{
if
(
!
mod_timer
(
&
tp
->
delack_timer
,
tp
->
ack
.
timeout
))
sock_hold
(
sk
);
goto
out
;
...
...
@@ -436,7 +436,7 @@ static void tcp_write_timer(unsigned long data)
if
(
sk
->
sk_state
==
TCP_CLOSE
||
!
tp
->
pending
)
goto
out
;
if
(
(
long
)(
tp
->
timeout
-
jiffies
)
>
0
)
{
if
(
time_after
(
tp
->
timeout
,
jiffies
)
)
{
if
(
!
mod_timer
(
&
tp
->
retransmit_timer
,
tp
->
timeout
))
sock_hold
(
sk
);
goto
out
;
...
...
@@ -516,7 +516,7 @@ static void tcp_synack_timer(struct sock *sk)
do
{
reqp
=&
lopt
->
syn_table
[
i
];
while
((
req
=
*
reqp
)
!=
NULL
)
{
if
(
(
long
)(
now
-
req
->
expires
)
>=
0
)
{
if
(
time_after_eq
(
now
,
req
->
expires
)
)
{
if
((
req
->
retrans
<
thresh
||
(
req
->
acked
&&
req
->
retrans
<
max_retries
))
&&
!
req
->
class
->
rtx_syn_ack
(
sk
,
req
,
NULL
))
{
...
...
net/ipv6/ah6.c
View file @
4f78b8d1
...
...
@@ -36,6 +36,114 @@
#include <net/xfrm.h>
#include <asm/scatterlist.h>
static
int
zero_out_mutable_opts
(
struct
ipv6_opt_hdr
*
opthdr
)
{
u8
*
opt
=
(
u8
*
)
opthdr
;
int
len
=
ipv6_optlen
(
opthdr
);
int
off
=
0
;
int
optlen
=
0
;
off
+=
2
;
len
-=
2
;
while
(
len
>
0
)
{
switch
(
opt
[
off
])
{
case
IPV6_TLV_PAD0
:
optlen
=
1
;
break
;
default:
if
(
len
<
2
)
goto
bad
;
optlen
=
opt
[
off
+
1
]
+
2
;
if
(
len
<
optlen
)
goto
bad
;
if
(
opt
[
off
]
&
0x20
)
memset
(
&
opt
[
off
+
2
],
0
,
opt
[
off
+
1
]);
break
;
}
off
+=
optlen
;
len
-=
optlen
;
}
if
(
len
==
0
)
return
1
;
bad:
return
0
;
}
static
int
ipv6_clear_mutable_options
(
struct
sk_buff
*
skb
,
u16
*
nh_offset
,
int
dir
)
{
u16
offset
=
sizeof
(
struct
ipv6hdr
);
struct
ipv6_opt_hdr
*
exthdr
=
(
struct
ipv6_opt_hdr
*
)(
skb
->
nh
.
raw
+
offset
);
unsigned
int
packet_len
=
skb
->
tail
-
skb
->
nh
.
raw
;
u8
nexthdr
=
skb
->
nh
.
ipv6h
->
nexthdr
;
u8
nextnexthdr
=
0
;
*
nh_offset
=
((
unsigned
char
*
)
&
skb
->
nh
.
ipv6h
->
nexthdr
)
-
skb
->
nh
.
raw
;
while
(
offset
+
1
<=
packet_len
)
{
switch
(
nexthdr
)
{
case
NEXTHDR_HOP
:
*
nh_offset
=
offset
;
offset
+=
ipv6_optlen
(
exthdr
);
if
(
!
zero_out_mutable_opts
(
exthdr
))
{
if
(
net_ratelimit
())
printk
(
KERN_WARNING
"overrun hopopts
\n
"
);
return
0
;
}
nexthdr
=
exthdr
->
nexthdr
;
exthdr
=
(
struct
ipv6_opt_hdr
*
)(
skb
->
nh
.
raw
+
offset
);
break
;
case
NEXTHDR_ROUTING
:
*
nh_offset
=
offset
;
offset
+=
ipv6_optlen
(
exthdr
);
((
struct
ipv6_rt_hdr
*
)
exthdr
)
->
segments_left
=
0
;
nexthdr
=
exthdr
->
nexthdr
;
exthdr
=
(
struct
ipv6_opt_hdr
*
)(
skb
->
nh
.
raw
+
offset
);
break
;
case
NEXTHDR_DEST
:
*
nh_offset
=
offset
;
offset
+=
ipv6_optlen
(
exthdr
);
if
(
!
zero_out_mutable_opts
(
exthdr
))
{
if
(
net_ratelimit
())
printk
(
KERN_WARNING
"overrun destopt
\n
"
);
return
0
;
}
nexthdr
=
exthdr
->
nexthdr
;
exthdr
=
(
struct
ipv6_opt_hdr
*
)(
skb
->
nh
.
raw
+
offset
);
break
;
case
NEXTHDR_AUTH
:
if
(
dir
==
XFRM_POLICY_OUT
)
{
memset
(((
struct
ipv6_auth_hdr
*
)
exthdr
)
->
auth_data
,
0
,
(((
struct
ipv6_auth_hdr
*
)
exthdr
)
->
hdrlen
-
1
)
<<
2
);
}
if
(
exthdr
->
nexthdr
==
NEXTHDR_DEST
)
{
offset
+=
(((
struct
ipv6_auth_hdr
*
)
exthdr
)
->
hdrlen
+
2
)
<<
2
;
exthdr
=
(
struct
ipv6_opt_hdr
*
)(
skb
->
nh
.
raw
+
offset
);
nextnexthdr
=
exthdr
->
nexthdr
;
if
(
!
zero_out_mutable_opts
(
exthdr
))
{
if
(
net_ratelimit
())
printk
(
KERN_WARNING
"overrun destopt
\n
"
);
return
0
;
}
}
return
nexthdr
;
default
:
return
nexthdr
;
}
}
return
nexthdr
;
}
int
ah6_output
(
struct
sk_buff
*
skb
)
{
int
err
;
...
...
@@ -80,7 +188,7 @@ int ah6_output(struct sk_buff *skb)
memcpy
(
iph
,
skb
->
data
,
hdr_len
);
skb
->
nh
.
ipv6h
=
(
struct
ipv6hdr
*
)
skb_push
(
skb
,
x
->
props
.
header_len
);
memcpy
(
skb
->
nh
.
ipv6h
,
iph
,
hdr_len
);
nexthdr
=
xfrm
6_clear_mutable_options
(
skb
,
&
nh_offset
,
XFRM_POLICY_OUT
);
nexthdr
=
ipv
6_clear_mutable_options
(
skb
,
&
nh_offset
,
XFRM_POLICY_OUT
);
if
(
nexthdr
==
0
)
goto
error
;
...
...
@@ -138,20 +246,46 @@ int ah6_output(struct sk_buff *skb)
int
ah6_input
(
struct
xfrm_state
*
x
,
struct
xfrm_decap_state
*
decap
,
struct
sk_buff
*
skb
)
{
int
ah_hlen
;
struct
ipv6hdr
*
iph
;
/*
* Before process AH
* [IPv6][Ext1][Ext2][AH][Dest][Payload]
* |<-------------->| hdr_len
* |<------------------------>| cleared_hlen
*
* To erase AH:
* Keeping copy of cleared headers. After AH processing,
* Moving the pointer of skb->nh.raw by using skb_pull as long as AH
* header length. Then copy back the copy as long as hdr_len
* If destination header following AH exists, copy it into after [Ext2].
*
* |<>|[IPv6][Ext1][Ext2][Dest][Payload]
* There is offset of AH before IPv6 header after the process.
*/
struct
ipv6hdr
*
iph
=
skb
->
nh
.
ipv6h
;
struct
ipv6_auth_hdr
*
ah
;
struct
ah_data
*
ahp
;
unsigned
char
*
tmp_hdr
=
NULL
;
int
hdr_len
=
skb
->
h
.
raw
-
skb
->
nh
.
raw
;
u16
hdr_len
=
skb
->
data
-
skb
->
nh
.
raw
;
u16
ah_hlen
;
u16
cleared_hlen
=
hdr_len
;
u16
nh_offset
=
0
;
u8
nexthdr
=
0
;
u8
*
prevhdr
;
if
(
!
pskb_may_pull
(
skb
,
sizeof
(
struct
ip_auth_hdr
)))
goto
out
;
ah
=
(
struct
ipv6_auth_hdr
*
)
skb
->
data
;
ahp
=
x
->
data
;
nexthdr
=
ah
->
nexthdr
;
ah_hlen
=
(
ah
->
hdrlen
+
2
)
<<
2
;
cleared_hlen
+=
ah_hlen
;
if
(
nexthdr
==
NEXTHDR_DEST
)
{
struct
ipv6_opt_hdr
*
dsthdr
=
(
struct
ipv6_opt_hdr
*
)(
skb
->
data
+
ah_hlen
);
cleared_hlen
+=
ipv6_optlen
(
dsthdr
);
}
if
(
ah_hlen
!=
XFRM_ALIGN8
(
sizeof
(
struct
ipv6_auth_hdr
)
+
ahp
->
icv_full_len
)
&&
ah_hlen
!=
XFRM_ALIGN8
(
sizeof
(
struct
ipv6_auth_hdr
)
+
ahp
->
icv_trunc_len
))
...
...
@@ -166,12 +300,16 @@ int ah6_input(struct xfrm_state *x, struct xfrm_decap_state *decap, struct sk_bu
pskb_expand_head
(
skb
,
0
,
0
,
GFP_ATOMIC
))
goto
out
;
tmp_hdr
=
kmalloc
(
hdr_
len
,
GFP_ATOMIC
);
tmp_hdr
=
kmalloc
(
cleared_h
len
,
GFP_ATOMIC
);
if
(
!
tmp_hdr
)
goto
out
;
memcpy
(
tmp_hdr
,
skb
->
nh
.
raw
,
hdr_len
);
ah
=
(
struct
ipv6_auth_hdr
*
)
skb
->
data
;
iph
=
skb
->
nh
.
ipv6h
;
memcpy
(
tmp_hdr
,
skb
->
nh
.
raw
,
cleared_hlen
);
ipv6_clear_mutable_options
(
skb
,
&
nh_offset
,
XFRM_POLICY_IN
);
iph
->
priority
=
0
;
iph
->
flow_lbl
[
0
]
=
0
;
iph
->
flow_lbl
[
1
]
=
0
;
iph
->
flow_lbl
[
2
]
=
0
;
iph
->
hop_limit
=
0
;
{
u8
auth_data
[
ahp
->
icv_trunc_len
];
...
...
@@ -187,9 +325,15 @@ int ah6_input(struct xfrm_state *x, struct xfrm_decap_state *decap, struct sk_bu
}
}
nexthdr
=
((
struct
ipv6hdr
*
)
tmp_hdr
)
->
nexthdr
=
ah
->
nexthdr
;
skb
->
nh
.
raw
=
skb_pull
(
skb
,
(
ah
->
hdrlen
+
2
)
<<
2
);
skb
->
nh
.
raw
=
skb_pull
(
skb
,
ah_hlen
);
memcpy
(
skb
->
nh
.
raw
,
tmp_hdr
,
hdr_len
);
if
(
nexthdr
==
NEXTHDR_DEST
)
{
memcpy
(
skb
->
nh
.
raw
+
hdr_len
,
tmp_hdr
+
hdr_len
+
ah_hlen
,
cleared_hlen
-
hdr_len
-
ah_hlen
);
}
prevhdr
=
(
u8
*
)(
skb
->
nh
.
raw
+
nh_offset
);
*
prevhdr
=
nexthdr
;
skb
->
nh
.
ipv6h
->
payload_len
=
htons
(
skb
->
len
-
sizeof
(
struct
ipv6hdr
));
skb_pull
(
skb
,
hdr_len
);
skb
->
h
.
raw
=
skb
->
data
;
...
...
net/ipv6/ipv6_syms.c
View file @
4f78b8d1
...
...
@@ -37,7 +37,6 @@ EXPORT_SYMBOL(in6addr_loopback);
EXPORT_SYMBOL
(
in6_dev_finish_destroy
);
EXPORT_SYMBOL
(
ip6_find_1stfragopt
);
EXPORT_SYMBOL
(
xfrm6_rcv
);
EXPORT_SYMBOL
(
xfrm6_clear_mutable_options
);
EXPORT_SYMBOL
(
rt6_lookup
);
EXPORT_SYMBOL
(
fl6_sock_lookup
);
EXPORT_SYMBOL
(
ipv6_ext_hdr
);
...
...
net/ipv6/xfrm6_input.c
View file @
4f78b8d1
...
...
@@ -15,114 +15,6 @@
static
kmem_cache_t
*
secpath_cachep
;
static
int
zero_out_mutable_opts
(
struct
ipv6_opt_hdr
*
opthdr
)
{
u8
*
opt
=
(
u8
*
)
opthdr
;
int
len
=
ipv6_optlen
(
opthdr
);
int
off
=
0
;
int
optlen
=
0
;
off
+=
2
;
len
-=
2
;
while
(
len
>
0
)
{
switch
(
opt
[
off
])
{
case
IPV6_TLV_PAD0
:
optlen
=
1
;
break
;
default:
if
(
len
<
2
)
goto
bad
;
optlen
=
opt
[
off
+
1
]
+
2
;
if
(
len
<
optlen
)
goto
bad
;
if
(
opt
[
off
]
&
0x20
)
memset
(
&
opt
[
off
+
2
],
0
,
opt
[
off
+
1
]);
break
;
}
off
+=
optlen
;
len
-=
optlen
;
}
if
(
len
==
0
)
return
1
;
bad:
return
0
;
}
int
xfrm6_clear_mutable_options
(
struct
sk_buff
*
skb
,
u16
*
nh_offset
,
int
dir
)
{
u16
offset
=
sizeof
(
struct
ipv6hdr
);
struct
ipv6_opt_hdr
*
exthdr
=
(
struct
ipv6_opt_hdr
*
)(
skb
->
nh
.
raw
+
offset
);
unsigned
int
packet_len
=
skb
->
tail
-
skb
->
nh
.
raw
;
u8
nexthdr
=
skb
->
nh
.
ipv6h
->
nexthdr
;
u8
nextnexthdr
=
0
;
*
nh_offset
=
((
unsigned
char
*
)
&
skb
->
nh
.
ipv6h
->
nexthdr
)
-
skb
->
nh
.
raw
;
while
(
offset
+
1
<=
packet_len
)
{
switch
(
nexthdr
)
{
case
NEXTHDR_HOP
:
*
nh_offset
=
offset
;
offset
+=
ipv6_optlen
(
exthdr
);
if
(
!
zero_out_mutable_opts
(
exthdr
))
{
if
(
net_ratelimit
())
printk
(
KERN_WARNING
"overrun hopopts
\n
"
);
return
0
;
}
nexthdr
=
exthdr
->
nexthdr
;
exthdr
=
(
struct
ipv6_opt_hdr
*
)(
skb
->
nh
.
raw
+
offset
);
break
;
case
NEXTHDR_ROUTING
:
*
nh_offset
=
offset
;
offset
+=
ipv6_optlen
(
exthdr
);
((
struct
ipv6_rt_hdr
*
)
exthdr
)
->
segments_left
=
0
;
nexthdr
=
exthdr
->
nexthdr
;
exthdr
=
(
struct
ipv6_opt_hdr
*
)(
skb
->
nh
.
raw
+
offset
);
break
;
case
NEXTHDR_DEST
:
*
nh_offset
=
offset
;
offset
+=
ipv6_optlen
(
exthdr
);
if
(
!
zero_out_mutable_opts
(
exthdr
))
{
if
(
net_ratelimit
())
printk
(
KERN_WARNING
"overrun destopt
\n
"
);
return
0
;
}
nexthdr
=
exthdr
->
nexthdr
;
exthdr
=
(
struct
ipv6_opt_hdr
*
)(
skb
->
nh
.
raw
+
offset
);
break
;
case
NEXTHDR_AUTH
:
if
(
dir
==
XFRM_POLICY_OUT
)
{
memset
(((
struct
ipv6_auth_hdr
*
)
exthdr
)
->
auth_data
,
0
,
(((
struct
ipv6_auth_hdr
*
)
exthdr
)
->
hdrlen
-
1
)
<<
2
);
}
if
(
exthdr
->
nexthdr
==
NEXTHDR_DEST
)
{
offset
+=
(((
struct
ipv6_auth_hdr
*
)
exthdr
)
->
hdrlen
+
2
)
<<
2
;
exthdr
=
(
struct
ipv6_opt_hdr
*
)(
skb
->
nh
.
raw
+
offset
);
nextnexthdr
=
exthdr
->
nexthdr
;
if
(
!
zero_out_mutable_opts
(
exthdr
))
{
if
(
net_ratelimit
())
printk
(
KERN_WARNING
"overrun destopt
\n
"
);
return
0
;
}
}
return
nexthdr
;
default
:
return
nexthdr
;
}
}
return
nexthdr
;
}
int
xfrm6_rcv
(
struct
sk_buff
**
pskb
,
unsigned
int
*
nhoffp
)
{
struct
sk_buff
*
skb
=
*
pskb
;
...
...
@@ -132,26 +24,12 @@ int xfrm6_rcv(struct sk_buff **pskb, unsigned int *nhoffp)
struct
xfrm_state
*
x
;
int
xfrm_nr
=
0
;
int
decaps
=
0
;
struct
ipv6hdr
*
hdr
=
skb
->
nh
.
ipv6h
;
unsigned
char
*
tmp_hdr
=
NULL
;
int
hdr_len
=
0
;
u16
nh_offset
=
0
;
int
nexthdr
=
0
;
u8
*
prevhdr
=
NULL
;
nh_offset
=
((
unsigned
char
*
)
&
skb
->
nh
.
ipv6h
->
nexthdr
)
-
skb
->
nh
.
raw
;
hdr_len
=
sizeof
(
struct
ipv6hdr
);
tmp_hdr
=
kmalloc
(
hdr_len
,
GFP_ATOMIC
);
if
(
!
tmp_hdr
)
goto
drop
;
memcpy
(
tmp_hdr
,
skb
->
nh
.
raw
,
hdr_len
);
nexthdr
=
xfrm6_clear_mutable_options
(
skb
,
&
nh_offset
,
XFRM_POLICY_IN
);
hdr
->
priority
=
0
;
hdr
->
flow_lbl
[
0
]
=
0
;
hdr
->
flow_lbl
[
1
]
=
0
;
hdr
->
flow_lbl
[
2
]
=
0
;
hdr
->
hop_limit
=
0
;
ip6_find_1stfragopt
(
skb
,
&
prevhdr
);
nexthdr
=
*
prevhdr
;
*
nhoffp
=
prevhdr
-
skb
->
nh
.
raw
;
if
((
err
=
xfrm_parse_spi
(
skb
,
nexthdr
,
&
spi
,
&
seq
))
!=
0
)
goto
drop
;
...
...
@@ -204,12 +82,6 @@ int xfrm6_rcv(struct sk_buff **pskb, unsigned int *nhoffp)
goto
drop
;
}
while
(
!
err
);
if
(
!
decaps
)
{
memcpy
(
skb
->
nh
.
raw
,
tmp_hdr
,
hdr_len
);
skb
->
nh
.
raw
[
nh_offset
]
=
nexthdr
;
skb
->
nh
.
ipv6h
->
payload_len
=
htons
(
hdr_len
+
skb
->
len
-
sizeof
(
struct
ipv6hdr
));
}
/* Allocate new secpath or COW existing one. */
if
(
!
skb
->
sp
||
atomic_read
(
&
skb
->
sp
->
refcnt
)
!=
1
)
{
kmem_cache_t
*
pool
=
skb
->
sp
?
skb
->
sp
->
pool
:
secpath_cachep
;
...
...
@@ -243,7 +115,6 @@ int xfrm6_rcv(struct sk_buff **pskb, unsigned int *nhoffp)
netif_rx
(
skb
);
return
-
1
;
}
else
{
*
nhoffp
=
nh_offset
;
return
1
;
}
...
...
@@ -251,7 +122,6 @@ int xfrm6_rcv(struct sk_buff **pskb, unsigned int *nhoffp)
spin_unlock
(
&
x
->
lock
);
xfrm_state_put
(
x
);
drop:
if
(
tmp_hdr
)
kfree
(
tmp_hdr
);
while
(
--
xfrm_nr
>=
0
)
xfrm_state_put
(
xfrm_vec
[
xfrm_nr
].
xvec
);
kfree_skb
(
skb
);
...
...
net/xfrm/xfrm_state.c
View file @
4f78b8d1
...
...
@@ -513,7 +513,7 @@ xfrm_alloc_spi(struct xfrm_state *x, u32 minspi, u32 maxspi)
maxspi
=
ntohl
(
maxspi
);
for
(
h
=
0
;
h
<
maxspi
-
minspi
+
1
;
h
++
)
{
spi
=
minspi
+
net_random
()
%
(
maxspi
-
minspi
+
1
);
x0
=
xfrm_state_lookup
(
&
x
->
id
.
daddr
,
minspi
,
x
->
id
.
proto
,
x
->
props
.
family
);
x0
=
xfrm_state_lookup
(
&
x
->
id
.
daddr
,
htonl
(
spi
)
,
x
->
id
.
proto
,
x
->
props
.
family
);
if
(
x0
==
NULL
)
break
;
xfrm_state_put
(
x0
);
...
...
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