summaryrefslogtreecommitdiffhomepage
path: root/src/afl
diff options
context:
space:
mode:
authormidipix <writeonce@midipix.org>2018-05-05 00:29:32 +0000
committermidipix <writeonce@midipix.org>2018-05-07 08:33:42 -0400
commit6a47931d980b8a417f769545eea1bda7b51afea9 (patch)
tree9b73d8f9126496cb05f563e7806bd95571b5916a /src/afl
parentdbeebdf22fad8254aa615b071c878b7a086246ed (diff)
downloadntapi-6a47931d980b8a417f769545eea1bda7b51afea9.tar.bz2
ntapi-6a47931d980b8a417f769545eea1bda7b51afea9.tar.xz
advisory file locking: integrated client-side interfaces.
Diffstat (limited to 'src/afl')
-rw-r--r--src/afl/ntapi_afl_connect.c335
-rw-r--r--src/afl/ntapi_afl_fcntl.c42
-rw-r--r--src/afl/ntapi_afl_fdio.c61
-rw-r--r--src/afl/ntapi_afl_ioctl.c92
-rw-r--r--src/afl/ntapi_afl_query.c67
-rw-r--r--src/afl/ntapi_afl_set.c64
6 files changed, 661 insertions, 0 deletions
diff --git a/src/afl/ntapi_afl_connect.c b/src/afl/ntapi_afl_connect.c
new file mode 100644
index 0000000..1e7215a
--- /dev/null
+++ b/src/afl/ntapi_afl_connect.c
@@ -0,0 +1,335 @@
+/********************************************************/
+/* ntapi: Native API core library */
+/* Copyright (C) 2013--2017 Z. Gilboa */
+/* Released under GPLv2 and GPLv3; see COPYING.NTAPI. */
+/********************************************************/
+
+#include <psxtypes/psxtypes.h>
+#include <ntapi/nt_file.h>
+#include <ntapi/nt_string.h>
+#include <ntapi/nt_atomic.h>
+#include <ntapi/nt_port.h>
+#include <ntapi/nt_ipc.h>
+#include <ntapi/nt_afl.h>
+#include <ntapi/ntapi.h>
+#include "ntapi_impl.h"
+
+static const nt_guid g_aflpid = NT_IPC_GUID_AFLPID;
+static const wchar16_t p_aflpid[6] = NT_IPC_OBJDIR_PREFIX_AFLPID;
+
+static int32_t __aflctl_get_service_attr(
+ nt_rtdata * rtdata,
+ nt_tty_service_info * aflctl)
+{
+ nt_iosb iosb;
+
+ /* inherited runtime data? */
+ if (rtdata->aflctl_keys[0]) {
+ aflctl->attr.ver_major = 0;
+ aflctl->attr.ver_minor = 0;
+ aflctl->attr.options = 0;
+ aflctl->attr.flags = 0;
+
+ aflctl->attr.type = rtdata->aflctl_type;
+ aflctl->attr.subtype = rtdata->aflctl_subtype;
+
+ aflctl->attr.keys.key[0] = rtdata->aflctl_keys[0];
+ aflctl->attr.keys.key[1] = rtdata->aflctl_keys[1];
+ aflctl->attr.keys.key[2] = rtdata->aflctl_keys[2];
+ aflctl->attr.keys.key[3] = rtdata->aflctl_keys[3];
+ aflctl->attr.keys.key[4] = rtdata->aflctl_keys[4];
+ aflctl->attr.keys.key[5] = rtdata->aflctl_keys[5];
+
+ __ntapi->tt_guid_copy(
+ &aflctl->attr.guid,
+ &rtdata->aflctl_guid);
+
+ return NT_STATUS_SUCCESS;
+ }
+
+ /* obtain service info */
+ return __ntapi->tty_query_information_service(
+ 0,&iosb,aflctl,
+ &(nt_guid)NT_PORT_GUID_AFLCTL,
+ 0,0);
+}
+
+static int32_t __aflctl_server_connect(
+ nt_rtdata * rtdata,
+ nt_tty_service_info * aflctl)
+{
+ int32_t status;
+
+ /* already cononected? */
+ if (rtdata->haflctl)
+ return NT_STATUS_SUCCESS;
+
+ /* connect */
+ if ((status = __ntapi->ipc_connect_by_attr(
+ &rtdata->haflctl,
+ &aflctl->attr)))
+ return status;
+
+ /* update */
+ rtdata->aflctl_type = aflctl->attr.type;
+ rtdata->aflctl_subtype = aflctl->attr.subtype;
+
+ rtdata->aflctl_keys[0] = aflctl->attr.keys.key[0];
+ rtdata->aflctl_keys[1] = aflctl->attr.keys.key[1];
+ rtdata->aflctl_keys[2] = aflctl->attr.keys.key[2];
+ rtdata->aflctl_keys[3] = aflctl->attr.keys.key[3];
+ rtdata->aflctl_keys[4] = aflctl->attr.keys.key[4];
+ rtdata->aflctl_keys[5] = aflctl->attr.keys.key[5];
+
+ __ntapi->tt_guid_copy(
+ &rtdata->aflctl_guid,
+ &aflctl->attr.guid);
+
+ return NT_STATUS_SUCCESS;
+}
+
+static int32_t __aflpid_symlink_set(
+ nt_rtdata * rtdata,
+ nt_tty_service_info * aflctl)
+{
+ int32_t status;
+ void * hpiddir;
+ nt_port_name svcname;
+ nt_unicode_string str;
+
+ if (rtdata->haflpid)
+ return NT_STATUS_SUCCESS;
+
+ if (!rtdata->haflpiddir) {
+ if ((status = __ntapi->tt_open_ipc_object_directory(
+ &hpiddir,
+ NT_SEC_READ_CONTROL
+ | NT_DIRECTORY_QUERY
+ | NT_DIRECTORY_TRAVERSE
+ | NT_DIRECTORY_CREATE_OBJECT
+ | NT_DIRECTORY_CREATE_SUBDIRECTORY,
+ p_aflpid,&g_aflpid)))
+ return status;
+
+ if (at_locked_cas((intptr_t *)&rtdata->haflpiddir,0,(intptr_t)hpiddir))
+ __ntapi->zw_close(hpiddir);
+ }
+
+ __ntapi->tt_port_name_from_attr(
+ &svcname,&aflctl->attr);
+
+ str.strlen = (uint16_t)(__offsetof(nt_port_name,null_termination));
+ str.maxlen = sizeof(nt_port_name);
+ str.buffer = svcname.base_named_objects;
+
+ return __ntapi->tt_create_ipc_object_directory_entry(
+ &rtdata->haflpid,
+ NT_SEC_STANDARD_RIGHTS_ALL,
+ rtdata->haflpiddir,
+ 0,&str,
+ pe_get_current_process_id());
+
+}
+
+static int32_t __stdcall __afl_open(
+ void * hipc,
+ nt_afl_info * afl,
+ nt_iosb * iosb,
+ nt_guid * afldev,
+ uint32_t opcode)
+{
+ int32_t status;
+ nt_tty_port_msg msg;
+ nt_iosb siosb;
+ nt_tty_service_info aflctl;
+ nt_runtime_data * rtdata;
+
+ /* init */
+ rtdata = (__ntapi_internals())->rtdata;
+
+ /* aflctl service attributes */
+ if (!rtdata->haflpid)
+ if ((status = __aflctl_get_service_attr(rtdata,&aflctl)))
+ return status;
+
+ /* aflctl server */
+ if ((status = __aflctl_server_connect(rtdata,&aflctl)))
+ return status;
+
+ /* aflpid symlink */
+ if ((status = __aflpid_symlink_set(rtdata,&aflctl)))
+ return status;
+
+ /* hipc */
+ if (!hipc && (opcode == NT_TTY_AFL_ALLOC))
+ hipc = (__ntapi_internals())->rtdata->haflctl;
+
+ /* obtain afl info */
+ __ntapi->tt_aligned_block_memset(
+ &msg,0,sizeof(msg));
+
+ if (!iosb)
+ iosb = &siosb;
+
+ msg.header.msg_type = NT_LPC_NEW_MESSAGE;
+ msg.header.data_size = sizeof(nt_afl_info_msg) - sizeof(msg.header);
+ msg.header.msg_size = sizeof(msg);
+ msg.ttyinfo.opcode = opcode;
+
+ __ntapi->tt_guid_copy(
+ &msg.aflinfo.afldev,
+ afldev);
+
+ /* todo: device guid */
+
+ if ((status = __ntapi->zw_request_wait_reply_port(hipc,&msg,&msg)))
+ return status;
+ else if (msg.ttyinfo.status)
+ return msg.ttyinfo.status;
+
+ iosb->info = sizeof(msg.svcinfo);
+ iosb->status = NT_STATUS_SUCCESS;
+
+ /* new afl node? */
+ if (opcode == NT_TTY_AFL_ALLOC)
+ if ((status = __ntapi->ipc_connect_by_attr(
+ &hipc,&msg.svcinfo.attr)))
+ return status;
+
+ /* all done */
+ __ntapi->tt_aligned_block_memset(
+ (uintptr_t *)afl,
+ 0,sizeof(*afl));
+
+ afl->hport = hipc;
+
+ __ntapi->tt_guid_copy(
+ &afl->afldev,
+ afldev);
+
+ return NT_STATUS_SUCCESS;
+}
+
+
+int32_t __ntapi_afl_create(
+ __in void * hport,
+ __out nt_afl_info * afl,
+ __in nt_oa * oa,
+ __out nt_iosb * iosb)
+{
+ nt_guid afldev;
+
+ /* validate */
+ if (!oa->root_dir)
+ return NT_STATUS_DIRECTORY_SERVICE_REQUIRED;
+
+ if (!oa->obj_name)
+ return NT_STATUS_INVALID_PARAMETER;
+
+ if (oa->obj_name->strlen != sizeof(nt_guid_str_utf16))
+ return NT_STATUS_OBJECT_NAME_INVALID;
+
+ if (__ntapi->tt_string_to_guid_utf16(
+ (nt_guid_str_utf16 *)oa->obj_name->buffer,
+ &afldev))
+ return NT_STATUS_OBJECT_NAME_INVALID;
+
+ /* open afldev */
+ return __afl_open(
+ hport,afl,iosb,
+ &afldev,
+ NT_TTY_AFL_ALLOC);
+}
+
+
+int32_t __stdcall __ntapi_afl_open(
+ __in void * hport,
+ __out nt_afl_info * afl,
+ __in nt_oa * oa,
+ __out nt_iosb * iosb)
+{
+ int32_t status;
+ nt_guid afldev;
+ void * hsymlink;
+ nt_oa ipcoa;
+ void * hipc;
+ nt_rtdata * rtdata;
+ nt_tty_service_info aflctl;
+
+ /* init */
+ rtdata = (__ntapi_internals())->rtdata;
+
+ /* validate */
+ if (!oa->root_dir)
+ return NT_STATUS_DIRECTORY_SERVICE_REQUIRED;
+
+ if (!oa->obj_name)
+ return NT_STATUS_INVALID_PARAMETER;
+
+ if (oa->obj_name->strlen != sizeof(nt_guid_str_utf16))
+ return NT_STATUS_OBJECT_NAME_INVALID;
+
+ if (__ntapi->tt_string_to_guid_utf16(
+ (nt_guid_str_utf16 *)oa->obj_name->buffer,
+ &afldev))
+ return NT_STATUS_OBJECT_NAME_INVALID;
+
+ /* open symlink */
+ ipcoa.len = sizeof(ipcoa);
+ ipcoa.root_dir = oa->root_dir;
+ ipcoa.obj_name = oa->obj_name;
+ ipcoa.obj_attr = 0;
+ ipcoa.sec_desc = oa->sec_desc;
+ ipcoa.sec_qos = oa->sec_qos;
+
+ status = __ntapi->zw_open_symbolic_link_object(
+ &hsymlink,
+ NT_SYMBOLIC_LINK_QUERY,
+ &ipcoa);
+
+ switch (status) {
+ case NT_STATUS_SUCCESS:
+ break;
+
+ case NT_STATUS_OBJECT_NAME_NOT_FOUND:
+ case NT_STATUS_OBJECT_PATH_NOT_FOUND:
+ if (oa->obj_attr & NT_OBJ_OPENIF)
+ return __afl_open(
+ hport,afl,iosb,
+ &afldev,
+ NT_TTY_AFL_ALLOC);
+ else
+ return status;
+
+ default:
+ return status;
+ }
+
+ /* aflctl service attributes */
+ if (!rtdata->haflpid)
+ if ((status = __aflctl_get_service_attr(rtdata,&aflctl)))
+ return status;
+
+ /* aflctl server */
+ if ((status = __aflctl_server_connect(rtdata,&aflctl)))
+ return status;
+
+ /* aflpid symlink */
+ if ((status = __aflpid_symlink_set(rtdata,&aflctl)))
+ return status;
+
+ /* ipc connect */
+ status = __ntapi->ipc_connect_by_symlink(
+ &hipc,hsymlink);
+
+ __ntapi->zw_close(
+ hsymlink);
+
+ if (status)
+ return status;
+
+ return __afl_open(
+ hipc,afl,iosb,
+ &afldev,
+ NT_TTY_AFL_OPEN);
+}
diff --git a/src/afl/ntapi_afl_fcntl.c b/src/afl/ntapi_afl_fcntl.c
new file mode 100644
index 0000000..3c60f54
--- /dev/null
+++ b/src/afl/ntapi_afl_fcntl.c
@@ -0,0 +1,42 @@
+/********************************************************/
+/* ntapi: Native API core library */
+/* Copyright (C) 2013--2017 Z. Gilboa */
+/* Released under GPLv2 and GPLv3; see COPYING.NTAPI. */
+/********************************************************/
+
+#include <psxtypes/psxtypes.h>
+#include <ntapi/nt_file.h>
+#include <ntapi/nt_string.h>
+#include <ntapi/nt_atomic.h>
+#include <ntapi/nt_port.h>
+#include <ntapi/nt_ipc.h>
+#include <ntapi/nt_afl.h>
+#include <ntapi/ntapi.h>
+#include "ntapi_impl.h"
+
+int32_t __stdcall __ntapi_afl_fcntl(
+ __in nt_afl_info * afl,
+ __in void * hevent __optional,
+ __in nt_io_apc_routine * apc_routine __optional,
+ __in void * apc_context __optional,
+ __out nt_iosb * iosb,
+ __in uint32_t fs_control_code,
+ __in void * input_buffer __optional,
+ __in uint32_t input_buffer_length,
+ __out void * output_buffer __optional,
+ __in uint32_t output_buffer_length)
+{
+ (void)afl;
+ (void)hevent;
+ (void)apc_routine;
+ (void)apc_context;
+ (void)iosb;
+ (void)fs_control_code;
+ (void)input_buffer;
+ (void)input_buffer_length;
+ (void)output_buffer;
+ (void)output_buffer_length;
+
+ /* internal only */
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
diff --git a/src/afl/ntapi_afl_fdio.c b/src/afl/ntapi_afl_fdio.c
new file mode 100644
index 0000000..d236964
--- /dev/null
+++ b/src/afl/ntapi_afl_fdio.c
@@ -0,0 +1,61 @@
+/********************************************************/
+/* ntapi: Native API core library */
+/* Copyright (C) 2013--2017 Z. Gilboa */
+/* Released under GPLv2 and GPLv3; see COPYING.NTAPI. */
+/********************************************************/
+
+#include <psxtypes/psxtypes.h>
+#include <ntapi/nt_file.h>
+#include <ntapi/nt_string.h>
+#include <ntapi/nt_atomic.h>
+#include <ntapi/nt_port.h>
+#include <ntapi/nt_ipc.h>
+#include <ntapi/nt_afl.h>
+#include <ntapi/ntapi.h>
+#include "ntapi_impl.h"
+
+static int32_t __afl_fdio(
+ nt_afl_info * afl,
+ nt_iosb * iosb,
+ uint32_t opcode)
+{
+ int32_t status;
+ nt_afl_info_msg msg;
+
+ /* validate */
+ if (!iosb)
+ return NT_STATUS_INVALID_PARAMETER;
+
+ /* msg */
+ __ntapi->tt_aligned_block_memset(
+ &msg,0,sizeof(msg));
+
+ msg.header.msg_type = NT_LPC_NEW_MESSAGE;
+ msg.header.data_size = sizeof(msg.data);
+ msg.header.msg_size = sizeof(msg);
+ msg.data.ttyinfo.opcode = opcode;
+
+ if ((status = __ntapi->zw_request_wait_reply_port(afl->hport,&msg,&msg)))
+ return status;
+ else if (msg.data.ttyinfo.status)
+ return msg.data.ttyinfo.status;
+
+ iosb->status = NT_STATUS_SUCCESS;
+ iosb->info = 0;
+
+ return NT_STATUS_SUCCESS;
+}
+
+int32_t __stdcall __ntapi_afl_cancel(
+ __in nt_afl_info * afl,
+ __out nt_iosb * iosb)
+{
+ return __afl_fdio(afl,iosb,NT_TTY_AFL_CANCEL);
+}
+
+int32_t __stdcall __ntapi_afl_free(
+ __in nt_afl_info * afl,
+ __out nt_iosb * iosb)
+{
+ return __afl_fdio(afl,iosb,NT_TTY_AFL_FREE);
+}
diff --git a/src/afl/ntapi_afl_ioctl.c b/src/afl/ntapi_afl_ioctl.c
new file mode 100644
index 0000000..07d07cf
--- /dev/null
+++ b/src/afl/ntapi_afl_ioctl.c
@@ -0,0 +1,92 @@
+/********************************************************/
+/* ntapi: Native API core library */
+/* Copyright (C) 2013--2017 Z. Gilboa */
+/* Released under GPLv2 and GPLv3; see COPYING.NTAPI. */
+/********************************************************/
+
+#include <psxtypes/psxtypes.h>
+#include <ntapi/nt_file.h>
+#include <ntapi/nt_string.h>
+#include <ntapi/nt_atomic.h>
+#include <ntapi/nt_port.h>
+#include <ntapi/nt_ipc.h>
+#include <ntapi/nt_afl.h>
+#include <ntapi/ntapi.h>
+#include "ntapi_impl.h"
+
+int32_t __stdcall __ntapi_afl_ioctl(
+ __in nt_afl_info * afl,
+ __in void * hevent __optional,
+ __in nt_io_apc_routine * apc_routine __optional,
+ __in void * apc_context __optional,
+ __out nt_iosb * iosb,
+ __in uint32_t io_control_code,
+ __in void * input_buffer __optional,
+ __in uint32_t input_buffer_length,
+ __out void * output_buffer __optional,
+ __in uint32_t output_buffer_length)
+{
+ int32_t status;
+ nt_afl_info_msg msg;
+ nt_afl_op * aflop;
+
+ /* validate */
+ if (io_control_code)
+ return NT_STATUS_NOT_SUPPORTED;
+
+ else if (!iosb)
+ return NT_STATUS_INVALID_PARAMETER;
+
+ else if (!(aflop = (nt_afl_op *)input_buffer))
+ return NT_STATUS_INVALID_PARAMETER;
+
+ else if (input_buffer_length != sizeof(nt_afl_op))
+ return NT_STATUS_INFO_LENGTH_MISMATCH;
+
+ if (output_buffer)
+ if (output_buffer_length < sizeof(nt_afl_op))
+ return NT_STATUS_BUFFER_TOO_SMALL;
+
+ /* msg */
+ __ntapi->tt_aligned_block_memset(
+ &msg,0,sizeof(msg));
+
+ __ntapi->tt_guid_copy(
+ &msg.data.aflinfo.afldev,
+ &afl->afldev);
+
+ msg.header.msg_type = NT_LPC_NEW_MESSAGE;
+ msg.header.data_size = sizeof(msg.data);
+ msg.header.msg_size = sizeof(msg);
+ msg.data.ttyinfo.opcode = NT_TTY_AFL_IOCTL;
+
+ msg.data.aflinfo.l_fileid = aflop->l_fileid;
+ msg.data.aflinfo.l_start = aflop->l_start;
+ msg.data.aflinfo.l_len = aflop->l_len;
+ msg.data.aflinfo.l_pid = aflop->l_pid;
+ msg.data.aflinfo.l_cmd = aflop->l_cmd;
+
+ msg.data.aflinfo.hevent = hevent;
+ msg.data.aflinfo.apc_routine = apc_routine;
+ msg.data.aflinfo.apc_context = apc_context;
+ msg.data.aflinfo.riosb = iosb;
+
+ if ((status = __ntapi->zw_request_wait_reply_port(afl->hport,&msg,&msg)))
+ return status;
+ else if (msg.data.ttyinfo.status)
+ return msg.data.ttyinfo.status;
+
+ iosb->status = NT_STATUS_SUCCESS;
+ iosb->info = msg.data.aflinfo.ntiosb.info;
+
+ if (msg.data.aflinfo.ntiosb.info && output_buffer) {
+ aflop = (nt_afl_op *)output_buffer;
+ aflop->l_fileid = msg.data.aflinfo.l_fileid;
+ aflop->l_start = msg.data.aflinfo.l_start;
+ aflop->l_len = msg.data.aflinfo.l_len;
+ aflop->l_pid = msg.data.aflinfo.l_pid;
+ aflop->l_cmd = msg.data.aflinfo.l_cmd;
+ }
+
+ return NT_STATUS_SUCCESS;
+}
diff --git a/src/afl/ntapi_afl_query.c b/src/afl/ntapi_afl_query.c
new file mode 100644
index 0000000..0128ac6
--- /dev/null
+++ b/src/afl/ntapi_afl_query.c
@@ -0,0 +1,67 @@
+/********************************************************/
+/* ntapi: Native API core library */
+/* Copyright (C) 2013--2017 Z. Gilboa */
+/* Released under GPLv2 and GPLv3; see COPYING.NTAPI. */
+/********************************************************/
+
+#include <psxtypes/psxtypes.h>
+#include <ntapi/nt_file.h>
+#include <ntapi/nt_string.h>
+#include <ntapi/nt_atomic.h>
+#include <ntapi/nt_port.h>
+#include <ntapi/nt_ipc.h>
+#include <ntapi/nt_afl.h>
+#include <ntapi/ntapi.h>
+#include "ntapi_impl.h"
+
+int32_t __stdcall __ntapi_afl_query(
+ __in nt_afl_info * afl,
+ __out nt_io_status_block * iosb,
+ __out void * afl_info,
+ __in uint32_t afl_info_length,
+ __in int32_t afl_info_class)
+{
+ int32_t status;
+ nt_afl_info_msg msg;
+
+ /* validate */
+ if (!iosb)
+ return NT_STATUS_INVALID_PARAMETER;
+
+ else if (!afl_info)
+ return NT_STATUS_INVALID_PARAMETER;
+
+ else if (afl_info_length < sizeof(msg.data.aflinfo))
+ return NT_STATUS_BUFFER_TOO_SMALL;
+
+ else if (afl_info_class)
+ return NT_STATUS_INVALID_INFO_CLASS;
+
+ /* msg */
+ __ntapi->tt_aligned_block_memset(
+ &msg,0,sizeof(msg));
+
+ msg.header.msg_type = NT_LPC_NEW_MESSAGE;
+ msg.header.data_size = sizeof(msg.data);
+ msg.header.msg_size = sizeof(msg);
+ msg.data.ttyinfo.opcode = NT_TTY_AFL_QUERY;
+
+ if ((status = __ntapi->zw_request_wait_reply_port(afl->hport,&msg,&msg)))
+ return status;
+ else if (msg.data.ttyinfo.status)
+ return msg.data.ttyinfo.status;
+
+ /* reply */
+ if (msg.header.data_size != sizeof(msg.data))
+ return NT_STATUS_UNEXPECTED_IO_ERROR;
+
+ __ntapi->tt_generic_memcpy(
+ afl_info,
+ &msg.data.aflinfo,
+ sizeof(msg.data.aflinfo));
+
+ iosb->status = NT_STATUS_SUCCESS;
+ iosb->info = sizeof(msg.data.aflinfo);
+
+ return NT_STATUS_SUCCESS;
+}
diff --git a/src/afl/ntapi_afl_set.c b/src/afl/ntapi_afl_set.c
new file mode 100644
index 0000000..c3aecc4
--- /dev/null
+++ b/src/afl/ntapi_afl_set.c
@@ -0,0 +1,64 @@
+/********************************************************/
+/* ntapi: Native API core library */
+/* Copyright (C) 2013--2017 Z. Gilboa */
+/* Released under GPLv2 and GPLv3; see COPYING.NTAPI. */
+/********************************************************/
+
+#include <psxtypes/psxtypes.h>
+#include <ntapi/nt_file.h>
+#include <ntapi/nt_string.h>
+#include <ntapi/nt_atomic.h>
+#include <ntapi/nt_port.h>
+#include <ntapi/nt_ipc.h>
+#include <ntapi/nt_afl.h>
+#include <ntapi/ntapi.h>
+#include "ntapi_impl.h"
+
+int32_t __stdcall __ntapi_afl_set(
+ __in nt_afl_info * afl,
+ __out nt_io_status_block * iosb,
+ __in void * afl_info,
+ __in uint32_t afl_info_length,
+ __in int32_t afl_info_class)
+{
+ int32_t status;
+ nt_afl_info_msg msg;
+
+ /* validate */
+ if (!iosb)
+ return NT_STATUS_INVALID_PARAMETER;
+
+ else if (!afl_info)
+ return NT_STATUS_INVALID_PARAMETER;
+
+ else if (afl_info_length != sizeof(msg.data.aflinfo))
+ return NT_STATUS_INFO_LENGTH_MISMATCH;
+
+ else if (afl_info_class)
+ return NT_STATUS_INVALID_INFO_CLASS;
+
+ /* msg */
+ __ntapi->tt_aligned_block_memset(
+ &msg,0,sizeof(msg));
+
+ msg.header.msg_type = NT_LPC_NEW_MESSAGE;
+ msg.header.data_size = sizeof(msg.data);
+ msg.header.msg_size = sizeof(msg);
+ msg.data.ttyinfo.opcode = NT_TTY_AFL_SET;
+
+ __ntapi->tt_generic_memcpy(
+ &msg.data.aflinfo,
+ afl_info,
+ sizeof(msg.data.aflinfo));
+
+ if ((status = __ntapi->zw_request_wait_reply_port(afl->hport,&msg,&msg)))
+ return status;
+ else if (msg.data.ttyinfo.status)
+ return msg.data.ttyinfo.status;
+
+ /* reply */
+ iosb->status = NT_STATUS_SUCCESS;
+ iosb->info = 0;
+
+ return NT_STATUS_SUCCESS;
+}