#include "systemEntropy.h"
#include "debug.h"
#include <stdlib.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/time.h>
#include <sys/kdebug.h>
#include <sys/sysctl.h>
#include <sys/errno.h>
#include <unistd.h>
#include "kdebug_private.h"
#define MS_TO_SLEEP 100
static int set_remove();
static int set_init();
static int set_enable(int val);
static int set_numbufs(int nbufs);
int systemEntropyBegin(UInt32 bufSize)
{
int rtn;
set_remove();
set_numbufs(bufSize);
if(rtn = set_init()) {
return rtn;
}
if(rtn = set_enable(1)) {
return rtn;
}
return 0;
}
int systemEntropyCollect(
UInt8 *buf,
UInt32 bufSize,
UInt32 *numBytes, UInt32 *bitsOfEntropy) {
int rtn = 0;
size_t mallocdSize;
UInt8 *cp = buf;
kd_buf *kd = NULL;
int i;
int mib[6];
size_t numEntries;
*numBytes = 0;
*bitsOfEntropy = 0;
mallocdSize = bufSize * sizeof(kd_buf);
kd = (kd_buf *)malloc(mallocdSize);
if(kd == NULL) {
rtn = ENOMEM;
goto errOut;
}
mib[0] = CTL_KERN;
mib[1] = KERN_KDEBUG;
mib[2] = KERN_KDREADTR;
mib[3] = 0;
mib[4] = 0;
mib[5] = 0;
numEntries = mallocdSize;
if (sysctl(mib, 3, kd, &numEntries, NULL, 0) < 0) {
int err = errno;
if(err != ENOMEM) {
errorLog1("sysctl-KERN_KDREADTR: %d\n", err);
rtn = err;
goto errOut;
}
}
if(numEntries == 0) {
rtn = ENOENT;
goto errOut;
}
*cp++ = (UInt8)kd[0].timestamp.tv_nsec;
for (i=1; i<numEntries; i++) {
*cp++ = kd[i].timestamp.tv_nsec - kd[i-1].timestamp.tv_nsec;
}
*numBytes = numEntries;
*bitsOfEntropy = numEntries * 4;
errOut:
set_enable(0);
set_remove(); return rtn;
}
static int set_remove()
{
int mib[6];
size_t needed;
mib[0] = CTL_KERN;
mib[1] = KERN_KDEBUG;
mib[2] = KERN_KDREMOVE;
mib[3] = 0;
mib[4] = 0;
mib[5] = 0;
if (sysctl(mib, 3, NULL, &needed, NULL, 0) < 0) {
int err = errno;
errorLog1("sysctl-KERN_KDREMOVE: %d\n", err);
return err;
}
return 0;
}
static int set_init()
{
kd_regtype kr;
int mib[6];
size_t needed;
kr.type = KDBG_RANGETYPE;
kr.value1 = 0;
kr.value2 = -1;
needed = sizeof(kd_regtype);
mib[0] = CTL_KERN;
mib[1] = KERN_KDEBUG;
mib[2] = KERN_KDSETREG;
mib[3] = 0;
mib[4] = 0;
mib[5] = 0;
if (sysctl(mib, 3, &kr, &needed, NULL, 0) < 0) {
int err = errno;
errorLog1("sysctl-KERN_KDSETREG: %d\n", err);
return err;
}
mib[0] = CTL_KERN;
mib[1] = KERN_KDEBUG;
mib[2] = KERN_KDSETUP;
mib[3] = 0;
mib[4] = 0;
mib[5] = 0;
if (sysctl(mib, 3, NULL, &needed, NULL, 0) < 0) {
int err = errno;
errorLog1("sysctl-KERN_KDSETUP: %d\n", err);
return err;
}
return 0;
}
static int set_enable(int val)
{
int mib[6];
size_t needed;
mib[0] = CTL_KERN;
mib[1] = KERN_KDEBUG;
mib[2] = KERN_KDENABLE;
mib[3] = val;
mib[4] = 0;
mib[5] = 0;
if (sysctl(mib, 4, NULL, &needed, NULL, 0) < 0) {
int err = errno;
errorLog1("sysctl-KERN_KDENABLE: %d\n", err);
return err;
}
return 0;
}
static int set_numbufs(int nbufs)
{
int mib[6];
size_t needed;
mib[0] = CTL_KERN;
mib[1] = KERN_KDEBUG;
mib[2] = KERN_KDSETBUF;
mib[3] = nbufs;
mib[4] = 0;
mib[5] = 0;
if (sysctl(mib, 4, NULL, &needed, NULL, 0) < 0) {
int err = errno;
errorLog2("ERROR: sysctl-KERN_KDSETBUF(%d): %s\n",
nbufs, strerror(err));
return err;
}
mib[0] = CTL_KERN;
mib[1] = KERN_KDEBUG;
mib[2] = KERN_KDSETUP;
mib[3] = 0;
mib[4] = 0;
mib[5] = 0;
if (sysctl(mib, 3, NULL, &needed, NULL, 0) < 0) {
int err = errno;
errorLog1("ERROR: sysctl-KERN_KDSETUP: %s\n",
strerror(err));
return err;
}
return 0;
}