1/*
2 * Copyright (c) 2003 Apple Computer, 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 * utils.c - various utility functions used in pppd.
25 *
26 * Copyright (c) 1999-2002 Paul Mackerras. All rights reserved.
27 *
28 * Redistribution and use in source and binary forms, with or without
29 * modification, are permitted provided that the following conditions
30 * are met:
31 *
32 * 1. Redistributions of source code must retain the above copyright
33 *    notice, this list of conditions and the following disclaimer.
34 *
35 * 2. Redistributions in binary form must reproduce the above copyright
36 *    notice, this list of conditions and the following disclaimer in
37 *    the documentation and/or other materials provided with the
38 *    distribution.
39 *
40 * 3. The name(s) of the authors of this software must not be used to
41 *    endorse or promote products derived from this software without
42 *    prior written permission.
43 *
44 * 4. Redistributions of any form whatsoever must retain the following
45 *    acknowledgment:
46 *    "This product includes software developed by Paul Mackerras
47 *     <paulus@samba.org>".
48 *
49 * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
50 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
51 * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
52 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
53 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
54 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
55 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
56 */
57
58#define RCSID	"$Id: utils.c,v 1.8 2005/12/13 06:30:15 lindak Exp $"
59
60#include <stdio.h>
61#include <ctype.h>
62#include <stdlib.h>
63#include <string.h>
64#include <unistd.h>
65#include <signal.h>
66#include <errno.h>
67#include <fcntl.h>
68#include <syslog.h>
69#include <netdb.h>
70#include <time.h>
71#include <pwd.h>
72#include <sys/param.h>
73#include <sys/types.h>
74#include <sys/wait.h>
75#include <sys/time.h>
76#include <sys/resource.h>
77#include <sys/stat.h>
78#include <sys/socket.h>
79#include <netinet/in.h>
80#ifdef SVR4
81#include <sys/mkdev.h>
82#endif
83#include <arpa/inet.h>
84#include <net/if.h>
85#include <net/if_media.h>
86#include <netinet/in_var.h>
87#include <sys/kern_event.h>
88#include <SystemConfiguration/SystemConfiguration.h>
89#include <SystemConfiguration/SCValidation.h>
90#include <CoreFoundation/CFBundle.h>
91
92#include "pppd.h"
93#include "fsm.h"
94#include "lcp.h"
95
96#ifndef lint
97static const char rcsid[] = RCSID;
98#endif
99
100#if defined(SUNOS4)
101extern char *strerror();
102#endif
103
104static void logit __P((int, char *, va_list));
105static void log_write __P((int, char *));
106static void vslp_printer __P((void *, char *, ...));
107static void format_packet __P((u_char *, int, void (*) (void *, char *, ...),
108			       void *));
109
110struct buffer_info {
111    char *ptr;
112    int len;
113};
114
115#ifdef NO_SRTLXXX
116
117/*
118 * strlcpy - like strcpy/strncpy, doesn't overflow destination buffer,
119 * always leaves destination null-terminated (for len > 0).
120 */
121size_t
122strlcpy(dest, src, len)
123    char *dest;
124    const char *src;
125    size_t len;
126{
127    size_t ret = strlen(src);
128
129    if (len != 0) {
130	if (ret < len)
131	    strcpy(dest, src);
132	else {
133	    strncpy(dest, src, len - 1);
134	    dest[len-1] = 0;
135	}
136    }
137    return ret;
138}
139
140/*
141 * strlcat - like strcat/strncat, doesn't overflow destination buffer,
142 * always leaves destination null-terminated (for len > 0).
143 */
144size_t
145strlcat(dest, src, len)
146    char *dest;
147    const char *src;
148    size_t len;
149{
150    size_t dlen = strlen(dest);
151
152    return dlen + strlcpy(dest + dlen, src, (len > dlen? len - dlen: 0));
153}
154
155#endif /* NO_SRTLXXX */
156
157/*
158 * slprintf - format a message into a buffer.  Like sprintf except we
159 * also specify the length of the output buffer, and we handle
160 * %m (error message), %v (visible string),
161 * %q (quoted string), %t (current time) and %I (IP address) formats.
162 * Doesn't do floating-point formats.
163 * Returns the number of chars put into buf.
164 */
165int
166slprintf __V((char *buf, int buflen, char *fmt, ...))
167{
168    va_list args;
169    int n;
170
171#if defined(__STDC__)
172    va_start(args, fmt);
173#else
174    char *buf;
175    int buflen;
176    char *fmt;
177    va_start(args);
178    buf = va_arg(args, char *);
179    buflen = va_arg(args, int);
180    fmt = va_arg(args, char *);
181#endif
182    n = vslprintf(buf, buflen, fmt, args);
183    va_end(args);
184    return n;
185}
186
187/*
188 * vslprintf - like slprintf, takes a va_list instead of a list of args.
189 */
190#define OUTCHAR(c)	(buflen > 0? (--buflen, *buf++ = (c)): 0)
191
192int
193vslprintf(buf, buflen, fmt, args)
194    char *buf;
195    int buflen;
196    char *fmt;
197    va_list args;
198{
199    int c, i, n;
200    int width, prec, fillch;
201    int base, len, neg, quoted;
202    unsigned long val = 0;
203    char *str, *f, *buf0;
204    unsigned char *p;
205    char num[32];
206    time_t t;
207    u_int32_t ip;
208    static char hexchars[] = "0123456789abcdef";
209    struct buffer_info bufinfo;
210
211    buf0 = buf;
212    --buflen;
213    while (buflen > 0) {
214	for (f = fmt; *f != '%' && *f != 0; ++f)
215	    ;
216	if (f > fmt) {
217	    len = f - fmt;
218	    if (len > buflen)
219		len = buflen;
220	    memcpy(buf, fmt, len);
221	    buf += len;
222	    buflen -= len;
223	    fmt = f;
224	}
225	if (*fmt == 0)
226	    break;
227	c = *++fmt;
228	width = 0;
229	prec = -1;
230	fillch = ' ';
231	if (c == '0') {
232	    fillch = '0';
233	    c = *++fmt;
234	}
235	if (c == '*') {
236	    width = va_arg(args, int);
237	    c = *++fmt;
238	} else {
239	    while (isdigit(c)) {
240		width = width * 10 + c - '0';
241		c = *++fmt;
242	    }
243	}
244	if (c == '.') {
245	    c = *++fmt;
246	    if (c == '*') {
247		prec = va_arg(args, int);
248		c = *++fmt;
249	    } else {
250		prec = 0;
251		while (isdigit(c)) {
252		    prec = prec * 10 + c - '0';
253		    c = *++fmt;
254		}
255	    }
256	}
257	str = 0;
258	base = 0;
259	neg = 0;
260	++fmt;
261	switch (c) {
262	case 'l':
263	    c = *fmt++;
264	    switch (c) {
265	    case 'd':
266		val = va_arg(args, long);
267		if ((long)val < 0) {
268		    neg = 1;
269		    val = -val;
270		}
271		base = 10;
272		break;
273	    case 'u':
274		val = va_arg(args, unsigned long);
275		base = 10;
276		break;
277	    default:
278		*buf++ = '%'; --buflen;
279		*buf++ = 'l'; --buflen;
280		--fmt;		/* so %lz outputs %lz etc. */
281		continue;
282	    }
283	    break;
284	case 'd':
285	    i = va_arg(args, int);
286	    if (i < 0) {
287		neg = 1;
288		val = -i;
289	    } else
290		val = i;
291	    base = 10;
292	    break;
293	case 'u':
294	    val = va_arg(args, unsigned int);
295	    base = 10;
296	    break;
297	case 'o':
298	    val = va_arg(args, unsigned int);
299	    base = 8;
300	    break;
301	case 'x':
302	case 'X':
303	    val = va_arg(args, unsigned int);
304	    base = 16;
305	    break;
306	case 'p':
307	    val = (unsigned long) va_arg(args, void *);
308	    base = 16;
309	    neg = 2;
310	    break;
311	case 's':
312	    str = va_arg(args, char *);
313	    break;
314	case 'c':
315	    num[0] = va_arg(args, int);
316	    num[1] = 0;
317	    str = num;
318	    break;
319	case 'm':
320	    str = strerror(errno);
321	    break;
322	case 'I':
323	    ip = va_arg(args, u_int32_t);
324	    ip = ntohl(ip);
325	    slprintf(num, sizeof(num), "%d.%d.%d.%d", (ip >> 24) & 0xff,
326		     (ip >> 16) & 0xff, (ip >> 8) & 0xff, ip & 0xff);
327	    str = num;
328	    break;
329#if 0	/* not used, and breaks on S/390, apparently */
330	case 'r':
331	    f = va_arg(args, char *);
332#ifndef __powerpc__
333	    n = vslprintf(buf, buflen + 1, f, va_arg(args, va_list));
334#else
335	    /* On the powerpc, a va_list is an array of 1 structure */
336	    n = vslprintf(buf, buflen + 1, f, va_arg(args, void *));
337#endif
338	    buf += n;
339	    buflen -= n;
340	    continue;
341#endif
342	case 't':
343	    time(&t);
344	    str = ctime(&t);
345	    str += 4;		/* chop off the day name */
346	    str[15] = 0;	/* chop off year and newline */
347	    break;
348	case 'v':		/* "visible" string */
349	case 'q':		/* quoted string */
350	    quoted = c == 'q';
351	    p = va_arg(args, unsigned char *);
352	    if (fillch == '0' && prec >= 0) {
353		n = prec;
354	    } else {
355		n = strlen((char *)p);
356		if (prec >= 0 && n > prec)
357		    n = prec;
358	    }
359	    while (n > 0 && buflen > 0) {
360		c = *p++;
361		--n;
362		if (!quoted && c >= 0x80) {
363		    OUTCHAR('M');
364		    OUTCHAR('-');
365		    c -= 0x80;
366		}
367		if (quoted && (c == '"' || c == '\\'))
368		    OUTCHAR('\\');
369		if (c < 0x20 || (0x7f <= c && c < 0xa0)) {
370		    if (quoted) {
371			OUTCHAR('\\');
372			switch (c) {
373			case '\t':	OUTCHAR('t');	break;
374			case '\n':	OUTCHAR('n');	break;
375			case '\b':	OUTCHAR('b');	break;
376			case '\f':	OUTCHAR('f');	break;
377			default:
378			    OUTCHAR('x');
379			    OUTCHAR(hexchars[c >> 4]);
380			    OUTCHAR(hexchars[c & 0xf]);
381			}
382		    } else {
383			if (c == '\t')
384			    OUTCHAR(c);
385			else {
386			    OUTCHAR('^');
387			    OUTCHAR(c ^ 0x40);
388			}
389		    }
390		} else
391		    OUTCHAR(c);
392	    }
393	    continue;
394	case 'P':		/* print PPP packet */
395	    bufinfo.ptr = buf;
396	    bufinfo.len = buflen + 1;
397	    p = va_arg(args, unsigned char *);
398	    n = va_arg(args, int);
399	    format_packet(p, n, vslp_printer, &bufinfo);
400	    buf = bufinfo.ptr;
401	    buflen = bufinfo.len - 1;
402	    continue;
403	case 'B':
404	    p = va_arg(args, unsigned char *);
405	    for (n = prec; n > 0; --n) {
406		c = *p++;
407		if (fillch == ' ')
408		    OUTCHAR(' ');
409		OUTCHAR(hexchars[(c >> 4) & 0xf]);
410		OUTCHAR(hexchars[c & 0xf]);
411	    }
412	    continue;
413	default:
414	    *buf++ = '%';
415	    if (c != '%')
416		--fmt;		/* so %z outputs %z etc. */
417	    --buflen;
418	    continue;
419	}
420	if (base != 0) {
421	    str = num + sizeof(num);
422	    *--str = 0;
423	    while (str > num + neg) {
424		*--str = hexchars[val % base];
425		val = val / base;
426		if (--prec <= 0 && val == 0)
427		    break;
428	    }
429	    switch (neg) {
430	    case 1:
431		*--str = '-';
432		break;
433	    case 2:
434		*--str = 'x';
435		*--str = '0';
436		break;
437	    }
438	    len = num + sizeof(num) - 1 - str;
439	} else {
440	    len = strlen(str);
441	    if (prec >= 0 && len > prec)
442		len = prec;
443	}
444	if (width > 0) {
445	    if (width > buflen)
446		width = buflen;
447	    if ((n = width - len) > 0) {
448		buflen -= n;
449		for (; n > 0; --n)
450		    *buf++ = fillch;
451	    }
452	}
453	if (len > buflen)
454	    len = buflen;
455	memcpy(buf, str, len);
456	buf += len;
457	buflen -= len;
458    }
459    *buf = 0;
460    return buf - buf0;
461}
462
463/*
464 * vslp_printer - used in processing a %P format
465 */
466static void
467vslp_printer __V((void *arg, char *fmt, ...))
468{
469    int n;
470    va_list pvar;
471    struct buffer_info *bi;
472
473#if defined(__STDC__)
474    va_start(pvar, fmt);
475#else
476    void *arg;
477    char *fmt;
478    va_start(pvar);
479    arg = va_arg(pvar, void *);
480    fmt = va_arg(pvar, char *);
481#endif
482
483    bi = (struct buffer_info *) arg;
484    n = vslprintf(bi->ptr, bi->len, fmt, pvar);
485    va_end(pvar);
486
487    bi->ptr += n;
488    bi->len -= n;
489}
490
491#ifdef unused
492/*
493 * log_packet - format a packet and log it.
494 */
495
496void
497log_packet(p, len, prefix, level)
498    u_char *p;
499    int len;
500    char *prefix;
501    int level;
502{
503	init_pr_log(prefix, level);
504	format_packet(p, len, pr_log, &level);
505	end_pr_log();
506}
507#endif /* unused */
508
509/*
510 * format_packet - make a readable representation of a packet,
511 * calling `printer(arg, format, ...)' to output it.
512 */
513static void
514format_packet(p, len, printer, arg)
515    u_char *p;
516    int len;
517    void (*printer) __P((void *, char *, ...));
518    void *arg;
519{
520    int i, n;
521    u_short proto;
522    struct protent *protp;
523
524    if (len >= PPP_HDRLEN && p[0] == PPP_ALLSTATIONS && p[1] == PPP_UI) {
525	p += 2;
526	GETSHORT(proto, p);
527	len -= PPP_HDRLEN;
528	for (i = 0; (protp = protocols[i]) != NULL; ++i)
529	    if (proto == protp->protocol)
530		break;
531	if (protp != NULL) {
532	    printer(arg, "[%s", protp->name);
533	    n = (*protp->printpkt)(p, len, printer, arg);
534	    printer(arg, "]");
535	    p += n;
536	    len -= n;
537	} else {
538	    for (i = 0; (protp = protocols[i]) != NULL; ++i)
539		if (proto == (protp->protocol & ~0x8000))
540		    break;
541	    if (protp != 0 && protp->data_name != 0) {
542#ifdef __APPLE__
543				printer(arg, "[%s data", protp->data_name);
544				if (protp->printdatapkt) {
545					n = (*protp->printdatapkt)(p, len, printer, arg);
546					p += n;
547					len -= n;
548				}
549				printer(arg, "]\n");
550
551                while (len > 0) {
552                    int lcount = (len > 16) ? 16 : len;
553
554                    /* output line (hex 1st, then ascii) */
555                    printer(arg, "  ");
556                    for(i = 0; i < lcount; i++) {
557                        if (i == 8) printer(arg, "  ");
558                        printer(arg, "%.1B", &p[i]);
559                    }
560                    for( ; i < 16; i++) {
561                        if (i == 8) printer(arg, "  ");
562                        printer(arg, "   ");
563                    }
564                    printer(arg, "   '");
565                    for(i = 0; i < lcount; i++)
566                        printer(arg, "%c",(p[i]>=040 && p[i]<=0176)?p[i]:'.');
567                    printer(arg, "'\n");
568
569                    len -= 16;
570                    p += 16;
571                }
572#else
573		printer(arg, "[%s data]\n", protp->data_name);
574		if (len > 8)
575		    printer(arg, "%.8B ...", p);
576		else
577		    printer(arg, "%.*B", len, p);
578#endif
579		len = 0;
580	    } else
581		printer(arg, "[proto=0x%x]", proto);
582	}
583    }
584
585    if (len > 32)
586	printer(arg, "%.32B ...", p);
587    else
588	printer(arg, "%.*B", len, p);
589}
590
591/*
592 * init_pr_log, end_pr_log - initialize and finish use of pr_log.
593 */
594
595static char line[256];		/* line to be logged accumulated here */
596static char *linep;		/* current pointer within line */
597static int llevel;		/* level for logging */
598
599void
600init_pr_log(prefix, level)
601     char *prefix;
602     int level;
603{
604	linep = line;
605	if (prefix != NULL) {
606		strlcpy(line, prefix, sizeof(line));
607		linep = line + strlen(line);
608	}
609	llevel = level;
610}
611
612void
613end_pr_log()
614{
615	if (linep != line) {
616		*linep = 0;
617		log_write(llevel, line);
618	}
619}
620
621/*
622 * pr_log - printer routine for outputting to syslog
623 */
624void
625pr_log __V((void *arg, char *fmt, ...))
626{
627	int l, n;
628	va_list pvar;
629	char *p, *eol;
630	char buf[256];
631
632#if defined(__STDC__)
633	va_start(pvar, fmt);
634#else
635	void *arg;
636	char *fmt;
637	va_start(pvar);
638	arg = va_arg(pvar, void *);
639	fmt = va_arg(pvar, char *);
640#endif
641
642	n = vslprintf(buf, sizeof(buf), fmt, pvar);
643	va_end(pvar);
644
645	p = buf;
646	eol = strchr(buf, '\n');
647	if (linep != line) {
648		l = (eol == NULL)? n: eol - buf;
649		if (linep + l < line + sizeof(line)) {
650			if (l > 0) {
651				memcpy(linep, buf, l);
652				linep += l;
653			}
654			if (eol == NULL)
655				return;
656			p = eol + 1;
657			eol = strchr(p, '\n');
658		}
659		*linep = 0;
660		log_write(llevel, line);
661		linep = line;
662	}
663
664	while (eol != NULL) {
665		*eol = 0;
666		log_write(llevel, p);
667		p = eol + 1;
668		eol = strchr(p, '\n');
669	}
670
671	/* assumes sizeof(buf) <= sizeof(line) */
672	l = buf + n - p;
673	if (l > 0) {
674		memcpy(line, p, n);
675		linep = line + l;
676	}
677}
678
679/*
680 * print_string - print a readable representation of a string using
681 * printer.
682 */
683void
684print_string(p, len, printer, arg)
685    char *p;
686    int len;
687    void (*printer) __P((void *, char *, ...));
688    void *arg;
689{
690    int c;
691
692    printer(arg, "\"");
693    for (; len > 0; --len) {
694	c = *p++;
695	if (' ' <= c && c <= '~') {
696	    if (c == '\\' || c == '"')
697		printer(arg, "\\");
698	    printer(arg, "%c", c);
699	} else {
700	    switch (c) {
701	    case '\n':
702		printer(arg, "\\n");
703		break;
704	    case '\r':
705		printer(arg, "\\r");
706		break;
707	    case '\t':
708		printer(arg, "\\t");
709		break;
710	    default:
711		printer(arg, "\\%.3o", c);
712	    }
713	}
714    }
715    printer(arg, "\"");
716}
717
718/*
719 * logit - does the hard work for fatal et al.
720 */
721static void
722logit(level, fmt, args)
723    int level;
724    char *fmt;
725    va_list args;
726{
727    int n;
728#ifdef __APPLE__
729    char buf[4096];
730#else
731    char buf[1024];
732#endif
733
734    n = vslprintf(buf, sizeof(buf), fmt, args);
735    log_write(level, buf);
736}
737
738static void
739log_write(level, buf)
740    int level;
741    char *buf;
742{
743#ifdef __APPLE__
744    time_t t;
745    int ns;
746    char s[64];
747#endif
748
749    syslog(level, "%s", buf);
750    if (log_to_fd >= 0 && (level != LOG_DEBUG || debug)) {
751	int n = strlen(buf);
752
753#ifdef __APPLE__
754	time(&t);
755	ns = strftime(s, sizeof(s), "%c : ", localtime(&t));
756        if (write(log_to_fd, s, ns) != ns)
757            log_to_fd = -1;
758#endif
759
760	if (n > 0 && buf[n-1] == '\n')
761	    --n;
762	if (write(log_to_fd, buf, n) != n
763	    || write(log_to_fd, "\n", 1) != 1)
764	    log_to_fd = -1;
765    }
766}
767
768/*
769 * fatal - log an error message and die horribly.
770 */
771void
772fatal __V((char *fmt, ...))
773{
774    va_list pvar;
775
776#if defined(__STDC__)
777    va_start(pvar, fmt);
778#else
779    char *fmt;
780    va_start(pvar);
781    fmt = va_arg(pvar, char *);
782#endif
783
784    logit(LOG_ERR, fmt, pvar);
785    va_end(pvar);
786
787    die(1);			/* as promised */
788}
789
790/*
791 * error - log an error message.
792 */
793void
794error __V((char *fmt, ...))
795{
796    va_list pvar;
797
798#if defined(__STDC__)
799    va_start(pvar, fmt);
800#else
801    char *fmt;
802    va_start(pvar);
803    fmt = va_arg(pvar, char *);
804#endif
805
806    logit(LOG_ERR, fmt, pvar);
807    va_end(pvar);
808    ++error_count;
809}
810
811/*
812 * warn - log a warning message.
813 */
814void
815#ifdef __APPLE__
816warning
817#else
818warn
819#endif
820 __V((char *fmt, ...))
821{
822    va_list pvar;
823
824#if defined(__STDC__)
825    va_start(pvar, fmt);
826#else
827    char *fmt;
828    va_start(pvar);
829    fmt = va_arg(pvar, char *);
830#endif
831
832    logit(LOG_WARNING, fmt, pvar);
833    va_end(pvar);
834}
835
836/*
837 * notice - log a notice-level message.
838 */
839void
840notice __V((char *fmt, ...))
841{
842    va_list pvar;
843
844#if defined(__STDC__)
845    va_start(pvar, fmt);
846#else
847    char *fmt;
848    va_start(pvar);
849    fmt = va_arg(pvar, char *);
850#endif
851
852    logit(LOG_NOTICE, fmt, pvar);
853    va_end(pvar);
854}
855
856/*
857 * info - log an informational message.
858 */
859void
860info __V((char *fmt, ...))
861{
862    va_list pvar;
863
864#if defined(__STDC__)
865    va_start(pvar, fmt);
866#else
867    char *fmt;
868    va_start(pvar);
869    fmt = va_arg(pvar, char *);
870#endif
871
872    logit(LOG_INFO, fmt, pvar);
873    va_end(pvar);
874}
875
876/*
877 * dbglog - log a debug message.
878 */
879void
880dbglog __V((char *fmt, ...))
881{
882    va_list pvar;
883
884#if defined(__STDC__)
885    va_start(pvar, fmt);
886#else
887    char *fmt;
888    va_start(pvar);
889    fmt = va_arg(pvar, char *);
890#endif
891
892    logit(LOG_DEBUG, fmt, pvar);
893    va_end(pvar);
894}
895
896/*
897 * dump_packet - print out a packet in readable form if it is interesting.
898 * Assumes len >= PPP_HDRLEN.
899 */
900void
901dump_packet(const char *tag, unsigned char *p, int len)
902{
903    int proto;
904
905    if (!debug)
906	return;
907
908    /*
909     * don't print LCP echo request/reply packets if debug <= 1
910     * and the link is up.
911     */
912    proto = (p[2] << 8) + p[3];
913    if (debug <= 1 && unsuccess == 0 && proto == PPP_LCP
914	&& len >= PPP_HDRLEN + HEADERLEN) {
915	unsigned char *lcp = p + PPP_HDRLEN;
916	int l = (lcp[2] << 8) + lcp[3];
917	if ((lcp[0] == ECHOREQ || lcp[0] == ECHOREP
918#ifdef __APPLE__
919            || lcp[0] == TIMEREMAINING
920#endif
921        )
922	    && l >= HEADERLEN && l <= len - PPP_HDRLEN)
923	    return;
924    }
925
926    dbglog("%s %P", tag, p, len);
927}
928
929/*
930 * complete_read - read a full `count' bytes from fd,
931 * unless end-of-file or an error other than EINTR is encountered.
932 */
933ssize_t
934complete_read(int fd, void *buf, size_t count)
935{
936	size_t done;
937	ssize_t nb;
938	char *ptr = buf;
939
940	for (done = 0; done < count; ) {
941		nb = read(fd, ptr, count - done);
942		if (nb < 0) {
943			if (errno == EINTR)
944				continue;
945			return -1;
946		}
947		if (nb == 0)
948			break;
949		done += nb;
950		ptr += nb;
951	}
952	return done;
953}
954
955/* Procedures for locking the serial device using a lock file. */
956#ifndef LOCK_DIR
957#ifdef __linux__
958#define LOCK_DIR	"/var/lock"
959#else
960#ifdef SVR4
961#define LOCK_DIR	"/var/spool/locks"
962#else
963#define LOCK_DIR	"/var/spool/lock"
964#endif
965#endif
966#endif /* LOCK_DIR */
967
968static char lock_file[MAXPATHLEN];
969
970/*
971 * lock - create a lock file for the named device
972 */
973int
974lock(dev)
975    char *dev;
976{
977#ifdef LOCKLIB
978    int result;
979
980    result = mklock (dev, (void *) 0);
981    if (result == 0) {
982	strlcpy(lock_file, dev, sizeof(lock_file));
983	return 0;
984    }
985
986    if (result > 0)
987        notice("Device %s is locked by pid %d", dev, result);
988    else
989	error("Can't create lock file %s", lock_file);
990    return -1;
991
992#else /* LOCKLIB */
993
994    char lock_buffer[12];
995    int fd, pid, n;
996
997#ifdef SVR4
998    struct stat sbuf;
999
1000    if (stat(dev, &sbuf) < 0) {
1001	error("Can't get device number for %s: %m", dev);
1002	return -1;
1003    }
1004    if ((sbuf.st_mode & S_IFMT) != S_IFCHR) {
1005	error("Can't lock %s: not a character device", dev);
1006	return -1;
1007    }
1008    slprintf(lock_file, sizeof(lock_file), "%s/LK.%03d.%03d.%03d",
1009	     LOCK_DIR, major(sbuf.st_dev),
1010	     major(sbuf.st_rdev), minor(sbuf.st_rdev));
1011#else
1012    char *p;
1013    char lockdev[MAXPATHLEN];
1014
1015    if ((p = strstr(dev, "dev/")) != NULL) {
1016	dev = p + 4;
1017	strncpy(lockdev, dev, MAXPATHLEN-1);
1018	lockdev[MAXPATHLEN-1] = 0;
1019	while ((p = strrchr(lockdev, '/')) != NULL) {
1020	    *p = '_';
1021	}
1022	dev = lockdev;
1023    } else
1024	if ((p = strrchr(dev, '/')) != NULL)
1025	    dev = p + 1;
1026
1027    slprintf(lock_file, sizeof(lock_file), "%s/LCK..%s", LOCK_DIR, dev);
1028#endif
1029
1030    while ((fd = open(lock_file, O_EXCL | O_CREAT | O_RDWR, 0644)) < 0) {
1031	if (errno != EEXIST) {
1032	    error("Can't create lock file %s: %m", lock_file);
1033	    break;
1034	}
1035
1036	/* Read the lock file to find out who has the device locked. */
1037	fd = open(lock_file, O_RDONLY, 0);
1038	if (fd < 0) {
1039	    if (errno == ENOENT) /* This is just a timing problem. */
1040		continue;
1041	    error("Can't open existing lock file %s: %m", lock_file);
1042	    break;
1043	}
1044#ifndef LOCK_BINARY
1045	n = read(fd, lock_buffer, 11);
1046#else
1047	n = read(fd, &pid, sizeof(pid));
1048#endif /* LOCK_BINARY */
1049	close(fd);
1050	fd = -1;
1051	if (n <= 0) {
1052	    error("Can't read pid from lock file %s", lock_file);
1053	    break;
1054	}
1055
1056	/* See if the process still exists. */
1057#ifndef LOCK_BINARY
1058	lock_buffer[n] = 0;
1059	pid = atoi(lock_buffer);
1060#endif /* LOCK_BINARY */
1061	if (pid == getpid())
1062	    return 1;		/* somebody else locked it for us */
1063	if (pid == 0
1064	    || (kill(pid, 0) == -1 && errno == ESRCH)) {
1065	    if (unlink (lock_file) == 0) {
1066		notice("Removed stale lock on %s (pid %d)", dev, pid);
1067		continue;
1068	    }
1069	    warning("Couldn't remove stale lock on %s", dev);
1070	} else
1071	    notice("Device %s is locked by pid %d", dev, pid);
1072	break;
1073    }
1074
1075    if (fd < 0) {
1076	lock_file[0] = 0;
1077	return -1;
1078    }
1079
1080    pid = getpid();
1081#ifndef LOCK_BINARY
1082    slprintf(lock_buffer, sizeof(lock_buffer), "%10d\n", pid);
1083    write (fd, lock_buffer, 11);
1084#else
1085    write(fd, &pid, sizeof (pid));
1086#endif
1087    close(fd);
1088    return 0;
1089
1090#endif
1091}
1092
1093/*
1094 * relock - called to update our lockfile when we are about to detach,
1095 * thus changing our pid (we fork, the child carries on, and the parent dies).
1096 * Note that this is called by the parent, with pid equal to the pid
1097 * of the child.  This avoids a potential race which would exist if
1098 * we had the child rewrite the lockfile (the parent might die first,
1099 * and another process could think the lock was stale if it checked
1100 * between when the parent died and the child rewrote the lockfile).
1101 */
1102int
1103relock(pid)
1104    int pid;
1105{
1106#ifdef LOCKLIB
1107    /* XXX is there a way to do this? */
1108    return -1;
1109#else /* LOCKLIB */
1110
1111    int fd;
1112    char lock_buffer[12];
1113
1114    if (lock_file[0] == 0)
1115	return -1;
1116    fd = open(lock_file, O_WRONLY, 0);
1117    if (fd < 0) {
1118	error("Couldn't reopen lock file %s: %m", lock_file);
1119	lock_file[0] = 0;
1120	return -1;
1121    }
1122
1123#ifndef LOCK_BINARY
1124    slprintf(lock_buffer, sizeof(lock_buffer), "%10d\n", pid);
1125    write (fd, lock_buffer, 11);
1126#else
1127    write(fd, &pid, sizeof(pid));
1128#endif /* LOCK_BINARY */
1129    close(fd);
1130    return 0;
1131
1132#endif /* LOCKLIB */
1133}
1134
1135/*
1136 * unlock - remove our lockfile
1137 */
1138void
1139unlock()
1140{
1141    if (lock_file[0]) {
1142#ifdef LOCKLIB
1143	(void) rmlock(lock_file, (void *) 0);
1144#else
1145	unlink(lock_file);
1146#endif
1147	lock_file[0] = 0;
1148    }
1149}
1150
1151static char unknown_if_family_str[16];
1152static char *
1153if_family2ascii (u_int32_t if_family)
1154{
1155	switch (if_family) {
1156		case APPLE_IF_FAM_LOOPBACK:
1157			return("Loopback");
1158		case APPLE_IF_FAM_ETHERNET:
1159			return("Ether");
1160		case APPLE_IF_FAM_SLIP:
1161			return("SLIP");
1162		case APPLE_IF_FAM_TUN:
1163			return("TUN");
1164		case APPLE_IF_FAM_VLAN:
1165			return("VLAN");
1166		case APPLE_IF_FAM_PPP:
1167			return("PPP");
1168		case APPLE_IF_FAM_PVC:
1169			return("PVC");
1170		case APPLE_IF_FAM_DISC:
1171			return("DISC");
1172		case APPLE_IF_FAM_MDECAP:
1173			return("MDECAP");
1174		case APPLE_IF_FAM_GIF:
1175			return("GIF");
1176		case APPLE_IF_FAM_FAITH:
1177			return("FAITH");
1178		case APPLE_IF_FAM_STF:
1179			return("STF");
1180		case APPLE_IF_FAM_FIREWIRE:
1181			return("FireWire");
1182		case APPLE_IF_FAM_BOND:
1183			return("Bond");
1184		default:
1185			snprintf(unknown_if_family_str, sizeof(unknown_if_family_str), "%d", if_family);
1186			return(unknown_if_family_str);
1187	}
1188}
1189
1190void
1191log_vpn_interface_address_event (const char                  *location,
1192								 struct kern_event_msg *ev_msg,
1193								 int                    wait_interface_timeout,
1194								 u_char                  *interface,
1195								 struct in_addr        *our_address)
1196{
1197	struct in_addr mask;
1198	char   our_addr_str[INET_ADDRSTRLEN];
1199
1200	if (!ev_msg) {
1201		notice("%s: %d secs TIMEOUT waiting for interface to be reconfigured. previous setting (name: %s, address: %s).",
1202			   location,
1203			   wait_interface_timeout,
1204			   interface,
1205			   addr2ascii(AF_INET, our_address, sizeof(*our_address), our_addr_str));
1206		return;
1207	} else {
1208		struct kev_in_data      *inetdata = (struct kev_in_data *) &ev_msg->event_data[0];
1209		struct kev_in_collision *inetdata_coll = (struct kev_in_collision *) &ev_msg->event_data[0];
1210		char                     new_addr_str[INET_ADDRSTRLEN];
1211		char                     new_mask_str[INET_ADDRSTRLEN];
1212		char                     dst_addr_str[INET_ADDRSTRLEN];
1213
1214		mask.s_addr = ntohl(inetdata->ia_subnetmask);
1215
1216		switch (ev_msg->event_code) {
1217			case KEV_INET_NEW_ADDR:
1218				notice("%s: Address added. previous interface setting (name: %s, address: %s), current interface setting (name: %s%d, family: %s, address: %s, subnet: %s, destination: %s).",
1219					   location,
1220					   interface,
1221					   addr2ascii(AF_INET, our_address, sizeof(*our_address), our_addr_str),
1222					   inetdata->link_data.if_name, inetdata->link_data.if_unit,
1223					   if_family2ascii(inetdata->link_data.if_family),
1224					   addr2ascii(AF_INET, &inetdata->ia_addr, sizeof(inetdata->ia_addr), new_addr_str),
1225					   addr2ascii(AF_INET, &mask, sizeof(mask), new_mask_str),
1226					   addr2ascii(AF_INET, &inetdata->ia_dstaddr, sizeof(inetdata->ia_dstaddr), dst_addr_str));
1227				break;
1228			case KEV_INET_CHANGED_ADDR:
1229				notice("%s: Address changed. previous interface setting (name: %s, address: %s), current interface setting (name: %s%d, family: %s, address: %s, subnet: %s, destination: %s).",
1230					   location,
1231					   interface,
1232					   addr2ascii(AF_INET, our_address, sizeof(*our_address), our_addr_str),
1233					   inetdata->link_data.if_name, inetdata->link_data.if_unit,
1234					   if_family2ascii(inetdata->link_data.if_family),
1235					   addr2ascii(AF_INET, &inetdata->ia_addr, sizeof(inetdata->ia_addr), new_addr_str),
1236					   addr2ascii(AF_INET, &mask, sizeof(mask), new_mask_str),
1237					   addr2ascii(AF_INET, &inetdata->ia_dstaddr, sizeof(inetdata->ia_dstaddr), dst_addr_str));
1238				break;
1239			case KEV_INET_ADDR_DELETED:
1240				notice("%s: Address deleted. previous interface setting (name: %s, address: %s), deleted interface setting (name: %s%d, family: %s, address: %s, subnet: %s, destination: %s).",
1241					   location,
1242					   interface,
1243					   addr2ascii(AF_INET, our_address, sizeof(*our_address), our_addr_str),
1244					   inetdata->link_data.if_name, inetdata->link_data.if_unit,
1245					   if_family2ascii(inetdata->link_data.if_family),
1246					   addr2ascii(AF_INET, &inetdata->ia_addr, sizeof(inetdata->ia_addr), new_addr_str),
1247					   addr2ascii(AF_INET, &mask, sizeof(mask), new_mask_str),
1248					   addr2ascii(AF_INET, &inetdata->ia_dstaddr, sizeof(inetdata->ia_dstaddr), dst_addr_str));
1249				break;
1250			case KEV_INET_ARPCOLLISION:
1251				notice("%s: ARP collided. previous interface setting (name: %s, address: %s), conflicting interface setting (name: %s%d, family: %s, address: %s, mac: %x:%x:%x:%x:%x:%x).",
1252					   location,
1253					   interface,
1254					   addr2ascii(AF_INET, our_address, sizeof(*our_address), our_addr_str),
1255					   inetdata_coll->link_data.if_name,
1256					   inetdata_coll->link_data.if_unit,
1257					   if_family2ascii(inetdata_coll->link_data.if_family),
1258					   addr2ascii(AF_INET, &inetdata_coll->ia_ipaddr, sizeof(inetdata_coll->ia_ipaddr), new_addr_str),
1259					   inetdata_coll->hw_addr[5],inetdata_coll->hw_addr[4],inetdata_coll->hw_addr[3],inetdata_coll->hw_addr[2],inetdata_coll->hw_addr[1],inetdata_coll->hw_addr[0]);
1260				break;
1261			default:
1262				notice("%s: Other Address event (%d). previous interface setting (name: %s, address: %s), other interface setting (name: %s%d, family: %s, address: %s, subnet: %s, destination: %s).",
1263					   location,
1264					   ev_msg->event_code,
1265					   interface,
1266					   addr2ascii(AF_INET, our_address, sizeof(*our_address), our_addr_str),
1267					   inetdata->link_data.if_name, inetdata->link_data.if_unit,
1268					   if_family2ascii(inetdata->link_data.if_family),
1269					   addr2ascii(AF_INET, &inetdata->ia_addr, sizeof(inetdata->ia_addr), new_addr_str),
1270					   addr2ascii(AF_INET, &mask, sizeof(mask), new_mask_str),
1271					   addr2ascii(AF_INET, &inetdata->ia_dstaddr, sizeof(inetdata->ia_dstaddr), dst_addr_str));
1272				break;
1273		}
1274	}
1275}
1276
1277int
1278check_vpn_interface_or_service_unrecoverable (SCDynamicStoreRef dynamicStoreRef,
1279					      const char                  *location,
1280					      struct kern_event_msg *ev_msg,
1281						  char                  *interface_buf)
1282{
1283	//SCDynamicStoreRef dynamicStoreRef = (SCDynamicStoreRef)dynamicStore;
1284
1285	// return 1, if this is a delete event, and;
1286	// TODO: add support for IPv6 <rdar://problem/5920237>
1287	// walk Setup:/Network/Service/* and check if there are service entries referencing this interface. e.g. Setup:/Network/Service/44DB8790-0177-4F17-8D4E-37F9413D1D87/Interface:DeviceName == interface, other_serv_found = 1
1288	// Setup:/Network/Interface/"interface"/AirPort:'PowerEnable' == 0 || Setup:/Network/Interface/"interface"/IPv4 is missing, interf_down = 1
1289	if (!dynamicStoreRef)
1290		dbglog("%s: invalid SCDynamicStore reference", location);
1291
1292	if (dynamicStoreRef &&
1293	    (ev_msg->event_code == KEV_INET_ADDR_DELETED || ev_msg->event_code == KEV_INET_CHANGED_ADDR)) {
1294		CFStringRef       interf_key;
1295		CFMutableArrayRef interf_keys;
1296		CFStringRef       pattern;
1297		CFMutableArrayRef patterns;
1298		CFDictionaryRef   dict = NULL;
1299		CFIndex           i;
1300		const void *      keys_q[128];
1301		const void **     keys = keys_q;
1302		const void *      values_q[128];
1303		const void **     values = values_q;
1304		CFIndex           n;
1305		CFStringRef       vpn_if;
1306		int               other_serv_found = 0, interf_down = 0;
1307
1308		vpn_if = CFStringCreateWithCStringNoCopy(NULL,
1309							 interface_buf,
1310							 kCFStringEncodingASCII,
1311							 kCFAllocatorNull);
1312		if (!vpn_if) {
1313			// if we could not initialize interface CFString
1314			notice("%s: failed to initialize interface CFString", location);
1315			goto done;
1316		}
1317
1318		interf_keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1319		patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1320		// get Setup:/Network/Interface/<vpn_if>/Airport
1321		interf_key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
1322									   kSCDynamicStoreDomainSetup,
1323									   vpn_if,
1324									   kSCEntNetAirPort);
1325		CFArrayAppendValue(interf_keys, interf_key);
1326		CFRelease(interf_key);
1327		// get State:/Network/Interface/<vpn_if>/Airport
1328		interf_key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
1329									   kSCDynamicStoreDomainState,
1330									   vpn_if,
1331									   kSCEntNetAirPort);
1332		CFArrayAppendValue(interf_keys, interf_key);
1333		CFRelease(interf_key);
1334		// get Setup:/Network/Service/*/Interface
1335		pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
1336								      kSCDynamicStoreDomainSetup,
1337								      kSCCompAnyRegex,
1338								      kSCEntNetInterface);
1339		CFArrayAppendValue(patterns, pattern);
1340		CFRelease(pattern);
1341		// get Setup:/Network/Service/*/IPv4
1342		pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
1343								      kSCDynamicStoreDomainSetup,
1344								      kSCCompAnyRegex,
1345								      kSCEntNetIPv4);
1346		CFArrayAppendValue(patterns, pattern);
1347		CFRelease(pattern);
1348		dict = SCDynamicStoreCopyMultiple(dynamicStoreRef, interf_keys, patterns);
1349		CFRelease(interf_keys);
1350		CFRelease(patterns);
1351
1352		if (!dict) {
1353			// if we could not access the SCDynamicStore
1354			notice("%s: failed to initialize SCDynamicStore dictionary", location);
1355			CFRelease(vpn_if);
1356			goto done;
1357		}
1358		// look for the service which matches the provided prefixes
1359		n = CFDictionaryGetCount(dict);
1360		if (n <= 0) {
1361			notice("%s: empty SCDynamicStore dictionary", location);
1362			CFRelease(vpn_if);
1363			goto done;
1364		}
1365		if (n > (CFIndex)(sizeof(keys_q) / sizeof(CFTypeRef))) {
1366			keys   = CFAllocatorAllocate(NULL, n * sizeof(CFTypeRef), 0);
1367			values = CFAllocatorAllocate(NULL, n * sizeof(CFTypeRef), 0);
1368		}
1369		CFDictionaryGetKeysAndValues(dict, keys, values);
1370		for (i=0; i < n; i++) {
1371			CFStringRef     s_key  = (CFStringRef)keys[i];
1372			CFDictionaryRef s_dict = (CFDictionaryRef)values[i];
1373			CFStringRef     s_if;
1374
1375			if (!isA_CFString(s_key) || !isA_CFDictionary(s_dict)) {
1376				continue;
1377			}
1378
1379			if (CFStringHasSuffix(s_key, kSCEntNetInterface)) {
1380				// is a Service Interface entity
1381				s_if = CFDictionaryGetValue(s_dict, kSCPropNetInterfaceDeviceName);
1382				if (isA_CFString(s_if) && CFEqual(vpn_if, s_if)) {
1383					CFArrayRef        components;
1384					CFStringRef       serviceIDRef = NULL, serviceKey = NULL;
1385					CFPropertyListRef serviceRef = NULL;
1386
1387					other_serv_found = 1;
1388					// extract service ID
1389					components = CFStringCreateArrayBySeparatingStrings(NULL, s_key, CFSTR("/"));
1390					if (CFArrayGetCount(components) > 3) {
1391						serviceIDRef = CFArrayGetValueAtIndex(components, 3);
1392						//if (new key) Setup:/Network/Service/service_id/IPv4 is missing, then interf_down = 1
1393						serviceKey = SCDynamicStoreKeyCreateNetworkServiceEntity(0, kSCDynamicStoreDomainSetup, serviceIDRef, kSCEntNetIPv4);
1394						if (!serviceKey ||
1395						    !(serviceRef = CFDictionaryGetValue(dict, serviceKey))) {
1396							notice("%s: detected disabled IPv4 Config", location);
1397							interf_down = 1;
1398						}
1399						if (serviceKey) CFRelease(serviceKey);
1400					}
1401					if (components) CFRelease(components);
1402					if (interf_down) break;
1403				}
1404				continue;
1405			} else if (CFStringHasSuffix(s_key, kSCEntNetAirPort)) {
1406				// Interface/<vpn_if>/Airport entity
1407				if (CFStringHasPrefix(s_key, kSCDynamicStoreDomainSetup)) {
1408					CFBooleanRef powerEnable = CFDictionaryGetValue(s_dict, SC_AIRPORT_POWERENABLED_KEY);
1409					if (isA_CFBoolean(powerEnable) &&
1410					    CFEqual(powerEnable, kCFBooleanFalse)) {
1411						notice("%s: detected AirPort, PowerEnable == FALSE", location);
1412						interf_down = 1;
1413						break;
1414					}
1415				} else if (CFStringHasPrefix(s_key, kSCDynamicStoreDomainState)) {
1416					UInt16      temp;
1417					CFNumberRef airStatus = CFDictionaryGetValue(s_dict, SC_AIRPORT_POWERSTATUS_KEY);
1418					if (isA_CFNumber(airStatus) &&
1419					    CFNumberGetValue(airStatus, kCFNumberShortType, &temp)) {
1420						if (temp ==0) {
1421							notice("%s: detected AirPort, PowerStatus == 0", location);
1422						}
1423					}
1424				}
1425				continue;
1426			}
1427		}
1428		if (vpn_if) CFRelease(vpn_if);
1429		if (keys != keys_q) {
1430			CFAllocatorDeallocate(NULL, keys);
1431			CFAllocatorDeallocate(NULL, values);
1432		}
1433done :
1434		if (dict) CFRelease(dict);
1435
1436		return (other_serv_found == 0 || interf_down == 1);
1437	}
1438	return 0;
1439}
1440
1441int
1442check_vpn_interface_address_change (int                    transport_down,
1443                                    struct kern_event_msg *ev_msg,
1444                                    char                  *interface_buf,
1445									int                    interface_media,
1446                                    struct in_addr        *our_address)
1447{
1448    struct kev_in_data *inetdata;
1449
1450    /* if transport is still down: ignore deletes, and check if the underlying interface's address has changed (ignore link-local addresses) */
1451    if (transport_down &&
1452        (ev_msg->event_code == KEV_INET_NEW_ADDR || ev_msg->event_code == KEV_INET_CHANGED_ADDR)) {
1453 		inetdata = (struct kev_in_data *) &ev_msg->event_data[0];
1454#if 0
1455        notice("%s: checking for interface address change. underlying %s, old-addr %x, new-addr %x\n",
1456               __FUNCTION__, interface_buf, our_address->s_addr, inetdata->ia_addr.s_addr);
1457#endif
1458        /* check if address changed */
1459        if (our_address->s_addr != inetdata->ia_addr.s_addr &&
1460            !IN_LINKLOCAL(ntohl(inetdata->ia_addr.s_addr))) {
1461            return 1;
1462        }
1463    }
1464
1465    return 0;
1466}
1467
1468int
1469check_vpn_interface_alternate (int                    transport_down,
1470                               struct kern_event_msg *ev_msg,
1471                               char                  *interface_buf)
1472{
1473    struct kev_in_data *inetdata;
1474
1475    /* if transport is still down: ignore deletes, and check if an alternative interface has a valid address (ignore link-local) */
1476    if (transport_down &&
1477        (ev_msg->event_code == KEV_INET_NEW_ADDR || ev_msg->event_code == KEV_INET_CHANGED_ADDR)) {
1478 		inetdata = (struct kev_in_data *) &ev_msg->event_data[0];
1479#if 0
1480        notice("%s: checking for alternate interface. underlying %s, new-addr %x\n",
1481               __FUNCTION__, interface_buf, inetdata->ia_addr.s_addr);
1482#endif
1483        if (!IN_LINKLOCAL(ntohl(inetdata->ia_addr.s_addr))) {
1484            return 1;
1485        }
1486    }
1487
1488    return 0;
1489}
1490
1491#if 0
1492/*
1493 * print_hex - hexdump (in out buffer) of binary data (in buffer), for count bytes
1494 */
1495static void
1496print_hex (unsigned char *out, unsigned char *in, int count)
1497{
1498	register unsigned char next_ch;
1499	static char hex[] = "0123456789abcdef";
1500
1501	while (count-- > 0) {
1502		next_ch = *in++;
1503		*out++ = hex[(next_ch >> 4) & 0x0F];
1504		*out++ = hex[next_ch & 0x0F];
1505	}
1506
1507	*out = '\0';
1508}
1509
1510/*
1511 * dump_mppe_keys - print out mppe send/recv keys
1512 */
1513void
1514dump_buffer(char *caller, unsigned char* binbuf, int size)
1515{
1516	if(binbuf)
1517	{
1518		static unsigned char buf[65];
1519
1520		print_hex(buf, binbuf, size);
1521		error("%s: data (%d bits) = %s",caller, size<<3, buf);
1522	}
1523}
1524#endif
1525
1526// check to see if interface is captive and if it is not ready.
1527int
1528check_vpn_interface_captive_and_not_ready (SCDynamicStoreRef  dynamicStoreRef,
1529										   char              *interface_buf)
1530{
1531	int rc = 0;
1532
1533	if (dynamicStoreRef) {
1534		CFStringRef     captiveState = CFStringCreateWithFormat(NULL, NULL,
1535																CFSTR("State:/Network/Interface/%s/CaptiveNetwork"),
1536																interface_buf);
1537		if (captiveState) {
1538			CFStringRef key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, captiveState);
1539			if (key) {
1540				CFDictionaryRef dict = SCDynamicStoreCopyValue(dynamicStoreRef, key);
1541				CFRelease(key);
1542				if (dict) {
1543					CFStringRef string = CFDictionaryGetValue(dict, CFSTR("Stage"));
1544					if (string) {
1545						// if string != Unknown && string != Online
1546						if (CFStringCompare(string, CFSTR("Uknown"), 0) != kCFCompareEqualTo &&
1547							CFStringCompare(string, CFSTR("Online"), 0) != kCFCompareEqualTo) {
1548							notice("underlying interface %s is captive and not yet ready.", interface_buf);
1549							rc = 1;
1550						} else {
1551							notice("underlying interface %s is either unknown or captive and ready.", interface_buf);
1552						}
1553					}
1554					CFRelease(dict);
1555				}
1556			}
1557			CFRelease(captiveState);
1558		}
1559	}
1560	return rc;
1561}
1562