17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5fb60e41dSss  * Common Development and Distribution License (the "License").
6fb60e41dSss  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
227c478bd9Sstevel@tonic-gate  * sppptun.c - Solaris STREAMS PPP multiplexing tunnel driver
237c478bd9Sstevel@tonic-gate  * installer.
247c478bd9Sstevel@tonic-gate  *
25*f53eecf5SJames Carlson  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
26fb60e41dSss  * Use is subject to license terms.
277c478bd9Sstevel@tonic-gate  */
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate #include <stdio.h>
307c478bd9Sstevel@tonic-gate #include <stdlib.h>
317c478bd9Sstevel@tonic-gate #include <unistd.h>
327c478bd9Sstevel@tonic-gate #include <string.h>
337c478bd9Sstevel@tonic-gate #include <ctype.h>
347c478bd9Sstevel@tonic-gate #include <errno.h>
357c478bd9Sstevel@tonic-gate #include <signal.h>
367c478bd9Sstevel@tonic-gate #include <stropts.h>
377c478bd9Sstevel@tonic-gate #include <fcntl.h>
387c478bd9Sstevel@tonic-gate #include <locale.h>
397c478bd9Sstevel@tonic-gate #include <sys/fcntl.h>
407c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
417c478bd9Sstevel@tonic-gate #include <sys/socket.h>
427c478bd9Sstevel@tonic-gate #include <net/if.h>
437c478bd9Sstevel@tonic-gate #include <netinet/in.h>
447c478bd9Sstevel@tonic-gate #include <netinet/if_ether.h>
457c478bd9Sstevel@tonic-gate #include <net/sppptun.h>
46fb60e41dSss #include <libdlpi.h>
477c478bd9Sstevel@tonic-gate 
487c478bd9Sstevel@tonic-gate static char *myname;		/* Copied from argv[0] */
497c478bd9Sstevel@tonic-gate static int verbose;		/* -v on command line */
507c478bd9Sstevel@tonic-gate 
517c478bd9Sstevel@tonic-gate /* Data gathered during per-style attach routine. */
527c478bd9Sstevel@tonic-gate struct attach_data {
53fb60e41dSss 	ppptun_lname appstr;    /* String to append to interface name (PPA) */
54fb60e41dSss 	ppptun_atype localaddr; /* Local interface address */
55fb60e41dSss 	uint_t locallen;	/* Length of local address */
56*f53eecf5SJames Carlson 	uint_t sap;		/* SAP for PPPoE */
577c478bd9Sstevel@tonic-gate };
587c478bd9Sstevel@tonic-gate 
597c478bd9Sstevel@tonic-gate /* Per-protocol plumbing data */
607c478bd9Sstevel@tonic-gate struct protos {
617c478bd9Sstevel@tonic-gate 	const char *name;
627c478bd9Sstevel@tonic-gate 	const char *desc;
63fb60e41dSss 	int (*attach)(struct protos *prot, char *linkname,
647c478bd9Sstevel@tonic-gate 	    struct attach_data *adata);
65fb60e41dSss 	uint_t protval;
667c478bd9Sstevel@tonic-gate 	int style;
677c478bd9Sstevel@tonic-gate };
687c478bd9Sstevel@tonic-gate 
697c478bd9Sstevel@tonic-gate /*
707c478bd9Sstevel@tonic-gate  * Print a usage string and terminate.  Used for command line argument
717c478bd9Sstevel@tonic-gate  * errors.  Does not return.
727c478bd9Sstevel@tonic-gate  */
737c478bd9Sstevel@tonic-gate static void
usage(void)747c478bd9Sstevel@tonic-gate usage(void)
757c478bd9Sstevel@tonic-gate {
767c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext(
77*f53eecf5SJames Carlson 	    "Usage:\n\t%s plumb [-s <sap>] [<protocol> <device>]\n"
78fb60e41dSss 	    "\t%s unplumb <interface-name>\n"
79fb60e41dSss 	    "\t%s query\n"), myname, myname, myname);
807c478bd9Sstevel@tonic-gate 	exit(1);
817c478bd9Sstevel@tonic-gate }
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate /*
84fb60e41dSss  * General DLPI function.  This is called indirectly through
85fb60e41dSss  * the protos structure for the selected lower stream protocol.
867c478bd9Sstevel@tonic-gate  */
87*f53eecf5SJames Carlson /* ARGSUSED */
887c478bd9Sstevel@tonic-gate static int
sppp_dlpi(struct protos * prot,char * linkname,struct attach_data * adata)89fb60e41dSss sppp_dlpi(struct protos *prot, char *linkname, struct attach_data *adata)
907c478bd9Sstevel@tonic-gate {
91fb60e41dSss 	int retv;
92fb60e41dSss 	dlpi_handle_t dh;
937c478bd9Sstevel@tonic-gate 
94fb60e41dSss 	if (verbose)
95fb60e41dSss 		(void) printf(gettext("opening DLPI link %s\n"), linkname);
96fb60e41dSss 	if ((retv = dlpi_open(linkname, &dh, 0)) != DLPI_SUCCESS) {
97fb60e41dSss 		(void) fprintf(stderr, gettext("%s: failed opening %s: %s\n"),
98fb60e41dSss 		    myname, linkname, dlpi_strerror(retv));
997c478bd9Sstevel@tonic-gate 		return (-1);
1007c478bd9Sstevel@tonic-gate 	}
1017c478bd9Sstevel@tonic-gate 
102fb60e41dSss 	if (verbose) {
103fb60e41dSss 		(void) printf(gettext("binding to Ethertype %04X\n"),
104*f53eecf5SJames Carlson 		    adata->sap);
1057c478bd9Sstevel@tonic-gate 	}
106*f53eecf5SJames Carlson 	if ((retv = dlpi_bind(dh, adata->sap, NULL)) != DLPI_SUCCESS) {
107*f53eecf5SJames Carlson 		(void) fprintf(stderr,
108*f53eecf5SJames Carlson 		    gettext("%s: failed binding on %s: %s\n"),
109fb60e41dSss 		    myname, linkname, dlpi_strerror(retv));
110fb60e41dSss 		dlpi_close(dh);
1117c478bd9Sstevel@tonic-gate 		return (-1);
1127c478bd9Sstevel@tonic-gate 	}
1137c478bd9Sstevel@tonic-gate 
114fb60e41dSss 	adata->locallen = DLPI_PHYSADDR_MAX;
115fb60e41dSss 	if ((retv = dlpi_get_physaddr(dh, DL_CURR_PHYS_ADDR, &adata->localaddr,
116fb60e41dSss 	    &adata->locallen)) != DLPI_SUCCESS) {
117fb60e41dSss 		(void) fprintf(stderr, gettext("%s: failed getting physical"
118*f53eecf5SJames Carlson 		    " address on %s: %s\n"), myname, linkname,
119fb60e41dSss 		    dlpi_strerror(retv));
120fb60e41dSss 		dlpi_close(dh);
1217c478bd9Sstevel@tonic-gate 		return (-1);
1227c478bd9Sstevel@tonic-gate 	}
1237c478bd9Sstevel@tonic-gate 
124*f53eecf5SJames Carlson 	if (strlcpy(adata->appstr, linkname, sizeof (adata->appstr)) >=
125*f53eecf5SJames Carlson 	    sizeof (adata->appstr)) {
126*f53eecf5SJames Carlson 		(void) fprintf(stderr,
127*f53eecf5SJames Carlson 		    gettext("%s: interface name too long: %s\n"),
128*f53eecf5SJames Carlson 		    myname, linkname);
129fb60e41dSss 		dlpi_close(dh);
1307c478bd9Sstevel@tonic-gate 		return (-1);
1317c478bd9Sstevel@tonic-gate 	}
1327c478bd9Sstevel@tonic-gate 
133fb60e41dSss 	return (dlpi_fd(dh));
1347c478bd9Sstevel@tonic-gate }
1357c478bd9Sstevel@tonic-gate 
1367c478bd9Sstevel@tonic-gate 
1377c478bd9Sstevel@tonic-gate static struct protos proto_list[] = {
138fb60e41dSss 	{ "pppoe", "RFC 2516 PPP over Ethernet", sppp_dlpi, ETHERTYPE_PPPOES,
1397c478bd9Sstevel@tonic-gate 	    PTS_PPPOE },
140fb60e41dSss 	{ "pppoed", "RFC 2516 PPP over Ethernet Discovery", sppp_dlpi,
1417c478bd9Sstevel@tonic-gate 	    ETHERTYPE_PPPOED, PTS_PPPOE },
1427c478bd9Sstevel@tonic-gate 	{ NULL }
1437c478bd9Sstevel@tonic-gate };
1447c478bd9Sstevel@tonic-gate 
1457c478bd9Sstevel@tonic-gate /*
1467c478bd9Sstevel@tonic-gate  * Issue a STREAMS I_STR ioctl and fetch the result.  Returns -1 on
1477c478bd9Sstevel@tonic-gate  * error, or length of returned data on success.
1487c478bd9Sstevel@tonic-gate  */
1497c478bd9Sstevel@tonic-gate static int
strioctl(int fd,int cmd,void * ptr,int ilen,int olen,const char * iocname)1507c478bd9Sstevel@tonic-gate strioctl(int fd, int cmd, void *ptr, int ilen, int olen, const char *iocname)
1517c478bd9Sstevel@tonic-gate {
1527c478bd9Sstevel@tonic-gate 	struct strioctl	str;
1537c478bd9Sstevel@tonic-gate 
1547c478bd9Sstevel@tonic-gate 	str.ic_cmd = cmd;
1557c478bd9Sstevel@tonic-gate 	str.ic_timout = 0;
1567c478bd9Sstevel@tonic-gate 	str.ic_len = ilen;
1577c478bd9Sstevel@tonic-gate 	str.ic_dp = ptr;
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate 	if (ioctl(fd, I_STR, &str) == -1) {
1607c478bd9Sstevel@tonic-gate 		perror(iocname);
1617c478bd9Sstevel@tonic-gate 		return (-1);
1627c478bd9Sstevel@tonic-gate 	}
1637c478bd9Sstevel@tonic-gate 
1647c478bd9Sstevel@tonic-gate 	if (olen >= 0) {
1657c478bd9Sstevel@tonic-gate 		if (str.ic_len > olen && verbose > 1) {
1667c478bd9Sstevel@tonic-gate 			(void) printf(gettext("%s:%s: extra data received; "
1677c478bd9Sstevel@tonic-gate 			    "%d > %d\n"), myname, iocname, str.ic_len, olen);
1687c478bd9Sstevel@tonic-gate 		} else if (str.ic_len < olen) {
1697c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("%s:%s: expected %d "
1707c478bd9Sstevel@tonic-gate 			    "bytes, got %d\n"), myname, iocname, olen,
1717c478bd9Sstevel@tonic-gate 			    str.ic_len);
1727c478bd9Sstevel@tonic-gate 			return (-1);
1737c478bd9Sstevel@tonic-gate 		}
1747c478bd9Sstevel@tonic-gate 	}
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate 	return (str.ic_len);
1777c478bd9Sstevel@tonic-gate }
1787c478bd9Sstevel@tonic-gate 
1797c478bd9Sstevel@tonic-gate /*
1807c478bd9Sstevel@tonic-gate  * Handle user request to plumb a new lower stream under the sppptun
1817c478bd9Sstevel@tonic-gate  * driver.
1827c478bd9Sstevel@tonic-gate  */
1837c478bd9Sstevel@tonic-gate static int
plumb_it(int argc,char ** argv)1847c478bd9Sstevel@tonic-gate plumb_it(int argc, char **argv)
1857c478bd9Sstevel@tonic-gate {
186*f53eecf5SJames Carlson 	int opt, devfd, muxfd, muxid;
1877c478bd9Sstevel@tonic-gate 	struct ppptun_info pti;
188fb60e41dSss 	char *cp, *linkname;
1897c478bd9Sstevel@tonic-gate 	struct protos *prot;
1907c478bd9Sstevel@tonic-gate 	struct attach_data adata;
191*f53eecf5SJames Carlson 	uint_t sap = 0;
1927c478bd9Sstevel@tonic-gate 
1937c478bd9Sstevel@tonic-gate 	/* If no protocol requested, then list known protocols. */
1947c478bd9Sstevel@tonic-gate 	if (optind == argc) {
1957c478bd9Sstevel@tonic-gate 		(void) puts("Known tunneling protocols:");
1967c478bd9Sstevel@tonic-gate 		for (prot = proto_list; prot->name != NULL; prot++)
1977c478bd9Sstevel@tonic-gate 			(void) printf("\t%s\t%s\n", prot->name, prot->desc);
1987c478bd9Sstevel@tonic-gate 		return (0);
1997c478bd9Sstevel@tonic-gate 	}
2007c478bd9Sstevel@tonic-gate 
201*f53eecf5SJames Carlson 	/* Parse plumbing flags */
202*f53eecf5SJames Carlson 	while ((opt = getopt(argc, argv, "s:")) != EOF) {
203*f53eecf5SJames Carlson 		switch (opt) {
204*f53eecf5SJames Carlson 		case 's':
205*f53eecf5SJames Carlson 			sap = strtoul(optarg, NULL, 16);
206*f53eecf5SJames Carlson 			break;
207*f53eecf5SJames Carlson 		default:
208*f53eecf5SJames Carlson 			usage();
209*f53eecf5SJames Carlson 		}
210*f53eecf5SJames Carlson 	}
211*f53eecf5SJames Carlson 
2127c478bd9Sstevel@tonic-gate 	/* If missing protocol or device, then abort. */
2137c478bd9Sstevel@tonic-gate 	if (optind != argc-2)
2147c478bd9Sstevel@tonic-gate 		usage();
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate 	/* Look up requested protocol. */
2177c478bd9Sstevel@tonic-gate 	cp = argv[optind++];
2187c478bd9Sstevel@tonic-gate 	for (prot = proto_list; prot->name != NULL; prot++)
2197c478bd9Sstevel@tonic-gate 		if (strcasecmp(cp, prot->name) == 0)
2207c478bd9Sstevel@tonic-gate 			break;
2217c478bd9Sstevel@tonic-gate 	if (prot->name == NULL) {
2227c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: unknown protocol %s\n"),
2237c478bd9Sstevel@tonic-gate 		    myname, cp);
2247c478bd9Sstevel@tonic-gate 		return (1);
2257c478bd9Sstevel@tonic-gate 	}
2267c478bd9Sstevel@tonic-gate 
227*f53eecf5SJames Carlson 	adata.sap = sap == 0 ? prot->protval : sap;
228*f53eecf5SJames Carlson 
229fb60e41dSss 	/* Get interface. */
230fb60e41dSss 	linkname = argv[optind];
2317c478bd9Sstevel@tonic-gate 	/* Call per-protocol attach routine to open device */
2327c478bd9Sstevel@tonic-gate 	if (verbose)
233fb60e41dSss 		(void) printf(gettext("opening %s\n"), linkname);
234fb60e41dSss 	if ((devfd = (*prot->attach)(prot, linkname, &adata)) < 0)
2357c478bd9Sstevel@tonic-gate 		return (1);
2367c478bd9Sstevel@tonic-gate 
2377c478bd9Sstevel@tonic-gate 	/* Open sppptun driver */
2387c478bd9Sstevel@tonic-gate 	if (verbose)
2397c478bd9Sstevel@tonic-gate 		(void) printf(gettext("opening /dev/%s\n"), PPP_TUN_NAME);
2407c478bd9Sstevel@tonic-gate 	if ((muxfd = open("/dev/" PPP_TUN_NAME, O_RDWR)) < 0) {
2417c478bd9Sstevel@tonic-gate 		perror("/dev/" PPP_TUN_NAME);
2427c478bd9Sstevel@tonic-gate 		return (1);
2437c478bd9Sstevel@tonic-gate 	}
2447c478bd9Sstevel@tonic-gate 
2457c478bd9Sstevel@tonic-gate 	/* Push sppptun module on top of lower driver. */
2467c478bd9Sstevel@tonic-gate 	if (verbose)
2477c478bd9Sstevel@tonic-gate 		(void) printf(gettext("pushing %s on %s\n"), PPP_TUN_NAME,
248fb60e41dSss 		    linkname);
2497c478bd9Sstevel@tonic-gate 	if (ioctl(devfd, I_PUSH, PPP_TUN_NAME) == -1) {
2507c478bd9Sstevel@tonic-gate 		perror("I_PUSH " PPP_TUN_NAME);
2517c478bd9Sstevel@tonic-gate 		return (1);
2527c478bd9Sstevel@tonic-gate 	}
2537c478bd9Sstevel@tonic-gate 
2547c478bd9Sstevel@tonic-gate 	/* Convert stream name to protocol-specific name. */
255*f53eecf5SJames Carlson 	if (snprintf(pti.pti_name, sizeof (pti.pti_name), "%s:%s",
256*f53eecf5SJames Carlson 	    adata.appstr, prot->name) >= sizeof (pti.pti_name)) {
257*f53eecf5SJames Carlson 		(void) fprintf(stderr,
258*f53eecf5SJames Carlson 		    gettext("%s: stream name too long: %s:%s\n"),
259*f53eecf5SJames Carlson 		    myname, adata.appstr, prot->name);
260*f53eecf5SJames Carlson 		return (1);
261*f53eecf5SJames Carlson 	}
2627c478bd9Sstevel@tonic-gate 
2637c478bd9Sstevel@tonic-gate 	/* Change the lower stream name. */
2647c478bd9Sstevel@tonic-gate 	if (verbose)
2657c478bd9Sstevel@tonic-gate 		(void) printf(gettext("resetting interface name to %s\n"),
2667c478bd9Sstevel@tonic-gate 		    pti.pti_name);
2677c478bd9Sstevel@tonic-gate 	if (strioctl(devfd, PPPTUN_SNAME, pti.pti_name,
2687c478bd9Sstevel@tonic-gate 	    sizeof (pti.pti_name), 0, "PPPTUN_SNAME") < 0) {
2697c478bd9Sstevel@tonic-gate 		if (errno == EEXIST)
2707c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("%s: %s already "
2717c478bd9Sstevel@tonic-gate 			    "installed\n"), myname, pti.pti_name);
2727c478bd9Sstevel@tonic-gate 		return (1);
2737c478bd9Sstevel@tonic-gate 	}
2747c478bd9Sstevel@tonic-gate 
2757c478bd9Sstevel@tonic-gate 	/*
2767c478bd9Sstevel@tonic-gate 	 * Send down the local interface address to the lower stream
2777c478bd9Sstevel@tonic-gate 	 * so that it can originate packets.
2787c478bd9Sstevel@tonic-gate 	 */
2797c478bd9Sstevel@tonic-gate 	if (verbose)
2807c478bd9Sstevel@tonic-gate 		(void) printf(gettext("send down local address\n"));
2817c478bd9Sstevel@tonic-gate 	if (strioctl(devfd, PPPTUN_LCLADDR, &adata.localaddr, adata.locallen,
2827c478bd9Sstevel@tonic-gate 	    0, "PPPTUN_LCLADDR") < 0)
2837c478bd9Sstevel@tonic-gate 		return (1);
2847c478bd9Sstevel@tonic-gate 
285*f53eecf5SJames Carlson 	/*
286*f53eecf5SJames Carlson 	 * And set the SAP value.
287*f53eecf5SJames Carlson 	 */
288*f53eecf5SJames Carlson 	if (verbose)
289*f53eecf5SJames Carlson 		(void) printf(gettext("send down SAP %x\n"), adata.sap);
290*f53eecf5SJames Carlson 	if (strioctl(devfd, PPPTUN_SSAP, &adata.sap, sizeof (adata.sap), 0,
291*f53eecf5SJames Carlson 	    "PPPTUN_SSAP") < 0)
292*f53eecf5SJames Carlson 		return (1);
293*f53eecf5SJames Carlson 
2947c478bd9Sstevel@tonic-gate 	/* Link the lower stream under the tunnel device. */
2957c478bd9Sstevel@tonic-gate 	if (verbose)
2967c478bd9Sstevel@tonic-gate 		(void) printf(gettext("doing I_PLINK\n"));
2977c478bd9Sstevel@tonic-gate 	if ((muxid = ioctl(muxfd, I_PLINK, devfd)) == -1) {
2987c478bd9Sstevel@tonic-gate 		perror("I_PLINK");
2997c478bd9Sstevel@tonic-gate 		return (1);
3007c478bd9Sstevel@tonic-gate 	}
3017c478bd9Sstevel@tonic-gate 
3027c478bd9Sstevel@tonic-gate 	/*
3037c478bd9Sstevel@tonic-gate 	 * Give the tunnel driver the multiplex ID of the new lower
3047c478bd9Sstevel@tonic-gate 	 * stream.  This allows the unplumb function to find and
3057c478bd9Sstevel@tonic-gate 	 * disconnect the lower stream.
3067c478bd9Sstevel@tonic-gate 	 */
3077c478bd9Sstevel@tonic-gate 	if (verbose)
3087c478bd9Sstevel@tonic-gate 		(void) printf(gettext("sending muxid %d and style %d to "
3097c478bd9Sstevel@tonic-gate 		    "driver\n"), muxid, prot->style);
3107c478bd9Sstevel@tonic-gate 	pti.pti_muxid = muxid;
3117c478bd9Sstevel@tonic-gate 	pti.pti_style = prot->style;
3127c478bd9Sstevel@tonic-gate 	if (strioctl(muxfd, PPPTUN_SINFO, &pti, sizeof (pti), 0,
3137c478bd9Sstevel@tonic-gate 	    "PPPTUN_SINFO") < 0)
3147c478bd9Sstevel@tonic-gate 		return (1);
3157c478bd9Sstevel@tonic-gate 
3167c478bd9Sstevel@tonic-gate 	if (verbose)
3177c478bd9Sstevel@tonic-gate 		(void) printf(gettext("done; installed %s\n"), pti.pti_name);
3187c478bd9Sstevel@tonic-gate 	else
3197c478bd9Sstevel@tonic-gate 		(void) puts(pti.pti_name);
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate 	return (0);
3227c478bd9Sstevel@tonic-gate }
3237c478bd9Sstevel@tonic-gate 
3247c478bd9Sstevel@tonic-gate /*
3257c478bd9Sstevel@tonic-gate  * Handle user request to unplumb an existing lower stream from the
3267c478bd9Sstevel@tonic-gate  * sppptun driver.
3277c478bd9Sstevel@tonic-gate  */
3287c478bd9Sstevel@tonic-gate static int
unplumb_it(int argc,char ** argv)3297c478bd9Sstevel@tonic-gate unplumb_it(int argc, char **argv)
3307c478bd9Sstevel@tonic-gate {
3317c478bd9Sstevel@tonic-gate 	char *ifname;
3327c478bd9Sstevel@tonic-gate 	int muxfd;
3337c478bd9Sstevel@tonic-gate 	struct ppptun_info pti;
3347c478bd9Sstevel@tonic-gate 
3357c478bd9Sstevel@tonic-gate 	/*
3367c478bd9Sstevel@tonic-gate 	 * Need to have the name of the lower stream on the command
3377c478bd9Sstevel@tonic-gate 	 * line.
3387c478bd9Sstevel@tonic-gate 	 */
3397c478bd9Sstevel@tonic-gate 	if (optind != argc-1)
3407c478bd9Sstevel@tonic-gate 		usage();
3417c478bd9Sstevel@tonic-gate 
3427c478bd9Sstevel@tonic-gate 	ifname = argv[optind];
3437c478bd9Sstevel@tonic-gate 
3447c478bd9Sstevel@tonic-gate 	/* Open the tunnel driver. */
3457c478bd9Sstevel@tonic-gate 	if (verbose)
3467c478bd9Sstevel@tonic-gate 		(void) printf(gettext("opening /dev/%s\n"), PPP_TUN_NAME);
3477c478bd9Sstevel@tonic-gate 	if ((muxfd = open("/dev/" PPP_TUN_NAME, O_RDWR)) < 0) {
3487c478bd9Sstevel@tonic-gate 		perror("/dev/" PPP_TUN_NAME);
3497c478bd9Sstevel@tonic-gate 		return (1);
3507c478bd9Sstevel@tonic-gate 	}
3517c478bd9Sstevel@tonic-gate 
3527c478bd9Sstevel@tonic-gate 	/* Get lower stream information; including multiplex ID. */
3537c478bd9Sstevel@tonic-gate 	if (verbose)
3547c478bd9Sstevel@tonic-gate 		(void) printf(gettext("getting info from driver\n"));
3557c478bd9Sstevel@tonic-gate 	(void) strncpy(pti.pti_name, ifname, sizeof (pti.pti_name));
3567c478bd9Sstevel@tonic-gate 	if (strioctl(muxfd, PPPTUN_GINFO, &pti, sizeof (pti),
3577c478bd9Sstevel@tonic-gate 	    sizeof (pti), "PPPTUN_GINFO") < 0)
3587c478bd9Sstevel@tonic-gate 		return (1);
3597c478bd9Sstevel@tonic-gate 	if (verbose)
3607c478bd9Sstevel@tonic-gate 		(void) printf(gettext("got muxid %d from driver\n"),
3617c478bd9Sstevel@tonic-gate 		    pti.pti_muxid);
3627c478bd9Sstevel@tonic-gate 
3637c478bd9Sstevel@tonic-gate 	/* Unlink lower stream from driver. */
3647c478bd9Sstevel@tonic-gate 	if (verbose)
3657c478bd9Sstevel@tonic-gate 		(void) printf(gettext("doing I_PUNLINK\n"));
3667c478bd9Sstevel@tonic-gate 	if (ioctl(muxfd, I_PUNLINK, pti.pti_muxid) < 0) {
3677c478bd9Sstevel@tonic-gate 		perror("I_PUNLINK");
3687c478bd9Sstevel@tonic-gate 		return (1);
3697c478bd9Sstevel@tonic-gate 	}
3707c478bd9Sstevel@tonic-gate 	if (verbose)
3717c478bd9Sstevel@tonic-gate 		(void) printf(gettext("done!\n"));
3727c478bd9Sstevel@tonic-gate 
3737c478bd9Sstevel@tonic-gate 	return (0);
3747c478bd9Sstevel@tonic-gate }
3757c478bd9Sstevel@tonic-gate 
3767c478bd9Sstevel@tonic-gate /*
3777c478bd9Sstevel@tonic-gate  * Handle user request to list lower streams plumbed under the sppptun
3787c478bd9Sstevel@tonic-gate  * driver.
3797c478bd9Sstevel@tonic-gate  */
3807c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3817c478bd9Sstevel@tonic-gate static int
query_interfaces(int argc,char ** argv)3827c478bd9Sstevel@tonic-gate query_interfaces(int argc, char **argv)
3837c478bd9Sstevel@tonic-gate {
3847c478bd9Sstevel@tonic-gate 	int muxfd, i;
3857c478bd9Sstevel@tonic-gate 	union ppptun_name ptn;
3867c478bd9Sstevel@tonic-gate 
3877c478bd9Sstevel@tonic-gate 	/* No other arguments permitted. */
3887c478bd9Sstevel@tonic-gate 	if (optind != argc)
3897c478bd9Sstevel@tonic-gate 		usage();
3907c478bd9Sstevel@tonic-gate 
3917c478bd9Sstevel@tonic-gate 	/* Open the tunnel driver. */
3927c478bd9Sstevel@tonic-gate 	if (verbose)
3937c478bd9Sstevel@tonic-gate 		(void) printf(gettext("opening /dev/%s\n"), PPP_TUN_NAME);
3947c478bd9Sstevel@tonic-gate 	if ((muxfd = open("/dev/" PPP_TUN_NAME, O_RDWR)) < 0) {
3957c478bd9Sstevel@tonic-gate 		perror("/dev/" PPP_TUN_NAME);
3967c478bd9Sstevel@tonic-gate 		return (1);
3977c478bd9Sstevel@tonic-gate 	}
3987c478bd9Sstevel@tonic-gate 
3997c478bd9Sstevel@tonic-gate 	/* Read and print names of lower streams. */
4007c478bd9Sstevel@tonic-gate 	for (i = 0; ; i++) {
4017c478bd9Sstevel@tonic-gate 		ptn.ptn_index = i;
4027c478bd9Sstevel@tonic-gate 		if (strioctl(muxfd, PPPTUN_GNNAME, &ptn, sizeof (ptn),
4037c478bd9Sstevel@tonic-gate 		    sizeof (ptn), "PPPTUN_GNNAME") < 0) {
4047c478bd9Sstevel@tonic-gate 			perror("PPPTUN_GNNAME");
4057c478bd9Sstevel@tonic-gate 			break;
4067c478bd9Sstevel@tonic-gate 		}
4077c478bd9Sstevel@tonic-gate 		/* Stop when we index off the end of the list. */
4087c478bd9Sstevel@tonic-gate 		if (ptn.ptn_name[0] == '\0')
4097c478bd9Sstevel@tonic-gate 			break;
4107c478bd9Sstevel@tonic-gate 		(void) puts(ptn.ptn_name);
4117c478bd9Sstevel@tonic-gate 	}
4127c478bd9Sstevel@tonic-gate 	return (0);
4137c478bd9Sstevel@tonic-gate }
4147c478bd9Sstevel@tonic-gate 
4157c478bd9Sstevel@tonic-gate /*
4167c478bd9Sstevel@tonic-gate  * Invoked by SIGALRM -- timer prevents problems in driver from
4177c478bd9Sstevel@tonic-gate  * hanging the utility.
4187c478bd9Sstevel@tonic-gate  */
4197c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4207c478bd9Sstevel@tonic-gate static void
toolong(int dummy)4217c478bd9Sstevel@tonic-gate toolong(int dummy)
4227c478bd9Sstevel@tonic-gate {
4237c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("%s: time-out in driver\n"), myname);
4247c478bd9Sstevel@tonic-gate 	exit(1);
4257c478bd9Sstevel@tonic-gate }
4267c478bd9Sstevel@tonic-gate 
4277c478bd9Sstevel@tonic-gate int
main(int argc,char ** argv)4287c478bd9Sstevel@tonic-gate main(int argc, char **argv)
4297c478bd9Sstevel@tonic-gate {
4307c478bd9Sstevel@tonic-gate 	int opt, errflag = 0;
4317c478bd9Sstevel@tonic-gate 	char *arg;
4327c478bd9Sstevel@tonic-gate 
4337c478bd9Sstevel@tonic-gate 	myname = *argv;
4347c478bd9Sstevel@tonic-gate 
4357c478bd9Sstevel@tonic-gate 
4367c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
4377c478bd9Sstevel@tonic-gate 
4387c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)	/* Should be defined by cc -D */
4397c478bd9Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"
4407c478bd9Sstevel@tonic-gate #endif
4417c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
4427c478bd9Sstevel@tonic-gate 
4437c478bd9Sstevel@tonic-gate 	/* Parse command line flags */
4447c478bd9Sstevel@tonic-gate 	while ((opt = getopt(argc, argv, "v")) != EOF)
4457c478bd9Sstevel@tonic-gate 		switch (opt) {
4467c478bd9Sstevel@tonic-gate 		case 'v':
4477c478bd9Sstevel@tonic-gate 			verbose++;
4487c478bd9Sstevel@tonic-gate 			break;
4497c478bd9Sstevel@tonic-gate 		default:
4507c478bd9Sstevel@tonic-gate 			errflag++;
4517c478bd9Sstevel@tonic-gate 			break;
4527c478bd9Sstevel@tonic-gate 		}
4537c478bd9Sstevel@tonic-gate 	if (errflag != 0 || optind >= argc)
4547c478bd9Sstevel@tonic-gate 		usage();
4557c478bd9Sstevel@tonic-gate 
4567c478bd9Sstevel@tonic-gate 	/* Set alarm to avoid stalling on any driver errors. */
4577c478bd9Sstevel@tonic-gate 	(void) signal(SIGALRM, toolong);
4587c478bd9Sstevel@tonic-gate 	(void) alarm(2);
4597c478bd9Sstevel@tonic-gate 
4607c478bd9Sstevel@tonic-gate 	/* Switch out based on user-requested function. */
4617c478bd9Sstevel@tonic-gate 	arg = argv[optind++];
4627c478bd9Sstevel@tonic-gate 	if (strcmp(arg, "plumb") == 0)
4637c478bd9Sstevel@tonic-gate 		return (plumb_it(argc, argv));
4647c478bd9Sstevel@tonic-gate 	if (strcmp(arg, "unplumb") == 0)
4657c478bd9Sstevel@tonic-gate 		return (unplumb_it(argc, argv));
4667c478bd9Sstevel@tonic-gate 	if (strcmp(arg, "query") == 0)
4677c478bd9Sstevel@tonic-gate 		return (query_interfaces(argc, argv));
4687c478bd9Sstevel@tonic-gate 
4697c478bd9Sstevel@tonic-gate 	usage();
4707c478bd9Sstevel@tonic-gate 	return (1);
4717c478bd9Sstevel@tonic-gate }
472