]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - net/ipv4/icmp.c
ipv4: Deliver ICMP redirects to sockets too.
[karo-tx-linux.git] / net / ipv4 / icmp.c
index 49a74cc79dc89ee1e07d129a6f23e6a027552c2b..588514627aa7060fba774d65ff0693a1c999739e 100644 (file)
@@ -95,6 +95,7 @@
 #include <net/checksum.h>
 #include <net/xfrm.h>
 #include <net/inet_common.h>
+#include <net/ip_fib.h>
 
 /*
  *     Build xmit assembly blocks
@@ -253,9 +254,10 @@ static inline bool icmpv4_xrlim_allow(struct net *net, struct rtable *rt,
 
        /* Limit if icmp type is enabled in ratemask. */
        if ((1 << type) & net->ipv4.sysctl_icmp_ratemask) {
-               struct inet_peer *peer = rt_get_peer_create(rt, fl4->daddr);
+               struct inet_peer *peer = inet_getpeer_v4(net->ipv4.peers, fl4->daddr, 1);
                rc = inet_peer_xrlim_allow(peer,
                                           net->ipv4.sysctl_icmp_ratelimit);
+               inet_putpeer(peer);
        }
 out:
        return rc;
@@ -333,7 +335,7 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb)
        struct flowi4 fl4;
        struct sock *sk;
        struct inet_sock *inet;
-       __be32 daddr;
+       __be32 daddr, saddr;
 
        if (ip_options_echo(&icmp_param->replyopts.opt.opt, skb))
                return;
@@ -347,6 +349,7 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb)
 
        inet->tos = ip_hdr(skb)->tos;
        daddr = ipc.addr = ip_hdr(skb)->saddr;
+       saddr = fib_compute_spec_dst(skb);
        ipc.opt = NULL;
        ipc.tx_flags = 0;
        if (icmp_param->replyopts.opt.opt.optlen) {
@@ -356,7 +359,7 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb)
        }
        memset(&fl4, 0, sizeof(fl4));
        fl4.daddr = daddr;
-       fl4.saddr = rt->rt_spec_dst;
+       fl4.saddr = saddr;
        fl4.flowi4_tos = RT_TOS(ip_hdr(skb)->tos);
        fl4.flowi4_proto = IPPROTO_ICMP;
        security_skb_classify_flow(skb, flowi4_to_flowi(&fl4));
@@ -631,18 +634,31 @@ out:;
 EXPORT_SYMBOL(icmp_send);
 
 
+static void icmp_socket_deliver(struct sk_buff *skb, u32 info)
+{
+       const struct iphdr *iph = (const struct iphdr *) skb->data;
+       const struct net_protocol *ipprot;
+       int protocol = iph->protocol;
+
+       raw_icmp_error(skb, protocol, info);
+
+       rcu_read_lock();
+       ipprot = rcu_dereference(inet_protos[protocol]);
+       if (ipprot && ipprot->err_handler)
+               ipprot->err_handler(skb, info);
+       rcu_read_unlock();
+}
+
 /*
  *     Handle ICMP_DEST_UNREACH, ICMP_TIME_EXCEED, and ICMP_QUENCH.
  */
 
 static void icmp_unreach(struct sk_buff *skb)
 {
-       const struct net_protocol *ipprot;
        const struct iphdr *iph;
        struct icmphdr *icmph;
        struct net *net;
        u32 info = 0;
-       int protocol;
 
        net = dev_net(skb_dst(skb)->dev);
 
@@ -723,19 +739,7 @@ static void icmp_unreach(struct sk_buff *skb)
        if (!pskb_may_pull(skb, iph->ihl * 4 + 8))
                goto out;
 
-       iph = (const struct iphdr *)skb->data;
-       protocol = iph->protocol;
-
-       /*
-        *      Deliver ICMP message to raw sockets. Pretty useless feature?
-        */
-       raw_icmp_error(skb, protocol, info);
-
-       rcu_read_lock();
-       ipprot = rcu_dereference(inet_protos[protocol]);
-       if (ipprot && ipprot->err_handler)
-               ipprot->err_handler(skb, info);
-       rcu_read_unlock();
+       icmp_socket_deliver(skb, info);
 
 out:
        return;
@@ -778,13 +782,7 @@ static void icmp_redirect(struct sk_buff *skb)
                break;
        }
 
-       /* Ping wants to see redirects.
-         * Let's pretend they are errors of sorts... */
-       if (iph->protocol == IPPROTO_ICMP &&
-           iph->ihl >= 5 &&
-           pskb_may_pull(skb, (iph->ihl<<2)+8)) {
-               ping_err(skb, icmp_hdr(skb)->un.gateway);
-       }
+       icmp_socket_deliver(skb, icmp_hdr(skb)->un.gateway);
 
 out:
        return;