#include <mach/mach_types.h>
#include <sys/kernel_types.h>
#include <sys/kpi_socket.h>
#include <sys/kpi_socketfilter.h>
#include <sys/kpi_mbuf.h>
#include <sys/malloc.h>
#include <sys/socketvar.h>
#include <sys/queue.h>
#include <sys/mbuf.h>
#include <sys/param.h>
#include <netinet/in.h>
#include <libkern/libkern.h>
#include <libkern/OSMalloc.h>
#include <stdint.h>
#include <IOKit/IOLib.h>
#include <stdarg.h>
#define DEBUG_ASSERT_COMPONENT_NAME_STRING "tlsnke"
#define DEBUG_ASSERT_PRODUCTION_CODE 0
#include <AssertMacros.h>
#include "SSLRecordInternal.h"
#include "tlsnke.h"
#include <net/if_utun_crypto_dtls.h>
#define MYBUNDLEID "com.apple.kext.tlsnke"
#define TLS_DEBUG 0
#define TLS_TEST 0
typedef struct dtls_ctx *dtls_ctx_t;
#define N_DTLS_MAX 1
static dtls_ctx_t g_dtls_contexts[N_DTLS_MAX];
static void clear_dtls_contexts(void)
{
memset(g_dtls_contexts, 0, sizeof(g_dtls_contexts));
}
static dtls_ctx_t get_dtls_context(int dtls_handle)
{
if(dtls_handle>=0 && dtls_handle<N_DTLS_MAX) {
return g_dtls_contexts[dtls_handle];
} else {
return NULL;
}
}
static int register_dtls_context(dtls_ctx_t dtls_ref)
{
int i;
for(i=0; i<N_DTLS_MAX; i++) {
if(g_dtls_contexts[i]==NULL) {
g_dtls_contexts[i]=dtls_ref;
return i;
}
}
return -1;
}
static int unregister_dtls_context(dtls_ctx_t dtls_ref)
{
int i;
for(i=0; i<N_DTLS_MAX; i++) {
if(g_dtls_contexts[i]==dtls_ref) {
g_dtls_contexts[i]=NULL;
return i;
}
}
return -1;
}
static void
tls_printf(const char *fmt, ...)
{
#if TLS_DEBUG
va_list listp;
char log_buffer[252];
log_buffer[250]='\n';
log_buffer[251]=0;
va_start(listp, fmt);
vsnprintf(log_buffer, sizeof(log_buffer)-2, fmt, listp);
IOLog("%s", log_buffer);
va_end(listp);
#endif
}
static void
tls_dump(const unsigned char *p, size_t len)
{
#if TLS_DEBUG
size_t i;
for(i=0; i<len; i++) {
tls_printf("%02x ", p[i]);
if(i%0x1F==0x1F)
tls_printf("\n");
}
tls_printf("\n");
#endif
}
static OSMallocTag gOSMallocTag;
struct PktQueueItem {
STAILQ_ENTRY(PktQueueItem) next;
mbuf_t data;
sflt_data_flag_t flags;
};
struct dtls_ctx {
socket_t socket;
bool has_from;
struct sockaddr from;
bool has_to;
struct sockaddr to;
struct utun_pcb *utun_ref;
bool wait_for_key;
SSLRecordContextRef ssl_ctx;
STAILQ_HEAD(, PktQueueItem) in_queue;
size_t in_off;
#ifdef TLS_TEST
bool queue_to_tlsnkedev;
#endif
};
#if TLS_TEST
static int tlsnkedev_queue(mbuf_t m);
#endif
static int utun_data_packet_input(struct utun_pcb *utun_ref, mbuf_t data)
{
tls_printf("tlsnke():%s\n",__FUNCTION__);
return utun_pkt_dtls_input(utun_ref, &data, 0);
}
static void utun_disable_dtls(struct utun_pcb *utun_ref)
{
tls_printf("tlsnke():%s\n",__FUNCTION__);
}
static
int DTLSIOReadFunc (SSLIOConnectionRef connection, void *data, size_t *dataLength)
{
dtls_ctx_t dtls_ref = connection;
struct PktQueueItem *in_q = STAILQ_FIRST(&dtls_ref->in_queue);
size_t avail;
size_t len = *dataLength;
int rc = 0;
check(dtls_ref);
check(data);
check(dataLength);
if(in_q==NULL) {
*dataLength=0;
return errSSLRecordWouldBlock;
}
avail = mbuf_pkthdr_len(in_q->data)-dtls_ref->in_off;
tls_printf("tlsnke(%p):%s - avail=%d wants=%d\n", dtls_ref, __FUNCTION__, avail, *dataLength);
if(len>avail) {
check(0);
len = avail;
}
require_noerr_action(mbuf_copydata(in_q->data, dtls_ref->in_off, *dataLength, data), out, rc=errSSLRecordInternal);
*dataLength = len;
if(len==avail) {
STAILQ_REMOVE_HEAD(&dtls_ref->in_queue, next);
mbuf_freem(in_q->data);
OSFree(in_q, sizeof(struct PktQueueItem), gOSMallocTag);
dtls_ref->in_off=0;
} else {
dtls_ref->in_off += len;
}
out:
return rc;
}
static
int DTLSIOWriteFunc (SSLIOConnectionRef connection, const void *data, size_t *dataLength)
{
dtls_ctx_t dtls_ref = connection;
mbuf_t out_mbuf=NULL;
check(dtls_ref);
require_noerr(mbuf_allocpacket(M_NOWAIT, *dataLength, NULL, &out_mbuf), fail);
require(out_mbuf, fail);
require_noerr(mbuf_copyback(out_mbuf, 0, *dataLength, data, M_NOWAIT), fail);
return sock_inject_data_out(dtls_ref->socket, dtls_ref->has_to?&dtls_ref->to:NULL, out_mbuf, NULL, 0);
fail:
if(out_mbuf)
mbuf_freem(out_mbuf);
return errSSLRecordInternal;
}
static
dtls_ctx_t dtls_create_context(socket_t so)
{
dtls_ctx_t dtls_ref;
dtls_ref = (dtls_ctx_t)OSMalloc(sizeof(struct dtls_ctx), gOSMallocTag);
require(dtls_ref, fail);
memset(dtls_ref, 0, sizeof(struct dtls_ctx));
dtls_ref->socket=so;
STAILQ_INIT(&dtls_ref->in_queue);
dtls_ref->ssl_ctx = SSLCreateInternalRecordLayer(true);
require(dtls_ref->ssl_ctx, fail);
SSLSetInternalRecordLayerIOFuncs(dtls_ref->ssl_ctx, DTLSIOReadFunc, DTLSIOWriteFunc);
SSLSetInternalRecordLayerConnection(dtls_ref->ssl_ctx, dtls_ref);
return dtls_ref;
fail:
if(dtls_ref)
OSFree(dtls_ref, sizeof(struct dtls_ctx), gOSMallocTag);
return NULL;
}
static
void dtls_free_context(dtls_ctx_t dtls_ref)
{
if(dtls_ref->utun_ref) {
utun_disable_dtls(dtls_ref->utun_ref);
}
SSLDestroyInternalRecordLayer(dtls_ref->ssl_ctx);
unregister_dtls_context(dtls_ref);
OSFree(dtls_ref, sizeof(struct dtls_ctx), gOSMallocTag);
}
static
tls_record_hdr_t dtls_get_header(mbuf_t *control)
{
struct cmsghdr *cm;
tls_record_hdr_t hdr;
if(control==NULL)
return NULL;
if((*control)==NULL)
return NULL;
if (mbuf_next(*control))
return NULL;
if (mbuf_len(*control) < CMSG_LEN(sizeof(struct tls_record_hdr)))
return NULL;
cm = mbuf_data(*control);
if(cm==NULL)
return NULL;
hdr=(tls_record_hdr_t)CMSG_DATA(cm);
return hdr;
}
static
int dtls_process_output_packet(dtls_ctx_t dtls_ref, mbuf_t data, tls_record_hdr_t hdr)
{
SSLRecord rec;
size_t len = mbuf_pkthdr_len(data);
errno_t err;
int rc = errSSLRecordInternal;
require(len<UINT32_MAX, out);
rec.contents.data = OSMalloc((uint32_t)len, gOSMallocTag);
rec.contents.length = len;
require(rec.contents.data, out);
rec.contentType = hdr->content_type;
rec.protocolVersion = hdr->protocol_version;
tls_printf("tlsnke(%p):%s ct=%d, pv=%04x, len=%d\n", dtls_ref, __FUNCTION__, rec.contentType, rec.protocolVersion, len);
err = mbuf_copydata(data, 0, len, rec.contents.data);
require_noerr(err, out);
rc=SSLRecordLayerInternal.write(dtls_ref->ssl_ctx, rec);
out:
if(rec.contents.data)
OSFree(rec.contents.data, (uint32_t)len, gOSMallocTag);
return rc;
}
static void dtls_process_incoming_queue(dtls_ctx_t dtls_ref)
{
SSLRecord rec;
struct cmsghdr *cmsg;
tls_record_hdr_t hdr;
size_t cbuf_len = CMSG_SPACE(sizeof(*hdr));
uint8_t *cbuf;
int rc;
errno_t err;
mbuf_t data;
mbuf_t control;
struct sockaddr *from;
tls_printf("tlsnke(%p):%s \n", dtls_ref, __FUNCTION__);
rc=0;
while(rc==0) {
rc=SSLRecordLayerInternal.read(dtls_ref->ssl_ctx, &rec);
if(rc)
break;
check_noerr(mbuf_get(M_NOWAIT, MBUF_TYPE_CONTROL, &control));
check(mbuf_maxlen(control)>=cbuf_len);
mbuf_setlen(control, cbuf_len);
cbuf = mbuf_data(control);
cmsg = (struct cmsghdr *)cbuf;
cmsg->cmsg_len = CMSG_LEN(sizeof(*hdr));
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_TLS_HEADER;
hdr = (tls_record_hdr_t)CMSG_DATA(cmsg);
hdr->content_type = rec.contentType;
hdr->protocol_version = rec.protocolVersion;
check_noerr(mbuf_allocpacket(M_NOWAIT, rec.contents.length, NULL, &data));
check_noerr(mbuf_copyback(data, 0, rec.contents.length, rec.contents.data, M_NOWAIT));
SSLRecordLayerInternal.free(dtls_ref->ssl_ctx, rec);
if(hdr->content_type==SSL_RecordTypeChangeCipher) {
tls_printf("tlsnke(%p):%s got a ChangeCipher message\n", dtls_ref, __FUNCTION__);
dtls_ref->wait_for_key=true;
}
if(dtls_ref->has_from)
from=&dtls_ref->from;
else
from=NULL;
tls_printf("tlsnke(%p):%s injecting packet d=%p c=%p h=%p, from=%p, flags=0x%x\n", dtls_ref, __FUNCTION__, data, control, hdr, from, mbuf_flags(data));
err = sock_inject_data_in(dtls_ref->socket, from, data, control, 0);
check_noerr(err);
}
}
static void
tls_unregistered_fn(sflt_handle handle)
{
tls_printf("tlsnke:%s\n", __FUNCTION__);
}
static errno_t
tls_attach_fn(void **cookie, socket_t so)
{
tls_printf("tlsnke:%s (so=%p)\n", __FUNCTION__, so);
dtls_ctx_t dtls_ref;
dtls_ref = dtls_create_context(so);
*cookie=dtls_ref;
if(dtls_ref)
return 0;
else
return -1;
}
static void
tls_detach_fn(void *cookie, socket_t so)
{
dtls_ctx_t dtls_ref = (dtls_ctx_t)cookie;
tls_printf("tlsnke(%p):%s\n", cookie, __FUNCTION__);
if(dtls_ref->utun_ref) {
utun_disable_dtls(dtls_ref->utun_ref);
}
dtls_free_context(dtls_ref);
}
static void
tls_notify_fn(void *cookie, socket_t so, sflt_event_t event, void *param)
{
tls_printf("tlsnke(%p):%s - so: %p - evt: %d\n", cookie, __FUNCTION__, so, event);
}
static errno_t
tls_data_in_fn(void *cookie, socket_t so, const struct sockaddr *from,
mbuf_t *data, mbuf_t *control, sflt_data_flag_t flags)
{
dtls_ctx_t dtls_ref = (dtls_ctx_t)cookie;
struct tls_record_hdr *hdr;
errno_t err;
tls_printf("tlsnke(%p):%s so=%p, data=%p/l=%d, control=%p/l=%d, from=%p, flags=0x%x\n",
cookie, __FUNCTION__, so,
data?*data:(void*)-1, (data && *data)?mbuf_pkthdr_len(*data):-1,
control?*control:(void*)-1, (control && *control)?mbuf_pkthdr_len(*control):-1,
from, flags);
hdr = dtls_get_header(control);
if(hdr) {
tls_printf("tlsnke(%p):%s This was already processed. hdr=%p\n", cookie, __FUNCTION__, hdr);
#if TLS_TEST
if((dtls_ref->queue_to_tlsnkedev) && (hdr->content_type==SSL_RecordTypeAppData)) {
tls_printf("tlsnke(%p):%s Sending packet to tlsnkdev. data=%p\n", cookie, __FUNCTION__, *data);
err = tlsnkedev_queue(*data);
verify_noerr_action(err, return err);
mbuf_freem(*control);
return EJUSTRETURN;
}
#endif
if(data && (dtls_ref->utun_ref) && (hdr->content_type==SSL_RecordTypeAppData)) {
tls_printf("tlsnke(%p):%s Sending packet to utun. data=%p\n", cookie, __FUNCTION__, *data);
err = utun_data_packet_input(dtls_ref->utun_ref, *data);
verify_noerr_action(err, return err);
mbuf_freem(*control);
return EJUSTRETURN;
}
return 0;
}
tls_printf("tlsnke(%p):%s Queuing the data %p\n", cookie, __FUNCTION__, data);
if(data) {
struct PktQueueItem *tlq= (struct PktQueueItem *)OSMalloc(sizeof (struct PktQueueItem), gOSMallocTag);
verify_action(tlq, return ENOMEM);
tlq->data = *data;
STAILQ_INSERT_TAIL(&dtls_ref->in_queue, tlq, next);
}
if(from) {
dtls_ref->has_from=true;
memcpy(&dtls_ref->from, from, sizeof(struct sockaddr));
} else {
dtls_ref->has_from=false;
}
if(dtls_ref->wait_for_key) {
tls_printf("tlsnke(%p):%s holding the Q\n", cookie, __FUNCTION__);
} else {
dtls_process_incoming_queue(dtls_ref);
}
return EJUSTRETURN;
}
static errno_t
tls_data_out_fn(void *cookie, socket_t so, const struct sockaddr *to, mbuf_t *data,
mbuf_t *control, sflt_data_flag_t flags)
{
errno_t err;
dtls_ctx_t dtls_ref = (dtls_ctx_t)cookie;
tls_record_hdr_t hdr;
tls_printf("tlsnke(%p):%s so=%p, data=%p/l=%d, control=%p/l=%d, to=%p, flags=0x%x\n", cookie, __FUNCTION__, so,
data?*data:(void *)-1, (data && *data)?mbuf_pkthdr_len(*data):-1,
control?*control:(void *)-1, (control && *control)?mbuf_pkthdr_len(*control):-1, to, flags);
hdr = dtls_get_header(control);
if(hdr && data) {
if(to) {
dtls_ref->has_to=true;
memcpy(&dtls_ref->to, to, sizeof(struct sockaddr));
} else {
dtls_ref->has_to=false;
}
err = dtls_process_output_packet(dtls_ref, *data, hdr);
verify_noerr_action(err, return err);
mbuf_freem(*data);
mbuf_freem(*control);
return EJUSTRETURN;
} else {
return 0;
}
}
static errno_t
tls_connect_in_fn(void *cookie, socket_t so, const struct sockaddr *from)
{
tls_printf("tlsnke(%p):%s\n", cookie, __FUNCTION__);
return 0;
}
static errno_t
tls_connect_out_fn(void *cookie, socket_t so, const struct sockaddr *to)
{
tls_printf("tlsnke(%p):%s\n", cookie, __FUNCTION__);
return 0;
}
static errno_t
tls_bind_fn(void *cookie, socket_t so, const struct sockaddr *to)
{
tls_printf("tlsnke(%p):%s\n", cookie, __FUNCTION__);
return 0;
}
static errno_t
tls_setoption_fn(void *cookie, socket_t so, sockopt_t opt)
{
errno_t err;
int rc;
dtls_ctx_t dtls_ref = (dtls_ctx_t)cookie;
int level = sockopt_level(opt);
int name = sockopt_name(opt);
size_t valsize = sockopt_valsize(opt);
tls_printf("tlsnke(%p):%s - %x %x %d\n", cookie, __FUNCTION__, level, name, valsize);
if(level!=SOL_SOCKET)
return 0;
switch (name) {
case SO_TLS_INIT_CIPHER:
{
uint16_t selectedCipher;
bool server;
SSLBuffer key;
unsigned char *buf;
verify_action(valsize>=4, return EINVAL);
verify_action(valsize<=4096, return EINVAL);
buf=OSMalloc((uint32_t)valsize, gOSMallocTag);
verify_action(buf, return ENOMEM);
err=sockopt_copyin(opt, buf, valsize);
verify_noerr_action(err, return err);
selectedCipher = (buf[0] << 8) | buf[1];
server = buf[2];
key.length = valsize - 3;
key.data = buf + 3;
tls_printf("tlsnke(%p):%s - Init Ciphers. cipherspec=%04x. server=%d.\n", dtls_ref, __FUNCTION__, selectedCipher, server);
rc = SSLRecordLayerInternal.initPendingCiphers(dtls_ref->ssl_ctx, selectedCipher, server, key);
tls_printf("tlsnke(%p):%s - Init Ciphers done rc=%d\n", dtls_ref, __FUNCTION__, rc);
}
break;
case SO_TLS_ADVANCE_READ_CIPHER:
check(dtls_ref->wait_for_key);
rc = SSLRecordLayerInternal.advanceReadCipher(dtls_ref->ssl_ctx);
tls_printf("tlsnke(%p):%s - Read Cipher Advanced, process incoming queue now.\n", dtls_ref, __FUNCTION__);
dtls_ref->wait_for_key=false;
dtls_process_incoming_queue(dtls_ref);
break;
case SO_TLS_ADVANCE_WRITE_CIPHER:
tls_printf("tlsnke(%p):%s - Advancing write cipher.\n", dtls_ref, __FUNCTION__);
rc = SSLRecordLayerInternal.advanceWriteCipher(dtls_ref->ssl_ctx);
break;
case SO_TLS_ROLLBACK_WRITE_CIPHER:
tls_printf("tlsnke(%p):%s - Rolling back write cipher.\n", dtls_ref, __FUNCTION__);
rc = SSLRecordLayerInternal.rollbackWriteCipher(dtls_ref->ssl_ctx);
break;
case SO_TLS_PROTOCOL_VERSION:
{
SSLProtocolVersion pv;
verify_action(valsize==sizeof(SSLProtocolVersion), return EINVAL);
err=sockopt_copyin(opt, &pv, sizeof(SSLProtocolVersion));
verify_noerr_action(err, return err);
tls_printf("tlsnke(%p):%s - Setting protocol version %04x\n", dtls_ref, __FUNCTION__, pv);
rc = SSLRecordLayerInternal.setProtocolVersion(dtls_ref->ssl_ctx, pv);
}
break;
case SO_TLS_SERVICE_WRITE_QUEUE:
tls_printf("tlsnke(%p):%s - Servicing the write Queue.\n", dtls_ref, __FUNCTION__);
rc = SSLRecordLayerInternal.serviceWriteQueue(dtls_ref->ssl_ctx);
break;
default:
return 0;
}
if(rc==0)
return EJUSTRETURN;
else
return rc;
}
static errno_t
tls_getoption_fn(void *cookie, socket_t so, sockopt_t opt)
{
errno_t err;
dtls_ctx_t dtls_ref = (dtls_ctx_t)cookie;
int level = sockopt_level(opt);
int name = sockopt_name(opt);
size_t valsize = sockopt_valsize(opt);
int handle;
if(level!=SOL_SOCKET)
return 0;
switch (name) {
case SO_TLS_HANDLE:
handle=register_dtls_context(dtls_ref);
verify_action(handle>=0, return EBUSY);
verify_action(valsize==sizeof(handle), return EINVAL);
err = sockopt_copyout(opt, &handle, valsize);
verify_noerr_action(err, return err);
tls_printf("tlsnke(%p):%s - get handle : %d\n", cookie, __FUNCTION__, handle);
break;
default:
return 0;
}
return EJUSTRETURN;
}
static errno_t
tls_listen_fn(void *cookie, socket_t so)
{
tls_printf("tlsnke(%p):%s\n", cookie, __FUNCTION__);
return 0;
}
static struct sflt_filter tls_sflt_filter_ip4 = {
TLS_HANDLE_IP4,
SFLT_PROG,
MYBUNDLEID,
tls_unregistered_fn,
tls_attach_fn,
tls_detach_fn,
tls_notify_fn,
NULL,
NULL,
tls_data_in_fn,
tls_data_out_fn,
tls_connect_in_fn,
tls_connect_out_fn,
tls_bind_fn,
tls_setoption_fn,
tls_getoption_fn,
tls_listen_fn,
NULL
};
static caddr_t tls_utun_crypto_kpi_connect_fn(int dtls_handle, struct utun_pcb *utun_ref)
{
dtls_ctx_t dtls_ref;
tls_printf("tlsnke:%s - handle=%d\n", __FUNCTION__, dtls_handle);
dtls_ref=get_dtls_context(dtls_handle);
if(dtls_ref) {
dtls_ref->utun_ref = utun_ref;
}
return (caddr_t)dtls_ref;
}
static errno_t tls_utun_crypto_kpi_send_fn(caddr_t ref, mbuf_t *pkt)
{
dtls_ctx_t dtls_ref = (dtls_ctx_t)ref;
mbuf_t control = NULL;
struct cmsghdr *cmsg;
tls_record_hdr_t hdr;
size_t cbuf_len = CMSG_SPACE(sizeof(*hdr));
uint8_t cbuf[cbuf_len];
errno_t err;
int tmp=0;
check(ref);
check(pkt);
cmsg = (struct cmsghdr *)cbuf;
cmsg->cmsg_len = CMSG_LEN(sizeof(*hdr));
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_TLS_HEADER;
hdr = (tls_record_hdr_t) CMSG_DATA(cmsg);
hdr->content_type = SSL_RecordTypeAppData;
hdr->protocol_version = DTLS_Version_1_0;
require_noerr(err=mbuf_allocpacket(M_NOWAIT, cbuf_len, NULL, &control), free_and_fail);
require_noerr(err=mbuf_copyback(control, 0, cbuf_len, cbuf, M_NOWAIT), free_and_fail);
require_noerr(err=sock_inject_data_out(dtls_ref->socket, NULL, *pkt, control, 0), just_fail);
require_noerr(err=sock_setsockopt(dtls_ref->socket, SOL_SOCKET, SO_TLS_SERVICE_WRITE_QUEUE, &tmp, 0), just_fail);
free_and_fail:
if(control)
mbuf_freem(control);
if(*pkt)
mbuf_freem(*pkt);
just_fail:
return err;
}
static struct utun_crypto_kpi_reg tls_utun_crypto_kpi = {
.crypto_kpi_type = UTUN_CRYPTO_TYPE_DTLS,
.crypto_kpi_flags = 0,
.crypto_kpi_connect = tls_utun_crypto_kpi_connect_fn,
.crypto_kpi_send = tls_utun_crypto_kpi_send_fn
};
#if TLS_TEST
#include <sys/conf.h>
#include <miscfs/devfs/devfs.h>
#include <sys/uio.h>
static STAILQ_HEAD(, PktQueueItem) tlsnkedev_inq;
static lck_grp_attr_t *tlsnkedev_lock_grp_attr;
static lck_grp_t *tlsnkedev_lock_grp;
static lck_attr_t *tlsnkedev_lock_attr;
static lck_mtx_t *tlsnkedev_lock;
static int tlsnkedev_queue(mbuf_t m)
{
struct PktQueueItem *tlq= (struct PktQueueItem *)OSMalloc(sizeof (struct PktQueueItem), gOSMallocTag);
tls_printf("tlsnkedev:%s\n", __FUNCTION__);
verify_action(tlq, return ENOMEM);
tlq->data = m;
lck_mtx_lock(tlsnkedev_lock);
STAILQ_INSERT_TAIL(&tlsnkedev_inq, tlq, next);
wakeup(&tlsnkedev_inq);
lck_mtx_unlock(tlsnkedev_lock);
return 0;
}
static int tlsnkedev_open(__unused dev_t dev, int flags, __unused int devtype, __unused struct proc *p)
{
dtls_ctx_t dtls_ref;
tls_printf("tlsnkedev:%s\n", __FUNCTION__);
dtls_ref = get_dtls_context(0);
dtls_ref->queue_to_tlsnkedev=true;
STAILQ_INIT(&tlsnkedev_inq);
tls_printf("tlsnkedev:%s. inq first=%p last=%p\n", __FUNCTION__, tlsnkedev_inq.stqh_first, tlsnkedev_inq.stqh_last);
return 0;
}
static int tlsnkedev_close(__unused dev_t dev, __unused int flags, __unused int mode, __unused struct proc *p)
{
dtls_ctx_t dtls_ref;
tls_printf("tlsnkedev:%s\n", __FUNCTION__);
dtls_ref = get_dtls_context(0);
dtls_ref->queue_to_tlsnkedev=false;
return 0;
}
static int tlsnkedev_read(dev_t dev, struct uio *uio, int ioflag)
{
int err=0;
int ulen, mlen, amnt;
char *buffer=NULL;
mbuf_t m;
struct PktQueueItem *in_q;
tls_printf("tlsnkedev:%s\n", __FUNCTION__);
ulen=uio_resid(uio);
lck_mtx_lock(tlsnkedev_lock);
if(STAILQ_EMPTY(&tlsnkedev_inq)) {
msleep(&tlsnkedev_inq, tlsnkedev_lock, 0, __FUNCTION__, NULL);
}
in_q = STAILQ_FIRST(&tlsnkedev_inq);
STAILQ_REMOVE_HEAD(&tlsnkedev_inq, next);
lck_mtx_unlock(tlsnkedev_lock);
tls_printf("tlsnkedev:%s. got %p from inq\n", __FUNCTION__, in_q);
verify_action(in_q, return EAGAIN);
m = in_q->data;
verify_action(m, return EFAULT);
mlen=mbuf_len(m);
check(mlen); check(ulen);
amnt = MIN(mlen, ulen);
buffer=OSMalloc(amnt, gOSMallocTag);
verify_action(buffer, return ENOMEM);
require_noerr(err=mbuf_copydata(m, 0, amnt, buffer), out);
require_noerr(err=uiomove(buffer, amnt, uio), out);
out:
OSFree(in_q, sizeof (struct PktQueueItem), gOSMallocTag);
mbuf_freem(m);
OSFree(buffer, amnt, gOSMallocTag);
return 0;
}
static int tlsnkedev_write(dev_t dev, struct uio *uio, int ioflag)
{
int err=0;
int len;
char *buffer=NULL;
mbuf_t m=NULL;
tls_printf("tlsnkedev:%s\n", __FUNCTION__);
len=uio_resid(uio);
buffer=OSMalloc(len, gOSMallocTag);
verify_action(buffer, return ENOMEM);
require_noerr(err=uiomove(buffer, len, uio), out);
require_noerr(err=mbuf_allocpacket(M_NOWAIT, len, NULL, &m), out);
require_noerr(err=mbuf_copyback(m, 0, len, buffer, M_NOWAIT), out);
err=tls_utun_crypto_kpi_send_fn((caddr_t)get_dtls_context(0), &m);
out:
OSFree(buffer, len, gOSMallocTag);
return err;
}
static struct cdevsw tlsnkedev_cdevsw =
{
tlsnkedev_open,
tlsnkedev_close,
tlsnkedev_read,
tlsnkedev_write,
eno_ioctl,
eno_stop,
eno_reset,
NULL,
eno_select,
eno_mmap,
eno_strat,
eno_getc,
eno_putc,
0
};
static void tlsnkedev_devinit(void)
{
int ret;
ret = cdevsw_add(-1, &tlsnkedev_cdevsw);
tls_printf("tlsnkedev:%s - major=%d\n", __FUNCTION__, ret);
devfs_make_node(makedev(ret, 0), DEVFS_CHAR, UID_ROOT, GID_WHEEL, 0666, "tlsnke");
tlsnkedev_lock_grp_attr = lck_grp_attr_alloc_init();
tlsnkedev_lock_grp = lck_grp_alloc_init("tlsnkedev_lock", tlsnkedev_lock_grp_attr);
tlsnkedev_lock_attr = lck_attr_alloc_init();
tlsnkedev_lock = lck_mtx_alloc_init(tlsnkedev_lock_grp, tlsnkedev_lock_attr);
}
#endif
kern_return_t tlsnke_start(kmod_info_t * ki, void *d);
kern_return_t tlsnke_stop(kmod_info_t *ki, void *d);
kern_return_t tlsnke_start(kmod_info_t * ki, void *d)
{
kern_return_t retval;
tls_printf("tlsnke:%s\n", __FUNCTION__);
#if TLS_TEST
tlsnkedev_devinit();
#endif
gOSMallocTag = OSMalloc_Tagalloc(MYBUNDLEID, OSMT_DEFAULT); verify_action(gOSMallocTag, return KERN_MEMORY_ERROR);
clear_dtls_contexts();
retval = utun_ctl_register_dtls(&tls_utun_crypto_kpi);
require_noerr(retval, out);
retval = sflt_register(&tls_sflt_filter_ip4, PF_INET, SOCK_DGRAM, IPPROTO_UDP);
out:
return retval;
}
kern_return_t tlsnke_stop(kmod_info_t *ki, void *d)
{
kern_return_t retval;
tls_printf("tlsnke:%s\n", __FUNCTION__);
retval = sflt_unregister(TLS_HANDLE_IP4);
return KERN_SUCCESS;
}