1/*	$NetBSD: pppoectl.c,v 1.23 2011/08/27 18:44:44 joerg Exp $	*/
2
3/*
4 * Copyright (c) 1997 Joerg Wunsch
5 *
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE DEVELOPERS BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * From: spppcontrol.c,v 1.3 1998/01/07 07:55:26 charnier Exp
29 * From: ispppcontrol
30 */
31#include <sys/cdefs.h>
32
33#ifndef lint
34__RCSID("$NetBSD: pppoectl.c,v 1.23 2011/08/27 18:44:44 joerg Exp $");
35#endif
36
37
38#include <sys/param.h>
39#include <sys/callout.h>
40#include <sys/ioctl.h>
41#include <sys/mbuf.h>
42#include <sys/socket.h>
43#include <sys/time.h>
44#include <sys/sysctl.h>
45#include <net/if.h>
46#include <net/if_sppp.h>
47#include <net/if_pppoe.h>
48#include <err.h>
49#include <stdio.h>
50#include <stdlib.h>
51#include <string.h>
52#include <sysexits.h>
53#include <unistd.h>
54
55__dead static void usage(void);
56__dead static void print_error(const char *ifname, int error, const char * str);
57static void print_vals(const char *ifname, int phase, struct spppauthcfg *sp,
58	int lcp_timeout, time_t idle_timeout, int authfailures,
59	int max_auth_failures, u_int maxalive, time_t max_noreceive);
60static const char *phase_name(int phase);
61static const char *proto_name(int proto);
62static const char *authflags(int flags);
63static void pppoectl_argument(char *arg);
64
65static int hz = 0;
66
67static int set_auth, set_lcp, set_idle_to, set_auth_failure, set_dns,
68    clear_auth_failure_count, set_keepalive;
69static int maxalive = -1;
70static int max_noreceive = -1;
71static struct spppauthcfg spr;
72static struct sppplcpcfg lcp;
73static struct spppstatus status;
74static struct spppidletimeout timeout;
75static struct spppauthfailurestats authfailstats;
76static struct spppauthfailuresettings authfailset;
77static struct spppdnssettings dnssettings;
78static struct spppkeepalivesettings keepalivesettings;
79
80int
81main(int argc, char **argv)
82{
83	FILE *fp;
84	int s, c;
85	int errs = 0, verbose = 0, dump = 0, dns1 = 0, dns2 = 0;
86	size_t len;
87	const char *eth_if_name, *access_concentrator, *service;
88	const char *ifname, *configname;
89	char *line;
90	int mib[2];
91	struct clockinfo clockinfo;
92	setprogname(argv[0]);
93
94	eth_if_name = NULL;
95	access_concentrator = NULL;
96	service = NULL;
97	configname = NULL;
98	while ((c = getopt(argc, argv, "vde:f:s:a:n:")) != -1)
99		switch (c) {
100		case 'v':
101			verbose++;
102			break;
103
104		case 'd':
105			dump++;
106			break;
107
108		case 'e':
109			eth_if_name = optarg;
110			break;
111
112		case 'f':
113			configname = optarg;
114			break;
115
116		case 's':
117			service = optarg;
118			break;
119
120		case 'a':
121			access_concentrator = optarg;
122			break;
123
124		case 'n':
125			if (strcmp(optarg, "1") == 0)
126				dns1 = 1;
127			else if (strcmp(optarg, "2") == 0)
128				dns2 = 1;
129			else {
130				fprintf(stderr, "bad argument \"%s\" to -n (only 1 or two allowed)\n",
131					optarg);
132				errs++;
133			}
134			break;
135
136		default:
137			errs++;
138			break;
139		}
140	argv += optind;
141	argc -= optind;
142
143	if (errs || argc < 1)
144		usage();
145
146	ifname = argv[0];
147
148	/* use a random AF to create the socket */
149	if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
150		err(EX_UNAVAILABLE, "ifconfig: socket");
151
152	argc--;
153	argv++;
154
155	if (eth_if_name) {
156		struct pppoediscparms parms;
157		int e;
158
159		memset(&parms, 0, sizeof parms);
160		strncpy(parms.ifname, ifname, sizeof(parms.ifname));
161		strncpy(parms.eth_ifname, eth_if_name, sizeof(parms.eth_ifname));
162		if (access_concentrator) {
163			parms.ac_name = access_concentrator;
164			parms.ac_name_len = strlen(access_concentrator);
165		}
166		if (service) {
167			parms.service_name = service;
168			parms.service_name_len = strlen(service);
169		}
170
171		e = ioctl(s, PPPOESETPARMS, &parms);
172		if (e)
173			print_error(ifname, e, "PPPOESETPARMS");
174		return 0;
175	}
176
177	if (dns1 || dns2) {
178		/* print DNS addresses */
179		int e;
180		struct spppdnsaddrs addrs;
181		memset(&addrs, 0, sizeof addrs);
182		strncpy(addrs.ifname, ifname, sizeof addrs.ifname);
183		e = ioctl(s, SPPPGETDNSADDRS, &addrs);
184		if (e)
185			print_error(ifname, e, "SPPPGETDNSADDRS");
186		if (dns1)
187			printf("%d.%d.%d.%d\n",
188				(addrs.dns[0] >> 24) & 0xff,
189				(addrs.dns[0] >> 16) & 0xff,
190				(addrs.dns[0] >> 8) & 0xff,
191				addrs.dns[0] & 0xff);
192		if (dns2)
193			printf("%d.%d.%d.%d\n",
194				(addrs.dns[1] >> 24) & 0xff,
195				(addrs.dns[1] >> 16) & 0xff,
196				(addrs.dns[1] >> 8) & 0xff,
197				addrs.dns[1] & 0xff);
198	}
199
200	if (dump) {
201		/* dump PPPoE session state */
202		struct pppoeconnectionstate state;
203		int e;
204
205		memset(&state, 0, sizeof state);
206		strncpy(state.ifname, ifname, sizeof state.ifname);
207		e = ioctl(s, PPPOEGETSESSION, &state);
208		if (e)
209			print_error(ifname, e, "PPPOEGETSESSION");
210
211		printf("%s:\tstate = ", ifname);
212		switch(state.state) {
213		case PPPOE_STATE_INITIAL:
214			printf("initial\n"); break;
215		case PPPOE_STATE_PADI_SENT:
216			printf("PADI sent\n"); break;
217		case PPPOE_STATE_PADR_SENT:
218			printf("PADR sent\n"); break;
219		case PPPOE_STATE_SESSION:
220			printf("session\n"); break;
221		case PPPOE_STATE_CLOSING:
222			printf("closing\n"); break;
223		}
224		printf("\tSession ID: 0x%x\n", state.session_id);
225		printf("\tPADI retries: %d\n", state.padi_retry_no);
226		printf("\tPADR retries: %d\n", state.padr_retry_no);
227
228		return 0;
229	}
230
231
232	memset(&spr, 0, sizeof spr);
233	strncpy(spr.ifname, ifname, sizeof spr.ifname);
234	memset(&lcp, 0, sizeof lcp);
235	strncpy(lcp.ifname, ifname, sizeof lcp.ifname);
236	memset(&status, 0, sizeof status);
237	strncpy(status.ifname, ifname, sizeof status.ifname);
238	memset(&timeout, 0, sizeof timeout);
239	strncpy(timeout.ifname, ifname, sizeof timeout.ifname);
240	memset(&authfailstats, 0, sizeof authfailstats);
241	strncpy(authfailstats.ifname, ifname, sizeof authfailstats.ifname);
242	memset(&authfailset, 0, sizeof authfailset);
243	strncpy(authfailset.ifname, ifname, sizeof authfailset.ifname);
244	memset(&dnssettings, 0, sizeof dnssettings);
245	strncpy(dnssettings.ifname, ifname, sizeof dnssettings.ifname);
246	memset(&keepalivesettings, 0, sizeof keepalivesettings);
247	strncpy(keepalivesettings.ifname, ifname, sizeof keepalivesettings.ifname);
248
249	mib[0] = CTL_KERN;
250	mib[1] = KERN_CLOCKRATE;
251	len = sizeof(clockinfo);
252	if(sysctl(mib, 2, &clockinfo, &len, NULL, 0) == -1)
253	{
254		fprintf(stderr, "error, cannot sysctl kern.clockrate!\n");
255		exit(1);
256	}
257
258	hz = clockinfo.hz;
259
260	if (argc == 0 && !(dns1||dns2) && !configname) {
261		/* list only mode */
262
263		/* first pass, get name lengths */
264		if (ioctl(s, SPPPGETAUTHCFG, &spr) == -1)
265			err(EX_OSERR, "SPPPGETAUTHCFG");
266		/* now allocate buffers for strings */
267		if (spr.myname_length)
268			if ((spr.myname = malloc(spr.myname_length)) == NULL)
269				err(1, NULL);
270		if (spr.hisname_length)
271			if ((spr.hisname = malloc(spr.hisname_length)) == NULL)
272				err(1, NULL);
273		/* second pass: get names too */
274		if (ioctl(s, SPPPGETAUTHCFG, &spr) == -1)
275			err(EX_OSERR, "SPPPGETAUTHCFG");
276
277		if (ioctl(s, SPPPGETLCPCFG, &lcp) == -1)
278			err(EX_OSERR, "SPPPGETLCPCFG");
279		if (ioctl(s, SPPPGETSTATUS, &status) == -1)
280			err(EX_OSERR, "SPPPGETSTATUS");
281		if (ioctl(s, SPPPGETIDLETO, &timeout) == -1)
282			err(EX_OSERR, "SPPPGETIDLETO");
283		if (ioctl(s, SPPPGETAUTHFAILURES, &authfailstats) == -1)
284			err(EX_OSERR, "SPPPGETAUTHFAILURES");
285		if (ioctl(s, SPPPGETKEEPALIVE, &keepalivesettings) == -1)
286			err(EX_OSERR, "SPPPGETKEEPALIVE");
287
288		print_vals(ifname, status.phase, &spr, lcp.lcp_timeout,
289		    timeout.idle_seconds, authfailstats.auth_failures,
290		    authfailstats.max_failures,
291		    keepalivesettings.maxalive,
292		    keepalivesettings.max_noreceive);
293
294		if (spr.hisname) free(spr.hisname);
295		if (spr.myname) free(spr.myname);
296		return 0;
297	}
298
299	/* first load the config file, then parse command line args */
300	if (configname && (fp = fopen(configname, "r")))
301		while ((line = fparseln(fp, NULL, NULL, NULL,
302		    FPARSELN_UNESCALL)) != NULL) {
303			if (line[0] != '\0')
304				pppoectl_argument(line);
305			/*
306			 * We do not free(line) here, because we
307			 * still have references to parts of the
308			 * string collected in the various ioctl
309			 * argument structures (and need those).
310			 * Yes, this is a memory leak.
311			 * We could copy the partial strings instead,
312			 * and free those later - but this is a one-shot
313			 * program and memory will be freed at process
314			 * exit time anyway.
315			 */
316		}
317
318
319	while (argc > 0) {
320		pppoectl_argument(argv[0]);
321
322		argv++;
323		argc--;
324	}
325
326	if (set_auth) {
327		if (ioctl(s, SPPPSETAUTHCFG, &spr) == -1)
328			err(EX_OSERR, "SPPPSETAUTHCFG");
329	}
330	if (set_lcp) {
331		if (ioctl(s, SPPPSETLCPCFG, &lcp) == -1)
332			err(EX_OSERR, "SPPPSETLCPCFG");
333	}
334	if (set_idle_to) {
335		if (ioctl(s, SPPPSETIDLETO, &timeout) == -1)
336			err(EX_OSERR, "SPPPSETIDLETO");
337	}
338	if (set_auth_failure) {
339		if (ioctl(s, SPPPSETAUTHFAILURE, &authfailset) == -1)
340			err(EX_OSERR, "SPPPSETAUTHFAILURE");
341	}
342	if (clear_auth_failure_count && !(set_auth || set_auth_failure)) {
343		/*
344		 * We want to clear the auth failure count, but did not
345		 * do that implicitly by setting authentication - so
346		 * do a zero-effect auth setting change
347		 */
348		if (ioctl(s, SPPPGETAUTHFAILURES, &authfailstats) == -1)
349			err(EX_OSERR, "SPPPGETAUTHFAILURES");
350		authfailset.max_failures = authfailstats.max_failures;
351		if (ioctl(s, SPPPSETAUTHFAILURE, &authfailset) == -1)
352			err(EX_OSERR, "SPPPSETAUTHFAILURE");
353	}
354	if (set_dns) {
355		if (ioctl(s, SPPPSETDNSOPTS, &dnssettings) == -1)
356			err(EX_OSERR, "SPPPSETDNSOPTS");
357	}
358	if (set_keepalive) {
359		if (ioctl(s, SPPPGETKEEPALIVE, &keepalivesettings) == -1)
360			err(EX_OSERR, "SPPPGETKEEPALIVE");
361		if (max_noreceive >= 0)
362			keepalivesettings.max_noreceive = max_noreceive;
363		if (maxalive >= 0)
364			keepalivesettings.maxalive = maxalive;
365		if (ioctl(s, SPPPSETKEEPALIVE, &keepalivesettings) == -1)
366			err(EX_OSERR, "SPPPSETKEEPALIVE");
367	}
368
369	if (verbose) {
370		if (ioctl(s, SPPPGETAUTHFAILURES, &authfailstats) == -1)
371			err(EX_OSERR, "SPPPGETAUTHFAILURES");
372		if (ioctl(s, SPPPGETKEEPALIVE, &keepalivesettings) == -1)
373			err(EX_OSERR, "SPPPGETKEEPALIVE");
374		print_vals(ifname, status.phase, &spr, lcp.lcp_timeout,
375		    timeout.idle_seconds, authfailstats.auth_failures,
376		    authfailstats.max_failures,
377		    keepalivesettings.maxalive,
378		    keepalivesettings.max_noreceive);
379	}
380
381	return 0;
382}
383
384static void
385pppoectl_argument(char *arg)
386{
387	size_t off;
388	const char *cp;
389
390#define startswith(a,s) strncmp(a, s, (off = strlen(s))) == 0
391	if (startswith(arg, "authproto=")) {
392		cp = arg + off;
393		if (strcmp(cp, "pap") == 0)
394			spr.myauth =
395				spr.hisauth = SPPP_AUTHPROTO_PAP;
396		else if (strcmp(cp, "chap") == 0)
397			spr.myauth = spr.hisauth = SPPP_AUTHPROTO_CHAP;
398		else if (strcmp(cp, "none") == 0)
399			spr.myauth = spr.hisauth = SPPP_AUTHPROTO_NONE;
400		else
401			errx(EX_DATAERR, "bad auth proto: %s", cp);
402		set_auth = 1;
403	} else if (startswith(arg, "myauthproto=")) {
404		cp = arg + off;
405		if (strcmp(cp, "pap") == 0)
406			spr.myauth = SPPP_AUTHPROTO_PAP;
407		else if (strcmp(cp, "chap") == 0)
408			spr.myauth = SPPP_AUTHPROTO_CHAP;
409		else if (strcmp(cp, "none") == 0)
410			spr.myauth = SPPP_AUTHPROTO_NONE;
411		else
412			errx(EX_DATAERR, "bad auth proto: %s", cp);
413		set_auth = 1;
414	} else if (startswith(arg, "myauthname=")) {
415		spr.myname = arg + off;
416		spr.myname_length = strlen(spr.myname)+1;
417		set_auth = 1;
418	} else if (startswith(arg, "myauthsecret=") || startswith(arg, "myauthkey=")) {
419		spr.mysecret = arg + off;
420		spr.mysecret_length = strlen(spr.mysecret)+1;
421		set_auth = 1;
422	} else if (startswith(arg, "hisauthproto=")) {
423		cp = arg + off;
424		if (strcmp(cp, "pap") == 0)
425			spr.hisauth = SPPP_AUTHPROTO_PAP;
426		else if (strcmp(cp, "chap") == 0)
427			spr.hisauth = SPPP_AUTHPROTO_CHAP;
428		else if (strcmp(cp, "none") == 0)
429			spr.hisauth = SPPP_AUTHPROTO_NONE;
430		else
431			errx(EX_DATAERR, "bad auth proto: %s", cp);
432		set_auth = 1;
433	} else if (startswith(arg, "hisauthname=")) {
434		spr.hisname = arg + off;
435		spr.hisname_length = strlen(spr.hisname)+1;
436		set_auth = 1;
437	} else if (startswith(arg, "hisauthsecret=") || startswith(arg, "hisauthkey=")) {
438		spr.hissecret = arg + off;
439		spr.hissecret_length = strlen(spr.hissecret)+1;
440		set_auth = 1;
441	} else if (startswith(arg, "max-noreceive=")) {
442		max_noreceive = atoi(arg+off);
443		if (max_noreceive < 0) {
444			fprintf(stderr,
445			    "max-noreceive value must be at least 0\n");
446			max_noreceive = -1;
447		} else {
448			set_keepalive = 1;
449		}
450	} else if (startswith(arg, "max-alive-missed=")) {
451		maxalive = atoi(arg+off);
452		if (maxalive < 0) {
453			fprintf(stderr,
454			    "max-alive-missed value must be at least 0\n");
455			maxalive = -1;
456		} else {
457			set_keepalive = 1;
458		}
459	} else if (strcmp(arg, "callin") == 0)
460		spr.hisauthflags |= SPPP_AUTHFLAG_NOCALLOUT;
461	else if (strcmp(arg, "always") == 0)
462		spr.hisauthflags &= ~SPPP_AUTHFLAG_NOCALLOUT;
463	else if (strcmp(arg, "norechallenge") == 0)
464		spr.hisauthflags |= SPPP_AUTHFLAG_NORECHALLENGE;
465	else if (strcmp(arg, "rechallenge") == 0)
466		spr.hisauthflags &= ~SPPP_AUTHFLAG_NORECHALLENGE;
467#ifndef __NetBSD__
468	else if (strcmp(arg, "enable-vj") == 0)
469		spr.defs.enable_vj = 1;
470	else if (strcmp(arg, "disable-vj") == 0)
471		spr.defs.enable_vj = 0;
472#endif
473	else if (startswith(arg, "lcp-timeout=")) {
474		int timeout_arg = atoi(arg+off);
475		if ((timeout_arg > 20000) || (timeout_arg <= 0))
476			errx(EX_DATAERR, "bad lcp timeout value: %s",
477			     arg+off);
478		lcp.lcp_timeout = timeout_arg * hz / 1000;
479		set_lcp = 1;
480	} else if (startswith(arg, "idle-timeout=")) {
481		timeout.idle_seconds = (time_t)atol(arg+off);
482		set_idle_to = 1;
483	} else if (startswith(arg, "max-auth-failure=")) {
484		authfailset.max_failures = atoi(arg+off);
485		set_auth_failure = 1;
486	} else if (strcmp(arg, "clear-auth-failure") == 0) {
487		clear_auth_failure_count = 1;
488	} else if (startswith(arg, "query-dns=")) {
489		dnssettings.query_dns = atoi(arg+off);
490		set_dns = 1;
491	} else
492		errx(EX_DATAERR, "bad parameter: \"%s\"", arg);
493}
494
495static void
496usage(void)
497{
498	const char * prog = getprogname();
499	fprintf(stderr,
500	    "usage:\n"
501	    "       %s [-f config] ifname [...]\n"
502	    "       %s [-v] ifname [{my|his}auth{proto|name|secret}=...] \\\n"
503            "                      [callin] [always] [{no}rechallenge]\n"
504            "                      [query-dns=3]\n"
505	    "           to set authentication names, passwords\n"
506	    "           and (optional) paramaters\n"
507	    "       %s [-v] ifname lcp-timeout=ms|idle-timeout=s|\n"
508	    "                      max-noreceive=s|max-alive-missed=cnt|\n"
509	    "                      max-auth-failure=count|clear-auth-failure\n"
510	    "           to set general parameters\n"
511	    "   or\n"
512	    "       %s -e ethernet-ifname ifname\n"
513	    "           to connect an ethernet interface for PPPoE\n"
514	    "       %s [-a access-concentrator-name] [-s service-name] ifname\n"
515	    "           to specify (optional) data for PPPoE sessions\n"
516	    "       %s -d ifname\n"
517	    "           to dump the current PPPoE session state\n"
518	    "       %s -n (1|2) ifname\n"
519	    "           to print DNS addresses retrieved via query-dns\n"
520	    , prog, prog, prog, prog, prog, prog, prog);
521	exit(EX_USAGE);
522}
523
524static void
525print_vals(const char *ifname, int phase, struct spppauthcfg *sp, int lcp_timeout,
526	time_t idle_timeout, int authfailures, int max_auth_failures,
527	u_int maxalive_cnt, time_t max_noreceive_time)
528{
529#ifndef __NetBSD__
530	time_t send, recv;
531#endif
532
533	printf("%s:\tphase=%s\n", ifname, phase_name(phase));
534	if (sp->myauth) {
535		printf("\tmyauthproto=%s myauthname=\"%s\"\n",
536		       proto_name(sp->myauth),
537		       sp->myname);
538	}
539	if (sp->hisauth) {
540		printf("\thisauthproto=%s hisauthname=\"%s\"%s\n",
541		       proto_name(sp->hisauth),
542		       sp->hisname,
543		       authflags(sp->hisauthflags));
544	}
545#ifndef __NetBSD__
546	if (sp->defs.pp_phase > PHASE_DEAD) {
547		send = time(NULL) - sp->defs.pp_last_sent;
548		recv = time(NULL) - sp->defs.pp_last_recv;
549		printf("\tidle_time=%ld\n", (send<recv)? send : recv);
550	}
551#endif
552
553	printf("\tlcp timeout: %.3f s\n",
554	       (double)lcp_timeout / hz);
555
556	if (idle_timeout != 0)
557		printf("\tidle timeout = %lu s\n", (unsigned long)idle_timeout);
558	else
559		printf("\tidle timeout = disabled\n");
560
561	if (authfailures != 0)
562		printf("\tauthentication failures = %d\n", authfailures);
563	printf("\tmax-auth-failure = %d\n", max_auth_failures);
564
565	printf("\tmax-noreceive = %ld seconds\n", (long)max_noreceive_time);
566	printf("\tmax-alive-missed = %u unanswered echo requests\n", maxalive_cnt);
567
568#ifndef __NetBSD__
569	printf("\tenable_vj: %s\n",
570	       sp->defs.enable_vj ? "on" : "off");
571#endif
572}
573
574static const char *
575phase_name(int phase)
576{
577	switch (phase) {
578	case SPPP_PHASE_DEAD:		return "dead";
579	case SPPP_PHASE_ESTABLISH:	return "establish";
580	case SPPP_PHASE_TERMINATE:	return "terminate";
581	case SPPP_PHASE_AUTHENTICATE:	return "authenticate";
582	case SPPP_PHASE_NETWORK:	return "network";
583	}
584	return "illegal";
585}
586
587static const char *
588proto_name(int proto)
589{
590	static char buf[12];
591	switch (proto) {
592	case SPPP_AUTHPROTO_PAP:	return "pap";
593	case SPPP_AUTHPROTO_CHAP:	return "chap";
594	case SPPP_AUTHPROTO_NONE:	return "none";
595	}
596	snprintf(buf, sizeof(buf), "0x%x", (unsigned)proto);
597	return buf;
598}
599
600static const char *
601authflags(int flags)
602{
603	static char buf[32];
604	buf[0] = '\0';
605	if (flags & SPPP_AUTHFLAG_NOCALLOUT)
606		strlcat(buf, " callin", sizeof(buf));
607	if (flags & SPPP_AUTHFLAG_NORECHALLENGE)
608		strlcat(buf, " norechallenge", sizeof(buf));
609	return buf;
610}
611
612static void
613print_error(const char *ifname, int error, const char * str)
614{
615	if (error == -1)
616		fprintf(stderr, "%s: interface not found\n", ifname);
617	else
618		fprintf(stderr, "%s: %s: %s\n", ifname, str, strerror(error));
619	exit(EX_DATAERR);
620}
621
622
623