17c478bd9Sstevel@tonic-gate /*
2dc632b73SJames Carlson * CDDL HEADER START
3dc632b73SJames Carlson *
4dc632b73SJames Carlson * The contents of this file are subject to the terms of the
5dc632b73SJames Carlson * Common Development and Distribution License (the "License").
6dc632b73SJames Carlson * You may not use this file except in compliance with the License.
7dc632b73SJames Carlson *
8dc632b73SJames Carlson * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9dc632b73SJames Carlson * or http://www.opensolaris.org/os/licensing.
10dc632b73SJames Carlson * See the License for the specific language governing permissions
11dc632b73SJames Carlson * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
13dc632b73SJames Carlson * When distributing Covered Code, include this CDDL HEADER in each
14dc632b73SJames Carlson * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15dc632b73SJames Carlson * If applicable, add the following below this CDDL HEADER, with the
16dc632b73SJames Carlson * fields enclosed by brackets "[]" replaced with your own identifying
17dc632b73SJames Carlson * information: Portions Copyright [yyyy] [name of copyright owner]
18dc632b73SJames Carlson *
19dc632b73SJames Carlson * CDDL HEADER END
20dc632b73SJames Carlson */
21dc632b73SJames Carlson
22dc632b73SJames Carlson /*
23*0b4fd3b1SSurya Prakki * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
247c478bd9Sstevel@tonic-gate * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate */
267c478bd9Sstevel@tonic-gate
27dc632b73SJames Carlson /*
28dc632b73SJames Carlson * pppoe.c - pppd plugin to handle PPPoE operation.
29dc632b73SJames Carlson */
30dc632b73SJames Carlson
317c478bd9Sstevel@tonic-gate #include <unistd.h>
327c478bd9Sstevel@tonic-gate #include <stddef.h>
337c478bd9Sstevel@tonic-gate #include <stdlib.h>
347c478bd9Sstevel@tonic-gate #include <errno.h>
357c478bd9Sstevel@tonic-gate #include <sys/types.h>
367c478bd9Sstevel@tonic-gate #include <fcntl.h>
377c478bd9Sstevel@tonic-gate #include <strings.h>
387c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
397c478bd9Sstevel@tonic-gate #include <netinet/in.h>
407c478bd9Sstevel@tonic-gate #include <net/pppio.h>
417c478bd9Sstevel@tonic-gate #include <net/sppptun.h>
427c478bd9Sstevel@tonic-gate #include <net/pppoe.h>
437c478bd9Sstevel@tonic-gate
447c478bd9Sstevel@tonic-gate #include "pppd.h"
457c478bd9Sstevel@tonic-gate #include "pathnames.h"
467c478bd9Sstevel@tonic-gate
477c478bd9Sstevel@tonic-gate /* Saved hook pointers */
487c478bd9Sstevel@tonic-gate static int (*old_check_options)(uid_t uid);
497c478bd9Sstevel@tonic-gate static int (*old_updown_script)(const char ***argsp);
507c478bd9Sstevel@tonic-gate static int (*old_sys_read_packet)(int retv, struct strbuf *ctrl,
517c478bd9Sstevel@tonic-gate struct strbuf *data, int flags);
527c478bd9Sstevel@tonic-gate
537c478bd9Sstevel@tonic-gate /* Room for 3 IPv4 addresses and metric */
547c478bd9Sstevel@tonic-gate #define RTE_MSG_LEN (3*16 + 10 + 1)
557c478bd9Sstevel@tonic-gate
567c478bd9Sstevel@tonic-gate /* Environment string for routes */
577c478bd9Sstevel@tonic-gate #define RTE_STR "ROUTE_%d"
587c478bd9Sstevel@tonic-gate
597c478bd9Sstevel@tonic-gate /*
607c478bd9Sstevel@tonic-gate * strioctl()
617c478bd9Sstevel@tonic-gate *
627c478bd9Sstevel@tonic-gate * wrapper for STREAMS I_STR ioctl.
637c478bd9Sstevel@tonic-gate */
647c478bd9Sstevel@tonic-gate static int
strioctl(int fd,int cmd,void * ptr,int ilen,int olen)657c478bd9Sstevel@tonic-gate strioctl(int fd, int cmd, void *ptr, int ilen, int olen)
667c478bd9Sstevel@tonic-gate {
677c478bd9Sstevel@tonic-gate struct strioctl str;
687c478bd9Sstevel@tonic-gate
697c478bd9Sstevel@tonic-gate str.ic_cmd = cmd;
707c478bd9Sstevel@tonic-gate str.ic_timout = 0; /* Use default timer; 15 seconds */
717c478bd9Sstevel@tonic-gate str.ic_len = ilen;
727c478bd9Sstevel@tonic-gate str.ic_dp = ptr;
737c478bd9Sstevel@tonic-gate
747c478bd9Sstevel@tonic-gate if (ioctl(fd, I_STR, &str) == -1) {
757c478bd9Sstevel@tonic-gate return (-1);
767c478bd9Sstevel@tonic-gate }
777c478bd9Sstevel@tonic-gate if (str.ic_len != olen) {
787c478bd9Sstevel@tonic-gate return (-1);
797c478bd9Sstevel@tonic-gate }
807c478bd9Sstevel@tonic-gate return (0);
817c478bd9Sstevel@tonic-gate }
827c478bd9Sstevel@tonic-gate
837c478bd9Sstevel@tonic-gate /*
847c478bd9Sstevel@tonic-gate * If the user named the tunneling device, check that it is
857c478bd9Sstevel@tonic-gate * reasonable; otherwise check that standard input is the tunnel.
867c478bd9Sstevel@tonic-gate */
877c478bd9Sstevel@tonic-gate static int
pppoe_check_options(uid_t uid)887c478bd9Sstevel@tonic-gate pppoe_check_options(uid_t uid)
897c478bd9Sstevel@tonic-gate {
907c478bd9Sstevel@tonic-gate int tstfd; /* fd for device being checked */
917c478bd9Sstevel@tonic-gate int err; /* saved errno value */
927c478bd9Sstevel@tonic-gate int retv; /* return value */
937c478bd9Sstevel@tonic-gate int intv; /* integer return value (from ioctl) */
947c478bd9Sstevel@tonic-gate union ppptun_name ptn;
957c478bd9Sstevel@tonic-gate
967c478bd9Sstevel@tonic-gate if (devnam[0] != '\0') {
977c478bd9Sstevel@tonic-gate /*
987c478bd9Sstevel@tonic-gate * Open as real user so that modes on device can be
997c478bd9Sstevel@tonic-gate * used to limit access.
1007c478bd9Sstevel@tonic-gate */
1017c478bd9Sstevel@tonic-gate if (!devnam_info.priv)
1027c478bd9Sstevel@tonic-gate (void) seteuid(uid);
1037c478bd9Sstevel@tonic-gate tstfd = open(devnam, O_NONBLOCK | O_RDWR, 0);
1047c478bd9Sstevel@tonic-gate err = errno;
1057c478bd9Sstevel@tonic-gate if (!devnam_info.priv)
1067c478bd9Sstevel@tonic-gate (void) seteuid(0);
1077c478bd9Sstevel@tonic-gate if (tstfd == -1) {
1087c478bd9Sstevel@tonic-gate errno = err;
1097c478bd9Sstevel@tonic-gate option_error("unable to open %s: %m", devnam);
1107c478bd9Sstevel@tonic-gate return (-1);
1117c478bd9Sstevel@tonic-gate }
1127c478bd9Sstevel@tonic-gate retv = strioctl(tstfd, PPPTUN_GDATA, &ptn, 0, sizeof (ptn));
1137c478bd9Sstevel@tonic-gate (void) close(tstfd);
1147c478bd9Sstevel@tonic-gate if (retv == -1) {
1157c478bd9Sstevel@tonic-gate option_error("device %s is not a PPP tunneling device",
1167c478bd9Sstevel@tonic-gate devnam);
1177c478bd9Sstevel@tonic-gate return (-1);
1187c478bd9Sstevel@tonic-gate }
1197c478bd9Sstevel@tonic-gate } else {
1207c478bd9Sstevel@tonic-gate retv = strioctl(0, PPPIO_GTYPE, &intv, 0, sizeof (intv));
1217c478bd9Sstevel@tonic-gate if (retv == -1) {
1227c478bd9Sstevel@tonic-gate option_error("standard input is not a PPP device");
1237c478bd9Sstevel@tonic-gate return (-1);
1247c478bd9Sstevel@tonic-gate }
1257c478bd9Sstevel@tonic-gate retv = strioctl(0, PPPTUN_GDATA, &ptn, 0, sizeof (ptn));
1267c478bd9Sstevel@tonic-gate if (retv == -1) {
1277c478bd9Sstevel@tonic-gate option_error("standard input is not a PPP tunnel");
1287c478bd9Sstevel@tonic-gate return (-1);
1297c478bd9Sstevel@tonic-gate }
1307c478bd9Sstevel@tonic-gate if (strcmp(ptn.ptn_name + strlen(ptn.ptn_name) - 6,
1317c478bd9Sstevel@tonic-gate ":pppoe") != 0) {
1327c478bd9Sstevel@tonic-gate option_error("standard input not connected to PPPoE");
1337c478bd9Sstevel@tonic-gate return (-1);
1347c478bd9Sstevel@tonic-gate }
1357c478bd9Sstevel@tonic-gate }
1367c478bd9Sstevel@tonic-gate if (old_check_options != NULL &&
1377c478bd9Sstevel@tonic-gate old_check_options != pppoe_check_options)
1387c478bd9Sstevel@tonic-gate return ((*old_check_options)(uid));
1397c478bd9Sstevel@tonic-gate return (0);
1407c478bd9Sstevel@tonic-gate }
1417c478bd9Sstevel@tonic-gate
1427c478bd9Sstevel@tonic-gate /*
1437c478bd9Sstevel@tonic-gate * When we're about to call one of the up or down scripts, change the
1447c478bd9Sstevel@tonic-gate * second argument to contain the interface name and selected PPPoE
1457c478bd9Sstevel@tonic-gate * service.
1467c478bd9Sstevel@tonic-gate */
1477c478bd9Sstevel@tonic-gate static int
pppoe_updown_script(const char *** argsp)1487c478bd9Sstevel@tonic-gate pppoe_updown_script(const char ***argsp)
1497c478bd9Sstevel@tonic-gate {
1507c478bd9Sstevel@tonic-gate const char *cp;
1517c478bd9Sstevel@tonic-gate
1527c478bd9Sstevel@tonic-gate if ((*argsp)[2] == devnam &&
1537c478bd9Sstevel@tonic-gate (cp = script_getenv("IF_AND_SERVICE")) != NULL)
1547c478bd9Sstevel@tonic-gate (*argsp)[2] = cp;
1557c478bd9Sstevel@tonic-gate if (old_updown_script != NULL &&
1567c478bd9Sstevel@tonic-gate old_updown_script != pppoe_updown_script)
1577c478bd9Sstevel@tonic-gate return ((*old_updown_script)(argsp));
1587c478bd9Sstevel@tonic-gate return (0);
1597c478bd9Sstevel@tonic-gate }
1607c478bd9Sstevel@tonic-gate
1617c478bd9Sstevel@tonic-gate /*
1627c478bd9Sstevel@tonic-gate * Concatenate and save strings from command line into environment
1637c478bd9Sstevel@tonic-gate * variable.
1647c478bd9Sstevel@tonic-gate */
1657c478bd9Sstevel@tonic-gate static void
cat_save_env(char ** argv,char idchar,const char * envname)1667c478bd9Sstevel@tonic-gate cat_save_env(char **argv, char idchar, const char *envname)
1677c478bd9Sstevel@tonic-gate {
1687c478bd9Sstevel@tonic-gate char **argp;
1697c478bd9Sstevel@tonic-gate int totlen;
1707c478bd9Sstevel@tonic-gate char *str;
1717c478bd9Sstevel@tonic-gate char *cp;
1727c478bd9Sstevel@tonic-gate
1737c478bd9Sstevel@tonic-gate totlen = 0;
1747c478bd9Sstevel@tonic-gate for (argp = argv; argp[0] != NULL; argp += 2)
1757c478bd9Sstevel@tonic-gate if (*argp[0] == idchar)
1767c478bd9Sstevel@tonic-gate totlen += strlen(argp[1]) + 1;
1777c478bd9Sstevel@tonic-gate if ((str = malloc(totlen + 1)) == NULL) {
1787c478bd9Sstevel@tonic-gate error("cannot malloc PPPoE environment for %s", envname);
1797c478bd9Sstevel@tonic-gate return;
1807c478bd9Sstevel@tonic-gate }
1817c478bd9Sstevel@tonic-gate cp = str;
1827c478bd9Sstevel@tonic-gate for (argp = argv; argp[0] != NULL; argp += 2)
1837c478bd9Sstevel@tonic-gate if (*argp[0] == idchar) {
1847c478bd9Sstevel@tonic-gate (void) strcpy(cp, argp[1]);
1857c478bd9Sstevel@tonic-gate cp += strlen(cp);
1867c478bd9Sstevel@tonic-gate *cp++ = '\n';
1877c478bd9Sstevel@tonic-gate }
1887c478bd9Sstevel@tonic-gate *cp = '\0';
1897c478bd9Sstevel@tonic-gate script_setenv(envname, str, 0);
1907c478bd9Sstevel@tonic-gate }
1917c478bd9Sstevel@tonic-gate
1927c478bd9Sstevel@tonic-gate /*
1937c478bd9Sstevel@tonic-gate * Convert Message Of The Moment (MOTM) and Host Uniform Resource
1947c478bd9Sstevel@tonic-gate * Locator (HURL) strings into environment variables and command-line
1957c478bd9Sstevel@tonic-gate * arguments for script.
1967c478bd9Sstevel@tonic-gate */
1977c478bd9Sstevel@tonic-gate static void
handle_motm_hurl(char ** argv,int argc,const uint8_t * tagp,int pktlen)1987c478bd9Sstevel@tonic-gate handle_motm_hurl(char **argv, int argc, const uint8_t *tagp, int pktlen)
1997c478bd9Sstevel@tonic-gate {
2007c478bd9Sstevel@tonic-gate int ttype;
2017c478bd9Sstevel@tonic-gate int tlen;
2027c478bd9Sstevel@tonic-gate char *str;
2037c478bd9Sstevel@tonic-gate char **oargv = argv;
2047c478bd9Sstevel@tonic-gate
2057c478bd9Sstevel@tonic-gate /* Must have room for two strings and NULL terminator. */
2067c478bd9Sstevel@tonic-gate while (argc >= 3) {
2077c478bd9Sstevel@tonic-gate str = NULL;
2087c478bd9Sstevel@tonic-gate while (pktlen >= POET_HDRLEN) {
2097c478bd9Sstevel@tonic-gate ttype = POET_GET_TYPE(tagp);
2107c478bd9Sstevel@tonic-gate if (ttype == POETT_END)
2117c478bd9Sstevel@tonic-gate break;
2127c478bd9Sstevel@tonic-gate tlen = POET_GET_LENG(tagp);
2137c478bd9Sstevel@tonic-gate if (tlen > pktlen - POET_HDRLEN)
2147c478bd9Sstevel@tonic-gate break;
2157c478bd9Sstevel@tonic-gate if (ttype == POETT_HURL || ttype == POETT_MOTM) {
2167c478bd9Sstevel@tonic-gate if ((str = malloc(tlen + 1)) == NULL) {
2177c478bd9Sstevel@tonic-gate error("cannot malloc PPPoE message");
2187c478bd9Sstevel@tonic-gate break;
2197c478bd9Sstevel@tonic-gate }
2207c478bd9Sstevel@tonic-gate (void) memcpy(str, POET_DATA(tagp), tlen);
2217c478bd9Sstevel@tonic-gate str[tlen] = '\0';
2227c478bd9Sstevel@tonic-gate }
2237c478bd9Sstevel@tonic-gate pktlen -= POET_HDRLEN + tlen;
2247c478bd9Sstevel@tonic-gate tagp += POET_HDRLEN + tlen;
2257c478bd9Sstevel@tonic-gate if (str != NULL)
2267c478bd9Sstevel@tonic-gate break;
2277c478bd9Sstevel@tonic-gate }
2287c478bd9Sstevel@tonic-gate if (str == NULL)
2297c478bd9Sstevel@tonic-gate break;
2307c478bd9Sstevel@tonic-gate *argv++ = ttype == POETT_HURL ? "hurl" : "motm";
2317c478bd9Sstevel@tonic-gate *argv++ = str;
2327c478bd9Sstevel@tonic-gate argc -= 2;
2337c478bd9Sstevel@tonic-gate }
2347c478bd9Sstevel@tonic-gate *argv = NULL;
2357c478bd9Sstevel@tonic-gate cat_save_env(oargv, 'h', "HURL");
2367c478bd9Sstevel@tonic-gate cat_save_env(oargv, 'm', "MOTM");
2377c478bd9Sstevel@tonic-gate }
2387c478bd9Sstevel@tonic-gate
2397c478bd9Sstevel@tonic-gate /*
2407c478bd9Sstevel@tonic-gate * Convert IP Route Add structures into environment variables and
2417c478bd9Sstevel@tonic-gate * command-line arguments for script.
2427c478bd9Sstevel@tonic-gate */
2437c478bd9Sstevel@tonic-gate static void
handle_ip_route_add(char ** argv,int argc,const uint8_t * tagp,int pktlen)2447c478bd9Sstevel@tonic-gate handle_ip_route_add(char **argv, int argc, const uint8_t *tagp, int pktlen)
2457c478bd9Sstevel@tonic-gate {
2467c478bd9Sstevel@tonic-gate int ttype;
2477c478bd9Sstevel@tonic-gate int tlen;
2487c478bd9Sstevel@tonic-gate char *str;
2497c478bd9Sstevel@tonic-gate poer_t poer;
2507c478bd9Sstevel@tonic-gate int idx;
2517c478bd9Sstevel@tonic-gate char envname[sizeof (RTE_STR) + 10];
2527c478bd9Sstevel@tonic-gate
2537c478bd9Sstevel@tonic-gate idx = 0;
2547c478bd9Sstevel@tonic-gate
2557c478bd9Sstevel@tonic-gate /* Must have room for four strings and NULL terminator. */
2567c478bd9Sstevel@tonic-gate while (argc >= 5) {
2577c478bd9Sstevel@tonic-gate str = NULL;
2587c478bd9Sstevel@tonic-gate while (pktlen >= POET_HDRLEN) {
2597c478bd9Sstevel@tonic-gate ttype = POET_GET_TYPE(tagp);
2607c478bd9Sstevel@tonic-gate if (ttype == POETT_END)
2617c478bd9Sstevel@tonic-gate break;
2627c478bd9Sstevel@tonic-gate tlen = POET_GET_LENG(tagp);
2637c478bd9Sstevel@tonic-gate if (tlen > pktlen - POET_HDRLEN)
2647c478bd9Sstevel@tonic-gate break;
2657c478bd9Sstevel@tonic-gate if (ttype == POETT_RTEADD && tlen >= sizeof (poer) &&
2667c478bd9Sstevel@tonic-gate (str = malloc(RTE_MSG_LEN)) == NULL) {
2677c478bd9Sstevel@tonic-gate error("cannot malloc PPPoE route");
2687c478bd9Sstevel@tonic-gate break;
2697c478bd9Sstevel@tonic-gate }
2707c478bd9Sstevel@tonic-gate pktlen -= POET_HDRLEN + tlen;
2717c478bd9Sstevel@tonic-gate tagp += POET_HDRLEN + tlen;
2727c478bd9Sstevel@tonic-gate if (str != NULL)
2737c478bd9Sstevel@tonic-gate break;
2747c478bd9Sstevel@tonic-gate }
2757c478bd9Sstevel@tonic-gate if (str == NULL)
2767c478bd9Sstevel@tonic-gate break;
2777c478bd9Sstevel@tonic-gate /* No alignment restrictions on source; copy to local. */
2787c478bd9Sstevel@tonic-gate (void) memcpy(&poer, POET_DATA(tagp), sizeof (poer));
2797c478bd9Sstevel@tonic-gate (void) slprintf(str, RTE_MSG_LEN, "%I %I %I %d",
2807c478bd9Sstevel@tonic-gate poer.poer_dest_network, poer.poer_subnet_mask,
2817c478bd9Sstevel@tonic-gate poer.poer_gateway, (int)poer.poer_metric);
2827c478bd9Sstevel@tonic-gate /* Save off the environment variable version of this. */
2837c478bd9Sstevel@tonic-gate (void) slprintf(envname, sizeof (envname), RTE_STR, ++idx);
2847c478bd9Sstevel@tonic-gate script_setenv(envname, str, 0);
2857c478bd9Sstevel@tonic-gate *argv++ = str; /* Destination */
2867c478bd9Sstevel@tonic-gate str = strchr(str, ' ');
2877c478bd9Sstevel@tonic-gate *str++ = '\0';
2887c478bd9Sstevel@tonic-gate *argv++ = str; /* Subnet mask */
2897c478bd9Sstevel@tonic-gate str = strchr(str, ' ');
2907c478bd9Sstevel@tonic-gate *str++ = '\0';
2917c478bd9Sstevel@tonic-gate *argv++ = str; /* Gateway */
2927c478bd9Sstevel@tonic-gate str = strchr(str, ' ');
2937c478bd9Sstevel@tonic-gate *str++ = '\0';
2947c478bd9Sstevel@tonic-gate *argv++ = str; /* Metric */
2957c478bd9Sstevel@tonic-gate argc -= 4;
2967c478bd9Sstevel@tonic-gate }
2977c478bd9Sstevel@tonic-gate *argv = NULL;
2987c478bd9Sstevel@tonic-gate }
2997c478bd9Sstevel@tonic-gate
3007c478bd9Sstevel@tonic-gate /*
3017c478bd9Sstevel@tonic-gate * If we get here, then the driver has already validated the sender,
3027c478bd9Sstevel@tonic-gate * the PPPoE version, the message length, and session ID. The code
3037c478bd9Sstevel@tonic-gate * number is known not to be zero.
3047c478bd9Sstevel@tonic-gate */
3057c478bd9Sstevel@tonic-gate static int
handle_pppoe_input(const ppptun_atype * pma,struct strbuf * ctrl,struct strbuf * data)3067c478bd9Sstevel@tonic-gate handle_pppoe_input(const ppptun_atype *pma, struct strbuf *ctrl,
3077c478bd9Sstevel@tonic-gate struct strbuf *data)
3087c478bd9Sstevel@tonic-gate {
3097c478bd9Sstevel@tonic-gate const poep_t *poep;
3107c478bd9Sstevel@tonic-gate struct ppp_ls *plp;
3117c478bd9Sstevel@tonic-gate const char *mname;
3127c478bd9Sstevel@tonic-gate const char *cstr;
3137c478bd9Sstevel@tonic-gate char *str;
3147c478bd9Sstevel@tonic-gate char *cp;
3157c478bd9Sstevel@tonic-gate char *argv[64];
3167c478bd9Sstevel@tonic-gate pid_t rpid;
3177c478bd9Sstevel@tonic-gate char **argp;
3187c478bd9Sstevel@tonic-gate int idx;
3197c478bd9Sstevel@tonic-gate char envname[sizeof (RTE_STR) + 10];
3207c478bd9Sstevel@tonic-gate const uint8_t *tagp;
3217c478bd9Sstevel@tonic-gate int pktlen;
3227c478bd9Sstevel@tonic-gate
3237c478bd9Sstevel@tonic-gate /*
3247c478bd9Sstevel@tonic-gate * Warning: the data->buf pointer here is not necessarily properly
3257c478bd9Sstevel@tonic-gate * aligned for access to the poep_session_id or poep_length members.
3267c478bd9Sstevel@tonic-gate */
3277c478bd9Sstevel@tonic-gate /* LINTED: alignment */
3287c478bd9Sstevel@tonic-gate poep = (const poep_t *)data->buf;
3297c478bd9Sstevel@tonic-gate tagp = (const uint8_t *)poep + offsetof(poep_t, poep_length);
3307c478bd9Sstevel@tonic-gate pktlen = (tagp[0] << 8) + tagp[1];
3317c478bd9Sstevel@tonic-gate tagp = (const uint8_t *)(poep + 1);
3327c478bd9Sstevel@tonic-gate switch (poep->poep_code) {
3337c478bd9Sstevel@tonic-gate case POECODE_PADT:
3347c478bd9Sstevel@tonic-gate dbglog("received PPPoE PADT; connection has been closed");
3357c478bd9Sstevel@tonic-gate /* LINTED: alignment */
3367c478bd9Sstevel@tonic-gate plp = (struct ppp_ls *)ctrl->buf;
3377c478bd9Sstevel@tonic-gate plp->magic = PPPLSMAGIC;
3387c478bd9Sstevel@tonic-gate plp->ppp_message = PPP_LINKSTAT_HANGUP;
3397c478bd9Sstevel@tonic-gate ctrl->len = sizeof (*plp);
3407c478bd9Sstevel@tonic-gate return (0);
3417c478bd9Sstevel@tonic-gate
3427c478bd9Sstevel@tonic-gate /* Active Discovery Message and Network extensions */
3437c478bd9Sstevel@tonic-gate case POECODE_PADM:
3447c478bd9Sstevel@tonic-gate case POECODE_PADN:
3457c478bd9Sstevel@tonic-gate if (poep->poep_code == POECODE_PADM) {
3467c478bd9Sstevel@tonic-gate argv[0] = _ROOT_PATH "/etc/ppp/pppoe-msg";
3477c478bd9Sstevel@tonic-gate mname = "PADM";
3487c478bd9Sstevel@tonic-gate handle_motm_hurl(argv + 4, Dim(argv) - 4, tagp, pktlen);
3497c478bd9Sstevel@tonic-gate } else {
3507c478bd9Sstevel@tonic-gate argv[0] = _ROOT_PATH "/etc/ppp/pppoe-network";
3517c478bd9Sstevel@tonic-gate mname = "PADN";
3527c478bd9Sstevel@tonic-gate handle_ip_route_add(argv + 4, Dim(argv) - 4, tagp,
3537c478bd9Sstevel@tonic-gate pktlen);
3547c478bd9Sstevel@tonic-gate }
3557c478bd9Sstevel@tonic-gate argv[1] = ifname;
3567c478bd9Sstevel@tonic-gate /* Note: strdup doesn't handle NULL input. */
3577c478bd9Sstevel@tonic-gate str = NULL;
3587c478bd9Sstevel@tonic-gate if ((cstr = script_getenv("IF_AND_SERVICE")) == NULL ||
3597c478bd9Sstevel@tonic-gate (str = strdup(cstr)) == NULL) {
3607c478bd9Sstevel@tonic-gate argv[2] = argv[3] = "";
3617c478bd9Sstevel@tonic-gate } else {
3627c478bd9Sstevel@tonic-gate if ((cp = strrchr(str, ':')) == NULL)
3637c478bd9Sstevel@tonic-gate cp = str + strlen(str);
3647c478bd9Sstevel@tonic-gate else
3657c478bd9Sstevel@tonic-gate *cp++ = '\0';
3667c478bd9Sstevel@tonic-gate argv[2] = str;
3677c478bd9Sstevel@tonic-gate argv[3] = cp;
3687c478bd9Sstevel@tonic-gate }
3697c478bd9Sstevel@tonic-gate rpid = run_program(argv[0], argv, 0, NULL, NULL);
3707c478bd9Sstevel@tonic-gate if (rpid == (pid_t)0)
3717c478bd9Sstevel@tonic-gate dbglog("ignored PPPoE %s; no %s script", mname,
3727c478bd9Sstevel@tonic-gate argv[0]);
3737c478bd9Sstevel@tonic-gate else if (rpid != (pid_t)-1)
3747c478bd9Sstevel@tonic-gate dbglog("PPPoE %s: started PID %d", mname, rpid);
3757c478bd9Sstevel@tonic-gate if (str != NULL)
3767c478bd9Sstevel@tonic-gate free(str);
3777c478bd9Sstevel@tonic-gate /* Free storage allocated by handle_{motm_hurl,ip_route_add} */
3787c478bd9Sstevel@tonic-gate idx = 0;
3797c478bd9Sstevel@tonic-gate for (argp = argv + 4; *argp != NULL; ) {
3807c478bd9Sstevel@tonic-gate if (poep->poep_code == POECODE_PADM) {
3817c478bd9Sstevel@tonic-gate free(argp[1]);
3827c478bd9Sstevel@tonic-gate argp += 2;
3837c478bd9Sstevel@tonic-gate } else {
3847c478bd9Sstevel@tonic-gate free(argp[0]);
3857c478bd9Sstevel@tonic-gate argp += 4;
3867c478bd9Sstevel@tonic-gate (void) slprintf(envname, sizeof (envname),
3877c478bd9Sstevel@tonic-gate RTE_STR, ++idx);
3887c478bd9Sstevel@tonic-gate script_unsetenv(envname);
3897c478bd9Sstevel@tonic-gate }
3907c478bd9Sstevel@tonic-gate }
3917c478bd9Sstevel@tonic-gate if (poep->poep_code == POECODE_PADM) {
3927c478bd9Sstevel@tonic-gate script_unsetenv("HURL");
3937c478bd9Sstevel@tonic-gate script_unsetenv("MOTM");
3947c478bd9Sstevel@tonic-gate }
3957c478bd9Sstevel@tonic-gate break;
3967c478bd9Sstevel@tonic-gate
3977c478bd9Sstevel@tonic-gate default:
3987c478bd9Sstevel@tonic-gate warn("unexpected PPPoE code %d from %s", poep->poep_code,
3997c478bd9Sstevel@tonic-gate ether_ntoa(&pma->pta_pppoe.ptma_mac_ether_addr));
4007c478bd9Sstevel@tonic-gate break;
4017c478bd9Sstevel@tonic-gate }
4027c478bd9Sstevel@tonic-gate return (-1);
4037c478bd9Sstevel@tonic-gate }
4047c478bd9Sstevel@tonic-gate
405f53eecf5SJames Carlson /*
406f53eecf5SJames Carlson * Handle an action code passed up from the driver.
407f53eecf5SJames Carlson */
408f53eecf5SJames Carlson static int
handle_action(struct ppptun_control * ptc,struct strbuf * ctrl,struct strbuf * data)409f53eecf5SJames Carlson handle_action(struct ppptun_control *ptc, struct strbuf *ctrl,
410f53eecf5SJames Carlson struct strbuf *data)
411f53eecf5SJames Carlson {
412f53eecf5SJames Carlson switch (ptc->ptc_action) {
413f53eecf5SJames Carlson case PTCA_CONTROL:
414f53eecf5SJames Carlson return (handle_pppoe_input(&ptc->ptc_address, ctrl, data));
415f53eecf5SJames Carlson
416f53eecf5SJames Carlson case PTCA_BADCTRL:
417f53eecf5SJames Carlson warn("bad control message; session %u on %s", ptc->ptc_rsessid,
418f53eecf5SJames Carlson ptc->ptc_name);
419f53eecf5SJames Carlson return (0);
420f53eecf5SJames Carlson }
421f53eecf5SJames Carlson
422f53eecf5SJames Carlson return (-1);
423f53eecf5SJames Carlson }
424f53eecf5SJames Carlson
4257c478bd9Sstevel@tonic-gate /*
4267c478bd9Sstevel@tonic-gate * sys-solaris has just read in a packet; grovel through it and see if
4277c478bd9Sstevel@tonic-gate * it's something we need to handle ourselves.
4287c478bd9Sstevel@tonic-gate */
4297c478bd9Sstevel@tonic-gate static int
pppoe_sys_read_packet(int retv,struct strbuf * ctrl,struct strbuf * data,int flags)4307c478bd9Sstevel@tonic-gate pppoe_sys_read_packet(int retv, struct strbuf *ctrl, struct strbuf *data,
4317c478bd9Sstevel@tonic-gate int flags)
4327c478bd9Sstevel@tonic-gate {
4337c478bd9Sstevel@tonic-gate struct ppptun_control *ptc;
4347c478bd9Sstevel@tonic-gate
4357c478bd9Sstevel@tonic-gate if (retv >= 0 && !(retv & MORECTL) && ctrl->len >= sizeof (uint32_t)) {
4367c478bd9Sstevel@tonic-gate /* LINTED: alignment */
4377c478bd9Sstevel@tonic-gate ptc = (struct ppptun_control *)ctrl->buf;
4387c478bd9Sstevel@tonic-gate /* ptc_discrim is the first uint32_t of the structure. */
4397c478bd9Sstevel@tonic-gate if (ptc->ptc_discrim == PPPOE_DISCRIM) {
4407c478bd9Sstevel@tonic-gate retv = -1;
441f53eecf5SJames Carlson if (ctrl->len == sizeof (*ptc))
442f53eecf5SJames Carlson retv = handle_action(ptc, ctrl, data);
4437c478bd9Sstevel@tonic-gate if (retv < 0)
4447c478bd9Sstevel@tonic-gate errno = EAGAIN;
4457c478bd9Sstevel@tonic-gate return (retv);
4467c478bd9Sstevel@tonic-gate }
4477c478bd9Sstevel@tonic-gate }
4487c478bd9Sstevel@tonic-gate /* Forward along to other plug-ins */
4497c478bd9Sstevel@tonic-gate if (old_sys_read_packet != NULL &&
4507c478bd9Sstevel@tonic-gate old_sys_read_packet != pppoe_sys_read_packet)
4517c478bd9Sstevel@tonic-gate return ((*old_sys_read_packet)(retv, ctrl, data, flags));
4527c478bd9Sstevel@tonic-gate return (retv);
4537c478bd9Sstevel@tonic-gate }
4547c478bd9Sstevel@tonic-gate
4557c478bd9Sstevel@tonic-gate /*
4567c478bd9Sstevel@tonic-gate * Get an environment variable from the chat script.
4577c478bd9Sstevel@tonic-gate */
4587c478bd9Sstevel@tonic-gate static int
saveenv(FILE * fd,const char * envname)4597c478bd9Sstevel@tonic-gate saveenv(FILE *fd, const char *envname)
4607c478bd9Sstevel@tonic-gate {
4617c478bd9Sstevel@tonic-gate char envstr[1024];
4627c478bd9Sstevel@tonic-gate int len;
4637c478bd9Sstevel@tonic-gate
4647c478bd9Sstevel@tonic-gate if (fgets(envstr, sizeof (envstr), fd) == NULL)
4657c478bd9Sstevel@tonic-gate return (-1);
4667c478bd9Sstevel@tonic-gate len = strlen(envstr);
4677c478bd9Sstevel@tonic-gate if (len <= 1)
4687c478bd9Sstevel@tonic-gate return (0);
4697c478bd9Sstevel@tonic-gate envstr[len-1] = '\0';
4707c478bd9Sstevel@tonic-gate script_setenv(envname, envstr, 0);
4717c478bd9Sstevel@tonic-gate return (1);
4727c478bd9Sstevel@tonic-gate }
4737c478bd9Sstevel@tonic-gate
4747c478bd9Sstevel@tonic-gate /*
4757c478bd9Sstevel@tonic-gate * Read environment variables exported by chat script.
4767c478bd9Sstevel@tonic-gate */
4777c478bd9Sstevel@tonic-gate static void
pppoe_device_pipe(int pipefd)4787c478bd9Sstevel@tonic-gate pppoe_device_pipe(int pipefd)
4797c478bd9Sstevel@tonic-gate {
4807c478bd9Sstevel@tonic-gate FILE *fd;
4817c478bd9Sstevel@tonic-gate int i;
4827c478bd9Sstevel@tonic-gate char envname[32];
4837c478bd9Sstevel@tonic-gate
4847c478bd9Sstevel@tonic-gate fd = fdopen(pipefd, "r");
4857c478bd9Sstevel@tonic-gate if (fd == NULL)
4867c478bd9Sstevel@tonic-gate fatal("unable to open environment file: %m");
4877c478bd9Sstevel@tonic-gate (void) saveenv(fd, "IF_AND_SERVICE");
4887c478bd9Sstevel@tonic-gate (void) saveenv(fd, "SERVICE_NAME");
4897c478bd9Sstevel@tonic-gate (void) saveenv(fd, "AC_NAME");
4907c478bd9Sstevel@tonic-gate (void) saveenv(fd, "AC_MAC");
4917c478bd9Sstevel@tonic-gate (void) saveenv(fd, "SESSION_ID");
4927c478bd9Sstevel@tonic-gate for (i = 1; ; i++) {
493*0b4fd3b1SSurya Prakki (void) slprintf(envname, sizeof (envname),
494*0b4fd3b1SSurya Prakki "VENDOR_SPECIFIC_%d", i);
4957c478bd9Sstevel@tonic-gate if (saveenv(fd, envname) <= 0)
4967c478bd9Sstevel@tonic-gate break;
4977c478bd9Sstevel@tonic-gate }
4987c478bd9Sstevel@tonic-gate (void) fclose(fd);
4997c478bd9Sstevel@tonic-gate }
5007c478bd9Sstevel@tonic-gate
5017c478bd9Sstevel@tonic-gate void
plugin_init(void)5027c478bd9Sstevel@tonic-gate plugin_init(void)
5037c478bd9Sstevel@tonic-gate {
5047c478bd9Sstevel@tonic-gate if (absmax_mtu > 1492)
5057c478bd9Sstevel@tonic-gate absmax_mtu = 1492;
5067c478bd9Sstevel@tonic-gate if (absmax_mru > 1492)
5077c478bd9Sstevel@tonic-gate absmax_mru = 1492;
5087c478bd9Sstevel@tonic-gate old_check_options = check_options_hook;
5097c478bd9Sstevel@tonic-gate check_options_hook = pppoe_check_options;
5107c478bd9Sstevel@tonic-gate old_updown_script = updown_script_hook;
5117c478bd9Sstevel@tonic-gate updown_script_hook = pppoe_updown_script;
5127c478bd9Sstevel@tonic-gate old_sys_read_packet = sys_read_packet_hook;
5137c478bd9Sstevel@tonic-gate sys_read_packet_hook = pppoe_sys_read_packet;
5147c478bd9Sstevel@tonic-gate device_pipe_hook = pppoe_device_pipe;
5157c478bd9Sstevel@tonic-gate already_ppp = 1;
5167c478bd9Sstevel@tonic-gate }
517