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
Hide 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 @@
* so sockets that fail to connect
* don't return -EINPROGRESS.
* 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
* Alan Cox : Semantics of SO_LINGER aren't state
moved
*
to close when you look carefully. With
*
this fixed and the accept bug fixed
* Alan Cox : Semantics of SO_LINGER aren't state
*
moved to close when you look carefully.
*
With this fixed and the accept bug fixed
* some RPC stuff seems happier.
* Niibe Yutaka : 4.4BSD style write async I/O
* Alan Cox,
* Alan Cox,
* Tony Gale : Fixed reuse semantics.
* Alan Cox : bind() shouldn't abort existing but dead
* sockets. Stops FTP netin:.. I hope.
* Alan Cox : bind() works correctly for RAW sockets. Note
* that FreeBSD at least was broken in this respect
* so be careful with compatibility tests...
* Alan Cox : bind() works correctly for RAW sockets.
* Note that FreeBSD at least was broken
* in this respect so be careful with
* compatibility tests...
* 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
* Alan Cox : Allow large numbers of pending sockets
* (eg for big web sites), but only if
* 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 : BSD rather than common sense
interpretation of
* listen.
* Alan Cox : BSD rather than common sense
*
interpretation of
listen.
* Germano Caronni : Assorted small races.
* Alan Cox : sendmsg/recvmsg basic support.
* Alan Cox : Only sendmsg/recvmsg now supported.
...
...
@@ -117,7 +121,7 @@
#include <linux/wireless.h>
/* Note : will define WIRELESS_EXT */
#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
atomic_t
inet_sock_nr
;
...
...
@@ -132,7 +136,7 @@ extern int udp_get_info(char *, char **, off_t, int);
extern
void
ip_mc_drop_socket
(
struct
sock
*
sk
);
#ifdef CONFIG_DLCI
extern
int
dlci_ioctl
(
unsigned
int
,
void
*
);
extern
int
dlci_ioctl
(
unsigned
int
,
void
*
);
#endif
#ifdef CONFIG_DLCI_MODULE
...
...
@@ -177,17 +181,18 @@ void inet_sock_destruct(struct sock *sk)
return
;
}
BUG_TRAP
(
atomic_read
(
&
sk
->
rmem_alloc
)
==
0
);
BUG_TRAP
(
atomic_read
(
&
sk
->
wmem_alloc
)
==
0
);
BUG_TRAP
(
sk
->
wmem_queued
==
0
);
BUG_TRAP
(
sk
->
forward_alloc
==
0
);
BUG_TRAP
(
!
atomic_read
(
&
sk
->
rmem_alloc
)
);
BUG_TRAP
(
!
atomic_read
(
&
sk
->
wmem_alloc
)
);
BUG_TRAP
(
!
sk
->
wmem_queued
);
BUG_TRAP
(
!
sk
->
forward_alloc
);
if
(
inet
->
opt
)
kfree
(
inet
->
opt
);
dst_release
(
sk
->
dst_cache
);
#ifdef INET_REFCNT_DEBUG
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
}
...
...
@@ -221,9 +226,9 @@ void inet_sock_release(struct sock *sk)
sock_orphan
(
sk
);
#ifdef INET_REFCNT_DEBUG
if
(
atomic_read
(
&
sk
->
refcnt
)
!=
1
)
{
printk
(
KERN_DEBUG
"Destruction inet %p delayed, c=%d
\n
"
,
sk
,
atomic_read
(
&
sk
->
refcnt
));
}
if
(
atomic_read
(
&
sk
->
refcnt
)
!=
1
)
printk
(
KERN_DEBUG
"Destruction inet %p delayed, c=%d
\n
"
,
sk
,
atomic_read
(
&
sk
->
refcnt
));
#endif
sock_put
(
sk
);
}
...
...
@@ -234,18 +239,16 @@ void inet_sock_release(struct sock *sk)
* socket object. Mostly it punts to the subprotocols of IP to do
* the work.
*/
/*
* Set socket options on an inet socket.
*/
int
inet_setsockopt
(
struct
socket
*
sock
,
int
level
,
int
optname
,
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,
int
inet_getsockopt
(
struct
socket
*
sock
,
int
level
,
int
optname
,
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,
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. */
lock_sock
(
sk
);
inet
=
inet_sk
(
sk
);
if
(
!
inet
->
num
)
{
if
(
sk
->
prot
->
get_port
(
sk
,
0
)
!=
0
)
{
if
(
sk
->
prot
->
get_port
(
sk
,
0
))
{
release_sock
(
sk
);
return
-
EAGAIN
;
}
...
...
@@ -287,7 +291,6 @@ static int inet_autobind(struct sock *sk)
/*
* Move a socket into listening state.
*/
int
inet_listen
(
struct
socket
*
sock
,
int
backlog
)
{
struct
sock
*
sk
=
sock
->
sk
;
...
...
@@ -301,7 +304,7 @@ int inet_listen(struct socket *sock, int backlog)
goto
out
;
old_state
=
sk
->
state
;
if
(
!
((
1
<<
old_state
)
&
(
TCPF_CLOSE
|
TCPF_LISTEN
)))
if
(
!
((
1
<<
old_state
)
&
(
TCPF_CLOSE
|
TCPF_LISTEN
)))
goto
out
;
/* Really, if the socket is already in listen state
...
...
@@ -349,16 +352,17 @@ static __inline__ int inet_sk_size(int protocol)
static
int
inet_create
(
struct
socket
*
sock
,
int
protocol
)
{
struct
sock
*
sk
;
struct
list_head
*
p
;
struct
inet_protosw
*
answer
;
struct
list_head
*
p
;
struct
inet_protosw
*
answer
;
struct
inet_opt
*
inet
;
int
err
=
-
ENOBUFS
;
sock
->
state
=
SS_UNCONNECTED
;
sk
=
sk_alloc
(
PF_INET
,
GFP_KERNEL
,
inet_sk_size
(
protocol
),
inet_sk_slab
(
protocol
));
if
(
sk
==
NULL
)
goto
do_oom
;
if
(
!
sk
)
goto
out
;
/* Look for the requested type/protocol pair. */
answer
=
NULL
;
br_read_lock_bh
(
BR_NETPROTO_LOCK
);
...
...
@@ -382,13 +386,16 @@ static int inet_create(struct socket *sock, int protocol)
}
br_read_unlock_bh
(
BR_NETPROTO_LOCK
);
err
=
-
ESOCKTNOSUPPORT
;
if
(
!
answer
)
goto
free_and_badtype
;
goto
out_sk_free
;
err
=
-
EPERM
;
if
(
answer
->
capability
>
0
&&
!
capable
(
answer
->
capability
))
goto
free_and_badperm
;
goto
out_sk_free
;
err
=
-
EPROTONOSUPPORT
;
if
(
!
protocol
)
goto
free_and_noproto
;
goto
out_sk_free
;
err
=
0
;
sock
->
ops
=
answer
->
ops
;
sk
->
prot
=
answer
->
prot
;
sk
->
no_check
=
answer
->
no_check
;
...
...
@@ -410,18 +417,15 @@ static int inet_create(struct socket *sock, int protocol)
inet
->
id
=
0
;
sock_init_data
(
sock
,
sk
);
sock_init_data
(
sock
,
sk
);
sk
->
destruct
=
inet_sock_destruct
;
sk
->
zapped
=
0
;
sk
->
family
=
PF_INET
;
sk
->
protocol
=
protocol
;
sk
->
backlog_rcv
=
sk
->
prot
->
backlog_rcv
;
inet
->
ttl
=
sysctl_ip_default_ttl
;
inet
->
mc_loop
=
1
;
inet
->
mc_ttl
=
1
;
inet
->
mc_index
=
0
;
...
...
@@ -438,34 +442,20 @@ static int inet_create(struct socket *sock, int protocol)
* shares.
*/
inet
->
sport
=
htons
(
inet
->
num
);
/* Add to protocol hash chains. */
sk
->
prot
->
hash
(
sk
);
}
if
(
sk
->
prot
->
init
)
{
int
err
=
sk
->
prot
->
init
(
sk
);
if
(
err
!=
0
)
{
err
=
sk
->
prot
->
init
(
sk
);
if
(
err
)
inet_sock_release
(
sk
);
return
err
;
}
}
return
0
;
free_and_badtype:
sk_free
(
sk
);
return
-
ESOCKTNOSUPPORT
;
free_and_badperm:
sk_free
(
sk
);
return
-
EPERM
;
free_and_noproto:
out:
return
err
;
out_sk_free:
sk_free
(
sk
);
return
-
EPROTONOSUPPORT
;
do_oom:
return
-
ENOBUFS
;
goto
out
;
}
...
...
@@ -474,7 +464,6 @@ static int inet_create(struct socket *sock, int protocol)
* function we are destroying the object and from then on nobody
* should refer to it.
*/
int
inet_release
(
struct
socket
*
sock
)
{
struct
sock
*
sk
=
sock
->
sk
;
...
...
@@ -498,7 +487,7 @@ int inet_release(struct socket *sock)
sock
->
sk
=
NULL
;
sk
->
prot
->
close
(
sk
,
timeout
);
}
return
(
0
)
;
return
0
;
}
/* It is off by default, see below. */
...
...
@@ -506,19 +495,21 @@ int sysctl_ip_nonlocal_bind;
static
int
inet_bind
(
struct
socket
*
sock
,
struct
sockaddr
*
uaddr
,
int
addr_len
)
{
struct
sockaddr_in
*
addr
=
(
struct
sockaddr_in
*
)
uaddr
;
struct
sock
*
sk
=
sock
->
sk
;
struct
sockaddr_in
*
addr
=
(
struct
sockaddr_in
*
)
uaddr
;
struct
sock
*
sk
=
sock
->
sk
;
struct
inet_opt
*
inet
=
inet_sk
(
sk
);
unsigned
short
snum
;
int
chk_addr_ret
;
int
err
;
/* If the socket has its own bind function then use it. (RAW) */
if
(
sk
->
prot
->
bind
)
return
sk
->
prot
->
bind
(
sk
,
uaddr
,
addr_len
);
if
(
sk
->
prot
->
bind
)
{
err
=
sk
->
prot
->
bind
(
sk
,
uaddr
,
addr_len
);
goto
out
;
}
err
=
-
EINVAL
;
if
(
addr_len
<
sizeof
(
struct
sockaddr_in
))
return
-
EINVAL
;
goto
out
;
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)
* (ie. your servers still start up even if your ISDN link
* is temporarily down)
*/
if
(
sysctl_ip_nonlocal_bind
==
0
&&
inet
->
freebind
==
0
&&
err
=
-
EADDRNOTAVAIL
;
if
(
!
sysctl_ip_nonlocal_bind
&&
!
inet
->
freebind
&&
addr
->
sin_addr
.
s_addr
!=
INADDR_ANY
&&
chk_addr_ret
!=
RTN_LOCAL
&&
chk_addr_ret
!=
RTN_MULTICAST
&&
chk_addr_ret
!=
RTN_BROADCAST
)
return
-
EADDRNOTAVAIL
;
goto
out
;
snum
=
ntohs
(
addr
->
sin_port
);
err
=
-
EACCES
;
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
* 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)
/* Check these errors (active socket, double bind). */
err
=
-
EINVAL
;
if
(
sk
->
state
!=
TCP_CLOSE
||
inet
->
num
)
goto
out
;
goto
out
_release_sock
;
inet
->
rcv_saddr
=
inet
->
saddr
=
addr
->
sin_addr
.
s_addr
;
if
(
chk_addr_ret
==
RTN_MULTICAST
||
chk_addr_ret
==
RTN_BROADCAST
)
inet
->
saddr
=
0
;
/* Use device */
/* 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
;
err
=
-
EADDRINUSE
;
goto
out
;
goto
out
_release_sock
;
}
if
(
inet
->
rcv_saddr
)
...
...
@@ -575,15 +568,16 @@ static int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
inet
->
dport
=
0
;
sk_dst_reset
(
sk
);
err
=
0
;
out:
out
_release_sock
:
release_sock
(
sk
);
out:
return
err
;
}
int
inet_dgram_connect
(
struct
socket
*
sock
,
struct
sockaddr
*
uaddr
,
int
addr_len
,
int
flags
)
{
struct
sock
*
sk
=
sock
->
sk
;
struct
sock
*
sk
=
sock
->
sk
;
if
(
uaddr
->
sa_family
==
AF_UNSPEC
)
return
sk
->
prot
->
disconnect
(
sk
,
flags
);
...
...
@@ -605,7 +599,7 @@ static long inet_wait_for_connect(struct sock *sk, long timeo)
* Connect() does not allow to get error notifications
* 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
);
timeo
=
schedule_timeout
(
timeo
);
lock_sock
(
sk
);
...
...
@@ -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
* 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
)
{
struct
sock
*
sk
=
sock
->
sk
;
struct
sock
*
sk
=
sock
->
sk
;
int
err
;
long
timeo
;
...
...
@@ -651,7 +644,7 @@ int inet_stream_connect(struct socket *sock, struct sockaddr * uaddr,
break
;
case
SS_UNCONNECTED
:
err
=
-
EISCONN
;
if
(
sk
->
state
!=
TCP_CLOSE
)
if
(
sk
->
state
!=
TCP_CLOSE
)
goto
out
;
err
=
sk
->
prot
->
connect
(
sk
,
uaddr
,
addr_len
);
...
...
@@ -668,9 +661,9 @@ int inet_stream_connect(struct socket *sock, struct sockaddr * uaddr,
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 */
if
(
!
timeo
||
!
inet_wait_for_connect
(
sk
,
timeo
))
goto
out
;
...
...
@@ -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
)
{
struct
sock
*
sk1
=
sock
->
sk
;
struct
sock
*
sk2
;
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
;
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
);
newsock
->
state
=
SS_CONNECTED
;
err
=
0
;
release_sock
(
sk2
);
return
0
;
do_err:
return
err
;
}
...
...
@@ -736,19 +729,18 @@ int inet_accept(struct socket *sock, struct socket *newsock, int flags)
/*
* This does both peername and sockname.
*/
static
int
inet_getname
(
struct
socket
*
sock
,
struct
sockaddr
*
uaddr
,
int
*
uaddr_len
,
int
peer
)
int
*
uaddr_len
,
int
peer
)
{
struct
sock
*
sk
=
sock
->
sk
;
struct
inet_opt
*
inet
=
inet_sk
(
sk
);
struct
sockaddr_in
*
sin
=
(
struct
sockaddr_in
*
)
uaddr
;
sin
->
sin_family
=
AF_INET
;
if
(
peer
)
{
if
(
!
inet
->
dport
)
return
-
ENOTCONN
;
if
(((
1
<<
sk
->
state
)
&
(
TCPF_CLOSE
|
TCPF_SYN_SENT
))
&&
peer
==
1
)
if
(
!
inet
->
dport
||
(((
1
<<
sk
->
state
)
&
(
TCPF_CLOSE
|
TCPF_SYN_SENT
))
&&
peer
==
1
)
)
return
-
ENOTCONN
;
sin
->
sin_port
=
inet
->
dport
;
sin
->
sin_addr
.
s_addr
=
inet
->
daddr
;
...
...
@@ -760,7 +752,7 @@ static int inet_getname(struct socket *sock, struct sockaddr *uaddr,
sin
->
sin_addr
.
s_addr
=
addr
;
}
*
uaddr_len
=
sizeof
(
*
sin
);
return
(
0
)
;
return
0
;
}
...
...
@@ -770,10 +762,8 @@ int inet_recvmsg(struct socket *sock, struct msghdr *msg, int size,
{
struct
sock
*
sk
=
sock
->
sk
;
int
addr_len
=
0
;
int
err
;
err
=
sk
->
prot
->
recvmsg
(
sk
,
msg
,
size
,
flags
&
MSG_DONTWAIT
,
flags
&~
MSG_DONTWAIT
,
&
addr_len
);
int
err
=
sk
->
prot
->
recvmsg
(
sk
,
msg
,
size
,
flags
&
MSG_DONTWAIT
,
flags
&
~
MSG_DONTWAIT
,
&
addr_len
);
if
(
err
>=
0
)
msg
->
msg_namelen
=
addr_len
;
return
err
;
...
...
@@ -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
1->2 bit 2 snds.
2->3 */
if
((
how
&
~
SHUTDOWN_MASK
)
||
how
==
0
)
/* MAXINT->0 */
if
((
how
&
~
SHUTDOWN_MASK
)
||
!
how
)
/* MAXINT->0 */
return
-
EINVAL
;
lock_sock
(
sk
);
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
;
else
sock
->
state
=
SS_CONNECTED
;
...
...
@@ -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
)
{
struct
sock
*
sk
=
sock
->
sk
;
int
err
;
int
err
=
0
;
int
pid
;
switch
(
cmd
)
{
switch
(
cmd
)
{
case
FIOSETOWN
:
case
SIOCSPGRP
:
err
=
get_user
(
pid
,
(
int
*
)
arg
);
if
(
err
)
return
err
;
if
(
current
->
pid
!=
pid
&&
current
->
pgrp
!=
-
pid
&&
!
capable
(
CAP_NET_ADMIN
))
return
-
EPERM
;
sk
->
proc
=
pid
;
return
(
0
);
if
(
get_user
(
pid
,
(
int
*
)
arg
))
err
=
-
EFAULT
;
else
if
(
current
->
pid
!=
pid
&&
current
->
pgrp
!=
-
pid
&&
!
capable
(
CAP_NET_ADMIN
))
err
=
-
EPERM
;
else
sk
->
proc
=
pid
;
break
;
case
FIOGETOWN
:
case
SIOCGPGRP
:
return
put_user
(
sk
->
proc
,
(
int
*
)
arg
);
err
=
put_user
(
sk
->
proc
,
(
int
*
)
arg
);
break
;
case
SIOCGSTAMP
:
if
(
sk
->
stamp
.
tv_sec
==
0
)
return
-
ENOENT
;
e
rr
=
copy_to_user
((
void
*
)
arg
,
&
sk
->
stamp
,
sizeof
(
struct
timeval
));
if
(
err
)
if
(
!
sk
->
stamp
.
tv_sec
)
err
=
-
ENOENT
;
e
lse
if
(
copy_to_user
((
void
*
)
arg
,
&
sk
->
stamp
,
sizeof
(
struct
timeval
))
)
err
=
-
EFAULT
;
return
err
;
break
;
case
SIOCADDRT
:
case
SIOCDELRT
:
case
SIOCRTMSG
:
return
(
ip_rt_ioctl
(
cmd
,(
void
*
)
arg
));
err
=
ip_rt_ioctl
(
cmd
,
(
void
*
)
arg
);
break
;
case
SIOCDARP
:
case
SIOCGARP
:
case
SIOCSARP
:
return
(
arp_ioctl
(
cmd
,(
void
*
)
arg
));
err
=
arp_ioctl
(
cmd
,
(
void
*
)
arg
);
break
;
case
SIOCGIFADDR
:
case
SIOCSIFADDR
:
case
SIOCGIFBRDADDR
:
...
...
@@ -898,83 +893,82 @@ static int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
case
SIOCSIFNETMASK
:
case
SIOCGIFDSTADDR
:
case
SIOCSIFDSTADDR
:
case
SIOCSIFPFLAGS
:
case
SIOCGIFPFLAGS
:
case
SIOCSIFPFLAGS
:
case
SIOCGIFPFLAGS
:
case
SIOCSIFFLAGS
:
return
(
devinet_ioctl
(
cmd
,(
void
*
)
arg
));
err
=
devinet_ioctl
(
cmd
,
(
void
*
)
arg
);
break
;
case
SIOCGIFBR
:
case
SIOCSIFBR
:
#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
#ifdef CONFIG_KMOD
if
(
br_ioctl_hook
==
NULL
)
if
(
!
br_ioctl_hook
)
request_module
(
"bridge"
);
#endif
if
(
br_ioctl_hook
!=
NULL
)
return
br_ioctl_hook
(
arg
);
if
(
br_ioctl_hook
)
err
=
br_ioctl_hook
(
arg
);
else
#endif
return
-
ENOPKG
;
err
=
-
ENOPKG
;
break
;
case
SIOCGIFVLAN
:
case
SIOCSIFVLAN
:
#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
#ifdef CONFIG_KMOD
if
(
vlan_ioctl_hook
==
NULL
)
if
(
!
vlan_ioctl_hook
)
request_module
(
"8021q"
);
#endif
if
(
vlan_ioctl_hook
!=
NULL
)
return
vlan_ioctl_hook
(
arg
);
if
(
vlan_ioctl_hook
)
err
=
vlan_ioctl_hook
(
arg
);
else
#endif
return
-
ENOPKG
;
err
=
-
ENOPKG
;
break
;
case
SIOCGIFDIVERT
:
case
SIOCSIFDIVERT
:
#ifdef CONFIG_NET_DIVERT
return
divert_ioctl
(
cmd
,
(
struct
divert_cf
*
)
arg
);
err
=
divert_ioctl
(
cmd
,
(
struct
divert_cf
*
)
arg
);
#else
return
-
ENOPKG
;
err
=
-
ENOPKG
;
#endif
/* CONFIG_NET_DIVERT */
break
;
case
SIOCADDDLCI
:
case
SIOCDELDLCI
:
#ifdef CONFIG_DLCI
lock_kernel
();
err
=
dlci_ioctl
(
cmd
,
(
void
*
)
arg
);
err
=
dlci_ioctl
(
cmd
,
(
void
*
)
arg
);
unlock_kernel
();
return
err
;
#endif
#ifdef CONFIG_DLCI_MODULE
break
;
#elif CONFIG_DLCI_MODULE
#ifdef CONFIG_KMOD
if
(
dlci_ioctl_hook
==
NULL
)
if
(
!
dlci_ioctl_hook
)
request_module
(
"dlci"
);
#endif
if
(
dlci_ioctl_hook
)
{
lock_kernel
();
err
=
(
*
dlci_ioctl_hook
)(
cmd
,
(
void
*
)
arg
);
err
=
(
*
dlci_ioctl_hook
)(
cmd
,
(
void
*
)
arg
);
unlock_kernel
();
return
err
;
}
}
else
#endif
return
-
ENOPKG
;
err
=
-
ENOPKG
;
break
;
default:
if
(
(
cmd
>=
SIOCDEVPRIVATE
)
&&
(
cmd
<=
(
SIOCDEVPRIVATE
+
15
)
))
return
(
dev_ioctl
(
cmd
,(
void
*
)
arg
)
);
if
(
cmd
>=
SIOCDEVPRIVATE
&&
cmd
<=
(
SIOCDEVPRIVATE
+
15
))
err
=
dev_ioctl
(
cmd
,
(
void
*
)
arg
);
else
#ifdef WIRELESS_EXT
if
((
cmd
>=
SIOCIWFIRST
)
&&
(
cmd
<=
SIOCIWLAST
))
return
(
dev_ioctl
(
cmd
,(
void
*
)
arg
));
if
(
cmd
>=
SIOCIWFIRST
&&
cmd
<=
SIOCIWLAST
)
err
=
dev_ioctl
(
cmd
,
(
void
*
)
arg
);
else
#endif
/* WIRELESS_EXT */
if
(
sk
->
prot
->
ioctl
==
NULL
||
(
err
=
sk
->
prot
->
ioctl
(
sk
,
cmd
,
arg
))
==-
ENOIOCTLCMD
)
return
(
dev_ioctl
(
cmd
,(
void
*
)
arg
));
return
err
;
if
(
!
sk
->
prot
->
ioctl
||
(
err
=
sk
->
prot
->
ioctl
(
sk
,
cmd
,
arg
))
==
-
ENOIOCTLCMD
)
err
=
dev_ioctl
(
cmd
,
(
void
*
)
arg
);
break
;
}
/*NOTREACHED*/
return
(
0
);
return
err
;
}
struct
proto_ops
inet_stream_ops
=
{
...
...
@@ -985,7 +979,7 @@ struct proto_ops inet_stream_ops = {
connect:
inet_stream_connect
,
socketpair:
sock_no_socketpair
,
accept:
inet_accept
,
getname:
inet_getname
,
getname:
inet_getname
,
poll:
tcp_poll
,
ioctl:
inet_ioctl
,
listen:
inet_listen
,
...
...
@@ -1006,7 +1000,7 @@ struct proto_ops inet_dgram_ops = {
connect:
inet_dgram_connect
,
socketpair:
sock_no_socketpair
,
accept:
sock_no_accept
,
getname:
inet_getname
,
getname:
inet_getname
,
poll:
datagram_poll
,
ioctl:
inet_ioctl
,
listen:
sock_no_listen
,
...
...
@@ -1067,8 +1061,7 @@ static struct inet_protosw inetsw_array[] =
#define INETSW_ARRAY_LEN (sizeof(inetsw_array) / sizeof(struct inet_protosw))
void
inet_register_protosw
(
struct
inet_protosw
*
p
)
void
inet_register_protosw
(
struct
inet_protosw
*
p
)
{
struct
list_head
*
lh
;
struct
inet_protosw
*
answer
;
...
...
@@ -1115,8 +1108,7 @@ inet_register_protosw(struct inet_protosw *p)
goto
out
;
}
void
inet_unregister_protosw
(
struct
inet_protosw
*
p
)
void
inet_unregister_protosw
(
struct
inet_protosw
*
p
)
{
if
(
INET_PROTOSW_PERMANENT
&
p
->
flags
)
{
printk
(
KERN_ERR
...
...
@@ -1133,7 +1125,7 @@ inet_unregister_protosw(struct inet_protosw *p)
/*
* Called by socket.c on kernel startup.
*/
static
int
__init
inet_init
(
void
)
{
struct
sk_buff
*
dummy_skb
;
...
...
@@ -1157,32 +1149,32 @@ static int __init inet_init(void)
raw4_sk_cachep
=
kmem_cache_create
(
"raw4_sock"
,
sizeof
(
struct
raw_sock
),
0
,
SLAB_HWCACHE_ALIGN
,
0
,
0
);
if
(
!
tcp_sk_cachep
||
!
udp_sk_cachep
||
!
raw4_sk_cachep
)
if
(
!
tcp_sk_cachep
||
!
udp_sk_cachep
||
!
raw4_sk_cachep
)
printk
(
KERN_CRIT
"inet_init: Can't create protocol sock SLAB caches!
\n
"
);
/*
* Tell SOCKET that we are alive...
*/
(
void
)
sock_register
(
&
inet_family_ops
);
(
void
)
sock_register
(
&
inet_family_ops
);
/*
* Add all the protocols.
*/
printk
(
KERN_INFO
"IP Protocols: "
);
for
(
p
=
inet_protocol_base
;
p
!=
NULL
;)
{
struct
inet_protocol
*
tmp
=
(
struct
inet_protocol
*
)
p
->
next
;
for
(
p
=
inet_protocol_base
;
p
;)
{
struct
inet_protocol
*
tmp
=
(
struct
inet_protocol
*
)
p
->
next
;
inet_add_protocol
(
p
);
printk
(
"%s%s"
,
p
->
name
,
tmp
?
", "
:
"
\n
"
);
printk
(
"%s%s"
,
p
->
name
,
tmp
?
", "
:
"
\n
"
);
p
=
tmp
;
}
/* 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
);
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
);
/*
...
...
net/ipv4/devinet.c
View file @
eb2e01d8
...
...
@@ -18,16 +18,17 @@
* Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
*
* Changes:
* Alexey Kuznetsov: pa_* fields are replaced with ifaddr lists.
* Alexey Kuznetsov: pa_* fields are replaced with ifaddr
* lists.
* 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),
* fall back to comparing just the label
* if no match found.
*/
#include <linux/config.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/bitops.h>
...
...
@@ -60,15 +61,29 @@
#include <net/route.h>
#include <net/ip_fib.h>
struct
ipv4_devconf
ipv4_devconf
=
{
1
,
1
,
1
,
1
,
0
,
};
static
struct
ipv4_devconf
ipv4_devconf_dflt
=
{
1
,
1
,
1
,
1
,
1
,
};
struct
ipv4_devconf
ipv4_devconf
=
{
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
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
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
);
#endif
...
...
@@ -79,12 +94,10 @@ int inet_dev_count;
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
)
{
memset
(
ifa
,
0
,
sizeof
(
*
ifa
));
inet_ifa_count
++
;
...
...
@@ -105,18 +118,19 @@ void in_dev_finish_destroy(struct in_device *idev)
{
struct
net_device
*
dev
=
idev
->
dev
;
BUG_TRAP
(
idev
->
ifa_list
==
NULL
);
BUG_TRAP
(
idev
->
mc_list
==
NULL
);
BUG_TRAP
(
!
idev
->
ifa_list
);
BUG_TRAP
(
!
idev
->
mc_list
);
#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
dev_put
(
dev
);
if
(
!
idev
->
dead
)
{
if
(
!
idev
->
dead
)
printk
(
"Freeing alive in_device %p
\n
"
,
idev
);
return
;
else
{
inet_dev_count
--
;
kfree
(
idev
);
}
inet_dev_count
--
;
kfree
(
idev
);
}
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
);
if
(
!
in_dev
)
return
NULL
;
goto
out
;
memset
(
in_dev
,
0
,
sizeof
(
*
in_dev
));
in_dev
->
lock
=
RW_LOCK_UNLOCKED
;
memcpy
(
&
in_dev
->
cnf
,
&
ipv4_devconf_dflt
,
sizeof
(
in_dev
->
cnf
));
in_dev
->
cnf
.
sysctl
=
NULL
;
in_dev
->
dev
=
dev
;
if
((
in_dev
->
arp_parms
=
neigh_parms_alloc
(
dev
,
&
arp_tbl
))
==
NULL
)
{
kfree
(
in_dev
);
return
NULL
;
}
if
((
in_dev
->
arp_parms
=
neigh_parms_alloc
(
dev
,
&
arp_tbl
))
==
NULL
)
goto
out_kfree
;
inet_dev_count
++
;
/* Reference in_dev->dev */
dev_hold
(
dev
);
#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
write_lock_bh
(
&
inetdev_lock
);
dev
->
ip_ptr
=
in_dev
;
...
...
@@ -151,9 +164,14 @@ struct in_device *inetdev_init(struct net_device *dev)
#ifdef CONFIG_SYSCTL
devinet_sysctl_register
(
in_dev
,
&
in_dev
->
cnf
);
#endif
if
(
dev
->
flags
&
IFF_UP
)
if
(
dev
->
flags
&
IFF_UP
)
ip_mc_up
(
in_dev
);
out:
return
in_dev
;
out_kfree:
kfree
(
in_dev
);
in_dev
=
NULL
;
goto
out
;
}
static
void
inetdev_destroy
(
struct
in_device
*
in_dev
)
...
...
@@ -197,10 +215,10 @@ int inet_addr_onlink(struct in_device *in_dev, u32 a, u32 b)
}
endfor_ifa
(
in_dev
);
read_unlock
(
&
in_dev
->
lock
);
return
0
;
}
}
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
)
{
struct
in_ifaddr
*
ifa1
=
*
ifap
;
...
...
@@ -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 */
if
(
!
(
ifa1
->
ifa_flags
&
IFA_F_SECONDARY
))
{
if
(
!
(
ifa1
->
ifa_flags
&
IFA_F_SECONDARY
))
{
struct
in_ifaddr
*
ifa
;
struct
in_ifaddr
**
ifap1
=
&
ifa1
->
ifa_next
;
while
((
ifa
=
*
ifap1
)
!=
NULL
)
{
if
(
!
(
ifa
->
ifa_flags
&
IFA_F_SECONDARY
)
||
while
((
ifa
=
*
ifap1
)
!=
NULL
)
{
if
(
!
(
ifa
->
ifa_flags
&
IFA_F_SECONDARY
)
||
ifa1
->
ifa_mask
!=
ifa
->
ifa_mask
||
!
inet_ifa_match
(
ifa1
->
ifa_address
,
ifa
))
{
ifap1
=
&
ifa
->
ifa_next
;
...
...
@@ -250,20 +268,19 @@ inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, int destroy)
if
(
destroy
)
{
inet_free_ifa
(
ifa1
);
if
(
in_dev
->
ifa_list
==
NULL
)
if
(
!
in_dev
->
ifa_list
)
inetdev_destroy
(
in_dev
);
}
}
static
int
inet_insert_ifa
(
struct
in_ifaddr
*
ifa
)
static
int
inet_insert_ifa
(
struct
in_ifaddr
*
ifa
)
{
struct
in_device
*
in_dev
=
ifa
->
ifa_dev
;
struct
in_ifaddr
*
ifa1
,
**
ifap
,
**
last_primary
;
ASSERT_RTNL
();
if
(
ifa
->
ifa_local
==
0
)
{
if
(
!
ifa
->
ifa_local
)
{
inet_free_ifa
(
ifa
);
return
0
;
}
...
...
@@ -271,10 +288,13 @@ inet_insert_ifa(struct in_ifaddr *ifa)
ifa
->
ifa_flags
&=
~
IFA_F_SECONDARY
;
last_primary
=
&
in_dev
->
ifa_list
;
for
(
ifap
=&
in_dev
->
ifa_list
;
(
ifa1
=*
ifap
)
!=
NULL
;
ifap
=&
ifa1
->
ifa_next
)
{
if
(
!
(
ifa1
->
ifa_flags
&
IFA_F_SECONDARY
)
&&
ifa
->
ifa_scope
<=
ifa1
->
ifa_scope
)
for
(
ifap
=
&
in_dev
->
ifa_list
;
(
ifa1
=
*
ifap
)
!=
NULL
;
ifap
=
&
ifa1
->
ifa_next
)
{
if
(
!
(
ifa1
->
ifa_flags
&
IFA_F_SECONDARY
)
&&
ifa
->
ifa_scope
<=
ifa1
->
ifa_scope
)
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
)
{
inet_free_ifa
(
ifa
);
return
-
EEXIST
;
...
...
@@ -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
);
ifap
=
last_primary
;
}
...
...
@@ -306,24 +326,23 @@ inet_insert_ifa(struct in_ifaddr *ifa)
return
0
;
}
static
int
inet_set_ifa
(
struct
net_device
*
dev
,
struct
in_ifaddr
*
ifa
)
static
int
inet_set_ifa
(
struct
net_device
*
dev
,
struct
in_ifaddr
*
ifa
)
{
struct
in_device
*
in_dev
=
__in_dev_get
(
dev
);
ASSERT_RTNL
();
if
(
in_dev
==
NULL
)
{
if
(
!
in_dev
)
{
in_dev
=
inetdev_init
(
dev
);
if
(
in_dev
==
NULL
)
{
if
(
!
in_dev
)
{
inet_free_ifa
(
ifa
);
return
-
ENOBUFS
;
}
}
if
(
ifa
->
ifa_dev
!=
in_dev
)
{
BUG_TRAP
(
ifa
->
ifa_dev
==
NULL
);
BUG_TRAP
(
!
ifa
->
ifa_dev
);
in_dev_hold
(
in_dev
);
ifa
->
ifa_dev
=
in_dev
;
ifa
->
ifa_dev
=
in_dev
;
}
if
(
LOOPBACK
(
ifa
->
ifa_local
))
ifa
->
ifa_scope
=
RT_SCOPE_HOST
;
...
...
@@ -344,7 +363,8 @@ struct in_device *inetdev_by_index(int ifindex)
/* 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
();
...
...
@@ -355,10 +375,9 @@ struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, u32 prefix, u32 ma
return
NULL
;
}
int
inet_rtm_deladdr
(
struct
sk_buff
*
skb
,
struct
nlmsghdr
*
nlh
,
void
*
arg
)
int
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
ifaddrmsg
*
ifm
=
NLMSG_DATA
(
nlh
);
struct
in_ifaddr
*
ifa
,
**
ifap
;
...
...
@@ -366,93 +385,103 @@ inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
ASSERT_RTNL
();
if
((
in_dev
=
inetdev_by_index
(
ifm
->
ifa_index
))
==
NULL
)
return
-
EADDRNOTAVAIL
;
goto
out
;
__in_dev_put
(
in_dev
);
for
(
ifap
=&
in_dev
->
ifa_list
;
(
ifa
=*
ifap
)
!=
NULL
;
ifap
=&
ifa
->
ifa_next
)
{
if
((
rta
[
IFA_LOCAL
-
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
]
&&
for
(
ifap
=
&
in_dev
->
ifa_list
;
(
ifa
=
*
ifap
)
!=
NULL
;
ifap
=
&
ifa
->
ifa_next
)
{
if
((
rta
[
IFA_LOCAL
-
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
||
!
inet_ifa_match
(
*
(
u32
*
)
RTA_DATA
(
rta
[
IFA_ADDRESS
-
1
]),
ifa
))))
!
inet_ifa_match
(
*
(
u32
*
)
RTA_DATA
(
rta
[
IFA_ADDRESS
-
1
]),
ifa
))))
continue
;
inet_del_ifa
(
in_dev
,
ifap
,
1
);
return
0
;
}
out:
return
-
EADDRNOTAVAIL
;
}
int
inet_rtm_newaddr
(
struct
sk_buff
*
skb
,
struct
nlmsghdr
*
nlh
,
void
*
arg
)
int
inet_rtm_newaddr
(
struct
sk_buff
*
skb
,
struct
nlmsghdr
*
nlh
,
void
*
arg
)
{
struct
rtattr
**
rta
=
arg
;
struct
net_device
*
dev
;
struct
in_device
*
in_dev
;
struct
ifaddrmsg
*
ifm
=
NLMSG_DATA
(
nlh
);
struct
in_ifaddr
*
ifa
;
int
rc
=
-
EINVAL
;
ASSERT_RTNL
();
if
(
ifm
->
ifa_prefixlen
>
32
||
rta
[
IFA_LOCAL
-
1
]
==
NULL
)
return
-
EINVAL
;
if
(
ifm
->
ifa_prefixlen
>
32
||
!
rta
[
IFA_LOCAL
-
1
]
)
goto
out
;
rc
=
-
ENODEV
;
if
((
dev
=
__dev_get_by_index
(
ifm
->
ifa_index
))
==
NULL
)
return
-
ENODEV
;
goto
out
;
rc
=
-
ENOBUFS
;
if
((
in_dev
=
__in_dev_get
(
dev
))
==
NULL
)
{
in_dev
=
inetdev_init
(
dev
);
if
(
!
in_dev
)
return
-
ENOBUFS
;
goto
out
;
}
if
((
ifa
=
inet_alloc_ifa
())
==
NULL
)
return
-
ENOBUFS
;
goto
out
;
if
(
rta
[
IFA_ADDRESS
-
1
]
==
NULL
)
rta
[
IFA_ADDRESS
-
1
]
=
rta
[
IFA_LOCAL
-
1
];
memcpy
(
&
ifa
->
ifa_local
,
RTA_DATA
(
rta
[
IFA_LOCAL
-
1
]),
4
);
memcpy
(
&
ifa
->
ifa_address
,
RTA_DATA
(
rta
[
IFA_ADDRESS
-
1
]),
4
);
if
(
!
rta
[
IFA_ADDRESS
-
1
]
)
rta
[
IFA_ADDRESS
-
1
]
=
rta
[
IFA_LOCAL
-
1
];
memcpy
(
&
ifa
->
ifa_local
,
RTA_DATA
(
rta
[
IFA_LOCAL
-
1
]),
4
);
memcpy
(
&
ifa
->
ifa_address
,
RTA_DATA
(
rta
[
IFA_ADDRESS
-
1
]),
4
);
ifa
->
ifa_prefixlen
=
ifm
->
ifa_prefixlen
;
ifa
->
ifa_mask
=
inet_make_mask
(
ifm
->
ifa_prefixlen
);
if
(
rta
[
IFA_BROADCAST
-
1
])
memcpy
(
&
ifa
->
ifa_broadcast
,
RTA_DATA
(
rta
[
IFA_BROADCAST
-
1
]),
4
);
if
(
rta
[
IFA_ANYCAST
-
1
])
memcpy
(
&
ifa
->
ifa_anycast
,
RTA_DATA
(
rta
[
IFA_ANYCAST
-
1
]),
4
);
if
(
rta
[
IFA_BROADCAST
-
1
])
memcpy
(
&
ifa
->
ifa_broadcast
,
RTA_DATA
(
rta
[
IFA_BROADCAST
-
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_scope
=
ifm
->
ifa_scope
;
in_dev_hold
(
in_dev
);
ifa
->
ifa_dev
=
in_dev
;
if
(
rta
[
IFA_LABEL
-
1
])
memcpy
(
ifa
->
ifa_label
,
RTA_DATA
(
rta
[
IFA_LABEL
-
1
]),
IFNAMSIZ
);
ifa
->
ifa_dev
=
in_dev
;
if
(
rta
[
IFA_LABEL
-
1
])
memcpy
(
ifa
->
ifa_label
,
RTA_DATA
(
rta
[
IFA_LABEL
-
1
]),
IFNAMSIZ
);
else
memcpy
(
ifa
->
ifa_label
,
dev
->
name
,
IFNAMSIZ
);
return
inet_insert_ifa
(
ifa
);
rc
=
inet_insert_ifa
(
ifa
);
out:
return
rc
;
}
/*
* Determine a default network mask, based on the IP address.
/*
* Determine a default network mask, based on the IP address.
*/
static
__inline__
int
inet_abc_len
(
u32
addr
)
{
if
(
ZERONET
(
addr
))
return
0
;
int
rc
=
-
1
;
/* Something else, probably a multicast. */
addr
=
ntohl
(
addr
);
if
(
IN_CLASSA
(
addr
))
return
8
;
if
(
IN_CLASSB
(
addr
))
return
16
;
if
(
IN_CLASSC
(
addr
))
return
24
;
if
(
ZERONET
(
addr
))
rc
=
0
;
else
{
addr
=
ntohl
(
addr
);
if
(
IN_CLASSA
(
addr
))
rc
=
8
;
else
if
(
IN_CLASSB
(
addr
))
rc
=
16
;
else
if
(
IN_CLASSC
(
addr
))
rc
=
24
;
}
/*
* Something else, probably a multicast.
*/
return
-
1
;
return
rc
;
}
...
...
@@ -466,7 +495,7 @@ int devinet_ioctl(unsigned int cmd, void *arg)
struct
in_ifaddr
*
ifa
=
NULL
;
struct
net_device
*
dev
;
char
*
colon
;
int
ret
=
0
;
int
ret
=
-
EFAULT
;
int
tryaddrmatch
=
0
;
/*
...
...
@@ -474,8 +503,8 @@ int devinet_ioctl(unsigned int cmd, void *arg)
*/
if
(
copy_from_user
(
&
ifr
,
arg
,
sizeof
(
struct
ifreq
)))
return
-
EFAULT
;
ifr
.
ifr_name
[
IFNAMSIZ
-
1
]
=
0
;
goto
out
;
ifr
.
ifr_name
[
IFNAMSIZ
-
1
]
=
0
;
/* save original address for comparison */
memcpy
(
&
sin_orig
,
sin
,
sizeof
(
*
sin
));
...
...
@@ -503,215 +532,222 @@ int devinet_ioctl(unsigned int cmd, void *arg)
break
;
case
SIOCSIFFLAGS
:
ret
=
-
EACCES
;
if
(
!
capable
(
CAP_NET_ADMIN
))
return
-
EACCES
;
goto
out
;
break
;
case
SIOCSIFADDR
:
/* Set interface address (and family) */
case
SIOCSIFBRDADDR
:
/* Set the broadcast address */
case
SIOCSIFDSTADDR
:
/* Set the destination address */
case
SIOCSIFNETMASK
:
/* Set the netmask for the interface */
ret
=
-
EACCES
;
if
(
!
capable
(
CAP_NET_ADMIN
))
return
-
EACCES
;
goto
out
;
ret
=
-
EINVAL
;
if
(
sin
->
sin_family
!=
AF_INET
)
return
-
EINVAL
;
goto
out
;
break
;
default:
return
-
EINVAL
;
ret
=
-
EINVAL
;
goto
out
;
}
dev_probe_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
;
}
if
(
colon
)
*
colon
=
':'
;
if
((
in_dev
=
__in_dev_get
(
dev
))
!=
NULL
)
{
if
((
in_dev
=
__in_dev_get
(
dev
))
!=
NULL
)
{
if
(
tryaddrmatch
)
{
/* Matthias Andree */
/* compare label and address (4.4BSD style) */
/* note: we only do this for a limited set of ioctls
and only if the original address family was AF_INET.
This is checked above. */
for
(
ifap
=&
in_dev
->
ifa_list
;
(
ifa
=*
ifap
)
!=
NULL
;
ifap
=&
ifa
->
ifa_next
)
{
if
((
strcmp
(
ifr
.
ifr_name
,
ifa
->
ifa_label
)
==
0
)
&&
(
sin_orig
.
sin_addr
.
s_addr
==
ifa
->
ifa_address
))
{
for
(
ifap
=
&
in_dev
->
ifa_list
;
(
ifa
=
*
ifap
)
!=
NULL
;
ifap
=
&
ifa
->
ifa_next
)
{
if
(
!
strcmp
(
ifr
.
ifr_name
,
ifa
->
ifa_label
)
&&
sin_orig
.
sin_addr
.
s_addr
==
ifa
->
ifa_address
)
{
break
;
/* found */
}
}
}
/* 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 */
if
(
ifa
==
NULL
)
{
for
(
ifap
=&
in_dev
->
ifa_list
;
(
ifa
=*
ifap
)
!=
NULL
;
ifap
=&
ifa
->
ifa_next
)
if
(
strcmp
(
ifr
.
ifr_name
,
ifa
->
ifa_label
)
==
0
)
if
(
!
ifa
)
{
for
(
ifap
=
&
in_dev
->
ifa_list
;
(
ifa
=
*
ifap
)
!=
NULL
;
ifap
=
&
ifa
->
ifa_next
)
if
(
!
strcmp
(
ifr
.
ifr_name
,
ifa
->
ifa_label
))
break
;
}
}
if
(
ifa
==
NULL
&&
cmd
!=
SIOCSIFADDR
&&
cmd
!=
SIOCSIFFLAGS
)
{
ret
=
-
EADDRNOTAVAIL
;
ret
=
-
EADDRNOTAVAIL
;
if
(
!
ifa
&&
cmd
!=
SIOCSIFADDR
&&
cmd
!=
SIOCSIFFLAGS
)
goto
done
;
}
switch
(
cmd
)
{
case
SIOCGIFADDR
:
/* Get interface address */
sin
->
sin_addr
.
s_addr
=
ifa
->
ifa_local
;
goto
rarok
;
case
SIOCGIFBRDADDR
:
/* Get the broadcast address */
sin
->
sin_addr
.
s_addr
=
ifa
->
ifa_broadcast
;
goto
rarok
;
case
SIOCGIFDSTADDR
:
/* Get the destination address */
sin
->
sin_addr
.
s_addr
=
ifa
->
ifa_address
;
goto
rarok
;
case
SIOCGIFNETMASK
:
/* Get the netmask for the interface */
sin
->
sin_addr
.
s_addr
=
ifa
->
ifa_mask
;
goto
rarok
;
case
SIOCSIFFLAGS
:
if
(
colon
)
{
if
(
ifa
==
NULL
)
{
ret
=
-
EADDRNOTAVAIL
;
break
;
}
if
(
!
(
ifr
.
ifr_flags
&
IFF_UP
))
inet_del_ifa
(
in_dev
,
ifap
,
1
);
case
SIOCGIFADDR
:
/* Get interface address */
sin
->
sin_addr
.
s_addr
=
ifa
->
ifa_local
;
goto
rarok
;
case
SIOCGIFBRDADDR
:
/* Get the broadcast address */
sin
->
sin_addr
.
s_addr
=
ifa
->
ifa_broadcast
;
goto
rarok
;
case
SIOCGIFDSTADDR
:
/* Get the destination address */
sin
->
sin_addr
.
s_addr
=
ifa
->
ifa_address
;
goto
rarok
;
case
SIOCGIFNETMASK
:
/* Get the netmask for the interface */
sin
->
sin_addr
.
s_addr
=
ifa
->
ifa_mask
;
goto
rarok
;
case
SIOCSIFFLAGS
:
if
(
colon
)
{
ret
=
-
EADDRNOTAVAIL
;
if
(
!
ifa
)
break
;
}
ret
=
dev_change_flags
(
dev
,
ifr
.
ifr_flags
);
ret
=
0
;
if
(
!
(
ifr
.
ifr_flags
&
IFF_UP
))
inet_del_ifa
(
in_dev
,
ifap
,
1
);
break
;
}
ret
=
dev_change_flags
(
dev
,
ifr
.
ifr_flags
);
break
;
case
SIOCSIFADDR
:
/* Set interface address (and family) */
ret
=
-
EINVAL
;
if
(
inet_abc_len
(
sin
->
sin_addr
.
s_addr
)
<
0
)
break
;
case
SIOCSIFADDR
:
/* Set interface address (and family) */
if
(
inet_abc_len
(
sin
->
sin_addr
.
s_addr
)
<
0
)
{
ret
=
-
EINVAL
;
if
(
!
ifa
)
{
ret
=
-
ENOBUFS
;
if
((
ifa
=
inet_alloc_ifa
())
==
NULL
)
break
;
}
if
(
colon
)
memcpy
(
ifa
->
ifa_label
,
ifr
.
ifr_name
,
IFNAMSIZ
);
else
memcpy
(
ifa
->
ifa_label
,
dev
->
name
,
IFNAMSIZ
);
}
else
{
ret
=
0
;
if
(
ifa
->
ifa_local
==
sin
->
sin_addr
.
s_addr
)
break
;
inet_del_ifa
(
in_dev
,
ifap
,
0
);
ifa
->
ifa_broadcast
=
0
;
ifa
->
ifa_anycast
=
0
;
}
if
(
!
ifa
)
{
if
((
ifa
=
inet_alloc_ifa
())
==
NULL
)
{
ret
=
-
ENOBUFS
;
break
;
}
if
(
colon
)
memcpy
(
ifa
->
ifa_label
,
ifr
.
ifr_name
,
IFNAMSIZ
);
else
memcpy
(
ifa
->
ifa_label
,
dev
->
name
,
IFNAMSIZ
);
}
else
{
ret
=
0
;
if
(
ifa
->
ifa_local
==
sin
->
sin_addr
.
s_addr
)
break
;
inet_del_ifa
(
in_dev
,
ifap
,
0
);
ifa
->
ifa_broadcast
=
0
;
ifa
->
ifa_anycast
=
0
;
}
ifa
->
ifa_address
=
ifa
->
ifa_local
=
sin
->
sin_addr
.
s_addr
;
if
(
!
(
dev
->
flags
&
IFF_POINTOPOINT
))
{
ifa
->
ifa_prefixlen
=
inet_abc_len
(
ifa
->
ifa_address
);
ifa
->
ifa_mask
=
inet_make_mask
(
ifa
->
ifa_prefixlen
);
if
((
dev
->
flags
&
IFF_BROADCAST
)
&&
ifa
->
ifa_prefixlen
<
31
)
ifa
->
ifa_broadcast
=
ifa
->
ifa_address
|
~
ifa
->
ifa_mask
;
}
else
{
ifa
->
ifa_prefixlen
=
32
;
ifa
->
ifa_mask
=
inet_make_mask
(
32
);
}
ret
=
inet_set_ifa
(
dev
,
ifa
);
break
;
ifa
->
ifa_address
=
ifa
->
ifa_local
=
sin
->
sin_addr
.
s_addr
;
if
(
!
(
dev
->
flags
&
IFF_POINTOPOINT
))
{
ifa
->
ifa_prefixlen
=
inet_abc_len
(
ifa
->
ifa_address
);
ifa
->
ifa_mask
=
inet_make_mask
(
ifa
->
ifa_prefixlen
);
if
((
dev
->
flags
&
IFF_BROADCAST
)
&&
ifa
->
ifa_prefixlen
<
31
)
ifa
->
ifa_broadcast
=
ifa
->
ifa_address
|~
ifa
->
ifa_mask
;
}
else
{
ifa
->
ifa_prefixlen
=
32
;
ifa
->
ifa_mask
=
inet_make_mask
(
32
);
}
ret
=
inet_set_ifa
(
dev
,
ifa
);
break
;
case
SIOCSIFBRDADDR
:
/* Set the broadcast address */
ret
=
0
;
if
(
ifa
->
ifa_broadcast
!=
sin
->
sin_addr
.
s_addr
)
{
inet_del_ifa
(
in_dev
,
ifap
,
0
);
ifa
->
ifa_broadcast
=
sin
->
sin_addr
.
s_addr
;
inet_insert_ifa
(
ifa
);
}
break
;
case
SIOCSIFBRDADDR
:
/* Set the broadcast address */
if
(
ifa
->
ifa_broadcast
!=
sin
->
sin_addr
.
s_addr
)
{
inet_del_ifa
(
in_dev
,
ifap
,
0
);
ifa
->
ifa_broadcast
=
sin
->
sin_addr
.
s_addr
;
inet_insert_ifa
(
ifa
);
}
case
SIOCSIFDSTADDR
:
/* Set the destination address */
ret
=
0
;
if
(
ifa
->
ifa_address
==
sin
->
sin_addr
.
s_addr
)
break
;
case
SIOCSIFDSTADDR
:
/* Set the destination address */
if
(
ifa
->
ifa_address
!=
sin
->
sin_addr
.
s_addr
)
{
if
(
inet_abc_len
(
sin
->
sin_addr
.
s_addr
)
<
0
)
{
ret
=
-
EINVAL
;
break
;
}
inet_del_ifa
(
in_dev
,
ifap
,
0
);
ifa
->
ifa_address
=
sin
->
sin_addr
.
s_addr
;
inet_insert_ifa
(
ifa
);
}
ret
=
-
EINVAL
;
if
(
inet_abc_len
(
sin
->
sin_addr
.
s_addr
)
<
0
)
break
;
ret
=
0
;
inet_del_ifa
(
in_dev
,
ifap
,
0
);
ifa
->
ifa_address
=
sin
->
sin_addr
.
s_addr
;
inet_insert_ifa
(
ifa
);
break
;
case
SIOCSIFNETMASK
:
/* Set the netmask for the interface */
/*
* The mask we set must be legal.
*/
if
(
bad_mask
(
sin
->
sin_addr
.
s_addr
,
0
))
{
ret
=
-
EINVAL
;
break
;
}
case
SIOCSIFNETMASK
:
/* Set the netmask for the interface */
if
(
ifa
->
ifa_mask
!=
sin
->
sin_addr
.
s_addr
)
{
inet_del_ifa
(
in_dev
,
ifap
,
0
);
ifa
->
ifa_mask
=
sin
->
sin_addr
.
s_addr
;
ifa
->
ifa_prefixlen
=
inet_mask_len
(
ifa
->
ifa_mask
);
inet_insert_ifa
(
ifa
);
}
/*
* The mask we set must be legal.
*/
ret
=
-
EINVAL
;
if
(
bad_mask
(
sin
->
sin_addr
.
s_addr
,
0
))
break
;
ret
=
0
;
if
(
ifa
->
ifa_mask
!=
sin
->
sin_addr
.
s_addr
)
{
inet_del_ifa
(
in_dev
,
ifap
,
0
);
ifa
->
ifa_mask
=
sin
->
sin_addr
.
s_addr
;
ifa
->
ifa_prefixlen
=
inet_mask_len
(
ifa
->
ifa_mask
);
inet_insert_ifa
(
ifa
);
}
break
;
}
done:
rtnl_unlock
();
dev_probe_unlock
();
out:
return
ret
;
rarok:
rtnl_unlock
();
dev_probe_unlock
();
if
(
copy_to_user
(
arg
,
&
ifr
,
sizeof
(
struct
ifreq
)))
return
-
EFAULT
;
return
0
;
ret
=
copy_to_user
(
arg
,
&
ifr
,
sizeof
(
struct
ifreq
))
?
-
EFAULT
:
0
;
goto
out
;
}
static
int
inet_gifconf
(
struct
net_device
*
dev
,
char
*
buf
,
int
len
)
static
int
inet_gifconf
(
struct
net_device
*
dev
,
char
*
buf
,
int
len
)
{
struct
in_device
*
in_dev
=
__in_dev_get
(
dev
);
struct
in_ifaddr
*
ifa
;
struct
ifreq
ifr
;
int
done
=
0
;
int
done
=
0
;
if
(
in_dev
==
NULL
||
(
ifa
=
in_dev
->
ifa_list
)
==
NULL
)
return
0
;
if
(
!
in_dev
||
(
ifa
=
in_dev
->
ifa_list
)
==
NULL
)
goto
out
;
for
(
;
ifa
;
ifa
=
ifa
->
ifa_next
)
{
for
(;
ifa
;
ifa
=
ifa
->
ifa_next
)
{
if
(
!
buf
)
{
done
+=
sizeof
(
ifr
);
continue
;
}
if
(
len
<
(
int
)
sizeof
(
ifr
))
return
done
;
break
;
memset
(
&
ifr
,
0
,
sizeof
(
struct
ifreq
));
if
(
ifa
->
ifa_label
)
strcpy
(
ifr
.
ifr_name
,
ifa
->
ifa_label
);
else
strcpy
(
ifr
.
ifr_name
,
dev
->
name
);
(
*
(
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_family
=
AF_INET
;
(
*
(
struct
sockaddr_in
*
)
&
ifr
.
ifr_addr
).
sin_addr
.
s_addr
=
ifa
->
ifa_local
;
if
(
copy_to_user
(
buf
,
&
ifr
,
sizeof
(
struct
ifreq
)))
return
-
EFAULT
;
buf
+=
sizeof
(
struct
ifreq
);
len
-=
sizeof
(
struct
ifreq
);
if
(
copy_to_user
(
buf
,
&
ifr
,
sizeof
(
struct
ifreq
)))
{
done
=
-
EFAULT
;
break
;
}
buf
+=
sizeof
(
struct
ifreq
);
len
-=
sizeof
(
struct
ifreq
);
done
+=
sizeof
(
struct
ifreq
);
}
out:
return
done
;
}
...
...
@@ -722,10 +758,8 @@ u32 inet_select_addr(const struct net_device *dev, u32 dst, int scope)
read_lock
(
&
inetdev_lock
);
in_dev
=
__in_dev_get
(
dev
);
if
(
in_dev
==
NULL
)
{
read_unlock
(
&
inetdev_lock
);
return
0
;
}
if
(
!
in_dev
)
goto
out_unlock_inetdev
;
read_lock
(
&
in_dev
->
lock
);
for_primary_ifa
(
in_dev
)
{
...
...
@@ -742,7 +776,7 @@ u32 inet_select_addr(const struct net_device *dev, u32 dst, int scope)
read_unlock
(
&
inetdev_lock
);
if
(
addr
)
return
addr
;
goto
out
;
/* Not loopback addresses on loopback should be preferred
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)
*/
read_lock
(
&
dev_base_lock
);
read_lock
(
&
inetdev_lock
);
for
(
dev
=
dev_base
;
dev
;
dev
=
dev
->
next
)
{
if
((
in_dev
=
__in_dev_get
(
dev
))
==
NULL
)
for
(
dev
=
dev_base
;
dev
;
dev
=
dev
->
next
)
{
if
((
in_dev
=
__in_dev_get
(
dev
))
==
NULL
)
continue
;
read_lock
(
&
in_dev
->
lock
);
...
...
@@ -759,17 +793,20 @@ u32 inet_select_addr(const struct net_device *dev, u32 dst, int scope)
if
(
ifa
->
ifa_scope
!=
RT_SCOPE_LINK
&&
ifa
->
ifa_scope
<=
scope
)
{
read_unlock
(
&
in_dev
->
lock
);
read_unlock
(
&
inetdev_lock
);
read_unlock
(
&
dev_base_lock
);
return
ifa
->
ifa_local
;
addr
=
ifa
->
ifa_local
;
goto
out_unlock_both
;
}
}
endfor_ifa
(
in_dev
);
read_unlock
(
&
in_dev
->
lock
);
}
out_unlock_both:
read_unlock
(
&
inetdev_lock
);
read_unlock
(
&
dev_base_lock
);
return
0
;
out:
return
addr
;
out_unlock_inetdev:
read_unlock
(
&
inetdev_lock
);
goto
out
;
}
/*
...
...
@@ -783,20 +820,21 @@ int register_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 */
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
in_device
*
in_dev
=
__in_dev_get
(
dev
);
ASSERT_RTNL
();
if
(
in_dev
==
NULL
)
return
NOTIFY_DONE
;
if
(
!
in_dev
)
goto
out
;
switch
(
event
)
{
case
NETDEV_REGISTER
:
...
...
@@ -810,7 +848,7 @@ static int inetdev_event(struct notifier_block *this, unsigned long event, void
struct
in_ifaddr
*
ifa
;
if
((
ifa
=
inet_alloc_ifa
())
!=
NULL
)
{
ifa
->
ifa_local
=
ifa
->
ifa_address
=
htonl
(
INADDR_LOOPBACK
);
ifa
->
ifa_address
=
htonl
(
INADDR_LOOPBACK
);
ifa
->
ifa_prefixlen
=
8
;
ifa
->
ifa_mask
=
inet_make_mask
(
8
);
in_dev_hold
(
in_dev
);
...
...
@@ -843,7 +881,7 @@ static int inetdev_event(struct notifier_block *this, unsigned long event, void
}
break
;
}
out:
return
NOTIFY_DONE
;
}
...
...
@@ -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
)
{
int
idx
,
ip_idx
;
int
s_idx
,
s_ip_idx
;
struct
net_device
*
dev
;
struct
in_device
*
in_dev
;
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
];
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
)
continue
;
if
(
idx
>
s_idx
)
...
...
@@ -911,7 +948,8 @@ static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
if
(
ip_idx
<
s_ip_idx
)
continue
;
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
(
&
inetdev_lock
);
goto
done
;
...
...
@@ -929,65 +967,39 @@ static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
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
);
return
;
}
if
(
inet_fill_ifaddr
(
skb
,
ifa
,
0
,
0
,
event
)
<
0
)
{
else
if
(
inet_fill_ifaddr
(
skb
,
ifa
,
0
,
0
,
event
)
<
0
)
{
kfree_skb
(
skb
);
netlink_set_err
(
rtnl
,
0
,
RTMGRP_IPV4_IFADDR
,
EINVAL
);
return
;
}
else
{
NETLINK_CB
(
skb
).
dst_groups
=
RTMGRP_IPV4_IFADDR
;
netlink_broadcast
(
rtnl
,
skb
,
0
,
RTMGRP_IPV4_IFADDR
,
GFP_KERNEL
);
}
NETLINK_CB
(
skb
).
dst_groups
=
RTMGRP_IPV4_IFADDR
;
netlink_broadcast
(
rtnl
,
skb
,
0
,
RTMGRP_IPV4_IFADDR
,
GFP_KERNEL
);
}
static
struct
rtnetlink_link
inet_rtnetlink_table
[
RTM_MAX
-
RTM_BASE
+
1
]
=
{
{
NULL
,
NULL
,
},
{
NULL
,
NULL
,
},
{
NULL
,
NULL
,
},
{
NULL
,
NULL
,
},
{
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
,
},
static
struct
rtnetlink_link
inet_rtnetlink_table
[
RTM_MAX
-
RTM_BASE
+
1
]
=
{
[
4
]
=
{
doit
:
inet_rtm_newaddr
,
},
[
5
]
=
{
doit
:
inet_rtm_deladdr
,
},
[
6
]
=
{
dumpit
:
inet_dump_ifaddr
,
},
[
8
]
=
{
doit
:
inet_rtm_newroute
,
},
[
9
]
=
{
doit
:
inet_rtm_delroute
,
},
[
10
]
=
{
doit
:
inet_rtm_getroute
,
dumpit
:
inet_dump_fib
,
},
#ifdef CONFIG_IP_MULTIPLE_TABLES
{
inet_rtm_newrule
,
NULL
,
},
{
inet_rtm_delrule
,
NULL
,
},
{
NULL
,
inet_dump_rules
,
},
{
NULL
,
NULL
,
},
#else
{
NULL
,
NULL
,
},
{
NULL
,
NULL
,
},
{
NULL
,
NULL
,
},
{
NULL
,
NULL
,
},
[
16
]
=
{
doit
:
inet_rtm_newrule
,
},
[
17
]
=
{
doit
:
inet_rtm_delrule
,
},
[
18
]
=
{
dumpit
:
inet_dump_rules
,
},
#endif
};
#ifdef CONFIG_SYSCTL
void
inet_forward_change
()
void
inet_forward_change
(
void
)
{
struct
net_device
*
dev
;
int
on
=
ipv4_devconf
.
forwarding
;
...
...
@@ -1009,15 +1021,13 @@ void inet_forward_change()
rt_cache_flush
(
0
);
}
static
int
devinet_sysctl_forward
(
ctl_table
*
ctl
,
int
write
,
struct
file
*
filp
,
void
*
buffer
,
size_t
*
lenp
)
static
int
devinet_sysctl_forward
(
ctl_table
*
ctl
,
int
write
,
struct
file
*
filp
,
void
*
buffer
,
size_t
*
lenp
)
{
int
*
valp
=
ctl
->
data
;
int
val
=
*
valp
;
int
ret
;
ret
=
proc_dointvec
(
ctl
,
write
,
filp
,
buffer
,
lenp
);
int
ret
=
proc_dointvec
(
ctl
,
write
,
filp
,
buffer
,
lenp
);
if
(
write
&&
*
valp
!=
val
)
{
if
(
valp
==
&
ipv4_devconf
.
forwarding
)
...
...
@@ -1026,81 +1036,179 @@ int devinet_sysctl_forward(ctl_table *ctl, int write, struct file * filp,
rt_cache_flush
(
0
);
}
return
ret
;
return
ret
;
}
static
struct
devinet_sysctl_table
{
static
struct
devinet_sysctl_table
{
struct
ctl_table_header
*
sysctl_header
;
ctl_table
devinet_vars
[
15
];
ctl_table
devinet_dev
[
2
];
ctl_table
devinet_conf_dir
[
2
];
ctl_table
devinet_proto_dir
[
2
];
ctl_table
devinet_root_dir
[
2
];
ctl_table
devinet_vars
[
15
];
ctl_table
devinet_dev
[
2
];
ctl_table
devinet_conf_dir
[
2
];
ctl_table
devinet_proto_dir
[
2
];
ctl_table
devinet_root_dir
[
2
];
}
devinet_sysctl
=
{
NULL
,
{{
NET_IPV4_CONF_FORWARDING
,
"forwarding"
,
&
ipv4_devconf
.
forwarding
,
sizeof
(
int
),
0644
,
NULL
,
&
devinet_sysctl_forward
},
{
NET_IPV4_CONF_MC_FORWARDING
,
"mc_forwarding"
,
&
ipv4_devconf
.
mc_forwarding
,
sizeof
(
int
),
0444
,
NULL
,
&
proc_dointvec
},
{
NET_IPV4_CONF_ACCEPT_REDIRECTS
,
"accept_redirects"
,
&
ipv4_devconf
.
accept_redirects
,
sizeof
(
int
),
0644
,
NULL
,
&
proc_dointvec
},
{
NET_IPV4_CONF_SECURE_REDIRECTS
,
"secure_redirects"
,
&
ipv4_devconf
.
secure_redirects
,
sizeof
(
int
),
0644
,
NULL
,
&
proc_dointvec
},
{
NET_IPV4_CONF_SHARED_MEDIA
,
"shared_media"
,
&
ipv4_devconf
.
shared_media
,
sizeof
(
int
),
0644
,
NULL
,
&
proc_dointvec
},
{
NET_IPV4_CONF_RP_FILTER
,
"rp_filter"
,
&
ipv4_devconf
.
rp_filter
,
sizeof
(
int
),
0644
,
NULL
,
&
proc_dointvec
},
{
NET_IPV4_CONF_SEND_REDIRECTS
,
"send_redirects"
,
&
ipv4_devconf
.
send_redirects
,
sizeof
(
int
),
0644
,
NULL
,
&
proc_dointvec
},
{
NET_IPV4_CONF_ACCEPT_SOURCE_ROUTE
,
"accept_source_route"
,
&
ipv4_devconf
.
accept_source_route
,
sizeof
(
int
),
0644
,
NULL
,
&
proc_dointvec
},
{
NET_IPV4_CONF_PROXY_ARP
,
"proxy_arp"
,
&
ipv4_devconf
.
proxy_arp
,
sizeof
(
int
),
0644
,
NULL
,
&
proc_dointvec
},
{
NET_IPV4_CONF_MEDIUM_ID
,
"medium_id"
,
&
ipv4_devconf
.
medium_id
,
sizeof
(
int
),
0644
,
NULL
,
&
proc_dointvec
},
{
NET_IPV4_CONF_BOOTP_RELAY
,
"bootp_relay"
,
&
ipv4_devconf
.
bootp_relay
,
sizeof
(
int
),
0644
,
NULL
,
&
proc_dointvec
},
{
NET_IPV4_CONF_LOG_MARTIANS
,
"log_martians"
,
&
ipv4_devconf
.
log_martians
,
sizeof
(
int
),
0644
,
NULL
,
&
proc_dointvec
},
{
NET_IPV4_CONF_TAG
,
"tag"
,
&
ipv4_devconf
.
tag
,
sizeof
(
int
),
0644
,
NULL
,
&
proc_dointvec
},
{
NET_IPV4_CONF_ARPFILTER
,
"arp_filter"
,
&
ipv4_devconf
.
arp_filter
,
sizeof
(
int
),
0644
,
NULL
,
&
proc_dointvec
},
{
0
}},
{{
NET_PROTO_CONF_ALL
,
"all"
,
NULL
,
0
,
0555
,
devinet_sysctl
.
devinet_vars
},{
0
}},
{{
NET_IPV4_CONF
,
"conf"
,
NULL
,
0
,
0555
,
devinet_sysctl
.
devinet_dev
},{
0
}},
{{
NET_IPV4
,
"ipv4"
,
NULL
,
0
,
0555
,
devinet_sysctl
.
devinet_conf_dir
},{
0
}},
{{
CTL_NET
,
"net"
,
NULL
,
0
,
0555
,
devinet_sysctl
.
devinet_proto_dir
},{
0
}}
devinet_vars:
{
{
ctl_name:
NET_IPV4_CONF_FORWARDING
,
procname:
"forwarding"
,
data:
&
ipv4_devconf
.
forwarding
,
maxlen:
sizeof
(
int
),
mode:
0644
,
proc_handler:
&
devinet_sysctl_forward
,
},
{
ctl_name:
NET_IPV4_CONF_MC_FORWARDING
,
procname:
"mc_forwarding"
,
data:
&
ipv4_devconf
.
mc_forwarding
,
maxlen:
sizeof
(
int
),
mode:
0444
,
proc_handler:
&
proc_dointvec
,
},
{
ctl_name:
NET_IPV4_CONF_ACCEPT_REDIRECTS
,
procname:
"accept_redirects"
,
data:
&
ipv4_devconf
.
accept_redirects
,
maxlen:
sizeof
(
int
),
mode:
0644
,
proc_handler:
&
proc_dointvec
,
},
{
ctl_name:
NET_IPV4_CONF_SECURE_REDIRECTS
,
procname:
"secure_redirects"
,
data:
&
ipv4_devconf
.
secure_redirects
,
maxlen:
sizeof
(
int
),
mode:
0644
,
proc_handler:
&
proc_dointvec
,
},
{
ctl_name:
NET_IPV4_CONF_SHARED_MEDIA
,
procname:
"shared_media"
,
data:
&
ipv4_devconf
.
shared_media
,
maxlen:
sizeof
(
int
),
mode:
0644
,
proc_handler:
&
proc_dointvec
,
},
{
ctl_name:
NET_IPV4_CONF_RP_FILTER
,
procname:
"rp_filter"
,
data:
&
ipv4_devconf
.
rp_filter
,
maxlen:
sizeof
(
int
),
mode:
0644
,
proc_handler:
&
proc_dointvec
,
},
{
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
;
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
==
NULL
)
if
(
!
t
)
return
;
memcpy
(
t
,
&
devinet_sysctl
,
sizeof
(
*
t
));
for
(
i
=
0
;
i
<
sizeof
(
t
->
devinet_vars
)
/
sizeof
(
t
->
devinet_vars
[
0
])
-
1
;
i
++
)
{
t
->
devinet_vars
[
i
].
data
+=
(
char
*
)
p
-
(
char
*
)
&
ipv4_devconf
;
for
(
i
=
0
;
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
;
}
if
(
dev
)
{
...
...
@@ -1110,17 +1218,17 @@ static void devinet_sysctl_register(struct in_device *in_dev, struct ipv4_devcon
t
->
devinet_dev
[
0
].
procname
=
"default"
;
t
->
devinet_dev
[
0
].
ctl_name
=
NET_PROTO_CONF_DEFAULT
;
}
t
->
devinet_dev
[
0
].
child
=
t
->
devinet_vars
;
t
->
devinet_dev
[
0
].
de
=
NULL
;
t
->
devinet_conf_dir
[
0
].
child
=
t
->
devinet_dev
;
t
->
devinet_conf_dir
[
0
].
de
=
NULL
;
t
->
devinet_dev
[
0
].
child
=
t
->
devinet_vars
;
t
->
devinet_dev
[
0
].
de
=
NULL
;
t
->
devinet_conf_dir
[
0
].
child
=
t
->
devinet_dev
;
t
->
devinet_conf_dir
[
0
].
de
=
NULL
;
t
->
devinet_proto_dir
[
0
].
child
=
t
->
devinet_conf_dir
;
t
->
devinet_proto_dir
[
0
].
de
=
NULL
;
t
->
devinet_root_dir
[
0
].
child
=
t
->
devinet_proto_dir
;
t
->
devinet_root_dir
[
0
].
de
=
NULL
;
t
->
devinet_proto_dir
[
0
].
de
=
NULL
;
t
->
devinet_root_dir
[
0
].
child
=
t
->
devinet_proto_dir
;
t
->
devinet_root_dir
[
0
].
de
=
NULL
;
t
->
sysctl_header
=
register_sysctl_table
(
t
->
devinet_root_dir
,
0
);
if
(
t
->
sysctl_header
==
NULL
)
if
(
!
t
->
sysctl_header
)
kfree
(
t
);
else
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