Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
[cascardo/linux.git] / net / rxrpc / peer_object.c
index 2efe29a..941b724 100644 (file)
 #include <linux/skbuff.h>
 #include <linux/udp.h>
 #include <linux/in.h>
+#include <linux/in6.h>
 #include <linux/slab.h>
 #include <linux/hashtable.h>
 #include <net/sock.h>
 #include <net/af_rxrpc.h>
 #include <net/ip.h>
 #include <net/route.h>
+#include <net/ip6_route.h>
 #include "ar-internal.h"
 
 static DEFINE_HASHTABLE(rxrpc_peer_hash, 10);
@@ -50,6 +52,13 @@ static unsigned long rxrpc_peer_hash_key(struct rxrpc_local *local,
                size = sizeof(srx->transport.sin.sin_addr);
                p = (u16 *)&srx->transport.sin.sin_addr;
                break;
+#ifdef CONFIG_AF_RXRPC_IPV6
+       case AF_INET6:
+               hash_key += (u16 __force)srx->transport.sin.sin_port;
+               size = sizeof(srx->transport.sin6.sin6_addr);
+               p = (u16 *)&srx->transport.sin6.sin6_addr;
+               break;
+#endif
        default:
                WARN(1, "AF_RXRPC: Unsupported transport address family\n");
                return 0;
@@ -93,6 +102,14 @@ static long rxrpc_peer_cmp_key(const struct rxrpc_peer *peer,
                        memcmp(&peer->srx.transport.sin.sin_addr,
                               &srx->transport.sin.sin_addr,
                               sizeof(struct in_addr));
+#ifdef CONFIG_AF_RXRPC_IPV6
+       case AF_INET6:
+               return ((u16 __force)peer->srx.transport.sin6.sin6_port -
+                       (u16 __force)srx->transport.sin6.sin6_port) ?:
+                       memcmp(&peer->srx.transport.sin6.sin6_addr,
+                              &srx->transport.sin6.sin6_addr,
+                              sizeof(struct in6_addr));
+#endif
        default:
                BUG();
        }
@@ -130,17 +147,7 @@ struct rxrpc_peer *rxrpc_lookup_peer_rcu(struct rxrpc_local *local,
 
        peer = __rxrpc_lookup_peer_rcu(local, srx, hash_key);
        if (peer) {
-               switch (srx->transport.family) {
-               case AF_INET:
-                       _net("PEER %d {%d,%u,%pI4+%hu}",
-                            peer->debug_id,
-                            peer->srx.transport_type,
-                            peer->srx.transport.family,
-                            &peer->srx.transport.sin.sin_addr,
-                            ntohs(peer->srx.transport.sin.sin_port));
-                       break;
-               }
-
+               _net("PEER %d {%pISp}", peer->debug_id, &peer->srx.transport);
                _leave(" = %p {u=%d}", peer, atomic_read(&peer->usage));
        }
        return peer;
@@ -152,22 +159,53 @@ struct rxrpc_peer *rxrpc_lookup_peer_rcu(struct rxrpc_local *local,
  */
 static void rxrpc_assess_MTU_size(struct rxrpc_peer *peer)
 {
+       struct dst_entry *dst;
        struct rtable *rt;
-       struct flowi4 fl4;
+       struct flowi fl;
+       struct flowi4 *fl4 = &fl.u.ip4;
+#ifdef CONFIG_AF_RXRPC_IPV6
+       struct flowi6 *fl6 = &fl.u.ip6;
+#endif
 
        peer->if_mtu = 1500;
 
-       rt = ip_route_output_ports(&init_net, &fl4, NULL,
-                                  peer->srx.transport.sin.sin_addr.s_addr, 0,
-                                  htons(7000), htons(7001),
-                                  IPPROTO_UDP, 0, 0);
-       if (IS_ERR(rt)) {
-               _leave(" [route err %ld]", PTR_ERR(rt));
-               return;
+       memset(&fl, 0, sizeof(fl));
+       switch (peer->srx.transport.family) {
+       case AF_INET:
+               rt = ip_route_output_ports(
+                       &init_net, fl4, NULL,
+                       peer->srx.transport.sin.sin_addr.s_addr, 0,
+                       htons(7000), htons(7001), IPPROTO_UDP, 0, 0);
+               if (IS_ERR(rt)) {
+                       _leave(" [route err %ld]", PTR_ERR(rt));
+                       return;
+               }
+               dst = &rt->dst;
+               break;
+
+#ifdef CONFIG_AF_RXRPC_IPV6
+       case AF_INET6:
+               fl6->flowi6_iif = LOOPBACK_IFINDEX;
+               fl6->flowi6_scope = RT_SCOPE_UNIVERSE;
+               fl6->flowi6_proto = IPPROTO_UDP;
+               memcpy(&fl6->daddr, &peer->srx.transport.sin6.sin6_addr,
+                      sizeof(struct in6_addr));
+               fl6->fl6_dport = htons(7001);
+               fl6->fl6_sport = htons(7000);
+               dst = ip6_route_output(&init_net, NULL, fl6);
+               if (IS_ERR(dst)) {
+                       _leave(" [route err %ld]", PTR_ERR(dst));
+                       return;
+               }
+               break;
+#endif
+
+       default:
+               BUG();
        }
 
-       peer->if_mtu = dst_mtu(&rt->dst);
-       dst_release(&rt->dst);
+       peer->if_mtu = dst_mtu(dst);
+       dst_release(dst);
 
        _leave(" [if_mtu %u]", peer->if_mtu);
 }
@@ -203,20 +241,29 @@ struct rxrpc_peer *rxrpc_alloc_peer(struct rxrpc_local *local, gfp_t gfp)
  */
 static void rxrpc_init_peer(struct rxrpc_peer *peer, unsigned long hash_key)
 {
+       peer->hash_key = hash_key;
        rxrpc_assess_MTU_size(peer);
        peer->mtu = peer->if_mtu;
+       peer->rtt_last_req = ktime_get_real();
 
-       if (peer->srx.transport.family == AF_INET) {
+       switch (peer->srx.transport.family) {
+       case AF_INET:
                peer->hdrsize = sizeof(struct iphdr);
-               switch (peer->srx.transport_type) {
-               case SOCK_DGRAM:
-                       peer->hdrsize += sizeof(struct udphdr);
-                       break;
-               default:
-                       BUG();
-                       break;
-               }
-       } else {
+               break;
+#ifdef CONFIG_AF_RXRPC_IPV6
+       case AF_INET6:
+               peer->hdrsize = sizeof(struct ipv6hdr);
+               break;
+#endif
+       default:
+               BUG();
+       }
+
+       switch (peer->srx.transport_type) {
+       case SOCK_DGRAM:
+               peer->hdrsize += sizeof(struct udphdr);
+               break;
+       default:
                BUG();
        }
 
@@ -238,7 +285,6 @@ static struct rxrpc_peer *rxrpc_create_peer(struct rxrpc_local *local,
 
        peer = rxrpc_alloc_peer(local, gfp);
        if (peer) {
-               peer->hash_key = hash_key;
                memcpy(&peer->srx, srx, sizeof(*srx));
                rxrpc_init_peer(peer, hash_key);
        }
@@ -285,11 +331,7 @@ struct rxrpc_peer *rxrpc_lookup_peer(struct rxrpc_local *local,
        struct rxrpc_peer *peer, *candidate;
        unsigned long hash_key = rxrpc_peer_hash_key(local, srx);
 
-       _enter("{%d,%d,%pI4+%hu}",
-              srx->transport_type,
-              srx->transport_len,
-              &srx->transport.sin.sin_addr,
-              ntohs(srx->transport.sin.sin_port));
+       _enter("{%pISp}", &srx->transport);
 
        /* search the peer list first */
        rcu_read_lock();
@@ -326,11 +368,7 @@ struct rxrpc_peer *rxrpc_lookup_peer(struct rxrpc_local *local,
                        peer = candidate;
        }
 
-       _net("PEER %d {%d,%pI4+%hu}",
-            peer->debug_id,
-            peer->srx.transport_type,
-            &peer->srx.transport.sin.sin_addr,
-            ntohs(peer->srx.transport.sin.sin_port));
+       _net("PEER %d {%pISp}", peer->debug_id, &peer->srx.transport);
 
        _leave(" = %p {u=%d}", peer, atomic_read(&peer->usage));
        return peer;