/********************************************************/
/* 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/ntapi.h>
#include "ntapi_impl.h"
static int32_t __ipc_connect_return(
intptr_t * hlock,
int32_t status)
{
at_store(hlock,0);
return status;
}
static int32_t __ipc_connect_by_attr(
void ** hport,
const nt_port_attr * attr,
nt_unicode_string * str,
void * hconn,
__out void ** hsection,
__out void ** secaddr,
__out size_t * secsize)
{
int32_t status;
struct dalist_node_ex * node;
const nt_port_attr * conn;
nt_port_attr * nconn;
nt_ipc_conn * ipc;
intptr_t * hlock;
ntapi_internals * __internals;
/* init */
__internals = __ntapi_internals();
/* lock */
hlock = &(__internals->hlock);
if (at_locked_cas(hlock,0,1))
return NT_STATUS_RESOURCE_NOT_OWNED;
/* already connected? */
node = (struct dalist_node_ex *)__internals->ipc_conns.head;
for (; node; node=node->next) {
ipc = (nt_ipc_conn *)&node->dblock;
conn = &ipc->attr;
if ((attr->keys.key[0] == conn->keys.key[0])
&& (attr->keys.key[1] == conn->keys.key[1])
&& (attr->keys.key[2] == conn->keys.key[2])
&& (attr->keys.key[3] == conn->keys.key[3])
&& (attr->keys.key[4] == conn->keys.key[4])
&& (attr->keys.key[5] == conn->keys.key[5])
&& !__ntapi->tt_guid_compare(
&attr->guid,
&conn->guid)) {
/* already connected */
if (hconn)
return __ipc_connect_return(
hlock,
((uintptr_t)hconn == node->key)
? NT_STATUS_SUCCESS
: NT_STATUS_CONTEXT_MISMATCH);
*hport = (void *)node->key;
*hsection = ipc->hsection;
*secaddr = ipc->secaddr;
*secsize = ipc->secsize;
return __ipc_connect_return(hlock,NT_STATUS_SUCCESS);
}
}
/* allocate list node */
if ((status = dalist_get_free_node(
&__internals->ipc_conns,
(void **)&node)))
return __ipc_connect_return(hlock,status);
/* connect as needed */
if (!hconn) {
status = __ntapi->zw_connect_port(
&hconn,str,0,0,0,0,0,0);
if (status) {
dalist_deposit_free_node(
&__internals->ipc_conns,
node);
return __ipc_connect_return(hlock,status);
}
}
/* add connection */
node->key = (uintptr_t)hconn;
ipc = (nt_ipc_conn *)&node->dblock;
nconn = &ipc->attr;
__ntapi->tt_aligned_block_memcpy(
(uintptr_t *)nconn,
(uintptr_t *)attr,
sizeof(nt_port_attr));
ipc->hsection = 0;
ipc->secaddr = 0;
ipc->secsize = 0;
dalist_insert_node_by_key(
&__internals->ipc_conns,
node);
/* all done */
*hport = hconn;
*hsection = 0;
*secaddr = 0;
*secsize = 0;
return __ipc_connect_return(hlock,NT_STATUS_SUCCESS);
}
int32_t __stdcall __ntapi_ipc_connect_section_by_attr(
__out void ** hport,
__in nt_port_attr * attr,
__out void ** hsection,
__out void ** secaddr,
__out size_t * secsize)
{
nt_port_name name;
nt_unicode_string str;
__ntapi->tt_port_name_from_attr(
&name,attr);
str.strlen = ((size_t)&(((nt_port_name *)0)->null_termination));
str.maxlen = 0;
str.buffer = &name.base_named_objects[0];
return __ipc_connect_by_attr(
hport,attr,&str,0,
hsection,secaddr,secsize);
}
int32_t __stdcall __ntapi_ipc_connect_section_by_name(
__out void ** hport,
__in nt_port_name * name,
__out void ** hsection,
__out void ** secaddr,
__out size_t * secsize)
{
int32_t status;
nt_port_attr attr;
nt_unicode_string str;
if ((status = __ntapi->tt_port_attr_from_name(&attr,name)))
return status;
str.strlen = ((size_t)&(((nt_port_name *)0)->null_termination));
str.maxlen = 0;
str.buffer = &name->base_named_objects[0];
return __ipc_connect_by_attr(
hport,&attr,&str,0,
hsection,secaddr,secsize);
}
int32_t __stdcall __ntapi_ipc_connect_section_by_symlink(
__out void ** hport,
__in void * hsymlink,
__out void ** hsection,
__out void ** secaddr,
__out size_t * secsize)
{
int32_t status;
nt_port_attr attr;
nt_port_name * name;
size_t namelen;
uintptr_t buffer[512/sizeof(uintptr_t)];
nt_unicode_string * str;
str = (nt_unicode_string *)buffer;
str->strlen = 0;
str->maxlen = sizeof(buffer) - sizeof(nt_unicode_string);
str->buffer = (wchar16_t *)&str[1];
if ((status = __ntapi->zw_query_symbolic_link_object(
hsymlink,str,&namelen)))
return status;
if (str->strlen != ((size_t)&(((nt_port_name *)0)->null_termination)))
return NT_STATUS_INVALID_PORT_ATTRIBUTES;
name = (nt_port_name *)str->buffer;
if ((status = __ntapi->tt_port_attr_from_name(&attr,name)))
return status;
return __ipc_connect_by_attr(
hport,&attr,str,0,
hsection,secaddr,secsize);
}
int32_t __stdcall __ntapi_ipc_connect_section_by_port(
__in void * hconn,
__in nt_port_attr * attr,
__out void ** hsection,
__out void ** secaddr,
__out size_t * secsize)
{
return __ipc_connect_by_attr(
&(void *){0},attr,0,hconn,
hsection,secaddr,secsize);
}
int32_t __stdcall __ntapi_ipc_connect_by_attr(
__out void ** hport,
__in nt_port_attr * attr)
{
return __ntapi_ipc_connect_section_by_attr(
hport,attr,
&(void *){0},
&(void *){0},
&(size_t){0});
}
int32_t __stdcall __ntapi_ipc_connect_by_name(
__out void ** hport,
__in nt_port_name * name)
{
return __ntapi_ipc_connect_section_by_name(
hport,name,
&(void *){0},
&(void *){0},
&(size_t){0});
}
int32_t __stdcall __ntapi_ipc_connect_by_symlink(
__out void ** hport,
__in void * hsymlink)
{
return __ntapi_ipc_connect_section_by_symlink(
hport,hsymlink,
&(void *){0},
&(void *){0},
&(size_t){0});
}
int32_t __stdcall __ntapi_ipc_connect_by_port(
__in void * hconn,
__in nt_port_attr * attr)
{
return __ntapi_ipc_connect_section_by_port(
hconn,attr,
&(void *){0},
&(void *){0},
&(size_t){0});
}
int __ntapi_ipc_page_alloc(
struct dalist_ex * dlist,
void ** addr,
size_t * alloc_size)
{
int32_t status;
ntapi_internals * __internals;
__internals = __ntapi_internals();
if (__internals->ipc_page == __NT_IPC_PAGES)
return NT_STATUS_QUOTA_EXCEEDED;
if ((status = __ntapi->zw_allocate_virtual_memory(
NT_CURRENT_PROCESS_HANDLE,
addr,0,alloc_size,
NT_MEM_COMMIT,
NT_PAGE_READWRITE)))
return status;
dalist_deposit_memory_block(
dlist,*addr,*alloc_size);
__internals->ipc_pages[__internals->ipc_page++] = *addr;
return 0;
}
int32_t __stdcall __ntapi_ipc_init_section_by_port(
__in void * hconn,
__out void ** hsection,
__out void ** secaddr,
__out size_t * secsize)
{
int32_t status;
nt_tty_section_info secinfo;
nt_iosb iosb;
struct dalist_node_ex * node;
nt_ipc_conn * ipc;
void * addr;
size_t size;
ntapi_internals * __internals;
/* init */
__internals = __ntapi_internals();
/* lock */
if (at_locked_cas(&__internals->hlock,0,1))
return NT_STATUS_RESOURCE_NOT_OWNED;
/* connection node */
if ((status = dalist_get_node_by_key(
&__internals->ipc_conns,
&node,(uintptr_t)hconn,
DALIST_NODE_TYPE_EXISTING,
&(uintptr_t){0})))
return __ipc_connect_return(
&__internals->hlock,
NT_STATUS_INTERNAL_ERROR);
else if (!node)
return NT_STATUS_NOT_FOUND;
else
ipc = (nt_ipc_conn *)&node->dblock;
/* already mapped? */
if (ipc->secaddr)
return __ipc_connect_return(
&__internals->hlock,
NT_STATUS_SUCCESS);
/* section info */
if ((status = __ntapi->tty_query_information_section(
hconn,&iosb,&secinfo,0)))
return __ipc_connect_return(
&__internals->hlock,
status);
/* map section */
addr = 0;
size = 0;
if ((status = __ntapi->zw_map_view_of_section(
secinfo.section,
NT_CURRENT_PROCESS_HANDLE,
&addr,0,
secinfo.section_size,0,&size,
NT_VIEW_UNMAP,0,
NT_PAGE_READWRITE)))
return __ipc_connect_return(
&__internals->hlock,
status);
/* update */
*hsection = secinfo.section;
*secaddr = addr;
*secsize = size;
/* all done */
return __ipc_connect_return(
&__internals->hlock,
NT_STATUS_SUCCESS);
}
int32_t __stdcall __ntapi_ipc_disconnect_unmap_section_by_port(
__in void * hconn)
{
int32_t status;
struct dalist_node_ex * node;
nt_ipc_conn * ipc;
ntapi_internals * __internals;
/* init */
__internals = __ntapi_internals();
/* lock */
if (at_locked_cas(&__internals->hlock,0,1))
return NT_STATUS_RESOURCE_NOT_OWNED;
/* connection node */
if ((status = dalist_get_node_by_key(
&__internals->ipc_conns,
&node,(uintptr_t)hconn,
DALIST_NODE_TYPE_EXISTING,
&(uintptr_t){0})))
return __ipc_connect_return(
&__internals->hlock,
NT_STATUS_INTERNAL_ERROR);
else if (!node)
return __ipc_connect_return(
&__internals->hlock,
NT_STATUS_NOT_FOUND);
else
ipc = (nt_ipc_conn *)&node->dblock;
/* unmap section */
if (ipc->secaddr)
__ntapi->zw_unmap_view_of_section(
NT_CURRENT_PROCESS_HANDLE,
ipc->secaddr);
/* close section */
if (ipc->hsection)
__ntapi->zw_close(ipc->hsection);
/* disconnect */
__ntapi->zw_close(hconn);
/* remove node */
dalist_discard_node(&__internals->ipc_conns,node);
return __ipc_connect_return(
&__internals->hlock,
NT_STATUS_SUCCESS);
}