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#define ROUNDUP(a) \ 414 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(u_int32_t) - 1))) : sizeof(u_int32_t)) 415 416PRIVATE_EXTERN int 417rt_xaddrs(const char * cp, const char * cplim, struct rt_addrinfo * rtinfo) 418{ 419 int i; 420 struct sockaddr * sa; 421 422 bzero(rtinfo->rti_info, sizeof(rtinfo->rti_info)); 423 for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) { 424 if ((rtinfo->rti_addrs & (1 << i)) == 0) { 425 continue; 426 } 427 sa = (struct sockaddr *)cp; 428 if ((cp + sa->sa_len) > cplim) { 429 return (EINVAL); 430 } 431 rtinfo->rti_info[i] = sa; 432 cp += ROUNDUP(sa->sa_len); 433 } 434 return (0); 435} 436 437