1/***********************************************************************
2*
3* discovery.c
4*
5* Perform PPPoE discovery
6*
7* Copyright (C) 1999-2012 by Roaring Penguin Software Inc.
8*
9* LIC: GPL
10*
11***********************************************************************/
12
13static char const RCSID[] =
14"$Id$";
15#define _GNU_SOURCE 1
16
17#include "pppoe.h"
18
19#ifdef HAVE_SYSLOG_H
20#include <syslog.h>
21#endif
22
23#include <string.h>
24#include <stdlib.h>
25#include <errno.h>
26
27#ifdef HAVE_SYS_TIME_H
28#include <sys/time.h>
29#endif
30#include <time.h>
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#include "pppd/pppd.h"
49#include "pppd/fsm.h"
50#include "pppd/lcp.h"
51extern int got_sigterm;
52extern int got_sighup;
53#else
54int persist = 0;
55#endif
56
57/**********************************************************************
58*%FUNCTION: parseForHostUniq
59*%ARGUMENTS:
60* type -- tag type
61* len -- tag length
62* data -- tag data.
63* extra -- user-supplied pointer.  This is assumed to be a pointer to int.
64*%RETURNS:
65* Nothing
66*%DESCRIPTION:
67* If a HostUnique tag is found which matches our PID, sets *extra to 1.
68***********************************************************************/
69static void
70parseForHostUniq(UINT16_t type, UINT16_t len, unsigned char *data,
71		 void *extra)
72{
73    int *val = (int *) extra;
74    if (type == TAG_HOST_UNIQ && len == sizeof(pid_t)) {
75	pid_t tmp;
76	memcpy(&tmp, data, len);
77	if (tmp == getpid()) {
78	    *val = 1;
79	}
80    }
81}
82
83/**********************************************************************
84*%FUNCTION: packetIsForMe
85*%ARGUMENTS:
86* conn -- PPPoE connection info
87* packet -- a received PPPoE packet
88*%RETURNS:
89* 1 if packet is for this PPPoE daemon; 0 otherwise.
90*%DESCRIPTION:
91* If we are using the Host-Unique tag, verifies that packet contains
92* our unique identifier.
93***********************************************************************/
94static int
95packetIsForMe(PPPoEConnection *conn, PPPoEPacket *packet)
96{
97    int forMe = 0;
98
99    /* If packet is not directed to our MAC address, forget it */
100    if (memcmp(packet->ethHdr.h_dest, conn->myEth, ETH_ALEN)) return 0;
101
102    /* If we're not using the Host-Unique tag, then accept the packet */
103    if (!conn->useHostUniq) return 1;
104
105    parsePacket(packet, parseForHostUniq, &forMe);
106    return forMe;
107}
108
109/**********************************************************************
110*%FUNCTION: parsePADOTags
111*%ARGUMENTS:
112* type -- tag type
113* len -- tag length
114* data -- tag data
115* extra -- extra user data.  Should point to a PacketCriteria structure
116*          which gets filled in according to selected AC name and service
117*          name.
118*%RETURNS:
119* Nothing
120*%DESCRIPTION:
121* Picks interesting tags out of a PADO packet
122***********************************************************************/
123static void
124parsePADOTags(UINT16_t type, UINT16_t len, unsigned char *data,
125	      void *extra)
126{
127    struct PacketCriteria *pc = (struct PacketCriteria *) extra;
128    PPPoEConnection *conn = pc->conn;
129    int i;
130#ifdef PLUGIN
131    UINT16_t mru;
132#endif
133
134    switch(type) {
135    case TAG_AC_NAME:
136	pc->seenACName = 1;
137	if (conn->printACNames) {
138	    printf("Access-Concentrator: %.*s\n", (int) len, data);
139	}
140	if (conn->acName && len == strlen(conn->acName) &&
141	    !strncmp((char *) data, conn->acName, len)) {
142	    pc->acNameOK = 1;
143	}
144	break;
145    case TAG_SERVICE_NAME:
146	pc->seenServiceName = 1;
147	if (conn->printACNames && len > 0) {
148	    printf("       Service-Name: %.*s\n", (int) len, data);
149	}
150	if (conn->serviceName && len == strlen(conn->serviceName) &&
151	    !strncmp((char *) data, conn->serviceName, len)) {
152	    pc->serviceNameOK = 1;
153	}
154	break;
155    case TAG_AC_COOKIE:
156	if (conn->printACNames) {
157	    printf("Got a cookie:");
158	    /* Print first 20 bytes of cookie */
159	    for (i=0; i<len && i < 20; i++) {
160		printf(" %02x", (unsigned) data[i]);
161	    }
162	    if (i < len) printf("...");
163	    printf("\n");
164	}
165	conn->cookie.type = htons(type);
166	conn->cookie.length = htons(len);
167	memcpy(conn->cookie.payload, data, len);
168	break;
169    case TAG_RELAY_SESSION_ID:
170	if (conn->printACNames) {
171	    printf("Got a Relay-ID:");
172	    /* Print first 20 bytes of relay ID */
173	    for (i=0; i<len && i < 20; i++) {
174		printf(" %02x", (unsigned) data[i]);
175	    }
176	    if (i < len) printf("...");
177	    printf("\n");
178	}
179	conn->relayId.type = htons(type);
180	conn->relayId.length = htons(len);
181	memcpy(conn->relayId.payload, data, len);
182	break;
183    case TAG_SERVICE_NAME_ERROR:
184	if (conn->printACNames) {
185	    printf("Got a Service-Name-Error tag: %.*s\n", (int) len, data);
186	} else {
187	    pktLogErrs("PADO", type, len, data, extra);
188	    pc->gotError = 1;
189	    if (!persist) {
190		exit(1);
191	    }
192	}
193	break;
194    case TAG_AC_SYSTEM_ERROR:
195	if (conn->printACNames) {
196	    printf("Got a System-Error tag: %.*s\n", (int) len, data);
197	} else {
198	    pktLogErrs("PADO", type, len, data, extra);
199	    pc->gotError = 1;
200	    if (!persist) {
201		exit(1);
202	    }
203	}
204	break;
205    case TAG_GENERIC_ERROR:
206	if (conn->printACNames) {
207	    printf("Got a Generic-Error tag: %.*s\n", (int) len, data);
208	} else {
209	    pktLogErrs("PADO", type, len, data, extra);
210	    pc->gotError = 1;
211	    if (!persist) {
212		exit(1);
213	    }
214	}
215	break;
216#ifdef PLUGIN
217    case TAG_PPP_MAX_PAYLOAD:
218	if (len == sizeof(mru)) {
219	    memcpy(&mru, data, sizeof(mru));
220	    mru = ntohs(mru);
221	    if (mru >= ETH_PPPOE_MTU) {
222		if (lcp_allowoptions[0].mru > mru) lcp_allowoptions[0].mru = mru;
223               if (lcp_wantoptions[0].mru > mru) lcp_wantoptions[0].mru = mru;
224               conn->seenMaxPayload = 1;
225	    }
226	}
227	break;
228#endif
229    }
230}
231
232/**********************************************************************
233*%FUNCTION: parsePADSTags
234*%ARGUMENTS:
235* type -- tag type
236* len -- tag length
237* data -- tag data
238* extra -- extra user data (pointer to PPPoEConnection structure)
239*%RETURNS:
240* Nothing
241*%DESCRIPTION:
242* Picks interesting tags out of a PADS packet
243***********************************************************************/
244static void
245parsePADSTags(UINT16_t type, UINT16_t len, unsigned char *data,
246	      void *extra)
247{
248#ifdef PLUGIN
249    UINT16_t mru;
250#endif
251    PPPoEConnection *conn = (PPPoEConnection *) extra;
252    switch(type) {
253    case TAG_SERVICE_NAME:
254	syslog(LOG_DEBUG, "PADS: Service-Name: '%.*s'", (int) len, data);
255	break;
256    case TAG_GENERIC_ERROR:
257    case TAG_AC_SYSTEM_ERROR:
258    case TAG_SERVICE_NAME_ERROR:
259	pktLogErrs("PADS", type, len, data, extra);
260	conn->PADSHadError = 1;
261	break;
262    case TAG_RELAY_SESSION_ID:
263	conn->relayId.type = htons(type);
264	conn->relayId.length = htons(len);
265	memcpy(conn->relayId.payload, data, len);
266	break;
267#ifdef PLUGIN
268    case TAG_PPP_MAX_PAYLOAD:
269	if (len == sizeof(mru)) {
270	    memcpy(&mru, data, sizeof(mru));
271	    mru = ntohs(mru);
272	    if (mru >= ETH_PPPOE_MTU) {
273		if (lcp_allowoptions[0].mru > mru) lcp_allowoptions[0].mru = mru;
274               if (lcp_wantoptions[0].mru > mru) lcp_wantoptions[0].mru = mru;
275               conn->seenMaxPayload = 1;
276	    }
277	}
278	break;
279#endif
280    }
281}
282
283/***********************************************************************
284*%FUNCTION: sendPADI
285*%ARGUMENTS:
286* conn -- PPPoEConnection structure
287*%RETURNS:
288* Nothing
289*%DESCRIPTION:
290* Sends a PADI packet
291***********************************************************************/
292static void
293sendPADI(PPPoEConnection *conn)
294{
295    PPPoEPacket packet;
296    unsigned char *cursor = packet.payload;
297    PPPoETag *svc = (PPPoETag *) (&packet.payload);
298    UINT16_t namelen = 0;
299    UINT16_t plen;
300    int omit_service_name = 0;
301
302    if (conn->serviceName) {
303	namelen = (UINT16_t) strlen(conn->serviceName);
304	if (!strcmp(conn->serviceName, "NO-SERVICE-NAME-NON-RFC-COMPLIANT")) {
305	    omit_service_name = 1;
306	}
307    }
308
309    /* Set destination to Ethernet broadcast address */
310    memset(packet.ethHdr.h_dest, 0xFF, ETH_ALEN);
311    memcpy(packet.ethHdr.h_source, conn->myEth, ETH_ALEN);
312
313    packet.ethHdr.h_proto = htons(Eth_PPPOE_Discovery);
314    packet.ver = 1;
315    packet.type = 1;
316    packet.code = CODE_PADI;
317    packet.session = 0;
318
319    if (!omit_service_name) {
320	plen = TAG_HDR_SIZE + namelen;
321	CHECK_ROOM(cursor, packet.payload, plen);
322
323	svc->type = TAG_SERVICE_NAME;
324	svc->length = htons(namelen);
325
326	if (conn->serviceName) {
327	    memcpy(svc->payload, conn->serviceName, strlen(conn->serviceName));
328	}
329	cursor += namelen + TAG_HDR_SIZE;
330    } else {
331	plen = 0;
332    }
333
334    /* If we're using Host-Uniq, copy it over */
335    if (conn->useHostUniq) {
336	PPPoETag hostUniq;
337	pid_t pid = getpid();
338	hostUniq.type = htons(TAG_HOST_UNIQ);
339	hostUniq.length = htons(sizeof(pid));
340	memcpy(hostUniq.payload, &pid, sizeof(pid));
341	CHECK_ROOM(cursor, packet.payload, sizeof(pid) + TAG_HDR_SIZE);
342	memcpy(cursor, &hostUniq, sizeof(pid) + TAG_HDR_SIZE);
343	cursor += sizeof(pid) + TAG_HDR_SIZE;
344	plen += sizeof(pid) + TAG_HDR_SIZE;
345    }
346
347#ifdef PLUGIN
348    /* Add our maximum MTU/MRU */
349    if (MIN(lcp_allowoptions[0].mru, lcp_wantoptions[0].mru) > ETH_PPPOE_MTU) {
350	PPPoETag maxPayload;
351	UINT16_t mru = htons(MIN(lcp_allowoptions[0].mru, lcp_wantoptions[0].mru));
352	maxPayload.type = htons(TAG_PPP_MAX_PAYLOAD);
353	maxPayload.length = htons(sizeof(mru));
354	memcpy(maxPayload.payload, &mru, sizeof(mru));
355	CHECK_ROOM(cursor, packet.payload, sizeof(mru) + TAG_HDR_SIZE);
356	memcpy(cursor, &maxPayload, sizeof(mru) + TAG_HDR_SIZE);
357	cursor += sizeof(mru) + TAG_HDR_SIZE;
358	plen += sizeof(mru) + TAG_HDR_SIZE;
359    }
360#endif
361
362    packet.length = htons(plen);
363
364    sendPacket(conn, conn->discoverySocket, &packet, (int) (plen + HDR_SIZE));
365#ifdef DEBUGGING_ENABLED
366    if (conn->debugFile) {
367	dumpPacket(conn->debugFile, &packet, "SENT");
368	fprintf(conn->debugFile, "\n");
369	fflush(conn->debugFile);
370    }
371#endif
372}
373
374/**********************************************************************
375*%FUNCTION: waitForPADO
376*%ARGUMENTS:
377* conn -- PPPoEConnection structure
378* timeout -- how long to wait (in seconds)
379*%RETURNS:
380* Nothing
381*%DESCRIPTION:
382* Waits for a PADO packet and copies useful information
383***********************************************************************/
384static void
385waitForPADO(PPPoEConnection *conn, int timeout)
386{
387    fd_set readable;
388    int r;
389    struct timeval tv;
390    struct timeval expire_at;
391    struct timeval now;
392
393    PPPoEPacket packet;
394    int len;
395
396    struct PacketCriteria pc;
397    pc.conn          = conn;
398#ifdef PLUGIN
399    conn->seenMaxPayload = 0;
400#endif
401
402    if (gettimeofday(&expire_at, NULL) < 0) {
403	fatalSys("gettimeofday (waitForPADO)");
404    }
405    expire_at.tv_sec += timeout;
406
407    do {
408#ifdef PLUGIN
409	if (got_sigterm || got_sighup) return;
410#endif
411	if (BPF_BUFFER_IS_EMPTY) {
412	    if (gettimeofday(&now, NULL) < 0) {
413		fatalSys("gettimeofday (waitForPADO)");
414	    }
415	    tv.tv_sec = expire_at.tv_sec - now.tv_sec;
416	    tv.tv_usec = expire_at.tv_usec - now.tv_usec;
417	    if (tv.tv_usec < 0) {
418		tv.tv_usec += 1000000;
419		if (tv.tv_sec) {
420		    tv.tv_sec--;
421		} else {
422		    /* Timed out */
423		    return;
424		}
425	    }
426	    if (tv.tv_sec <= 0 && tv.tv_usec <= 0) {
427		/* Timed out */
428		return;
429	    }
430
431	    FD_ZERO(&readable);
432	    FD_SET(conn->discoverySocket, &readable);
433
434	    while(1) {
435		r = select(conn->discoverySocket+1, &readable, NULL, NULL, &tv);
436		if (r >= 0 || errno != EINTR) break;
437#ifdef PLUGIN
438		if (got_sigterm || got_sighup) return;
439#endif
440	    }
441	    if (r < 0) {
442		fatalSys("select (waitForPADO)");
443	    }
444	    if (r == 0) {
445		/* Timed out */
446		return;
447	    }
448	}
449
450	/* Get the packet */
451	receivePacket(conn->discoverySocket, &packet, &len);
452
453	/* Check length */
454	if (ntohs(packet.length) + HDR_SIZE > len) {
455	    syslog(LOG_ERR, "Bogus PPPoE length field (%u)",
456		   (unsigned int) ntohs(packet.length));
457	    continue;
458	}
459
460#ifdef USE_BPF
461	/* If it's not a Discovery packet, loop again */
462	if (etherType(&packet) != Eth_PPPOE_Discovery) continue;
463#endif
464
465#ifdef DEBUGGING_ENABLED
466	if (conn->debugFile) {
467	    dumpPacket(conn->debugFile, &packet, "RCVD");
468	    fprintf(conn->debugFile, "\n");
469	    fflush(conn->debugFile);
470	}
471#endif
472	/* If it's not for us, loop again */
473	if (!packetIsForMe(conn, &packet)) continue;
474
475	if (packet.code == CODE_PADO) {
476	    if (BROADCAST(packet.ethHdr.h_source)) {
477		printErr("Ignoring PADO packet from broadcast MAC address");
478		continue;
479	    }
480#ifdef PLUGIN
481	    if (conn->req_peer
482		&& memcmp(packet.ethHdr.h_source, conn->req_peer_mac, ETH_ALEN) != 0) {
483		warn("Ignoring PADO packet from wrong MAC address");
484		continue;
485	    }
486#endif
487	    pc.gotError = 0;
488	    pc.seenACName    = 0;
489	    pc.seenServiceName = 0;
490	    pc.acNameOK      = (conn->acName)      ? 0 : 1;
491	    pc.serviceNameOK = (conn->serviceName) ? 0 : 1;
492	    parsePacket(&packet, parsePADOTags, &pc);
493	    if (pc.gotError) {
494		printErr("Error in PADO packet");
495		continue;
496	    }
497
498	    if (!pc.seenACName) {
499		printErr("Ignoring PADO packet with no AC-Name tag");
500		continue;
501	    }
502	    if (!pc.seenServiceName) {
503		printErr("Ignoring PADO packet with no Service-Name tag");
504		continue;
505	    }
506	    conn->numPADOs++;
507	    if (pc.acNameOK && pc.serviceNameOK) {
508		memcpy(conn->peerEth, packet.ethHdr.h_source, ETH_ALEN);
509		if (conn->printACNames) {
510		    printf("AC-Ethernet-Address: %02x:%02x:%02x:%02x:%02x:%02x\n",
511			   (unsigned) conn->peerEth[0],
512			   (unsigned) conn->peerEth[1],
513			   (unsigned) conn->peerEth[2],
514			   (unsigned) conn->peerEth[3],
515			   (unsigned) conn->peerEth[4],
516			   (unsigned) conn->peerEth[5]);
517		    printf("--------------------------------------------------\n");
518		    continue;
519		}
520		conn->discoveryState = STATE_RECEIVED_PADO;
521		break;
522	    }
523	}
524    } while (conn->discoveryState != STATE_RECEIVED_PADO);
525}
526
527/***********************************************************************
528*%FUNCTION: sendPADR
529*%ARGUMENTS:
530* conn -- PPPoE connection structur
531*%RETURNS:
532* Nothing
533*%DESCRIPTION:
534* Sends a PADR packet
535***********************************************************************/
536static void
537sendPADR(PPPoEConnection *conn)
538{
539    PPPoEPacket packet;
540    PPPoETag *svc = (PPPoETag *) packet.payload;
541    unsigned char *cursor = packet.payload;
542
543    UINT16_t namelen = 0;
544    UINT16_t plen;
545
546    if (conn->serviceName) {
547	namelen = (UINT16_t) strlen(conn->serviceName);
548    }
549    plen = TAG_HDR_SIZE + namelen;
550    CHECK_ROOM(cursor, packet.payload, plen);
551
552    memcpy(packet.ethHdr.h_dest, conn->peerEth, ETH_ALEN);
553    memcpy(packet.ethHdr.h_source, conn->myEth, ETH_ALEN);
554
555    packet.ethHdr.h_proto = htons(Eth_PPPOE_Discovery);
556    packet.ver = 1;
557    packet.type = 1;
558    packet.code = CODE_PADR;
559    packet.session = 0;
560
561    svc->type = TAG_SERVICE_NAME;
562    svc->length = htons(namelen);
563    if (conn->serviceName) {
564	memcpy(svc->payload, conn->serviceName, namelen);
565    }
566    cursor += namelen + TAG_HDR_SIZE;
567
568    /* If we're using Host-Uniq, copy it over */
569    if (conn->useHostUniq) {
570	PPPoETag hostUniq;
571	pid_t pid = getpid();
572	hostUniq.type = htons(TAG_HOST_UNIQ);
573	hostUniq.length = htons(sizeof(pid));
574	memcpy(hostUniq.payload, &pid, sizeof(pid));
575	CHECK_ROOM(cursor, packet.payload, sizeof(pid)+TAG_HDR_SIZE);
576	memcpy(cursor, &hostUniq, sizeof(pid) + TAG_HDR_SIZE);
577	cursor += sizeof(pid) + TAG_HDR_SIZE;
578	plen += sizeof(pid) + TAG_HDR_SIZE;
579    }
580
581    /* Copy cookie and relay-ID if needed */
582    if (conn->cookie.type) {
583	CHECK_ROOM(cursor, packet.payload,
584		   ntohs(conn->cookie.length) + TAG_HDR_SIZE);
585	memcpy(cursor, &conn->cookie, ntohs(conn->cookie.length) + TAG_HDR_SIZE);
586	cursor += ntohs(conn->cookie.length) + TAG_HDR_SIZE;
587	plen += ntohs(conn->cookie.length) + TAG_HDR_SIZE;
588    }
589
590    if (conn->relayId.type) {
591	CHECK_ROOM(cursor, packet.payload,
592		   ntohs(conn->relayId.length) + TAG_HDR_SIZE);
593	memcpy(cursor, &conn->relayId, ntohs(conn->relayId.length) + TAG_HDR_SIZE);
594	cursor += ntohs(conn->relayId.length) + TAG_HDR_SIZE;
595	plen += ntohs(conn->relayId.length) + TAG_HDR_SIZE;
596    }
597
598#ifdef PLUGIN
599    /* Add our maximum MTU/MRU */
600    if (MIN(lcp_allowoptions[0].mru, lcp_wantoptions[0].mru) > ETH_PPPOE_MTU) {
601	PPPoETag maxPayload;
602	UINT16_t mru = htons(MIN(lcp_allowoptions[0].mru, lcp_wantoptions[0].mru));
603	maxPayload.type = htons(TAG_PPP_MAX_PAYLOAD);
604	maxPayload.length = htons(sizeof(mru));
605	memcpy(maxPayload.payload, &mru, sizeof(mru));
606	CHECK_ROOM(cursor, packet.payload, sizeof(mru) + TAG_HDR_SIZE);
607	memcpy(cursor, &maxPayload, sizeof(mru) + TAG_HDR_SIZE);
608	cursor += sizeof(mru) + TAG_HDR_SIZE;
609	plen += sizeof(mru) + TAG_HDR_SIZE;
610    }
611#endif
612
613    packet.length = htons(plen);
614    sendPacket(conn, conn->discoverySocket, &packet, (int) (plen + HDR_SIZE));
615#ifdef DEBUGGING_ENABLED
616    if (conn->debugFile) {
617	dumpPacket(conn->debugFile, &packet, "SENT");
618	fprintf(conn->debugFile, "\n");
619	fflush(conn->debugFile);
620    }
621#endif
622}
623
624/**********************************************************************
625*%FUNCTION: waitForPADS
626*%ARGUMENTS:
627* conn -- PPPoE connection info
628* timeout -- how long to wait (in seconds)
629*%RETURNS:
630* Nothing
631*%DESCRIPTION:
632* Waits for a PADS packet and copies useful information
633***********************************************************************/
634static void
635waitForPADS(PPPoEConnection *conn, int timeout)
636{
637    fd_set readable;
638    int r;
639    struct timeval tv;
640    struct timeval expire_at;
641    struct timeval now;
642
643    PPPoEPacket packet;
644    int len;
645
646    if (gettimeofday(&expire_at, NULL) < 0) {
647	fatalSys("gettimeofday (waitForPADS)");
648    }
649    expire_at.tv_sec += timeout;
650
651    do {
652#ifdef PLUGIN
653	if (got_sigterm || got_sighup) return;
654#endif
655	if (BPF_BUFFER_IS_EMPTY) {
656	    if (gettimeofday(&now, NULL) < 0) {
657		fatalSys("gettimeofday (waitForPADS)");
658	    }
659	    tv.tv_sec = expire_at.tv_sec - now.tv_sec;
660	    tv.tv_usec = expire_at.tv_usec - now.tv_usec;
661	    if (tv.tv_usec < 0) {
662		tv.tv_usec += 1000000;
663		if (tv.tv_sec) {
664		    tv.tv_sec--;
665		} else {
666		    /* Timed out */
667		    return;
668		}
669	    }
670	    if (tv.tv_sec <= 0 && tv.tv_usec <= 0) {
671		/* Timed out */
672		return;
673	    }
674
675	    FD_ZERO(&readable);
676	    FD_SET(conn->discoverySocket, &readable);
677
678	    while(1) {
679		r = select(conn->discoverySocket+1, &readable, NULL, NULL, &tv);
680		if (r >= 0 || errno != EINTR) break;
681#ifdef PLUGIN
682		if (got_sigterm || got_sighup) return;
683#endif
684	    }
685	    if (r < 0) {
686		fatalSys("select (waitForPADS)");
687	    }
688	    if (r == 0) {
689		/* Timed out */
690		return;
691	    }
692	}
693
694	/* Get the packet */
695	receivePacket(conn->discoverySocket, &packet, &len);
696
697	/* Check length */
698	if (ntohs(packet.length) + HDR_SIZE > len) {
699	    syslog(LOG_ERR, "Bogus PPPoE length field (%u)",
700		   (unsigned int) ntohs(packet.length));
701	    continue;
702	}
703
704#ifdef USE_BPF
705	/* If it's not a Discovery packet, loop again */
706	if (etherType(&packet) != Eth_PPPOE_Discovery) continue;
707#endif
708#ifdef DEBUGGING_ENABLED
709	if (conn->debugFile) {
710	    dumpPacket(conn->debugFile, &packet, "RCVD");
711	    fprintf(conn->debugFile, "\n");
712	    fflush(conn->debugFile);
713	}
714#endif
715	/* If it's not from the AC, it's not for me */
716	if (memcmp(packet.ethHdr.h_source, conn->peerEth, ETH_ALEN)) continue;
717
718	/* If it's not for us, loop again */
719	if (!packetIsForMe(conn, &packet)) continue;
720
721	/* Is it PADS?  */
722	if (packet.code == CODE_PADS) {
723	    /* Parse for goodies */
724	    conn->PADSHadError = 0;
725	    parsePacket(&packet, parsePADSTags, conn);
726	    if (!conn->PADSHadError) {
727		conn->discoveryState = STATE_SESSION;
728		break;
729	    }
730	}
731    } while (conn->discoveryState != STATE_SESSION);
732
733    /* Don't bother with ntohs; we'll just end up converting it back... */
734    conn->session = packet.session;
735
736    syslog(LOG_INFO, "PPP session is %d (0x%x)", (int) ntohs(conn->session),
737	   (unsigned int) ntohs(conn->session));
738
739    /* RFC 2516 says session id MUST NOT be zero or 0xFFFF */
740    if (ntohs(conn->session) == 0 || ntohs(conn->session) == 0xFFFF) {
741	syslog(LOG_ERR, "Access concentrator used a session value of %x -- the AC is violating RFC 2516", (unsigned int) ntohs(conn->session));
742    }
743}
744
745/**********************************************************************
746*%FUNCTION: discovery
747*%ARGUMENTS:
748* conn -- PPPoE connection info structure
749*%RETURNS:
750* Nothing
751*%DESCRIPTION:
752* Performs the PPPoE discovery phase
753***********************************************************************/
754void
755discovery(PPPoEConnection *conn)
756{
757    int padiAttempts;
758    int padrAttempts;
759    int timeout = conn->discoveryTimeout;
760
761    /* Skip discovery? */
762    if (conn->skipDiscovery) {
763	conn->discoveryState = STATE_SESSION;
764	if (conn->killSession) {
765	    sendPADT(conn, "RP-PPPoE: Session killed manually");
766	    exit(0);
767	}
768	return;
769    }
770
771  SEND_PADI:
772    padiAttempts = 0;
773    do {
774#ifdef PLUGIN
775	if (got_sigterm || got_sighup) return;
776#endif
777	padiAttempts++;
778	if (padiAttempts > MAX_PADI_ATTEMPTS) {
779	    if (persist) {
780		padiAttempts = 0;
781		timeout = conn->discoveryTimeout;
782		printErr("Timeout waiting for PADO packets");
783	    } else {
784#ifdef PLUGIN
785		printErr("Timeout waiting for PADO packets");
786		return;
787#else
788		rp_fatal("Timeout waiting for PADO packets");
789#endif
790	    }
791	}
792	sendPADI(conn);
793	conn->discoveryState = STATE_SENT_PADI;
794	waitForPADO(conn, timeout);
795
796	/* If we're just probing for access concentrators, don't do
797	   exponential backoff.  This reduces the time for an unsuccessful
798	   probe to 15 seconds. */
799	if (!conn->printACNames) {
800	    timeout *= 2;
801	}
802	if (conn->printACNames && conn->numPADOs) {
803	    break;
804	}
805    } while (conn->discoveryState == STATE_SENT_PADI);
806
807    /* If we're only printing access concentrator names, we're done */
808    if (conn->printACNames) {
809	exit(0);
810    }
811
812    timeout = conn->discoveryTimeout;
813    padrAttempts = 0;
814    do {
815#ifdef PLUGIN
816	if (got_sigterm || got_sighup) return;
817#endif
818	padrAttempts++;
819	if (padrAttempts > MAX_PADI_ATTEMPTS) {
820	    if (persist) {
821		padrAttempts = 0;
822		timeout = conn->discoveryTimeout;
823		printErr("Timeout waiting for PADS packets");
824		/* Go back to sending PADI again */
825		goto SEND_PADI;
826	    } else {
827#ifdef PLUGIN
828		printErr("Timeout waiting for PADS packets");
829		return;
830#else
831		rp_fatal("Timeout waiting for PADS packets");
832#endif
833	    }
834	}
835	sendPADR(conn);
836	conn->discoveryState = STATE_SENT_PADR;
837	waitForPADS(conn, timeout);
838	timeout *= 2;
839    } while (conn->discoveryState == STATE_SENT_PADR);
840
841#ifdef PLUGIN
842    if (!conn->seenMaxPayload) {
843	/* RFC 4638: MUST limit MTU/MRU to 1492 */
844	if (lcp_allowoptions[0].mru > ETH_PPPOE_MTU) lcp_allowoptions[0].mru = ETH_PPPOE_MTU;
845	if (lcp_wantoptions[0].mru > ETH_PPPOE_MTU)  lcp_wantoptions[0].mru = ETH_PPPOE_MTU;
846    }
847#endif
848    /* We're done. */
849    conn->discoveryState = STATE_SESSION;
850    return;
851}
852