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
eb2e01d8
Commit
eb2e01d8
authored
May 22, 2002
by
David S. Miller
Browse files
Options
Browse Files
Download
Plain Diff
Merge
http://kernel-acme.bkbits.net:8080/net-cleanups-2.5
into nuts.ninka.net:/home/davem/src/BK/net-2.5
parents
d0f0cde1
3d588ade
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
648 additions
and
548 deletions
+648
-548
net/ipv4/af_inet.c
net/ipv4/af_inet.c
+173
-181
net/ipv4/devinet.c
net/ipv4/devinet.c
+475
-367
No files found.
net/ipv4/af_inet.c
View file @
eb2e01d8
...
@@ -21,30 +21,34 @@
...
@@ -21,30 +21,34 @@
* so sockets that fail to connect
* so sockets that fail to connect
* don't return -EINPROGRESS.
* don't return -EINPROGRESS.
* Alan Cox : Asynchronous I/O support
* Alan Cox : Asynchronous I/O support
* Alan Cox : Keep correct socket pointer on sock structures
* Alan Cox : Keep correct socket pointer on sock
* structures
* when accept() ed
* when accept() ed
* Alan Cox : Semantics of SO_LINGER aren't state
moved
* Alan Cox : Semantics of SO_LINGER aren't state
*
to close when you look carefully. With
*
moved to close when you look carefully.
*
this fixed and the accept bug fixed
*
With this fixed and the accept bug fixed
* some RPC stuff seems happier.
* some RPC stuff seems happier.
* Niibe Yutaka : 4.4BSD style write async I/O
* Niibe Yutaka : 4.4BSD style write async I/O
* Alan Cox,
* Alan Cox,
* Tony Gale : Fixed reuse semantics.
* Tony Gale : Fixed reuse semantics.
* Alan Cox : bind() shouldn't abort existing but dead
* Alan Cox : bind() shouldn't abort existing but dead
* sockets. Stops FTP netin:.. I hope.
* sockets. Stops FTP netin:.. I hope.
* Alan Cox : bind() works correctly for RAW sockets. Note
* Alan Cox : bind() works correctly for RAW sockets.
* that FreeBSD at least was broken in this respect
* Note that FreeBSD at least was broken
* so be careful with compatibility tests...
* in this respect so be careful with
* compatibility tests...
* Alan Cox : routing cache support
* Alan Cox : routing cache support
* Alan Cox : memzero the socket structure for compactness.
* Alan Cox : memzero the socket structure for
* compactness.
* Matt Day : nonblock connect error handler
* Matt Day : nonblock connect error handler
* Alan Cox : Allow large numbers of pending sockets
* Alan Cox : Allow large numbers of pending sockets
* (eg for big web sites), but only if
* (eg for big web sites), but only if
* specifically application requested.
* specifically application requested.
* Alan Cox : New buffering throughout IP. Used dumbly.
* Alan Cox : New buffering throughout IP. Used
* dumbly.
* Alan Cox : New buffering now used smartly.
* Alan Cox : New buffering now used smartly.
* Alan Cox : BSD rather than common sense
interpretation of
* Alan Cox : BSD rather than common sense
* listen.
*
interpretation of
listen.
* Germano Caronni : Assorted small races.
* Germano Caronni : Assorted small races.
* Alan Cox : sendmsg/recvmsg basic support.
* Alan Cox : sendmsg/recvmsg basic support.
* Alan Cox : Only sendmsg/recvmsg now supported.
* Alan Cox : Only sendmsg/recvmsg now supported.
...
@@ -117,7 +121,7 @@
...
@@ -117,7 +121,7 @@
#include <linux/wireless.h>
/* Note : will define WIRELESS_EXT */
#include <linux/wireless.h>
/* Note : will define WIRELESS_EXT */
#endif
/* CONFIG_NET_RADIO || CONFIG_NET_PCMCIA_RADIO */
#endif
/* CONFIG_NET_RADIO || CONFIG_NET_PCMCIA_RADIO */
struct
linux_mib
net_statistics
[
NR_CPUS
*
2
];
struct
linux_mib
net_statistics
[
NR_CPUS
*
2
];
#ifdef INET_REFCNT_DEBUG
#ifdef INET_REFCNT_DEBUG
atomic_t
inet_sock_nr
;
atomic_t
inet_sock_nr
;
...
@@ -132,7 +136,7 @@ extern int udp_get_info(char *, char **, off_t, int);
...
@@ -132,7 +136,7 @@ extern int udp_get_info(char *, char **, off_t, int);
extern
void
ip_mc_drop_socket
(
struct
sock
*
sk
);
extern
void
ip_mc_drop_socket
(
struct
sock
*
sk
);
#ifdef CONFIG_DLCI
#ifdef CONFIG_DLCI
extern
int
dlci_ioctl
(
unsigned
int
,
void
*
);
extern
int
dlci_ioctl
(
unsigned
int
,
void
*
);
#endif
#endif
#ifdef CONFIG_DLCI_MODULE
#ifdef CONFIG_DLCI_MODULE
...
@@ -177,17 +181,18 @@ void inet_sock_destruct(struct sock *sk)
...
@@ -177,17 +181,18 @@ void inet_sock_destruct(struct sock *sk)
return
;
return
;
}
}
BUG_TRAP
(
atomic_read
(
&
sk
->
rmem_alloc
)
==
0
);
BUG_TRAP
(
!
atomic_read
(
&
sk
->
rmem_alloc
)
);
BUG_TRAP
(
atomic_read
(
&
sk
->
wmem_alloc
)
==
0
);
BUG_TRAP
(
!
atomic_read
(
&
sk
->
wmem_alloc
)
);
BUG_TRAP
(
sk
->
wmem_queued
==
0
);
BUG_TRAP
(
!
sk
->
wmem_queued
);
BUG_TRAP
(
sk
->
forward_alloc
==
0
);
BUG_TRAP
(
!
sk
->
forward_alloc
);
if
(
inet
->
opt
)
if
(
inet
->
opt
)
kfree
(
inet
->
opt
);
kfree
(
inet
->
opt
);
dst_release
(
sk
->
dst_cache
);
dst_release
(
sk
->
dst_cache
);
#ifdef INET_REFCNT_DEBUG
#ifdef INET_REFCNT_DEBUG
atomic_dec
(
&
inet_sock_nr
);
atomic_dec
(
&
inet_sock_nr
);
printk
(
KERN_DEBUG
"INET socket %p released, %d are still alive
\n
"
,
sk
,
atomic_read
(
&
inet_sock_nr
));
printk
(
KERN_DEBUG
"INET socket %p released, %d are still alive
\n
"
,
sk
,
atomic_read
(
&
inet_sock_nr
));
#endif
#endif
}
}
...
@@ -221,9 +226,9 @@ void inet_sock_release(struct sock *sk)
...
@@ -221,9 +226,9 @@ void inet_sock_release(struct sock *sk)
sock_orphan
(
sk
);
sock_orphan
(
sk
);
#ifdef INET_REFCNT_DEBUG
#ifdef INET_REFCNT_DEBUG
if
(
atomic_read
(
&
sk
->
refcnt
)
!=
1
)
{
if
(
atomic_read
(
&
sk
->
refcnt
)
!=
1
)
printk
(
KERN_DEBUG
"Destruction inet %p delayed, c=%d
\n
"
,
sk
,
atomic_read
(
&
sk
->
refcnt
));
printk
(
KERN_DEBUG
"Destruction inet %p delayed, c=%d
\n
"
,
}
sk
,
atomic_read
(
&
sk
->
refcnt
));
#endif
#endif
sock_put
(
sk
);
sock_put
(
sk
);
}
}
...
@@ -235,17 +240,15 @@ void inet_sock_release(struct sock *sk)
...
@@ -235,17 +240,15 @@ void inet_sock_release(struct sock *sk)
* the work.
* the work.
*/
*/
/*
/*
* Set socket options on an inet socket.
* Set socket options on an inet socket.
*/
*/
int
inet_setsockopt
(
struct
socket
*
sock
,
int
level
,
int
optname
,
int
inet_setsockopt
(
struct
socket
*
sock
,
int
level
,
int
optname
,
char
*
optval
,
int
optlen
)
char
*
optval
,
int
optlen
)
{
{
struct
sock
*
sk
=
sock
->
sk
;
struct
sock
*
sk
=
sock
->
sk
;
return
sk
->
prot
->
setsockopt
(
sk
,
level
,
optname
,
optval
,
optlen
);
return
sk
->
prot
->
setsockopt
(
sk
,
level
,
optname
,
optval
,
optlen
);
}
}
/*
/*
...
@@ -259,9 +262,9 @@ int inet_setsockopt(struct socket *sock, int level, int optname,
...
@@ -259,9 +262,9 @@ int inet_setsockopt(struct socket *sock, int level, int optname,
int
inet_getsockopt
(
struct
socket
*
sock
,
int
level
,
int
optname
,
int
inet_getsockopt
(
struct
socket
*
sock
,
int
level
,
int
optname
,
char
*
optval
,
int
*
optlen
)
char
*
optval
,
int
*
optlen
)
{
{
struct
sock
*
sk
=
sock
->
sk
;
struct
sock
*
sk
=
sock
->
sk
;
return
sk
->
prot
->
getsockopt
(
sk
,
level
,
optname
,
optval
,
optlen
);
return
sk
->
prot
->
getsockopt
(
sk
,
level
,
optname
,
optval
,
optlen
);
}
}
/*
/*
...
@@ -270,11 +273,12 @@ int inet_getsockopt(struct socket *sock, int level, int optname,
...
@@ -270,11 +273,12 @@ int inet_getsockopt(struct socket *sock, int level, int optname,
static
int
inet_autobind
(
struct
sock
*
sk
)
static
int
inet_autobind
(
struct
sock
*
sk
)
{
{
struct
inet_opt
*
inet
=
inet_sk
(
sk
)
;
struct
inet_opt
*
inet
;
/* We may need to bind the socket. */
/* We may need to bind the socket. */
lock_sock
(
sk
);
lock_sock
(
sk
);
inet
=
inet_sk
(
sk
);
if
(
!
inet
->
num
)
{
if
(
!
inet
->
num
)
{
if
(
sk
->
prot
->
get_port
(
sk
,
0
)
!=
0
)
{
if
(
sk
->
prot
->
get_port
(
sk
,
0
))
{
release_sock
(
sk
);
release_sock
(
sk
);
return
-
EAGAIN
;
return
-
EAGAIN
;
}
}
...
@@ -287,7 +291,6 @@ static int inet_autobind(struct sock *sk)
...
@@ -287,7 +291,6 @@ static int inet_autobind(struct sock *sk)
/*
/*
* Move a socket into listening state.
* Move a socket into listening state.
*/
*/
int
inet_listen
(
struct
socket
*
sock
,
int
backlog
)
int
inet_listen
(
struct
socket
*
sock
,
int
backlog
)
{
{
struct
sock
*
sk
=
sock
->
sk
;
struct
sock
*
sk
=
sock
->
sk
;
...
@@ -301,7 +304,7 @@ int inet_listen(struct socket *sock, int backlog)
...
@@ -301,7 +304,7 @@ int inet_listen(struct socket *sock, int backlog)
goto
out
;
goto
out
;
old_state
=
sk
->
state
;
old_state
=
sk
->
state
;
if
(
!
((
1
<<
old_state
)
&
(
TCPF_CLOSE
|
TCPF_LISTEN
)))
if
(
!
((
1
<<
old_state
)
&
(
TCPF_CLOSE
|
TCPF_LISTEN
)))
goto
out
;
goto
out
;
/* Really, if the socket is already in listen state
/* Really, if the socket is already in listen state
...
@@ -352,12 +355,13 @@ static int inet_create(struct socket *sock, int protocol)
...
@@ -352,12 +355,13 @@ static int inet_create(struct socket *sock, int protocol)
struct
list_head
*
p
;
struct
list_head
*
p
;
struct
inet_protosw
*
answer
;
struct
inet_protosw
*
answer
;
struct
inet_opt
*
inet
;
struct
inet_opt
*
inet
;
int
err
=
-
ENOBUFS
;
sock
->
state
=
SS_UNCONNECTED
;
sock
->
state
=
SS_UNCONNECTED
;
sk
=
sk_alloc
(
PF_INET
,
GFP_KERNEL
,
inet_sk_size
(
protocol
),
sk
=
sk_alloc
(
PF_INET
,
GFP_KERNEL
,
inet_sk_size
(
protocol
),
inet_sk_slab
(
protocol
));
inet_sk_slab
(
protocol
));
if
(
sk
==
NULL
)
if
(
!
sk
)
goto
do_oom
;
goto
out
;
/* Look for the requested type/protocol pair. */
/* Look for the requested type/protocol pair. */
answer
=
NULL
;
answer
=
NULL
;
...
@@ -382,13 +386,16 @@ static int inet_create(struct socket *sock, int protocol)
...
@@ -382,13 +386,16 @@ static int inet_create(struct socket *sock, int protocol)
}
}
br_read_unlock_bh
(
BR_NETPROTO_LOCK
);
br_read_unlock_bh
(
BR_NETPROTO_LOCK
);
err
=
-
ESOCKTNOSUPPORT
;
if
(
!
answer
)
if
(
!
answer
)
goto
free_and_badtype
;
goto
out_sk_free
;
err
=
-
EPERM
;
if
(
answer
->
capability
>
0
&&
!
capable
(
answer
->
capability
))
if
(
answer
->
capability
>
0
&&
!
capable
(
answer
->
capability
))
goto
free_and_badperm
;
goto
out_sk_free
;
err
=
-
EPROTONOSUPPORT
;
if
(
!
protocol
)
if
(
!
protocol
)
goto
free_and_noproto
;
goto
out_sk_free
;
err
=
0
;
sock
->
ops
=
answer
->
ops
;
sock
->
ops
=
answer
->
ops
;
sk
->
prot
=
answer
->
prot
;
sk
->
prot
=
answer
->
prot
;
sk
->
no_check
=
answer
->
no_check
;
sk
->
no_check
=
answer
->
no_check
;
...
@@ -410,18 +417,15 @@ static int inet_create(struct socket *sock, int protocol)
...
@@ -410,18 +417,15 @@ static int inet_create(struct socket *sock, int protocol)
inet
->
id
=
0
;
inet
->
id
=
0
;
sock_init_data
(
sock
,
sk
);
sock_init_data
(
sock
,
sk
);
sk
->
destruct
=
inet_sock_destruct
;
sk
->
destruct
=
inet_sock_destruct
;
sk
->
zapped
=
0
;
sk
->
zapped
=
0
;
sk
->
family
=
PF_INET
;
sk
->
family
=
PF_INET
;
sk
->
protocol
=
protocol
;
sk
->
protocol
=
protocol
;
sk
->
backlog_rcv
=
sk
->
prot
->
backlog_rcv
;
sk
->
backlog_rcv
=
sk
->
prot
->
backlog_rcv
;
inet
->
ttl
=
sysctl_ip_default_ttl
;
inet
->
ttl
=
sysctl_ip_default_ttl
;
inet
->
mc_loop
=
1
;
inet
->
mc_loop
=
1
;
inet
->
mc_ttl
=
1
;
inet
->
mc_ttl
=
1
;
inet
->
mc_index
=
0
;
inet
->
mc_index
=
0
;
...
@@ -438,34 +442,20 @@ static int inet_create(struct socket *sock, int protocol)
...
@@ -438,34 +442,20 @@ static int inet_create(struct socket *sock, int protocol)
* shares.
* shares.
*/
*/
inet
->
sport
=
htons
(
inet
->
num
);
inet
->
sport
=
htons
(
inet
->
num
);
/* Add to protocol hash chains. */
/* Add to protocol hash chains. */
sk
->
prot
->
hash
(
sk
);
sk
->
prot
->
hash
(
sk
);
}
}
if
(
sk
->
prot
->
init
)
{
if
(
sk
->
prot
->
init
)
{
int
err
=
sk
->
prot
->
init
(
sk
);
err
=
sk
->
prot
->
init
(
sk
);
if
(
err
!=
0
)
{
if
(
err
)
inet_sock_release
(
sk
);
inet_sock_release
(
sk
);
return
err
;
}
}
}
out:
return
0
;
return
err
;
out_sk_free:
free_and_badtype:
sk_free
(
sk
);
return
-
ESOCKTNOSUPPORT
;
free_and_badperm:
sk_free
(
sk
);
return
-
EPERM
;
free_and_noproto:
sk_free
(
sk
);
sk_free
(
sk
);
return
-
EPROTONOSUPPORT
;
goto
out
;
do_oom:
return
-
ENOBUFS
;
}
}
...
@@ -474,7 +464,6 @@ static int inet_create(struct socket *sock, int protocol)
...
@@ -474,7 +464,6 @@ static int inet_create(struct socket *sock, int protocol)
* function we are destroying the object and from then on nobody
* function we are destroying the object and from then on nobody
* should refer to it.
* should refer to it.
*/
*/
int
inet_release
(
struct
socket
*
sock
)
int
inet_release
(
struct
socket
*
sock
)
{
{
struct
sock
*
sk
=
sock
->
sk
;
struct
sock
*
sk
=
sock
->
sk
;
...
@@ -498,7 +487,7 @@ int inet_release(struct socket *sock)
...
@@ -498,7 +487,7 @@ int inet_release(struct socket *sock)
sock
->
sk
=
NULL
;
sock
->
sk
=
NULL
;
sk
->
prot
->
close
(
sk
,
timeout
);
sk
->
prot
->
close
(
sk
,
timeout
);
}
}
return
(
0
)
;
return
0
;
}
}
/* It is off by default, see below. */
/* It is off by default, see below. */
...
@@ -506,19 +495,21 @@ int sysctl_ip_nonlocal_bind;
...
@@ -506,19 +495,21 @@ int sysctl_ip_nonlocal_bind;
static
int
inet_bind
(
struct
socket
*
sock
,
struct
sockaddr
*
uaddr
,
int
addr_len
)
static
int
inet_bind
(
struct
socket
*
sock
,
struct
sockaddr
*
uaddr
,
int
addr_len
)
{
{
struct
sockaddr_in
*
addr
=
(
struct
sockaddr_in
*
)
uaddr
;
struct
sockaddr_in
*
addr
=
(
struct
sockaddr_in
*
)
uaddr
;
struct
sock
*
sk
=
sock
->
sk
;
struct
sock
*
sk
=
sock
->
sk
;
struct
inet_opt
*
inet
=
inet_sk
(
sk
);
struct
inet_opt
*
inet
=
inet_sk
(
sk
);
unsigned
short
snum
;
unsigned
short
snum
;
int
chk_addr_ret
;
int
chk_addr_ret
;
int
err
;
int
err
;
/* If the socket has its own bind function then use it. (RAW) */
/* If the socket has its own bind function then use it. (RAW) */
if
(
sk
->
prot
->
bind
)
if
(
sk
->
prot
->
bind
)
{
return
sk
->
prot
->
bind
(
sk
,
uaddr
,
addr_len
);
err
=
sk
->
prot
->
bind
(
sk
,
uaddr
,
addr_len
);
goto
out
;
}
err
=
-
EINVAL
;
if
(
addr_len
<
sizeof
(
struct
sockaddr_in
))
if
(
addr_len
<
sizeof
(
struct
sockaddr_in
))
return
-
EINVAL
;
goto
out
;
chk_addr_ret
=
inet_addr_type
(
addr
->
sin_addr
.
s_addr
);
chk_addr_ret
=
inet_addr_type
(
addr
->
sin_addr
.
s_addr
);
...
@@ -529,17 +520,19 @@ static int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
...
@@ -529,17 +520,19 @@ static int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
* (ie. your servers still start up even if your ISDN link
* (ie. your servers still start up even if your ISDN link
* is temporarily down)
* is temporarily down)
*/
*/
if
(
sysctl_ip_nonlocal_bind
==
0
&&
err
=
-
EADDRNOTAVAIL
;
inet
->
freebind
==
0
&&
if
(
!
sysctl_ip_nonlocal_bind
&&
!
inet
->
freebind
&&
addr
->
sin_addr
.
s_addr
!=
INADDR_ANY
&&
addr
->
sin_addr
.
s_addr
!=
INADDR_ANY
&&
chk_addr_ret
!=
RTN_LOCAL
&&
chk_addr_ret
!=
RTN_LOCAL
&&
chk_addr_ret
!=
RTN_MULTICAST
&&
chk_addr_ret
!=
RTN_MULTICAST
&&
chk_addr_ret
!=
RTN_BROADCAST
)
chk_addr_ret
!=
RTN_BROADCAST
)
return
-
EADDRNOTAVAIL
;
goto
out
;
snum
=
ntohs
(
addr
->
sin_port
);
snum
=
ntohs
(
addr
->
sin_port
);
err
=
-
EACCES
;
if
(
snum
&&
snum
<
PROT_SOCK
&&
!
capable
(
CAP_NET_BIND_SERVICE
))
if
(
snum
&&
snum
<
PROT_SOCK
&&
!
capable
(
CAP_NET_BIND_SERVICE
))
return
-
EACCES
;
goto
out
;
/* We keep a pair of addresses. rcv_saddr is the one
/* We keep a pair of addresses. rcv_saddr is the one
* used by hash lookups, and saddr is used for transmit.
* used by hash lookups, and saddr is used for transmit.
...
@@ -553,17 +546,17 @@ static int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
...
@@ -553,17 +546,17 @@ static int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
/* Check these errors (active socket, double bind). */
/* Check these errors (active socket, double bind). */
err
=
-
EINVAL
;
err
=
-
EINVAL
;
if
(
sk
->
state
!=
TCP_CLOSE
||
inet
->
num
)
if
(
sk
->
state
!=
TCP_CLOSE
||
inet
->
num
)
goto
out
;
goto
out
_release_sock
;
inet
->
rcv_saddr
=
inet
->
saddr
=
addr
->
sin_addr
.
s_addr
;
inet
->
rcv_saddr
=
inet
->
saddr
=
addr
->
sin_addr
.
s_addr
;
if
(
chk_addr_ret
==
RTN_MULTICAST
||
chk_addr_ret
==
RTN_BROADCAST
)
if
(
chk_addr_ret
==
RTN_MULTICAST
||
chk_addr_ret
==
RTN_BROADCAST
)
inet
->
saddr
=
0
;
/* Use device */
inet
->
saddr
=
0
;
/* Use device */
/* Make sure we are allowed to bind here. */
/* Make sure we are allowed to bind here. */
if
(
sk
->
prot
->
get_port
(
sk
,
snum
)
!=
0
)
{
if
(
sk
->
prot
->
get_port
(
sk
,
snum
))
{
inet
->
saddr
=
inet
->
rcv_saddr
=
0
;
inet
->
saddr
=
inet
->
rcv_saddr
=
0
;
err
=
-
EADDRINUSE
;
err
=
-
EADDRINUSE
;
goto
out
;
goto
out
_release_sock
;
}
}
if
(
inet
->
rcv_saddr
)
if
(
inet
->
rcv_saddr
)
...
@@ -575,15 +568,16 @@ static int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
...
@@ -575,15 +568,16 @@ static int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
inet
->
dport
=
0
;
inet
->
dport
=
0
;
sk_dst_reset
(
sk
);
sk_dst_reset
(
sk
);
err
=
0
;
err
=
0
;
out:
out
_release_sock
:
release_sock
(
sk
);
release_sock
(
sk
);
out:
return
err
;
return
err
;
}
}
int
inet_dgram_connect
(
struct
socket
*
sock
,
struct
sockaddr
*
uaddr
,
int
inet_dgram_connect
(
struct
socket
*
sock
,
struct
sockaddr
*
uaddr
,
int
addr_len
,
int
flags
)
int
addr_len
,
int
flags
)
{
{
struct
sock
*
sk
=
sock
->
sk
;
struct
sock
*
sk
=
sock
->
sk
;
if
(
uaddr
->
sa_family
==
AF_UNSPEC
)
if
(
uaddr
->
sa_family
==
AF_UNSPEC
)
return
sk
->
prot
->
disconnect
(
sk
,
flags
);
return
sk
->
prot
->
disconnect
(
sk
,
flags
);
...
@@ -605,7 +599,7 @@ static long inet_wait_for_connect(struct sock *sk, long timeo)
...
@@ -605,7 +599,7 @@ static long inet_wait_for_connect(struct sock *sk, long timeo)
* Connect() does not allow to get error notifications
* Connect() does not allow to get error notifications
* without closing the socket.
* without closing the socket.
*/
*/
while
((
1
<<
sk
->
state
)
&
(
TCPF_SYN_SENT
|
TCPF_SYN_RECV
))
{
while
((
1
<<
sk
->
state
)
&
(
TCPF_SYN_SENT
|
TCPF_SYN_RECV
))
{
release_sock
(
sk
);
release_sock
(
sk
);
timeo
=
schedule_timeout
(
timeo
);
timeo
=
schedule_timeout
(
timeo
);
lock_sock
(
sk
);
lock_sock
(
sk
);
...
@@ -622,11 +616,10 @@ static long inet_wait_for_connect(struct sock *sk, long timeo)
...
@@ -622,11 +616,10 @@ static long inet_wait_for_connect(struct sock *sk, long timeo)
* Connect to a remote host. There is regrettably still a little
* Connect to a remote host. There is regrettably still a little
* TCP 'magic' in here.
* TCP 'magic' in here.
*/
*/
int
inet_stream_connect
(
struct
socket
*
sock
,
struct
sockaddr
*
uaddr
,
int
inet_stream_connect
(
struct
socket
*
sock
,
struct
sockaddr
*
uaddr
,
int
addr_len
,
int
flags
)
int
addr_len
,
int
flags
)
{
{
struct
sock
*
sk
=
sock
->
sk
;
struct
sock
*
sk
=
sock
->
sk
;
int
err
;
int
err
;
long
timeo
;
long
timeo
;
...
@@ -668,9 +661,9 @@ int inet_stream_connect(struct socket *sock, struct sockaddr * uaddr,
...
@@ -668,9 +661,9 @@ int inet_stream_connect(struct socket *sock, struct sockaddr * uaddr,
break
;
break
;
}
}
timeo
=
sock_sndtimeo
(
sk
,
flags
&
O_NONBLOCK
);
timeo
=
sock_sndtimeo
(
sk
,
flags
&
O_NONBLOCK
);
if
((
1
<<
sk
->
state
)
&
(
TCPF_SYN_SENT
|
TCPF_SYN_RECV
))
{
if
((
1
<<
sk
->
state
)
&
(
TCPF_SYN_SENT
|
TCPF_SYN_RECV
))
{
/* Error code is set above */
/* Error code is set above */
if
(
!
timeo
||
!
inet_wait_for_connect
(
sk
,
timeo
))
if
(
!
timeo
||
!
inet_wait_for_connect
(
sk
,
timeo
))
goto
out
;
goto
out
;
...
@@ -712,22 +705,22 @@ int inet_stream_connect(struct socket *sock, struct sockaddr * uaddr,
...
@@ -712,22 +705,22 @@ int inet_stream_connect(struct socket *sock, struct sockaddr * uaddr,
int
inet_accept
(
struct
socket
*
sock
,
struct
socket
*
newsock
,
int
flags
)
int
inet_accept
(
struct
socket
*
sock
,
struct
socket
*
newsock
,
int
flags
)
{
{
struct
sock
*
sk1
=
sock
->
sk
;
struct
sock
*
sk1
=
sock
->
sk
;
struct
sock
*
sk2
;
int
err
=
-
EINVAL
;
int
err
=
-
EINVAL
;
struct
sock
*
sk2
=
sk1
->
prot
->
accept
(
sk1
,
flags
,
&
err
);
if
((
sk2
=
sk1
->
prot
->
accept
(
sk1
,
flags
,
&
err
))
==
NULL
)
if
(
!
sk2
)
goto
do_err
;
goto
do_err
;
lock_sock
(
sk2
);
lock_sock
(
sk2
);
BUG_TRAP
((
1
<<
sk2
->
state
)
&
(
TCPF_ESTABLISHED
|
TCPF_CLOSE_WAIT
|
TCPF_CLOSE
));
BUG_TRAP
((
1
<<
sk2
->
state
)
&
(
TCPF_ESTABLISHED
|
TCPF_CLOSE_WAIT
|
TCPF_CLOSE
));
sock_graft
(
sk2
,
newsock
);
sock_graft
(
sk2
,
newsock
);
newsock
->
state
=
SS_CONNECTED
;
newsock
->
state
=
SS_CONNECTED
;
err
=
0
;
release_sock
(
sk2
);
release_sock
(
sk2
);
return
0
;
do_err:
do_err:
return
err
;
return
err
;
}
}
...
@@ -736,7 +729,6 @@ int inet_accept(struct socket *sock, struct socket *newsock, int flags)
...
@@ -736,7 +729,6 @@ int inet_accept(struct socket *sock, struct socket *newsock, int flags)
/*
/*
* This does both peername and sockname.
* This does both peername and sockname.
*/
*/
static
int
inet_getname
(
struct
socket
*
sock
,
struct
sockaddr
*
uaddr
,
static
int
inet_getname
(
struct
socket
*
sock
,
struct
sockaddr
*
uaddr
,
int
*
uaddr_len
,
int
peer
)
int
*
uaddr_len
,
int
peer
)
{
{
...
@@ -746,9 +738,9 @@ static int inet_getname(struct socket *sock, struct sockaddr *uaddr,
...
@@ -746,9 +738,9 @@ static int inet_getname(struct socket *sock, struct sockaddr *uaddr,
sin
->
sin_family
=
AF_INET
;
sin
->
sin_family
=
AF_INET
;
if
(
peer
)
{
if
(
peer
)
{
if
(
!
inet
->
dport
)
if
(
!
inet
->
dport
||
return
-
ENOTCONN
;
(((
1
<<
sk
->
state
)
&
(
TCPF_CLOSE
|
TCPF_SYN_SENT
))
&&
if
(((
1
<<
sk
->
state
)
&
(
TCPF_CLOSE
|
TCPF_SYN_SENT
))
&&
peer
==
1
)
peer
==
1
)
)
return
-
ENOTCONN
;
return
-
ENOTCONN
;
sin
->
sin_port
=
inet
->
dport
;
sin
->
sin_port
=
inet
->
dport
;
sin
->
sin_addr
.
s_addr
=
inet
->
daddr
;
sin
->
sin_addr
.
s_addr
=
inet
->
daddr
;
...
@@ -760,7 +752,7 @@ static int inet_getname(struct socket *sock, struct sockaddr *uaddr,
...
@@ -760,7 +752,7 @@ static int inet_getname(struct socket *sock, struct sockaddr *uaddr,
sin
->
sin_addr
.
s_addr
=
addr
;
sin
->
sin_addr
.
s_addr
=
addr
;
}
}
*
uaddr_len
=
sizeof
(
*
sin
);
*
uaddr_len
=
sizeof
(
*
sin
);
return
(
0
)
;
return
0
;
}
}
...
@@ -770,10 +762,8 @@ int inet_recvmsg(struct socket *sock, struct msghdr *msg, int size,
...
@@ -770,10 +762,8 @@ int inet_recvmsg(struct socket *sock, struct msghdr *msg, int size,
{
{
struct
sock
*
sk
=
sock
->
sk
;
struct
sock
*
sk
=
sock
->
sk
;
int
addr_len
=
0
;
int
addr_len
=
0
;
int
err
;
int
err
=
sk
->
prot
->
recvmsg
(
sk
,
msg
,
size
,
flags
&
MSG_DONTWAIT
,
flags
&
~
MSG_DONTWAIT
,
&
addr_len
);
err
=
sk
->
prot
->
recvmsg
(
sk
,
msg
,
size
,
flags
&
MSG_DONTWAIT
,
flags
&~
MSG_DONTWAIT
,
&
addr_len
);
if
(
err
>=
0
)
if
(
err
>=
0
)
msg
->
msg_namelen
=
addr_len
;
msg
->
msg_namelen
=
addr_len
;
return
err
;
return
err
;
...
@@ -803,12 +793,13 @@ int inet_shutdown(struct socket *sock, int how)
...
@@ -803,12 +793,13 @@ int inet_shutdown(struct socket *sock, int how)
how
++
;
/* maps 0->1 has the advantage of making bit 1 rcvs and
how
++
;
/* maps 0->1 has the advantage of making bit 1 rcvs and
1->2 bit 2 snds.
1->2 bit 2 snds.
2->3 */
2->3 */
if
((
how
&
~
SHUTDOWN_MASK
)
||
how
==
0
)
/* MAXINT->0 */
if
((
how
&
~
SHUTDOWN_MASK
)
||
!
how
)
/* MAXINT->0 */
return
-
EINVAL
;
return
-
EINVAL
;
lock_sock
(
sk
);
lock_sock
(
sk
);
if
(
sock
->
state
==
SS_CONNECTING
)
{
if
(
sock
->
state
==
SS_CONNECTING
)
{
if
((
1
<<
sk
->
state
)
&
(
TCPF_SYN_SENT
|
TCPF_SYN_RECV
|
TCPF_CLOSE
))
if
((
1
<<
sk
->
state
)
&
(
TCPF_SYN_SENT
|
TCPF_SYN_RECV
|
TCPF_CLOSE
))
sock
->
state
=
SS_DISCONNECTING
;
sock
->
state
=
SS_DISCONNECTING
;
else
else
sock
->
state
=
SS_CONNECTED
;
sock
->
state
=
SS_CONNECTED
;
...
@@ -858,38 +849,42 @@ int inet_shutdown(struct socket *sock, int how)
...
@@ -858,38 +849,42 @@ int inet_shutdown(struct socket *sock, int how)
static
int
inet_ioctl
(
struct
socket
*
sock
,
unsigned
int
cmd
,
unsigned
long
arg
)
static
int
inet_ioctl
(
struct
socket
*
sock
,
unsigned
int
cmd
,
unsigned
long
arg
)
{
{
struct
sock
*
sk
=
sock
->
sk
;
struct
sock
*
sk
=
sock
->
sk
;
int
err
;
int
err
=
0
;
int
pid
;
int
pid
;
switch
(
cmd
)
{
switch
(
cmd
)
{
case
FIOSETOWN
:
case
FIOSETOWN
:
case
SIOCSPGRP
:
case
SIOCSPGRP
:
err
=
get_user
(
pid
,
(
int
*
)
arg
);
if
(
get_user
(
pid
,
(
int
*
)
arg
))
if
(
err
)
err
=
-
EFAULT
;
return
err
;
else
if
(
current
->
pid
!=
pid
&&
if
(
current
->
pid
!=
pid
&&
current
->
pgrp
!=
-
pid
&&
current
->
pgrp
!=
-
pid
&&
!
capable
(
CAP_NET_ADMIN
))
!
capable
(
CAP_NET_ADMIN
))
return
-
EPERM
;
err
=
-
EPERM
;
else
sk
->
proc
=
pid
;
sk
->
proc
=
pid
;
return
(
0
)
;
break
;
case
FIOGETOWN
:
case
FIOGETOWN
:
case
SIOCGPGRP
:
case
SIOCGPGRP
:
return
put_user
(
sk
->
proc
,
(
int
*
)
arg
);
err
=
put_user
(
sk
->
proc
,
(
int
*
)
arg
);
break
;
case
SIOCGSTAMP
:
case
SIOCGSTAMP
:
if
(
sk
->
stamp
.
tv_sec
==
0
)
if
(
!
sk
->
stamp
.
tv_sec
)
return
-
ENOENT
;
err
=
-
ENOENT
;
e
rr
=
copy_to_user
((
void
*
)
arg
,
&
sk
->
stamp
,
sizeof
(
struct
timeval
));
e
lse
if
(
copy_to_user
((
void
*
)
arg
,
&
sk
->
stamp
,
if
(
err
)
sizeof
(
struct
timeval
))
)
err
=
-
EFAULT
;
err
=
-
EFAULT
;
return
err
;
break
;
case
SIOCADDRT
:
case
SIOCADDRT
:
case
SIOCDELRT
:
case
SIOCDELRT
:
case
SIOCRTMSG
:
case
SIOCRTMSG
:
return
(
ip_rt_ioctl
(
cmd
,(
void
*
)
arg
));
err
=
ip_rt_ioctl
(
cmd
,
(
void
*
)
arg
);
break
;
case
SIOCDARP
:
case
SIOCDARP
:
case
SIOCGARP
:
case
SIOCGARP
:
case
SIOCSARP
:
case
SIOCSARP
:
return
(
arp_ioctl
(
cmd
,(
void
*
)
arg
));
err
=
arp_ioctl
(
cmd
,
(
void
*
)
arg
);
break
;
case
SIOCGIFADDR
:
case
SIOCGIFADDR
:
case
SIOCSIFADDR
:
case
SIOCSIFADDR
:
case
SIOCGIFBRDADDR
:
case
SIOCGIFBRDADDR
:
...
@@ -901,80 +896,79 @@ static int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
...
@@ -901,80 +896,79 @@ static int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
case
SIOCSIFPFLAGS
:
case
SIOCSIFPFLAGS
:
case
SIOCGIFPFLAGS
:
case
SIOCGIFPFLAGS
:
case
SIOCSIFFLAGS
:
case
SIOCSIFFLAGS
:
return
(
devinet_ioctl
(
cmd
,(
void
*
)
arg
));
err
=
devinet_ioctl
(
cmd
,
(
void
*
)
arg
);
break
;
case
SIOCGIFBR
:
case
SIOCGIFBR
:
case
SIOCSIFBR
:
case
SIOCSIFBR
:
#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
#ifdef CONFIG_KMOD
#ifdef CONFIG_KMOD
if
(
br_ioctl_hook
==
NULL
)
if
(
!
br_ioctl_hook
)
request_module
(
"bridge"
);
request_module
(
"bridge"
);
#endif
#endif
if
(
br_ioctl_hook
!=
NULL
)
if
(
br_ioctl_hook
)
return
br_ioctl_hook
(
arg
);
err
=
br_ioctl_hook
(
arg
);
else
#endif
#endif
return
-
ENOPKG
;
err
=
-
ENOPKG
;
break
;
case
SIOCGIFVLAN
:
case
SIOCGIFVLAN
:
case
SIOCSIFVLAN
:
case
SIOCSIFVLAN
:
#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
#ifdef CONFIG_KMOD
#ifdef CONFIG_KMOD
if
(
vlan_ioctl_hook
==
NULL
)
if
(
!
vlan_ioctl_hook
)
request_module
(
"8021q"
);
request_module
(
"8021q"
);
#endif
#endif
if
(
vlan_ioctl_hook
!=
NULL
)
if
(
vlan_ioctl_hook
)
return
vlan_ioctl_hook
(
arg
);
err
=
vlan_ioctl_hook
(
arg
);
else
#endif
#endif
return
-
ENOPKG
;
err
=
-
ENOPKG
;
break
;
case
SIOCGIFDIVERT
:
case
SIOCGIFDIVERT
:
case
SIOCSIFDIVERT
:
case
SIOCSIFDIVERT
:
#ifdef CONFIG_NET_DIVERT
#ifdef CONFIG_NET_DIVERT
return
divert_ioctl
(
cmd
,
(
struct
divert_cf
*
)
arg
);
err
=
divert_ioctl
(
cmd
,
(
struct
divert_cf
*
)
arg
);
#else
#else
return
-
ENOPKG
;
err
=
-
ENOPKG
;
#endif
/* CONFIG_NET_DIVERT */
#endif
/* CONFIG_NET_DIVERT */
break
;
case
SIOCADDDLCI
:
case
SIOCADDDLCI
:
case
SIOCDELDLCI
:
case
SIOCDELDLCI
:
#ifdef CONFIG_DLCI
#ifdef CONFIG_DLCI
lock_kernel
();
lock_kernel
();
err
=
dlci_ioctl
(
cmd
,
(
void
*
)
arg
);
err
=
dlci_ioctl
(
cmd
,
(
void
*
)
arg
);
unlock_kernel
();
unlock_kernel
();
return
err
;
break
;
#endif
#elif CONFIG_DLCI_MODULE
#ifdef CONFIG_DLCI_MODULE
#ifdef CONFIG_KMOD
#ifdef CONFIG_KMOD
if
(
dlci_ioctl_hook
==
NULL
)
if
(
!
dlci_ioctl_hook
)
request_module
(
"dlci"
);
request_module
(
"dlci"
);
#endif
#endif
if
(
dlci_ioctl_hook
)
{
if
(
dlci_ioctl_hook
)
{
lock_kernel
();
lock_kernel
();
err
=
(
*
dlci_ioctl_hook
)(
cmd
,
(
void
*
)
arg
);
err
=
(
*
dlci_ioctl_hook
)(
cmd
,
(
void
*
)
arg
);
unlock_kernel
();
unlock_kernel
();
return
err
;
}
else
}
#endif
#endif
return
-
ENOPKG
;
err
=
-
ENOPKG
;
break
;
default:
default:
if
(
(
cmd
>=
SIOCDEVPRIVATE
)
&&
if
(
cmd
>=
SIOCDEVPRIVATE
&&
(
cmd
<=
(
SIOCDEVPRIVATE
+
15
)
))
cmd
<=
(
SIOCDEVPRIVATE
+
15
))
return
(
dev_ioctl
(
cmd
,(
void
*
)
arg
)
);
err
=
dev_ioctl
(
cmd
,
(
void
*
)
arg
);
else
#ifdef WIRELESS_EXT
#ifdef WIRELESS_EXT
if
((
cmd
>=
SIOCIWFIRST
)
&&
(
cmd
<=
SIOCIWLAST
))
if
(
cmd
>=
SIOCIWFIRST
&&
cmd
<=
SIOCIWLAST
)
return
(
dev_ioctl
(
cmd
,(
void
*
)
arg
));
err
=
dev_ioctl
(
cmd
,
(
void
*
)
arg
);
else
#endif
/* WIRELESS_EXT */
#endif
/* WIRELESS_EXT */
if
(
!
sk
->
prot
->
ioctl
||
if
(
sk
->
prot
->
ioctl
==
NULL
||
(
err
=
sk
->
prot
->
ioctl
(
sk
,
cmd
,
arg
))
==-
ENOIOCTLCMD
)
(
err
=
sk
->
prot
->
ioctl
(
sk
,
cmd
,
arg
))
==
return
(
dev_ioctl
(
cmd
,(
void
*
)
arg
));
-
ENOIOCTLCMD
)
return
err
;
err
=
dev_ioctl
(
cmd
,
(
void
*
)
arg
);
break
;
}
}
/*NOTREACHED*/
return
err
;
return
(
0
);
}
}
struct
proto_ops
inet_stream_ops
=
{
struct
proto_ops
inet_stream_ops
=
{
...
@@ -1067,8 +1061,7 @@ static struct inet_protosw inetsw_array[] =
...
@@ -1067,8 +1061,7 @@ static struct inet_protosw inetsw_array[] =
#define INETSW_ARRAY_LEN (sizeof(inetsw_array) / sizeof(struct inet_protosw))
#define INETSW_ARRAY_LEN (sizeof(inetsw_array) / sizeof(struct inet_protosw))
void
void
inet_register_protosw
(
struct
inet_protosw
*
p
)
inet_register_protosw
(
struct
inet_protosw
*
p
)
{
{
struct
list_head
*
lh
;
struct
list_head
*
lh
;
struct
inet_protosw
*
answer
;
struct
inet_protosw
*
answer
;
...
@@ -1115,8 +1108,7 @@ inet_register_protosw(struct inet_protosw *p)
...
@@ -1115,8 +1108,7 @@ inet_register_protosw(struct inet_protosw *p)
goto
out
;
goto
out
;
}
}
void
void
inet_unregister_protosw
(
struct
inet_protosw
*
p
)
inet_unregister_protosw
(
struct
inet_protosw
*
p
)
{
{
if
(
INET_PROTOSW_PERMANENT
&
p
->
flags
)
{
if
(
INET_PROTOSW_PERMANENT
&
p
->
flags
)
{
printk
(
KERN_ERR
printk
(
KERN_ERR
...
@@ -1164,25 +1156,25 @@ static int __init inet_init(void)
...
@@ -1164,25 +1156,25 @@ static int __init inet_init(void)
* Tell SOCKET that we are alive...
* Tell SOCKET that we are alive...
*/
*/
(
void
)
sock_register
(
&
inet_family_ops
);
(
void
)
sock_register
(
&
inet_family_ops
);
/*
/*
* Add all the protocols.
* Add all the protocols.
*/
*/
printk
(
KERN_INFO
"IP Protocols: "
);
printk
(
KERN_INFO
"IP Protocols: "
);
for
(
p
=
inet_protocol_base
;
p
!=
NULL
;)
{
for
(
p
=
inet_protocol_base
;
p
;)
{
struct
inet_protocol
*
tmp
=
(
struct
inet_protocol
*
)
p
->
next
;
struct
inet_protocol
*
tmp
=
(
struct
inet_protocol
*
)
p
->
next
;
inet_add_protocol
(
p
);
inet_add_protocol
(
p
);
printk
(
"%s%s"
,
p
->
name
,
tmp
?
", "
:
"
\n
"
);
printk
(
"%s%s"
,
p
->
name
,
tmp
?
", "
:
"
\n
"
);
p
=
tmp
;
p
=
tmp
;
}
}
/* Register the socket-side information for inet_create. */
/* Register the socket-side information for inet_create. */
for
(
r
=
&
inetsw
[
0
];
r
<
&
inetsw
[
SOCK_MAX
];
++
r
)
for
(
r
=
&
inetsw
[
0
];
r
<
&
inetsw
[
SOCK_MAX
];
++
r
)
INIT_LIST_HEAD
(
r
);
INIT_LIST_HEAD
(
r
);
for
(
q
=
inetsw_array
;
q
<
&
inetsw_array
[
INETSW_ARRAY_LEN
];
++
q
)
for
(
q
=
inetsw_array
;
q
<
&
inetsw_array
[
INETSW_ARRAY_LEN
];
++
q
)
inet_register_protosw
(
q
);
inet_register_protosw
(
q
);
/*
/*
...
...
net/ipv4/devinet.c
View file @
eb2e01d8
...
@@ -18,7 +18,8 @@
...
@@ -18,7 +18,8 @@
* Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
* Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
*
*
* Changes:
* Changes:
* Alexey Kuznetsov: pa_* fields are replaced with ifaddr lists.
* Alexey Kuznetsov: pa_* fields are replaced with ifaddr
* lists.
* Cyrus Durgin: updated for kmod
* Cyrus Durgin: updated for kmod
* Matthias Andree: in devinet_ioctl, compare label and
* Matthias Andree: in devinet_ioctl, compare label and
* address (4.4BSD alias style support),
* address (4.4BSD alias style support),
...
@@ -60,15 +61,29 @@
...
@@ -60,15 +61,29 @@
#include <net/route.h>
#include <net/route.h>
#include <net/ip_fib.h>
#include <net/ip_fib.h>
struct
ipv4_devconf
ipv4_devconf
=
{
1
,
1
,
1
,
1
,
0
,
};
struct
ipv4_devconf
ipv4_devconf
=
{
static
struct
ipv4_devconf
ipv4_devconf_dflt
=
{
1
,
1
,
1
,
1
,
1
,
};
accept_redirects:
1
,
send_redirects:
1
,
secure_redirects:
1
,
shared_media:
1
,
};
static
struct
ipv4_devconf
ipv4_devconf_dflt
=
{
accept_redirects:
1
,
send_redirects:
1
,
secure_redirects:
1
,
shared_media:
1
,
accept_source_route:
1
,
};
static
void
rtmsg_ifa
(
int
event
,
struct
in_ifaddr
*
);
static
void
rtmsg_ifa
(
int
event
,
struct
in_ifaddr
*
);
static
struct
notifier_block
*
inetaddr_chain
;
static
struct
notifier_block
*
inetaddr_chain
;
static
void
inet_del_ifa
(
struct
in_device
*
in_dev
,
struct
in_ifaddr
**
ifap
,
int
destroy
);
static
void
inet_del_ifa
(
struct
in_device
*
in_dev
,
struct
in_ifaddr
**
ifap
,
int
destroy
);
#ifdef CONFIG_SYSCTL
#ifdef CONFIG_SYSCTL
static
void
devinet_sysctl_register
(
struct
in_device
*
in_dev
,
struct
ipv4_devconf
*
p
);
static
void
devinet_sysctl_register
(
struct
in_device
*
in_dev
,
struct
ipv4_devconf
*
p
);
static
void
devinet_sysctl_unregister
(
struct
ipv4_devconf
*
p
);
static
void
devinet_sysctl_unregister
(
struct
ipv4_devconf
*
p
);
#endif
#endif
...
@@ -79,12 +94,10 @@ int inet_dev_count;
...
@@ -79,12 +94,10 @@ int inet_dev_count;
rwlock_t
inetdev_lock
=
RW_LOCK_UNLOCKED
;
rwlock_t
inetdev_lock
=
RW_LOCK_UNLOCKED
;
static
struct
in_ifaddr
*
inet_alloc_ifa
(
void
)
static
struct
in_ifaddr
*
inet_alloc_ifa
(
void
)
{
{
struct
in_ifaddr
*
ifa
;
struct
in_ifaddr
*
ifa
=
kmalloc
(
sizeof
(
*
ifa
),
GFP_KERNEL
)
;
ifa
=
kmalloc
(
sizeof
(
*
ifa
),
GFP_KERNEL
);
if
(
ifa
)
{
if
(
ifa
)
{
memset
(
ifa
,
0
,
sizeof
(
*
ifa
));
memset
(
ifa
,
0
,
sizeof
(
*
ifa
));
inet_ifa_count
++
;
inet_ifa_count
++
;
...
@@ -105,18 +118,19 @@ void in_dev_finish_destroy(struct in_device *idev)
...
@@ -105,18 +118,19 @@ void in_dev_finish_destroy(struct in_device *idev)
{
{
struct
net_device
*
dev
=
idev
->
dev
;
struct
net_device
*
dev
=
idev
->
dev
;
BUG_TRAP
(
idev
->
ifa_list
==
NULL
);
BUG_TRAP
(
!
idev
->
ifa_list
);
BUG_TRAP
(
idev
->
mc_list
==
NULL
);
BUG_TRAP
(
!
idev
->
mc_list
);
#ifdef NET_REFCNT_DEBUG
#ifdef NET_REFCNT_DEBUG
printk
(
KERN_DEBUG
"in_dev_finish_destroy: %p=%s
\n
"
,
idev
,
dev
?
dev
->
name
:
"NIL"
);
printk
(
KERN_DEBUG
"in_dev_finish_destroy: %p=%s
\n
"
,
idev
,
dev
?
dev
->
name
:
"NIL"
);
#endif
#endif
dev_put
(
dev
);
dev_put
(
dev
);
if
(
!
idev
->
dead
)
{
if
(
!
idev
->
dead
)
printk
(
"Freeing alive in_device %p
\n
"
,
idev
);
printk
(
"Freeing alive in_device %p
\n
"
,
idev
);
return
;
else
{
}
inet_dev_count
--
;
inet_dev_count
--
;
kfree
(
idev
);
kfree
(
idev
);
}
}
}
struct
in_device
*
inetdev_init
(
struct
net_device
*
dev
)
struct
in_device
*
inetdev_init
(
struct
net_device
*
dev
)
...
@@ -127,21 +141,20 @@ struct in_device *inetdev_init(struct net_device *dev)
...
@@ -127,21 +141,20 @@ struct in_device *inetdev_init(struct net_device *dev)
in_dev
=
kmalloc
(
sizeof
(
*
in_dev
),
GFP_KERNEL
);
in_dev
=
kmalloc
(
sizeof
(
*
in_dev
),
GFP_KERNEL
);
if
(
!
in_dev
)
if
(
!
in_dev
)
return
NULL
;
goto
out
;
memset
(
in_dev
,
0
,
sizeof
(
*
in_dev
));
memset
(
in_dev
,
0
,
sizeof
(
*
in_dev
));
in_dev
->
lock
=
RW_LOCK_UNLOCKED
;
in_dev
->
lock
=
RW_LOCK_UNLOCKED
;
memcpy
(
&
in_dev
->
cnf
,
&
ipv4_devconf_dflt
,
sizeof
(
in_dev
->
cnf
));
memcpy
(
&
in_dev
->
cnf
,
&
ipv4_devconf_dflt
,
sizeof
(
in_dev
->
cnf
));
in_dev
->
cnf
.
sysctl
=
NULL
;
in_dev
->
cnf
.
sysctl
=
NULL
;
in_dev
->
dev
=
dev
;
in_dev
->
dev
=
dev
;
if
((
in_dev
->
arp_parms
=
neigh_parms_alloc
(
dev
,
&
arp_tbl
))
==
NULL
)
{
if
((
in_dev
->
arp_parms
=
neigh_parms_alloc
(
dev
,
&
arp_tbl
))
==
NULL
)
kfree
(
in_dev
);
goto
out_kfree
;
return
NULL
;
}
inet_dev_count
++
;
inet_dev_count
++
;
/* Reference in_dev->dev */
/* Reference in_dev->dev */
dev_hold
(
dev
);
dev_hold
(
dev
);
#ifdef CONFIG_SYSCTL
#ifdef CONFIG_SYSCTL
neigh_sysctl_register
(
dev
,
in_dev
->
arp_parms
,
NET_IPV4
,
NET_IPV4_NEIGH
,
"ipv4"
);
neigh_sysctl_register
(
dev
,
in_dev
->
arp_parms
,
NET_IPV4
,
NET_IPV4_NEIGH
,
"ipv4"
);
#endif
#endif
write_lock_bh
(
&
inetdev_lock
);
write_lock_bh
(
&
inetdev_lock
);
dev
->
ip_ptr
=
in_dev
;
dev
->
ip_ptr
=
in_dev
;
...
@@ -151,9 +164,14 @@ struct in_device *inetdev_init(struct net_device *dev)
...
@@ -151,9 +164,14 @@ struct in_device *inetdev_init(struct net_device *dev)
#ifdef CONFIG_SYSCTL
#ifdef CONFIG_SYSCTL
devinet_sysctl_register
(
in_dev
,
&
in_dev
->
cnf
);
devinet_sysctl_register
(
in_dev
,
&
in_dev
->
cnf
);
#endif
#endif
if
(
dev
->
flags
&
IFF_UP
)
if
(
dev
->
flags
&
IFF_UP
)
ip_mc_up
(
in_dev
);
ip_mc_up
(
in_dev
);
out:
return
in_dev
;
return
in_dev
;
out_kfree:
kfree
(
in_dev
);
in_dev
=
NULL
;
goto
out
;
}
}
static
void
inetdev_destroy
(
struct
in_device
*
in_dev
)
static
void
inetdev_destroy
(
struct
in_device
*
in_dev
)
...
@@ -199,8 +217,8 @@ int inet_addr_onlink(struct in_device *in_dev, u32 a, u32 b)
...
@@ -199,8 +217,8 @@ int inet_addr_onlink(struct in_device *in_dev, u32 a, u32 b)
return
0
;
return
0
;
}
}
static
void
static
void
inet_del_ifa
(
struct
in_device
*
in_dev
,
struct
in_ifaddr
**
ifap
,
inet_del_ifa
(
struct
in_device
*
in_dev
,
struct
in_ifaddr
**
ifap
,
int
destroy
)
int
destroy
)
{
{
struct
in_ifaddr
*
ifa1
=
*
ifap
;
struct
in_ifaddr
*
ifa1
=
*
ifap
;
...
@@ -208,12 +226,12 @@ inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, int destroy)
...
@@ -208,12 +226,12 @@ inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, int destroy)
/* 1. Deleting primary ifaddr forces deletion all secondaries */
/* 1. Deleting primary ifaddr forces deletion all secondaries */
if
(
!
(
ifa1
->
ifa_flags
&
IFA_F_SECONDARY
))
{
if
(
!
(
ifa1
->
ifa_flags
&
IFA_F_SECONDARY
))
{
struct
in_ifaddr
*
ifa
;
struct
in_ifaddr
*
ifa
;
struct
in_ifaddr
**
ifap1
=
&
ifa1
->
ifa_next
;
struct
in_ifaddr
**
ifap1
=
&
ifa1
->
ifa_next
;
while
((
ifa
=
*
ifap1
)
!=
NULL
)
{
while
((
ifa
=
*
ifap1
)
!=
NULL
)
{
if
(
!
(
ifa
->
ifa_flags
&
IFA_F_SECONDARY
)
||
if
(
!
(
ifa
->
ifa_flags
&
IFA_F_SECONDARY
)
||
ifa1
->
ifa_mask
!=
ifa
->
ifa_mask
||
ifa1
->
ifa_mask
!=
ifa
->
ifa_mask
||
!
inet_ifa_match
(
ifa1
->
ifa_address
,
ifa
))
{
!
inet_ifa_match
(
ifa1
->
ifa_address
,
ifa
))
{
ifap1
=
&
ifa
->
ifa_next
;
ifap1
=
&
ifa
->
ifa_next
;
...
@@ -250,20 +268,19 @@ inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, int destroy)
...
@@ -250,20 +268,19 @@ inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, int destroy)
if
(
destroy
)
{
if
(
destroy
)
{
inet_free_ifa
(
ifa1
);
inet_free_ifa
(
ifa1
);
if
(
in_dev
->
ifa_list
==
NULL
)
if
(
!
in_dev
->
ifa_list
)
inetdev_destroy
(
in_dev
);
inetdev_destroy
(
in_dev
);
}
}
}
}
static
int
static
int
inet_insert_ifa
(
struct
in_ifaddr
*
ifa
)
inet_insert_ifa
(
struct
in_ifaddr
*
ifa
)
{
{
struct
in_device
*
in_dev
=
ifa
->
ifa_dev
;
struct
in_device
*
in_dev
=
ifa
->
ifa_dev
;
struct
in_ifaddr
*
ifa1
,
**
ifap
,
**
last_primary
;
struct
in_ifaddr
*
ifa1
,
**
ifap
,
**
last_primary
;
ASSERT_RTNL
();
ASSERT_RTNL
();
if
(
ifa
->
ifa_local
==
0
)
{
if
(
!
ifa
->
ifa_local
)
{
inet_free_ifa
(
ifa
);
inet_free_ifa
(
ifa
);
return
0
;
return
0
;
}
}
...
@@ -271,10 +288,13 @@ inet_insert_ifa(struct in_ifaddr *ifa)
...
@@ -271,10 +288,13 @@ inet_insert_ifa(struct in_ifaddr *ifa)
ifa
->
ifa_flags
&=
~
IFA_F_SECONDARY
;
ifa
->
ifa_flags
&=
~
IFA_F_SECONDARY
;
last_primary
=
&
in_dev
->
ifa_list
;
last_primary
=
&
in_dev
->
ifa_list
;
for
(
ifap
=&
in_dev
->
ifa_list
;
(
ifa1
=*
ifap
)
!=
NULL
;
ifap
=&
ifa1
->
ifa_next
)
{
for
(
ifap
=
&
in_dev
->
ifa_list
;
(
ifa1
=
*
ifap
)
!=
NULL
;
if
(
!
(
ifa1
->
ifa_flags
&
IFA_F_SECONDARY
)
&&
ifa
->
ifa_scope
<=
ifa1
->
ifa_scope
)
ifap
=
&
ifa1
->
ifa_next
)
{
if
(
!
(
ifa1
->
ifa_flags
&
IFA_F_SECONDARY
)
&&
ifa
->
ifa_scope
<=
ifa1
->
ifa_scope
)
last_primary
=
&
ifa1
->
ifa_next
;
last_primary
=
&
ifa1
->
ifa_next
;
if
(
ifa1
->
ifa_mask
==
ifa
->
ifa_mask
&&
inet_ifa_match
(
ifa1
->
ifa_address
,
ifa
))
{
if
(
ifa1
->
ifa_mask
==
ifa
->
ifa_mask
&&
inet_ifa_match
(
ifa1
->
ifa_address
,
ifa
))
{
if
(
ifa1
->
ifa_local
==
ifa
->
ifa_local
)
{
if
(
ifa1
->
ifa_local
==
ifa
->
ifa_local
)
{
inet_free_ifa
(
ifa
);
inet_free_ifa
(
ifa
);
return
-
EEXIST
;
return
-
EEXIST
;
...
@@ -287,7 +307,7 @@ inet_insert_ifa(struct in_ifaddr *ifa)
...
@@ -287,7 +307,7 @@ inet_insert_ifa(struct in_ifaddr *ifa)
}
}
}
}
if
(
!
(
ifa
->
ifa_flags
&
IFA_F_SECONDARY
))
{
if
(
!
(
ifa
->
ifa_flags
&
IFA_F_SECONDARY
))
{
net_srandom
(
ifa
->
ifa_local
);
net_srandom
(
ifa
->
ifa_local
);
ifap
=
last_primary
;
ifap
=
last_primary
;
}
}
...
@@ -306,24 +326,23 @@ inet_insert_ifa(struct in_ifaddr *ifa)
...
@@ -306,24 +326,23 @@ inet_insert_ifa(struct in_ifaddr *ifa)
return
0
;
return
0
;
}
}
static
int
static
int
inet_set_ifa
(
struct
net_device
*
dev
,
struct
in_ifaddr
*
ifa
)
inet_set_ifa
(
struct
net_device
*
dev
,
struct
in_ifaddr
*
ifa
)
{
{
struct
in_device
*
in_dev
=
__in_dev_get
(
dev
);
struct
in_device
*
in_dev
=
__in_dev_get
(
dev
);
ASSERT_RTNL
();
ASSERT_RTNL
();
if
(
in_dev
==
NULL
)
{
if
(
!
in_dev
)
{
in_dev
=
inetdev_init
(
dev
);
in_dev
=
inetdev_init
(
dev
);
if
(
in_dev
==
NULL
)
{
if
(
!
in_dev
)
{
inet_free_ifa
(
ifa
);
inet_free_ifa
(
ifa
);
return
-
ENOBUFS
;
return
-
ENOBUFS
;
}
}
}
}
if
(
ifa
->
ifa_dev
!=
in_dev
)
{
if
(
ifa
->
ifa_dev
!=
in_dev
)
{
BUG_TRAP
(
ifa
->
ifa_dev
==
NULL
);
BUG_TRAP
(
!
ifa
->
ifa_dev
);
in_dev_hold
(
in_dev
);
in_dev_hold
(
in_dev
);
ifa
->
ifa_dev
=
in_dev
;
ifa
->
ifa_dev
=
in_dev
;
}
}
if
(
LOOPBACK
(
ifa
->
ifa_local
))
if
(
LOOPBACK
(
ifa
->
ifa_local
))
ifa
->
ifa_scope
=
RT_SCOPE_HOST
;
ifa
->
ifa_scope
=
RT_SCOPE_HOST
;
...
@@ -344,7 +363,8 @@ struct in_device *inetdev_by_index(int ifindex)
...
@@ -344,7 +363,8 @@ struct in_device *inetdev_by_index(int ifindex)
/* Called only from RTNL semaphored context. No locks. */
/* Called only from RTNL semaphored context. No locks. */
struct
in_ifaddr
*
inet_ifa_byprefix
(
struct
in_device
*
in_dev
,
u32
prefix
,
u32
mask
)
struct
in_ifaddr
*
inet_ifa_byprefix
(
struct
in_device
*
in_dev
,
u32
prefix
,
u32
mask
)
{
{
ASSERT_RTNL
();
ASSERT_RTNL
();
...
@@ -355,8 +375,7 @@ struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, u32 prefix, u32 ma
...
@@ -355,8 +375,7 @@ struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, u32 prefix, u32 ma
return
NULL
;
return
NULL
;
}
}
int
int
inet_rtm_deladdr
(
struct
sk_buff
*
skb
,
struct
nlmsghdr
*
nlh
,
void
*
arg
)
inet_rtm_deladdr
(
struct
sk_buff
*
skb
,
struct
nlmsghdr
*
nlh
,
void
*
arg
)
{
{
struct
rtattr
**
rta
=
arg
;
struct
rtattr
**
rta
=
arg
;
struct
in_device
*
in_dev
;
struct
in_device
*
in_dev
;
...
@@ -366,69 +385,79 @@ inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
...
@@ -366,69 +385,79 @@ inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
ASSERT_RTNL
();
ASSERT_RTNL
();
if
((
in_dev
=
inetdev_by_index
(
ifm
->
ifa_index
))
==
NULL
)
if
((
in_dev
=
inetdev_by_index
(
ifm
->
ifa_index
))
==
NULL
)
return
-
EADDRNOTAVAIL
;
goto
out
;
__in_dev_put
(
in_dev
);
__in_dev_put
(
in_dev
);
for
(
ifap
=&
in_dev
->
ifa_list
;
(
ifa
=*
ifap
)
!=
NULL
;
ifap
=&
ifa
->
ifa_next
)
{
for
(
ifap
=
&
in_dev
->
ifa_list
;
(
ifa
=
*
ifap
)
!=
NULL
;
if
((
rta
[
IFA_LOCAL
-
1
]
&&
memcmp
(
RTA_DATA
(
rta
[
IFA_LOCAL
-
1
]),
&
ifa
->
ifa_local
,
4
))
||
ifap
=
&
ifa
->
ifa_next
)
{
(
rta
[
IFA_LABEL
-
1
]
&&
strcmp
(
RTA_DATA
(
rta
[
IFA_LABEL
-
1
]),
ifa
->
ifa_label
))
||
if
((
rta
[
IFA_LOCAL
-
1
]
&&
(
rta
[
IFA_ADDRESS
-
1
]
&&
memcmp
(
RTA_DATA
(
rta
[
IFA_LOCAL
-
1
]),
&
ifa
->
ifa_local
,
4
))
||
(
rta
[
IFA_LABEL
-
1
]
&&
strcmp
(
RTA_DATA
(
rta
[
IFA_LABEL
-
1
]),
ifa
->
ifa_label
))
||
(
rta
[
IFA_ADDRESS
-
1
]
&&
(
ifm
->
ifa_prefixlen
!=
ifa
->
ifa_prefixlen
||
(
ifm
->
ifa_prefixlen
!=
ifa
->
ifa_prefixlen
||
!
inet_ifa_match
(
*
(
u32
*
)
RTA_DATA
(
rta
[
IFA_ADDRESS
-
1
]),
ifa
))))
!
inet_ifa_match
(
*
(
u32
*
)
RTA_DATA
(
rta
[
IFA_ADDRESS
-
1
]),
ifa
))))
continue
;
continue
;
inet_del_ifa
(
in_dev
,
ifap
,
1
);
inet_del_ifa
(
in_dev
,
ifap
,
1
);
return
0
;
return
0
;
}
}
out:
return
-
EADDRNOTAVAIL
;
return
-
EADDRNOTAVAIL
;
}
}
int
int
inet_rtm_newaddr
(
struct
sk_buff
*
skb
,
struct
nlmsghdr
*
nlh
,
void
*
arg
)
inet_rtm_newaddr
(
struct
sk_buff
*
skb
,
struct
nlmsghdr
*
nlh
,
void
*
arg
)
{
{
struct
rtattr
**
rta
=
arg
;
struct
rtattr
**
rta
=
arg
;
struct
net_device
*
dev
;
struct
net_device
*
dev
;
struct
in_device
*
in_dev
;
struct
in_device
*
in_dev
;
struct
ifaddrmsg
*
ifm
=
NLMSG_DATA
(
nlh
);
struct
ifaddrmsg
*
ifm
=
NLMSG_DATA
(
nlh
);
struct
in_ifaddr
*
ifa
;
struct
in_ifaddr
*
ifa
;
int
rc
=
-
EINVAL
;
ASSERT_RTNL
();
ASSERT_RTNL
();
if
(
ifm
->
ifa_prefixlen
>
32
||
rta
[
IFA_LOCAL
-
1
]
==
NULL
)
if
(
ifm
->
ifa_prefixlen
>
32
||
!
rta
[
IFA_LOCAL
-
1
]
)
return
-
EINVAL
;
goto
out
;
rc
=
-
ENODEV
;
if
((
dev
=
__dev_get_by_index
(
ifm
->
ifa_index
))
==
NULL
)
if
((
dev
=
__dev_get_by_index
(
ifm
->
ifa_index
))
==
NULL
)
return
-
ENODEV
;
goto
out
;
rc
=
-
ENOBUFS
;
if
((
in_dev
=
__in_dev_get
(
dev
))
==
NULL
)
{
if
((
in_dev
=
__in_dev_get
(
dev
))
==
NULL
)
{
in_dev
=
inetdev_init
(
dev
);
in_dev
=
inetdev_init
(
dev
);
if
(
!
in_dev
)
if
(
!
in_dev
)
return
-
ENOBUFS
;
goto
out
;
}
}
if
((
ifa
=
inet_alloc_ifa
())
==
NULL
)
if
((
ifa
=
inet_alloc_ifa
())
==
NULL
)
return
-
ENOBUFS
;
goto
out
;
if
(
rta
[
IFA_ADDRESS
-
1
]
==
NULL
)
if
(
!
rta
[
IFA_ADDRESS
-
1
]
)
rta
[
IFA_ADDRESS
-
1
]
=
rta
[
IFA_LOCAL
-
1
];
rta
[
IFA_ADDRESS
-
1
]
=
rta
[
IFA_LOCAL
-
1
];
memcpy
(
&
ifa
->
ifa_local
,
RTA_DATA
(
rta
[
IFA_LOCAL
-
1
]),
4
);
memcpy
(
&
ifa
->
ifa_local
,
RTA_DATA
(
rta
[
IFA_LOCAL
-
1
]),
4
);
memcpy
(
&
ifa
->
ifa_address
,
RTA_DATA
(
rta
[
IFA_ADDRESS
-
1
]),
4
);
memcpy
(
&
ifa
->
ifa_address
,
RTA_DATA
(
rta
[
IFA_ADDRESS
-
1
]),
4
);
ifa
->
ifa_prefixlen
=
ifm
->
ifa_prefixlen
;
ifa
->
ifa_prefixlen
=
ifm
->
ifa_prefixlen
;
ifa
->
ifa_mask
=
inet_make_mask
(
ifm
->
ifa_prefixlen
);
ifa
->
ifa_mask
=
inet_make_mask
(
ifm
->
ifa_prefixlen
);
if
(
rta
[
IFA_BROADCAST
-
1
])
if
(
rta
[
IFA_BROADCAST
-
1
])
memcpy
(
&
ifa
->
ifa_broadcast
,
RTA_DATA
(
rta
[
IFA_BROADCAST
-
1
]),
4
);
memcpy
(
&
ifa
->
ifa_broadcast
,
if
(
rta
[
IFA_ANYCAST
-
1
])
RTA_DATA
(
rta
[
IFA_BROADCAST
-
1
]),
4
);
memcpy
(
&
ifa
->
ifa_anycast
,
RTA_DATA
(
rta
[
IFA_ANYCAST
-
1
]),
4
);
if
(
rta
[
IFA_ANYCAST
-
1
])
memcpy
(
&
ifa
->
ifa_anycast
,
RTA_DATA
(
rta
[
IFA_ANYCAST
-
1
]),
4
);
ifa
->
ifa_flags
=
ifm
->
ifa_flags
;
ifa
->
ifa_flags
=
ifm
->
ifa_flags
;
ifa
->
ifa_scope
=
ifm
->
ifa_scope
;
ifa
->
ifa_scope
=
ifm
->
ifa_scope
;
in_dev_hold
(
in_dev
);
in_dev_hold
(
in_dev
);
ifa
->
ifa_dev
=
in_dev
;
ifa
->
ifa_dev
=
in_dev
;
if
(
rta
[
IFA_LABEL
-
1
])
if
(
rta
[
IFA_LABEL
-
1
])
memcpy
(
ifa
->
ifa_label
,
RTA_DATA
(
rta
[
IFA_LABEL
-
1
]),
IFNAMSIZ
);
memcpy
(
ifa
->
ifa_label
,
RTA_DATA
(
rta
[
IFA_LABEL
-
1
]),
IFNAMSIZ
);
else
else
memcpy
(
ifa
->
ifa_label
,
dev
->
name
,
IFNAMSIZ
);
memcpy
(
ifa
->
ifa_label
,
dev
->
name
,
IFNAMSIZ
);
return
inet_insert_ifa
(
ifa
);
rc
=
inet_insert_ifa
(
ifa
);
out:
return
rc
;
}
}
/*
/*
...
@@ -437,22 +466,22 @@ inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
...
@@ -437,22 +466,22 @@ inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
static
__inline__
int
inet_abc_len
(
u32
addr
)
static
__inline__
int
inet_abc_len
(
u32
addr
)
{
{
if
(
ZERONET
(
addr
))
int
rc
=
-
1
;
/* Something else, probably a multicast. */
return
0
;
if
(
ZERONET
(
addr
))
rc
=
0
;
else
{
addr
=
ntohl
(
addr
);
addr
=
ntohl
(
addr
);
if
(
IN_CLASSA
(
addr
))
return
8
;
if
(
IN_CLASSB
(
addr
))
return
16
;
if
(
IN_CLASSC
(
addr
))
return
24
;
/*
if
(
IN_CLASSA
(
addr
))
* Something else, probably a multicast.
rc
=
8
;
*/
else
if
(
IN_CLASSB
(
addr
))
rc
=
16
;
else
if
(
IN_CLASSC
(
addr
))
rc
=
24
;
}
return
-
1
;
return
rc
;
}
}
...
@@ -466,7 +495,7 @@ int devinet_ioctl(unsigned int cmd, void *arg)
...
@@ -466,7 +495,7 @@ int devinet_ioctl(unsigned int cmd, void *arg)
struct
in_ifaddr
*
ifa
=
NULL
;
struct
in_ifaddr
*
ifa
=
NULL
;
struct
net_device
*
dev
;
struct
net_device
*
dev
;
char
*
colon
;
char
*
colon
;
int
ret
=
0
;
int
ret
=
-
EFAULT
;
int
tryaddrmatch
=
0
;
int
tryaddrmatch
=
0
;
/*
/*
...
@@ -474,8 +503,8 @@ int devinet_ioctl(unsigned int cmd, void *arg)
...
@@ -474,8 +503,8 @@ int devinet_ioctl(unsigned int cmd, void *arg)
*/
*/
if
(
copy_from_user
(
&
ifr
,
arg
,
sizeof
(
struct
ifreq
)))
if
(
copy_from_user
(
&
ifr
,
arg
,
sizeof
(
struct
ifreq
)))
return
-
EFAULT
;
goto
out
;
ifr
.
ifr_name
[
IFNAMSIZ
-
1
]
=
0
;
ifr
.
ifr_name
[
IFNAMSIZ
-
1
]
=
0
;
/* save original address for comparison */
/* save original address for comparison */
memcpy
(
&
sin_orig
,
sin
,
sizeof
(
*
sin
));
memcpy
(
&
sin_orig
,
sin
,
sizeof
(
*
sin
));
...
@@ -503,43 +532,48 @@ int devinet_ioctl(unsigned int cmd, void *arg)
...
@@ -503,43 +532,48 @@ int devinet_ioctl(unsigned int cmd, void *arg)
break
;
break
;
case
SIOCSIFFLAGS
:
case
SIOCSIFFLAGS
:
ret
=
-
EACCES
;
if
(
!
capable
(
CAP_NET_ADMIN
))
if
(
!
capable
(
CAP_NET_ADMIN
))
return
-
EACCES
;
goto
out
;
break
;
break
;
case
SIOCSIFADDR
:
/* Set interface address (and family) */
case
SIOCSIFADDR
:
/* Set interface address (and family) */
case
SIOCSIFBRDADDR
:
/* Set the broadcast address */
case
SIOCSIFBRDADDR
:
/* Set the broadcast address */
case
SIOCSIFDSTADDR
:
/* Set the destination address */
case
SIOCSIFDSTADDR
:
/* Set the destination address */
case
SIOCSIFNETMASK
:
/* Set the netmask for the interface */
case
SIOCSIFNETMASK
:
/* Set the netmask for the interface */
ret
=
-
EACCES
;
if
(
!
capable
(
CAP_NET_ADMIN
))
if
(
!
capable
(
CAP_NET_ADMIN
))
return
-
EACCES
;
goto
out
;
ret
=
-
EINVAL
;
if
(
sin
->
sin_family
!=
AF_INET
)
if
(
sin
->
sin_family
!=
AF_INET
)
return
-
EINVAL
;
goto
out
;
break
;
break
;
default:
default:
return
-
EINVAL
;
ret
=
-
EINVAL
;
goto
out
;
}
}
dev_probe_lock
();
dev_probe_lock
();
rtnl_lock
();
rtnl_lock
();
if
((
dev
=
__dev_get_by_name
(
ifr
.
ifr_name
))
==
NULL
)
{
ret
=
-
ENODEV
;
ret
=
-
ENODEV
;
if
((
dev
=
__dev_get_by_name
(
ifr
.
ifr_name
))
==
NULL
)
goto
done
;
goto
done
;
}
if
(
colon
)
if
(
colon
)
*
colon
=
':'
;
*
colon
=
':'
;
if
((
in_dev
=
__in_dev_get
(
dev
))
!=
NULL
)
{
if
((
in_dev
=
__in_dev_get
(
dev
))
!=
NULL
)
{
if
(
tryaddrmatch
)
{
if
(
tryaddrmatch
)
{
/* Matthias Andree */
/* Matthias Andree */
/* compare label and address (4.4BSD style) */
/* compare label and address (4.4BSD style) */
/* note: we only do this for a limited set of ioctls
/* note: we only do this for a limited set of ioctls
and only if the original address family was AF_INET.
and only if the original address family was AF_INET.
This is checked above. */
This is checked above. */
for
(
ifap
=&
in_dev
->
ifa_list
;
(
ifa
=*
ifap
)
!=
NULL
;
ifap
=&
ifa
->
ifa_next
)
{
for
(
ifap
=
&
in_dev
->
ifa_list
;
(
ifa
=
*
ifap
)
!=
NULL
;
if
((
strcmp
(
ifr
.
ifr_name
,
ifa
->
ifa_label
)
==
0
)
ifap
=
&
ifa
->
ifa_next
)
{
&&
(
sin_orig
.
sin_addr
.
s_addr
==
ifa
->
ifa_address
))
{
if
(
!
strcmp
(
ifr
.
ifr_name
,
ifa
->
ifa_label
)
&&
sin_orig
.
sin_addr
.
s_addr
==
ifa
->
ifa_address
)
{
break
;
/* found */
break
;
/* found */
}
}
}
}
...
@@ -547,17 +581,17 @@ int devinet_ioctl(unsigned int cmd, void *arg)
...
@@ -547,17 +581,17 @@ int devinet_ioctl(unsigned int cmd, void *arg)
/* we didn't get a match, maybe the application is
/* we didn't get a match, maybe the application is
4.3BSD-style and passed in junk so we fall back to
4.3BSD-style and passed in junk so we fall back to
comparing just the label */
comparing just the label */
if
(
ifa
==
NULL
)
{
if
(
!
ifa
)
{
for
(
ifap
=&
in_dev
->
ifa_list
;
(
ifa
=*
ifap
)
!=
NULL
;
ifap
=&
ifa
->
ifa_next
)
for
(
ifap
=
&
in_dev
->
ifa_list
;
(
ifa
=
*
ifap
)
!=
NULL
;
if
(
strcmp
(
ifr
.
ifr_name
,
ifa
->
ifa_label
)
==
0
)
ifap
=
&
ifa
->
ifa_next
)
if
(
!
strcmp
(
ifr
.
ifr_name
,
ifa
->
ifa_label
))
break
;
break
;
}
}
}
}
if
(
ifa
==
NULL
&&
cmd
!=
SIOCSIFADDR
&&
cmd
!=
SIOCSIFFLAGS
)
{
ret
=
-
EADDRNOTAVAIL
;
ret
=
-
EADDRNOTAVAIL
;
if
(
!
ifa
&&
cmd
!=
SIOCSIFADDR
&&
cmd
!=
SIOCSIFFLAGS
)
goto
done
;
goto
done
;
}
switch
(
cmd
)
{
switch
(
cmd
)
{
case
SIOCGIFADDR
:
/* Get interface address */
case
SIOCGIFADDR
:
/* Get interface address */
...
@@ -578,11 +612,11 @@ int devinet_ioctl(unsigned int cmd, void *arg)
...
@@ -578,11 +612,11 @@ int devinet_ioctl(unsigned int cmd, void *arg)
case
SIOCSIFFLAGS
:
case
SIOCSIFFLAGS
:
if
(
colon
)
{
if
(
colon
)
{
if
(
ifa
==
NULL
)
{
ret
=
-
EADDRNOTAVAIL
;
ret
=
-
EADDRNOTAVAIL
;
if
(
!
ifa
)
break
;
break
;
}
ret
=
0
;
if
(
!
(
ifr
.
ifr_flags
&
IFF_UP
))
if
(
!
(
ifr
.
ifr_flags
&
IFF_UP
))
inet_del_ifa
(
in_dev
,
ifap
,
1
);
inet_del_ifa
(
in_dev
,
ifap
,
1
);
break
;
break
;
}
}
...
@@ -590,16 +624,14 @@ int devinet_ioctl(unsigned int cmd, void *arg)
...
@@ -590,16 +624,14 @@ int devinet_ioctl(unsigned int cmd, void *arg)
break
;
break
;
case
SIOCSIFADDR
:
/* Set interface address (and family) */
case
SIOCSIFADDR
:
/* Set interface address (and family) */
if
(
inet_abc_len
(
sin
->
sin_addr
.
s_addr
)
<
0
)
{
ret
=
-
EINVAL
;
ret
=
-
EINVAL
;
if
(
inet_abc_len
(
sin
->
sin_addr
.
s_addr
)
<
0
)
break
;
break
;
}
if
(
!
ifa
)
{
if
(
!
ifa
)
{
if
((
ifa
=
inet_alloc_ifa
())
==
NULL
)
{
ret
=
-
ENOBUFS
;
ret
=
-
ENOBUFS
;
if
((
ifa
=
inet_alloc_ifa
())
==
NULL
)
break
;
break
;
}
if
(
colon
)
if
(
colon
)
memcpy
(
ifa
->
ifa_label
,
ifr
.
ifr_name
,
IFNAMSIZ
);
memcpy
(
ifa
->
ifa_label
,
ifr
.
ifr_name
,
IFNAMSIZ
);
else
else
...
@@ -613,14 +645,15 @@ int devinet_ioctl(unsigned int cmd, void *arg)
...
@@ -613,14 +645,15 @@ int devinet_ioctl(unsigned int cmd, void *arg)
ifa
->
ifa_anycast
=
0
;
ifa
->
ifa_anycast
=
0
;
}
}
ifa
->
ifa_address
=
ifa
->
ifa_address
=
ifa
->
ifa_local
=
sin
->
sin_addr
.
s_addr
;
ifa
->
ifa_local
=
sin
->
sin_addr
.
s_addr
;
if
(
!
(
dev
->
flags
&
IFF_POINTOPOINT
))
{
if
(
!
(
dev
->
flags
&
IFF_POINTOPOINT
))
{
ifa
->
ifa_prefixlen
=
inet_abc_len
(
ifa
->
ifa_address
);
ifa
->
ifa_prefixlen
=
inet_abc_len
(
ifa
->
ifa_address
);
ifa
->
ifa_mask
=
inet_make_mask
(
ifa
->
ifa_prefixlen
);
ifa
->
ifa_mask
=
inet_make_mask
(
ifa
->
ifa_prefixlen
);
if
((
dev
->
flags
&
IFF_BROADCAST
)
&&
ifa
->
ifa_prefixlen
<
31
)
if
((
dev
->
flags
&
IFF_BROADCAST
)
&&
ifa
->
ifa_broadcast
=
ifa
->
ifa_address
|~
ifa
->
ifa_mask
;
ifa
->
ifa_prefixlen
<
31
)
ifa
->
ifa_broadcast
=
ifa
->
ifa_address
|
~
ifa
->
ifa_mask
;
}
else
{
}
else
{
ifa
->
ifa_prefixlen
=
32
;
ifa
->
ifa_prefixlen
=
32
;
ifa
->
ifa_mask
=
inet_make_mask
(
32
);
ifa
->
ifa_mask
=
inet_make_mask
(
32
);
...
@@ -629,6 +662,7 @@ int devinet_ioctl(unsigned int cmd, void *arg)
...
@@ -629,6 +662,7 @@ int devinet_ioctl(unsigned int cmd, void *arg)
break
;
break
;
case
SIOCSIFBRDADDR
:
/* Set the broadcast address */
case
SIOCSIFBRDADDR
:
/* Set the broadcast address */
ret
=
0
;
if
(
ifa
->
ifa_broadcast
!=
sin
->
sin_addr
.
s_addr
)
{
if
(
ifa
->
ifa_broadcast
!=
sin
->
sin_addr
.
s_addr
)
{
inet_del_ifa
(
in_dev
,
ifap
,
0
);
inet_del_ifa
(
in_dev
,
ifap
,
0
);
ifa
->
ifa_broadcast
=
sin
->
sin_addr
.
s_addr
;
ifa
->
ifa_broadcast
=
sin
->
sin_addr
.
s_addr
;
...
@@ -637,15 +671,16 @@ int devinet_ioctl(unsigned int cmd, void *arg)
...
@@ -637,15 +671,16 @@ int devinet_ioctl(unsigned int cmd, void *arg)
break
;
break
;
case
SIOCSIFDSTADDR
:
/* Set the destination address */
case
SIOCSIFDSTADDR
:
/* Set the destination address */
if
(
ifa
->
ifa_address
!=
sin
->
sin_addr
.
s_addr
)
{
ret
=
0
;
if
(
inet_abc_len
(
sin
->
sin_addr
.
s_addr
)
<
0
)
{
if
(
ifa
->
ifa_address
==
sin
->
sin_addr
.
s_addr
)
break
;
ret
=
-
EINVAL
;
ret
=
-
EINVAL
;
if
(
inet_abc_len
(
sin
->
sin_addr
.
s_addr
)
<
0
)
break
;
break
;
}
ret
=
0
;
inet_del_ifa
(
in_dev
,
ifap
,
0
);
inet_del_ifa
(
in_dev
,
ifap
,
0
);
ifa
->
ifa_address
=
sin
->
sin_addr
.
s_addr
;
ifa
->
ifa_address
=
sin
->
sin_addr
.
s_addr
;
inet_insert_ifa
(
ifa
);
inet_insert_ifa
(
ifa
);
}
break
;
break
;
case
SIOCSIFNETMASK
:
/* Set the netmask for the interface */
case
SIOCSIFNETMASK
:
/* Set the netmask for the interface */
...
@@ -653,11 +688,10 @@ int devinet_ioctl(unsigned int cmd, void *arg)
...
@@ -653,11 +688,10 @@ int devinet_ioctl(unsigned int cmd, void *arg)
/*
/*
* The mask we set must be legal.
* The mask we set must be legal.
*/
*/
if
(
bad_mask
(
sin
->
sin_addr
.
s_addr
,
0
))
{
ret
=
-
EINVAL
;
ret
=
-
EINVAL
;
if
(
bad_mask
(
sin
->
sin_addr
.
s_addr
,
0
))
break
;
break
;
}
ret
=
0
;
if
(
ifa
->
ifa_mask
!=
sin
->
sin_addr
.
s_addr
)
{
if
(
ifa
->
ifa_mask
!=
sin
->
sin_addr
.
s_addr
)
{
inet_del_ifa
(
in_dev
,
ifap
,
0
);
inet_del_ifa
(
in_dev
,
ifap
,
0
);
ifa
->
ifa_mask
=
sin
->
sin_addr
.
s_addr
;
ifa
->
ifa_mask
=
sin
->
sin_addr
.
s_addr
;
...
@@ -669,49 +703,51 @@ int devinet_ioctl(unsigned int cmd, void *arg)
...
@@ -669,49 +703,51 @@ int devinet_ioctl(unsigned int cmd, void *arg)
done:
done:
rtnl_unlock
();
rtnl_unlock
();
dev_probe_unlock
();
dev_probe_unlock
();
out:
return
ret
;
return
ret
;
rarok:
rarok:
rtnl_unlock
();
rtnl_unlock
();
dev_probe_unlock
();
dev_probe_unlock
();
if
(
copy_to_user
(
arg
,
&
ifr
,
sizeof
(
struct
ifreq
)))
ret
=
copy_to_user
(
arg
,
&
ifr
,
sizeof
(
struct
ifreq
))
?
-
EFAULT
:
0
;
return
-
EFAULT
;
goto
out
;
return
0
;
}
}
static
int
static
int
inet_gifconf
(
struct
net_device
*
dev
,
char
*
buf
,
int
len
)
inet_gifconf
(
struct
net_device
*
dev
,
char
*
buf
,
int
len
)
{
{
struct
in_device
*
in_dev
=
__in_dev_get
(
dev
);
struct
in_device
*
in_dev
=
__in_dev_get
(
dev
);
struct
in_ifaddr
*
ifa
;
struct
in_ifaddr
*
ifa
;
struct
ifreq
ifr
;
struct
ifreq
ifr
;
int
done
=
0
;
int
done
=
0
;
if
(
in_dev
==
NULL
||
(
ifa
=
in_dev
->
ifa_list
)
==
NULL
)
if
(
!
in_dev
||
(
ifa
=
in_dev
->
ifa_list
)
==
NULL
)
return
0
;
goto
out
;
for
(
;
ifa
;
ifa
=
ifa
->
ifa_next
)
{
for
(;
ifa
;
ifa
=
ifa
->
ifa_next
)
{
if
(
!
buf
)
{
if
(
!
buf
)
{
done
+=
sizeof
(
ifr
);
done
+=
sizeof
(
ifr
);
continue
;
continue
;
}
}
if
(
len
<
(
int
)
sizeof
(
ifr
))
if
(
len
<
(
int
)
sizeof
(
ifr
))
return
done
;
break
;
memset
(
&
ifr
,
0
,
sizeof
(
struct
ifreq
));
memset
(
&
ifr
,
0
,
sizeof
(
struct
ifreq
));
if
(
ifa
->
ifa_label
)
if
(
ifa
->
ifa_label
)
strcpy
(
ifr
.
ifr_name
,
ifa
->
ifa_label
);
strcpy
(
ifr
.
ifr_name
,
ifa
->
ifa_label
);
else
else
strcpy
(
ifr
.
ifr_name
,
dev
->
name
);
strcpy
(
ifr
.
ifr_name
,
dev
->
name
);
(
*
(
struct
sockaddr_in
*
)
&
ifr
.
ifr_addr
).
sin_family
=
AF_INET
;
(
*
(
struct
sockaddr_in
*
)
&
ifr
.
ifr_addr
).
sin_family
=
AF_INET
;
(
*
(
struct
sockaddr_in
*
)
&
ifr
.
ifr_addr
).
sin_addr
.
s_addr
=
ifa
->
ifa_local
;
(
*
(
struct
sockaddr_in
*
)
&
ifr
.
ifr_addr
).
sin_addr
.
s_addr
=
ifa
->
ifa_local
;
if
(
copy_to_user
(
buf
,
&
ifr
,
sizeof
(
struct
ifreq
)))
if
(
copy_to_user
(
buf
,
&
ifr
,
sizeof
(
struct
ifreq
)))
{
return
-
EFAULT
;
done
=
-
EFAULT
;
break
;
}
buf
+=
sizeof
(
struct
ifreq
);
buf
+=
sizeof
(
struct
ifreq
);
len
-=
sizeof
(
struct
ifreq
);
len
-=
sizeof
(
struct
ifreq
);
done
+=
sizeof
(
struct
ifreq
);
done
+=
sizeof
(
struct
ifreq
);
}
}
out:
return
done
;
return
done
;
}
}
...
@@ -722,10 +758,8 @@ u32 inet_select_addr(const struct net_device *dev, u32 dst, int scope)
...
@@ -722,10 +758,8 @@ u32 inet_select_addr(const struct net_device *dev, u32 dst, int scope)
read_lock
(
&
inetdev_lock
);
read_lock
(
&
inetdev_lock
);
in_dev
=
__in_dev_get
(
dev
);
in_dev
=
__in_dev_get
(
dev
);
if
(
in_dev
==
NULL
)
{
if
(
!
in_dev
)
read_unlock
(
&
inetdev_lock
);
goto
out_unlock_inetdev
;
return
0
;
}
read_lock
(
&
in_dev
->
lock
);
read_lock
(
&
in_dev
->
lock
);
for_primary_ifa
(
in_dev
)
{
for_primary_ifa
(
in_dev
)
{
...
@@ -742,7 +776,7 @@ u32 inet_select_addr(const struct net_device *dev, u32 dst, int scope)
...
@@ -742,7 +776,7 @@ u32 inet_select_addr(const struct net_device *dev, u32 dst, int scope)
read_unlock
(
&
inetdev_lock
);
read_unlock
(
&
inetdev_lock
);
if
(
addr
)
if
(
addr
)
return
addr
;
goto
out
;
/* Not loopback addresses on loopback should be preferred
/* Not loopback addresses on loopback should be preferred
in this case. It is importnat that lo is the first interface
in this case. It is importnat that lo is the first interface
...
@@ -750,8 +784,8 @@ u32 inet_select_addr(const struct net_device *dev, u32 dst, int scope)
...
@@ -750,8 +784,8 @@ u32 inet_select_addr(const struct net_device *dev, u32 dst, int scope)
*/
*/
read_lock
(
&
dev_base_lock
);
read_lock
(
&
dev_base_lock
);
read_lock
(
&
inetdev_lock
);
read_lock
(
&
inetdev_lock
);
for
(
dev
=
dev_base
;
dev
;
dev
=
dev
->
next
)
{
for
(
dev
=
dev_base
;
dev
;
dev
=
dev
->
next
)
{
if
((
in_dev
=
__in_dev_get
(
dev
))
==
NULL
)
if
((
in_dev
=
__in_dev_get
(
dev
))
==
NULL
)
continue
;
continue
;
read_lock
(
&
in_dev
->
lock
);
read_lock
(
&
in_dev
->
lock
);
...
@@ -759,17 +793,20 @@ u32 inet_select_addr(const struct net_device *dev, u32 dst, int scope)
...
@@ -759,17 +793,20 @@ u32 inet_select_addr(const struct net_device *dev, u32 dst, int scope)
if
(
ifa
->
ifa_scope
!=
RT_SCOPE_LINK
&&
if
(
ifa
->
ifa_scope
!=
RT_SCOPE_LINK
&&
ifa
->
ifa_scope
<=
scope
)
{
ifa
->
ifa_scope
<=
scope
)
{
read_unlock
(
&
in_dev
->
lock
);
read_unlock
(
&
in_dev
->
lock
);
read_unlock
(
&
inetdev_lock
);
addr
=
ifa
->
ifa_local
;
read_unlock
(
&
dev_base_lock
);
goto
out_unlock_both
;
return
ifa
->
ifa_local
;
}
}
}
endfor_ifa
(
in_dev
);
}
endfor_ifa
(
in_dev
);
read_unlock
(
&
in_dev
->
lock
);
read_unlock
(
&
in_dev
->
lock
);
}
}
out_unlock_both:
read_unlock
(
&
inetdev_lock
);
read_unlock
(
&
inetdev_lock
);
read_unlock
(
&
dev_base_lock
);
read_unlock
(
&
dev_base_lock
);
out:
return
0
;
return
addr
;
out_unlock_inetdev:
read_unlock
(
&
inetdev_lock
);
goto
out
;
}
}
/*
/*
...
@@ -783,20 +820,21 @@ int register_inetaddr_notifier(struct notifier_block *nb)
...
@@ -783,20 +820,21 @@ int register_inetaddr_notifier(struct notifier_block *nb)
int
unregister_inetaddr_notifier
(
struct
notifier_block
*
nb
)
int
unregister_inetaddr_notifier
(
struct
notifier_block
*
nb
)
{
{
return
notifier_chain_unregister
(
&
inetaddr_chain
,
nb
);
return
notifier_chain_unregister
(
&
inetaddr_chain
,
nb
);
}
}
/* Called only under RTNL semaphore */
/* Called only under RTNL semaphore */
static
int
inetdev_event
(
struct
notifier_block
*
this
,
unsigned
long
event
,
void
*
ptr
)
static
int
inetdev_event
(
struct
notifier_block
*
this
,
unsigned
long
event
,
void
*
ptr
)
{
{
struct
net_device
*
dev
=
ptr
;
struct
net_device
*
dev
=
ptr
;
struct
in_device
*
in_dev
=
__in_dev_get
(
dev
);
struct
in_device
*
in_dev
=
__in_dev_get
(
dev
);
ASSERT_RTNL
();
ASSERT_RTNL
();
if
(
in_dev
==
NULL
)
if
(
!
in_dev
)
return
NOTIFY_DONE
;
goto
out
;
switch
(
event
)
{
switch
(
event
)
{
case
NETDEV_REGISTER
:
case
NETDEV_REGISTER
:
...
@@ -843,7 +881,7 @@ static int inetdev_event(struct notifier_block *this, unsigned long event, void
...
@@ -843,7 +881,7 @@ static int inetdev_event(struct notifier_block *this, unsigned long event, void
}
}
break
;
break
;
}
}
out:
return
NOTIFY_DONE
;
return
NOTIFY_DONE
;
}
}
...
@@ -887,15 +925,14 @@ static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa,
...
@@ -887,15 +925,14 @@ static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa,
static
int
inet_dump_ifaddr
(
struct
sk_buff
*
skb
,
struct
netlink_callback
*
cb
)
static
int
inet_dump_ifaddr
(
struct
sk_buff
*
skb
,
struct
netlink_callback
*
cb
)
{
{
int
idx
,
ip_idx
;
int
idx
,
ip_idx
;
int
s_idx
,
s_ip_idx
;
struct
net_device
*
dev
;
struct
net_device
*
dev
;
struct
in_device
*
in_dev
;
struct
in_device
*
in_dev
;
struct
in_ifaddr
*
ifa
;
struct
in_ifaddr
*
ifa
;
int
s_ip_idx
,
s_idx
=
cb
->
args
[
0
];
s_idx
=
cb
->
args
[
0
];
s_ip_idx
=
ip_idx
=
cb
->
args
[
1
];
s_ip_idx
=
ip_idx
=
cb
->
args
[
1
];
read_lock
(
&
dev_base_lock
);
read_lock
(
&
dev_base_lock
);
for
(
dev
=
dev_base
,
idx
=
0
;
dev
;
dev
=
dev
->
next
,
idx
++
)
{
for
(
dev
=
dev_base
,
idx
=
0
;
dev
;
dev
=
dev
->
next
,
idx
++
)
{
if
(
idx
<
s_idx
)
if
(
idx
<
s_idx
)
continue
;
continue
;
if
(
idx
>
s_idx
)
if
(
idx
>
s_idx
)
...
@@ -911,7 +948,8 @@ static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
...
@@ -911,7 +948,8 @@ static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
if
(
ip_idx
<
s_ip_idx
)
if
(
ip_idx
<
s_ip_idx
)
continue
;
continue
;
if
(
inet_fill_ifaddr
(
skb
,
ifa
,
NETLINK_CB
(
cb
->
skb
).
pid
,
if
(
inet_fill_ifaddr
(
skb
,
ifa
,
NETLINK_CB
(
cb
->
skb
).
pid
,
cb
->
nlh
->
nlmsg_seq
,
RTM_NEWADDR
)
<=
0
)
{
cb
->
nlh
->
nlmsg_seq
,
RTM_NEWADDR
)
<=
0
)
{
read_unlock
(
&
in_dev
->
lock
);
read_unlock
(
&
in_dev
->
lock
);
read_unlock
(
&
inetdev_lock
);
read_unlock
(
&
inetdev_lock
);
goto
done
;
goto
done
;
...
@@ -929,65 +967,39 @@ static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
...
@@ -929,65 +967,39 @@ static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
return
skb
->
len
;
return
skb
->
len
;
}
}
static
void
rtmsg_ifa
(
int
event
,
struct
in_ifaddr
*
ifa
)
static
void
rtmsg_ifa
(
int
event
,
struct
in_ifaddr
*
ifa
)
{
{
struct
sk_buff
*
skb
;
int
size
=
NLMSG_SPACE
(
sizeof
(
struct
ifaddrmsg
)
+
128
)
;
int
size
=
NLMSG_SPACE
(
sizeof
(
struct
ifaddrmsg
)
+
128
);
struct
sk_buff
*
skb
=
alloc_skb
(
size
,
GFP_KERNEL
);
skb
=
alloc_skb
(
size
,
GFP_KERNEL
);
if
(
!
skb
)
if
(
!
skb
)
{
netlink_set_err
(
rtnl
,
0
,
RTMGRP_IPV4_IFADDR
,
ENOBUFS
);
netlink_set_err
(
rtnl
,
0
,
RTMGRP_IPV4_IFADDR
,
ENOBUFS
);
return
;
else
if
(
inet_fill_ifaddr
(
skb
,
ifa
,
0
,
0
,
event
)
<
0
)
{
}
if
(
inet_fill_ifaddr
(
skb
,
ifa
,
0
,
0
,
event
)
<
0
)
{
kfree_skb
(
skb
);
kfree_skb
(
skb
);
netlink_set_err
(
rtnl
,
0
,
RTMGRP_IPV4_IFADDR
,
EINVAL
);
netlink_set_err
(
rtnl
,
0
,
RTMGRP_IPV4_IFADDR
,
EINVAL
);
return
;
}
else
{
}
NETLINK_CB
(
skb
).
dst_groups
=
RTMGRP_IPV4_IFADDR
;
NETLINK_CB
(
skb
).
dst_groups
=
RTMGRP_IPV4_IFADDR
;
netlink_broadcast
(
rtnl
,
skb
,
0
,
RTMGRP_IPV4_IFADDR
,
GFP_KERNEL
);
netlink_broadcast
(
rtnl
,
skb
,
0
,
RTMGRP_IPV4_IFADDR
,
GFP_KERNEL
);
}
}
}
static
struct
rtnetlink_link
inet_rtnetlink_table
[
RTM_MAX
-
RTM_BASE
+
1
]
=
{
static
struct
rtnetlink_link
inet_rtnetlink_table
[
RTM_MAX
-
RTM_BASE
+
1
]
=
[
4
]
=
{
doit
:
inet_rtm_newaddr
,
},
{
[
5
]
=
{
doit
:
inet_rtm_deladdr
,
},
{
NULL
,
NULL
,
},
[
6
]
=
{
dumpit
:
inet_dump_ifaddr
,
},
{
NULL
,
NULL
,
},
[
8
]
=
{
doit
:
inet_rtm_newroute
,
},
{
NULL
,
NULL
,
},
[
9
]
=
{
doit
:
inet_rtm_delroute
,
},
{
NULL
,
NULL
,
},
[
10
]
=
{
doit
:
inet_rtm_getroute
,
dumpit
:
inet_dump_fib
,
},
{
inet_rtm_newaddr
,
NULL
,
},
{
inet_rtm_deladdr
,
NULL
,
},
{
NULL
,
inet_dump_ifaddr
,
},
{
NULL
,
NULL
,
},
{
inet_rtm_newroute
,
NULL
,
},
{
inet_rtm_delroute
,
NULL
,
},
{
inet_rtm_getroute
,
inet_dump_fib
,
},
{
NULL
,
NULL
,
},
{
NULL
,
NULL
,
},
{
NULL
,
NULL
,
},
{
NULL
,
NULL
,
},
{
NULL
,
NULL
,
},
#ifdef CONFIG_IP_MULTIPLE_TABLES
#ifdef CONFIG_IP_MULTIPLE_TABLES
{
inet_rtm_newrule
,
NULL
,
},
[
16
]
=
{
doit
:
inet_rtm_newrule
,
},
{
inet_rtm_delrule
,
NULL
,
},
[
17
]
=
{
doit
:
inet_rtm_delrule
,
},
{
NULL
,
inet_dump_rules
,
},
[
18
]
=
{
dumpit
:
inet_dump_rules
,
},
{
NULL
,
NULL
,
},
#else
{
NULL
,
NULL
,
},
{
NULL
,
NULL
,
},
{
NULL
,
NULL
,
},
{
NULL
,
NULL
,
},
#endif
#endif
};
};
#ifdef CONFIG_SYSCTL
#ifdef CONFIG_SYSCTL
void
inet_forward_change
()
void
inet_forward_change
(
void
)
{
{
struct
net_device
*
dev
;
struct
net_device
*
dev
;
int
on
=
ipv4_devconf
.
forwarding
;
int
on
=
ipv4_devconf
.
forwarding
;
...
@@ -1009,15 +1021,13 @@ void inet_forward_change()
...
@@ -1009,15 +1021,13 @@ void inet_forward_change()
rt_cache_flush
(
0
);
rt_cache_flush
(
0
);
}
}
static
static
int
devinet_sysctl_forward
(
ctl_table
*
ctl
,
int
write
,
int
devinet_sysctl_forward
(
ctl_table
*
ctl
,
int
write
,
struct
file
*
filp
,
struct
file
*
filp
,
void
*
buffer
,
void
*
buffer
,
size_t
*
lenp
)
size_t
*
lenp
)
{
{
int
*
valp
=
ctl
->
data
;
int
*
valp
=
ctl
->
data
;
int
val
=
*
valp
;
int
val
=
*
valp
;
int
ret
;
int
ret
=
proc_dointvec
(
ctl
,
write
,
filp
,
buffer
,
lenp
);
ret
=
proc_dointvec
(
ctl
,
write
,
filp
,
buffer
,
lenp
);
if
(
write
&&
*
valp
!=
val
)
{
if
(
write
&&
*
valp
!=
val
)
{
if
(
valp
==
&
ipv4_devconf
.
forwarding
)
if
(
valp
==
&
ipv4_devconf
.
forwarding
)
...
@@ -1029,8 +1039,7 @@ int devinet_sysctl_forward(ctl_table *ctl, int write, struct file * filp,
...
@@ -1029,8 +1039,7 @@ int devinet_sysctl_forward(ctl_table *ctl, int write, struct file * filp,
return
ret
;
return
ret
;
}
}
static
struct
devinet_sysctl_table
static
struct
devinet_sysctl_table
{
{
struct
ctl_table_header
*
sysctl_header
;
struct
ctl_table_header
*
sysctl_header
;
ctl_table
devinet_vars
[
15
];
ctl_table
devinet_vars
[
15
];
ctl_table
devinet_dev
[
2
];
ctl_table
devinet_dev
[
2
];
...
@@ -1038,69 +1047,168 @@ static struct devinet_sysctl_table
...
@@ -1038,69 +1047,168 @@ static struct devinet_sysctl_table
ctl_table
devinet_proto_dir
[
2
];
ctl_table
devinet_proto_dir
[
2
];
ctl_table
devinet_root_dir
[
2
];
ctl_table
devinet_root_dir
[
2
];
}
devinet_sysctl
=
{
}
devinet_sysctl
=
{
NULL
,
devinet_vars:
{
{{
NET_IPV4_CONF_FORWARDING
,
"forwarding"
,
{
&
ipv4_devconf
.
forwarding
,
sizeof
(
int
),
0644
,
NULL
,
ctl_name:
NET_IPV4_CONF_FORWARDING
,
&
devinet_sysctl_forward
},
procname:
"forwarding"
,
{
NET_IPV4_CONF_MC_FORWARDING
,
"mc_forwarding"
,
data:
&
ipv4_devconf
.
forwarding
,
&
ipv4_devconf
.
mc_forwarding
,
sizeof
(
int
),
0444
,
NULL
,
maxlen:
sizeof
(
int
),
&
proc_dointvec
},
mode:
0644
,
{
NET_IPV4_CONF_ACCEPT_REDIRECTS
,
"accept_redirects"
,
proc_handler:
&
devinet_sysctl_forward
,
&
ipv4_devconf
.
accept_redirects
,
sizeof
(
int
),
0644
,
NULL
,
},
&
proc_dointvec
},
{
{
NET_IPV4_CONF_SECURE_REDIRECTS
,
"secure_redirects"
,
ctl_name:
NET_IPV4_CONF_MC_FORWARDING
,
&
ipv4_devconf
.
secure_redirects
,
sizeof
(
int
),
0644
,
NULL
,
procname:
"mc_forwarding"
,
&
proc_dointvec
},
data:
&
ipv4_devconf
.
mc_forwarding
,
{
NET_IPV4_CONF_SHARED_MEDIA
,
"shared_media"
,
maxlen:
sizeof
(
int
),
&
ipv4_devconf
.
shared_media
,
sizeof
(
int
),
0644
,
NULL
,
mode:
0444
,
&
proc_dointvec
},
proc_handler:
&
proc_dointvec
,
{
NET_IPV4_CONF_RP_FILTER
,
"rp_filter"
,
},
&
ipv4_devconf
.
rp_filter
,
sizeof
(
int
),
0644
,
NULL
,
{
&
proc_dointvec
},
ctl_name:
NET_IPV4_CONF_ACCEPT_REDIRECTS
,
{
NET_IPV4_CONF_SEND_REDIRECTS
,
"send_redirects"
,
procname:
"accept_redirects"
,
&
ipv4_devconf
.
send_redirects
,
sizeof
(
int
),
0644
,
NULL
,
data:
&
ipv4_devconf
.
accept_redirects
,
&
proc_dointvec
},
maxlen:
sizeof
(
int
),
{
NET_IPV4_CONF_ACCEPT_SOURCE_ROUTE
,
"accept_source_route"
,
mode:
0644
,
&
ipv4_devconf
.
accept_source_route
,
sizeof
(
int
),
0644
,
NULL
,
proc_handler:
&
proc_dointvec
,
&
proc_dointvec
},
},
{
NET_IPV4_CONF_PROXY_ARP
,
"proxy_arp"
,
{
&
ipv4_devconf
.
proxy_arp
,
sizeof
(
int
),
0644
,
NULL
,
ctl_name:
NET_IPV4_CONF_SECURE_REDIRECTS
,
&
proc_dointvec
},
procname:
"secure_redirects"
,
{
NET_IPV4_CONF_MEDIUM_ID
,
"medium_id"
,
data:
&
ipv4_devconf
.
secure_redirects
,
&
ipv4_devconf
.
medium_id
,
sizeof
(
int
),
0644
,
NULL
,
maxlen:
sizeof
(
int
),
&
proc_dointvec
},
mode:
0644
,
{
NET_IPV4_CONF_BOOTP_RELAY
,
"bootp_relay"
,
proc_handler:
&
proc_dointvec
,
&
ipv4_devconf
.
bootp_relay
,
sizeof
(
int
),
0644
,
NULL
,
},
&
proc_dointvec
},
{
{
NET_IPV4_CONF_LOG_MARTIANS
,
"log_martians"
,
ctl_name:
NET_IPV4_CONF_SHARED_MEDIA
,
&
ipv4_devconf
.
log_martians
,
sizeof
(
int
),
0644
,
NULL
,
procname:
"shared_media"
,
&
proc_dointvec
},
data:
&
ipv4_devconf
.
shared_media
,
{
NET_IPV4_CONF_TAG
,
"tag"
,
maxlen:
sizeof
(
int
),
&
ipv4_devconf
.
tag
,
sizeof
(
int
),
0644
,
NULL
,
mode:
0644
,
&
proc_dointvec
},
proc_handler:
&
proc_dointvec
,
{
NET_IPV4_CONF_ARPFILTER
,
"arp_filter"
,
},
&
ipv4_devconf
.
arp_filter
,
sizeof
(
int
),
0644
,
NULL
,
{
&
proc_dointvec
},
ctl_name:
NET_IPV4_CONF_RP_FILTER
,
{
0
}},
procname:
"rp_filter"
,
data:
&
ipv4_devconf
.
rp_filter
,
{{
NET_PROTO_CONF_ALL
,
"all"
,
NULL
,
0
,
0555
,
devinet_sysctl
.
devinet_vars
},{
0
}},
maxlen:
sizeof
(
int
),
{{
NET_IPV4_CONF
,
"conf"
,
NULL
,
0
,
0555
,
devinet_sysctl
.
devinet_dev
},{
0
}},
mode:
0644
,
{{
NET_IPV4
,
"ipv4"
,
NULL
,
0
,
0555
,
devinet_sysctl
.
devinet_conf_dir
},{
0
}},
proc_handler:
&
proc_dointvec
,
{{
CTL_NET
,
"net"
,
NULL
,
0
,
0555
,
devinet_sysctl
.
devinet_proto_dir
},{
0
}}
},
{
ctl_name:
NET_IPV4_CONF_SEND_REDIRECTS
,
procname:
"send_redirects"
,
data:
&
ipv4_devconf
.
send_redirects
,
maxlen:
sizeof
(
int
),
mode:
0644
,
proc_handler:
&
proc_dointvec
,
},
{
ctl_name:
NET_IPV4_CONF_ACCEPT_SOURCE_ROUTE
,
procname:
"accept_source_route"
,
data:
&
ipv4_devconf
.
accept_source_route
,
maxlen:
sizeof
(
int
),
mode:
0644
,
proc_handler:
&
proc_dointvec
,
},
{
ctl_name:
NET_IPV4_CONF_PROXY_ARP
,
procname:
"proxy_arp"
,
data:
&
ipv4_devconf
.
proxy_arp
,
maxlen:
sizeof
(
int
),
mode:
0644
,
proc_handler:
&
proc_dointvec
,
},
{
ctl_name:
NET_IPV4_CONF_MEDIUM_ID
,
procname:
"medium_id"
,
data:
&
ipv4_devconf
.
medium_id
,
maxlen:
sizeof
(
int
),
mode:
0644
,
proc_handler:
&
proc_dointvec
,
},
{
ctl_name:
NET_IPV4_CONF_BOOTP_RELAY
,
procname:
"bootp_relay"
,
data:
&
ipv4_devconf
.
bootp_relay
,
maxlen:
sizeof
(
int
),
mode:
0644
,
proc_handler:
&
proc_dointvec
,
},
{
ctl_name:
NET_IPV4_CONF_LOG_MARTIANS
,
procname:
"log_martians"
,
data:
&
ipv4_devconf
.
log_martians
,
maxlen:
sizeof
(
int
),
mode:
0644
,
proc_handler:
&
proc_dointvec
,
},
{
ctl_name:
NET_IPV4_CONF_TAG
,
procname:
"tag"
,
data:
&
ipv4_devconf
.
tag
,
maxlen:
sizeof
(
int
),
mode:
0644
,
proc_handler:
&
proc_dointvec
,
},
{
ctl_name:
NET_IPV4_CONF_ARPFILTER
,
procname:
"arp_filter"
,
data:
&
ipv4_devconf
.
arp_filter
,
maxlen:
sizeof
(
int
),
mode:
0644
,
proc_handler:
&
proc_dointvec
,
},
},
devinet_dev:
{
{
ctl_name:
NET_PROTO_CONF_ALL
,
procname:
"all"
,
mode:
0555
,
child:
devinet_sysctl
.
devinet_vars
,
},
},
devinet_conf_dir:
{
{
ctl_name:
NET_IPV4_CONF
,
procname:
"conf"
,
mode:
0555
,
child:
devinet_sysctl
.
devinet_dev
,
},
},
devinet_proto_dir:
{
{
ctl_name:
NET_IPV4
,
procname:
"ipv4"
,
mode:
0555
,
child:
devinet_sysctl
.
devinet_conf_dir
,
},
},
devinet_root_dir:
{
{
ctl_name:
CTL_NET
,
procname:
"net"
,
mode:
0555
,
child:
devinet_sysctl
.
devinet_proto_dir
,
},
},
};
};
static
void
devinet_sysctl_register
(
struct
in_device
*
in_dev
,
struct
ipv4_devconf
*
p
)
static
void
devinet_sysctl_register
(
struct
in_device
*
in_dev
,
struct
ipv4_devconf
*
p
)
{
{
int
i
;
int
i
;
struct
net_device
*
dev
=
in_dev
?
in_dev
->
dev
:
NULL
;
struct
net_device
*
dev
=
in_dev
?
in_dev
->
dev
:
NULL
;
struct
devinet_sysctl_table
*
t
;
struct
devinet_sysctl_table
*
t
=
kmalloc
(
sizeof
(
*
t
),
GFP_KERNEL
)
;
t
=
kmalloc
(
sizeof
(
*
t
),
GFP_KERNEL
);
if
(
!
t
)
if
(
t
==
NULL
)
return
;
return
;
memcpy
(
t
,
&
devinet_sysctl
,
sizeof
(
*
t
));
memcpy
(
t
,
&
devinet_sysctl
,
sizeof
(
*
t
));
for
(
i
=
0
;
i
<
sizeof
(
t
->
devinet_vars
)
/
sizeof
(
t
->
devinet_vars
[
0
])
-
1
;
i
++
)
{
for
(
i
=
0
;
t
->
devinet_vars
[
i
].
data
+=
(
char
*
)
p
-
(
char
*
)
&
ipv4_devconf
;
i
<
sizeof
(
t
->
devinet_vars
)
/
sizeof
(
t
->
devinet_vars
[
0
])
-
1
;
i
++
)
{
t
->
devinet_vars
[
i
].
data
+=
(
char
*
)
p
-
(
char
*
)
&
ipv4_devconf
;
t
->
devinet_vars
[
i
].
de
=
NULL
;
t
->
devinet_vars
[
i
].
de
=
NULL
;
}
}
if
(
dev
)
{
if
(
dev
)
{
...
@@ -1120,7 +1228,7 @@ static void devinet_sysctl_register(struct in_device *in_dev, struct ipv4_devcon
...
@@ -1120,7 +1228,7 @@ static void devinet_sysctl_register(struct in_device *in_dev, struct ipv4_devcon
t
->
devinet_root_dir
[
0
].
de
=
NULL
;
t
->
devinet_root_dir
[
0
].
de
=
NULL
;
t
->
sysctl_header
=
register_sysctl_table
(
t
->
devinet_root_dir
,
0
);
t
->
sysctl_header
=
register_sysctl_table
(
t
->
devinet_root_dir
,
0
);
if
(
t
->
sysctl_header
==
NULL
)
if
(
!
t
->
sysctl_header
)
kfree
(
t
);
kfree
(
t
);
else
else
p
->
sysctl
=
t
;
p
->
sysctl
=
t
;
...
...
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