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
36 #ifdef USE_LINUX_PACKET
37 #include <sys/ioctl.h>
43 /**********************************************************************
44 *%FUNCTION: parseForHostUniq
49 * extra -- user-supplied pointer. This is assumed to be a pointer to int.
53 * If a HostUnique tag is found which matches our PID, sets *extra to 1.
54 ***********************************************************************/
56 parseForHostUniq(UINT16_t type, UINT16_t len, unsigned char *data,
59 int *val = (int *) extra;
60 if (type == TAG_HOST_UNIQ && len == sizeof(pid_t)) {
62 memcpy(&tmp, data, len);
63 if (tmp == getpid()) {
69 /**********************************************************************
70 *%FUNCTION: packetIsForMe
72 * conn -- PPPoE connection info
73 * packet -- a received PPPoE packet
75 * 1 if packet is for this PPPoE daemon; 0 otherwise.
77 * If we are using the Host-Unique tag, verifies that packet contains
78 * our unique identifier.
79 ***********************************************************************/
81 packetIsForMe(PPPoEConnection *conn, PPPoEPacket *packet)
85 /* If packet is not directed to our MAC address, forget it */
86 if (memcmp(packet->ethHdr.h_dest, conn->myEth, ETH_ALEN)) return 0;
88 /* If we're not using the Host-Unique tag, then accept the packet */
89 if (!conn->useHostUniq) return 1;
91 parsePacket(packet, parseForHostUniq, &forMe);
95 /**********************************************************************
96 *%FUNCTION: parsePADOTags
101 * extra -- extra user data. Should point to a PacketCriteria structure
102 * which gets filled in according to selected AC name and service
107 * Picks interesting tags out of a PADO packet
108 ***********************************************************************/
110 parsePADOTags(UINT16_t type, UINT16_t len, unsigned char *data,
113 struct PacketCriteria *pc = (struct PacketCriteria *) extra;
114 PPPoEConnection *conn = pc->conn;
121 if (conn->printACNames) {
122 info("Access-Concentrator: %.*s", (int) len, data);
124 if (conn->acName && len == strlen(conn->acName) &&
125 !strncmp((char *) data, conn->acName, len)) {
129 case TAG_SERVICE_NAME:
130 pc->seenServiceName = 1;
131 if (conn->serviceName && len == strlen(conn->serviceName) &&
132 !strncmp((char *) data, conn->serviceName, len)) {
133 pc->serviceNameOK = 1;
137 conn->cookie.type = htons(type);
138 conn->cookie.length = htons(len);
139 memcpy(conn->cookie.payload, data, len);
141 case TAG_RELAY_SESSION_ID:
142 conn->relayId.type = htons(type);
143 conn->relayId.length = htons(len);
144 memcpy(conn->relayId.payload, data, len);
146 case TAG_PPP_MAX_PAYLOAD:
147 if (len == sizeof(mru)) {
148 memcpy(&mru, data, sizeof(mru));
150 if (mru >= ETH_PPPOE_MTU) {
151 if (lcp_allowoptions[0].mru > mru)
152 lcp_allowoptions[0].mru = mru;
153 if (lcp_wantoptions[0].mru > mru)
154 lcp_wantoptions[0].mru = mru;
155 conn->seenMaxPayload = 1;
159 case TAG_SERVICE_NAME_ERROR:
160 error("PADO: Service-Name-Error: %.*s", (int) len, data);
163 case TAG_AC_SYSTEM_ERROR:
164 error("PADO: System-Error: %.*s", (int) len, data);
167 case TAG_GENERIC_ERROR:
168 error("PADO: Generic-Error: %.*s", (int) len, data);
174 /**********************************************************************
175 *%FUNCTION: parsePADSTags
180 * extra -- extra user data (pointer to PPPoEConnection structure)
184 * Picks interesting tags out of a PADS packet
185 ***********************************************************************/
187 parsePADSTags(UINT16_t type, UINT16_t len, unsigned char *data,
190 PPPoEConnection *conn = (PPPoEConnection *) extra;
193 case TAG_SERVICE_NAME:
194 dbglog("PADS: Service-Name: '%.*s'", (int) len, data);
196 case TAG_PPP_MAX_PAYLOAD:
197 if (len == sizeof(mru)) {
198 memcpy(&mru, data, sizeof(mru));
200 if (mru >= ETH_PPPOE_MTU) {
201 if (lcp_allowoptions[0].mru > mru)
202 lcp_allowoptions[0].mru = mru;
203 if (lcp_wantoptions[0].mru > mru)
204 lcp_wantoptions[0].mru = mru;
205 conn->seenMaxPayload = 1;
209 case TAG_SERVICE_NAME_ERROR:
210 error("PADS: Service-Name-Error: %.*s", (int) len, data);
213 case TAG_AC_SYSTEM_ERROR:
214 error("PADS: System-Error: %.*s", (int) len, data);
217 case TAG_GENERIC_ERROR:
218 error("PADS: Generic-Error: %.*s", (int) len, data);
221 case TAG_RELAY_SESSION_ID:
222 conn->relayId.type = htons(type);
223 conn->relayId.length = htons(len);
224 memcpy(conn->relayId.payload, data, len);
229 /***********************************************************************
232 * conn -- PPPoEConnection structure
236 * Sends a PADI packet
237 ***********************************************************************/
239 sendPADI(PPPoEConnection *conn)
242 unsigned char *cursor = packet.payload;
243 PPPoETag *svc = (PPPoETag *) (&packet.payload);
244 UINT16_t namelen = 0;
246 int omit_service_name = 0;
248 if (conn->serviceName) {
249 namelen = (UINT16_t) strlen(conn->serviceName);
250 if (!strcmp(conn->serviceName, "NO-SERVICE-NAME-NON-RFC-COMPLIANT")) {
251 omit_service_name = 1;
255 /* Set destination to Ethernet broadcast address */
256 memset(packet.ethHdr.h_dest, 0xFF, ETH_ALEN);
257 memcpy(packet.ethHdr.h_source, conn->myEth, ETH_ALEN);
259 packet.ethHdr.h_proto = htons(Eth_PPPOE_Discovery);
260 packet.vertype = PPPOE_VER_TYPE(1, 1);
261 packet.code = CODE_PADI;
264 if (!omit_service_name) {
265 plen = TAG_HDR_SIZE + namelen;
266 CHECK_ROOM(cursor, packet.payload, plen);
268 svc->type = TAG_SERVICE_NAME;
269 svc->length = htons(namelen);
271 if (conn->serviceName) {
272 memcpy(svc->payload, conn->serviceName, strlen(conn->serviceName));
274 cursor += namelen + TAG_HDR_SIZE;
279 /* If we're using Host-Uniq, copy it over */
280 if (conn->useHostUniq) {
282 pid_t pid = getpid();
283 hostUniq.type = htons(TAG_HOST_UNIQ);
284 hostUniq.length = htons(sizeof(pid));
285 memcpy(hostUniq.payload, &pid, sizeof(pid));
286 CHECK_ROOM(cursor, packet.payload, sizeof(pid) + TAG_HDR_SIZE);
287 memcpy(cursor, &hostUniq, sizeof(pid) + TAG_HDR_SIZE);
288 cursor += sizeof(pid) + TAG_HDR_SIZE;
289 plen += sizeof(pid) + TAG_HDR_SIZE;
292 /* Add our maximum MTU/MRU */
293 if (MIN(lcp_allowoptions[0].mru, lcp_wantoptions[0].mru) > ETH_PPPOE_MTU) {
295 UINT16_t mru = htons(MIN(lcp_allowoptions[0].mru, lcp_wantoptions[0].mru));
296 maxPayload.type = htons(TAG_PPP_MAX_PAYLOAD);
297 maxPayload.length = htons(sizeof(mru));
298 memcpy(maxPayload.payload, &mru, sizeof(mru));
299 CHECK_ROOM(cursor, packet.payload, sizeof(mru) + TAG_HDR_SIZE);
300 memcpy(cursor, &maxPayload, sizeof(mru) + TAG_HDR_SIZE);
301 cursor += sizeof(mru) + TAG_HDR_SIZE;
302 plen += sizeof(mru) + TAG_HDR_SIZE;
305 packet.length = htons(plen);
307 sendPacket(conn, conn->discoverySocket, &packet, (int) (plen + HDR_SIZE));
310 /**********************************************************************
311 *%FUNCTION: waitForPADO
313 * conn -- PPPoEConnection structure
314 * timeout -- how long to wait (in seconds)
318 * Waits for a PADO packet and copies useful information
319 ***********************************************************************/
321 waitForPADO(PPPoEConnection *conn, int timeout)
329 struct PacketCriteria pc;
331 pc.acNameOK = (conn->acName) ? 0 : 1;
332 pc.serviceNameOK = (conn->serviceName) ? 0 : 1;
334 pc.seenServiceName = 0;
335 conn->seenMaxPayload = 0;
339 if (BPF_BUFFER_IS_EMPTY) {
344 FD_SET(conn->discoverySocket, &readable);
347 r = select(conn->discoverySocket+1, &readable, NULL, NULL, &tv);
348 if (r >= 0 || errno != EINTR) break;
351 error("select (waitForPADO): %m");
354 if (r == 0) return; /* Timed out */
358 receivePacket(conn->discoverySocket, &packet, &len);
361 if (ntohs(packet.length) + HDR_SIZE > len) {
362 error("Bogus PPPoE length field (%u)",
363 (unsigned int) ntohs(packet.length));
368 /* If it's not a Discovery packet, loop again */
369 if (etherType(&packet) != Eth_PPPOE_Discovery) continue;
372 /* If it's not for us, loop again */
373 if (!packetIsForMe(conn, &packet)) continue;
375 if (packet.code == CODE_PADO) {
376 if (NOT_UNICAST(packet.ethHdr.h_source)) {
377 error("Ignoring PADO packet from non-unicast MAC address");
381 && memcmp(packet.ethHdr.h_source, conn->req_peer_mac, ETH_ALEN) != 0) {
382 warn("Ignoring PADO packet from wrong MAC address");
385 if (parsePacket(&packet, parsePADOTags, &pc) < 0)
389 if (!pc.seenACName) {
390 error("Ignoring PADO packet with no AC-Name tag");
393 if (!pc.seenServiceName) {
394 error("Ignoring PADO packet with no Service-Name tag");
398 if (pc.acNameOK && pc.serviceNameOK) {
399 memcpy(conn->peerEth, packet.ethHdr.h_source, ETH_ALEN);
400 conn->discoveryState = STATE_RECEIVED_PADO;
404 } while (conn->discoveryState != STATE_RECEIVED_PADO);
407 /***********************************************************************
410 * conn -- PPPoE connection structur
414 * Sends a PADR packet
415 ***********************************************************************/
417 sendPADR(PPPoEConnection *conn)
420 PPPoETag *svc = (PPPoETag *) packet.payload;
421 unsigned char *cursor = packet.payload;
423 UINT16_t namelen = 0;
426 if (conn->serviceName) {
427 namelen = (UINT16_t) strlen(conn->serviceName);
429 plen = TAG_HDR_SIZE + namelen;
430 CHECK_ROOM(cursor, packet.payload, plen);
432 memcpy(packet.ethHdr.h_dest, conn->peerEth, ETH_ALEN);
433 memcpy(packet.ethHdr.h_source, conn->myEth, ETH_ALEN);
435 packet.ethHdr.h_proto = htons(Eth_PPPOE_Discovery);
436 packet.vertype = PPPOE_VER_TYPE(1, 1);
437 packet.code = CODE_PADR;
440 svc->type = TAG_SERVICE_NAME;
441 svc->length = htons(namelen);
442 if (conn->serviceName) {
443 memcpy(svc->payload, conn->serviceName, namelen);
445 cursor += namelen + TAG_HDR_SIZE;
447 /* If we're using Host-Uniq, copy it over */
448 if (conn->useHostUniq) {
450 pid_t pid = getpid();
451 hostUniq.type = htons(TAG_HOST_UNIQ);
452 hostUniq.length = htons(sizeof(pid));
453 memcpy(hostUniq.payload, &pid, sizeof(pid));
454 CHECK_ROOM(cursor, packet.payload, sizeof(pid)+TAG_HDR_SIZE);
455 memcpy(cursor, &hostUniq, sizeof(pid) + TAG_HDR_SIZE);
456 cursor += sizeof(pid) + TAG_HDR_SIZE;
457 plen += sizeof(pid) + TAG_HDR_SIZE;
460 /* Add our maximum MTU/MRU */
461 if (MIN(lcp_allowoptions[0].mru, lcp_wantoptions[0].mru) > ETH_PPPOE_MTU) {
463 UINT16_t mru = htons(MIN(lcp_allowoptions[0].mru, lcp_wantoptions[0].mru));
464 maxPayload.type = htons(TAG_PPP_MAX_PAYLOAD);
465 maxPayload.length = htons(sizeof(mru));
466 memcpy(maxPayload.payload, &mru, sizeof(mru));
467 CHECK_ROOM(cursor, packet.payload, sizeof(mru) + TAG_HDR_SIZE);
468 memcpy(cursor, &maxPayload, sizeof(mru) + TAG_HDR_SIZE);
469 cursor += sizeof(mru) + TAG_HDR_SIZE;
470 plen += sizeof(mru) + TAG_HDR_SIZE;
473 /* Copy cookie and relay-ID if needed */
474 if (conn->cookie.type) {
475 CHECK_ROOM(cursor, packet.payload,
476 ntohs(conn->cookie.length) + TAG_HDR_SIZE);
477 memcpy(cursor, &conn->cookie, ntohs(conn->cookie.length) + TAG_HDR_SIZE);
478 cursor += ntohs(conn->cookie.length) + TAG_HDR_SIZE;
479 plen += ntohs(conn->cookie.length) + TAG_HDR_SIZE;
482 if (conn->relayId.type) {
483 CHECK_ROOM(cursor, packet.payload,
484 ntohs(conn->relayId.length) + TAG_HDR_SIZE);
485 memcpy(cursor, &conn->relayId, ntohs(conn->relayId.length) + TAG_HDR_SIZE);
486 cursor += ntohs(conn->relayId.length) + TAG_HDR_SIZE;
487 plen += ntohs(conn->relayId.length) + TAG_HDR_SIZE;
490 packet.length = htons(plen);
491 sendPacket(conn, conn->discoverySocket, &packet, (int) (plen + HDR_SIZE));
494 /**********************************************************************
495 *%FUNCTION: waitForPADS
497 * conn -- PPPoE connection info
498 * timeout -- how long to wait (in seconds)
502 * Waits for a PADS packet and copies useful information
503 ***********************************************************************/
505 waitForPADS(PPPoEConnection *conn, int timeout)
515 if (BPF_BUFFER_IS_EMPTY) {
520 FD_SET(conn->discoverySocket, &readable);
523 r = select(conn->discoverySocket+1, &readable, NULL, NULL, &tv);
524 if (r >= 0 || errno != EINTR) break;
527 error("select (waitForPADS): %m");
534 receivePacket(conn->discoverySocket, &packet, &len);
537 if (ntohs(packet.length) + HDR_SIZE > len) {
538 error("Bogus PPPoE length field (%u)",
539 (unsigned int) ntohs(packet.length));
544 /* If it's not a Discovery packet, loop again */
545 if (etherType(&packet) != Eth_PPPOE_Discovery) continue;
548 /* If it's not from the AC, it's not for me */
549 if (memcmp(packet.ethHdr.h_source, conn->peerEth, ETH_ALEN)) continue;
551 /* If it's not for us, loop again */
552 if (!packetIsForMe(conn, &packet)) continue;
555 if (packet.code == CODE_PADS) {
556 /* Parse for goodies */
557 if (parsePacket(&packet, parsePADSTags, conn) < 0)
561 conn->discoveryState = STATE_SESSION;
564 } while (conn->discoveryState != STATE_SESSION);
566 /* Don't bother with ntohs; we'll just end up converting it back... */
567 conn->session = packet.session;
569 info("PPP session is %d", (int) ntohs(conn->session));
571 /* RFC 2516 says session id MUST NOT be zero or 0xFFFF */
572 if (ntohs(conn->session) == 0 || ntohs(conn->session) == 0xFFFF) {
573 error("Access concentrator used a session value of %x -- the AC is violating RFC 2516", (unsigned int) ntohs(conn->session));
577 /**********************************************************************
578 *%FUNCTION: discovery
580 * conn -- PPPoE connection info structure
584 * Performs the PPPoE discovery phase
585 ***********************************************************************/
587 discovery(PPPoEConnection *conn)
589 int padiAttempts = 0;
590 int padrAttempts = 0;
591 int timeout = conn->discoveryTimeout;
593 conn->discoverySocket =
594 openInterface(conn->ifName, Eth_PPPOE_Discovery, conn->myEth);
598 if (padiAttempts > MAX_PADI_ATTEMPTS) {
599 warn("Timeout waiting for PADO packets");
600 close(conn->discoverySocket);
601 conn->discoverySocket = -1;
605 conn->discoveryState = STATE_SENT_PADI;
606 waitForPADO(conn, timeout);
609 } while (conn->discoveryState == STATE_SENT_PADI);
611 timeout = conn->discoveryTimeout;
614 if (padrAttempts > MAX_PADI_ATTEMPTS) {
615 warn("Timeout waiting for PADS packets");
616 close(conn->discoverySocket);
617 conn->discoverySocket = -1;
621 conn->discoveryState = STATE_SENT_PADR;
622 waitForPADS(conn, timeout);
624 } while (conn->discoveryState == STATE_SENT_PADR);
626 if (!conn->seenMaxPayload) {
627 /* RFC 4638: MUST limit MTU/MRU to 1492 */
628 if (lcp_allowoptions[0].mru > ETH_PPPOE_MTU)
629 lcp_allowoptions[0].mru = ETH_PPPOE_MTU;
630 if (lcp_wantoptions[0].mru > ETH_PPPOE_MTU)
631 lcp_wantoptions[0].mru = ETH_PPPOE_MTU;
635 conn->discoveryState = STATE_SESSION;