#include <smbsrv/smb2_kproto.h>
#include <smbsrv/smb_fsops.h>
#include <smb/winioctl.h>
static uint32_t
smb2_fsctl_invalid(smb_request_t *sr, smb_fsctl_t *fsctl)
{
return (NT_STATUS_INVALID_DEVICE_REQUEST);
}
static uint32_t
smb2_fsctl_notsup(smb_request_t *sr, smb_fsctl_t *fsctl)
{
return (NT_STATUS_NOT_SUPPORTED);
}
static uint32_t
smb2_fsctl_unknown(smb_request_t *sr, smb_fsctl_t *fsctl)
{
#ifdef DEBUG
cmn_err(CE_NOTE, "smb2_fsctl_unknown: code 0x%x", fsctl->CtlCode);
#endif
return (NT_STATUS_INVALID_DEVICE_REQUEST);
}
static uint32_t
smb2_fsctl_get_compression(smb_request_t *sr, smb_fsctl_t *fsctl)
{
_NOTE(ARGUNUSED(sr))
uint16_t compress_state = 0;
int rc;
rc = smb_mbc_encodef(fsctl->in_mbc, "w",
compress_state);
if (rc != 0)
return (NT_STATUS_BUFFER_OVERFLOW);
return (NT_STATUS_SUCCESS);
}
static uint32_t
smb2_fsctl_set_compression(smb_request_t *sr, smb_fsctl_t *fsctl)
{
_NOTE(ARGUNUSED(sr))
uint16_t compress_state;
(void) smb_mbc_decodef(fsctl->in_mbc, "w",
&compress_state);
if (compress_state > 0)
return (NT_STATUS_COMPRESSION_DISABLED);
return (NT_STATUS_SUCCESS);
}
static uint32_t
smb2_fsctl_get_resume_key(smb_request_t *sr, smb_fsctl_t *fsctl)
{
smb_ofile_t *of = sr->fid_ofile;
smb2fid_t smb2fid;
int rc;
smb2fid.persistent = of->f_persistid;
smb2fid.temporal = of->f_fid;
rc = smb_mbc_encodef(
fsctl->out_mbc, "qq16.",
smb2fid.persistent,
smb2fid.temporal);
if (rc != 0)
return (NT_STATUS_BUFFER_OVERFLOW);
return (NT_STATUS_SUCCESS);
}
uint32_t
smb2_fsctl_fs(smb_request_t *sr, smb_fsctl_t *fsctl)
{
uint32_t (*func)(smb_request_t *, smb_fsctl_t *);
uint32_t status;
switch (fsctl->CtlCode) {
case FSCTL_GET_COMPRESSION:
func = smb2_fsctl_get_compression;
break;
case FSCTL_SET_COMPRESSION:
func = smb2_fsctl_set_compression;
break;
case FSCTL_SET_REPARSE_POINT:
case FSCTL_GET_REPARSE_POINT:
func = smb2_fsctl_invalid;
break;
case FSCTL_CREATE_OR_GET_OBJECT_ID:
func = smb2_fsctl_invalid;
break;
case FSCTL_SET_SPARSE:
func = smb2_fsctl_set_sparse;
break;
case FSCTL_SET_ZERO_DATA:
func = smb2_fsctl_set_zero_data;
break;
case FSCTL_QUERY_ALLOCATED_RANGES:
func = smb2_fsctl_query_alloc_ranges;
break;
case FSCTL_FILE_LEVEL_TRIM:
func = smb2_fsctl_invalid;
break;
case FSCTL_OFFLOAD_READ:
func = smb2_fsctl_odx_read;
break;
case FSCTL_OFFLOAD_WRITE:
func = smb2_fsctl_odx_write;
break;
case FSCTL_GET_INTEGRITY_INFORMATION:
case FSCTL_SET_INTEGRITY_INFORMATION:
func = smb2_fsctl_invalid;
break;
case FSCTL_QUERY_FILE_REGIONS:
func = smb2_fsctl_query_file_regions;
break;
case FSCTL_REFS_STREAM_SNAPSHOT_MANAGEMENT:
func = smb2_fsctl_notsup;
break;
default:
func = smb2_fsctl_unknown;
break;
}
if (sr->fid_ofile == NULL ||
!SMB_FTYPE_IS_DISK(sr->fid_ofile->f_ftype))
return (NT_STATUS_INVALID_PARAMETER);
status = (*func)(sr, fsctl);
return (status);
}
uint32_t
smb2_fsctl_netfs(smb_request_t *sr, smb_fsctl_t *fsctl)
{
uint32_t (*func)(smb_request_t *, smb_fsctl_t *);
uint32_t status;
boolean_t need_disk_file = B_TRUE;
switch (fsctl->CtlCode) {
case FSCTL_SRV_ENUMERATE_SNAPSHOTS:
func = smb_vss_enum_snapshots;
break;
case FSCTL_SRV_REQUEST_RESUME_KEY:
func = smb2_fsctl_get_resume_key;
break;
case FSCTL_SRV_COPYCHUNK:
case FSCTL_SRV_COPYCHUNK_WRITE:
func = smb2_fsctl_copychunk;
break;
case FSCTL_SRV_READ_HASH:
func = smb2_fsctl_invalid;
break;
case FSCTL_LMR_REQUEST_RESILIENCY:
func = smb2_fsctl_set_resilient;
break;
case FSCTL_QUERY_NETWORK_INTERFACE_INFO:
need_disk_file = B_FALSE;
func = smb2_fsctl_invalid;
break;
case FSCTL_VALIDATE_NEGOTIATE_INFO:
need_disk_file = B_FALSE;
func = smb2_nego_validate;
break;
default:
func = smb2_fsctl_unknown;
break;
}
if (need_disk_file && (sr->fid_ofile == NULL ||
!SMB_FTYPE_IS_DISK(sr->fid_ofile->f_ftype)))
return (NT_STATUS_INVALID_PARAMETER);
status = (*func)(sr, fsctl);
return (status);
}