1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * PPPoE Client-mode "chat" utility for use with Solaris PPP 4.0. 24*7c478bd9Sstevel@tonic-gate * 25*7c478bd9Sstevel@tonic-gate * Copyright 2000-2002 Sun Microsystems, Inc. All rights reserved. 26*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 27*7c478bd9Sstevel@tonic-gate */ 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 30*7c478bd9Sstevel@tonic-gate 31*7c478bd9Sstevel@tonic-gate #include <stdio.h> 32*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 33*7c478bd9Sstevel@tonic-gate #include <unistd.h> 34*7c478bd9Sstevel@tonic-gate #include <ctype.h> 35*7c478bd9Sstevel@tonic-gate #include <strings.h> 36*7c478bd9Sstevel@tonic-gate #include <fcntl.h> 37*7c478bd9Sstevel@tonic-gate #include <errno.h> 38*7c478bd9Sstevel@tonic-gate #include <signal.h> 39*7c478bd9Sstevel@tonic-gate #include <stropts.h> 40*7c478bd9Sstevel@tonic-gate #include <netdb.h> 41*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 42*7c478bd9Sstevel@tonic-gate #include <sys/socket.h> 43*7c478bd9Sstevel@tonic-gate #include <net/if.h> 44*7c478bd9Sstevel@tonic-gate #include <netinet/in.h> 45*7c478bd9Sstevel@tonic-gate #include <netinet/if_ether.h> 46*7c478bd9Sstevel@tonic-gate 47*7c478bd9Sstevel@tonic-gate #include <net/sppptun.h> 48*7c478bd9Sstevel@tonic-gate #include <net/pppoe.h> 49*7c478bd9Sstevel@tonic-gate 50*7c478bd9Sstevel@tonic-gate #include "common.h" 51*7c478bd9Sstevel@tonic-gate #include "logging.h" 52*7c478bd9Sstevel@tonic-gate 53*7c478bd9Sstevel@tonic-gate /* 54*7c478bd9Sstevel@tonic-gate * This value, currently set to the characters "POE1," is used to 55*7c478bd9Sstevel@tonic-gate * distinguish among control messages from multiple lower streams 56*7c478bd9Sstevel@tonic-gate * under /dev/sppp. This feature is needed to support PPP translation 57*7c478bd9Sstevel@tonic-gate * (LAC-like behavior), but isn't currently used. 58*7c478bd9Sstevel@tonic-gate */ 59*7c478bd9Sstevel@tonic-gate #define PPPOE_DISCRIM 0x504F4531 60*7c478bd9Sstevel@tonic-gate 61*7c478bd9Sstevel@tonic-gate /* milliseconds between retries */ 62*7c478bd9Sstevel@tonic-gate #define PADI_RESTART_TIME 500 63*7c478bd9Sstevel@tonic-gate #define PADR_RESTART_TIME 2000 64*7c478bd9Sstevel@tonic-gate 65*7c478bd9Sstevel@tonic-gate /* default inquiry mode timer in milliseconds. */ 66*7c478bd9Sstevel@tonic-gate #define PADI_INQUIRY_DWELL 3000 67*7c478bd9Sstevel@tonic-gate 68*7c478bd9Sstevel@tonic-gate /* maximum timer value in milliseconds */ 69*7c478bd9Sstevel@tonic-gate #define RESTART_LIMIT 5000 70*7c478bd9Sstevel@tonic-gate 71*7c478bd9Sstevel@tonic-gate char *myname; /* copy of argv[0] for error messages */ 72*7c478bd9Sstevel@tonic-gate static int verbose; /* -v flag given */ 73*7c478bd9Sstevel@tonic-gate static int onlyflag; /* keyword "only" at end of command line */ 74*7c478bd9Sstevel@tonic-gate static char *service = ""; /* saved service name from command line */ 75*7c478bd9Sstevel@tonic-gate 76*7c478bd9Sstevel@tonic-gate static int pado_wait_time = 0; /* see main() */ 77*7c478bd9Sstevel@tonic-gate static int pads_wait_time = PADR_RESTART_TIME; 78*7c478bd9Sstevel@tonic-gate 79*7c478bd9Sstevel@tonic-gate static int tunfd; /* open connection to sppptun driver */ 80*7c478bd9Sstevel@tonic-gate 81*7c478bd9Sstevel@tonic-gate static struct timeval tvstart; /* time of last PADI/PADR transmission */ 82*7c478bd9Sstevel@tonic-gate 83*7c478bd9Sstevel@tonic-gate struct server_filter { 84*7c478bd9Sstevel@tonic-gate struct server_filter *sf_next; /* Next filter in list */ 85*7c478bd9Sstevel@tonic-gate struct ether_addr sf_mac; /* Ethernet address */ 86*7c478bd9Sstevel@tonic-gate struct ether_addr sf_mask; /* Mask (0 or 0xFF in each byte) */ 87*7c478bd9Sstevel@tonic-gate const char *sf_name; /* String for AC-Name compare */ 88*7c478bd9Sstevel@tonic-gate boolean_t sf_hasmac; /* Set if string could be MAC */ 89*7c478bd9Sstevel@tonic-gate boolean_t sf_isexcept; /* Ignore server if matching */ 90*7c478bd9Sstevel@tonic-gate }; 91*7c478bd9Sstevel@tonic-gate 92*7c478bd9Sstevel@tonic-gate /* List of filters defined on command line. */ 93*7c478bd9Sstevel@tonic-gate static struct server_filter *sfhead, *sftail; 94*7c478bd9Sstevel@tonic-gate 95*7c478bd9Sstevel@tonic-gate /* 96*7c478bd9Sstevel@tonic-gate * PPPoE Client State Machine 97*7c478bd9Sstevel@tonic-gate */ 98*7c478bd9Sstevel@tonic-gate 99*7c478bd9Sstevel@tonic-gate /* Client events */ 100*7c478bd9Sstevel@tonic-gate #define PCSME_CLOSE 0 /* User close */ 101*7c478bd9Sstevel@tonic-gate #define PCSME_OPEN 1 /* User open */ 102*7c478bd9Sstevel@tonic-gate #define PCSME_TOP 2 /* Timeout+ (counter non-zero) */ 103*7c478bd9Sstevel@tonic-gate #define PCSME_TOM 3 /* Timeout- (counter zero) */ 104*7c478bd9Sstevel@tonic-gate #define PCSME_RPADT 4 /* Receive PADT (unexpected here) */ 105*7c478bd9Sstevel@tonic-gate #define PCSME_RPADOP 5 /* Receive desired PADO */ 106*7c478bd9Sstevel@tonic-gate #define PCSME_RPADO 6 /* Receive ordinary PADO */ 107*7c478bd9Sstevel@tonic-gate #define PCSME_RPADS 7 /* Receive PADS */ 108*7c478bd9Sstevel@tonic-gate #define PCSME_RPADSN 8 /* Receive bad (errored) PADS */ 109*7c478bd9Sstevel@tonic-gate #define PCSME__MAX 9 110*7c478bd9Sstevel@tonic-gate 111*7c478bd9Sstevel@tonic-gate /* Client states */ 112*7c478bd9Sstevel@tonic-gate #define PCSMS_DEAD 0 /* Initial state */ 113*7c478bd9Sstevel@tonic-gate #define PCSMS_INITSENT 1 /* PADI sent */ 114*7c478bd9Sstevel@tonic-gate #define PCSMS_OFFRRCVD 2 /* PADO received */ 115*7c478bd9Sstevel@tonic-gate #define PCSMS_REQSENT 3 /* PADR sent */ 116*7c478bd9Sstevel@tonic-gate #define PCSMS_CONVERS 4 /* Conversational */ 117*7c478bd9Sstevel@tonic-gate #define PCSMS__MAX 5 118*7c478bd9Sstevel@tonic-gate 119*7c478bd9Sstevel@tonic-gate /* Client actions */ 120*7c478bd9Sstevel@tonic-gate #define PCSMA_NONE 0 /* Do nothing */ 121*7c478bd9Sstevel@tonic-gate #define PCSMA_FAIL 1 /* Unrecoverable error */ 122*7c478bd9Sstevel@tonic-gate #define PCSMA_SPADI 2 /* Send PADI */ 123*7c478bd9Sstevel@tonic-gate #define PCSMA_ADD 3 /* Add ordinary server to list */ 124*7c478bd9Sstevel@tonic-gate #define PCSMA_SPADR 4 /* Send PADR to top server */ 125*7c478bd9Sstevel@tonic-gate #define PCSMA_SPADRP 5 /* Send PADR to this server (make top) */ 126*7c478bd9Sstevel@tonic-gate #define PCSMA_SPADRN 6 /* Send PADR to next (or terminate) */ 127*7c478bd9Sstevel@tonic-gate #define PCSMA_OPEN 7 /* Start PPP */ 128*7c478bd9Sstevel@tonic-gate #define PCSMA__MAX 8 129*7c478bd9Sstevel@tonic-gate 130*7c478bd9Sstevel@tonic-gate static uint8_t client_next_state[PCSMS__MAX][PCSME__MAX] = { 131*7c478bd9Sstevel@tonic-gate /* 0 PCSMS_DEAD Initial state */ 132*7c478bd9Sstevel@tonic-gate { 133*7c478bd9Sstevel@tonic-gate PCSMS_DEAD, /* PCSME_CLOSE User close */ 134*7c478bd9Sstevel@tonic-gate PCSMS_INITSENT, /* PCSME_OPEN User open */ 135*7c478bd9Sstevel@tonic-gate PCSMS_DEAD, /* PCSME_TOP Timeout+ */ 136*7c478bd9Sstevel@tonic-gate PCSMS_DEAD, /* PCSME_TOM Timeout- */ 137*7c478bd9Sstevel@tonic-gate PCSMS_DEAD, /* PCSME_RPADT Receive PADT */ 138*7c478bd9Sstevel@tonic-gate PCSMS_DEAD, /* PCSME_RPADOP Receive desired PADO */ 139*7c478bd9Sstevel@tonic-gate PCSMS_DEAD, /* PCSME_RPADO Receive ordinary PADO */ 140*7c478bd9Sstevel@tonic-gate PCSMS_DEAD, /* PCSME_RPADS Receive PADS */ 141*7c478bd9Sstevel@tonic-gate PCSMS_DEAD, /* PCSME_RPADSN Receive bad PADS */ 142*7c478bd9Sstevel@tonic-gate }, 143*7c478bd9Sstevel@tonic-gate /* 1 PCSMS_INITSENT PADI sent */ 144*7c478bd9Sstevel@tonic-gate { 145*7c478bd9Sstevel@tonic-gate PCSMS_DEAD, /* PCSME_CLOSE User close */ 146*7c478bd9Sstevel@tonic-gate PCSMS_INITSENT, /* PCSME_OPEN User open */ 147*7c478bd9Sstevel@tonic-gate PCSMS_INITSENT, /* PCSME_TOP Timeout+ */ 148*7c478bd9Sstevel@tonic-gate PCSMS_DEAD, /* PCSME_TOM Timeout- */ 149*7c478bd9Sstevel@tonic-gate PCSMS_DEAD, /* PCSME_RPADT Receive PADT */ 150*7c478bd9Sstevel@tonic-gate PCSMS_REQSENT, /* PCSME_RPADOP Receive desired PADO */ 151*7c478bd9Sstevel@tonic-gate PCSMS_OFFRRCVD, /* PCSME_RPADO Receive ordinary PADO */ 152*7c478bd9Sstevel@tonic-gate PCSMS_INITSENT, /* PCSME_RPADS Receive PADS */ 153*7c478bd9Sstevel@tonic-gate PCSMS_INITSENT, /* PCSME_RPADSN Receive bad PADS */ 154*7c478bd9Sstevel@tonic-gate }, 155*7c478bd9Sstevel@tonic-gate /* 2 PCSMS_OFFRRCVD PADO received */ 156*7c478bd9Sstevel@tonic-gate { 157*7c478bd9Sstevel@tonic-gate PCSMS_DEAD, /* PCSME_CLOSE User close */ 158*7c478bd9Sstevel@tonic-gate PCSMS_INITSENT, /* PCSME_OPEN User open */ 159*7c478bd9Sstevel@tonic-gate PCSMS_REQSENT, /* PCSME_TOP Timeout+ */ 160*7c478bd9Sstevel@tonic-gate PCSMS_REQSENT, /* PCSME_TOM Timeout- */ 161*7c478bd9Sstevel@tonic-gate PCSMS_DEAD, /* PCSME_RPADT Receive PADT */ 162*7c478bd9Sstevel@tonic-gate PCSMS_REQSENT, /* PCSME_RPADOP Receive desired PADO */ 163*7c478bd9Sstevel@tonic-gate PCSMS_OFFRRCVD, /* PCSME_RPADO Receive ordinary PADO */ 164*7c478bd9Sstevel@tonic-gate PCSMS_OFFRRCVD, /* PCSME_RPADS Receive PADS */ 165*7c478bd9Sstevel@tonic-gate PCSMS_OFFRRCVD, /* PCSME_RPADSN Receive bad PADS */ 166*7c478bd9Sstevel@tonic-gate }, 167*7c478bd9Sstevel@tonic-gate /* 3 PCSMS_REQSENT PADR sent */ 168*7c478bd9Sstevel@tonic-gate { 169*7c478bd9Sstevel@tonic-gate PCSMS_DEAD, /* PCSME_CLOSE User close */ 170*7c478bd9Sstevel@tonic-gate PCSMS_INITSENT, /* PCSME_OPEN User open */ 171*7c478bd9Sstevel@tonic-gate PCSMS_REQSENT, /* PCSME_TOP Timeout+ */ 172*7c478bd9Sstevel@tonic-gate PCSMS_REQSENT, /* PCSME_TOM Timeout- */ 173*7c478bd9Sstevel@tonic-gate PCSMS_DEAD, /* PCSME_RPADT Receive PADT */ 174*7c478bd9Sstevel@tonic-gate PCSMS_REQSENT, /* PCSME_RPADOP Receive desired PADO */ 175*7c478bd9Sstevel@tonic-gate PCSMS_REQSENT, /* PCSME_RPADO Receive ordinary PADO */ 176*7c478bd9Sstevel@tonic-gate PCSMS_CONVERS, /* PCSME_RPADS Receive PADS */ 177*7c478bd9Sstevel@tonic-gate PCSMS_REQSENT, /* PCSME_RPADSN Receive bad PADS */ 178*7c478bd9Sstevel@tonic-gate }, 179*7c478bd9Sstevel@tonic-gate /* 4 PCSMS_CONVERS Conversational */ 180*7c478bd9Sstevel@tonic-gate { 181*7c478bd9Sstevel@tonic-gate PCSMS_DEAD, /* PCSME_CLOSE User close */ 182*7c478bd9Sstevel@tonic-gate PCSMS_INITSENT, /* PCSME_OPEN User open */ 183*7c478bd9Sstevel@tonic-gate PCSMS_CONVERS, /* PCSME_TOP Timeout+ */ 184*7c478bd9Sstevel@tonic-gate PCSMS_CONVERS, /* PCSME_TOM Timeout- */ 185*7c478bd9Sstevel@tonic-gate PCSMS_DEAD, /* PCSME_RPADT Receive PADT */ 186*7c478bd9Sstevel@tonic-gate PCSMS_CONVERS, /* PCSME_RPADOP Receive desired PADO */ 187*7c478bd9Sstevel@tonic-gate PCSMS_CONVERS, /* PCSME_RPADO Receive ordinary PADO */ 188*7c478bd9Sstevel@tonic-gate PCSMS_CONVERS, /* PCSME_RPADS Receive PADS */ 189*7c478bd9Sstevel@tonic-gate PCSMS_CONVERS, /* PCSME_RPADSN Receive bad PADS */ 190*7c478bd9Sstevel@tonic-gate }, 191*7c478bd9Sstevel@tonic-gate }; 192*7c478bd9Sstevel@tonic-gate 193*7c478bd9Sstevel@tonic-gate static uint8_t client_action[PCSMS__MAX][PCSME__MAX] = { 194*7c478bd9Sstevel@tonic-gate /* 0 PCSMS_DEAD Initial state */ 195*7c478bd9Sstevel@tonic-gate { 196*7c478bd9Sstevel@tonic-gate PCSMA_NONE, /* PCSME_CLOSE User close */ 197*7c478bd9Sstevel@tonic-gate PCSMA_SPADI, /* PCSME_OPEN User open */ 198*7c478bd9Sstevel@tonic-gate PCSMA_NONE, /* PCSME_TOP Timeout+ */ 199*7c478bd9Sstevel@tonic-gate PCSMA_NONE, /* PCSME_TOM Timeout- */ 200*7c478bd9Sstevel@tonic-gate PCSMA_NONE, /* PCSME_RPADT Receive PADT */ 201*7c478bd9Sstevel@tonic-gate PCSMA_NONE, /* PCSME_RPADOP Receive desired PADO */ 202*7c478bd9Sstevel@tonic-gate PCSMA_NONE, /* PCSME_RPADO Receive ordinary PADO */ 203*7c478bd9Sstevel@tonic-gate PCSMA_NONE, /* PCSME_RPADS Receive PADS */ 204*7c478bd9Sstevel@tonic-gate PCSMA_NONE, /* PCSME_RPADSN Receive bad PADS */ 205*7c478bd9Sstevel@tonic-gate }, 206*7c478bd9Sstevel@tonic-gate /* 1 PCSMS_INITSENT PADI sent */ 207*7c478bd9Sstevel@tonic-gate { 208*7c478bd9Sstevel@tonic-gate PCSMA_FAIL, /* PCSME_CLOSE User close */ 209*7c478bd9Sstevel@tonic-gate PCSMA_SPADI, /* PCSME_OPEN User open */ 210*7c478bd9Sstevel@tonic-gate PCSMA_SPADI, /* PCSME_TOP Timeout+ */ 211*7c478bd9Sstevel@tonic-gate PCSMA_FAIL, /* PCSME_TOM Timeout- */ 212*7c478bd9Sstevel@tonic-gate PCSMA_FAIL, /* PCSME_RPADT Receive PADT */ 213*7c478bd9Sstevel@tonic-gate PCSMA_SPADRP, /* PCSME_RPADOP Receive desired PADO */ 214*7c478bd9Sstevel@tonic-gate PCSMA_ADD, /* PCSME_RPADO Receive ordinary PADO */ 215*7c478bd9Sstevel@tonic-gate PCSMA_NONE, /* PCSME_RPADS Receive PADS */ 216*7c478bd9Sstevel@tonic-gate PCSMA_NONE, /* PCSME_RPADSN Receive bad PADS */ 217*7c478bd9Sstevel@tonic-gate }, 218*7c478bd9Sstevel@tonic-gate /* 2 PCSMS_OFFRRCVD PADO received */ 219*7c478bd9Sstevel@tonic-gate { 220*7c478bd9Sstevel@tonic-gate PCSMA_FAIL, /* PCSME_CLOSE User close */ 221*7c478bd9Sstevel@tonic-gate PCSMA_SPADI, /* PCSME_OPEN User open */ 222*7c478bd9Sstevel@tonic-gate PCSMA_SPADR, /* PCSME_TOP Timeout+ */ 223*7c478bd9Sstevel@tonic-gate PCSMA_SPADR, /* PCSME_TOM Timeout- */ 224*7c478bd9Sstevel@tonic-gate PCSMA_FAIL, /* PCSME_RPADT Receive PADT */ 225*7c478bd9Sstevel@tonic-gate PCSMA_SPADRP, /* PCSME_RPADOP Receive desired PADO */ 226*7c478bd9Sstevel@tonic-gate PCSMA_ADD, /* PCSME_RPADO Receive ordinary PADO */ 227*7c478bd9Sstevel@tonic-gate PCSMA_NONE, /* PCSME_RPADS Receive PADS */ 228*7c478bd9Sstevel@tonic-gate PCSMA_NONE, /* PCSME_RPADSN Receive bad PADS */ 229*7c478bd9Sstevel@tonic-gate }, 230*7c478bd9Sstevel@tonic-gate /* 3 PCSMS_REQSENT PADR sent */ 231*7c478bd9Sstevel@tonic-gate { 232*7c478bd9Sstevel@tonic-gate PCSMA_FAIL, /* PCSME_CLOSE User close */ 233*7c478bd9Sstevel@tonic-gate PCSMA_SPADI, /* PCSME_OPEN User open */ 234*7c478bd9Sstevel@tonic-gate PCSMA_SPADR, /* PCSME_TOP Timeout+ */ 235*7c478bd9Sstevel@tonic-gate PCSMA_SPADRN, /* PCSME_TOM Timeout- */ 236*7c478bd9Sstevel@tonic-gate PCSMA_FAIL, /* PCSME_RPADT Receive PADT */ 237*7c478bd9Sstevel@tonic-gate PCSMA_ADD, /* PCSME_RPADOP Receive desired PADO */ 238*7c478bd9Sstevel@tonic-gate PCSMA_ADD, /* PCSME_RPADO Receive ordinary PADO */ 239*7c478bd9Sstevel@tonic-gate PCSMA_OPEN, /* PCSME_RPADS Receive PADS */ 240*7c478bd9Sstevel@tonic-gate PCSMA_SPADRN, /* PCSME_RPADSN Receive bad PADS */ 241*7c478bd9Sstevel@tonic-gate }, 242*7c478bd9Sstevel@tonic-gate /* 4 PCSMS_CONVERS Conversational */ 243*7c478bd9Sstevel@tonic-gate { 244*7c478bd9Sstevel@tonic-gate PCSMA_FAIL, /* PCSME_CLOSE User close */ 245*7c478bd9Sstevel@tonic-gate PCSMA_SPADI, /* PCSME_OPEN User open */ 246*7c478bd9Sstevel@tonic-gate PCSMA_FAIL, /* PCSME_TOP Timeout+ */ 247*7c478bd9Sstevel@tonic-gate PCSMA_FAIL, /* PCSME_TOM Timeout- */ 248*7c478bd9Sstevel@tonic-gate PCSMA_FAIL, /* PCSME_RPADT Receive PADT */ 249*7c478bd9Sstevel@tonic-gate PCSMA_NONE, /* PCSME_RPADOP Receive desired PADO */ 250*7c478bd9Sstevel@tonic-gate PCSMA_NONE, /* PCSME_RPADO Receive ordinary PADO */ 251*7c478bd9Sstevel@tonic-gate PCSMA_NONE, /* PCSME_RPADS Receive PADS */ 252*7c478bd9Sstevel@tonic-gate PCSMA_NONE, /* PCSME_RPADSN Receive bad PADS */ 253*7c478bd9Sstevel@tonic-gate }, 254*7c478bd9Sstevel@tonic-gate }; 255*7c478bd9Sstevel@tonic-gate 256*7c478bd9Sstevel@tonic-gate /* 257*7c478bd9Sstevel@tonic-gate * PPPoE Message structure -- holds data from a received PPPoE 258*7c478bd9Sstevel@tonic-gate * message. These are copied and saved when queuing offers from 259*7c478bd9Sstevel@tonic-gate * possible servers. 260*7c478bd9Sstevel@tonic-gate */ 261*7c478bd9Sstevel@tonic-gate typedef struct poesm_s { 262*7c478bd9Sstevel@tonic-gate struct poesm_s *poemsg_next; /* Next message in list */ 263*7c478bd9Sstevel@tonic-gate const poep_t *poemsg_data; /* Pointer to PPPoE packet */ 264*7c478bd9Sstevel@tonic-gate int poemsg_len; /* Length of packet */ 265*7c478bd9Sstevel@tonic-gate ppptun_atype poemsg_sender; /* Address of sender */ 266*7c478bd9Sstevel@tonic-gate const char *poemsg_iname; /* Name of input interface */ 267*7c478bd9Sstevel@tonic-gate } poemsg_t; 268*7c478bd9Sstevel@tonic-gate 269*7c478bd9Sstevel@tonic-gate /* 270*7c478bd9Sstevel@tonic-gate * PPPoE State Machine structure -- holds state of PPPoE negotiation; 271*7c478bd9Sstevel@tonic-gate * currently, there's exactly one of these per pppoec instance. 272*7c478bd9Sstevel@tonic-gate */ 273*7c478bd9Sstevel@tonic-gate typedef struct { 274*7c478bd9Sstevel@tonic-gate int poesm_state; /* PCSMS_* */ 275*7c478bd9Sstevel@tonic-gate int poesm_timer; /* Milliseconds to next TO */ 276*7c478bd9Sstevel@tonic-gate int poesm_count; /* Retry countdown */ 277*7c478bd9Sstevel@tonic-gate int poesm_interval; /* Reload value */ 278*7c478bd9Sstevel@tonic-gate uint32_t poesm_sequence; /* Sequence for PADR */ 279*7c478bd9Sstevel@tonic-gate 280*7c478bd9Sstevel@tonic-gate poemsg_t *poesm_firstoff; /* Queue of valid offers; */ 281*7c478bd9Sstevel@tonic-gate poemsg_t *poesm_lastoff; /* first is best offer */ 282*7c478bd9Sstevel@tonic-gate poemsg_t *poesm_tried; /* Tried and failed offers */ 283*7c478bd9Sstevel@tonic-gate 284*7c478bd9Sstevel@tonic-gate int poesm_localid; /* Local session ID (driver) */ 285*7c478bd9Sstevel@tonic-gate } poesm_t; 286*7c478bd9Sstevel@tonic-gate 287*7c478bd9Sstevel@tonic-gate /* 288*7c478bd9Sstevel@tonic-gate * Convert an internal PPPoE event code number into a printable 289*7c478bd9Sstevel@tonic-gate * string. 290*7c478bd9Sstevel@tonic-gate */ 291*7c478bd9Sstevel@tonic-gate static const char * 292*7c478bd9Sstevel@tonic-gate poe_event(int event) 293*7c478bd9Sstevel@tonic-gate { 294*7c478bd9Sstevel@tonic-gate static const char *poeevent[PCSME__MAX] = { 295*7c478bd9Sstevel@tonic-gate "Close", "Open", "TO+", "TO-", "rPADT", 296*7c478bd9Sstevel@tonic-gate "rPADO+", "rPADO", "rPADS", "rPADS-" 297*7c478bd9Sstevel@tonic-gate }; 298*7c478bd9Sstevel@tonic-gate 299*7c478bd9Sstevel@tonic-gate if (event < 0 || event >= PCSME__MAX) { 300*7c478bd9Sstevel@tonic-gate return ("?"); 301*7c478bd9Sstevel@tonic-gate } 302*7c478bd9Sstevel@tonic-gate return (poeevent[event]); 303*7c478bd9Sstevel@tonic-gate } 304*7c478bd9Sstevel@tonic-gate 305*7c478bd9Sstevel@tonic-gate /* 306*7c478bd9Sstevel@tonic-gate * Convert an internal PPPoE state number into a printable string. 307*7c478bd9Sstevel@tonic-gate */ 308*7c478bd9Sstevel@tonic-gate static const char * 309*7c478bd9Sstevel@tonic-gate poe_state(int state) 310*7c478bd9Sstevel@tonic-gate { 311*7c478bd9Sstevel@tonic-gate static const char *poestate[PCSMS__MAX] = { 312*7c478bd9Sstevel@tonic-gate "Dead", "InitSent", "OffrRcvd", "ReqSent", "Convers", 313*7c478bd9Sstevel@tonic-gate }; 314*7c478bd9Sstevel@tonic-gate 315*7c478bd9Sstevel@tonic-gate if (state < 0 || state >= PCSMS__MAX) { 316*7c478bd9Sstevel@tonic-gate return ("?"); 317*7c478bd9Sstevel@tonic-gate } 318*7c478bd9Sstevel@tonic-gate return (poestate[state]); 319*7c478bd9Sstevel@tonic-gate } 320*7c478bd9Sstevel@tonic-gate 321*7c478bd9Sstevel@tonic-gate /* 322*7c478bd9Sstevel@tonic-gate * Convert an internal PPPoE action number into a printable string. 323*7c478bd9Sstevel@tonic-gate */ 324*7c478bd9Sstevel@tonic-gate static const char * 325*7c478bd9Sstevel@tonic-gate poe_action(int act) 326*7c478bd9Sstevel@tonic-gate { 327*7c478bd9Sstevel@tonic-gate static const char *poeaction[PCSMA__MAX] = { 328*7c478bd9Sstevel@tonic-gate "None", "Fail", "SendPADI", "Add", "SendPADR", 329*7c478bd9Sstevel@tonic-gate "SendPADR+", "SendPADR-", "Open" 330*7c478bd9Sstevel@tonic-gate }; 331*7c478bd9Sstevel@tonic-gate 332*7c478bd9Sstevel@tonic-gate if (act < 0 || act >= PCSMA__MAX) { 333*7c478bd9Sstevel@tonic-gate return ("?"); 334*7c478bd9Sstevel@tonic-gate } 335*7c478bd9Sstevel@tonic-gate return (poeaction[act]); 336*7c478bd9Sstevel@tonic-gate } 337*7c478bd9Sstevel@tonic-gate 338*7c478bd9Sstevel@tonic-gate /* 339*7c478bd9Sstevel@tonic-gate * This calls mygetmsg (which discards partial messages as needed) and 340*7c478bd9Sstevel@tonic-gate * logs errors as appropriate. 341*7c478bd9Sstevel@tonic-gate */ 342*7c478bd9Sstevel@tonic-gate static int 343*7c478bd9Sstevel@tonic-gate pppoec_getmsg(int fd, struct strbuf *ctrl, struct strbuf *data, int *flags) 344*7c478bd9Sstevel@tonic-gate { 345*7c478bd9Sstevel@tonic-gate int retv; 346*7c478bd9Sstevel@tonic-gate 347*7c478bd9Sstevel@tonic-gate for (;;) { 348*7c478bd9Sstevel@tonic-gate retv = mygetmsg(fd, ctrl, data, flags); 349*7c478bd9Sstevel@tonic-gate if (retv == 0) 350*7c478bd9Sstevel@tonic-gate break; 351*7c478bd9Sstevel@tonic-gate if (retv < 0) { 352*7c478bd9Sstevel@tonic-gate if (errno == EINTR) 353*7c478bd9Sstevel@tonic-gate continue; 354*7c478bd9Sstevel@tonic-gate logstrerror("getmsg"); 355*7c478bd9Sstevel@tonic-gate break; 356*7c478bd9Sstevel@tonic-gate } 357*7c478bd9Sstevel@tonic-gate if (verbose) { 358*7c478bd9Sstevel@tonic-gate if (!(retv & (MORECTL | MOREDATA))) 359*7c478bd9Sstevel@tonic-gate logerr("%s: discard: " 360*7c478bd9Sstevel@tonic-gate "unexpected status %d\n", myname, retv); 361*7c478bd9Sstevel@tonic-gate else 362*7c478bd9Sstevel@tonic-gate logerr("%s: discard: " 363*7c478bd9Sstevel@tonic-gate "truncated %s%smessage\n", myname, 364*7c478bd9Sstevel@tonic-gate retv & MORECTL ? "control " : "", 365*7c478bd9Sstevel@tonic-gate retv & MOREDATA ? "data " : ""); 366*7c478bd9Sstevel@tonic-gate } 367*7c478bd9Sstevel@tonic-gate } 368*7c478bd9Sstevel@tonic-gate return (retv); 369*7c478bd9Sstevel@tonic-gate } 370*7c478bd9Sstevel@tonic-gate 371*7c478bd9Sstevel@tonic-gate /* 372*7c478bd9Sstevel@tonic-gate * Connect the control path to the lower stream of interest. This 373*7c478bd9Sstevel@tonic-gate * must be called after opening the tunnel driver in order to 374*7c478bd9Sstevel@tonic-gate * establish the interface to be used for signaling. Returns local 375*7c478bd9Sstevel@tonic-gate * session ID number. 376*7c478bd9Sstevel@tonic-gate */ 377*7c478bd9Sstevel@tonic-gate static int 378*7c478bd9Sstevel@tonic-gate set_control(const char *dname) 379*7c478bd9Sstevel@tonic-gate { 380*7c478bd9Sstevel@tonic-gate struct ppptun_peer ptp; 381*7c478bd9Sstevel@tonic-gate union ppptun_name ptn; 382*7c478bd9Sstevel@tonic-gate 383*7c478bd9Sstevel@tonic-gate /* Fetch the local session ID first. */ 384*7c478bd9Sstevel@tonic-gate (void) memset(&ptp, '\0', sizeof (ptp)); 385*7c478bd9Sstevel@tonic-gate ptp.ptp_style = PTS_PPPOE; 386*7c478bd9Sstevel@tonic-gate if (strioctl(tunfd, PPPTUN_SPEER, &ptp, sizeof (ptp), sizeof (ptp)) < 387*7c478bd9Sstevel@tonic-gate 0) { 388*7c478bd9Sstevel@tonic-gate logstrerror("PPPTUN_SPEER"); 389*7c478bd9Sstevel@tonic-gate exit(1); 390*7c478bd9Sstevel@tonic-gate } 391*7c478bd9Sstevel@tonic-gate 392*7c478bd9Sstevel@tonic-gate /* Connect to lower stream. */ 393*7c478bd9Sstevel@tonic-gate (void) snprintf(ptn.ptn_name, sizeof (ptn.ptn_name), "%s:pppoed", 394*7c478bd9Sstevel@tonic-gate dname); 395*7c478bd9Sstevel@tonic-gate if (strioctl(tunfd, PPPTUN_SCTL, &ptn, sizeof (ptn), 0) < 0) { 396*7c478bd9Sstevel@tonic-gate logerr("%s: PPPTUN_SCTL %s: %s\n", myname, 397*7c478bd9Sstevel@tonic-gate ptn.ptn_name, mystrerror(errno)); 398*7c478bd9Sstevel@tonic-gate exit(1); 399*7c478bd9Sstevel@tonic-gate } 400*7c478bd9Sstevel@tonic-gate return (ptp.ptp_lsessid); 401*7c478bd9Sstevel@tonic-gate } 402*7c478bd9Sstevel@tonic-gate 403*7c478bd9Sstevel@tonic-gate /* 404*7c478bd9Sstevel@tonic-gate * Check if standard input is actually a viable connection to the 405*7c478bd9Sstevel@tonic-gate * tunnel driver. This is the normal mode of operation with pppd; the 406*7c478bd9Sstevel@tonic-gate * tunnel driver is opened by pppd as the tty and pppoec is exec'd as 407*7c478bd9Sstevel@tonic-gate * the connect script. 408*7c478bd9Sstevel@tonic-gate */ 409*7c478bd9Sstevel@tonic-gate static void 410*7c478bd9Sstevel@tonic-gate check_stdin(void) 411*7c478bd9Sstevel@tonic-gate { 412*7c478bd9Sstevel@tonic-gate struct ppptun_info pti; 413*7c478bd9Sstevel@tonic-gate union ppptun_name ptn; 414*7c478bd9Sstevel@tonic-gate 415*7c478bd9Sstevel@tonic-gate if (strioctl(0, PPPTUN_GDATA, &ptn, 0, sizeof (ptn)) < 0) { 416*7c478bd9Sstevel@tonic-gate if (errno == EINVAL) 417*7c478bd9Sstevel@tonic-gate logerr("%s: PPPoE operation requires " 418*7c478bd9Sstevel@tonic-gate "the use of a tunneling device\n", myname); 419*7c478bd9Sstevel@tonic-gate else 420*7c478bd9Sstevel@tonic-gate logstrerror("PPPTUN_GDATA"); 421*7c478bd9Sstevel@tonic-gate exit(1); 422*7c478bd9Sstevel@tonic-gate } 423*7c478bd9Sstevel@tonic-gate if (ptn.ptn_name[0] != '\0') { 424*7c478bd9Sstevel@tonic-gate if (strioctl(0, PPPTUN_GINFO, &pti, 0, sizeof (pti)) < 0) { 425*7c478bd9Sstevel@tonic-gate logstrerror("PPPTUN_GINFO"); 426*7c478bd9Sstevel@tonic-gate exit(1); 427*7c478bd9Sstevel@tonic-gate } 428*7c478bd9Sstevel@tonic-gate if (pti.pti_style != PTS_PPPOE) { 429*7c478bd9Sstevel@tonic-gate logerr("%s: Cannot connect to server " 430*7c478bd9Sstevel@tonic-gate "using PPPoE; stream already set to style %d\n", 431*7c478bd9Sstevel@tonic-gate myname, pti.pti_style); 432*7c478bd9Sstevel@tonic-gate exit(1); 433*7c478bd9Sstevel@tonic-gate } 434*7c478bd9Sstevel@tonic-gate if (verbose) 435*7c478bd9Sstevel@tonic-gate logerr("%s: Warning: PPPoE data link " 436*7c478bd9Sstevel@tonic-gate "already connected\n", myname); 437*7c478bd9Sstevel@tonic-gate exit(0); 438*7c478bd9Sstevel@tonic-gate } 439*7c478bd9Sstevel@tonic-gate /* Standard input is the tunnel driver; use it. */ 440*7c478bd9Sstevel@tonic-gate tunfd = 0; 441*7c478bd9Sstevel@tonic-gate } 442*7c478bd9Sstevel@tonic-gate 443*7c478bd9Sstevel@tonic-gate /* 444*7c478bd9Sstevel@tonic-gate * Write a summary of a PPPoE message to the given file. This is used 445*7c478bd9Sstevel@tonic-gate * for logging and to display received offers in the inquiry (-i) mode. 446*7c478bd9Sstevel@tonic-gate */ 447*7c478bd9Sstevel@tonic-gate static void 448*7c478bd9Sstevel@tonic-gate display_pppoe(FILE *out, const poep_t *poep, int plen, const ppptun_atype *pap) 449*7c478bd9Sstevel@tonic-gate { 450*7c478bd9Sstevel@tonic-gate int ttyp; 451*7c478bd9Sstevel@tonic-gate int tlen; 452*7c478bd9Sstevel@tonic-gate const uint8_t *tagp; 453*7c478bd9Sstevel@tonic-gate const uint8_t *dp; 454*7c478bd9Sstevel@tonic-gate const char *str; 455*7c478bd9Sstevel@tonic-gate poer_t poer; 456*7c478bd9Sstevel@tonic-gate uint32_t mask; 457*7c478bd9Sstevel@tonic-gate 458*7c478bd9Sstevel@tonic-gate if (out == stderr) 459*7c478bd9Sstevel@tonic-gate logerr(" "); /* Give us a timestamp */ 460*7c478bd9Sstevel@tonic-gate /* Print name of sender. */ 461*7c478bd9Sstevel@tonic-gate (void) fprintf(out, "%-16s ", ehost(pap)); 462*7c478bd9Sstevel@tonic-gate 463*7c478bd9Sstevel@tonic-gate /* Loop through tags and print each. */ 464*7c478bd9Sstevel@tonic-gate tagp = (const uint8_t *)(poep + 1); 465*7c478bd9Sstevel@tonic-gate while (poe_tagcheck(poep, plen, tagp)) { 466*7c478bd9Sstevel@tonic-gate ttyp = POET_GET_TYPE(tagp); 467*7c478bd9Sstevel@tonic-gate if (ttyp == POETT_END) 468*7c478bd9Sstevel@tonic-gate break; 469*7c478bd9Sstevel@tonic-gate tlen = POET_GET_LENG(tagp); 470*7c478bd9Sstevel@tonic-gate dp = POET_DATA(tagp); 471*7c478bd9Sstevel@tonic-gate str = NULL; 472*7c478bd9Sstevel@tonic-gate switch (ttyp) { 473*7c478bd9Sstevel@tonic-gate case POETT_SERVICE: /* Service-Name */ 474*7c478bd9Sstevel@tonic-gate str = "Svc"; 475*7c478bd9Sstevel@tonic-gate break; 476*7c478bd9Sstevel@tonic-gate case POETT_ACCESS: /* AC-Name */ 477*7c478bd9Sstevel@tonic-gate str = "Name"; 478*7c478bd9Sstevel@tonic-gate break; 479*7c478bd9Sstevel@tonic-gate case POETT_UNIQ: /* Host-Uniq */ 480*7c478bd9Sstevel@tonic-gate str = "Uniq"; 481*7c478bd9Sstevel@tonic-gate break; 482*7c478bd9Sstevel@tonic-gate case POETT_COOKIE: /* AC-Cookie */ 483*7c478bd9Sstevel@tonic-gate str = "Cookie"; 484*7c478bd9Sstevel@tonic-gate break; 485*7c478bd9Sstevel@tonic-gate case POETT_VENDOR: /* Vendor-Specific */ 486*7c478bd9Sstevel@tonic-gate break; 487*7c478bd9Sstevel@tonic-gate case POETT_RELAY: /* Relay-Session-Id */ 488*7c478bd9Sstevel@tonic-gate str = "Relay"; 489*7c478bd9Sstevel@tonic-gate break; 490*7c478bd9Sstevel@tonic-gate case POETT_NAMERR: /* Service-Name-Error */ 491*7c478bd9Sstevel@tonic-gate str = "SvcNameErr"; 492*7c478bd9Sstevel@tonic-gate break; 493*7c478bd9Sstevel@tonic-gate case POETT_SYSERR: /* AC-System-Error */ 494*7c478bd9Sstevel@tonic-gate str = "SysErr"; 495*7c478bd9Sstevel@tonic-gate break; 496*7c478bd9Sstevel@tonic-gate case POETT_GENERR: /* Generic-Error */ 497*7c478bd9Sstevel@tonic-gate str = "GenErr"; 498*7c478bd9Sstevel@tonic-gate break; 499*7c478bd9Sstevel@tonic-gate case POETT_MULTI: /* Multicast-Capable */ 500*7c478bd9Sstevel@tonic-gate break; 501*7c478bd9Sstevel@tonic-gate case POETT_HURL: /* Host-URL */ 502*7c478bd9Sstevel@tonic-gate str = "URL"; 503*7c478bd9Sstevel@tonic-gate break; 504*7c478bd9Sstevel@tonic-gate case POETT_MOTM: /* Message-Of-The-Minute */ 505*7c478bd9Sstevel@tonic-gate str = "Mesg"; 506*7c478bd9Sstevel@tonic-gate break; 507*7c478bd9Sstevel@tonic-gate case POETT_RTEADD: /* IP-Route-Add */ 508*7c478bd9Sstevel@tonic-gate break; 509*7c478bd9Sstevel@tonic-gate } 510*7c478bd9Sstevel@tonic-gate switch (ttyp) { 511*7c478bd9Sstevel@tonic-gate case POETT_NAMERR: /* Service-Name-Error */ 512*7c478bd9Sstevel@tonic-gate case POETT_SYSERR: /* AC-System-Error */ 513*7c478bd9Sstevel@tonic-gate if (tlen > 0 && *dp == '\0') 514*7c478bd9Sstevel@tonic-gate tlen = 0; 515*7c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 516*7c478bd9Sstevel@tonic-gate case POETT_SERVICE: /* Service-Name */ 517*7c478bd9Sstevel@tonic-gate case POETT_ACCESS: /* AC-Name */ 518*7c478bd9Sstevel@tonic-gate case POETT_GENERR: /* Generic-Error */ 519*7c478bd9Sstevel@tonic-gate case POETT_MOTM: /* Message-Of-The-Minute */ 520*7c478bd9Sstevel@tonic-gate case POETT_HURL: /* Host-URL */ 521*7c478bd9Sstevel@tonic-gate (void) fprintf(out, "%s:\"%.*s\" ", str, tlen, dp); 522*7c478bd9Sstevel@tonic-gate break; 523*7c478bd9Sstevel@tonic-gate case POETT_UNIQ: /* Host-Uniq */ 524*7c478bd9Sstevel@tonic-gate case POETT_COOKIE: /* AC-Cookie */ 525*7c478bd9Sstevel@tonic-gate case POETT_RELAY: /* Relay-Session-Id */ 526*7c478bd9Sstevel@tonic-gate (void) fprintf(out, "%s:", str); 527*7c478bd9Sstevel@tonic-gate while (--tlen >= 0) 528*7c478bd9Sstevel@tonic-gate (void) fprintf(out, "%02X", *dp++); 529*7c478bd9Sstevel@tonic-gate (void) putc(' ', out); 530*7c478bd9Sstevel@tonic-gate break; 531*7c478bd9Sstevel@tonic-gate case POETT_VENDOR: /* Vendor-Specific */ 532*7c478bd9Sstevel@tonic-gate (void) fputs("Vendor:", out); 533*7c478bd9Sstevel@tonic-gate if (tlen >= 4) { 534*7c478bd9Sstevel@tonic-gate if (*dp++ != 0) { 535*7c478bd9Sstevel@tonic-gate (void) fprintf(out, "(%02X?)", dp[-1]); 536*7c478bd9Sstevel@tonic-gate } 537*7c478bd9Sstevel@tonic-gate (void) fprintf(out, "%x-%x-%x:", dp[0], dp[1], 538*7c478bd9Sstevel@tonic-gate dp[2]); 539*7c478bd9Sstevel@tonic-gate tlen -= 4; 540*7c478bd9Sstevel@tonic-gate dp += 3; 541*7c478bd9Sstevel@tonic-gate } 542*7c478bd9Sstevel@tonic-gate while (--tlen >= 0) 543*7c478bd9Sstevel@tonic-gate (void) fprintf(out, "%02X", *dp++); 544*7c478bd9Sstevel@tonic-gate (void) putc(' ', out); 545*7c478bd9Sstevel@tonic-gate break; 546*7c478bd9Sstevel@tonic-gate case POETT_MULTI: /* Multicast-Capable */ 547*7c478bd9Sstevel@tonic-gate (void) fprintf(out, "Multi:%d ", *dp); 548*7c478bd9Sstevel@tonic-gate break; 549*7c478bd9Sstevel@tonic-gate case POETT_RTEADD: /* IP-Route-Add */ 550*7c478bd9Sstevel@tonic-gate if (tlen != sizeof (poer)) { 551*7c478bd9Sstevel@tonic-gate (void) fprintf(out, "RTE%d? ", tlen); 552*7c478bd9Sstevel@tonic-gate break; 553*7c478bd9Sstevel@tonic-gate } 554*7c478bd9Sstevel@tonic-gate (void) memcpy(&poer, dp, sizeof (poer)); 555*7c478bd9Sstevel@tonic-gate (void) fputs("RTE:", out); 556*7c478bd9Sstevel@tonic-gate if (poer.poer_dest_network == 0) 557*7c478bd9Sstevel@tonic-gate (void) fputs("default", out); 558*7c478bd9Sstevel@tonic-gate else 559*7c478bd9Sstevel@tonic-gate (void) fputs(ihost(poer.poer_dest_network), 560*7c478bd9Sstevel@tonic-gate out); 561*7c478bd9Sstevel@tonic-gate mask = ntohl(poer.poer_subnet_mask); 562*7c478bd9Sstevel@tonic-gate if (mask != 0 && mask != (uint32_t)~0) { 563*7c478bd9Sstevel@tonic-gate if ((~mask & (~mask + 1)) == 0) 564*7c478bd9Sstevel@tonic-gate (void) fprintf(out, "/%d", 565*7c478bd9Sstevel@tonic-gate sizeof (struct in_addr) * NBBY + 566*7c478bd9Sstevel@tonic-gate 1 - ffs(mask)); 567*7c478bd9Sstevel@tonic-gate else 568*7c478bd9Sstevel@tonic-gate (void) fprintf(out, "/%s", 569*7c478bd9Sstevel@tonic-gate ihost(poer.poer_subnet_mask)); 570*7c478bd9Sstevel@tonic-gate } 571*7c478bd9Sstevel@tonic-gate (void) fprintf(out, ",%s,%u ", 572*7c478bd9Sstevel@tonic-gate ihost(poer.poer_gateway), ntohl(poer.poer_metric)); 573*7c478bd9Sstevel@tonic-gate break; 574*7c478bd9Sstevel@tonic-gate default: 575*7c478bd9Sstevel@tonic-gate (void) fprintf(out, "%s:%d ", poe_tagname(ttyp), tlen); 576*7c478bd9Sstevel@tonic-gate break; 577*7c478bd9Sstevel@tonic-gate } 578*7c478bd9Sstevel@tonic-gate tagp = POET_NEXT(tagp); 579*7c478bd9Sstevel@tonic-gate } 580*7c478bd9Sstevel@tonic-gate (void) putc('\n', out); 581*7c478bd9Sstevel@tonic-gate } 582*7c478bd9Sstevel@tonic-gate 583*7c478bd9Sstevel@tonic-gate /* 584*7c478bd9Sstevel@tonic-gate * Transmit a PPPoE message to the indicated destination. Used for 585*7c478bd9Sstevel@tonic-gate * PADI and PADR messages. 586*7c478bd9Sstevel@tonic-gate */ 587*7c478bd9Sstevel@tonic-gate static int 588*7c478bd9Sstevel@tonic-gate send_pppoe(const poep_t *poep, const char *msgname, 589*7c478bd9Sstevel@tonic-gate const ppptun_atype *destaddr) 590*7c478bd9Sstevel@tonic-gate { 591*7c478bd9Sstevel@tonic-gate struct strbuf ctrl; 592*7c478bd9Sstevel@tonic-gate struct strbuf data; 593*7c478bd9Sstevel@tonic-gate struct ppptun_control *ptc; 594*7c478bd9Sstevel@tonic-gate 595*7c478bd9Sstevel@tonic-gate /* Set up the control data expected by the driver. */ 596*7c478bd9Sstevel@tonic-gate ptc = (struct ppptun_control *)pkt_octl; 597*7c478bd9Sstevel@tonic-gate (void) memset(ptc, '\0', sizeof (*ptc)); 598*7c478bd9Sstevel@tonic-gate ptc->ptc_discrim = PPPOE_DISCRIM; 599*7c478bd9Sstevel@tonic-gate ptc->ptc_action = PTCA_CONTROL; 600*7c478bd9Sstevel@tonic-gate ptc->ptc_address = *destaddr; 601*7c478bd9Sstevel@tonic-gate ctrl.len = sizeof (*ptc); 602*7c478bd9Sstevel@tonic-gate ctrl.buf = (caddr_t)ptc; 603*7c478bd9Sstevel@tonic-gate data.len = poe_length(poep) + sizeof (*poep); 604*7c478bd9Sstevel@tonic-gate data.buf = (caddr_t)poep; 605*7c478bd9Sstevel@tonic-gate if (verbose) 606*7c478bd9Sstevel@tonic-gate logerr("%s: Sending %s to %s: %d bytes\n", 607*7c478bd9Sstevel@tonic-gate myname, msgname, ehost(destaddr), data.len); 608*7c478bd9Sstevel@tonic-gate if (putmsg(tunfd, &ctrl, &data, 0) < 0) { 609*7c478bd9Sstevel@tonic-gate logstrerror("putmsg"); 610*7c478bd9Sstevel@tonic-gate return (-1); 611*7c478bd9Sstevel@tonic-gate } 612*7c478bd9Sstevel@tonic-gate return (0); 613*7c478bd9Sstevel@tonic-gate } 614*7c478bd9Sstevel@tonic-gate 615*7c478bd9Sstevel@tonic-gate /* 616*7c478bd9Sstevel@tonic-gate * Create and transmit a PPPoE Active Discovery Initiation packet. 617*7c478bd9Sstevel@tonic-gate * This is broadcasted to all hosts on the LAN. 618*7c478bd9Sstevel@tonic-gate */ 619*7c478bd9Sstevel@tonic-gate static int 620*7c478bd9Sstevel@tonic-gate send_padi(int localid) 621*7c478bd9Sstevel@tonic-gate { 622*7c478bd9Sstevel@tonic-gate poep_t *poep; 623*7c478bd9Sstevel@tonic-gate ppptun_atype destaddr; 624*7c478bd9Sstevel@tonic-gate 625*7c478bd9Sstevel@tonic-gate poep = poe_mkheader(pkt_output, POECODE_PADI, 0); 626*7c478bd9Sstevel@tonic-gate (void) poe_add_str(poep, POETT_SERVICE, ""); 627*7c478bd9Sstevel@tonic-gate (void) poe_add_long(poep, POETT_UNIQ, localid); 628*7c478bd9Sstevel@tonic-gate (void) memset(&destaddr, '\0', sizeof (destaddr)); 629*7c478bd9Sstevel@tonic-gate (void) memcpy(destaddr.pta_pppoe.ptma_mac, ether_bcast, 630*7c478bd9Sstevel@tonic-gate sizeof (destaddr.pta_pppoe.ptma_mac)); 631*7c478bd9Sstevel@tonic-gate return (send_pppoe(poep, "PADI", &destaddr)); 632*7c478bd9Sstevel@tonic-gate } 633*7c478bd9Sstevel@tonic-gate 634*7c478bd9Sstevel@tonic-gate /* 635*7c478bd9Sstevel@tonic-gate * This is used by the procedure below -- when the alarm goes off, 636*7c478bd9Sstevel@tonic-gate * just exit. (This was once a dummy procedure and used the EINTR 637*7c478bd9Sstevel@tonic-gate * side-effect to terminate the loop, but that's not reliable, since 638*7c478bd9Sstevel@tonic-gate * the EINTR could be caught and ignored by the calls to standard 639*7c478bd9Sstevel@tonic-gate * output.) 640*7c478bd9Sstevel@tonic-gate */ 641*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 642*7c478bd9Sstevel@tonic-gate static void 643*7c478bd9Sstevel@tonic-gate alarm_hand(int dummy) 644*7c478bd9Sstevel@tonic-gate { 645*7c478bd9Sstevel@tonic-gate exit(0); 646*7c478bd9Sstevel@tonic-gate } 647*7c478bd9Sstevel@tonic-gate 648*7c478bd9Sstevel@tonic-gate /* 649*7c478bd9Sstevel@tonic-gate * Send out a single PADI and listen for servers. This implements the 650*7c478bd9Sstevel@tonic-gate * "inquiry" (-i) mode. 651*7c478bd9Sstevel@tonic-gate */ 652*7c478bd9Sstevel@tonic-gate static void 653*7c478bd9Sstevel@tonic-gate find_all_servers(int localid) 654*7c478bd9Sstevel@tonic-gate { 655*7c478bd9Sstevel@tonic-gate struct strbuf ctrl; 656*7c478bd9Sstevel@tonic-gate struct strbuf data; 657*7c478bd9Sstevel@tonic-gate poep_t *poep; 658*7c478bd9Sstevel@tonic-gate int flags; 659*7c478bd9Sstevel@tonic-gate struct sigaction act; 660*7c478bd9Sstevel@tonic-gate struct ppptun_control *ptc; 661*7c478bd9Sstevel@tonic-gate 662*7c478bd9Sstevel@tonic-gate /* Set a default 3-second timer */ 663*7c478bd9Sstevel@tonic-gate (void) memset(&act, '\0', sizeof (act)); 664*7c478bd9Sstevel@tonic-gate act.sa_handler = alarm_hand; 665*7c478bd9Sstevel@tonic-gate (void) sigaction(SIGALRM, &act, NULL); 666*7c478bd9Sstevel@tonic-gate (void) alarm((pado_wait_time + 999) / 1000); 667*7c478bd9Sstevel@tonic-gate 668*7c478bd9Sstevel@tonic-gate /* Broadcast a single request. */ 669*7c478bd9Sstevel@tonic-gate if (send_padi(localid) != 0) 670*7c478bd9Sstevel@tonic-gate return; 671*7c478bd9Sstevel@tonic-gate 672*7c478bd9Sstevel@tonic-gate /* Loop over responses and print them. */ 673*7c478bd9Sstevel@tonic-gate for (;;) { 674*7c478bd9Sstevel@tonic-gate ctrl.maxlen = PKT_OCTL_LEN; 675*7c478bd9Sstevel@tonic-gate ctrl.buf = (caddr_t)pkt_octl; 676*7c478bd9Sstevel@tonic-gate data.maxlen = PKT_INPUT_LEN; 677*7c478bd9Sstevel@tonic-gate data.buf = (caddr_t)pkt_input; 678*7c478bd9Sstevel@tonic-gate flags = 0; 679*7c478bd9Sstevel@tonic-gate 680*7c478bd9Sstevel@tonic-gate if (pppoec_getmsg(tunfd, &ctrl, &data, &flags) < 0) 681*7c478bd9Sstevel@tonic-gate break; 682*7c478bd9Sstevel@tonic-gate 683*7c478bd9Sstevel@tonic-gate /* Ignore unwanted responses from the driver. */ 684*7c478bd9Sstevel@tonic-gate if (ctrl.len != sizeof (*ptc)) { 685*7c478bd9Sstevel@tonic-gate if (verbose) 686*7c478bd9Sstevel@tonic-gate logerr("%s: unexpected %d byte" 687*7c478bd9Sstevel@tonic-gate " control message from driver.\n", myname, 688*7c478bd9Sstevel@tonic-gate ctrl.len); 689*7c478bd9Sstevel@tonic-gate continue; 690*7c478bd9Sstevel@tonic-gate } 691*7c478bd9Sstevel@tonic-gate ptc = (struct ppptun_control *)pkt_octl; 692*7c478bd9Sstevel@tonic-gate poep = (poep_t *)pkt_input; 693*7c478bd9Sstevel@tonic-gate 694*7c478bd9Sstevel@tonic-gate /* If it's an offer, then print it out. */ 695*7c478bd9Sstevel@tonic-gate if (poe_code(poep) == POECODE_PADO) { 696*7c478bd9Sstevel@tonic-gate display_pppoe(stdout, poep, data.len, 697*7c478bd9Sstevel@tonic-gate &ptc->ptc_address); 698*7c478bd9Sstevel@tonic-gate } 699*7c478bd9Sstevel@tonic-gate } 700*7c478bd9Sstevel@tonic-gate } 701*7c478bd9Sstevel@tonic-gate 702*7c478bd9Sstevel@tonic-gate /* 703*7c478bd9Sstevel@tonic-gate * Parse a server filter from the command line. The passed-in string 704*7c478bd9Sstevel@tonic-gate * must be allocated and unchanged, since a pointer to it is saved in 705*7c478bd9Sstevel@tonic-gate * the filter data structure. The string is also parsed for a MAC 706*7c478bd9Sstevel@tonic-gate * address, if possible. 707*7c478bd9Sstevel@tonic-gate */ 708*7c478bd9Sstevel@tonic-gate static void 709*7c478bd9Sstevel@tonic-gate parse_filter(const char *str, int exceptflag) 710*7c478bd9Sstevel@tonic-gate { 711*7c478bd9Sstevel@tonic-gate struct server_filter *sfnew; 712*7c478bd9Sstevel@tonic-gate const char *cp; 713*7c478bd9Sstevel@tonic-gate const char *wordstart; 714*7c478bd9Sstevel@tonic-gate const char *wordend; 715*7c478bd9Sstevel@tonic-gate int len; 716*7c478bd9Sstevel@tonic-gate char hbuf[MAXHOSTNAMELEN]; 717*7c478bd9Sstevel@tonic-gate uchar_t *ucp; 718*7c478bd9Sstevel@tonic-gate uchar_t *mcp; 719*7c478bd9Sstevel@tonic-gate 720*7c478bd9Sstevel@tonic-gate /* Allocate the new filter structure. */ 721*7c478bd9Sstevel@tonic-gate sfnew = (struct server_filter *)calloc(1, sizeof (*sfnew)); 722*7c478bd9Sstevel@tonic-gate if (sfnew == NULL) { 723*7c478bd9Sstevel@tonic-gate logstrerror("filter allocation"); 724*7c478bd9Sstevel@tonic-gate exit(1); 725*7c478bd9Sstevel@tonic-gate } 726*7c478bd9Sstevel@tonic-gate 727*7c478bd9Sstevel@tonic-gate /* Save the string for AC-Name comparison. */ 728*7c478bd9Sstevel@tonic-gate sfnew->sf_name = str; 729*7c478bd9Sstevel@tonic-gate 730*7c478bd9Sstevel@tonic-gate sfnew->sf_isexcept = exceptflag == 0 ? 0 : 1; 731*7c478bd9Sstevel@tonic-gate 732*7c478bd9Sstevel@tonic-gate /* Extract just one word. */ 733*7c478bd9Sstevel@tonic-gate cp = str; 734*7c478bd9Sstevel@tonic-gate while (isspace(*cp)) 735*7c478bd9Sstevel@tonic-gate cp++; 736*7c478bd9Sstevel@tonic-gate wordstart = cp; 737*7c478bd9Sstevel@tonic-gate while (*cp != '\0' && !isspace(*cp)) 738*7c478bd9Sstevel@tonic-gate cp++; 739*7c478bd9Sstevel@tonic-gate wordend = cp; 740*7c478bd9Sstevel@tonic-gate if ((len = wordend - wordstart) >= sizeof (hbuf)) 741*7c478bd9Sstevel@tonic-gate len = sizeof (hbuf) - 1; 742*7c478bd9Sstevel@tonic-gate (void) strlcpy(hbuf, wordstart, len); 743*7c478bd9Sstevel@tonic-gate hbuf[len] = '\0'; 744*7c478bd9Sstevel@tonic-gate 745*7c478bd9Sstevel@tonic-gate /* Try to translate this as an Ethernet host or address. */ 746*7c478bd9Sstevel@tonic-gate mcp = sfnew->sf_mask.ether_addr_octet; 747*7c478bd9Sstevel@tonic-gate if (ether_hostton(hbuf, &sfnew->sf_mac) == 0) { 748*7c478bd9Sstevel@tonic-gate mcp[0] = mcp[1] = mcp[2] = mcp[3] = mcp[4] = mcp[5] = 0xFF; 749*7c478bd9Sstevel@tonic-gate sfnew->sf_hasmac = 1; 750*7c478bd9Sstevel@tonic-gate } else { 751*7c478bd9Sstevel@tonic-gate ucp = sfnew->sf_mac.ether_addr_octet; 752*7c478bd9Sstevel@tonic-gate len = wordend - wordstart; 753*7c478bd9Sstevel@tonic-gate cp = wordstart; 754*7c478bd9Sstevel@tonic-gate while (cp < wordend) { 755*7c478bd9Sstevel@tonic-gate if (ucp >= sfnew->sf_mac.ether_addr_octet + 756*7c478bd9Sstevel@tonic-gate sizeof (sfnew->sf_mac)) 757*7c478bd9Sstevel@tonic-gate break; 758*7c478bd9Sstevel@tonic-gate if (*cp == '*') { 759*7c478bd9Sstevel@tonic-gate *mcp++ = *ucp++ = 0; 760*7c478bd9Sstevel@tonic-gate cp++; 761*7c478bd9Sstevel@tonic-gate } else { 762*7c478bd9Sstevel@tonic-gate if (!isxdigit(*cp)) 763*7c478bd9Sstevel@tonic-gate break; 764*7c478bd9Sstevel@tonic-gate *ucp = hexdecode(*cp++); 765*7c478bd9Sstevel@tonic-gate if (cp < wordend && isxdigit(*cp)) { 766*7c478bd9Sstevel@tonic-gate *ucp = (*ucp << 4) | 767*7c478bd9Sstevel@tonic-gate hexdecode(*cp++); 768*7c478bd9Sstevel@tonic-gate } 769*7c478bd9Sstevel@tonic-gate ucp++; 770*7c478bd9Sstevel@tonic-gate *mcp++ = 0xFF; 771*7c478bd9Sstevel@tonic-gate } 772*7c478bd9Sstevel@tonic-gate if (cp < wordend) { 773*7c478bd9Sstevel@tonic-gate if (*cp != ':' || cp + 1 == wordend) 774*7c478bd9Sstevel@tonic-gate break; 775*7c478bd9Sstevel@tonic-gate cp++; 776*7c478bd9Sstevel@tonic-gate } 777*7c478bd9Sstevel@tonic-gate } 778*7c478bd9Sstevel@tonic-gate if (cp >= wordend) 779*7c478bd9Sstevel@tonic-gate sfnew->sf_hasmac = 1; 780*7c478bd9Sstevel@tonic-gate else if (verbose) 781*7c478bd9Sstevel@tonic-gate logerr("%s: treating '%.*s' as server " 782*7c478bd9Sstevel@tonic-gate "name only, not MAC address\n", myname, len, 783*7c478bd9Sstevel@tonic-gate wordstart); 784*7c478bd9Sstevel@tonic-gate } 785*7c478bd9Sstevel@tonic-gate 786*7c478bd9Sstevel@tonic-gate /* Add to end of list. */ 787*7c478bd9Sstevel@tonic-gate if (sftail == NULL) 788*7c478bd9Sstevel@tonic-gate sfhead = sfnew; 789*7c478bd9Sstevel@tonic-gate else 790*7c478bd9Sstevel@tonic-gate sftail->sf_next = sfnew; 791*7c478bd9Sstevel@tonic-gate sftail = sfnew; 792*7c478bd9Sstevel@tonic-gate } 793*7c478bd9Sstevel@tonic-gate 794*7c478bd9Sstevel@tonic-gate /* 795*7c478bd9Sstevel@tonic-gate * Create a copy of a given PPPoE message. This is used for enqueuing 796*7c478bd9Sstevel@tonic-gate * received PADO (offers) from possible servers. 797*7c478bd9Sstevel@tonic-gate */ 798*7c478bd9Sstevel@tonic-gate static poemsg_t * 799*7c478bd9Sstevel@tonic-gate save_message(const poemsg_t *pmsg) 800*7c478bd9Sstevel@tonic-gate { 801*7c478bd9Sstevel@tonic-gate poemsg_t *newmsg; 802*7c478bd9Sstevel@tonic-gate char *cp; 803*7c478bd9Sstevel@tonic-gate 804*7c478bd9Sstevel@tonic-gate newmsg = (poemsg_t *)malloc(sizeof (*pmsg) + pmsg->poemsg_len + 805*7c478bd9Sstevel@tonic-gate strlen(pmsg->poemsg_iname) + 1); 806*7c478bd9Sstevel@tonic-gate if (newmsg != NULL) { 807*7c478bd9Sstevel@tonic-gate newmsg->poemsg_next = NULL; 808*7c478bd9Sstevel@tonic-gate newmsg->poemsg_data = (const poep_t *)(newmsg + 1); 809*7c478bd9Sstevel@tonic-gate (void) memcpy(newmsg + 1, pmsg->poemsg_data, pmsg->poemsg_len); 810*7c478bd9Sstevel@tonic-gate newmsg->poemsg_len = pmsg->poemsg_len; 811*7c478bd9Sstevel@tonic-gate cp = (char *)newmsg->poemsg_data + pmsg->poemsg_len; 812*7c478bd9Sstevel@tonic-gate newmsg->poemsg_iname = (const char *)cp; 813*7c478bd9Sstevel@tonic-gate (void) strcpy(cp, pmsg->poemsg_iname); 814*7c478bd9Sstevel@tonic-gate (void) memcpy(&newmsg->poemsg_sender, &pmsg->poemsg_sender, 815*7c478bd9Sstevel@tonic-gate sizeof (newmsg->poemsg_sender)); 816*7c478bd9Sstevel@tonic-gate } 817*7c478bd9Sstevel@tonic-gate return (newmsg); 818*7c478bd9Sstevel@tonic-gate } 819*7c478bd9Sstevel@tonic-gate 820*7c478bd9Sstevel@tonic-gate /* 821*7c478bd9Sstevel@tonic-gate * Create and send a PPPoE Active Discovery Request (PADR) message to 822*7c478bd9Sstevel@tonic-gate * the sender of the given PADO. Some tags -- Service-Name, 823*7c478bd9Sstevel@tonic-gate * AC-Cookie, and Relay-Session-Id -- must be copied from PADO to 824*7c478bd9Sstevel@tonic-gate * PADR. Others are not. The Service-Name must be selected from the 825*7c478bd9Sstevel@tonic-gate * offered services in the PADO based on the user's requested service 826*7c478bd9Sstevel@tonic-gate * name. If the server offered "wildcard" service, then we ask for 827*7c478bd9Sstevel@tonic-gate * this only if we can't find the user's requested service. 828*7c478bd9Sstevel@tonic-gate * 829*7c478bd9Sstevel@tonic-gate * Returns 1 if we can't send a valid PADR in response to the given 830*7c478bd9Sstevel@tonic-gate * PADO. The offer should be ignored and the next one tried. 831*7c478bd9Sstevel@tonic-gate */ 832*7c478bd9Sstevel@tonic-gate static int 833*7c478bd9Sstevel@tonic-gate send_padr(poesm_t *psm, const poemsg_t *pado) 834*7c478bd9Sstevel@tonic-gate { 835*7c478bd9Sstevel@tonic-gate poep_t *poep; 836*7c478bd9Sstevel@tonic-gate boolean_t haswild; 837*7c478bd9Sstevel@tonic-gate boolean_t hassvc; 838*7c478bd9Sstevel@tonic-gate const uint8_t *tagp; 839*7c478bd9Sstevel@tonic-gate int ttyp; 840*7c478bd9Sstevel@tonic-gate int tlen; 841*7c478bd9Sstevel@tonic-gate 842*7c478bd9Sstevel@tonic-gate /* 843*7c478bd9Sstevel@tonic-gate * Increment sequence number for PADR so that we don't mistake 844*7c478bd9Sstevel@tonic-gate * old replies for valid ones if the server is very slow. 845*7c478bd9Sstevel@tonic-gate */ 846*7c478bd9Sstevel@tonic-gate psm->poesm_sequence++; 847*7c478bd9Sstevel@tonic-gate 848*7c478bd9Sstevel@tonic-gate poep = poe_mkheader(pkt_output, POECODE_PADR, 0); 849*7c478bd9Sstevel@tonic-gate (void) poe_two_longs(poep, POETT_UNIQ, psm->poesm_localid, 850*7c478bd9Sstevel@tonic-gate psm->poesm_sequence); 851*7c478bd9Sstevel@tonic-gate 852*7c478bd9Sstevel@tonic-gate haswild = B_FALSE; 853*7c478bd9Sstevel@tonic-gate hassvc = B_FALSE; 854*7c478bd9Sstevel@tonic-gate tagp = (const uint8_t *)(pado->poemsg_data + 1); 855*7c478bd9Sstevel@tonic-gate while (poe_tagcheck(pado->poemsg_data, pado->poemsg_len, tagp)) { 856*7c478bd9Sstevel@tonic-gate ttyp = POET_GET_TYPE(tagp); 857*7c478bd9Sstevel@tonic-gate if (ttyp == POETT_END) 858*7c478bd9Sstevel@tonic-gate break; 859*7c478bd9Sstevel@tonic-gate tlen = POET_GET_LENG(tagp); 860*7c478bd9Sstevel@tonic-gate switch (ttyp) { 861*7c478bd9Sstevel@tonic-gate case POETT_SERVICE: /* Service-Name */ 862*7c478bd9Sstevel@tonic-gate /* Allow only one */ 863*7c478bd9Sstevel@tonic-gate if (hassvc) 864*7c478bd9Sstevel@tonic-gate break; 865*7c478bd9Sstevel@tonic-gate if (tlen == 0) { 866*7c478bd9Sstevel@tonic-gate haswild = B_TRUE; 867*7c478bd9Sstevel@tonic-gate break; 868*7c478bd9Sstevel@tonic-gate } 869*7c478bd9Sstevel@tonic-gate if (service[0] == '\0' || 870*7c478bd9Sstevel@tonic-gate (tlen == strlen(service) && 871*7c478bd9Sstevel@tonic-gate memcmp(service, POET_DATA(tagp), tlen) == 0)) { 872*7c478bd9Sstevel@tonic-gate (void) poe_tag_copy(poep, tagp); 873*7c478bd9Sstevel@tonic-gate hassvc = B_TRUE; 874*7c478bd9Sstevel@tonic-gate } 875*7c478bd9Sstevel@tonic-gate break; 876*7c478bd9Sstevel@tonic-gate /* Ones we should discard */ 877*7c478bd9Sstevel@tonic-gate case POETT_ACCESS: /* AC-Name */ 878*7c478bd9Sstevel@tonic-gate case POETT_UNIQ: /* Host-Uniq */ 879*7c478bd9Sstevel@tonic-gate case POETT_NAMERR: /* Service-Name-Error */ 880*7c478bd9Sstevel@tonic-gate case POETT_SYSERR: /* AC-System-Error */ 881*7c478bd9Sstevel@tonic-gate case POETT_GENERR: /* Generic-Error */ 882*7c478bd9Sstevel@tonic-gate case POETT_HURL: /* Host-URL */ 883*7c478bd9Sstevel@tonic-gate case POETT_MOTM: /* Message-Of-The-Minute */ 884*7c478bd9Sstevel@tonic-gate case POETT_RTEADD: /* IP-Route-Add */ 885*7c478bd9Sstevel@tonic-gate case POETT_VENDOR: /* Vendor-Specific */ 886*7c478bd9Sstevel@tonic-gate case POETT_MULTI: /* Multicast-Capable */ 887*7c478bd9Sstevel@tonic-gate default: /* Anything else we don't understand */ 888*7c478bd9Sstevel@tonic-gate break; 889*7c478bd9Sstevel@tonic-gate /* Ones we should copy */ 890*7c478bd9Sstevel@tonic-gate case POETT_COOKIE: /* AC-Cookie */ 891*7c478bd9Sstevel@tonic-gate case POETT_RELAY: /* Relay-Session-Id */ 892*7c478bd9Sstevel@tonic-gate (void) poe_tag_copy(poep, tagp); 893*7c478bd9Sstevel@tonic-gate break; 894*7c478bd9Sstevel@tonic-gate } 895*7c478bd9Sstevel@tonic-gate tagp = POET_NEXT(tagp); 896*7c478bd9Sstevel@tonic-gate } 897*7c478bd9Sstevel@tonic-gate if (!hassvc) { 898*7c478bd9Sstevel@tonic-gate if (haswild) 899*7c478bd9Sstevel@tonic-gate (void) poe_add_str(poep, POETT_SERVICE, ""); 900*7c478bd9Sstevel@tonic-gate else 901*7c478bd9Sstevel@tonic-gate return (1); 902*7c478bd9Sstevel@tonic-gate } 903*7c478bd9Sstevel@tonic-gate 904*7c478bd9Sstevel@tonic-gate return (send_pppoe(poep, "PADR", &pado->poemsg_sender)); 905*7c478bd9Sstevel@tonic-gate } 906*7c478bd9Sstevel@tonic-gate 907*7c478bd9Sstevel@tonic-gate /* 908*7c478bd9Sstevel@tonic-gate * ******************************************************************** 909*7c478bd9Sstevel@tonic-gate * act_* functions implement the actions driven by the state machine 910*7c478bd9Sstevel@tonic-gate * tables. See "action_table" below. 911*7c478bd9Sstevel@tonic-gate * 912*7c478bd9Sstevel@tonic-gate * All action routines must return the next state value. 913*7c478bd9Sstevel@tonic-gate * ******************************************************************** 914*7c478bd9Sstevel@tonic-gate */ 915*7c478bd9Sstevel@tonic-gate 916*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 917*7c478bd9Sstevel@tonic-gate static int 918*7c478bd9Sstevel@tonic-gate act_none(poesm_t *psm, poemsg_t *pmsg, int event, int nextst) 919*7c478bd9Sstevel@tonic-gate { 920*7c478bd9Sstevel@tonic-gate return (nextst); 921*7c478bd9Sstevel@tonic-gate } 922*7c478bd9Sstevel@tonic-gate 923*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 924*7c478bd9Sstevel@tonic-gate static int 925*7c478bd9Sstevel@tonic-gate act_fail(poesm_t *psm, poemsg_t *pmsg, int event, int nextst) 926*7c478bd9Sstevel@tonic-gate { 927*7c478bd9Sstevel@tonic-gate if (verbose) 928*7c478bd9Sstevel@tonic-gate logerr("%s: unrecoverable error\n", myname); 929*7c478bd9Sstevel@tonic-gate return (PCSMS_DEAD); 930*7c478bd9Sstevel@tonic-gate } 931*7c478bd9Sstevel@tonic-gate 932*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 933*7c478bd9Sstevel@tonic-gate static int 934*7c478bd9Sstevel@tonic-gate act_spadi(poesm_t *psm, poemsg_t *pmsg, int event, int nextst) 935*7c478bd9Sstevel@tonic-gate { 936*7c478bd9Sstevel@tonic-gate if (send_padi(psm->poesm_localid) != 0) 937*7c478bd9Sstevel@tonic-gate return (PCSMS_DEAD); 938*7c478bd9Sstevel@tonic-gate /* 939*7c478bd9Sstevel@tonic-gate * If this is the first time, then initialize the retry count 940*7c478bd9Sstevel@tonic-gate * and interval. 941*7c478bd9Sstevel@tonic-gate */ 942*7c478bd9Sstevel@tonic-gate if (psm->poesm_state == PCSMS_DEAD) { 943*7c478bd9Sstevel@tonic-gate psm->poesm_count = 3; 944*7c478bd9Sstevel@tonic-gate psm->poesm_interval = pado_wait_time; 945*7c478bd9Sstevel@tonic-gate } else { 946*7c478bd9Sstevel@tonic-gate if ((psm->poesm_interval <<= 1) > RESTART_LIMIT) 947*7c478bd9Sstevel@tonic-gate psm->poesm_interval = RESTART_LIMIT; 948*7c478bd9Sstevel@tonic-gate } 949*7c478bd9Sstevel@tonic-gate psm->poesm_timer = psm->poesm_interval; 950*7c478bd9Sstevel@tonic-gate (void) gettimeofday(&tvstart, NULL); 951*7c478bd9Sstevel@tonic-gate return (nextst); 952*7c478bd9Sstevel@tonic-gate } 953*7c478bd9Sstevel@tonic-gate 954*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 955*7c478bd9Sstevel@tonic-gate static int 956*7c478bd9Sstevel@tonic-gate act_add(poesm_t *psm, poemsg_t *pmsg, int event, int nextst) 957*7c478bd9Sstevel@tonic-gate { 958*7c478bd9Sstevel@tonic-gate pmsg = save_message(pmsg); 959*7c478bd9Sstevel@tonic-gate if (pmsg != NULL) { 960*7c478bd9Sstevel@tonic-gate if (psm->poesm_lastoff == NULL) 961*7c478bd9Sstevel@tonic-gate psm->poesm_firstoff = pmsg; 962*7c478bd9Sstevel@tonic-gate else 963*7c478bd9Sstevel@tonic-gate psm->poesm_lastoff->poemsg_next = pmsg; 964*7c478bd9Sstevel@tonic-gate psm->poesm_lastoff = pmsg; 965*7c478bd9Sstevel@tonic-gate } 966*7c478bd9Sstevel@tonic-gate return (nextst); 967*7c478bd9Sstevel@tonic-gate } 968*7c478bd9Sstevel@tonic-gate 969*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 970*7c478bd9Sstevel@tonic-gate static int 971*7c478bd9Sstevel@tonic-gate act_spadr(poesm_t *psm, poemsg_t *pmsg, int event, int nextst) 972*7c478bd9Sstevel@tonic-gate { 973*7c478bd9Sstevel@tonic-gate poemsg_t *msgp; 974*7c478bd9Sstevel@tonic-gate int retv; 975*7c478bd9Sstevel@tonic-gate 976*7c478bd9Sstevel@tonic-gate for (;;) { 977*7c478bd9Sstevel@tonic-gate if ((msgp = psm->poesm_firstoff) == NULL) 978*7c478bd9Sstevel@tonic-gate return (PCSMS_DEAD); 979*7c478bd9Sstevel@tonic-gate retv = send_padr(psm, msgp); 980*7c478bd9Sstevel@tonic-gate if (retv < 0) 981*7c478bd9Sstevel@tonic-gate return (PCSMS_DEAD); 982*7c478bd9Sstevel@tonic-gate if (retv == 0) 983*7c478bd9Sstevel@tonic-gate break; 984*7c478bd9Sstevel@tonic-gate /* Can't send this request; try looking at next offer. */ 985*7c478bd9Sstevel@tonic-gate psm->poesm_firstoff = msgp->poemsg_next; 986*7c478bd9Sstevel@tonic-gate msgp->poemsg_next = psm->poesm_tried; 987*7c478bd9Sstevel@tonic-gate psm->poesm_tried = msgp; 988*7c478bd9Sstevel@tonic-gate } 989*7c478bd9Sstevel@tonic-gate if (psm->poesm_state != PCSMS_REQSENT) { 990*7c478bd9Sstevel@tonic-gate psm->poesm_count = 3; 991*7c478bd9Sstevel@tonic-gate psm->poesm_interval = pads_wait_time; 992*7c478bd9Sstevel@tonic-gate } else { 993*7c478bd9Sstevel@tonic-gate if ((psm->poesm_interval <<= 1) > RESTART_LIMIT) 994*7c478bd9Sstevel@tonic-gate psm->poesm_interval = RESTART_LIMIT; 995*7c478bd9Sstevel@tonic-gate } 996*7c478bd9Sstevel@tonic-gate psm->poesm_timer = psm->poesm_interval; 997*7c478bd9Sstevel@tonic-gate (void) gettimeofday(&tvstart, NULL); 998*7c478bd9Sstevel@tonic-gate return (nextst); 999*7c478bd9Sstevel@tonic-gate } 1000*7c478bd9Sstevel@tonic-gate 1001*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 1002*7c478bd9Sstevel@tonic-gate static int 1003*7c478bd9Sstevel@tonic-gate act_spadrp(poesm_t *psm, poemsg_t *pmsg, int event, int nextst) 1004*7c478bd9Sstevel@tonic-gate { 1005*7c478bd9Sstevel@tonic-gate int retv; 1006*7c478bd9Sstevel@tonic-gate 1007*7c478bd9Sstevel@tonic-gate retv = send_padr(psm, pmsg); 1008*7c478bd9Sstevel@tonic-gate if (retv < 0) 1009*7c478bd9Sstevel@tonic-gate return (PCSMS_DEAD); 1010*7c478bd9Sstevel@tonic-gate pmsg = save_message(pmsg); 1011*7c478bd9Sstevel@tonic-gate if (retv > 0) { 1012*7c478bd9Sstevel@tonic-gate /* 1013*7c478bd9Sstevel@tonic-gate * Cannot use this one; mark as tried and continue as 1014*7c478bd9Sstevel@tonic-gate * if we never saw it. 1015*7c478bd9Sstevel@tonic-gate */ 1016*7c478bd9Sstevel@tonic-gate pmsg->poemsg_next = psm->poesm_tried; 1017*7c478bd9Sstevel@tonic-gate psm->poesm_tried = pmsg; 1018*7c478bd9Sstevel@tonic-gate return (psm->poesm_state); 1019*7c478bd9Sstevel@tonic-gate } 1020*7c478bd9Sstevel@tonic-gate pmsg->poemsg_next = psm->poesm_firstoff; 1021*7c478bd9Sstevel@tonic-gate psm->poesm_firstoff = pmsg; 1022*7c478bd9Sstevel@tonic-gate if (psm->poesm_lastoff == NULL) 1023*7c478bd9Sstevel@tonic-gate psm->poesm_lastoff = pmsg; 1024*7c478bd9Sstevel@tonic-gate psm->poesm_count = 3; 1025*7c478bd9Sstevel@tonic-gate psm->poesm_timer = psm->poesm_interval = pads_wait_time; 1026*7c478bd9Sstevel@tonic-gate (void) gettimeofday(&tvstart, NULL); 1027*7c478bd9Sstevel@tonic-gate return (nextst); 1028*7c478bd9Sstevel@tonic-gate } 1029*7c478bd9Sstevel@tonic-gate 1030*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 1031*7c478bd9Sstevel@tonic-gate static int 1032*7c478bd9Sstevel@tonic-gate act_spadrn(poesm_t *psm, poemsg_t *pmsg, int event, int nextst) 1033*7c478bd9Sstevel@tonic-gate { 1034*7c478bd9Sstevel@tonic-gate poemsg_t *msgp; 1035*7c478bd9Sstevel@tonic-gate int retv; 1036*7c478bd9Sstevel@tonic-gate 1037*7c478bd9Sstevel@tonic-gate if ((msgp = psm->poesm_firstoff) == NULL) 1038*7c478bd9Sstevel@tonic-gate return (PCSMS_DEAD); 1039*7c478bd9Sstevel@tonic-gate do { 1040*7c478bd9Sstevel@tonic-gate psm->poesm_firstoff = msgp->poemsg_next; 1041*7c478bd9Sstevel@tonic-gate msgp->poemsg_next = psm->poesm_tried; 1042*7c478bd9Sstevel@tonic-gate psm->poesm_tried = msgp; 1043*7c478bd9Sstevel@tonic-gate if ((msgp = psm->poesm_firstoff) == NULL) 1044*7c478bd9Sstevel@tonic-gate return (PCSMS_DEAD); 1045*7c478bd9Sstevel@tonic-gate retv = send_padr(psm, msgp); 1046*7c478bd9Sstevel@tonic-gate if (retv < 0) 1047*7c478bd9Sstevel@tonic-gate return (PCSMS_DEAD); 1048*7c478bd9Sstevel@tonic-gate } while (retv != 0); 1049*7c478bd9Sstevel@tonic-gate psm->poesm_count = 3; 1050*7c478bd9Sstevel@tonic-gate psm->poesm_timer = psm->poesm_interval = pads_wait_time; 1051*7c478bd9Sstevel@tonic-gate (void) gettimeofday(&tvstart, NULL); 1052*7c478bd9Sstevel@tonic-gate return (nextst); 1053*7c478bd9Sstevel@tonic-gate } 1054*7c478bd9Sstevel@tonic-gate 1055*7c478bd9Sstevel@tonic-gate /* 1056*7c478bd9Sstevel@tonic-gate * For safety -- remove end of line from strings passed back to pppd. 1057*7c478bd9Sstevel@tonic-gate */ 1058*7c478bd9Sstevel@tonic-gate static void 1059*7c478bd9Sstevel@tonic-gate remove_eol(char *str, size_t len) 1060*7c478bd9Sstevel@tonic-gate { 1061*7c478bd9Sstevel@tonic-gate while (len > 0) { 1062*7c478bd9Sstevel@tonic-gate if (*str == '\n') 1063*7c478bd9Sstevel@tonic-gate *str = '$'; 1064*7c478bd9Sstevel@tonic-gate str++; 1065*7c478bd9Sstevel@tonic-gate len--; 1066*7c478bd9Sstevel@tonic-gate } 1067*7c478bd9Sstevel@tonic-gate } 1068*7c478bd9Sstevel@tonic-gate 1069*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 1070*7c478bd9Sstevel@tonic-gate static int 1071*7c478bd9Sstevel@tonic-gate act_open(poesm_t *psm, poemsg_t *pmsg, int event, int nextst) 1072*7c478bd9Sstevel@tonic-gate { 1073*7c478bd9Sstevel@tonic-gate struct ppptun_peer ptp; 1074*7c478bd9Sstevel@tonic-gate union ppptun_name ptn; 1075*7c478bd9Sstevel@tonic-gate const char *cp; 1076*7c478bd9Sstevel@tonic-gate FILE *fp; 1077*7c478bd9Sstevel@tonic-gate const uint8_t *tagp, *vp; 1078*7c478bd9Sstevel@tonic-gate int tlen, ttyp; 1079*7c478bd9Sstevel@tonic-gate char *access; 1080*7c478bd9Sstevel@tonic-gate uint32_t val; 1081*7c478bd9Sstevel@tonic-gate size_t acc_len, serv_len; 1082*7c478bd9Sstevel@tonic-gate 1083*7c478bd9Sstevel@tonic-gate /* 1084*7c478bd9Sstevel@tonic-gate * The server has now assigned its session ID for the data 1085*7c478bd9Sstevel@tonic-gate * (PPP) portion of this tunnel. Send that ID down to the 1086*7c478bd9Sstevel@tonic-gate * driver. 1087*7c478bd9Sstevel@tonic-gate */ 1088*7c478bd9Sstevel@tonic-gate (void) memset(&ptp, '\0', sizeof (ptp)); 1089*7c478bd9Sstevel@tonic-gate ptp.ptp_lsessid = psm->poesm_localid; 1090*7c478bd9Sstevel@tonic-gate ptp.ptp_rsessid = poe_session_id(pmsg->poemsg_data); 1091*7c478bd9Sstevel@tonic-gate (void) memcpy(&ptp.ptp_address, &pmsg->poemsg_sender, 1092*7c478bd9Sstevel@tonic-gate sizeof (ptp.ptp_address)); 1093*7c478bd9Sstevel@tonic-gate ptp.ptp_style = PTS_PPPOE; 1094*7c478bd9Sstevel@tonic-gate if (strioctl(tunfd, PPPTUN_SPEER, &ptp, sizeof (ptp), sizeof (ptp)) < 1095*7c478bd9Sstevel@tonic-gate 0) { 1096*7c478bd9Sstevel@tonic-gate logstrerror("PPPTUN_SPEER"); 1097*7c478bd9Sstevel@tonic-gate return (PCSMS_DEAD); 1098*7c478bd9Sstevel@tonic-gate } 1099*7c478bd9Sstevel@tonic-gate 1100*7c478bd9Sstevel@tonic-gate /* 1101*7c478bd9Sstevel@tonic-gate * Data communication is now possible on this session. 1102*7c478bd9Sstevel@tonic-gate * Connect the data portion to the correct lower stream. 1103*7c478bd9Sstevel@tonic-gate */ 1104*7c478bd9Sstevel@tonic-gate if ((cp = strchr(pmsg->poemsg_iname, ':')) == NULL) 1105*7c478bd9Sstevel@tonic-gate cp = pmsg->poemsg_iname + strlen(pmsg->poemsg_iname); 1106*7c478bd9Sstevel@tonic-gate (void) snprintf(ptn.ptn_name, sizeof (ptn.ptn_name), "%.*s:pppoe", 1107*7c478bd9Sstevel@tonic-gate cp - pmsg->poemsg_iname, pmsg->poemsg_iname); 1108*7c478bd9Sstevel@tonic-gate if (strioctl(tunfd, PPPTUN_SDATA, &ptn, sizeof (ptn), 0) < 0) { 1109*7c478bd9Sstevel@tonic-gate logerr("%s: PPPTUN_SDATA %s: %s\n", 1110*7c478bd9Sstevel@tonic-gate myname, ptn.ptn_name, mystrerror(errno)); 1111*7c478bd9Sstevel@tonic-gate return (PCSMS_DEAD); 1112*7c478bd9Sstevel@tonic-gate } 1113*7c478bd9Sstevel@tonic-gate if (verbose) 1114*7c478bd9Sstevel@tonic-gate logerr("%s: Connection open; session %04X on " 1115*7c478bd9Sstevel@tonic-gate "%s\n", myname, ptp.ptp_rsessid, ptn.ptn_name); 1116*7c478bd9Sstevel@tonic-gate 1117*7c478bd9Sstevel@tonic-gate /* 1118*7c478bd9Sstevel@tonic-gate * Walk through the PADS message to get the access server name 1119*7c478bd9Sstevel@tonic-gate * and the service. If there are multiple instances of either 1120*7c478bd9Sstevel@tonic-gate * tag, then take the last access server and the first 1121*7c478bd9Sstevel@tonic-gate * non-null service. 1122*7c478bd9Sstevel@tonic-gate */ 1123*7c478bd9Sstevel@tonic-gate access = ""; 1124*7c478bd9Sstevel@tonic-gate acc_len = 0; 1125*7c478bd9Sstevel@tonic-gate serv_len = strlen(service); 1126*7c478bd9Sstevel@tonic-gate tagp = (const uint8_t *)(pmsg->poemsg_data + 1); 1127*7c478bd9Sstevel@tonic-gate while (poe_tagcheck(pmsg->poemsg_data, pmsg->poemsg_len, tagp)) { 1128*7c478bd9Sstevel@tonic-gate ttyp = POET_GET_TYPE(tagp); 1129*7c478bd9Sstevel@tonic-gate if (ttyp == POETT_END) 1130*7c478bd9Sstevel@tonic-gate break; 1131*7c478bd9Sstevel@tonic-gate tlen = POET_GET_LENG(tagp); 1132*7c478bd9Sstevel@tonic-gate if (ttyp == POETT_ACCESS) { 1133*7c478bd9Sstevel@tonic-gate access = (char *)POET_DATA(tagp); 1134*7c478bd9Sstevel@tonic-gate acc_len = tlen; 1135*7c478bd9Sstevel@tonic-gate } 1136*7c478bd9Sstevel@tonic-gate if (serv_len == 0 && ttyp == POETT_SERVICE && tlen != 0) { 1137*7c478bd9Sstevel@tonic-gate service = (char *)POET_DATA(tagp); 1138*7c478bd9Sstevel@tonic-gate serv_len = tlen; 1139*7c478bd9Sstevel@tonic-gate } 1140*7c478bd9Sstevel@tonic-gate tagp = POET_NEXT(tagp); 1141*7c478bd9Sstevel@tonic-gate } 1142*7c478bd9Sstevel@tonic-gate 1143*7c478bd9Sstevel@tonic-gate /* 1144*7c478bd9Sstevel@tonic-gate * Remove end of line to make sure that integrity of values 1145*7c478bd9Sstevel@tonic-gate * passed back to pppd can't be compromised by the PPPoE 1146*7c478bd9Sstevel@tonic-gate * server. 1147*7c478bd9Sstevel@tonic-gate */ 1148*7c478bd9Sstevel@tonic-gate remove_eol(service, serv_len); 1149*7c478bd9Sstevel@tonic-gate remove_eol(access, acc_len); 1150*7c478bd9Sstevel@tonic-gate 1151*7c478bd9Sstevel@tonic-gate /* 1152*7c478bd9Sstevel@tonic-gate * pppd has given us a pipe as fd 3, and we're expected to 1153*7c478bd9Sstevel@tonic-gate * write out the values of the following environment 1154*7c478bd9Sstevel@tonic-gate * variables: 1155*7c478bd9Sstevel@tonic-gate * IF_AND_SERVICE 1156*7c478bd9Sstevel@tonic-gate * SERVICE_NAME 1157*7c478bd9Sstevel@tonic-gate * AC_NAME 1158*7c478bd9Sstevel@tonic-gate * AC_MAC 1159*7c478bd9Sstevel@tonic-gate * SESSION_ID 1160*7c478bd9Sstevel@tonic-gate * VENDOR_SPECIFIC_1 ... N 1161*7c478bd9Sstevel@tonic-gate * See usr.bin/pppd/plugins/pppoe.c for more information. 1162*7c478bd9Sstevel@tonic-gate */ 1163*7c478bd9Sstevel@tonic-gate if ((fp = fdopen(3, "w")) != NULL) { 1164*7c478bd9Sstevel@tonic-gate (void) fprintf(fp, "%.*s:%.*s\n", 1165*7c478bd9Sstevel@tonic-gate cp - pmsg->poemsg_iname, pmsg->poemsg_iname, serv_len, 1166*7c478bd9Sstevel@tonic-gate service); 1167*7c478bd9Sstevel@tonic-gate (void) fprintf(fp, "%.*s\n", serv_len, service); 1168*7c478bd9Sstevel@tonic-gate (void) fprintf(fp, "%.*s\n", acc_len, access); 1169*7c478bd9Sstevel@tonic-gate (void) fprintf(fp, "%s\n", ehost(&pmsg->poemsg_sender)); 1170*7c478bd9Sstevel@tonic-gate (void) fprintf(fp, "%d\n", poe_session_id(pmsg->poemsg_data)); 1171*7c478bd9Sstevel@tonic-gate tagp = (const uint8_t *)(pmsg->poemsg_data + 1); 1172*7c478bd9Sstevel@tonic-gate while (poe_tagcheck(pmsg->poemsg_data, pmsg->poemsg_len, 1173*7c478bd9Sstevel@tonic-gate tagp)) { 1174*7c478bd9Sstevel@tonic-gate ttyp = POET_GET_TYPE(tagp); 1175*7c478bd9Sstevel@tonic-gate if (ttyp == POETT_END) 1176*7c478bd9Sstevel@tonic-gate break; 1177*7c478bd9Sstevel@tonic-gate tlen = POET_GET_LENG(tagp); 1178*7c478bd9Sstevel@tonic-gate if (ttyp == POETT_VENDOR && tlen >= 4) { 1179*7c478bd9Sstevel@tonic-gate (void) memcpy(&val, POET_DATA(tagp), 4); 1180*7c478bd9Sstevel@tonic-gate (void) fprintf(fp, "%08lX:", 1181*7c478bd9Sstevel@tonic-gate (unsigned long)ntohl(val)); 1182*7c478bd9Sstevel@tonic-gate tlen -= 4; 1183*7c478bd9Sstevel@tonic-gate vp = POET_DATA(tagp) + 4; 1184*7c478bd9Sstevel@tonic-gate while (--tlen >= 0) 1185*7c478bd9Sstevel@tonic-gate (void) fprintf(fp, "%02X", *vp++); 1186*7c478bd9Sstevel@tonic-gate (void) putc('\n', fp); 1187*7c478bd9Sstevel@tonic-gate } 1188*7c478bd9Sstevel@tonic-gate tagp = POET_NEXT(tagp); 1189*7c478bd9Sstevel@tonic-gate } 1190*7c478bd9Sstevel@tonic-gate (void) fclose(fp); 1191*7c478bd9Sstevel@tonic-gate } 1192*7c478bd9Sstevel@tonic-gate 1193*7c478bd9Sstevel@tonic-gate return (nextst); 1194*7c478bd9Sstevel@tonic-gate } 1195*7c478bd9Sstevel@tonic-gate 1196*7c478bd9Sstevel@tonic-gate static int (* const action_table[PCSMA__MAX])(poesm_t *psm, poemsg_t *pmsg, 1197*7c478bd9Sstevel@tonic-gate int event, int nextst) = { 1198*7c478bd9Sstevel@tonic-gate act_none, act_fail, act_spadi, act_add, act_spadr, act_spadrp, 1199*7c478bd9Sstevel@tonic-gate act_spadrn, act_open 1200*7c478bd9Sstevel@tonic-gate }; 1201*7c478bd9Sstevel@tonic-gate 1202*7c478bd9Sstevel@tonic-gate /* 1203*7c478bd9Sstevel@tonic-gate * Dispatch an event and a corresponding message on a given state 1204*7c478bd9Sstevel@tonic-gate * machine. 1205*7c478bd9Sstevel@tonic-gate */ 1206*7c478bd9Sstevel@tonic-gate static void 1207*7c478bd9Sstevel@tonic-gate handle_event(poesm_t *psm, int event, poemsg_t *pmsg) 1208*7c478bd9Sstevel@tonic-gate { 1209*7c478bd9Sstevel@tonic-gate int nextst; 1210*7c478bd9Sstevel@tonic-gate 1211*7c478bd9Sstevel@tonic-gate if (verbose) 1212*7c478bd9Sstevel@tonic-gate logerr("%s: PPPoE Event %s (%d) in state %s " 1213*7c478bd9Sstevel@tonic-gate "(%d): action %s (%d)\n", myname, poe_event(event), event, 1214*7c478bd9Sstevel@tonic-gate poe_state(psm->poesm_state), psm->poesm_state, 1215*7c478bd9Sstevel@tonic-gate poe_action(client_action[psm->poesm_state][event]), 1216*7c478bd9Sstevel@tonic-gate client_action[psm->poesm_state][event]); 1217*7c478bd9Sstevel@tonic-gate 1218*7c478bd9Sstevel@tonic-gate nextst = (*action_table[client_action[psm->poesm_state][event]])(psm, 1219*7c478bd9Sstevel@tonic-gate pmsg, event, client_next_state[psm->poesm_state][event]); 1220*7c478bd9Sstevel@tonic-gate 1221*7c478bd9Sstevel@tonic-gate if (verbose) 1222*7c478bd9Sstevel@tonic-gate logerr("%s: PPPoE State change %s (%d) -> %s (%d)\n", myname, 1223*7c478bd9Sstevel@tonic-gate poe_state(psm->poesm_state), psm->poesm_state, 1224*7c478bd9Sstevel@tonic-gate poe_state(nextst), nextst); 1225*7c478bd9Sstevel@tonic-gate 1226*7c478bd9Sstevel@tonic-gate psm->poesm_state = nextst; 1227*7c478bd9Sstevel@tonic-gate 1228*7c478bd9Sstevel@tonic-gate /* 1229*7c478bd9Sstevel@tonic-gate * Life-altering states are handled here. If we reach dead 1230*7c478bd9Sstevel@tonic-gate * state again after starting, then we failed. If we reach 1231*7c478bd9Sstevel@tonic-gate * conversational state, then we're open. 1232*7c478bd9Sstevel@tonic-gate */ 1233*7c478bd9Sstevel@tonic-gate if (nextst == PCSMS_DEAD) { 1234*7c478bd9Sstevel@tonic-gate if (verbose) 1235*7c478bd9Sstevel@tonic-gate logerr("%s: action failed\n", myname); 1236*7c478bd9Sstevel@tonic-gate exit(1); 1237*7c478bd9Sstevel@tonic-gate } 1238*7c478bd9Sstevel@tonic-gate if (nextst == PCSMS_CONVERS) { 1239*7c478bd9Sstevel@tonic-gate if (verbose) 1240*7c478bd9Sstevel@tonic-gate logerr("%s: connected\n", myname); 1241*7c478bd9Sstevel@tonic-gate exit(0); 1242*7c478bd9Sstevel@tonic-gate } 1243*7c478bd9Sstevel@tonic-gate } 1244*7c478bd9Sstevel@tonic-gate 1245*7c478bd9Sstevel@tonic-gate /* 1246*7c478bd9Sstevel@tonic-gate * Check for error message tags in the PPPoE packet. We must ignore 1247*7c478bd9Sstevel@tonic-gate * offers that merely report errors, and need to log errors in any 1248*7c478bd9Sstevel@tonic-gate * case. 1249*7c478bd9Sstevel@tonic-gate */ 1250*7c478bd9Sstevel@tonic-gate static int 1251*7c478bd9Sstevel@tonic-gate error_check(poemsg_t *pmsg) 1252*7c478bd9Sstevel@tonic-gate { 1253*7c478bd9Sstevel@tonic-gate const uint8_t *tagp; 1254*7c478bd9Sstevel@tonic-gate int ttyp; 1255*7c478bd9Sstevel@tonic-gate 1256*7c478bd9Sstevel@tonic-gate tagp = (const uint8_t *)(pmsg->poemsg_data + 1); 1257*7c478bd9Sstevel@tonic-gate while (poe_tagcheck(pmsg->poemsg_data, pmsg->poemsg_len, tagp)) { 1258*7c478bd9Sstevel@tonic-gate ttyp = POET_GET_TYPE(tagp); 1259*7c478bd9Sstevel@tonic-gate if (ttyp == POETT_END) 1260*7c478bd9Sstevel@tonic-gate break; 1261*7c478bd9Sstevel@tonic-gate if (ttyp == POETT_NAMERR || ttyp == POETT_SYSERR || 1262*7c478bd9Sstevel@tonic-gate ttyp == POETT_GENERR) { 1263*7c478bd9Sstevel@tonic-gate if (verbose) 1264*7c478bd9Sstevel@tonic-gate display_pppoe(stderr, pmsg->poemsg_data, 1265*7c478bd9Sstevel@tonic-gate pmsg->poemsg_len, &pmsg->poemsg_sender); 1266*7c478bd9Sstevel@tonic-gate return (-1); 1267*7c478bd9Sstevel@tonic-gate } 1268*7c478bd9Sstevel@tonic-gate tagp = POET_NEXT(tagp); 1269*7c478bd9Sstevel@tonic-gate } 1270*7c478bd9Sstevel@tonic-gate return (0); 1271*7c478bd9Sstevel@tonic-gate } 1272*7c478bd9Sstevel@tonic-gate 1273*7c478bd9Sstevel@tonic-gate /* 1274*7c478bd9Sstevel@tonic-gate * Extract sequence number, if any, from PADS message, so that we can 1275*7c478bd9Sstevel@tonic-gate * relate it to the PADR that we sent. 1276*7c478bd9Sstevel@tonic-gate */ 1277*7c478bd9Sstevel@tonic-gate static uint32_t 1278*7c478bd9Sstevel@tonic-gate get_sequence(const poemsg_t *pmsg) 1279*7c478bd9Sstevel@tonic-gate { 1280*7c478bd9Sstevel@tonic-gate const uint8_t *tagp; 1281*7c478bd9Sstevel@tonic-gate int ttyp; 1282*7c478bd9Sstevel@tonic-gate uint32_t vals[2]; 1283*7c478bd9Sstevel@tonic-gate 1284*7c478bd9Sstevel@tonic-gate tagp = (const uint8_t *)(pmsg->poemsg_data + 1); 1285*7c478bd9Sstevel@tonic-gate while (poe_tagcheck(pmsg->poemsg_data, pmsg->poemsg_len, tagp)) { 1286*7c478bd9Sstevel@tonic-gate ttyp = POET_GET_TYPE(tagp); 1287*7c478bd9Sstevel@tonic-gate if (ttyp == POETT_END) 1288*7c478bd9Sstevel@tonic-gate break; 1289*7c478bd9Sstevel@tonic-gate if (ttyp == POETT_UNIQ) { 1290*7c478bd9Sstevel@tonic-gate if (POET_GET_LENG(tagp) < sizeof (vals)) 1291*7c478bd9Sstevel@tonic-gate break; 1292*7c478bd9Sstevel@tonic-gate (void) memcpy(vals, POET_DATA(tagp), sizeof (vals)); 1293*7c478bd9Sstevel@tonic-gate return (ntohl(vals[1])); 1294*7c478bd9Sstevel@tonic-gate } 1295*7c478bd9Sstevel@tonic-gate tagp = POET_NEXT(tagp); 1296*7c478bd9Sstevel@tonic-gate } 1297*7c478bd9Sstevel@tonic-gate return (0); 1298*7c478bd9Sstevel@tonic-gate } 1299*7c478bd9Sstevel@tonic-gate 1300*7c478bd9Sstevel@tonic-gate /* 1301*7c478bd9Sstevel@tonic-gate * Server filter cases: 1302*7c478bd9Sstevel@tonic-gate * 1303*7c478bd9Sstevel@tonic-gate * No filters -- all servers generate RPADO+ event; select the 1304*7c478bd9Sstevel@tonic-gate * first responding server. 1305*7c478bd9Sstevel@tonic-gate * 1306*7c478bd9Sstevel@tonic-gate * Only "except" filters -- matching servers are RPADO, others 1307*7c478bd9Sstevel@tonic-gate * are RPADO+. 1308*7c478bd9Sstevel@tonic-gate * 1309*7c478bd9Sstevel@tonic-gate * Mix of filters -- those matching "pass" are RPADO+, those 1310*7c478bd9Sstevel@tonic-gate * matching "except" are RPADO, and all others are also RPADO. 1311*7c478bd9Sstevel@tonic-gate * 1312*7c478bd9Sstevel@tonic-gate * If the "only" keyword was given, then RPADO becomes -1; only RPADO+ 1313*7c478bd9Sstevel@tonic-gate * events occur. 1314*7c478bd9Sstevel@tonic-gate */ 1315*7c478bd9Sstevel@tonic-gate static int 1316*7c478bd9Sstevel@tonic-gate use_server(poemsg_t *pado) 1317*7c478bd9Sstevel@tonic-gate { 1318*7c478bd9Sstevel@tonic-gate struct server_filter *sfp; 1319*7c478bd9Sstevel@tonic-gate const uchar_t *sndp; 1320*7c478bd9Sstevel@tonic-gate const uchar_t *macp; 1321*7c478bd9Sstevel@tonic-gate const uchar_t *maskp; 1322*7c478bd9Sstevel@tonic-gate int i; 1323*7c478bd9Sstevel@tonic-gate int passmatched; 1324*7c478bd9Sstevel@tonic-gate const uint8_t *tagp; 1325*7c478bd9Sstevel@tonic-gate int ttyp; 1326*7c478bd9Sstevel@tonic-gate 1327*7c478bd9Sstevel@tonic-gate /* 1328*7c478bd9Sstevel@tonic-gate * If no service mentioned in offer, then we can't use it. 1329*7c478bd9Sstevel@tonic-gate */ 1330*7c478bd9Sstevel@tonic-gate tagp = (const uint8_t *)(pado->poemsg_data + 1); 1331*7c478bd9Sstevel@tonic-gate ttyp = POETT_END; 1332*7c478bd9Sstevel@tonic-gate while (poe_tagcheck(pado->poemsg_data, pado->poemsg_len, tagp)) { 1333*7c478bd9Sstevel@tonic-gate ttyp = POET_GET_TYPE(tagp); 1334*7c478bd9Sstevel@tonic-gate if (ttyp == POETT_END || ttyp == POETT_SERVICE) 1335*7c478bd9Sstevel@tonic-gate break; 1336*7c478bd9Sstevel@tonic-gate tagp = POET_NEXT(tagp); 1337*7c478bd9Sstevel@tonic-gate } 1338*7c478bd9Sstevel@tonic-gate if (ttyp != POETT_SERVICE) 1339*7c478bd9Sstevel@tonic-gate return (-1); 1340*7c478bd9Sstevel@tonic-gate 1341*7c478bd9Sstevel@tonic-gate passmatched = 0; 1342*7c478bd9Sstevel@tonic-gate for (sfp = sfhead; sfp != NULL; sfp = sfp->sf_next) { 1343*7c478bd9Sstevel@tonic-gate passmatched |= !sfp->sf_isexcept; 1344*7c478bd9Sstevel@tonic-gate if (sfp->sf_hasmac) { 1345*7c478bd9Sstevel@tonic-gate sndp = pado->poemsg_sender.pta_pppoe.ptma_mac; 1346*7c478bd9Sstevel@tonic-gate macp = sfp->sf_mac.ether_addr_octet; 1347*7c478bd9Sstevel@tonic-gate maskp = sfp->sf_mask.ether_addr_octet; 1348*7c478bd9Sstevel@tonic-gate i = sizeof (pado->poemsg_sender.pta_pppoe.ptma_mac); 1349*7c478bd9Sstevel@tonic-gate for (; i > 0; i--) 1350*7c478bd9Sstevel@tonic-gate if (((*macp++ ^ *sndp++) & *maskp++) != 0) 1351*7c478bd9Sstevel@tonic-gate break; 1352*7c478bd9Sstevel@tonic-gate if (i <= 0) 1353*7c478bd9Sstevel@tonic-gate break; 1354*7c478bd9Sstevel@tonic-gate } 1355*7c478bd9Sstevel@tonic-gate } 1356*7c478bd9Sstevel@tonic-gate 1357*7c478bd9Sstevel@tonic-gate if (sfp == NULL) { 1358*7c478bd9Sstevel@tonic-gate /* 1359*7c478bd9Sstevel@tonic-gate * No match encountered; if only exclude rules have 1360*7c478bd9Sstevel@tonic-gate * been seen, then accept this offer. 1361*7c478bd9Sstevel@tonic-gate */ 1362*7c478bd9Sstevel@tonic-gate if (!passmatched) 1363*7c478bd9Sstevel@tonic-gate return (PCSME_RPADOP); 1364*7c478bd9Sstevel@tonic-gate } else { 1365*7c478bd9Sstevel@tonic-gate if (!sfp->sf_isexcept) 1366*7c478bd9Sstevel@tonic-gate return (PCSME_RPADOP); 1367*7c478bd9Sstevel@tonic-gate } 1368*7c478bd9Sstevel@tonic-gate if (onlyflag) 1369*7c478bd9Sstevel@tonic-gate return (-1); 1370*7c478bd9Sstevel@tonic-gate return (PCSME_RPADO); 1371*7c478bd9Sstevel@tonic-gate } 1372*7c478bd9Sstevel@tonic-gate 1373*7c478bd9Sstevel@tonic-gate /* 1374*7c478bd9Sstevel@tonic-gate * This is the normal event loop. It initializes the state machine 1375*7c478bd9Sstevel@tonic-gate * and sends in an Open event to kick things off. Then it drops into 1376*7c478bd9Sstevel@tonic-gate * a loop to dispatch events for the state machine. 1377*7c478bd9Sstevel@tonic-gate */ 1378*7c478bd9Sstevel@tonic-gate static void 1379*7c478bd9Sstevel@tonic-gate find_server(int localid) 1380*7c478bd9Sstevel@tonic-gate { 1381*7c478bd9Sstevel@tonic-gate poesm_t psm; 1382*7c478bd9Sstevel@tonic-gate struct pollfd pfd[1]; 1383*7c478bd9Sstevel@tonic-gate struct timeval tv, tvnow; 1384*7c478bd9Sstevel@tonic-gate int retv; 1385*7c478bd9Sstevel@tonic-gate poemsg_t pmsg; 1386*7c478bd9Sstevel@tonic-gate struct strbuf ctrl; 1387*7c478bd9Sstevel@tonic-gate struct strbuf data; 1388*7c478bd9Sstevel@tonic-gate poep_t *poep; 1389*7c478bd9Sstevel@tonic-gate int flags; 1390*7c478bd9Sstevel@tonic-gate uint32_t seqval; 1391*7c478bd9Sstevel@tonic-gate struct ppptun_control *ptc; 1392*7c478bd9Sstevel@tonic-gate 1393*7c478bd9Sstevel@tonic-gate (void) memset(&psm, '\0', sizeof (psm)); 1394*7c478bd9Sstevel@tonic-gate 1395*7c478bd9Sstevel@tonic-gate /* 1396*7c478bd9Sstevel@tonic-gate * Initialize the sequence number with something handy. It 1397*7c478bd9Sstevel@tonic-gate * doesn't need to be absolutely unique, since the localid 1398*7c478bd9Sstevel@tonic-gate * value actually demultiplexes everything. This just makes 1399*7c478bd9Sstevel@tonic-gate * the operation a little safer. 1400*7c478bd9Sstevel@tonic-gate */ 1401*7c478bd9Sstevel@tonic-gate psm.poesm_sequence = getpid() << 16; 1402*7c478bd9Sstevel@tonic-gate psm.poesm_localid = localid; 1403*7c478bd9Sstevel@tonic-gate 1404*7c478bd9Sstevel@tonic-gate /* Start the state machine */ 1405*7c478bd9Sstevel@tonic-gate handle_event(&psm, PCSME_OPEN, NULL); 1406*7c478bd9Sstevel@tonic-gate 1407*7c478bd9Sstevel@tonic-gate /* Enter event polling loop. */ 1408*7c478bd9Sstevel@tonic-gate pfd[0].fd = tunfd; 1409*7c478bd9Sstevel@tonic-gate pfd[0].events = POLLIN; 1410*7c478bd9Sstevel@tonic-gate for (;;) { 1411*7c478bd9Sstevel@tonic-gate /* Wait for timeout or message */ 1412*7c478bd9Sstevel@tonic-gate retv = poll(pfd, 1, psm.poesm_timer > 0 ? psm.poesm_timer : 1413*7c478bd9Sstevel@tonic-gate INFTIM); 1414*7c478bd9Sstevel@tonic-gate if (retv < 0) { 1415*7c478bd9Sstevel@tonic-gate logstrerror("poll"); 1416*7c478bd9Sstevel@tonic-gate break; 1417*7c478bd9Sstevel@tonic-gate } 1418*7c478bd9Sstevel@tonic-gate 1419*7c478bd9Sstevel@tonic-gate /* Handle a timeout */ 1420*7c478bd9Sstevel@tonic-gate if (retv == 0) { 1421*7c478bd9Sstevel@tonic-gate psm.poesm_timer = 0; 1422*7c478bd9Sstevel@tonic-gate handle_event(&psm, --psm.poesm_count > 0 ? PCSME_TOP : 1423*7c478bd9Sstevel@tonic-gate PCSME_TOM, NULL); 1424*7c478bd9Sstevel@tonic-gate continue; 1425*7c478bd9Sstevel@tonic-gate } 1426*7c478bd9Sstevel@tonic-gate 1427*7c478bd9Sstevel@tonic-gate /* Adjust the timer for the time we slept. */ 1428*7c478bd9Sstevel@tonic-gate if (psm.poesm_timer > 0) { 1429*7c478bd9Sstevel@tonic-gate (void) gettimeofday(&tvnow, NULL); 1430*7c478bd9Sstevel@tonic-gate tv = tvnow; 1431*7c478bd9Sstevel@tonic-gate if ((tv.tv_sec -= tvstart.tv_sec) < 0) { 1432*7c478bd9Sstevel@tonic-gate /* Darn */ 1433*7c478bd9Sstevel@tonic-gate tv.tv_sec = 1; 1434*7c478bd9Sstevel@tonic-gate tv.tv_usec = 0; 1435*7c478bd9Sstevel@tonic-gate } else if ((tv.tv_usec -= tvstart.tv_usec) < 0) { 1436*7c478bd9Sstevel@tonic-gate tv.tv_usec += 1000000; 1437*7c478bd9Sstevel@tonic-gate if (--tv.tv_sec < 0) 1438*7c478bd9Sstevel@tonic-gate tv.tv_sec = 0; 1439*7c478bd9Sstevel@tonic-gate } 1440*7c478bd9Sstevel@tonic-gate psm.poesm_timer -= tv.tv_sec*1000 + tv.tv_usec/1000; 1441*7c478bd9Sstevel@tonic-gate tvstart = tvnow; 1442*7c478bd9Sstevel@tonic-gate } 1443*7c478bd9Sstevel@tonic-gate 1444*7c478bd9Sstevel@tonic-gate /* Read in the message from the server. */ 1445*7c478bd9Sstevel@tonic-gate ctrl.maxlen = PKT_OCTL_LEN; 1446*7c478bd9Sstevel@tonic-gate ctrl.buf = (caddr_t)pkt_octl; 1447*7c478bd9Sstevel@tonic-gate data.maxlen = PKT_INPUT_LEN; 1448*7c478bd9Sstevel@tonic-gate data.buf = (caddr_t)pkt_input; 1449*7c478bd9Sstevel@tonic-gate flags = 0; 1450*7c478bd9Sstevel@tonic-gate 1451*7c478bd9Sstevel@tonic-gate if (pppoec_getmsg(tunfd, &ctrl, &data, &flags) < 0) 1452*7c478bd9Sstevel@tonic-gate break; 1453*7c478bd9Sstevel@tonic-gate 1454*7c478bd9Sstevel@tonic-gate if (ctrl.len != sizeof (*ptc)) { 1455*7c478bd9Sstevel@tonic-gate if (verbose) 1456*7c478bd9Sstevel@tonic-gate logerr("%s: discard: ctrl len %d\n", myname, 1457*7c478bd9Sstevel@tonic-gate ctrl.len); 1458*7c478bd9Sstevel@tonic-gate continue; 1459*7c478bd9Sstevel@tonic-gate } 1460*7c478bd9Sstevel@tonic-gate poep = (poep_t *)pkt_input; 1461*7c478bd9Sstevel@tonic-gate (void) memset(&pmsg, '\0', sizeof (pmsg)); 1462*7c478bd9Sstevel@tonic-gate pmsg.poemsg_next = NULL; 1463*7c478bd9Sstevel@tonic-gate pmsg.poemsg_data = poep; 1464*7c478bd9Sstevel@tonic-gate pmsg.poemsg_len = data.len; 1465*7c478bd9Sstevel@tonic-gate ptc = (struct ppptun_control *)pkt_octl; 1466*7c478bd9Sstevel@tonic-gate if (ptc->ptc_action != PTCA_CONTROL) { 1467*7c478bd9Sstevel@tonic-gate if (verbose) 1468*7c478bd9Sstevel@tonic-gate logerr("%s: discard: unexpected action %d\n", 1469*7c478bd9Sstevel@tonic-gate myname, ptc->ptc_action); 1470*7c478bd9Sstevel@tonic-gate continue; 1471*7c478bd9Sstevel@tonic-gate } 1472*7c478bd9Sstevel@tonic-gate pmsg.poemsg_iname = ptc->ptc_name; 1473*7c478bd9Sstevel@tonic-gate if (verbose) 1474*7c478bd9Sstevel@tonic-gate logerr("%s: Received %s from %s/%s\n", 1475*7c478bd9Sstevel@tonic-gate myname, poe_codename(poep->poep_code), 1476*7c478bd9Sstevel@tonic-gate ehost(&ptc->ptc_address), pmsg.poemsg_iname); 1477*7c478bd9Sstevel@tonic-gate pmsg.poemsg_sender = ptc->ptc_address; 1478*7c478bd9Sstevel@tonic-gate 1479*7c478bd9Sstevel@tonic-gate /* Check for messages from unexpected peers. */ 1480*7c478bd9Sstevel@tonic-gate if ((poep->poep_code == POECODE_PADT || 1481*7c478bd9Sstevel@tonic-gate poep->poep_code == POECODE_PADS) && 1482*7c478bd9Sstevel@tonic-gate (psm.poesm_firstoff == NULL || 1483*7c478bd9Sstevel@tonic-gate memcmp(&psm.poesm_firstoff->poemsg_sender, 1484*7c478bd9Sstevel@tonic-gate &pmsg.poemsg_sender, 1485*7c478bd9Sstevel@tonic-gate sizeof (pmsg.poemsg_sender)) != 0)) { 1486*7c478bd9Sstevel@tonic-gate if (verbose) { 1487*7c478bd9Sstevel@tonic-gate logerr("%s: Unexpected peer %s", myname, 1488*7c478bd9Sstevel@tonic-gate ehost(&ptc->ptc_address)); 1489*7c478bd9Sstevel@tonic-gate logerr(" != %s\n", 1490*7c478bd9Sstevel@tonic-gate ehost(&psm.poesm_firstoff->poemsg_sender)); 1491*7c478bd9Sstevel@tonic-gate } 1492*7c478bd9Sstevel@tonic-gate continue; 1493*7c478bd9Sstevel@tonic-gate } 1494*7c478bd9Sstevel@tonic-gate 1495*7c478bd9Sstevel@tonic-gate /* Eliminate stale PADS responses. */ 1496*7c478bd9Sstevel@tonic-gate if (poep->poep_code == POECODE_PADS) { 1497*7c478bd9Sstevel@tonic-gate seqval = get_sequence(&pmsg); 1498*7c478bd9Sstevel@tonic-gate if (seqval != psm.poesm_sequence) { 1499*7c478bd9Sstevel@tonic-gate if (verbose) { 1500*7c478bd9Sstevel@tonic-gate if (seqval == 0) 1501*7c478bd9Sstevel@tonic-gate logerr( 1502*7c478bd9Sstevel@tonic-gate "%s: PADS has no sequence " 1503*7c478bd9Sstevel@tonic-gate "number.\n", myname); 1504*7c478bd9Sstevel@tonic-gate else 1505*7c478bd9Sstevel@tonic-gate logerr( 1506*7c478bd9Sstevel@tonic-gate "%s: PADS has sequence " 1507*7c478bd9Sstevel@tonic-gate "%08X instead of %08X.\n", 1508*7c478bd9Sstevel@tonic-gate myname, seqval, 1509*7c478bd9Sstevel@tonic-gate psm.poesm_sequence); 1510*7c478bd9Sstevel@tonic-gate } 1511*7c478bd9Sstevel@tonic-gate continue; 1512*7c478bd9Sstevel@tonic-gate } 1513*7c478bd9Sstevel@tonic-gate } 1514*7c478bd9Sstevel@tonic-gate 1515*7c478bd9Sstevel@tonic-gate /* Dispatch message event. */ 1516*7c478bd9Sstevel@tonic-gate retv = error_check(&pmsg); 1517*7c478bd9Sstevel@tonic-gate switch (poep->poep_code) { 1518*7c478bd9Sstevel@tonic-gate case POECODE_PADT: 1519*7c478bd9Sstevel@tonic-gate handle_event(&psm, PCSME_RPADT, &pmsg); 1520*7c478bd9Sstevel@tonic-gate break; 1521*7c478bd9Sstevel@tonic-gate case POECODE_PADS: 1522*7c478bd9Sstevel@tonic-gate /* 1523*7c478bd9Sstevel@tonic-gate * Got a PPPoE Active Discovery Session- 1524*7c478bd9Sstevel@tonic-gate * confirmation message. It's a PADS event if 1525*7c478bd9Sstevel@tonic-gate * everything's in order. It's a PADS- event 1526*7c478bd9Sstevel@tonic-gate * if the message is merely reporting an 1527*7c478bd9Sstevel@tonic-gate * error. 1528*7c478bd9Sstevel@tonic-gate */ 1529*7c478bd9Sstevel@tonic-gate handle_event(&psm, retv != 0 ? PCSME_RPADSN : 1530*7c478bd9Sstevel@tonic-gate PCSME_RPADS, &pmsg); 1531*7c478bd9Sstevel@tonic-gate break; 1532*7c478bd9Sstevel@tonic-gate case POECODE_PADO: 1533*7c478bd9Sstevel@tonic-gate /* Ignore offers that merely report errors. */ 1534*7c478bd9Sstevel@tonic-gate if (retv != 0) 1535*7c478bd9Sstevel@tonic-gate break; 1536*7c478bd9Sstevel@tonic-gate /* Ignore offers from servers we don't want. */ 1537*7c478bd9Sstevel@tonic-gate if ((retv = use_server(&pmsg)) < 0) 1538*7c478bd9Sstevel@tonic-gate break; 1539*7c478bd9Sstevel@tonic-gate /* Dispatch either RPADO or RAPDO+ event. */ 1540*7c478bd9Sstevel@tonic-gate handle_event(&psm, retv, &pmsg); 1541*7c478bd9Sstevel@tonic-gate break; 1542*7c478bd9Sstevel@tonic-gate 1543*7c478bd9Sstevel@tonic-gate default: 1544*7c478bd9Sstevel@tonic-gate if (verbose) 1545*7c478bd9Sstevel@tonic-gate logerr("%s: Unexpected code %s (%d)\n", myname, 1546*7c478bd9Sstevel@tonic-gate poe_codename(poep->poep_code), 1547*7c478bd9Sstevel@tonic-gate poep->poep_code); 1548*7c478bd9Sstevel@tonic-gate break; 1549*7c478bd9Sstevel@tonic-gate } 1550*7c478bd9Sstevel@tonic-gate } 1551*7c478bd9Sstevel@tonic-gate exit(1); 1552*7c478bd9Sstevel@tonic-gate } 1553*7c478bd9Sstevel@tonic-gate 1554*7c478bd9Sstevel@tonic-gate static void 1555*7c478bd9Sstevel@tonic-gate usage(void) 1556*7c478bd9Sstevel@tonic-gate { 1557*7c478bd9Sstevel@tonic-gate logerr("Usage:\n" 1558*7c478bd9Sstevel@tonic-gate "\t%s [-os#] [-v] <dev> [<service> [<server> [only]]]\n\n" 1559*7c478bd9Sstevel@tonic-gate " or\n\n" 1560*7c478bd9Sstevel@tonic-gate "\t%s [-o#] [-v] -i <dev>\n", myname, myname); 1561*7c478bd9Sstevel@tonic-gate exit(1); 1562*7c478bd9Sstevel@tonic-gate } 1563*7c478bd9Sstevel@tonic-gate 1564*7c478bd9Sstevel@tonic-gate /* 1565*7c478bd9Sstevel@tonic-gate * In addition to the usual 0-2 file descriptors, pppd will leave fd 3 1566*7c478bd9Sstevel@tonic-gate * open on a pipe to receive the environment variables. See 1567*7c478bd9Sstevel@tonic-gate * pppoe_device_pipe() in pppd/plugins/pppoe.c and device_pipe_hook in 1568*7c478bd9Sstevel@tonic-gate * pppd/main.c. 1569*7c478bd9Sstevel@tonic-gate */ 1570*7c478bd9Sstevel@tonic-gate int 1571*7c478bd9Sstevel@tonic-gate main(int argc, char **argv) 1572*7c478bd9Sstevel@tonic-gate { 1573*7c478bd9Sstevel@tonic-gate int inquiry_mode, exceptflag, arg, localid; 1574*7c478bd9Sstevel@tonic-gate char *cp; 1575*7c478bd9Sstevel@tonic-gate 1576*7c478bd9Sstevel@tonic-gate log_to_stderr(LOGLVL_DBG); 1577*7c478bd9Sstevel@tonic-gate 1578*7c478bd9Sstevel@tonic-gate if ((myname = *argv) == NULL) 1579*7c478bd9Sstevel@tonic-gate myname = "pppoec"; 1580*7c478bd9Sstevel@tonic-gate 1581*7c478bd9Sstevel@tonic-gate inquiry_mode = 0; 1582*7c478bd9Sstevel@tonic-gate while ((arg = getopt(argc, argv, "io:s:v")) != EOF) 1583*7c478bd9Sstevel@tonic-gate switch (arg) { 1584*7c478bd9Sstevel@tonic-gate case 'i': 1585*7c478bd9Sstevel@tonic-gate inquiry_mode++; 1586*7c478bd9Sstevel@tonic-gate break; 1587*7c478bd9Sstevel@tonic-gate case 'v': 1588*7c478bd9Sstevel@tonic-gate verbose++; 1589*7c478bd9Sstevel@tonic-gate break; 1590*7c478bd9Sstevel@tonic-gate case 'o': 1591*7c478bd9Sstevel@tonic-gate pado_wait_time = strtol(optarg, &cp, 0); 1592*7c478bd9Sstevel@tonic-gate if (pado_wait_time <= 0 || *cp != '\0' || 1593*7c478bd9Sstevel@tonic-gate cp == optarg) { 1594*7c478bd9Sstevel@tonic-gate logerr("%s: illegal PADO wait time: %s\n", 1595*7c478bd9Sstevel@tonic-gate myname, optarg); 1596*7c478bd9Sstevel@tonic-gate exit(1); 1597*7c478bd9Sstevel@tonic-gate } 1598*7c478bd9Sstevel@tonic-gate break; 1599*7c478bd9Sstevel@tonic-gate case 's': 1600*7c478bd9Sstevel@tonic-gate pads_wait_time = strtol(optarg, &cp, 0); 1601*7c478bd9Sstevel@tonic-gate if (pads_wait_time <= 0 || *cp != '\0' || 1602*7c478bd9Sstevel@tonic-gate cp == optarg) { 1603*7c478bd9Sstevel@tonic-gate logerr("%s: illegal PADS wait time: %s\n", 1604*7c478bd9Sstevel@tonic-gate myname, optarg); 1605*7c478bd9Sstevel@tonic-gate exit(1); 1606*7c478bd9Sstevel@tonic-gate } 1607*7c478bd9Sstevel@tonic-gate break; 1608*7c478bd9Sstevel@tonic-gate case '?': 1609*7c478bd9Sstevel@tonic-gate usage(); 1610*7c478bd9Sstevel@tonic-gate } 1611*7c478bd9Sstevel@tonic-gate 1612*7c478bd9Sstevel@tonic-gate /* Handle inquiry mode. */ 1613*7c478bd9Sstevel@tonic-gate if (inquiry_mode) { 1614*7c478bd9Sstevel@tonic-gate if (optind != argc-1) 1615*7c478bd9Sstevel@tonic-gate usage(); 1616*7c478bd9Sstevel@tonic-gate if (pado_wait_time == 0) 1617*7c478bd9Sstevel@tonic-gate pado_wait_time = PADI_INQUIRY_DWELL; 1618*7c478bd9Sstevel@tonic-gate 1619*7c478bd9Sstevel@tonic-gate /* Invoked by user; open the tunnel driver myself. */ 1620*7c478bd9Sstevel@tonic-gate tunfd = open(tunnam, O_RDWR | O_NOCTTY); 1621*7c478bd9Sstevel@tonic-gate if (tunfd == -1) { 1622*7c478bd9Sstevel@tonic-gate logstrerror(tunnam); 1623*7c478bd9Sstevel@tonic-gate exit(1); 1624*7c478bd9Sstevel@tonic-gate } 1625*7c478bd9Sstevel@tonic-gate 1626*7c478bd9Sstevel@tonic-gate /* 1627*7c478bd9Sstevel@tonic-gate * Set up the control stream for PPPoE negotiation 1628*7c478bd9Sstevel@tonic-gate * (set_control), then broadcast a query for all servers 1629*7c478bd9Sstevel@tonic-gate * and listen for replies (find_all_servers). 1630*7c478bd9Sstevel@tonic-gate */ 1631*7c478bd9Sstevel@tonic-gate find_all_servers(set_control(argv[optind])); 1632*7c478bd9Sstevel@tonic-gate return (0); 1633*7c478bd9Sstevel@tonic-gate } 1634*7c478bd9Sstevel@tonic-gate 1635*7c478bd9Sstevel@tonic-gate if (pado_wait_time == 0) 1636*7c478bd9Sstevel@tonic-gate pado_wait_time = PADI_RESTART_TIME; 1637*7c478bd9Sstevel@tonic-gate 1638*7c478bd9Sstevel@tonic-gate if (optind >= argc) 1639*7c478bd9Sstevel@tonic-gate usage(); 1640*7c478bd9Sstevel@tonic-gate 1641*7c478bd9Sstevel@tonic-gate /* Make sure we've got a usable tunnel driver on stdin. */ 1642*7c478bd9Sstevel@tonic-gate check_stdin(); 1643*7c478bd9Sstevel@tonic-gate 1644*7c478bd9Sstevel@tonic-gate /* Set up the control stream for PPPoE negotiation. */ 1645*7c478bd9Sstevel@tonic-gate localid = set_control(argv[optind++]); 1646*7c478bd9Sstevel@tonic-gate 1647*7c478bd9Sstevel@tonic-gate /* Pick the service, if any. */ 1648*7c478bd9Sstevel@tonic-gate if (optind < argc) 1649*7c478bd9Sstevel@tonic-gate service = argv[optind++]; 1650*7c478bd9Sstevel@tonic-gate 1651*7c478bd9Sstevel@tonic-gate /* Parse out the filters. */ 1652*7c478bd9Sstevel@tonic-gate if (optind < argc) { 1653*7c478bd9Sstevel@tonic-gate if (strcasecmp(argv[argc - 1], "only") == 0) { 1654*7c478bd9Sstevel@tonic-gate argc--; 1655*7c478bd9Sstevel@tonic-gate onlyflag = 1; 1656*7c478bd9Sstevel@tonic-gate } 1657*7c478bd9Sstevel@tonic-gate exceptflag = 0; 1658*7c478bd9Sstevel@tonic-gate for (; optind < argc; optind++) { 1659*7c478bd9Sstevel@tonic-gate if (!exceptflag && 1660*7c478bd9Sstevel@tonic-gate strcasecmp(argv[optind], "except") == 0) { 1661*7c478bd9Sstevel@tonic-gate exceptflag = 1; 1662*7c478bd9Sstevel@tonic-gate } else { 1663*7c478bd9Sstevel@tonic-gate parse_filter(argv[optind], exceptflag); 1664*7c478bd9Sstevel@tonic-gate exceptflag = 0; 1665*7c478bd9Sstevel@tonic-gate } 1666*7c478bd9Sstevel@tonic-gate } 1667*7c478bd9Sstevel@tonic-gate } 1668*7c478bd9Sstevel@tonic-gate 1669*7c478bd9Sstevel@tonic-gate /* Enter the main loop. */ 1670*7c478bd9Sstevel@tonic-gate find_server(localid); 1671*7c478bd9Sstevel@tonic-gate 1672*7c478bd9Sstevel@tonic-gate return (0); 1673*7c478bd9Sstevel@tonic-gate } 1674