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