Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
[cascardo/linux.git] / net / rxrpc / af_rxrpc.c
index 25d00de..44c9c2b 100644 (file)
@@ -45,7 +45,7 @@ u32 rxrpc_epoch;
 atomic_t rxrpc_debug_id;
 
 /* count of skbs currently in use */
-atomic_t rxrpc_n_skbs;
+atomic_t rxrpc_n_tx_skbs, rxrpc_n_rx_skbs;
 
 struct workqueue_struct *rxrpc_workqueue;
 
@@ -106,19 +106,25 @@ static int rxrpc_validate_address(struct rxrpc_sock *rx,
        case AF_INET:
                if (srx->transport_len < sizeof(struct sockaddr_in))
                        return -EINVAL;
-               _debug("INET: %x @ %pI4",
-                      ntohs(srx->transport.sin.sin_port),
-                      &srx->transport.sin.sin_addr);
                tail = offsetof(struct sockaddr_rxrpc, transport.sin.__pad);
                break;
 
+#ifdef CONFIG_AF_RXRPC_IPV6
        case AF_INET6:
+               if (srx->transport_len < sizeof(struct sockaddr_in6))
+                       return -EINVAL;
+               tail = offsetof(struct sockaddr_rxrpc, transport) +
+                       sizeof(struct sockaddr_in6);
+               break;
+#endif
+
        default:
                return -EAFNOSUPPORT;
        }
 
        if (tail < len)
                memset((void *)srx + tail, 0, len - tail);
+       _debug("INET: %pISp", &srx->transport);
        return 0;
 }
 
@@ -130,7 +136,8 @@ static int rxrpc_bind(struct socket *sock, struct sockaddr *saddr, int len)
        struct sockaddr_rxrpc *srx = (struct sockaddr_rxrpc *)saddr;
        struct sock *sk = sock->sk;
        struct rxrpc_local *local;
-       struct rxrpc_sock *rx = rxrpc_sk(sk), *prx;
+       struct rxrpc_sock *rx = rxrpc_sk(sk);
+       u16 service_id = srx->srx_service;
        int ret;
 
        _enter("%p,%p,%d", rx, saddr, len);
@@ -154,15 +161,12 @@ static int rxrpc_bind(struct socket *sock, struct sockaddr *saddr, int len)
                goto error_unlock;
        }
 
-       if (rx->srx.srx_service) {
+       if (service_id) {
                write_lock(&local->services_lock);
-               hlist_for_each_entry(prx, &local->services, listen_link) {
-                       if (prx->srx.srx_service == rx->srx.srx_service)
-                               goto service_in_use;
-               }
-
+               if (rcu_access_pointer(local->service))
+                       goto service_in_use;
                rx->local = local;
-               hlist_add_head_rcu(&rx->listen_link, &local->services);
+               rcu_assign_pointer(local->service, rx);
                write_unlock(&local->services_lock);
 
                rx->sk.sk_state = RXRPC_SERVER_BOUND;
@@ -401,6 +405,23 @@ static int rxrpc_sendmsg(struct socket *sock, struct msghdr *m, size_t len)
 
        switch (rx->sk.sk_state) {
        case RXRPC_UNBOUND:
+               rx->srx.srx_family = AF_RXRPC;
+               rx->srx.srx_service = 0;
+               rx->srx.transport_type = SOCK_DGRAM;
+               rx->srx.transport.family = rx->family;
+               switch (rx->family) {
+               case AF_INET:
+                       rx->srx.transport_len = sizeof(struct sockaddr_in);
+                       break;
+#ifdef CONFIG_AF_RXRPC_IPV6
+               case AF_INET6:
+                       rx->srx.transport_len = sizeof(struct sockaddr_in6);
+                       break;
+#endif
+               default:
+                       ret = -EAFNOSUPPORT;
+                       goto error_unlock;
+               }
                local = rxrpc_lookup_local(&rx->srx);
                if (IS_ERR(local)) {
                        ret = PTR_ERR(local);
@@ -551,7 +572,8 @@ static int rxrpc_create(struct net *net, struct socket *sock, int protocol,
                return -EAFNOSUPPORT;
 
        /* we support transport protocol UDP/UDP6 only */
-       if (protocol != PF_INET)
+       if (protocol != PF_INET &&
+           IS_ENABLED(CONFIG_AF_RXRPC_IPV6) && protocol != PF_INET6)
                return -EPROTONOSUPPORT;
 
        if (sock->type != SOCK_DGRAM)
@@ -575,7 +597,6 @@ static int rxrpc_create(struct net *net, struct socket *sock, int protocol,
        rx->family = protocol;
        rx->calls = RB_ROOT;
 
-       INIT_HLIST_NODE(&rx->listen_link);
        spin_lock_init(&rx->incoming_lock);
        INIT_LIST_HEAD(&rx->sock_calls);
        INIT_LIST_HEAD(&rx->to_be_accepted);
@@ -657,11 +678,9 @@ static int rxrpc_release_sock(struct sock *sk)
        sk->sk_state = RXRPC_CLOSE;
        spin_unlock_bh(&sk->sk_receive_queue.lock);
 
-       ASSERTCMP(rx->listen_link.next, !=, LIST_POISON1);
-
-       if (!hlist_unhashed(&rx->listen_link)) {
+       if (rx->local && rx->local->service == rx) {
                write_lock(&rx->local->services_lock);
-               hlist_del_rcu(&rx->listen_link);
+               rx->local->service = NULL;
                write_unlock(&rx->local->services_lock);
        }
 
@@ -843,7 +862,8 @@ static void __exit af_rxrpc_exit(void)
        proto_unregister(&rxrpc_proto);
        rxrpc_destroy_all_calls();
        rxrpc_destroy_all_connections();
-       ASSERTCMP(atomic_read(&rxrpc_n_skbs), ==, 0);
+       ASSERTCMP(atomic_read(&rxrpc_n_tx_skbs), ==, 0);
+       ASSERTCMP(atomic_read(&rxrpc_n_rx_skbs), ==, 0);
        rxrpc_destroy_all_locals();
 
        remove_proc_entry("rxrpc_conns", init_net.proc_net);