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 = psm->poesm_firstoff) == NULL) 1044 return (PCSMS_DEAD); 1045 retv = send_padr(psm, msgp); 1046 if (retv < 0) 1047 return (PCSMS_DEAD); 1048 } while (retv != 0); 1049 psm->poesm_count = 3; 1050 psm->poesm_timer = psm->poesm_interval = pads_wait_time; 1051 (void) gettimeofday(&tvstart, NULL); 1052 return (nextst); 1053 } 1054 1055 /* 1056 * For safety -- remove end of line from strings passed back to pppd. 1057 */ 1058 static void 1059 remove_eol(char *str, size_t len) 1060 { 1061 while (len > 0) { 1062 if (*str == '\n') 1063 *str = '$'; 1064 str++; 1065 len--; 1066 } 1067 } 1068 1069 /* ARGSUSED */ 1070 static int 1071 act_open(poesm_t *psm, poemsg_t *pmsg, int event, int nextst) 1072 { 1073 struct ppptun_peer ptp; 1074 union ppptun_name ptn; 1075 const char *cp; 1076 FILE *fp; 1077 const uint8_t *tagp, *vp; 1078 int tlen, ttyp; 1079 char *access; 1080 uint32_t val; 1081 size_t acc_len, serv_len; 1082 1083 /* 1084 * The server has now assigned its session ID for the data 1085 * (PPP) portion of this tunnel. Send that ID down to the 1086 * driver. 1087 */ 1088 (void) memset(&ptp, '\0', sizeof (ptp)); 1089 ptp.ptp_lsessid = psm->poesm_localid; 1090 ptp.ptp_rsessid = poe_session_id(pmsg->poemsg_data); 1091 (void) memcpy(&ptp.ptp_address, &pmsg->poemsg_sender, 1092 sizeof (ptp.ptp_address)); 1093 ptp.ptp_style = PTS_PPPOE; 1094 if (strioctl(tunfd, PPPTUN_SPEER, &ptp, sizeof (ptp), sizeof (ptp)) < 1095 0) { 1096 logstrerror("PPPTUN_SPEER"); 1097 return (PCSMS_DEAD); 1098 } 1099 1100 /* 1101 * Data communication is now possible on this session. 1102 * Connect the data portion to the correct lower stream. 1103 */ 1104 if ((cp = strchr(pmsg->poemsg_iname, ':')) == NULL) 1105 cp = pmsg->poemsg_iname + strlen(pmsg->poemsg_iname); 1106 (void) snprintf(ptn.ptn_name, sizeof (ptn.ptn_name), "%.*s:pppoe", 1107 cp - pmsg->poemsg_iname, pmsg->poemsg_iname); 1108 if (strioctl(tunfd, PPPTUN_SDATA, &ptn, sizeof (ptn), 0) < 0) { 1109 logerr("%s: PPPTUN_SDATA %s: %s\n", 1110 myname, ptn.ptn_name, mystrerror(errno)); 1111 return (PCSMS_DEAD); 1112 } 1113 if (verbose) 1114 logerr("%s: Connection open; session %04X on " 1115 "%s\n", myname, ptp.ptp_rsessid, ptn.ptn_name); 1116 1117 /* 1118 * Walk through the PADS message to get the access server name 1119 * and the service. If there are multiple instances of either 1120 * tag, then take the last access server and the first 1121 * non-null service. 1122 */ 1123 access = ""; 1124 acc_len = 0; 1125 serv_len = strlen(service); 1126 tagp = (const uint8_t *)(pmsg->poemsg_data + 1); 1127 while (poe_tagcheck(pmsg->poemsg_data, pmsg->poemsg_len, tagp)) { 1128 ttyp = POET_GET_TYPE(tagp); 1129 if (ttyp == POETT_END) 1130 break; 1131 tlen = POET_GET_LENG(tagp); 1132 if (ttyp == POETT_ACCESS) { 1133 access = (char *)POET_DATA(tagp); 1134 acc_len = tlen; 1135 } 1136 if (serv_len == 0 && ttyp == POETT_SERVICE && tlen != 0) { 1137 service = (char *)POET_DATA(tagp); 1138 serv_len = tlen; 1139 } 1140 tagp = POET_NEXT(tagp); 1141 } 1142 1143 /* 1144 * Remove end of line to make sure that integrity of values 1145 * passed back to pppd can't be compromised by the PPPoE 1146 * server. 1147 */ 1148 remove_eol(service, serv_len); 1149 remove_eol(access, acc_len); 1150 1151 /* 1152 * pppd has given us a pipe as fd 3, and we're expected to 1153 * write out the values of the following environment 1154 * variables: 1155 * IF_AND_SERVICE 1156 * SERVICE_NAME 1157 * AC_NAME 1158 * AC_MAC 1159 * SESSION_ID 1160 * VENDOR_SPECIFIC_1 ... N 1161 * See usr.bin/pppd/plugins/pppoe.c for more information. 1162 */ 1163 if ((fp = fdopen(3, "w")) != NULL) { 1164 (void) fprintf(fp, "%.*s:%.*s\n", 1165 cp - pmsg->poemsg_iname, pmsg->poemsg_iname, serv_len, 1166 service); 1167 (void) fprintf(fp, "%.*s\n", serv_len, service); 1168 (void) fprintf(fp, "%.*s\n", acc_len, access); 1169 (void) fprintf(fp, "%s\n", ehost(&pmsg->poemsg_sender)); 1170 (void) fprintf(fp, "%d\n", poe_session_id(pmsg->poemsg_data)); 1171 tagp = (const uint8_t *)(pmsg->poemsg_data + 1); 1172 while (poe_tagcheck(pmsg->poemsg_data, pmsg->poemsg_len, 1173 tagp)) { 1174 ttyp = POET_GET_TYPE(tagp); 1175 if (ttyp == POETT_END) 1176 break; 1177 tlen = POET_GET_LENG(tagp); 1178 if (ttyp == POETT_VENDOR && tlen >= 4) { 1179 (void) memcpy(&val, POET_DATA(tagp), 4); 1180 (void) fprintf(fp, "%08lX:", 1181 (unsigned long)ntohl(val)); 1182 tlen -= 4; 1183 vp = POET_DATA(tagp) + 4; 1184 while (--tlen >= 0) 1185 (void) fprintf(fp, "%02X", *vp++); 1186 (void) putc('\n', fp); 1187 } 1188 tagp = POET_NEXT(tagp); 1189 } 1190 (void) fclose(fp); 1191 } 1192 1193 return (nextst); 1194 } 1195 1196 static int (* const action_table[PCSMA__MAX])(poesm_t *psm, poemsg_t *pmsg, 1197 int event, int nextst) = { 1198 act_none, act_fail, act_spadi, act_add, act_spadr, act_spadrp, 1199 act_spadrn, act_open 1200 }; 1201 1202 /* 1203 * Dispatch an event and a corresponding message on a given state 1204 * machine. 1205 */ 1206 static void 1207 handle_event(poesm_t *psm, int event, poemsg_t *pmsg) 1208 { 1209 int nextst; 1210 1211 if (verbose) 1212 logerr("%s: PPPoE Event %s (%d) in state %s " 1213 "(%d): action %s (%d)\n", myname, poe_event(event), event, 1214 poe_state(psm->poesm_state), psm->poesm_state, 1215 poe_action(client_action[psm->poesm_state][event]), 1216 client_action[psm->poesm_state][event]); 1217 1218 nextst = (*action_table[client_action[psm->poesm_state][event]])(psm, 1219 pmsg, event, client_next_state[psm->poesm_state][event]); 1220 1221 if (verbose) 1222 logerr("%s: PPPoE State change %s (%d) -> %s (%d)\n", myname, 1223 poe_state(psm->poesm_state), psm->poesm_state, 1224 poe_state(nextst), nextst); 1225 1226 psm->poesm_state = nextst; 1227 1228 /* 1229 * Life-altering states are handled here. If we reach dead 1230 * state again after starting, then we failed. If we reach 1231 * conversational state, then we're open. 1232 */ 1233 if (nextst == PCSMS_DEAD) { 1234 if (verbose) 1235 logerr("%s: action failed\n", myname); 1236 exit(1); 1237 } 1238 if (nextst == PCSMS_CONVERS) { 1239 if (verbose) 1240 logerr("%s: connected\n", myname); 1241 exit(0); 1242 } 1243 } 1244 1245 /* 1246 * Check for error message tags in the PPPoE packet. We must ignore 1247 * offers that merely report errors, and need to log errors in any 1248 * case. 1249 */ 1250 static int 1251 error_check(poemsg_t *pmsg) 1252 { 1253 const uint8_t *tagp; 1254 int ttyp; 1255 1256 tagp = (const uint8_t *)(pmsg->poemsg_data + 1); 1257 while (poe_tagcheck(pmsg->poemsg_data, pmsg->poemsg_len, tagp)) { 1258 ttyp = POET_GET_TYPE(tagp); 1259 if (ttyp == POETT_END) 1260 break; 1261 if (ttyp == POETT_NAMERR || ttyp == POETT_SYSERR || 1262 ttyp == POETT_GENERR) { 1263 if (verbose) 1264 display_pppoe(stderr, pmsg->poemsg_data, 1265 pmsg->poemsg_len, &pmsg->poemsg_sender); 1266 return (-1); 1267 } 1268 tagp = POET_NEXT(tagp); 1269 } 1270 return (0); 1271 } 1272 1273 /* 1274 * Extract sequence number, if any, from PADS message, so that we can 1275 * relate it to the PADR that we sent. 1276 */ 1277 static uint32_t 1278 get_sequence(const poemsg_t *pmsg) 1279 { 1280 const uint8_t *tagp; 1281 int ttyp; 1282 uint32_t vals[2]; 1283 1284 tagp = (const uint8_t *)(pmsg->poemsg_data + 1); 1285 while (poe_tagcheck(pmsg->poemsg_data, pmsg->poemsg_len, tagp)) { 1286 ttyp = POET_GET_TYPE(tagp); 1287 if (ttyp == POETT_END) 1288 break; 1289 if (ttyp == POETT_UNIQ) { 1290 if (POET_GET_LENG(tagp) < sizeof (vals)) 1291 break; 1292 (void) memcpy(vals, POET_DATA(tagp), sizeof (vals)); 1293 return (ntohl(vals[1])); 1294 } 1295 tagp = POET_NEXT(tagp); 1296 } 1297 return (0); 1298 } 1299 1300 /* 1301 * Server filter cases: 1302 * 1303 * No filters -- all servers generate RPADO+ event; select the 1304 * first responding server. 1305 * 1306 * Only "except" filters -- matching servers are RPADO, others 1307 * are RPADO+. 1308 * 1309 * Mix of filters -- those matching "pass" are RPADO+, those 1310 * matching "except" are RPADO, and all others are also RPADO. 1311 * 1312 * If the "only" keyword was given, then RPADO becomes -1; only RPADO+ 1313 * events occur. 1314 */ 1315 static int 1316 use_server(poemsg_t *pado) 1317 { 1318 struct server_filter *sfp; 1319 const uchar_t *sndp; 1320 const uchar_t *macp; 1321 const uchar_t *maskp; 1322 int i; 1323 int passmatched; 1324 const uint8_t *tagp; 1325 int ttyp; 1326 1327 /* 1328 * If no service mentioned in offer, then we can't use it. 1329 */ 1330 tagp = (const uint8_t *)(pado->poemsg_data + 1); 1331 ttyp = POETT_END; 1332 while (poe_tagcheck(pado->poemsg_data, pado->poemsg_len, tagp)) { 1333 ttyp = POET_GET_TYPE(tagp); 1334 if (ttyp == POETT_END || ttyp == POETT_SERVICE) 1335 break; 1336 tagp = POET_NEXT(tagp); 1337 } 1338 if (ttyp != POETT_SERVICE) 1339 return (-1); 1340 1341 passmatched = 0; 1342 for (sfp = sfhead; sfp != NULL; sfp = sfp->sf_next) { 1343 passmatched |= !sfp->sf_isexcept; 1344 if (sfp->sf_hasmac) { 1345 sndp = pado->poemsg_sender.pta_pppoe.ptma_mac; 1346 macp = sfp->sf_mac.ether_addr_octet; 1347 maskp = sfp->sf_mask.ether_addr_octet; 1348 i = sizeof (pado->poemsg_sender.pta_pppoe.ptma_mac); 1349 for (; i > 0; i--) 1350 if (((*macp++ ^ *sndp++) & *maskp++) != 0) 1351 break; 1352 if (i <= 0) 1353 break; 1354 } 1355 } 1356 1357 if (sfp == NULL) { 1358 /* 1359 * No match encountered; if only exclude rules have 1360 * been seen, then accept this offer. 1361 */ 1362 if (!passmatched) 1363 return (PCSME_RPADOP); 1364 } else { 1365 if (!sfp->sf_isexcept) 1366 return (PCSME_RPADOP); 1367 } 1368 if (onlyflag) 1369 return (-1); 1370 return (PCSME_RPADO); 1371 } 1372 1373 /* 1374 * This is the normal event loop. It initializes the state machine 1375 * and sends in an Open event to kick things off. Then it drops into 1376 * a loop to dispatch events for the state machine. 1377 */ 1378 static void 1379 find_server(int localid) 1380 { 1381 poesm_t psm; 1382 struct pollfd pfd[1]; 1383 struct timeval tv, tvnow; 1384 int retv; 1385 poemsg_t pmsg; 1386 struct strbuf ctrl; 1387 struct strbuf data; 1388 poep_t *poep; 1389 int flags; 1390 uint32_t seqval; 1391 struct ppptun_control *ptc; 1392 1393 (void) memset(&psm, '\0', sizeof (psm)); 1394 1395 /* 1396 * Initialize the sequence number with something handy. It 1397 * doesn't need to be absolutely unique, since the localid 1398 * value actually demultiplexes everything. This just makes 1399 * the operation a little safer. 1400 */ 1401 psm.poesm_sequence = getpid() << 16; 1402 psm.poesm_localid = localid; 1403 1404 /* Start the state machine */ 1405 handle_event(&psm, PCSME_OPEN, NULL); 1406 1407 /* Enter event polling loop. */ 1408 pfd[0].fd = tunfd; 1409 pfd[0].events = POLLIN; 1410 for (;;) { 1411 /* Wait for timeout or message */ 1412 retv = poll(pfd, 1, psm.poesm_timer > 0 ? psm.poesm_timer : 1413 INFTIM); 1414 if (retv < 0) { 1415 logstrerror("poll"); 1416 break; 1417 } 1418 1419 /* Handle a timeout */ 1420 if (retv == 0) { 1421 psm.poesm_timer = 0; 1422 handle_event(&psm, --psm.poesm_count > 0 ? PCSME_TOP : 1423 PCSME_TOM, NULL); 1424 continue; 1425 } 1426 1427 /* Adjust the timer for the time we slept. */ 1428 if (psm.poesm_timer > 0) { 1429 (void) gettimeofday(&tvnow, NULL); 1430 tv = tvnow; 1431 if ((tv.tv_sec -= tvstart.tv_sec) < 0) { 1432 /* Darn */ 1433 tv.tv_sec = 1; 1434 tv.tv_usec = 0; 1435 } else if ((tv.tv_usec -= tvstart.tv_usec) < 0) { 1436 tv.tv_usec += 1000000; 1437 if (--tv.tv_sec < 0) 1438 tv.tv_sec = 0; 1439 } 1440 psm.poesm_timer -= tv.tv_sec*1000 + tv.tv_usec/1000; 1441 tvstart = tvnow; 1442 } 1443 1444 /* Read in the message from the server. */ 1445 ctrl.maxlen = PKT_OCTL_LEN; 1446 ctrl.buf = (caddr_t)pkt_octl; 1447 data.maxlen = PKT_INPUT_LEN; 1448 data.buf = (caddr_t)pkt_input; 1449 flags = 0; 1450 1451 if (pppoec_getmsg(tunfd, &ctrl, &data, &flags) < 0) 1452 break; 1453 1454 if (ctrl.len != sizeof (*ptc)) { 1455 if (verbose) 1456 logerr("%s: discard: ctrl len %d\n", myname, 1457 ctrl.len); 1458 continue; 1459 } 1460 poep = (poep_t *)pkt_input; 1461 (void) memset(&pmsg, '\0', sizeof (pmsg)); 1462 pmsg.poemsg_next = NULL; 1463 pmsg.poemsg_data = poep; 1464 pmsg.poemsg_len = data.len; 1465 ptc = (struct ppptun_control *)pkt_octl; 1466 if (ptc->ptc_action != PTCA_CONTROL) { 1467 if (verbose) 1468 logerr("%s: discard: unexpected action %d\n", 1469 myname, ptc->ptc_action); 1470 continue; 1471 } 1472 pmsg.poemsg_iname = ptc->ptc_name; 1473 if (verbose) 1474 logerr("%s: Received %s from %s/%s\n", 1475 myname, poe_codename(poep->poep_code), 1476 ehost(&ptc->ptc_address), pmsg.poemsg_iname); 1477 pmsg.poemsg_sender = ptc->ptc_address; 1478 1479 /* Check for messages from unexpected peers. */ 1480 if ((poep->poep_code == POECODE_PADT || 1481 poep->poep_code == POECODE_PADS) && 1482 (psm.poesm_firstoff == NULL || 1483 memcmp(&psm.poesm_firstoff->poemsg_sender, 1484 &pmsg.poemsg_sender, 1485 sizeof (pmsg.poemsg_sender)) != 0)) { 1486 if (verbose) { 1487 logerr("%s: Unexpected peer %s", myname, 1488 ehost(&ptc->ptc_address)); 1489 logerr(" != %s\n", 1490 ehost(&psm.poesm_firstoff->poemsg_sender)); 1491 } 1492 continue; 1493 } 1494 1495 /* Eliminate stale PADS responses. */ 1496 if (poep->poep_code == POECODE_PADS) { 1497 seqval = get_sequence(&pmsg); 1498 if (seqval != psm.poesm_sequence) { 1499 if (verbose) { 1500 if (seqval == 0) 1501 logerr( 1502 "%s: PADS has no sequence " 1503 "number.\n", myname); 1504 else 1505 logerr( 1506 "%s: PADS has sequence " 1507 "%08X instead of %08X.\n", 1508 myname, seqval, 1509 psm.poesm_sequence); 1510 } 1511 continue; 1512 } 1513 } 1514 1515 /* Dispatch message event. */ 1516 retv = error_check(&pmsg); 1517 switch (poep->poep_code) { 1518 case POECODE_PADT: 1519 handle_event(&psm, PCSME_RPADT, &pmsg); 1520 break; 1521 case POECODE_PADS: 1522 /* 1523 * Got a PPPoE Active Discovery Session- 1524 * confirmation message. It's a PADS event if 1525 * everything's in order. It's a PADS- event 1526 * if the message is merely reporting an 1527 * error. 1528 */ 1529 handle_event(&psm, retv != 0 ? PCSME_RPADSN : 1530 PCSME_RPADS, &pmsg); 1531 break; 1532 case POECODE_PADO: 1533 /* Ignore offers that merely report errors. */ 1534 if (retv != 0) 1535 break; 1536 /* Ignore offers from servers we don't want. */ 1537 if ((retv = use_server(&pmsg)) < 0) 1538 break; 1539 /* Dispatch either RPADO or RAPDO+ event. */ 1540 handle_event(&psm, retv, &pmsg); 1541 break; 1542 1543 default: 1544 if (verbose) 1545 logerr("%s: Unexpected code %s (%d)\n", myname, 1546 poe_codename(poep->poep_code), 1547 poep->poep_code); 1548 break; 1549 } 1550 } 1551 exit(1); 1552 } 1553 1554 static void 1555 usage(void) 1556 { 1557 logerr("Usage:\n" 1558 "\t%s [-os#] [-v] <dev> [<service> [<server> [only]]]\n\n" 1559 " or\n\n" 1560 "\t%s [-o#] [-v] -i <dev>\n", myname, myname); 1561 exit(1); 1562 } 1563 1564 /* 1565 * In addition to the usual 0-2 file descriptors, pppd will leave fd 3 1566 * open on a pipe to receive the environment variables. See 1567 * pppoe_device_pipe() in pppd/plugins/pppoe.c and device_pipe_hook in 1568 * pppd/main.c. 1569 */ 1570 int 1571 main(int argc, char **argv) 1572 { 1573 int inquiry_mode, exceptflag, arg, localid; 1574 char *cp; 1575 1576 log_to_stderr(LOGLVL_DBG); 1577 1578 if ((myname = *argv) == NULL) 1579 myname = "pppoec"; 1580 1581 inquiry_mode = 0; 1582 while ((arg = getopt(argc, argv, "io:s:v")) != EOF) 1583 switch (arg) { 1584 case 'i': 1585 inquiry_mode++; 1586 break; 1587 case 'v': 1588 verbose++; 1589 break; 1590 case 'o': 1591 pado_wait_time = strtol(optarg, &cp, 0); 1592 if (pado_wait_time <= 0 || *cp != '\0' || 1593 cp == optarg) { 1594 logerr("%s: illegal PADO wait time: %s\n", 1595 myname, optarg); 1596 exit(1); 1597 } 1598 break; 1599 case 's': 1600 pads_wait_time = strtol(optarg, &cp, 0); 1601 if (pads_wait_time <= 0 || *cp != '\0' || 1602 cp == optarg) { 1603 logerr("%s: illegal PADS wait time: %s\n", 1604 myname, optarg); 1605 exit(1); 1606 } 1607 break; 1608 case '?': 1609 usage(); 1610 } 1611 1612 /* Handle inquiry mode. */ 1613 if (inquiry_mode) { 1614 if (optind != argc-1) 1615 usage(); 1616 if (pado_wait_time == 0) 1617 pado_wait_time = PADI_INQUIRY_DWELL; 1618 1619 /* Invoked by user; open the tunnel driver myself. */ 1620 tunfd = open(tunnam, O_RDWR | O_NOCTTY); 1621 if (tunfd == -1) { 1622 logstrerror(tunnam); 1623 exit(1); 1624 } 1625 1626 /* 1627 * Set up the control stream for PPPoE negotiation 1628 * (set_control), then broadcast a query for all servers 1629 * and listen for replies (find_all_servers). 1630 */ 1631 find_all_servers(set_control(argv[optind])); 1632 return (0); 1633 } 1634 1635 if (pado_wait_time == 0) 1636 pado_wait_time = PADI_RESTART_TIME; 1637 1638 if (optind >= argc) 1639 usage(); 1640 1641 /* Make sure we've got a usable tunnel driver on stdin. */ 1642 check_stdin(); 1643 1644 /* Set up the control stream for PPPoE negotiation. */ 1645 localid = set_control(argv[optind++]); 1646 1647 /* Pick the service, if any. */ 1648 if (optind < argc) 1649 service = argv[optind++]; 1650 1651 /* Parse out the filters. */ 1652 if (optind < argc) { 1653 if (strcasecmp(argv[argc - 1], "only") == 0) { 1654 argc--; 1655 onlyflag = 1; 1656 } 1657 exceptflag = 0; 1658 for (; optind < argc; optind++) { 1659 if (!exceptflag && 1660 strcasecmp(argv[optind], "except") == 0) { 1661 exceptflag = 1; 1662 } else { 1663 parse_filter(argv[optind], exceptflag); 1664 exceptflag = 0; 1665 } 1666 } 1667 } 1668 1669 /* Enter the main loop. */ 1670 find_server(localid); 1671 1672 return (0); 1673 } 1674