xref: /onnv-gate/usr/src/cmd/cmd-inet/usr.sbin/sppptun/sppptun.c (revision 6631:989eb4b851bb)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*6631Sss150715  * Common Development and Distribution License (the "License").
6*6631Sss150715  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
220Sstevel@tonic-gate  * sppptun.c - Solaris STREAMS PPP multiplexing tunnel driver
230Sstevel@tonic-gate  * installer.
240Sstevel@tonic-gate  *
25*6631Sss150715  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
26*6631Sss150715  * Use is subject to license terms.
270Sstevel@tonic-gate  */
280Sstevel@tonic-gate 
290Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
300Sstevel@tonic-gate 
310Sstevel@tonic-gate #include <stdio.h>
320Sstevel@tonic-gate #include <stdlib.h>
330Sstevel@tonic-gate #include <unistd.h>
340Sstevel@tonic-gate #include <string.h>
350Sstevel@tonic-gate #include <ctype.h>
360Sstevel@tonic-gate #include <errno.h>
370Sstevel@tonic-gate #include <signal.h>
380Sstevel@tonic-gate #include <stropts.h>
390Sstevel@tonic-gate #include <fcntl.h>
400Sstevel@tonic-gate #include <locale.h>
410Sstevel@tonic-gate #include <sys/fcntl.h>
420Sstevel@tonic-gate #include <sys/stropts.h>
430Sstevel@tonic-gate #include <sys/socket.h>
440Sstevel@tonic-gate #include <net/if.h>
450Sstevel@tonic-gate #include <netinet/in.h>
460Sstevel@tonic-gate #include <netinet/if_ether.h>
470Sstevel@tonic-gate #include <net/sppptun.h>
48*6631Sss150715 #include <libdlpi.h>
490Sstevel@tonic-gate 
500Sstevel@tonic-gate static char *myname;		/* Copied from argv[0] */
510Sstevel@tonic-gate static int verbose;		/* -v on command line */
520Sstevel@tonic-gate 
530Sstevel@tonic-gate /* Data gathered during per-style attach routine. */
540Sstevel@tonic-gate struct attach_data {
55*6631Sss150715 	ppptun_lname appstr;    /* String to append to interface name (PPA) */
56*6631Sss150715 	ppptun_atype localaddr; /* Local interface address */
57*6631Sss150715 	uint_t locallen;	/* Length of local address */
580Sstevel@tonic-gate };
590Sstevel@tonic-gate 
600Sstevel@tonic-gate /* Per-protocol plumbing data */
610Sstevel@tonic-gate struct protos {
620Sstevel@tonic-gate 	const char *name;
630Sstevel@tonic-gate 	const char *desc;
64*6631Sss150715 	int (*attach)(struct protos *prot, char *linkname,
650Sstevel@tonic-gate 	    struct attach_data *adata);
66*6631Sss150715 	uint_t protval;
670Sstevel@tonic-gate 	int style;
680Sstevel@tonic-gate };
690Sstevel@tonic-gate 
700Sstevel@tonic-gate /*
710Sstevel@tonic-gate  * Print a usage string and terminate.  Used for command line argument
720Sstevel@tonic-gate  * errors.  Does not return.
730Sstevel@tonic-gate  */
740Sstevel@tonic-gate static void
750Sstevel@tonic-gate usage(void)
760Sstevel@tonic-gate {
770Sstevel@tonic-gate 	(void) fprintf(stderr, gettext(
78*6631Sss150715 	    "Usage:\n\t%s plumb [<protocol> <device>]\n"
79*6631Sss150715 	    "\t%s unplumb <interface-name>\n"
80*6631Sss150715 	    "\t%s query\n"), myname, myname, myname);
810Sstevel@tonic-gate 	exit(1);
820Sstevel@tonic-gate }
830Sstevel@tonic-gate 
840Sstevel@tonic-gate /*
85*6631Sss150715  * General DLPI function.  This is called indirectly through
86*6631Sss150715  * the protos structure for the selected lower stream protocol.
870Sstevel@tonic-gate  */
880Sstevel@tonic-gate static int
89*6631Sss150715 sppp_dlpi(struct protos *prot, char *linkname, struct attach_data *adata)
900Sstevel@tonic-gate {
91*6631Sss150715 	int retv;
92*6631Sss150715 	uint_t ppa;
93*6631Sss150715 	dlpi_handle_t dh;
940Sstevel@tonic-gate 
95*6631Sss150715 	if (verbose)
96*6631Sss150715 		(void) printf(gettext("opening DLPI link %s\n"), linkname);
97*6631Sss150715 	if ((retv = dlpi_open(linkname, &dh, 0)) != DLPI_SUCCESS) {
98*6631Sss150715 		(void) fprintf(stderr, gettext("%s: failed opening %s: %s\n"),
99*6631Sss150715 		    myname, linkname, dlpi_strerror(retv));
1000Sstevel@tonic-gate 		return (-1);
1010Sstevel@tonic-gate 	}
1020Sstevel@tonic-gate 
103*6631Sss150715 	if (verbose) {
104*6631Sss150715 		(void) printf(gettext("binding to Ethertype %04X\n"),
105*6631Sss150715 		    prot->protval);
1060Sstevel@tonic-gate 	}
107*6631Sss150715 	if ((retv = dlpi_bind(dh, prot->protval, NULL)) != DLPI_SUCCESS) {
108*6631Sss150715 		(void) fprintf(stderr, gettext("%s: failed binding on %s: %s"),
109*6631Sss150715 		    myname, linkname, dlpi_strerror(retv));
110*6631Sss150715 		dlpi_close(dh);
1110Sstevel@tonic-gate 		return (-1);
1120Sstevel@tonic-gate 	}
1130Sstevel@tonic-gate 
114*6631Sss150715 	adata->locallen = DLPI_PHYSADDR_MAX;
115*6631Sss150715 	if ((retv = dlpi_get_physaddr(dh, DL_CURR_PHYS_ADDR, &adata->localaddr,
116*6631Sss150715 	    &adata->locallen)) != DLPI_SUCCESS) {
117*6631Sss150715 		(void) fprintf(stderr, gettext("%s: failed getting physical"
118*6631Sss150715 		    " address on %s: %s"), myname, linkname,
119*6631Sss150715 		    dlpi_strerror(retv));
120*6631Sss150715 		dlpi_close(dh);
1210Sstevel@tonic-gate 		return (-1);
1220Sstevel@tonic-gate 	}
1230Sstevel@tonic-gate 
124*6631Sss150715 	/* Store ppa to append to interface name. */
125*6631Sss150715 	if ((retv = dlpi_parselink(linkname, NULL, &ppa)) != DLPI_SUCCESS) {
126*6631Sss150715 		(void) fprintf(stderr, gettext("%s: failed parsing linkname on"
127*6631Sss150715 		    " %s: %s"), myname, linkname, dlpi_strerror(retv));
128*6631Sss150715 		dlpi_close(dh);
129*6631Sss150715 		return (-1);
1300Sstevel@tonic-gate 	}
1310Sstevel@tonic-gate 
132*6631Sss150715 	(void) snprintf(adata->appstr, sizeof (adata->appstr), "%d", ppa);
1330Sstevel@tonic-gate 
134*6631Sss150715 	return (dlpi_fd(dh));
1350Sstevel@tonic-gate }
1360Sstevel@tonic-gate 
1370Sstevel@tonic-gate 
1380Sstevel@tonic-gate static struct protos proto_list[] = {
139*6631Sss150715 	{ "pppoe", "RFC 2516 PPP over Ethernet", sppp_dlpi, ETHERTYPE_PPPOES,
1400Sstevel@tonic-gate 	    PTS_PPPOE },
141*6631Sss150715 	{ "pppoed", "RFC 2516 PPP over Ethernet Discovery", sppp_dlpi,
1420Sstevel@tonic-gate 	    ETHERTYPE_PPPOED, PTS_PPPOE },
1430Sstevel@tonic-gate 	{ NULL }
1440Sstevel@tonic-gate };
1450Sstevel@tonic-gate 
1460Sstevel@tonic-gate /*
1470Sstevel@tonic-gate  * Issue a STREAMS I_STR ioctl and fetch the result.  Returns -1 on
1480Sstevel@tonic-gate  * error, or length of returned data on success.
1490Sstevel@tonic-gate  */
1500Sstevel@tonic-gate static int
1510Sstevel@tonic-gate strioctl(int fd, int cmd, void *ptr, int ilen, int olen, const char *iocname)
1520Sstevel@tonic-gate {
1530Sstevel@tonic-gate 	struct strioctl	str;
1540Sstevel@tonic-gate 
1550Sstevel@tonic-gate 	str.ic_cmd = cmd;
1560Sstevel@tonic-gate 	str.ic_timout = 0;
1570Sstevel@tonic-gate 	str.ic_len = ilen;
1580Sstevel@tonic-gate 	str.ic_dp = ptr;
1590Sstevel@tonic-gate 
1600Sstevel@tonic-gate 	if (ioctl(fd, I_STR, &str) == -1) {
1610Sstevel@tonic-gate 		perror(iocname);
1620Sstevel@tonic-gate 		return (-1);
1630Sstevel@tonic-gate 	}
1640Sstevel@tonic-gate 
1650Sstevel@tonic-gate 	if (olen >= 0) {
1660Sstevel@tonic-gate 		if (str.ic_len > olen && verbose > 1) {
1670Sstevel@tonic-gate 			(void) printf(gettext("%s:%s: extra data received; "
1680Sstevel@tonic-gate 			    "%d > %d\n"), myname, iocname, str.ic_len, olen);
1690Sstevel@tonic-gate 		} else if (str.ic_len < olen) {
1700Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("%s:%s: expected %d "
1710Sstevel@tonic-gate 			    "bytes, got %d\n"), myname, iocname, olen,
1720Sstevel@tonic-gate 			    str.ic_len);
1730Sstevel@tonic-gate 			return (-1);
1740Sstevel@tonic-gate 		}
1750Sstevel@tonic-gate 	}
1760Sstevel@tonic-gate 
1770Sstevel@tonic-gate 	return (str.ic_len);
1780Sstevel@tonic-gate }
1790Sstevel@tonic-gate 
1800Sstevel@tonic-gate /*
1810Sstevel@tonic-gate  * Handle user request to plumb a new lower stream under the sppptun
1820Sstevel@tonic-gate  * driver.
1830Sstevel@tonic-gate  */
1840Sstevel@tonic-gate static int
1850Sstevel@tonic-gate plumb_it(int argc, char **argv)
1860Sstevel@tonic-gate {
1870Sstevel@tonic-gate 	int devfd, muxfd, muxid;
1880Sstevel@tonic-gate 	struct ppptun_info pti;
189*6631Sss150715 	char *cp, *linkname;
1900Sstevel@tonic-gate 	struct protos *prot;
1910Sstevel@tonic-gate 	struct attach_data adata;
1920Sstevel@tonic-gate 
1930Sstevel@tonic-gate 	/* If no protocol requested, then list known protocols. */
1940Sstevel@tonic-gate 	if (optind == argc) {
1950Sstevel@tonic-gate 		(void) puts("Known tunneling protocols:");
1960Sstevel@tonic-gate 		for (prot = proto_list; prot->name != NULL; prot++)
1970Sstevel@tonic-gate 			(void) printf("\t%s\t%s\n", prot->name, prot->desc);
1980Sstevel@tonic-gate 		return (0);
1990Sstevel@tonic-gate 	}
2000Sstevel@tonic-gate 
2010Sstevel@tonic-gate 	/* If missing protocol or device, then abort. */
2020Sstevel@tonic-gate 	if (optind != argc-2)
2030Sstevel@tonic-gate 		usage();
2040Sstevel@tonic-gate 
2050Sstevel@tonic-gate 	/* Look up requested protocol. */
2060Sstevel@tonic-gate 	cp = argv[optind++];
2070Sstevel@tonic-gate 	for (prot = proto_list; prot->name != NULL; prot++)
2080Sstevel@tonic-gate 		if (strcasecmp(cp, prot->name) == 0)
2090Sstevel@tonic-gate 			break;
2100Sstevel@tonic-gate 	if (prot->name == NULL) {
2110Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: unknown protocol %s\n"),
2120Sstevel@tonic-gate 		    myname, cp);
2130Sstevel@tonic-gate 		return (1);
2140Sstevel@tonic-gate 	}
2150Sstevel@tonic-gate 
216*6631Sss150715 	/* Get interface. */
217*6631Sss150715 	linkname = argv[optind];
2180Sstevel@tonic-gate 	/* Call per-protocol attach routine to open device */
2190Sstevel@tonic-gate 	if (verbose)
220*6631Sss150715 		(void) printf(gettext("opening %s\n"), linkname);
221*6631Sss150715 	if ((devfd = (*prot->attach)(prot, linkname, &adata)) < 0)
2220Sstevel@tonic-gate 		return (1);
2230Sstevel@tonic-gate 
2240Sstevel@tonic-gate 	/* Open sppptun driver */
2250Sstevel@tonic-gate 	if (verbose)
2260Sstevel@tonic-gate 		(void) printf(gettext("opening /dev/%s\n"), PPP_TUN_NAME);
2270Sstevel@tonic-gate 	if ((muxfd = open("/dev/" PPP_TUN_NAME, O_RDWR)) < 0) {
2280Sstevel@tonic-gate 		perror("/dev/" PPP_TUN_NAME);
2290Sstevel@tonic-gate 		return (1);
2300Sstevel@tonic-gate 	}
2310Sstevel@tonic-gate 
2320Sstevel@tonic-gate 	/* Push sppptun module on top of lower driver. */
2330Sstevel@tonic-gate 	if (verbose)
2340Sstevel@tonic-gate 		(void) printf(gettext("pushing %s on %s\n"), PPP_TUN_NAME,
235*6631Sss150715 		    linkname);
2360Sstevel@tonic-gate 	if (ioctl(devfd, I_PUSH, PPP_TUN_NAME) == -1) {
2370Sstevel@tonic-gate 		perror("I_PUSH " PPP_TUN_NAME);
2380Sstevel@tonic-gate 		return (1);
2390Sstevel@tonic-gate 	}
2400Sstevel@tonic-gate 
2410Sstevel@tonic-gate 	/* Get the name of the newly-created lower stream. */
2420Sstevel@tonic-gate 	if (verbose)
2430Sstevel@tonic-gate 		(void) printf(gettext("getting new interface name\n"));
2440Sstevel@tonic-gate 	if (strioctl(devfd, PPPTUN_GNAME, pti.pti_name, 0,
2450Sstevel@tonic-gate 	    sizeof (pti.pti_name), "PPPTUN_GNAME") < 0)
2460Sstevel@tonic-gate 		return (1);
2470Sstevel@tonic-gate 	if (verbose)
2480Sstevel@tonic-gate 		(void) printf(gettext("got interface %s\n"), pti.pti_name);
2490Sstevel@tonic-gate 
2500Sstevel@tonic-gate 	/* Convert stream name to protocol-specific name. */
2510Sstevel@tonic-gate 	if ((cp = strchr(pti.pti_name, ':')) != NULL)
2520Sstevel@tonic-gate 		*cp = '\0';
2530Sstevel@tonic-gate 	(void) snprintf(pti.pti_name+strlen(pti.pti_name),
2540Sstevel@tonic-gate 	    sizeof (pti.pti_name)-strlen(pti.pti_name), "%s:%s", adata.appstr,
2550Sstevel@tonic-gate 	    prot->name);
2560Sstevel@tonic-gate 
2570Sstevel@tonic-gate 	/* Change the lower stream name. */
2580Sstevel@tonic-gate 	if (verbose)
2590Sstevel@tonic-gate 		(void) printf(gettext("resetting interface name to %s\n"),
2600Sstevel@tonic-gate 		    pti.pti_name);
2610Sstevel@tonic-gate 	if (strioctl(devfd, PPPTUN_SNAME, pti.pti_name,
2620Sstevel@tonic-gate 	    sizeof (pti.pti_name), 0, "PPPTUN_SNAME") < 0) {
2630Sstevel@tonic-gate 		if (errno == EEXIST)
2640Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("%s: %s already "
2650Sstevel@tonic-gate 			    "installed\n"), myname, pti.pti_name);
2660Sstevel@tonic-gate 		return (1);
2670Sstevel@tonic-gate 	}
2680Sstevel@tonic-gate 
2690Sstevel@tonic-gate 	/*
2700Sstevel@tonic-gate 	 * Send down the local interface address to the lower stream
2710Sstevel@tonic-gate 	 * so that it can originate packets.
2720Sstevel@tonic-gate 	 */
2730Sstevel@tonic-gate 	if (verbose)
2740Sstevel@tonic-gate 		(void) printf(gettext("send down local address\n"));
2750Sstevel@tonic-gate 	if (strioctl(devfd, PPPTUN_LCLADDR, &adata.localaddr, adata.locallen,
2760Sstevel@tonic-gate 	    0, "PPPTUN_LCLADDR") < 0)
2770Sstevel@tonic-gate 		return (1);
2780Sstevel@tonic-gate 
2790Sstevel@tonic-gate 	/* Link the lower stream under the tunnel device. */
2800Sstevel@tonic-gate 	if (verbose)
2810Sstevel@tonic-gate 		(void) printf(gettext("doing I_PLINK\n"));
2820Sstevel@tonic-gate 	if ((muxid = ioctl(muxfd, I_PLINK, devfd)) == -1) {
2830Sstevel@tonic-gate 		perror("I_PLINK");
2840Sstevel@tonic-gate 		return (1);
2850Sstevel@tonic-gate 	}
2860Sstevel@tonic-gate 
2870Sstevel@tonic-gate 	/*
2880Sstevel@tonic-gate 	 * Give the tunnel driver the multiplex ID of the new lower
2890Sstevel@tonic-gate 	 * stream.  This allows the unplumb function to find and
2900Sstevel@tonic-gate 	 * disconnect the lower stream.
2910Sstevel@tonic-gate 	 */
2920Sstevel@tonic-gate 	if (verbose)
2930Sstevel@tonic-gate 		(void) printf(gettext("sending muxid %d and style %d to "
2940Sstevel@tonic-gate 		    "driver\n"), muxid, prot->style);
2950Sstevel@tonic-gate 	pti.pti_muxid = muxid;
2960Sstevel@tonic-gate 	pti.pti_style = prot->style;
2970Sstevel@tonic-gate 	if (strioctl(muxfd, PPPTUN_SINFO, &pti, sizeof (pti), 0,
2980Sstevel@tonic-gate 	    "PPPTUN_SINFO") < 0)
2990Sstevel@tonic-gate 		return (1);
3000Sstevel@tonic-gate 
3010Sstevel@tonic-gate 	if (verbose)
3020Sstevel@tonic-gate 		(void) printf(gettext("done; installed %s\n"), pti.pti_name);
3030Sstevel@tonic-gate 	else
3040Sstevel@tonic-gate 		(void) puts(pti.pti_name);
3050Sstevel@tonic-gate 
3060Sstevel@tonic-gate 	return (0);
3070Sstevel@tonic-gate }
3080Sstevel@tonic-gate 
3090Sstevel@tonic-gate /*
3100Sstevel@tonic-gate  * Handle user request to unplumb an existing lower stream from the
3110Sstevel@tonic-gate  * sppptun driver.
3120Sstevel@tonic-gate  */
3130Sstevel@tonic-gate static int
3140Sstevel@tonic-gate unplumb_it(int argc, char **argv)
3150Sstevel@tonic-gate {
3160Sstevel@tonic-gate 	char *ifname;
3170Sstevel@tonic-gate 	int muxfd;
3180Sstevel@tonic-gate 	struct ppptun_info pti;
3190Sstevel@tonic-gate 
3200Sstevel@tonic-gate 	/*
3210Sstevel@tonic-gate 	 * Need to have the name of the lower stream on the command
3220Sstevel@tonic-gate 	 * line.
3230Sstevel@tonic-gate 	 */
3240Sstevel@tonic-gate 	if (optind != argc-1)
3250Sstevel@tonic-gate 		usage();
3260Sstevel@tonic-gate 
3270Sstevel@tonic-gate 	ifname = argv[optind];
3280Sstevel@tonic-gate 
3290Sstevel@tonic-gate 	/* Open the tunnel driver. */
3300Sstevel@tonic-gate 	if (verbose)
3310Sstevel@tonic-gate 		(void) printf(gettext("opening /dev/%s\n"), PPP_TUN_NAME);
3320Sstevel@tonic-gate 	if ((muxfd = open("/dev/" PPP_TUN_NAME, O_RDWR)) < 0) {
3330Sstevel@tonic-gate 		perror("/dev/" PPP_TUN_NAME);
3340Sstevel@tonic-gate 		return (1);
3350Sstevel@tonic-gate 	}
3360Sstevel@tonic-gate 
3370Sstevel@tonic-gate 	/* Get lower stream information; including multiplex ID. */
3380Sstevel@tonic-gate 	if (verbose)
3390Sstevel@tonic-gate 		(void) printf(gettext("getting info from driver\n"));
3400Sstevel@tonic-gate 	(void) strncpy(pti.pti_name, ifname, sizeof (pti.pti_name));
3410Sstevel@tonic-gate 	if (strioctl(muxfd, PPPTUN_GINFO, &pti, sizeof (pti),
3420Sstevel@tonic-gate 	    sizeof (pti), "PPPTUN_GINFO") < 0)
3430Sstevel@tonic-gate 		return (1);
3440Sstevel@tonic-gate 	if (verbose)
3450Sstevel@tonic-gate 		(void) printf(gettext("got muxid %d from driver\n"),
3460Sstevel@tonic-gate 		    pti.pti_muxid);
3470Sstevel@tonic-gate 
3480Sstevel@tonic-gate 	/* Unlink lower stream from driver. */
3490Sstevel@tonic-gate 	if (verbose)
3500Sstevel@tonic-gate 		(void) printf(gettext("doing I_PUNLINK\n"));
3510Sstevel@tonic-gate 	if (ioctl(muxfd, I_PUNLINK, pti.pti_muxid) < 0) {
3520Sstevel@tonic-gate 		perror("I_PUNLINK");
3530Sstevel@tonic-gate 		return (1);
3540Sstevel@tonic-gate 	}
3550Sstevel@tonic-gate 	if (verbose)
3560Sstevel@tonic-gate 		(void) printf(gettext("done!\n"));
3570Sstevel@tonic-gate 
3580Sstevel@tonic-gate 	return (0);
3590Sstevel@tonic-gate }
3600Sstevel@tonic-gate 
3610Sstevel@tonic-gate /*
3620Sstevel@tonic-gate  * Handle user request to list lower streams plumbed under the sppptun
3630Sstevel@tonic-gate  * driver.
3640Sstevel@tonic-gate  */
3650Sstevel@tonic-gate /*ARGSUSED*/
3660Sstevel@tonic-gate static int
3670Sstevel@tonic-gate query_interfaces(int argc, char **argv)
3680Sstevel@tonic-gate {
3690Sstevel@tonic-gate 	int muxfd, i;
3700Sstevel@tonic-gate 	union ppptun_name ptn;
3710Sstevel@tonic-gate 
3720Sstevel@tonic-gate 	/* No other arguments permitted. */
3730Sstevel@tonic-gate 	if (optind != argc)
3740Sstevel@tonic-gate 		usage();
3750Sstevel@tonic-gate 
3760Sstevel@tonic-gate 	/* Open the tunnel driver. */
3770Sstevel@tonic-gate 	if (verbose)
3780Sstevel@tonic-gate 		(void) printf(gettext("opening /dev/%s\n"), PPP_TUN_NAME);
3790Sstevel@tonic-gate 	if ((muxfd = open("/dev/" PPP_TUN_NAME, O_RDWR)) < 0) {
3800Sstevel@tonic-gate 		perror("/dev/" PPP_TUN_NAME);
3810Sstevel@tonic-gate 		return (1);
3820Sstevel@tonic-gate 	}
3830Sstevel@tonic-gate 
3840Sstevel@tonic-gate 	/* Read and print names of lower streams. */
3850Sstevel@tonic-gate 	for (i = 0; ; i++) {
3860Sstevel@tonic-gate 		ptn.ptn_index = i;
3870Sstevel@tonic-gate 		if (strioctl(muxfd, PPPTUN_GNNAME, &ptn, sizeof (ptn),
3880Sstevel@tonic-gate 		    sizeof (ptn), "PPPTUN_GNNAME") < 0) {
3890Sstevel@tonic-gate 			perror("PPPTUN_GNNAME");
3900Sstevel@tonic-gate 			break;
3910Sstevel@tonic-gate 		}
3920Sstevel@tonic-gate 		/* Stop when we index off the end of the list. */
3930Sstevel@tonic-gate 		if (ptn.ptn_name[0] == '\0')
3940Sstevel@tonic-gate 			break;
3950Sstevel@tonic-gate 		(void) puts(ptn.ptn_name);
3960Sstevel@tonic-gate 	}
3970Sstevel@tonic-gate 	return (0);
3980Sstevel@tonic-gate }
3990Sstevel@tonic-gate 
4000Sstevel@tonic-gate /*
4010Sstevel@tonic-gate  * Invoked by SIGALRM -- timer prevents problems in driver from
4020Sstevel@tonic-gate  * hanging the utility.
4030Sstevel@tonic-gate  */
4040Sstevel@tonic-gate /*ARGSUSED*/
4050Sstevel@tonic-gate static void
4060Sstevel@tonic-gate toolong(int dummy)
4070Sstevel@tonic-gate {
4080Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("%s: time-out in driver\n"), myname);
4090Sstevel@tonic-gate 	exit(1);
4100Sstevel@tonic-gate }
4110Sstevel@tonic-gate 
4120Sstevel@tonic-gate int
4130Sstevel@tonic-gate main(int argc, char **argv)
4140Sstevel@tonic-gate {
4150Sstevel@tonic-gate 	int opt, errflag = 0;
4160Sstevel@tonic-gate 	char *arg;
4170Sstevel@tonic-gate 
4180Sstevel@tonic-gate 	myname = *argv;
4190Sstevel@tonic-gate 
4200Sstevel@tonic-gate 
4210Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
4220Sstevel@tonic-gate 
4230Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)	/* Should be defined by cc -D */
4240Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"
4250Sstevel@tonic-gate #endif
4260Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
4270Sstevel@tonic-gate 
4280Sstevel@tonic-gate 	/* Parse command line flags */
4290Sstevel@tonic-gate 	while ((opt = getopt(argc, argv, "v")) != EOF)
4300Sstevel@tonic-gate 		switch (opt) {
4310Sstevel@tonic-gate 		case 'v':
4320Sstevel@tonic-gate 			verbose++;
4330Sstevel@tonic-gate 			break;
4340Sstevel@tonic-gate 		default:
4350Sstevel@tonic-gate 			errflag++;
4360Sstevel@tonic-gate 			break;
4370Sstevel@tonic-gate 		}
4380Sstevel@tonic-gate 	if (errflag != 0 || optind >= argc)
4390Sstevel@tonic-gate 		usage();
4400Sstevel@tonic-gate 
4410Sstevel@tonic-gate 	/* Set alarm to avoid stalling on any driver errors. */
4420Sstevel@tonic-gate 	(void) signal(SIGALRM, toolong);
4430Sstevel@tonic-gate 	(void) alarm(2);
4440Sstevel@tonic-gate 
4450Sstevel@tonic-gate 	/* Switch out based on user-requested function. */
4460Sstevel@tonic-gate 	arg = argv[optind++];
4470Sstevel@tonic-gate 	if (strcmp(arg, "plumb") == 0)
4480Sstevel@tonic-gate 		return (plumb_it(argc, argv));
4490Sstevel@tonic-gate 	if (strcmp(arg, "unplumb") == 0)
4500Sstevel@tonic-gate 		return (unplumb_it(argc, argv));
4510Sstevel@tonic-gate 	if (strcmp(arg, "query") == 0)
4520Sstevel@tonic-gate 		return (query_interfaces(argc, argv));
4530Sstevel@tonic-gate 
4540Sstevel@tonic-gate 	usage();
4550Sstevel@tonic-gate 	return (1);
4560Sstevel@tonic-gate }
457