+ if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_LOCAL_NFS_PORT)) {
+ if (nmp->nm_nfsport) {
+ error = EINVAL;
+ NFS_VFS_DBG("Can't have ports specified over incompatible socket families");
+ }
+ nfsmerr_if(error);
+ xb_get_32(error, &xb, len);
+ if (!error && ((len < 1) || (len > sizeof(((struct sockaddr_un *)0)->sun_path)))) {
+ error = EINVAL;
+ }
+ nfsmerr_if(error);
+ MALLOC(nmp->nm_nfs_localport, char *, len + 1, M_TEMP, M_WAITOK | M_ZERO);
+ if (!nmp->nm_nfs_localport) {
+ error = ENOMEM;
+ }
+ nfsmerr_if(error);
+ error = xb_get_bytes(&xb, nmp->nm_nfs_localport, len, 0);
+ nmp->nm_sofamily = AF_LOCAL;
+ nmp->nm_nfsport = 1; /* We use the now deprecated tpcmux port to indcate that we have an AF_LOCAL port */
+ NFS_VFS_DBG("Setting nfs local port %s (%d)\n", nmp->nm_nfs_localport, nmp->nm_nfsport);
+ }
+ if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_LOCAL_MOUNT_PORT)) {
+ if (nmp->nm_mountport) {
+ error = EINVAL;
+ NFS_VFS_DBG("Can't have ports specified over mulitple socket families");
+ }
+ nfsmerr_if(error);
+ xb_get_32(error, &xb, len);
+ if (!error && ((len < 1) || (len > sizeof(((struct sockaddr_un *)0)->sun_path)))) {
+ error = EINVAL;
+ }
+ nfsmerr_if(error);
+ MALLOC(nmp->nm_mount_localport, char *, len + 1, M_TEMP, M_WAITOK | M_ZERO);
+ if (!nmp->nm_mount_localport) {
+ error = ENOMEM;
+ }
+ nfsmerr_if(error);
+ error = xb_get_bytes(&xb, nmp->nm_mount_localport, len, 0);
+ nmp->nm_sofamily = AF_LOCAL;
+ nmp->nm_mountport = 1; /* We use the now deprecated tpcmux port to indcate that we have an AF_LOCAL port */
+ NFS_VFS_DBG("Setting mount local port %s (%d)\n", nmp->nm_mount_localport, nmp->nm_mountport);
+ }
+ if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_SET_MOUNT_OWNER)) {
+ xb_get_32(error, &xb, set_owner);
+ nfsmerr_if(error);
+ error = vfs_context_suser(ctx);
+ /*
+ * root can set owner to whatever, user can set owner to self
+ */
+ if ((error) && (set_owner == kauth_cred_getuid(vfs_context_ucred(ctx)))) {
+ /* ok for non-root can set owner to self */
+ error = 0;
+ }
+ nfsmerr_if(error);
+ }
+
+ /*
+ * Sanity check/finalize settings.
+ */
+
+ if (nmp->nm_timeo < NFS_MINTIMEO) {
+ nmp->nm_timeo = NFS_MINTIMEO;
+ } else if (nmp->nm_timeo > NFS_MAXTIMEO) {
+ nmp->nm_timeo = NFS_MAXTIMEO;
+ }
+ if (nmp->nm_retry > NFS_MAXREXMIT) {
+ nmp->nm_retry = NFS_MAXREXMIT;
+ }
+
+ if (nmp->nm_numgrps > NFS_MAXGRPS) {
+ nmp->nm_numgrps = NFS_MAXGRPS;
+ }
+ if (nmp->nm_readahead > NFS_MAXRAHEAD) {
+ nmp->nm_readahead = NFS_MAXRAHEAD;
+ }
+ if (nmp->nm_acregmin > nmp->nm_acregmax) {
+ nmp->nm_acregmin = nmp->nm_acregmax;
+ }
+ if (nmp->nm_acdirmin > nmp->nm_acdirmax) {
+ nmp->nm_acdirmin = nmp->nm_acdirmax;
+ }
+
+ /* need at least one fs location */
+ if (nmp->nm_locations.nl_numlocs < 1) {
+ error = EINVAL;
+ }
+ nfsmerr_if(error);
+
+ if (!NM_OMATTR_GIVEN(nmp, MNTFROM)) {
+ /* init mount's mntfromname to first location */
+ nfs_location_mntfromname(&nmp->nm_locations, firstloc,
+ vfs_statfs(mp)->f_mntfromname,
+ sizeof(vfs_statfs(mp)->f_mntfromname), 0);
+ }
+
+ /* Need to save the mounting credential for v4. */
+ nmp->nm_mcred = vfs_context_ucred(ctx);
+ if (IS_VALID_CRED(nmp->nm_mcred)) {
+ kauth_cred_ref(nmp->nm_mcred);
+ }
+
+ /*
+ * If a reserved port is required, check for that privilege.
+ * (Note that mirror mounts are exempt because the privilege was
+ * already checked for the original mount.)
+ */
+ if (NMFLAG(nmp, RESVPORT) && !vfs_iskernelmount(mp)) {
+ error = priv_check_cred(nmp->nm_mcred, PRIV_NETINET_RESERVEDPORT, 0);
+ }
+ nfsmerr_if(error);
+
+ /* set up the version-specific function tables */
+ if (nmp->nm_vers < NFS_VER4) {
+ nmp->nm_funcs = &nfs3_funcs;
+ } else {
+#if CONFIG_NFS4
+ nmp->nm_funcs = &nfs4_funcs;
+#else
+ /* don't go any further if we don't support NFS4 */
+ nmp->nm_funcs = NULL;
+ error = ENOTSUP;
+ nfsmerr_if(error);
+#endif
+ }
+
+ /* do mount's initial socket connection */
+ error = nfs_mount_connect(nmp);
+ nfsmerr_if(error);
+
+ /* sanity check settings now that version/connection is set */
+ if (nmp->nm_vers == NFS_VER2) { /* ignore RDIRPLUS on NFSv2 */
+ NFS_BITMAP_CLR(nmp->nm_flags, NFS_MFLAG_RDIRPLUS);
+ }
+#if CONFIG_NFS4