summaryrefslogtreecommitdiffstats
path: root/net/ipv6/raw.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1997-12-16 05:34:03 +0000
committerRalf Baechle <ralf@linux-mips.org>1997-12-16 05:34:03 +0000
commit967c65a99059fd459b956c1588ce0ba227912c4e (patch)
tree8224d013ff5d255420713d05610c7efebd204d2a /net/ipv6/raw.c
parente20c1cc1656a66a2773bca4591a895cbc12696ff (diff)
Merge with Linux 2.1.72, part 1.
Diffstat (limited to 'net/ipv6/raw.c')
-rw-r--r--net/ipv6/raw.c111
1 files changed, 88 insertions, 23 deletions
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
index 303649705..17af36fe6 100644
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -7,7 +7,7 @@
*
* Adapted from linux/net/ipv4/raw.c
*
- * $Id: raw.c,v 1.12 1997/04/01 02:23:34 davem Exp $
+ * $Id: raw.c,v 1.13 1997/09/14 08:32:14 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -156,7 +156,7 @@ static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
/* Check if the address belongs to the host. */
if (addr_type == IPV6_ADDR_MAPPED) {
v4addr = addr->sin6_addr.s6_addr32[3];
- if (__ip_chk_addr(v4addr) != IS_MYADDR)
+ if (inet_addr_type(v4addr) != RTN_LOCAL)
return(-EADDRNOTAVAIL);
} else {
if (addr_type != IPV6_ADDR_ANY) {
@@ -307,8 +307,9 @@ static int rawv6_frag_cksum(const void *data, struct in6_addr *addr,
{
struct rawv6_fakehdr *hdr = (struct rawv6_fakehdr *) data;
- hdr->cksum = csum_partial_copy_fromiovecend(buff, hdr->iov, offset,
- len, hdr->cksum);
+ if (csum_partial_copy_fromiovecend(buff, hdr->iov, offset,
+ len, &hdr->cksum))
+ return -EFAULT;
if (offset == 0) {
struct sock *sk;
@@ -461,28 +462,49 @@ static int rawv6_sendmsg(struct sock *sk, struct msghdr *msg, int len)
static int rawv6_seticmpfilter(struct sock *sk, int level, int optname,
char *optval, int optlen)
{
- struct raw6_opt *opt = &sk->tp_pinfo.tp_raw;
- int err = 0;
+ switch (optname) {
+ case ICMPV6_FILTER:
+ if (optlen > sizeof(struct icmp6_filter))
+ optlen = sizeof(struct icmp6_filter);
+ if (copy_from_user(&sk->tp_pinfo.tp_raw.filter, optval, optlen))
+ return -EFAULT;
+ return 0;
+ default:
+ return -ENOPROTOOPT;
+ };
+
+ return 0;
+}
+
+static int rawv6_geticmpfilter(struct sock *sk, int level, int optname,
+ char *optval, int *optlen)
+{
+ int len;
switch (optname) {
- case ICMPV6_FILTER:
- err = copy_from_user(&opt->filter, optval,
- sizeof(struct icmp6_filter));
- if (err)
- err = -EFAULT;
- break;
- default:
- err = -ENOPROTOOPT;
+ case ICMPV6_FILTER:
+ if (get_user(len, optlen))
+ return -EFAULT;
+ if (len > sizeof(struct icmp6_filter))
+ len = sizeof(struct icmp6_filter);
+ if (put_user(len, optlen))
+ return -EFAULT;
+ if (copy_to_user(optval, &sk->tp_pinfo.tp_raw.filter, len))
+ return -EFAULT;
+ return 0;
+ default:
+ return -ENOPROTOOPT;
};
- return err;
+ return 0;
}
+
static int rawv6_setsockopt(struct sock *sk, int level, int optname,
char *optval, int optlen)
{
struct raw6_opt *opt = &sk->tp_pinfo.tp_raw;
- int val, err;
+ int val;
switch(level) {
case SOL_RAW:
@@ -501,12 +523,8 @@ static int rawv6_setsockopt(struct sock *sk, int level, int optname,
optlen);
};
- if (optval == NULL)
- return(-EINVAL);
-
- err = get_user(val, (int *)optval);
- if(err)
- return err;
+ if (get_user(val, (int *)optval))
+ return -EFAULT;
switch (optname) {
case IPV6_CHECKSUM:
@@ -525,6 +543,53 @@ static int rawv6_setsockopt(struct sock *sk, int level, int optname,
}
}
+static int rawv6_getsockopt(struct sock *sk, int level, int optname,
+ char *optval, int *optlen)
+{
+ struct raw6_opt *opt = &sk->tp_pinfo.tp_raw;
+ int val, len;
+
+ switch(level) {
+ case SOL_RAW:
+ break;
+
+ case SOL_ICMPV6:
+ if (sk->num != IPPROTO_ICMPV6)
+ return -EOPNOTSUPP;
+ return rawv6_geticmpfilter(sk, level, optname, optval,
+ optlen);
+ case SOL_IPV6:
+ if (optname == IPV6_CHECKSUM)
+ break;
+ default:
+ return ipv6_getsockopt(sk, level, optname, optval,
+ optlen);
+ };
+
+ if (get_user(len,optlen))
+ return -EFAULT;
+
+ switch (optname) {
+ case IPV6_CHECKSUM:
+ if (opt->checksum == 0)
+ val = -1;
+ else
+ val = opt->offset;
+
+ default:
+ return -ENOPROTOOPT;
+ }
+
+ len=min(sizeof(int),len);
+
+ if (put_user(len, optlen))
+ return -EFAULT;
+ if (copy_to_user(optval,&val,len))
+ return -EFAULT;
+ return 0;
+}
+
+
static void rawv6_close(struct sock *sk, unsigned long timeout)
{
struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
@@ -558,7 +623,7 @@ struct proto rawv6_prot = {
NULL, /* destroy */
NULL, /* shutdown */
rawv6_setsockopt, /* setsockopt */
- ipv6_getsockopt, /* getsockopt - FIXME */
+ rawv6_getsockopt, /* getsockopt */
rawv6_sendmsg, /* sendmsg */
rawv6_recvmsg, /* recvmsg */
rawv6_bind, /* bind */