#include "DHCPDUID.h"
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <CoreFoundation/CFString.h>
#include "util.h"
#include "cfutil.h"
#include "symbol_scope.h"
STATIC uint32_t
S_seconds_since_Jan_1_2000(void)
{
time_t DHCPDUID_epoch;
uint32_t seconds;
struct tm tm;
bzero(&tm, sizeof(tm));
tm.tm_year = 100;
tm.tm_mon = 0;
tm.tm_mday = 1;
DHCPDUID_epoch = timegm(&tm);
seconds = (uint32_t)(time(NULL) - DHCPDUID_epoch);
return (seconds);
}
PRIVATE_EXTERN void
DHCPDUIDPrintToString(CFMutableStringRef str,
const DHCPDUIDRef duid, int duid_len)
{
int required_len;
DHCPDUIDType type;
required_len = offsetof(DHCPDUID_LLT, hardware_type);
if (duid_len < required_len) {
goto too_short;
}
type = DHCPDUIDGetType(duid);
switch (type) {
case kDHCPDUIDTypeLLT:
required_len = offsetof(DHCPDUID_LLT, linklayer_address);
if (duid_len < required_len) {
goto too_short;
}
CFStringAppendFormat(str,
NULL,
CFSTR("DUID LLT HW %d Time %u Addr "),
DHCPDUID_LLTGetHardwareType(&duid->llt),
DHCPDUID_LLTGetTime(&duid->llt));
my_CFStringAppendBytesAsHex(str, duid->llt.linklayer_address,
duid_len - required_len, ':');
break;
case kDHCPDUIDTypeEN:
required_len = offsetof(DHCPDUID_EN, identifier);
if (duid_len < required_len) {
goto too_short;
}
CFStringAppendFormat(str, NULL, CFSTR("DUID EN Num %d Id "),
DHCPDUID_ENGetEnterpriseNumber(&duid->en));
my_CFStringAppendBytesAsHex(str, duid->en.identifier,
duid_len - required_len, ':');
break;
case kDHCPDUIDTypeLL:
required_len = offsetof(DHCPDUID_LL, linklayer_address);
if (duid_len < required_len) {
goto too_short;
}
CFStringAppendFormat(str, NULL,
CFSTR("DUID LL HW %d Addr "),
DHCPDUID_LLGetHardwareType(&duid->ll));
my_CFStringAppendBytesAsHex(str, duid->ll.linklayer_address,
duid_len - required_len, ':');
break;
default:
CFStringAppendFormat(str, NULL, CFSTR("DUID (unrecognized type=%d): "),
type);
my_CFStringAppendBytesAsHex(str, (const uint8_t *)duid, duid_len, ' ');
break;
}
return;
too_short:
CFStringAppendFormat(str, NULL,
CFSTR("DUID too short (%d < %d), Data = { "),
duid_len, required_len);
my_CFStringAppendBytesAsHex(str, (const uint8_t *)duid, duid_len, ' ');
CFStringAppendCString(str, " }", kCFStringEncodingASCII);
return;
}
PRIVATE_EXTERN bool
DHCPDUIDIsValid(const DHCPDUIDRef duid, int duid_len)
{
int required_len;
DHCPDUIDType type;
required_len = offsetof(DHCPDUID_LLT, hardware_type);
if (duid_len < required_len) {
return (FALSE);
}
type = DHCPDUIDGetType(duid);
switch (type) {
case kDHCPDUIDTypeLLT:
required_len = offsetof(DHCPDUID_LLT, linklayer_address);
if (duid_len <= required_len) {
return (FALSE);
}
break;
case kDHCPDUIDTypeEN:
required_len = offsetof(DHCPDUID_EN, identifier);
if (duid_len <= required_len) {
return (FALSE);
}
break;
case kDHCPDUIDTypeLL:
required_len = offsetof(DHCPDUID_LL, linklayer_address);
if (duid_len <= required_len) {
return (FALSE);
}
break;
default:
break;
}
return (TRUE);
}
PRIVATE_EXTERN CFDataRef
DHCPDUID_LLDataCreate(const void * ll_addr, int ll_len, int ll_type)
{
CFMutableDataRef data;
int duid_len;
DHCPDUID_LLRef ll_p;
duid_len = offsetof(DHCPDUID_LL, linklayer_address) + ll_len;
data = CFDataCreateMutable(NULL, duid_len);
CFDataSetLength(data, duid_len);
ll_p = (DHCPDUID_LLRef)CFDataGetMutableBytePtr(data);
DHCPDUIDSetType((DHCPDUIDRef)ll_p, kDHCPDUIDTypeLL);
DHCPDUID_LLSetHardwareType(ll_p, ll_type);
memcpy(ll_p->linklayer_address, ll_addr, ll_len);
return (data);
}
CFDataRef
DHCPDUID_LLTDataCreate(const void * ll_addr, int ll_len, int ll_type)
{
CFMutableDataRef data;
int duid_len;
DHCPDUID_LLTRef llt_p;
duid_len = offsetof(DHCPDUID_LLT, linklayer_address) + ll_len;
data = CFDataCreateMutable(NULL, duid_len);
CFDataSetLength(data, duid_len);
llt_p = (DHCPDUID_LLTRef)CFDataGetMutableBytePtr(data);
DHCPDUIDSetType((DHCPDUIDRef)llt_p, kDHCPDUIDTypeLLT);
DHCPDUID_LLTSetHardwareType(llt_p, ll_type);
memcpy(llt_p->linklayer_address, ll_addr, ll_len);
DHCPDUID_LLTSetTime(llt_p, S_seconds_since_Jan_1_2000());
return (data);
}