diff options
author | ume <ume@FreeBSD.org> | 2003-10-26 18:17:01 +0000 |
---|---|---|
committer | ume <ume@FreeBSD.org> | 2003-10-26 18:17:01 +0000 |
commit | ecb479d77a3176ca6036907492337c471a157aac (patch) | |
tree | 3e1395e0c09588c3fea16548fd4b3dba938a73c1 | |
parent | 5d6245ce54bf25a1d84868ce65c49dd703dd26fb (diff) | |
download | FreeBSD-src-ecb479d77a3176ca6036907492337c471a157aac.zip FreeBSD-src-ecb479d77a3176ca6036907492337c471a157aac.tar.gz |
re-add wrongly disappered IPV6_CHECKSUM stuff by introducing
ip6_raw_ctloutput().
Obtained from: KAME
-rw-r--r-- | sys/netinet6/ip6_output.c | 76 | ||||
-rw-r--r-- | sys/netinet6/ip6_var.h | 1 | ||||
-rw-r--r-- | sys/netinet6/raw_ip6.c | 6 |
3 files changed, 83 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. diff --git a/sys/netinet6/ip6_var.h b/sys/netinet6/ip6_var.h index 641914d..6edaa1c 100644 --- a/sys/netinet6/ip6_var.h +++ b/sys/netinet6/ip6_var.h @@ -367,6 +367,7 @@ int ip6_output __P((struct mbuf *, struct ip6_pktopts *, struct ip6_moptions *, struct ifnet **, struct inpcb *)); int ip6_ctloutput __P((struct socket *, struct sockopt *)); +int ip6_raw_ctloutput __P((struct socket *, struct sockopt *)); void init_ip6pktopts __P((struct ip6_pktopts *)); int ip6_setpktoptions __P((struct mbuf *, struct ip6_pktopts *, struct ip6_pktopts *, int, int, int)); diff --git a/sys/netinet6/raw_ip6.c b/sys/netinet6/raw_ip6.c index 01f2440..6dddaac 100644 --- a/sys/netinet6/raw_ip6.c +++ b/sys/netinet6/raw_ip6.c @@ -527,6 +527,9 @@ rip6_ctloutput(so, sopt) case MRT6_PIM: error = ip6_mrouter_get(so, sopt); break; + case IPV6_CHECKSUM: + error = ip6_raw_ctloutput(so, sopt); + break; default: error = ip6_ctloutput(so, sopt); break; @@ -544,6 +547,9 @@ rip6_ctloutput(so, sopt) case MRT6_PIM: error = ip6_mrouter_set(so, sopt); break; + case IPV6_CHECKSUM: + error = ip6_raw_ctloutput(so, sopt); + break; default: error = ip6_ctloutput(so, sopt); break; |