xref: /onnv-gate/usr/src/cmd/cmd-inet/usr.sbin/sppptun/sppptun.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * sppptun.c - Solaris STREAMS PPP multiplexing tunnel driver
24*0Sstevel@tonic-gate  * installer.
25*0Sstevel@tonic-gate  *
26*0Sstevel@tonic-gate  * Copyright (c) 2000-2001 by Sun Microsystems, Inc.
27*0Sstevel@tonic-gate  * All rights reserved.
28*0Sstevel@tonic-gate  */
29*0Sstevel@tonic-gate 
30*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
31*0Sstevel@tonic-gate 
32*0Sstevel@tonic-gate #include <stdio.h>
33*0Sstevel@tonic-gate #include <stdlib.h>
34*0Sstevel@tonic-gate #include <unistd.h>
35*0Sstevel@tonic-gate #include <string.h>
36*0Sstevel@tonic-gate #include <ctype.h>
37*0Sstevel@tonic-gate #include <errno.h>
38*0Sstevel@tonic-gate #include <signal.h>
39*0Sstevel@tonic-gate #include <alloca.h>
40*0Sstevel@tonic-gate #include <stropts.h>
41*0Sstevel@tonic-gate #include <fcntl.h>
42*0Sstevel@tonic-gate #include <locale.h>
43*0Sstevel@tonic-gate #include <sys/dlpi.h>
44*0Sstevel@tonic-gate #include <sys/fcntl.h>
45*0Sstevel@tonic-gate #include <sys/stropts.h>
46*0Sstevel@tonic-gate #include <sys/socket.h>
47*0Sstevel@tonic-gate #include <net/if.h>
48*0Sstevel@tonic-gate #include <netinet/in.h>
49*0Sstevel@tonic-gate #include <netinet/if_ether.h>
50*0Sstevel@tonic-gate #include <net/sppptun.h>
51*0Sstevel@tonic-gate 
52*0Sstevel@tonic-gate static char *myname;		/* Copied from argv[0] */
53*0Sstevel@tonic-gate static int verbose;		/* -v on command line */
54*0Sstevel@tonic-gate 
55*0Sstevel@tonic-gate /* Data gathered during per-style attach routine. */
56*0Sstevel@tonic-gate struct attach_data {
57*0Sstevel@tonic-gate 	ppptun_lname appstr;	/* String to append to interface name (PPA) */
58*0Sstevel@tonic-gate 	ppptun_atype localaddr;	/* Local interface address */
59*0Sstevel@tonic-gate 	int locallen;		/* Length of local address */
60*0Sstevel@tonic-gate };
61*0Sstevel@tonic-gate 
62*0Sstevel@tonic-gate /* Per-protocol plumbing data */
63*0Sstevel@tonic-gate struct protos {
64*0Sstevel@tonic-gate 	const char *name;
65*0Sstevel@tonic-gate 	const char *desc;
66*0Sstevel@tonic-gate 	int (*attach)(struct protos *prot, char *ifname,
67*0Sstevel@tonic-gate 	    struct attach_data *adata);
68*0Sstevel@tonic-gate 	int protval;
69*0Sstevel@tonic-gate 	int style;
70*0Sstevel@tonic-gate };
71*0Sstevel@tonic-gate 
72*0Sstevel@tonic-gate /*
73*0Sstevel@tonic-gate  * Print a usage string and terminate.  Used for command line argument
74*0Sstevel@tonic-gate  * errors.  Does not return.
75*0Sstevel@tonic-gate  */
76*0Sstevel@tonic-gate static void
77*0Sstevel@tonic-gate usage(void)
78*0Sstevel@tonic-gate {
79*0Sstevel@tonic-gate 	(void) fprintf(stderr, gettext(
80*0Sstevel@tonic-gate 		"Usage:\n\t%s plumb [<protocol> <device>]\n"
81*0Sstevel@tonic-gate 		"\t%s unplumb <interface-name>\n"
82*0Sstevel@tonic-gate 		"\t%s query\n"), myname, myname, myname);
83*0Sstevel@tonic-gate 	exit(1);
84*0Sstevel@tonic-gate }
85*0Sstevel@tonic-gate 
86*0Sstevel@tonic-gate /*
87*0Sstevel@tonic-gate  * Await a DLPI response to a previous driver command.  "etype" is set
88*0Sstevel@tonic-gate  * to the expected response primitive.  "rptr" and "rlen" may point to
89*0Sstevel@tonic-gate  * a buffer to hold returned data, if desired.  Otherwise, "rptr" is
90*0Sstevel@tonic-gate  * NULL.  Returns -1 on error, 0 on success.
91*0Sstevel@tonic-gate  *
92*0Sstevel@tonic-gate  * If "rlen" is a positive number, then it indicates the number of
93*0Sstevel@tonic-gate  * bytes expected in return, and any longer response is truncated to
94*0Sstevel@tonic-gate  * that value, and any shorter response generates a warning message.
95*0Sstevel@tonic-gate  * If it's a negative number, then it indicates the maximum number of
96*0Sstevel@tonic-gate  * bytes expected, and no warning is printed if fewer are received.
97*0Sstevel@tonic-gate  */
98*0Sstevel@tonic-gate static int
99*0Sstevel@tonic-gate dlpi_reply(int fd, int etype, void *rptr, int rlen)
100*0Sstevel@tonic-gate {
101*0Sstevel@tonic-gate 	/* Align 'buf' on natural boundary for aggregates. */
102*0Sstevel@tonic-gate 	uintptr_t buf[BUFSIZ/sizeof (uintptr_t)];
103*0Sstevel@tonic-gate 	int flags;
104*0Sstevel@tonic-gate 	union DL_primitives *dlp = (union DL_primitives *)buf;
105*0Sstevel@tonic-gate 	struct strbuf  ctl;
106*0Sstevel@tonic-gate 
107*0Sstevel@tonic-gate 	/* read reply */
108*0Sstevel@tonic-gate 	ctl.buf = (caddr_t)dlp;
109*0Sstevel@tonic-gate 	ctl.len = 0;
110*0Sstevel@tonic-gate 	ctl.maxlen = BUFSIZ;
111*0Sstevel@tonic-gate 	flags = 0;
112*0Sstevel@tonic-gate 	if (getmsg(fd, &ctl, NULL, &flags) < 0) {
113*0Sstevel@tonic-gate 		perror("getmsg");
114*0Sstevel@tonic-gate 		return (-1);
115*0Sstevel@tonic-gate 	}
116*0Sstevel@tonic-gate 
117*0Sstevel@tonic-gate 	/* Validate reply.  */
118*0Sstevel@tonic-gate 	if (ctl.len < sizeof (t_uscalar_t)) {
119*0Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: request: short reply\n"),
120*0Sstevel@tonic-gate 		    myname);
121*0Sstevel@tonic-gate 		return (-1);
122*0Sstevel@tonic-gate 	}
123*0Sstevel@tonic-gate 
124*0Sstevel@tonic-gate 	if (dlp->dl_primitive == DL_ERROR_ACK) {
125*0Sstevel@tonic-gate 		(void) fprintf(stderr,
126*0Sstevel@tonic-gate 		    gettext("%s: request:  dl_errno %lu errno %lu\n"), myname,
127*0Sstevel@tonic-gate 		    dlp->error_ack.dl_errno, dlp->error_ack.dl_unix_errno);
128*0Sstevel@tonic-gate 		return (-1);
129*0Sstevel@tonic-gate 	}
130*0Sstevel@tonic-gate 	if (dlp->dl_primitive != etype) {
131*0Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: request: unexpected "
132*0Sstevel@tonic-gate 		    "dl_primitive %lu received\n"), myname, dlp->dl_primitive);
133*0Sstevel@tonic-gate 		return (-1);
134*0Sstevel@tonic-gate 	}
135*0Sstevel@tonic-gate 	if (rptr == NULL)
136*0Sstevel@tonic-gate 		return (0);
137*0Sstevel@tonic-gate 	if (ctl.len < rlen) {
138*0Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: request: short information"
139*0Sstevel@tonic-gate 		    " received %d < %d\n"), myname, ctl.len, rlen);
140*0Sstevel@tonic-gate 		return (-1);
141*0Sstevel@tonic-gate 	}
142*0Sstevel@tonic-gate 	if (rlen < 0)
143*0Sstevel@tonic-gate 		rlen = -rlen;
144*0Sstevel@tonic-gate 	(void) memcpy(rptr, buf, rlen);
145*0Sstevel@tonic-gate 	return (0);
146*0Sstevel@tonic-gate }
147*0Sstevel@tonic-gate 
148*0Sstevel@tonic-gate /*
149*0Sstevel@tonic-gate  * Send a DLPI Info-Request message and return the response in the
150*0Sstevel@tonic-gate  * provided buffer.  Returns -1 on error, 0 on success.
151*0Sstevel@tonic-gate  */
152*0Sstevel@tonic-gate static int
153*0Sstevel@tonic-gate dlpi_info_req(int fd, dl_info_ack_t *info_ack)
154*0Sstevel@tonic-gate {
155*0Sstevel@tonic-gate 	dl_info_req_t info_req;
156*0Sstevel@tonic-gate 	struct strbuf ctl;
157*0Sstevel@tonic-gate 	int flags;
158*0Sstevel@tonic-gate 
159*0Sstevel@tonic-gate 	(void) memset(&info_req, '\0', sizeof (info_req));
160*0Sstevel@tonic-gate 	info_req.dl_primitive = DL_INFO_REQ;
161*0Sstevel@tonic-gate 
162*0Sstevel@tonic-gate 	ctl.maxlen = 0;
163*0Sstevel@tonic-gate 	ctl.len = DL_INFO_REQ_SIZE;
164*0Sstevel@tonic-gate 	ctl.buf = (char *)&info_req;
165*0Sstevel@tonic-gate 
166*0Sstevel@tonic-gate 	flags = 0;
167*0Sstevel@tonic-gate 	if (putmsg(fd, &ctl, (struct strbuf *)NULL, flags) < 0) {
168*0Sstevel@tonic-gate 		perror("putmsg DL_INFO_REQ");
169*0Sstevel@tonic-gate 		return (-1);
170*0Sstevel@tonic-gate 	}
171*0Sstevel@tonic-gate 	return (dlpi_reply(fd, DL_INFO_ACK, info_ack, sizeof (*info_ack)));
172*0Sstevel@tonic-gate }
173*0Sstevel@tonic-gate 
174*0Sstevel@tonic-gate /*
175*0Sstevel@tonic-gate  * Send a DLPI Attach-Request message for the indicated PPA.  Returns
176*0Sstevel@tonic-gate  * -1 on error, 0 for success.
177*0Sstevel@tonic-gate  */
178*0Sstevel@tonic-gate static int
179*0Sstevel@tonic-gate dlpi_attach_req(int fd, int ppa)
180*0Sstevel@tonic-gate {
181*0Sstevel@tonic-gate 	dl_attach_req_t attach_req;
182*0Sstevel@tonic-gate 	struct strbuf ctl;
183*0Sstevel@tonic-gate 	int flags;
184*0Sstevel@tonic-gate 
185*0Sstevel@tonic-gate 	(void) memset(&attach_req, '\0', sizeof (attach_req));
186*0Sstevel@tonic-gate 	attach_req.dl_primitive = DL_ATTACH_REQ;
187*0Sstevel@tonic-gate 	attach_req.dl_ppa = ppa;
188*0Sstevel@tonic-gate 
189*0Sstevel@tonic-gate 	ctl.maxlen = 0;
190*0Sstevel@tonic-gate 	ctl.len = DL_ATTACH_REQ_SIZE;
191*0Sstevel@tonic-gate 	ctl.buf = (char *)&attach_req;
192*0Sstevel@tonic-gate 
193*0Sstevel@tonic-gate 	flags = 0;
194*0Sstevel@tonic-gate 	if (putmsg(fd, &ctl, (struct strbuf *)NULL, flags) < 0) {
195*0Sstevel@tonic-gate 		perror("putmsg DL_ATTACH_REQ");
196*0Sstevel@tonic-gate 		return (-1);
197*0Sstevel@tonic-gate 	}
198*0Sstevel@tonic-gate 	return (dlpi_reply(fd, DL_OK_ACK, NULL, 0));
199*0Sstevel@tonic-gate }
200*0Sstevel@tonic-gate 
201*0Sstevel@tonic-gate /*
202*0Sstevel@tonic-gate  * Send a DLPI Bind-Request message for the requested SAP and set the
203*0Sstevel@tonic-gate  * local address.  Returns -1 for error.  Otherwise, the length of the
204*0Sstevel@tonic-gate  * local address is returned.
205*0Sstevel@tonic-gate  */
206*0Sstevel@tonic-gate static int
207*0Sstevel@tonic-gate dlpi_bind_req(int fd, int sap, uint8_t *localaddr, int maxaddr)
208*0Sstevel@tonic-gate {
209*0Sstevel@tonic-gate 	dl_bind_req_t bind_req;
210*0Sstevel@tonic-gate 	dl_bind_ack_t *back;
211*0Sstevel@tonic-gate 	struct strbuf ctl;
212*0Sstevel@tonic-gate 	int flags, repsize, rsize;
213*0Sstevel@tonic-gate 
214*0Sstevel@tonic-gate 	(void) memset(&bind_req, '\0', sizeof (*&bind_req));
215*0Sstevel@tonic-gate 	bind_req.dl_primitive = DL_BIND_REQ;
216*0Sstevel@tonic-gate 	/* DLPI SAPs are in host byte order! */
217*0Sstevel@tonic-gate 	bind_req.dl_sap = sap;
218*0Sstevel@tonic-gate 	bind_req.dl_service_mode = DL_CLDLS;
219*0Sstevel@tonic-gate 
220*0Sstevel@tonic-gate 	ctl.maxlen = 0;
221*0Sstevel@tonic-gate 	ctl.len = DL_BIND_REQ_SIZE;
222*0Sstevel@tonic-gate 	ctl.buf = (char *)&bind_req;
223*0Sstevel@tonic-gate 
224*0Sstevel@tonic-gate 	flags = 0;
225*0Sstevel@tonic-gate 	if (putmsg(fd, &ctl, (struct strbuf *)NULL, flags) < 0) {
226*0Sstevel@tonic-gate 		perror("putmsg DL_BIND_REQ");
227*0Sstevel@tonic-gate 		return (-1);
228*0Sstevel@tonic-gate 	}
229*0Sstevel@tonic-gate 
230*0Sstevel@tonic-gate 	repsize = sizeof (*back) + maxaddr;
231*0Sstevel@tonic-gate 	back = (dl_bind_ack_t *)alloca(repsize);
232*0Sstevel@tonic-gate 	if (dlpi_reply(fd, DL_BIND_ACK, (void *)back, -repsize) < 0)
233*0Sstevel@tonic-gate 		return (-1);
234*0Sstevel@tonic-gate 	rsize = back->dl_addr_length;
235*0Sstevel@tonic-gate 	if (rsize > maxaddr || back->dl_addr_offset+rsize > repsize) {
236*0Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: Bad hardware address size "
237*0Sstevel@tonic-gate 		    "from driver; %d > %d or %lu+%d > %d\n"), myname,
238*0Sstevel@tonic-gate 		    rsize, maxaddr, back->dl_addr_offset, rsize, repsize);
239*0Sstevel@tonic-gate 		return (-1);
240*0Sstevel@tonic-gate 	}
241*0Sstevel@tonic-gate 	(void) memcpy(localaddr, (char *)back + back->dl_addr_offset, rsize);
242*0Sstevel@tonic-gate 	return (rsize);
243*0Sstevel@tonic-gate }
244*0Sstevel@tonic-gate 
245*0Sstevel@tonic-gate /*
246*0Sstevel@tonic-gate  * Return a printable string for a DLPI style number.  (Unfortunately,
247*0Sstevel@tonic-gate  * these style numbers aren't just simple integer values, and printing
248*0Sstevel@tonic-gate  * with %d gives ugly output.)
249*0Sstevel@tonic-gate  */
250*0Sstevel@tonic-gate static const char *
251*0Sstevel@tonic-gate styleof(int dlstyle)
252*0Sstevel@tonic-gate {
253*0Sstevel@tonic-gate 	static char buf[32];
254*0Sstevel@tonic-gate 
255*0Sstevel@tonic-gate 	switch (dlstyle) {
256*0Sstevel@tonic-gate 	case DL_STYLE1:
257*0Sstevel@tonic-gate 		return ("1");
258*0Sstevel@tonic-gate 	case DL_STYLE2:
259*0Sstevel@tonic-gate 		return ("2");
260*0Sstevel@tonic-gate 	}
261*0Sstevel@tonic-gate 	(void) snprintf(buf, sizeof (buf), gettext("Unknown (0x%04X)"),
262*0Sstevel@tonic-gate 	    dlstyle);
263*0Sstevel@tonic-gate 	return ((const char *)buf);
264*0Sstevel@tonic-gate }
265*0Sstevel@tonic-gate 
266*0Sstevel@tonic-gate /*
267*0Sstevel@tonic-gate  * General DLPI attach function.  This is called indirectly through
268*0Sstevel@tonic-gate  * the protos structure for the selected lower stream protocol.
269*0Sstevel@tonic-gate  */
270*0Sstevel@tonic-gate static int
271*0Sstevel@tonic-gate dlpi_attach(struct protos *prot, char *ifname, struct attach_data *adata)
272*0Sstevel@tonic-gate {
273*0Sstevel@tonic-gate 	int devfd, ppa, dlstyle, retv;
274*0Sstevel@tonic-gate 	dl_info_ack_t dl_info;
275*0Sstevel@tonic-gate 	char tname[MAXPATHLEN], *cp;
276*0Sstevel@tonic-gate 
277*0Sstevel@tonic-gate 	cp = ifname + strlen(ifname) - 1;
278*0Sstevel@tonic-gate 	while (cp > ifname && isdigit(*cp))
279*0Sstevel@tonic-gate 		cp--;
280*0Sstevel@tonic-gate 	cp++;
281*0Sstevel@tonic-gate 	ppa = strtol(cp, NULL, 10);
282*0Sstevel@tonic-gate 
283*0Sstevel@tonic-gate 	/*
284*0Sstevel@tonic-gate 	 * Try once for the exact device name as a node.  If it's
285*0Sstevel@tonic-gate 	 * there, then this should be a DLPI style 1 driver (one node
286*0Sstevel@tonic-gate 	 * per instance).  If it's not, then it should be a style 2
287*0Sstevel@tonic-gate 	 * driver (attach specifies instance number).
288*0Sstevel@tonic-gate 	 */
289*0Sstevel@tonic-gate 	dlstyle = DL_STYLE1;
290*0Sstevel@tonic-gate 	(void) strlcpy(tname, ifname, MAXPATHLEN-1);
291*0Sstevel@tonic-gate 	if ((devfd = open(tname, O_RDWR)) < 0) {
292*0Sstevel@tonic-gate 		if (cp < ifname + MAXPATHLEN)
293*0Sstevel@tonic-gate 			tname[cp - ifname] = '\0';
294*0Sstevel@tonic-gate 		if ((devfd = open(tname, O_RDWR)) < 0) {
295*0Sstevel@tonic-gate 			perror(ifname);
296*0Sstevel@tonic-gate 			return (-1);
297*0Sstevel@tonic-gate 		}
298*0Sstevel@tonic-gate 		dlstyle = DL_STYLE2;
299*0Sstevel@tonic-gate 	}
300*0Sstevel@tonic-gate 
301*0Sstevel@tonic-gate 	if (verbose)
302*0Sstevel@tonic-gate 		(void) printf(gettext("requesting device info on %s\n"),
303*0Sstevel@tonic-gate 		    tname);
304*0Sstevel@tonic-gate 	if (dlpi_info_req(devfd, &dl_info))
305*0Sstevel@tonic-gate 		return (-1);
306*0Sstevel@tonic-gate 	if (dl_info.dl_provider_style != dlstyle) {
307*0Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: unexpected DLPI provider "
308*0Sstevel@tonic-gate 		    "style on %s: got %s, "), myname, tname,
309*0Sstevel@tonic-gate 		    styleof(dl_info.dl_provider_style));
310*0Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("expected %s\n"),
311*0Sstevel@tonic-gate 		    styleof(dlstyle));
312*0Sstevel@tonic-gate 		if (ifname[0] != '\0' &&
313*0Sstevel@tonic-gate 		    !isdigit(ifname[strlen(ifname) - 1])) {
314*0Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("(did you forget an "
315*0Sstevel@tonic-gate 			    "instance number?)\n"));
316*0Sstevel@tonic-gate 		}
317*0Sstevel@tonic-gate 		(void) close(devfd);
318*0Sstevel@tonic-gate 		return (-1);
319*0Sstevel@tonic-gate 	}
320*0Sstevel@tonic-gate 
321*0Sstevel@tonic-gate 	if (dlstyle == DL_STYLE2) {
322*0Sstevel@tonic-gate 		if (verbose)
323*0Sstevel@tonic-gate 			(void) printf(gettext("attaching to ppa %d\n"), ppa);
324*0Sstevel@tonic-gate 		if (dlpi_attach_req(devfd, ppa)) {
325*0Sstevel@tonic-gate 			(void) close(devfd);
326*0Sstevel@tonic-gate 			return (-1);
327*0Sstevel@tonic-gate 		}
328*0Sstevel@tonic-gate 	}
329*0Sstevel@tonic-gate 
330*0Sstevel@tonic-gate 	if (verbose)
331*0Sstevel@tonic-gate 		(void) printf(gettext("binding to Ethertype %04X\n"),
332*0Sstevel@tonic-gate 		    prot->protval);
333*0Sstevel@tonic-gate 	retv = dlpi_bind_req(devfd, prot->protval,
334*0Sstevel@tonic-gate 	    (uint8_t *)&adata->localaddr, sizeof (adata->localaddr));
335*0Sstevel@tonic-gate 	if (retv < 0) {
336*0Sstevel@tonic-gate 		(void) close(devfd);
337*0Sstevel@tonic-gate 		return (-1);
338*0Sstevel@tonic-gate 	}
339*0Sstevel@tonic-gate 	adata->locallen = retv;
340*0Sstevel@tonic-gate 
341*0Sstevel@tonic-gate 	(void) snprintf(adata->appstr, sizeof (adata->appstr), "%d", ppa);
342*0Sstevel@tonic-gate 	return (devfd);
343*0Sstevel@tonic-gate }
344*0Sstevel@tonic-gate 
345*0Sstevel@tonic-gate 
346*0Sstevel@tonic-gate static struct protos proto_list[] = {
347*0Sstevel@tonic-gate 	{ "pppoe", "RFC 2516 PPP over Ethernet", dlpi_attach, ETHERTYPE_PPPOES,
348*0Sstevel@tonic-gate 	    PTS_PPPOE },
349*0Sstevel@tonic-gate 	{ "pppoed", "RFC 2516 PPP over Ethernet Discovery", dlpi_attach,
350*0Sstevel@tonic-gate 	    ETHERTYPE_PPPOED, PTS_PPPOE },
351*0Sstevel@tonic-gate 	{ NULL }
352*0Sstevel@tonic-gate };
353*0Sstevel@tonic-gate 
354*0Sstevel@tonic-gate /*
355*0Sstevel@tonic-gate  * Issue a STREAMS I_STR ioctl and fetch the result.  Returns -1 on
356*0Sstevel@tonic-gate  * error, or length of returned data on success.
357*0Sstevel@tonic-gate  */
358*0Sstevel@tonic-gate static int
359*0Sstevel@tonic-gate strioctl(int fd, int cmd, void *ptr, int ilen, int olen, const char *iocname)
360*0Sstevel@tonic-gate {
361*0Sstevel@tonic-gate 	struct strioctl	str;
362*0Sstevel@tonic-gate 
363*0Sstevel@tonic-gate 	str.ic_cmd = cmd;
364*0Sstevel@tonic-gate 	str.ic_timout = 0;
365*0Sstevel@tonic-gate 	str.ic_len = ilen;
366*0Sstevel@tonic-gate 	str.ic_dp = ptr;
367*0Sstevel@tonic-gate 
368*0Sstevel@tonic-gate 	if (ioctl(fd, I_STR, &str) == -1) {
369*0Sstevel@tonic-gate 		perror(iocname);
370*0Sstevel@tonic-gate 		return (-1);
371*0Sstevel@tonic-gate 	}
372*0Sstevel@tonic-gate 
373*0Sstevel@tonic-gate 	if (olen >= 0) {
374*0Sstevel@tonic-gate 		if (str.ic_len > olen && verbose > 1) {
375*0Sstevel@tonic-gate 			(void) printf(gettext("%s:%s: extra data received; "
376*0Sstevel@tonic-gate 			    "%d > %d\n"), myname, iocname, str.ic_len, olen);
377*0Sstevel@tonic-gate 		} else if (str.ic_len < olen) {
378*0Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("%s:%s: expected %d "
379*0Sstevel@tonic-gate 			    "bytes, got %d\n"), myname, iocname, olen,
380*0Sstevel@tonic-gate 			    str.ic_len);
381*0Sstevel@tonic-gate 			return (-1);
382*0Sstevel@tonic-gate 		}
383*0Sstevel@tonic-gate 	}
384*0Sstevel@tonic-gate 
385*0Sstevel@tonic-gate 	return (str.ic_len);
386*0Sstevel@tonic-gate }
387*0Sstevel@tonic-gate 
388*0Sstevel@tonic-gate /*
389*0Sstevel@tonic-gate  * Handle user request to plumb a new lower stream under the sppptun
390*0Sstevel@tonic-gate  * driver.
391*0Sstevel@tonic-gate  */
392*0Sstevel@tonic-gate static int
393*0Sstevel@tonic-gate plumb_it(int argc, char **argv)
394*0Sstevel@tonic-gate {
395*0Sstevel@tonic-gate 	int devfd, muxfd, muxid;
396*0Sstevel@tonic-gate 	struct ppptun_info pti;
397*0Sstevel@tonic-gate 	char *cp, *ifname;
398*0Sstevel@tonic-gate 	struct protos *prot;
399*0Sstevel@tonic-gate 	char dname[MAXPATHLEN];
400*0Sstevel@tonic-gate 	struct attach_data adata;
401*0Sstevel@tonic-gate 
402*0Sstevel@tonic-gate 	/* If no protocol requested, then list known protocols. */
403*0Sstevel@tonic-gate 	if (optind == argc) {
404*0Sstevel@tonic-gate 		(void) puts("Known tunneling protocols:");
405*0Sstevel@tonic-gate 		for (prot = proto_list; prot->name != NULL; prot++)
406*0Sstevel@tonic-gate 			(void) printf("\t%s\t%s\n", prot->name, prot->desc);
407*0Sstevel@tonic-gate 		return (0);
408*0Sstevel@tonic-gate 	}
409*0Sstevel@tonic-gate 
410*0Sstevel@tonic-gate 	/* If missing protocol or device, then abort. */
411*0Sstevel@tonic-gate 	if (optind != argc-2)
412*0Sstevel@tonic-gate 		usage();
413*0Sstevel@tonic-gate 
414*0Sstevel@tonic-gate 	/* Look up requested protocol. */
415*0Sstevel@tonic-gate 	cp = argv[optind++];
416*0Sstevel@tonic-gate 	for (prot = proto_list; prot->name != NULL; prot++)
417*0Sstevel@tonic-gate 		if (strcasecmp(cp, prot->name) == 0)
418*0Sstevel@tonic-gate 			break;
419*0Sstevel@tonic-gate 	if (prot->name == NULL) {
420*0Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: unknown protocol %s\n"),
421*0Sstevel@tonic-gate 		    myname, cp);
422*0Sstevel@tonic-gate 		return (1);
423*0Sstevel@tonic-gate 	}
424*0Sstevel@tonic-gate 
425*0Sstevel@tonic-gate 	/* Get interface and make relative to /dev/ if necessary. */
426*0Sstevel@tonic-gate 	ifname = argv[optind];
427*0Sstevel@tonic-gate 	if (ifname[0] != '.' && ifname[0] != '/') {
428*0Sstevel@tonic-gate 		(void) snprintf(dname, sizeof (dname), "/dev/%s", ifname);
429*0Sstevel@tonic-gate 		ifname = dname;
430*0Sstevel@tonic-gate 	}
431*0Sstevel@tonic-gate 
432*0Sstevel@tonic-gate 	/* Call per-protocol attach routine to open device */
433*0Sstevel@tonic-gate 	if (verbose)
434*0Sstevel@tonic-gate 		(void) printf(gettext("opening %s\n"), ifname);
435*0Sstevel@tonic-gate 	devfd = (*prot->attach)(prot, ifname, &adata);
436*0Sstevel@tonic-gate 	if (devfd < 0)
437*0Sstevel@tonic-gate 		return (1);
438*0Sstevel@tonic-gate 
439*0Sstevel@tonic-gate 	/* Open sppptun driver */
440*0Sstevel@tonic-gate 	if (verbose)
441*0Sstevel@tonic-gate 		(void) printf(gettext("opening /dev/%s\n"), PPP_TUN_NAME);
442*0Sstevel@tonic-gate 	if ((muxfd = open("/dev/" PPP_TUN_NAME, O_RDWR)) < 0) {
443*0Sstevel@tonic-gate 		perror("/dev/" PPP_TUN_NAME);
444*0Sstevel@tonic-gate 		return (1);
445*0Sstevel@tonic-gate 	}
446*0Sstevel@tonic-gate 
447*0Sstevel@tonic-gate 	/* Push sppptun module on top of lower driver. */
448*0Sstevel@tonic-gate 	if (verbose)
449*0Sstevel@tonic-gate 		(void) printf(gettext("pushing %s on %s\n"), PPP_TUN_NAME,
450*0Sstevel@tonic-gate 		    ifname);
451*0Sstevel@tonic-gate 	if (ioctl(devfd, I_PUSH, PPP_TUN_NAME) == -1) {
452*0Sstevel@tonic-gate 		perror("I_PUSH " PPP_TUN_NAME);
453*0Sstevel@tonic-gate 		return (1);
454*0Sstevel@tonic-gate 	}
455*0Sstevel@tonic-gate 
456*0Sstevel@tonic-gate 	/* Get the name of the newly-created lower stream. */
457*0Sstevel@tonic-gate 	if (verbose)
458*0Sstevel@tonic-gate 		(void) printf(gettext("getting new interface name\n"));
459*0Sstevel@tonic-gate 	if (strioctl(devfd, PPPTUN_GNAME, pti.pti_name, 0,
460*0Sstevel@tonic-gate 	    sizeof (pti.pti_name), "PPPTUN_GNAME") < 0)
461*0Sstevel@tonic-gate 		return (1);
462*0Sstevel@tonic-gate 	if (verbose)
463*0Sstevel@tonic-gate 		(void) printf(gettext("got interface %s\n"), pti.pti_name);
464*0Sstevel@tonic-gate 
465*0Sstevel@tonic-gate 	/* Convert stream name to protocol-specific name. */
466*0Sstevel@tonic-gate 	if ((cp = strchr(pti.pti_name, ':')) != NULL)
467*0Sstevel@tonic-gate 		*cp = '\0';
468*0Sstevel@tonic-gate 	(void) snprintf(pti.pti_name+strlen(pti.pti_name),
469*0Sstevel@tonic-gate 	    sizeof (pti.pti_name)-strlen(pti.pti_name), "%s:%s", adata.appstr,
470*0Sstevel@tonic-gate 	    prot->name);
471*0Sstevel@tonic-gate 
472*0Sstevel@tonic-gate 	/* Change the lower stream name. */
473*0Sstevel@tonic-gate 	if (verbose)
474*0Sstevel@tonic-gate 		(void) printf(gettext("resetting interface name to %s\n"),
475*0Sstevel@tonic-gate 		    pti.pti_name);
476*0Sstevel@tonic-gate 	if (strioctl(devfd, PPPTUN_SNAME, pti.pti_name,
477*0Sstevel@tonic-gate 	    sizeof (pti.pti_name), 0, "PPPTUN_SNAME") < 0) {
478*0Sstevel@tonic-gate 		if (errno == EEXIST)
479*0Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("%s: %s already "
480*0Sstevel@tonic-gate 			    "installed\n"), myname, pti.pti_name);
481*0Sstevel@tonic-gate 		return (1);
482*0Sstevel@tonic-gate 	}
483*0Sstevel@tonic-gate 
484*0Sstevel@tonic-gate 	/*
485*0Sstevel@tonic-gate 	 * Send down the local interface address to the lower stream
486*0Sstevel@tonic-gate 	 * so that it can originate packets.
487*0Sstevel@tonic-gate 	 */
488*0Sstevel@tonic-gate 	if (verbose)
489*0Sstevel@tonic-gate 		(void) printf(gettext("send down local address\n"));
490*0Sstevel@tonic-gate 	if (strioctl(devfd, PPPTUN_LCLADDR, &adata.localaddr, adata.locallen,
491*0Sstevel@tonic-gate 	    0, "PPPTUN_LCLADDR") < 0)
492*0Sstevel@tonic-gate 		return (1);
493*0Sstevel@tonic-gate 
494*0Sstevel@tonic-gate 	/* Link the lower stream under the tunnel device. */
495*0Sstevel@tonic-gate 	if (verbose)
496*0Sstevel@tonic-gate 		(void) printf(gettext("doing I_PLINK\n"));
497*0Sstevel@tonic-gate 	if ((muxid = ioctl(muxfd, I_PLINK, devfd)) == -1) {
498*0Sstevel@tonic-gate 		perror("I_PLINK");
499*0Sstevel@tonic-gate 		return (1);
500*0Sstevel@tonic-gate 	}
501*0Sstevel@tonic-gate 
502*0Sstevel@tonic-gate 	/*
503*0Sstevel@tonic-gate 	 * Give the tunnel driver the multiplex ID of the new lower
504*0Sstevel@tonic-gate 	 * stream.  This allows the unplumb function to find and
505*0Sstevel@tonic-gate 	 * disconnect the lower stream.
506*0Sstevel@tonic-gate 	 */
507*0Sstevel@tonic-gate 	if (verbose)
508*0Sstevel@tonic-gate 		(void) printf(gettext("sending muxid %d and style %d to "
509*0Sstevel@tonic-gate 		    "driver\n"), muxid, prot->style);
510*0Sstevel@tonic-gate 	pti.pti_muxid = muxid;
511*0Sstevel@tonic-gate 	pti.pti_style = prot->style;
512*0Sstevel@tonic-gate 	if (strioctl(muxfd, PPPTUN_SINFO, &pti, sizeof (pti), 0,
513*0Sstevel@tonic-gate 	    "PPPTUN_SINFO") < 0)
514*0Sstevel@tonic-gate 		return (1);
515*0Sstevel@tonic-gate 
516*0Sstevel@tonic-gate 	if (verbose)
517*0Sstevel@tonic-gate 		(void) printf(gettext("done; installed %s\n"), pti.pti_name);
518*0Sstevel@tonic-gate 	else
519*0Sstevel@tonic-gate 		(void) puts(pti.pti_name);
520*0Sstevel@tonic-gate 
521*0Sstevel@tonic-gate 	return (0);
522*0Sstevel@tonic-gate }
523*0Sstevel@tonic-gate 
524*0Sstevel@tonic-gate /*
525*0Sstevel@tonic-gate  * Handle user request to unplumb an existing lower stream from the
526*0Sstevel@tonic-gate  * sppptun driver.
527*0Sstevel@tonic-gate  */
528*0Sstevel@tonic-gate static int
529*0Sstevel@tonic-gate unplumb_it(int argc, char **argv)
530*0Sstevel@tonic-gate {
531*0Sstevel@tonic-gate 	char *ifname;
532*0Sstevel@tonic-gate 	int muxfd;
533*0Sstevel@tonic-gate 	struct ppptun_info pti;
534*0Sstevel@tonic-gate 
535*0Sstevel@tonic-gate 	/*
536*0Sstevel@tonic-gate 	 * Need to have the name of the lower stream on the command
537*0Sstevel@tonic-gate 	 * line.
538*0Sstevel@tonic-gate 	 */
539*0Sstevel@tonic-gate 	if (optind != argc-1)
540*0Sstevel@tonic-gate 		usage();
541*0Sstevel@tonic-gate 
542*0Sstevel@tonic-gate 	ifname = argv[optind];
543*0Sstevel@tonic-gate 
544*0Sstevel@tonic-gate 	/* Open the tunnel driver. */
545*0Sstevel@tonic-gate 	if (verbose)
546*0Sstevel@tonic-gate 		(void) printf(gettext("opening /dev/%s\n"), PPP_TUN_NAME);
547*0Sstevel@tonic-gate 	if ((muxfd = open("/dev/" PPP_TUN_NAME, O_RDWR)) < 0) {
548*0Sstevel@tonic-gate 		perror("/dev/" PPP_TUN_NAME);
549*0Sstevel@tonic-gate 		return (1);
550*0Sstevel@tonic-gate 	}
551*0Sstevel@tonic-gate 
552*0Sstevel@tonic-gate 	/* Get lower stream information; including multiplex ID. */
553*0Sstevel@tonic-gate 	if (verbose)
554*0Sstevel@tonic-gate 		(void) printf(gettext("getting info from driver\n"));
555*0Sstevel@tonic-gate 	(void) strncpy(pti.pti_name, ifname, sizeof (pti.pti_name));
556*0Sstevel@tonic-gate 	if (strioctl(muxfd, PPPTUN_GINFO, &pti, sizeof (pti),
557*0Sstevel@tonic-gate 	    sizeof (pti), "PPPTUN_GINFO") < 0)
558*0Sstevel@tonic-gate 		return (1);
559*0Sstevel@tonic-gate 	if (verbose)
560*0Sstevel@tonic-gate 		(void) printf(gettext("got muxid %d from driver\n"),
561*0Sstevel@tonic-gate 		    pti.pti_muxid);
562*0Sstevel@tonic-gate 
563*0Sstevel@tonic-gate 	/* Unlink lower stream from driver. */
564*0Sstevel@tonic-gate 	if (verbose)
565*0Sstevel@tonic-gate 		(void) printf(gettext("doing I_PUNLINK\n"));
566*0Sstevel@tonic-gate 	if (ioctl(muxfd, I_PUNLINK, pti.pti_muxid) < 0) {
567*0Sstevel@tonic-gate 		perror("I_PUNLINK");
568*0Sstevel@tonic-gate 		return (1);
569*0Sstevel@tonic-gate 	}
570*0Sstevel@tonic-gate 	if (verbose)
571*0Sstevel@tonic-gate 		(void) printf(gettext("done!\n"));
572*0Sstevel@tonic-gate 
573*0Sstevel@tonic-gate 	return (0);
574*0Sstevel@tonic-gate }
575*0Sstevel@tonic-gate 
576*0Sstevel@tonic-gate /*
577*0Sstevel@tonic-gate  * Handle user request to list lower streams plumbed under the sppptun
578*0Sstevel@tonic-gate  * driver.
579*0Sstevel@tonic-gate  */
580*0Sstevel@tonic-gate /*ARGSUSED*/
581*0Sstevel@tonic-gate static int
582*0Sstevel@tonic-gate query_interfaces(int argc, char **argv)
583*0Sstevel@tonic-gate {
584*0Sstevel@tonic-gate 	int muxfd, i;
585*0Sstevel@tonic-gate 	union ppptun_name ptn;
586*0Sstevel@tonic-gate 
587*0Sstevel@tonic-gate 	/* No other arguments permitted. */
588*0Sstevel@tonic-gate 	if (optind != argc)
589*0Sstevel@tonic-gate 		usage();
590*0Sstevel@tonic-gate 
591*0Sstevel@tonic-gate 	/* Open the tunnel driver. */
592*0Sstevel@tonic-gate 	if (verbose)
593*0Sstevel@tonic-gate 		(void) printf(gettext("opening /dev/%s\n"), PPP_TUN_NAME);
594*0Sstevel@tonic-gate 	if ((muxfd = open("/dev/" PPP_TUN_NAME, O_RDWR)) < 0) {
595*0Sstevel@tonic-gate 		perror("/dev/" PPP_TUN_NAME);
596*0Sstevel@tonic-gate 		return (1);
597*0Sstevel@tonic-gate 	}
598*0Sstevel@tonic-gate 
599*0Sstevel@tonic-gate 	/* Read and print names of lower streams. */
600*0Sstevel@tonic-gate 	for (i = 0; ; i++) {
601*0Sstevel@tonic-gate 		ptn.ptn_index = i;
602*0Sstevel@tonic-gate 		if (strioctl(muxfd, PPPTUN_GNNAME, &ptn, sizeof (ptn),
603*0Sstevel@tonic-gate 		    sizeof (ptn), "PPPTUN_GNNAME") < 0) {
604*0Sstevel@tonic-gate 			perror("PPPTUN_GNNAME");
605*0Sstevel@tonic-gate 			break;
606*0Sstevel@tonic-gate 		}
607*0Sstevel@tonic-gate 		/* Stop when we index off the end of the list. */
608*0Sstevel@tonic-gate 		if (ptn.ptn_name[0] == '\0')
609*0Sstevel@tonic-gate 			break;
610*0Sstevel@tonic-gate 		(void) puts(ptn.ptn_name);
611*0Sstevel@tonic-gate 	}
612*0Sstevel@tonic-gate 	return (0);
613*0Sstevel@tonic-gate }
614*0Sstevel@tonic-gate 
615*0Sstevel@tonic-gate /*
616*0Sstevel@tonic-gate  * Invoked by SIGALRM -- timer prevents problems in driver from
617*0Sstevel@tonic-gate  * hanging the utility.
618*0Sstevel@tonic-gate  */
619*0Sstevel@tonic-gate /*ARGSUSED*/
620*0Sstevel@tonic-gate static void
621*0Sstevel@tonic-gate toolong(int dummy)
622*0Sstevel@tonic-gate {
623*0Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("%s: time-out in driver\n"), myname);
624*0Sstevel@tonic-gate 	exit(1);
625*0Sstevel@tonic-gate }
626*0Sstevel@tonic-gate 
627*0Sstevel@tonic-gate int
628*0Sstevel@tonic-gate main(int argc, char **argv)
629*0Sstevel@tonic-gate {
630*0Sstevel@tonic-gate 	int opt, errflag = 0;
631*0Sstevel@tonic-gate 	char *arg;
632*0Sstevel@tonic-gate 
633*0Sstevel@tonic-gate 	myname = *argv;
634*0Sstevel@tonic-gate 
635*0Sstevel@tonic-gate 
636*0Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
637*0Sstevel@tonic-gate 
638*0Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)	/* Should be defined by cc -D */
639*0Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"
640*0Sstevel@tonic-gate #endif
641*0Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
642*0Sstevel@tonic-gate 
643*0Sstevel@tonic-gate 	/* Parse command line flags */
644*0Sstevel@tonic-gate 	while ((opt = getopt(argc, argv, "v")) != EOF)
645*0Sstevel@tonic-gate 		switch (opt) {
646*0Sstevel@tonic-gate 		case 'v':
647*0Sstevel@tonic-gate 			verbose++;
648*0Sstevel@tonic-gate 			break;
649*0Sstevel@tonic-gate 		default:
650*0Sstevel@tonic-gate 			errflag++;
651*0Sstevel@tonic-gate 			break;
652*0Sstevel@tonic-gate 		}
653*0Sstevel@tonic-gate 	if (errflag != 0 || optind >= argc)
654*0Sstevel@tonic-gate 		usage();
655*0Sstevel@tonic-gate 
656*0Sstevel@tonic-gate 	/* Set alarm to avoid stalling on any driver errors. */
657*0Sstevel@tonic-gate 	(void) signal(SIGALRM, toolong);
658*0Sstevel@tonic-gate 	(void) alarm(2);
659*0Sstevel@tonic-gate 
660*0Sstevel@tonic-gate 	/* Switch out based on user-requested function. */
661*0Sstevel@tonic-gate 	arg = argv[optind++];
662*0Sstevel@tonic-gate 	if (strcmp(arg, "plumb") == 0)
663*0Sstevel@tonic-gate 		return (plumb_it(argc, argv));
664*0Sstevel@tonic-gate 	if (strcmp(arg, "unplumb") == 0)
665*0Sstevel@tonic-gate 		return (unplumb_it(argc, argv));
666*0Sstevel@tonic-gate 	if (strcmp(arg, "query") == 0)
667*0Sstevel@tonic-gate 		return (query_interfaces(argc, argv));
668*0Sstevel@tonic-gate 
669*0Sstevel@tonic-gate 	usage();
670*0Sstevel@tonic-gate 	return (1);
671*0Sstevel@tonic-gate }
672