xref: /netbsd-src/external/bsd/ppp/dist/pppd/plugins/pppoe/discovery.c (revision 15a984a0d95c8f96abe9717ee6241762c55dc106)
1 /***********************************************************************
2 *
3 * discovery.c
4 *
5 * Perform PPPoE discovery
6 *
7 * Copyright (C) 1999 by Roaring Penguin Software Inc.
8 *
9 ***********************************************************************/
10 
11 static char const RCSID[] =
12 "Id: discovery.c,v 1.6 2008/06/15 04:35:50 paulus Exp ";
13 
14 #define _GNU_SOURCE 1
15 #include "pppoe.h"
16 #include "pppd/pppd.h"
17 #include "pppd/fsm.h"
18 #include "pppd/lcp.h"
19 
20 #include <string.h>
21 #include <stdlib.h>
22 #include <errno.h>
23 
24 #ifdef HAVE_SYS_TIME_H
25 #include <sys/time.h>
26 #endif
27 
28 #ifdef HAVE_SYS_UIO_H
29 #include <sys/uio.h>
30 #endif
31 
32 #ifdef HAVE_UNISTD_H
33 #include <unistd.h>
34 #endif
35 
36 #ifdef USE_LINUX_PACKET
37 #include <sys/ioctl.h>
38 #include <fcntl.h>
39 #endif
40 
41 #include <signal.h>
42 
43 /* Calculate time remaining until *exp, return 0 if now >= *exp */
44 static int time_left(struct timeval *diff, struct timeval *exp)
45 {
46     struct timeval now;
47 
48     if (get_time(&now) < 0) {
49 	error("get_time: %m");
50 	return 0;
51     }
52 
53     if (now.tv_sec > exp->tv_sec
54 	|| (now.tv_sec == exp->tv_sec && now.tv_usec >= exp->tv_usec))
55 	return 0;
56 
57     diff->tv_sec = exp->tv_sec - now.tv_sec;
58     diff->tv_usec = exp->tv_usec - now.tv_usec;
59     if (diff->tv_usec < 0) {
60 	diff->tv_usec += 1000000;
61 	--diff->tv_sec;
62     }
63 
64     return 1;
65 }
66 
67 /**********************************************************************
68 *%FUNCTION: parseForHostUniq
69 *%ARGUMENTS:
70 * type -- tag type
71 * len -- tag length
72 * data -- tag data.
73 * extra -- user-supplied pointer.  This is assumed to be a pointer to int.
74 *%RETURNS:
75 * Nothing
76 *%DESCRIPTION:
77 * If a HostUnique tag is found which matches our PID, sets *extra to 1.
78 ***********************************************************************/
79 static void
80 parseForHostUniq(UINT16_t type, UINT16_t len, unsigned char *data,
81 		 void *extra)
82 {
83     PPPoETag *tag = extra;
84 
85     if (type == TAG_HOST_UNIQ && len == ntohs(tag->length))
86 	tag->length = memcmp(data, tag->payload, len);
87 }
88 
89 /**********************************************************************
90 *%FUNCTION: packetIsForMe
91 *%ARGUMENTS:
92 * conn -- PPPoE connection info
93 * packet -- a received PPPoE packet
94 *%RETURNS:
95 * 1 if packet is for this PPPoE daemon; 0 otherwise.
96 *%DESCRIPTION:
97 * If we are using the Host-Unique tag, verifies that packet contains
98 * our unique identifier.
99 ***********************************************************************/
100 static int
101 packetIsForMe(PPPoEConnection *conn, PPPoEPacket *packet)
102 {
103     PPPoETag hostUniq = conn->hostUniq;
104 
105     /* If packet is not directed to our MAC address, forget it */
106     if (memcmp(packet->ethHdr.h_dest, conn->myEth, ETH_ALEN)) return 0;
107 
108     /* If we're not using the Host-Unique tag, then accept the packet */
109     if (!conn->hostUniq.length) return 1;
110 
111     parsePacket(packet, parseForHostUniq, &hostUniq);
112     return !hostUniq.length;
113 }
114 
115 /**********************************************************************
116 *%FUNCTION: parsePADOTags
117 *%ARGUMENTS:
118 * type -- tag type
119 * len -- tag length
120 * data -- tag data
121 * extra -- extra user data.  Should point to a PacketCriteria structure
122 *          which gets filled in according to selected AC name and service
123 *          name.
124 *%RETURNS:
125 * Nothing
126 *%DESCRIPTION:
127 * Picks interesting tags out of a PADO packet
128 ***********************************************************************/
129 static void
130 parsePADOTags(UINT16_t type, UINT16_t len, unsigned char *data,
131 	      void *extra)
132 {
133     struct PacketCriteria *pc = (struct PacketCriteria *) extra;
134     PPPoEConnection *conn = pc->conn;
135     UINT16_t mru;
136     int i;
137 
138     switch(type) {
139     case TAG_AC_NAME:
140 	pc->seenACName = 1;
141 	if (conn->printACNames) {
142 	    info("Access-Concentrator: %.*s", (int) len, data);
143 	}
144 	if (conn->acName && len == strlen(conn->acName) &&
145 	    !strncmp((char *) data, conn->acName, len)) {
146 	    pc->acNameOK = 1;
147 	}
148 	break;
149     case TAG_SERVICE_NAME:
150 	pc->seenServiceName = 1;
151 	if (conn->serviceName && len == strlen(conn->serviceName) &&
152 	    !strncmp((char *) data, conn->serviceName, len)) {
153 	    pc->serviceNameOK = 1;
154 	}
155 	break;
156     case TAG_AC_COOKIE:
157 	conn->cookie.type = htons(type);
158 	conn->cookie.length = htons(len);
159 	memcpy(conn->cookie.payload, data, len);
160 	break;
161     case TAG_RELAY_SESSION_ID:
162 	conn->relayId.type = htons(type);
163 	conn->relayId.length = htons(len);
164 	memcpy(conn->relayId.payload, data, len);
165 	break;
166     case TAG_PPP_MAX_PAYLOAD:
167 	if (len == sizeof(mru)) {
168 	    memcpy(&mru, data, sizeof(mru));
169 	    mru = ntohs(mru);
170 	    if (mru >= ETH_PPPOE_MTU) {
171 		if (lcp_allowoptions[0].mru > mru)
172 		    lcp_allowoptions[0].mru = mru;
173 		if (lcp_wantoptions[0].mru > mru)
174 		    lcp_wantoptions[0].mru = mru;
175 		conn->seenMaxPayload = 1;
176 	    }
177 	}
178 	break;
179     case TAG_SERVICE_NAME_ERROR:
180 	error("PADO: Service-Name-Error: %.*s", (int) len, data);
181 	conn->error = 1;
182 	break;
183     case TAG_AC_SYSTEM_ERROR:
184 	error("PADO: System-Error: %.*s", (int) len, data);
185 	conn->error = 1;
186 	break;
187     case TAG_GENERIC_ERROR:
188 	error("PADO: Generic-Error: %.*s", (int) len, data);
189 	conn->error = 1;
190 	break;
191     }
192 }
193 
194 /**********************************************************************
195 *%FUNCTION: parsePADSTags
196 *%ARGUMENTS:
197 * type -- tag type
198 * len -- tag length
199 * data -- tag data
200 * extra -- extra user data (pointer to PPPoEConnection structure)
201 *%RETURNS:
202 * Nothing
203 *%DESCRIPTION:
204 * Picks interesting tags out of a PADS packet
205 ***********************************************************************/
206 static void
207 parsePADSTags(UINT16_t type, UINT16_t len, unsigned char *data,
208 	      void *extra)
209 {
210     PPPoEConnection *conn = (PPPoEConnection *) extra;
211     UINT16_t mru;
212     switch(type) {
213     case TAG_SERVICE_NAME:
214 	dbglog("PADS: Service-Name: '%.*s'", (int) len, data);
215 	break;
216     case TAG_PPP_MAX_PAYLOAD:
217 	if (len == sizeof(mru)) {
218 	    memcpy(&mru, data, sizeof(mru));
219 	    mru = ntohs(mru);
220 	    if (mru >= ETH_PPPOE_MTU) {
221 		if (lcp_allowoptions[0].mru > mru)
222 		    lcp_allowoptions[0].mru = mru;
223 		if (lcp_wantoptions[0].mru > mru)
224 		    lcp_wantoptions[0].mru = mru;
225 		conn->seenMaxPayload = 1;
226 	    }
227 	}
228 	break;
229     case TAG_SERVICE_NAME_ERROR:
230 	error("PADS: Service-Name-Error: %.*s", (int) len, data);
231 	conn->error = 1;
232 	break;
233     case TAG_AC_SYSTEM_ERROR:
234 	error("PADS: System-Error: %.*s", (int) len, data);
235 	conn->error = 1;
236 	break;
237     case TAG_GENERIC_ERROR:
238 	error("PADS: Generic-Error: %.*s", (int) len, data);
239 	conn->error = 1;
240 	break;
241     case TAG_RELAY_SESSION_ID:
242 	conn->relayId.type = htons(type);
243 	conn->relayId.length = htons(len);
244 	memcpy(conn->relayId.payload, data, len);
245 	break;
246     }
247 }
248 
249 /***********************************************************************
250 *%FUNCTION: sendPADI
251 *%ARGUMENTS:
252 * conn -- PPPoEConnection structure
253 *%RETURNS:
254 * Nothing
255 *%DESCRIPTION:
256 * Sends a PADI packet
257 ***********************************************************************/
258 static void
259 sendPADI(PPPoEConnection *conn)
260 {
261     PPPoEPacket packet;
262     unsigned char *cursor = packet.payload;
263     PPPoETag *svc = (PPPoETag *) (&packet.payload);
264     UINT16_t namelen = 0;
265     UINT16_t plen;
266     int omit_service_name = 0;
267 
268     if (conn->serviceName) {
269 	namelen = (UINT16_t) strlen(conn->serviceName);
270 	if (!strcmp(conn->serviceName, "NO-SERVICE-NAME-NON-RFC-COMPLIANT")) {
271 	    omit_service_name = 1;
272 	}
273     }
274 
275     /* Set destination to Ethernet broadcast address */
276     memset(packet.ethHdr.h_dest, 0xFF, ETH_ALEN);
277     memcpy(packet.ethHdr.h_source, conn->myEth, ETH_ALEN);
278 
279     packet.ethHdr.h_proto = htons(Eth_PPPOE_Discovery);
280     packet.vertype = PPPOE_VER_TYPE(1, 1);
281     packet.code = CODE_PADI;
282     packet.session = 0;
283 
284     if (!omit_service_name) {
285 	plen = TAG_HDR_SIZE + namelen;
286 	CHECK_ROOM(cursor, packet.payload, plen);
287 
288 	svc->type = TAG_SERVICE_NAME;
289 	svc->length = htons(namelen);
290 
291 	if (conn->serviceName) {
292 	    memcpy(svc->payload, conn->serviceName, strlen(conn->serviceName));
293 	}
294 	cursor += namelen + TAG_HDR_SIZE;
295     } else {
296 	plen = 0;
297     }
298 
299     /* If we're using Host-Uniq, copy it over */
300     if (conn->hostUniq.length) {
301 	int len = ntohs(conn->hostUniq.length);
302 	CHECK_ROOM(cursor, packet.payload, len + TAG_HDR_SIZE);
303 	memcpy(cursor, &conn->hostUniq, len + TAG_HDR_SIZE);
304 	cursor += len + TAG_HDR_SIZE;
305 	plen += len + TAG_HDR_SIZE;
306     }
307 
308     /* Add our maximum MTU/MRU */
309     if (MIN(lcp_allowoptions[0].mru, lcp_wantoptions[0].mru) > ETH_PPPOE_MTU) {
310 	PPPoETag maxPayload;
311 	UINT16_t mru = htons(MIN(lcp_allowoptions[0].mru, lcp_wantoptions[0].mru));
312 	maxPayload.type = htons(TAG_PPP_MAX_PAYLOAD);
313 	maxPayload.length = htons(sizeof(mru));
314 	memcpy(maxPayload.payload, &mru, sizeof(mru));
315 	CHECK_ROOM(cursor, packet.payload, sizeof(mru) + TAG_HDR_SIZE);
316 	memcpy(cursor, &maxPayload, sizeof(mru) + TAG_HDR_SIZE);
317 	cursor += sizeof(mru) + TAG_HDR_SIZE;
318 	plen += sizeof(mru) + TAG_HDR_SIZE;
319     }
320 
321     packet.length = htons(plen);
322 
323     sendPacket(conn, conn->discoverySocket, &packet, (int) (plen + HDR_SIZE));
324 }
325 
326 /**********************************************************************
327 *%FUNCTION: waitForPADO
328 *%ARGUMENTS:
329 * conn -- PPPoEConnection structure
330 * timeout -- how long to wait (in seconds)
331 *%RETURNS:
332 * Nothing
333 *%DESCRIPTION:
334 * Waits for a PADO packet and copies useful information
335 ***********************************************************************/
336 void
337 waitForPADO(PPPoEConnection *conn, int timeout)
338 {
339     fd_set readable;
340     int r;
341     struct timeval tv;
342     struct timeval expire_at;
343 
344     PPPoEPacket packet;
345     int len;
346 
347     struct PacketCriteria pc;
348     pc.conn          = conn;
349     pc.acNameOK      = (conn->acName)      ? 0 : 1;
350     pc.serviceNameOK = (conn->serviceName) ? 0 : 1;
351     pc.seenACName    = 0;
352     pc.seenServiceName = 0;
353     conn->seenMaxPayload = 0;
354     conn->error = 0;
355 
356     if (get_time(&expire_at) < 0) {
357 	error("get_time (waitForPADO): %m");
358 	return;
359     }
360     expire_at.tv_sec += timeout;
361 
362     do {
363 	if (BPF_BUFFER_IS_EMPTY) {
364 	    if (!time_left(&tv, &expire_at))
365 		return;		/* Timed out */
366 
367 	    FD_ZERO(&readable);
368 	    FD_SET(conn->discoverySocket, &readable);
369 
370 	    while(1) {
371 		r = select(conn->discoverySocket+1, &readable, NULL, NULL, &tv);
372 		if (r >= 0 || errno != EINTR || got_sigterm) break;
373 	    }
374 	    if (r < 0) {
375 		error("select (waitForPADO): %m");
376 		return;
377 	    }
378 	    if (r == 0)
379 		return;		/* Timed out */
380 	}
381 
382 	/* Get the packet */
383 	receivePacket(conn->discoverySocket, &packet, &len);
384 
385 	/* Check length */
386 	if (ntohs(packet.length) + HDR_SIZE > len) {
387 	    error("Bogus PPPoE length field (%u)",
388 		   (unsigned int) ntohs(packet.length));
389 	    continue;
390 	}
391 
392 #ifdef USE_BPF
393 	/* If it's not a Discovery packet, loop again */
394 	if (etherType(&packet) != Eth_PPPOE_Discovery) continue;
395 #endif
396 
397 	/* If it's not for us, loop again */
398 	if (!packetIsForMe(conn, &packet)) continue;
399 
400 	if (packet.code == CODE_PADO) {
401 	    if (NOT_UNICAST(packet.ethHdr.h_source)) {
402 		error("Ignoring PADO packet from non-unicast MAC address");
403 		continue;
404 	    }
405 	    if (conn->req_peer
406 		&& memcmp(packet.ethHdr.h_source, conn->req_peer_mac, ETH_ALEN) != 0) {
407 		warn("Ignoring PADO packet from wrong MAC address");
408 		continue;
409 	    }
410 	    if (parsePacket(&packet, parsePADOTags, &pc) < 0)
411 		return;
412 	    if (conn->error)
413 		return;
414 	    if (!pc.seenACName) {
415 		error("Ignoring PADO packet with no AC-Name tag");
416 		continue;
417 	    }
418 	    if (!pc.seenServiceName) {
419 		error("Ignoring PADO packet with no Service-Name tag");
420 		continue;
421 	    }
422 	    conn->numPADOs++;
423 	    if (pc.acNameOK && pc.serviceNameOK) {
424 		memcpy(conn->peerEth, packet.ethHdr.h_source, ETH_ALEN);
425 		conn->discoveryState = STATE_RECEIVED_PADO;
426 		break;
427 	    }
428 	}
429     } while (conn->discoveryState != STATE_RECEIVED_PADO);
430 }
431 
432 /***********************************************************************
433 *%FUNCTION: sendPADR
434 *%ARGUMENTS:
435 * conn -- PPPoE connection structur
436 *%RETURNS:
437 * Nothing
438 *%DESCRIPTION:
439 * Sends a PADR packet
440 ***********************************************************************/
441 static void
442 sendPADR(PPPoEConnection *conn)
443 {
444     PPPoEPacket packet;
445     PPPoETag *svc = (PPPoETag *) packet.payload;
446     unsigned char *cursor = packet.payload;
447 
448     UINT16_t namelen = 0;
449     UINT16_t plen;
450 
451     if (conn->serviceName) {
452 	namelen = (UINT16_t) strlen(conn->serviceName);
453     }
454     plen = TAG_HDR_SIZE + namelen;
455     CHECK_ROOM(cursor, packet.payload, plen);
456 
457     memcpy(packet.ethHdr.h_dest, conn->peerEth, ETH_ALEN);
458     memcpy(packet.ethHdr.h_source, conn->myEth, ETH_ALEN);
459 
460     packet.ethHdr.h_proto = htons(Eth_PPPOE_Discovery);
461     packet.vertype = PPPOE_VER_TYPE(1, 1);
462     packet.code = CODE_PADR;
463     packet.session = 0;
464 
465     svc->type = TAG_SERVICE_NAME;
466     svc->length = htons(namelen);
467     if (conn->serviceName) {
468 	memcpy(svc->payload, conn->serviceName, namelen);
469     }
470     cursor += namelen + TAG_HDR_SIZE;
471 
472     /* If we're using Host-Uniq, copy it over */
473     if (conn->hostUniq.length) {
474 	int len = ntohs(conn->hostUniq.length);
475 	CHECK_ROOM(cursor, packet.payload, len+TAG_HDR_SIZE);
476 	memcpy(cursor, &conn->hostUniq, len + TAG_HDR_SIZE);
477 	cursor += len + TAG_HDR_SIZE;
478 	plen += len + TAG_HDR_SIZE;
479     }
480 
481     /* Add our maximum MTU/MRU */
482     if (MIN(lcp_allowoptions[0].mru, lcp_wantoptions[0].mru) > ETH_PPPOE_MTU) {
483 	PPPoETag maxPayload;
484 	UINT16_t mru = htons(MIN(lcp_allowoptions[0].mru, lcp_wantoptions[0].mru));
485 	maxPayload.type = htons(TAG_PPP_MAX_PAYLOAD);
486 	maxPayload.length = htons(sizeof(mru));
487 	memcpy(maxPayload.payload, &mru, sizeof(mru));
488 	CHECK_ROOM(cursor, packet.payload, sizeof(mru) + TAG_HDR_SIZE);
489 	memcpy(cursor, &maxPayload, sizeof(mru) + TAG_HDR_SIZE);
490 	cursor += sizeof(mru) + TAG_HDR_SIZE;
491 	plen += sizeof(mru) + TAG_HDR_SIZE;
492     }
493 
494     /* Copy cookie and relay-ID if needed */
495     if (conn->cookie.type) {
496 	CHECK_ROOM(cursor, packet.payload,
497 		   ntohs(conn->cookie.length) + TAG_HDR_SIZE);
498 	memcpy(cursor, &conn->cookie, ntohs(conn->cookie.length) + TAG_HDR_SIZE);
499 	cursor += ntohs(conn->cookie.length) + TAG_HDR_SIZE;
500 	plen += ntohs(conn->cookie.length) + TAG_HDR_SIZE;
501     }
502 
503     if (conn->relayId.type) {
504 	CHECK_ROOM(cursor, packet.payload,
505 		   ntohs(conn->relayId.length) + TAG_HDR_SIZE);
506 	memcpy(cursor, &conn->relayId, ntohs(conn->relayId.length) + TAG_HDR_SIZE);
507 	cursor += ntohs(conn->relayId.length) + TAG_HDR_SIZE;
508 	plen += ntohs(conn->relayId.length) + TAG_HDR_SIZE;
509     }
510 
511     packet.length = htons(plen);
512     sendPacket(conn, conn->discoverySocket, &packet, (int) (plen + HDR_SIZE));
513 }
514 
515 /**********************************************************************
516 *%FUNCTION: waitForPADS
517 *%ARGUMENTS:
518 * conn -- PPPoE connection info
519 * timeout -- how long to wait (in seconds)
520 *%RETURNS:
521 * Nothing
522 *%DESCRIPTION:
523 * Waits for a PADS packet and copies useful information
524 ***********************************************************************/
525 static void
526 waitForPADS(PPPoEConnection *conn, int timeout)
527 {
528     fd_set readable;
529     int r;
530     struct timeval tv;
531     struct timeval expire_at;
532 
533     PPPoEPacket packet;
534     int len;
535 
536     if (get_time(&expire_at) < 0) {
537 	error("get_time (waitForPADS): %m");
538 	return;
539     }
540     expire_at.tv_sec += timeout;
541 
542     conn->error = 0;
543     do {
544 	if (BPF_BUFFER_IS_EMPTY) {
545 	    if (!time_left(&tv, &expire_at))
546 		return;		/* Timed out */
547 
548 	    FD_ZERO(&readable);
549 	    FD_SET(conn->discoverySocket, &readable);
550 
551 	    while(1) {
552 		r = select(conn->discoverySocket+1, &readable, NULL, NULL, &tv);
553 		if (r >= 0 || errno != EINTR || got_sigterm) break;
554 	    }
555 	    if (r < 0) {
556 		error("select (waitForPADS): %m");
557 		return;
558 	    }
559 	    if (r == 0)
560 		return;		/* Timed out */
561 	}
562 
563 	/* Get the packet */
564 	receivePacket(conn->discoverySocket, &packet, &len);
565 
566 	/* Check length */
567 	if (ntohs(packet.length) + HDR_SIZE > len) {
568 	    error("Bogus PPPoE length field (%u)",
569 		   (unsigned int) ntohs(packet.length));
570 	    continue;
571 	}
572 
573 #ifdef USE_BPF
574 	/* If it's not a Discovery packet, loop again */
575 	if (etherType(&packet) != Eth_PPPOE_Discovery) continue;
576 #endif
577 
578 	/* If it's not from the AC, it's not for me */
579 	if (memcmp(packet.ethHdr.h_source, conn->peerEth, ETH_ALEN)) continue;
580 
581 	/* If it's not for us, loop again */
582 	if (!packetIsForMe(conn, &packet)) continue;
583 
584 	/* Is it PADS?  */
585 	if (packet.code == CODE_PADS) {
586 	    /* Parse for goodies */
587 	    if (parsePacket(&packet, parsePADSTags, conn) < 0)
588 		return;
589 	    if (conn->error)
590 		return;
591 	    conn->discoveryState = STATE_SESSION;
592 	    break;
593 	}
594     } while (conn->discoveryState != STATE_SESSION);
595 
596     /* Don't bother with ntohs; we'll just end up converting it back... */
597     conn->session = packet.session;
598 
599     info("PPP session is %d", (int) ntohs(conn->session));
600 
601     /* RFC 2516 says session id MUST NOT be zero or 0xFFFF */
602     if (ntohs(conn->session) == 0 || ntohs(conn->session) == 0xFFFF) {
603 	error("Access concentrator used a session value of %x -- the AC is violating RFC 2516", (unsigned int) ntohs(conn->session));
604     }
605 }
606 
607 /**********************************************************************
608 *%FUNCTION: discovery
609 *%ARGUMENTS:
610 * conn -- PPPoE connection info structure
611 *%RETURNS:
612 * Nothing
613 *%DESCRIPTION:
614 * Performs the PPPoE discovery phase
615 ***********************************************************************/
616 void
617 discovery(PPPoEConnection *conn)
618 {
619     int padiAttempts = 0;
620     int padrAttempts = 0;
621     int timeout = conn->discoveryTimeout;
622 
623     do {
624 	padiAttempts++;
625 	if (got_sigterm || padiAttempts > conn->discoveryAttempts) {
626 	    warn("Timeout waiting for PADO packets");
627 	    close(conn->discoverySocket);
628 	    conn->discoverySocket = -1;
629 	    return;
630 	}
631 	sendPADI(conn);
632 	conn->discoveryState = STATE_SENT_PADI;
633 	waitForPADO(conn, timeout);
634 
635 	timeout *= 2;
636     } while (conn->discoveryState == STATE_SENT_PADI);
637 
638     timeout = conn->discoveryTimeout;
639     do {
640 	padrAttempts++;
641 	if (got_sigterm || padrAttempts > conn->discoveryAttempts) {
642 	    warn("Timeout waiting for PADS packets");
643 	    close(conn->discoverySocket);
644 	    conn->discoverySocket = -1;
645 	    return;
646 	}
647 	sendPADR(conn);
648 	conn->discoveryState = STATE_SENT_PADR;
649 	waitForPADS(conn, timeout);
650 	timeout *= 2;
651     } while (conn->discoveryState == STATE_SENT_PADR);
652 
653     if (!conn->seenMaxPayload) {
654 	/* RFC 4638: MUST limit MTU/MRU to 1492 */
655 	if (lcp_allowoptions[0].mru > ETH_PPPOE_MTU)
656 	    lcp_allowoptions[0].mru = ETH_PPPOE_MTU;
657 	if (lcp_wantoptions[0].mru > ETH_PPPOE_MTU)
658 	    lcp_wantoptions[0].mru = ETH_PPPOE_MTU;
659     }
660 
661     /* We're done. */
662     close(conn->discoverySocket);
663     conn->discoverySocket = -1;
664     conn->discoveryState = STATE_SESSION;
665     return;
666 }
667