#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <sys/syslog.h>
#include <errno.h>
#include <mach/boolean.h>
#include <string.h>
#include <ctype.h>
#include <SystemConfiguration/SCPrivate.h>
#include "util.h"
#include "cfutil.h"
#include "symbol_scope.h"
PRIVATE_EXTERN int
nbits_host(struct in_addr mask)
{
u_long l = iptohl(mask);
int i;
for (i = 0; i < 32; i++) {
if (l & (1 << i))
return (32 - i);
}
return (32);
}
PRIVATE_EXTERN char *
inet_nettoa(struct in_addr addr, struct in_addr mask)
{
uint8_t * addr_p;
int nbits = nbits_host(mask);
int nbytes;
static char sbuf[32];
char tmp[8];
#define NBITS_PER_BYTE 8
sbuf[0] = '\0';
nbytes = (nbits + NBITS_PER_BYTE - 1) / NBITS_PER_BYTE;
for (addr_p = (uint8_t *)&addr.s_addr; nbytes > 0; addr_p++) {
snprintf(tmp, sizeof(tmp), "%d%s", *addr_p, nbytes > 1 ? "." : "");
strlcat(sbuf, tmp, sizeof(sbuf));
nbytes--;
}
if (nbits % NBITS_PER_BYTE) {
snprintf(tmp, sizeof(tmp), "/%d", nbits);
strlcat(sbuf, tmp, sizeof(sbuf));
}
return (sbuf);
}
PRIVATE_EXTERN long
random_range(long bottom, long top)
{
long ret;
long number = top - bottom + 1;
long range_size = UINT32_MAX / number;
if (range_size == 0)
return (bottom);
ret = (arc4random() / range_size) + bottom;
return (ret);
}
PRIVATE_EXTERN void
timeval_subtract(struct timeval tv1, struct timeval tv2,
struct timeval * result)
{
result->tv_sec = tv1.tv_sec - tv2.tv_sec;
result->tv_usec = tv1.tv_usec - tv2.tv_usec;
if (result->tv_usec < 0) {
result->tv_usec += USECS_PER_SEC;
result->tv_sec--;
}
return;
}
PRIVATE_EXTERN void
timeval_add(struct timeval tv1, struct timeval tv2,
struct timeval * result)
{
result->tv_sec = tv1.tv_sec + tv2.tv_sec;
result->tv_usec = tv1.tv_usec + tv2.tv_usec;
if (result->tv_usec > USECS_PER_SEC) {
result->tv_usec -= USECS_PER_SEC;
result->tv_sec++;
}
return;
}
PRIVATE_EXTERN int
timeval_compare(struct timeval tv1, struct timeval tv2)
{
struct timeval result;
timeval_subtract(tv1, tv2, &result);
if (result.tv_sec < 0 || result.tv_usec < 0)
return (-1);
if (result.tv_sec == 0 && result.tv_usec == 0)
return (0);
return (1);
}
PRIVATE_EXTERN void
print_data_cfstr(CFMutableStringRef str, const uint8_t * data_p,
int n_bytes)
{
#define CHARS_PER_LINE 16
char line_buf[CHARS_PER_LINE + 1];
int line_pos;
int offset;
for (line_pos = 0, offset = 0; offset < n_bytes; offset++, data_p++) {
if (line_pos == 0) {
STRING_APPEND(str, "%04x ", offset);
}
line_buf[line_pos] = isprint(*data_p) ? *data_p : '.';
STRING_APPEND(str, " %02x", *data_p);
line_pos++;
if (line_pos == CHARS_PER_LINE) {
line_buf[CHARS_PER_LINE] = '\0';
STRING_APPEND(str, " %s\n", line_buf);
line_pos = 0;
}
else if (line_pos == (CHARS_PER_LINE / 2))
STRING_APPEND(str, " ");
}
if (line_pos) {
char * extra_space = "";
if (line_pos < (CHARS_PER_LINE / 2)) {
extra_space = " ";
}
for (; line_pos < CHARS_PER_LINE; line_pos++) {
STRING_APPEND(str, " ");
line_buf[line_pos] = ' ';
}
line_buf[CHARS_PER_LINE] = '\0';
STRING_APPEND(str, " %s%s\n", extra_space, line_buf);
}
return;
}
PRIVATE_EXTERN void
fprint_data(FILE * out_f, const uint8_t * data_p, int n_bytes)
{
CFMutableStringRef str;
str = CFStringCreateMutable(NULL, 0);
print_data_cfstr(str, data_p, n_bytes);
SCPrint(TRUE, out_f, CFSTR("%@"), str);
CFRelease(str);
fflush(out_f);
return;
}
PRIVATE_EXTERN void
print_data(const uint8_t * data_p, int n_bytes)
{
fprint_data(stdout, data_p, n_bytes);
return;
}
PRIVATE_EXTERN void
print_bytes_sep_cfstr(CFMutableStringRef str, uint8_t * data_p, int n_bytes,
char separator)
{
int i;
for (i = 0; i < n_bytes; i++) {
char sep[3];
if (i == 0) {
sep[0] = '\0';
}
else {
if ((i % 8) == 0 && separator == ' ') {
sep[0] = sep[1] = ' ';
sep[2] = '\0';
}
else {
sep[0] = separator;
sep[1] = '\0';
}
}
STRING_APPEND(str, "%s%02x", sep, data_p[i]);
}
return;
}
PRIVATE_EXTERN void
print_bytes_cfstr(CFMutableStringRef str, uint8_t * data, int len)
{
print_bytes_sep_cfstr(str, data, len, ' ');
return;
}
PRIVATE_EXTERN void
fprint_bytes_sep(FILE * out_f, uint8_t * data_p, int n_bytes, char separator)
{
CFMutableStringRef str;
str = CFStringCreateMutable(NULL, 0);
print_bytes_sep_cfstr(str, data_p, n_bytes, separator);
SCPrint(TRUE, out_f, CFSTR("%@"), str);
CFRelease(str);
fflush(out_f);
return;
}
PRIVATE_EXTERN void
print_bytes(uint8_t * data, int len)
{
fprint_bytes_sep(stdout, data, len, ' ');
return;
}
PRIVATE_EXTERN void
print_bytes_sep(uint8_t * data, int len, char separator)
{
fprint_bytes_sep(stdout, data, len, separator);
return;
}
PRIVATE_EXTERN int
create_path(const char * dirname, mode_t mode)
{
boolean_t done = FALSE;
const char * scan;
if (mkdir(dirname, mode) == 0 || errno == EEXIST)
return (0);
if (errno != ENOENT)
return (-1);
{
char path[PATH_MAX];
for (path[0] = '\0', scan = dirname; done == FALSE;) {
const char * next_sep;
if (scan == NULL || *scan != '/')
return (FALSE);
scan++;
next_sep = strchr(scan, '/');
if (next_sep == 0) {
done = TRUE;
next_sep = dirname + strlen(dirname);
}
strncpy(path, dirname , next_sep - dirname);
path[next_sep - dirname] = '\0';
if (mkdir(path, mode) == 0 || errno == EEXIST)
;
else
return (-1);
scan = next_sep;
}
}
return (0);
}
PRIVATE_EXTERN int
ether_cmp(struct ether_addr * e1, struct ether_addr * e2)
{
int i;
uint8_t * c1 = e1->octet;
uint8_t * c2 = e2->octet;
for (i = 0; i < sizeof(e1->octet); i++, c1++, c2++) {
if (*c1 == *c2)
continue;
return ((int)*c1 - (int)*c2);
}
return (0);
}
PRIVATE_EXTERN void
link_addr_to_string(char * string_buffer, int string_buffer_length,
const uint8_t * hwaddr, int hwaddr_len)
{
int i;
switch (hwaddr_len) {
case 6:
snprintf(string_buffer, string_buffer_length,
EA_FORMAT, EA_LIST(hwaddr));
break;
case 8:
snprintf(string_buffer, string_buffer_length,
FWA_FORMAT, FWA_LIST(hwaddr));
break;
default:
for (i = 0; i < hwaddr_len; i++) {
if (i == 0) {
snprintf(string_buffer, string_buffer_length,
"%02x", hwaddr[i]);
string_buffer += 2;
string_buffer_length -= 2;
}
else {
snprintf(string_buffer, string_buffer_length,
":%02x", hwaddr[i]);
string_buffer += 3;
string_buffer_length -= 3;
}
}
break;
}
return;
}
PRIVATE_EXTERN void
fill_with_random(void * buf, uint32_t len)
{
int i;
int n;
uint32_t * p = (uint32_t *)buf;
n = len / sizeof(*p);
for (i = 0; i < n; i++, p++) {
*p = arc4random();
}
return;
}
#define ROUNDUP(a) \
((a) > 0 ? (1 + (((a) - 1) | (sizeof(u_int32_t) - 1))) : sizeof(u_int32_t))
PRIVATE_EXTERN int
rt_xaddrs(const char * cp, const char * cplim, struct rt_addrinfo * rtinfo)
{
int i;
struct sockaddr * sa;
bzero(rtinfo->rti_info, sizeof(rtinfo->rti_info));
for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) {
if ((rtinfo->rti_addrs & (1 << i)) == 0) {
continue;
}
sa = (struct sockaddr *)cp;
if ((cp + sa->sa_len) > cplim) {
return (EINVAL);
}
rtinfo->rti_info[i] = sa;
cp += ROUNDUP(sa->sa_len);
}
return (0);
}