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