1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * pppoe.c - pppd plugin to handle PPPoE operation.
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
5*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
6*7c478bd9Sstevel@tonic-gate  */
7*7c478bd9Sstevel@tonic-gate 
8*7c478bd9Sstevel@tonic-gate #include <unistd.h>
9*7c478bd9Sstevel@tonic-gate #include <stddef.h>
10*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
11*7c478bd9Sstevel@tonic-gate #include <errno.h>
12*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
13*7c478bd9Sstevel@tonic-gate #include <fcntl.h>
14*7c478bd9Sstevel@tonic-gate #include <strings.h>
15*7c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
16*7c478bd9Sstevel@tonic-gate #include <netinet/in.h>
17*7c478bd9Sstevel@tonic-gate #include <net/pppio.h>
18*7c478bd9Sstevel@tonic-gate #include <net/sppptun.h>
19*7c478bd9Sstevel@tonic-gate #include <net/pppoe.h>
20*7c478bd9Sstevel@tonic-gate 
21*7c478bd9Sstevel@tonic-gate #include "pppd.h"
22*7c478bd9Sstevel@tonic-gate #include "pathnames.h"
23*7c478bd9Sstevel@tonic-gate 
24*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
25*7c478bd9Sstevel@tonic-gate 
26*7c478bd9Sstevel@tonic-gate /* Saved hook pointers */
27*7c478bd9Sstevel@tonic-gate static int (*old_check_options)(uid_t uid);
28*7c478bd9Sstevel@tonic-gate static int (*old_updown_script)(const char ***argsp);
29*7c478bd9Sstevel@tonic-gate static int (*old_sys_read_packet)(int retv, struct strbuf *ctrl,
30*7c478bd9Sstevel@tonic-gate     struct strbuf *data, int flags);
31*7c478bd9Sstevel@tonic-gate 
32*7c478bd9Sstevel@tonic-gate /* Room for 3 IPv4 addresses and metric */
33*7c478bd9Sstevel@tonic-gate #define	RTE_MSG_LEN	(3*16 + 10 + 1)
34*7c478bd9Sstevel@tonic-gate 
35*7c478bd9Sstevel@tonic-gate /* Environment string for routes */
36*7c478bd9Sstevel@tonic-gate #define	RTE_STR	"ROUTE_%d"
37*7c478bd9Sstevel@tonic-gate 
38*7c478bd9Sstevel@tonic-gate /*
39*7c478bd9Sstevel@tonic-gate  * strioctl()
40*7c478bd9Sstevel@tonic-gate  *
41*7c478bd9Sstevel@tonic-gate  * wrapper for STREAMS I_STR ioctl.
42*7c478bd9Sstevel@tonic-gate  */
43*7c478bd9Sstevel@tonic-gate static int
44*7c478bd9Sstevel@tonic-gate strioctl(int fd, int cmd, void *ptr, int ilen, int olen)
45*7c478bd9Sstevel@tonic-gate {
46*7c478bd9Sstevel@tonic-gate 	struct strioctl	str;
47*7c478bd9Sstevel@tonic-gate 
48*7c478bd9Sstevel@tonic-gate 	str.ic_cmd = cmd;
49*7c478bd9Sstevel@tonic-gate 	str.ic_timout = 0;	/* Use default timer; 15 seconds */
50*7c478bd9Sstevel@tonic-gate 	str.ic_len = ilen;
51*7c478bd9Sstevel@tonic-gate 	str.ic_dp = ptr;
52*7c478bd9Sstevel@tonic-gate 
53*7c478bd9Sstevel@tonic-gate 	if (ioctl(fd, I_STR, &str) == -1) {
54*7c478bd9Sstevel@tonic-gate 		return (-1);
55*7c478bd9Sstevel@tonic-gate 	}
56*7c478bd9Sstevel@tonic-gate 	if (str.ic_len != olen) {
57*7c478bd9Sstevel@tonic-gate 		return (-1);
58*7c478bd9Sstevel@tonic-gate 	}
59*7c478bd9Sstevel@tonic-gate 	return (0);
60*7c478bd9Sstevel@tonic-gate }
61*7c478bd9Sstevel@tonic-gate 
62*7c478bd9Sstevel@tonic-gate /*
63*7c478bd9Sstevel@tonic-gate  * If the user named the tunneling device, check that it is
64*7c478bd9Sstevel@tonic-gate  * reasonable; otherwise check that standard input is the tunnel.
65*7c478bd9Sstevel@tonic-gate  */
66*7c478bd9Sstevel@tonic-gate static int
67*7c478bd9Sstevel@tonic-gate pppoe_check_options(uid_t uid)
68*7c478bd9Sstevel@tonic-gate {
69*7c478bd9Sstevel@tonic-gate 	int tstfd;	/* fd for device being checked */
70*7c478bd9Sstevel@tonic-gate 	int err;	/* saved errno value */
71*7c478bd9Sstevel@tonic-gate 	int retv;	/* return value */
72*7c478bd9Sstevel@tonic-gate 	int intv;	/* integer return value (from ioctl) */
73*7c478bd9Sstevel@tonic-gate 	union ppptun_name ptn;
74*7c478bd9Sstevel@tonic-gate 
75*7c478bd9Sstevel@tonic-gate 	if (devnam[0] != '\0') {
76*7c478bd9Sstevel@tonic-gate 		/*
77*7c478bd9Sstevel@tonic-gate 		 * Open as real user so that modes on device can be
78*7c478bd9Sstevel@tonic-gate 		 * used to limit access.
79*7c478bd9Sstevel@tonic-gate 		 */
80*7c478bd9Sstevel@tonic-gate 		if (!devnam_info.priv)
81*7c478bd9Sstevel@tonic-gate 			(void) seteuid(uid);
82*7c478bd9Sstevel@tonic-gate 		tstfd = open(devnam, O_NONBLOCK | O_RDWR, 0);
83*7c478bd9Sstevel@tonic-gate 		err = errno;
84*7c478bd9Sstevel@tonic-gate 		if (!devnam_info.priv)
85*7c478bd9Sstevel@tonic-gate 			(void) seteuid(0);
86*7c478bd9Sstevel@tonic-gate 		if (tstfd == -1) {
87*7c478bd9Sstevel@tonic-gate 			errno = err;
88*7c478bd9Sstevel@tonic-gate 			option_error("unable to open %s: %m", devnam);
89*7c478bd9Sstevel@tonic-gate 			return (-1);
90*7c478bd9Sstevel@tonic-gate 		}
91*7c478bd9Sstevel@tonic-gate 		retv = strioctl(tstfd, PPPTUN_GDATA, &ptn, 0, sizeof (ptn));
92*7c478bd9Sstevel@tonic-gate 		(void) close(tstfd);
93*7c478bd9Sstevel@tonic-gate 		if (retv == -1) {
94*7c478bd9Sstevel@tonic-gate 			option_error("device %s is not a PPP tunneling device",
95*7c478bd9Sstevel@tonic-gate 			    devnam);
96*7c478bd9Sstevel@tonic-gate 			return (-1);
97*7c478bd9Sstevel@tonic-gate 		}
98*7c478bd9Sstevel@tonic-gate 	} else {
99*7c478bd9Sstevel@tonic-gate 		retv = strioctl(0, PPPIO_GTYPE, &intv, 0, sizeof (intv));
100*7c478bd9Sstevel@tonic-gate 		if (retv == -1) {
101*7c478bd9Sstevel@tonic-gate 			option_error("standard input is not a PPP device");
102*7c478bd9Sstevel@tonic-gate 			return (-1);
103*7c478bd9Sstevel@tonic-gate 		}
104*7c478bd9Sstevel@tonic-gate 		retv = strioctl(0, PPPTUN_GDATA, &ptn, 0, sizeof (ptn));
105*7c478bd9Sstevel@tonic-gate 		if (retv == -1) {
106*7c478bd9Sstevel@tonic-gate 			option_error("standard input is not a PPP tunnel");
107*7c478bd9Sstevel@tonic-gate 			return (-1);
108*7c478bd9Sstevel@tonic-gate 		}
109*7c478bd9Sstevel@tonic-gate 		if (strcmp(ptn.ptn_name + strlen(ptn.ptn_name) - 6,
110*7c478bd9Sstevel@tonic-gate 		    ":pppoe") != 0) {
111*7c478bd9Sstevel@tonic-gate 			option_error("standard input not connected to PPPoE");
112*7c478bd9Sstevel@tonic-gate 			return (-1);
113*7c478bd9Sstevel@tonic-gate 		}
114*7c478bd9Sstevel@tonic-gate 	}
115*7c478bd9Sstevel@tonic-gate 	if (old_check_options != NULL &&
116*7c478bd9Sstevel@tonic-gate 	    old_check_options != pppoe_check_options)
117*7c478bd9Sstevel@tonic-gate 		return ((*old_check_options)(uid));
118*7c478bd9Sstevel@tonic-gate 	return (0);
119*7c478bd9Sstevel@tonic-gate }
120*7c478bd9Sstevel@tonic-gate 
121*7c478bd9Sstevel@tonic-gate /*
122*7c478bd9Sstevel@tonic-gate  * When we're about to call one of the up or down scripts, change the
123*7c478bd9Sstevel@tonic-gate  * second argument to contain the interface name and selected PPPoE
124*7c478bd9Sstevel@tonic-gate  * service.
125*7c478bd9Sstevel@tonic-gate  */
126*7c478bd9Sstevel@tonic-gate static int
127*7c478bd9Sstevel@tonic-gate pppoe_updown_script(const char ***argsp)
128*7c478bd9Sstevel@tonic-gate {
129*7c478bd9Sstevel@tonic-gate 	const char *cp;
130*7c478bd9Sstevel@tonic-gate 
131*7c478bd9Sstevel@tonic-gate 	if ((*argsp)[2] == devnam &&
132*7c478bd9Sstevel@tonic-gate 	    (cp = script_getenv("IF_AND_SERVICE")) != NULL)
133*7c478bd9Sstevel@tonic-gate 		(*argsp)[2] = cp;
134*7c478bd9Sstevel@tonic-gate 	if (old_updown_script != NULL &&
135*7c478bd9Sstevel@tonic-gate 	    old_updown_script != pppoe_updown_script)
136*7c478bd9Sstevel@tonic-gate 		return ((*old_updown_script)(argsp));
137*7c478bd9Sstevel@tonic-gate 	return (0);
138*7c478bd9Sstevel@tonic-gate }
139*7c478bd9Sstevel@tonic-gate 
140*7c478bd9Sstevel@tonic-gate /*
141*7c478bd9Sstevel@tonic-gate  * Concatenate and save strings from command line into environment
142*7c478bd9Sstevel@tonic-gate  * variable.
143*7c478bd9Sstevel@tonic-gate  */
144*7c478bd9Sstevel@tonic-gate static void
145*7c478bd9Sstevel@tonic-gate cat_save_env(char **argv, char idchar, const char *envname)
146*7c478bd9Sstevel@tonic-gate {
147*7c478bd9Sstevel@tonic-gate 	char **argp;
148*7c478bd9Sstevel@tonic-gate 	int totlen;
149*7c478bd9Sstevel@tonic-gate 	char *str;
150*7c478bd9Sstevel@tonic-gate 	char *cp;
151*7c478bd9Sstevel@tonic-gate 
152*7c478bd9Sstevel@tonic-gate 	totlen = 0;
153*7c478bd9Sstevel@tonic-gate 	for (argp = argv; argp[0] != NULL; argp += 2)
154*7c478bd9Sstevel@tonic-gate 		if (*argp[0] == idchar)
155*7c478bd9Sstevel@tonic-gate 			totlen += strlen(argp[1]) + 1;
156*7c478bd9Sstevel@tonic-gate 	if ((str = malloc(totlen + 1)) == NULL) {
157*7c478bd9Sstevel@tonic-gate 		error("cannot malloc PPPoE environment for %s", envname);
158*7c478bd9Sstevel@tonic-gate 		return;
159*7c478bd9Sstevel@tonic-gate 	}
160*7c478bd9Sstevel@tonic-gate 	cp = str;
161*7c478bd9Sstevel@tonic-gate 	for (argp = argv; argp[0] != NULL; argp += 2)
162*7c478bd9Sstevel@tonic-gate 		if (*argp[0] == idchar) {
163*7c478bd9Sstevel@tonic-gate 			(void) strcpy(cp, argp[1]);
164*7c478bd9Sstevel@tonic-gate 			cp += strlen(cp);
165*7c478bd9Sstevel@tonic-gate 			*cp++ = '\n';
166*7c478bd9Sstevel@tonic-gate 		}
167*7c478bd9Sstevel@tonic-gate 	*cp = '\0';
168*7c478bd9Sstevel@tonic-gate 	script_setenv(envname, str, 0);
169*7c478bd9Sstevel@tonic-gate }
170*7c478bd9Sstevel@tonic-gate 
171*7c478bd9Sstevel@tonic-gate /*
172*7c478bd9Sstevel@tonic-gate  * Convert Message Of The Moment (MOTM) and Host Uniform Resource
173*7c478bd9Sstevel@tonic-gate  * Locator (HURL) strings into environment variables and command-line
174*7c478bd9Sstevel@tonic-gate  * arguments for script.
175*7c478bd9Sstevel@tonic-gate  */
176*7c478bd9Sstevel@tonic-gate static void
177*7c478bd9Sstevel@tonic-gate handle_motm_hurl(char **argv, int argc, const uint8_t *tagp, int pktlen)
178*7c478bd9Sstevel@tonic-gate {
179*7c478bd9Sstevel@tonic-gate 	int ttype;
180*7c478bd9Sstevel@tonic-gate 	int tlen;
181*7c478bd9Sstevel@tonic-gate 	char *str;
182*7c478bd9Sstevel@tonic-gate 	char **oargv = argv;
183*7c478bd9Sstevel@tonic-gate 
184*7c478bd9Sstevel@tonic-gate 	/* Must have room for two strings and NULL terminator. */
185*7c478bd9Sstevel@tonic-gate 	while (argc >= 3) {
186*7c478bd9Sstevel@tonic-gate 		str = NULL;
187*7c478bd9Sstevel@tonic-gate 		while (pktlen >= POET_HDRLEN) {
188*7c478bd9Sstevel@tonic-gate 			ttype = POET_GET_TYPE(tagp);
189*7c478bd9Sstevel@tonic-gate 			if (ttype == POETT_END)
190*7c478bd9Sstevel@tonic-gate 				break;
191*7c478bd9Sstevel@tonic-gate 			tlen = POET_GET_LENG(tagp);
192*7c478bd9Sstevel@tonic-gate 			if (tlen > pktlen - POET_HDRLEN)
193*7c478bd9Sstevel@tonic-gate 				break;
194*7c478bd9Sstevel@tonic-gate 			if (ttype == POETT_HURL || ttype == POETT_MOTM) {
195*7c478bd9Sstevel@tonic-gate 				if ((str = malloc(tlen + 1)) == NULL) {
196*7c478bd9Sstevel@tonic-gate 					error("cannot malloc PPPoE message");
197*7c478bd9Sstevel@tonic-gate 					break;
198*7c478bd9Sstevel@tonic-gate 				}
199*7c478bd9Sstevel@tonic-gate 				(void) memcpy(str, POET_DATA(tagp), tlen);
200*7c478bd9Sstevel@tonic-gate 				str[tlen] = '\0';
201*7c478bd9Sstevel@tonic-gate 			}
202*7c478bd9Sstevel@tonic-gate 			pktlen -= POET_HDRLEN + tlen;
203*7c478bd9Sstevel@tonic-gate 			tagp += POET_HDRLEN + tlen;
204*7c478bd9Sstevel@tonic-gate 			if (str != NULL)
205*7c478bd9Sstevel@tonic-gate 				break;
206*7c478bd9Sstevel@tonic-gate 		}
207*7c478bd9Sstevel@tonic-gate 		if (str == NULL)
208*7c478bd9Sstevel@tonic-gate 			break;
209*7c478bd9Sstevel@tonic-gate 		*argv++ = ttype == POETT_HURL ? "hurl" : "motm";
210*7c478bd9Sstevel@tonic-gate 		*argv++ = str;
211*7c478bd9Sstevel@tonic-gate 		argc -= 2;
212*7c478bd9Sstevel@tonic-gate 	}
213*7c478bd9Sstevel@tonic-gate 	*argv = NULL;
214*7c478bd9Sstevel@tonic-gate 	cat_save_env(oargv, 'h', "HURL");
215*7c478bd9Sstevel@tonic-gate 	cat_save_env(oargv, 'm', "MOTM");
216*7c478bd9Sstevel@tonic-gate }
217*7c478bd9Sstevel@tonic-gate 
218*7c478bd9Sstevel@tonic-gate /*
219*7c478bd9Sstevel@tonic-gate  * Convert IP Route Add structures into environment variables and
220*7c478bd9Sstevel@tonic-gate  * command-line arguments for script.
221*7c478bd9Sstevel@tonic-gate  */
222*7c478bd9Sstevel@tonic-gate static void
223*7c478bd9Sstevel@tonic-gate handle_ip_route_add(char **argv, int argc, const uint8_t *tagp, int pktlen)
224*7c478bd9Sstevel@tonic-gate {
225*7c478bd9Sstevel@tonic-gate 	int ttype;
226*7c478bd9Sstevel@tonic-gate 	int tlen;
227*7c478bd9Sstevel@tonic-gate 	char *str;
228*7c478bd9Sstevel@tonic-gate 	poer_t poer;
229*7c478bd9Sstevel@tonic-gate 	int idx;
230*7c478bd9Sstevel@tonic-gate 	char envname[sizeof (RTE_STR) + 10];
231*7c478bd9Sstevel@tonic-gate 
232*7c478bd9Sstevel@tonic-gate 	idx = 0;
233*7c478bd9Sstevel@tonic-gate 
234*7c478bd9Sstevel@tonic-gate 	/* Must have room for four strings and NULL terminator. */
235*7c478bd9Sstevel@tonic-gate 	while (argc >= 5) {
236*7c478bd9Sstevel@tonic-gate 		str = NULL;
237*7c478bd9Sstevel@tonic-gate 		while (pktlen >= POET_HDRLEN) {
238*7c478bd9Sstevel@tonic-gate 			ttype = POET_GET_TYPE(tagp);
239*7c478bd9Sstevel@tonic-gate 			if (ttype == POETT_END)
240*7c478bd9Sstevel@tonic-gate 				break;
241*7c478bd9Sstevel@tonic-gate 			tlen = POET_GET_LENG(tagp);
242*7c478bd9Sstevel@tonic-gate 			if (tlen > pktlen - POET_HDRLEN)
243*7c478bd9Sstevel@tonic-gate 				break;
244*7c478bd9Sstevel@tonic-gate 			if (ttype == POETT_RTEADD && tlen >= sizeof (poer) &&
245*7c478bd9Sstevel@tonic-gate 			    (str = malloc(RTE_MSG_LEN)) == NULL) {
246*7c478bd9Sstevel@tonic-gate 				error("cannot malloc PPPoE route");
247*7c478bd9Sstevel@tonic-gate 				break;
248*7c478bd9Sstevel@tonic-gate 			}
249*7c478bd9Sstevel@tonic-gate 			pktlen -= POET_HDRLEN + tlen;
250*7c478bd9Sstevel@tonic-gate 			tagp += POET_HDRLEN + tlen;
251*7c478bd9Sstevel@tonic-gate 			if (str != NULL)
252*7c478bd9Sstevel@tonic-gate 				break;
253*7c478bd9Sstevel@tonic-gate 		}
254*7c478bd9Sstevel@tonic-gate 		if (str == NULL)
255*7c478bd9Sstevel@tonic-gate 			break;
256*7c478bd9Sstevel@tonic-gate 		/* No alignment restrictions on source; copy to local. */
257*7c478bd9Sstevel@tonic-gate 		(void) memcpy(&poer, POET_DATA(tagp), sizeof (poer));
258*7c478bd9Sstevel@tonic-gate 		(void) slprintf(str, RTE_MSG_LEN, "%I %I %I %d",
259*7c478bd9Sstevel@tonic-gate 		    poer.poer_dest_network, poer.poer_subnet_mask,
260*7c478bd9Sstevel@tonic-gate 		    poer.poer_gateway, (int)poer.poer_metric);
261*7c478bd9Sstevel@tonic-gate 		/* Save off the environment variable version of this. */
262*7c478bd9Sstevel@tonic-gate 		(void) slprintf(envname, sizeof (envname), RTE_STR, ++idx);
263*7c478bd9Sstevel@tonic-gate 		script_setenv(envname, str, 0);
264*7c478bd9Sstevel@tonic-gate 		*argv++ = str;	/* Destination */
265*7c478bd9Sstevel@tonic-gate 		str = strchr(str, ' ');
266*7c478bd9Sstevel@tonic-gate 		*str++ = '\0';
267*7c478bd9Sstevel@tonic-gate 		*argv++ = str;	/* Subnet mask */
268*7c478bd9Sstevel@tonic-gate 		str = strchr(str, ' ');
269*7c478bd9Sstevel@tonic-gate 		*str++ = '\0';
270*7c478bd9Sstevel@tonic-gate 		*argv++ = str;	/* Gateway */
271*7c478bd9Sstevel@tonic-gate 		str = strchr(str, ' ');
272*7c478bd9Sstevel@tonic-gate 		*str++ = '\0';
273*7c478bd9Sstevel@tonic-gate 		*argv++ = str;	/* Metric */
274*7c478bd9Sstevel@tonic-gate 		argc -= 4;
275*7c478bd9Sstevel@tonic-gate 	}
276*7c478bd9Sstevel@tonic-gate 	*argv = NULL;
277*7c478bd9Sstevel@tonic-gate }
278*7c478bd9Sstevel@tonic-gate 
279*7c478bd9Sstevel@tonic-gate /*
280*7c478bd9Sstevel@tonic-gate  * If we get here, then the driver has already validated the sender,
281*7c478bd9Sstevel@tonic-gate  * the PPPoE version, the message length, and session ID.  The code
282*7c478bd9Sstevel@tonic-gate  * number is known not to be zero.
283*7c478bd9Sstevel@tonic-gate  */
284*7c478bd9Sstevel@tonic-gate static int
285*7c478bd9Sstevel@tonic-gate handle_pppoe_input(const ppptun_atype *pma, struct strbuf *ctrl,
286*7c478bd9Sstevel@tonic-gate     struct strbuf *data)
287*7c478bd9Sstevel@tonic-gate {
288*7c478bd9Sstevel@tonic-gate 	const poep_t *poep;
289*7c478bd9Sstevel@tonic-gate 	struct ppp_ls *plp;
290*7c478bd9Sstevel@tonic-gate 	const char *mname;
291*7c478bd9Sstevel@tonic-gate 	const char *cstr;
292*7c478bd9Sstevel@tonic-gate 	char *str;
293*7c478bd9Sstevel@tonic-gate 	char *cp;
294*7c478bd9Sstevel@tonic-gate 	char *argv[64];
295*7c478bd9Sstevel@tonic-gate 	pid_t rpid;
296*7c478bd9Sstevel@tonic-gate 	char **argp;
297*7c478bd9Sstevel@tonic-gate 	int idx;
298*7c478bd9Sstevel@tonic-gate 	char envname[sizeof (RTE_STR) + 10];
299*7c478bd9Sstevel@tonic-gate 	const uint8_t *tagp;
300*7c478bd9Sstevel@tonic-gate 	int pktlen;
301*7c478bd9Sstevel@tonic-gate 
302*7c478bd9Sstevel@tonic-gate 	/*
303*7c478bd9Sstevel@tonic-gate 	 * Warning: the data->buf pointer here is not necessarily properly
304*7c478bd9Sstevel@tonic-gate 	 * aligned for access to the poep_session_id or poep_length members.
305*7c478bd9Sstevel@tonic-gate 	 */
306*7c478bd9Sstevel@tonic-gate 	/* LINTED: alignment */
307*7c478bd9Sstevel@tonic-gate 	poep = (const poep_t *)data->buf;
308*7c478bd9Sstevel@tonic-gate 	tagp = (const uint8_t *)poep + offsetof(poep_t, poep_length);
309*7c478bd9Sstevel@tonic-gate 	pktlen = (tagp[0] << 8) + tagp[1];
310*7c478bd9Sstevel@tonic-gate 	tagp = (const uint8_t *)(poep + 1);
311*7c478bd9Sstevel@tonic-gate 	switch (poep->poep_code) {
312*7c478bd9Sstevel@tonic-gate 	case POECODE_PADT:
313*7c478bd9Sstevel@tonic-gate 		dbglog("received PPPoE PADT; connection has been closed");
314*7c478bd9Sstevel@tonic-gate 		/* LINTED: alignment */
315*7c478bd9Sstevel@tonic-gate 		plp = (struct ppp_ls *)ctrl->buf;
316*7c478bd9Sstevel@tonic-gate 		plp->magic = PPPLSMAGIC;
317*7c478bd9Sstevel@tonic-gate 		plp->ppp_message = PPP_LINKSTAT_HANGUP;
318*7c478bd9Sstevel@tonic-gate 		ctrl->len = sizeof (*plp);
319*7c478bd9Sstevel@tonic-gate 		return (0);
320*7c478bd9Sstevel@tonic-gate 
321*7c478bd9Sstevel@tonic-gate 		/* Active Discovery Message and Network extensions */
322*7c478bd9Sstevel@tonic-gate 	case POECODE_PADM:
323*7c478bd9Sstevel@tonic-gate 	case POECODE_PADN:
324*7c478bd9Sstevel@tonic-gate 		if (poep->poep_code == POECODE_PADM) {
325*7c478bd9Sstevel@tonic-gate 			argv[0] = _ROOT_PATH "/etc/ppp/pppoe-msg";
326*7c478bd9Sstevel@tonic-gate 			mname = "PADM";
327*7c478bd9Sstevel@tonic-gate 			handle_motm_hurl(argv + 4, Dim(argv) - 4, tagp, pktlen);
328*7c478bd9Sstevel@tonic-gate 		} else {
329*7c478bd9Sstevel@tonic-gate 			argv[0] = _ROOT_PATH "/etc/ppp/pppoe-network";
330*7c478bd9Sstevel@tonic-gate 			mname = "PADN";
331*7c478bd9Sstevel@tonic-gate 			handle_ip_route_add(argv + 4, Dim(argv) - 4, tagp,
332*7c478bd9Sstevel@tonic-gate 			    pktlen);
333*7c478bd9Sstevel@tonic-gate 		}
334*7c478bd9Sstevel@tonic-gate 		argv[1] = ifname;
335*7c478bd9Sstevel@tonic-gate 		/* Note: strdup doesn't handle NULL input. */
336*7c478bd9Sstevel@tonic-gate 		str = NULL;
337*7c478bd9Sstevel@tonic-gate 		if ((cstr = script_getenv("IF_AND_SERVICE")) == NULL ||
338*7c478bd9Sstevel@tonic-gate 		    (str = strdup(cstr)) == NULL) {
339*7c478bd9Sstevel@tonic-gate 			argv[2] = argv[3] = "";
340*7c478bd9Sstevel@tonic-gate 		} else {
341*7c478bd9Sstevel@tonic-gate 			if ((cp = strrchr(str, ':')) == NULL)
342*7c478bd9Sstevel@tonic-gate 				cp = str + strlen(str);
343*7c478bd9Sstevel@tonic-gate 			else
344*7c478bd9Sstevel@tonic-gate 				*cp++ = '\0';
345*7c478bd9Sstevel@tonic-gate 			argv[2] = str;
346*7c478bd9Sstevel@tonic-gate 			argv[3] = cp;
347*7c478bd9Sstevel@tonic-gate 		}
348*7c478bd9Sstevel@tonic-gate 		rpid = run_program(argv[0], argv, 0, NULL, NULL);
349*7c478bd9Sstevel@tonic-gate 		if (rpid == (pid_t)0)
350*7c478bd9Sstevel@tonic-gate 			dbglog("ignored PPPoE %s; no %s script", mname,
351*7c478bd9Sstevel@tonic-gate 			    argv[0]);
352*7c478bd9Sstevel@tonic-gate 		else if (rpid != (pid_t)-1)
353*7c478bd9Sstevel@tonic-gate 			dbglog("PPPoE %s: started PID %d", mname, rpid);
354*7c478bd9Sstevel@tonic-gate 		if (str != NULL)
355*7c478bd9Sstevel@tonic-gate 			free(str);
356*7c478bd9Sstevel@tonic-gate 		/* Free storage allocated by handle_{motm_hurl,ip_route_add} */
357*7c478bd9Sstevel@tonic-gate 		idx = 0;
358*7c478bd9Sstevel@tonic-gate 		for (argp = argv + 4; *argp != NULL; ) {
359*7c478bd9Sstevel@tonic-gate 			if (poep->poep_code == POECODE_PADM) {
360*7c478bd9Sstevel@tonic-gate 				free(argp[1]);
361*7c478bd9Sstevel@tonic-gate 				argp += 2;
362*7c478bd9Sstevel@tonic-gate 			} else {
363*7c478bd9Sstevel@tonic-gate 				free(argp[0]);
364*7c478bd9Sstevel@tonic-gate 				argp += 4;
365*7c478bd9Sstevel@tonic-gate 				(void) slprintf(envname, sizeof (envname),
366*7c478bd9Sstevel@tonic-gate 				    RTE_STR, ++idx);
367*7c478bd9Sstevel@tonic-gate 				script_unsetenv(envname);
368*7c478bd9Sstevel@tonic-gate 			}
369*7c478bd9Sstevel@tonic-gate 		}
370*7c478bd9Sstevel@tonic-gate 		if (poep->poep_code == POECODE_PADM) {
371*7c478bd9Sstevel@tonic-gate 			script_unsetenv("HURL");
372*7c478bd9Sstevel@tonic-gate 			script_unsetenv("MOTM");
373*7c478bd9Sstevel@tonic-gate 		}
374*7c478bd9Sstevel@tonic-gate 		break;
375*7c478bd9Sstevel@tonic-gate 
376*7c478bd9Sstevel@tonic-gate 	default:
377*7c478bd9Sstevel@tonic-gate 		warn("unexpected PPPoE code %d from %s", poep->poep_code,
378*7c478bd9Sstevel@tonic-gate 		    ether_ntoa(&pma->pta_pppoe.ptma_mac_ether_addr));
379*7c478bd9Sstevel@tonic-gate 		break;
380*7c478bd9Sstevel@tonic-gate 	}
381*7c478bd9Sstevel@tonic-gate 	return (-1);
382*7c478bd9Sstevel@tonic-gate }
383*7c478bd9Sstevel@tonic-gate 
384*7c478bd9Sstevel@tonic-gate /*
385*7c478bd9Sstevel@tonic-gate  * sys-solaris has just read in a packet; grovel through it and see if
386*7c478bd9Sstevel@tonic-gate  * it's something we need to handle ourselves.
387*7c478bd9Sstevel@tonic-gate  */
388*7c478bd9Sstevel@tonic-gate static int
389*7c478bd9Sstevel@tonic-gate pppoe_sys_read_packet(int retv, struct strbuf *ctrl, struct strbuf *data,
390*7c478bd9Sstevel@tonic-gate     int flags)
391*7c478bd9Sstevel@tonic-gate {
392*7c478bd9Sstevel@tonic-gate 	struct ppptun_control *ptc;
393*7c478bd9Sstevel@tonic-gate 
394*7c478bd9Sstevel@tonic-gate 	if (retv >= 0 && !(retv & MORECTL) && ctrl->len >= sizeof (uint32_t)) {
395*7c478bd9Sstevel@tonic-gate 		/* LINTED: alignment */
396*7c478bd9Sstevel@tonic-gate 		ptc = (struct ppptun_control *)ctrl->buf;
397*7c478bd9Sstevel@tonic-gate 		/* ptc_discrim is the first uint32_t of the structure. */
398*7c478bd9Sstevel@tonic-gate 		if (ptc->ptc_discrim == PPPOE_DISCRIM) {
399*7c478bd9Sstevel@tonic-gate 			retv = -1;
400*7c478bd9Sstevel@tonic-gate 			if (ctrl->len == sizeof (*ptc) &&
401*7c478bd9Sstevel@tonic-gate 			    ptc->ptc_action == PTCA_CONTROL)
402*7c478bd9Sstevel@tonic-gate 				retv = handle_pppoe_input(&ptc->ptc_address,
403*7c478bd9Sstevel@tonic-gate 				    ctrl, data);
404*7c478bd9Sstevel@tonic-gate 			if (retv < 0)
405*7c478bd9Sstevel@tonic-gate 				errno = EAGAIN;
406*7c478bd9Sstevel@tonic-gate 			return (retv);
407*7c478bd9Sstevel@tonic-gate 		}
408*7c478bd9Sstevel@tonic-gate 	}
409*7c478bd9Sstevel@tonic-gate 	/* Forward along to other plug-ins */
410*7c478bd9Sstevel@tonic-gate 	if (old_sys_read_packet != NULL &&
411*7c478bd9Sstevel@tonic-gate 	    old_sys_read_packet != pppoe_sys_read_packet)
412*7c478bd9Sstevel@tonic-gate 		return ((*old_sys_read_packet)(retv, ctrl, data, flags));
413*7c478bd9Sstevel@tonic-gate 	return (retv);
414*7c478bd9Sstevel@tonic-gate }
415*7c478bd9Sstevel@tonic-gate 
416*7c478bd9Sstevel@tonic-gate /*
417*7c478bd9Sstevel@tonic-gate  * Get an environment variable from the chat script.
418*7c478bd9Sstevel@tonic-gate  */
419*7c478bd9Sstevel@tonic-gate static int
420*7c478bd9Sstevel@tonic-gate saveenv(FILE *fd, const char *envname)
421*7c478bd9Sstevel@tonic-gate {
422*7c478bd9Sstevel@tonic-gate 	char envstr[1024];
423*7c478bd9Sstevel@tonic-gate 	int len;
424*7c478bd9Sstevel@tonic-gate 
425*7c478bd9Sstevel@tonic-gate 	if (fgets(envstr, sizeof (envstr), fd) == NULL)
426*7c478bd9Sstevel@tonic-gate 		return (-1);
427*7c478bd9Sstevel@tonic-gate 	len = strlen(envstr);
428*7c478bd9Sstevel@tonic-gate 	if (len <= 1)
429*7c478bd9Sstevel@tonic-gate 		return (0);
430*7c478bd9Sstevel@tonic-gate 	envstr[len-1] = '\0';
431*7c478bd9Sstevel@tonic-gate 	script_setenv(envname, envstr, 0);
432*7c478bd9Sstevel@tonic-gate 	return (1);
433*7c478bd9Sstevel@tonic-gate }
434*7c478bd9Sstevel@tonic-gate 
435*7c478bd9Sstevel@tonic-gate /*
436*7c478bd9Sstevel@tonic-gate  * Read environment variables exported by chat script.
437*7c478bd9Sstevel@tonic-gate  */
438*7c478bd9Sstevel@tonic-gate static void
439*7c478bd9Sstevel@tonic-gate pppoe_device_pipe(int pipefd)
440*7c478bd9Sstevel@tonic-gate {
441*7c478bd9Sstevel@tonic-gate 	FILE *fd;
442*7c478bd9Sstevel@tonic-gate 	int i;
443*7c478bd9Sstevel@tonic-gate 	char envname[32];
444*7c478bd9Sstevel@tonic-gate 
445*7c478bd9Sstevel@tonic-gate 	fd = fdopen(pipefd, "r");
446*7c478bd9Sstevel@tonic-gate 	if (fd == NULL)
447*7c478bd9Sstevel@tonic-gate 		fatal("unable to open environment file: %m");
448*7c478bd9Sstevel@tonic-gate 	(void) saveenv(fd, "IF_AND_SERVICE");
449*7c478bd9Sstevel@tonic-gate 	(void) saveenv(fd, "SERVICE_NAME");
450*7c478bd9Sstevel@tonic-gate 	(void) saveenv(fd, "AC_NAME");
451*7c478bd9Sstevel@tonic-gate 	(void) saveenv(fd, "AC_MAC");
452*7c478bd9Sstevel@tonic-gate 	(void) saveenv(fd, "SESSION_ID");
453*7c478bd9Sstevel@tonic-gate 	for (i = 1; ; i++) {
454*7c478bd9Sstevel@tonic-gate 		slprintf(envname, sizeof (envname), "VENDOR_SPECIFIC_%d", i);
455*7c478bd9Sstevel@tonic-gate 		if (saveenv(fd, envname) <= 0)
456*7c478bd9Sstevel@tonic-gate 			break;
457*7c478bd9Sstevel@tonic-gate 	}
458*7c478bd9Sstevel@tonic-gate 	(void) fclose(fd);
459*7c478bd9Sstevel@tonic-gate }
460*7c478bd9Sstevel@tonic-gate 
461*7c478bd9Sstevel@tonic-gate void
462*7c478bd9Sstevel@tonic-gate plugin_init(void)
463*7c478bd9Sstevel@tonic-gate {
464*7c478bd9Sstevel@tonic-gate 	if (absmax_mtu > 1492)
465*7c478bd9Sstevel@tonic-gate 		absmax_mtu = 1492;
466*7c478bd9Sstevel@tonic-gate 	if (absmax_mru > 1492)
467*7c478bd9Sstevel@tonic-gate 		absmax_mru = 1492;
468*7c478bd9Sstevel@tonic-gate 	old_check_options = check_options_hook;
469*7c478bd9Sstevel@tonic-gate 	check_options_hook = pppoe_check_options;
470*7c478bd9Sstevel@tonic-gate 	old_updown_script = updown_script_hook;
471*7c478bd9Sstevel@tonic-gate 	updown_script_hook = pppoe_updown_script;
472*7c478bd9Sstevel@tonic-gate 	old_sys_read_packet = sys_read_packet_hook;
473*7c478bd9Sstevel@tonic-gate 	sys_read_packet_hook = pppoe_sys_read_packet;
474*7c478bd9Sstevel@tonic-gate 	device_pipe_hook = pppoe_device_pipe;
475*7c478bd9Sstevel@tonic-gate 	already_ppp = 1;
476*7c478bd9Sstevel@tonic-gate }
477