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 *
poe_event(int event)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 *
poe_state(int state)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 *
poe_action(int act)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
pppoec_getmsg(int fd,struct strbuf * ctrl,struct strbuf * data,int * flags)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
set_control(const char * dname)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
check_stdin(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
display_pppoe(FILE * out,const poep_t * poep,int plen,const ppptun_atype * pap)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
send_pppoe(const poep_t * poep,const char * msgname,const ppptun_atype * destaddr)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
send_padi(int localid)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
alarm_hand(int dummy)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
find_all_servers(int localid)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
parse_filter(const char * str,int exceptflag)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 *
save_message(const poemsg_t * pmsg)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 +
802*f53eecf5SJames Carlson 	    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
send_padr(poesm_t * psm,const poemsg_t * pado)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) &&
868*f53eecf5SJames Carlson 			    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
act_none(poesm_t * psm,poemsg_t * pmsg,int event,int nextst)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
act_fail(poesm_t * psm,poemsg_t * pmsg,int event,int nextst)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
act_spadi(poesm_t * psm,poemsg_t * pmsg,int event,int nextst)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
act_add(poesm_t * psm,poemsg_t * pmsg,int event,int nextst)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
act_spadr(poesm_t * psm,poemsg_t * pmsg,int event,int nextst)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
act_spadrp(poesm_t * psm,poemsg_t * pmsg,int event,int nextst)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
act_spadrn(poesm_t * psm,poemsg_t * pmsg,int event,int nextst)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
remove_eol(char * str,size_t len)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
act_open(poesm_t * psm,poemsg_t * pmsg,int event,int nextst)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
handle_event(poesm_t * psm,int event,poemsg_t * pmsg)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
error_check(poemsg_t * pmsg)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
get_sequence(const poemsg_t * pmsg)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
use_server(poemsg_t * pado,const ppptun_atype * pap)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
find_server(int localid)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 ||
1502*f53eecf5SJames Carlson 		    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
usage(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
main(int argc,char ** argv)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