Commit eb2e01d8 authored by David S. Miller's avatar David S. Miller

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
...@@ -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;
err = copy_to_user((void *)arg,&sk->stamp,sizeof(struct timeval)); else 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);
/* /*
......
...@@ -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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment