1/*
2 * Copyright (c) 2003-2013 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24/*
25 * util.c
26 * - contains miscellaneous routines
27 */
28#include <stdio.h>
29#include <unistd.h>
30#include <stdlib.h>
31#include <netinet/in.h>
32#include <sys/types.h>
33#include <sys/stat.h>
34#include <sys/param.h>
35#include <sys/syslog.h>
36#include <errno.h>
37#include <mach/boolean.h>
38#include <string.h>
39#include <ctype.h>
40#include <SystemConfiguration/SCPrivate.h>
41#include "util.h"
42#include "cfutil.h"
43#include "symbol_scope.h"
44
45/*
46 * Function: nbits_host
47 * Purpose:
48 *   Return the number of bits of host address
49 */
50PRIVATE_EXTERN int
51nbits_host(struct in_addr mask)
52{
53    u_long l = iptohl(mask);
54    int i;
55
56    for (i = 0; i < 32; i++) {
57	if (l & (1 << i))
58	    return (32 - i);
59    }
60    return (32);
61}
62
63/*
64 * Function: inet_nettoa
65 * Purpose:
66 *   Turns a network address (expressed as an IP address and mask)
67 *   into a string e.g. 17.202.40.0 and mask 255.255.252.0 yields
68 *   the string  "17.202.40/22".
69 */
70PRIVATE_EXTERN char *
71inet_nettoa(struct in_addr addr, struct in_addr mask)
72{
73    uint8_t *		addr_p;
74    int 		nbits = nbits_host(mask);
75    int 		nbytes;
76    static char 	sbuf[32];
77    char 		tmp[8];
78
79#define NBITS_PER_BYTE	8
80    sbuf[0] = '\0';
81    nbytes = (nbits + NBITS_PER_BYTE - 1) / NBITS_PER_BYTE;
82//    printf("-- nbits %d, nbytes %d--", nbits, nbytes);
83    for (addr_p = (uint8_t *)&addr.s_addr; nbytes > 0; addr_p++) {
84
85	snprintf(tmp, sizeof(tmp), "%d%s", *addr_p, nbytes > 1 ? "." : "");
86	strlcat(sbuf, tmp, sizeof(sbuf));
87	nbytes--;
88    }
89    if (nbits % NBITS_PER_BYTE) {
90	snprintf(tmp, sizeof(tmp), "/%d", nbits);
91	strlcat(sbuf, tmp, sizeof(sbuf));
92    }
93    return (sbuf);
94}
95
96/*
97 * Function: random_range
98 * Purpose:
99 *   Return a random number in the given range.
100 */
101PRIVATE_EXTERN long
102random_range(long bottom, long top)
103{
104    long ret;
105    long number = top - bottom + 1;
106    long range_size = UINT32_MAX / number;
107    if (range_size == 0)
108	return (bottom);
109    ret = (arc4random() / range_size) + bottom;
110    return (ret);
111}
112
113/*
114 * Function: timeval_subtract
115 *
116 * Purpose:
117 *   Computes result = tv1 - tv2.
118 */
119PRIVATE_EXTERN void
120timeval_subtract(struct timeval tv1, struct timeval tv2,
121		 struct timeval * result)
122{
123    result->tv_sec = tv1.tv_sec - tv2.tv_sec;
124    result->tv_usec = tv1.tv_usec - tv2.tv_usec;
125    if (result->tv_usec < 0) {
126	result->tv_usec += USECS_PER_SEC;
127	result->tv_sec--;
128    }
129    return;
130}
131
132/*
133 * Function: timeval_add
134 *
135 * Purpose:
136 *   Computes result = tv1 + tv2.
137 */
138PRIVATE_EXTERN void
139timeval_add(struct timeval tv1, struct timeval tv2,
140	    struct timeval * result)
141{
142    result->tv_sec = tv1.tv_sec + tv2.tv_sec;
143    result->tv_usec = tv1.tv_usec + tv2.tv_usec;
144    if (result->tv_usec > USECS_PER_SEC) {
145	result->tv_usec -= USECS_PER_SEC;
146	result->tv_sec++;
147    }
148    return;
149}
150
151/*
152 * Function: timeval_compare
153 *
154 * Purpose:
155 *   Compares two timeval values, tv1 and tv2.
156 *
157 * Returns:
158 *   -1		if tv1 is less than tv2
159 *   0 		if tv1 is equal to tv2
160 *   1 		if tv1 is greater than tv2
161 */
162PRIVATE_EXTERN int
163timeval_compare(struct timeval tv1, struct timeval tv2)
164{
165    struct timeval result;
166
167    timeval_subtract(tv1, tv2, &result);
168    if (result.tv_sec < 0 || result.tv_usec < 0)
169	return (-1);
170    if (result.tv_sec == 0 && result.tv_usec == 0)
171	return (0);
172    return (1);
173}
174
175/*
176 * Function: print_data_cfstr
177 * Purpose:
178 *   Displays the buffer as a series of 8-bit hex numbers with an ASCII
179 *   representation off to the side.
180 */
181PRIVATE_EXTERN void
182print_data_cfstr(CFMutableStringRef str, const uint8_t * data_p,
183		 int n_bytes)
184{
185#define CHARS_PER_LINE 	16
186    char		line_buf[CHARS_PER_LINE + 1];
187    int			line_pos;
188    int			offset;
189
190    for (line_pos = 0, offset = 0; offset < n_bytes; offset++, data_p++) {
191	if (line_pos == 0) {
192	    STRING_APPEND(str, "%04x ", offset);
193	}
194
195	line_buf[line_pos] = isprint(*data_p) ? *data_p : '.';
196	STRING_APPEND(str, " %02x", *data_p);
197	line_pos++;
198	if (line_pos == CHARS_PER_LINE) {
199	    line_buf[CHARS_PER_LINE] = '\0';
200	    STRING_APPEND(str, "  %s\n", line_buf);
201	    line_pos = 0;
202	}
203	else if (line_pos == (CHARS_PER_LINE / 2))
204	    STRING_APPEND(str, " ");
205    }
206    if (line_pos) { /* need to finish up the line */
207	char * extra_space = "";
208	if (line_pos < (CHARS_PER_LINE / 2)) {
209	    extra_space = " ";
210	}
211	for (; line_pos < CHARS_PER_LINE; line_pos++) {
212	    STRING_APPEND(str, "   ");
213	    line_buf[line_pos] = ' ';
214	}
215	line_buf[CHARS_PER_LINE] = '\0';
216	STRING_APPEND(str, "  %s%s\n", extra_space, line_buf);
217    }
218    return;
219}
220
221PRIVATE_EXTERN void
222fprint_data(FILE * out_f, const uint8_t * data_p, int n_bytes)
223{
224    CFMutableStringRef	str;
225
226    str = CFStringCreateMutable(NULL, 0);
227    print_data_cfstr(str, data_p, n_bytes);
228    SCPrint(TRUE, out_f, CFSTR("%@"), str);
229    CFRelease(str);
230    fflush(out_f);
231    return;
232}
233
234PRIVATE_EXTERN void
235print_data(const uint8_t * data_p, int n_bytes)
236{
237    fprint_data(stdout, data_p, n_bytes);
238    return;
239}
240
241PRIVATE_EXTERN void
242print_bytes_sep_cfstr(CFMutableStringRef str, uint8_t * data_p, int n_bytes,
243		      char separator)
244{
245    int i;
246
247    for (i = 0; i < n_bytes; i++) {
248	char  	sep[3];
249
250	if (i == 0) {
251	    sep[0] = '\0';
252	}
253	else {
254	    if ((i % 8) == 0 && separator == ' ') {
255		sep[0] = sep[1] = ' ';
256		sep[2] = '\0';
257	    }
258	    else {
259		sep[0] = separator;
260		sep[1] = '\0';
261	    }
262	}
263	STRING_APPEND(str, "%s%02x", sep, data_p[i]);
264    }
265    return;
266}
267
268PRIVATE_EXTERN void
269print_bytes_cfstr(CFMutableStringRef str, uint8_t * data, int len)
270{
271    print_bytes_sep_cfstr(str, data, len, ' ');
272    return;
273}
274
275
276PRIVATE_EXTERN void
277fprint_bytes_sep(FILE * out_f, uint8_t * data_p, int n_bytes, char separator)
278{
279    CFMutableStringRef	str;
280
281    str = CFStringCreateMutable(NULL, 0);
282    print_bytes_sep_cfstr(str, data_p, n_bytes, separator);
283    SCPrint(TRUE, out_f, CFSTR("%@"), str);
284    CFRelease(str);
285    fflush(out_f);
286    return;
287}
288
289PRIVATE_EXTERN void
290print_bytes(uint8_t * data, int len)
291{
292    fprint_bytes_sep(stdout, data, len, ' ');
293    return;
294}
295
296PRIVATE_EXTERN void
297print_bytes_sep(uint8_t * data, int len, char separator)
298{
299    fprint_bytes_sep(stdout, data, len, separator);
300    return;
301}
302
303
304/*
305 * Function: create_path
306 *
307 * Purpose:
308 *   Create the given directory hierarchy.  Return -1 if anything
309 *   went wrong, 0 if successful.
310 */
311PRIVATE_EXTERN int
312create_path(const char * dirname, mode_t mode)
313{
314    boolean_t		done = FALSE;
315    const char *	scan;
316
317    if (mkdir(dirname, mode) == 0 || errno == EEXIST)
318	return (0);
319
320    if (errno != ENOENT)
321	return (-1);
322
323    {
324	char	path[PATH_MAX];
325
326	for (path[0] = '\0', scan = dirname; done == FALSE;) {
327	    const char * 	next_sep;
328
329	    if (scan == NULL || *scan != '/')
330		return (FALSE);
331	    scan++;
332	    next_sep = strchr(scan, '/');
333	    if (next_sep == 0) {
334		done = TRUE;
335		next_sep = dirname + strlen(dirname);
336	    }
337	    strncpy(path, dirname , next_sep - dirname);
338	    path[next_sep - dirname] = '\0';
339	    if (mkdir(path, mode) == 0 || errno == EEXIST)
340		;
341	    else
342		return (-1);
343	    scan = next_sep;
344	}
345    }
346    return (0);
347}
348
349PRIVATE_EXTERN int
350ether_cmp(struct ether_addr * e1, struct ether_addr * e2)
351{
352    int i;
353    uint8_t * c1 = e1->octet;
354    uint8_t * c2 = e2->octet;
355
356    for (i = 0; i < sizeof(e1->octet); i++, c1++, c2++) {
357	if (*c1 == *c2)
358	    continue;
359	return ((int)*c1 - (int)*c2);
360    }
361    return (0);
362}
363
364PRIVATE_EXTERN void
365link_addr_to_string(char * string_buffer, int string_buffer_length,
366		    const uint8_t * hwaddr, int hwaddr_len)
367{
368    int		i;
369
370    switch (hwaddr_len) {
371    case 6:
372	snprintf(string_buffer, string_buffer_length,
373		 EA_FORMAT, EA_LIST(hwaddr));
374	break;
375    case 8:
376	snprintf(string_buffer, string_buffer_length,
377		 FWA_FORMAT, FWA_LIST(hwaddr));
378	break;
379    default:
380	for (i = 0; i < hwaddr_len; i++) {
381	    if (i == 0) {
382		snprintf(string_buffer, string_buffer_length,
383			 "%02x", hwaddr[i]);
384		string_buffer += 2;
385		string_buffer_length -= 2;
386	    }
387	    else {
388		snprintf(string_buffer, string_buffer_length,
389			 ":%02x", hwaddr[i]);
390		string_buffer += 3;
391		string_buffer_length -= 3;
392	    }
393	}
394	break;
395    }
396    return;
397}
398
399PRIVATE_EXTERN void
400fill_with_random(void * buf, uint32_t len)
401{
402    int			i;
403    int			n;
404    uint32_t * 		p = (uint32_t *)buf;
405
406    n = len / sizeof(*p);
407    for (i = 0; i < n; i++, p++) {
408	*p = arc4random();
409    }
410    return;
411}
412
413