void                    *xpt_auth_cache;/* auth cache */
        struct list_head        xpt_deferred;   /* deferred requests that need
                                                 * to be revisted */
+       struct sockaddr_storage xpt_local;      /* local address */
+       size_t                  xpt_locallen;   /* length of address */
+       struct sockaddr_storage xpt_remote;     /* remote peer's address */
+       size_t                  xpt_remotelen;  /* length of address */
 };
 
 int    svc_reg_xprt_class(struct svc_xprt_class *);
 int    svc_create_xprt(struct svc_serv *, char *, unsigned short, int);
 void   svc_xprt_received(struct svc_xprt *);
 void   svc_xprt_put(struct svc_xprt *xprt);
+void   svc_xprt_copy_addrs(struct svc_rqst *rqstp, struct svc_xprt *xprt);
 static inline void svc_xprt_get(struct svc_xprt *xprt)
 {
        kref_get(&xprt->xpt_ref);
 }
+static inline void svc_xprt_set_local(struct svc_xprt *xprt,
+                                     struct sockaddr *sa, int salen)
+{
+       memcpy(&xprt->xpt_local, sa, salen);
+       xprt->xpt_locallen = salen;
+}
+static inline void svc_xprt_set_remote(struct svc_xprt *xprt,
+                                      struct sockaddr *sa, int salen)
+{
+       memcpy(&xprt->xpt_remote, sa, salen);
+       xprt->xpt_remotelen = salen;
+}
+static inline unsigned short svc_addr_port(struct sockaddr *sa)
+{
+       unsigned short ret = 0;
+       switch (sa->sa_family) {
+       case AF_INET:
+               ret = ntohs(((struct sockaddr_in *)sa)->sin_port);
+               break;
+       case AF_INET6:
+               ret = ntohs(((struct sockaddr_in6 *)sa)->sin6_port);
+               break;
+       }
+       return ret;
+}
+
+static inline size_t svc_addr_len(struct sockaddr *sa)
+{
+       switch (sa->sa_family) {
+       case AF_INET:
+               return sizeof(struct sockaddr_in);
+       case AF_INET6:
+               return sizeof(struct sockaddr_in6);
+       }
+       return -EAFNOSUPPORT;
+}
+
+static inline unsigned short svc_xprt_local_port(struct svc_xprt *xprt)
+{
+       return svc_addr_port((struct sockaddr *)&xprt->xpt_local);
+}
+
+static inline unsigned short svc_xprt_remote_port(struct svc_xprt *xprt)
+{
+       return svc_addr_port((struct sockaddr *)&xprt->xpt_remote);
+}
 
 #endif /* SUNRPC_SVC_XPRT_H */
 
                        spin_unlock(&svc_xprt_class_lock);
                        if (try_module_get(xcl->xcl_owner)) {
                                struct svc_xprt *newxprt;
-                               ret = 0;
                                newxprt = xcl->xcl_ops->xpo_create
                                        (serv,
                                         (struct sockaddr *)&sin, sizeof(sin),
                                if (IS_ERR(newxprt)) {
                                        module_put(xcl->xcl_owner);
                                        ret = PTR_ERR(newxprt);
-                               }
+                               } else
+                                       ret = svc_xprt_local_port(newxprt);
                        }
                        goto out;
                }
        return ret;
 }
 EXPORT_SYMBOL_GPL(svc_create_xprt);
+
+/*
+ * Copy the local and remote xprt addresses to the rqstp structure
+ */
+void svc_xprt_copy_addrs(struct svc_rqst *rqstp, struct svc_xprt *xprt)
+{
+       struct sockaddr *sin;
+
+       memcpy(&rqstp->rq_addr, &xprt->xpt_remote, xprt->xpt_remotelen);
+       rqstp->rq_addrlen = xprt->xpt_remotelen;
+
+       /*
+        * Destination address in request is needed for binding the
+        * source address in RPC replies/callbacks later.
+        */
+       sin = (struct sockaddr *)&xprt->xpt_local;
+       switch (sin->sa_family) {
+       case AF_INET:
+               rqstp->rq_daddr.addr = ((struct sockaddr_in *)sin)->sin_addr;
+               break;
+       case AF_INET6:
+               rqstp->rq_daddr.addr6 = ((struct sockaddr_in6 *)sin)->sin6_addr;
+               break;
+       }
+}
+EXPORT_SYMBOL_GPL(svc_xprt_copy_addrs);
+
 
        struct msghdr msg = {
                .msg_flags      = MSG_DONTWAIT,
        };
-       struct sockaddr *sin;
        int len;
 
        len = kernel_recvmsg(svsk->sk_sock, &msg, iov, nr, buflen,
                                msg.msg_flags);
 
