1 /***********************************************************************
5 * Perform PPPoE discovery
7 * Copyright (C) 1999 by Roaring Penguin Software Inc.
9 ***********************************************************************/
11 static char const RCSID
[] =
12 "$Id: discovery.c,v 1.6 2008/06/15 04:35:50 paulus Exp $";
16 #include "pppd/pppd.h"
24 #ifdef HAVE_SYS_TIME_H
37 #ifdef USE_LINUX_PACKET
38 #include <sys/ioctl.h>
44 /**********************************************************************
45 *%FUNCTION: parseForHostUniq
50 * extra -- user-supplied pointer. This is assumed to be a pointer to int.
54 * If a HostUnique tag is found which matches our PID, sets *extra to 1.
55 ***********************************************************************/
57 parseForHostUniq(UINT16_t type
, UINT16_t len
, unsigned char *data
,
60 int *val
= (int *) extra
;
61 if (type
== TAG_HOST_UNIQ
&& len
== sizeof(pid_t
)) {
63 memcpy(&tmp
, data
, len
);
64 if (tmp
== getpid()) {
70 /**********************************************************************
71 *%FUNCTION: packetIsForMe
73 * conn -- PPPoE connection info
74 * packet -- a received PPPoE packet
76 * 1 if packet is for this PPPoE daemon; 0 otherwise.
78 * If we are using the Host-Unique tag, verifies that packet contains
79 * our unique identifier.
80 ***********************************************************************/
82 packetIsForMe(PPPoEConnection
*conn
, PPPoEPacket
*packet
)
86 /* If packet is not directed to our MAC address, forget it */
87 if (memcmp(packet
->ethHdr
.h_dest
, conn
->myEth
, ETH_ALEN
)) return 0;
89 /* If we're not using the Host-Unique tag, then accept the packet */
90 if (!conn
->useHostUniq
) return 1;
92 parsePacket(packet
, parseForHostUniq
, &forMe
);
96 /**********************************************************************
97 *%FUNCTION: parsePADOTags
102 * extra -- extra user data. Should point to a PacketCriteria structure
103 * which gets filled in according to selected AC name and service
108 * Picks interesting tags out of a PADO packet
109 ***********************************************************************/
111 parsePADOTags(UINT16_t type
, UINT16_t len
, unsigned char *data
,
114 struct PacketCriteria
*pc
= (struct PacketCriteria
*) extra
;
115 PPPoEConnection
*conn
= pc
->conn
;
122 if (conn
->printACNames
) {
123 info("Access-Concentrator: %.*s", (int) len
, data
);
125 if (conn
->acName
&& len
== strlen(conn
->acName
) &&
126 !strncmp((char *) data
, conn
->acName
, len
)) {
130 case TAG_SERVICE_NAME
:
131 pc
->seenServiceName
= 1;
132 if (conn
->serviceName
&& len
== strlen(conn
->serviceName
) &&
133 !strncmp((char *) data
, conn
->serviceName
, len
)) {
134 pc
->serviceNameOK
= 1;
138 conn
->cookie
.type
= htons(type
);
139 conn
->cookie
.length
= htons(len
);
140 memcpy(conn
->cookie
.payload
, data
, len
);
142 case TAG_RELAY_SESSION_ID
:
143 conn
->relayId
.type
= htons(type
);
144 conn
->relayId
.length
= htons(len
);
145 memcpy(conn
->relayId
.payload
, data
, len
);
147 case TAG_PPP_MAX_PAYLOAD
:
148 if (len
== sizeof(mru
)) {
149 memcpy(&mru
, data
, sizeof(mru
));
151 if (mru
>= ETH_PPPOE_MTU
) {
152 if (lcp_allowoptions
[0].mru
> mru
)
153 lcp_allowoptions
[0].mru
= mru
;
154 if (lcp_wantoptions
[0].mru
> mru
)
155 lcp_wantoptions
[0].mru
= mru
;
156 conn
->seenMaxPayload
= 1;
160 case TAG_SERVICE_NAME_ERROR
:
161 error("PADO: Service-Name-Error: %.*s", (int) len
, data
);
164 case TAG_AC_SYSTEM_ERROR
:
165 error("PADO: System-Error: %.*s", (int) len
, data
);
168 case TAG_GENERIC_ERROR
:
169 error("PADO: Generic-Error: %.*s", (int) len
, data
);
175 /**********************************************************************
176 *%FUNCTION: parsePADSTags
181 * extra -- extra user data (pointer to PPPoEConnection structure)
185 * Picks interesting tags out of a PADS packet
186 ***********************************************************************/
188 parsePADSTags(UINT16_t type
, UINT16_t len
, unsigned char *data
,
191 PPPoEConnection
*conn
= (PPPoEConnection
*) extra
;
194 case TAG_SERVICE_NAME
:
195 dbglog("PADS: Service-Name: '%.*s'", (int) len
, data
);
197 case TAG_PPP_MAX_PAYLOAD
:
198 if (len
== sizeof(mru
)) {
199 memcpy(&mru
, data
, sizeof(mru
));
201 if (mru
>= ETH_PPPOE_MTU
) {
202 if (lcp_allowoptions
[0].mru
> mru
)
203 lcp_allowoptions
[0].mru
= mru
;
204 if (lcp_wantoptions
[0].mru
> mru
)
205 lcp_wantoptions
[0].mru
= mru
;
206 conn
->seenMaxPayload
= 1;
210 case TAG_SERVICE_NAME_ERROR
:
211 error("PADS: Service-Name-Error: %.*s", (int) len
, data
);
214 case TAG_AC_SYSTEM_ERROR
:
215 error("PADS: System-Error: %.*s", (int) len
, data
);
218 case TAG_GENERIC_ERROR
:
219 error("PADS: Generic-Error: %.*s", (int) len
, data
);
222 case TAG_RELAY_SESSION_ID
:
223 conn
->relayId
.type
= htons(type
);
224 conn
->relayId
.length
= htons(len
);
225 memcpy(conn
->relayId
.payload
, data
, len
);
230 /***********************************************************************
233 * conn -- PPPoEConnection structure
237 * Sends a PADI packet
238 ***********************************************************************/
240 sendPADI(PPPoEConnection
*conn
)
243 unsigned char *cursor
= packet
.payload
;
244 PPPoETag
*svc
= (PPPoETag
*) (&packet
.payload
);
245 UINT16_t namelen
= 0;
247 int omit_service_name
= 0;
249 if (conn
->serviceName
) {
250 namelen
= (UINT16_t
) strlen(conn
->serviceName
);
251 if (!strcmp(conn
->serviceName
, "NO-SERVICE-NAME-NON-RFC-COMPLIANT")) {
252 omit_service_name
= 1;
256 /* Set destination to Ethernet broadcast address */
257 memset(packet
.ethHdr
.h_dest
, 0xFF, ETH_ALEN
);
258 memcpy(packet
.ethHdr
.h_source
, conn
->myEth
, ETH_ALEN
);
260 packet
.ethHdr
.h_proto
= htons(Eth_PPPOE_Discovery
);
261 packet
.vertype
= PPPOE_VER_TYPE(1, 1);
262 packet
.code
= CODE_PADI
;
265 if (!omit_service_name
) {
266 plen
= TAG_HDR_SIZE
+ namelen
;
267 CHECK_ROOM(cursor
, packet
.payload
, plen
);
269 svc
->type
= TAG_SERVICE_NAME
;
270 svc
->length
= htons(namelen
);
272 if (conn
->serviceName
) {
273 memcpy(svc
->payload
, conn
->serviceName
, strlen(conn
->serviceName
));
275 cursor
+= namelen
+ TAG_HDR_SIZE
;
280 /* If we're using Host-Uniq, copy it over */
281 if (conn
->useHostUniq
) {
283 pid_t pid
= getpid();
284 hostUniq
.type
= htons(TAG_HOST_UNIQ
);
285 hostUniq
.length
= htons(sizeof(pid
));
286 memcpy(hostUniq
.payload
, &pid
, sizeof(pid
));
287 CHECK_ROOM(cursor
, packet
.payload
, sizeof(pid
) + TAG_HDR_SIZE
);
288 memcpy(cursor
, &hostUniq
, sizeof(pid
) + TAG_HDR_SIZE
);
289 cursor
+= sizeof(pid
) + TAG_HDR_SIZE
;
290 plen
+= sizeof(pid
) + TAG_HDR_SIZE
;
293 /* Add our maximum MTU/MRU */
294 if (MIN(lcp_allowoptions
[0].mru
, lcp_wantoptions
[0].mru
) > ETH_PPPOE_MTU
) {
296 UINT16_t mru
= htons(MIN(lcp_allowoptions
[0].mru
, lcp_wantoptions
[0].mru
));
297 maxPayload
.type
= htons(TAG_PPP_MAX_PAYLOAD
);
298 maxPayload
.length
= htons(sizeof(mru
));
299 memcpy(maxPayload
.payload
, &mru
, sizeof(mru
));
300 CHECK_ROOM(cursor
, packet
.payload
, sizeof(mru
) + TAG_HDR_SIZE
);
301 memcpy(cursor
, &maxPayload
, sizeof(mru
) + TAG_HDR_SIZE
);
302 cursor
+= sizeof(mru
) + TAG_HDR_SIZE
;
303 plen
+= sizeof(mru
) + TAG_HDR_SIZE
;
306 packet
.length
= htons(plen
);
308 sendPacket(conn
, conn
->discoverySocket
, &packet
, (int) (plen
+ HDR_SIZE
));
311 /**********************************************************************
312 *%FUNCTION: waitForPADO
314 * conn -- PPPoEConnection structure
315 * timeout -- how long to wait (in seconds)
319 * Waits for a PADO packet and copies useful information
320 ***********************************************************************/
322 waitForPADO(PPPoEConnection
*conn
, int timeout
)
327 struct timeval expire_at
;
333 struct PacketCriteria pc
;
335 pc
.acNameOK
= (conn
->acName
) ? 0 : 1;
336 pc
.serviceNameOK
= (conn
->serviceName
) ? 0 : 1;
338 pc
.seenServiceName
= 0;
339 conn
->seenMaxPayload
= 0;
342 if (gettimeofday(&expire_at
, NULL
) < 0) {
343 fatalSys("gettimeofday (waitForPADO)");
345 expire_at
.tv_sec
+= timeout
;
348 if (BPF_BUFFER_IS_EMPTY
) {
349 if (gettimeofday(&now
, NULL
) < 0) {
350 fatalSys("gettimeofday (waitForPADO)");
352 tv
.tv_sec
= expire_at
.tv_sec
- now
.tv_sec
;
353 tv
.tv_usec
= expire_at
.tv_usec
- now
.tv_usec
;
354 if (tv
.tv_usec
< 0) {
355 tv
.tv_usec
+= 1000000;
363 if (tv
.tv_sec
<= 0 && tv
.tv_usec
<= 0) {
369 FD_SET(conn
->discoverySocket
, &readable
);
372 r
= select(conn
->discoverySocket
+1, &readable
, NULL
, NULL
, &tv
);
373 if (r
>= 0 || errno
!= EINTR
) break;
376 error("select (waitForPADO): %m");
386 receivePacket(conn
->discoverySocket
, &packet
, &len
);
389 if (ntohs(packet
.length
) + HDR_SIZE
> len
) {
390 error("Bogus PPPoE length field (%u)",
391 (unsigned int) ntohs(packet
.length
));
396 /* If it's not a Discovery packet, loop again */
397 if (etherType(&packet
) != Eth_PPPOE_Discovery
) continue;
400 /* If it's not for us, loop again */
401 if (!packetIsForMe(conn
, &packet
)) continue;
403 if (packet
.code
== CODE_PADO
) {
404 if (BROADCAST(packet
.ethHdr
.h_source
)) {
405 error("Ignoring PADO packet from broadcast MAC address");
409 && memcmp(packet
.ethHdr
.h_source
, conn
->req_peer_mac
, ETH_ALEN
) != 0) {
410 warn("Ignoring PADO packet from wrong MAC address");
413 if (parsePacket(&packet
, parsePADOTags
, &pc
) < 0)
417 if (!pc
.seenACName
) {
418 error("Ignoring PADO packet with no AC-Name tag");
421 if (!pc
.seenServiceName
) {
422 error("Ignoring PADO packet with no Service-Name tag");
426 if (pc
.acNameOK
&& pc
.serviceNameOK
) {
427 memcpy(conn
->peerEth
, packet
.ethHdr
.h_source
, ETH_ALEN
);
428 conn
->discoveryState
= STATE_RECEIVED_PADO
;
432 } while (conn
->discoveryState
!= STATE_RECEIVED_PADO
);
435 /***********************************************************************
438 * conn -- PPPoE connection structur
442 * Sends a PADR packet
443 ***********************************************************************/
445 sendPADR(PPPoEConnection
*conn
)
448 PPPoETag
*svc
= (PPPoETag
*) packet
.payload
;
449 unsigned char *cursor
= packet
.payload
;
451 UINT16_t namelen
= 0;
454 if (conn
->serviceName
) {
455 namelen
= (UINT16_t
) strlen(conn
->serviceName
);
457 plen
= TAG_HDR_SIZE
+ namelen
;
458 CHECK_ROOM(cursor
, packet
.payload
, plen
);
460 memcpy(packet
.ethHdr
.h_dest
, conn
->peerEth
, ETH_ALEN
);
461 memcpy(packet
.ethHdr
.h_source
, conn
->myEth
, ETH_ALEN
);
463 packet
.ethHdr
.h_proto
= htons(Eth_PPPOE_Discovery
);
464 packet
.vertype
= PPPOE_VER_TYPE(1, 1);
465 packet
.code
= CODE_PADR
;
468 svc
->type
= TAG_SERVICE_NAME
;
469 svc
->length
= htons(namelen
);
470 if (conn
->serviceName
) {
471 memcpy(svc
->payload
, conn
->serviceName
, namelen
);
473 cursor
+= namelen
+ TAG_HDR_SIZE
;
475 /* If we're using Host-Uniq, copy it over */
476 if (conn
->useHostUniq
) {
478 pid_t pid
= getpid();
479 hostUniq
.type
= htons(TAG_HOST_UNIQ
);
480 hostUniq
.length
= htons(sizeof(pid
));
481 memcpy(hostUniq
.payload
, &pid
, sizeof(pid
));
482 CHECK_ROOM(cursor
, packet
.payload
, sizeof(pid
)+TAG_HDR_SIZE
);
483 memcpy(cursor
, &hostUniq
, sizeof(pid
) + TAG_HDR_SIZE
);
484 cursor
+= sizeof(pid
) + TAG_HDR_SIZE
;
485 plen
+= sizeof(pid
) + TAG_HDR_SIZE
;
488 /* Add our maximum MTU/MRU */
489 if (MIN(lcp_allowoptions
[0].mru
, lcp_wantoptions
[0].mru
) > ETH_PPPOE_MTU
) {
491 UINT16_t mru
= htons(MIN(lcp_allowoptions
[0].mru
, lcp_wantoptions
[0].mru
));
492 maxPayload
.type
= htons(TAG_PPP_MAX_PAYLOAD
);
493 maxPayload
.length
= htons(sizeof(mru
));
494 memcpy(maxPayload
.payload
, &mru
, sizeof(mru
));
495 CHECK_ROOM(cursor
, packet
.payload
, sizeof(mru
) + TAG_HDR_SIZE
);
496 memcpy(cursor
, &maxPayload
, sizeof(mru
) + TAG_HDR_SIZE
);
497 cursor
+= sizeof(mru
) + TAG_HDR_SIZE
;
498 plen
+= sizeof(mru
) + TAG_HDR_SIZE
;
501 /* Copy cookie and relay-ID if needed */
502 if (conn
->cookie
.type
) {
503 CHECK_ROOM(cursor
, packet
.payload
,
504 ntohs(conn
->cookie
.length
) + TAG_HDR_SIZE
);
505 memcpy(cursor
, &conn
->cookie
, ntohs(conn
->cookie
.length
) + TAG_HDR_SIZE
);
506 cursor
+= ntohs(conn
->cookie
.length
) + TAG_HDR_SIZE
;
507 plen
+= ntohs(conn
->cookie
.length
) + TAG_HDR_SIZE
;
510 if (conn
->relayId
.type
) {
511 CHECK_ROOM(cursor
, packet
.payload
,
512 ntohs(conn
->relayId
.length
) + TAG_HDR_SIZE
);
513 memcpy(cursor
, &conn
->relayId
, ntohs(conn
->relayId
.length
) + TAG_HDR_SIZE
);
514 cursor
+= ntohs(conn
->relayId
.length
) + TAG_HDR_SIZE
;
515 plen
+= ntohs(conn
->relayId
.length
) + TAG_HDR_SIZE
;
518 packet
.length
= htons(plen
);
519 sendPacket(conn
, conn
->discoverySocket
, &packet
, (int) (plen
+ HDR_SIZE
));
522 /**********************************************************************
523 *%FUNCTION: waitForPADS
525 * conn -- PPPoE connection info
526 * timeout -- how long to wait (in seconds)
530 * Waits for a PADS packet and copies useful information
531 ***********************************************************************/
533 waitForPADS(PPPoEConnection
*conn
, int timeout
)
538 struct timeval expire_at
;
544 if (gettimeofday(&expire_at
, NULL
) < 0) {
545 fatalSys("gettimeofday (waitForPADS)");
547 expire_at
.tv_sec
+= timeout
;
551 if (BPF_BUFFER_IS_EMPTY
) {
552 if (gettimeofday(&now
, NULL
) < 0) {
553 fatalSys("gettimeofday (waitForPADS)");
555 tv
.tv_sec
= expire_at
.tv_sec
- now
.tv_sec
;
556 tv
.tv_usec
= expire_at
.tv_usec
- now
.tv_usec
;
557 if (tv
.tv_usec
< 0) {
558 tv
.tv_usec
+= 1000000;
566 if (tv
.tv_sec
<= 0 && tv
.tv_usec
<= 0) {
572 FD_SET(conn
->discoverySocket
, &readable
);
575 r
= select(conn
->discoverySocket
+1, &readable
, NULL
, NULL
, &tv
);
576 if (r
>= 0 || errno
!= EINTR
) break;
579 error("select (waitForPADS): %m");
589 receivePacket(conn
->discoverySocket
, &packet
, &len
);
592 if (ntohs(packet
.length
) + HDR_SIZE
> len
) {
593 error("Bogus PPPoE length field (%u)",
594 (unsigned int) ntohs(packet
.length
));
599 /* If it's not a Discovery packet, loop again */
600 if (etherType(&packet
) != Eth_PPPOE_Discovery
) continue;
603 /* If it's not from the AC, it's not for me */
604 if (memcmp(packet
.ethHdr
.h_source
, conn
->peerEth
, ETH_ALEN
)) continue;
606 /* If it's not for us, loop again */
607 if (!packetIsForMe(conn
, &packet
)) continue;
610 if (packet
.code
== CODE_PADS
) {
611 /* Parse for goodies */
612 if (parsePacket(&packet
, parsePADSTags
, conn
) < 0)
616 conn
->discoveryState
= STATE_SESSION
;
619 } while (conn
->discoveryState
!= STATE_SESSION
);
621 /* Don't bother with ntohs; we'll just end up converting it back... */
622 conn
->session
= packet
.session
;
624 info("PPP session is %d", (int) ntohs(conn
->session
));
626 /* RFC 2516 says session id MUST NOT be zero or 0xFFFF */
627 if (ntohs(conn
->session
) == 0 || ntohs(conn
->session
) == 0xFFFF) {
628 error("Access concentrator used a session value of %x -- the AC is violating RFC 2516", (unsigned int) ntohs(conn
->session
));
632 /**********************************************************************
633 *%FUNCTION: discovery
635 * conn -- PPPoE connection info structure
639 * Performs the PPPoE discovery phase
640 ***********************************************************************/
642 discovery(PPPoEConnection
*conn
)
644 int padiAttempts
= 0;
645 int padrAttempts
= 0;
646 int timeout
= conn
->discoveryTimeout
;
648 conn
->discoverySocket
=
649 openInterface(conn
->ifName
, Eth_PPPOE_Discovery
, conn
->myEth
);
653 if (padiAttempts
> MAX_PADI_ATTEMPTS
) {
654 warn("Timeout waiting for PADO packets");
655 system("ppp_event -t PADO_TIMEOUT &");
656 close(conn
->discoverySocket
);
657 conn
->discoverySocket
= -1;
661 conn
->discoveryState
= STATE_SENT_PADI
;
662 waitForPADO(conn
, timeout
);
665 } while (conn
->discoveryState
== STATE_SENT_PADI
);
667 timeout
= conn
->discoveryTimeout
;
670 if (padrAttempts
> MAX_PADI_ATTEMPTS
) {
671 warn("Timeout waiting for PADS packets");
672 system("ppp_event -t PADS_TIMEOUT &");
673 close(conn
->discoverySocket
);
674 conn
->discoverySocket
= -1;
678 conn
->discoveryState
= STATE_SENT_PADR
;
679 waitForPADS(conn
, timeout
);
681 } while (conn
->discoveryState
== STATE_SENT_PADR
);
683 if (!conn
->seenMaxPayload
) {
684 /* RFC 4638: MUST limit MTU/MRU to 1492 */
685 if (lcp_allowoptions
[0].mru
> ETH_PPPOE_MTU
)
686 lcp_allowoptions
[0].mru
= ETH_PPPOE_MTU
;
687 if (lcp_wantoptions
[0].mru
> ETH_PPPOE_MTU
)
688 lcp_wantoptions
[0].mru
= ETH_PPPOE_MTU
;
692 conn
->discoveryState
= STATE_SESSION
;