17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*f53eecf5SJames Carlson * Common Development and Distribution License (the "License"). 6*f53eecf5SJames Carlson * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 227c478bd9Sstevel@tonic-gate * PPPoE Client-mode "chat" utility for use with Solaris PPP 4.0. 237c478bd9Sstevel@tonic-gate * 24*f53eecf5SJames Carlson * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 257c478bd9Sstevel@tonic-gate * Use is subject to license terms. 267c478bd9Sstevel@tonic-gate */ 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate #include <stdio.h> 297c478bd9Sstevel@tonic-gate #include <stdlib.h> 307c478bd9Sstevel@tonic-gate #include <unistd.h> 317c478bd9Sstevel@tonic-gate #include <ctype.h> 327c478bd9Sstevel@tonic-gate #include <strings.h> 337c478bd9Sstevel@tonic-gate #include <fcntl.h> 347c478bd9Sstevel@tonic-gate #include <errno.h> 357c478bd9Sstevel@tonic-gate #include <signal.h> 367c478bd9Sstevel@tonic-gate #include <stropts.h> 377c478bd9Sstevel@tonic-gate #include <netdb.h> 387c478bd9Sstevel@tonic-gate #include <sys/types.h> 397c478bd9Sstevel@tonic-gate #include <sys/socket.h> 407c478bd9Sstevel@tonic-gate #include <net/if.h> 417c478bd9Sstevel@tonic-gate #include <netinet/in.h> 427c478bd9Sstevel@tonic-gate #include <netinet/if_ether.h> 437c478bd9Sstevel@tonic-gate 447c478bd9Sstevel@tonic-gate #include <net/sppptun.h> 457c478bd9Sstevel@tonic-gate #include <net/pppoe.h> 467c478bd9Sstevel@tonic-gate 477c478bd9Sstevel@tonic-gate #include "common.h" 487c478bd9Sstevel@tonic-gate #include "logging.h" 497c478bd9Sstevel@tonic-gate 507c478bd9Sstevel@tonic-gate /* 517c478bd9Sstevel@tonic-gate * This value, currently set to the characters "POE1," is used to 527c478bd9Sstevel@tonic-gate * distinguish among control messages from multiple lower streams 537c478bd9Sstevel@tonic-gate * under /dev/sppp. This feature is needed to support PPP translation 547c478bd9Sstevel@tonic-gate * (LAC-like behavior), but isn't currently used. 557c478bd9Sstevel@tonic-gate */ 567c478bd9Sstevel@tonic-gate #define PPPOE_DISCRIM 0x504F4531 577c478bd9Sstevel@tonic-gate 587c478bd9Sstevel@tonic-gate /* milliseconds between retries */ 597c478bd9Sstevel@tonic-gate #define PADI_RESTART_TIME 500 607c478bd9Sstevel@tonic-gate #define PADR_RESTART_TIME 2000 617c478bd9Sstevel@tonic-gate 627c478bd9Sstevel@tonic-gate /* default inquiry mode timer in milliseconds. */ 637c478bd9Sstevel@tonic-gate #define PADI_INQUIRY_DWELL 3000 647c478bd9Sstevel@tonic-gate 657c478bd9Sstevel@tonic-gate /* maximum timer value in milliseconds */ 667c478bd9Sstevel@tonic-gate #define RESTART_LIMIT 5000 677c478bd9Sstevel@tonic-gate 687c478bd9Sstevel@tonic-gate char *myname; /* copy of argv[0] for error messages */ 697c478bd9Sstevel@tonic-gate static int verbose; /* -v flag given */ 707c478bd9Sstevel@tonic-gate static int onlyflag; /* keyword "only" at end of command line */ 717c478bd9Sstevel@tonic-gate static char *service = ""; /* saved service name from command line */ 727c478bd9Sstevel@tonic-gate 737c478bd9Sstevel@tonic-gate static int pado_wait_time = 0; /* see main() */ 747c478bd9Sstevel@tonic-gate static int pads_wait_time = PADR_RESTART_TIME; 757c478bd9Sstevel@tonic-gate 767c478bd9Sstevel@tonic-gate static int tunfd; /* open connection to sppptun driver */ 777c478bd9Sstevel@tonic-gate 787c478bd9Sstevel@tonic-gate static struct timeval tvstart; /* time of last PADI/PADR transmission */ 797c478bd9Sstevel@tonic-gate 807c478bd9Sstevel@tonic-gate struct server_filter { 817c478bd9Sstevel@tonic-gate struct server_filter *sf_next; /* Next filter in list */ 827c478bd9Sstevel@tonic-gate struct ether_addr sf_mac; /* Ethernet address */ 837c478bd9Sstevel@tonic-gate struct ether_addr sf_mask; /* Mask (0 or 0xFF in each byte) */ 847c478bd9Sstevel@tonic-gate const char *sf_name; /* String for AC-Name compare */ 857c478bd9Sstevel@tonic-gate boolean_t sf_hasmac; /* Set if string could be MAC */ 867c478bd9Sstevel@tonic-gate boolean_t sf_isexcept; /* Ignore server if matching */ 877c478bd9Sstevel@tonic-gate }; 887c478bd9Sstevel@tonic-gate 897c478bd9Sstevel@tonic-gate /* List of filters defined on command line. */ 907c478bd9Sstevel@tonic-gate static struct server_filter *sfhead, *sftail; 917c478bd9Sstevel@tonic-gate 927c478bd9Sstevel@tonic-gate /* 937c478bd9Sstevel@tonic-gate * PPPoE Client State Machine 947c478bd9Sstevel@tonic-gate */ 957c478bd9Sstevel@tonic-gate 967c478bd9Sstevel@tonic-gate /* Client events */ 977c478bd9Sstevel@tonic-gate #define PCSME_CLOSE 0 /* User close */ 987c478bd9Sstevel@tonic-gate #define PCSME_OPEN 1 /* User open */ 997c478bd9Sstevel@tonic-gate #define PCSME_TOP 2 /* Timeout+ (counter non-zero) */ 1007c478bd9Sstevel@tonic-gate #define PCSME_TOM 3 /* Timeout- (counter zero) */ 1017c478bd9Sstevel@tonic-gate #define PCSME_RPADT 4 /* Receive PADT (unexpected here) */ 1027c478bd9Sstevel@tonic-gate #define PCSME_RPADOP 5 /* Receive desired PADO */ 1037c478bd9Sstevel@tonic-gate #define PCSME_RPADO 6 /* Receive ordinary PADO */ 1047c478bd9Sstevel@tonic-gate #define PCSME_RPADS 7 /* Receive PADS */ 1057c478bd9Sstevel@tonic-gate #define PCSME_RPADSN 8 /* Receive bad (errored) PADS */ 1067c478bd9Sstevel@tonic-gate #define PCSME__MAX 9 1077c478bd9Sstevel@tonic-gate 1087c478bd9Sstevel@tonic-gate /* Client states */ 1097c478bd9Sstevel@tonic-gate #define PCSMS_DEAD 0 /* Initial state */ 1107c478bd9Sstevel@tonic-gate #define PCSMS_INITSENT 1 /* PADI sent */ 1117c478bd9Sstevel@tonic-gate #define PCSMS_OFFRRCVD 2 /* PADO received */ 1127c478bd9Sstevel@tonic-gate #define PCSMS_REQSENT 3 /* PADR sent */ 1137c478bd9Sstevel@tonic-gate #define PCSMS_CONVERS 4 /* Conversational */ 1147c478bd9Sstevel@tonic-gate #define PCSMS__MAX 5 1157c478bd9Sstevel@tonic-gate 1167c478bd9Sstevel@tonic-gate /* Client actions */ 1177c478bd9Sstevel@tonic-gate #define PCSMA_NONE 0 /* Do nothing */ 1187c478bd9Sstevel@tonic-gate #define PCSMA_FAIL 1 /* Unrecoverable error */ 1197c478bd9Sstevel@tonic-gate #define PCSMA_SPADI 2 /* Send PADI */ 1207c478bd9Sstevel@tonic-gate #define PCSMA_ADD 3 /* Add ordinary server to list */ 1217c478bd9Sstevel@tonic-gate #define PCSMA_SPADR 4 /* Send PADR to top server */ 1227c478bd9Sstevel@tonic-gate #define PCSMA_SPADRP 5 /* Send PADR to this server (make top) */ 1237c478bd9Sstevel@tonic-gate #define PCSMA_SPADRN 6 /* Send PADR to next (or terminate) */ 1247c478bd9Sstevel@tonic-gate #define PCSMA_OPEN 7 /* Start PPP */ 1257c478bd9Sstevel@tonic-gate #define PCSMA__MAX 8 1267c478bd9Sstevel@tonic-gate 1277c478bd9Sstevel@tonic-gate static uint8_t client_next_state[PCSMS__MAX][PCSME__MAX] = { 1287c478bd9Sstevel@tonic-gate /* 0 PCSMS_DEAD Initial state */ 1297c478bd9Sstevel@tonic-gate { 1307c478bd9Sstevel@tonic-gate PCSMS_DEAD, /* PCSME_CLOSE User close */ 1317c478bd9Sstevel@tonic-gate PCSMS_INITSENT, /* PCSME_OPEN User open */ 1327c478bd9Sstevel@tonic-gate PCSMS_DEAD, /* PCSME_TOP Timeout+ */ 1337c478bd9Sstevel@tonic-gate PCSMS_DEAD, /* PCSME_TOM Timeout- */ 1347c478bd9Sstevel@tonic-gate PCSMS_DEAD, /* PCSME_RPADT Receive PADT */ 1357c478bd9Sstevel@tonic-gate PCSMS_DEAD, /* PCSME_RPADOP Receive desired PADO */ 1367c478bd9Sstevel@tonic-gate PCSMS_DEAD, /* PCSME_RPADO Receive ordinary PADO */ 1377c478bd9Sstevel@tonic-gate PCSMS_DEAD, /* PCSME_RPADS Receive PADS */ 1387c478bd9Sstevel@tonic-gate PCSMS_DEAD, /* PCSME_RPADSN Receive bad PADS */ 1397c478bd9Sstevel@tonic-gate }, 1407c478bd9Sstevel@tonic-gate /* 1 PCSMS_INITSENT PADI sent */ 1417c478bd9Sstevel@tonic-gate { 1427c478bd9Sstevel@tonic-gate PCSMS_DEAD, /* PCSME_CLOSE User close */ 1437c478bd9Sstevel@tonic-gate PCSMS_INITSENT, /* PCSME_OPEN User open */ 1447c478bd9Sstevel@tonic-gate PCSMS_INITSENT, /* PCSME_TOP Timeout+ */ 1457c478bd9Sstevel@tonic-gate PCSMS_DEAD, /* PCSME_TOM Timeout- */ 1467c478bd9Sstevel@tonic-gate PCSMS_DEAD, /* PCSME_RPADT Receive PADT */ 1477c478bd9Sstevel@tonic-gate PCSMS_REQSENT, /* PCSME_RPADOP Receive desired PADO */ 1487c478bd9Sstevel@tonic-gate PCSMS_OFFRRCVD, /* PCSME_RPADO Receive ordinary PADO */ 1497c478bd9Sstevel@tonic-gate PCSMS_INITSENT, /* PCSME_RPADS Receive PADS */ 1507c478bd9Sstevel@tonic-gate PCSMS_INITSENT, /* PCSME_RPADSN Receive bad PADS */ 1517c478bd9Sstevel@tonic-gate }, 1527c478bd9Sstevel@tonic-gate /* 2 PCSMS_OFFRRCVD PADO received */ 1537c478bd9Sstevel@tonic-gate { 1547c478bd9Sstevel@tonic-gate PCSMS_DEAD, /* PCSME_CLOSE User close */ 1557c478bd9Sstevel@tonic-gate PCSMS_INITSENT, /* PCSME_OPEN User open */ 1567c478bd9Sstevel@tonic-gate PCSMS_REQSENT, /* PCSME_TOP Timeout+ */ 1577c478bd9Sstevel@tonic-gate PCSMS_REQSENT, /* PCSME_TOM Timeout- */ 1587c478bd9Sstevel@tonic-gate PCSMS_DEAD, /* PCSME_RPADT Receive PADT */ 1597c478bd9Sstevel@tonic-gate PCSMS_REQSENT, /* PCSME_RPADOP Receive desired PADO */ 1607c478bd9Sstevel@tonic-gate PCSMS_OFFRRCVD, /* PCSME_RPADO Receive ordinary PADO */ 1617c478bd9Sstevel@tonic-gate PCSMS_OFFRRCVD, /* PCSME_RPADS Receive PADS */ 1627c478bd9Sstevel@tonic-gate PCSMS_OFFRRCVD, /* PCSME_RPADSN Receive bad PADS */ 1637c478bd9Sstevel@tonic-gate }, 1647c478bd9Sstevel@tonic-gate /* 3 PCSMS_REQSENT PADR sent */ 1657c478bd9Sstevel@tonic-gate { 1667c478bd9Sstevel@tonic-gate PCSMS_DEAD, /* PCSME_CLOSE User close */ 1677c478bd9Sstevel@tonic-gate PCSMS_INITSENT, /* PCSME_OPEN User open */ 1687c478bd9Sstevel@tonic-gate PCSMS_REQSENT, /* PCSME_TOP Timeout+ */ 1697c478bd9Sstevel@tonic-gate PCSMS_REQSENT, /* PCSME_TOM Timeout- */ 1707c478bd9Sstevel@tonic-gate PCSMS_DEAD, /* PCSME_RPADT Receive PADT */ 1717c478bd9Sstevel@tonic-gate PCSMS_REQSENT, /* PCSME_RPADOP Receive desired PADO */ 1727c478bd9Sstevel@tonic-gate PCSMS_REQSENT, /* PCSME_RPADO Receive ordinary PADO */ 1737c478bd9Sstevel@tonic-gate PCSMS_CONVERS, /* PCSME_RPADS Receive PADS */ 1747c478bd9Sstevel@tonic-gate PCSMS_REQSENT, /* PCSME_RPADSN Receive bad PADS */ 1757c478bd9Sstevel@tonic-gate }, 1767c478bd9Sstevel@tonic-gate /* 4 PCSMS_CONVERS Conversational */ 1777c478bd9Sstevel@tonic-gate { 1787c478bd9Sstevel@tonic-gate PCSMS_DEAD, /* PCSME_CLOSE User close */ 1797c478bd9Sstevel@tonic-gate PCSMS_INITSENT, /* PCSME_OPEN User open */ 1807c478bd9Sstevel@tonic-gate PCSMS_CONVERS, /* PCSME_TOP Timeout+ */ 1817c478bd9Sstevel@tonic-gate PCSMS_CONVERS, /* PCSME_TOM Timeout- */ 1827c478bd9Sstevel@tonic-gate PCSMS_DEAD, /* PCSME_RPADT Receive PADT */ 1837c478bd9Sstevel@tonic-gate PCSMS_CONVERS, /* PCSME_RPADOP Receive desired PADO */ 1847c478bd9Sstevel@tonic-gate PCSMS_CONVERS, /* PCSME_RPADO Receive ordinary PADO */ 1857c478bd9Sstevel@tonic-gate PCSMS_CONVERS, /* PCSME_RPADS Receive PADS */ 1867c478bd9Sstevel@tonic-gate PCSMS_CONVERS, /* PCSME_RPADSN Receive bad PADS */ 1877c478bd9Sstevel@tonic-gate }, 1887c478bd9Sstevel@tonic-gate }; 1897c478bd9Sstevel@tonic-gate 1907c478bd9Sstevel@tonic-gate static uint8_t client_action[PCSMS__MAX][PCSME__MAX] = { 1917c478bd9Sstevel@tonic-gate /* 0 PCSMS_DEAD Initial state */ 1927c478bd9Sstevel@tonic-gate { 1937c478bd9Sstevel@tonic-gate PCSMA_NONE, /* PCSME_CLOSE User close */ 1947c478bd9Sstevel@tonic-gate PCSMA_SPADI, /* PCSME_OPEN User open */ 1957c478bd9Sstevel@tonic-gate PCSMA_NONE, /* PCSME_TOP Timeout+ */ 1967c478bd9Sstevel@tonic-gate PCSMA_NONE, /* PCSME_TOM Timeout- */ 1977c478bd9Sstevel@tonic-gate PCSMA_NONE, /* PCSME_RPADT Receive PADT */ 1987c478bd9Sstevel@tonic-gate PCSMA_NONE, /* PCSME_RPADOP Receive desired PADO */ 1997c478bd9Sstevel@tonic-gate PCSMA_NONE, /* PCSME_RPADO Receive ordinary PADO */ 2007c478bd9Sstevel@tonic-gate PCSMA_NONE, /* PCSME_RPADS Receive PADS */ 2017c478bd9Sstevel@tonic-gate PCSMA_NONE, /* PCSME_RPADSN Receive bad PADS */ 2027c478bd9Sstevel@tonic-gate }, 2037c478bd9Sstevel@tonic-gate /* 1 PCSMS_INITSENT PADI sent */ 2047c478bd9Sstevel@tonic-gate { 2057c478bd9Sstevel@tonic-gate PCSMA_FAIL, /* PCSME_CLOSE User close */ 2067c478bd9Sstevel@tonic-gate PCSMA_SPADI, /* PCSME_OPEN User open */ 2077c478bd9Sstevel@tonic-gate PCSMA_SPADI, /* PCSME_TOP Timeout+ */ 2087c478bd9Sstevel@tonic-gate PCSMA_FAIL, /* PCSME_TOM Timeout- */ 2097c478bd9Sstevel@tonic-gate PCSMA_FAIL, /* PCSME_RPADT Receive PADT */ 2107c478bd9Sstevel@tonic-gate PCSMA_SPADRP, /* PCSME_RPADOP Receive desired PADO */ 2117c478bd9Sstevel@tonic-gate PCSMA_ADD, /* PCSME_RPADO Receive ordinary PADO */ 2127c478bd9Sstevel@tonic-gate PCSMA_NONE, /* PCSME_RPADS Receive PADS */ 2137c478bd9Sstevel@tonic-gate PCSMA_NONE, /* PCSME_RPADSN Receive bad PADS */ 2147c478bd9Sstevel@tonic-gate }, 2157c478bd9Sstevel@tonic-gate /* 2 PCSMS_OFFRRCVD PADO received */ 2167c478bd9Sstevel@tonic-gate { 2177c478bd9Sstevel@tonic-gate PCSMA_FAIL, /* PCSME_CLOSE User close */ 2187c478bd9Sstevel@tonic-gate PCSMA_SPADI, /* PCSME_OPEN User open */ 2197c478bd9Sstevel@tonic-gate PCSMA_SPADR, /* PCSME_TOP Timeout+ */ 2207c478bd9Sstevel@tonic-gate PCSMA_SPADR, /* PCSME_TOM Timeout- */ 2217c478bd9Sstevel@tonic-gate PCSMA_FAIL, /* PCSME_RPADT Receive PADT */ 2227c478bd9Sstevel@tonic-gate PCSMA_SPADRP, /* PCSME_RPADOP Receive desired PADO */ 2237c478bd9Sstevel@tonic-gate PCSMA_ADD, /* PCSME_RPADO Receive ordinary PADO */ 2247c478bd9Sstevel@tonic-gate PCSMA_NONE, /* PCSME_RPADS Receive PADS */ 2257c478bd9Sstevel@tonic-gate PCSMA_NONE, /* PCSME_RPADSN Receive bad PADS */ 2267c478bd9Sstevel@tonic-gate }, 2277c478bd9Sstevel@tonic-gate /* 3 PCSMS_REQSENT PADR sent */ 2287c478bd9Sstevel@tonic-gate { 2297c478bd9Sstevel@tonic-gate PCSMA_FAIL, /* PCSME_CLOSE User close */ 2307c478bd9Sstevel@tonic-gate PCSMA_SPADI, /* PCSME_OPEN User open */ 2317c478bd9Sstevel@tonic-gate PCSMA_SPADR, /* PCSME_TOP Timeout+ */ 2327c478bd9Sstevel@tonic-gate PCSMA_SPADRN, /* PCSME_TOM Timeout- */ 2337c478bd9Sstevel@tonic-gate PCSMA_FAIL, /* PCSME_RPADT Receive PADT */ 2347c478bd9Sstevel@tonic-gate PCSMA_ADD, /* PCSME_RPADOP Receive desired PADO */ 2357c478bd9Sstevel@tonic-gate PCSMA_ADD, /* PCSME_RPADO Receive ordinary PADO */ 2367c478bd9Sstevel@tonic-gate PCSMA_OPEN, /* PCSME_RPADS Receive PADS */ 2377c478bd9Sstevel@tonic-gate PCSMA_SPADRN, /* PCSME_RPADSN Receive bad PADS */ 2387c478bd9Sstevel@tonic-gate }, 2397c478bd9Sstevel@tonic-gate /* 4 PCSMS_CONVERS Conversational */ 2407c478bd9Sstevel@tonic-gate { 2417c478bd9Sstevel@tonic-gate PCSMA_FAIL, /* PCSME_CLOSE User close */ 2427c478bd9Sstevel@tonic-gate PCSMA_SPADI, /* PCSME_OPEN User open */ 2437c478bd9Sstevel@tonic-gate PCSMA_FAIL, /* PCSME_TOP Timeout+ */ 2447c478bd9Sstevel@tonic-gate PCSMA_FAIL, /* PCSME_TOM Timeout- */ 2457c478bd9Sstevel@tonic-gate PCSMA_FAIL, /* PCSME_RPADT Receive PADT */ 2467c478bd9Sstevel@tonic-gate PCSMA_NONE, /* PCSME_RPADOP Receive desired PADO */ 2477c478bd9Sstevel@tonic-gate PCSMA_NONE, /* PCSME_RPADO Receive ordinary PADO */ 2487c478bd9Sstevel@tonic-gate PCSMA_NONE, /* PCSME_RPADS Receive PADS */ 2497c478bd9Sstevel@tonic-gate PCSMA_NONE, /* PCSME_RPADSN Receive bad PADS */ 2507c478bd9Sstevel@tonic-gate }, 2517c478bd9Sstevel@tonic-gate }; 2527c478bd9Sstevel@tonic-gate 2537c478bd9Sstevel@tonic-gate /* 2547c478bd9Sstevel@tonic-gate * PPPoE Message structure -- holds data from a received PPPoE 2557c478bd9Sstevel@tonic-gate * message. These are copied and saved when queuing offers from 2567c478bd9Sstevel@tonic-gate * possible servers. 2577c478bd9Sstevel@tonic-gate */ 2587c478bd9Sstevel@tonic-gate typedef struct poesm_s { 2597c478bd9Sstevel@tonic-gate struct poesm_s *poemsg_next; /* Next message in list */ 2607c478bd9Sstevel@tonic-gate const poep_t *poemsg_data; /* Pointer to PPPoE packet */ 2617c478bd9Sstevel@tonic-gate int poemsg_len; /* Length of packet */ 2627c478bd9Sstevel@tonic-gate ppptun_atype poemsg_sender; /* Address of sender */ 2637c478bd9Sstevel@tonic-gate const char *poemsg_iname; /* Name of input interface */ 2647c478bd9Sstevel@tonic-gate } poemsg_t; 2657c478bd9Sstevel@tonic-gate 2667c478bd9Sstevel@tonic-gate /* 2677c478bd9Sstevel@tonic-gate * PPPoE State Machine structure -- holds state of PPPoE negotiation; 2687c478bd9Sstevel@tonic-gate * currently, there's exactly one of these per pppoec instance. 2697c478bd9Sstevel@tonic-gate */ 2707c478bd9Sstevel@tonic-gate typedef struct { 2717c478bd9Sstevel@tonic-gate int poesm_state; /* PCSMS_* */ 2727c478bd9Sstevel@tonic-gate int poesm_timer; /* Milliseconds to next TO */ 2737c478bd9Sstevel@tonic-gate int poesm_count; /* Retry countdown */ 2747c478bd9Sstevel@tonic-gate int poesm_interval; /* Reload value */ 2757c478bd9Sstevel@tonic-gate uint32_t poesm_sequence; /* Sequence for PADR */ 2767c478bd9Sstevel@tonic-gate 2777c478bd9Sstevel@tonic-gate poemsg_t *poesm_firstoff; /* Queue of valid offers; */ 2787c478bd9Sstevel@tonic-gate poemsg_t *poesm_lastoff; /* first is best offer */ 2797c478bd9Sstevel@tonic-gate poemsg_t *poesm_tried; /* Tried and failed offers */ 2807c478bd9Sstevel@tonic-gate 2817c478bd9Sstevel@tonic-gate int poesm_localid; /* Local session ID (driver) */ 2827c478bd9Sstevel@tonic-gate } poesm_t; 2837c478bd9Sstevel@tonic-gate 2847c478bd9Sstevel@tonic-gate /* 2857c478bd9Sstevel@tonic-gate * Convert an internal PPPoE event code number into a printable 2867c478bd9Sstevel@tonic-gate * string. 2877c478bd9Sstevel@tonic-gate */ 2887c478bd9Sstevel@tonic-gate static const char * 2897c478bd9Sstevel@tonic-gate poe_event(int event) 2907c478bd9Sstevel@tonic-gate { 2917c478bd9Sstevel@tonic-gate static const char *poeevent[PCSME__MAX] = { 2927c478bd9Sstevel@tonic-gate "Close", "Open", "TO+", "TO-", "rPADT", 2937c478bd9Sstevel@tonic-gate "rPADO+", "rPADO", "rPADS", "rPADS-" 2947c478bd9Sstevel@tonic-gate }; 2957c478bd9Sstevel@tonic-gate 2967c478bd9Sstevel@tonic-gate if (event < 0 || event >= PCSME__MAX) { 2977c478bd9Sstevel@tonic-gate return ("?"); 2987c478bd9Sstevel@tonic-gate } 2997c478bd9Sstevel@tonic-gate return (poeevent[event]); 3007c478bd9Sstevel@tonic-gate } 3017c478bd9Sstevel@tonic-gate 3027c478bd9Sstevel@tonic-gate /* 3037c478bd9Sstevel@tonic-gate * Convert an internal PPPoE state number into a printable string. 3047c478bd9Sstevel@tonic-gate */ 3057c478bd9Sstevel@tonic-gate static const char * 3067c478bd9Sstevel@tonic-gate poe_state(int state) 3077c478bd9Sstevel@tonic-gate { 3087c478bd9Sstevel@tonic-gate static const char *poestate[PCSMS__MAX] = { 3097c478bd9Sstevel@tonic-gate "Dead", "InitSent", "OffrRcvd", "ReqSent", "Convers", 3107c478bd9Sstevel@tonic-gate }; 3117c478bd9Sstevel@tonic-gate 3127c478bd9Sstevel@tonic-gate if (state < 0 || state >= PCSMS__MAX) { 3137c478bd9Sstevel@tonic-gate return ("?"); 3147c478bd9Sstevel@tonic-gate } 3157c478bd9Sstevel@tonic-gate return (poestate[state]); 3167c478bd9Sstevel@tonic-gate } 3177c478bd9Sstevel@tonic-gate 3187c478bd9Sstevel@tonic-gate /* 3197c478bd9Sstevel@tonic-gate * Convert an internal PPPoE action number into a printable string. 3207c478bd9Sstevel@tonic-gate */ 3217c478bd9Sstevel@tonic-gate static const char * 3227c478bd9Sstevel@tonic-gate poe_action(int act) 3237c478bd9Sstevel@tonic-gate { 3247c478bd9Sstevel@tonic-gate static const char *poeaction[PCSMA__MAX] = { 3257c478bd9Sstevel@tonic-gate "None", "Fail", "SendPADI", "Add", "SendPADR", 3267c478bd9Sstevel@tonic-gate "SendPADR+", "SendPADR-", "Open" 3277c478bd9Sstevel@tonic-gate }; 3287c478bd9Sstevel@tonic-gate 3297c478bd9Sstevel@tonic-gate if (act < 0 || act >= PCSMA__MAX) { 3307c478bd9Sstevel@tonic-gate return ("?"); 3317c478bd9Sstevel@tonic-gate } 3327c478bd9Sstevel@tonic-gate return (poeaction[act]); 3337c478bd9Sstevel@tonic-gate } 3347c478bd9Sstevel@tonic-gate 3357c478bd9Sstevel@tonic-gate /* 3367c478bd9Sstevel@tonic-gate * This calls mygetmsg (which discards partial messages as needed) and 3377c478bd9Sstevel@tonic-gate * logs errors as appropriate. 3387c478bd9Sstevel@tonic-gate */ 3397c478bd9Sstevel@tonic-gate static int 3407c478bd9Sstevel@tonic-gate pppoec_getmsg(int fd, struct strbuf *ctrl, struct strbuf *data, int *flags) 3417c478bd9Sstevel@tonic-gate { 3427c478bd9Sstevel@tonic-gate int retv; 3437c478bd9Sstevel@tonic-gate 3447c478bd9Sstevel@tonic-gate for (;;) { 3457c478bd9Sstevel@tonic-gate retv = mygetmsg(fd, ctrl, data, flags); 3467c478bd9Sstevel@tonic-gate if (retv == 0) 3477c478bd9Sstevel@tonic-gate break; 3487c478bd9Sstevel@tonic-gate if (retv < 0) { 3497c478bd9Sstevel@tonic-gate if (errno == EINTR) 3507c478bd9Sstevel@tonic-gate continue; 3517c478bd9Sstevel@tonic-gate logstrerror("getmsg"); 3527c478bd9Sstevel@tonic-gate break; 3537c478bd9Sstevel@tonic-gate } 3547c478bd9Sstevel@tonic-gate if (verbose) { 3557c478bd9Sstevel@tonic-gate if (!(retv & (MORECTL | MOREDATA))) 3567c478bd9Sstevel@tonic-gate logerr("%s: discard: " 3577c478bd9Sstevel@tonic-gate "unexpected status %d\n", myname, retv); 3587c478bd9Sstevel@tonic-gate else 3597c478bd9Sstevel@tonic-gate logerr("%s: discard: " 3607c478bd9Sstevel@tonic-gate "truncated %s%smessage\n", myname, 3617c478bd9Sstevel@tonic-gate retv & MORECTL ? "control " : "", 3627c478bd9Sstevel@tonic-gate retv & MOREDATA ? "data " : ""); 3637c478bd9Sstevel@tonic-gate } 3647c478bd9Sstevel@tonic-gate } 3657c478bd9Sstevel@tonic-gate return (retv); 3667c478bd9Sstevel@tonic-gate } 3677c478bd9Sstevel@tonic-gate 3687c478bd9Sstevel@tonic-gate /* 3697c478bd9Sstevel@tonic-gate * Connect the control path to the lower stream of interest. This 3707c478bd9Sstevel@tonic-gate * must be called after opening the tunnel driver in order to 3717c478bd9Sstevel@tonic-gate * establish the interface to be used for signaling. Returns local 3727c478bd9Sstevel@tonic-gate * session ID number. 3737c478bd9Sstevel@tonic-gate */ 3747c478bd9Sstevel@tonic-gate static int 3757c478bd9Sstevel@tonic-gate set_control(const char *dname) 3767c478bd9Sstevel@tonic-gate { 3777c478bd9Sstevel@tonic-gate struct ppptun_peer ptp; 3787c478bd9Sstevel@tonic-gate union ppptun_name ptn; 3797c478bd9Sstevel@tonic-gate 3807c478bd9Sstevel@tonic-gate /* Fetch the local session ID first. */ 3817c478bd9Sstevel@tonic-gate (void) memset(&ptp, '\0', sizeof (ptp)); 3827c478bd9Sstevel@tonic-gate ptp.ptp_style = PTS_PPPOE; 3837c478bd9Sstevel@tonic-gate if (strioctl(tunfd, PPPTUN_SPEER, &ptp, sizeof (ptp), sizeof (ptp)) < 3847c478bd9Sstevel@tonic-gate 0) { 3857c478bd9Sstevel@tonic-gate logstrerror("PPPTUN_SPEER"); 3867c478bd9Sstevel@tonic-gate exit(1); 3877c478bd9Sstevel@tonic-gate } 3887c478bd9Sstevel@tonic-gate 3897c478bd9Sstevel@tonic-gate /* Connect to lower stream. */ 3907c478bd9Sstevel@tonic-gate (void) snprintf(ptn.ptn_name, sizeof (ptn.ptn_name), "%s:pppoed", 3917c478bd9Sstevel@tonic-gate dname); 3927c478bd9Sstevel@tonic-gate if (strioctl(tunfd, PPPTUN_SCTL, &ptn, sizeof (ptn), 0) < 0) { 3937c478bd9Sstevel@tonic-gate logerr("%s: PPPTUN_SCTL %s: %s\n", myname, 3947c478bd9Sstevel@tonic-gate ptn.ptn_name, mystrerror(errno)); 3957c478bd9Sstevel@tonic-gate exit(1); 3967c478bd9Sstevel@tonic-gate } 3977c478bd9Sstevel@tonic-gate return (ptp.ptp_lsessid); 3987c478bd9Sstevel@tonic-gate } 3997c478bd9Sstevel@tonic-gate 4007c478bd9Sstevel@tonic-gate /* 4017c478bd9Sstevel@tonic-gate * Check if standard input is actually a viable connection to the 4027c478bd9Sstevel@tonic-gate * tunnel driver. This is the normal mode of operation with pppd; the 4037c478bd9Sstevel@tonic-gate * tunnel driver is opened by pppd as the tty and pppoec is exec'd as 4047c478bd9Sstevel@tonic-gate * the connect script. 4057c478bd9Sstevel@tonic-gate */ 4067c478bd9Sstevel@tonic-gate static void 4077c478bd9Sstevel@tonic-gate check_stdin(void) 4087c478bd9Sstevel@tonic-gate { 4097c478bd9Sstevel@tonic-gate struct ppptun_info pti; 4107c478bd9Sstevel@tonic-gate union ppptun_name ptn; 4117c478bd9Sstevel@tonic-gate 4127c478bd9Sstevel@tonic-gate if (strioctl(0, PPPTUN_GDATA, &ptn, 0, sizeof (ptn)) < 0) { 4137c478bd9Sstevel@tonic-gate if (errno == EINVAL) 4147c478bd9Sstevel@tonic-gate logerr("%s: PPPoE operation requires " 4157c478bd9Sstevel@tonic-gate "the use of a tunneling device\n", myname); 4167c478bd9Sstevel@tonic-gate else 4177c478bd9Sstevel@tonic-gate logstrerror("PPPTUN_GDATA"); 4187c478bd9Sstevel@tonic-gate exit(1); 4197c478bd9Sstevel@tonic-gate } 4207c478bd9Sstevel@tonic-gate if (ptn.ptn_name[0] != '\0') { 4217c478bd9Sstevel@tonic-gate if (strioctl(0, PPPTUN_GINFO, &pti, 0, sizeof (pti)) < 0) { 4227c478bd9Sstevel@tonic-gate logstrerror("PPPTUN_GINFO"); 4237c478bd9Sstevel@tonic-gate exit(1); 4247c478bd9Sstevel@tonic-gate } 4257c478bd9Sstevel@tonic-gate if (pti.pti_style != PTS_PPPOE) { 4267c478bd9Sstevel@tonic-gate logerr("%s: Cannot connect to server " 4277c478bd9Sstevel@tonic-gate "using PPPoE; stream already set to style %d\n", 4287c478bd9Sstevel@tonic-gate myname, pti.pti_style); 4297c478bd9Sstevel@tonic-gate exit(1); 4307c478bd9Sstevel@tonic-gate } 4317c478bd9Sstevel@tonic-gate if (verbose) 4327c478bd9Sstevel@tonic-gate logerr("%s: Warning: PPPoE data link " 4337c478bd9Sstevel@tonic-gate "already connected\n", myname); 4347c478bd9Sstevel@tonic-gate exit(0); 4357c478bd9Sstevel@tonic-gate } 4367c478bd9Sstevel@tonic-gate /* Standard input is the tunnel driver; use it. */ 4377c478bd9Sstevel@tonic-gate tunfd = 0; 4387c478bd9Sstevel@tonic-gate } 4397c478bd9Sstevel@tonic-gate 4407c478bd9Sstevel@tonic-gate /* 4417c478bd9Sstevel@tonic-gate * Write a summary of a PPPoE message to the given file. This is used 4427c478bd9Sstevel@tonic-gate * for logging and to display received offers in the inquiry (-i) mode. 4437c478bd9Sstevel@tonic-gate */ 4447c478bd9Sstevel@tonic-gate static void 4457c478bd9Sstevel@tonic-gate display_pppoe(FILE *out, const poep_t *poep, int plen, const ppptun_atype *pap) 4467c478bd9Sstevel@tonic-gate { 4477c478bd9Sstevel@tonic-gate int ttyp; 4487c478bd9Sstevel@tonic-gate int tlen; 4497c478bd9Sstevel@tonic-gate const uint8_t *tagp; 4507c478bd9Sstevel@tonic-gate const uint8_t *dp; 4517c478bd9Sstevel@tonic-gate const char *str; 4527c478bd9Sstevel@tonic-gate poer_t poer; 4537c478bd9Sstevel@tonic-gate uint32_t mask; 4547c478bd9Sstevel@tonic-gate 4557c478bd9Sstevel@tonic-gate if (out == stderr) 4567c478bd9Sstevel@tonic-gate logerr(" "); /* Give us a timestamp */ 4577c478bd9Sstevel@tonic-gate /* Print name of sender. */ 4587c478bd9Sstevel@tonic-gate (void) fprintf(out, "%-16s ", ehost(pap)); 4597c478bd9Sstevel@tonic-gate 4607c478bd9Sstevel@tonic-gate /* Loop through tags and print each. */ 4617c478bd9Sstevel@tonic-gate tagp = (const uint8_t *)(poep + 1); 4627c478bd9Sstevel@tonic-gate while (poe_tagcheck(poep, plen, tagp)) { 4637c478bd9Sstevel@tonic-gate ttyp = POET_GET_TYPE(tagp); 4647c478bd9Sstevel@tonic-gate if (ttyp == POETT_END) 4657c478bd9Sstevel@tonic-gate break; 4667c478bd9Sstevel@tonic-gate tlen = POET_GET_LENG(tagp); 4677c478bd9Sstevel@tonic-gate dp = POET_DATA(tagp); 4687c478bd9Sstevel@tonic-gate str = NULL; 4697c478bd9Sstevel@tonic-gate switch (ttyp) { 4707c478bd9Sstevel@tonic-gate case POETT_SERVICE: /* Service-Name */ 4717c478bd9Sstevel@tonic-gate str = "Svc"; 4727c478bd9Sstevel@tonic-gate break; 4737c478bd9Sstevel@tonic-gate case POETT_ACCESS: /* AC-Name */ 4747c478bd9Sstevel@tonic-gate str = "Name"; 4757c478bd9Sstevel@tonic-gate break; 4767c478bd9Sstevel@tonic-gate case POETT_UNIQ: /* Host-Uniq */ 4777c478bd9Sstevel@tonic-gate str = "Uniq"; 4787c478bd9Sstevel@tonic-gate break; 4797c478bd9Sstevel@tonic-gate case POETT_COOKIE: /* AC-Cookie */ 4807c478bd9Sstevel@tonic-gate str = "Cookie"; 4817c478bd9Sstevel@tonic-gate break; 4827c478bd9Sstevel@tonic-gate case POETT_VENDOR: /* Vendor-Specific */ 4837c478bd9Sstevel@tonic-gate break; 4847c478bd9Sstevel@tonic-gate case POETT_RELAY: /* Relay-Session-Id */ 4857c478bd9Sstevel@tonic-gate str = "Relay"; 4867c478bd9Sstevel@tonic-gate break; 4877c478bd9Sstevel@tonic-gate case POETT_NAMERR: /* Service-Name-Error */ 4887c478bd9Sstevel@tonic-gate str = "SvcNameErr"; 4897c478bd9Sstevel@tonic-gate break; 4907c478bd9Sstevel@tonic-gate case POETT_SYSERR: /* AC-System-Error */ 4917c478bd9Sstevel@tonic-gate str = "SysErr"; 4927c478bd9Sstevel@tonic-gate break; 4937c478bd9Sstevel@tonic-gate case POETT_GENERR: /* Generic-Error */ 4947c478bd9Sstevel@tonic-gate str = "GenErr"; 4957c478bd9Sstevel@tonic-gate break; 4967c478bd9Sstevel@tonic-gate case POETT_MULTI: /* Multicast-Capable */ 4977c478bd9Sstevel@tonic-gate break; 4987c478bd9Sstevel@tonic-gate case POETT_HURL: /* Host-URL */ 4997c478bd9Sstevel@tonic-gate str = "URL"; 5007c478bd9Sstevel@tonic-gate break; 5017c478bd9Sstevel@tonic-gate case POETT_MOTM: /* Message-Of-The-Minute */ 5027c478bd9Sstevel@tonic-gate str = "Mesg"; 5037c478bd9Sstevel@tonic-gate break; 5047c478bd9Sstevel@tonic-gate case POETT_RTEADD: /* IP-Route-Add */ 5057c478bd9Sstevel@tonic-gate break; 5067c478bd9Sstevel@tonic-gate } 5077c478bd9Sstevel@tonic-gate switch (ttyp) { 5087c478bd9Sstevel@tonic-gate case POETT_NAMERR: /* Service-Name-Error */ 5097c478bd9Sstevel@tonic-gate case POETT_SYSERR: /* AC-System-Error */ 5107c478bd9Sstevel@tonic-gate if (tlen > 0 && *dp == '\0') 5117c478bd9Sstevel@tonic-gate tlen = 0; 5127c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 5137c478bd9Sstevel@tonic-gate case POETT_SERVICE: /* Service-Name */ 5147c478bd9Sstevel@tonic-gate case POETT_ACCESS: /* AC-Name */ 5157c478bd9Sstevel@tonic-gate case POETT_GENERR: /* Generic-Error */ 5167c478bd9Sstevel@tonic-gate case POETT_MOTM: /* Message-Of-The-Minute */ 5177c478bd9Sstevel@tonic-gate case POETT_HURL: /* Host-URL */ 5187c478bd9Sstevel@tonic-gate (void) fprintf(out, "%s:\"%.*s\" ", str, tlen, dp); 5197c478bd9Sstevel@tonic-gate break; 5207c478bd9Sstevel@tonic-gate case POETT_UNIQ: /* Host-Uniq */ 5217c478bd9Sstevel@tonic-gate case POETT_COOKIE: /* AC-Cookie */ 5227c478bd9Sstevel@tonic-gate case POETT_RELAY: /* Relay-Session-Id */ 5237c478bd9Sstevel@tonic-gate (void) fprintf(out, "%s:", str); 5247c478bd9Sstevel@tonic-gate while (--tlen >= 0) 5257c478bd9Sstevel@tonic-gate (void) fprintf(out, "%02X", *dp++); 5267c478bd9Sstevel@tonic-gate (void) putc(' ', out); 5277c478bd9Sstevel@tonic-gate break; 5287c478bd9Sstevel@tonic-gate case POETT_VENDOR: /* Vendor-Specific */ 5297c478bd9Sstevel@tonic-gate (void) fputs("Vendor:", out); 5307c478bd9Sstevel@tonic-gate if (tlen >= 4) { 5317c478bd9Sstevel@tonic-gate if (*dp++ != 0) { 5327c478bd9Sstevel@tonic-gate (void) fprintf(out, "(%02X?)", dp[-1]); 5337c478bd9Sstevel@tonic-gate } 5347c478bd9Sstevel@tonic-gate (void) fprintf(out, "%x-%x-%x:", dp[0], dp[1], 5357c478bd9Sstevel@tonic-gate dp[2]); 5367c478bd9Sstevel@tonic-gate tlen -= 4; 5377c478bd9Sstevel@tonic-gate dp += 3; 5387c478bd9Sstevel@tonic-gate } 5397c478bd9Sstevel@tonic-gate while (--tlen >= 0) 5407c478bd9Sstevel@tonic-gate (void) fprintf(out, "%02X", *dp++); 5417c478bd9Sstevel@tonic-gate (void) putc(' ', out); 5427c478bd9Sstevel@tonic-gate break; 5437c478bd9Sstevel@tonic-gate case POETT_MULTI: /* Multicast-Capable */ 5447c478bd9Sstevel@tonic-gate (void) fprintf(out, "Multi:%d ", *dp); 5457c478bd9Sstevel@tonic-gate break; 5467c478bd9Sstevel@tonic-gate case POETT_RTEADD: /* IP-Route-Add */ 5477c478bd9Sstevel@tonic-gate if (tlen != sizeof (poer)) { 5487c478bd9Sstevel@tonic-gate (void) fprintf(out, "RTE%d? ", tlen); 5497c478bd9Sstevel@tonic-gate break; 5507c478bd9Sstevel@tonic-gate } 5517c478bd9Sstevel@tonic-gate (void) memcpy(&poer, dp, sizeof (poer)); 5527c478bd9Sstevel@tonic-gate (void) fputs("RTE:", out); 5537c478bd9Sstevel@tonic-gate if (poer.poer_dest_network == 0) 5547c478bd9Sstevel@tonic-gate (void) fputs("default", out); 5557c478bd9Sstevel@tonic-gate else 5567c478bd9Sstevel@tonic-gate (void) fputs(ihost(poer.poer_dest_network), 5577c478bd9Sstevel@tonic-gate out); 5587c478bd9Sstevel@tonic-gate mask = ntohl(poer.poer_subnet_mask); 5597c478bd9Sstevel@tonic-gate if (mask != 0 && mask != (uint32_t)~0) { 5607c478bd9Sstevel@tonic-gate if ((~mask & (~mask + 1)) == 0) 5617c478bd9Sstevel@tonic-gate (void) fprintf(out, "/%d", 5627c478bd9Sstevel@tonic-gate sizeof (struct in_addr) * NBBY + 5637c478bd9Sstevel@tonic-gate 1 - ffs(mask)); 5647c478bd9Sstevel@tonic-gate else 5657c478bd9Sstevel@tonic-gate (void) fprintf(out, "/%s", 5667c478bd9Sstevel@tonic-gate ihost(poer.poer_subnet_mask)); 5677c478bd9Sstevel@tonic-gate } 5687c478bd9Sstevel@tonic-gate (void) fprintf(out, ",%s,%u ", 5697c478bd9Sstevel@tonic-gate ihost(poer.poer_gateway), ntohl(poer.poer_metric)); 5707c478bd9Sstevel@tonic-gate break; 5717c478bd9Sstevel@tonic-gate default: 5727c478bd9Sstevel@tonic-gate (void) fprintf(out, "%s:%d ", poe_tagname(ttyp), tlen); 5737c478bd9Sstevel@tonic-gate break; 5747c478bd9Sstevel@tonic-gate } 5757c478bd9Sstevel@tonic-gate tagp = POET_NEXT(tagp); 5767c478bd9Sstevel@tonic-gate } 5777c478bd9Sstevel@tonic-gate (void) putc('\n', out); 5787c478bd9Sstevel@tonic-gate } 5797c478bd9Sstevel@tonic-gate 5807c478bd9Sstevel@tonic-gate /* 5817c478bd9Sstevel@tonic-gate * Transmit a PPPoE message to the indicated destination. Used for 5827c478bd9Sstevel@tonic-gate * PADI and PADR messages. 5837c478bd9Sstevel@tonic-gate */ 5847c478bd9Sstevel@tonic-gate static int 5857c478bd9Sstevel@tonic-gate send_pppoe(const poep_t *poep, const char *msgname, 5867c478bd9Sstevel@tonic-gate const ppptun_atype *destaddr) 5877c478bd9Sstevel@tonic-gate { 5887c478bd9Sstevel@tonic-gate struct strbuf ctrl; 5897c478bd9Sstevel@tonic-gate struct strbuf data; 5907c478bd9Sstevel@tonic-gate struct ppptun_control *ptc; 5917c478bd9Sstevel@tonic-gate 5927c478bd9Sstevel@tonic-gate /* Set up the control data expected by the driver. */ 5937c478bd9Sstevel@tonic-gate ptc = (struct ppptun_control *)pkt_octl; 5947c478bd9Sstevel@tonic-gate (void) memset(ptc, '\0', sizeof (*ptc)); 5957c478bd9Sstevel@tonic-gate ptc->ptc_discrim = PPPOE_DISCRIM; 5967c478bd9Sstevel@tonic-gate ptc->ptc_action = PTCA_CONTROL; 5977c478bd9Sstevel@tonic-gate ptc->ptc_address = *destaddr; 5987c478bd9Sstevel@tonic-gate ctrl.len = sizeof (*ptc); 5997c478bd9Sstevel@tonic-gate ctrl.buf = (caddr_t)ptc; 6007c478bd9Sstevel@tonic-gate data.len = poe_length(poep) + sizeof (*poep); 6017c478bd9Sstevel@tonic-gate data.buf = (caddr_t)poep; 6027c478bd9Sstevel@tonic-gate if (verbose) 6037c478bd9Sstevel@tonic-gate logerr("%s: Sending %s to %s: %d bytes\n", 6047c478bd9Sstevel@tonic-gate myname, msgname, ehost(destaddr), data.len); 6057c478bd9Sstevel@tonic-gate if (putmsg(tunfd, &ctrl, &data, 0) < 0) { 6067c478bd9Sstevel@tonic-gate logstrerror("putmsg"); 6077c478bd9Sstevel@tonic-gate return (-1); 6087c478bd9Sstevel@tonic-gate } 6097c478bd9Sstevel@tonic-gate return (0); 6107c478bd9Sstevel@tonic-gate } 6117c478bd9Sstevel@tonic-gate 6127c478bd9Sstevel@tonic-gate /* 6137c478bd9Sstevel@tonic-gate * Create and transmit a PPPoE Active Discovery Initiation packet. 6147c478bd9Sstevel@tonic-gate * This is broadcasted to all hosts on the LAN. 6157c478bd9Sstevel@tonic-gate */ 6167c478bd9Sstevel@tonic-gate static int 6177c478bd9Sstevel@tonic-gate send_padi(int localid) 6187c478bd9Sstevel@tonic-gate { 6197c478bd9Sstevel@tonic-gate poep_t *poep; 6207c478bd9Sstevel@tonic-gate ppptun_atype destaddr; 6217c478bd9Sstevel@tonic-gate 6227c478bd9Sstevel@tonic-gate poep = poe_mkheader(pkt_output, POECODE_PADI, 0); 623*f53eecf5SJames Carlson (void) poe_add_str(poep, POETT_SERVICE, service); 6247c478bd9Sstevel@tonic-gate (void) poe_add_long(poep, POETT_UNIQ, localid); 6257c478bd9Sstevel@tonic-gate (void) memset(&destaddr, '\0', sizeof (destaddr)); 6267c478bd9Sstevel@tonic-gate (void) memcpy(destaddr.pta_pppoe.ptma_mac, ether_bcast, 6277c478bd9Sstevel@tonic-gate sizeof (destaddr.pta_pppoe.ptma_mac)); 6287c478bd9Sstevel@tonic-gate return (send_pppoe(poep, "PADI", &destaddr)); 6297c478bd9Sstevel@tonic-gate } 6307c478bd9Sstevel@tonic-gate 6317c478bd9Sstevel@tonic-gate /* 6327c478bd9Sstevel@tonic-gate * This is used by the procedure below -- when the alarm goes off, 6337c478bd9Sstevel@tonic-gate * just exit. (This was once a dummy procedure and used the EINTR 6347c478bd9Sstevel@tonic-gate * side-effect to terminate the loop, but that's not reliable, since 6357c478bd9Sstevel@tonic-gate * the EINTR could be caught and ignored by the calls to standard 6367c478bd9Sstevel@tonic-gate * output.) 6377c478bd9Sstevel@tonic-gate */ 6387c478bd9Sstevel@tonic-gate /* ARGSUSED */ 6397c478bd9Sstevel@tonic-gate static void 6407c478bd9Sstevel@tonic-gate alarm_hand(int dummy) 6417c478bd9Sstevel@tonic-gate { 6427c478bd9Sstevel@tonic-gate exit(0); 6437c478bd9Sstevel@tonic-gate } 6447c478bd9Sstevel@tonic-gate 6457c478bd9Sstevel@tonic-gate /* 6467c478bd9Sstevel@tonic-gate * Send out a single PADI and listen for servers. This implements the 6477c478bd9Sstevel@tonic-gate * "inquiry" (-i) mode. 6487c478bd9Sstevel@tonic-gate */ 6497c478bd9Sstevel@tonic-gate static void 6507c478bd9Sstevel@tonic-gate find_all_servers(int localid) 6517c478bd9Sstevel@tonic-gate { 6527c478bd9Sstevel@tonic-gate struct strbuf ctrl; 6537c478bd9Sstevel@tonic-gate struct strbuf data; 6547c478bd9Sstevel@tonic-gate poep_t *poep; 6557c478bd9Sstevel@tonic-gate int flags; 6567c478bd9Sstevel@tonic-gate struct sigaction act; 6577c478bd9Sstevel@tonic-gate struct ppptun_control *ptc; 6587c478bd9Sstevel@tonic-gate 6597c478bd9Sstevel@tonic-gate /* Set a default 3-second timer */ 6607c478bd9Sstevel@tonic-gate (void) memset(&act, '\0', sizeof (act)); 6617c478bd9Sstevel@tonic-gate act.sa_handler = alarm_hand; 6627c478bd9Sstevel@tonic-gate (void) sigaction(SIGALRM, &act, NULL); 6637c478bd9Sstevel@tonic-gate (void) alarm((pado_wait_time + 999) / 1000); 6647c478bd9Sstevel@tonic-gate 6657c478bd9Sstevel@tonic-gate /* Broadcast a single request. */ 6667c478bd9Sstevel@tonic-gate if (send_padi(localid) != 0) 6677c478bd9Sstevel@tonic-gate return; 6687c478bd9Sstevel@tonic-gate 6697c478bd9Sstevel@tonic-gate /* Loop over responses and print them. */ 6707c478bd9Sstevel@tonic-gate for (;;) { 6717c478bd9Sstevel@tonic-gate ctrl.maxlen = PKT_OCTL_LEN; 6727c478bd9Sstevel@tonic-gate ctrl.buf = (caddr_t)pkt_octl; 6737c478bd9Sstevel@tonic-gate data.maxlen = PKT_INPUT_LEN; 6747c478bd9Sstevel@tonic-gate data.buf = (caddr_t)pkt_input; 6757c478bd9Sstevel@tonic-gate flags = 0; 6767c478bd9Sstevel@tonic-gate 6777c478bd9Sstevel@tonic-gate if (pppoec_getmsg(tunfd, &ctrl, &data, &flags) < 0) 6787c478bd9Sstevel@tonic-gate break; 6797c478bd9Sstevel@tonic-gate 6807c478bd9Sstevel@tonic-gate /* Ignore unwanted responses from the driver. */ 6817c478bd9Sstevel@tonic-gate if (ctrl.len != sizeof (*ptc)) { 6827c478bd9Sstevel@tonic-gate if (verbose) 6837c478bd9Sstevel@tonic-gate logerr("%s: unexpected %d byte" 6847c478bd9Sstevel@tonic-gate " control message from driver.\n", myname, 6857c478bd9Sstevel@tonic-gate ctrl.len); 6867c478bd9Sstevel@tonic-gate continue; 6877c478bd9Sstevel@tonic-gate } 6887c478bd9Sstevel@tonic-gate ptc = (struct ppptun_control *)pkt_octl; 6897c478bd9Sstevel@tonic-gate poep = (poep_t *)pkt_input; 6907c478bd9Sstevel@tonic-gate 6917c478bd9Sstevel@tonic-gate /* If it's an offer, then print it out. */ 6927c478bd9Sstevel@tonic-gate if (poe_code(poep) == POECODE_PADO) { 6937c478bd9Sstevel@tonic-gate display_pppoe(stdout, poep, data.len, 6947c478bd9Sstevel@tonic-gate &ptc->ptc_address); 6957c478bd9Sstevel@tonic-gate } 6967c478bd9Sstevel@tonic-gate } 6977c478bd9Sstevel@tonic-gate } 6987c478bd9Sstevel@tonic-gate 6997c478bd9Sstevel@tonic-gate /* 7007c478bd9Sstevel@tonic-gate * Parse a server filter from the command line. The passed-in string 7017c478bd9Sstevel@tonic-gate * must be allocated and unchanged, since a pointer to it is saved in 7027c478bd9Sstevel@tonic-gate * the filter data structure. The string is also parsed for a MAC 7037c478bd9Sstevel@tonic-gate * address, if possible. 7047c478bd9Sstevel@tonic-gate */ 7057c478bd9Sstevel@tonic-gate static void 7067c478bd9Sstevel@tonic-gate parse_filter(const char *str, int exceptflag) 7077c478bd9Sstevel@tonic-gate { 7087c478bd9Sstevel@tonic-gate struct server_filter *sfnew; 7097c478bd9Sstevel@tonic-gate const char *cp; 7107c478bd9Sstevel@tonic-gate const char *wordstart; 7117c478bd9Sstevel@tonic-gate const char *wordend; 7127c478bd9Sstevel@tonic-gate int len; 7137c478bd9Sstevel@tonic-gate char hbuf[MAXHOSTNAMELEN]; 7147c478bd9Sstevel@tonic-gate uchar_t *ucp; 7157c478bd9Sstevel@tonic-gate uchar_t *mcp; 7167c478bd9Sstevel@tonic-gate 7177c478bd9Sstevel@tonic-gate /* Allocate the new filter structure. */ 7187c478bd9Sstevel@tonic-gate sfnew = (struct server_filter *)calloc(1, sizeof (*sfnew)); 7197c478bd9Sstevel@tonic-gate if (sfnew == NULL) { 7207c478bd9Sstevel@tonic-gate logstrerror("filter allocation"); 7217c478bd9Sstevel@tonic-gate exit(1); 7227c478bd9Sstevel@tonic-gate } 7237c478bd9Sstevel@tonic-gate 7247c478bd9Sstevel@tonic-gate /* Save the string for AC-Name comparison. */ 7257c478bd9Sstevel@tonic-gate sfnew->sf_name = str; 7267c478bd9Sstevel@tonic-gate 7277c478bd9Sstevel@tonic-gate sfnew->sf_isexcept = exceptflag == 0 ? 0 : 1; 7287c478bd9Sstevel@tonic-gate 7297c478bd9Sstevel@tonic-gate /* Extract just one word. */ 7307c478bd9Sstevel@tonic-gate cp = str; 7317c478bd9Sstevel@tonic-gate while (isspace(*cp)) 7327c478bd9Sstevel@tonic-gate cp++; 7337c478bd9Sstevel@tonic-gate wordstart = cp; 7347c478bd9Sstevel@tonic-gate while (*cp != '\0' && !isspace(*cp)) 7357c478bd9Sstevel@tonic-gate cp++; 7367c478bd9Sstevel@tonic-gate wordend = cp; 7377c478bd9Sstevel@tonic-gate if ((len = wordend - wordstart) >= sizeof (hbuf)) 7387c478bd9Sstevel@tonic-gate len = sizeof (hbuf) - 1; 7397c478bd9Sstevel@tonic-gate (void) strlcpy(hbuf, wordstart, len); 7407c478bd9Sstevel@tonic-gate hbuf[len] = '\0'; 7417c478bd9Sstevel@tonic-gate 7427c478bd9Sstevel@tonic-gate /* Try to translate this as an Ethernet host or address. */ 7437c478bd9Sstevel@tonic-gate mcp = sfnew->sf_mask.ether_addr_octet; 7447c478bd9Sstevel@tonic-gate if (ether_hostton(hbuf, &sfnew->sf_mac) == 0) { 7457c478bd9Sstevel@tonic-gate mcp[0] = mcp[1] = mcp[2] = mcp[3] = mcp[4] = mcp[5] = 0xFF; 7467c478bd9Sstevel@tonic-gate sfnew->sf_hasmac = 1; 7477c478bd9Sstevel@tonic-gate } else { 7487c478bd9Sstevel@tonic-gate ucp = sfnew->sf_mac.ether_addr_octet; 7497c478bd9Sstevel@tonic-gate len = wordend - wordstart; 7507c478bd9Sstevel@tonic-gate cp = wordstart; 7517c478bd9Sstevel@tonic-gate while (cp < wordend) { 7527c478bd9Sstevel@tonic-gate if (ucp >= sfnew->sf_mac.ether_addr_octet + 7537c478bd9Sstevel@tonic-gate sizeof (sfnew->sf_mac)) 7547c478bd9Sstevel@tonic-gate break; 7557c478bd9Sstevel@tonic-gate if (*cp == '*') { 7567c478bd9Sstevel@tonic-gate *mcp++ = *ucp++ = 0; 7577c478bd9Sstevel@tonic-gate cp++; 7587c478bd9Sstevel@tonic-gate } else { 7597c478bd9Sstevel@tonic-gate if (!isxdigit(*cp)) 7607c478bd9Sstevel@tonic-gate break; 7617c478bd9Sstevel@tonic-gate *ucp = hexdecode(*cp++); 7627c478bd9Sstevel@tonic-gate if (cp < wordend && isxdigit(*cp)) { 7637c478bd9Sstevel@tonic-gate *ucp = (*ucp << 4) | 7647c478bd9Sstevel@tonic-gate hexdecode(*cp++); 7657c478bd9Sstevel@tonic-gate } 7667c478bd9Sstevel@tonic-gate ucp++; 7677c478bd9Sstevel@tonic-gate *mcp++ = 0xFF; 7687c478bd9Sstevel@tonic-gate } 7697c478bd9Sstevel@tonic-gate if (cp < wordend) { 7707c478bd9Sstevel@tonic-gate if (*cp != ':' || cp + 1 == wordend) 7717c478bd9Sstevel@tonic-gate break; 7727c478bd9Sstevel@tonic-gate cp++; 7737c478bd9Sstevel@tonic-gate } 7747c478bd9Sstevel@tonic-gate } 7757c478bd9Sstevel@tonic-gate if (cp >= wordend) 7767c478bd9Sstevel@tonic-gate sfnew->sf_hasmac = 1; 7777c478bd9Sstevel@tonic-gate else if (verbose) 7787c478bd9Sstevel@tonic-gate logerr("%s: treating '%.*s' as server " 7797c478bd9Sstevel@tonic-gate "name only, not MAC address\n", myname, len, 7807c478bd9Sstevel@tonic-gate wordstart); 7817c478bd9Sstevel@tonic-gate } 7827c478bd9Sstevel@tonic-gate 7837c478bd9Sstevel@tonic-gate /* Add to end of list. */ 7847c478bd9Sstevel@tonic-gate if (sftail == NULL) 7857c478bd9Sstevel@tonic-gate sfhead = sfnew; 7867c478bd9Sstevel@tonic-gate else 7877c478bd9Sstevel@tonic-gate sftail->sf_next = sfnew; 7887c478bd9Sstevel@tonic-gate sftail = sfnew; 7897c478bd9Sstevel@tonic-gate } 7907c478bd9Sstevel@tonic-gate 7917c478bd9Sstevel@tonic-gate /* 7927c478bd9Sstevel@tonic-gate * Create a copy of a given PPPoE message. This is used for enqueuing 7937c478bd9Sstevel@tonic-gate * received PADO (offers) from possible servers. 7947c478bd9Sstevel@tonic-gate */ 7957c478bd9Sstevel@tonic-gate static poemsg_t * 7967c478bd9Sstevel@tonic-gate save_message(const poemsg_t *pmsg) 7977c478bd9Sstevel@tonic-gate { 7987c478bd9Sstevel@tonic-gate poemsg_t *newmsg; 7997c478bd9Sstevel@tonic-gate char *cp; 8007c478bd9Sstevel@tonic-gate 8017c478bd9Sstevel@tonic-gate newmsg = (poemsg_t *)malloc(sizeof (*pmsg) + pmsg->poemsg_len + 8027c478bd9Sstevel@tonic-gate strlen(pmsg->poemsg_iname) + 1); 8037c478bd9Sstevel@tonic-gate if (newmsg != NULL) { 8047c478bd9Sstevel@tonic-gate newmsg->poemsg_next = NULL; 8057c478bd9Sstevel@tonic-gate newmsg->poemsg_data = (const poep_t *)(newmsg + 1); 8067c478bd9Sstevel@tonic-gate (void) memcpy(newmsg + 1, pmsg->poemsg_data, pmsg->poemsg_len); 8077c478bd9Sstevel@tonic-gate newmsg->poemsg_len = pmsg->poemsg_len; 8087c478bd9Sstevel@tonic-gate cp = (char *)newmsg->poemsg_data + pmsg->poemsg_len; 8097c478bd9Sstevel@tonic-gate newmsg->poemsg_iname = (const char *)cp; 8107c478bd9Sstevel@tonic-gate (void) strcpy(cp, pmsg->poemsg_iname); 8117c478bd9Sstevel@tonic-gate (void) memcpy(&newmsg->poemsg_sender, &pmsg->poemsg_sender, 8127c478bd9Sstevel@tonic-gate sizeof (newmsg->poemsg_sender)); 8137c478bd9Sstevel@tonic-gate } 8147c478bd9Sstevel@tonic-gate return (newmsg); 8157c478bd9Sstevel@tonic-gate } 8167c478bd9Sstevel@tonic-gate 8177c478bd9Sstevel@tonic-gate /* 8187c478bd9Sstevel@tonic-gate * Create and send a PPPoE Active Discovery Request (PADR) message to 8197c478bd9Sstevel@tonic-gate * the sender of the given PADO. Some tags -- Service-Name, 8207c478bd9Sstevel@tonic-gate * AC-Cookie, and Relay-Session-Id -- must be copied from PADO to 8217c478bd9Sstevel@tonic-gate * PADR. Others are not. The Service-Name must be selected from the 8227c478bd9Sstevel@tonic-gate * offered services in the PADO based on the user's requested service 8237c478bd9Sstevel@tonic-gate * name. If the server offered "wildcard" service, then we ask for 8247c478bd9Sstevel@tonic-gate * this only if we can't find the user's requested service. 8257c478bd9Sstevel@tonic-gate * 8267c478bd9Sstevel@tonic-gate * Returns 1 if we can't send a valid PADR in response to the given 8277c478bd9Sstevel@tonic-gate * PADO. The offer should be ignored and the next one tried. 8287c478bd9Sstevel@tonic-gate */ 8297c478bd9Sstevel@tonic-gate static int 8307c478bd9Sstevel@tonic-gate send_padr(poesm_t *psm, const poemsg_t *pado) 8317c478bd9Sstevel@tonic-gate { 8327c478bd9Sstevel@tonic-gate poep_t *poep; 8337c478bd9Sstevel@tonic-gate boolean_t haswild; 8347c478bd9Sstevel@tonic-gate boolean_t hassvc; 8357c478bd9Sstevel@tonic-gate const uint8_t *tagp; 8367c478bd9Sstevel@tonic-gate int ttyp; 8377c478bd9Sstevel@tonic-gate int tlen; 8387c478bd9Sstevel@tonic-gate 8397c478bd9Sstevel@tonic-gate /* 8407c478bd9Sstevel@tonic-gate * Increment sequence number for PADR so that we don't mistake 8417c478bd9Sstevel@tonic-gate * old replies for valid ones if the server is very slow. 8427c478bd9Sstevel@tonic-gate */ 8437c478bd9Sstevel@tonic-gate psm->poesm_sequence++; 8447c478bd9Sstevel@tonic-gate 8457c478bd9Sstevel@tonic-gate poep = poe_mkheader(pkt_output, POECODE_PADR, 0); 8467c478bd9Sstevel@tonic-gate (void) poe_two_longs(poep, POETT_UNIQ, psm->poesm_localid, 8477c478bd9Sstevel@tonic-gate psm->poesm_sequence); 8487c478bd9Sstevel@tonic-gate 8497c478bd9Sstevel@tonic-gate haswild = B_FALSE; 8507c478bd9Sstevel@tonic-gate hassvc = B_FALSE; 8517c478bd9Sstevel@tonic-gate tagp = (const uint8_t *)(pado->poemsg_data + 1); 8527c478bd9Sstevel@tonic-gate while (poe_tagcheck(pado->poemsg_data, pado->poemsg_len, tagp)) { 8537c478bd9Sstevel@tonic-gate ttyp = POET_GET_TYPE(tagp); 8547c478bd9Sstevel@tonic-gate if (ttyp == POETT_END) 8557c478bd9Sstevel@tonic-gate break; 8567c478bd9Sstevel@tonic-gate tlen = POET_GET_LENG(tagp); 8577c478bd9Sstevel@tonic-gate switch (ttyp) { 8587c478bd9Sstevel@tonic-gate case POETT_SERVICE: /* Service-Name */ 8597c478bd9Sstevel@tonic-gate /* Allow only one */ 8607c478bd9Sstevel@tonic-gate if (hassvc) 8617c478bd9Sstevel@tonic-gate break; 8627c478bd9Sstevel@tonic-gate if (tlen == 0) { 8637c478bd9Sstevel@tonic-gate haswild = B_TRUE; 8647c478bd9Sstevel@tonic-gate break; 8657c478bd9Sstevel@tonic-gate } 8667c478bd9Sstevel@tonic-gate if (service[0] == '\0' || 8677c478bd9Sstevel@tonic-gate (tlen == strlen(service) && 8687c478bd9Sstevel@tonic-gate memcmp(service, POET_DATA(tagp), tlen) == 0)) { 8697c478bd9Sstevel@tonic-gate (void) poe_tag_copy(poep, tagp); 8707c478bd9Sstevel@tonic-gate hassvc = B_TRUE; 8717c478bd9Sstevel@tonic-gate } 8727c478bd9Sstevel@tonic-gate break; 8737c478bd9Sstevel@tonic-gate /* Ones we should discard */ 8747c478bd9Sstevel@tonic-gate case POETT_ACCESS: /* AC-Name */ 8757c478bd9Sstevel@tonic-gate case POETT_UNIQ: /* Host-Uniq */ 8767c478bd9Sstevel@tonic-gate case POETT_NAMERR: /* Service-Name-Error */ 8777c478bd9Sstevel@tonic-gate case POETT_SYSERR: /* AC-System-Error */ 8787c478bd9Sstevel@tonic-gate case POETT_GENERR: /* Generic-Error */ 8797c478bd9Sstevel@tonic-gate case POETT_HURL: /* Host-URL */ 8807c478bd9Sstevel@tonic-gate case POETT_MOTM: /* Message-Of-The-Minute */ 8817c478bd9Sstevel@tonic-gate case POETT_RTEADD: /* IP-Route-Add */ 8827c478bd9Sstevel@tonic-gate case POETT_VENDOR: /* Vendor-Specific */ 8837c478bd9Sstevel@tonic-gate case POETT_MULTI: /* Multicast-Capable */ 8847c478bd9Sstevel@tonic-gate default: /* Anything else we don't understand */ 8857c478bd9Sstevel@tonic-gate break; 8867c478bd9Sstevel@tonic-gate /* Ones we should copy */ 8877c478bd9Sstevel@tonic-gate case POETT_COOKIE: /* AC-Cookie */ 8887c478bd9Sstevel@tonic-gate case POETT_RELAY: /* Relay-Session-Id */ 8897c478bd9Sstevel@tonic-gate (void) poe_tag_copy(poep, tagp); 8907c478bd9Sstevel@tonic-gate break; 8917c478bd9Sstevel@tonic-gate } 8927c478bd9Sstevel@tonic-gate tagp = POET_NEXT(tagp); 8937c478bd9Sstevel@tonic-gate } 8947c478bd9Sstevel@tonic-gate if (!hassvc) { 895*f53eecf5SJames Carlson if (haswild && service[0] == '\0') 8967c478bd9Sstevel@tonic-gate (void) poe_add_str(poep, POETT_SERVICE, ""); 8977c478bd9Sstevel@tonic-gate else 8987c478bd9Sstevel@tonic-gate return (1); 8997c478bd9Sstevel@tonic-gate } 9007c478bd9Sstevel@tonic-gate 9017c478bd9Sstevel@tonic-gate return (send_pppoe(poep, "PADR", &pado->poemsg_sender)); 9027c478bd9Sstevel@tonic-gate } 9037c478bd9Sstevel@tonic-gate 9047c478bd9Sstevel@tonic-gate /* 9057c478bd9Sstevel@tonic-gate * ******************************************************************** 9067c478bd9Sstevel@tonic-gate * act_* functions implement the actions driven by the state machine 9077c478bd9Sstevel@tonic-gate * tables. See "action_table" below. 9087c478bd9Sstevel@tonic-gate * 9097c478bd9Sstevel@tonic-gate * All action routines must return the next state value. 9107c478bd9Sstevel@tonic-gate * ******************************************************************** 9117c478bd9Sstevel@tonic-gate */ 9127c478bd9Sstevel@tonic-gate 9137c478bd9Sstevel@tonic-gate /* ARGSUSED */ 9147c478bd9Sstevel@tonic-gate static int 9157c478bd9Sstevel@tonic-gate act_none(poesm_t *psm, poemsg_t *pmsg, int event, int nextst) 9167c478bd9Sstevel@tonic-gate { 9177c478bd9Sstevel@tonic-gate return (nextst); 9187c478bd9Sstevel@tonic-gate } 9197c478bd9Sstevel@tonic-gate 9207c478bd9Sstevel@tonic-gate /* ARGSUSED */ 9217c478bd9Sstevel@tonic-gate static int 9227c478bd9Sstevel@tonic-gate act_fail(poesm_t *psm, poemsg_t *pmsg, int event, int nextst) 9237c478bd9Sstevel@tonic-gate { 9247c478bd9Sstevel@tonic-gate if (verbose) 9257c478bd9Sstevel@tonic-gate logerr("%s: unrecoverable error\n", myname); 9267c478bd9Sstevel@tonic-gate return (PCSMS_DEAD); 9277c478bd9Sstevel@tonic-gate } 9287c478bd9Sstevel@tonic-gate 9297c478bd9Sstevel@tonic-gate /* ARGSUSED */ 9307c478bd9Sstevel@tonic-gate static int 9317c478bd9Sstevel@tonic-gate act_spadi(poesm_t *psm, poemsg_t *pmsg, int event, int nextst) 9327c478bd9Sstevel@tonic-gate { 9337c478bd9Sstevel@tonic-gate if (send_padi(psm->poesm_localid) != 0) 9347c478bd9Sstevel@tonic-gate return (PCSMS_DEAD); 9357c478bd9Sstevel@tonic-gate /* 9367c478bd9Sstevel@tonic-gate * If this is the first time, then initialize the retry count 9377c478bd9Sstevel@tonic-gate * and interval. 9387c478bd9Sstevel@tonic-gate */ 9397c478bd9Sstevel@tonic-gate if (psm->poesm_state == PCSMS_DEAD) { 9407c478bd9Sstevel@tonic-gate psm->poesm_count = 3; 9417c478bd9Sstevel@tonic-gate psm->poesm_interval = pado_wait_time; 9427c478bd9Sstevel@tonic-gate } else { 9437c478bd9Sstevel@tonic-gate if ((psm->poesm_interval <<= 1) > RESTART_LIMIT) 9447c478bd9Sstevel@tonic-gate psm->poesm_interval = RESTART_LIMIT; 9457c478bd9Sstevel@tonic-gate } 9467c478bd9Sstevel@tonic-gate psm->poesm_timer = psm->poesm_interval; 9477c478bd9Sstevel@tonic-gate (void) gettimeofday(&tvstart, NULL); 9487c478bd9Sstevel@tonic-gate return (nextst); 9497c478bd9Sstevel@tonic-gate } 9507c478bd9Sstevel@tonic-gate 9517c478bd9Sstevel@tonic-gate /* ARGSUSED */ 9527c478bd9Sstevel@tonic-gate static int 9537c478bd9Sstevel@tonic-gate act_add(poesm_t *psm, poemsg_t *pmsg, int event, int nextst) 9547c478bd9Sstevel@tonic-gate { 9557c478bd9Sstevel@tonic-gate pmsg = save_message(pmsg); 9567c478bd9Sstevel@tonic-gate if (pmsg != NULL) { 9577c478bd9Sstevel@tonic-gate if (psm->poesm_lastoff == NULL) 9587c478bd9Sstevel@tonic-gate psm->poesm_firstoff = pmsg; 9597c478bd9Sstevel@tonic-gate else 9607c478bd9Sstevel@tonic-gate psm->poesm_lastoff->poemsg_next = pmsg; 9617c478bd9Sstevel@tonic-gate psm->poesm_lastoff = pmsg; 9627c478bd9Sstevel@tonic-gate } 9637c478bd9Sstevel@tonic-gate return (nextst); 9647c478bd9Sstevel@tonic-gate } 9657c478bd9Sstevel@tonic-gate 9667c478bd9Sstevel@tonic-gate /* ARGSUSED */ 9677c478bd9Sstevel@tonic-gate static int 9687c478bd9Sstevel@tonic-gate act_spadr(poesm_t *psm, poemsg_t *pmsg, int event, int nextst) 9697c478bd9Sstevel@tonic-gate { 9707c478bd9Sstevel@tonic-gate poemsg_t *msgp; 9717c478bd9Sstevel@tonic-gate int retv; 9727c478bd9Sstevel@tonic-gate 9737c478bd9Sstevel@tonic-gate for (;;) { 9747c478bd9Sstevel@tonic-gate if ((msgp = psm->poesm_firstoff) == NULL) 9757c478bd9Sstevel@tonic-gate return (PCSMS_DEAD); 9767c478bd9Sstevel@tonic-gate retv = send_padr(psm, msgp); 9777c478bd9Sstevel@tonic-gate if (retv < 0) 9787c478bd9Sstevel@tonic-gate return (PCSMS_DEAD); 9797c478bd9Sstevel@tonic-gate if (retv == 0) 9807c478bd9Sstevel@tonic-gate break; 9817c478bd9Sstevel@tonic-gate /* Can't send this request; try looking at next offer. */ 9827c478bd9Sstevel@tonic-gate psm->poesm_firstoff = msgp->poemsg_next; 9837c478bd9Sstevel@tonic-gate msgp->poemsg_next = psm->poesm_tried; 9847c478bd9Sstevel@tonic-gate psm->poesm_tried = msgp; 9857c478bd9Sstevel@tonic-gate } 9867c478bd9Sstevel@tonic-gate if (psm->poesm_state != PCSMS_REQSENT) { 9877c478bd9Sstevel@tonic-gate psm->poesm_count = 3; 9887c478bd9Sstevel@tonic-gate psm->poesm_interval = pads_wait_time; 9897c478bd9Sstevel@tonic-gate } else { 9907c478bd9Sstevel@tonic-gate if ((psm->poesm_interval <<= 1) > RESTART_LIMIT) 9917c478bd9Sstevel@tonic-gate psm->poesm_interval = RESTART_LIMIT; 9927c478bd9Sstevel@tonic-gate } 9937c478bd9Sstevel@tonic-gate psm->poesm_timer = psm->poesm_interval; 9947c478bd9Sstevel@tonic-gate (void) gettimeofday(&tvstart, NULL); 9957c478bd9Sstevel@tonic-gate return (nextst); 9967c478bd9Sstevel@tonic-gate } 9977c478bd9Sstevel@tonic-gate 9987c478bd9Sstevel@tonic-gate /* ARGSUSED */ 9997c478bd9Sstevel@tonic-gate static int 10007c478bd9Sstevel@tonic-gate act_spadrp(poesm_t *psm, poemsg_t *pmsg, int event, int nextst) 10017c478bd9Sstevel@tonic-gate { 10027c478bd9Sstevel@tonic-gate int retv; 10037c478bd9Sstevel@tonic-gate 10047c478bd9Sstevel@tonic-gate retv = send_padr(psm, pmsg); 10057c478bd9Sstevel@tonic-gate if (retv < 0) 10067c478bd9Sstevel@tonic-gate return (PCSMS_DEAD); 10077c478bd9Sstevel@tonic-gate pmsg = save_message(pmsg); 10087c478bd9Sstevel@tonic-gate if (retv > 0) { 10097c478bd9Sstevel@tonic-gate /* 10107c478bd9Sstevel@tonic-gate * Cannot use this one; mark as tried and continue as 10117c478bd9Sstevel@tonic-gate * if we never saw it. 10127c478bd9Sstevel@tonic-gate */ 10137c478bd9Sstevel@tonic-gate pmsg->poemsg_next = psm->poesm_tried; 10147c478bd9Sstevel@tonic-gate psm->poesm_tried = pmsg; 10157c478bd9Sstevel@tonic-gate return (psm->poesm_state); 10167c478bd9Sstevel@tonic-gate } 10177c478bd9Sstevel@tonic-gate pmsg->poemsg_next = psm->poesm_firstoff; 10187c478bd9Sstevel@tonic-gate psm->poesm_firstoff = pmsg; 10197c478bd9Sstevel@tonic-gate if (psm->poesm_lastoff == NULL) 10207c478bd9Sstevel@tonic-gate psm->poesm_lastoff = pmsg; 10217c478bd9Sstevel@tonic-gate psm->poesm_count = 3; 10227c478bd9Sstevel@tonic-gate psm->poesm_timer = psm->poesm_interval = pads_wait_time; 10237c478bd9Sstevel@tonic-gate (void) gettimeofday(&tvstart, NULL); 10247c478bd9Sstevel@tonic-gate return (nextst); 10257c478bd9Sstevel@tonic-gate } 10267c478bd9Sstevel@tonic-gate 10277c478bd9Sstevel@tonic-gate /* ARGSUSED */ 10287c478bd9Sstevel@tonic-gate static int 10297c478bd9Sstevel@tonic-gate act_spadrn(poesm_t *psm, poemsg_t *pmsg, int event, int nextst) 10307c478bd9Sstevel@tonic-gate { 10317c478bd9Sstevel@tonic-gate poemsg_t *msgp; 10327c478bd9Sstevel@tonic-gate int retv; 10337c478bd9Sstevel@tonic-gate 10347c478bd9Sstevel@tonic-gate if ((msgp = psm->poesm_firstoff) == NULL) 10357c478bd9Sstevel@tonic-gate return (PCSMS_DEAD); 10367c478bd9Sstevel@tonic-gate do { 10377c478bd9Sstevel@tonic-gate psm->poesm_firstoff = msgp->poemsg_next; 10387c478bd9Sstevel@tonic-gate msgp->poemsg_next = psm->poesm_tried; 10397c478bd9Sstevel@tonic-gate psm->poesm_tried = msgp; 10407c478bd9Sstevel@tonic-gate if ((msgp = psm->poesm_firstoff) == NULL) 10417c478bd9Sstevel@tonic-gate return (PCSMS_DEAD); 10427c478bd9Sstevel@tonic-gate retv = send_padr(psm, msgp); 10437c478bd9Sstevel@tonic-gate if (retv < 0) 10447c478bd9Sstevel@tonic-gate return (PCSMS_DEAD); 10457c478bd9Sstevel@tonic-gate } while (retv != 0); 10467c478bd9Sstevel@tonic-gate psm->poesm_count = 3; 10477c478bd9Sstevel@tonic-gate psm->poesm_timer = psm->poesm_interval = pads_wait_time; 10487c478bd9Sstevel@tonic-gate (void) gettimeofday(&tvstart, NULL); 10497c478bd9Sstevel@tonic-gate return (nextst); 10507c478bd9Sstevel@tonic-gate } 10517c478bd9Sstevel@tonic-gate 10527c478bd9Sstevel@tonic-gate /* 10537c478bd9Sstevel@tonic-gate * For safety -- remove end of line from strings passed back to pppd. 10547c478bd9Sstevel@tonic-gate */ 10557c478bd9Sstevel@tonic-gate static void 10567c478bd9Sstevel@tonic-gate remove_eol(char *str, size_t len) 10577c478bd9Sstevel@tonic-gate { 10587c478bd9Sstevel@tonic-gate while (len > 0) { 10597c478bd9Sstevel@tonic-gate if (*str == '\n') 10607c478bd9Sstevel@tonic-gate *str = '$'; 10617c478bd9Sstevel@tonic-gate str++; 10627c478bd9Sstevel@tonic-gate len--; 10637c478bd9Sstevel@tonic-gate } 10647c478bd9Sstevel@tonic-gate } 10657c478bd9Sstevel@tonic-gate 10667c478bd9Sstevel@tonic-gate /* ARGSUSED */ 10677c478bd9Sstevel@tonic-gate static int 10687c478bd9Sstevel@tonic-gate act_open(poesm_t *psm, poemsg_t *pmsg, int event, int nextst) 10697c478bd9Sstevel@tonic-gate { 10707c478bd9Sstevel@tonic-gate struct ppptun_peer ptp; 10717c478bd9Sstevel@tonic-gate union ppptun_name ptn; 10727c478bd9Sstevel@tonic-gate const char *cp; 10737c478bd9Sstevel@tonic-gate FILE *fp; 10747c478bd9Sstevel@tonic-gate const uint8_t *tagp, *vp; 10757c478bd9Sstevel@tonic-gate int tlen, ttyp; 10767c478bd9Sstevel@tonic-gate char *access; 10777c478bd9Sstevel@tonic-gate uint32_t val; 10787c478bd9Sstevel@tonic-gate size_t acc_len, serv_len; 10797c478bd9Sstevel@tonic-gate 10807c478bd9Sstevel@tonic-gate /* 10817c478bd9Sstevel@tonic-gate * The server has now assigned its session ID for the data 10827c478bd9Sstevel@tonic-gate * (PPP) portion of this tunnel. Send that ID down to the 10837c478bd9Sstevel@tonic-gate * driver. 10847c478bd9Sstevel@tonic-gate */ 10857c478bd9Sstevel@tonic-gate (void) memset(&ptp, '\0', sizeof (ptp)); 10867c478bd9Sstevel@tonic-gate ptp.ptp_lsessid = psm->poesm_localid; 10877c478bd9Sstevel@tonic-gate ptp.ptp_rsessid = poe_session_id(pmsg->poemsg_data); 10887c478bd9Sstevel@tonic-gate (void) memcpy(&ptp.ptp_address, &pmsg->poemsg_sender, 10897c478bd9Sstevel@tonic-gate sizeof (ptp.ptp_address)); 10907c478bd9Sstevel@tonic-gate ptp.ptp_style = PTS_PPPOE; 10917c478bd9Sstevel@tonic-gate if (strioctl(tunfd, PPPTUN_SPEER, &ptp, sizeof (ptp), sizeof (ptp)) < 10927c478bd9Sstevel@tonic-gate 0) { 10937c478bd9Sstevel@tonic-gate logstrerror("PPPTUN_SPEER"); 10947c478bd9Sstevel@tonic-gate return (PCSMS_DEAD); 10957c478bd9Sstevel@tonic-gate } 10967c478bd9Sstevel@tonic-gate 10977c478bd9Sstevel@tonic-gate /* 10987c478bd9Sstevel@tonic-gate * Data communication is now possible on this session. 10997c478bd9Sstevel@tonic-gate * Connect the data portion to the correct lower stream. 11007c478bd9Sstevel@tonic-gate */ 11017c478bd9Sstevel@tonic-gate if ((cp = strchr(pmsg->poemsg_iname, ':')) == NULL) 11027c478bd9Sstevel@tonic-gate cp = pmsg->poemsg_iname + strlen(pmsg->poemsg_iname); 11037c478bd9Sstevel@tonic-gate (void) snprintf(ptn.ptn_name, sizeof (ptn.ptn_name), "%.*s:pppoe", 11047c478bd9Sstevel@tonic-gate cp - pmsg->poemsg_iname, pmsg->poemsg_iname); 11057c478bd9Sstevel@tonic-gate if (strioctl(tunfd, PPPTUN_SDATA, &ptn, sizeof (ptn), 0) < 0) { 11067c478bd9Sstevel@tonic-gate logerr("%s: PPPTUN_SDATA %s: %s\n", 11077c478bd9Sstevel@tonic-gate myname, ptn.ptn_name, mystrerror(errno)); 11087c478bd9Sstevel@tonic-gate return (PCSMS_DEAD); 11097c478bd9Sstevel@tonic-gate } 11107c478bd9Sstevel@tonic-gate if (verbose) 11117c478bd9Sstevel@tonic-gate logerr("%s: Connection open; session %04X on " 11127c478bd9Sstevel@tonic-gate "%s\n", myname, ptp.ptp_rsessid, ptn.ptn_name); 11137c478bd9Sstevel@tonic-gate 11147c478bd9Sstevel@tonic-gate /* 11157c478bd9Sstevel@tonic-gate * Walk through the PADS message to get the access server name 11167c478bd9Sstevel@tonic-gate * and the service. If there are multiple instances of either 11177c478bd9Sstevel@tonic-gate * tag, then take the last access server and the first 11187c478bd9Sstevel@tonic-gate * non-null service. 11197c478bd9Sstevel@tonic-gate */ 11207c478bd9Sstevel@tonic-gate access = ""; 11217c478bd9Sstevel@tonic-gate acc_len = 0; 11227c478bd9Sstevel@tonic-gate serv_len = strlen(service); 11237c478bd9Sstevel@tonic-gate tagp = (const uint8_t *)(pmsg->poemsg_data + 1); 11247c478bd9Sstevel@tonic-gate while (poe_tagcheck(pmsg->poemsg_data, pmsg->poemsg_len, tagp)) { 11257c478bd9Sstevel@tonic-gate ttyp = POET_GET_TYPE(tagp); 11267c478bd9Sstevel@tonic-gate if (ttyp == POETT_END) 11277c478bd9Sstevel@tonic-gate break; 11287c478bd9Sstevel@tonic-gate tlen = POET_GET_LENG(tagp); 11297c478bd9Sstevel@tonic-gate if (ttyp == POETT_ACCESS) { 11307c478bd9Sstevel@tonic-gate access = (char *)POET_DATA(tagp); 11317c478bd9Sstevel@tonic-gate acc_len = tlen; 11327c478bd9Sstevel@tonic-gate } 11337c478bd9Sstevel@tonic-gate if (serv_len == 0 && ttyp == POETT_SERVICE && tlen != 0) { 11347c478bd9Sstevel@tonic-gate service = (char *)POET_DATA(tagp); 11357c478bd9Sstevel@tonic-gate serv_len = tlen; 11367c478bd9Sstevel@tonic-gate } 11377c478bd9Sstevel@tonic-gate tagp = POET_NEXT(tagp); 11387c478bd9Sstevel@tonic-gate } 11397c478bd9Sstevel@tonic-gate 11407c478bd9Sstevel@tonic-gate /* 11417c478bd9Sstevel@tonic-gate * Remove end of line to make sure that integrity of values 11427c478bd9Sstevel@tonic-gate * passed back to pppd can't be compromised by the PPPoE 11437c478bd9Sstevel@tonic-gate * server. 11447c478bd9Sstevel@tonic-gate */ 11457c478bd9Sstevel@tonic-gate remove_eol(service, serv_len); 11467c478bd9Sstevel@tonic-gate remove_eol(access, acc_len); 11477c478bd9Sstevel@tonic-gate 11487c478bd9Sstevel@tonic-gate /* 11497c478bd9Sstevel@tonic-gate * pppd has given us a pipe as fd 3, and we're expected to 11507c478bd9Sstevel@tonic-gate * write out the values of the following environment 11517c478bd9Sstevel@tonic-gate * variables: 11527c478bd9Sstevel@tonic-gate * IF_AND_SERVICE 11537c478bd9Sstevel@tonic-gate * SERVICE_NAME 11547c478bd9Sstevel@tonic-gate * AC_NAME 11557c478bd9Sstevel@tonic-gate * AC_MAC 11567c478bd9Sstevel@tonic-gate * SESSION_ID 11577c478bd9Sstevel@tonic-gate * VENDOR_SPECIFIC_1 ... N 11587c478bd9Sstevel@tonic-gate * See usr.bin/pppd/plugins/pppoe.c for more information. 11597c478bd9Sstevel@tonic-gate */ 11607c478bd9Sstevel@tonic-gate if ((fp = fdopen(3, "w")) != NULL) { 11617c478bd9Sstevel@tonic-gate (void) fprintf(fp, "%.*s:%.*s\n", 11627c478bd9Sstevel@tonic-gate cp - pmsg->poemsg_iname, pmsg->poemsg_iname, serv_len, 11637c478bd9Sstevel@tonic-gate service); 11647c478bd9Sstevel@tonic-gate (void) fprintf(fp, "%.*s\n", serv_len, service); 11657c478bd9Sstevel@tonic-gate (void) fprintf(fp, "%.*s\n", acc_len, access); 11667c478bd9Sstevel@tonic-gate (void) fprintf(fp, "%s\n", ehost(&pmsg->poemsg_sender)); 11677c478bd9Sstevel@tonic-gate (void) fprintf(fp, "%d\n", poe_session_id(pmsg->poemsg_data)); 11687c478bd9Sstevel@tonic-gate tagp = (const uint8_t *)(pmsg->poemsg_data + 1); 11697c478bd9Sstevel@tonic-gate while (poe_tagcheck(pmsg->poemsg_data, pmsg->poemsg_len, 11707c478bd9Sstevel@tonic-gate tagp)) { 11717c478bd9Sstevel@tonic-gate ttyp = POET_GET_TYPE(tagp); 11727c478bd9Sstevel@tonic-gate if (ttyp == POETT_END) 11737c478bd9Sstevel@tonic-gate break; 11747c478bd9Sstevel@tonic-gate tlen = POET_GET_LENG(tagp); 11757c478bd9Sstevel@tonic-gate if (ttyp == POETT_VENDOR && tlen >= 4) { 11767c478bd9Sstevel@tonic-gate (void) memcpy(&val, POET_DATA(tagp), 4); 11777c478bd9Sstevel@tonic-gate (void) fprintf(fp, "%08lX:", 11787c478bd9Sstevel@tonic-gate (unsigned long)ntohl(val)); 11797c478bd9Sstevel@tonic-gate tlen -= 4; 11807c478bd9Sstevel@tonic-gate vp = POET_DATA(tagp) + 4; 11817c478bd9Sstevel@tonic-gate while (--tlen >= 0) 11827c478bd9Sstevel@tonic-gate (void) fprintf(fp, "%02X", *vp++); 11837c478bd9Sstevel@tonic-gate (void) putc('\n', fp); 11847c478bd9Sstevel@tonic-gate } 11857c478bd9Sstevel@tonic-gate tagp = POET_NEXT(tagp); 11867c478bd9Sstevel@tonic-gate } 11877c478bd9Sstevel@tonic-gate (void) fclose(fp); 11887c478bd9Sstevel@tonic-gate } 11897c478bd9Sstevel@tonic-gate 11907c478bd9Sstevel@tonic-gate return (nextst); 11917c478bd9Sstevel@tonic-gate } 11927c478bd9Sstevel@tonic-gate 11937c478bd9Sstevel@tonic-gate static int (* const action_table[PCSMA__MAX])(poesm_t *psm, poemsg_t *pmsg, 11947c478bd9Sstevel@tonic-gate int event, int nextst) = { 11957c478bd9Sstevel@tonic-gate act_none, act_fail, act_spadi, act_add, act_spadr, act_spadrp, 11967c478bd9Sstevel@tonic-gate act_spadrn, act_open 11977c478bd9Sstevel@tonic-gate }; 11987c478bd9Sstevel@tonic-gate 11997c478bd9Sstevel@tonic-gate /* 12007c478bd9Sstevel@tonic-gate * Dispatch an event and a corresponding message on a given state 12017c478bd9Sstevel@tonic-gate * machine. 12027c478bd9Sstevel@tonic-gate */ 12037c478bd9Sstevel@tonic-gate static void 12047c478bd9Sstevel@tonic-gate handle_event(poesm_t *psm, int event, poemsg_t *pmsg) 12057c478bd9Sstevel@tonic-gate { 12067c478bd9Sstevel@tonic-gate int nextst; 12077c478bd9Sstevel@tonic-gate 12087c478bd9Sstevel@tonic-gate if (verbose) 12097c478bd9Sstevel@tonic-gate logerr("%s: PPPoE Event %s (%d) in state %s " 12107c478bd9Sstevel@tonic-gate "(%d): action %s (%d)\n", myname, poe_event(event), event, 12117c478bd9Sstevel@tonic-gate poe_state(psm->poesm_state), psm->poesm_state, 12127c478bd9Sstevel@tonic-gate poe_action(client_action[psm->poesm_state][event]), 12137c478bd9Sstevel@tonic-gate client_action[psm->poesm_state][event]); 12147c478bd9Sstevel@tonic-gate 12157c478bd9Sstevel@tonic-gate nextst = (*action_table[client_action[psm->poesm_state][event]])(psm, 12167c478bd9Sstevel@tonic-gate pmsg, event, client_next_state[psm->poesm_state][event]); 12177c478bd9Sstevel@tonic-gate 12187c478bd9Sstevel@tonic-gate if (verbose) 12197c478bd9Sstevel@tonic-gate logerr("%s: PPPoE State change %s (%d) -> %s (%d)\n", myname, 12207c478bd9Sstevel@tonic-gate poe_state(psm->poesm_state), psm->poesm_state, 12217c478bd9Sstevel@tonic-gate poe_state(nextst), nextst); 12227c478bd9Sstevel@tonic-gate 12237c478bd9Sstevel@tonic-gate psm->poesm_state = nextst; 12247c478bd9Sstevel@tonic-gate 12257c478bd9Sstevel@tonic-gate /* 12267c478bd9Sstevel@tonic-gate * Life-altering states are handled here. If we reach dead 12277c478bd9Sstevel@tonic-gate * state again after starting, then we failed. If we reach 12287c478bd9Sstevel@tonic-gate * conversational state, then we're open. 12297c478bd9Sstevel@tonic-gate */ 12307c478bd9Sstevel@tonic-gate if (nextst == PCSMS_DEAD) { 12317c478bd9Sstevel@tonic-gate if (verbose) 12327c478bd9Sstevel@tonic-gate logerr("%s: action failed\n", myname); 12337c478bd9Sstevel@tonic-gate exit(1); 12347c478bd9Sstevel@tonic-gate } 12357c478bd9Sstevel@tonic-gate if (nextst == PCSMS_CONVERS) { 12367c478bd9Sstevel@tonic-gate if (verbose) 12377c478bd9Sstevel@tonic-gate logerr("%s: connected\n", myname); 12387c478bd9Sstevel@tonic-gate exit(0); 12397c478bd9Sstevel@tonic-gate } 12407c478bd9Sstevel@tonic-gate } 12417c478bd9Sstevel@tonic-gate 12427c478bd9Sstevel@tonic-gate /* 12437c478bd9Sstevel@tonic-gate * Check for error message tags in the PPPoE packet. We must ignore 12447c478bd9Sstevel@tonic-gate * offers that merely report errors, and need to log errors in any 12457c478bd9Sstevel@tonic-gate * case. 12467c478bd9Sstevel@tonic-gate */ 12477c478bd9Sstevel@tonic-gate static int 12487c478bd9Sstevel@tonic-gate error_check(poemsg_t *pmsg) 12497c478bd9Sstevel@tonic-gate { 12507c478bd9Sstevel@tonic-gate const uint8_t *tagp; 12517c478bd9Sstevel@tonic-gate int ttyp; 12527c478bd9Sstevel@tonic-gate 12537c478bd9Sstevel@tonic-gate tagp = (const uint8_t *)(pmsg->poemsg_data + 1); 12547c478bd9Sstevel@tonic-gate while (poe_tagcheck(pmsg->poemsg_data, pmsg->poemsg_len, tagp)) { 12557c478bd9Sstevel@tonic-gate ttyp = POET_GET_TYPE(tagp); 12567c478bd9Sstevel@tonic-gate if (ttyp == POETT_END) 12577c478bd9Sstevel@tonic-gate break; 12587c478bd9Sstevel@tonic-gate if (ttyp == POETT_NAMERR || ttyp == POETT_SYSERR || 12597c478bd9Sstevel@tonic-gate ttyp == POETT_GENERR) { 12607c478bd9Sstevel@tonic-gate if (verbose) 12617c478bd9Sstevel@tonic-gate display_pppoe(stderr, pmsg->poemsg_data, 12627c478bd9Sstevel@tonic-gate pmsg->poemsg_len, &pmsg->poemsg_sender); 12637c478bd9Sstevel@tonic-gate return (-1); 12647c478bd9Sstevel@tonic-gate } 12657c478bd9Sstevel@tonic-gate tagp = POET_NEXT(tagp); 12667c478bd9Sstevel@tonic-gate } 12677c478bd9Sstevel@tonic-gate return (0); 12687c478bd9Sstevel@tonic-gate } 12697c478bd9Sstevel@tonic-gate 12707c478bd9Sstevel@tonic-gate /* 12717c478bd9Sstevel@tonic-gate * Extract sequence number, if any, from PADS message, so that we can 12727c478bd9Sstevel@tonic-gate * relate it to the PADR that we sent. 12737c478bd9Sstevel@tonic-gate */ 12747c478bd9Sstevel@tonic-gate static uint32_t 12757c478bd9Sstevel@tonic-gate get_sequence(const poemsg_t *pmsg) 12767c478bd9Sstevel@tonic-gate { 12777c478bd9Sstevel@tonic-gate const uint8_t *tagp; 12787c478bd9Sstevel@tonic-gate int ttyp; 12797c478bd9Sstevel@tonic-gate uint32_t vals[2]; 12807c478bd9Sstevel@tonic-gate 12817c478bd9Sstevel@tonic-gate tagp = (const uint8_t *)(pmsg->poemsg_data + 1); 12827c478bd9Sstevel@tonic-gate while (poe_tagcheck(pmsg->poemsg_data, pmsg->poemsg_len, tagp)) { 12837c478bd9Sstevel@tonic-gate ttyp = POET_GET_TYPE(tagp); 12847c478bd9Sstevel@tonic-gate if (ttyp == POETT_END) 12857c478bd9Sstevel@tonic-gate break; 12867c478bd9Sstevel@tonic-gate if (ttyp == POETT_UNIQ) { 12877c478bd9Sstevel@tonic-gate if (POET_GET_LENG(tagp) < sizeof (vals)) 12887c478bd9Sstevel@tonic-gate break; 12897c478bd9Sstevel@tonic-gate (void) memcpy(vals, POET_DATA(tagp), sizeof (vals)); 12907c478bd9Sstevel@tonic-gate return (ntohl(vals[1])); 12917c478bd9Sstevel@tonic-gate } 12927c478bd9Sstevel@tonic-gate tagp = POET_NEXT(tagp); 12937c478bd9Sstevel@tonic-gate } 12947c478bd9Sstevel@tonic-gate return (0); 12957c478bd9Sstevel@tonic-gate } 12967c478bd9Sstevel@tonic-gate 12977c478bd9Sstevel@tonic-gate /* 12987c478bd9Sstevel@tonic-gate * Server filter cases: 12997c478bd9Sstevel@tonic-gate * 13007c478bd9Sstevel@tonic-gate * No filters -- all servers generate RPADO+ event; select the 13017c478bd9Sstevel@tonic-gate * first responding server. 13027c478bd9Sstevel@tonic-gate * 13037c478bd9Sstevel@tonic-gate * Only "except" filters -- matching servers are RPADO, others 13047c478bd9Sstevel@tonic-gate * are RPADO+. 13057c478bd9Sstevel@tonic-gate * 13067c478bd9Sstevel@tonic-gate * Mix of filters -- those matching "pass" are RPADO+, those 13077c478bd9Sstevel@tonic-gate * matching "except" are RPADO, and all others are also RPADO. 13087c478bd9Sstevel@tonic-gate * 13097c478bd9Sstevel@tonic-gate * If the "only" keyword was given, then RPADO becomes -1; only RPADO+ 13107c478bd9Sstevel@tonic-gate * events occur. 13117c478bd9Sstevel@tonic-gate */ 13127c478bd9Sstevel@tonic-gate static int 1313*f53eecf5SJames Carlson use_server(poemsg_t *pado, const ppptun_atype *pap) 13147c478bd9Sstevel@tonic-gate { 13157c478bd9Sstevel@tonic-gate struct server_filter *sfp; 13167c478bd9Sstevel@tonic-gate const uchar_t *sndp; 13177c478bd9Sstevel@tonic-gate const uchar_t *macp; 13187c478bd9Sstevel@tonic-gate const uchar_t *maskp; 13197c478bd9Sstevel@tonic-gate int i; 13207c478bd9Sstevel@tonic-gate int passmatched; 1321*f53eecf5SJames Carlson int tlen; 13227c478bd9Sstevel@tonic-gate const uint8_t *tagp; 13237c478bd9Sstevel@tonic-gate int ttyp; 13247c478bd9Sstevel@tonic-gate 13257c478bd9Sstevel@tonic-gate /* 13267c478bd9Sstevel@tonic-gate * If no service mentioned in offer, then we can't use it. 13277c478bd9Sstevel@tonic-gate */ 13287c478bd9Sstevel@tonic-gate tagp = (const uint8_t *)(pado->poemsg_data + 1); 13297c478bd9Sstevel@tonic-gate ttyp = POETT_END; 13307c478bd9Sstevel@tonic-gate while (poe_tagcheck(pado->poemsg_data, pado->poemsg_len, tagp)) { 13317c478bd9Sstevel@tonic-gate ttyp = POET_GET_TYPE(tagp); 1332*f53eecf5SJames Carlson if (ttyp == POETT_END) 13337c478bd9Sstevel@tonic-gate break; 1334*f53eecf5SJames Carlson if (ttyp == POETT_SERVICE) { 1335*f53eecf5SJames Carlson /* 1336*f53eecf5SJames Carlson * If the user has requested a specific service, then 1337*f53eecf5SJames Carlson * this selection is exclusive. We never use the 1338*f53eecf5SJames Carlson * wildcard for this. 1339*f53eecf5SJames Carlson */ 1340*f53eecf5SJames Carlson tlen = POET_GET_LENG(tagp); 1341*f53eecf5SJames Carlson if (service[0] == '\0' || (strlen(service) == tlen && 1342*f53eecf5SJames Carlson memcmp(service, POET_DATA(tagp), tlen) == 0)) 1343*f53eecf5SJames Carlson break; 1344*f53eecf5SJames Carlson /* just in case we run off the end */ 1345*f53eecf5SJames Carlson ttyp = POETT_END; 1346*f53eecf5SJames Carlson } 13477c478bd9Sstevel@tonic-gate tagp = POET_NEXT(tagp); 13487c478bd9Sstevel@tonic-gate } 1349*f53eecf5SJames Carlson if (ttyp != POETT_SERVICE) { 1350*f53eecf5SJames Carlson if (verbose) 1351*f53eecf5SJames Carlson logerr("%s: Discard unusable offer from %s; service " 1352*f53eecf5SJames Carlson "'%s' not seen\n", myname, ehost(pap), service); 13537c478bd9Sstevel@tonic-gate return (-1); 1354*f53eecf5SJames Carlson } 13557c478bd9Sstevel@tonic-gate 13567c478bd9Sstevel@tonic-gate passmatched = 0; 13577c478bd9Sstevel@tonic-gate for (sfp = sfhead; sfp != NULL; sfp = sfp->sf_next) { 13587c478bd9Sstevel@tonic-gate passmatched |= !sfp->sf_isexcept; 13597c478bd9Sstevel@tonic-gate if (sfp->sf_hasmac) { 13607c478bd9Sstevel@tonic-gate sndp = pado->poemsg_sender.pta_pppoe.ptma_mac; 13617c478bd9Sstevel@tonic-gate macp = sfp->sf_mac.ether_addr_octet; 13627c478bd9Sstevel@tonic-gate maskp = sfp->sf_mask.ether_addr_octet; 13637c478bd9Sstevel@tonic-gate i = sizeof (pado->poemsg_sender.pta_pppoe.ptma_mac); 13647c478bd9Sstevel@tonic-gate for (; i > 0; i--) 13657c478bd9Sstevel@tonic-gate if (((*macp++ ^ *sndp++) & *maskp++) != 0) 13667c478bd9Sstevel@tonic-gate break; 13677c478bd9Sstevel@tonic-gate if (i <= 0) 13687c478bd9Sstevel@tonic-gate break; 13697c478bd9Sstevel@tonic-gate } 13707c478bd9Sstevel@tonic-gate } 13717c478bd9Sstevel@tonic-gate 13727c478bd9Sstevel@tonic-gate if (sfp == NULL) { 13737c478bd9Sstevel@tonic-gate /* 13747c478bd9Sstevel@tonic-gate * No match encountered; if only exclude rules have 13757c478bd9Sstevel@tonic-gate * been seen, then accept this offer. 13767c478bd9Sstevel@tonic-gate */ 13777c478bd9Sstevel@tonic-gate if (!passmatched) 13787c478bd9Sstevel@tonic-gate return (PCSME_RPADOP); 13797c478bd9Sstevel@tonic-gate } else { 13807c478bd9Sstevel@tonic-gate if (!sfp->sf_isexcept) 13817c478bd9Sstevel@tonic-gate return (PCSME_RPADOP); 13827c478bd9Sstevel@tonic-gate } 1383*f53eecf5SJames Carlson if (onlyflag) { 1384*f53eecf5SJames Carlson if (verbose) 1385*f53eecf5SJames Carlson logerr("%s: Discard unusable offer from %s; server not " 1386*f53eecf5SJames Carlson "matched\n", myname, ehost(pap)); 13877c478bd9Sstevel@tonic-gate return (-1); 1388*f53eecf5SJames Carlson } 13897c478bd9Sstevel@tonic-gate return (PCSME_RPADO); 13907c478bd9Sstevel@tonic-gate } 13917c478bd9Sstevel@tonic-gate 13927c478bd9Sstevel@tonic-gate /* 13937c478bd9Sstevel@tonic-gate * This is the normal event loop. It initializes the state machine 13947c478bd9Sstevel@tonic-gate * and sends in an Open event to kick things off. Then it drops into 13957c478bd9Sstevel@tonic-gate * a loop to dispatch events for the state machine. 13967c478bd9Sstevel@tonic-gate */ 13977c478bd9Sstevel@tonic-gate static void 13987c478bd9Sstevel@tonic-gate find_server(int localid) 13997c478bd9Sstevel@tonic-gate { 14007c478bd9Sstevel@tonic-gate poesm_t psm; 14017c478bd9Sstevel@tonic-gate struct pollfd pfd[1]; 14027c478bd9Sstevel@tonic-gate struct timeval tv, tvnow; 14037c478bd9Sstevel@tonic-gate int retv; 14047c478bd9Sstevel@tonic-gate poemsg_t pmsg; 14057c478bd9Sstevel@tonic-gate struct strbuf ctrl; 14067c478bd9Sstevel@tonic-gate struct strbuf data; 14077c478bd9Sstevel@tonic-gate poep_t *poep; 14087c478bd9Sstevel@tonic-gate int flags; 14097c478bd9Sstevel@tonic-gate uint32_t seqval; 14107c478bd9Sstevel@tonic-gate struct ppptun_control *ptc; 14117c478bd9Sstevel@tonic-gate 14127c478bd9Sstevel@tonic-gate (void) memset(&psm, '\0', sizeof (psm)); 14137c478bd9Sstevel@tonic-gate 14147c478bd9Sstevel@tonic-gate /* 14157c478bd9Sstevel@tonic-gate * Initialize the sequence number with something handy. It 14167c478bd9Sstevel@tonic-gate * doesn't need to be absolutely unique, since the localid 14177c478bd9Sstevel@tonic-gate * value actually demultiplexes everything. This just makes 14187c478bd9Sstevel@tonic-gate * the operation a little safer. 14197c478bd9Sstevel@tonic-gate */ 14207c478bd9Sstevel@tonic-gate psm.poesm_sequence = getpid() << 16; 14217c478bd9Sstevel@tonic-gate psm.poesm_localid = localid; 14227c478bd9Sstevel@tonic-gate 14237c478bd9Sstevel@tonic-gate /* Start the state machine */ 14247c478bd9Sstevel@tonic-gate handle_event(&psm, PCSME_OPEN, NULL); 14257c478bd9Sstevel@tonic-gate 14267c478bd9Sstevel@tonic-gate /* Enter event polling loop. */ 14277c478bd9Sstevel@tonic-gate pfd[0].fd = tunfd; 14287c478bd9Sstevel@tonic-gate pfd[0].events = POLLIN; 14297c478bd9Sstevel@tonic-gate for (;;) { 14307c478bd9Sstevel@tonic-gate /* Wait for timeout or message */ 14317c478bd9Sstevel@tonic-gate retv = poll(pfd, 1, psm.poesm_timer > 0 ? psm.poesm_timer : 14327c478bd9Sstevel@tonic-gate INFTIM); 14337c478bd9Sstevel@tonic-gate if (retv < 0) { 14347c478bd9Sstevel@tonic-gate logstrerror("poll"); 14357c478bd9Sstevel@tonic-gate break; 14367c478bd9Sstevel@tonic-gate } 14377c478bd9Sstevel@tonic-gate 14387c478bd9Sstevel@tonic-gate /* Handle a timeout */ 14397c478bd9Sstevel@tonic-gate if (retv == 0) { 14407c478bd9Sstevel@tonic-gate psm.poesm_timer = 0; 14417c478bd9Sstevel@tonic-gate handle_event(&psm, --psm.poesm_count > 0 ? PCSME_TOP : 14427c478bd9Sstevel@tonic-gate PCSME_TOM, NULL); 14437c478bd9Sstevel@tonic-gate continue; 14447c478bd9Sstevel@tonic-gate } 14457c478bd9Sstevel@tonic-gate 14467c478bd9Sstevel@tonic-gate /* Adjust the timer for the time we slept. */ 14477c478bd9Sstevel@tonic-gate if (psm.poesm_timer > 0) { 14487c478bd9Sstevel@tonic-gate (void) gettimeofday(&tvnow, NULL); 14497c478bd9Sstevel@tonic-gate tv = tvnow; 14507c478bd9Sstevel@tonic-gate if ((tv.tv_sec -= tvstart.tv_sec) < 0) { 14517c478bd9Sstevel@tonic-gate /* Darn */ 14527c478bd9Sstevel@tonic-gate tv.tv_sec = 1; 14537c478bd9Sstevel@tonic-gate tv.tv_usec = 0; 14547c478bd9Sstevel@tonic-gate } else if ((tv.tv_usec -= tvstart.tv_usec) < 0) { 14557c478bd9Sstevel@tonic-gate tv.tv_usec += 1000000; 14567c478bd9Sstevel@tonic-gate if (--tv.tv_sec < 0) 14577c478bd9Sstevel@tonic-gate tv.tv_sec = 0; 14587c478bd9Sstevel@tonic-gate } 14597c478bd9Sstevel@tonic-gate psm.poesm_timer -= tv.tv_sec*1000 + tv.tv_usec/1000; 14607c478bd9Sstevel@tonic-gate tvstart = tvnow; 14617c478bd9Sstevel@tonic-gate } 14627c478bd9Sstevel@tonic-gate 14637c478bd9Sstevel@tonic-gate /* Read in the message from the server. */ 14647c478bd9Sstevel@tonic-gate ctrl.maxlen = PKT_OCTL_LEN; 14657c478bd9Sstevel@tonic-gate ctrl.buf = (caddr_t)pkt_octl; 14667c478bd9Sstevel@tonic-gate data.maxlen = PKT_INPUT_LEN; 14677c478bd9Sstevel@tonic-gate data.buf = (caddr_t)pkt_input; 14687c478bd9Sstevel@tonic-gate flags = 0; 14697c478bd9Sstevel@tonic-gate 14707c478bd9Sstevel@tonic-gate if (pppoec_getmsg(tunfd, &ctrl, &data, &flags) < 0) 14717c478bd9Sstevel@tonic-gate break; 14727c478bd9Sstevel@tonic-gate 14737c478bd9Sstevel@tonic-gate if (ctrl.len != sizeof (*ptc)) { 14747c478bd9Sstevel@tonic-gate if (verbose) 14757c478bd9Sstevel@tonic-gate logerr("%s: discard: ctrl len %d\n", myname, 14767c478bd9Sstevel@tonic-gate ctrl.len); 14777c478bd9Sstevel@tonic-gate continue; 14787c478bd9Sstevel@tonic-gate } 14797c478bd9Sstevel@tonic-gate poep = (poep_t *)pkt_input; 14807c478bd9Sstevel@tonic-gate (void) memset(&pmsg, '\0', sizeof (pmsg)); 14817c478bd9Sstevel@tonic-gate pmsg.poemsg_next = NULL; 14827c478bd9Sstevel@tonic-gate pmsg.poemsg_data = poep; 14837c478bd9Sstevel@tonic-gate pmsg.poemsg_len = data.len; 14847c478bd9Sstevel@tonic-gate ptc = (struct ppptun_control *)pkt_octl; 14857c478bd9Sstevel@tonic-gate if (ptc->ptc_action != PTCA_CONTROL) { 14867c478bd9Sstevel@tonic-gate if (verbose) 14877c478bd9Sstevel@tonic-gate logerr("%s: discard: unexpected action %d\n", 14887c478bd9Sstevel@tonic-gate myname, ptc->ptc_action); 14897c478bd9Sstevel@tonic-gate continue; 14907c478bd9Sstevel@tonic-gate } 14917c478bd9Sstevel@tonic-gate pmsg.poemsg_iname = ptc->ptc_name; 14927c478bd9Sstevel@tonic-gate if (verbose) 14937c478bd9Sstevel@tonic-gate logerr("%s: Received %s from %s/%s\n", 14947c478bd9Sstevel@tonic-gate myname, poe_codename(poep->poep_code), 14957c478bd9Sstevel@tonic-gate ehost(&ptc->ptc_address), pmsg.poemsg_iname); 14967c478bd9Sstevel@tonic-gate pmsg.poemsg_sender = ptc->ptc_address; 14977c478bd9Sstevel@tonic-gate 14987c478bd9Sstevel@tonic-gate /* Check for messages from unexpected peers. */ 14997c478bd9Sstevel@tonic-gate if ((poep->poep_code == POECODE_PADT || 15007c478bd9Sstevel@tonic-gate poep->poep_code == POECODE_PADS) && 15017c478bd9Sstevel@tonic-gate (psm.poesm_firstoff == NULL || 15027c478bd9Sstevel@tonic-gate memcmp(&psm.poesm_firstoff->poemsg_sender, 1503*f53eecf5SJames Carlson &pmsg.poemsg_sender, sizeof (pmsg.poemsg_sender)) != 0)) { 15047c478bd9Sstevel@tonic-gate if (verbose) { 15057c478bd9Sstevel@tonic-gate logerr("%s: Unexpected peer %s", myname, 15067c478bd9Sstevel@tonic-gate ehost(&ptc->ptc_address)); 15077c478bd9Sstevel@tonic-gate logerr(" != %s\n", 15087c478bd9Sstevel@tonic-gate ehost(&psm.poesm_firstoff->poemsg_sender)); 15097c478bd9Sstevel@tonic-gate } 15107c478bd9Sstevel@tonic-gate continue; 15117c478bd9Sstevel@tonic-gate } 15127c478bd9Sstevel@tonic-gate 15137c478bd9Sstevel@tonic-gate /* Eliminate stale PADS responses. */ 15147c478bd9Sstevel@tonic-gate if (poep->poep_code == POECODE_PADS) { 15157c478bd9Sstevel@tonic-gate seqval = get_sequence(&pmsg); 15167c478bd9Sstevel@tonic-gate if (seqval != psm.poesm_sequence) { 15177c478bd9Sstevel@tonic-gate if (verbose) { 15187c478bd9Sstevel@tonic-gate if (seqval == 0) 15197c478bd9Sstevel@tonic-gate logerr( 15207c478bd9Sstevel@tonic-gate "%s: PADS has no sequence " 15217c478bd9Sstevel@tonic-gate "number.\n", myname); 15227c478bd9Sstevel@tonic-gate else 15237c478bd9Sstevel@tonic-gate logerr( 15247c478bd9Sstevel@tonic-gate "%s: PADS has sequence " 15257c478bd9Sstevel@tonic-gate "%08X instead of %08X.\n", 15267c478bd9Sstevel@tonic-gate myname, seqval, 15277c478bd9Sstevel@tonic-gate psm.poesm_sequence); 15287c478bd9Sstevel@tonic-gate } 15297c478bd9Sstevel@tonic-gate continue; 15307c478bd9Sstevel@tonic-gate } 15317c478bd9Sstevel@tonic-gate } 15327c478bd9Sstevel@tonic-gate 15337c478bd9Sstevel@tonic-gate /* Dispatch message event. */ 15347c478bd9Sstevel@tonic-gate retv = error_check(&pmsg); 15357c478bd9Sstevel@tonic-gate switch (poep->poep_code) { 15367c478bd9Sstevel@tonic-gate case POECODE_PADT: 15377c478bd9Sstevel@tonic-gate handle_event(&psm, PCSME_RPADT, &pmsg); 15387c478bd9Sstevel@tonic-gate break; 15397c478bd9Sstevel@tonic-gate case POECODE_PADS: 15407c478bd9Sstevel@tonic-gate /* 15417c478bd9Sstevel@tonic-gate * Got a PPPoE Active Discovery Session- 15427c478bd9Sstevel@tonic-gate * confirmation message. It's a PADS event if 15437c478bd9Sstevel@tonic-gate * everything's in order. It's a PADS- event 15447c478bd9Sstevel@tonic-gate * if the message is merely reporting an 15457c478bd9Sstevel@tonic-gate * error. 15467c478bd9Sstevel@tonic-gate */ 15477c478bd9Sstevel@tonic-gate handle_event(&psm, retv != 0 ? PCSME_RPADSN : 15487c478bd9Sstevel@tonic-gate PCSME_RPADS, &pmsg); 15497c478bd9Sstevel@tonic-gate break; 15507c478bd9Sstevel@tonic-gate case POECODE_PADO: 15517c478bd9Sstevel@tonic-gate /* Ignore offers that merely report errors. */ 15527c478bd9Sstevel@tonic-gate if (retv != 0) 15537c478bd9Sstevel@tonic-gate break; 15547c478bd9Sstevel@tonic-gate /* Ignore offers from servers we don't want. */ 1555*f53eecf5SJames Carlson if ((retv = use_server(&pmsg, &ptc->ptc_address)) < 0) 15567c478bd9Sstevel@tonic-gate break; 15577c478bd9Sstevel@tonic-gate /* Dispatch either RPADO or RAPDO+ event. */ 15587c478bd9Sstevel@tonic-gate handle_event(&psm, retv, &pmsg); 15597c478bd9Sstevel@tonic-gate break; 15607c478bd9Sstevel@tonic-gate 15617c478bd9Sstevel@tonic-gate default: 15627c478bd9Sstevel@tonic-gate if (verbose) 15637c478bd9Sstevel@tonic-gate logerr("%s: Unexpected code %s (%d)\n", myname, 15647c478bd9Sstevel@tonic-gate poe_codename(poep->poep_code), 15657c478bd9Sstevel@tonic-gate poep->poep_code); 15667c478bd9Sstevel@tonic-gate break; 15677c478bd9Sstevel@tonic-gate } 15687c478bd9Sstevel@tonic-gate } 15697c478bd9Sstevel@tonic-gate exit(1); 15707c478bd9Sstevel@tonic-gate } 15717c478bd9Sstevel@tonic-gate 15727c478bd9Sstevel@tonic-gate static void 15737c478bd9Sstevel@tonic-gate usage(void) 15747c478bd9Sstevel@tonic-gate { 15757c478bd9Sstevel@tonic-gate logerr("Usage:\n" 15767c478bd9Sstevel@tonic-gate "\t%s [-os#] [-v] <dev> [<service> [<server> [only]]]\n\n" 15777c478bd9Sstevel@tonic-gate " or\n\n" 15787c478bd9Sstevel@tonic-gate "\t%s [-o#] [-v] -i <dev>\n", myname, myname); 15797c478bd9Sstevel@tonic-gate exit(1); 15807c478bd9Sstevel@tonic-gate } 15817c478bd9Sstevel@tonic-gate 15827c478bd9Sstevel@tonic-gate /* 15837c478bd9Sstevel@tonic-gate * In addition to the usual 0-2 file descriptors, pppd will leave fd 3 15847c478bd9Sstevel@tonic-gate * open on a pipe to receive the environment variables. See 15857c478bd9Sstevel@tonic-gate * pppoe_device_pipe() in pppd/plugins/pppoe.c and device_pipe_hook in 15867c478bd9Sstevel@tonic-gate * pppd/main.c. 15877c478bd9Sstevel@tonic-gate */ 15887c478bd9Sstevel@tonic-gate int 15897c478bd9Sstevel@tonic-gate main(int argc, char **argv) 15907c478bd9Sstevel@tonic-gate { 15917c478bd9Sstevel@tonic-gate int inquiry_mode, exceptflag, arg, localid; 15927c478bd9Sstevel@tonic-gate char *cp; 15937c478bd9Sstevel@tonic-gate 15947c478bd9Sstevel@tonic-gate log_to_stderr(LOGLVL_DBG); 15957c478bd9Sstevel@tonic-gate 15967c478bd9Sstevel@tonic-gate if ((myname = *argv) == NULL) 15977c478bd9Sstevel@tonic-gate myname = "pppoec"; 15987c478bd9Sstevel@tonic-gate 15997c478bd9Sstevel@tonic-gate inquiry_mode = 0; 16007c478bd9Sstevel@tonic-gate while ((arg = getopt(argc, argv, "io:s:v")) != EOF) 16017c478bd9Sstevel@tonic-gate switch (arg) { 16027c478bd9Sstevel@tonic-gate case 'i': 16037c478bd9Sstevel@tonic-gate inquiry_mode++; 16047c478bd9Sstevel@tonic-gate break; 16057c478bd9Sstevel@tonic-gate case 'v': 16067c478bd9Sstevel@tonic-gate verbose++; 16077c478bd9Sstevel@tonic-gate break; 16087c478bd9Sstevel@tonic-gate case 'o': 16097c478bd9Sstevel@tonic-gate pado_wait_time = strtol(optarg, &cp, 0); 16107c478bd9Sstevel@tonic-gate if (pado_wait_time <= 0 || *cp != '\0' || 16117c478bd9Sstevel@tonic-gate cp == optarg) { 16127c478bd9Sstevel@tonic-gate logerr("%s: illegal PADO wait time: %s\n", 16137c478bd9Sstevel@tonic-gate myname, optarg); 16147c478bd9Sstevel@tonic-gate exit(1); 16157c478bd9Sstevel@tonic-gate } 16167c478bd9Sstevel@tonic-gate break; 16177c478bd9Sstevel@tonic-gate case 's': 16187c478bd9Sstevel@tonic-gate pads_wait_time = strtol(optarg, &cp, 0); 16197c478bd9Sstevel@tonic-gate if (pads_wait_time <= 0 || *cp != '\0' || 16207c478bd9Sstevel@tonic-gate cp == optarg) { 16217c478bd9Sstevel@tonic-gate logerr("%s: illegal PADS wait time: %s\n", 16227c478bd9Sstevel@tonic-gate myname, optarg); 16237c478bd9Sstevel@tonic-gate exit(1); 16247c478bd9Sstevel@tonic-gate } 16257c478bd9Sstevel@tonic-gate break; 16267c478bd9Sstevel@tonic-gate case '?': 16277c478bd9Sstevel@tonic-gate usage(); 16287c478bd9Sstevel@tonic-gate } 16297c478bd9Sstevel@tonic-gate 16307c478bd9Sstevel@tonic-gate /* Handle inquiry mode. */ 16317c478bd9Sstevel@tonic-gate if (inquiry_mode) { 16327c478bd9Sstevel@tonic-gate if (optind != argc-1) 16337c478bd9Sstevel@tonic-gate usage(); 16347c478bd9Sstevel@tonic-gate if (pado_wait_time == 0) 16357c478bd9Sstevel@tonic-gate pado_wait_time = PADI_INQUIRY_DWELL; 16367c478bd9Sstevel@tonic-gate 16377c478bd9Sstevel@tonic-gate /* Invoked by user; open the tunnel driver myself. */ 16387c478bd9Sstevel@tonic-gate tunfd = open(tunnam, O_RDWR | O_NOCTTY); 16397c478bd9Sstevel@tonic-gate if (tunfd == -1) { 16407c478bd9Sstevel@tonic-gate logstrerror(tunnam); 16417c478bd9Sstevel@tonic-gate exit(1); 16427c478bd9Sstevel@tonic-gate } 16437c478bd9Sstevel@tonic-gate 16447c478bd9Sstevel@tonic-gate /* 16457c478bd9Sstevel@tonic-gate * Set up the control stream for PPPoE negotiation 16467c478bd9Sstevel@tonic-gate * (set_control), then broadcast a query for all servers 16477c478bd9Sstevel@tonic-gate * and listen for replies (find_all_servers). 16487c478bd9Sstevel@tonic-gate */ 16497c478bd9Sstevel@tonic-gate find_all_servers(set_control(argv[optind])); 16507c478bd9Sstevel@tonic-gate return (0); 16517c478bd9Sstevel@tonic-gate } 16527c478bd9Sstevel@tonic-gate 16537c478bd9Sstevel@tonic-gate if (pado_wait_time == 0) 16547c478bd9Sstevel@tonic-gate pado_wait_time = PADI_RESTART_TIME; 16557c478bd9Sstevel@tonic-gate 16567c478bd9Sstevel@tonic-gate if (optind >= argc) 16577c478bd9Sstevel@tonic-gate usage(); 16587c478bd9Sstevel@tonic-gate 16597c478bd9Sstevel@tonic-gate /* Make sure we've got a usable tunnel driver on stdin. */ 16607c478bd9Sstevel@tonic-gate check_stdin(); 16617c478bd9Sstevel@tonic-gate 16627c478bd9Sstevel@tonic-gate /* Set up the control stream for PPPoE negotiation. */ 16637c478bd9Sstevel@tonic-gate localid = set_control(argv[optind++]); 16647c478bd9Sstevel@tonic-gate 16657c478bd9Sstevel@tonic-gate /* Pick the service, if any. */ 16667c478bd9Sstevel@tonic-gate if (optind < argc) 16677c478bd9Sstevel@tonic-gate service = argv[optind++]; 16687c478bd9Sstevel@tonic-gate 16697c478bd9Sstevel@tonic-gate /* Parse out the filters. */ 16707c478bd9Sstevel@tonic-gate if (optind < argc) { 16717c478bd9Sstevel@tonic-gate if (strcasecmp(argv[argc - 1], "only") == 0) { 16727c478bd9Sstevel@tonic-gate argc--; 16737c478bd9Sstevel@tonic-gate onlyflag = 1; 16747c478bd9Sstevel@tonic-gate } 16757c478bd9Sstevel@tonic-gate exceptflag = 0; 16767c478bd9Sstevel@tonic-gate for (; optind < argc; optind++) { 16777c478bd9Sstevel@tonic-gate if (!exceptflag && 16787c478bd9Sstevel@tonic-gate strcasecmp(argv[optind], "except") == 0) { 16797c478bd9Sstevel@tonic-gate exceptflag = 1; 16807c478bd9Sstevel@tonic-gate } else { 16817c478bd9Sstevel@tonic-gate parse_filter(argv[optind], exceptflag); 16827c478bd9Sstevel@tonic-gate exceptflag = 0; 16837c478bd9Sstevel@tonic-gate } 16847c478bd9Sstevel@tonic-gate } 16857c478bd9Sstevel@tonic-gate } 16867c478bd9Sstevel@tonic-gate 16877c478bd9Sstevel@tonic-gate /* Enter the main loop. */ 16887c478bd9Sstevel@tonic-gate find_server(localid); 16897c478bd9Sstevel@tonic-gate 16907c478bd9Sstevel@tonic-gate return (0); 16917c478bd9Sstevel@tonic-gate } 1692