diff options
Diffstat (limited to 'net/ipv6/raw.c')
-rw-r--r-- | net/ipv6/raw.c | 28 |
1 files changed, 22 insertions, 6 deletions
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index dc65ec198f7c..fa59dd7a427e 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c | |||
@@ -733,6 +733,7 @@ static int raw6_getfrag(void *from, char *to, int offset, int len, int odd, | |||
733 | 733 | ||
734 | static int rawv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) | 734 | static int rawv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) |
735 | { | 735 | { |
736 | struct ipv6_txoptions *opt_to_free = NULL; | ||
736 | struct ipv6_txoptions opt_space; | 737 | struct ipv6_txoptions opt_space; |
737 | DECLARE_SOCKADDR(struct sockaddr_in6 *, sin6, msg->msg_name); | 738 | DECLARE_SOCKADDR(struct sockaddr_in6 *, sin6, msg->msg_name); |
738 | struct in6_addr *daddr, *final_p, final; | 739 | struct in6_addr *daddr, *final_p, final; |
@@ -839,8 +840,10 @@ static int rawv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) | |||
839 | if (!(opt->opt_nflen|opt->opt_flen)) | 840 | if (!(opt->opt_nflen|opt->opt_flen)) |
840 | opt = NULL; | 841 | opt = NULL; |
841 | } | 842 | } |
842 | if (!opt) | 843 | if (!opt) { |
843 | opt = np->opt; | 844 | opt = txopt_get(np); |
845 | opt_to_free = opt; | ||
846 | } | ||
844 | if (flowlabel) | 847 | if (flowlabel) |
845 | opt = fl6_merge_options(&opt_space, flowlabel, opt); | 848 | opt = fl6_merge_options(&opt_space, flowlabel, opt); |
846 | opt = ipv6_fixup_options(&opt_space, opt); | 849 | opt = ipv6_fixup_options(&opt_space, opt); |
@@ -906,6 +909,7 @@ done: | |||
906 | dst_release(dst); | 909 | dst_release(dst); |
907 | out: | 910 | out: |
908 | fl6_sock_release(flowlabel); | 911 | fl6_sock_release(flowlabel); |
912 | txopt_put(opt_to_free); | ||
909 | return err < 0 ? err : len; | 913 | return err < 0 ? err : len; |
910 | do_confirm: | 914 | do_confirm: |
911 | dst_confirm(dst); | 915 | dst_confirm(dst); |
@@ -968,6 +972,11 @@ static int do_rawv6_setsockopt(struct sock *sk, int level, int optname, | |||
968 | return -EFAULT; | 972 | return -EFAULT; |
969 | 973 | ||
970 | switch (optname) { | 974 | switch (optname) { |
975 | case IPV6_HDRINCL: | ||
976 | if (sk->sk_type != SOCK_RAW) | ||
977 | return -EINVAL; | ||
978 | inet_sk(sk)->hdrincl = !!val; | ||
979 | return 0; | ||
971 | case IPV6_CHECKSUM: | 980 | case IPV6_CHECKSUM: |
972 | if (inet_sk(sk)->inet_num == IPPROTO_ICMPV6 && | 981 | if (inet_sk(sk)->inet_num == IPPROTO_ICMPV6 && |
973 | level == IPPROTO_IPV6) { | 982 | level == IPPROTO_IPV6) { |
@@ -1012,7 +1021,8 @@ static int rawv6_setsockopt(struct sock *sk, int level, int optname, | |||
1012 | return -EOPNOTSUPP; | 1021 | return -EOPNOTSUPP; |
1013 | return rawv6_seticmpfilter(sk, level, optname, optval, optlen); | 1022 | return rawv6_seticmpfilter(sk, level, optname, optval, optlen); |
1014 | case SOL_IPV6: | 1023 | case SOL_IPV6: |
1015 | if (optname == IPV6_CHECKSUM) | 1024 | if (optname == IPV6_CHECKSUM || |
1025 | optname == IPV6_HDRINCL) | ||
1016 | break; | 1026 | break; |
1017 | default: | 1027 | default: |
1018 | return ipv6_setsockopt(sk, level, optname, optval, optlen); | 1028 | return ipv6_setsockopt(sk, level, optname, optval, optlen); |
@@ -1033,7 +1043,8 @@ static int compat_rawv6_setsockopt(struct sock *sk, int level, int optname, | |||
1033 | return -EOPNOTSUPP; | 1043 | return -EOPNOTSUPP; |
1034 | return rawv6_seticmpfilter(sk, level, optname, optval, optlen); | 1044 | return rawv6_seticmpfilter(sk, level, optname, optval, optlen); |
1035 | case SOL_IPV6: | 1045 | case SOL_IPV6: |
1036 | if (optname == IPV6_CHECKSUM) | 1046 | if (optname == IPV6_CHECKSUM || |
1047 | optname == IPV6_HDRINCL) | ||
1037 | break; | 1048 | break; |
1038 | default: | 1049 | default: |
1039 | return compat_ipv6_setsockopt(sk, level, optname, | 1050 | return compat_ipv6_setsockopt(sk, level, optname, |
@@ -1053,6 +1064,9 @@ static int do_rawv6_getsockopt(struct sock *sk, int level, int optname, | |||
1053 | return -EFAULT; | 1064 | return -EFAULT; |
1054 | 1065 | ||
1055 | switch (optname) { | 1066 | switch (optname) { |
1067 | case IPV6_HDRINCL: | ||
1068 | val = inet_sk(sk)->hdrincl; | ||
1069 | break; | ||
1056 | case IPV6_CHECKSUM: | 1070 | case IPV6_CHECKSUM: |
1057 | /* | 1071 | /* |
1058 | * We allow getsockopt() for IPPROTO_IPV6-level | 1072 | * We allow getsockopt() for IPPROTO_IPV6-level |
@@ -1090,7 +1104,8 @@ static int rawv6_getsockopt(struct sock *sk, int level, int optname, | |||
1090 | return -EOPNOTSUPP; | 1104 | return -EOPNOTSUPP; |
1091 | return rawv6_geticmpfilter(sk, level, optname, optval, optlen); | 1105 | return rawv6_geticmpfilter(sk, level, optname, optval, optlen); |
1092 | case SOL_IPV6: | 1106 | case SOL_IPV6: |
1093 | if (optname == IPV6_CHECKSUM) | 1107 | if (optname == IPV6_CHECKSUM || |
1108 | optname == IPV6_HDRINCL) | ||
1094 | break; | 1109 | break; |
1095 | default: | 1110 | default: |
1096 | return ipv6_getsockopt(sk, level, optname, optval, optlen); | 1111 | return ipv6_getsockopt(sk, level, optname, optval, optlen); |
@@ -1111,7 +1126,8 @@ static int compat_rawv6_getsockopt(struct sock *sk, int level, int optname, | |||
1111 | return -EOPNOTSUPP; | 1126 | return -EOPNOTSUPP; |
1112 | return rawv6_geticmpfilter(sk, level, optname, optval, optlen); | 1127 | return rawv6_geticmpfilter(sk, level, optname, optval, optlen); |
1113 | case SOL_IPV6: | 1128 | case SOL_IPV6: |
1114 | if (optname == IPV6_CHECKSUM) | 1129 | if (optname == IPV6_CHECKSUM || |
1130 | optname == IPV6_HDRINCL) | ||
1115 | break; | 1131 | break; |
1116 | default: | 1132 | default: |
1117 | return compat_ipv6_getsockopt(sk, level, optname, | 1133 | return compat_ipv6_getsockopt(sk, level, optname, |