root/usr/src/cmd/smbsrv/fksmbd/fksmbd_kmod.c
/*
 * This file and its contents are supplied under the terms of the
 * Common Development and Distribution License ("CDDL"), version 1.0.
 * You may only use this file in accordance with the terms of version
 * 1.0 of the CDDL.
 *
 * A full copy of the text of the CDDL should have accompanied this
 * source.  A copy of the CDDL is also available via the Internet at
 * http://www.illumos.org/license/CDDL.
 */

/*
 * Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
 */

/*
 * These replace NODIRECT functions of the same name in
 * $SRC/lib/smbsrv/libsmb/common/smb_kmod.c including:
 *      smb_kmod_bind, smb_kmod_ioctl, smb_kmod_isbound,
 *      smb_kmod_start, smb_kmod_stop, smb_kmod_unbind.
 *
 * For all the other smb_kmod_... functions, we can just use the
 * libsmb code because those all call smb_kmod_ioctl, for which
 * we have an override here.
 *
 * The replacment functions here just call the libfksmbsrv code
 * directly where the real (in-kernel) versions would be entered
 * via the driver framework (open, close, ioctl).  Aside from that,
 * the call sequences are intentionally the same (where possible).
 * In particular, that makes it possible to debug startup/teardown
 * problems in the user-space version of this code.
 */

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioccom.h>
#include <sys/param.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <note.h>

#include <smbsrv/smbinfo.h>
#include <smbsrv/smb_ioctl.h>
#include "smbd.h"

boolean_t smbdrv_opened = B_FALSE;

/*
 * We want to adjust a few things in the standard configuration
 * passed to the "fake" version of the smbsrv kernel module.
 *
 * Reduce the maximum number of connections and workers, just for
 * convenience while debugging.  (Don't want hundreds of threads.)
 */
static void
fksmbd_adjust_config(smb_ioc_header_t *ioc_hdr)
{
        smb_ioc_cfg_t *ioc = (smb_ioc_cfg_t *)ioc_hdr;
        char *s;

        ioc->maxconnections = 10;
        ioc->maxworkers = 20;
        smbd_report("maxconnections=%d, maxworkers=%d",
            ioc->maxconnections, ioc->maxworkers);

        if ((s = getenv("SMB_MAX_PROTOCOL")) != NULL) {
                ioc->max_protocol = strtol(s, NULL, 16);
                smbd_report("max_protocol=0x%x", ioc->max_protocol);
        }

        if ((s = getenv("SMB_MIN_PROTOCOL")) != NULL) {
                ioc->min_protocol = strtol(s, NULL, 16);
                smbd_report("min_protocol=0x%x", ioc->min_protocol);
        }

        if ((s = getenv("SMB_SIGNING")) != NULL) {
                ioc->signing_enable = 0;
                ioc->signing_required = 0;
                switch (s[0]) {
                case 'e':
                        ioc->signing_enable = 1;
                        break;
                case 'r':
                        ioc->signing_enable = 1;
                        ioc->signing_required = 1;
                        break;
                default:
                        smbd_report("env SMB_SIGNING invalid");
                        break;
                }
        }
        smbd_report("signing: enable=%d, required=%d",
            ioc->signing_enable, ioc->signing_required);
}

boolean_t
smb_kmod_isbound(void)
{
        return (smbdrv_opened);
}

int
smb_kmod_bind(boolean_t smbd)
{
        int rc;

        if (!smbd)
                return (ENXIO);

        if (smbdrv_opened) {
                smbdrv_opened = B_FALSE;
                (void) fksmbsrv_drv_close();
        }

        rc = fksmbsrv_drv_open();
        if (rc == 0)
                smbdrv_opened = B_TRUE;

        return (rc);
}

void
smb_kmod_unbind(void)
{
        if (smbdrv_opened) {
                smbdrv_opened = B_FALSE;
                (void) fksmbsrv_drv_close();
        }
}

int
smb_kmod_ioctl(int cmd, smb_ioc_header_t *ioc, uint32_t len)
{
        int rc;

        _NOTE(ARGUNUSED(len));

        if (!smbdrv_opened)
                return (EBADF);

        if (cmd == SMB_IOC_CONFIG)
                fksmbd_adjust_config(ioc);

        rc = fksmbsrv_drv_ioctl(cmd, ioc);
        return (rc);
}

/* ARGSUSED */
int
smb_kmod_start(int opipe, int lmshr, int udoor)
{
        smb_ioc_start_t ioc;
        int rc;

        bzero(&ioc, sizeof (ioc));

        /* These three are unused */
        ioc.opipe = -1;
        ioc.lmshrd = -1;
        ioc.udoor = -1;

        /* These are the "door" dispatch callbacks */
        ioc.lmshr_func = NULL; /* not used */
        ioc.opipe_func = NULL; /* not used */
        ioc.udoor_func = (void *)fksmbd_door_dispatch;

        rc = smb_kmod_ioctl(SMB_IOC_START, &ioc.hdr, sizeof (ioc));
        return (rc);
}

void
smb_kmod_stop(void)
{
        smb_ioc_header_t ioc;

        bzero(&ioc, sizeof (ioc));
        (void) smb_kmod_ioctl(SMB_IOC_STOP, &ioc, sizeof (ioc));
}