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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * PPPoE Client-mode "chat" utility for use with Solaris PPP 4.0. 23 * 24 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 25 * Use is subject to license terms. 26 */ 27 28 #include <stdio.h> 29 #include <stdlib.h> 30 #include <unistd.h> 31 #include <ctype.h> 32 #include <strings.h> 33 #include <fcntl.h> 34 #include <errno.h> 35 #include <signal.h> 36 #include <stropts.h> 37 #include <netdb.h> 38 #include <sys/types.h> 39 #include <sys/socket.h> 40 #include <net/if.h> 41 #include <netinet/in.h> 42 #include <netinet/if_ether.h> 43 44 #include <net/sppptun.h> 45 #include <net/pppoe.h> 46 47 #include "common.h" 48 #include "logging.h" 49 50 /* 51 * This value, currently set to the characters "POE1," is used to 52 * distinguish among control messages from multiple lower streams 53 * under /dev/sppp. This feature is needed to support PPP translation 54 * (LAC-like behavior), but isn't currently used. 55 */ 56 #define PPPOE_DISCRIM 0x504F4531 57 58 /* milliseconds between retries */ 59 #define PADI_RESTART_TIME 500 60 #define PADR_RESTART_TIME 2000 61 62 /* default inquiry mode timer in milliseconds. */ 63 #define PADI_INQUIRY_DWELL 3000 64 65 /* maximum timer value in milliseconds */ 66 #define RESTART_LIMIT 5000 67 68 char *myname; /* copy of argv[0] for error messages */ 69 static int verbose; /* -v flag given */ 70 static int onlyflag; /* keyword "only" at end of command line */ 71 static char *service = ""; /* saved service name from command line */ 72 73 static int pado_wait_time = 0; /* see main() */ 74 static int pads_wait_time = PADR_RESTART_TIME; 75 76 static int tunfd; /* open connection to sppptun driver */ 77 78 static struct timeval tvstart; /* time of last PADI/PADR transmission */ 79 80 struct server_filter { 81 struct server_filter *sf_next; /* Next filter in list */ 82 struct ether_addr sf_mac; /* Ethernet address */ 83 struct ether_addr sf_mask; /* Mask (0 or 0xFF in each byte) */ 84 const char *sf_name; /* String for AC-Name compare */ 85 boolean_t sf_hasmac; /* Set if string could be MAC */ 86 boolean_t sf_isexcept; /* Ignore server if matching */ 87 }; 88 89 /* List of filters defined on command line. */ 90 static struct server_filter *sfhead, *sftail; 91 92 /* 93 * PPPoE Client State Machine 94 */ 95 96 /* Client events */ 97 #define PCSME_CLOSE 0 /* User close */ 98 #define PCSME_OPEN 1 /* User open */ 99 #define PCSME_TOP 2 /* Timeout+ (counter non-zero) */ 100 #define PCSME_TOM 3 /* Timeout- (counter zero) */ 101 #define PCSME_RPADT 4 /* Receive PADT (unexpected here) */ 102 #define PCSME_RPADOP 5 /* Receive desired PADO */ 103 #define PCSME_RPADO 6 /* Receive ordinary PADO */ 104 #define PCSME_RPADS 7 /* Receive PADS */ 105 #define PCSME_RPADSN 8 /* Receive bad (errored) PADS */ 106 #define PCSME__MAX 9 107 108 /* Client states */ 109 #define PCSMS_DEAD 0 /* Initial state */ 110 #define PCSMS_INITSENT 1 /* PADI sent */ 111 #define PCSMS_OFFRRCVD 2 /* PADO received */ 112 #define PCSMS_REQSENT 3 /* PADR sent */ 113 #define PCSMS_CONVERS 4 /* Conversational */ 114 #define PCSMS__MAX 5 115 116 /* Client actions */ 117 #define PCSMA_NONE 0 /* Do nothing */ 118 #define PCSMA_FAIL 1 /* Unrecoverable error */ 119 #define PCSMA_SPADI 2 /* Send PADI */ 120 #define PCSMA_ADD 3 /* Add ordinary server to list */ 121 #define PCSMA_SPADR 4 /* Send PADR to top server */ 122 #define PCSMA_SPADRP 5 /* Send PADR to this server (make top) */ 123 #define PCSMA_SPADRN 6 /* Send PADR to next (or terminate) */ 124 #define PCSMA_OPEN 7 /* Start PPP */ 125 #define PCSMA__MAX 8 126 127 static uint8_t client_next_state[PCSMS__MAX][PCSME__MAX] = { 128 /* 0 PCSMS_DEAD Initial state */ 129 { 130 PCSMS_DEAD, /* PCSME_CLOSE User close */ 131 PCSMS_INITSENT, /* PCSME_OPEN User open */ 132 PCSMS_DEAD, /* PCSME_TOP Timeout+ */ 133 PCSMS_DEAD, /* PCSME_TOM Timeout- */ 134 PCSMS_DEAD, /* PCSME_RPADT Receive PADT */ 135 PCSMS_DEAD, /* PCSME_RPADOP Receive desired PADO */ 136 PCSMS_DEAD, /* PCSME_RPADO Receive ordinary PADO */ 137 PCSMS_DEAD, /* PCSME_RPADS Receive PADS */ 138 PCSMS_DEAD, /* PCSME_RPADSN Receive bad PADS */ 139 }, 140 /* 1 PCSMS_INITSENT PADI sent */ 141 { 142 PCSMS_DEAD, /* PCSME_CLOSE User close */ 143 PCSMS_INITSENT, /* PCSME_OPEN User open */ 144 PCSMS_INITSENT, /* PCSME_TOP Timeout+ */ 145 PCSMS_DEAD, /* PCSME_TOM Timeout- */ 146 PCSMS_DEAD, /* PCSME_RPADT Receive PADT */ 147 PCSMS_REQSENT, /* PCSME_RPADOP Receive desired PADO */ 148 PCSMS_OFFRRCVD, /* PCSME_RPADO Receive ordinary PADO */ 149 PCSMS_INITSENT, /* PCSME_RPADS Receive PADS */ 150 PCSMS_INITSENT, /* PCSME_RPADSN Receive bad PADS */ 151 }, 152 /* 2 PCSMS_OFFRRCVD PADO received */ 153 { 154 PCSMS_DEAD, /* PCSME_CLOSE User close */ 155 PCSMS_INITSENT, /* PCSME_OPEN User open */ 156 PCSMS_REQSENT, /* PCSME_TOP Timeout+ */ 157 PCSMS_REQSENT, /* PCSME_TOM Timeout- */ 158 PCSMS_DEAD, /* PCSME_RPADT Receive PADT */ 159 PCSMS_REQSENT, /* PCSME_RPADOP Receive desired PADO */ 160 PCSMS_OFFRRCVD, /* PCSME_RPADO Receive ordinary PADO */ 161 PCSMS_OFFRRCVD, /* PCSME_RPADS Receive PADS */ 162 PCSMS_OFFRRCVD, /* PCSME_RPADSN Receive bad PADS */ 163 }, 164 /* 3 PCSMS_REQSENT PADR sent */ 165 { 166 PCSMS_DEAD, /* PCSME_CLOSE User close */ 167 PCSMS_INITSENT, /* PCSME_OPEN User open */ 168 PCSMS_REQSENT, /* PCSME_TOP Timeout+ */ 169 PCSMS_REQSENT, /* PCSME_TOM Timeout- */ 170 PCSMS_DEAD, /* PCSME_RPADT Receive PADT */ 171 PCSMS_REQSENT, /* PCSME_RPADOP Receive desired PADO */ 172 PCSMS_REQSENT, /* PCSME_RPADO Receive ordinary PADO */ 173 PCSMS_CONVERS, /* PCSME_RPADS Receive PADS */ 174 PCSMS_REQSENT, /* PCSME_RPADSN Receive bad PADS */ 175 }, 176 /* 4 PCSMS_CONVERS Conversational */ 177 { 178 PCSMS_DEAD, /* PCSME_CLOSE User close */ 179 PCSMS_INITSENT, /* PCSME_OPEN User open */ 180 PCSMS_CONVERS, /* PCSME_TOP Timeout+ */ 181 PCSMS_CONVERS, /* PCSME_TOM Timeout- */ 182 PCSMS_DEAD, /* PCSME_RPADT Receive PADT */ 183 PCSMS_CONVERS, /* PCSME_RPADOP Receive desired PADO */ 184 PCSMS_CONVERS, /* PCSME_RPADO Receive ordinary PADO */ 185 PCSMS_CONVERS, /* PCSME_RPADS Receive PADS */ 186 PCSMS_CONVERS, /* PCSME_RPADSN Receive bad PADS */ 187 }, 188 }; 189 190 static uint8_t client_action[PCSMS__MAX][PCSME__MAX] = { 191 /* 0 PCSMS_DEAD Initial state */ 192 { 193 PCSMA_NONE, /* PCSME_CLOSE User close */ 194 PCSMA_SPADI, /* PCSME_OPEN User open */ 195 PCSMA_NONE, /* PCSME_TOP Timeout+ */ 196 PCSMA_NONE, /* PCSME_TOM Timeout- */ 197 PCSMA_NONE, /* PCSME_RPADT Receive PADT */ 198 PCSMA_NONE, /* PCSME_RPADOP Receive desired PADO */ 199 PCSMA_NONE, /* PCSME_RPADO Receive ordinary PADO */ 200 PCSMA_NONE, /* PCSME_RPADS Receive PADS */ 201 PCSMA_NONE, /* PCSME_RPADSN Receive bad PADS */ 202 }, 203 /* 1 PCSMS_INITSENT PADI sent */ 204 { 205 PCSMA_FAIL, /* PCSME_CLOSE User close */ 206 PCSMA_SPADI, /* PCSME_OPEN User open */ 207 PCSMA_SPADI, /* PCSME_TOP Timeout+ */ 208 PCSMA_FAIL, /* PCSME_TOM Timeout- */ 209 PCSMA_FAIL, /* PCSME_RPADT Receive PADT */ 210 PCSMA_SPADRP, /* PCSME_RPADOP Receive desired PADO */ 211 PCSMA_ADD, /* PCSME_RPADO Receive ordinary PADO */ 212 PCSMA_NONE, /* PCSME_RPADS Receive PADS */ 213 PCSMA_NONE, /* PCSME_RPADSN Receive bad PADS */ 214 }, 215 /* 2 PCSMS_OFFRRCVD PADO received */ 216 { 217 PCSMA_FAIL, /* PCSME_CLOSE User close */ 218 PCSMA_SPADI, /* PCSME_OPEN User open */ 219 PCSMA_SPADR, /* PCSME_TOP Timeout+ */ 220 PCSMA_SPADR, /* PCSME_TOM Timeout- */ 221 PCSMA_FAIL, /* PCSME_RPADT Receive PADT */ 222 PCSMA_SPADRP, /* PCSME_RPADOP Receive desired PADO */ 223 PCSMA_ADD, /* PCSME_RPADO Receive ordinary PADO */ 224 PCSMA_NONE, /* PCSME_RPADS Receive PADS */ 225 PCSMA_NONE, /* PCSME_RPADSN Receive bad PADS */ 226 }, 227 /* 3 PCSMS_REQSENT PADR sent */ 228 { 229 PCSMA_FAIL, /* PCSME_CLOSE User close */ 230 PCSMA_SPADI, /* PCSME_OPEN User open */ 231 PCSMA_SPADR, /* PCSME_TOP Timeout+ */ 232 PCSMA_SPADRN, /* PCSME_TOM Timeout- */ 233 PCSMA_FAIL, /* PCSME_RPADT Receive PADT */ 234 PCSMA_ADD, /* PCSME_RPADOP Receive desired PADO */ 235 PCSMA_ADD, /* PCSME_RPADO Receive ordinary PADO */ 236 PCSMA_OPEN, /* PCSME_RPADS Receive PADS */ 237 PCSMA_SPADRN, /* PCSME_RPADSN Receive bad PADS */ 238 }, 239 /* 4 PCSMS_CONVERS Conversational */ 240 { 241 PCSMA_FAIL, /* PCSME_CLOSE User close */ 242 PCSMA_SPADI, /* PCSME_OPEN User open */ 243 PCSMA_FAIL, /* PCSME_TOP Timeout+ */ 244 PCSMA_FAIL, /* PCSME_TOM Timeout- */ 245 PCSMA_FAIL, /* PCSME_RPADT Receive PADT */ 246 PCSMA_NONE, /* PCSME_RPADOP Receive desired PADO */ 247 PCSMA_NONE, /* PCSME_RPADO Receive ordinary PADO */ 248 PCSMA_NONE, /* PCSME_RPADS Receive PADS */ 249 PCSMA_NONE, /* PCSME_RPADSN Receive bad PADS */ 250 }, 251 }; 252 253 /* 254 * PPPoE Message structure -- holds data from a received PPPoE 255 * message. These are copied and saved when queuing offers from 256 * possible servers. 257 */ 258 typedef struct poesm_s { 259 struct poesm_s *poemsg_next; /* Next message in list */ 260 const poep_t *poemsg_data; /* Pointer to PPPoE packet */ 261 int poemsg_len; /* Length of packet */ 262 ppptun_atype poemsg_sender; /* Address of sender */ 263 const char *poemsg_iname; /* Name of input interface */ 264 } poemsg_t; 265 266 /* 267 * PPPoE State Machine structure -- holds state of PPPoE negotiation; 268 * currently, there's exactly one of these per pppoec instance. 269 */ 270 typedef struct { 271 int poesm_state; /* PCSMS_* */ 272 int poesm_timer; /* Milliseconds to next TO */ 273 int poesm_count; /* Retry countdown */ 274 int poesm_interval; /* Reload value */ 275 uint32_t poesm_sequence; /* Sequence for PADR */ 276 277 poemsg_t *poesm_firstoff; /* Queue of valid offers; */ 278 poemsg_t *poesm_lastoff; /* first is best offer */ 279 poemsg_t *poesm_tried; /* Tried and failed offers */ 280 281 int poesm_localid; /* Local session ID (driver) */ 282 } poesm_t; 283 284 /* 285 * Convert an internal PPPoE event code number into a printable 286 * string. 287 */ 288 static const char * 289 poe_event(int event) 290 { 291 static const char *poeevent[PCSME__MAX] = { 292 "Close", "Open", "TO+", "TO-", "rPADT", 293 "rPADO+", "rPADO", "rPADS", "rPADS-" 294 }; 295 296 if (event < 0 || event >= PCSME__MAX) { 297 return ("?"); 298 } 299 return (poeevent[event]); 300 } 301 302 /* 303 * Convert an internal PPPoE state number into a printable string. 304 */ 305 static const char * 306 poe_state(int state) 307 { 308 static const char *poestate[PCSMS__MAX] = { 309 "Dead", "InitSent", "OffrRcvd", "ReqSent", "Convers", 310 }; 311 312 if (state < 0 || state >= PCSMS__MAX) { 313 return ("?"); 314 } 315 return (poestate[state]); 316 } 317 318 /* 319 * Convert an internal PPPoE action number into a printable string. 320 */ 321 static const char * 322 poe_action(int act) 323 { 324 static const char *poeaction[PCSMA__MAX] = { 325 "None", "Fail", "SendPADI", "Add", "SendPADR", 326 "SendPADR+", "SendPADR-", "Open" 327 }; 328 329 if (act < 0 || act >= PCSMA__MAX) { 330 return ("?"); 331 } 332 return (poeaction[act]); 333 } 334 335 /* 336 * This calls mygetmsg (which discards partial messages as needed) and 337 * logs errors as appropriate. 338 */ 339 static int 340 pppoec_getmsg(int fd, struct strbuf *ctrl, struct strbuf *data, int *flags) 341 { 342 int retv; 343 344 for (;;) { 345 retv = mygetmsg(fd, ctrl, data, flags); 346 if (retv == 0) 347 break; 348 if (retv < 0) { 349 if (errno == EINTR) 350 continue; 351 logstrerror("getmsg"); 352 break; 353 } 354 if (verbose) { 355 if (!(retv & (MORECTL | MOREDATA))) 356 logerr("%s: discard: " 357 "unexpected status %d\n", myname, retv); 358 else 359 logerr("%s: discard: " 360 "truncated %s%smessage\n", myname, 361 retv & MORECTL ? "control " : "", 362 retv & MOREDATA ? "data " : ""); 363 } 364 } 365 return (retv); 366 } 367 368 /* 369 * Connect the control path to the lower stream of interest. This 370 * must be called after opening the tunnel driver in order to 371 * establish the interface to be used for signaling. Returns local 372 * session ID number. 373 */ 374 static int 375 set_control(const char *dname) 376 { 377 struct ppptun_peer ptp; 378 union ppptun_name ptn; 379 380 /* Fetch the local session ID first. */ 381 (void) memset(&ptp, '\0', sizeof (ptp)); 382 ptp.ptp_style = PTS_PPPOE; 383 if (strioctl(tunfd, PPPTUN_SPEER, &ptp, sizeof (ptp), sizeof (ptp)) < 384 0) { 385 logstrerror("PPPTUN_SPEER"); 386 exit(1); 387 } 388 389 /* Connect to lower stream. */ 390 (void) snprintf(ptn.ptn_name, sizeof (ptn.ptn_name), "%s:pppoed", 391 dname); 392 if (strioctl(tunfd, PPPTUN_SCTL, &ptn, sizeof (ptn), 0) < 0) { 393 logerr("%s: PPPTUN_SCTL %s: %s\n", myname, 394 ptn.ptn_name, mystrerror(errno)); 395 exit(1); 396 } 397 return (ptp.ptp_lsessid); 398 } 399 400 /* 401 * Check if standard input is actually a viable connection to the 402 * tunnel driver. This is the normal mode of operation with pppd; the 403 * tunnel driver is opened by pppd as the tty and pppoec is exec'd as 404 * the connect script. 405 */ 406 static void 407 check_stdin(void) 408 { 409 struct ppptun_info pti; 410 union ppptun_name ptn; 411 412 if (strioctl(0, PPPTUN_GDATA, &ptn, 0, sizeof (ptn)) < 0) { 413 if (errno == EINVAL) 414 logerr("%s: PPPoE operation requires " 415 "the use of a tunneling device\n", myname); 416 else 417 logstrerror("PPPTUN_GDATA"); 418 exit(1); 419 } 420 if (ptn.ptn_name[0] != '\0') { 421 if (strioctl(0, PPPTUN_GINFO, &pti, 0, sizeof (pti)) < 0) { 422 logstrerror("PPPTUN_GINFO"); 423 exit(1); 424 } 425 if (pti.pti_style != PTS_PPPOE) { 426 logerr("%s: Cannot connect to server " 427 "using PPPoE; stream already set to style %d\n", 428 myname, pti.pti_style); 429 exit(1); 430 } 431 if (verbose) 432 logerr("%s: Warning: PPPoE data link " 433 "already connected\n", myname); 434 exit(0); 435 } 436 /* Standard input is the tunnel driver; use it. */ 437 tunfd = 0; 438 } 439 440 /* 441 * Write a summary of a PPPoE message to the given file. This is used 442 * for logging and to display received offers in the inquiry (-i) mode. 443 */ 444 static void 445 display_pppoe(FILE *out, const poep_t *poep, int plen, const ppptun_atype *pap) 446 { 447 int ttyp; 448 int tlen; 449 const uint8_t *tagp; 450 const uint8_t *dp; 451 const char *str; 452 poer_t poer; 453 uint32_t mask; 454 455 if (out == stderr) 456 logerr(" "); /* Give us a timestamp */ 457 /* Print name of sender. */ 458 (void) fprintf(out, "%-16s ", ehost(pap)); 459 460 /* Loop through tags and print each. */ 461 tagp = (const uint8_t *)(poep + 1); 462 while (poe_tagcheck(poep, plen, tagp)) { 463 ttyp = POET_GET_TYPE(tagp); 464 if (ttyp == POETT_END) 465 break; 466 tlen = POET_GET_LENG(tagp); 467 dp = POET_DATA(tagp); 468 str = NULL; 469 switch (ttyp) { 470 case POETT_SERVICE: /* Service-Name */ 471 str = "Svc"; 472 break; 473 case POETT_ACCESS: /* AC-Name */ 474 str = "Name"; 475 break; 476 case POETT_UNIQ: /* Host-Uniq */ 477 str = "Uniq"; 478 break; 479 case POETT_COOKIE: /* AC-Cookie */ 480 str = "Cookie"; 481 break; 482 case POETT_VENDOR: /* Vendor-Specific */ 483 break; 484 case POETT_RELAY: /* Relay-Session-Id */ 485 str = "Relay"; 486 break; 487 case POETT_NAMERR: /* Service-Name-Error */ 488 str = "SvcNameErr"; 489 break; 490 case POETT_SYSERR: /* AC-System-Error */ 491 str = "SysErr"; 492 break; 493 case POETT_GENERR: /* Generic-Error */ 494 str = "GenErr"; 495 break; 496 case POETT_MULTI: /* Multicast-Capable */ 497 break; 498 case POETT_HURL: /* Host-URL */ 499 str = "URL"; 500 break; 501 case POETT_MOTM: /* Message-Of-The-Minute */ 502 str = "Mesg"; 503 break; 504 case POETT_RTEADD: /* IP-Route-Add */ 505 break; 506 } 507 switch (ttyp) { 508 case POETT_NAMERR: /* Service-Name-Error */ 509 case POETT_SYSERR: /* AC-System-Error */ 510 if (tlen > 0 && *dp == '\0') 511 tlen = 0; 512 /* FALLTHROUGH */ 513 case POETT_SERVICE: /* Service-Name */ 514 case POETT_ACCESS: /* AC-Name */ 515 case POETT_GENERR: /* Generic-Error */ 516 case POETT_MOTM: /* Message-Of-The-Minute */ 517 case POETT_HURL: /* Host-URL */ 518 (void) fprintf(out, "%s:\"%.*s\" ", str, tlen, dp); 519 break; 520 case POETT_UNIQ: /* Host-Uniq */ 521 case POETT_COOKIE: /* AC-Cookie */ 522 case POETT_RELAY: /* Relay-Session-Id */ 523 (void) fprintf(out, "%s:", str); 524 while (--tlen >= 0) 525 (void) fprintf(out, "%02X", *dp++); 526 (void) putc(' ', out); 527 break; 528 case POETT_VENDOR: /* Vendor-Specific */ 529 (void) fputs("Vendor:", out); 530 if (tlen >= 4) { 531 if (*dp++ != 0) { 532 (void) fprintf(out, "(%02X?)", dp[-1]); 533 } 534 (void) fprintf(out, "%x-%x-%x:", dp[0], dp[1], 535 dp[2]); 536 tlen -= 4; 537 dp += 3; 538 } 539 while (--tlen >= 0) 540 (void) fprintf(out, "%02X", *dp++); 541 (void) putc(' ', out); 542 break; 543 case POETT_MULTI: /* Multicast-Capable */ 544 (void) fprintf(out, "Multi:%d ", *dp); 545 break; 546 case POETT_RTEADD: /* IP-Route-Add */ 547 if (tlen != sizeof (poer)) { 548 (void) fprintf(out, "RTE%d? ", tlen); 549 break; 550 } 551 (void) memcpy(&poer, dp, sizeof (poer)); 552 (void) fputs("RTE:", out); 553 if (poer.poer_dest_network == 0) 554 (void) fputs("default", out); 555 else 556 (void) fputs(ihost(poer.poer_dest_network), 557 out); 558 mask = ntohl(poer.poer_subnet_mask); 559 if (mask != 0 && mask != (uint32_t)~0) { 560 if ((~mask & (~mask + 1)) == 0) 561 (void) fprintf(out, "/%d", 562 sizeof (struct in_addr) * NBBY + 563 1 - ffs(mask)); 564 else 565 (void) fprintf(out, "/%s", 566 ihost(poer.poer_subnet_mask)); 567 } 568 (void) fprintf(out, ",%s,%u ", 569 ihost(poer.poer_gateway), ntohl(poer.poer_metric)); 570 break; 571 default: 572 (void) fprintf(out, "%s:%d ", poe_tagname(ttyp), tlen); 573 break; 574 } 575 tagp = POET_NEXT(tagp); 576 } 577 (void) putc('\n', out); 578 } 579 580 /* 581 * Transmit a PPPoE message to the indicated destination. Used for 582 * PADI and PADR messages. 583 */ 584 static int 585 send_pppoe(const poep_t *poep, const char *msgname, 586 const ppptun_atype *destaddr) 587 { 588 struct strbuf ctrl; 589 struct strbuf data; 590 struct ppptun_control *ptc; 591 592 /* Set up the control data expected by the driver. */ 593 ptc = (struct ppptun_control *)pkt_octl; 594 (void) memset(ptc, '\0', sizeof (*ptc)); 595 ptc->ptc_discrim = PPPOE_DISCRIM; 596 ptc->ptc_action = PTCA_CONTROL; 597 ptc->ptc_address = *destaddr; 598 ctrl.len = sizeof (*ptc); 599 ctrl.buf = (caddr_t)ptc; 600 data.len = poe_length(poep) + sizeof (*poep); 601 data.buf = (caddr_t)poep; 602 if (verbose) 603 logerr("%s: Sending %s to %s: %d bytes\n", 604 myname, msgname, ehost(destaddr), data.len); 605 if (putmsg(tunfd, &ctrl, &data, 0) < 0) { 606 logstrerror("putmsg"); 607 return (-1); 608 } 609 return (0); 610 } 611 612 /* 613 * Create and transmit a PPPoE Active Discovery Initiation packet. 614 * This is broadcasted to all hosts on the LAN. 615 */ 616 static int 617 send_padi(int localid) 618 { 619 poep_t *poep; 620 ppptun_atype destaddr; 621 622 poep = poe_mkheader(pkt_output, POECODE_PADI, 0); 623 (void) poe_add_str(poep, POETT_SERVICE, service); 624 (void) poe_add_long(poep, POETT_UNIQ, localid); 625 (void) memset(&destaddr, '\0', sizeof (destaddr)); 626 (void) memcpy(destaddr.pta_pppoe.ptma_mac, ether_bcast, 627 sizeof (destaddr.pta_pppoe.ptma_mac)); 628 return (send_pppoe(poep, "PADI", &destaddr)); 629 } 630 631 /* 632 * This is used by the procedure below -- when the alarm goes off, 633 * just exit. (This was once a dummy procedure and used the EINTR 634 * side-effect to terminate the loop, but that's not reliable, since 635 * the EINTR could be caught and ignored by the calls to standard 636 * output.) 637 */ 638 /* ARGSUSED */ 639 static void 640 alarm_hand(int dummy) 641 { 642 exit(0); 643 } 644 645 /* 646 * Send out a single PADI and listen for servers. This implements the 647 * "inquiry" (-i) mode. 648 */ 649 static void 650 find_all_servers(int localid) 651 { 652 struct strbuf ctrl; 653 struct strbuf data; 654 poep_t *poep; 655 int flags; 656 struct sigaction act; 657 struct ppptun_control *ptc; 658 659 /* Set a default 3-second timer */ 660 (void) memset(&act, '\0', sizeof (act)); 661 act.sa_handler = alarm_hand; 662 (void) sigaction(SIGALRM, &act, NULL); 663 (void) alarm((pado_wait_time + 999) / 1000); 664 665 /* Broadcast a single request. */ 666 if (send_padi(localid) != 0) 667 return; 668 669 /* Loop over responses and print them. */ 670 for (;;) { 671 ctrl.maxlen = PKT_OCTL_LEN; 672 ctrl.buf = (caddr_t)pkt_octl; 673 data.maxlen = PKT_INPUT_LEN; 674 data.buf = (caddr_t)pkt_input; 675 flags = 0; 676 677 if (pppoec_getmsg(tunfd, &ctrl, &data, &flags) < 0) 678 break; 679 680 /* Ignore unwanted responses from the driver. */ 681 if (ctrl.len != sizeof (*ptc)) { 682 if (verbose) 683 logerr("%s: unexpected %d byte" 684 " control message from driver.\n", myname, 685 ctrl.len); 686 continue; 687 } 688 ptc = (struct ppptun_control *)pkt_octl; 689 poep = (poep_t *)pkt_input; 690 691 /* If it's an offer, then print it out. */ 692 if (poe_code(poep) == POECODE_PADO) { 693 display_pppoe(stdout, poep, data.len, 694 &ptc->ptc_address); 695 } 696 } 697 } 698 699 /* 700 * Parse a server filter from the command line. The passed-in string 701 * must be allocated and unchanged, since a pointer to it is saved in 702 * the filter data structure. The string is also parsed for a MAC 703 * address, if possible. 704 */ 705 static void 706 parse_filter(const char *str, int exceptflag) 707 { 708 struct server_filter *sfnew; 709 const char *cp; 710 const char *wordstart; 711 const char *wordend; 712 int len; 713 char hbuf[MAXHOSTNAMELEN]; 714 uchar_t *ucp; 715 uchar_t *mcp; 716 717 /* Allocate the new filter structure. */ 718 sfnew = (struct server_filter *)calloc(1, sizeof (*sfnew)); 719 if (sfnew == NULL) { 720 logstrerror("filter allocation"); 721 exit(1); 722 } 723 724 /* Save the string for AC-Name comparison. */ 725 sfnew->sf_name = str; 726 727 sfnew->sf_isexcept = exceptflag == 0 ? 0 : 1; 728 729 /* Extract just one word. */ 730 cp = str; 731 while (isspace(*cp)) 732 cp++; 733 wordstart = cp; 734 while (*cp != '\0' && !isspace(*cp)) 735 cp++; 736 wordend = cp; 737 if ((len = wordend - wordstart) >= sizeof (hbuf)) 738 len = sizeof (hbuf) - 1; 739 (void) strlcpy(hbuf, wordstart, len); 740 hbuf[len] = '\0'; 741 742 /* Try to translate this as an Ethernet host or address. */ 743 mcp = sfnew->sf_mask.ether_addr_octet; 744 if (ether_hostton(hbuf, &sfnew->sf_mac) == 0) { 745 mcp[0] = mcp[1] = mcp[2] = mcp[3] = mcp[4] = mcp[5] = 0xFF; 746 sfnew->sf_hasmac = 1; 747 } else { 748 ucp = sfnew->sf_mac.ether_addr_octet; 749 len = wordend - wordstart; 750 cp = wordstart; 751 while (cp < wordend) { 752 if (ucp >= sfnew->sf_mac.ether_addr_octet + 753 sizeof (sfnew->sf_mac)) 754 break; 755 if (*cp == '*') { 756 *mcp++ = *ucp++ = 0; 757 cp++; 758 } else { 759 if (!isxdigit(*cp)) 760 break; 761 *ucp = hexdecode(*cp++); 762 if (cp < wordend && isxdigit(*cp)) { 763 *ucp = (*ucp << 4) | 764 hexdecode(*cp++); 765 } 766 ucp++; 767 *mcp++ = 0xFF; 768 } 769 if (cp < wordend) { 770 if (*cp != ':' || cp + 1 == wordend) 771 break; 772 cp++; 773 } 774 } 775 if (cp >= wordend) 776 sfnew->sf_hasmac = 1; 777 else if (verbose) 778 logerr("%s: treating '%.*s' as server " 779 "name only, not MAC address\n", myname, len, 780 wordstart); 781 } 782 783 /* Add to end of list. */ 784 if (sftail == NULL) 785 sfhead = sfnew; 786 else 787 sftail->sf_next = sfnew; 788 sftail = sfnew; 789 } 790 791 /* 792 * Create a copy of a given PPPoE message. This is used for enqueuing 793 * received PADO (offers) from possible servers. 794 */ 795 static poemsg_t * 796 save_message(const poemsg_t *pmsg) 797 { 798 poemsg_t *newmsg; 799 char *cp; 800 801 newmsg = (poemsg_t *)malloc(sizeof (*pmsg) + pmsg->poemsg_len + 802 strlen(pmsg->poemsg_iname) + 1); 803 if (newmsg != NULL) { 804 newmsg->poemsg_next = NULL; 805 newmsg->poemsg_data = (const poep_t *)(newmsg + 1); 806 (void) memcpy(newmsg + 1, pmsg->poemsg_data, pmsg->poemsg_len); 807 newmsg->poemsg_len = pmsg->poemsg_len; 808 cp = (char *)newmsg->poemsg_data + pmsg->poemsg_len; 809 newmsg->poemsg_iname = (const char *)cp; 810 (void) strcpy(cp, pmsg->poemsg_iname); 811 (void) memcpy(&newmsg->poemsg_sender, &pmsg->poemsg_sender, 812 sizeof (newmsg->poemsg_sender)); 813 } 814 return (newmsg); 815 } 816 817 /* 818 * Create and send a PPPoE Active Discovery Request (PADR) message to 819 * the sender of the given PADO. Some tags -- Service-Name, 820 * AC-Cookie, and Relay-Session-Id -- must be copied from PADO to 821 * PADR. Others are not. The Service-Name must be selected from the 822 * offered services in the PADO based on the user's requested service 823 * name. If the server offered "wildcard" service, then we ask for 824 * this only if we can't find the user's requested service. 825 * 826 * Returns 1 if we can't send a valid PADR in response to the given 827 * PADO. The offer should be ignored and the next one tried. 828 */ 829 static int 830 send_padr(poesm_t *psm, const poemsg_t *pado) 831 { 832 poep_t *poep; 833 boolean_t haswild; 834 boolean_t hassvc; 835 const uint8_t *tagp; 836 int ttyp; 837 int tlen; 838 839 /* 840 * Increment sequence number for PADR so that we don't mistake 841 * old replies for valid ones if the server is very slow. 842 */ 843 psm->poesm_sequence++; 844 845 poep = poe_mkheader(pkt_output, POECODE_PADR, 0); 846 (void) poe_two_longs(poep, POETT_UNIQ, psm->poesm_localid, 847 psm->poesm_sequence); 848 849 haswild = B_FALSE; 850 hassvc = B_FALSE; 851 tagp = (const uint8_t *)(pado->poemsg_data + 1); 852 while (poe_tagcheck(pado->poemsg_data, pado->poemsg_len, tagp)) { 853 ttyp = POET_GET_TYPE(tagp); 854 if (ttyp == POETT_END) 855 break; 856 tlen = POET_GET_LENG(tagp); 857 switch (ttyp) { 858 case POETT_SERVICE: /* Service-Name */ 859 /* Allow only one */ 860 if (hassvc) 861 break; 862 if (tlen == 0) { 863 haswild = B_TRUE; 864 break; 865 } 866 if (service[0] == '\0' || 867 (tlen == strlen(service) && 868 memcmp(service, POET_DATA(tagp), tlen) == 0)) { 869 (void) poe_tag_copy(poep, tagp); 870 hassvc = B_TRUE; 871 } 872 break; 873 /* Ones we should discard */ 874 case POETT_ACCESS: /* AC-Name */ 875 case POETT_UNIQ: /* Host-Uniq */ 876 case POETT_NAMERR: /* Service-Name-Error */ 877 case POETT_SYSERR: /* AC-System-Error */ 878 case POETT_GENERR: /* Generic-Error */ 879 case POETT_HURL: /* Host-URL */ 880 case POETT_MOTM: /* Message-Of-The-Minute */ 881 case POETT_RTEADD: /* IP-Route-Add */ 882 case POETT_VENDOR: /* Vendor-Specific */ 883 case POETT_MULTI: /* Multicast-Capable */ 884 default: /* Anything else we don't understand */ 885 break; 886 /* Ones we should copy */ 887 case POETT_COOKIE: /* AC-Cookie */ 888 case POETT_RELAY: /* Relay-Session-Id */ 889 (void) poe_tag_copy(poep, tagp); 890 break; 891 } 892 tagp = POET_NEXT(tagp); 893 } 894 if (!hassvc) { 895 if (haswild && service[0] == '\0') 896 (void) poe_add_str(poep, POETT_SERVICE, ""); 897 else 898 return (1); 899 } 900 901 return (send_pppoe(poep, "PADR", &pado->poemsg_sender)); 902 } 903 904 /* 905 * ******************************************************************** 906 * act_* functions implement the actions driven by the state machine 907 * tables. See "action_table" below. 908 * 909 * All action routines must return the next state value. 910 * ******************************************************************** 911 */ 912 913 /* ARGSUSED */ 914 static int 915 act_none(poesm_t *psm, poemsg_t *pmsg, int event, int nextst) 916 { 917 return (nextst); 918 } 919 920 /* ARGSUSED */ 921 static int 922 act_fail(poesm_t *psm, poemsg_t *pmsg, int event, int nextst) 923 { 924 if (verbose) 925 logerr("%s: unrecoverable error\n", myname); 926 return (PCSMS_DEAD); 927 } 928 929 /* ARGSUSED */ 930 static int 931 act_spadi(poesm_t *psm, poemsg_t *pmsg, int event, int nextst) 932 { 933 if (send_padi(psm->poesm_localid) != 0) 934 return (PCSMS_DEAD); 935 /* 936 * If this is the first time, then initialize the retry count 937 * and interval. 938 */ 939 if (psm->poesm_state == PCSMS_DEAD) { 940 psm->poesm_count = 3; 941 psm->poesm_interval = pado_wait_time; 942 } else { 943 if ((psm->poesm_interval <<= 1) > RESTART_LIMIT) 944 psm->poesm_interval = RESTART_LIMIT; 945 } 946 psm->poesm_timer = psm->poesm_interval; 947 (void) gettimeofday(&tvstart, NULL); 948 return (nextst); 949 } 950 951 /* ARGSUSED */ 952 static int 953 act_add(poesm_t *psm, poemsg_t *pmsg, int event, int nextst) 954 { 955 pmsg = save_message(pmsg); 956 if (pmsg != NULL) { 957 if (psm->poesm_lastoff == NULL) 958 psm->poesm_firstoff = pmsg; 959 else 960 psm->poesm_lastoff->poemsg_next = pmsg; 961 psm->poesm_lastoff = pmsg; 962 } 963 return (nextst); 964 } 965 966 /* ARGSUSED */ 967 static int 968 act_spadr(poesm_t *psm, poemsg_t *pmsg, int event, int nextst) 969 { 970 poemsg_t *msgp; 971 int retv; 972 973 for (;;) { 974 if ((msgp = psm->poesm_firstoff) == NULL) 975 return (PCSMS_DEAD); 976 retv = send_padr(psm, msgp); 977 if (retv < 0) 978 return (PCSMS_DEAD); 979 if (retv == 0) 980 break; 981 /* Can't send this request; try looking at next offer. */ 982 psm->poesm_firstoff = msgp->poemsg_next; 983 msgp->poemsg_next = psm->poesm_tried; 984 psm->poesm_tried = msgp; 985 } 986 if (psm->poesm_state != PCSMS_REQSENT) { 987 psm->poesm_count = 3; 988 psm->poesm_interval = pads_wait_time; 989 } else { 990 if ((psm->poesm_interval <<= 1) > RESTART_LIMIT) 991 psm->poesm_interval = RESTART_LIMIT; 992 } 993 psm->poesm_timer = psm->poesm_interval; 994 (void) gettimeofday(&tvstart, NULL); 995 return (nextst); 996 } 997 998 /* ARGSUSED */ 999 static int 1000 act_spadrp(poesm_t *psm, poemsg_t *pmsg, int event, int nextst) 1001 { 1002 int retv; 1003 1004 retv = send_padr(psm, pmsg); 1005 if (retv < 0) 1006 return (PCSMS_DEAD); 1007 pmsg = save_message(pmsg); 1008 if (retv > 0) { 1009 /* 1010 * Cannot use this one; mark as tried and continue as 1011 * if we never saw it. 1012 */ 1013 pmsg->poemsg_next = psm->poesm_tried; 1014 psm->poesm_tried = pmsg; 1015 return (psm->poesm_state); 1016 } 1017 pmsg->poemsg_next = psm->poesm_firstoff; 1018 psm->poesm_firstoff = pmsg; 1019 if (psm->poesm_lastoff == NULL) 1020 psm->poesm_lastoff = pmsg; 1021 psm->poesm_count = 3; 1022 psm->poesm_timer = psm->poesm_interval = pads_wait_time; 1023 (void) gettimeofday(&tvstart, NULL); 1024 return (nextst); 1025 } 1026 1027 /* ARGSUSED */ 1028 static int 1029 act_spadrn(poesm_t *psm, poemsg_t *pmsg, int event, int nextst) 1030 { 1031 poemsg_t *msgp; 1032 int retv; 1033 1034 if ((msgp = psm->poesm_firstoff) == NULL) 1035 return (PCSMS_DEAD); 1036 do { 1037 psm->poesm_firstoff = msgp->poemsg_next; 1038 msgp->poemsg_next = psm->poesm_tried; 1039 psm->poesm_tried = msgp; 1040 if ((msgp = psm->poesm_firstoff) == NULL) 1041 return (PCSMS_DEAD); 1042 retv = send_padr(psm, msgp); 1043 if (retv < 0) 1044 return (PCSMS_DEAD); 1045 } while (retv != 0); 1046 psm->poesm_count = 3; 1047 psm->poesm_timer = psm->poesm_interval = pads_wait_time; 1048 (void) gettimeofday(&tvstart, NULL); 1049 return (nextst); 1050 } 1051 1052 /* 1053 * For safety -- remove end of line from strings passed back to pppd. 1054 */ 1055 static void 1056 remove_eol(char *str, size_t len) 1057 { 1058 while (len > 0) { 1059 if (*str == '\n') 1060 *str = '$'; 1061 str++; 1062 len--; 1063 } 1064 } 1065 1066 /* ARGSUSED */ 1067 static int 1068 act_open(poesm_t *psm, poemsg_t *pmsg, int event, int nextst) 1069 { 1070 struct ppptun_peer ptp; 1071 union ppptun_name ptn; 1072 const char *cp; 1073 FILE *fp; 1074 const uint8_t *tagp, *vp; 1075 int tlen, ttyp; 1076 char *access; 1077 uint32_t val; 1078 size_t acc_len, serv_len; 1079 1080 /* 1081 * The server has now assigned its session ID for the data 1082 * (PPP) portion of this tunnel. Send that ID down to the 1083 * driver. 1084 */ 1085 (void) memset(&ptp, '\0', sizeof (ptp)); 1086 ptp.ptp_lsessid = psm->poesm_localid; 1087 ptp.ptp_rsessid = poe_session_id(pmsg->poemsg_data); 1088 (void) memcpy(&ptp.ptp_address, &pmsg->poemsg_sender, 1089 sizeof (ptp.ptp_address)); 1090 ptp.ptp_style = PTS_PPPOE; 1091 if (strioctl(tunfd, PPPTUN_SPEER, &ptp, sizeof (ptp), sizeof (ptp)) < 1092 0) { 1093 logstrerror("PPPTUN_SPEER"); 1094 return (PCSMS_DEAD); 1095 } 1096 1097 /* 1098 * Data communication is now possible on this session. 1099 * Connect the data portion to the correct lower stream. 1100 */ 1101 if ((cp = strchr(pmsg->poemsg_iname, ':')) == NULL) 1102 cp = pmsg->poemsg_iname + strlen(pmsg->poemsg_iname); 1103 (void) snprintf(ptn.ptn_name, sizeof (ptn.ptn_name), "%.*s:pppoe", 1104 cp - pmsg->poemsg_iname, pmsg->poemsg_iname); 1105 if (strioctl(tunfd, PPPTUN_SDATA, &ptn, sizeof (ptn), 0) < 0) { 1106 logerr("%s: PPPTUN_SDATA %s: %s\n", 1107 myname, ptn.ptn_name, mystrerror(errno)); 1108 return (PCSMS_DEAD); 1109 } 1110 if (verbose) 1111 logerr("%s: Connection open; session %04X on " 1112 "%s\n", myname, ptp.ptp_rsessid, ptn.ptn_name); 1113 1114 /* 1115 * Walk through the PADS message to get the access server name 1116 * and the service. If there are multiple instances of either 1117 * tag, then take the last access server and the first 1118 * non-null service. 1119 */ 1120 access = ""; 1121 acc_len = 0; 1122 serv_len = strlen(service); 1123 tagp = (const uint8_t *)(pmsg->poemsg_data + 1); 1124 while (poe_tagcheck(pmsg->poemsg_data, pmsg->poemsg_len, tagp)) { 1125 ttyp = POET_GET_TYPE(tagp); 1126 if (ttyp == POETT_END) 1127 break; 1128 tlen = POET_GET_LENG(tagp); 1129 if (ttyp == POETT_ACCESS) { 1130 access = (char *)POET_DATA(tagp); 1131 acc_len = tlen; 1132 } 1133 if (serv_len == 0 && ttyp == POETT_SERVICE && tlen != 0) { 1134 service = (char *)POET_DATA(tagp); 1135 serv_len = tlen; 1136 } 1137 tagp = POET_NEXT(tagp); 1138 } 1139 1140 /* 1141 * Remove end of line to make sure that integrity of values 1142 * passed back to pppd can't be compromised by the PPPoE 1143 * server. 1144 */ 1145 remove_eol(service, serv_len); 1146 remove_eol(access, acc_len); 1147 1148 /* 1149 * pppd has given us a pipe as fd 3, and we're expected to 1150 * write out the values of the following environment 1151 * variables: 1152 * IF_AND_SERVICE 1153 * SERVICE_NAME 1154 * AC_NAME 1155 * AC_MAC 1156 * SESSION_ID 1157 * VENDOR_SPECIFIC_1 ... N 1158 * See usr.bin/pppd/plugins/pppoe.c for more information. 1159 */ 1160 if ((fp = fdopen(3, "w")) != NULL) { 1161 (void) fprintf(fp, "%.*s:%.*s\n", 1162 cp - pmsg->poemsg_iname, pmsg->poemsg_iname, serv_len, 1163 service); 1164 (void) fprintf(fp, "%.*s\n", serv_len, service); 1165 (void) fprintf(fp, "%.*s\n", acc_len, access); 1166 (void) fprintf(fp, "%s\n", ehost(&pmsg->poemsg_sender)); 1167 (void) fprintf(fp, "%d\n", poe_session_id(pmsg->poemsg_data)); 1168 tagp = (const uint8_t *)(pmsg->poemsg_data + 1); 1169 while (poe_tagcheck(pmsg->poemsg_data, pmsg->poemsg_len, 1170 tagp)) { 1171 ttyp = POET_GET_TYPE(tagp); 1172 if (ttyp == POETT_END) 1173 break; 1174 tlen = POET_GET_LENG(tagp); 1175 if (ttyp == POETT_VENDOR && tlen >= 4) { 1176 (void) memcpy(&val, POET_DATA(tagp), 4); 1177 (void) fprintf(fp, "%08lX:", 1178 (unsigned long)ntohl(val)); 1179 tlen -= 4; 1180 vp = POET_DATA(tagp) + 4; 1181 while (--tlen >= 0) 1182 (void) fprintf(fp, "%02X", *vp++); 1183 (void) putc('\n', fp); 1184 } 1185 tagp = POET_NEXT(tagp); 1186 } 1187 (void) fclose(fp); 1188 } 1189 1190 return (nextst); 1191 } 1192 1193 static int (* const action_table[PCSMA__MAX])(poesm_t *psm, poemsg_t *pmsg, 1194 int event, int nextst) = { 1195 act_none, act_fail, act_spadi, act_add, act_spadr, act_spadrp, 1196 act_spadrn, act_open 1197 }; 1198 1199 /* 1200 * Dispatch an event and a corresponding message on a given state 1201 * machine. 1202 */ 1203 static void 1204 handle_event(poesm_t *psm, int event, poemsg_t *pmsg) 1205 { 1206 int nextst; 1207 1208 if (verbose) 1209 logerr("%s: PPPoE Event %s (%d) in state %s " 1210 "(%d): action %s (%d)\n", myname, poe_event(event), event, 1211 poe_state(psm->poesm_state), psm->poesm_state, 1212 poe_action(client_action[psm->poesm_state][event]), 1213 client_action[psm->poesm_state][event]); 1214 1215 nextst = (*action_table[client_action[psm->poesm_state][event]])(psm, 1216 pmsg, event, client_next_state[psm->poesm_state][event]); 1217 1218 if (verbose) 1219 logerr("%s: PPPoE State change %s (%d) -> %s (%d)\n", myname, 1220 poe_state(psm->poesm_state), psm->poesm_state, 1221 poe_state(nextst), nextst); 1222 1223 psm->poesm_state = nextst; 1224 1225 /* 1226 * Life-altering states are handled here. If we reach dead 1227 * state again after starting, then we failed. If we reach 1228 * conversational state, then we're open. 1229 */ 1230 if (nextst == PCSMS_DEAD) { 1231 if (verbose) 1232 logerr("%s: action failed\n", myname); 1233 exit(1); 1234 } 1235 if (nextst == PCSMS_CONVERS) { 1236 if (verbose) 1237 logerr("%s: connected\n", myname); 1238 exit(0); 1239 } 1240 } 1241 1242 /* 1243 * Check for error message tags in the PPPoE packet. We must ignore 1244 * offers that merely report errors, and need to log errors in any 1245 * case. 1246 */ 1247 static int 1248 error_check(poemsg_t *pmsg) 1249 { 1250 const uint8_t *tagp; 1251 int ttyp; 1252 1253 tagp = (const uint8_t *)(pmsg->poemsg_data + 1); 1254 while (poe_tagcheck(pmsg->poemsg_data, pmsg->poemsg_len, tagp)) { 1255 ttyp = POET_GET_TYPE(tagp); 1256 if (ttyp == POETT_END) 1257 break; 1258 if (ttyp == POETT_NAMERR || ttyp == POETT_SYSERR || 1259 ttyp == POETT_GENERR) { 1260 if (verbose) 1261 display_pppoe(stderr, pmsg->poemsg_data, 1262 pmsg->poemsg_len, &pmsg->poemsg_sender); 1263 return (-1); 1264 } 1265 tagp = POET_NEXT(tagp); 1266 } 1267 return (0); 1268 } 1269 1270 /* 1271 * Extract sequence number, if any, from PADS message, so that we can 1272 * relate it to the PADR that we sent. 1273 */ 1274 static uint32_t 1275 get_sequence(const poemsg_t *pmsg) 1276 { 1277 const uint8_t *tagp; 1278 int ttyp; 1279 uint32_t vals[2]; 1280 1281 tagp = (const uint8_t *)(pmsg->poemsg_data + 1); 1282 while (poe_tagcheck(pmsg->poemsg_data, pmsg->poemsg_len, tagp)) { 1283 ttyp = POET_GET_TYPE(tagp); 1284 if (ttyp == POETT_END) 1285 break; 1286 if (ttyp == POETT_UNIQ) { 1287 if (POET_GET_LENG(tagp) < sizeof (vals)) 1288 break; 1289 (void) memcpy(vals, POET_DATA(tagp), sizeof (vals)); 1290 return (ntohl(vals[1])); 1291 } 1292 tagp = POET_NEXT(tagp); 1293 } 1294 return (0); 1295 } 1296 1297 /* 1298 * Server filter cases: 1299 * 1300 * No filters -- all servers generate RPADO+ event; select the 1301 * first responding server. 1302 * 1303 * Only "except" filters -- matching servers are RPADO, others 1304 * are RPADO+. 1305 * 1306 * Mix of filters -- those matching "pass" are RPADO+, those 1307 * matching "except" are RPADO, and all others are also RPADO. 1308 * 1309 * If the "only" keyword was given, then RPADO becomes -1; only RPADO+ 1310 * events occur. 1311 */ 1312 static int 1313 use_server(poemsg_t *pado, const ppptun_atype *pap) 1314 { 1315 struct server_filter *sfp; 1316 const uchar_t *sndp; 1317 const uchar_t *macp; 1318 const uchar_t *maskp; 1319 int i; 1320 int passmatched; 1321 int tlen; 1322 const uint8_t *tagp; 1323 int ttyp; 1324 1325 /* 1326 * If no service mentioned in offer, then we can't use it. 1327 */ 1328 tagp = (const uint8_t *)(pado->poemsg_data + 1); 1329 ttyp = POETT_END; 1330 while (poe_tagcheck(pado->poemsg_data, pado->poemsg_len, tagp)) { 1331 ttyp = POET_GET_TYPE(tagp); 1332 if (ttyp == POETT_END) 1333 break; 1334 if (ttyp == POETT_SERVICE) { 1335 /* 1336 * If the user has requested a specific service, then 1337 * this selection is exclusive. We never use the 1338 * wildcard for this. 1339 */ 1340 tlen = POET_GET_LENG(tagp); 1341 if (service[0] == '\0' || (strlen(service) == tlen && 1342 memcmp(service, POET_DATA(tagp), tlen) == 0)) 1343 break; 1344 /* just in case we run off the end */ 1345 ttyp = POETT_END; 1346 } 1347 tagp = POET_NEXT(tagp); 1348 } 1349 if (ttyp != POETT_SERVICE) { 1350 if (verbose) 1351 logerr("%s: Discard unusable offer from %s; service " 1352 "'%s' not seen\n", myname, ehost(pap), service); 1353 return (-1); 1354 } 1355 1356 passmatched = 0; 1357 for (sfp = sfhead; sfp != NULL; sfp = sfp->sf_next) { 1358 passmatched |= !sfp->sf_isexcept; 1359 if (sfp->sf_hasmac) { 1360 sndp = pado->poemsg_sender.pta_pppoe.ptma_mac; 1361 macp = sfp->sf_mac.ether_addr_octet; 1362 maskp = sfp->sf_mask.ether_addr_octet; 1363 i = sizeof (pado->poemsg_sender.pta_pppoe.ptma_mac); 1364 for (; i > 0; i--) 1365 if (((*macp++ ^ *sndp++) & *maskp++) != 0) 1366 break; 1367 if (i <= 0) 1368 break; 1369 } 1370 } 1371 1372 if (sfp == NULL) { 1373 /* 1374 * No match encountered; if only exclude rules have 1375 * been seen, then accept this offer. 1376 */ 1377 if (!passmatched) 1378 return (PCSME_RPADOP); 1379 } else { 1380 if (!sfp->sf_isexcept) 1381 return (PCSME_RPADOP); 1382 } 1383 if (onlyflag) { 1384 if (verbose) 1385 logerr("%s: Discard unusable offer from %s; server not " 1386 "matched\n", myname, ehost(pap)); 1387 return (-1); 1388 } 1389 return (PCSME_RPADO); 1390 } 1391 1392 /* 1393 * This is the normal event loop. It initializes the state machine 1394 * and sends in an Open event to kick things off. Then it drops into 1395 * a loop to dispatch events for the state machine. 1396 */ 1397 static void 1398 find_server(int localid) 1399 { 1400 poesm_t psm; 1401 struct pollfd pfd[1]; 1402 struct timeval tv, tvnow; 1403 int retv; 1404 poemsg_t pmsg; 1405 struct strbuf ctrl; 1406 struct strbuf data; 1407 poep_t *poep; 1408 int flags; 1409 uint32_t seqval; 1410 struct ppptun_control *ptc; 1411 1412 (void) memset(&psm, '\0', sizeof (psm)); 1413 1414 /* 1415 * Initialize the sequence number with something handy. It 1416 * doesn't need to be absolutely unique, since the localid 1417 * value actually demultiplexes everything. This just makes 1418 * the operation a little safer. 1419 */ 1420 psm.poesm_sequence = getpid() << 16; 1421 psm.poesm_localid = localid; 1422 1423 /* Start the state machine */ 1424 handle_event(&psm, PCSME_OPEN, NULL); 1425 1426 /* Enter event polling loop. */ 1427 pfd[0].fd = tunfd; 1428 pfd[0].events = POLLIN; 1429 for (;;) { 1430 /* Wait for timeout or message */ 1431 retv = poll(pfd, 1, psm.poesm_timer > 0 ? psm.poesm_timer : 1432 INFTIM); 1433 if (retv < 0) { 1434 logstrerror("poll"); 1435 break; 1436 } 1437 1438 /* Handle a timeout */ 1439 if (retv == 0) { 1440 psm.poesm_timer = 0; 1441 handle_event(&psm, --psm.poesm_count > 0 ? PCSME_TOP : 1442 PCSME_TOM, NULL); 1443 continue; 1444 } 1445 1446 /* Adjust the timer for the time we slept. */ 1447 if (psm.poesm_timer > 0) { 1448 (void) gettimeofday(&tvnow, NULL); 1449 tv = tvnow; 1450 if ((tv.tv_sec -= tvstart.tv_sec) < 0) { 1451 /* Darn */ 1452 tv.tv_sec = 1; 1453 tv.tv_usec = 0; 1454 } else if ((tv.tv_usec -= tvstart.tv_usec) < 0) { 1455 tv.tv_usec += 1000000; 1456 if (--tv.tv_sec < 0) 1457 tv.tv_sec = 0; 1458 } 1459 psm.poesm_timer -= tv.tv_sec*1000 + tv.tv_usec/1000; 1460 tvstart = tvnow; 1461 } 1462 1463 /* Read in the message from the server. */ 1464 ctrl.maxlen = PKT_OCTL_LEN; 1465 ctrl.buf = (caddr_t)pkt_octl; 1466 data.maxlen = PKT_INPUT_LEN; 1467 data.buf = (caddr_t)pkt_input; 1468 flags = 0; 1469 1470 if (pppoec_getmsg(tunfd, &ctrl, &data, &flags) < 0) 1471 break; 1472 1473 if (ctrl.len != sizeof (*ptc)) { 1474 if (verbose) 1475 logerr("%s: discard: ctrl len %d\n", myname, 1476 ctrl.len); 1477 continue; 1478 } 1479 poep = (poep_t *)pkt_input; 1480 (void) memset(&pmsg, '\0', sizeof (pmsg)); 1481 pmsg.poemsg_next = NULL; 1482 pmsg.poemsg_data = poep; 1483 pmsg.poemsg_len = data.len; 1484 ptc = (struct ppptun_control *)pkt_octl; 1485 if (ptc->ptc_action != PTCA_CONTROL) { 1486 if (verbose) 1487 logerr("%s: discard: unexpected action %d\n", 1488 myname, ptc->ptc_action); 1489 continue; 1490 } 1491 pmsg.poemsg_iname = ptc->ptc_name; 1492 if (verbose) 1493 logerr("%s: Received %s from %s/%s\n", 1494 myname, poe_codename(poep->poep_code), 1495 ehost(&ptc->ptc_address), pmsg.poemsg_iname); 1496 pmsg.poemsg_sender = ptc->ptc_address; 1497 1498 /* Check for messages from unexpected peers. */ 1499 if ((poep->poep_code == POECODE_PADT || 1500 poep->poep_code == POECODE_PADS) && 1501 (psm.poesm_firstoff == NULL || 1502 memcmp(&psm.poesm_firstoff->poemsg_sender, 1503 &pmsg.poemsg_sender, sizeof (pmsg.poemsg_sender)) != 0)) { 1504 if (verbose) { 1505 logerr("%s: Unexpected peer %s", myname, 1506 ehost(&ptc->ptc_address)); 1507 logerr(" != %s\n", 1508 ehost(&psm.poesm_firstoff->poemsg_sender)); 1509 } 1510 continue; 1511 } 1512 1513 /* Eliminate stale PADS responses. */ 1514 if (poep->poep_code == POECODE_PADS) { 1515 seqval = get_sequence(&pmsg); 1516 if (seqval != psm.poesm_sequence) { 1517 if (verbose) { 1518 if (seqval == 0) 1519 logerr( 1520 "%s: PADS has no sequence " 1521 "number.\n", myname); 1522 else 1523 logerr( 1524 "%s: PADS has sequence " 1525 "%08X instead of %08X.\n", 1526 myname, seqval, 1527 psm.poesm_sequence); 1528 } 1529 continue; 1530 } 1531 } 1532 1533 /* Dispatch message event. */ 1534 retv = error_check(&pmsg); 1535 switch (poep->poep_code) { 1536 case POECODE_PADT: 1537 handle_event(&psm, PCSME_RPADT, &pmsg); 1538 break; 1539 case POECODE_PADS: 1540 /* 1541 * Got a PPPoE Active Discovery Session- 1542 * confirmation message. It's a PADS event if 1543 * everything's in order. It's a PADS- event 1544 * if the message is merely reporting an 1545 * error. 1546 */ 1547 handle_event(&psm, retv != 0 ? PCSME_RPADSN : 1548 PCSME_RPADS, &pmsg); 1549 break; 1550 case POECODE_PADO: 1551 /* Ignore offers that merely report errors. */ 1552 if (retv != 0) 1553 break; 1554 /* Ignore offers from servers we don't want. */ 1555 if ((retv = use_server(&pmsg, &ptc->ptc_address)) < 0) 1556 break; 1557 /* Dispatch either RPADO or RAPDO+ event. */ 1558 handle_event(&psm, retv, &pmsg); 1559 break; 1560 1561 default: 1562 if (verbose) 1563 logerr("%s: Unexpected code %s (%d)\n", myname, 1564 poe_codename(poep->poep_code), 1565 poep->poep_code); 1566 break; 1567 } 1568 } 1569 exit(1); 1570 } 1571 1572 static void 1573 usage(void) 1574 { 1575 logerr("Usage:\n" 1576 "\t%s [-os#] [-v] <dev> [<service> [<server> [only]]]\n\n" 1577 " or\n\n" 1578 "\t%s [-o#] [-v] -i <dev>\n", myname, myname); 1579 exit(1); 1580 } 1581 1582 /* 1583 * In addition to the usual 0-2 file descriptors, pppd will leave fd 3 1584 * open on a pipe to receive the environment variables. See 1585 * pppoe_device_pipe() in pppd/plugins/pppoe.c and device_pipe_hook in 1586 * pppd/main.c. 1587 */ 1588 int 1589 main(int argc, char **argv) 1590 { 1591 int inquiry_mode, exceptflag, arg, localid; 1592 char *cp; 1593 1594 log_to_stderr(LOGLVL_DBG); 1595 1596 if ((myname = *argv) == NULL) 1597 myname = "pppoec"; 1598 1599 inquiry_mode = 0; 1600 while ((arg = getopt(argc, argv, "io:s:v")) != EOF) 1601 switch (arg) { 1602 case 'i': 1603 inquiry_mode++; 1604 break; 1605 case 'v': 1606 verbose++; 1607 break; 1608 case 'o': 1609 pado_wait_time = strtol(optarg, &cp, 0); 1610 if (pado_wait_time <= 0 || *cp != '\0' || 1611 cp == optarg) { 1612 logerr("%s: illegal PADO wait time: %s\n", 1613 myname, optarg); 1614 exit(1); 1615 } 1616 break; 1617 case 's': 1618 pads_wait_time = strtol(optarg, &cp, 0); 1619 if (pads_wait_time <= 0 || *cp != '\0' || 1620 cp == optarg) { 1621 logerr("%s: illegal PADS wait time: %s\n", 1622 myname, optarg); 1623 exit(1); 1624 } 1625 break; 1626 case '?': 1627 usage(); 1628 } 1629 1630 /* Handle inquiry mode. */ 1631 if (inquiry_mode) { 1632 if (optind != argc-1) 1633 usage(); 1634 if (pado_wait_time == 0) 1635 pado_wait_time = PADI_INQUIRY_DWELL; 1636 1637 /* Invoked by user; open the tunnel driver myself. */ 1638 tunfd = open(tunnam, O_RDWR | O_NOCTTY); 1639 if (tunfd == -1) { 1640 logstrerror(tunnam); 1641 exit(1); 1642 } 1643 1644 /* 1645 * Set up the control stream for PPPoE negotiation 1646 * (set_control), then broadcast a query for all servers 1647 * and listen for replies (find_all_servers). 1648 */ 1649 find_all_servers(set_control(argv[optind])); 1650 return (0); 1651 } 1652 1653 if (pado_wait_time == 0) 1654 pado_wait_time = PADI_RESTART_TIME; 1655 1656 if (optind >= argc) 1657 usage(); 1658 1659 /* Make sure we've got a usable tunnel driver on stdin. */ 1660 check_stdin(); 1661 1662 /* Set up the control stream for PPPoE negotiation. */ 1663 localid = set_control(argv[optind++]); 1664 1665 /* Pick the service, if any. */ 1666 if (optind < argc) 1667 service = argv[optind++]; 1668 1669 /* Parse out the filters. */ 1670 if (optind < argc) { 1671 if (strcasecmp(argv[argc - 1], "only") == 0) { 1672 argc--; 1673 onlyflag = 1; 1674 } 1675 exceptflag = 0; 1676 for (; optind < argc; optind++) { 1677 if (!exceptflag && 1678 strcasecmp(argv[optind], "except") == 0) { 1679 exceptflag = 1; 1680 } else { 1681 parse_filter(argv[optind], exceptflag); 1682 exceptflag = 0; 1683 } 1684 } 1685 } 1686 1687 /* Enter the main loop. */ 1688 find_server(localid); 1689 1690 return (0); 1691 } 1692