2005-04-16 22:20:36 +00:00
|
|
|
/*
|
|
|
|
* IPv6 BSD socket options interface
|
2007-02-09 14:24:49 +00:00
|
|
|
* Linux INET6 implementation
|
2005-04-16 22:20:36 +00:00
|
|
|
*
|
|
|
|
* Authors:
|
2007-02-09 14:24:49 +00:00
|
|
|
* Pedro Roque <roque@di.fc.ul.pt>
|
2005-04-16 22:20:36 +00:00
|
|
|
*
|
|
|
|
* Based on linux/net/ipv4/ip_sockglue.c
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version
|
|
|
|
* 2 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* FIXME: Make the setsockopt code POSIX compliant: That is
|
|
|
|
*
|
|
|
|
* o Truncate getsockopt returns
|
|
|
|
* o Return an optlen of the truncated length if need be
|
|
|
|
*
|
|
|
|
* Changes:
|
|
|
|
* David L Stevens <dlstevens@us.ibm.com>:
|
|
|
|
* - added multicast source filtering API for MLDv2
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <linux/module.h>
|
2006-01-11 20:17:47 +00:00
|
|
|
#include <linux/capability.h>
|
2005-04-16 22:20:36 +00:00
|
|
|
#include <linux/errno.h>
|
|
|
|
#include <linux/types.h>
|
|
|
|
#include <linux/socket.h>
|
|
|
|
#include <linux/sockios.h>
|
|
|
|
#include <linux/net.h>
|
|
|
|
#include <linux/in6.h>
|
2008-04-03 00:22:53 +00:00
|
|
|
#include <linux/mroute6.h>
|
2005-04-16 22:20:36 +00:00
|
|
|
#include <linux/netdevice.h>
|
|
|
|
#include <linux/if_arp.h>
|
|
|
|
#include <linux/init.h>
|
|
|
|
#include <linux/sysctl.h>
|
|
|
|
#include <linux/netfilter.h>
|
include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit slab.h inclusion from percpu.h
percpu.h is included by sched.h and module.h and thus ends up being
included when building most .c files. percpu.h includes slab.h which
in turn includes gfp.h making everything defined by the two files
universally available and complicating inclusion dependencies.
percpu.h -> slab.h dependency is about to be removed. Prepare for
this change by updating users of gfp and slab facilities include those
headers directly instead of assuming availability. As this conversion
needs to touch large number of source files, the following script is
used as the basis of conversion.
http://userweb.kernel.org/~tj/misc/slabh-sweep.py
The script does the followings.
* Scan files for gfp and slab usages and update includes such that
only the necessary includes are there. ie. if only gfp is used,
gfp.h, if slab is used, slab.h.
* When the script inserts a new include, it looks at the include
blocks and try to put the new include such that its order conforms
to its surrounding. It's put in the include block which contains
core kernel includes, in the same order that the rest are ordered -
alphabetical, Christmas tree, rev-Xmas-tree or at the end if there
doesn't seem to be any matching order.
* If the script can't find a place to put a new include (mostly
because the file doesn't have fitting include block), it prints out
an error message indicating which .h file needs to be added to the
file.
The conversion was done in the following steps.
1. The initial automatic conversion of all .c files updated slightly
over 4000 files, deleting around 700 includes and adding ~480 gfp.h
and ~3000 slab.h inclusions. The script emitted errors for ~400
files.
2. Each error was manually checked. Some didn't need the inclusion,
some needed manual addition while adding it to implementation .h or
embedding .c file was more appropriate for others. This step added
inclusions to around 150 files.
3. The script was run again and the output was compared to the edits
from #2 to make sure no file was left behind.
4. Several build tests were done and a couple of problems were fixed.
e.g. lib/decompress_*.c used malloc/free() wrappers around slab
APIs requiring slab.h to be added manually.
5. The script was run on all .h files but without automatically
editing them as sprinkling gfp.h and slab.h inclusions around .h
files could easily lead to inclusion dependency hell. Most gfp.h
inclusion directives were ignored as stuff from gfp.h was usually
wildly available and often used in preprocessor macros. Each
slab.h inclusion directive was examined and added manually as
necessary.
6. percpu.h was updated not to include slab.h.
7. Build test were done on the following configurations and failures
were fixed. CONFIG_GCOV_KERNEL was turned off for all tests (as my
distributed build env didn't work with gcov compiles) and a few
more options had to be turned off depending on archs to make things
build (like ipr on powerpc/64 which failed due to missing writeq).
* x86 and x86_64 UP and SMP allmodconfig and a custom test config.
* powerpc and powerpc64 SMP allmodconfig
* sparc and sparc64 SMP allmodconfig
* ia64 SMP allmodconfig
* s390 SMP allmodconfig
* alpha SMP allmodconfig
* um on x86_64 SMP allmodconfig
8. percpu.h modifications were reverted so that it could be applied as
a separate patch and serve as bisection point.
Given the fact that I had only a couple of failures from tests on step
6, I'm fairly confident about the coverage of this conversion patch.
If there is a breakage, it's likely to be something in one of the arch
headers which should be easily discoverable easily on most builds of
the specific arch.
Signed-off-by: Tejun Heo <tj@kernel.org>
Guess-its-ok-by: Christoph Lameter <cl@linux-foundation.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Lee Schermerhorn <Lee.Schermerhorn@hp.com>
2010-03-24 08:04:11 +00:00
|
|
|
#include <linux/slab.h>
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
#include <net/sock.h>
|
|
|
|
#include <net/snmp.h>
|
|
|
|
#include <net/ipv6.h>
|
|
|
|
#include <net/ndisc.h>
|
|
|
|
#include <net/protocol.h>
|
|
|
|
#include <net/transp_v6.h>
|
|
|
|
#include <net/ip6_route.h>
|
|
|
|
#include <net/addrconf.h>
|
|
|
|
#include <net/inet_common.h>
|
|
|
|
#include <net/tcp.h>
|
|
|
|
#include <net/udp.h>
|
2006-11-27 19:10:57 +00:00
|
|
|
#include <net/udplite.h>
|
2005-04-16 22:20:36 +00:00
|
|
|
#include <net/xfrm.h>
|
2008-04-27 08:06:07 +00:00
|
|
|
#include <net/compat.h>
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
#include <asm/uaccess.h>
|
|
|
|
|
2005-08-26 19:05:31 +00:00
|
|
|
DEFINE_SNMP_STAT(struct ipstats_mib, ipv6_statistics) __read_mostly;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
struct ip6_ra_chain *ip6_ra_chain;
|
|
|
|
DEFINE_RWLOCK(ip6_ra_lock);
|
|
|
|
|
2008-07-19 07:28:58 +00:00
|
|
|
int ip6_ra_control(struct sock *sk, int sel)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
struct ip6_ra_chain *ra, *new_ra, **rap;
|
|
|
|
|
|
|
|
/* RA packet may be delivered ONLY to IPPROTO_RAW socket */
|
2009-10-15 06:30:45 +00:00
|
|
|
if (sk->sk_type != SOCK_RAW || inet_sk(sk)->inet_num != IPPROTO_RAW)
|
2008-06-11 18:27:26 +00:00
|
|
|
return -ENOPROTOOPT;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
new_ra = (sel>=0) ? kmalloc(sizeof(*new_ra), GFP_KERNEL) : NULL;
|
|
|
|
|
|
|
|
write_lock_bh(&ip6_ra_lock);
|
|
|
|
for (rap = &ip6_ra_chain; (ra=*rap) != NULL; rap = &ra->next) {
|
|
|
|
if (ra->sk == sk) {
|
|
|
|
if (sel>=0) {
|
|
|
|
write_unlock_bh(&ip6_ra_lock);
|
2005-11-08 17:41:34 +00:00
|
|
|
kfree(new_ra);
|
2005-04-16 22:20:36 +00:00
|
|
|
return -EADDRINUSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
*rap = ra->next;
|
|
|
|
write_unlock_bh(&ip6_ra_lock);
|
|
|
|
|
|
|
|
sock_put(sk);
|
|
|
|
kfree(ra);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (new_ra == NULL) {
|
|
|
|
write_unlock_bh(&ip6_ra_lock);
|
|
|
|
return -ENOBUFS;
|
|
|
|
}
|
|
|
|
new_ra->sk = sk;
|
|
|
|
new_ra->sel = sel;
|
|
|
|
new_ra->next = ra;
|
|
|
|
*rap = new_ra;
|
|
|
|
sock_hold(sk);
|
|
|
|
write_unlock_bh(&ip6_ra_lock);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-04-14 06:21:52 +00:00
|
|
|
static
|
|
|
|
struct ipv6_txoptions *ipv6_update_options(struct sock *sk,
|
|
|
|
struct ipv6_txoptions *opt)
|
|
|
|
{
|
|
|
|
if (inet_sk(sk)->is_icsk) {
|
|
|
|
if (opt &&
|
|
|
|
!((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_CLOSE)) &&
|
2009-10-15 06:30:45 +00:00
|
|
|
inet_sk(sk)->inet_daddr != LOOPBACK4_IPV6) {
|
2008-04-14 06:21:52 +00:00
|
|
|
struct inet_connection_sock *icsk = inet_csk(sk);
|
|
|
|
icsk->icsk_ext_hdr_len = opt->opt_flen + opt->opt_nflen;
|
|
|
|
icsk->icsk_sync_mss(sk, icsk->icsk_pmtu_cookie);
|
|
|
|
}
|
|
|
|
opt = xchg(&inet6_sk(sk)->opt, opt);
|
|
|
|
} else {
|
|
|
|
write_lock(&sk->sk_dst_lock);
|
|
|
|
opt = xchg(&inet6_sk(sk)->opt, opt);
|
|
|
|
write_unlock(&sk->sk_dst_lock);
|
|
|
|
}
|
|
|
|
sk_dst_reset(sk);
|
|
|
|
|
|
|
|
return opt;
|
|
|
|
}
|
|
|
|
|
2006-03-21 06:45:21 +00:00
|
|
|
static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
|
2009-09-30 23:12:20 +00:00
|
|
|
char __user *optval, unsigned int optlen)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
struct ipv6_pinfo *np = inet6_sk(sk);
|
2008-03-25 17:26:21 +00:00
|
|
|
struct net *net = sock_net(sk);
|
2005-04-16 22:20:36 +00:00
|
|
|
int val, valbool;
|
|
|
|
int retv = -ENOPROTOOPT;
|
|
|
|
|
|
|
|
if (optval == NULL)
|
|
|
|
val=0;
|
2008-04-12 03:59:42 +00:00
|
|
|
else {
|
|
|
|
if (optlen >= sizeof(int)) {
|
|
|
|
if (get_user(val, (int __user *) optval))
|
|
|
|
return -EFAULT;
|
|
|
|
} else
|
|
|
|
val = 0;
|
|
|
|
}
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
valbool = (val!=0);
|
|
|
|
|
2008-04-03 00:22:53 +00:00
|
|
|
if (ip6_mroute_opt(optname))
|
|
|
|
return ip6_mroute_setsockopt(sk, optname, optval, optlen);
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
lock_sock(sk);
|
|
|
|
|
|
|
|
switch (optname) {
|
|
|
|
|
|
|
|
case IPV6_ADDRFORM:
|
2008-04-12 03:59:42 +00:00
|
|
|
if (optlen < sizeof(int))
|
|
|
|
goto e_inval;
|
2005-04-16 22:20:36 +00:00
|
|
|
if (val == PF_INET) {
|
|
|
|
struct ipv6_txoptions *opt;
|
|
|
|
struct sk_buff *pktopt;
|
|
|
|
|
2008-06-04 11:49:06 +00:00
|
|
|
if (sk->sk_type == SOCK_RAW)
|
|
|
|
break;
|
|
|
|
|
2008-06-04 11:49:08 +00:00
|
|
|
if (sk->sk_protocol == IPPROTO_UDP ||
|
|
|
|
sk->sk_protocol == IPPROTO_UDPLITE) {
|
|
|
|
struct udp_sock *up = udp_sk(sk);
|
|
|
|
if (up->pending == AF_INET6) {
|
|
|
|
retv = -EBUSY;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else if (sk->sk_protocol != IPPROTO_TCP)
|
2005-04-16 22:20:36 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
if (sk->sk_state != TCP_ESTABLISHED) {
|
|
|
|
retv = -ENOTCONN;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ipv6_only_sock(sk) ||
|
2007-08-25 06:16:08 +00:00
|
|
|
!ipv6_addr_v4mapped(&np->daddr)) {
|
2005-04-16 22:20:36 +00:00
|
|
|
retv = -EADDRNOTAVAIL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
fl6_free_socklist(sk);
|
|
|
|
ipv6_sock_mc_close(sk);
|
|
|
|
|
2005-08-10 02:45:38 +00:00
|
|
|
/*
|
|
|
|
* Sock is moving from IPv6 to IPv4 (sk_prot), so
|
|
|
|
* remove it from the refcnt debug socks count in the
|
|
|
|
* original family...
|
|
|
|
*/
|
|
|
|
sk_refcnt_debug_dec(sk);
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
if (sk->sk_protocol == IPPROTO_TCP) {
|
2005-12-14 07:26:10 +00:00
|
|
|
struct inet_connection_sock *icsk = inet_csk(sk);
|
2005-04-16 22:20:36 +00:00
|
|
|
local_bh_disable();
|
2008-04-01 02:41:46 +00:00
|
|
|
sock_prot_inuse_add(net, sk->sk_prot, -1);
|
|
|
|
sock_prot_inuse_add(net, &tcp_prot, 1);
|
2005-04-16 22:20:36 +00:00
|
|
|
local_bh_enable();
|
|
|
|
sk->sk_prot = &tcp_prot;
|
2005-12-14 07:26:10 +00:00
|
|
|
icsk->icsk_af_ops = &ipv4_specific;
|
2005-04-16 22:20:36 +00:00
|
|
|
sk->sk_socket->ops = &inet_stream_ops;
|
|
|
|
sk->sk_family = PF_INET;
|
2005-12-14 07:26:10 +00:00
|
|
|
tcp_sync_mss(sk, icsk->icsk_pmtu_cookie);
|
2005-04-16 22:20:36 +00:00
|
|
|
} else {
|
2006-11-27 19:10:57 +00:00
|
|
|
struct proto *prot = &udp_prot;
|
|
|
|
|
2008-03-07 00:22:02 +00:00
|
|
|
if (sk->sk_protocol == IPPROTO_UDPLITE)
|
2006-11-27 19:10:57 +00:00
|
|
|
prot = &udplite_prot;
|
2005-04-16 22:20:36 +00:00
|
|
|
local_bh_disable();
|
2008-04-01 02:41:46 +00:00
|
|
|
sock_prot_inuse_add(net, sk->sk_prot, -1);
|
|
|
|
sock_prot_inuse_add(net, prot, 1);
|
2005-04-16 22:20:36 +00:00
|
|
|
local_bh_enable();
|
2006-11-27 19:10:57 +00:00
|
|
|
sk->sk_prot = prot;
|
2005-04-16 22:20:36 +00:00
|
|
|
sk->sk_socket->ops = &inet_dgram_ops;
|
|
|
|
sk->sk_family = PF_INET;
|
|
|
|
}
|
|
|
|
opt = xchg(&np->opt, NULL);
|
|
|
|
if (opt)
|
|
|
|
sock_kfree_s(sk, opt, opt->tot_len);
|
|
|
|
pktopt = xchg(&np->pktoptions, NULL);
|
2009-02-23 21:45:33 +00:00
|
|
|
kfree_skb(pktopt);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
sk->sk_destruct = inet_sock_destruct;
|
2005-08-10 02:45:38 +00:00
|
|
|
/*
|
|
|
|
* ... and add it to the refcnt debug socks count
|
|
|
|
* in the new family. -acme
|
|
|
|
*/
|
|
|
|
sk_refcnt_debug_inc(sk);
|
2005-04-16 22:20:36 +00:00
|
|
|
module_put(THIS_MODULE);
|
|
|
|
retv = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
goto e_inval;
|
|
|
|
|
|
|
|
case IPV6_V6ONLY:
|
2008-04-12 03:59:42 +00:00
|
|
|
if (optlen < sizeof(int) ||
|
2009-10-15 06:30:45 +00:00
|
|
|
inet_sk(sk)->inet_num)
|
2005-04-16 22:20:36 +00:00
|
|
|
goto e_inval;
|
|
|
|
np->ipv6only = valbool;
|
|
|
|
retv = 0;
|
|
|
|
break;
|
|
|
|
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 00:59:17 +00:00
|
|
|
case IPV6_RECVPKTINFO:
|
2008-04-12 03:59:42 +00:00
|
|
|
if (optlen < sizeof(int))
|
|
|
|
goto e_inval;
|
2005-04-16 22:20:36 +00:00
|
|
|
np->rxopt.bits.rxinfo = valbool;
|
|
|
|
retv = 0;
|
|
|
|
break;
|
2007-02-09 14:24:49 +00:00
|
|
|
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 00:59:17 +00:00
|
|
|
case IPV6_2292PKTINFO:
|
2008-04-12 03:59:42 +00:00
|
|
|
if (optlen < sizeof(int))
|
|
|
|
goto e_inval;
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 00:59:17 +00:00
|
|
|
np->rxopt.bits.rxoinfo = valbool;
|
|
|
|
retv = 0;
|
|
|
|
break;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 00:59:17 +00:00
|
|
|
case IPV6_RECVHOPLIMIT:
|
2008-04-12 03:59:42 +00:00
|
|
|
if (optlen < sizeof(int))
|
|
|
|
goto e_inval;
|
2005-04-16 22:20:36 +00:00
|
|
|
np->rxopt.bits.rxhlim = valbool;
|
|
|
|
retv = 0;
|
|
|
|
break;
|
|
|
|
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 00:59:17 +00:00
|
|
|
case IPV6_2292HOPLIMIT:
|
2008-04-12 03:59:42 +00:00
|
|
|
if (optlen < sizeof(int))
|
|
|
|
goto e_inval;
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 00:59:17 +00:00
|
|
|
np->rxopt.bits.rxohlim = valbool;
|
|
|
|
retv = 0;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IPV6_RECVRTHDR:
|
2008-04-12 03:59:42 +00:00
|
|
|
if (optlen < sizeof(int))
|
|
|
|
goto e_inval;
|
2007-05-23 04:28:48 +00:00
|
|
|
np->rxopt.bits.srcrt = valbool;
|
2005-04-16 22:20:36 +00:00
|
|
|
retv = 0;
|
|
|
|
break;
|
|
|
|
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 00:59:17 +00:00
|
|
|
case IPV6_2292RTHDR:
|
2008-04-12 03:59:42 +00:00
|
|
|
if (optlen < sizeof(int))
|
|
|
|
goto e_inval;
|
2007-05-23 04:28:48 +00:00
|
|
|
np->rxopt.bits.osrcrt = valbool;
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 00:59:17 +00:00
|
|
|
retv = 0;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IPV6_RECVHOPOPTS:
|
2008-04-12 03:59:42 +00:00
|
|
|
if (optlen < sizeof(int))
|
|
|
|
goto e_inval;
|
2005-04-16 22:20:36 +00:00
|
|
|
np->rxopt.bits.hopopts = valbool;
|
|
|
|
retv = 0;
|
|
|
|
break;
|
|
|
|
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 00:59:17 +00:00
|
|
|
case IPV6_2292HOPOPTS:
|
2008-04-12 03:59:42 +00:00
|
|
|
if (optlen < sizeof(int))
|
|
|
|
goto e_inval;
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 00:59:17 +00:00
|
|
|
np->rxopt.bits.ohopopts = valbool;
|
|
|
|
retv = 0;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IPV6_RECVDSTOPTS:
|
2008-04-12 03:59:42 +00:00
|
|
|
if (optlen < sizeof(int))
|
|
|
|
goto e_inval;
|
2005-04-16 22:20:36 +00:00
|
|
|
np->rxopt.bits.dstopts = valbool;
|
|
|
|
retv = 0;
|
|
|
|
break;
|
|
|
|
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 00:59:17 +00:00
|
|
|
case IPV6_2292DSTOPTS:
|
2008-04-12 03:59:42 +00:00
|
|
|
if (optlen < sizeof(int))
|
|
|
|
goto e_inval;
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 00:59:17 +00:00
|
|
|
np->rxopt.bits.odstopts = valbool;
|
|
|
|
retv = 0;
|
|
|
|
break;
|
|
|
|
|
2005-09-08 01:19:03 +00:00
|
|
|
case IPV6_TCLASS:
|
2008-04-12 03:59:42 +00:00
|
|
|
if (optlen < sizeof(int))
|
|
|
|
goto e_inval;
|
2006-09-14 03:08:07 +00:00
|
|
|
if (val < -1 || val > 0xff)
|
2005-09-08 01:19:03 +00:00
|
|
|
goto e_inval;
|
inet6: Set default traffic class
This patch addresses:
* assigning -1 to np->tclass as it is currently done is not very meaningful,
since it turns into 0xff;
* RFC 3542, 6.5 allows -1 for clearing the sticky IPV6_TCLASS option
and specifies -1 to mean "use kernel default":
- RFC 2460, 7. requires that the default traffic class must be zero for
all 8 bits,
- this is consistent with RFC 2474, 4.1 which recommends a default PHB of 0,
in combination with a value of the ECN field of "non-ECT" (RFC 3168, 5.).
This patch changes the meaning of -1 from assigning 255 to mean the RFC 2460
default, which at the same time allows to satisfy clearing the sticky TCLASS
option as per RFC 3542, 6.5.
(When passing -1 as ancillary data, the fallback remains np->tclass, which
has either been set via socket options, or contains the default value.)
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Signed-off-by: David S. Miller <davem@davemloft.net>
2009-08-09 08:12:49 +00:00
|
|
|
/* RFC 3542, 6.5: default traffic class of 0x0 */
|
|
|
|
if (val == -1)
|
|
|
|
val = 0;
|
2005-09-08 01:19:03 +00:00
|
|
|
np->tclass = val;
|
|
|
|
retv = 0;
|
|
|
|
break;
|
2007-02-09 14:24:49 +00:00
|
|
|
|
2005-09-08 01:19:03 +00:00
|
|
|
case IPV6_RECVTCLASS:
|
2008-04-12 03:59:42 +00:00
|
|
|
if (optlen < sizeof(int))
|
|
|
|
goto e_inval;
|
2005-09-08 01:19:03 +00:00
|
|
|
np->rxopt.bits.rxtclass = valbool;
|
|
|
|
retv = 0;
|
|
|
|
break;
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
case IPV6_FLOWINFO:
|
2008-04-12 03:59:42 +00:00
|
|
|
if (optlen < sizeof(int))
|
|
|
|
goto e_inval;
|
2005-04-16 22:20:36 +00:00
|
|
|
np->rxopt.bits.rxflow = valbool;
|
|
|
|
retv = 0;
|
|
|
|
break;
|
|
|
|
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 00:59:17 +00:00
|
|
|
case IPV6_HOPOPTS:
|
|
|
|
case IPV6_RTHDRDSTOPTS:
|
|
|
|
case IPV6_RTHDR:
|
|
|
|
case IPV6_DSTOPTS:
|
|
|
|
{
|
|
|
|
struct ipv6_txoptions *opt;
|
2008-06-19 23:29:39 +00:00
|
|
|
|
|
|
|
/* remove any sticky options header with a zero option
|
|
|
|
* length, per RFC3542.
|
|
|
|
*/
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 00:59:17 +00:00
|
|
|
if (optlen == 0)
|
2005-11-15 05:43:36 +00:00
|
|
|
optval = NULL;
|
2008-08-04 01:16:15 +00:00
|
|
|
else if (optval == NULL)
|
|
|
|
goto e_inval;
|
2008-06-19 23:29:39 +00:00
|
|
|
else if (optlen < sizeof(struct ipv6_opt_hdr) ||
|
|
|
|
optlen & 0x7 || optlen > 8 * 255)
|
|
|
|
goto e_inval;
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 00:59:17 +00:00
|
|
|
|
|
|
|
/* hop-by-hop / destination options are privileged option */
|
|
|
|
retv = -EPERM;
|
|
|
|
if (optname != IPV6_RTHDR && !capable(CAP_NET_RAW))
|
|
|
|
break;
|
|
|
|
|
|
|
|
opt = ipv6_renew_options(sk, np->opt, optname,
|
|
|
|
(struct ipv6_opt_hdr __user *)optval,
|
|
|
|
optlen);
|
|
|
|
if (IS_ERR(opt)) {
|
|
|
|
retv = PTR_ERR(opt);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* routing header option needs extra check */
|
2008-11-13 06:59:21 +00:00
|
|
|
retv = -EINVAL;
|
2007-03-09 21:55:38 +00:00
|
|
|
if (optname == IPV6_RTHDR && opt && opt->srcrt) {
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 00:59:17 +00:00
|
|
|
struct ipv6_rt_hdr *rthdr = opt->srcrt;
|
2006-08-24 02:17:12 +00:00
|
|
|
switch (rthdr->type) {
|
2007-06-27 06:56:32 +00:00
|
|
|
#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
|
2006-08-24 02:17:12 +00:00
|
|
|
case IPV6_SRCRT_TYPE_2:
|
2008-11-13 06:59:21 +00:00
|
|
|
if (rthdr->hdrlen != 2 ||
|
|
|
|
rthdr->segments_left != 1)
|
|
|
|
goto sticky_done;
|
|
|
|
|
2006-08-24 02:17:12 +00:00
|
|
|
break;
|
2007-07-11 05:55:49 +00:00
|
|
|
#endif
|
2006-08-24 02:17:12 +00:00
|
|
|
default:
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 00:59:17 +00:00
|
|
|
goto sticky_done;
|
2006-08-24 02:17:12 +00:00
|
|
|
}
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 00:59:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
retv = 0;
|
2008-04-14 06:21:52 +00:00
|
|
|
opt = ipv6_update_options(sk, opt);
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 00:59:17 +00:00
|
|
|
sticky_done:
|
|
|
|
if (opt)
|
|
|
|
sock_kfree_s(sk, opt, opt->tot_len);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2008-12-16 10:06:23 +00:00
|
|
|
case IPV6_PKTINFO:
|
|
|
|
{
|
|
|
|
struct in6_pktinfo pkt;
|
|
|
|
|
|
|
|
if (optlen == 0)
|
|
|
|
goto e_inval;
|
|
|
|
else if (optlen < sizeof(struct in6_pktinfo) || optval == NULL)
|
|
|
|
goto e_inval;
|
|
|
|
|
2009-01-05 01:27:31 +00:00
|
|
|
if (copy_from_user(&pkt, optval, sizeof(struct in6_pktinfo))) {
|
2008-12-16 10:06:23 +00:00
|
|
|
retv = -EFAULT;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (sk->sk_bound_dev_if && pkt.ipi6_ifindex != sk->sk_bound_dev_if)
|
|
|
|
goto e_inval;
|
|
|
|
|
|
|
|
np->sticky_pktinfo.ipi6_ifindex = pkt.ipi6_ifindex;
|
|
|
|
ipv6_addr_copy(&np->sticky_pktinfo.ipi6_addr, &pkt.ipi6_addr);
|
|
|
|
retv = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 00:59:17 +00:00
|
|
|
case IPV6_2292PKTOPTIONS:
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
struct ipv6_txoptions *opt = NULL;
|
|
|
|
struct msghdr msg;
|
|
|
|
struct flowi fl;
|
|
|
|
int junk;
|
|
|
|
|
|
|
|
fl.fl6_flowlabel = 0;
|
|
|
|
fl.oif = sk->sk_bound_dev_if;
|
2009-10-05 08:24:16 +00:00
|
|
|
fl.mark = sk->sk_mark;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
if (optlen == 0)
|
|
|
|
goto update;
|
|
|
|
|
|
|
|
/* 1K is probably excessive
|
|
|
|
* 1K is surely not enough, 2K per standard header is 16K.
|
|
|
|
*/
|
|
|
|
retv = -EINVAL;
|
|
|
|
if (optlen > 64*1024)
|
|
|
|
break;
|
|
|
|
|
|
|
|
opt = sock_kmalloc(sk, sizeof(*opt) + optlen, GFP_KERNEL);
|
|
|
|
retv = -ENOBUFS;
|
|
|
|
if (opt == NULL)
|
|
|
|
break;
|
|
|
|
|
|
|
|
memset(opt, 0, sizeof(*opt));
|
|
|
|
opt->tot_len = sizeof(*opt) + optlen;
|
|
|
|
retv = -EFAULT;
|
|
|
|
if (copy_from_user(opt+1, optval, optlen))
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
msg.msg_controllen = optlen;
|
|
|
|
msg.msg_control = (void*)(opt+1);
|
|
|
|
|
2008-06-04 04:02:49 +00:00
|
|
|
retv = datagram_send_ctl(net, &msg, &fl, opt, &junk, &junk);
|
2005-04-16 22:20:36 +00:00
|
|
|
if (retv)
|
|
|
|
goto done;
|
|
|
|
update:
|
|
|
|
retv = 0;
|
2008-04-14 06:21:52 +00:00
|
|
|
opt = ipv6_update_options(sk, opt);
|
2005-04-16 22:20:36 +00:00
|
|
|
done:
|
|
|
|
if (opt)
|
|
|
|
sock_kfree_s(sk, opt, opt->tot_len);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case IPV6_UNICAST_HOPS:
|
2008-04-12 03:59:42 +00:00
|
|
|
if (optlen < sizeof(int))
|
|
|
|
goto e_inval;
|
2005-04-16 22:20:36 +00:00
|
|
|
if (val > 255 || val < -1)
|
|
|
|
goto e_inval;
|
|
|
|
np->hop_limit = val;
|
|
|
|
retv = 0;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IPV6_MULTICAST_HOPS:
|
|
|
|
if (sk->sk_type == SOCK_STREAM)
|
2008-06-11 18:27:26 +00:00
|
|
|
break;
|
2008-04-12 03:59:42 +00:00
|
|
|
if (optlen < sizeof(int))
|
|
|
|
goto e_inval;
|
2005-04-16 22:20:36 +00:00
|
|
|
if (val > 255 || val < -1)
|
|
|
|
goto e_inval;
|
|
|
|
np->mcast_hops = val;
|
|
|
|
retv = 0;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IPV6_MULTICAST_LOOP:
|
2008-04-12 03:59:42 +00:00
|
|
|
if (optlen < sizeof(int))
|
|
|
|
goto e_inval;
|
2008-06-11 18:14:51 +00:00
|
|
|
if (val != valbool)
|
|
|
|
goto e_inval;
|
2005-04-16 22:20:36 +00:00
|
|
|
np->mc_loop = valbool;
|
|
|
|
retv = 0;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IPV6_MULTICAST_IF:
|
|
|
|
if (sk->sk_type == SOCK_STREAM)
|
2008-06-11 18:27:26 +00:00
|
|
|
break;
|
2008-04-12 03:59:42 +00:00
|
|
|
if (optlen < sizeof(int))
|
|
|
|
goto e_inval;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2007-10-11 21:39:29 +00:00
|
|
|
if (val) {
|
2009-10-19 06:41:58 +00:00
|
|
|
struct net_device *dev;
|
|
|
|
|
2007-10-11 21:39:29 +00:00
|
|
|
if (sk->sk_bound_dev_if && sk->sk_bound_dev_if != val)
|
|
|
|
goto e_inval;
|
|
|
|
|
2009-10-19 06:41:58 +00:00
|
|
|
dev = dev_get_by_index(net, val);
|
|
|
|
if (!dev) {
|
2007-10-11 21:39:29 +00:00
|
|
|
retv = -ENODEV;
|
|
|
|
break;
|
|
|
|
}
|
2009-10-19 06:41:58 +00:00
|
|
|
dev_put(dev);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
np->mcast_oif = val;
|
|
|
|
retv = 0;
|
|
|
|
break;
|
|
|
|
case IPV6_ADD_MEMBERSHIP:
|
|
|
|
case IPV6_DROP_MEMBERSHIP:
|
|
|
|
{
|
|
|
|
struct ipv6_mreq mreq;
|
|
|
|
|
2008-04-07 01:42:07 +00:00
|
|
|
if (optlen < sizeof(struct ipv6_mreq))
|
|
|
|
goto e_inval;
|
|
|
|
|
2007-08-25 05:16:39 +00:00
|
|
|
retv = -EPROTO;
|
|
|
|
if (inet_sk(sk)->is_icsk)
|
|
|
|
break;
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
retv = -EFAULT;
|
|
|
|
if (copy_from_user(&mreq, optval, sizeof(struct ipv6_mreq)))
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (optname == IPV6_ADD_MEMBERSHIP)
|
|
|
|
retv = ipv6_sock_mc_join(sk, mreq.ipv6mr_ifindex, &mreq.ipv6mr_multiaddr);
|
|
|
|
else
|
|
|
|
retv = ipv6_sock_mc_drop(sk, mreq.ipv6mr_ifindex, &mreq.ipv6mr_multiaddr);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case IPV6_JOIN_ANYCAST:
|
|
|
|
case IPV6_LEAVE_ANYCAST:
|
|
|
|
{
|
|
|
|
struct ipv6_mreq mreq;
|
|
|
|
|
2008-04-07 01:42:07 +00:00
|
|
|
if (optlen < sizeof(struct ipv6_mreq))
|
2005-04-16 22:20:36 +00:00
|
|
|
goto e_inval;
|
|
|
|
|
|
|
|
retv = -EFAULT;
|
|
|
|
if (copy_from_user(&mreq, optval, sizeof(struct ipv6_mreq)))
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (optname == IPV6_JOIN_ANYCAST)
|
|
|
|
retv = ipv6_sock_ac_join(sk, mreq.ipv6mr_ifindex, &mreq.ipv6mr_acaddr);
|
|
|
|
else
|
|
|
|
retv = ipv6_sock_ac_drop(sk, mreq.ipv6mr_ifindex, &mreq.ipv6mr_acaddr);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case MCAST_JOIN_GROUP:
|
|
|
|
case MCAST_LEAVE_GROUP:
|
|
|
|
{
|
|
|
|
struct group_req greq;
|
|
|
|
struct sockaddr_in6 *psin6;
|
|
|
|
|
2008-04-07 01:42:07 +00:00
|
|
|
if (optlen < sizeof(struct group_req))
|
|
|
|
goto e_inval;
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
retv = -EFAULT;
|
|
|
|
if (copy_from_user(&greq, optval, sizeof(struct group_req)))
|
|
|
|
break;
|
|
|
|
if (greq.gr_group.ss_family != AF_INET6) {
|
|
|
|
retv = -EADDRNOTAVAIL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
psin6 = (struct sockaddr_in6 *)&greq.gr_group;
|
|
|
|
if (optname == MCAST_JOIN_GROUP)
|
|
|
|
retv = ipv6_sock_mc_join(sk, greq.gr_interface,
|
|
|
|
&psin6->sin6_addr);
|
|
|
|
else
|
|
|
|
retv = ipv6_sock_mc_drop(sk, greq.gr_interface,
|
|
|
|
&psin6->sin6_addr);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case MCAST_JOIN_SOURCE_GROUP:
|
|
|
|
case MCAST_LEAVE_SOURCE_GROUP:
|
|
|
|
case MCAST_BLOCK_SOURCE:
|
|
|
|
case MCAST_UNBLOCK_SOURCE:
|
|
|
|
{
|
|
|
|
struct group_source_req greqs;
|
|
|
|
int omode, add;
|
|
|
|
|
2008-04-07 01:42:07 +00:00
|
|
|
if (optlen < sizeof(struct group_source_req))
|
2005-04-16 22:20:36 +00:00
|
|
|
goto e_inval;
|
|
|
|
if (copy_from_user(&greqs, optval, sizeof(greqs))) {
|
|
|
|
retv = -EFAULT;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (greqs.gsr_group.ss_family != AF_INET6 ||
|
|
|
|
greqs.gsr_source.ss_family != AF_INET6) {
|
|
|
|
retv = -EADDRNOTAVAIL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (optname == MCAST_BLOCK_SOURCE) {
|
|
|
|
omode = MCAST_EXCLUDE;
|
|
|
|
add = 1;
|
|
|
|
} else if (optname == MCAST_UNBLOCK_SOURCE) {
|
|
|
|
omode = MCAST_EXCLUDE;
|
|
|
|
add = 0;
|
|
|
|
} else if (optname == MCAST_JOIN_SOURCE_GROUP) {
|
|
|
|
struct sockaddr_in6 *psin6;
|
|
|
|
|
|
|
|
psin6 = (struct sockaddr_in6 *)&greqs.gsr_group;
|
|
|
|
retv = ipv6_sock_mc_join(sk, greqs.gsr_interface,
|
|
|
|
&psin6->sin6_addr);
|
2005-06-21 20:58:25 +00:00
|
|
|
/* prior join w/ different source is ok */
|
|
|
|
if (retv && retv != -EADDRINUSE)
|
2005-04-16 22:20:36 +00:00
|
|
|
break;
|
|
|
|
omode = MCAST_INCLUDE;
|
|
|
|
add = 1;
|
2005-06-21 20:58:25 +00:00
|
|
|
} else /* MCAST_LEAVE_SOURCE_GROUP */ {
|
2005-04-16 22:20:36 +00:00
|
|
|
omode = MCAST_INCLUDE;
|
|
|
|
add = 0;
|
|
|
|
}
|
|
|
|
retv = ip6_mc_source(add, omode, sk, &greqs);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case MCAST_MSFILTER:
|
|
|
|
{
|
|
|
|
extern int sysctl_mld_max_msf;
|
|
|
|
struct group_filter *gsf;
|
|
|
|
|
|
|
|
if (optlen < GROUP_FILTER_SIZE(0))
|
|
|
|
goto e_inval;
|
|
|
|
if (optlen > sysctl_optmem_max) {
|
|
|
|
retv = -ENOBUFS;
|
|
|
|
break;
|
|
|
|
}
|
2006-01-11 23:56:43 +00:00
|
|
|
gsf = kmalloc(optlen,GFP_KERNEL);
|
2007-10-09 08:59:42 +00:00
|
|
|
if (!gsf) {
|
2005-04-16 22:20:36 +00:00
|
|
|
retv = -ENOBUFS;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
retv = -EFAULT;
|
|
|
|
if (copy_from_user(gsf, optval, optlen)) {
|
|
|
|
kfree(gsf);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/* numsrc >= (4G-140)/128 overflow in 32 bits */
|
|
|
|
if (gsf->gf_numsrc >= 0x1ffffffU ||
|
|
|
|
gsf->gf_numsrc > sysctl_mld_max_msf) {
|
|
|
|
kfree(gsf);
|
|
|
|
retv = -ENOBUFS;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (GROUP_FILTER_SIZE(gsf->gf_numsrc) > optlen) {
|
|
|
|
kfree(gsf);
|
|
|
|
retv = -EINVAL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
retv = ip6_mc_msfilter(sk, gsf);
|
|
|
|
kfree(gsf);
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case IPV6_ROUTER_ALERT:
|
2008-04-12 03:59:42 +00:00
|
|
|
if (optlen < sizeof(int))
|
|
|
|
goto e_inval;
|
2008-07-19 07:28:58 +00:00
|
|
|
retv = ip6_ra_control(sk, val);
|
2005-04-16 22:20:36 +00:00
|
|
|
break;
|
|
|
|
case IPV6_MTU_DISCOVER:
|
2008-04-12 03:59:42 +00:00
|
|
|
if (optlen < sizeof(int))
|
|
|
|
goto e_inval;
|
2009-10-20 04:53:53 +00:00
|
|
|
if (val < IP_PMTUDISC_DONT || val > IP_PMTUDISC_PROBE)
|
2005-04-16 22:20:36 +00:00
|
|
|
goto e_inval;
|
|
|
|
np->pmtudisc = val;
|
|
|
|
retv = 0;
|
|
|
|
break;
|
|
|
|
case IPV6_MTU:
|
2008-04-12 03:59:42 +00:00
|
|
|
if (optlen < sizeof(int))
|
|
|
|
goto e_inval;
|
2005-04-16 22:20:36 +00:00
|
|
|
if (val && val < IPV6_MIN_MTU)
|
|
|
|
goto e_inval;
|
|
|
|
np->frag_size = val;
|
|
|
|
retv = 0;
|
|
|
|
break;
|
|
|
|
case IPV6_RECVERR:
|
2008-04-12 03:59:42 +00:00
|
|
|
if (optlen < sizeof(int))
|
|
|
|
goto e_inval;
|
2005-04-16 22:20:36 +00:00
|
|
|
np->recverr = valbool;
|
|
|
|
if (!val)
|
|
|
|
skb_queue_purge(&sk->sk_error_queue);
|
|
|
|
retv = 0;
|
|
|
|
break;
|
|
|
|
case IPV6_FLOWINFO_SEND:
|
2008-04-12 03:59:42 +00:00
|
|
|
if (optlen < sizeof(int))
|
|
|
|
goto e_inval;
|
2005-04-16 22:20:36 +00:00
|
|
|
np->sndflow = valbool;
|
|
|
|
retv = 0;
|
|
|
|
break;
|
|
|
|
case IPV6_FLOWLABEL_MGR:
|
|
|
|
retv = ipv6_flowlabel_opt(sk, optval, optlen);
|
|
|
|
break;
|
|
|
|
case IPV6_IPSEC_POLICY:
|
|
|
|
case IPV6_XFRM_POLICY:
|
2005-08-06 13:33:15 +00:00
|
|
|
retv = -EPERM;
|
|
|
|
if (!capable(CAP_NET_ADMIN))
|
|
|
|
break;
|
2005-04-16 22:20:36 +00:00
|
|
|
retv = xfrm_user_policy(sk, optname, optval, optlen);
|
|
|
|
break;
|
|
|
|
|
2008-03-25 00:37:42 +00:00
|
|
|
case IPV6_ADDR_PREFERENCES:
|
|
|
|
{
|
|
|
|
unsigned int pref = 0;
|
|
|
|
unsigned int prefmask = ~0;
|
|
|
|
|
2008-04-12 03:59:42 +00:00
|
|
|
if (optlen < sizeof(int))
|
|
|
|
goto e_inval;
|
|
|
|
|
2008-03-25 00:37:42 +00:00
|
|
|
retv = -EINVAL;
|
|
|
|
|
|
|
|
/* check PUBLIC/TMP/PUBTMP_DEFAULT conflicts */
|
|
|
|
switch (val & (IPV6_PREFER_SRC_PUBLIC|
|
|
|
|
IPV6_PREFER_SRC_TMP|
|
|
|
|
IPV6_PREFER_SRC_PUBTMP_DEFAULT)) {
|
|
|
|
case IPV6_PREFER_SRC_PUBLIC:
|
|
|
|
pref |= IPV6_PREFER_SRC_PUBLIC;
|
|
|
|
break;
|
|
|
|
case IPV6_PREFER_SRC_TMP:
|
|
|
|
pref |= IPV6_PREFER_SRC_TMP;
|
|
|
|
break;
|
|
|
|
case IPV6_PREFER_SRC_PUBTMP_DEFAULT:
|
|
|
|
break;
|
|
|
|
case 0:
|
|
|
|
goto pref_skip_pubtmp;
|
|
|
|
default:
|
|
|
|
goto e_inval;
|
|
|
|
}
|
|
|
|
|
|
|
|
prefmask &= ~(IPV6_PREFER_SRC_PUBLIC|
|
|
|
|
IPV6_PREFER_SRC_TMP);
|
|
|
|
pref_skip_pubtmp:
|
|
|
|
|
|
|
|
/* check HOME/COA conflicts */
|
|
|
|
switch (val & (IPV6_PREFER_SRC_HOME|IPV6_PREFER_SRC_COA)) {
|
|
|
|
case IPV6_PREFER_SRC_HOME:
|
|
|
|
break;
|
|
|
|
case IPV6_PREFER_SRC_COA:
|
|
|
|
pref |= IPV6_PREFER_SRC_COA;
|
|
|
|
case 0:
|
|
|
|
goto pref_skip_coa;
|
|
|
|
default:
|
|
|
|
goto e_inval;
|
|
|
|
}
|
|
|
|
|
|
|
|
prefmask &= ~IPV6_PREFER_SRC_COA;
|
|
|
|
pref_skip_coa:
|
|
|
|
|
|
|
|
/* check CGA/NONCGA conflicts */
|
|
|
|
switch (val & (IPV6_PREFER_SRC_CGA|IPV6_PREFER_SRC_NONCGA)) {
|
|
|
|
case IPV6_PREFER_SRC_CGA:
|
|
|
|
case IPV6_PREFER_SRC_NONCGA:
|
|
|
|
case 0:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
goto e_inval;
|
|
|
|
}
|
|
|
|
|
|
|
|
np->srcprefs = (np->srcprefs & prefmask) | pref;
|
|
|
|
retv = 0;
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
2008-03-25 00:37:42 +00:00
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
release_sock(sk);
|
|
|
|
|
|
|
|
return retv;
|
|
|
|
|
|
|
|
e_inval:
|
|
|
|
release_sock(sk);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2006-03-21 06:45:21 +00:00
|
|
|
int ipv6_setsockopt(struct sock *sk, int level, int optname,
|
2009-09-30 23:12:20 +00:00
|
|
|
char __user *optval, unsigned int optlen)
|
2006-03-21 06:45:21 +00:00
|
|
|
{
|
|
|
|
int err;
|
|
|
|
|
|
|
|
if (level == SOL_IP && sk->sk_type != SOCK_RAW)
|
|
|
|
return udp_prot.setsockopt(sk, level, optname, optval, optlen);
|
|
|
|
|
|
|
|
if (level != SOL_IPV6)
|
|
|
|
return -ENOPROTOOPT;
|
|
|
|
|
|
|
|
err = do_ipv6_setsockopt(sk, level, optname, optval, optlen);
|
|
|
|
#ifdef CONFIG_NETFILTER
|
|
|
|
/* we need to exclude all possible ENOPROTOOPTs except default case */
|
|
|
|
if (err == -ENOPROTOOPT && optname != IPV6_IPSEC_POLICY &&
|
|
|
|
optname != IPV6_XFRM_POLICY) {
|
|
|
|
lock_sock(sk);
|
|
|
|
err = nf_setsockopt(sk, PF_INET6, optname, optval,
|
|
|
|
optlen);
|
|
|
|
release_sock(sk);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2007-02-22 13:05:40 +00:00
|
|
|
EXPORT_SYMBOL(ipv6_setsockopt);
|
2006-03-21 06:45:21 +00:00
|
|
|
|
|
|
|
#ifdef CONFIG_COMPAT
|
|
|
|
int compat_ipv6_setsockopt(struct sock *sk, int level, int optname,
|
2009-09-30 23:12:20 +00:00
|
|
|
char __user *optval, unsigned int optlen)
|
2006-03-21 06:45:21 +00:00
|
|
|
{
|
|
|
|
int err;
|
|
|
|
|
|
|
|
if (level == SOL_IP && sk->sk_type != SOCK_RAW) {
|
2006-03-21 06:48:35 +00:00
|
|
|
if (udp_prot.compat_setsockopt != NULL)
|
|
|
|
return udp_prot.compat_setsockopt(sk, level, optname,
|
|
|
|
optval, optlen);
|
|
|
|
return udp_prot.setsockopt(sk, level, optname, optval, optlen);
|
2006-03-21 06:45:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (level != SOL_IPV6)
|
|
|
|
return -ENOPROTOOPT;
|
|
|
|
|
2008-04-27 08:06:07 +00:00
|
|
|
if (optname >= MCAST_JOIN_GROUP && optname <= MCAST_MSFILTER)
|
|
|
|
return compat_mc_setsockopt(sk, level, optname, optval, optlen,
|
|
|
|
ipv6_setsockopt);
|
|
|
|
|
2006-03-21 06:45:21 +00:00
|
|
|
err = do_ipv6_setsockopt(sk, level, optname, optval, optlen);
|
|
|
|
#ifdef CONFIG_NETFILTER
|
|
|
|
/* we need to exclude all possible ENOPROTOOPTs except default case */
|
|
|
|
if (err == -ENOPROTOOPT && optname != IPV6_IPSEC_POLICY &&
|
2006-03-21 06:48:35 +00:00
|
|
|
optname != IPV6_XFRM_POLICY) {
|
2006-03-21 06:45:21 +00:00
|
|
|
lock_sock(sk);
|
2006-03-21 06:48:35 +00:00
|
|
|
err = compat_nf_setsockopt(sk, PF_INET6, optname,
|
|
|
|
optval, optlen);
|
2006-03-21 06:45:21 +00:00
|
|
|
release_sock(sk);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
return err;
|
|
|
|
}
|
2006-03-21 06:48:35 +00:00
|
|
|
|
|
|
|
EXPORT_SYMBOL(compat_ipv6_setsockopt);
|
2006-03-21 06:45:21 +00:00
|
|
|
#endif
|
|
|
|
|
2007-03-07 20:50:46 +00:00
|
|
|
static int ipv6_getsockopt_sticky(struct sock *sk, struct ipv6_txoptions *opt,
|
2007-03-19 00:35:57 +00:00
|
|
|
int optname, char __user *optval, int len)
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 00:59:17 +00:00
|
|
|
{
|
2007-03-07 20:50:46 +00:00
|
|
|
struct ipv6_opt_hdr *hdr;
|
|
|
|
|
2007-03-19 00:35:57 +00:00
|
|
|
if (!opt)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
switch(optname) {
|
|
|
|
case IPV6_HOPOPTS:
|
|
|
|
hdr = opt->hopopt;
|
|
|
|
break;
|
|
|
|
case IPV6_RTHDRDSTOPTS:
|
|
|
|
hdr = opt->dst0opt;
|
|
|
|
break;
|
|
|
|
case IPV6_RTHDR:
|
|
|
|
hdr = (struct ipv6_opt_hdr *)opt->srcrt;
|
|
|
|
break;
|
|
|
|
case IPV6_DSTOPTS:
|
|
|
|
hdr = opt->dst1opt;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return -EINVAL; /* should not happen */
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!hdr)
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 00:59:17 +00:00
|
|
|
return 0;
|
2007-03-07 20:50:46 +00:00
|
|
|
|
2007-03-10 00:19:17 +00:00
|
|
|
len = min_t(unsigned int, len, ipv6_optlen(hdr));
|
2007-08-15 22:07:30 +00:00
|
|
|
if (copy_to_user(optval, hdr, len))
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 00:59:17 +00:00
|
|
|
return -EFAULT;
|
2008-05-28 08:27:28 +00:00
|
|
|
return len;
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 00:59:17 +00:00
|
|
|
}
|
|
|
|
|
2006-03-21 06:45:21 +00:00
|
|
|
static int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
|
2005-04-16 22:20:36 +00:00
|
|
|
char __user *optval, int __user *optlen)
|
|
|
|
{
|
|
|
|
struct ipv6_pinfo *np = inet6_sk(sk);
|
|
|
|
int len;
|
|
|
|
int val;
|
|
|
|
|
2008-04-03 00:22:53 +00:00
|
|
|
if (ip6_mroute_opt(optname))
|
|
|
|
return ip6_mroute_getsockopt(sk, optname, optval, optlen);
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
if (get_user(len, optlen))
|
|
|
|
return -EFAULT;
|
|
|
|
switch (optname) {
|
|
|
|
case IPV6_ADDRFORM:
|
|
|
|
if (sk->sk_protocol != IPPROTO_UDP &&
|
2006-11-27 19:10:57 +00:00
|
|
|
sk->sk_protocol != IPPROTO_UDPLITE &&
|
2005-04-16 22:20:36 +00:00
|
|
|
sk->sk_protocol != IPPROTO_TCP)
|
2008-06-11 18:27:26 +00:00
|
|
|
return -ENOPROTOOPT;
|
2005-04-16 22:20:36 +00:00
|
|
|
if (sk->sk_state != TCP_ESTABLISHED)
|
|
|
|
return -ENOTCONN;
|
|
|
|
val = sk->sk_family;
|
|
|
|
break;
|
|
|
|
case MCAST_MSFILTER:
|
|
|
|
{
|
|
|
|
struct group_filter gsf;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
if (len < GROUP_FILTER_SIZE(0))
|
|
|
|
return -EINVAL;
|
|
|
|
if (copy_from_user(&gsf, optval, GROUP_FILTER_SIZE(0)))
|
|
|
|
return -EFAULT;
|
2008-04-28 05:40:55 +00:00
|
|
|
if (gsf.gf_group.ss_family != AF_INET6)
|
|
|
|
return -EADDRNOTAVAIL;
|
2005-04-16 22:20:36 +00:00
|
|
|
lock_sock(sk);
|
|
|
|
err = ip6_mc_msfget(sk, &gsf,
|
|
|
|
(struct group_filter __user *)optval, optlen);
|
|
|
|
release_sock(sk);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 00:59:17 +00:00
|
|
|
case IPV6_2292PKTOPTIONS:
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
struct msghdr msg;
|
|
|
|
struct sk_buff *skb;
|
|
|
|
|
|
|
|
if (sk->sk_type != SOCK_STREAM)
|
|
|
|
return -ENOPROTOOPT;
|
|
|
|
|
|
|
|
msg.msg_control = optval;
|
|
|
|
msg.msg_controllen = len;
|
|
|
|
msg.msg_flags = 0;
|
|
|
|
|
|
|
|
lock_sock(sk);
|
|
|
|
skb = np->pktoptions;
|
|
|
|
if (skb)
|
|
|
|
atomic_inc(&skb->users);
|
|
|
|
release_sock(sk);
|
|
|
|
|
|
|
|
if (skb) {
|
|
|
|
int err = datagram_recv_ctl(sk, &msg, skb);
|
|
|
|
kfree_skb(skb);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
} else {
|
|
|
|
if (np->rxopt.bits.rxinfo) {
|
|
|
|
struct in6_pktinfo src_info;
|
2008-12-16 10:07:45 +00:00
|
|
|
src_info.ipi6_ifindex = np->mcast_oif ? np->mcast_oif :
|
|
|
|
np->sticky_pktinfo.ipi6_ifindex;
|
|
|
|
np->mcast_oif? ipv6_addr_copy(&src_info.ipi6_addr, &np->daddr) :
|
|
|
|
ipv6_addr_copy(&src_info.ipi6_addr, &(np->sticky_pktinfo.ipi6_addr));
|
2005-04-16 22:20:36 +00:00
|
|
|
put_cmsg(&msg, SOL_IPV6, IPV6_PKTINFO, sizeof(src_info), &src_info);
|
|
|
|
}
|
|
|
|
if (np->rxopt.bits.rxhlim) {
|
|
|
|
int hlim = np->mcast_hops;
|
|
|
|
put_cmsg(&msg, SOL_IPV6, IPV6_HOPLIMIT, sizeof(hlim), &hlim);
|
|
|
|
}
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 00:59:17 +00:00
|
|
|
if (np->rxopt.bits.rxoinfo) {
|
|
|
|
struct in6_pktinfo src_info;
|
2008-12-16 10:07:45 +00:00
|
|
|
src_info.ipi6_ifindex = np->mcast_oif ? np->mcast_oif :
|
|
|
|
np->sticky_pktinfo.ipi6_ifindex;
|
|
|
|
np->mcast_oif? ipv6_addr_copy(&src_info.ipi6_addr, &np->daddr) :
|
|
|
|
ipv6_addr_copy(&src_info.ipi6_addr, &(np->sticky_pktinfo.ipi6_addr));
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 00:59:17 +00:00
|
|
|
put_cmsg(&msg, SOL_IPV6, IPV6_2292PKTINFO, sizeof(src_info), &src_info);
|
|
|
|
}
|
|
|
|
if (np->rxopt.bits.rxohlim) {
|
|
|
|
int hlim = np->mcast_hops;
|
|
|
|
put_cmsg(&msg, SOL_IPV6, IPV6_2292HOPLIMIT, sizeof(hlim), &hlim);
|
|
|
|
}
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
len -= msg.msg_controllen;
|
|
|
|
return put_user(len, optlen);
|
|
|
|
}
|
|
|
|
case IPV6_MTU:
|
|
|
|
{
|
|
|
|
struct dst_entry *dst;
|
2007-02-09 14:24:49 +00:00
|
|
|
val = 0;
|
2005-04-16 22:20:36 +00:00
|
|
|
lock_sock(sk);
|
|
|
|
dst = sk_dst_get(sk);
|
|
|
|
if (dst) {
|
|
|
|
val = dst_mtu(dst);
|
|
|
|
dst_release(dst);
|
|
|
|
}
|
|
|
|
release_sock(sk);
|
|
|
|
if (!val)
|
|
|
|
return -ENOTCONN;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case IPV6_V6ONLY:
|
|
|
|
val = np->ipv6only;
|
|
|
|
break;
|
|
|
|
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 00:59:17 +00:00
|
|
|
case IPV6_RECVPKTINFO:
|
2005-04-16 22:20:36 +00:00
|
|
|
val = np->rxopt.bits.rxinfo;
|
|
|
|
break;
|
|
|
|
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 00:59:17 +00:00
|
|
|
case IPV6_2292PKTINFO:
|
|
|
|
val = np->rxopt.bits.rxoinfo;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IPV6_RECVHOPLIMIT:
|
2005-04-16 22:20:36 +00:00
|
|
|
val = np->rxopt.bits.rxhlim;
|
|
|
|
break;
|
|
|
|
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 00:59:17 +00:00
|
|
|
case IPV6_2292HOPLIMIT:
|
|
|
|
val = np->rxopt.bits.rxohlim;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IPV6_RECVRTHDR:
|
2005-04-16 22:20:36 +00:00
|
|
|
val = np->rxopt.bits.srcrt;
|
|
|
|
break;
|
|
|
|
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 00:59:17 +00:00
|
|
|
case IPV6_2292RTHDR:
|
|
|
|
val = np->rxopt.bits.osrcrt;
|
|
|
|
break;
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
case IPV6_HOPOPTS:
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 00:59:17 +00:00
|
|
|
case IPV6_RTHDRDSTOPTS:
|
|
|
|
case IPV6_RTHDR:
|
|
|
|
case IPV6_DSTOPTS:
|
|
|
|
{
|
|
|
|
|
|
|
|
lock_sock(sk);
|
2007-03-07 20:50:46 +00:00
|
|
|
len = ipv6_getsockopt_sticky(sk, np->opt,
|
2007-03-19 00:35:57 +00:00
|
|
|
optname, optval, len);
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 00:59:17 +00:00
|
|
|
release_sock(sk);
|
2008-05-28 08:23:47 +00:00
|
|
|
/* check if ipv6_getsockopt_sticky() returns err code */
|
|
|
|
if (len < 0)
|
|
|
|
return len;
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 00:59:17 +00:00
|
|
|
return put_user(len, optlen);
|
|
|
|
}
|
|
|
|
|
|
|
|
case IPV6_RECVHOPOPTS:
|
2005-04-16 22:20:36 +00:00
|
|
|
val = np->rxopt.bits.hopopts;
|
|
|
|
break;
|
|
|
|
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 00:59:17 +00:00
|
|
|
case IPV6_2292HOPOPTS:
|
|
|
|
val = np->rxopt.bits.ohopopts;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IPV6_RECVDSTOPTS:
|
2005-04-16 22:20:36 +00:00
|
|
|
val = np->rxopt.bits.dstopts;
|
|
|
|
break;
|
|
|
|
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 00:59:17 +00:00
|
|
|
case IPV6_2292DSTOPTS:
|
|
|
|
val = np->rxopt.bits.odstopts;
|
|
|
|
break;
|
|
|
|
|
2005-09-08 01:19:03 +00:00
|
|
|
case IPV6_TCLASS:
|
|
|
|
val = np->tclass;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IPV6_RECVTCLASS:
|
|
|
|
val = np->rxopt.bits.rxtclass;
|
|
|
|
break;
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
case IPV6_FLOWINFO:
|
|
|
|
val = np->rxopt.bits.rxflow;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IPV6_UNICAST_HOPS:
|
|
|
|
case IPV6_MULTICAST_HOPS:
|
2006-12-13 01:09:49 +00:00
|
|
|
{
|
|
|
|
struct dst_entry *dst;
|
|
|
|
|
|
|
|
if (optname == IPV6_UNICAST_HOPS)
|
|
|
|
val = np->hop_limit;
|
|
|
|
else
|
|
|
|
val = np->mcast_hops;
|
|
|
|
|
|
|
|
dst = sk_dst_get(sk);
|
|
|
|
if (dst) {
|
|
|
|
if (val < 0)
|
2008-03-10 10:00:30 +00:00
|
|
|
val = ip6_dst_hoplimit(dst);
|
2006-12-13 01:09:49 +00:00
|
|
|
dst_release(dst);
|
|
|
|
}
|
|
|
|
if (val < 0)
|
2008-07-20 05:35:03 +00:00
|
|
|
val = sock_net(sk)->ipv6.devconf_all->hop_limit;
|
2005-04-16 22:20:36 +00:00
|
|
|
break;
|
2006-12-13 01:09:49 +00:00
|
|
|
}
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
case IPV6_MULTICAST_LOOP:
|
|
|
|
val = np->mc_loop;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IPV6_MULTICAST_IF:
|
|
|
|
val = np->mcast_oif;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IPV6_MTU_DISCOVER:
|
|
|
|
val = np->pmtudisc;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IPV6_RECVERR:
|
|
|
|
val = np->recverr;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IPV6_FLOWINFO_SEND:
|
|
|
|
val = np->sndflow;
|
|
|
|
break;
|
|
|
|
|
2008-03-25 00:37:42 +00:00
|
|
|
case IPV6_ADDR_PREFERENCES:
|
|
|
|
val = 0;
|
|
|
|
|
|
|
|
if (np->srcprefs & IPV6_PREFER_SRC_TMP)
|
|
|
|
val |= IPV6_PREFER_SRC_TMP;
|
|
|
|
else if (np->srcprefs & IPV6_PREFER_SRC_PUBLIC)
|
|
|
|
val |= IPV6_PREFER_SRC_PUBLIC;
|
|
|
|
else {
|
|
|
|
/* XXX: should we return system default? */
|
|
|
|
val |= IPV6_PREFER_SRC_PUBTMP_DEFAULT;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (np->srcprefs & IPV6_PREFER_SRC_COA)
|
|
|
|
val |= IPV6_PREFER_SRC_COA;
|
|
|
|
else
|
|
|
|
val |= IPV6_PREFER_SRC_HOME;
|
|
|
|
break;
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
default:
|
2007-12-16 21:39:57 +00:00
|
|
|
return -ENOPROTOOPT;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
len = min_t(unsigned int, sizeof(int), len);
|
|
|
|
if(put_user(len, optlen))
|
|
|
|
return -EFAULT;
|
|
|
|
if(copy_to_user(optval,&val,len))
|
|
|
|
return -EFAULT;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-03-21 06:45:21 +00:00
|
|
|
int ipv6_getsockopt(struct sock *sk, int level, int optname,
|
|
|
|
char __user *optval, int __user *optlen)
|
|
|
|
{
|
|
|
|
int err;
|
|
|
|
|
|
|
|
if (level == SOL_IP && sk->sk_type != SOCK_RAW)
|
|
|
|
return udp_prot.getsockopt(sk, level, optname, optval, optlen);
|
|
|
|
|
|
|
|
if(level != SOL_IPV6)
|
|
|
|
return -ENOPROTOOPT;
|
|
|
|
|
|
|
|
err = do_ipv6_getsockopt(sk, level, optname, optval, optlen);
|
|
|
|
#ifdef CONFIG_NETFILTER
|
2007-12-16 21:39:57 +00:00
|
|
|
/* we need to exclude all possible ENOPROTOOPTs except default case */
|
|
|
|
if (err == -ENOPROTOOPT && optname != IPV6_2292PKTOPTIONS) {
|
2006-03-21 06:45:21 +00:00
|
|
|
int len;
|
|
|
|
|
|
|
|
if (get_user(len, optlen))
|
|
|
|
return -EFAULT;
|
|
|
|
|
|
|
|
lock_sock(sk);
|
|
|
|
err = nf_getsockopt(sk, PF_INET6, optname, optval,
|
|
|
|
&len);
|
|
|
|
release_sock(sk);
|
|
|
|
if (err >= 0)
|
|
|
|
err = put_user(len, optlen);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2007-02-22 13:05:40 +00:00
|
|
|
EXPORT_SYMBOL(ipv6_getsockopt);
|
|
|
|
|
2006-03-21 06:45:21 +00:00
|
|
|
#ifdef CONFIG_COMPAT
|
|
|
|
int compat_ipv6_getsockopt(struct sock *sk, int level, int optname,
|
2006-03-21 06:48:35 +00:00
|
|
|
char __user *optval, int __user *optlen)
|
2006-03-21 06:45:21 +00:00
|
|
|
{
|
|
|
|
int err;
|
|
|
|
|
|
|
|
if (level == SOL_IP && sk->sk_type != SOCK_RAW) {
|
2006-03-21 06:48:35 +00:00
|
|
|
if (udp_prot.compat_getsockopt != NULL)
|
|
|
|
return udp_prot.compat_getsockopt(sk, level, optname,
|
|
|
|
optval, optlen);
|
|
|
|
return udp_prot.getsockopt(sk, level, optname, optval, optlen);
|
2006-03-21 06:45:21 +00:00
|
|
|
}
|
|
|
|
|
2006-03-21 06:48:35 +00:00
|
|
|
if (level != SOL_IPV6)
|
2006-03-21 06:45:21 +00:00
|
|
|
return -ENOPROTOOPT;
|
|
|
|
|
2008-04-30 21:49:54 +00:00
|
|
|
if (optname == MCAST_MSFILTER)
|
|
|
|
return compat_mc_getsockopt(sk, level, optname, optval, optlen,
|
|
|
|
ipv6_getsockopt);
|
|
|
|
|
2006-03-21 06:45:21 +00:00
|
|
|
err = do_ipv6_getsockopt(sk, level, optname, optval, optlen);
|
|
|
|
#ifdef CONFIG_NETFILTER
|
2007-12-16 21:39:57 +00:00
|
|
|
/* we need to exclude all possible ENOPROTOOPTs except default case */
|
|
|
|
if (err == -ENOPROTOOPT && optname != IPV6_2292PKTOPTIONS) {
|
2006-03-21 06:45:21 +00:00
|
|
|
int len;
|
|
|
|
|
|
|
|
if (get_user(len, optlen))
|
|
|
|
return -EFAULT;
|
|
|
|
|
|
|
|
lock_sock(sk);
|
2006-03-21 06:48:35 +00:00
|
|
|
err = compat_nf_getsockopt(sk, PF_INET6,
|
|
|
|
optname, optval, &len);
|
2006-03-21 06:45:21 +00:00
|
|
|
release_sock(sk);
|
|
|
|
if (err >= 0)
|
|
|
|
err = put_user(len, optlen);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
return err;
|
|
|
|
}
|
2006-03-21 06:48:35 +00:00
|
|
|
|
|
|
|
EXPORT_SYMBOL(compat_ipv6_getsockopt);
|
2006-03-21 06:45:21 +00:00
|
|
|
#endif
|
|
|
|
|