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