* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $Id: ip6_output.c,v 1.34 2002/02/01 22:01:04 davem Exp $
- *
* Based on linux/net/ipv4/ip_output.c
*
* This program is free software; you can redistribute it and/or
#include <net/icmp.h>
#include <net/xfrm.h>
#include <net/checksum.h>
+#include <linux/mroute6.h>
static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *));
struct inet6_dev *idev = ip6_dst_idev(skb->dst);
if (!(dev->flags & IFF_LOOPBACK) && (!np || np->mc_loop) &&
- ipv6_chk_mcast_addr(dev, &ipv6_hdr(skb)->daddr,
- &ipv6_hdr(skb)->saddr)) {
+ ((mroute6_socket && !(IP6CB(skb)->flags & IP6SKB_FORWARDED)) ||
+ ipv6_chk_mcast_addr(dev, &ipv6_hdr(skb)->daddr,
+ &ipv6_hdr(skb)->saddr))) {
struct sk_buff *newskb = skb_clone(skb, GFP_ATOMIC);
/* Do not check for IFF_ALLMULTI; multicast routing
int ip6_output(struct sk_buff *skb)
{
+ struct inet6_dev *idev = ip6_dst_idev(skb->dst);
+ if (unlikely(idev->cnf.disable_ipv6)) {
+ IP6_INC_STATS(idev, IPSTATS_MIB_OUTDISCARDS);
+ kfree_skb(skb);
+ return 0;
+ }
+
if ((skb->len > ip6_skb_dst_mtu(skb) && !skb_is_gso(skb)) ||
dst_allfrag(skb->dst))
return ip6_fragment(skb, ip6_output2);
if (np)
hlimit = np->hop_limit;
if (hlimit < 0)
- hlimit = dst_metric(dst, RTAX_HOPLIMIT);
- if (hlimit < 0)
- hlimit = ipv6_get_hoplimit(dst->dev);
+ hlimit = ip6_dst_hoplimit(dst);
tclass = -1;
if (np)
*/
int ip6_nd_hdr(struct sock *sk, struct sk_buff *skb, struct net_device *dev,
- struct in6_addr *saddr, struct in6_addr *daddr,
+ const struct in6_addr *saddr, const struct in6_addr *daddr,
int proto, int len)
{
struct ipv6_pinfo *np = inet6_sk(sk);
struct dst_entry *dst = skb->dst;
struct ipv6hdr *hdr = ipv6_hdr(skb);
struct inet6_skb_parm *opt = IP6CB(skb);
- struct net *net = dst->dev->nd_net;
+ struct net *net = dev_net(dst->dev);
- if (ipv6_devconf.forwarding == 0)
+ if (net->ipv6.devconf_all->forwarding == 0)
goto error;
+ if (skb_warn_if_lro(skb))
+ goto drop;
+
if (!xfrm6_policy_check(NULL, XFRM_POLICY_FWD, skb)) {
IP6_INC_STATS(ip6_dst_idev(dst), IPSTATS_MIB_INDISCARDS);
goto drop;
}
/* XXX: idev->cnf.proxy_ndp? */
- if (ipv6_devconf.proxy_ndp &&
+ if (net->ipv6.devconf_all->proxy_ndp &&
pneigh_lookup(&nd_tbl, net, &hdr->daddr, skb->dev, 0)) {
int proxied = ip6_forward_proxy_check(skb);
if (proxied > 0)
int addrtype = ipv6_addr_type(&hdr->saddr);
/* This check is security critical. */
- if (addrtype & (IPV6_ADDR_MULTICAST|IPV6_ADDR_LOOPBACK))
+ if (addrtype == IPV6_ADDR_ANY ||
+ addrtype & (IPV6_ADDR_MULTICAST | IPV6_ADDR_LOOPBACK))
goto error;
if (addrtype & IPV6_ADDR_LINKLOCAL) {
icmpv6_send(skb, ICMPV6_DEST_UNREACH,
* Allocate buffer.
*/
- if ((frag = alloc_skb(len+hlen+sizeof(struct frag_hdr)+LL_RESERVED_SPACE(rt->u.dst.dev), GFP_ATOMIC)) == NULL) {
+ if ((frag = alloc_skb(len+hlen+sizeof(struct frag_hdr)+LL_ALLOCATED_SPACE(rt->u.dst.dev), GFP_ATOMIC)) == NULL) {
NETDEBUG(KERN_INFO "IPv6: frag: no memory for new fragment!\n");
IP6_INC_STATS(ip6_dst_idev(skb->dst),
IPSTATS_MIB_FRAGFAILS);
struct dst_entry **dst, struct flowi *fl)
{
int err;
- struct net *net = sk->sk_net;
+ struct net *net = sock_net(sk);
if (*dst == NULL)
*dst = ip6_route_output(net, sk, fl);
if (ipv6_addr_any(&fl->fl6_src)) {
err = ipv6_dev_get_saddr(ip6_dst_idev(*dst)->dev,
- &fl->fl6_dst, &fl->fl6_src);
+ &fl->fl6_dst,
+ sk ? inet6_sk(sk)->srcprefs : 0,
+ &fl->fl6_src);
if (err)
goto out_err_release;
}
/* need source address above miyazawa*/
}
dst_hold(&rt->u.dst);
- np->cork.rt = rt;
+ inet->cork.dst = &rt->u.dst;
inet->cork.fl = *fl;
np->cork.hop_limit = hlimit;
np->cork.tclass = tclass;
length += exthdrlen;
transhdrlen += exthdrlen;
} else {
- rt = np->cork.rt;
+ rt = (struct rt6_info *)inet->cork.dst;
fl = &inet->cork.fl;
if (inet->cork.flags & IPCORK_OPT)
opt = np->cork.opt;
inet->cork.flags &= ~IPCORK_OPT;
kfree(np->cork.opt);
np->cork.opt = NULL;
- if (np->cork.rt) {
- dst_release(&np->cork.rt->u.dst);
- np->cork.rt = NULL;
+ if (inet->cork.dst) {
+ dst_release(inet->cork.dst);
+ inet->cork.dst = NULL;
inet->cork.flags &= ~IPCORK_ALLFRAG;
}
memset(&inet->cork.fl, 0, sizeof(inet->cork.fl));
struct ipv6_pinfo *np = inet6_sk(sk);
struct ipv6hdr *hdr;
struct ipv6_txoptions *opt = np->cork.opt;
- struct rt6_info *rt = np->cork.rt;
+ struct rt6_info *rt = (struct rt6_info *)inet->cork.dst;
struct flowi *fl = &inet->cork.fl;
unsigned char proto = fl->proto;
int err = 0;