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