Home | History | Annotate | Download | only in pppoe
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License, Version 1.0 only
      6  * (the "License").  You may not use this file except in compliance
      7  * with the License.
      8  *
      9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
     10  * or http://www.opensolaris.org/os/licensing.
     11  * See the License for the specific language governing permissions
     12  * and limitations under the License.
     13  *
     14  * When distributing Covered Code, include this CDDL HEADER in each
     15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     16  * If applicable, add the following below this CDDL HEADER, with the
     17  * fields enclosed by brackets "[]" replaced with your own identifying
     18  * information: Portions Copyright [yyyy] [name of copyright owner]
     19  *
     20  * CDDL HEADER END
     21  */
     22 /*
     23  * PPPoE Client-mode "chat" utility for use with Solaris PPP 4.0.
     24  *
     25  * Copyright 2000-2002 Sun Microsystems, Inc.  All rights reserved.
     26  * Use is subject to license terms.
     27  */
     28 
     29 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     30 
     31 #include <stdio.h>
     32 #include <stdlib.h>
     33 #include <unistd.h>
     34 #include <ctype.h>
     35 #include <strings.h>
     36 #include <fcntl.h>
     37 #include <errno.h>
     38 #include <signal.h>
     39 #include <stropts.h>
     40 #include <netdb.h>
     41 #include <sys/types.h>
     42 #include <sys/socket.h>
     43 #include <net/if.h>
     44 #include <netinet/in.h>
     45 #include <netinet/if_ether.h>
     46 
     47 #include <net/sppptun.h>
     48 #include <net/pppoe.h>
     49 
     50 #include "common.h"
     51 #include "logging.h"
     52 
     53 /*
     54  * This value, currently set to the characters "POE1," is used to
     55  * distinguish among control messages from multiple lower streams
     56  * under /dev/sppp.  This feature is needed to support PPP translation
     57  * (LAC-like behavior), but isn't currently used.
     58  */
     59 #define	PPPOE_DISCRIM	0x504F4531
     60 
     61 /* milliseconds between retries */
     62 #define	PADI_RESTART_TIME	500
     63 #define	PADR_RESTART_TIME	2000
     64 
     65 /* default inquiry mode timer in milliseconds. */
     66 #define	PADI_INQUIRY_DWELL	3000
     67 
     68 /* maximum timer value in milliseconds */
     69 #define	RESTART_LIMIT	5000
     70 
     71 char *myname;		/* copy of argv[0] for error messages */
     72 static int verbose;	/* -v flag given */
     73 static int onlyflag;	/* keyword "only" at end of command line */
     74 static char *service = "";	/* saved service name from command line */
     75 
     76 static int pado_wait_time = 0;	/* see main() */
     77 static int pads_wait_time = PADR_RESTART_TIME;
     78 
     79 static int tunfd;	/* open connection to sppptun driver */
     80 
     81 static struct timeval tvstart;	/* time of last PADI/PADR transmission */
     82 
     83 struct server_filter {
     84 	struct server_filter *sf_next;	/* Next filter in list */
     85 	struct ether_addr sf_mac;	/* Ethernet address */
     86 	struct ether_addr sf_mask;	/* Mask (0 or 0xFF in each byte) */
     87 	const char *sf_name;		/* String for AC-Name compare */
     88 	boolean_t sf_hasmac;		/* Set if string could be MAC */
     89 	boolean_t sf_isexcept;		/* Ignore server if matching */
     90 };
     91 
     92 /* List of filters defined on command line. */
     93 static struct server_filter *sfhead, *sftail;
     94 
     95 /*
     96  * PPPoE Client State Machine
     97  */
     98 
     99 /* Client events */
    100 #define	PCSME_CLOSE	0	/* User close */
    101 #define	PCSME_OPEN	1	/* User open */
    102 #define	PCSME_TOP	2	/* Timeout+ (counter non-zero) */
    103 #define	PCSME_TOM	3	/* Timeout- (counter zero) */
    104 #define	PCSME_RPADT	4	/* Receive PADT (unexpected here) */
    105 #define	PCSME_RPADOP	5	/* Receive desired PADO */
    106 #define	PCSME_RPADO	6	/* Receive ordinary PADO */
    107 #define	PCSME_RPADS	7	/* Receive PADS */
    108 #define	PCSME_RPADSN	8	/* Receive bad (errored) PADS */
    109 #define	PCSME__MAX	9
    110 
    111 /* Client states */
    112 #define	PCSMS_DEAD	0	/* Initial state */
    113 #define	PCSMS_INITSENT	1	/* PADI sent */
    114 #define	PCSMS_OFFRRCVD	2	/* PADO received */
    115 #define	PCSMS_REQSENT	3	/* PADR sent */
    116 #define	PCSMS_CONVERS	4	/* Conversational */
    117 #define	PCSMS__MAX	5
    118 
    119 /* Client actions */
    120 #define	PCSMA_NONE	0	/* Do nothing */
    121 #define	PCSMA_FAIL	1	/* Unrecoverable error */
    122 #define	PCSMA_SPADI	2	/* Send PADI */
    123 #define	PCSMA_ADD	3	/* Add ordinary server to list */
    124 #define	PCSMA_SPADR	4	/* Send PADR to top server */
    125 #define	PCSMA_SPADRP	5	/* Send PADR to this server (make top) */
    126 #define	PCSMA_SPADRN	6	/* Send PADR to next (or terminate) */
    127 #define	PCSMA_OPEN	7	/* Start PPP */
    128 #define	PCSMA__MAX	8
    129 
    130 static uint8_t client_next_state[PCSMS__MAX][PCSME__MAX] = {
    131 /* 0 PCSMS_DEAD Initial state */
    132 	{
    133 		PCSMS_DEAD,	/* PCSME_CLOSE  User close */
    134 		PCSMS_INITSENT,	/* PCSME_OPEN   User open */
    135 		PCSMS_DEAD,	/* PCSME_TOP    Timeout+ */
    136 		PCSMS_DEAD,	/* PCSME_TOM    Timeout- */
    137 		PCSMS_DEAD,	/* PCSME_RPADT  Receive PADT */
    138 		PCSMS_DEAD,	/* PCSME_RPADOP Receive desired PADO */
    139 		PCSMS_DEAD,	/* PCSME_RPADO  Receive ordinary PADO */
    140 		PCSMS_DEAD,	/* PCSME_RPADS  Receive PADS */
    141 		PCSMS_DEAD,	/* PCSME_RPADSN Receive bad PADS */
    142 	},
    143 /* 1 PCSMS_INITSENT PADI sent */
    144 	{
    145 		PCSMS_DEAD,	/* PCSME_CLOSE  User close */
    146 		PCSMS_INITSENT,	/* PCSME_OPEN   User open */
    147 		PCSMS_INITSENT,	/* PCSME_TOP    Timeout+ */
    148 		PCSMS_DEAD,	/* PCSME_TOM    Timeout- */
    149 		PCSMS_DEAD,	/* PCSME_RPADT  Receive PADT */
    150 		PCSMS_REQSENT,	/* PCSME_RPADOP Receive desired PADO */
    151 		PCSMS_OFFRRCVD,	/* PCSME_RPADO  Receive ordinary PADO */
    152 		PCSMS_INITSENT,	/* PCSME_RPADS  Receive PADS */
    153 		PCSMS_INITSENT,	/* PCSME_RPADSN Receive bad PADS */
    154 	},
    155 /* 2 PCSMS_OFFRRCVD PADO received */
    156 	{
    157 		PCSMS_DEAD,	/* PCSME_CLOSE  User close */
    158 		PCSMS_INITSENT,	/* PCSME_OPEN   User open */
    159 		PCSMS_REQSENT,	/* PCSME_TOP    Timeout+ */
    160 		PCSMS_REQSENT,	/* PCSME_TOM    Timeout- */
    161 		PCSMS_DEAD,	/* PCSME_RPADT  Receive PADT */
    162 		PCSMS_REQSENT,	/* PCSME_RPADOP Receive desired PADO */
    163 		PCSMS_OFFRRCVD,	/* PCSME_RPADO  Receive ordinary PADO */
    164 		PCSMS_OFFRRCVD,	/* PCSME_RPADS  Receive PADS */
    165 		PCSMS_OFFRRCVD,	/* PCSME_RPADSN Receive bad PADS */
    166 	},
    167 /* 3 PCSMS_REQSENT  PADR sent */
    168 	{
    169 		PCSMS_DEAD,	/* PCSME_CLOSE  User close */
    170 		PCSMS_INITSENT,	/* PCSME_OPEN   User open */
    171 		PCSMS_REQSENT,	/* PCSME_TOP    Timeout+ */
    172 		PCSMS_REQSENT,	/* PCSME_TOM    Timeout- */
    173 		PCSMS_DEAD,	/* PCSME_RPADT  Receive PADT */
    174 		PCSMS_REQSENT,	/* PCSME_RPADOP Receive desired PADO */
    175 		PCSMS_REQSENT,	/* PCSME_RPADO  Receive ordinary PADO */
    176 		PCSMS_CONVERS,	/* PCSME_RPADS  Receive PADS */
    177 		PCSMS_REQSENT,	/* PCSME_RPADSN Receive bad PADS */
    178 	},
    179 /* 4 PCSMS_CONVERS  Conversational */
    180 	{
    181 		PCSMS_DEAD,	/* PCSME_CLOSE  User close */
    182 		PCSMS_INITSENT,	/* PCSME_OPEN   User open */
    183 		PCSMS_CONVERS,	/* PCSME_TOP    Timeout+ */
    184 		PCSMS_CONVERS,	/* PCSME_TOM    Timeout- */
    185 		PCSMS_DEAD,	/* PCSME_RPADT  Receive PADT */
    186 		PCSMS_CONVERS,	/* PCSME_RPADOP Receive desired PADO */
    187 		PCSMS_CONVERS,	/* PCSME_RPADO  Receive ordinary PADO */
    188 		PCSMS_CONVERS,	/* PCSME_RPADS  Receive PADS */
    189 		PCSMS_CONVERS,	/* PCSME_RPADSN Receive bad PADS */
    190 	},
    191 };
    192 
    193 static uint8_t client_action[PCSMS__MAX][PCSME__MAX] = {
    194 /* 0 PCSMS_DEAD Initial state */
    195 	{
    196 		PCSMA_NONE,	/* PCSME_CLOSE  User close */
    197 		PCSMA_SPADI,	/* PCSME_OPEN   User open */
    198 		PCSMA_NONE,	/* PCSME_TOP    Timeout+ */
    199 		PCSMA_NONE,	/* PCSME_TOM    Timeout- */
    200 		PCSMA_NONE,	/* PCSME_RPADT  Receive PADT */
    201 		PCSMA_NONE,	/* PCSME_RPADOP Receive desired PADO */
    202 		PCSMA_NONE,	/* PCSME_RPADO  Receive ordinary PADO */
    203 		PCSMA_NONE,	/* PCSME_RPADS  Receive PADS */
    204 		PCSMA_NONE,	/* PCSME_RPADSN Receive bad PADS */
    205 	},
    206 /* 1 PCSMS_INITSENT PADI sent */
    207 	{
    208 		PCSMA_FAIL,	/* PCSME_CLOSE  User close */
    209 		PCSMA_SPADI,	/* PCSME_OPEN   User open */
    210 		PCSMA_SPADI,	/* PCSME_TOP    Timeout+ */
    211 		PCSMA_FAIL,	/* PCSME_TOM    Timeout- */
    212 		PCSMA_FAIL,	/* PCSME_RPADT  Receive PADT */
    213 		PCSMA_SPADRP,	/* PCSME_RPADOP Receive desired PADO */
    214 		PCSMA_ADD,	/* PCSME_RPADO  Receive ordinary PADO */
    215 		PCSMA_NONE,	/* PCSME_RPADS  Receive PADS */
    216 		PCSMA_NONE,	/* PCSME_RPADSN Receive bad PADS */
    217 	},
    218 /* 2 PCSMS_OFFRRCVD PADO received */
    219 	{
    220 		PCSMA_FAIL,	/* PCSME_CLOSE  User close */
    221 		PCSMA_SPADI,	/* PCSME_OPEN   User open */
    222 		PCSMA_SPADR,	/* PCSME_TOP    Timeout+ */
    223 		PCSMA_SPADR,	/* PCSME_TOM    Timeout- */
    224 		PCSMA_FAIL,	/* PCSME_RPADT  Receive PADT */
    225 		PCSMA_SPADRP,	/* PCSME_RPADOP Receive desired PADO */
    226 		PCSMA_ADD,	/* PCSME_RPADO  Receive ordinary PADO */
    227 		PCSMA_NONE,	/* PCSME_RPADS  Receive PADS */
    228 		PCSMA_NONE,	/* PCSME_RPADSN Receive bad PADS */
    229 	},
    230 /* 3 PCSMS_REQSENT  PADR sent */
    231 	{
    232 		PCSMA_FAIL,	/* PCSME_CLOSE  User close */
    233 		PCSMA_SPADI,	/* PCSME_OPEN   User open */
    234 		PCSMA_SPADR,	/* PCSME_TOP    Timeout+ */
    235 		PCSMA_SPADRN,	/* PCSME_TOM    Timeout- */
    236 		PCSMA_FAIL,	/* PCSME_RPADT  Receive PADT */
    237 		PCSMA_ADD,	/* PCSME_RPADOP Receive desired PADO */
    238 		PCSMA_ADD,	/* PCSME_RPADO  Receive ordinary PADO */
    239 		PCSMA_OPEN,	/* PCSME_RPADS  Receive PADS */
    240 		PCSMA_SPADRN,	/* PCSME_RPADSN Receive bad PADS */
    241 	},
    242 /* 4 PCSMS_CONVERS  Conversational */
    243 	{
    244 		PCSMA_FAIL,	/* PCSME_CLOSE  User close */
    245 		PCSMA_SPADI,	/* PCSME_OPEN   User open */
    246 		PCSMA_FAIL,	/* PCSME_TOP    Timeout+ */
    247 		PCSMA_FAIL,	/* PCSME_TOM    Timeout- */
    248 		PCSMA_FAIL,	/* PCSME_RPADT  Receive PADT */
    249 		PCSMA_NONE,	/* PCSME_RPADOP Receive desired PADO */
    250 		PCSMA_NONE,	/* PCSME_RPADO  Receive ordinary PADO */
    251 		PCSMA_NONE,	/* PCSME_RPADS  Receive PADS */
    252 		PCSMA_NONE,	/* PCSME_RPADSN Receive bad PADS */
    253 	},
    254 };
    255 
    256 /*
    257  * PPPoE Message structure -- holds data from a received PPPoE
    258  * message.  These are copied and saved when queuing offers from
    259  * possible servers.
    260  */
    261 typedef struct poesm_s {
    262 	struct poesm_s	*poemsg_next;	/* Next message in list */
    263 	const poep_t	*poemsg_data;	/* Pointer to PPPoE packet */
    264 	int		poemsg_len;	/* Length of packet */
    265 	ppptun_atype	poemsg_sender;	/* Address of sender */
    266 	const char	*poemsg_iname;	/* Name of input interface */
    267 } poemsg_t;
    268 
    269 /*
    270  * PPPoE State Machine structure -- holds state of PPPoE negotiation;
    271  * currently, there's exactly one of these per pppoec instance.
    272  */
    273 typedef struct {
    274 	int		poesm_state;		/* PCSMS_* */
    275 	int		poesm_timer;		/* Milliseconds to next TO */
    276 	int		poesm_count;		/* Retry countdown */
    277 	int		poesm_interval;		/* Reload value */
    278 	uint32_t	poesm_sequence;		/* Sequence for PADR */
    279 
    280 	poemsg_t	*poesm_firstoff;	/* Queue of valid offers; */
    281 	poemsg_t	*poesm_lastoff;		/* first is best offer */
    282 	poemsg_t	*poesm_tried;		/* Tried and failed offers */
    283 
    284 	int		poesm_localid;		/* Local session ID (driver) */
    285 } poesm_t;
    286 
    287 /*
    288  * Convert an internal PPPoE event code number into a printable
    289  * string.
    290  */
    291 static const char *
    292 poe_event(int event)
    293 {
    294 	static const char *poeevent[PCSME__MAX] = {
    295 		"Close", "Open", "TO+", "TO-", "rPADT",
    296 		"rPADO+", "rPADO", "rPADS", "rPADS-"
    297 	};
    298 
    299 	if (event < 0 || event >= PCSME__MAX) {
    300 		return ("?");
    301 	}
    302 	return (poeevent[event]);
    303 }
    304 
    305 /*
    306  * Convert an internal PPPoE state number into a printable string.
    307  */
    308 static const char *
    309 poe_state(int state)
    310 {
    311 	static const char *poestate[PCSMS__MAX] = {
    312 		"Dead", "InitSent", "OffrRcvd", "ReqSent", "Convers",
    313 	};
    314 
    315 	if (state < 0 || state >= PCSMS__MAX) {
    316 		return ("?");
    317 	}
    318 	return (poestate[state]);
    319 }
    320 
    321 /*
    322  * Convert an internal PPPoE action number into a printable string.
    323  */
    324 static const char *
    325 poe_action(int act)
    326 {
    327 	static const char *poeaction[PCSMA__MAX] = {
    328 		"None", "Fail", "SendPADI", "Add", "SendPADR",
    329 		"SendPADR+", "SendPADR-", "Open"
    330 	};
    331 
    332 	if (act < 0 || act >= PCSMA__MAX) {
    333 		return ("?");
    334 	}
    335 	return (poeaction[act]);
    336 }
    337 
    338 /*
    339  * This calls mygetmsg (which discards partial messages as needed) and
    340  * logs errors as appropriate.
    341  */
    342 static int
    343 pppoec_getmsg(int fd, struct strbuf *ctrl, struct strbuf *data, int *flags)
    344 {
    345 	int retv;
    346 
    347 	for (;;) {
    348 		retv = mygetmsg(fd, ctrl, data, flags);
    349 		if (retv == 0)
    350 			break;
    351 		if (retv < 0) {
    352 			if (errno == EINTR)
    353 				continue;
    354 			logstrerror("getmsg");
    355 			break;
    356 		}
    357 		if (verbose) {
    358 			if (!(retv & (MORECTL | MOREDATA)))
    359 				logerr("%s: discard: "
    360 				    "unexpected status %d\n", myname, retv);
    361 			else
    362 				logerr("%s: discard: "
    363 				    "truncated %s%smessage\n", myname,
    364 				    retv & MORECTL ? "control " : "",
    365 				    retv & MOREDATA ? "data " : "");
    366 		}
    367 	}
    368 	return (retv);
    369 }
    370 
    371 /*
    372  * Connect the control path to the lower stream of interest.  This
    373  * must be called after opening the tunnel driver in order to
    374  * establish the interface to be used for signaling.  Returns local
    375  * session ID number.
    376  */
    377 static int
    378 set_control(const char *dname)
    379 {
    380 	struct ppptun_peer ptp;
    381 	union ppptun_name ptn;
    382 
    383 	/* Fetch the local session ID first. */
    384 	(void) memset(&ptp, '\0', sizeof (ptp));
    385 	ptp.ptp_style = PTS_PPPOE;
    386 	if (strioctl(tunfd, PPPTUN_SPEER, &ptp, sizeof (ptp), sizeof (ptp)) <
    387 	    0) {
    388 		logstrerror("PPPTUN_SPEER");
    389 		exit(1);
    390 	}
    391 
    392 	/* Connect to lower stream. */
    393 	(void) snprintf(ptn.ptn_name, sizeof (ptn.ptn_name), "%s:pppoed",
    394 	    dname);
    395 	if (strioctl(tunfd, PPPTUN_SCTL, &ptn, sizeof (ptn), 0) < 0) {
    396 		logerr("%s: PPPTUN_SCTL %s: %s\n", myname,
    397 		    ptn.ptn_name, mystrerror(errno));
    398 		exit(1);
    399 	}
    400 	return (ptp.ptp_lsessid);
    401 }
    402 
    403 /*
    404  * Check if standard input is actually a viable connection to the
    405  * tunnel driver.  This is the normal mode of operation with pppd; the
    406  * tunnel driver is opened by pppd as the tty and pppoec is exec'd as
    407  * the connect script.
    408  */
    409 static void
    410 check_stdin(void)
    411 {
    412 	struct ppptun_info pti;
    413 	union ppptun_name ptn;
    414 
    415 	if (strioctl(0, PPPTUN_GDATA, &ptn, 0, sizeof (ptn)) < 0) {
    416 		if (errno == EINVAL)
    417 			logerr("%s: PPPoE operation requires "
    418 			    "the use of a tunneling device\n", myname);
    419 		else
    420 			logstrerror("PPPTUN_GDATA");
    421 		exit(1);
    422 	}
    423 	if (ptn.ptn_name[0] != '\0') {
    424 		if (strioctl(0, PPPTUN_GINFO, &pti, 0, sizeof (pti)) < 0) {
    425 			logstrerror("PPPTUN_GINFO");
    426 			exit(1);
    427 		}
    428 		if (pti.pti_style != PTS_PPPOE) {
    429 			logerr("%s: Cannot connect to server "
    430 			    "using PPPoE; stream already set to style %d\n",
    431 			    myname, pti.pti_style);
    432 			exit(1);
    433 		}
    434 		if (verbose)
    435 			logerr("%s: Warning:  PPPoE data link "
    436 			    "already connected\n", myname);
    437 		exit(0);
    438 	}
    439 	/* Standard input is the tunnel driver; use it. */
    440 	tunfd = 0;
    441 }
    442 
    443 /*
    444  * Write a summary of a PPPoE message to the given file.  This is used
    445  * for logging and to display received offers in the inquiry (-i) mode.
    446  */
    447 static void
    448 display_pppoe(FILE *out, const poep_t *poep, int plen, const ppptun_atype *pap)
    449 {
    450 	int ttyp;
    451 	int tlen;
    452 	const uint8_t *tagp;
    453 	const uint8_t *dp;
    454 	const char *str;
    455 	poer_t poer;
    456 	uint32_t mask;
    457 
    458 	if (out == stderr)
    459 		logerr(" ");	/* Give us a timestamp */
    460 	/* Print name of sender. */
    461 	(void) fprintf(out, "%-16s ", ehost(pap));
    462 
    463 	/* Loop through tags and print each. */
    464 	tagp = (const uint8_t *)(poep + 1);
    465 	while (poe_tagcheck(poep, plen, tagp)) {
    466 		ttyp = POET_GET_TYPE(tagp);
    467 		if (ttyp == POETT_END)
    468 			break;
    469 		tlen = POET_GET_LENG(tagp);
    470 		dp = POET_DATA(tagp);
    471 		str = NULL;
    472 		switch (ttyp) {
    473 		case POETT_SERVICE:	/* Service-Name */
    474 			str = "Svc";
    475 			break;
    476 		case POETT_ACCESS:	/* AC-Name */
    477 			str = "Name";
    478 			break;
    479 		case POETT_UNIQ:	/* Host-Uniq */
    480 			str = "Uniq";
    481 			break;
    482 		case POETT_COOKIE:	/* AC-Cookie */
    483 			str = "Cookie";
    484 			break;
    485 		case POETT_VENDOR:	/* Vendor-Specific */
    486 			break;
    487 		case POETT_RELAY:	/* Relay-Session-Id */
    488 			str = "Relay";
    489 			break;
    490 		case POETT_NAMERR:	/* Service-Name-Error */
    491 			str = "SvcNameErr";
    492 			break;
    493 		case POETT_SYSERR:	/* AC-System-Error */
    494 			str = "SysErr";
    495 			break;
    496 		case POETT_GENERR:	/* Generic-Error */
    497 			str = "GenErr";
    498 			break;
    499 		case POETT_MULTI:	/* Multicast-Capable */
    500 			break;
    501 		case POETT_HURL:	/* Host-URL */
    502 			str = "URL";
    503 			break;
    504 		case POETT_MOTM:	/* Message-Of-The-Minute */
    505 			str = "Mesg";
    506 			break;
    507 		case POETT_RTEADD:	/* IP-Route-Add */
    508 			break;
    509 		}
    510 		switch (ttyp) {
    511 		case POETT_NAMERR:	/* Service-Name-Error */
    512 		case POETT_SYSERR:	/* AC-System-Error */
    513 			if (tlen > 0 && *dp == '\0')
    514 				tlen = 0;
    515 			/* FALLTHROUGH */
    516 		case POETT_SERVICE:	/* Service-Name */
    517 		case POETT_ACCESS:	/* AC-Name */
    518 		case POETT_GENERR:	/* Generic-Error */
    519 		case POETT_MOTM:	/* Message-Of-The-Minute */
    520 		case POETT_HURL:	/* Host-URL */
    521 			(void) fprintf(out, "%s:\"%.*s\" ", str, tlen, dp);
    522 			break;
    523 		case POETT_UNIQ:	/* Host-Uniq */
    524 		case POETT_COOKIE:	/* AC-Cookie */
    525 		case POETT_RELAY:	/* Relay-Session-Id */
    526 			(void) fprintf(out, "%s:", str);
    527 			while (--tlen >= 0)
    528 				(void) fprintf(out, "%02X", *dp++);
    529 			(void) putc(' ', out);
    530 			break;
    531 		case POETT_VENDOR:	/* Vendor-Specific */
    532 			(void) fputs("Vendor:", out);
    533 			if (tlen >= 4) {
    534 				if (*dp++ != 0) {
    535 					(void) fprintf(out, "(%02X?)", dp[-1]);
    536 				}
    537 				(void) fprintf(out, "%x-%x-%x:", dp[0], dp[1],
    538 				    dp[2]);
    539 				tlen -= 4;
    540 				dp += 3;
    541 			}
    542 			while (--tlen >= 0)
    543 				(void) fprintf(out, "%02X", *dp++);
    544 			(void) putc(' ', out);
    545 			break;
    546 		case POETT_MULTI:	/* Multicast-Capable */
    547 			(void) fprintf(out, "Multi:%d ", *dp);
    548 			break;
    549 		case POETT_RTEADD:	/* IP-Route-Add */
    550 			if (tlen != sizeof (poer)) {
    551 				(void) fprintf(out, "RTE%d? ", tlen);
    552 				break;
    553 			}
    554 			(void) memcpy(&poer, dp, sizeof (poer));
    555 			(void) fputs("RTE:", out);
    556 			if (poer.poer_dest_network == 0)
    557 				(void) fputs("default", out);
    558 			else
    559 				(void) fputs(ihost(poer.poer_dest_network),
    560 				    out);
    561 			mask = ntohl(poer.poer_subnet_mask);
    562 			if (mask != 0 && mask != (uint32_t)~0) {
    563 				if ((~mask & (~mask + 1)) == 0)
    564 					(void) fprintf(out, "/%d",
    565 					    sizeof (struct in_addr) * NBBY +
    566 					    1 - ffs(mask));
    567 				else
    568 					(void) fprintf(out, "/%s",
    569 					    ihost(poer.poer_subnet_mask));
    570 			}
    571 			(void) fprintf(out, ",%s,%u ",
    572 			    ihost(poer.poer_gateway), ntohl(poer.poer_metric));
    573 			break;
    574 		default:
    575 			(void) fprintf(out, "%s:%d ", poe_tagname(ttyp), tlen);
    576 			break;
    577 		}
    578 		tagp = POET_NEXT(tagp);
    579 	}
    580 	(void) putc('\n', out);
    581 }
    582 
    583 /*
    584  * Transmit a PPPoE message to the indicated destination.  Used for
    585  * PADI and PADR messages.
    586  */
    587 static int
    588 send_pppoe(const poep_t *poep, const char *msgname,
    589     const ppptun_atype *destaddr)
    590 {
    591 	struct strbuf ctrl;
    592 	struct strbuf data;
    593 	struct ppptun_control *ptc;
    594 
    595 	/* Set up the control data expected by the driver. */
    596 	ptc = (struct ppptun_control *)pkt_octl;
    597 	(void) memset(ptc, '\0', sizeof (*ptc));
    598 	ptc->ptc_discrim = PPPOE_DISCRIM;
    599 	ptc->ptc_action = PTCA_CONTROL;
    600 	ptc->ptc_address = *destaddr;
    601 	ctrl.len = sizeof (*ptc);
    602 	ctrl.buf = (caddr_t)ptc;
    603 	data.len = poe_length(poep) + sizeof (*poep);
    604 	data.buf = (caddr_t)poep;
    605 	if (verbose)
    606 		logerr("%s: Sending %s to %s: %d bytes\n",
    607 		    myname, msgname, ehost(destaddr), data.len);
    608 	if (putmsg(tunfd, &ctrl, &data, 0) < 0) {
    609 		logstrerror("putmsg");
    610 		return (-1);
    611 	}
    612 	return (0);
    613 }
    614 
    615 /*
    616  * Create and transmit a PPPoE Active Discovery Initiation packet.
    617  * This is broadcasted to all hosts on the LAN.
    618  */
    619 static int
    620 send_padi(int localid)
    621 {
    622 	poep_t *poep;
    623 	ppptun_atype destaddr;
    624 
    625 	poep = poe_mkheader(pkt_output, POECODE_PADI, 0);
    626 	(void) poe_add_str(poep, POETT_SERVICE, "");
    627 	(void) poe_add_long(poep, POETT_UNIQ, localid);
    628 	(void) memset(&destaddr, '\0', sizeof (destaddr));
    629 	(void) memcpy(destaddr.pta_pppoe.ptma_mac, ether_bcast,
    630 	    sizeof (destaddr.pta_pppoe.ptma_mac));
    631 	return (send_pppoe(poep, "PADI", &destaddr));
    632 }
    633 
    634 /*
    635  * This is used by the procedure below -- when the alarm goes off,
    636  * just exit.  (This was once a dummy procedure and used the EINTR
    637  * side-effect to terminate the loop, but that's not reliable, since
    638  * the EINTR could be caught and ignored by the calls to standard
    639  * output.)
    640  */
    641 /* ARGSUSED */
    642 static void
    643 alarm_hand(int dummy)
    644 {
    645 	exit(0);
    646 }
    647 
    648 /*
    649  * Send out a single PADI and listen for servers.  This implements the
    650  * "inquiry" (-i) mode.
    651  */
    652 static void
    653 find_all_servers(int localid)
    654 {
    655 	struct strbuf ctrl;
    656 	struct strbuf data;
    657 	poep_t *poep;
    658 	int flags;
    659 	struct sigaction act;
    660 	struct ppptun_control *ptc;
    661 
    662 	/* Set a default 3-second timer */
    663 	(void) memset(&act, '\0', sizeof (act));
    664 	act.sa_handler = alarm_hand;
    665 	(void) sigaction(SIGALRM, &act, NULL);
    666 	(void) alarm((pado_wait_time + 999) / 1000);
    667 
    668 	/* Broadcast a single request. */
    669 	if (send_padi(localid) != 0)
    670 		return;
    671 
    672 	/* Loop over responses and print them. */
    673 	for (;;) {
    674 		ctrl.maxlen = PKT_OCTL_LEN;
    675 		ctrl.buf = (caddr_t)pkt_octl;
    676 		data.maxlen = PKT_INPUT_LEN;
    677 		data.buf = (caddr_t)pkt_input;
    678 		flags = 0;
    679 
    680 		if (pppoec_getmsg(tunfd, &ctrl, &data, &flags) < 0)
    681 			break;
    682 
    683 		/* Ignore unwanted responses from the driver. */
    684 		if (ctrl.len != sizeof (*ptc)) {
    685 			if (verbose)
    686 				logerr("%s: unexpected %d byte"
    687 				    " control message from driver.\n", myname,
    688 				    ctrl.len);
    689 			continue;
    690 		}
    691 		ptc = (struct ppptun_control *)pkt_octl;
    692 		poep = (poep_t *)pkt_input;
    693 
    694 		/* If it's an offer, then print it out. */
    695 		if (poe_code(poep) == POECODE_PADO) {
    696 			display_pppoe(stdout, poep, data.len,
    697 			    &ptc->ptc_address);
    698 		}
    699 	}
    700 }
    701 
    702 /*
    703  * Parse a server filter from the command line.  The passed-in string
    704  * must be allocated and unchanged, since a pointer to it is saved in
    705  * the filter data structure.  The string is also parsed for a MAC
    706  * address, if possible.
    707  */
    708 static void
    709 parse_filter(const char *str, int exceptflag)
    710 {
    711 	struct server_filter *sfnew;
    712 	const char *cp;
    713 	const char *wordstart;
    714 	const char *wordend;
    715 	int len;
    716 	char hbuf[MAXHOSTNAMELEN];
    717 	uchar_t *ucp;
    718 	uchar_t *mcp;
    719 
    720 	/* Allocate the new filter structure. */
    721 	sfnew = (struct server_filter *)calloc(1, sizeof (*sfnew));
    722 	if (sfnew == NULL) {
    723 		logstrerror("filter allocation");
    724 		exit(1);
    725 	}
    726 
    727 	/* Save the string for AC-Name comparison. */
    728 	sfnew->sf_name = str;
    729 
    730 	sfnew->sf_isexcept = exceptflag == 0 ? 0 : 1;
    731 
    732 	/* Extract just one word. */
    733 	cp = str;
    734 	while (isspace(*cp))
    735 		cp++;
    736 	wordstart = cp;
    737 	while (*cp != '\0' && !isspace(*cp))
    738 		cp++;
    739 	wordend = cp;
    740 	if ((len = wordend - wordstart) >= sizeof (hbuf))
    741 		len = sizeof (hbuf) - 1;
    742 	(void) strlcpy(hbuf, wordstart, len);
    743 	hbuf[len] = '\0';
    744 
    745 	/* Try to translate this as an Ethernet host or address. */
    746 	mcp = sfnew->sf_mask.ether_addr_octet;
    747 	if (ether_hostton(hbuf, &sfnew->sf_mac) == 0) {
    748 		mcp[0] = mcp[1] = mcp[2] = mcp[3] = mcp[4] = mcp[5] = 0xFF;
    749 		sfnew->sf_hasmac = 1;
    750 	} else {
    751 		ucp = sfnew->sf_mac.ether_addr_octet;
    752 		len = wordend - wordstart;
    753 		cp = wordstart;
    754 		while (cp < wordend) {
    755 			if (ucp >= sfnew->sf_mac.ether_addr_octet +
    756 			    sizeof (sfnew->sf_mac))
    757 				break;
    758 			if (*cp == '*') {
    759 				*mcp++ = *ucp++ = 0;
    760 				cp++;
    761 			} else {
    762 				if (!isxdigit(*cp))
    763 					break;
    764 				*ucp = hexdecode(*cp++);
    765 				if (cp < wordend && isxdigit(*cp)) {
    766 					*ucp = (*ucp << 4) |
    767 					    hexdecode(*cp++);
    768 				}
    769 				ucp++;
    770 				*mcp++ = 0xFF;
    771 			}
    772 			if (cp < wordend) {
    773 				if (*cp != ':' || cp + 1 == wordend)
    774 					break;
    775 				cp++;
    776 			}
    777 		}
    778 		if (cp >= wordend)
    779 			sfnew->sf_hasmac = 1;
    780 		else if (verbose)
    781 			logerr("%s: treating '%.*s' as server "
    782 			    "name only, not MAC address\n", myname, len,
    783 			    wordstart);
    784 	}
    785 
    786 	/* Add to end of list. */
    787 	if (sftail == NULL)
    788 		sfhead = sfnew;
    789 	else
    790 		sftail->sf_next = sfnew;
    791 	sftail = sfnew;
    792 }
    793 
    794 /*
    795  * Create a copy of a given PPPoE message.  This is used for enqueuing
    796  * received PADO (offers) from possible servers.
    797  */
    798 static poemsg_t *
    799 save_message(const poemsg_t *pmsg)
    800 {
    801 	poemsg_t *newmsg;
    802 	char *cp;
    803 
    804 	newmsg = (poemsg_t *)malloc(sizeof (*pmsg) + pmsg->poemsg_len +
    805 		strlen(pmsg->poemsg_iname) + 1);
    806 	if (newmsg != NULL) {
    807 		newmsg->poemsg_next = NULL;
    808 		newmsg->poemsg_data = (const poep_t *)(newmsg + 1);
    809 		(void) memcpy(newmsg + 1, pmsg->poemsg_data, pmsg->poemsg_len);
    810 		newmsg->poemsg_len = pmsg->poemsg_len;
    811 		cp = (char *)newmsg->poemsg_data + pmsg->poemsg_len;
    812 		newmsg->poemsg_iname = (const char *)cp;
    813 		(void) strcpy(cp, pmsg->poemsg_iname);
    814 		(void) memcpy(&newmsg->poemsg_sender, &pmsg->poemsg_sender,
    815 		    sizeof (newmsg->poemsg_sender));
    816 	}
    817 	return (newmsg);
    818 }
    819 
    820 /*
    821  * Create and send a PPPoE Active Discovery Request (PADR) message to
    822  * the sender of the given PADO.  Some tags -- Service-Name,
    823  * AC-Cookie, and Relay-Session-Id -- must be copied from PADO to
    824  * PADR.  Others are not.  The Service-Name must be selected from the
    825  * offered services in the PADO based on the user's requested service
    826  * name.  If the server offered "wildcard" service, then we ask for
    827  * this only if we can't find the user's requested service.
    828  *
    829  * Returns 1 if we can't send a valid PADR in response to the given
    830  * PADO.  The offer should be ignored and the next one tried.
    831  */
    832 static int
    833 send_padr(poesm_t *psm, const poemsg_t *pado)
    834 {
    835 	poep_t *poep;
    836 	boolean_t haswild;
    837 	boolean_t hassvc;
    838 	const uint8_t *tagp;
    839 	int ttyp;
    840 	int tlen;
    841 
    842 	/*
    843 	 * Increment sequence number for PADR so that we don't mistake
    844 	 * old replies for valid ones if the server is very slow.
    845 	 */
    846 	psm->poesm_sequence++;
    847 
    848 	poep = poe_mkheader(pkt_output, POECODE_PADR, 0);
    849 	(void) poe_two_longs(poep, POETT_UNIQ, psm->poesm_localid,
    850 	    psm->poesm_sequence);
    851 
    852 	haswild = B_FALSE;
    853 	hassvc = B_FALSE;
    854 	tagp = (const uint8_t *)(pado->poemsg_data + 1);
    855 	while (poe_tagcheck(pado->poemsg_data, pado->poemsg_len, tagp)) {
    856 		ttyp = POET_GET_TYPE(tagp);
    857 		if (ttyp == POETT_END)
    858 			break;
    859 		tlen = POET_GET_LENG(tagp);
    860 		switch (ttyp) {
    861 		case POETT_SERVICE:	/* Service-Name */
    862 			/* Allow only one */
    863 			if (hassvc)
    864 				break;
    865 			if (tlen == 0) {
    866 				haswild = B_TRUE;
    867 				break;
    868 			}
    869 			if (service[0] == '\0' ||
    870 			    (tlen == strlen(service) &&
    871 				memcmp(service, POET_DATA(tagp), tlen) == 0)) {
    872 				(void) poe_tag_copy(poep, tagp);
    873 				hassvc = B_TRUE;
    874 			}
    875 			break;
    876 		/* Ones we should discard */
    877 		case POETT_ACCESS:	/* AC-Name */
    878 		case POETT_UNIQ:	/* Host-Uniq */
    879 		case POETT_NAMERR:	/* Service-Name-Error */
    880 		case POETT_SYSERR:	/* AC-System-Error */
    881 		case POETT_GENERR:	/* Generic-Error */
    882 		case POETT_HURL:	/* Host-URL */
    883 		case POETT_MOTM:	/* Message-Of-The-Minute */
    884 		case POETT_RTEADD:	/* IP-Route-Add */
    885 		case POETT_VENDOR:	/* Vendor-Specific */
    886 		case POETT_MULTI:	/* Multicast-Capable */
    887 		default:		/* Anything else we don't understand */
    888 			break;
    889 		/* Ones we should copy */
    890 		case POETT_COOKIE:	/* AC-Cookie */
    891 		case POETT_RELAY:	/* Relay-Session-Id */
    892 			(void) poe_tag_copy(poep, tagp);
    893 			break;
    894 		}
    895 		tagp = POET_NEXT(tagp);
    896 	}
    897 	if (!hassvc) {
    898 		if (haswild)
    899 			(void) poe_add_str(poep, POETT_SERVICE, "");
    900 		else
    901 			return (1);
    902 	}
    903 
    904 	return (send_pppoe(poep, "PADR", &pado->poemsg_sender));
    905 }
    906 
    907 /*
    908  * ********************************************************************
    909  * act_* functions implement the actions driven by the state machine
    910  * tables.  See "action_table" below.
    911  *
    912  * All action routines must return the next state value.
    913  * ********************************************************************
    914  */
    915 
    916 /* ARGSUSED */
    917 static int
    918 act_none(poesm_t *psm, poemsg_t *pmsg, int event, int nextst)
    919 {
    920 	return (nextst);
    921 }
    922 
    923 /* ARGSUSED */
    924 static int
    925 act_fail(poesm_t *psm, poemsg_t *pmsg, int event, int nextst)
    926 {
    927 	if (verbose)
    928 		logerr("%s: unrecoverable error\n", myname);
    929 	return (PCSMS_DEAD);
    930 }
    931 
    932 /* ARGSUSED */
    933 static int
    934 act_spadi(poesm_t *psm, poemsg_t *pmsg, int event, int nextst)
    935 {
    936 	if (send_padi(psm->poesm_localid) != 0)
    937 		return (PCSMS_DEAD);
    938 	/*
    939 	 * If this is the first time, then initialize the retry count
    940 	 * and interval.
    941 	 */
    942 	if (psm->poesm_state == PCSMS_DEAD) {
    943 		psm->poesm_count = 3;
    944 		psm->poesm_interval = pado_wait_time;
    945 	} else {
    946 		if ((psm->poesm_interval <<= 1) > RESTART_LIMIT)
    947 			psm->poesm_interval = RESTART_LIMIT;
    948 	}
    949 	psm->poesm_timer = psm->poesm_interval;
    950 	(void) gettimeofday(&tvstart, NULL);
    951 	return (nextst);
    952 }
    953 
    954 /* ARGSUSED */
    955 static int
    956 act_add(poesm_t *psm, poemsg_t *pmsg, int event, int nextst)
    957 {
    958 	pmsg = save_message(pmsg);
    959 	if (pmsg != NULL) {
    960 		if (psm->poesm_lastoff == NULL)
    961 			psm->poesm_firstoff = pmsg;
    962 		else
    963 			psm->poesm_lastoff->poemsg_next = pmsg;
    964 		psm->poesm_lastoff = pmsg;
    965 	}
    966 	return (nextst);
    967 }
    968 
    969 /* ARGSUSED */
    970 static int
    971 act_spadr(poesm_t *psm, poemsg_t *pmsg, int event, int nextst)
    972 {
    973 	poemsg_t *msgp;
    974 	int retv;
    975 
    976 	for (;;) {
    977 		if ((msgp = psm->poesm_firstoff) == NULL)
    978 			return (PCSMS_DEAD);
    979 		retv = send_padr(psm, msgp);
    980 		if (retv < 0)
    981 			return (PCSMS_DEAD);
    982 		if (retv == 0)
    983 			break;
    984 		/* Can't send this request; try looking at next offer. */
    985 		psm->poesm_firstoff = msgp->poemsg_next;
    986 		msgp->poemsg_next = psm->poesm_tried;
    987 		psm->poesm_tried = msgp;
    988 	}
    989 	if (psm->poesm_state != PCSMS_REQSENT) {
    990 		psm->poesm_count = 3;
    991 		psm->poesm_interval = pads_wait_time;
    992 	} else {
    993 		if ((psm->poesm_interval <<= 1) > RESTART_LIMIT)
    994 			psm->poesm_interval = RESTART_LIMIT;
    995 	}
    996 	psm->poesm_timer = psm->poesm_interval;
    997 	(void) gettimeofday(&tvstart, NULL);
    998 	return (nextst);
    999 }
   1000 
   1001 /* ARGSUSED */
   1002 static int
   1003 act_spadrp(poesm_t *psm, poemsg_t *pmsg, int event, int nextst)
   1004 {
   1005 	int retv;
   1006 
   1007 	retv = send_padr(psm, pmsg);
   1008 	if (retv < 0)
   1009 		return (PCSMS_DEAD);
   1010 	pmsg = save_message(pmsg);
   1011 	if (retv > 0) {
   1012 		/*
   1013 		 * Cannot use this one; mark as tried and continue as
   1014 		 * if we never saw it.
   1015 		 */
   1016 		pmsg->poemsg_next = psm->poesm_tried;
   1017 		psm->poesm_tried = pmsg;
   1018 		return (psm->poesm_state);
   1019 	}
   1020 	pmsg->poemsg_next = psm->poesm_firstoff;
   1021 	psm->poesm_firstoff = pmsg;
   1022 	if (psm->poesm_lastoff == NULL)
   1023 		psm->poesm_lastoff = pmsg;
   1024 	psm->poesm_count = 3;
   1025 	psm->poesm_timer = psm->poesm_interval = pads_wait_time;
   1026 	(void) gettimeofday(&tvstart, NULL);
   1027 	return (nextst);
   1028 }
   1029 
   1030 /* ARGSUSED */
   1031 static int
   1032 act_spadrn(poesm_t *psm, poemsg_t *pmsg, int event, int nextst)
   1033 {
   1034 	poemsg_t *msgp;
   1035 	int retv;
   1036 
   1037 	if ((msgp = psm->poesm_firstoff) == NULL)
   1038 		return (PCSMS_DEAD);
   1039 	do {
   1040 		psm->poesm_firstoff = msgp->poemsg_next;
   1041 		msgp->poemsg_next = psm->poesm_tried;
   1042 		psm->poesm_tried = msgp;
   1043 		if ((msgp