summaryrefslogtreecommitdiffstats
path: root/sys/netinet6/ip6_output.c
diff options
context:
space:
mode:
authorume <ume@FreeBSD.org>2003-10-26 18:17:01 +0000
committerume <ume@FreeBSD.org>2003-10-26 18:17:01 +0000
commitecb479d77a3176ca6036907492337c471a157aac (patch)
tree3e1395e0c09588c3fea16548fd4b3dba938a73c1 /sys/netinet6/ip6_output.c
parent5d6245ce54bf25a1d84868ce65c49dd703dd26fb (diff)
downloadFreeBSD-src-ecb479d77a3176ca6036907492337c471a157aac.zip
FreeBSD-src-ecb479d77a3176ca6036907492337c471a157aac.tar.gz
re-add wrongly disappered IPV6_CHECKSUM stuff by introducing
ip6_raw_ctloutput(). Obtained from: KAME
Diffstat (limited to 'sys/netinet6/ip6_output.c')
-rw-r--r--sys/netinet6/ip6_output.c76
1 files changed, 76 insertions, 0 deletions
diff --git a/sys/netinet6/ip6_output.c b/sys/netinet6/ip6_output.c
index 0e20f6c..d916434 100644
--- a/sys/netinet6/ip6_output.c
+++ b/sys/netinet6/ip6_output.c
@@ -2118,6 +2118,82 @@ do { \
return (error);
}
+int
+ip6_raw_ctloutput(so, sopt)
+ struct socket *so;
+ struct sockopt *sopt;
+{
+ int error = 0, optval, optlen;
+ const int icmp6off = offsetof(struct icmp6_hdr, icmp6_cksum);
+ struct in6pcb *in6p = sotoin6pcb(so);
+ int level, op, optname;
+
+ if (sopt) {
+ level = sopt->sopt_level;
+ op = sopt->sopt_dir;
+ optname = sopt->sopt_name;
+ optlen = sopt->sopt_valsize;
+ } else
+ panic("ip6_raw_ctloutput: arg soopt is NULL");
+
+ if (level != IPPROTO_IPV6) {
+ return (EINVAL);
+ }
+
+ switch (optname) {
+ case IPV6_CHECKSUM:
+ /*
+ * For ICMPv6 sockets, no modification allowed for checksum
+ * offset, permit "no change" values to help existing apps.
+ *
+ * XXX 2292bis says: "An attempt to set IPV6_CHECKSUM
+ * for an ICMPv6 socket will fail."
+ * The current behavior does not meet 2292bis.
+ */
+ switch (op) {
+ case SOPT_SET:
+ if (optlen != sizeof(int)) {
+ error = EINVAL;
+ break;
+ }
+ error = sooptcopyin(sopt, &optval, sizeof(optval),
+ sizeof(optval));
+ if (error)
+ break;
+ if ((optval % 2) != 0) {
+ /* the API assumes even offset values */
+ error = EINVAL;
+ } else if (so->so_proto->pr_protocol ==
+ IPPROTO_ICMPV6) {
+ if (optval != icmp6off)
+ error = EINVAL;
+ } else
+ in6p->in6p_cksum = optval;
+ break;
+
+ case SOPT_GET:
+ if (so->so_proto->pr_protocol == IPPROTO_ICMPV6)
+ optval = icmp6off;
+ else
+ optval = in6p->in6p_cksum;
+
+ error = sooptcopyout(sopt, &optval, sizeof(optval));
+ break;
+
+ default:
+ error = EINVAL;
+ break;
+ }
+ break;
+
+ default:
+ error = ENOPROTOOPT;
+ break;
+ }
+
+ return (error);
+}
+
/*
* Set up IP6 options in pcb for insertion in output packets or
* specifying behavior of outgoing packets.
OpenPOWER on IntegriCloud