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.
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.
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]
22 * PPPoE Client-mode "chat" utility for use with Solaris PPP 4.0.
24 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
25 * Use is subject to license terms.
38 #include <sys/types.h>
39 #include <sys/socket.h>
41 #include <netinet/in.h>
42 #include <netinet/if_ether.h>
44 #include <net/sppptun.h>
45 #include <net/pppoe.h>
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.
56 #define PPPOE_DISCRIM 0x504F4531
58 /* milliseconds between retries */
59 #define PADI_RESTART_TIME 500
60 #define PADR_RESTART_TIME 2000
62 /* default inquiry mode timer in milliseconds. */
63 #define PADI_INQUIRY_DWELL 3000
65 /* maximum timer value in milliseconds */
66 #define RESTART_LIMIT 5000
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 */
73 static int pado_wait_time
= 0; /* see main() */
74 static int pads_wait_time
= PADR_RESTART_TIME
;
76 static int tunfd
; /* open connection to sppptun driver */
78 static struct timeval tvstart
; /* time of last PADI/PADR transmission */
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 */
89 /* List of filters defined on command line. */
90 static struct server_filter
*sfhead
, *sftail
;
93 * PPPoE Client State Machine
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 */
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 */
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 */
127 static uint8_t client_next_state
[PCSMS__MAX
][PCSME__MAX
] = {
128 /* 0 PCSMS_DEAD Initial state */
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 */
140 /* 1 PCSMS_INITSENT PADI sent */
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 */
152 /* 2 PCSMS_OFFRRCVD PADO received */
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 */
164 /* 3 PCSMS_REQSENT PADR sent */
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 */
176 /* 4 PCSMS_CONVERS Conversational */
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 */
190 static uint8_t client_action
[PCSMS__MAX
][PCSME__MAX
] = {
191 /* 0 PCSMS_DEAD Initial state */
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 */
203 /* 1 PCSMS_INITSENT PADI sent */
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 */
215 /* 2 PCSMS_OFFRRCVD PADO received */
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 */
227 /* 3 PCSMS_REQSENT PADR sent */
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 */
239 /* 4 PCSMS_CONVERS Conversational */
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 */
254 * PPPoE Message structure -- holds data from a received PPPoE
255 * message. These are copied and saved when queuing offers from
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 */
267 * PPPoE State Machine structure -- holds state of PPPoE negotiation;
268 * currently, there's exactly one of these per pppoec instance.
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 */
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 */
281 int poesm_localid
; /* Local session ID (driver) */
285 * Convert an internal PPPoE event code number into a printable
291 static const char *poeevent
[PCSME__MAX
] = {
292 "Close", "Open", "TO+", "TO-", "rPADT",
293 "rPADO+", "rPADO", "rPADS", "rPADS-"
296 if (event
< 0 || event
>= PCSME__MAX
) {
299 return (poeevent
[event
]);
303 * Convert an internal PPPoE state number into a printable string.
308 static const char *poestate
[PCSMS__MAX
] = {
309 "Dead", "InitSent", "OffrRcvd", "ReqSent", "Convers",
312 if (state
< 0 || state
>= PCSMS__MAX
) {
315 return (poestate
[state
]);
319 * Convert an internal PPPoE action number into a printable string.
324 static const char *poeaction
[PCSMA__MAX
] = {
325 "None", "Fail", "SendPADI", "Add", "SendPADR",
326 "SendPADR+", "SendPADR-", "Open"
329 if (act
< 0 || act
>= PCSMA__MAX
) {
332 return (poeaction
[act
]);
336 * This calls mygetmsg (which discards partial messages as needed) and
337 * logs errors as appropriate.
340 pppoec_getmsg(int fd
, struct strbuf
*ctrl
, struct strbuf
*data
, int *flags
)
345 retv
= mygetmsg(fd
, ctrl
, data
, flags
);
351 logstrerror("getmsg");
355 if (!(retv
& (MORECTL
| MOREDATA
)))
356 logerr("%s: discard: "
357 "unexpected status %d\n", myname
, retv
);
359 logerr("%s: discard: "
360 "truncated %s%smessage\n", myname
,
361 retv
& MORECTL
? "control " : "",
362 retv
& MOREDATA
? "data " : "");
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
375 set_control(const char *dname
)
377 struct ppptun_peer ptp
;
378 union ppptun_name ptn
;
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
)) <
385 logstrerror("PPPTUN_SPEER");
389 /* Connect to lower stream. */
390 (void) snprintf(ptn
.ptn_name
, sizeof (ptn
.ptn_name
), "%s:pppoed",
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
));
397 return (ptp
.ptp_lsessid
);
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.
409 struct ppptun_info pti
;
410 union ppptun_name ptn
;
412 if (strioctl(0, PPPTUN_GDATA
, &ptn
, 0, sizeof (ptn
)) < 0) {
414 logerr("%s: PPPoE operation requires "
415 "the use of a tunneling device\n", myname
);
417 logstrerror("PPPTUN_GDATA");
420 if (ptn
.ptn_name
[0] != '\0') {
421 if (strioctl(0, PPPTUN_GINFO
, &pti
, 0, sizeof (pti
)) < 0) {
422 logstrerror("PPPTUN_GINFO");
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
);
432 logerr("%s: Warning: PPPoE data link "
433 "already connected\n", myname
);
436 /* Standard input is the tunnel driver; use it. */
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.
445 display_pppoe(FILE *out
, const poep_t
*poep
, int plen
, const ppptun_atype
*pap
)
456 logerr(" "); /* Give us a timestamp */
457 /* Print name of sender. */
458 (void) fprintf(out
, "%-16s ", ehost(pap
));
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
)
466 tlen
= POET_GET_LENG(tagp
);
467 dp
= POET_DATA(tagp
);
470 case POETT_SERVICE
: /* Service-Name */
473 case POETT_ACCESS
: /* AC-Name */
476 case POETT_UNIQ
: /* Host-Uniq */
479 case POETT_COOKIE
: /* AC-Cookie */
482 case POETT_VENDOR
: /* Vendor-Specific */
484 case POETT_RELAY
: /* Relay-Session-Id */
487 case POETT_NAMERR
: /* Service-Name-Error */
490 case POETT_SYSERR
: /* AC-System-Error */
493 case POETT_GENERR
: /* Generic-Error */
496 case POETT_MULTI
: /* Multicast-Capable */
498 case POETT_HURL
: /* Host-URL */
501 case POETT_MOTM
: /* Message-Of-The-Minute */
504 case POETT_RTEADD
: /* IP-Route-Add */
508 case POETT_NAMERR
: /* Service-Name-Error */
509 case POETT_SYSERR
: /* AC-System-Error */
510 if (tlen
> 0 && *dp
== '\0')
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
);
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
);
525 (void) fprintf(out
, "%02X", *dp
++);
526 (void) putc(' ', out
);
528 case POETT_VENDOR
: /* Vendor-Specific */
529 (void) fputs("Vendor:", out
);
532 (void) fprintf(out
, "(%02X?)", dp
[-1]);
534 (void) fprintf(out
, "%x-%x-%x:", dp
[0], dp
[1],
540 (void) fprintf(out
, "%02X", *dp
++);
541 (void) putc(' ', out
);
543 case POETT_MULTI
: /* Multicast-Capable */
544 (void) fprintf(out
, "Multi:%d ", *dp
);
546 case POETT_RTEADD
: /* IP-Route-Add */
547 if (tlen
!= sizeof (poer
)) {
548 (void) fprintf(out
, "RTE%d? ", tlen
);
551 (void) memcpy(&poer
, dp
, sizeof (poer
));
552 (void) fputs("RTE:", out
);
553 if (poer
.poer_dest_network
== 0)
554 (void) fputs("default", out
);
556 (void) fputs(ihost(poer
.poer_dest_network
),
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
+
565 (void) fprintf(out
, "/%s",
566 ihost(poer
.poer_subnet_mask
));
568 (void) fprintf(out
, ",%s,%u ",
569 ihost(poer
.poer_gateway
), ntohl(poer
.poer_metric
));
572 (void) fprintf(out
, "%s:%d ", poe_tagname(ttyp
), tlen
);
575 tagp
= POET_NEXT(tagp
);
577 (void) putc('\n', out
);
581 * Transmit a PPPoE message to the indicated destination. Used for
582 * PADI and PADR messages.
585 send_pppoe(const poep_t
*poep
, const char *msgname
,
586 const ppptun_atype
*destaddr
)
590 struct ppptun_control
*ptc
;
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
;
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");
613 * Create and transmit a PPPoE Active Discovery Initiation packet.
614 * This is broadcasted to all hosts on the LAN.
617 send_padi(int localid
)
620 ppptun_atype destaddr
;
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
));
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
640 alarm_hand(int dummy
)
646 * Send out a single PADI and listen for servers. This implements the
647 * "inquiry" (-i) mode.
650 find_all_servers(int localid
)
656 struct sigaction act
;
657 struct ppptun_control
*ptc
;
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);
665 /* Broadcast a single request. */
666 if (send_padi(localid
) != 0)
669 /* Loop over responses and print them. */
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
;
677 if (pppoec_getmsg(tunfd
, &ctrl
, &data
, &flags
) < 0)
680 /* Ignore unwanted responses from the driver. */
681 if (ctrl
.len
!= sizeof (*ptc
)) {
683 logerr("%s: unexpected %d byte"
684 " control message from driver.\n", myname
,
688 ptc
= (struct ppptun_control
*)pkt_octl
;
689 poep
= (poep_t
*)pkt_input
;
691 /* If it's an offer, then print it out. */
692 if (poe_code(poep
) == POECODE_PADO
) {
693 display_pppoe(stdout
, poep
, data
.len
,
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.
706 parse_filter(const char *str
, int exceptflag
)
708 struct server_filter
*sfnew
;
710 const char *wordstart
;
713 char hbuf
[MAXHOSTNAMELEN
];
717 /* Allocate the new filter structure. */
718 sfnew
= (struct server_filter
*)calloc(1, sizeof (*sfnew
));
720 logstrerror("filter allocation");
724 /* Save the string for AC-Name comparison. */
725 sfnew
->sf_name
= str
;
727 sfnew
->sf_isexcept
= exceptflag
== 0 ? 0 : 1;
729 /* Extract just one word. */
734 while (*cp
!= '\0' && !isspace(*cp
))
737 if ((len
= wordend
- wordstart
) >= sizeof (hbuf
))
738 len
= sizeof (hbuf
) - 1;
739 (void) strlcpy(hbuf
, wordstart
, len
);
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;
748 ucp
= sfnew
->sf_mac
.ether_addr_octet
;
749 len
= wordend
- wordstart
;
751 while (cp
< wordend
) {
752 if (ucp
>= sfnew
->sf_mac
.ether_addr_octet
+
753 sizeof (sfnew
->sf_mac
))
761 *ucp
= hexdecode(*cp
++);
762 if (cp
< wordend
&& isxdigit(*cp
)) {
770 if (*cp
!= ':' || cp
+ 1 == wordend
)
776 sfnew
->sf_hasmac
= 1;
778 logerr("%s: treating '%.*s' as server "
779 "name only, not MAC address\n", myname
, len
,
783 /* Add to end of list. */
787 sftail
->sf_next
= sfnew
;
792 * Create a copy of a given PPPoE message. This is used for enqueuing
793 * received PADO (offers) from possible servers.
796 save_message(const poemsg_t
*pmsg
)
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
));
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.
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.
830 send_padr(poesm_t
*psm
, const poemsg_t
*pado
)
840 * Increment sequence number for PADR so that we don't mistake
841 * old replies for valid ones if the server is very slow.
843 psm
->poesm_sequence
++;
845 poep
= poe_mkheader(pkt_output
, POECODE_PADR
, 0);
846 (void) poe_two_longs(poep
, POETT_UNIQ
, psm
->poesm_localid
,
847 psm
->poesm_sequence
);
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
)
856 tlen
= POET_GET_LENG(tagp
);
858 case POETT_SERVICE
: /* Service-Name */
866 if (service
[0] == '\0' ||
867 (tlen
== strlen(service
) &&
868 memcmp(service
, POET_DATA(tagp
), tlen
) == 0)) {
869 (void) poe_tag_copy(poep
, tagp
);
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 */
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
);
892 tagp
= POET_NEXT(tagp
);
895 if (haswild
&& service
[0] == '\0')
896 (void) poe_add_str(poep
, POETT_SERVICE
, "");
901 return (send_pppoe(poep
, "PADR", &pado
->poemsg_sender
));
905 * ********************************************************************
906 * act_* functions implement the actions driven by the state machine
907 * tables. See "action_table" below.
909 * All action routines must return the next state value.
910 * ********************************************************************
915 act_none(poesm_t
*psm
, poemsg_t
*pmsg
, int event
, int nextst
)
922 act_fail(poesm_t
*psm
, poemsg_t
*pmsg
, int event
, int nextst
)
925 logerr("%s: unrecoverable error\n", myname
);
931 act_spadi(poesm_t
*psm
, poemsg_t
*pmsg
, int event
, int nextst
)
933 if (send_padi(psm
->poesm_localid
) != 0)
936 * If this is the first time, then initialize the retry count
939 if (psm
->poesm_state
== PCSMS_DEAD
) {
940 psm
->poesm_count
= 3;
941 psm
->poesm_interval
= pado_wait_time
;
943 if ((psm
->poesm_interval
<<= 1) > RESTART_LIMIT
)
944 psm
->poesm_interval
= RESTART_LIMIT
;
946 psm
->poesm_timer
= psm
->poesm_interval
;
947 (void) gettimeofday(&tvstart
, NULL
);
953 act_add(poesm_t
*psm
, poemsg_t
*pmsg
, int event
, int nextst
)
955 pmsg
= save_message(pmsg
);
957 if (psm
->poesm_lastoff
== NULL
)
958 psm
->poesm_firstoff
= pmsg
;
960 psm
->poesm_lastoff
->poemsg_next
= pmsg
;
961 psm
->poesm_lastoff
= pmsg
;
968 act_spadr(poesm_t
*psm
, poemsg_t
*pmsg
, int event
, int nextst
)
974 if ((msgp
= psm
->poesm_firstoff
) == NULL
)
976 retv
= send_padr(psm
, msgp
);
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
;
986 if (psm
->poesm_state
!= PCSMS_REQSENT
) {
987 psm
->poesm_count
= 3;
988 psm
->poesm_interval
= pads_wait_time
;
990 if ((psm
->poesm_interval
<<= 1) > RESTART_LIMIT
)
991 psm
->poesm_interval
= RESTART_LIMIT
;
993 psm
->poesm_timer
= psm
->poesm_interval
;
994 (void) gettimeofday(&tvstart
, NULL
);
1000 act_spadrp(poesm_t
*psm
, poemsg_t
*pmsg
, int event
, int nextst
)
1004 retv
= send_padr(psm
, pmsg
);
1006 return (PCSMS_DEAD
);
1007 pmsg
= save_message(pmsg
);
1010 * Cannot use this one; mark as tried and continue as
1011 * if we never saw it.
1013 pmsg
->poemsg_next
= psm
->poesm_tried
;
1014 psm
->poesm_tried
= pmsg
;
1015 return (psm
->poesm_state
);
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
);
1029 act_spadrn(poesm_t
*psm
, poemsg_t
*pmsg
, int event
, int nextst
)
1034 if ((msgp
= psm
->poesm_firstoff
) == NULL
)
1035 return (PCSMS_DEAD
);
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
);
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
);
1053 * For safety -- remove end of line from strings passed back to pppd.
1056 remove_eol(char *str
, size_t len
)
1068 act_open(poesm_t
*psm
, poemsg_t
*pmsg
, int event
, int nextst
)
1070 struct ppptun_peer ptp
;
1071 union ppptun_name ptn
;
1074 const uint8_t *tagp
, *vp
;
1078 size_t acc_len
, serv_len
;
1081 * The server has now assigned its session ID for the data
1082 * (PPP) portion of this tunnel. Send that ID down to the
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
)) <
1093 logstrerror("PPPTUN_SPEER");
1094 return (PCSMS_DEAD
);
1098 * Data communication is now possible on this session.
1099 * Connect the data portion to the correct lower stream.
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
);
1111 logerr("%s: Connection open; session %04X on "
1112 "%s\n", myname
, ptp
.ptp_rsessid
, ptn
.ptn_name
);
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
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
)
1128 tlen
= POET_GET_LENG(tagp
);
1129 if (ttyp
== POETT_ACCESS
) {
1130 access
= (char *)POET_DATA(tagp
);
1133 if (serv_len
== 0 && ttyp
== POETT_SERVICE
&& tlen
!= 0) {
1134 service
= (char *)POET_DATA(tagp
);
1137 tagp
= POET_NEXT(tagp
);
1141 * Remove end of line to make sure that integrity of values
1142 * passed back to pppd can't be compromised by the PPPoE
1145 remove_eol(service
, serv_len
);
1146 remove_eol(access
, acc_len
);
1149 * pppd has given us a pipe as fd 3, and we're expected to
1150 * write out the values of the following environment
1157 * VENDOR_SPECIFIC_1 ... N
1158 * See usr.bin/pppd/plugins/pppoe.c for more information.
1160 if ((fp
= fdopen(3, "w")) != NULL
) {
1161 (void) fprintf(fp
, "%.*s:%.*s\n",
1162 cp
- pmsg
->poemsg_iname
, pmsg
->poemsg_iname
, serv_len
,
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
,
1171 ttyp
= POET_GET_TYPE(tagp
);
1172 if (ttyp
== POETT_END
)
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
));
1180 vp
= POET_DATA(tagp
) + 4;
1182 (void) fprintf(fp
, "%02X", *vp
++);
1183 (void) putc('\n', fp
);
1185 tagp
= POET_NEXT(tagp
);
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
1200 * Dispatch an event and a corresponding message on a given state
1204 handle_event(poesm_t
*psm
, int event
, poemsg_t
*pmsg
)
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
]);
1215 nextst
= (*action_table
[client_action
[psm
->poesm_state
][event
]])(psm
,
1216 pmsg
, event
, client_next_state
[psm
->poesm_state
][event
]);
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
);
1223 psm
->poesm_state
= nextst
;
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.
1230 if (nextst
== PCSMS_DEAD
) {
1232 logerr("%s: action failed\n", myname
);
1235 if (nextst
== PCSMS_CONVERS
) {
1237 logerr("%s: connected\n", myname
);
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
1248 error_check(poemsg_t
*pmsg
)
1250 const uint8_t *tagp
;
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
)
1258 if (ttyp
== POETT_NAMERR
|| ttyp
== POETT_SYSERR
||
1259 ttyp
== POETT_GENERR
) {
1261 display_pppoe(stderr
, pmsg
->poemsg_data
,
1262 pmsg
->poemsg_len
, &pmsg
->poemsg_sender
);
1265 tagp
= POET_NEXT(tagp
);
1271 * Extract sequence number, if any, from PADS message, so that we can
1272 * relate it to the PADR that we sent.
1275 get_sequence(const poemsg_t
*pmsg
)
1277 const uint8_t *tagp
;
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
)
1286 if (ttyp
== POETT_UNIQ
) {
1287 if (POET_GET_LENG(tagp
) < sizeof (vals
))
1289 (void) memcpy(vals
, POET_DATA(tagp
), sizeof (vals
));
1290 return (ntohl(vals
[1]));
1292 tagp
= POET_NEXT(tagp
);
1298 * Server filter cases:
1300 * No filters -- all servers generate RPADO+ event; select the
1301 * first responding server.
1303 * Only "except" filters -- matching servers are RPADO, others
1306 * Mix of filters -- those matching "pass" are RPADO+, those
1307 * matching "except" are RPADO, and all others are also RPADO.
1309 * If the "only" keyword was given, then RPADO becomes -1; only RPADO+
1313 use_server(poemsg_t
*pado
, const ppptun_atype
*pap
)
1315 struct server_filter
*sfp
;
1316 const uchar_t
*sndp
;
1317 const uchar_t
*macp
;
1318 const uchar_t
*maskp
;
1322 const uint8_t *tagp
;
1326 * If no service mentioned in offer, then we can't use it.
1328 tagp
= (const uint8_t *)(pado
->poemsg_data
+ 1);
1330 while (poe_tagcheck(pado
->poemsg_data
, pado
->poemsg_len
, tagp
)) {
1331 ttyp
= POET_GET_TYPE(tagp
);
1332 if (ttyp
== POETT_END
)
1334 if (ttyp
== POETT_SERVICE
) {
1336 * If the user has requested a specific service, then
1337 * this selection is exclusive. We never use the
1338 * wildcard for this.
1340 tlen
= POET_GET_LENG(tagp
);
1341 if (service
[0] == '\0' || (strlen(service
) == tlen
&&
1342 memcmp(service
, POET_DATA(tagp
), tlen
) == 0))
1344 /* just in case we run off the end */
1347 tagp
= POET_NEXT(tagp
);
1349 if (ttyp
!= POETT_SERVICE
) {
1351 logerr("%s: Discard unusable offer from %s; service "
1352 "'%s' not seen\n", myname
, ehost(pap
), service
);
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
);
1365 if (((*macp
++ ^ *sndp
++) & *maskp
++) != 0)
1374 * No match encountered; if only exclude rules have
1375 * been seen, then accept this offer.
1378 return (PCSME_RPADOP
);
1380 if (!sfp
->sf_isexcept
)
1381 return (PCSME_RPADOP
);
1385 logerr("%s: Discard unusable offer from %s; server not "
1386 "matched\n", myname
, ehost(pap
));
1389 return (PCSME_RPADO
);
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.
1398 find_server(int localid
)
1401 struct pollfd pfd
[1];
1402 struct timeval tv
, tvnow
;
1410 struct ppptun_control
*ptc
;
1412 (void) memset(&psm
, '\0', sizeof (psm
));
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.
1420 psm
.poesm_sequence
= getpid() << 16;
1421 psm
.poesm_localid
= localid
;
1423 /* Start the state machine */
1424 handle_event(&psm
, PCSME_OPEN
, NULL
);
1426 /* Enter event polling loop. */
1428 pfd
[0].events
= POLLIN
;
1430 /* Wait for timeout or message */
1431 retv
= poll(pfd
, 1, psm
.poesm_timer
> 0 ? psm
.poesm_timer
:
1434 logstrerror("poll");
1438 /* Handle a timeout */
1440 psm
.poesm_timer
= 0;
1441 handle_event(&psm
, --psm
.poesm_count
> 0 ? PCSME_TOP
:
1446 /* Adjust the timer for the time we slept. */
1447 if (psm
.poesm_timer
> 0) {
1448 (void) gettimeofday(&tvnow
, NULL
);
1450 if ((tv
.tv_sec
-= tvstart
.tv_sec
) < 0) {
1454 } else if ((tv
.tv_usec
-= tvstart
.tv_usec
) < 0) {
1455 tv
.tv_usec
+= 1000000;
1456 if (--tv
.tv_sec
< 0)
1459 psm
.poesm_timer
-= tv
.tv_sec
*1000 + tv
.tv_usec
/1000;
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
;
1470 if (pppoec_getmsg(tunfd
, &ctrl
, &data
, &flags
) < 0)
1473 if (ctrl
.len
!= sizeof (*ptc
)) {
1475 logerr("%s: discard: ctrl len %d\n", myname
,
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
) {
1487 logerr("%s: discard: unexpected action %d\n",
1488 myname
, ptc
->ptc_action
);
1491 pmsg
.poemsg_iname
= ptc
->ptc_name
;
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
;
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)) {
1505 logerr("%s: Unexpected peer %s", myname
,
1506 ehost(&ptc
->ptc_address
));
1508 ehost(&psm
.poesm_firstoff
->poemsg_sender
));
1513 /* Eliminate stale PADS responses. */
1514 if (poep
->poep_code
== POECODE_PADS
) {
1515 seqval
= get_sequence(&pmsg
);
1516 if (seqval
!= psm
.poesm_sequence
) {
1520 "%s: PADS has no sequence "
1521 "number.\n", myname
);
1524 "%s: PADS has sequence "
1525 "%08X instead of %08X.\n",
1527 psm
.poesm_sequence
);
1533 /* Dispatch message event. */
1534 retv
= error_check(&pmsg
);
1535 switch (poep
->poep_code
) {
1537 handle_event(&psm
, PCSME_RPADT
, &pmsg
);
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
1547 handle_event(&psm
, retv
!= 0 ? PCSME_RPADSN
:
1548 PCSME_RPADS
, &pmsg
);
1551 /* Ignore offers that merely report errors. */
1554 /* Ignore offers from servers we don't want. */
1555 if ((retv
= use_server(&pmsg
, &ptc
->ptc_address
)) < 0)
1557 /* Dispatch either RPADO or RAPDO+ event. */
1558 handle_event(&psm
, retv
, &pmsg
);
1563 logerr("%s: Unexpected code %s (%d)\n", myname
,
1564 poe_codename(poep
->poep_code
),
1576 "\t%s [-os#] [-v] <dev> [<service> [<server> [only]]]\n\n"
1578 "\t%s [-o#] [-v] -i <dev>\n", myname
, myname
);
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
1589 main(int argc
, char **argv
)
1591 int inquiry_mode
, exceptflag
, arg
, localid
;
1594 log_to_stderr(LOGLVL_DBG
);
1596 if ((myname
= *argv
) == NULL
)
1600 while ((arg
= getopt(argc
, argv
, "io:s:v")) != EOF
)
1609 pado_wait_time
= strtol(optarg
, &cp
, 0);
1610 if (pado_wait_time
<= 0 || *cp
!= '\0' ||
1612 logerr("%s: illegal PADO wait time: %s\n",
1618 pads_wait_time
= strtol(optarg
, &cp
, 0);
1619 if (pads_wait_time
<= 0 || *cp
!= '\0' ||
1621 logerr("%s: illegal PADS wait time: %s\n",
1630 /* Handle inquiry mode. */
1632 if (optind
!= argc
-1)
1634 if (pado_wait_time
== 0)
1635 pado_wait_time
= PADI_INQUIRY_DWELL
;
1637 /* Invoked by user; open the tunnel driver myself. */
1638 tunfd
= open(tunnam
, O_RDWR
| O_NOCTTY
);
1640 logstrerror(tunnam
);
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).
1649 find_all_servers(set_control(argv
[optind
]));
1653 if (pado_wait_time
== 0)
1654 pado_wait_time
= PADI_RESTART_TIME
;
1659 /* Make sure we've got a usable tunnel driver on stdin. */
1662 /* Set up the control stream for PPPoE negotiation. */
1663 localid
= set_control(argv
[optind
++]);
1665 /* Pick the service, if any. */
1667 service
= argv
[optind
++];
1669 /* Parse out the filters. */
1670 if (optind
< argc
) {
1671 if (strcasecmp(argv
[argc
- 1], "only") == 0) {
1676 for (; optind
< argc
; optind
++) {
1678 strcasecmp(argv
[optind
], "except") == 0) {
1681 parse_filter(argv
[optind
], exceptflag
);
1687 /* Enter the main loop. */
1688 find_server(localid
);