|
@@ -719,13 +719,92 @@ svc_exit_thread(struct svc_rqst *rqstp)
|
|
|
}
|
|
|
EXPORT_SYMBOL(svc_exit_thread);
|
|
|
|
|
|
+#ifdef CONFIG_SUNRPC_REGISTER_V4
|
|
|
/*
|
|
|
- * Register an RPC service with the local portmapper.
|
|
|
- * To unregister a service, call this routine with
|
|
|
- * proto and port == 0.
|
|
|
+ * Registering kernel RPC services with rpcbind version 2 will work
|
|
|
+ * over either IPv4 or IPv6, since the Linux kernel always registers
|
|
|
+ * services for the "any" address.
|
|
|
+ *
|
|
|
+ * However, the local rpcbind daemon listens on either only AF_INET
|
|
|
+ * or AF_INET6 (never both). When it listens on AF_INET6, an rpcbind
|
|
|
+ * version 2 registration will result in registering the service at
|
|
|
+ * IN6ADDR_ANY, even if the RPC service being registered is not
|
|
|
+ * IPv6-enabled.
|
|
|
+ *
|
|
|
+ * Rpcbind version 4 allows us to be a little more specific. Kernel
|
|
|
+ * RPC services that don't yet support AF_INET6 can register
|
|
|
+ * themselves as IPv4-only with the local rpcbind daemon, even if the
|
|
|
+ * daemon is listening only on AF_INET6.
|
|
|
+ *
|
|
|
+ * And, registering IPv6-enabled kernel RPC services via AF_INET6
|
|
|
+ * verifies that the local user space rpcbind daemon is properly
|
|
|
+ * configured to support remote AF_INET6 rpcbind requests.
|
|
|
+ *
|
|
|
+ * An AF_INET6 registration request will fail if the local rpcbind
|
|
|
+ * daemon is not set up to listen on AF_INET6. Likewise, we fail
|
|
|
+ * AF_INET6 registration requests if svc_register() is configured to
|
|
|
+ * support only rpcbind version 2.
|
|
|
*/
|
|
|
-int
|
|
|
-svc_register(struct svc_serv *serv, int proto, unsigned short port)
|
|
|
+static int __svc_register(const u32 program, const u32 version,
|
|
|
+ const sa_family_t family,
|
|
|
+ const unsigned short protocol,
|
|
|
+ const unsigned short port)
|
|
|
+{
|
|
|
+ struct sockaddr_in sin = {
|
|
|
+ .sin_family = AF_INET,
|
|
|
+ .sin_addr.s_addr = htonl(INADDR_ANY),
|
|
|
+ .sin_port = htons(port),
|
|
|
+ };
|
|
|
+ struct sockaddr_in6 sin6 = {
|
|
|
+ .sin6_family = AF_INET6,
|
|
|
+ .sin6_addr = IN6ADDR_ANY_INIT,
|
|
|
+ .sin6_port = htons(port),
|
|
|
+ };
|
|
|
+ struct sockaddr *sap;
|
|
|
+ char *netid;
|
|
|
+
|
|
|
+ switch (family) {
|
|
|
+ case AF_INET:
|
|
|
+ sap = (struct sockaddr *)&sin;
|
|
|
+ netid = RPCBIND_NETID_TCP;
|
|
|
+ if (protocol == IPPROTO_UDP)
|
|
|
+ netid = RPCBIND_NETID_UDP;
|
|
|
+ break;
|
|
|
+ case AF_INET6:
|
|
|
+ sap = (struct sockaddr *)&sin6;
|
|
|
+ netid = RPCBIND_NETID_TCP6;
|
|
|
+ if (protocol == IPPROTO_UDP)
|
|
|
+ netid = RPCBIND_NETID_UDP6;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ return -EAFNOSUPPORT;
|
|
|
+ }
|
|
|
+
|
|
|
+ return rpcb_v4_register(program, version, sap, netid);
|
|
|
+}
|
|
|
+#else
|
|
|
+static int __svc_register(const u32 program, const u32 version,
|
|
|
+ sa_family_t family,
|
|
|
+ const unsigned short protocol,
|
|
|
+ const unsigned short port)
|
|
|
+{
|
|
|
+ if (family != AF_INET)
|
|
|
+ return -EAFNOSUPPORT;
|
|
|
+
|
|
|
+ return rpcb_register(program, version, protocol, port);
|
|
|
+}
|
|
|
+#endif
|
|
|
+
|
|
|
+/**
|
|
|
+ * svc_register - register an RPC service with the local portmapper
|
|
|
+ * @serv: svc_serv struct for the service to register
|
|
|
+ * @proto: transport protocol number to advertise
|
|
|
+ * @port: port to advertise
|
|
|
+ *
|
|
|
+ * Service is registered for any address in serv's address family
|
|
|
+ */
|
|
|
+int svc_register(const struct svc_serv *serv, const unsigned short proto,
|
|
|
+ const unsigned short port)
|
|
|
{
|
|
|
struct svc_program *progp;
|
|
|
unsigned int i;
|
|
@@ -738,8 +817,9 @@ svc_register(struct svc_serv *serv, int proto, unsigned short port)
|
|
|
if (progp->pg_vers[i] == NULL)
|
|
|
continue;
|
|
|
|
|
|
- dprintk("svc: svc_register(%s, %s, %d, %d)%s\n",
|
|
|
+ dprintk("svc: svc_register(%s, %u, %s, %u, %d)%s\n",
|
|
|
progp->pg_name,
|
|
|
+ serv->sv_family,
|
|
|
proto == IPPROTO_UDP? "udp" : "tcp",
|
|
|
port,
|
|
|
i,
|
|
@@ -749,7 +829,8 @@ svc_register(struct svc_serv *serv, int proto, unsigned short port)
|
|
|
if (progp->pg_vers[i]->vs_hidden)
|
|
|
continue;
|
|
|
|
|
|
- error = rpcb_register(progp->pg_prog, i, proto, port);
|
|
|
+ error = __svc_register(progp->pg_prog, i,
|
|
|
+ serv->sv_family, proto, port);
|
|
|
if (error < 0)
|
|
|
break;
|
|
|
}
|