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