|
@@ -971,6 +971,19 @@ static int do_rawv6_setsockopt(struct sock *sk, int level, int optname,
|
|
|
|
|
|
switch (optname) {
|
|
|
case IPV6_CHECKSUM:
|
|
|
+ if (inet_sk(sk)->num == IPPROTO_ICMPV6 &&
|
|
|
+ level == IPPROTO_IPV6) {
|
|
|
+ /*
|
|
|
+ * RFC3542 tells that IPV6_CHECKSUM socket
|
|
|
+ * option in the IPPROTO_IPV6 level is not
|
|
|
+ * allowed on ICMPv6 sockets.
|
|
|
+ * If you want to set it, use IPPROTO_RAW
|
|
|
+ * level IPV6_CHECKSUM socket option
|
|
|
+ * (Linux extension).
|
|
|
+ */
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
/* You may get strange result with a positive odd offset;
|
|
|
RFC2292bis agrees with me. */
|
|
|
if (val > 0 && (val&1))
|
|
@@ -1046,6 +1059,11 @@ static int do_rawv6_getsockopt(struct sock *sk, int level, int optname,
|
|
|
|
|
|
switch (optname) {
|
|
|
case IPV6_CHECKSUM:
|
|
|
+ /*
|
|
|
+ * We allow getsockopt() for IPPROTO_IPV6-level
|
|
|
+ * IPV6_CHECKSUM socket option on ICMPv6 sockets
|
|
|
+ * since RFC3542 is silent about it.
|
|
|
+ */
|
|
|
if (rp->checksum == 0)
|
|
|
val = -1;
|
|
|
else
|