#include <asm/uaccess.h>
#include <asm/ioctls.h>
+#include <net/net_namespace.h>
#include <net/ip.h>
#include <net/sock.h>
#include <net/snmp.h>
#include <net/udp.h>
#include <net/inet_common.h>
#include <net/tcp_states.h>
-#ifdef CONFIG_IPV6_MIP6
+#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
#include <net/mip6.h>
#endif
return 0;
}
+#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
+static int (*mh_filter)(struct sock *sock, struct sk_buff *skb);
+
+int rawv6_mh_filter_register(int (*filter)(struct sock *sock,
+ struct sk_buff *skb))
+{
+ rcu_assign_pointer(mh_filter, filter);
+ return 0;
+}
+EXPORT_SYMBOL(rawv6_mh_filter_register);
+
+int rawv6_mh_filter_unregister(int (*filter)(struct sock *sock,
+ struct sk_buff *skb))
+{
+ rcu_assign_pointer(mh_filter, NULL);
+ synchronize_rcu();
+ return 0;
+}
+EXPORT_SYMBOL(rawv6_mh_filter_unregister);
+
+#endif
+
/*
* demultiplex raw sockets.
* (should consider queueing the skb in the sock receive_queue
int delivered = 0;
__u8 hash;
- saddr = &skb->nh.ipv6h->saddr;
+ saddr = &ipv6_hdr(skb)->saddr;
daddr = saddr + 1;
hash = nexthdr & (MAX_INET_PROTOS - 1);
case IPPROTO_ICMPV6:
filtered = icmpv6_filter(sk, skb);
break;
-#ifdef CONFIG_IPV6_MIP6
+
+#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
case IPPROTO_MH:
+ {
/* XXX: To validate MH only once for each packet,
* this is placed here. It should be after checking
* xfrm policy, however it doesn't. The checking xfrm
* policy is placed in rawv6_rcv() because it is
* required for each socket.
*/
- filtered = mip6_mh_filter(sk, skb);
+ int (*filter)(struct sock *sock, struct sk_buff *skb);
+
+ filter = rcu_dereference(mh_filter);
+ filtered = filter ? filter(sk, skb) : 0;
break;
+ }
#endif
default:
filtered = 0;
if (!sk->sk_bound_dev_if)
goto out;
- dev = dev_get_by_index(sk->sk_bound_dev_if);
+ dev = dev_get_by_index(&init_net, sk->sk_bound_dev_if);
if (!dev) {
err = -ENODEV;
goto out;
{
if ((raw6_sk(sk)->checksum || sk->sk_filter) &&
skb_checksum_complete(skb)) {
- /* FIXME: increment a raw6 drops counter here */
+ atomic_inc(&sk->sk_drops);
kfree_skb(skb);
return 0;
}
/* Charge it to the socket. */
if (sock_queue_rcv_skb(sk,skb)<0) {
- /* FIXME: increment a raw6 drops counter here */
+ atomic_inc(&sk->sk_drops);
kfree_skb(skb);
return 0;
}
struct raw6_sock *rp = raw6_sk(sk);
if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) {
+ atomic_inc(&sk->sk_drops);
kfree_skb(skb);
return NET_RX_DROP;
}
if (skb->ip_summed == CHECKSUM_COMPLETE) {
skb_postpull_rcsum(skb, skb_network_header(skb),
- skb->h.raw - skb->nh.raw);
- if (!csum_ipv6_magic(&skb->nh.ipv6h->saddr,
- &skb->nh.ipv6h->daddr,
+ skb_network_header_len(skb));
+ if (!csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
+ &ipv6_hdr(skb)->daddr,
skb->len, inet->num, skb->csum))
skb->ip_summed = CHECKSUM_UNNECESSARY;
}
- if (skb->ip_summed != CHECKSUM_UNNECESSARY)
- skb->csum = ~csum_unfold(csum_ipv6_magic(&skb->nh.ipv6h->saddr,
- &skb->nh.ipv6h->daddr,
- skb->len, inet->num, 0));
+ if (!skb_csum_unnecessary(skb))
+ skb->csum = ~csum_unfold(csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
+ &ipv6_hdr(skb)->daddr,
+ skb->len,
+ inet->num, 0));
if (inet->hdrincl) {
if (skb_checksum_complete(skb)) {
- /* FIXME: increment a raw6 drops counter here */
+ atomic_inc(&sk->sk_drops);
kfree_skb(skb);
return 0;
}
msg->msg_flags |= MSG_TRUNC;
}
- if (skb->ip_summed==CHECKSUM_UNNECESSARY) {
+ if (skb_csum_unnecessary(skb)) {
err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
} else if (msg->msg_flags&MSG_TRUNC) {
if (__skb_checksum_complete(skb))
if (sin6) {
sin6->sin6_family = AF_INET6;
sin6->sin6_port = 0;
- ipv6_addr_copy(&sin6->sin6_addr, &skb->nh.ipv6h->saddr);
+ ipv6_addr_copy(&sin6->sin6_addr, &ipv6_hdr(skb)->saddr);
sin6->sin6_flowinfo = 0;
sin6->sin6_scope_id = 0;
if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL)
as some normal condition.
*/
err = (flags&MSG_DONTWAIT) ? -EAGAIN : -EHOSTUNREACH;
- /* FIXME: increment a raw6 drops counter here */
+ atomic_inc(&sk->sk_drops);
goto out;
}
if (csum_skb)
continue;
- len = skb->len - (skb->h.raw - skb->data);
+ len = skb->len - skb_transport_offset(skb);
if (offset >= len) {
offset -= len;
continue;
skb = csum_skb;
}
- offset += skb->h.raw - skb->data;
+ offset += skb_transport_offset(skb);
if (skb_copy_bits(skb, offset, &csum, 2))
BUG();
skb_put(skb, length);
skb_reset_network_header(skb);
- iph = skb->nh.ipv6h;
+ iph = ipv6_hdr(skb);
skb->ip_summed = CHECKSUM_NONE;
- skb->h.raw = skb->nh.raw;
+ skb->transport_header = skb->network_header;
err = memcpy_fromiovecend((void *)iph, from, 0, length);
if (err)
goto error_fault;
IP6_INC_STATS(rt->rt6i_idev, IPSTATS_MIB_OUTREQUESTS);
- err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, rt->u.dst.dev,
+ err = NF_HOOK(PF_INET6, NF_INET_LOCAL_OUT, skb, NULL, rt->u.dst.dev,
dst_output);
if (err > 0)
err = np->recverr ? net_xmit_errno(err) : 0;
struct iovec *iov;
u8 __user *type = NULL;
u8 __user *code = NULL;
-#ifdef CONFIG_IPV6_MIP6
u8 len = 0;
-#endif
int probed = 0;
int i;
probed = 1;
}
break;
-#ifdef CONFIG_IPV6_MIP6
case IPPROTO_MH:
if (iov->iov_base && iov->iov_len < 1)
break;
len += iov->iov_len;
break;
-#endif
default:
probed = 1;
break;
if (final_p)
ipv6_addr_copy(&fl.fl6_dst, final_p);
- if ((err = xfrm_lookup(&dst, &fl, sk, 1)) < 0)
- goto out;
+ if ((err = __xfrm_lookup(&dst, &fl, sk, 1)) < 0) {
+ if (err == -EREMOTE)
+ err = ip6_dst_blackhole(sk, &dst, &fl);
+ if (err < 0)
+ goto out;
+ }
if (hlimit < 0) {
if (ipv6_addr_is_multicast(&fl.fl6_dst))
ip6_flush_pending_frames(sk);
else if (!(msg->msg_flags & MSG_MORE))
err = rawv6_push_pending_frames(sk, &fl, rp);
+ release_sock(sk);
}
done:
dst_release(dst);
- if (!inet->hdrincl)
- release_sock(sk);
out:
fl6_sock_release(flowlabel);
return err<0?err:len;
return 0;
default:
return -ENOPROTOOPT;
- };
+ }
return 0;
}
return 0;
default:
return -ENOPROTOOPT;
- };
+ }
return 0;
}
default:
return ipv6_setsockopt(sk, level, optname, optval,
optlen);
- };
+ }
+
return do_rawv6_setsockopt(sk, level, optname, optval, optlen);
}
default:
return compat_ipv6_setsockopt(sk, level, optname,
optval, optlen);
- };
+ }
return do_rawv6_setsockopt(sk, level, optname, optval, optlen);
}
#endif
default:
return ipv6_getsockopt(sk, level, optname, optval,
optlen);
- };
+ }
+
return do_rawv6_getsockopt(sk, level, optname, optval, optlen);
}
default:
return compat_ipv6_getsockopt(sk, level, optname,
optval, optlen);
- };
+ }
return do_rawv6_getsockopt(sk, level, optname, optval, optlen);
}
#endif
spin_lock_bh(&sk->sk_receive_queue.lock);
skb = skb_peek(&sk->sk_receive_queue);
if (skb != NULL)
- amount = skb->tail - skb->h.raw;
+ amount = skb->tail - skb->transport_header;
spin_unlock_bh(&sk->sk_receive_queue.lock);
return put_user(amount, (int __user *)arg);
}
return(0);
}
+DEFINE_PROTO_INUSE(rawv6)
+
struct proto rawv6_prot = {
.name = "RAWv6",
.owner = THIS_MODULE,
.compat_setsockopt = compat_rawv6_setsockopt,
.compat_getsockopt = compat_rawv6_getsockopt,
#endif
+ REF_PROTO_INUSE(rawv6)
};
#ifdef CONFIG_PROC_FS
srcp = inet_sk(sp)->num;
seq_printf(seq,
"%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
- "%02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p\n",
+ "%02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %d\n",
i,
src->s6_addr32[0], src->s6_addr32[1],
src->s6_addr32[2], src->s6_addr32[3], srcp,
0, 0L, 0,
sock_i_uid(sp), 0,
sock_i_ino(sp),
- atomic_read(&sp->sk_refcnt), sp);
+ atomic_read(&sp->sk_refcnt), sp, atomic_read(&sp->sk_drops));
}
static int raw6_seq_show(struct seq_file *seq, void *v)
"local_address "
"remote_address "
"st tx_queue rx_queue tr tm->when retrnsmt"
- " uid timeout inode\n");
+ " uid timeout inode drops\n");
else
raw6_sock_seq_show(seq, v, raw6_seq_private(seq)->bucket);
return 0;
}
-static struct seq_operations raw6_seq_ops = {
+static const struct seq_operations raw6_seq_ops = {
.start = raw6_seq_start,
.next = raw6_seq_next,
.stop = raw6_seq_stop,
static int raw6_seq_open(struct inode *inode, struct file *file)
{
- struct seq_file *seq;
- int rc = -ENOMEM;
- struct raw6_iter_state *s = kzalloc(sizeof(*s), GFP_KERNEL);
- if (!s)
- goto out;
- rc = seq_open(file, &raw6_seq_ops);
- if (rc)
- goto out_kfree;
- seq = file->private_data;
- seq->private = s;
-out:
- return rc;
-out_kfree:
- kfree(s);
- goto out;
+ return seq_open_private(file, &raw6_seq_ops,
+ sizeof(struct raw6_iter_state));
}
static const struct file_operations raw6_seq_fops = {
int __init raw6_proc_init(void)
{
- if (!proc_net_fops_create("raw6", S_IRUGO, &raw6_seq_fops))
+ if (!proc_net_fops_create(&init_net, "raw6", S_IRUGO, &raw6_seq_fops))
return -ENOMEM;
return 0;
}
void raw6_proc_exit(void)
{
- proc_net_remove("raw6");
+ proc_net_remove(&init_net, "raw6");
}
#endif /* CONFIG_PROC_FS */