#include <net/xfrm.h>
#include <linux/mroute.h>
#include <linux/netlink.h>
+#include <linux/sdt.h>
/*
* Process Router Attention IP option (RFC 2113)
*/
int ip_local_deliver(struct sk_buff *skb)
{
+ struct iphdr *iph = ip_hdr(skb);
+
/*
* Reassemble IP fragments.
*/
- if (ip_is_fragment(ip_hdr(skb))) {
+ if (ip_is_fragment(iph)) {
if (ip_defrag(skb, IP_DEFRAG_LOCAL_DELIVER))
return 0;
}
+ DTRACE_IP(receive,
+ struct sk_buff * : pktinfo_t *, skb,
+ struct sock * : csinfo_t *, skb->sk,
+ void_ip_t * : ipinfo_t *, iph,
+ struct net_device * : ifinfo_t *, skb->dev,
+ struct iphdr * : ipv4info_t *, iph,
+ struct ipv6hdr * : ipv6info_t *, NULL);
+
return NF_HOOK(NFPROTO_IPV4, NF_INET_LOCAL_IN, NULL, skb,
skb->dev, NULL,
ip_local_deliver_finish);
static inline bool ip_rcv_options(struct sk_buff *skb)
{
struct ip_options *opt;
- const struct iphdr *iph;
+ const struct iphdr *iph = NULL;
struct net_device *dev = skb->dev;
+ const char *dropreason;
/* It looks as overkill, because not all
IP options require packet mangling.
--ANK (980813)
*/
if (skb_cow(skb, skb_headroom(skb))) {
+ dropreason = "copy-on-write failed";
IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_INDISCARDS);
goto drop;
}
opt->optlen = iph->ihl*4 - sizeof(struct iphdr);
if (ip_options_compile(dev_net(dev), opt, skb)) {
+ dropreason = "invalid options";
IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_INHDRERRORS);
goto drop;
}
net_info_ratelimited("source route option %pI4 -> %pI4\n",
&iph->saddr,
&iph->daddr);
+ dropreason = "invalid source route options";
goto drop;
}
}
- if (ip_options_rcv_srr(skb))
+ if (ip_options_rcv_srr(skb)) {
+ dropreason = "invalid options";
goto drop;
+ }
}
return false;
drop:
+ DTRACE_IP(drop__in,
+ struct sk_buff * : pktinfo_t *, skb,
+ struct sock * : csinfo_t *, skb->sk,
+ void_ip_t * : ipinfo_t *, iph,
+ struct net_device * : ifinfo_t *, skb->dev,
+ struct iphdr * : ipv4info_t *, iph,
+ struct ipv6hdr * : ipv6info_t *, NULL,
+ char * : string, dropreason);
+
return true;
}
*/
int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
{
- const struct iphdr *iph;
+ const struct iphdr *iph = NULL;
u32 len;
+ const char *dropreason = "header invalid";
/* When the interface is in promisc. mode, drop all the crap
* that it receives, do not try to analyse it.
skb = skb_share_check(skb, GFP_ATOMIC);
if (!skb) {
+ dropreason = "could not clone shared buffer";
IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_INDISCARDS);
- goto out;
+ goto drop;
}
if (!pskb_may_pull(skb, sizeof(struct iphdr)))
len = ntohs(iph->tot_len);
if (skb->len < len) {
+ dropreason = "packet too short";
IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_INTRUNCATEDPKTS);
goto drop;
} else if (len < (iph->ihl*4))
* Note this now means skb->len holds ntohs(iph->tot_len).
*/
if (pskb_trim_rcsum(skb, len)) {
+ dropreason = "could not trim buffer";
IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_INDISCARDS);
goto drop;
}
csum_error:
IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_CSUMERRORS);
+ dropreason = "checksum error";
inhdr_error:
IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_INHDRERRORS);
+
drop:
+ DTRACE_IP(drop__in,
+ struct sk_buff * : pktinfo_t *, skb,
+ struct sock * : csinfo_t *, skb ? skb->sk : NULL,
+ void_ip_t * : ipinfo_t *, iph,
+ struct net_device * : ifinfo_t *, dev,
+ struct iphdr * : ipv4info_t *, iph,
+ void * : ipv6info_t *, NULL,
+ char * : string, dropreason);
+
kfree_skb(skb);
-out:
return NET_RX_DROP;
}
#include <linux/mroute.h>
#include <linux/netlink.h>
#include <linux/tcp.h>
+#include <linux/sdt.h>
int sysctl_ip_default_ttl __read_mostly = IPDEFTTL;
EXPORT_SYMBOL(sysctl_ip_default_ttl);
iph->tot_len = htons(skb->len);
ip_send_check(iph);
+
+ DTRACE_IP(send,
+ struct sk_buff * : pktinfo_t *, skb,
+ struct sock * : csinfo_t *, sk,
+ void_ip_t * : ipinfo_t *, iph,
+ struct net_device * : ifinfo_t *, skb->dev,
+ struct iphdr * : ipv4info_t *, iph,
+ struct ipv6hdr * : ipv6info_t *, NULL);
+
return nf_hook(NFPROTO_IPV4, NF_INET_LOCAL_OUT, sk, skb, NULL,
skb_dst(skb)->dev, dst_output_sk);
}
int csummode = CHECKSUM_NONE;
struct rtable *rt = (struct rtable *)cork->dst;
u32 tskey = 0;
+ const char *dropreason;
skb = skb_peek_tail(queue);
maxnonfragsize = ip_sk_ignore_df(sk) ? 0xFFFF : mtu;
if (cork->length + length > maxnonfragsize - fragheaderlen) {
+ struct iphdr *iph = ip_hdr(skb);
+
ip_local_error(sk, EMSGSIZE, fl4->daddr, inet->inet_dport,
mtu - (opt ? opt->optlen : 0));
- return -EMSGSIZE;
+ dropreason = "packet too big";
+ err = -EMSGSIZE;
+ goto error2;
}
/*
err = ip_ufo_append_data(sk, queue, getfrag, from, length,
hh_len, fragheaderlen, transhdrlen,
maxfraglen, flags);
- if (err)
+ if (err) {
+ dropreason = "could not offload UDP fragmentation";
goto error;
+ }
return 0;
}
skb = sock_wmalloc(sk,
alloclen + hh_len + 15, 1,
sk->sk_allocation);
- if (unlikely(!skb))
+ if (unlikely(!skb)) {
+ dropreason = "no buffers";
err = -ENOBUFS;
+ }
}
if (!skb)
goto error;
copy = datalen - transhdrlen - fraggap;
if (copy > 0 && getfrag(from, data + transhdrlen, offset, copy, fraggap, skb) < 0) {
err = -EFAULT;
+ dropreason = "could not fragment packet";
kfree_skb(skb);
+ skb = NULL;
goto error;
}
if (getfrag(from, skb_put(skb, copy),
offset, copy, off, skb) < 0) {
__skb_trim(skb, off);
+ dropreason = "could not fragment packet";
err = -EFAULT;
goto error;
}
int i = skb_shinfo(skb)->nr_frags;
err = -ENOMEM;
- if (!sk_page_frag_refill(sk, pfrag))
+ if (!sk_page_frag_refill(sk, pfrag)) {
+ dropreason = "no memory";
goto error;
+ }
if (!skb_can_coalesce(skb, i, pfrag->page,
pfrag->offset)) {
err = -EMSGSIZE;
- if (i == MAX_SKB_FRAGS)
+ if (i == MAX_SKB_FRAGS) {
+ dropreason = "too many fragments";
goto error;
+ }
__skb_fill_page_desc(skb, i, pfrag->page,
pfrag->offset, 0);
copy = min_t(int, copy, pfrag->size - pfrag->offset);
if (getfrag(from,
page_address(pfrag->page) + pfrag->offset,
- offset, copy, skb->len, skb) < 0)
+ offset, copy, skb->len, skb) < 0) {
+ dropreason = "could not framgent packet";
goto error_efault;
+ }
pfrag->offset += copy;
skb_frag_size_add(&skb_shinfo(skb)->frags[i - 1], copy);
error:
cork->length -= length;
IP_INC_STATS(sock_net(sk), IPSTATS_MIB_OUTDISCARDS);
+error2:
+ DTRACE_IP(drop__out,
+ struct sk_buff * : pktinfo_t *, skb,
+ struct sock * : csinfo_t *, skb ? skb->sk : NULL,
+ void_ip_t * : ipinfo_t *, skb ? ip_hdr(skb) : NULL,
+ struct net_device * : ifinfo_t *, skb ? skb->dev : NULL,
+ struct iphdr * : ipv4info_t *, skb ? ip_hdr(skb) : NULL,
+ struct ipv6hdr * : ipv6info_t *, NULL,
+ char * : string, dropreason);
+
return err;
}
int len;
int err;
unsigned int maxfraglen, fragheaderlen, fraggap, maxnonfragsize;
+ struct iphdr *iph;
+ const char *dropreason;
if (inet->hdrincl)
return -EPERM;
alloclen = fragheaderlen + hh_len + fraggap + 15;
skb = sock_wmalloc(sk, alloclen, 1, sk->sk_allocation);
if (unlikely(!skb)) {
+ dropreason = "no buffers";
err = -ENOBUFS;
goto error;
}
get_page(page);
skb_fill_page_desc(skb, i, page, offset, len);
} else {
+ dropreason = "packet too big";
err = -EMSGSIZE;
goto error;
}
error:
cork->length -= size;
IP_INC_STATS(sock_net(sk), IPSTATS_MIB_OUTDISCARDS);
+ iph = skb ? ip_hdr(skb) : NULL;
+ DTRACE_IP(drop__out,
+ struct sk_buff * : pktinfo_t *, skb,
+ struct sock * : csinfo_t *, skb ? skb->sk : NULL,
+ void_ip_t * : ipinfo_t *, iph,
+ struct net_device * : ifinfo_t *, skb ? skb->dev : NULL,
+ struct iphdr * : ipv4info_t *, iph,
+ struct ipv6hdr * : ipv6info_t *, NULL,
+ char * : string, dropreason);
+
return err;
}
if (err) {
if (err > 0)
err = net_xmit_errno(err);
- if (err)
+ if (err) {
+ struct iphdr *iph = ip_hdr(skb);
+
IP_INC_STATS(net, IPSTATS_MIB_OUTDISCARDS);
+ DTRACE_IP(drop__out,
+ struct sk_buff * : pktinfo_t *, skb,
+ struct sock * : csinfo_t *, skb->sk,
+ void_ip_t * : ipinfo_t *, iph,
+ struct net_device * : ifinfo_t *, skb->dev,
+ struct iphdr * : ipv4info_t *, iph,
+ struct ipv6hdr * : ipv6info_t *, NULL,
+ char * : string, "packet too short");
+ }
+
+
}
return err;
#include <linux/netfilter_ipv4.h>
#include <linux/compat.h>
#include <linux/uio.h>
+#include <linux/sdt.h>
struct raw_frag_vec {
struct msghdr *msg;
icmp_out_count(net, ((struct icmphdr *)
skb_transport_header(skb))->type);
+ DTRACE_IP(send,
+ struct sk_buff * : pktinfo_t *, skb,
+ struct sock * : csinfo_t *, sk,
+ void_ip_t * : ipinfo_t *, iph,
+ struct net_device * : ifinfo_t *, skb->dev,
+ struct iphdr * : ipv4info_t *, iph,
+ struct ipv6hdr * : ipv6info_t *, NULL);
+
err = NF_HOOK(NFPROTO_IPV4, NF_INET_LOCAL_OUT, sk, skb,
NULL, rt->dst.dev, dst_output_sk);
if (err > 0)
#include <net/addrconf.h>
#include <net/xfrm.h>
#include <net/inet_ecn.h>
+#include <linux/sdt.h>
int ip6_rcv_finish(struct sock *sk, struct sk_buff *skb)
{
int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
{
- const struct ipv6hdr *hdr;
+ const struct ipv6hdr *hdr = NULL;
u32 pkt_len;
struct inet6_dev *idev;
struct net *net = dev_net(skb->dev);
+ const char *dropreason = "header invalid";
if (skb->pkt_type == PACKET_OTHERHOST) {
kfree_skb(skb);
if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL ||
!idev || unlikely(idev->cnf.disable_ipv6)) {
IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_INDISCARDS);
+ dropreason = "could not clone shared buffer";
goto drop;
}
*/
IP6CB(skb)->iif = skb_dst(skb) ? ip6_dst_idev(skb_dst(skb))->dev->ifindex : dev->ifindex;
- if (unlikely(!pskb_may_pull(skb, sizeof(*hdr))))
+ if (unlikely(!pskb_may_pull(skb, sizeof(*hdr)))) {
+ hdr = ipv6_hdr(skb);
goto err;
+ }
hdr = ipv6_hdr(skb);
* of loopback must be dropped.
*/
if (!(dev->flags & IFF_LOOPBACK) &&
- ipv6_addr_loopback(&hdr->daddr))
+ ipv6_addr_loopback(&hdr->daddr)) {
+ dropreason = "loopback destination received on inteface";
goto err;
+ }
/* RFC4291 Errata ID: 3480
* Interface-Local scope spans only a single interface on a
if (!(skb->pkt_type == PACKET_LOOPBACK ||
dev->flags & IFF_LOOPBACK) &&
ipv6_addr_is_multicast(&hdr->daddr) &&
- IPV6_ADDR_MC_SCOPE(&hdr->daddr) == 1)
+ IPV6_ADDR_MC_SCOPE(&hdr->daddr) == 1) {
+ dropreason = "interface-local scope received from other node";
goto err;
+ }
/* RFC4291 2.7
* Nodes must not originate a packet to a multicast address whose scope
* must be silently dropped.
*/
if (ipv6_addr_is_multicast(&hdr->daddr) &&
- IPV6_ADDR_MC_SCOPE(&hdr->daddr) == 0)
+ IPV6_ADDR_MC_SCOPE(&hdr->daddr) == 0) {
+ dropreason =
+ "packet to multicast address with reserved scope 0";
goto err;
+ }
/*
* RFC4291 2.7
* Multicast addresses must not be used as source addresses in IPv6
* packets or appear in any Routing header.
*/
- if (ipv6_addr_is_multicast(&hdr->saddr))
+ if (ipv6_addr_is_multicast(&hdr->saddr)) {
+ dropreason = "multicast source address in IPv6 packet";
goto err;
+ }
skb->transport_header = skb->network_header + sizeof(*hdr);
IP6CB(skb)->nhoff = offsetof(struct ipv6hdr, nexthdr);
if (pkt_len + sizeof(struct ipv6hdr) > skb->len) {
IP6_INC_STATS_BH(net,
idev, IPSTATS_MIB_INTRUNCATEDPKTS);
+ dropreason = "packet too short";
goto drop;
}
if (pskb_trim_rcsum(skb, pkt_len + sizeof(struct ipv6hdr))) {
IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_INHDRERRORS);
+ dropreason = "could not trim buffer";
goto drop;
}
hdr = ipv6_hdr(skb);
err:
IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_INHDRERRORS);
drop:
+ DTRACE_IP(drop__in,
+ struct sk_buff * : pktinfo_t *, skb,
+ struct sock * : csinfo_t *, skb ? skb->sk : NULL,
+ void_ip_t * : ipinfo_t *, hdr,
+ struct net_device * : ifinfo_t *, skb ? skb->dev : NULL,
+ struct iphdr * : ipv4info_t *, NULL,
+ struct ipv6hdr * : ipv6info_t *, hdr,
+ char * : string, dropreason);
+
rcu_read_unlock();
kfree_skb(skb);
return NET_RX_DROP;
unsigned int nhoff;
int nexthdr;
bool raw;
+ struct ipv6hdr *hdr;
+ const char *dropreason = "header invalid";
/*
* Parse extension headers
if (ipv6_addr_is_multicast(&hdr->daddr) &&
!ipv6_chk_mcast_addr(skb->dev, &hdr->daddr,
&hdr->saddr) &&
- !ipv6_is_mld(skb, nexthdr, skb_network_header_len(skb)))
+ !ipv6_is_mld(skb, nexthdr, skb_network_header_len(skb))) {
+ dropreason = "destination is multicast";
goto discard;
+ }
}
if (!(ipprot->flags & INET6_PROTO_NOPOLICY) &&
- !xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb))
+ !xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) {
+ dropreason = "policy failure";
goto discard;
+ }
ret = ipprot->handler(skb);
if (ret > 0)
discard:
IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_INDISCARDS);
+
+ hdr = ipv6_hdr(skb);
+ DTRACE_IP(drop__in,
+ struct sk_buff * : pktinfo_t *, skb,
+ struct sock * : csinfo_t *, skb->sk,
+ void_ip_t * : ipinfo_t *, hdr,
+ struct net_device * : ifinfo_t *, skb->dev,
+ struct iphdr * : ipv4info_t *, NULL,
+ struct ipv6hdr * : ipv6info_t *, hdr,
+ char * : string, dropreason);
+
rcu_read_unlock();
kfree_skb(skb);
return 0;
int ip6_input(struct sk_buff *skb)
{
+ struct ipv6hdr *hdr = ipv6_hdr(skb);
+
+ DTRACE_IP(receive,
+ struct sk_buff * : pktinfo_t *, skb,
+ struct sock * : csinfo_t *, skb->sk,
+ void_ip_t * : ipinfo_t *, hdr,
+ struct net_device * : ifinfo_t *, skb->dev,
+ struct iphdr * : ipv4info_t *, NULL,
+ struct ipv6hdr * : ipv6info_t *, hdr);
+
return NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_IN, NULL, skb,
skb->dev, NULL,
ip6_input_finish);
#include <net/xfrm.h>
#include <net/checksum.h>
#include <linux/mroute6.h>
+#include <linux/sdt.h>
static int ip6_finish_output2(struct sock *sk, struct sk_buff *skb)
{
dev_loopback_xmit);
if (ipv6_hdr(skb)->hop_limit == 0) {
+ DTRACE_IP(drop__out,
+ struct sk_buff * : pktinfo_t *, skb,
+ struct sock * : csinfo_t *, skb->sk,
+ void_ip_t * : ipinfo_t *, ipv6_hdr(skb),
+ struct net_device * : ifinfo_t *, skb->dev,
+ struct iphdr * : ipv4info_t *, NULL,
+ struct ipv6hdr * : ipv6info_t *,
+ ipv6_hdr(skb),
+ char * : string, "hoplimit exceeded");
+
IP6_INC_STATS(dev_net(dev), idev,
IPSTATS_MIB_OUTDISCARDS);
kfree_skb(skb);
struct net_device *dev = skb_dst(skb)->dev;
struct inet6_dev *idev = ip6_dst_idev(skb_dst(skb));
if (unlikely(idev->cnf.disable_ipv6)) {
+ DTRACE_IP(drop__out,
+ struct sk_buff * : pktinfo_t *, skb,
+ struct sock * : csinfo_t *, skb->sk,
+ void_ip_t * : ipinfo_t *, NULL,
+ struct net_device * : ifinfo_t *, skb->dev,
+ struct iphdr * : ipv4info_t *, NULL,
+ struct ipv6hdr * : ipv6info_t *, NULL,
+ char * : string, "IPv6 is disabled");
+
IP6_INC_STATS(dev_net(dev), idev,
IPSTATS_MIB_OUTDISCARDS);
kfree_skb(skb);
if (skb_headroom(skb) < head_room) {
struct sk_buff *skb2 = skb_realloc_headroom(skb, head_room);
if (!skb2) {
+ DTRACE_IP(drop__out,
+ struct sk_buff * : pktinfo_t *, skb,
+ struct sock * : csinfo_t *, skb->sk,
+ void_ip_t * : ipinfo_t *, NULL,
+ struct net_device * : ifinfo_t *, skb->dev,
+ struct iphdr * : ipv4info_t *, NULL,
+ struct ipv6hdr * : ipv6info_t *, NULL,
+ char * : string, "out of memory");
+
IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
IPSTATS_MIB_OUTDISCARDS);
kfree_skb(skb);
if ((skb->len <= mtu) || skb->ignore_df || skb_is_gso(skb)) {
IP6_UPD_PO_STATS(net, ip6_dst_idev(skb_dst(skb)),
IPSTATS_MIB_OUT, skb->len);
+ DTRACE_IP(send,
+ struct sk_buff * : pktinfo_t *, skb,
+ struct sock * : csinfo_t *, skb->sk,
+ void_ip_t * : ipinfo_t *, hdr,
+ struct net_device * : ifinfo_t *, skb->dev,
+ struct iphdr *: ipv4info_t *, NULL,
+ struct ipv6hdr * : ipv6info_t *, hdr);
+
return NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, sk, skb,
NULL, dst->dev, dst_output_sk);
}
struct inet6_skb_parm *opt = IP6CB(skb);
struct net *net = dev_net(dst->dev);
u32 mtu;
+ const char *dropreason;
- if (net->ipv6.devconf_all->forwarding == 0)
+ if (net->ipv6.devconf_all->forwarding == 0) {
+ dropreason = "forwarding disabled";
goto error;
+ }
- if (skb->pkt_type != PACKET_HOST)
+ if (skb->pkt_type != PACKET_HOST) {
+ dropreason = "non-host packet type cannot be forwarded";
goto drop;
+ }
- if (unlikely(skb->sk))
+ if (unlikely(skb->sk)) {
+ dropreason = "socket found for packet to be forwarded";
goto drop;
+ }
- if (skb_warn_if_lro(skb))
+ if (skb_warn_if_lro(skb)) {
+ dropreason = "LRO warning";
goto drop;
+ }
if (!xfrm6_policy_check(NULL, XFRM_POLICY_FWD, skb)) {
IP6_INC_STATS_BH(net, ip6_dst_idev(dst),
IPSTATS_MIB_INDISCARDS);
+ dropreason = "forwarding disabled by policy";
goto drop;
}
if (hdr->hop_limit <= 1) {
/* Force OUTPUT device used as source address */
skb->dev = dst->dev;
+
+ DTRACE_IP(drop__out,
+ struct sk_buff * : pktinfo_t *, skb,
+ struct sock * : csinfo_t *, skb->sk,
+ void_ip_t * : ipinfo_t *, hdr,
+ struct net_device * : ifinfo_t *, skb->dev,
+ struct iphdr * : ipv4info_t *, NULL,
+ struct ipv6hdr * : ipv6info_t *, hdr,
+ char * : string, "hoplimit exceeded");
+
icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT, 0);
IP6_INC_STATS_BH(net, ip6_dst_idev(dst),
IPSTATS_MIB_INHDRERRORS);
if (proxied > 0)
return ip6_input(skb);
else if (proxied < 0) {
+ dropreason = "proxy router cannot forward";
+
IP6_INC_STATS_BH(net, ip6_dst_idev(dst),
IPSTATS_MIB_INDISCARDS);
goto drop;
if (!xfrm6_route_forward(skb)) {
IP6_INC_STATS_BH(net, ip6_dst_idev(dst),
IPSTATS_MIB_INDISCARDS);
+ dropreason = "forwarding disabled for destination";
goto drop;
}
dst = skb_dst(skb);
/* This check is security critical. */
if (addrtype == IPV6_ADDR_ANY ||
- addrtype & (IPV6_ADDR_MULTICAST | IPV6_ADDR_LOOPBACK))
+ addrtype & (IPV6_ADDR_MULTICAST | IPV6_ADDR_LOOPBACK)) {
+ dropreason = "invalid address type for forwarding";
goto error;
+ }
if (addrtype & IPV6_ADDR_LINKLOCAL) {
+ dropreason = "invalid address type for forwarding";
icmpv6_send(skb, ICMPV6_DEST_UNREACH,
ICMPV6_NOT_NEIGHBOUR, 0);
goto error;
if (ip6_pkt_too_big(skb, mtu)) {
/* Again, force OUTPUT device used as source address */
skb->dev = dst->dev;
+ DTRACE_IP(drop__out,
+ struct sk_buff * : pktinfo_t *, skb,
+ struct sock * : csinfo_t *, skb->sk,
+ void_ip_t * : ipinfo_t *, hdr,
+ struct net_device * : ifinfo_t *, skb->dev,
+ struct iphdr * : ipv4info_t *, NULL,
+ struct ipv6hdr * : ipv6info_t *, hdr,
+ char * : string, "packet too big");
+
icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
IP6_INC_STATS_BH(net, ip6_dst_idev(dst),
IPSTATS_MIB_INTOOBIGERRORS);
if (skb_cow(skb, dst->dev->hard_header_len)) {
IP6_INC_STATS_BH(net, ip6_dst_idev(dst),
IPSTATS_MIB_OUTDISCARDS);
+ dropreason = "copy-on-write failed";
goto drop;
}
error:
IP6_INC_STATS_BH(net, ip6_dst_idev(dst), IPSTATS_MIB_INADDRERRORS);
drop:
+ DTRACE_IP(drop__out,
+ struct sk_buff * : pktinfo_t *, skb,
+ struct sock * : csinfo_t *, skb->sk,
+ void_ip_t * : ipinfo_t *, hdr,
+ struct net_device * : ifinfo_t *, skb->dev,
+ struct iphdr * : ipv4info_t *, NULL,
+ struct ipv6hdr * : ipv6info_t *, hdr,
+ char * : string, dropreason);
+
kfree_skb(skb);
return -EINVAL;
}
struct rt6_info *rt = (struct rt6_info *)cork->dst;
struct ipv6_txoptions *opt = v6_cork->opt;
int csummode = CHECKSUM_NONE;
+ const char *dropreason;
skb = skb_peek_tail(queue);
if (!skb) {
sk->sk_protocol == IPPROTO_RAW)) {
ipv6_local_rxpmtu(sk, fl6, mtu - headersize +
sizeof(struct ipv6hdr));
+ dropreason = "fragmentation needed but disabled";
goto emsgsize;
}
ipv6_local_error(sk, EMSGSIZE, fl6,
mtu - headersize +
sizeof(struct ipv6hdr));
+ DTRACE_IP(drop__out,
+ struct sk_buff * : pktinfo_t *, skb,
+ struct sock * : csinfo_t *, skb->sk,
+ void_ip_t * : ipinfo_t *, NULL,
+ struct net_device * : ifinfo_t *, skb->dev,
+ struct iphdr * : ipv4info_t *, NULL,
+ struct ipv6hdr * : ipv6info_t *, NULL,
+ char * : string, "packet too big");
+
return -EMSGSIZE;
}
}
err = ip6_ufo_append_data(sk, queue, getfrag, from, length,
hh_len, fragheaderlen,
transhdrlen, mtu, flags, rt);
- if (err)
+ if (err) {
+ dropreason = "could not append data";
goto error;
+ }
return 0;
}
if (unlikely(!skb))
err = -ENOBUFS;
}
- if (!skb)
+ if (!skb) {
+ dropreason = "out of memory";
goto error;
+ }
+
/*
* Fill in the control structures
*/
if (copy < 0) {
err = -EINVAL;
kfree_skb(skb);
+ skb = NULL;
+ dropreason = "invalid header";
goto error;
} else if (copy > 0 && getfrag(from, data + transhdrlen, offset, copy, fraggap, skb) < 0) {
err = -EFAULT;
+ dropreason = "could not get fragment";
kfree_skb(skb);
+ skb = NULL;
goto error;
}
offset, copy, off, skb) < 0) {
__skb_trim(skb, off);
err = -EFAULT;
+ dropreason = "could not get fragment";
goto error;
}
} else {
int i = skb_shinfo(skb)->nr_frags;
err = -ENOMEM;
- if (!sk_page_frag_refill(sk, pfrag))
+ if (!sk_page_frag_refill(sk, pfrag)) {
+ dropreason = "out of memory";
goto error;
+ }
if (!skb_can_coalesce(skb, i, pfrag->page,
pfrag->offset)) {
err = -EMSGSIZE;
- if (i == MAX_SKB_FRAGS)
+ if (i == MAX_SKB_FRAGS) {
+ dropreason = "too many fragments";
goto error;
+ }
__skb_fill_page_desc(skb, i, pfrag->page,
pfrag->offset, 0);
copy = min_t(int, copy, pfrag->size - pfrag->offset);
if (getfrag(from,
page_address(pfrag->page) + pfrag->offset,
- offset, copy, skb->len, skb) < 0)
+ offset, copy, skb->len, skb) < 0) {
+ dropreason = "could not get fragment";
goto error_efault;
+ }
pfrag->offset += copy;
skb_frag_size_add(&skb_shinfo(skb)->frags[i - 1], copy);
error_efault:
err = -EFAULT;
error:
+ DTRACE_IP(drop__out,
+ struct sk_buff * : pktinfo_t *, skb,
+ struct sock * : csinfo_t *, skb ? skb->sk : NULL,
+ void_ip_t * : ipinfo_t *, NULL,
+ struct net_device * : ifinfo_t *, skb ? skb->dev : NULL,
+ struct iphdr * : ipv4info_t *, NULL,
+ struct ipv6hdr * : ipv6info_t *, NULL,
+ char * : string, dropreason);
+
cork->length -= length;
IP6_INC_STATS(sock_net(sk), rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS);
return err;
if (err) {
if (err > 0)
err = net_xmit_errno(err);
- if (err)
+ if (err) {
+ DTRACE_IP(drop__out,
+ struct sk_buff * : pktinfo_t *, skb,
+ struct sock * : csinfo_t *, skb->sk,
+ void_ip_t * : ipinfo_t *, ipv6_hdr(skb),
+ struct net_device * : ifinfo_t *, skb->dev,
+ struct iphdr * : ipv4info_t *, NULL,
+ struct ipv6hdr * : ipv6info_t *, ipv6_hdr(skb),
+ char * : string, "out of memory");
+
IP6_INC_STATS(net, rt->rt6i_idev,
IPSTATS_MIB_OUTDISCARDS);
+ }
}
return err;
struct sk_buff *skb;
while ((skb = __skb_dequeue_tail(queue)) != NULL) {
- if (skb_dst(skb))
+ if (skb_dst(skb)) {
+ DTRACE_IP(drop__out,
+ struct sk_buff * : pktinfo_t *, skb,
+ struct sock * : csinfo_t *, skb->sk,
+ void_ip_t * : ipinfo_t *, ipv6_hdr(skb),
+ struct net_device * : ifinfo_t *, skb->dev,
+ struct iphdr * : ipv4info_t *, NULL,
+ struct ipv6hdr * : ipv6info_t *,
+ ipv6_hdr(skb),
+ char * : string, "flushing pending frames");
IP6_INC_STATS(sock_net(sk), ip6_dst_idev(skb_dst(skb)),
IPSTATS_MIB_OUTDISCARDS);
+ }
kfree_skb(skb);
}
#include <net/ip6_checksum.h>
+#include <linux/sdt.h>
+
/* Ensure that we have struct in6_addr aligned on 32bit word. */
static void *__mld2_query_bugs[] __attribute__((__unused__)) = {
BUILD_BUG_ON_NULL(offsetof(struct mld2_query, mld2q_srcs) % 4),
dst = NULL;
}
skb_dst_set(skb, dst);
- if (err)
- goto err_out;
+ if (err) {
+ kfree_skb(skb);
+ skb = NULL;
+ goto out;
+ }
payload_len = skb->len;
+ DTRACE_IP(send,
+ struct sk_buff * : pktinfo_t *, skb,
+ struct sock * : csinfo_t *, skb->sk,
+ void_ip_t * : ipinfo_t *, ipv6_hdr(skb),
+ struct net_device * : ifinfo_t *, skb->dev,
+ struct iphdr *: ipv4info_t *, NULL,
+ struct ipv6hdr * : ipv6info_t *, ipv6_hdr(skb));
+
err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT,
net->ipv6.igmp_sk, skb, NULL, skb->dev,
dst_output_sk);
ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTMSGS);
IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUTMCAST, payload_len);
} else {
+ DTRACE_IP(drop__out,
+ struct sk_buff * : pktinfo_t *, skb,
+ struct sock * : csinfo_t *, skb ? skb->sk : NULL,
+ void_ip_t * : ipinfo_t *, skb ? ipv6_hdr(skb) : NULL,
+ struct net_device * : ifinfo_t *, skb ? skb->dev : NULL,
+ struct iphdr * : ipv4info_t *, NULL,
+ struct ipv6hdr * : ipv6info_t *, skb ? ipv6_hdr(skb) : NULL,
+ char * : string, "multicast send error");
+
IP6_INC_STATS(net, idev, IPSTATS_MIB_OUTDISCARDS);
}
rcu_read_unlock();
return;
-
-err_out:
- kfree_skb(skb);
- goto out;
}
static int grec_size(struct ifmcaddr6 *pmc, int type, int gdel, int sdel)
if (!skb) {
rcu_read_lock();
+ DTRACE_IP(drop__out,
+ struct sk_buff * : pktinfo_t *, NULL,
+ struct sock * : csinfo_t *, sk,
+ void_ip_t * : ipinfo_t *, NULL,
+ struct net_device * : ifinfo_t *, NULL,
+ struct iphdr * : ipv4info_t *, NULL,
+ struct ipv6hdr * : ipv6info_t *, NULL,
+ char * : string, "out of memory");
+
IP6_INC_STATS(net, __in6_dev_get(dev),
IPSTATS_MIB_OUTDISCARDS);
rcu_read_unlock();
dst = icmp6_dst_alloc(skb->dev, &fl6);
if (IS_ERR(dst)) {
err = PTR_ERR(dst);
- goto err_out;
+ kfree_skb(skb);
+ skb = NULL;
+ goto out;
}
skb_dst_set(skb, dst);
+
+ DTRACE_IP(send,
+ struct sk_buff * : pktinfo_t *, skb,
+ struct sock * : csinfo_t *, skb->sk,
+ void_ip_t * : ipinfo_t *, ipv6_hdr(skb),
+ struct net_device * : ifinfo_t *, skb->dev,
+ struct iphdr *: ipv4info_t *, NULL,
+ struct ipv6hdr * : ipv6info_t *, ipv6_hdr(skb));
+
err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, sk, skb,
NULL, skb->dev, dst_output_sk);
out:
ICMP6MSGOUT_INC_STATS(net, idev, type);
ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTMSGS);
IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUTMCAST, full_len);
- } else
+ } else {
+ DTRACE_IP(drop__out,
+ struct sk_buff * : pktinfo_t *, skb,
+ struct sock * : csinfo_t *, skb ? skb->sk : NULL,
+ void_ip_t * : ipinfo_t *, skb ? ipv6_hdr(skb) : NULL,
+ struct net_device * : ifinfo_t *, skb ? skb->dev : NULL,
+ struct iphdr * : ipv4info_t *, NULL,
+ struct ipv6hdr * : ipv6info_t *, skb ? ipv6_hdr(skb) : NULL,
+ char * : string, "multicast send error");
+
IP6_INC_STATS(net, idev, IPSTATS_MIB_OUTDISCARDS);
+ }
rcu_read_unlock();
return;
-
-err_out:
- kfree_skb(skb);
- goto out;
}
static void mld_send_initial_cr(struct inet6_dev *idev)
#include <linux/netfilter.h>
#include <linux/netfilter_ipv6.h>
+#include <linux/sdt.h>
/* Set to 3 to get tracing... */
#define ND_DEBUG 1
idev = __in6_dev_get(dst->dev);
IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len);
+ DTRACE_IP(send,
+ struct sk_buff * : pktinfo_t *, skb,
+ struct sock * : csinfo_t *, skb->sk,
+ void_ip_t * : ipinfo_t *, ipv6_hdr(skb),
+ struct net_device * : ifinfo_t *, skb->dev,
+ struct iphdr * : ipv4info_t *, NULL,
+ struct ipv6hdr * : ipv6info_t *, ipv6_hdr(skb));
+
err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, sk, skb,
NULL, dst->dev,
dst_output_sk);
#include <net/ip6_fib.h>
#include <net/addrconf.h>
#include <net/secure_seq.h>
+#include <linux/sdt.h>
static u32 __ipv6_select_ident(struct net *net, u32 hashrnd,
struct in6_addr *dst, struct in6_addr *src)
ipv6_hdr(skb)->payload_len = htons(len);
IP6CB(skb)->nhoff = offsetof(struct ipv6hdr, nexthdr);
+ DTRACE_IP(send,
+ struct sk_buff * : pktinfo_t *, skb,
+ struct sock * : csinfo_t *, skb->sk,
+ void_ip_t * : ipinfo_t *, ipv6_hdr(skb),
+ struct net_device * : ifinfo_t *, skb->dev,
+ struct iphdr *: ipv4info_t *, NULL,
+ struct ipv6hdr * : ipv6info_t *, ipv6_hdr(skb));
+
return nf_hook(NFPROTO_IPV6, NF_INET_LOCAL_OUT, sk, skb,
NULL, skb_dst(skb)->dev, dst_output_sk);
}
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/export.h>
+#include <linux/sdt.h>
#define ICMPV6_HDRLEN 4 /* ICMPv6 header, RFC 4443 Section 2.1 */
goto error_fault;
IP6_UPD_PO_STATS(sock_net(sk), rt->rt6i_idev, IPSTATS_MIB_OUT, skb->len);
+ DTRACE_IP(send,
+ struct sk_buff * : pktinfo_t *, skb,
+ struct sock * : csinfo_t *, skb->sk,
+ void_ip_t * : ipinfo_t *, ipv6_hdr(skb),
+ struct net_device * : ifinfo_t *, skb->dev,
+ struct iphdr * : ipv4info_t *, NULL,
+ struct ipv6hdr * : ipv6info_t *, ipv6_hdr(skb));
+
err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, sk, skb,
NULL, rt->dst.dev, dst_output_sk);
if (err > 0)
error_fault:
err = -EFAULT;
kfree_skb(skb);
+ skb = NULL;
error:
+ DTRACE_IP(send,
+ struct sk_buff * : pktinfo_t *, skb,
+ struct sock * : csinfo_t *, skb ? skb->sk : NULL,
+ void_ip_t * : ipinfo_t *, skb ? ipv6_hdr(skb) : NULL,
+ struct net_device * : ifinfo_t *, skb ? skb->dev : NULL,
+ struct iphdr * : ipv4info_t *, NULL,
+ struct ipv6hdr * : ipv6info_t *, skb ? ipv6_hdr(skb) : NULL);
+
IP6_INC_STATS(sock_net(sk), rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS);
if (err == -ENOBUFS && !np->recverr)
err = 0;