-       /* sock_recvmsg doesn't fill in the name/namelen, so we must..
-        */
-       memcpy(&rqstp->rq_addr, &svsk->sk_remote, svsk->sk_remotelen);
-       rqstp->rq_addrlen = svsk->sk_remotelen;
-
-       /* Destination address in request is needed for binding the
-        * source address in RPC callbacks later.
-        */
-       sin = (struct sockaddr *)&svsk->sk_local;
-       switch (sin->sa_family) {
-       case AF_INET:
-               rqstp->rq_daddr.addr = ((struct sockaddr_in *)sin)->sin_addr;
-               break;
-       case AF_INET6:
-               rqstp->rq_daddr.addr6 = ((struct sockaddr_in6 *)sin)->sin6_addr;
-               break;
-       }
-
        dprintk("svc: socket %p recvfrom(%p, %Zu) = %d\n",
                svsk, iov[0].iov_base, iov[0].iov_len, len);
-
        return len;
 }
 
        }
 }
 
-static inline void svc_udp_get_dest_address(struct svc_rqst *rqstp,
-                                           struct cmsghdr *cmh)
+/*
+ * Copy the UDP datagram's destination address to the rqstp structure.
+ * The 'destination' address in this case is the address to which the
+ * peer sent the datagram, i.e. our local address. For multihomed
+ * hosts, this can change from msg to msg. Note that only the IP
+ * address changes, the port number should remain the same.
+ */
+static void svc_udp_get_dest_address(struct svc_rqst *rqstp,
+                                    struct cmsghdr *cmh)
 {
        switch (rqstp->rq_sock->sk_sk->sk_family) {
        case AF_INET: {
                svc_xprt_received(&svsk->sk_xprt);
                return -EAGAIN;
        }
-       rqstp->rq_addrlen = sizeof(rqstp->rq_addr);
+       len = svc_addr_len(svc_addr(rqstp));
+       if (len < 0)
+               return len;
+       rqstp->rq_addrlen = len;
        if (skb->tstamp.tv64 == 0) {
                skb->tstamp = ktime_get_real();
                /* Don't enable netstamp, sunrpc doesn't
        if (!(newsvsk = svc_setup_socket(serv, newsock, &err,
                                 (SVC_SOCK_ANONYMOUS | SVC_SOCK_TEMPORARY))))
                goto failed;
-       memcpy(&newsvsk->sk_remote, sin, slen);
-       newsvsk->sk_remotelen = slen;
+       svc_xprt_set_remote(&newsvsk->sk_xprt, sin, slen);
        err = kernel_getsockname(newsock, sin, &slen);
        if (unlikely(err < 0)) {
                dprintk("svc_tcp_accept: kernel_getsockname error %d\n", -err);
                slen = offsetof(struct sockaddr, sa_data);
        }
-       memcpy(&newsvsk->sk_local, sin, slen);
+       svc_xprt_set_local(&newsvsk->sk_xprt, sin, slen);
 
        if (serv->sv_stats)
                serv->sv_stats->nettcpconn++;
        svsk->sk_reclen = 0;
        svsk->sk_tcplen = 0;
 
+       svc_xprt_copy_addrs(rqstp, &svsk->sk_xprt);
        svc_xprt_received(&svsk->sk_xprt);
        if (serv->sv_stats)
                serv->sv_stats->nettcpcnt++;
        else {
                svsk = svc_setup_socket(serv, so, &err, SVC_SOCK_DEFAULTS);
                if (svsk) {
+                       struct sockaddr_storage addr;
+                       struct sockaddr *sin = (struct sockaddr *)&addr;
+                       int salen;
+                       if (kernel_getsockname(svsk->sk_sock, sin, &salen) == 0)
+                               svc_xprt_set_local(&svsk->sk_xprt, sin, salen);
                        svc_xprt_received(&svsk->sk_xprt);
                        err = 0;
                }
        int             error;
        int             type;
        char            buf[RPC_MAX_ADDRBUFLEN];
+       struct sockaddr_storage addr;
+       struct sockaddr *newsin = (struct sockaddr *)&addr;
+       int             newlen;
 
        dprintk("svc: svc_create_socket(%s, %d, %s)\n",
                        serv->sv_program->pg_name, protocol,
        if (error < 0)
                goto bummer;
 
+       newlen = len;
+       error = kernel_getsockname(sock, newsin, &newlen);
+       if (error < 0)
+               goto bummer;
+
        if (protocol == IPPROTO_TCP) {
                if ((error = kernel_listen(sock, 64)) < 0)
                        goto bummer;
        }
 
        if ((svsk = svc_setup_socket(serv, sock, &error, flags)) != NULL) {
+               svc_xprt_set_local(&svsk->sk_xprt, newsin, newlen);
                svc_xprt_received(&svsk->sk_xprt);
                return (struct svc_xprt *)svsk;
        }